From 758e7ca41e06c32236862c9f0440bf8ad81bc9bc Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Fri, 6 Jan 2017 21:47:44 +0100 Subject: [PATCH] Change (discovery) multicast to IPv6 We use ff02::1 as discovery multicast address. This "all nodes" multicast address is good enough for discovery in the local network as packets there are likely broadcasted over ethernet anyways. --- src/network/C4NetIO.cpp | 32 ++++++++++++++++++++---------- src/network/C4NetIO.h | 6 +++--- src/network/C4Network2Discover.cpp | 11 ++++++++++ src/network/C4Network2Discover.h | 2 +- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/network/C4NetIO.cpp b/src/network/C4NetIO.cpp index a341b1d1c..38675631a 100644 --- a/src/network/C4NetIO.cpp +++ b/src/network/C4NetIO.cpp @@ -356,6 +356,17 @@ void C4NetIO::HostAddress::SetHost(uint32_t v4addr) memset(&v4.sin_zero, 0, sizeof(v4.sin_zero)); } +void C4NetIO::HostAddress::SetHost(const StdStrBuf &addr) +{ + addrinfo hints = addrinfo(); + addrinfo *addresses = nullptr; + if (getaddrinfo(addr.getData(), nullptr, &hints, &addresses) != 0) + // GAI failed + return; + SetHost(addresses->ai_addr); + freeaddrinfo(addresses); +} + void C4NetIO::EndpointAddress::SetAddress(const StdStrBuf &addr) { Clear(); @@ -1767,7 +1778,7 @@ bool C4NetIOSimpleUDP::InitBroadcast(addr_t *pBroadcastAddr) if (fMultiCast) CloseBroadcast(); // broadcast addr valid? - if (pBroadcastAddr->IsMulticast()) + if (!pBroadcastAddr->IsMulticast()) { SetError("invalid broadcast address"); return false; @@ -1779,8 +1790,8 @@ bool C4NetIOSimpleUDP::InitBroadcast(addr_t *pBroadcastAddr) } // set mc ttl to somewhat about "same net" - int iTTL = 16; - if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, reinterpret_cast(&iTTL), sizeof(iTTL)) == SOCKET_ERROR) + int TTL = 16; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, reinterpret_cast(&TTL), sizeof(TTL)) == SOCKET_ERROR) { SetError("could not set mc ttl", true); return false; @@ -1788,11 +1799,12 @@ bool C4NetIOSimpleUDP::InitBroadcast(addr_t *pBroadcastAddr) // set up multicast group information this->MCAddr = *pBroadcastAddr; - MCGrpInfo.imr_multiaddr = static_cast(&MCAddr)->sin_addr; - MCGrpInfo.imr_interface.s_addr = INADDR_ANY; + MCGrpInfo.ipv6mr_multiaddr = static_cast(MCAddr).sin6_addr; + // TODO: do multicast on all interfaces? + MCGrpInfo.ipv6mr_interface = 0; // default interface // join multicast group - if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, reinterpret_cast(&MCGrpInfo), sizeof(MCGrpInfo)) == SOCKET_ERROR) { SetError("could not join multicast group"); // to do: more error information @@ -1854,10 +1866,10 @@ bool C4NetIOSimpleUDP::CloseBroadcast() if (!fMultiCast) return true; // leave multicast group - if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, + if (setsockopt(sock, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, reinterpret_cast(&MCGrpInfo), sizeof(MCGrpInfo)) == SOCKET_ERROR) { - SetError("could not join multicast group"); // to do: more error information + SetError("could not leave multicast group"); // to do: more error information return false; } @@ -2059,10 +2071,10 @@ enum C4NetIOSimpleUDP::WaitResult C4NetIOSimpleUDP::WaitForSocket(int iTimeout) bool C4NetIOSimpleUDP::SetMCLoopback(int fLoopback) { // enable/disable MC loopback - setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, reinterpret_cast(&fLoopback), sizeof fLoopback); + setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, reinterpret_cast(&fLoopback), sizeof fLoopback); // read result socklen_t iSize = sizeof(fLoopback); - if (getsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, reinterpret_cast(&fLoopback), &iSize) == SOCKET_ERROR) + if (getsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, reinterpret_cast(&fLoopback), &iSize) == SOCKET_ERROR) return false; fMCLoopback = !! fLoopback; return true; diff --git a/src/network/C4NetIO.h b/src/network/C4NetIO.h index 7837dcc1d..35349504f 100644 --- a/src/network/C4NetIO.h +++ b/src/network/C4NetIO.h @@ -193,8 +193,8 @@ public: // 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; }*/ + 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); @@ -533,7 +533,7 @@ private: #endif // multicast - addr_t MCAddr; ip_mreq MCGrpInfo; + addr_t MCAddr; ipv6_mreq MCGrpInfo; bool fMCLoopback; // multibind diff --git a/src/network/C4Network2Discover.cpp b/src/network/C4Network2Discover.cpp index 9f35d5711..b9346dd07 100644 --- a/src/network/C4Network2Discover.cpp +++ b/src/network/C4Network2Discover.cpp @@ -17,6 +17,17 @@ #include "network/C4Network2Discover.h" // *** C4Network2IODiscover +// +// Quick multicast discovery guide by Luchs: +// +// All engines in network mode join a multicast group (defined by C4NetDiscoveryAddress). +// +// Engines searching for a game ("client") send a single byte c = 3 to that multicast group. This +// happens while on the network list on each refresh. +// +// Engines hosting a game (when going into the lobby) send a byte c = 4 plus their reference server +// port to the multicast group. Additionally, they listen for the c = 3 bytes and will reply with +// another multicast answer. struct C4Network2IODiscoverReply { diff --git a/src/network/C4Network2Discover.h b/src/network/C4Network2Discover.h index 6ae405c42..01d3572fd 100644 --- a/src/network/C4Network2Discover.h +++ b/src/network/C4Network2Discover.h @@ -20,7 +20,7 @@ const int C4NetMaxDiscover = 64; -const C4NetIO::HostAddress C4NetDiscoveryAddress = C4NetIO::HostAddress(0xef000000); // 239.0.0.0 +const C4NetIO::HostAddress C4NetDiscoveryAddress = C4NetIO::HostAddress(StdStrBuf("ff02::1")); class C4Network2IODiscover : public C4NetIOSimpleUDP, private C4NetIO::CBClass {