4 * Herein lies all the mangement routines for the transmit (Tx) queue.
13 * The overall purpose here is to enqueue the passed in command struct
14 * into the outgoing (tx) queue. Basically...
15 * 1) Make a scope-irrelevent copy of the struct
17 * 3) Mark as not-sent-yet
18 * 4) Enqueue the struct into the list
19 * 5) Unlock the struct once it's linked in
24 int aim_tx_enqueue(struct command_tx_struct *newpacket)
26 struct command_tx_struct *workingPtr = NULL;
27 struct command_tx_struct *newpacket_copy = NULL;
29 if (newpacket->conn == NULL)
31 printf("aim_tx_enqueue: WARNING: enqueueing packet with no connecetion, defaulting to BOS\n");
32 newpacket->conn = aim_getconn_type(AIM_CONN_TYPE_BOS);
35 newpacket_copy = (struct command_tx_struct *) malloc (sizeof(struct command_tx_struct));
36 memcpy(newpacket_copy, newpacket, sizeof(struct command_tx_struct));
39 newpacket_copy->seqnum = aim_get_next_txseqnum(newpacket_copy->conn);
40 /* set some more fields */
41 newpacket_copy->lock = 1; /* lock */
42 newpacket_copy->sent = 0; /* not sent yet */
43 newpacket_copy->next = NULL; /* always last */
45 if (aim_queue_outgoing == NULL)
47 aim_queue_outgoing = newpacket_copy;
51 workingPtr = aim_queue_outgoing;
52 while (workingPtr->next != NULL)
53 workingPtr = workingPtr->next;
54 workingPtr->next = newpacket_copy;
57 newpacket_copy->lock = 0; /* unlock so it can be sent */
60 printf("calling aim_tx_printqueue()\n");
62 printf("back from aim_tx_printqueue()\n");
65 /* we'll force a flush for now -- this behavior probably will change */
67 printf("calling aim_tx_flushqueue()\n");
71 printf("back from aim_tx_flushqueue()\n");
78 aim_get_next_txseqnum()
80 This increments the tx command count, and returns the seqnum
81 that should be stamped on the next FLAP packet sent. This is
82 normally called during the final step of packet preparation
83 before enqueuement (in aim_tx_enqueue()).
86 u_int aim_get_next_txseqnum(struct aim_conn_t *conn)
88 return ( ++conn->seqnum );
94 This is basically for debuging purposes only. It dumps all the
95 records in the tx queue and their current status. Very helpful
96 if the queue isn't working quite right.
100 int aim_tx_printqueue(void)
102 struct command_tx_struct *workingPtr = NULL;
104 workingPtr = aim_queue_outgoing;
106 printf("\ncurrent aim_queue_outgoing...\n");
107 printf("\ttype seqnum len lock sent\n");
109 if (workingPtr == NULL)
110 printf("aim_tx_flushqueue(): queue empty");
113 while (workingPtr != NULL)
115 printf("\t %2x %4x %4x %1d %1d\n", workingPtr->type, workingPtr->seqnum, workingPtr->commandlen, workingPtr->lock, workingPtr->sent);
117 workingPtr = workingPtr->next;
121 printf("\n(done printing queue)\n");
130 This the function is responsable for putting the queued commands
131 onto the wire. This function is critical to the operation of
132 the queue and therefore is the most prone to brokenness. It
133 seems to be working quite well at this point.
136 1) Traverse the list, only operate on commands that are unlocked
137 and haven't been sent yet.
139 3) Allocate a temporary buffer to store the finished, fully
141 4) Build the packet from the command_tx_struct data.
142 5) Write the packet to the socket.
143 6) If success, mark the packet sent, if fail report failure, do NOT
144 mark the packet sent (so it will not get purged and therefore
145 be attempted again on next call).
146 7) Unlock the struct.
147 8) Free the temp buffer
148 9) Step to next struct in list and go back to 1.
151 int aim_tx_flushqueue(void)
153 struct command_tx_struct *workingPtr = NULL;
154 u_char *curPacket = NULL;
159 workingPtr = aim_queue_outgoing;
161 printf("beginning txflush...\n");
163 while (workingPtr != NULL)
165 /* only process if its unlocked and unsent */
166 if ( (workingPtr->lock == 0) &&
167 (workingPtr->sent == 0) )
171 * And now for the meager attempt to force transmit
172 * latency and avoid missed messages.
174 if ((workingPtr->conn->lastactivity + workingPtr->conn->forcedlatency)
177 /* FIXME FIXME -- should be a break! we dont want to block the upper layers */
178 sleep((workingPtr->conn->lastactivity + workingPtr->conn->forcedlatency) - time(NULL));
181 workingPtr->lock = 1; /* lock the struct */
183 /* allocate full-packet buffer */
184 curPacket = (char *) malloc(workingPtr->commandlen + 6);
188 /* type/family byte */
189 curPacket[1] = workingPtr->type;
190 /* bytes 3+4: word: FLAP sequence number */
191 curPacket[2] = (char) ( (workingPtr->seqnum) >> 8);
192 curPacket[3] = (char) ( (workingPtr->seqnum) & 0xFF);
193 /* bytes 5+6: word: SNAC len */
194 curPacket[4] = (char) ( (workingPtr->commandlen) >> 8);
195 curPacket[5] = (char) ( (workingPtr->commandlen) & 0xFF);
196 /* bytes 7 and on: raw: SNAC data */
197 memcpy(&(curPacket[6]), workingPtr->data, workingPtr->commandlen);
199 /* full image of raw packet data now in curPacket */
201 if ( (u_int)write(workingPtr->conn->fd, curPacket, (workingPtr->commandlen + 6)) != (workingPtr->commandlen + 6))
203 printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", workingPtr->seqnum);
204 workingPtr->sent = 0; /* mark it unsent */
205 return -1; /* bail out */
210 printf("\nSENT 0x%4x\n\n", workingPtr->seqnum);
212 workingPtr->sent = 1; /* mark the struct as sent */
213 workingPtr->conn->lastactivity = time(NULL);
217 for (i = 0; i < (workingPtr->commandlen + 6); i++)
221 if (curPacket[i] >= ' ' && curPacket[i]<127)
222 printf("%c=%02x ",curPacket[i], curPacket[i]);
224 printf("0x%2x ", curPacket[i]);
228 workingPtr->lock = 0; /* unlock the struct */
229 free(curPacket); /* free up full-packet buffer */
231 workingPtr = workingPtr->next;
234 /* purge sent commands from queue */
235 /* this may not always occur explicitly--i may put this on a timer later */
237 printf("calling aim_tx_purgequeue()\n");
241 printf("back from aim_tx_purgequeu() [you must be a lucky one]\n");
250 This is responsable for removing sent commands from the transmit
251 queue. This is not a required operation, but it of course helps
252 reduce memory footprint at run time!
255 int aim_tx_purgequeue(void)
257 struct command_tx_struct *workingPtr = NULL;
258 struct command_tx_struct *workingPtr2 = NULL;
260 printf("purgequeue(): starting purge\n");
262 /* Empty queue: nothing to do */
263 if (aim_queue_outgoing == NULL)
266 printf("purgequeue(): purge done (len=0)\n");
270 /* One Node queue: free node and return */
271 else if (aim_queue_outgoing->next == NULL)
274 printf("purgequeue(): entered case len=1\n");
276 /* only free if sent AND unlocked -- dont assume sent structs are done */
277 if ( (aim_queue_outgoing->lock == 0) &&
278 (aim_queue_outgoing->sent == 1) )
281 printf("purgequeue(): purging seqnum 0x%04x\n", aim_queue_outgoing->seqnum);
283 workingPtr2 = aim_queue_outgoing;
284 aim_queue_outgoing = NULL;
285 free(workingPtr2->data);
289 printf("purgequeue(): purge done (len=1)\n");
296 printf("purgequeue(): entering case len>1\n");
298 while(workingPtr->next != NULL)
300 if ( (workingPtr->next->lock == 0) &&
301 (workingPtr->next->sent == 1) )
304 printf("purgequeue(): purging seqnum 0x%04x\n", workingPtr->next->seqnum);
306 workingPtr2 = workingPtr->next;
307 workingPtr->next = workingPtr2->next;
308 free(workingPtr2->data);
313 printf("purgequeue(): purge done (len>1)\n");