]> andersk Git - libfaim.git/blob - aim_txqueue.c
Integrated session changes needed for Jabber transport. Lots of changes.
[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 <faim/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 aim_session_t *sess,
25                    struct command_tx_struct *newpacket)
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");
33       newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
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
46   if (sess->queue_outgoing == NULL)
47     {
48       sess->queue_outgoing = newpacket_copy;
49     }
50   else
51     {
52       workingPtr = sess->queue_outgoing;
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
70   aim_tx_flushqueue(sess);
71 #if debug > 1
72   printf("back from aim_tx_flushqueue()\n");
73 #endif
74
75   return 0;
76 }
77
78 /* 
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  *
86  */
87 u_int aim_get_next_txseqnum(struct aim_conn_t *conn)
88 {
89   return ( ++conn->seqnum );
90 }
91
92 /*
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  *
99  */
100 #if debug > 2
101 int aim_tx_printqueue(void)
102 {
103   struct command_tx_struct *workingPtr = NULL;
104
105   workingPtr = sess->queue_outgoing;
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 /*
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  *
151  */
152 int aim_tx_flushqueue(struct aim_session_t *sess)
153 {
154   struct command_tx_struct *workingPtr = NULL;
155   u_char *curPacket = NULL;
156 #if debug > 1
157   int i = 0;
158 #endif
159
160   workingPtr = sess->queue_outgoing;
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;
189
190           /* type/family byte */
191           curPacket[1] = workingPtr->type;
192
193           /* bytes 3+4: word: FLAP sequence number */
194           aimutil_put16(curPacket+2, workingPtr->seqnum);
195
196           /* bytes 5+6: word: SNAC len */
197           aimutil_put16(curPacket+4, workingPtr->commandlen);
198
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 */
203           if ( (u_int)write(workingPtr->conn->fd, curPacket, (workingPtr->commandlen + 6)) != (workingPtr->commandlen + 6))
204             {
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
241   aim_tx_purgequeue(sess);
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 /*
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  *
256  */
257 int aim_tx_purgequeue(struct aim_session_t *sess)
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 */
265   if (sess->queue_outgoing == NULL)
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 */
273   else if (sess->queue_outgoing->next == NULL)
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 */
279       if ( (sess->queue_outgoing->lock == 0) &&
280            (sess->queue_outgoing->sent == 1) )
281         {
282 #if debug > 1
283           printf("purgequeue(): purging seqnum 0x%04x\n", aim_queue_outgoing->seqnum);
284 #endif
285           workingPtr2 = sess->queue_outgoing;
286           sess->queue_outgoing = NULL;
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.081474 seconds and 5 git commands to generate.