2007-01-15 12:09:25 -08:00
/*
This file is part of Warzone 2100.
Copyright ( C ) 1999 - 2004 Eidos Interactive
2009-02-10 10:01:48 -08:00
Copyright ( C ) 2005 - 2009 Warzone Resurrection Project
2007-01-15 12:09:25 -08:00
Warzone 2100 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 2 of the License , or
( at your option ) any later version .
Warzone 2100 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 Warzone 2100 ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2008-02-16 05:39:23 -08:00
/**
* @ file netplay . c
*
* Basic netcode .
*/
2007-06-28 10:47:08 -07:00
2007-04-18 07:46:38 -07:00
# include "lib/framework/frame.h"
2009-02-10 09:23:09 -08:00
# include "lib/framework/string_ext.h"
2009-04-10 21:41:14 -07:00
# include "lib/gamelib/gtime.h"
2007-04-18 07:46:38 -07:00
2005-12-02 13:45:42 -08:00
# include <time.h> // for stats
2009-07-13 13:09:57 -07:00
# include <SDL_timer.h>
2006-06-16 12:10:23 -07:00
# include <physfs.h>
2006-11-06 06:40:07 -08:00
# include <string.h>
2007-06-28 10:47:08 -07:00
# include "netplay.h"
2006-04-08 12:32:29 -07:00
# include "netlog.h"
2007-06-28 10:47:08 -07:00
2009-05-03 08:16:49 -07:00
# if defined(WZ_OS_UNIX)
# include <arpa / inet.h>
# include <errno.h>
# include <fcntl.h>
# include <netdb.h>
2009-05-24 14:43:42 -07:00
# include <netinet / in.h>
2009-05-03 08:16:49 -07:00
# include <sys / socket.h>
# include <sys / types.h>
# include <unistd.h>
typedef int SOCKET ;
2009-05-03 08:17:05 -07:00
static const SOCKET INVALID_SOCKET = - 1 ;
2009-05-03 08:17:36 -07:00
static const int SOCKET_ERROR = - 1 ;
2009-05-03 08:16:49 -07:00
# elif defined(WZ_OS_WIN)
# include <winsock2.h>
# include <ws2tcpip.h>
2009-05-03 12:02:06 -07:00
# undef EAGAIN
2009-05-06 13:07:04 -07:00
# undef ECONNRESET
2009-05-03 12:02:06 -07:00
# undef EINPROGRESS
# undef EINTR
# undef EISCONN
# undef ETIMEDOUT
# undef EWOULDBLOCK
2009-05-03 08:38:16 -07:00
# define EAGAIN WSAEWOULDBLOCK
2009-05-06 13:07:04 -07:00
# define ECONNRESET WSAECONNRESET
2009-05-03 08:16:49 -07:00
# define EINPROGRESS WSAEINPROGRESS
2009-05-03 12:02:06 -07:00
# define EINTR WSAEINTR
2009-05-03 08:16:49 -07:00
# define EISCONN WSAEISCONN
# define ETIMEDOUT WSAETIMEDOUT
# define EWOULDBLOCK WSAEWOULDBLOCK
2009-05-03 11:56:36 -07:00
typedef SSIZE_T ssize_t ;
2009-05-03 08:16:49 -07:00
# ifndef AI_V4MAPPED
# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */
# endif
# ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose returned address type.. */
# endif
# endif
static int getSockErr ( void )
{
# if defined(WZ_OS_UNIX)
return errno ;
# elif defined(WZ_OS_WIN)
return WSAGetLastError ( ) ;
# endif
}
static void setSockErr ( int error )
{
# if defined(WZ_OS_UNIX)
errno = error ;
# elif defined(WZ_OS_WIN)
WSASetLastError ( error ) ;
# endif
}
2009-05-03 08:16:03 -07:00
2007-04-21 06:46:28 -07:00
// WARNING !!! This is initialised via configuration.c !!!
char masterserver_name [ 255 ] = { ' \0 ' } ;
unsigned int masterserver_port = 0 , gameserver_port = 0 ;
2007-06-28 10:47:08 -07:00
# define MAX_CONNECTED_PLAYERS 8
# define MAX_TMP_SOCKETS 16
2009-06-10 20:51:37 -07:00
# define NET_TIMEOUT_DELAY 2500 // we wait this amount of time for socket activity
2005-12-02 13:45:42 -08:00
# define NET_READ_TIMEOUT 0
2009-03-20 12:28:04 -07:00
/*
*
* NOTE / rant : If the buffer size isn ' t big enough , it will invalidate the socket .
* Which means that we need to allocate a buffer big enough to handle worst case
* situations .
* SDLNet_TCP_Recv ( ) craps out because of this , and the forthcoming error message
* is less than eloquent .
* ( " SDL is not running on known window manager " is NOT a valid socket error msg ! )
* Perhaps SDLNet_GetError ( ) being a alias for SDL_GetError ( ) has something to do with this ?
*
* reference : MaxMsgSize in netplay . h ( currently set to 8192 )
*
*/
# define NET_BUFFER_SIZE (MaxMsgSize) // Would be 8K
2007-06-28 10:47:08 -07:00
2009-04-10 21:41:14 -07:00
// HACK(s) to allow us to call a src/multi*.c function
extern void recvMultiStats ( void ) ; // from src/multistat.c
extern BOOL sendTextMessage ( const char * pStr , BOOL all ) ; // from src/multiplay.c
2009-06-07 11:10:13 -07:00
extern BOOL MultiPlayerJoin ( UDWORD playerIndex ) ; // from src/multijoin.c
extern BOOL MultiPlayerLeave ( UDWORD playerIndex ) ; // from src/multijoin.c
2009-04-19 11:45:28 -07:00
extern void ShowMOTD ( void ) ; // from src/multijoin.c
extern void kickPlayer ( uint32_t player_id , const char * reason , LOBBY_ERROR_TYPES type ) ; // from src/multiinit.c
extern void setLobbyError ( LOBBY_ERROR_TYPES error_type ) ; // from src/multiinit.c
extern LOBBY_ERROR_TYPES getLobbyError ( void ) ; // from src/multiinit.c
2007-07-25 08:31:27 -07:00
// ////////////////////////////////////////////////////////////////////////
// Function prototypes
2009-06-07 11:10:13 -07:00
void NETplayerLeaving ( UDWORD player ) ; // Cleanup sockets on player leaving (nicely)
void NETplayerDropped ( UDWORD player ) ; // Broadcast NET_PLAYER_DROPPED & cleanup
2006-09-13 14:14:47 -07:00
static void NETallowJoining ( void ) ;
2009-06-07 11:10:13 -07:00
static void sendVersionCheck ( void ) ;
static void recvVersionCheck ( void ) ;
static void VersionCheckTimeOut ( uint32_t victim ) ;
void NETGameLocked ( bool flag ) ;
void NETresetGamePassword ( void ) ;
void sendPasswordCheck ( void ) ;
void recvPasswordCheck ( void ) ;
2009-04-19 11:45:28 -07:00
void NETGameLocked ( bool flag ) ;
void NETresetGamePassword ( void ) ;
void sendPasswordCheck ( void ) ;
void recvPasswordCheck ( void ) ;
2007-08-08 11:50:28 -07:00
/*
* Network globals , these are part of the new network API
*/
NETMSG NetMsg ;
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////
2007-07-25 08:31:27 -07:00
// Types
2007-06-28 10:47:08 -07:00
2007-07-25 08:31:27 -07:00
typedef struct // data regarding the last one second or so.
{
UDWORD bytesRecvd ;
UDWORD bytesSent ; // number of bytes sent in about 1 sec.
UDWORD packetsSent ;
UDWORD packetsRecvd ;
} NETSTATS ;
2007-06-28 10:47:08 -07:00
2007-07-25 08:31:27 -07:00
typedef struct
{
2008-02-02 06:45:08 -08:00
uint16_t size ;
void * data ;
size_t buffer_size ;
2007-07-24 11:59:57 -07:00
} NET_PLAYER_DATA ;
2009-05-09 10:20:32 -07:00
enum
{
SOCK_CONNECTION ,
SOCK_IPV4_LISTEN = SOCK_CONNECTION ,
SOCK_IPV6_LISTEN ,
SOCK_COUNT ,
} ;
2007-07-25 08:31:27 -07:00
typedef struct
{
2009-05-09 10:20:32 -07:00
/* Multiple socket handles only for listening sockets. This allows us
* to listen on multiple protocols and address families ( e . g . IPv4 and
* IPv6 ) .
*
* All non - listening sockets will only use the first socket handle .
*/
SOCKET fd [ SOCK_COUNT ] ;
2009-05-03 08:16:03 -07:00
bool ready ;
} Socket ;
typedef struct
{
Socket * socket ;
2007-06-28 10:47:08 -07:00
char * buffer ;
unsigned int buffer_start ;
unsigned int bytes ;
} NETBUFSOCKET ;
2009-05-03 08:16:03 -07:00
typedef struct
{
size_t len ;
Socket * * fds ;
} SocketSet ;
2007-07-25 08:31:27 -07:00
# define PLAYER_HOST 1
// ////////////////////////////////////////////////////////////////////////
// Variables
NETPLAY NetPlay ;
2008-03-24 09:51:17 -07:00
static BOOL allow_joining = false ;
2009-04-23 20:16:04 -07:00
static bool server_not_there = false ;
2007-07-25 08:31:27 -07:00
static GAMESTRUCT game ;
2009-04-30 17:01:13 -07:00
/**
* Socket used for these purposes :
* * Host a game , be a server .
* * Connect to the lobby server .
* * Join a server for a game .
*/
2009-05-03 08:16:03 -07:00
static Socket * tcp_socket = NULL ; //socket used to talk to lobbyserver/ host machine
2009-04-30 17:01:13 -07:00
2009-02-21 14:09:58 -08:00
static NETBUFSOCKET * bsocket = NULL ; //buffered socket (holds tcp_socket) (clients only?)
2007-07-25 08:31:27 -07:00
static NETBUFSOCKET * connected_bsocket [ MAX_CONNECTED_PLAYERS ] = { NULL } ;
2009-05-03 08:16:03 -07:00
static SocketSet * socket_set = NULL ;
2009-04-30 17:01:13 -07:00
/**
* Used for connections with clients .
*/
2009-05-03 08:16:03 -07:00
static Socket * tmp_socket [ MAX_TMP_SOCKETS ] = { NULL } ;
2009-04-30 17:01:13 -07:00
2009-05-03 08:16:03 -07:00
static SocketSet * tmp_socket_set = NULL ;
2007-07-25 08:31:27 -07:00
static char * hostname ;
static NETSTATS nStats = { 0 , 0 , 0 , 0 } ;
2008-03-24 09:02:11 -07:00
static int32_t NetGameFlags [ 4 ] = { 0 , 0 , 0 , 0 } ;
2008-05-11 12:09:29 -07:00
char iptoconnect [ PATH_MAX ] = " \0 " ; // holds IP/hostname from command line
2007-07-25 08:31:27 -07:00
2009-02-21 14:09:58 -08:00
extern int NET_PlayerConnectionStatus ; // from src/display3d.c
2009-04-19 11:45:28 -07:00
extern LOBBY_ERROR_TYPES LobbyError ; // from src/multiint.c
2009-04-10 21:41:14 -07:00
2009-06-07 11:10:13 -07:00
//time when check sent. Note, using 0xffffffff to signal nothing sent yet.
2009-04-10 21:41:14 -07:00
uint32_t VersionCheckTime [ MAX_PLAYERS ] = { - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ;
static BOOL playerVersionFlag [ MAX_PLAYERS ] = { false } ; // we kick on false
2009-04-19 11:45:28 -07:00
static bool playerPasswordFlag [ MAX_PLAYERS ] = { false } ; // we kick on false
2009-04-10 21:41:14 -07:00
// ////////////////////////////////////////////////////////////////////////////
# define VersionStringSize 80
/************************************************************************************
* * NOTE ( ! ) Change the VersionString when net code changes ! !
* * ie ( " trunk " , " 2.1.3 " , . . . )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* */
2009-10-04 19:49:58 -07:00
char VersionString [ VersionStringSize ] = " trunk-check " ;
2009-04-10 21:41:14 -07:00
static int NETCODE_VERSION_MAJOR = 2 ; // unused for now
2009-10-04 19:49:58 -07:00
static int NETCODE_VERSION_MINOR = 24 ; // unused for now
2009-04-10 21:41:14 -07:00
static int NUMBER_OF_MODS = 0 ; // unused for now
static int NETCODE_HASH = 0 ; // unused for now
2009-05-03 08:16:49 -07:00
# if defined(WZ_OS_WIN)
static HMODULE winsock2_dll = NULL ;
static unsigned int major_windows_version = 0 ;
static int ( WINAPI * getaddrinfo_dll_func ) ( const char * node , const char * service ,
const struct addrinfo * hints ,
struct addrinfo * * res ) = NULL ;
static int ( WINAPI * freeaddrinfo_dll_func ) ( struct addrinfo * res ) = NULL ;
# define getaddrinfo getaddrinfo_dll_dispatcher
# define freeaddrinfo freeaddrinfo_dll_dispatcher
static int getaddrinfo ( const char * node , const char * service ,
const struct addrinfo * hints ,
struct addrinfo * * res )
{
struct addrinfo hint ;
if ( hints )
{
memcpy ( & hint , hints , sizeof ( hint ) ) ;
}
switch ( major_windows_version )
{
case 0 :
case 1 :
case 2 :
case 3 :
// Windows 95, 98 and ME
case 4 :
debug ( LOG_ERROR , " Name resolution isn't supported on this version (%u) of Windows " , major_windows_version ) ;
return EAI_FAIL ;
// Windows 2000, XP and Server 2003
case 5 :
if ( hints )
{
// These flags are only supported from version 6 and onward
hint . ai_flags & = ~ ( AI_V4MAPPED | AI_ADDRCONFIG ) ;
}
// Windows Vista and Server 2008
case 6 :
// Onward (aka: in the future)
default :
if ( ! winsock2_dll )
{
debug ( LOG_ERROR , " Failed to load winsock2 DLL. Required for name resolution. " ) ;
return EAI_FAIL ;
}
if ( ! getaddrinfo_dll_func )
{
debug ( LOG_ERROR , " Failed to retrieve \" getaddrinfo \" function from winsock2 DLL. Required for name resolution. " ) ;
return EAI_FAIL ;
}
return getaddrinfo_dll_func ( node , service , hints ? & hint : NULL , res ) ;
}
}
static void freeaddrinfo ( struct addrinfo * res )
{
switch ( major_windows_version )
{
case 0 :
case 1 :
case 2 :
case 3 :
// Windows 95, 98 and ME
case 4 :
debug ( LOG_ERROR , " Name resolution isn't supported on this version (%u) of Windows " , major_windows_version ) ;
return ;
// Windows 2000, XP and Server 2003
case 5 :
// Windows Vista and Server 2008
case 6 :
// Onward (aka: in the future)
default :
if ( ! winsock2_dll )
{
debug ( LOG_ERROR , " Failed to load winsock2 DLL. Required for name resolution. " ) ;
return ;
}
if ( ! freeaddrinfo_dll_func )
{
debug ( LOG_ERROR , " Failed to retrieve \" freeaddrinfo \" function from winsock2 DLL. Required for name resolution. " ) ;
return ;
}
freeaddrinfo_dll_func ( res ) ;
}
}
# endif
2009-05-03 08:52:37 -07:00
static int addressToText ( const struct sockaddr * addr , char * buf , size_t size )
{
switch ( addr - > sa_family )
{
case AF_INET :
{
unsigned char * address = ( unsigned char * ) & ( ( const struct sockaddr_in * ) addr ) - > sin_addr . s_addr ;
return snprintf ( buf , size ,
2009-07-26 05:34:26 -07:00
" %hhu.%hhu.%hhu.%hhu " ,
address [ 0 ] ,
address [ 1 ] ,
address [ 2 ] ,
address [ 3 ] ) ;
2009-05-03 08:52:37 -07:00
}
2009-05-09 10:21:29 -07:00
case AF_INET6 :
{
uint16_t * address = ( uint16_t * ) & ( ( const struct sockaddr_in6 * ) addr ) - > sin6_addr . s6_addr ;
return snprintf ( buf , size ,
2009-07-26 05:34:26 -07:00
" %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx " ,
ntohs ( address [ 0 ] ) ,
ntohs ( address [ 1 ] ) ,
ntohs ( address [ 2 ] ) ,
ntohs ( address [ 3 ] ) ,
ntohs ( address [ 4 ] ) ,
ntohs ( address [ 5 ] ) ,
ntohs ( address [ 6 ] ) ,
ntohs ( address [ 7 ] ) ) ;
2009-05-09 10:21:29 -07:00
}
2009-05-03 08:52:37 -07:00
default :
2009-07-26 05:34:26 -07:00
ASSERT ( ! " Unknown address family " , " Got non IPv4 or IPv6 address! " ) ;
2009-05-03 08:52:37 -07:00
return - 1 ;
}
}
2009-05-03 08:35:50 -07:00
static const char * strSockError ( int error )
2009-05-03 08:16:49 -07:00
{
# if defined(WZ_OS_WIN)
switch ( error )
{
case 0 : return " No error " ;
case WSAEINTR : return " Interrupted system call " ;
case WSAEBADF : return " Bad file number " ;
case WSAEACCES : return " Permission denied " ;
case WSAEFAULT : return " Bad address " ;
case WSAEINVAL : return " Invalid argument " ;
case WSAEMFILE : return " Too many open sockets " ;
case WSAEWOULDBLOCK : return " Operation would block " ;
case WSAEINPROGRESS : return " Operation now in progress " ;
case WSAEALREADY : return " Operation already in progress " ;
case WSAENOTSOCK : return " Socket operation on non-socket " ;
case WSAEDESTADDRREQ : return " Destination address required " ;
case WSAEMSGSIZE : return " Message too long " ;
case WSAEPROTOTYPE : return " Protocol wrong type for socket " ;
case WSAENOPROTOOPT : return " Bad protocol option " ;
case WSAEPROTONOSUPPORT : return " Protocol not supported " ;
case WSAESOCKTNOSUPPORT : return " Socket type not supported " ;
case WSAEOPNOTSUPP : return " Operation not supported on socket " ;
case WSAEPFNOSUPPORT : return " Protocol family not supported " ;
case WSAEAFNOSUPPORT : return " Address family not supported " ;
case WSAEADDRINUSE : return " Address already in use " ;
case WSAEADDRNOTAVAIL : return " Can't assign requested address " ;
case WSAENETDOWN : return " Network is down " ;
case WSAENETUNREACH : return " Network is unreachable " ;
case WSAENETRESET : return " Net connection reset " ;
case WSAECONNABORTED : return " Software caused connection abort " ;
case WSAECONNRESET : return " Connection reset by peer " ;
case WSAENOBUFS : return " No buffer space available " ;
case WSAEISCONN : return " Socket is already connected " ;
case WSAENOTCONN : return " Socket is not connected " ;
case WSAESHUTDOWN : return " Can't send after socket shutdown " ;
case WSAETOOMANYREFS : return " Too many references, can't splice " ;
case WSAETIMEDOUT : return " Connection timed out " ;
case WSAECONNREFUSED : return " Connection refused " ;
case WSAELOOP : return " Too many levels of symbolic links " ;
case WSAENAMETOOLONG : return " File name too long " ;
case WSAEHOSTDOWN : return " Host is down " ;
case WSAEHOSTUNREACH : return " No route to host " ;
case WSAENOTEMPTY : return " Directory not empty " ;
case WSAEPROCLIM : return " Too many processes " ;
case WSAEUSERS : return " Too many users " ;
case WSAEDQUOT : return " Disc quota exceeded " ;
case WSAESTALE : return " Stale NFS file handle " ;
case WSAEREMOTE : return " Too many levels of remote in path " ;
case WSASYSNOTREADY : return " Network system is unavailable " ;
case WSAVERNOTSUPPORTED : return " Winsock version out of range " ;
case WSANOTINITIALISED : return " WSAStartup not yet called " ;
case WSAEDISCON : return " Graceful shutdown in progress " ;
case WSAHOST_NOT_FOUND : return " Host not found " ;
case WSANO_DATA : return " No host data of that type was found " ;
default : return " Unknown error " ;
}
# elif defined(WZ_OS_UNIX)
return strerror ( error ) ;
# endif
}
2009-05-03 08:35:50 -07:00
/**
* Similar to read ( 2 ) with the exception that this function won ' t be
* interrupted by signals ( EINTR ) .
*/
static ssize_t readNoInt ( Socket * sock , void * buf , size_t max_size )
2009-05-03 08:16:03 -07:00
{
ssize_t received ;
{
2009-05-09 10:20:32 -07:00
received = recv ( sock - > fd [ SOCK_CONNECTION ] , buf , max_size , 0 ) ;
2009-05-03 08:17:21 -07:00
} while ( received = = SOCKET_ERROR & & getSockErr ( ) = = EINTR ) ;
2009-05-03 08:16:03 -07:00
2009-05-03 08:16:19 -07:00
sock - > ready = false ;
2009-05-03 08:16:03 -07:00
return received ;
}
2009-05-03 08:35:50 -07:00
/**
* Similar to write ( 2 ) with the exception that this function will block until
* < em > all < / em > data has been written or an error occurs .
*
* @ return @ c size when succesful or @ c SOCKET_ERROR if an error occurred .
*/
static ssize_t writeAll ( Socket * sock , const void * buf , size_t size )
2009-05-03 08:16:03 -07:00
{
size_t written = 0 ;
while ( written < size )
{
2009-05-09 10:20:32 -07:00
ssize_t ret = send ( sock - > fd [ SOCK_CONNECTION ] , & ( ( char * ) buf ) [ written ] , size - written , 0 ) ;
2009-05-03 08:17:05 -07:00
if ( ret = = SOCKET_ERROR )
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:16:49 -07:00
switch ( getSockErr ( ) )
2009-05-03 08:16:03 -07:00
{
case EAGAIN :
case EINTR :
continue ;
default :
2009-05-03 08:17:05 -07:00
return SOCKET_ERROR ;
2009-05-03 08:16:03 -07:00
}
}
written + = ret ;
}
return written ;
}
static SocketSet * allocSocketSet ( size_t count )
{
SocketSet * const set = malloc ( sizeof ( * set ) + sizeof ( set - > fds [ 0 ] ) * count ) ;
if ( set = = NULL )
{
debug ( LOG_ERROR , " Out of memory! " ) ;
abort ( ) ;
return NULL ;
}
set - > len = count ;
set - > fds = ( Socket * * ) ( set + 1 ) ;
memset ( set - > fds , 0 , sizeof ( set - > fds [ 0 ] ) * count ) ;
return set ;
}
/**
* @ return true if @ c socket is succesfully added to @ set .
*/
static bool addSocket ( SocketSet * set , Socket * socket )
{
size_t i ;
ASSERT ( set ! = NULL , " NULL SocketSet provided " ) ;
ASSERT ( socket ! = NULL , " NULL Socket provided " ) ;
/* Check whether this socket is already present in this set (i.e. it
* shouldn ' t be added again ) .
*/
for ( i = 0 ; i < set - > len ; + + i )
{
if ( set - > fds [ i ] = = socket )
return true ;
}
for ( i = 0 ; i < set - > len ; + + i )
{
if ( set - > fds [ i ] = = NULL )
{
set - > fds [ i ] = socket ;
return true ;
}
}
2009-05-03 08:18:07 -07:00
debug ( LOG_ERROR , " Socket set full, no room left (max %zu) " , set - > len ) ;
2009-05-03 08:16:03 -07:00
return false ;
}
/**
* @ return true if @ c socket is succesfully added to @ set .
*/
static void delSocket ( SocketSet * set , Socket * socket )
{
size_t i ;
ASSERT ( set ! = NULL , " NULL SocketSet provided " ) ;
ASSERT ( socket ! = NULL , " NULL Socket provided " ) ;
for ( i = 0 ; i < set - > len ; + + i )
{
if ( set - > fds [ i ] = = socket )
{
set - > fds [ i ] = NULL ;
break ;
}
}
}
2009-05-03 08:16:49 -07:00
static bool setSocketBlocking ( const SOCKET fd , bool blocking )
{
# if defined(WZ_OS_UNIX)
int sockopts = fcntl ( fd , F_GETFL ) ;
2009-05-03 08:17:05 -07:00
if ( sockopts = = SOCKET_ERROR )
2009-05-03 08:16:49 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_NET , " Failed to retrieve current socket options: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-05-03 08:16:49 -07:00
return false ;
}
// Set or clear O_NONBLOCK flag
if ( blocking )
sockopts & = ~ O_NONBLOCK ;
else
sockopts | = O_NONBLOCK ;
2009-05-03 08:17:05 -07:00
if ( fcntl ( fd , F_SETFL , sockopts ) = = SOCKET_ERROR )
2009-05-03 08:16:49 -07:00
# elif defined(WZ_OS_WIN)
unsigned long nonblocking = ! blocking ;
if ( ioctlsocket ( fd , FIONBIO , & nonblocking ) = = SOCKET_ERROR )
2009-05-03 08:17:51 -07:00
# endif
2009-05-03 08:16:49 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_NET , " Failed to set socket %sblocking: %s " , ( blocking ? " " : " non- " ) , strSockError ( getSockErr ( ) ) ) ;
2009-05-03 08:16:49 -07:00
return false ;
}
return true ;
}
2009-05-03 08:16:03 -07:00
static int checkSockets ( const SocketSet * set , unsigned int timeout )
{
int ret ;
fd_set fds ;
2009-05-03 08:16:49 -07:00
size_t count = 0 , i ;
# if defined(WZ_OS_UNIX)
SOCKET maxfd = INT_MIN ;
# elif defined(WZ_OS_WIN)
SOCKET maxfd = 0 ;
# endif
2009-05-03 08:16:03 -07:00
for ( i = 0 ; i < set - > len ; + + i )
{
if ( set - > fds [ i ] )
{
2009-05-09 10:20:32 -07:00
ASSERT ( set - > fds [ i ] - > fd [ SOCK_CONNECTION ] ! = INVALID_SOCKET , " Invalid file descriptor! " ) ;
2009-05-03 08:16:03 -07:00
+ + count ;
2009-05-09 10:20:32 -07:00
maxfd = MAX ( maxfd , set - > fds [ i ] - > fd [ SOCK_CONNECTION ] ) ;
2009-05-03 08:16:03 -07:00
}
}
if ( ! count )
return 0 ;
{
struct timeval tv = { timeout / 1000 , ( timeout % 1000 ) * 1000 } ;
FD_ZERO ( & fds ) ;
for ( i = 0 ; i < set - > len ; + + i )
{
if ( set - > fds [ i ] )
2009-05-09 10:20:32 -07:00
FD_SET ( set - > fds [ i ] - > fd [ SOCK_CONNECTION ] , & fds ) ;
2009-05-03 08:16:03 -07:00
}
ret = select ( maxfd + 1 , & fds , NULL , NULL , & tv ) ;
2009-05-03 08:17:05 -07:00
} while ( ret = = SOCKET_ERROR & & getSockErr ( ) = = EINTR ) ;
2009-05-03 08:16:03 -07:00
2009-05-03 08:17:05 -07:00
if ( ret = = SOCKET_ERROR )
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " select failed: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-05-03 08:17:05 -07:00
return SOCKET_ERROR ;
2009-05-03 08:16:03 -07:00
}
for ( i = 0 ; i < set - > len ; + + i )
{
if ( set - > fds [ i ] )
{
2009-05-09 10:20:32 -07:00
set - > fds [ i ] - > ready = FD_ISSET ( set - > fds [ i ] - > fd [ SOCK_CONNECTION ] , & fds ) ;
2009-05-03 08:16:03 -07:00
}
}
return ret ;
}
2009-05-04 14:52:01 -07:00
/**
* Similar to read ( 2 ) with the exception that this function won ' t be
* interrupted by signals ( EINTR ) and will only return when < em > exactly < / em >
* @ c size bytes have been received . I . e . this function blocks until all data
* has been received or a timeout occurred .
*
* @ param timeout When non - zero this function times out after @ c timeout
* milliseconds . When zero this function blocks until success or
* an error occurs .
*
* @ c return @ c size when succesful , less than @ c size but at least zero ( 0 )
* when the other end disconnected or a timeout occurred . Or @ c SOCKET_ERROR if
* an error occurred .
*/
static ssize_t readAll ( Socket * sock , void * buf , size_t size , unsigned int timeout )
{
Socket * sockAr [ ] = { sock } ;
const SocketSet set = { ARRAY_SIZE ( sockAr ) , sockAr } ;
size_t received = 0 ;
while ( received < size )
{
ssize_t ret ;
// If a timeout is set, wait for that amount of time for data to arrive (or abort)
if ( timeout )
{
ret = checkSockets ( & set , timeout ) ;
if ( ret < set . len
| | ! sock - > ready )
{
if ( ret = = 0 )
setSockErr ( ETIMEDOUT ) ;
return SOCKET_ERROR ;
}
}
2009-05-09 10:20:32 -07:00
ret = recv ( sock - > fd [ SOCK_CONNECTION ] , & ( ( char * ) buf ) [ received ] , size - received , 0 ) ;
2009-05-04 14:52:01 -07:00
sock - > ready = false ;
if ( ret = = 0 )
{
debug ( LOG_NET , " Socket disconnected. " ) ;
2009-05-06 13:07:04 -07:00
setSockErr ( ECONNRESET ) ;
2009-05-04 14:52:01 -07:00
return received ;
}
if ( ret = = SOCKET_ERROR )
{
switch ( getSockErr ( ) )
{
case EINTR :
case EAGAIN :
continue ;
default :
return SOCKET_ERROR ;
}
}
received + = ret ;
}
return received ;
}
2009-05-03 08:35:50 -07:00
static void socketClose ( Socket * sock )
2009-05-03 08:21:44 -07:00
{
2009-05-09 10:20:32 -07:00
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( sock - > fd ) ; + + i )
2009-05-03 08:21:44 -07:00
{
2009-05-09 10:20:32 -07:00
if ( sock - > fd [ i ] ! = INVALID_SOCKET )
{
2009-05-03 08:21:44 -07:00
# if defined(WZ_OS_WIN)
2009-05-09 10:20:32 -07:00
closesocket ( sock - > fd [ i ] ) ;
2009-05-03 08:21:44 -07:00
# else
2009-05-09 10:20:32 -07:00
close ( sock - > fd [ i ] ) ;
2009-05-03 08:21:44 -07:00
# endif
2009-05-09 10:20:32 -07:00
}
2009-05-03 08:21:44 -07:00
}
free ( sock ) ;
}
2009-05-03 08:35:50 -07:00
static Socket * socketAccept ( Socket * sock )
2009-05-03 08:16:03 -07:00
{
2009-05-09 10:20:32 -07:00
unsigned int i ;
2009-05-03 08:49:56 -07:00
ASSERT ( sock ! = NULL , " NULL Socket provided " ) ;
2009-05-09 10:20:32 -07:00
/* Search for a socket that has a pending connection on it and accept
* the first one .
*/
for ( i = 0 ; i < ARRAY_SIZE ( sock - > fd ) ; + + i )
2009-05-03 08:49:56 -07:00
{
2009-05-09 10:20:32 -07:00
if ( sock - > fd [ i ] ! = INVALID_SOCKET )
2009-05-03 08:49:56 -07:00
{
2009-05-09 10:20:32 -07:00
char textAddress [ 40 ] ;
struct sockaddr_storage addr ;
socklen_t addr_len = sizeof ( addr ) ;
Socket * conn ;
unsigned int j ;
const SOCKET newConn = accept ( sock - > fd [ i ] , ( struct sockaddr * ) & addr , & addr_len ) ;
if ( newConn = = INVALID_SOCKET )
{
// Ignore the case where no connection is pending
if ( getSockErr ( ) ! = EAGAIN
& & getSockErr ( ) ! = EWOULDBLOCK )
{
debug ( LOG_ERROR , " accept failed: %s " , strSockError ( getSockErr ( ) ) ) ;
}
continue ;
}
2009-05-03 08:49:56 -07:00
2009-05-09 10:20:32 -07:00
conn = malloc ( sizeof ( * conn ) + addr_len ) ;
if ( conn = = NULL )
{
debug ( LOG_ERROR , " Out of memory! " ) ;
abort ( ) ;
return NULL ;
}
2009-05-03 08:49:56 -07:00
2009-05-09 10:20:32 -07:00
// Mark all unused socket handles as invalid
for ( j = 0 ; j < ARRAY_SIZE ( conn - > fd ) ; + + j )
{
conn - > fd [ j ] = INVALID_SOCKET ;
}
2009-05-03 08:16:03 -07:00
2009-05-09 10:20:32 -07:00
conn - > ready = false ;
conn - > fd [ SOCK_CONNECTION ] = newConn ;
2009-05-03 08:16:03 -07:00
2009-05-09 10:20:32 -07:00
sock - > ready = false ;
2009-05-03 08:22:00 -07:00
2009-05-09 10:20:32 -07:00
addressToText ( ( const struct sockaddr * ) & addr , textAddress , sizeof ( textAddress ) ) ;
debug ( LOG_NET , " Incoming connection from [%s]:%d " , textAddress , ( unsigned int ) ntohs ( ( ( const struct sockaddr_in * ) & addr ) - > sin_port ) ) ;
2009-05-03 08:57:30 -07:00
2009-05-09 10:20:32 -07:00
return conn ;
}
}
return NULL ;
2009-05-03 08:16:03 -07:00
}
static Socket * SocketOpen ( const struct addrinfo * addr , unsigned int timeout )
{
2009-05-03 08:52:37 -07:00
char textAddress [ 40 ] ;
2009-05-09 10:20:32 -07:00
unsigned int i ;
2009-05-03 08:16:03 -07:00
int ret ;
Socket * const conn = malloc ( sizeof ( * conn ) ) ;
if ( conn = = NULL )
{
debug ( LOG_ERROR , " Out of memory! " ) ;
abort ( ) ;
return NULL ;
}
ASSERT ( addr ! = NULL , " NULL Socket provided " ) ;
2009-05-03 08:52:37 -07:00
addressToText ( addr - > ai_addr , textAddress , sizeof ( textAddress ) ) ;
2009-05-09 10:20:32 -07:00
debug ( LOG_NET , " Connecting to [%s]:%d " , textAddress , ( int ) ntohs ( ( ( const struct sockaddr_in * ) addr - > ai_addr ) - > sin_port ) ) ;
// Mark all unused socket handles as invalid
for ( i = 0 ; i < ARRAY_SIZE ( conn - > fd ) ; + + i )
{
conn - > fd [ i ] = INVALID_SOCKET ;
}
2009-05-03 08:16:03 -07:00
conn - > ready = false ;
2009-05-09 10:20:32 -07:00
conn - > fd [ SOCK_CONNECTION ] = socket ( addr - > ai_family , addr - > ai_socktype , addr - > ai_protocol ) ;
2009-05-03 08:16:03 -07:00
2009-05-09 10:20:32 -07:00
if ( conn - > fd [ SOCK_CONNECTION ] = = INVALID_SOCKET )
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to create a socket: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
2009-05-09 10:20:32 -07:00
if ( ! setSocketBlocking ( conn - > fd [ SOCK_CONNECTION ] , false ) )
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:35:50 -07:00
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
2009-05-09 10:20:32 -07:00
ret = connect ( conn - > fd [ SOCK_CONNECTION ] , addr - > ai_addr , addr - > ai_addrlen ) ;
2009-05-03 08:17:05 -07:00
if ( ret = = SOCKET_ERROR )
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:16:49 -07:00
fd_set conReady ;
# if defined(WZ_OS_WIN)
fd_set conFailed ;
# endif
2009-05-03 08:16:03 -07:00
2009-05-03 08:16:49 -07:00
if ( ( getSockErr ( ) ! = EINPROGRESS
2009-05-03 08:38:16 -07:00
& & getSockErr ( ) ! = EAGAIN
2009-05-03 08:16:49 -07:00
& & getSockErr ( ) ! = EWOULDBLOCK )
# if defined(WZ_OS_UNIX)
2009-05-09 10:20:32 -07:00
| | conn - > fd [ SOCK_CONNECTION ] > = FD_SETSIZE
2009-05-03 08:16:49 -07:00
# endif
| | timeout = = 0 )
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_NET , " Failed to start connecting: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
{
struct timeval tv = { timeout / 1000 , ( timeout % 1000 ) * 1000 } ;
2009-05-03 08:16:49 -07:00
FD_ZERO ( & conReady ) ;
2009-05-09 10:20:32 -07:00
FD_SET ( conn - > fd [ SOCK_CONNECTION ] , & conReady ) ;
2009-05-03 08:16:49 -07:00
# if defined(WZ_OS_WIN)
FD_ZERO ( & conFailed ) ;
2009-05-09 10:20:32 -07:00
FD_SET ( conn - > fd [ SOCK_CONNECTION ] , & conFailed ) ;
2009-05-03 08:16:49 -07:00
# endif
2009-05-03 08:16:03 -07:00
2009-05-03 08:16:49 -07:00
# if defined(WZ_OS_WIN)
2009-05-09 10:20:32 -07:00
ret = select ( conn - > fd [ SOCK_CONNECTION ] + 1 , NULL , & conReady , & conFailed , & tv ) ;
2009-05-03 08:16:49 -07:00
# else
2009-05-09 10:20:32 -07:00
ret = select ( conn - > fd [ SOCK_CONNECTION ] + 1 , NULL , & conReady , NULL , & tv ) ;
2009-05-03 08:16:49 -07:00
# endif
2009-05-03 08:17:05 -07:00
} while ( ret = = SOCKET_ERROR & & getSockErr ( ) = = EINTR ) ;
2009-05-03 08:16:03 -07:00
2009-05-03 08:17:05 -07:00
if ( ret = = SOCKET_ERROR )
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_NET , " Failed to wait for connection: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
if ( ret = = 0 )
{
2009-05-03 08:16:49 -07:00
setSockErr ( ETIMEDOUT ) ;
2009-05-03 08:35:50 -07:00
debug ( LOG_NET , " Timed out while waiting for connection to be established: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
2009-05-03 08:16:49 -07:00
# if defined(WZ_OS_WIN)
2009-05-09 10:20:32 -07:00
ASSERT ( FD_ISSET ( conn - > fd [ SOCK_CONNECTION ] , & conReady ) | | FD_ISSET ( conn - > fd [ SOCK_CONNECTION ] , & conFailed ) , " \" sock \" is the only file descriptor in set, it should be the one that is set. " ) ;
2009-05-03 11:44:57 -07:00
# else
2009-05-09 10:20:32 -07:00
ASSERT ( FD_ISSET ( conn - > fd [ SOCK_CONNECTION ] , & conReady ) , " \" sock \" is the only file descriptor in set, it should be the one that is set. " ) ;
2009-05-03 08:16:49 -07:00
# endif
2009-05-03 08:16:03 -07:00
2009-05-03 08:16:49 -07:00
# if defined(WZ_OS_WIN)
2009-05-09 10:20:32 -07:00
if ( FD_ISSET ( conn - > fd [ SOCK_CONNECTION ] , & conFailed ) )
2009-05-03 08:16:49 -07:00
# elif defined(WZ_OS_UNIX)
2009-05-09 10:20:32 -07:00
if ( connect ( conn - > fd [ SOCK_CONNECTION ] , addr - > ai_addr , addr - > ai_addrlen ) = = SOCKET_ERROR
2009-05-03 08:16:49 -07:00
& & getSockErr ( ) ! = EISCONN )
# endif
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_NET , " Failed to connect: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
}
2009-05-09 10:20:32 -07:00
if ( ! setSocketBlocking ( conn - > fd [ SOCK_CONNECTION ] , true ) )
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:35:50 -07:00
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
return conn ;
}
2009-05-03 08:35:50 -07:00
static Socket * socketListen ( unsigned int port )
2009-05-03 08:16:03 -07:00
{
2009-05-24 15:01:08 -07:00
/* Enable the V4 to V6 mapping, but only when available, because it
* isn ' t available on all platforms .
2009-05-09 10:20:32 -07:00
*/
2009-05-24 15:01:08 -07:00
static const int ipv6_v6only = 0 ;
2009-05-09 10:20:32 -07:00
struct sockaddr_in addr4 ;
struct sockaddr_in6 addr6 ;
unsigned int i ;
2009-05-03 08:16:03 -07:00
Socket * const conn = malloc ( sizeof ( * conn ) ) ;
if ( conn = = NULL )
{
debug ( LOG_ERROR , " Out of memory! " ) ;
abort ( ) ;
return NULL ;
}
2009-05-09 10:20:32 -07:00
// Mark all unused socket handles as invalid
for ( i = 0 ; i < ARRAY_SIZE ( conn - > fd ) ; + + i )
{
conn - > fd [ i ] = INVALID_SOCKET ;
}
// Listen on all local IPv4 and IPv6 addresses for the given port
addr4 . sin_family = AF_INET ;
addr4 . sin_port = htons ( port ) ;
addr4 . sin_addr . s_addr = INADDR_ANY ;
addr6 . sin6_family = AF_INET6 ;
addr6 . sin6_port = htons ( port ) ;
addr6 . sin6_addr = in6addr_any ;
addr6 . sin6_flowinfo = 0 ;
addr6 . sin6_scope_id = 0 ;
2009-05-03 08:16:03 -07:00
conn - > ready = false ;
2009-05-09 10:20:32 -07:00
conn - > fd [ SOCK_IPV4_LISTEN ] = socket ( addr4 . sin_family , SOCK_STREAM , 0 ) ;
conn - > fd [ SOCK_IPV6_LISTEN ] = socket ( addr6 . sin6_family , SOCK_STREAM , 0 ) ;
2009-05-03 08:16:03 -07:00
2009-05-09 10:20:32 -07:00
if ( conn - > fd [ SOCK_IPV4_LISTEN ] = = INVALID_SOCKET
2009-05-24 15:01:08 -07:00
& & conn - > fd [ SOCK_IPV6_LISTEN ] = = INVALID_SOCKET )
2009-05-03 08:16:03 -07:00
{
2009-05-24 15:01:08 -07:00
debug ( LOG_ERROR , " Failed to create an IPv4 and IPv6 (only supported address families) socket: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-05-03 08:35:50 -07:00
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
2009-05-25 02:21:06 -07:00
if ( conn - > fd [ SOCK_IPV4_LISTEN ] ! = INVALID_SOCKET )
2009-05-09 10:20:32 -07:00
{
2009-05-25 02:21:06 -07:00
debug ( LOG_NET , " Succesfully created an IPv4 socket " ) ;
2009-05-24 15:01:08 -07:00
}
2009-05-25 02:21:06 -07:00
if ( conn - > fd [ SOCK_IPV6_LISTEN ] ! = INVALID_SOCKET )
2009-05-24 15:01:08 -07:00
{
2009-05-25 02:21:06 -07:00
debug ( LOG_NET , " Succesfully created an IPv6 socket " ) ;
}
# if defined(IPV6_V6ONLY)
if ( conn - > fd [ SOCK_IPV6_LISTEN ] ! = INVALID_SOCKET )
{
if ( setsockopt ( conn - > fd [ SOCK_IPV6_LISTEN ] , IPPROTO_IPV6 , IPV6_V6ONLY , & ipv6_v6only , sizeof ( ipv6_v6only ) ) = = SOCKET_ERROR )
{
debug ( LOG_WARNING , " Failed to set IPv6 socket to perform IPv4 to IPv6 mapping. Falling back to using two sockets. Error: %s " , strSockError ( getSockErr ( ) ) ) ;
}
else
{
debug ( LOG_NET , " Succesfully enabled IPv4 to IPv6 mapping. Cleaning up IPv4 socket. " ) ;
2009-05-24 15:01:08 -07:00
# if defined(WZ_OS_WIN)
2009-05-25 02:21:06 -07:00
closesocket ( conn - > fd [ SOCK_IPV4_LISTEN ] ) ;
2009-05-24 15:01:08 -07:00
# else
2009-05-25 02:21:06 -07:00
close ( conn - > fd [ SOCK_IPV4_LISTEN ] ) ;
2009-05-24 15:01:08 -07:00
# endif
2009-05-25 02:21:06 -07:00
conn - > fd [ SOCK_IPV4_LISTEN ] = INVALID_SOCKET ;
}
}
2009-06-03 14:24:33 -07:00
# endif
2009-05-09 10:20:32 -07:00
2009-05-24 15:01:08 -07:00
if ( conn - > fd [ SOCK_IPV4_LISTEN ] ! = INVALID_SOCKET )
{
if ( bind ( conn - > fd [ SOCK_IPV4_LISTEN ] , ( const struct sockaddr * ) & addr4 , sizeof ( addr4 ) ) = = SOCKET_ERROR
| | listen ( conn - > fd [ SOCK_IPV4_LISTEN ] , 5 ) = = SOCKET_ERROR
| | ! setSocketBlocking ( conn - > fd [ SOCK_IPV4_LISTEN ] , false ) )
{
debug ( LOG_ERROR , " Failed to set up IPv4 socket for listening on port %u: %s " , port , strSockError ( getSockErr ( ) ) ) ;
2009-05-25 02:21:06 -07:00
# if defined(WZ_OS_WIN)
closesocket ( conn - > fd [ SOCK_IPV4_LISTEN ] ) ;
# else
close ( conn - > fd [ SOCK_IPV4_LISTEN ] ) ;
# endif
conn - > fd [ SOCK_IPV4_LISTEN ] = INVALID_SOCKET ;
2009-05-24 15:01:08 -07:00
}
}
if ( conn - > fd [ SOCK_IPV6_LISTEN ] ! = INVALID_SOCKET )
{
if ( bind ( conn - > fd [ SOCK_IPV6_LISTEN ] , ( const struct sockaddr * ) & addr6 , sizeof ( addr6 ) ) = = SOCKET_ERROR
| | listen ( conn - > fd [ SOCK_IPV6_LISTEN ] , 5 ) = = SOCKET_ERROR
| | ! setSocketBlocking ( conn - > fd [ SOCK_IPV6_LISTEN ] , false ) )
{
debug ( LOG_ERROR , " Failed to set up IPv6 socket for listening on port %u: %s " , port , strSockError ( getSockErr ( ) ) ) ;
2009-05-25 02:21:06 -07:00
# if defined(WZ_OS_WIN)
closesocket ( conn - > fd [ SOCK_IPV6_LISTEN ] ) ;
# else
close ( conn - > fd [ SOCK_IPV6_LISTEN ] ) ;
# endif
conn - > fd [ SOCK_IPV6_LISTEN ] = INVALID_SOCKET ;
2009-05-24 15:01:08 -07:00
}
}
// Check whether we still have at least a single (operating) socket.
if ( conn - > fd [ SOCK_IPV4_LISTEN ] = = INVALID_SOCKET
& & conn - > fd [ SOCK_IPV6_LISTEN ] = = INVALID_SOCKET )
2009-05-03 08:16:03 -07:00
{
2009-05-03 08:35:50 -07:00
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
return conn ;
}
static struct addrinfo * resolveHost ( const char * host , unsigned int port )
{
struct addrinfo * results ;
char * service ;
struct addrinfo hint ;
int error ;
2009-05-09 10:21:29 -07:00
hint . ai_family = AF_UNSPEC ;
2009-05-03 08:16:49 -07:00
hint . ai_socktype = SOCK_STREAM ;
hint . ai_protocol = 0 ;
hint . ai_flags = ( AI_V4MAPPED | AI_ADDRCONFIG ) ;
hint . ai_addrlen = 0 ;
hint . ai_addr = NULL ;
hint . ai_canonname = NULL ;
hint . ai_next = NULL ;
2009-05-03 08:16:03 -07:00
sasprintf ( & service , " %u " , port ) ;
error = getaddrinfo ( host , service , & hint , & results ) ;
if ( error ! = 0 )
{
debug ( LOG_NET , " getaddrinfo failed for %s:%s: %s " , host , service , gai_strerror ( error ) ) ;
return NULL ;
}
return results ;
}
2009-04-10 21:41:14 -07:00
void sendVersionCheck ( void )
{
NETlogEntry ( " Sending version check " , 0 , 0 ) ;
NETbeginEncode ( NET_VERSION_CHECK , NET_ALL_PLAYERS ) ;
2009-06-07 11:10:13 -07:00
NETuint32_t ( & selectedPlayer ) ;
NETstring ( VersionString , sizeof ( VersionString ) ) ;
NETint32_t ( & NETCODE_VERSION_MAJOR ) ;
NETint32_t ( & NETCODE_VERSION_MINOR ) ;
NETint32_t ( & NUMBER_OF_MODS ) ;
NETint32_t ( & NETCODE_HASH ) ;
2009-04-10 21:41:14 -07:00
NETend ( ) ;
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " sending player %u, version string [%s] " , selectedPlayer , VersionString ) ;
2009-04-10 21:41:14 -07:00
}
2009-06-07 11:10:13 -07:00
2009-04-10 21:41:14 -07:00
// Checks the version string, and if they are not the same, we auto-kick the player.
2009-06-07 11:10:13 -07:00
static void recvVersionCheck ( )
2009-04-10 21:41:14 -07:00
{
2009-06-07 11:10:13 -07:00
uint32_t victim = 0 ;
2009-04-19 11:45:28 -07:00
char playersVersion [ VersionStringSize ] = { ' \0 ' } ;
2009-04-10 21:41:14 -07:00
const char * msg ;
int32_t MajorVersion = 0 ; // Not currently used
int32_t MinorVersion = 0 ; // Not currently used
int32_t ModCount = 0 ; // Not currently used
int32_t Hash_Data = 0 ; // Not currently used
NETlogEntry ( " Receiving version check " , 0 , 0 ) ;
NETbeginDecode ( NET_VERSION_CHECK ) ;
2009-06-07 11:10:13 -07:00
NETuint32_t ( & victim ) ;
NETstring ( playersVersion , sizeof ( playersVersion ) ) ;
NETint32_t ( & MajorVersion ) ; // NETCODE_VERSION_MAJOR
NETint32_t ( & MinorVersion ) ; // NETCODE_VERSION_MINOR
NETint32_t ( & ModCount ) ; // NUMBER_OF_MODS
NETint32_t ( & Hash_Data ) ; // NETCODE_HASH
2009-04-10 21:41:14 -07:00
NETend ( ) ;
2009-06-07 11:10:13 -07:00
if ( strcmp ( VersionString , playersVersion ) ! = 0 )
2009-04-10 21:41:14 -07:00
{
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Received *wrong* version string [%s] from player %u. Expected [%s] " , playersVersion , victim , VersionString ) ;
2009-04-10 21:41:14 -07:00
2009-06-07 11:10:13 -07:00
sasprintf ( ( char * * ) & msg , _ ( " Player %u has the wrong game version. Auto kicking. " ) , victim ) ;
2009-04-10 21:41:14 -07:00
sendTextMessage ( msg , true ) ;
2009-11-20 15:33:08 -08:00
sasprintf ( ( char * * ) & msg , " you have the wrong version; update it! (You have [%s], we expect [%s].) " , playersVersion , VersionString ) ;
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2009-04-10 21:41:14 -07:00
{
2009-11-20 15:33:08 -08:00
kickPlayer ( victim , msg , ERROR_WRONGVERSION ) ;
2009-04-10 21:41:14 -07:00
// reset flags /time after we kick them
2009-06-07 11:10:13 -07:00
NetPlay . players [ victim ] . versionCheckTime = - 1 ;
NetPlay . players [ victim ] . playerVersionFlag = false ;
2009-04-10 21:41:14 -07:00
}
}
else
{
2009-06-07 11:10:13 -07:00
NetPlay . players [ victim ] . playerVersionFlag = true ;
debug ( LOG_NET , " Received correct version string [%s] from player %u " , playersVersion , victim ) ;
2009-04-10 21:41:14 -07:00
}
2009-04-19 11:45:28 -07:00
// just in case someone has the bright idea of trying to fool us...
2009-06-07 11:10:13 -07:00
if ( NetPlay . GamePassworded & & playerVersionFlag [ victim ] & & ! playerPasswordFlag [ victim ] )
2009-04-19 11:45:28 -07:00
{
// really should ban them. :P
2009-06-07 11:10:13 -07:00
debug ( LOG_ERROR , " Received correct version string [%s] from player %u " , playersVersion , victim ) ;
2009-04-19 11:45:28 -07:00
debug ( LOG_ERROR , " Did NOT receive passowrd from them --Autokicking ip %s " , " 123 " ) ;
2009-06-07 11:10:13 -07:00
kickPlayer ( victim , " you have attempted to thwart the security measuers. Entry denied! " , ERROR_CHEAT ) ;
2009-04-19 11:45:28 -07:00
}
2009-04-10 21:41:14 -07:00
}
2009-06-07 11:10:13 -07:00
static void VersionCheckTimeOut ( uint32_t victim )
2009-04-10 21:41:14 -07:00
{
const char * msg ;
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " version string was never received from player %u. Auto kicking at %u " , victim , gameTime2 ) ;
2009-04-10 21:41:14 -07:00
2009-06-07 11:10:13 -07:00
sasprintf ( ( char * * ) & msg , _ ( " Player %u has the wrong game version. Auto kicking. " ) , victim ) ;
2009-04-10 21:41:14 -07:00
sendTextMessage ( msg , true ) ;
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2009-04-10 21:41:14 -07:00
{
2009-11-20 15:33:08 -08:00
kickPlayer ( victim , " you have the wrong version; update it! (Version string never received.) " , ERROR_WRONGVERSION ) ;
2009-04-10 21:41:14 -07:00
// reset flags /time after we kick them
2009-06-07 11:10:13 -07:00
NetPlay . players [ victim ] . versionCheckTime = - 1 ;
NetPlay . players [ victim ] . playerVersionFlag = false ;
2009-04-10 21:41:14 -07:00
}
}
2009-06-07 11:10:13 -07:00
void NETCheckVersion ( uint32_t player )
2009-04-10 21:41:14 -07:00
{
// When flag is true, means we have received the check OK
2009-06-07 11:10:13 -07:00
if ( NetPlay . players [ player ] . playerVersionFlag = = false )
2009-04-10 21:41:14 -07:00
{
2009-06-07 11:10:13 -07:00
if ( player ! = NET_HOST_ONLY )
2009-04-10 21:41:14 -07:00
{
2009-06-07 11:10:13 -07:00
VersionCheckTimeOut ( player ) ;
2009-04-10 21:41:14 -07:00
}
}
}
2009-04-19 11:45:28 -07:00
// Sets if the game is password protected or not
void NETGameLocked ( bool flag )
{
NetPlay . GamePassworded = flag ;
game . privateGame = flag ;
debug ( LOG_NET , " Passworded game is %s " , NetPlay . GamePassworded ? " TRUE " : " FALSE " ) ;
}
// Sets the game password
void NETsetGamePassword ( const char * password )
{
sstrcpy ( NetPlay . gamePassword , password ) ;
debug ( LOG_NET , " Password entered is: [%s] " , NetPlay . gamePassword ) ;
}
// Resets the game password
void NETresetGamePassword ( void )
{
sstrcpy ( NetPlay . gamePassword , " Enter Password Here " ) ;
debug ( LOG_NET , " password reset to 'Enter Password here' " ) ;
NETGameLocked ( false ) ;
}
// send our password to host
void sendPasswordCheck ( void )
{
2009-06-07 11:10:13 -07:00
uint32_t player = selectedPlayer ;
2009-04-19 11:45:28 -07:00
NETlogEntry ( " Sending password check " , 0 , 0 ) ;
2009-06-07 11:10:13 -07:00
NETbeginEncode ( NET_PASSWORD_CHECK , NET_HOST_ONLY ) ;
NETuint32_t ( & player ) ;
2009-04-19 11:45:28 -07:00
NETstring ( NetPlay . gamePassword , sizeof ( NetPlay . gamePassword ) ) ;
NETend ( ) ;
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " sending player %u, password [%s] " , player , NetPlay . gamePassword ) ;
2009-04-19 11:45:28 -07:00
}
// Checks the password, and if they are not the same, we auto-kick the player.
void recvPasswordCheck ( void )
{
2009-06-07 11:10:13 -07:00
uint32_t victim = 0 ;
2009-04-19 11:45:28 -07:00
char passwordreceived [ StringSize ] ;
const char * msg ;
NETlogEntry ( " Receiving password check " , 0 , 0 ) ;
NETbeginDecode ( NET_PASSWORD_CHECK ) ;
2009-06-07 11:10:13 -07:00
NETuint32_t ( & victim ) ;
2009-04-19 11:45:28 -07:00
NETstring ( passwordreceived , sizeof ( passwordreceived ) ) ;
NETend ( ) ;
if ( strcmp ( NetPlay . gamePassword , passwordreceived ) ! = 0 )
{
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Received *wrong* password [%s] from player %u. Expected [%s] " , passwordreceived , victim , NetPlay . gamePassword ) ;
2009-04-19 11:45:28 -07:00
2009-06-07 11:10:13 -07:00
sasprintf ( ( char * * ) & msg , _ ( " Player %u has the wrong password. Auto kicking. " ) , victim ) ;
2009-04-19 11:45:28 -07:00
sendTextMessage ( msg , true ) ;
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2009-04-19 11:45:28 -07:00
{
2009-06-07 11:10:13 -07:00
kickPlayer ( victim , " you have the wrong password! Entry denied! " , ERROR_WRONGPASSWORD ) ;
playerPasswordFlag [ victim ] = false ;
2009-04-19 11:45:28 -07:00
}
}
else
{
2009-06-07 11:10:13 -07:00
playerPasswordFlag [ victim ] = true ;
debug ( LOG_NET , " Received correct password [%s] from player %u " , passwordreceived , victim ) ;
2009-04-19 11:45:28 -07:00
}
}
2007-07-25 08:31:27 -07:00
// *********** Socket with buffer that read NETMSGs ******************
2007-07-15 06:48:22 -07:00
static NETBUFSOCKET * NET_createBufferedSocket ( void )
{
2008-05-02 14:19:15 -07:00
NETBUFSOCKET * bs = ( NETBUFSOCKET * ) malloc ( sizeof ( * bs ) ) ;
2007-06-28 10:47:08 -07:00
bs - > socket = NULL ;
bs - > buffer = NULL ;
bs - > buffer_start = 0 ;
bs - > bytes = 0 ;
return bs ;
}
2007-07-15 06:48:22 -07:00
static void NET_destroyBufferedSocket ( NETBUFSOCKET * bs )
{
2007-06-28 10:47:08 -07:00
free ( bs - > buffer ) ;
free ( bs ) ;
}
2009-05-03 08:16:03 -07:00
static void NET_initBufferedSocket ( NETBUFSOCKET * bs , Socket * s )
2007-07-15 06:48:22 -07:00
{
2007-06-28 10:47:08 -07:00
bs - > socket = s ;
if ( bs - > buffer = = NULL ) {
bs - > buffer = ( char * ) malloc ( NET_BUFFER_SIZE ) ;
}
bs - > buffer_start = 0 ;
bs - > bytes = 0 ;
}
2009-05-03 08:16:03 -07:00
static BOOL NET_fillBuffer ( NETBUFSOCKET * bs , SocketSet * socket_set )
2007-06-28 10:47:08 -07:00
{
int size ;
char * bufstart = bs - > buffer + bs - > buffer_start + bs - > bytes ;
const int bufsize = NET_BUFFER_SIZE - bs - > buffer_start - bs - > bytes ;
2009-05-03 08:16:03 -07:00
if ( bs - > buffer_start ! = 0
| | ! bs - > socket - > ready )
2007-07-25 08:31:27 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2009-05-03 08:35:50 -07:00
size = readNoInt ( bs - > socket , bufstart , bufsize ) ;
2007-06-28 10:47:08 -07:00
2007-07-25 08:31:27 -07:00
if ( size > 0 )
{
2007-06-28 10:47:08 -07:00
bs - > bytes + = size ;
2008-03-24 09:51:17 -07:00
return true ;
2009-02-21 14:09:58 -08:00
}
else
{ // an error occured, or the remote host has closed the connection.
2007-07-25 08:31:27 -07:00
if ( socket_set ! = NULL )
{
2009-05-03 08:16:03 -07:00
delSocket ( socket_set , bs - > socket ) ;
2007-06-28 10:47:08 -07:00
}
2009-03-20 12:28:04 -07:00
ASSERT ( bs - > bytes < NET_BUFFER_SIZE , " Socket buffer is too small! " ) ;
if ( bs - > bytes > NET_BUFFER_SIZE )
{
debug ( LOG_ERROR , " Fatal connection error: buffer size of (%d) was too small, current byte count was %d " , NET_BUFFER_SIZE , bs - > bytes ) ;
}
2009-05-03 08:35:50 -07:00
debug ( LOG_WARNING , " SDLNet_TCP_Recv error: %s tcp_socket %p is now invalid " , strSockError ( getSockErr ( ) ) , bs - > socket ) ;
socketClose ( bs - > socket ) ;
2007-06-28 10:47:08 -07:00
bs - > socket = NULL ;
}
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 09:51:17 -07:00
// Check if we have a full message waiting for us. If not, return false and wait for more data.
2007-07-25 08:31:27 -07:00
// If there is a data remnant somewhere in the buffer except at its beginning, move it to the
// beginning.
2008-02-16 05:39:23 -08:00
static BOOL NET_recvMessage ( NETBUFSOCKET * bs )
2007-06-28 10:47:08 -07:00
{
2008-02-16 05:39:23 -08:00
NETMSG * pMsg = & NetMsg ;
2007-06-28 10:47:08 -07:00
unsigned int size ;
const NETMSG * message = ( NETMSG * ) ( bs - > buffer + bs - > buffer_start ) ;
const unsigned int headersize = sizeof ( message - > size )
+ sizeof ( message - > type )
2008-01-02 09:08:29 -08:00
+ sizeof ( message - > destination )
+ sizeof ( message - > source ) ;
2007-06-28 10:47:08 -07:00
2007-07-25 08:31:27 -07:00
if ( headersize > bs - > bytes )
{
2007-06-28 10:47:08 -07:00
goto error ;
}
2009-05-03 08:16:03 -07:00
size = ntohs ( message - > size ) + headersize ;
2007-06-28 10:47:08 -07:00
2007-07-25 08:31:27 -07:00
if ( size > bs - > bytes )
{
2007-06-28 10:47:08 -07:00
goto error ;
}
memcpy ( pMsg , message , size ) ;
2009-05-03 08:16:03 -07:00
pMsg - > size = ntohs ( message - > size ) ;
2007-06-28 10:47:08 -07:00
bs - > buffer_start + = size ;
bs - > bytes - = size ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
error :
2007-08-08 11:50:28 -07:00
if ( bs - > buffer_start ! = 0 )
2007-07-24 11:59:57 -07:00
{
2007-06-28 10:47:08 -07:00
static char * tmp_buffer = NULL ;
char * buffer_start = bs - > buffer + bs - > buffer_start ;
char * tmp ;
// Create tmp buffer if necessary
2007-08-08 11:50:28 -07:00
if ( tmp_buffer = = NULL )
2007-07-24 11:59:57 -07:00
{
2007-06-28 10:47:08 -07:00
tmp_buffer = ( char * ) malloc ( NET_BUFFER_SIZE ) ;
}
// Move remaining contents into tmp buffer
memcpy ( tmp_buffer , buffer_start , bs - > bytes ) ;
// swap tmp buffer with buffer
tmp = bs - > buffer ;
bs - > buffer = tmp_buffer ;
tmp_buffer = tmp ;
2009-02-21 14:09:58 -08:00
if ( tmp_buffer )
{
free ( tmp_buffer ) ;
tmp_buffer = NULL ;
}
2007-06-28 10:47:08 -07:00
// Now data is in the beginning of the buffer
bs - > buffer_start = 0 ;
}
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2009-06-07 11:10:13 -07:00
void NET_InitPlayers ( )
2007-07-15 06:48:22 -07:00
{
2007-06-28 10:47:08 -07:00
unsigned int i ;
2007-07-25 08:31:27 -07:00
for ( i = 0 ; i < MAX_CONNECTED_PLAYERS ; + + i )
{
2009-06-07 11:10:13 -07:00
NetPlay . players [ i ] . allocated = false ;
NetPlay . players [ i ] . heartattacktime = 0 ;
NetPlay . players [ i ] . heartbeat = true ; // we always start with a hearbeat
NetPlay . players [ i ] . kick = false ;
NetPlay . players [ i ] . name [ 0 ] = ' \0 ' ;
NetPlay . players [ i ] . colour = i ;
NetPlay . players [ i ] . position = i ;
NetPlay . players [ i ] . team = i ;
NetPlay . players [ i ] . ready = false ;
NetPlay . players [ i ] . versionCheckTime = 0xffffffff ;
NetPlay . players [ i ] . playerVersionFlag = false ;
2007-06-28 10:47:08 -07:00
}
2009-06-07 11:10:13 -07:00
NetPlay . hostPlayer = NET_HOST_ONLY ; // right now, host starts always at index zero
NetPlay . playercount = 0 ;
debug ( LOG_NET , " Players initialized " ) ;
2007-06-28 10:47:08 -07:00
}
2009-06-07 11:10:13 -07:00
void NETBroadcastPlayerInfo ( uint32_t index )
2007-07-15 06:48:22 -07:00
{
2008-02-16 05:53:17 -08:00
NETbeginEncode ( NET_PLAYER_INFO , NET_ALL_PLAYERS ) ;
2009-06-07 11:10:13 -07:00
NETuint32_t ( & index ) ;
NETbool ( & NetPlay . players [ index ] . allocated ) ;
NETbool ( & NetPlay . players [ index ] . heartbeat ) ;
NETbool ( & NetPlay . players [ index ] . kick ) ;
NETstring ( NetPlay . players [ index ] . name , sizeof ( NetPlay . players [ index ] . name ) ) ;
NETuint32_t ( & NetPlay . players [ index ] . heartattacktime ) ;
NETint32_t ( & NetPlay . players [ index ] . colour ) ;
NETint32_t ( & NetPlay . players [ index ] . team ) ;
NETbool ( & NetPlay . players [ index ] . ready ) ;
NETuint32_t ( & NetPlay . hostPlayer ) ;
2008-02-16 05:53:17 -08:00
NETend ( ) ;
2007-06-28 10:47:08 -07:00
}
2009-06-07 11:10:13 -07:00
static unsigned int NET_CreatePlayer ( const char * name )
2007-07-15 06:48:22 -07:00
{
2009-06-07 11:10:13 -07:00
unsigned int index ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
for ( index = 0 ; index < MAX_CONNECTED_PLAYERS ; index + + )
2007-07-24 11:59:57 -07:00
{
2009-06-07 11:10:13 -07:00
if ( NetPlay . players [ index ] . allocated = = false )
2007-07-24 11:59:57 -07:00
{
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " A new player has been created. Player, %s, is set to slot %u " , name , index ) ;
NetPlay . players [ index ] . allocated = true ;
sstrcpy ( NetPlay . players [ index ] . name , name ) ;
NETBroadcastPlayerInfo ( index ) ;
NetPlay . playercount + + ;
return index ;
2007-06-28 10:47:08 -07:00
}
}
2009-06-07 11:10:13 -07:00
debug ( LOG_ERROR , " Could not find place for player %s " , name ) ;
2007-06-28 10:47:08 -07:00
return 0 ;
}
2009-06-07 11:10:13 -07:00
static void NET_DestroyPlayer ( unsigned int index )
2007-07-15 06:48:22 -07:00
{
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Freeing slot %u for a new player " , index ) ;
2009-07-16 17:13:31 -07:00
if ( NetPlay . players [ index ] . allocated )
{
NetPlay . players [ index ] . allocated = false ;
NetPlay . playercount - - ;
}
2007-06-28 10:47:08 -07:00
}
2009-02-21 14:09:58 -08:00
/**
* @ note When a player leaves nicely ( ie , we got a NET_PLAYER_LEAVING
* message ) , we clean up the socket that we used .
2009-06-07 11:10:13 -07:00
* \ param index
2009-02-21 14:09:58 -08:00
*/
2009-06-07 11:10:13 -07:00
void NETplayerLeaving ( UDWORD index )
2009-02-21 14:09:58 -08:00
{
2009-06-07 11:10:13 -07:00
if ( connected_bsocket [ index ] )
2009-02-21 14:09:58 -08:00
{
debug ( LOG_NET , " Player (%u) has left nicely, closing socket %p " ,
2009-06-07 11:10:13 -07:00
index , connected_bsocket [ index ] - > socket ) ;
2007-06-28 10:47:08 -07:00
2009-02-21 14:09:58 -08:00
// Although we can get a error result from DelSocket, it don't really matter here.
2009-06-07 11:10:13 -07:00
delSocket ( socket_set , connected_bsocket [ index ] - > socket ) ;
socketClose ( connected_bsocket [ index ] - > socket ) ;
connected_bsocket [ index ] - > socket = NULL ;
2009-02-21 14:09:58 -08:00
}
else
{
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Player (%u) has left nicely " , index ) ;
2009-02-21 14:09:58 -08:00
}
}
2009-06-07 11:10:13 -07:00
2009-02-21 14:09:58 -08:00
/**
* @ note When a player ' s connection is broken we broadcast the NET_PLAYER_DROPPED
* message .
2009-06-07 11:10:13 -07:00
* \ param index
2009-02-21 14:09:58 -08:00
*/
2009-06-07 11:10:13 -07:00
void NETplayerDropped ( UDWORD index )
2009-02-21 14:09:58 -08:00
{
2009-06-07 11:10:13 -07:00
uint32_t id = index ;
2009-02-21 14:09:58 -08:00
// Send message type speciffically for dropped / disconnects
NETbeginEncode ( NET_PLAYER_DROPPED , NET_ALL_PLAYERS ) ;
NETuint32_t ( & id ) ;
NETend ( ) ;
NET_DestroyPlayer ( id ) ; // just clears array
MultiPlayerLeave ( id ) ; // more cleanup
NET_PlayerConnectionStatus = 2 ; //DROPPED_CONNECTION
}
2009-06-07 11:10:13 -07:00
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////
// rename the local player
2009-06-07 11:10:13 -07:00
BOOL NETchangePlayerName ( UDWORD index , char * newName )
2007-06-28 10:47:08 -07:00
{
if ( ! NetPlay . bComms )
{
2008-05-25 06:46:49 -07:00
sstrcpy ( NetPlay . players [ 0 ] . name , newName ) ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Requesting a change of player name for pid=%u to %s " , index , newName ) ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
sstrcpy ( NetPlay . players [ index ] . name , newName ) ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
NETBroadcastPlayerInfo ( index ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////
// return one of the four user flags in the current sessiondescription.
2006-11-04 15:16:51 -08:00
SDWORD NETgetGameFlags ( UDWORD flag )
2006-02-18 10:54:37 -08:00
{
2007-07-25 08:31:27 -07:00
if ( flag < 1 | | flag > 4 )
{
2007-06-28 10:47:08 -07:00
return 0 ;
2007-07-25 08:31:27 -07:00
}
else
{
2007-06-28 10:47:08 -07:00
return NetGameFlags [ flag - 1 ] ;
}
}
2008-02-02 06:45:13 -08:00
static void NETsendGameFlags ( void )
{
2008-02-15 12:55:38 -08:00
NETbeginEncode ( NET_GAME_FLAGS , NET_ALL_PLAYERS ) ;
2008-02-02 06:45:13 -08:00
{
// Send the amount of game flags we're about to send
2008-05-02 14:19:15 -07:00
uint8_t i , count = ARRAY_SIZE ( NetGameFlags ) ;
2008-02-02 06:45:13 -08:00
NETuint8_t ( & count ) ;
// Send over all game flags
for ( i = 0 ; i < count ; + + i )
{
NETint32_t ( & NetGameFlags [ i ] ) ;
}
2008-02-03 08:39:49 -08:00
}
2008-02-02 06:45:13 -08:00
NETend ( ) ;
}
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////
// Set a game flag
2006-11-04 15:16:51 -08:00
BOOL NETsetGameFlags ( UDWORD flag , SDWORD value )
2006-02-18 10:54:37 -08:00
{
2007-07-25 08:31:27 -07:00
if ( ! NetPlay . bComms )
{
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 08:40:13 -07:00
if ( flag > 0 & & flag < 5 )
2007-07-25 08:31:27 -07:00
{
2008-03-24 09:58:26 -07:00
return ( NetGameFlags [ flag - 1 ] = value ) ;
2007-06-28 10:47:08 -07:00
}
2008-02-02 06:45:13 -08:00
NETsendGameFlags ( ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2008-08-03 14:34:18 -07:00
/**
2008-09-11 11:25:34 -07:00
* @ note \ c game is being sent to the master server ( if hosting )
2008-08-03 14:34:18 -07:00
* The implementation of NETsendGAMESTRUCT < em > must < / em > guarantee to
* pack it in network byte order ( big - endian ) .
*
* @ see GAMESTRUCT , NETrecvGAMESTRUCT
*/
2009-05-03 08:16:19 -07:00
static void NETsendGAMESTRUCT ( Socket * sock , const GAMESTRUCT * game )
2008-02-03 08:39:46 -08:00
{
// A buffer that's guaranteed to have the correct size (i.e. it
2008-09-13 13:39:26 -07:00
// circumvents struct padding, which could pose a problem). Initialise
// to zero so that we can be sure we're not sending any (undefined)
// memory content across the network.
2009-04-29 13:03:40 -07:00
char buf [ sizeof ( game - > GAMESTRUCT_VERSION ) + sizeof ( game - > name ) + sizeof ( game - > desc . host ) + ( sizeof ( int32_t ) * 8 ) +
2009-05-09 10:22:44 -07:00
sizeof ( game - > secondaryHosts ) + sizeof ( game - > extra ) + sizeof ( game - > versionstring ) +
2009-04-29 13:03:40 -07:00
sizeof ( game - > modlist ) + ( sizeof ( uint32_t ) * 9 ) ] = { 0 } ;
2008-04-11 11:35:53 -07:00
char * buffer = buf ;
2008-10-14 05:58:59 -07:00
unsigned int i ;
2008-07-12 04:50:18 -07:00
int result ;
2008-02-03 08:39:46 -08:00
// Now dump the data into the buffer
2009-04-29 13:03:40 -07:00
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( uint32_t * ) buffer = htonl ( game - > GAMESTRUCT_VERSION ) ;
2009-04-29 13:03:40 -07:00
buffer + = sizeof ( uint32_t ) ;
2008-02-03 08:39:46 -08:00
// Copy a string
2008-06-08 06:30:05 -07:00
strlcpy ( buffer , game - > name , sizeof ( game - > name ) ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( game - > name ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( int32_t * ) buffer = htonl ( game - > desc . dwSize ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-05-03 08:16:03 -07:00
* ( int32_t * ) buffer = htonl ( game - > desc . dwFlags ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
// Copy yet another string
2008-06-08 06:30:05 -07:00
strlcpy ( buffer , game - > desc . host , sizeof ( game - > desc . host ) ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( game - > desc . host ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( int32_t * ) buffer = htonl ( game - > desc . dwMaxPlayers ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-05-03 08:16:03 -07:00
* ( int32_t * ) buffer = htonl ( game - > desc . dwCurrentPlayers ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2008-10-14 05:58:59 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( game - > desc . dwUserFlags ) ; + + i )
{
2009-05-03 08:16:03 -07:00
* ( int32_t * ) buffer = htonl ( game - > desc . dwUserFlags [ i ] ) ;
2008-10-14 05:58:59 -07:00
buffer + = sizeof ( int32_t ) ;
}
2008-02-03 08:39:46 -08:00
2009-04-19 11:45:28 -07:00
// Copy a string
2009-05-09 10:22:44 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( game - > secondaryHosts ) ; + + i )
{
strlcpy ( buffer , game - > secondaryHosts [ i ] , sizeof ( game - > secondaryHosts [ i ] ) ) ;
buffer + = sizeof ( game - > secondaryHosts [ i ] ) ;
}
2009-04-19 11:45:28 -07:00
// Copy a string
strlcpy ( buffer , game - > extra , sizeof ( game - > extra ) ) ;
buffer + = sizeof ( game - > extra ) ;
// Copy a string
strlcpy ( buffer , game - > versionstring , sizeof ( game - > versionstring ) ) ;
buffer + = sizeof ( game - > versionstring ) ;
// Copy a string
strlcpy ( buffer , game - > modlist , sizeof ( game - > modlist ) ) ;
buffer + = sizeof ( game - > modlist ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( uint32_t * ) buffer = htonl ( game - > game_version_major ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( uint32_t * ) buffer = htonl ( game - > game_version_minor ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( uint32_t * ) buffer = htonl ( game - > privateGame ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( uint32_t * ) buffer = htonl ( game - > pureGame ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( uint32_t * ) buffer = htonl ( game - > Mods ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-05-09 10:22:44 -07:00
* ( uint32_t * ) buffer = htonl ( game - > gameId ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( uint32_t * ) buffer = htonl ( game - > future2 ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( uint32_t * ) buffer = htonl ( game - > future3 ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
* ( uint32_t * ) buffer = htonl ( game - > future4 ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2008-02-03 08:39:46 -08:00
// Send over the GAMESTRUCT
2009-05-03 08:35:50 -07:00
result = writeAll ( sock , buf , sizeof ( buf ) ) ;
2009-05-03 08:17:05 -07:00
if ( result = = SOCKET_ERROR )
2008-07-12 04:50:18 -07:00
{
2009-02-21 14:09:58 -08:00
// If packet could not be sent, we should inform user of the error.
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to send GAMESTRUCT. Reason: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-04-27 16:54:58 -07:00
debug ( LOG_ERROR , " Please make sure TCP ports %u & %u are open! " , masterserver_port , gameserver_port ) ;
2008-07-12 04:50:18 -07:00
}
2008-02-03 08:39:46 -08:00
}
2008-08-03 14:34:18 -07:00
/**
2008-09-11 11:25:34 -07:00
* @ note \ c game is being retrieved from the master server ( if browsing the
2008-08-03 14:34:18 -07:00
* lobby ) . The implementation of NETrecvGAMESTRUCT should assume the data
* to be packed in network byte order ( big - endian ) .
*
* @ see GAMESTRUCT , NETsendGAMESTRUCT
*/
2008-02-03 08:39:46 -08:00
static bool NETrecvGAMESTRUCT ( GAMESTRUCT * game )
{
// A buffer that's guaranteed to have the correct size (i.e. it
// circumvents struct padding, which could pose a problem).
2009-04-29 13:03:40 -07:00
char buf [ sizeof ( game - > GAMESTRUCT_VERSION ) + sizeof ( game - > name ) + sizeof ( game - > desc . host ) + ( sizeof ( int32_t ) * 8 ) +
2009-05-09 10:22:44 -07:00
sizeof ( game - > secondaryHosts ) + sizeof ( game - > extra ) + sizeof ( game - > versionstring ) +
2009-04-29 13:03:40 -07:00
sizeof ( game - > modlist ) + ( sizeof ( uint32_t ) * 9 ) ] = { 0 } ;
2008-02-03 08:39:46 -08:00
char * buffer = buf ;
2008-10-14 05:58:59 -07:00
unsigned int i ;
2008-04-11 11:35:53 -07:00
int result = 0 ;
2008-02-03 08:39:46 -08:00
// Read a GAMESTRUCT from the connection
if ( tcp_socket = = NULL
| | socket_set = = NULL
2009-06-10 20:51:37 -07:00
| | checkSockets ( socket_set , NET_TIMEOUT_DELAY ) < = 0
2009-05-03 08:16:03 -07:00
| | ! tcp_socket - > ready
2009-05-03 08:35:50 -07:00
| | ( result = readNoInt ( tcp_socket , buf , sizeof ( buf ) ) ) ! = sizeof ( buf ) )
2008-02-03 08:39:46 -08:00
{
2009-07-13 13:09:57 -07:00
unsigned int time = SDL_GetTicks ( ) ;
2009-05-03 08:17:05 -07:00
if ( result = = SOCKET_ERROR )
2008-04-11 11:35:53 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_WARNING , " Server socket ecountered error: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( tcp_socket ) ;
2009-05-03 08:16:34 -07:00
tcp_socket = NULL ;
2009-07-13 13:09:57 -07:00
return false ;
}
i = result ;
while ( i < sizeof ( buf ) & & SDL_GetTicks ( ) < time + 2500 )
{
result = readNoInt ( tcp_socket , buf + i , sizeof ( buf ) - i ) ;
if ( result = = SOCKET_ERROR | | result < = 0 )
{
2009-07-14 14:23:19 -07:00
debug ( LOG_WARNING , " GAMESTRUCT recv failed; received %u bytes out of %d " , i , ( int ) sizeof ( buf ) ) ;
2009-07-13 13:09:57 -07:00
return false ;
}
i + = result ;
}
if ( i ! = sizeof ( buf ) )
{
2009-07-14 14:23:19 -07:00
debug ( LOG_WARNING , " GAMESTRUCT recv size mismatch; received %u bytes; expecting %d " , i , ( int ) sizeof ( buf ) ) ;
2009-07-13 13:09:57 -07:00
return false ;
2008-04-11 11:35:53 -07:00
}
2008-02-03 08:39:46 -08:00
}
// Now dump the data into the game struct
2009-04-29 13:03:40 -07:00
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
game - > GAMESTRUCT_VERSION = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-29 13:03:40 -07:00
buffer + = sizeof ( uint32_t ) ;
2008-02-03 08:39:46 -08:00
// Copy a string
2008-05-25 06:46:49 -07:00
sstrcpy ( game - > name , buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( game - > name ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
game - > desc . dwSize = ntohl ( * ( int32_t * ) buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-05-03 08:16:03 -07:00
game - > desc . dwFlags = ntohl ( * ( int32_t * ) buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
// Copy yet another string
2008-05-25 06:46:49 -07:00
sstrcpy ( game - > desc . host , buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( game - > desc . host ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
game - > desc . dwMaxPlayers = ntohl ( * ( int32_t * ) buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-05-03 08:16:03 -07:00
game - > desc . dwCurrentPlayers = ntohl ( * ( int32_t * ) buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2008-10-14 05:58:59 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( game - > desc . dwUserFlags ) ; + + i )
{
2009-05-03 08:16:03 -07:00
game - > desc . dwUserFlags [ i ] = ntohl ( * ( int32_t * ) buffer ) ;
2008-10-14 05:58:59 -07:00
buffer + = sizeof ( int32_t ) ;
}
2008-02-03 08:39:46 -08:00
2009-04-19 11:45:28 -07:00
// Copy a string
2009-05-09 10:22:44 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( game - > secondaryHosts ) ; + + i )
{
sstrcpy ( game - > secondaryHosts [ i ] , buffer ) ;
buffer + = sizeof ( game - > secondaryHosts [ i ] ) ;
}
2009-04-19 11:45:28 -07:00
// Copy a string
sstrcpy ( game - > extra , buffer ) ;
buffer + = sizeof ( game - > extra ) ;
// Copy a string
sstrcpy ( game - > versionstring , buffer ) ;
buffer + = sizeof ( game - > versionstring ) ;
// Copy a string
sstrcpy ( game - > modlist , buffer ) ;
buffer + = sizeof ( game - > modlist ) ;
// Copy 32bit large big endian numbers
2009-05-03 08:16:03 -07:00
game - > game_version_major = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-05-03 08:16:03 -07:00
game - > game_version_minor = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-05-03 08:16:03 -07:00
game - > privateGame = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-05-03 08:16:03 -07:00
game - > pureGame = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-05-03 08:16:03 -07:00
game - > Mods = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-05-09 10:22:44 -07:00
game - > gameId = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-05-03 08:16:03 -07:00
game - > future2 = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-05-03 08:16:03 -07:00
game - > future3 = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-05-03 08:16:03 -07:00
game - > future4 = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2008-02-03 08:39:46 -08:00
return true ;
}
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////
// setup stuff
2008-04-11 11:35:53 -07:00
int NETinit ( BOOL bFirstCall )
2007-06-28 10:47:08 -07:00
{
2007-04-21 06:46:28 -07:00
UDWORD i ;
2007-06-28 10:47:08 -07:00
2008-07-12 04:02:55 -07:00
debug ( LOG_NET , " NETinit " ) ;
2009-06-07 11:10:13 -07:00
NET_InitPlayers ( ) ;
2007-06-28 10:47:08 -07:00
if ( bFirstCall )
{
2007-07-25 08:31:27 -07:00
debug ( LOG_NET , " NETPLAY: Init called, MORNIN' " ) ;
2006-02-18 10:54:37 -08:00
2008-02-11 08:23:20 -08:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2007-06-28 10:47:08 -07:00
{
2008-05-02 14:19:15 -07:00
memset ( & NetPlay . games [ i ] , 0 , sizeof ( NetPlay . games [ i ] ) ) ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 09:51:17 -07:00
NetPlay . bComms = true ;
2009-04-19 11:45:28 -07:00
NetPlay . GamePassworded = false ;
NetPlay . ShowedMOTD = false ;
NetPlay . gamePassword [ 0 ] = ' \0 ' ;
2009-05-04 14:52:01 -07:00
NetPlay . MOTD = strdup ( " " ) ;
2009-04-19 11:45:28 -07:00
sstrcpy ( NetPlay . gamePassword , " Enter Password First " ) ;
2007-06-28 10:47:08 -07:00
NETstartLogging ( ) ;
}
2009-05-03 08:16:03 -07:00
# if defined(WZ_OS_WIN)
2007-07-25 08:31:27 -07:00
{
2009-05-03 08:16:03 -07:00
static WSADATA stuff ;
WORD ver_required = ( 2 < < 8 ) + 2 ;
if ( WSAStartup ( ver_required , & stuff ) ! = 0 )
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to initialize Winsock: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-05-03 08:16:03 -07:00
return - 1 ;
}
2007-06-28 10:47:08 -07:00
}
2009-05-03 08:16:49 -07:00
winsock2_dll = LoadLibraryA ( " ws2_32.dll " ) ;
if ( winsock2_dll )
{
getaddrinfo_dll_func = GetProcAddress ( winsock2_dll , " getaddrinfo " ) ;
freeaddrinfo_dll_func = GetProcAddress ( winsock2_dll , " freeaddrinfo " ) ;
}
// Determine major Windows version
major_windows_version = LOBYTE ( LOWORD ( GetVersion ( ) ) ) ;
2009-05-03 08:16:03 -07:00
# endif
2006-02-18 10:54:37 -08:00
2009-04-19 11:45:28 -07:00
NetPlay . ShowedMOTD = false ;
NetPlay . GamePassworded = false ;
2008-04-11 11:35:53 -07:00
return 0 ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////
// SHUTDOWN THE CONNECTION.
2008-04-11 11:35:53 -07:00
int NETshutdown ( void )
2007-06-28 10:47:08 -07:00
{
2006-02-18 10:54:37 -08:00
debug ( LOG_NET , " NETshutdown " ) ;
NETstopLogging ( ) ;
2009-05-03 08:16:03 -07:00
# if defined(WZ_OS_WIN)
WSACleanup ( ) ;
2009-05-03 08:16:49 -07:00
if ( winsock2_dll )
{
FreeLibrary ( winsock2_dll ) ;
winsock2_dll = NULL ;
getaddrinfo_dll_func = NULL ;
freeaddrinfo_dll_func = NULL ;
}
2009-05-03 08:16:03 -07:00
# endif
2007-06-28 10:47:08 -07:00
return 0 ;
}
// ////////////////////////////////////////////////////////////////////////
//close the open game..
2008-04-11 11:35:53 -07:00
int NETclose ( void )
2007-06-28 10:47:08 -07:00
{
unsigned int i ;
2009-04-19 11:45:28 -07:00
// reset flag
NetPlay . ShowedMOTD = false ;
2005-12-02 13:45:42 -08:00
NEThaltJoining ( ) ;
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Terminating sockets. " ) ;
2009-06-07 11:10:13 -07:00
NetPlay . isHost = false ;
server_not_there = false ;
2009-04-23 20:16:04 -07:00
server_not_there = false ;
2007-06-28 10:47:08 -07:00
2007-07-25 08:31:27 -07:00
if ( bsocket )
2009-05-03 08:16:03 -07:00
{ // need delSocket() as well, socket_set or tmp_socket_set?
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Closing bsocket %p socket %p (tcp_socket=%p) " , bsocket , bsocket - > socket , tcp_socket ) ;
2009-05-03 08:35:50 -07:00
//socketClose(bsocket->socket);
2007-06-28 10:47:08 -07:00
NET_destroyBufferedSocket ( bsocket ) ;
bsocket = NULL ;
}
2006-02-18 10:54:37 -08:00
2008-04-11 11:35:53 -07:00
for ( i = 0 ; i < MAX_CONNECTED_PLAYERS ; i + + )
{
if ( connected_bsocket [ i ] )
{
2009-02-21 14:09:58 -08:00
if ( connected_bsocket [ i ] - > socket )
{
debug ( LOG_NET , " Closing connected_bsocket[%u], %p " , i , connected_bsocket [ i ] - > socket ) ;
2009-05-03 08:35:50 -07:00
socketClose ( connected_bsocket [ i ] - > socket ) ;
2009-02-21 14:09:58 -08:00
}
2007-06-28 10:47:08 -07:00
NET_destroyBufferedSocket ( connected_bsocket [ i ] ) ;
connected_bsocket [ i ] = NULL ;
}
NET_DestroyPlayer ( i ) ;
}
2008-04-11 11:35:53 -07:00
if ( tmp_socket_set )
2007-07-25 08:31:27 -07:00
{
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Freeing tmp_socket_set %p " , tmp_socket_set ) ;
2009-05-03 08:16:03 -07:00
free ( tmp_socket_set ) ;
2007-06-28 10:47:08 -07:00
tmp_socket_set = NULL ;
}
2007-07-25 08:31:27 -07:00
for ( i = 0 ; i < MAX_TMP_SOCKETS ; i + + )
{
if ( tmp_socket [ i ] )
{
2009-05-03 08:16:03 -07:00
// FIXME: need delSocket() as well, socket_set or tmp_socket_set?
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Closing tmp_socket[%d] %p " , i , tmp_socket [ i ] ) ;
2009-05-03 08:35:50 -07:00
socketClose ( tmp_socket [ i ] ) ;
2007-06-28 10:47:08 -07:00
tmp_socket [ i ] = NULL ;
}
}
2007-07-25 08:31:27 -07:00
if ( socket_set )
{
2008-04-11 11:35:53 -07:00
// checking to make sure tcp_socket is still valid
2009-05-03 08:16:03 -07:00
delSocket ( socket_set , tcp_socket ) ;
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Freeing socket_set %p " , socket_set ) ;
2009-05-03 08:16:03 -07:00
free ( socket_set ) ;
2007-06-28 10:47:08 -07:00
socket_set = NULL ;
}
2007-07-25 08:31:27 -07:00
if ( tcp_socket )
{
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Closing tcp_socket %p " , tcp_socket ) ;
2009-05-03 08:35:50 -07:00
socketClose ( tcp_socket ) ;
2007-06-28 10:47:08 -07:00
tcp_socket = NULL ;
}
2008-04-11 11:35:53 -07:00
return 0 ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
// Send and Recv functions
// ////////////////////////////////////////////////////////////////////////
// return bytes of data sent recently.
2006-09-13 02:09:05 -07:00
UDWORD NETgetBytesSent ( void )
2007-06-28 10:47:08 -07:00
{
static UDWORD lastsec = 0 ;
static UDWORD timy = 0 ;
2006-02-18 10:54:37 -08:00
if ( ( UDWORD ) clock ( ) > ( timy + CLOCKS_PER_SEC ) )
2007-06-28 10:47:08 -07:00
{
timy = clock ( ) ;
lastsec = nStats . bytesSent ;
nStats . bytesSent = 0 ;
}
return lastsec ;
}
2006-09-13 02:09:05 -07:00
UDWORD NETgetRecentBytesSent ( void )
2007-06-28 10:47:08 -07:00
{
return nStats . bytesSent ;
}
2006-09-13 02:09:05 -07:00
UDWORD NETgetBytesRecvd ( void )
2007-06-28 10:47:08 -07:00
{
static UDWORD lastsec = 0 ;
static UDWORD timy = 0 ;
2006-02-18 10:54:37 -08:00
if ( ( UDWORD ) clock ( ) > ( timy + CLOCKS_PER_SEC ) )
2007-06-28 10:47:08 -07:00
{
timy = clock ( ) ;
lastsec = nStats . bytesRecvd ;
nStats . bytesRecvd = 0 ;
}
return lastsec ;
}
2006-09-13 02:09:05 -07:00
UDWORD NETgetRecentBytesRecvd ( void )
2007-06-28 10:47:08 -07:00
{
return nStats . bytesRecvd ;
}
//return number of packets sent last sec.
2006-09-13 02:09:05 -07:00
UDWORD NETgetPacketsSent ( void )
2007-06-28 10:47:08 -07:00
{
static UDWORD lastsec = 0 ;
static UDWORD timy = 0 ;
2006-02-18 10:54:37 -08:00
if ( ( UDWORD ) clock ( ) > ( timy + CLOCKS_PER_SEC ) )
2007-06-28 10:47:08 -07:00
{
timy = clock ( ) ;
lastsec = nStats . packetsSent ;
nStats . packetsSent = 0 ;
}
return lastsec ;
}
2006-09-13 02:09:05 -07:00
UDWORD NETgetRecentPacketsSent ( void )
2007-06-28 10:47:08 -07:00
{
return nStats . packetsSent ;
}
2006-09-13 02:09:05 -07:00
UDWORD NETgetPacketsRecvd ( void )
2007-06-28 10:47:08 -07:00
{
static UDWORD lastsec = 0 ;
static UDWORD timy = 0 ;
2006-02-18 10:54:37 -08:00
if ( ( UDWORD ) clock ( ) > ( timy + CLOCKS_PER_SEC ) )
2007-06-28 10:47:08 -07:00
{
timy = clock ( ) ;
lastsec = nStats . packetsRecvd ;
nStats . packetsRecvd = 0 ;
}
return lastsec ;
}
// ////////////////////////////////////////////////////////////////////////
// Send a message to a player, option to guarantee message
2008-03-24 09:02:11 -07:00
BOOL NETsend ( NETMSG * msg , UDWORD player )
2006-02-18 10:54:37 -08:00
{
2007-01-04 12:24:26 -08:00
int size ;
2008-04-11 11:35:53 -07:00
int result = 0 ;
2007-06-28 10:47:08 -07:00
if ( ! NetPlay . bComms )
{
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 09:51:17 -07:00
if ( player > = MAX_CONNECTED_PLAYERS ) return false ;
2007-06-28 10:47:08 -07:00
msg - > destination = player ;
2008-01-02 09:08:29 -08:00
msg - > source = selectedPlayer ;
2007-06-28 10:47:08 -07:00
2008-01-02 09:08:29 -08:00
size = msg - > size + sizeof ( msg - > size ) + sizeof ( msg - > type ) + sizeof ( msg - > destination ) + sizeof ( msg - > source ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
NETlogPacket ( msg , false ) ;
2009-05-03 08:16:03 -07:00
msg - > size = htons ( msg - > size ) ;
2007-07-15 08:26:23 -07:00
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2009-05-03 08:16:03 -07:00
{ // FIXME: We are NOT checking checkSockets/SDLNet_SocketReady
2009-02-21 14:09:58 -08:00
// SDLNet_TCP_Send *can* block!
2007-06-28 10:47:08 -07:00
if ( player < MAX_CONNECTED_PLAYERS
& & connected_bsocket [ player ] ! = NULL
& & connected_bsocket [ player ] - > socket ! = NULL
2009-05-03 08:35:50 -07:00
& & ( result = writeAll ( connected_bsocket [ player ] - > socket ,
2008-04-11 11:35:53 -07:00
msg , size ) = = size ) )
2007-07-25 08:31:27 -07:00
{
2007-06-28 10:47:08 -07:00
nStats . bytesSent + = size ;
nStats . packetsSent + = 1 ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2009-05-03 08:17:05 -07:00
else if ( result = = SOCKET_ERROR )
2007-07-25 08:31:27 -07:00
{
2009-05-03 08:16:34 -07:00
// Write error, most likely client disconnect.
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to send message: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( connected_bsocket [ player ] - > socket ) ;
2009-05-03 08:16:34 -07:00
connected_bsocket [ player ] - > socket = NULL ;
2007-06-28 10:47:08 -07:00
}
}
2008-04-11 11:35:53 -07:00
else
{
2009-05-03 08:16:03 -07:00
// FIXME: We are NOT checking checkSockets/SDLNet_SocketReady
2009-02-21 14:09:58 -08:00
// SDLNet_TCP_Send *can* block!
2009-05-03 08:35:50 -07:00
if ( tcp_socket & & ( result = writeAll ( tcp_socket , msg , size ) = = size ) )
2008-04-11 11:35:53 -07:00
{
return true ;
}
2009-05-03 08:17:05 -07:00
else if ( result = = SOCKET_ERROR )
2008-04-11 11:35:53 -07:00
{
2009-05-03 08:16:34 -07:00
// Write error, most likely client disconnect.
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to send message: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( tcp_socket ) ;
2009-05-03 08:16:34 -07:00
tcp_socket = NULL ;
2008-04-11 11:35:53 -07:00
}
}
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////
// broadcast a message to all players.
2008-03-24 09:02:11 -07:00
BOOL NETbcast ( NETMSG * msg )
2006-02-18 10:54:37 -08:00
{
2007-01-04 12:24:26 -08:00
int size ;
2007-06-28 10:47:08 -07:00
if ( ! NetPlay . bComms )
{
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
msg - > destination = NET_ALL_PLAYERS ;
2008-01-02 09:08:29 -08:00
msg - > source = selectedPlayer ;
2007-06-28 10:47:08 -07:00
2008-01-02 09:08:29 -08:00
size = msg - > size + sizeof ( msg - > size ) + sizeof ( msg - > type ) + sizeof ( msg - > destination ) + sizeof ( msg - > source ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
NETlogPacket ( msg , false ) ;
2009-05-03 08:16:03 -07:00
msg - > size = htons ( msg - > size ) ;
2007-07-15 08:26:23 -07:00
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2007-07-25 08:31:27 -07:00
{
2007-06-28 10:47:08 -07:00
unsigned int i ;
2007-07-25 08:31:27 -07:00
for ( i = 0 ; i < MAX_CONNECTED_PLAYERS ; + + i )
{
2009-02-21 14:09:58 -08:00
if ( connected_bsocket [ i ] = = NULL
| | connected_bsocket [ i ] - > socket = = NULL )
2007-07-25 08:31:27 -07:00
{
2009-02-21 14:09:58 -08:00
continue ;
}
else
{
2009-05-03 08:16:03 -07:00
// FIXME: We are NOT checking checkSockets/SDLNet_SocketReady
2009-02-21 14:09:58 -08:00
// SDLNet_TCP_Send *can* block!
2009-05-03 08:35:50 -07:00
if ( writeAll ( connected_bsocket [ i ] - > socket , msg , size ) = = SOCKET_ERROR )
2008-04-11 11:35:53 -07:00
{
2009-05-03 08:16:34 -07:00
// Write error, most likely client disconnect.
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to send message: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-06-07 11:10:13 -07:00
NetPlay . players [ i ] . heartbeat = false ; //mark them dead
debug ( LOG_WARNING , " Player (player %u) connection was broken. " , i ) ;
2009-05-03 08:35:50 -07:00
socketClose ( connected_bsocket [ i ] - > socket ) ;
2009-05-03 08:16:34 -07:00
connected_bsocket [ i ] - > socket = NULL ;
2008-04-11 11:35:53 -07:00
}
2007-06-28 10:47:08 -07:00
}
}
2008-04-11 11:35:53 -07:00
}
else
{
if ( tcp_socket = = NULL )
2007-07-25 08:31:27 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2009-05-03 08:16:03 -07:00
// FIXME: We are NOT checking checkSockets/SDLNet_SocketReady
2009-02-21 14:09:58 -08:00
// SDLNet_TCP_Send *can* block!
2009-05-03 08:35:50 -07:00
if ( writeAll ( tcp_socket , msg , size ) = = SOCKET_ERROR )
2008-04-11 11:35:53 -07:00
{
2009-05-03 08:16:34 -07:00
// Write error, most likely client disconnect.
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to send message: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-02-21 14:09:58 -08:00
debug ( LOG_WARNING , " Host connection was broken? " ) ;
2009-05-03 08:35:50 -07:00
socketClose ( tcp_socket ) ;
2009-05-03 08:16:34 -07:00
tcp_socket = NULL ;
2009-06-07 11:10:13 -07:00
NetPlay . players [ NetPlay . hostPlayer ] . heartbeat = false ; // mark host as dead
2009-02-21 14:09:58 -08:00
//Game is pretty much over --should just end everything when HOST dies.
2008-04-11 11:35:53 -07:00
return false ;
}
2007-06-28 10:47:08 -07:00
}
nStats . bytesSent + = size ;
nStats . packetsSent + = 1 ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
///////////////////////////////////////////////////////////////////////////
// Check if a message is a system message
2008-02-16 05:39:23 -08:00
static BOOL NETprocessSystemMessage ( void )
2007-06-28 10:47:08 -07:00
{
2008-02-16 05:39:23 -08:00
NETMSG * pMsg = & NetMsg ;
2007-07-25 08:31:27 -07:00
switch ( pMsg - > type )
{
2008-02-15 12:55:38 -08:00
case NET_PLAYER_STATS :
2008-02-12 10:56:58 -08:00
{
recvMultiStats ( ) ;
break ;
}
2008-02-16 05:53:17 -08:00
case NET_PLAYER_INFO :
{
2009-06-07 11:10:13 -07:00
uint32_t index ;
2008-02-16 05:53:17 -08:00
NETbeginDecode ( NET_PLAYER_INFO ) ;
// Retrieve the player's ID
2009-06-07 11:10:13 -07:00
NETuint32_t ( & index ) ;
2008-02-16 05:53:17 -08:00
// Bail out if the given ID number is out of range
2009-06-07 11:10:13 -07:00
if ( index > = MAX_CONNECTED_PLAYERS )
2008-02-16 05:53:17 -08:00
{
2009-06-07 11:10:13 -07:00
debug ( LOG_WARNING , " MSG_PLAYER_INFO: Player ID (%u) out of range (max %u) " , index , ( unsigned int ) MAX_CONNECTED_PLAYERS ) ;
2008-02-16 05:53:17 -08:00
NETend ( ) ;
break ;
}
// Retrieve the rest of the data
2009-06-07 11:10:13 -07:00
NETbool ( & NetPlay . players [ index ] . allocated ) ;
NETbool ( & NetPlay . players [ index ] . heartbeat ) ;
NETbool ( & NetPlay . players [ index ] . kick ) ;
NETstring ( NetPlay . players [ index ] . name , sizeof ( NetPlay . players [ index ] . name ) ) ;
NETuint32_t ( & NetPlay . players [ index ] . heartattacktime ) ;
NETint32_t ( & NetPlay . players [ index ] . colour ) ;
NETint32_t ( & NetPlay . players [ index ] . team ) ;
NETbool ( & NetPlay . players [ index ] . ready ) ;
NETuint32_t ( & NetPlay . hostPlayer ) ;
2008-02-16 05:53:17 -08:00
NETend ( ) ;
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Receiving MSG_PLAYER_INFO for player %u (%s) " , ( unsigned int ) index , NetPlay . players [ index ] . allocated ? " human " : " AI " ) ;
2007-06-28 10:47:08 -07:00
2008-02-16 05:53:17 -08:00
// If we're the game host make sure to send the updated
// data to all other clients as well.
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2007-07-25 08:31:27 -07:00
{
2009-06-07 11:10:13 -07:00
NETBroadcastPlayerInfo ( index ) ;
2007-06-28 10:47:08 -07:00
}
2008-02-02 06:45:17 -08:00
break ;
}
2008-02-15 12:55:38 -08:00
case NET_PLAYER_JOINED :
2008-02-02 06:45:17 -08:00
{
2009-06-07 11:10:13 -07:00
uint8_t index ;
2008-02-15 12:55:38 -08:00
NETbeginDecode ( NET_PLAYER_JOINED ) ;
2009-06-07 11:10:13 -07:00
NETuint8_t ( & index ) ;
2008-02-02 06:45:17 -08:00
NETend ( ) ;
2007-07-24 12:33:46 -07:00
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Receiving NET_PLAYER_JOINED for player %u using socket %p " ,
2009-06-07 11:10:13 -07:00
( unsigned int ) index , tcp_socket ) ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
MultiPlayerJoin ( index ) ;
2008-02-02 06:45:17 -08:00
break ;
}
2009-02-21 14:09:58 -08:00
// This message type is when player is leaving 'nicely', and socket is still valid.
case NET_PLAYER_LEAVING :
2008-02-02 06:45:17 -08:00
{
2009-06-07 11:10:13 -07:00
uint32_t index ;
2008-04-11 11:35:53 -07:00
2009-02-21 14:09:58 -08:00
NETbeginDecode ( NET_PLAYER_LEAVING ) ;
2009-06-07 11:10:13 -07:00
NETuint32_t ( & index ) ;
2008-02-02 06:45:20 -08:00
NETend ( ) ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
if ( connected_bsocket [ index ] )
2009-02-21 14:09:58 -08:00
{
debug ( LOG_NET , " Receiving NET_PLAYER_LEAVING for player %u on socket %p " ,
2009-06-07 11:10:13 -07:00
( unsigned int ) index , connected_bsocket [ index ] - > socket ) ;
2009-02-21 14:09:58 -08:00
}
else
{ // dropped from join screen most likely
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Receiving NET_PLAYER_LEAVING for player %u " , ( unsigned int ) index ) ;
2009-02-21 14:09:58 -08:00
}
2007-07-24 12:33:46 -07:00
2009-06-07 11:10:13 -07:00
NET_DestroyPlayer ( index ) ; // sets index player's array to false
MultiPlayerLeave ( index ) ; // more cleanup
NETplayerLeaving ( index ) ; // need to close socket for the player that left.
NET_PlayerConnectionStatus = 1 ; // LEAVING_NICELY
2008-02-02 06:45:17 -08:00
break ;
}
2008-02-15 12:55:38 -08:00
case NET_GAME_FLAGS :
2008-02-02 06:45:13 -08:00
{
2008-07-12 04:02:55 -07:00
debug ( LOG_NET , " Receiving game flags " ) ;
2007-06-28 10:47:08 -07:00
2008-02-15 12:55:38 -08:00
NETbeginDecode ( NET_GAME_FLAGS ) ;
2007-07-25 08:31:27 -07:00
{
2008-05-02 14:19:15 -07:00
static unsigned int max_flags = ARRAY_SIZE ( NetGameFlags ) ;
2008-02-02 06:45:13 -08:00
// Retrieve the amount of game flags that we should receive
uint8_t i , count ;
NETuint8_t ( & count ) ;
2008-02-03 08:39:49 -08:00
2008-02-02 06:45:13 -08:00
// Make sure that we won't get buffer overflows by checking that we
// have enough space to store the given amount of game flags.
if ( count > max_flags )
{
2008-07-12 04:02:55 -07:00
debug ( LOG_NET , " NET_GAME_FLAGS: More game flags sent (%u) than our buffer can hold (%u) " , ( unsigned int ) count , max_flags ) ;
2008-02-02 06:45:13 -08:00
count = max_flags ;
}
// Retrieve all game flags
for ( i = 0 ; i < count ; + + i )
{
NETint32_t ( & NetGameFlags [ i ] ) ;
}
2008-02-03 08:39:49 -08:00
}
2008-02-02 06:45:13 -08:00
NETend ( ) ;
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2008-02-02 06:45:13 -08:00
{
NETsendGameFlags ( ) ;
2007-06-28 10:47:08 -07:00
}
2008-02-02 06:45:13 -08:00
break ;
}
2009-04-19 11:45:28 -07:00
case NET_PASSWORD_CHECK :
{
recvPasswordCheck ( ) ;
break ;
}
case NET_REQUEST_PASSWORD :
{
sendPasswordCheck ( ) ;
break ;
}
2009-04-10 21:41:14 -07:00
case NET_VERSION_CHECK :
{
recvVersionCheck ( ) ;
break ;
}
case NET_REQUEST_VERSION :
{
sendVersionCheck ( ) ;
break ;
}
2007-06-28 10:47:08 -07:00
default :
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2009-06-07 11:10:13 -07:00
2009-02-21 14:09:58 -08:00
/*
* Checks to see if a human player is still with us .
* @ note : resuscitation isn ' t possible with current code , so once we lose
* the socket , then we have no way to connect with them again . Future
* item to enhance .
*/
static void NETcheckPlayers ( void )
{
int i ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2009-02-21 14:09:58 -08:00
{
2009-06-07 11:10:13 -07:00
if ( NetPlay . players [ i ] . allocated = = 0 ) continue ; // not allocated means that it most like it is a AI player
if ( NetPlay . players [ i ] . heartbeat = = 0 & & NetPlay . players [ i ] . heartattacktime = = 0 ) // looks like they are dead
2009-02-21 14:09:58 -08:00
{
2009-06-07 11:10:13 -07:00
NetPlay . players [ i ] . heartattacktime = gameTime2 ; // mark when this occured
2009-02-21 14:09:58 -08:00
}
else
{
2009-06-07 11:10:13 -07:00
if ( NetPlay . players [ i ] . heartattacktime )
2009-02-21 14:09:58 -08:00
{
2009-06-07 11:10:13 -07:00
if ( NetPlay . players [ i ] . heartattacktime + ( 15 * GAME_TICKS_PER_SEC ) < gameTime2 ) // wait 15 secs
2009-02-21 14:09:58 -08:00
{
2009-06-07 11:10:13 -07:00
NetPlay . players [ i ] . kick = true ; // if still dead, then kick em.
2009-02-21 14:09:58 -08:00
}
}
}
2009-06-07 11:10:13 -07:00
if ( NetPlay . players [ i ] . kick )
2009-02-21 14:09:58 -08:00
{
NETplayerDropped ( i ) ;
}
}
}
2009-06-07 11:10:13 -07:00
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////
2008-03-24 09:51:17 -07:00
// Receive a message over the current connection. We return true if there
// is a message for the higher level code to process, and false otherwise.
2007-07-24 11:59:57 -07:00
// We should not block here.
2008-02-13 12:25:12 -08:00
BOOL NETrecv ( uint8_t * type )
2007-06-28 10:47:08 -07:00
{
2008-02-13 12:25:12 -08:00
NETMSG * pMsg = & NetMsg ;
2007-06-28 10:47:08 -07:00
static unsigned int current = 0 ;
BOOL received ;
int size ;
if ( ! NetPlay . bComms )
{
2008-03-24 09:51:17 -07:00
return false ;
2006-02-18 10:54:37 -08:00
}
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2007-07-24 11:59:57 -07:00
{
2007-06-28 10:47:08 -07:00
NETallowJoining ( ) ;
}
2009-02-21 14:09:58 -08:00
NETcheckPlayers ( ) ; // make sure players are still alive & well
2007-06-28 10:47:08 -07:00
do {
receive_message :
2008-03-24 09:51:17 -07:00
received = false ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
if ( NetPlay . isHost )
2007-07-24 11:59:57 -07:00
{
if ( connected_bsocket [ current ] = = NULL )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-07-24 11:59:57 -07:00
}
2007-06-28 10:47:08 -07:00
2008-02-16 05:39:23 -08:00
received = NET_recvMessage ( connected_bsocket [ current ] ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
if ( received = = false )
2007-07-24 11:59:57 -07:00
{
2009-02-19 12:01:10 -08:00
uint32_t i = ( current + 1 ) % 8 ;
2007-06-28 10:47:08 -07:00
2007-07-24 11:59:57 -07:00
if ( socket_set = = NULL
2009-05-03 08:16:03 -07:00
| | checkSockets ( socket_set , NET_READ_TIMEOUT ) < = 0 )
2007-07-24 11:59:57 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2007-08-08 11:50:28 -07:00
for ( ; ; )
2007-07-24 11:59:57 -07:00
{
2009-02-19 12:01:10 -08:00
ASSERT ( i < MAX_CONNECTED_PLAYERS , " Bad player number %u (current was %u) " , i , current ) ;
if ( connected_bsocket [ i ] = = NULL | | connected_bsocket [ i ] - > socket = = NULL )
2007-07-24 11:59:57 -07:00
{
// do nothing
}
2007-08-08 11:50:28 -07:00
else if ( NET_fillBuffer ( connected_bsocket [ i ] , socket_set ) )
2007-07-24 11:59:57 -07:00
{
// we received some data, add to buffer
2008-02-16 05:39:23 -08:00
received = NET_recvMessage ( connected_bsocket [ i ] ) ;
2007-06-28 10:47:08 -07:00
current = i ;
break ;
2007-08-08 11:50:28 -07:00
}
else if ( connected_bsocket [ i ] - > socket = = NULL )
2007-07-24 11:59:57 -07:00
{
2009-02-21 14:09:58 -08:00
// If there is a error in NET_fillBuffer() then socket is already invalid.
// This means that the player dropped / disconnected for whatever reason.
2009-06-07 11:10:13 -07:00
debug ( LOG_WARNING , " Player, (player %u) seems to have dropped/disconnected. " , i ) ;
2007-06-28 10:47:08 -07:00
2009-02-21 14:09:58 -08:00
// Send message type speciffically for dropped / disconnects
NETbeginEncode ( NET_PLAYER_DROPPED , NET_ALL_PLAYERS ) ;
2008-02-02 06:45:20 -08:00
NETuint32_t ( & i ) ;
NETend ( ) ;
2009-02-21 14:09:58 -08:00
NET_DestroyPlayer ( i ) ; // just clears array
MultiPlayerLeave ( i ) ; // more cleanup
NET_PlayerConnectionStatus = 2 ; //DROPPED_CONNECTION
2009-06-07 11:10:13 -07:00
NetPlay . players [ i ] . kick = true ; //they are going to get kicked.
2007-06-28 10:47:08 -07:00
}
2007-07-24 11:59:57 -07:00
2007-08-08 11:50:28 -07:00
if ( + + i = = MAX_CONNECTED_PLAYERS )
2007-07-24 11:59:57 -07:00
{
2007-06-28 10:47:08 -07:00
i = 0 ;
}
2007-07-24 11:59:57 -07:00
2007-08-08 11:50:28 -07:00
if ( i = = current + 1 )
2007-07-24 11:59:57 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
}
2009-02-21 14:09:58 -08:00
}
else
{
2007-07-24 11:59:57 -07:00
// we are a client
2007-08-08 11:50:28 -07:00
if ( bsocket = = NULL )
2007-07-24 11:59:57 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2009-02-21 14:09:58 -08:00
}
else
{
2008-02-16 05:39:23 -08:00
received = NET_recvMessage ( bsocket ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
if ( received = = false )
2007-07-24 11:59:57 -07:00
{
2007-06-28 10:47:08 -07:00
if ( socket_set ! = NULL
2009-05-03 08:16:03 -07:00
& & checkSockets ( socket_set , NET_READ_TIMEOUT ) > 0
2007-08-08 11:50:28 -07:00
& & NET_fillBuffer ( bsocket , socket_set ) )
2007-07-24 11:59:57 -07:00
{
2008-02-16 05:39:23 -08:00
received = NET_recvMessage ( bsocket ) ;
2007-06-28 10:47:08 -07:00
}
}
}
}
2008-03-24 09:51:17 -07:00
if ( received = = false )
2007-07-24 11:59:57 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2007-07-24 11:59:57 -07:00
}
2007-08-08 11:50:28 -07:00
else
2007-07-24 11:59:57 -07:00
{
2007-06-28 10:47:08 -07:00
size = pMsg - > size + sizeof ( pMsg - > size ) + sizeof ( pMsg - > type )
2008-01-02 09:08:29 -08:00
+ sizeof ( pMsg - > destination ) + sizeof ( pMsg - > source ) ;
2009-06-07 11:10:13 -07:00
if ( ! NetPlay . isHost )
2007-07-24 11:59:57 -07:00
{
// do nothing
2007-08-08 11:50:28 -07:00
}
else if ( pMsg - > destination = = NET_ALL_PLAYERS )
2007-07-24 11:59:57 -07:00
{
2007-06-28 10:47:08 -07:00
unsigned int j ;
2009-05-03 08:16:03 -07:00
pMsg - > size = ntohs ( pMsg - > size ) ;
2008-07-12 13:36:59 -07:00
2007-07-24 11:59:57 -07:00
// we are the host, and have received a broadcast packet; distribute it
2007-08-08 11:50:28 -07:00
for ( j = 0 ; j < MAX_CONNECTED_PLAYERS ; + + j )
2007-07-24 11:59:57 -07:00
{
2007-06-28 10:47:08 -07:00
if ( j ! = current
& & connected_bsocket [ j ] ! = NULL
2007-08-08 11:50:28 -07:00
& & connected_bsocket [ j ] - > socket ! = NULL )
2007-07-24 11:59:57 -07:00
{
2009-05-03 08:35:50 -07:00
if ( writeAll ( connected_bsocket [ j ] - > socket , pMsg , size ) = = SOCKET_ERROR )
2009-05-03 08:16:34 -07:00
{
// Write error, most likely client disconnect.
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to send message: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( connected_bsocket [ pMsg - > destination ] - > socket ) ;
2009-05-03 08:16:34 -07:00
connected_bsocket [ pMsg - > destination ] - > socket = NULL ;
}
2007-06-28 10:47:08 -07:00
}
}
2007-08-08 11:50:28 -07:00
}
2009-06-07 11:10:13 -07:00
else if ( pMsg - > destination ! = selectedPlayer )
2007-07-24 11:59:57 -07:00
{
// message was not meant for us; send it further
2007-06-28 10:47:08 -07:00
if ( pMsg - > destination < MAX_CONNECTED_PLAYERS
& & connected_bsocket [ pMsg - > destination ] ! = NULL
2007-08-08 11:50:28 -07:00
& & connected_bsocket [ pMsg - > destination ] - > socket ! = NULL )
2007-07-24 11:59:57 -07:00
{
2008-07-12 09:21:00 -07:00
debug ( LOG_NET , " Reflecting message type %hhu to %hhu " , pMsg - > type , pMsg - > destination ) ;
2009-05-03 08:16:03 -07:00
pMsg - > size = ntohs ( pMsg - > size ) ;
2009-02-21 14:09:58 -08:00
2009-05-03 08:35:50 -07:00
if ( writeAll ( connected_bsocket [ pMsg - > destination ] - > socket , pMsg , size ) = = SOCKET_ERROR )
2009-02-21 14:09:58 -08:00
{
2009-05-03 08:16:34 -07:00
// Write error, most likely client disconnect.
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to send message: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( connected_bsocket [ pMsg - > destination ] - > socket ) ;
2009-05-03 08:16:34 -07:00
connected_bsocket [ pMsg - > destination ] - > socket = NULL ;
2009-02-21 14:09:58 -08:00
}
}
else
{
2007-07-25 08:31:27 -07:00
debug ( LOG_NET , " Cannot reflect message type %hhu to %hhu " , pMsg - > type , pMsg - > destination ) ;
2007-06-28 10:47:08 -07:00
}
2006-02-18 10:54:37 -08:00
2007-06-28 10:47:08 -07:00
goto receive_message ;
}
nStats . bytesRecvd + = size ;
nStats . packetsRecvd + = 1 ;
}
2006-02-18 10:54:37 -08:00
2008-03-24 09:51:17 -07:00
} while ( NETprocessSystemMessage ( ) = = true ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
NETlogPacket ( pMsg , true ) ;
2007-07-15 08:26:23 -07:00
2008-02-13 12:25:12 -08:00
* type = pMsg - > type ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
// Protocol functions
2008-02-13 09:22:43 -08:00
BOOL NETsetupTCPIP ( const char * machine )
2007-06-28 10:47:08 -07:00
{
2008-07-12 04:02:55 -07:00
debug ( LOG_NET , " NETsetupTCPIP(%s) " , machine ? machine : " NULL " ) ;
2006-08-23 08:27:20 -07:00
2005-12-02 13:45:42 -08:00
if ( hostname ! = NULL
2007-07-25 08:31:27 -07:00
& & hostname ! = masterserver_name )
{
2005-12-02 13:45:42 -08:00
free ( hostname ) ;
}
if ( machine ! = NULL
2007-07-25 08:31:27 -07:00
& & machine [ 0 ] ! = ' \0 ' )
{
2005-12-02 13:45:42 -08:00
hostname = strdup ( machine ) ;
} else {
2007-04-21 06:46:28 -07:00
hostname = masterserver_name ;
2005-12-02 13:45:42 -08:00
}
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////
// File Transfer programs.
2009-02-03 09:02:17 -08:00
/** Send file. It returns % of file sent when 100 it's complete. Call until it returns 100.
* @ TODO Needs to be rewritten . See issue # 215. */
2009-10-09 17:38:33 -07:00
# define MAX_FILE_TRANSFER_PACKET 1024
2008-01-11 13:39:41 -08:00
UBYTE NETsendFile ( BOOL newFile , char * fileName , UDWORD player )
2007-06-28 10:47:08 -07:00
{
2008-01-11 13:39:41 -08:00
static int32_t fileSize , currPos ;
2006-06-16 12:10:23 -07:00
static PHYSFS_file * pFileHandle ;
2008-01-11 13:39:41 -08:00
int32_t bytesRead ;
char inBuff [ MAX_FILE_TRANSFER_PACKET ] ;
uint8_t sendto = 0 ;
2006-02-18 10:54:37 -08:00
2008-01-11 13:39:41 -08:00
memset ( inBuff , 0x0 , sizeof ( inBuff ) ) ;
if ( newFile )
2007-06-28 10:47:08 -07:00
{
// open the file.
2006-06-16 12:10:23 -07:00
pFileHandle = PHYSFS_openRead ( fileName ) ; // check file exists
2008-09-07 13:00:54 -07:00
debug ( LOG_WZ , " Reading...[directory: %s] %s " , PHYSFS_getRealDir ( fileName ) , fileName ) ;
2007-06-28 10:47:08 -07:00
if ( pFileHandle = = NULL )
{
2009-02-03 09:02:17 -08:00
debug ( LOG_ERROR , " Failed to open %s for reading: %s " , fileName , PHYSFS_getLastError ( ) ) ;
2007-05-23 12:36:21 -07:00
return 0 ; // failed
2007-06-28 10:47:08 -07:00
}
// get the file's size.
fileSize = 0 ;
2008-01-11 13:39:41 -08:00
currPos = 0 ;
2007-06-28 10:47:08 -07:00
do
{
2008-01-11 13:39:41 -08:00
bytesRead = PHYSFS_read ( pFileHandle , inBuff , 1 , MAX_FILE_TRANSFER_PACKET ) ;
2007-06-28 10:47:08 -07:00
fileSize + = bytesRead ;
} while ( bytesRead ! = 0 ) ;
2008-01-11 13:39:41 -08:00
PHYSFS_seek ( pFileHandle , 0 ) ;
2007-06-28 10:47:08 -07:00
}
// read some bytes.
2009-02-03 09:02:17 -08:00
if ( ! pFileHandle )
{
debug ( LOG_ERROR , " No filehandle " ) ;
return 0 ; // failed
}
2008-01-11 13:39:41 -08:00
bytesRead = PHYSFS_read ( pFileHandle , inBuff , 1 , MAX_FILE_TRANSFER_PACKET ) ;
2009-04-27 11:02:38 -07:00
if ( player = = 0 )
{ // FIXME: why would you send (map) file to everyone ??
// even if they already have it? multiplay.c 1529 & 1550 are both
// NETsendFile(true,mapStr,0); & NETsendFile(false,game.map,0);
// so we ALWAYS send it, it seems?
NETbeginEncode ( FILEMSG , NET_ALL_PLAYERS ) ; // send it.
}
else
{
sendto = ( uint8_t ) player ;
NETbeginEncode ( FILEMSG , sendto ) ;
}
2006-02-18 10:54:37 -08:00
2008-01-11 13:39:41 -08:00
// form a message
NETint32_t ( & fileSize ) ; // total bytes in this file.
NETint32_t ( & bytesRead ) ; // bytes in this packet
NETint32_t ( & currPos ) ; // start byte
NETstring ( fileName , 256 ) ; //256 = max filename size
NETbin ( inBuff , bytesRead ) ;
NETend ( ) ;
2007-06-28 10:47:08 -07:00
currPos + = bytesRead ; // update position!
if ( currPos = = fileSize )
{
2006-06-16 12:10:23 -07:00
PHYSFS_close ( pFileHandle ) ;
2007-06-28 10:47:08 -07:00
}
2008-01-11 13:39:41 -08:00
return ( currPos * 100 ) / fileSize ;
2007-06-28 10:47:08 -07:00
}
// recv file. it returns % of the file so far recvd.
2008-01-11 13:39:41 -08:00
UBYTE NETrecvFile ( void )
2007-06-28 10:47:08 -07:00
{
2008-01-11 13:39:41 -08:00
int32_t fileSize , currPos , bytesRead ;
char fileName [ 256 ] ;
char outBuff [ MAX_FILE_TRANSFER_PACKET ] ;
2006-06-16 12:10:23 -07:00
static PHYSFS_file * pFileHandle ;
2007-06-28 10:47:08 -07:00
2008-01-11 13:39:41 -08:00
memset ( fileName , 0x0 , sizeof ( fileName ) ) ;
memset ( outBuff , 0x0 , sizeof ( outBuff ) ) ;
2007-06-28 10:47:08 -07:00
//read incoming bytes.
2008-02-13 12:25:12 -08:00
NETbeginDecode ( FILEMSG ) ;
2008-01-11 13:39:41 -08:00
NETint32_t ( & fileSize ) ; // total bytes in this file.
NETint32_t ( & bytesRead ) ; // bytes in this packet
NETint32_t ( & currPos ) ; // start byte
2006-02-18 10:54:37 -08:00
2007-06-28 10:47:08 -07:00
// read filename
2008-01-11 13:39:41 -08:00
NETstring ( fileName , 256 ) ; // Ugh. 256 = max array size
2008-07-12 04:02:55 -07:00
debug ( LOG_NET , " Creating new file %s " , fileName ) ;
2007-06-28 10:47:08 -07:00
2008-01-11 13:39:41 -08:00
if ( currPos = = 0 ) // first packet!
2007-06-28 10:47:08 -07:00
{
2006-06-16 12:10:23 -07:00
pFileHandle = PHYSFS_openWrite ( fileName ) ; // create a new file.
2007-06-28 10:47:08 -07:00
}
2006-02-18 10:54:37 -08:00
2009-10-30 20:57:44 -07:00
if ( ! pFileHandle ) // file can't be opened
{
debug ( LOG_FATAL , " Fatal error while creating file: %s " , PHYSFS_getLastError ( ) ) ;
abort ( ) ;
}
2008-01-11 13:39:41 -08:00
NETbin ( outBuff , bytesRead ) ;
NETend ( ) ;
2007-06-28 10:47:08 -07:00
//write packet to the file.
2008-01-11 13:39:41 -08:00
PHYSFS_write ( pFileHandle , outBuff , bytesRead , 1 ) ;
2007-06-28 10:47:08 -07:00
2008-01-11 13:39:41 -08:00
if ( currPos + bytesRead = = fileSize ) // last packet
2007-06-28 10:47:08 -07:00
{
2006-06-16 12:10:23 -07:00
PHYSFS_close ( pFileHandle ) ;
2007-06-28 10:47:08 -07:00
}
2008-01-11 13:39:41 -08:00
//return the percentage count
return ( ( currPos + bytesRead ) * 100 ) / fileSize ;
2007-06-28 10:47:08 -07:00
}
2009-05-04 14:52:01 -07:00
static ssize_t readLobbyResponse ( Socket * sock , unsigned int timeout )
{
uint32_t lobbyStatusCode ;
uint32_t MOTDLength ;
uint32_t buffer [ 2 ] ;
ssize_t result , received = 0 ;
// Get status and message length
result = readAll ( sock , & buffer , sizeof ( buffer ) , timeout ) ;
if ( result ! = sizeof ( buffer ) )
goto error ;
received + = result ;
lobbyStatusCode = ntohl ( buffer [ 0 ] ) ;
MOTDLength = ntohl ( buffer [ 1 ] ) ;
// Get status message
free ( NetPlay . MOTD ) ;
NetPlay . MOTD = malloc ( MOTDLength + 1 ) ;
result = readAll ( sock , NetPlay . MOTD , MOTDLength , timeout ) ;
if ( result ! = MOTDLength )
goto error ;
received + = result ;
// NUL terminate string
NetPlay . MOTD [ MOTDLength ] = ' \0 ' ;
if ( lobbyStatusCode / 100 ! = 2 ) // Check whether status code is 2xx (success)
{
debug ( LOG_ERROR , " Lobby error (%u): %s " , ( unsigned int ) lobbyStatusCode , NetPlay . MOTD ) ;
return SOCKET_ERROR ;
}
debug ( LOG_NET , " Lobby success (%u): %s " , ( unsigned int ) lobbyStatusCode , NetPlay . MOTD ) ;
return received ;
error :
if ( result = = SOCKET_ERROR )
{
free ( NetPlay . MOTD ) ;
asprintf ( & NetPlay . MOTD , " Error while communicating with the lobby server: %s " , strSockError ( getSockErr ( ) ) ) ;
debug ( LOG_ERROR , " %s " , NetPlay . MOTD ) ;
}
else
{
free ( NetPlay . MOTD ) ;
asprintf ( & NetPlay . MOTD , " Disconnected from lobby server. Failed to register game. " ) ;
debug ( LOG_ERROR , " %s " , NetPlay . MOTD ) ;
}
return SOCKET_ERROR ;
}
2008-03-28 16:28:44 -07:00
static void NETregisterServer ( int state )
2007-07-25 08:31:27 -07:00
{
2009-05-09 10:22:44 -07:00
static Socket * rs_socket [ 2 ] = { NULL } ;
2006-02-28 22:12:28 -08:00
static int registered = 0 ;
2009-05-09 10:22:44 -07:00
unsigned int i ;
2005-12-02 13:45:42 -08:00
2007-07-25 08:31:27 -07:00
if ( server_not_there )
{
2006-02-28 22:12:28 -08:00
return ;
}
2007-07-25 08:31:27 -07:00
if ( state ! = registered )
{
switch ( state )
{
2009-05-03 08:16:03 -07:00
case 1 :
{
2009-05-09 10:22:44 -07:00
bool succesful = false ;
uint32_t gameId = 0 ;
2009-05-03 08:16:03 -07:00
struct addrinfo * cur ;
struct addrinfo * const hosts = resolveHost ( masterserver_name , masterserver_port ) ;
2009-05-04 14:52:01 -07:00
2009-05-03 08:16:03 -07:00
if ( hosts = = NULL )
2007-07-25 08:31:27 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot resolve masterserver \" %s \" : %s " , masterserver_name , strSockError ( getSockErr ( ) ) ) ;
2009-05-04 14:52:01 -07:00
free ( NetPlay . MOTD ) ;
asprintf ( & NetPlay . MOTD , _ ( " Could not resolve masterserver name (%s)! " ) , masterserver_name ) ;
2009-04-23 20:16:04 -07:00
server_not_there = true ;
2005-12-02 13:45:42 -08:00
return ;
}
2009-05-03 08:16:03 -07:00
for ( cur = hosts ; cur ; cur = cur - > ai_next )
{
2009-05-09 10:22:44 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( rs_socket ) ; + + i )
{
if ( rs_socket [ i ] = = NULL )
break ;
}
if ( i > = ARRAY_SIZE ( rs_socket ) )
2009-05-03 08:16:03 -07:00
break ;
2009-05-09 10:22:44 -07:00
if ( cur - > ai_family = = AF_INET
| | cur - > ai_family = = AF_INET6 )
rs_socket [ i ] = SocketOpen ( cur , 15000 ) ;
2009-05-03 08:16:03 -07:00
}
freeaddrinfo ( hosts ) ;
2009-05-09 10:22:44 -07:00
if ( rs_socket [ 0 ] = = NULL )
2007-07-25 08:31:27 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot connect to masterserver \" %s:%d \" : %s " , masterserver_name , masterserver_port , strSockError ( getSockErr ( ) ) ) ;
2009-05-04 14:52:01 -07:00
free ( NetPlay . MOTD ) ;
2009-05-09 10:22:44 -07:00
asprintf ( & NetPlay . MOTD , _ ( " Could not communicate with lobby server! Is TCP port %u open for outgoing traffic? " ) , masterserver_port ) ;
server_not_there = true ;
return ;
}
// Get a game ID
writeAll ( rs_socket [ 0 ] , " gaId " , sizeof ( " gaId " ) ) ;
if ( readAll ( rs_socket [ 0 ] , & gameId , sizeof ( gameId ) , 10000 ) ! = sizeof ( gameId ) )
{
free ( NetPlay . MOTD ) ;
asprintf ( & NetPlay . MOTD , " Failed to retrieve a game ID: %s " , strSockError ( getSockErr ( ) ) ) ;
debug ( LOG_ERROR , " %s " , NetPlay . MOTD ) ;
// The sockets have been invalidated, so get rid of it. (using them now may cause SIGPIPE).
for ( i = 0 ; i < ARRAY_SIZE ( rs_socket ) ; + + i )
{
if ( rs_socket [ i ] = = NULL )
continue ;
socketClose ( rs_socket [ i ] ) ;
rs_socket [ i ] = NULL ;
}
2009-04-23 20:16:04 -07:00
server_not_there = true ;
2005-12-02 13:45:42 -08:00
return ;
}
2009-05-09 10:22:44 -07:00
game . gameId = ntohl ( gameId ) ;
debug ( LOG_NET , " Using game ID: %u " , ( unsigned int ) game . gameId ) ;
2009-05-04 14:52:01 -07:00
2009-05-09 10:22:44 -07:00
// Register our game with the server for all available address families
for ( i = 0 ; i < ARRAY_SIZE ( rs_socket ) ; + + i )
{
if ( rs_socket [ i ] = = NULL )
continue ;
writeAll ( rs_socket [ i ] , " addg " , sizeof ( " addg " ) ) ;
// and now send what the server wants
NETsendGAMESTRUCT ( rs_socket [ i ] , & game ) ;
}
// Get the return codes
for ( i = 0 ; i < ARRAY_SIZE ( rs_socket ) ; + + i )
{
if ( rs_socket [ i ] = = NULL )
continue ;
2009-06-10 20:51:37 -07:00
if ( readLobbyResponse ( rs_socket [ i ] , NET_TIMEOUT_DELAY ) = = SOCKET_ERROR )
2009-05-09 10:22:44 -07:00
{
socketClose ( rs_socket [ i ] ) ;
rs_socket [ i ] = NULL ;
continue ;
}
succesful = true ;
}
if ( ! succesful )
2009-05-04 14:52:01 -07:00
{
2009-05-05 13:00:06 -07:00
server_not_there = true ;
2009-05-04 14:52:01 -07:00
return ;
}
2005-12-02 13:45:42 -08:00
}
break ;
case 0 :
2009-04-19 11:45:28 -07:00
// we don't need this anymore, so clean up
2009-05-09 10:22:44 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( rs_socket ) ; + + i )
{
if ( rs_socket [ i ] = = NULL )
continue ;
socketClose ( rs_socket [ i ] ) ;
rs_socket [ i ] = NULL ;
}
2005-12-02 13:45:42 -08:00
break ;
}
registered = state ;
}
}
2007-06-28 10:47:08 -07:00
// ////////////////////////////////////////////////////////////////////////
// Host a game with a given name and player name. & 4 user game flags
2007-08-08 11:50:28 -07:00
static void NETallowJoining ( void )
2007-07-24 11:22:04 -07:00
{
2007-06-28 10:47:08 -07:00
unsigned int i ;
2009-05-03 08:16:03 -07:00
UDWORD numgames = htonl ( 1 ) ; // always 1 on normal server
2005-12-02 13:45:42 -08:00
char buffer [ 5 ] ;
2009-02-21 14:09:58 -08:00
int recv_result = 9999 ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
if ( allow_joining = = false ) return ;
2009-06-07 11:10:13 -07:00
ASSERT ( NetPlay . isHost , " Cannot receive joins if not host! " ) ;
2007-06-28 10:47:08 -07:00
2005-12-02 13:45:42 -08:00
NETregisterServer ( 1 ) ;
2009-04-19 11:45:28 -07:00
// This is here since we need to get the status, before we can show the info.
// FIXME: find better location to stick this?
if ( ! NetPlay . ShowedMOTD )
{
ShowMOTD ( ) ;
NetPlay . ShowedMOTD = true ;
}
2009-06-07 11:10:13 -07:00
// Version check - make sure we sent the check, then check for timelimit
for ( i = 0 ; i < MAX_CONNECTED_PLAYERS ; i + + )
{
if ( NetPlay . players [ i ] . versionCheckTime ! = 0xffffffff & & NetPlay . players [ i ] . versionCheckTime < gameTime2 )
{
NETCheckVersion ( i ) ;
}
}
2007-08-08 11:50:28 -07:00
if ( tmp_socket_set = = NULL )
2007-07-24 12:33:46 -07:00
{
// initialize server socket set
// FIXME: why is this not done in NETinit()?? - Per
2009-05-03 08:16:03 -07:00
tmp_socket_set = allocSocketSet ( MAX_TMP_SOCKETS + 1 ) ;
2007-08-08 11:50:28 -07:00
if ( tmp_socket_set = = NULL )
2007-07-24 12:33:46 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot create socket set: %s " , strSockError ( getSockErr ( ) ) ) ;
2007-06-28 10:47:08 -07:00
return ;
}
2009-05-03 08:50:11 -07:00
}
2008-05-07 03:09:20 -07:00
2009-05-03 08:50:11 -07:00
// Find the first empty socket slot
for ( i = 0 ; i < MAX_TMP_SOCKETS ; + + i )
{
if ( tmp_socket [ i ] = = NULL )
2009-02-21 14:09:58 -08:00
{
2009-05-03 08:50:11 -07:00
break ;
2009-02-21 14:09:58 -08:00
}
2007-06-28 10:47:08 -07:00
}
2009-07-15 15:50:41 -07:00
if ( i = = MAX_TMP_SOCKETS )
{
// prevent out-of-bounds access
i - - ;
}
2007-06-28 10:47:08 -07:00
2009-05-03 08:50:11 -07:00
// See if there's an incoming connection
if ( tmp_socket [ i ] = = NULL // Make sure that we're not out of sockets
& & ( tmp_socket [ i ] = socketAccept ( tcp_socket ) ) ! = NULL )
2007-07-24 12:33:46 -07:00
{
2009-05-03 08:50:11 -07:00
addSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
2009-06-10 20:51:37 -07:00
if ( checkSockets ( tmp_socket_set , NET_TIMEOUT_DELAY ) > 0
2009-05-03 08:50:11 -07:00
& & tmp_socket [ i ] - > ready
& & ( recv_result = readNoInt ( tmp_socket [ i ] , buffer , 5 ) ) )
2007-07-24 12:33:46 -07:00
{
2009-05-03 08:50:11 -07:00
if ( strcmp ( buffer , " list " ) = = 0 )
2007-07-24 12:33:46 -07:00
{
2009-05-03 08:50:11 -07:00
debug ( LOG_NET , " cmd: list. Sending game list " ) ;
if ( writeAll ( tmp_socket [ i ] , & numgames , sizeof ( numgames ) ) = = SOCKET_ERROR )
2007-07-25 08:31:27 -07:00
{
2009-05-03 08:50:11 -07:00
// Write error, most likely client disconnect.
debug ( LOG_ERROR , " Failed to send message: %s " , strSockError ( getSockErr ( ) ) ) ;
debug ( LOG_WARNING , " Couldn't get list from server. Make sure required ports are open. (TCP 9998-9999) " ) ;
2005-12-02 13:45:42 -08:00
}
2009-04-30 18:27:13 -07:00
else
{
2009-05-03 08:50:11 -07:00
// get the correct player count after kicks / leaves
2009-06-07 11:10:13 -07:00
game . desc . dwCurrentPlayers = NetPlay . playercount ;
2009-05-03 08:50:11 -07:00
NETsendGAMESTRUCT ( tmp_socket [ i ] , & game ) ;
2009-04-30 18:27:13 -07:00
}
2009-05-03 08:50:11 -07:00
delSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
socketClose ( tmp_socket [ i ] ) ;
tmp_socket [ i ] = NULL ;
}
else if ( strcmp ( buffer , " join " ) = = 0 )
{
debug ( LOG_NET , " cmd: join. Sending GAMESTRUCT " ) ;
NETsendGAMESTRUCT ( tmp_socket [ i ] , & game ) ;
2009-02-21 14:09:58 -08:00
}
else
{
2009-05-03 08:16:03 -07:00
delSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
2009-05-03 08:35:50 -07:00
socketClose ( tmp_socket [ i ] ) ;
2009-04-30 18:27:13 -07:00
tmp_socket [ i ] = NULL ;
2005-12-02 13:45:42 -08:00
}
2007-06-28 10:47:08 -07:00
}
2009-05-03 08:50:11 -07:00
else
{
delSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
socketClose ( tmp_socket [ i ] ) ;
tmp_socket [ i ] = NULL ;
}
}
if ( checkSockets ( tmp_socket_set , NET_READ_TIMEOUT ) > 0 )
{
2007-08-08 11:50:28 -07:00
for ( i = 0 ; i < MAX_TMP_SOCKETS ; + + i )
2007-07-24 12:33:46 -07:00
{
2007-06-28 10:47:08 -07:00
if ( tmp_socket [ i ] ! = NULL
2009-05-03 08:16:03 -07:00
& & tmp_socket [ i ] - > ready )
2007-07-24 12:33:46 -07:00
{
2009-05-03 08:35:50 -07:00
int size = readNoInt ( tmp_socket [ i ] , & NetMsg , sizeof ( NetMsg ) ) ;
2007-06-28 10:47:08 -07:00
2007-07-24 12:33:46 -07:00
if ( size < = 0 )
{
2009-05-03 08:16:34 -07:00
// disconnect or programmer error
if ( size = = 0 )
{
debug ( LOG_NET , " Client socket disconnected. " ) ;
}
else
{
2009-05-03 08:35:50 -07:00
debug ( LOG_NET , " Client socket ecountered error: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-05-03 08:16:34 -07:00
}
2009-05-03 08:16:03 -07:00
delSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
2009-05-03 08:35:50 -07:00
socketClose ( tmp_socket [ i ] ) ;
2007-06-28 10:47:08 -07:00
tmp_socket [ i ] = NULL ;
2007-07-24 12:33:46 -07:00
}
2008-02-15 12:55:38 -08:00
else if ( NetMsg . type = = NET_JOIN )
2007-07-24 12:33:46 -07:00
{
2008-02-02 06:45:24 -08:00
char name [ 64 ] ;
2009-06-07 11:10:13 -07:00
uint8_t j ;
uint8_t index ;
2007-06-28 10:47:08 -07:00
2008-02-15 12:55:38 -08:00
NETbeginDecode ( NET_JOIN ) ;
2008-02-02 06:45:24 -08:00
NETstring ( name , sizeof ( name ) ) ;
NETend ( ) ;
2009-06-07 11:10:13 -07:00
index = NET_CreatePlayer ( name ) ;
2007-06-28 10:47:08 -07:00
2009-05-03 08:16:03 -07:00
delSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
2009-06-07 11:10:13 -07:00
NET_initBufferedSocket ( connected_bsocket [ index ] , tmp_socket [ i ] ) ;
addSocket ( socket_set , connected_bsocket [ index ] - > socket ) ;
2007-06-28 10:47:08 -07:00
tmp_socket [ i ] = NULL ;
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Player, %s, with index of %u has joined using socket %p " , name ,
( unsigned int ) index , connected_bsocket [ index ] - > socket ) ;
2009-02-21 14:09:58 -08:00
2008-02-02 06:45:17 -08:00
// Increment player count
2007-06-28 10:47:08 -07:00
game . desc . dwCurrentPlayers + + ;
2009-06-07 11:10:13 -07:00
NETbeginEncode ( NET_ACCEPTED , index ) ;
NETuint8_t ( & index ) ;
2008-02-02 06:45:17 -08:00
NETend ( ) ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
MultiPlayerJoin ( index ) ;
2007-06-28 10:47:08 -07:00
// Send info about players to newcomer.
2007-08-08 11:50:28 -07:00
for ( j = 0 ; j < MAX_CONNECTED_PLAYERS ; + + j )
2007-07-24 12:33:46 -07:00
{
2009-06-07 11:10:13 -07:00
if ( NetPlay . players [ j ] . allocated & & index ! = j )
2007-07-24 12:33:46 -07:00
{
2009-06-07 11:10:13 -07:00
NETbeginEncode ( NET_PLAYER_JOINED , index ) ;
NETuint8_t ( & j ) ;
2008-02-02 06:45:17 -08:00
NETend ( ) ;
2007-06-28 10:47:08 -07:00
}
}
// Send info about newcomer to all players.
2008-02-15 12:55:38 -08:00
NETbeginEncode ( NET_PLAYER_JOINED , NET_ALL_PLAYERS ) ;
2009-06-07 11:10:13 -07:00
NETuint8_t ( & index ) ;
2008-02-02 06:45:17 -08:00
NETend ( ) ;
2007-06-28 10:47:08 -07:00
2007-08-08 11:50:28 -07:00
for ( j = 0 ; j < MAX_CONNECTED_PLAYERS ; + + j )
2007-07-24 12:33:46 -07:00
{
2007-06-28 10:47:08 -07:00
NETBroadcastPlayerInfo ( j ) ;
}
2007-04-21 06:46:28 -07:00
// Make sure the master server gets updated by disconnecting from it
// NETallowJoining will reconnect
NETregisterServer ( 0 ) ;
2009-04-19 11:45:28 -07:00
// if this is a password locked game then ask for password.
if ( NetPlay . GamePassworded )
{
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Requesting password from %u " , index ) ;
NETbeginEncode ( NET_REQUEST_PASSWORD , index ) ;
2009-04-19 11:45:28 -07:00
NETend ( ) ;
}
2009-04-10 21:41:14 -07:00
// and now, request version from new person
2009-06-07 11:10:13 -07:00
NETbeginEncode ( NET_REQUEST_VERSION , index ) ;
2009-04-10 21:41:14 -07:00
NETend ( ) ;
2009-06-07 11:10:13 -07:00
NetPlay . players [ index ] . versionCheckTime = gameTime2 ; // Time we sent the msg
2009-04-10 21:41:14 -07:00
// add 7 sec delay factor for lag/slow modems?
2009-06-07 11:10:13 -07:00
NetPlay . players [ index ] . versionCheckTime + = GAME_TICKS_PER_SEC * 7 ;
debug ( LOG_NET , " Requesting Version check @(+7) %u from %u " , NetPlay . players [ index ] . versionCheckTime , index ) ;
2007-06-28 10:47:08 -07:00
}
}
}
}
}
2006-11-03 17:11:26 -08:00
BOOL NEThostGame ( const char * SessionName , const char * PlayerName ,
2006-11-04 15:16:51 -08:00
SDWORD one , SDWORD two , SDWORD three , SDWORD four ,
2007-06-28 10:47:08 -07:00
UDWORD plyrs ) // # of players.
{
unsigned int i ;
2007-07-25 08:31:27 -07:00
debug ( LOG_NET , " NEThostGame(%s, %s, %d, %d, %d, %d, %u) " , SessionName , PlayerName ,
one , two , three , four , plyrs ) ;
2006-08-23 08:27:20 -07:00
2009-06-07 11:10:13 -07:00
NET_InitPlayers ( ) ;
NetPlay . maxPlayers = MAX_PLAYERS ;
2007-06-28 10:47:08 -07:00
if ( ! NetPlay . bComms )
{
2009-06-07 11:10:13 -07:00
selectedPlayer = 0 ;
NetPlay . isHost = true ;
NetPlay . players [ 0 ] . allocated = true ;
NetPlay . players [ 0 ] . connection = - 1 ;
NetPlay . playercount = 1 ;
debug ( LOG_NET , " Hosting but no comms " ) ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2009-02-21 14:09:58 -08:00
// tcp_socket is the connection to the lobby server (or machine)
2009-05-03 08:16:03 -07:00
if ( ! tcp_socket )
2009-05-03 08:35:50 -07:00
tcp_socket = socketListen ( gameserver_port ) ;
2007-07-25 08:31:27 -07:00
if ( tcp_socket = = NULL )
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot connect to master self: %s " , strSockError ( getSockErr ( ) ) ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2008-04-11 11:35:53 -07:00
debug ( LOG_NET , " New tcp_socket = %p " , tcp_socket ) ;
2009-02-21 14:09:58 -08:00
// Host needs to create a socket set for MAX_PLAYERS
2009-05-03 08:16:03 -07:00
if ( ! socket_set ) socket_set = allocSocketSet ( MAX_CONNECTED_PLAYERS ) ;
2007-07-25 08:31:27 -07:00
if ( socket_set = = NULL )
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot create socket set: %s " , strSockError ( getSockErr ( ) ) ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2009-02-21 14:09:58 -08:00
// allocate socket storage for all possible players
2007-07-25 08:31:27 -07:00
for ( i = 0 ; i < MAX_CONNECTED_PLAYERS ; + + i )
{
2007-06-28 10:47:08 -07:00
connected_bsocket [ i ] = NET_createBufferedSocket ( ) ;
}
2009-06-07 11:10:13 -07:00
NetPlay . isHost = true ;
2007-06-28 10:47:08 -07:00
2008-05-25 06:46:49 -07:00
sstrcpy ( game . name , SessionName ) ;
2008-05-02 14:19:15 -07:00
memset ( & game . desc , 0 , sizeof ( game . desc ) ) ;
game . desc . dwSize = sizeof ( game . desc ) ;
2007-06-28 10:47:08 -07:00
//game.desc.guidApplication = GAME_GUID;
2009-05-09 10:22:44 -07:00
memset ( game . desc . host , 0 , sizeof ( game . desc . host ) ) ;
2007-06-28 10:47:08 -07:00
game . desc . dwCurrentPlayers = 1 ;
game . desc . dwMaxPlayers = plyrs ;
game . desc . dwFlags = 0 ;
2008-10-14 05:58:59 -07:00
game . desc . dwUserFlags [ 0 ] = one ;
game . desc . dwUserFlags [ 1 ] = two ;
game . desc . dwUserFlags [ 2 ] = three ;
game . desc . dwUserFlags [ 3 ] = four ;
2009-05-09 10:22:44 -07:00
memset ( game . secondaryHosts , 0 , sizeof ( game . secondaryHosts ) ) ;
2009-04-19 11:45:28 -07:00
sstrcpy ( game . extra , " Extra " ) ; // extra string (future use)
sstrcpy ( game . versionstring , VersionString ) ; // version (string)
sstrcpy ( game . modlist , " Mod list " ) ; // List of mods
2009-05-09 10:22:44 -07:00
game . GAMESTRUCT_VERSION = 3 ; // version of this structure
2009-04-19 11:45:28 -07:00
game . game_version_major = NETCODE_VERSION_MAJOR ; // Netcode Major version
game . game_version_minor = NETCODE_VERSION_MINOR ; // NetCode Minor version
// game.privateGame = 0; // if true, it is a private game
game . pureGame = 0 ; // NO mods allowed if true
game . Mods = 0 ; // number of concatenated mods?
2009-05-09 10:22:44 -07:00
game . gameId = 0 ;
2009-04-19 11:45:28 -07:00
game . future2 = 0xBAD02 ; // for future use
game . future3 = 0xBAD03 ; // for future use
game . future4 = 0xBAD04 ; // for future use
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
selectedPlayer = NET_CreatePlayer ( PlayerName ) ;
NetPlay . isHost = true ;
NetPlay . hostPlayer = NET_HOST_ONLY ;
ASSERT ( selectedPlayer = = NET_HOST_ONLY , " For now, host must start at player index zero, was %d " , ( int ) selectedPlayer ) ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
MultiPlayerJoin ( selectedPlayer ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
allow_joining = true ;
2007-06-28 10:47:08 -07:00
2005-12-02 13:45:42 -08:00
NETregisterServer ( 0 ) ;
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Hosting a server. We are player %d. " , selectedPlayer ) ;
2008-02-11 09:19:12 -08:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////
// Stop the dplay interface from accepting more players.
2006-09-13 02:09:05 -07:00
BOOL NEThaltJoining ( void )
2007-06-28 10:47:08 -07:00
{
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " temporarily locking game to prevent more players " ) ;
2006-08-23 08:27:20 -07:00
2008-03-24 09:51:17 -07:00
allow_joining = false ;
2007-04-21 06:46:28 -07:00
// disconnect from the master server
NETregisterServer ( 0 ) ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////
2007-05-13 10:31:12 -07:00
// find games on open connection
2007-05-20 06:51:53 -07:00
BOOL NETfindGame ( void )
2007-06-28 10:47:08 -07:00
{
2009-05-03 08:16:03 -07:00
struct addrinfo * cur ;
struct addrinfo * hosts ;
2008-02-03 08:39:49 -08:00
unsigned int gamecount = 0 ;
uint32_t gamesavailable ;
2007-04-21 06:46:28 -07:00
unsigned int port = ( hostname = = masterserver_name ) ? masterserver_port : gameserver_port ;
2008-04-11 11:35:53 -07:00
int result = 0 ;
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Looking for games... " ) ;
2009-04-10 11:26:55 -07:00
2009-04-19 11:45:28 -07:00
if ( getLobbyError ( ) > ERROR_CONNECTION )
{
return false ;
}
setLobbyError ( ERROR_NOERROR ) ;
2006-08-23 08:27:20 -07:00
2007-06-28 10:47:08 -07:00
NetPlay . games [ 0 ] . desc . dwSize = 0 ;
NetPlay . games [ 0 ] . desc . dwCurrentPlayers = 0 ;
NetPlay . games [ 0 ] . desc . dwMaxPlayers = 0 ;
if ( ! NetPlay . bComms )
{
2009-06-07 11:10:13 -07:00
selectedPlayer = NET_HOST_ONLY ; // Host is always 0
NetPlay . isHost = true ;
NetPlay . hostPlayer = NET_HOST_ONLY ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2008-05-11 12:53:27 -07:00
// We first check to see if we were given a IP/hostname from the command line
2008-05-11 12:09:29 -07:00
if ( strlen ( iptoconnect ) )
{
2009-05-03 08:16:03 -07:00
hosts = resolveHost ( iptoconnect , port ) ;
if ( hosts = = NULL )
2008-05-11 12:09:29 -07:00
{
debug ( LOG_ERROR , " Error connecting to client via hostname provided (%s) " , iptoconnect ) ;
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot resolve hostname :%s " , strSockError ( getSockErr ( ) ) ) ;
2009-04-19 11:45:28 -07:00
setLobbyError ( ERROR_CONNECTION ) ;
2008-05-11 12:09:29 -07:00
return false ;
}
else
{
2008-05-11 12:53:27 -07:00
// We got a valid ip now
2008-05-11 12:09:29 -07:00
hostname = strdup ( iptoconnect ) ; //copy it
2008-05-11 12:53:27 -07:00
memset ( iptoconnect , 0x0 , sizeof ( iptoconnect ) ) ; //reset it (so we don't loop back to this routine)
2008-05-11 12:09:29 -07:00
}
}
2009-05-03 08:16:03 -07:00
else if ( ( hosts = resolveHost ( hostname , port ) ) = = NULL )
2007-07-25 08:31:27 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot resolve hostname \" %s \" : %s " , hostname , strSockError ( getSockErr ( ) ) ) ;
2009-04-19 11:45:28 -07:00
setLobbyError ( ERROR_CONNECTION ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2007-07-25 08:31:27 -07:00
if ( tcp_socket ! = NULL )
{
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Deleting tcp_socket %p " , tcp_socket ) ;
2009-05-03 08:16:03 -07:00
delSocket ( socket_set , tcp_socket ) ;
2009-05-03 08:35:50 -07:00
socketClose ( tcp_socket ) ;
2008-04-11 11:35:53 -07:00
tcp_socket = NULL ;
2007-06-28 10:47:08 -07:00
}
2009-05-03 08:16:03 -07:00
for ( cur = hosts ; cur ; cur = cur - > ai_next )
{
tcp_socket = SocketOpen ( cur , 15000 ) ;
if ( tcp_socket )
break ;
}
2007-07-25 08:31:27 -07:00
if ( tcp_socket = = NULL )
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot connect to \" %s:%d \" : %s " , hostname , port , strSockError ( getSockErr ( ) ) ) ;
2009-04-19 11:45:28 -07:00
setLobbyError ( ERROR_CONNECTION ) ;
2009-05-03 08:16:03 -07:00
freeaddrinfo ( hosts ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2008-04-11 11:35:53 -07:00
debug ( LOG_NET , " New tcp_socket = %p " , tcp_socket ) ;
2009-02-21 14:09:58 -08:00
// client machines only need 1 socket set
2009-05-03 08:16:03 -07:00
socket_set = allocSocketSet ( 1 ) ;
2007-07-25 08:31:27 -07:00
if ( socket_set = = NULL )
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot create socket set: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-04-19 11:45:28 -07:00
setLobbyError ( ERROR_CONNECTION ) ;
2009-05-03 08:16:03 -07:00
freeaddrinfo ( hosts ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Created socket_set %p " , socket_set ) ;
2009-05-03 08:16:03 -07:00
addSocket ( socket_set , tcp_socket ) ;
2007-06-28 10:47:08 -07:00
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Sending list cmd " ) ;
2009-05-03 08:35:50 -07:00
writeAll ( tcp_socket , " list " , sizeof ( " list " ) ) ;
2006-02-18 10:54:37 -08:00
2009-06-10 20:51:37 -07:00
if ( checkSockets ( socket_set , NET_TIMEOUT_DELAY ) > 0
2009-05-03 08:16:03 -07:00
& & tcp_socket - > ready
2009-05-03 08:35:50 -07:00
& & ( result = readNoInt ( tcp_socket , & gamesavailable , sizeof ( gamesavailable ) ) ) )
2007-07-25 08:31:27 -07:00
{
2009-05-03 08:16:03 -07:00
gamesavailable = ntohl ( gamesavailable ) ;
2007-06-28 10:47:08 -07:00
}
2008-02-11 11:51:24 -08:00
else
{
2009-05-03 08:17:05 -07:00
if ( result = = SOCKET_ERROR )
2008-04-11 11:35:53 -07:00
{
2009-05-03 08:35:50 -07:00
debug ( LOG_NET , " Server socket ecountered error: %s " , strSockError ( getSockErr ( ) ) ) ;
2008-04-11 11:35:53 -07:00
}
2009-05-09 10:22:44 -07:00
else
{
debug ( LOG_NET , " Server didn't respond (timeout) " ) ;
}
socketClose ( tcp_socket ) ;
tcp_socket = NULL ;
2008-02-11 11:51:24 -08:00
// when we fail to receive a game count, bail out
2009-04-19 11:45:28 -07:00
setLobbyError ( ERROR_CONNECTION ) ;
2009-05-03 08:16:03 -07:00
freeaddrinfo ( hosts ) ;
2008-03-24 09:51:17 -07:00
return false ;
2008-02-11 11:51:24 -08:00
}
2007-06-28 10:47:08 -07:00
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " receiving info on %u game(s) " , ( unsigned int ) gamesavailable ) ;
2006-02-18 10:54:37 -08:00
2008-02-03 08:39:49 -08:00
do
{
// Attempt to receive a game description structure
2008-02-11 13:20:25 -08:00
if ( ! NETrecvGAMESTRUCT ( & NetPlay . games [ gamecount ] ) )
2009-05-03 08:16:03 -07:00
{
2009-07-13 13:09:57 -07:00
debug ( LOG_NET , " only %u game(s) received " , ( unsigned int ) gamecount ) ;
2008-02-11 13:20:25 -08:00
// If we fail, success depends on the amount of games that we've read already
2009-05-03 08:16:03 -07:00
freeaddrinfo ( hosts ) ;
2008-02-11 13:20:25 -08:00
return gamecount ;
2009-05-03 08:16:03 -07:00
}
2005-12-02 13:45:42 -08:00
2008-02-11 13:20:25 -08:00
if ( NetPlay . games [ gamecount ] . desc . host [ 0 ] = = ' \0 ' )
{
2009-05-03 08:52:37 -07:00
addressToText ( cur - > ai_addr , NetPlay . games [ gamecount ] . desc . host , sizeof ( NetPlay . games [ gamecount ] . desc . host ) ) ;
2005-12-02 13:45:42 -08:00
}
2008-02-11 13:20:25 -08:00
+ + gamecount ;
2008-02-03 08:39:49 -08:00
} while ( gamecount < gamesavailable ) ;
2007-06-28 10:47:08 -07:00
2009-05-03 08:16:03 -07:00
freeaddrinfo ( hosts ) ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
// Functions used to setup and join games.
2006-11-03 17:11:26 -08:00
BOOL NETjoinGame ( UDWORD gameNumber , const char * playername )
2007-06-28 10:47:08 -07:00
{
2009-05-03 08:16:03 -07:00
struct addrinfo * cur ;
struct addrinfo * hosts ;
2009-05-09 10:22:44 -07:00
unsigned int i ;
2006-02-18 10:54:37 -08:00
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " resetting sockets. " ) ;
2005-12-02 13:45:42 -08:00
NETclose ( ) ; // just to be sure :)
2006-02-18 10:54:37 -08:00
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Trying to join gameNumber (%u)... " , gameNumber ) ;
2009-05-09 10:22:44 -07:00
if ( hostname = = masterserver_name )
2007-07-25 08:31:27 -07:00
{
2009-05-09 10:22:44 -07:00
hostname = NULL ;
2005-12-02 13:45:42 -08:00
}
2006-02-18 10:54:37 -08:00
2009-05-09 10:22:44 -07:00
// Loop through all of the hosts, using the first one we can connect to.
for ( i = 0 ; i < ARRAY_SIZE ( NetPlay . games [ gameNumber ] . secondaryHosts ) + 1 ; + + i )
2007-07-25 08:31:27 -07:00
{
2009-05-09 10:22:44 -07:00
free ( hostname ) ;
if ( i > 0 )
hostname = strdup ( NetPlay . games [ gameNumber ] . secondaryHosts [ i - 1 ] ) ;
else
hostname = strdup ( NetPlay . games [ gameNumber ] . desc . host ) ;
2006-02-18 10:54:37 -08:00
2009-05-09 10:22:44 -07:00
hosts = resolveHost ( hostname , gameserver_port ) ;
if ( hosts = = NULL )
{
debug ( LOG_ERROR , " Cannot resolve hostname \" %s \" : %s " , hostname , strSockError ( getSockErr ( ) ) ) ;
continue ;
}
2009-05-03 08:16:03 -07:00
2009-05-09 10:22:44 -07:00
if ( tcp_socket ! = NULL )
{
socketClose ( tcp_socket ) ;
}
for ( cur = hosts ; cur ; cur = cur - > ai_next )
{
tcp_socket = SocketOpen ( cur , 15000 ) ;
if ( tcp_socket )
goto connect_succesfull ;
}
freeaddrinfo ( hosts ) ;
2005-12-02 13:45:42 -08:00
}
2009-05-09 10:22:44 -07:00
if ( tcp_socket = = NULL )
2007-07-25 08:31:27 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2005-12-02 13:45:42 -08:00
}
2009-05-09 10:22:44 -07:00
connect_succesfull :
2009-02-21 14:09:58 -08:00
// client machines only need 1 socket set
2009-05-03 08:16:03 -07:00
socket_set = allocSocketSet ( 1 ) ;
2007-07-25 08:31:27 -07:00
if ( socket_set = = NULL )
{
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Cannot create socket set: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-05-03 08:16:03 -07:00
freeaddrinfo ( hosts ) ;
2008-03-24 09:51:17 -07:00
return false ;
2005-12-02 13:45:42 -08:00
}
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " Created socket_set %p " , socket_set ) ;
// tcp_socket is used to talk to host machine
2009-05-03 08:16:03 -07:00
addSocket ( socket_set , tcp_socket ) ;
2005-12-02 13:45:42 -08:00
2009-05-03 08:35:50 -07:00
writeAll ( tcp_socket , " join " , sizeof ( " join " ) ) ;
2006-02-18 10:54:37 -08:00
2008-02-03 08:39:49 -08:00
if ( NETrecvGAMESTRUCT ( & NetPlay . games [ gameNumber ] )
& & NetPlay . games [ gameNumber ] . desc . host [ 0 ] = = ' \0 ' )
2007-07-25 08:31:27 -07:00
{
2009-05-03 08:52:37 -07:00
addressToText ( cur - > ai_addr , NetPlay . games [ gameNumber ] . desc . host , sizeof ( NetPlay . games [ gameNumber ] . desc . host ) ) ;
2005-12-02 13:45:42 -08:00
}
2009-05-03 08:16:03 -07:00
freeaddrinfo ( hosts ) ;
2009-02-21 14:09:58 -08:00
// Allocate memory for a new socket
2007-06-28 10:47:08 -07:00
bsocket = NET_createBufferedSocket ( ) ;
2009-02-21 14:09:58 -08:00
// NOTE: tcp_socket = bsocket->socket now!
2007-06-28 10:47:08 -07:00
NET_initBufferedSocket ( bsocket , tcp_socket ) ;
2009-06-07 11:10:13 -07:00
// Send a join message to the host
NETbeginEncode ( NET_JOIN , NET_HOST_ONLY ) ;
2008-02-02 06:45:24 -08:00
// Casting constness away, because NETstring is const-incorrect
// when sending/encoding a packet.
NETstring ( ( char * ) playername , 64 ) ;
NETend ( ) ;
2007-06-28 10:47:08 -07:00
2008-02-02 06:45:17 -08:00
// Loop until we've been accepted into the game
2007-07-25 08:31:27 -07:00
for ( ; ; )
{
2008-03-24 12:24:07 -07:00
uint8_t type = NUM_GAME_PACKETS ;
2007-06-28 10:47:08 -07:00
2008-02-13 12:25:12 -08:00
NETrecv ( & type ) ;
2008-02-15 12:55:38 -08:00
if ( type = = NET_ACCEPTED )
2007-07-24 12:33:46 -07:00
{
2009-06-07 11:10:13 -07:00
uint8_t index ;
2008-02-15 12:55:38 -08:00
NETbeginDecode ( NET_ACCEPTED ) ;
2008-02-02 06:45:17 -08:00
// Retrieve the player ID the game host arranged for us
2009-06-07 11:10:13 -07:00
NETuint8_t ( & index ) ;
2008-02-02 06:45:17 -08:00
NETend ( ) ;
2009-06-07 11:10:13 -07:00
selectedPlayer = index ;
2009-02-21 14:09:58 -08:00
debug ( LOG_NET , " NET_ACCEPTED received. Accepted into the game - I'm player %u using bsocket %p, tcp_socket=%p " ,
2009-06-07 11:10:13 -07:00
( unsigned int ) index , bsocket - > socket , tcp_socket ) ;
NetPlay . isHost = false ;
2007-06-28 10:47:08 -07:00
2009-06-07 11:10:13 -07:00
if ( index > = MAX_CONNECTED_PLAYERS )
2007-07-22 04:12:50 -07:00
{
2009-06-07 11:10:13 -07:00
debug ( LOG_ERROR , " Bad player number (%u) received from host! " , index ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-07-22 04:12:50 -07:00
}
2008-02-02 06:45:17 -08:00
2009-06-07 11:10:13 -07:00
NetPlay . players [ index ] . allocated = true ;
sstrcpy ( NetPlay . players [ index ] . name , playername ) ;
NetPlay . players [ index ] . heartbeat = true ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
}
}
2007-04-21 06:46:28 -07:00
/*!
* Set the masterserver name
* \ param hostname The hostname of the masterserver to connect to
*/
void NETsetMasterserverName ( const char * hostname )
{
2008-05-25 06:46:49 -07:00
sstrcpy ( masterserver_name , hostname ) ;
2007-04-21 06:46:28 -07:00
}
2009-04-19 18:56:53 -07:00
/**
* @ return The hostname of the masterserver we will connect to .
*/
const char * NETgetMasterserverName ( )
{
return masterserver_name ;
}
2007-04-21 06:46:28 -07:00
/*!
* Set the masterserver port
* \ param port The port of the masterserver to connect to
*/
void NETsetMasterserverPort ( unsigned int port )
{
masterserver_port = port ;
}
2009-04-19 18:56:53 -07:00
/**
* @ return The port of the masterserver we will connect to .
*/
unsigned int NETgetMasterserverPort ( )
{
return masterserver_port ;
}
2007-04-21 06:46:28 -07:00
/*!
* Set the port we shall host games on
* \ param port The port to listen to
*/
void NETsetGameserverPort ( unsigned int port )
{
gameserver_port = port ;
}
2009-04-19 18:56:53 -07:00
/**
* @ return The port we will host games on .
*/
unsigned int NETgetGameserverPort ( )
{
return gameserver_port ;
}