• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ServerPaused(void)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 */
SV_Shutdown(void)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 */
SV_Error(char * error,...)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 */
SV_FinalMessage(char * message)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 */
SV_DropClient(client_t * drop)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 */
SV_CalcPing(client_t * cl)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 */
SV_FullClientUpdate(client_t * client,sizebuf_t * buf)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 */
SV_FullClientUpdateToClient(client_t * client,client_t * cl)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 */
SVC_Status(void)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
SV_CheckLog(void)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 */
SVC_Log(void)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 */
SVC_Ping(void)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 */
SVC_GetChallenge(void)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 */
SVC_DirectConnect(void)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 
Rcon_Validate(void)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 */
SVC_RemoteCommand(void)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 */
SV_ConnectionlessPacket(void)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 */
StringToFilter(char * s,ipfilter_t * f)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 */
SV_AddIP_f(void)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 */
SV_RemoveIP_f(void)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 */
SV_ListIP_f(void)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 */
SV_WriteIP_f(void)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 */
SV_SendBan(void)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 */
SV_FilterPacket(void)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 */
SV_ReadPackets(void)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 */
SV_CheckTimeouts(void)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 */
SV_GetConsoleCommands(void)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 */
SV_CheckVars(void)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 */
SV_Frame(float time)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 */
SV_InitLocal(void)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
Master_Heartbeat(void)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 */
Master_Shutdown(void)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 */
SV_ExtractFromUserinfo(client_t * cl)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 */
SV_InitNet(void)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 */
SV_Init(quakeparms_t * parms)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