/* =========================================================================== Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. Copyright (C) 2013 Daniel Gibson (changes for POSIX) This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 BFG Edition Source Code. If not, see . In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 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. =========================================================================== */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(MACOS_X) || defined(__FreeBSD__) #include #endif #include "../../idlib/precompiled.h" // DG: TODO: this could be unified with win_net.cpp quite easily, would just need some defines etc.. /* ================================================================================================ Contains the NetworkSystem implementation specific to POSIX Systems (Linux, *BSD, OSX, ...) ================================================================================================ */ static bool usingSocks = false; /* ================================================================================================ Network CVars ================================================================================================ */ idCVar net_socksServer( "net_socksServer", "", CVAR_ARCHIVE, "" ); idCVar net_socksPort( "net_socksPort", "1080", CVAR_ARCHIVE | CVAR_INTEGER, "" ); idCVar net_socksUsername( "net_socksUsername", "", CVAR_ARCHIVE, "" ); idCVar net_socksPassword( "net_socksPassword", "", CVAR_ARCHIVE, "" ); idCVar net_ip( "net_ip", "localhost", CVAR_NOCHEAT, "local IP address" ); static struct sockaddr_in socksRelayAddr; // static int ip_socket; FIXME: what was this about? static int socks_socket = 0; static char socksBuf[4096]; typedef struct { // RB: 64 bit fixes, changed long to int // FIXME: IPv6? unsigned int ip; unsigned int mask; // RB end char addr[16]; } net_interface; #define MAX_INTERFACES 32 int num_interfaces = 0; net_interface netint[MAX_INTERFACES]; /* ================================================================================================ Free Functions ================================================================================================ */ /* ======================== NET_ErrorString ======================== */ const char* NET_ErrorString() { return strerror( errno ); } /* ======================== Net_NetadrToSockadr ======================== */ void Net_NetadrToSockadr( const netadr_t* a, sockaddr_in* s ) { memset( s, 0, sizeof( *s ) ); if( a->type == NA_BROADCAST ) { s->sin_family = AF_INET; s->sin_addr.s_addr = INADDR_BROADCAST; } else if( a->type == NA_IP || a->type == NA_LOOPBACK ) { s->sin_family = AF_INET; s->sin_addr.s_addr = *( ( in_addr_t* ) &a->ip ); } s->sin_port = htons( ( short )a->port ); } /* ======================== Net_SockadrToNetadr ======================== */ #define LOOPBACK_NET 0x7F000000 #define LOOPBACK_PREFIX 0xFF000000 // /8 or 255.0.0.0 void Net_SockadrToNetadr( sockaddr_in* s, netadr_t* a ) { in_addr_t ip; if( s->sin_family == AF_INET ) { ip = s->sin_addr.s_addr; *( in_addr_t* )&a->ip = ip; a->port = ntohs( s->sin_port ); // we store in network order, that loopback test is host order.. ip = ntohl( ip ); // DG: just comparing ip with INADDR_LOOPBACK is lame, // because all of 127.0.0.0/8 is loopback. // if( ( ip & LOOPBACK_PREFIX ) == LOOPBACK_NET ) if( ip == INADDR_LOOPBACK ) { a->type = NA_LOOPBACK; } else { a->type = NA_IP; } } } /* ======================== Net_ExtractPort ======================== */ static bool Net_ExtractPort( const char* src, char* buf, int bufsize, int* port ) { char* p; strncpy( buf, src, bufsize ); p = buf; p += Min( bufsize - 1, idStr::Length( src ) ); *p = '\0'; p = strchr( buf, ':' ); if( !p ) { return false; } *p = '\0'; long lport = strtol( p + 1, NULL, 10 ); if( lport == 0 || lport == LONG_MIN || lport == LONG_MAX ) { *port = 0; return false; } *port = lport; return true; } /* ======================== Net_StringToSockaddr ======================== */ static bool Net_StringToSockaddr( const char* s, sockaddr_in* sadr, bool doDNSResolve ) { /* NOTE: the doDNSResolve argument is ignored for two reasons: * 1. domains can start with numbers nowadays so the old heuristic to find out if it's * an IP (check if the first char is a digit) isn't reliable * 2. gethostbyname() works fine for IPs and doesn't do a lookup if the passed string * is an IP */ struct hostent* h; char buf[256]; int port; memset( sadr, 0, sizeof( *sadr ) ); sadr->sin_family = AF_INET; sadr->sin_port = 0; // try to remove the port first, otherwise the DNS gets confused into multiple timeouts // failed or not failed, buf is expected to contain the appropriate host to resolve if( Net_ExtractPort( s, buf, sizeof( buf ), &port ) ) { sadr->sin_port = htons( port ); } // buf contains the host, even if Net_ExtractPort returned false h = gethostbyname( buf ); if( h == NULL ) { return false; } sadr->sin_addr.s_addr = *( in_addr_t* ) h->h_addr_list[0]; return true; } /* ======================== NET_IPSocket ======================== */ int NET_IPSocket( const char* bind_ip, int port, netadr_t* bound_to ) { int newsocket; sockaddr_in address; if( port != PORT_ANY ) { if( bind_ip ) { idLib::Printf( "Opening IP socket: %s:%i\n", bind_ip, port ); } else { idLib::Printf( "Opening IP socket: localhost:%i\n", port ); } } if( ( newsocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ) { idLib::Printf( "WARNING: UDP_OpenSocket: socket: %s\n", NET_ErrorString() ); return 0; } // make it non-blocking int flags = fcntl( newsocket, F_GETFL, 0 ); if( flags < 0 ) { idLib::Printf( "WARNING: UDP_OpenSocket: fcntl F_GETFL: %s\n", NET_ErrorString() ); close( newsocket ); return 0; } flags |= O_NONBLOCK; if( fcntl( newsocket, F_SETFL, flags ) < 0 ) { idLib::Printf( "WARNING: UDP_OpenSocket: fcntl F_SETFL with O_NONBLOCK: %s\n", NET_ErrorString() ); close( newsocket ); return 0; } // make it broadcast capable int i = 1; if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, ( void* )&i, sizeof( i ) ) < 0 ) { idLib::Printf( "WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() ); close( newsocket ); return 0; } if( !bind_ip || !bind_ip[0] || !idStr::Icmp( bind_ip, "localhost" ) ) { address.sin_addr.s_addr = INADDR_ANY; } else { Net_StringToSockaddr( bind_ip, &address, true ); } if( port == PORT_ANY ) { address.sin_port = 0; } else { address.sin_port = htons( ( short )port ); } address.sin_family = AF_INET; if( bind( newsocket, ( const sockaddr* )&address, sizeof( address ) ) < 0 ) { idLib::Printf( "WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString() ); close( newsocket ); return 0; } // if the port was PORT_ANY, we need to query again to know the real port we got bound to // ( this used to be in idUDP::InitForPort ) if( bound_to ) { socklen_t len = sizeof( address ); if( getsockname( newsocket, ( struct sockaddr* )&address, &len ) < 0 ) { common->Printf( "ERROR: IPSocket: getsockname: %s\n", NET_ErrorString() ); close( newsocket ); return 0; } Net_SockadrToNetadr( &address, bound_to ); } return newsocket; } /* ======================== NET_OpenSocks ======================== */ void NET_OpenSocks( int port ) { sockaddr_in address; struct hostent* h; int len; bool rfc1929; unsigned char buf[64]; usingSocks = false; idLib::Printf( "Opening connection to SOCKS server.\n" ); if( ( socks_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) < 0 ) { idLib::Printf( "WARNING: NET_OpenSocks: socket: %s\n", NET_ErrorString() ); return; } h = gethostbyname( net_socksServer.GetString() ); if( h == NULL ) { idLib::Printf( "WARNING: NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString() ); return; } if( h->h_addrtype != AF_INET ) { idLib::Printf( "WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\n" ); return; } address.sin_family = AF_INET; address.sin_addr.s_addr = *( in_addr_t* )h->h_addr_list[0]; address.sin_port = htons( ( short )net_socksPort.GetInteger() ); if( connect( socks_socket, ( sockaddr* )&address, sizeof( address ) ) < 0 ) { idLib::Printf( "NET_OpenSocks: connect: %s\n", NET_ErrorString() ); return; } // send socks authentication handshake if( *net_socksUsername.GetString() || *net_socksPassword.GetString() ) { rfc1929 = true; } else { rfc1929 = false; } buf[0] = 5; // SOCKS version // method count if( rfc1929 ) { buf[1] = 2; len = 4; } else { buf[1] = 1; len = 3; } buf[2] = 0; // method #1 - method id #00: no authentication if( rfc1929 ) { buf[2] = 2; // method #2 - method id #02: username/password } if( send( socks_socket, ( const char* )buf, len, 0 ) < 0 ) { idLib::Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() ); return; } // get the response len = recv( socks_socket, ( char* )buf, 64, 0 ); if( len < 0 ) { idLib::Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() ); return; } if( len != 2 || buf[0] != 5 ) { idLib::Printf( "NET_OpenSocks: bad response\n" ); return; } switch( buf[1] ) { case 0: // no authentication break; case 2: // username/password authentication break; default: idLib::Printf( "NET_OpenSocks: request denied\n" ); return; } // do username/password authentication if needed if( buf[1] == 2 ) { int ulen; int plen; // build the request ulen = idStr::Length( net_socksUsername.GetString() ); plen = idStr::Length( net_socksPassword.GetString() ); buf[0] = 1; // username/password authentication version buf[1] = ulen; if( ulen ) { memcpy( &buf[2], net_socksUsername.GetString(), ulen ); } buf[2 + ulen] = plen; if( plen ) { memcpy( &buf[3 + ulen], net_socksPassword.GetString(), plen ); } // send it if( send( socks_socket, ( const char* )buf, 3 + ulen + plen, 0 ) < 0 ) { idLib::Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() ); return; } // get the response len = recv( socks_socket, ( char* )buf, 64, 0 ); if( len < 0 ) { idLib::Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() ); return; } if( len != 2 || buf[0] != 1 ) { idLib::Printf( "NET_OpenSocks: bad response\n" ); return; } if( buf[1] != 0 ) { idLib::Printf( "NET_OpenSocks: authentication failed\n" ); return; } } // send the UDP associate request buf[0] = 5; // SOCKS version buf[1] = 3; // command: UDP associate buf[2] = 0; // reserved buf[3] = 1; // address type: IPV4 *( int* )&buf[4] = INADDR_ANY; *( short* )&buf[8] = htons( ( short )port ); // port if( send( socks_socket, ( const char* )buf, 10, 0 ) < 0 ) { idLib::Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() ); return; } // get the response len = recv( socks_socket, ( char* )buf, 64, 0 ); if( len < 0 ) { idLib::Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() ); return; } if( len < 2 || buf[0] != 5 ) { idLib::Printf( "NET_OpenSocks: bad response\n" ); return; } // check completion code if( buf[1] != 0 ) { idLib::Printf( "NET_OpenSocks: request denied: %i\n", buf[1] ); return; } if( buf[3] != 1 ) { idLib::Printf( "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] ); return; } socksRelayAddr.sin_family = AF_INET; socksRelayAddr.sin_addr.s_addr = *( int* )&buf[4]; socksRelayAddr.sin_port = *( short* )&buf[8]; memset( socksRelayAddr.sin_zero, 0, sizeof( socksRelayAddr.sin_zero ) ); usingSocks = true; } /* ======================== Net_WaitForData ======================== */ bool Net_WaitForData( int netSocket, int timeout ) { int ret; fd_set set; struct timeval tv; if( !netSocket ) { return false; } if( timeout < 0 ) { return true; } FD_ZERO( &set ); FD_SET( netSocket, &set ); tv.tv_sec = timeout / 1000; tv.tv_usec = ( timeout % 1000 ) * 1000; ret = select( netSocket + 1, &set, NULL, NULL, &tv ); if( ret == -1 ) { idLib::Printf( "Net_WaitForData select(): %s\n", strerror( errno ) ); return false; } // timeout with no data if( ret == 0 ) { return false; } return true; } /* ======================== Net_GetUDPPacket ======================== */ bool Net_GetUDPPacket( int netSocket, netadr_t& net_from, void* data, int& size, int maxSize ) { int ret; sockaddr_in from; socklen_t fromlen; int err; if( !netSocket ) { return false; } fromlen = sizeof( from ); ret = recvfrom( netSocket, data, maxSize, 0, ( sockaddr* )&from, &fromlen ); if( ret < 0 ) { err = errno; if( err == EWOULDBLOCK || err == ECONNRESET ) { return false; } idLib::Printf( "Net_GetUDPPacket: %s\n", NET_ErrorString() ); return false; } #if 0 // TODO: WTF was this about? // DG: ip_socket is never initialized, so this is dead code // - and if netSocket is 0 (so this would be true) recvfrom above will already fail if( static_cast( netSocket ) == ip_socket ) { memset( from.sin_zero, 0, sizeof( from.sin_zero ) ); } if( usingSocks && static_cast( netSocket ) == ip_socket && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) { if( ret < 10 || data[0] != 0 || data[1] != 0 || data[2] != 0 || data[3] != 1 ) { return false; } net_from.type = NA_IP; net_from.ip[0] = data[4]; net_from.ip[1] = data[5]; net_from.ip[2] = data[6]; net_from.ip[3] = data[7]; net_from.port = *( short* )&data[8]; memmove( data, &data[10], ret - 10 ); } else { #endif // 0 Net_SockadrToNetadr( &from, &net_from ); #if 0 // this is ugly, but else astyle is confused } #endif if( ret > maxSize ) { idLib::Printf( "Net_GetUDPPacket: oversize packet from %s\n", Sys_NetAdrToString( net_from ) ); return false; } size = ret; return true; } /* ======================== Net_SendUDPPacket ======================== */ void Net_SendUDPPacket( int netSocket, int length, const void* data, const netadr_t to ) { int ret; sockaddr_in addr; if( !netSocket ) { return; } Net_NetadrToSockadr( &to, &addr ); if( usingSocks && to.type == NA_IP ) { socksBuf[0] = 0; // reserved socksBuf[1] = 0; socksBuf[2] = 0; // fragment (not fragmented) socksBuf[3] = 1; // address type: IPV4 *( int* )&socksBuf[4] = addr.sin_addr.s_addr; *( short* )&socksBuf[8] = addr.sin_port; memcpy( &socksBuf[10], data, length ); ret = sendto( netSocket, socksBuf, length + 10, 0, ( sockaddr* )&socksRelayAddr, sizeof( socksRelayAddr ) ); } else { ret = sendto( netSocket, ( const char* )data, length, 0, ( sockaddr* )&addr, sizeof( addr ) ); } if( ret < 0 ) { // some PPP links do not allow broadcasts and return an error if( ( errno == EADDRNOTAVAIL ) && ( to.type == NA_BROADCAST ) ) { return; } // NOTE: EWOULDBLOCK used to be silently ignored, // but that means the packet will be dropped so I don't feel it's a good thing to ignore idLib::Printf( "UDP sendto error - packet dropped: %s\n", NET_ErrorString() ); } } static void ip_to_addr( const char ip[4], char* addr ) { idStr::snPrintf( addr, 16, "%d.%d.%d.%d", ( unsigned char )ip[0], ( unsigned char )ip[1], ( unsigned char )ip[2], ( unsigned char )ip[3] ); } /* ======================== Sys_InitNetworking ======================== */ void Sys_InitNetworking() { // haven't been able to clearly pinpoint which standards or RFCs define SIOCGIFCONF, SIOCGIFADDR, SIOCGIFNETMASK ioctls // it seems fairly widespread, in Linux kernel ioctl, and in BSD .. so let's assume it's always available on our targets bool foundloopback = false; #if defined(MACOS_X) || defined(__FreeBSD__) unsigned int ip, mask; struct ifaddrs* ifap, *ifp; num_interfaces = 0; if( getifaddrs( &ifap ) < 0 ) { common->FatalError( "InitNetworking: SIOCGIFCONF error - %s\n", strerror( errno ) ); return; } for( ifp = ifap; ifp; ifp = ifp->ifa_next ) { if( ifp->ifa_addr->sa_family != AF_INET ) continue; if( !( ifp->ifa_flags & IFF_UP ) ) continue; if( !ifp->ifa_addr ) continue; if( !ifp->ifa_netmask ) continue; // RB: 64 bit fixes, changed long to int ip = ntohl( *( unsigned int* )&ifp->ifa_addr->sa_data[2] ); mask = ntohl( *( unsigned int* )&ifp->ifa_netmask->sa_data[2] ); // RB end if( ip == INADDR_LOOPBACK ) { foundloopback = true; common->Printf( "loopback\n" ); } else { common->Printf( "%d.%d.%d.%d", ( unsigned char )ifp->ifa_addr->sa_data[2], ( unsigned char )ifp->ifa_addr->sa_data[3], ( unsigned char )ifp->ifa_addr->sa_data[4], ( unsigned char )ifp->ifa_addr->sa_data[5] ); common->Printf( "/%d.%d.%d.%d\n", ( unsigned char )ifp->ifa_netmask->sa_data[2], ( unsigned char )ifp->ifa_netmask->sa_data[3], ( unsigned char )ifp->ifa_netmask->sa_data[4], ( unsigned char )ifp->ifa_netmask->sa_data[5] ); } netint[ num_interfaces ].ip = ip; netint[ num_interfaces ].mask = mask; // DG: set netint addr ip_to_addr( &ifp->ifa_addr->sa_data[2], netint[ num_interfaces ].addr ); // DG end num_interfaces++; } #else int s; char buf[ MAX_INTERFACES * sizeof( ifreq ) ]; ifconf ifc; ifreq* ifr; int ifindex; unsigned int ip, mask; num_interfaces = 0; s = socket( AF_INET, SOCK_DGRAM, 0 ); ifc.ifc_len = MAX_INTERFACES * sizeof( ifreq ); ifc.ifc_buf = buf; if( ioctl( s, SIOCGIFCONF, &ifc ) < 0 ) { common->FatalError( "InitNetworking: SIOCGIFCONF error - %s\n", strerror( errno ) ); return; } ifindex = 0; while( ifindex < ifc.ifc_len ) { common->Printf( "found interface %s - ", ifc.ifc_buf + ifindex ); // find the type - ignore interfaces for which we can find we can't get IP and mask ( not configured ) ifr = ( ifreq* )( ifc.ifc_buf + ifindex ); if( ioctl( s, SIOCGIFADDR, ifr ) < 0 ) { common->Printf( "SIOCGIFADDR failed: %s\n", strerror( errno ) ); } else { if( ifr->ifr_addr.sa_family != AF_INET ) { common->Printf( "not AF_INET\n" ); } else { // RB: 64 bit fixes, changed long to int ip = ntohl( *( unsigned int* )&ifr->ifr_addr.sa_data[2] ); // RB end if( ip == INADDR_LOOPBACK ) { foundloopback = true; common->Printf( "loopback\n" ); } else { common->Printf( "%d.%d.%d.%d", ( unsigned char )ifr->ifr_addr.sa_data[2], ( unsigned char )ifr->ifr_addr.sa_data[3], ( unsigned char )ifr->ifr_addr.sa_data[4], ( unsigned char )ifr->ifr_addr.sa_data[5] ); } // DG: set netint address before getting the mask ip_to_addr( &ifr->ifr_addr.sa_data[2], netint[ num_interfaces ].addr ); // DG end if( ioctl( s, SIOCGIFNETMASK, ifr ) < 0 ) { common->Printf( " SIOCGIFNETMASK failed: %s\n", strerror( errno ) ); } else { // RB: 64 bit fixes, changed long to int mask = ntohl( *( unsigned int* )&ifr->ifr_addr.sa_data[2] ); // RB end if( ip != INADDR_LOOPBACK ) { common->Printf( "/%d.%d.%d.%d\n", ( unsigned char )ifr->ifr_addr.sa_data[2], ( unsigned char )ifr->ifr_addr.sa_data[3], ( unsigned char )ifr->ifr_addr.sa_data[4], ( unsigned char )ifr->ifr_addr.sa_data[5] ); } netint[ num_interfaces ].ip = ip; netint[ num_interfaces ].mask = mask; num_interfaces++; } } } ifindex += sizeof( ifreq ); } #endif // for some retarded reason, win32 doesn't count loopback as an adapter... // and because I'm extra-cautious I add this check on real operating systems as well :) if( !foundloopback && num_interfaces < MAX_INTERFACES ) { idLib::Printf( "Sys_InitNetworking: adding loopback interface\n" ); netint[num_interfaces].ip = ntohl( inet_addr( "127.0.0.1" ) ); netint[num_interfaces].mask = ntohl( inet_addr( "255.0.0.0" ) ); num_interfaces++; } } /* ======================== Sys_ShutdownNetworking ======================== */ void Sys_ShutdownNetworking() { if( usingSocks ) close( socks_socket ); } /* ======================== Sys_StringToNetAdr ======================== */ bool Sys_StringToNetAdr( const char* s, netadr_t* a, bool doDNSResolve ) { sockaddr_in sadr; if( !Net_StringToSockaddr( s, &sadr, doDNSResolve ) ) { return false; } Net_SockadrToNetadr( &sadr, a ); return true; } /* ======================== Sys_NetAdrToString ======================== */ const char* Sys_NetAdrToString( const netadr_t a ) { // DG: FIXME: those static buffers look fishy - I would feel better if they were // at least thread-local - so /maybe/ use ID_TLS here? static int index = 0; static char buf[ 4 ][ 64 ]; // flip/flop char* s; s = buf[index]; index = ( index + 1 ) & 3; if( a.type == NA_IP || a.type == NA_LOOPBACK ) idStr::snPrintf( s, 64, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], a.port ); else if( a.type == NA_BROADCAST ) idStr::snPrintf( s, 64, "BROADCAST" ); else if( a.type == NA_BAD ) idStr::snPrintf( s, 64, "BAD_IP" ); else { idStr::snPrintf( s, 64, "WTF_UNKNOWN_IP_TYPE_%i", a.type ); } return s; } /* ======================== Sys_IsLANAddress ======================== */ bool Sys_IsLANAddress( const netadr_t adr ) { if( adr.type == NA_LOOPBACK ) { return true; } if( adr.type != NA_IP ) { return false; } // NOTE: this function won't work reliably for addresses on the local net // that are connected through a router (i.e. no IP from that net is on any interface) // However, I don't expect most people to have such setups at home and the code // would get a lot more complex and less portable. // Furthermore, this function isn't even used currently if( num_interfaces ) { int i; // DG: for 64bit compatibility, make these longs ints. unsigned int* p_ip; unsigned int ip; p_ip = ( unsigned int* )&adr.ip[0]; // DG end ip = ntohl( *p_ip ); for( i = 0; i < num_interfaces; i++ ) { if( ( netint[i].ip & netint[i].mask ) == ( ip & netint[i].mask ) ) { return true; } } } return false; } /* ======================== Sys_CompareNetAdrBase Compares without the port. ======================== */ bool Sys_CompareNetAdrBase( const netadr_t a, const netadr_t b ) { if( a.type != b.type ) { return false; } if( a.type == NA_LOOPBACK ) { // DG: wtf is this comparison about, the comment above says "without the port" if( a.port == b.port ) { return true; } return false; } if( a.type == NA_IP ) { 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] ) { return true; } return false; } idLib::Printf( "Sys_CompareNetAdrBase: bad address type\n" ); return false; } /* ======================== Sys_GetLocalIPCount ======================== */ int Sys_GetLocalIPCount() { return num_interfaces; } /* ======================== Sys_GetLocalIP ======================== */ const char* Sys_GetLocalIP( int i ) { if( ( i < 0 ) || ( i >= num_interfaces ) ) { return NULL; } return netint[i].addr; } /* ================================================================================================ idUDP ================================================================================================ */ /* ======================== idUDP::idUDP ======================== */ idUDP::idUDP() { netSocket = 0; memset( &bound_to, 0, sizeof( bound_to ) ); silent = false; packetsRead = 0; bytesRead = 0; packetsWritten = 0; bytesWritten = 0; } /* ======================== idUDP::~idUDP ======================== */ idUDP::~idUDP() { Close(); } /* ======================== idUDP::InitForPort ======================== */ bool idUDP::InitForPort( int portNumber ) { // DG: don't specify an IP to bind for (and certainly not net_ip) // => it'll listen on all addresses (0.0.0.0 / INADDR_ANY) netSocket = NET_IPSocket( NULL, portNumber, &bound_to ); // DG end if( netSocket <= 0 ) { netSocket = 0; memset( &bound_to, 0, sizeof( bound_to ) ); return false; } return true; } /* ======================== idUDP::Close ======================== */ void idUDP::Close() { if( netSocket ) { close( netSocket ); netSocket = 0; memset( &bound_to, 0, sizeof( bound_to ) ); } } /* ======================== idUDP::GetPacket ======================== */ bool idUDP::GetPacket( netadr_t& from, void* data, int& size, int maxSize ) { // DG: this fake while(1) loop pissed me off so I replaced it.. no functional change. if( ! Net_GetUDPPacket( netSocket, from, data, size, maxSize ) ) { return false; } packetsRead++; bytesRead += size; return true; // DG end } /* ======================== idUDP::GetPacketBlocking ======================== */ bool idUDP::GetPacketBlocking( netadr_t& from, void* data, int& size, int maxSize, int timeout ) { if( !Net_WaitForData( netSocket, timeout ) ) { return false; } if( GetPacket( from, data, size, maxSize ) ) { return true; } return false; } /* ======================== idUDP::SendPacket ======================== */ void idUDP::SendPacket( const netadr_t to, const void* data, int size ) { if( to.type == NA_BAD ) { idLib::Warning( "idUDP::SendPacket: bad address type NA_BAD - ignored" ); return; } packetsWritten++; bytesWritten += size; if( silent ) { return; } Net_SendUDPPacket( netSocket, size, data, to ); }