forked from Mirrors/openclonk
Change C4NetIOUDP broadcast to IPv6
It's not actually used anywhere, but it's not broken now! This also moves the low-level and OS-specific GetLocalAddresses code to C4NetIO where it's fitting better than in C4Network2Client.ipv6
parent
fd857ef771
commit
76327b62a7
|
@ -31,6 +31,8 @@
|
|||
|
||||
#include <process.h>
|
||||
#include <share.h>
|
||||
#include <winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
|
||||
typedef int socklen_t;
|
||||
int pipe(int *phandles) { return _pipe(phandles, 10, O_BINARY); }
|
||||
|
@ -43,6 +45,8 @@ int pipe(int *phandles) { return _pipe(phandles, 10, O_BINARY); }
|
|||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <stdlib.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#define ioctlsocket ioctl
|
||||
#define closesocket close
|
||||
|
@ -50,7 +54,6 @@ int pipe(int *phandles) { return _pipe(phandles, 10, O_BINARY); }
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable : 4355)
|
||||
#endif
|
||||
|
@ -591,6 +594,66 @@ void C4NetIO::EndpointAddress::CompileFunc(StdCompiler *comp)
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<C4NetIO::HostAddress> C4NetIO::GetLocalAddresses()
|
||||
{
|
||||
std::vector<HostAddress> result;
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
HostAddress addr;
|
||||
const size_t BUFFER_SIZE = 16000;
|
||||
PIP_ADAPTER_ADDRESSES addresses = nullptr;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
addresses = (PIP_ADAPTER_ADDRESSES) realloc(addresses, BUFFER_SIZE * (i+1));
|
||||
if (!addresses)
|
||||
// allocation failed
|
||||
return result;
|
||||
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)
|
||||
{
|
||||
// Something else happened
|
||||
free(addresses);
|
||||
return result;
|
||||
}
|
||||
// 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;
|
||||
result.push_back(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(addresses);
|
||||
#else
|
||||
struct ifaddrs* addrs;
|
||||
if (getifaddrs(&addrs) < 0)
|
||||
return result;
|
||||
for (struct ifaddrs* ifaddr = addrs; ifaddr != nullptr; ifaddr = ifaddr->ifa_next)
|
||||
{
|
||||
struct sockaddr* ad = ifaddr->ifa_addr;
|
||||
if (ad == nullptr) continue;
|
||||
|
||||
if ((ad->sa_family == AF_INET || ad->sa_family == AF_INET6) && (~ifaddr->ifa_flags & IFF_LOOPBACK)) // Choose only non-loopback IPv4/6 devices
|
||||
{
|
||||
result.emplace_back(ad);
|
||||
}
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// *** C4NetIO
|
||||
|
||||
// construction / destruction
|
||||
|
@ -1802,9 +1865,9 @@ bool C4NetIOSimpleUDP::InitBroadcast(addr_t *pBroadcastAddr)
|
|||
if (fMultiCast) CloseBroadcast();
|
||||
|
||||
// broadcast addr valid?
|
||||
if (!pBroadcastAddr->IsMulticast())
|
||||
if (!pBroadcastAddr->IsMulticast() || pBroadcastAddr->GetFamily() != HostAddress::IPv6)
|
||||
{
|
||||
SetError("invalid broadcast address");
|
||||
SetError("invalid broadcast address (only IPv6 multicast addresses are supported)");
|
||||
return false;
|
||||
}
|
||||
if (pBroadcastAddr->GetPort() != iPort)
|
||||
|
@ -2260,13 +2323,40 @@ bool C4NetIOUDP::InitBroadcast(addr_t *pBroadcastAddr)
|
|||
SetError("broadcast address is not valid");
|
||||
return false;
|
||||
}
|
||||
// set up adress
|
||||
MCAddr.SetAddress(addr_t::AnyIPv4, iPort);
|
||||
// search for a free one
|
||||
// Set up address as unicast-prefix-based IPv6 multicast address (RFC 3306).
|
||||
sockaddr_in6 saddrgen = sockaddr_in6();
|
||||
saddrgen.sin6_family = AF_INET6;
|
||||
uint8_t *addrgen = saddrgen.sin6_addr.s6_addr;
|
||||
// ff3e ("global multicast based on network prefix") : 64 (length of network prefix)
|
||||
static const uint8_t mcast_prefix[4] = { 0xff, 0x3e, 0, 64};
|
||||
memcpy(addrgen, mcast_prefix, sizeof(mcast_prefix));
|
||||
addrgen += sizeof(mcast_prefix);
|
||||
// 64 bit network prefix
|
||||
addr_t prefixAddr;
|
||||
for (auto& addr : GetLocalAddresses())
|
||||
if (addr.GetFamily() == HostAddress::IPv6 && !addr.IsLocal())
|
||||
{
|
||||
prefixAddr.SetAddress(addr);
|
||||
break;
|
||||
}
|
||||
if (prefixAddr.IsNull())
|
||||
{
|
||||
SetError("no IPv6 unicast address available");
|
||||
return false;
|
||||
}
|
||||
static const size_t network_prefix_size = 8;
|
||||
memcpy(addrgen, &static_cast<sockaddr_in6*>(&prefixAddr)->sin6_addr, network_prefix_size);
|
||||
addrgen += network_prefix_size;
|
||||
// 32 bit group id: search for a free one
|
||||
for (int iRetries = 1000; iRetries; iRetries--)
|
||||
{
|
||||
uint32_t rnd = UnsyncedRandom();
|
||||
memcpy(addrgen, &rnd, sizeof(rnd));
|
||||
// "high-order bit of the Group ID will be the same value as the T flag"
|
||||
addrgen[0] |= 0x80;
|
||||
// create new - random - address
|
||||
MCAddr.SetAddress(C4NetIO::HostAddress(0x000000ef | (UnsyncedRandom(0x1000000) << 8)));
|
||||
MCAddr.SetAddress((sockaddr*) &saddrgen);
|
||||
MCAddr.SetPort(iPort);
|
||||
// init broadcast
|
||||
if (!C4NetIOSimpleUDP::InitBroadcast(&MCAddr))
|
||||
return false;
|
||||
|
|
|
@ -92,6 +92,7 @@ public:
|
|||
HostAddress(SpecialAddress addr) { SetHost(addr); }
|
||||
explicit HostAddress(uint32_t addr) { SetHost(addr); }
|
||||
HostAddress(const StdStrBuf &addr) { SetHost(addr); }
|
||||
HostAddress(const sockaddr *addr) { SetHost(addr); }
|
||||
|
||||
AddressFamily GetFamily() const;
|
||||
|
||||
|
@ -209,6 +210,8 @@ public:
|
|||
};
|
||||
typedef EndpointAddress addr_t;
|
||||
|
||||
static std::vector<HostAddress> GetLocalAddresses();
|
||||
|
||||
// callback class
|
||||
class CBClass
|
||||
{
|
||||
|
|
|
@ -25,16 +25,6 @@
|
|||
#include "game/C4Game.h"
|
||||
#include "player/C4PlayerList.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
// *** C4Network2Client
|
||||
|
||||
C4Network2Client::C4Network2Client(C4Client *pClient)
|
||||
|
@ -187,84 +177,24 @@ bool C4Network2Client::AddAddr(const C4Network2Address &addr, bool fAnnounce)
|
|||
|
||||
void C4Network2Client::AddLocalAddrs(int16_t iPortTCP, int16_t iPortUDP)
|
||||
{
|
||||
// set up address struct
|
||||
C4NetIO::addr_t addr;
|
||||
|
||||
// get local address(es)
|
||||
#ifdef HAVE_WINSOCK
|
||||
const size_t BUFFER_SIZE = 16000;
|
||||
PIP_ADAPTER_ADDRESSES addresses = nullptr;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
for (auto& ha : C4NetIO::GetLocalAddresses())
|
||||
{
|
||||
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)
|
||||
addr.SetAddress(ha);
|
||||
if (iPortTCP)
|
||||
{
|
||||
// Something else happened
|
||||
free(addresses);
|
||||
return;
|
||||
addr.SetPort(iPortTCP);
|
||||
AddAddr(C4Network2Address(addr, P_TCP), false);
|
||||
}
|
||||
// All okay, add addresses
|
||||
for (PIP_ADAPTER_ADDRESSES address = addresses; address; address = address->Next)
|
||||
if (iPortUDP)
|
||||
{
|
||||
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);
|
||||
}
|
||||
if (addr.GetScopeId())
|
||||
InterfaceIDs.insert(addr.GetScopeId());
|
||||
}
|
||||
addr.SetPort(iPortUDP);
|
||||
AddAddr(C4Network2Address(addr, P_UDP), false);
|
||||
}
|
||||
if (addr.GetScopeId())
|
||||
InterfaceIDs.insert(addr.GetScopeId());
|
||||
}
|
||||
free(addresses);
|
||||
#else
|
||||
struct ifaddrs* addrs;
|
||||
if (getifaddrs(&addrs) < 0)
|
||||
return;
|
||||
for (struct ifaddrs* ifaddr = addrs; ifaddr != nullptr; ifaddr = ifaddr->ifa_next)
|
||||
{
|
||||
struct sockaddr* ad = ifaddr->ifa_addr;
|
||||
if (ad == nullptr) continue;
|
||||
|
||||
if ((ad->sa_family == AF_INET || ad->sa_family == AF_INET6) && (~ifaddr->ifa_flags & IFF_LOOPBACK)) // Choose only non-loopback IPv4/6 devices
|
||||
{
|
||||
addr.SetHost(ad);
|
||||
if (iPortTCP >= 0)
|
||||
{
|
||||
addr.SetPort(iPortTCP);
|
||||
AddAddr(C4Network2Address(addr, P_TCP), false);
|
||||
}
|
||||
if (iPortUDP >= 0)
|
||||
{
|
||||
addr.SetPort(iPortUDP);
|
||||
AddAddr(C4Network2Address(addr, P_UDP), false);
|
||||
}
|
||||
if (addr.GetScopeId())
|
||||
InterfaceIDs.insert(addr.GetScopeId());
|
||||
}
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
#endif
|
||||
}
|
||||
|
||||
void C4Network2Client::SendAddresses(C4Network2IOConnection *pConn)
|
||||
|
|
Loading…
Reference in New Issue