From 780a37965bce3201228221b55f5b025ddf6285af Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Sun, 21 Oct 2018 20:52:24 +0100 Subject: [PATCH] Implement IDirectPlay8Peer::GetLocalHostAddresses() method --- build.bat | 4 +-- src/DirectPlay8Peer.cpp | 59 +++++++++++++++++++++++++++++++++++- src/network.cpp | 66 +++++++++++++++++++++++++++++++++++++++++ src/network.hpp | 10 +++++++ 4 files changed, 136 insertions(+), 3 deletions(-) diff --git a/build.bat b/build.bat index cc87753..db56084 100644 --- a/build.bat +++ b/build.bat @@ -58,7 +58,7 @@ SET TEST_OBJS=^ tests/PacketSerialiser.obj^ tests/SendQueue.obj -SET TEST_LIBS=ws2_32.lib dxguid.lib ole32.lib +SET TEST_LIBS=ws2_32.lib dxguid.lib ole32.lib iphlpapi.lib SET HOOK_DLLS=ddraw @@ -81,7 +81,7 @@ SET HOOK_OBJS=^ src/packet.obj^ src/SendQueue.obj -SET HOOK_LIBS=ws2_32.lib dxguid.lib ole32.lib +SET HOOK_LIBS=ws2_32.lib dxguid.lib ole32.lib iphlpapi.lib SET CFLAGS=^ /Zi^ diff --git a/src/DirectPlay8Peer.cpp b/src/DirectPlay8Peer.cpp index 5d7bb31..5638d39 100644 --- a/src/DirectPlay8Peer.cpp +++ b/src/DirectPlay8Peer.cpp @@ -1567,7 +1567,64 @@ HRESULT DirectPlay8Peer::GetPeerAddress(CONST DPNID dpnid, IDirectPlay8Address** HRESULT DirectPlay8Peer::GetLocalHostAddresses(IDirectPlay8Address** CONST prgpAddress, DWORD* CONST pcAddress, CONST DWORD dwFlags) { - UNIMPLEMENTED("DirectPlay8Peer::GetLocalHostAddresses"); + std::unique_lock l(lock); + + switch(state) + { + case STATE_NEW: return DPNERR_UNINITIALIZED; + case STATE_INITIALISED: return DPNERR_NOCONNECTION; + case STATE_HOSTING: break; + case STATE_CONNECTING_TO_HOST: return DPNERR_NOCONNECTION; + case STATE_CONNECTING_TO_PEERS: return DPNERR_NOCONNECTION; + case STATE_CONNECT_FAILED: return DPNERR_NOCONNECTION; + case STATE_CONNECTED: return DPNERR_NOTHOST; + case STATE_CLOSING: return DPNERR_NOCONNECTION; + case STATE_TERMINATED: return DPNERR_NOCONNECTION; + } + + if(dwFlags & DPNGETLOCALHOSTADDRESSES_COMBINED) + { + /* TODO: Implement DPNGETLOCALHOSTADDRESSES_COMBINED */ + return E_NOTIMPL; + } + + /* We don't support binding to specific interfaces yet, so we just return all the IPv4 + * addresses assigned to the system. + */ + + std::list interfaces = get_network_interfaces(); + std::list local_addrs; + + for(auto i = interfaces.begin(); i != interfaces.end(); ++i) + { + for(auto a = i->unicast_addrs.begin(); a != i->unicast_addrs.end(); ++a) + { + if(a->ss_family == AF_INET) + { + struct sockaddr_in sa_v4 = *(struct sockaddr_in*)(&(*a)); + sa_v4.sin_port = htons(local_port); + + local_addrs.push_back(sa_v4); + } + } + } + + if(*pcAddress < local_addrs.size()) + { + *pcAddress = local_addrs.size(); + return DPNERR_BUFFERTOOSMALL; + } + + IDirectPlay8Address **dest = prgpAddress; + for(auto a = local_addrs.begin(); a != local_addrs.end(); ++a) + { + *dest = DirectPlay8Address::create_host_address(global_refcount, service_provider, (struct sockaddr*)(&(*a))); + ++dest; + } + + *pcAddress = local_addrs.size(); + + return S_OK; } HRESULT DirectPlay8Peer::Close(CONST DWORD dwFlags) diff --git a/src/network.cpp b/src/network.cpp index 29a9807..b301014 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -1,10 +1,13 @@ #include +#include #include #include #include #include +#include #include "network.hpp" +#include "log.hpp" int create_udp_socket(uint32_t ipaddr, uint16_t port) { @@ -173,3 +176,66 @@ int create_discovery_socket() return sock; } + +std::list get_network_interfaces() +{ + std::vector buf; + + while(1) + { + ULONG size = buf.size(); + ULONG err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, (IP_ADAPTER_ADDRESSES*)(buf.data()), &size); + + if(err == ERROR_SUCCESS) + { + break; + } + else if(err == ERROR_NO_DATA) + { + return std::list(); + } + else if(err == ERROR_BUFFER_OVERFLOW) + { + buf.resize(size); + } + else{ + log_printf("GetAdaptersAddresses: %s", win_strerror(err).c_str()); + return std::list(); + } + } + + std::list interfaces; + + for(IP_ADAPTER_ADDRESSES *ipaa = (IP_ADAPTER_ADDRESSES*)(buf.data()); ipaa != NULL; ipaa = ipaa->Next) + { + if(ipaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK) + { + continue; + } + + SystemNetworkInterface iface; + + iface.friendly_name = ipaa->FriendlyName; + + for(IP_ADAPTER_UNICAST_ADDRESS_LH *uc = ipaa->FirstUnicastAddress; uc != NULL; uc = uc->Next) + { + if(uc->Address.iSockaddrLength > sizeof(struct sockaddr_storage)) + { + log_printf("Ignoring oversize address (family = %u, size = %u)", + (unsigned)(uc->Address.lpSockaddr->sa_family), + (unsigned)(uc->Address.iSockaddrLength)); + continue; + } + + struct sockaddr_storage ss; + memset(&ss, 0, sizeof(ss)); + memcpy(&ss, uc->Address.lpSockaddr, uc->Address.iSockaddrLength); + + iface.unicast_addrs.push_back(ss); + } + + interfaces.push_back(iface); + } + + return interfaces; +} diff --git a/src/network.hpp b/src/network.hpp index f22c53e..3f53c56 100644 --- a/src/network.hpp +++ b/src/network.hpp @@ -1,16 +1,26 @@ #ifndef DPLITE_NETWORK_HPP #define DPLITE_NETWORK_HPP +#include +#include #include +#include #define DISCOVERY_PORT 6073 #define DEFAULT_HOST_PORT 6072 #define LISTEN_QUEUE_SIZE 16 #define MAX_PACKET_SIZE (60 * 1024) +struct SystemNetworkInterface { + std::wstring friendly_name; + + std::list unicast_addrs; +}; + int create_udp_socket(uint32_t ipaddr, uint16_t port); int create_listener_socket(uint32_t ipaddr, uint16_t port); int create_client_socket(uint32_t local_ipaddr, uint16_t local_port); int create_discovery_socket(); +std::list get_network_interfaces(); #endif /* !DPLITE_NETWORK_HPP */