From 102047f5379ea365f1aa08540eaba801010e701b Mon Sep 17 00:00:00 2001 From: Nicolas Hake Date: Mon, 18 Feb 2013 15:30:00 +0100 Subject: [PATCH] Implement IPv6 support to C4NetIO --- CMakeLists.txt | 1 + planet/System.ocg/LanguageDE.txt | 4 +- planet/System.ocg/LanguageUS.txt | 4 +- src/gui/C4StartupNetDlg.cpp | 3 +- src/netpuncher/C4PuncherHash.h | 23 +- src/netpuncher/C4PuncherPacket.cpp | 4 +- src/netpuncher/main.cpp | 6 +- src/network/C4NetIO.cpp | 446 ++++++++++++++++++++++++---- src/network/C4NetIO.h | 175 +++++++++-- src/network/C4Network2.cpp | 31 +- src/network/C4Network2Address.cpp | 22 +- src/network/C4Network2Address.h | 14 +- src/network/C4Network2Client.cpp | 83 ++++-- src/network/C4Network2Dialogs.cpp | 11 +- src/network/C4Network2Discover.cpp | 14 +- src/network/C4Network2Discover.h | 8 +- src/network/C4Network2IO.cpp | 47 ++- src/network/C4Network2IO.h | 2 +- src/network/C4Network2IRC.cpp | 2 +- src/network/C4Network2Reference.cpp | 24 +- src/network/C4Network2Reference.h | 5 +- src/script/C4AulDebug.cpp | 17 +- 22 files changed, 714 insertions(+), 232 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e13d13ba..3505e896a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1248,6 +1248,7 @@ target_link_libraries(netpuncher ) if(WIN32) + target_link_libraries(libmisc iphlpapi) target_link_libraries(openclonk ws2_32) target_link_libraries(openclonk-server ws2_32) target_link_libraries(c4group ws2_32) diff --git a/planet/System.ocg/LanguageDE.txt b/planet/System.ocg/LanguageDE.txt index f7df50a77..00231b48e 100644 --- a/planet/System.ocg/LanguageDE.txt +++ b/planet/System.ocg/LanguageDE.txt @@ -743,8 +743,8 @@ IDS_NET_CLIENT_IGNORE=Ignorieren IDS_NET_CLIENT_IGNORE_DESC=%s ignorieren. Du kannst Nachrichten von diesem Client dann in der Lobby nicht mehr lesen. IDS_NET_CLIENT_INFO=Client-Informationen IDS_NET_CLIENT_INFO_ADDRESSES=Adressen: -IDS_NET_CLIENT_INFO_CONNDATA= Daten: %s (%s:%d, %d ms) -IDS_NET_CLIENT_INFO_CONNECTIONS=Verbindungen: %s: %s (%s:%d, %d ms) +IDS_NET_CLIENT_INFO_CONNDATA= Daten: %s (%s, %d ms) +IDS_NET_CLIENT_INFO_CONNECTIONS=Verbindungen: %s: %s (%s, %d ms) IDS_NET_CLIENT_INFO_NOADDRESSES=Addressen: Keine IDS_NET_CLIENT_INFO_NOCONNECTIONS=Verbindungen: Nicht verbunden IDS_NET_CLIENT_INFO_UNKNOWNID=Unbekannte client ID #%d. diff --git a/planet/System.ocg/LanguageUS.txt b/planet/System.ocg/LanguageUS.txt index 1c1cdc3f9..efd0df93b 100644 --- a/planet/System.ocg/LanguageUS.txt +++ b/planet/System.ocg/LanguageUS.txt @@ -743,8 +743,8 @@ IDS_NET_CLIENT_IGNORE=Ignore IDS_NET_CLIENT_IGNORE_DESC=Ignores %s. You will not be able to see messages from this client. IDS_NET_CLIENT_INFO=Client info IDS_NET_CLIENT_INFO_ADDRESSES=Addresses: -IDS_NET_CLIENT_INFO_CONNDATA= Data: %s (%s:%d, %d ms) -IDS_NET_CLIENT_INFO_CONNECTIONS=Connections: %s: %s (%s:%d, %d ms) +IDS_NET_CLIENT_INFO_CONNDATA= Data: %s (%s, %d ms) +IDS_NET_CLIENT_INFO_CONNECTIONS=Connections: %s: %s (%s, %d ms) IDS_NET_CLIENT_INFO_NOADDRESSES=Addresses: none IDS_NET_CLIENT_INFO_NOCONNECTIONS=Connections: Not connected IDS_NET_CLIENT_INFO_UNKNOWNID=Unknown client ID #%d. diff --git a/src/gui/C4StartupNetDlg.cpp b/src/gui/C4StartupNetDlg.cpp index 96dbfba1e..843d41760 100644 --- a/src/gui/C4StartupNetDlg.cpp +++ b/src/gui/C4StartupNetDlg.cpp @@ -920,8 +920,7 @@ void C4StartupNetDlg::UpdateList(bool fGotReference) C4NetIO::addr_t Discover; while (DiscoverClient.PopDiscover(Discover)) { - StdStrBuf Address; - Address.Format("%s:%d", inet_ntoa(Discover.sin_addr), htons(Discover.sin_port)); + StdStrBuf Address(Discover.ToString()); AddReferenceQuery(Address.getData(), C4StartupNetListEntry::NRQT_GameDiscovery); } diff --git a/src/netpuncher/C4PuncherHash.h b/src/netpuncher/C4PuncherHash.h index fcf435b84..c8357945c 100644 --- a/src/netpuncher/C4PuncherHash.h +++ b/src/netpuncher/C4PuncherHash.h @@ -60,10 +60,25 @@ namespace std { }; template<> - struct hash<::sockaddr_in> { - size_t operator()(const ::sockaddr_in& addr) const { - auto unpack = make_tuple(addr.sin_family, addr.sin_addr.s_addr, addr.sin_port); - return hash()(unpack); + struct hash { + size_t operator()(const C4NetIO::addr_t& addr) const { + switch (addr.GetFamily()) + { + case C4NetIO::HostAddress::IPv4: + { + sockaddr_in v4 = addr; + auto unpack = make_tuple(v4.sin_family, v4.sin_addr.s_addr, v4.sin_port); + return hash()(unpack); + } + case C4NetIO::HostAddress::IPv6: + { + sockaddr_in6 v6 = addr; + auto unpack = make_tuple(v6.sin6_family, v6.sin6_port, v6.sin6_flowinfo, std::string((char*) v6.sin6_addr.s6_addr, 16), v6.sin6_scope_id); + return hash()(unpack); + } + default: + return 0; + } } }; } diff --git a/src/netpuncher/C4PuncherPacket.cpp b/src/netpuncher/C4PuncherPacket.cpp index 12929d8cb..53619ccc6 100644 --- a/src/netpuncher/C4PuncherPacket.cpp +++ b/src/netpuncher/C4PuncherPacket.cpp @@ -47,9 +47,7 @@ C4NetpuncherPacketCReq::C4NetpuncherPacketCReq(const C4NetIOPacket& rpack) { C4Network2Address parse_addr; CompileFromBuf(parse_addr, rpack.getPBuf()); if (parse_addr.getProtocol() != P_UDP) throw P_UDP; - addr.sin_addr.s_addr = parse_addr.getAddr().sin_addr.s_addr, - addr.sin_family = parse_addr.getAddr().sin_family, - addr.sin_port = parse_addr.getAddr().sin_port; + addr = parse_addr.getAddr(); } StdBuf C4NetpuncherPacketCReq::PackInto() const { diff --git a/src/netpuncher/main.cpp b/src/netpuncher/main.cpp index 405bfecb6..ea6120b95 100644 --- a/src/netpuncher/main.cpp +++ b/src/netpuncher/main.cpp @@ -48,7 +48,7 @@ private: peer_ids.emplace(AddrPeer, nid); peer_addrs.emplace(nid, AddrPeer); Send(C4NetpuncherPacketAssID(nid).PackTo(AddrPeer)); - printf("Punched %s:%d... #%u\n", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port), nid); + printf("Punched %s... #%u\n", AddrPeer.ToString().getData(), nid); return true; } virtual void OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) { @@ -63,12 +63,12 @@ private: virtual void OnDisconn(const addr_t &AddrPeer, C4NetIO *pNetIO, const char *szReason) { auto it = peer_ids.find(AddrPeer); if (it == peer_ids.end()) { - printf("ERROR: closing connection for %s:%d: (%s) but no connection is known\n", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port), szReason); + printf("ERROR: closing connection for %s: (%s) but no connection is known\n", AddrPeer.ToString().getData(), szReason); return; } peer_addrs.erase(it->second); peer_ids.erase(it); - printf("Stopped punching %s:%d: %s...\n", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port), szReason); + printf("Stopped punching %s: %s...\n", AddrPeer.ToString().getData(), szReason); }; } Puncher; diff --git a/src/network/C4NetIO.cpp b/src/network/C4NetIO.cpp index 6b1712fb6..a9a492e8f 100644 --- a/src/network/C4NetIO.cpp +++ b/src/network/C4NetIO.cpp @@ -57,7 +57,6 @@ int pipe(int *phandles) { return _pipe(phandles, 10, O_BINARY); } // constants definition const int C4NetIO::TO_INF = -1; -const uint16_t C4NetIO::P_NONE = ~0; // simulate packet loss (loss probability in percent) // #define C4NETIO_SIMULATE_PACKETLOSS 10 @@ -203,6 +202,350 @@ void ResetSocketError() #endif // HAVE_WINSOCK +// *** C4NetIO::HostAddress +void C4NetIO::HostAddress::Clear() +{ + v6.sin6_family = AF_INET6; + v6.sin6_flowinfo = 0; + v6.sin6_scope_id = 0; + memset(&v6.sin6_addr, 0, sizeof(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; +} + +void C4NetIO::HostAddress::SetScopeId(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 const uint8_t 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: + memmove(((char*)&nrv.v6.sin6_addr) + sizeof(v6_mapped_v4_prefix), &v4.sin_addr, sizeof(v4.sin_addr)); + nrv.v6.sin6_family = AF_INET6; + memcpy(&nrv.v6.sin6_addr, v6_mapped_v4_prefix, sizeof(v6_mapped_v4_prefix)); + nrv.v6.sin6_flowinfo = 0; + nrv.v6.sin6_scope_id = 0; + break; + default: assert(!"Shouldn't reach this"); break; + } + return nrv; +} + +C4NetIO::EndpointAddress C4NetIO::EndpointAddress::AsIPv6() const +{ + return EndpointAddress(HostAddress::AsIPv6(), GetPort()); +} + +void C4NetIO::HostAddress::SetHost(const sockaddr *addr) +{ + // Copy all but port number + if (addr->sa_family == AF_INET6) + { + v6.sin6_family = ((const sockaddr_in6*)addr)->sin6_family; + v6.sin6_flowinfo = ((const sockaddr_in6*)addr)->sin6_flowinfo; + memcpy(&v6.sin6_addr, &((const sockaddr_in6*)addr)->sin6_addr, sizeof(v6.sin6_addr)); + v6.sin6_scope_id = ((const sockaddr_in6*)addr)->sin6_scope_id; + } + else if (addr->sa_family == AF_INET) + { + v4.sin_family = ((const sockaddr_in*)addr)->sin_family; + v4.sin_addr.s_addr = ((const sockaddr_in*)addr)->sin_addr.s_addr; + memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); + } +} + +void C4NetIO::EndpointAddress::SetAddress(const sockaddr *addr) +{ + switch (addr->sa_family) + { + case AF_INET: memcpy(&v4, addr, sizeof(v4)); break; + case AF_INET6: memcpy(&v6, addr, sizeof(v6)); break; + default: + assert(!"Unexpected address family"); + memcpy(&gen, addr, sizeof(gen)); break; + } +} + +void C4NetIO::HostAddress::SetHost(SpecialAddress addr) +{ + switch (addr) + { + case Any: + v6.sin6_family = AF_INET6; + 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; + memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); + break; + case Loopback: + v6.sin6_family = AF_INET6; + 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(uint32_t v4addr) +{ + v4.sin_family = AF_INET; + v4.sin_addr.s_addr = v4addr; + memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); +} + +void C4NetIO::EndpointAddress::SetAddress(const StdStrBuf &addr) +{ + Clear(); + + if (addr.isNull()) return; + + const char *begin = addr.getData(); + const char *end = begin + addr.getLength(); + + const char *ab = begin; + const char *ae = end; + + const char *pb = end; + const char *pe = end; + + bool isIPv6 = false; + + // If addr begins with [, it's an IPv6 address + if (ab[0] == '[') + { + ++ab; // skip bracket + const char *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 char *colon = std::find(ab, ae, ':'); + if (colon != ae) + { + ae = colon; + pb = colon + 1; + if (pb == end) + // Trailing colon: invalid + return; + } + } + + addrinfo hints = addrinfo(); + //hints.ai_flags = AI_NUMERICHOST; + addrinfo *addresses = nullptr; + if (getaddrinfo(std::string(ab, ae).c_str(), pb != end ? std::string(pb, pe).c_str() : nullptr, &hints, &addresses) != 0) + // GAI failed + return; + SetAddress(addresses->ai_addr); + freeaddrinfo(addresses); +} + +void C4NetIO::EndpointAddress::SetAddress(const EndpointAddress &addr) +{ + SetHost(addr); + SetPort(addr.GetPort()); +} + +void C4NetIO::EndpointAddress::SetAddress(HostAddress::SpecialAddress host, uint16_t port) +{ + SetHost(host); + SetPort(port); +} + +void C4NetIO::EndpointAddress::SetAddress(const HostAddress &host, 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; +} + +void C4NetIO::EndpointAddress::SetPort(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; + } +} + +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 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(int flags) const +{ + if (gen.sa_family == AF_INET6 && v6.sin6_scope_id != 0 && (flags & TSF_SkipZoneId)) + { + HostAddress addr = *this; + addr.v6.sin6_scope_id = 0; + return addr.ToString(flags); + } + + char buf[INET6_ADDRSTRLEN]; + if (getnameinfo(&gen, sizeof(v6), buf, sizeof(buf), 0, 0, NI_NUMERICHOST) != 0) + return StdStrBuf(); + + return StdStrBuf(buf, true); +} + +StdStrBuf C4NetIO::EndpointAddress::ToString(int flags) const +{ + 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()); + default: assert(!"Shouldn't reach this"); + } + return StdStrBuf(); +} + +void C4NetIO::EndpointAddress::CompileFunc(StdCompiler *comp) +{ + if (!comp->isCompiler()) + { + StdStrBuf val(ToString(TSF_SkipZoneId)); + comp->Value(val); + } else { + StdStrBuf val; + comp->Value(val); + SetAddress(val); + } +} + // *** C4NetIO // construction / destruction @@ -318,7 +661,7 @@ bool C4NetIOTCP::Init(uint16_t iPort) #endif // create listen socket (if necessary) - if (iPort != P_NONE) + if (iPort != addr_t::IPPORT_NONE) if (!Listen(iPort)) return false; @@ -633,7 +976,7 @@ bool C4NetIOTCP::Execute(int iMaxTime, pollfd *fds) // (mt-safe) bool C4NetIOTCP::Connect(const C4NetIO::addr_t &addr) // (mt-safe) { // create new socket - SOCKET nsock = ::socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP); + SOCKET nsock = ::socket(addr.GetFamily() == HostAddress::IPv6 ? AF_INET6 : AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP); if (nsock == INVALID_SOCKET) { SetError("socket creation failed", true); @@ -675,7 +1018,7 @@ bool C4NetIOTCP::Connect(const C4NetIO::addr_t &addr) // (mt-safe) #endif // connect (async) - if (::connect(nsock, reinterpret_cast(&addr), sizeof addr) == SOCKET_ERROR) + if (::connect(nsock, &addr, sizeof addr) == SOCKET_ERROR) { if (!HaveWouldBlockError()) // expected { @@ -853,9 +1196,9 @@ C4NetIOTCP::Peer *C4NetIOTCP::Accept(SOCKET nsock, const addr_t &ConnectAddr) // { // accept from listener #ifdef __linux__ - if ((nsock = ::accept4(lsock, reinterpret_cast(&addr), &iAddrSize, SOCK_CLOEXEC)) == INVALID_SOCKET) + if ((nsock = ::accept4(lsock, &addr, &iAddrSize, SOCK_CLOEXEC)) == INVALID_SOCKET) #else - if ((nsock = ::accept(lsock, reinterpret_cast(&addr), &iAddrSize)) == INVALID_SOCKET) + if ((nsock = ::accept(lsock, &addr, &iAddrSize)) == INVALID_SOCKET) #endif { // set error @@ -863,12 +1206,12 @@ C4NetIOTCP::Peer *C4NetIOTCP::Accept(SOCKET nsock, const addr_t &ConnectAddr) // return nullptr; } // connect address unknown, so zero it - ZeroMem(&caddr, sizeof caddr); + caddr.Clear(); } else { // get peer address - if (::getpeername(nsock, reinterpret_cast(&addr), &iAddrSize) == SOCKET_ERROR) + if (::getpeername(nsock, &addr, &iAddrSize) == SOCKET_ERROR) { #ifndef HAVE_WINSOCK // getpeername behaves strangely on exotic platforms. Just ignore it. @@ -885,7 +1228,7 @@ C4NetIOTCP::Peer *C4NetIOTCP::Accept(SOCKET nsock, const addr_t &ConnectAddr) // } // check address - if (iAddrSize != sizeof addr || addr.sin_family != AF_INET) + if (addr.GetFamily() == addr_t::UnknownFamily) { // set error SetError("socket accept failed: invalid address returned"); @@ -959,10 +1302,10 @@ bool C4NetIOTCP::Listen(uint16_t inListenPort) if (lsock != INVALID_SOCKET) // close existing socket closesocket(lsock); - iListenPort = P_NONE; + iListenPort = addr_t::IPPORT_NONE; // create socket - if ((lsock = ::socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP)) == INVALID_SOCKET) + if ((lsock = ::socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP)) == INVALID_SOCKET) { SetError("socket creation failed", true); return false; @@ -973,12 +1316,9 @@ bool C4NetIOTCP::Listen(uint16_t inListenPort) setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseaddr), sizeof(reuseaddr)); #endif // bind listen socket - C4NetIO::addr_t addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(inListenPort); - addr.sin_addr.s_addr = INADDR_ANY; - memset(addr.sin_zero, 0, sizeof addr.sin_zero); - if (::bind(lsock, reinterpret_cast(&addr), sizeof addr) == SOCKET_ERROR) + addr_t addr = addr_t::Any; + addr.SetPort(inListenPort); + if (::bind(lsock, &addr, sizeof(addr)) == SOCKET_ERROR) { SetError("socket bind failed", true); closesocket(lsock); lsock = INVALID_SOCKET; @@ -1014,7 +1354,7 @@ C4NetIOTCP::Peer *C4NetIOTCP::GetPeer(const addr_t &addr) // (mt-safe) CStdShareLock PeerListLock(&PeerListCSec); for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next) if (pPeer->Open()) - if (AddrEqual(pPeer->GetAddr(), addr)) + if (pPeer->GetAddr() == addr) return pPeer; return nullptr; } @@ -1088,7 +1428,7 @@ C4NetIOTCP::ConnectWait *C4NetIOTCP::GetConnectWait(const addr_t &addr) // (mt-s CStdShareLock PeerListLock(&PeerListCSec); // search for (ConnectWait *pWait = pConnectWaits; pWait; pWait = pWait->Next) - if (AddrEqual(pWait->addr, addr)) + if (pWait->addr == addr) return pWait; return nullptr; } @@ -1335,8 +1675,8 @@ bool C4NetIOSimpleUDP::Init(uint16_t inPort) } #endif - // create socket - if ((sock = ::socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) == INVALID_SOCKET) + // create sockets + if ((sock = ::socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) == INVALID_SOCKET) { SetError("could not create socket", true); return false; @@ -1351,12 +1691,9 @@ bool C4NetIOSimpleUDP::Init(uint16_t inPort) // bind socket iPort = inPort; - C4NetIO::addr_t naddr; - naddr.sin_family = AF_INET; - naddr.sin_port = (iPort == P_NONE ? 0 : htons(iPort)); - naddr.sin_addr.s_addr = INADDR_ANY; - memset(naddr.sin_zero, 0, sizeof naddr.sin_zero); - if (::bind(sock, reinterpret_cast(&naddr), sizeof naddr) == SOCKET_ERROR) + addr_t naddr = addr_t::Any; + naddr.SetPort(iPort); + if (::bind(sock, &naddr, sizeof(naddr)) == SOCKET_ERROR) { SetError("could not bind socket", true); return false; @@ -1420,13 +1757,12 @@ bool C4NetIOSimpleUDP::InitBroadcast(addr_t *pBroadcastAddr) if (fMultiCast) CloseBroadcast(); // broadcast addr valid? - if (pBroadcastAddr->sin_family != AF_INET || - in_addr_b(pBroadcastAddr->sin_addr, 0) != 239) + if (pBroadcastAddr->IsMulticast()) { SetError("invalid broadcast address"); return false; } - if (pBroadcastAddr->sin_port != htons(iPort)) + if (pBroadcastAddr->GetPort() != iPort) { SetError("invalid broadcast address (different port)"); return false; @@ -1442,7 +1778,7 @@ bool C4NetIOSimpleUDP::InitBroadcast(addr_t *pBroadcastAddr) // set up multicast group information this->MCAddr = *pBroadcastAddr; - MCGrpInfo.imr_multiaddr = MCAddr.sin_addr; + MCGrpInfo.imr_multiaddr = static_cast(&MCAddr)->sin_addr; MCGrpInfo.imr_interface.s_addr = INADDR_ANY; // join multicast group @@ -1559,8 +1895,8 @@ bool C4NetIOSimpleUDP::Execute(int iMaxTime, pollfd *) // alloc buffer C4NetIOPacket Pkt; Pkt.New(iMaxMsgSize); // read data (note: it is _not_ garantueed that iMaxMsgSize bytes are available) - addr_t SrcAddr; socklen_t iSrcAddrLen = sizeof(SrcAddr); - int iMsgSize = ::recvfrom(sock, getMBufPtr(Pkt), iMaxMsgSize, 0, reinterpret_cast(&SrcAddr), &iSrcAddrLen); + addr_t SrcAddr; socklen_t iSrcAddrLen = sizeof(sockaddr_in6); + int iMsgSize = ::recvfrom(sock, getMBufPtr(Pkt), iMaxMsgSize, 0, &SrcAddr, &iSrcAddrLen); // error? if (iMsgSize == SOCKET_ERROR) { @@ -1579,7 +1915,7 @@ bool C4NetIOSimpleUDP::Execute(int iMaxTime, pollfd *) } } // invalid address? - if (iSrcAddrLen != sizeof(SrcAddr) || SrcAddr.sin_family != AF_INET) + if ((iSrcAddrLen != sizeof(sockaddr_in) && iSrcAddrLen != sizeof(sockaddr_in6)) || SrcAddr.GetFamily() == addr_t::UnknownFamily) { SetError("recvfrom returned an invalid address"); return false; @@ -1607,7 +1943,7 @@ bool C4NetIOSimpleUDP::Send(const C4NetIOPacket &rPacket) // send it C4NetIO::addr_t addr = rPacket.getAddr(); if (::sendto(sock, getBufPtr(rPacket), rPacket.getSize(), 0, - reinterpret_cast(&addr), sizeof(addr)) + &addr, sizeof(addr)) != int(rPacket.getSize()) && !HaveWouldBlockError()) { @@ -1870,8 +2206,7 @@ bool C4NetIOUDP::InitBroadcast(addr_t *pBroadcastAddr) C4NetIO::addr_t MCAddr = *pBroadcastAddr; // broadcast addr valid? - if (MCAddr.sin_family != AF_INET || - in_addr_b(MCAddr.sin_addr, 0) != 239) + if (!MCAddr.IsMulticast()) { // port is needed in order to search a mc address automatically if (!iPort) @@ -1880,15 +2215,12 @@ bool C4NetIOUDP::InitBroadcast(addr_t *pBroadcastAddr) return false; } // set up adress - MCAddr.sin_family = AF_INET; - MCAddr.sin_port = htons(iPort); - memset(&MCAddr.sin_zero, 0, sizeof MCAddr.sin_zero); + MCAddr.SetAddress(addr_t::AnyIPv4, iPort); // search for a free one for (int iRetries = 1000; iRetries; iRetries--) { // create new - random - address - MCAddr.sin_addr.s_addr = - 0x000000ef | (UnsyncedRandom(0x1000000) << 8); + MCAddr.SetAddress(C4NetIO::HostAddress(0x000000ef | (UnsyncedRandom(0x1000000) << 8))); // init broadcast if (!C4NetIOSimpleUDP::InitBroadcast(&MCAddr)) return false; @@ -1921,7 +2253,7 @@ bool C4NetIOUDP::InitBroadcast(addr_t *pBroadcastAddr) // Timeout? So expect this address to be unused if (LastPacket.isNull()) { fSuccess = true; break; } // looped back? - if (C4NetIOSimpleUDP::getMCLoopback() && AddrEqual(LastPacket.getAddr(), MCLoopbackAddr)) + if (C4NetIOSimpleUDP::getMCLoopback() && LastPacket.getAddr() == MCLoopbackAddr) // ignore this one continue; // otherwise: there must be someone else in this MC group @@ -1938,7 +2270,7 @@ bool C4NetIOUDP::InitBroadcast(addr_t *pBroadcastAddr) else { // check: must be same port - if (MCAddr.sin_port != htons(iPort)) + if (MCAddr.GetPort() == iPort) { SetError("invalid multicast address: wrong port"); return false; @@ -2173,7 +2505,7 @@ void C4NetIOUDP::OnPacket(const C4NetIOPacket &Packet, C4NetIO *pNetIO) } // looped back? if (fMultiCast && !fDelayedLoopbackTest) - if (AddrEqual(Packet.getAddr(), MCLoopbackAddr)) + if (Packet.getAddr() == MCLoopbackAddr) return; // loopback test packet? ignore if ((Packet.getStatus() & 0x7F) == IPID_Test) return; @@ -2234,7 +2566,7 @@ void C4NetIOUDP::OnDisconn(const addr_t &AddrPeer, C4NetIO *pNetIO, const char * void C4NetIOUDP::OnAddAddress(const addr_t &FromAddr, const AddAddrPacket &Packet) { // Security (this would be strange behavior indeed...) - if (!AddrEqual(FromAddr, Packet.Addr) && !AddrEqual(FromAddr, Packet.NewAddr)) return; + if (FromAddr != Packet.Addr && FromAddr != Packet.NewAddr) return; // Search peer(s) Peer *pPeer = GetPeer(Packet.Addr); Peer *pPeer2 = GetPeer(Packet.NewAddr); @@ -2494,7 +2826,7 @@ const unsigned int C4NetIOUDP::Peer::iReCheckInterval = 1000; // (ms) // construction / destruction -C4NetIOUDP::Peer::Peer(const sockaddr_in &naddr, C4NetIOUDP *pnParent) +C4NetIOUDP::Peer::Peer(const addr_t &naddr, C4NetIOUDP *pnParent) : pParent(pnParent), addr(naddr), eStatus(CS_None), fMultiCast(false), fDoBroadcast(false), @@ -2506,8 +2838,6 @@ C4NetIOUDP::Peer::Peer(const sockaddr_in &naddr, C4NetIOUDP *pnParent) tNextReCheck(C4TimeMilliseconds::NegativeInfinity), iIRate(0), iORate(0), iLoss(0) { - ZeroMem(&addr2, sizeof(addr2)); - ZeroMem(&PeerAddr, sizeof(PeerAddr)); } C4NetIOUDP::Peer::~Peer() @@ -2610,7 +2940,7 @@ void C4NetIOUDP::Peer::OnRecv(const C4NetIOPacket &rPacket) // (mt-safe) if (!fBroadcasted) { // Second connection attempt using different address? - if (PeerAddr.sin_addr.s_addr && !AddrEqual(PeerAddr, pPkt->Addr)) + if (!PeerAddr.IsNull() && PeerAddr != pPkt->Addr) { // Notify peer that he has two addresses to reach this connection. AddAddrPacket Pkt; @@ -2647,7 +2977,7 @@ void C4NetIOUDP::Peer::OnRecv(const C4NetIOPacket &rPacket) // (mt-safe) iLastPacketAsked = iLastMCPacketAsked = 0; // Activate Multicast? if (!pParent->fMultiCast) - if (pPkt->MCAddr.sin_addr.s_addr) + if (!pPkt->MCAddr.IsNull()) { addr_t MCAddr = pPkt->MCAddr; // Init Broadcast (with delayed loopback test) @@ -2663,7 +2993,7 @@ void C4NetIOUDP::Peer::OnRecv(const C4NetIOPacket &rPacket) // (mt-safe) nPack.Addr = addr; if (fBroadcasted) nPack.MCMode = ConnOKPacket::MCM_MCOK; // multicast send ok - else if (pParent->fMultiCast && addr.sin_port == pParent->iPort) + else if (pParent->fMultiCast && addr.GetPort() == pParent->iPort) nPack.MCMode = ConnOKPacket::MCM_MC; // du ok, try multicast next else nPack.MCMode = ConnOKPacket::MCM_NoMC; // du ok @@ -2774,7 +3104,7 @@ void C4NetIOUDP::Peer::OnRecv(const C4NetIOPacket &rPacket) // (mt-safe) if (rPacket.getSize() < sizeof(ClosePacket)) break; const ClosePacket *pPkt = getBufPtr(rPacket); // ignore if it's for another address - if (PeerAddr.sin_addr.s_addr && !AddrEqual(PeerAddr, pPkt->Addr)) + if (!PeerAddr.IsNull() && PeerAddr != pPkt->Addr) break; // close OnClose("connection closed by peer"); @@ -2828,7 +3158,7 @@ bool C4NetIOUDP::Peer::DoConn(bool fMC) // (mt-safe) if (pParent->fMultiCast) Pkt.MCAddr = pParent->C4NetIOSimpleUDP::getMCAddr(); else - memset(&Pkt.MCAddr, 0, sizeof Pkt.MCAddr); + Pkt.MCAddr.Clear(); return SendDirect(C4NetIOPacket(&Pkt, sizeof(Pkt), false, addr)); } @@ -2871,7 +3201,8 @@ bool C4NetIOUDP::Peer::SendDirect(const Packet &rPacket, unsigned int iNr) bool C4NetIOUDP::Peer::SendDirect(C4NetIOPacket &&rPacket) // (mt-safe) { // insert correct addr - if (!(rPacket.getStatus() & 0x80)) rPacket.SetAddr(addr); + C4NetIO::addr_t v6Addr(addr.AsIPv6()); + if (!(rPacket.getStatus() & 0x80)) rPacket.SetAddr(v6Addr); // count outgoing { CStdLock StatLock(&StatCSec); iORate += rPacket.getSize() + iUDPHeaderSize; } // forward call @@ -3123,7 +3454,7 @@ C4NetIOUDP::Peer *C4NetIOUDP::GetPeer(const addr_t &addr) CStdShareLock PeerListLock(&PeerListCSec); for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next) if (!pPeer->Closed()) - if (AddrEqual(pPeer->GetAddr(), addr) || AddrEqual(pPeer->GetAltAddr(), addr)) + if (pPeer->GetAddr() == addr || pPeer->GetAltAddr() == addr) return pPeer; return nullptr; } @@ -3405,6 +3736,7 @@ bool ResolveAddress(const char *szAddress, C4NetIO::addr_t *paddr, uint16_t iPor raddr.sin_addr = *reinterpret_cast(pHost->h_addr_list[0]); } // ok - *paddr = raddr; + paddr->SetAddress(reinterpret_cast(&raddr)); + paddr->SetPort(iPort); return true; } diff --git a/src/network/C4NetIO.h b/src/network/C4NetIO.h index 121155e9c..c58b2e558 100644 --- a/src/network/C4NetIO.h +++ b/src/network/C4NetIO.h @@ -65,9 +65,145 @@ public: // *** constants / types static const int TO_INF; // = -1; - static const uint16_t P_NONE; // = -1 - typedef sockaddr_in addr_t; + 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(SpecialAddress addr) { SetHost(addr); } + explicit HostAddress(uint32_t addr) { SetHost(addr); } + HostAddress(const StdStrBuf &addr) { SetHost(addr); } + + AddressFamily GetFamily() 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); + void SetHost(uint32_t host); + + C4NetIO::HostAddress AsIPv6() const; // convert an IPv4 address to an IPv6-mapped IPv4 address + + // General categories + bool IsNull() const; + bool IsMulticast() const; + bool IsLoopback() const; +// bool IsBroadcast() const; + + StdStrBuf ToString(int flags = 0) const; + + bool operator ==(const HostAddress &rhs) const; + bool operator !=(const HostAddress &rhs) const { return !(*this == rhs); } + + protected: + // data + union + { + sockaddr gen; + sockaddr_in v4; + sockaddr_in6 v6; + }; + }; + + struct EndpointAddress : public HostAddress // Host and port + { + static const uint16_t IPPORT_NONE = 0; + + EndpointAddress() { Clear(); } + EndpointAddress(const EndpointAddress &other) : HostAddress() { SetAddress(other); } + EndpointAddress(const HostAddress &host, uint16_t port = IPPORT_NONE) : HostAddress(host) { SetPort(port); } + EndpointAddress(HostAddress::SpecialAddress addr, 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, uint16_t port = IPPORT_NONE); + void SetAddress(const HostAddress &host, uint16_t port = IPPORT_NONE); + void SetAddress(const StdStrBuf &addr); + + 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 + + void SetPort(uint16_t port); + 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 *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; + bool operator !=(const EndpointAddress &rhs) const { return !(*this == rhs); } + + // 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); + + private: + bool SetAddressByString(const StdStrBuf &address, short family); + + friend class EndpointAddressPtr; + }; + typedef EndpointAddress addr_t; // callback class class CBClass @@ -108,10 +244,8 @@ public: // *** interface // * not multithreading safe - virtual bool Init(uint16_t iPort = P_NONE) = 0; - virtual bool InitBroadcast(addr_t *pBroadcastAddr) = 0; + virtual bool Init(uint16_t iPort = addr_t::IPPORT_NONE) = 0; virtual bool Close() = 0; - virtual bool CloseBroadcast() = 0; virtual bool Execute(int iTimeout = -1, pollfd * = 0) = 0; // (for StdSchedulerProc) virtual bool IsNotify() { return true; } @@ -129,6 +263,9 @@ public: virtual bool GetConnStatistic(const addr_t &addr, int *pIRate, int *pORate, int *pLoss) = 0; virtual void ClearStatistic() = 0; +protected: +// virtual SOCKET CreateSocket() = 0; + // *** errors protected: StdCopyStrBuf Error; @@ -193,7 +330,7 @@ public: // *** interface // * not multithreading safe - virtual bool Init(uint16_t iPort = P_NONE); + virtual bool Init(uint16_t iPort = addr_t::IPPORT_NONE); virtual bool InitBroadcast(addr_t *pBroadcastAddr); virtual bool Close(); virtual bool CloseBroadcast(); @@ -352,7 +489,7 @@ public: C4NetIOSimpleUDP(); virtual ~C4NetIOSimpleUDP(); - virtual bool Init(uint16_t iPort = P_NONE); + virtual bool Init(uint16_t iPort = addr_t::IPPORT_NONE); virtual bool InitBroadcast(addr_t *pBroadcastAddr); virtual bool Close(); virtual bool CloseBroadcast(); @@ -440,7 +577,7 @@ public: // *** interface - virtual bool Init(uint16_t iPort = P_NONE); + virtual bool Init(uint16_t iPort = addr_t::IPPORT_NONE); virtual bool InitBroadcast(addr_t *pBroadcastAddr); virtual bool Close(); virtual bool CloseBroadcast(); @@ -807,15 +944,6 @@ private: }; // helpers -inline bool AddrEqual(const C4NetIO::addr_t addr1, const C4NetIO::addr_t addr2) -{ - return addr1.sin_addr.s_addr == addr2.sin_addr.s_addr && - addr1.sin_family == addr2.sin_family && - addr1.sin_port == addr2.sin_port; -} -inline bool operator == (const C4NetIO::addr_t addr1, const C4NetIO::addr_t addr2) { return AddrEqual(addr1, addr2); } -inline bool operator != (const C4NetIO::addr_t addr1, const C4NetIO::addr_t addr2) { return !AddrEqual(addr1, addr2); } - // there seems to be no standard way to get these numbers, so let's do it the dirty way... inline uint8_t &in_addr_b(in_addr &addr, int i) { @@ -831,19 +959,6 @@ inline void CompileFunc(in_addr &ip, StdCompiler *pComp) pComp->Value(in_addr_b(ip, 3)); } -inline void CompileFunc(C4NetIO::addr_t &addr, StdCompiler *pComp) -{ - pComp->Value(addr.sin_addr); pComp->Separator(StdCompiler::SEP_PART2); - uint16_t iPort = htons(addr.sin_port); - pComp->Value(iPort); - addr.sin_port = htons(iPort); - if (pComp->isCompiler()) - { - addr.sin_family = AF_INET; - ZeroMem(addr.sin_zero, sizeof(addr.sin_zero)); - } -} - #ifdef HAVE_WINSOCK bool AcquireWinSock(); void ReleaseWinSock(); diff --git a/src/network/C4Network2.cpp b/src/network/C4Network2.cpp index 21bb27691..1ef12d313 100644 --- a/src/network/C4Network2.cpp +++ b/src/network/C4Network2.cpp @@ -247,7 +247,10 @@ C4Network2::InitResult C4Network2::InitClient(const C4Network2Reference &Ref, bo // copy addresses C4Network2Address Addrs[C4ClientMaxAddr]; for (int i = 0; i < Ref.getAddrCnt(); i++) + { Addrs[i] = Ref.getAddr(i); + Addrs[i].getAddr().SetScopeId(Ref.GetSourceAddress().GetScopeId()); + } // Try to connect to host if (InitClient(Addrs, Ref.getAddrCnt(), HostCore, Password.getData()) == IR_Fatal) return IR_Fatal; @@ -1043,18 +1046,16 @@ void C4Network2::DrawStatus(C4TargetFacet &cgo) // connections if (pClient->isConnected()) { - Stat.AppendFormat( "| Connections: %s: %s (%s:%d p%d l%d)", + Stat.AppendFormat( "| Connections: %s: %s (%s p%d l%d)", pClient->getMsgConn() == pClient->getDataConn() ? "Msg/Data" : "Msg", NetIO.getNetIOName(pClient->getMsgConn()->getNetClass()), - inet_ntoa(pClient->getMsgConn()->getPeerAddr().sin_addr), - htons(pClient->getMsgConn()->getPeerAddr().sin_port), + pClient->getMsgConn()->getPeerAddr().ToString().getData(), pClient->getMsgConn()->getPingTime(), pClient->getMsgConn()->getPacketLoss()); if (pClient->getMsgConn() != pClient->getDataConn()) Stat.AppendFormat( ", Data: %s (%s:%d p%d l%d)", NetIO.getNetIOName(pClient->getDataConn()->getNetClass()), - inet_ntoa(pClient->getDataConn()->getPeerAddr().sin_addr), - htons(pClient->getDataConn()->getPeerAddr().sin_port), + pClient->getDataConn()->getPeerAddr().ToString().getData(), pClient->getDataConn()->getPingTime(), pClient->getDataConn()->getPacketLoss()); } @@ -1183,7 +1184,7 @@ void C4Network2::HandleConn(const C4PacketConn &Pkt, C4Network2IOConnection *pCo else { // log & close - LogSilentF("Network: connection by %s (%s:%d) blocked: %s", CCore.getName(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port), reply.getData()); + LogSilentF("Network: connection by %s (%s) blocked: %s", CCore.getName(), pConn->getPeerAddr().ToString().getData(), reply.getData()); pConn->Close(); } } @@ -1198,7 +1199,7 @@ bool C4Network2::CheckConn(const C4ClientCore &CCore, C4Network2IOConnection *pC if (CCore.getDiffLevel(pClient->getCore()) > C4ClientCoreDL_IDMatch) { *szReply = "wrong client core"; return false; } // check address - if (pClient->isConnected() && pClient->getMsgConn()->getPeerAddr().sin_addr.s_addr != pConn->getPeerAddr().sin_addr.s_addr) + if (pClient->isConnected() && pClient->getMsgConn()->getPeerAddr() != pConn->getPeerAddr()) { *szReply = "wrong address"; return false; } // accept return true; @@ -1277,7 +1278,7 @@ void C4Network2::HandleConnRe(const C4PacketConnRe &Pkt, C4Network2IOConnection // wrong password? fWrongPassword = Pkt.isPasswordWrong(); // show message - LogSilentF("Network: connection to %s (%s:%d) refused: %s", pClient->getName(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port), Pkt.getMsg()); + LogSilentF("Network: connection to %s (%s) refused: %s", pClient->getName(), pConn->getPeerAddr().ToString().getData(), Pkt.getMsg()); // close connection pConn->Close(); return; @@ -1302,7 +1303,7 @@ void C4Network2::HandleConnRe(const C4PacketConnRe &Pkt, C4Network2IOConnection if (pConn->getNetClass() == NetIO.DataIO()) pClient->SetDataConn(pConn); // add peer connect address to client address list - if (pConn->getConnectAddr().sin_addr.s_addr) + if (!pConn->getConnectAddr().IsNull()) { C4Network2Address Addr(pConn->getConnectAddr(), pConn->getProtocol()); pClient->AddAddr(Addr, Status.getState() != GS_Init); @@ -1432,8 +1433,8 @@ void C4Network2::HandleJoinData(const C4PacketJoinData &rPkt) void C4Network2::OnConnect(C4Network2Client *pClient, C4Network2IOConnection *pConn, const char *szMsg, bool fFirstConnection) { // log - LogSilentF("Network: %s %s connected (%s:%d/%s) (%s)", pClient->isHost() ? "host" : "client", - pClient->getName(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port), + LogSilentF("Network: %s %s connected (%s/%s) (%s)", pClient->isHost() ? "host" : "client", + pClient->getName(), pConn->getPeerAddr().ToString().getData(), NetIO.getNetIOName(pConn->getNetClass()), szMsg ? szMsg : ""); // first connection for this peer? call special handler @@ -1442,8 +1443,8 @@ void C4Network2::OnConnect(C4Network2Client *pClient, C4Network2IOConnection *pC void C4Network2::OnConnectFail(C4Network2IOConnection *pConn) { - LogSilentF("Network: %s connection to %s:%d failed!", NetIO.getNetIOName(pConn->getNetClass()), - inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port)); + LogSilentF("Network: %s connection to %s failed!", NetIO.getNetIOName(pConn->getNetClass()), + pConn->getPeerAddr().ToString().getData()); // maybe client connection failure // (happens if the connection is not fully accepted and the client disconnects. @@ -1455,8 +1456,8 @@ void C4Network2::OnConnectFail(C4Network2IOConnection *pConn) void C4Network2::OnDisconnect(C4Network2Client *pClient, C4Network2IOConnection *pConn) { - LogSilentF("Network: %s connection to %s (%s:%d) lost!", NetIO.getNetIOName(pConn->getNetClass()), - pClient->getName(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port)); + LogSilentF("Network: %s connection to %s (%s) lost!", NetIO.getNetIOName(pConn->getNetClass()), + pClient->getName(), pConn->getPeerAddr().ToString().getData()); // connection lost? if (!pClient->isConnected()) diff --git a/src/network/C4Network2Address.cpp b/src/network/C4Network2Address.cpp index 005cf9e7c..5e23731bf 100644 --- a/src/network/C4Network2Address.cpp +++ b/src/network/C4Network2Address.cpp @@ -31,8 +31,7 @@ void C4Network2Address::CompileFunc(StdCompiler *pComp) // Clear if (pComp->isCompiler()) { - ZeroMem(&addr, sizeof(addr)); - addr.sin_family = AF_INET; + addr.Clear(); } // Write protocol @@ -41,34 +40,27 @@ void C4Network2Address::CompileFunc(StdCompiler *pComp) { "UDP", P_UDP }, { "TCP", P_TCP }, - { nullptr, P_NONE }, + { nullptr, P_NONE }, }; pComp->Value(mkEnumAdaptT(eProtocol, Protocols)); pComp->Separator(StdCompiler::SEP_PART2); // ':' - // Write IP (no IP = 0.0.0.0) - in_addr zero; zero.s_addr = INADDR_ANY; - pComp->Value(mkDefaultAdapt(addr.sin_addr, zero)); - pComp->Separator(StdCompiler::SEP_PART2); // ':' - - // Write port - uint16_t iPort = htons(addr.sin_port); - pComp->Value(iPort); - addr.sin_port = htons(iPort); + pComp->Value(mkDefaultAdapt(addr, C4NetIO::addr_t())); } StdStrBuf C4Network2Address::toString() const { switch (eProtocol) { - case P_UDP: return FormatString("UDP:%s:%d", inet_ntoa(addr.sin_addr), htons(addr.sin_port)); - case P_TCP: return FormatString("TCP:%s:%d", inet_ntoa(addr.sin_addr), htons(addr.sin_port)); + case P_UDP: return FormatString("UDP:%s", addr.ToString().getData()); + case P_TCP: return FormatString("TCP:%s", addr.ToString().getData()); default: return StdStrBuf("INVALID"); } } bool C4Network2Address::operator == (const C4Network2Address &addr2) const { - return eProtocol == addr2.getProtocol() && AddrEqual(addr, addr2.getAddr()); + return eProtocol == addr2.getProtocol() && addr == addr2.getAddr(); } + diff --git a/src/network/C4Network2Address.h b/src/network/C4Network2Address.h index 554d35201..d15d1c0bd 100644 --- a/src/network/C4Network2Address.h +++ b/src/network/C4Network2Address.h @@ -24,7 +24,7 @@ class C4Network2Address public: C4Network2Address() : eProtocol(P_NONE) - { ZeroMem(&addr, sizeof(addr)); } + { } C4Network2Address(C4NetIO::addr_t addr, C4Network2IOProtocol eProtocol) : addr(addr), eProtocol(eProtocol) @@ -45,16 +45,18 @@ protected: public: const C4NetIO::addr_t &getAddr() const { return addr; } - in_addr getIPAddr() const { return addr.sin_addr; } - bool isIPNull() const { return !addr.sin_addr.s_addr; } - uint16_t getPort() const { return htons(addr.sin_port); } + C4NetIO::addr_t &getAddr() { return addr; } + //in_addr getIPAddr() const { return addr.sin_addr; } + bool isIPNull() const { return addr.IsNull(); } + uint16_t getPort() const { return addr.GetPort(); } C4Network2IOProtocol getProtocol() const { return eProtocol; } StdStrBuf toString() const; void SetAddr(C4NetIO::addr_t naddr) { addr = naddr; } - void SetIP(in_addr ip) { addr.sin_addr = ip; } - void SetPort(uint16_t iPort) { addr.sin_port = htons(iPort); } + //void SetIP(in_addr ip) { addr.SetAddress(ip); } + void SetIP(C4NetIO::addr_t ip) { addr.SetAddress(ip); } + void SetPort(uint16_t iPort) { addr.SetPort(iPort); } void SetProtocol(C4Network2IOProtocol enProtocol) { eProtocol = enProtocol; } void CompileFunc(StdCompiler *pComp); diff --git a/src/network/C4Network2Client.cpp b/src/network/C4Network2Client.cpp index 7476e0a67..d0c9707f6 100644 --- a/src/network/C4Network2Client.cpp +++ b/src/network/C4Network2Client.cpp @@ -25,7 +25,10 @@ #include "game/C4Game.h" #include "player/C4PlayerList.h" -#ifndef _WIN32 +#ifdef _WIN32 +#include +#include +#else #include #include #include @@ -185,30 +188,55 @@ bool C4Network2Client::AddAddr(const C4Network2Address &addr, bool fAnnounce) void C4Network2Client::AddLocalAddrs(int16_t iPortTCP, int16_t iPortUDP) { // set up address struct - sockaddr_in addr; ZeroMem(&addr, sizeof addr); - addr.sin_family = AF_INET; + C4NetIO::addr_t addr; // get local address(es) - in_addr **ppAddr = nullptr; #ifdef HAVE_WINSOCK - bool fGotWinSock = AcquireWinSock(); - if (fGotWinSock) + const size_t BUFFER_SIZE = 16000; + PIP_ADAPTER_ADDRESSES addresses = nullptr; + for (int i = 0; i < 3; ++i) { - // get local host name - char szLocalHostName[128+1]; *szLocalHostName = '\0'; - ::gethostname(szLocalHostName, 128); - // get hostent-struct - hostent *ph = ::gethostbyname(szLocalHostName); - // check type, get addr list - if (ph) + addresses = (PIP_ADAPTER_ADDRESSES) realloc(addresses, BUFFER_SIZE * (i+1)); + if (!addresses) + // allocation failed + return; + ULONG bufsz = BUFFER_SIZE * (i+1); + DWORD rv = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_FRIENDLY_NAME, + nullptr, addresses, &bufsz); + if (rv == ERROR_BUFFER_OVERFLOW) + // too little space, try again + continue; + if (rv != NO_ERROR) { - if (ph->h_addrtype != AF_INET) - ph = nullptr; - else - ppAddr = reinterpret_cast(ph->h_addr_list); + // Something else happened + free(addresses); + return; + } + // All okay, add addresses + for (PIP_ADAPTER_ADDRESSES address = addresses; address; address = address->Next) + { + for (PIP_ADAPTER_UNICAST_ADDRESS unicast = address->FirstUnicastAddress; unicast; unicast = unicast->Next) + { + addr.SetHost(unicast->Address.lpSockaddr); + if (addr.IsLoopback()) + continue; + if (iPortTCP) + { + addr.SetPort(iPortTCP); + AddAddr(C4Network2Address(addr, P_TCP), false); + } + if (iPortUDP) + { + addr.SetPort(iPortUDP); + AddAddr(C4Network2Address(addr, P_UDP), false); + } + } } } + free(addresses); #else + in_addr **ppAddr = NULL; std::vector addr_vec; struct ifaddrs* addrs; getifaddrs(&addrs); @@ -223,29 +251,24 @@ void C4Network2Client::AddLocalAddrs(int16_t iPortTCP, int16_t iPortUDP) addr_vec.push_back(nullptr); ppAddr = &addr_vec[0]; -#endif // add address(es) for (;;) { if (iPortTCP >= 0) { - addr.sin_port = htons(iPortTCP); + addr.SetPort(iPortTCP); AddAddr(C4Network2Address(addr, P_TCP), false); } if (iPortUDP >= 0) { - addr.sin_port = htons(iPortUDP); + addr.SetPort(iPortUDP); AddAddr(C4Network2Address(addr, P_UDP), false); } // get next if (!ppAddr || !*ppAddr) break; - addr.sin_addr = **ppAddr++; + addr.SetHost(C4NetIO::HostAddress((**ppAddr++).s_addr)); } - -#ifdef HAVE_WINSOCK - if (fGotWinSock) ReleaseWinSock(); -#else if(addrs) freeifaddrs(addrs); #endif } @@ -255,7 +278,11 @@ void C4Network2Client::SendAddresses(C4Network2IOConnection *pConn) // send all addresses for (int32_t i = 0; i < iAddrCnt; i++) { - C4NetIOPacket Pkt = MkC4NetIOPacket(PID_Addr, C4PacketAddr(getID(), Addr[i])); + if (Addr[i].getAddr().GetScopeId() && (!pConn || pConn->getPeerAddr().GetScopeId() != Addr[i].getAddr().GetScopeId())) + continue; + C4Network2Address addr(Addr[i]); + addr.getAddr().SetScopeId(0); + C4NetIOPacket Pkt = MkC4NetIOPacket(PID_Addr, C4PacketAddr(getID(), addr)); if (pConn) pConn->Send(Pkt); else @@ -534,7 +561,9 @@ void C4Network2ClientList::HandlePacket(char cStatus, const C4PacketBase *pBaseP C4Network2Address addr = rPkt.getAddr(); // IP zero? Set to IP from where the packet came if (addr.isIPNull()) - addr.SetIP(pConn->getPeerAddr().sin_addr); + { + addr.SetIP(pConn->getPeerAddr()); + } // add (no announce) if (pClient->AddAddr(addr, true)) // new address? Try to connect diff --git a/src/network/C4Network2Dialogs.cpp b/src/network/C4Network2Dialogs.cpp index ffe3d7827..7c0f94936 100644 --- a/src/network/C4Network2Dialogs.cpp +++ b/src/network/C4Network2Dialogs.cpp @@ -96,14 +96,12 @@ void C4Network2ClientDlg::UpdateText() AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_CONNECTIONS"), pNetClient->getMsgConn() == pNetClient->getDataConn() ? "Msg/Data" : "Msg", ::Network.NetIO.getNetIOName(pNetClient->getMsgConn()->getNetClass()), - inet_ntoa(pNetClient->getMsgConn()->getPeerAddr().sin_addr), - htons(pNetClient->getMsgConn()->getPeerAddr().sin_port), + pNetClient->getMsgConn()->getPeerAddr().ToString().getData(), pNetClient->getMsgConn()->getPingTime()); if (pNetClient->getMsgConn() != pNetClient->getDataConn()) AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_CONNDATA"), ::Network.NetIO.getNetIOName(pNetClient->getDataConn()->getNetClass()), - inet_ntoa(pNetClient->getDataConn()->getPeerAddr().sin_addr), - htons(pNetClient->getDataConn()->getPeerAddr().sin_port), + pNetClient->getDataConn()->getPeerAddr().ToString().getData(), pNetClient->getDataConn()->getPingTime()); } else @@ -386,11 +384,10 @@ void C4Network2ClientListBox::ConnectionListItem::Update() else szConnType = "Data"; // display info - pDesc->SetText(FormatString("%s: %s (%s:%d l%d)", + pDesc->SetText(FormatString("%s: %s (%s l%d)", szConnType, ::Network.NetIO.getNetIOName(pConn->getNetClass()), - inet_ntoa(pConn->getPeerAddr().sin_addr), - htons(pConn->getPeerAddr().sin_port), + pConn->getPeerAddr().ToString().getData(), pConn->getPacketLoss()).getData()); } diff --git a/src/network/C4Network2Discover.cpp b/src/network/C4Network2Discover.cpp index 8da86e926..9f35d5711 100644 --- a/src/network/C4Network2Discover.cpp +++ b/src/network/C4Network2Discover.cpp @@ -41,10 +41,8 @@ bool C4Network2IODiscover::Init(uint16_t iPort) // Set callback C4NetIOSimpleUDP::SetCallback(this); // Build broadcast address - DiscoveryAddr.sin_addr.s_addr = C4NetDiscoveryAddress; - DiscoveryAddr.sin_port = htons(iPort); - DiscoveryAddr.sin_family = AF_INET; - ZeroMem(DiscoveryAddr.sin_zero, sizeof(DiscoveryAddr.sin_zero)); + DiscoveryAddr.SetAddress(C4NetDiscoveryAddress); + DiscoveryAddr.SetPort(iPort); // Initialize broadcast if (!C4NetIOSimpleUDP::InitBroadcast(&DiscoveryAddr)) return false; @@ -71,7 +69,7 @@ void C4Network2IODiscoverClient::OnPacket(const class C4NetIOPacket &rPacket, C4 { const C4Network2IODiscoverReply *pReply = reinterpret_cast(rPacket.getData()); Discovers[iDiscoverCount] = rPacket.getAddr(); - Discovers[iDiscoverCount].sin_port = pReply->Port; + Discovers[iDiscoverCount].SetPort(pReply->Port); iDiscoverCount++; } } @@ -87,10 +85,8 @@ bool C4Network2IODiscoverClient::Init(uint16_t iPort) // Set callback C4NetIOSimpleUDP::SetCallback(this); // Build broadcast address - DiscoveryAddr.sin_addr.s_addr = C4NetDiscoveryAddress; - DiscoveryAddr.sin_port = htons(iPort); - DiscoveryAddr.sin_family = AF_INET; - ZeroMem(DiscoveryAddr.sin_zero, sizeof(DiscoveryAddr.sin_zero)); + DiscoveryAddr.SetAddress(C4NetDiscoveryAddress); + DiscoveryAddr.SetPort(iPort); // Initialize broadcast if (!C4NetIOSimpleUDP::InitBroadcast(&DiscoveryAddr)) return false; diff --git a/src/network/C4Network2Discover.h b/src/network/C4Network2Discover.h index 6b51b4442..6ae405c42 100644 --- a/src/network/C4Network2Discover.h +++ b/src/network/C4Network2Discover.h @@ -20,7 +20,7 @@ const int C4NetMaxDiscover = 64; -const unsigned long C4NetDiscoveryAddress = 0xef; // 239.0.0.0 +const C4NetIO::HostAddress C4NetDiscoveryAddress = C4NetIO::HostAddress(0xef000000); // 239.0.0.0 class C4Network2IODiscover : public C4NetIOSimpleUDP, private C4NetIO::CBClass { @@ -34,12 +34,12 @@ protected: virtual void OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO); public: - bool Init(uint16_t iPort = P_NONE); + bool Init(uint16_t iPort = C4NetIO::addr_t::IPPORT_NONE); void SetDiscoverable(bool fnEnabled) { fEnabled = fnEnabled; } bool Announce(); private: - sockaddr_in DiscoveryAddr; + C4NetIO::addr_t DiscoveryAddr; uint16_t iRefServerPort; bool fEnabled; @@ -61,7 +61,7 @@ public: const C4NetIO::addr_t &getDiscover(int i) { return Discovers[i]; } void Clear() { iDiscoverCount = 0; } - bool Init(uint16_t iPort = P_NONE); + bool Init(uint16_t iPort = C4NetIO::addr_t::IPPORT_NONE); bool StartDiscovery(); bool PopDiscover(C4NetIO::addr_t &Discover); diff --git a/src/network/C4Network2IO.cpp b/src/network/C4Network2IO.cpp index 3d35a3c03..d1ffa94f6 100644 --- a/src/network/C4Network2IO.cpp +++ b/src/network/C4Network2IO.cpp @@ -56,7 +56,6 @@ C4Network2IO::C4Network2IO() iTCPIRate(0), iTCPORate(0), iTCPBCRate(0), iUDPIRate(0), iUDPORate(0), iUDPBCRate(0) { - ZeroMem(&PuncherAddr, sizeof(PuncherAddr)); } C4Network2IO::~C4Network2IO() @@ -253,7 +252,7 @@ bool C4Network2IO::Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol ePr if (GetConnectionByConnAddr(addr, pNetIO)) return true; // assign new connection ID, peer address isn't known yet uint32_t iConnID = iNextConnID++; - C4NetIO::addr_t paddr; ZeroMem(&paddr, sizeof paddr); + C4NetIO::addr_t paddr; // create connection object and add to list C4Network2IOConnection *pConn = new C4Network2IOConnection(); pConn->Set(pNetIO, eProt, paddr, addr, CS_Connect, szPassword, iConnID); @@ -263,7 +262,7 @@ bool C4Network2IO::Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol ePr if (!pConn->Connect()) { // show error - LogF("Network: could not connect to %s:%d using %s: %s", inet_ntoa(addr.sin_addr), htons(addr.sin_port), + LogF("Network: could not connect to %s using %s: %s", addr.ToString().getData(), getNetIOName(pNetIO), pNetIO->GetError() ? pNetIO->GetError() : ""); pNetIO->ResetError(); // remove class @@ -474,7 +473,7 @@ void C4Network2IO::Punch(const C4NetIO::addr_t &punchee_addr) { } void C4Network2IO::SendPuncherPacket(const C4NetpuncherPacket& p) { - if (!pNetIO_UDP || !PuncherAddr.sin_addr.s_addr) return; + if (!pNetIO_UDP || PuncherAddr.IsNull()) return; pNetIO_UDP->Send(p.PackTo(PuncherAddr)); } @@ -482,7 +481,7 @@ void C4Network2IO::SendPuncherPacket(const C4NetpuncherPacket& p) { bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t &ConnectAddr, const C4NetIO::addr_t *pOwnAddr, C4NetIO *pNetIO) { // puncher answer? - if (pNetIO == pNetIO_UDP && PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, ConnectAddr)) + if (pNetIO == pNetIO_UDP && !PuncherAddr.IsNull() && PuncherAddr == ConnectAddr) { // got an address? if (pOwnAddr) @@ -497,7 +496,7 @@ bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t #endif // search connection C4Network2IOConnection *pConn = nullptr; - if (ConnectAddr.sin_addr.s_addr) + if (!ConnectAddr.IsNull()) pConn = GetConnectionByConnAddr(ConnectAddr, pNetIO); // not found? if (!pConn) @@ -527,7 +526,7 @@ bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t SendConnPackets(); #if(C4NET2IO_DUMP_LEVEL > 0) // log - Application.InteractiveThread.ThreadLogS("Network: got %s connection from %s:%d", getNetIOName(pNetIO), inet_ntoa(PeerAddr.sin_addr), htons(PeerAddr.sin_port)); + Application.InteractiveThread.ThreadLogS("Network: got %s connection from %s", getNetIOName(pNetIO), PeerAddr.ToString().getData()); #endif // do event (disabled - unused) // pConn->AddRef(); PushNetEv(NE_Conn, pConn); @@ -538,9 +537,9 @@ bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t void C4Network2IO::OnDisconn(const C4NetIO::addr_t &addr, C4NetIO *pNetIO, const char *szReason) { // punch? - if (pNetIO == pNetIO_UDP && PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, addr)) + if (pNetIO == pNetIO_UDP && !PuncherAddr.IsNull() && PuncherAddr == addr) { - ZeroMem(&PuncherAddr, sizeof(PuncherAddr)); + PuncherAddr.Clear(); return; } #if(C4NET2IO_DUMP_LEVEL > 1) @@ -554,8 +553,8 @@ void C4Network2IO::OnDisconn(const C4NetIO::addr_t &addr, C4NetIO *pNetIO, const if (!pConn) return; #if(C4NET2IO_DUMP_LEVEL > 0) // log - Application.InteractiveThread.ThreadLogS("Network: %s connection to %s:%d %s (%s)", - getNetIOName(pNetIO), inet_ntoa(addr.sin_addr), htons(addr.sin_port), pConn->isConnecting() ? "failed" : "closed" , szReason); + Application.InteractiveThread.ThreadLogS("Network: %s connection to %s %s (%s)", + getNetIOName(pNetIO), addr.ToString().getData(), pConn->isConnecting() ? "failed" : "closed" , szReason); #endif // already closed? ignore if (!pConn->isClosed()) @@ -580,7 +579,7 @@ void C4Network2IO::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) C4TimeMilliseconds::Now().AsString().getData(), rPacket.getStatus(), getNetIOName(pNetIO)); #endif - if (pNetIO == pNetIO_UDP && PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, rPacket.getAddr())) + if (pNetIO == pNetIO_UDP && !PuncherAddr.IsNull() && PuncherAddr == rPacket.getAddr()) { HandlePuncherPacket(rPacket); return; @@ -588,7 +587,7 @@ void C4Network2IO::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) if (!rPacket.getSize()) return; // find connection C4Network2IOConnection *pConn = GetConnection(rPacket.getAddr(), pNetIO); - if (!pConn) { Application.InteractiveThread.ThreadLog("Network: could not find connection for packet from %s:%d!", inet_ntoa(rPacket.getAddr().sin_addr), htons(rPacket.getAddr().sin_port)); return; } + if (!pConn) { Application.InteractiveThread.ThreadLog("Network: could not find connection for packet from %s!", rPacket.getAddr().ToString().getData()); return; } #if(C4NET2IO_DUMP_LEVEL > 2) uint32_t iFindConnectionBlocked = C4TimeMilliseconds::Now() - tTime; if (iFindConnectionBlocked > 100) @@ -748,7 +747,7 @@ C4Network2IOConnection *C4Network2IO::GetConnection(const C4NetIO::addr_t &addr, CStdLock ConnListLock(&ConnListCSec); // search for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) - if (pConn->getNetClass() == pNetIO && AddrEqual(pConn->getPeerAddr(), addr)) + if (pConn->getNetClass() == pNetIO && pConn->getPeerAddr() == addr) return pConn; return nullptr; } @@ -758,7 +757,7 @@ C4Network2IOConnection *C4Network2IO::GetConnectionByConnAddr(const C4NetIO::add CStdLock ConnListLock(&ConnListCSec); // search for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) - if (pConn->getNetClass() == pNetIO && AddrEqual(pConn->getConnectAddr(), addr)) + if (pConn->getNetClass() == pNetIO && pConn->getConnectAddr() == addr) return pConn; return nullptr; } @@ -798,7 +797,7 @@ bool C4Network2IO::doAutoAccept(const C4ClientCore &CCore, const C4Network2IOCon for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext) if (pConn->isAccepted() && pConn->getCCore().getDiffLevel(CCore) <= C4ClientCoreDL_IDMatch && - pConn->getPeerAddr().sin_addr.s_addr != Conn.getPeerAddr().sin_addr.s_addr) + pConn->getPeerAddr().GetHost() != Conn.getPeerAddr().GetHost()) return false; // not found or IP matches? Let pass return true; @@ -837,9 +836,9 @@ bool C4Network2IO::HandlePacket(const C4NetIOPacket &rPacket, C4Network2IOConnec if (Config.Network.PacketLogging && fThread && Pkt.getPktType() != PID_Ping && Pkt.getPktType() != PID_Pong && Pkt.getPktType() != PID_NetResData) { // StdStrBuf PacketDump = DecompileToBuf(mkNamingAdaptrPacket); - StdStrBuf PacketHeader = FormatString("HandlePacket: %s by %s:%d (%lu bytes, counter %d)", + StdStrBuf PacketHeader = FormatString("HandlePacket: %s by %s (%lu bytes, counter %d)", C4TimeMilliseconds::Now().AsString().getData(), - inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port), + pConn->getPeerAddr().ToString().getData(), static_cast(rPacket.getSize()), pConn->getInPacketCounter()); StdStrBuf Dump = DecompileToBuf(mkNamingAdapt(Pkt, PacketHeader.getData())); // Put it directly. The standard functions behind StdBuf.Format seem to choke when you pass them too much data. @@ -1172,7 +1171,7 @@ void C4Network2IO::CheckTimeout() if (!pConn->isClosed() && !pConn->isAccepted()) if (difftime(time(nullptr), pConn->getTimestamp()) > C4NetAcceptTimeout) { - Application.InteractiveThread.ThreadLogS("Network: connection accept timeout to %s:%d", inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port)); + Application.InteractiveThread.ThreadLogS("Network: connection accept timeout to %s", pConn->getPeerAddr().ToString().getData()); pConn->Close(); } // ping timeout @@ -1181,7 +1180,7 @@ void C4Network2IO::CheckTimeout() > C4NetPingTimeout) { Application.InteractiveThread.ThreadLogS("%d %d %d", (int)pConn->getLag(), (int)time(nullptr), (int)pConn->getTimestamp()); - Application.InteractiveThread.ThreadLogS("Network: ping timeout to %s:%d", inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port)); + Application.InteractiveThread.ThreadLogS("Network: ping timeout to %s", pConn->getPeerAddr().ToString().getData()); pConn->Close(); } // delayed connection removal @@ -1266,13 +1265,9 @@ void C4Network2IO::SendConnPackets() void C4Network2IO::OnPuncherConnect(C4NetIO::addr_t addr) { // Sanity check - assert (addr.sin_family == AF_INET); - if (addr.sin_family != AF_INET) + if (addr.GetFamily() != C4NetIO::HostAddress::IPv4) return; - - Application.InteractiveThread.ThreadLogS("Adding address from puncher: %s:%d", inet_ntoa(addr.sin_addr), htons(addr.sin_port)); - - ZeroMem(addr.sin_zero, sizeof(addr.sin_zero)); + Application.InteractiveThread.ThreadLogS("Adding address from puncher: %s", addr.ToString().getData()); // Add for local client C4Network2Client *pLocal = ::Network.Clients.GetLocal(); if (pLocal) diff --git a/src/network/C4Network2IO.h b/src/network/C4Network2IO.h index dba3126d7..d561fa149 100644 --- a/src/network/C4Network2IO.h +++ b/src/network/C4Network2IO.h @@ -261,7 +261,7 @@ protected: public: C4NetIO *getNetClass() const { return pNetClass; } C4Network2IOProtocol getProtocol() const { return eProt; } - const C4NetIO::addr_t &getPeerAddr() const { return PeerAddr.sin_port ? PeerAddr : ConnectAddr; } + const C4NetIO::addr_t &getPeerAddr() const { return PeerAddr.GetPort() ? PeerAddr : ConnectAddr; } const C4NetIO::addr_t &getConnectAddr() const { return ConnectAddr; } uint32_t getID() const { return iID; } uint32_t getRemoteID() const { return iRemoteID; } diff --git a/src/network/C4Network2IRC.cpp b/src/network/C4Network2IRC.cpp index 36a2610ac..879810a08 100644 --- a/src/network/C4Network2IRC.cpp +++ b/src/network/C4Network2IRC.cpp @@ -246,7 +246,7 @@ size_t C4Network2IRCClient::UnpackPacket(const StdBuf &rInBuf, const C4NetIO::ad bool C4Network2IRCClient::OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t &AddrConnect, const addr_t *pOwnAddr, C4NetIO *pNetIO) { // Security checks - if (!fConnecting || fConnected || !AddrEqual(AddrConnect, ServerAddr)) return false; + if (!fConnecting || fConnected || AddrConnect != ServerAddr) return false; CStdLock Lock(&CSec); // Save connection data fConnected = true; diff --git a/src/network/C4Network2Reference.cpp b/src/network/C4Network2Reference.cpp index fbebd9e97..7190f3738 100644 --- a/src/network/C4Network2Reference.cpp +++ b/src/network/C4Network2Reference.cpp @@ -40,11 +40,11 @@ C4Network2Reference::~C4Network2Reference() } -void C4Network2Reference::SetSourceIP(in_addr ip) +void C4Network2Reference::SetSourceAddress(const C4NetIO::EndpointAddress &ip) { - for (int i = 0; i < iAddrCnt; i++) - if (Addrs[i].isIPNull()) - Addrs[i].SetIP(ip); + source = ip; + if (iAddrCnt < C4ClientMaxAddr) + Addrs[++iAddrCnt].SetAddr(ip); } void C4Network2Reference::InitLocal() @@ -407,12 +407,15 @@ bool C4Network2HTTPClient::Decompress(StdBuf *pData) bool C4Network2HTTPClient::OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t &AddrConnect, const C4NetIO::addr_t *pOwnAddr, C4NetIO *pNetIO) { // Make sure we're actually waiting for this connection - if (!AddrEqual(AddrConnect, ServerAddr)) + if (AddrConnect != ServerAddr) return false; // Save pack peer address PeerAddr = AddrPeer; // Send the request - Send(C4NetIOPacket(Request, AddrPeer)); + if (!Send(C4NetIOPacket(Request, AddrPeer))) + { + Error.Format("Unable to send HTTP request: %s", Error.getData()); + } Request.Clear(); fConnected = true; return true; @@ -557,11 +560,16 @@ bool C4Network2HTTPClient::SetServer(const char *szServerAddress) RequestPath = "/"; } // Resolve address - if (!ResolveAddress(Server.getData(), &ServerAddr, GetDefaultPort())) + ServerAddr.SetAddress(Server); + if (ServerAddr.IsNull()) { SetError(FormatString("Could not resolve server address %s!", Server.getData()).getData()); return false; } + if (ServerAddr.GetPort() == C4NetIO::EndpointAddress::IPPORT_NONE) + { + ServerAddr.SetPort(GetDefaultPort()); + } // Remove port const char *pColon = strchr(Server.getData(), ':'); if (pColon) @@ -657,7 +665,7 @@ bool C4Network2RefClient::GetReferences(C4Network2Reference **&rpReferences, int } // Set source ip for (int i = 0; i < rRefCount; i++) - rpReferences[i]->SetSourceIP(getServerAddress().sin_addr); + rpReferences[i]->SetSourceAddress(getServerAddress()); // Done ResetError(); return true; diff --git a/src/network/C4Network2Reference.h b/src/network/C4Network2Reference.h index f78abfea7..3a47c0409 100644 --- a/src/network/C4Network2Reference.h +++ b/src/network/C4Network2Reference.h @@ -60,9 +60,11 @@ private: // Network addresses uint8_t iAddrCnt; C4Network2Address Addrs[C4ClientMaxAddr]; + C4NetIO::EndpointAddress source; public: const C4Network2Address &getAddr(int i) const { return Addrs[i]; } + C4Network2Address &getAddr(int i) { return Addrs[i]; } int getAddrCnt() const { return iAddrCnt; } const char *getTitle() const { return Title.getData(); } int32_t getIcon() const { return Icon; } @@ -80,7 +82,8 @@ public: C4NetpuncherID_t getNetpuncherGameID() const { return NetpuncherGameID; } StdStrBuf getNetpuncherAddr() const { return NetpuncherAddr; } - void SetSourceIP(in_addr ip); + void SetSourceAddress(const C4NetIO::EndpointAddress &ip); + const C4NetIO::EndpointAddress &GetSourceAddress() const { return source; } void InitLocal(); diff --git a/src/script/C4AulDebug.cpp b/src/script/C4AulDebug.cpp index 2f57a6031..b3173a34e 100644 --- a/src/script/C4AulDebug.cpp +++ b/src/script/C4AulDebug.cpp @@ -33,7 +33,6 @@ C4AulDebug::C4AulDebug() : fInit(false), fConnected(false) { - ZeroMem(&PeerAddr, sizeof PeerAddr); } C4AulDebug::~C4AulDebug() @@ -125,15 +124,15 @@ bool C4AulDebug::OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t & // Already have a connection? if (fConnected) return false; // Check address - if (AllowedAddr.sin_addr.s_addr) - if (AllowedAddr.sin_addr.s_addr != AddrPeer.sin_addr.s_addr || - (AllowedAddr.sin_port && AllowedAddr.sin_port != AddrPeer.sin_port)) + if (!AllowedAddr.IsNull()) + if (AllowedAddr.GetHost() != AddrPeer.GetHost() || + (AllowedAddr.GetPort() && AllowedAddr.GetPort() != AddrPeer.GetPort())) { - LogF("C4AulDebug blocked connection from %s:%d", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port)); + LogF("C4AulDebug blocked connection from %s", AddrPeer.ToString().getData()); return false; } // Log - LogF("C4AulDebug got connection from %s:%d", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port)); + LogF("C4AulDebug got connection from %s", AddrPeer.ToString().getData()); // Accept connection PeerAddr = AddrPeer; return true; @@ -144,7 +143,7 @@ void C4AulDebug::OnDisconn(const C4NetIO::addr_t &AddrPeer, C4NetIO *pNetIO, con LogF("C4AulDebug lost connection (%s)", szReason); fConnected = false; eState = DS_Go; - ZeroMem(&PeerAddr, sizeof PeerAddr); + PeerAddr.Clear(); } void C4AulDebug::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) @@ -155,7 +154,7 @@ void C4AulDebug::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) bool C4AulDebug::SetAllowed(const char *szHost) { // Clear - ZeroMem(&AllowedAddr, sizeof(AllowedAddr)); + AllowedAddr.Clear(); // No host? if (!szHost || !*szHost) return true; // Resolve the address @@ -165,7 +164,7 @@ bool C4AulDebug::SetAllowed(const char *szHost) bool C4AulDebug::Init(uint16_t iPort) { if (fInit) Close(); - if (iPort == P_NONE) return false; + if (iPort == EndpointAddress::IPPORT_NONE) return false; // Register self as callback for network events C4NetIOTCP::SetCallback(this);