net_chan.c (17808B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 23 #include "../game/q_shared.h" 24 #include "qcommon.h" 25 26 /* 27 28 packet header 29 ------------- 30 4 outgoing sequence. high bit will be set if this is a fragmented message 31 [2 qport (only for client to server)] 32 [2 fragment start byte] 33 [2 fragment length. if < FRAGMENT_SIZE, this is the last fragment] 34 35 if the sequence number is -1, the packet should be handled as an out-of-band 36 message instead of as part of a netcon. 37 38 All fragments will have the same sequence numbers. 39 40 The qport field is a workaround for bad address translating routers that 41 sometimes remap the client's source port on a packet during gameplay. 42 43 If the base part of the net address matches and the qport matches, then the 44 channel matches even if the IP port differs. The IP port should be updated 45 to the new value before sending out any replies. 46 47 */ 48 49 50 #define MAX_PACKETLEN 1400 // max size of a network packet 51 52 #define FRAGMENT_SIZE (MAX_PACKETLEN - 100) 53 #define PACKET_HEADER 10 // two ints and a short 54 55 #define FRAGMENT_BIT (1<<31) 56 57 cvar_t *showpackets; 58 cvar_t *showdrop; 59 cvar_t *qport; 60 61 static char *netsrcString[2] = { 62 "client", 63 "server" 64 }; 65 66 /* 67 =============== 68 Netchan_Init 69 70 =============== 71 */ 72 void Netchan_Init( int port ) { 73 port &= 0xffff; 74 showpackets = Cvar_Get ("showpackets", "0", CVAR_TEMP ); 75 showdrop = Cvar_Get ("showdrop", "0", CVAR_TEMP ); 76 qport = Cvar_Get ("net_qport", va("%i", port), CVAR_INIT ); 77 } 78 79 /* 80 ============== 81 Netchan_Setup 82 83 called to open a channel to a remote system 84 ============== 85 */ 86 void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) { 87 Com_Memset (chan, 0, sizeof(*chan)); 88 89 chan->sock = sock; 90 chan->remoteAddress = adr; 91 chan->qport = qport; 92 chan->incomingSequence = 0; 93 chan->outgoingSequence = 1; 94 } 95 96 // TTimo: unused, commenting out to make gcc happy 97 #if 0 98 /* 99 ============== 100 Netchan_ScramblePacket 101 102 A probably futile attempt to make proxy hacking somewhat 103 more difficult. 104 ============== 105 */ 106 #define SCRAMBLE_START 6 107 static void Netchan_ScramblePacket( msg_t *buf ) { 108 unsigned seed; 109 int i, j, c, mask, temp; 110 int seq[MAX_PACKETLEN]; 111 112 seed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 ); 113 c = buf->cursize; 114 if ( c <= SCRAMBLE_START ) { 115 return; 116 } 117 if ( c > MAX_PACKETLEN ) { 118 Com_Error( ERR_DROP, "MAX_PACKETLEN" ); 119 } 120 121 // generate a sequence of "random" numbers 122 for (i = 0 ; i < c ; i++) { 123 seed = (119 * seed + 1); 124 seq[i] = seed; 125 } 126 127 // transpose each character 128 for ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) { 129 } 130 mask >>= 1; 131 for (i = SCRAMBLE_START ; i < c ; i++) { 132 j = SCRAMBLE_START + ( seq[i] & mask ); 133 temp = buf->data[j]; 134 buf->data[j] = buf->data[i]; 135 buf->data[i] = temp; 136 } 137 138 // byte xor the data after the header 139 for (i = SCRAMBLE_START ; i < c ; i++) { 140 buf->data[i] ^= seq[i]; 141 } 142 } 143 144 static void Netchan_UnScramblePacket( msg_t *buf ) { 145 unsigned seed; 146 int i, j, c, mask, temp; 147 int seq[MAX_PACKETLEN]; 148 149 seed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 ); 150 c = buf->cursize; 151 if ( c <= SCRAMBLE_START ) { 152 return; 153 } 154 if ( c > MAX_PACKETLEN ) { 155 Com_Error( ERR_DROP, "MAX_PACKETLEN" ); 156 } 157 158 // generate a sequence of "random" numbers 159 for (i = 0 ; i < c ; i++) { 160 seed = (119 * seed + 1); 161 seq[i] = seed; 162 } 163 164 // byte xor the data after the header 165 for (i = SCRAMBLE_START ; i < c ; i++) { 166 buf->data[i] ^= seq[i]; 167 } 168 169 // transpose each character in reverse order 170 for ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) { 171 } 172 mask >>= 1; 173 for (i = c-1 ; i >= SCRAMBLE_START ; i--) { 174 j = SCRAMBLE_START + ( seq[i] & mask ); 175 temp = buf->data[j]; 176 buf->data[j] = buf->data[i]; 177 buf->data[i] = temp; 178 } 179 } 180 #endif 181 182 /* 183 ================= 184 Netchan_TransmitNextFragment 185 186 Send one fragment of the current message 187 ================= 188 */ 189 void Netchan_TransmitNextFragment( netchan_t *chan ) { 190 msg_t send; 191 byte send_buf[MAX_PACKETLEN]; 192 int fragmentLength; 193 194 // write the packet header 195 MSG_InitOOB (&send, send_buf, sizeof(send_buf)); // <-- only do the oob here 196 197 MSG_WriteLong( &send, chan->outgoingSequence | FRAGMENT_BIT ); 198 199 // send the qport if we are a client 200 if ( chan->sock == NS_CLIENT ) { 201 MSG_WriteShort( &send, qport->integer ); 202 } 203 204 // copy the reliable message to the packet first 205 fragmentLength = FRAGMENT_SIZE; 206 if ( chan->unsentFragmentStart + fragmentLength > chan->unsentLength ) { 207 fragmentLength = chan->unsentLength - chan->unsentFragmentStart; 208 } 209 210 MSG_WriteShort( &send, chan->unsentFragmentStart ); 211 MSG_WriteShort( &send, fragmentLength ); 212 MSG_WriteData( &send, chan->unsentBuffer + chan->unsentFragmentStart, fragmentLength ); 213 214 // send the datagram 215 NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress ); 216 217 if ( showpackets->integer ) { 218 Com_Printf ("%s send %4i : s=%i fragment=%i,%i\n" 219 , netsrcString[ chan->sock ] 220 , send.cursize 221 , chan->outgoingSequence 222 , chan->unsentFragmentStart, fragmentLength); 223 } 224 225 chan->unsentFragmentStart += fragmentLength; 226 227 // this exit condition is a little tricky, because a packet 228 // that is exactly the fragment length still needs to send 229 // a second packet of zero length so that the other side 230 // can tell there aren't more to follow 231 if ( chan->unsentFragmentStart == chan->unsentLength && fragmentLength != FRAGMENT_SIZE ) { 232 chan->outgoingSequence++; 233 chan->unsentFragments = qfalse; 234 } 235 } 236 237 238 /* 239 =============== 240 Netchan_Transmit 241 242 Sends a message to a connection, fragmenting if necessary 243 A 0 length will still generate a packet. 244 ================ 245 */ 246 void Netchan_Transmit( netchan_t *chan, int length, const byte *data ) { 247 msg_t send; 248 byte send_buf[MAX_PACKETLEN]; 249 250 if ( length > MAX_MSGLEN ) { 251 Com_Error( ERR_DROP, "Netchan_Transmit: length = %i", length ); 252 } 253 chan->unsentFragmentStart = 0; 254 255 // fragment large reliable messages 256 if ( length >= FRAGMENT_SIZE ) { 257 chan->unsentFragments = qtrue; 258 chan->unsentLength = length; 259 Com_Memcpy( chan->unsentBuffer, data, length ); 260 261 // only send the first fragment now 262 Netchan_TransmitNextFragment( chan ); 263 264 return; 265 } 266 267 // write the packet header 268 MSG_InitOOB (&send, send_buf, sizeof(send_buf)); 269 270 MSG_WriteLong( &send, chan->outgoingSequence ); 271 chan->outgoingSequence++; 272 273 // send the qport if we are a client 274 if ( chan->sock == NS_CLIENT ) { 275 MSG_WriteShort( &send, qport->integer ); 276 } 277 278 MSG_WriteData( &send, data, length ); 279 280 // send the datagram 281 NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress ); 282 283 if ( showpackets->integer ) { 284 Com_Printf( "%s send %4i : s=%i ack=%i\n" 285 , netsrcString[ chan->sock ] 286 , send.cursize 287 , chan->outgoingSequence - 1 288 , chan->incomingSequence ); 289 } 290 } 291 292 /* 293 ================= 294 Netchan_Process 295 296 Returns qfalse if the message should not be processed due to being 297 out of order or a fragment. 298 299 Msg must be large enough to hold MAX_MSGLEN, because if this is the 300 final fragment of a multi-part message, the entire thing will be 301 copied out. 302 ================= 303 */ 304 qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { 305 int sequence; 306 int qport; 307 int fragmentStart, fragmentLength; 308 qboolean fragmented; 309 310 // XOR unscramble all data in the packet after the header 311 // Netchan_UnScramblePacket( msg ); 312 313 // get sequence numbers 314 MSG_BeginReadingOOB( msg ); 315 sequence = MSG_ReadLong( msg ); 316 317 // check for fragment information 318 if ( sequence & FRAGMENT_BIT ) { 319 sequence &= ~FRAGMENT_BIT; 320 fragmented = qtrue; 321 } else { 322 fragmented = qfalse; 323 } 324 325 // read the qport if we are a server 326 if ( chan->sock == NS_SERVER ) { 327 qport = MSG_ReadShort( msg ); 328 } 329 330 // read the fragment information 331 if ( fragmented ) { 332 fragmentStart = MSG_ReadShort( msg ); 333 fragmentLength = MSG_ReadShort( msg ); 334 } else { 335 fragmentStart = 0; // stop warning message 336 fragmentLength = 0; 337 } 338 339 if ( showpackets->integer ) { 340 if ( fragmented ) { 341 Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n" 342 , netsrcString[ chan->sock ] 343 , msg->cursize 344 , sequence 345 , fragmentStart, fragmentLength ); 346 } else { 347 Com_Printf( "%s recv %4i : s=%i\n" 348 , netsrcString[ chan->sock ] 349 , msg->cursize 350 , sequence ); 351 } 352 } 353 354 // 355 // discard out of order or duplicated packets 356 // 357 if ( sequence <= chan->incomingSequence ) { 358 if ( showdrop->integer || showpackets->integer ) { 359 Com_Printf( "%s:Out of order packet %i at %i\n" 360 , NET_AdrToString( chan->remoteAddress ) 361 , sequence 362 , chan->incomingSequence ); 363 } 364 return qfalse; 365 } 366 367 // 368 // dropped packets don't keep the message from being used 369 // 370 chan->dropped = sequence - (chan->incomingSequence+1); 371 if ( chan->dropped > 0 ) { 372 if ( showdrop->integer || showpackets->integer ) { 373 Com_Printf( "%s:Dropped %i packets at %i\n" 374 , NET_AdrToString( chan->remoteAddress ) 375 , chan->dropped 376 , sequence ); 377 } 378 } 379 380 381 // 382 // if this is the final framgent of a reliable message, 383 // bump incoming_reliable_sequence 384 // 385 if ( fragmented ) { 386 // TTimo 387 // make sure we add the fragments in correct order 388 // either a packet was dropped, or we received this one too soon 389 // we don't reconstruct the fragments. we will wait till this fragment gets to us again 390 // (NOTE: we could probably try to rebuild by out of order chunks if needed) 391 if ( sequence != chan->fragmentSequence ) { 392 chan->fragmentSequence = sequence; 393 chan->fragmentLength = 0; 394 } 395 396 // if we missed a fragment, dump the message 397 if ( fragmentStart != chan->fragmentLength ) { 398 if ( showdrop->integer || showpackets->integer ) { 399 Com_Printf( "%s:Dropped a message fragment\n" 400 , NET_AdrToString( chan->remoteAddress ) 401 , sequence); 402 } 403 // we can still keep the part that we have so far, 404 // so we don't need to clear chan->fragmentLength 405 return qfalse; 406 } 407 408 // copy the fragment to the fragment buffer 409 if ( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize || 410 chan->fragmentLength + fragmentLength > sizeof( chan->fragmentBuffer ) ) { 411 if ( showdrop->integer || showpackets->integer ) { 412 Com_Printf ("%s:illegal fragment length\n" 413 , NET_AdrToString (chan->remoteAddress ) ); 414 } 415 return qfalse; 416 } 417 418 Com_Memcpy( chan->fragmentBuffer + chan->fragmentLength, 419 msg->data + msg->readcount, fragmentLength ); 420 421 chan->fragmentLength += fragmentLength; 422 423 // if this wasn't the last fragment, don't process anything 424 if ( fragmentLength == FRAGMENT_SIZE ) { 425 return qfalse; 426 } 427 428 if ( chan->fragmentLength > msg->maxsize ) { 429 Com_Printf( "%s:fragmentLength %i > msg->maxsize\n" 430 , NET_AdrToString (chan->remoteAddress ), 431 chan->fragmentLength ); 432 return qfalse; 433 } 434 435 // copy the full message over the partial fragment 436 437 // make sure the sequence number is still there 438 *(int *)msg->data = LittleLong( sequence ); 439 440 Com_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength ); 441 msg->cursize = chan->fragmentLength + 4; 442 chan->fragmentLength = 0; 443 msg->readcount = 4; // past the sequence number 444 msg->bit = 32; // past the sequence number 445 446 // TTimo 447 // clients were not acking fragmented messages 448 chan->incomingSequence = sequence; 449 450 return qtrue; 451 } 452 453 // 454 // the message can now be read from the current message pointer 455 // 456 chan->incomingSequence = sequence; 457 458 return qtrue; 459 } 460 461 462 //============================================================================== 463 464 /* 465 =================== 466 NET_CompareBaseAdr 467 468 Compares without the port 469 =================== 470 */ 471 qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b) 472 { 473 if (a.type != b.type) 474 return qfalse; 475 476 if (a.type == NA_LOOPBACK) 477 return qtrue; 478 479 if (a.type == NA_IP) 480 { 481 if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3]) 482 return qtrue; 483 return qfalse; 484 } 485 486 if (a.type == NA_IPX) 487 { 488 if ((memcmp(a.ipx, b.ipx, 10) == 0)) 489 return qtrue; 490 return qfalse; 491 } 492 493 494 Com_Printf ("NET_CompareBaseAdr: bad address type\n"); 495 return qfalse; 496 } 497 498 const char *NET_AdrToString (netadr_t a) 499 { 500 static char s[64]; 501 502 if (a.type == NA_LOOPBACK) { 503 Com_sprintf (s, sizeof(s), "loopback"); 504 } else if (a.type == NA_BOT) { 505 Com_sprintf (s, sizeof(s), "bot"); 506 } else if (a.type == NA_IP) { 507 Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%hu", 508 a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port)); 509 } else { 510 Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x:%hu", 511 a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], 512 BigShort(a.port)); 513 } 514 515 return s; 516 } 517 518 519 qboolean NET_CompareAdr (netadr_t a, netadr_t b) 520 { 521 if (a.type != b.type) 522 return qfalse; 523 524 if (a.type == NA_LOOPBACK) 525 return qtrue; 526 527 if (a.type == NA_IP) 528 { 529 if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port) 530 return qtrue; 531 return qfalse; 532 } 533 534 if (a.type == NA_IPX) 535 { 536 if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port) 537 return qtrue; 538 return qfalse; 539 } 540 541 Com_Printf ("NET_CompareAdr: bad address type\n"); 542 return qfalse; 543 } 544 545 546 qboolean NET_IsLocalAddress( netadr_t adr ) { 547 return adr.type == NA_LOOPBACK; 548 } 549 550 551 552 /* 553 ============================================================================= 554 555 LOOPBACK BUFFERS FOR LOCAL PLAYER 556 557 ============================================================================= 558 */ 559 560 // there needs to be enough loopback messages to hold a complete 561 // gamestate of maximum size 562 #define MAX_LOOPBACK 16 563 564 typedef struct { 565 byte data[MAX_PACKETLEN]; 566 int datalen; 567 } loopmsg_t; 568 569 typedef struct { 570 loopmsg_t msgs[MAX_LOOPBACK]; 571 int get, send; 572 } loopback_t; 573 574 loopback_t loopbacks[2]; 575 576 577 qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message) 578 { 579 int i; 580 loopback_t *loop; 581 582 loop = &loopbacks[sock]; 583 584 if (loop->send - loop->get > MAX_LOOPBACK) 585 loop->get = loop->send - MAX_LOOPBACK; 586 587 if (loop->get >= loop->send) 588 return qfalse; 589 590 i = loop->get & (MAX_LOOPBACK-1); 591 loop->get++; 592 593 Com_Memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen); 594 net_message->cursize = loop->msgs[i].datalen; 595 Com_Memset (net_from, 0, sizeof(*net_from)); 596 net_from->type = NA_LOOPBACK; 597 return qtrue; 598 599 } 600 601 602 void NET_SendLoopPacket (netsrc_t sock, int length, const void *data, netadr_t to) 603 { 604 int i; 605 loopback_t *loop; 606 607 loop = &loopbacks[sock^1]; 608 609 i = loop->send & (MAX_LOOPBACK-1); 610 loop->send++; 611 612 Com_Memcpy (loop->msgs[i].data, data, length); 613 loop->msgs[i].datalen = length; 614 } 615 616 //============================================================================= 617 618 619 void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to ) { 620 621 // sequenced packets are shown in netchan, so just show oob 622 if ( showpackets->integer && *(int *)data == -1 ) { 623 Com_Printf ("send packet %4i\n", length); 624 } 625 626 if ( to.type == NA_LOOPBACK ) { 627 NET_SendLoopPacket (sock, length, data, to); 628 return; 629 } 630 if ( to.type == NA_BOT ) { 631 return; 632 } 633 if ( to.type == NA_BAD ) { 634 return; 635 } 636 637 Sys_SendPacket( length, data, to ); 638 } 639 640 /* 641 =============== 642 NET_OutOfBandPrint 643 644 Sends a text message in an out-of-band datagram 645 ================ 646 */ 647 void QDECL NET_OutOfBandPrint( netsrc_t sock, netadr_t adr, const char *format, ... ) { 648 va_list argptr; 649 char string[MAX_MSGLEN]; 650 651 652 // set the header 653 string[0] = -1; 654 string[1] = -1; 655 string[2] = -1; 656 string[3] = -1; 657 658 va_start( argptr, format ); 659 vsprintf( string+4, format, argptr ); 660 va_end( argptr ); 661 662 // send the datagram 663 NET_SendPacket( sock, strlen( string ), string, adr ); 664 } 665 666 /* 667 =============== 668 NET_OutOfBandPrint 669 670 Sends a data message in an out-of-band datagram (only used for "connect") 671 ================ 672 */ 673 void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len ) { 674 byte string[MAX_MSGLEN*2]; 675 int i; 676 msg_t mbuf; 677 678 // set the header 679 string[0] = 0xff; 680 string[1] = 0xff; 681 string[2] = 0xff; 682 string[3] = 0xff; 683 684 for(i=0;i<len;i++) { 685 string[i+4] = format[i]; 686 } 687 688 mbuf.data = string; 689 mbuf.cursize = len+4; 690 Huff_Compress( &mbuf, 12); 691 // send the datagram 692 NET_SendPacket( sock, mbuf.cursize, mbuf.data, adr ); 693 } 694 695 /* 696 ============= 697 NET_StringToAdr 698 699 Traps "localhost" for loopback, passes everything else to system 700 ============= 701 */ 702 qboolean NET_StringToAdr( const char *s, netadr_t *a ) { 703 qboolean r; 704 char base[MAX_STRING_CHARS]; 705 char *port; 706 707 if (!strcmp (s, "localhost")) { 708 Com_Memset (a, 0, sizeof(*a)); 709 a->type = NA_LOOPBACK; 710 return qtrue; 711 } 712 713 // look for a port number 714 Q_strncpyz( base, s, sizeof( base ) ); 715 port = strstr( base, ":" ); 716 if ( port ) { 717 *port = 0; 718 port++; 719 } 720 721 r = Sys_StringToAdr( base, a ); 722 723 if ( !r ) { 724 a->type = NA_BAD; 725 return qfalse; 726 } 727 728 // inet_addr returns this if out of range 729 if ( a->ip[0] == 255 && a->ip[1] == 255 && a->ip[2] == 255 && a->ip[3] == 255 ) { 730 a->type = NA_BAD; 731 return qfalse; 732 } 733 734 if ( port ) { 735 a->port = BigShort( (short)atoi( port ) ); 736 } else { 737 a->port = BigShort( PORT_SERVER ); 738 } 739 740 return qtrue; 741 } 742