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"
2009-11-28 13:18:34 -08:00
# include "src/component.h" // FIXME: we need to handle this better
2010-01-17 12:12:03 -08:00
# include "src/modding.h" // FIXME: we need to handle this better
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>
2009-11-29 11:09:44 -08:00
# include <SDL_thread.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-11-21 11:04:16 -08:00
# include "miniupnpc/miniwget.h"
# include "miniupnpc/miniupnpc.h"
# include "miniupnpc/upnpcommands.h"
2009-11-28 13:18:34 -08:00
# include "lib/exceptionhandler/dumpinfo.h"
2009-11-21 11:04:16 -08:00
2010-02-28 15:24:38 -08:00
# include "src/multistat.h"
# include "src/multijoin.h"
# include "src/multiint.h"
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>
2010-02-20 15:10:36 -08:00
# include <sys / ioctl.h>
2009-05-03 08:16:49 -07:00
# include <sys / socket.h>
# include <sys / types.h>
2009-12-13 12:25:00 -08:00
# include <sys / select.h>
2009-05-03 08:16:49 -07:00
# 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-12-20 12:16:17 -08:00
# undef EBADF
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-12-20 12:16:17 -08:00
# define EBADF WSAEBADF
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
2010-02-20 15:55:23 -08:00
// Fallback for systems that don't #define this flag
# ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL 0
# endif
2009-05-03 08:16:49 -07:00
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 ' } ;
2010-01-16 16:20:54 -08:00
static unsigned int masterserver_port = 0 , gameserver_port = 0 ;
2007-04-21 06:46:28 -07:00
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
/*
2009-11-26 10:20:40 -08:00
* = = = Using new socket code , this might not hold true any longer = = =
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 .
2009-11-26 10:20:40 -08:00
* reference : MaxMsgSize in netplay . h ( currently set to 16 K )
2009-03-20 12:28:04 -07:00
*
*/
2009-11-26 10:20:40 -08:00
# define NET_BUFFER_SIZE (MaxMsgSize) // Would be 16K
2007-06-28 10:47:08 -07:00
2007-07-25 08:31:27 -07:00
// ////////////////////////////////////////////////////////////////////////
// Function prototypes
2010-02-01 12:26:49 -08:00
static void NETplayerLeaving ( UDWORD player ) ; // Cleanup sockets on player leaving (nicely)
static void NETplayerDropped ( UDWORD player ) ; // Broadcast NET_PLAYER_DROPPED & cleanup
2010-01-04 21:34:17 -08:00
static void NETregisterServer ( int state ) ;
2006-09-13 14:14:47 -07:00
static void NETallowJoining ( void ) ;
2010-02-28 15:24:38 -08:00
static void NET_InitPlayer ( int i , bool initPosition ) ;
2009-04-19 11:45:28 -07:00
2007-08-08 11:50:28 -07:00
/*
* Network globals , these are part of the new network API
*/
NETMSG NetMsg ;
2010-01-30 20:45:20 -08:00
SYNC_COUNTER sync_counter ; // keeps track on how well we are in sync
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
// ////////////////////////////////////////////////////////////////////////
// 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 ;
2009-12-18 16:12:33 -08:00
static GAMESTRUCT gamestruct ;
2009-04-30 17:01:13 -07:00
2009-12-03 21:50:40 -08:00
// update flags
bool netPlayersUpdated ;
int mapDownloadProgress ;
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
2009-11-21 11:04:16 -08:00
// UPnP
static int upnp = false ;
2009-11-29 11:09:44 -08:00
static bool upnp_done = false ;
SDL_Thread * upnpdiscover ;
2009-11-21 11:04:16 -08:00
static struct UPNPUrls urls ;
static struct IGDdatas data ;
// local ip address
static char lanaddr [ 16 ] ;
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
// ////////////////////////////////////////////////////////////////////////////
# define VersionStringSize 80
/************************************************************************************
* * NOTE ( ! ) Change the VersionString when net code changes ! !
* * ie ( " trunk " , " 2.1.3 " , . . . )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* */
2010-01-10 02:03:50 -08:00
char VersionString [ VersionStringSize ] = " trunk, netcode 3.32 " ;
2010-01-17 12:12:03 -08:00
static int NETCODE_VERSION_MAJOR = 2 ;
2010-01-22 12:39:01 -08:00
static int NETCODE_VERSION_MINOR = 35 ;
2009-04-10 21:41:14 -07:00
static int NETCODE_HASH = 0 ; // unused for now
2010-02-20 15:10:36 -08:00
static int checkSockets ( const SocketSet * set , unsigned int timeout ) ;
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
}
2010-02-21 07:00:47 -08:00
/**
* Test whether the given socket still has an open connection .
*
* @ return true when the connection is open , false when it ' s closed or in an
* error state , check getSockErr ( ) to find out which .
*/
static bool connectionIsOpen ( Socket * sock )
{
Socket * sockAr [ ] = { sock } ;
const SocketSet set = { ARRAY_SIZE ( sockAr ) , sockAr } ;
int ret ;
ASSERT_OR_RETURN ( ( setSockErr ( EBADF ) , false ) ,
sock & & sock - > fd [ SOCK_CONNECTION ] ! = INVALID_SOCKET , " Invalid socket " ) ;
// Check whether the socket is still connected
ret = checkSockets ( & set , 0 ) ;
if ( ret = = SOCKET_ERROR )
{
return false ;
}
else if ( ret = = set . len
& & sock - > ready )
{
/* The next recv(2) call won't block, but we're writing. So
* check the read queue to see if the connection is closed .
* If there ' s no data in the queue that means the connection
* is closed .
*/
# if defined(WZ_OS_WIN)
unsigned long readQueue ;
ret = ioctlsocket ( sock - > fd [ SOCK_CONNECTION ] , FIONREAD , & readQueue ) ;
# else
int readQueue ;
ret = ioctl ( sock - > fd [ SOCK_CONNECTION ] , FIONREAD , & readQueue ) ;
# endif
if ( ret = = SOCKET_ERROR )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " socket error " ) ;
2010-02-21 07:00:47 -08:00
return false ;
}
else if ( readQueue = = 0 )
{
// Disconnected
setSockErr ( ECONNRESET ) ;
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Read queue empty - failing (ECONNRESET) " ) ;
2010-02-21 07:00:47 -08:00
return false ;
}
}
return true ;
}
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-12-20 12:16:17 -08:00
if ( sock - > fd [ SOCK_CONNECTION ] = = INVALID_SOCKET )
{
debug ( LOG_ERROR , " Invalid socket " ) ;
setSockErr ( EBADF ) ;
return SOCKET_ERROR ;
}
2010-01-31 13:30:07 -08:00
do
2009-05-03 08:16:03 -07:00
{
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 ;
2009-12-20 12:16:17 -08:00
if ( ! sock
| | sock - > fd [ SOCK_CONNECTION ] = = INVALID_SOCKET )
2009-12-18 16:37:09 -08:00
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " Invalid socket (EBADF) " ) ;
2009-12-20 12:16:17 -08:00
setSockErr ( EBADF ) ;
2009-12-18 16:37:09 -08:00
return SOCKET_ERROR ;
}
2009-05-03 08:16:03 -07:00
while ( written < size )
{
2010-02-20 15:10:36 -08:00
ssize_t ret ;
2010-02-20 15:55:23 -08:00
ret = send ( sock - > fd [ SOCK_CONNECTION ] , & ( ( char * ) buf ) [ written ] , size - written , MSG_NOSIGNAL ) ;
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 :
2010-02-20 14:55:39 -08:00
# if defined(EWOULDBLOCK) && EAGAIN != EWOULDBLOCK
case EWOULDBLOCK :
# endif
2010-02-21 15:07:36 -08:00
if ( ! connectionIsOpen ( sock ) )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Socket error " ) ;
2010-02-21 15:07:36 -08:00
return SOCKET_ERROR ;
}
2009-05-03 08:16:03 -07:00
case EINTR :
continue ;
2010-02-21 15:52:58 -08:00
# if defined(EPIPE)
2010-02-21 15:07:36 -08:00
case EPIPE :
debug ( LOG_NET , " EPIPE generated " ) ;
// fall through
2010-02-21 15:52:58 -08:00
# endif
2009-05-03 08:16:03 -07:00
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 ;
}
/**
2009-12-20 14:40:12 -08:00
* Add the given socket to the given socket set .
*
2009-05-03 08:16:03 -07:00
* @ return true if @ c socket is succesfully added to @ set .
*/
2010-02-21 12:26:27 -08:00
static bool SocketSet_AddSocket ( SocketSet * set , Socket * socket )
2009-05-03 08:16:03 -07:00
{
size_t i ;
2010-02-21 15:25:52 -08:00
ASSERT_OR_RETURN ( false , set ! = NULL , " NULL SocketSet provided " ) ;
ASSERT_OR_RETURN ( false , socket ! = NULL , " NULL Socket provided " ) ;
2009-05-03 08:16:03 -07:00
/* 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 )
2010-02-23 21:07:09 -08:00
{
debug ( LOG_NET , " Already found, socket: (set->fds[%lu]) %p " , ( unsigned long ) i , socket ) ;
2009-05-03 08:16:03 -07:00
return true ;
2010-02-23 21:07:09 -08:00
}
2009-05-03 08:16:03 -07:00
}
for ( i = 0 ; i < set - > len ; + + i )
{
if ( set - > fds [ i ] = = NULL )
{
set - > fds [ i ] = socket ;
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Socket added: set->fds[%lu] = %p " , ( unsigned long ) i , socket ) ;
2009-05-03 08:16:03 -07:00
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 ;
}
/**
2009-12-20 14:40:12 -08:00
* Remove the given socket from the given socket set .
2009-05-03 08:16:03 -07:00
*/
2010-02-21 12:26:27 -08:00
static void SocketSet_DelSocket ( SocketSet * set , Socket * socket )
2009-05-03 08:16:03 -07:00
{
size_t i ;
2010-01-09 07:45:12 -08:00
ASSERT_OR_RETURN ( , set ! = NULL , " NULL SocketSet provided " ) ;
2010-02-21 15:25:52 -08:00
ASSERT_OR_RETURN ( , socket ! = NULL , " NULL Socket provided " ) ;
2009-05-03 08:16:03 -07:00
for ( i = 0 ; i < set - > len ; + + i )
{
if ( set - > fds [ i ] = = socket )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Socket %p nullified (set->fds[%lu]) " , socket , ( unsigned long ) i ) ;
2009-05-03 08:16:03 -07:00
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 ;
}
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Socket is set to %sblocking. " , ( blocking ? " " : " non- " ) ) ;
2009-05-03 08:16:49 -07:00
return true ;
}
2010-02-21 07:02:05 -08:00
static void socketBlockSIGPIPE ( const SOCKET fd , bool block_sigpipe )
{
# if defined(SO_NOSIGPIPE)
const int no_sigpipe = block_sigpipe ? 1 : 0 ;
if ( setsockopt ( fd , SOL_SOCKET , SO_NOSIGPIPE , & no_sigpipe , sizeof ( no_sigpipe ) ) = = SOCKET_ERROR )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_INFO , " Failed to set SO_NOSIGPIPE on socket, SIGPIPE might be raised when connections gets broken. Error: %s " , strSockError ( getSockErr ( ) ) ) ;
2010-02-21 07:02:05 -08:00
}
2010-02-23 21:07:09 -08:00
// this is only for unix, windows don't have SIGPIPE
debug ( LOG_NET , " Socket fd %x sets SIGPIPE to %sblocked. " , fd , ( block_sigpipe ? " " : " non- " ) ) ;
2010-02-21 07:02:05 -08:00
# else
// Prevent warnings
( void ) fd ;
( void ) block_sigpipe ;
# endif
}
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 ;
2010-01-30 13:26:41 -08:00
do
2009-05-03 08:16:03 -07:00
{
struct timeval tv = { timeout / 1000 , ( timeout % 1000 ) * 1000 } ;
FD_ZERO ( & fds ) ;
for ( i = 0 ; i < set - > len ; + + i )
{
if ( set - > fds [ i ] )
2010-02-21 12:13:16 -08:00
{
const SOCKET fd = set - > fds [ i ] - > fd [ SOCK_CONNECTION ] ;
FD_SET ( fd , & 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 ;
2009-12-20 12:16:17 -08:00
if ( ! sock
| | sock - > fd [ SOCK_CONNECTION ] = = INVALID_SOCKET )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " Invalid socket (%p), sock->fd[SOCK_CONNECTION]=%x (error: EBADF) " , sock , sock - > fd [ SOCK_CONNECTION ] ) ;
2009-12-20 12:16:17 -08:00
setSockErr ( EBADF ) ;
return SOCKET_ERROR ;
}
2009-05-04 14:52:01 -07:00
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 )
2010-02-23 21:07:09 -08:00
{
debug ( LOG_NET , " socket (%p) has timed out. " , socket ) ;
2009-05-04 14:52:01 -07:00
setSockErr ( ETIMEDOUT ) ;
2010-02-23 21:07:09 -08:00
}
debug ( LOG_NET , " socket (%p) error. " , socket ) ;
2009-05-04 14:52:01 -07:00
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 )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Socket %x disconnected. " , sock - > fd [ SOCK_CONNECTION ] ) ;
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 EAGAIN :
2010-02-20 14:55:39 -08:00
# if defined(EWOULDBLOCK) && EAGAIN != EWOULDBLOCK
case EWOULDBLOCK :
# endif
case EINTR :
2009-05-04 14:52:01 -07:00
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 ;
2009-11-26 15:41:16 -08:00
int err = 0 ;
2009-05-09 10:20:32 -07:00
2009-11-26 15:41:16 -08:00
if ( sock )
{
2009-12-18 17:36:26 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( sock - > fd ) ; + + i )
2009-05-09 10:20:32 -07:00
{
2009-12-18 17:36:26 -08:00
if ( sock - > fd [ i ] ! = INVALID_SOCKET )
{
2009-05-03 08:21:44 -07:00
# if defined(WZ_OS_WIN)
2009-11-26 15:41:16 -08:00
err = closesocket ( sock - > fd [ i ] ) ;
2009-05-03 08:21:44 -07:00
# else
2009-11-26 15:41:16 -08:00
err = close ( sock - > fd [ i ] ) ;
2009-05-03 08:21:44 -07:00
# endif
2009-11-26 15:41:16 -08:00
if ( err )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " Failed to close socket %p: %s " , sock , strSockError ( getSockErr ( ) ) ) ;
2009-12-18 17:36:26 -08:00
}
2009-12-20 12:16:17 -08:00
/* Make sure that dangling pointers to this
* structure don ' t think they ' ve got their
* hands on a valid socket .
*/
sock - > fd [ i ] = INVALID_SOCKET ;
2009-12-18 17:36:26 -08:00
}
2009-05-09 10:20:32 -07:00
}
2009-11-26 15:41:16 -08:00
free ( sock ) ;
sock = NULL ;
2009-05-03 08:21:44 -07:00
}
}
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 )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " accept failed for socket %p: %s " , sock , strSockError ( getSockErr ( ) ) ) ;
2009-05-09 10:20:32 -07:00
}
continue ;
}
2009-05-03 08:49:56 -07:00
2010-02-21 07:02:05 -08:00
socketBlockSIGPIPE ( newConn , true ) ;
2010-02-20 15:55:23 -08: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 ) ) ;
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Using socket %p " , conn ) ;
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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " Failed to create a socket (%p): %s " , conn , strSockError ( getSockErr ( ) ) ) ;
2009-05-03 08:35:50 -07:00
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " setting socket (%p) blocking status (false). " , conn ) ;
2009-05-09 10:20:32 -07:00
if ( ! setSocketBlocking ( conn - > fd [ SOCK_CONNECTION ] , false ) )
2009-05-03 08:16:03 -07:00
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Couldn't set socket (%p) blocking status (false). Closing. " , conn ) ;
2009-05-03 08:35:50 -07:00
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
2010-02-21 07:02:05 -08:00
socketBlockSIGPIPE ( conn - > fd [ SOCK_CONNECTION ] , true ) ;
2010-02-20 15:55:23 -08:00
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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Failed to start connecting: %s, using socket %p " , strSockError ( getSockErr ( ) ) , conn ) ;
2009-05-03 08:35:50 -07:00
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
2010-01-31 13:30:07 -08:00
do
2009-05-03 08:16:03 -07:00
{
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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Failed to wait for connection: %s, socket %p. Closing. " , strSockError ( getSockErr ( ) ) , conn ) ;
2009-05-03 08:35:50 -07:00
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 ) ;
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Timed out while waiting for connection to be established: %s, using socket %p. Closing. " , strSockError ( getSockErr ( ) ) , conn ) ;
2009-05-03 08:35:50 -07:00
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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Failed to connect: %s, with socket %p. Closing. " , strSockError ( getSockErr ( ) ) , conn ) ;
2009-05-03 08:35:50 -07:00
socketClose ( conn ) ;
2009-05-03 08:16:03 -07:00
return NULL ;
}
}
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " setting socket (%p) blocking status (true). " , conn ) ;
2009-05-09 10:20:32 -07:00
if ( ! setSocketBlocking ( conn - > fd [ SOCK_CONNECTION ] , true ) )
2009-05-03 08:16:03 -07:00
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Failed to set socket %p blocking status (true). Closing. " , conn ) ;
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
*/
2010-02-20 15:55:23 -08:00
# if defined(IPV6_V6ONLY)
2009-05-24 15:01:08 -07:00
static const int ipv6_v6only = 0 ;
2010-02-20 15:55:23 -08:00
# endif
2010-02-21 07:01:46 -08:00
static const int so_reuseaddr = 1 ;
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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " Failed to create an IPv4 and IPv6 (only supported address families) socket (%p): %s. Closing. " , conn , 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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Successfully created an IPv4 socket (%p) " , conn ) ;
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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Successfully created an IPv6 socket (%p) " , conn ) ;
2009-05-25 02:21:06 -07:00
}
# 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 )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_INFO , " Failed to set IPv6 socket to perform IPv4 to IPv6 mapping. Falling back to using two sockets. Error: %s " , strSockError ( getSockErr ( ) ) ) ;
2009-05-25 02:21:06 -07:00
}
else
{
2009-12-08 14:17:42 -08:00
debug ( LOG_NET , " Successfully 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 )
{
2010-02-21 07:01:46 -08:00
if ( setsockopt ( conn - > fd [ SOCK_IPV4_LISTEN ] , SOL_SOCKET , SO_REUSEADDR , & so_reuseaddr , sizeof ( so_reuseaddr ) ) = = SOCKET_ERROR )
2010-01-22 08:14:57 -08:00
{
debug ( LOG_WARNING , " Failed to set SO_REUSEADDR on IPv4 socket. Error: %s " , strSockError ( getSockErr ( ) ) ) ;
}
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " setting socket (%p) blocking status (false, IPv4). " , conn ) ;
2009-05-24 15:01:08 -07:00
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 )
{
2010-02-21 07:01:46 -08:00
if ( setsockopt ( conn - > fd [ SOCK_IPV6_LISTEN ] , SOL_SOCKET , SO_REUSEADDR , & so_reuseaddr , sizeof ( so_reuseaddr ) ) = = SOCKET_ERROR )
2010-01-22 08:14:57 -08:00
{
2010-02-23 21:07:09 -08:00
debug ( LOG_INFO , " Failed to set SO_REUSEADDR on IPv6 socket. Error: %s " , strSockError ( getSockErr ( ) ) ) ;
2010-01-22 08:14:57 -08:00
}
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " setting socket (%p) blocking status (false, IPv6). " , conn ) ;
2009-05-24 15:01:08 -07:00
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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " No IPv4 or IPv6 sockets created. " ) ;
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 ;
2009-12-13 12:25:00 -08:00
int error , flags = 0 ;
2009-05-03 08:16:03 -07:00
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 ;
2009-12-13 12:25:00 -08:00
# ifdef AI_V4MAPPED
flags | = AI_V4MAPPED ;
# endif
# ifdef AI_ADDRCONFIG
flags | = AI_ADDRCONFIG ;
# endif
hint . ai_flags = flags ;
2009-05-03 08:16:49 -07:00
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 ;
}
2010-01-04 03:02:37 -08:00
bool NETisCorrectVersion ( uint32_t game_version_major , uint32_t game_version_minor )
{
return ( NETCODE_VERSION_MAJOR = = game_version_major & & NETCODE_VERSION_MINOR = = game_version_minor ) ;
}
bool NETgameIsCorrectVersion ( GAMESTRUCT * check_game )
{
return ( NETCODE_VERSION_MAJOR = = check_game - > game_version_major & & NETCODE_VERSION_MINOR = = check_game - > game_version_minor ) ;
}
2009-04-19 11:45:28 -07:00
// Sets if the game is password protected or not
void NETGameLocked ( bool flag )
{
NetPlay . GamePassworded = flag ;
2009-12-18 16:12:33 -08:00
gamestruct . privateGame = flag ;
2009-04-19 11:45:28 -07:00
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 )
{
2010-01-02 18:37:15 -08:00
sstrcpy ( NetPlay . gamePassword , _ ( " Enter password here " ) ) ;
debug ( LOG_NET , " password reset to 'Enter password here' " ) ;
2009-04-19 11:45:28 -07:00
NETGameLocked ( false ) ;
}
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
{
2009-12-20 13:13:21 -08:00
ssize_t size ;
2007-06-28 10:47:08 -07:00
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
2009-12-20 13:13:21 -08:00
if ( size ! = 0 & & size ! = SOCKET_ERROR )
2007-07-25 08:31:27 -07:00
{
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
2009-12-20 13:13:21 -08:00
{
if ( size = = 0 )
{
debug ( LOG_NET , " Connection closed from the other side " ) ;
}
else
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " %s tcp_socket %p is now invalid " , strSockError ( getSockErr ( ) ) , bs - > socket ) ;
2009-12-20 13:13:21 -08:00
}
// an error occured, or the remote host has closed the connection.
2007-07-25 08:31:27 -07:00
if ( socket_set ! = NULL )
{
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( socket_set , bs - > socket ) ;
2007-06-28 10:47:08 -07:00
}
2009-12-20 13:13:21 -08:00
ASSERT ( bs - > bytes < NET_BUFFER_SIZE , " Socket buffer is too small! " ) ;
if ( bs - > bytes > NET_BUFFER_SIZE )
2009-03-20 12:28:04 -07:00
{
debug ( LOG_ERROR , " Fatal connection error: buffer size of (%d) was too small, current byte count was %d " , NET_BUFFER_SIZE , bs - > bytes ) ;
}
2009-12-18 16:37:09 -08:00
if ( tcp_socket = = bs - > socket )
{
debug ( LOG_NET , " Host connection was lost! " ) ;
tcp_socket = NULL ;
//Game is pretty much over --should just end everything when HOST dies.
NetPlay . isHostAlive = false ;
2010-02-24 20:06:46 -08:00
setLobbyError ( ERROR_HOSTDROPPED ) ;
NETclose ( ) ;
return false ;
2009-12-18 16:37:09 -08:00
}
2009-05-03 08:35:50 -07:00
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
}
2010-02-28 15:24:38 -08:00
static void NET_InitPlayer ( int i , bool initPosition )
2010-02-21 15:07:36 -08: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 ' ;
2010-02-28 15:24:38 -08:00
if ( initPosition )
{
NetPlay . players [ i ] . colour = i ;
NetPlay . players [ i ] . position = i ;
NetPlay . players [ i ] . team = i ;
}
2010-02-21 15:07:36 -08:00
NetPlay . players [ i ] . ready = false ;
NetPlay . players [ i ] . needFile = false ;
NetPlay . players [ i ] . wzFile . isCancelled = false ;
NetPlay . players [ i ] . wzFile . isSending = false ;
}
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 )
{
2010-02-28 15:24:38 -08:00
NET_InitPlayer ( i , true ) ;
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 ;
2010-02-20 21:32:36 -08:00
NetPlay . pMapFileHandle = NULL ;
2009-06-07 11:10:13 -07:00
debug ( LOG_NET , " Players initialized " ) ;
2007-06-28 10:47:08 -07:00
}
2010-02-28 15:24:38 -08:00
static void NETSendPlayerInfoTo ( uint32_t index , unsigned to )
2007-07-15 06:48:22 -07:00
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " sending player's (%u) info to all players " , index ) ;
2010-02-28 15:24:38 -08:00
NETbeginEncode ( NET_PLAYER_INFO , to ) ;
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 ) ;
2009-11-26 10:33:03 -08:00
NETint32_t ( & NetPlay . players [ index ] . position ) ;
2009-06-07 11:10:13 -07:00
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
}
2010-02-28 15:24:38 -08:00
void NETBroadcastPlayerInfo ( uint32_t index )
{
NETSendPlayerInfoTo ( index , NET_ALL_PLAYERS ) ;
}
2010-01-03 02:40:52 -08:00
static signed int NET_CreatePlayer ( const char * name )
2007-07-15 06:48:22 -07:00
{
2010-01-03 02:40:52 -08:00
signed 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 ) ;
2010-01-03 02:40:52 -08:00
return - 1 ;
2007-06-28 10:47:08 -07:00
}
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 - - ;
2009-12-18 16:12:33 -08:00
gamestruct . desc . dwCurrentPlayers = NetPlay . playercount ;
2010-01-04 21:34:17 -08:00
if ( allow_joining & & NetPlay . isHost )
{
// Update player count in the lobby by disconnecting
// and reconnecting
NETregisterServer ( 0 ) ;
NETregisterServer ( 1 ) ;
}
2009-07-16 17:13:31 -07:00
}
2010-02-28 15:24:38 -08:00
NET_InitPlayer ( index , false ) ; // reinitialize
2007-06-28 10:47:08 -07:00
}
2010-02-01 12:26:49 -08:00
/**
* @ note Connection dropped . Handle it gracefully .
* \ param index
*/
static void NETplayerClientDisconnect ( uint32_t index )
{
if ( connected_bsocket [ index ] )
{
debug ( LOG_NET , " Player (%u) has left unexpectedly, closing socket %p " ,
index , connected_bsocket [ index ] - > socket ) ;
2010-02-21 15:07:36 -08:00
NETplayerLeaving ( index ) ;
2010-02-01 12:26:49 -08:00
// Announce to the world. This is really icky, because we may be calling the send
// function recursively. We really ought to have a send queue...
NETbeginEncode ( NET_PLAYER_DROPPED , NET_ALL_PLAYERS ) ;
NETuint32_t ( & index ) ;
NETend ( ) ;
}
else
{
debug ( LOG_ERROR , " Player (%u) has left unexpectedly - but socket already closed? " , index ) ;
}
}
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
*/
2010-02-01 12:26:49 -08:00
static 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
{
2010-02-21 15:07:36 -08:00
debug ( LOG_NET , " Player (%u) has left, closing socket %p " , 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.
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( socket_set , connected_bsocket [ index ] - > socket ) ;
2009-06-07 11:10:13 -07:00
socketClose ( connected_bsocket [ index ] - > socket ) ;
connected_bsocket [ index ] - > socket = NULL ;
2009-02-21 14:09:58 -08:00
}
else
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Player (%u) has left nicely, socket already closed? " , index ) ;
2009-02-21 14:09:58 -08:00
}
2010-02-24 20:07:53 -08:00
MultiPlayerLeave ( index ) ; // more cleanup
NET_DestroyPlayer ( index ) ; // sets index player's array to false
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
*/
2010-02-01 12:26:49 -08:00
static 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 ( ) ;
2010-02-20 21:32:36 -08:00
debug ( LOG_INFO , " sending NET_PLAYER_DROPPED for player %d " , id ) ;
2009-02-21 14:09:58 -08:00
NET_DestroyPlayer ( id ) ; // just clears array
MultiPlayerLeave ( id ) ; // more cleanup
NET_PlayerConnectionStatus = 2 ; //DROPPED_CONNECTION
}
2009-06-07 11:10:13 -07:00
2010-01-09 05:39:09 -08:00
/**
* @ note Cleanup for when a player is kicked .
* \ param index
*/
void NETplayerKicked ( UDWORD index )
{
// kicking a player counts as "leaving nicely", since "nicely" in this case
// simply means "there wasn't a connection error."
2010-02-06 20:49:23 -08:00
debug ( LOG_INFO , " Player %u was kicked. " , index ) ;
2010-01-09 05:39:09 -08:00
NETplayerLeaving ( index ) ; // need to close socket for the player that left.
NET_PlayerConnectionStatus = 1 ; // LEAVING_NICELY
}
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 )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " sending game flags " ) ;
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 ) .
*
2009-12-20 13:13:21 -08:00
* @ return true on success , false when a socket error has occurred
*
2008-08-03 14:34:18 -07:00
* @ see GAMESTRUCT , NETrecvGAMESTRUCT
*/
2009-12-20 13:13:21 -08:00
static bool NETsendGAMESTRUCT ( Socket * sock , const GAMESTRUCT * ourgamestruct )
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-12-18 16:12:33 -08:00
char buf [ sizeof ( ourgamestruct - > GAMESTRUCT_VERSION ) + sizeof ( ourgamestruct - > name ) + sizeof ( ourgamestruct - > desc . host ) + ( sizeof ( int32_t ) * 8 ) +
sizeof ( ourgamestruct - > secondaryHosts ) + sizeof ( ourgamestruct - > extra ) + sizeof ( ourgamestruct - > versionstring ) +
sizeof ( ourgamestruct - > 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 ;
2009-12-20 13:13:21 -08:00
ssize_t 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-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > 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
2009-12-18 16:12:33 -08:00
strlcpy ( buffer , ourgamestruct - > name , sizeof ( ourgamestruct - > name ) ) ;
buffer + = sizeof ( ourgamestruct - > name ) ;
2008-02-03 08:39:46 -08:00
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( int32_t * ) buffer = htonl ( ourgamestruct - > desc . dwSize ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-12-18 16:12:33 -08:00
* ( int32_t * ) buffer = htonl ( ourgamestruct - > desc . dwFlags ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
// Copy yet another string
2009-12-18 16:12:33 -08:00
strlcpy ( buffer , ourgamestruct - > desc . host , sizeof ( ourgamestruct - > desc . host ) ) ;
buffer + = sizeof ( ourgamestruct - > desc . host ) ;
2008-02-03 08:39:46 -08:00
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( int32_t * ) buffer = htonl ( ourgamestruct - > desc . dwMaxPlayers ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-12-18 16:12:33 -08:00
* ( int32_t * ) buffer = htonl ( ourgamestruct - > desc . dwCurrentPlayers ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-12-18 16:12:33 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( ourgamestruct - > desc . dwUserFlags ) ; + + i )
2008-10-14 05:58:59 -07:00
{
2009-12-18 16:12:33 -08:00
* ( int32_t * ) buffer = htonl ( ourgamestruct - > 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-12-18 16:12:33 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( ourgamestruct - > secondaryHosts ) ; + + i )
2009-05-09 10:22:44 -07:00
{
2009-12-18 16:12:33 -08:00
strlcpy ( buffer , ourgamestruct - > secondaryHosts [ i ] , sizeof ( ourgamestruct - > secondaryHosts [ i ] ) ) ;
buffer + = sizeof ( ourgamestruct - > secondaryHosts [ i ] ) ;
2009-05-09 10:22:44 -07:00
}
2009-04-19 11:45:28 -07:00
// Copy a string
2009-12-18 16:12:33 -08:00
strlcpy ( buffer , ourgamestruct - > extra , sizeof ( ourgamestruct - > extra ) ) ;
buffer + = sizeof ( ourgamestruct - > extra ) ;
2009-04-19 11:45:28 -07:00
// Copy a string
2009-12-18 16:12:33 -08:00
strlcpy ( buffer , ourgamestruct - > versionstring , sizeof ( ourgamestruct - > versionstring ) ) ;
buffer + = sizeof ( ourgamestruct - > versionstring ) ;
2009-04-19 11:45:28 -07:00
// Copy a string
2009-12-18 16:12:33 -08:00
strlcpy ( buffer , ourgamestruct - > modlist , sizeof ( ourgamestruct - > modlist ) ) ;
buffer + = sizeof ( ourgamestruct - > modlist ) ;
2009-04-19 11:45:28 -07:00
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > game_version_major ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > game_version_minor ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > privateGame ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > pureGame ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > Mods ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > gameId ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > future2 ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > future3 ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
* ( uint32_t * ) buffer = htonl ( ourgamestruct - > 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-12-20 13:13:21 -08:00
const int err = getSockErr ( ) ;
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 ) ;
2009-12-20 13:13:21 -08:00
setSockErr ( err ) ;
return false ;
2008-07-12 04:50:18 -07:00
}
2009-12-20 13:13:21 -08:00
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " sending GAMESTRUCT " ) ;
2009-12-20 13:13:21 -08:00
return true ;
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
*/
2009-12-18 16:12:33 -08:00
static bool NETrecvGAMESTRUCT ( GAMESTRUCT * ourgamestruct )
2008-02-03 08:39:46 -08:00
{
// A buffer that's guaranteed to have the correct size (i.e. it
// circumvents struct padding, which could pose a problem).
2009-12-18 16:12:33 -08:00
char buf [ sizeof ( ourgamestruct - > GAMESTRUCT_VERSION ) + sizeof ( ourgamestruct - > name ) + sizeof ( ourgamestruct - > desc . host ) + ( sizeof ( int32_t ) * 8 ) +
sizeof ( ourgamestruct - > secondaryHosts ) + sizeof ( ourgamestruct - > extra ) + sizeof ( ourgamestruct - > versionstring ) +
sizeof ( ourgamestruct - > 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 ;
2009-12-20 13:13:21 -08:00
ssize_t 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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " Server socket (%p) ecountered error: %s " , tcp_socket , strSockError ( getSockErr ( ) ) ) ;
2010-02-23 21:03:24 -08:00
SocketSet_DelSocket ( socket_set , tcp_socket ) ; // mark it invalid
2009-05-03 08:35:50 -07:00
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 ) ;
2009-12-20 13:13:21 -08:00
if ( result = = SOCKET_ERROR
| | result = = 0 )
2009-07-13 13:09:57 -07:00
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " Server socket (%p) ecountered error: %s " , tcp_socket , strSockError ( getSockErr ( ) ) ) ;
debug ( LOG_ERROR , " GAMESTRUCT recv failed; received %u bytes out of %d " , i , ( int ) sizeof ( buf ) ) ;
2010-02-23 21:03:24 -08:00
SocketSet_DelSocket ( socket_set , tcp_socket ) ; // mark it invalid
2009-12-20 13:13:21 -08:00
socketClose ( tcp_socket ) ;
tcp_socket = NULL ;
2009-07-13 13:09:57 -07:00
return false ;
}
i + = result ;
}
if ( i ! = sizeof ( buf ) )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " 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-12-18 16:12:33 -08:00
ourgamestruct - > 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
2009-12-18 16:12:33 -08:00
sstrcpy ( ourgamestruct - > name , buffer ) ;
buffer + = sizeof ( ourgamestruct - > name ) ;
2008-02-03 08:39:46 -08:00
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
ourgamestruct - > desc . dwSize = ntohl ( * ( int32_t * ) buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > desc . dwFlags = ntohl ( * ( int32_t * ) buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
// Copy yet another string
2009-12-18 16:12:33 -08:00
sstrcpy ( ourgamestruct - > desc . host , buffer ) ;
buffer + = sizeof ( ourgamestruct - > desc . host ) ;
2008-02-03 08:39:46 -08:00
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
ourgamestruct - > desc . dwMaxPlayers = ntohl ( * ( int32_t * ) buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > desc . dwCurrentPlayers = ntohl ( * ( int32_t * ) buffer ) ;
2008-02-03 08:39:46 -08:00
buffer + = sizeof ( int32_t ) ;
2009-12-18 16:12:33 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( ourgamestruct - > desc . dwUserFlags ) ; + + i )
2008-10-14 05:58:59 -07:00
{
2009-12-18 16:12:33 -08:00
ourgamestruct - > 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-12-18 16:12:33 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( ourgamestruct - > secondaryHosts ) ; + + i )
2009-05-09 10:22:44 -07:00
{
2009-12-18 16:12:33 -08:00
sstrcpy ( ourgamestruct - > secondaryHosts [ i ] , buffer ) ;
buffer + = sizeof ( ourgamestruct - > secondaryHosts [ i ] ) ;
2009-05-09 10:22:44 -07:00
}
2009-04-19 11:45:28 -07:00
// Copy a string
2009-12-18 16:12:33 -08:00
sstrcpy ( ourgamestruct - > extra , buffer ) ;
buffer + = sizeof ( ourgamestruct - > extra ) ;
2009-04-19 11:45:28 -07:00
// Copy a string
2009-12-18 16:12:33 -08:00
sstrcpy ( ourgamestruct - > versionstring , buffer ) ;
buffer + = sizeof ( ourgamestruct - > versionstring ) ;
2009-04-19 11:45:28 -07:00
// Copy a string
2009-12-18 16:12:33 -08:00
sstrcpy ( ourgamestruct - > modlist , buffer ) ;
buffer + = sizeof ( ourgamestruct - > modlist ) ;
2009-04-19 11:45:28 -07:00
// Copy 32bit large big endian numbers
2009-12-18 16:12:33 -08:00
ourgamestruct - > game_version_major = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > game_version_minor = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > privateGame = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > pureGame = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > Mods = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > gameId = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > future2 = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > future3 = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2009-12-18 16:12:33 -08:00
ourgamestruct - > future4 = ntohl ( * ( uint32_t * ) buffer ) ;
2009-04-19 11:45:28 -07:00
buffer + = sizeof ( uint32_t ) ;
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " received GAMESTRUCT " ) ;
2008-02-03 08:39:46 -08:00
return true ;
}
2007-06-28 10:47:08 -07:00
2009-11-21 11:04:16 -08:00
static int upnp_init ( void * asdf )
{
struct UPNPDev * devlist ;
struct UPNPDev * dev ;
char * descXML ;
int descXMLsize = 0 ;
2009-11-28 13:18:34 -08:00
char buf [ 255 ] ;
2009-11-21 11:04:16 -08:00
memset ( & urls , 0 , sizeof ( struct UPNPUrls ) ) ;
memset ( & data , 0 , sizeof ( struct IGDdatas ) ) ;
2009-12-18 16:13:42 -08:00
if ( NetPlay . isUPNP )
{
2009-12-18 17:36:26 -08:00
debug ( LOG_NET , " Searching for UPnP devices for automatic port forwarding... " ) ;
devlist = upnpDiscover ( 2000 , NULL , NULL , 0 ) ;
debug ( LOG_NET , " UPnP device search finished. " ) ;
if ( devlist )
2009-11-21 11:04:16 -08:00
{
2009-12-18 17:36:26 -08:00
dev = devlist ;
while ( dev )
{
if ( strstr ( dev - > st , " InternetGatewayDevice " ) )
break ;
dev = dev - > pNext ;
}
if ( ! dev )
{
dev = devlist ; /* defaulting to first device */
}
2009-11-21 11:04:16 -08:00
2009-12-18 17:36:26 -08:00
debug ( LOG_NET , " UPnP device found: %s %s \n " , dev - > descURL , dev - > st ) ;
2009-11-21 11:04:16 -08:00
2009-12-18 17:36:26 -08:00
descXML = miniwget_getaddr ( dev - > descURL , & descXMLsize , lanaddr , sizeof ( lanaddr ) ) ;
debug ( LOG_NET , " LAN address: %s " , lanaddr ) ;
if ( descXML )
{
parserootdesc ( descXML , descXMLsize , & data ) ;
free ( descXML ) ; descXML = 0 ;
GetUPNPUrls ( & urls , & data , dev - > descURL ) ;
}
ssprintf ( buf , " UPnP device found: %s %s LAN address %s " , dev - > descURL , dev - > st , lanaddr ) ;
2009-11-28 13:18:34 -08:00
addDumpInfo ( buf ) ;
2009-12-18 17:36:26 -08:00
freeUPNPDevlist ( devlist ) ;
if ( ! urls . controlURL | | urls . controlURL [ 0 ] = = ' \0 ' )
{
ssprintf ( buf , " controlURL not available, UPnP disabled " ) ;
addDumpInfo ( buf ) ;
return false ;
}
return true ;
2009-11-21 11:04:16 -08:00
}
2009-12-18 17:36:26 -08:00
ssprintf ( buf , " UPnP device not found. " ) ;
addDumpInfo ( buf ) ;
debug ( LOG_NET , " No UPnP devices found. " ) ;
return false ;
2009-12-18 16:13:42 -08:00
}
else
{
ssprintf ( buf , " UPnP detection routine disabled by user. " ) ;
addDumpInfo ( buf ) ;
debug ( LOG_NET , " UPnP detection routine disabled by user. " ) ;
return false ;
}
2009-11-21 11:04:16 -08:00
}
static bool upnp_add_redirect ( int port )
{
char externalIP [ 16 ] ;
char port_str [ 16 ] ;
int r ;
debug ( LOG_NET , " upnp_add_redir(%d) \n " , port ) ;
UPNP_GetExternalIPAddress ( urls . controlURL , data . servicetype , externalIP ) ;
sprintf ( port_str , " %d " , port ) ;
r = UPNP_AddPortMapping ( urls . controlURL , data . servicetype ,
port_str , port_str , lanaddr , " Warzone 2100 " , " TCP " , 0 ) ;
if ( r ! = UPNPCOMMAND_SUCCESS )
{
debug ( LOG_NET , " AddPortMapping(%s, %s, %s) failed \n " , port_str , port_str , lanaddr ) ;
return false ;
}
return true ;
}
static void upnp_rem_redirect ( int port )
{
char port_str [ 16 ] ;
debug ( LOG_NET , " upnp_rem_redir(%d) " , port ) ;
sprintf ( port_str , " %d " , port ) ;
UPNP_DeletePortMapping ( urls . controlURL , data . servicetype , port_str , " TCP " , 0 ) ;
}
void NETaddRedirects ( void )
{
debug ( LOG_NET , " %s \n " , __FUNCTION__ ) ;
2009-11-29 11:09:44 -08:00
if ( ! upnp_done )
{
SDL_WaitThread ( upnpdiscover , & upnp ) ;
upnp_done = true ;
}
2009-11-21 11:04:16 -08:00
if ( upnp ) {
2010-01-16 16:20:54 -08:00
upnp_add_redirect ( gameserver_port ) ;
2009-11-21 11:04:16 -08:00
}
}
void NETremRedirects ( void )
{
debug ( LOG_NET , " %s \n " , __FUNCTION__ ) ;
if ( upnp )
{
2010-01-16 16:20:54 -08:00
upnp_rem_redirect ( gameserver_port ) ;
2009-11-21 11:04:16 -08:00
}
}
2010-01-05 15:31:55 -08:00
void NETdiscoverUPnPDevices ( void )
{
upnpdiscover = SDL_CreateThread ( & upnp_init , NULL ) ;
}
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
2009-11-21 11:04:16 -08:00
# if defined(WZ_OS_WIN)
{
static WSADATA stuff ;
WORD ver_required = ( 2 < < 8 ) + 2 ;
if ( WSAStartup ( ver_required , & stuff ) ! = 0 )
{
debug ( LOG_ERROR , " Failed to initialize Winsock: %s " , strSockError ( getSockErr ( ) ) ) ;
return - 1 ;
}
}
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 ( ) ) ) ;
# endif
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
}
2009-12-18 16:13:42 -08:00
// NOTE NetPlay.isUPNP is already set in configuration.c!
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 ;
2009-12-18 16:37:09 -08:00
NetPlay . isHostAlive = false ;
2009-04-19 11:45:28 -07:00
NetPlay . gamePassword [ 0 ] = ' \0 ' ;
2009-05-04 14:52:01 -07:00
NetPlay . MOTD = strdup ( " " ) ;
2010-01-03 11:20:45 -08:00
sstrcpy ( NetPlay . gamePassword , _ ( " Enter password here " ) ) ;
2007-06-28 10:47:08 -07:00
NETstartLogging ( ) ;
}
2009-04-19 11:45:28 -07:00
NetPlay . ShowedMOTD = false ;
NetPlay . GamePassworded = false ;
2010-01-30 20:45:20 -08:00
memset ( & sync_counter , 0x0 , sizeof ( sync_counter ) ) ; //clear counters
2009-04-19 11:45:28 -07:00
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
2009-12-18 16:13:42 -08:00
if ( NetPlay . bComms & & NetPlay . isUPNP )
{
2009-12-18 17:36:26 -08:00
NETremRedirects ( ) ;
2009-12-18 16:13:42 -08:00
}
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-12-18 16:37:09 -08:00
allow_joining = false ;
2007-06-28 10:47:08 -07:00
2007-07-25 08:31:27 -07:00
if ( bsocket )
2010-02-21 12:26:27 -08:00
{ // need SocketSet_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 ] )
{
2010-02-21 12:26:27 -08:00
// FIXME: need SocketSet_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-12-20 14:42:21 -08:00
if ( tcp_socket )
{
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( socket_set , tcp_socket ) ;
2009-12-20 14:42:21 -08:00
}
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 ;
2009-12-20 13:13:21 -08:00
ssize_t 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-11-24 14:50:41 -08:00
{
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 ( ) ) ) ;
2010-02-01 12:26:49 -08:00
NETplayerClientDisconnect ( player ) ;
2007-06-28 10:47:08 -07:00
}
}
2008-04-11 11:35:53 -07:00
else
{
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 ( ) ) ) ;
2010-02-23 21:03:24 -08:00
SocketSet_DelSocket ( socket_set , tcp_socket ) ; // mark it invalid
2009-05-03 08:35:50 -07:00
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: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 ( ) ) ) ;
2010-02-01 12:26:49 -08:00
NETplayerClientDisconnect ( i ) ;
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
{
2009-12-18 16:37:09 -08:00
if ( ! tcp_socket )
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
if ( writeAll ( tcp_socket , msg , size ) = = SOCKET_ERROR )
2008-04-11 11:35:53 -07:00
{
2010-02-23 21:03:24 -08:00
// Write error, most likely host disconnect.
2009-05-03 08:35:50 -07:00
debug ( LOG_ERROR , " Failed to send message: %s " , strSockError ( getSockErr ( ) ) ) ;
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " Host connection was broken, socket %p. " , tcp_socket ) ;
2010-02-23 21:03:24 -08:00
SocketSet_DelSocket ( socket_set , tcp_socket ) ; // mark it invalid
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.
2009-12-18 16:37:09 -08:00
NetPlay . isHostAlive = false ;
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 ( ) ;
2009-12-03 21:50:40 -08:00
netPlayersUpdated = true ;
2008-02-12 10:56:58 -08:00
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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " 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 ) ;
2009-11-26 10:33:03 -08:00
NETint32_t ( & NetPlay . players [ index ] . position ) ;
2009-06-07 11:10:13 -07:00
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 " ) ;
2009-11-26 10:33:03 -08:00
// update the color to the local array
setPlayerColour ( index , NetPlay . players [ index ] . colour ) ;
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
}
2009-12-03 21:50:40 -08:00
netPlayersUpdated = true ;
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 ) ;
2009-12-03 21:50:40 -08:00
netPlayersUpdated = true ;
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
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " Receiving NET_PLAYER_LEAVING for player %u (no socket?) " , ( unsigned int ) index ) ;
2009-02-21 14:09:58 -08:00
}
2010-02-23 21:04:56 -08:00
if ( NetPlay . isHost )
{
debug ( LOG_NET , " Broadcast leaving message to everyone else " ) ;
NETbeginEncode ( NET_PLAYER_LEAVING , NET_ALL_PLAYERS ) ;
{
BOOL host = NetPlay . isHost ;
uint32_t id = index ;
NETuint32_t ( & id ) ;
NETbool ( & host ) ;
}
NETend ( ) ;
}
2010-02-06 20:49:23 -08:00
debug ( LOG_INFO , " Player %u has left the game. " , index ) ;
2009-06-07 11:10:13 -07:00
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-10 21:41:14 -07:00
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
{
2010-02-21 15:07:36 -08:00
debug ( LOG_NET , " Kicking due to client heart attack " ) ;
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
{
2010-02-21 15:07:36 -08:00
debug ( LOG_NET , " Kicking player %d " , i ) ;
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 ] ) ;
2010-01-09 05:39:09 -08:00
if ( i = = pMsg - > source ) // prevent spoofing
{
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.
2010-02-23 21:07:09 -08:00
debug ( LOG_INFO , " 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 ( ) ;
2010-02-06 20:49:23 -08:00
debug ( LOG_INFO , " sending NET_PLAYER_DROPPED for player %d (invalid socket) " , i ) ;
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.
2010-02-21 15:07:36 -08:00
debug ( LOG_ERROR , " Failed to send message (host broadcast): %s " , strSockError ( getSockErr ( ) ) ) ;
NETplayerClientDisconnect ( j ) ;
2009-05-03 08:16:34 -07:00
}
2007-06-28 10:47:08 -07:00
}
}
2007-08-08 11:50:28 -07:00
}
2010-02-21 15:07:36 -08:00
else if ( pMsg - > destination ! = selectedPlayer & & pMsg - > destination < MAX_CONNECTED_PLAYERS )
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.
2010-02-21 15:07:36 -08:00
debug ( LOG_ERROR , " Failed to send message (host specific): %s " , strSockError ( getSockErr ( ) ) ) ;
NETplayerClientDisconnect ( pMsg - > destination ) ;
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.
2009-12-18 16:23:37 -08:00
* @ TODO : more error checking ( ? ) different file types ( ? )
* Maybe should close file handle , and seek each time ?
*
* @ NOTE : MAX_FILE_TRANSFER_PACKET is set to 2 k per packet since 7 * 2 = 14 K which is pretty
* much our limit . Don ' t screw with that without having a bigger buffer !
* NET_BUFFER_SIZE is at 16 k . ( also remember text chat , plus all the other cruff )
*/
2009-11-26 23:14:28 -08:00
# define MAX_FILE_TRANSFER_PACKET 2048
2009-12-18 16:23:37 -08:00
UBYTE NETsendFile ( char * fileName , UDWORD player )
2007-06-28 10:47:08 -07:00
{
2009-12-18 16:23:37 -08:00
int32_t bytesRead = 0 ;
uint8_t sendto = 0 ;
char inBuff [ MAX_FILE_TRANSFER_PACKET ] ;
2008-01-11 13:39:41 -08:00
2009-12-18 16:23:37 -08:00
// We are not the host, so we don't care. (in fact, this would be a error)
2009-12-18 17:36:26 -08:00
if ( ! NetPlay . isHost )
2009-04-27 11:02:38 -07:00
{
2010-02-16 21:08:31 -08:00
debug ( LOG_ERROR , " trying to send a file and we are not the host! " ) ;
2009-12-18 16:23:37 -08:00
return true ;
2009-04-27 11:02:38 -07:00
}
2006-02-18 10:54:37 -08:00
2009-12-18 16:23:37 -08:00
memset ( inBuff , 0x0 , sizeof ( inBuff ) ) ;
2008-01-11 13:39:41 -08:00
2009-12-18 16:23:37 -08:00
// read some bytes.
bytesRead = PHYSFS_read ( NetPlay . players [ player ] . wzFile . pFileHandle , inBuff , 1 , MAX_FILE_TRANSFER_PACKET ) ;
sendto = ( uint8_t ) player ;
NETbeginEncode ( NET_FILE_PAYLOAD , sendto ) ;
NETint32_t ( & NetPlay . players [ player ] . wzFile . fileSize_32 ) ; // total bytes in this file. (we don't support 64bit yet)
NETint32_t ( & bytesRead ) ; // bytes in this packet
NETint32_t ( & NetPlay . players [ player ] . wzFile . currPos ) ; // start byte
NETstring ( fileName , 256 ) ; //256 = max filename size
NETbin ( inBuff , bytesRead ) ;
2008-01-11 13:39:41 -08:00
NETend ( ) ;
2009-12-18 16:23:37 -08:00
NetPlay . players [ player ] . wzFile . currPos + = bytesRead ; // update position!
if ( NetPlay . players [ player ] . wzFile . currPos = = NetPlay . players [ player ] . wzFile . fileSize_32 )
2007-06-28 10:47:08 -07:00
{
2009-12-18 16:23:37 -08:00
PHYSFS_close ( NetPlay . players [ player ] . wzFile . pFileHandle ) ;
NetPlay . players [ player ] . wzFile . isSending = false ; // we are done sending to this client.
NetPlay . players [ player ] . needFile = false ;
2007-06-28 10:47:08 -07:00
}
2009-12-18 16:23:37 -08:00
return ( NetPlay . players [ player ] . wzFile . currPos * 100 ) / NetPlay . players [ player ] . wzFile . fileSize_32 ;
2007-06-28 10:47:08 -07:00
}
2009-12-18 16:23:37 -08:00
/* @TODO more error checking (?) different file types (?) */
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
{
2009-11-26 23:14:28 -08:00
int32_t fileSize = 0 , currPos = 0 , bytesRead = 0 ;
2008-01-11 13:39:41 -08:00
char fileName [ 256 ] ;
char outBuff [ MAX_FILE_TRANSFER_PACKET ] ;
2009-12-18 16:23:37 -08:00
static bool isLoop = false ;
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.
2009-12-18 16:23:37 -08:00
NETbeginDecode ( NET_FILE_PAYLOAD ) ;
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
2009-12-18 16:23:37 -08:00
NETstring ( fileName , 256 ) ; // read filename (only valid on 1st packet)
2009-11-26 23:14:28 -08:00
debug ( LOG_NET , " Creating new file %s, position is %d " , fileName , currPos ) ;
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
{
2009-11-28 12:48:29 -08:00
if ( PHYSFS_exists ( fileName ) )
{
PHYSFS_file * fin ;
PHYSFS_sint64 fsize ;
fin = PHYSFS_openRead ( fileName ) ;
2010-02-20 21:32:36 -08:00
if ( ! fin )
{
// the file exists, but we can't open it, and I have no clue how to fix this...
debug ( LOG_FATAL , " PHYSFS_openRead( \" %s \" ) failed with error: %s \n " , fileName , PHYSFS_getLastError ( ) ) ;
debug ( LOG_NET , " We are leaving 'nicely' after a fatal error " ) ;
2010-02-23 21:04:56 -08:00
NETbeginEncode ( NET_PLAYER_LEAVING , NET_HOST_ONLY ) ;
2010-02-20 21:32:36 -08:00
{
BOOL host = NetPlay . isHost ;
uint32_t id = selectedPlayer ;
NETuint32_t ( & id ) ;
NETbool ( & host ) ;
}
NETend ( ) ;
abort ( ) ;
}
else
{
fsize = PHYSFS_fileLength ( fin ) ;
}
2009-11-28 12:48:29 -08:00
if ( ( int32_t ) fsize = = fileSize )
{
2009-12-18 16:23:37 -08:00
uint32_t reason = ALREADY_HAVE_FILE ;
debug ( LOG_NET , " We already have the file %s! " , fileName ) ;
PHYSFS_close ( fin ) ;
NETend ( ) ;
NETbeginEncode ( NET_FILE_CANCELLED , NET_HOST_ONLY ) ;
NETuint32_t ( & selectedPlayer ) ;
NETuint32_t ( & reason ) ;
NETend ( ) ;
if ( ! isLoop )
{
isLoop = true ;
}
else
{
uint32_t reason = STUCK_IN_FILE_LOOP ;
NETend ( ) ;
// we should never get here, it means, that the game can't detect the level, but we have the file.
// so we kick this player out.
NETbeginEncode ( NET_FILE_CANCELLED , NET_HOST_ONLY ) ;
NETuint32_t ( & selectedPlayer ) ;
NETuint32_t ( & reason ) ;
NETend ( ) ;
2010-02-20 21:32:36 -08:00
PHYSFS_close ( NetPlay . pMapFileHandle ) ;
NetPlay . pMapFileHandle = NULL ;
2009-12-18 16:23:37 -08:00
debug ( LOG_FATAL , " Something is really wrong with the file's (%s) data, game can't detect it? " , fileName ) ;
return 100 ;
}
2009-11-28 12:48:29 -08:00
}
PHYSFS_close ( fin ) ;
2009-12-18 16:23:37 -08:00
debug ( LOG_NET , " We already have the file %s, but different size %d vs %d. Redownloading " , fileName , ( int32_t ) fsize , fileSize ) ;
2009-11-28 12:48:29 -08:00
}
2010-02-20 21:32:36 -08:00
NetPlay . pMapFileHandle = PHYSFS_openWrite ( fileName ) ; // create a new file.
2007-06-28 10:47:08 -07:00
}
2006-02-18 10:54:37 -08:00
2010-02-20 21:32:36 -08:00
if ( ! NetPlay . pMapFileHandle ) // file can't be opened
2009-10-30 20:57:44 -07:00
{
debug ( LOG_FATAL , " Fatal error while creating file: %s " , PHYSFS_getLastError ( ) ) ;
2009-11-26 23:14:28 -08:00
debug ( LOG_FATAL , " Either we do not have write permission, or the Host sent us a invalid file (%s)! " , fileName ) ;
2009-10-30 20:57:44 -07:00
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.
2010-02-20 21:32:36 -08:00
PHYSFS_write ( NetPlay . pMapFileHandle , 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
{
2010-02-20 21:32:36 -08:00
PHYSFS_close ( NetPlay . pMapFileHandle ) ;
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
2009-12-20 13:13:21 -08:00
if ( writeAll ( rs_socket [ 0 ] , " gaId " , sizeof ( " gaId " ) ) = = SOCKET_ERROR
| | readAll ( rs_socket [ 0 ] , & gameId , sizeof ( gameId ) , 10000 ) ! = sizeof ( gameId ) )
2009-05-09 10:22:44 -07:00
{
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-12-18 16:12:33 -08:00
gamestruct . gameId = ntohl ( gameId ) ;
debug ( LOG_NET , " Using game ID: %u " , ( unsigned int ) gamestruct . 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 ;
2009-12-20 13:13:21 -08:00
if ( writeAll ( rs_socket [ i ] , " addg " , sizeof ( " addg " ) ) = = SOCKET_ERROR
// and now send what the server wants
| | ! NETsendGAMESTRUCT ( rs_socket [ i ] , & gamestruct ) )
{
debug ( LOG_ERROR , " Failed to register game with server: %s " , strSockError ( getSockErr ( ) ) ) ;
socketClose ( rs_socket [ i ] ) ;
rs_socket [ i ] = NULL ;
}
2009-05-09 10:22:44 -07:00
}
// 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-12-20 13:13:21 -08:00
ssize_t recv_result = 0 ;
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 ;
}
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 )
{
2010-02-23 21:08:30 -08:00
// this should *never* happen, it would mean we are going to reuse a socket already in use.
debug ( LOG_ERROR , " all temp sockets are used up! " ) ;
return ;
2009-07-15 15:50:41 -07:00
}
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
{
2010-02-21 12:26:27 -08:00
SocketSet_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
2009-12-20 13:13:21 -08:00
& & ( recv_result = readNoInt ( tmp_socket [ i ] , buffer , 5 ) )
& & recv_result ! = SOCKET_ERROR )
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 ( ) ) ) ;
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " 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-12-18 16:12:33 -08:00
gamestruct . desc . dwCurrentPlayers = NetPlay . playercount ;
2009-11-28 12:40:53 -08:00
debug ( LOG_NET , " Sending update to server to reflect new player count %d " , NetPlay . playercount ) ;
2009-12-18 16:12:33 -08:00
NETsendGAMESTRUCT ( tmp_socket [ i ] , & gamestruct ) ;
2009-04-30 18:27:13 -07:00
}
2009-05-03 08:50:11 -07:00
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " freeing temp socket %p (%d) " , tmp_socket [ i ] , __LINE__ ) ;
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
2009-05-03 08:50:11 -07:00
socketClose ( tmp_socket [ i ] ) ;
tmp_socket [ i ] = NULL ;
}
else if ( strcmp ( buffer , " join " ) = = 0 )
{
debug ( LOG_NET , " cmd: join. Sending GAMESTRUCT " ) ;
2009-12-20 13:13:21 -08:00
if ( ! NETsendGAMESTRUCT ( tmp_socket [ i ] , & gamestruct ) )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " Failed to respond (with GAMESTRUCT) to 'join' command, socket (%p) error: %s " , tmp_socket [ i ] , strSockError ( getSockErr ( ) ) ) ;
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
2009-12-20 13:13:21 -08:00
socketClose ( tmp_socket [ i ] ) ;
tmp_socket [ i ] = NULL ;
}
2009-02-21 14:09:58 -08:00
}
else
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " freeing temp socket %p (%d) " , tmp_socket [ i ] , __LINE__ ) ;
2010-02-21 12:26:27 -08:00
SocketSet_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
{
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " freeing temp socket %p (%d) " , tmp_socket [ i ] , __LINE__ ) ;
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
2009-05-03 08:50:11 -07:00
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-12-20 13:13:21 -08:00
ssize_t size = readNoInt ( tmp_socket [ i ] , & NetMsg , sizeof ( NetMsg ) ) ;
2007-06-28 10:47:08 -07:00
2009-12-20 13:13:21 -08:00
if ( size = = 0 | | size = = SOCKET_ERROR )
2007-07-24 12:33:46 -07:00
{
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
}
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " freeing temp socket %p (%d) " , tmp_socket [ i ] , __LINE__ ) ;
2010-02-21 12:26:27 -08:00
SocketSet_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
{
2009-06-07 11:10:13 -07:00
uint8_t j ;
2010-02-28 15:24:38 -08:00
uint8_t index ;
2010-01-22 12:39:01 -08:00
uint8_t rejected = 0 ;
2010-03-01 10:55:53 -08:00
int tmp ;
2010-01-22 12:39:01 -08:00
char name [ 64 ] ;
int32_t MajorVersion = 0 ;
int32_t MinorVersion = 0 ;
char ModList [ modlist_string_size ] = { ' \0 ' } ;
char GamePassword [ password_string_size ] = { ' \0 ' } ;
int32_t Hash_Data = 0 ; // Not currently used
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 ) ) ;
2010-01-22 12:39:01 -08:00
NETint32_t ( & MajorVersion ) ; // NETCODE_VERSION_MAJOR
NETint32_t ( & MinorVersion ) ; // NETCODE_VERSION_MINOR
NETstring ( ModList , sizeof ( ModList ) ) ;
NETstring ( GamePassword , sizeof ( GamePassword ) ) ;
NETint32_t ( & Hash_Data ) ; // NETCODE_HASH, not currently used
2008-02-02 06:45:24 -08:00
NETend ( ) ;
2010-01-22 12:39:01 -08:00
2010-03-01 10:55:53 -08:00
tmp = NET_CreatePlayer ( name ) ;
2007-06-28 10:47:08 -07:00
2010-03-01 10:55:53 -08:00
if ( tmp = = - 1 )
2010-01-03 02:40:52 -08:00
{
2010-01-22 12:39:01 -08:00
// FIXME: No room. Dropping the player without warning since protocol doesn't seem to support rejection at this point
2010-02-23 21:07:09 -08:00
debug ( LOG_ERROR , " freeing temp socket %p, couldn't create player! " , tmp_socket [ i ] ) ;
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
2010-01-03 02:40:52 -08:00
socketClose ( tmp_socket [ i ] ) ;
tmp_socket [ i ] = NULL ;
return ;
}
2010-03-01 10:55:53 -08:00
index = tmp ;
2010-02-23 21:07:09 -08:00
debug ( LOG_NET , " freeing temp socket %p (%d) " , tmp_socket [ i ] , __LINE__ ) ;
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( tmp_socket_set , tmp_socket [ i ] ) ;
2009-06-07 11:10:13 -07:00
NET_initBufferedSocket ( connected_bsocket [ index ] , tmp_socket [ i ] ) ;
2010-02-21 12:26:27 -08:00
SocketSet_AddSocket ( socket_set , connected_bsocket [ index ] - > socket ) ;
2007-06-28 10:47:08 -07:00
tmp_socket [ i ] = NULL ;
2010-01-22 12:39:01 -08:00
if ( ! NETisCorrectVersion ( MajorVersion , MinorVersion ) )
{
// Wrong version. Reject.
rejected = ( uint8_t ) ERROR_WRONGVERSION ;
}
else if ( NetPlay . GamePassworded & & strcmp ( NetPlay . gamePassword , GamePassword ) ! = 0 )
{
// Wrong password. Reject.
rejected = ( uint8_t ) ERROR_WRONGPASSWORD ;
}
else if ( NetPlay . playercount > gamestruct . desc . dwMaxPlayers )
{
// Game full. Reject.
rejected = ( uint8_t ) ERROR_FULL ;
}
else if ( strcmp ( getModList ( ) , ModList ) ! = 0 )
{
// Incompatible mods. Reject.
rejected = ( uint8_t ) ERROR_WRONGDATA ;
}
if ( rejected )
{
2010-02-23 21:07:09 -08:00
debug ( LOG_INFO , " We were rejected, reason (%u) " , ( unsigned int ) rejected ) ;
2010-01-22 12:39:01 -08:00
NETbeginEncode ( NET_REJECTED , index ) ;
NETuint8_t ( & rejected ) ;
NETend ( ) ;
allow_joining = false ; // no need to inform master server
NET_DestroyPlayer ( index ) ;
allow_joining = true ;
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( socket_set , connected_bsocket [ index ] - > socket ) ;
2010-01-22 12:39:01 -08:00
socketClose ( connected_bsocket [ index ] - > socket ) ;
connected_bsocket [ index ] - > socket = NULL ;
return ;
}
NETbeginEncode ( NET_ACCEPTED , index ) ;
2010-02-28 15:24:38 -08:00
NETuint8_t ( & index ) ;
2010-01-22 12:39:01 -08:00
NETend ( ) ;
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
2009-12-18 16:12:33 -08:00
gamestruct . desc . dwCurrentPlayers + + ;
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 ( ) ;
2010-02-28 15:24:38 -08:00
NETSendPlayerInfoTo ( j , index ) ;
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 ) ;
2010-02-28 15:24:38 -08:00
NETuint8_t ( & index ) ;
2008-02-02 06:45:17 -08:00
NETend ( ) ;
2010-02-28 15:24:38 -08:00
NETBroadcastPlayerInfo ( index ) ;
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-12-18 16:25:54 -08:00
// reset flags for new players
NetPlay . players [ index ] . wzFile . isCancelled = false ;
NetPlay . players [ index ] . wzFile . isSending = false ;
NetPlay . players [ index ] . needFile = false ;
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-12-03 21:50:40 -08:00
mapDownloadProgress = 100 ;
netPlayersUpdated = true ;
2009-12-18 16:13:42 -08:00
if ( NetPlay . bComms & & NetPlay . isUPNP )
2009-12-08 14:19:18 -08:00
{
NETaddRedirects ( ) ;
}
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
2009-12-18 16:12:33 -08:00
sstrcpy ( gamestruct . name , SessionName ) ;
memset ( & gamestruct . desc , 0 , sizeof ( gamestruct . desc ) ) ;
gamestruct . desc . dwSize = sizeof ( gamestruct . desc ) ;
//gamestruct.desc.guidApplication = GAME_GUID;
memset ( gamestruct . desc . host , 0 , sizeof ( gamestruct . desc . host ) ) ;
gamestruct . desc . dwCurrentPlayers = 1 ;
gamestruct . desc . dwMaxPlayers = plyrs ;
gamestruct . desc . dwFlags = 0 ;
gamestruct . desc . dwUserFlags [ 0 ] = one ;
gamestruct . desc . dwUserFlags [ 1 ] = two ;
gamestruct . desc . dwUserFlags [ 2 ] = three ;
gamestruct . desc . dwUserFlags [ 3 ] = four ;
memset ( gamestruct . secondaryHosts , 0 , sizeof ( gamestruct . secondaryHosts ) ) ;
sstrcpy ( gamestruct . extra , " Extra " ) ; // extra string (future use)
2010-01-17 12:12:03 -08:00
sstrcpy ( gamestruct . versionstring , VersionString ) ; // version (string)
if ( * getModList ( ) )
{
sstrcat ( gamestruct . versionstring , _ ( " , mods: " ) ) ; // version (string)
sstrcat ( gamestruct . versionstring , getModList ( ) ) ; // version (string)
}
sstrcpy ( gamestruct . modlist , getModList ( ) ) ; // List of mods
2009-12-18 16:12:33 -08:00
gamestruct . GAMESTRUCT_VERSION = 3 ; // version of this structure
gamestruct . game_version_major = NETCODE_VERSION_MAJOR ; // Netcode Major version
gamestruct . game_version_minor = NETCODE_VERSION_MINOR ; // NetCode Minor version
// gamestruct.privateGame = 0; // if true, it is a private game
gamestruct . pureGame = 0 ; // NO mods allowed if true
gamestruct . Mods = 0 ; // number of concatenated mods?
gamestruct . gameId = 0 ;
gamestruct . future2 = 0xBAD02 ; // for future use
gamestruct . future3 = 0xBAD03 ; // for future use
gamestruct . 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 ;
2009-12-18 16:37:09 -08:00
NetPlay . isHostAlive = true ;
2009-06-07 11:10:13 -07:00
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-11-28 12:40:53 -08:00
if ( getLobbyError ( ) = = ERROR_CHEAT | | getLobbyError ( ) = = ERROR_KICKED )
2009-04-19 11:45:28 -07:00
{
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 ) ;
2010-02-21 15:25:52 -08:00
if ( socket_set )
{
SocketSet_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 ) ;
2010-02-21 12:26:27 -08:00
SocketSet_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 " ) ;
2006-02-18 10:54:37 -08:00
2009-12-20 13:13:21 -08:00
if ( writeAll ( tcp_socket , " list " , sizeof ( " list " ) ) ! = SOCKET_ERROR
& & 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) " ) ;
}
2010-02-23 21:03:24 -08:00
SocketSet_DelSocket ( socket_set , tcp_socket ) ; // mark it invalid
2009-05-09 10:22:44 -07:00
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
{
2010-01-14 06:07:14 -08:00
struct addrinfo * cur = NULL ;
struct addrinfo * hosts = NULL ;
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-12-03 21:50:40 -08:00
mapDownloadProgress = 100 ;
netPlayersUpdated = true ;
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 )
2010-01-14 06:07:14 -08:00
{
2009-05-09 10:22:44 -07:00
hostname = strdup ( NetPlay . games [ gameNumber ] . secondaryHosts [ i - 1 ] ) ;
2010-01-14 06:07:14 -08:00
}
2009-05-09 10:22:44 -07:00
else
2010-01-14 06:07:14 -08:00
{
2009-05-09 10:22:44 -07:00
hostname = strdup ( NetPlay . games [ gameNumber ] . desc . host ) ;
2010-01-14 06:07:14 -08:00
}
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 )
2010-01-14 06:07:14 -08:00
{
2009-05-09 10:22:44 -07:00
goto connect_succesfull ;
2010-01-14 06:07:14 -08:00
}
2009-05-09 10:22:44 -07:00
}
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
2010-02-21 12:26:27 -08:00
SocketSet_AddSocket ( socket_set , tcp_socket ) ;
2005-12-02 13:45:42 -08:00
2009-12-20 13:13:21 -08:00
if ( writeAll ( tcp_socket , " join " , sizeof ( " join " ) ) = = SOCKET_ERROR )
{
debug ( LOG_ERROR , " Failed to send 'join' command: %s " , strSockError ( getSockErr ( ) ) ) ;
freeaddrinfo ( hosts ) ;
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( socket_set , tcp_socket ) ;
2009-12-20 13:13:21 -08:00
socketClose ( tcp_socket ) ;
free ( socket_set ) ;
socket_set = NULL ;
return false ;
}
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 ) ;
2010-01-22 12:39:01 -08:00
if ( NetPlay . games [ gameNumber ] . desc . dwCurrentPlayers > = NetPlay . games [ gameNumber ] . desc . dwMaxPlayers )
2010-01-03 02:40:52 -08:00
{
2010-01-22 12:39:01 -08:00
// Shouldn't join; game is full
2010-02-21 12:26:27 -08:00
SocketSet_DelSocket ( socket_set , tcp_socket ) ;
2010-01-03 02:40:52 -08:00
socketClose ( tcp_socket ) ;
free ( socket_set ) ;
socket_set = NULL ;
2010-01-22 12:39:01 -08:00
setLobbyError ( ERROR_FULL ) ;
2010-01-03 02:40:52 -08:00
return false ;
}
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 ) ;
2010-01-22 12:39:01 -08:00
NETint32_t ( & NETCODE_VERSION_MAJOR ) ;
NETint32_t ( & NETCODE_VERSION_MINOR ) ;
NETstring ( getModList ( ) , modlist_string_size ) ;
NETstring ( NetPlay . gamePassword , sizeof ( NetPlay . gamePassword ) ) ;
NETint32_t ( & NETCODE_HASH ) ; //unused
2008-02-02 06:45:24 -08:00
NETend ( ) ;
2007-06-28 10:47:08 -07:00
2010-01-03 02:40:52 -08:00
i = SDL_GetTicks ( ) ;
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 ) ;
2010-01-03 02:40:52 -08:00
// FIXME: shouldn't there be some sort of rejection message?
2010-01-22 12:39:01 -08:00
if ( SDL_GetTicks ( ) > i + 5000 )
2010-01-03 02:40:52 -08:00
{
// timeout
return false ;
}
2008-02-15 12:55:38 -08:00
if ( type = = NET_ACCEPTED )
2007-07-24 12:33:46 -07:00
{
2010-01-22 12:39:01 -08: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 ;
2009-12-18 16:37:09 -08:00
NetPlay . isHostAlive = true ;
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
}
2010-01-22 12:39:01 -08:00
else if ( type = = NET_REJECTED )
{
// :(
uint8_t rejection = 0 ;
NETbeginDecode ( NET_REJECTED ) ;
// WRY???
NETuint8_t ( & rejection ) ;
NETend ( ) ;
debug ( LOG_NET , " NET_REJECTED received. Better luck next time? " ) ;
setLobbyError ( ( LOBBY_ERROR_TYPES ) rejection ) ;
}
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 ;
}