summaryrefslogtreecommitdiffstats
path: root/src/core/network/network_interface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/network/network_interface.cpp')
-rw-r--r--src/core/network/network_interface.cpp113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp
new file mode 100644
index 000000000..bba4c8b26
--- /dev/null
+++ b/src/core/network/network_interface.cpp
@@ -0,0 +1,113 @@
+// 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 <ifaddrs.h>
+#include <net/if.h>
+#include <cerrno>
+#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