/**************************************************************************** * Copyright (C) 2016,2017 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 "TCPServer.hpp" #include #include #include #include #include "../ControllerPatcher.hpp" #include "./ControllerPatcherNet.hpp" #define WIIU_CP_TCP_HANDSHAKE 0x12 #define WIIU_CP_TCP_SAME_CLIENT 0x20 #define WIIU_CP_TCP_NEW_CLIENT 0x21 #define ATTACH 0x01 #define DETACH 0x00 #define WIIU_CP_TCP_ATTACH 0x01 #define WIIU_CP_TCP_DETACH 0x02 #define WIIU_CP_TCP_PING 0xF0 #define WIIU_CP_TCP_PONG 0xF1 #define WIIU_CP_TCP_ATTACH_CONFIG_FOUND 0xE0 #define WIIU_CP_TCP_ATTACH_CONFIG_NOT_FOUND 0xE1 #define WIIU_CP_TCP_ATTACH_USER_DATA_OKAY 0xE8 #define WIIU_CP_TCP_ATTACH_USER_DATA_BAD 0xE9 #define errno (*__gh_errno_ptr()) ControllerPatcherThread * TCPServer::pThread = NULL; TCPServer * TCPServer::instance = NULL; TCPServer::TCPServer(int port){ this->sockfd = -1; this->clientfd = -1; memset(&(this->sock_addr),0,sizeof(this->sock_addr)); TCPServer::AttachDetach(DETACH); StartTCPThread(this); } TCPServer::~TCPServer(){ CloseSockets(); if(HID_DEBUG) log_printf("TCPServer: Thread will be closed\n"); TCPServer::AttachDetach(DETACH); exitThread = 1; if(TCPServer::pThread != NULL){ if(HID_DEBUG) log_printf("TCPServer: Deleting it!\n"); delete TCPServer::pThread; } if(HID_DEBUG) log_printf("TCPServer: Thread done\n"); TCPServer::pThread = NULL; } void TCPServer::CloseSockets(){ if (this->sockfd != -1){ socketclose(this->sockfd); } if (this->clientfd != -1){ socketclose(this->clientfd); } this->sockfd = -1; this->clientfd = -1; } void TCPServer::StartTCPThread(TCPServer * server){ TCPServer::pThread = ControllerPatcherThread::create(TCPServer::DoTCPThread, (void*)server, ControllerPatcherThread::eAttributeAffCore2,28); TCPServer::pThread->resumeThread(); } void TCPServer::AttachDetach(int attach){ if(HID_DEBUG){ if(attach){ log_printf("TCPServer: Network Attach\n"); }else{ log_printf("TCPServer: Network Detach\n"); } } for(int i= 0;i< gHIDMaxDevices;i++){ for(int j= 0;j< HID_MAX_PADS_COUNT;j++){ if(gNetworkController[i][j][NETWORK_CONTROLLER_ACTIVE] > 0){ log_printf("Found a registered pad in deviceslot %d and padslot %d! Lets detach it.\n",i,j); HIDDevice device; memset(&device,0,sizeof(device)); device.interface_index = 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.max_packet_size_rx = 8; ControllerPatcherHID::externAttachDetachCallback(&device,attach); memset(gNetworkController[i][j],0,sizeof(gNetworkController[i][j])); } } } if(HID_DEBUG){ if(attach){ log_printf("TCPServer: Network Attach DONE!\n"); }else{ log_printf("TCPServer: Network Detach DONE!\n"); } } } void TCPServer::DetachAndDelete(){ TCPServer::AttachDetach(DETACH); memset(&gNetworkController,0,sizeof(gNetworkController)); } int TCPServer::RunTCP(){ int ret; while (1) { if(exitThread) break; ret = ControllerPatcherNet::checkbyte(clientfd); if (ret < 0) { if(errno != 6) return ret; usleep(1000); continue; } //log_printf("got byte from tcp! %01X\n",ret); switch (ret) { case WIIU_CP_TCP_ATTACH: { /*attach */ int handle; ret = ControllerPatcherNet::recvwait(clientfd, &handle, 4); if(ret < 0){ log_printf("TCPServer::RunTCP() Error in %02X: recvwait handle\n",WIIU_CP_TCP_ATTACH); return ret; } if(HID_DEBUG) log_printf("TCPServer: got handle %d\n",handle); u16 vid = 0; u16 pid = 0; ret = ControllerPatcherNet::recvwait(clientfd, &vid, 2); if(ret < 0){ log_printf("TCPServer::RunTCP() Error in %02X: recvwait vid\n",WIIU_CP_TCP_ATTACH); return ret; } if(HID_DEBUG) log_printf("TCPServer: got vid %04X\n",vid); ret = ControllerPatcherNet::recvwait(clientfd, &pid, 2); if(ret < 0){ log_printf("TCPServer::RunTCP() Error in %02X: recvwait pid\n",WIIU_CP_TCP_ATTACH); return ret; } if(HID_DEBUG) log_printf("TCPServer: got pid %04X\n",pid); HIDDevice device; memset(&device,0,sizeof(device)); device.handle = handle; device.interface_index = 0; device.vid = SWAP16(vid); device.pid = SWAP16(pid); device.max_packet_size_rx = 8; my_cb_user * user = NULL; ControllerPatcherHID::externAttachDetachCallback(&device,1); if((ret = ControllerPatcherUtils::getDataByHandle(handle,&user)) < 0){ log_printf("TCPServer::RunTCP() Error in %02X: getDataByHandle(%d,%08X).\n",WIIU_CP_TCP_ATTACH,handle,&user); log_printf("TCPServer::RunTCP() Error in %02X: Config for the controller is missing.\n",WIIU_CP_TCP_ATTACH); if((ret = ControllerPatcherNet::sendbyte(clientfd, WIIU_CP_TCP_ATTACH_CONFIG_NOT_FOUND) < 0)){ log_printf("TCPServer::RunTCP() Error in %02X: Sending the WIIU_CP_TCP_ATTACH_CONFIG_NOT_FOUND byte failed. Error: %d.\n",WIIU_CP_TCP_ATTACH,ret); } return -1; } if((ret = ControllerPatcherNet::sendbyte(clientfd, WIIU_CP_TCP_ATTACH_CONFIG_FOUND) < 0)){ log_printf("TCPServer::RunTCP() Error in %02X: Sending the WIIU_CP_TCP_ATTACH_CONFIG_FOUND byte failed. Error: %d.\n",WIIU_CP_TCP_ATTACH,ret); return ret; } if(user != NULL){ if((ret = ControllerPatcherNet::sendbyte(clientfd, WIIU_CP_TCP_ATTACH_USER_DATA_OKAY) < 0)){ log_printf("TCPServer::RunTCP() Error in %02X: Sending the WIIU_CP_TCP_ATTACH_USER_DATA_OKAY byte failed. Error: %d.\n",WIIU_CP_TCP_ATTACH,ret); return ret; } ret = ControllerPatcherNet::sendwait(clientfd,&user->slotdata.deviceslot,2); if(ret < 0){ log_printf("TCPServer::RunTCP() Error in %02X: sendwait slotdata: %04X\n",WIIU_CP_TCP_ATTACH,user->slotdata.deviceslot); return ret; } ret = ControllerPatcherNet::sendwait(clientfd,&user->pad_slot,1); if(ret < 0){ log_printf("TCPServer::RunTCP() Error in %02X: sendwait pad_slot: %04X\n",WIIU_CP_TCP_ATTACH,user->pad_slot); return ret; } }else{ log_printf("TCPServer::RunTCP() Error in %02X: invalid user data.\n",WIIU_CP_TCP_ATTACH); if((ret = ControllerPatcherNet::sendbyte(clientfd, WIIU_CP_TCP_ATTACH_USER_DATA_BAD) < 0)){ log_printf("TCPServer::RunTCP() Error in %02X: Sending the WIIU_CP_TCP_ATTACH_USER_DATA_BAD byte failed. Error: %d.\n",WIIU_CP_TCP_ATTACH,ret); return ret; } return -1; break; } if(HID_DEBUG) log_printf("TCPServer: attachted to device slot: %d , pad slot is: %d\n",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) log_printf("TCPServer: handle %d connected! vid: %02X pid: %02X deviceslot %d, padslot %d\n",handle,vid,pid,user->slotdata.deviceslot,user->pad_slot); break; } case WIIU_CP_TCP_DETACH: { /*detach */ int handle; ret = ControllerPatcherNet::recvwait(clientfd, &handle, 4); if(ret < 0){ log_printf("TCPServer::RunTCP() Error in %02X: recvwait handle\n",WIIU_CP_TCP_DETACH); return ret; break; } if(HID_DEBUG) log_printf("TCPServer: got detach for handle: %d\n",handle); my_cb_user * user = NULL; if(ControllerPatcherUtils::getDataByHandle(handle,&user) < 0){ log_printf("TCPServer::RunTCP() Error in %02X: getDataByHandle(%d,%08X).\n",WIIU_CP_TCP_DETACH,handle,&user); return -1; break; } if(user == NULL){ log_printf("TCPServer::RunTCP() Error in %02X: invalid user data.\n",WIIU_CP_TCP_DETACH); return -1; break; } int deviceslot = user->slotdata.deviceslot; if(HID_DEBUG) log_printf("TCPServer: device slot is: %d , pad slot is: %d\n",deviceslot,user->pad_slot); DeviceVIDPIDInfo vidpid; int result; if((result = ControllerPatcherUtils::getVIDPIDbyDeviceSlot(deviceslot,&vidpid)) < 0){ log_printf("TCPServer::RunTCP() Error in %02X: Couldn't find a valid VID/PID for device slot %d. Error: %d\n",WIIU_CP_TCP_DETACH,deviceslot,ret); return -1; break; } HIDDevice device; memset(&device,0,sizeof(device)); device.handle = handle; device.interface_index = 0; device.vid = SWAP16(vidpid.vid); device.pid = SWAP16(vidpid.pid); device.max_packet_size_rx = 14; ControllerPatcherHID::externAttachDetachCallback(&device,DETACH); memset(gNetworkController[deviceslot][user->pad_slot],0,sizeof(gNetworkController[deviceslot][user->pad_slot])); if(HID_DEBUG) log_printf("TCPServer: handle %d disconnected!\n",handle); break; } case WIIU_CP_TCP_PING: { /*ping*/ if(HID_DEBUG) log_printf("TCPServer: GOT PING\n"); int ret = ControllerPatcherNet::sendbyte(clientfd, WIIU_CP_TCP_PONG); if(ret < 0){ log_printf("TCPServer::RunTCP() Error in %02X: sendbyte PONG\n"); return -1;} break; } default: return -1; break; } } return 0; } void TCPServer::ErrorHandling(){ CloseSockets(); usleep(1000*1000*2); } void TCPServer::DoTCPThreadInternal(){ int ret; s32 len; while (1) { if(exitThread) break; memset(&(this->sock_addr),0,sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_port = DEFAULT_TCP_PORT; sock_addr.sin_addr.s_addr = 0; this->sockfd = ret = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(ret == -1){ ErrorHandling(); continue;} int enable = 1; setsockopt(this->sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); ret = bind(this->sockfd, (sockaddr *)&sock_addr, 16); if(ret < 0) { ErrorHandling(); continue;} ret = listen(this->sockfd, 1); if(ret < 0){ ErrorHandling(); continue;} do{ if(HID_DEBUG) log_printf("TCPServer::DoTCPThreadInternal: Waiting for a connection\n"); if(exitThread) break; len = 16; clientfd = ret = accept(sockfd, (sockaddr *)&(sock_addr), &len); if(HID_DEBUG) log_printf("TCPServer::DoTCPThreadInternal: Connection accepted\n"); if(ret == -1){ ErrorHandling(); break;} int ret; ret = ControllerPatcherNet::sendbyte(clientfd, WIIU_CP_TCP_HANDSHAKE); //Hey I'm a WiiU console! if(ret < 0){ log_printf("TCPServer::DoTCPThreadInternal: Error sendbyte: %02X\n",WIIU_CP_TCP_HANDSHAKE); ErrorHandling(); break;} if(ret < 0){ log_printf("TCPServer::DoTCPThreadInternal: Error sendbyte %02X/02X\n",WIIU_CP_TCP_NEW_CLIENT,WIIU_CP_TCP_SAME_CLIENT); ErrorHandling(); break;} TCPServer::DetachAndDelete(); //Clear connected controller RunTCP(); if(clientfd != -1){ socketclose(clientfd); } clientfd = -1; }while(0); TCPServer::DetachAndDelete(); //Clear connected controller CloseSockets(); if(HID_DEBUG) log_printf("TCPServer: Connection closed\n"); continue; } } void TCPServer::DoTCPThread(ControllerPatcherThread *thread, void *arg){ TCPServer * args = (TCPServer * )arg; return args->DoTCPThreadInternal(); }