From 652e5e3df0afabffe1ff0d61f475d847a1d7f6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 6 Aug 2021 21:08:31 +0200 Subject: network: fix fcntl cmds F_SETFL/F_GETFL are the correct commands to set a socket to be non-blocking --- src/core/network/network.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 375bc79ec..5dc9cdc14 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -182,7 +182,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 +191,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) { -- cgit v1.2.3 From dd5c41b5a600764b029617520c737b94a58f6b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Sat, 7 Aug 2021 02:17:02 +0200 Subject: network: GetCurrentIpConfigInfo: return host IP address Service::NIFM::IGeneralService::GetCurrentIpConfigInfo currently hardcodes 192.168.1.100 as the IP address, which prevents LAN play from working correctly. --- src/core/hle/service/nifm/nifm.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index e742db48f..5ef574d20 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -354,10 +354,13 @@ 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"); + const IpConfigInfo ip_config_info{ .ip_address_setting{ .is_automatic{true}, - .current_address{192, 168, 1, 100}, + .current_address{ipv4}, .subnet_mask{255, 255, 255, 0}, .gateway{192, 168, 1, 1}, }, -- cgit v1.2.3 From ddeb8d854e6d2a5c0c82c21b8fbe46390b09098a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Sat, 7 Aug 2021 02:54:25 +0200 Subject: network: GetAndLogLastError: ignore Errno::AGAIN If non-blocking sockets are used, they generate a lot of Errno::AGAIN errors when they didn't receive any data. These errors shouldn't be logged. --- src/core/network/network.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 5dc9cdc14..7b038041e 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -227,8 +227,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) { -- cgit v1.2.3 From 1e98e738283ccb81303d29305188ac825ecfcba9 Mon Sep 17 00:00:00 2001 From: spholz <44805808+spholz@users.noreply.github.com> Date: Thu, 12 Aug 2021 21:32:53 +0200 Subject: configuration: add option to select network interface This commit renames the "Services" tab to "Network" and adds a combobox that allows the user to select the network interface that yuzu should use. This new setting is now used to get the local IP address in Network::GetHostIPv4Address. This prevents yuzu from selecting the wrong network interface and thus using the wrong IP address. The return type of Network::GetHostIPv4Adress has also been changed. --- CMakeLists.txt | 2 +- src/common/settings.h | 3 +- src/core/CMakeLists.txt | 2 + src/core/hle/service/nifm/nifm.cpp | 36 +++--- src/core/network/network.cpp | 43 ++++---- src/core/network/network.h | 5 +- src/core/network/network_interface.cpp | 113 +++++++++++++++++++ src/core/network/network_interface.h | 25 +++++ src/yuzu/CMakeLists.txt | 6 +- src/yuzu/configuration/config.cpp | 6 +- src/yuzu/configuration/config.h | 2 +- src/yuzu/configuration/configure.ui | 10 +- src/yuzu/configuration/configure_dialog.cpp | 4 +- src/yuzu/configuration/configure_network.cpp | 158 +++++++++++++++++++++++++++ src/yuzu/configuration/configure_network.h | 36 ++++++ src/yuzu/configuration/configure_network.ui | 143 ++++++++++++++++++++++++ src/yuzu/configuration/configure_service.cpp | 144 ------------------------ src/yuzu/configuration/configure_service.h | 34 ------ src/yuzu/configuration/configure_service.ui | 124 --------------------- 19 files changed, 542 insertions(+), 354 deletions(-) create mode 100644 src/core/network/network_interface.cpp create mode 100644 src/core/network/network_interface.h create mode 100644 src/yuzu/configuration/configure_network.cpp create mode 100644 src/yuzu/configuration/configure_network.h create mode 100644 src/yuzu/configuration/configure_network.ui delete mode 100644 src/yuzu/configuration/configure_service.cpp delete mode 100644 src/yuzu/configuration/configure_service.h delete mode 100644 src/yuzu/configuration/configure_service.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index de2413843..907fcfdd0 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 a88ee045d..e1ae72c7a 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -433,9 +433,10 @@ struct Values { BasicSetting log_filter{"*:Info", "log_filter"}; BasicSetting use_dev_keys{false, "use_dev_keys"}; - // Services + // Network BasicSetting bcat_backend{"none", "bcat_backend"}; BasicSetting bcat_boxcat_local{false, "bcat_boxcat_local"}; + BasicSetting network_interface{std::string(), "network_interface"}; // WebService BasicSetting 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 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(0); - } else { + if (Network::GetHostIPv4Address().has_value()) { rb.Push(1); + } else { + rb.Push(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(0); - } else { + if (Network::GetHostIPv4Address().has_value()) { rb.Push(1); + } else { + rb.Push(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 +#include #elif YUZU_UNIX #include #include @@ -19,6 +19,7 @@ #include #include #include +#include #include #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 GetHostIPv4Address() { - std::array name{}; - if (gethostname(name.data(), static_cast(name.size()) - 1) == SOCKET_ERROR) { - return {IPv4Address{}, GetAndLogLastError()}; - } +std::optional 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 Poll(std::vector& 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 +#include #include #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 GetHostIPv4Address(); +/// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array +std::optional 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 + +#include "common/common_types.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/network/network_interface.h" + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif + +namespace Network { + +#ifdef _WIN32 + +std::vector GetAvailableNetworkInterfaces() { + std::vector result; + + std::vector adapter_addresses_raw; + auto adapter_addresses = reinterpret_cast(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(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( + *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 GetAvailableNetworkInterfaces() { + std::vector 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(*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 +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace Network { + +struct NetworkInterface { + std::string name; + struct in_addr ip_address; +}; + +std::vector GetAvailableNetworkInterfaces(); + +} // 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 @@ Web - + - Services + Network - Services + Network @@ -242,9 +242,9 @@ 1 - ConfigureService + ConfigureNetwork QWidget -
configuration/configure_service.h
+
configuration/configure_network.h
1
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); void ConfigureDialog::PopulateSelectionList() { const std::array>, 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_network.cpp b/src/yuzu/configuration/configure_network.cpp new file mode 100644 index 000000000..9787d4f1b --- /dev/null +++ b/src/yuzu/configuration/configure_network.cpp @@ -0,0 +1,158 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/settings.h" +#include "core/core.h" +#include "core/hle/service/bcat/backend/boxcat.h" +#include "ui_configure_network.h" +#include "yuzu/configuration/configure_network.h" + +#ifdef YUZU_ENABLE_BOXCAT +namespace { +QString FormatEventStatusString(const Service::BCAT::EventStatus& status) { + QString out; + + if (status.header.has_value()) { + out += QStringLiteral("%1
").arg(QString::fromStdString(*status.header)); + } + + if (status.events.size() == 1) { + out += QStringLiteral("%1
").arg(QString::fromStdString(status.events.front())); + } else { + for (const auto& event : status.events) { + out += QStringLiteral("- %1
").arg(QString::fromStdString(event)); + } + } + + if (status.footer.has_value()) { + out += QStringLiteral("%1
").arg(QString::fromStdString(*status.footer)); + } + + return out; +} +} // Anonymous namespace +#endif + +ConfigureNetwork::ConfigureNetwork(QWidget* parent) + : QWidget(parent), ui(std::make_unique()) { + ui->setupUi(this); + + ui->bcat_source->addItem(QStringLiteral("None")); + ui->bcat_empty_label->setHidden(true); + ui->bcat_empty_header->setHidden(true); + +#ifdef YUZU_ENABLE_BOXCAT + ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat")); +#endif + + ui->network_interface->addItem(QStringLiteral("None")); + for (const auto& interface : Network::GetAvailableNetworkInterfaces()) { + ui->network_interface->addItem(QString::fromStdString(interface.name)); + } + + connect(ui->bcat_source, QOverload::of(&QComboBox::currentIndexChanged), this, + &ConfigureNetwork::OnBCATImplChanged); + + this->SetConfiguration(); +} + +ConfigureNetwork::~ConfigureNetwork() = default; + +void ConfigureNetwork::ApplyConfiguration() { + Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString(); + Settings::values.network_interface = ui->network_interface->currentText().toStdString(); +} + +void ConfigureNetwork::RetranslateUi() { + ui->retranslateUi(this); +} + +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 ConfigureNetwork::BCATDownloadEvents() { +#ifdef YUZU_ENABLE_BOXCAT + std::optional global; + std::map map; + const auto res = Service::BCAT::Boxcat::GetStatus(global, map); + + switch (res) { + case Service::BCAT::Boxcat::StatusResult::Success: + break; + case Service::BCAT::Boxcat::StatusResult::Offline: + return {QString{}, + tr("The boxcat service is offline or you are not connected to the internet.")}; + case Service::BCAT::Boxcat::StatusResult::ParseError: + return {QString{}, + tr("There was an error while processing the boxcat event data. Contact the yuzu " + "developers.")}; + case Service::BCAT::Boxcat::StatusResult::BadClientVersion: + return {QString{}, + tr("The version of yuzu you are using is either too new or too old for the server. " + "Try updating to the latest official release of yuzu.")}; + } + + if (map.empty()) { + return {QStringLiteral("Current Boxcat Events"), + tr("There are currently no events on boxcat.")}; + } + + QString out; + + if (global.has_value()) { + out += QStringLiteral("%1
").arg(QString::fromStdString(*global)); + } + + for (const auto& [key, value] : map) { + out += QStringLiteral("%1%2
%3") + .arg(out.isEmpty() ? QString{} : QStringLiteral("
")) + .arg(QString::fromStdString(key)) + .arg(FormatEventStatusString(value)); + } + return {tr("Current Boxcat Events"), std::move(out)}; +#else + return {tr("Current Boxcat Events"), tr("There are currently no events on boxcat.")}; +#endif +} + +void ConfigureNetwork::OnBCATImplChanged() { +#ifdef YUZU_ENABLE_BOXCAT + const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat"); + ui->bcat_empty_header->setHidden(!boxcat); + ui->bcat_empty_label->setHidden(!boxcat); + ui->bcat_empty_header->setText(QString{}); + ui->bcat_empty_label->setText(tr("Yuzu is retrieving the latest boxcat status...")); + + if (!boxcat) + return; + + const auto future = QtConcurrent::run([this] { return BCATDownloadEvents(); }); + + watcher.setFuture(future); + connect(&watcher, &QFutureWatcher>::finished, this, + [this] { OnUpdateBCATEmptyLabel(watcher.result()); }); +#endif +} + +void ConfigureNetwork::OnUpdateBCATEmptyLabel(std::pair string) { +#ifdef YUZU_ENABLE_BOXCAT + const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat"); + if (boxcat) { + ui->bcat_empty_header->setText(string.first); + ui->bcat_empty_label->setText(string.second); + } +#endif +} diff --git a/src/yuzu/configuration/configure_network.h b/src/yuzu/configuration/configure_network.h new file mode 100644 index 000000000..d4ef33fbf --- /dev/null +++ b/src/yuzu/configuration/configure_network.h @@ -0,0 +1,36 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "core/network/network_interface.h" + +namespace Ui { +class ConfigureNetwork; +} + +class ConfigureNetwork : public QWidget { + Q_OBJECT + +public: + explicit ConfigureNetwork(QWidget* parent = nullptr); + ~ConfigureNetwork() override; + + void ApplyConfiguration(); + void RetranslateUi(); + +private: + void SetConfiguration(); + + std::pair BCATDownloadEvents(); + void OnBCATImplChanged(); + void OnUpdateBCATEmptyLabel(std::pair string); + + std::unique_ptr ui; + QFutureWatcher> watcher{this}; +}; diff --git a/src/yuzu/configuration/configure_network.ui b/src/yuzu/configuration/configure_network.ui new file mode 100644 index 000000000..5f9b7e97b --- /dev/null +++ b/src/yuzu/configuration/configure_network.ui @@ -0,0 +1,143 @@ + + + ConfigureNetwork + + + + 0 + 0 + 433 + 561 + + + + Form + + + + + + + + General + + + + + + + + + Network Interface + + + + + + + + + + BCAT + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + 16777215 + 16777215 + + + + BCAT Backend + + + + + + + + 260 + 16777215 + + + + BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content. + + + true + + + + + + + <html><head/><body><p><a href="https://yuzu-emu.org/help/feature/boxcat"><span style=" text-decoration: underline; color:#0000ff;">Learn more about BCAT, Boxcat, and Current Events</span></a></p></body></html> + + + true + + + + + + + + + + true + + + + 260 + 16777215 + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_service.cpp deleted file mode 100644 index 4aa424803..000000000 --- a/src/yuzu/configuration/configure_service.cpp +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include "common/settings.h" -#include "core/hle/service/bcat/backend/boxcat.h" -#include "ui_configure_service.h" -#include "yuzu/configuration/configure_service.h" - -#ifdef YUZU_ENABLE_BOXCAT -namespace { -QString FormatEventStatusString(const Service::BCAT::EventStatus& status) { - QString out; - - if (status.header.has_value()) { - out += QStringLiteral("%1
").arg(QString::fromStdString(*status.header)); - } - - if (status.events.size() == 1) { - out += QStringLiteral("%1
").arg(QString::fromStdString(status.events.front())); - } else { - for (const auto& event : status.events) { - out += QStringLiteral("- %1
").arg(QString::fromStdString(event)); - } - } - - if (status.footer.has_value()) { - out += QStringLiteral("%1
").arg(QString::fromStdString(*status.footer)); - } - - return out; -} -} // Anonymous namespace -#endif - -ConfigureService::ConfigureService(QWidget* parent) - : QWidget(parent), ui(std::make_unique()) { - ui->setupUi(this); - - ui->bcat_source->addItem(QStringLiteral("None")); - ui->bcat_empty_label->setHidden(true); - ui->bcat_empty_header->setHidden(true); - -#ifdef YUZU_ENABLE_BOXCAT - ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat")); -#endif - - connect(ui->bcat_source, QOverload::of(&QComboBox::currentIndexChanged), this, - &ConfigureService::OnBCATImplChanged); - - this->SetConfiguration(); -} - -ConfigureService::~ConfigureService() = default; - -void ConfigureService::ApplyConfiguration() { - Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString(); -} - -void ConfigureService::RetranslateUi() { - ui->retranslateUi(this); -} - -void ConfigureService::SetConfiguration() { - const int index = - ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue())); - ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index); -} - -std::pair ConfigureService::BCATDownloadEvents() { -#ifdef YUZU_ENABLE_BOXCAT - std::optional global; - std::map map; - const auto res = Service::BCAT::Boxcat::GetStatus(global, map); - - switch (res) { - case Service::BCAT::Boxcat::StatusResult::Success: - break; - case Service::BCAT::Boxcat::StatusResult::Offline: - return {QString{}, - tr("The boxcat service is offline or you are not connected to the internet.")}; - case Service::BCAT::Boxcat::StatusResult::ParseError: - return {QString{}, - tr("There was an error while processing the boxcat event data. Contact the yuzu " - "developers.")}; - case Service::BCAT::Boxcat::StatusResult::BadClientVersion: - return {QString{}, - tr("The version of yuzu you are using is either too new or too old for the server. " - "Try updating to the latest official release of yuzu.")}; - } - - if (map.empty()) { - return {QStringLiteral("Current Boxcat Events"), - tr("There are currently no events on boxcat.")}; - } - - QString out; - - if (global.has_value()) { - out += QStringLiteral("%1
").arg(QString::fromStdString(*global)); - } - - for (const auto& [key, value] : map) { - out += QStringLiteral("%1%2
%3") - .arg(out.isEmpty() ? QString{} : QStringLiteral("
")) - .arg(QString::fromStdString(key)) - .arg(FormatEventStatusString(value)); - } - return {tr("Current Boxcat Events"), std::move(out)}; -#else - return {tr("Current Boxcat Events"), tr("There are currently no events on boxcat.")}; -#endif -} - -void ConfigureService::OnBCATImplChanged() { -#ifdef YUZU_ENABLE_BOXCAT - const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat"); - ui->bcat_empty_header->setHidden(!boxcat); - ui->bcat_empty_label->setHidden(!boxcat); - ui->bcat_empty_header->setText(QString{}); - ui->bcat_empty_label->setText(tr("Yuzu is retrieving the latest boxcat status...")); - - if (!boxcat) - return; - - const auto future = QtConcurrent::run([this] { return BCATDownloadEvents(); }); - - watcher.setFuture(future); - connect(&watcher, &QFutureWatcher>::finished, this, - [this] { OnUpdateBCATEmptyLabel(watcher.result()); }); -#endif -} - -void ConfigureService::OnUpdateBCATEmptyLabel(std::pair string) { -#ifdef YUZU_ENABLE_BOXCAT - const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat"); - if (boxcat) { - ui->bcat_empty_header->setText(string.first); - ui->bcat_empty_label->setText(string.second); - } -#endif -} diff --git a/src/yuzu/configuration/configure_service.h b/src/yuzu/configuration/configure_service.h deleted file mode 100644 index f5c1b703a..000000000 --- a/src/yuzu/configuration/configure_service.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -namespace Ui { -class ConfigureService; -} - -class ConfigureService : public QWidget { - Q_OBJECT - -public: - explicit ConfigureService(QWidget* parent = nullptr); - ~ConfigureService() override; - - void ApplyConfiguration(); - void RetranslateUi(); - -private: - void SetConfiguration(); - - std::pair BCATDownloadEvents(); - void OnBCATImplChanged(); - void OnUpdateBCATEmptyLabel(std::pair string); - - std::unique_ptr ui; - QFutureWatcher> watcher{this}; -}; diff --git a/src/yuzu/configuration/configure_service.ui b/src/yuzu/configuration/configure_service.ui deleted file mode 100644 index 9668dd557..000000000 --- a/src/yuzu/configuration/configure_service.ui +++ /dev/null @@ -1,124 +0,0 @@ - - - ConfigureService - - - - 0 - 0 - 433 - 561 - - - - Form - - - - - - - - BCAT - - - - - - - 260 - 16777215 - - - - BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content. - - - true - - - - - - - - 16777215 - 16777215 - - - - BCAT Backend - - - - - - - true - - - - 260 - 16777215 - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - <html><head/><body><p><a href="https://yuzu-emu.org/help/feature/boxcat"><span style=" text-decoration: underline; color:#0000ff;">Learn more about BCAT, Boxcat, and Current Events</span></a></p></body></html> - - - true - - - - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - -- cgit v1.2.3 From 21743daf38f19160baa2da0e939a4e945dd57228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Thu, 12 Aug 2021 22:15:48 +0200 Subject: network: correct formatting in network.cpp and network_interface.cpp --- src/core/network/network.cpp | 6 +++--- src/core/network/network_interface.cpp | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 67ecf57bd..9a4ac7e83 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -13,13 +13,13 @@ #include #include #elif YUZU_UNIX +#include #include #include #include #include #include #include -#include #include #else #error "Unimplemented platform" @@ -363,8 +363,8 @@ NetworkInstance::~NetworkInstance() { std::optional 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"); - + ASSERT_MSG(network_interfaces.size() > 0, + "GetAvailableNetworkInterfaces returned no interfaces"); const auto res = std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& interface) { diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp index bba4c8b26..2b53682ea 100644 --- a/src/core/network/network_interface.cpp +++ b/src/core/network/network_interface.cpp @@ -12,9 +12,9 @@ #ifdef _WIN32 #include #else +#include #include #include -#include #endif namespace Network { @@ -61,8 +61,7 @@ std::vector GetAvailableNetworkInterfaces() { result.push_back(NetworkInterface{ .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})}, - .ip_address{ip_addr} - }); + .ip_address{ip_addr}}); } } else { LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses"); @@ -99,8 +98,7 @@ std::vector GetAvailableNetworkInterfaces() { result.push_back(NetworkInterface{ .name{ifa->ifa_name}, - .ip_address{std::bit_cast(*ifa->ifa_addr).sin_addr} - }); + .ip_address{std::bit_cast(*ifa->ifa_addr).sin_addr}}); } freeifaddrs(ifaddr); -- cgit v1.2.3 From 970d81abfcbcca905bbfb52f415c38ab5da812e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 00:21:54 +0200 Subject: nifm: treat a missing host IP address as a non-critical error --- src/core/hle/service/nifm/nifm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 168053d80..f2ab4ffaa 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -324,7 +324,7 @@ private: auto ipv4 = Network::GetHostIPv4Address(); if (!ipv4) { - LOG_CRITICAL(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0"); + LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0"); ipv4.emplace(Network::IPv4Address{0, 0, 0, 0}); } @@ -359,7 +359,7 @@ private: auto ipv4 = Network::GetHostIPv4Address(); if (!ipv4) { - LOG_CRITICAL(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0"); + LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0"); ipv4.emplace(Network::IPv4Address{0, 0, 0, 0}); } -- cgit v1.2.3 From acca8aca8c3edb2a79a87276a681a7a559242166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 00:24:33 +0200 Subject: nifm: use operator*() instead of .value() to get value of std::optional --- src/core/hle/service/nifm/nifm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index f2ab4ffaa..796c89d47 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -330,7 +330,7 @@ private: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushRaw(ipv4.value()); + rb.PushRaw(*ipv4); } void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NIFM, "called"); @@ -366,7 +366,7 @@ private: const IpConfigInfo ip_config_info{ .ip_address_setting{ .is_automatic{true}, - .current_address{ipv4.value()}, + .current_address{*ipv4}, .subnet_mask{255, 255, 255, 0}, .gateway{192, 168, 1, 1}, }, -- cgit v1.2.3 From 765e97c34765330e1f05ee1b5a9a58a43f9c8921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 00:28:44 +0200 Subject: network: initialize ip_addr in GetHostIPv4Address() --- src/core/network/network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 9a4ac7e83..6571005d0 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -372,7 +372,7 @@ std::optional GetHostIPv4Address() { }); if (res != network_interfaces.end()) { - char ip_addr[16]; + 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); -- cgit v1.2.3 From 771de32af16f70d63c76f2f95698be7751374c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 00:31:33 +0200 Subject: network: use explicit bool conversions in GetAvailableNetworkInterfaces --- src/core/network/network_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp index 2b53682ea..887aee708 100644 --- a/src/core/network/network_interface.cpp +++ b/src/core/network/network_interface.cpp @@ -92,7 +92,7 @@ std::vector GetAvailableNetworkInterfaces() { continue; } - if (!(ifa->ifa_flags & IFF_UP) || ifa->ifa_flags & IFF_LOOPBACK) { + if ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) { continue; } -- cgit v1.2.3 From 04ec426201ff8706f94f784cbb542298e5f6daa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 00:34:04 +0200 Subject: configuration: use tr instead of QStringLiteral for "None" item in network interface combobox --- src/yuzu/configuration/configure_network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/configuration/configure_network.cpp b/src/yuzu/configuration/configure_network.cpp index 9787d4f1b..3716967f6 100644 --- a/src/yuzu/configuration/configure_network.cpp +++ b/src/yuzu/configuration/configure_network.cpp @@ -48,7 +48,7 @@ ConfigureNetwork::ConfigureNetwork(QWidget* parent) ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat")); #endif - ui->network_interface->addItem(QStringLiteral("None")); + ui->network_interface->addItem(tr("None")); for (const auto& interface : Network::GetAvailableNetworkInterfaces()) { ui->network_interface->addItem(QString::fromStdString(interface.name)); } -- cgit v1.2.3 From 8513e594310af03df7613fb3255b6ca5cd84710d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 00:37:03 +0200 Subject: network: narrow down scope of "result" in win32 code for GetAvailableNetworkInterfaces --- src/core/network/network_interface.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp index 887aee708..34e20f547 100644 --- a/src/core/network/network_interface.cpp +++ b/src/core/network/network_interface.cpp @@ -22,8 +22,6 @@ namespace Network { #ifdef _WIN32 std::vector GetAvailableNetworkInterfaces() { - std::vector result; - std::vector adapter_addresses_raw; auto adapter_addresses = reinterpret_cast(adapter_addresses_raw.data()); DWORD ret = ERROR_BUFFER_OVERFLOW; @@ -44,6 +42,8 @@ std::vector GetAvailableNetworkInterfaces() { } if (ret == NO_ERROR) { + std::vector result; + for (auto current_address = adapter_addresses; current_address != nullptr; current_address = current_address->Next) { if (current_address->FirstUnicastAddress == nullptr || @@ -63,11 +63,12 @@ std::vector GetAvailableNetworkInterfaces() { .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})}, .ip_address{ip_addr}}); } + + return result; } else { LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses"); + return {}; } - - return result; } #else -- cgit v1.2.3 From a0c4c1a23adb3645e1d225644ab5e0e7aea513ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 01:28:14 +0200 Subject: network: use Common::BitCast instead of std::bit_cast --- src/core/network/network_interface.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp index 34e20f547..e9060f13f 100644 --- a/src/core/network/network_interface.cpp +++ b/src/core/network/network_interface.cpp @@ -4,6 +4,7 @@ #include +#include "common/bit_cast.h" #include "common/common_types.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -55,7 +56,7 @@ std::vector GetAvailableNetworkInterfaces() { continue; } - const auto ip_addr = std::bit_cast( + const auto ip_addr = Common::BitCast( *current_address->FirstUnicastAddress->Address.lpSockaddr) .sin_addr; @@ -99,7 +100,7 @@ std::vector GetAvailableNetworkInterfaces() { result.push_back(NetworkInterface{ .name{ifa->ifa_name}, - .ip_address{std::bit_cast(*ifa->ifa_addr).sin_addr}}); + .ip_address{Common::BitCast(*ifa->ifa_addr).sin_addr}}); } freeifaddrs(ifaddr); -- cgit v1.2.3 From 0476751ee2123f7ef1abc60c6530f3840a525f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 02:48:39 +0200 Subject: configuration: move network_interface include to source file --- src/yuzu/configuration/configure_network.cpp | 1 + src/yuzu/configuration/configure_network.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/yuzu/configuration/configure_network.cpp b/src/yuzu/configuration/configure_network.cpp index 3716967f6..e6924883c 100644 --- a/src/yuzu/configuration/configure_network.cpp +++ b/src/yuzu/configuration/configure_network.cpp @@ -7,6 +7,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/hle/service/bcat/backend/boxcat.h" +#include "core/network/network_interface.h" #include "ui_configure_network.h" #include "yuzu/configuration/configure_network.h" diff --git a/src/yuzu/configuration/configure_network.h b/src/yuzu/configuration/configure_network.h index d4ef33fbf..442b68e6b 100644 --- a/src/yuzu/configuration/configure_network.h +++ b/src/yuzu/configuration/configure_network.h @@ -8,8 +8,6 @@ #include #include -#include "core/network/network_interface.h" - namespace Ui { class ConfigureNetwork; } -- cgit v1.2.3 From b18e1d031f5c14a84b70f25ac97a01602ff1e063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 11:21:34 +0200 Subject: network: don't use assert to check if no network interfaces are returned --- src/core/network/network.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 6571005d0..4669130ee 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -363,8 +363,10 @@ NetworkInstance::~NetworkInstance() { std::optional 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"); + 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& interface) { -- cgit v1.2.3 From e660334a21a697754f3a9859da5e32c327a7d3e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 11:23:50 +0200 Subject: network: fix mingw-w64 build The header "combaseapi.h" of mingw-w64 defines "interface" as "struct". --- src/core/network/network.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 4669130ee..71583159a 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -368,10 +368,10 @@ std::optional GetHostIPv4Address() { return {}; } - const auto res = std::ranges::find_if(network_interfaces, - [&selected_network_interface](const auto& interface) { - return interface.name == selected_network_interface; - }); + 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] = {}; -- cgit v1.2.3 From deb65a5717036c4f6497d4102082921352dfcda0 Mon Sep 17 00:00:00 2001 From: spholz <44805808+spholz@users.noreply.github.com> Date: Fri, 13 Aug 2021 11:58:34 +0200 Subject: network: don't use reinterpret_cast in GetAvailableNetworkInterfaces --- src/core/network/network_interface.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp index e9060f13f..75f4dc54f 100644 --- a/src/core/network/network_interface.cpp +++ b/src/core/network/network_interface.cpp @@ -23,20 +23,17 @@ namespace Network { #ifdef _WIN32 std::vector GetAvailableNetworkInterfaces() { - std::vector adapter_addresses_raw; - auto adapter_addresses = reinterpret_cast(adapter_addresses_raw.data()); + std::vector 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, - nullptr, adapter_addresses, &buf_size); + nullptr, adapter_addresses.data(), &buf_size); if (ret == ERROR_BUFFER_OVERFLOW) { - adapter_addresses_raw.resize(buf_size); - adapter_addresses = - reinterpret_cast(adapter_addresses_raw.data()); + adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1); } else { break; } @@ -45,7 +42,7 @@ std::vector GetAvailableNetworkInterfaces() { if (ret == NO_ERROR) { std::vector result; - for (auto current_address = adapter_addresses; current_address != nullptr; + 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) { -- cgit v1.2.3 From 068c66672dd8314693f5f5ee29941dce1973b405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 13 Aug 2021 12:39:14 +0200 Subject: configuration: fix mingw-w64 build --- src/yuzu/configuration/configure_network.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yuzu/configuration/configure_network.cpp b/src/yuzu/configuration/configure_network.cpp index e6924883c..ae22f1018 100644 --- a/src/yuzu/configuration/configure_network.cpp +++ b/src/yuzu/configuration/configure_network.cpp @@ -50,8 +50,8 @@ ConfigureNetwork::ConfigureNetwork(QWidget* parent) #endif ui->network_interface->addItem(tr("None")); - for (const auto& interface : Network::GetAvailableNetworkInterfaces()) { - ui->network_interface->addItem(QString::fromStdString(interface.name)); + for (const auto& iface : Network::GetAvailableNetworkInterfaces()) { + ui->network_interface->addItem(QString::fromStdString(iface.name)); } connect(ui->bcat_source, QOverload::of(&QComboBox::currentIndexChanged), this, -- cgit v1.2.3 From 70419f7a17880fd1e7834e7fe6e1aad14b0565bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Mon, 16 Aug 2021 10:32:25 +0200 Subject: network: retrieve subnet mask and gateway info --- src/core/hle/service/nifm/nifm.cpp | 24 +++++--- src/core/network/network.cpp | 11 ---- src/core/network/network.h | 19 ++++++ src/core/network/network_interface.cpp | 103 +++++++++++++++++++++++++++++++-- src/core/network/network_interface.h | 4 ++ 5 files changed, 137 insertions(+), 24 deletions(-) diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 796c89d47..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 { @@ -357,16 +358,10 @@ private: static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting), "IpConfigInfo has incorrect size."); - 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}); - } - - const IpConfigInfo ip_config_info{ + IpConfigInfo ip_config_info{ .ip_address_setting{ .is_automatic{true}, - .current_address{*ipv4}, + .current_address{0, 0, 0, 0}, .subnet_mask{255, 255, 255, 0}, .gateway{192, 168, 1, 1}, }, @@ -377,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(ip_config_info); diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 71583159a..4732d4485 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp @@ -50,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; @@ -141,12 +136,6 @@ void Initialize() {} void Finalize() {} -constexpr IPv4Address TranslateIPv4(in_addr addr) { - const u32 bytes = addr.s_addr; - return IPv4Address{static_cast(bytes), static_cast(bytes >> 8), - static_cast(bytes >> 16), static_cast(bytes >> 24)}; -} - sockaddr TranslateFromSockAddrIn(SockAddrIn input) { sockaddr_in result; diff --git a/src/core/network/network.h b/src/core/network/network.h index cfa68d478..fdd3e4655 100644 --- a/src/core/network/network.h +++ b/src/core/network/network.h @@ -11,6 +11,12 @@ #include "common/common_funcs.h" #include "common/common_types.h" +#ifdef _WIN32 +#include +#elif YUZU_UNIX +#include +#endif + namespace Network { class Socket; @@ -93,6 +99,19 @@ 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(bytes), static_cast(bytes >> 8), + static_cast(bytes >> 16), static_cast(bytes >> 24)}; +} +#endif + /// @brief Returns host's IPv4 address /// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array std::optional GetHostIPv4Address(); diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp index 75f4dc54f..b719da881 100644 --- a/src/core/network/network_interface.cpp +++ b/src/core/network/network_interface.cpp @@ -2,11 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include +#include +#include #include #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" @@ -29,8 +33,9 @@ std::vector GetAvailableNetworkInterfaces() { // 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.data(), &buf_size); + 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); @@ -57,9 +62,26 @@ std::vector GetAvailableNetworkInterfaces() { *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 = {0}; + if (current_address->FirstGatewayAddress != nullptr && + current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) { + gateway = Common::BitCast( + *current_address->FirstGatewayAddress->Address.lpSockaddr) + .sin_addr; + } + result.push_back(NetworkInterface{ .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})}, - .ip_address{ip_addr}}); + .ip_address{ip_addr}, + .subnet_mask = in_addr{.S_un{.S_addr{mask}}}, + .gateway = gateway}); } return result; @@ -83,7 +105,7 @@ std::vector GetAvailableNetworkInterfaces() { } for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == nullptr) { + if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr) { continue; } @@ -95,9 +117,59 @@ std::vector GetAvailableNetworkInterfaces() { continue; } + std::uint32_t gateway{0}; + std::ifstream file{"/proc/net/route"}; + if (file.is_open()) { + + // ignore header + file.ignore(std::numeric_limits::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 ) + 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(*ifa->ifa_addr).sin_addr}}); + .ip_address{Common::BitCast(*ifa->ifa_addr).sin_addr}, + .subnet_mask{Common::BitCast(*ifa->ifa_netmask).sin_addr}, + .gateway{in_addr{.s_addr = gateway}}}); } freeifaddrs(ifaddr); @@ -107,4 +179,25 @@ std::vector GetAvailableNetworkInterfaces() { #endif +std::optional 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 index d7184e14a..980edb2f5 100644 --- a/src/core/network/network_interface.h +++ b/src/core/network/network_interface.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include @@ -18,8 +19,11 @@ namespace Network { struct NetworkInterface { std::string name; struct in_addr ip_address; + struct in_addr subnet_mask; + struct in_addr gateway; }; std::vector GetAvailableNetworkInterfaces(); +std::optional GetSelectedNetworkInterface(); } // namespace Network -- cgit v1.2.3 From dc47b5a5bf1236c4ae4c1b48b14e59e013f3f6b0 Mon Sep 17 00:00:00 2001 From: spholz <44805808+spholz@users.noreply.github.com> Date: Mon, 16 Aug 2021 12:06:35 +0200 Subject: network_interface: fix mingw-w64 build --- src/core/network/network_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp index b719da881..c60deb196 100644 --- a/src/core/network/network_interface.cpp +++ b/src/core/network/network_interface.cpp @@ -69,7 +69,7 @@ std::vector GetAvailableNetworkInterfaces() { continue; } - struct in_addr gateway = {0}; + struct in_addr gateway{.S_un{.S_addr{0}}}; if (current_address->FirstGatewayAddress != nullptr && current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) { gateway = Common::BitCast( -- cgit v1.2.3 From 356dbf4d1d314448495ab4e558aa8f799f20caac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Mon, 16 Aug 2021 12:18:19 +0200 Subject: network_interface: correct formatting --- src/core/network/network_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp index c60deb196..cecc9aa11 100644 --- a/src/core/network/network_interface.cpp +++ b/src/core/network/network_interface.cpp @@ -69,7 +69,7 @@ std::vector GetAvailableNetworkInterfaces() { continue; } - struct in_addr gateway{.S_un{.S_addr{0}}}; + struct in_addr gateway = {.S_un{.S_addr{0}}}; if (current_address->FirstGatewayAddress != nullptr && current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) { gateway = Common::BitCast( -- cgit v1.2.3