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.
This commit is contained in:
Martin Michelsen 2023-02-12 17:58:17 -08:00
parent 85dee300b5
commit 0c364cbb4c
14 changed files with 134 additions and 44 deletions

View File

@ -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,

View File

@ -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(

View File

@ -133,6 +133,8 @@
<string name="xlink_kai_guide_header">For setup instructions, <a href="https://www.teamxlink.co.uk/wiki/Dolphin">refer to this page.</a></string>
<string name="xlink_kai_bba_ip">XLink Kai IP Address/hostname</string>
<string name="xlink_kai_bba_ip_description">IP address or hostname of device running the XLink Kai client</string>
<string name="bba_tapserver_destination">Tapserver destination</string>
<string name="bba_tapserver_destination_description">Enter the socket path or netloc (address:port) of the tapserver instance</string>
<string name="bba_builtin_dns">DNS Server</string>
<string name="bba_builtin_dns_description">Use 8.8.8.8 for normal DNS, else enter your custom one</string>

View File

@ -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()
endif()

View File

@ -137,6 +137,8 @@ const Info<bool> MAIN_BBA_XLINK_CHAT_OSD{{System::Main, "Core", "BBA_XLINK_CHAT_
// Schthack PSO Server - https://schtserv.com/
const Info<std::string> MAIN_BBA_BUILTIN_DNS{{System::Main, "Core", "BBA_BUILTIN_DNS"},
"3.18.217.27"};
const Info<std::string> MAIN_BBA_TAPSERVER_DESTINATION{
{System::Main, "Core", "BBA_TAPSERVER_DESTINATION"}, "/tmp/dolphin-tap"};
const Info<std::string> MAIN_BBA_BUILTIN_IP{{System::Main, "Core", "BBA_BUILTIN_IP"}, ""};
const Info<SerialInterface::SIDevices>& GetInfoForSIDevice(int channel)

View File

@ -96,6 +96,7 @@ extern const Info<std::string> MAIN_BBA_XLINK_IP;
extern const Info<bool> MAIN_BBA_XLINK_CHAT_OSD;
extern const Info<std::string> MAIN_BBA_BUILTIN_DNS;
extern const Info<std::string> MAIN_BBA_BUILTIN_IP;
extern const Info<std::string> MAIN_BBA_TAPSERVER_DESTINATION;
const Info<SerialInterface::SIDevices>& GetInfoForSIDevice(int channel);
const Info<bool>& GetInfoForAdapterRumble(int channel);
const Info<bool>& GetInfoForSimulateKonga(int channel);

View File

@ -3,10 +3,16 @@
#include "Core/HW/EXI/EXI_DeviceEthernet.h"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2ipdef.h>
#else
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#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<struct sockaddr_in*>(&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<struct sockaddr_un*>(&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<sockaddr*>(&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<sockaddr*>(&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();

View File

@ -137,11 +137,9 @@ std::unique_ptr<IEXIDevice> EXIDevice_Create(Core::System& system, const EXIDevi
result = std::make_unique<CEXIETHERNET>(system, BBADeviceType::TAP);
break;
#if defined(__APPLE__)
case EXIDeviceType::EthernetTapServer:
result = std::make_unique<CEXIETHERNET>(system, BBADeviceType::TAPSERVER);
break;
#endif
case EXIDeviceType::EthernetXLink:
result = std::make_unique<CEXIETHERNET>(system, BBADeviceType::XLINK);

View File

@ -39,7 +39,6 @@ enum class EXIDeviceType : int
MemoryCardFolder,
AGP,
EthernetXLink,
// Only used on Apple devices.
EthernetTapServer,
EthernetBuiltIn,
None = 0xFF

View File

@ -50,12 +50,11 @@ CEXIETHERNET::CEXIETHERNET(Core::System& system, BBADeviceType type) : IEXIDevic
m_network_interface = std::make_unique<TAPNetworkInterface>(this);
INFO_LOG_FMT(SP1, "Created TAP physical network interface.");
break;
#if defined(__APPLE__)
case BBADeviceType::TAPSERVER:
m_network_interface = std::make_unique<TAPServerNetworkInterface>(this);
m_network_interface = std::make_unique<TAPServerNetworkInterface>(
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<BuiltInBBAInterface>(
this, Config::Get(Config::MAIN_BBA_BUILTIN_DNS), Config::Get(Config::MAIN_BBA_BUILTIN_IP));

View File

@ -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
{

View File

@ -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;

View File

@ -15,6 +15,7 @@ public:
{
Ethernet,
XLinkKai,
TapServer,
BuiltIn
};

View File

@ -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);