comparison src/protocols/oscar/txqueue.c @ 2246:933346315b9b

[gaim-migrate @ 2256] heh. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sun, 09 Sep 2001 10:07:14 +0000
parents 424a40f12a6c
children d82efea341ef
comparison
equal deleted inserted replaced
2245:31157c54fe6e 2246:933346315b9b
18 * This is more for looks than anything else. 18 * This is more for looks than anything else.
19 * 19 *
20 * Right now, that is. If/when we implement a pool of transmit 20 * Right now, that is. If/when we implement a pool of transmit
21 * frames, this will become the request-an-unused-frame part. 21 * frames, this will become the request-an-unused-frame part.
22 * 22 *
23 * framing = AIM_FRAMETYPE_OFT/OSCAR 23 * framing = AIM_FRAMETYPE_OFT/FLAP
24 * chan = channel for OSCAR, hdrtype for OFT 24 * chan = channel for FLAP, hdrtype for OFT
25 * 25 *
26 */ 26 */
27 faim_internal struct command_tx_struct *aim_tx_new(struct aim_session_t *sess, 27 faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen)
28 struct aim_conn_t *conn, 28 {
29 unsigned char framing, 29 aim_frame_t *fr;
30 int chan, 30
31 int datalen) 31 if (!conn) {
32 { 32 faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n");
33 struct command_tx_struct *newtx; 33 return NULL;
34 34 }
35 if (!conn) { 35
36 faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n"); 36 /* For sanity... */
37 return NULL; 37 if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) ||
38 } 38 (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)) {
39 39 if (framing != AIM_FRAMETYPE_OFT) {
40 /* For sanity... */ 40 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n");
41 if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) || (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)) { 41 return NULL;
42 if (framing != AIM_FRAMETYPE_OFT) { 42 }
43 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n"); 43 } else {
44 return NULL; 44 if (framing != AIM_FRAMETYPE_FLAP) {
45 } 45 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n");
46 } else { 46 return NULL;
47 if (framing != AIM_FRAMETYPE_OSCAR) { 47 }
48 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n"); 48 }
49 return NULL; 49
50 } 50 if (!(fr = (aim_frame_t *)malloc(sizeof(aim_frame_t))))
51 } 51 return NULL;
52 52 memset(fr, 0, sizeof(aim_frame_t));
53 newtx = (struct command_tx_struct *)malloc(sizeof(struct command_tx_struct)); 53
54 if (!newtx) 54 fr->conn = conn;
55 return NULL; 55
56 memset(newtx, 0, sizeof(struct command_tx_struct)); 56 fr->hdrtype = framing;
57 57
58 newtx->conn = conn; 58 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
59 59
60 if(datalen) { 60 fr->hdr.flap.type = chan;
61 newtx->data = (unsigned char *)malloc(datalen); 61
62 newtx->commandlen = datalen; 62 } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) {
63 } else 63
64 newtx->data = NULL; 64 fr->hdr.oft.type = chan;
65 65 fr->hdr.oft.hdr2len = 0; /* this will get setup by caller */
66 newtx->hdrtype = framing; 66
67 if (newtx->hdrtype == AIM_FRAMETYPE_OSCAR) { 67 } else
68 newtx->hdr.oscar.type = chan; 68 faimdprintf(sess, 0, "tx_new: unknown framing\n");
69 } else if (newtx->hdrtype == AIM_FRAMETYPE_OFT) { 69
70 newtx->hdr.oft.type = chan; 70 if (datalen > 0) {
71 newtx->hdr.oft.hdr2len = 0; /* this will get setup by caller */ 71 fu8_t *data;
72 } else { 72
73 faimdprintf(sess, 0, "tx_new: unknown framing\n"); 73 if (!(data = (unsigned char *)malloc(datalen))) {
74 } 74 aim_frame_destroy(fr);
75 75 return NULL;
76 return newtx; 76 }
77
78 aim_bstream_init(&fr->data, data, datalen);
79 }
80
81 return fr;
77 } 82 }
78 83
79 /* 84 /*
80 * aim_tx_enqeue__queuebased() 85 * aim_tx_enqeue__queuebased()
81 * 86 *
82 * The overall purpose here is to enqueue the passed in command struct 87 * The overall purpose here is to enqueue the passed in command struct
83 * into the outgoing (tx) queue. Basically... 88 * into the outgoing (tx) queue. Basically...
84 * 1) Make a scope-irrelevent copy of the struct 89 * 1) Make a scope-irrelevent copy of the struct
85 * 2) Lock the struct
86 * 3) Mark as not-sent-yet 90 * 3) Mark as not-sent-yet
87 * 4) Enqueue the struct into the list 91 * 4) Enqueue the struct into the list
88 * 5) Unlock the struct once it's linked in
89 * 6) Return 92 * 6) Return
90 * 93 *
91 * Note that this is only used when doing queue-based transmitting; 94 * Note that this is only used when doing queue-based transmitting;
92 * that is, when sess->tx_enqueue is set to &aim_tx_enqueue__queuebased. 95 * that is, when sess->tx_enqueue is set to &aim_tx_enqueue__queuebased.
93 * 96 *
94 */ 97 */
95 static int aim_tx_enqueue__queuebased(struct aim_session_t *sess, struct command_tx_struct *newpacket) 98 static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr)
96 { 99 {
97 struct command_tx_struct *cur; 100
98 101 if (!fr->conn) {
99 if (newpacket->conn == NULL) { 102 faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n");
100 faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n"); 103 fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
101 newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); 104 }
102 } 105
103 106 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
104 if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR) { 107 /* assign seqnum -- XXX should really not assign until hardxmit */
105 /* assign seqnum */ 108 fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
106 newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn); 109 }
107 } 110
108 /* set some more fields */ 111 fr->handled = 0; /* not sent yet */
109 newpacket->lock = 1; /* lock */ 112
110 newpacket->sent = 0; /* not sent yet */ 113 /* see overhead note in aim_rxqueue counterpart */
111 newpacket->next = NULL; /* always last */ 114 if (!sess->queue_outgoing)
112 115 sess->queue_outgoing = fr;
113 /* see overhead note in aim_rxqueue counterpart */ 116 else {
114 if (sess->queue_outgoing == NULL) { 117 aim_frame_t *cur;
115 sess->queue_outgoing = newpacket; 118
116 } else { 119 for (cur = sess->queue_outgoing; cur->next; cur = cur->next)
117 for (cur = sess->queue_outgoing; 120 ;
118 cur->next; 121 cur->next = fr;
119 cur = cur->next) 122 }
120 ; 123
121 cur->next = newpacket; 124 return 0;
122 }
123
124 newpacket->lock = 0; /* unlock so it can be sent */
125
126 return 0;
127 } 125 }
128 126
129 /* 127 /*
130 * aim_tx_enqueue__immediate() 128 * aim_tx_enqueue__immediate()
131 * 129 *
135 * Basically the same as its __queuebased couterpart, however 133 * Basically the same as its __queuebased couterpart, however
136 * instead of doing a list append, it just calls aim_tx_sendframe() 134 * instead of doing a list append, it just calls aim_tx_sendframe()
137 * right here. 135 * right here.
138 * 136 *
139 */ 137 */
140 static int aim_tx_enqueue__immediate(struct aim_session_t *sess, struct command_tx_struct *newpacket) 138 static int aim_tx_enqueue__immediate(aim_session_t *sess, aim_frame_t *fr)
141 { 139 {
142 if (newpacket->conn == NULL) { 140
143 faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n"); 141 if (!fr->conn) {
144 if (newpacket->data) 142 faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n");
145 free(newpacket->data); 143 aim_frame_destroy(fr);
146 free(newpacket); 144 return 0;
147 return -1; 145 }
148 } 146
149 147 if (fr->hdrtype == AIM_FRAMETYPE_FLAP)
150 if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR) 148 fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
151 newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn); 149
152 150 fr->handled = 0; /* not sent yet */
153 newpacket->lock = 1; /* lock */ 151
154 newpacket->sent = 0; /* not sent yet */ 152 aim_tx_sendframe(sess, fr);
155 153
156 aim_tx_sendframe(sess, newpacket); 154 aim_frame_destroy(fr);
157 155
158 if (newpacket->data) 156 return 0;
159 free(newpacket->data); 157 }
160 free(newpacket); 158
161 159 faim_export int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *))
162 return 0; 160 {
163 } 161
164 162 if (what == AIM_TX_QUEUED)
165 faim_export int aim_tx_setenqueue(struct aim_session_t *sess, 163 sess->tx_enqueue = &aim_tx_enqueue__queuebased;
166 int what, 164 else if (what == AIM_TX_IMMEDIATE)
167 int (*func)(struct aim_session_t *, struct command_tx_struct *)) 165 sess->tx_enqueue = &aim_tx_enqueue__immediate;
168 { 166 else if (what == AIM_TX_USER) {
169 if (!sess) 167 if (!func)
170 return -1; 168 return -EINVAL;
171 169 sess->tx_enqueue = func;
172 if (what == AIM_TX_QUEUED) 170 } else
173 sess->tx_enqueue = &aim_tx_enqueue__queuebased; 171 return -EINVAL; /* unknown action */
174 else if (what == AIM_TX_IMMEDIATE) 172
175 sess->tx_enqueue = &aim_tx_enqueue__immediate; 173 return 0;
176 else if (what == AIM_TX_USER) { 174 }
177 if (!func) 175
178 return -1; 176 faim_internal int aim_tx_enqueue(aim_session_t *sess, aim_frame_t *fr)
179 sess->tx_enqueue = func; 177 {
180 } else 178
181 return -1; /* unknown action */ 179 /*
182 180 * If we want to send a connection thats inprogress, we have to force
183 return 0; 181 * them to use the queue based version. Otherwise, use whatever they
184 } 182 * want.
185 183 */
186 faim_internal int aim_tx_enqueue(struct aim_session_t *sess, struct command_tx_struct *command) 184 if (fr && fr->conn &&
187 { 185 (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
188 /* 186 return aim_tx_enqueue__queuebased(sess, fr);
189 * If we want to send a connection thats inprogress, we have to force 187 }
190 * them to use the queue based version. Otherwise, use whatever they 188
191 * want. 189 return (*sess->tx_enqueue)(sess, fr);
192 */
193 if (command && command->conn && (command->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
194 return aim_tx_enqueue__queuebased(sess, command);
195 }
196 return (*sess->tx_enqueue)(sess, command);
197 } 190 }
198 191
199 /* 192 /*
200 * aim_get_next_txseqnum() 193 * aim_get_next_txseqnum()
201 * 194 *
203 * that should be stamped on the next FLAP packet sent. This is 196 * that should be stamped on the next FLAP packet sent. This is
204 * normally called during the final step of packet preparation 197 * normally called during the final step of packet preparation
205 * before enqueuement (in aim_tx_enqueue()). 198 * before enqueuement (in aim_tx_enqueue()).
206 * 199 *
207 */ 200 */
208 faim_internal unsigned int aim_get_next_txseqnum(struct aim_conn_t *conn) 201 faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *conn)
209 { 202 {
210 u_int ret; 203 flap_seqnum_t ret;
211 204
212 faim_mutex_lock(&conn->seqnum_lock); 205 faim_mutex_lock(&conn->seqnum_lock);
213 ret = ++conn->seqnum; 206 ret = ++conn->seqnum;
214 faim_mutex_unlock(&conn->seqnum_lock); 207 faim_mutex_unlock(&conn->seqnum_lock);
215 return ret; 208
216 } 209 return ret;
217 210 }
218 /* 211
219 * aim_tx_flushqueue() 212 static int aim_send(int fd, const void *buf, size_t count)
220 * 213 {
221 * This the function is responsable for putting the queued commands 214 int left, cur;
222 * onto the wire. This function is critical to the operation of 215
223 * the queue and therefore is the most prone to brokenness. It 216 for (cur = 0, left = count; left; ) {
224 * seems to be working quite well at this point. 217 int ret;
225 * 218
226 * Procedure: 219 ret = send(fd, ((unsigned char *)buf)+cur, left, 0);
227 * 1) Traverse the list, only operate on commands that are unlocked 220 if (ret == -1)
228 * and haven't been sent yet. 221 return -1;
229 * 2) Lock the struct 222 else if (ret == 0)
230 * 3) Allocate a temporary buffer to store the finished, fully 223 return cur;
231 * processed packet in. 224
232 * 4) Build the packet from the command_tx_struct data. 225 cur += ret;
233 * 5) Write the packet to the socket. 226 left -= ret;
234 * 6) If success, mark the packet sent, if fail report failure, do NOT 227 }
235 * mark the packet sent (so it will not get purged and therefore 228
236 * be attempted again on next call). 229 return cur;
237 * 7) Unlock the struct. 230 }
238 * 8) Free the temp buffer 231
239 * 9) Step to next struct in list and go back to 1. 232 static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count)
240 * 233 {
241 */ 234 int wrote = 0;
242 faim_internal int aim_tx_sendframe(struct aim_session_t *sess, struct command_tx_struct *cur) 235
243 { 236 if (!bs || !conn || (count < 0))
244 int buflen = 0; 237 return -EINVAL;
245 unsigned char *curPacket; 238
246 239 if (count > aim_bstream_empty(bs))
247 if (!cur) 240 count = aim_bstream_empty(bs); /* truncate to remaining space */
248 return -1; /* fatal */ 241
249 242 if (count)
250 cur->lock = 1; /* lock the struct */ 243 wrote = aim_send(conn->fd, bs->data + bs->offset, count);
251 244
252 if (cur->hdrtype == AIM_FRAMETYPE_OSCAR) 245 if (((aim_session_t *)conn->sessv)->debug >= 2) {
253 buflen = cur->commandlen + 6; 246 int i;
254 else if (cur->hdrtype == AIM_FRAMETYPE_OFT) 247 aim_session_t *sess = (aim_session_t *)conn->sessv;
255 buflen = cur->hdr.oft.hdr2len + 8; 248
256 else { 249 faimdprintf(sess, 2, "\nOutgoing data: (%d bytes)", wrote);
257 cur->lock = 0; 250 for (i = 0; i < wrote; i++) {
258 return -1; 251 if (!(i % 8))
259 } 252 faimdprintf(sess, 2, "\n\t");
260 253 faimdprintf(sess, 2, "0x%02x ", *(bs->data + bs->offset + i));
261 /* allocate full-packet buffer */ 254 }
262 if (!(curPacket = (unsigned char *) malloc(buflen))) { 255 faimdprintf(sess, 2, "\n");
263 cur->lock = 0; 256 }
264 return -1; 257
265 } 258
266 259 bs->offset += wrote;
267 if (cur->hdrtype == AIM_FRAMETYPE_OSCAR) { 260
268 /* command byte */ 261 return wrote;
269 curPacket[0] = 0x2a; 262 }
270 263
271 /* type/family byte */ 264 static int sendframe_flap(aim_session_t *sess, aim_frame_t *fr)
272 curPacket[1] = cur->hdr.oscar.type; 265 {
273 266 aim_bstream_t obs;
274 /* bytes 3+4: word: FLAP sequence number */ 267 fu8_t *obs_raw;
275 aimutil_put16(curPacket+2, cur->hdr.oscar.seqnum); 268 int payloadlen, err = 0, obslen;
276 269
277 /* bytes 5+6: word: SNAC len */ 270 payloadlen = aim_bstream_curpos(&fr->data);
278 aimutil_put16(curPacket+4, cur->commandlen); 271
279 272 if (!(obs_raw = malloc(6 + payloadlen)))
280 /* bytes 7 and on: raw: SNAC data */ /* XXX: ye gods! get rid of this! */ 273 return -ENOMEM;
281 memcpy(&(curPacket[6]), cur->data, cur->commandlen); 274
282 275 aim_bstream_init(&obs, obs_raw, 6 + payloadlen);
283 } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) { 276
284 int z = 0; 277 /* FLAP header */
285 278 aimbs_put8(&obs, 0x2a);
286 z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[0]); 279 aimbs_put8(&obs, fr->hdr.flap.type);
287 z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[1]); 280 aimbs_put16(&obs, fr->hdr.flap.seqnum);
288 z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[2]); 281 aimbs_put16(&obs, payloadlen);
289 z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[3]); 282
290 283 /* payload */
291 z += aimutil_put16(curPacket+z, cur->hdr.oft.hdr2len + 8); 284 aim_bstream_rewind(&fr->data);
292 z += aimutil_put16(curPacket+z, cur->hdr.oft.type); 285 aimbs_putbs(&obs, &fr->data, payloadlen);
293 286
294 memcpy(curPacket+z, cur->hdr.oft.hdr2, cur->hdr.oft.hdr2len); 287 obslen = aim_bstream_curpos(&obs);
295 } 288 aim_bstream_rewind(&obs);
296 289
297 /* 290 if (aim_bstream_send(&obs, fr->conn, obslen) != obslen)
298 * For OSCAR, a full image of the raw packet data now in curPacket. 291 err = -errno;
299 * For OFT, an image of just the bloated header is in curPacket, 292
300 * since OFT allows us to do the data in a different write (yay!). 293 free(obs_raw); /* XXX aim_bstream_free */
301 */ 294
302 faim_mutex_lock(&cur->conn->active); 295 fr->handled = 1;
303 if (send(cur->conn->fd, curPacket, buflen, 0) != buflen) { 296 fr->conn->lastactivity = time(NULL);
304 faim_mutex_unlock(&cur->conn->active); 297
305 cur->sent = 1; 298 return err;
306 aim_conn_close(cur->conn); 299 }
307 return 0; /* bail out */ 300
308 } 301 static int sendframe_oft(aim_session_t *sess, aim_frame_t *fr)
309 302 {
310 if ((cur->hdrtype == AIM_FRAMETYPE_OFT) && cur->commandlen) { 303 aim_bstream_t hbs;
311 int curposi; 304 fu8_t *hbs_raw;
312 for(curposi = 0; curposi < cur->commandlen; curposi++) 305 int hbslen;
313 faimdprintf(sess, 0, "%02x ", cur->data[curposi]); 306 int err = 0;
314 307
315 if (send(cur->conn->fd, cur->data, cur->commandlen, 0) != (int)cur->commandlen) { 308 hbslen = 8 + fr->hdr.oft.hdr2len;
316 /* 309
317 * Theres nothing we can do about this since we've already sent the 310 if (!(hbs_raw = malloc(hbslen)))
318 * header! The connection is unstable. 311 return -1;
319 */ 312
320 faim_mutex_unlock(&cur->conn->active); 313 aim_bstream_init(&hbs, hbs_raw, hbslen);
321 cur->sent = 1; 314
322 aim_conn_close(cur->conn); 315 aimbs_putraw(&hbs, fr->hdr.oft.magic, 4);
323 return 0; /* bail out */ 316 aimbs_put16(&hbs, fr->hdr.oft.hdr2len + 8);
324 } 317 aimbs_put16(&hbs, fr->hdr.oft.type);
325 318 aimbs_putraw(&hbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len);
326 } 319
327 320 aim_bstream_rewind(&hbs);
328 cur->sent = 1; /* mark the struct as sent */ 321
329 cur->conn->lastactivity = time(NULL); 322 if (aim_bstream_send(&hbs, fr->conn, hbslen) != hbslen) {
330 323
331 faim_mutex_unlock(&cur->conn->active); 324 err = -errno;
332 325
333 if (sess->debug >= 2) { 326 } else if (aim_bstream_curpos(&fr->data)) {
334 int i; 327 int len;
335 328
336 faimdprintf(sess, 2, "\nOutgoing packet: (only valid for OSCAR)"); 329 len = aim_bstream_curpos(&fr->data);
337 for (i = 0; i < buflen; i++) { 330 aim_bstream_rewind(&fr->data);
338 if (!(i % 8)) 331
339 faimdprintf(sess, 2, "\n\t"); 332 if (aim_bstream_send(&fr->data, fr->conn, len) != len)
340 faimdprintf(sess, 2, "0x%02x ", curPacket[i]); 333 err = -errno;
341 } 334 }
342 faimdprintf(sess, 2, "\n"); 335
343 } 336 free(hbs_raw); /* XXX aim_bstream_free */
344 337
345 cur->lock = 0; /* unlock the struct */ 338 fr->handled = 1;
346 339 fr->conn->lastactivity = time(NULL);
347 free(curPacket); /* free up full-packet buffer */ 340
348 341
349 return 1; /* success */ 342 return err;
350 } 343 }
351 344
352 faim_export int aim_tx_flushqueue(struct aim_session_t *sess) 345 faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *fr)
353 { 346 {
354 struct command_tx_struct *cur; 347 if (fr->hdrtype == AIM_FRAMETYPE_FLAP)
355 348 return sendframe_flap(sess, fr);
356 if (sess->queue_outgoing == NULL) 349 else if (fr->hdrtype == AIM_FRAMETYPE_OFT)
357 return 0; 350 return sendframe_oft(sess, fr);
358 351 return -1;
359 faimdprintf(sess, 2, "beginning txflush...\n"); 352 }
360 for (cur = sess->queue_outgoing; cur; cur = cur->next) { 353
361 /* only process if its unlocked and unsent */ 354 faim_export int aim_tx_flushqueue(aim_session_t *sess)
362 if (!cur->lock && !cur->sent) { 355 {
363 356 aim_frame_t *cur;
364 if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS)) 357
365 continue; 358 for (cur = sess->queue_outgoing; cur; cur = cur->next) {
366 359
367 /* 360 if (cur->handled)
368 * And now for the meager attempt to force transmit 361 continue; /* already been sent */
369 * latency and avoid missed messages. 362
370 */ 363 if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS))
371 if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) { 364 continue;
372 /* FIXME FIXME -- should be a break! we dont want to block the upper layers */ 365
373 sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL)); 366 /*
374 } 367 * And now for the meager attempt to force transmit
375 368 * latency and avoid missed messages.
376 /* XXX XXX XXX this should call the custom "queuing" function!! */ 369 */
377 if (aim_tx_sendframe(sess, cur) == -1) 370 if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) {
378 break; 371 /*
379 } 372 * XXX should be a break! we dont want to block the
380 } 373 * upper layers
381 374 *
382 /* purge sent commands from queue */ 375 * XXX or better, just do this right.
383 aim_tx_purgequeue(sess); 376 *
384 377 */
385 return 0; 378 sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL));
379 }
380
381 /* XXX this should call the custom "queuing" function!! */
382 aim_tx_sendframe(sess, cur);
383 }
384
385 /* purge sent commands from queue */
386 aim_tx_purgequeue(sess);
387
388 return 0;
386 } 389 }
387 390
388 /* 391 /*
389 * aim_tx_purgequeue() 392 * aim_tx_purgequeue()
390 * 393 *
391 * This is responsable for removing sent commands from the transmit 394 * This is responsable for removing sent commands from the transmit
392 * queue. This is not a required operation, but it of course helps 395 * queue. This is not a required operation, but it of course helps
393 * reduce memory footprint at run time! 396 * reduce memory footprint at run time!
394 * 397 *
395 */ 398 */
396 faim_export void aim_tx_purgequeue(struct aim_session_t *sess) 399 faim_export void aim_tx_purgequeue(aim_session_t *sess)
397 { 400 {
398 struct command_tx_struct *cur = NULL; 401 aim_frame_t *cur, **prev;
399 struct command_tx_struct *tmp; 402
400 403 for (prev = &sess->queue_outgoing; (cur = *prev); ) {
401 if (sess->queue_outgoing == NULL) 404
402 return; 405 if (cur->handled) {
403 406 *prev = cur->next;
404 if (sess->queue_outgoing->next == NULL) { 407
405 if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) { 408 aim_frame_destroy(cur);
406 tmp = sess->queue_outgoing; 409
407 sess->queue_outgoing = NULL; 410 } else
408 if (tmp->hdrtype == AIM_FRAMETYPE_OFT) 411 prev = &cur->next;
409 free(tmp->hdr.oft.hdr2); 412 }
410 free(tmp->data); 413
411 free(tmp); 414 return;
412 }
413 return;
414 }
415
416 for(cur = sess->queue_outgoing; cur->next != NULL; ) {
417 if (!cur->next->lock && cur->next->sent) {
418 tmp = cur->next;
419 cur->next = tmp->next;
420 if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
421 free(tmp->hdr.oft.hdr2);
422 free(tmp->data);
423 free(tmp);
424 }
425 cur = cur->next;
426
427 /*
428 * Be careful here. Because of the way we just
429 * manipulated the pointer, cur may be NULL and
430 * the for() will segfault doing the check unless
431 * we find this case first.
432 */
433 if (cur == NULL)
434 break;
435 }
436 return;
437 } 415 }
438 416
439 /** 417 /**
440 * aim_tx_cleanqueue - get rid of packets waiting for tx on a dying conn 418 * aim_tx_cleanqueue - get rid of packets waiting for tx on a dying conn
441 * @sess: session 419 * @sess: session
442 * @conn: connection that's dying 420 * @conn: connection that's dying
443 * 421 *
444 * for now this simply marks all packets as sent and lets them 422 * for now this simply marks all packets as sent and lets them
445 * disappear without warning. 423 * disappear without warning.
446 * 424 *
447 * doesn't respect command_tx_struct locks. 425 */
448 */ 426 faim_export void aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn)
449 427 {
450 faim_export int aim_tx_cleanqueue(struct aim_session_t *sess, struct aim_conn_t *conn) 428 aim_frame_t *cur;
451 { 429
452 struct command_tx_struct *cur = NULL; 430 for (cur = sess->queue_outgoing; cur; cur = cur->next) {
453 431 if (cur->conn == conn)
454 if(!sess || !conn) 432 cur->handled = 1;
455 return -1; 433 }
456 434
457 /* we don't respect locks here */ 435 return;
458 for(cur = sess->queue_outgoing; cur; cur = cur->next) 436 }
459 if(cur->conn == conn) 437
460 cur->sent = 1; 438
461
462 return 0;
463 }
464
465