]> andersk Git - libfaim.git/blob - aim_txqueue.c
8a42e333e2a06af6a6309085f881182d3ee7183a
[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 int aim_tx_enqueue(struct aim_session_t *sess,
24                    struct command_tx_struct *newpacket)
25 {
26   struct command_tx_struct *cur;
27   struct command_tx_struct *newpacket_copy = NULL;
28
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);
32   }
33  
34   newpacket_copy = (struct command_tx_struct *) malloc (sizeof(struct command_tx_struct));
35   memcpy(newpacket_copy, newpacket, sizeof(struct command_tx_struct));
36
37   /* assign seqnum */
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 */
43
44   /* see overhead note in aim_rxqueue counterpart */
45   if (sess->queue_outgoing == NULL) {
46     sess->queue_outgoing = newpacket_copy;
47   } else {
48     for (cur = sess->queue_outgoing;
49          cur->next;
50          cur = cur->next)
51       ;
52     cur->next = newpacket_copy;
53   }
54
55   newpacket_copy->lock = 0; /* unlock so it can be sent */
56
57 #if debug == 2
58   faimdprintf(2, "calling aim_tx_printqueue()\n");
59   aim_tx_printqueue(sess);
60   faimdprintf(2, "back from aim_tx_printqueue()\n");
61 #endif
62
63   return 0;
64 }
65
66 /* 
67  *  aim_get_next_txseqnum()
68  *
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()).
73  *
74  */
75 u_int aim_get_next_txseqnum(struct aim_conn_t *conn)
76 {
77   return ( ++conn->seqnum );
78 }
79
80 /*
81  *  aim_tx_printqueue()
82  *
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.
86  *
87  */
88 #if debug == 2
89 int aim_tx_printqueue(struct aim_session_t *sess)
90 {
91   struct command_tx_struct *cur;
92
93   faimdprintf(2, "\ncurrent aim_queue_outgoing...\n");
94   faimdprintf(2, "\ttype seqnum  len  lock sent\n");  
95
96   if (sess->queue_outgoing == NULL)
97     faimdprintf(2, "aim_tx_flushqueue(): queue empty");
98   else {
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, 
103                       cur->sent);
104       }
105   }
106
107   faimdprintf(2, "\n(done printing queue)\n");
108   
109   return 0;
110 }
111 #endif
112
113 /*
114  *  aim_tx_flushqueue()
115  *
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.
120  *
121  *  Procedure:
122  *    1) Traverse the list, only operate on commands that are unlocked
123  *       and haven't been sent yet.
124  *    2) Lock the struct
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.
135  *
136  */
137 int aim_tx_flushqueue(struct aim_session_t *sess)
138 {
139   struct command_tx_struct *cur;
140   u_char *curPacket = NULL;
141 #if debug > 1
142   int i = 0;
143 #endif
144
145   if (sess->queue_outgoing == NULL)
146     return 0;
147
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) {
152
153       /*
154        * And now for the meager attempt to force transmit
155        * latency and avoid missed messages.
156        */
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));
160       }
161       
162       cur->lock = 1; /* lock the struct */
163       
164       /* allocate full-packet buffer */
165       curPacket = (char *) malloc(cur->commandlen + 6);
166       
167       /* command byte */
168       curPacket[0] = 0x2a;
169       
170       /* type/family byte */
171       curPacket[1] = cur->type;
172       
173       /* bytes 3+4: word: FLAP sequence number */
174       aimutil_put16(curPacket+2, cur->seqnum);
175
176       /* bytes 5+6: word: SNAC len */
177       aimutil_put16(curPacket+4, cur->commandlen);
178       
179       /* bytes 7 and on: raw: SNAC data */
180       memcpy(&(curPacket[6]), cur->data, cur->commandlen);
181       
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 */
187       } else {
188         faimdprintf(2, "\nSENT 0x%4x\n\n", cur->seqnum);
189
190         cur->sent = 1; /* mark the struct as sent */
191         cur->conn->lastactivity = time(NULL);
192       }
193 #if debug > 2
194       faimdprintf(2, "\nPacket:");
195       for (i = 0; i < (cur->commandlen + 6); i++) {
196         if ((i % 8) == 0) {
197           faimdprintf(2, "\n\t");
198         }
199         if (curPacket[i] >= ' ' && curPacket[i]<127) {
200           faimdprintf(2, "%c=%02x ", curPacket[i], curPacket[i]);
201         } else {
202           faimdprintf(2, "0x%2x ", curPacket[i]);
203         }
204       }
205       faimdprintf(2, "\n");
206 #endif
207       cur->lock = 0; /* unlock the struct */
208       free(curPacket); /* free up full-packet buffer */
209     }
210   }
211
212   /* purge sent commands from queue */
213   aim_tx_purgequeue(sess);
214
215   return 0;
216 }
217
218 /*
219  *  aim_tx_purgequeue()
220  *  
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!  
224  *
225  */
226 void aim_tx_purgequeue(struct aim_session_t *sess)
227 {
228   struct command_tx_struct *cur = NULL;
229   struct command_tx_struct *tmp;
230
231   if (sess->queue_outgoing == NULL)
232     return;
233   
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;
238       free(tmp->data);
239       free(tmp);
240     }
241     return;
242   }
243
244   for(cur = sess->queue_outgoing; cur->next != NULL; ) {
245     if (!cur->next->lock && cur->next->sent) {
246       tmp = cur->next;
247       cur->next = tmp->next;
248       free(tmp->data);
249       free(tmp);
250     }   
251     cur = cur->next;
252
253     /* 
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.
258      */
259     if (cur == NULL)    
260       break;
261   }
262   return;
263 }
This page took 0.55461 seconds and 3 git commands to generate.