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
23 int aim_tx_enqueue(struct aim_session_t *sess,
24 struct command_tx_struct *newpacket)
26 struct command_tx_struct *cur;
27 struct command_tx_struct *newpacket_copy = NULL;
29 if (newpacket->conn == NULL) {
30 faimdprintf(1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion, defaulting to BOS\n");
31 newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
34 newpacket_copy = (struct command_tx_struct *) malloc (sizeof(struct command_tx_struct));
35 memcpy(newpacket_copy, newpacket, sizeof(struct command_tx_struct));
38 newpacket_copy->seqnum = aim_get_next_txseqnum(newpacket_copy->conn);
39 /* set some more fields */
40 newpacket_copy->lock = 1; /* lock */
41 newpacket_copy->sent = 0; /* not sent yet */
42 newpacket_copy->next = NULL; /* always last */
44 /* see overhead note in aim_rxqueue counterpart */
45 if (sess->queue_outgoing == NULL) {
46 sess->queue_outgoing = newpacket_copy;
48 for (cur = sess->queue_outgoing;
52 cur->next = newpacket_copy;
55 newpacket_copy->lock = 0; /* unlock so it can be sent */
58 faimdprintf(2, "calling aim_tx_printqueue()\n");
59 aim_tx_printqueue(sess);
60 faimdprintf(2, "back from aim_tx_printqueue()\n");
67 * aim_get_next_txseqnum()
69 * This increments the tx command count, and returns the seqnum
70 * that should be stamped on the next FLAP packet sent. This is
71 * normally called during the final step of packet preparation
72 * before enqueuement (in aim_tx_enqueue()).
75 u_int aim_get_next_txseqnum(struct aim_conn_t *conn)
77 return ( ++conn->seqnum );
83 * This is basically for debuging purposes only. It dumps all the
84 * records in the tx queue and their current status. Very helpful
85 * if the queue isn't working quite right.
89 int aim_tx_printqueue(struct aim_session_t *sess)
91 struct command_tx_struct *cur;
93 faimdprintf(2, "\ncurrent aim_queue_outgoing...\n");
94 faimdprintf(2, "\ttype seqnum len lock sent\n");
96 if (sess->queue_outgoing == NULL)
97 faimdprintf(2, "aim_tx_flushqueue(): queue empty");
99 for (cur = sess->queue_outgoing; cur; cur = cur->next) {
100 faimdprintf(2, "\t %2x %4x %4x %1d %1d\n",
101 cur->type, cur->seqnum,
102 cur->commandlen, cur->lock,
107 faimdprintf(2, "\n(done printing queue)\n");
114 * aim_tx_flushqueue()
116 * This the function is responsable for putting the queued commands
117 * onto the wire. This function is critical to the operation of
118 * the queue and therefore is the most prone to brokenness. It
119 * seems to be working quite well at this point.
122 * 1) Traverse the list, only operate on commands that are unlocked
123 * and haven't been sent yet.
125 * 3) Allocate a temporary buffer to store the finished, fully
126 * processed packet in.
127 * 4) Build the packet from the command_tx_struct data.
128 * 5) Write the packet to the socket.
129 * 6) If success, mark the packet sent, if fail report failure, do NOT
130 * mark the packet sent (so it will not get purged and therefore
131 * be attempted again on next call).
132 * 7) Unlock the struct.
133 * 8) Free the temp buffer
134 * 9) Step to next struct in list and go back to 1.
137 int aim_tx_flushqueue(struct aim_session_t *sess)
139 struct command_tx_struct *cur;
140 u_char *curPacket = NULL;
145 if (sess->queue_outgoing == NULL)
148 faimdprintf(2, "beginning txflush...\n");
149 for (cur = sess->queue_outgoing; cur; cur = cur->next) {
150 /* only process if its unlocked and unsent */
151 if (!cur->lock && !cur->sent) {
154 * And now for the meager attempt to force transmit
155 * latency and avoid missed messages.
157 if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) {
158 /* FIXME FIXME -- should be a break! we dont want to block the upper layers */
159 sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL));
162 cur->lock = 1; /* lock the struct */
164 /* allocate full-packet buffer */
165 curPacket = (char *) malloc(cur->commandlen + 6);
170 /* type/family byte */
171 curPacket[1] = cur->type;
173 /* bytes 3+4: word: FLAP sequence number */
174 aimutil_put16(curPacket+2, cur->seqnum);
176 /* bytes 5+6: word: SNAC len */
177 aimutil_put16(curPacket+4, cur->commandlen);
179 /* bytes 7 and on: raw: SNAC data */
180 memcpy(&(curPacket[6]), cur->data, cur->commandlen);
182 /* full image of raw packet data now in curPacket */
183 if ( (u_int)write(cur->conn->fd, curPacket, (cur->commandlen + 6)) != (cur->commandlen + 6)) {
184 printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", cur->seqnum);
185 cur->sent = 0; /* mark it unsent */
186 continue; /* bail out */
188 faimdprintf(2, "\nSENT 0x%4x\n\n", cur->seqnum);
190 cur->sent = 1; /* mark the struct as sent */
191 cur->conn->lastactivity = time(NULL);
194 faimdprintf(2, "\nPacket:");
195 for (i = 0; i < (cur->commandlen + 6); i++) {
197 faimdprintf(2, "\n\t");
199 if (curPacket[i] >= ' ' && curPacket[i]<127) {
200 faimdprintf(2, "%c=%02x ", curPacket[i], curPacket[i]);
202 faimdprintf(2, "0x%2x ", curPacket[i]);
205 faimdprintf(2, "\n");
207 cur->lock = 0; /* unlock the struct */
208 free(curPacket); /* free up full-packet buffer */
212 /* purge sent commands from queue */
213 aim_tx_purgequeue(sess);
219 * aim_tx_purgequeue()
221 * This is responsable for removing sent commands from the transmit
222 * queue. This is not a required operation, but it of course helps
223 * reduce memory footprint at run time!
226 void aim_tx_purgequeue(struct aim_session_t *sess)
228 struct command_tx_struct *cur = NULL;
229 struct command_tx_struct *tmp;
231 if (sess->queue_outgoing == NULL)
234 if (sess->queue_outgoing->next == NULL) {
235 if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) {
236 tmp = sess->queue_outgoing;
237 sess->queue_outgoing = NULL;
244 for(cur = sess->queue_outgoing; cur->next != NULL; ) {
245 if (!cur->next->lock && cur->next->sent) {
247 cur->next = tmp->next;
254 * Be careful here. Because of the way we just
255 * manipulated the pointer, cur may be NULL and
256 * the for() will segfault doing the check unless
257 * we find this case first.