Home | History | Annotate | Download | only in server
      1 /*
      2 Copyright (C) 1996-1997 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 
     21 #include "qwsvdef.h"
     22 
     23 quakeparms_t host_parms;
     24 
     25 qboolean	host_initialized;		// true if into command execution (compatability)
     26 
     27 double		host_frametime;
     28 double		realtime;				// without any filtering or bounding
     29 
     30 int			host_hunklevel;
     31 
     32 netadr_t	master_adr[MAX_MASTERS];	// address of group servers
     33 
     34 client_t	*host_client;			// current client
     35 
     36 cvar_t	sv_mintic = {"sv_mintic","0.03"};	// bound the size of the
     37 cvar_t	sv_maxtic = {"sv_maxtic","0.1"};	// physics time tic
     38 
     39 cvar_t	developer = {"developer","0"};		// show extra messages
     40 
     41 cvar_t	timeout = {"timeout","65"};		// seconds without any message
     42 cvar_t	zombietime = {"zombietime", "2"};	// seconds to sink messages
     43 											// after disconnect
     44 
     45 cvar_t	rcon_password = {"rcon_password", ""};	// password for remote server commands
     46 cvar_t	password = {"password", ""};	// password for entering the game
     47 cvar_t	spectator_password = {"spectator_password", ""};	// password for entering as a sepctator
     48 
     49 cvar_t	allow_download = {"allow_download", "1"};
     50 cvar_t	allow_download_skins = {"allow_download_skins", "1"};
     51 cvar_t	allow_download_models = {"allow_download_models", "1"};
     52 cvar_t	allow_download_sounds = {"allow_download_sounds", "1"};
     53 cvar_t	allow_download_maps = {"allow_download_maps", "1"};
     54 
     55 cvar_t sv_highchars = {"sv_highchars", "1"};
     56 
     57 cvar_t sv_phs = {"sv_phs", "1"};
     58 
     59 cvar_t pausable	= {"pausable", "1"};
     60 
     61 
     62 //
     63 // game rules mirrored in svs.info
     64 //
     65 cvar_t	fraglimit = {"fraglimit","0",false,true};
     66 cvar_t	timelimit = {"timelimit","0",false,true};
     67 cvar_t	teamplay = {"teamplay","0",false,true};
     68 cvar_t	samelevel = {"samelevel","0", false, true};
     69 cvar_t	maxclients = {"maxclients","8", false, true};
     70 cvar_t	maxspectators = {"maxspectators","8", false, true};
     71 cvar_t	deathmatch = {"deathmatch","1", false, true};			// 0, 1, or 2
     72 cvar_t	spawn = {"spawn","0", false, true};
     73 cvar_t	watervis = {"watervis", "0", false, true};
     74 
     75 cvar_t	hostname = {"hostname","unnamed", false, true};
     76 
     77 FILE	*sv_logfile;
     78 FILE	*sv_fraglogfile;
     79 
     80 void SV_AcceptClient (netadr_t adr, int userid, char *userinfo);
     81 void Master_Shutdown (void);
     82 
     83 //============================================================================
     84 
     85 qboolean ServerPaused(void)
     86 {
     87 	return sv.paused;
     88 }
     89 
     90 /*
     91 ================
     92 SV_Shutdown
     93 
     94 Quake calls this before calling Sys_Quit or Sys_Error
     95 ================
     96 */
     97 void SV_Shutdown (void)
     98 {
     99 	Master_Shutdown ();
    100 	if (sv_logfile)
    101 	{
    102 		fclose (sv_logfile);
    103 		sv_logfile = NULL;
    104 	}
    105 	if (sv_fraglogfile)
    106 	{
    107 		fclose (sv_fraglogfile);
    108 		sv_logfile = NULL;
    109 	}
    110 	NET_Shutdown ();
    111 }
    112 
    113 /*
    114 ================
    115 SV_Error
    116 
    117 Sends a datagram to all the clients informing them of the server crash,
    118 then exits
    119 ================
    120 */
    121 void SV_Error (char *error, ...)
    122 {
    123 	va_list		argptr;
    124 	static	char		string[1024];
    125 	static	qboolean inerror = false;
    126 
    127 	if (inerror)
    128 		Sys_Error ("SV_Error: recursively entered (%s)", string);
    129 
    130 	inerror = true;
    131 
    132 	va_start (argptr,error);
    133 	vsprintf (string,error,argptr);
    134 	va_end (argptr);
    135 
    136 	Con_Printf ("SV_Error: %s\n",string);
    137 
    138 	SV_FinalMessage (va("server crashed: %s\n", string));
    139 
    140 	SV_Shutdown ();
    141 
    142 	Sys_Error ("SV_Error: %s\n",string);
    143 }
    144 
    145 /*
    146 ==================
    147 SV_FinalMessage
    148 
    149 Used by SV_Error and SV_Quit_f to send a final message to all connected
    150 clients before the server goes down.  The messages are sent immediately,
    151 not just stuck on the outgoing message list, because the server is going
    152 to totally exit after returning from this function.
    153 ==================
    154 */
    155 void SV_FinalMessage (char *message)
    156 {
    157 	int			i;
    158 	client_t	*cl;
    159 
    160 	SZ_Clear (&net_message);
    161 	MSG_WriteByte (&net_message, svc_print);
    162 	MSG_WriteByte (&net_message, PRINT_HIGH);
    163 	MSG_WriteString (&net_message, message);
    164 	MSG_WriteByte (&net_message, svc_disconnect);
    165 
    166 	for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
    167 		if (cl->state >= cs_spawned)
    168 			Netchan_Transmit (&cl->netchan, net_message.cursize
    169 			, net_message.data);
    170 }
    171 
    172 
    173 
    174 /*
    175 =====================
    176 SV_DropClient
    177 
    178 Called when the player is totally leaving the server, either willingly
    179 or unwillingly.  This is NOT called if the entire server is quiting
    180 or crashing.
    181 =====================
    182 */
    183 void SV_DropClient (client_t *drop)
    184 {
    185 	// add the disconnect
    186 	MSG_WriteByte (&drop->netchan.message, svc_disconnect);
    187 
    188 	if (drop->state == cs_spawned)
    189 		if (!drop->spectator)
    190 		{
    191 			// call the prog function for removing a client
    192 			// this will set the body to a dead frame, among other things
    193 			pr_global_struct->self = EDICT_TO_PROG(drop->edict);
    194 			PR_ExecuteProgram (pr_global_struct->ClientDisconnect);
    195 		}
    196 		else if (SpectatorDisconnect)
    197 		{
    198 			// call the prog function for removing a client
    199 			// this will set the body to a dead frame, among other things
    200 			pr_global_struct->self = EDICT_TO_PROG(drop->edict);
    201 			PR_ExecuteProgram (SpectatorDisconnect);
    202 		}
    203 
    204 	if (drop->spectator)
    205 		Con_Printf ("Spectator %s removed\n",drop->name);
    206 	else
    207 		Con_Printf ("Client %s removed\n",drop->name);
    208 
    209 	if (drop->download)
    210 	{
    211 		fclose (drop->download);
    212 		drop->download = NULL;
    213 	}
    214 	if (drop->upload)
    215 	{
    216 		fclose (drop->upload);
    217 		drop->upload = NULL;
    218 	}
    219 	*drop->uploadfn = 0;
    220 
    221 	drop->state = cs_zombie;		// become free in a few seconds
    222 	drop->connection_started = realtime;	// for zombie timeout
    223 
    224 	drop->old_frags = 0;
    225 	drop->edict->v.frags = 0;
    226 	drop->name[0] = 0;
    227 	memset (drop->userinfo, 0, sizeof(drop->userinfo));
    228 
    229 // send notification to all remaining clients
    230 	SV_FullClientUpdate (drop, &sv.reliable_datagram);
    231 }
    232 
    233 
    234 //====================================================================
    235 
    236 /*
    237 ===================
    238 SV_CalcPing
    239 
    240 ===================
    241 */
    242 int SV_CalcPing (client_t *cl)
    243 {
    244 	float		ping;
    245 	int			i;
    246 	int			count;
    247 	register	client_frame_t *frame;
    248 
    249 	ping = 0;
    250 	count = 0;
    251 	for (frame = cl->frames, i=0 ; i<UPDATE_BACKUP ; i++, frame++)
    252 	{
    253 		if (frame->ping_time > 0)
    254 		{
    255 			ping += frame->ping_time;
    256 			count++;
    257 		}
    258 	}
    259 	if (!count)
    260 		return 9999;
    261 	ping /= count;
    262 
    263 	return ping*1000;
    264 }
    265 
    266 /*
    267 ===================
    268 SV_FullClientUpdate
    269 
    270 Writes all update values to a sizebuf
    271 ===================
    272 */
    273 void SV_FullClientUpdate (client_t *client, sizebuf_t *buf)
    274 {
    275 	int		i;
    276 	char	info[MAX_INFO_STRING];
    277 
    278 	i = client - svs.clients;
    279 
    280 //Sys_Printf("SV_FullClientUpdate:  Updated frags for client %d\n", i);
    281 
    282 	MSG_WriteByte (buf, svc_updatefrags);
    283 	MSG_WriteByte (buf, i);
    284 	MSG_WriteShort (buf, client->old_frags);
    285 
    286 	MSG_WriteByte (buf, svc_updateping);
    287 	MSG_WriteByte (buf, i);
    288 	MSG_WriteShort (buf, SV_CalcPing (client));
    289 
    290 	MSG_WriteByte (buf, svc_updatepl);
    291 	MSG_WriteByte (buf, i);
    292 	MSG_WriteByte (buf, client->lossage);
    293 
    294 	MSG_WriteByte (buf, svc_updateentertime);
    295 	MSG_WriteByte (buf, i);
    296 	MSG_WriteFloat (buf, realtime - client->connection_started);
    297 
    298 	strcpy (info, client->userinfo);
    299 	Info_RemovePrefixedKeys (info, '_');	// server passwords, etc
    300 
    301 	MSG_WriteByte (buf, svc_updateuserinfo);
    302 	MSG_WriteByte (buf, i);
    303 	MSG_WriteLong (buf, client->userid);
    304 	MSG_WriteString (buf, info);
    305 }
    306 
    307 /*
    308 ===================
    309 SV_FullClientUpdateToClient
    310 
    311 Writes all update values to a client's reliable stream
    312 ===================
    313 */
    314 void SV_FullClientUpdateToClient (client_t *client, client_t *cl)
    315 {
    316 	ClientReliableCheckBlock(cl, 24 + strlen(client->userinfo));
    317 	if (cl->num_backbuf) {
    318 		SV_FullClientUpdate (client, &cl->backbuf);
    319 		ClientReliable_FinishWrite(cl);
    320 	} else
    321 		SV_FullClientUpdate (client, &cl->netchan.message);
    322 }
    323 
    324 
    325 /*
    326 ==============================================================================
    327 
    328 CONNECTIONLESS COMMANDS
    329 
    330 ==============================================================================
    331 */
    332 
    333 /*
    334 ================
    335 SVC_Status
    336 
    337 Responds with all the info that qplug or qspy can see
    338 This message can be up to around 5k with worst case string lengths.
    339 ================
    340 */
    341 void SVC_Status (void)
    342 {
    343 	int		i;
    344 	client_t	*cl;
    345 	int		ping;
    346 	int		top, bottom;
    347 
    348 	Cmd_TokenizeString ("status");
    349 	SV_BeginRedirect (RD_PACKET);
    350 	Con_Printf ("%s\n", svs.info);
    351 	for (i=0 ; i<MAX_CLIENTS ; i++)
    352 	{
    353 		cl = &svs.clients[i];
    354 		if ((cl->state == cs_connected || cl->state == cs_spawned ) && !cl->spectator)
    355 		{
    356 			top = atoi(Info_ValueForKey (cl->userinfo, "topcolor"));
    357 			bottom = atoi(Info_ValueForKey (cl->userinfo, "bottomcolor"));
    358 			top = (top < 0) ? 0 : ((top > 13) ? 13 : top);
    359 			bottom = (bottom < 0) ? 0 : ((bottom > 13) ? 13 : bottom);
    360 			ping = SV_CalcPing (cl);
    361 			Con_Printf ("%i %i %i %i \"%s\" \"%s\" %i %i\n", cl->userid,
    362 				cl->old_frags, (int)(realtime - cl->connection_started)/60,
    363 				ping, cl->name, Info_ValueForKey (cl->userinfo, "skin"), top, bottom);
    364 		}
    365 	}
    366 	SV_EndRedirect ();
    367 }
    368 
    369 /*
    370 ===================
    371 SV_CheckLog
    372 
    373 ===================
    374 */
    375 #define	LOG_HIGHWATER	4096
    376 #define	LOG_FLUSH		10*60
    377 void SV_CheckLog (void)
    378 {
    379 	sizebuf_t	*sz;
    380 
    381 	sz = &svs.log[svs.logsequence&1];
    382 
    383 	// bump sequence if allmost full, or ten minutes have passed and
    384 	// there is something still sitting there
    385 	if (sz->cursize > LOG_HIGHWATER
    386 	|| (realtime - svs.logtime > LOG_FLUSH && sz->cursize) )
    387 	{
    388 		// swap buffers and bump sequence
    389 		svs.logtime = realtime;
    390 		svs.logsequence++;
    391 		sz = &svs.log[svs.logsequence&1];
    392 		sz->cursize = 0;
    393 		Con_Printf ("beginning fraglog sequence %i\n", svs.logsequence);
    394 	}
    395 
    396 }
    397 
    398 /*
    399 ================
    400 SVC_Log
    401 
    402 Responds with all the logged frags for ranking programs.
    403 If a sequence number is passed as a parameter and it is
    404 the same as the current sequence, an A2A_NACK will be returned
    405 instead of the data.
    406 ================
    407 */
    408 void SVC_Log (void)
    409 {
    410 	int		seq;
    411 	char	data[MAX_DATAGRAM+64];
    412 
    413 	if (Cmd_Argc() == 2)
    414 		seq = atoi(Cmd_Argv(1));
    415 	else
    416 		seq = -1;
    417 
    418 	if (seq == svs.logsequence-1 || !sv_fraglogfile)
    419 	{	// they allready have this data, or we aren't logging frags
    420 		data[0] = A2A_NACK;
    421 		NET_SendPacket (1, data, net_from);
    422 		return;
    423 	}
    424 
    425 	Con_DPrintf ("sending log %i to %s\n", svs.logsequence-1, NET_AdrToString(net_from));
    426 
    427 	sprintf (data, "stdlog %i\n", svs.logsequence-1);
    428 	strcat (data, (char *)svs.log_buf[((svs.logsequence-1)&1)]);
    429 
    430 	NET_SendPacket (strlen(data)+1, data, net_from);
    431 }
    432 
    433 /*
    434 ================
    435 SVC_Ping
    436 
    437 Just responds with an acknowledgement
    438 ================
    439 */
    440 void SVC_Ping (void)
    441 {
    442 	char	data;
    443 
    444 	data = A2A_ACK;
    445 
    446 	NET_SendPacket (1, &data, net_from);
    447 }
    448 
    449 /*
    450 =================
    451 SVC_GetChallenge
    452 
    453 Returns a challenge number that can be used
    454 in a subsequent client_connect command.
    455 We do this to prevent denial of service attacks that
    456 flood the server with invalid connection IPs.  With a
    457 challenge, they must give a valid IP address.
    458 =================
    459 */
    460 void SVC_GetChallenge (void)
    461 {
    462 	int		i;
    463 	int		oldest;
    464 	int		oldestTime;
    465 
    466 	oldest = 0;
    467 	oldestTime = 0x7fffffff;
    468 
    469 	// see if we already have a challenge for this ip
    470 	for (i = 0 ; i < MAX_CHALLENGES ; i++)
    471 	{
    472 		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
    473 			break;
    474 		if (svs.challenges[i].time < oldestTime)
    475 		{
    476 			oldestTime = svs.challenges[i].time;
    477 			oldest = i;
    478 		}
    479 	}
    480 
    481 	if (i == MAX_CHALLENGES)
    482 	{
    483 		// overwrite the oldest
    484 		svs.challenges[oldest].challenge = (rand() << 16) ^ rand();
    485 		svs.challenges[oldest].adr = net_from;
    486 		svs.challenges[oldest].time = realtime;
    487 		i = oldest;
    488 	}
    489 
    490 	// send it back
    491 	Netchan_OutOfBandPrint (net_from, "%c%i", S2C_CHALLENGE,
    492 			svs.challenges[i].challenge);
    493 }
    494 
    495 /*
    496 ==================
    497 SVC_DirectConnect
    498 
    499 A connection request that did not come from the master
    500 ==================
    501 */
    502 void SVC_DirectConnect (void)
    503 {
    504 	char		userinfo[1024];
    505 	static		int	userid;
    506 	netadr_t	adr;
    507 	int			i;
    508 	client_t	*cl, *newcl;
    509 	client_t	temp;
    510 	edict_t		*ent;
    511 	int			edictnum;
    512 	char		*s;
    513 	int			clients, spectators;
    514 	qboolean	spectator;
    515 	int			qport;
    516 	int			version;
    517 	int			challenge;
    518 
    519 	version = atoi(Cmd_Argv(1));
    520 	if (version != PROTOCOL_VERSION)
    521 	{
    522 		Netchan_OutOfBandPrint (net_from, "%c\nServer is version %4.2f.\n", A2C_PRINT, VERSION);
    523 		Con_Printf ("* rejected connect from version %i\n", version);
    524 		return;
    525 	}
    526 
    527 	qport = atoi(Cmd_Argv(2));
    528 
    529 	challenge = atoi(Cmd_Argv(3));
    530 
    531 	// note an extra byte is needed to replace spectator key
    532 	strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-2);
    533 	userinfo[sizeof(userinfo) - 2] = 0;
    534 
    535 	// see if the challenge is valid
    536 	for (i=0 ; i<MAX_CHALLENGES ; i++)
    537 	{
    538 		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
    539 		{
    540 			if (challenge == svs.challenges[i].challenge)
    541 				break;		// good
    542 			Netchan_OutOfBandPrint (net_from, "%c\nBad challenge.\n", A2C_PRINT);
    543 			return;
    544 		}
    545 	}
    546 	if (i == MAX_CHALLENGES)
    547 	{
    548 		Netchan_OutOfBandPrint (net_from, "%c\nNo challenge for address.\n", A2C_PRINT);
    549 		return;
    550 	}
    551 
    552 	// check for password or spectator_password
    553 	s = Info_ValueForKey (userinfo, "spectator");
    554 	if (s[0] && strcmp(s, "0"))
    555 	{
    556 		if (spectator_password.string[0] &&
    557 			stricmp(spectator_password.string, "none") &&
    558 			strcmp(spectator_password.string, s) )
    559 		{	// failed
    560 			Con_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from));
    561 			Netchan_OutOfBandPrint (net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT);
    562 			return;
    563 		}
    564 		Info_RemoveKey (userinfo, "spectator"); // remove passwd
    565 		Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING);
    566 		spectator = true;
    567 	}
    568 	else
    569 	{
    570 		s = Info_ValueForKey (userinfo, "password");
    571 		if (password.string[0] &&
    572 			stricmp(password.string, "none") &&
    573 			strcmp(password.string, s) )
    574 		{
    575 			Con_Printf ("%s:password failed\n", NET_AdrToString (net_from));
    576 			Netchan_OutOfBandPrint (net_from, "%c\nserver requires a password\n\n", A2C_PRINT);
    577 			return;
    578 		}
    579 		spectator = false;
    580 		Info_RemoveKey (userinfo, "password"); // remove passwd
    581 	}
    582 
    583 	adr = net_from;
    584 	userid++;	// so every client gets a unique id
    585 
    586 	newcl = &temp;
    587 	memset (newcl, 0, sizeof(client_t));
    588 
    589 	newcl->userid = userid;
    590 
    591 	// works properly
    592 	if (!sv_highchars.value) {
    593 		byte *p, *q;
    594 
    595 		for (p = (byte *)newcl->userinfo, q = (byte *)userinfo;
    596 			*q && p < (byte *)newcl->userinfo + sizeof(newcl->userinfo)-1; q++)
    597 			if (*q > 31 && *q <= 127)
    598 				*p++ = *q;
    599 	} else
    600 		strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
    601 
    602 	// if there is allready a slot for this ip, drop it
    603 	for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
    604 	{
    605 		if (cl->state == cs_free)
    606 			continue;
    607 		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
    608 			&& ( cl->netchan.qport == qport
    609 			|| adr.port == cl->netchan.remote_address.port ))
    610 		{
    611 			if (cl->state == cs_connected) {
    612 				Con_Printf("%s:dup connect\n", NET_AdrToString (adr));
    613 				userid--;
    614 				return;
    615 			}
    616 
    617 			Con_Printf ("%s:reconnect\n", NET_AdrToString (adr));
    618 			SV_DropClient (cl);
    619 			break;
    620 		}
    621 	}
    622 
    623 	// count up the clients and spectators
    624 	clients = 0;
    625 	spectators = 0;
    626 	for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
    627 	{
    628 		if (cl->state == cs_free)
    629 			continue;
    630 		if (cl->spectator)
    631 			spectators++;
    632 		else
    633 			clients++;
    634 	}
    635 
    636 	// if at server limits, refuse connection
    637 	if ( maxclients.value > MAX_CLIENTS )
    638 		Cvar_SetValue ("maxclients", MAX_CLIENTS);
    639 	if (maxspectators.value > MAX_CLIENTS)
    640 		Cvar_SetValue ("maxspectators", MAX_CLIENTS);
    641 	if (maxspectators.value + maxclients.value > MAX_CLIENTS)
    642 		Cvar_SetValue ("maxspectators", MAX_CLIENTS - maxspectators.value + maxclients.value);
    643 	if ( (spectator && spectators >= (int)maxspectators.value)
    644 		|| (!spectator && clients >= (int)maxclients.value) )
    645 	{
    646 		Con_Printf ("%s:full connect\n", NET_AdrToString (adr));
    647 		Netchan_OutOfBandPrint (adr, "%c\nserver is full\n\n", A2C_PRINT);
    648 		return;
    649 	}
    650 
    651 	// find a client slot
    652 	newcl = NULL;
    653 	for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
    654 	{
    655 		if (cl->state == cs_free)
    656 		{
    657 			newcl = cl;
    658 			break;
    659 		}
    660 	}
    661 	if (!newcl)
    662 	{
    663 		Con_Printf ("WARNING: miscounted available clients\n");
    664 		return;
    665 	}
    666 
    667 
    668 	// build a new connection
    669 	// accept the new client
    670 	// this is the only place a client_t is ever initialized
    671 	*newcl = temp;
    672 
    673 	Netchan_OutOfBandPrint (adr, "%c", S2C_CONNECTION );
    674 
    675 	edictnum = (newcl-svs.clients)+1;
    676 
    677 	Netchan_Setup (&newcl->netchan , adr, qport);
    678 
    679 	newcl->state = cs_connected;
    680 
    681 	newcl->datagram.allowoverflow = true;
    682 	newcl->datagram.data = newcl->datagram_buf;
    683 	newcl->datagram.maxsize = sizeof(newcl->datagram_buf);
    684 
    685 	// spectator mode can ONLY be set at join time
    686 	newcl->spectator = spectator;
    687 
    688 	ent = EDICT_NUM(edictnum);
    689 	newcl->edict = ent;
    690 
    691 	// parse some info from the info strings
    692 	SV_ExtractFromUserinfo (newcl);
    693 
    694 	// JACK: Init the floodprot stuff.
    695 	for (i=0; i<10; i++)
    696 		newcl->whensaid[i] = 0.0;
    697 	newcl->whensaidhead = 0;
    698 	newcl->lockedtill = 0;
    699 
    700 	// call the progs to get default spawn parms for the new client
    701 	PR_ExecuteProgram (pr_global_struct->SetNewParms);
    702 	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
    703 		newcl->spawn_parms[i] = (&pr_global_struct->parm1)[i];
    704 
    705 	if (newcl->spectator)
    706 		Con_Printf ("Spectator %s connected\n", newcl->name);
    707 	else
    708 		Con_DPrintf ("Client %s connected\n", newcl->name);
    709 	newcl->sendinfo = true;
    710 }
    711 
    712 int Rcon_Validate (void)
    713 {
    714 	if (!strlen (rcon_password.string))
    715 		return 0;
    716 
    717 	if (strcmp (Cmd_Argv(1), rcon_password.string) )
    718 		return 0;
    719 
    720 	return 1;
    721 }
    722 
    723 /*
    724 ===============
    725 SVC_RemoteCommand
    726 
    727 A client issued an rcon command.
    728 Shift down the remaining args
    729 Redirect all printfs
    730 ===============
    731 */
    732 void SVC_RemoteCommand (void)
    733 {
    734 	int		i;
    735 	char	remaining[1024];
    736 
    737 
    738 	if (!Rcon_Validate ()) {
    739 		Con_Printf ("Bad rcon from %s:\n%s\n"
    740 			, NET_AdrToString (net_from), net_message.data+4);
    741 
    742 		SV_BeginRedirect (RD_PACKET);
    743 
    744 		Con_Printf ("Bad rcon_password.\n");
    745 
    746 	} else {
    747 
    748 		Con_Printf ("Rcon from %s:\n%s\n"
    749 			, NET_AdrToString (net_from), net_message.data+4);
    750 
    751 		SV_BeginRedirect (RD_PACKET);
    752 
    753 		remaining[0] = 0;
    754 
    755 		for (i=2 ; i<Cmd_Argc() ; i++)
    756 		{
    757 			strcat (remaining, Cmd_Argv(i) );
    758 			strcat (remaining, " ");
    759 		}
    760 
    761 		Cmd_ExecuteString (remaining);
    762 
    763 	}
    764 
    765 	SV_EndRedirect ();
    766 }
    767 
    768 
    769 /*
    770 =================
    771 SV_ConnectionlessPacket
    772 
    773 A connectionless packet has four leading 0xff
    774 characters to distinguish it from a game channel.
    775 Clients that are in the game can still send
    776 connectionless packets.
    777 =================
    778 */
    779 void SV_ConnectionlessPacket (void)
    780 {
    781 	char	*s;
    782 	char	*c;
    783 
    784 	MSG_BeginReading ();
    785 	MSG_ReadLong ();		// skip the -1 marker
    786 
    787 	s = MSG_ReadStringLine ();
    788 
    789 	Cmd_TokenizeString (s);
    790 
    791 	c = Cmd_Argv(0);
    792 
    793 	if (!strcmp(c, "ping") || ( c[0] == A2A_PING && (c[1] == 0 || c[1] == '\n')) )
    794 	{
    795 		SVC_Ping ();
    796 		return;
    797 	}
    798 	if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n') )
    799 	{
    800 		Con_Printf ("A2A_ACK from %s\n", NET_AdrToString (net_from));
    801 		return;
    802 	}
    803 	else if (!strcmp(c,"status"))
    804 	{
    805 		SVC_Status ();
    806 		return;
    807 	}
    808 	else if (!strcmp(c,"log"))
    809 	{
    810 		SVC_Log ();
    811 		return;
    812 	}
    813 	else if (!strcmp(c,"connect"))
    814 	{
    815 		SVC_DirectConnect ();
    816 		return;
    817 	}
    818 	else if (!strcmp(c,"getchallenge"))
    819 	{
    820 		SVC_GetChallenge ();
    821 		return;
    822 	}
    823 	else if (!strcmp(c, "rcon"))
    824 		SVC_RemoteCommand ();
    825 	else
    826 		Con_Printf ("bad connectionless packet from %s:\n%s\n"
    827 		, NET_AdrToString (net_from), s);
    828 }
    829 
    830 /*
    831 ==============================================================================
    832 
    833 PACKET FILTERING
    834 
    835 
    836 You can add or remove addresses from the filter list with:
    837 
    838 addip <ip>
    839 removeip <ip>
    840 
    841 The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with "addip 192.246.40".
    842 
    843 Removeip will only remove an address specified exactly the same way.  You cannot addip a subnet, then removeip a single host.
    844 
    845 listip
    846 Prints the current list of filters.
    847 
    848 writeip
    849 Dumps "addip <ip>" commands to listip.cfg so it can be execed at a later date.  The filter lists are not saved and restored by default, because I beleive it would cause too much confusion.
    850 
    851 filterban <0 or 1>
    852 
    853 If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game.  This is the default setting.
    854 
    855 If 0, then only addresses matching the list will be allowed.  This lets you easily set up a private game, or a game that only allows players from your local network.
    856 
    857 
    858 ==============================================================================
    859 */
    860 
    861 
    862 typedef struct
    863 {
    864 	unsigned	mask;
    865 	unsigned	compare;
    866 } ipfilter_t;
    867 
    868 #define	MAX_IPFILTERS	1024
    869 
    870 ipfilter_t	ipfilters[MAX_IPFILTERS];
    871 int			numipfilters;
    872 
    873 cvar_t	filterban = {"filterban", "1"};
    874 
    875 /*
    876 =================
    877 StringToFilter
    878 =================
    879 */
    880 qboolean StringToFilter (char *s, ipfilter_t *f)
    881 {
    882 	char	num[128];
    883 	int		i, j;
    884 	byte	b[4];
    885 	byte	m[4];
    886 
    887 	for (i=0 ; i<4 ; i++)
    888 	{
    889 		b[i] = 0;
    890 		m[i] = 0;
    891 	}
    892 
    893 	for (i=0 ; i<4 ; i++)
    894 	{
    895 		if (*s < '0' || *s > '9')
    896 		{
    897 			Con_Printf ("Bad filter address: %s\n", s);
    898 			return false;
    899 		}
    900 
    901 		j = 0;
    902 		while (*s >= '0' && *s <= '9')
    903 		{
    904 			num[j++] = *s++;
    905 		}
    906 		num[j] = 0;
    907 		b[i] = atoi(num);
    908 		if (b[i] != 0)
    909 			m[i] = 255;
    910 
    911 		if (!*s)
    912 			break;
    913 		s++;
    914 	}
    915 
    916 	f->mask = *(unsigned *)m;
    917 	f->compare = *(unsigned *)b;
    918 
    919 	return true;
    920 }
    921 
    922 /*
    923 =================
    924 SV_AddIP_f
    925 =================
    926 */
    927 void SV_AddIP_f (void)
    928 {
    929 	int		i;
    930 
    931 	for (i=0 ; i<numipfilters ; i++)
    932 		if (ipfilters[i].compare == 0xffffffff)
    933 			break;		// free spot
    934 	if (i == numipfilters)
    935 	{
    936 		if (numipfilters == MAX_IPFILTERS)
    937 		{
    938 			Con_Printf ("IP filter list is full\n");
    939 			return;
    940 		}
    941 		numipfilters++;
    942 	}
    943 
    944 	if (!StringToFilter (Cmd_Argv(1), &ipfilters[i]))
    945 		ipfilters[i].compare = 0xffffffff;
    946 }
    947 
    948 /*
    949 =================
    950 SV_RemoveIP_f
    951 =================
    952 */
    953 void SV_RemoveIP_f (void)
    954 {
    955 	ipfilter_t	f;
    956 	int			i, j;
    957 
    958 	if (!StringToFilter (Cmd_Argv(1), &f))
    959 		return;
    960 	for (i=0 ; i<numipfilters ; i++)
    961 		if (ipfilters[i].mask == f.mask
    962 		&& ipfilters[i].compare == f.compare)
    963 		{
    964 			for (j=i+1 ; j<numipfilters ; j++)
    965 				ipfilters[j-1] = ipfilters[j];
    966 			numipfilters--;
    967 			Con_Printf ("Removed.\n");
    968 			return;
    969 		}
    970 	Con_Printf ("Didn't find %s.\n", Cmd_Argv(1));
    971 }
    972 
    973 /*
    974 =================
    975 SV_ListIP_f
    976 =================
    977 */
    978 void SV_ListIP_f (void)
    979 {
    980 	int		i;
    981 	byte	b[4];
    982 
    983 	Con_Printf ("Filter list:\n");
    984 	for (i=0 ; i<numipfilters ; i++)
    985 	{
    986 		*(unsigned *)b = ipfilters[i].compare;
    987 		Con_Printf ("%3i.%3i.%3i.%3i\n", b[0], b[1], b[2], b[3]);
    988 	}
    989 }
    990 
    991 /*
    992 =================
    993 SV_WriteIP_f
    994 =================
    995 */
    996 void SV_WriteIP_f (void)
    997 {
    998 	FILE	*f;
    999 	char	name[MAX_OSPATH];
   1000 	byte	b[4];
   1001 	int		i;
   1002 
   1003 	sprintf (name, "%s/listip.cfg", com_gamedir);
   1004 
   1005 	Con_Printf ("Writing %s.\n", name);
   1006 
   1007 	f = fopen (name, "wb");
   1008 	if (!f)
   1009 	{
   1010 		Con_Printf ("Couldn't open %s\n", name);
   1011 		return;
   1012 	}
   1013 
   1014 	for (i=0 ; i<numipfilters ; i++)
   1015 	{
   1016 		*(unsigned *)b = ipfilters[i].compare;
   1017 		fprintf (f, "addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]);
   1018 	}
   1019 
   1020 	fclose (f);
   1021 }
   1022 
   1023 /*
   1024 =================
   1025 SV_SendBan
   1026 =================
   1027 */
   1028 void SV_SendBan (void)
   1029 {
   1030 	char		data[128];
   1031 
   1032 	data[0] = data[1] = data[2] = data[3] = 0xff;
   1033 	data[4] = A2C_PRINT;
   1034 	data[5] = 0;
   1035 	strcat (data, "\nbanned.\n");
   1036 
   1037 	NET_SendPacket (strlen(data), data, net_from);
   1038 }
   1039 
   1040 /*
   1041 =================
   1042 SV_FilterPacket
   1043 =================
   1044 */
   1045 qboolean SV_FilterPacket (void)
   1046 {
   1047 	int		i;
   1048 	unsigned	in;
   1049 
   1050 	in = *(unsigned *)net_from.ip;
   1051 
   1052 	for (i=0 ; i<numipfilters ; i++)
   1053 		if ( (in & ipfilters[i].mask) == ipfilters[i].compare)
   1054 			return filterban.value;
   1055 
   1056 	return !filterban.value;
   1057 }
   1058 
   1059 //============================================================================
   1060 
   1061 /*
   1062 =================
   1063 SV_ReadPackets
   1064 =================
   1065 */
   1066 void SV_ReadPackets (void)
   1067 {
   1068 	int			i;
   1069 	client_t	*cl;
   1070 	qboolean	good;
   1071 	int			qport;
   1072 
   1073 	good = false;
   1074 	while (NET_GetPacket ())
   1075 	{
   1076 		if (SV_FilterPacket ())
   1077 		{
   1078 			SV_SendBan ();	// tell them we aren't listening...
   1079 			continue;
   1080 		}
   1081 
   1082 		// check for connectionless packet (0xffffffff) first
   1083 		if (*(int *)net_message.data == -1)
   1084 		{
   1085 			SV_ConnectionlessPacket ();
   1086 			continue;
   1087 		}
   1088 
   1089 		// read the qport out of the message so we can fix up
   1090 		// stupid address translating routers
   1091 		MSG_BeginReading ();
   1092 		MSG_ReadLong ();		// sequence number
   1093 		MSG_ReadLong ();		// sequence number
   1094 		qport = MSG_ReadShort () & 0xffff;
   1095 
   1096 		// check for packets from connected clients
   1097 		for (i=0, cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
   1098 		{
   1099 			if (cl->state == cs_free)
   1100 				continue;
   1101 			if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
   1102 				continue;
   1103 			if (cl->netchan.qport != qport)
   1104 				continue;
   1105 			if (cl->netchan.remote_address.port != net_from.port)
   1106 			{
   1107 				Con_DPrintf ("SV_ReadPackets: fixing up a translated port\n");
   1108 				cl->netchan.remote_address.port = net_from.port;
   1109 			}
   1110 			if (Netchan_Process(&cl->netchan))
   1111 			{	// this is a valid, sequenced packet, so process it
   1112 				svs.stats.packets++;
   1113 				good = true;
   1114 				cl->send_message = true;	// reply at end of frame
   1115 				if (cl->state != cs_zombie)
   1116 					SV_ExecuteClientMessage (cl);
   1117 			}
   1118 			break;
   1119 		}
   1120 
   1121 		if (i != MAX_CLIENTS)
   1122 			continue;
   1123 
   1124 		// packet is not from a known client
   1125 		//	Con_Printf ("%s:sequenced packet without connection\n"
   1126 		// ,NET_AdrToString(net_from));
   1127 	}
   1128 }
   1129 
   1130 /*
   1131 ==================
   1132 SV_CheckTimeouts
   1133 
   1134 If a packet has not been received from a client in timeout.value
   1135 seconds, drop the conneciton.
   1136 
   1137 When a client is normally dropped, the client_t goes into a zombie state
   1138 for a few seconds to make sure any final reliable message gets resent
   1139 if necessary
   1140 ==================
   1141 */
   1142 void SV_CheckTimeouts (void)
   1143 {
   1144 	int		i;
   1145 	client_t	*cl;
   1146 	float	droptime;
   1147 	int	nclients;
   1148 
   1149 	droptime = realtime - timeout.value;
   1150 	nclients = 0;
   1151 
   1152 	for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
   1153 	{
   1154 		if (cl->state == cs_connected || cl->state == cs_spawned) {
   1155 			if (!cl->spectator)
   1156 				nclients++;
   1157 			if (cl->netchan.last_received < droptime) {
   1158 				SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
   1159 				SV_DropClient (cl);
   1160 				cl->state = cs_free;	// don't bother with zombie state
   1161 			}
   1162 		}
   1163 		if (cl->state == cs_zombie &&
   1164 			realtime - cl->connection_started > zombietime.value)
   1165 		{
   1166 			cl->state = cs_free;	// can now be reused
   1167 		}
   1168 	}
   1169 	if (sv.paused && !nclients) {
   1170 		// nobody left, unpause the server
   1171 		SV_TogglePause("Pause released since no players are left.\n");
   1172 	}
   1173 }
   1174 
   1175 /*
   1176 ===================
   1177 SV_GetConsoleCommands
   1178 
   1179 Add them exactly as if they had been typed at the console
   1180 ===================
   1181 */
   1182 void SV_GetConsoleCommands (void)
   1183 {
   1184 	char	*cmd;
   1185 
   1186 	while (1)
   1187 	{
   1188 		cmd = Sys_ConsoleInput ();
   1189 		if (!cmd)
   1190 			break;
   1191 		Cbuf_AddText (cmd);
   1192 	}
   1193 }
   1194 
   1195 /*
   1196 ===================
   1197 SV_CheckVars
   1198 
   1199 ===================
   1200 */
   1201 void SV_CheckVars (void)
   1202 {
   1203 	static char *pw, *spw;
   1204 	int			v;
   1205 
   1206 	if (password.string == pw && spectator_password.string == spw)
   1207 		return;
   1208 	pw = password.string;
   1209 	spw = spectator_password.string;
   1210 
   1211 	v = 0;
   1212 	if (pw && pw[0] && strcmp(pw, "none"))
   1213 		v |= 1;
   1214 	if (spw && spw[0] && strcmp(spw, "none"))
   1215 		v |= 2;
   1216 
   1217 	Con_Printf ("Updated needpass.\n");
   1218 	if (!v)
   1219 		Info_SetValueForKey (svs.info, "needpass", "", MAX_SERVERINFO_STRING);
   1220 	else
   1221 		Info_SetValueForKey (svs.info, "needpass", va("%i",v), MAX_SERVERINFO_STRING);
   1222 }
   1223 
   1224 /*
   1225 ==================
   1226 SV_Frame
   1227 
   1228 ==================
   1229 */
   1230 void SV_Frame (float time)
   1231 {
   1232 	static double	start, end;
   1233 
   1234 	start = Sys_DoubleTime ();
   1235 	svs.stats.idle += start - end;
   1236 
   1237 // keep the random time dependent
   1238 	rand ();
   1239 
   1240 // decide the simulation time
   1241 	if (!sv.paused) {
   1242 		realtime += time;
   1243 		sv.time += time;
   1244 	}
   1245 
   1246 // check timeouts
   1247 	SV_CheckTimeouts ();
   1248 
   1249 // toggle the log buffer if full
   1250 	SV_CheckLog ();
   1251 
   1252 // move autonomous things around if enough time has passed
   1253 	if (!sv.paused)
   1254 		SV_Physics ();
   1255 
   1256 // get packets
   1257 	SV_ReadPackets ();
   1258 
   1259 // check for commands typed to the host
   1260 	SV_GetConsoleCommands ();
   1261 
   1262 // process console commands
   1263 	Cbuf_Execute ();
   1264 
   1265 	SV_CheckVars ();
   1266 
   1267 // send messages back to the clients that had packets read this frame
   1268 	SV_SendClientMessages ();
   1269 
   1270 // send a heartbeat to the master if needed
   1271 	Master_Heartbeat ();
   1272 
   1273 // collect timing statistics
   1274 	end = Sys_DoubleTime ();
   1275 	svs.stats.active += end-start;
   1276 	if (++svs.stats.count == STATFRAMES)
   1277 	{
   1278 		svs.stats.latched_active = svs.stats.active;
   1279 		svs.stats.latched_idle = svs.stats.idle;
   1280 		svs.stats.latched_packets = svs.stats.packets;
   1281 		svs.stats.active = 0;
   1282 		svs.stats.idle = 0;
   1283 		svs.stats.packets = 0;
   1284 		svs.stats.count = 0;
   1285 	}
   1286 }
   1287 
   1288 /*
   1289 ===============
   1290 SV_InitLocal
   1291 ===============
   1292 */
   1293 void SV_InitLocal (void)
   1294 {
   1295 	int		i;
   1296 	extern	cvar_t	sv_maxvelocity;
   1297 	extern	cvar_t	sv_gravity;
   1298 	extern	cvar_t	sv_aim;
   1299 	extern	cvar_t	sv_stopspeed;
   1300 	extern	cvar_t	sv_spectatormaxspeed;
   1301 	extern	cvar_t	sv_accelerate;
   1302 	extern	cvar_t	sv_airaccelerate;
   1303 	extern	cvar_t	sv_wateraccelerate;
   1304 	extern	cvar_t	sv_friction;
   1305 	extern	cvar_t	sv_waterfriction;
   1306 
   1307 	SV_InitOperatorCommands	();
   1308 	SV_UserInit ();
   1309 
   1310 	Cvar_RegisterVariable (&rcon_password);
   1311 	Cvar_RegisterVariable (&password);
   1312 	Cvar_RegisterVariable (&spectator_password);
   1313 
   1314 	Cvar_RegisterVariable (&sv_mintic);
   1315 	Cvar_RegisterVariable (&sv_maxtic);
   1316 
   1317 	Cvar_RegisterVariable (&fraglimit);
   1318 	Cvar_RegisterVariable (&timelimit);
   1319 	Cvar_RegisterVariable (&teamplay);
   1320 	Cvar_RegisterVariable (&samelevel);
   1321 	Cvar_RegisterVariable (&maxclients);
   1322 	Cvar_RegisterVariable (&maxspectators);
   1323 	Cvar_RegisterVariable (&hostname);
   1324 	Cvar_RegisterVariable (&deathmatch);
   1325 	Cvar_RegisterVariable (&spawn);
   1326 	Cvar_RegisterVariable (&watervis);
   1327 
   1328 	Cvar_RegisterVariable (&developer);
   1329 
   1330 	Cvar_RegisterVariable (&timeout);
   1331 	Cvar_RegisterVariable (&zombietime);
   1332 
   1333 	Cvar_RegisterVariable (&sv_maxvelocity);
   1334 	Cvar_RegisterVariable (&sv_gravity);
   1335 	Cvar_RegisterVariable (&sv_stopspeed);
   1336 	Cvar_RegisterVariable (&sv_maxspeed);
   1337 	Cvar_RegisterVariable (&sv_spectatormaxspeed);
   1338 	Cvar_RegisterVariable (&sv_accelerate);
   1339 	Cvar_RegisterVariable (&sv_airaccelerate);
   1340 	Cvar_RegisterVariable (&sv_wateraccelerate);
   1341 	Cvar_RegisterVariable (&sv_friction);
   1342 	Cvar_RegisterVariable (&sv_waterfriction);
   1343 
   1344 	Cvar_RegisterVariable (&sv_aim);
   1345 
   1346 	Cvar_RegisterVariable (&filterban);
   1347 
   1348 	Cvar_RegisterVariable (&allow_download);
   1349 	Cvar_RegisterVariable (&allow_download_skins);
   1350 	Cvar_RegisterVariable (&allow_download_models);
   1351 	Cvar_RegisterVariable (&allow_download_sounds);
   1352 	Cvar_RegisterVariable (&allow_download_maps);
   1353 
   1354 	Cvar_RegisterVariable (&sv_highchars);
   1355 
   1356 	Cvar_RegisterVariable (&sv_phs);
   1357 
   1358 	Cvar_RegisterVariable (&pausable);
   1359 
   1360 	Cmd_AddCommand ("addip", SV_AddIP_f);
   1361 	Cmd_AddCommand ("removeip", SV_RemoveIP_f);
   1362 	Cmd_AddCommand ("listip", SV_ListIP_f);
   1363 	Cmd_AddCommand ("writeip", SV_WriteIP_f);
   1364 
   1365 	for (i=0 ; i<MAX_MODELS ; i++)
   1366 		sprintf (localmodels[i], "*%i", i);
   1367 
   1368 	Info_SetValueForStarKey (svs.info, "*version", va("%4.2f", VERSION), MAX_SERVERINFO_STRING);
   1369 
   1370 	// init fraglog stuff
   1371 	svs.logsequence = 1;
   1372 	svs.logtime = realtime;
   1373 	svs.log[0].data = svs.log_buf[0];
   1374 	svs.log[0].maxsize = sizeof(svs.log_buf[0]);
   1375 	svs.log[0].cursize = 0;
   1376 	svs.log[0].allowoverflow = true;
   1377 	svs.log[1].data = svs.log_buf[1];
   1378 	svs.log[1].maxsize = sizeof(svs.log_buf[1]);
   1379 	svs.log[1].cursize = 0;
   1380 	svs.log[1].allowoverflow = true;
   1381 }
   1382 
   1383 
   1384 //============================================================================
   1385 
   1386 /*
   1387 ================
   1388 Master_Heartbeat
   1389 
   1390 Send a message to the master every few minutes to
   1391 let it know we are alive, and log information
   1392 ================
   1393 */
   1394 #define	HEARTBEAT_SECONDS	300
   1395 void Master_Heartbeat (void)
   1396 {
   1397 	char		string[2048];
   1398 	int			active;
   1399 	int			i;
   1400 
   1401 	if (realtime - svs.last_heartbeat < HEARTBEAT_SECONDS)
   1402 		return;		// not time to send yet
   1403 
   1404 	svs.last_heartbeat = realtime;
   1405 
   1406 	//
   1407 	// count active users
   1408 	//
   1409 	active = 0;
   1410 	for (i=0 ; i<MAX_CLIENTS ; i++)
   1411 		if (svs.clients[i].state == cs_connected ||
   1412 		svs.clients[i].state == cs_spawned )
   1413 			active++;
   1414 
   1415 	svs.heartbeat_sequence++;
   1416 	sprintf (string, "%c\n%i\n%i\n", S2M_HEARTBEAT,
   1417 		svs.heartbeat_sequence, active);
   1418 
   1419 
   1420 	// send to group master
   1421 	for (i=0 ; i<MAX_MASTERS ; i++)
   1422 		if (master_adr[i].port)
   1423 		{
   1424 			Con_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
   1425 			NET_SendPacket (strlen(string), string, master_adr[i]);
   1426 		}
   1427 }
   1428 
   1429 /*
   1430 =================
   1431 Master_Shutdown
   1432 
   1433 Informs all masters that this server is going down
   1434 =================
   1435 */
   1436 void Master_Shutdown (void)
   1437 {
   1438 	char		string[2048];
   1439 	int			i;
   1440 
   1441 	sprintf (string, "%c\n", S2M_SHUTDOWN);
   1442 
   1443 	// send to group master
   1444 	for (i=0 ; i<MAX_MASTERS ; i++)
   1445 		if (master_adr[i].port)
   1446 		{
   1447 			Con_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
   1448 			NET_SendPacket (strlen(string), string, master_adr[i]);
   1449 		}
   1450 }
   1451 
   1452 /*
   1453 =================
   1454 SV_ExtractFromUserinfo
   1455 
   1456 Pull specific info from a newly changed userinfo string
   1457 into a more C freindly form.
   1458 =================
   1459 */
   1460 void SV_ExtractFromUserinfo (client_t *cl)
   1461 {
   1462 	char	*val, *p, *q;
   1463 	int		i;
   1464 	client_t	*client;
   1465 	int		dupc = 1;
   1466 	char	newname[80];
   1467 
   1468 
   1469 	// name for C code
   1470 	val = Info_ValueForKey (cl->userinfo, "name");
   1471 
   1472 	// trim user name
   1473 	strncpy(newname, val, sizeof(newname) - 1);
   1474 	newname[sizeof(newname) - 1] = 0;
   1475 
   1476 	for (p = newname; (*p == ' ' || *p == '\r' || *p == '\n') && *p; p++)
   1477 		;
   1478 
   1479 	if (p != newname && !*p) {
   1480 		//white space only
   1481 		strcpy(newname, "unnamed");
   1482 		p = newname;
   1483 	}
   1484 
   1485 	if (p != newname && *p) {
   1486 		for (q = newname; *p; *q++ = *p++)
   1487 			;
   1488 		*q = 0;
   1489 	}
   1490 	for (p = newname + strlen(newname) - 1; p != newname && (*p == ' ' || *p == '\r' || *p == '\n') ; p--)
   1491 		;
   1492 	p[1] = 0;
   1493 
   1494 	if (strcmp(val, newname)) {
   1495 		Info_SetValueForKey (cl->userinfo, "name", newname, MAX_INFO_STRING);
   1496 		val = Info_ValueForKey (cl->userinfo, "name");
   1497 	}
   1498 
   1499 	if (!val[0] || !stricmp(val, "console")) {
   1500 		Info_SetValueForKey (cl->userinfo, "name", "unnamed", MAX_INFO_STRING);
   1501 		val = Info_ValueForKey (cl->userinfo, "name");
   1502 	}
   1503 
   1504 	// check to see if another user by the same name exists
   1505 	while (1) {
   1506 		for (i=0, client = svs.clients ; i<MAX_CLIENTS ; i++, client++) {
   1507 			if (client->state != cs_spawned || client == cl)
   1508 				continue;
   1509 			if (!stricmp(client->name, val))
   1510 				break;
   1511 		}
   1512 		if (i != MAX_CLIENTS) { // dup name
   1513 			if (strlen(val) > sizeof(cl->name) - 1)
   1514 				val[sizeof(cl->name) - 4] = 0;
   1515 			p = val;
   1516 
   1517 			if (val[0] == '(')
   1518 				if (val[2] == ')')
   1519 					p = val + 3;
   1520 				else if (val[3] == ')')
   1521 					p = val + 4;
   1522 
   1523 			sprintf(newname, "(%d)%-.40s", dupc++, p);
   1524 			Info_SetValueForKey (cl->userinfo, "name", newname, MAX_INFO_STRING);
   1525 			val = Info_ValueForKey (cl->userinfo, "name");
   1526 		} else
   1527 			break;
   1528 	}
   1529 
   1530 	if (strncmp(val, cl->name, strlen(cl->name))) {
   1531 		if (!sv.paused) {
   1532 			if (!cl->lastnametime || realtime - cl->lastnametime > 5) {
   1533 				cl->lastnamecount = 0;
   1534 				cl->lastnametime = realtime;
   1535 			} else if (cl->lastnamecount++ > 4) {
   1536 				SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked for name spam\n", cl->name);
   1537 				SV_ClientPrintf (cl, PRINT_HIGH, "You were kicked from the game for name spamming\n");
   1538 				SV_DropClient (cl);
   1539 				return;
   1540 			}
   1541 		}
   1542 
   1543 		if (cl->state >= cs_spawned && !cl->spectator)
   1544 			SV_BroadcastPrintf (PRINT_HIGH, "%s changed name to %s\n", cl->name, val);
   1545 	}
   1546 
   1547 
   1548 	strncpy (cl->name, val, sizeof(cl->name)-1);
   1549 
   1550 	// rate command
   1551 	val = Info_ValueForKey (cl->userinfo, "rate");
   1552 	if (strlen(val))
   1553 	{
   1554 		i = atoi(val);
   1555 		if (i < 500)
   1556 			i = 500;
   1557 		if (i > 10000)
   1558 			i = 10000;
   1559 		cl->netchan.rate = 1.0/i;
   1560 	}
   1561 
   1562 	// msg command
   1563 	val = Info_ValueForKey (cl->userinfo, "msg");
   1564 	if (strlen(val))
   1565 	{
   1566 		cl->messagelevel = atoi(val);
   1567 	}
   1568 
   1569 }
   1570 
   1571 
   1572 //============================================================================
   1573 
   1574 /*
   1575 ====================
   1576 SV_InitNet
   1577 ====================
   1578 */
   1579 void SV_InitNet (void)
   1580 {
   1581 	int	port;
   1582 	int	p;
   1583 
   1584 	port = PORT_SERVER;
   1585 	p = COM_CheckParm ("-port");
   1586 	if (p && p < com_argc)
   1587 	{
   1588 		port = atoi(com_argv[p+1]);
   1589 		Con_Printf ("Port: %i\n", port);
   1590 	}
   1591 	NET_Init (port);
   1592 
   1593 	Netchan_Init ();
   1594 
   1595 	// heartbeats will allways be sent to the id master
   1596 	svs.last_heartbeat = -99999;		// send immediately
   1597 //	NET_StringToAdr ("192.246.40.70:27000", &idmaster_adr);
   1598 }
   1599 
   1600 
   1601 /*
   1602 ====================
   1603 SV_Init
   1604 ====================
   1605 */
   1606 void SV_Init (quakeparms_t *parms)
   1607 {
   1608 	COM_InitArgv (parms->argc, parms->argv);
   1609 	COM_AddParm ("-game");
   1610 	COM_AddParm ("qw");
   1611 
   1612 	if (COM_CheckParm ("-minmemory"))
   1613 		parms->memsize = MINIMUM_MEMORY;
   1614 
   1615 	host_parms = *parms;
   1616 
   1617 	if (parms->memsize < MINIMUM_MEMORY)
   1618 		SV_Error ("Only %4.1f megs of memory reported, can't execute game", parms->memsize / (float)0x100000);
   1619 
   1620 	Memory_Init (parms->membase, parms->memsize);
   1621 	Cbuf_Init ();
   1622 	Cmd_Init ();
   1623 
   1624 	COM_Init ();
   1625 
   1626 	PR_Init ();
   1627 	Mod_Init ();
   1628 
   1629 	SV_InitNet ();
   1630 
   1631 	SV_InitLocal ();
   1632 	Sys_Init ();
   1633 	Pmove_Init ();
   1634 
   1635 	Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
   1636 	host_hunklevel = Hunk_LowMark ();
   1637 
   1638 	Cbuf_InsertText ("exec server.cfg\n");
   1639 
   1640 	host_initialized = true;
   1641 
   1642 	Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
   1643 	Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0));
   1644 
   1645 	Con_Printf ("\nServer Version %4.2f (Build %04d)\n\n", VERSION, build_number());
   1646 
   1647 	Con_Printf ("======== QuakeWorld Initialized ========\n");
   1648 
   1649 // process command line arguments
   1650 	Cmd_StuffCmds_f ();
   1651 	Cbuf_Execute ();
   1652 
   1653 // if a map wasn't specified on the command line, spawn start.map
   1654 	if (sv.state == ss_dead)
   1655 		Cmd_ExecuteString ("map start");
   1656 	if (sv.state == ss_dead)
   1657 		SV_Error ("Couldn't spawn a server");
   1658 }
   1659