]> andersk Git - libfaim.git/blame - src/rxqueue.c
- Mon Sep 3 18:48:26 PDT 2001
[libfaim.git] / src / rxqueue.c
CommitLineData
9de3ca7e 1/*
f1a5efe0 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.
9de3ca7e 7 */
8
37ee990e 9#define FAIM_INTERNAL
dd60ff8b 10#include <aim.h>
54d280df 11
12#ifndef _WIN32
78b3fb13 13#include <sys/socket.h>
54d280df 14#endif
9de3ca7e 15
a3619f23 16/*
78b3fb13 17 *
a3619f23 18 */
5ac21963 19faim_internal int aim_recv(int fd, void *buf, size_t count)
a3619f23 20{
d410cf58 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 */
43faim_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
66faim_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
79faim_internal int aim_bstream_empty(aim_bstream_t *bs)
80{
81 return bs->len - bs->offset;
82}
83
84faim_internal int aim_bstream_curpos(aim_bstream_t *bs)
85{
86 return bs->offset;
87}
88
89faim_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
100faim_internal void aim_bstream_rewind(aim_bstream_t *bs)
101{
102
103 aim_bstream_setpos(bs, 0);
104
105 return;
106}
107
108faim_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
119faim_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
130faim_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
141faim_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
152faim_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
163faim_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
174faim_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
185faim_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
197faim_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
212faim_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;
a3619f23 227}
228
d410cf58 229faim_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
241faim_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 */
264faim_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
9de3ca7e 277/*
f1a5efe0 278 * Grab a single command sequence off the socket, and enqueue
279 * it in the incoming event queue in a seperate struct.
a25832e6 280 */
d410cf58 281faim_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 faim_mutex_lock(&conn->active);
322 if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
323 aim_conn_close(conn);
324 faim_mutex_unlock(&conn->active);
325 return -1;
326 }
327
328 aim_bstream_rewind(&flaphdr);
329
330 /*
331 * This shouldn't happen unless the socket breaks, the server breaks,
332 * or we break. We must handle it just in case.
333 */
334 if (aimbs_get8(&flaphdr) != 0x2a) {
335 faimdprintf(sess, 0, "FLAP framing disrupted");
336 aim_conn_close(conn);
337 faim_mutex_unlock(&conn->active);
338 return -1;
339 }
340
341 /* allocate a new struct */
342 if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) {
343 faim_mutex_unlock(&conn->active);
344 return -1;
345 }
346 memset(newrx, 0, sizeof(aim_frame_t));
347
348 /* we're doing FLAP if we're here */
349 newrx->hdrtype = AIM_FRAMETYPE_FLAP;
350
351 newrx->hdr.flap.type = aimbs_get8(&flaphdr);
352 newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
353 payloadlen = aimbs_get16(&flaphdr);
354
355 newrx->nofree = 0; /* free by default */
356
357 if (payloadlen) {
358 fu8_t *payload = NULL;
359
360 if (!(payload = (fu8_t *) malloc(payloadlen))) {
361 aim_frame_destroy(newrx);
362 faim_mutex_unlock(&conn->active);
363 return -1;
364 }
365
366 aim_bstream_init(&newrx->data, payload, payloadlen);
367
368 /* read the payload */
369 if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) {
370 free(payload);
371 aim_frame_destroy(newrx);
372 aim_conn_close(conn);
373 faim_mutex_unlock(&conn->active);
374 return -1;
375 }
376 } else
377 aim_bstream_init(&newrx->data, NULL, 0);
378
379 faim_mutex_unlock(&conn->active);
380
381 aim_bstream_rewind(&newrx->data);
382
383 newrx->conn = conn;
384
385 newrx->next = NULL; /* this will always be at the bottom */
386
387 if (!sess->queue_incoming)
388 sess->queue_incoming = newrx;
389 else {
390 aim_frame_t *cur;
391
392 for (cur = sess->queue_incoming; cur->next; cur = cur->next)
393 ;
394 cur->next = newrx;
395 }
396
397 newrx->conn->lastactivity = time(NULL);
398
399 return 0;
9de3ca7e 400}
401
402/*
b8d0da45 403 * Purge recieve queue of all handled commands (->handled==1). Also
404 * allows for selective freeing using ->nofree so that the client can
405 * keep the data for various purposes.
a25832e6 406 *
b8d0da45 407 * If ->nofree is nonzero, the frame will be delinked from the global list,
408 * but will not be free'ed. The client _must_ keep a pointer to the
409 * data -- libfaim will not! If the client marks ->nofree but
410 * does not keep a pointer, it's lost forever.
a25832e6 411 *
9de3ca7e 412 */
d410cf58 413faim_export void aim_purge_rxqueue(aim_session_t *sess)
414{
415 aim_frame_t *cur, **prev;
416
417 for (prev = &sess->queue_incoming; (cur = *prev); ) {
418 if (cur->handled) {
419
420 *prev = cur->next;
421
422 if (!cur->nofree)
423 aim_frame_destroy(cur);
424
425 } else
426 prev = &cur->next;
427 }
428
429 return;
9de3ca7e 430}
68ac63c2 431
432/*
433 * Since aim_get_command will aim_conn_kill dead connections, we need
434 * to clean up the rxqueue of unprocessed connections on that socket.
435 *
436 * XXX: this is something that was handled better in the old connection
437 * handling method, but eh.
438 */
d410cf58 439faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn)
68ac63c2 440{
d410cf58 441 aim_frame_t *currx;
68ac63c2 442
d410cf58 443 for (currx = sess->queue_incoming; currx; currx = currx->next) {
444 if ((!currx->handled) && (currx->conn == conn))
445 currx->handled = 1;
446 }
447 return;
68ac63c2 448}
d410cf58 449
This page took 0.924577 seconds and 5 git commands to generate.