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