AuroraRuntime/Source/IO/Net/AuIPAddress.cpp

178 lines
4.2 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuIPAddress.hpp
Date: 2022-8-16
Author: Reece
***/
#include "Networking.hpp"
#include "AuIPAddress.hpp"
#if defined(AURORA_COMPILER_CLANG)
// warning: enumeration values 'kEnumCount' and 'kEnumInvalid' not handled in switch [-Wswitch
#pragma clang diagnostic ignored "-Wswitch"
// Yea, I don't give a shit.
#endif
namespace Aurora::IO::Net
{
IPAddress::IPAddress()
{
AuMemset(this, 0, sizeof(*this));
this->ip = EIPProtocol::eEnumInvalid;
}
#if defined(AURORA_PLATFORM_WIN32)
int inet_pton_2(int af, const char *src, void *dst)
{
sockaddr_storage sastor {};
int size = sizeof(sastor);
if (!pWSAStringToAddressA)
{
return 0;
}
if (pWSAStringToAddressA(AuString(src).data(),
af,
NULL,
(struct sockaddr *)&sastor,
&size))
{
return 0;
}
switch (af)
{
case AF_INET:
{
*(in_addr *)dst = ((sockaddr_in *)&sastor)->sin_addr;
return 1;
}
#if defined(AF_INET6)
case AF_INET6:
{
*(in6_addr *)dst = ((sockaddr_in6 *)&sastor)->sin6_addr;
return 1;
}
#endif
}
return 0;
}
#else
int inet_pton_2(int af, const char *src, void *dst)
{
return ::inet_pton(af, src, dst);
}
#endif
IPAddress::IPAddress(const AuString &parse)
{
char buf[64];
static_assert(AuArraySize(buf) >= sizeof(struct in6_addr));
static_assert(AuArraySize(buf) >= sizeof(struct in_addr));
this->ip = EIPProtocol::eEnumInvalid;
bool isIPV4 {};
if (parse.size() > 4)
{
isIPV4 = parse[1] == '.' || parse[2] == '.' || parse[3] == '.';
}
if (inet_pton_2(isIPV4 ? AF_INET : AF_INET6,
parse.c_str(),
buf) != 1)
{
return;
}
UpdateFromName(!isIPV4, buf);
}
AuString IPAddress::ToString() const
{
switch (this->ip)
{
case EIPProtocol::eIPProtocolV4:
return fmt::format("{}.{}.{}.{}", this->v4[0], this->v4[1], this->v4[2], this->v4[3]);
case EIPProtocol::eIPProtocolV6:
return fmt::format("{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}", this->v6[0], this->v6[1], this->v6[2], this->v6[3], this->v6[4], this->v6[5], this->v6[6], this->v6[7]);
}
return {};
}
void IPAddress::UpdateFromName(bool bIPv6, const char *buf)
{
if (!bIPv6)
{
AuWriteU32LE(this->v4, 0, AuReadU32LE(buf, 0));
this->ip = EIPProtocol::eIPProtocolV4;
}
else
{
auto ipv6 = reinterpret_cast<const AuUInt16 *>(buf);
for (int i = 0; i < AuArraySize(this->v6); i++)
{
AuWriteU16BE(this->v6, i * sizeof(*this->v6), ipv6[i]);// AuArraySize(this->v6) - 1 - i]);
}
this->ip = EIPProtocol::eIPProtocolV6;
}
}
bool IPAddress::IsValid() const
{
return EIPProtocolIsValid(this->ip);
}
IPAddress::operator bool() const
{
return IsValid();
}
bool IPAddress::operator==(const IPAddress &cmp) const
{
if (cmp.ip != this->ip)
{
return false;
}
switch (this->ip)
{
case EIPProtocol::eIPProtocolV4:
{
return AuMemcmp(cmp.v4, this->v4, sizeof(this->v4)) == 0;
}
case EIPProtocol::eIPProtocolV6:
{
return AuMemcmp(cmp.v6, this->v6, sizeof(this->v6)) == 0;
}
case EIPProtocol::kEnumInvalid:
{
return true;
}
}
return false;
}
AuUInt IPToDomain(EIPProtocol protocol)
{
switch (protocol)
{
case EIPProtocol::eIPProtocolV4:
{
return AF_INET;
}
case EIPProtocol::eIPProtocolV6:
{
return AF_INET6;
}
}
return 0;
}
}