2017-03-30 17:53:36 +02:00
/****************************************************************************
* 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
# include "dynamic_libs/socket_functions.h"
# include "utils/logger.h"
2017-03-30 17:53:36 +02:00
# define MAX_UDP_SIZE 0x578
2017-04-10 15:39:58 +02:00
# define wiiu_errno (*__gh_errno_ptr())
2017-03-30 17:53:36 +02:00
ControllerPatcherThread * UDPServer : : pThread = NULL ;
UDPServer * UDPServer : : instance = NULL ;
2017-04-10 11:00:55 +02:00
UDPServer : : UDPServer ( s32 port ) {
s32 ret ;
2017-03-30 17:53:36 +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 ;
2017-04-10 11:00:55 +02:00
s32 enable = 1 ;
2017-03-30 17:53:36 +02:00
setsockopt ( sockfd , SOL_SOCKET , SO_REUSEADDR , & enable , sizeof ( enable ) ) ;
ret = bind ( sockfd , ( sockaddr * ) & addr , 16 ) ;
if ( ret < 0 ) return ;
StartUDPThread ( this ) ;
}
UDPServer : : ~ UDPServer ( ) {
ControllerPatcherThread * pThreadPointer = UDPServer : : pThread ;
if ( pThreadPointer ! = NULL ) {
exitThread = 1 ;
if ( pThreadPointer ! = NULL ) {
delete pThreadPointer ;
UDPServer : : pThread = NULL ;
if ( this - > sockfd ! = - 1 ) {
socketclose ( sockfd ) ;
}
this - > sockfd = - 1 ;
}
}
2017-05-06 19:46:05 +02:00
if ( HID_DEBUG ) { log_printf ( " UDPServer::~UDPServer(line %d): Thread has been closed \n " , __LINE__ ) ; }
2017-03-30 17:53:36 +02:00
}
void UDPServer : : StartUDPThread ( UDPServer * server ) {
2017-04-13 10:14:41 +02:00
s32 priority = 28 ;
if ( OSGetTitleID ( ) = = 0x00050000101c9300 | | //The Legend of Zelda Breath of the Wild JPN
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 ;
log_printf ( " UDPServer::StartUDPThread(line %d): This game needs higher thread priority. We set it to %d \n " , __LINE__ , priority ) ;
}
UDPServer : : pThread = ControllerPatcherThread : : create ( UDPServer : : DoUDPThread , ( void * ) server , ControllerPatcherThread : : eAttributeAffCore2 , priority ) ;
2017-03-30 17:53:36 +02:00
UDPServer : : pThread - > resumeThread ( ) ;
}
2017-04-10 11:00:55 +02:00
bool UDPServer : : cpyIncrementBufferOffset ( void * target , void * source , s32 * offset , s32 typesize , s32 maximum ) {
2017-03-30 17:53:36 +02:00
if ( ( ( int ) * offset + typesize ) > maximum ) {
2017-04-10 11:00:55 +02:00
log_printf ( " UDPServer::cpyIncrementBufferOffset(line %d): Transfer error. Excepted %04X bytes, but only got %04X \n " , __LINE__ , ( * offset + typesize ) , maximum ) ;
2017-03-30 17:53:36 +02:00
return false ;
}
memcpy ( target , ( void * ) ( ( u32 ) source + ( * offset ) ) , typesize ) ;
* offset + = typesize ;
return true ;
}
void UDPServer : : DoUDPThread ( ControllerPatcherThread * thread , void * arg ) {
UDPServer * args = ( UDPServer * ) arg ;
args - > DoUDPThreadInternal ( ) ;
}
void UDPServer : : DoUDPThreadInternal ( ) {
u8 buffer [ MAX_UDP_SIZE ] ;
2017-04-10 11:00:55 +02:00
s32 n ;
2017-03-30 17:53:36 +02:00
my_cb_user user ;
while ( 1 ) {
2017-04-10 11:00:55 +02:00
//s32 usingVar = exitThread;
2017-03-30 17:53:36 +02:00
if ( exitThread ) break ;
memset ( buffer , 0 , MAX_UDP_SIZE ) ;
n = recv ( sockfd , buffer , MAX_UDP_SIZE , 0 ) ;
if ( n < 0 ) {
2017-04-10 15:39:58 +02:00
s32 errno_ = wiiu_errno ;
2017-05-07 14:29:19 +02:00
os_usleep ( 2000 ) ;
2017-03-30 17:53:36 +02:00
if ( errno_ ! = 11 & & errno_ ! = 9 ) {
break ;
}
continue ;
}
2017-04-10 11:00:55 +02:00
s32 bufferoffset = 0 ;
2017-03-30 17:53:36 +02:00
u8 type ;
memcpy ( ( void * ) & type , buffer , sizeof ( type ) ) ;
bufferoffset + = sizeof ( type ) ;
switch ( buffer [ 0 ] ) {
2017-04-10 15:39:58 +02:00
case WIIU_CP_UDP_CONTROLLER_READ_DATA : {
if ( gUsedProtocolVersion > = WIIU_CP_TCP_HANDSHAKE_VERSION_1 ) {
u8 count_commands ;
memcpy ( ( void * ) & count_commands , buffer + bufferoffset , sizeof ( count_commands ) ) ;
bufferoffset + = sizeof ( count_commands ) ;
for ( s32 i = 0 ; i < count_commands ; i + + ) {
s32 handle ;
u16 deviceSlot ;
2017-04-10 17:15:26 +02:00
u32 hid ;
2017-04-10 15:39:58 +02:00
u8 padslot ;
u8 datasize ;
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 ;
u8 * databuffer = ( u8 * ) malloc ( datasize * sizeof ( u8 ) ) ;
if ( ! databuffer ) {
log_printf ( " UDPServer::DoUDPThreadInternal(line %d): Allocating memory failed \n " , __LINE__ ) ;
continue ;
}
if ( ! cpyIncrementBufferOffset ( ( void * ) databuffer , ( void * ) buffer , & bufferoffset , datasize , n ) ) continue ;
2017-04-13 10:14:41 +02:00
//log_printf("UDPServer::DoUDPThreadInternal(): Got handle: %d slot %04X hid %04X pad %02X datasize %02X\n",handle,deviceSlot,hid,padslot,datasize);
2017-04-10 15:39:58 +02:00
user . pad_slot = padslot ;
user . slotdata . deviceslot = deviceSlot ;
user . slotdata . hidmask = hid ;
if ( gNetworkController [ deviceSlot ] [ padslot ] [ 0 ] = = 0 ) {
log_printf ( " UDPServer::DoUDPThreadInternal(line %d): Ehm. Pad is not connected. STOP SENDING DATA ;) \n " , __LINE__ ) ;
} else {
ControllerPatcherHID : : externHIDReadCallback ( handle , databuffer , datasize , & user ) ;
}
if ( databuffer ) {
free ( databuffer ) ;
databuffer = NULL ;
}
2017-03-30 17:53:36 +02:00
}
2017-04-10 15:39:58 +02:00
break ;
2017-03-30 17:53:36 +02:00
}
break ;
}
default : {
break ;
}
}
}
2017-05-06 19:46:05 +02:00
if ( HID_DEBUG ) { log_printf ( " UDPServer::DoUDPThreadInternal(line %d): UDPServer Thread ended \n " , __LINE__ ) ; }
2017-03-30 17:53:36 +02:00
}