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