mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
* All libraries have been isolated from each other, and build into separate artifacts. * Project has been restructured to support isolating libraries. * CCrashHandler now calls a callback on crash (setup from core/dllmain.cpp, this can be setup in any way for any project. This callback is getting called when the apllication crashes. Useful for flushing buffers before closing handles to logging files for example). * Tier0 'CoreMsgV' function now calls a callback sink, which could be set by the user (currently setup to the SDK's internal logger in core/dllmain.cpp). TODO: * Add a batch file to autogenerate all projects. * Add support for dedicated server. * Add support for client dll. Bugs: * Game crashes on the title screen after the UI script compiler has finished (root cause unknown). * Curl error messages are getting logged twice for the dedicated server due to the removal of all "DEDICATED" preprocessor directives to support isolating projects. This has to be fixed properly!
315 lines
8.2 KiB
C++
315 lines
8.2 KiB
C++
//===========================================================================//
|
|
//
|
|
// Purpose: implementation of the CNetAdr class.
|
|
// --------------------------------------------------------------------------
|
|
//===========================================================================//
|
|
|
|
#include "tier0_pch.h"
|
|
#include "tier1/NetAdr.h"
|
|
#include "tier1/strtools.h"
|
|
#include "mathlib/swap.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Constructors.
|
|
//////////////////////////////////////////////////////////////////////
|
|
CNetAdr::CNetAdr(void)
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Constructors.
|
|
//////////////////////////////////////////////////////////////////////
|
|
CNetAdr::CNetAdr(const char* pch)
|
|
{
|
|
SetFromString(pch);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Clears IP.
|
|
//////////////////////////////////////////////////////////////////////
|
|
void CNetAdr::Clear(void)
|
|
{
|
|
adr = { };
|
|
port = 0;
|
|
reliable = 0;
|
|
type = netadrtype_t::NA_NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Sets IP.
|
|
//////////////////////////////////////////////////////////////////////
|
|
void CNetAdr::SetIP(IN6_ADDR* inAdr)
|
|
{
|
|
adr = *inAdr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Sets the address type.
|
|
//////////////////////////////////////////////////////////////////////
|
|
void CNetAdr::SetType(netadrtype_t newtype)
|
|
{
|
|
type = newtype;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Returns the address type.
|
|
//////////////////////////////////////////////////////////////////////
|
|
netadrtype_t CNetAdr::GetType(void) const
|
|
{
|
|
return type;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Sets the port (must be network byte order, use 'htons' to flip).
|
|
//////////////////////////////////////////////////////////////////////
|
|
void CNetAdr::SetPort(uint16_t newport)
|
|
{
|
|
port = newport;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Returns the port in network byte order (use 'ntohs' to flip).
|
|
//////////////////////////////////////////////////////////////////////
|
|
uint16_t CNetAdr::GetPort(void) const
|
|
{
|
|
return port;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Compares two addresses.
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool CNetAdr::CompareAdr(const CNetAdr& other) const
|
|
{
|
|
if (type != other.type)
|
|
{
|
|
return false;
|
|
}
|
|
if (type == netadrtype_t::NA_LOOPBACK)
|
|
{
|
|
return true;
|
|
}
|
|
if (type == netadrtype_t::NA_IP)
|
|
{
|
|
return (CompareIPv6(adr, other.adr) == 0);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Compares two ports.
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool CNetAdr::ComparePort(const CNetAdr& other) const
|
|
{
|
|
return port == other.port;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Convert address to string.
|
|
//////////////////////////////////////////////////////////////////////
|
|
const char* CNetAdr::ToString(bool bOnlyBase) const
|
|
{
|
|
// Main thread only due to use of static buffers.
|
|
//Assert(ThreadInMainThread());
|
|
|
|
// Select a static buffer.
|
|
static char s[4][128];
|
|
static int slot = 0;
|
|
int useSlot = (slot++) % 4;
|
|
|
|
// Render into it.
|
|
ToString(s[useSlot], sizeof(s[0]), bOnlyBase);
|
|
|
|
// Pray the caller uses it before it gets clobbered.
|
|
return s[useSlot];
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Convert address to string.
|
|
//////////////////////////////////////////////////////////////////////
|
|
void CNetAdr::ToString(char* pchBuffer, size_t unBufferSize, bool bOnlyBase) const
|
|
{
|
|
if (type == netadrtype_t::NA_NULL)
|
|
{
|
|
strncpy(pchBuffer, "null", unBufferSize);
|
|
}
|
|
else if (type == netadrtype_t::NA_LOOPBACK)
|
|
{
|
|
strncpy(pchBuffer, "loopback", unBufferSize);
|
|
}
|
|
else if (type == netadrtype_t::NA_IP)
|
|
{
|
|
char pStringBuf[128];
|
|
inet_ntop(AF_INET6, &adr, pStringBuf, INET6_ADDRSTRLEN);
|
|
|
|
if (bOnlyBase)
|
|
{
|
|
snprintf(pchBuffer, unBufferSize, "%s", pStringBuf);
|
|
}
|
|
else
|
|
{
|
|
snprintf(pchBuffer, unBufferSize, "[%s]:%i", pStringBuf, ntohs(port));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memmove(pchBuffer, "unknown", unBufferSize);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
void CNetAdr::ToAdrinfo(addrinfo* pHint) const
|
|
{
|
|
addrinfo hint{};
|
|
hint.ai_flags = AI_PASSIVE;
|
|
hint.ai_family = AF_INET6;
|
|
hint.ai_socktype = SOCK_STREAM;
|
|
hint.ai_protocol = IPPROTO_TCP;
|
|
|
|
char szBuffer[33];
|
|
int results = getaddrinfo(ToString(true), _itoa(GetPort(), szBuffer, 10), &hint, &pHint);
|
|
|
|
if (results != 0)
|
|
{
|
|
WCHAR* wszError = gai_strerror(results);
|
|
_bstr_t bStr(wszError);
|
|
const char* pszError = bStr;
|
|
|
|
Warning(eDLL_T::ENGINE, "Address info translation failed: (%s)\n", pszError);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
void CNetAdr::ToSockadr(struct sockaddr_storage* pSadr) const
|
|
{
|
|
memset(pSadr, NULL, sizeof(struct sockaddr));
|
|
|
|
if (GetType() == netadrtype_t::NA_IP)
|
|
{
|
|
reinterpret_cast<sockaddr_in6*>(pSadr)->sin6_family = AF_INET6;
|
|
reinterpret_cast<sockaddr_in6*>(pSadr)->sin6_port = port;
|
|
inet_pton(AF_INET6, ToString(true), &reinterpret_cast<sockaddr_in6*>(pSadr)->sin6_addr);
|
|
}
|
|
else if (GetType() == netadrtype_t::NA_LOOPBACK)
|
|
{
|
|
reinterpret_cast<sockaddr_in6*>(pSadr)->sin6_family = AF_INET6;
|
|
reinterpret_cast<sockaddr_in6*>(pSadr)->sin6_port = port;
|
|
reinterpret_cast<sockaddr_in6*>(pSadr)->sin6_addr = in6addr_loopback;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool CNetAdr::SetFromSockadr(struct sockaddr_storage* s)
|
|
{
|
|
char szAdrv6[INET6_ADDRSTRLEN]{};
|
|
sockaddr_in6* pAdrv6 = reinterpret_cast<sockaddr_in6*>(s);
|
|
|
|
inet_ntop(pAdrv6->sin6_family, &pAdrv6->sin6_addr, szAdrv6, sizeof(sockaddr_in6)); // TODO: Error check?
|
|
|
|
SetFromString(szAdrv6);
|
|
SetPort(pAdrv6->sin6_port);
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Returns true if we use the loopback buffers.
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool CNetAdr::IsLoopback(void) const
|
|
{
|
|
return type == netadrtype_t::NA_LOOPBACK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool CNetAdr::SetFromString(const char* pch, bool bUseDNS)
|
|
{
|
|
Clear();
|
|
if (!pch)
|
|
{
|
|
Assert(pch, "Invalid call: 'szIpAdr' was nullptr.");
|
|
return false;
|
|
}
|
|
|
|
SetType(netadrtype_t::NA_IP);
|
|
|
|
char szAddress[128];
|
|
strncpy(szAddress, pch, sizeof(szAddress));
|
|
|
|
char* pszAddress = szAddress;
|
|
szAddress[sizeof(szAddress) - 1] = '\0';
|
|
|
|
if (szAddress[0] == '[') // Skip bracket.
|
|
{
|
|
pszAddress = &szAddress[1];
|
|
}
|
|
|
|
char* bracketEnd = strchr(szAddress, ']');
|
|
if (bracketEnd) // Get and remove the last bracket.
|
|
{
|
|
*bracketEnd = '\0';
|
|
|
|
char* portStart = &bracketEnd[1];
|
|
char* pchColon = strrchr(portStart, ':');
|
|
|
|
if (pchColon && strchr(portStart, ':') == pchColon)
|
|
{
|
|
pchColon[0] = '\0'; // Set the port.
|
|
SetPort(uint16_t(htons(uint16_t(atoi(&pchColon[1])))));
|
|
}
|
|
}
|
|
|
|
if (!strchr(pszAddress, ':'))
|
|
{
|
|
char szNewAddressV4[128];
|
|
V_snprintf(szNewAddressV4, sizeof(szNewAddressV4), "::FFFF:%s", pszAddress);
|
|
|
|
if (inet_pton(AF_INET6, szNewAddressV4, &this->adr) > 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else // Address is formatted as IPv6.
|
|
{
|
|
if (inet_pton(AF_INET6, pszAddress, &this->adr) > 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (bUseDNS) // Perform DNS lookup instead.
|
|
{
|
|
ADDRINFOA pHints{};
|
|
PADDRINFOA ppResult = nullptr;
|
|
|
|
pHints.ai_family = AF_INET6;
|
|
pHints.ai_flags = AI_ALL | AI_V4MAPPED;
|
|
pHints.ai_socktype = NULL;
|
|
pHints.ai_addrlen = NULL;
|
|
pHints.ai_canonname = nullptr;
|
|
pHints.ai_addr = nullptr;
|
|
pHints.ai_next = nullptr;
|
|
|
|
if (getaddrinfo(pszAddress, nullptr, &pHints, &ppResult))
|
|
{
|
|
freeaddrinfo(ppResult);
|
|
return false;
|
|
}
|
|
|
|
SetIP(reinterpret_cast<IN6_ADDR*>(&ppResult->ai_addr->sa_data[6]));
|
|
freeaddrinfo(ppResult);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|