6 #include "util.h" // for log()
15 #define DEBUG_CMD(_a) if (DEBUG_ON) { _a }
18 #define MIN_CAPACITY 128 /* min allocated buffer for a packet */
20 static int pqueue_alloc (int seq
, unsigned char *packet
, int packlen
, pqueue_t
**new);
22 int packet_timeout_usecs
= DEFAULT_PACKET_TIMEOUT
* 1000000;
25 static pqueue_t
*pq_head
= NULL
, *pq_tail
= NULL
;
27 /* contains a list of free queue elements.*/
28 static pqueue_t
*pq_freelist_head
= NULL
;
32 static int pqueue_alloc(int seq
, unsigned char *packet
, int packlen
, pqueue_t
**new) {
36 DEBUG_CMD(log("seq=%d, packlen=%d", seq
, packlen
););
38 /* search the freelist for one that has sufficient space */
39 if (pq_freelist_head
) {
41 for (newent
= pq_freelist_head
; newent
; newent
= newent
->next
) {
43 if (newent
->capacity
>= packlen
) {
45 /* unlink from freelist */
46 if (pq_freelist_head
== newent
)
47 pq_freelist_head
= newent
->next
;
50 newent
->prev
->next
= newent
->next
;
53 newent
->next
->prev
= newent
->prev
;
56 pq_freelist_head
->prev
= NULL
;
59 } /* end if capacity >= packlen */
62 /* nothing found? Take first and reallocate it */
65 newent
= pq_freelist_head
;
66 pq_freelist_head
= pq_freelist_head
->next
;
69 pq_freelist_head
->prev
= NULL
;
71 DEBUG_CMD(log("realloc capacity %d to %d",newent
->capacity
, packlen
););
73 newent
->packet
= (unsigned char *)realloc(newent
->packet
, packlen
);
75 if (!newent
->packet
) {
76 warn("error reallocating packet: %s", strerror(errno
));
79 newent
->capacity
= packlen
;
82 DEBUG_CMD(log("Recycle entry from freelist. Capacity: %d", newent
->capacity
););
86 /* allocate a new one */
87 newent
= (pqueue_t
*)malloc( sizeof(pqueue_t
) );
89 warn("error allocating newent: %s", strerror(errno
));
94 DEBUG_CMD(log("Alloc new queue entry"););
97 if ( ! newent
->capacity
) {
98 /* a new queue entry was allocated. Allocate the packet buffer */
99 int size
= packlen
< MIN_CAPACITY
? MIN_CAPACITY
: packlen
;
100 /* Allocate at least MIN_CAPACITY */
101 DEBUG_CMD(log("allocating for packet size %d", size
););
102 newent
->packet
= (unsigned char *)malloc(size
);
103 if (!newent
->packet
) {
104 warn("error allocating packet: %s", strerror(errno
));
107 newent
->capacity
= size
;
108 } /* endif ! capacity */
109 assert( newent
->capacity
>= packlen
);
110 /* store the contents into the buffer */
111 memcpy(newent
->packet
, packet
, packlen
);
113 newent
->next
= newent
->prev
= NULL
;
115 newent
->packlen
= packlen
;
117 gettimeofday(&newent
->expires
, NULL
);
118 newent
->expires
.tv_usec
+= packet_timeout_usecs
;
119 newent
->expires
.tv_sec
+= (newent
->expires
.tv_usec
/ 1000000);
120 newent
->expires
.tv_usec
%= 1000000;
128 int pqueue_add (int seq
, unsigned char *packet
, int packlen
) {
129 pqueue_t
*newent
, *point
;
131 /* get a new entry */
132 if ( 0 != pqueue_alloc(seq
, packet
, packlen
, &newent
) ) {
136 for (point
= pq_head
; point
!= NULL
; point
= point
->next
) {
137 if (point
->seq
== seq
) {
138 // queue already contains this packet
139 warn("discarding duplicate packet %d", seq
);
142 if (point
->seq
> seq
) {
143 // gone too far: point->seq > seq and point->prev->seq < seq
145 // insert between point->prev and point
146 DEBUG_CMD(log("adding %d between %d and %d",
147 seq
, point
->prev
->seq
, point
->seq
););
149 point
->prev
->next
= newent
;
151 // insert at head of queue, before point
152 DEBUG_CMD(log("adding %d before %d", seq
, point
->seq
););
155 newent
->prev
= point
->prev
; // will be NULL, at head of queue
156 newent
->next
= point
;
157 point
->prev
= newent
;
162 /* We didn't find anywhere to insert the packet,
163 * so there are no packets in the queue with higher sequences than this one,
164 * so all the packets in the queue have lower sequences,
165 * so this packet belongs at the end of the queue (which might be empty)
168 if (pq_head
== NULL
) {
169 DEBUG_CMD(log("adding %d to empty queue", seq
););
172 DEBUG_CMD(log("adding %d as tail, after %d", seq
, pq_tail
->seq
););
173 pq_tail
->next
= newent
;
175 newent
->prev
= pq_tail
;
183 int pqueue_del (pqueue_t
*point
) {
185 DEBUG_CMD(log("Move seq %d to freelist", point
->seq
););
188 if (pq_head
== point
) pq_head
= point
->next
;
189 if (pq_tail
== point
) pq_tail
= point
->prev
;
190 if (point
->prev
) point
->prev
->next
= point
->next
;
191 if (point
->next
) point
->next
->prev
= point
->prev
;
193 /* add point to the freelist */
194 point
->next
= pq_freelist_head
;
198 point
->next
->prev
= point
;
199 pq_freelist_head
= point
;
203 int pq_freelist_count
= 0;
205 for ( point
= pq_head
; point
; point
= point
->next
) {
209 for ( point
= pq_freelist_head
; point
; point
= point
->next
) {
212 log("queue length is %d, freelist length is %d", pq_count
, pq_freelist_count
);
220 pqueue_t
*pqueue_head () {
226 int pqueue_expiry_time (pqueue_t
*entry
) {
230 gettimeofday(&tv
, NULL
);
231 expiry_time
= (entry
->expires
.tv_sec
- tv
.tv_sec
) * 1000000;
232 expiry_time
+= (entry
->expires
.tv_usec
- tv
.tv_usec
);