]> andersk Git - libfaim.git/blame - aim_txqueue.c
Added stubs for those capability TLVs in userinfo.
[libfaim.git] / aim_txqueue.c
CommitLineData
9de3ca7e 1/*
24286d93 2 * aim_txqueue.c
3 *
4 * Herein lies all the mangement routines for the transmit (Tx) queue.
5 *
9de3ca7e 6 */
7
a25832e6 8#include <faim/aim.h>
9de3ca7e 9
10/*
24286d93 11 * aim_tx_enqeue()
12 *
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
16 * 2) Lock 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
20 * 6) Return
21 *
9de3ca7e 22 */
23
a25832e6 24int aim_tx_enqueue(struct aim_session_t *sess,
25 struct command_tx_struct *newpacket)
9de3ca7e 26{
27 struct command_tx_struct *workingPtr = NULL;
28 struct command_tx_struct *newpacket_copy = NULL;
29
30 if (newpacket->conn == NULL)
31 {
32 printf("aim_tx_enqueue: WARNING: enqueueing packet with no connecetion, defaulting to BOS\n");
a25832e6 33 newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
9de3ca7e 34 }
35
36 newpacket_copy = (struct command_tx_struct *) malloc (sizeof(struct command_tx_struct));
37 memcpy(newpacket_copy, newpacket, sizeof(struct command_tx_struct));
38
39 /* assign seqnum */
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 */
45
a25832e6 46 if (sess->queue_outgoing == NULL)
9de3ca7e 47 {
a25832e6 48 sess->queue_outgoing = newpacket_copy;
9de3ca7e 49 }
50 else
51 {
a25832e6 52 workingPtr = sess->queue_outgoing;
9de3ca7e 53 while (workingPtr->next != NULL)
54 workingPtr = workingPtr->next;
55 workingPtr->next = newpacket_copy;
56 }
57
58 newpacket_copy->lock = 0; /* unlock so it can be sent */
59
60#if debug > 2
61 printf("calling aim_tx_printqueue()\n");
62 aim_tx_printqueue();
63 printf("back from aim_tx_printqueue()\n");
64#endif
65
66 /* we'll force a flush for now -- this behavior probably will change */
67#if debug > 1
68 printf("calling aim_tx_flushqueue()\n");
69#endif
a25832e6 70 aim_tx_flushqueue(sess);
9de3ca7e 71#if debug > 1
72 printf("back from aim_tx_flushqueue()\n");
73#endif
74
75 return 0;
76}
77
78/*
a25832e6 79 * aim_get_next_txseqnum()
80 *
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()).
85 *
9de3ca7e 86 */
87u_int aim_get_next_txseqnum(struct aim_conn_t *conn)
88{
89 return ( ++conn->seqnum );
90}
91
92/*
a25832e6 93 * aim_tx_printqueue()
94 *
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.
98 *
9de3ca7e 99 */
100#if debug > 2
101int aim_tx_printqueue(void)
102{
103 struct command_tx_struct *workingPtr = NULL;
104
a25832e6 105 workingPtr = sess->queue_outgoing;
9de3ca7e 106#if debug > 2
107 printf("\ncurrent aim_queue_outgoing...\n");
108 printf("\ttype seqnum len lock sent\n");
109#endif
110 if (workingPtr == NULL)
111 printf("aim_tx_flushqueue(): queue empty");
112 else
113 {
114 while (workingPtr != NULL)
115 {
116 printf("\t %2x %4x %4x %1d %1d\n", workingPtr->type, workingPtr->seqnum, workingPtr->commandlen, workingPtr->lock, workingPtr->sent);
117
118 workingPtr = workingPtr->next;
119 }
120 }
121
122 printf("\n(done printing queue)\n");
123
124 return 0;
125}
126#endif
127
128/*
a25832e6 129 * aim_tx_flushqueue()
130 *
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.
135 *
136 * Procedure:
137 * 1) Traverse the list, only operate on commands that are unlocked
138 * and haven't been sent yet.
139 * 2) Lock the struct
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.
150 *
9de3ca7e 151 */
a25832e6 152int aim_tx_flushqueue(struct aim_session_t *sess)
9de3ca7e 153{
154 struct command_tx_struct *workingPtr = NULL;
155 u_char *curPacket = NULL;
156#if debug > 1
157 int i = 0;
158#endif
159
a25832e6 160 workingPtr = sess->queue_outgoing;
9de3ca7e 161#if debug > 1
162 printf("beginning txflush...\n");
163#endif
164 while (workingPtr != NULL)
165 {
166 /* only process if its unlocked and unsent */
167 if ( (workingPtr->lock == 0) &&
168 (workingPtr->sent == 0) )
169 {
170
171 /*
172 * And now for the meager attempt to force transmit
173 * latency and avoid missed messages.
174 */
175 if ((workingPtr->conn->lastactivity + workingPtr->conn->forcedlatency)
176 >= time(NULL))
177 {
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));
180 }
181
182 workingPtr->lock = 1; /* lock the struct */
183
184 /* allocate full-packet buffer */
185 curPacket = (char *) malloc(workingPtr->commandlen + 6);
186
187 /* command byte */
188 curPacket[0] = 0x2a;
a25832e6 189
9de3ca7e 190 /* type/family byte */
191 curPacket[1] = workingPtr->type;
a25832e6 192
9de3ca7e 193 /* bytes 3+4: word: FLAP sequence number */
a25832e6 194 aimutil_put16(curPacket+2, workingPtr->seqnum);
195
9de3ca7e 196 /* bytes 5+6: word: SNAC len */
a25832e6 197 aimutil_put16(curPacket+4, workingPtr->commandlen);
198
9de3ca7e 199 /* bytes 7 and on: raw: SNAC data */
200 memcpy(&(curPacket[6]), workingPtr->data, workingPtr->commandlen);
201
202 /* full image of raw packet data now in curPacket */
9de3ca7e 203 if ( (u_int)write(workingPtr->conn->fd, curPacket, (workingPtr->commandlen + 6)) != (workingPtr->commandlen + 6))
204 {
9de3ca7e 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 */
208 }
209 else
210 {
211#if debug > 2
212 printf("\nSENT 0x%4x\n\n", workingPtr->seqnum);
213#endif
214 workingPtr->sent = 1; /* mark the struct as sent */
215 workingPtr->conn->lastactivity = time(NULL);
216 }
217#if debug > 2
218 printf("\nPacket:");
219 for (i = 0; i < (workingPtr->commandlen + 6); i++)
220 {
221 if ((i % 8) == 0)
222 printf("\n\t");
223 if (curPacket[i] >= ' ' && curPacket[i]<127)
224 printf("%c=%02x ",curPacket[i], curPacket[i]);
225 else
226 printf("0x%2x ", curPacket[i]);
227 }
228 printf("\n");
229#endif
230 workingPtr->lock = 0; /* unlock the struct */
231 free(curPacket); /* free up full-packet buffer */
232 }
233 workingPtr = workingPtr->next;
234 }
235
236 /* purge sent commands from queue */
237 /* this may not always occur explicitly--i may put this on a timer later */
238#if debug > 1
239 printf("calling aim_tx_purgequeue()\n");
240#endif
a25832e6 241 aim_tx_purgequeue(sess);
9de3ca7e 242#if debug > 1
243 printf("back from aim_tx_purgequeu() [you must be a lucky one]\n");
244#endif
245
246 return 0;
247}
248
249/*
a25832e6 250 * aim_tx_purgequeue()
251 *
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!
255 *
9de3ca7e 256 */
a25832e6 257int aim_tx_purgequeue(struct aim_session_t *sess)
9de3ca7e 258{
259 struct command_tx_struct *workingPtr = NULL;
260 struct command_tx_struct *workingPtr2 = NULL;
261#if debug > 1
262 printf("purgequeue(): starting purge\n");
263#endif
264 /* Empty queue: nothing to do */
a25832e6 265 if (sess->queue_outgoing == NULL)
9de3ca7e 266 {
267#if debug > 1
268 printf("purgequeue(): purge done (len=0)\n");
269#endif
270 return 0;
271 }
272 /* One Node queue: free node and return */
a25832e6 273 else if (sess->queue_outgoing->next == NULL)
9de3ca7e 274 {
275#if debug > 1
276 printf("purgequeue(): entered case len=1\n");
277#endif
278 /* only free if sent AND unlocked -- dont assume sent structs are done */
a25832e6 279 if ( (sess->queue_outgoing->lock == 0) &&
280 (sess->queue_outgoing->sent == 1) )
9de3ca7e 281 {
282#if debug > 1
283 printf("purgequeue(): purging seqnum 0x%04x\n", aim_queue_outgoing->seqnum);
284#endif
a25832e6 285 workingPtr2 = sess->queue_outgoing;
286 sess->queue_outgoing = NULL;
9de3ca7e 287 free(workingPtr2->data);
288 free(workingPtr2);
289 }
290#if debug > 1
291 printf("purgequeue(): purge done (len=1)\n");
292#endif
293 return 0;
294 }
295 else
296 {
297#if debug > 1
298 printf("purgequeue(): entering case len>1\n");
299#endif
300 while(workingPtr->next != NULL)
301 {
302 if ( (workingPtr->next->lock == 0) &&
303 (workingPtr->next->sent == 1) )
304 {
305#if debug > 1
306 printf("purgequeue(): purging seqnum 0x%04x\n", workingPtr->next->seqnum);
307#endif
308 workingPtr2 = workingPtr->next;
309 workingPtr->next = workingPtr2->next;
310 free(workingPtr2->data);
311 free(workingPtr2);
312 }
313 }
314#if debug > 1
315 printf("purgequeue(): purge done (len>1)\n");
316#endif
317 return 0;
318 }
319
320 /* no reach */
321}
This page took 0.14285 seconds and 5 git commands to generate.