2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
28 #include "../../idlib/precompiled.h"
34 #include "win_local.h"
36 static WSADATA winsockdata;
37 static bool winsockInitialized = false;
38 static bool usingSocks = false;
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" );
45 idCVar net_socksEnabled( "net_socksEnabled", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "" );
46 idCVar net_socksServer( "net_socksServer", "", CVAR_SYSTEM | CVAR_ARCHIVE, "" );
47 idCVar net_socksPort( "net_socksPort", "1080", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "" );
48 idCVar net_socksUsername( "net_socksUsername", "", CVAR_SYSTEM | CVAR_ARCHIVE, "" );
49 idCVar net_socksPassword( "net_socksPassword", "", CVAR_SYSTEM | CVAR_ARCHIVE, "" );
52 static struct sockaddr socksRelayAddr;
54 static SOCKET ip_socket;
55 static SOCKET socks_socket;
56 static char socksBuf[4096];
63 #define MAX_INTERFACES 32
64 int num_interfaces = 0;
65 net_interface netint[MAX_INTERFACES];
67 //=============================================================================
75 char *NET_ErrorString( void ) {
78 code = WSAGetLastError();
80 case WSAEINTR: return "WSAEINTR";
81 case WSAEBADF: return "WSAEBADF";
82 case WSAEACCES: return "WSAEACCES";
83 case WSAEDISCON: return "WSAEDISCON";
84 case WSAEFAULT: return "WSAEFAULT";
85 case WSAEINVAL: return "WSAEINVAL";
86 case WSAEMFILE: return "WSAEMFILE";
87 case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
88 case WSAEINPROGRESS: return "WSAEINPROGRESS";
89 case WSAEALREADY: return "WSAEALREADY";
90 case WSAENOTSOCK: return "WSAENOTSOCK";
91 case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
92 case WSAEMSGSIZE: return "WSAEMSGSIZE";
93 case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
94 case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
95 case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
96 case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
97 case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
98 case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
99 case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
100 case WSAEADDRINUSE: return "WSAEADDRINUSE";
101 case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
102 case WSAENETDOWN: return "WSAENETDOWN";
103 case WSAENETUNREACH: return "WSAENETUNREACH";
104 case WSAENETRESET: return "WSAENETRESET";
105 case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
106 case WSAECONNRESET: return "WSAECONNRESET";
107 case WSAENOBUFS: return "WSAENOBUFS";
108 case WSAEISCONN: return "WSAEISCONN";
109 case WSAENOTCONN: return "WSAENOTCONN";
110 case WSAESHUTDOWN: return "WSAESHUTDOWN";
111 case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
112 case WSAETIMEDOUT: return "WSAETIMEDOUT";
113 case WSAECONNREFUSED: return "WSAECONNREFUSED";
114 case WSAELOOP: return "WSAELOOP";
115 case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
116 case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
117 case WSASYSNOTREADY: return "WSASYSNOTREADY";
118 case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
119 case WSANOTINITIALISED: return "WSANOTINITIALISED";
120 case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
121 case WSATRY_AGAIN: return "WSATRY_AGAIN";
122 case WSANO_RECOVERY: return "WSANO_RECOVERY";
123 case WSANO_DATA: return "WSANO_DATA";
124 default: return "NO ERROR";
133 void Net_NetadrToSockadr( const netadr_t *a, struct sockaddr *s ) {
134 memset( s, 0, sizeof(*s) );
136 if( a->type == NA_BROADCAST ) {
137 ((struct sockaddr_in *)s)->sin_family = AF_INET;
138 ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
140 else if( a->type == NA_IP || a->type == NA_LOOPBACK ) {
141 ((struct sockaddr_in *)s)->sin_family = AF_INET;
142 ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
145 ((struct sockaddr_in *)s)->sin_port = htons( (short)a->port );
154 void Net_SockadrToNetadr( struct sockaddr *s, netadr_t *a ) {
156 if (s->sa_family == AF_INET) {
157 ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
158 *(unsigned int *)&a->ip = ip;
159 a->port = htons( ((struct sockaddr_in *)s)->sin_port );
160 // we store in network order, that loopback test is host order..
162 if ( ip == INADDR_LOOPBACK ) {
163 a->type = NA_LOOPBACK;
175 static bool Net_ExtractPort( const char *src, char *buf, int bufsize, int *port ) {
177 strncpy( buf, src, bufsize );
178 p = buf; p += Min( bufsize - 1, (int)strlen( src ) ); *p = '\0';
179 p = strchr( buf, ':' );
184 *port = strtol( p+1, NULL, 10 );
185 if ( errno == ERANGE ) {
196 static bool Net_StringToSockaddr( const char *s, struct sockaddr *sadr, bool doDNSResolve ) {
201 memset( sadr, 0, sizeof( *sadr ) );
203 ((struct sockaddr_in *)sadr)->sin_family = AF_INET;
204 ((struct sockaddr_in *)sadr)->sin_port = 0;
206 if( s[0] >= '0' && s[0] <= '9' ) {
207 unsigned long ret = inet_addr(s);
208 if ( ret != INADDR_NONE ) {
209 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = ret;
212 if ( !Net_ExtractPort( s, buf, sizeof( buf ), &port ) ) {
215 ret = inet_addr( buf );
216 if ( ret == INADDR_NONE ) {
219 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = ret;
220 ((struct sockaddr_in *)sadr)->sin_port = htons( port );
222 } else if ( doDNSResolve ) {
223 // try to remove the port first, otherwise the DNS gets confused into multiple timeouts
224 // failed or not failed, buf is expected to contain the appropriate host to resolve
225 if ( Net_ExtractPort( s, buf, sizeof( buf ), &port ) ) {
226 ((struct sockaddr_in *)sadr)->sin_port = htons( port );
228 h = gethostbyname( buf );
232 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
243 int NET_IPSocket( const char *net_interface, int port, netadr_t *bound_to ) {
245 struct sockaddr_in address;
246 unsigned long _true = 1;
250 if( net_interface ) {
251 common->DPrintf( "Opening IP socket: %s:%i\n", net_interface, port );
253 common->DPrintf( "Opening IP socket: localhost:%i\n", port );
256 if( ( newsocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
257 err = WSAGetLastError();
258 if( err != WSAEAFNOSUPPORT ) {
259 common->Printf( "WARNING: UDP_OpenSocket: socket: %s\n", NET_ErrorString() );
264 // make it non-blocking
265 if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
266 common->Printf( "WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString() );
270 // make it broadcast capable
271 if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == SOCKET_ERROR ) {
272 common->Printf( "WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() );
276 if( !net_interface || !net_interface[0] || !idStr::Icmp( net_interface, "localhost" ) ) {
277 address.sin_addr.s_addr = INADDR_ANY;
280 Net_StringToSockaddr( net_interface, (struct sockaddr *)&address, true );
283 if( port == PORT_ANY ) {
284 address.sin_port = 0;
287 address.sin_port = htons( (short)port );
290 address.sin_family = AF_INET;
292 if( bind( newsocket, (const struct sockaddr *)&address, sizeof(address) ) == SOCKET_ERROR ) {
293 common->Printf( "WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString() );
294 closesocket( newsocket );
298 // if the port was PORT_ANY, we need to query again to know the real port we got bound to
299 // ( this used to be in idPort::InitForPort )
301 int len = sizeof( address );
302 getsockname( newsocket, (sockaddr *)&address, &len );
303 Net_SockadrToNetadr( (sockaddr *)&address, bound_to );
314 void NET_OpenSocks( int port ) {
315 struct sockaddr_in address;
320 unsigned char buf[64];
324 common->Printf( "Opening connection to SOCKS server.\n" );
326 if ( ( socks_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ) {
327 err = WSAGetLastError();
328 common->Printf( "WARNING: NET_OpenSocks: socket: %s\n", NET_ErrorString() );
332 h = gethostbyname( net_socksServer.GetString() );
334 err = WSAGetLastError();
335 common->Printf( "WARNING: NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString() );
338 if ( h->h_addrtype != AF_INET ) {
339 common->Printf( "WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\n" );
342 address.sin_family = AF_INET;
343 address.sin_addr.s_addr = *(int *)h->h_addr_list[0];
344 address.sin_port = htons( (short)net_socksPort.GetInteger() );
346 if ( connect( socks_socket, (struct sockaddr *)&address, sizeof( address ) ) == SOCKET_ERROR ) {
347 err = WSAGetLastError();
348 common->Printf( "NET_OpenSocks: connect: %s\n", NET_ErrorString() );
352 // send socks authentication handshake
353 if ( *net_socksUsername.GetString() || *net_socksPassword.GetString() ) {
360 buf[0] = 5; // SOCKS version
370 buf[2] = 0; // method #1 - method id #00: no authentication
372 buf[2] = 2; // method #2 - method id #02: username/password
374 if ( send( socks_socket, (const char *)buf, len, 0 ) == SOCKET_ERROR ) {
375 err = WSAGetLastError();
376 common->Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
381 len = recv( socks_socket, (char *)buf, 64, 0 );
382 if ( len == SOCKET_ERROR ) {
383 err = WSAGetLastError();
384 common->Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
387 if ( len != 2 || buf[0] != 5 ) {
388 common->Printf( "NET_OpenSocks: bad response\n" );
392 case 0: // no authentication
394 case 2: // username/password authentication
397 common->Printf( "NET_OpenSocks: request denied\n" );
401 // do username/password authentication if needed
407 ulen = strlen( net_socksUsername.GetString() );
408 plen = strlen( net_socksPassword.GetString() );
410 buf[0] = 1; // username/password authentication version
413 memcpy( &buf[2], net_socksUsername.GetString(), ulen );
415 buf[2 + ulen] = plen;
417 memcpy( &buf[3 + ulen], net_socksPassword.GetString(), plen );
421 if ( send( socks_socket, (const char *)buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) {
422 err = WSAGetLastError();
423 common->Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
428 len = recv( socks_socket, (char *)buf, 64, 0 );
429 if ( len == SOCKET_ERROR ) {
430 err = WSAGetLastError();
431 common->Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
434 if ( len != 2 || buf[0] != 1 ) {
435 common->Printf( "NET_OpenSocks: bad response\n" );
439 common->Printf( "NET_OpenSocks: authentication failed\n" );
444 // send the UDP associate request
445 buf[0] = 5; // SOCKS version
446 buf[1] = 3; // command: UDP associate
447 buf[2] = 0; // reserved
448 buf[3] = 1; // address type: IPV4
449 *(int *)&buf[4] = INADDR_ANY;
450 *(short *)&buf[8] = htons( (short)port ); // port
451 if ( send( socks_socket, (const char *)buf, 10, 0 ) == SOCKET_ERROR ) {
452 err = WSAGetLastError();
453 common->Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
458 len = recv( socks_socket, (char *)buf, 64, 0 );
459 if( len == SOCKET_ERROR ) {
460 err = WSAGetLastError();
461 common->Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
464 if( len < 2 || buf[0] != 5 ) {
465 common->Printf( "NET_OpenSocks: bad response\n" );
468 // check completion code
470 common->Printf( "NET_OpenSocks: request denied: %i\n", buf[1] );
474 common->Printf( "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] );
477 ((struct sockaddr_in *)&socksRelayAddr)->sin_family = AF_INET;
478 ((struct sockaddr_in *)&socksRelayAddr)->sin_addr.s_addr = *(int *)&buf[4];
479 ((struct sockaddr_in *)&socksRelayAddr)->sin_port = *(short *)&buf[8];
480 memset( ((struct sockaddr_in *)&socksRelayAddr)->sin_zero, 0, 8 );
490 bool Net_WaitForUDPPacket( int netSocket, int timeout ) {
499 if ( timeout <= 0 ) {
504 FD_SET( netSocket, &set );
507 tv.tv_usec = timeout * 1000;
509 ret = select( netSocket + 1, &set, NULL, NULL, &tv );
512 common->DPrintf( "Net_WaitForUPDPacket select(): %s\n", strerror( errno ) );
516 // timeout with no data
529 bool Net_GetUDPPacket( int netSocket, netadr_t &net_from, char *data, int &size, int maxSize ) {
531 struct sockaddr from;
539 fromlen = sizeof(from);
540 ret = recvfrom( netSocket, data, maxSize, 0, (struct sockaddr *)&from, &fromlen );
541 if ( ret == SOCKET_ERROR ) {
542 err = WSAGetLastError();
544 if( err == WSAEWOULDBLOCK || err == WSAECONNRESET ) {
548 sprintf( buf, "Net_GetUDPPacket: %s\n", NET_ErrorString() );
549 OutputDebugString( buf );
553 if ( netSocket == ip_socket ) {
554 memset( ((struct sockaddr_in *)&from)->sin_zero, 0, 8 );
557 if ( usingSocks && netSocket == ip_socket && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) {
558 if ( ret < 10 || data[0] != 0 || data[1] != 0 || data[2] != 0 || data[3] != 1 ) {
561 net_from.type = NA_IP;
562 net_from.ip[0] = data[4];
563 net_from.ip[1] = data[5];
564 net_from.ip[2] = data[6];
565 net_from.ip[3] = data[7];
566 net_from.port = *(short *)&data[8];
567 memmove( data, &data[10], ret - 10 );
569 Net_SockadrToNetadr( &from, &net_from );
572 if( ret == maxSize ) {
574 sprintf( buf, "Net_GetUDPPacket: oversize packet from %s\n", Sys_NetAdrToString( net_from ) );
575 OutputDebugString( buf );
589 void Net_SendUDPPacket( int netSocket, int length, const void *data, const netadr_t to ) {
591 struct sockaddr addr;
597 Net_NetadrToSockadr( &to, &addr );
599 if( usingSocks && to.type == NA_IP ) {
600 socksBuf[0] = 0; // reserved
602 socksBuf[2] = 0; // fragment (not fragmented)
603 socksBuf[3] = 1; // address type: IPV4
604 *(int *)&socksBuf[4] = ((struct sockaddr_in *)&addr)->sin_addr.s_addr;
605 *(short *)&socksBuf[8] = ((struct sockaddr_in *)&addr)->sin_port;
606 memcpy( &socksBuf[10], data, length );
607 ret = sendto( netSocket, socksBuf, length+10, 0, &socksRelayAddr, sizeof(socksRelayAddr) );
609 ret = sendto( netSocket, (const char *)data, length, 0, &addr, sizeof(addr) );
611 if( ret == SOCKET_ERROR ) {
612 int err = WSAGetLastError();
614 // wouldblock is silent
615 if( err == WSAEWOULDBLOCK ) {
619 // some PPP links do not allow broadcasts and return an error
620 if( ( err == WSAEADDRNOTAVAIL ) && ( to.type == NA_BROADCAST ) ) {
625 sprintf( buf, "Net_SendUDPPacket: %s\n", NET_ErrorString() );
626 OutputDebugString( buf );
635 void Sys_InitNetworking( void ) {
638 r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );
640 common->Printf( "WARNING: Winsock initialization failed, returned %d\n", r );
644 winsockInitialized = true;
645 common->Printf( "Winsock Initialized\n" );
647 PIP_ADAPTER_INFO pAdapterInfo;
648 PIP_ADAPTER_INFO pAdapter = NULL;
650 PIP_ADDR_STRING pIPAddrString;
655 foundloopback = false;
657 pAdapterInfo = (IP_ADAPTER_INFO *)malloc( sizeof( IP_ADAPTER_INFO ) );
658 if( !pAdapterInfo ) {
659 common->FatalError( "Sys_InitNetworking: Couldn't malloc( %d )", sizeof( IP_ADAPTER_INFO ) );
661 ulOutBufLen = sizeof( IP_ADAPTER_INFO );
663 // Make an initial call to GetAdaptersInfo to get
664 // the necessary size into the ulOutBufLen variable
665 if( GetAdaptersInfo( pAdapterInfo, &ulOutBufLen ) == ERROR_BUFFER_OVERFLOW ) {
666 free( pAdapterInfo );
667 pAdapterInfo = (IP_ADAPTER_INFO *)malloc( ulOutBufLen );
668 if( !pAdapterInfo ) {
669 common->FatalError( "Sys_InitNetworking: Couldn't malloc( %ld )", ulOutBufLen );
673 if( ( dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) ) != NO_ERROR ) {
674 // happens if you have no network connection
675 common->Printf( "Sys_InitNetworking: GetAdaptersInfo failed (%ld).\n", dwRetVal );
677 pAdapter = pAdapterInfo;
679 common->Printf( "Found interface: %s %s - ", pAdapter->AdapterName, pAdapter->Description );
680 pIPAddrString = &pAdapter->IpAddressList;
681 while( pIPAddrString ) {
682 unsigned long ip_a, ip_m;
683 if( !idStr::Icmp( "127.0.0.1", pIPAddrString->IpAddress.String ) ) {
684 foundloopback = true;
686 ip_a = ntohl( inet_addr( pIPAddrString->IpAddress.String ) );
687 ip_m = ntohl( inet_addr( pIPAddrString->IpMask.String ) );
690 common->Printf( "%s NULL netmask - skipped\n", pIPAddrString->IpAddress.String );
691 pIPAddrString = pIPAddrString->Next;
694 common->Printf( "%s/%s\n", pIPAddrString->IpAddress.String, pIPAddrString->IpMask.String );
695 netint[num_interfaces].ip = ip_a;
696 netint[num_interfaces].mask = ip_m;
698 if( num_interfaces >= MAX_INTERFACES ) {
699 common->Printf( "Sys_InitNetworking: MAX_INTERFACES(%d) hit.\n", MAX_INTERFACES );
700 free( pAdapterInfo );
703 pIPAddrString = pIPAddrString->Next;
705 pAdapter = pAdapter->Next;
708 // for some retarded reason, win32 doesn't count loopback as an adapter...
709 if( !foundloopback && num_interfaces < MAX_INTERFACES ) {
710 common->Printf( "Sys_InitNetworking: adding loopback interface\n" );
711 netint[num_interfaces].ip = ntohl( inet_addr( "127.0.0.1" ) );
712 netint[num_interfaces].mask = ntohl( inet_addr( "255.0.0.0" ) );
715 free( pAdapterInfo );
721 Sys_ShutdownNetworking
724 void Sys_ShutdownNetworking( void ) {
725 if ( !winsockInitialized ) {
729 winsockInitialized = false;
737 bool Sys_StringToNetAdr( const char *s, netadr_t *a, bool doDNSResolve ) {
738 struct sockaddr sadr;
740 if ( !Net_StringToSockaddr( s, &sadr, doDNSResolve ) ) {
744 Net_SockadrToNetadr( &sadr, a );
753 const char *Sys_NetAdrToString( const netadr_t a ) {
754 static int index = 0;
755 static char buf[ 4 ][ 64 ]; // flip/flop
759 index = (index + 1) & 3;
761 if ( a.type == NA_LOOPBACK ) {
763 idStr::snPrintf( s, 64, "localhost:%i", a.port );
765 idStr::snPrintf( s, 64, "localhost" );
767 } else if ( a.type == NA_IP ) {
768 idStr::snPrintf( s, 64, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], a.port );
778 bool Sys_IsLANAddress( const netadr_t adr ) {
780 common->Printf( "Sys_IsLANAddress: ID_NOLANADDRESS\n" );
783 if( adr.type == NA_LOOPBACK ) {
787 if( adr.type != NA_IP ) {
791 if( num_interfaces ) {
795 p_ip = (unsigned long *)&adr.ip[0];
798 for( i=0; i < num_interfaces; i++ ) {
799 if( ( netint[i].ip & netint[i].mask ) == ( ip & netint[i].mask ) ) {
809 Sys_CompareNetAdrBase
811 Compares without the port
814 bool Sys_CompareNetAdrBase( const netadr_t a, const netadr_t b ) {
815 if ( a.type != b.type ) {
819 if ( a.type == NA_LOOPBACK ) {
823 if ( a.type == NA_IP ) {
824 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] ) {
830 common->Printf( "Sys_CompareNetAdrBase: bad address type\n" );
834 //=============================================================================
837 #define MAX_UDP_MSG_SIZE 1400
839 typedef struct udpMsg_s {
840 byte data[MAX_UDP_MSG_SIZE];
844 struct udpMsg_s * next;
852 udpMsg_t * sendFirst;
854 udpMsg_t * recieveFirst;
855 udpMsg_t * recieveLast;
856 idBlockAlloc<udpMsg_t, 64> udpMsgAllocator;
859 idUDPLag::idUDPLag( void ) {
860 sendFirst = sendLast = recieveFirst = recieveLast = NULL;
863 idUDPLag::~idUDPLag( void ) {
864 udpMsgAllocator.Shutdown();
867 idUDPLag *udpPorts[65536];
876 memset( &bound_to, 0, sizeof( bound_to ) );
893 bool idPort::InitForPort( int portNumber ) {
894 int len = sizeof( struct sockaddr_in );
896 netSocket = NET_IPSocket( net_ip.GetString(), portNumber, &bound_to );
897 if ( netSocket <= 0 ) {
899 memset( &bound_to, 0, sizeof( bound_to ) );
904 if ( net_socksEnabled.GetBool() ) {
905 NET_OpenSocks( portNumber );
909 udpPorts[ bound_to.port ] = new idUDPLag;
919 void idPort::Close() {
921 if ( udpPorts[ bound_to.port ] ) {
922 delete udpPorts[ bound_to.port ];
923 udpPorts[ bound_to.port ] = NULL;
925 closesocket( netSocket );
927 memset( &bound_to, 0, sizeof( bound_to ) );
936 bool idPort::GetPacket( netadr_t &from, void *data, int &size, int maxSize ) {
942 ret = Net_GetUDPPacket( netSocket, from, (char *)data, size, maxSize );
947 if ( net_forceDrop.GetInteger() > 0 ) {
948 if ( rand() < net_forceDrop.GetInteger() * RAND_MAX / 100 ) {
956 if ( net_forceLatency.GetInteger() > 0 ) {
958 assert( size <= MAX_UDP_MSG_SIZE );
959 msg = udpPorts[ bound_to.port ]->udpMsgAllocator.Alloc();
960 memcpy( msg->data, data, size );
963 msg->time = Sys_Milliseconds();
965 if ( udpPorts[ bound_to.port ]->recieveLast ) {
966 udpPorts[ bound_to.port ]->recieveLast->next = msg;
968 udpPorts[ bound_to.port ]->recieveFirst = msg;
970 udpPorts[ bound_to.port ]->recieveLast = msg;
976 if ( net_forceLatency.GetInteger() > 0 || ( udpPorts[ bound_to.port] && udpPorts[ bound_to.port ]->recieveFirst ) ) {
978 msg = udpPorts[ bound_to.port ]->recieveFirst;
979 if ( msg && msg->time <= Sys_Milliseconds() - net_forceLatency.GetInteger() ) {
980 memcpy( data, msg->data, msg->size );
983 udpPorts[ bound_to.port ]->recieveFirst = udpPorts[ bound_to.port ]->recieveFirst->next;
984 if ( !udpPorts[ bound_to.port ]->recieveFirst ) {
985 udpPorts[ bound_to.port ]->recieveLast = NULL;
987 udpPorts[ bound_to.port ]->udpMsgAllocator.Free( msg );
999 idPort::GetPacketBlocking
1002 bool idPort::GetPacketBlocking( netadr_t &from, void *data, int &size, int maxSize, int timeout ) {
1004 Net_WaitForUDPPacket( netSocket, timeout );
1006 if ( GetPacket( from, data, size, maxSize ) ) {
1018 void idPort::SendPacket( const netadr_t to, const void *data, int size ) {
1021 if ( to.type == NA_BAD ) {
1022 common->Warning( "idPort::SendPacket: bad address type NA_BAD - ignored" );
1027 bytesWritten += size;
1029 if ( net_forceDrop.GetInteger() > 0 ) {
1030 if ( rand() < net_forceDrop.GetInteger() * RAND_MAX / 100 ) {
1035 if ( net_forceLatency.GetInteger() > 0 || ( udpPorts[ bound_to.port ] && udpPorts[ bound_to.port ]->sendFirst ) ) {
1037 assert( size <= MAX_UDP_MSG_SIZE );
1038 msg = udpPorts[ bound_to.port ]->udpMsgAllocator.Alloc();
1039 memcpy( msg->data, data, size );
1042 msg->time = Sys_Milliseconds();
1044 if ( udpPorts[ bound_to.port ]->sendLast ) {
1045 udpPorts[ bound_to.port ]->sendLast->next = msg;
1047 udpPorts[ bound_to.port ]->sendFirst = msg;
1049 udpPorts[ bound_to.port ]->sendLast = msg;
1051 for ( msg = udpPorts[ bound_to.port ]->sendFirst; msg && msg->time <= Sys_Milliseconds() - net_forceLatency.GetInteger(); msg = udpPorts[ bound_to.port ]->sendFirst ) {
1052 Net_SendUDPPacket( netSocket, msg->size, msg->data, msg->address );
1053 udpPorts[ bound_to.port ]->sendFirst = udpPorts[ bound_to.port ]->sendFirst->next;
1054 if ( !udpPorts[ bound_to.port ]->sendFirst ) {
1055 udpPorts[ bound_to.port ]->sendLast = NULL;
1057 udpPorts[ bound_to.port ]->udpMsgAllocator.Free( msg );
1061 Net_SendUDPPacket( netSocket, size, data, to );
1066 //=============================================================================
1075 memset( &address, 0, sizeof( address ) );
1092 bool idTCP::Init( const char *host, short port ) {
1093 unsigned long _true = 1;
1094 struct sockaddr sadr;
1096 if ( !Sys_StringToNetAdr( host, &address, true ) ) {
1097 common->Printf( "Couldn't resolve server name \"%s\"\n", host );
1100 address.type = NA_IP;
1101 if ( !address.port ) {
1102 address.port = port;
1104 common->Printf( "\"%s\" resolved to %i.%i.%i.%i:%i\n", host,
1105 address.ip[0], address.ip[1], address.ip[2], address.ip[3], address.port );
1106 Net_NetadrToSockadr( &address, &sadr );
1109 common->Warning( "idTCP::Init: already initialized?" );
1112 if ( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == INVALID_SOCKET ) {
1114 common->Printf( "ERROR: idTCP::Init: socket: %s\n", NET_ErrorString() );
1118 if ( connect( fd, &sadr, sizeof(sadr)) == SOCKET_ERROR ) {
1119 common->Printf( "ERROR: idTCP::Init: connect: %s\n", NET_ErrorString() );
1125 // make it non-blocking
1126 if( ioctlsocket( fd, FIONBIO, &_true ) == SOCKET_ERROR ) {
1127 common->Printf( "ERROR: idTCP::Init: ioctl FIONBIO: %s\n", NET_ErrorString() );
1133 common->DPrintf( "Opened TCP connection\n" );
1142 void idTCP::Close() {
1154 int idTCP::Read( void *data, int size ) {
1158 common->Printf("idTCP::Read: not initialized\n");
1162 if ( ( nbytes = recv( fd, (char *)data, size, 0 ) ) == SOCKET_ERROR ) {
1163 if ( WSAGetLastError() == WSAEWOULDBLOCK ) {
1166 common->Printf( "ERROR: idTCP::Read: %s\n", NET_ErrorString() );
1171 // a successful read of 0 bytes indicates remote has closed the connection
1172 if ( nbytes == 0 ) {
1173 common->DPrintf( "idTCP::Read: read 0 bytes - assume connection closed\n" );
1185 int idTCP::Write( void *data, int size ) {
1189 common->Printf("idTCP::Write: not initialized\n");
1193 if ( ( nbytes = send( fd, (char *)data, size, 0 ) ) == SOCKET_ERROR ) {
1194 common->Printf( "ERROR: idTCP::Write: %s\n", NET_ErrorString() );