diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/network/network.cpp | 53 | ||||
-rw-r--r-- | src/core/network/network.h | 5 | ||||
-rw-r--r-- | src/core/network/network_interface.cpp | 111 | ||||
-rw-r--r-- | src/core/network/network_interface.h | 25 |
4 files changed, 169 insertions, 25 deletions
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 375bc79ec..9a4ac7e83 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -10,9 +10,10 @@ #include "common/common_funcs.h" #ifdef _WIN32 -#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname #include <winsock2.h> +#include <ws2tcpip.h> #elif YUZU_UNIX +#include <arpa/inet.h> #include <errno.h> #include <fcntl.h> #include <netdb.h> @@ -27,7 +28,9 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "common/settings.h" #include "core/network/network.h" +#include "core/network/network_interface.h" #include "core/network/sockets.h" namespace Network { @@ -182,7 +185,7 @@ linger MakeLinger(bool enable, u32 linger_value) { } bool EnableNonBlock(int fd, bool enable) { - int flags = fcntl(fd, F_GETFD); + int flags = fcntl(fd, F_GETFL); if (flags == -1) { return false; } @@ -191,7 +194,7 @@ bool EnableNonBlock(int fd, bool enable) { } else { flags &= ~O_NONBLOCK; } - return fcntl(fd, F_SETFD, flags) == 0; + return fcntl(fd, F_SETFL, flags) == 0; } Errno TranslateNativeError(int e) { @@ -227,8 +230,12 @@ Errno GetAndLogLastError() { #else int e = errno; #endif + const Errno err = TranslateNativeError(e); + if (err == Errno::AGAIN) { + return err; + } LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e)); - return TranslateNativeError(e); + return err; } int TranslateDomain(Domain domain) { @@ -353,27 +360,27 @@ NetworkInstance::~NetworkInstance() { Finalize(); } -std::pair<IPv4Address, Errno> GetHostIPv4Address() { - std::array<char, 256> name{}; - if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) { - return {IPv4Address{}, GetAndLogLastError()}; - } +std::optional<IPv4Address> GetHostIPv4Address() { + const std::string& selected_network_interface = Settings::values.network_interface.GetValue(); + const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); + ASSERT_MSG(network_interfaces.size() > 0, + "GetAvailableNetworkInterfaces returned no interfaces"); - hostent* const ent = gethostbyname(name.data()); - if (!ent) { - return {IPv4Address{}, GetAndLogLastError()}; - } - if (ent->h_addr_list == nullptr) { - UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list"); - return {IPv4Address{}, Errno::SUCCESS}; - } - if (ent->h_length != sizeof(in_addr)) { - UNIMPLEMENTED_MSG("Unexpected size={} in hostent->h_length", ent->h_length); - } + const auto res = std::ranges::find_if(network_interfaces, + [&selected_network_interface](const auto& interface) { + return interface.name == selected_network_interface; + }); + + if (res != network_interfaces.end()) { + char ip_addr[16]; + ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr); + LOG_INFO(Network, "IP address: {}", ip_addr); - in_addr addr; - std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr)); - return {TranslateIPv4(addr), Errno::SUCCESS}; + return TranslateIPv4(res->ip_address); + } else { + LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface); + return {}; + } } std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { diff --git a/src/core/network/network.h b/src/core/network/network.h index bd30f1899..cfa68d478 100644 --- a/src/core/network/network.h +++ b/src/core/network/network.h @@ -5,6 +5,7 @@ #pragma once #include <array> +#include <optional> #include <utility> #include "common/common_funcs.h" @@ -93,7 +94,7 @@ public: }; /// @brief Returns host's IPv4 address -/// @return Pair of an array of human ordered IPv4 address (e.g. 192.168.0.1) and an error code -std::pair<IPv4Address, Errno> GetHostIPv4Address(); +/// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array +std::optional<IPv4Address> GetHostIPv4Address(); } // namespace Network diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp new file mode 100644 index 000000000..2b53682ea --- /dev/null +++ b/src/core/network/network_interface.cpp @@ -0,0 +1,111 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <vector> + +#include "common/common_types.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/network/network_interface.h" + +#ifdef _WIN32 +#include <iphlpapi.h> +#else +#include <cerrno> +#include <ifaddrs.h> +#include <net/if.h> +#endif + +namespace Network { + +#ifdef _WIN32 + +std::vector<NetworkInterface> GetAvailableNetworkInterfaces() { + std::vector<NetworkInterface> result; + + std::vector<u8> adapter_addresses_raw; + auto adapter_addresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_addresses_raw.data()); + DWORD ret = ERROR_BUFFER_OVERFLOW; + DWORD buf_size = 0; + + // retry up to 5 times + for (int i = 0; i < 5 && ret == ERROR_BUFFER_OVERFLOW; i++) { + ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, + nullptr, adapter_addresses, &buf_size); + + if (ret == ERROR_BUFFER_OVERFLOW) { + adapter_addresses_raw.resize(buf_size); + adapter_addresses = + reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_addresses_raw.data()); + } else { + break; + } + } + + if (ret == NO_ERROR) { + for (auto current_address = adapter_addresses; current_address != nullptr; + current_address = current_address->Next) { + if (current_address->FirstUnicastAddress == nullptr || + current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) { + continue; + } + + if (current_address->OperStatus != IfOperStatusUp) { + continue; + } + + const auto ip_addr = std::bit_cast<struct sockaddr_in>( + *current_address->FirstUnicastAddress->Address.lpSockaddr) + .sin_addr; + + result.push_back(NetworkInterface{ + .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})}, + .ip_address{ip_addr}}); + } + } else { + LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses"); + } + + return result; +} + +#else + +std::vector<NetworkInterface> GetAvailableNetworkInterfaces() { + std::vector<NetworkInterface> result; + + struct ifaddrs* ifaddr = nullptr; + + if (getifaddrs(&ifaddr) != 0) { + LOG_ERROR(Network, "Failed to get network interfaces with getifaddrs: {}", + std::strerror(errno)); + return result; + } + + for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == nullptr) { + continue; + } + + if (ifa->ifa_addr->sa_family != AF_INET) { + continue; + } + + if (!(ifa->ifa_flags & IFF_UP) || ifa->ifa_flags & IFF_LOOPBACK) { + continue; + } + + result.push_back(NetworkInterface{ + .name{ifa->ifa_name}, + .ip_address{std::bit_cast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr}}); + } + + freeifaddrs(ifaddr); + + return result; +} + +#endif + +} // namespace Network diff --git a/src/core/network/network_interface.h b/src/core/network/network_interface.h new file mode 100644 index 000000000..d7184e14a --- /dev/null +++ b/src/core/network/network_interface.h @@ -0,0 +1,25 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include <vector> + +#ifdef _WIN32 +#include <winsock2.h> +#else +#include <netinet/in.h> +#endif + +namespace Network { + +struct NetworkInterface { + std::string name; + struct in_addr ip_address; +}; + +std::vector<NetworkInterface> GetAvailableNetworkInterfaces(); + +} // namespace Network |