From 367b84bc65c02447827b4b58b0e485b2889b449d Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Sun, 1 Oct 2023 20:30:11 +0200 Subject: [PATCH] Move C4NetIO::HostAddress and C4NetIO::EndpointAddress to C4Network2Address and rename them to C4Network2HostAddress and C4Network2EndpointAddress This removes the dependency on C4NetIO.h and other headers like C4Client.h just to resolve an address. --- src/C4NetIO.cpp | 478 ++---------------------------------- src/C4NetIO.h | 160 +----------- src/C4Network2.cpp | 12 +- src/C4Network2.h | 4 +- src/C4Network2Address.cpp | 456 +++++++++++++++++++++++++++++++++- src/C4Network2Address.h | 185 +++++++++++++- src/C4Network2Client.cpp | 2 +- src/C4Network2IO.cpp | 10 +- src/C4Network2IO.h | 9 +- src/C4Network2Reference.cpp | 6 +- src/C4Network2Reference.h | 6 +- src/C4PuncherPacket.cpp | 1 + 12 files changed, 674 insertions(+), 655 deletions(-) diff --git a/src/C4NetIO.cpp b/src/C4NetIO.cpp index ddebac1ca..0335802b8 100644 --- a/src/C4NetIO.cpp +++ b/src/C4NetIO.cpp @@ -77,26 +77,6 @@ const int C4NetIO::TO_INF = -1; // simulate packet loss (loss probability in percent) // #define C4NETIO_SIMULATE_PACKETLOSS 10 -namespace -{ - class AddrInfo - { - public: - AddrInfo(const char *const node, const char *const service, - const struct addrinfo *const hints) - { - if (::getaddrinfo(node, service, hints, &addrs) != 0) addrs = nullptr; - } - - ~AddrInfo() { if (addrs) ::freeaddrinfo(addrs); } - explicit operator bool() const { return addrs != nullptr; } - addrinfo *GetAddrs() const { return addrs; } - - private: - addrinfo *addrs; - }; -} - // *** helpers #ifdef _WIN32 @@ -247,445 +227,15 @@ void ResetSocketError() #endif -// *** C4NetIO::HostAddress -void C4NetIO::HostAddress::Clear() -{ - v6.sin6_family = AF_INET6; - v6.sin6_flowinfo = 0; - v6.sin6_scope_id = 0; - v6.sin6_addr = {}; -} - -// *** C4NetIO::EndpointAddress -const C4NetIO::EndpointAddress::EndpointAddressPtr C4NetIO::EndpointAddress::operator&() const { return EndpointAddressPtr{const_cast(this)}; } -C4NetIO::EndpointAddress::EndpointAddressPtr C4NetIO::EndpointAddress::operator&() { return EndpointAddressPtr{this}; } - -void C4NetIO::EndpointAddress::Clear() -{ - HostAddress::Clear(); - SetPort(IPPORT_NONE); -} - -void C4NetIO::HostAddress::SetHost(const HostAddress &other) -{ - SetHost(&other.gen); -} - -bool C4NetIO::HostAddress::IsMulticast() const -{ - if (gen.sa_family == AF_INET6) - return IN6_IS_ADDR_MULTICAST(&v6.sin6_addr) != 0; - if (gen.sa_family == AF_INET) - return (ntohl(v4.sin_addr.s_addr) >> 24) == 239; - return false; -} - -bool C4NetIO::HostAddress::IsLoopback() const -{ - if (gen.sa_family == AF_INET6) - return IN6_IS_ADDR_LOOPBACK(&v6.sin6_addr) != 0; - if (gen.sa_family == AF_INET) - return (ntohl(v4.sin_addr.s_addr) >> 24) == 127; - return false; -} - -bool C4NetIO::HostAddress::IsLocal() const -{ - if (gen.sa_family == AF_INET6) - return IN6_IS_ADDR_LINKLOCAL(&v6.sin6_addr) != 0; - if (gen.sa_family == AF_INET) - { - const std::uint32_t addr{ntohl(v4.sin_addr.s_addr)}; - return addr >> 24 == 169 && ((addr >> 16) & 0xff) == 254; - } - return false; -} - -bool C4NetIO::HostAddress::IsPrivate() const -{ - // IPv6 unique local address - if (gen.sa_family == AF_INET6) - return (v6.sin6_addr.s6_addr[0] & 0xfe) == 0xfc; - if (gen.sa_family == AF_INET) - { - const std::uint32_t addr{ntohl(v4.sin_addr.s_addr)}; - const std::uint32_t s{(addr >> 16) & 0xff}; - switch (addr >> 24) - { - case 10: return true; - case 172: return s >= 16 && s <= 31; - case 192: return s == 168; - } - } - return false; -} - -void C4NetIO::HostAddress::SetScopeId(const int scopeId) -{ - if (gen.sa_family != AF_INET6) return; - if (IN6_IS_ADDR_LINKLOCAL(&v6.sin6_addr) != 0) - v6.sin6_scope_id = scopeId; -} - -int C4NetIO::HostAddress::GetScopeId() const -{ - if (gen.sa_family == AF_INET6) - return v6.sin6_scope_id; - return 0; -} - -C4NetIO::HostAddress C4NetIO::HostAddress::AsIPv6() const -{ - static constexpr unsigned char v6_mapped_v4_prefix[12]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; - - HostAddress nrv{*this}; - switch (gen.sa_family) - { - case AF_INET6: - // That was easy - break; - case AF_INET: - nrv.v6.sin6_family = AF_INET6; - std::memcpy(&nrv.v6.sin6_addr.s6_addr[0], v6_mapped_v4_prefix, sizeof(v6_mapped_v4_prefix)); - std::memcpy(&nrv.v6.sin6_addr.s6_addr[sizeof(v6_mapped_v4_prefix)], &v4.sin_addr, sizeof(v4.sin_addr)); - nrv.v6.sin6_flowinfo = 0; - nrv.v6.sin6_scope_id = 0; - break; - default: - assert(!"Shouldn't reach this"); - break; - } - return nrv; -} - -bool C4NetIO::HostAddress::IsIPv6MappedIPv4() const -{ - return gen.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&v6.sin6_addr); -} - -C4NetIO::HostAddress C4NetIO::HostAddress::AsIPv4() const -{ - HostAddress nrv{*this}; - if (IsIPv6MappedIPv4()) - { - nrv.v4.sin_family = AF_INET; - std::memcpy(&nrv.v4.sin_addr, &v6.sin6_addr.s6_addr[12], sizeof(v4.sin_addr)); - } - return nrv; -} - -C4NetIO::EndpointAddress C4NetIO::EndpointAddress::AsIPv6() const -{ - return {HostAddress::AsIPv6(), GetPort()}; -} - -C4NetIO::EndpointAddress C4NetIO::EndpointAddress::AsIPv4() const -{ - return {HostAddress::AsIPv4(), GetPort()}; -} - -void C4NetIO::HostAddress::SetHost(const sockaddr *const addr) -{ - // Copy all but port number - if (addr->sa_family == AF_INET6) - { - const auto addr6 = reinterpret_cast(addr); - v6.sin6_family = addr6->sin6_family; - v6.sin6_flowinfo = addr6->sin6_flowinfo; - v6.sin6_addr = addr6->sin6_addr; - v6.sin6_scope_id = addr6->sin6_scope_id; - } - else if (addr->sa_family == AF_INET) - { - const auto addr4 = reinterpret_cast(addr); - v4.sin_family = addr4->sin_family; - v4.sin_addr.s_addr = addr4->sin_addr.s_addr; - std::memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); - } -} - -void C4NetIO::EndpointAddress::SetAddress(const sockaddr *const addr) -{ - switch (addr->sa_family) - { - case AF_INET: std::memcpy(&v4, addr, sizeof(v4)); break; - case AF_INET6: std::memcpy(&v6, addr, sizeof(v6)); break; - default: - assert(!"Unexpected address family"); - std::memcpy(&gen, addr, sizeof(gen)); - break; - } -} - -void C4NetIO::HostAddress::SetHost(const SpecialAddress addr) -{ - switch (addr) - { - case Any: - v6.sin6_family = AF_INET6; - std::memset(&v6.sin6_addr, 0, sizeof(v6.sin6_addr)); - v6.sin6_flowinfo = 0; - v6.sin6_scope_id = 0; - break; - case AnyIPv4: - v4.sin_family = AF_INET; - v4.sin_addr.s_addr = 0; - std::memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); - break; - case Loopback: - v6.sin6_family = AF_INET6; - std::memset(&v6.sin6_addr, 0, sizeof(v6.sin6_addr)); - v6.sin6_addr.s6_addr[15] = 1; - v6.sin6_flowinfo = 0; - v6.sin6_scope_id = 0; - break; - } -} - -void C4NetIO::HostAddress::SetHost(const std::uint32_t v4addr) -{ - v4.sin_family = AF_INET; - v4.sin_addr.s_addr = v4addr; - std::memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); -} - -void C4NetIO::HostAddress::SetHost(const StdStrBuf &addr, const AddressFamily family) -{ - addrinfo hints{}; - hints.ai_family = family; - - if (const AddrInfo ai{addr.getData(), nullptr, &hints}) - { - SetHost(ai.GetAddrs()->ai_addr); - } -} -void C4NetIO::EndpointAddress::SetAddress(const StdStrBuf &addr, const AddressFamily family) -{ - Clear(); - - if (addr.isNull()) return; - - const auto begin = addr.getData(); - const auto end = begin + addr.getLength(); - - auto ab = begin; - auto ae = end; - - auto pb = end; - const auto pe = end; - - bool isIPv6{false}; - - // If addr begins with [, it's an IPv6 address - if (ab[0] == '[') - { - ++ab; // Skip bracket - auto cbracket = std::find(ab, ae, ']'); - if (cbracket == ae) - // No closing bracket found: invalid - return; - ae = cbracket++; - if (cbracket != end && cbracket[0] == ':') - { - // Port number given - pb = ++cbracket; - if (pb == end) - // Trailing colon: invalid - return; - } - isIPv6 = true; - } - // If there's more than 1 colon in the address, it's IPv6 - else if (std::count(ab, ae, ':') > 1) - { - isIPv6 = true; - } - // It's probably not IPv6, but look for a port specification - else - { - const auto colon = std::find(ab, ae, ':'); - if (colon != ae) - { - ae = colon; - pb = colon + 1; - if (pb == end) - // Trailing colon: invalid - return; - } - } - - addrinfo hints{}; - hints.ai_family = family; - if (const AddrInfo ai{std::string{ab, ae}.c_str(), - (pb != end ? std::string{pb, pe}.c_str() : nullptr), &hints}) - { - SetAddress(ai.GetAddrs()->ai_addr); - } -} - -void C4NetIO::EndpointAddress::SetAddress(const EndpointAddress &addr) -{ - SetHost(addr); - SetPort(addr.GetPort()); -} - -void C4NetIO::EndpointAddress::SetAddress( - const HostAddress::SpecialAddress host, const std::uint16_t port) -{ - SetHost(host); - SetPort(port); -} - -void C4NetIO::EndpointAddress::SetAddress(const HostAddress &host, const std::uint16_t port) -{ - SetHost(host); - SetPort(port); -} - -bool C4NetIO::EndpointAddress::IsNull() const -{ - return IsNullHost() && GetPort() == IPPORT_NONE; -} - -bool C4NetIO::HostAddress::IsNull() const -{ - switch (gen.sa_family) - { - case AF_INET: return v4.sin_addr.s_addr == 0; - case AF_INET6: return IN6_IS_ADDR_UNSPECIFIED(&v6.sin6_addr); - } - assert(!"Shouldn't reach this"); - return false; -} - -C4NetIO::HostAddress::AddressFamily C4NetIO::HostAddress::GetFamily() const -{ - return - gen.sa_family == AF_INET ? IPv4 : - gen.sa_family == AF_INET6 ? IPv6 : - UnknownFamily; -} - -std::size_t C4NetIO::HostAddress::GetAddrLen() const -{ - return GetFamily() == IPv4 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); -} - -void C4NetIO::EndpointAddress::SetPort(const std::uint16_t port) -{ - switch (gen.sa_family) - { - case AF_INET: v4.sin_port = htons(port); break; - case AF_INET6: v6.sin6_port = htons(port); break; - default: assert(!"Shouldn't reach this"); break; - } -} - -void C4NetIO::EndpointAddress::SetDefaultPort(const std::uint16_t port) -{ - if (GetPort() == IPPORT_NONE) - SetPort(port); -} - -std::uint16_t C4NetIO::EndpointAddress::GetPort() const -{ - switch (gen.sa_family) - { - case AF_INET: return ntohs(v4.sin_port); - case AF_INET6: return ntohs(v6.sin6_port); - } - assert(!"Shouldn't reach this"); - return IPPORT_NONE; -} - -bool C4NetIO::HostAddress::operator==(const HostAddress &rhs) const -{ - // Check for IPv4-mapped IPv6 addresses. - if (gen.sa_family != rhs.gen.sa_family) - return AsIPv6() == rhs.AsIPv6(); - if (gen.sa_family == AF_INET) - return v4.sin_addr.s_addr == rhs.v4.sin_addr.s_addr; - if (gen.sa_family == AF_INET6) - return std::memcmp(&v6.sin6_addr, &rhs.v6.sin6_addr, sizeof(v6.sin6_addr)) == 0 && - v6.sin6_scope_id == rhs.v6.sin6_scope_id; - assert(!"Shouldn't reach this"); - return false; -} - -bool C4NetIO::EndpointAddress::operator==(const addr_t &rhs) const -{ - if (!HostAddress::operator==(rhs)) return false; - if (gen.sa_family == AF_INET) - { - return v4.sin_port == rhs.v4.sin_port; - } - else if (gen.sa_family == AF_INET6) - { - return v6.sin6_port == rhs.v6.sin6_port && - v6.sin6_scope_id == rhs.v6.sin6_scope_id; - } - assert(!"Shouldn't reach this"); - return false; -} - -StdStrBuf C4NetIO::HostAddress::ToString(const int flags) const -{ - if (IsIPv6MappedIPv4()) return AsIPv4().ToString(flags); - - if (gen.sa_family == AF_INET6 && v6.sin6_scope_id != 0 && (flags & TSF_SkipZoneId)) - { - auto addr = *this; - addr.v6.sin6_scope_id = 0; - return addr.ToString(flags); - } - - char buf[INET6_ADDRSTRLEN]; - if (::getnameinfo(&gen, GetAddrLen(), buf, sizeof(buf), nullptr, 0, NI_NUMERICHOST) != 0) - return {}; - - return StdStrBuf{buf, true}; -} - -StdStrBuf C4NetIO::EndpointAddress::ToString(const int flags) const -{ - if (IsIPv6MappedIPv4()) return AsIPv4().ToString(flags); - - if (flags & TSF_SkipPort) - return HostAddress::ToString(flags); - - switch (GetFamily()) - { - case IPv4: return FormatString("%s:%d", HostAddress::ToString(flags).getData(), GetPort()); - case IPv6: return FormatString("[%s]:%d", HostAddress::ToString(flags).getData(), GetPort()); - case UnknownFamily: ; // fallthrough - } - assert(!"Shouldn't reach this"); - return {}; -} - -void C4NetIO::EndpointAddress::CompileFunc(StdCompiler *const comp) -{ - if (!comp->isCompiler()) - { - StdStrBuf val{ToString(TSF_SkipZoneId)}; - comp->Value(val); - } - else - { - StdStrBuf val; - comp->Value(val); - SetAddress(val); - } -} namespace { - bool ContainsGlobalIpv6(const std::vector &addresses) + bool ContainsGlobalIpv6(const std::vector &addresses) { return std::any_of(addresses.cbegin(), addresses.cend(), [](const auto &addr) { - return addr.GetFamily() == C4NetIO::HostAddress::IPv6 + return addr.GetFamily() == C4Network2HostAddress::IPv6 && !addr.IsLocal() && !addr.IsPrivate(); }); @@ -709,11 +259,11 @@ namespace { switch (addr.GetFamily()) { - case C4NetIO::HostAddress::IPv6: + case C4Network2HostAddress::IPv6: return haveIPv6 ? 300 : 0; - case C4NetIO::HostAddress::IPv4: + case C4Network2HostAddress::IPv4: return 200; - case C4NetIO::HostAddress::UnknownFamily: + case C4Network2HostAddress::UnknownFamily: ; // fallthrough } @@ -727,9 +277,9 @@ namespace } } -std::vector C4NetIO::GetLocalAddresses(bool unsorted) +std::vector C4NetIO::GetLocalAddresses(bool unsorted) { - std::vector result; + std::vector result; #ifdef _WIN32 std::vector addresses{32}; @@ -752,7 +302,7 @@ std::vector C4NetIO::GetLocalAddresses(bool unsorted) { for (const auto *unicast = address->FirstUnicastAddress; unicast; unicast = unicast->Next) { - const HostAddress addr{unicast->Address.lpSockaddr}; + const C4Network2HostAddress addr{unicast->Address.lpSockaddr}; if (!addr.IsLoopback()) result.push_back(addr); } } @@ -1253,7 +803,7 @@ C4NetIO::addr_t C4NetIOTCP::Socket::GetAddress() const SOCKET C4NetIOTCP::CreateSocket(const addr_t::AddressFamily family) { // create new socket - const auto &nsock = ::socket((family == HostAddress::IPv6 ? AF_INET6 : AF_INET), + const auto &nsock = ::socket((family == C4Network2HostAddress::IPv6 ? AF_INET6 : AF_INET), SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP); if (nsock == INVALID_SOCKET) { @@ -1261,7 +811,7 @@ SOCKET C4NetIOTCP::CreateSocket(const addr_t::AddressFamily family) return INVALID_SOCKET; } - if (family == HostAddress::IPv6 && !InitIPv6Socket(nsock)) + if (family == C4Network2HostAddress::IPv6 && !InitIPv6Socket(nsock)) { ::closesocket(nsock); return INVALID_SOCKET; @@ -2055,7 +1605,7 @@ bool C4NetIOSimpleUDP::InitBroadcast(addr_t *pBroadcastAddr) if (fMultiCast) CloseBroadcast(); // broadcast addr valid? - if (!pBroadcastAddr->IsMulticast() || pBroadcastAddr->GetFamily() != HostAddress::IPv6) + if (!pBroadcastAddr->IsMulticast() || pBroadcastAddr->GetFamily() != C4Network2HostAddress::IPv6) { SetError("invalid broadcast address (only IPv6 multicast addresses are supported)"); return false; @@ -2394,7 +1944,7 @@ struct C4NetIOUDP::BinAddr { switch (addr.GetFamily()) { - case C4NetIO::HostAddress::IPv4: + case C4Network2HostAddress::IPv4: { type = 1; const auto addr4 = static_cast(&addr); @@ -2402,7 +1952,7 @@ struct C4NetIOUDP::BinAddr std::memcpy(&v4, &addr4->sin_addr, sizeof(v4)); break; } - case C4NetIO::HostAddress::IPv6: + case C4Network2HostAddress::IPv6: { type = 2; const auto addr6 = static_cast(&addr); @@ -2594,7 +2144,7 @@ bool C4NetIOUDP::InitBroadcast(addr_t *pBroadcastAddr) addr_t prefixAddr; for (const auto &addr : GetLocalAddresses()) { - if (addr.GetFamily() == HostAddress::IPv6 && !addr.IsLocal()) + if (addr.GetFamily() == C4Network2HostAddress::IPv6 && !addr.IsLocal()) { prefixAddr.SetAddress(addr); break; diff --git a/src/C4NetIO.h b/src/C4NetIO.h index c24cab56e..cee42f076 100644 --- a/src/C4NetIO.h +++ b/src/C4NetIO.h @@ -19,6 +19,7 @@ #pragma once +#include "C4Network2Address.h" #include "Standard.h" #include "StdSync.h" #include "StdBuf.h" @@ -28,19 +29,6 @@ #include #include -#ifdef _WIN32 - #include - #include -#else - #define SOCKET int - #define INVALID_SOCKET (-1) - #include - #include -#endif - -#ifndef SOCK_CLOEXEC -#define SOCK_CLOEXEC 0 -#endif #include @@ -56,151 +44,9 @@ class C4NetIO : public StdSchedulerProc // *** constants / types static const int TO_INF; // = -1; - struct HostAddress - { - enum AddressFamily - { - IPv6 = AF_INET6, - IPv4 = AF_INET, - UnknownFamily = 0 - }; - enum SpecialAddress - { - Loopback, // IPv6 localhost (::1) - Any, // IPv6 any-address (::) - AnyIPv4 // IPv4 any-address (0.0.0.0) - }; - - enum ToStringFlags - { - TSF_SkipZoneId = 1, - TSF_SkipPort = 2 - }; - - HostAddress() { Clear(); } - HostAddress(const HostAddress &other) { SetHost(other); } - HostAddress(const SpecialAddress addr) { SetHost(addr); } - explicit HostAddress(const std::uint32_t addr) { SetHost(addr); } - HostAddress(const StdStrBuf &addr) { SetHost(addr); } - HostAddress(const sockaddr *const addr) { SetHost(addr); } - - AddressFamily GetFamily() const; - std::size_t GetAddrLen() const; - - void SetScopeId(int scopeId); - int GetScopeId() const; - - void Clear(); - void SetHost(const sockaddr *addr); - void SetHost(const HostAddress &host); - void SetHost(SpecialAddress host); - void SetHost(const StdStrBuf &host, AddressFamily family = UnknownFamily); - void SetHost(std::uint32_t host); - - C4NetIO::HostAddress AsIPv6() const; // Convert an IPv4 address to an IPv6-mapped IPv4 address - bool IsIPv6MappedIPv4() const; - C4NetIO::HostAddress AsIPv4() const; // Try to convert an IPv6-mapped IPv4 address to an IPv4 address (returns unchanged address if not possible) - - // General categories - bool IsNull() const; - bool IsMulticast() const; - bool IsLoopback() const; - bool IsLocal() const; // IPv6 link-local address - bool IsPrivate() const; // IPv6 ULA or IPv4 private address range - - StdStrBuf ToString(int flags = 0) const; - - bool operator ==(const HostAddress &rhs) const; - - protected: - // Data - union - { - sockaddr gen; - sockaddr_in v4; - sockaddr_in6 v6; - }; - }; - - struct EndpointAddress : public HostAddress // Host and port - { - static constexpr std::uint16_t IPPORT_NONE{0}; - - EndpointAddress() { Clear(); } - EndpointAddress(const EndpointAddress &other) : HostAddress{} { SetAddress(other); } - EndpointAddress(const HostAddress &host, const std::uint16_t port = IPPORT_NONE) : HostAddress{host} { SetPort(port); } - EndpointAddress(const HostAddress::SpecialAddress addr, const std::uint16_t port = IPPORT_NONE) : HostAddress{addr} { SetPort(port); } - explicit EndpointAddress(const StdStrBuf &addr) { SetAddress(addr); } - - StdStrBuf ToString(int flags = 0) const; - - void Clear(); - - void SetAddress(const sockaddr *addr); - void SetAddress(const EndpointAddress &other); - void SetAddress(HostAddress::SpecialAddress addr, std::uint16_t port = IPPORT_NONE); - void SetAddress(const HostAddress &host, std::uint16_t port = IPPORT_NONE); - void SetAddress(const StdStrBuf &addr, AddressFamily family = UnknownFamily); - - HostAddress GetHost() const { return *this; } // HostAddress copy ctor slices off port information - EndpointAddress AsIPv6() const; // Convert an IPv4 address to an IPv6-mapped IPv4 address - EndpointAddress AsIPv4() const; // Try to convert an IPv6-mapped IPv4 address to an IPv4 address (returns unchanged address if not possible) - - void SetPort(std::uint16_t port); - void SetDefaultPort(std::uint16_t port); // Set a port only if there is none - std::uint16_t GetPort() const; - - bool IsNull() const; - bool IsNullHost() const { return HostAddress::IsNull(); } - - // Pointer wrapper to be able to implicitly convert to sockaddr* - class EndpointAddressPtr; - const EndpointAddressPtr operator&() const; - EndpointAddressPtr operator&(); - - class EndpointAddressPtr - { - EndpointAddress *const p; - friend EndpointAddressPtr EndpointAddress::operator&(); - friend const EndpointAddressPtr EndpointAddress::operator&() const; - EndpointAddressPtr(EndpointAddress *const p) : p(p) {} - - public: - const EndpointAddress &operator*() const { return *p; } - EndpointAddress &operator*() { return *p; } - - const EndpointAddress &operator->() const { return *p; } - EndpointAddress &operator->() { return *p; } - - operator const EndpointAddress *() const { return p; } - operator EndpointAddress *() { return p; } - - operator const sockaddr *() const { return &p->gen; } - operator sockaddr *() { return &p->gen; } - - operator const sockaddr_in *() const { return &p->v4; } - operator sockaddr_in *() { return &p->v4; } - - operator const sockaddr_in6 *() const { return &p->v6; } - operator sockaddr_in6 *() { return &p->v6; } - }; - - bool operator==(const EndpointAddress &rhs) const; - - // Conversions - operator sockaddr() const { return gen; } - operator sockaddr_in() const { assert(gen.sa_family == AF_INET); return v4; } - operator sockaddr_in6() const { assert(gen.sa_family == AF_INET6); return v6; } - - // StdCompiler - void CompileFunc(StdCompiler *comp); - - friend class EndpointAddressPtr; - }; - - using addr_t = EndpointAddress; + using addr_t = C4Network2EndpointAddress; - static std::vector GetLocalAddresses(bool unsorted = false); + static std::vector GetLocalAddresses(bool unsorted = false); static void SortAddresses(std::vector &addresses); // callback class diff --git a/src/C4Network2.cpp b/src/C4Network2.cpp index 5edf78c01..b84b26a62 100644 --- a/src/C4Network2.cpp +++ b/src/C4Network2.cpp @@ -995,7 +995,7 @@ void C4Network2::HandleLobbyPacket(char cStatus, const C4PacketBase *pBasePkt, C if (pLobby) pLobby->HandlePacket(cStatus, pBasePkt, pClient); } -bool C4Network2::HandlePuncherPacket(const C4NetpuncherPacket::uptr pkt, const C4NetIO::HostAddress::AddressFamily family) +bool C4Network2::HandlePuncherPacket(const C4NetpuncherPacket::uptr pkt, const C4Network2HostAddress::AddressFamily family) { // TODO: is this all thread-safe? assert(pkt); @@ -1032,13 +1032,13 @@ bool C4Network2::HandlePuncherPacket(const C4NetpuncherPacket::uptr pkt, const C #pragma pop_macro("GETPKT") } -C4NetpuncherID::value &C4Network2::getNetpuncherGameID(const C4NetIO::HostAddress::AddressFamily family) +C4NetpuncherID::value &C4Network2::getNetpuncherGameID(const C4Network2HostAddress::AddressFamily family) { switch (family) { - case C4NetIO::HostAddress::IPv4: return NetpuncherGameID.v4; - case C4NetIO::HostAddress::IPv6: return NetpuncherGameID.v6; - case C4NetIO::HostAddress::UnknownFamily: ; // fallthrough + case C4Network2HostAddress::IPv4: return NetpuncherGameID.v4; + case C4Network2HostAddress::IPv6: return NetpuncherGameID.v6; + case C4Network2HostAddress::UnknownFamily: ; // fallthrough } assert(!"Unexpected address family"); // We need to return a valid reference to satisfy the compiler, even though the code here is unreachable. @@ -1075,7 +1075,7 @@ void C4Network2::OnPuncherConnect(const C4NetIO::addr_t addr) void C4Network2::InitPuncher() { // We have an internet connection, so let's punch the puncher server here in order to open an udp port - for (const auto &family : { C4NetIO::HostAddress::IPv4, C4NetIO::HostAddress::IPv6 }) + for (const auto &family : { C4Network2HostAddress::IPv4, C4Network2HostAddress::IPv6 }) { C4NetIO::addr_t puncherAddr{}; puncherAddr.SetAddress(getNetpuncherAddr(), family); diff --git a/src/C4Network2.h b/src/C4Network2.h index a364eb746..9c5fe3648 100644 --- a/src/C4Network2.h +++ b/src/C4Network2.h @@ -302,7 +302,7 @@ class C4Network2 void OnDisconn(C4Network2IOConnection *pConn); void HandlePacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn); void HandleLobbyPacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn); - bool HandlePuncherPacket(C4NetpuncherPacket::uptr, C4NetIO::HostAddress::AddressFamily family); + bool HandlePuncherPacket(C4NetpuncherPacket::uptr, C4Network2HostAddress::AddressFamily family); void OnPuncherConnect(C4NetIO::addr_t addr); // runtime join stuff @@ -348,7 +348,7 @@ class C4Network2 bool StopStreaming(); // Netpuncher - C4NetpuncherID::value &getNetpuncherGameID(C4NetIO::HostAddress::AddressFamily family); + C4NetpuncherID::value &getNetpuncherGameID(C4Network2HostAddress::AddressFamily family); C4NetpuncherID getNetpuncherGameID() const { return NetpuncherGameID; } StdStrBuf getNetpuncherAddr() const { return NetpuncherAddr; } diff --git a/src/C4Network2Address.cpp b/src/C4Network2Address.cpp index dbd11237c..637c61667 100644 --- a/src/C4Network2Address.cpp +++ b/src/C4Network2Address.cpp @@ -24,6 +24,460 @@ #endif #include "C4Network2Address.h" +#include "StdAdaptors.h" +#include "StdCompiler.h" + +namespace +{ + class AddrInfo + { + public: + AddrInfo(const char *const node, const char *const service, + const struct addrinfo *const hints) + { + if (::getaddrinfo(node, service, hints, &addrs) != 0) addrs = nullptr; + } + + ~AddrInfo() { if (addrs) ::freeaddrinfo(addrs); } + explicit operator bool() const { return addrs != nullptr; } + addrinfo *GetAddrs() const { return addrs; } + + private: + addrinfo *addrs; + }; +} + +// *** C4Network2HostAddress +void C4Network2HostAddress::Clear() +{ + v6.sin6_family = AF_INET6; + v6.sin6_flowinfo = 0; + v6.sin6_scope_id = 0; + v6.sin6_addr = {}; +} + +// *** C4Network2EndpointAddress +const C4Network2EndpointAddress::EndpointAddressPtr C4Network2EndpointAddress::operator&() const { return EndpointAddressPtr{const_cast(this)}; } +C4Network2EndpointAddress::EndpointAddressPtr C4Network2EndpointAddress::operator&() { return EndpointAddressPtr{this}; } + +void C4Network2EndpointAddress::Clear() +{ + C4Network2HostAddress::Clear(); + SetPort(IPPORT_NONE); +} + +void C4Network2HostAddress::SetHost(const C4Network2HostAddress &other) +{ + SetHost(&other.gen); +} + +bool C4Network2HostAddress::IsMulticast() const +{ + if (gen.sa_family == AF_INET6) + return IN6_IS_ADDR_MULTICAST(&v6.sin6_addr) != 0; + if (gen.sa_family == AF_INET) + return (ntohl(v4.sin_addr.s_addr) >> 24) == 239; + return false; +} + +bool C4Network2HostAddress::IsLoopback() const +{ + if (gen.sa_family == AF_INET6) + return IN6_IS_ADDR_LOOPBACK(&v6.sin6_addr) != 0; + if (gen.sa_family == AF_INET) + return (ntohl(v4.sin_addr.s_addr) >> 24) == 127; + return false; +} + +bool C4Network2HostAddress::IsLocal() const +{ + if (gen.sa_family == AF_INET6) + return IN6_IS_ADDR_LINKLOCAL(&v6.sin6_addr) != 0; + if (gen.sa_family == AF_INET) + { + const std::uint32_t addr{ntohl(v4.sin_addr.s_addr)}; + return addr >> 24 == 169 && ((addr >> 16) & 0xff) == 254; + } + return false; +} + +bool C4Network2HostAddress::IsPrivate() const +{ + // IPv6 unique local address + if (gen.sa_family == AF_INET6) + return (v6.sin6_addr.s6_addr[0] & 0xfe) == 0xfc; + if (gen.sa_family == AF_INET) + { + const std::uint32_t addr{ntohl(v4.sin_addr.s_addr)}; + const std::uint32_t s{(addr >> 16) & 0xff}; + switch (addr >> 24) + { + case 10: return true; + case 172: return s >= 16 && s <= 31; + case 192: return s == 168; + } + } + return false; +} + +void C4Network2HostAddress::SetScopeId(const int scopeId) +{ + if (gen.sa_family != AF_INET6) return; + if (IN6_IS_ADDR_LINKLOCAL(&v6.sin6_addr) != 0) + v6.sin6_scope_id = scopeId; +} + +int C4Network2HostAddress::GetScopeId() const +{ + if (gen.sa_family == AF_INET6) + return v6.sin6_scope_id; + return 0; +} + +C4Network2HostAddress C4Network2HostAddress::AsIPv6() const +{ + static constexpr unsigned char v6_mapped_v4_prefix[12]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; + + C4Network2HostAddress nrv{*this}; + switch (gen.sa_family) + { + case AF_INET6: + // That was easy + break; + case AF_INET: + nrv.v6.sin6_family = AF_INET6; + std::memcpy(&nrv.v6.sin6_addr.s6_addr[0], v6_mapped_v4_prefix, sizeof(v6_mapped_v4_prefix)); + std::memcpy(&nrv.v6.sin6_addr.s6_addr[sizeof(v6_mapped_v4_prefix)], &v4.sin_addr, sizeof(v4.sin_addr)); + nrv.v6.sin6_flowinfo = 0; + nrv.v6.sin6_scope_id = 0; + break; + default: + assert(!"Shouldn't reach this"); + break; + } + return nrv; +} + +bool C4Network2HostAddress::IsIPv6MappedIPv4() const +{ + return gen.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&v6.sin6_addr); +} + +C4Network2HostAddress C4Network2HostAddress::AsIPv4() const +{ + C4Network2HostAddress nrv{*this}; + if (IsIPv6MappedIPv4()) + { + nrv.v4.sin_family = AF_INET; + std::memcpy(&nrv.v4.sin_addr, &v6.sin6_addr.s6_addr[12], sizeof(v4.sin_addr)); + } + return nrv; +} + +C4Network2EndpointAddress C4Network2EndpointAddress::AsIPv6() const +{ + return {C4Network2HostAddress::AsIPv6(), GetPort()}; +} + +C4Network2EndpointAddress C4Network2EndpointAddress::AsIPv4() const +{ + return {C4Network2HostAddress::AsIPv4(), GetPort()}; +} + +void C4Network2HostAddress::SetHost(const sockaddr *const addr) +{ + // Copy all but port number + if (addr->sa_family == AF_INET6) + { + const auto addr6 = reinterpret_cast(addr); + v6.sin6_family = addr6->sin6_family; + v6.sin6_flowinfo = addr6->sin6_flowinfo; + v6.sin6_addr = addr6->sin6_addr; + v6.sin6_scope_id = addr6->sin6_scope_id; + } + else if (addr->sa_family == AF_INET) + { + const auto addr4 = reinterpret_cast(addr); + v4.sin_family = addr4->sin_family; + v4.sin_addr.s_addr = addr4->sin_addr.s_addr; + std::memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); + } +} + +void C4Network2EndpointAddress::SetAddress(const sockaddr *const addr) +{ + switch (addr->sa_family) + { + case AF_INET: std::memcpy(&v4, addr, sizeof(v4)); break; + case AF_INET6: std::memcpy(&v6, addr, sizeof(v6)); break; + default: + assert(!"Unexpected address family"); + std::memcpy(&gen, addr, sizeof(gen)); + break; + } +} + +void C4Network2HostAddress::SetHost(const SpecialAddress addr) +{ + switch (addr) + { + case Any: + v6.sin6_family = AF_INET6; + std::memset(&v6.sin6_addr, 0, sizeof(v6.sin6_addr)); + v6.sin6_flowinfo = 0; + v6.sin6_scope_id = 0; + break; + case AnyIPv4: + v4.sin_family = AF_INET; + v4.sin_addr.s_addr = 0; + std::memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); + break; + case Loopback: + v6.sin6_family = AF_INET6; + std::memset(&v6.sin6_addr, 0, sizeof(v6.sin6_addr)); + v6.sin6_addr.s6_addr[15] = 1; + v6.sin6_flowinfo = 0; + v6.sin6_scope_id = 0; + break; + } +} + +void C4Network2HostAddress::SetHost(const std::uint32_t v4addr) +{ + v4.sin_family = AF_INET; + v4.sin_addr.s_addr = v4addr; + std::memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); +} + +void C4Network2HostAddress::SetHost(const StdStrBuf &addr, const AddressFamily family) +{ + addrinfo hints{}; + hints.ai_family = family; + + if (const AddrInfo ai{addr.getData(), nullptr, &hints}) + { + SetHost(ai.GetAddrs()->ai_addr); + } +} + +void C4Network2EndpointAddress::SetAddress(const StdStrBuf &addr, const AddressFamily family) +{ + Clear(); + + if (addr.isNull()) return; + + const auto begin = addr.getData(); + const auto end = begin + addr.getLength(); + + auto ab = begin; + auto ae = end; + + auto pb = end; + const auto pe = end; + + bool isIPv6{false}; + + // If addr begins with [, it's an IPv6 address + if (ab[0] == '[') + { + ++ab; // Skip bracket + auto cbracket = std::find(ab, ae, ']'); + if (cbracket == ae) + // No closing bracket found: invalid + return; + ae = cbracket++; + if (cbracket != end && cbracket[0] == ':') + { + // Port number given + pb = ++cbracket; + if (pb == end) + // Trailing colon: invalid + return; + } + isIPv6 = true; + } + // If there's more than 1 colon in the address, it's IPv6 + else if (std::count(ab, ae, ':') > 1) + { + isIPv6 = true; + } + // It's probably not IPv6, but look for a port specification + else + { + const auto colon = std::find(ab, ae, ':'); + if (colon != ae) + { + ae = colon; + pb = colon + 1; + if (pb == end) + // Trailing colon: invalid + return; + } + } + + addrinfo hints{}; + hints.ai_family = family; + if (const AddrInfo ai{std::string{ab, ae}.c_str(), + (pb != end ? std::string{pb, pe}.c_str() : nullptr), &hints}) + { + SetAddress(ai.GetAddrs()->ai_addr); + } +} + +void C4Network2EndpointAddress::SetAddress(const C4Network2EndpointAddress &addr) +{ + SetHost(addr); + SetPort(addr.GetPort()); +} + +void C4Network2EndpointAddress::SetAddress( + const C4Network2HostAddress::SpecialAddress host, const std::uint16_t port) +{ + SetHost(host); + SetPort(port); +} + +void C4Network2EndpointAddress::SetAddress(const C4Network2HostAddress &host, const std::uint16_t port) +{ + SetHost(host); + SetPort(port); +} + +bool C4Network2EndpointAddress::IsNull() const +{ + return IsNullHost() && GetPort() == IPPORT_NONE; +} + +bool C4Network2HostAddress::IsNull() const +{ + switch (gen.sa_family) + { + case AF_INET: return v4.sin_addr.s_addr == 0; + case AF_INET6: return IN6_IS_ADDR_UNSPECIFIED(&v6.sin6_addr); + } + assert(!"Shouldn't reach this"); + return false; +} + +C4Network2HostAddress::AddressFamily C4Network2HostAddress::GetFamily() const +{ + return + gen.sa_family == AF_INET ? IPv4 : + gen.sa_family == AF_INET6 ? IPv6 : + UnknownFamily; +} + +std::size_t C4Network2HostAddress::GetAddrLen() const +{ + return GetFamily() == IPv4 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); +} + +void C4Network2EndpointAddress::SetPort(const std::uint16_t port) +{ + switch (gen.sa_family) + { + case AF_INET: v4.sin_port = htons(port); break; + case AF_INET6: v6.sin6_port = htons(port); break; + default: assert(!"Shouldn't reach this"); break; + } +} + +void C4Network2EndpointAddress::SetDefaultPort(const std::uint16_t port) +{ + if (GetPort() == IPPORT_NONE) + SetPort(port); +} + +std::uint16_t C4Network2EndpointAddress::GetPort() const +{ + switch (gen.sa_family) + { + case AF_INET: return ntohs(v4.sin_port); + case AF_INET6: return ntohs(v6.sin6_port); + } + assert(!"Shouldn't reach this"); + return IPPORT_NONE; +} + +bool C4Network2HostAddress::operator==(const C4Network2HostAddress &rhs) const +{ + // Check for IPv4-mapped IPv6 addresses. + if (gen.sa_family != rhs.gen.sa_family) + return AsIPv6() == rhs.AsIPv6(); + if (gen.sa_family == AF_INET) + return v4.sin_addr.s_addr == rhs.v4.sin_addr.s_addr; + if (gen.sa_family == AF_INET6) + return std::memcmp(&v6.sin6_addr, &rhs.v6.sin6_addr, sizeof(v6.sin6_addr)) == 0 && + v6.sin6_scope_id == rhs.v6.sin6_scope_id; + assert(!"Shouldn't reach this"); + return false; +} + +bool C4Network2EndpointAddress::operator==(const C4Network2EndpointAddress &rhs) const +{ + if (!C4Network2HostAddress::operator==(rhs)) return false; + if (gen.sa_family == AF_INET) + { + return v4.sin_port == rhs.v4.sin_port; + } + else if (gen.sa_family == AF_INET6) + { + return v6.sin6_port == rhs.v6.sin6_port && + v6.sin6_scope_id == rhs.v6.sin6_scope_id; + } + assert(!"Shouldn't reach this"); + return false; +} + +StdStrBuf C4Network2HostAddress::ToString(const int flags) const +{ + if (IsIPv6MappedIPv4()) return AsIPv4().ToString(flags); + + if (gen.sa_family == AF_INET6 && v6.sin6_scope_id != 0 && (flags & TSF_SkipZoneId)) + { + auto addr = *this; + addr.v6.sin6_scope_id = 0; + return addr.ToString(flags); + } + + char buf[INET6_ADDRSTRLEN]; + if (::getnameinfo(&gen, GetAddrLen(), buf, sizeof(buf), nullptr, 0, NI_NUMERICHOST) != 0) + return {}; + + return StdStrBuf{buf, true}; +} + +StdStrBuf C4Network2EndpointAddress::ToString(const int flags) const +{ + if (IsIPv6MappedIPv4()) return AsIPv4().ToString(flags); + + if (flags & TSF_SkipPort) + return C4Network2HostAddress::ToString(flags); + + switch (GetFamily()) + { + case IPv4: return FormatString("%s:%d", C4Network2HostAddress::ToString(flags).getData(), GetPort()); + case IPv6: return FormatString("[%s]:%d", C4Network2HostAddress::ToString(flags).getData(), GetPort()); + case UnknownFamily: ; // fallthrough + } + assert(!"Shouldn't reach this"); + return {}; +} + +void C4Network2EndpointAddress::CompileFunc(StdCompiler *const comp) +{ + if (!comp->isCompiler()) + { + StdStrBuf val{ToString(TSF_SkipZoneId)}; + comp->Value(val); + } + else + { + StdStrBuf val; + comp->Value(val); + SetAddress(val); + } +} // *** C4Network2Address @@ -43,7 +497,7 @@ void C4Network2Address::CompileFunc(StdCompiler *const comp) comp->Value(mkEnumAdaptT(protocol, Protocols)); comp->Separator(StdCompiler::SEP_PART2); // ':' - comp->Value(mkDefaultAdapt(addr, C4NetIO::addr_t{})); + comp->Value(mkDefaultAdapt(addr, C4Network2EndpointAddress{})); } StdStrBuf C4Network2Address::toString() const diff --git a/src/C4Network2Address.h b/src/C4Network2Address.h index 68108df94..953bf9bfe 100644 --- a/src/C4Network2Address.h +++ b/src/C4Network2Address.h @@ -17,7 +17,178 @@ #pragma once -#include "C4Network2IO.h" +#include "StdBuf.h" + +#include +#include + +#ifdef _WIN32 + #include + #include +#else + #define SOCKET int + #define INVALID_SOCKET (-1) + #include + #include +#endif + +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 0 +#endif + + +class C4Network2HostAddress +{ +public: + enum AddressFamily + { + IPv6 = AF_INET6, + IPv4 = AF_INET, + UnknownFamily = 0 + }; + enum SpecialAddress + { + Loopback, // IPv6 localhost (::1) + Any, // IPv6 any-address (::) + AnyIPv4 // IPv4 any-address (0.0.0.0) + }; + + enum ToStringFlags + { + TSF_SkipZoneId = 1, + TSF_SkipPort = 2 + }; + +public: + C4Network2HostAddress() { Clear(); } + C4Network2HostAddress(const C4Network2HostAddress &other) { SetHost(other); } + C4Network2HostAddress(const SpecialAddress addr) { SetHost(addr); } + explicit C4Network2HostAddress(const std::uint32_t addr) { SetHost(addr); } + C4Network2HostAddress(const StdStrBuf &addr) { SetHost(addr); } + C4Network2HostAddress(const sockaddr *const addr) { SetHost(addr); } + +public: + AddressFamily GetFamily() const; + std::size_t GetAddrLen() const; + + void SetScopeId(int scopeId); + int GetScopeId() const; + + void Clear(); + void SetHost(const sockaddr *addr); + void SetHost(const C4Network2HostAddress &host); + void SetHost(SpecialAddress host); + void SetHost(const StdStrBuf &host, AddressFamily family = UnknownFamily); + void SetHost(std::uint32_t host); + + C4Network2HostAddress AsIPv6() const; // Convert an IPv4 address to an IPv6-mapped IPv4 address + bool IsIPv6MappedIPv4() const; + C4Network2HostAddress AsIPv4() const; // Try to convert an IPv6-mapped IPv4 address to an IPv4 address (returns unchanged address if not possible) + + // General categories + bool IsNull() const; + bool IsMulticast() const; + bool IsLoopback() const; + bool IsLocal() const; // IPv6 link-local address + bool IsPrivate() const; // IPv6 ULA or IPv4 private address range + + StdStrBuf ToString(int flags = 0) const; + + bool operator ==(const C4Network2HostAddress &rhs) const; + +protected: + // Data + union + { + sockaddr gen; + sockaddr_in v4; + sockaddr_in6 v6; + }; +}; + +class C4Network2EndpointAddress : public C4Network2HostAddress // Host and port +{ +public: + static constexpr std::uint16_t IPPORT_NONE{0}; + +public: + C4Network2EndpointAddress() { Clear(); } + C4Network2EndpointAddress(const C4Network2EndpointAddress &other) : C4Network2HostAddress{} { SetAddress(other); } + C4Network2EndpointAddress(const C4Network2HostAddress &host, const std::uint16_t port = IPPORT_NONE) : C4Network2HostAddress{host} { SetPort(port); } + C4Network2EndpointAddress(const C4Network2HostAddress::SpecialAddress addr, const std::uint16_t port = IPPORT_NONE) : C4Network2HostAddress{addr} { SetPort(port); } + explicit C4Network2EndpointAddress(const StdStrBuf &addr) { SetAddress(addr); } + +public: + StdStrBuf ToString(int flags = 0) const; + + void Clear(); + + void SetAddress(const sockaddr *addr); + void SetAddress(const C4Network2EndpointAddress &other); + void SetAddress(C4Network2HostAddress::SpecialAddress addr, std::uint16_t port = IPPORT_NONE); + void SetAddress(const C4Network2HostAddress &host, std::uint16_t port = IPPORT_NONE); + void SetAddress(const StdStrBuf &addr, AddressFamily family = UnknownFamily); + + C4Network2HostAddress GetHost() const { return *this; } // HostAddress copy ctor slices off port information + C4Network2EndpointAddress AsIPv6() const; // Convert an IPv4 address to an IPv6-mapped IPv4 address + C4Network2EndpointAddress AsIPv4() const; // Try to convert an IPv6-mapped IPv4 address to an IPv4 address (returns unchanged address if not possible) + + void SetPort(std::uint16_t port); + void SetDefaultPort(std::uint16_t port); // Set a port only if there is none + std::uint16_t GetPort() const; + + bool IsNull() const; + bool IsNullHost() const { return C4Network2HostAddress::IsNull(); } + + // Pointer wrapper to be able to implicitly convert to sockaddr* + class EndpointAddressPtr; + const EndpointAddressPtr operator&() const; + EndpointAddressPtr operator&(); + + class EndpointAddressPtr + { + C4Network2EndpointAddress *const p; + friend EndpointAddressPtr C4Network2EndpointAddress::operator&(); + friend const EndpointAddressPtr C4Network2EndpointAddress::operator&() const; + EndpointAddressPtr(C4Network2EndpointAddress *const p) : p(p) {} + + public: + const C4Network2EndpointAddress &operator*() const { return *p; } + C4Network2EndpointAddress &operator*() { return *p; } + + const C4Network2EndpointAddress &operator->() const { return *p; } + C4Network2EndpointAddress &operator->() { return *p; } + + operator const C4Network2EndpointAddress *() const { return p; } + operator C4Network2EndpointAddress *() { return p; } + + operator const sockaddr *() const { return &p->gen; } + operator sockaddr *() { return &p->gen; } + + operator const sockaddr_in *() const { return &p->v4; } + operator sockaddr_in *() { return &p->v4; } + + operator const sockaddr_in6 *() const { return &p->v6; } + operator sockaddr_in6 *() { return &p->v6; } + }; + + bool operator==(const C4Network2EndpointAddress &rhs) const; + + // Conversions + operator sockaddr() const { return gen; } + operator sockaddr_in() const { assert(gen.sa_family == AF_INET); return v4; } + operator sockaddr_in6() const { assert(gen.sa_family == AF_INET6); return v6; } + + // StdCompiler + void CompileFunc(StdCompiler *comp); + + friend class EndpointAddressPtr; +}; + +enum C4Network2IOProtocol +{ + P_UDP, P_TCP, P_NONE = -1 +}; class C4Network2Address { @@ -25,7 +196,7 @@ class C4Network2Address C4Network2Address() : protocol{P_NONE} {} - C4Network2Address(const C4NetIO::addr_t addr, const C4Network2IOProtocol protocol) + C4Network2Address(const C4Network2EndpointAddress addr, const C4Network2IOProtocol protocol) : addr{addr.AsIPv4()}, protocol{protocol} {} C4Network2Address(const C4Network2Address &addr) @@ -39,22 +210,22 @@ class C4Network2Address bool operator==(const C4Network2Address &addr) const; - const C4NetIO::addr_t &GetAddr() const { return addr; } - C4NetIO::addr_t &GetAddr() { return addr; } + const C4Network2EndpointAddress &GetAddr() const { return addr; } + C4Network2EndpointAddress &GetAddr() { return addr; } bool isIPNull() const { return addr.IsNull(); } std::uint16_t GetPort() const { return addr.GetPort(); } C4Network2IOProtocol GetProtocol() const { return protocol; } StdStrBuf toString() const; - void SetAddr(const C4NetIO::addr_t naddr) { addr = naddr.AsIPv4(); } - void SetIP(const C4NetIO::addr_t ip) { addr.SetAddress(ip.AsIPv4()); } + void SetAddr(const C4Network2EndpointAddress naddr) { addr = naddr.AsIPv4(); } + void SetIP(const C4Network2EndpointAddress ip) { addr.SetAddress(ip.AsIPv4()); } void SetPort(const std::uint16_t port) { addr.SetPort(port); } void SetProtocol(const C4Network2IOProtocol protocol) { this->protocol = protocol; } void CompileFunc(StdCompiler *comp); protected: - C4NetIO::addr_t addr; + C4Network2EndpointAddress addr; C4Network2IOProtocol protocol; }; diff --git a/src/C4Network2Client.cpp b/src/C4Network2Client.cpp index 999c3efa5..d9552dc84 100644 --- a/src/C4Network2Client.cpp +++ b/src/C4Network2Client.cpp @@ -279,7 +279,7 @@ bool C4Network2Client::AddAddr(const C4Network2Address &addr, bool fAnnounce, bo void C4Network2Client::AddLocalAddrs(const std::uint16_t iPortTCP, const std::uint16_t iPortUDP) { - C4NetIO::addr_t addr{C4NetIO::HostAddress::AnyIPv4}; + C4NetIO::addr_t addr{C4Network2HostAddress::AnyIPv4}; if (iPortTCP != 0) { diff --git a/src/C4Network2IO.cpp b/src/C4Network2IO.cpp index 02090fe53..81be06cb8 100644 --- a/src/C4Network2IO.cpp +++ b/src/C4Network2IO.cpp @@ -416,10 +416,10 @@ bool C4Network2IO::InitPuncher(const C4NetIO::addr_t puncherAddr) // save address switch (puncherAddr.GetFamily()) { - case C4NetIO::HostAddress::IPv4: + case C4Network2HostAddress::IPv4: PuncherAddrIPv4 = puncherAddr; break; - case C4NetIO::HostAddress::IPv6: + case C4Network2HostAddress::IPv6: PuncherAddrIPv6 = puncherAddr; break; default: @@ -436,12 +436,12 @@ void C4Network2IO::Punch(const C4NetIO::addr_t &puncheeAddr) dynamic_cast(pNetIO_UDP)->SendDirect(MkC4NetIOPacket(PID_Pong, C4PacketPing{}, puncheeAddr)); } -void C4Network2IO::SendPuncherPacket(const C4NetpuncherPacket &p, const C4NetIO::HostAddress::AddressFamily family) +void C4Network2IO::SendPuncherPacket(const C4NetpuncherPacket &p, const C4Network2HostAddress::AddressFamily family) { if (!pNetIO_UDP) return; - if (family == C4NetIO::HostAddress::IPv4 && !PuncherAddrIPv4.IsNull()) + if (family == C4Network2HostAddress::IPv4 && !PuncherAddrIPv4.IsNull()) pNetIO_UDP->Send(p.PackTo(PuncherAddrIPv4)); - else if (family == C4NetIO::HostAddress::IPv6 && !PuncherAddrIPv6.IsNull()) + else if (family == C4Network2HostAddress::IPv6 && !PuncherAddrIPv6.IsNull()) pNetIO_UDP->Send(p.PackTo(PuncherAddrIPv6)); } diff --git a/src/C4Network2IO.h b/src/C4Network2IO.h index 339012078..f077f47c9 100644 --- a/src/C4Network2IO.h +++ b/src/C4Network2IO.h @@ -17,6 +17,7 @@ #pragma once +#include "C4Network2Address.h" #include "C4NetIO.h" #include "C4Client.h" #include "C4InteractiveThread.h" @@ -27,11 +28,7 @@ class C4Network2IOConnection; -// enums & constants -enum C4Network2IOProtocol -{ - P_UDP, P_TCP, P_NONE = -1 -}; +// constants const int C4NetTimer = 500, // ms C4NetPingFreq = 1000, // ms @@ -136,7 +133,7 @@ class C4Network2IO // punch bool InitPuncher(C4NetIO::addr_t puncherAddr); // by main thread - void SendPuncherPacket(const C4NetpuncherPacket &, C4NetIO::HostAddress::AddressFamily family); + void SendPuncherPacket(const C4NetpuncherPacket &, C4Network2HostAddress::AddressFamily family); void Punch(const C4NetIO::addr_t &); // Sends a ping packet // stuff diff --git a/src/C4Network2Reference.cpp b/src/C4Network2Reference.cpp index 8540d6bfc..910cfca8e 100644 --- a/src/C4Network2Reference.cpp +++ b/src/C4Network2Reference.cpp @@ -33,7 +33,7 @@ C4Network2Reference::C4Network2Reference() C4Network2Reference::~C4Network2Reference() {} -void C4Network2Reference::SetSourceAddress(const C4NetIO::EndpointAddress &ip) +void C4Network2Reference::SetSourceAddress(const C4Network2EndpointAddress &ip) { source = ip; for (auto &addr : Addrs) @@ -560,10 +560,10 @@ bool C4Network2HTTPClient::SetServer(const char *szServerAddress) } ServerAddr.SetDefaultPort(GetDefaultPort()); - if (ServerAddr.GetFamily() == C4NetIO::HostAddress::IPv6) + if (ServerAddr.GetFamily() == C4Network2HostAddress::IPv6) { // Try to find a fallback IPv4 address for Happy Eyeballs. - ServerAddrFallback.SetAddress(Server, C4NetIO::HostAddress::IPv4); + ServerAddrFallback.SetAddress(Server, C4Network2HostAddress::IPv4); ServerAddrFallback.SetDefaultPort(GetDefaultPort()); } else diff --git a/src/C4Network2Reference.h b/src/C4Network2Reference.h index 0fca13630..ad4b4fa24 100644 --- a/src/C4Network2Reference.h +++ b/src/C4Network2Reference.h @@ -61,7 +61,7 @@ class C4Network2Reference // Network addresses std::vector Addrs; - C4NetIO::EndpointAddress source; + C4Network2EndpointAddress source; public: const std::vector &getAddresses() const { return Addrs; } @@ -79,8 +79,8 @@ class C4Network2Reference C4NetpuncherID getNetpuncherGameID() const { return NetpuncherGameID; } StdStrBuf getNetpuncherAddr() const { return NetpuncherAddr; } - void SetSourceAddress(const C4NetIO::EndpointAddress &ip); - const C4NetIO::EndpointAddress &GetSourceAddress() const { return source; } + void SetSourceAddress(const C4Network2EndpointAddress &ip); + const C4Network2EndpointAddress &GetSourceAddress() const { return source; } void InitLocal(C4Game *pGame); diff --git a/src/C4PuncherPacket.cpp b/src/C4PuncherPacket.cpp index e2f6996cf..a49a0438e 100644 --- a/src/C4PuncherPacket.cpp +++ b/src/C4PuncherPacket.cpp @@ -18,6 +18,7 @@ #include "C4PuncherPacket.h" #include "C4Network2Address.h" +#include "StdAdaptors.h" #include