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