/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cl_serverlist.c -- interactuates with the master server #include "client.h" //========================================================= typedef struct serverlist_s { char address[32]; struct serverlist_s *pnext; } serverlist_t; serverlist_t *serverList; static qboolean filter_allow_full = qfalse; static qboolean filter_allow_empty = qfalse; //========================================================= //================= //CL_FreeServerlist //================= void CL_FreeServerlist( void ) { serverlist_t *ptr; while( serverList ) { ptr = serverList; serverList = serverList->pnext; Mem_TempFree(ptr); } } //================= //CL_ServerIsInList //================= qboolean CL_ServerIsInList( char *adr ) { serverlist_t *server; if( !serverList ) return qfalse; server = serverList; while( server ) { if( !Q_stricmp(server->address, adr) ) return qtrue; server = server->pnext; } return qfalse; } //================= //CL_AddServerToList //================= qboolean CL_AddServerToList( char *adr ) { serverlist_t *newserv; netadr_t nadr; if( !adr || !strlen(adr) ) return qfalse; if( !NET_StringToAdr(adr, &nadr) ) return qfalse; if( CL_ServerIsInList(adr) ) return qfalse; newserv = (serverlist_t*)Mem_TempMalloc( sizeof(serverlist_t) ); Q_strncpyz( newserv->address, adr, sizeof(newserv->address) ); newserv->pnext = serverList; serverList = newserv; return qtrue; } //================= //CL_LoadServerList //================= qboolean CL_LoadServerList( void ) { qbyte *buf; char *ptr, *tok; int filehandle; int length; // load the file length = FS_FOpenFile( "serverlist.txt", &filehandle, FS_READ ); if( length < 1 ) { if( length == -1 ) return qfalse; FS_FCloseFile( filehandle ); return qfalse; } buf = Mem_TempMalloc( length + 1 ); FS_Read( buf, length, filehandle ); FS_FCloseFile( filehandle ); if( !buf ) { Mem_TempFree( buf ); return qfalse; } // proceed ptr = ( char * )buf; while( ptr ) { tok = COM_ParseExt( &ptr, qtrue ); if( !tok ) break; CL_AddServerToList( tok ); } Mem_TempFree( buf ); return qtrue; } //================= //CL_WriteServerList //================= void CL_WriteServerList( void ) { int serversfile, length = 0; serverlist_t *server; if( !serverList ) return; length = FS_FOpenFile( "serverlist.txt", &serversfile, FS_WRITE ); if( length == -1 ) { return; } server = serverList; while( server ) { FS_Write( server->address, strlen(server->address), serversfile ); FS_Write( " ", 1, serversfile ); server = server->pnext; } FS_FCloseFile( serversfile ); } /* ================= CL_ParseGetInfoResponse Handle a reply from getservers message to master server ================= */ void CL_ParseGetInfoResponse( msg_t *msg ) { char *s = MSG_ReadString( msg ); Com_Printf( "%s\n", s ); } /* ================= CL_QueryGetInfoMessage_f - getinfo 83.97.146.17:27911 ================= */ void CL_QueryGetInfoMessage_f( void ) { netadr_t adr; char *requeststring; cvar_t *net_noudp, *net_noipx; char *server; //get what master server = Cmd_Argv(1); if( !server || !(*server) ) { Com_Printf( "no address provided %s...\n", server ? server : "" ); return; } NET_Config( qtrue ); // allow remote net_noipx = Cvar_Get( "net_noipx", "0", CVAR_NOSET ); net_noudp = Cvar_Get( "net_noudp", "0", CVAR_NOSET ); // if( !net_noudp->integer ) { // Com_Printf( "udp disabled\n" ); // return; // } requeststring = va( "getinfo" ); // send a broadcast packet Com_Printf( "quering %s...\n", server ); if( NET_StringToAdr( server, &adr ) ) { if( !adr.port ) adr.port = BigShort( PORT_SERVER ); Netchan_OutOfBandPrint( NS_CLIENT, adr, requeststring ); } else { Com_Printf( "Bad address: %s\n", server ); } } typedef struct { unsigned int starttime; char address[MAX_QPATH]; }pingserver_t; static pingserver_t pingServer; void CL_PingServer_f( void ) { char *address_string; char requestString[32]; netadr_t adr; if( Cmd_Argc() < 2 ) Com_Printf( "Usage: pingserver [ip:port]\n" ); address_string = Cmd_Argv(1); if( !Q_stricmp(address_string, pingServer.address) && cls.realtime - pingServer.starttime < SERVER_PINGING_TIMEOUT ) // don't ping again before getting the reply return; Q_strncpyz( pingServer.address, address_string, sizeof(pingServer.address) ); pingServer.starttime = cls.realtime; Q_snprintfz( requestString, sizeof( requestString ), "info %i %s %s", PROTOCOL_VERSION, filter_allow_full ? "full" : "", filter_allow_empty ? "empty" : "" ); if( NET_StringToAdr( address_string, &adr ) ) Netchan_OutOfBandPrint( NS_CLIENT, adr, requestString ); } /* ================= CL_ParseStatusMessage Handle a reply from a ping ================= */ void CL_ParseStatusMessage( msg_t *msg ) { char *s = MSG_ReadString( msg ); Com_Printf( "%s\n", s ); if( !Q_stricmp( NET_AdrToString(&net_from), pingServer.address ) ) { unsigned int ping = cls.realtime - pingServer.starttime; CL_UIModule_AddToServerList( NET_AdrToString(&net_from), va("\\\\ping\\\\%i%s", ping,s) ); pingServer.address[0] = 0; pingServer.starttime = 0; return; } CL_UIModule_AddToServerList( NET_AdrToString(&net_from), s ); } /* ================= CL_ParseGetServersResponse Handle a reply from getservers message to master server ================= */ void CL_ParseGetServersResponse2( msg_t *msg ) { char adrString[32]; qbyte addr[4]; unsigned short port; netadr_t adr; MSG_BeginReading( msg ); MSG_ReadLong( msg ); // skip the -1 //jump over the command name if ( ! MSG_SkipData( msg, strlen( "getserversResponse\\" ) ) ) { Com_Printf( "Invalid master packet ( missing getserversResponse )\n" ); return; } while( msg->readcount +6 <= msg->cursize ) { MSG_ReadData( msg, addr, 4 ); port = BigShort( MSG_ReadShort( msg ) ); if ( 0 == port ) { // last server seen break; } Q_snprintfz( adrString, sizeof( adrString ), "%u.%u.%u.%u:%u", addr[0], addr[1], addr[2], addr[3], port ); Com_DPrintf( "%s\n", adrString ); if( !NET_StringToAdr( adrString, &adr ) ) { Com_Printf( "Bad address: %s\n", adrString ); continue; } //Netchan_OutOfBandPrint( NS_CLIENT, adr, requestString ); CL_AddServerToList( adrString ); if( '\\' != MSG_ReadChar( msg ) ) { Com_Printf( "Invalid master packet ( missing seperator )\n" ); break; } } } //jal: I will remove this function soon //jal: the browser bug was the response string being parsed by //jal: using MSG_ParseStringLine instead of using MSG_ParseString. //jal: MSG_ParseStringLine cutted off the string when it found //jal: a line ending, a zero or a -1. void CL_ParseGetServersResponse( msg_t *msg ) { CL_FreeServerlist(); CL_ParseGetServersResponse2( msg ); // CL_LoadServerList(); //jal: tmp // CL_WriteServerList(); #if 1 //send the servers to the ui { serverlist_t *server; netadr_t adr; server = serverList; while( server ) { if( NET_StringToAdr( server->address, &adr ) ) { CL_UIModule_AddToServerList( server->address, "\\\\EOT" ); } server = server->pnext; } } #else { serverlist_t *server; char requestString[32]; netadr_t adr; Q_snprintfz( requestString, sizeof( requestString ), "info %i %s %s", PROTOCOL_VERSION, filter_allow_full ? "full" : "", filter_allow_empty ? "empty" : "" ); server = serverList; while( server ) { if( NET_StringToAdr( server->address, &adr ) ) Netchan_OutOfBandPrint( NS_CLIENT, adr, requestString ); server = server->pnext; } } #endif CL_FreeServerlist(); } /* ================= CL_GetServers_f ================= */ void CL_GetServers_f( void ) { netadr_t adr; char *requeststring; cvar_t *net_noudp, *net_noipx; char gameName[MAX_QPATH]; int i; char *modname; NET_Config( qtrue ); // allow remote net_noipx = Cvar_Get( "net_noipx", "0", CVAR_NOSET ); net_noudp = Cvar_Get( "net_noudp", "0", CVAR_NOSET ); filter_allow_full = qfalse; filter_allow_empty = qfalse; for( i=0; iinteger ) { adr.type = NA_BROADCAST; adr.port = BigShort( PORT_SERVER ); Netchan_OutOfBandPrint( NS_CLIENT, adr, requeststring ); } else if( !net_noipx->integer ) { adr.type = NA_BROADCAST_IPX; adr.port = BigShort( PORT_SERVER ); Netchan_OutOfBandPrint( NS_CLIENT, adr, requeststring ); } } else if( !net_noudp->integer ) { char *master; //get what master master = Cmd_Argv(2); if( !master || !(*master) ) return; modname = Cmd_Argv(3); if( !modname || !modname[0] || !Q_stricmp(modname, "basewsw") ) { // never allow anyone to use basewsw as mod name Q_strncpyz( gameName, APPLICATION, sizeof( gameName ) ); } else { Q_strncpyz( gameName, modname, sizeof( gameName ) ); } toupper( gameName[0] ); // make sure it starts with capital // create the message requeststring = va( "getservers %s %i %s %s", gameName, PROTOCOL_VERSION, filter_allow_full ? "full" : "", filter_allow_empty ? "empty" : "" ); // send a broadcast packet if( NET_StringToAdr( master, &adr ) ) { adr.type = NA_IP; if( !adr.port ) adr.port = BigShort( PORT_MASTER ); Netchan_OutOfBandPrint( NS_CLIENT, adr, requeststring ); Com_Printf( "quering %s...%s\n", master, NET_AdrToString(&adr) ); } else { Com_Printf( "Bad address: %s\n", master ); } } } //=============================================================================