UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
sv_main.cpp
Go to the documentation of this file.
1 
6 /*
7 All original material Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 Original file from Quake 2 v3.21: quake2-2.31/server/sv_main.c
10 Copyright (C) 1997-2001 Id Software, Inc.
11 
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 as published by the Free Software Foundation; either version 2
15 of the License, or (at your option) any later version.
16 
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 
21 See the GNU General Public License for more details.
22 
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 
27 */
28 
29 #include "server.h"
30 #include "sv_log.h"
31 #include "../ports/system.h"
32 #include "../shared/scopedmutex.h"
33 #include "../shared/thread.h"
34 
44 static cvar_t* sv_timeout; /* seconds without any message */
45 
46 cvar_t* sv_maxclients = nullptr;
54 
56 
57 typedef struct leakyBucket_s {
58  char node[64];
59 
60  int lastTime;
61  signed char burst;
62 
63  long hash;
64 
68 
69 /* This is deliberately quite large to make it more of an effort to DoS */
70 #define MAX_BUCKETS 16384
71 #define MAX_HASHES 1024
72 
76 
78 {
79  if (!Com_CheckConfigStringIndex(index))
80  Com_Error(ERR_FATAL, "Invalid config string index given: %i", index);
81 
82  return sv->configstrings[index];
83 }
84 
86 {
87  if (!Com_CheckConfigStringIndex(index))
88  Com_Error(ERR_FATAL, "Invalid config string index given: %i", index);
89 
90  switch (index) {
91  case CS_ENTITYSTRING:
93  case CS_TILES:
95  case CS_POSITIONS:
97  case CS_MODELS:
98  return MAX_TOKEN_CHARS * MAX_MODELS;
99  case CS_PLAYERNAMES:
100  return MAX_TOKEN_CHARS * MAX_CLIENTS;
101  case CS_GENERAL:
102  return MAX_TOKEN_CHARS * MAX_GENERAL;
103  default:
104  return MAX_TOKEN_CHARS;
105  }
106 }
107 
109 {
110  return atoi(SV_GetConfigString(index));
111 }
112 
113 char* SV_SetConfigString (int index, ...)
114 {
115  va_list ap;
116  const char* value;
117 
118  if (!Com_CheckConfigStringIndex(index))
119  Com_Error(ERR_FATAL, "Invalid config string index given: %i", index);
120 
121  va_start(ap, index);
122 
123  switch (index) {
124  case CS_LIGHTMAP:
125  case CS_MAPCHECKSUM:
126  case CS_UFOCHECKSUM:
127  case CS_OBJECTAMOUNT:
128  value = va("%i", va_arg(ap, int));
129  break;
130  default:
131  value = va_arg(ap, char*);
132  break;
133  }
134 
135  /* change the string in sv
136  * there may be overflows in i==CS_TILES - but thats ok
137  * see definition of configstrings and MAX_TILESTRINGS */
138  if (index == CS_TILES || index == CS_POSITIONS)
140  else
141  Q_strncpyz(sv->configstrings[index], value, sizeof(sv->configstrings[index]));
142 
143  va_end(ap);
144 
145  return sv->configstrings[index];
146 }
147 
153 {
154  client_t* endOfClients = &svs.clients[sv_maxclients->integer];
155  client_t* client;
156 
157  if (!sv_maxclients->integer)
158  return nullptr;
159 
160  if (!lastClient)
161  return svs.clients;
162  assert(lastClient >= svs.clients);
163  assert(lastClient < endOfClients);
164 
165  client = lastClient;
166 
167  client++;
168  if (client >= endOfClients)
169  return nullptr;
170  else
171  return client;
172 }
173 
175 {
176  return &svs.clients[index];
177 }
178 
184 void SV_DropClient (client_t* drop, const char* message)
185 {
186  /* add the disconnect */
187  dbuffer msg(2 + strlen(message));
189  NET_WriteString(&msg, message);
190  NET_WriteMsg(drop->stream, msg);
191  SV_BroadcastPrintf(PRINT_CHAT, "%s was dropped from the server - reason: %s\n", drop->name, message);
192 
193  if (drop->state == cs_spawned || drop->state == cs_spawning) {
194  /* call the prog function for removing a client */
195  /* this will remove the body, among other things */
196  const ScopedMutex scopedMutex(svs.serverMutex);
197  svs.ge->ClientDisconnect(*drop->player);
198  }
199 
200  NET_StreamFinished(drop->stream);
201  drop->stream = nullptr;
202 
203  drop->player->setInUse(false);
204  SV_SetClientState(drop, cs_free);
205  drop->name[0] = 0;
206 
207  if (svs.abandon) {
208  int count = 0;
209  client_t* cl = nullptr;
210  while ((cl = SV_GetNextClient(cl)) != nullptr)
211  if (cl->state >= cs_connected)
212  count++;
213  if (count == 0)
214  svs.killserver = true;
215  }
216 }
217 
218 /*
219 ==============================================================================
220 CONNECTIONLESS COMMANDS
221 ==============================================================================
222 */
223 
227 static leakyBucket_t* SVC_BucketForAddress (struct net_stream& address, int burst, int period)
228 {
229  char node[64];
230  NET_StreamPeerToName(&address, node, sizeof(node), false);
231 
232  const long hash = Com_HashKey(node, MAX_HASHES);
233  const int now = Sys_Milliseconds();
234 
235  for (leakyBucket_t* bucket = bucketHashes[hash]; bucket; bucket = bucket->next) {
236  if (!Q_streq(bucket->node, node))
237  continue;
238 
239  return bucket;
240  }
241 
242  for (int i = 0; i < MAX_BUCKETS; i++) {
243  leakyBucket_t* bucket = &buckets[i];
244  const int interval = now - bucket->lastTime;
245 
246  /* Reclaim expired buckets */
247  if (bucket->lastTime > 0 && (interval > (burst * period) || interval < 0)) {
248  if (bucket->prev != nullptr) {
249  bucket->prev->next = bucket->next;
250  } else {
251  bucketHashes[bucket->hash] = bucket->next;
252  }
253 
254  if (bucket->next != nullptr) {
255  bucket->next->prev = bucket->prev;
256  }
257 
258  OBJZERO(*bucket);
259  }
260 
261  if (Q_strnull(bucket->node)) {
262  Q_strncpyz(bucket->node, node, sizeof(bucket->node));
263  bucket->lastTime = now;
264  bucket->burst = 0;
265  bucket->hash = hash;
266 
267  /* Add to the head of the relevant hash chain */
268  bucket->next = bucketHashes[hash];
269  if (bucketHashes[hash] != nullptr) {
270  bucketHashes[hash]->prev = bucket;
271  }
272 
273  bucket->prev = nullptr;
274  bucketHashes[hash] = bucket;
275 
276  return bucket;
277  }
278  }
279 
280  /* Couldn't allocate a bucket for this address */
281  return nullptr;
282 }
283 
284 static bool SVC_RateLimit (leakyBucket_t* bucket, int burst = 10, int period = 100)
285 {
286  if (bucket == nullptr)
287  return true;
288 
289  const int now = Sys_Milliseconds();
290  const int interval = now - bucket->lastTime;
291  const int expired = interval / period;
292  const int expiredRemainder = interval % period;
293 
294  if (expired > bucket->burst) {
295  bucket->burst = 0;
296  bucket->lastTime = now;
297  } else {
298  bucket->burst -= expired;
299  bucket->lastTime = now - expiredRemainder;
300  }
301 
302  if (bucket->burst < burst) {
303  bucket->burst++;
304  return false;
305  }
306 
307  return true;
308 }
309 
313 static bool SVC_RateLimitAddress (struct net_stream& from, int burst = 10, int period = 1000)
314 {
315  leakyBucket_t* bucket = SVC_BucketForAddress(from, burst, period);
316  return SVC_RateLimit(bucket, burst, period);
317 }
318 
323 static void SVC_TeamInfo (struct net_stream* s)
324 {
325  if (SVC_RateLimitAddress(*s)) {
326  Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s));
327  return;
328  }
329 
330  /* Allow getinfo to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */
331  if (SVC_RateLimit(&outboundLeakyBucket)) {
332  Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit exceeded, dropping request\n");
333  return;
334  }
335 
336  char infoGlobal[MAX_INFO_STRING] = "";
337  Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay"));
338  Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams"));
339  Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam"));
340 
341  dbuffer msg;
342  NET_WriteByte(&msg, svc_oob);
343  NET_WriteRawString(&msg, "teaminfo\n");
344  NET_WriteString(&msg, infoGlobal);
345 
346  client_t* cl = nullptr;
347  while ((cl = SV_GetNextClient(cl)) != nullptr) {
348  if (cl->state < cs_connected)
349  continue;
350  char infoPlayer[MAX_INFO_STRING] = "";
351  /* show players that already have a team with their teamnum */
352  int teamId = svs.ge->ClientGetTeamNum(*cl->player);
353  if (!teamId)
354  teamId = TEAM_NO_ACTIVE;
355  Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId);
356  Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player));
357  Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name);
358  NET_WriteString(&msg, infoPlayer);
359  }
360 
361  NET_WriteByte(&msg, 0);
362 
363  NET_WriteMsg(s, msg);
364 }
365 
370 static void SVC_Status (struct net_stream* s)
371 {
372  if (SVC_RateLimitAddress(*s)) {
373  Com_DPrintf(DEBUG_SERVER, "SVC_Status: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s));
374  return;
375  }
376 
377  /* Allow getstatus to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */
378  if (SVC_RateLimit(&outboundLeakyBucket, 10, 100)) {
379  Com_DPrintf(DEBUG_SERVER, "SVC_Status: rate limit exceeded, dropping request\n");
380  return;
381  }
382 
383  dbuffer msg;
384  NET_WriteByte(&msg, svc_oob);
385  NET_WriteRawString(&msg, SV_CMD_PRINT "\n");
386  char info[MAX_INFO_STRING];
387  NET_WriteRawString(&msg, Cvar_Serverinfo(info, sizeof(info)));
388  NET_WriteRawString(&msg, "\n");
389 
390  client_t* cl = nullptr;
391  while ((cl = SV_GetNextClient(cl)) != nullptr) {
392  if (cl->state <= cs_free)
393  continue;
394 
395  char player[1024];
396  Com_sprintf(player, sizeof(player), "%i \"%s\"\n", svs.ge->ClientGetTeamNum(*cl->player), cl->name);
397  NET_WriteRawString(&msg, player);
398  }
399 
400  NET_WriteMsg(s, msg);
401 }
402 
411 static void SVC_Info (struct net_stream* s)
412 {
413  if (SVC_RateLimitAddress(*s)) {
414  Com_DPrintf(DEBUG_SERVER, "SVC_Info: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s));
415  return;
416  }
417 
418  /* Allow getinfo to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */
419  if (SVC_RateLimit(&outboundLeakyBucket)) {
420  Com_DPrintf(DEBUG_SERVER, "SVC_Info: rate limit exceeded, dropping request\n");
421  return;
422  }
423 
424  if (sv_maxclients->integer == 1) {
425  Com_DPrintf(DEBUG_SERVER, "Ignore info string in singleplayer mode\n");
426  return; /* ignore in single player */
427  }
428 
429  const int version = atoi(Cmd_Argv(1));
430  if (version != PROTOCOL_VERSION) {
431  char string[MAX_VAR];
432  Com_sprintf(string, sizeof(string), "%s: wrong version (client: %i, host: %i)\n", sv_hostname->string, version, PROTOCOL_VERSION);
433  NET_OOB_Printf(s, SV_CMD_PRINT "\n%s", string);
434  return;
435  }
436 
437  int count = 0;
438 
439  client_t* cl = nullptr;
440  while ((cl = SV_GetNextClient(cl)) != nullptr)
441  if (cl->state >= cs_spawning)
442  count++;
443 
444  char infostring[MAX_INFO_STRING];
445  infostring[0] = '\0';
446  Info_SetValueForKey(infostring, sizeof(infostring), "sv_protocol", DOUBLEQUOTE(PROTOCOL_VERSION));
447  Info_SetValueForKey(infostring, sizeof(infostring), "sv_hostname", sv_hostname->string);
448  Info_SetValueForKey(infostring, sizeof(infostring), "sv_dedicated", sv_dedicated->string);
449  Info_SetValueForKey(infostring, sizeof(infostring), "sv_gametype", sv_gametype->string);
450  Info_SetValueForKey(infostring, sizeof(infostring), "sv_mapname", sv->name);
451  Info_SetValueForKeyAsInteger(infostring, sizeof(infostring), "clients", count);
452  Info_SetValueForKey(infostring, sizeof(infostring), "sv_maxclients", sv_maxclients->string);
453  Info_SetValueForKey(infostring, sizeof(infostring), "sv_version", UFO_VERSION);
454  NET_OOB_Printf(s, SV_CMD_INFO "\n%s", infostring);
455 }
456 
457 
462 static void SVC_DirectConnect (struct net_stream* stream)
463 {
464  Com_DPrintf(DEBUG_SERVER, "SVC_DirectConnect()\n");
465 
466  if (sv->started || sv->spawned) {
467  Com_Printf("rejected connect because match is already running\n");
469  return;
470  }
471 
472  char buf[256];
473  const char* peername = NET_StreamPeerToName(stream, buf, sizeof(buf), false);
474 
475  const int version = atoi(Cmd_Argv(1));
476  if (version != PROTOCOL_VERSION) {
477  Com_Printf("rejected connect from version %i - %s\n", version, peername);
479  return;
480  }
481 
482  char userinfo[MAX_INFO_STRING];
483  Q_strncpyz(userinfo, Cmd_Argv(2), sizeof(userinfo));
484 
485  if (Q_strnull(userinfo)) { /* catch empty userinfo */
486  Com_Printf("Empty userinfo from %s\n", peername);
488  return;
489  }
490 
491  if (strchr(userinfo, '\xFF')) { /* catch end of message in string exploit */
492  Com_Printf("Illegal userinfo contained xFF from %s\n", peername);
494  return;
495  }
496 
497  if (strlen(Info_ValueForKey(userinfo, "ip"))) { /* catch spoofed ips */
498  Com_Printf("Illegal userinfo contained ip from %s\n", peername);
500  return;
501  }
502 
503  /* force the IP key/value pair so the game can filter based on ip */
504  Info_SetValueForKey(userinfo, sizeof(userinfo), "ip", peername);
505 
506  /* find a client slot */
507  client_t* cl = nullptr;
508  while ((cl = SV_GetNextClient(cl)) != nullptr)
509  if (cl->state == cs_free)
510  break;
511  if (cl == nullptr) {
512  NET_OOB_Printf(stream, SV_CMD_PRINT "\n" REJ_SERVER_FULL "\n");
513  Com_Printf("Rejected a connection - server is full.\n");
514  return;
515  }
516 
517  /* build a new connection - accept the new client
518  * this is the only place a client_t is ever initialized */
519  OBJZERO(*cl);
520  const int playernum = cl - SV_GetClient(0);
521  SrvPlayer* player = PLAYER_NUM(playernum);
522  cl->player = player;
523  cl->player->setNum(playernum);
524 
525  bool connected;
526  {
527  const ScopedMutex scopedMutex(svs.serverMutex);
528  connected = svs.ge->ClientConnect(player, userinfo, sizeof(userinfo));
529  }
530 
531  /* get the game a chance to reject this connection or modify the userinfo */
532  if (!connected) {
533  const char* rejmsg = Info_ValueForKey(userinfo, "rejmsg");
534  if (rejmsg[0] != '\0') {
535  NET_OOB_Printf(stream, SV_CMD_PRINT "\n%s\n" REJ_CONNECTION_REFUSED "\n", rejmsg);
536  Com_Printf("Game rejected a connection from %s. Reason: %s\n", peername, rejmsg);
537  } else {
539  Com_Printf("Game rejected a connection from %s.\n", peername);
540  }
541  return;
542  }
543 
544  /* new player */
545  cl->player->setInUse(true);
546  cl->lastmessage = svs.realtime;
547 
548  /* parse some info from the info strings */
549  Q_strncpyz(cl->userinfo, userinfo, sizeof(cl->userinfo));
550  SV_UserinfoChanged(cl);
551 
552  /* send the connect packet to the client */
553  if (sv_http_downloadserver->string[0])
554  NET_OOB_Printf(stream, CL_CMD_CLIENT_CONNECT " dlserver=%s", sv_http_downloadserver->string);
555  else
557 
559 
560  Q_strncpyz(cl->peername, peername, sizeof(cl->peername));
561  cl->stream = stream;
562  NET_StreamSetData(stream, cl);
563 }
564 
569 static inline bool Rcon_Validate (const char* password)
570 {
571  /* no rcon access */
572  if (Q_strnull(rcon_password->string))
573  return false;
574 
575  /* password not valid */
576  if (!Q_streq(password, rcon_password->string))
577  return false;
578 
579  return true;
580 }
581 
585 static void SVC_RemoteCommand (struct net_stream* stream)
586 {
587  char buf[64];
588  const char* peername = NET_StreamPeerToName(stream, buf, sizeof(buf), false);
589 
590  /* Prevent using rcon as an amplifier and make dictionary attacks impractical */
591  if (SVC_RateLimitAddress(*stream)) {
592  Com_DPrintf(DEBUG_SERVER, "SVC_RemoteCommand: rate limit from %s exceeded, dropping request\n", peername);
593  return;
594  }
595 
596  const bool valid = Rcon_Validate(Cmd_Argv(1));
597  if (!valid) {
598  static leakyBucket_t bucket;
599  /* Make DoS via rcon impractical */
600  if (SVC_RateLimit(&bucket, 10, 1000)) {
601  Com_DPrintf(DEBUG_SERVER, "SVC_RemoteCommand: rate limit exceeded, dropping request\n");
602  return;
603  }
604 
605  Com_Printf("Bad rcon from %s with password: '%s'\n", peername, Cmd_Argv(1));
606  } else {
607  Com_Printf("Rcon from %s\n", peername);
608  }
609 
610  static char sv_outputbuf[1024];
611  Com_BeginRedirect(stream, sv_outputbuf, sizeof(sv_outputbuf));
612 
613  if (!valid) {
614  /* inform the client */
616  } else {
617  char remaining[1024] = "";
618  int i;
619 
620  /* execute the rcon commands */
621  for (i = 2; i < Cmd_Argc(); i++) {
622  Q_strcat(remaining, sizeof(remaining), "%s ", Cmd_Argv(i));
623  }
624 
625  /* execute the string */
626  Cmd_ExecuteString("%s", remaining);
627  }
628 
629  Com_EndRedirect();
630 }
631 
639 {
640  char s[512];
641 
642  NET_ReadStringLine(msg, s, sizeof(s));
643  Cmd_TokenizeString(s, false, false);
644 
645  const char* c = Cmd_Argv(0);
646  Com_DPrintf(DEBUG_SERVER, "Packet : %s\n", c);
647 
648  if (Q_streq(c, SV_CMD_TEAMINFO)) {
649  SVC_TeamInfo(stream);
650  } else if (Q_streq(c, SV_CMD_INFO)) {
651  SVC_Info(stream);
652  } else if (Q_streq(c, SV_CMD_STATUS)) {
653  SVC_Status(stream);
654  } else if (Q_streq(c, SV_CMD_CONNECT)) {
655  SVC_DirectConnect(stream);
656  } else if (Q_streq(c, SV_CMD_RCON)) {
657  SVC_RemoteCommand(stream);
658  } else {
659  char buf[256];
660  Com_Printf("Bad connectionless packet from %s:\n%s\n", NET_StreamPeerToName(stream, buf, sizeof(buf), true), s);
661  }
662 }
663 
669 void SV_ReadPacket (struct net_stream* s)
670 {
671  client_t* cl = static_cast<client_t* >(NET_StreamGetData(s));
672  dbuffer* msg;
673 
674  while ((msg = NET_ReadMsg(s))) {
675  const int cmd = NET_ReadByte(msg);
676 
677  if (cmd == clc_oob)
678  SV_ConnectionlessPacket(s, msg);
679  else if (cl)
680  SV_ExecuteClientMessage(cl, cmd, msg);
681  else {
682  NET_StreamFree(s);
683  s = nullptr;
684  }
685 
686  delete msg;
687  }
688 }
689 
690 #define HEARTBEAT_SECONDS 30
691 
692 static SDL_Thread* masterServerHeartBeatThread;
693 
698 static int Master_HeartbeatThread (void* data)
699 {
700  char url[512];
701  Com_sprintf(url, sizeof(url), "%s/ufo/masterserver.php?heartbeat&port=%s", masterserver_url->string, port->string);
702 
703  /* send to master */
704  Com_Printf("sending heartbeat\n");
705  HTTP_GetURL(url, nullptr);
706 
707  masterServerHeartBeatThread = nullptr;
708  return 0;
709 }
710 
714 static void Master_Heartbeat (void)
715 {
717  return; /* only dedicated servers send heartbeats */
718 
719  if (!sv_public || !sv_public->integer)
720  return; /* a private dedicated game */
721 
722  /* check for time wraparound */
725 
727  return; /* not time to send yet */
728 
730 
731  if (masterServerHeartBeatThread != nullptr)
732  SDL_WaitThread(masterServerHeartBeatThread, nullptr);
733 
735 }
736 
742 static void SV_CheckSpawnSoldiers (void)
743 {
744  /* already started? */
745  if (sv->spawned)
746  return;
747 
748  client_t* cl = nullptr;
749  while ((cl = SV_GetNextClient(cl)) != nullptr) {
750  /* all players must be connected and all of them must have set
751  * the ready flag */
752  if (cl->state != cs_began || !cl->player->isReady())
753  return;
754  }
755 
756  sv->spawned = true;
757 
758  cl = nullptr;
759  while ((cl = SV_GetNextClient(cl)) != nullptr)
760  if (cl->state != cs_free)
762 }
763 
764 static void SV_CheckStartMatch (void)
765 {
766  client_t* cl;
767 
768  if (!sv->spawned || sv->started)
769  return;
770 
771  if (sv_maxclients->integer > 1) {
772  cl = nullptr;
773  while ((cl = SV_GetNextClient(cl)) != nullptr) {
774  /* all players must have their actors spawned */
775  if (cl->state != cs_spawned)
776  return;
777  }
778  } else if (SV_GetClient(0)->state != cs_spawned) {
779  /* in single player mode we must have received the 'spawnsoldiers' */
780  return;
781  }
782 
783  sv->started = true;
784 
785  cl = nullptr;
786  while ((cl = SV_GetNextClient(cl)) != nullptr)
787  if (cl->state != cs_free)
789 }
790 
791 #define PING_SECONDS 5
792 
793 static void SV_PingPlayers (void)
794 {
795  /* check for time wraparound */
796  if (svs.lastPing > svs.realtime)
798 
799  if (svs.realtime - svs.lastPing < PING_SECONDS * 1000)
800  return; /* not time to send yet */
801 
803  client_t* cl = nullptr;
804  while ((cl = SV_GetNextClient(cl)) != nullptr) {
805  if (cl->state == cs_free)
806  continue;
807  dbuffer msg(1);
808  NET_WriteByte(&msg, svc_ping);
809  NET_WriteMsg(cl->stream, msg);
810  }
811 }
812 
813 static void SV_CheckTimeouts (void)
814 {
815  const int droppoint = svs.realtime - 1000 * sv_timeout->integer;
816 
817  if (sv_maxclients->integer == 1)
818  return;
819 
820  client_t* cl = nullptr;
821  while ((cl = SV_GetNextClient(cl)) != nullptr) {
822  if (cl->state == cs_free)
823  continue;
824 
825  /* might be invalid across a mapchange */
826  if (cl->lastmessage > svs.realtime)
827  cl->lastmessage = svs.realtime;
828 
829  if (cl->lastmessage > 0 && cl->lastmessage < droppoint)
830  SV_DropClient(cl, "timed out");
831  }
832 }
833 
837 void SV_Frame (int now, void* data)
838 {
840 
841  /* change the gametype even if no server is running (e.g. the first time) */
843  Com_SetGameType();
844  sv_gametype->modified = false;
845  }
846 
847  if (sv_dedicated->integer) {
848  const char* s;
849  do {
850  s = Sys_ConsoleInput();
851  if (s)
852  Cbuf_AddText("%s\n", s);
853  } while (s);
854  }
855 
856  /* if server is not active, do nothing */
857  if (!svs.initialized) {
858 #ifdef DEDICATED_ONLY
859  Com_Printf("Starting next map from the mapcycle\n");
860  SV_NextMapcycle();
861 #endif
862  return;
863  }
864 
865  svs.realtime = now;
866 
867  /* if time is about to hit the 32nd bit, kick all clients
868  * and clear sv.time, rather
869  * than checking for negative time wraparound everywhere.
870  * 2giga-milliseconds = 23 days, so it won't be too often */
871  if (svs.realtime > 0x70000000) {
872  SV_Map(true, sv->name, sv->assembly);
873  return;
874  }
875 
876  /* keep the random time dependent */
877  rand();
878 
882 
883  if (!sv_threads->integer)
884  SV_RunGameFrame();
885  else
886  /* signal the game frame thread to wake up */
887  SDL_CondSignal(svs.gameFrameCond);
889 
890  /* next map in the cycle */
891  if (sv->endgame && sv_maxclients->integer > 1)
892  SV_NextMapcycle();
893 
894  /* send a heartbeat to the master if needed */
896  SV_PingPlayers();
897 
898  /* server is empty - so shutdown */
899  if (svs.abandon && svs.killserver)
900  SV_Shutdown("Server disconnected.", false);
901 }
902 
906 static void Master_Shutdown (void)
907 {
909  return; /* only dedicated servers send heartbeats */
910 
911  if (!sv_public || !sv_public->integer)
912  return; /* a private dedicated game */
913 
914  /* send to master */
915  HTTP_GetURL(va("%s/ufo/masterserver.php?shutdown&port=%s", masterserver_url->string, port->string), nullptr);
916 }
917 
922 {
923  /* call prog code to allow overrides */
924  {
925  const ScopedMutex scopedMutex(svs.serverMutex);
926  svs.ge->ClientUserinfoChanged(*cl->player, cl->userinfo);
927  }
928 
929  /* name of the player */
930  Q_strncpyz(cl->name, Info_ValueForKey(cl->userinfo, "cl_name"), sizeof(cl->name));
931  /* mask off high bit */
932  for (int i = 0; i < sizeof(cl->name); i++)
933  cl->name[i] &= 127;
934 
935  /* msg command */
936  cl->messagelevel = Info_IntegerForKey(cl->userinfo, "cl_msg");
937 
938  Com_DPrintf(DEBUG_SERVER, "SV_UserinfoChanged: Changed userinfo for player %s\n", cl->name);
939 }
940 
942 {
943  const int max = MAX_ACTIVETEAM;
944  return Cvar_AssertValue(cvar, 1, max, true);
945 }
946 
948 {
949  return &sv->mapData;
950 }
951 
953 {
954  return &sv->mapTiles;
955 }
956 
960 void SV_Init (void)
961 {
962  Com_Printf("\n------ server initialization -------\n");
963 
964  sv_genericPool = Mem_CreatePool("Server: Generic");
965 
966  OBJZERO(svs);
967 
968  sv = Mem_PoolAllocType(serverInstanceGame_t, sv_genericPool);
969 
971 
972  rcon_password = Cvar_Get("rcon_password", "", CVAR_ARCHIVE);
973  Cvar_Get("sv_cheats", "0", CVAR_SERVERINFO | CVAR_LATCH);
975  /* this cvar will become a latched cvar when you start the server */
976  sv_maxclients = Cvar_Get("sv_maxclients", "1", CVAR_SERVERINFO, "Max. connected clients");
977  sv_hostname = Cvar_Get("sv_hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE, "The name of the server that is displayed in the serverlist");
978  sv_http_downloadserver = Cvar_Get("sv_http_downloadserver", "", CVAR_ARCHIVE, "URL to a location where clients can download game content over HTTP");
979  sv_enablemorale = Cvar_Get("sv_enablemorale", "1", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH, "Enable morale changes in multiplayer");
980  sv_maxsoldiersperteam = Cvar_Get("sv_maxsoldiersperteam", "4", CVAR_ARCHIVE | CVAR_SERVERINFO, "Max. amount of soldiers per team (see sv_maxsoldiersperplayer and sv_teamplay)");
981  sv_maxsoldiersperplayer = Cvar_Get("sv_maxsoldiersperplayer", DOUBLEQUOTE(MAX_ACTIVETEAM), CVAR_ARCHIVE | CVAR_SERVERINFO, "Max. amount of soldiers each player can control (see maxsoldiers and sv_teamplay)");
982  Cvar_SetCheckFunction("sv_maxsoldiersperplayer", SV_CheckMaxSoldiersPerPlayer);
983 
984  sv_dumpmapassembly = Cvar_Get("sv_dumpmapassembly", "0", CVAR_ARCHIVE, "Dump map assembly information to game console");
985 
986  sv_threads = Cvar_Get("sv_threads", "1", CVAR_LATCH | CVAR_ARCHIVE, "Run the server threaded");
987  sv_rma = Cvar_Get("sv_rma", "2", 0, "1 = old algorithm, 2 = new algorithm");
988  sv_rmadisplaythemap = Cvar_Get("sv_rmadisplaythemap", "0", 0, "Activate rma problem output");
989  sv_public = Cvar_Get("sv_public", "1", 0, "Should heartbeats be send to the masterserver");
990  sv_reconnect_limit = Cvar_Get("sv_reconnect_limit", "3", CVAR_ARCHIVE, "Minimum seconds between connect messages");
991  sv_timeout = Cvar_Get("sv_timeout", "200", CVAR_ARCHIVE, "Seconds until a client times out");
992 
993  SV_MapcycleInit();
994  SV_LogInit();
995 }
996 
1002 static void SV_FinalMessage (const char* message, bool reconnect)
1003 {
1004  client_t* cl;
1005  dbuffer msg(2 + strlen(message));
1006 
1007  if (reconnect)
1009  else
1011  NET_WriteString(&msg, message);
1012 
1013  cl = nullptr;
1014  while ((cl = SV_GetNextClient(cl)) != nullptr)
1015  if (cl->state >= cs_connected) {
1016  NET_WriteConstMsg(cl->stream, msg);
1018  cl->stream = nullptr;
1019  }
1020 
1021  /* make sure, that this is send */
1022  NET_Wait(0);
1023 }
1024 
1030 void SV_Clear (void)
1031 {
1032  SV_MapcycleClear();
1033  SV_LogShutdown();
1034 }
1035 
1042 void SV_Shutdown (const char* finalmsg, bool reconnect)
1043 {
1044  if (!svs.initialized)
1045  return;
1046 
1047  if (svs.clients)
1048  SV_FinalMessage(finalmsg, reconnect);
1049 
1050  Com_Printf("Shutdown server: %s\n", finalmsg);
1051 
1052  Master_Shutdown();
1054 
1056  SV_Stop();
1057 
1058  for (int i = 0; i < sv->numSVModels; i++) {
1059  sv_model_t* model = &sv->svModels[i];
1060  Mem_Free(model->name);
1061  }
1062 
1063  /* free current level */
1064  OBJZERO(*sv);
1065 
1066  /* free server static data */
1067  Mem_Free(svs.clients);
1068 
1069  SDL_DestroyMutex(svs.serverMutex);
1070 
1071  OBJZERO(svs);
1072 
1073  /* maybe we shut down before we init - e.g. in case of an error */
1074  if (sv_maxclients)
1075  sv_maxclients->flags &= ~CVAR_LATCH;
1076 
1077  if (sv_mapname)
1078  sv_mapname->flags &= ~CVAR_NOSET;
1079 }
1080 
1086 {
1087  svs.abandon = true;
1088  /* pretend server is already dead, otherwise clients may try and reconnect */
1090 }
1091 
1097 {
1098  int count = 0;
1099  client_t* cl;
1100 
1101  if (!svs.initialized)
1102  return 0;
1103 
1104  cl = nullptr;
1105  while ((cl = SV_GetNextClient(cl)) != nullptr) {
1106  if (cl->state != cs_spawned)
1107  continue;
1108 
1109  count++;
1110  }
1111 
1112  return count;
1113 }
sv_model_t svModels[MAX_MOD_KNOWN]
Definition: server.h:128
bool Q_strnull(const char *string)
Definition: shared.h:138
void SV_ShutdownWhenEmpty(void)
Will eventually shutdown the server once all clients have disconnected.
Definition: sv_main.cpp:1085
static void SVC_Status(struct net_stream *s)
Responds with all the info that the server browser can see.
Definition: sv_main.cpp:370
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition: cmd.cpp:516
static bool SVC_RateLimit(leakyBucket_t *bucket, int burst=10, int period=100)
Definition: sv_main.cpp:284
void NET_StreamFinished(struct net_stream *s)
Call NET_StreamFinished to mark the stream as uninteresting, but to finish sending any data in the bu...
Definition: net.cpp:832
void Info_SetValueForKeyAsInteger(char *s, const size_t size, const char *key, const int value)
Definition: infostring.cpp:154
void SV_DropClient(client_t *drop, const char *message)
Called when the player is totally leaving the server, either willingly or unwillingly. This is NOT called if the entire server is quitting or crashing.
Definition: sv_main.cpp:184
void void void SV_BroadcastPrintf(int level, const char *fmt,...) __attribute__((format(__printf__
cvar_t * sv_public
Definition: sv_main.cpp:52
#define HEARTBEAT_SECONDS
Definition: sv_main.cpp:690
char peername[256]
Definition: server.h:162
memPool_t * sv_genericPool
Definition: sv_main.cpp:55
void setInUse(bool inuse)
Definition: game.h:55
static void Master_Shutdown(void)
Informs all masters that this server is going down.
Definition: sv_main.cpp:906
void SV_Init(void)
Only called once at startup, not for each game.
Definition: sv_main.cpp:960
#define DEBUG_SERVER
Definition: defines.h:60
SDL_mutex * serverMutex
Definition: server.h:86
static SDL_Thread * masterServerHeartBeatThread
Definition: sv_main.cpp:692
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
#define CL_CMD_CLIENT_CONNECT
Definition: q_shared.h:606
#define SV_CMD_CONNECT
Definition: q_shared.h:588
#define PRINT_CHAT
Definition: defines.h:106
#define SV_CMD_TEAMINFO
Definition: q_shared.h:591
static cvar_t * sv_http_downloadserver
Definition: sv_main.cpp:37
bool Cvar_AssertValue(cvar_t *cvar, float minVal, float maxVal, bool shouldBeIntegral)
Checks cvar values.
Definition: cvar.cpp:161
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
#define CL_STARTMATCH
Definition: q_shared.h:603
#define BAD_RCON_PASSWORD
Definition: q_shared.h:581
#define PLAYER_NUM(n)
Definition: server.h:137
void SV_LogInit(void)
Definition: sv_log.cpp:71
void NET_WriteRawString(dbuffer *buf, const char *str)
Skip the zero string terminal character. If you need it, use NET_WriteString.
Definition: netpack.cpp:71
static cvar_t * sv_hostname
Definition: sv_main.cpp:41
void NET_Wait(int timeout)
Definition: net.cpp:423
void SV_Stop(void)
Definition: net.cpp:1026
const char * Cvar_Serverinfo(char *info, size_t infoSize)
Returns an info string containing all the CVAR_SERVERINFO cvars.
Definition: cvar.cpp:977
Definition: game.h:45
struct leakyBucket_s * next
Definition: sv_main.cpp:66
int messagelevel
Definition: server.h:160
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
#define REJ_CONNECTION_REFUSED
Definition: q_shared.h:586
signed char burst
Definition: sv_main.cpp:61
#define MAX_TILESTRINGS
Definition: q_shared.h:298
char userinfo[MAX_INFO_STRING]
Definition: server.h:157
#define CL_SPAWNSOLDIERS
Definition: q_shared.h:602
static void SVC_TeamInfo(struct net_stream *s)
Responds with teaminfo such as free team num.
Definition: sv_main.cpp:323
static leakyBucket_t buckets[MAX_BUCKETS]
Definition: sv_main.cpp:73
#define CS_MAPCHECKSUM
Definition: q_shared.h:312
void Cbuf_AddText(const char *format,...)
Adds command text at the end of the buffer.
Definition: cmd.cpp:126
static cvar_t * sv_timeout
Definition: sv_main.cpp:44
void NET_WriteString(dbuffer *buf, const char *str)
Definition: netpack.cpp:59
static void SV_PingPlayers(void)
Definition: sv_main.cpp:793
static void SV_CheckStartMatch(void)
Definition: sv_main.cpp:764
void SV_ReadPacket(struct net_stream *s)
Definition: sv_main.cpp:669
void SV_Map(bool day, const char *levelstring, const char *assembly, bool verbose=true)
Change the server to a new map, taking all connected clients along with it.
Definition: sv_init.cpp:113
cvar_t * sv_rma
Definition: sv_main.cpp:49
client_t * SV_GetClient(int index)
Definition: sv_main.cpp:174
#define MAX_ENTITYSTRINGS
Definition: q_shared.h:301
void Cmd_TokenizeString(const char *text, bool macroExpand, bool replaceWhitespaces)
Parses the given string into command line tokens.
Definition: cmd.cpp:565
player_t * player
Definition: server.h:158
void NET_StreamFree(struct net_stream *s)
Call NET_StreamFree to dump the whole thing right now.
Definition: net.cpp:817
cvar_t * sv_gametype
Definition: common.cpp:56
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
SDL_Thread * Com_CreateThread(int(*fn)(void *), const char *name, void *data=nullptr)
Definition: thread.h:5
const char * NET_StreamToString(struct net_stream *s)
Returns the numerical representation of a net_stream.
Definition: net.cpp:859
void SV_SetClientState(client_t *client, client_state_t state)
Set the client state.
Definition: sv_user.cpp:36
char * SV_GetConfigString(int index)
Definition: sv_main.cpp:77
void SV_Frame(int now, void *data)
Definition: sv_main.cpp:837
#define SV_CMD_PRINT
Definition: q_shared.h:593
void Com_SetServerState(int state)
Definition: common.cpp:547
static leakyBucket_t * SVC_BucketForAddress(struct net_stream &address, int burst, int period)
Find or allocate a bucket for an address.
Definition: sv_main.cpp:227
void SV_MapcycleClear(void)
Empty the mapcycle list.
void SV_LogShutdown(void)
Definition: sv_log.cpp:78
static cvar_t * sv_reconnect_limit
Definition: sv_main.cpp:43
#define CS_POSITIONS
Definition: q_shared.h:326
int integer
Definition: cvar.h:81
cvar_t * masterserver_url
Definition: common.cpp:57
static bool Rcon_Validate(const char *password)
Checks whether the remote connection is allowed (rcon_password must be set on the server) - and verif...
Definition: sv_main.cpp:569
voidpf void * buf
Definition: ioapi.h:42
#define ERR_FATAL
Definition: common.h:210
#define CVAR_ARCHIVE
Definition: cvar.h:40
void SV_InitOperatorCommands(void)
Definition: sv_ccmds.cpp:542
int lastmessage
Definition: server.h:161
int flags
Definition: cvar.h:78
static bool SVC_RateLimitAddress(struct net_stream &from, int burst=10, int period=1000)
Rate limit for a particular address.
Definition: sv_main.cpp:313
void * NET_StreamGetData(struct net_stream *s)
Definition: net.cpp:800
#define MAX_CLIENTS
Definition: q_shared.h:299
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
void Cmd_ExecuteString(const char *text,...)
A complete command line has been parsed, so try to execute it.
Definition: cmd.cpp:1007
Struct that is only valid for one map. It's deleted on every map load.
Definition: server.h:106
static leakyBucket_t outboundLeakyBucket
Definition: sv_main.cpp:75
#define REJ_GAME_ALREADY_STARTED
Definition: q_shared.h:585
#define CS_PLAYERNAMES
Definition: q_shared.h:328
const char * Info_ValueForKey(const char *s, const char *key)
Searches the string for the given key and returns the associated value, or an empty string...
Definition: infostring.cpp:39
serverInstanceGame_t * sv
Definition: sv_init.cpp:36
cvar_t * sv_rmadisplaythemap
display a character graphic of the tiles placed when RMA2 reaches a dead end.
Definition: sv_main.cpp:50
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
static cvar_t * sv_maxsoldiersperteam
Definition: sv_main.cpp:39
void NET_OOB_Printf(struct net_stream *s, const char *format,...)
Out of band print.
Definition: netpack.cpp:548
#define CS_MODELS
Definition: q_shared.h:327
void SV_LogHandleOutput(void)
Handle the log output from the main thread by reading the strings from the dbuffer the game lib threa...
Definition: sv_log.cpp:44
client_t * SV_GetNextClient(client_t *lastClient)
Iterates through clients.
Definition: sv_main.cpp:152
#define UFO_VERSION
Definition: common.h:36
unsigned int numSVModels
Definition: server.h:129
#define MAX_INFO_STRING
Definition: infostring.h:36
void SV_Shutdown(const char *finalmsg, bool reconnect)
Called when each game quits, before Sys_Quit or Sys_Error.
Definition: sv_main.cpp:1042
const char * Sys_ConsoleInput(void)
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition: cvar.cpp:342
game lib logging handling
char node[64]
Definition: sv_main.cpp:58
#define OBJZERO(obj)
Definition: shared.h:178
Definition: server.h:96
#define MAX_VAR
Definition: shared.h:36
static void SV_CheckSpawnSoldiers(void)
If all connected clients have set their ready flag the server will spawn the clients and that change ...
Definition: sv_main.cpp:742
#define MAX_GENERAL
Definition: q_shared.h:300
#define CS_OBJECTAMOUNT
Definition: q_shared.h:320
static wrapCache_t * hash[MAX_WRAP_HASH]
Definition: r_font.cpp:86
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition: cmd.cpp:505
bool isReady() const
Definition: game.h:64
void SV_MapcycleInit(void)
static void SVC_Info(struct net_stream *s)
Responds with short info for broadcast scans.
Definition: sv_main.cpp:411
char * name
Definition: server.h:50
void Com_EndRedirect(void)
End the redirection of packets/output.
Definition: common.cpp:325
Main server include file.
#define CVAR_NOSET
Definition: cvar.h:43
struct leakyBucket_s * prev
Definition: sv_main.cpp:65
clientBattleScape_t cl
#define Mem_CreatePool(name)
Definition: mem.h:32
struct leakyBucket_s leakyBucket_t
int SV_GetConfigStringInteger(int index)
Definition: sv_main.cpp:108
char assembly[MAX_QPATH]
Definition: server.h:110
mapData_t mapData
Definition: server.h:124
void SV_RunGameFrame(void)
Calls the G_RunFrame function from game api let everything in the world think and move...
Definition: sv_game.cpp:758
#define MAX_TOKEN_CHARS
Definition: defines.h:372
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
static void SVC_RemoteCommand(struct net_stream *stream)
A client issued an rcon command. Shift down the remaining args. Redirect all printfs.
Definition: sv_main.cpp:585
static void SV_ConnectionlessPacket(struct net_stream *stream, dbuffer *msg)
Handles a connectionless message from a client.
Definition: sv_main.cpp:638
static cvar_t * sv_maxsoldiersperplayer
Definition: sv_main.cpp:40
char name[32]
Definition: server.h:159
QGL_EXTERN GLuint index
Definition: r_gl.h:110
#define MAX_HASHES
Definition: sv_main.cpp:71
int SV_GetConfigStringLength(int index)
Definition: sv_main.cpp:85
bool Com_CheckConfigStringIndex(int index)
Definition: common.cpp:860
QGL_EXTERN GLuint count
Definition: r_gl.h:99
#define CS_UFOCHECKSUM
Definition: q_shared.h:319
#define MAX_MODELS
Definition: defines.h:100
char name[MAX_QPATH]
Definition: server.h:109
static void SV_FinalMessage(const char *message, bool reconnect)
Used by SV_Shutdown to send a final message to all connected clients before the server goes down...
Definition: sv_main.cpp:1002
void Info_SetValueForKey(char *s, const size_t size, const char *key, const char *value)
Adds a new entry into string with given value.
Definition: infostring.cpp:169
void Com_BeginRedirect(struct net_stream *stream, char *buffer, int buffersize)
Redirect packets/output from server to client.
Definition: common.cpp:308
void SV_UserinfoChanged(client_t *cl)
Pull specific info from a newly changed userinfo string into a more C friendly form.
Definition: sv_main.cpp:921
#define CVAR_LATCH
Definition: cvar.h:44
cvar_t * sv_threads
Definition: sv_main.cpp:48
mapTiles_t mapTiles
Definition: server.h:126
cvar_t * password
Definition: g_main.cpp:67
void NET_StreamSetData(struct net_stream *s, void *data)
Definition: net.cpp:805
#define SV_CMD_STATUS
Definition: q_shared.h:590
static void Master_Heartbeat(void)
Definition: sv_main.cpp:714
voidpf stream
Definition: ioapi.h:42
cvar_t * sv_maxclients
Definition: sv_main.cpp:46
void SV_ClientCommand(client_t *client, const char *fmt,...) __attribute__((format(__printf__
#define REJ_SERVER_VERSION_MISMATCH
Definition: q_shared.h:584
cvar_t * sv_dumpmapassembly
Definition: sv_main.cpp:47
QGL_EXTERN GLint i
Definition: r_gl.h:113
mapData_t * SV_GetMapData(void)
Definition: sv_main.cpp:947
char * string
Definition: cvar.h:73
cvar_t * sv_dedicated
Definition: common.cpp:51
struct net_stream * stream
Definition: server.h:163
void NET_DatagramSocketClose(struct datagram_socket *s)
Definition: net.cpp:1182
struct client_s * clients
Definition: server.h:80
void NET_WriteByte(dbuffer *buf, byte c)
Definition: netpack.cpp:39
#define PING_SECONDS
Definition: sv_main.cpp:791
#define CS_TILES
Definition: q_shared.h:325
#define CS_LIGHTMAP
Definition: q_shared.h:321
static cvar_t * sv_enablemorale
Definition: sv_main.cpp:38
#define REJ_SERVER_FULL
Definition: q_shared.h:583
#define Mem_Free(ptr)
Definition: mem.h:35
unsigned int Com_HashKey(const char *name, int hashsize)
returns hash key for a string
Definition: shared.cpp:336
cvar_t * port
Definition: common.cpp:58
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition: shared.cpp:475
static void SV_CheckTimeouts(void)
Definition: sv_main.cpp:813
#define MAX_ACTIVETEAM
Definition: defines.h:41
void Com_SetGameType(void)
Definition: common.cpp:815
void Com_ReadFromPipe(void)
Read whatever is in com_pipefile, if anything, and execute it.
Definition: common.cpp:1260
static cvar_t * rcon_password
Definition: sv_main.cpp:36
void SV_Clear(void)
Cleanup when the whole game process is shutting down.
Definition: sv_main.cpp:1030
client_state_t state
Definition: server.h:156
cvar_t * sv_mapname
Definition: sv_main.cpp:53
dbuffer * NET_ReadMsg(struct net_stream *s)
Reads messages from the network channel and adds them to the dbuffer where you can use the NET_Read* ...
Definition: net.cpp:774
void void void void SV_ExecuteClientMessage(client_t *cl, int cmd, dbuffer *msg)
The current net_message is parsed for the given client.
Definition: sv_user.cpp:235
bool HTTP_GetURL(const char *url, http_callback_t callback, void *userdata, const char *postfields)
Downloads the given url and return the data to the callback (optional)
Definition: http.cpp:374
GLsizei const GLvoid * data
Definition: r_gl.h:152
const char * NET_StreamPeerToName(struct net_stream *s, char *dst, int len, bool appendPort)
Definition: net.cpp:872
const char * Cvar_GetString(const char *varName)
Returns the value of cvar as string.
Definition: cvar.cpp:210
#define Q_streq(a, b)
Definition: shared.h:136
#define SV_CMD_RCON
Definition: q_shared.h:589
#define TEAM_NO_ACTIVE
Definition: q_shared.h:60
bool modified
Definition: cvar.h:79
#define Mem_PoolAllocType(type, pool)
Definition: mem.h:43
void setNum(int num)
Definition: game.h:61
#define PROTOCOL_VERSION
Definition: common.h:134
char configstrings[MAX_CONFIGSTRINGS][MAX_TOKEN_CHARS]
Definition: server.h:117
#define CS_ENTITYSTRING
Definition: q_shared.h:324
void SV_NextMapcycle(void)
Start the next map in the cycle.
Definition: sv_mapcycle.cpp:20
void SV_ShutdownGameProgs(void)
Called when either the entire server is being killed, or it is changing to a different game directory...
Definition: sv_game.cpp:703
static leakyBucket_t * bucketHashes[MAX_HASHES]
Definition: sv_main.cpp:74
#define SV_CMD_INFO
Definition: q_shared.h:592
static mesh models (none-animated) can have a server side flag set to be clipped for pathfinding ...
Definition: server.h:47
#define CS_GENERAL
Definition: q_shared.h:329
static void SVC_DirectConnect(struct net_stream *stream)
A connection request that did not come from the master.
Definition: sv_main.cpp:462
mapTiles_t * SV_GetMapTiles(void)
Definition: sv_main.cpp:952
serverInstanceStatic_t svs
Definition: sv_init.cpp:35
char * SV_SetConfigString(int index,...)
Definition: sv_main.cpp:113
#define DOUBLEQUOTE(x)
Definition: shared.h:90
int NET_ReadByte(dbuffer *buf)
Reads a byte from the netchannel.
Definition: netpack.cpp:234
static bool SV_CheckMaxSoldiersPerPlayer(cvar_t *cvar)
Definition: sv_main.cpp:941
bool Cvar_SetCheckFunction(const char *varName, bool(*check)(cvar_t *cvar))
Set a checker function for cvar values.
Definition: cvar.cpp:139
#define CVAR_SERVERINFO
Definition: cvar.h:42
int NET_ReadStringLine(dbuffer *buf, char *string, size_t length)
Definition: netpack.cpp:328
int Info_IntegerForKey(const char *s, const char *key)
Definition: infostring.cpp:84
static int Master_HeartbeatThread(void *data)
Send a message to the master every few minutes to let it know we are alive, and log information...
Definition: sv_main.cpp:698
SDL_cond * gameFrameCond
Definition: server.h:87
int SV_CountPlayers(void)
Returns the number of spawned players.
Definition: sv_main.cpp:1096
struct datagram_socket * netDatagramSocket
Definition: server.h:79
void NET_WriteConstMsg(struct net_stream *s, const dbuffer &buf)
Enqueue the buffer in the net stream for MULTIPLE clients.
Definition: netpack.cpp:588
int Sys_Milliseconds(void)
Definition: unix_shared.cpp:41
#define MAX_BUCKETS
Definition: sv_main.cpp:70
game_export_t * ge
Definition: server.h:92
void NET_WriteMsg(struct net_stream *s, dbuffer &buf)
Enqueue the buffer in the net stream for ONE client.
Definition: netpack.cpp:569