comparison libfaim/aim_txqueue.c @ 237:6ced2f1c8b24

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