From 0c364cbb4cc0bc6ef2937826d67c1483cf17551a Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 12 Feb 2023 17:58:17 -0800 Subject: [PATCH] implement tapserver BBA on all platforms This expands the tapserver BBA interface to be available on all platforms. tapserver itself is still macOS-only, but newserv (the PSO server) is not, and it can directly accept local and remote tapserver connections as well. This makes the tapserver interface potentially useful on all platforms. --- .../features/settings/model/StringSetting.kt | 6 + .../settings/ui/SettingsFragmentPresenter.kt | 11 ++ .../app/src/main/res/values/strings.xml | 2 + Source/Core/Core/CMakeLists.txt | 6 +- Source/Core/Core/Config/MainSettings.cpp | 2 + Source/Core/Core/Config/MainSettings.h | 1 + .../{TAPServer_Apple.cpp => TAPServer.cpp} | 106 +++++++++++++----- Source/Core/Core/HW/EXI/EXI_Device.cpp | 2 - Source/Core/Core/HW/EXI/EXI_Device.h | 1 - .../Core/Core/HW/EXI/EXI_DeviceEthernet.cpp | 5 +- Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h | 11 +- .../BroadbandAdapterSettingsDialog.cpp | 14 +++ .../Settings/BroadbandAdapterSettingsDialog.h | 1 + .../Core/DolphinQt/Settings/GameCubePane.cpp | 10 +- 14 files changed, 134 insertions(+), 44 deletions(-) rename Source/Core/Core/HW/EXI/BBA/{TAPServer_Apple.cpp => TAPServer.cpp} (54%) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt index ea685b817d..8dc9e619c5 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.kt @@ -23,6 +23,12 @@ enum class StringSetting( "BBA_BUILTIN_DNS", "3.18.217.27" ), + MAIN_BBA_TAPSERVER_DESTINATION( + Settings.FILE_DOLPHIN, + Settings.SECTION_INI_CORE, + "BBA_TAPSERVER_DESTINATION", + "/tmp/dolphin-tap" + ), MAIN_CUSTOM_RTC_VALUE( Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt index 44e2b2b915..ef395ed6a4 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt @@ -1101,6 +1101,17 @@ class SettingsFragmentPresenter( R.string.xlink_kai_bba_ip_description ) ) + } else if (serialPort1Type == 11) { + // Broadband Adapter (tapserver) + sl.add( + InputStringSetting( + context, + StringSetting.MAIN_BBA_TAPSERVER_DESTINATION, + R.string.bba_tapserver_destination, + R.string.bba_tapserver_destination_description + ) + ) + } } else if (serialPort1Type == 12) { // Broadband Adapter (Built In) sl.add( diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 251886b98a..2e8fc6856e 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -133,6 +133,8 @@ For setup instructions, refer to this page. XLink Kai IP Address/hostname IP address or hostname of device running the XLink Kai client + Tapserver destination + Enter the socket path or netloc (address:port) of the tapserver instance DNS Server Use 8.8.8.8 for normal DNS, else enter your custom one diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 290947e722..945c57760d 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -696,6 +696,7 @@ if(WIN32) target_sources(core PRIVATE HW/EXI/BBA/TAP_Win32.cpp HW/EXI/BBA/TAP_Win32.h + HW/EXI/BBA/TAPServer.cpp HW/EXI/BBA/XLINK_KAI_BBA.cpp HW/EXI/BBA/BuiltIn.cpp HW/EXI/BBA/BuiltIn.h @@ -712,7 +713,7 @@ if(WIN32) elseif(APPLE) target_sources(core PRIVATE HW/EXI/BBA/TAP_Apple.cpp - HW/EXI/BBA/TAPServer_Apple.cpp + HW/EXI/BBA/TAPServer.cpp HW/EXI/BBA/XLINK_KAI_BBA.cpp HW/EXI/BBA/BuiltIn.cpp HW/EXI/BBA/BuiltIn.h @@ -721,6 +722,7 @@ elseif(APPLE) elseif(UNIX) target_sources(core PRIVATE HW/EXI/BBA/TAP_Unix.cpp + HW/EXI/BBA/TAPServer.cpp HW/EXI/BBA/XLINK_KAI_BBA.cpp HW/EXI/BBA/BuiltIn.cpp HW/EXI/BBA/BuiltIn.h @@ -778,4 +780,4 @@ endif() if(USE_RETRO_ACHIEVEMENTS) target_link_libraries(core PRIVATE rcheevos) target_compile_definitions(core PRIVATE -DUSE_RETRO_ACHIEVEMENTS) -endif() \ No newline at end of file +endif() diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 21c453b6c7..cdd852c260 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -137,6 +137,8 @@ const Info MAIN_BBA_XLINK_CHAT_OSD{{System::Main, "Core", "BBA_XLINK_CHAT_ // Schthack PSO Server - https://schtserv.com/ const Info MAIN_BBA_BUILTIN_DNS{{System::Main, "Core", "BBA_BUILTIN_DNS"}, "3.18.217.27"}; +const Info MAIN_BBA_TAPSERVER_DESTINATION{ + {System::Main, "Core", "BBA_TAPSERVER_DESTINATION"}, "/tmp/dolphin-tap"}; const Info MAIN_BBA_BUILTIN_IP{{System::Main, "Core", "BBA_BUILTIN_IP"}, ""}; const Info& GetInfoForSIDevice(int channel) diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index dddda8ae7a..b13615df5d 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -96,6 +96,7 @@ extern const Info MAIN_BBA_XLINK_IP; extern const Info MAIN_BBA_XLINK_CHAT_OSD; extern const Info MAIN_BBA_BUILTIN_DNS; extern const Info MAIN_BBA_BUILTIN_IP; +extern const Info MAIN_BBA_TAPSERVER_DESTINATION; const Info& GetInfoForSIDevice(int channel); const Info& GetInfoForAdapterRumble(int channel); const Info& GetInfoForSimulateKonga(int channel); diff --git a/Source/Core/Core/HW/EXI/BBA/TAPServer_Apple.cpp b/Source/Core/Core/HW/EXI/BBA/TAPServer.cpp similarity index 54% rename from Source/Core/Core/HW/EXI/BBA/TAPServer_Apple.cpp rename to Source/Core/Core/HW/EXI/BBA/TAPServer.cpp index de71067c1b..3e0644a41b 100644 --- a/Source/Core/Core/HW/EXI/BBA/TAPServer_Apple.cpp +++ b/Source/Core/Core/HW/EXI/BBA/TAPServer.cpp @@ -3,10 +3,16 @@ #include "Core/HW/EXI/EXI_DeviceEthernet.h" +#ifdef _WIN32 +#include +#include +#else #include #include +#include #include #include +#endif #include "Common/CommonFuncs.h" #include "Common/Logging/Log.h" @@ -15,42 +21,84 @@ namespace ExpansionInterface { -// This interface is only implemented on macOS, since macOS needs a replacement -// for TunTap when the kernel extension is no longer supported. This interface -// only appears in the menu on macOS, so on other platforms, it does nothing and -// refuses to activate. -constexpr char socket_path[] = "/tmp/dolphin-tap"; +static int ConnectToDestination(const std::string& destination) +{ + if (destination.empty()) + { + INFO_LOG_FMT(SP1, "Cannot connect: destination is empty\n"); + return -1; + } + + size_t ss_size; + struct sockaddr_storage ss; + memset(&ss, 0, sizeof(ss)); + if (destination[0] != '/') + { // IP address or hostname + size_t colon_offset = destination.find(':'); + if (colon_offset == std::string::npos) + { + INFO_LOG_FMT(SP1, "Destination IP address does not include port\n"); + return -1; + } + + struct sockaddr_in* sin = reinterpret_cast(&ss); + sin->sin_addr.s_addr = htonl(sf::IpAddress(destination.substr(0, colon_offset)).toInteger()); + sin->sin_family = AF_INET; + sin->sin_port = htons(stoul(destination.substr(colon_offset + 1))); + ss_size = sizeof(*sin); +#ifndef _WIN32 + } + else + { // UNIX socket + struct sockaddr_un* sun = reinterpret_cast(&ss); + if (destination.size() + 1 > sizeof(sun->sun_path)) + { + INFO_LOG_FMT(SP1, "Socket path is too long, unable to init BBA\n"); + return -1; + } + sun->sun_family = AF_UNIX; + strcpy(sun->sun_path, destination.c_str()); + ss_size = sizeof(*sun); +#else + } + else + { + INFO_LOG_FMT(SP1, "UNIX sockets are not supported on Windows\n"); + return -1; +#endif + } + + int fd = socket(ss.ss_family, SOCK_STREAM, (ss.ss_family == AF_INET) ? IPPROTO_TCP : 0); + if (fd == -1) + { + INFO_LOG_FMT(SP1, "Couldn't create socket; unable to init BBA\n"); + return -1; + } + +#ifdef __APPLE__ + int opt_no_sigpipe = 1; + if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &opt_no_sigpipe, sizeof(opt_no_sigpipe)) < 0) + INFO_LOG_FMT(SP1, "Failed to set SO_NOSIGPIPE on socket\n"); +#endif + + if (connect(fd, reinterpret_cast(&ss), ss_size) == -1) + { + std::string s = Common::LastStrerrorString(); + INFO_LOG_FMT(SP1, "Couldn't connect socket ({}), unable to init BBA\n", s.c_str()); + close(fd); + return -1; + } + + return fd; +} bool CEXIETHERNET::TAPServerNetworkInterface::Activate() { if (IsActivated()) return true; - sockaddr_un sun = {}; - if (sizeof(socket_path) > sizeof(sun.sun_path)) - { - ERROR_LOG_FMT(SP1, "Socket path is too long, unable to init BBA"); - return false; - } - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, socket_path); - - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) - { - ERROR_LOG_FMT(SP1, "Couldn't create socket, unable to init BBA"); - return false; - } - - if (connect(fd, reinterpret_cast(&sun), sizeof(sun)) == -1) - { - ERROR_LOG_FMT(SP1, "Couldn't connect socket ({}), unable to init BBA", - Common::LastStrerrorString()); - close(fd); - fd = -1; - return false; - } + fd = ConnectToDestination(m_destination); INFO_LOG_FMT(SP1, "BBA initialized."); return RecvInit(); diff --git a/Source/Core/Core/HW/EXI/EXI_Device.cpp b/Source/Core/Core/HW/EXI/EXI_Device.cpp index 425ce9dbb2..ad25a94522 100644 --- a/Source/Core/Core/HW/EXI/EXI_Device.cpp +++ b/Source/Core/Core/HW/EXI/EXI_Device.cpp @@ -137,11 +137,9 @@ std::unique_ptr EXIDevice_Create(Core::System& system, const EXIDevi result = std::make_unique(system, BBADeviceType::TAP); break; -#if defined(__APPLE__) case EXIDeviceType::EthernetTapServer: result = std::make_unique(system, BBADeviceType::TAPSERVER); break; -#endif case EXIDeviceType::EthernetXLink: result = std::make_unique(system, BBADeviceType::XLINK); diff --git a/Source/Core/Core/HW/EXI/EXI_Device.h b/Source/Core/Core/HW/EXI/EXI_Device.h index 2c90d772f9..c927a255d3 100644 --- a/Source/Core/Core/HW/EXI/EXI_Device.h +++ b/Source/Core/Core/HW/EXI/EXI_Device.h @@ -39,7 +39,6 @@ enum class EXIDeviceType : int MemoryCardFolder, AGP, EthernetXLink, - // Only used on Apple devices. EthernetTapServer, EthernetBuiltIn, None = 0xFF diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.cpp index 549ace3a6e..fb2660ed04 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.cpp @@ -50,12 +50,11 @@ CEXIETHERNET::CEXIETHERNET(Core::System& system, BBADeviceType type) : IEXIDevic m_network_interface = std::make_unique(this); INFO_LOG_FMT(SP1, "Created TAP physical network interface."); break; -#if defined(__APPLE__) case BBADeviceType::TAPSERVER: - m_network_interface = std::make_unique(this); + m_network_interface = std::make_unique( + this, Config::Get(Config::MAIN_BBA_TAPSERVER_DESTINATION)); INFO_LOG_FMT(SP1, "Created tapserver physical network interface."); break; -#endif case BBADeviceType::BuiltIn: m_network_interface = std::make_unique( this, Config::Get(Config::MAIN_BBA_BUILTIN_DNS), Config::Get(Config::MAIN_BBA_BUILTIN_IP)); diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h b/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h index cdbf645aee..301420fbea 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h @@ -205,9 +205,7 @@ enum class BBADeviceType { TAP, XLINK, -#if defined(__APPLE__) TAPSERVER, -#endif BuiltIn, }; @@ -364,11 +362,13 @@ private: #endif }; -#if defined(__APPLE__) class TAPServerNetworkInterface : public TAPNetworkInterface { public: - explicit TAPServerNetworkInterface(CEXIETHERNET* eth_ref) : TAPNetworkInterface(eth_ref) {} + explicit TAPServerNetworkInterface(CEXIETHERNET* eth_ref, const std::string& destination) + : TAPNetworkInterface(eth_ref), m_destination(destination) + { + } public: bool Activate() override; @@ -376,9 +376,10 @@ private: bool RecvInit() override; private: + std::string m_destination; + void ReadThreadHandler(); }; -#endif class XLinkNetworkInterface : public NetworkInterface { diff --git a/Source/Core/DolphinQt/Settings/BroadbandAdapterSettingsDialog.cpp b/Source/Core/DolphinQt/Settings/BroadbandAdapterSettingsDialog.cpp index 91aeae8a22..f8abbc77ab 100644 --- a/Source/Core/DolphinQt/Settings/BroadbandAdapterSettingsDialog.cpp +++ b/Source/Core/DolphinQt/Settings/BroadbandAdapterSettingsDialog.cpp @@ -48,6 +48,17 @@ void BroadbandAdapterSettingsDialog::InitControls() window_title = tr("Broadband Adapter MAC Address"); break; + case Type::TapServer: + address_label = new QLabel(tr("UNIX socket path or netloc (address:port):")); + address_placeholder = QStringLiteral("/tmp/dolphin-tap"); + current_address = QString::fromStdString(Config::Get(Config::MAIN_BBA_TAPSERVER_DESTINATION)); + description = + new QLabel(tr("On macOS and Linux, the default value \"/tmp/dolphin-tap\" will work with " + "tapserver and newserv. On Windows, you must enter an IP address and port.")); + + window_title = tr("BBA destination address"); + break; + case Type::BuiltIn: address_label = new QLabel(tr("Enter the DNS server to use:")); address_placeholder = QStringLiteral("8.8.8.8"); @@ -114,6 +125,9 @@ void BroadbandAdapterSettingsDialog::SaveAddress() Config::SetBaseOrCurrent(Config::MAIN_BBA_MAC, bba_new_address); break; } + case Type::TapServer: + Config::SetBaseOrCurrent(Config::MAIN_BBA_TAPSERVER_DESTINATION, bba_new_address); + break; case Type::BuiltIn: Config::SetBaseOrCurrent(Config::MAIN_BBA_BUILTIN_DNS, bba_new_address); break; diff --git a/Source/Core/DolphinQt/Settings/BroadbandAdapterSettingsDialog.h b/Source/Core/DolphinQt/Settings/BroadbandAdapterSettingsDialog.h index ca8d813cbe..53863f1d15 100644 --- a/Source/Core/DolphinQt/Settings/BroadbandAdapterSettingsDialog.h +++ b/Source/Core/DolphinQt/Settings/BroadbandAdapterSettingsDialog.h @@ -15,6 +15,7 @@ public: { Ethernet, XLinkKai, + TapServer, BuiltIn }; diff --git a/Source/Core/DolphinQt/Settings/GameCubePane.cpp b/Source/Core/DolphinQt/Settings/GameCubePane.cpp index 8c89badf00..944efa7a9f 100644 --- a/Source/Core/DolphinQt/Settings/GameCubePane.cpp +++ b/Source/Core/DolphinQt/Settings/GameCubePane.cpp @@ -149,9 +149,7 @@ void GameCubePane::CreateWidgets() EXIDeviceType::Dummy, EXIDeviceType::Ethernet, EXIDeviceType::EthernetXLink, -#ifdef __APPLE__ EXIDeviceType::EthernetTapServer, -#endif EXIDeviceType::EthernetBuiltIn, }) { @@ -355,6 +353,7 @@ void GameCubePane::UpdateButton(ExpansionInterface::Slot slot) case ExpansionInterface::Slot::SP1: has_config = (device == ExpansionInterface::EXIDeviceType::Ethernet || device == ExpansionInterface::EXIDeviceType::EthernetXLink || + device == ExpansionInterface::EXIDeviceType::EthernetTapServer || device == ExpansionInterface::EXIDeviceType::EthernetBuiltIn); break; } @@ -400,6 +399,13 @@ void GameCubePane::OnConfigPressed(ExpansionInterface::Slot slot) dialog.exec(); return; } + case ExpansionInterface::EXIDeviceType::EthernetTapServer: + { + BroadbandAdapterSettingsDialog dialog(this, BroadbandAdapterSettingsDialog::Type::TapServer); + SetQWidgetWindowDecorations(&dialog); + dialog.exec(); + return; + } case ExpansionInterface::EXIDeviceType::EthernetBuiltIn: { BroadbandAdapterSettingsDialog dialog(this, BroadbandAdapterSettingsDialog::Type::BuiltIn);