source: protocols/oscar/rxqueue.c @ 3e1de87

Last change on this file since 3e1de87 was b7d3cc34, checked in by Wilmer van der Gaast <wilmer@…>, at 2005-11-06T18:23:18Z

Initial repository (0.99 release tree)

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