comparison src/protocols/oscar/rxqueue.c @ 2246:933346315b9b

[gaim-migrate @ 2256] heh. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sun, 09 Sep 2001 10:07:14 +0000
parents 424a40f12a6c
children d82efea341ef
comparison
equal deleted inserted replaced
2245:31157c54fe6e 2246:933346315b9b
12 #ifndef _WIN32 12 #ifndef _WIN32
13 #include <sys/socket.h> 13 #include <sys/socket.h>
14 #endif 14 #endif
15 15
16 /* 16 /*
17 * Since not all implementations support MSG_WAITALL, define
18 * an alternate guarenteed read function...
19 *
20 * We keep recv() for systems that can do it because it means
21 * a single system call for the entire packet, where read may
22 * take more for a badly fragmented packet.
23 * 17 *
24 */ 18 */
25 faim_internal int aim_recv(int fd, void *buf, size_t count) 19 faim_internal int aim_recv(int fd, void *buf, size_t count)
26 { 20 {
27 #ifdef MSG_WAITALL 21 int left, cur;
28 return recv(fd, buf, count, MSG_WAITALL); 22
29 #else 23 for (cur = 0, left = count; left; ) {
30 int left, ret, cur = 0; 24 int ret;
31 25
32 left = count; 26 ret = recv(fd, ((unsigned char *)buf)+cur, left, 0);
33 27 if (ret == -1)
34 while (left) { 28 return -1;
35 ret = recv(fd, ((unsigned char *)buf)+cur, left, 0); 29 else if (ret == 0)
36 if (ret == -1) 30 return cur;
37 return -1; 31
38 if (ret == 0) 32 cur += ret;
39 return cur; 33 left -= ret;
40 34 }
41 cur += ret; 35
42 left -= ret; 36 return cur;
43 } 37 }
44 38
45 return cur; 39 /*
46 #endif 40 * Read into a byte stream. Will not read more than count, but may read
47 } 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
48 276
49 /* 277 /*
50 * Grab a single command sequence off the socket, and enqueue 278 * Grab a single command sequence off the socket, and enqueue
51 * it in the incoming event queue in a seperate struct. 279 * it in the incoming event queue in a seperate struct.
52 */ 280 */
53 faim_export int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn) 281 faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn)
54 { 282 {
55 unsigned char generic[6]; 283 fu8_t flaphdr_raw[6];
56 struct command_rx_struct *newrx = NULL; 284 aim_bstream_t flaphdr;
57 285 aim_frame_t *newrx;
58 if (!sess || !conn) 286 fu16_t payloadlen;
59 return 0; 287
60 288 if (!sess || !conn)
61 if (conn->fd == -1) 289 return 0;
62 return -1; /* its a aim_conn_close()'d connection */ 290
63 291 if (conn->fd == -1)
64 if (conn->fd < 3) /* can happen when people abuse the interface */ 292 return -1; /* its a aim_conn_close()'d connection */
65 return 0; 293
66 294 if (conn->fd < 3) /* can happen when people abuse the interface */
67 if (conn->status & AIM_CONN_STATUS_INPROGRESS) 295 return 0;
68 return aim_conn_completeconnect(sess, conn); 296
69 297 if (conn->status & AIM_CONN_STATUS_INPROGRESS)
70 /* 298 return aim_conn_completeconnect(sess, conn);
71 * Rendezvous (client-client) connections do not speak 299
72 * FLAP, so this function will break on them. 300 /*
73 */ 301 * Rendezvous (client-client) connections do not speak
74 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) 302 * FLAP, so this function will break on them.
75 return aim_get_command_rendezvous(sess, conn); 303 */
76 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { 304 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
77 faimdprintf(sess, 0, "out on fd %d\n", conn->fd); 305 return aim_get_command_rendezvous(sess, conn);
78 return 0; 306 else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
79 } 307 faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd);
80 308 return 0;
81 /* 309 }
82 * Read FLAP header. Six bytes: 310
83 * 311 aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));
84 * 0 char -- Always 0x2a 312
85 * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. 313 /*
86 * 2 short -- Sequence number 314 * Read FLAP header. Six bytes:
87 * 4 short -- Number of data bytes that follow. 315 *
88 */ 316 * 0 char -- Always 0x2a
89 faim_mutex_lock(&conn->active); 317 * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login.
90 if (aim_recv(conn->fd, generic, 6) < 6){ 318 * 2 short -- Sequence number
91 aim_conn_close(conn); 319 * 4 short -- Number of data bytes that follow.
92 faim_mutex_unlock(&conn->active); 320 */
93 return -1; 321 faim_mutex_lock(&conn->active);
94 } 322 if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
95 323 aim_conn_close(conn);
96 /* 324 faim_mutex_unlock(&conn->active);
97 * This shouldn't happen unless the socket breaks, the server breaks, 325 return -1;
98 * or we break. We must handle it just in case. 326 }
99 */ 327
100 if (generic[0] != 0x2a) { 328 aim_bstream_rewind(&flaphdr);
101 faimdprintf(sess, 1, "Bad incoming data!"); 329
102 aim_conn_close(conn); 330 /*
103 faim_mutex_unlock(&conn->active); 331 * This shouldn't happen unless the socket breaks, the server breaks,
104 return -1; 332 * or we break. We must handle it just in case.
105 } 333 */
106 334 if (aimbs_get8(&flaphdr) != 0x2a) {
107 /* allocate a new struct */ 335 faimdprintf(sess, 0, "FLAP framing disrupted");
108 if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) { 336 aim_conn_close(conn);
109 faim_mutex_unlock(&conn->active); 337 faim_mutex_unlock(&conn->active);
110 return -1; 338 return -1;
111 } 339 }
112 memset(newrx, 0x00, sizeof(struct command_rx_struct)); 340
113 341 /* allocate a new struct */
114 newrx->lock = 1; /* lock the struct */ 342 if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) {
115 343 faim_mutex_unlock(&conn->active);
116 /* we're doing OSCAR if we're here */ 344 return -1;
117 newrx->hdrtype = AIM_FRAMETYPE_OSCAR; 345 }
118 346 memset(newrx, 0, sizeof(aim_frame_t));
119 /* store channel -- byte 2 */ 347
120 newrx->hdr.oscar.type = (char) generic[1]; 348 /* we're doing FLAP if we're here */
121 349 newrx->hdrtype = AIM_FRAMETYPE_FLAP;
122 /* store seqnum -- bytes 3 and 4 */ 350
123 newrx->hdr.oscar.seqnum = aimutil_get16(generic+2); 351 newrx->hdr.flap.type = aimbs_get8(&flaphdr);
124 352 newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
125 /* store commandlen -- bytes 5 and 6 */ 353 payloadlen = aimbs_get16(&flaphdr);
126 newrx->commandlen = aimutil_get16(generic+4); 354
127 355 newrx->nofree = 0; /* free by default */
128 newrx->nofree = 0; /* free by default */ 356
129 357 if (payloadlen) {
130 /* malloc for data portion */ 358 fu8_t *payload = NULL;
131 if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) { 359
132 free(newrx); 360 if (!(payload = (fu8_t *) malloc(payloadlen))) {
133 faim_mutex_unlock(&conn->active); 361 aim_frame_destroy(newrx);
134 return -1; 362 faim_mutex_unlock(&conn->active);
135 } 363 return -1;
136 364 }
137 /* read the data portion of the packet */ 365
138 if (aim_recv(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){ 366 aim_bstream_init(&newrx->data, payload, payloadlen);
139 free(newrx->data); 367
140 free(newrx); 368 /* read the payload */
141 aim_conn_close(conn); 369 if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) {
142 faim_mutex_unlock(&conn->active); 370 free(payload);
143 return -1; 371 aim_frame_destroy(newrx);
144 } 372 aim_conn_close(conn);
145 faim_mutex_unlock(&conn->active); 373 faim_mutex_unlock(&conn->active);
146 374 return -1;
147 newrx->conn = conn; 375 }
148 376 } else
149 newrx->next = NULL; /* this will always be at the bottom */ 377 aim_bstream_init(&newrx->data, NULL, 0);
150 newrx->lock = 0; /* unlock */ 378
151 379 faim_mutex_unlock(&conn->active);
152 /* enqueue this packet */ 380
153 if (sess->queue_incoming == NULL) { 381 aim_bstream_rewind(&newrx->data);
154 sess->queue_incoming = newrx; 382
155 } else { 383 newrx->conn = conn;
156 struct command_rx_struct *cur; 384
157 385 newrx->next = NULL; /* this will always be at the bottom */
158 /* 386
159 * This append operation takes a while. It might be faster 387 if (!sess->queue_incoming)
160 * if we maintain a pointer to the last entry in the queue 388 sess->queue_incoming = newrx;
161 * and just update that. Need to determine if the overhead 389 else {
162 * to maintain that is lower than the overhead for this loop. 390 aim_frame_t *cur;
163 */ 391
164 for (cur = sess->queue_incoming; cur->next; cur = cur->next) 392 for (cur = sess->queue_incoming; cur->next; cur = cur->next)
165 ; 393 ;
166 cur->next = newrx; 394 cur->next = newrx;
167 } 395 }
168 396
169 newrx->conn->lastactivity = time(NULL); 397 newrx->conn->lastactivity = time(NULL);
170 398
171 return 0; 399 return 0;
172 } 400 }
173 401
174 /* 402 /*
175 * Purge recieve queue of all handled commands (->handled==1). Also 403 * Purge recieve queue of all handled commands (->handled==1). Also
176 * allows for selective freeing using ->nofree so that the client can 404 * allows for selective freeing using ->nofree so that the client can
180 * but will not be free'ed. The client _must_ keep a pointer to the 408 * but will not be free'ed. The client _must_ keep a pointer to the
181 * data -- libfaim will not! If the client marks ->nofree but 409 * data -- libfaim will not! If the client marks ->nofree but
182 * does not keep a pointer, it's lost forever. 410 * does not keep a pointer, it's lost forever.
183 * 411 *
184 */ 412 */
185 faim_export void aim_purge_rxqueue(struct aim_session_t *sess) 413 faim_export void aim_purge_rxqueue(aim_session_t *sess)
186 { 414 {
187 struct command_rx_struct *cur = NULL; 415 aim_frame_t *cur, **prev;
188 struct command_rx_struct *tmp; 416
189 417 for (prev = &sess->queue_incoming; (cur = *prev); ) {
190 if (sess->queue_incoming == NULL) 418 if (cur->handled) {
191 return; 419
192 420 *prev = cur->next;
193 if (sess->queue_incoming->next == NULL) { 421
194 if (sess->queue_incoming->handled) { 422 if (!cur->nofree)
195 tmp = sess->queue_incoming; 423 aim_frame_destroy(cur);
196 sess->queue_incoming = NULL; 424
197 425 } else
198 if (!tmp->nofree) { 426 prev = &cur->next;
199 if (tmp->hdrtype == AIM_FRAMETYPE_OFT) 427 }
200 free(tmp->hdr.oft.hdr2); 428
201 free(tmp->data); 429 return;
202 free(tmp);
203 } else
204 tmp->next = NULL;
205 }
206 return;
207 }
208
209 for(cur = sess->queue_incoming; cur->next != NULL; ) {
210 if (cur->next->handled) {
211 tmp = cur->next;
212 cur->next = tmp->next;
213 if (!tmp->nofree) {
214 if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
215 free(tmp->hdr.oft.hdr2);
216 free(tmp->data);
217 free(tmp);
218 } else
219 tmp->next = NULL;
220 }
221 cur = cur->next;
222
223 /*
224 * Be careful here. Because of the way we just
225 * manipulated the pointer, cur may be NULL and
226 * the for() will segfault doing the check unless
227 * we find this case first.
228 */
229 if (cur == NULL)
230 break;
231 }
232
233 return;
234 } 430 }
235 431
236 /* 432 /*
237 * Since aim_get_command will aim_conn_kill dead connections, we need 433 * Since aim_get_command will aim_conn_kill dead connections, we need
238 * to clean up the rxqueue of unprocessed connections on that socket. 434 * to clean up the rxqueue of unprocessed connections on that socket.
239 * 435 *
240 * XXX: this is something that was handled better in the old connection 436 * XXX: this is something that was handled better in the old connection
241 * handling method, but eh. 437 * handling method, but eh.
242 */ 438 */
243 faim_internal void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn) 439 faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn)
244 { 440 {
245 struct command_rx_struct *currx; 441 aim_frame_t *currx;
246 442
247 for (currx = sess->queue_incoming; currx; currx = currx->next) { 443 for (currx = sess->queue_incoming; currx; currx = currx->next) {
248 if ((!currx->handled) && (currx->conn == conn)) 444 if ((!currx->handled) && (currx->conn == conn))
249 currx->handled = 1; 445 currx->handled = 1;
250 } 446 }
251 return; 447 return;
252 } 448 }
449