2005-02-28 07:16:19 +00:00
# include "quakedef.h"
2004-08-23 00:15:46 +00:00
# ifdef CL_MASTER
# include "cl_master.h"
# define NET_GAMENAME_NQ "QUAKE"
//rename to cl_master.c sometime
//the networking operates seperatly from the main code. This is so we can have full control over all parts of the server sending prints.
//when we send status to the server, it replys with a print command. The text to print contains the serverinfo.
//Q2's print command is a compleate 'print', while qw is just a 'p', thus we can distinguish the two easily.
//save favorites and allow addition of new ones from game?
//add filters some time
//remove dead servers.
//master was polled a minute ago and server was not on list - server on multiple masters would be awkward.
# ifdef _WIN32
# include "winquake.h"
# define USEIPX
# define EWOULDBLOCK WSAEWOULDBLOCK
# define ECONNREFUSED WSAECONNREFUSED
# define EADDRNOTAVAIL WSAEADDRNOTAVAIL
# define EMSGSIZE WSAEMSGSIZE
# define ECONNABORTED WSAECONNABORTED
# define ECONNRESET WSAECONNRESET
# define qerrno WSAGetLastError()
# else
# define qerrno errno
# include <sys/socket.h>
# include <sys/types.h>
# include <netinet/in.h>
# include <errno.h>
typedef int SOCKET ;
# endif
# ifdef AF_IPX
# define USEIPX
# endif
//the number of servers should be limited only by memory.
2006-02-11 02:09:43 +00:00
cvar_t slist_cacheinfo = SCVAR ( " slist_cacheinfo " , " 0 " ) ; //this proves dangerous, memory wise.
cvar_t slist_writeserverstxt = SCVAR ( " slist_writeservers " , " 0 " ) ;
2004-08-23 00:15:46 +00:00
2005-05-17 17:38:50 +00:00
void CL_MasterListParse ( int type , qboolean slashpad ) ;
2004-08-23 00:15:46 +00:00
void CL_QueryServers ( void ) ;
int CL_ReadServerInfo ( char * msg , int servertype , qboolean favorite ) ;
master_t * master ;
player_t * mplayers ;
serverinfo_t * firstserver ;
2005-05-13 10:42:48 +00:00
static serverinfo_t * * visibleservers ;
static int numvisibleservers ;
static int maxvisibleservers ;
static qboolean needsort ;
static hostcachekey_t sortfield ;
static qboolean decreasingorder ;
typedef struct {
hostcachekey_t fieldindex ;
float operandi ;
char * operands ;
qboolean or ;
int compareop ;
} visrules_t ;
# define MAX_VISRULES 8
visrules_t visrules [ MAX_VISRULES ] ;
int numvisrules ;
# define SLIST_MAXKEYS 64
char slist_keyname [ SLIST_MAXKEYS ] [ MAX_INFO_KEY ] ;
int slist_customkeys ;
2005-09-08 02:05:36 +00:00
# ifndef INVALID_SOCKET
# define INVALID_SOCKET -1
# endif
2005-05-13 10:42:48 +00:00
2004-08-23 00:15:46 +00:00
# define POLLUDPSOCKETS 64 //it's big so we can have lots of messages when behind a firewall. Basically if a firewall only allows replys, and only remembers 3 servers per socket, we need this big cos it can take a while for a packet to find a fast optimised route and we might be waiting for a few secs for a reply the first time around.
SOCKET pollsocketsUDP [ POLLUDPSOCKETS ] ;
int lastpollsockUDP ;
# ifdef USEIPX
# define POLLIPXSOCKETS 2 //ipx isn't used as much. In fact, we only expect local servers to be using it. I'm not sure why I implemented it anyway.
SOCKET pollsocketsIPX [ POLLIPXSOCKETS ] ;
int lastpollsockIPX ;
# else
# define POLLIPXSOCKETS 0
# endif
2005-10-07 16:27:20 +00:00
void Master_SetupSockets ( void )
2005-09-08 02:05:36 +00:00
{
int i ;
for ( i = 0 ; i < POLLUDPSOCKETS ; i + + )
pollsocketsUDP [ i ] = INVALID_SOCKET ;
2005-12-15 19:15:39 +00:00
# ifdef USEIPX
2005-09-08 02:05:36 +00:00
for ( i = 0 ; i < POLLIPXSOCKETS ; i + + )
pollsocketsIPX [ i ] = INVALID_SOCKET ;
2005-12-15 19:15:39 +00:00
# endif
2005-09-08 02:05:36 +00:00
}
2005-05-13 10:42:48 +00:00
void Master_HideServer ( serverinfo_t * server )
{
int i , j ;
for ( i = 0 ; i < numvisibleservers ; )
{
if ( visibleservers [ i ] = = server )
{
for ( j = i ; j < numvisibleservers - 1 ; j + + )
visibleservers [ j ] = visibleservers [ j + 1 ] ;
visibleservers - - ;
}
else
i + + ;
}
server - > insortedlist = false ;
}
void Master_InsertAt ( serverinfo_t * server , int pos )
{
int i ;
for ( i = numvisibleservers ; i > pos ; i - - )
{
visibleservers [ i ] = visibleservers [ i - 1 ] ;
}
visibleservers [ pos ] = server ;
numvisibleservers + + ;
server - > insortedlist = true ;
}
qboolean Master_CompareInteger ( int a , int b , slist_test_t rule )
{
switch ( rule )
{
case SLIST_TEST_CONTAINS :
2006-02-28 00:46:04 +00:00
return ! ! ( a & b ) ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_NOTCONTAIN :
return ! ( a & b ) ;
case SLIST_TEST_LESSEQUAL :
return a < = b ;
case SLIST_TEST_LESS :
return a < b ;
case SLIST_TEST_EQUAL :
return a = = b ;
case SLIST_TEST_GREATER :
return a > b ;
case SLIST_TEST_GREATEREQUAL :
return a > = b ;
case SLIST_TEST_NOTEQUAL :
return a ! = b ;
}
return false ;
}
qboolean Master_CompareString ( char * a , char * b , slist_test_t rule )
{
switch ( rule )
{
case SLIST_TEST_CONTAINS :
return ! ! strstr ( a , b ) ;
case SLIST_TEST_NOTCONTAIN :
return ! strstr ( a , b ) ;
case SLIST_TEST_LESSEQUAL :
return strcmp ( a , b ) < = 0 ;
case SLIST_TEST_LESS :
return strcmp ( a , b ) < 0 ;
case SLIST_TEST_EQUAL :
return strcmp ( a , b ) = = 0 ;
case SLIST_TEST_GREATER :
return strcmp ( a , b ) > 0 ;
case SLIST_TEST_GREATEREQUAL :
return strcmp ( a , b ) > = 0 ;
case SLIST_TEST_NOTEQUAL :
return strcmp ( a , b ) ! = 0 ;
}
return false ;
}
qboolean Master_ServerIsGreater ( serverinfo_t * a , serverinfo_t * b )
{
switch ( sortfield )
{
case SLKEY_PING :
return Master_CompareInteger ( a - > ping , b - > ping , SLIST_TEST_LESS ) ;
case SLKEY_NUMPLAYERS :
return Master_CompareInteger ( a - > players , b - > players , SLIST_TEST_LESS ) ;
case SLKEY_MAXPLAYERS :
return Master_CompareInteger ( a - > maxplayers , b - > maxplayers , SLIST_TEST_LESS ) ;
2006-02-28 00:46:04 +00:00
case SLKEY_FREEPLAYERS :
return Master_CompareInteger ( a - > maxplayers - a - > players , b - > maxplayers - b - > players , SLIST_TEST_LESS ) ;
case SLKEY_BASEGAME :
return Master_CompareInteger ( a - > special , b - > special , SLIST_TEST_LESS ) ;
2005-05-13 10:42:48 +00:00
case SLKEY_MAP :
return Master_CompareString ( a - > map , b - > map , SLIST_TEST_LESS ) ;
case SLKEY_GAMEDIR :
return Master_CompareString ( a - > gamedir , b - > gamedir , SLIST_TEST_LESS ) ;
case SLKEY_NAME :
return Master_CompareString ( a - > name , b - > name , SLIST_TEST_LESS ) ;
}
return false ;
}
qboolean Master_PassesMasks ( serverinfo_t * a )
{
int i ;
2006-02-28 00:46:04 +00:00
qboolean val , res ;
2005-05-13 10:42:48 +00:00
//always filter out dead unresponsive servers.
if ( ! a - > ping )
return false ;
2006-02-28 00:46:04 +00:00
val = 1 ;
2005-05-13 10:42:48 +00:00
for ( i = 0 ; i < numvisrules ; i + + )
{
switch ( visrules [ i ] . fieldindex )
{
case SLKEY_PING :
2006-02-28 00:46:04 +00:00
res = Master_CompareInteger ( a - > ping , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
case SLKEY_NUMPLAYERS :
2006-02-28 00:46:04 +00:00
res = Master_CompareInteger ( a - > players , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
case SLKEY_MAXPLAYERS :
2006-02-28 00:46:04 +00:00
res = Master_CompareInteger ( a - > maxplayers , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
break ;
case SLKEY_FREEPLAYERS :
res = Master_CompareInteger ( a - > maxplayers - a - > players , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
case SLKEY_MAP :
2006-02-28 00:46:04 +00:00
res = Master_CompareString ( a - > map , visrules [ i ] . operands , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
case SLKEY_NAME :
2006-02-28 00:46:04 +00:00
res = Master_CompareString ( a - > name , visrules [ i ] . operands , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
case SLKEY_GAMEDIR :
2006-02-28 00:46:04 +00:00
res = Master_CompareString ( a - > gamedir , visrules [ i ] . operands , visrules [ i ] . compareop ) ;
break ;
case SLKEY_BASEGAME :
res = Master_CompareInteger ( a - > special , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
2006-02-28 00:46:04 +00:00
default :
continue ;
2005-05-13 10:42:48 +00:00
}
2006-02-28 00:46:04 +00:00
if ( visrules [ i ] . or )
val | = res ;
else
val & = res ;
2005-05-13 10:42:48 +00:00
}
2006-02-28 00:46:04 +00:00
return val ;
2005-05-13 10:42:48 +00:00
}
void Master_ClearMasks ( void )
{
numvisrules = 0 ;
}
void Master_SetMaskString ( qboolean or , hostcachekey_t field , char * param , slist_test_t testop )
{
if ( numvisrules = = MAX_VISRULES )
return ; //just don't add it.
visrules [ numvisrules ] . fieldindex = field ;
visrules [ numvisrules ] . compareop = testop ;
visrules [ numvisrules ] . operands = param ;
visrules [ numvisrules ] . or = or ;
numvisrules + + ;
}
void Master_SetMaskInteger ( qboolean or , hostcachekey_t field , int param , slist_test_t testop )
{
if ( numvisrules = = MAX_VISRULES )
return ; //just don't add it.
visrules [ numvisrules ] . fieldindex = field ;
visrules [ numvisrules ] . compareop = testop ;
visrules [ numvisrules ] . operandi = param ;
visrules [ numvisrules ] . or = or ;
numvisrules + + ;
}
void Master_SetSortField ( hostcachekey_t field , qboolean descending )
{
sortfield = field ;
decreasingorder = descending ;
}
hostcachekey_t Master_GetSortField ( void )
{
return sortfield ;
}
qboolean Master_GetSortDescending ( void )
{
return decreasingorder ;
}
void Master_ShowServer ( serverinfo_t * server )
{
int i ;
if ( ! numvisibleservers )
{
Master_InsertAt ( server , 0 ) ;
return ;
}
if ( ! decreasingorder )
{
for ( i = 0 ; i < numvisibleservers ; i + + )
{
if ( ! Master_ServerIsGreater ( server , visibleservers [ i ] ) )
{
Master_InsertAt ( server , i ) ;
return ;
}
}
}
else
{
for ( i = 0 ; i < numvisibleservers ; i + + )
{
if ( Master_ServerIsGreater ( server , visibleservers [ i ] ) )
{
Master_InsertAt ( server , i ) ;
return ;
}
}
}
Master_InsertAt ( server , numvisibleservers ) ;
}
void Master_ResortServer ( serverinfo_t * server )
{
if ( server - > insortedlist )
{
if ( ! Master_PassesMasks ( server ) )
Master_HideServer ( server ) ;
}
else
{
if ( Master_PassesMasks ( server ) )
Master_ShowServer ( server ) ;
}
}
void Master_SortServers ( void )
{
serverinfo_t * server ;
int total = Master_TotalCount ( ) ;
if ( maxvisibleservers < total )
{
maxvisibleservers = total ;
visibleservers = BZ_Realloc ( visibleservers , maxvisibleservers * sizeof ( serverinfo_t * ) ) ;
}
{
numvisibleservers = 0 ;
for ( server = firstserver ; server ; server = server - > next )
server - > insortedlist = false ;
}
for ( server = firstserver ; server ; server = server - > next )
{
Master_ResortServer ( server ) ;
}
needsort = false ;
}
serverinfo_t * Master_SortedServer ( int idx )
{
if ( needsort )
Master_SortServers ( ) ;
if ( idx < 0 | | idx > = numvisibleservers )
return NULL ;
return visibleservers [ idx ] ;
}
int Master_NumSorted ( void )
{
// if (needsort)
Master_SortServers ( ) ;
return numvisibleservers ;
}
float Master_ReadKeyFloat ( serverinfo_t * server , int keynum )
{
if ( ! server )
return - 1 ;
else if ( keynum < SLKEY_CUSTOM )
{
switch ( keynum )
{
case SLKEY_PING :
return server - > ping ;
case SLKEY_NUMPLAYERS :
return server - > players ;
case SLKEY_MAXPLAYERS :
return server - > maxplayers ;
2006-02-28 00:46:04 +00:00
case SLKEY_FREEPLAYERS :
return server - > maxplayers - server - > players ;
case SLKEY_BASEGAME :
return server - > special ;
2005-05-13 10:42:48 +00:00
default :
return atof ( Master_ReadKeyString ( server , keynum ) ) ;
}
}
else if ( server - > moreinfo )
return atof ( Info_ValueForKey ( server - > moreinfo - > info , slist_keyname [ keynum - SLKEY_CUSTOM ] ) ) ;
return 0 ;
}
char * Master_ReadKeyString ( serverinfo_t * server , int keynum )
{
if ( keynum < SLKEY_CUSTOM )
{
switch ( keynum )
{
case SLKEY_MAP :
return server - > map ;
case SLKEY_NAME :
return server - > name ;
case SLKEY_ADDRESS :
return NET_AdrToString ( server - > adr ) ;
case SLKEY_GAMEDIR :
return server - > gamedir ;
default :
{
static char s [ 64 ] ;
sprintf ( s , " %f " , Master_ReadKeyFloat ( server , keynum ) ) ;
return s ;
}
}
}
else if ( server - > moreinfo )
return Info_ValueForKey ( server - > moreinfo - > info , slist_keyname [ keynum - SLKEY_CUSTOM ] ) ;
return " " ;
}
int Master_KeyForName ( char * keyname )
{
int i ;
if ( ! strcmp ( keyname , " map " ) )
return SLKEY_MAP ;
else if ( ! strcmp ( keyname , " ping " ) )
return SLKEY_PING ;
else if ( ! strcmp ( keyname , " name " ) )
return SLKEY_NAME ;
else if ( ! strcmp ( keyname , " address " ) | | ! strcmp ( keyname , " cname " ) )
return SLKEY_ADDRESS ;
else if ( ! strcmp ( keyname , " maxplayers " ) )
return SLKEY_MAXPLAYERS ;
else if ( ! strcmp ( keyname , " numplayers " ) )
return SLKEY_NUMPLAYERS ;
2006-02-28 00:46:04 +00:00
else if ( ! strcmp ( keyname , " freeplayers " ) )
return SLKEY_FREEPLAYERS ;
2005-05-13 10:42:48 +00:00
else if ( ! strcmp ( keyname , " gamedir " ) | | ! strcmp ( keyname , " game " ) | | ! strcmp ( keyname , " *gamedir " ) | | ! strcmp ( keyname , " mod " ) )
return SLKEY_GAMEDIR ;
2006-02-28 00:46:04 +00:00
else if ( ! strcmp ( keyname , " special " ) )
return SLKEY_BASEGAME ;
2005-05-13 10:42:48 +00:00
else if ( slist_customkeys = = SLIST_MAXKEYS )
return SLKEY_TOOMANY ;
else
{
for ( i = 0 ; i < slist_customkeys ; i + + )
{
if ( ! strcmp ( slist_keyname [ i ] , keyname ) )
{
return i + SLKEY_CUSTOM ;
}
}
Q_strncpyz ( slist_keyname [ slist_customkeys ] , keyname , MAX_INFO_KEY ) ;
slist_customkeys + + ;
return slist_customkeys - 1 + SLKEY_CUSTOM ;
}
}
2004-08-23 00:15:46 +00:00
void Master_AddMaster ( char * address , int type , char * description )
{
netadr_t adr ;
master_t * mast ;
if ( ! NET_StringToAdr ( address , & adr ) )
{
Con_Printf ( " Failed to resolve address \" %s \" \n " , address ) ;
2005-03-15 22:51:01 +00:00
return ;
2004-08-23 00:15:46 +00:00
}
2005-05-26 12:55:34 +00:00
2004-08-23 00:15:46 +00:00
if ( type < MT_SINGLEQW ) //broadcasts
{
if ( adr . type = = NA_IP )
adr . type = NA_BROADCAST_IP ;
if ( adr . type = = NA_IPX )
adr . type = NA_BROADCAST_IPX ;
}
for ( mast = master ; mast ; mast = mast - > next )
{
2005-05-17 02:36:54 +00:00
if ( NET_CompareAdr ( mast - > adr , adr ) & & mast - > type = = type ) //already exists.
2004-08-23 00:15:46 +00:00
return ;
}
2005-05-26 12:55:34 +00:00
mast = Z_Malloc ( sizeof ( master_t ) + strlen ( description ) + 1 + strlen ( address ) + 1 ) ;
2004-08-23 00:15:46 +00:00
mast - > adr = adr ;
2005-05-26 12:55:34 +00:00
mast - > address = mast - > name + strlen ( description ) + 1 ;
2004-08-23 00:15:46 +00:00
mast - > type = type ;
strcpy ( mast - > name , description ) ;
2005-05-26 12:55:34 +00:00
strcpy ( mast - > address , address ) ;
mast - > next = master ;
master = mast ;
}
2006-02-26 09:37:55 +00:00
void Master_AddMasterHTTP ( char * address , int mastertype , char * description )
2005-05-26 12:55:34 +00:00
{
master_t * mast ;
2006-02-26 09:37:55 +00:00
int servertype ;
if ( mastertype = = MT_MASTERHTTPQW )
servertype = 0 ;
else
servertype = SS_NETQUAKE ;
2005-05-26 12:55:34 +00:00
for ( mast = master ; mast ; mast = mast - > next )
{
2006-02-26 09:37:55 +00:00
if ( ! strcmp ( mast - > address , address ) & & mast - > type = = mastertype ) //already exists.
2005-05-26 12:55:34 +00:00
return ;
}
mast = Z_Malloc ( sizeof ( master_t ) + strlen ( description ) + 1 + strlen ( address ) + 1 ) ;
mast - > address = mast - > name + strlen ( description ) + 1 ;
2006-02-26 09:37:55 +00:00
mast - > type = mastertype ;
2005-05-26 12:55:34 +00:00
mast - > servertype = servertype ;
strcpy ( mast - > name , description ) ;
strcpy ( mast - > address , address ) ;
2004-08-23 00:15:46 +00:00
mast - > next = master ;
master = mast ;
}
//build a linked list of masters. Doesn't duplicate addresses.
qboolean Master_LoadMasterList ( char * filename , int defaulttype , int depth )
{
2005-09-26 08:07:26 +00:00
extern char * com_basedir ;
2005-12-21 03:07:33 +00:00
vfsfile_t * f ;
2004-08-23 00:15:46 +00:00
char line [ 1024 ] ;
char file [ 1024 ] ;
char * name , * next ;
int servertype ;
if ( depth < = 0 )
return false ;
depth - - ;
2006-02-26 08:54:43 +00:00
f = FS_OpenVFS ( filename , " rb " , FS_BASE ) ;
2004-08-23 00:15:46 +00:00
if ( ! f )
return false ;
2005-12-21 03:07:33 +00:00
while ( VFS_GETS ( f , line , sizeof ( line ) - 1 ) )
2004-08-23 00:15:46 +00:00
{
if ( * line = = ' # ' ) //comment
continue ;
next = COM_Parse ( line ) ;
if ( ! * com_token )
continue ;
if ( ! strcmp ( com_token , " file " ) ) //special case. Add a port if you have a server named 'file'... (unlikly)
{
next = COM_Parse ( next ) ;
if ( ! next )
continue ;
Q_strncpyz ( file , com_token , sizeof ( file ) ) ;
}
else
* file = ' \0 ' ;
* next = ' \0 ' ;
next + + ;
name = COM_Parse ( next ) ;
servertype = - 1 ;
if ( ! strcmp ( com_token , " single:qw " ) )
servertype = MT_SINGLEQW ;
else if ( ! strcmp ( com_token , " single:q2 " ) )
servertype = MT_SINGLEQ2 ;
2005-08-26 22:56:51 +00:00
else if ( ! strcmp ( com_token , " single:q3 " ) )
servertype = MT_SINGLEQ3 ;
2005-05-17 02:36:54 +00:00
else if ( ! strcmp ( com_token , " single:dp " ) )
servertype = MT_SINGLEDP ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " single:nq " ) | | ! strcmp ( com_token , " single:q1 " ) )
servertype = MT_SINGLENQ ;
else if ( ! strcmp ( com_token , " single " ) )
servertype = MT_SINGLEQW ;
2005-05-17 02:36:54 +00:00
else if ( ! strcmp ( com_token , " master:dp " ) )
servertype = MT_MASTERDP ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " master:qw " ) )
servertype = MT_MASTERQW ;
else if ( ! strcmp ( com_token , " master:q2 " ) )
servertype = MT_MASTERQ2 ;
2005-08-26 22:56:51 +00:00
else if ( ! strcmp ( com_token , " master:q3 " ) )
servertype = MT_MASTERQ3 ;
2006-02-26 09:37:55 +00:00
else if ( ! strcmp ( com_token , " master:http " ) )
servertype = MT_MASTERHTTP ;
else if ( ! strcmp ( com_token , " master:httpqw " ) )
servertype = MT_MASTERHTTPQW ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " master " ) ) //any other sort of master, assume it's a qw master.
servertype = MT_MASTERQW ;
else if ( ! strcmp ( com_token , " bcast:qw " ) )
servertype = MT_BCASTQW ;
else if ( ! strcmp ( com_token , " bcast:q2 " ) )
servertype = MT_BCASTQ2 ;
2005-08-26 22:56:51 +00:00
else if ( ! strcmp ( com_token , " bcast:q3 " ) )
servertype = MT_BCASTQ3 ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " bcast:nq " ) )
servertype = MT_BCASTNQ ;
2005-05-17 02:36:54 +00:00
else if ( ! strcmp ( com_token , " bcast:dp " ) )
servertype = MT_BCASTDP ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " bcast " ) )
servertype = MT_BCASTQW ;
else if ( ! strcmp ( com_token , " favorite:qw " ) )
servertype = - MT_SINGLEQW ;
else if ( ! strcmp ( com_token , " favorite:q2 " ) )
servertype = - MT_SINGLEQ2 ;
2005-08-26 22:56:51 +00:00
else if ( ! strcmp ( com_token , " favorite:q3 " ) )
servertype = - MT_SINGLEQ3 ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " favorite:nq " ) )
servertype = - MT_SINGLENQ ;
else if ( ! strcmp ( com_token , " favorite " ) )
servertype = - MT_SINGLEQW ;
else
{
name = next ; //go back one token.
servertype = defaulttype ;
}
while ( * name < = ' ' & & * name ! = 0 ) //skip whitespace
name + + ;
next = name + strlen ( name ) - 1 ;
while ( * next < = ' ' & & next > name )
{
* next = ' \0 ' ;
next - - ;
}
if ( * file )
Master_LoadMasterList ( file , servertype , depth ) ;
else if ( servertype < 0 )
{
if ( NET_StringToAdr ( line , & net_from ) )
CL_ReadServerInfo ( va ( " \\ hostname \\ %s " , name ) , - servertype , true ) ;
else
Con_Printf ( " Failed to resolve address - \" %s \" \n " , line ) ;
}
else
2006-02-26 09:37:55 +00:00
{
switch ( servertype )
{
case MT_MASTERHTTP :
case MT_MASTERHTTPQW :
Master_AddMasterHTTP ( line , servertype , name ) ;
break ;
default :
Master_AddMaster ( line , servertype , name ) ;
}
}
2004-08-23 00:15:46 +00:00
}
2005-12-21 03:07:33 +00:00
VFS_CLOSE ( f ) ;
2004-08-23 00:15:46 +00:00
return true ;
}
void NET_SendPollPacket ( int len , void * data , netadr_t to )
{
int ret ;
struct sockaddr_qstorage addr ;
NetadrToSockadr ( & to , & addr ) ;
# ifdef USEIPX
2005-01-29 02:26:42 +00:00
if ( ( ( struct sockaddr * ) & addr ) - > sa_family = = AF_IPX )
2004-08-23 00:15:46 +00:00
{
lastpollsockIPX + + ;
if ( lastpollsockIPX > = POLLIPXSOCKETS )
lastpollsockIPX = 0 ;
2005-09-08 02:05:36 +00:00
if ( pollsocketsIPX [ lastpollsockIPX ] = = INVALID_SOCKET )
2004-08-23 00:15:46 +00:00
pollsocketsIPX [ lastpollsockIPX ] = IPX_OpenSocket ( PORT_ANY , true ) ;
2005-09-08 02:05:36 +00:00
if ( pollsocketsIPX [ lastpollsockIPX ] = = INVALID_SOCKET )
2005-03-18 06:14:07 +00:00
return ; //bother
2004-08-23 00:15:46 +00:00
ret = sendto ( pollsocketsIPX [ lastpollsockIPX ] , data , len , 0 , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
}
else
# endif
{
lastpollsockUDP + + ;
if ( lastpollsockUDP > = POLLUDPSOCKETS )
lastpollsockUDP = 0 ;
2005-09-08 02:05:36 +00:00
if ( pollsocketsUDP [ lastpollsockUDP ] = = INVALID_SOCKET )
2004-08-23 00:15:46 +00:00
pollsocketsUDP [ lastpollsockUDP ] = UDP_OpenSocket ( PORT_ANY , true ) ;
2005-09-08 02:05:36 +00:00
if ( pollsocketsUDP [ lastpollsockUDP ] = = INVALID_SOCKET )
2005-03-18 06:14:07 +00:00
return ; //bother
2004-08-23 00:15:46 +00:00
ret = sendto ( pollsocketsUDP [ lastpollsockUDP ] , data , len , 0 , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
}
if ( ret = = - 1 )
{
// wouldblock is silent
if ( qerrno = = EWOULDBLOCK )
return ;
if ( qerrno = = ECONNREFUSED )
return ;
if ( qerrno = = EADDRNOTAVAIL )
2005-03-18 06:14:07 +00:00
Con_DPrintf ( " NET_SendPollPacket Warning: %i \n " , qerrno ) ;
2004-08-23 00:15:46 +00:00
else
2005-03-18 06:14:07 +00:00
Con_Printf ( " NET_SendPollPacket ERROR: %i \n " , qerrno ) ;
2004-08-23 00:15:46 +00:00
}
}
int NET_CheckPollSockets ( void )
{
# define MAX_UDP_PACKET 8192 // one more than msg + header
extern qbyte net_message_buffer [ MAX_UDP_PACKET ] ;
int sock ;
SOCKET usesocket ;
for ( sock = 0 ; sock < POLLUDPSOCKETS + POLLIPXSOCKETS ; sock + + )
{
int ret ;
struct sockaddr_qstorage from ;
int fromlen ;
# ifdef USEIPX
if ( sock > = POLLUDPSOCKETS )
usesocket = pollsocketsIPX [ sock - POLLUDPSOCKETS ] ;
else
# endif
usesocket = pollsocketsUDP [ sock ] ;
2005-09-08 02:05:36 +00:00
if ( usesocket = = INVALID_SOCKET )
2004-08-23 00:15:46 +00:00
continue ;
fromlen = sizeof ( from ) ;
ret = recvfrom ( usesocket , ( char * ) net_message_buffer , sizeof ( net_message_buffer ) , 0 , ( struct sockaddr * ) & from , & fromlen ) ;
if ( ret = = - 1 )
{
if ( qerrno = = EWOULDBLOCK )
continue ;
if ( qerrno = = EMSGSIZE )
{
SockadrToNetadr ( & from , & net_from ) ;
Con_Printf ( " Warning: Oversize packet from %s \n " ,
NET_AdrToString ( net_from ) ) ;
continue ;
}
if ( qerrno = = ECONNABORTED | | qerrno = = ECONNRESET )
{
// Con_Printf ("Connection lost or aborted\n");
continue ;
}
2005-08-27 04:23:22 +00:00
Con_Printf ( " NET_CheckPollSockets: %i, %s \n " , qerrno , strerror ( qerrno ) ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
SockadrToNetadr ( & from , & net_from ) ;
net_message . cursize = ret ;
if ( ret = = sizeof ( net_message_buffer ) )
{
Con_Printf ( " Oversize packet from %s \n " , NET_AdrToString ( net_from ) ) ;
continue ;
}
if ( * ( int * ) net_message . data = = - 1 )
{
int c ;
char * s ;
2005-08-26 22:56:51 +00:00
2004-08-23 00:15:46 +00:00
MSG_BeginReading ( ) ;
MSG_ReadLong ( ) ; // skip the -1
c = msg_readcount ;
s = MSG_ReadStringLine ( ) ; //peek for q2 messages.
2005-08-26 22:56:51 +00:00
# ifdef Q2CLIENT
2004-08-23 00:15:46 +00:00
if ( ! strcmp ( s , " print " ) )
{
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEQ2 , false ) ;
continue ;
}
2005-08-26 22:56:51 +00:00
if ( ! strcmp ( s , " info " ) ) //parse a bit more...
2004-08-23 00:15:46 +00:00
{
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEQ2 , false ) ;
continue ;
}
2005-08-26 22:56:51 +00:00
if ( ! strncmp ( s , " servers " , 6 ) ) //parse a bit more...
2005-05-17 02:36:54 +00:00
{
2005-08-26 22:56:51 +00:00
msg_readcount = c + 7 ;
CL_MasterListParse ( SS_QUAKE2 , false ) ;
2005-05-17 02:36:54 +00:00
continue ;
}
2005-08-26 22:56:51 +00:00
# endif
# ifdef Q3CLIENT
if ( ! strcmp ( s , " statusResponse " ) )
2004-08-23 00:15:46 +00:00
{
2005-08-26 22:56:51 +00:00
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEQ3 , false ) ;
continue ;
}
# endif
if ( ! strncmp ( s , " getserversResponse \\ " , 19 ) ) //parse a bit more...
{
msg_readcount = c + 18 - 1 ;
CL_MasterListParse ( SS_DARKPLACES , true ) ;
2005-05-17 02:36:54 +00:00
continue ;
}
2005-08-26 22:56:51 +00:00
if ( ! strcmp ( s , " infoResponse " ) ) //parse a bit more...
2005-05-17 02:36:54 +00:00
{
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEDP , false ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
msg_readcount = c ;
c = MSG_ReadByte ( ) ;
if ( c = = A2C_PRINT ) //qw server reply.
{
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEQW , false ) ;
continue ;
}
if ( c = = M2C_MASTER_REPLY ) //qw master reply.
{
2005-05-17 02:36:54 +00:00
CL_MasterListParse ( false , false ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
}
# ifdef NQPROT
else
{ //connected packet? Must be a NQ packet.
char name [ 32 ] ;
char map [ 16 ] ;
int users , maxusers ;
int control ;
MSG_BeginReading ( ) ;
control = BigLong ( * ( ( int * ) net_message . data ) ) ;
MSG_ReadLong ( ) ;
if ( control = = - 1 )
continue ;
if ( ( control & ( ~ NETFLAG_LENGTH_MASK ) ) ! = NETFLAG_CTL )
continue ;
if ( ( control & NETFLAG_LENGTH_MASK ) ! = ret )
continue ;
if ( MSG_ReadByte ( ) ! = CCREP_SERVER_INFO )
continue ;
NET_StringToAdr ( MSG_ReadString ( ) , & net_from ) ;
Q_strncpyz ( name , MSG_ReadString ( ) , sizeof ( name ) ) ;
Q_strncpyz ( map , MSG_ReadString ( ) , sizeof ( map ) ) ;
users = MSG_ReadByte ( ) ;
maxusers = MSG_ReadByte ( ) ;
if ( MSG_ReadByte ( ) ! = NET_PROTOCOL_VERSION )
{
// Q_strcpy(name, "*");
// Q_strcat(name, name);
}
CL_ReadServerInfo ( va ( " \\ hostname \\ %s \\ map \\ %s \\ maxclients \\ %i " , name , map , maxusers ) , MT_SINGLENQ , false ) ;
}
# endif
continue ;
}
return 0 ;
}
void Master_RemoveKeepInfo ( serverinfo_t * sv )
{
sv - > special & = ~ SS_KEEPINFO ;
if ( sv - > moreinfo )
{
Z_Free ( sv - > moreinfo ) ;
sv - > moreinfo = NULL ;
}
}
void SListOptionChanged ( serverinfo_t * newserver )
{
if ( selectedserver . inuse )
{
serverinfo_t * oldserver ;
selectedserver . detail = NULL ;
if ( ! slist_cacheinfo . value ) //we have to flush it. That's the rules.
{
for ( oldserver = firstserver ; oldserver ; oldserver = oldserver - > next )
{
if ( NET_CompareAdr ( selectedserver . adr , oldserver - > adr ) ) //*(int*)selectedserver.ipaddress == *(int*)server->ipaddress && selectedserver.port == server->port)
{
if ( oldserver - > moreinfo )
{
Z_Free ( oldserver - > moreinfo ) ;
oldserver - > moreinfo = NULL ;
}
break ;
}
}
}
if ( ! newserver )
return ;
selectedserver . adr = newserver - > adr ;
if ( newserver - > moreinfo ) //we cached it.
{
selectedserver . detail = newserver - > moreinfo ;
return ;
}
//we don't know all the info, so send a request for it.
selectedserver . detail = newserver - > moreinfo = Z_Malloc ( sizeof ( serverdetailedinfo_t ) ) ;
newserver - > moreinfo - > numplayers = newserver - > players ;
strcpy ( newserver - > moreinfo - > info , " " ) ;
Info_SetValueForKey ( newserver - > moreinfo - > info , " hostname " , newserver - > name , sizeof ( newserver - > moreinfo - > info ) ) ;
2005-05-17 02:36:54 +00:00
newserver - > sends + + ;
Master_QueryServer ( newserver ) ;
2004-08-23 00:15:46 +00:00
}
}
2005-05-26 12:55:34 +00:00
# ifdef WEBCLIENT
2006-02-26 09:37:55 +00:00
void MasterInfo_ProcessHTTP ( char * name , qboolean success , int type )
2005-05-26 12:55:34 +00:00
{
netadr_t adr ;
char * s ;
char * el ;
serverinfo_t * info ;
if ( ! success )
return ;
el = COM_LoadTempFile ( name ) ;
2005-06-04 04:20:20 +00:00
if ( ! el )
return ;
2005-05-26 12:55:34 +00:00
while ( * el )
{
s = el ;
while ( * s < = ' ' & & * s ! = ' \n ' & & * s )
s + + ;
el = strchr ( s , ' \n ' ) ;
if ( ! el )
el = s + strlen ( s ) ;
else if ( el > s & & el [ - 1 ] = = ' \r ' )
el [ - 1 ] = ' \0 ' ;
if ( * s = = ' # ' ) //hash is a comment, apparently.
continue ;
* el = ' \0 ' ;
el + + ;
if ( ! NET_StringToAdr ( s , & adr ) )
continue ;
if ( ( info = Master_InfoForServer ( adr ) ) ) //remove if the server already exists.
{
info - > sends = 1 ; //reset.
}
else
{
info = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
info - > adr = adr ;
info - > sends = 1 ;
2006-02-26 09:37:55 +00:00
info - > special = type ;
2005-05-26 12:55:34 +00:00
info - > refreshtime = 0 ;
sprintf ( info - > name , " %s " , NET_AdrToString ( info - > adr ) ) ;
info - > next = firstserver ;
firstserver = info ;
}
}
2006-01-02 22:41:59 +00:00
FS_Remove ( name , FS_GAME ) ;
2005-05-26 12:55:34 +00:00
}
2006-02-26 09:37:55 +00:00
// wrapper functions for the different server types
void MasterInfo_ProcessHTTPNQ ( char * name , qboolean success )
{
MasterInfo_ProcessHTTP ( name , success , SS_NETQUAKE ) ;
}
void MasterInfo_ProcessHTTPQW ( char * name , qboolean success )
{
MasterInfo_ProcessHTTP ( name , success , 0 ) ;
}
2005-05-26 12:55:34 +00:00
# endif
2004-08-23 00:15:46 +00:00
//don't try sending to servers we don't support
2005-03-18 06:14:07 +00:00
void MasterInfo_Request ( master_t * mast , qboolean evenifwedonthavethefiles )
2004-08-23 00:15:46 +00:00
{
2005-05-26 12:55:34 +00:00
static int mastersequence ;
2004-08-23 00:15:46 +00:00
if ( ! mast )
return ;
switch ( mast - > type )
{
2005-08-26 22:56:51 +00:00
# ifdef Q3CLIENT
case MT_BCASTQ3 :
case MT_SINGLEQ3 :
NET_SendPollPacket ( 14 , va ( " %c%c%c%cgetstatus \n " , 255 , 255 , 255 , 255 ) , mast - > adr ) ;
break ;
case MT_MASTERQ3 :
{
char * str ;
str = va ( " %c%c%c%cgetservers %u empty full \x0A \n " , 255 , 255 , 255 , 255 , 68 ) ;
NET_SendPollPacket ( strlen ( str ) , str , mast - > adr ) ;
}
break ;
# endif
2004-08-23 00:15:46 +00:00
# ifdef Q2CLIENT
case MT_BCASTQ2 :
case MT_SINGLEQ2 :
# endif
case MT_SINGLEQW :
case MT_BCASTQW :
NET_SendPollPacket ( 11 , va ( " %c%c%c%cstatus \n " , 255 , 255 , 255 , 255 ) , mast - > adr ) ;
break ;
# ifdef NQPROT
case MT_BCASTNQ :
case MT_SINGLENQ :
SZ_Clear ( & net_message ) ;
2004-12-25 00:55:01 +00:00
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
2004-08-23 00:15:46 +00:00
MSG_WriteLong ( & net_message , 0 ) ; // save space for the header, filled in later
MSG_WriteByte ( & net_message , CCREQ_SERVER_INFO ) ;
MSG_WriteString ( & net_message , NET_GAMENAME_NQ ) ; //look for either sort of server
MSG_WriteByte ( & net_message , NET_PROTOCOL_VERSION ) ;
* ( ( int * ) net_message . data ) = BigLong ( NETFLAG_CTL | ( net_message . cursize & NETFLAG_LENGTH_MASK ) ) ;
NET_SendPollPacket ( net_message . cursize , net_message . data , mast - > adr ) ;
SZ_Clear ( & net_message ) ;
break ;
2005-05-17 02:36:54 +00:00
case MT_MASTERDP :
2005-05-26 12:55:34 +00:00
{
char * str ;
str = va ( " %c%c%c%cgetservers %s %u empty full \x0A \n " , 255 , 255 , 255 , 255 , com_gamename . string , 3 ) ;
NET_SendPollPacket ( strlen ( str ) , str , mast - > adr ) ;
}
2005-05-17 02:36:54 +00:00
break ;
case MT_SINGLEDP :
case MT_BCASTDP :
2005-05-26 12:55:34 +00:00
{
char * str ;
str = va ( " %c%c%c%cgetinfo " , 255 , 255 , 255 , 255 ) ;
NET_SendPollPacket ( strlen ( str ) , str , mast - > adr ) ;
}
2005-05-17 02:36:54 +00:00
break ;
2004-08-23 00:15:46 +00:00
# endif
case MT_MASTERQW :
NET_SendPollPacket ( 3 , " c \n " , mast - > adr ) ;
break ;
# ifdef Q2CLIENT
case MT_MASTERQ2 :
2005-03-18 06:14:07 +00:00
if ( evenifwedonthavethefiles | | COM_FDepthFile ( " pics/colormap.pcx " , true ) ! = 0x7fffffff ) //only query this master if we expect to be able to load it's maps.
2004-08-23 00:15:46 +00:00
NET_SendPollPacket ( 6 , " query " , mast - > adr ) ;
break ;
# endif
2005-05-26 12:55:34 +00:00
# ifdef WEBCLIENT
2006-02-26 09:37:55 +00:00
case MT_MASTERHTTP :
HTTP_CL_Get ( mast - > address , va ( " master_%i_%i.tmp " , mastersequence + + , mast - > servertype ) , MasterInfo_ProcessHTTPNQ ) ;
break ;
case MT_MASTERHTTPQW :
HTTP_CL_Get ( mast - > address , va ( " master_%i_%i.tmp " , mastersequence + + , mast - > servertype ) , MasterInfo_ProcessHTTPQW ) ;
2005-05-26 12:55:34 +00:00
break ;
2006-02-26 09:37:55 +00:00
# endif
2004-08-23 00:15:46 +00:00
}
}
void MasterInfo_WriteServers ( void )
{
char * typename ;
master_t * mast ;
serverinfo_t * server ;
FILE * mf , * qws ;
mf = fopen ( " masters.txt " , " wt " ) ;
if ( ! mf )
{
Con_Printf ( " Couldn't write masters.txt " ) ;
return ;
}
for ( mast = master ; mast ; mast = mast - > next )
{
switch ( mast - > type )
{
case MT_MASTERQW :
typename = " master:qw " ;
break ;
case MT_MASTERQ2 :
typename = " master:q2 " ;
break ;
2005-08-26 22:56:51 +00:00
case MT_MASTERQ3 :
typename = " master:q3 " ;
break ;
2005-05-17 02:36:54 +00:00
case MT_MASTERDP :
typename = " master:dp " ;
break ;
2005-09-28 23:37:15 +00:00
case MT_MASTERHTTP :
typename = " master:http " ;
break ;
2006-02-26 09:37:55 +00:00
case MT_MASTERHTTPQW :
typename = " master:httpqw " ;
break ;
2004-08-23 00:15:46 +00:00
case MT_BCASTQW :
typename = " bcast:qw " ;
break ;
case MT_BCASTQ2 :
typename = " bcast:q2 " ;
break ;
2005-08-26 22:56:51 +00:00
case MT_BCASTQ3 :
typename = " bcast:q3 " ;
break ;
2004-08-23 00:15:46 +00:00
case MT_BCASTNQ :
typename = " bcast:nq " ;
break ;
case MT_SINGLEQW :
typename = " single:qw " ;
break ;
case MT_SINGLEQ2 :
typename = " single:q2 " ;
break ;
2005-08-26 22:56:51 +00:00
case MT_SINGLEQ3 :
typename = " single:q3 " ;
break ;
2004-08-23 00:15:46 +00:00
case MT_SINGLENQ :
typename = " single:nq " ;
break ;
2005-09-28 23:37:15 +00:00
case MT_SINGLEDP :
typename = " single:dp " ;
break ;
2004-08-23 00:15:46 +00:00
default :
typename = " writeerror " ;
}
2005-09-28 23:37:15 +00:00
if ( mast - > address )
fprintf ( mf , " %s \t %s \t %s \n " , mast - > address , typename , mast - > name ) ;
else
fprintf ( mf , " %s \t %s \t %s \n " , NET_AdrToString ( mast - > adr ) , typename , mast - > name ) ;
2004-08-23 00:15:46 +00:00
}
if ( slist_writeserverstxt . value )
2005-03-18 06:14:07 +00:00
qws = fopen ( " servers.txt " , " wt " ) ;
2004-08-23 00:15:46 +00:00
else
qws = NULL ;
if ( qws )
fprintf ( mf , " \n %s \t %s \t %s \n \n " , " file servers.txt " , " favorite:qw " , " personal server list " ) ;
for ( server = firstserver ; server ; server = server - > next )
{
if ( server - > special & SS_FAVORITE )
{
2005-08-26 22:56:51 +00:00
if ( server - > special & SS_QUAKE3 )
fprintf ( mf , " %s \t %s \t %s \n " , NET_AdrToString ( server - > adr ) , " favorite:q3 " , server - > name ) ;
else if ( server - > special & SS_QUAKE2 )
2004-08-23 00:15:46 +00:00
fprintf ( mf , " %s \t %s \t %s \n " , NET_AdrToString ( server - > adr ) , " favorite:q2 " , server - > name ) ;
else if ( server - > special & SS_NETQUAKE )
fprintf ( mf , " %s \t %s \t %s \n " , NET_AdrToString ( server - > adr ) , " favorite:nq " , server - > name ) ;
else if ( qws ) //servers.txt doesn't support the extra info.
fprintf ( qws , " %s \t %s \n " , NET_AdrToString ( server - > adr ) , server - > name ) ;
else //read only? damn them!
fprintf ( mf , " %s \t %s \t %s \n " , NET_AdrToString ( server - > adr ) , " favorite:qw " , server - > name ) ;
}
}
if ( qws )
fclose ( qws ) ;
fclose ( mf ) ;
}
//poll master servers for server lists.
void MasterInfo_Begin ( void )
{
master_t * mast ;
if ( ! Master_LoadMasterList ( " masters.txt " , MT_MASTERQW , 5 ) )
{
Master_LoadMasterList ( " servers.txt " , MT_SINGLEQW , 1 ) ;
2005-05-26 12:55:34 +00:00
// if (q1servers) //qw master servers
2004-08-23 00:15:46 +00:00
{
2006-02-26 09:37:55 +00:00
Master_AddMasterHTTP ( " http://www.gameaholic.com/servers/qspy-quakeworld " , MT_MASTERHTTPQW , " gameaholic's QW master " ) ;
2004-08-23 00:15:46 +00:00
Master_AddMaster ( " 192.246.40.37:27000 " , MT_MASTERQW , " id Limbo " ) ;
Master_AddMaster ( " 192.246.40.37:27002 " , MT_MASTERQW , " id CTF " ) ;
Master_AddMaster ( " 192.246.40.37:27003 " , MT_MASTERQW , " id TeamFortress " ) ;
Master_AddMaster ( " 192.246.40.37:27004 " , MT_MASTERQW , " id Miscilaneous " ) ;
Master_AddMaster ( " 192.246.40.37:27006 " , MT_MASTERQW , " id Deathmatch Only " ) ;
Master_AddMaster ( " 150.254.66.120:27000 " , MT_MASTERQW , " Poland's master server. " ) ;
Master_AddMaster ( " 62.112.145.129:27000 " , MT_MASTERQW , " Ocrana master server. " ) ;
2005-11-14 01:28:05 +00:00
Master_AddMaster ( " master.edome.net " , MT_MASTERQW , " edome master server. " ) ;
Master_AddMaster ( " qwmaster.barrysworld.com " , MT_MASTERQW , " barrysworld master server. " ) ;
2005-12-21 03:07:33 +00:00
Master_AddMaster ( " qwmaster.ocrana.de:27000 " , MT_MASTERQW , " Ocrana2 master server. " ) ;
2005-11-14 01:28:05 +00:00
Master_AddMaster ( " 213.221.174.165:27000 " , MT_MASTERQW , " unknown1 master server. " ) ;
Master_AddMaster ( " 195.74.0.8 " , MT_MASTERQW , " unknown2 master server. " ) ;
Master_AddMaster ( " 192.246.40.37 " , MT_MASTERQW , " unknown3 master server. " ) ;
Master_AddMaster ( " 192.246.40.37:27006 " , MT_MASTERQW , " unknown4 master server. " ) ;
Master_AddMaster ( " 204.182.161.2 " , MT_MASTERQW , " unknown5 master server. " ) ;
2005-05-26 12:55:34 +00:00
Master_AddMaster ( " 255.255.255.255:27500 " , MT_BCASTQW , " Nearby QuakeWorld UDP servers. " ) ;
2004-08-23 00:15:46 +00:00
}
2005-05-26 12:55:34 +00:00
// if (q1servers) //nq master servers
{
2006-02-26 09:37:55 +00:00
Master_AddMasterHTTP ( " http://www.gameaholic.com/servers/qspy-quake " , MT_MASTERHTTP , " gameaholic's NQ master " ) ;
2005-05-26 12:55:34 +00:00
Master_AddMaster ( " 255.255.255.255:26000 " , MT_BCASTNQ , " Nearby Quake1 servers " ) ;
2005-05-17 02:36:54 +00:00
2005-05-26 12:55:34 +00:00
Master_AddMaster ( " ghdigital.com:27950 " , MT_MASTERDP , " DarkPlaces Master 1 " ) ;
Master_AddMaster ( " dpmaster.deathmask.net:27950 " , MT_MASTERDP , " DarkPlaces Master 2 " ) ;
Master_AddMaster ( " 12.166.196.192:27950 " , MT_MASTERDP , " DarkPlaces Master 3 " ) ;
2005-05-17 02:36:54 +00:00
2005-05-26 12:55:34 +00:00
Master_AddMaster ( " 255.255.255.255:26000 " , MT_BCASTDP , " Nearby DarkPlaces servers " ) ;
}
2005-05-17 02:36:54 +00:00
2005-05-26 12:55:34 +00:00
// if (q2servers) //q2
{
Master_AddMaster ( " 255.255.255.255:27910 " , MT_BCASTQ2 , " Nearby Quake2 UDP servers. " ) ;
Master_AddMaster ( " 00000000:ffffffffffff:27910 " , MT_BCASTQ2 , " Nearby Quake2 IPX servers. " ) ;
Master_AddMaster ( " 192.246.40.37:27900 " , MT_MASTERQ2 , " id q2 Master. " ) ;
}
2005-08-26 22:56:51 +00:00
//q3
{
Master_AddMaster ( " 255.255.255.255:27960 " , MT_BCASTQ3 , " Nearby Quake3 UDP servers. " ) ;
Master_AddMaster ( " master.quake3arena.com:27950 " , MT_MASTERQ3 , " Quake3 master server. " ) ;
}
2004-08-23 00:15:46 +00:00
}
2006-02-26 09:37:55 +00:00
2004-08-23 00:15:46 +00:00
for ( mast = master ; mast ; mast = mast - > next )
{
2005-03-18 06:14:07 +00:00
MasterInfo_Request ( mast , false ) ;
2004-08-23 00:15:46 +00:00
}
}
void Master_QueryServer ( serverinfo_t * server )
{
char data [ 2048 ] ;
2005-05-13 10:42:48 +00:00
server - > sends - - ;
2004-08-23 00:15:46 +00:00
server - > refreshtime = Sys_DoubleTime ( ) ;
2005-08-26 22:56:51 +00:00
if ( server - > special & SS_QUAKE3 )
sprintf ( data , " %c%c%c%cgetstatus " , 255 , 255 , 255 , 255 ) ;
else if ( server - > special & SS_DARKPLACES )
2005-05-17 02:36:54 +00:00
sprintf ( data , " %c%c%c%cgetinfo " , 255 , 255 , 255 , 255 ) ;
2005-05-26 12:55:34 +00:00
else if ( server - > special & SS_NETQUAKE )
{
# ifdef NQPROT
SZ_Clear ( & net_message ) ;
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
MSG_WriteLong ( & net_message , 0 ) ; // save space for the header, filled in later
MSG_WriteByte ( & net_message , CCREQ_SERVER_INFO ) ;
MSG_WriteString ( & net_message , NET_GAMENAME_NQ ) ; //look for either sort of server
MSG_WriteByte ( & net_message , NET_PROTOCOL_VERSION ) ;
* ( ( int * ) net_message . data ) = BigLong ( NETFLAG_CTL | ( net_message . cursize & NETFLAG_LENGTH_MASK ) ) ;
NET_SendPollPacket ( net_message . cursize , net_message . data , server - > adr ) ;
SZ_Clear ( & net_message ) ;
# endif
return ;
}
2005-05-17 02:36:54 +00:00
else
sprintf ( data , " %c%c%c%cstatus " , 255 , 255 , 255 , 255 ) ;
2004-08-23 00:15:46 +00:00
NET_SendPollPacket ( strlen ( data ) , data , server - > adr ) ;
}
//send a packet to each server in sequence.
void CL_QueryServers ( void )
{
static int poll ;
int op ;
serverinfo_t * server ;
op = poll ;
for ( server = firstserver ; op > 0 & & server ; server = server - > next , op - - ) ;
if ( ! server )
{
poll = 0 ;
return ;
}
if ( op = = 0 )
{
2005-05-13 10:42:48 +00:00
if ( server - > sends > 0 )
2004-08-23 00:15:46 +00:00
{
Master_QueryServer ( server ) ;
}
poll + + ;
return ;
}
poll = 0 ;
}
int Master_TotalCount ( void )
{
int count = 0 ;
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
count + + ;
}
return count ;
}
//true if server is on a different master's list.
serverinfo_t * Master_InfoForServer ( netadr_t addr )
{
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
if ( NET_CompareAdr ( info - > adr , addr ) )
return info ;
}
return NULL ;
}
serverinfo_t * Master_InfoForNum ( int num )
{
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
if ( num - - < = 0 )
return info ;
}
return NULL ;
}
void MasterInfo_RemovePlayers ( netadr_t adr )
{
player_t * p , * prev ;
prev = NULL ;
for ( p = mplayers ; p ; )
{
if ( NET_CompareAdr ( p - > adr , adr ) )
{
if ( prev )
prev - > next = p - > next ;
else
mplayers = p - > next ;
Z_Free ( p ) ;
p = prev ;
continue ;
}
else
prev = p ;
p = p - > next ;
}
}
void MasterInfo_AddPlayer ( netadr_t serveradr , char * name , int ping , int frags , int colours , char * skin )
{
player_t * p ;
p = Z_Malloc ( sizeof ( player_t ) ) ;
p - > next = mplayers ;
p - > adr = serveradr ;
p - > colour = colours ;
p - > frags = frags ;
Q_strncpyz ( p - > name , name , sizeof ( p - > name ) ) ;
Q_strncpyz ( p - > skin , skin , sizeof ( p - > skin ) ) ;
mplayers = p ;
}
//we got told about a server, parse it's info
int CL_ReadServerInfo ( char * msg , int servertype , qboolean favorite )
{
serverdetailedinfo_t details ;
char * token ;
char * nl ;
char * name ;
int ping ;
int len ;
serverinfo_t * info ;
info = Master_InfoForServer ( net_from ) ;
if ( ! info ) //not found...
{
2005-08-26 22:56:51 +00:00
if ( atoi ( Info_ValueForKey ( msg , " sv_punkbuster " ) ) )
return false ; //never add servers that require punkbuster. :(
if ( atoi ( Info_ValueForKey ( msg , " sv_pure " ) ) )
return false ; //we don't support the filesystem hashing. :(
2004-08-23 00:15:46 +00:00
info = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
info - > adr = net_from ;
sprintf ( info - > name , " %s " , NET_AdrToString ( info - > adr ) ) ;
info - > next = firstserver ;
firstserver = info ;
}
else
{
MasterInfo_RemovePlayers ( info - > adr ) ;
}
nl = strchr ( msg , ' \n ' ) ;
if ( nl )
{
* nl = ' \0 ' ;
nl + + ;
}
name = Info_ValueForKey ( msg , " hostname " ) ;
2005-08-26 22:56:51 +00:00
if ( ! * name )
name = Info_ValueForKey ( msg , " sv_hostname " ) ;
2004-08-23 00:15:46 +00:00
Q_strncpyz ( info - > name , name , sizeof ( info - > name ) ) ;
info - > special = info - > special & ( SS_FAVORITE | SS_KEEPINFO ) ; //favorite is never cleared
2005-11-14 01:28:05 +00:00
if ( ! strcmp ( DISTRIBUTION , Info_ValueForKey ( msg , " *distrib " ) ) )
2004-08-23 00:15:46 +00:00
info - > special | = SS_FTESERVER ;
2005-11-14 01:28:05 +00:00
else if ( ! strncmp ( DISTRIBUTION , Info_ValueForKey ( msg , " *version " ) , 3 ) )
2004-08-23 00:15:46 +00:00
info - > special | = SS_FTESERVER ;
2004-10-10 06:32:29 +00:00
2005-05-17 02:36:54 +00:00
if ( servertype = = MT_SINGLEDP )
2005-08-26 22:56:51 +00:00
{
if ( atoi ( Info_ValueForKey ( msg , " protocol " ) ) > 60 )
info - > special | = SS_QUAKE3 ;
else
info - > special | = SS_DARKPLACES ;
}
2005-05-17 02:36:54 +00:00
else if ( servertype = = MT_SINGLEQ2 )
2004-08-23 00:15:46 +00:00
info - > special | = SS_QUAKE2 ;
2005-08-26 22:56:51 +00:00
else if ( servertype = = MT_SINGLEQ3 )
info - > special | = SS_QUAKE3 ;
2004-08-23 00:15:46 +00:00
else if ( servertype = = MT_SINGLENQ )
info - > special | = SS_NETQUAKE ;
if ( favorite ) //was specifically named, not retrieved from a master.
info - > special | = SS_FAVORITE ;
ping = ( Sys_DoubleTime ( ) - info - > refreshtime ) * 1000 ;
if ( ping > 0xffff )
info - > ping = 0xffff ;
else
info - > ping = ping ;
info - > players = 0 ;
info - > maxplayers = atoi ( Info_ValueForKey ( msg , " maxclients " ) ) ;
2005-05-26 12:55:34 +00:00
if ( ! info - > maxplayers )
info - > maxplayers = atoi ( Info_ValueForKey ( msg , " sv_maxclients " ) ) ;
2004-08-23 00:15:46 +00:00
info - > tl = atoi ( Info_ValueForKey ( msg , " timelimit " ) ) ;
info - > fl = atoi ( Info_ValueForKey ( msg , " fraglimit " ) ) ;
2005-09-28 23:37:15 +00:00
if ( * Info_ValueForKey ( msg , " *qtv " ) )
info - > special | = SS_QTV ;
2005-08-26 22:56:51 +00:00
if ( servertype = = MT_SINGLEQ3 | | servertype = = MT_SINGLEQ2 | | servertype = = MT_SINGLEDP )
2004-08-23 00:15:46 +00:00
{
Q_strncpyz ( info - > gamedir , Info_ValueForKey ( msg , " gamename " ) , sizeof ( info - > gamedir ) ) ;
Q_strncpyz ( info - > map , Info_ValueForKey ( msg , " mapname " ) , sizeof ( info - > map ) ) ;
}
else
{
Q_strncpyz ( info - > gamedir , Info_ValueForKey ( msg , " *gamedir " ) , sizeof ( info - > gamedir ) ) ;
Q_strncpyz ( info - > map , Info_ValueForKey ( msg , " map " ) , sizeof ( info - > map ) ) ;
}
2005-06-04 04:20:20 +00:00
strcpy ( details . info , msg ) ;
msg = msg + strlen ( msg ) + 1 ;
info - > players = details . numplayers = 0 ;
if ( ! strchr ( msg , ' \n ' ) )
info - > players = atoi ( Info_ValueForKey ( details . info , " clients " ) ) ;
else
2004-08-23 00:15:46 +00:00
{
int clnum ;
for ( clnum = 0 ; clnum < MAX_CLIENTS ; clnum + + )
{
nl = strchr ( msg , ' \n ' ) ;
if ( ! nl )
break ;
* nl = ' \0 ' ;
token = msg ;
if ( ! token )
break ;
details . players [ clnum ] . userid = atoi ( token ) ;
token = strchr ( token + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . frags = atoi ( token ) ;
token = strchr ( token + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . time = atoi ( token ) ;
msg = token ;
token = strchr ( msg + 1 , ' ' ) ;
if ( ! token ) //probably q2 response
{
//see if this is actually a Quake2 server.
token = strchr ( msg + 1 , ' \" ' ) ;
if ( ! token ) //it wasn't.
break ;
details . players [ clnum ] . ping = details . players [ clnum ] . frags ;
details . players [ clnum ] . frags = details . players [ clnum ] . userid ;
msg = strchr ( token + 1 , ' \" ' ) ;
if ( ! msg )
break ;
len = msg - token ;
if ( len > = sizeof ( details . players [ clnum ] . name ) )
len = sizeof ( details . players [ clnum ] . name ) ;
Q_strncpyz ( details . players [ clnum ] . name , token + 1 , len ) ;
details . players [ clnum ] . skin [ 0 ] = ' \0 ' ;
details . players [ clnum ] . topc = 0 ;
details . players [ clnum ] . botc = 0 ;
details . players [ clnum ] . time = 0 ;
}
else //qw responce
{
details . players [ clnum ] . time = atoi ( token ) ;
msg = token ;
token = strchr ( msg + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . ping = atoi ( token ) ;
token = strchr ( token + 1 , ' \" ' ) ;
if ( ! token )
break ;
msg = strchr ( token + 1 , ' \" ' ) ;
if ( ! msg )
break ;
len = msg - token ;
if ( len > = sizeof ( details . players [ clnum ] . name ) )
len = sizeof ( details . players [ clnum ] . name ) ;
Q_strncpyz ( details . players [ clnum ] . name , token + 1 , len ) ;
details . players [ clnum ] . name [ len ] = ' \0 ' ;
token = strchr ( msg + 1 , ' \" ' ) ;
if ( ! token )
break ;
msg = strchr ( token + 1 , ' \" ' ) ;
if ( ! msg )
break ;
len = msg - token ;
if ( len > = sizeof ( details . players [ clnum ] . skin ) )
len = sizeof ( details . players [ clnum ] . skin ) ;
Q_strncpyz ( details . players [ clnum ] . skin , token + 1 , len ) ;
details . players [ clnum ] . skin [ len ] = ' \0 ' ;
token = strchr ( msg + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . topc = atoi ( token ) ;
token = strchr ( token + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . botc = atoi ( token ) ;
}
MasterInfo_AddPlayer ( info - > adr , details . players [ clnum ] . name , details . players [ clnum ] . ping , details . players [ clnum ] . frags , details . players [ clnum ] . topc * 4 | details . players [ clnum ] . botc , details . players [ clnum ] . skin ) ;
info - > players = + + details . numplayers ;
msg = nl ;
if ( ! msg )
break ; //erm...
msg + + ;
}
}
if ( ! info - > moreinfo & & ( ( slist_cacheinfo . value = = 2 | | NET_CompareAdr ( info - > adr , selectedserver . adr ) ) | | ( info - > special & SS_KEEPINFO ) ) )
info - > moreinfo = Z_Malloc ( sizeof ( serverdetailedinfo_t ) ) ;
if ( NET_CompareAdr ( info - > adr , selectedserver . adr ) )
selectedserver . detail = info - > moreinfo ;
if ( info - > moreinfo )
memcpy ( info - > moreinfo , & details , sizeof ( serverdetailedinfo_t ) ) ;
return true ;
}
//rewrite to scan for existing server instead of wiping all.
2005-05-17 02:36:54 +00:00
void CL_MasterListParse ( int type , qboolean slashpad )
2004-08-23 00:15:46 +00:00
{
serverinfo_t * info ;
serverinfo_t * last , * old ;
int p1 , p2 ;
MSG_ReadByte ( ) ;
last = firstserver ;
2005-05-17 02:36:54 +00:00
while ( msg_readcount + 6 < net_message . cursize )
2004-08-23 00:15:46 +00:00
{
2005-05-17 02:36:54 +00:00
if ( slashpad )
{
if ( MSG_ReadByte ( ) ! = ' \\ ' )
break ;
}
2004-08-23 00:15:46 +00:00
info = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
info - > adr . type = NA_IP ;
2006-02-17 02:51:59 +00:00
info - > adr . address . ip [ 0 ] = MSG_ReadByte ( ) ;
info - > adr . address . ip [ 1 ] = MSG_ReadByte ( ) ;
info - > adr . address . ip [ 2 ] = MSG_ReadByte ( ) ;
info - > adr . address . ip [ 3 ] = MSG_ReadByte ( ) ;
2004-08-23 00:15:46 +00:00
p1 = MSG_ReadByte ( ) ;
p2 = MSG_ReadByte ( ) ;
2005-05-26 12:55:34 +00:00
info - > adr . port = htons ( ( unsigned short ) ( ( p1 < < 8 ) | p2 ) ) ;
2005-05-17 02:36:54 +00:00
if ( ! info - > adr . port )
{
Z_Free ( info ) ;
break ;
}
2004-08-23 00:15:46 +00:00
if ( ( old = Master_InfoForServer ( info - > adr ) ) ) //remove if the server already exists.
{
2005-05-13 10:42:48 +00:00
old - > sends = 1 ; //reset.
2004-08-23 00:15:46 +00:00
Z_Free ( info ) ;
}
else
{
2005-05-17 02:36:54 +00:00
info - > sends = 1 ;
info - > special = type ;
2004-08-23 00:15:46 +00:00
info - > refreshtime = 0 ;
sprintf ( info - > name , " %s " , NET_AdrToString ( info - > adr ) ) ;
info - > next = last ;
last = info ;
}
}
firstserver = last ;
}
# endif