source: protocols/oscar/rxqueue.c @ 8045d37

Last change on this file since 8045d37 was 66c57924, checked in by Jelmer Vernooij <jelmer@…>, at 2005-11-20T16:09:23Z

Remove OFT and rendez-vous support (not used anyway and implemented
in a way too complicated way)

  • Property mode set to 100644
File size: 9.0 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        if (conn->fd < 3)  /* can happen when people abuse the interface */
356                return 0;
357
358        if (conn->status & AIM_CONN_STATUS_INPROGRESS)
359                return aim_conn_completeconnect(sess, conn);
360
361        aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));
362
363        /*
364         * Read FLAP header.  Six bytes:
365         *   
366         *   0 char  -- Always 0x2a
367         *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
368         *   2 short -- Sequence number
369         *   4 short -- Number of data bytes that follow.
370         */
371        if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
372                aim_conn_close(conn);
373                return -1;
374        }
375
376        aim_bstream_rewind(&flaphdr);
377
378        /*
379         * This shouldn't happen unless the socket breaks, the server breaks,
380         * or we break.  We must handle it just in case.
381         */
382        if (aimbs_get8(&flaphdr) != 0x2a) {
383                guint8 start;
384
385                aim_bstream_rewind(&flaphdr);
386                start = aimbs_get8(&flaphdr);
387                do_error_dialog(sess->aux_data, "FLAP framing disrupted", "Gaim");
388                aim_conn_close(conn);
389                return -1;
390        }       
391
392        /* allocate a new struct */
393        if (!(newrx = (aim_frame_t *)g_new0(aim_frame_t,1)))
394                return -1;
395
396        /* we're doing FLAP if we're here */
397        newrx->hdrtype = AIM_FRAMETYPE_FLAP;
398       
399        newrx->hdr.flap.type = aimbs_get8(&flaphdr);
400        newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
401        payloadlen = aimbs_get16(&flaphdr);
402
403        newrx->nofree = 0; /* free by default */
404
405        if (payloadlen) {
406                guint8 *payload = NULL;
407
408                if (!(payload = (guint8 *) g_malloc(payloadlen))) {
409                        aim_frame_destroy(newrx);
410                        return -1;
411                }
412
413                aim_bstream_init(&newrx->data, payload, payloadlen);
414
415                /* read the payload */
416                if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) {
417                        aim_frame_destroy(newrx); /* free's payload */
418                        aim_conn_close(conn);
419                        return -1;
420                }
421        } else
422                aim_bstream_init(&newrx->data, NULL, 0);
423
424
425        aim_bstream_rewind(&newrx->data);
426
427        newrx->conn = conn;
428
429        newrx->next = NULL;  /* this will always be at the bottom */
430
431        if (!sess->queue_incoming)
432                sess->queue_incoming = newrx;
433        else {
434                aim_frame_t *cur;
435
436                for (cur = sess->queue_incoming; cur->next; cur = cur->next)
437                        ;
438                cur->next = newrx;
439        }
440
441        newrx->conn->lastactivity = time(NULL);
442
443        return 0; 
444}
445
446/*
447 * Purge recieve queue of all handled commands (->handled==1).  Also
448 * allows for selective freeing using ->nofree so that the client can
449 * keep the data for various purposes. 
450 *
451 * If ->nofree is nonzero, the frame will be delinked from the global list,
452 * but will not be free'ed.  The client _must_ keep a pointer to the
453 * data -- libfaim will not!  If the client marks ->nofree but
454 * does not keep a pointer, it's lost forever.
455 *
456 */
457void aim_purge_rxqueue(aim_session_t *sess)
458{
459        aim_frame_t *cur, **prev;
460
461        for (prev = &sess->queue_incoming; (cur = *prev); ) {
462                if (cur->handled) {
463
464                        *prev = cur->next;
465                       
466                        if (!cur->nofree)
467                                aim_frame_destroy(cur);
468
469                } else
470                        prev = &cur->next;
471        }
472
473        return;
474}
475
476/*
477 * Since aim_get_command will aim_conn_kill dead connections, we need
478 * to clean up the rxqueue of unprocessed connections on that socket.
479 *
480 * XXX: this is something that was handled better in the old connection
481 * handling method, but eh.
482 */
483void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn)
484{
485        aim_frame_t *currx;
486
487        for (currx = sess->queue_incoming; currx; currx = currx->next) {
488                if ((!currx->handled) && (currx->conn == conn))
489                        currx->handled = 1;
490        }       
491        return;
492}
493
Note: See TracBrowser for help on using the repository browser.