From 3ce271991ba0c258eea1746b698f8ba472458c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 19 Apr 2018 19:02:15 +0200 Subject: [PATCH] IOS/SO: Implement GetSystemDefaultInterface for non-Windows This fixes gethostid on non-Windows platforms. Except on Android, where this is left unimplemented because Android does not support getifaddrs. --- Source/Core/Core/IOS/Network/IP/Top.cpp | 50 ++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/IOS/Network/IP/Top.cpp b/Source/Core/Core/IOS/Network/IP/Top.cpp index 2081b3a595..ce418cf7fe 100644 --- a/Source/Core/Core/IOS/Network/IP/Top.cpp +++ b/Source/Core/Core/IOS/Network/IP/Top.cpp @@ -22,6 +22,7 @@ #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Common/Network.h" +#include "Common/ScopeGuard.h" #include "Common/StringUtil.h" #include "Core/Core.h" @@ -37,16 +38,12 @@ #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) -#elif defined(__linux__) or defined(__APPLE__) -#include -#include - -typedef struct pollfd pollfd_t; #else -#include +#include #include #include #include +#include #endif // WSAPoll doesn't support POLLPRI and POLLWRBAND flags @@ -212,6 +209,47 @@ static std::optional GetSystemDefaultInterface() return DefaultInterface{entry.dwAddr, entry.dwMask, entry.dwBCastAddr}; } } +#elif !defined(__ANDROID__) + // Assume that the address that is used to access the Internet corresponds + // to the default interface. + auto get_default_address = []() -> std::optional { + const int sock = socket(AF_INET, SOCK_DGRAM, 0); + Common::ScopeGuard sock_guard{[sock] { close(sock); }}; + + sockaddr_in addr{}; + socklen_t length = sizeof(addr); + addr.sin_family = AF_INET; + // The address is irrelevant -- no packet is actually sent. This just needs to be a public IP. + addr.sin_addr.s_addr = inet_addr(8, 8, 8, 8); + if (connect(sock, reinterpret_cast(&addr), sizeof(addr)) == -1) + return {}; + if (getsockname(sock, reinterpret_cast(&addr), &length) == -1) + return {}; + return addr.sin_addr; + }; + + auto get_addr = [](const sockaddr* addr) { + return reinterpret_cast(addr)->sin_addr.s_addr; + }; + + const auto default_interface_address = get_default_address(); + if (!default_interface_address) + return {}; + + ifaddrs* iflist; + if (getifaddrs(&iflist) != 0) + return {}; + Common::ScopeGuard iflist_guard{[iflist] { freeifaddrs(iflist); }}; + + for (const ifaddrs* iface = iflist; iface; iface = iface->ifa_next) + { + if (iface->ifa_addr && iface->ifa_addr->sa_family == AF_INET && + get_addr(iface->ifa_addr) == default_interface_address->s_addr) + { + return DefaultInterface{get_addr(iface->ifa_addr), get_addr(iface->ifa_netmask), + get_addr(iface->ifa_broadaddr)}; + } + } #endif return {}; }