From 891fb056a3c28b7ad46c30a2ae7dc4cb042d08a5 Mon Sep 17 00:00:00 2001 From: SlEePlEs5 Date: Sat, 12 Apr 2014 01:38:22 +0200 Subject: [PATCH] Added BBA TAP backend for OS X. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TUN/TAP OS X needs to be installed, and /dev/tap0 chown’d to the user. The tap0 network interface doesn’t appear until /dev/tap0 is opened by the program, so all bridging must be done once the game is already running. Unfortunately, bridging seems to be broken on OS X, so this does not actually work over LAN (yet!). --- Source/Core/Core/HW/BBA-TAP/TAP_Apple.cpp | 84 ++++++++++++++++++++-- Source/Core/Core/HW/EXI_DeviceEthernet.cpp | 2 +- Source/Core/Core/HW/EXI_DeviceEthernet.h | 2 +- 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/Source/Core/Core/HW/BBA-TAP/TAP_Apple.cpp b/Source/Core/Core/HW/BBA-TAP/TAP_Apple.cpp index 6d658121f2..07c892e312 100644 --- a/Source/Core/Core/HW/BBA-TAP/TAP_Apple.cpp +++ b/Source/Core/Core/HW/BBA-TAP/TAP_Apple.cpp @@ -2,38 +2,110 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include "Common/StringUtil.h" #include "Core/HW/EXI_Device.h" #include "Core/HW/EXI_DeviceEthernet.h" bool CEXIETHERNET::Activate() { - return false; + if (IsActivated()) + return true; + + // Assumes TunTap OS X is installed, and /dev/tun0 is not in use + // and readable / writable by the logged-in user + + if ((fd = open("/dev/tap0", O_RDWR)) < 0) + { + ERROR_LOG(SP1, "Couldn't open /dev/tap0, unable to init BBA"); + return false; + } + + readEnabled = false; + + INFO_LOG(SP1, "BBA initialized."); + return true; } void CEXIETHERNET::Deactivate() { + close(fd); + fd = -1; + + readEnabled = false; + if (readThread.joinable()) + readThread.join(); } bool CEXIETHERNET::IsActivated() { - return false; + return fd != -1; } -bool CEXIETHERNET::SendFrame(u8 *, u32) +bool CEXIETHERNET::SendFrame(u8* frame, u32 size) { - return false; + INFO_LOG(SP1, "SendFrame %x\n%s", size, ArrayToString(frame, size, 0x10).c_str()); + + int writtenBytes = write(fd, frame, size); + if ((u32)writtenBytes != size) + { + ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", + size, writtenBytes); + return false; + } + else + { + SendComplete(); + return true; + } +} + +void ReadThreadHandler(CEXIETHERNET* self) +{ + while (true) + { + if (self->fd < 0) + return; + + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(self->fd, &rfds); + + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; + if (select(self->fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0) + continue; + + int readBytes = read(self->fd, self->mRecvBuffer, BBA_RECV_SIZE); + if (readBytes < 0) + { + ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes); + } + else if (self->readEnabled) + { + INFO_LOG(SP1, "Read data: %s", ArrayToString(self->mRecvBuffer, readBytes, 0x10).c_str()); + self->mRecvBufferLength = readBytes; + self->RecvHandlePacket(); + } + } } bool CEXIETHERNET::RecvInit() { - return false; + readThread = std::thread(ReadThreadHandler, this); + return true; } bool CEXIETHERNET::RecvStart() { - return false; + if (!readThread.joinable()) + RecvInit(); + + readEnabled = true; + return true; } void CEXIETHERNET::RecvStop() { + readEnabled = false; } diff --git a/Source/Core/Core/HW/EXI_DeviceEthernet.cpp b/Source/Core/Core/HW/EXI_DeviceEthernet.cpp index aa6342322e..3cb9bc4cf4 100644 --- a/Source/Core/Core/HW/EXI_DeviceEthernet.cpp +++ b/Source/Core/Core/HW/EXI_DeviceEthernet.cpp @@ -44,7 +44,7 @@ CEXIETHERNET::CEXIETHERNET() mHAdapter = INVALID_HANDLE_VALUE; mHRecvEvent = INVALID_HANDLE_VALUE; mHReadWait = INVALID_HANDLE_VALUE; -#elif defined(__linux__) +#elif defined(__linux__) || defined(__APPLE__) fd = -1; #endif } diff --git a/Source/Core/Core/HW/EXI_DeviceEthernet.h b/Source/Core/Core/HW/EXI_DeviceEthernet.h index 182f6c28b3..f1747301e8 100644 --- a/Source/Core/Core/HW/EXI_DeviceEthernet.h +++ b/Source/Core/Core/HW/EXI_DeviceEthernet.h @@ -319,7 +319,7 @@ public: DWORD mMtu; OVERLAPPED mReadOverlapped; static VOID CALLBACK ReadWaitCallback(PVOID lpParameter, BOOLEAN TimerFired); -#elif defined(__linux__) +#elif defined(__linux__) || defined(__APPLE__) int fd; std::thread readThread; volatile bool readEnabled;