source: protocols/oscar/rxqueue.c @ a81e6a0

Last change on this file since a81e6a0 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
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#include <aim.h>
10
11#include <sys/socket.h>
12
13/*
14 *
15 */
16int aim_recv(int fd, void *buf, size_t count)
17{
18        int left, cur;
19
20        for (cur = 0, left = count; left; ) {
21                int ret;
22
23                ret = recv(fd, ((unsigned char *) buf) + cur, left, 0);
24
25                /* Of course EOF is an error, only morons disagree with that. */
26                if (ret <= 0) {
27                        return -1;
28                }
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
45        if (!bs || (fd < 0) || (count < 0)) {
46                return -1;
47        }
48
49        if (count > (bs->len - bs->offset)) {
50                count = bs->len - bs->offset; /* truncate to remaining space */
51
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
62        bs->offset += red;
63
64        return red;
65}
66
67int aim_bstream_init(aim_bstream_t *bs, guint8 *data, int len)
68{
69
70        if (!bs) {
71                return -1;
72        }
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
94        if (off > bs->len) {
95                return -1;
96        }
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
114        if (aim_bstream_empty(bs) < n) {
115                return 0; /* XXX throw an exception */
116
117        }
118        bs->offset += n;
119
120        return n;
121}
122
123guint8 aimbs_get8(aim_bstream_t *bs)
124{
125
126        if (aim_bstream_empty(bs) < 1) {
127                return 0; /* XXX throw an exception */
128
129        }
130        bs->offset++;
131
132        return aimutil_get8(bs->data + bs->offset - 1);
133}
134
135guint16 aimbs_get16(aim_bstream_t *bs)
136{
137
138        if (aim_bstream_empty(bs) < 2) {
139                return 0; /* XXX throw an exception */
140
141        }
142        bs->offset += 2;
143
144        return aimutil_get16(bs->data + bs->offset - 2);
145}
146
147guint32 aimbs_get32(aim_bstream_t *bs)
148{
149
150        if (aim_bstream_empty(bs) < 4) {
151                return 0; /* XXX throw an exception */
152
153        }
154        bs->offset += 4;
155
156        return aimutil_get32(bs->data + bs->offset - 4);
157}
158
159guint8 aimbs_getle8(aim_bstream_t *bs)
160{
161
162        if (aim_bstream_empty(bs) < 1) {
163                return 0; /* XXX throw an exception */
164
165        }
166        bs->offset++;
167
168        return aimutil_getle8(bs->data + bs->offset - 1);
169}
170
171guint16 aimbs_getle16(aim_bstream_t *bs)
172{
173
174        if (aim_bstream_empty(bs) < 2) {
175                return 0; /* XXX throw an exception */
176
177        }
178        bs->offset += 2;
179
180        return aimutil_getle16(bs->data + bs->offset - 2);
181}
182
183guint32 aimbs_getle32(aim_bstream_t *bs)
184{
185
186        if (aim_bstream_empty(bs) < 4) {
187                return 0; /* XXX throw an exception */
188
189        }
190        bs->offset += 4;
191
192        return aimutil_getle32(bs->data + bs->offset - 4);
193}
194
195int aimbs_put8(aim_bstream_t *bs, guint8 v)
196{
197
198        if (aim_bstream_empty(bs) < 1) {
199                return 0; /* XXX throw an exception */
200
201        }
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
210        if (aim_bstream_empty(bs) < 2) {
211                return 0; /* XXX throw an exception */
212
213        }
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
222        if (aim_bstream_empty(bs) < 4) {
223                return 0; /* XXX throw an exception */
224
225        }
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
234        if (aim_bstream_empty(bs) < 1) {
235                return 0; /* XXX throw an exception */
236
237        }
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
246        if (aim_bstream_empty(bs) < 2) {
247                return 0; /* XXX throw an exception */
248
249        }
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
258        if (aim_bstream_empty(bs) < 4) {
259                return 0; /* XXX throw an exception */
260
261        }
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
270        if (aim_bstream_empty(bs) < len) {
271                return 0;
272        }
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
284        if (!(ob = g_malloc(len))) {
285                return NULL;
286        }
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
300        if (!(ob = g_malloc(len + 1))) {
301                return NULL;
302        }
303
304        if (aimbs_getrawbuf(bs, ob, len) < len) {
305                g_free(ob);
306                return NULL;
307        }
308
309        ob[len] = '\0';
310
311        return (char *) ob;
312}
313
314int aimbs_putraw(aim_bstream_t *bs, const guint8 *v, int len)
315{
316
317        if (aim_bstream_empty(bs) < len) {
318                return 0; /* XXX throw an exception */
319
320        }
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
330        if (aim_bstream_empty(srcbs) < len) {
331                return 0; /* XXX throw exception (underrun) */
332
333        }
334        if (aim_bstream_empty(bs) < len) {
335                return 0; /* XXX throw exception (overflow) */
336
337        }
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/**
346 * aim_frame_destroy - free aim_frame_t
347 * @frame: the frame to free
348 *
349 * returns -1 on error; 0 on success.
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);
358}
359
360
361/*
362 * Grab a single command sequence off the socket, and enqueue
363 * it in the incoming event queue in a separate struct.
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;
371
372        if (!sess || !conn) {
373                return 0;
374        }
375
376        if (conn->fd == -1) {
377                return -1; /* its a aim_conn_close()'d connection */
378
379        }
380        /* KIDS, THIS IS WHAT HAPPENS IF YOU USE CODE WRITTEN FOR GUIS IN A DAEMON!
381
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)?...
385
386        if (conn->fd < 3)
387                return 0;
388        */
389
390        if (conn->status & AIM_CONN_STATUS_INPROGRESS) {
391                return aim_conn_completeconnect(sess, conn);
392        }
393
394        aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));
395
396        /*
397         * Read FLAP header.  Six bytes:
398         *
399         *   0 char  -- Always 0x2a
400         *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
401         *   2 short -- Sequence number
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);
417                aimbs_get8(&flaphdr);
418                imcb_error(sess->aux_data, "FLAP framing disrupted");
419                aim_conn_close(conn);
420                return -1;
421        }
422
423        /* allocate a new struct */
424        if (!(newrx = (aim_frame_t *) g_new0(aim_frame_t, 1))) {
425                return -1;
426        }
427
428        /* we're doing FLAP if we're here */
429        newrx->hdrtype = AIM_FRAMETYPE_FLAP;
430
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                }
453        } else {
454                aim_bstream_init(&newrx->data, NULL, 0);
455        }
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
464        if (!sess->queue_incoming) {
465                sess->queue_incoming = newrx;
466        } else {
467                aim_frame_t *cur;
468
469                for (cur = sess->queue_incoming; cur->next; cur = cur->next) {
470                        ;
471                }
472                cur->next = newrx;
473        }
474
475        newrx->conn->lastactivity = time(NULL);
476
477        return 0;
478}
479
480/*
481 * Purge receive queue of all handled commands (->handled==1).  Also
482 * allows for selective freeing using ->nofree so that the client can
483 * keep the data for various purposes.
484 *
485 * If ->nofree is nonzero, the frame will be delinked from the global list,
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;
499
500                        if (!cur->nofree) {
501                                aim_frame_destroy(cur);
502                        }
503
504                } else {
505                        prev = &cur->next;
506                }
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) {
524                if ((!currx->handled) && (currx->conn == conn)) {
525                        currx->handled = 1;
526                }
527        }
528        return;
529}
530
Note: See TracBrowser for help on using the repository browser.