Mercurial > pidgin
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 |