controller_patcher/source/network/UDPServer.cpp

172 lines
6.5 KiB
C++
Raw Normal View History

/****************************************************************************
* 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 <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "UDPServer.hpp"
#include <malloc.h>
#include <stdio.h>
#include <string.h>
2017-05-07 14:44:09 +02:00
2017-10-29 09:34:47 +01:00
#include <utils/logger.h>
2017-05-07 14:44:09 +02:00
#define MAX_UDP_SIZE 0x578
2017-10-29 09:34:47 +01:00
CThread * UDPServer::pThread = NULL;
UDPServer * UDPServer::instance = NULL;
2018-06-20 15:07:15 +02:00
UDPServer::UDPServer(int32_t port) {
int32_t ret;
2018-06-19 17:46:37 +02:00
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr.s_addr = 0;
this->sockfd = ret = socket(AF_INET, SOCK_DGRAM, 0);
if(ret == -1) return;
2018-06-20 15:07:15 +02:00
int32_t enable = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
ret = bind(sockfd, (sockaddr *)&addr, 16);
if(ret < 0) return;
StartUDPThread(this);
}
2018-06-19 17:46:37 +02:00
UDPServer::~UDPServer() {
2017-10-29 09:34:47 +01:00
CThread * pThreadPointer = UDPServer::pThread;
2018-06-19 17:46:37 +02:00
if(pThreadPointer != NULL) {
exitThread = 1;
2018-06-19 17:46:37 +02:00
if(pThreadPointer != NULL) {
delete pThreadPointer;
UDPServer::pThread = NULL;
2018-06-19 17:46:37 +02:00
if (this->sockfd != -1) {
socketclose(sockfd);
}
this->sockfd = -1;
}
}
2018-06-19 17:46:37 +02:00
if(HID_DEBUG) {
2020-12-16 02:04:31 +01:00
DEBUG_FUNCTION_LINE("Thread has been closed");
2018-06-19 17:46:37 +02:00
}
}
2018-06-19 17:46:37 +02:00
void UDPServer::StartUDPThread(UDPServer * server) {
2018-06-20 15:07:15 +02:00
int32_t priority = 28;
if(OSGetTitleID() == 0x00050000101c9300 || //The Legend of Zelda Breath of the Wild JPN
2018-06-19 17:46:37 +02:00
OSGetTitleID() == 0x00050000101c9400 || //The Legend of Zelda Breath of the Wild USA
OSGetTitleID() == 0x00050000101c9500 || //The Legend of Zelda Breath of the Wild EUR
OSGetTitleID() == 0x00050000101c9b00 || //The Binding of Isaac: Rebirth EUR
OSGetTitleID() == 0x00050000101a3c00) { //The Binding of Isaac: Rebirth USA
priority = 10;
2020-12-16 02:04:31 +01:00
DEBUG_FUNCTION_LINE("This game needs higher thread priority. We set it to %d",priority);
}
2017-10-29 09:34:47 +01:00
UDPServer::pThread = CThread::create(UDPServer::DoUDPThread, (void*)server, CThread::eAttributeAffCore2,priority);
UDPServer::pThread->resumeThread();
}
2018-06-20 15:07:15 +02:00
BOOL UDPServer::cpyIncrementBufferOffset(void * target, void * source, int32_t * offset, int32_t typesize, int32_t maximum) {
2018-06-19 17:46:37 +02:00
if(((int)*offset + typesize) > maximum) {
2020-12-16 02:04:31 +01:00
DEBUG_FUNCTION_LINE("Transfer error. Excepted %04X bytes, but only got %04X",(*offset + typesize),maximum);
return false;
}
2018-06-20 15:07:15 +02:00
memcpy(target,(void*)((uint32_t)source+(*offset)),typesize);
*offset += typesize;
return true;
}
2018-06-19 17:46:37 +02:00
void UDPServer::DoUDPThread(CThread *thread, void *arg) {
UDPServer * args = (UDPServer * )arg;
args->DoUDPThreadInternal();
}
2018-06-19 17:46:37 +02:00
void UDPServer::DoUDPThreadInternal() {
2018-06-20 15:07:15 +02:00
uint8_t buffer[MAX_UDP_SIZE];
int32_t n;
my_cb_user user;
2018-06-19 17:46:37 +02:00
while(1) {
2018-06-20 15:07:15 +02:00
//int32_t usingVar = exitThread;
if(exitThread)break;
memset(buffer,0,MAX_UDP_SIZE);
n = recv(sockfd,buffer,MAX_UDP_SIZE,0);
2018-06-19 17:46:37 +02:00
if (n < 0) {
2018-06-20 15:07:15 +02:00
int32_t errno_ = socketlasterr();
OSSleepTicks(OSMicrosecondsToTicks(2000));
2018-06-19 17:46:37 +02:00
if(errno_ != 11 && errno_ != 9) {
break;
}
2018-06-19 17:46:37 +02:00
continue;
}
2018-06-20 15:07:15 +02:00
int32_t bufferoffset = 0;
uint8_t type;
memcpy((void *)&type,buffer,sizeof(type));
bufferoffset += sizeof(type);
switch (buffer[0]) {
2018-06-19 17:46:37 +02:00
case WIIU_CP_UDP_CONTROLLER_READ_DATA: {
if(gUsedProtocolVersion >= WIIU_CP_TCP_HANDSHAKE_VERSION_1) {
2018-06-20 15:07:15 +02:00
uint8_t count_commands;
2018-06-19 17:46:37 +02:00
memcpy((void *)&count_commands,buffer+bufferoffset,sizeof(count_commands));
bufferoffset += sizeof(count_commands);
2018-06-20 15:07:15 +02:00
for(int32_t i = 0; i<count_commands; i++) {
int32_t handle;
uint16_t deviceSlot;
uint32_t hid;
uint8_t padslot;
uint8_t datasize;
2018-06-19 17:46:37 +02:00
if(!cpyIncrementBufferOffset((void *)&handle, (void *)buffer,&bufferoffset,sizeof(handle), n))continue;
if(!cpyIncrementBufferOffset((void *)&deviceSlot, (void *)buffer,&bufferoffset,sizeof(deviceSlot),n))continue;
hid = (1 << deviceSlot);
if(!cpyIncrementBufferOffset((void *)&padslot, (void *)buffer,&bufferoffset,sizeof(padslot), n))continue;
if(!cpyIncrementBufferOffset((void *)&datasize, (void *)buffer,&bufferoffset,sizeof(datasize), n))continue;
2018-06-20 15:07:15 +02:00
uint8_t * databuffer = (uint8_t*) malloc(datasize * sizeof(uint8_t));
2018-06-19 17:46:37 +02:00
if(!databuffer) {
2020-12-16 02:04:31 +01:00
DEBUG_FUNCTION_LINE("Allocating memory failed");
2018-06-19 17:46:37 +02:00
continue;
}
if(!cpyIncrementBufferOffset((void *)databuffer, (void *)buffer,&bufferoffset,datasize, n))continue;
//DEBUG_FUNCTION_LINE("UDPServer::DoUDPThreadInternal(): Got handle: %d slot %04X hid %04X pad %02X datasize %02X\n",handle,deviceSlot,hid,padslot,datasize);
user.pad_slot = padslot;
user.slotdata.deviceslot = deviceSlot;
user.slotdata.hidmask = hid;
if(gNetworkController[deviceSlot][padslot][0] == 0) {
DEBUG_FUNCTION_LINE("Ehm. Pad is not connected. STOP SENDING DATA ;) \n");
} else {
ControllerPatcherHID::externHIDReadCallback(handle,databuffer,datasize,&user);
}
if(databuffer) {
free(databuffer);
databuffer = NULL;
}
}
break;
}
2018-06-19 17:46:37 +02:00
break;
}
default: {
break;
}
2018-06-19 17:46:37 +02:00
}
}
if(HID_DEBUG) {
2020-12-16 02:04:31 +01:00
DEBUG_FUNCTION_LINE("UDPServer Thread ended");
}
}