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 aim_session_t *sess,
25 struct command_tx_struct *newpacket)
27 struct command_tx_struct *workingPtr = NULL;
28 struct command_tx_struct *newpacket_copy = NULL;
30 if (newpacket->conn == NULL)
32 printf("aim_tx_enqueue: WARNING: enqueueing packet with no connecetion, defaulting to BOS\n");
33 newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
36 newpacket_copy = (struct command_tx_struct *) malloc (sizeof(struct command_tx_struct));
37 memcpy(newpacket_copy, newpacket, sizeof(struct command_tx_struct));
40 newpacket_copy->seqnum = aim_get_next_txseqnum(newpacket_copy->conn);
41 /* set some more fields */
42 newpacket_copy->lock = 1; /* lock */
43 newpacket_copy->sent = 0; /* not sent yet */
44 newpacket_copy->next = NULL; /* always last */
46 if (sess->queue_outgoing == NULL)
48 sess->queue_outgoing = newpacket_copy;
52 workingPtr = sess->queue_outgoing;
53 while (workingPtr->next != NULL)
54 workingPtr = workingPtr->next;
55 workingPtr->next = newpacket_copy;
58 newpacket_copy->lock = 0; /* unlock so it can be sent */
61 printf("calling aim_tx_printqueue()\n");
63 printf("back from aim_tx_printqueue()\n");
66 /* we'll force a flush for now -- this behavior probably will change */
68 printf("calling aim_tx_flushqueue()\n");
70 aim_tx_flushqueue(sess);
72 printf("back from aim_tx_flushqueue()\n");
79 * aim_get_next_txseqnum()
81 * This increments the tx command count, and returns the seqnum
82 * that should be stamped on the next FLAP packet sent. This is
83 * normally called during the final step of packet preparation
84 * before enqueuement (in aim_tx_enqueue()).
87 u_int aim_get_next_txseqnum(struct aim_conn_t *conn)
89 return ( ++conn->seqnum );
95 * This is basically for debuging purposes only. It dumps all the
96 * records in the tx queue and their current status. Very helpful
97 * if the queue isn't working quite right.
101 int aim_tx_printqueue(void)
103 struct command_tx_struct *workingPtr = NULL;
105 workingPtr = sess->queue_outgoing;
107 printf("\ncurrent aim_queue_outgoing...\n");
108 printf("\ttype seqnum len lock sent\n");
110 if (workingPtr == NULL)
111 printf("aim_tx_flushqueue(): queue empty");
114 while (workingPtr != NULL)
116 printf("\t %2x %4x %4x %1d %1d\n", workingPtr->type, workingPtr->seqnum, workingPtr->commandlen, workingPtr->lock, workingPtr->sent);
118 workingPtr = workingPtr->next;
122 printf("\n(done printing queue)\n");
129 * aim_tx_flushqueue()
131 * This the function is responsable for putting the queued commands
132 * onto the wire. This function is critical to the operation of
133 * the queue and therefore is the most prone to brokenness. It
134 * seems to be working quite well at this point.
137 * 1) Traverse the list, only operate on commands that are unlocked
138 * and haven't been sent yet.
140 * 3) Allocate a temporary buffer to store the finished, fully
141 * processed packet in.
142 * 4) Build the packet from the command_tx_struct data.
143 * 5) Write the packet to the socket.
144 * 6) If success, mark the packet sent, if fail report failure, do NOT
145 * mark the packet sent (so it will not get purged and therefore
146 * be attempted again on next call).
147 * 7) Unlock the struct.
148 * 8) Free the temp buffer
149 * 9) Step to next struct in list and go back to 1.
152 int aim_tx_flushqueue(struct aim_session_t *sess)
154 struct command_tx_struct *workingPtr = NULL;
155 u_char *curPacket = NULL;
160 workingPtr = sess->queue_outgoing;
162 printf("beginning txflush...\n");
164 while (workingPtr != NULL)
166 /* only process if its unlocked and unsent */
167 if ( (workingPtr->lock == 0) &&
168 (workingPtr->sent == 0) )
172 * And now for the meager attempt to force transmit
173 * latency and avoid missed messages.
175 if ((workingPtr->conn->lastactivity + workingPtr->conn->forcedlatency)
178 /* FIXME FIXME -- should be a break! we dont want to block the upper layers */
179 sleep((workingPtr->conn->lastactivity + workingPtr->conn->forcedlatency) - time(NULL));
182 workingPtr->lock = 1; /* lock the struct */
184 /* allocate full-packet buffer */
185 curPacket = (char *) malloc(workingPtr->commandlen + 6);
190 /* type/family byte */
191 curPacket[1] = workingPtr->type;
193 /* bytes 3+4: word: FLAP sequence number */
194 aimutil_put16(curPacket+2, workingPtr->seqnum);
196 /* bytes 5+6: word: SNAC len */
197 aimutil_put16(curPacket+4, workingPtr->commandlen);
199 /* bytes 7 and on: raw: SNAC data */
200 memcpy(&(curPacket[6]), workingPtr->data, workingPtr->commandlen);
202 /* full image of raw packet data now in curPacket */
203 if ( (u_int)write(workingPtr->conn->fd, curPacket, (workingPtr->commandlen + 6)) != (workingPtr->commandlen + 6))
205 printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", workingPtr->seqnum);
206 workingPtr->sent = 0; /* mark it unsent */
207 return -1; /* bail out */
212 printf("\nSENT 0x%4x\n\n", workingPtr->seqnum);
214 workingPtr->sent = 1; /* mark the struct as sent */
215 workingPtr->conn->lastactivity = time(NULL);
219 for (i = 0; i < (workingPtr->commandlen + 6); i++)
223 if (curPacket[i] >= ' ' && curPacket[i]<127)
224 printf("%c=%02x ",curPacket[i], curPacket[i]);
226 printf("0x%2x ", curPacket[i]);
230 workingPtr->lock = 0; /* unlock the struct */
231 free(curPacket); /* free up full-packet buffer */
233 workingPtr = workingPtr->next;
236 /* purge sent commands from queue */
237 /* this may not always occur explicitly--i may put this on a timer later */
239 printf("calling aim_tx_purgequeue()\n");
241 aim_tx_purgequeue(sess);
243 printf("back from aim_tx_purgequeu() [you must be a lucky one]\n");
250 * aim_tx_purgequeue()
252 * This is responsable for removing sent commands from the transmit
253 * queue. This is not a required operation, but it of course helps
254 * reduce memory footprint at run time!
257 int aim_tx_purgequeue(struct aim_session_t *sess)
259 struct command_tx_struct *workingPtr = NULL;
260 struct command_tx_struct *workingPtr2 = NULL;
262 printf("purgequeue(): starting purge\n");
264 /* Empty queue: nothing to do */
265 if (sess->queue_outgoing == NULL)
268 printf("purgequeue(): purge done (len=0)\n");
272 /* One Node queue: free node and return */
273 else if (sess->queue_outgoing->next == NULL)
276 printf("purgequeue(): entered case len=1\n");
278 /* only free if sent AND unlocked -- dont assume sent structs are done */
279 if ( (sess->queue_outgoing->lock == 0) &&
280 (sess->queue_outgoing->sent == 1) )
283 printf("purgequeue(): purging seqnum 0x%04x\n", aim_queue_outgoing->seqnum);
285 workingPtr2 = sess->queue_outgoing;
286 sess->queue_outgoing = NULL;
287 free(workingPtr2->data);
291 printf("purgequeue(): purge done (len=1)\n");
298 printf("purgequeue(): entering case len>1\n");
300 while(workingPtr->next != NULL)
302 if ( (workingPtr->next->lock == 0) &&
303 (workingPtr->next->sent == 1) )
306 printf("purgequeue(): purging seqnum 0x%04x\n", workingPtr->next->seqnum);
308 workingPtr2 = workingPtr->next;
309 workingPtr->next = workingPtr2->next;
310 free(workingPtr2->data);
315 printf("purgequeue(): purge done (len>1)\n");