source: protocols/oscar/rxqueue.c @ 2d09041

Last change on this file since 2d09041 was e88fe7da, checked in by Veres Lajos <vlajos@…>, at 2015-08-07T21:53:25Z

typofix - https://github.com/vlajos/misspell_fixer

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