/**************************************************************************** * Copyright (C) 2016-2018 Maschell * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . ****************************************************************************/ #include "CPTCPServer.hpp" #include #include #include #include #include CPTCPServer *CPTCPServer::instance = NULL; CPTCPServer::CPTCPServer(int32_t port) : TCPServer(port, CPTCPServer::getPriority()) { CPTCPServer::AttachDetach(HID_DEVICE_DETACH); } CPTCPServer::~CPTCPServer() { DEBUG_FUNCTION_LINE("~CPTCPServer"); CPTCPServer::AttachDetach(HID_DEVICE_DETACH); } void CPTCPServer::AttachDetach(HIDAttachEvent attach) { if (HID_DEBUG) { if (attach) { DEBUG_FUNCTION_LINE("Network Attach"); } else { DEBUG_FUNCTION_LINE("Network Detach"); } } for (int32_t i = 0; i < gHIDMaxDevices; i++) { for (int32_t j = 0; j < HID_MAX_PADS_COUNT; j++) { if (gNetworkController[i][j][NETWORK_CONTROLLER_ACTIVE] > 0) { DEBUG_FUNCTION_LINE("Found a registered pad in deviceslot %d and padslot %d! Lets detach it.", i, j); HIDDevice device; memset(&device, 0, sizeof(device)); device.interfaceIndex = 0; device.vid = gNetworkController[i][j][NETWORK_CONTROLLER_VID]; device.pid = gNetworkController[i][j][NETWORK_CONTROLLER_PID]; device.handle = gNetworkController[i][j][NETWORK_CONTROLLER_HANDLE]; device.maxPacketSizeRx = 8; ControllerPatcherHID::externAttachDetachCallback(&device, attach); memset(gNetworkController[i][j], 0, sizeof(gNetworkController[i][j])); } } } if (HID_DEBUG) { if (attach) { DEBUG_FUNCTION_LINE("Network Attach DONE!"); } else { DEBUG_FUNCTION_LINE("Network Detach DONE!"); } } } void CPTCPServer::DetachAndDelete() { CPTCPServer::AttachDetach(HID_DEVICE_DETACH); memset(&gNetworkController, 0, sizeof(gNetworkController)); } BOOL CPTCPServer::whileLoop() { int32_t ret; int32_t clientfd = getClientFD(); while (1) { if (shouldExit()) { break; } ret = checkbyte(clientfd); if (ret < 0) { if (errno != EWOULDBLOCK) { return false; } OSSleepTicks(OSMicrosecondsToTicks(1000)); continue; } //DEBUG_FUNCTION_LINE("got byte from tcp! %01X",ret); switch (ret) { case WIIU_CP_TCP_ATTACH: { /*attach */ if (gUsedProtocolVersion >= WIIU_CP_TCP_HANDSHAKE_VERSION_1) { int32_t handle; ret = recvwait(clientfd, &handle, 4); if (ret < 0) { DEBUG_FUNCTION_LINE("Error in %02X: recvwait handle", WIIU_CP_TCP_ATTACH); return false; } if (HID_DEBUG) { DEBUG_FUNCTION_LINE("got handle %d", handle); } uint16_t vid = 0; uint16_t pid = 0; ret = recvwait(clientfd, &vid, 2); if (ret < 0) { DEBUG_FUNCTION_LINE("Error in %02X: recvwait vid", WIIU_CP_TCP_ATTACH); return false; } if (HID_DEBUG) { DEBUG_FUNCTION_LINE("got vid %04X", vid); } ret = recvwait(clientfd, &pid, 2); if (ret < 0) { DEBUG_FUNCTION_LINE("Error in %02X: recvwait pid", WIIU_CP_TCP_ATTACH); return false; } if (HID_DEBUG) { DEBUG_FUNCTION_LINE("got pid %04X", pid); } HIDDevice device; memset(&device, 0, sizeof(device)); device.handle = handle; device.interfaceIndex = 0; device.vid = SWAP16(vid); device.pid = SWAP16(pid); device.maxPacketSizeRx = 8; my_cb_user *user = NULL; ControllerPatcherHID::externAttachDetachCallback(&device, HID_DEVICE_ATTACH); if ((ret = ControllerPatcherUtils::getDataByHandle(handle, &user)) < 0) { DEBUG_FUNCTION_LINE("Error in %02X: getDataByHandle(%d,%08X).", WIIU_CP_TCP_ATTACH, handle, &user); DEBUG_FUNCTION_LINE("Error in %02X: Config for the controller is missing.", WIIU_CP_TCP_ATTACH); if ((ret = sendbyte(clientfd, WIIU_CP_TCP_ATTACH_CONFIG_NOT_FOUND) < 0)) { DEBUG_FUNCTION_LINE("Error in %02X: Sending the WIIU_CP_TCP_ATTACH_CONFIG_NOT_FOUND byte failed. Error: %d.", WIIU_CP_TCP_ATTACH, ret); } return false; } if ((ret = sendbyte(clientfd, WIIU_CP_TCP_ATTACH_CONFIG_FOUND) < 0)) { DEBUG_FUNCTION_LINE("Error in %02X: Sending the WIIU_CP_TCP_ATTACH_CONFIG_FOUND byte failed. Error: %d.", WIIU_CP_TCP_ATTACH, ret); return false; } if (user != NULL) { if ((ret = sendbyte(clientfd, WIIU_CP_TCP_ATTACH_USER_DATA_OKAY) < 0)) { DEBUG_FUNCTION_LINE("Error in %02X: Sending the WIIU_CP_TCP_ATTACH_USER_DATA_OKAY byte failed. Error: %d.", WIIU_CP_TCP_ATTACH, ret); return false; } ret = sendwait(clientfd, &user->slotdata.deviceslot, 2); if (ret < 0) { DEBUG_FUNCTION_LINE("Error in %02X: sendwait slotdata: %04X", WIIU_CP_TCP_ATTACH, user->slotdata.deviceslot); return false; } ret = sendwait(clientfd, &user->pad_slot, 1); if (ret < 0) { DEBUG_FUNCTION_LINE("Error in %02X: sendwait pad_slot: %04X", WIIU_CP_TCP_ATTACH, user->pad_slot); return false; } } else { DEBUG_FUNCTION_LINE("Error in %02X: invalid user data.", WIIU_CP_TCP_ATTACH); if ((ret = sendbyte(clientfd, WIIU_CP_TCP_ATTACH_USER_DATA_BAD) < 0)) { DEBUG_FUNCTION_LINE("Error in %02X: Sending the WIIU_CP_TCP_ATTACH_USER_DATA_BAD byte failed. Error: %d.", WIIU_CP_TCP_ATTACH, ret); return false; } return false; break; } if (HID_DEBUG) { DEBUG_FUNCTION_LINE("attachted to device slot: %d , pad slot is: %d", user->slotdata.deviceslot, user->pad_slot); } gNetworkController[user->slotdata.deviceslot][user->pad_slot][NETWORK_CONTROLLER_VID] = device.vid; gNetworkController[user->slotdata.deviceslot][user->pad_slot][NETWORK_CONTROLLER_PID] = device.pid; gNetworkController[user->slotdata.deviceslot][user->pad_slot][NETWORK_CONTROLLER_ACTIVE] = 1; gNetworkController[user->slotdata.deviceslot][user->pad_slot][NETWORK_CONTROLLER_HANDLE] = handle; if (HID_DEBUG) { DEBUG_FUNCTION_LINE("handle %d connected! vid: %02X pid: %02X deviceslot %d, padslot %d", handle, vid, pid, user->slotdata.deviceslot, user->pad_slot); } break; } break; } case WIIU_CP_TCP_DETACH: { /*detach */ if (gUsedProtocolVersion >= WIIU_CP_TCP_HANDSHAKE_VERSION_1) { int32_t handle; ret = recvwait(clientfd, &handle, 4); if (ret < 0) { DEBUG_FUNCTION_LINE("Error in %02X: recvwait handle", WIIU_CP_TCP_DETACH); return false; break; } if (HID_DEBUG) { DEBUG_FUNCTION_LINE("got detach for handle: %d", handle); } my_cb_user *user = NULL; if (ControllerPatcherUtils::getDataByHandle(handle, &user) < 0) { DEBUG_FUNCTION_LINE("Error in %02X: getDataByHandle(%d,%08X).", WIIU_CP_TCP_DETACH, handle, &user); return false; break; } if (user == NULL) { DEBUG_FUNCTION_LINE("Error in %02X: invalid user data.", WIIU_CP_TCP_DETACH); return false; break; } int32_t deviceslot = user->slotdata.deviceslot; if (HID_DEBUG) { DEBUG_FUNCTION_LINE("device slot is: %d , pad slot is: %d", deviceslot, user->pad_slot); } DeviceVIDPIDInfo vidpid; int32_t result; if ((result = ControllerPatcherUtils::getVIDPIDbyDeviceSlot(deviceslot, &vidpid)) < 0) { DEBUG_FUNCTION_LINE("Error in %02X: Couldn't find a valid VID/PID for device slot %d. Error: %d", WIIU_CP_TCP_DETACH, deviceslot, ret); return false; break; } HIDDevice device; memset(&device, 0, sizeof(device)); device.handle = handle; device.interfaceIndex = 0; device.vid = SWAP16(vidpid.vid); device.pid = SWAP16(vidpid.pid); device.maxPacketSizeRx = 14; ControllerPatcherHID::externAttachDetachCallback(&device, HID_DEVICE_DETACH); memset(gNetworkController[deviceslot][user->pad_slot], 0, sizeof(gNetworkController[deviceslot][user->pad_slot])); if (HID_DEBUG) { DEBUG_FUNCTION_LINE("handle %d disconnected!", handle); } break; } break; } case WIIU_CP_TCP_PING: { /*ping*/ if (gUsedProtocolVersion >= WIIU_CP_TCP_HANDSHAKE_VERSION_1) { if (HID_DEBUG) { DEBUG_FUNCTION_LINE("Got Ping, sending now a Pong"); } int32_t ret = sendbyte(clientfd, WIIU_CP_TCP_PONG); if (ret < 0) { DEBUG_FUNCTION_LINE("Error in %02X: sendbyte PONG"); return false; } break; } break; } default: return false; break; } } return true; } BOOL CPTCPServer::acceptConnection() { int32_t clientfd = getClientFD(); DEBUG_FUNCTION_LINE("TCP Connection accepted! Sending my protocol version: %d (0x%02X)", (WIIU_CP_TCP_HANDSHAKE - WIIU_CP_TCP_HANDSHAKE_VERSION_1) + 1, WIIU_CP_TCP_HANDSHAKE); gUDPClientip = getSockAddr().sin_addr.s_addr; UDPClient::createInstance(); int32_t ret; ret = sendbyte(clientfd, WIIU_CP_TCP_HANDSHAKE); //Hey I'm a WiiU console! if (ret < 0) { DEBUG_FUNCTION_LINE("Error sendbyte: %02X", WIIU_CP_TCP_HANDSHAKE); return false; } uint8_t clientProtocolVersion = recvbyte(clientfd); if (ret < 0) { DEBUG_FUNCTION_LINE("Error recvbyte: %02X", WIIU_CP_TCP_HANDSHAKE); return false; } if (clientProtocolVersion == WIIU_CP_TCP_HANDSHAKE_ABORT) { DEBUG_FUNCTION_LINE("The network client wants to abort."); return false; } DEBUG_FUNCTION_LINE("received protocol version: %d (0x%02X)", (clientProtocolVersion - WIIU_CP_TCP_HANDSHAKE_VERSION_1) + 1, clientProtocolVersion); if (clientProtocolVersion >= WIIU_CP_TCP_HANDSHAKE_VERSION_MIN && clientProtocolVersion <= WIIU_CP_TCP_HANDSHAKE_VERSION_MAX) { DEBUG_FUNCTION_LINE("We support this protocol version. Let's confirm it to the network client."); gUsedProtocolVersion = clientProtocolVersion; ret = sendbyte(clientfd, clientProtocolVersion); if (ret < 0) { DEBUG_FUNCTION_LINE("Error sendbyte: %02X", clientProtocolVersion); return false; } } else { DEBUG_FUNCTION_LINE("We don't support this protocol version. We need to abort =(."); ret = sendbyte(clientfd, WIIU_CP_TCP_HANDSHAKE_ABORT); return false; } DEBUG_FUNCTION_LINE("Handshake done! Success!"); return true; } void CPTCPServer::onConnectionClosed() { gUDPClientip = 0; UDPClient::destroyInstance(); CPTCPServer::DetachAndDelete(); //Clear connected controller }