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