]> andersk Git - libfaim.git/blob - aim_txqueue.c
- Sun Apr 2 07:29:11 UTC 2000
[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  * Allocate a new tx frame.
12  *
13  * This is more for looks than anything else.
14  *
15  * Right now, that is.  If/when we implement a pool of transmit
16  * frames, this will become the request-an-unused-frame part.
17  */
18 struct command_tx_struct *aim_tx_new(int chan, struct aim_conn_t *conn, int datalen)
19 {
20   struct command_tx_struct *new;
21
22   if (!conn)
23     return NULL;
24
25   new = (struct command_tx_struct *)malloc(sizeof(struct command_tx_struct));
26   if (!new)
27     return NULL;
28   memset(new, 0, sizeof(struct command_tx_struct));
29
30   new->conn = conn; 
31   new->type = chan;
32
33   if(datalen) {
34     new->data = (u_char *)malloc(datalen);
35     new->commandlen = datalen;
36   }
37
38   return new;
39 }
40
41 /*
42  * aim_tx_enqeue()
43  *
44  * The overall purpose here is to enqueue the passed in command struct
45  * into the outgoing (tx) queue.  Basically...
46  *   1) Make a scope-irrelevent copy of the struct
47  *   2) Lock the struct
48  *   3) Mark as not-sent-yet
49  *   4) Enqueue the struct into the list
50  *   5) Unlock the struct once it's linked in
51  *   6) Return
52  *
53  */
54 int aim_tx_enqueue(struct aim_session_t *sess,
55                    struct command_tx_struct *newpacket)
56 {
57   struct command_tx_struct *cur;
58
59   if (newpacket->conn == NULL) {
60       faimdprintf(1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n");
61       newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
62   }
63  
64   /* assign seqnum */
65   newpacket->seqnum = aim_get_next_txseqnum(newpacket->conn);
66   /* set some more fields */
67   newpacket->lock = 1; /* lock */
68   newpacket->sent = 0; /* not sent yet */
69   newpacket->next = NULL; /* always last */
70
71   /* see overhead note in aim_rxqueue counterpart */
72   if (sess->queue_outgoing == NULL) {
73     sess->queue_outgoing = newpacket;
74   } else {
75     for (cur = sess->queue_outgoing;
76          cur->next;
77          cur = cur->next)
78       ;
79     cur->next = newpacket;
80   }
81
82   newpacket->lock = 0; /* unlock so it can be sent */
83
84 #if debug == 2
85   faimdprintf(2, "calling aim_tx_printqueue()\n");
86   aim_tx_printqueue(sess);
87   faimdprintf(2, "back from aim_tx_printqueue()\n");
88 #endif
89
90   return 0;
91 }
92
93 /* 
94  *  aim_get_next_txseqnum()
95  *
96  *   This increments the tx command count, and returns the seqnum
97  *   that should be stamped on the next FLAP packet sent.  This is
98  *   normally called during the final step of packet preparation
99  *   before enqueuement (in aim_tx_enqueue()).
100  *
101  */
102 u_int aim_get_next_txseqnum(struct aim_conn_t *conn)
103 {
104   return ( ++conn->seqnum );
105 }
106
107 /*
108  *  aim_tx_printqueue()
109  *
110  *  This is basically for debuging purposes only.  It dumps all the
111  *  records in the tx queue and their current status.  Very helpful
112  *  if the queue isn't working quite right.
113  *
114  */
115 #if debug == 2
116 int aim_tx_printqueue(struct aim_session_t *sess)
117 {
118   struct command_tx_struct *cur;
119
120   faimdprintf(2, "\ncurrent aim_queue_outgoing...\n");
121   faimdprintf(2, "\ttype seqnum  len  lock sent\n");  
122
123   if (sess->queue_outgoing == NULL)
124     faimdprintf(2, "aim_tx_flushqueue(): queue empty");
125   else {
126       for (cur = sess->queue_outgoing; cur; cur = cur->next) {
127           faimdprintf(2, "\t  %2x   %4x %4x   %1d    %1d\n", 
128                       cur->type, cur->seqnum, 
129                       cur->commandlen, cur->lock, 
130                       cur->sent);
131       }
132   }
133
134   faimdprintf(2, "\n(done printing queue)\n");
135   
136   return 0;
137 }
138 #endif
139
140 /*
141  *  aim_tx_flushqueue()
142  *
143  *  This the function is responsable for putting the queued commands
144  *  onto the wire.  This function is critical to the operation of 
145  *  the queue and therefore is the most prone to brokenness.  It
146  *  seems to be working quite well at this point.
147  *
148  *  Procedure:
149  *    1) Traverse the list, only operate on commands that are unlocked
150  *       and haven't been sent yet.
151  *    2) Lock the struct
152  *    3) Allocate a temporary buffer to store the finished, fully
153  *       processed packet in.
154  *    4) Build the packet from the command_tx_struct data.
155  *    5) Write the packet to the socket.
156  *    6) If success, mark the packet sent, if fail report failure, do NOT
157  *       mark the packet sent (so it will not get purged and therefore
158  *       be attempted again on next call).
159  *    7) Unlock the struct.
160  *    8) Free the temp buffer
161  *    9) Step to next struct in list and go back to 1.
162  *
163  */
164 int aim_tx_flushqueue(struct aim_session_t *sess)
165 {
166   struct command_tx_struct *cur;
167   u_char *curPacket = NULL;
168 #if debug > 1
169   int i = 0;
170 #endif
171
172   if (sess->queue_outgoing == NULL)
173     return 0;
174
175   faimdprintf(2, "beginning txflush...\n");
176   for (cur = sess->queue_outgoing; cur; cur = cur->next) {
177     /* only process if its unlocked and unsent */
178     if (!cur->lock && !cur->sent) {
179
180       /*
181        * And now for the meager attempt to force transmit
182        * latency and avoid missed messages.
183        */
184       if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) {
185         /* FIXME FIXME -- should be a break! we dont want to block the upper layers */
186         sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL));
187       }
188       
189       cur->lock = 1; /* lock the struct */
190       
191       /* allocate full-packet buffer */
192       curPacket = (char *) malloc(cur->commandlen + 6);
193       
194       /* command byte */
195       curPacket[0] = 0x2a;
196       
197       /* type/family byte */
198       curPacket[1] = cur->type;
199       
200       /* bytes 3+4: word: FLAP sequence number */
201       aimutil_put16(curPacket+2, cur->seqnum);
202
203       /* bytes 5+6: word: SNAC len */
204       aimutil_put16(curPacket+4, cur->commandlen);
205       
206       /* bytes 7 and on: raw: SNAC data */
207       memcpy(&(curPacket[6]), cur->data, cur->commandlen);
208       
209       /* full image of raw packet data now in curPacket */
210       if ( (u_int)write(cur->conn->fd, curPacket, (cur->commandlen + 6)) != (cur->commandlen + 6)) {
211         printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", cur->seqnum);
212         cur->sent = 0; /* mark it unsent */
213         continue; /* bail out */
214       } else {
215         faimdprintf(2, "\nSENT 0x%4x\n\n", cur->seqnum);
216
217         cur->sent = 1; /* mark the struct as sent */
218         cur->conn->lastactivity = time(NULL);
219       }
220 #if debug > 2
221       faimdprintf(2, "\nPacket:");
222       for (i = 0; i < (cur->commandlen + 6); i++) {
223         if ((i % 8) == 0) {
224           faimdprintf(2, "\n\t");
225         }
226         if (curPacket[i] >= ' ' && curPacket[i]<127) {
227           faimdprintf(2, "%c=%02x ", curPacket[i], curPacket[i]);
228         } else {
229           faimdprintf(2, "0x%2x ", curPacket[i]);
230         }
231       }
232       faimdprintf(2, "\n");
233 #endif
234       cur->lock = 0; /* unlock the struct */
235       free(curPacket); /* free up full-packet buffer */
236     }
237   }
238
239   /* purge sent commands from queue */
240   aim_tx_purgequeue(sess);
241
242   return 0;
243 }
244
245 /*
246  *  aim_tx_purgequeue()
247  *  
248  *  This is responsable for removing sent commands from the transmit 
249  *  queue. This is not a required operation, but it of course helps
250  *  reduce memory footprint at run time!  
251  *
252  */
253 void aim_tx_purgequeue(struct aim_session_t *sess)
254 {
255   struct command_tx_struct *cur = NULL;
256   struct command_tx_struct *tmp;
257
258   if (sess->queue_outgoing == NULL)
259     return;
260   
261   if (sess->queue_outgoing->next == NULL) {
262     if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) {
263       tmp = sess->queue_outgoing;
264       sess->queue_outgoing = NULL;
265       free(tmp->data);
266       free(tmp);
267     }
268     return;
269   }
270
271   for(cur = sess->queue_outgoing; cur->next != NULL; ) {
272     if (!cur->next->lock && cur->next->sent) {
273       tmp = cur->next;
274       cur->next = tmp->next;
275       free(tmp->data);
276       free(tmp);
277     }   
278     cur = cur->next;
279
280     /* 
281      * Be careful here.  Because of the way we just
282      * manipulated the pointer, cur may be NULL and 
283      * the for() will segfault doing the check unless
284      * we find this case first.
285      */
286     if (cur == NULL)    
287       break;
288   }
289   return;
290 }
This page took 0.060106 seconds and 5 git commands to generate.