summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/nifm/nifm.cpp36
-rw-r--r--src/core/network/network.cpp43
-rw-r--r--src/core/network/network.h5
-rw-r--r--src/core/network/network_interface.cpp113
-rw-r--r--src/core/network/network_interface.h25
6 files changed, 187 insertions, 37 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 5c99c00f5..f5cf5c16a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -636,6 +636,8 @@ add_library(core STATIC
memory.h
network/network.cpp
network/network.h
+ network/network_interface.cpp
+ network/network_interface.h
network/sockets.h
perf_stats.cpp
perf_stats.h
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 5ef574d20..168053d80 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -179,10 +179,10 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- if (Settings::values.bcat_backend.GetValue() == "none") {
- rb.PushEnum(RequestState::NotSubmitted);
- } else {
+ if (Network::GetHostIPv4Address().has_value()) {
rb.PushEnum(RequestState::Connected);
+ } else {
+ rb.PushEnum(RequestState::NotSubmitted);
}
}
@@ -322,12 +322,15 @@ private:
void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
- const auto [ipv4, error] = Network::GetHostIPv4Address();
- UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS);
+ auto ipv4 = Network::GetHostIPv4Address();
+ if (!ipv4) {
+ LOG_CRITICAL(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0");
+ ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
+ }
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.PushRaw(ipv4);
+ rb.PushRaw(ipv4.value());
}
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
@@ -354,13 +357,16 @@ private:
static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
"IpConfigInfo has incorrect size.");
- const auto [ipv4, error] = Network::GetHostIPv4Address();
- ASSERT_MSG(error == Network::Errno::SUCCESS, "Couldn't get host IPv4 address");
+ auto ipv4 = Network::GetHostIPv4Address();
+ if (!ipv4) {
+ LOG_CRITICAL(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0");
+ ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
+ }
const IpConfigInfo ip_config_info{
.ip_address_setting{
.is_automatic{true},
- .current_address{ipv4},
+ .current_address{ipv4.value()},
.subnet_mask{255, 255, 255, 0},
.gateway{192, 168, 1, 1},
},
@@ -387,10 +393,10 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- if (Settings::values.bcat_backend.GetValue() == "none") {
- rb.Push<u8>(0);
- } else {
+ if (Network::GetHostIPv4Address().has_value()) {
rb.Push<u8>(1);
+ } else {
+ rb.Push<u8>(0);
}
}
void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
@@ -398,10 +404,10 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- if (Settings::values.bcat_backend.GetValue() == "none") {
- rb.Push<u8>(0);
- } else {
+ if (Network::GetHostIPv4Address().has_value()) {
rb.Push<u8>(1);
+ } else {
+ rb.Push<u8>(0);
}
}
};
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index 7b038041e..67ecf57bd 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -10,8 +10,8 @@
#include "common/common_funcs.h"
#ifdef _WIN32
-#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
#include <winsock2.h>
+#include <ws2tcpip.h>
#elif YUZU_UNIX
#include <errno.h>
#include <fcntl.h>
@@ -19,6 +19,7 @@
#include <netinet/in.h>
#include <poll.h>
#include <sys/socket.h>
+#include <arpa/inet.h>
#include <unistd.h>
#else
#error "Unimplemented platform"
@@ -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 {
@@ -357,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);
- }
- in_addr addr;
- std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr));
- return {TranslateIPv4(addr), Errno::SUCCESS};
+ 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);
+
+ 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..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
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