1 /*
2 Copyright (C) 1997-2001 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 "server.h"
22 
23 netadr_t	master_adr[MAX_MASTERS];	// address of group servers
24 
25 client_t	*sv_client;			// current client
26 
27 cvar_t	*sv_paused;
28 cvar_t	*sv_timedemo;
29 
30 cvar_t	*sv_enforcetime;
31 
32 cvar_t	*timeout;				// seconds without any message
33 cvar_t	*zombietime;			// seconds to sink messages after disconnect
34 
35 cvar_t	*rcon_password;			// password for remote server commands
36 
37 cvar_t	*allow_download;
38 cvar_t *allow_download_players;
39 cvar_t *allow_download_models;
40 cvar_t *allow_download_sounds;
41 cvar_t *allow_download_maps;
42 
43 cvar_t *sv_airaccelerate;
44 
45 cvar_t	*sv_noreload;			// don't reload level state when reentering
46 
47 cvar_t	*maxclients;			// FIXME: rename sv_maxclients
48 cvar_t	*sv_showclamp;
49 
50 cvar_t	*hostname;
51 cvar_t	*public_server;			// should heartbeats be sent
52 
53 cvar_t	*sv_reconnect_limit;	// minimum seconds between connect messages
54 
55 void Master_Shutdown (void);
56 
57 
58 //============================================================================
59 
60 
61 /*
62 =====================
63 SV_DropClient
64 
65 Called when the player is totally leaving the server, either willingly
66 or unwillingly.  This is NOT called if the entire server is quiting
67 or crashing.
68 =====================
69 */
SV_DropClient(client_t * drop)70 void SV_DropClient (client_t *drop)
71 {
72 	// add the disconnect
73 	MSG_WriteByte (&drop->netchan.message, svc_disconnect);
74 
75 	if (drop->state == cs_spawned)
76 	{
77 		// call the prog function for removing a client
78 		// this will remove the body, among other things
79 		ge->ClientDisconnect (drop->edict);
80 	}
81 
82 	if (drop->download)
83 	{
84 		FS_FreeFile (drop->download);
85 		drop->download = NULL;
86 	}
87 
88 	drop->state = cs_zombie;		// become free in a few seconds
89 	drop->name[0] = 0;
90 }
91 
92 
93 
94 /*
95 ==============================================================================
96 
97 CONNECTIONLESS COMMANDS
98 
99 ==============================================================================
100 */
101 
102 /*
103 ===============
104 SV_StatusString
105 
106 Builds the string that is sent as heartbeats and status replies
107 ===============
108 */
SV_StatusString(void)109 char	*SV_StatusString (void)
110 {
111 	char	player[1024];
112 	static char	status[MAX_MSGLEN - 16];
113 	int		i;
114 	client_t	*cl;
115 	int		statusLength;
116 	int		playerLength;
117 
118 	strcpy (status, Cvar_Serverinfo());
119 	strcat (status, "\n");
120 	statusLength = strlen(status);
121 
122 	for (i=0 ; i<maxclients->value ; i++)
123 	{
124 		cl = &svs.clients[i];
125 		if (cl->state == cs_connected || cl->state == cs_spawned )
126 		{
127 			Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n",
128 				cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name);
129 			playerLength = strlen(player);
130 			if (statusLength + playerLength >= sizeof(status) )
131 				break;		// can't hold any more
132 			strcpy (status + statusLength, player);
133 			statusLength += playerLength;
134 		}
135 	}
136 
137 	return status;
138 }
139 
140 /*
141 ================
142 SVC_Status
143 
144 Responds with all the info that qplug or qspy can see
145 ================
146 */
SVC_Status(void)147 void SVC_Status (void)
148 {
149 	Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", SV_StatusString());
150 #if 0
151 	Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
152 	Com_Printf (SV_StatusString());
153 	Com_EndRedirect ();
154 #endif
155 }
156 
157 /*
158 ================
159 SVC_Ack
160 
161 ================
162 */
SVC_Ack(void)163 void SVC_Ack (void)
164 {
165 	Com_Printf ("Ping acknowledge from %s\n", NET_AdrToString(net_from));
166 }
167 
168 /*
169 ================
170 SVC_Info
171 
172 Responds with short info for broadcast scans
173 The second parameter should be the current protocol version number.
174 ================
175 */
SVC_Info(void)176 void SVC_Info (void)
177 {
178 	char	string[64];
179 	int		i, count;
180 	int		version;
181 
182 	if (maxclients->value == 1)
183 		return;		// ignore in single player
184 
185 	version = atoi (Cmd_Argv(1));
186 
187 	if (version != PROTOCOL_VERSION)
188 		Com_sprintf (string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string));
189 	else
190 	{
191 		count = 0;
192 		for (i=0 ; i<maxclients->value ; i++)
193 			if (svs.clients[i].state >= cs_connected)
194 				count++;
195 
196 		Com_sprintf (string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value);
197 	}
198 
199 	Netchan_OutOfBandPrint (NS_SERVER, net_from, "info\n%s", string);
200 }
201 
202 /*
203 ================
204 SVC_Ping
205 
206 Just responds with an acknowledgement
207 ================
208 */
SVC_Ping(void)209 void SVC_Ping (void)
210 {
211 	Netchan_OutOfBandPrint (NS_SERVER, net_from, "ack");
212 }
213 
214 
215 /*
216 =================
217 SVC_GetChallenge
218 
219 Returns a challenge number that can be used
220 in a subsequent client_connect command.
221 We do this to prevent denial of service attacks that
222 flood the server with invalid connection IPs.  With a
223 challenge, they must give a valid IP address.
224 =================
225 */
SVC_GetChallenge(void)226 void SVC_GetChallenge (void)
227 {
228 	int		i;
229 	int		oldest;
230 	int		oldestTime;
231 
232 	oldest = 0;
233 	oldestTime = 0x7fffffff;
234 
235 	// see if we already have a challenge for this ip
236 	for (i = 0 ; i < MAX_CHALLENGES ; i++)
237 	{
238 		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
239 			break;
240 		if (svs.challenges[i].time < oldestTime)
241 		{
242 			oldestTime = svs.challenges[i].time;
243 			oldest = i;
244 		}
245 	}
246 
247 	if (i == MAX_CHALLENGES)
248 	{
249 		// overwrite the oldest
250 		svs.challenges[oldest].challenge = rand() & 0x7fff;
251 		svs.challenges[oldest].adr = net_from;
252 		svs.challenges[oldest].time = curtime;
253 		i = oldest;
254 	}
255 
256 	// send it back
257 	Netchan_OutOfBandPrint (NS_SERVER, net_from, "challenge %i", svs.challenges[i].challenge);
258 }
259 
260 /*
261 ==================
262 SVC_DirectConnect
263 
264 A connection request that did not come from the master
265 ==================
266 */
SVC_DirectConnect(void)267 void SVC_DirectConnect (void)
268 {
269 	char		userinfo[MAX_INFO_STRING];
270 	netadr_t	adr;
271 	int			i;
272 	client_t	*cl, *newcl;
273 	client_t	temp;
274 	edict_t		*ent;
275 	int			edictnum;
276 	int			version;
277 	int			qport;
278 	int			challenge;
279 
280 	adr = net_from;
281 
282 	Com_DPrintf ("SVC_DirectConnect ()\n");
283 
284 	version = atoi(Cmd_Argv(1));
285 	if (version != PROTOCOL_VERSION)
286 	{
287 		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
288 		Com_DPrintf ("    rejected connect from version %i\n", version);
289 		return;
290 	}
291 
292 	qport = atoi(Cmd_Argv(2));
293 
294 	challenge = atoi(Cmd_Argv(3));
295 
296 	// sku - reserve 32 bytes for the IP address
297 	strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-32);
298 	userinfo[sizeof(userinfo) - 32] = 0;
299 
300 	// force the IP key/value pair so the game can filter based on ip
301 	Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));
302 
303 	// attractloop servers are ONLY for local clients
304 	if (sv.attractloop)
305 	{
306 		if (!NET_IsLocalAddress (adr))
307 		{
308 			Com_Printf ("Remote connect in attract loop.  Ignored.\n");
309 			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n");
310 			return;
311 		}
312 	}
313 
314 	// see if the challenge is valid
315 	if (!NET_IsLocalAddress (adr))
316 	{
317 		for (i=0 ; i<MAX_CHALLENGES ; i++)
318 		{
319 			if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
320 			{
321 				if (challenge == svs.challenges[i].challenge)
322 					break;		// good
323 				Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad challenge.\n");
324 				return;
325 			}
326 		}
327 		if (i == MAX_CHALLENGES)
328 		{
329 			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nNo challenge for address.\n");
330 			return;
331 		}
332 	}
333 
334 	newcl = &temp;
335 	memset (newcl, 0, sizeof(client_t));
336 
337 	// if there is already a slot for this ip, reuse it
338 	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
339 	{
340 		if (cl->state == cs_free)
341 			continue;
342 		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
343 			&& ( cl->netchan.qport == qport
344 			|| adr.port == cl->netchan.remote_address.port ) )
345 		{
346 			// sku - avoid reusing slot of the client already connected
347 			if( cl->state != cs_zombie ) {
348 				Netchan_OutOfBandPrint( NS_SERVER, adr, "print\nConnected client from this IP is already present.\n" );
349 				return;
350 			}
351 			if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value * 1000))
352 			{
353 				Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
354 				return;
355 			}
356 			Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
357 			newcl = cl;
358 			goto gotnewcl;
359 		}
360 	}
361 
362 	// find a client slot
363 	newcl = NULL;
364 	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
365 	{
366 		if (cl->state == cs_free)
367 		{
368 			newcl = cl;
369 			break;
370 		}
371 	}
372 	if (!newcl)
373 	{
374 		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is full.\n");
375 		Com_DPrintf ("Rejected a connection.\n");
376 		return;
377 	}
378 
379 gotnewcl:
380 	// build a new connection
381 	// accept the new client
382 	// this is the only place a client_t is ever initialized
383 	*newcl = temp;
384 	sv_client = newcl;
385 	edictnum = (newcl-svs.clients)+1;
386 	ent = EDICT_NUM(edictnum);
387 	newcl->edict = ent;
388 	newcl->challenge = challenge; // save challenge for checksumming
389 
390 	// get the game a chance to reject this connection or modify the userinfo
391 	if (!(ge->ClientConnect (ent, userinfo)))
392 	{
393 	  	if (*Info_ValueForKey (userinfo, "rejmsg"))
394 			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n",
395 				Info_ValueForKey (userinfo, "rejmsg"));
396 		else
397 			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" );
398 		Com_DPrintf ("Game rejected a connection.\n");
399 		return;
400 	}
401 
402 	// parse some info from the info strings
403 	strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
404 	SV_UserinfoChanged (newcl);
405 
406 	// send the connect packet to the client
407 	Netchan_OutOfBandPrint (NS_SERVER, adr, "client_connect");
408 
409 	Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);
410 
411 	newcl->state = cs_connected;
412 
413 	SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf) );
414 	newcl->datagram.allowoverflow = true;
415 	newcl->lastmessage = svs.realtime;	// don't timeout
416 	newcl->lastconnect = svs.realtime;
417 }
418 
Rcon_Validate(void)419 int Rcon_Validate (void)
420 {
421 	if (!strlen (rcon_password->string))
422 		return 0;
423 
424 	if (strcmp (Cmd_Argv(1), rcon_password->string) )
425 		return 0;
426 
427 	return 1;
428 }
429 
430 /*
431 ===============
432 SVC_RemoteCommand
433 
434 A client issued an rcon command.
435 Shift down the remaining args
436 Redirect all printfs
437 ===============
438 */
SVC_RemoteCommand(void)439 void SVC_RemoteCommand (void)
440 {
441 	int		i;
442 	char	remaining[1024];
443 
444 	i = Rcon_Validate ();
445 
446 	if (i == 0)
447 		Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
448 	else
449 		Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
450 
451 	Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
452 
453 	if (!Rcon_Validate ())
454 	{
455 		Com_Printf ("Bad rcon_password.\n");
456 	}
457 	else
458 	{
459 		remaining[0] = 0;
460 
461 		for (i=2 ; i<Cmd_Argc() ; i++)
462 		{
463 			strcat (remaining, Cmd_Argv(i) );
464 			strcat (remaining, " ");
465 		}
466 
467 		Cmd_ExecuteString (remaining);
468 	}
469 
470 	Com_EndRedirect ();
471 }
472 
473 /*
474 =================
475 SV_ConnectionlessPacket
476 
477 A connectionless packet has four leading 0xff
478 characters to distinguish it from a game channel.
479 Clients that are in the game can still send
480 connectionless packets.
481 =================
482 */
SV_ConnectionlessPacket(void)483 void SV_ConnectionlessPacket (void)
484 {
485 	char	*s;
486 	char	*c;
487 
488 	MSG_BeginReading (&net_message);
489 	MSG_ReadLong (&net_message);		// skip the -1 marker
490 
491 	s = MSG_ReadStringLine (&net_message);
492 
493 	Cmd_TokenizeString (s, false);
494 
495 	c = Cmd_Argv(0);
496 	Com_DPrintf ("Packet %s : %s\n", NET_AdrToString(net_from), c);
497 
498 	if (!strcmp(c, "ping"))
499 		SVC_Ping ();
500 	else if (!strcmp(c, "ack"))
501 		SVC_Ack ();
502 	else if (!strcmp(c,"status"))
503 		SVC_Status ();
504 	else if (!strcmp(c,"info"))
505 		SVC_Info ();
506 	else if (!strcmp(c,"getchallenge"))
507 		SVC_GetChallenge ();
508 	else if (!strcmp(c,"connect"))
509 		SVC_DirectConnect ();
510 	else if (!strcmp(c, "rcon"))
511 		SVC_RemoteCommand ();
512 	else
513 		Com_Printf ("bad connectionless packet from %s:\n%s\n"
514 		, NET_AdrToString (net_from), s);
515 }
516 
517 
518 //============================================================================
519 
520 /*
521 ===================
522 SV_CalcPings
523 
524 Updates the cl->ping variables
525 ===================
526 */
SV_CalcPings(void)527 void SV_CalcPings (void)
528 {
529 	int			i, j;
530 	client_t	*cl;
531 	int			total, count;
532 
533 	for (i=0 ; i<maxclients->value ; i++)
534 	{
535 		cl = &svs.clients[i];
536 		if (cl->state != cs_spawned )
537 			continue;
538 
539 #if 0
540 		if (cl->lastframe > 0)
541 			cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = sv.framenum - cl->lastframe + 1;
542 		else
543 			cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = 0;
544 #endif
545 
546 		total = 0;
547 		count = 0;
548 		for (j=0 ; j<LATENCY_COUNTS ; j++)
549 		{
550 			if (cl->frame_latency[j] > 0)
551 			{
552 				count++;
553 				total += cl->frame_latency[j];
554 			}
555 		}
556 		if (!count)
557 			cl->ping = 0;
558 		else
559 #if 0
560 			cl->ping = total*100/count - 100;
561 #else
562 			cl->ping = total / count;
563 #endif
564 
565 		// let the game dll know about the ping
566 		cl->edict->client->ping = cl->ping;
567 	}
568 }
569 
570 
571 /*
572 ===================
573 SV_GiveMsec
574 
575 Every few frames, gives all clients an allotment of milliseconds
576 for their command moves.  If they exceed it, assume cheating.
577 ===================
578 */
SV_GiveMsec(void)579 void SV_GiveMsec (void)
580 {
581 	int			i;
582 	client_t	*cl;
583 
584 	if (sv.framenum & 15)
585 		return;
586 
587 	for (i=0 ; i<maxclients->value ; i++)
588 	{
589 		cl = &svs.clients[i];
590 		if (cl->state == cs_free )
591 			continue;
592 
593 		cl->commandMsec = 1800;		// 1600 + some slop
594 	}
595 }
596 
597 
598 /*
599 =================
600 SV_ReadPackets
601 =================
602 */
SV_ReadPackets(void)603 void SV_ReadPackets (void)
604 {
605 	int			i;
606 	client_t	*cl;
607 	int			qport;
608 
609 	while (NET_GetPacket (NS_SERVER, &net_from, &net_message))
610 	{
611 		// check for connectionless packet (0xffffffff) first
612 		if (*(int *)net_message.data == -1)
613 		{
614 			SV_ConnectionlessPacket ();
615 			continue;
616 		}
617 
618 		// read the qport out of the message so we can fix up
619 		// stupid address translating routers
620 		MSG_BeginReading (&net_message);
621 		MSG_ReadLong (&net_message);		// sequence number
622 		MSG_ReadLong (&net_message);		// sequence number
623 		qport = MSG_ReadShort (&net_message) & 0xffff;
624 
625 		// check for packets from connected clients
626 		for (i=0, cl=svs.clients ; i<maxclients->value ; i++,cl++)
627 		{
628 			if (cl->state == cs_free)
629 				continue;
630 			if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
631 				continue;
632 			if (cl->netchan.qport != qport)
633 				continue;
634 			if (cl->netchan.remote_address.port != net_from.port)
635 			{
636 				Com_Printf ("SV_ReadPackets: fixing up a translated port\n");
637 				cl->netchan.remote_address.port = net_from.port;
638 			}
639 
640 			if (Netchan_Process(&cl->netchan, &net_message))
641 			{	// this is a valid, sequenced packet, so process it
642 				if (cl->state != cs_zombie)
643 				{
644 					cl->lastmessage = svs.realtime;	// don't timeout
645 					SV_ExecuteClientMessage (cl);
646 				}
647 			}
648 			break;
649 		}
650 
651 		if (i != maxclients->value)
652 			continue;
653 	}
654 }
655 
656 /*
657 ==================
658 SV_CheckTimeouts
659 
660 If a packet has not been received from a client for timeout->value
661 seconds, drop the conneciton.  Server frames are used instead of
662 realtime to avoid dropping the local client while debugging.
663 
664 When a client is normally dropped, the client_t goes into a zombie state
665 for a few seconds to make sure any final reliable message gets resent
666 if necessary
667 ==================
668 */
SV_CheckTimeouts(void)669 void SV_CheckTimeouts (void)
670 {
671 	int		i;
672 	client_t	*cl;
673 	int			droppoint;
674 	int			zombiepoint;
675 
676 	droppoint = svs.realtime - 1000*timeout->value;
677 	zombiepoint = svs.realtime - 1000*zombietime->value;
678 
679 	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
680 	{
681 		// message times may be wrong across a changelevel
682 		if (cl->lastmessage > svs.realtime)
683 			cl->lastmessage = svs.realtime;
684 
685 		if (cl->state == cs_zombie
686 		&& cl->lastmessage < zombiepoint)
687 		{
688 			cl->state = cs_free;	// can now be reused
689 			continue;
690 		}
691 		if ( (cl->state == cs_connected || cl->state == cs_spawned)
692 			&& cl->lastmessage < droppoint)
693 		{
694 			SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
695 			SV_DropClient (cl);
696 			cl->state = cs_free;	// don't bother with zombie state
697 		}
698 	}
699 }
700 
701 /*
702 ================
703 SV_PrepWorldFrame
704 
705 This has to be done before the world logic, because
706 player processing happens outside RunWorldFrame
707 ================
708 */
SV_PrepWorldFrame(void)709 void SV_PrepWorldFrame (void)
710 {
711 	edict_t	*ent;
712 	int		i;
713 
714 	for (i=0 ; i<ge->num_edicts ; i++, ent++)
715 	{
716 		ent = EDICT_NUM(i);
717 		// events only last for a single message
718 		ent->s.event = 0;
719 	}
720 
721 }
722 
723 
724 /*
725 =================
726 SV_RunGameFrame
727 =================
728 */
SV_RunGameFrame(void)729 void SV_RunGameFrame (void)
730 {
731 	if (host_speeds->value)
732 		time_before_game = Sys_Milliseconds ();
733 
734 	// we always need to bump framenum, even if we
735 	// don't run the world, otherwise the delta
736 	// compression can get confused when a client
737 	// has the "current" frame
738 	sv.framenum++;
739 	sv.time = sv.framenum*100;
740 
741 	// don't run if paused
742 	if (!sv_paused->value || maxclients->value > 1)
743 	{
744 		ge->RunFrame ();
745 
746 		// never get more than one tic behind
747 		if (sv.time < svs.realtime)
748 		{
749 			if (sv_showclamp->value)
750 				Com_Printf ("sv highclamp\n");
751 			svs.realtime = sv.time;
752 		}
753 	}
754 
755 	if (host_speeds->value)
756 		time_after_game = Sys_Milliseconds ();
757 
758 }
759 
760 /*
761 ==================
762 SV_Frame
763 
764 ==================
765 */
SV_Frame(int msec)766 void SV_Frame (int msec)
767 {
768 	time_before_game = time_after_game = 0;
769 
770 	// if server is not active, do nothing
771 	if (!svs.initialized)
772 		return;
773 
774     svs.realtime += msec;
775 
776 	// keep the random time dependent
777 	rand ();
778 
779 	// check timeouts
780 	SV_CheckTimeouts ();
781 
782 	// get packets from clients
783 	SV_ReadPackets ();
784 
785 	// move autonomous things around if enough time has passed
786 	if (!sv_timedemo->value && svs.realtime < sv.time)
787 	{
788 		// never let the time get too far off
789 		if (sv.time - svs.realtime > 100)
790 		{
791 			if (sv_showclamp->value)
792 				Com_Printf ("sv lowclamp\n");
793 			svs.realtime = sv.time - 100;
794 		}
795 		NET_Sleep(sv.time - svs.realtime);
796 		return;
797 	}
798 
799 	// update ping based on the last known frame from all clients
800 	SV_CalcPings ();
801 
802 	// give the clients some timeslices
803 	SV_GiveMsec ();
804 
805 	// let everything in the world think and move
806 	SV_RunGameFrame ();
807 
808 	// send messages back to the clients that had packets read this frame
809 	SV_SendClientMessages ();
810 
811 	// save the entire world state if recording a serverdemo
812 	SV_RecordDemoMessage ();
813 
814 	// send a heartbeat to the master if needed
815 	Master_Heartbeat ();
816 
817 	// clear teleport flags, etc for next frame
818 	SV_PrepWorldFrame ();
819 
820 }
821 
822 //============================================================================
823 
824 /*
825 ================
826 Master_Heartbeat
827 
828 Send a message to the master every few minutes to
829 let it know we are alive, and log information
830 ================
831 */
832 #define	HEARTBEAT_SECONDS	300
Master_Heartbeat(void)833 void Master_Heartbeat (void)
834 {
835 	char		*string;
836 	int			i;
837 
838 	// pgm post3.19 change, cvar pointer not validated before dereferencing
839 	if (!dedicated || !dedicated->value)
840 		return;		// only dedicated servers send heartbeats
841 
842 	// pgm post3.19 change, cvar pointer not validated before dereferencing
843 	if (!public_server || !public_server->value)
844 		return;		// a private dedicated game
845 
846 	// check for time wraparound
847 	if (svs.last_heartbeat > svs.realtime)
848 		svs.last_heartbeat = svs.realtime;
849 
850 	if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000)
851 		return;		// not time to send yet
852 
853 	svs.last_heartbeat = svs.realtime;
854 
855 	// send the same string that we would give for a status OOB command
856 	string = SV_StatusString();
857 
858 	// send to group master
859 	for (i=0 ; i<MAX_MASTERS ; i++)
860 		if (master_adr[i].port)
861 		{
862 			Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
863 			Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "heartbeat\n%s", string);
864 		}
865 }
866 
867 /*
868 =================
869 Master_Shutdown
870 
871 Informs all masters that this server is going down
872 =================
873 */
Master_Shutdown(void)874 void Master_Shutdown (void)
875 {
876 	int			i;
877 
878 	// pgm post3.19 change, cvar pointer not validated before dereferencing
879 	if (!dedicated || !dedicated->value)
880 		return;		// only dedicated servers send heartbeats
881 
882 	// pgm post3.19 change, cvar pointer not validated before dereferencing
883 	if (!public_server || !public_server->value)
884 		return;		// a private dedicated game
885 
886 	// send to group master
887 	for (i=0 ; i<MAX_MASTERS ; i++)
888 		if (master_adr[i].port)
889 		{
890 			if (i > 0)
891 				Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
892 			Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "shutdown");
893 		}
894 }
895 
896 //============================================================================
897 
898 
899 /*
900 =================
901 SV_UserinfoChanged
902 
903 Pull specific info from a newly changed userinfo string
904 into a more C freindly form.
905 =================
906 */
SV_UserinfoChanged(client_t * cl)907 void SV_UserinfoChanged (client_t *cl)
908 {
909 	char	*val;
910 	int		i;
911 
912 	// call prog code to allow overrides
913 	ge->ClientUserinfoChanged (cl->edict, cl->userinfo);
914 
915 	// name for C code
916 	strncpy (cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name)-1);
917 	// mask off high bit
918 	for (i=0 ; i<sizeof(cl->name) ; i++)
919 		cl->name[i] &= 127;
920 
921 	// rate command
922 	val = Info_ValueForKey (cl->userinfo, "rate");
923 	if (strlen(val))
924 	{
925 		i = atoi(val);
926 		cl->rate = i;
927 		if (cl->rate < 100)
928 			cl->rate = 100;
929 		if (cl->rate > 15000)
930 			cl->rate = 15000;
931 	}
932 	else
933 		cl->rate = 5000;
934 
935 	// msg command
936 	val = Info_ValueForKey (cl->userinfo, "msg");
937 	if (strlen(val))
938 	{
939 		cl->messagelevel = atoi(val);
940 	}
941 
942 }
943 
944 
945 //============================================================================
946 
947 /*
948 ===============
949 SV_Init
950 
951 Only called at quake2.exe startup, not for each game
952 ===============
953 */
SV_Init(void)954 void SV_Init (void)
955 {
956 	SV_InitOperatorCommands	();
957 
958 	rcon_password = Cvar_Get ("rcon_password", "", 0);
959 	Cvar_Get ("skill", "1", 0);
960 	Cvar_Get ("deathmatch", "0", CVAR_LATCH);
961 	Cvar_Get ("coop", "0", CVAR_LATCH);
962 	Cvar_Get ("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO);
963 	Cvar_Get ("fraglimit", "0", CVAR_SERVERINFO);
964 	Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
965 	Cvar_Get ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
966 	Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_NOSET);;
967 	maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
968 	hostname = Cvar_Get ("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE);
969 	timeout = Cvar_Get ("timeout", "125", 0);
970 	zombietime = Cvar_Get ("zombietime", "2", 0);
971 	sv_showclamp = Cvar_Get ("showclamp", "0", 0);
972 	sv_paused = Cvar_Get ("paused", "0", 0);
973 	sv_timedemo = Cvar_Get ("timedemo", "0", 0);
974 	sv_enforcetime = Cvar_Get ("sv_enforcetime", "0", 0);
975 	allow_download = Cvar_Get ("allow_download", "1", CVAR_ARCHIVE);
976 	allow_download_players  = Cvar_Get ("allow_download_players", "0", CVAR_ARCHIVE);
977 	allow_download_models = Cvar_Get ("allow_download_models", "1", CVAR_ARCHIVE);
978 	allow_download_sounds = Cvar_Get ("allow_download_sounds", "1", CVAR_ARCHIVE);
979 	allow_download_maps	  = Cvar_Get ("allow_download_maps", "1", CVAR_ARCHIVE);
980 
981 	sv_noreload = Cvar_Get ("sv_noreload", "0", 0);
982 
983 	sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH);
984 
985 	public_server = Cvar_Get ("public", "0", 0);
986 
987 	sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE);
988 
989 	SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
990 }
991 
992 /*
993 ==================
994 SV_FinalMessage
995 
996 Used by SV_Shutdown to send a final message to all
997 connected clients before the server goes down.  The messages are sent immediately,
998 not just stuck on the outgoing message list, because the server is going
999 to totally exit after returning from this function.
1000 ==================
1001 */
SV_FinalMessage(char * message,qboolean reconnect)1002 void SV_FinalMessage (char *message, qboolean reconnect)
1003 {
1004 	int			i;
1005 	client_t	*cl;
1006 
1007 	SZ_Clear (&net_message);
1008 	MSG_WriteByte (&net_message, svc_print);
1009 	MSG_WriteByte (&net_message, PRINT_HIGH);
1010 	MSG_WriteString (&net_message, message);
1011 
1012 	if (reconnect)
1013 		MSG_WriteByte (&net_message, svc_reconnect);
1014 	else
1015 		MSG_WriteByte (&net_message, svc_disconnect);
1016 
1017 	// send it twice
1018 	// stagger the packets to crutch operating system limited buffers
1019 
1020 	for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
1021 		if (cl->state >= cs_connected)
1022 			Netchan_Transmit (&cl->netchan, net_message.cursize
1023 			, net_message.data);
1024 
1025 	for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
1026 		if (cl->state >= cs_connected)
1027 			Netchan_Transmit (&cl->netchan, net_message.cursize
1028 			, net_message.data);
1029 }
1030 
1031 
1032 
1033 /*
1034 ================
1035 SV_Shutdown
1036 
1037 Called when each game quits,
1038 before Sys_Quit or Sys_Error
1039 ================
1040 */
SV_Shutdown(char * finalmsg,qboolean reconnect)1041 void SV_Shutdown (char *finalmsg, qboolean reconnect)
1042 {
1043 	if (svs.clients)
1044 		SV_FinalMessage (finalmsg, reconnect);
1045 
1046 	Master_Shutdown ();
1047 	SV_ShutdownGameProgs ();
1048 
1049 	// free current level
1050 	if (sv.demofile)
1051 		fclose (sv.demofile);
1052 	memset (&sv, 0, sizeof(sv));
1053 	Com_SetServerState (sv.state);
1054 
1055 	// free server static data
1056 	if (svs.clients)
1057 		Z_Free (svs.clients);
1058 	if (svs.client_entities)
1059 		Z_Free (svs.client_entities);
1060 	if (svs.demofile)
1061 		fclose (svs.demofile);
1062 	memset (&svs, 0, sizeof(svs));
1063 }
1064 
1065