summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/common/settings.h3
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/nifm/nifm.cpp45
-rw-r--r--src/core/network/network.cpp64
-rw-r--r--src/core/network/network.h24
-rw-r--r--src/core/network/network_interface.cpp203
-rw-r--r--src/core/network/network_interface.h29
-rw-r--r--src/yuzu/CMakeLists.txt6
-rw-r--r--src/yuzu/configuration/config.cpp6
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure.ui10
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp4
-rw-r--r--src/yuzu/configuration/configure_network.cpp (renamed from src/yuzu/configuration/configure_service.cpp)39
-rw-r--r--src/yuzu/configuration/configure_network.h (renamed from src/yuzu/configuration/configure_service.h)10
-rw-r--r--src/yuzu/configuration/configure_network.ui (renamed from src/yuzu/configuration/configure_service.ui)63
16 files changed, 409 insertions, 103 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 826bc42c0..0e064ab44 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -701,7 +701,7 @@ if (APPLE)
elseif (WIN32)
# WSAPoll and SHGetKnownFolderPath (AppData/Roaming) didn't exist before WinNT 6.x (Vista)
add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600)
- set(PLATFORM_LIBRARIES winmm ws2_32)
+ set(PLATFORM_LIBRARIES winmm ws2_32 iphlpapi)
if (MINGW)
# PSAPI is the Process Status API
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
diff --git a/src/common/settings.h b/src/common/settings.h
index 1ba9b606c..c65746749 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -558,9 +558,10 @@ struct Values {
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
- // Services
+ // Network
BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
+ BasicSetting<std::string> network_interface{std::string(), "network_interface"};
// WebService
BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
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 e742db48f..0a53c0c81 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -11,6 +11,7 @@
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/service.h"
#include "core/network/network.h"
+#include "core/network/network_interface.h"
namespace Service::NIFM {
@@ -179,10 +180,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 +323,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_ERROR(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);
}
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
@@ -354,10 +358,10 @@ private:
static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
"IpConfigInfo has incorrect size.");
- const IpConfigInfo ip_config_info{
+ IpConfigInfo ip_config_info{
.ip_address_setting{
.is_automatic{true},
- .current_address{192, 168, 1, 100},
+ .current_address{0, 0, 0, 0},
.subnet_mask{255, 255, 255, 0},
.gateway{192, 168, 1, 1},
},
@@ -368,6 +372,19 @@ private:
},
};
+ const auto iface = Network::GetSelectedNetworkInterface();
+ if (iface) {
+ ip_config_info.ip_address_setting =
+ IpAddressSetting{.is_automatic{true},
+ .current_address{Network::TranslateIPv4(iface->ip_address)},
+ .subnet_mask{Network::TranslateIPv4(iface->subnet_mask)},
+ .gateway{Network::TranslateIPv4(iface->gateway)}};
+
+ } else {
+ LOG_ERROR(Service_NIFM,
+ "Couldn't get host network configuration info, using default values");
+ }
+
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
rb.Push(ResultSuccess);
rb.PushRaw<IpConfigInfo>(ip_config_info);
@@ -384,10 +401,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) {
@@ -395,10 +412,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 375bc79ec..4732d4485 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 {
@@ -47,11 +50,6 @@ void Finalize() {
WSACleanup();
}
-constexpr IPv4Address TranslateIPv4(in_addr addr) {
- auto& bytes = addr.S_un.S_un_b;
- return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
-}
-
sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
sockaddr_in result;
@@ -138,12 +136,6 @@ void Initialize() {}
void Finalize() {}
-constexpr IPv4Address TranslateIPv4(in_addr addr) {
- const u32 bytes = addr.s_addr;
- return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),
- static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)};
-}
-
sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
sockaddr_in result;
@@ -182,7 +174,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 +183,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 +219,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 +349,29 @@ 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();
+ if (network_interfaces.size() == 0) {
+ LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
+ return {};
}
- 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& iface) {
+ return iface.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..fdd3e4655 100644
--- a/src/core/network/network.h
+++ b/src/core/network/network.h
@@ -5,11 +5,18 @@
#pragma once
#include <array>
+#include <optional>
#include <utility>
#include "common/common_funcs.h"
#include "common/common_types.h"
+#ifdef _WIN32
+#include <winsock2.h>
+#elif YUZU_UNIX
+#include <netinet/in.h>
+#endif
+
namespace Network {
class Socket;
@@ -92,8 +99,21 @@ public:
~NetworkInstance();
};
+#ifdef _WIN32
+constexpr IPv4Address TranslateIPv4(in_addr addr) {
+ auto& bytes = addr.S_un.S_un_b;
+ return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
+}
+#elif YUZU_UNIX
+constexpr IPv4Address TranslateIPv4(in_addr addr) {
+ const u32 bytes = addr.s_addr;
+ return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),
+ static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)};
+}
+#endif
+
/// @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..cecc9aa11
--- /dev/null
+++ b/src/core/network/network_interface.cpp
@@ -0,0 +1,203 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <vector>
+
+#include "common/bit_cast.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "common/settings.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<IP_ADAPTER_ADDRESSES> adapter_addresses;
+ 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 | GAA_FLAG_INCLUDE_GATEWAYS,
+ nullptr, adapter_addresses.data(), &buf_size);
+
+ if (ret == ERROR_BUFFER_OVERFLOW) {
+ adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1);
+ } else {
+ break;
+ }
+ }
+
+ if (ret == NO_ERROR) {
+ std::vector<NetworkInterface> result;
+
+ for (auto current_address = adapter_addresses.data(); 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 = Common::BitCast<struct sockaddr_in>(
+ *current_address->FirstUnicastAddress->Address.lpSockaddr)
+ .sin_addr;
+
+ ULONG mask = 0;
+ if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength,
+ &mask) != NO_ERROR) {
+ LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask");
+ continue;
+ }
+
+ struct in_addr gateway = {.S_un{.S_addr{0}}};
+ if (current_address->FirstGatewayAddress != nullptr &&
+ current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) {
+ gateway = Common::BitCast<struct sockaddr_in>(
+ *current_address->FirstGatewayAddress->Address.lpSockaddr)
+ .sin_addr;
+ }
+
+ result.push_back(NetworkInterface{
+ .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
+ .ip_address{ip_addr},
+ .subnet_mask = in_addr{.S_un{.S_addr{mask}}},
+ .gateway = gateway});
+ }
+
+ return result;
+ } else {
+ LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
+ return {};
+ }
+}
+
+#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 || ifa->ifa_netmask == nullptr) {
+ continue;
+ }
+
+ if (ifa->ifa_addr->sa_family != AF_INET) {
+ continue;
+ }
+
+ if ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) {
+ continue;
+ }
+
+ std::uint32_t gateway{0};
+ std::ifstream file{"/proc/net/route"};
+ if (file.is_open()) {
+
+ // ignore header
+ file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+
+ bool gateway_found = false;
+
+ for (std::string line; std::getline(file, line);) {
+ std::istringstream iss{line};
+
+ std::string iface_name{};
+ iss >> iface_name;
+ if (iface_name != ifa->ifa_name) {
+ continue;
+ }
+
+ iss >> std::hex;
+
+ std::uint32_t dest{0};
+ iss >> dest;
+ if (dest != 0) {
+ // not the default route
+ continue;
+ }
+
+ iss >> gateway;
+
+ std::uint16_t flags{0};
+ iss >> flags;
+
+ // flag RTF_GATEWAY (defined in <linux/route.h>)
+ if ((flags & 0x2) == 0) {
+ continue;
+ }
+
+ gateway_found = true;
+ break;
+ }
+
+ if (!gateway_found) {
+ gateway = 0;
+ }
+ } else {
+ LOG_ERROR(Network, "Failed to open \"/proc/net/route\"");
+ }
+
+ result.push_back(NetworkInterface{
+ .name{ifa->ifa_name},
+ .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
+ .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
+ .gateway{in_addr{.s_addr = gateway}}});
+ }
+
+ freeifaddrs(ifaddr);
+
+ return result;
+}
+
+#endif
+
+std::optional<NetworkInterface> GetSelectedNetworkInterface() {
+ const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
+ const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
+ if (network_interfaces.size() == 0) {
+ LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
+ return {};
+ }
+
+ const auto res =
+ std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) {
+ return iface.name == selected_network_interface;
+ });
+
+ if (res != network_interfaces.end()) {
+ return *res;
+ } else {
+ LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
+ return {};
+ }
+}
+
+} // namespace Network
diff --git a/src/core/network/network_interface.h b/src/core/network/network_interface.h
new file mode 100644
index 000000000..980edb2f5
--- /dev/null
+++ b/src/core/network/network_interface.h
@@ -0,0 +1,29 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <optional>
+#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;
+ struct in_addr subnet_mask;
+ struct in_addr gateway;
+};
+
+std::vector<NetworkInterface> GetAvailableNetworkInterfaces();
+std::optional<NetworkInterface> GetSelectedNetworkInterface();
+
+} // namespace Network
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index cb4bdcc7e..cf68a95b5 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -102,9 +102,9 @@ add_executable(yuzu
configuration/configure_profile_manager.cpp
configuration/configure_profile_manager.h
configuration/configure_profile_manager.ui
- configuration/configure_service.cpp
- configuration/configure_service.h
- configuration/configure_service.ui
+ configuration/configure_network.cpp
+ configuration/configure_network.h
+ configuration/configure_network.ui
configuration/configure_system.cpp
configuration/configure_system.h
configuration/configure_system.ui
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 380379eb4..377795326 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -692,6 +692,7 @@ void Config::ReadServiceValues() {
qt_config->beginGroup(QStringLiteral("Services"));
ReadBasicSetting(Settings::values.bcat_backend);
ReadBasicSetting(Settings::values.bcat_boxcat_local);
+ ReadBasicSetting(Settings::values.network_interface);
qt_config->endGroup();
}
@@ -1144,7 +1145,7 @@ void Config::SaveValues() {
SaveDataStorageValues();
SaveDebuggingValues();
SaveDisabledAddOnValues();
- SaveServiceValues();
+ SaveNetworkValues();
SaveUIValues();
SaveWebServiceValues();
SaveMiscellaneousValues();
@@ -1238,11 +1239,12 @@ void Config::SaveDebuggingValues() {
qt_config->endGroup();
}
-void Config::SaveServiceValues() {
+void Config::SaveNetworkValues() {
qt_config->beginGroup(QStringLiteral("Services"));
WriteBasicSetting(Settings::values.bcat_backend);
WriteBasicSetting(Settings::values.bcat_boxcat_local);
+ WriteBasicSetting(Settings::values.network_interface);
qt_config->endGroup();
}
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index c1d7feb9f..9555f4498 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -88,7 +88,7 @@ private:
void SaveCoreValues();
void SaveDataStorageValues();
void SaveDebuggingValues();
- void SaveServiceValues();
+ void SaveNetworkValues();
void SaveDisabledAddOnValues();
void SaveMiscellaneousValues();
void SavePathValues();
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index fca9aed5f..6258dcf20 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -147,12 +147,12 @@
<string>Web</string>
</attribute>
</widget>
- <widget class="ConfigureService" name="serviceTab">
+ <widget class="ConfigureNetwork" name="networkTab">
<property name="accessibleName">
- <string>Services</string>
+ <string>Network</string>
</property>
<attribute name="title">
- <string>Services</string>
+ <string>Network</string>
</attribute>
</widget>
</widget>
@@ -242,9 +242,9 @@
<container>1</container>
</customwidget>
<customwidget>
- <class>ConfigureService</class>
+ <class>ConfigureNetwork</class>
<extends>QWidget</extends>
- <header>configuration/configure_service.h</header>
+ <header>configuration/configure_network.h</header>
<container>1</container>
</customwidget>
<customwidget>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index bc009b6b3..fe4186157 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -67,7 +67,7 @@ void ConfigureDialog::ApplyConfiguration() {
ui->audioTab->ApplyConfiguration();
ui->debugTab->ApplyConfiguration();
ui->webTab->ApplyConfiguration();
- ui->serviceTab->ApplyConfiguration();
+ ui->networkTab->ApplyConfiguration();
Core::System::GetInstance().ApplySettings();
Settings::LogSettings();
}
@@ -103,7 +103,7 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
void ConfigureDialog::PopulateSelectionList() {
const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
{{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}},
- {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
+ {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->networkTab, ui->filesystemTab}},
{tr("CPU"), {ui->cpuTab}},
{tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
{tr("Audio"), {ui->audioTab}},
diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_network.cpp
index 4aa424803..ae22f1018 100644
--- a/src/yuzu/configuration/configure_service.cpp
+++ b/src/yuzu/configuration/configure_network.cpp
@@ -5,9 +5,11 @@
#include <QGraphicsItem>
#include <QtConcurrent/QtConcurrent>
#include "common/settings.h"
+#include "core/core.h"
#include "core/hle/service/bcat/backend/boxcat.h"
-#include "ui_configure_service.h"
-#include "yuzu/configuration/configure_service.h"
+#include "core/network/network_interface.h"
+#include "ui_configure_network.h"
+#include "yuzu/configuration/configure_network.h"
#ifdef YUZU_ENABLE_BOXCAT
namespace {
@@ -35,8 +37,8 @@ QString FormatEventStatusString(const Service::BCAT::EventStatus& status) {
} // Anonymous namespace
#endif
-ConfigureService::ConfigureService(QWidget* parent)
- : QWidget(parent), ui(std::make_unique<Ui::ConfigureService>()) {
+ConfigureNetwork::ConfigureNetwork(QWidget* parent)
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureNetwork>()) {
ui->setupUi(this);
ui->bcat_source->addItem(QStringLiteral("None"));
@@ -47,29 +49,42 @@ ConfigureService::ConfigureService(QWidget* parent)
ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat"));
#endif
+ ui->network_interface->addItem(tr("None"));
+ for (const auto& iface : Network::GetAvailableNetworkInterfaces()) {
+ ui->network_interface->addItem(QString::fromStdString(iface.name));
+ }
+
connect(ui->bcat_source, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
- &ConfigureService::OnBCATImplChanged);
+ &ConfigureNetwork::OnBCATImplChanged);
this->SetConfiguration();
}
-ConfigureService::~ConfigureService() = default;
+ConfigureNetwork::~ConfigureNetwork() = default;
-void ConfigureService::ApplyConfiguration() {
+void ConfigureNetwork::ApplyConfiguration() {
Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString();
+ Settings::values.network_interface = ui->network_interface->currentText().toStdString();
}
-void ConfigureService::RetranslateUi() {
+void ConfigureNetwork::RetranslateUi() {
ui->retranslateUi(this);
}
-void ConfigureService::SetConfiguration() {
+void ConfigureNetwork::SetConfiguration() {
+ const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
+
const int index =
ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
+
+ const std::string& network_interface = Settings::values.network_interface.GetValue();
+
+ ui->network_interface->setCurrentText(QString::fromStdString(network_interface));
+ ui->network_interface->setEnabled(runtime_lock);
}
-std::pair<QString, QString> ConfigureService::BCATDownloadEvents() {
+std::pair<QString, QString> ConfigureNetwork::BCATDownloadEvents() {
#ifdef YUZU_ENABLE_BOXCAT
std::optional<std::string> global;
std::map<std::string, Service::BCAT::EventStatus> map;
@@ -114,7 +129,7 @@ std::pair<QString, QString> ConfigureService::BCATDownloadEvents() {
#endif
}
-void ConfigureService::OnBCATImplChanged() {
+void ConfigureNetwork::OnBCATImplChanged() {
#ifdef YUZU_ENABLE_BOXCAT
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
ui->bcat_empty_header->setHidden(!boxcat);
@@ -133,7 +148,7 @@ void ConfigureService::OnBCATImplChanged() {
#endif
}
-void ConfigureService::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
+void ConfigureNetwork::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
#ifdef YUZU_ENABLE_BOXCAT
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
if (boxcat) {
diff --git a/src/yuzu/configuration/configure_service.h b/src/yuzu/configuration/configure_network.h
index f5c1b703a..442b68e6b 100644
--- a/src/yuzu/configuration/configure_service.h
+++ b/src/yuzu/configuration/configure_network.h
@@ -9,15 +9,15 @@
#include <QWidget>
namespace Ui {
-class ConfigureService;
+class ConfigureNetwork;
}
-class ConfigureService : public QWidget {
+class ConfigureNetwork : public QWidget {
Q_OBJECT
public:
- explicit ConfigureService(QWidget* parent = nullptr);
- ~ConfigureService() override;
+ explicit ConfigureNetwork(QWidget* parent = nullptr);
+ ~ConfigureNetwork() override;
void ApplyConfiguration();
void RetranslateUi();
@@ -29,6 +29,6 @@ private:
void OnBCATImplChanged();
void OnUpdateBCATEmptyLabel(std::pair<QString, QString> string);
- std::unique_ptr<Ui::ConfigureService> ui;
+ std::unique_ptr<Ui::ConfigureNetwork> ui;
QFutureWatcher<std::pair<QString, QString>> watcher{this};
};
diff --git a/src/yuzu/configuration/configure_service.ui b/src/yuzu/configuration/configure_network.ui
index 9668dd557..5f9b7e97b 100644
--- a/src/yuzu/configuration/configure_service.ui
+++ b/src/yuzu/configuration/configure_network.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>ConfigureService</class>
- <widget class="QWidget" name="ConfigureService">
+ <class>ConfigureNetwork</class>
+ <widget class="QWidget" name="ConfigureNetwork">
<property name="geometry">
<rect>
<x>0</x>
@@ -17,21 +17,37 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>General</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="1" column="1">
+ <widget class="QComboBox" name="network_interface"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Network Interface</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>BCAT</string>
</property>
<layout class="QGridLayout" name="gridLayout">
- <item row="1" column="1" colspan="2">
- <widget class="QLabel" name="label_2">
- <property name="maximumSize">
- <size>
- <width>260</width>
- <height>16777215</height>
- </size>
- </property>
+ <item row="3" column="0">
+ <widget class="QLabel" name="bcat_empty_header">
<property name="text">
- <string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string>
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -51,11 +67,8 @@
</property>
</widget>
</item>
- <item row="3" column="1" colspan="2">
- <widget class="QLabel" name="bcat_empty_label">
- <property name="enabled">
- <bool>true</bool>
- </property>
+ <item row="1" column="1" colspan="2">
+ <widget class="QLabel" name="label_2">
<property name="maximumSize">
<size>
<width>260</width>
@@ -63,10 +76,7 @@
</size>
</property>
<property name="text">
- <string/>
- </property>
- <property name="alignment">
- <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ <string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -86,8 +96,17 @@
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="bcat_source"/>
</item>
- <item row="3" column="0">
- <widget class="QLabel" name="bcat_empty_header">
+ <item row="3" column="1" colspan="2">
+ <widget class="QLabel" name="bcat_empty_label">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>260</width>
+ <height>16777215</height>
+ </size>
+ </property>
<property name="text">
<string/>
</property>