source: protocols/oscar/rxqueue.c @ bc49ec2

Last change on this file since bc49ec2 was 84b045d, checked in by Wilmer van der Gaast <wilmer@…>, at 2007-04-16T01:03:08Z

s/imc/imcb/ for callback functions. Moved things aroundin nogaim.h a
little bit, grouping things by category instead of original Gaim 0.58
filename.

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