source: protocols/oscar/rxqueue.c @ 8407e25

Last change on this file since 8407e25 was d18db32f, checked in by Miklos Vajna <vmiklos@…>, at 2011-12-06T00:53:26Z

oscar: unused-but-set-variables

  • 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                aim_bstream_rewind(&flaphdr);
391                aimbs_get8(&flaphdr);
392                imcb_error(sess->aux_data, "FLAP framing disrupted");
393                aim_conn_close(conn);
394                return -1;
395        }       
396
397        /* allocate a new struct */
398        if (!(newrx = (aim_frame_t *)g_new0(aim_frame_t,1)))
399                return -1;
400
401        /* we're doing FLAP if we're here */
402        newrx->hdrtype = AIM_FRAMETYPE_FLAP;
403       
404        newrx->hdr.flap.type = aimbs_get8(&flaphdr);
405        newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
406        payloadlen = aimbs_get16(&flaphdr);
407
408        newrx->nofree = 0; /* free by default */
409
410        if (payloadlen) {
411                guint8 *payload = NULL;
412
413                if (!(payload = (guint8 *) g_malloc(payloadlen))) {
414                        aim_frame_destroy(newrx);
415                        return -1;
416                }
417
418                aim_bstream_init(&newrx->data, payload, payloadlen);
419
420                /* read the payload */
421                if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) {
422                        aim_frame_destroy(newrx); /* free's payload */
423                        aim_conn_close(conn);
424                        return -1;
425                }
426        } else
427                aim_bstream_init(&newrx->data, NULL, 0);
428
429
430        aim_bstream_rewind(&newrx->data);
431
432        newrx->conn = conn;
433
434        newrx->next = NULL;  /* this will always be at the bottom */
435
436        if (!sess->queue_incoming)
437                sess->queue_incoming = newrx;
438        else {
439                aim_frame_t *cur;
440
441                for (cur = sess->queue_incoming; cur->next; cur = cur->next)
442                        ;
443                cur->next = newrx;
444        }
445
446        newrx->conn->lastactivity = time(NULL);
447
448        return 0; 
449}
450
451/*
452 * Purge recieve queue of all handled commands (->handled==1).  Also
453 * allows for selective freeing using ->nofree so that the client can
454 * keep the data for various purposes. 
455 *
456 * If ->nofree is nonzero, the frame will be delinked from the global list,
457 * but will not be free'ed.  The client _must_ keep a pointer to the
458 * data -- libfaim will not!  If the client marks ->nofree but
459 * does not keep a pointer, it's lost forever.
460 *
461 */
462void aim_purge_rxqueue(aim_session_t *sess)
463{
464        aim_frame_t *cur, **prev;
465
466        for (prev = &sess->queue_incoming; (cur = *prev); ) {
467                if (cur->handled) {
468
469                        *prev = cur->next;
470                       
471                        if (!cur->nofree)
472                                aim_frame_destroy(cur);
473
474                } else
475                        prev = &cur->next;
476        }
477
478        return;
479}
480
481/*
482 * Since aim_get_command will aim_conn_kill dead connections, we need
483 * to clean up the rxqueue of unprocessed connections on that socket.
484 *
485 * XXX: this is something that was handled better in the old connection
486 * handling method, but eh.
487 */
488void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn)
489{
490        aim_frame_t *currx;
491
492        for (currx = sess->queue_incoming; currx; currx = currx->next) {
493                if ((!currx->handled) && (currx->conn == conn))
494                        currx->handled = 1;
495        }       
496        return;
497}
498
Note: See TracBrowser for help on using the repository browser.