Merge pull request #9117 from fuzziqersoftware/add-tapserver-bba

Add tapserver network interface for macOS since TunTap is now unmaintained
This commit is contained in:
Léo Lam 2020-12-15 03:08:26 +01:00 committed by GitHub
commit 2feb5f204a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 173 additions and 7 deletions

View File

@ -623,6 +623,7 @@ if(WIN32)
elseif(APPLE)
target_sources(core PRIVATE
HW/EXI/BBA/TAP_Apple.cpp
HW/EXI/BBA/TAPServer_Apple.cpp
HW/EXI/BBA/XLINK_KAI_BBA.cpp
HW/WiimoteReal/IOdarwin.h
HW/WiimoteReal/IOdarwin_private.h

View File

@ -0,0 +1,127 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Core/HW/EXI/EXI_Device.h"
#include "Core/HW/EXI/EXI_DeviceEthernet.h"
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";
bool CEXIETHERNET::TAPServerNetworkInterface::Activate()
{
if (IsActivated())
return true;
sockaddr_un sun = {};
if (sizeof(socket_path) > sizeof(sun.sun_path))
{
ERROR_LOG(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(SP1, "Couldn't create socket, unable to init BBA");
return false;
}
if (connect(fd, reinterpret_cast<sockaddr*>(&sun), sizeof(sun)) == -1)
{
ERROR_LOG(SP1, "Couldn't connect socket (%d), unable to init BBA", errno);
close(fd);
fd = -1;
return false;
}
INFO_LOG(SP1, "BBA initialized.\n");
return RecvInit();
}
bool CEXIETHERNET::TAPServerNetworkInterface::SendFrame(const u8* frame, u32 size)
{
{
const std::string s = ArrayToString(frame, size, 0x10);
INFO_LOG(SP1, "SendFrame %x\n%s\n", size, s.c_str());
}
auto size16 = u16(size);
if (write(fd, &size16, 2) != 2)
{
ERROR_LOG(SP1, "SendFrame(): could not write size field\n");
return false;
}
int written_bytes = write(fd, frame, size);
if (u32(written_bytes) != size)
{
ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", size,
written_bytes);
return false;
}
else
{
m_eth_ref->SendComplete();
return true;
}
}
void CEXIETHERNET::TAPServerNetworkInterface::ReadThreadHandler()
{
while (!readThreadShutdown.IsSet())
{
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 50000;
if (select(fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0)
continue;
u16 size;
if (read(fd, &size, 2) != 2)
{
ERROR_LOG(SP1, "Failed to read size field from BBA, err=%d", errno);
}
else
{
int read_bytes = read(fd, m_eth_ref->mRecvBuffer.get(), size);
if (read_bytes < 0)
{
ERROR_LOG(SP1, "Failed to read packet data from BBA, err=%d", errno);
}
else if (readEnabled.IsSet())
{
std::string data_string = ArrayToString(m_eth_ref->mRecvBuffer.get(), read_bytes, 0x10);
INFO_LOG(SP1, "Read data: %s", data_string.c_str());
m_eth_ref->mRecvBufferLength = read_bytes;
m_eth_ref->RecvHandlePacket();
}
}
}
}
bool CEXIETHERNET::TAPServerNetworkInterface::RecvInit()
{
readThread = std::thread(&CEXIETHERNET::TAPServerNetworkInterface::ReadThreadHandler, this);
return true;
}
} // namespace ExpansionInterface

View File

@ -136,6 +136,12 @@ std::unique_ptr<IEXIDevice> EXIDevice_Create(const TEXIDevices device_type, cons
result = std::make_unique<CEXIETHERNET>(BBADeviceType::TAP);
break;
#if defined(__APPLE__)
case EXIDEVICE_ETHTAPSERVER:
result = std::make_unique<CEXIETHERNET>(BBADeviceType::TAPSERVER);
break;
#endif
case EXIDEVICE_ETHXLINK:
result = std::make_unique<CEXIETHERNET>(BBADeviceType::XLINK);
break;

View File

@ -33,6 +33,9 @@ enum TEXIDevices : int
EXIDEVICE_MEMORYCARDFOLDER,
EXIDEVICE_AGP,
EXIDEVICE_ETHXLINK,
#if defined(__APPLE__)
EXIDEVICE_ETHTAPSERVER,
#endif
EXIDEVICE_NONE = 0xFF
};

View File

@ -48,6 +48,12 @@ CEXIETHERNET::CEXIETHERNET(BBADeviceType type)
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);
INFO_LOG(SP1, "Created tapserver physical network interface.");
break;
#endif
case BBADeviceType::XLINK:
// TODO start BBA with network link down, bring it up after "connected" response from XLink

View File

@ -202,6 +202,9 @@ enum class BBADeviceType
{
TAP,
XLINK,
#if defined(__APPLE__)
TAPSERVER,
#endif
};
class CEXIETHERNET : public IEXIDevice
@ -337,7 +340,7 @@ private:
void RecvStart() override;
void RecvStop() override;
private:
protected:
#if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__OpenBSD__)
std::thread readThread;
@ -356,6 +359,22 @@ private:
#endif
};
#if defined(__APPLE__)
class TAPServerNetworkInterface : public TAPNetworkInterface
{
public:
explicit TAPServerNetworkInterface(CEXIETHERNET* eth_ref) : TAPNetworkInterface(eth_ref) {}
public:
bool Activate() override;
bool SendFrame(const u8* frame, u32 size) override;
bool RecvInit() override;
private:
void ReadThreadHandler();
};
#endif
class XLinkNetworkInterface : public NetworkInterface
{
public:

View File

@ -100,12 +100,16 @@ void GameCubePane::CreateWidgets()
// Add SP1 devices
for (const auto& entry :
{std::make_pair(tr("<Nothing>"), ExpansionInterface::EXIDEVICE_NONE),
std::make_pair(tr("Dummy"), ExpansionInterface::EXIDEVICE_DUMMY),
std::make_pair(tr("Broadband Adapter (TAP)"), ExpansionInterface::EXIDEVICE_ETH),
std::make_pair(tr("Broadband Adapter (XLink Kai)"),
ExpansionInterface::EXIDEVICE_ETHXLINK)})
std::vector<std::pair<QString, ExpansionInterface::TEXIDevices>> sp1Entries{
std::make_pair(tr("<Nothing>"), ExpansionInterface::EXIDEVICE_NONE),
std::make_pair(tr("Dummy"), ExpansionInterface::EXIDEVICE_DUMMY),
std::make_pair(tr("Broadband Adapter (TAP)"), ExpansionInterface::EXIDEVICE_ETH),
std::make_pair(tr("Broadband Adapter (XLink Kai)"), ExpansionInterface::EXIDEVICE_ETHXLINK)};
#if defined(__APPLE__)
sp1Entries.emplace_back(std::make_pair(tr("Broadband Adapter (tapserver)"),
ExpansionInterface::EXIDEVICE_ETHTAPSERVER));
#endif
for (const auto& entry : sp1Entries)
{
m_slot_combos[2]->addItem(entry.first, entry.second);
}