ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/lowlevel.C
(Generate patch)

Comparing deliantra/server/socket/lowlevel.C (file contents):
Revision 1.89 by root, Tue Nov 6 21:50:36 2012 UTC vs.
Revision 1.94 by root, Sun Nov 18 09:29:25 2012 UTC

48 * 48 *
49 * When the socket is clear to write, and we have backlogged data, this 49 * When the socket is clear to write, and we have backlogged data, this
50 * is called to write it out. 50 * is called to write it out.
51 */ 51 */
52 52
53 // write a nop to the socket at least every IDLE_NOP seconds. 53 // write a nop to the socket at least every IDLE_PING seconds.
54 if (!outputbuffer.len) 54 if (!outputbuffer.len)
55 { 55 {
56 if (last_send + IDLE_PING <= NOW && pl && pl->active) 56 if (last_send + IDLE_PING <= NOW && pl && pl->active)
57 { 57 {
58 // this is a bit ugly, but map1a seems to be the only 58 // this is a bit ugly, but map1a seems to be the only
132 if (inbuf_len >= 2 + pkt_len) 132 if (inbuf_len >= 2 + pkt_len)
133 return 2 + pkt_len; 133 return 2 + pkt_len;
134 134
135 if (inbuf_len == sizeof (inbuf)) 135 if (inbuf_len == sizeof (inbuf))
136 { 136 {
137 send_packet_printf ("drawinfo %d input buffer overflow - closing connection.", NDI_RED | NDI_REPLY); 137 send_packet_printf ("msg %d log input buffer overflow - closing connection.", NDI_RED | NDI_REPLY);
138 destroy (); 138 destroy ();
139 return -1; 139 return -1;
140 } 140 }
141 } 141 }
142 142
167 167
168/** 168/**
169 * Dispatch table for the server. 169 * Dispatch table for the server.
170 */ 170 */
171static struct packet_type packets[] = { 171static struct packet_type packets[] = {
172 {"ncom", PC(NewPlayerCmd) PF_PLAYING | PF_COMMAND6 },
173 {"command", PC(PlayerCmd) PF_PLAYING | PF_COMMAND0 }, 172 {"command", PC(PlayerCmd) PF_PLAYING | PF_COMMAND },
174 173
175 {"examine", PC(ExamineCmd) PF_PLAYING }, 174 {"examine", PC(ExamineCmd) PF_PLAYING },
176 {"ex", PC(ExCmd) PF_PLAYING }, 175 {"ex", PC(ExCmd) PF_PLAYING },
177 {"apply", PC(ApplyCmd) PF_PLAYING }, 176 {"apply", PC(ApplyCmd) PF_PLAYING },
178 {"lookat", PC(LookAt) PF_PLAYING }, 177 {"lookat", PC(LookAt) PF_PLAYING },
208// but kept seperate to emphasise the hack aspect, i.e. 207// but kept seperate to emphasise the hack aspect, i.e.
209// do it better, then remove. 208// do it better, then remove.
210static bool 209static bool
211always_immediate (const client *ns, const packet_type *pkt, const char *data, int len) 210always_immediate (const client *ns, const packet_type *pkt, const char *data, int len)
212{ 211{
213 if (!(pkt->flags & (PF_COMMAND0 | PF_COMMAND6))) 212 if (!(pkt->flags & PF_COMMAND))
214 return false; 213 return false;
215 214
216 if (!ns->pl || !ns->pl->ob || !ns->pl->ob->map) 215 if (!ns->pl || !ns->pl->ob || !ns->pl->ob->map)
217 return false; 216 return false;
218
219 if (pkt->flags & PF_COMMAND6)
220 {
221 data += 6;
222 len -= 6;
223 }
224 217
225 if (len > 4 && data [ 3] == ' ' && !strncmp (data, "say " , 4)) return true; 218 if (len > 4 && data [ 3] == ' ' && !strncmp (data, "say " , 4)) return true;
226 if (len > 5 && data [ 4] == ' ' && !strncmp (data, "chat " , 5)) return true; 219 if (len > 5 && data [ 4] == ' ' && !strncmp (data, "chat " , 5)) return true;
227 if (len > 6 && data [ 5] == ' ' && !strncmp (data, "shout " , 6)) return true; 220 if (len > 6 && data [ 5] == ' ' && !strncmp (data, "shout " , 6)) return true;
228 if (len > 8 && data [ 7] == ' ' && !strncmp (data, "suicide " , 8)) return true; 221 if (len > 8 && data [ 7] == ' ' && !strncmp (data, "suicide " , 8)) return true;
298 291
299 goto next_packet; 292 goto next_packet;
300 } 293 }
301 294
302 // If we get here, we didn't find a valid command. 295 // If we get here, we didn't find a valid command.
303 send_packet_printf ("drawinfo %d ERROR: command '%s' not supported.", NDI_RED | NDI_REPLY, (char *)inbuf + 2); 296 send_packet_printf ("msg %d log ERROR: command '%s' not supported.", NDI_RED | NDI_REPLY, (char *)inbuf + 2);
304 297
305next_packet: 298next_packet:
306 inbuf [pkt_len] = save_byte; // rather ugly 299 inbuf [pkt_len] = save_byte; // rather ugly
307 skip_packet (pkt_len); 300 skip_packet (pkt_len);
308 301
343 socket_ev.poll (socket_ev.poll () & ~EV_WRITE); 336 socket_ev.poll (socket_ev.poll () & ~EV_WRITE);
344 } 337 }
345 338
346 if (revents & EV_READ) 339 if (revents & EV_READ)
347 { 340 {
348 //TODO: rate-limit tcp connection in better ways, important 341 int amount;
342 uint8 *rbuf;
349 343
344 if (ws_version)
345 {
346 if (ws_inbuf_len + 2048 > ws_inbuf_alloc)
347 ws_inbuf = (uint8 *)realloc (ws_inbuf, ws_inbuf_alloc += 4096);
348
349 rbuf = ws_inbuf + ws_inbuf_len;
350 amount = ws_inbuf_alloc - ws_inbuf_len;
351 }
352 else
353 {
354 rbuf = inbuf + inbuf_len;
350 int amount = sizeof (inbuf) - inbuf_len; 355 amount = sizeof (inbuf) - inbuf_len;
356 }
351 357
352 if (!amount) 358 if (!amount)
353 { 359 {
354 // input buffer full 360 // input buffer full
355 LOG (llevError, "input buffer overflow."); 361 LOG (llevError, "input buffer overflow.");
356 destroy (); 362 destroy ();
357 return; 363 return;
358 } 364 }
359 365
366 amount = read (fd, rbuf, amount);
367
368 if (!amount)
369 {
370 destroy ();
371 return;
372 }
373 else if (amount < 0)
374 {
375 if (errno != EAGAIN && errno != EINTR)
376 {
377 LOG (llevError, "read error: %s\n", strerror (errno));
378 destroy ();
379 return;
380 }
381
382 // should not be here, normally
383 }
384
360 if (ws_version) 385 if (ws_version)
361 { 386 {
362 if (ws_inbuf_len + 2048 > ws_inbuf_alloc) 387 ws_inbuf_len += amount;
363 ws_inbuf = (uint8 *)realloc (ws_inbuf, ws_inbuf_alloc += 4096);
364 388
365 int len = read (fd, ws_inbuf + ws_inbuf_len, ws_inbuf_alloc - ws_inbuf_len); 389 while (ws_inbuf_len)
366
367 if (len > 0)
368 { 390 {
369 ws_inbuf_len += len;
370
371 if (ws_inbuf_len < 2 + 4) // 6 is minimum length: op, len, mask 391 if (ws_inbuf_len < 2 + 4) // 6 is minimum length: op, len, mask
372 return; 392 break;
373 393
374 int d = 2; 394 int d = 2;
395 int fin = ws_inbuf [0] & 0x80;
375 int o = ws_inbuf [0] & 15; 396 int op = ws_inbuf [0] & 0x0f;
376 int l = ws_inbuf [1] & 127; 397 int len = ws_inbuf [1] & 0x7f;
377 398
378 if (l == 126) 399 if (len == 126)
379 { 400 {
380 l = (ws_inbuf [2] << 8) | ws_inbuf [3]; 401 len = (ws_inbuf [2] << 8) | ws_inbuf [3];
381 d += 2; 402 d += 2;
382 } 403 }
383 else if (l == 127) 404 else if (len == 127)
384 { 405 {
385 if (ws_inbuf_len < 2 + 8) 406 if (ws_inbuf_len < 2 + 8)
386 return; 407 return;
387 408
388 // we don't do extra long frames, if a browser wants to send >2**32 bytes, 409 // we don't do extra long frames, if a browser wants to send >2**32 bytes,
389 // there are bigger issues to fix. 410 // there are bigger issues to fix.
390 l = (ws_inbuf [6] << 24) 411 len = (ws_inbuf [8] << 8) | ws_inbuf [9];
391 | (ws_inbuf [7] << 16)
392 | (ws_inbuf [8] << 8)
393 | ws_inbuf [9];
394 d += 8; 412 d += 8;
395 } 413 }
396 414
397 // we only continue if we have a complete frame 415 // we only continue if we have a complete frame
398 if (ws_inbuf_len < d + 4 + l) 416 if (ws_inbuf_len < d + 4 + len)
399 return; 417 return;
400 418
401 switch (o) 419 switch (op)
402 { 420 {
403 case 0: o = ws_inbuf_type; break; // continuation 421 case 0: op = ws_inbuf_type; break; // continuation
404 case 1: ws_inbuf_type = 1; break; // utf-8 422 case 1: ws_inbuf_type = 1; break; // utf-8
405 case 2: ws_inbuf_type = 2; break; // binary 423 case 2: ws_inbuf_type = 2; break; // binary
406 } 424 }
407 425
408 if (l > amount) 426 if (len > sizeof (inbuf) - inbuf_len)
409 { 427 {
410 // input buffer full 428 // input buffer full
411 LOG (llevError, "input buffer overflow (ws)."); 429 LOG (llevError, "input buffer overflow (ws).");
412 destroy (); 430 destroy ();
413 return; 431 return;
414 } 432 }
415 433
434 uint8 *buf = inbuf + inbuf_len + 2;
435
416 for (int i = 0; i < l; ++i) 436 for (int i = 0; i < len; ++i)
417 inbuf [inbuf_len + i] = ws_inbuf [d + 4 + i] ^ ws_inbuf [d + (i & 3)]; 437 buf [i] = ws_inbuf [d + 4 + i] ^ ws_inbuf [d + (i & 3)];
418 438
419 // remove frame 439 // remove frame
420 ws_inbuf_len -= d + 4 + l; 440 ws_inbuf_len -= d + 4 + len;
421 memmove (ws_inbuf, ws_inbuf + d + 4 + l, ws_inbuf_len); 441 memmove (ws_inbuf, ws_inbuf + d + 4 + len, ws_inbuf_len);
422 442
423 switch (o) 443 switch (op)
424 { 444 {
425 case 1: // utf-8 445 case 1: // utf-8
446 // utf-8 encoded frames cannot have full length (MAXSOCKBUF) in all cases
447 // but we assume that these extra-long packets will be rare.
426 { 448 {
427 uint8 *a = inbuf + inbuf_len; 449 uint8 *a = buf;
428 uint8 *b = a; 450 uint8 *b = a;
429 uint8 *c = a + l; 451 uint8 *c = a + len;
430 452
431 for (; a < c; ++a, ++b) 453 for (; a < c; ++a, ++b)
432 { 454 {
433 *b = *a; 455 *b = *a;
434 456
435 if (*a >= 0x80) 457 if (*a >= 0x80)
436 *b = (a [0] & 0x1f) << 6 | (a [1] & 0x3f), ++a; 458 *b = (a [0] & 0x1f) << 6 | (a [1] & 0x3f), ++a;
437 } 459 }
438 460
439 l -= a - b; 461 len -= a - b;
440 } 462 }
463 /* FALLTHROUGH */
464 case 2: // binary
465 inbuf_len += len;
466
467 if (fin)
468 {
469 inbuf [0] = inbuf_len >> 8;
470 inbuf [1] = inbuf_len;
471
472 inbuf_len += 2;
473
474 inbuf_handle ();
475 }
441 break; 476 break;
442 case 2: // binary
443 break;
444 477
445 case 9: // ping 478 case 9: // ping
446 { 479 {
447 // send pong - we assume ping messages are <64k 480 // send pong - we assume ping messages are <64k
448 // as we can't handle >10k at the moment anyway. 481 // as we can't handle >10k at the moment anyway.
449 uint8 hdr [] = { 0x8a, 126, l >> 8, l }; 482 uint8 hdr [] = { 0x8a, 126, len >> 8, len };
450 send (hdr, sizeof (hdr)); 483 send (hdr, sizeof (hdr));
451 send (inbuf + inbuf_len, l); 484 send (inbuf + inbuf_len, len);
452 } 485 }
453 return; 486 break;
454 487
455 case 10: // pong 488 case 10: // pong
456 return; 489 break;
457 490
458 case 8: // close 491 case 8: // close
459 default: 492 default:
460 destroy (); 493 destroy ();
461 return; 494 return;
462 } 495 }
463
464 amount = l;
465 } 496 }
466 else
467 amount = -1;
468 }
469 else
470 amount = read (fd, inbuf + inbuf_len, amount);
471
472 if (!amount)
473 {
474 destroy ();
475 return;
476 }
477 else if (amount < 0)
478 {
479 if (errno != EAGAIN && errno != EINTR)
480 {
481 LOG (llevError, "read error: %s\n", strerror (errno));
482 destroy ();
483 return;
484 }
485
486 // should not be here, normally
487 } 497 }
488 else 498 else
489 { 499 {
490 inbuf_len += amount; 500 inbuf_len += amount;
491 inbuf_handle (); 501 inbuf_handle ();
584 } 594 }
585 } 595 }
586 596
587 assert (b - buf < sizeof (buf)); 597 assert (b - buf < sizeof (buf));
588 598
589 int l = b - (buf + 4); 599 int len = b - (buf + 4);
590 600
591 if (l < 126) 601 if (len < 126)
592 { 602 {
593 buf [2] = 0x81; 603 buf [2] = 0x81;
594 buf [3] = l; 604 buf [3] = len;
595 605
596 send (buf + 2, l + 2); 606 send (buf + 2, len + 2);
597 } 607 }
598 else 608 else
599 { 609 {
600 buf [0] = 0x81; 610 buf [0] = 0x81;
601 buf [1] = 126; 611 buf [1] = 126;
602 buf [2] = l >> 8; 612 buf [2] = len >> 8;
603 buf [3] = l; 613 buf [3] = len;
604 614
605 send (buf, l + 4); 615 send (buf, len + 4);
606 } 616 }
607 } 617 }
608 else if (ws_version == 13) 618 else if (ws_version == 13)
609 { 619 {
610 int l = sl.length (); 620 int len = sl.length ();
611 621
612 if (l < 126) 622 if (len < 126)
613 { 623 {
614 uint8 hdr [] = { 0x82, l }; 624 uint8 hdr [] = { 0x82, len };
615 send (hdr, sizeof (hdr)); 625 send (hdr, sizeof (hdr));
616 } 626 }
617 else 627 else
618 { 628 {
619 uint8 hdr [] = { 0x82, 126, l >> 8, l }; 629 uint8 hdr [] = { 0x82, 126, len >> 8, len };
620 send (hdr, sizeof (hdr)); 630 send (hdr, sizeof (hdr));
621 } 631 }
622 632
623 send (sl.buf_ + sl.hdrlen, l); 633 send (sl.buf_ + sl.hdrlen, len);
624 } 634 }
625 else 635 else
626 { 636 {
627 assert (sl.hdrlen == 2); 637 assert (sl.hdrlen == 2);
628 638

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines