2012-04-21 21:13:50 +00:00
/* RetroArch - A frontend for libretro.
2014-01-01 00:50:59 +00:00
* Copyright ( C ) 2010 - 2014 - Hans - Kristian Arntzen
2011-02-13 15:40:24 +00:00
*
2012-04-21 21:13:50 +00:00
* RetroArch is free software : you can redistribute it and / or modify it under the terms
2011-02-13 15:40:24 +00:00
* of the GNU General Public License as published by the Free Software Found -
* ation , either version 3 of the License , or ( at your option ) any later version .
*
2012-04-21 21:13:50 +00:00
* RetroArch is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ;
2011-02-13 15:40:24 +00:00
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE . See the GNU General Public License for more details .
*
2012-04-21 21:31:57 +00:00
* You should have received a copy of the GNU General Public License along with RetroArch .
2011-02-13 15:40:24 +00:00
* If not , see < http : //www.gnu.org/licenses/>.
*/
2011-12-04 17:03:08 +00:00
2012-11-15 13:32:06 +00:00
# if defined(_MSC_VER) && !defined(_XBOX)
2012-11-15 08:40:31 +00:00
# pragma comment(lib, "ws2_32")
2012-11-14 20:01:40 +00:00
# endif
2012-05-27 12:12:29 +00:00
# include "netplay_compat.h"
2011-10-18 17:22:20 +00:00
# include "netplay.h"
# include "general.h"
# include "autosave.h"
# include "dynamic.h"
2013-11-06 14:08:54 +00:00
# include "message_queue.h"
2011-10-18 17:22:20 +00:00
# include <stdlib.h>
# include <string.h>
2012-01-11 18:22:18 +00:00
// Checks if input port/index is controlled by netplay or not.
static bool netplay_is_alive ( netplay_t * handle ) ;
static bool netplay_poll ( netplay_t * handle ) ;
static int16_t netplay_input_state ( netplay_t * handle , bool port , unsigned device , unsigned index , unsigned id ) ;
// If we're fast-forward replaying to resync, check if we should actually show frame.
static bool netplay_should_skip ( netplay_t * handle ) ;
static bool netplay_can_poll ( netplay_t * handle ) ;
static void netplay_set_spectate_input ( netplay_t * handle , int16_t input ) ;
2012-01-21 13:00:11 +00:00
static bool netplay_send_cmd ( netplay_t * handle , uint32_t cmd , const void * data , size_t size ) ;
static bool netplay_get_cmd ( netplay_t * handle ) ;
2011-02-14 15:10:53 +00:00
# define PREV_PTR(x) ((x) == 0 ? handle->buffer_size - 1 : (x) - 1)
# define NEXT_PTR(x) ((x + 1) % handle->buffer_size)
struct delta_frame
{
2012-04-07 09:55:37 +00:00
void * state ;
2011-02-14 15:10:53 +00:00
uint16_t real_input_state ;
uint16_t simulated_input_state ;
uint16_t self_state ;
2013-11-04 04:57:41 +00:00
bool is_simulated ;
2011-02-14 19:11:46 +00:00
bool used_real ;
2011-02-14 15:10:53 +00:00
} ;
2011-11-06 19:28:02 +00:00
# define UDP_FRAME_PACKETS 16
2012-01-11 18:22:18 +00:00
# define MAX_SPECTATORS 16
2011-02-18 01:01:47 +00:00
2012-01-21 13:00:11 +00:00
# define NETPLAY_CMD_ACK 0
# define NETPLAY_CMD_NAK 1
# define NETPLAY_CMD_FLIP_PLAYERS 2
2011-02-13 15:40:24 +00:00
struct netplay
{
2012-01-21 17:12:42 +00:00
char nick [ 32 ] ;
char other_nick [ 32 ] ;
struct sockaddr_storage other_addr ;
2012-04-07 09:55:37 +00:00
struct retro_callbacks cbs ;
2012-01-21 13:00:11 +00:00
int fd ; // TCP connection for state sending, etc. Also used for commands.
2011-02-18 01:01:47 +00:00
int udp_fd ; // UDP connection for game state updates.
2012-01-21 13:00:11 +00:00
unsigned port ; // Which port is governed by netplay (other player)?
2011-02-13 15:40:24 +00:00
bool has_connection ;
2011-02-14 15:10:53 +00:00
struct delta_frame * buffer ;
size_t buffer_size ;
size_t self_ptr ; // Ptr where we are now.
size_t other_ptr ; // Points to the last reliable state that self ever had.
size_t read_ptr ; // Ptr to where we are reading. Generally, other_ptr <= read_ptr <= self_ptr.
size_t tmp_ptr ; // A temporary pointer used on replay.
size_t state_size ;
2012-01-21 13:00:11 +00:00
bool is_replay ; // Are we replaying old frames?
2011-02-18 01:01:47 +00:00
bool can_poll ; // We don't want to poll several times on a frame.
uint32_t packet_buffer [ UDP_FRAME_PACKETS * 2 ] ; // To compat UDP packet loss we also send old data along with the packets.
uint32_t frame_count ;
uint32_t read_frame_count ;
2011-10-05 00:09:54 +00:00
uint32_t other_frame_count ;
2012-01-21 15:14:10 +00:00
uint32_t tmp_frame_count ;
2011-02-18 01:01:47 +00:00
struct addrinfo * addr ;
struct sockaddr_storage their_addr ;
bool has_client_addr ;
2011-11-06 19:28:02 +00:00
unsigned timeout_cnt ;
2012-01-11 18:22:18 +00:00
// Spectating.
bool spectate ;
bool spectate_client ;
int spectate_fds [ MAX_SPECTATORS ] ;
uint16_t * spectate_input ;
size_t spectate_input_ptr ;
size_t spectate_input_size ;
2012-01-21 13:00:11 +00:00
// Player flipping
// Flipping state. If ptr >= flip_frame, we apply the flip.
// If not, we apply the opposite, effectively creating a trigger point.
// To avoid collition we need to make sure our client/host is synced up well after flip_frame
// before allowing another flip.
bool flip ;
uint32_t flip_frame ;
2011-02-13 15:40:24 +00:00
} ;
2012-01-21 13:00:11 +00:00
static bool send_all ( int fd , const void * data_ , size_t size )
{
const uint8_t * data = ( const uint8_t * ) data_ ;
while ( size )
{
ssize_t ret = send ( fd , CONST_CAST data , size , 0 ) ;
if ( ret < = 0 )
return false ;
data + = ret ;
size - = ret ;
}
return true ;
}
static bool recv_all ( int fd , void * data_ , size_t size )
{
uint8_t * data = ( uint8_t * ) data_ ;
while ( size )
{
ssize_t ret = recv ( fd , NONCONST_CAST data , size , 0 ) ;
if ( ret < = 0 )
return false ;
data + = ret ;
size - = ret ;
}
return true ;
}
2011-10-05 19:44:17 +00:00
static void warn_hangup ( void )
{
2012-04-21 21:25:32 +00:00
RARCH_WARN ( " Netplay has disconnected. Will continue without connection ... \n " ) ;
2011-10-05 19:44:17 +00:00
if ( g_extern . msg_queue )
msg_queue_push ( g_extern . msg_queue , " Netplay has disconnected. Will continue without connection. " , 0 , 480 ) ;
}
2011-02-13 15:40:24 +00:00
void input_poll_net ( void )
{
2011-02-14 19:11:46 +00:00
if ( ! netplay_should_skip ( g_extern . netplay ) & & netplay_can_poll ( g_extern . netplay ) )
2011-02-14 15:10:53 +00:00
netplay_poll ( g_extern . netplay ) ;
2011-02-13 15:40:24 +00:00
}
2012-04-07 09:55:37 +00:00
void video_frame_net ( const void * data , unsigned width , unsigned height , size_t pitch )
2011-02-13 15:40:24 +00:00
{
2011-02-14 15:10:53 +00:00
if ( ! netplay_should_skip ( g_extern . netplay ) )
2012-04-07 09:55:37 +00:00
g_extern . netplay - > cbs . frame_cb ( data , width , height , pitch ) ;
2011-02-13 15:40:24 +00:00
}
2012-04-07 09:55:37 +00:00
void audio_sample_net ( int16_t left , int16_t right )
2011-02-13 15:40:24 +00:00
{
2011-02-14 15:10:53 +00:00
if ( ! netplay_should_skip ( g_extern . netplay ) )
2012-04-07 09:55:37 +00:00
g_extern . netplay - > cbs . sample_cb ( left , right ) ;
2011-02-13 15:40:24 +00:00
}
2012-04-07 09:55:37 +00:00
size_t audio_sample_batch_net ( const int16_t * data , size_t frames )
{
if ( ! netplay_should_skip ( g_extern . netplay ) )
return g_extern . netplay - > cbs . sample_batch_cb ( data , frames ) ;
else
return frames ;
}
int16_t input_state_net ( unsigned port , unsigned device , unsigned index , unsigned id )
2011-02-13 15:40:24 +00:00
{
2011-02-14 15:10:53 +00:00
if ( netplay_is_alive ( g_extern . netplay ) )
2011-02-13 15:40:24 +00:00
return netplay_input_state ( g_extern . netplay , port , device , index , id ) ;
else
2012-04-07 09:55:37 +00:00
return g_extern . netplay - > cbs . state_cb ( port , device , index , id ) ;
2011-02-13 15:40:24 +00:00
}
2012-01-24 22:14:11 +00:00
# ifndef HAVE_SOCKET_LEGACY
2012-01-21 13:58:39 +00:00
// Custom inet_ntop. Win32 doesn't seem to support this ...
2012-01-21 17:12:42 +00:00
static void log_connection ( const struct sockaddr_storage * their_addr ,
unsigned slot , const char * nick )
2012-01-11 19:50:21 +00:00
{
union
{
const struct sockaddr_storage * storage ;
const struct sockaddr_in * v4 ;
const struct sockaddr_in6 * v6 ;
} u ;
u . storage = their_addr ;
const char * str = NULL ;
2012-01-21 13:58:39 +00:00
char buf_v4 [ INET_ADDRSTRLEN ] = { 0 } ;
char buf_v6 [ INET6_ADDRSTRLEN ] = { 0 } ;
2012-01-11 19:50:21 +00:00
if ( their_addr - > ss_family = = AF_INET )
{
2012-01-21 13:58:39 +00:00
str = buf_v4 ;
2012-01-11 19:50:21 +00:00
struct sockaddr_in in ;
memset ( & in , 0 , sizeof ( in ) ) ;
in . sin_family = AF_INET ;
memcpy ( & in . sin_addr , & u . v4 - > sin_addr , sizeof ( struct in_addr ) ) ;
2012-01-21 13:58:39 +00:00
getnameinfo ( ( struct sockaddr * ) & in , sizeof ( struct sockaddr_in ) , buf_v4 , sizeof ( buf_v4 ) ,
2012-01-11 19:50:21 +00:00
NULL , 0 , NI_NUMERICHOST ) ;
}
else if ( their_addr - > ss_family = = AF_INET6 )
{
2012-01-21 13:58:39 +00:00
str = buf_v6 ;
2012-01-11 19:50:21 +00:00
struct sockaddr_in6 in ;
memset ( & in , 0 , sizeof ( in ) ) ;
in . sin6_family = AF_INET6 ;
memcpy ( & in . sin6_addr , & u . v6 - > sin6_addr , sizeof ( struct in6_addr ) ) ;
getnameinfo ( ( struct sockaddr * ) & in , sizeof ( struct sockaddr_in6 ) ,
2012-01-21 13:58:39 +00:00
buf_v6 , sizeof ( buf_v6 ) , NULL , 0 , NI_NUMERICHOST ) ;
2012-01-11 19:50:21 +00:00
}
if ( str )
{
char msg [ 512 ] ;
2012-01-21 17:12:42 +00:00
snprintf ( msg , sizeof ( msg ) , " Got connection from: \" %s (%s) \" (#%u) " , nick , str , slot ) ;
2012-01-11 19:50:21 +00:00
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
2012-01-11 19:50:21 +00:00
}
}
2012-01-24 22:14:11 +00:00
# endif
2012-01-11 19:50:21 +00:00
2012-05-31 18:34:33 +00:00
static int init_tcp_connection ( const struct addrinfo * res , bool server , bool spectate ,
struct sockaddr * other_addr , socklen_t addr_size )
{
bool ret = true ;
int fd = socket ( res - > ai_family , res - > ai_socktype , res - > ai_protocol ) ;
if ( fd < 0 )
{
ret = false ;
goto end ;
}
if ( server )
{
if ( connect ( fd , res - > ai_addr , res - > ai_addrlen ) < 0 )
{
ret = false ;
goto end ;
}
}
else if ( spectate )
{
int yes = 1 ;
setsockopt ( fd , SOL_SOCKET , SO_REUSEADDR , CONST_CAST & yes , sizeof ( int ) ) ;
if ( bind ( fd , res - > ai_addr , res - > ai_addrlen ) < 0 | |
listen ( fd , MAX_SPECTATORS ) < 0 )
{
ret = false ;
goto end ;
}
}
else
{
int yes = 1 ;
setsockopt ( fd , SOL_SOCKET , SO_REUSEADDR , CONST_CAST & yes , sizeof ( int ) ) ;
if ( bind ( fd , res - > ai_addr , res - > ai_addrlen ) < 0 | |
listen ( fd , 1 ) < 0 )
{
ret = false ;
goto end ;
}
int new_fd = accept ( fd , other_addr , & addr_size ) ;
if ( new_fd < 0 )
{
ret = false ;
goto end ;
}
close ( fd ) ;
fd = new_fd ;
}
end :
if ( ! ret & & fd > = 0 )
{
close ( fd ) ;
fd = - 1 ;
}
return fd ;
}
2012-01-11 18:22:18 +00:00
static bool init_tcp_socket ( netplay_t * handle , const char * server , uint16_t port , bool spectate )
2011-02-13 15:40:24 +00:00
{
struct addrinfo hints , * res = NULL ;
memset ( & hints , 0 , sizeof ( hints ) ) ;
2012-05-31 18:34:33 +00:00
2012-01-24 20:00:30 +00:00
# if defined(_WIN32) || defined(HAVE_SOCKET_LEGACY)
2011-02-13 15:40:24 +00:00
hints . ai_family = AF_INET ;
# else
hints . ai_family = AF_UNSPEC ;
# endif
2012-05-31 18:34:33 +00:00
2011-02-13 15:40:24 +00:00
hints . ai_socktype = SOCK_STREAM ;
if ( ! server )
hints . ai_flags = AI_PASSIVE ;
2012-05-31 18:34:33 +00:00
bool ret = false ;
2011-02-13 15:40:24 +00:00
char port_buf [ 16 ] ;
snprintf ( port_buf , sizeof ( port_buf ) , " %hu " , ( unsigned short ) port ) ;
if ( getaddrinfo ( server , port_buf , & hints , & res ) < 0 )
return false ;
2011-02-15 16:29:03 +00:00
if ( ! res )
return false ;
2012-05-31 18:34:33 +00:00
// If "localhost" is used, it is important to check every possible address for ipv4/ipv6.
const struct addrinfo * tmp_info = res ;
while ( tmp_info )
2011-02-13 15:40:24 +00:00
{
2012-05-31 18:34:33 +00:00
int fd ;
if ( ( fd = init_tcp_connection ( tmp_info , server , handle - > spectate ,
( struct sockaddr * ) & handle - > other_addr , sizeof ( handle - > other_addr ) ) ) > = 0 )
2011-02-13 15:40:24 +00:00
{
2012-05-31 18:34:33 +00:00
ret = true ;
handle - > fd = fd ;
break ;
2011-02-13 15:40:24 +00:00
}
2012-01-11 18:22:18 +00:00
2012-05-31 18:34:33 +00:00
tmp_info = tmp_info - > ai_next ;
2012-01-11 18:22:18 +00:00
}
2011-02-13 19:24:54 +00:00
2012-05-31 18:34:33 +00:00
if ( res )
freeaddrinfo ( res ) ;
2012-01-11 19:50:21 +00:00
2012-05-31 18:34:33 +00:00
if ( ! ret )
RARCH_ERR ( " Failed to set up netplay sockets. \n " ) ;
2011-02-13 15:40:24 +00:00
2012-05-31 18:34:33 +00:00
return ret ;
2011-02-18 01:01:47 +00:00
}
static bool init_udp_socket ( netplay_t * handle , const char * server , uint16_t port )
{
struct addrinfo hints ;
memset ( & hints , 0 , sizeof ( hints ) ) ;
2012-01-24 20:00:30 +00:00
# if defined(_WIN32) || defined(HAVE_SOCKET_LEGACY)
2011-02-18 01:01:47 +00:00
hints . ai_family = AF_INET ;
# else
hints . ai_family = AF_UNSPEC ;
# endif
hints . ai_socktype = SOCK_DGRAM ;
if ( ! server )
hints . ai_flags = AI_PASSIVE ;
char port_buf [ 16 ] ;
snprintf ( port_buf , sizeof ( port_buf ) , " %hu " , ( unsigned short ) port ) ;
if ( getaddrinfo ( server , port_buf , & hints , & handle - > addr ) < 0 )
return false ;
if ( ! handle - > addr )
return false ;
handle - > udp_fd = socket ( handle - > addr - > ai_family , handle - > addr - > ai_socktype , handle - > addr - > ai_protocol ) ;
if ( handle - > udp_fd < 0 )
{
2014-05-30 16:22:49 +00:00
RARCH_ERR ( " Failed to initialize socket. \n " ) ;
2011-02-18 01:01:47 +00:00
return false ;
}
if ( ! server )
{
// Note sure if we have to do this for UDP, but hey :)
int yes = 1 ;
setsockopt ( handle - > udp_fd , SOL_SOCKET , SO_REUSEADDR , CONST_CAST & yes , sizeof ( int ) ) ;
if ( bind ( handle - > udp_fd , handle - > addr - > ai_addr , handle - > addr - > ai_addrlen ) < 0 )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to bind socket. \n " ) ;
2011-02-18 01:01:47 +00:00
close ( handle - > udp_fd ) ;
2012-01-12 08:21:33 +00:00
handle - > udp_fd = - 1 ;
2011-02-18 01:01:47 +00:00
}
freeaddrinfo ( handle - > addr ) ;
handle - > addr = NULL ;
}
2011-02-13 15:40:24 +00:00
return true ;
}
2012-01-24 20:00:30 +00:00
// Platform specific socket library init.
2012-06-01 13:20:53 +00:00
bool netplay_init_network ( void )
2011-02-18 01:01:47 +00:00
{
2012-01-24 20:00:30 +00:00
static bool inited = false ;
if ( inited )
return true ;
2012-01-24 21:38:25 +00:00
# if defined(_WIN32)
2011-02-18 01:01:47 +00:00
WSADATA wsaData ;
2011-06-26 13:32:24 +00:00
if ( WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsaData ) ! = 0 )
2011-02-18 01:01:47 +00:00
{
WSACleanup ( ) ;
return false ;
}
2012-09-16 03:22:44 +00:00
# elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
2012-01-24 21:38:25 +00:00
cellSysmoduleLoadModule ( CELL_SYSMODULE_NET ) ;
sys_net_initialize_network ( ) ;
2011-02-18 01:01:47 +00:00
# else
signal ( SIGPIPE , SIG_IGN ) ; // Do not like SIGPIPE killing our app :(
# endif
2012-01-24 20:00:30 +00:00
inited = true ;
return true ;
}
static bool init_socket ( netplay_t * handle , const char * server , uint16_t port )
{
2012-06-01 13:20:53 +00:00
if ( ! netplay_init_network ( ) )
2012-01-24 20:00:30 +00:00
return false ;
2012-01-11 18:22:18 +00:00
if ( ! init_tcp_socket ( handle , server , port , handle - > spectate ) )
2011-02-18 01:01:47 +00:00
return false ;
2012-01-24 20:00:30 +00:00
if ( ! handle - > spectate & & ! init_udp_socket ( handle , server , port ) )
return false ;
2011-02-18 01:01:47 +00:00
return true ;
}
2011-02-14 19:11:46 +00:00
bool netplay_can_poll ( netplay_t * handle )
{
return handle - > can_poll ;
}
2011-10-07 20:33:38 +00:00
// Not really a hash, but should be enough to differentiate implementations from each other.
// Subtle differences in the implementation will not be possible to spot.
// The alternative would have been checking serialization sizes, but it was troublesome for cross platform compat.
static uint32_t implementation_magic_value ( void )
{
2013-10-22 19:26:33 +00:00
size_t i ;
2011-10-07 20:33:38 +00:00
uint32_t res = 0 ;
2012-04-07 09:55:37 +00:00
unsigned api = pretro_api_version ( ) ;
2012-01-21 17:12:42 +00:00
2012-04-07 09:55:37 +00:00
res | = api ;
2011-10-07 20:33:38 +00:00
2012-04-07 09:55:37 +00:00
const char * lib = g_extern . system . info . library_name ;
2011-10-07 20:33:38 +00:00
size_t len = strlen ( lib ) ;
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < len ; i + + )
2011-10-07 20:33:38 +00:00
res ^ = lib [ i ] < < ( i & 0xf ) ;
2012-04-07 09:55:37 +00:00
lib = g_extern . system . info . library_version ;
len = strlen ( lib ) ;
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < len ; i + + )
2012-04-07 09:55:37 +00:00
res ^ = lib [ i ] < < ( i & 0xf ) ;
2012-01-21 17:12:42 +00:00
const char * ver = PACKAGE_VERSION ;
len = strlen ( ver ) ;
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < len ; i + + )
2012-01-21 17:12:42 +00:00
res ^ = ver [ i ] < < ( ( i & 0xf ) + 16 ) ;
2011-10-07 20:33:38 +00:00
return res ;
}
2012-01-21 17:34:07 +00:00
static bool send_nickname ( netplay_t * handle , int fd )
2012-01-21 17:12:42 +00:00
{
uint8_t nick_size = strlen ( handle - > nick ) ;
2012-01-21 17:34:07 +00:00
if ( ! send_all ( fd , & nick_size , sizeof ( nick_size ) ) )
2012-01-21 17:12:42 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to send nick size. \n " ) ;
2012-01-21 17:12:42 +00:00
return false ;
}
2012-01-21 17:34:07 +00:00
if ( ! send_all ( fd , handle - > nick , nick_size ) )
2012-01-21 17:12:42 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to send nick. \n " ) ;
2012-01-21 17:12:42 +00:00
return false ;
}
return true ;
}
2012-01-21 17:34:07 +00:00
static bool get_nickname ( netplay_t * handle , int fd )
2012-01-21 17:12:42 +00:00
{
uint8_t nick_size ;
2012-01-21 17:34:07 +00:00
if ( ! recv_all ( fd , & nick_size , sizeof ( nick_size ) ) )
2012-01-21 17:12:42 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to receive nick size from host. \n " ) ;
2012-01-21 17:12:42 +00:00
return false ;
}
if ( nick_size > = sizeof ( handle - > other_nick ) )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Invalid nick size. \n " ) ;
2012-01-21 17:12:42 +00:00
return false ;
}
2012-01-21 17:34:07 +00:00
if ( ! recv_all ( fd , handle - > other_nick , nick_size ) )
2012-01-21 17:12:42 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to receive nick. \n " ) ;
2012-01-21 17:12:42 +00:00
return false ;
}
return true ;
}
2011-02-13 15:40:24 +00:00
static bool send_info ( netplay_t * handle )
{
2012-01-21 17:12:42 +00:00
uint32_t header [ 3 ] = {
htonl ( g_extern . cart_crc ) ,
htonl ( implementation_magic_value ( ) ) ,
2012-04-07 09:55:37 +00:00
htonl ( pretro_get_memory_size ( RETRO_MEMORY_SAVE_RAM ) )
2012-01-21 17:12:42 +00:00
} ;
2012-01-21 13:00:11 +00:00
if ( ! send_all ( handle - > fd , header , sizeof ( header ) ) )
2011-02-13 15:40:24 +00:00
return false ;
2011-02-13 16:45:14 +00:00
2012-01-21 17:34:07 +00:00
if ( ! send_nickname ( handle , handle - > fd ) )
2012-01-21 17:12:42 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to send nick to host. \n " ) ;
2012-01-21 17:12:42 +00:00
return false ;
}
2012-04-07 09:55:37 +00:00
// Get SRAM data from Player 1.
void * sram = pretro_get_memory_data ( RETRO_MEMORY_SAVE_RAM ) ;
unsigned sram_size = pretro_get_memory_size ( RETRO_MEMORY_SAVE_RAM ) ;
2012-01-21 13:00:11 +00:00
if ( ! recv_all ( handle - > fd , sram , sram_size ) )
2011-02-13 16:45:14 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to receive SRAM data from host. \n " ) ;
2012-01-21 13:00:11 +00:00
return false ;
2011-02-13 16:45:14 +00:00
}
2012-01-21 17:34:07 +00:00
if ( ! get_nickname ( handle , handle - > fd ) )
2012-01-21 17:12:42 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to receive nick from host. \n " ) ;
2012-01-21 17:12:42 +00:00
return false ;
}
char msg [ 512 ] ;
snprintf ( msg , sizeof ( msg ) , " Connected to: \" %s \" " , handle - > other_nick ) ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
2012-01-21 17:12:42 +00:00
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2011-02-13 15:40:24 +00:00
return true ;
}
static bool get_info ( netplay_t * handle )
{
2011-02-13 16:45:14 +00:00
uint32_t header [ 3 ] ;
2012-01-21 17:12:42 +00:00
2012-01-21 13:00:11 +00:00
if ( ! recv_all ( handle - > fd , header , sizeof ( header ) ) )
2011-02-13 19:24:54 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to receive header from client. \n " ) ;
2011-02-13 15:40:24 +00:00
return false ;
2011-02-13 19:24:54 +00:00
}
2012-01-21 17:12:42 +00:00
2011-02-13 15:40:24 +00:00
if ( g_extern . cart_crc ! = ntohl ( header [ 0 ] ) )
2011-02-13 19:24:54 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Cart CRC32s differ. Cannot use different games. \n " ) ;
2011-02-13 15:40:24 +00:00
return false ;
2011-02-13 19:24:54 +00:00
}
2012-01-21 17:12:42 +00:00
2011-10-31 21:51:54 +00:00
if ( implementation_magic_value ( ) ! = ntohl ( header [ 1 ] ) )
2011-02-13 19:24:54 +00:00
{
2012-07-07 15:08:55 +00:00
RARCH_ERR ( " Implementations differ, make sure you're using exact same libretro implementations and RetroArch version. \n " ) ;
2011-02-13 15:40:24 +00:00
return false ;
2011-02-13 19:24:54 +00:00
}
2012-01-21 17:12:42 +00:00
2012-04-07 09:55:37 +00:00
if ( pretro_get_memory_size ( RETRO_MEMORY_SAVE_RAM ) ! = ntohl ( header [ 2 ] ) )
2011-02-13 19:24:54 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Cartridge SRAM sizes do not correspond. \n " ) ;
2011-02-13 16:45:14 +00:00
return false ;
2011-02-13 19:24:54 +00:00
}
2011-02-13 16:45:14 +00:00
2012-01-21 17:34:07 +00:00
if ( ! get_nickname ( handle , handle - > fd ) )
2012-01-21 17:12:42 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to get nickname from client. \n " ) ;
2012-01-21 17:12:42 +00:00
return false ;
}
2012-04-07 09:55:37 +00:00
// Send SRAM data to our Player 2.
const void * sram = pretro_get_memory_data ( RETRO_MEMORY_SAVE_RAM ) ;
unsigned sram_size = pretro_get_memory_size ( RETRO_MEMORY_SAVE_RAM ) ;
2012-01-21 13:00:11 +00:00
if ( ! send_all ( handle - > fd , sram , sram_size ) )
2011-02-13 16:45:14 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to send SRAM data to client. \n " ) ;
2012-01-21 13:00:11 +00:00
return false ;
2011-02-13 16:45:14 +00:00
}
2012-01-21 17:34:07 +00:00
if ( ! send_nickname ( handle , handle - > fd ) )
2012-01-21 17:12:42 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to send nickname to client. \n " ) ;
2012-01-21 17:12:42 +00:00
return false ;
}
2012-01-24 22:14:11 +00:00
# ifndef HAVE_SOCKET_LEGACY
2012-01-21 17:12:42 +00:00
log_connection ( & handle - > other_addr , 0 , handle - > other_nick ) ;
2012-01-24 22:14:11 +00:00
# endif
2012-01-21 17:12:42 +00:00
2011-02-13 15:40:24 +00:00
return true ;
}
2012-03-25 21:48:27 +00:00
static uint32_t * bsv_header_generate ( size_t * size , uint32_t magic )
{
uint32_t bsv_header [ 4 ] = { 0 } ;
2012-04-07 09:55:37 +00:00
size_t serialize_size = pretro_serialize_size ( ) ;
2012-03-25 21:48:27 +00:00
size_t header_size = sizeof ( bsv_header ) + serialize_size ;
* size = header_size ;
uint32_t * header = ( uint32_t * ) malloc ( header_size ) ;
if ( ! header )
return NULL ;
bsv_header [ MAGIC_INDEX ] = swap_if_little32 ( BSV_MAGIC ) ;
bsv_header [ SERIALIZER_INDEX ] = swap_if_big32 ( magic ) ;
bsv_header [ CRC_INDEX ] = swap_if_big32 ( g_extern . cart_crc ) ;
bsv_header [ STATE_SIZE_INDEX ] = swap_if_big32 ( serialize_size ) ;
2012-05-04 17:56:48 +00:00
if ( serialize_size & & ! pretro_serialize ( header + 4 , serialize_size ) )
2012-03-25 21:48:27 +00:00
{
free ( header ) ;
return NULL ;
}
memcpy ( header , bsv_header , sizeof ( bsv_header ) ) ;
return header ;
}
static bool bsv_parse_header ( const uint32_t * header , uint32_t magic )
{
uint32_t in_bsv = swap_if_little32 ( header [ MAGIC_INDEX ] ) ;
if ( in_bsv ! = BSV_MAGIC )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " BSV magic mismatch, got 0x%x, expected 0x%x. \n " ,
2012-03-25 21:48:27 +00:00
in_bsv , BSV_MAGIC ) ;
return false ;
}
uint32_t in_magic = swap_if_big32 ( header [ SERIALIZER_INDEX ] ) ;
if ( in_magic ! = magic )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Magic mismatch, got 0x%x, expected 0x%x. \n " , in_magic , magic ) ;
2012-03-25 21:48:27 +00:00
return false ;
}
uint32_t in_crc = swap_if_big32 ( header [ CRC_INDEX ] ) ;
if ( in_crc ! = g_extern . cart_crc )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " CRC32 mismatch, got 0x%x, expected 0x%x. \n " , in_crc , g_extern . cart_crc ) ;
2012-03-25 21:48:27 +00:00
return false ;
}
uint32_t in_state_size = swap_if_big32 ( header [ STATE_SIZE_INDEX ] ) ;
2012-04-07 09:55:37 +00:00
if ( in_state_size ! = pretro_serialize_size ( ) )
2012-03-25 21:48:27 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Serialization size mismatch, got 0x%x, expected 0x%x. \n " ,
2012-04-07 09:55:37 +00:00
( unsigned ) in_state_size , ( unsigned ) pretro_serialize_size ( ) ) ;
2012-03-25 21:48:27 +00:00
return false ;
}
return true ;
}
2012-01-11 18:22:18 +00:00
static bool get_info_spectate ( netplay_t * handle )
{
2012-01-21 17:34:07 +00:00
if ( ! send_nickname ( handle , handle - > fd ) )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to send nickname to host. \n " ) ;
2012-01-21 17:34:07 +00:00
return false ;
}
if ( ! get_nickname ( handle , handle - > fd ) )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to receive nickname from host. \n " ) ;
2012-01-21 17:34:07 +00:00
return false ;
}
char msg [ 512 ] ;
snprintf ( msg , sizeof ( msg ) , " Connected to \" %s \" " , handle - > other_nick ) ;
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " %s \n " , msg ) ;
2012-01-21 17:34:07 +00:00
2012-01-11 18:22:18 +00:00
uint32_t header [ 4 ] ;
2012-01-21 17:12:42 +00:00
if ( ! recv_all ( handle - > fd , header , sizeof ( header ) ) )
2012-01-11 18:22:18 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Cannot get header from host. \n " ) ;
2012-01-11 18:22:18 +00:00
return false ;
}
2012-04-07 09:55:37 +00:00
size_t save_state_size = pretro_serialize_size ( ) ;
2012-01-21 17:12:42 +00:00
if ( ! bsv_parse_header ( header , implementation_magic_value ( ) ) )
2012-01-11 18:22:18 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Received invalid BSV header from host. \n " ) ;
2012-01-11 18:22:18 +00:00
return false ;
}
2012-04-07 09:55:37 +00:00
void * buf = malloc ( save_state_size ) ;
2012-01-11 18:22:18 +00:00
if ( ! buf )
return false ;
size_t size = save_state_size ;
2012-04-07 09:55:37 +00:00
if ( ! recv_all ( handle - > fd , buf , size ) )
2012-01-21 13:00:11 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to receive save state from host. \n " ) ;
2012-04-07 09:55:37 +00:00
free ( buf ) ;
2012-01-21 13:00:11 +00:00
return false ;
2012-01-11 18:22:18 +00:00
}
bool ret = true ;
if ( save_state_size )
2012-04-07 09:55:37 +00:00
ret = pretro_unserialize ( buf , save_state_size ) ;
2012-01-11 18:22:18 +00:00
free ( buf ) ;
return ret ;
}
2011-02-14 15:10:53 +00:00
static void init_buffers ( netplay_t * handle )
{
2013-10-22 19:26:33 +00:00
unsigned i ;
2011-12-24 12:46:12 +00:00
handle - > buffer = ( struct delta_frame * ) calloc ( handle - > buffer_size , sizeof ( * handle - > buffer ) ) ;
2012-04-07 09:55:37 +00:00
handle - > state_size = pretro_serialize_size ( ) ;
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < handle - > buffer_size ; i + + )
2011-02-18 01:01:47 +00:00
{
2012-04-07 09:55:37 +00:00
handle - > buffer [ i ] . state = malloc ( handle - > state_size ) ;
2011-02-18 01:01:47 +00:00
handle - > buffer [ i ] . is_simulated = true ;
}
2011-02-14 15:10:53 +00:00
}
2012-01-21 17:12:42 +00:00
netplay_t * netplay_new ( const char * server , uint16_t port ,
2012-04-07 09:55:37 +00:00
unsigned frames , const struct retro_callbacks * cb ,
2012-01-21 17:12:42 +00:00
bool spectate ,
const char * nick )
2011-02-13 15:40:24 +00:00
{
2013-10-22 19:26:33 +00:00
unsigned i ;
2011-11-06 19:38:42 +00:00
if ( frames > UDP_FRAME_PACKETS )
frames = UDP_FRAME_PACKETS ;
2011-12-24 12:46:12 +00:00
netplay_t * handle = ( netplay_t * ) calloc ( 1 , sizeof ( * handle ) ) ;
2011-02-13 15:40:24 +00:00
if ( ! handle )
return NULL ;
2012-01-11 18:22:18 +00:00
handle - > fd = - 1 ;
handle - > udp_fd = - 1 ;
2011-02-13 15:40:24 +00:00
handle - > cbs = * cb ;
handle - > port = server ? 0 : 1 ;
2012-01-11 18:22:18 +00:00
handle - > spectate = spectate ;
handle - > spectate_client = server ! = NULL ;
2012-01-21 17:12:42 +00:00
strlcpy ( handle - > nick , nick , sizeof ( handle - > nick ) ) ;
2011-02-13 15:40:24 +00:00
if ( ! init_socket ( handle , server , port ) )
{
free ( handle ) ;
return NULL ;
}
2012-01-11 18:22:18 +00:00
if ( spectate )
2011-02-13 15:40:24 +00:00
{
2012-01-11 18:22:18 +00:00
if ( server )
2011-02-13 15:40:24 +00:00
{
2012-01-11 18:22:18 +00:00
if ( ! get_info_spectate ( handle ) )
goto error ;
2011-02-13 15:40:24 +00:00
}
2012-01-11 18:22:18 +00:00
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < MAX_SPECTATORS ; i + + )
2012-01-11 18:22:18 +00:00
handle - > spectate_fds [ i ] = - 1 ;
2011-02-13 15:40:24 +00:00
}
else
{
2012-01-11 18:22:18 +00:00
if ( server )
2011-02-13 15:40:24 +00:00
{
2012-01-11 18:22:18 +00:00
if ( ! send_info ( handle ) )
goto error ;
}
else
{
if ( ! get_info ( handle ) )
goto error ;
2011-02-13 15:40:24 +00:00
}
2012-01-11 18:22:18 +00:00
handle - > buffer_size = frames + 1 ;
2011-02-18 01:01:47 +00:00
2012-01-11 18:22:18 +00:00
init_buffers ( handle ) ;
handle - > has_connection = true ;
}
2011-02-18 01:01:47 +00:00
2011-02-13 15:40:24 +00:00
return handle ;
2012-01-11 18:22:18 +00:00
error :
if ( handle - > fd > = 0 )
close ( handle - > fd ) ;
if ( handle - > udp_fd > = 0 )
close ( handle - > udp_fd ) ;
free ( handle ) ;
return NULL ;
2011-02-13 15:40:24 +00:00
}
2011-02-14 15:10:53 +00:00
2012-01-11 18:22:18 +00:00
static bool netplay_is_alive ( netplay_t * handle )
2011-02-13 15:40:24 +00:00
{
2011-02-14 15:10:53 +00:00
return handle - > has_connection ;
}
2011-02-18 22:51:51 +00:00
static bool send_chunk ( netplay_t * handle )
{
const struct sockaddr * addr = NULL ;
if ( handle - > addr )
addr = handle - > addr - > ai_addr ;
else if ( handle - > has_client_addr )
addr = ( const struct sockaddr * ) & handle - > their_addr ;
if ( addr )
{
2012-01-11 20:08:44 +00:00
if ( sendto ( handle - > udp_fd , CONST_CAST handle - > packet_buffer ,
sizeof ( handle - > packet_buffer ) , 0 , addr ,
sizeof ( struct sockaddr ) ) ! = sizeof ( handle - > packet_buffer ) )
2011-02-18 22:51:51 +00:00
{
2011-10-05 19:44:17 +00:00
warn_hangup ( ) ;
2011-02-18 22:51:51 +00:00
handle - > has_connection = false ;
return false ;
}
}
return true ;
}
2011-11-06 19:28:02 +00:00
# define MAX_RETRIES 16
2011-03-01 13:46:58 +00:00
# define RETRY_MS 500
2011-02-14 15:10:53 +00:00
2011-02-18 01:01:47 +00:00
static int poll_input ( netplay_t * handle , bool block )
2011-02-14 15:10:53 +00:00
{
2011-03-01 13:46:58 +00:00
int max_fd = ( handle - > fd > handle - > udp_fd ? handle - > fd : handle - > udp_fd ) + 1 ;
2011-02-14 15:10:53 +00:00
2011-12-24 12:46:12 +00:00
struct timeval tv = { 0 } ;
tv . tv_sec = 0 ;
tv . tv_usec = block ? ( RETRY_MS * 1000 ) : 0 ;
2011-02-14 15:10:53 +00:00
2011-02-18 22:51:51 +00:00
do
2011-11-03 23:18:17 +00:00
{
2011-11-06 19:28:02 +00:00
handle - > timeout_cnt + + ;
2011-11-03 23:18:17 +00:00
// select() does not take pointer to const struct timeval.
// Technically possible for select() to modify tmp_tv, so we go paranoia mode.
struct timeval tmp_tv = tv ;
2011-11-06 19:28:02 +00:00
fd_set fds ;
FD_ZERO ( & fds ) ;
FD_SET ( handle - > udp_fd , & fds ) ;
FD_SET ( handle - > fd , & fds ) ;
2011-11-03 23:18:17 +00:00
if ( select ( max_fd , & fds , NULL , NULL , & tmp_tv ) < 0 )
2011-02-18 22:51:51 +00:00
return - 1 ;
2011-02-14 15:10:53 +00:00
2012-01-21 13:00:11 +00:00
// Somewhat hacky,
// but we aren't using the TCP connection for anything useful atm.
if ( FD_ISSET ( handle - > fd , & fds ) & & ! netplay_get_cmd ( handle ) )
2011-03-01 13:46:58 +00:00
return - 1 ;
2011-02-18 22:51:51 +00:00
if ( FD_ISSET ( handle - > udp_fd , & fds ) )
return 1 ;
2011-02-18 01:01:47 +00:00
2011-02-18 22:51:51 +00:00
if ( block & & ! send_chunk ( handle ) )
{
2011-10-05 19:44:17 +00:00
warn_hangup ( ) ;
2011-02-18 22:51:51 +00:00
handle - > has_connection = false ;
2011-03-01 13:46:58 +00:00
return - 1 ;
2011-02-18 22:51:51 +00:00
}
2011-03-01 13:46:58 +00:00
if ( block )
2011-11-06 19:28:02 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Network is stalling, resending packet... Count %u of %d ... \n " ,
2011-11-16 21:30:57 +00:00
handle - > timeout_cnt , MAX_RETRIES ) ;
2011-11-06 19:28:02 +00:00
}
} while ( ( handle - > timeout_cnt < MAX_RETRIES ) & & block ) ;
2011-02-18 01:01:47 +00:00
2011-02-18 22:51:51 +00:00
if ( block )
return - 1 ;
2011-02-18 01:01:47 +00:00
return 0 ;
2011-02-13 15:40:24 +00:00
}
2011-02-14 15:10:53 +00:00
// Grab our own input state and send this over the network.
static bool get_self_input_state ( netplay_t * handle )
2011-02-13 15:40:24 +00:00
{
2013-10-22 19:26:33 +00:00
unsigned i ;
2011-02-14 15:10:53 +00:00
struct delta_frame * ptr = & handle - > buffer [ handle - > self_ptr ] ;
2011-02-13 20:19:20 +00:00
2011-02-18 01:01:47 +00:00
uint32_t state = 0 ;
2014-07-10 22:26:50 +00:00
if ( ! driver . block_libretro_input & & handle - > frame_count > 0 ) // First frame we always give zero input since relying on input from first frame screws up when we use -F 0.
2011-02-13 15:40:24 +00:00
{
2012-04-07 09:55:37 +00:00
retro_input_state_t cb = handle - > cbs . state_cb ;
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < RARCH_FIRST_META_KEY ; i + + )
2011-02-18 12:39:31 +00:00
{
2012-01-21 13:00:11 +00:00
int16_t tmp = cb ( g_settings . input . netplay_client_swap_input ? 0 : ! handle - > port ,
2012-04-07 09:55:37 +00:00
RETRO_DEVICE_JOYPAD , 0 , i ) ;
2011-02-18 12:39:31 +00:00
state | = tmp ? 1 < < i : 0 ;
}
2011-02-13 15:40:24 +00:00
}
2012-01-21 13:00:11 +00:00
memmove ( handle - > packet_buffer , handle - > packet_buffer + 2 ,
sizeof ( handle - > packet_buffer ) - 2 * sizeof ( uint32_t ) ) ;
2011-02-18 01:01:47 +00:00
handle - > packet_buffer [ ( UDP_FRAME_PACKETS - 1 ) * 2 ] = htonl ( handle - > frame_count ) ;
handle - > packet_buffer [ ( UDP_FRAME_PACKETS - 1 ) * 2 + 1 ] = htonl ( state ) ;
2011-02-18 22:51:51 +00:00
if ( ! send_chunk ( handle ) )
2011-02-13 15:40:24 +00:00
{
2011-10-05 19:44:17 +00:00
warn_hangup ( ) ;
2011-02-18 22:51:51 +00:00
handle - > has_connection = false ;
return false ;
2011-02-13 15:40:24 +00:00
}
2011-02-18 01:01:47 +00:00
2011-02-14 15:10:53 +00:00
ptr - > self_state = state ;
2011-02-14 19:11:46 +00:00
handle - > self_ptr = NEXT_PTR ( handle - > self_ptr ) ;
2011-02-14 15:10:53 +00:00
return true ;
}
2011-02-13 15:40:24 +00:00
2011-02-14 15:10:53 +00:00
// TODO: Somewhat better prediction. :P
static void simulate_input ( netplay_t * handle )
{
size_t ptr = PREV_PTR ( handle - > self_ptr ) ;
2011-02-14 21:37:57 +00:00
size_t prev = PREV_PTR ( handle - > read_ptr ) ;
2011-02-14 15:10:53 +00:00
2011-02-14 21:37:57 +00:00
handle - > buffer [ ptr ] . simulated_input_state = handle - > buffer [ prev ] . real_input_state ;
2011-02-14 15:10:53 +00:00
handle - > buffer [ ptr ] . is_simulated = true ;
2011-02-18 02:14:32 +00:00
handle - > buffer [ ptr ] . used_real = false ;
2011-02-14 15:10:53 +00:00
}
2011-02-18 01:01:47 +00:00
static void parse_packet ( netplay_t * handle , uint32_t * buffer , unsigned size )
{
2013-10-22 19:26:33 +00:00
unsigned i ;
for ( i = 0 ; i < size * 2 ; i + + )
2011-02-18 01:01:47 +00:00
buffer [ i ] = ntohl ( buffer [ i ] ) ;
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < size & & handle - > read_frame_count < = handle - > frame_count ; i + + )
2011-02-18 01:01:47 +00:00
{
2011-11-06 19:28:02 +00:00
uint32_t frame = buffer [ 2 * i + 0 ] ;
2011-02-18 01:16:32 +00:00
uint32_t state = buffer [ 2 * i + 1 ] ;
2011-02-18 02:42:43 +00:00
if ( frame = = handle - > read_frame_count )
2011-02-18 01:01:47 +00:00
{
2011-02-18 02:42:43 +00:00
handle - > buffer [ handle - > read_ptr ] . is_simulated = false ;
handle - > buffer [ handle - > read_ptr ] . real_input_state = state ;
handle - > read_ptr = NEXT_PTR ( handle - > read_ptr ) ;
handle - > read_frame_count + + ;
2011-11-06 19:28:02 +00:00
handle - > timeout_cnt = 0 ;
2011-02-18 01:01:47 +00:00
}
}
}
static bool receive_data ( netplay_t * handle , uint32_t * buffer , size_t size )
{
socklen_t addrlen = sizeof ( handle - > their_addr ) ;
2011-12-24 12:46:12 +00:00
if ( recvfrom ( handle - > udp_fd , NONCONST_CAST buffer , size , 0 , ( struct sockaddr * ) & handle - > their_addr , & addrlen ) ! = ( ssize_t ) size )
2011-02-18 01:01:47 +00:00
return false ;
handle - > has_client_addr = true ;
return true ;
}
2011-02-14 15:10:53 +00:00
// Poll network to see if we have anything new. If our network buffer is full, we simply have to block for new input data.
2012-01-11 18:22:18 +00:00
static bool netplay_poll ( netplay_t * handle )
2011-02-14 15:10:53 +00:00
{
if ( ! handle - > has_connection )
2011-02-13 15:40:24 +00:00
return false ;
2011-02-14 15:10:53 +00:00
2011-02-14 19:11:46 +00:00
handle - > can_poll = false ;
2011-02-14 15:10:53 +00:00
if ( ! get_self_input_state ( handle ) )
return false ;
2011-10-05 00:09:54 +00:00
// We skip reading the first frame so the host has a chance to grab our host info so we don't block forever :')
2011-02-18 01:01:47 +00:00
if ( handle - > frame_count = = 0 )
{
2011-02-18 14:50:57 +00:00
handle - > buffer [ 0 ] . used_real = true ;
handle - > buffer [ 0 ] . is_simulated = false ;
handle - > buffer [ 0 ] . real_input_state = 0 ;
2011-02-18 13:49:15 +00:00
handle - > read_ptr = NEXT_PTR ( handle - > read_ptr ) ;
2011-02-18 14:50:57 +00:00
handle - > read_frame_count + + ;
2011-02-18 01:01:47 +00:00
return true ;
}
2011-02-14 15:10:53 +00:00
// We might have reached the end of the buffer, where we simply have to block.
2011-10-04 23:05:34 +00:00
int res = poll_input ( handle , handle - > other_ptr = = handle - > self_ptr ) ;
2011-02-18 01:01:47 +00:00
if ( res = = - 1 )
{
handle - > has_connection = false ;
2011-10-05 19:44:17 +00:00
warn_hangup ( ) ;
2011-02-18 01:01:47 +00:00
return false ;
}
if ( res = = 1 )
2011-02-14 15:10:53 +00:00
{
2011-02-18 14:50:57 +00:00
uint32_t first_read = handle - > read_frame_count ;
2011-02-14 15:10:53 +00:00
do
{
2011-02-18 01:01:47 +00:00
uint32_t buffer [ UDP_FRAME_PACKETS * 2 ] ;
if ( ! receive_data ( handle , buffer , sizeof ( buffer ) ) )
2011-02-14 15:10:53 +00:00
{
2011-10-05 19:44:17 +00:00
warn_hangup ( ) ;
2011-02-14 15:10:53 +00:00
handle - > has_connection = false ;
return false ;
}
2011-02-18 01:01:47 +00:00
parse_packet ( handle , buffer , UDP_FRAME_PACKETS ) ;
2011-02-14 15:10:53 +00:00
2011-02-18 14:50:57 +00:00
} while ( ( handle - > read_frame_count < = handle - > frame_count ) & &
2011-10-04 23:05:34 +00:00
poll_input ( handle , ( handle - > other_ptr = = handle - > self_ptr ) & &
2011-02-18 14:50:57 +00:00
( first_read = = handle - > read_frame_count ) ) = = 1 ) ;
2011-02-14 15:10:53 +00:00
}
else
{
// Cannot allow this. Should not happen though.
2011-10-05 00:09:54 +00:00
if ( handle - > self_ptr = = handle - > other_ptr )
2011-02-14 15:10:53 +00:00
{
2011-10-05 19:44:17 +00:00
warn_hangup ( ) ;
2011-02-14 15:10:53 +00:00
return false ;
}
2011-02-14 19:11:46 +00:00
}
if ( handle - > read_ptr ! = handle - > self_ptr )
2011-02-14 15:10:53 +00:00
simulate_input ( handle ) ;
2011-02-14 19:11:46 +00:00
else
handle - > buffer [ PREV_PTR ( handle - > self_ptr ) ] . used_real = true ;
2011-02-13 15:40:24 +00:00
return true ;
}
2012-01-21 13:00:11 +00:00
static bool netplay_send_cmd ( netplay_t * handle , uint32_t cmd , const void * data , size_t size )
{
cmd = ( cmd < < 16 ) | ( size & 0xffff ) ;
cmd = htonl ( cmd ) ;
if ( ! send_all ( handle - > fd , & cmd , sizeof ( cmd ) ) )
return false ;
if ( ! send_all ( handle - > fd , data , size ) )
return false ;
return true ;
}
static bool netplay_cmd_ack ( netplay_t * handle )
{
uint32_t cmd = htonl ( NETPLAY_CMD_ACK ) ;
return send_all ( handle - > fd , & cmd , sizeof ( cmd ) ) ;
}
static bool netplay_cmd_nak ( netplay_t * handle )
{
uint32_t cmd = htonl ( NETPLAY_CMD_NAK ) ;
return send_all ( handle - > fd , & cmd , sizeof ( cmd ) ) ;
}
static bool netplay_get_response ( netplay_t * handle )
{
uint32_t response ;
if ( ! recv_all ( handle - > fd , & response , sizeof ( response ) ) )
return false ;
return ntohl ( response ) = = NETPLAY_CMD_ACK ;
}
static bool netplay_get_cmd ( netplay_t * handle )
{
uint32_t cmd ;
if ( ! recv_all ( handle - > fd , & cmd , sizeof ( cmd ) ) )
return false ;
cmd = ntohl ( cmd ) ;
size_t cmd_size = cmd & 0xffff ;
cmd = cmd > > 16 ;
switch ( cmd )
{
case NETPLAY_CMD_FLIP_PLAYERS :
{
if ( cmd_size ! = sizeof ( uint32_t ) )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " CMD_FLIP_PLAYERS has unexpected command size. \n " ) ;
2012-01-21 13:00:11 +00:00
return netplay_cmd_nak ( handle ) ;
}
uint32_t flip_frame ;
if ( ! recv_all ( handle - > fd , & flip_frame , sizeof ( flip_frame ) ) )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to receive CMD_FLIP_PLAYERS argument. \n " ) ;
2012-01-21 13:00:11 +00:00
return netplay_cmd_nak ( handle ) ;
}
flip_frame = ntohl ( flip_frame ) ;
if ( flip_frame < handle - > flip_frame )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Host asked us to flip players in the past. Not possible ... \n " ) ;
2012-01-21 13:00:11 +00:00
return netplay_cmd_nak ( handle ) ;
}
handle - > flip ^ = true ;
handle - > flip_frame = flip_frame ;
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Netplay players are flipped. \n " ) ;
2012-02-11 19:59:41 +00:00
msg_queue_push ( g_extern . msg_queue , " Netplay players are flipped. " , 1 , 180 ) ;
2012-01-21 13:24:38 +00:00
2012-01-21 13:00:11 +00:00
return netplay_cmd_ack ( handle ) ;
}
default :
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Unknown netplay command received. \n " ) ;
2012-01-21 13:00:11 +00:00
return netplay_cmd_nak ( handle ) ;
}
}
void netplay_flip_players ( netplay_t * handle )
{
2012-01-21 13:46:33 +00:00
uint32_t flip_frame = handle - > frame_count + 2 * UDP_FRAME_PACKETS ;
2012-01-21 13:00:11 +00:00
uint32_t flip_frame_net = htonl ( flip_frame ) ;
const char * msg = NULL ;
if ( handle - > spectate )
{
2012-02-11 19:59:41 +00:00
msg = " Cannot flip players in spectate mode. " ;
2012-01-21 13:00:11 +00:00
goto error ;
}
if ( handle - > port = = 0 )
{
2012-02-11 19:59:41 +00:00
msg = " Cannot flip players if you're not the host. " ;
2012-01-21 13:00:11 +00:00
goto error ;
}
// Make sure both clients are definitely synced up.
2012-01-21 13:46:33 +00:00
if ( handle - > frame_count < ( handle - > flip_frame + 2 * UDP_FRAME_PACKETS ) )
2012-01-21 13:00:11 +00:00
{
2012-02-11 20:11:36 +00:00
msg = " Cannot flip players yet. Wait a second or two before attempting flip. " ;
2012-01-21 13:00:11 +00:00
goto error ;
}
if ( netplay_send_cmd ( handle , NETPLAY_CMD_FLIP_PLAYERS , & flip_frame_net , sizeof ( flip_frame_net ) )
& & netplay_get_response ( handle ) )
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Netplay players are flipped. \n " ) ;
2012-02-11 19:59:41 +00:00
msg_queue_push ( g_extern . msg_queue , " Netplay players are flipped. " , 1 , 180 ) ;
2012-01-21 13:24:38 +00:00
2012-01-21 13:00:11 +00:00
// Queue up a flip well enough in the future.
handle - > flip ^ = true ;
handle - > flip_frame = flip_frame ;
}
else
{
2012-02-11 19:59:41 +00:00
msg = " Failed to flip players. " ;
2012-01-21 13:00:11 +00:00
goto error ;
}
return ;
error :
2012-04-21 21:25:32 +00:00
RARCH_WARN ( " %s \n " , msg ) ;
2012-01-21 13:00:11 +00:00
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
}
2012-01-21 13:46:33 +00:00
static bool netplay_flip_port ( netplay_t * handle , bool port )
2012-01-21 13:00:11 +00:00
{
if ( handle - > flip_frame = = 0 )
return port ;
2012-01-21 15:14:10 +00:00
size_t frame = handle - > is_replay ? handle - > tmp_frame_count : handle - > frame_count ;
2012-01-21 13:46:33 +00:00
return port ^ handle - > flip ^ ( frame < handle - > flip_frame ) ;
2012-01-21 13:00:11 +00:00
}
2011-02-13 15:40:24 +00:00
int16_t netplay_input_state ( netplay_t * handle , bool port , unsigned device , unsigned index , unsigned id )
{
2011-02-14 15:10:53 +00:00
uint16_t input_state = 0 ;
2012-01-21 13:00:11 +00:00
size_t ptr = handle - > is_replay ? handle - > tmp_ptr : PREV_PTR ( handle - > self_ptr ) ;
2011-02-14 15:10:53 +00:00
2012-01-21 13:46:33 +00:00
port = netplay_flip_port ( handle , port ) ;
2011-02-14 15:10:53 +00:00
2011-02-14 19:11:46 +00:00
if ( ( port ? 1 : 0 ) = = handle - > port )
2011-02-14 15:10:53 +00:00
{
if ( handle - > buffer [ ptr ] . is_simulated )
input_state = handle - > buffer [ ptr ] . simulated_input_state ;
else
input_state = handle - > buffer [ ptr ] . real_input_state ;
}
else
input_state = handle - > buffer [ ptr ] . self_state ;
return ( ( 1 < < id ) & input_state ) ? 1 : 0 ;
2011-02-13 15:40:24 +00:00
}
void netplay_free ( netplay_t * handle )
{
2013-10-22 19:26:33 +00:00
unsigned i ;
2011-02-13 15:40:24 +00:00
close ( handle - > fd ) ;
2011-02-14 15:10:53 +00:00
2012-01-11 18:22:18 +00:00
if ( handle - > spectate )
{
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < MAX_SPECTATORS ; i + + )
2012-01-11 18:22:18 +00:00
if ( handle - > spectate_fds [ i ] > = 0 )
close ( handle - > spectate_fds [ i ] ) ;
free ( handle - > spectate_input ) ;
}
else
{
close ( handle - > udp_fd ) ;
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < handle - > buffer_size ; i + + )
2012-01-11 18:22:18 +00:00
free ( handle - > buffer [ i ] . state ) ;
free ( handle - > buffer ) ;
}
2011-02-18 01:01:47 +00:00
if ( handle - > addr )
freeaddrinfo ( handle - > addr ) ;
2012-01-11 18:22:18 +00:00
2011-02-13 15:40:24 +00:00
free ( handle ) ;
}
2012-01-11 18:22:18 +00:00
static bool netplay_should_skip ( netplay_t * handle )
2011-02-14 15:10:53 +00:00
{
return handle - > is_replay & & handle - > has_connection ;
}
2012-01-11 18:22:18 +00:00
static void netplay_pre_frame_net ( netplay_t * handle )
2011-02-14 15:10:53 +00:00
{
2012-04-07 09:55:37 +00:00
pretro_serialize ( handle - > buffer [ handle - > self_ptr ] . state , handle - > state_size ) ;
2011-02-14 19:11:46 +00:00
handle - > can_poll = true ;
2011-06-26 13:32:24 +00:00
input_poll_net ( ) ;
2011-02-14 15:10:53 +00:00
}
2012-01-11 18:22:18 +00:00
static void netplay_set_spectate_input ( netplay_t * handle , int16_t input )
{
if ( handle - > spectate_input_ptr > = handle - > spectate_input_size )
{
handle - > spectate_input_size + + ;
handle - > spectate_input_size * = 2 ;
handle - > spectate_input = ( uint16_t * ) realloc ( handle - > spectate_input ,
handle - > spectate_input_size * sizeof ( uint16_t ) ) ;
}
handle - > spectate_input [ handle - > spectate_input_ptr + + ] = swap_if_big16 ( input ) ;
}
2012-04-07 09:55:37 +00:00
int16_t input_state_spectate ( unsigned port , unsigned device , unsigned index , unsigned id )
2012-01-11 18:22:18 +00:00
{
2012-04-07 09:55:37 +00:00
int16_t res = g_extern . netplay - > cbs . state_cb ( port , device , index , id ) ;
2012-01-11 18:22:18 +00:00
netplay_set_spectate_input ( g_extern . netplay , res ) ;
return res ;
}
static int16_t netplay_get_spectate_input ( netplay_t * handle , bool port , unsigned device , unsigned index , unsigned id )
{
int16_t inp ;
2012-01-21 13:00:11 +00:00
if ( recv_all ( handle - > fd , NONCONST_CAST & inp , sizeof ( inp ) ) )
2012-01-11 18:22:18 +00:00
return swap_if_big16 ( inp ) ;
else
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Connection with host was cut. \n " ) ;
2012-01-11 18:22:18 +00:00
msg_queue_clear ( g_extern . msg_queue ) ;
2012-02-11 19:59:41 +00:00
msg_queue_push ( g_extern . msg_queue , " Connection with host was cut. " , 1 , 180 ) ;
2012-01-11 18:22:18 +00:00
2012-04-07 09:55:37 +00:00
pretro_set_input_state ( g_extern . netplay - > cbs . state_cb ) ;
return g_extern . netplay - > cbs . state_cb ( port , device , index , id ) ;
2012-01-11 18:22:18 +00:00
}
}
2012-04-07 09:55:37 +00:00
int16_t input_state_spectate_client ( unsigned port , unsigned device , unsigned index , unsigned id )
2012-01-11 18:22:18 +00:00
{
return netplay_get_spectate_input ( g_extern . netplay , port , device , index , id ) ;
}
static void netplay_pre_frame_spectate ( netplay_t * handle )
{
2013-10-22 19:26:33 +00:00
unsigned i ;
2012-01-11 18:22:18 +00:00
if ( handle - > spectate_client )
return ;
fd_set fds ;
FD_ZERO ( & fds ) ;
FD_SET ( handle - > fd , & fds ) ;
struct timeval tmp_tv = { 0 } ;
if ( select ( handle - > fd + 1 , & fds , NULL , NULL , & tmp_tv ) < = 0 )
return ;
if ( ! FD_ISSET ( handle - > fd , & fds ) )
return ;
2012-01-11 19:50:21 +00:00
struct sockaddr_storage their_addr ;
socklen_t addr_size = sizeof ( their_addr ) ;
int new_fd = accept ( handle - > fd , ( struct sockaddr * ) & their_addr , & addr_size ) ;
2012-01-11 18:22:18 +00:00
if ( new_fd < 0 )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to accept incoming spectator. \n " ) ;
2012-01-11 18:22:18 +00:00
return ;
}
int index = - 1 ;
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < MAX_SPECTATORS ; i + + )
2012-01-11 18:22:18 +00:00
{
if ( handle - > spectate_fds [ i ] = = - 1 )
{
index = i ;
break ;
}
}
// No vacant client streams :(
if ( index = = - 1 )
{
close ( new_fd ) ;
return ;
}
2012-01-21 17:34:07 +00:00
if ( ! get_nickname ( handle , new_fd ) )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to get nickname from client. \n " ) ;
2012-01-21 17:34:07 +00:00
close ( new_fd ) ;
return ;
}
if ( ! send_nickname ( handle , new_fd ) )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to send nickname to client. \n " ) ;
2012-01-21 17:34:07 +00:00
close ( new_fd ) ;
return ;
}
2012-01-11 18:22:18 +00:00
size_t header_size ;
2012-01-21 17:12:42 +00:00
uint32_t * header = bsv_header_generate ( & header_size , implementation_magic_value ( ) ) ;
2012-01-11 18:22:18 +00:00
if ( ! header )
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to generate BSV header. \n " ) ;
2012-01-11 18:22:18 +00:00
close ( new_fd ) ;
return ;
}
2012-01-11 19:14:59 +00:00
int bufsize = header_size ;
setsockopt ( new_fd , SOL_SOCKET , SO_SNDBUF , CONST_CAST & bufsize , sizeof ( int ) ) ;
2012-01-21 17:12:42 +00:00
if ( ! send_all ( new_fd , header , header_size ) )
2012-01-11 18:22:18 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_ERR ( " Failed to send header to client. \n " ) ;
2012-01-21 13:00:11 +00:00
close ( new_fd ) ;
free ( header ) ;
return ;
2012-01-11 18:22:18 +00:00
}
free ( header ) ;
handle - > spectate_fds [ index ] = new_fd ;
2012-01-11 19:50:21 +00:00
2012-01-24 22:14:11 +00:00
# ifndef HAVE_SOCKET_LEGACY
2012-01-21 17:12:42 +00:00
log_connection ( & their_addr , index , handle - > other_nick ) ;
2012-01-24 22:14:11 +00:00
# endif
2012-01-11 18:22:18 +00:00
}
void netplay_pre_frame ( netplay_t * handle )
{
if ( handle - > spectate )
netplay_pre_frame_spectate ( handle ) ;
else
netplay_pre_frame_net ( handle ) ;
}
static void netplay_post_frame_net ( netplay_t * handle )
2011-02-14 15:10:53 +00:00
{
2011-02-18 01:01:47 +00:00
handle - > frame_count + + ;
2011-02-14 15:10:53 +00:00
// Nothing to do...
2011-10-05 00:09:54 +00:00
if ( handle - > other_frame_count = = handle - > read_frame_count )
2011-02-14 15:10:53 +00:00
return ;
// Skip ahead if we predicted correctly. Skip until our simulation failed.
2011-10-05 00:09:54 +00:00
while ( handle - > other_frame_count < handle - > read_frame_count )
2011-02-14 15:10:53 +00:00
{
2012-01-11 18:22:18 +00:00
const struct delta_frame * ptr = & handle - > buffer [ handle - > other_ptr ] ;
2011-02-14 19:11:46 +00:00
if ( ( ptr - > simulated_input_state ! = ptr - > real_input_state ) & & ! ptr - > used_real )
2011-02-14 15:10:53 +00:00
break ;
handle - > other_ptr = NEXT_PTR ( handle - > other_ptr ) ;
2011-10-05 00:09:54 +00:00
handle - > other_frame_count + + ;
2011-02-14 15:10:53 +00:00
}
2011-10-05 00:09:54 +00:00
if ( handle - > other_frame_count < handle - > read_frame_count )
2011-02-14 15:10:53 +00:00
{
// Replay frames
handle - > is_replay = true ;
handle - > tmp_ptr = handle - > other_ptr ;
2012-01-21 15:14:10 +00:00
handle - > tmp_frame_count = handle - > other_frame_count ;
2012-04-07 09:55:37 +00:00
pretro_unserialize ( handle - > buffer [ handle - > other_ptr ] . state , handle - > state_size ) ;
2011-10-05 00:09:54 +00:00
bool first = true ;
while ( first | | ( handle - > tmp_ptr ! = handle - > self_ptr ) )
2011-02-14 15:10:53 +00:00
{
2012-04-07 09:55:37 +00:00
pretro_serialize ( handle - > buffer [ handle - > tmp_ptr ] . state , handle - > state_size ) ;
2013-02-17 01:00:51 +00:00
# if defined(HAVE_THREADS) && !defined(RARCH_CONSOLE)
2011-02-18 22:51:51 +00:00
lock_autosave ( ) ;
2011-11-30 16:46:58 +00:00
# endif
2012-04-07 09:55:37 +00:00
pretro_run ( ) ;
2013-02-17 01:00:51 +00:00
# if defined(HAVE_THREADS) && !defined(RARCH_CONSOLE)
2011-02-18 22:51:51 +00:00
unlock_autosave ( ) ;
2011-11-30 16:46:58 +00:00
# endif
2011-02-14 15:10:53 +00:00
handle - > tmp_ptr = NEXT_PTR ( handle - > tmp_ptr ) ;
2012-01-21 15:14:10 +00:00
handle - > tmp_frame_count + + ;
2011-10-05 00:09:54 +00:00
first = false ;
2011-02-14 15:10:53 +00:00
}
2012-01-21 15:14:10 +00:00
2011-02-14 15:10:53 +00:00
handle - > other_ptr = handle - > read_ptr ;
2011-10-05 00:09:54 +00:00
handle - > other_frame_count = handle - > read_frame_count ;
2011-02-14 15:10:53 +00:00
handle - > is_replay = false ;
}
}
2011-12-04 17:03:08 +00:00
2012-01-11 18:22:18 +00:00
static void netplay_post_frame_spectate ( netplay_t * handle )
{
2013-10-22 19:26:33 +00:00
unsigned i ;
2012-01-11 18:22:18 +00:00
if ( handle - > spectate_client )
return ;
2013-10-22 19:26:33 +00:00
for ( i = 0 ; i < MAX_SPECTATORS ; i + + )
2012-01-11 18:22:18 +00:00
{
if ( handle - > spectate_fds [ i ] = = - 1 )
continue ;
2012-01-21 13:00:11 +00:00
if ( ! send_all ( handle - > spectate_fds [ i ] ,
handle - > spectate_input , handle - > spectate_input_ptr * sizeof ( int16_t ) ) )
2012-01-11 18:22:18 +00:00
{
2012-04-21 21:25:32 +00:00
RARCH_LOG ( " Client (#%u) disconnected ... \n " , i ) ;
2012-01-11 20:08:44 +00:00
2012-01-21 13:00:11 +00:00
char msg [ 512 ] ;
2012-02-11 19:59:41 +00:00
snprintf ( msg , sizeof ( msg ) , " Client (#%u) disconnected. " , i ) ;
2012-01-21 13:00:11 +00:00
msg_queue_push ( g_extern . msg_queue , msg , 1 , 180 ) ;
2012-01-11 18:22:18 +00:00
2012-01-21 13:00:11 +00:00
close ( handle - > spectate_fds [ i ] ) ;
handle - > spectate_fds [ i ] = - 1 ;
break ;
2012-01-11 18:22:18 +00:00
}
}
handle - > spectate_input_ptr = 0 ;
}
// Here we check if we have new input and replay from recorded input.
void netplay_post_frame ( netplay_t * handle )
{
if ( handle - > spectate )
netplay_post_frame_spectate ( handle ) ;
else
netplay_post_frame_net ( handle ) ;
}
2012-03-16 23:48:43 +00:00
# ifdef HAVE_SOCKET_LEGACY
# undef getaddrinfo
# undef freeaddrinfo
# undef sockaddr_storage
# undef addrinfo
# include <stdlib.h>
# include <ctype.h>
# include <string.h>
2012-04-21 21:25:32 +00:00
# define addrinfo addrinfo_rarch__
2012-03-16 23:48:43 +00:00
// Yes, we love shitty implementations, don't we? :(
# ifdef _XBOX
struct hostent
{
char * * h_addr_list ; // Just do the minimal needed ...
} ;
static struct hostent * gethostbyname ( const char * name )
{
static struct hostent he ;
static struct in_addr addr ;
static char * addr_ptr ;
he . h_addr_list = & addr_ptr ;
addr_ptr = ( char * ) & addr ;
if ( ! name )
return NULL ;
XNDNS * dns = NULL ;
WSAEVENT event = WSACreateEvent ( ) ;
XNetDnsLookup ( name , event , & dns ) ;
if ( ! dns )
goto error ;
WaitForSingleObject ( ( HANDLE ) event , INFINITE ) ;
if ( dns - > iStatus )
goto error ;
memcpy ( & addr , dns - > aina , sizeof ( addr ) ) ;
WSACloseEvent ( event ) ;
XNetDnsRelease ( dns ) ;
return & he ;
error :
if ( event )
WSACloseEvent ( event ) ;
return NULL ;
}
# endif
2012-04-21 21:25:32 +00:00
int getaddrinfo_rarch__ ( const char * node , const char * service ,
2012-03-16 23:48:43 +00:00
const struct addrinfo * hints ,
struct addrinfo * * res )
{
struct addrinfo * info = ( struct addrinfo * ) calloc ( 1 , sizeof ( * info ) ) ;
if ( ! info )
return - 1 ;
info - > ai_family = AF_INET ;
info - > ai_socktype = hints - > ai_socktype ;
struct sockaddr_in * in_addr = ( struct sockaddr_in * ) calloc ( 1 , sizeof ( * in_addr ) ) ;
if ( ! in_addr )
{
free ( info ) ;
return - 1 ;
}
info - > ai_addrlen = sizeof ( * in_addr ) ;
in_addr - > sin_family = AF_INET ;
in_addr - > sin_port = htons ( strtoul ( service , NULL , 0 ) ) ;
if ( ! node & & ( hints - > ai_flags & AI_PASSIVE ) )
in_addr - > sin_addr . s_addr = INADDR_ANY ;
else if ( node & & isdigit ( * node ) )
in_addr - > sin_addr . s_addr = inet_addr ( node ) ;
else if ( node & & ! isdigit ( * node ) )
{
struct hostent * host = gethostbyname ( node ) ;
if ( ! host | | ! host - > h_addr_list [ 0 ] )
goto error ;
in_addr - > sin_addr . s_addr = inet_addr ( host - > h_addr_list [ 0 ] ) ;
}
else
goto error ;
info - > ai_addr = ( struct sockaddr * ) in_addr ;
* res = info ;
return 0 ;
error :
free ( in_addr ) ;
free ( info ) ;
return - 1 ;
}
2012-04-21 21:25:32 +00:00
void freeaddrinfo_rarch__ ( struct addrinfo * res )
2012-03-16 23:48:43 +00:00
{
free ( res - > ai_addr ) ;
free ( res ) ;
}
# endif