source: libfaim/rxqueue.c @ 290f290

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 290f290 was 5e53c4a, checked in by James M. Kretchmar <kretch@mit.edu>, 22 years ago
*** empty log message ***
  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 *  aim_rxqueue.c
3 *
4 * This file contains the management routines for the receive
5 * (incoming packet) queue.  The actual packet handlers are in
6 * aim_rxhandlers.c.
7 */
8
9#define FAIM_INTERNAL
10#include <aim.h>
11
12#ifndef _WIN32
13#include <sys/socket.h>
14#endif
15
16/*
17 *
18 */
19faim_internal int aim_recv(int fd, void *buf, size_t count)
20{
21        int left, cur; 
22
23        for (cur = 0, left = count; left; ) {
24                int ret;
25               
26                ret = recv(fd, ((unsigned char *)buf)+cur, left, 0);
27
28                /* Of course EOF is an error, only morons disagree with that. */
29                if (ret <= 0)
30                        return -1;
31
32                cur += ret;
33                left -= ret;
34        }
35
36        return cur;
37}
38
39/*
40 * Read into a byte stream.  Will not read more than count, but may read
41 * less if there is not enough room in the stream buffer.
42 */
43faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count)
44{
45        int red = 0;
46
47        if (!bs || (fd < 0) || (count < 0))
48                return -1;
49       
50        if (count > (bs->len - bs->offset))
51                count = bs->len - bs->offset; /* truncate to remaining space */
52
53        if (count) {
54
55                red = aim_recv(fd, bs->data + bs->offset, count);
56
57                if (red <= 0)
58                        return -1;
59        }
60
61        bs->offset += red;
62
63        return red;
64}
65
66faim_internal int aim_bstream_init(aim_bstream_t *bs, fu8_t *data, int len)
67{
68       
69        if (!bs)
70                return -1;
71
72        bs->data = data;
73        bs->len = len;
74        bs->offset = 0;
75
76        return 0;
77}
78
79faim_internal int aim_bstream_empty(aim_bstream_t *bs)
80{
81        return bs->len - bs->offset;
82}
83
84faim_internal int aim_bstream_curpos(aim_bstream_t *bs)
85{
86        return bs->offset;
87}
88
89faim_internal int aim_bstream_setpos(aim_bstream_t *bs, int off)
90{
91
92        if (off > bs->len)
93                return -1;
94
95        bs->offset = off;
96
97        return off;
98}
99
100faim_internal void aim_bstream_rewind(aim_bstream_t *bs)
101{
102
103        aim_bstream_setpos(bs, 0);
104
105        return;
106}
107
108faim_internal int aim_bstream_advance(aim_bstream_t *bs, int n)
109{
110
111        if (aim_bstream_empty(bs) < n)
112                return 0; /* XXX throw an exception */
113
114        bs->offset += n;
115
116        return n;
117}
118
119faim_internal fu8_t aimbs_get8(aim_bstream_t *bs)
120{
121       
122        if (aim_bstream_empty(bs) < 1)
123                return 0; /* XXX throw an exception */
124       
125        bs->offset++;
126       
127        return aimutil_get8(bs->data + bs->offset - 1);
128}
129
130faim_internal fu16_t aimbs_get16(aim_bstream_t *bs)
131{
132       
133        if (aim_bstream_empty(bs) < 2)
134                return 0; /* XXX throw an exception */
135       
136        bs->offset += 2;
137       
138        return aimutil_get16(bs->data + bs->offset - 2);
139}
140
141faim_internal fu32_t aimbs_get32(aim_bstream_t *bs)
142{
143       
144        if (aim_bstream_empty(bs) < 4)
145                return 0; /* XXX throw an exception */
146       
147        bs->offset += 4;
148       
149        return aimutil_get32(bs->data + bs->offset - 4);
150}
151
152faim_internal fu8_t aimbs_getle8(aim_bstream_t *bs)
153{
154       
155        if (aim_bstream_empty(bs) < 1)
156                return 0; /* XXX throw an exception */
157       
158        bs->offset++;
159       
160        return aimutil_getle8(bs->data + bs->offset - 1);
161}
162
163faim_internal fu16_t aimbs_getle16(aim_bstream_t *bs)
164{
165       
166        if (aim_bstream_empty(bs) < 2)
167                return 0; /* XXX throw an exception */
168       
169        bs->offset += 2;
170       
171        return aimutil_getle16(bs->data + bs->offset - 2);
172}
173
174faim_internal fu32_t aimbs_getle32(aim_bstream_t *bs)
175{
176       
177        if (aim_bstream_empty(bs) < 4)
178                return 0; /* XXX throw an exception */
179       
180        bs->offset += 4;
181       
182        return aimutil_getle32(bs->data + bs->offset - 4);
183}
184
185faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v)
186{
187
188        if (aim_bstream_empty(bs) < 1)
189                return 0; /* XXX throw an exception */
190
191        bs->offset += aimutil_put8(bs->data + bs->offset, v);
192
193        return 1;
194}
195
196faim_internal int aimbs_put16(aim_bstream_t *bs, fu16_t v)
197{
198
199        if (aim_bstream_empty(bs) < 2)
200                return 0; /* XXX throw an exception */
201
202        bs->offset += aimutil_put16(bs->data + bs->offset, v);
203
204        return 2;
205}
206
207faim_internal int aimbs_put32(aim_bstream_t *bs, fu32_t v)
208{
209
210        if (aim_bstream_empty(bs) < 4)
211                return 0; /* XXX throw an exception */
212
213        bs->offset += aimutil_put32(bs->data + bs->offset, v);
214
215        return 1;
216}
217
218faim_internal int aimbs_putle8(aim_bstream_t *bs, fu8_t v)
219{
220
221        if (aim_bstream_empty(bs) < 1)
222                return 0; /* XXX throw an exception */
223
224        bs->offset += aimutil_putle8(bs->data + bs->offset, v);
225
226        return 1;
227}
228
229faim_internal int aimbs_putle16(aim_bstream_t *bs, fu16_t v)
230{
231
232        if (aim_bstream_empty(bs) < 2)
233                return 0; /* XXX throw an exception */
234
235        bs->offset += aimutil_putle16(bs->data + bs->offset, v);
236
237        return 2;
238}
239
240faim_internal int aimbs_putle32(aim_bstream_t *bs, fu32_t v)
241{
242
243        if (aim_bstream_empty(bs) < 4)
244                return 0; /* XXX throw an exception */
245
246        bs->offset += aimutil_putle32(bs->data + bs->offset, v);
247
248        return 1;
249}
250
251faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len)
252{
253
254        if (aim_bstream_empty(bs) < len)
255                return 0;
256
257        memcpy(buf, bs->data + bs->offset, len);
258        bs->offset += len;
259
260        return len;
261}
262
263faim_internal fu8_t *aimbs_getraw(aim_bstream_t *bs, int len)
264{
265        fu8_t *ob;
266
267        if (!(ob = malloc(len)))
268                return NULL;
269
270        if (aimbs_getrawbuf(bs, ob, len) < len) {
271                free(ob);
272                return NULL;
273        }
274
275        return ob;
276}
277
278faim_internal char *aimbs_getstr(aim_bstream_t *bs, int len)
279{
280        char *ob;
281
282        if (!(ob = malloc(len+1)))
283                return NULL;
284
285        if (aimbs_getrawbuf(bs, ob, len) < len) {
286                free(ob);
287                return NULL;
288        }
289       
290        ob[len] = '\0';
291
292        return ob;
293}
294
295faim_internal int aimbs_putraw(aim_bstream_t *bs, const fu8_t *v, int len)
296{
297
298        if (aim_bstream_empty(bs) < len)
299                return 0; /* XXX throw an exception */
300
301        memcpy(bs->data + bs->offset, v, len);
302        bs->offset += len;
303
304        return len;
305}
306
307faim_internal int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len)
308{
309
310        if (aim_bstream_empty(srcbs) < len)
311                return 0; /* XXX throw exception (underrun) */
312
313        if (aim_bstream_empty(bs) < len)
314                return 0; /* XXX throw exception (overflow) */
315
316        memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len);
317        bs->offset += len;
318        srcbs->offset += len;
319
320        return len;
321}
322
323/**
324 * aim_frame_destroy - free aim_frame_t
325 * @frame: the frame to free 
326 *
327 * returns -1 on error; 0 on success. 
328 *
329 */
330faim_internal void aim_frame_destroy(aim_frame_t *frame)
331{
332
333        free(frame->data.data); /* XXX aim_bstream_free */
334
335        if (frame->hdrtype == AIM_FRAMETYPE_OFT)
336                free(frame->hdr.oft.hdr2);
337        free(frame);
338       
339        return;
340} 
341
342
343/*
344 * Grab a single command sequence off the socket, and enqueue
345 * it in the incoming event queue in a seperate struct.
346 */
347faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn)
348{
349        fu8_t flaphdr_raw[6];
350        aim_bstream_t flaphdr;
351        aim_frame_t *newrx;
352        fu16_t payloadlen;
353       
354        if (!sess || !conn)
355                return 0;
356
357        if (conn->fd == -1)
358                return -1; /* its a aim_conn_close()'d connection */
359
360        if (conn->fd < 3)  /* can happen when people abuse the interface */
361                return 0;
362
363        if (conn->status & AIM_CONN_STATUS_INPROGRESS)
364                return aim_conn_completeconnect(sess, conn);
365
366        /*
367         * Rendezvous (client-client) connections do not speak
368         * FLAP, so this function will break on them.
369         */
370        if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) 
371                return aim_get_command_rendezvous(sess, conn);
372        else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
373                faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd);
374                return 0; 
375        }
376
377        aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));
378
379        /*
380         * Read FLAP header.  Six bytes:
381         *   
382         *   0 char  -- Always 0x2a
383         *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
384         *   2 short -- Sequence number
385         *   4 short -- Number of data bytes that follow.
386         */
387        if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
388                aim_conn_close(conn);
389                return -1;
390        }
391
392        aim_bstream_rewind(&flaphdr);
393
394        /*
395         * This shouldn't happen unless the socket breaks, the server breaks,
396         * or we break.  We must handle it just in case.
397         */
398        if (aimbs_get8(&flaphdr) != 0x2a) {
399                fu8_t start;
400
401                aim_bstream_rewind(&flaphdr);
402                start = aimbs_get8(&flaphdr);
403                faimdprintf(sess, 0, "FLAP framing disrupted (0x%02x)", start);
404                aim_conn_close(conn);
405                return -1;
406        }       
407
408        /* allocate a new struct */
409        if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t))))
410                return -1;
411        memset(newrx, 0, sizeof(aim_frame_t));
412
413        /* we're doing FLAP if we're here */
414        newrx->hdrtype = AIM_FRAMETYPE_FLAP;
415       
416        newrx->hdr.flap.type = aimbs_get8(&flaphdr);
417        newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
418        payloadlen = aimbs_get16(&flaphdr);
419
420        newrx->nofree = 0; /* free by default */
421
422        if (payloadlen) {
423                fu8_t *payload = NULL;
424
425                if (!(payload = (fu8_t *) malloc(payloadlen))) {
426                        aim_frame_destroy(newrx);
427                        return -1;
428                }
429
430                aim_bstream_init(&newrx->data, payload, payloadlen);
431
432                /* read the payload */
433                if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) {
434                        aim_frame_destroy(newrx); /* free's payload */
435                        aim_conn_close(conn);
436                        return -1;
437                }
438        } else
439                aim_bstream_init(&newrx->data, NULL, 0);
440
441
442        aim_bstream_rewind(&newrx->data);
443
444        newrx->conn = conn;
445
446        newrx->next = NULL;  /* this will always be at the bottom */
447
448        if (!sess->queue_incoming)
449                sess->queue_incoming = newrx;
450        else {
451                aim_frame_t *cur;
452
453                for (cur = sess->queue_incoming; cur->next; cur = cur->next)
454                        ;
455                cur->next = newrx;
456        }
457
458        newrx->conn->lastactivity = time(NULL);
459
460        return 0; 
461}
462
463/*
464 * Purge recieve queue of all handled commands (->handled==1).  Also
465 * allows for selective freeing using ->nofree so that the client can
466 * keep the data for various purposes. 
467 *
468 * If ->nofree is nonzero, the frame will be delinked from the global list,
469 * but will not be free'ed.  The client _must_ keep a pointer to the
470 * data -- libfaim will not!  If the client marks ->nofree but
471 * does not keep a pointer, it's lost forever.
472 *
473 */
474faim_export void aim_purge_rxqueue(aim_session_t *sess)
475{
476        aim_frame_t *cur, **prev;
477
478        for (prev = &sess->queue_incoming; (cur = *prev); ) {
479                if (cur->handled) {
480
481                        *prev = cur->next;
482                       
483                        if (!cur->nofree)
484                                aim_frame_destroy(cur);
485
486                } else
487                        prev = &cur->next;
488        }
489
490        return;
491}
492
493/*
494 * Since aim_get_command will aim_conn_kill dead connections, we need
495 * to clean up the rxqueue of unprocessed connections on that socket.
496 *
497 * XXX: this is something that was handled better in the old connection
498 * handling method, but eh.
499 */
500faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn)
501{
502        aim_frame_t *currx;
503
504        for (currx = sess->queue_incoming; currx; currx = currx->next) {
505                if ((!currx->handled) && (currx->conn == conn))
506                        currx->handled = 1;
507        }       
508        return;
509}
510
Note: See TracBrowser for help on using the repository browser.