You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
8.1 KiB
378 lines
8.1 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// NetAdr.cpp: implementation of the CNetAdr class. |
|
// |
|
//===========================================================================// |
|
#if defined( _WIN32 ) && !defined( _X360 ) |
|
#include <windows.h> |
|
#endif |
|
|
|
#include "tier0/dbg.h" |
|
#include "netadr.h" |
|
#include "tier1/strtools.h" |
|
|
|
#if defined( _WIN32 ) && !defined( _X360 ) |
|
#define WIN32_LEAN_AND_MEAN |
|
#include <winsock.h> |
|
typedef int socklen_t; |
|
#elif !defined( _X360 ) |
|
#include <netinet/in.h> // ntohs() |
|
#include <netdb.h> // gethostbyname() |
|
#include <sys/socket.h> // getsockname() |
|
#endif |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
// Construction/Destruction |
|
////////////////////////////////////////////////////////////////////// |
|
|
|
bool netadr_t::CompareAdr (const netadr_t &a, bool onlyBase) const |
|
{ |
|
if ( a.type != type ) |
|
return false; |
|
|
|
if ( type == NA_LOOPBACK ) |
|
return true; |
|
|
|
if ( type == NA_BROADCAST ) |
|
return true; |
|
|
|
if ( type == NA_IP ) |
|
{ |
|
if ( !onlyBase && (port != a.port) ) |
|
return false; |
|
|
|
if ( a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] && a.ip[3] == ip[3] ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool netadr_t::CompareClassBAdr (const netadr_t &a) const |
|
{ |
|
if ( a.type != type ) |
|
return false; |
|
|
|
if ( type == NA_LOOPBACK ) |
|
return true; |
|
|
|
if ( type == NA_IP ) |
|
{ |
|
if (a.ip[0] == ip[0] && a.ip[1] == ip[1] ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool netadr_t::CompareClassCAdr (const netadr_t &a) const |
|
{ |
|
if ( a.type != type ) |
|
return false; |
|
|
|
if ( type == NA_LOOPBACK ) |
|
return true; |
|
|
|
if ( type == NA_IP ) |
|
{ |
|
if (a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
// reserved addresses are not routeable, so they can all be used in a LAN game |
|
bool netadr_t::IsReservedAdr () const |
|
{ |
|
if ( type == NA_LOOPBACK ) |
|
return true; |
|
|
|
if ( type == NA_IP ) |
|
{ |
|
if ( (ip[0] == 10) || // 10.x.x.x is reserved |
|
(ip[0] == 127) || // 127.x.x.x |
|
(ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) || // 172.16.x.x - 172.31.x.x |
|
(ip[0] == 192 && ip[1] >= 168) ) // 192.168.x.x |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
const char * netadr_t::ToString( bool onlyBase ) const |
|
{ |
|
// Select a static buffer |
|
static char s[4][64]; |
|
static int slot = 0; |
|
int useSlot = ( slot++ ) % 4; |
|
|
|
// Render into it |
|
ToString( s[useSlot], sizeof(s[0]), onlyBase ); |
|
|
|
// Pray the caller uses it before it gets clobbered |
|
return s[useSlot]; |
|
} |
|
|
|
void netadr_t::ToString( char *pchBuffer, uint32 unBufferSize, bool onlyBase ) const |
|
{ |
|
|
|
if (type == NA_LOOPBACK) |
|
{ |
|
V_strncpy( pchBuffer, "loopback", unBufferSize ); |
|
} |
|
else if (type == NA_BROADCAST) |
|
{ |
|
V_strncpy( pchBuffer, "broadcast", unBufferSize ); |
|
} |
|
else if (type == NA_IP) |
|
{ |
|
if ( onlyBase ) |
|
{ |
|
V_snprintf( pchBuffer, unBufferSize, "%i.%i.%i.%i", ip[0], ip[1], ip[2], ip[3]); |
|
} |
|
else |
|
{ |
|
V_snprintf( pchBuffer, unBufferSize, "%i.%i.%i.%i:%i", ip[0], ip[1], ip[2], ip[3], ntohs(port)); |
|
} |
|
} |
|
else |
|
{ |
|
V_strncpy( pchBuffer, "unknown", unBufferSize ); |
|
} |
|
} |
|
|
|
bool netadr_t::IsLocalhost() const |
|
{ |
|
// are we 127.0.0.1 ? |
|
return (ip[0] == 127) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 1); |
|
} |
|
|
|
bool netadr_t::IsLoopback() const |
|
{ |
|
// are we useding engine loopback buffers |
|
return type == NA_LOOPBACK; |
|
} |
|
|
|
void netadr_t::Clear() |
|
{ |
|
ip[0] = ip[1] = ip[2] = ip[3] = 0; |
|
port = 0; |
|
type = NA_NULL; |
|
} |
|
|
|
void netadr_t::SetIP(uint8 b1, uint8 b2, uint8 b3, uint8 b4) |
|
{ |
|
ip[0] = b1; |
|
ip[1] = b2; |
|
ip[2] = b3; |
|
ip[3] = b4; |
|
} |
|
|
|
void netadr_t::SetIP(uint unIP) |
|
{ |
|
*((uint*)ip) = BigLong( unIP ); |
|
} |
|
|
|
void netadr_t::SetType(netadrtype_t newtype) |
|
{ |
|
type = newtype; |
|
} |
|
|
|
netadrtype_t netadr_t::GetType() const |
|
{ |
|
return type; |
|
} |
|
|
|
unsigned short netadr_t::GetPort() const |
|
{ |
|
return BigShort( port ); |
|
} |
|
|
|
unsigned int netadr_t::GetIPNetworkByteOrder() const |
|
{ |
|
return *(unsigned int *)&ip; |
|
} |
|
|
|
unsigned int netadr_t::GetIPHostByteOrder() const |
|
{ |
|
return BigDWord( GetIPNetworkByteOrder() ); |
|
} |
|
|
|
void netadr_t::ToSockadr (struct sockaddr * s) const |
|
{ |
|
Q_memset ( s, 0, sizeof(struct sockaddr)); |
|
|
|
if (type == NA_BROADCAST) |
|
{ |
|
((struct sockaddr_in*)s)->sin_family = AF_INET; |
|
((struct sockaddr_in*)s)->sin_port = port; |
|
((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_BROADCAST; |
|
} |
|
else if (type == NA_IP) |
|
{ |
|
((struct sockaddr_in*)s)->sin_family = AF_INET; |
|
((struct sockaddr_in*)s)->sin_addr.s_addr = *(int *)&ip; |
|
((struct sockaddr_in*)s)->sin_port = port; |
|
} |
|
else if (type == NA_LOOPBACK ) |
|
{ |
|
((struct sockaddr_in*)s)->sin_family = AF_INET; |
|
((struct sockaddr_in*)s)->sin_port = port; |
|
((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_LOOPBACK ; |
|
} |
|
} |
|
|
|
bool netadr_t::SetFromSockadr(const struct sockaddr * s) |
|
{ |
|
if (s->sa_family == AF_INET) |
|
{ |
|
type = NA_IP; |
|
*(int *)&ip = ((struct sockaddr_in *)s)->sin_addr.s_addr; |
|
port = ((struct sockaddr_in *)s)->sin_port; |
|
return true; |
|
} |
|
else |
|
{ |
|
Clear(); |
|
return false; |
|
} |
|
} |
|
|
|
bool netadr_t::IsValid() const |
|
{ |
|
return ( (port !=0 ) && (type != NA_NULL) && |
|
( ip[0] != 0 || ip[1] != 0 || ip[2] != 0 || ip[3] != 0 ) ); |
|
} |
|
|
|
bool netadr_t::IsBaseAdrValid() const |
|
{ |
|
return ( (type != NA_NULL) && |
|
( ip[0] != 0 || ip[1] != 0 || ip[2] != 0 || ip[3] != 0 ) ); |
|
} |
|
|
|
#ifdef _WIN32 |
|
#undef SetPort // get around stupid WINSPOOL.H macro |
|
#endif |
|
|
|
void netadr_t::SetPort(unsigned short newport) |
|
{ |
|
port = BigShort( newport ); |
|
} |
|
|
|
bool netadr_t::SetFromString( const char *pch, bool bUseDNS ) |
|
{ |
|
Clear(); |
|
type = NA_IP; |
|
|
|
Assert( pch ); // invalid to call this with NULL pointer; fix your code bug! |
|
if ( !pch ) // but let's not crash |
|
return false; |
|
|
|
char address[ 128 ]; |
|
V_strcpy_safe( address, pch ); |
|
|
|
if ( !V_strnicmp( address, "loopback", 8 ) ) |
|
{ |
|
char newaddress[ 128 ]; |
|
type = NA_LOOPBACK; |
|
V_strcpy_safe( newaddress, "127.0.0.1" ); |
|
V_strcat_safe( newaddress, address + 8 ); // copy anything after "loopback" |
|
|
|
V_strcpy_safe( address, newaddress ); |
|
} |
|
|
|
if ( !V_strnicmp( address, "localhost", 9 ) ) |
|
{ |
|
V_memcpy( address, "127.0.0.1", 9 ); // Note use of memcpy allows us to keep the colon and rest of string since localhost and 127.0.0.1 are both 9 characters. |
|
} |
|
|
|
// Starts with a number and has a dot |
|
if ( address[0] >= '0' && |
|
address[0] <= '9' && |
|
strchr( address, '.' ) ) |
|
{ |
|
int n1 = -1, n2 = -1, n3 = -1, n4 = -1, n5 = 0; // set port to 0 if we don't parse one |
|
int nRes = sscanf( address, "%d.%d.%d.%d:%d", &n1, &n2, &n3, &n4, &n5 ); |
|
if ( |
|
nRes < 4 |
|
|| n1 < 0 || n1 > 255 |
|
|| n2 < 0 || n2 > 255 |
|
|| n3 < 0 || n3 > 255 |
|
|| n4 < 0 || n4 > 255 |
|
|| n5 < 0 || n5 > 65535 |
|
) |
|
return false; |
|
SetIP( n1, n2, n3, n4 ); |
|
SetPort( ( uint16 ) n5 ); |
|
return true; |
|
} |
|
|
|
if ( bUseDNS ) |
|
{ |
|
// X360TBD: |
|
// dgoodenough - since this is skipped on X360, seems reasonable to skip as well on PS3 |
|
// PS3_BUILDFIX |
|
// FIXME - Leap of faith, this works without asserting on X360, so I assume it will on PS3 |
|
#if !defined( _X360 ) && !defined( _PS3 ) |
|
// Null out the colon if there is one |
|
char *pchColon = strchr( address, ':' ); |
|
if ( pchColon ) |
|
{ |
|
*pchColon = 0; |
|
} |
|
|
|
// DNS it base name |
|
struct hostent *h = gethostbyname( address ); |
|
if ( !h ) |
|
return false; |
|
|
|
SetIP( ntohl( *(int *)h->h_addr_list[0] ) ); |
|
|
|
// Set Port to whatever was specified after the colon |
|
if ( pchColon ) |
|
{ |
|
SetPort( V_atoi( ++pchColon ) ); |
|
} |
|
return true; |
|
#else |
|
Assert( 0 ); |
|
return false; |
|
#endif |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool netadr_t::operator<(const netadr_t &netadr) const |
|
{ |
|
if ( *((uint *)netadr.ip) < *((uint *)ip) ) |
|
return true; |
|
else if ( *((uint *)netadr.ip) > *((uint *)ip) ) |
|
return false; |
|
return ( netadr.port < port ); |
|
} |
|
|
|
|
|
void netadr_t::SetFromSocket( int hSocket ) |
|
{ |
|
// dgoodenough - since this is skipped on X360, seems reasonable to skip as well on PS3 |
|
// PS3_BUILDFIX |
|
// FIXME - Leap of faith, this works without asserting on X360, so I assume it will on PS3 |
|
#if !defined( _X360 ) && !defined( _PS3 ) |
|
Clear(); |
|
type = NA_IP; |
|
|
|
struct sockaddr address; |
|
socklen_t namelen = sizeof(address); |
|
if ( getsockname( hSocket, (struct sockaddr *)&address, &namelen) == 0 ) |
|
{ |
|
SetFromSockadr( &address ); |
|
} |
|
#else |
|
Assert(0); |
|
#endif |
|
}
|
|
|