1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "sys/platform.h"
30 #include "framework/Common.h"
31
32 #include "sys/win32/win_local.h"
33
34 #include <iptypes.h>
35 #include <iphlpapi.h>
36
37 static WSADATA winsockdata;
38 static bool winsockInitialized = false;
39
40 idCVar net_ip( "net_ip", "localhost", CVAR_SYSTEM, "local IP address" );
41 idCVar net_port( "net_port", "0", CVAR_SYSTEM | CVAR_INTEGER, "local IP port number" );
42 idCVar net_forceLatency( "net_forceLatency", "0", CVAR_SYSTEM | CVAR_INTEGER, "milliseconds latency" );
43 idCVar net_forceDrop( "net_forceDrop", "0", CVAR_SYSTEM | CVAR_INTEGER, "percentage packet loss" );
44
45 static SOCKET ip_socket;
46
47 typedef struct {
48 unsigned long ip;
49 unsigned long mask;
50 } net_interface;
51
52 #define MAX_INTERFACES 32
53 int num_interfaces = 0;
54 net_interface netint[MAX_INTERFACES];
55
56 //=============================================================================
57
58
59 /*
60 ====================
61 NET_ErrorString
62 ====================
63 */
NET_ErrorString(void)64 const char *NET_ErrorString( void ) {
65 int code;
66
67 code = WSAGetLastError();
68 switch( code ) {
69 case WSAEINTR: return "WSAEINTR";
70 case WSAEBADF: return "WSAEBADF";
71 case WSAEACCES: return "WSAEACCES";
72 case WSAEDISCON: return "WSAEDISCON";
73 case WSAEFAULT: return "WSAEFAULT";
74 case WSAEINVAL: return "WSAEINVAL";
75 case WSAEMFILE: return "WSAEMFILE";
76 case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
77 case WSAEINPROGRESS: return "WSAEINPROGRESS";
78 case WSAEALREADY: return "WSAEALREADY";
79 case WSAENOTSOCK: return "WSAENOTSOCK";
80 case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
81 case WSAEMSGSIZE: return "WSAEMSGSIZE";
82 case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
83 case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
84 case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
85 case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
86 case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
87 case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
88 case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
89 case WSAEADDRINUSE: return "WSAEADDRINUSE";
90 case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
91 case WSAENETDOWN: return "WSAENETDOWN";
92 case WSAENETUNREACH: return "WSAENETUNREACH";
93 case WSAENETRESET: return "WSAENETRESET";
94 case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
95 case WSAECONNRESET: return "WSAECONNRESET";
96 case WSAENOBUFS: return "WSAENOBUFS";
97 case WSAEISCONN: return "WSAEISCONN";
98 case WSAENOTCONN: return "WSAENOTCONN";
99 case WSAESHUTDOWN: return "WSAESHUTDOWN";
100 case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
101 case WSAETIMEDOUT: return "WSAETIMEDOUT";
102 case WSAECONNREFUSED: return "WSAECONNREFUSED";
103 case WSAELOOP: return "WSAELOOP";
104 case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
105 case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
106 case WSASYSNOTREADY: return "WSASYSNOTREADY";
107 case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
108 case WSANOTINITIALISED: return "WSANOTINITIALISED";
109 case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
110 case WSATRY_AGAIN: return "WSATRY_AGAIN";
111 case WSANO_RECOVERY: return "WSANO_RECOVERY";
112 case WSANO_DATA: return "WSANO_DATA";
113 default: return "NO ERROR";
114 }
115 }
116
117 /*
118 ====================
119 Net_NetadrToSockadr
120 ====================
121 */
Net_NetadrToSockadr(const netadr_t * a,struct sockaddr * s)122 void Net_NetadrToSockadr( const netadr_t *a, struct sockaddr *s ) {
123 memset( s, 0, sizeof(*s) );
124
125 if( a->type == NA_BROADCAST ) {
126 ((struct sockaddr_in *)s)->sin_family = AF_INET;
127 ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
128 }
129 else if( a->type == NA_IP || a->type == NA_LOOPBACK ) {
130 ((struct sockaddr_in *)s)->sin_family = AF_INET;
131 ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
132 }
133
134 ((struct sockaddr_in *)s)->sin_port = htons( (short)a->port );
135 }
136
137
138 /*
139 ====================
140 Net_SockadrToNetadr
141 ====================
142 */
Net_SockadrToNetadr(struct sockaddr * s,netadr_t * a)143 void Net_SockadrToNetadr( struct sockaddr *s, netadr_t *a ) {
144 unsigned int ip;
145 if (s->sa_family == AF_INET) {
146 ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
147 *(unsigned int *)&a->ip = ip;
148 a->port = htons( ((struct sockaddr_in *)s)->sin_port );
149 // we store in network order, that loopback test is host order..
150 ip = ntohl( ip );
151 if ( ip == INADDR_LOOPBACK ) {
152 a->type = NA_LOOPBACK;
153 } else {
154 a->type = NA_IP;
155 }
156 }
157 }
158
159 /*
160 =============
161 Net_ExtractPort
162 =============
163 */
Net_ExtractPort(const char * src,char * buf,int bufsize,int * port)164 static bool Net_ExtractPort( const char *src, char *buf, int bufsize, int *port ) {
165 char *p;
166 strncpy( buf, src, bufsize );
167 p = buf; p += Min( bufsize - 1, (int)strlen( src ) ); *p = '\0';
168 p = strchr( buf, ':' );
169 if ( !p ) {
170 return false;
171 }
172 *p = '\0';
173 *port = strtol( p+1, NULL, 10 );
174 if ( errno == ERANGE ) {
175 return false;
176 }
177 return true;
178 }
179
180 /*
181 =============
182 Net_StringToSockaddr
183 =============
184 */
Net_StringToSockaddr(const char * s,struct sockaddr * sadr,bool doDNSResolve)185 static bool Net_StringToSockaddr( const char *s, struct sockaddr *sadr, bool doDNSResolve ) {
186 struct hostent *h;
187 char buf[256];
188 int port;
189
190 memset( sadr, 0, sizeof( *sadr ) );
191
192 ((struct sockaddr_in *)sadr)->sin_family = AF_INET;
193 ((struct sockaddr_in *)sadr)->sin_port = 0;
194
195 if( s[0] >= '0' && s[0] <= '9' ) {
196 unsigned long ret = inet_addr(s);
197 if ( ret != INADDR_NONE ) {
198 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = ret;
199 } else {
200 // check for port
201 if ( !Net_ExtractPort( s, buf, sizeof( buf ), &port ) ) {
202 return false;
203 }
204 ret = inet_addr( buf );
205 if ( ret == INADDR_NONE ) {
206 return false;
207 }
208 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = ret;
209 ((struct sockaddr_in *)sadr)->sin_port = htons( port );
210 }
211 } else if ( doDNSResolve ) {
212 // try to remove the port first, otherwise the DNS gets confused into multiple timeouts
213 // failed or not failed, buf is expected to contain the appropriate host to resolve
214 if ( Net_ExtractPort( s, buf, sizeof( buf ), &port ) ) {
215 ((struct sockaddr_in *)sadr)->sin_port = htons( port );
216 }
217 h = gethostbyname( buf );
218 if ( h == 0 ) {
219 return false;
220 }
221 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
222 }
223
224 return true;
225 }
226
227 /*
228 ====================
229 NET_IPSocket
230 ====================
231 */
NET_IPSocket(const char * net_interface,int port,netadr_t * bound_to)232 int NET_IPSocket( const char *net_interface, int port, netadr_t *bound_to ) {
233 SOCKET newsocket;
234 struct sockaddr_in address;
235 unsigned long _true = 1;
236 int i = 1;
237 int err;
238
239 if( net_interface ) {
240 common->DPrintf( "Opening IP socket: %s:%i\n", net_interface, port );
241 } else {
242 common->DPrintf( "Opening IP socket: localhost:%i\n", port );
243 }
244
245 if( ( newsocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
246 err = WSAGetLastError();
247 if( err != WSAEAFNOSUPPORT ) {
248 common->Printf( "WARNING: UDP_OpenSocket: socket: %s\n", NET_ErrorString() );
249 }
250 return 0;
251 }
252
253 // make it non-blocking
254 if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
255 common->Printf( "WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString() );
256 return 0;
257 }
258
259 // make it broadcast capable
260 if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == SOCKET_ERROR ) {
261 common->Printf( "WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() );
262 return 0;
263 }
264
265 if( !net_interface || !net_interface[0] || !idStr::Icmp( net_interface, "localhost" ) ) {
266 address.sin_addr.s_addr = INADDR_ANY;
267 }
268 else {
269 Net_StringToSockaddr( net_interface, (struct sockaddr *)&address, true );
270 }
271
272 if( port == PORT_ANY ) {
273 address.sin_port = 0;
274 }
275 else {
276 address.sin_port = htons( (short)port );
277 }
278
279 address.sin_family = AF_INET;
280
281 if( bind( newsocket, (const struct sockaddr *)&address, sizeof(address) ) == SOCKET_ERROR ) {
282 common->Printf( "WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString() );
283 closesocket( newsocket );
284 return 0;
285 }
286
287 // if the port was PORT_ANY, we need to query again to know the real port we got bound to
288 // ( this used to be in idPort::InitForPort )
289 if ( bound_to ) {
290 int len = sizeof( address );
291 getsockname( newsocket, (sockaddr *)&address, &len );
292 Net_SockadrToNetadr( (sockaddr *)&address, bound_to );
293 }
294
295 return newsocket;
296 }
297
298 /*
299 ==================
300 Net_WaitForUDPPacket
301 ==================
302 */
Net_WaitForUDPPacket(int netSocket,int timeout)303 bool Net_WaitForUDPPacket( int netSocket, int timeout ) {
304 int ret;
305 fd_set set;
306 struct timeval tv;
307
308 if ( !netSocket ) {
309 return false;
310 }
311
312 if ( timeout <= 0 ) {
313 return true;
314 }
315
316 FD_ZERO( &set );
317 FD_SET( netSocket, &set );
318
319 tv.tv_sec = 0;
320 tv.tv_usec = timeout * 1000;
321
322 ret = select( netSocket + 1, &set, NULL, NULL, &tv );
323
324 if ( ret == -1 ) {
325 common->DPrintf( "Net_WaitForUPDPacket select(): %s\n", strerror( errno ) );
326 return false;
327 }
328
329 // timeout with no data
330 if ( ret == 0 ) {
331 return false;
332 }
333
334 return true;
335 }
336
337 /*
338 ==================
339 Net_GetUDPPacket
340 ==================
341 */
Net_GetUDPPacket(int netSocket,netadr_t & net_from,char * data,int & size,int maxSize)342 bool Net_GetUDPPacket( int netSocket, netadr_t &net_from, char *data, int &size, int maxSize ) {
343 int ret;
344 struct sockaddr from;
345 int fromlen;
346 int err;
347
348 if( !netSocket ) {
349 return false;
350 }
351
352 fromlen = sizeof(from);
353 ret = recvfrom( netSocket, data, maxSize, 0, (struct sockaddr *)&from, &fromlen );
354 if ( ret == SOCKET_ERROR ) {
355 err = WSAGetLastError();
356
357 if( err == WSAEWOULDBLOCK || err == WSAECONNRESET ) {
358 return false;
359 }
360 char buf[1024];
361 sprintf( buf, "Net_GetUDPPacket: %s\n", NET_ErrorString() );
362 OutputDebugString( buf );
363 return false;
364 }
365
366 if ( netSocket == ip_socket ) {
367 memset( ((struct sockaddr_in *)&from)->sin_zero, 0, 8 );
368 }
369
370 Net_SockadrToNetadr( &from, &net_from );
371
372 if( ret == maxSize ) {
373 char buf[1024];
374 sprintf( buf, "Net_GetUDPPacket: oversize packet from %s\n", Sys_NetAdrToString( net_from ) );
375 OutputDebugString( buf );
376 return false;
377 }
378
379 size = ret;
380
381 return true;
382 }
383
384 /*
385 ==================
386 Net_SendUDPPacket
387 ==================
388 */
Net_SendUDPPacket(int netSocket,int length,const void * data,const netadr_t to)389 void Net_SendUDPPacket( int netSocket, int length, const void *data, const netadr_t to ) {
390 int ret;
391 struct sockaddr addr;
392
393 if( !netSocket ) {
394 return;
395 }
396
397 Net_NetadrToSockadr( &to, &addr );
398 ret = sendto( netSocket, (const char *)data, length, 0, &addr, sizeof(addr) );
399 if( ret == SOCKET_ERROR ) {
400 int err = WSAGetLastError();
401
402 // wouldblock is silent
403 if( err == WSAEWOULDBLOCK ) {
404 return;
405 }
406
407 // some PPP links do not allow broadcasts and return an error
408 if( ( err == WSAEADDRNOTAVAIL ) && ( to.type == NA_BROADCAST ) ) {
409 return;
410 }
411
412 char buf[1024];
413 sprintf( buf, "Net_SendUDPPacket: %s\n", NET_ErrorString() );
414 OutputDebugString( buf );
415 }
416 }
417
418 /*
419 ====================
420 Sys_InitNetworking
421 ====================
422 */
Sys_InitNetworking(void)423 void Sys_InitNetworking( void ) {
424 int r;
425
426 r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );
427 if( r ) {
428 common->Printf( "WARNING: Winsock initialization failed, returned %d\n", r );
429 return;
430 }
431
432 winsockInitialized = true;
433 common->Printf( "Winsock Initialized\n" );
434
435 PIP_ADAPTER_INFO pAdapterInfo;
436 PIP_ADAPTER_INFO pAdapter = NULL;
437 DWORD dwRetVal = 0;
438 PIP_ADDR_STRING pIPAddrString;
439 ULONG ulOutBufLen;
440 bool foundloopback;
441
442 num_interfaces = 0;
443 foundloopback = false;
444
445 pAdapterInfo = (IP_ADAPTER_INFO *)malloc( sizeof( IP_ADAPTER_INFO ) );
446 if( !pAdapterInfo ) {
447 common->FatalError( "Sys_InitNetworking: Couldn't malloc( %u )", (unsigned int)sizeof( IP_ADAPTER_INFO ) );
448 }
449 ulOutBufLen = sizeof( IP_ADAPTER_INFO );
450
451 // Make an initial call to GetAdaptersInfo to get
452 // the necessary size into the ulOutBufLen variable
453 if( GetAdaptersInfo( pAdapterInfo, &ulOutBufLen ) == ERROR_BUFFER_OVERFLOW ) {
454 free( pAdapterInfo );
455 pAdapterInfo = (IP_ADAPTER_INFO *)malloc( ulOutBufLen );
456 if( !pAdapterInfo ) {
457 common->FatalError( "Sys_InitNetworking: Couldn't malloc( %ld )", ulOutBufLen );
458 }
459 }
460
461 if( ( dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) ) != NO_ERROR ) {
462 // happens if you have no network connection
463 common->Printf( "Sys_InitNetworking: GetAdaptersInfo failed (%ld).\n", dwRetVal );
464 } else {
465 pAdapter = pAdapterInfo;
466 while( pAdapter ) {
467 common->Printf( "Found interface: %s %s - ", pAdapter->AdapterName, pAdapter->Description );
468 pIPAddrString = &pAdapter->IpAddressList;
469 while( pIPAddrString ) {
470 unsigned long ip_a, ip_m;
471 if( !idStr::Icmp( "127.0.0.1", pIPAddrString->IpAddress.String ) ) {
472 foundloopback = true;
473 }
474 ip_a = ntohl( inet_addr( pIPAddrString->IpAddress.String ) );
475 ip_m = ntohl( inet_addr( pIPAddrString->IpMask.String ) );
476 //skip null netmasks
477 if( !ip_m ) {
478 common->Printf( "%s NULL netmask - skipped\n", pIPAddrString->IpAddress.String );
479 pIPAddrString = pIPAddrString->Next;
480 continue;
481 }
482 common->Printf( "%s/%s\n", pIPAddrString->IpAddress.String, pIPAddrString->IpMask.String );
483 netint[num_interfaces].ip = ip_a;
484 netint[num_interfaces].mask = ip_m;
485 num_interfaces++;
486 if( num_interfaces >= MAX_INTERFACES ) {
487 common->Printf( "Sys_InitNetworking: MAX_INTERFACES(%d) hit.\n", MAX_INTERFACES );
488 free( pAdapterInfo );
489 return;
490 }
491 pIPAddrString = pIPAddrString->Next;
492 }
493 pAdapter = pAdapter->Next;
494 }
495 }
496 // for some retarded reason, win32 doesn't count loopback as an adapter...
497 if( !foundloopback && num_interfaces < MAX_INTERFACES ) {
498 common->Printf( "Sys_InitNetworking: adding loopback interface\n" );
499 netint[num_interfaces].ip = ntohl( inet_addr( "127.0.0.1" ) );
500 netint[num_interfaces].mask = ntohl( inet_addr( "255.0.0.0" ) );
501 num_interfaces++;
502 }
503 free( pAdapterInfo );
504 }
505
506
507 /*
508 ====================
509 Sys_ShutdownNetworking
510 ====================
511 */
Sys_ShutdownNetworking(void)512 void Sys_ShutdownNetworking( void ) {
513 if ( !winsockInitialized ) {
514 return;
515 }
516 WSACleanup();
517 winsockInitialized = false;
518 }
519
520 /*
521 =============
522 Sys_StringToNetAdr
523 =============
524 */
Sys_StringToNetAdr(const char * s,netadr_t * a,bool doDNSResolve)525 bool Sys_StringToNetAdr( const char *s, netadr_t *a, bool doDNSResolve ) {
526 struct sockaddr sadr;
527
528 if ( !Net_StringToSockaddr( s, &sadr, doDNSResolve ) ) {
529 return false;
530 }
531
532 Net_SockadrToNetadr( &sadr, a );
533 return true;
534 }
535
536 /*
537 =============
538 Sys_NetAdrToString
539 =============
540 */
Sys_NetAdrToString(const netadr_t a)541 const char *Sys_NetAdrToString( const netadr_t a ) {
542 static int index = 0;
543 static char buf[ 4 ][ 64 ]; // flip/flop
544 char *s;
545
546 s = buf[index];
547 index = (index + 1) & 3;
548
549 if ( a.type == NA_LOOPBACK ) {
550 if ( a.port ) {
551 idStr::snPrintf( s, 64, "localhost:%i", a.port );
552 } else {
553 idStr::snPrintf( s, 64, "localhost" );
554 }
555 } else if ( a.type == NA_IP ) {
556 idStr::snPrintf( s, 64, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], a.port );
557 }
558 return s;
559 }
560
561 /*
562 ==================
563 Sys_IsLANAddress
564 ==================
565 */
Sys_IsLANAddress(const netadr_t adr)566 bool Sys_IsLANAddress( const netadr_t adr ) {
567 #if ID_NOLANADDRESS
568 common->Printf( "Sys_IsLANAddress: ID_NOLANADDRESS\n" );
569 return false;
570 #endif
571 if( adr.type == NA_LOOPBACK ) {
572 return true;
573 }
574
575 if( adr.type != NA_IP ) {
576 return false;
577 }
578
579 if( num_interfaces ) {
580 int i;
581 unsigned long *p_ip;
582 unsigned long ip;
583 p_ip = (unsigned long *)&adr.ip[0];
584 ip = ntohl( *p_ip );
585
586 for( i=0; i < num_interfaces; i++ ) {
587 if( ( netint[i].ip & netint[i].mask ) == ( ip & netint[i].mask ) ) {
588 return true;
589 }
590 }
591 }
592 return false;
593 }
594
595 /*
596 ===================
597 Sys_CompareNetAdrBase
598
599 Compares without the port
600 ===================
601 */
Sys_CompareNetAdrBase(const netadr_t a,const netadr_t b)602 bool Sys_CompareNetAdrBase( const netadr_t a, const netadr_t b ) {
603 if ( a.type != b.type ) {
604 return false;
605 }
606
607 if ( a.type == NA_LOOPBACK ) {
608 return true;
609 }
610
611 if ( a.type == NA_IP ) {
612 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] ) {
613 return true;
614 }
615 return false;
616 }
617
618 common->Printf( "Sys_CompareNetAdrBase: bad address type\n" );
619 return false;
620 }
621
622 //=============================================================================
623
624
625 #define MAX_UDP_MSG_SIZE 1400
626
627 typedef struct udpMsg_s {
628 byte data[MAX_UDP_MSG_SIZE];
629 netadr_t address;
630 int size;
631 unsigned int time;
632 struct udpMsg_s * next;
633 } udpMsg_t;
634
635 class idUDPLag {
636 public:
637 idUDPLag( void );
638 ~idUDPLag( void );
639
640 udpMsg_t * sendFirst;
641 udpMsg_t * sendLast;
642 udpMsg_t * recieveFirst;
643 udpMsg_t * recieveLast;
644 idBlockAlloc<udpMsg_t, 64> udpMsgAllocator;
645 };
646
idUDPLag(void)647 idUDPLag::idUDPLag( void ) {
648 sendFirst = sendLast = recieveFirst = recieveLast = NULL;
649 }
650
~idUDPLag(void)651 idUDPLag::~idUDPLag( void ) {
652 udpMsgAllocator.Shutdown();
653 }
654
655 idUDPLag *udpPorts[65536];
656
657 /*
658 ==================
659 idPort::idPort
660 ==================
661 */
idPort()662 idPort::idPort() {
663 netSocket = 0;
664 memset( &bound_to, 0, sizeof( bound_to ) );
665 }
666
667 /*
668 ==================
669 idPort::~idPort
670 ==================
671 */
~idPort()672 idPort::~idPort() {
673 Close();
674 }
675
676 /*
677 ==================
678 InitForPort
679 ==================
680 */
InitForPort(int portNumber)681 bool idPort::InitForPort( int portNumber ) {
682 netSocket = NET_IPSocket( net_ip.GetString(), portNumber, &bound_to );
683 if ( netSocket <= 0 ) {
684 netSocket = 0;
685 memset( &bound_to, 0, sizeof( bound_to ) );
686 return false;
687 }
688
689 udpPorts[ bound_to.port ] = new idUDPLag;
690
691 return true;
692 }
693
694 /*
695 ==================
696 idPort::Close
697 ==================
698 */
Close()699 void idPort::Close() {
700 if ( netSocket ) {
701 if ( udpPorts[ bound_to.port ] ) {
702 delete udpPorts[ bound_to.port ];
703 udpPorts[ bound_to.port ] = NULL;
704 }
705 closesocket( netSocket );
706 netSocket = 0;
707 memset( &bound_to, 0, sizeof( bound_to ) );
708 }
709 }
710
711 /*
712 ==================
713 idPort::GetPacket
714 ==================
715 */
GetPacket(netadr_t & from,void * data,int & size,int maxSize)716 bool idPort::GetPacket( netadr_t &from, void *data, int &size, int maxSize ) {
717 udpMsg_t *msg;
718 bool ret;
719
720 while( 1 ) {
721
722 ret = Net_GetUDPPacket( netSocket, from, (char *)data, size, maxSize );
723 if ( !ret ) {
724 break;
725 }
726
727 if ( net_forceDrop.GetInteger() > 0 ) {
728 if ( rand() < net_forceDrop.GetInteger() * RAND_MAX / 100 ) {
729 continue;
730 }
731 }
732
733 packetsRead++;
734 bytesRead += size;
735
736 if ( net_forceLatency.GetInteger() > 0 ) {
737
738 assert( size <= MAX_UDP_MSG_SIZE );
739 msg = udpPorts[ bound_to.port ]->udpMsgAllocator.Alloc();
740 memcpy( msg->data, data, size );
741 msg->size = size;
742 msg->address = from;
743 msg->time = Sys_Milliseconds();
744 msg->next = NULL;
745 if ( udpPorts[ bound_to.port ]->recieveLast ) {
746 udpPorts[ bound_to.port ]->recieveLast->next = msg;
747 } else {
748 udpPorts[ bound_to.port ]->recieveFirst = msg;
749 }
750 udpPorts[ bound_to.port ]->recieveLast = msg;
751 } else {
752 break;
753 }
754 }
755
756 if ( net_forceLatency.GetInteger() > 0 || ( udpPorts[ bound_to.port] && udpPorts[ bound_to.port ]->recieveFirst ) ) {
757
758 msg = udpPorts[ bound_to.port ]->recieveFirst;
759 if ( msg && msg->time <= Sys_Milliseconds() - net_forceLatency.GetInteger() ) {
760 memcpy( data, msg->data, msg->size );
761 size = msg->size;
762 from = msg->address;
763 udpPorts[ bound_to.port ]->recieveFirst = udpPorts[ bound_to.port ]->recieveFirst->next;
764 if ( !udpPorts[ bound_to.port ]->recieveFirst ) {
765 udpPorts[ bound_to.port ]->recieveLast = NULL;
766 }
767 udpPorts[ bound_to.port ]->udpMsgAllocator.Free( msg );
768 return true;
769 }
770 return false;
771
772 } else {
773 return ret;
774 }
775 }
776
777 /*
778 ==================
779 idPort::GetPacketBlocking
780 ==================
781 */
GetPacketBlocking(netadr_t & from,void * data,int & size,int maxSize,int timeout)782 bool idPort::GetPacketBlocking( netadr_t &from, void *data, int &size, int maxSize, int timeout ) {
783
784 Net_WaitForUDPPacket( netSocket, timeout );
785
786 if ( GetPacket( from, data, size, maxSize ) ) {
787 return true;
788 }
789
790 return false;
791 }
792
793 /*
794 ==================
795 idPort::SendPacket
796 ==================
797 */
SendPacket(const netadr_t to,const void * data,int size)798 void idPort::SendPacket( const netadr_t to, const void *data, int size ) {
799 udpMsg_t *msg;
800
801 if ( to.type == NA_BAD ) {
802 common->Warning( "idPort::SendPacket: bad address type NA_BAD - ignored" );
803 return;
804 }
805
806 packetsWritten++;
807 bytesWritten += size;
808
809 if ( net_forceDrop.GetInteger() > 0 ) {
810 if ( rand() < net_forceDrop.GetInteger() * RAND_MAX / 100 ) {
811 return;
812 }
813 }
814
815 if ( net_forceLatency.GetInteger() > 0 || ( udpPorts[ bound_to.port ] && udpPorts[ bound_to.port ]->sendFirst ) ) {
816
817 assert( size <= MAX_UDP_MSG_SIZE );
818 msg = udpPorts[ bound_to.port ]->udpMsgAllocator.Alloc();
819 memcpy( msg->data, data, size );
820 msg->size = size;
821 msg->address = to;
822 msg->time = Sys_Milliseconds();
823 msg->next = NULL;
824 if ( udpPorts[ bound_to.port ]->sendLast ) {
825 udpPorts[ bound_to.port ]->sendLast->next = msg;
826 } else {
827 udpPorts[ bound_to.port ]->sendFirst = msg;
828 }
829 udpPorts[ bound_to.port ]->sendLast = msg;
830
831 for ( msg = udpPorts[ bound_to.port ]->sendFirst; msg && msg->time <= Sys_Milliseconds() - net_forceLatency.GetInteger(); msg = udpPorts[ bound_to.port ]->sendFirst ) {
832 Net_SendUDPPacket( netSocket, msg->size, msg->data, msg->address );
833 udpPorts[ bound_to.port ]->sendFirst = udpPorts[ bound_to.port ]->sendFirst->next;
834 if ( !udpPorts[ bound_to.port ]->sendFirst ) {
835 udpPorts[ bound_to.port ]->sendLast = NULL;
836 }
837 udpPorts[ bound_to.port ]->udpMsgAllocator.Free( msg );
838 }
839
840 } else {
841 Net_SendUDPPacket( netSocket, size, data, to );
842 }
843 }
844
845
846 //=============================================================================
847
848 /*
849 ==================
850 idTCP::idTCP
851 ==================
852 */
idTCP()853 idTCP::idTCP() {
854 fd = 0;
855 memset( &address, 0, sizeof( address ) );
856 }
857
858 /*
859 ==================
860 idTCP::~idTCP
861 ==================
862 */
~idTCP()863 idTCP::~idTCP() {
864 Close();
865 }
866
867 /*
868 ==================
869 idTCP::Init
870 ==================
871 */
Init(const char * host,short port)872 bool idTCP::Init( const char *host, short port ) {
873 unsigned long _true = 1;
874 struct sockaddr sadr;
875
876 if ( !Sys_StringToNetAdr( host, &address, true ) ) {
877 common->Printf( "Couldn't resolve server name \"%s\"\n", host );
878 return false;
879 }
880 address.type = NA_IP;
881 if ( !address.port ) {
882 address.port = port;
883 }
884 common->Printf( "\"%s\" resolved to %i.%i.%i.%i:%i\n", host,
885 address.ip[0], address.ip[1], address.ip[2], address.ip[3], address.port );
886 Net_NetadrToSockadr( &address, &sadr );
887
888 if ( fd ) {
889 common->Warning( "idTCP::Init: already initialized?" );
890 }
891
892 if ( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == INVALID_SOCKET ) {
893 fd = 0;
894 common->Printf( "ERROR: idTCP::Init: socket: %s\n", NET_ErrorString() );
895 return false;
896 }
897
898 if ( connect( fd, &sadr, sizeof(sadr)) == SOCKET_ERROR ) {
899 common->Printf( "ERROR: idTCP::Init: connect: %s\n", NET_ErrorString() );
900 closesocket( fd );
901 fd = 0;
902 return false;
903 }
904
905 // make it non-blocking
906 if( ioctlsocket( fd, FIONBIO, &_true ) == SOCKET_ERROR ) {
907 common->Printf( "ERROR: idTCP::Init: ioctl FIONBIO: %s\n", NET_ErrorString() );
908 closesocket( fd );
909 fd = 0;
910 return false;
911 }
912
913 common->DPrintf( "Opened TCP connection\n" );
914 return true;
915 }
916
917 /*
918 ==================
919 idTCP::Close
920 ==================
921 */
Close()922 void idTCP::Close() {
923 if ( fd ) {
924 closesocket( fd );
925 }
926 fd = 0;
927 }
928
929 /*
930 ==================
931 idTCP::Read
932 ==================
933 */
Read(void * data,int size)934 int idTCP::Read( void *data, int size ) {
935 int nbytes;
936
937 if ( !fd ) {
938 common->Printf("idTCP::Read: not initialized\n");
939 return -1;
940 }
941
942 if ( ( nbytes = recv( fd, (char *)data, size, 0 ) ) == SOCKET_ERROR ) {
943 if ( WSAGetLastError() == WSAEWOULDBLOCK ) {
944 return 0;
945 }
946 common->Printf( "ERROR: idTCP::Read: %s\n", NET_ErrorString() );
947 Close();
948 return -1;
949 }
950
951 // a successful read of 0 bytes indicates remote has closed the connection
952 if ( nbytes == 0 ) {
953 common->DPrintf( "idTCP::Read: read 0 bytes - assume connection closed\n" );
954 return -1;
955 }
956
957 return nbytes;
958 }
959
960 /*
961 ==================
962 idTCP::Write
963 ==================
964 */
Write(void * data,int size)965 int idTCP::Write( void *data, int size ) {
966 int nbytes;
967
968 if ( !fd ) {
969 common->Printf("idTCP::Write: not initialized\n");
970 return -1;
971 }
972
973 if ( ( nbytes = send( fd, (char *)data, size, 0 ) ) == SOCKET_ERROR ) {
974 common->Printf( "ERROR: idTCP::Write: %s\n", NET_ErrorString() );
975 Close();
976 return -1;
977 }
978
979 return nbytes;
980 }
981