source: protocols/oscar/rxqueue.c @ 6b13103

Last change on this file since 6b13103 was e252d8c, checked in by dequis <dx@…>, at 2014-09-27T14:54:35Z

RIP native win32 support (use cygwin instead)

It has been broken for a very long time and nobody cared about it.

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