r5sdk/r5dev/tier1/NetAdr.cpp

441 lines
11 KiB
C++
Raw Normal View History

//===========================================================================//
//
// Purpose: implementation of the CNetAdr class.
// --------------------------------------------------------------------------
//
// NOTE: This implementation is considered deprecated. I rebuilded this
// not knowing that the engine supports IPv6 as well. I have fully rewritten
// this class in 'tier1/NetAdr2.cpp' in modern C++. Please use this instead.
// This class is for reference material only may some bits in the engine line
// up with this original 'CNetAdr' implementation.
//
//===========================================================================//
#include "core/stdafx.h"
#include "tier1/netadr.h"
#include "mathlib/swap.h"
//////////////////////////////////////////////////////////////////////
// Constructors
//////////////////////////////////////////////////////////////////////
netadr_s::netadr_s(void)
{
SetIP(0);
SetPort(0);
SetType(netadrtype_t::NA_IP);
}
netadr_s::netadr_s(std::uint32_t unIP, std::uint16_t usPort)
{
SetIP(unIP);
SetPort(usPort);
SetType(netadrtype_t::NA_IP);
}
netadr_s::netadr_s(const char* pch)
{
SetFromString(pch);
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
void netadr_t::SetFromSocket(int hSocket)
{
Clear();
type = netadrtype_t::NA_IP;
struct sockaddr address{};
socklen_t namelen = sizeof(address);
if (getsockname(hSocket, (struct sockaddr*)&address, &namelen) == 0)
{
SetFromSockadr(&address);
}
}
//////////////////////////////////////////////////////////////////////
// Compares IP for equality
//////////////////////////////////////////////////////////////////////
bool netadr_t::CompareAdr(const netadr_t& a, bool onlyBase) const
{
if (a.type != type)
{
return false;
}
if (type == netadrtype_t::NA_LOOPBACK)
{
return true;
}
if (type == netadrtype_t::NA_BROADCAST)
{
return true;
}
if (type == netadrtype_t::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;
}
//////////////////////////////////////////////////////////////////////
// Compares Class-B IP for equality
//////////////////////////////////////////////////////////////////////
bool netadr_t::CompareClassBAdr(const netadr_t& a) const
{
if (a.type != type)
{
return false;
}
if (type == netadrtype_t::NA_LOOPBACK)
{
return true;
}
if (type == netadrtype_t::NA_IP)
{
if (a.ip[0] == ip[0] && a.ip[1] == ip[1])
{
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////
// Compares Class-C IP for equality
//////////////////////////////////////////////////////////////////////
bool netadr_t::CompareClassCAdr(const netadr_t& a) const
{
if (a.type != type)
{
return false;
}
if (type == netadrtype_t::NA_LOOPBACK)
{
return true;
}
if (type == netadrtype_t::NA_IP)
{
if (a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2])
{
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////
// Convert address to string
//////////////////////////////////////////////////////////////////////
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];
}
//////////////////////////////////////////////////////////////////////
// Convert address to string
//////////////////////////////////////////////////////////////////////
void netadr_t::ToString(char* pchBuffer, std::uint32_t unBufferSize, bool bOnlyBase) const
{
if (type == netadrtype_t::NA_LOOPBACK)
{
memmove(pchBuffer, "loopback", unBufferSize);
}
else if (type == netadrtype_t::NA_BROADCAST)
{
memmove(pchBuffer, "broadcast", unBufferSize);
}
else if (type == netadrtype_t::NA_IP)
{
if (bOnlyBase)
{
snprintf(pchBuffer, unBufferSize, "%i.%i.%i.%i", ip[0], ip[1], ip[2], ip[3]);
}
else
{
snprintf(pchBuffer, unBufferSize, "%i.%i.%i.%i:%i", ip[0], ip[1], ip[2], ip[3], ntohs(port));
}
}
else
{
memmove(pchBuffer, "unknown", unBufferSize);
}
}
//////////////////////////////////////////////////////////////////////
// Clears IP
//////////////////////////////////////////////////////////////////////
void netadr_t::Clear(void)
{
ip[0] = ip[1] = ip[2] = ip[3] = 0;
port = 0;
type = netadrtype_t::NA_NULL;
}
//////////////////////////////////////////////////////////////////////
// Sets IP
//////////////////////////////////////////////////////////////////////
void netadr_t::SetIP(std::uint8_t b1, std::uint8_t b2, std::uint8_t b3, std::uint8_t b4)
{
ip[0] = b1;
ip[1] = b2;
ip[2] = b3;
ip[3] = b4;
}
//////////////////////////////////////////////////////////////////////
// Sets IP
//////////////////////////////////////////////////////////////////////
void netadr_t::SetIP(std::uint32_t unIP)
{
*((std::uint32_t*)ip) = DWordSwapC(unIP);
}
//////////////////////////////////////////////////////////////////////
// Sets type
//////////////////////////////////////////////////////////////////////
void netadr_t::SetType(netadrtype_t newtype)
{
type = newtype;
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
netadrtype_t netadr_t::GetType(void) const
{
return type;
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
std::uint16_t netadr_t::GetPort(void) const
{
return WordSwapC(port);
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
std::uint32_t netadr_t::GetIPNetworkByteOrder(void) const
{
return *(std::uint32_t*)&ip;
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
std::uint32_t netadr_t::GetIPHostByteOrder(void) const
{
return DWordSwapC(GetIPNetworkByteOrder());
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
void netadr_t::ToSockadr(struct sockaddr* s) const
{
memset(s, 0, sizeof(struct sockaddr));
if (type == netadrtype_t::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 == netadrtype_t::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 == netadrtype_t::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 = netadrtype_t::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(void) const
{
return ((port != 0) && (type != netadrtype_t::NA_NULL) &&
(ip[0] != 0 || ip[1] != 0 || ip[2] != 0 || ip[3] != 0));
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
bool netadr_t::IsBaseAdrValid(void) const
{
return ((type != netadrtype_t::NA_NULL) &&
(ip[0] != 0 || ip[1] != 0 || ip[2] != 0 || ip[3] != 0));
}
//////////////////////////////////////////////////////////////////////
// Returns true if we are localhost
//////////////////////////////////////////////////////////////////////
bool netadr_t::IsLocalhost(void) const
{
return (ip[0] == 127) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 1);
}
//////////////////////////////////////////////////////////////////////
// Returns true if we use the loopback buffers
//////////////////////////////////////////////////////////////////////
bool netadr_t::IsLoopback(void) const
{
return type == netadrtype_t::NA_LOOPBACK;
}
//////////////////////////////////////////////////////////////////////
// Check if address is reserved and not routable.
//////////////////////////////////////////////////////////////////////
bool netadr_t::IsReservedAdr(void) const
{
if (type == netadrtype_t::NA_LOOPBACK)
{
return true;
}
if (type == netadrtype_t::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;
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
void netadr_t::SetPort(std::uint16_t newport)
{
port = WordSwapC(newport);
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
bool netadr_t::SetFromString(const char* szIpAdr, bool bUseDNS)
{
Clear();
if (!szIpAdr)
{
Assert(szIpAdr, "Invalid call: 'szIpAdr' was nullptr.");
return false;
}
type = netadrtype_t::NA_IP;
char szAddress[128]{};
strcpy_s(szAddress, szIpAdr);
if (!_strnicmp(szAddress, "loopback", 8))
{
char szNewAddress[128]{};
type = netadrtype_t::NA_LOOPBACK;
strcpy_s(szNewAddress, "127.0.0.1");
strcat_s(szNewAddress, szAddress + 8); // copy anything after "loopback"
strcpy_s(szAddress, szNewAddress);
}
if (!_strnicmp(szAddress, "localhost", 9))
{
memcpy(szAddress, "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.
}
// IPv4 starts with a number and has a dot.
if (szAddress[0] >= '0' && szAddress[0] <= '9' && strchr(szAddress, '.'))
{
int i0 = -1, i1 = -1, i2 = -1, i3 = -1, n0 = 0; // Initialize port as zero
int nRes = sscanf_s(szAddress, "%d.%d.%d.%d:%d", &i0, &i1, &i2, &i3, &n0);
if (
nRes < 4
|| i0 < 0 || i0 > 255
|| i1 < 0 || i1 > 255
|| i2 < 0 || i2 > 255
|| i3 < 0 || i3 > 255
|| n0 < 0 || n0 > 65535
)
{
return false;
}
SetIP(i0, i1, i2, i3);
SetPort((std::uint16_t)n0);
return true;
}
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
bool netadr_t::operator<(const netadr_t& netadr) const
{
if (*((std::uint32_t*)netadr.ip) < *((std::uint32_t*)ip))
{
return true;
}
else if (*((std::uint32_t*)netadr.ip) > *((std::uint32_t*)ip))
{
return false;
}
return (netadr.port < port);
}