summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2005-12-28 02:32:43 +0000
committerTim Angus <tim@ngus.net>2005-12-28 02:32:43 +0000
commit1dc7e94283f026b17c1e793cbf7542872812ffda (patch)
tree33de56bca208626f1e7c77853255afc2b8244279
parent4b614e63d7da358a8a30e61a89365add79ecde9c (diff)
* Added master server to source, based on dpmaster
* Removed gametype, fraglimit and dmflags cvars * Removed CD key authentication stuff * Implemented a means to save and restore cmd context * Bumped protocol version up to 69 (same as 68) * Removed various references to punkbuster * Maps on create server menu now sorted by name * Fixed some warnings
-rw-r--r--src/client/cl_console.c4
-rw-r--r--src/client/cl_main.c215
-rw-r--r--src/client/cl_ui.c60
-rw-r--r--src/client/client.h2
-rw-r--r--src/game/bg_public.h2
-rw-r--r--src/game/g_local.h3
-rw-r--r--src/game/g_main.c6
-rw-r--r--src/master/Makefile52
-rw-r--r--src/master/common.h88
-rw-r--r--src/master/master.c657
-rw-r--r--src/master/messages.c526
-rw-r--r--src/master/messages.h35
-rw-r--r--src/master/servers.c666
-rw-r--r--src/master/servers.h102
-rw-r--r--src/null/null_client.c3
-rw-r--r--src/qcommon/cm_trace.c3
-rw-r--r--src/qcommon/cmd.c93
-rw-r--r--src/qcommon/common.c72
-rw-r--r--src/qcommon/cvar.c3
-rw-r--r--src/qcommon/files.c10
-rw-r--r--src/qcommon/q_shared.h4
-rw-r--r--src/qcommon/qcommon.h22
-rw-r--r--src/server/server.h1
-rw-r--r--src/server/sv_ccmds.c11
-rw-r--r--src/server/sv_client.c140
-rw-r--r--src/server/sv_init.c6
-rw-r--r--src/server/sv_main.c6
-rw-r--r--src/server/sv_rankings.c2
-rw-r--r--src/ui/ui_atoms.c5
-rw-r--r--src/ui/ui_gameinfo.c23
-rw-r--r--src/ui/ui_local.h13
-rw-r--r--src/ui/ui_main.c75
-rw-r--r--src/ui/ui_public.h10
-rw-r--r--src/ui/ui_syscalls.asm3
-rw-r--r--src/ui/ui_syscalls.c12
-rw-r--r--src/unix/Makefile10
-rw-r--r--ui/createserver.menu59
-rw-r--r--ui/joinserver.menu104
-rw-r--r--ui/quitcredit.menu1
39 files changed, 2290 insertions, 819 deletions
diff --git a/src/client/cl_console.c b/src/client/cl_console.c
index d80bff0f..efbf2d17 100644
--- a/src/client/cl_console.c
+++ b/src/client/cl_console.c
@@ -378,9 +378,13 @@ void CL_ConsolePrint( char *txt ) {
}
if( !skipnotify && !( cls.keyCatchers & KEYCATCH_CONSOLE ) ) {
+ Cmd_SaveCmdContext( );
+
// feed the text to cgame
Cmd_TokenizeString( txt );
CL_GameConsoleText( );
+
+ Cmd_RestoreCmdContext( );
}
color = ColorIndex(COLOR_WHITE);
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index bb322b6a..0789ac9b 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -820,116 +820,31 @@ void CL_RequestMotd( void ) {
if ( !cl_motd->integer ) {
return;
}
- Com_Printf( "Resolving %s\n", UPDATE_SERVER_NAME );
- if ( !NET_StringToAdr( UPDATE_SERVER_NAME, &cls.updateServer ) ) {
+ Com_Printf( "Resolving %s\n", MASTER_SERVER_NAME );
+ if ( !NET_StringToAdr( MASTER_SERVER_NAME, &cls.updateServer ) ) {
Com_Printf( "Couldn't resolve address\n" );
return;
}
- cls.updateServer.port = BigShort( PORT_UPDATE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", UPDATE_SERVER_NAME,
+ cls.updateServer.port = BigShort( PORT_MASTER );
+ Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", MASTER_SERVER_NAME,
cls.updateServer.ip[0], cls.updateServer.ip[1],
cls.updateServer.ip[2], cls.updateServer.ip[3],
BigShort( cls.updateServer.port ) );
-
+
info[0] = 0;
// NOTE TTimo xoring against Com_Milliseconds, otherwise we may not have a true randomization
// only srand I could catch before here is tr_noise.c l:26 srand(1001)
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=382
// NOTE: the Com_Milliseconds xoring only affects the lower 16-bit word,
// but I decided it was enough randomization
- Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ), "%i", ((rand() << 16) ^ rand()) ^ Com_Milliseconds());
+ Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ),
+ "%i", ((rand() << 16) ^ rand()) ^ Com_Milliseconds());
Info_SetValueForKey( info, "challenge", cls.updateChallenge );
Info_SetValueForKey( info, "renderer", cls.glconfig.renderer_string );
Info_SetValueForKey( info, "version", com_version->string );
- NET_OutOfBandPrint( NS_CLIENT, cls.updateServer, "getmotd \"%s\"\n", info );
-}
-
-/*
-===================
-CL_RequestAuthorization
-
-Authorization server protocol
------------------------------
-
-All commands are text in Q3 out of band packets (leading 0xff 0xff 0xff 0xff).
-
-Whenever the client tries to get a challenge from the server it wants to
-connect to, it also blindly fires off a packet to the authorize server:
-
-getKeyAuthorize <challenge> <cdkey>
-
-cdkey may be "demo"
-
-
-#OLD The authorize server returns a:
-#OLD
-#OLD keyAthorize <challenge> <accept | deny>
-#OLD
-#OLD A client will be accepted if the cdkey is valid and it has not been used by any other IP
-#OLD address in the last 15 minutes.
-
-
-The server sends a:
-
-getIpAuthorize <challenge> <ip>
-
-The authorize server returns a:
-
-ipAuthorize <challenge> <accept | deny | demo | unknown >
-
-A client will be accepted if a valid cdkey was sent by that ip (only) in the last 15 minutes.
-If no response is received from the authorize server after two tries, the client will be let
-in anyway.
-===================
-*/
-void CL_RequestAuthorization( void ) {
- char nums[64];
- int i, j, l;
- cvar_t *fs;
-
- if ( !cls.authorizeServer.port ) {
- Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
- if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &cls.authorizeServer ) ) {
- Com_Printf( "Couldn't resolve address\n" );
- return;
- }
-
- cls.authorizeServer.port = BigShort( PORT_AUTHORIZE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
- cls.authorizeServer.ip[0], cls.authorizeServer.ip[1],
- cls.authorizeServer.ip[2], cls.authorizeServer.ip[3],
- BigShort( cls.authorizeServer.port ) );
- }
- if ( cls.authorizeServer.type == NA_BAD ) {
- return;
- }
-
- if ( Cvar_VariableValue( "fs_restrict" ) ) {
- Q_strncpyz( nums, "demota", sizeof( nums ) );
- } else {
- // only grab the alphanumeric values from the cdkey, to avoid any dashes or spaces
- j = 0;
- l = strlen( cl_cdkey );
- if ( l > 32 ) {
- l = 32;
- }
- for ( i = 0 ; i < l ; i++ ) {
- if ( ( cl_cdkey[i] >= '0' && cl_cdkey[i] <= '9' )
- || ( cl_cdkey[i] >= 'a' && cl_cdkey[i] <= 'z' )
- || ( cl_cdkey[i] >= 'A' && cl_cdkey[i] <= 'Z' )
- ) {
- nums[j] = cl_cdkey[i];
- j++;
- }
- }
- nums[j] = 0;
- }
-
- fs = Cvar_Get ("cl_anonymous", "0", CVAR_INIT|CVAR_SYSTEMINFO );
-
- NET_OutOfBandPrint(NS_CLIENT, cls.authorizeServer, va("getKeyAuthorize %i %s", fs->integer, nums) );
+ NET_OutOfBandPrint( NS_CLIENT, cls.updateServer, "getmotd%s", info );
}
/*
@@ -1519,9 +1434,6 @@ void CL_CheckForResend( void ) {
switch ( cls.state ) {
case CA_CONNECTING:
// requesting a challenge
- if ( !Sys_IsLANAddress( clc.serverAddress ) ) {
- CL_RequestAuthorization();
- }
NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "getchallenge");
break;
@@ -1596,27 +1508,24 @@ CL_MotdPacket
===================
*/
-void CL_MotdPacket( netadr_t from ) {
- char *challenge;
- char *info;
+void CL_MotdPacket( netadr_t from, const char *info ) {
+ char *v;
// if not from our server, ignore it
if ( !NET_CompareAdr( from, cls.updateServer ) ) {
return;
}
- info = Cmd_Argv(1);
-
// check challenge
- challenge = Info_ValueForKey( info, "challenge" );
- if ( strcmp( challenge, cls.updateChallenge ) ) {
+ v = Info_ValueForKey( info, "challenge" );
+ if ( strcmp( v, cls.updateChallenge ) ) {
return;
}
- challenge = Info_ValueForKey( info, "motd" );
+ v = Info_ValueForKey( info, "motd" );
Q_strncpyz( cls.updateInfoString, info, sizeof( cls.updateInfoString ) );
- Cvar_Set( "cl_motdString", challenge );
+ Cvar_Set( "cl_motdString", v );
}
/*
@@ -1706,7 +1615,7 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) {
addresses[numservers].ip[1],
addresses[numservers].ip[2],
addresses[numservers].ip[3],
- addresses[numservers].port );
+ BigShort( addresses[numservers].port ) );
numservers++;
if (numservers >= MAX_SERVERSPERPACKET) {
@@ -1773,7 +1682,8 @@ Responses to broadcasts, etc
*/
void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
char *s;
- char *c;
+ char c[ BIG_INFO_STRING ];
+ char arg1[ BIG_INFO_STRING ];
MSG_BeginReadingOOB( msg );
MSG_ReadLong( msg ); // skip the -1
@@ -1782,7 +1692,8 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
Cmd_TokenizeString( s );
- c = Cmd_Argv(0);
+ Q_strncpyz( c, Cmd_Argv( 0 ), BIG_INFO_STRING );
+ Q_strncpyz( arg1, Cmd_Argv( 1 ), BIG_INFO_STRING );
Com_DPrintf ("CL packet %s: %s\n", NET_AdrToString(from), c);
@@ -1792,7 +1703,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
Com_Printf( "Unwanted challenge response received. Ignored.\n" );
} else {
// start sending challenge repsonse instead of challenge request packets
- clc.challenge = atoi(Cmd_Argv(1));
+ clc.challenge = atoi(arg1);
cls.state = CA_CHALLENGING;
clc.connectPacketCount = 0;
clc.connectTime = -99999;
@@ -1848,19 +1759,13 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
// echo request from server
if ( !Q_stricmp(c, "echo") ) {
- NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) );
+ NET_OutOfBandPrint( NS_CLIENT, from, "%s", arg1 );
return;
}
- // cd check
- if ( !Q_stricmp(c, "keyAuthorize") ) {
- // we don't use these now, so dump them on the floor
- return;
- }
-
- // global MOTD from id
+ // global MOTD from trem master
if ( !Q_stricmp(c, "motd") ) {
- CL_MotdPacket( from );
+ CL_MotdPacket( from, arg1 );
return;
}
@@ -2003,11 +1908,7 @@ void CL_Frame ( int msec ) {
return;
}
- if ( cls.cddialog ) {
- // bring up the cd error dialog if needed
- cls.cddialog = qfalse;
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NEED_CD );
- } else if ( cls.state == CA_DISCONNECTED && !( cls.keyCatchers & KEYCATCH_UI )
+ if ( cls.state == CA_DISCONNECTED && !( cls.keyCatchers & KEYCATCH_UI )
&& !com_sv_running->integer ) {
// if disconnected, bring up the menu
S_StopAllSounds();
@@ -2474,7 +2375,6 @@ static void CL_SetServerInfo(serverInfo_t *server, const char *info, int ping) {
server->netType = atoi(Info_ValueForKey(info, "nettype"));
server->minPing = atoi(Info_ValueForKey(info, "minping"));
server->maxPing = atoi(Info_ValueForKey(info, "maxping"));
- server->punkbuster = atoi(Info_ValueForKey(info, "punkbuster"));
}
server->ping = ping;
}
@@ -2605,7 +2505,6 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
cls.localServers[i].game[0] = '\0';
cls.localServers[i].gameType = 0;
cls.localServers[i].netType = from.type;
- cls.localServers[i].punkbuster = 0;
Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING );
if (strlen(info)) {
@@ -3260,69 +3159,3 @@ CL_ShowIP_f
void CL_ShowIP_f(void) {
Sys_ShowIP();
}
-
-/*
-=================
-bool CL_CDKeyValidate
-=================
-*/
-qboolean CL_CDKeyValidate( const char *key, const char *checksum ) {
- char ch;
- byte sum;
- char chs[3];
- int i, len;
-
- len = strlen(key);
- if( len != CDKEY_LEN ) {
- return qfalse;
- }
-
- if( checksum && strlen( checksum ) != CDCHKSUM_LEN ) {
- return qfalse;
- }
-
- sum = 0;
- // for loop gets rid of conditional assignment warning
- for (i = 0; i < len; i++) {
- ch = *key++;
- if (ch>='a' && ch<='z') {
- ch -= 32;
- }
- switch( ch ) {
- case '2':
- case '3':
- case '7':
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'G':
- case 'H':
- case 'J':
- case 'L':
- case 'P':
- case 'R':
- case 'S':
- case 'T':
- case 'W':
- sum += ch;
- continue;
- default:
- return qfalse;
- }
- }
-
- sprintf(chs, "%02x", sum);
-
- if (checksum && !Q_stricmp(chs, checksum)) {
- return qtrue;
- }
-
- if (!checksum) {
- return qtrue;
- }
-
- return qfalse;
-}
-
-
diff --git a/src/client/cl_ui.c b/src/client/cl_ui.c
index 24186379..7351d77e 100644
--- a/src/client/cl_ui.c
+++ b/src/client/cl_ui.c
@@ -322,7 +322,6 @@ static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) {
Info_SetValueForKey( info, "gametype", va("%i",server->gameType));
Info_SetValueForKey( info, "nettype", va("%i",server->netType));
Info_SetValueForKey( info, "addr", NET_AdrToString(server->adr));
- Info_SetValueForKey( info, "punkbuster", va("%i", server->punkbuster));
Q_strncpyz(buf, info, buflen);
} else {
if (buf) {
@@ -673,44 +672,6 @@ void Key_SetCatcher( int catcher ) {
/*
====================
-CLUI_GetCDKey
-====================
-*/
-static void CLUI_GetCDKey( char *buf, int buflen ) {
- cvar_t *fs;
- fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
- if (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) {
- Com_Memcpy( buf, &cl_cdkey[16], 16);
- buf[16] = 0;
- } else {
- Com_Memcpy( buf, cl_cdkey, 16);
- buf[16] = 0;
- }
-}
-
-
-/*
-====================
-CLUI_SetCDKey
-====================
-*/
-static void CLUI_SetCDKey( char *buf ) {
- cvar_t *fs;
- fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
- if (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) {
- Com_Memcpy( &cl_cdkey[16], buf, 16 );
- cl_cdkey[32] = 0;
- // set the flag so the fle will be written at the next opportunity
- cvar_modifiedFlags |= CVAR_ARCHIVE;
- } else {
- Com_Memcpy( cl_cdkey, buf, 16 );
- // set the flag so the fle will be written at the next opportunity
- cvar_modifiedFlags |= CVAR_ARCHIVE;
- }
-}
-
-/*
-====================
GetConfigString
====================
*/
@@ -1005,14 +966,6 @@ long CL_UISystemCalls( long *args ) {
case UI_MEMORY_REMAINING:
return Hunk_MemoryRemaining();
- case UI_GET_CDKEY:
- CLUI_GetCDKey( VMA(1), args[2] );
- return 0;
-
- case UI_SET_CDKEY:
- CLUI_SetCDKey( VMA(1) );
- return 0;
-
case UI_SET_PBCLSTATUS:
return 0;
@@ -1093,11 +1046,6 @@ long CL_UISystemCalls( long *args ) {
re.RemapShader( VMA(1), VMA(2), VMA(3) );
return 0;
- case UI_VERIFY_CDKEY:
- return CL_CDKeyValidate(VMA(1), VMA(2));
-
-
-
default:
Com_Error( ERR_DROP, "Bad UI system trap: %i", args[0] );
@@ -1162,14 +1110,6 @@ void CL_InitUI( void ) {
}
}
-qboolean UI_usesUniqueCDKey( void ) {
- if (uivm) {
- return (VM_Call( uivm, UI_HASUNIQUECDKEY) == qtrue);
- } else {
- return qfalse;
- }
-}
-
/*
====================
UI_GameCommand
diff --git a/src/client/client.h b/src/client/client.h
index eff15d51..e597047f 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -239,7 +239,6 @@ typedef struct {
int maxPing;
int ping;
qboolean visible;
- int punkbuster;
} serverInfo_t;
typedef struct {
@@ -382,7 +381,6 @@ int CL_GetPingQueueCount( void );
void CL_ShutdownRef( void );
void CL_InitRef( void );
-qboolean CL_CDKeyValidate( const char *key, const char *checksum );
int CL_ServerStatus( char *serverAddress, char *serverStatusString, int maxLen );
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 2b713951..6bcb0d4e 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -28,7 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// because games can change separately from the main system version, we need a
// second version that must match between game and cgame
-#define GAME_VERSION "tremulous"
+#define GAME_VERSION "base"
#define DEFAULT_GRAVITY 800
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 0d38cf02..4431edaf 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -29,9 +29,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//==================================================================
-// the "gameversion" client command will print this plus compile date
-#define GAMEVERSION "tremulous"
-
#define INFINITE 1000000
#define FRAMETIME 100 // msec
diff --git a/src/game/g_main.c b/src/game/g_main.c
index 95cbda14..e77b5b76 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -112,7 +112,7 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_cheats, "sv_cheats", "", 0, 0, qfalse },
// noset vars
- { NULL, "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
+ { NULL, "gamename", GAME_VERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
{ NULL, "gamedate", __DATE__ , CVAR_ROM, 0, qfalse },
{ &g_restarted, "g_restarted", "0", CVAR_ROM, 0, qfalse },
{ NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
@@ -545,10 +545,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
G_RegisterCvars( );
- //TA: moved after G_RegisterCvars since G_Printf
- // now depends on the value of g_dedicated
G_Printf( "------- Game Initialization -------\n" );
- G_Printf( "gamename: %s\n", GAMEVERSION );
+ G_Printf( "gamename: %s\n", GAME_VERSION );
G_Printf( "gamedate: %s\n", __DATE__ );
G_ProcessIPBans( );
diff --git a/src/master/Makefile b/src/master/Makefile
new file mode 100644
index 00000000..308ebf05
--- /dev/null
+++ b/src/master/Makefile
@@ -0,0 +1,52 @@
+ARCH=$(shell uname -m | sed -e s/i.86/i386/)
+PLATFORM=$(shell uname|sed -e s/_.*//|tr A-Z a-z)
+BD_DEBUG=debug-$(ARCH)$(PLATFORM)
+BD_RELEASE=release-$(ARCH)$(PLATFORM)
+
+ifeq ($(PLATFORM),mingw32)
+ BINEXT=.exe
+ RELEASE_LDFLAGS=-lwsock32
+ DEBUG_LDFLAGS=-lwsock32
+ RM=del
+ MKDIR=md
+else
+ BINEXT=
+ RELEASE_LDFLAGS=
+ DEBUG_LDFLAGS=
+ RM=rm -f
+ MKDIR=mkdir
+endif
+
+CC=gcc
+RELEASE_CFLAGS=-Wall -O2
+DEBUG_CFLAGS=-g
+OBJECTS= \
+ $(BD)/master.o \
+ $(BD)/messages.o \
+ $(BD)/servers.o
+
+release: makedirs
+ $(MAKE) $(BD_RELEASE)/tremmaster BD=$(BD_RELEASE) \
+ CFLAGS="$(CFLAGS) $(RELEASE_CFLAGS)" LDFLAGS="$(LDFLAGS) $(RELEASE_LDFLAGS)"
+
+debug: makedirs
+ $(MAKE) $(BD_DEBUG)/tremmaster BD=$(BD_DEBUG) \
+ CFLAGS="$(CFLAGS) $(DEBUG_CFLAGS)" LDFLAGS="$(LDFLAGS) $(DEBUG_LDFLAGS)"
+
+all: release debug
+
+$(BD)/%.o: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+$(BD)/tremmaster: $(OBJECTS)
+ $(CC) -o $@ $(OBJECTS) $(LDFLAGS)
+
+clean:
+ -$(RM) $(BD_DEBUG)/*
+ -$(RM) $(BD_RELEASE)/*
+
+makedirs:
+ @if [ ! -d $(BD_RELEASE) ];then $(MKDIR) $(BD_RELEASE);fi
+ @if [ ! -d $(BD_DEBUG) ];then $(MKDIR) $(BD_DEBUG);fi
+
+.PHONY: all clean
diff --git a/src/master/common.h b/src/master/common.h
new file mode 100644
index 00000000..e38aa039
--- /dev/null
+++ b/src/master/common.h
@@ -0,0 +1,88 @@
+/*
+ common.h
+
+ Common header file for dpmaster
+
+ Copyright (C) 2004-2005 Mathieu Olivier
+
+ 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
+*/
+
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#ifdef WIN32
+# include <winsock2.h>
+#else
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# include <sys/socket.h>
+#endif
+
+
+// ---------- Types ---------- //
+
+// A few basic types
+typedef enum {qfalse, qtrue} qboolean;
+typedef unsigned char qbyte;
+
+// The various messages levels
+typedef enum
+{
+ MSG_NOPRINT, // used by "max_msg_level" (= no printings)
+ MSG_ERROR, // errors
+ MSG_WARNING, // warnings
+ MSG_NORMAL, // standard messages
+ MSG_DEBUG // for debugging purpose
+} msg_level_t;
+
+
+// ---------- Public variables ---------- //
+
+// The master socket
+extern int sock;
+
+// The current time (updated every time we receive a packet)
+extern time_t crt_time;
+
+// Maximum level for a message to be printed
+extern msg_level_t max_msg_level;
+
+// Peer address. We rebuild it every time we receive a new packet
+extern char peer_address [128];
+
+
+// ---------- Public functions ---------- //
+
+// Win32 uses a different name for some standard functions
+#ifdef WIN32
+# define snprintf _snprintf
+#endif
+
+// Print a message to screen, depending on its verbose level
+int MsgPrint (msg_level_t msg_level, const char* format, ...);
+
+
+#endif // #ifndef _COMMON_H_
diff --git a/src/master/master.c b/src/master/master.c
new file mode 100644
index 00000000..1158e59e
--- /dev/null
+++ b/src/master/master.c
@@ -0,0 +1,657 @@
+/*
+ master.c
+
+ A master server for Tremulous
+
+ Copyright (C) 2002-2005 Mathieu Olivier
+
+ 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
+*/
+
+
+#include <stdarg.h>
+#include <signal.h>
+#include <sys/poll.h>
+
+#ifndef WIN32
+# include <pwd.h>
+# include <unistd.h>
+#endif
+
+#include "common.h"
+#include "messages.h"
+#include "servers.h"
+
+
+// ---------- Constants ---------- //
+
+// Version of dpmaster
+#define VERSION "1.6"
+
+// Default master port
+#define DEFAULT_MASTER_PORT 27950
+
+// Maximum and minimum sizes for a valid packet
+#define MAX_PACKET_SIZE 2048
+#define MIN_PACKET_SIZE 5
+
+#ifndef WIN32
+// Default path we use for chroot
+# define DEFAULT_JAIL_PATH "/var/empty/"
+
+// User we use by default for dropping super-user privileges
+# define DEFAULT_LOW_PRIV_USER "nobody"
+#endif
+
+
+// ---------- Types ---------- //
+
+#ifdef WIN32
+typedef int socklen_t;
+#endif
+
+
+// ---------- Private variables ---------- //
+
+// The port we use
+static unsigned short master_port = DEFAULT_MASTER_PORT;
+
+// Local address we listen on, if any
+static const char* listen_name = NULL;
+static struct in_addr listen_addr;
+
+#ifndef WIN32
+// On UNIX systems, we can run as a daemon
+static qboolean daemon_mode = qfalse;
+
+// Path we use for chroot
+static const char* jail_path = DEFAULT_JAIL_PATH;
+
+// Low privileges user
+static const char* low_priv_user = DEFAULT_LOW_PRIV_USER;
+#endif
+
+
+// ---------- Public variables ---------- //
+
+// The master socket
+int sock = -1;
+
+// The current time (updated every time we receive a packet)
+time_t crt_time;
+
+// Maximum level for a message to be printed
+msg_level_t max_msg_level = MSG_NORMAL;
+
+// Peer address. We rebuild it every time we receive a new packet
+char peer_address [128];
+
+
+// ---------- Private functions ---------- //
+
+/*
+====================
+PrintPacket
+
+Print the contents of a packet on stdout
+====================
+*/
+static void PrintPacket (const char* packet, size_t length)
+{
+ size_t i;
+
+ // Exceptionally, we use MSG_NOPRINT here because if the function is
+ // called, the user probably wants this text to be displayed
+ // whatever the maximum message level is.
+ MsgPrint (MSG_NOPRINT, "\"");
+
+ for (i = 0; i < length; i++)
+ {
+ char c = packet[i];
+ if (c == '\\')
+ MsgPrint (MSG_NOPRINT, "\\\\");
+ else if (c == '\"')
+ MsgPrint (MSG_NOPRINT, "\"");
+ else if (c >= 32 && (qbyte)c <= 127)
+ MsgPrint (MSG_NOPRINT, "%c", c);
+ else
+ MsgPrint (MSG_NOPRINT, "\\x%02X", c);
+ }
+
+ MsgPrint (MSG_NOPRINT, "\" (%u bytes)\n", length);
+}
+
+
+/*
+====================
+SysInit
+
+System dependent initializations
+====================
+*/
+static qboolean SysInit (void)
+{
+#ifdef WIN32
+ WSADATA winsockdata;
+
+ if (WSAStartup (MAKEWORD (1, 1), &winsockdata))
+ {
+ MsgPrint (MSG_ERROR, "ERROR: can't initialize winsocks\n");
+ return qfalse;
+ }
+#endif
+
+ return qtrue;
+}
+
+
+/*
+====================
+UnsecureInit
+
+System independent initializations, called BEFORE the security initializations.
+We need this intermediate step because DNS requests may not be able to resolve
+after the security initializations, due to chroot.
+====================
+*/
+static qboolean UnsecureInit (void)
+{
+ // Resolve the address mapping list
+ if (! Sv_ResolveAddressMappings ())
+ return qfalse;
+
+ // Resolve the listen address if one was specified
+ if (listen_name != NULL)
+ {
+ struct hostent* itf;
+
+ itf = gethostbyname (listen_name);
+ if (itf == NULL)
+ {
+ MsgPrint (MSG_ERROR, "ERROR: can't resolve %s\n", listen_name);
+ return qfalse;
+ }
+ if (itf->h_addrtype != AF_INET)
+ {
+ MsgPrint (MSG_ERROR, "ERROR: %s is not an IPv4 address\n",
+ listen_name);
+ return qfalse;
+ }
+
+ memcpy (&listen_addr.s_addr, itf->h_addr,
+ sizeof (listen_addr.s_addr));
+ }
+
+ return qtrue;
+}
+
+
+/*
+====================
+SecInit
+
+Security initializations (system dependent)
+====================
+*/
+static qboolean SecInit (void)
+{
+#ifndef WIN32
+ // Should we run as a daemon?
+ if (daemon_mode && daemon (0, 0))
+ {
+ MsgPrint (MSG_NOPRINT, "ERROR: daemonization failed (%s)\n",
+ strerror (errno));
+ return qfalse;
+ }
+
+ // UNIX allows us to be completely paranoid, so let's go for it
+ if (geteuid () == 0)
+ {
+ struct passwd* pw;
+
+ MsgPrint (MSG_WARNING,
+ "WARNING: running with super-user privileges\n");
+
+ // We must get the account infos before the calls to chroot and chdir
+ pw = getpwnam (low_priv_user);
+ if (pw == NULL)
+ {
+ MsgPrint (MSG_ERROR, "ERROR: can't get user \"%s\" properties\n",
+ low_priv_user);
+ return qfalse;
+ }
+
+ // Chroot ourself
+ MsgPrint (MSG_NORMAL, " - chrooting myself to %s... ", jail_path);
+ if (chroot (jail_path) || chdir ("/"))
+ {
+ MsgPrint (MSG_ERROR, "FAILED (%s)\n", strerror (errno));
+ return qfalse;
+ }
+ MsgPrint (MSG_NORMAL, "succeeded\n");
+
+ // Switch to lower privileges
+ MsgPrint (MSG_NORMAL, " - switching to user \"%s\" privileges... ",
+ low_priv_user);
+ if (setgid (pw->pw_gid) || setuid (pw->pw_uid))
+ {
+ MsgPrint (MSG_ERROR, "FAILED (%s)\n", strerror (errno));
+ return qfalse;
+ }
+ MsgPrint (MSG_NORMAL, "succeeded (UID: %u, GID: %u)\n",
+ pw->pw_uid, pw->pw_gid);
+
+ MsgPrint (MSG_NORMAL, "\n");
+ }
+#endif
+
+ return qtrue;
+}
+
+
+/*
+====================
+ParseCommandLine
+
+Parse the options passed by the command line
+====================
+*/
+static qboolean ParseCommandLine (int argc, const char* argv [])
+{
+ int ind = 1;
+ unsigned int vlevel = max_msg_level;
+ qboolean valid_options = qtrue;
+
+ while (ind < argc && valid_options)
+ {
+ // If it doesn't even look like an option, why bother?
+ if (argv[ind][0] != '-')
+ valid_options = qfalse;
+
+ else switch (argv[ind][1])
+ {
+#ifndef WIN32
+ // Daemon mode
+ case 'D':
+ daemon_mode = qtrue;
+ break;
+#endif
+
+ // Help
+ case 'h':
+ valid_options = qfalse;
+ break;
+
+ // Hash size
+ case 'H':
+ ind++;
+ if (ind < argc)
+ valid_options = Sv_SetHashSize (atoi (argv[ind]));
+ else
+ valid_options = qfalse;
+ break;
+
+#ifndef WIN32
+ // Jail path
+ case 'j':
+ ind++;
+ if (ind < argc)
+ jail_path = argv[ind];
+ else
+ valid_options = qfalse;
+ break;
+#endif
+
+ // Listen address
+ case 'l':
+ ind++;
+ if (ind >= argc || argv[ind][0] == '\0')
+ valid_options = qfalse;
+ else
+ listen_name = argv[ind];
+ break;
+
+ // Address mapping
+ case 'm':
+ ind++;
+ if (ind < argc)
+ valid_options = Sv_AddAddressMapping (argv[ind]);
+ else
+ valid_options = qfalse;
+ break;
+
+ // Maximum number of servers
+ case 'n':
+ ind++;
+ if (ind < argc)
+ valid_options = Sv_SetMaxNbServers (atoi (argv[ind]));
+ else
+ valid_options = qfalse;
+ break;
+
+ // Port number
+ case 'p':
+ {
+ unsigned short port_num = 0;
+ ind++;
+ if (ind < argc)
+ port_num = atoi (argv[ind]);
+ if (!port_num)
+ valid_options = qfalse;
+ else
+ master_port = port_num;
+ break;
+ }
+
+#ifndef WIN32
+ // Low privileges user
+ case 'u':
+ ind++;
+ if (ind < argc)
+ low_priv_user = argv[ind];
+ else
+ valid_options = qfalse;
+ break;
+#endif
+
+ // Verbose level
+ case 'v':
+ // If a verbose level has been specified
+ if (ind + 1 < argc && argv[ind + 1][0] != '-')
+ {
+ ind++;
+ vlevel = atoi (argv[ind]);
+ if (vlevel > MSG_DEBUG)
+ valid_options = qfalse;
+ }
+ else
+ vlevel = MSG_DEBUG;
+ break;
+
+ default:
+ valid_options = qfalse;
+ }
+
+ ind++;
+ }
+
+ // If the command line is OK, we can set the verbose level now
+ if (valid_options)
+ {
+#ifndef WIN32
+ // If we run as a daemon, don't bother printing anything
+ if (daemon_mode)
+ max_msg_level = MSG_NOPRINT;
+ else
+#endif
+ max_msg_level = vlevel;
+ }
+
+ return valid_options;
+}
+
+
+/*
+====================
+PrintHelp
+
+Print the command line syntax and the available options
+====================
+*/
+static void PrintHelp (void)
+{
+ MsgPrint (MSG_ERROR,
+ "Syntax: dpmaster [options]\n"
+ "Available options are:\n"
+#ifndef WIN32
+ " -D : run as a daemon\n"
+#endif
+ " -h : this help\n"
+ " -H <hash_size> : hash size in bits, up to %u (default: %u)\n"
+#ifndef WIN32
+ " -j <jail_path> : use <jail_path> as chroot path (default: %s)\n"
+ " only available when running with super-user privileges\n"
+#endif
+ " -l <address> : listen on local address <address>\n"
+ " -m <a1>=<a2> : map address <a1> to <a2> when sending it to clients\n"
+ " addresses can contain a port number (ex: myaddr.net:1234)\n"
+ " -n <max_servers> : maximum number of servers recorded (default: %u)\n"
+ " -p <port_num> : use port <port_num> (default: %u)\n"
+#ifndef WIN32
+ " -u <user> : use <user> privileges (default: %s)\n"
+ " only available when running with super-user privileges\n"
+#endif
+ " -v [verbose_lvl] : verbose level, up to %u (default: %u; no value means max)\n"
+ "\n",
+ MAX_HASH_SIZE, DEFAULT_HASH_SIZE,
+#ifndef WIN32
+ DEFAULT_JAIL_PATH,
+#endif
+ DEFAULT_MAX_NB_SERVERS,
+ DEFAULT_MASTER_PORT,
+#ifndef WIN32
+ DEFAULT_LOW_PRIV_USER,
+#endif
+ MSG_DEBUG, MSG_NORMAL);
+}
+
+
+/*
+====================
+SecureInit
+
+System independent initializations, called AFTER the security initializations
+====================
+*/
+static qboolean SecureInit (void)
+{
+ struct sockaddr_in address;
+
+ // Init the time and the random seed
+ crt_time = time (NULL);
+ srand (crt_time);
+
+ // Initialize the server list and hash table
+ if (!Sv_Init ())
+ return qfalse;
+
+ // Open the socket
+ sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0)
+ {
+ MsgPrint (MSG_ERROR, "ERROR: socket creation failed (%s)\n",
+ strerror (errno));
+ return qfalse;
+ }
+
+ // Bind it to the master port
+ memset (&address, 0, sizeof (address));
+ address.sin_family = AF_INET;
+ if (listen_name != NULL)
+ {
+ MsgPrint (MSG_NORMAL, "Listening on address %s (%s)\n",
+ listen_name, inet_ntoa (listen_addr));
+ address.sin_addr.s_addr = listen_addr.s_addr;
+ }
+ else
+ address.sin_addr.s_addr = htonl (INADDR_ANY);
+ address.sin_port = htons (master_port);
+ if (bind (sock, (struct sockaddr*)&address, sizeof (address)) != 0)
+ {
+ MsgPrint (MSG_ERROR, "ERROR: socket binding failed (%s)\n",
+ strerror (errno));
+#ifdef WIN32
+ closesocket (sock);
+#else
+ close (sock);
+#endif
+ return qfalse;
+ }
+ MsgPrint (MSG_NORMAL, "Listening on UDP port %hu\n",
+ ntohs (address.sin_port));
+
+ return qtrue;
+}
+
+static qboolean exitNow = qfalse;
+
+/*
+===============
+cleanUp
+
+Clean up
+===============
+*/
+static void cleanUp( int signal )
+{
+ MsgPrint( MSG_NORMAL, "Caught signal %d, exiting...\n", signal );
+
+ exitNow = qtrue;
+}
+
+/*
+====================
+main
+
+Main function
+====================
+*/
+int main (int argc, const char* argv [])
+{
+ struct sockaddr_in address;
+ socklen_t addrlen;
+ int nb_bytes;
+ char packet [MAX_PACKET_SIZE + 1]; // "+ 1" because we append a '\0'
+ qboolean valid_options;
+ struct pollfd socket_poll;
+
+ signal( SIGINT, cleanUp );
+ signal( SIGTERM, cleanUp );
+
+ // Get the options from the command line
+ valid_options = ParseCommandLine (argc, argv);
+
+ MsgPrint (MSG_NORMAL,
+ "tremmaster (version " VERSION " " __DATE__ " " __TIME__ ")\n" );
+
+ // If there was a mistake in the command line, print the help and exit
+ if (!valid_options)
+ {
+ PrintHelp ();
+ return EXIT_FAILURE;
+ }
+
+ // Initializations
+ if (!SysInit () || !UnsecureInit () || !SecInit () || !SecureInit ())
+ return EXIT_FAILURE;
+ MsgPrint (MSG_NORMAL, "\n");
+
+ memset( &socket_poll, 0, sizeof( struct pollfd ) );
+ socket_poll.fd = sock;
+ socket_poll.events = POLLIN;
+
+ // Until the end of times...
+ while( !exitNow )
+ {
+ // Check for new data every 100ms
+ if( poll( &socket_poll, 1, 100 ) <= 0 )
+ continue;
+
+ // Get the next valid message
+ addrlen = sizeof (address);
+ nb_bytes = recvfrom (sock, packet, sizeof (packet) - 1, 0,
+ (struct sockaddr*)&address, &addrlen);
+ if (nb_bytes <= 0)
+ {
+ MsgPrint (MSG_WARNING,
+ "WARNING: \"recvfrom\" returned %d\n", nb_bytes);
+ continue;
+ }
+
+ // If we may have to print something, rebuild the peer address buffer
+ if (max_msg_level != MSG_NOPRINT)
+ snprintf (peer_address, sizeof (peer_address), "%s:%hu",
+ inet_ntoa (address.sin_addr), ntohs (address.sin_port));
+
+ // We print the packet contents if necessary
+ // TODO: print the current time here
+ if (max_msg_level >= MSG_DEBUG)
+ {
+ MsgPrint (MSG_DEBUG, "New packet received from %s: ",
+ peer_address);
+ PrintPacket (packet, nb_bytes);
+ }
+
+ // A few sanity checks
+ if (nb_bytes < MIN_PACKET_SIZE)
+ {
+ MsgPrint (MSG_WARNING,
+ "WARNING: rejected packet from %s (size = %d bytes)\n",
+ peer_address, nb_bytes);
+ continue;
+ }
+ if (*((unsigned int*)packet) != 0xFFFFFFFF)
+ {
+ MsgPrint (MSG_WARNING,
+ "WARNING: rejected packet from %s (invalid header)\n",
+ peer_address);
+ continue;
+ }
+ if (! ntohs (address.sin_port))
+ {
+ MsgPrint (MSG_WARNING,
+ "WARNING: rejected packet from %s (source port = 0)\n",
+ peer_address);
+ continue;
+ }
+
+ // Append a '\0' to make the parsing easier and update the current time
+ packet[nb_bytes] = '\0';
+ crt_time = time (NULL);
+
+ // Call HandleMessage with the remaining contents
+ HandleMessage (packet + 4, nb_bytes - 4, &address);
+ }
+
+ return 0;
+}
+
+
+// ---------- Public functions ---------- //
+
+/*
+====================
+MsgPrint
+
+Print a message to screen, depending on its verbose level
+====================
+*/
+int MsgPrint (msg_level_t msg_level, const char* format, ...)
+{
+ va_list args;
+ int result;
+
+ // If the message level is above the maximum level, don't print it
+ if (msg_level > max_msg_level)
+ return 0;
+
+ va_start (args, format);
+ result = vprintf (format, args);
+ va_end (args);
+
+ fflush (stdout);
+
+ return result;
+}
diff --git a/src/master/messages.c b/src/master/messages.c
new file mode 100644
index 00000000..665b9382
--- /dev/null
+++ b/src/master/messages.c
@@ -0,0 +1,526 @@
+/*
+ messages.c
+
+ Message management for tremmaster
+
+ Copyright (C) 2004 Mathieu Olivier
+
+ 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
+*/
+
+
+#include "common.h"
+#include "messages.h"
+#include "servers.h"
+
+
+// ---------- Constants ---------- //
+
+// Timeouts (in secondes)
+#define TIMEOUT_HEARTBEAT 2
+#define TIMEOUT_INFORESPONSE (15 * 60)
+
+// Period of validity for a challenge string (in secondes)
+#define TIMEOUT_CHALLENGE 2
+
+// Maximum size of a reponse packet
+#define MAX_PACKET_SIZE 1400
+
+
+// Types of messages (with samples):
+
+// "heartbeat Tremulous\n"
+#define S2M_HEARTBEAT "heartbeat"
+
+// "getinfo A_Challenge"
+#define M2S_GETINFO "getinfo"
+
+// "infoResponse\n\\pure\\1\\..."
+#define S2M_INFORESPONSE "infoResponse\x0A"
+
+// "getservers 67 empty full"
+#define C2M_GETSERVERS "getservers "
+
+// "getserversResponse\\...(6 bytes)...\\...(6 bytes)...\\EOT\0\0\0"
+#define M2C_GETSERVERSREPONSE "getserversResponse"
+
+#define C2M_GETMOTD "getmotd"
+#define M2C_MOTD "motd "
+
+
+// ---------- Private functions ---------- //
+
+/*
+====================
+SearchInfostring
+
+Search an infostring for the value of a key
+====================
+*/
+static char* SearchInfostring (const char* infostring, const char* key)
+{
+ static char value [256];
+ char crt_key [256];
+ size_t value_ind, key_ind;
+ char c;
+
+ if (*infostring++ != '\\')
+ return NULL;
+
+ value_ind = 0;
+ for (;;)
+ {
+ key_ind = 0;
+
+ // Get the key name
+ for (;;)
+ {
+ c = *infostring++;
+
+ if (c == '\0')
+ return NULL;
+ if (c == '\\' || key_ind == sizeof (crt_key) - 1)
+ {
+ crt_key[key_ind] = '\0';
+ break;
+ }
+
+ crt_key[key_ind++] = c;
+ }
+
+ // If it's the key we are looking for, save it in "value"
+ if (!strcmp (crt_key, key))
+ {
+ for (;;)
+ {
+ c = *infostring++;
+
+ if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
+ {
+ value[value_ind] = '\0';
+ return value;
+ }
+
+ value[value_ind++] = c;
+ }
+ }
+
+ // Else, skip the value
+ for (;;)
+ {
+ c = *infostring++;
+
+ if (c == '\0')
+ return NULL;
+ if (c == '\\')
+ break;
+ }
+ }
+}
+
+
+/*
+====================
+BuildChallenge
+
+Build a challenge string for a "getinfo" message
+====================
+*/
+static const char* BuildChallenge (void)
+{
+ static char challenge [CHALLENGE_MAX_LENGTH];
+ size_t ind;
+ size_t length = CHALLENGE_MIN_LENGTH - 1; // We start at the minimum size
+
+ // ... then we add a random number of characters
+ length += rand () % (CHALLENGE_MAX_LENGTH - CHALLENGE_MIN_LENGTH + 1);
+
+ for (ind = 0; ind < length; ind++)
+ {
+ char c;
+ do
+ {
+ c = 33 + rand () % (126 - 33 + 1); // -> c = 33..126
+ } while (c == '\\' || c == ';' || c == '"' || c == '%' || c == '/');
+
+ challenge[ind] = c;
+ }
+
+ challenge[length] = '\0';
+ return challenge;
+}
+
+
+/*
+====================
+SendGetInfo
+
+Send a "getinfo" message to a server
+====================
+*/
+static void SendGetInfo (server_t* server)
+{
+ char msg [64] = "\xFF\xFF\xFF\xFF" M2S_GETINFO " ";
+
+ if (!server->challenge_timeout || server->challenge_timeout < crt_time)
+ {
+ strncpy (server->challenge, BuildChallenge (),
+ sizeof (server->challenge) - 1);
+ server->challenge_timeout = crt_time + TIMEOUT_CHALLENGE;
+ }
+
+ strncat (msg, server->challenge, sizeof (msg) - strlen (msg) - 1);
+ sendto (sock, msg, strlen (msg), 0,
+ (const struct sockaddr*)&server->address,
+ sizeof (server->address));
+
+ MsgPrint (MSG_DEBUG, "%s <--- getinfo with challenge \"%s\"\n",
+ peer_address, server->challenge);
+}
+
+
+/*
+====================
+HandleGetServers
+
+Parse getservers requests and send the appropriate response
+====================
+*/
+static void HandleGetServers (const char* msg, const struct sockaddr_in* addr)
+{
+ const char* packetheader = "\xFF\xFF\xFF\xFF" M2C_GETSERVERSREPONSE "\\";
+ const size_t headersize = strlen (packetheader);
+ char packet [MAX_PACKET_SIZE];
+ size_t packetind;
+ server_t* sv;
+ unsigned int protocol;
+ unsigned int sv_addr;
+ unsigned short sv_port;
+ qboolean no_empty;
+ qboolean no_full;
+ unsigned int numServers = 0;
+
+ // Check if there's a name before the protocol number
+ // In this case, the message comes from a DarkPlaces-compatible client
+ protocol = atoi (msg);
+
+ MsgPrint (MSG_NORMAL, "%s ---> getservers( protocol version %d )\n",
+ peer_address, protocol );
+
+ no_empty = (strstr (msg, "empty") == NULL);
+ no_full = (strstr (msg, "full") == NULL);
+
+ // Initialize the packet contents with the header
+ packetind = headersize;
+ memcpy(packet, packetheader, headersize);
+
+ // Add every relevant server
+ for (sv = Sv_GetFirst (); /* see below */; sv = Sv_GetNext ())
+ {
+ // If we're done, or if the packet is full, send the packet
+ if (sv == NULL || packetind > sizeof (packet) - (7 + 6))
+ {
+ // End Of Transmission
+ packet[packetind ] = 'E';
+ packet[packetind + 1] = 'O';
+ packet[packetind + 2] = 'T';
+ packet[packetind + 3] = '\0';
+ packet[packetind + 4] = '\0';
+ packet[packetind + 5] = '\0';
+ packetind += 6;
+
+ // Send the packet to the client
+ sendto (sock, packet, packetind, 0, (const struct sockaddr*)addr,
+ sizeof (*addr));
+
+ MsgPrint (MSG_DEBUG, "%s <--- getserversResponse (%u servers)\n",
+ peer_address, numServers);
+
+ // If we're done
+ if (sv == NULL)
+ return;
+
+ // Reset the packet index (no need to change the header)
+ packetind = headersize;
+ }
+
+ sv_addr = ntohl (sv->address.sin_addr.s_addr);
+ sv_port = ntohs (sv->address.sin_port);
+
+ // Extra debugging info
+ if (max_msg_level >= MSG_DEBUG)
+ {
+ MsgPrint (MSG_DEBUG,
+ "Comparing server: IP:\"%u.%u.%u.%u:%hu\", p:%u, c:%hu\n",
+ sv_addr >> 24, (sv_addr >> 16) & 0xFF,
+ (sv_addr >> 8) & 0xFF, sv_addr & 0xFF,
+ sv_port, sv->protocol, sv->nbclients );
+
+ if (sv->protocol != protocol)
+ MsgPrint (MSG_DEBUG,
+ "Reject: protocol %u != requested %u\n",
+ sv->protocol, protocol);
+ if (sv->nbclients == 0 && no_empty)
+ MsgPrint (MSG_DEBUG,
+ "Reject: nbclients is %hu/%hu && no_empty\n",
+ sv->nbclients, sv->maxclients);
+ if (sv->nbclients == sv->maxclients && no_full)
+ MsgPrint (MSG_DEBUG,
+ "Reject: nbclients is %hu/%hu && no_full\n",
+ sv->nbclients, sv->maxclients);
+ }
+
+ // Check protocol, options
+ if (sv->protocol != protocol ||
+ (sv->nbclients == 0 && no_empty) ||
+ (sv->nbclients == sv->maxclients && no_full))
+ {
+
+ // Skip it
+ continue;
+ }
+
+ // Use the address mapping associated with the server, if any
+ if (sv->addrmap != NULL)
+ {
+ const addrmap_t* addrmap = sv->addrmap;
+
+ sv_addr = ntohl (addrmap->to.sin_addr.s_addr);
+ if (addrmap->to.sin_port != 0)
+ sv_port = ntohs (addrmap->to.sin_port);
+
+ MsgPrint (MSG_DEBUG,
+ "Server address mapped to %u.%u.%u.%u:%hu\n",
+ sv_addr >> 24, (sv_addr >> 16) & 0xFF,
+ (sv_addr >> 8) & 0xFF, sv_addr & 0xFF,
+ sv_port);
+ }
+
+ // IP address
+ packet[packetind ] = sv_addr >> 24;
+ packet[packetind + 1] = (sv_addr >> 16) & 0xFF;
+ packet[packetind + 2] = (sv_addr >> 8) & 0xFF;
+ packet[packetind + 3] = sv_addr & 0xFF;
+
+ // Port
+ packet[packetind + 4] = sv_port >> 8;
+ packet[packetind + 5] = sv_port & 0xFF;
+
+ // Trailing '\'
+ packet[packetind + 6] = '\\';
+
+ MsgPrint (MSG_DEBUG, " - Sending server %u.%u.%u.%u:%hu\n",
+ (qbyte)packet[packetind ], (qbyte)packet[packetind + 1],
+ (qbyte)packet[packetind + 2], (qbyte)packet[packetind + 3],
+ sv_port);
+
+ packetind += 7;
+ numServers++;
+ }
+}
+
+
+/*
+====================
+HandleInfoResponse
+
+Parse infoResponse messages
+====================
+*/
+static void HandleInfoResponse (server_t* server, const char* msg)
+{
+ char* value;
+ unsigned int new_protocol = 0, new_maxclients = 0;
+
+ MsgPrint (MSG_DEBUG, "%s ---> infoResponse\n", peer_address);
+
+ // Check the challenge
+ if (!server->challenge_timeout || server->challenge_timeout < crt_time)
+ {
+ MsgPrint (MSG_WARNING,
+ "WARNING: infoResponse with obsolete challenge from %s\n",
+ peer_address);
+ return;
+ }
+ value = SearchInfostring (msg, "challenge");
+ if (!value || strcmp (value, server->challenge))
+ {
+ MsgPrint (MSG_ERROR, "ERROR: invalid challenge from %s (%s)\n",
+ peer_address, value);
+ return;
+ }
+
+ // Check and save the values of "protocol" and "maxclients"
+ value = SearchInfostring (msg, "protocol");
+ if (value)
+ new_protocol = atoi (value);
+ value = SearchInfostring (msg, "sv_maxclients");
+ if (value)
+ new_maxclients = atoi (value);
+ if (!new_protocol || !new_maxclients)
+ {
+ MsgPrint (MSG_ERROR,
+ "ERROR: invalid infoResponse from %s (protocol: %d, maxclients: %d)\n",
+ peer_address, new_protocol, new_maxclients);
+ return;
+ }
+ server->protocol = new_protocol;
+ server->maxclients = new_maxclients;
+
+ // Save some other useful values
+ value = SearchInfostring (msg, "clients");
+ if (value)
+ server->nbclients = atoi (value);
+
+ // Set a new timeout
+ server->timeout = crt_time + TIMEOUT_INFORESPONSE;
+}
+
+
+#define CHALLENGE_KEY "challenge\\"
+#define MOTD_KEY "motd\\"
+
+/*
+====================
+HandleGetMotd
+
+Parse getservers requests and send the appropriate response
+====================
+*/
+static void HandleGetMotd( const char* msg, const struct sockaddr_in* addr )
+{
+ const char *packetheader = "\xFF\xFF\xFF\xFF" M2C_MOTD "\"";
+ const size_t headersize = strlen (packetheader);
+ char packet[ MAX_PACKET_SIZE ];
+ char challenge[ MAX_PACKET_SIZE ];
+ const char *motd = ""; //FIXME
+ size_t packetind;
+ char *value;
+
+ MsgPrint( MSG_DEBUG, "%s ---> getmotd\n", peer_address );
+
+ value = SearchInfostring( msg, "challenge" );
+ if( !value )
+ {
+ MsgPrint( MSG_ERROR, "ERROR: invalid challenge from %s (%s)\n",
+ peer_address, value );
+ return;
+ }
+
+ strncpy( challenge, value, MAX_PACKET_SIZE );
+
+ value = SearchInfostring( msg, "renderer" );
+ if( value )
+ {
+ //FIXME: create renderer stats
+ MsgPrint( MSG_DEBUG, "%s is using renderer %s\n", peer_address, value );
+ }
+
+ value = SearchInfostring( msg, "version" );
+ if( value )
+ {
+ //FIXME: create version stats
+ MsgPrint( MSG_DEBUG, "%s is using version %s\n", peer_address, value );
+ }
+
+ // Initialize the packet contents with the header
+ packetind = headersize;
+ memcpy( packet, packetheader, headersize );
+
+ strncpy( &packet[ packetind ], CHALLENGE_KEY, MAX_PACKET_SIZE - packetind );
+ packetind += strlen( CHALLENGE_KEY );
+
+ strncpy( &packet[ packetind ], challenge, MAX_PACKET_SIZE - packetind );
+ packetind += strlen( challenge );
+ packet[ packetind++ ] = '\\';
+
+ strncpy( &packet[ packetind ], MOTD_KEY, MAX_PACKET_SIZE - packetind );
+ packetind += strlen( MOTD_KEY );
+
+ strncpy( &packet[ packetind ], motd, MAX_PACKET_SIZE - packetind );
+ packetind += strlen( motd );
+ packet[ packetind++ ] = '\"';
+ packet[ packetind++ ] = '\0';
+
+ MsgPrint( MSG_DEBUG, "%s <--- motd\n", peer_address );
+
+ // Send the packet to the client
+ sendto( sock, packet, packetind, 0, (const struct sockaddr*)addr,
+ sizeof( *addr ) );
+}
+
+// ---------- Public functions ---------- //
+
+/*
+====================
+HandleMessage
+
+Parse a packet to figure out what to do with it
+====================
+*/
+void HandleMessage (const char* msg, size_t length,
+ const struct sockaddr_in* address)
+{
+ server_t* server;
+
+ // If it's an heartbeat
+ if (!strncmp (S2M_HEARTBEAT, msg, strlen (S2M_HEARTBEAT)))
+ {
+ char gameId [64];
+
+ // Extract the game id
+ sscanf (msg + strlen (S2M_HEARTBEAT) + 1, "%63s", gameId);
+ MsgPrint (MSG_DEBUG, "%s ---> heartbeat (%s)\n",
+ peer_address, gameId);
+
+ // Get the server in the list (add it to the list if necessary)
+ server = Sv_GetByAddr (address, qtrue);
+ if (server == NULL)
+ return;
+
+ server->active = qtrue;
+
+ // If we haven't yet received any infoResponse from this server,
+ // we let it some more time to contact us. After that, only
+ // infoResponse messages can update the timeout value.
+ if (!server->maxclients)
+ server->timeout = crt_time + TIMEOUT_HEARTBEAT;
+
+ // Ask for some infos
+ SendGetInfo (server);
+ }
+
+ // If it's an infoResponse message
+ else if (!strncmp (S2M_INFORESPONSE, msg, strlen (S2M_INFORESPONSE)))
+ {
+ server = Sv_GetByAddr (address, qfalse);
+ if (server == NULL)
+ return;
+
+ HandleInfoResponse (server, msg + strlen (S2M_INFORESPONSE));
+ }
+
+ // If it's a getservers request
+ else if (!strncmp (C2M_GETSERVERS, msg, strlen (C2M_GETSERVERS)))
+ {
+ HandleGetServers (msg + strlen (C2M_GETSERVERS), address);
+ }
+
+ // If it's a getmotd request
+ else if (!strncmp (C2M_GETMOTD, msg, strlen (C2M_GETMOTD)))
+ {
+ HandleGetMotd (msg + strlen (C2M_GETMOTD), address);
+ }
+}
diff --git a/src/master/messages.h b/src/master/messages.h
new file mode 100644
index 00000000..93b52716
--- /dev/null
+++ b/src/master/messages.h
@@ -0,0 +1,35 @@
+/*
+ messages.h
+
+ Message management for dpmaster
+
+ Copyright (C) 2004 Mathieu Olivier
+
+ 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
+*/
+
+
+#ifndef _MESSAGES_H_
+#define _MESSAGES_H_
+
+
+// ---------- Public functions ---------- //
+
+// Parse a packet to figure out what to do with it
+void HandleMessage (const char* msg, size_t length,
+ const struct sockaddr_in* address);
+
+
+#endif // #ifndef _MESSAGES_H_
diff --git a/src/master/servers.c b/src/master/servers.c
new file mode 100644
index 00000000..a8412a1d
--- /dev/null
+++ b/src/master/servers.c
@@ -0,0 +1,666 @@
+/*
+ servers.c
+
+ Server list and address mapping management for dpmaster
+
+ Copyright (C) 2004 Mathieu Olivier
+
+ 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
+*/
+
+
+#include "common.h"
+#include "servers.h"
+
+
+// ---------- Constants ---------- //
+
+// Address hash bitmask
+#define HASH_BITMASK (hash_table_size - 1)
+
+
+// ---------- Variables ---------- //
+
+// All server structures are allocated in one block in the "servers" array.
+// Each used slot is also part of a linked list in "hash_table". A simple
+// hash of the address and port of a server gives its index in the table.
+static server_t* servers = NULL;
+static size_t max_nb_servers = DEFAULT_MAX_NB_SERVERS;
+static size_t nb_servers = 0;
+static server_t** hash_table = NULL;
+static size_t hash_table_size = (1 << DEFAULT_HASH_SIZE);
+
+// Last allocated entry in the "servers" array.
+// Used as a start index for finding a free slot in "servers" more quickly
+static unsigned int last_alloc;
+
+// Variables for Sv_GetFirst, Sv_GetNext and Sv_RemoveCurrentAndGetNext
+static server_t* crt_server = NULL;
+static server_t** prev_pointer = NULL;
+static int crt_hash_ind = -1;
+
+// List of address mappings. They are sorted by "from" field (IP, then port)
+static addrmap_t* addrmaps = NULL;
+
+
+// ---------- Private functions ---------- //
+
+/*
+====================
+Sv_AddressHash
+
+Compute the hash of a server address
+====================
+*/
+static unsigned int Sv_AddressHash (const struct sockaddr_in* address)
+{
+ qbyte* addr = (qbyte*)&address->sin_addr.s_addr;
+ qbyte* port = (qbyte*)&address->sin_port;
+ qbyte hash;
+
+ hash = addr[0] ^ addr[1] ^ addr[2] ^ addr[3] ^ port[0] ^ port[1];
+ return hash & HASH_BITMASK;
+}
+
+
+/*
+====================
+Sv_RemoveAndGetNextPtr
+
+Remove a server from the list and returns its "next" pointer
+====================
+*/
+static server_t* Sv_RemoveAndGetNextPtr (server_t* sv, server_t** prev)
+{
+ nb_servers--;
+ MsgPrint (MSG_NORMAL,
+ "%s:%hu timed out; %u servers currently registered\n",
+ inet_ntoa (sv->address.sin_addr), ntohs (sv->address.sin_port),
+ nb_servers);
+
+ // Mark this structure as "free"
+ sv->active = qfalse;
+
+ *prev = sv->next;
+ return sv->next;
+}
+
+
+/*
+====================
+Sv_ResolveAddr
+
+Resolve an internet address
+name may include a port number, after a ':'
+====================
+*/
+static qboolean Sv_ResolveAddr (const char* name, struct sockaddr_in* addr)
+{
+ char *namecpy, *port;
+ struct hostent* host;
+
+ // Create a work copy
+ namecpy = strdup (name);
+ if (namecpy == NULL)
+ {
+ MsgPrint (MSG_ERROR,
+ "ERROR: can't allocate enough memory to resolve %s\n",
+ name);
+ return qfalse;
+ }
+
+ // Find the port in the address
+ port = strchr (namecpy, ':');
+ if (port != NULL)
+ *port++ = '\0';
+
+ // Resolve the address
+ host = gethostbyname (namecpy);
+ if (host == NULL)
+ {
+ MsgPrint (MSG_ERROR, "ERROR: can't resolve %s\n", namecpy);
+ free (namecpy);
+ return qfalse;
+ }
+ if (host->h_addrtype != AF_INET)
+ {
+ MsgPrint (MSG_ERROR, "ERROR: %s is not an IPv4 address\n",
+ namecpy);
+ free (namecpy);
+ return qfalse;
+ }
+
+ // Build the structure
+ memset (addr, 0, sizeof (*addr));
+ addr->sin_family = AF_INET;
+ memcpy (&addr->sin_addr.s_addr, host->h_addr,
+ sizeof (addr->sin_addr.s_addr));
+ if (port != NULL)
+ addr->sin_port = htons ((unsigned short)atoi (port));
+
+ MsgPrint (MSG_DEBUG, "\"%s\" resolved to %s:%hu\n",
+ name, inet_ntoa (addr->sin_addr), ntohs (addr->sin_port));
+
+ free (namecpy);
+ return qtrue;
+}
+
+
+/*
+====================
+Sv_InsertAddrmapIntoList
+
+Insert an addrmap structure to the addrmaps list
+====================
+*/
+static void Sv_InsertAddrmapIntoList (addrmap_t* new_map)
+{
+ addrmap_t* addrmap = addrmaps;
+ addrmap_t** prev = &addrmaps;
+
+ // Stop at the end of the list, or if the addresses become too high
+ while (addrmap != NULL &&
+ addrmap->from.sin_addr.s_addr <= new_map->from.sin_addr.s_addr)
+ {
+ // If we found the right place
+ if (addrmap->from.sin_addr.s_addr == new_map->from.sin_addr.s_addr &&
+ addrmap->from.sin_port >= new_map->from.sin_port)
+ {
+ // If a mapping is already recorded for this address
+ if (addrmap->from.sin_port == new_map->from.sin_port)
+ {
+ MsgPrint (MSG_WARNING,
+ "WARNING: Address %s:%hu has several mappings\n",
+ inet_ntoa (new_map->from.sin_addr),
+ ntohs (new_map->from.sin_port));
+
+ *prev = addrmap->next;
+ free (addrmap);
+ }
+ break;
+ }
+
+ prev = &addrmap->next;
+ addrmap = addrmap->next;
+ }
+
+ // Insert it
+ new_map->next = *prev;
+ *prev = new_map;
+
+ MsgPrint (MSG_NORMAL, "Address \"%s\" mapped to \"%s\" (%s:%hu)\n",
+ new_map->from_string, new_map->to_string,
+ inet_ntoa (new_map->to.sin_addr), ntohs (new_map->to.sin_port));
+}
+
+
+/*
+====================
+Sv_GetAddrmap
+
+Look for an address mapping corresponding to addr
+====================
+*/
+static const addrmap_t* Sv_GetAddrmap (const struct sockaddr_in* addr)
+{
+ const addrmap_t* addrmap = addrmaps;
+ const addrmap_t* found = NULL;
+
+ // Stop at the end of the list, or if the addresses become too high
+ while (addrmap != NULL &&
+ addrmap->from.sin_addr.s_addr <= addr->sin_addr.s_addr)
+ {
+ // If it's the right address
+ if (addrmap->from.sin_addr.s_addr == addr->sin_addr.s_addr)
+ {
+ // If the exact mapping isn't there
+ if (addrmap->from.sin_port > addr->sin_port)
+ return found;
+
+ // If we found the exact address
+ if (addrmap->from.sin_port == addr->sin_port)
+ return addrmap;
+
+ // General mapping
+ // Store it in case we don't find the exact address mapping
+ if (addrmap->from.sin_port == 0)
+ found = addrmap;
+ }
+
+ addrmap = addrmap->next;
+ }
+
+ return found;
+}
+
+
+/*
+====================
+Sv_ResolveAddrmap
+
+Resolve an addrmap structure and check the parameters validity
+====================
+*/
+static qboolean Sv_ResolveAddrmap (addrmap_t* addrmap)
+{
+ // Resolve the addresses
+ if (!Sv_ResolveAddr (addrmap->from_string, &addrmap->from) ||
+ !Sv_ResolveAddr (addrmap->to_string, &addrmap->to))
+ return qfalse;
+
+ // 0.0.0.0 addresses are forbidden
+ if (addrmap->from.sin_addr.s_addr == 0 ||
+ addrmap->to.sin_addr.s_addr == 0)
+ {
+ MsgPrint (MSG_ERROR,
+ "ERROR: Mapping from or to 0.0.0.0 is forbidden\n");
+ return qfalse;
+ }
+
+ // Do NOT allow mapping to loopback addresses
+ if ((ntohl (addrmap->to.sin_addr.s_addr) >> 24) == 127)
+ {
+ MsgPrint (MSG_ERROR,
+ "ERROR: Mapping to a loopback address is forbidden\n");
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+/*
+====================
+Sv_IsActive
+
+Return qtrue if a server is active.
+Test if the server has timed out and remove it if it's the case.
+====================
+*/
+static qboolean Sv_IsActive (server_t* server)
+{
+
+ // If the entry isn't even used
+ if (! server->active)
+ return qfalse;
+
+ // If the server has timed out
+ if (server->timeout < crt_time)
+ {
+ unsigned int hash;
+ server_t **prev, *sv;
+
+ hash = Sv_AddressHash (&server->address);
+ prev = &hash_table[hash];
+ sv = hash_table[hash];
+
+ while (sv != server)
+ {
+ prev = &sv->next;
+ sv = sv->next;
+ }
+
+ Sv_RemoveAndGetNextPtr (sv, prev);
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+// ---------- Public functions (servers) ---------- //
+
+/*
+====================
+Sv_SetHashSize
+
+Set a new hash size value
+====================
+*/
+qboolean Sv_SetHashSize (unsigned int size)
+{
+ // Too late?
+ if (hash_table != NULL)
+ return qfalse;
+
+ // Too big?
+ if (size > MAX_HASH_SIZE)
+ return qfalse;
+
+ hash_table_size = 1 << size;
+ return qtrue;
+}
+
+
+/*
+====================
+Sv_SetMaxNbServers
+
+Set a new hash size value
+====================
+*/
+qboolean Sv_SetMaxNbServers (unsigned int nb)
+{
+ // Too late?
+ if (servers != NULL)
+ return qfalse;
+
+ max_nb_servers = nb;
+ return qtrue;
+}
+
+
+/*
+====================
+Sv_Init
+
+Initialize the server list and hash table
+====================
+*/
+qboolean Sv_Init (void)
+{
+ size_t array_size;
+
+ // Allocate "servers" and clean it
+ array_size = max_nb_servers * sizeof (servers[0]);
+ servers = malloc (array_size);
+ if (!servers)
+ {
+ MsgPrint (MSG_ERROR,
+ "ERROR: can't allocate the servers array (%s)\n",
+ strerror (errno));
+ return qfalse;
+ }
+ last_alloc = max_nb_servers - 1;
+ memset (servers, 0, array_size);
+ MsgPrint (MSG_NORMAL, "%u server records allocated\n", max_nb_servers);
+
+ // Allocate "hash_table" and clean it
+ array_size = hash_table_size * sizeof (hash_table[0]);
+ hash_table = malloc (array_size);
+ if (!hash_table)
+ {
+ MsgPrint (MSG_ERROR, "ERROR: can't allocate the hash table (%s)\n",
+ strerror (errno));
+ free (servers);
+ return qfalse;
+ }
+ memset (hash_table, 0, array_size);
+ MsgPrint (MSG_NORMAL,
+ "Hash table allocated (%u entries)\n", hash_table_size);
+
+ return qtrue;
+}
+
+
+/*
+====================
+Sv_GetByAddr
+
+Search for a particular server in the list; add it if necessary
+====================
+*/
+server_t* Sv_GetByAddr (const struct sockaddr_in* address, qboolean add_it)
+{
+ server_t **prev, *sv;
+ unsigned int hash;
+ const addrmap_t* addrmap = Sv_GetAddrmap (address);
+ unsigned int startpt;
+
+ // Allow servers on a loopback address ONLY if a mapping is defined for them
+ if ((ntohl (address->sin_addr.s_addr) >> 24) == 127 && addrmap == NULL)
+ {
+ MsgPrint (MSG_WARNING,
+ "WARNING: server %s isn't allowed (loopback address)\n",
+ peer_address);
+ return NULL;
+ }
+
+ hash = Sv_AddressHash (address);
+ prev = &hash_table[hash];
+ sv = hash_table[hash];
+
+ while (sv != NULL)
+ {
+ // We check the timeout values while browsing this list
+ if (sv->timeout < crt_time)
+ {
+ sv = Sv_RemoveAndGetNextPtr (sv, prev);
+ continue;
+ }
+
+ // Found!
+ if (sv->address.sin_addr.s_addr == address->sin_addr.s_addr &&
+ sv->address.sin_port == address->sin_port)
+ {
+ // Put it on top of the list (it's useful because heartbeats
+ // are almost always followed by infoResponses)
+ *prev = sv->next;
+ sv->next = hash_table[hash];
+ hash_table[hash] = sv;
+
+ return sv;
+ }
+
+ prev = &sv->next;
+ sv = sv->next;
+ }
+
+ if (! add_it)
+ return NULL;
+
+ // Look for the first free entry in "servers"
+ startpt = last_alloc;
+ for (;;)
+ {
+ last_alloc = (last_alloc + 1) % max_nb_servers;
+
+ // Free entry found?
+ if (!Sv_IsActive (&servers[last_alloc]))
+ break;
+
+ // No more room
+ if (last_alloc == startpt)
+ return NULL;
+ }
+ sv = &servers[last_alloc];
+
+ // Initialize the structure
+ memset (sv, 0, sizeof (*sv));
+ memcpy (&sv->address, address, sizeof (sv->address));
+ sv->addrmap = addrmap;
+
+ // Add it to the list it belongs to
+ sv->next = hash_table[hash];
+ hash_table[hash] = sv;
+ nb_servers++;
+
+ MsgPrint (MSG_NORMAL,
+ "New server added: %s; %u servers are currently registered\n",
+ peer_address, nb_servers);
+ MsgPrint (MSG_DEBUG,
+ " - index: %u\n"
+ " - hash: 0x%02X\n",
+ last_alloc, hash);
+
+ return sv;
+}
+
+
+/*
+====================
+Sv_GetFirst
+
+Get the first server in the list
+====================
+*/
+server_t* Sv_GetFirst (void)
+{
+ crt_server = NULL;
+ prev_pointer = NULL;
+ crt_hash_ind = -1;
+
+ return Sv_GetNext ();
+}
+
+
+/*
+====================
+Sv_GetNext
+
+Get the next server in the list
+====================
+*/
+server_t* Sv_GetNext (void)
+{
+ for (;;)
+ {
+ // If there is a current server, follow the link
+ if (crt_server != NULL)
+ {
+ prev_pointer = &crt_server->next;
+ crt_server = crt_server->next;
+ }
+
+ // If we don't have the next server yet
+ if (crt_server == NULL)
+ {
+ // Search the hash table for the next server
+ while (crt_hash_ind < (int)(hash_table_size - 1))
+ {
+ crt_hash_ind++;
+
+ if (hash_table[crt_hash_ind] != NULL)
+ {
+ crt_server = hash_table[crt_hash_ind];
+ prev_pointer = &hash_table[crt_hash_ind];
+ break;
+ }
+ }
+ }
+
+ // Did we hit the end of the list?
+ if (crt_server == NULL)
+ return NULL;
+
+ // If the new current server has timed out, remove it
+ if (crt_server->timeout < crt_time)
+ crt_server = Sv_RemoveAndGetNextPtr (crt_server, prev_pointer);
+ else
+ return crt_server;
+ }
+}
+
+
+// ---------- Public functions (address mappings) ---------- //
+
+/*
+====================
+Sv_AddAddressMapping
+
+Add an unresolved address mapping to the list
+mapping must be of the form "addr1:port1=addr2:port2", ":portX" are optional
+====================
+*/
+qboolean Sv_AddAddressMapping (const char* mapping)
+{
+ char *map_string, *to_ip;
+ addrmap_t* addrmap;
+
+ // Get a working copy of the mapping string
+ map_string = strdup (mapping);
+ if (map_string == NULL)
+ {
+ MsgPrint (MSG_ERROR,
+ "ERROR: can't allocate address mapping string\n");
+ return qfalse;
+ }
+
+ // Find the '='
+ to_ip = strchr (map_string, '=');
+ if (to_ip == NULL)
+ {
+ MsgPrint (MSG_ERROR,
+ "ERROR: invalid syntax in address mapping string\n");
+ free (map_string);
+ return qfalse;
+ }
+ *to_ip++ = '\0';
+
+ // Allocate the structure
+ addrmap = malloc (sizeof (*addrmap));
+ if (addrmap == NULL)
+ {
+ MsgPrint (MSG_ERROR,
+ "ERROR: can't allocate address mapping structure\n");
+ free (map_string);
+ return qfalse;
+ }
+ memset (addrmap, 0, sizeof (*addrmap));
+ addrmap->from_string = strdup (map_string);
+ addrmap->to_string = strdup (to_ip);
+ if (addrmap->from_string == NULL || addrmap->to_string == NULL)
+ {
+ MsgPrint (MSG_ERROR,
+ "ERROR: can't allocate address mapping strings\n");
+ free (addrmap->to_string);
+ free (addrmap->from_string);
+ free (map_string);
+ return qfalse;
+ }
+
+ // Add it on top of "addrmaps"
+ addrmap->next = addrmaps;
+ addrmaps = addrmap;
+
+ return qtrue;
+}
+
+
+/*
+====================
+Sv_ResolveAddressMappings
+
+Resolve the address mapping list
+====================
+*/
+qboolean Sv_ResolveAddressMappings (void)
+{
+ addrmap_t* unresolved = addrmaps;
+ addrmap_t* addrmap;
+ qboolean succeeded = qtrue;
+
+ addrmaps = NULL;
+
+ while (unresolved != NULL)
+ {
+ // Remove it from the unresolved list
+ addrmap = unresolved;
+ unresolved = unresolved->next;
+
+ // Continue the resolution, even if there's an error
+ if (!Sv_ResolveAddrmap (addrmap))
+ {
+ free (addrmap->from_string);
+ free (addrmap->to_string);
+ free (addrmap);
+ succeeded = qfalse;
+ }
+ else
+ Sv_InsertAddrmapIntoList (addrmap);
+ }
+
+ return succeeded;
+}
diff --git a/src/master/servers.h b/src/master/servers.h
new file mode 100644
index 00000000..fbeef1c2
--- /dev/null
+++ b/src/master/servers.h
@@ -0,0 +1,102 @@
+/*
+ servers.h
+
+ Server list and address mapping management for dpmaster
+
+ Copyright (C) 2004-2005 Mathieu Olivier
+
+ 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
+*/
+
+
+#ifndef _SERVERS_H_
+#define _SERVERS_H_
+
+
+// ---------- Constants ---------- //
+
+// Maximum number of servers in all lists by default
+#define DEFAULT_MAX_NB_SERVERS 256
+
+// Address hash size in bits (between 0 and MAX_HASH_SIZE)
+#define DEFAULT_HASH_SIZE 6
+#define MAX_HASH_SIZE 8
+
+// Number of characters in a challenge, including the '\0'
+#define CHALLENGE_MIN_LENGTH 9
+#define CHALLENGE_MAX_LENGTH 12
+
+// ---------- Types ---------- //
+
+// Address mapping
+typedef struct addrmap_s
+{
+ struct addrmap_s* next;
+ struct sockaddr_in from;
+ struct sockaddr_in to;
+ char* from_string;
+ char* to_string;
+} addrmap_t;
+
+// Server properties
+typedef struct server_s
+{
+ struct server_s* next;
+ struct sockaddr_in address;
+ unsigned int protocol;
+ char challenge [CHALLENGE_MAX_LENGTH];
+ unsigned short nbclients;
+ unsigned short maxclients;
+ time_t timeout;
+ time_t challenge_timeout;
+ const struct addrmap_s* addrmap;
+ qboolean active;
+} server_t;
+
+
+// ---------- Public functions (servers) ---------- //
+
+// Will simply return "false" if called after Sv_Init
+qboolean Sv_SetHashSize (unsigned int size);
+qboolean Sv_SetMaxNbServers (unsigned int nb);
+
+// Initialize the server list and hash table
+qboolean Sv_Init (void);
+
+// Search for a particular server in the list; add it if necessary
+// NOTE: doesn't change the current position for "Sv_GetNext"
+server_t* Sv_GetByAddr (const struct sockaddr_in* address, qboolean add_it);
+
+// Get the first server in the list
+server_t* Sv_GetFirst (void);
+
+// Get the next server in the list
+server_t* Sv_GetNext (void);
+
+
+// ---------- Public functions (address mappings) ---------- //
+
+// NOTE: this is a 2-step process because resolving address mappings directly
+// during the parsing of the command line would cause several problems
+
+// Add an unresolved address mapping to the list
+// mapping must be of the form "addr1:port1=addr2:port2", ":portX" are optional
+qboolean Sv_AddAddressMapping (const char* mapping);
+
+// Resolve the address mapping list
+qboolean Sv_ResolveAddressMappings (void);
+
+
+#endif // #ifndef _SERVERS_H_
diff --git a/src/null/null_client.c b/src/null/null_client.c
index 039aa7c2..994f53f4 100644
--- a/src/null/null_client.c
+++ b/src/null/null_client.c
@@ -87,6 +87,3 @@ void CL_StartHunkUsers( void ) {
// bk001119 - added new dummy for sv_init.c
void CL_ShutdownAll(void) {};
-
-// bk001208 - added new dummy (RC4)
-qboolean CL_CDKeyValidate( const char *key, const char *checksum ) { return qtrue; }
diff --git a/src/qcommon/cm_trace.c b/src/qcommon/cm_trace.c
index 483b0756..ee9540e3 100644
--- a/src/qcommon/cm_trace.c
+++ b/src/qcommon/cm_trace.c
@@ -738,7 +738,8 @@ static void CM_ProximityToBrush( traceWork_t *tw, cbrush_t *brush )
cbrushedge_t *edge;
float dist, minDist = 1e+10f;
float s, t;
- float sAtMin, radius, fraction;
+ float sAtMin = 0.0f;
+ float radius = 0.0f, fraction;
traceWork_t tw2;
// cheapish purely linear trace to test for intersection
diff --git a/src/qcommon/cmd.c b/src/qcommon/cmd.c
index 2968f708..a3053c89 100644
--- a/src/qcommon/cmd.c
+++ b/src/qcommon/cmd.c
@@ -315,12 +315,37 @@ typedef struct cmd_function_s
} cmd_function_t;
-static int cmd_argc;
-static char *cmd_argv[MAX_STRING_TOKENS]; // points into cmd_tokenized
-static char cmd_tokenized[BIG_INFO_STRING+MAX_STRING_TOKENS]; // will have 0 bytes inserted
-static char cmd_cmd[BIG_INFO_STRING]; // the original command we received (no token processing)
+typedef struct cmdContext_s
+{
+ int argc;
+ char *argv[ MAX_STRING_TOKENS ]; // points into cmd.tokenized
+ char tokenized[ BIG_INFO_STRING + MAX_STRING_TOKENS ]; // will have 0 bytes inserted
+ char cmd[ BIG_INFO_STRING ]; // the original command we received (no token processing)
+} cmdContext_t;
+
+static cmdContext_t cmd;
+static cmdContext_t savedCmd;
+static cmd_function_t *cmd_functions; // possible commands to execute
-static cmd_function_t *cmd_functions; // possible commands to execute
+/*
+============
+Cmd_SaveCmdContext
+============
+*/
+void Cmd_SaveCmdContext( void )
+{
+ Com_Memcpy( &savedCmd, &cmd, sizeof( cmdContext_t ) );
+}
+
+/*
+============
+Cmd_RestoreCmdContext
+============
+*/
+void Cmd_RestoreCmdContext( void )
+{
+ Com_Memcpy( &cmd, &savedCmd, sizeof( cmdContext_t ) );
+}
/*
============
@@ -328,7 +353,7 @@ Cmd_Argc
============
*/
int Cmd_Argc( void ) {
- return cmd_argc;
+ return cmd.argc;
}
/*
@@ -337,10 +362,10 @@ Cmd_Argv
============
*/
char *Cmd_Argv( int arg ) {
- if ( (unsigned)arg >= cmd_argc ) {
+ if ( (unsigned)arg >= cmd.argc ) {
return "";
}
- return cmd_argv[arg];
+ return cmd.argv[arg];
}
/*
@@ -368,9 +393,9 @@ char *Cmd_Args( void ) {
int i;
cmd_args[0] = 0;
- for ( i = 1 ; i < cmd_argc ; i++ ) {
- strcat( cmd_args, cmd_argv[i] );
- if ( i != cmd_argc-1 ) {
+ for ( i = 1 ; i < cmd.argc ; i++ ) {
+ strcat( cmd_args, cmd.argv[i] );
+ if ( i != cmd.argc-1 ) {
strcat( cmd_args, " " );
}
}
@@ -392,9 +417,9 @@ char *Cmd_ArgsFrom( int arg ) {
cmd_args[0] = 0;
if (arg < 0)
arg = 0;
- for ( i = arg ; i < cmd_argc ; i++ ) {
- strcat( cmd_args, cmd_argv[i] );
- if ( i != cmd_argc-1 ) {
+ for ( i = arg ; i < cmd.argc ; i++ ) {
+ strcat( cmd_args, cmd.argv[i] );
+ if ( i != cmd.argc-1 ) {
strcat( cmd_args, " " );
}
}
@@ -423,7 +448,7 @@ they can't have pointers returned to them
============
*/
void Cmd_LiteralArgsBuffer( char *buffer, int bufferLength ) {
- Q_strncpyz( buffer, cmd_cmd, bufferLength );
+ Q_strncpyz( buffer, cmd.cmd, bufferLength );
}
/*
@@ -437,7 +462,7 @@ https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
*/
char *Cmd_Cmd(void)
{
- return cmd_cmd;
+ return cmd.cmd;
}
/*
@@ -462,20 +487,20 @@ void Cmd_TokenizeString( const char *text_in ) {
#endif
// clear previous args
- cmd_argc = 0;
- cmd_cmd[ 0 ] = '\0';
+ cmd.argc = 0;
+ cmd.cmd[ 0 ] = '\0';
if ( !text_in ) {
return;
}
- Q_strncpyz( cmd_cmd, text_in, sizeof(cmd_cmd) );
+ Q_strncpyz( cmd.cmd, text_in, sizeof(cmd.cmd) );
text = text_in;
- textOut = cmd_tokenized;
+ textOut = cmd.tokenized;
while ( 1 ) {
- if ( cmd_argc == MAX_STRING_TOKENS ) {
+ if ( cmd.argc == MAX_STRING_TOKENS ) {
return; // this is usually something malicious
}
@@ -510,8 +535,8 @@ void Cmd_TokenizeString( const char *text_in ) {
// handle quoted strings
// NOTE TTimo this doesn't handle \" escaping
if ( *text == '"' ) {
- cmd_argv[cmd_argc] = textOut;
- cmd_argc++;
+ cmd.argv[cmd.argc] = textOut;
+ cmd.argc++;
text++;
while ( *text && *text != '"' ) {
*textOut++ = *text++;
@@ -525,8 +550,8 @@ void Cmd_TokenizeString( const char *text_in ) {
}
// regular token
- cmd_argv[cmd_argc] = textOut;
- cmd_argc++;
+ cmd.argv[cmd.argc] = textOut;
+ cmd.argc++;
// skip until whitespace, quote, or command
while ( *text > ' ' ) {
@@ -633,7 +658,7 @@ A complete command line has been parsed, so try to execute it
============
*/
void Cmd_ExecuteString( const char *text ) {
- cmd_function_t *cmd, **prev;
+ cmd_function_t *cmdFunc, **prev;
// execute the command line
Cmd_TokenizeString( text );
@@ -642,21 +667,21 @@ void Cmd_ExecuteString( const char *text ) {
}
// check registered command functions
- for ( prev = &cmd_functions ; *prev ; prev = &cmd->next ) {
- cmd = *prev;
- if ( !Q_stricmp( cmd_argv[0],cmd->name ) ) {
+ for ( prev = &cmd_functions ; *prev ; prev = &cmdFunc->next ) {
+ cmdFunc = *prev;
+ if ( !Q_stricmp( cmd.argv[0], cmdFunc->name ) ) {
// rearrange the links so that the command will be
// near the head of the list next time it is used
- *prev = cmd->next;
- cmd->next = cmd_functions;
- cmd_functions = cmd;
+ *prev = cmdFunc->next;
+ cmdFunc->next = cmd_functions;
+ cmd_functions = cmdFunc;
// perform the action
- if ( !cmd->function ) {
+ if ( !cmdFunc->function ) {
// let the cgame or game handle it
break;
} else {
- cmd->function ();
+ cmdFunc->function ();
}
return;
}
diff --git a/src/qcommon/common.c b/src/qcommon/common.c
index 6ba479e3..231f4aa8 100644
--- a/src/qcommon/common.c
+++ b/src/qcommon/common.c
@@ -33,7 +33,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
int demo_protocols[] =
-{ 66, 67, 68, 0 };
+{ 66, 67, 68, 69, 0 };
#define MAX_NUM_ARGVS 50
@@ -2229,76 +2229,6 @@ static void Com_Crash_f( void ) {
* ( int * ) 0 = 0x12345678;
}
-// TTimo: centralizing the cl_cdkey stuff after I discovered a buffer overflow problem with the dedicated server version
-// not sure it's necessary to have different defaults for regular and dedicated, but I don't want to risk it
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=470
-#ifndef DEDICATED
-char cl_cdkey[34] = " ";
-#else
-char cl_cdkey[34] = "123456789";
-#endif
-
-/*
-=================
-Com_ReadCDKey
-=================
-*/
-qboolean CL_CDKeyValidate( const char *key, const char *checksum );
-void Com_ReadCDKey( const char *filename ) {
- fileHandle_t f;
- char buffer[33];
- char fbuffer[MAX_OSPATH];
-
- sprintf(fbuffer, "%s/q3key", filename);
-
- FS_SV_FOpenFileRead( fbuffer, &f );
- if ( !f ) {
- Q_strncpyz( cl_cdkey, " ", 17 );
- return;
- }
-
- Com_Memset( buffer, 0, sizeof(buffer) );
-
- FS_Read( buffer, 16, f );
- FS_FCloseFile( f );
-
- if (CL_CDKeyValidate(buffer, NULL)) {
- Q_strncpyz( cl_cdkey, buffer, 17 );
- } else {
- Q_strncpyz( cl_cdkey, " ", 17 );
- }
-}
-
-/*
-=================
-Com_AppendCDKey
-=================
-*/
-void Com_AppendCDKey( const char *filename ) {
- fileHandle_t f;
- char buffer[33];
- char fbuffer[MAX_OSPATH];
-
- sprintf(fbuffer, "%s/q3key", filename);
-
- FS_SV_FOpenFileRead( fbuffer, &f );
- if (!f) {
- Q_strncpyz( &cl_cdkey[16], " ", 17 );
- return;
- }
-
- Com_Memset( buffer, 0, sizeof(buffer) );
-
- FS_Read( buffer, 16, f );
- FS_FCloseFile( f );
-
- if (CL_CDKeyValidate(buffer, NULL)) {
- strcat( &cl_cdkey[16], buffer );
- } else {
- Q_strncpyz( &cl_cdkey[16], " ", 17 );
- }
-}
-
static void Com_DetectAltivec(void)
{
// Only detect if user hasn't forcibly disabled it.
diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c
index 6c0f612f..839f41ce 100644
--- a/src/qcommon/cvar.c
+++ b/src/qcommon/cvar.c
@@ -640,9 +640,6 @@ void Cvar_WriteVariables( fileHandle_t f ) {
char buffer[1024];
for (var = cvar_vars ; var ; var = var->next) {
- if( Q_stricmp( var->name, "cl_cdkey" ) == 0 ) {
- continue;
- }
if( var->flags & CVAR_ARCHIVE ) {
// write the latched value, even if it hasn't taken effect yet
if ( var->latchedString ) {
diff --git a/src/qcommon/files.c b/src/qcommon/files.c
index 09926a1a..1ea34cc6 100644
--- a/src/qcommon/files.c
+++ b/src/qcommon/files.c
@@ -2702,9 +2702,6 @@ void FS_Shutdown( qboolean closemfp ) {
#endif
}
-void Com_AppendCDKey( const char *filename );
-void Com_ReadCDKey( const char *filename );
-
/*
================
FS_ReorderPurePaks
@@ -2752,7 +2749,6 @@ FS_Startup
*/
static void FS_Startup( const char *gameName ) {
const char *homePath;
- cvar_t *fs;
Com_Printf( "----- FS_Startup -----\n" );
@@ -2808,12 +2804,6 @@ static void FS_Startup( const char *gameName ) {
}
}
- Com_ReadCDKey( "base" );
- fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
- if (fs && fs->string[0] != 0) {
- Com_AppendCDKey( fs->string );
- }
-
// add our commands
Cmd_AddCommand ("path", FS_Path_f);
Cmd_AddCommand ("dir", FS_Dir_f );
diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h
index 6dd8527d..53848aa4 100644
--- a/src/qcommon/q_shared.h
+++ b/src/qcommon/q_shared.h
@@ -1274,8 +1274,4 @@ typedef enum _flag_status {
#define SAY_TEAM 1
#define SAY_TELL 2
-#define CDKEY_LEN 16
-#define CDCHKSUM_LEN 2
-
-
#endif // __Q_SHARED_H
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index 11c332ce..843f04ef 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -227,27 +227,20 @@ PROTOCOL
==============================================================
*/
-#define PROTOCOL_VERSION 68
-// 1.31 - 67
+// 69 is identical in every way to 68 - the change is to avoid
+// confusing connecting Q3 clients
+#define PROTOCOL_VERSION 69
// maintain a list of compatible protocols for demo playing
// NOTE: that stuff only works with two digits protocols
extern int demo_protocols[];
-#define UPDATE_SERVER_NAME "update.quake3arena.com"
// override on command line, config files etc.
#ifndef MASTER_SERVER_NAME
-#define MASTER_SERVER_NAME "master.quake3arena.com"
-#endif
-#ifndef AUTHORIZE_SERVER_NAME
-#define AUTHORIZE_SERVER_NAME "authorize.quake3arena.com"
+#define MASTER_SERVER_NAME "master.tremulous.net"
#endif
#define PORT_MASTER 27950
-#define PORT_UPDATE 27951
-#ifndef PORT_AUTHORIZE
-#define PORT_AUTHORIZE 27952
-#endif
#define PORT_SERVER 27960
#define NUM_SERVER_PORTS 4 // broadcast scan this many ports after
// PORT_SERVER so a single machine can
@@ -424,6 +417,8 @@ void Cmd_ExecuteString( const char *text );
// Parses a single line of text into arguments and tries to execute it
// as if it was typed at the console
+void Cmd_SaveCmdContext( void );
+void Cmd_RestoreCmdContext( void );
/*
==============================================================
@@ -693,10 +688,6 @@ MISC
#define Q_vsnprintf vsnprintf
#endif
-// centralizing the declarations for cl_cdkey
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=470
-extern char cl_cdkey[34];
-
// returnbed by Sys_GetProcessorId
#define CPUID_GENERIC 0 // any unrecognized processor
@@ -916,7 +907,6 @@ qboolean SV_GameCommand( void );
// UI interface
//
qboolean UI_GameCommand( void );
-qboolean UI_usesUniqueCDKey(void);
/*
==============================================================
diff --git a/src/server/server.h b/src/server/server.h
index 6740a82d..da8c8aae 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -242,7 +242,6 @@ extern cvar_t *sv_serverid;
extern cvar_t *sv_maxRate;
extern cvar_t *sv_minPing;
extern cvar_t *sv_maxPing;
-extern cvar_t *sv_gametype;
extern cvar_t *sv_pure;
extern cvar_t *sv_floodProtect;
extern cvar_t *sv_lanForceRate;
diff --git a/src/server/sv_ccmds.c b/src/server/sv_ccmds.c
index 9128249f..fde921d1 100644
--- a/src/server/sv_ccmds.c
+++ b/src/server/sv_ccmds.c
@@ -154,9 +154,6 @@ static void SV_Map_f( void ) {
return;
}
- // force latched values to get set
- Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH );
-
cmd = Cmd_Argv(0);
if ( !Q_stricmp( cmd, "devmap" ) || !Q_stricmp( cmd, "spdevmap" ) ) {
cheat = qtrue;
@@ -228,7 +225,7 @@ static void SV_MapRestart_f( void ) {
// check for changes in variables that can't just be restarted
// check for maxclients change
- if ( sv_maxclients->modified || sv_gametype->modified ) {
+ if ( sv_maxclients->modified ) {
char mapname[MAX_QPATH];
Com_Printf( "variable change -- restarting.\n" );
@@ -400,6 +397,8 @@ static void SV_Ban_f( void ) {
return;
}
+ //FIXME: there is no auth server in Tremulous
+#if 0
// look up the authorize server's IP
if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
@@ -421,6 +420,7 @@ static void SV_Ban_f( void ) {
cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
Com_Printf("%s was banned from coming back\n", cl->name);
}
+#endif
}
/*
@@ -454,6 +454,8 @@ static void SV_BanNum_f( void ) {
return;
}
+ //FIXME: there is no auth server in Tremulous
+#if 0
// look up the authorize server's IP
if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
@@ -475,6 +477,7 @@ static void SV_BanNum_f( void ) {
cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
Com_Printf("%s was banned from coming back\n", cl->name);
}
+#endif
}
/*
diff --git a/src/server/sv_client.c b/src/server/sv_client.c
index ba32299e..84ce86a0 100644
--- a/src/server/sv_client.c
+++ b/src/server/sv_client.c
@@ -77,138 +77,9 @@ void SV_GetChallenge( netadr_t from ) {
i = oldest;
}
- // if they are on a lan address, send the challengeResponse immediately
- if ( Sys_IsLANAddress( from ) ) {
- challenge->pingTime = svs.time;
- NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge );
- return;
- }
-
- // look up the authorize server's IP
- if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
- Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
- if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {
- Com_Printf( "Couldn't resolve address\n" );
- return;
- }
- svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
- svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
- svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
- BigShort( svs.authorizeAddress.port ) );
- }
-
- // if they have been challenging for a long time and we
- // haven't heard anything from the authorize server, go ahead and
- // let them in, assuming the id server is down
- if ( svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT ) {
- Com_DPrintf( "authorize server timed out\n" );
-
- challenge->pingTime = svs.time;
- NET_OutOfBandPrint( NS_SERVER, challenge->adr,
- "challengeResponse %i", challenge->challenge );
- return;
- }
-
- // otherwise send their ip to the authorize server
- if ( svs.authorizeAddress.type != NA_BAD ) {
- cvar_t *fs;
- char game[1024];
-
- Com_DPrintf( "sending getIpAuthorize for %s\n", NET_AdrToString( from ));
-
- strcpy(game, BASEGAME);
- fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
- if (fs && fs->string[0] != 0) {
- strcpy(game, fs->string);
- }
-
- // the 0 is for backwards compatibility with obsolete sv_allowanonymous flags
- // getIpAuthorize <challenge> <IP> <game> 0 <auth-flag>
- NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
- "getIpAuthorize %i %i.%i.%i.%i %s 0 %s", svs.challenges[i].challenge,
- from.ip[0], from.ip[1], from.ip[2], from.ip[3], game, "0" );
- }
-}
-
-/*
-====================
-SV_AuthorizeIpPacket
-
-A packet has been returned from the authorize server.
-If we have a challenge adr for that ip, send the
-challengeResponse to it
-====================
-*/
-void SV_AuthorizeIpPacket( netadr_t from ) {
- int challenge;
- int i;
- char *s;
- char *r;
- char ret[1024];
-
- if ( !NET_CompareBaseAdr( from, svs.authorizeAddress ) ) {
- Com_Printf( "SV_AuthorizeIpPacket: not from authorize server\n" );
- return;
- }
-
- challenge = atoi( Cmd_Argv( 1 ) );
-
- for (i = 0 ; i < MAX_CHALLENGES ; i++) {
- if ( svs.challenges[i].challenge == challenge ) {
- break;
- }
- }
- if ( i == MAX_CHALLENGES ) {
- Com_Printf( "SV_AuthorizeIpPacket: challenge not found\n" );
- return;
- }
-
- // send a packet back to the original client
- svs.challenges[i].pingTime = svs.time;
- s = Cmd_Argv( 2 );
- r = Cmd_Argv( 3 ); // reason
-
- if ( !Q_stricmp( s, "demo" ) ) {
- if ( Cvar_VariableValue( "fs_restrict" ) ) {
- // a demo client connecting to a demo server
- NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr,
- "challengeResponse %i", svs.challenges[i].challenge );
- return;
- }
- // they are a demo client trying to connect to a real server
- NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nServer is not a demo server\n" );
- // clear the challenge record so it won't timeout and let them through
- Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );
- return;
- }
- if ( !Q_stricmp( s, "accept" ) ) {
- NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr,
- "challengeResponse %i", svs.challenges[i].challenge );
- return;
- }
- if ( !Q_stricmp( s, "unknown" ) ) {
- if (!r) {
- NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nAwaiting CD key authorization\n" );
- } else {
- sprintf(ret, "print\n%s\n", r);
- NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret );
- }
- // clear the challenge record so it won't timeout and let them through
- Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );
- return;
- }
-
- // authorization failed
- if (!r) {
- NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nSomeone is using this CD Key\n" );
- } else {
- sprintf(ret, "print\n%s\n", r);
- NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret );
- }
-
- // clear the challenge record so it won't timeout and let them through
- Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );
+ // send the challengeResponse
+ challenge->pingTime = svs.time;
+ NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge );
}
/*
@@ -218,11 +89,6 @@ SV_DirectConnect
A "connect" OOB command has been received
==================
*/
-
-#define PB_MESSAGE "PunkBuster Anti-Cheat software must be installed " \
- "and Enabled in order to join this server. An updated game patch can be downloaded from " \
- "www.idsoftware.com"
-
void SV_DirectConnect( netadr_t from ) {
char userinfo[MAX_INFO_STRING];
int i;
diff --git a/src/server/sv_init.c b/src/server/sv_init.c
index e484edcc..3d08b6ea 100644
--- a/src/server/sv_init.c
+++ b/src/server/sv_init.c
@@ -442,9 +442,6 @@ void SV_SpawnServer( char *server, qboolean killBots ) {
// load and spawn all other entities
SV_InitGameProgs();
- // don't allow a map_restart if game is modified
- sv_gametype->modified = qfalse;
-
// run a few frames to allow everything to settle
for (i = 0;i < 3; i++)
{
@@ -572,10 +569,7 @@ void SV_Init (void) {
SV_AddOperatorCommands ();
// serverinfo vars
- Cvar_Get ("dmflags", "0", CVAR_SERVERINFO);
- Cvar_Get ("fraglimit", "20", CVAR_SERVERINFO);
Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
- sv_gametype = Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH );
Cvar_Get ("sv_keywords", "", CVAR_SERVERINFO);
Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_ROM);
sv_mapname = Cvar_Get ("mapname", "nomap", CVAR_SERVERINFO | CVAR_ROM);
diff --git a/src/server/sv_main.c b/src/server/sv_main.c
index 6f96ac7f..1d658a60 100644
--- a/src/server/sv_main.c
+++ b/src/server/sv_main.c
@@ -48,7 +48,6 @@ cvar_t *sv_serverid;
cvar_t *sv_maxRate;
cvar_t *sv_minPing;
cvar_t *sv_maxPing;
-cvar_t *sv_gametype;
cvar_t *sv_pure;
cvar_t *sv_floodProtect;
cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491)
@@ -220,7 +219,7 @@ but not on every player enter or exit.
================
*/
#define HEARTBEAT_MSEC 300*1000
-#define HEARTBEAT_GAME "QuakeArena-1"
+#define HEARTBEAT_GAME "Tremulous"
void SV_MasterHeartbeat( void ) {
static netadr_t adr[MAX_MASTER_SERVERS];
int i;
@@ -400,7 +399,6 @@ void SVC_Info( netadr_t from ) {
Info_SetValueForKey( infostring, "clients", va("%i", count) );
Info_SetValueForKey( infostring, "sv_maxclients",
va("%i", sv_maxclients->integer - sv_privateClients->integer ) );
- Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) );
Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) );
if( sv_minPing->integer ) {
@@ -531,8 +529,6 @@ void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
SV_GetChallenge( from );
} else if (!Q_stricmp(c, "connect")) {
SV_DirectConnect( from );
- } else if (!Q_stricmp(c, "ipAuthorize")) {
- SV_AuthorizeIpPacket( from );
} else if (!Q_stricmp(c, "rcon")) {
SVC_RemoteCommand( from, msg );
} else if (!Q_stricmp(c, "disconnect")) {
diff --git a/src/server/sv_rankings.c b/src/server/sv_rankings.c
index 023a7a2a..20d24fd4 100644
--- a/src/server/sv_rankings.c
+++ b/src/server/sv_rankings.c
@@ -86,7 +86,7 @@ void SV_RankBegin( char *gamekey )
assert( !s_rankings_active );
assert( s_ranked_players == NULL );
- if( sv_enableRankings->integer == 0 || Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER )
+ if( sv_enableRankings->integer == 0 )
{
s_rankings_active = qfalse;
if( sv_rankingsActive->integer == 1 )
diff --git a/src/ui/ui_atoms.c b/src/ui/ui_atoms.c
index 850a1ac2..64efa914 100644
--- a/src/ui/ui_atoms.c
+++ b/src/ui/ui_atoms.c
@@ -377,11 +377,6 @@ qboolean UI_ConsoleCommand( int realTime )
}
}
- if ( Q_stricmp (cmd, "ui_cdkey") == 0 ) {
- //UI_CDKeyMenu_f();
- return qtrue;
- }
-
return qfalse;
}
diff --git a/src/ui/ui_gameinfo.c b/src/ui/ui_gameinfo.c
index 451e54af..ab3ce6da 100644
--- a/src/ui/ui_gameinfo.c
+++ b/src/ui/ui_gameinfo.c
@@ -124,6 +124,19 @@ static void UI_LoadArenasFromFile( char *filename ) {
}
/*
+=================
+UI_MapNameCompare
+=================
+*/
+static int UI_MapNameCompare( const void *a, const void *b )
+{
+ mapInfo *A = (mapInfo *)a;
+ mapInfo *B = (mapInfo *)b;
+
+ return Q_stricmp( A->mapName, B->mapName );
+}
+
+/*
===============
UI_LoadArenas
===============
@@ -140,14 +153,6 @@ void UI_LoadArenas( void ) {
ui_numArenas = 0;
uiInfo.mapCount = 0;
-/* trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
- if( *arenasFile.string ) {
- UI_LoadArenasFromFile(arenasFile.string);
- }
- else {
- UI_LoadArenasFromFile("scripts/arenas.txt");
- }*/
-
// get all arenas from .arena files
numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
dirptr = dirlist;
@@ -183,6 +188,8 @@ void UI_LoadArenas( void ) {
if( uiInfo.mapCount >= MAX_MAPS )
break;
}
+
+ qsort( uiInfo.mapList, uiInfo.mapCount, sizeof( mapInfo ), UI_MapNameCompare );
}
diff --git a/src/ui/ui_local.h b/src/ui/ui_local.h
index 865ce927..d8340695 100644
--- a/src/ui/ui_local.h
+++ b/src/ui/ui_local.h
@@ -88,9 +88,6 @@ extern vmCvar_t ui_server14;
extern vmCvar_t ui_server15;
extern vmCvar_t ui_server16;
-extern vmCvar_t ui_cdkey;
-extern vmCvar_t ui_cdkeychecked;
-
extern vmCvar_t ui_captureLimit;
extern vmCvar_t ui_fragLimit;
extern vmCvar_t ui_gameType;
@@ -432,13 +429,6 @@ extern void UI_ModsMenu( void );
extern void UI_ModsMenu_Cache( void );
//
-// ui_cdkey.c
-//
-extern void UI_CDKeyMenu( void );
-extern void UI_CDKeyMenu_Cache( void );
-extern void UI_CDKeyMenu_f( void );
-
-//
// ui_playermodel.c
//
extern void UI_PlayerModelMenu( void );
@@ -1059,8 +1049,6 @@ void trap_LAN_ResetPings(int n);
int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen );
int trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 );
int trap_MemoryRemaining( void );
-void trap_GetCDKey( char *buf, int buflen );
-void trap_SetCDKey( char *buf );
void trap_R_RegisterFont(const char *pFontname, int pointSize, fontInfo_t *font);
void trap_S_StopBackgroundTrack( void );
void trap_S_StartBackgroundTrack( const char *intro, const char *loop);
@@ -1071,7 +1059,6 @@ void trap_CIN_DrawCinematic (int handle);
void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
int trap_RealTime(qtime_t *qtime);
void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
-qboolean trap_VerifyCDKey( const char *key, const char *chksum);
void trap_SetPbClStatus( int status );
diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c
index bf00c5fa..198a33f6 100644
--- a/src/ui/ui_main.c
+++ b/src/ui/ui_main.c
@@ -199,9 +199,6 @@ long vmMain( long command, long arg0, long arg1, long arg2, long arg3,
case UI_DRAW_CONNECT_SCREEN:
UI_DrawConnectScreen( arg0 );
return 0;
- case UI_HASUNIQUECDKEY: // mod authors need to observe this
- return qfalse; // bk010117 - change this to qfalse for mods!
-
}
return -1;
@@ -4002,37 +3999,6 @@ static void UI_RunMenuScript(char **args) {
Controls_SetDefaults();
trap_Cvar_Set("com_introPlayed", "1" );
trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
- } else if (Q_stricmp(name, "getCDKey") == 0) {
- char out[17];
- trap_GetCDKey(buff, 17);
- trap_Cvar_Set("cdkey1", "");
- trap_Cvar_Set("cdkey2", "");
- trap_Cvar_Set("cdkey3", "");
- trap_Cvar_Set("cdkey4", "");
- if (strlen(buff) == CDKEY_LEN) {
- Q_strncpyz(out, buff, 5);
- trap_Cvar_Set("cdkey1", out);
- Q_strncpyz(out, buff + 4, 5);
- trap_Cvar_Set("cdkey2", out);
- Q_strncpyz(out, buff + 8, 5);
- trap_Cvar_Set("cdkey3", out);
- Q_strncpyz(out, buff + 12, 5);
- trap_Cvar_Set("cdkey4", out);
- }
-
- } else if (Q_stricmp(name, "verifyCDKey") == 0) {
- buff[0] = '\0';
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey1"));
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey2"));
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey3"));
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey4"));
- trap_Cvar_Set("cdkey", buff);
- if (trap_VerifyCDKey(buff, UI_Cvar_VariableString("cdkeychecksum"))) {
- trap_Cvar_Set("ui_cdkeyvalid", "CD Key Appears to be valid.");
- trap_SetCDKey(buff);
- } else {
- trap_Cvar_Set("ui_cdkeyvalid", "CD Key does not appear to be valid.");
- }
} else if (Q_stricmp(name, "loadArenas") == 0) {
UI_LoadArenas();
UI_MapCountByGameType(qfalse);
@@ -4601,10 +4567,6 @@ static void UI_BuildServerDisplayList(qboolean force) {
// do motd updates here too
trap_Cvar_VariableStringBuffer( "cl_motdString", uiInfo.serverStatus.motd, sizeof(uiInfo.serverStatus.motd) );
len = strlen(uiInfo.serverStatus.motd);
- if (len == 0) {
- strcpy(uiInfo.serverStatus.motd, "Welcome to Tremulous!");
- len = strlen(uiInfo.serverStatus.motd);
- }
if (len != uiInfo.serverStatus.motdLen) {
uiInfo.serverStatus.motdLen = len;
uiInfo.serverStatus.motdWidth = -1;
@@ -4670,13 +4632,6 @@ static void UI_BuildServerDisplayList(qboolean force) {
}
}
- //TA: only show tremulous servers
- if( Q_stricmp( Info_ValueForKey( info, "game" ), "tremulous" ) != 0 )
- {
- trap_LAN_MarkServerVisible( ui_netSource.integer, i, qfalse );
- continue;
- }
-
// make sure we never add a favorite server twice
if (ui_netSource.integer == AS_FAVORITES) {
UI_RemoveServerFromDisplayList(i);
@@ -5173,13 +5128,13 @@ static const char *UI_FeederItemText(float feederID, int index, int column, qhan
return UI_SelectedMap(index, &actual);
} else if (feederID == FEEDER_SERVERS) {
if (index >= 0 && index < uiInfo.serverStatus.numDisplayServers) {
- int ping, punkbuster;
+ int ping;
if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000) {
trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
lastColumn = column;
lastTime = uiInfo.uiDC.realTime;
}
- /*return "bah";*/
+
ping = atoi(Info_ValueForKey(info, "ping"));
if (ping == -1) {
// if we ever see a ping that is out of date, do a server refresh
@@ -5213,13 +5168,6 @@ static const char *UI_FeederItemText(float feederID, int index, int column, qhan
} else {
return Info_ValueForKey(info, "ping");
}
- case SORT_PUNKBUSTER:
- punkbuster = atoi(Info_ValueForKey(info, "punkbuster"));
- if ( punkbuster ) {
- return "Yes";
- } else {
- return "No";
- }
}
}
} else if (feederID == FEEDER_SERVERSTATUS) {
@@ -5831,18 +5779,6 @@ void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
trap_Key_SetCatcher( KEYCATCH_UI );
Menus_ActivateByName("team");
return;
- case UIMENU_NEED_CD:
- // no cd check in TA
- //trap_Key_SetCatcher( KEYCATCH_UI );
- //Menus_ActivateByName("needcd");
- //UI_ConfirmMenu( "Insert the CD", NULL, NeedCDAction );
- return;
- case UIMENU_BAD_CD_KEY:
- // no cd check in TA
- //trap_Key_SetCatcher( KEYCATCH_UI );
- //Menus_ActivateByName("badcd");
- //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
- return;
case UIMENU_POSTGAME:
//trap_Cvar_Set( "sv_killserver", "1" );
trap_Key_SetCatcher( KEYCATCH_UI );
@@ -5851,7 +5787,6 @@ void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
}
Menus_CloseAll();
Menus_ActivateByName("endofgame");
- //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
return;
case UIMENU_INGAME:
trap_Cvar_Set( "cl_paused", "1" );
@@ -6198,8 +6133,6 @@ vmCvar_t ui_server14;
vmCvar_t ui_server15;
vmCvar_t ui_server16;
-vmCvar_t ui_cdkeychecked;
-
vmCvar_t ui_redteam;
vmCvar_t ui_redteam1;
vmCvar_t ui_redteam2;
@@ -6321,7 +6254,6 @@ static cvarTable_t cvarTable[] = {
{ &ui_server14, "server14", "", CVAR_ARCHIVE },
{ &ui_server15, "server15", "", CVAR_ARCHIVE },
{ &ui_server16, "server16", "", CVAR_ARCHIVE },
- { &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
{ &ui_new, "ui_new", "0", CVAR_TEMP },
{ &ui_debug, "ui_debug", "0", CVAR_TEMP },
{ &ui_initialized, "ui_initialized", "0", CVAR_TEMP },
@@ -6504,7 +6436,8 @@ static void UI_StartServerRefresh(qboolean full)
qtime_t q;
trap_RealTime(&q);
- trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i at %i:%i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min));
+ trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer),
+ va("%s-%i, %i at %i:%02i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min));
if (!full) {
UI_UpdatePendingPings();
diff --git a/src/ui/ui_public.h b/src/ui/ui_public.h
index 2308256d..9e39d52b 100644
--- a/src/ui/ui_public.h
+++ b/src/ui/ui_public.h
@@ -89,8 +89,6 @@ typedef enum {
UI_CVAR_REGISTER,
UI_CVAR_UPDATE,
UI_MEMORY_REMAINING,
- UI_GET_CDKEY,
- UI_SET_CDKEY,
UI_R_REGISTERFONT,
UI_R_MODELBOUNDS,
UI_PC_ADD_GLOBAL_DEFINE,
@@ -117,7 +115,6 @@ typedef enum {
UI_CIN_DRAWCINEMATIC,
UI_CIN_SETEXTENTS,
UI_R_REMAP_SHADER,
- UI_VERIFY_CDKEY,
UI_LAN_SERVERSTATUS,
UI_LAN_GETSERVERPING,
UI_LAN_SERVERISVISIBLE,
@@ -141,8 +138,6 @@ typedef enum {
UIMENU_NONE,
UIMENU_MAIN,
UIMENU_INGAME,
- UIMENU_NEED_CD,
- UIMENU_BAD_CD_KEY,
UIMENU_TEAM,
UIMENU_POSTGAME
} uiMenuCommand_t;
@@ -152,7 +147,6 @@ typedef enum
SORT_HOST,
SORT_MAP,
SORT_CLIENTS,
- SORT_PUNKBUSTER,
SORT_PING
} serverSortField_t;
@@ -183,9 +177,9 @@ typedef enum {
UI_CONSOLE_COMMAND,
// qboolean UI_ConsoleCommand( int realTime );
- UI_DRAW_CONNECT_SCREEN,
+ UI_DRAW_CONNECT_SCREEN
// void UI_DrawConnectScreen( qboolean overlay );
- UI_HASUNIQUECDKEY
+
// if !overlay, the background will be drawn, otherwise it will be
// overlayed over whatever the cgame has drawn.
// a GetClientState syscall will be made to get the current strings
diff --git a/src/ui/ui_syscalls.asm b/src/ui/ui_syscalls.asm
index 54255f29..d84ce335 100644
--- a/src/ui/ui_syscalls.asm
+++ b/src/ui/ui_syscalls.asm
@@ -53,8 +53,6 @@ equ trap_LAN_GetPingInfo -50
equ trap_Cvar_Register -51
equ trap_Cvar_Update -52
equ trap_MemoryRemaining -53
-equ trap_GetCDKey -54
-equ trap_SetCDKey -55
equ trap_R_RegisterFont -56
equ trap_R_ModelBounds -57
equ trap_PC_AddGlobalDefine -58
@@ -81,7 +79,6 @@ equ trap_CIN_RunCinematic -78
equ trap_CIN_DrawCinematic -79
equ trap_CIN_SetExtents -80
equ trap_R_RemapShader -81
-equ trap_VerifyCDKey -82
equ trap_LAN_ServerStatus -83
equ trap_LAN_GetServerPing -84
equ trap_LAN_ServerIsVisible -85
diff --git a/src/ui/ui_syscalls.c b/src/ui/ui_syscalls.c
index d0a17b77..3aba4d69 100644
--- a/src/ui/ui_syscalls.c
+++ b/src/ui/ui_syscalls.c
@@ -316,14 +316,6 @@ int trap_MemoryRemaining( void ) {
return syscall( UI_MEMORY_REMAINING );
}
-void trap_GetCDKey( char *buf, int buflen ) {
- syscall( UI_GET_CDKEY, buf, buflen );
-}
-
-void trap_SetCDKey( char *buf ) {
- syscall( UI_SET_CDKEY, buf );
-}
-
int trap_PC_AddGlobalDefine( char *define ) {
return syscall( UI_PC_ADD_GLOBAL_DEFINE, define );
}
@@ -390,10 +382,6 @@ void trap_R_RemapShader( const char *oldShader, const char *newShader, const ch
syscall( UI_R_REMAP_SHADER, oldShader, newShader, timeOffset );
}
-qboolean trap_VerifyCDKey( const char *key, const char *chksum) {
- return syscall( UI_VERIFY_CDKEY, key, chksum);
-}
-
void trap_SetPbClStatus( int status ) {
syscall( UI_SET_PBCLSTATUS, status );
}
diff --git a/src/unix/Makefile b/src/unix/Makefile
index 69b3826c..6070a846 100644
--- a/src/unix/Makefile
+++ b/src/unix/Makefile
@@ -588,6 +588,9 @@ else # ifeq SunOS
SHLIBLDFLAGS=-shared
TARGETS=\
+ $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
+ $(B)/base/qagame$(ARCH).$(SHLIBEXT) \
+ $(B)/base/ui$(ARCH).$(SHLIBEXT) \
$(B)/$(PLATFORM)tremded
endif #Linux
@@ -650,11 +653,13 @@ release: build_release
build_debug: B=$(BD)
build_debug: makedirs tools
- $(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(DEBUG_CFLAGS) $(DEPEND_CFLAGS)"
+ $(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(DEBUG_CFLAGS) $(DEPEND_CFLAGS)"
+ $(MAKE) -C ../master debug
build_release: B=$(BR)
build_release: makedirs tools
- $(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(RELEASE_CFLAGS) $(DEPEND_CFLAGS)"
+ $(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(RELEASE_CFLAGS) $(DEPEND_CFLAGS)"
+ $(MAKE) -C ../master release
#Build both debug and release builds
all:build_debug build_release
@@ -1558,6 +1563,7 @@ copyfiles: build_release
clean:clean-debug clean-release
$(MAKE) -C setup clean
+ $(MAKE) -C ../master clean
clean2:
if [ -d $(B) ];then (find $(B) -name '*.d' -exec rm {} \;)fi
diff --git a/ui/createserver.menu b/ui/createserver.menu
index 1b071270..abd93cee 100644
--- a/ui/createserver.menu
+++ b/ui/createserver.menu
@@ -125,7 +125,7 @@
cvar "sv_hostname"
maxChars 32
maxPaintChars 20
- rect 420 20 128 20
+ rect 420 30 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
textaligny 12
@@ -141,7 +141,7 @@
type ITEM_TYPE_NUMERICFIELD
text "Time Limit:"
cvar "timelimit"
- rect 420 40 128 20
+ rect 420 50 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
maxchars 4
@@ -158,7 +158,7 @@
type ITEM_TYPE_NUMERICFIELD
text "Maximum Players:"
cvar "sv_maxclients"
- rect 420 60 128 20
+ rect 420 70 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
maxchars 4
@@ -175,7 +175,7 @@
type ITEM_TYPE_YESNO
text "Require Password:"
cvar "g_needpassword"
- rect 420 80 128 20
+ rect 420 90 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
textaligny 12
@@ -195,7 +195,7 @@
type 4
text "Password:"
cvar "g_password"
- rect 420 100 128 20
+ rect 420 110 128 20
maxchars 10
maxPaintChars 10
textalign ITEM_ALIGN_RIGHT
@@ -208,31 +208,6 @@
-
-
-
-
- itemDef
- {
- name normal
- group grpsettings
- type ITEM_TYPE_MULTI
- text "Punkbuster:"
- cvar "sv_punkbuster"
- cvarFloatList { "No" 0 "Yes" 1 }
- rect 420 150 128 20
- textalign ITEM_ALIGN_RIGHT
- textalignx 65
- textaligny 12
- textscale .36
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav"
- }
- }
-
itemDef
{
name normal
@@ -240,7 +215,7 @@
type ITEM_TYPE_YESNO
text "Pure Server:"
cvar "sv_pure"
- rect 420 170 128 20
+ rect 420 160 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
textaligny 12
@@ -263,7 +238,7 @@
// the game goes to console only so the ui catches this one specifically
cvar "ui_dedicated"
cvarFloatList { "No" 0 "LAN" 1 "Internet" 2 }
- rect 420 190 128 20
+ rect 420 180 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
textaligny 12
@@ -283,7 +258,7 @@
type ITEM_TYPE_YESNO
text "Auto Download:"
cvar "sv_allowdownload"
- rect 420 210 128 20
+ rect 420 200 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
textaligny 12
@@ -303,7 +278,7 @@
type ITEM_TYPE_YESNO
text "Enable Voting:"
cvar "g_allowvote"
- rect 420 230 128 20
+ rect 420 220 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
textaligny 12
@@ -318,10 +293,6 @@
-
-
-
-
itemDef
{
name expert
@@ -329,7 +300,7 @@
type ITEM_TYPE_NUMERICFIELD
text "Minimum Ping:"
cvar "sv_minping"
- rect 420 280 128 20
+ rect 420 270 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
maxchars 4
@@ -346,7 +317,7 @@
type ITEM_TYPE_NUMERICFIELD
text "Maximum Ping:"
cvar "sv_maxping"
- rect 420 300 128 20
+ rect 420 290 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
textaligny 12
@@ -363,7 +334,7 @@
type ITEM_TYPE_YESNO
text "Synchronous Client:"
cvar "g_synchronousclients"
- rect 420 320 128 20
+ rect 420 310 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
textaligny 12
@@ -383,7 +354,7 @@
type ITEM_TYPE_NUMERICFIELD
text "Max Rate:"
cvar "sv_maxrate"
- rect 420 340 128 20
+ rect 420 330 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
maxchars 4
@@ -400,7 +371,7 @@
type ITEM_TYPE_NUMERICFIELD
text "Zombie Time:"
cvar "sv_zombietime"
- rect 420 360 128 20
+ rect 420 350 128 20
maxchars 4
textalign ITEM_ALIGN_RIGHT
textalignx 65
@@ -418,7 +389,7 @@
text "Reconnect Limit:"
cvar "sv_reconnectlimit"
maxchars 4
- rect 420 380 128 20
+ rect 420 370 128 20
textalign ITEM_ALIGN_RIGHT
textalignx 65
textaligny 12
diff --git a/ui/joinserver.menu b/ui/joinserver.menu
index 4d6b846b..38ee1b1e 100644
--- a/ui/joinserver.menu
+++ b/ui/joinserver.menu
@@ -194,49 +194,6 @@
}
}
- itemDef
- {
- name PunkBusterInfo
- group pbgrp
- text "PunkBuster:"
- type ITEM_TYPE_BUTTON
- cvar "ui_browserShowEmpty"
- textscale .4
- style WINDOW_STYLE_FILLED
- rect 354 50 128 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 22
- backcolor 0 0 0 0
- forecolor 1 1 1 1
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- conditionalopen cl_punkbuster pbdisable_popmenu pbenable_popmenu
- }
- }
-
- itemDef
- {
- name pbstatus
- group pbgrp
- type ITEM_TYPE_MULTI
- text ""
- cvar "cl_punkbuster"
- cvarFloatList { "Off" 0 "On" 1 }
- rect 438 50 64 26
- textalign ITEM_ALIGN_CENTER
- textalignx 10
- textaligny 22
- textscale .4
- forecolor 1 1 1 1
- style WINDOW_STYLE_FILLED
- backcolor 0 0 0 0
- visible 1
- decoration
- }
-
// map selection
@@ -267,7 +224,7 @@
{
name serverColumn
group grpColumn
- rect 10 130 333 232
+ rect 10 130 365 232
style WINDOW_STYLE_FILLED
border 1
backcolor 0 0 0 0
@@ -281,7 +238,7 @@
{
name mapColumn
group grpColumn
- rect 343 130 125 232
+ rect 375 130 125 232
style WINDOW_STYLE_FILLED
border 1
backcolor 0 0 0 0
@@ -295,7 +252,7 @@
{
name playerColumn
group grpColumn
- rect 468 130 60 232
+ rect 500 130 60 232
style WINDOW_STYLE_FILLED
border 1
backcolor 0 0 0 0
@@ -307,20 +264,6 @@
itemDef
{
- name pbColumn
- group grpColumn
- rect 528 130 32 232
- style WINDOW_STYLE_FILLED
- border 1
- backcolor 0 0 0 0
- bordersize 1
- bordercolor .5 .5 .5 1
- visible 1
- decoration
- }
-
- itemDef
- {
name pingColumn
group grpColumn
rect 560 130 52 232
@@ -350,11 +293,10 @@
backcolor 0.2 0.2 0.2 1
outlinecolor 0.1 0.1 0.1 0.5
visible 1
- columns 5
+ columns 4
2 40 40 ITEM_ALIGN_LEFT
- 343 40 20 ITEM_ALIGN_LEFT
- 468 5 10 ITEM_ALIGN_LEFT
- 528 5 10 ITEM_ALIGN_LEFT
+ 375 40 20 ITEM_ALIGN_LEFT
+ 500 5 10 ITEM_ALIGN_LEFT
560 20 20 ITEM_ALIGN_LEFT
doubleClick { uiScript JoinServer }
@@ -371,7 +313,7 @@
type ITEM_TYPE_BUTTON
textscale .33
style WINDOW_STYLE_EMPTY
- rect 10 103 333 26
+ rect 10 103 365 26
textalign ITEM_ALIGN_LEFT
textalignx 10
textaligny 18
@@ -399,7 +341,7 @@
text "Map Name"
textscale .33
style WINDOW_STYLE_EMPTY
- rect 343 103 125 26
+ rect 375 103 125 26
textalign ITEM_ALIGN_LEFT
textalignx 10
textaligny 18
@@ -427,7 +369,7 @@
type ITEM_TYPE_BUTTON
textscale .33
style WINDOW_STYLE_EMPTY
- rect 468 103 60 26
+ rect 500 103 60 26
textalign ITEM_ALIGN_LEFT
textalignx 10
textaligny 18
@@ -447,34 +389,6 @@
}
}
- itemDef
- {
- name PB
- group grpTabs
- text "PB"
- type ITEM_TYPE_BUTTON
- textscale .33
- style WINDOW_STYLE_EMPTY
- rect 528 103 32 26
- textalign ITEM_ALIGN_LEFT
- textalignx 10
- textaligny 18
- border 1
- bordercolor 0.5 0.5 0.5 1
- forecolor 1 1 1 1
- backcolor 0.2 0.2 0.2 1
- outlinecolor 0.1 0.1 0.1 0.5
- visible 1
- action
- {
- play "sound/misc/menu1.wav";
- uiScript ServerSort 5;
-
- setitemcolor grpColumn backcolor 0 0 0 0;
- setitemcolor pbColumn backcolor 0.3 1 1 0.5
- }
- }
-
itemDef
{
diff --git a/ui/quitcredit.menu b/ui/quitcredit.menu
index 27568ea1..e3798d0c 100644
--- a/ui/quitcredit.menu
+++ b/ui/quitcredit.menu
@@ -28,7 +28,6 @@
background "ui/assets/credits_splash.jpg"
action
{
- play "sound/misc/nomenu.wav";
close quitCredit;
uiScript "quit"
}