1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 
23 #include "server.h"
24 
25 #if USE_VOIP
26 cvar_t *sv_voip;
27 #endif
28 
29 serverStatic_t	svs;				// persistant server info
30 server_t		sv;					// local server
31 vm_t			*gvm = NULL;				// game virtual machine
32 
33 cvar_t	*sv_fps;				// time rate for running non-clients
34 cvar_t	*sv_timeout;			// seconds without any message
35 cvar_t	*sv_zombietime;			// seconds to sink messages after disconnect
36 cvar_t	*sv_rconPassword;		// password for remote server commands
37 cvar_t	*sv_privatePassword;	// password for the privateClient slots
38 cvar_t	*sv_allowDownload;
39 cvar_t	*sv_maxclients;
40 
41 cvar_t	*sv_privateClients;		// number of clients reserved for password
42 cvar_t	*sv_hostname;
43 cvar_t	*sv_master[MAX_MASTER_SERVERS];		// master server ip address
44 cvar_t	*sv_reconnectlimit;		// minimum seconds between connect messages
45 cvar_t	*sv_showloss;			// report when usercmds are lost
46 cvar_t	*sv_padPackets;			// add nop bytes to messages
47 cvar_t	*sv_killserver;			// menu system can set to 1 to shut server down
48 cvar_t	*sv_mapname;
49 cvar_t	*sv_mapChecksum;
50 cvar_t	*sv_serverid;
51 cvar_t	*sv_minRate;
52 cvar_t	*sv_maxRate;
53 cvar_t	*sv_minPing;
54 cvar_t	*sv_maxPing;
55 cvar_t	*sv_gametype;
56 cvar_t	*sv_pure;
57 cvar_t	*sv_floodProtect;
58 cvar_t	*sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491)
59 cvar_t	*sv_strictAuth;
60 
61 serverBan_t serverBans[SERVER_MAXBANS];
62 int serverBansCount = 0;
63 
64 /*
65 =============================================================================
66 
67 EVENT MESSAGES
68 
69 =============================================================================
70 */
71 
72 /*
73 ===============
74 SV_ExpandNewlines
75 
76 Converts newlines to "\n" so a line prints nicer
77 ===============
78 */
SV_ExpandNewlines(char * in)79 char	*SV_ExpandNewlines( char *in ) {
80 	static	char	string[1024];
81 	int		l;
82 
83 	l = 0;
84 	while ( *in && l < sizeof(string) - 3 ) {
85 		if ( *in == '\n' ) {
86 			string[l++] = '\\';
87 			string[l++] = 'n';
88 		} else {
89 			string[l++] = *in;
90 		}
91 		in++;
92 	}
93 	string[l] = 0;
94 
95 	return string;
96 }
97 
98 /*
99 ======================
100 SV_ReplacePendingServerCommands
101 
102   This is ugly
103 ======================
104 */
SV_ReplacePendingServerCommands(client_t * client,const char * cmd)105 int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) {
106 	int i, index, csnum1, csnum2;
107 
108 	for ( i = client->reliableSent+1; i <= client->reliableSequence; i++ ) {
109 		index = i & ( MAX_RELIABLE_COMMANDS - 1 );
110 		//
111 		if ( !Q_strncmp(cmd, client->reliableCommands[ index ], strlen("cs")) ) {
112 			sscanf(cmd, "cs %i", &csnum1);
113 			sscanf(client->reliableCommands[ index ], "cs %i", &csnum2);
114 			if ( csnum1 == csnum2 ) {
115 				Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
116 				/*
117 				if ( client->netchan.remoteAddress.type != NA_BOT ) {
118 					Com_Printf( "WARNING: client %i removed double pending config string %i: %s\n", client-svs.clients, csnum1, cmd );
119 				}
120 				*/
121 				return qtrue;
122 			}
123 		}
124 	}
125 	return qfalse;
126 }
127 
128 /*
129 ======================
130 SV_AddServerCommand
131 
132 The given command will be transmitted to the client, and is guaranteed to
133 not have future snapshot_t executed before it is executed
134 ======================
135 */
SV_AddServerCommand(client_t * client,const char * cmd)136 void SV_AddServerCommand( client_t *client, const char *cmd ) {
137 	int		index, i;
138 
139 	// this is very ugly but it's also a waste to for instance send multiple config string updates
140 	// for the same config string index in one snapshot
141 //	if ( SV_ReplacePendingServerCommands( client, cmd ) ) {
142 //		return;
143 //	}
144 
145 	// do not send commands until the gamestate has been sent
146 	if( client->state < CS_PRIMED )
147 		return;
148 
149 	client->reliableSequence++;
150 	// if we would be losing an old command that hasn't been acknowledged,
151 	// we must drop the connection
152 	// we check == instead of >= so a broadcast print added by SV_DropClient()
153 	// doesn't cause a recursive drop client
154 	if ( client->reliableSequence - client->reliableAcknowledge == MAX_RELIABLE_COMMANDS + 1 ) {
155 		Com_Printf( "===== pending server commands =====\n" );
156 		for ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {
157 			Com_Printf( "cmd %5d: %s\n", i, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
158 		}
159 		Com_Printf( "cmd %5d: %s\n", i, cmd );
160 		SV_DropClient( client, "Server command overflow" );
161 		return;
162 	}
163 	index = client->reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
164 	Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
165 }
166 
167 
168 /*
169 =================
170 SV_SendServerCommand
171 
172 Sends a reliable command string to be interpreted by
173 the client game module: "cp", "print", "chat", etc
174 A NULL client will broadcast to all clients
175 =================
176 */
SV_SendServerCommand(client_t * cl,const char * fmt,...)177 void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
178 	va_list		argptr;
179 	byte		message[MAX_MSGLEN];
180 	client_t	*client;
181 	int			j;
182 
183 	va_start (argptr,fmt);
184 	Q_vsnprintf ((char *)message, sizeof(message), fmt,argptr);
185 	va_end (argptr);
186 
187 	// Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt
188 	// The actual cause of the bug is probably further downstream
189 	// and should maybe be addressed later, but this certainly
190 	// fixes the problem for now
191 	if ( strlen ((char *)message) > 1022 ) {
192 		return;
193 	}
194 
195 	if ( cl != NULL ) {
196 		SV_AddServerCommand( cl, (char *)message );
197 		return;
198 	}
199 
200 	// hack to echo broadcast prints to console
201 	if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) {
202 		Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) );
203 	}
204 
205 	// send the data to all relevent clients
206 	for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) {
207 		SV_AddServerCommand( client, (char *)message );
208 	}
209 }
210 
211 
212 /*
213 ==============================================================================
214 
215 MASTER SERVER FUNCTIONS
216 
217 ==============================================================================
218 */
219 
220 /*
221 ================
222 SV_MasterHeartbeat
223 
224 Send a message to the masters every few minutes to
225 let it know we are alive, and log information.
226 We will also have a heartbeat sent when a server
227 changes from empty to non-empty, and full to non-full,
228 but not on every player enter or exit.
229 ================
230 */
231 #define	HEARTBEAT_MSEC	300*1000
232 #define	HEARTBEAT_GAME	"QuakeArena-1"
SV_MasterHeartbeat(void)233 void SV_MasterHeartbeat( void ) {
234 	static netadr_t	adr[MAX_MASTER_SERVERS];
235 	int			i;
236 
237 	// "dedicated 1" is for lan play, "dedicated 2" is for inet public play
238 	if ( !com_dedicated || com_dedicated->integer != 2 ) {
239 		return;		// only dedicated servers send heartbeats
240 	}
241 
242 	// if not time yet, don't send anything
243 	if ( svs.time < svs.nextHeartbeatTime ) {
244 		return;
245 	}
246 	svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC;
247 
248 
249 	// send to group masters
250 	for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) {
251 		if ( !sv_master[i]->string[0] ) {
252 			continue;
253 		}
254 
255 		// see if we haven't already resolved the name
256 		// resolving usually causes hitches on win95, so only
257 		// do it when needed
258 		if ( sv_master[i]->modified ) {
259 			sv_master[i]->modified = qfalse;
260 
261 			Com_Printf( "Resolving %s\n", sv_master[i]->string );
262 			if ( !NET_StringToAdr( sv_master[i]->string, &adr[i], NA_UNSPEC ) ) {
263 				// if the address failed to resolve, clear it
264 				// so we don't take repeated dns hits
265 				Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string );
266 				Cvar_Set( sv_master[i]->name, "" );
267 				sv_master[i]->modified = qfalse;
268 				continue;
269 			}
270 			if ( !strchr( sv_master[i]->string, ':' ) ) {
271 				adr[i].port = BigShort( PORT_MASTER );
272 			}
273 			Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i]));
274 		}
275 
276 
277 		Com_Printf ("Sending heartbeat to %s\n", sv_master[i]->string );
278 		// this command should be changed if the server info / status format
279 		// ever incompatably changes
280 		NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", HEARTBEAT_GAME );
281 	}
282 }
283 
284 /*
285 =================
286 SV_MasterShutdown
287 
288 Informs all masters that this server is going down
289 =================
290 */
SV_MasterShutdown(void)291 void SV_MasterShutdown( void ) {
292 	// send a hearbeat right now
293 	svs.nextHeartbeatTime = -9999;
294 	SV_MasterHeartbeat();
295 
296 	// send it again to minimize chance of drops
297 	svs.nextHeartbeatTime = -9999;
298 	SV_MasterHeartbeat();
299 
300 	// when the master tries to poll the server, it won't respond, so
301 	// it will be removed from the list
302 }
303 
304 
305 /*
306 ==============================================================================
307 
308 CONNECTIONLESS COMMANDS
309 
310 ==============================================================================
311 */
312 
313 /*
314 ================
315 SVC_Status
316 
317 Responds with all the info that qplug or qspy can see about the server
318 and all connected players.  Used for getting detailed information after
319 the simple info query.
320 ================
321 */
SVC_Status(netadr_t from)322 void SVC_Status( netadr_t from ) {
323 	char	player[1024];
324 	char	status[MAX_MSGLEN];
325 	int		i;
326 	client_t	*cl;
327 	playerState_t	*ps;
328 	int		statusLength;
329 	int		playerLength;
330 	char	infostring[MAX_INFO_STRING];
331 
332 	// ignore if we are in single player
333 	if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) {
334 		return;
335 	}
336 
337 	strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) );
338 
339 	// echo back the parameter to status. so master servers can use it as a challenge
340 	// to prevent timed spoofed reply packets that add ghost servers
341 	Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
342 
343 	status[0] = 0;
344 	statusLength = 0;
345 
346 	for (i=0 ; i < sv_maxclients->integer ; i++) {
347 		cl = &svs.clients[i];
348 		if ( cl->state >= CS_CONNECTED ) {
349 			ps = SV_GameClientNum( i );
350 			Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n",
351 				ps->persistant[PERS_SCORE], cl->ping, cl->name);
352 			playerLength = strlen(player);
353 			if (statusLength + playerLength >= sizeof(status) ) {
354 				break;		// can't hold any more
355 			}
356 			strcpy (status + statusLength, player);
357 			statusLength += playerLength;
358 		}
359 	}
360 
361 	NET_OutOfBandPrint( NS_SERVER, from, "statusResponse\n%s\n%s", infostring, status );
362 }
363 
364 /*
365 ================
366 SVC_Info
367 
368 Responds with a short info message that should be enough to determine
369 if a user is interested in a server to do a full status
370 ================
371 */
SVC_Info(netadr_t from)372 void SVC_Info( netadr_t from ) {
373 	int		i, count;
374 	char	*gamedir;
375 	char	infostring[MAX_INFO_STRING];
376 
377 	// ignore if we are in single player
378 	if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) {
379 		return;
380 	}
381 
382 	/*
383 	 * Check whether Cmd_Argv(1) has a sane length. This was not done in the original Quake3 version which led
384 	 * to the Infostring bug discovered by Luigi Auriemma. See http://aluigi.altervista.org/ for the advisory.
385 	 */
386 
387 	// A maximum challenge length of 128 should be more than plenty.
388 	if(strlen(Cmd_Argv(1)) > 128)
389 		return;
390 
391 	// don't count privateclients
392 	count = 0;
393 	for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) {
394 		if ( svs.clients[i].state >= CS_CONNECTED ) {
395 			count++;
396 		}
397 	}
398 
399 	infostring[0] = 0;
400 
401 	// echo back the parameter to status. so servers can use it as a challenge
402 	// to prevent timed spoofed reply packets that add ghost servers
403 	Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
404 
405 	Info_SetValueForKey( infostring, "protocol", va("%i", PROTOCOL_VERSION) );
406 	Info_SetValueForKey( infostring, "hostname", sv_hostname->string );
407 	Info_SetValueForKey( infostring, "mapname", sv_mapname->string );
408 	Info_SetValueForKey( infostring, "clients", va("%i", count) );
409 	Info_SetValueForKey( infostring, "sv_maxclients",
410 		va("%i", sv_maxclients->integer - sv_privateClients->integer ) );
411 	Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) );
412 	Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) );
413 
414 #if USE_VOIP
415 	if (sv_voip->integer) {
416 		Info_SetValueForKey( infostring, "voip", va("%i", sv_voip->integer ) );
417 	}
418 #endif
419 
420 	if( sv_minPing->integer ) {
421 		Info_SetValueForKey( infostring, "minPing", va("%i", sv_minPing->integer) );
422 	}
423 	if( sv_maxPing->integer ) {
424 		Info_SetValueForKey( infostring, "maxPing", va("%i", sv_maxPing->integer) );
425 	}
426 	gamedir = Cvar_VariableString( "fs_game" );
427 	if( *gamedir ) {
428 		Info_SetValueForKey( infostring, "game", gamedir );
429 	}
430 
431 	NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
432 }
433 
434 /*
435 ================
436 SVC_FlushRedirect
437 
438 ================
439 */
SV_FlushRedirect(char * outputbuf)440 void SV_FlushRedirect( char *outputbuf ) {
441 	NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf );
442 }
443 
444 /*
445 ===============
446 SVC_RemoteCommand
447 
448 An rcon packet arrived from the network.
449 Shift down the remaining args
450 Redirect all printfs
451 ===============
452 */
SVC_RemoteCommand(netadr_t from,msg_t * msg)453 void SVC_RemoteCommand( netadr_t from, msg_t *msg ) {
454 	qboolean	valid;
455 	unsigned int time;
456 	char		remaining[1024];
457 	// TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc.
458 	// (OOB messages are the bottleneck here)
459 #define SV_OUTPUTBUF_LENGTH (1024 - 16)
460 	char		sv_outputbuf[SV_OUTPUTBUF_LENGTH];
461 	static unsigned int lasttime = 0;
462 	char *cmd_aux;
463 
464 	// TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534
465 	time = Com_Milliseconds();
466 	if ( (unsigned)( time - lasttime ) < 500u ) {
467 		return;
468 	}
469 	lasttime = time;
470 
471 	if ( !strlen( sv_rconPassword->string ) ||
472 		strcmp (Cmd_Argv(1), sv_rconPassword->string) ) {
473 		valid = qfalse;
474 		Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) );
475 	} else {
476 		valid = qtrue;
477 		Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) );
478 	}
479 
480 	// start redirecting all print outputs to the packet
481 	svs.redirectAddress = from;
482 	Com_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
483 
484 	if ( !strlen( sv_rconPassword->string ) ) {
485 		Com_Printf ("No rconpassword set on the server.\n");
486 	} else if ( !valid ) {
487 		Com_Printf ("Bad rconpassword.\n");
488 	} else {
489 		remaining[0] = 0;
490 
491 		// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
492 		// get the command directly, "rcon <pass> <command>" to avoid quoting issues
493 		// extract the command by walking
494 		// since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing
495 		cmd_aux = Cmd_Cmd();
496 		cmd_aux+=4;
497 		while(cmd_aux[0]==' ')
498 			cmd_aux++;
499 		while(cmd_aux[0] && cmd_aux[0]!=' ') // password
500 			cmd_aux++;
501 		while(cmd_aux[0]==' ')
502 			cmd_aux++;
503 
504 		Q_strcat( remaining, sizeof(remaining), cmd_aux);
505 
506 		Cmd_ExecuteString (remaining);
507 
508 	}
509 
510 	Com_EndRedirect ();
511 }
512 
513 /*
514 =================
515 SV_ConnectionlessPacket
516 
517 A connectionless packet has four leading 0xff
518 characters to distinguish it from a game channel.
519 Clients that are in the game can still send
520 connectionless packets.
521 =================
522 */
SV_ConnectionlessPacket(netadr_t from,msg_t * msg)523 void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
524 	char	*s;
525 	char	*c;
526 
527 	MSG_BeginReadingOOB( msg );
528 	MSG_ReadLong( msg );		// skip the -1 marker
529 
530 	if (!Q_strncmp("connect", (char *) &msg->data[4], 7)) {
531 		Huff_Decompress(msg, 12);
532 	}
533 
534 	s = MSG_ReadStringLine( msg );
535 	Cmd_TokenizeString( s );
536 
537 	c = Cmd_Argv(0);
538 	Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c);
539 
540 	if (!Q_stricmp(c, "getstatus")) {
541 		SVC_Status( from  );
542   } else if (!Q_stricmp(c, "getinfo")) {
543 		SVC_Info( from );
544 	} else if (!Q_stricmp(c, "getchallenge")) {
545 		SV_GetChallenge( from );
546 	} else if (!Q_stricmp(c, "connect")) {
547 		SV_DirectConnect( from );
548 #ifndef STANDALONE
549 	} else if (!Q_stricmp(c, "ipAuthorize")) {
550 		SV_AuthorizeIpPacket( from );
551 #endif
552 	} else if (!Q_stricmp(c, "rcon")) {
553 		SVC_RemoteCommand( from, msg );
554 	} else if (!Q_stricmp(c, "disconnect")) {
555 		// if a client starts up a local server, we may see some spurious
556 		// server disconnect messages when their new server sees our final
557 		// sequenced messages to the old client
558 	} else {
559 		Com_DPrintf ("bad connectionless packet from %s:\n%s\n"
560 		, NET_AdrToString (from), s);
561 	}
562 }
563 
564 //============================================================================
565 
566 /*
567 =================
568 SV_ReadPackets
569 =================
570 */
SV_PacketEvent(netadr_t from,msg_t * msg)571 void SV_PacketEvent( netadr_t from, msg_t *msg ) {
572 	int			i;
573 	client_t	*cl;
574 	int			qport;
575 
576 	// check for connectionless packet (0xffffffff) first
577 	if ( msg->cursize >= 4 && *(int *)msg->data == -1) {
578 		SV_ConnectionlessPacket( from, msg );
579 		return;
580 	}
581 
582 	// read the qport out of the message so we can fix up
583 	// stupid address translating routers
584 	MSG_BeginReadingOOB( msg );
585 	MSG_ReadLong( msg );				// sequence number
586 	qport = MSG_ReadShort( msg ) & 0xffff;
587 
588 	// find which client the message is from
589 	for (i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
590 		if (cl->state == CS_FREE) {
591 			continue;
592 		}
593 		if ( !NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) ) {
594 			continue;
595 		}
596 		// it is possible to have multiple clients from a single IP
597 		// address, so they are differentiated by the qport variable
598 		if (cl->netchan.qport != qport) {
599 			continue;
600 		}
601 
602 		// the IP port can't be used to differentiate them, because
603 		// some address translating routers periodically change UDP
604 		// port assignments
605 		if (cl->netchan.remoteAddress.port != from.port) {
606 			Com_Printf( "SV_PacketEvent: fixing up a translated port\n" );
607 			cl->netchan.remoteAddress.port = from.port;
608 		}
609 
610 		// make sure it is a valid, in sequence packet
611 		if (SV_Netchan_Process(cl, msg)) {
612 			// zombie clients still need to do the Netchan_Process
613 			// to make sure they don't need to retransmit the final
614 			// reliable message, but they don't do any other processing
615 			if (cl->state != CS_ZOMBIE) {
616 				cl->lastPacketTime = svs.time;	// don't timeout
617 				SV_ExecuteClientMessage( cl, msg );
618 			}
619 		}
620 		return;
621 	}
622 
623 	// if we received a sequenced packet from an address we don't recognize,
624 	// send an out of band disconnect packet to it
625 	NET_OutOfBandPrint( NS_SERVER, from, "disconnect" );
626 }
627 
628 
629 /*
630 ===================
631 SV_CalcPings
632 
633 Updates the cl->ping variables
634 ===================
635 */
SV_CalcPings(void)636 void SV_CalcPings( void ) {
637 	int			i, j;
638 	client_t	*cl;
639 	int			total, count;
640 	int			delta;
641 	playerState_t	*ps;
642 
643 	for (i=0 ; i < sv_maxclients->integer ; i++) {
644 		cl = &svs.clients[i];
645 		if ( cl->state != CS_ACTIVE ) {
646 			cl->ping = 999;
647 			continue;
648 		}
649 		if ( !cl->gentity ) {
650 			cl->ping = 999;
651 			continue;
652 		}
653 		if ( cl->gentity->r.svFlags & SVF_BOT ) {
654 			cl->ping = 0;
655 			continue;
656 		}
657 
658 		total = 0;
659 		count = 0;
660 		for ( j = 0 ; j < PACKET_BACKUP ; j++ ) {
661 			if ( cl->frames[j].messageAcked <= 0 ) {
662 				continue;
663 			}
664 			delta = cl->frames[j].messageAcked - cl->frames[j].messageSent;
665 			count++;
666 			total += delta;
667 		}
668 		if (!count) {
669 			cl->ping = 999;
670 		} else {
671 			cl->ping = total/count;
672 			if ( cl->ping > 999 ) {
673 				cl->ping = 999;
674 			}
675 		}
676 
677 		// let the game dll know about the ping
678 		ps = SV_GameClientNum( i );
679 		ps->ping = cl->ping;
680 	}
681 }
682 
683 /*
684 ==================
685 SV_CheckTimeouts
686 
687 If a packet has not been received from a client for timeout->integer
688 seconds, drop the conneciton.  Server time is used instead of
689 realtime to avoid dropping the local client while debugging.
690 
691 When a client is normally dropped, the client_t goes into a zombie state
692 for a few seconds to make sure any final reliable message gets resent
693 if necessary
694 ==================
695 */
SV_CheckTimeouts(void)696 void SV_CheckTimeouts( void ) {
697 	int		i;
698 	client_t	*cl;
699 	int			droppoint;
700 	int			zombiepoint;
701 
702 	droppoint = svs.time - 1000 * sv_timeout->integer;
703 	zombiepoint = svs.time - 1000 * sv_zombietime->integer;
704 
705 	for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
706 		// message times may be wrong across a changelevel
707 		if (cl->lastPacketTime > svs.time) {
708 			cl->lastPacketTime = svs.time;
709 		}
710 
711 		if (cl->state == CS_ZOMBIE
712 		&& cl->lastPacketTime < zombiepoint) {
713 			// using the client id cause the cl->name is empty at this point
714 			Com_DPrintf( "Going from CS_ZOMBIE to CS_FREE for client %d\n", i );
715 			cl->state = CS_FREE;	// can now be reused
716 			continue;
717 		}
718 		if ( cl->state >= CS_CONNECTED && cl->lastPacketTime < droppoint) {
719 			// wait several frames so a debugger session doesn't
720 			// cause a timeout
721 			if ( ++cl->timeoutCount > 5 ) {
722 				SV_DropClient (cl, "timed out");
723 				cl->state = CS_FREE;	// don't bother with zombie state
724 			}
725 		} else {
726 			cl->timeoutCount = 0;
727 		}
728 	}
729 }
730 
731 
732 /*
733 ==================
734 SV_CheckPaused
735 ==================
736 */
SV_CheckPaused(void)737 qboolean SV_CheckPaused( void ) {
738 	int		count;
739 	client_t	*cl;
740 	int		i;
741 
742 	if ( !cl_paused->integer ) {
743 		return qfalse;
744 	}
745 
746 	// only pause if there is just a single client connected
747 	count = 0;
748 	for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
749 		if ( cl->state >= CS_CONNECTED && cl->netchan.remoteAddress.type != NA_BOT ) {
750 			count++;
751 		}
752 	}
753 
754 	if ( count > 1 ) {
755 		// don't pause
756 		if (sv_paused->integer)
757 			Cvar_Set("sv_paused", "0");
758 		return qfalse;
759 	}
760 
761 	if (!sv_paused->integer)
762 		Cvar_Set("sv_paused", "1");
763 	return qtrue;
764 }
765 
766 /*
767 ==================
768 SV_Frame
769 
770 Player movement occurs as a result of packet events, which
771 happen before SV_Frame is called
772 ==================
773 */
SV_Frame(int msec)774 void SV_Frame( int msec ) {
775 	int		frameMsec;
776 	int		startTime;
777 
778 	// the menu kills the server with this cvar
779 	if ( sv_killserver->integer ) {
780 		SV_Shutdown ("Server was killed");
781 		Cvar_Set( "sv_killserver", "0" );
782 		return;
783 	}
784 
785 	if (!com_sv_running->integer)
786 	{
787 		// Running as a server, but no map loaded
788 #ifdef DEDICATED
789 		// Block until something interesting happens
790 		Sys_Sleep(-1);
791 #endif
792 
793 		return;
794 	}
795 
796 	// allow pause if only the local client is connected
797 	if ( SV_CheckPaused() ) {
798 		return;
799 	}
800 
801 	// if it isn't time for the next frame, do nothing
802 	if ( sv_fps->integer < 1 ) {
803 		Cvar_Set( "sv_fps", "10" );
804 	}
805 
806 	frameMsec = 1000 / sv_fps->integer * com_timescale->value;
807 	// don't let it scale below 1ms
808 	if(frameMsec < 1)
809 	{
810 		Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f));
811 		frameMsec = 1;
812 	}
813 
814 	sv.timeResidual += msec;
815 
816 	if (!com_dedicated->integer) SV_BotFrame (sv.time + sv.timeResidual);
817 
818 	if ( com_dedicated->integer && sv.timeResidual < frameMsec ) {
819 		// NET_Sleep will give the OS time slices until either get a packet
820 		// or time enough for a server frame has gone by
821 		NET_Sleep(frameMsec - sv.timeResidual);
822 		return;
823 	}
824 
825 	// if time is about to hit the 32nd bit, kick all clients
826 	// and clear sv.time, rather
827 	// than checking for negative time wraparound everywhere.
828 	// 2giga-milliseconds = 23 days, so it won't be too often
829 	if ( svs.time > 0x70000000 ) {
830 		SV_Shutdown( "Restarting server due to time wrapping" );
831 		Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) );
832 		return;
833 	}
834 	// this can happen considerably earlier when lots of clients play and the map doesn't change
835 	if ( svs.nextSnapshotEntities >= 0x7FFFFFFE - svs.numSnapshotEntities ) {
836 		SV_Shutdown( "Restarting server due to numSnapshotEntities wrapping" );
837 		Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) );
838 		return;
839 	}
840 
841 	if( sv.restartTime && sv.time >= sv.restartTime ) {
842 		sv.restartTime = 0;
843 		Cbuf_AddText( "map_restart 0\n" );
844 		return;
845 	}
846 
847 	// update infostrings if anything has been changed
848 	if ( cvar_modifiedFlags & CVAR_SERVERINFO ) {
849 		SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
850 		cvar_modifiedFlags &= ~CVAR_SERVERINFO;
851 	}
852 	if ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) {
853 		SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) );
854 		cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
855 	}
856 
857 	if ( com_speeds->integer ) {
858 		startTime = Sys_Milliseconds ();
859 	} else {
860 		startTime = 0;	// quite a compiler warning
861 	}
862 
863 	// update ping based on the all received frames
864 	SV_CalcPings();
865 
866 	if (com_dedicated->integer) SV_BotFrame (sv.time);
867 
868 	// run the game simulation in chunks
869 	while ( sv.timeResidual >= frameMsec ) {
870 		sv.timeResidual -= frameMsec;
871 		svs.time += frameMsec;
872 		sv.time += frameMsec;
873 
874 		// let everything in the world think and move
875 		VM_Call (gvm, GAME_RUN_FRAME, sv.time);
876 	}
877 
878 	if ( com_speeds->integer ) {
879 		time_game = Sys_Milliseconds () - startTime;
880 	}
881 
882 	// check timeouts
883 	SV_CheckTimeouts();
884 
885 	// send messages back to the clients
886 	SV_SendClientMessages();
887 
888 	// send a heartbeat to the master if needed
889 	SV_MasterHeartbeat();
890 }
891 
892 //============================================================================
893 
894