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
22 #ifndef CLIENTONLY
23 #include "qwsvdef.h"
24
25 #ifdef SERVERONLY
26
27 qbool host_initialized;
28 qbool host_everything_loaded; // true if OnChange() applied to every var, end of Host_Init()
29
30 double curtime; // not bounded or scaled, shared by local client and server.
31 double realtime; // affected by pause, you should not use it unless it something like physics and such.
32
33 static int host_hunklevel;
34
35 #else
36
37 qbool server_cfg_done = false;
38 double realtime; // affected by pause, you should not use it unless it something like physics and such.
39
40 #endif
41
42 int current_skill; // for entity spawnflags checking
43
44 client_t *sv_client; // current client
45
46 char master_rcon_password[128] = ""; //bliP: password for remote server commands
47
48 cvar_t sv_mintic = {"sv_mintic","0.013"}; // bound the size of the
49 cvar_t sv_maxtic = {"sv_maxtic","0.1"}; // physics time tic
50 cvar_t sv_maxfps = {"maxfps", "77", CVAR_SERVERINFO}; // It actually should be called maxpps (max packets per second).
51 // It was serverinfo variable for quite long time, lets legolize it as cvar.
52 // Sad part is what we can't call it like sv_maxfps since clients relay on its name 'maxfps' already.
53
54 void OnChange_sysselecttimeout_var (cvar_t *var, char *value, qbool *cancel);
55 cvar_t sys_select_timeout = {"sys_select_timeout", "10000", 0, OnChange_sysselecttimeout_var}; // microseconds.
56
57 cvar_t sys_restart_on_error = {"sys_restart_on_error", "0"};
58 cvar_t sv_mod_extensions = { "sv_mod_extensions", "2", CVAR_ROM };
59
60 #ifdef SERVERONLY
61 cvar_t sys_simulation = { "sys_simulation", "0" };
62 cvar_t developer = {"developer", "0"}; // show extra messages
63 cvar_t version = {"version", "", CVAR_ROM};
64 #endif
65
66 cvar_t timeout = {"timeout", "65"}; // seconds without any message
67 cvar_t zombietime = {"zombietime", "2"}; // seconds to sink messages
68 // after disconnect
69
70 #ifdef SERVERONLY
71 cvar_t rcon_password = {"rcon_password", ""}; // password for remote server commands
72 cvar_t password = {"password", ""}; // password for entering the game
73 #else
74 // client already have such variables.
75 extern cvar_t rcon_password;
76 extern cvar_t password;
77 #endif
78
79 cvar_t sv_hashpasswords = {"sv_hashpasswords", "1"}; // 0 - plain passwords; 1 - hashed passwords
80 cvar_t sv_crypt_rcon = {"sv_crypt_rcon", "1"}; // use SHA1 for encryption of rcon_password and using timestamps
81 // Time in seconds during which in rcon command this encryption is valid (change only with master_rcon_password).
82 cvar_t sv_timestamplen = {"sv_timestamplen", "60"};
83 cvar_t sv_rconlim = {"sv_rconlim", "10"}; // rcon bandwith limit: requests per second
84
85 //bliP: telnet log level
86 void OnChange_telnetloglevel_var (cvar_t *var, char *string, qbool *cancel);
87 cvar_t telnet_log_level = {"telnet_log_level", "0", 0, OnChange_telnetloglevel_var};
88 //<-
89
90 cvar_t frag_log_type = {"frag_log_type", "0"};
91 // frag log type:
92 // 0 - old style ( qwsv - v0.165)
93 // 1 - new style (v0.168 - v0.172)
94
95 void OnChange_qconsolelogsay_var (cvar_t *var, char *string, qbool *cancel);
96 cvar_t qconsole_log_say = {"qconsole_log_say", "0", 0, OnChange_qconsolelogsay_var};
97 // logging "say" and "say_team" messages to the qconsole_PORT.log file
98
99 cvar_t sys_command_line = {"sys_command_line", "", CVAR_ROM};
100
101 cvar_t sv_use_dns = {"sv_use_dns", "0"}; // 1 - use DNS lookup in status command, 0 - don't use
102 cvar_t spectator_password = {"spectator_password", ""}; // password for entering as a sepctator
103 cvar_t vip_password = {"vip_password", ""}; // password for entering as a VIP sepctator
104 cvar_t vip_values = {"vip_values", ""};
105
106 cvar_t allow_download = {"allow_download", "1"};
107 cvar_t allow_download_skins = {"allow_download_skins", "1"};
108 cvar_t allow_download_models = {"allow_download_models", "1"};
109 cvar_t allow_download_sounds = {"allow_download_sounds", "1"};
110 cvar_t allow_download_maps = {"allow_download_maps", "1"};
111 cvar_t allow_download_pakmaps = {"allow_download_pakmaps", "1"};
112 cvar_t allow_download_demos = {"allow_download_demos", "1"};
113 cvar_t allow_download_other = {"allow_download_other", "0"};
114 //bliP: init ->
115 cvar_t download_map_url = {"download_map_url", ""};
116
117 cvar_t sv_specprint = {"sv_specprint", "0"};
118 cvar_t sv_reconnectlimit = {"sv_reconnectlimit", "0"};
119
120 void OnChange_admininfo_var (cvar_t *var, char *string, qbool *cancel);
121 cvar_t sv_admininfo = {"sv_admininfo", "", 0, OnChange_admininfo_var};
122
123 cvar_t sv_unfake = {"sv_unfake", "1"}; //bliP: 24/9 kickfake to unfake
124 cvar_t sv_kicktop = {"sv_kicktop", "1"};
125
126 cvar_t sv_allowlastscores = {"sv_allowlastscores", "1"};
127
128 cvar_t sv_maxlogsize = {"sv_maxlogsize", "0"};
129 //bliP: 24/9 ->
130 void OnChange_logdir_var (cvar_t *var, char *string, qbool *cancel);
131 cvar_t sv_logdir = {"sv_logdir", ".", 0, OnChange_logdir_var};
132
133 cvar_t sv_speedcheck = {"sv_speedcheck", "1"};
134 //<-
135 //<-
136 //cvar_t sv_highchars = {"sv_highchars", "1"};
137 cvar_t sv_phs = {"sv_phs", "1"};
138 cvar_t pausable = {"pausable", "0"};
139 cvar_t sv_maxrate = {"sv_maxrate", "0"};
140 cvar_t sv_getrealip = {"sv_getrealip", "1"};
141 cvar_t sv_serverip = {"sv_serverip", ""};
142 cvar_t sv_forcespec_onfull = {"sv_forcespec_onfull", "2"};
143 cvar_t sv_maxdownloadrate = {"sv_maxdownloadrate", "0"};
144
145 cvar_t sv_loadentfiles = {"sv_loadentfiles", "1"}; //loads .ent files by default if there
146 cvar_t sv_loadentfiles_dir = {"sv_loadentfiles_dir", ""}; // check for .ent file in maps/sv_loadentfiles_dir first then just maps/
147 cvar_t sv_default_name = {"sv_default_name", "unnamed"};
148
149 void sv_mod_msg_file_OnChange(cvar_t *cvar, char *value, qbool *cancel);
150 cvar_t sv_mod_msg_file = {"sv_mod_msg_file", "", CVAR_NONE, sv_mod_msg_file_OnChange};
151
152 cvar_t sv_reliable_sound = {"sv_reliable_sound", "0"};
153
154 //
155 // game rules mirrored in svs.info
156 //
157 cvar_t fraglimit = {"fraglimit","0",CVAR_SERVERINFO};
158 cvar_t timelimit = {"timelimit","0",CVAR_SERVERINFO};
159 cvar_t teamplay = {"teamplay","0",CVAR_SERVERINFO};
160 cvar_t maxclients = {"maxclients","24",CVAR_SERVERINFO};
161 cvar_t maxspectators = {"maxspectators","8",CVAR_SERVERINFO};
162 cvar_t maxvip_spectators = {"maxvip_spectators","0"/*,CVAR_SERVERINFO*/};
163 cvar_t deathmatch = {"deathmatch","3",CVAR_SERVERINFO};
164 cvar_t watervis = {"watervis","0",CVAR_SERVERINFO};
165 cvar_t serverdemo = {"serverdemo","",CVAR_SERVERINFO | CVAR_ROM};
166
167 cvar_t samelevel = {"samelevel","1"}; // dont delete this variable - it used by mods
168 cvar_t skill = {"skill", "1"}; // dont delete this variable - it used by mods
169 cvar_t coop = {"coop", "0"}; // dont delete this variable - it used by mods
170
171 cvar_t sv_paused = {"sv_paused", "0", CVAR_ROM};
172
173 cvar_t hostname = {"hostname", "unnamed", CVAR_SERVERINFO};
174
175 cvar_t sv_forcenick = {"sv_forcenick", "0"}; //0 - don't force; 1 - as login;
176 cvar_t sv_registrationinfo = {"sv_registrationinfo", ""}; // text shown before "enter login"
177
178 // We need this cvar, because some mods didn't allow us to go at some placeses of, for example, start map.
179 cvar_t registered = {"registered", "1", CVAR_ROM};
180
181 cvar_t sv_halflifebsp = {"halflifebsp", "0", CVAR_ROM};
182 cvar_t sv_bspversion = {"sv_bspversion", "1", CVAR_ROM};
183
184 // If set, don't send broadcast messages, entities or player info to ServeMe bot
185 cvar_t sv_serveme_fix = { "sv_serveme_fix", "1", CVAR_ROM };
186
187 #ifdef FTE_PEXT_FLOATCOORDS
188 cvar_t sv_bigcoords = {"sv_bigcoords", "", CVAR_SERVERINFO};
189 #endif
190 #ifdef MVD_PEXT1_SERVERSIDEWEAPON
191 // Only enabled on KTX mod (see sv_init)
192 cvar_t sv_pext_mvdsv_serversideweapon = { "sv_pext_mvdsv_serversideweapon", "1" };
193 #endif
194
195 cvar_t sv_extlimits = { "sv_extlimits", "2" };
196
197 qbool sv_error = false;
198
199 client_t *WatcherId = NULL; // QW262
200
201 //============================================================================
202
GameStarted(void)203 qbool GameStarted(void)
204 {
205 mvddest_t *d;
206
207 for (d = demo.dest; d; d = d->nextdest)
208 if (d->desttype != DEST_STREAM) // oh, its not stream, treat as "game is started"
209 break;
210
211 return (d || strncasecmp(Info_ValueForKey(svs.info, "status"), "Standby", 8));
212 }
213 /*
214 ================
215 SV_Shutdown
216
217 Quake calls this before calling Sys_Quit or Sys_Error
218 ================
219 */
SV_Shutdown(char * finalmsg)220 void SV_Shutdown (char *finalmsg)
221 {
222 int i;
223
224 if (!sv.state)
225 return; // already shutdown. FIXME: what about error during SV_SpawnServer() ?
226
227 SV_FinalMessage(finalmsg);
228
229 Master_Shutdown ();
230
231 for (i = MIN_LOG; i < MAX_LOG; ++i)
232 {
233 if (logs[i].sv_logfile)
234 {
235 fclose (logs[i].sv_logfile);
236 logs[i].sv_logfile = NULL;
237 }
238 }
239 if (sv.mvdrecording)
240 SV_MVDStop_f();
241
242 #ifndef SERVER_ONLY
243 NET_CloseServer ();
244 #endif
245
246 #if defined(SERVERONLY) && defined(WWW_INTEGRATION)
247 Central_Shutdown();
248 #endif
249
250 // Shutdown game.
251 PR_GameShutDown();
252 PR_UnLoadProgs();
253
254 memset (&sv, 0, sizeof(sv));
255 sv.state = ss_dead;
256 #ifndef SERVERONLY
257 com_serveractive = false;
258 {
259 extern ctxinfo_t _localinfo_;
260
261 Info_RemoveAll(&_localinfo_);
262 for (i = 0; i < MAX_CLIENTS; ++i) {
263 Info_RemoveAll(&svs.clients[i]._userinfo_ctx_);
264 Info_RemoveAll(&svs.clients[i]._userinfoshort_ctx_);
265 }
266 }
267 #endif
268
269 memset (svs.clients, 0, sizeof(svs.clients));
270 svs.lastuserid = 0;
271 svs.serverflags = 0;
272 }
273
274 /*
275 ================
276 SV_Error
277
278 Sends a datagram to all the clients informing them of the server crash,
279 then exits
280 ================
281 */
SV_Error(char * error,...)282 void SV_Error (char *error, ...)
283 {
284 static qbool inerror = false;
285 static char string[1024];
286 va_list argptr;
287
288 sv_error = true;
289
290 if (inerror)
291 Sys_Error ("SV_Error: recursively entered (%s)", string);
292
293 inerror = true;
294
295 va_start (argptr, error);
296 vsnprintf (string, sizeof (string), error, argptr);
297 va_end (argptr);
298
299 SV_Shutdown (va ("SV_Error: %s\n", string));
300
301 Sys_Error ("SV_Error: %s", string);
302 }
303
SV_FreeHeadDelayedPacket(client_t * cl)304 static void SV_FreeHeadDelayedPacket(client_t *cl) {
305 if (cl->packets) {
306 packet_t *next = cl->packets->next;
307 cl->packets->next = svs.free_packets;
308 svs.free_packets = cl->packets;
309 cl->packets = next;
310 }
311 }
312
313
SV_FreeDelayedPackets(client_t * cl)314 void SV_FreeDelayedPackets (client_t *cl) {
315 while (cl->packets)
316 SV_FreeHeadDelayedPacket(cl);
317 }
318
319 /*
320 ==================
321 SV_FinalMessage
322
323 Used by SV_Error and SV_Quit_f to send a final message to all connected
324 clients before the server goes down. The messages are sent immediately,
325 not just stuck on the outgoing message list, because the server is going
326 to totally exit after returning from this function.
327 ==================
328 */
SV_FinalMessage(const char * message)329 void SV_FinalMessage (const char *message)
330 {
331 client_t *cl;
332 int i;
333
334 SZ_Clear (&net_message);
335 MSG_WriteByte (&net_message, svc_print);
336 MSG_WriteByte (&net_message, PRINT_HIGH);
337 MSG_WriteString (&net_message, message);
338 MSG_WriteByte (&net_message, svc_disconnect);
339
340 for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
341 if (cl->state >= cs_spawned
342 #ifdef USE_PR2
343 && !cl->isBot
344 #endif
345 ) {
346 Netchan_Transmit(&cl->netchan, net_message.cursize
347 , net_message.data);
348 }
349 }
350
351
352
353 /*
354 =====================
355 SV_DropClient
356
357 Called when the player is totally leaving the server, either willingly
358 or unwillingly. This is NOT called if the entire server is quiting
359 or crashing.
360 =====================
361 */
SV_DropClient(client_t * drop)362 void SV_DropClient(client_t* drop)
363 {
364 //bliP: cuff, mute ->
365 SV_SavePenaltyFilter (drop, ft_mute, drop->lockedtill);
366 SV_SavePenaltyFilter (drop, ft_cuff, drop->cuff_time);
367 //<-
368
369 //bliP: player logging
370 if (drop->name[0])
371 SV_LogPlayer(drop, "disconnect", 1);
372 //<-
373
374 // add the disconnect
375 #ifdef USE_PR2
376 if( drop->isBot )
377 {
378 extern void RemoveBot(client_t *cl);
379 RemoveBot(drop);
380 return;
381 }
382 #endif
383 MSG_WriteByte (&drop->netchan.message, svc_disconnect);
384
385 if (drop->state == cs_spawned)
386 {
387 // call the prog function for removing a client
388 // this will set the body to a dead frame, among other things
389 pr_global_struct->self = EDICT_TO_PROG(drop->edict);
390 PR_GameClientDisconnect(drop->spectator);
391 }
392
393 if (drop->spectator)
394 Con_Printf ("Spectator %s removed\n",drop->name);
395 else
396 Con_Printf ("Client %s removed\n",drop->name);
397
398 if (drop->download)
399 {
400 VFS_CLOSE(drop->download);
401 drop->download = NULL;
402 }
403 if (drop->upload)
404 {
405 fclose (drop->upload);
406 drop->upload = NULL;
407 }
408 *drop->uploadfn = 0;
409
410 SV_Logout(drop);
411
412 drop->state = cs_zombie; // become free in a few seconds
413 SV_SetClientConnectionTime(drop); // for zombie timeout
414
415 // MD -->
416 if (drop == WatcherId)
417 WatcherId = NULL;
418 // <-- MD
419
420 drop->old_frags = 0;
421 drop->edict->v.frags = 0.0;
422 drop->name[0] = 0;
423
424 Info_RemoveAll(&drop->_userinfo_ctx_);
425 Info_RemoveAll(&drop->_userinfoshort_ctx_);
426
427 // send notification to all remaining clients
428 SV_FullClientUpdate(drop, &sv.reliable_datagram);
429 }
430
431
432 //====================================================================
433
434 /*
435 ===================
436 SV_CalcPing
437
438 ===================
439 */
SV_CalcPing(client_t * cl)440 int SV_CalcPing (client_t *cl)
441 {
442 register client_frame_t *frame;
443 int count, i;
444 float ping;
445
446
447 //bliP: 999 ping for connecting players
448 if (cl->state != cs_spawned)
449 return 999;
450 //<-
451
452 ping = 0;
453 count = 0;
454 #ifdef USE_PR2
455 if (cl->isBot) {
456 return 10;
457 }
458 #endif
459 for (frame = cl->frames, i=0 ; i<UPDATE_BACKUP ; i++, frame++)
460 {
461 if (frame->ping_time > 0)
462 {
463 ping += frame->ping_time;
464 count++;
465 }
466 }
467 if (!count)
468 return 9999;
469 ping /= count;
470
471 return ping*1000;
472 }
473
474 /*
475 ===================
476 SV_FullClientUpdate
477
478 Writes all update values to a sizebuf
479 ===================
480 */
SV_FullClientUpdate(client_t * client,sizebuf_t * buf)481 void SV_FullClientUpdate (client_t *client, sizebuf_t *buf)
482 {
483 char info[MAX_EXT_INFO_STRING];
484 int i;
485
486 i = client - svs.clients;
487
488 //Sys_Printf("SV_FullClientUpdate: Updated frags for client %d\n", i);
489
490 MSG_WriteByte (buf, svc_updatefrags);
491 MSG_WriteByte (buf, i);
492 MSG_WriteShort (buf, client->old_frags);
493
494 MSG_WriteByte (buf, svc_updateping);
495 MSG_WriteByte (buf, i);
496 MSG_WriteShort (buf, SV_CalcPing (client));
497
498 MSG_WriteByte (buf, svc_updatepl);
499 MSG_WriteByte (buf, i);
500 MSG_WriteByte (buf, client->lossage);
501
502 MSG_WriteByte (buf, svc_updateentertime);
503 MSG_WriteByte (buf, i);
504 MSG_WriteFloat (buf, SV_ClientGameTime(client));
505
506 Info_ReverseConvert(&client->_userinfoshort_ctx_, info, sizeof(info));
507 Info_RemovePrefixedKeys (info, '_'); // server passwords, etc
508
509 MSG_WriteByte (buf, svc_updateuserinfo);
510 MSG_WriteByte (buf, i);
511 MSG_WriteLong (buf, client->userid);
512 MSG_WriteString (buf, info);
513 }
514
515 /*
516 ===================
517 SV_FullClientUpdateToClient
518
519 Writes all update values to a client's reliable stream
520 ===================
521 */
SV_FullClientUpdateToClient(client_t * client,client_t * cl)522 void SV_FullClientUpdateToClient (client_t *client, client_t *cl)
523 {
524 char info[MAX_EXT_INFO_STRING];
525
526 Info_ReverseConvert(&client->_userinfoshort_ctx_, info, sizeof(info));
527
528 ClientReliableCheckBlock(cl, 24 + strlen(info));
529 if (cl->num_backbuf)
530 {
531 SV_FullClientUpdate (client, &cl->backbuf);
532 ClientReliable_FinishWrite(cl);
533 }
534 else
535 SV_FullClientUpdate (client, &cl->netchan.message);
536 }
537
538 //Returns a unique userid in [1..MAXUSERID] range
539 #define MAXUSERID 99
SV_GenerateUserID(void)540 int SV_GenerateUserID (void)
541 {
542 client_t *cl;
543 int i;
544
545
546 do {
547 svs.lastuserid++;
548 if (svs.lastuserid == 1 + MAXUSERID)
549 svs.lastuserid = 1;
550 for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
551 if (cl->state != cs_free && cl->userid == svs.lastuserid)
552 break;
553 } while (i != MAX_CLIENTS);
554
555 return svs.lastuserid;
556 }
557
558 /*
559 ==============================================================================
560
561 CONNECTIONLESS COMMANDS
562
563 ==============================================================================
564 */
565
566 /*
567 SVC_QTVStreams
568
569 Responds with info on connected QTV users
570 */
SVC_QTVUsers(void)571 static void SVC_QTVUsers (void)
572 {
573 SV_BeginRedirect (RD_PACKET);
574 QTV_Streams_UserList ();
575 SV_EndRedirect ();
576 }
577
578 /*
579 ================
580 SVC_Status
581
582 Responds with all the info that qplug or qspy can see
583 This message can be up to around 5k with worst case string lengths.
584 ================
585 */
586 #define STATUS_OLDSTYLE 0
587 #define STATUS_SERVERINFO 1
588 #define STATUS_PLAYERS 2
589 #define STATUS_SPECTATORS 4
590 #define STATUS_SPECTATORS_AS_PLAYERS 8 //for ASE - change only frags: show as "S"
591 #define STATUS_SHOWTEAMS 16
592 #define STATUS_SHOWQTV 32
593 #define STATUS_SHOWFLAGS 64
594
SVC_Status(void)595 static void SVC_Status (void)
596 {
597 int top, bottom, ping, i, opt = 0;
598 char *name, *frags;
599 client_t *cl;
600
601
602 if (Cmd_Argc() > 1)
603 opt = Q_atoi(Cmd_Argv(1));
604
605 SV_BeginRedirect (RD_PACKET);
606 if (opt == STATUS_OLDSTYLE || (opt & STATUS_SERVERINFO))
607 Con_Printf ("%s\n", svs.info);
608 if (opt == STATUS_OLDSTYLE || (opt & (STATUS_PLAYERS | STATUS_SPECTATORS)))
609 for (i = 0; i < MAX_CLIENTS; i++)
610 {
611 cl = &svs.clients[i];
612 if ( (cl->state >= cs_preconnected/* || cl->state == cs_spawned */) &&
613 ( (!cl->spectator && ((opt & STATUS_PLAYERS) || opt == STATUS_OLDSTYLE)) ||
614 ( cl->spectator && ( opt & STATUS_SPECTATORS)) ) )
615 {
616 top = Q_atoi(Info_Get (&cl->_userinfo_ctx_, "topcolor"));
617 bottom = Q_atoi(Info_Get (&cl->_userinfo_ctx_, "bottomcolor"));
618 top = (top < 0) ? 0 : ((top > 13) ? 13 : top);
619 bottom = (bottom < 0) ? 0 : ((bottom > 13) ? 13 : bottom);
620 ping = SV_CalcPing (cl);
621 name = cl->name;
622 if (cl->spectator)
623 {
624 if (opt & STATUS_SPECTATORS_AS_PLAYERS)
625 frags = "S";
626 else
627 {
628 ping = -ping;
629 frags = "-9999";
630 name = va("\\s\\%s", name);
631 }
632 }
633 else
634 frags = va("%i", cl->old_frags);
635
636 Con_Printf ("%i %s %i %i \"%s\" \"%s\" %i %i", cl->userid, frags,
637 (int)(SV_ClientConnectedTime(cl) / 60.0f), ping, name,
638 Info_Get (&cl->_userinfo_ctx_, "skin"), top, bottom);
639
640 if (opt & STATUS_SHOWTEAMS) {
641 Con_Printf(" \"%s\"", cl->team);
642 }
643
644 if (opt & STATUS_SHOWFLAGS) {
645 if (cl->login_flag[0]) {
646 Con_Printf(" \"%s\"", cl->login_flag);
647 }
648 else if (cl->logged_in_via_web || cl->logged > 0) {
649 Con_Printf(" \"none\"");
650 }
651 else {
652 Con_Printf(" \"\"");
653 }
654 }
655
656 Con_Printf("\n");
657 }
658 }
659
660 if (opt & STATUS_SHOWQTV)
661 QTV_Streams_List ();
662 SV_EndRedirect ();
663 }
664
665 /*
666 ===================
667 SVC_LastScores
668
669 ===================
670 */
671 void SV_LastScores_f (void);
SVC_LastScores(void)672 static void SVC_LastScores (void)
673 {
674 if(!(int)sv_allowlastscores.value)
675 return;
676
677 SV_BeginRedirect (RD_PACKET);
678 SV_LastScores_f ();
679 SV_EndRedirect ();
680 }
681
682 /*
683 ===================
684 SVC_DemoList
685 SVC_DemoListRegex
686 ===================
687 */
688 void SV_DemoList_f (void);
SVC_DemoList(void)689 static void SVC_DemoList (void)
690 {
691 SV_BeginRedirect (RD_PACKET);
692 SV_DemoList_f ();
693 SV_EndRedirect ();
694 }
695 void SV_DemoListRegex_f (void);
SVC_DemoListRegex(void)696 static void SVC_DemoListRegex (void)
697 {
698 SV_BeginRedirect (RD_PACKET);
699 SV_DemoListRegex_f ();
700 SV_EndRedirect ();
701 }
702
703 /*
704 ===================
705 SV_CheckLog
706
707 ===================
708 */
709 #define LOG_HIGHWATER (MAX_DATAGRAM - 128)
710 #define LOG_FLUSH 10*60
SV_CheckLog(void)711 static void SV_CheckLog (void)
712 {
713 sizebuf_t *sz;
714
715 if (sv.state != ss_active)
716 return;
717
718 sz = &svs.log[svs.logsequence&1];
719
720 // bump sequence if allmost full, or ten minutes have passed and
721 // there is something still sitting there
722 if (sz->cursize > LOG_HIGHWATER
723 || (realtime - svs.logtime > LOG_FLUSH && sz->cursize) )
724 {
725 // swap buffers and bump sequence
726 svs.logtime = realtime;
727 svs.logsequence++;
728 sz = &svs.log[svs.logsequence&1];
729 sz->cursize = 0;
730 Con_DPrintf ("beginning fraglog sequence %i\n", svs.logsequence);
731 }
732
733 }
734
735 /*
736 ================
737 SVC_Log
738
739 Responds with all the logged frags for ranking programs.
740 If a sequence number is passed as a parameter and it is
741 the same as the current sequence, an A2A_NACK will be returned
742 instead of the data.
743 ================
744 */
SVC_Log(void)745 static void SVC_Log (void)
746 {
747 char data[MAX_DATAGRAM+64];
748 int seq;
749
750
751 if (Cmd_Argc() == 2)
752 seq = Q_atoi(Cmd_Argv(1));
753 else
754 seq = -1;
755
756 if (seq == svs.logsequence-1 || !logs[FRAG_LOG].sv_logfile)
757 { // they already have this data, or we aren't logging frags
758 data[0] = A2A_NACK;
759 NET_SendPacket (NS_SERVER, 1, data, net_from);
760 return;
761 }
762
763 Con_DPrintf ("sending log %i to %s\n", svs.logsequence-1, NET_AdrToString(net_from));
764
765 snprintf (data, MAX_DATAGRAM + 64, "stdlog %i\n", svs.logsequence-1);
766 strlcat (data, (char *)svs.log_buf[((svs.logsequence-1)&1)], MAX_DATAGRAM + 64);
767
768 NET_SendPacket (NS_SERVER, strlen(data)+1, data, net_from);
769 }
770
771 /*
772 ================
773 SVC_Ping
774
775 Just responds with an acknowledgement
776 ================
777 */
SVC_Ping(void)778 static void SVC_Ping (void)
779 {
780 char data = A2A_ACK;
781
782 NET_SendPacket (NS_SERVER, 1, &data, net_from);
783 }
784
785 /*
786 =================
787 SVC_GetChallenge
788
789 Returns a challenge number that can be used
790 in a subsequent client_connect command.
791 We do this to prevent denial of service attacks that
792 flood the server with invalid connection IPs. With a
793 challenge, they must give a valid IP address.
794 =================
795 */
SVC_GetChallenge(void)796 static void SVC_GetChallenge (void)
797 {
798 int oldestTime, oldest, i;
799 char buf[256], *over;
800
801
802 oldest = 0;
803 oldestTime = 0x7fffffff;
804
805 // see if we already have a challenge for this ip
806 for (i = 0 ; i < MAX_CHALLENGES ; i++)
807 {
808 if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
809 break;
810 if (svs.challenges[i].time < oldestTime)
811 {
812 oldestTime = svs.challenges[i].time;
813 oldest = i;
814 }
815 }
816
817 if (i == MAX_CHALLENGES)
818 {
819 // overwrite the oldest
820 svs.challenges[oldest].challenge = (rand() << 16) ^ rand();
821 svs.challenges[oldest].adr = net_from;
822 svs.challenges[oldest].time = realtime;
823 i = oldest;
824 }
825
826 // send it back
827 snprintf(buf, sizeof(buf), "%c%i", S2C_CHALLENGE, svs.challenges[i].challenge);
828 over = buf + strlen(buf) + 1;
829
830 #ifdef PROTOCOL_VERSION_FTE
831 //tell the client what fte extensions we support
832 if (svs.fteprotocolextensions)
833 {
834 int lng;
835
836 lng = LittleLong(PROTOCOL_VERSION_FTE);
837 memcpy(over, &lng, sizeof(int));
838 over += 4;
839
840 lng = LittleLong(svs.fteprotocolextensions);
841 memcpy(over, &lng, sizeof(int));
842 over += 4;
843 }
844 #endif // PROTOCOL_VERSION_FTE
845
846 #ifdef PROTOCOL_VERSION_FTE2
847 //tell the client what fte extensions2 we support
848 if (svs.fteprotocolextensions2)
849 {
850 int lng;
851
852 lng = LittleLong(PROTOCOL_VERSION_FTE2);
853 memcpy(over, &lng, sizeof(int));
854 over += 4;
855
856 lng = LittleLong(svs.fteprotocolextensions2);
857 memcpy(over, &lng, sizeof(int));
858 over += 4;
859 }
860 #endif // PROTOCOL_VERSION_FTE2
861
862 #ifdef PROTOCOL_VERSION_MVD1
863 // tell the client what mvdsv extensions we support
864 if (svs.mvdprotocolextension1) {
865 int lng;
866
867 lng = LittleLong(PROTOCOL_VERSION_MVD1);
868 memcpy(over, &lng, sizeof(int));
869 over += 4;
870
871 lng = LittleLong(svs.mvdprotocolextension1);
872 memcpy(over, &lng, sizeof(int));
873 over += 4;
874 }
875 #endif
876
877 Netchan_OutOfBand(NS_SERVER, net_from, over-buf, (byte*) buf);
878 }
879
ValidateUserInfo(char * userinfo)880 static qbool ValidateUserInfo (char *userinfo)
881 {
882 if (strstr(userinfo, "&c") || strstr(userinfo, "&r"))
883 return false;
884
885 while (*userinfo)
886 {
887 if (*userinfo == '\\')
888 userinfo++;
889
890 if (*userinfo++ == '\\')
891 return false;
892 while (*userinfo && *userinfo != '\\')
893 userinfo++;
894 }
895 return true;
896 }
897
898 //==============================================
899
FixMaxClientsCvars(void)900 void FixMaxClientsCvars(void)
901 {
902 if ((int)maxclients.value > MAX_CLIENTS)
903 Cvar_SetValue (&maxclients, MAX_CLIENTS);
904
905 if ((int)maxspectators.value > MAX_CLIENTS)
906 Cvar_SetValue (&maxspectators, MAX_CLIENTS);
907
908 if ((int)maxvip_spectators.value > MAX_CLIENTS)
909 Cvar_SetValue (&maxvip_spectators, MAX_CLIENTS);
910
911 if ((int)maxspectators.value + maxclients.value > MAX_CLIENTS)
912 Cvar_SetValue (&maxspectators, MAX_CLIENTS - (int)maxclients.value);
913
914 if ((int)maxspectators.value + maxclients.value + maxvip_spectators.value > MAX_CLIENTS)
915 Cvar_SetValue (&maxvip_spectators, MAX_CLIENTS - (int)maxclients.value - (int)maxspectators.value);
916
917 }
918
919 //==============================================
920
921 // see if the challenge is valid
CheckChallange(int challenge)922 qbool CheckChallange( int challenge )
923 {
924 int i;
925
926 if (net_from.type == NA_LOOPBACK)
927 return true; // local client do not need challenge
928
929 for (i = 0; i < MAX_CHALLENGES; i++)
930 {
931 if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
932 {
933 if (challenge == svs.challenges[i].challenge)
934 break; // good
935
936 Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nBad challenge.\n", A2C_PRINT);
937 return false;
938 }
939 }
940
941 if (i == MAX_CHALLENGES)
942 {
943 Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nNo challenge for address.\n", A2C_PRINT);
944 return false;
945 }
946
947 return true;
948 }
949
950 //==============================================
951
CheckProtocol(int ver)952 qbool CheckProtocol( int ver )
953 {
954 if (ver != PROTOCOL_VERSION)
955 {
956 Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nServer is version " QW_VERSION ".\n", A2C_PRINT);
957 Con_Printf ("* rejected connect from version %i\n", ver);
958 return false;
959 }
960
961 return true;
962 }
963
964 //==============================================
965
CheckUserinfo(char * userinfobuf,unsigned int bufsize,char * userinfo)966 qbool CheckUserinfo( char *userinfobuf, unsigned int bufsize, char *userinfo )
967 {
968 strlcpy (userinfobuf, userinfo, bufsize);
969
970 // and now validate userinfo
971 if ( !ValidateUserInfo( userinfobuf ) )
972 {
973 Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nInvalid userinfo, perhaps &c sequences. Restart your qwcl\n", A2C_PRINT);
974 return false;
975 }
976
977 return true;
978 }
979
980 //==============================================
981
982 int SV_VIPbyIP(netadr_t adr);
983 int SV_VIPbyPass (char *pass);
984
CheckPasswords(char * userinfo,int userinfo_size,qbool * spass_ptr,qbool * vip_ptr,int * spectator_ptr)985 qbool CheckPasswords( char *userinfo, int userinfo_size, qbool *spass_ptr, qbool *vip_ptr, int *spectator_ptr )
986 {
987 int spectator;
988 qbool spass, vip;
989
990 char *s = Info_ValueForKey (userinfo, "spectator");
991 char *pwd;
992
993 spass = vip = spectator = false;
994
995 if (s[0] && strcmp(s, "0"))
996 {
997 spass = true;
998
999 // first the pass, then ip
1000 if ( !( vip = SV_VIPbyPass( s ) ) )
1001 {
1002 if ( !( vip = SV_VIPbyPass( Info_ValueForKey( userinfo, "password") ) ) )
1003 {
1004 vip = SV_VIPbyIP( net_from );
1005 }
1006 }
1007
1008 pwd = spectator_password.string;
1009
1010 if (pwd[0] && strcasecmp(pwd, "none") && strcmp(pwd, s))
1011 {
1012 spass = false; // failed
1013 }
1014
1015 if (!vip && !spass)
1016 {
1017 Con_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from));
1018 Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT);
1019
1020 return false;
1021 }
1022
1023 Info_RemoveKey (userinfo, "spectator"); // remove passwd
1024 Info_SetValueForStarKey (userinfo, "*spectator", "1", userinfo_size);
1025
1026 spectator = Q_atoi(s);
1027
1028 if (!spectator)
1029 spectator = true;
1030 }
1031 else
1032 {
1033 s = Info_ValueForKey (userinfo, "password");
1034
1035 // first the pass, then ip
1036 if (!(vip = SV_VIPbyPass(s)))
1037 {
1038 vip = SV_VIPbyIP(net_from);
1039 }
1040
1041 pwd = password.string;
1042
1043 if (!vip && pwd[0] && strcasecmp(pwd, "none") && strcmp(pwd, s))
1044 {
1045 Con_Printf ("%s:password failed\n", NET_AdrToString (net_from));
1046 Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nserver requires a password\n\n", A2C_PRINT);
1047
1048 return false;
1049 }
1050
1051 Info_RemoveKey (userinfo, "spectator"); // remove "spectator 0" for example
1052
1053 spectator = false;
1054 }
1055
1056 Info_RemoveKey (userinfo, "password"); // remove passwd
1057
1058 // copy
1059 *spass_ptr = spass;
1060 *vip_ptr = vip;
1061 *spectator_ptr = spectator;
1062
1063 return true;
1064 }
1065
1066 //==============================================
1067
CheckReConnect(netadr_t adr,int qport)1068 qbool CheckReConnect( netadr_t adr, int qport )
1069 {
1070 int i;
1071 client_t *cl;
1072
1073 for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
1074 {
1075 if (cl->state == cs_free)
1076 continue;
1077
1078 if (NET_CompareBaseAdr (adr, cl->netchan.remote_address) &&
1079 (cl->netchan.qport == qport || adr.port == cl->netchan.remote_address.port))
1080 {
1081 if (SV_ClientConnectedTime(cl) < sv_reconnectlimit.value)
1082 {
1083 Con_Printf ("%s:reconnect rejected: too soon\n", NET_AdrToString (adr));
1084 return false;
1085 }
1086
1087 switch ( cl->state )
1088 {
1089 case cs_zombie: // zombie already dropped.
1090 break;
1091
1092 case cs_preconnected:
1093 case cs_connected:
1094 case cs_spawned:
1095
1096 SV_DropClient (cl);
1097 SV_ClearReliable (cl); // don't send the disconnect
1098 break;
1099
1100 default:
1101 return false; // unknown state, should not be the case.
1102 }
1103
1104 cl->state = cs_free;
1105 Con_Printf ("%s:reconnect\n", NET_AdrToString (adr));
1106 break;
1107 }
1108 }
1109
1110 return true;
1111 }
1112
1113 //==============================================
1114
CountPlayersSpecsVips(int * clients_ptr,int * spectators_ptr,int * vips_ptr,client_t ** newcl_ptr)1115 void CountPlayersSpecsVips(int *clients_ptr, int *spectators_ptr, int *vips_ptr, client_t **newcl_ptr)
1116 {
1117 client_t *cl = NULL, *newcl = NULL;
1118 int clients = 0, spectators = 0, vips = 0;
1119 int i;
1120
1121 for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
1122 {
1123 if (cl->state == cs_free)
1124 {
1125 if (!newcl)
1126 newcl = cl; // grab first available slot
1127
1128 continue;
1129 }
1130
1131 if (cl->spectator)
1132 {
1133 if (cl->vip)
1134 vips++;
1135 else
1136 spectators++;
1137 }
1138 else
1139 {
1140 clients++;
1141 }
1142 }
1143
1144 if (clients_ptr)
1145 *clients_ptr = clients;
1146 if (spectators_ptr)
1147 *spectators_ptr = spectators;
1148 if (vips_ptr)
1149 *vips_ptr = vips;
1150 if (newcl_ptr)
1151 *newcl_ptr = newcl;
1152 }
1153
1154 //==============================================
1155
SpectatorCanConnect(int vip,int spass,int spectators,int vips)1156 qbool SpectatorCanConnect(int vip, int spass, int spectators, int vips)
1157 {
1158 FixMaxClientsCvars(); // not a bad idea
1159
1160 if (vip)
1161 {
1162 if (spass && (spectators < (int)maxspectators.value || vips < (int)maxvip_spectators.value))
1163 return true;
1164 }
1165 else
1166 {
1167 if (spass && spectators < (int)maxspectators.value)
1168 return true;
1169 }
1170
1171 return false;
1172 }
1173
PlayerCanConnect(int clients)1174 qbool PlayerCanConnect(int clients)
1175 {
1176 FixMaxClientsCvars(); // not a bad idea
1177
1178 if (clients < (int)maxclients.value)
1179 return true;
1180
1181 return false;
1182 }
1183
1184 /*
1185 ==================
1186 SVC_DirectConnect
1187
1188 A connection request that did not come from the master
1189 ==================
1190 */
1191 extern void MVD_PlayerReset(int player);
1192
1193 extern char *shortinfotbl[];
1194
SVC_DirectConnect(void)1195 static void SVC_DirectConnect (void)
1196 {
1197 int spectator;
1198 qbool spass, vip, rip_vip;
1199
1200 int clients, spectators, vips;
1201 int qport, i, edictnum;
1202
1203 client_t *newcl;
1204
1205 char userinfo[1024];
1206 char *s;
1207 netadr_t adr;
1208 edict_t *ent;
1209
1210 #ifdef PROTOCOL_VERSION_FTE
1211 unsigned int protextsupported = 0;
1212 #endif // PROTOCOL_VERSION_FTE
1213
1214 #ifdef PROTOCOL_VERSION_FTE2
1215 unsigned int protextsupported2 = 0;
1216 #endif // PROTOCOL_VERSION_FTE2
1217
1218 #ifdef PROTOCOL_VERSION_MVD1
1219 unsigned int mvdext_supported1 = 0;
1220 #endif
1221
1222 // check version/protocol
1223 if ( !CheckProtocol( Q_atoi( Cmd_Argv( 1 ) ) ) )
1224 return; // wrong protocol number
1225
1226 // get qport
1227 qport = Q_atoi( Cmd_Argv( 2 ) );
1228
1229 // see if the challenge is valid
1230 if ( !CheckChallange( Q_atoi( Cmd_Argv( 3 ) ) ) )
1231 return; // wrong challange
1232
1233 // and now validate userinfo
1234 if ( !CheckUserinfo( userinfo, sizeof( userinfo ), Cmd_Argv( 4 ) ) )
1235 return; // wrong userinfo
1236
1237 //
1238 // WARNING: WARNING: WARNING: using Cmd_TokenizeString() so do all Cmd_Argv() above.
1239 //
1240
1241 while( !msg_badread )
1242 {
1243 Cmd_TokenizeString( MSG_ReadStringLine() );
1244
1245 switch( Q_atoi( Cmd_Argv( 0 ) ) )
1246 {
1247 #ifdef PROTOCOL_VERSION_FTE
1248 case PROTOCOL_VERSION_FTE:
1249 protextsupported = Q_atoi( Cmd_Argv( 1 ) );
1250 Con_DPrintf("Client supports 0x%x fte extensions\n", protextsupported);
1251 break;
1252 #endif // PROTOCOL_VERSION_FTE
1253
1254 #ifdef PROTOCOL_VERSION_FTE2
1255 case PROTOCOL_VERSION_FTE2:
1256 protextsupported2 = Q_atoi( Cmd_Argv( 1 ) );
1257 Con_DPrintf("Client supports 0x%x fte extensions2\n", protextsupported2);
1258 break;
1259 #endif // PROTOCOL_VERSION_FTE2
1260
1261 #ifdef PROTOCOL_VERSION_MVD1
1262 case PROTOCOL_VERSION_MVD1:
1263 mvdext_supported1 = Q_atoi( Cmd_Argv( 1 ) );
1264 Con_DPrintf("Client supports 0x%x mvdsv extensions\n", mvdext_supported1);
1265 break;
1266 #endif
1267 }
1268 }
1269
1270 msg_badread = false;
1271
1272 spass = vip = rip_vip = spectator = false;
1273
1274 // check for password or spectator_password
1275 if ( !CheckPasswords( userinfo, sizeof(userinfo), &spass, &vip, &spectator) )
1276 return; // pass was wrong
1277
1278 adr = net_from;
1279
1280 // if there is already a slot for this ip, reuse (changed from drop) it
1281 if ( !CheckReConnect( adr, qport ) )
1282 return; // can't do that for some reason
1283
1284 // count up the clients and spectators
1285 CountPlayersSpecsVips(&clients, &spectators, &vips, &newcl);
1286
1287 FixMaxClientsCvars();
1288
1289 // if at server limits, refuse connection
1290
1291 if ((spectator && !SpectatorCanConnect(vip, spass, spectators, vips)) ||
1292 (!spectator && !PlayerCanConnect(clients)) ||
1293 !newcl)
1294 {
1295 Sys_Printf ("%s:full connect\n", NET_AdrToString (adr));
1296
1297 // no way to connect does't matter VIP or whatever, just no free slots
1298 if (!newcl)
1299 {
1300 Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full\n\n", A2C_PRINT);
1301 return;
1302 }
1303
1304 // !!! SPECTATOR 2 FEATURE !!!
1305 if (spectator == 2 && !vip && vips < (int)maxvip_spectators.value)
1306 {
1307 vip = rip_vip = 1; // yet can be connected if realip is on vip list
1308 }
1309 else if ( !spectator && spectators < (int)maxspectators.value
1310 && (
1311 ( (int)sv_forcespec_onfull.value == 2
1312 && (Q_atoi(Info_ValueForKey(userinfo, "svf")) & SVF_SPEC_ONFULL)
1313 )
1314 ||
1315 ( (int)sv_forcespec_onfull.value == 1
1316 && !(Q_atoi(Info_ValueForKey(userinfo, "svf")) & SVF_NO_SPEC_ONFULL)
1317 )
1318 )
1319 )
1320 {
1321 Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full: connecting as spectator\n", A2C_PRINT);
1322 Info_SetValueForStarKey (userinfo, "*spectator", "1", sizeof(userinfo));
1323 spectator = true;
1324 }
1325 else
1326 {
1327 Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full\n\n", A2C_PRINT);
1328 return;
1329 }
1330 }
1331
1332 // build a new connection
1333 // accept the new client
1334 // this is the only place a client_t is ever initialized
1335 memset (newcl, 0, sizeof(*newcl));
1336
1337 newcl->userid = SV_GenerateUserID();
1338
1339 #ifdef PROTOCOL_VERSION_FTE
1340 newcl->fteprotocolextensions = protextsupported;
1341 #endif // PROTOCOL_VERSION_FTE
1342
1343 #ifdef PROTOCOL_VERSION_FTE2
1344 newcl->fteprotocolextensions2 = protextsupported2;
1345 #endif // PROTOCOL_VERSION_FTE2
1346
1347 #ifdef PROTOCOL_VERSION_MVD1
1348 newcl->mvdprotocolextensions1 = mvdext_supported1;
1349 #endif
1350
1351 newcl->_userinfo_ctx_.max = MAX_CLIENT_INFOS;
1352 newcl->_userinfoshort_ctx_.max = MAX_CLIENT_INFOS;
1353 Info_Convert(&newcl->_userinfo_ctx_, userinfo);
1354
1355 // request protocol extensions.
1356 if (*Info_Get(&newcl->_userinfo_ctx_, "Qizmo")
1357 || *Info_Get(&newcl->_userinfo_ctx_, "*qtv")
1358 )
1359 {
1360 newcl->process_pext = false; // this whould not work over such proxies.
1361 }
1362 else
1363 {
1364 newcl->process_pext = true;
1365 }
1366
1367 Netchan_OutOfBandPrint (NS_SERVER, adr, "%c", S2C_CONNECTION);
1368
1369 Netchan_Setup (NS_SERVER, &newcl->netchan, adr, qport, Q_atoi(Info_Get(&newcl->_userinfo_ctx_, "mtu")));
1370
1371 newcl->state = cs_preconnected;
1372
1373 newcl->datagram.allowoverflow = true;
1374 newcl->datagram.data = newcl->datagram_buf;
1375 newcl->datagram.maxsize = sizeof(newcl->datagram_buf);
1376
1377 // spectator mode can ONLY be set at join time
1378 newcl->spectator = spectator;
1379 newcl->vip = vip;
1380 newcl->rip_vip = rip_vip;
1381
1382 // extract extensions mask
1383 newcl->extensions = Q_atoi(Info_Get(&newcl->_userinfo_ctx_, "*z_ext"));
1384 Info_Remove (&newcl->_userinfo_ctx_, "*z_ext");
1385
1386 edictnum = (newcl-svs.clients)+1;
1387 ent = EDICT_NUM(edictnum);
1388 ent->e->free = false;
1389 newcl->edict = ent;
1390 // restore client name.
1391 PR_SetEntityString(ent, ent->v.netname, newcl->name);
1392
1393 s = ( vip ? va("%d", vip) : "" );
1394
1395 Info_SetStar (&newcl->_userinfo_ctx_, "*VIP", s);
1396
1397 // copy the most important userinfo into userinfoshort
1398 // {
1399
1400 // parse some info from the info strings
1401 SV_ExtractFromUserinfo (newcl, true);
1402
1403 for (i = 0; shortinfotbl[i] != NULL; i++)
1404 {
1405 s = Info_Get(&newcl->_userinfo_ctx_, shortinfotbl[i]);
1406 Info_SetStar (&newcl->_userinfoshort_ctx_, shortinfotbl[i], s);
1407 }
1408
1409 // move star keys to infoshort
1410 Info_CopyStar( &newcl->_userinfo_ctx_, &newcl->_userinfoshort_ctx_ );
1411
1412 // }
1413
1414 // JACK: Init the floodprot stuff.
1415 memset(newcl->whensaid, 0, sizeof(newcl->whensaid));
1416 newcl->whensaidhead = 0;
1417 newcl->lockedtill = 0;
1418 newcl->disable_updates_stop = -1.0; // Vladis
1419
1420 newcl->realip_num = rand();
1421
1422 //bliP: init
1423 newcl->spec_print = (int)sv_specprint.value;
1424 newcl->logincount = 0;
1425 //<-
1426
1427 #ifdef FTE_PEXT2_VOICECHAT
1428 SV_VoiceInitClient(newcl);
1429 #endif
1430
1431 // call the progs to get default spawn parms for the new client
1432 PR_GameSetNewParms();
1433
1434 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
1435 newcl->spawn_parms[i] = (&PR_GLOBAL(parm1))[i];
1436
1437 // mvd/qtv related stuff
1438 // Well, here is a chance what player connect after demo recording started,
1439 // so demo.info[edictnum - 1].model == player_model so SV_MVDWritePackets() will not wrote player model index,
1440 // so client during playback this demo will got invisible model, because model index will be 0.
1441 // Fixing that.
1442 // Btw, struct demo contain different client specific structs, may be they need clearing too, not sure.
1443 // Also, we have Cmd_Join_f()/Cmd_Observe_f() which have close behaviour to SVC_DirectConnect(),
1444 // so I put same demo fix in mentioned functions too.
1445 MVD_PlayerReset(NUM_FOR_EDICT(newcl->edict) - 1);
1446
1447 newcl->sendinfo = true;
1448 }
1449
char2int(int c)1450 static int char2int (int c)
1451 {
1452 if (c <= '9' && c >= '0')
1453 return c - '0';
1454 else if (c <= 'f' && c >= 'a')
1455 return c - 'a' + 10;
1456 else if (c <= 'F' && c >= 'A')
1457 return c - 'A' + 10;
1458 return 0;
1459 }
1460 /*
1461 * rcon_bandlim() - check for rcon requests bandwidth limit
1462 *
1463 * From kernel of the FreeBSD 4.10 release:
1464 * sys/netinet/ip_icmp.c(846): int badport_bandlim(int which);
1465 *
1466 * Return false if it is ok to check rcon_password, true if we have
1467 * hit our bandwidth limit and it is not ok.
1468 *
1469 * If sv_rconlim.value is <= 0, the feature is disabled and false is returned.
1470 *
1471 * Note that the printing of the error message is delayed so we can
1472 * properly print the rcon limit error rate that the system was trying to do
1473 * (i.e. 22000/100 rcon pps, etc...). This can cause long delays in printing
1474 * the 'final' error, but it doesn't make sense to solve the printing
1475 * delay with more complex code.
1476 */
rcon_bandlim(void)1477 static qbool rcon_bandlim (void)
1478 {
1479 static double lticks = 0;
1480 static int lpackets = 0;
1481
1482 /*
1483 * Return ok status if feature disabled or argument out of
1484 * ranage.
1485 */
1486
1487 if ((int)sv_rconlim.value <= 0)
1488 return false;
1489
1490 /*
1491 * reset stats when cumulative dt exceeds one second.
1492 */
1493
1494 if (realtime - lticks > 1.0)
1495 {
1496 if (lpackets > (int)sv_rconlim.value)
1497 Sys_Printf("WARNING: Limiting rcon response from %d to %d rcon pequests per second from %s\n",
1498 lpackets, (int)sv_rconlim.value, NET_AdrToString(net_from));
1499 lticks = realtime;
1500 lpackets = 0;
1501 }
1502
1503 /*
1504 * bump packet count
1505 */
1506
1507 if (++lpackets > (int)sv_rconlim.value)
1508 return true;
1509
1510 return false;
1511 }
1512
1513 //bliP: master rcon/logging ->
Rcon_Validate(char * client_string,char * password1)1514 int Rcon_Validate (char *client_string, char *password1)
1515 {
1516 unsigned int i;
1517
1518 if (rcon_bandlim()) {
1519 return 0;
1520 }
1521
1522 if (!strlen(password1)) {
1523 return 0;
1524 }
1525
1526 if ((int)sv_crypt_rcon.value) {
1527 const char* digest = Cmd_Argv(1);
1528 const char* time_start = Cmd_Argv(1) + DIGEST_SIZE * 2;
1529
1530 if (strlen(digest) < DIGEST_SIZE * 2 + sizeof(time_t) * 2) {
1531 return 0;
1532 }
1533
1534 if ((int)sv_timestamplen.value) {
1535 time_t server_time, client_time = 0;
1536 double difftime_server_client;
1537
1538 time(&server_time);
1539 for (i = 0; i < sizeof(client_time) * 2; i += 2) {
1540 client_time += (char2int((unsigned char)time_start[i]) << (4 + i * 4)) +
1541 (char2int((unsigned char)time_start[i + 1]) << (i * 4));
1542 }
1543 difftime_server_client = difftime(server_time, client_time);
1544
1545 if (difftime_server_client > (double)sv_timestamplen.value || difftime_server_client < -(double)sv_timestamplen.value) {
1546 return 0;
1547 }
1548 }
1549 SHA1_Init();
1550 SHA1_Update((unsigned char*)Cmd_Argv(0));
1551 SHA1_Update((unsigned char*)" ");
1552 SHA1_Update((unsigned char*)password1);
1553 SHA1_Update((unsigned char*)time_start);
1554 SHA1_Update((unsigned char*)" ");
1555 for (i = 2; (int) i < Cmd_Argc(); i++) {
1556 SHA1_Update((unsigned char*)Cmd_Argv(i));
1557 SHA1_Update((unsigned char*)" ");
1558 }
1559 if (strncmp(digest, SHA1_Final(), DIGEST_SIZE * 2)) {
1560 return 0;
1561 }
1562 }
1563 else if (strcmp(Cmd_Argv(1), password1)) {
1564 return 0;
1565 }
1566 return 1;
1567 }
1568
Master_Rcon_Validate(void)1569 int Master_Rcon_Validate (void)
1570 {
1571 int i, client_string_len = Cmd_Argc() + 1;
1572 char *client_string;
1573
1574 for (i = 0; i < Cmd_Argc(); ++i) {
1575 client_string_len += strlen(Cmd_Argv(i));
1576 }
1577 client_string = (char *) Q_malloc (client_string_len);
1578
1579 *client_string = 0;
1580 for (i = 0; i < Cmd_Argc(); ++i) {
1581 strlcat(client_string, Cmd_Argv(i), client_string_len);
1582 strlcat(client_string, " ", client_string_len);
1583 }
1584 i = Rcon_Validate (client_string, master_rcon_password);
1585 Q_free(client_string);
1586 return i;
1587 }
1588
1589 // QW262 -->
SV_Admin_f(void)1590 void SV_Admin_f (void)
1591 {
1592 client_t *cl;
1593 int i = 0;
1594
1595 if (Cmd_Argc () == 2 && !strcmp (Cmd_Argv (1), "off") && WatcherId &&
1596 NET_CompareAdr (WatcherId->netchan.remote_address, net_from))
1597 {
1598 Con_Printf ("Rcon Watch stopped\n");
1599 WatcherId = NULL;
1600 return;
1601 }
1602
1603 if (WatcherId)
1604 Con_Printf ("Rcon Watch is already being made by %s\n", WatcherId->name);
1605 else
1606 {
1607 for (cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
1608 {
1609 if (cl->state != cs_spawned)
1610 continue;
1611
1612 if (NET_CompareAdr (cl->netchan.remote_address, net_from))
1613 break;
1614 }
1615
1616 if (i == MAX_CLIENTS)
1617 {
1618 Con_Printf ("You are not connected to server!\n");
1619 return;
1620 }
1621
1622 WatcherId = cl;
1623 Con_Printf ("Rcon Watch started for %s\n", cl->name);
1624 }
1625 }
1626 // <-- QW262
1627
1628 /*
1629 ===============
1630 SVC_RemoteCommand
1631
1632 A client issued an rcon command.
1633 Shift down the remaining args
1634 Redirect all printfs
1635 ===============
1636 */
SVC_RemoteCommand(char * remote_command)1637 static void SVC_RemoteCommand (char *remote_command)
1638 {
1639 int i;
1640 char str[1024];
1641 char plain[32];
1642 char *p;
1643 unsigned char *hide;
1644 client_t *cl;
1645 qbool admin_cmd = false;
1646 qbool do_cmd = false;
1647 qbool bad_cmd = false;
1648 qbool banned = false;
1649
1650
1651 if (Rcon_Validate (remote_command, master_rcon_password))
1652 {
1653 if (SV_FilterPacket()) //banned players can't use rcon, but we log it
1654 banned = true;
1655 else
1656 do_cmd = true;
1657 }
1658 else if (Rcon_Validate (remote_command, rcon_password.string))
1659 {
1660 admin_cmd = true;
1661 if (SV_FilterPacket()) //banned players can't use rcon, but we log it
1662 {
1663 bad_cmd = true;
1664 banned = true;
1665 }
1666 else
1667 {
1668 //
1669 // the following line prevents exploits like:
1670 // coop rm
1671 // $coop . *
1672 // which expands to:
1673 // rm . *
1674
1675 Cmd_ExpandString (remote_command, str); // check *expanded* command
1676
1677 //
1678 // since the execution parser is not case sensitive, we
1679 // must check not only for chmod, but also CHMOD, ChmoD, etc.
1680 // so we lowercase the whole temporary line before checking
1681
1682 // VVD: strcmp => strcasecmp and we don't need to do this (yes?)
1683 //for(i = 0; str[i]; i++)
1684 // str[i] = (char)tolower(str[i]);
1685
1686 Cmd_TokenizeString (str); // must check *all* tokens, because
1687 // a command/var may not be the first
1688 // token -- example: "" ls .
1689
1690 //
1691 // normal rcon can't use these commands
1692 //
1693 // NOTE: this would still be vulnerable to semicolons if
1694 // they were still allowed, so keep that in mind before
1695 // re-enabling them
1696
1697 for (i = 2; i < Cmd_Argc(); i++)
1698 {
1699 const char *tstr = Cmd_Argv(i);
1700
1701 if(!tstr[0]) // skip leading empty tokens
1702 continue;
1703
1704 if (!strcasecmp(tstr, "rm") ||
1705 !strcasecmp(tstr, "rmdir") ||
1706 !strcasecmp(tstr, "ls") ||
1707 !strcasecmp(tstr, "chmod") ||
1708 !strcasecmp(tstr, "sv_admininfo") ||
1709 !strcasecmp(tstr, "if") ||
1710 !strcasecmp(tstr, "localcommand") ||
1711 !strcasecmp(tstr, "sv_crypt_rcon") ||
1712 !strcasecmp(tstr, "sv_timestamplen") ||
1713 !strncasecmp(tstr, "log", 3) ||
1714 !strcasecmp(tstr, "sys_command_line")
1715 )
1716 {
1717 bad_cmd = true;
1718 }
1719 break; // stop after first non-empty token
1720 }
1721
1722 Cmd_TokenizeString (remote_command); // restore original tokens
1723 }
1724 do_cmd = !bad_cmd;
1725 }
1726
1727 //find player name if rcon came from someone on server
1728 plain[0] = '\0';
1729 for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
1730 {
1731 if (cl->state == cs_free)
1732 continue;
1733 #ifdef USE_PR2
1734 if (cl->isBot)
1735 continue;
1736 #endif
1737 if (!NET_CompareBaseAdr(net_from, cl->netchan.remote_address))
1738 continue;
1739 if (cl->netchan.remote_address.port != net_from.port)
1740 continue;
1741
1742 strlcpy(plain, cl->name, sizeof(plain));
1743 Q_normalizetext(plain);
1744
1745 // we found what we need
1746 break;
1747 }
1748
1749 if (do_cmd)
1750 {
1751 if (!(int)sv_crypt_rcon.value)
1752 {
1753 hide = net_message.data + 9;
1754 p = admin_cmd ? rcon_password.string : master_rcon_password;
1755 while (*p)
1756 {
1757 p++;
1758 *hide++ = '*';
1759 }
1760 }
1761
1762 if (plain[0])
1763 SV_Write_Log(RCON_LOG, 1, va("Rcon from %s (%s): %s\n", NET_AdrToString(net_from), plain, net_message.data + 4));
1764 else
1765 SV_Write_Log(RCON_LOG, 1, va("Rcon from %s: %s\n", NET_AdrToString(net_from), net_message.data + 4));
1766
1767 Con_Printf("Rcon from %s:\n%s\n", NET_AdrToString(net_from), net_message.data + 4);
1768
1769 SV_BeginRedirect(RD_PACKET);
1770
1771 str[0] = '\0';
1772 for (i = 2; i < Cmd_Argc(); i++)
1773 {
1774 strlcat(str, Cmd_Argv(i), sizeof(str));
1775 strlcat(str, " ", sizeof(str));
1776 }
1777
1778 Cmd_ExecuteString(str);
1779 }
1780 else
1781 {
1782 if (admin_cmd && !(int)sv_crypt_rcon.value)
1783 {
1784 hide = net_message.data + 9;
1785 p = admin_cmd ? rcon_password.string : master_rcon_password;
1786 while (*p)
1787 {
1788 p++;
1789 *hide++ = '*';
1790 }
1791 }
1792
1793 Con_Printf ("Bad rcon from %s: %s\n", NET_AdrToString(net_from), net_message.data + 4);
1794
1795 if (!banned)
1796 {
1797 if (plain[0])
1798 SV_Write_Log(RCON_LOG, 1, va("Bad rcon from %s (%s):\n%s\n", NET_AdrToString(net_from), plain, net_message.data + 4));
1799 else
1800 SV_Write_Log(RCON_LOG, 1, va("Bad rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data + 4));
1801 }
1802 else
1803 {
1804 SV_Write_Log(RCON_LOG, 1, va("Rcon from banned IP: %s: %s\n", NET_AdrToString(net_from), net_message.data + 4));
1805 SV_SendBan();
1806 return;
1807 }
1808
1809 SV_BeginRedirect (RD_PACKET);
1810 if (admin_cmd)
1811 Con_Printf ("Command not valid.\n");
1812 else
1813 Con_Printf ("Bad rcon_password.\n");
1814 }
1815 SV_EndRedirect ();
1816 }
1817 //<-
1818
SVC_IP(void)1819 static void SVC_IP(void)
1820 {
1821 int num;
1822 client_t *client;
1823
1824 if (Cmd_Argc() < 3)
1825 return;
1826
1827 num = Q_atoi(Cmd_Argv(1));
1828
1829 if (num < 0 || num >= MAX_CLIENTS)
1830 return;
1831
1832 client = &svs.clients[num];
1833 if (client->state != cs_preconnected)
1834 return;
1835
1836 // prevent cheating
1837 if (client->realip_num != Q_atoi(Cmd_Argv(2)))
1838 return;
1839
1840 // don't override previously set ip
1841 if (client->realip.ip[0])
1842 return;
1843
1844 client->realip = net_from;
1845
1846 // if banned drop
1847 if (SV_FilterPacket()/* && !client->vip*/)
1848 SV_DropClient(client);
1849
1850 }
1851
1852
1853 /*
1854 =================
1855 SV_ConnectionlessPacket
1856
1857 A connectionless packet has four leading 0xff
1858 characters to distinguish it from a game channel.
1859 Clients that are in the game can still send
1860 connectionless packets.
1861 =================
1862 */
1863
SV_ConnectionlessPacket(void)1864 static void SV_ConnectionlessPacket (void)
1865 {
1866 char *s;
1867 char *c;
1868
1869 MSG_BeginReading ();
1870 MSG_ReadLong (); // skip the -1 marker
1871
1872 s = MSG_ReadStringLine ();
1873
1874 Cmd_TokenizeString (s);
1875
1876 c = Cmd_Argv(0);
1877
1878 if (!strcmp(c, "ping") || ( c[0] == A2A_PING && (c[1] == 0 || c[1] == '\n')) )
1879 SVC_Ping ();
1880 else if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n') )
1881 Con_Printf ("A2A_ACK from %s\n", NET_AdrToString (net_from));
1882 else if (!strcmp(c,"status"))
1883 SVC_Status ();
1884 else if (!strcmp(c,"log"))
1885 SVC_Log ();
1886 else if (!strcmp(c, "rcon"))
1887 SVC_RemoteCommand (s);
1888 else if (!strcmp(c, "ip"))
1889 SVC_IP();
1890 else if (!strcmp(c,"connect"))
1891 SVC_DirectConnect ();
1892 else if (!strcmp(c,"getchallenge"))
1893 SVC_GetChallenge ();
1894 else if (!strcmp(c,"lastscores"))
1895 SVC_LastScores ();
1896 else if (!strcmp(c,"dlist"))
1897 SVC_DemoList ();
1898 else if (!strcmp(c,"dlistr"))
1899 SVC_DemoListRegex ();
1900 else if (!strcmp(c,"dlistregex"))
1901 SVC_DemoListRegex ();
1902 else if (!strcmp(c,"demolist"))
1903 SVC_DemoList ();
1904 else if (!strcmp(c,"demolistr"))
1905 SVC_DemoListRegex ();
1906 else if (!strcmp(c,"demolistregex"))
1907 SVC_DemoListRegex ();
1908 else if (!strcmp(c,"qtvusers"))
1909 SVC_QTVUsers ();
1910 else
1911 Con_Printf ("bad connectionless packet from %s:\n%s\n"
1912 , NET_AdrToString (net_from), s);
1913 }
1914
1915 /*
1916 ==============================================================================
1917
1918 PACKET FILTERING
1919
1920
1921 You can add or remove addresses from the filter list with:
1922
1923 addip <ip>
1924 removeip <ip>
1925
1926 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".
1927
1928 Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
1929
1930 listip
1931 Prints the current list of filters.
1932
1933 writeip
1934 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.
1935
1936 filterban <0 or 1>
1937
1938 If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
1939
1940 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.
1941
1942
1943 ==============================================================================
1944 */
1945
1946
1947 /*typedef struct
1948 {
1949 unsigned mask;
1950 unsigned compare;
1951 int level;
1952 } ipfilter_t;
1953 */
1954
1955 #define MAX_IPFILTERS 1024
1956
1957 ipfilter_t ipfilters[MAX_IPFILTERS];
1958 int numipfilters;
1959
1960 ipfilter_t ipvip[MAX_IPFILTERS];
1961 int numipvips;
1962
1963 //bliP: cuff, mute ->
1964 penfilter_t penfilters[MAX_PENFILTERS];
1965 int numpenfilters;
1966 //<-
1967
1968 cvar_t filterban = {"filterban", "1"};
1969
1970 /*
1971 =================
1972 StringToFilter
1973 =================
1974 */
StringToFilter(char * s,ipfilter_t * f)1975 qbool StringToFilter (char *s, ipfilter_t *f)
1976 {
1977 char num[128];
1978 int i, j;
1979 byte b[4];
1980 byte m[4];
1981
1982 for (i=0 ; i<4 ; i++)
1983 {
1984 b[i] = 0;
1985 m[i] = 0;
1986 }
1987
1988 for (i=0 ; i<4 ; i++)
1989 {
1990 if (*s < '0' || *s > '9')
1991 {
1992 //Con_Printf ("Bad filter address: %s\n", s);
1993 return false;
1994 }
1995
1996 j = 0;
1997 while (*s >= '0' && *s <= '9')
1998 {
1999 num[j++] = *s++;
2000 }
2001 num[j] = 0;
2002 b[i] = Q_atoi(num);
2003 if (b[i] != 0)
2004 m[i] = 255;
2005
2006 if (!*s)
2007 break;
2008 s++;
2009 }
2010
2011 f->mask = *(unsigned *)m;
2012 f->compare = *(unsigned *)b;
2013
2014 return true;
2015 }
2016
2017 /*
2018 =================
2019 SV_AddIPVIP_f
2020 =================
2021 */
SV_AddIPVIP_f(void)2022 static void SV_AddIPVIP_f (void)
2023 {
2024 int i, l;
2025 ipfilter_t f;
2026
2027 if (!StringToFilter (Cmd_Argv(1), &f))
2028 {
2029 Con_Printf ("Bad filter address: %s\n", Cmd_Argv(1));
2030 return;
2031 }
2032
2033 l = Q_atoi(Cmd_Argv(2));
2034
2035 if (l < 1) l = 1;
2036
2037 for (i=0 ; i<numipvips ; i++)
2038 if (ipvip[i].compare == 0xffffffff || (ipvip[i].mask == f.mask
2039 && ipvip[i].compare == f.compare))
2040 break; // free spot
2041 if (i == numipvips)
2042 {
2043 if (numipvips == MAX_IPFILTERS)
2044 {
2045 Con_Printf ("VIP spectator IP list is full\n");
2046 return;
2047 }
2048 numipvips++;
2049 }
2050
2051 ipvip[i] = f;
2052 ipvip[i].level = l;
2053 }
2054
2055 /*
2056 =================
2057 SV_RemoveIPVIP_f
2058 =================
2059 */
SV_RemoveIPVIP_f(void)2060 static void SV_RemoveIPVIP_f (void)
2061 {
2062 ipfilter_t f;
2063 int i, j;
2064
2065 if (!StringToFilter (Cmd_Argv(1), &f))
2066 {
2067 Con_Printf ("Bad filter address: %s\n", Cmd_Argv(1));
2068 return;
2069 }
2070 for (i=0 ; i<numipvips ; i++)
2071 if (ipvip[i].mask == f.mask
2072 && ipvip[i].compare == f.compare)
2073 {
2074 for (j=i+1 ; j<numipvips ; j++)
2075 ipvip[j-1] = ipvip[j];
2076 numipvips--;
2077 Con_Printf ("Removed.\n");
2078 return;
2079 }
2080 Con_Printf ("Didn't find %s.\n", Cmd_Argv(1));
2081 }
2082
2083 /*
2084 =================
2085 SV_ListIP_f
2086 =================
2087 */
SV_ListIPVIP_f(void)2088 static void SV_ListIPVIP_f (void)
2089 {
2090 int i;
2091 byte b[4];
2092
2093 Con_Printf ("VIP list:\n");
2094 for (i=0 ; i<numipvips ; i++)
2095 {
2096 *(unsigned *)b = ipvip[i].compare;
2097 Con_Printf ("%3i.%3i.%3i.%3i level %d\n", b[0], b[1], b[2], b[3], ipvip[i].level);
2098 }
2099 }
2100
2101 /*
2102 =================
2103 SV_WriteIPVIP_f
2104 =================
2105 */
SV_WriteIPVIP_f(void)2106 static void SV_WriteIPVIP_f (void)
2107 {
2108 FILE *f;
2109 char name[MAX_OSPATH];
2110 byte b[4];
2111 int i;
2112
2113 snprintf (name, MAX_OSPATH, "%s/vip_ip.cfg", fs_gamedir);
2114
2115 Con_Printf ("Writing %s.\n", name);
2116
2117 f = fopen (name, "wb");
2118 if (!f)
2119 {
2120 Con_Printf ("Couldn't open %s\n", name);
2121 return;
2122 }
2123
2124 for (i=0 ; i<numipvips ; i++)
2125 {
2126 *(unsigned *)b = ipvip[i].compare;
2127 fprintf (f, "vip_addip %i.%i.%i.%i %d\n", b[0], b[1], b[2], b[3], ipvip[i].level);
2128 }
2129
2130 fclose (f);
2131
2132 // force cache rebuild.
2133 FS_FlushFSHash();
2134 }
2135
2136
2137 /*
2138 =================
2139 SV_AddIP_f
2140 =================
2141 */
SV_AddIP_f(void)2142 static void SV_AddIP_f (void)
2143 {
2144 int i;
2145 double t = 0;
2146 char *s;
2147 time_t long_time = time(NULL);
2148 ipfilter_t f;
2149 ipfiltertype_t ipft = ipft_ban; // default is ban
2150
2151 if (!StringToFilter (Cmd_Argv(1), &f) || f.compare == 0)
2152 {
2153 Con_Printf ("Bad filter address: %s\n", Cmd_Argv(1));
2154 return;
2155 }
2156
2157 s = Cmd_Argv(2);
2158 if ( !s[0] || !strcmp(s, "ban"))
2159 ipft = ipft_ban;
2160 else if (!strcmp(s, "safe"))
2161 ipft = ipft_safe;
2162 else {
2163 Con_Printf ("Wrong filter type %s, use ban or safe\n", Cmd_Argv(2));
2164 return;
2165 }
2166
2167 s = Cmd_Argv(3);
2168 if (long_time > 0) {
2169 if (*s == '+') // "addip 127.0.0.1 ban +10" will ban for 10 seconds from current time
2170 s++;
2171 else
2172 long_time = 0; // "addip 127.0.0.1 ban 1234567" will ban for some seconds since 00:00:00 GMT, January 1, 1970
2173
2174 t = (sscanf(s, "%lf", &t) == 1) ? t + long_time : 0;
2175 }
2176
2177 f.time = t;
2178 f.type = ipft;
2179
2180 for (i=0 ; i<numipfilters ; i++)
2181 if (ipfilters[i].compare == 0xffffffff || (ipfilters[i].mask == f.mask
2182 && ipfilters[i].compare == f.compare))
2183 break; // free spot
2184 if (i == numipfilters)
2185 {
2186 if (numipfilters == MAX_IPFILTERS)
2187 {
2188 Con_Printf ("IP filter list is full\n");
2189 return;
2190 }
2191 numipfilters++;
2192 }
2193
2194 ipfilters[i] = f;
2195 }
2196
2197 /*
2198 =================
2199 SV_RemoveIP_f
2200 =================
2201 */
SV_RemoveIP_f(void)2202 static void SV_RemoveIP_f (void)
2203 {
2204 ipfilter_t f;
2205 int i, j;
2206
2207 if (!StringToFilter (Cmd_Argv(1), &f))
2208 {
2209 Con_Printf ("Bad filter address: %s\n", Cmd_Argv(1));
2210 return;
2211 }
2212
2213 for (i=0 ; i<numipfilters ; i++)
2214 if (ipfilters[i].mask == f.mask
2215 && ipfilters[i].compare == f.compare)
2216 {
2217 for (j=i+1 ; j<numipfilters ; j++)
2218 ipfilters[j-1] = ipfilters[j];
2219 numipfilters--;
2220 Con_Printf ("Removed.\n");
2221 return;
2222 }
2223 Con_Printf ("Didn't find %s.\n", Cmd_Argv(1));
2224 }
2225
2226 /*
2227 =================
2228 SV_ListIP_f
2229 =================
2230 */
SV_ListIP_f(void)2231 static void SV_ListIP_f (void)
2232 {
2233 time_t long_time = time(NULL);
2234 int i;
2235 byte b[4];
2236
2237 Con_Printf ("Filter list:\n");
2238 for (i=0 ; i<numipfilters ; i++)
2239 {
2240 *(unsigned *)b = ipfilters[i].compare;
2241 Con_Printf ("%3i.%3i.%3i.%3i | ", b[0], b[1], b[2], b[3]);
2242 switch((int)ipfilters[i].type){
2243 case ipft_ban: Con_Printf (" ban"); break;
2244 case ipft_safe: Con_Printf ("safe"); break;
2245 default: Con_Printf ("unkn"); break;
2246 }
2247 if (ipfilters[i].time)
2248 Con_Printf (" | %i s", (int)(ipfilters[i].time-long_time));
2249 Con_Printf ("\n");
2250 }
2251 }
2252
2253 /*
2254 =================
2255 SV_WriteIP_f
2256 =================
2257 */
SV_WriteIP_f(void)2258 static void SV_WriteIP_f (void)
2259 {
2260 FILE *f;
2261 char name[MAX_OSPATH], *s;
2262 byte b[4];
2263 int i;
2264
2265 snprintf (name, MAX_OSPATH, "%s/listip.cfg", fs_gamedir);
2266
2267 Con_Printf ("Writing %s.\n", name);
2268
2269 f = fopen (name, "wb");
2270 if (!f)
2271 {
2272 Con_Printf ("Couldn't open %s\n", name);
2273 return;
2274 }
2275
2276 // write safe filters first
2277 for (i=0 ; i<numipfilters ; i++)
2278 {
2279 if(ipfilters[i].type != ipft_safe)
2280 continue;
2281
2282 *(unsigned *)b = ipfilters[i].compare;
2283 fprintf (f, "addip %i.%i.%i.%i safe %.0f\n", b[0], b[1], b[2], b[3], ipfilters[i].time);
2284 }
2285
2286 for (i=0 ; i<numipfilters ; i++)
2287 {
2288 if(ipfilters[i].type == ipft_safe)
2289 continue; // ignore safe, we already save it
2290
2291 switch((int)ipfilters[i].type){
2292 case ipft_ban: s = " ban"; break;
2293 case ipft_safe: s = "safe"; break;
2294 default: s = "unkn"; break;
2295 }
2296 *(unsigned *)b = ipfilters[i].compare;
2297 fprintf (f, "addip %i.%i.%i.%i %s %.0f\n", b[0], b[1], b[2], b[3], s, ipfilters[i].time);
2298 }
2299
2300 fclose (f);
2301
2302 // force cache rebuild.
2303 FS_FlushFSHash();
2304 }
2305
2306 /*
2307 =================
2308 SV_SendBan
2309 =================
2310 */
SV_SendBan(void)2311 void SV_SendBan (void)
2312 {
2313 char data[128];
2314
2315 data[0] = data[1] = data[2] = data[3] = 0xff;
2316 data[4] = A2C_PRINT;
2317 data[5] = 0;
2318 strlcat (data, "\nbanned.\n", sizeof(data));
2319
2320 NET_SendPacket (NS_SERVER, strlen(data), data, net_from);
2321 }
2322
2323 /*
2324 =================
2325 SV_FilterPacket
2326 =================
2327 */
SV_FilterPacket(void)2328 qbool SV_FilterPacket (void)
2329 {
2330 int i;
2331 unsigned in;
2332
2333 in = *(unsigned *)net_from.ip;
2334
2335 for (i=0 ; i<numipfilters ; i++)
2336 if ( ipfilters[i].type == ipft_ban && (in & ipfilters[i].mask) == ipfilters[i].compare )
2337 return (int)filterban.value;
2338
2339 return !(int)filterban.value;
2340 }
2341
2342 // { server internal BAN support
2343
2344 #define AF_REAL_ADMIN (1<<1) // pass/vip granted admin.
2345
Do_BanList(ipfiltertype_t ipft)2346 void Do_BanList(ipfiltertype_t ipft)
2347 {
2348 time_t long_time = time(NULL);
2349 int i;
2350 byte b[4];
2351
2352 for (i=0 ; i<numipfilters ; i++)
2353 {
2354 if (ipfilters[i].type != ipft)
2355 continue;
2356
2357 *(unsigned *)b = ipfilters[i].compare;
2358 Con_Printf ("%3i|%3i.%3i.%3i.%3i", i, b[0], b[1], b[2], b[3]);
2359 switch((int)ipfilters[i].type){
2360 case ipft_ban: Con_Printf ("| ban"); break;
2361 case ipft_safe: Con_Printf ("|safe"); break;
2362 default: Con_Printf ("|unkn"); break;
2363 }
2364
2365 if (ipfilters[i].time) {
2366 long df = ipfilters[i].time-long_time;
2367 long d, h, m, s;
2368 d = df / (60*60*24);
2369 df -= d * 60*60*24;
2370 h = df / (60*60);
2371 df -= h * 60*60;
2372 m = df / 60;
2373 df -= m * 60;
2374 s = df;
2375
2376 if (d)
2377 Con_Printf ("|%4ldd:%2ldh", d, h);
2378 else if (h)
2379 Con_Printf ("|%4ldh:%2ldm", h, m);
2380 else
2381 Con_Printf ("|%4ldm:%2lds", m, s);
2382 }
2383 else
2384 Con_Printf ("|permanent");
2385 Con_Printf ("\n");
2386 }
2387 }
2388
SV_BanList(void)2389 void SV_BanList (void)
2390 {
2391 unsigned char blist[64] = "Ban list:", id[64] = "id", ipmask[64] = "ip mask", type[64] = "type", expire[64] = "expire";
2392
2393 if (numipfilters < 1) {
2394 Con_Printf ("Ban list: empty\n");
2395 return;
2396 }
2397
2398 Con_Printf ("%s\n"
2399 "\235\236\236\236\236\236\236\236\236\236\236\236\236\236\236\236"
2400 "\236\236\236\236\236\236\236\236\236\236\236\236\236\236\236\236\236\237\n"
2401 "%3.3s|%15.15s|%4.4s|%9.9s\n",
2402 Q_redtext(blist), Q_redtext(id), Q_redtext(ipmask), Q_redtext(type), Q_redtext(expire));
2403
2404 Do_BanList(ipft_safe);
2405 Do_BanList(ipft_ban);
2406 }
2407
SV_CanAddBan(ipfilter_t * f)2408 qbool SV_CanAddBan (ipfilter_t *f)
2409 {
2410 int i;
2411
2412 if (f->compare == 0)
2413 return false;
2414
2415 for (i=0 ; i<numipfilters ; i++)
2416 if (ipfilters[i].mask == f->mask && ipfilters[i].compare == f->compare && ipfilters[i].type == ipft_safe)
2417 return false; // can't add filter f because present "safe" filter
2418
2419 return true;
2420 }
2421
SV_RemoveBansIPFilter(int i)2422 void SV_RemoveBansIPFilter (int i)
2423 {
2424 for (; i + 1 < numipfilters; i++)
2425 ipfilters[i] = ipfilters[i + 1];
2426
2427 numipfilters--;
2428 }
2429
SV_CleanBansIPList(void)2430 void SV_CleanBansIPList (void)
2431 {
2432 time_t long_time = time(NULL);
2433 int i;
2434
2435 if (sv.state != ss_active)
2436 return;
2437
2438 for (i = 0; i < numipfilters;)
2439 {
2440 if (ipfilters[i].time && ipfilters[i].time <= long_time)
2441 {
2442 SV_RemoveBansIPFilter (i);
2443 }
2444 else
2445 i++;
2446 }
2447 }
2448
SV_Cmd_Ban_f(void)2449 void SV_Cmd_Ban_f(void)
2450 {
2451 edict_t *ent;
2452 eval_t *val;
2453 double d;
2454 int i, j, t;
2455 client_t *cl;
2456 ipfilter_t f;
2457 int uid;
2458 int c;
2459 char reason[80] = "", arg2[32], arg2c[sizeof(arg2)], *s;
2460
2461 // set up the edict
2462 ent = sv_client->edict;
2463
2464 // ============
2465 // get ADMIN rights from MOD via "mod_admin" field, mod MUST export such field if wanna server ban support
2466 // ============
2467
2468 val = PR_GetEdictFieldValue(ent, "mod_admin");
2469 if (!val || !(val->_int & AF_REAL_ADMIN) ) {
2470 Con_Printf("You are not an admin\n");
2471 return;
2472 }
2473
2474 c = Cmd_Argc ();
2475 if (c < 3)
2476 {
2477 Con_Printf("usage: cmd ban <id/nick> <time<s m h d>> [reason]\n");
2478 return;
2479 }
2480
2481 uid = Q_atoi(Cmd_Argv(1));
2482
2483 strlcpy(arg2, Cmd_Argv(2), sizeof(arg2));
2484
2485 // sscanf safe here since sizeof(arg2) == sizeof(arg2c), right?
2486 if (sscanf(arg2, "%d%s", &t, arg2c) != 2 || strlen(arg2c) != 1) {
2487 Con_Printf("ban: wrong time arg\n");
2488 return;
2489 }
2490
2491 d = t = bound(0, t, 999);
2492 switch(arg2c[0]) {
2493 case 's': break; // seconds is seconds
2494 case 'm': d *= 60; break; // 60 seconds per minute
2495 case 'h': d *= 60*60; break; // 3600 seconds per hour
2496 case 'd': d *= 60*60*24; break; // 86400 seconds per day
2497 default:
2498 Con_Printf("ban: wrong time arg\n");
2499 return;
2500 }
2501
2502 for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
2503 {
2504 if (!cl->state)
2505 continue;
2506 if (cl->userid == uid || !strcmp(Cmd_Argv(1), cl->name))
2507 {
2508 if (c > 3) // serve reason arguments
2509 {
2510 strlcpy (reason, " (", sizeof(reason));
2511 for (j=3 ; j<c; j++)
2512 {
2513 strlcat (reason, Cmd_Argv(j), sizeof(reason)-4);
2514 if (j < c-1)
2515 strlcat (reason, " ", sizeof(reason)-4);
2516 }
2517 if (strlen(reason) < 3)
2518 reason[0] = '\0';
2519 else
2520 strlcat (reason, ")", sizeof(reason));
2521 }
2522
2523 s = NET_BaseAdrToString(cl->netchan.remote_address);
2524 if (!StringToFilter (s, &f))
2525 {
2526 Con_Printf ("ban: bad ip address: %s\n", s);
2527 return;
2528 }
2529
2530 if (!SV_CanAddBan(&f))
2531 {
2532 Con_Printf ("ban: can't ban such ip: %s\n", s);
2533 return;
2534 }
2535
2536 SV_BroadcastPrintf (PRINT_HIGH, "%s was banned for %d%s%s\n", cl->name, t, arg2c, reason);
2537
2538 Cbuf_AddText(va("addip %s ban %s%.0lf\n", s, d ? "+" : "", d));
2539 Cbuf_AddText("writeip\n");
2540 return;
2541 }
2542 }
2543
2544 Con_Printf ("Couldn't find user %s\n", Cmd_Argv(1));
2545 }
2546
SV_Cmd_Banip_f(void)2547 void SV_Cmd_Banip_f(void)
2548 {
2549 edict_t *ent;
2550 eval_t *val;
2551 byte b[4];
2552 double d;
2553 int c, t;
2554 ipfilter_t f;
2555 char arg2[32], arg2c[sizeof(arg2)];
2556
2557 // set up the edict
2558 ent = sv_client->edict;
2559
2560 // ============
2561 // get ADMIN rights from MOD via "mod_admin" field, mod MUST export such field if wanna server ban support
2562 // ============
2563
2564 val = PR_GetEdictFieldValue(ent, "mod_admin");
2565 if (!val || !(val->_int & AF_REAL_ADMIN) ) {
2566 Con_Printf("You are not an admin\n");
2567 return;
2568 }
2569
2570 c = Cmd_Argc ();
2571 if (c < 3)
2572 {
2573 Con_Printf("usage: cmd banip <ip> <time<s m h d>>\n");
2574 return;
2575 }
2576
2577 if (!StringToFilter (Cmd_Argv(1), &f))
2578 {
2579 Con_Printf ("ban: bad ip address: %s\n", Cmd_Argv(1));
2580 return;
2581 }
2582
2583 if (!SV_CanAddBan(&f))
2584 {
2585 Con_Printf ("ban: can't ban such ip: %s\n", Cmd_Argv(1));
2586 return;
2587 }
2588
2589 strlcpy(arg2, Cmd_Argv(2), sizeof(arg2));
2590
2591 // sscanf safe here since sizeof(arg2) == sizeof(arg2c), right?
2592 if (sscanf(arg2, "%d%s", &t, arg2c) != 2 || strlen(arg2c) != 1) {
2593 Con_Printf("ban: wrong time arg\n");
2594 return;
2595 }
2596
2597 d = t = bound(0, t, 999);
2598 switch(arg2c[0]) {
2599 case 's': break; // seconds is seconds
2600 case 'm': d *= 60; break; // 60 seconds per minute
2601 case 'h': d *= 60*60; break; // 3600 seconds per hour
2602 case 'd': d *= 60*60*24; break; // 86400 seconds per day
2603 default:
2604 Con_Printf("ban: wrong time arg\n");
2605 return;
2606 }
2607
2608 *(unsigned *)b = f.compare;
2609 SV_BroadcastPrintf (PRINT_HIGH, "%3i.%3i.%3i.%3i was banned for %d%s\n", b[0], b[1], b[2], b[3], t, arg2c);
2610
2611 Cbuf_AddText(va("addip %i.%i.%i.%i ban %s%.0lf\n", b[0], b[1], b[2], b[3], d ? "+" : "", d));
2612 Cbuf_AddText("writeip\n");
2613 }
2614
SV_Cmd_Banremove_f(void)2615 void SV_Cmd_Banremove_f(void)
2616 {
2617 edict_t *ent;
2618 eval_t *val;
2619 byte b[4];
2620 int id;
2621
2622 // set up the edict
2623 ent = sv_client->edict;
2624
2625 // ============
2626 // get ADMIN rights from MOD via "mod_admin" field, mod MUST export such field if wanna server ban support
2627 // ============
2628
2629 val = PR_GetEdictFieldValue(ent, "mod_admin");
2630 if (!val || !(val->_int & AF_REAL_ADMIN) ) {
2631 Con_Printf("You are not an admin\n");
2632 return;
2633 }
2634
2635 if (Cmd_Argc () < 2)
2636 {
2637 Con_Printf("usage: cmd banrem [banid]\n");
2638 SV_BanList();
2639 return;
2640 }
2641
2642 id = Q_atoi(Cmd_Argv(1));
2643
2644 if (id < 0 || id >= numipfilters) {
2645 Con_Printf ("Wrong ban id: %d\n", id);
2646 return;
2647 }
2648
2649 if (ipfilters[id].type == ipft_safe) {
2650 Con_Printf ("Can't remove such ban with id: %d\n", id);
2651 return;
2652 }
2653
2654 *(unsigned *)b = ipfilters[id].compare;
2655 SV_BroadcastPrintf (PRINT_HIGH, "%3i.%3i.%3i.%3i was unbanned\n", b[0], b[1], b[2], b[3]);
2656
2657 SV_RemoveBansIPFilter (id);
2658 Cbuf_AddText("writeip\n");
2659 }
2660
2661 // } server internal BAN support
2662
2663 /*
2664 =================
2665 SV_VIPbyIP
2666 =================
2667 */
SV_VIPbyIP(netadr_t adr)2668 int SV_VIPbyIP (netadr_t adr)
2669 {
2670 int i;
2671 unsigned in;
2672
2673 in = *(unsigned *)adr.ip;
2674
2675 for (i=0 ; i<numipvips ; i++)
2676 if ( (in & ipvip[i].mask) == ipvip[i].compare)
2677 return ipvip[i].level;
2678
2679 return 0;
2680 }
2681
2682 /*
2683 =================
2684 SV_VIPbyPass
2685 =================
2686 */
SV_VIPbyPass(char * pass)2687 int SV_VIPbyPass (char *pass)
2688 {
2689 qbool use_value = false;
2690 int vip_value[MAX_ARGS];
2691 int i;
2692
2693 if (!vip_password.string[0] || !strcasecmp(vip_password.string, "none"))
2694 return 0;
2695
2696 if (vip_values.string[0]) {
2697 use_value = true;
2698 // 2VVD: vip_password count may be not equal vip_values count, what we must do in this case?
2699 memset((void*)vip_value, 0, sizeof(vip_value));
2700 Cmd_TokenizeString(vip_values.string);
2701 for (i = 0; i < Cmd_Argc(); i++)
2702 vip_value[i] = atoi(Cmd_Argv(i));
2703 }
2704
2705 Cmd_TokenizeString(vip_password.string);
2706
2707 for (i = 0; i < Cmd_Argc(); i++)
2708 if (!strcmp(Cmd_Argv(i), pass) && strcasecmp(Cmd_Argv(i), "none"))
2709 return (use_value ? vip_value[i] : i+1);
2710
2711 return 0;
2712 }
2713
DecodeArgs(char * args)2714 static char *DecodeArgs(char *args)
2715 {
2716 static char string[1024];
2717 char *p, key[32], *s, *value, ch, tmp_value[512];
2718
2719 string[0] = 0;
2720 p = string;
2721
2722 while (*args)
2723 {
2724 // skip whitespaces
2725 while (*args && *args <= 32)
2726 *p++ = *args++;
2727
2728 if (*args == '\"')
2729 {
2730 do *p++ = *args++; while (*args && *args != '\"');
2731 *p++ = '\"';
2732 if (*args)
2733 args++;
2734 }
2735 else if (*args == '@' || *args == '$')
2736 {
2737 // get the key and read value from localinfo
2738 ch = *args;
2739 s = key;
2740 args++;
2741 while (*args > 32)
2742 *s++ = *args++;
2743 *s = 0;
2744
2745 if ((value = Info_ValueForKey (svs.info, key)) == NULL || !*value)
2746 value = Info_Get(&_localinfo_, key);
2747
2748 if (ch == '$' && value)
2749 {
2750 strlcpy(tmp_value, value, sizeof(tmp_value));
2751 Q_normalizetext(tmp_value);
2752 value = tmp_value;
2753 }
2754
2755 *p++ = '\"';
2756 if (value)
2757 {
2758 while (*value)
2759 *p++ = *value++;
2760 }
2761 *p++ = '\"';
2762 }
2763 else {
2764 while (*args > 32) {
2765 *p++ = *args++;
2766 }
2767 }
2768 }
2769
2770 *p = 0;
2771
2772 return string;
2773 }
2774
SV_Script_f(void)2775 void SV_Script_f (void)
2776 {
2777 char *path, *p;
2778 extern redirect_t sv_redirected;
2779
2780 if (Cmd_Argc() < 2)
2781 {
2782 Con_Printf("usage: script <path> [<args>]\n");
2783 return;
2784 }
2785
2786 path = Cmd_Argv(1);
2787
2788 //bliP: 24/9 need subdirs here ->
2789 if (!strncmp(path, "../", 3) || !strncmp(path, "..\\", 3))
2790 path += 3;
2791
2792 if (strstr(path, ".."))
2793 {
2794 Con_Printf("Invalid path.\n");
2795 return;
2796 }
2797 //<-
2798
2799 path = Cmd_Argv(1);
2800
2801 p = Cmd_Args();
2802 while (*p > 32)
2803 p++;
2804 while (*p && *p <= 32)
2805 p++;
2806
2807 p = DecodeArgs(p);
2808
2809 if (sv_redirected != RD_MOD)
2810 Sys_Printf("Running %s.qws\n", path);
2811
2812 Sys_Script(path, va("%d %s", sv_redirected, p));
2813
2814 }
2815
2816 //============================================================================
2817
2818 //bliP: cuff, mute ->
SV_RemoveIPFilter(int i)2819 void SV_RemoveIPFilter (int i)
2820 {
2821 for (; i + 1 < numpenfilters; i++)
2822 penfilters[i] = penfilters[i + 1];
2823
2824 numpenfilters--;
2825 }
2826
SV_CleanIPList(void)2827 static void SV_CleanIPList (void)
2828 {
2829 int i;
2830
2831 if (sv.state != ss_active)
2832 return;
2833
2834 for (i = 0; i < numpenfilters;)
2835 {
2836 if (penfilters[i].time && (penfilters[i].time <= realtime))
2837 {
2838 SV_RemoveIPFilter (i);
2839 }
2840 else
2841 i++;
2842 }
2843 }
2844
SV_IPCompare(byte * a,byte * b)2845 static qbool SV_IPCompare (byte *a, byte *b)
2846 {
2847 int i;
2848
2849 for (i = 0; i < 1; i++)
2850 if (((unsigned int *)a)[i] != ((unsigned int *)b)[i])
2851 return false;
2852
2853 return true;
2854 }
2855
SV_IPCopy(byte * dest,byte * src)2856 static void SV_IPCopy (byte *dest, byte *src)
2857 {
2858 int i;
2859
2860 for (i = 0; i < 1; i++)
2861 ((unsigned int *)dest)[i] = ((unsigned int *)src)[i];
2862 }
2863
SV_SavePenaltyFilter(client_t * cl,filtertype_t type,double pentime)2864 void SV_SavePenaltyFilter (client_t *cl, filtertype_t type, double pentime)
2865 {
2866 int i;
2867
2868 if (pentime < curtime) // no point
2869 return;
2870
2871 for (i = 0; i < numpenfilters; i++)
2872 if (SV_IPCompare (penfilters[i].ip, cl->realip.ip) && penfilters[i].type == type)
2873 {
2874 return;
2875 }
2876
2877 if (numpenfilters == MAX_IPFILTERS)
2878 {
2879 return;
2880 }
2881
2882 SV_IPCopy (penfilters[numpenfilters].ip, cl->realip.ip);
2883 penfilters[numpenfilters].time = pentime;
2884 penfilters[numpenfilters].type = type;
2885 numpenfilters++;
2886 }
2887
SV_RestorePenaltyFilter(client_t * cl,filtertype_t type)2888 double SV_RestorePenaltyFilter (client_t *cl, filtertype_t type)
2889 {
2890 int i;
2891 double time1 = 0.0;
2892
2893 // search for existing penalty filter of same type
2894 for (i = 0; i < numpenfilters; i++)
2895 {
2896 if (type == penfilters[i].type && SV_IPCompare (cl->realip.ip, penfilters[i].ip))
2897 {
2898 time1 = penfilters[i].time;
2899 SV_RemoveIPFilter (i);
2900 return time1;
2901 }
2902 }
2903 return time1;
2904 }
2905 //<-
2906
2907 //============================================================================
2908
2909 /*
2910 =================
2911 SV_ReadPackets
2912 =================
2913 */
SV_ReadPackets(void)2914 static void SV_ReadPackets (void)
2915 {
2916 client_t *cl;
2917 int qport;
2918 int i;
2919
2920 if (sv.state != ss_active)
2921 return;
2922
2923 // first deal with delayed packets from connected clients
2924 for (i = 0, cl=svs.clients; i < MAX_CLIENTS; i++, cl++)
2925 {
2926 if (cl->state == cs_free)
2927 continue;
2928
2929 net_from = cl->netchan.remote_address;
2930
2931 while (cl->packets && (realtime - cl->packets->time >= cl->delay || sv.paused))
2932 {
2933 SZ_Clear(&net_message);
2934 SZ_Write(&net_message, cl->packets->msg.data, cl->packets->msg.cursize);
2935 SV_ExecuteClientMessage(cl);
2936 SV_FreeHeadDelayedPacket(cl);
2937 }
2938 }
2939
2940 // now deal with new packets
2941 while (NET_GetPacket(NS_SERVER))
2942 {
2943 if (SV_FilterPacket ())
2944 {
2945 SV_SendBan (); // tell them we aren't listening...
2946 continue;
2947 }
2948
2949 // check for connectionless packet (0xffffffff) first
2950 if (*(int *)net_message.data == -1)
2951 {
2952 SV_ConnectionlessPacket ();
2953 continue;
2954 }
2955
2956 // read the qport out of the message so we can fix up
2957 // stupid address translating routers
2958 MSG_BeginReading ();
2959 MSG_ReadLong (); // sequence number
2960 MSG_ReadLong (); // sequence number
2961 qport = MSG_ReadShort () & 0xffff;
2962
2963 // check which client sent this packet
2964 for (i=0, cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
2965 {
2966 if (cl->state == cs_free)
2967 continue;
2968 if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
2969 continue;
2970 if (cl->netchan.qport != qport)
2971 continue;
2972 if (cl->netchan.remote_address.port != net_from.port)
2973 {
2974 Con_DPrintf ("SV_ReadPackets: fixing up a translated port\n");
2975 cl->netchan.remote_address.port = net_from.port;
2976 }
2977
2978 break;
2979 }
2980
2981 if (i == MAX_CLIENTS)
2982 continue;
2983
2984 // ok, we know who sent this packet, but do we need to delay executing it?
2985 if (cl->delay > 0)
2986 {
2987 if (!svs.free_packets) // packet has to be dropped..
2988 break;
2989
2990 // insert at end of list
2991 if (!cl->packets) {
2992 cl->last_packet = cl->packets = svs.free_packets;
2993 } else {
2994 // this works because '=' associates from right to left
2995 cl->last_packet = cl->last_packet->next = svs.free_packets;
2996 }
2997
2998 svs.free_packets = svs.free_packets->next;
2999 cl->last_packet->next = NULL;
3000
3001 cl->last_packet->time = realtime;
3002 SZ_Clear(&cl->last_packet->msg);
3003 SZ_Write(&cl->last_packet->msg, net_message.data, net_message.cursize);
3004 }
3005 else
3006 {
3007 SV_ExecuteClientMessage (cl);
3008 }
3009 }
3010 }
3011
3012
3013 /*
3014 ==================
3015 SV_CheckTimeouts
3016
3017 If a packet has not been received from a client in timeout.value
3018 seconds, drop the conneciton.
3019
3020 When a client is normally dropped, the client_t goes into a zombie state
3021 for a few seconds to make sure any final reliable message gets resent
3022 if necessary
3023 ==================
3024 */
SV_CheckTimeouts(void)3025 static void SV_CheckTimeouts (void)
3026 {
3027 int i, nclients;
3028 float droptime;
3029 client_t *cl;
3030
3031 if (sv.state != ss_active)
3032 return;
3033
3034 droptime = curtime - timeout.value;
3035 nclients = 0;
3036
3037 for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
3038 {
3039 #ifdef USE_PR2
3040 if( cl->isBot )
3041 continue;
3042 #endif
3043 if (cl->state >= cs_preconnected /*|| cl->state == cs_spawned*/)
3044 {
3045 if (!cl->spectator)
3046 nclients++;
3047 if (cl->netchan.last_received < droptime)
3048 {
3049 SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
3050 SV_DropClient (cl);
3051 cl->state = cs_free; // don't bother with zombie state
3052 }
3053 if (!cl->logged && !cl->logged_in_via_web) {
3054 SV_LoginCheckTimeOut(cl);
3055 }
3056 }
3057 if (cl->state == cs_zombie && SV_ClientConnectedTime(cl) > zombietime.value)
3058 {
3059 cl->state = cs_free; // can now be reused
3060 }
3061 }
3062 if ((sv.paused & 1) && !nclients)
3063 {
3064 // nobody left, unpause the server
3065 if (GE_ShouldPause) {
3066 pr_global_struct->time = sv.time;
3067 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
3068 G_FLOAT(OFS_PARM0) = 0 /* newstate = false */;
3069 PR_ExecuteProgram (GE_ShouldPause);
3070 if (!G_FLOAT(OFS_RETURN))
3071 return; // progs said don't unpause
3072 }
3073 SV_TogglePause("Pause released since no players are left.\n", 1);
3074 }
3075 }
3076
3077 #ifdef SERVERONLY
3078 /*
3079 ===================
3080 SV_GetConsoleCommands
3081
3082 Add them exactly as if they had been typed at the console
3083 ===================
3084 */
SV_GetConsoleCommands(void)3085 static void SV_GetConsoleCommands (void)
3086 {
3087 char *cmd;
3088
3089 while (1)
3090 {
3091 cmd = Sys_ConsoleInput ();
3092 if (!cmd)
3093 break;
3094 Cbuf_AddText (cmd);
3095 Cbuf_AddText ("\n");
3096 }
3097 }
3098 #endif
3099
3100 /*
3101 ===================
3102 SV_BoundRate
3103 ===================
3104 */
SV_BoundRate(qbool dl,int rate)3105 int SV_BoundRate (qbool dl, int rate)
3106 {
3107 if (!rate)
3108 rate = 2500;
3109 if (dl)
3110 {
3111 if (!(int)sv_maxdownloadrate.value && (int)sv_maxrate.value && rate > (int)sv_maxrate.value)
3112 rate = (int)sv_maxrate.value;
3113
3114 if (sv_maxdownloadrate.value && rate > sv_maxdownloadrate.value)
3115 rate = (int)sv_maxdownloadrate.value;
3116 }
3117 else
3118 if ((int)sv_maxrate.value && rate > (int) sv_maxrate.value)
3119 rate = (int)sv_maxrate.value;
3120
3121 if (rate < 500)
3122 rate = 500;
3123
3124 if (rate > 100000 * MAX_DUPLICATE_PACKETS)
3125 rate = 100000 * MAX_DUPLICATE_PACKETS;
3126
3127 return rate;
3128 }
3129
3130
3131 /*
3132 ===================
3133 SV_CheckVars
3134
3135 ===================
3136 */
3137
SV_CheckVars(void)3138 static void SV_CheckVars (void)
3139 {
3140 static char pw[MAX_KEY_STRING] = {0}, spw[MAX_KEY_STRING] = {0}, vspw[MAX_KEY_STRING]= {0};
3141 static float old_maxrate = 0, old_maxdlrate = 0;
3142 int v;
3143
3144 if (sv.state != ss_active)
3145 return;
3146
3147 // check password and spectator_password
3148 if (strcmp(password.string, pw) ||
3149 strcmp(spectator_password.string, spw) || strcmp(vip_password.string, vspw))
3150 {
3151 strlcpy (pw, password.string, sizeof(pw));
3152 strlcpy (spw, spectator_password.string, sizeof(spw));
3153 strlcpy (vspw, vip_password.string, sizeof(vspw));
3154 Cvar_Set (&password, pw);
3155 Cvar_Set (&spectator_password, spw);
3156 Cvar_Set (&vip_password, vspw);
3157
3158 v = 0;
3159 if (pw[0] && strcmp(pw, "none"))
3160 v |= 1;
3161 if (spw[0] && strcmp(spw, "none"))
3162 v |= 2;
3163 if (vspw[0] && strcmp(vspw, "none"))
3164 v |= 4;
3165
3166 Con_DPrintf ("Updated needpass.\n");
3167 if (!v)
3168 Info_SetValueForKey (svs.info, "needpass", "", MAX_SERVERINFO_STRING);
3169 else
3170 Info_SetValueForKey (svs.info, "needpass", va("%i",v), MAX_SERVERINFO_STRING);
3171 }
3172
3173 // check sv_maxrate
3174 if ((int)sv_maxrate.value != old_maxrate || (int)sv_maxdownloadrate.value != old_maxdlrate )
3175 {
3176 client_t *cl;
3177 int i;
3178 char *val;
3179
3180 old_maxrate = (int)sv_maxrate.value;
3181 old_maxdlrate = (int)sv_maxdownloadrate.value;
3182
3183 for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
3184 {
3185 if (cl->state < cs_preconnected)
3186 continue;
3187
3188 val = Info_Get (&cl->_userinfo_ctx_, cl->download ? "drate" : "rate");
3189 cl->netchan.rate = 1.0 / SV_BoundRate (cl->download != NULL, Q_atoi(*val ? val : "99999"));
3190 }
3191 }
3192 }
3193
PausedTic(void)3194 static void PausedTic (void)
3195 {
3196 if (sv.state != ss_active)
3197 return;
3198
3199 PR_PausedTic(Sys_DoubleTime() - sv.pausedsince);
3200 }
3201
3202 /*
3203 ==================
3204 SV_Frame
3205
3206 ==================
3207 */
3208 void SV_Map (qbool now);
SV_Frame(double time1)3209 void SV_Frame (double time1)
3210 {
3211 static double start, end;
3212 double demo_start, demo_end;
3213
3214 start = Sys_DoubleTime ();
3215 svs.stats.idle += start - end;
3216
3217 // keep the random time dependent
3218 rand ();
3219
3220 // decide the simulation time
3221 if (!sv.paused)
3222 {
3223 realtime += time1;
3224 sv.time += time1;
3225 }
3226
3227 // check timeouts
3228 SV_CheckTimeouts ();
3229
3230 //bliP: cuff, mute ->
3231 // clean out expired cuffs/mutes
3232 SV_CleanIPList ();
3233 //<-
3234
3235 // clean out bans
3236 SV_CleanBansIPList ();
3237
3238 // toggle the log buffer if full
3239 SV_CheckLog ();
3240
3241 SV_MVDStream_Poll();
3242
3243 #ifdef SERVERONLY
3244 // check for commands typed to the host
3245 SV_GetConsoleCommands ();
3246
3247 // process console commands
3248 Cbuf_Execute ();
3249 #endif
3250
3251 // check for map change;
3252 SV_Map(true);
3253
3254 SV_CheckVars ();
3255
3256 // get packets
3257 SV_ReadPackets ();
3258
3259 // move autonomous things around if enough time has passed
3260 if (!sv.paused) {
3261 SV_Physics();
3262 #ifdef USE_PR2
3263 SV_RunBots();
3264 #endif
3265 }
3266 else
3267 PausedTic ();
3268
3269 // send messages back to the clients that had packets read this frame
3270 SV_SendClientMessages ();
3271
3272 #if defined(SERVERONLY) && defined(WWW_INTEGRATION)
3273 Central_ProcessResponses();
3274 #endif
3275
3276 demo_start = Sys_DoubleTime ();
3277 SV_SendDemoMessage();
3278 demo_end = Sys_DoubleTime ();
3279 svs.stats.demo += demo_end - demo_start;
3280
3281 // send a heartbeat to the master if needed
3282 Master_Heartbeat ();
3283
3284 // collect timing statistics
3285 end = Sys_DoubleTime ();
3286 svs.stats.active += end-start;
3287 if (++svs.stats.count == STATFRAMES)
3288 {
3289 svs.stats.latched_active = svs.stats.active;
3290 svs.stats.latched_idle = svs.stats.idle;
3291 svs.stats.latched_packets = svs.stats.packets;
3292 svs.stats.latched_demo = svs.stats.demo;
3293 svs.stats.active = 0;
3294 svs.stats.idle = 0;
3295 svs.stats.packets = 0;
3296 svs.stats.count = 0;
3297 svs.stats.demo = 0;
3298 }
3299 }
3300
3301 /*
3302 ===============
3303 SV_InitLocal
3304 ===============
3305 */
SV_InitLocal(void)3306 void SV_InitLocal (void)
3307 {
3308 int i;
3309 char cmd_line[1024] = {0};
3310
3311 extern cvar_t sv_maxvelocity;
3312 extern cvar_t sv_gravity;
3313 extern cvar_t sv_stopspeed;
3314 extern cvar_t sv_spectatormaxspeed;
3315 extern cvar_t sv_accelerate;
3316 extern cvar_t sv_airaccelerate;
3317 extern cvar_t sv_wateraccelerate;
3318 extern cvar_t sv_friction;
3319 extern cvar_t sv_waterfriction;
3320 extern cvar_t sv_nailhack;
3321
3322 extern cvar_t sv_maxpitch;
3323 extern cvar_t sv_minpitch;
3324
3325 extern cvar_t pm_airstep;
3326 extern cvar_t pm_pground;
3327 extern cvar_t pm_rampjump;
3328 //extern cvar_t pm_slidefix;
3329 extern cvar_t pm_ktjump;
3330 //extern cvar_t pm_bunnyspeedcap;
3331
3332 // qws = QuakeWorld Server information
3333 static cvar_t qws_name = { "qws_name", SERVER_NAME, CVAR_ROM };
3334 static cvar_t qws_fullname = { "qws_fullname", SERVER_FULLNAME, CVAR_ROM };
3335 static cvar_t qws_version = { "qws_version", SERVER_VERSION, CVAR_ROM };
3336 static cvar_t qws_buildnum = { "qws_buildnum", "unknown", CVAR_ROM };
3337 static cvar_t qws_platform = { "qws_platform", QW_PLATFORM_SHORT, CVAR_ROM };
3338 static cvar_t qws_builddate = { "qws_builddate", BUILD_DATE, CVAR_ROM };
3339 static cvar_t qws_homepage = { "qws_homepage", SERVER_HOME_URL, CVAR_ROM };
3340 // qwm = QuakeWorld Mod information placeholders
3341 static cvar_t qwm_name = { "qwm_name", "" };
3342 static cvar_t qwm_fullname = { "qwm_fullname", "" };
3343 static cvar_t qwm_version = { "qwm_version", "" };
3344 static cvar_t qwm_buildnum = { "qwm_buildnum", "" };
3345 static cvar_t qwm_platform = { "qwm_platform", "" };
3346 static cvar_t qwm_builddate = { "qwm_builddate", "" };
3347 static cvar_t qwm_homepage = { "qwm_homepage", "" };
3348
3349 packet_t *packet_freeblock; // initialise delayed packet free block
3350
3351 SV_InitOperatorCommands ();
3352 SV_UserInit ();
3353
3354 Cvar_Register (&sv_getrealip);
3355 Cvar_Register (&sv_maxdownloadrate);
3356 Cvar_Register (&sv_serverip);
3357 Cvar_Register (&sv_forcespec_onfull);
3358
3359 #ifdef SERVERONLY
3360 Cvar_Register (&rcon_password);
3361 Cvar_Register (&password);
3362 #endif
3363
3364 Cvar_Register (&sv_hashpasswords);
3365 //Added by VVD {
3366 Cvar_Register (&sv_crypt_rcon);
3367 Cvar_Register (&sv_timestamplen);
3368 Cvar_Register (&sv_rconlim);
3369
3370 Cvar_Register (&telnet_log_level);
3371
3372 Cvar_Register (&frag_log_type);
3373 Cvar_Register (&qconsole_log_say);
3374 Cvar_Register (&sv_use_dns);
3375
3376 for (i = 0; i < COM_Argc(); i++)
3377 {
3378 if (i)
3379 strlcat(cmd_line, " ", sizeof(cmd_line));
3380 strlcat(cmd_line, COM_Argv(i), sizeof(cmd_line));
3381 }
3382 Cvar_Register (&sys_command_line);
3383 Cvar_SetROM(&sys_command_line, cmd_line);
3384
3385 //Added by VVD }
3386 Cvar_Register (&spectator_password);
3387 Cvar_Register (&vip_password);
3388 Cvar_Register (&vip_values);
3389
3390 Cvar_Register (&sv_nailhack);
3391
3392 Cvar_Register (&sv_mintic);
3393 Cvar_Register (&sv_maxtic);
3394 Cvar_Register (&sv_maxfps);
3395 Cvar_Register (&sys_select_timeout);
3396 Cvar_Register (&sys_restart_on_error);
3397
3398 Cvar_Register (&sv_maxpitch);
3399 Cvar_Register (&sv_minpitch);
3400
3401 Cvar_Register (&skill);
3402 Cvar_Register (&coop);
3403
3404 Cvar_Register (&fraglimit);
3405 Cvar_Register (&timelimit);
3406 Cvar_Register (&teamplay);
3407 Cvar_Register (&samelevel);
3408 Cvar_Register (&maxclients);
3409 Cvar_Register (&maxspectators);
3410 Cvar_Register (&maxvip_spectators);
3411 Cvar_Register (&hostname);
3412 Cvar_Register (&deathmatch);
3413 Cvar_Register (&watervis);
3414 Cvar_Register (&serverdemo);
3415 Cvar_Register (&sv_paused);
3416
3417 Cvar_Register (&timeout);
3418 Cvar_Register (&zombietime);
3419
3420 Cvar_Register (&sv_maxvelocity);
3421 Cvar_Register (&sv_gravity);
3422 Cvar_Register (&sv_stopspeed);
3423 Cvar_Register (&sv_maxspeed);
3424 Cvar_Register (&sv_spectatormaxspeed);
3425 Cvar_Register (&sv_accelerate);
3426 Cvar_Register (&sv_airaccelerate);
3427 Cvar_Register (&sv_wateraccelerate);
3428 Cvar_Register (&sv_friction);
3429 Cvar_Register (&sv_waterfriction);
3430
3431 Cvar_Register (&sv_antilag);
3432 Cvar_Register (&sv_antilag_no_pred);
3433 Cvar_Register (&sv_antilag_projectiles);
3434
3435 //Cvar_Register (&pm_bunnyspeedcap);
3436 Cvar_Register (&pm_ktjump);
3437 //Cvar_Register (&pm_slidefix);
3438 Cvar_Register (&pm_pground);
3439 Cvar_Register (&pm_airstep);
3440 Cvar_Register (&pm_rampjump);
3441
3442 Cvar_Register (&filterban);
3443
3444 Cvar_Register (&allow_download);
3445 Cvar_Register (&allow_download_skins);
3446 Cvar_Register (&allow_download_models);
3447 Cvar_Register (&allow_download_sounds);
3448 Cvar_Register (&allow_download_maps);
3449 Cvar_Register (&allow_download_pakmaps);
3450 Cvar_Register (&allow_download_demos);
3451 Cvar_Register (&allow_download_other);
3452 //bliP: init ->
3453 Cvar_Register (&download_map_url);
3454
3455 Cvar_Register (&sv_specprint);
3456 Cvar_Register (&sv_admininfo);
3457 Cvar_Register (&sv_reconnectlimit);
3458 Cvar_Register (&sv_maxlogsize);
3459 //bliP: 24/9 ->
3460 Cvar_Register (&sv_logdir);
3461 Cvar_Register (&sv_speedcheck);
3462 Cvar_Register (&sv_unfake); // kickfake to unfake
3463 //<-
3464 Cvar_Register (&sv_kicktop);
3465 //<-
3466 Cvar_Register (&sv_allowlastscores);
3467 // Cvar_Register (&sv_highchars);
3468 Cvar_Register (&sv_phs);
3469 Cvar_Register (&pausable);
3470 Cvar_Register (&sv_maxrate);
3471 Cvar_Register (&sv_loadentfiles);
3472 Cvar_Register (&sv_loadentfiles_dir);
3473 Cvar_Register (&sv_default_name);
3474 Cvar_Register (&sv_mod_msg_file);
3475 Cvar_Register (&sv_forcenick);
3476 Cvar_Register (&sv_registrationinfo);
3477 Cvar_Register (®istered);
3478
3479 Cvar_Register (&sv_halflifebsp);
3480 Cvar_Register (&sv_bspversion);
3481 Cvar_Register (&sv_serveme_fix);
3482
3483 #ifdef FTE_PEXT_FLOATCOORDS
3484 Cvar_Register (&sv_bigcoords);
3485 #endif
3486
3487 Cvar_Register (&sv_extlimits);
3488 Cvar_Register (&sv_pext_mvdsv_serversideweapon);
3489
3490 Cvar_Register (&sv_reliable_sound);
3491
3492 Cvar_Register(&qws_name);
3493 Cvar_Register(&qws_fullname);
3494 Cvar_Register(&qws_version);
3495 if (GIT_COMMIT[0]) {
3496 qws_buildnum.string = GIT_COMMIT;
3497 }
3498 Cvar_Register(&qws_buildnum);
3499 Cvar_Register(&qws_platform);
3500 Cvar_Register(&qws_builddate);
3501 Cvar_Register(&qws_homepage);
3502 Cvar_Register(&qwm_name);
3503 Cvar_Register(&qwm_fullname);
3504 Cvar_Register(&qwm_version);
3505 Cvar_Register(&qwm_buildnum);
3506 Cvar_Register(&qwm_platform);
3507 Cvar_Register(&qwm_builddate);
3508 Cvar_Register(&qwm_homepage);
3509
3510 Cvar_Register(&sv_mod_extensions);
3511
3512 // QW262 -->
3513 Cmd_AddCommand ("svadmin", SV_Admin_f);
3514 // <-- QW262
3515
3516 Cmd_AddCommand ("addip", SV_AddIP_f);
3517 Cmd_AddCommand ("removeip", SV_RemoveIP_f);
3518 Cmd_AddCommand ("listip", SV_ListIP_f);
3519 Cmd_AddCommand ("writeip", SV_WriteIP_f);
3520 Cmd_AddCommand ("vip_addip", SV_AddIPVIP_f);
3521 Cmd_AddCommand ("vip_removeip", SV_RemoveIPVIP_f);
3522 Cmd_AddCommand ("vip_listip", SV_ListIPVIP_f);
3523 Cmd_AddCommand ("vip_writeip", SV_WriteIPVIP_f);
3524
3525
3526 for (i=0 ; i<MAX_MODELS ; i++)
3527 snprintf (localmodels[i], MODEL_NAME_LEN, "*%i", i);
3528
3529 #ifdef FTE_PEXT_ACCURATETIMINGS
3530 svs.fteprotocolextensions |= FTE_PEXT_ACCURATETIMINGS;
3531 #endif
3532 #ifdef FTE_PEXT_256PACKETENTITIES
3533 svs.fteprotocolextensions |= FTE_PEXT_256PACKETENTITIES;
3534 #endif
3535 #ifdef FTE_PEXT_CHUNKEDDOWNLOADS
3536 svs.fteprotocolextensions |= FTE_PEXT_CHUNKEDDOWNLOADS;
3537 #endif
3538 #ifdef FTE_PEXT_FLOATCOORDS
3539 svs.fteprotocolextensions |= FTE_PEXT_FLOATCOORDS;
3540 #endif
3541 #ifdef FTE_PEXT_MODELDBL
3542 svs.fteprotocolextensions |= FTE_PEXT_MODELDBL;
3543 #endif
3544 #ifdef FTE_PEXT_ENTITYDBL
3545 svs.fteprotocolextensions |= FTE_PEXT_ENTITYDBL;
3546 #endif
3547 #ifdef FTE_PEXT_ENTITYDBL2
3548 svs.fteprotocolextensions |= FTE_PEXT_ENTITYDBL2;
3549 #endif
3550 #ifdef FTE_PEXT_SPAWNSTATIC2
3551 svs.fteprotocolextensions |= FTE_PEXT_SPAWNSTATIC2;
3552 #endif
3553
3554 #ifdef FTE_PEXT2_VOICECHAT
3555 svs.fteprotocolextensions2 |= FTE_PEXT2_VOICECHAT;
3556 #endif
3557
3558 #ifdef MVD_PEXT1_FLOATCOORDS
3559 svs.mvdprotocolextension1 |= MVD_PEXT1_FLOATCOORDS;
3560 #endif
3561 #ifdef MVD_PEXT1_HIGHLAGTELEPORT
3562 svs.mvdprotocolextension1 |= MVD_PEXT1_HIGHLAGTELEPORT;
3563 #endif
3564 #ifdef MVD_PEXT1_SERVERSIDEWEAPON
3565 svs.mvdprotocolextension1 |= MVD_PEXT1_SERVERSIDEWEAPON;
3566 #endif
3567 #ifdef MVD_PEXT1_HIDDEN_MESSAGES
3568 svs.mvdprotocolextension1 |= MVD_PEXT1_HIDDEN_MESSAGES;
3569 #endif
3570 #ifdef MVD_PEXT1_SERVERSIDEWEAPON2
3571 svs.mvdprotocolextension1 |= MVD_PEXT1_SERVERSIDEWEAPON2;
3572 #endif
3573
3574 Info_SetValueForStarKey (svs.info, "*version", SERVER_NAME " " SERVER_VERSION, MAX_SERVERINFO_STRING);
3575 Info_SetValueForStarKey (svs.info, "*z_ext", va("%i", SERVER_EXTENSIONS), MAX_SERVERINFO_STRING);
3576
3577 // init fraglog stuff
3578 svs.logsequence = 1;
3579 svs.logtime = realtime;
3580 svs.log[0].data = svs.log_buf[0];
3581 svs.log[0].maxsize = sizeof(svs.log_buf[0]);
3582 svs.log[0].cursize = 0;
3583 svs.log[0].allowoverflow = true;
3584 svs.log[1].data = svs.log_buf[1];
3585 svs.log[1].maxsize = sizeof(svs.log_buf[1]);
3586 svs.log[1].cursize = 0;
3587 svs.log[1].allowoverflow = true;
3588
3589 packet_freeblock = (packet_t *) Hunk_AllocName (MAX_DELAYED_PACKETS * sizeof(packet_t), "delayed_packets");
3590
3591 for (i = 0; i < MAX_DELAYED_PACKETS; i++) {
3592 SZ_Init (&packet_freeblock[i].msg, packet_freeblock[i].buf, sizeof(packet_freeblock[i].buf));
3593 packet_freeblock[i].next = &packet_freeblock[i + 1];
3594 }
3595 packet_freeblock[MAX_DELAYED_PACKETS - 1].next = NULL;
3596 svs.free_packets = &packet_freeblock[0];
3597 }
3598
3599
3600 //============================================================================
3601
3602 /*
3603 =================
3604 SV_ExtractFromUserinfo
3605
3606 Pull specific info from a newly changed userinfo string
3607 into a more C freindly form.
3608 =================
3609 */
SV_ExtractFromUserinfo(client_t * cl,qbool namechanged)3610 void SV_ExtractFromUserinfo (client_t *cl, qbool namechanged)
3611 {
3612 char *val, *p;
3613 int i;
3614 client_t *client;
3615 int dupc = 1;
3616 char newname[CLIENT_NAME_LEN];
3617
3618 if (namechanged)
3619 {
3620 // name for C code
3621 val = Info_Get (&cl->_userinfo_ctx_, "name");
3622
3623 // trim user name
3624 strlcpy (newname, val, sizeof(newname));
3625
3626 for (p = val; *p; p++)
3627 {
3628 if ((*p & 127) == '\\' || *p == '\r' || *p == '\n' || *p == '$' || *p == '#' || *p == '"' || *p == ';')
3629 { // illegal characters in name, set some default
3630 strlcpy(newname, sv_default_name.string, sizeof(newname));
3631 break;
3632 }
3633 }
3634
3635 for (p = newname; *p && (*p & 127) == ' '; p++)
3636 ; // empty operator
3637
3638 if (p != newname) // skip prefixed spaces, if any, even whole string of spaces
3639 strlcpy(newname, p, sizeof(newname));
3640
3641 for (p = newname + strlen(newname) - 1; p >= newname; p--)
3642 {
3643 if (*p && (*p & 127) != ' ') // skip spaces in suffix, if any
3644 {
3645 p[1] = 0;
3646 break;
3647 }
3648 }
3649
3650 if (strcmp(val, newname))
3651 {
3652 Info_Set (&cl->_userinfo_ctx_, "name", newname);
3653 val = Info_Get (&cl->_userinfo_ctx_, "name");
3654 }
3655
3656 if (!val[0] || !Q_namecmp(val, "console") || strstr(val, "&c") || strstr(val, "&r"))
3657 {
3658 Info_Set (&cl->_userinfo_ctx_, "name", sv_default_name.string);
3659 val = Info_Get (&cl->_userinfo_ctx_, "name");
3660 }
3661
3662 // check to see if another user by the same name exists
3663 while ( 1 )
3664 {
3665 for (i = 0, client = svs.clients ; i<MAX_CLIENTS ; i++, client++)
3666 {
3667 if (client->state != cs_spawned || client == cl)
3668 continue;
3669
3670 if (!Q_namecmp(client->name, val))
3671 break;
3672 }
3673 if (i != MAX_CLIENTS)
3674 { // dup name
3675 if (strlen(val) > CLIENT_NAME_LEN - 1)
3676 val[CLIENT_NAME_LEN - 4] = 0;
3677 p = val;
3678
3679 if (val[0] == '(')
3680 {
3681 if (val[2] == ')')
3682 p = val + 3;
3683 else if (val[3] == ')')
3684 p = val + 4;
3685 }
3686
3687 snprintf(newname, sizeof(newname), "(%d)%-.10s", dupc++, p);
3688 Info_Set (&cl->_userinfo_ctx_, "name", newname);
3689 val = Info_Get (&cl->_userinfo_ctx_, "name");
3690 }
3691 else
3692 break;
3693 }
3694
3695 if (strncmp(val, cl->name, strlen(cl->name) + 1))
3696 {
3697 if (!cl->lastnametime || curtime - cl->lastnametime > 5) {
3698 cl->lastnamecount = 0;
3699 cl->lastnametime = curtime;
3700 }
3701 else if (cl->lastnamecount++ > 4) {
3702 SV_BroadcastPrintf(PRINT_HIGH, "%s was kicked for name spamming\n", cl->name);
3703 SV_ClientPrintf(cl, PRINT_HIGH, "You were kicked from the game for name spamming\n");
3704 SV_LogPlayer(cl, "name spam", 1); //bliP: player logging
3705 SV_DropClient(cl);
3706 return;
3707 }
3708
3709 if (cl->state >= cs_spawned && !cl->spectator) {
3710 SV_BroadcastPrintf(PRINT_HIGH, "%s changed name to %s\n", cl->name, val);
3711 }
3712 }
3713
3714 strlcpy(cl->name, val, CLIENT_NAME_LEN);
3715
3716 if (cl->state >= cs_spawned) //bliP: player logging
3717 SV_LogPlayer(cl, "name change", 1);
3718 }
3719
3720 // team
3721 val = Info_Get (&cl->_userinfo_ctx_, "team");
3722 if (strstr(val, "&c") || strstr(val, "&r"))
3723 Info_Set (&cl->_userinfo_ctx_, "team", "none");
3724 strlcpy (cl->team, Info_Get (&cl->_userinfo_ctx_, "team"), sizeof(cl->team));
3725
3726 // rate
3727 val = Info_Get (&cl->_userinfo_ctx_, cl->download ? "drate" : "rate");
3728 cl->netchan.rate = 1.0 / SV_BoundRate (cl->download != NULL, Q_atoi(*val ? val : "99999"));
3729
3730 // s2c packet dupes
3731 val = Info_Get(&cl->_userinfo_ctx_, "dupe");
3732 cl->dupe = atoi(val);
3733 cl->dupe = (int)bound(0, cl->dupe, MAX_DUPLICATE_PACKETS); // 0=1 packet (aka: no dupes)
3734 cl->netchan.dupe = (cl->download ? 0 : cl->dupe);
3735
3736 // message level
3737 val = Info_Get (&cl->_userinfo_ctx_, "msg");
3738 if (val[0])
3739 cl->messagelevel = Q_atoi(val);
3740
3741 //spectator print
3742 val = Info_Get(&cl->_userinfo_ctx_, "sp");
3743 if (val[0])
3744 cl->spec_print = Q_atoi(val);
3745 }
3746
3747
3748 //============================================================================
3749
OnChange_sysselecttimeout_var(cvar_t * var,char * value,qbool * cancel)3750 void OnChange_sysselecttimeout_var (cvar_t *var, char *value, qbool *cancel)
3751 {
3752 int t = Q_atoi (value);
3753
3754 if (t < 1000 || t > 1000000)
3755 {
3756 Con_Printf("WARNING: sys_select_timeout can't be less then 1000 (1 millisecond) and more then 1 000 000 (1 second).\n");
3757 *cancel = true;
3758 return;
3759 }
3760 }
3761
3762 //bliP: 24/9 logdir ->
OnChange_logdir_var(cvar_t * var,char * value,qbool * cancel)3763 void OnChange_logdir_var (cvar_t *var, char *value, qbool *cancel)
3764 {
3765 if (strstr(value, ".."))
3766 {
3767 *cancel = true;
3768 return;
3769 }
3770
3771 if (value[0])
3772 Sys_mkdir (value);
3773 }
3774 //<-
3775
3776 //bliP: admininfo ->
OnChange_admininfo_var(cvar_t * var,char * value,qbool * cancel)3777 void OnChange_admininfo_var (cvar_t *var, char *value, qbool *cancel)
3778 {
3779 if (value[0])
3780 Info_SetValueForStarKey (svs.info, "*admin", value, MAX_SERVERINFO_STRING);
3781 else
3782 Info_RemoveKey (svs.info, "*admin");
3783 }
3784 //<-
3785
3786 //bliP: telnet log level ->
OnChange_telnetloglevel_var(cvar_t * var,char * value,qbool * cancel)3787 void OnChange_telnetloglevel_var (cvar_t *var, char *value, qbool *cancel)
3788 {
3789 logs[TELNET_LOG].log_level = Q_atoi(value);
3790 }
3791 //<-
OnChange_qconsolelogsay_var(cvar_t * var,char * value,qbool * cancel)3792 void OnChange_qconsolelogsay_var (cvar_t *var, char *value, qbool *cancel)
3793 {
3794 logs[CONSOLE_LOG].log_level = Q_atoi(value);
3795 }
3796
3797 #ifdef SERVERONLY
3798
COM_Init(void)3799 void COM_Init (void)
3800 {
3801 Cvar_Register (&developer);
3802 Cvar_Register (&version);
3803 Cvar_Register (&sys_simulation);
3804
3805 Cvar_SetROM(&version, SERVER_NAME " " SERVER_VERSION);
3806 }
3807
3808 //Free hunk memory up to host_hunklevel
3809 //Can only be called when changing levels!
Host_ClearMemory(void)3810 void Host_ClearMemory (void)
3811 {
3812 if (!host_initialized)
3813 Sys_Error ("Host_ClearMemory before host initialized");
3814
3815 CM_InvalidateMap ();
3816
3817 // any data previously allocated on hunk is no longer valid
3818 Hunk_FreeToLowMark (host_hunklevel);
3819 }
3820
3821 //memsize is the recommended amount of memory to use for hunk
Host_InitMemory(int memsize)3822 void Host_InitMemory (int memsize)
3823 {
3824 int t;
3825
3826 if (SV_CommandLineUseMinimumMemory())
3827 memsize = MINIMUM_MEMORY;
3828
3829 if ((t = SV_CommandLineHeapSizeMemoryKB()) != 0 && t + 1 < COM_Argc())
3830 memsize = Q_atoi (COM_Argv(t + 1)) * 1024;
3831
3832 if ((t = SV_CommandLineHeapSizeMemoryMB()) != 0 && t + 1 < COM_Argc())
3833 memsize = Q_atoi (COM_Argv(t + 1)) * 1024 * 1024;
3834
3835 if (memsize < MINIMUM_MEMORY)
3836 Sys_Error ("Only %4.1f megs of memory reported, can't execute game", memsize / (float)0x100000);
3837
3838 Memory_Init (Q_malloc(memsize), memsize);
3839 }
3840
Host_Init(int argc,char ** argv,int default_memsize)3841 void Host_Init (int argc, char **argv, int default_memsize)
3842 {
3843 extern int hunk_size;
3844 cvar_t *v;
3845
3846 srand((unsigned)time(NULL));
3847
3848 COM_InitArgv (argc, argv);
3849
3850 Host_InitMemory (default_memsize);
3851
3852 Con_Printf ("============= Starting %s =============\n", VersionStringFull());
3853
3854 Cbuf_Init ();
3855 Cmd_Init ();
3856 Cvar_Init ();
3857 COM_Init ();
3858
3859 FS_Init ();
3860 NET_Init ();
3861
3862 Netchan_Init ();
3863
3864 Sys_Init ();
3865 CM_Init ();
3866
3867 SV_Init ();
3868
3869 Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
3870 host_hunklevel = Hunk_LowMark ();
3871
3872 host_initialized = true;
3873
3874 // walk through all vars and forse OnChange event if cvar was modified,
3875 // also apply that to variables which mirrored in userinfo because of cl_parsefunchars was't applyed as this moment,
3876 // same for serverinfo and may be this fix something also.
3877 for ( v = NULL; (v = Cvar_Next ( v )); )
3878 {
3879 if ( Cvar_GetFlags( v ) & (CVAR_ROM) )
3880 continue;
3881
3882 Cvar_Set(v, v->string);
3883 }
3884
3885 Con_Printf ("%4.1f megabyte heap\n", (float)hunk_size / (1024 * 1024));
3886 Con_Printf ("QuakeWorld Initialized\n");
3887
3888 Cbuf_InsertText ("exec server.cfg\n");
3889
3890 // process command line arguments
3891 Cmd_StuffCmds_f ();
3892 Cbuf_Execute ();
3893
3894 host_everything_loaded = true;
3895
3896 SV_Map(true);
3897
3898 // if a map wasn't specified on the command line, spawn mvdsv-kg map
3899 if (sv.state == ss_dead)
3900 {
3901 Cmd_ExecuteString ("map mvdsv-kg");
3902 SV_Map(true);
3903 }
3904
3905 // last resort - start map
3906 if (sv.state == ss_dead)
3907 {
3908 Cmd_ExecuteString ("map start");
3909 SV_Map(true);
3910 }
3911
3912 if (sv.state == ss_dead)
3913 SV_Error ("Couldn't spawn a server");
3914
3915 #if defined (_WIN32) && !defined(_CONSOLE)
3916 {
3917 void SetWindowText_(char*);
3918 SetWindowText_(va(SERVER_NAME ":%d - QuakeWorld server", NET_UDPSVPort()));
3919 }
3920 #endif
3921 }
3922
3923 #endif // SERVERONLY
3924
3925 /*
3926 ====================
3927 SV_Init
3928 ====================
3929 */
3930
SV_Init(void)3931 void SV_Init (void)
3932 {
3933 memset(&_localinfo_, 0, sizeof(_localinfo_));
3934 _localinfo_.max = MAX_LOCALINFOS;
3935
3936 PR_Init ();
3937
3938 // send immediately
3939 svs.last_heartbeat = -99999;
3940
3941 SV_InitLocal ();
3942
3943 SV_MVDInit ();
3944 Login_Init ();
3945 #ifndef SERVERONLY
3946 server_cfg_done = true;
3947 #endif
3948
3949 #if defined(SERVERONLY) && defined(WWW_INTEGRATION)
3950 Central_Init ();
3951 #endif
3952 }
3953
3954 /*
3955 ============
3956 SV_TimeOfDay
3957 ============
3958 */
SV_TimeOfDay(date_t * date,char * timeformat)3959 void SV_TimeOfDay(date_t *date, char *timeformat)
3960 {
3961 struct tm *newtime;
3962 time_t long_time;
3963
3964 time(&long_time);
3965 newtime = localtime(&long_time);
3966
3967 //bliP: date check ->
3968 if (!newtime)
3969 {
3970 date->day = 0;
3971 date->mon = 0;
3972 date->year = 0;
3973 date->hour = 0;
3974 date->min = 0;
3975 date->sec = 0;
3976 strlcpy(date->str, "#bad date#", sizeof(date->str));
3977 return;
3978 }
3979 //<-
3980
3981 date->day = newtime->tm_mday;
3982 date->mon = newtime->tm_mon;
3983 date->year = newtime->tm_year + 1900;
3984 date->hour = newtime->tm_hour;
3985 date->min = newtime->tm_min;
3986 date->sec = newtime->tm_sec;
3987 strftime(date->str, sizeof(date->str)-1, timeformat, newtime);
3988 }
3989
3990 //bliP: player logging ->
3991 /*
3992 ============
3993 SV_LogPlayer
3994 ============
3995 */
SV_LogPlayer(client_t * cl,char * msg,int level)3996 void SV_LogPlayer(client_t *cl, char *msg, int level)
3997 {
3998 char info[MAX_EXT_INFO_STRING];
3999 char name[CLIENT_NAME_LEN];
4000
4001 Info_ReverseConvert(&cl->_userinfo_ctx_, info, sizeof(info));
4002 Q_normalizetext(info);
4003 strlcpy(name, cl->name, sizeof(name));
4004 Q_normalizetext(name);
4005
4006 SV_Write_Log(PLAYER_LOG, level,
4007 va("%s\\%s\\%i\\%s\\%s\\%i%s\n",
4008 msg,
4009 name,
4010 cl->userid,
4011 NET_BaseAdrToString(cl->netchan.remote_address),
4012 NET_BaseAdrToString(cl->realip),
4013 cl->netchan.remote_address.port,
4014 info
4015 )
4016 );
4017 }
4018
4019 /*
4020 ============
4021 SV_Write_Log
4022 ============
4023 */
SV_Write_Log(int sv_log,int level,char * msg)4024 void SV_Write_Log(int sv_log, int level, char *msg)
4025 {
4026 static date_t date;
4027 char *log_msg, *error_msg;
4028
4029 if (!(logs[sv_log].sv_logfile && *msg))
4030 return;
4031
4032 if (logs[sv_log].log_level < level)
4033 return;
4034
4035 SV_TimeOfDay(&date, "%a %b %d, %H:%M:%S %Y");
4036
4037 switch (sv_log)
4038 {
4039 case FRAG_LOG:
4040 case MOD_FRAG_LOG:
4041 log_msg = msg; // these logs aren't in fs_gamedir
4042 error_msg = va("Can't write in %s log file: "/*%s/ */"%sN.log.\n",
4043 /*fs_gamedir,*/ logs[sv_log].message_on,
4044 logs[sv_log].file_name);
4045 break;
4046 default:
4047 log_msg = va("[%s].[%d] %s", date.str, level, msg);
4048 error_msg = va("Can't write in %s log file: "/*%s/ */"%s%i.log.\n",
4049 /*fs_gamedir,*/ logs[sv_log].message_on,
4050 logs[sv_log].file_name, NET_UDPSVPort());
4051 }
4052
4053 if (fprintf(logs[sv_log].sv_logfile, "%s", log_msg) < 0)
4054 {
4055 //bliP: Sys_Error to Con_DPrintf ->
4056 //VVD: Con_DPrintf to Sys_Printf ->
4057 Sys_Printf("%s", error_msg);
4058 //<-
4059 SV_Logfile(sv_log, false);
4060 }
4061 else
4062 {
4063 fflush(logs[sv_log].sv_logfile);
4064 if ((int)sv_maxlogsize.value &&
4065 (FS_FileLength(logs[sv_log].sv_logfile) > (int)sv_maxlogsize.value))
4066 {
4067 SV_Logfile(sv_log, true);
4068 }
4069 }
4070 }
4071
4072 /*
4073 ============
4074 Sys_compare_by functions for sort files in list
4075 ============
4076 */
Sys_compare_by_date(const void * a,const void * b)4077 int Sys_compare_by_date (const void *a, const void *b)
4078 {
4079 return (int)(((file_t *)a)->time - ((file_t *)b)->time);
4080 }
4081
Sys_compare_by_name(const void * a,const void * b)4082 int Sys_compare_by_name (const void *a, const void *b)
4083 {
4084 return strncmp(((file_t *)a)->name, ((file_t *)b)->name, MAX_DEMO_NAME);
4085 }
4086
4087 // real-world time passed
SV_ClientConnectedTime(client_t * client)4088 double SV_ClientConnectedTime(client_t* client)
4089 {
4090 if (!client->connection_started_curtime) {
4091 return 0;
4092 }
4093 return curtime - client->connection_started_curtime;
4094 }
4095
4096 // affected by pause
SV_ClientGameTime(client_t * client)4097 double SV_ClientGameTime(client_t* client)
4098 {
4099 if (!client->connection_started_realtime) {
4100 return 0;
4101 }
4102
4103 return realtime - client->connection_started_realtime;
4104 }
4105
SV_SetClientConnectionTime(client_t * client)4106 void SV_SetClientConnectionTime(client_t* client)
4107 {
4108 client->connection_started_realtime = realtime;
4109 client->connection_started_curtime = curtime;
4110 }
4111
4112 #endif // !CLIENTONLY
4113