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.87 by root, Tue Nov 6 03:45:17 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 },
200{ 199{
201 return (!(pkt->flags & PF_PLAYER) || pl) 200 return (!(pkt->flags & PF_PLAYER) || pl)
202 && (!(pkt->flags & PF_PLAYING) || state == ST_PLAYING); 201 && (!(pkt->flags & PF_PLAYING) || state == ST_PLAYING);
203} 202}
204 203
205// HACK: some commands currently should be executed 204// HACK: some commands currently should be executed
206// even when the player is frozen. this hack detects 205// even when the player is frozen. this hack detects
207// those commands. it should be folded into may_execute, 206// those commands. it should be folded into may_execute,
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 + 4096 > 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 //TODO 448 {
449 uint8 *a = buf;
450 uint8 *b = a;
451 uint8 *c = a + len;
452
453 for (; a < c; ++a, ++b)
454 {
455 *b = *a;
456
457 if (*a >= 0x80)
458 *b = (a [0] & 0x1f) << 6 | (a [1] & 0x3f), ++a;
459 }
460
461 len -= a - b;
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 }
427 break; 476 break;
428 case 2: // binary
429 break;
430 477
431 case 9: // ping 478 case 9: // ping
432 { 479 {
433 // send pong - we assume ping messages are <64k 480 // send pong - we assume ping messages are <64k
434 // as we can't handle >10k at the moment anyway. 481 // as we can't handle >10k at the moment anyway.
435 uint8 hdr [] = { 0x8a, 126, l >> 8, l }; 482 uint8 hdr [] = { 0x8a, 126, len >> 8, len };
436 send (hdr, sizeof (hdr)); 483 send (hdr, sizeof (hdr));
437 send (inbuf + inbuf_len, l); 484 send (inbuf + inbuf_len, len);
438 } 485 }
439 return; 486 break;
440 487
441 case 10: // pong 488 case 10: // pong
442 return; 489 break;
443 490
444 case 8: // close 491 case 8: // close
445 default: 492 default:
446 destroy (); 493 destroy ();
447 return; 494 return;
448 } 495 }
449
450 amount = l;
451 } 496 }
452 else
453 amount = -1;
454 }
455 else
456 amount = read (fd, inbuf + inbuf_len, amount);
457
458 if (!amount)
459 {
460 destroy ();
461 return;
462 }
463 else if (amount < 0)
464 {
465 if (errno != EAGAIN && errno != EINTR)
466 {
467 LOG (llevError, "read error: %s\n", strerror (errno));
468 destroy ();
469 return;
470 }
471
472 // should not be here, normally
473 } 497 }
474 else 498 else
475 { 499 {
476 inbuf_len += amount; 500 inbuf_len += amount;
477 inbuf_handle (); 501 inbuf_handle ();
554 if (!sl.length ()) 578 if (!sl.length ())
555 return; 579 return;
556 580
557 if (ws_version == 8) 581 if (ws_version == 8)
558 { 582 {
559 uint8 hdr [4] = { 0x81, 126, sl.length () >> 8, sl.length () }; 583 static uint8 buf [MAXSOCKBUF * 2 + 4];
560 // TODO: utf-8 encoding 584
561 send (hdr, 4); 585 uint8 *b = buf + 4;
562 send (sl.buf_ + sl.hdrlen, sl.cur - sl.buf_ - sl.hdrlen); 586 for (uint8 *a = sl.buf_ + sl.hdrlen; a < sl.cur; ++a)
587 {
588 if (*a < 0x80)
589 *b++ = *a;
590 else
591 {
592 *b++ = 0xc0 | ((*a >> 6) & 0x1f);
593 *b++ = 0x80 | ( *a & 0x3f);
594 }
595 }
596
597 assert (b - buf < sizeof (buf));
598
599 int len = b - (buf + 4);
600
601 if (len < 126)
602 {
603 buf [2] = 0x81;
604 buf [3] = len;
605
606 send (buf + 2, len + 2);
607 }
608 else
609 {
610 buf [0] = 0x81;
611 buf [1] = 126;
612 buf [2] = len >> 8;
613 buf [3] = len;
614
615 send (buf, len + 4);
616 }
563 } 617 }
564 else if (ws_version == 13) 618 else if (ws_version == 13)
565 { 619 {
620 int len = sl.length ();
621
622 if (len < 126)
623 {
624 uint8 hdr [] = { 0x82, len };
625 send (hdr, sizeof (hdr));
626 }
627 else
628 {
566 uint8 hdr [4] = { 0x82, 126, sl.length () >> 8, sl.length () }; 629 uint8 hdr [] = { 0x82, 126, len >> 8, len };
567 send (hdr, 4); 630 send (hdr, sizeof (hdr));
631 }
632
568 send (sl.buf_ + sl.hdrlen, sl.cur - sl.buf_ - sl.hdrlen); 633 send (sl.buf_ + sl.hdrlen, len);
569 } 634 }
570 else 635 else
571 { 636 {
572 assert (sl.hdrlen == 2); 637 assert (sl.hdrlen == 2);
573 638

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines