UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
sv_user.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_users.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 "../shared/scopedmutex.h"
31 
37 {
38  assert(client);
39  Com_DPrintf(DEBUG_SERVER, "Set state for client '%s' to %i\n", client->name, state);
40  client->state = state;
41 }
42 
43 /*
44 ============================================================
45 USER STRINGCMD EXECUTION
46 ============================================================
47 */
48 
56 static void SV_New_f (client_t* cl)
57 {
58  Com_DPrintf(DEBUG_SERVER, "New() from %s\n", cl->name);
59 
60  if (cl->state != cs_connected) {
61  if (cl->state == cs_spawning) {
62  /* client typed 'reconnect/new' while connecting. */
63  Com_Printf("SV_New_f: client typed 'reconnect/new' while connecting\n");
64  SV_ClientCommand(cl, "\ndisconnect\nreconnect\n");
65  SV_DropClient(cl, "");
66  } else
67  Com_DPrintf(DEBUG_SERVER, "WARNING: Illegal 'new' from %s, client state %d. This shouldn't happen...\n", cl->name, cl->state);
68  return;
69  }
70 
71  /* client state to prevent multiple new from causing high cpu / overflows. */
73 
74  /* serverdata needs to go over for all types of servers
75  * to make sure the protocol is right, and to set the gamedir */
76 
77  /* send the serverdata */
78  {
79  const int playernum = cl - SV_GetClient(0);
80  dbuffer msg;
83 
84  NET_WriteShort(&msg, playernum);
85 
86  /* send full levelname */
88 
89  NET_WriteMsg(cl->stream, msg);
90  }
91 
92  /* game server */
93  if (Com_ServerState() == ss_game) {
94  for (int i = 0; i < MAX_CONFIGSTRINGS; i++) {
95  /* CS_TILES and CS_POSITIONS can stretch over multiple configstrings,
96  * so don't send the middle parts again. */
97  if (i > CS_TILES && i < CS_POSITIONS)
98  continue;
99  if (i > CS_POSITIONS && i < CS_MODELS)
100  continue;
101 
102  const char* configString = SV_GetConfigString(i);
103  if (!Q_strvalid(configString))
104  continue;
105 
106  Com_DPrintf(DEBUG_SERVER, "sending configstring %d: %s\n", i, configString);
107 
108  dbuffer msg;
110  NET_WriteShort(&msg, i);
111  NET_WriteString(&msg, configString);
112  /* enqueue and free msg */
113  NET_WriteMsg(cl->stream, msg);
114  }
115  }
116 
117  SV_ClientCommand(cl, CL_PRECACHE "\n");
118 }
119 
123 static void SV_Begin_f (client_t* cl)
124 {
125  bool began;
126 
127  Com_DPrintf(DEBUG_SERVER, "Begin() from %s\n", cl->name);
128 
129  /* could be abused to respawn or cause spam/other mod-specific problems */
130  if (cl->state != cs_spawning) {
131  Com_Printf("EXPLOIT: Illegal 'begin' from %s (already spawned), client dropped.\n", cl->name);
132  SV_DropClient(cl, "Illegal begin\n");
133  return;
134  }
135 
136  /* call the game begin function */
137  {
138  ScopedMutex scopedMutex(svs.serverMutex);
139  began = svs.ge->ClientBegin(*cl->player);
140  }
141 
142  if (!began) {
143  SV_DropClient(cl, "'begin' failed\n");
144  return;
145  }
147 
149 }
150 
155 {
156  Com_DPrintf(DEBUG_SERVER, "StartMatch() from %s\n", cl->name);
157 
158  if (cl->state != cs_spawned) {
159  SV_DropClient(cl, "Invalid state\n");
160  return;
161  }
162 
163  {
164  ScopedMutex scopedMutex(svs.serverMutex);
165  svs.ge->ClientStartMatch(*cl->player);
166  }
167 
169 }
170 
171 /*============================================================================ */
172 
177 {
178  SV_DropClient(cl, "Disconnect\n");
179 }
180 
181 
186 {
187  char info[MAX_INFO_STRING];
188  Info_Print(Cvar_Serverinfo(info, sizeof(info)));
189 }
190 
191 
192 typedef struct {
193  const char* name;
194  void (*func) (client_t* client);
195 } ucmd_t;
196 
197 static const ucmd_t ucmds[] = {
198  /* auto issued */
202 
204 
205  /* issued by hand at client consoles */
207 
208  {nullptr, nullptr}
209 };
210 
214 static void SV_ExecuteUserCommand (client_t* cl, const char* s)
215 {
216  Cmd_TokenizeString(s, false, false);
217 
218  for (const ucmd_t* u = ucmds; u->name; u++)
219  if (Q_streq(Cmd_Argv(0), u->name)) {
220  Com_DPrintf(DEBUG_SERVER, "SV_ExecuteUserCommand: %s\n", s);
221  u->func(cl);
222  return;
223  }
224 
225  if (Com_ServerState() == ss_game) {
226  Com_DPrintf(DEBUG_SERVER, "SV_ExecuteUserCommand: client command: %s\n", s);
227  ScopedMutex scopedMutex(svs.serverMutex);
228  svs.ge->ClientCommand(*cl->player);
229  }
230 }
231 
236 {
237  if (cmd == -1)
238  return;
239 
240  switch (cmd) {
241  default:
242  Com_Printf("SV_ExecuteClientMessage: unknown command char '%d'\n", cmd);
243  SV_DropClient(cl, "Unknown command\n");
244  return;
245 
246  case clc_nop:
247  break;
248 
249  case clc_ack:
250  cl->lastmessage = svs.realtime;
251  break;
252 
253  case clc_userinfo:
254  NET_ReadString(msg, cl->userinfo, sizeof(cl->userinfo));
255  Com_DPrintf(DEBUG_SERVER, "userinfo from client: %s\n", cl->userinfo);
256  SV_UserinfoChanged(cl);
257  break;
258 
259  case clc_stringcmd: {
260  char str[MAX_CLC_STRINGCMD];
261  NET_ReadString(msg, str, sizeof(str));
262 
263  Com_DPrintf(DEBUG_SERVER, "stringcmd from client: %s\n", str);
264  SV_ExecuteUserCommand(cl, str);
265 
266  if (cl->state == cs_free)
267  return; /* disconnect command */
268  break;
269  }
270 
271  case clc_action: {
272  /* client actions are handled by the game module */
273  ScopedMutex scopedMutex(svs.serverMutex);
274  sv->messageBuffer = msg;
275  svs.ge->ClientAction(*cl->player);
276  sv->messageBuffer = nullptr;
277  break;
278  }
279 
280  case clc_endround: {
281  /* player wants to end round */
282  ScopedMutex scopedMutex(svs.serverMutex);
283  sv->messageBuffer = msg;
284  svs.ge->ClientEndRound(*cl->player);
285  sv->messageBuffer = nullptr;
286  break;
287  }
288 
289  case clc_teaminfo: {
290  /* player sends team info */
291  /* actors spawn accordingly */
292  ScopedMutex scopedMutex(svs.serverMutex);
293  sv->messageBuffer = msg;
294  svs.ge->ClientTeamInfo(*cl->player);
295  sv->messageBuffer = nullptr;
297  break;
298  }
299 
300  case clc_initactorstates: {
301  /* player sends team info */
302  /* actors spawn accordingly */
303  ScopedMutex scopedMutex(svs.serverMutex);
304  sv->messageBuffer = msg;
305  svs.ge->ClientInitActorStates(*cl->player);
306  sv->messageBuffer = nullptr;
307  break;
308  }
309  }
310 }
311 
313 {
314  return sv->state;
315 }
316 
318 {
319  sv->state = state;
320 }
static void SV_StartMatch_f(client_t *cl)
Definition: sv_user.cpp:154
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition: cmd.cpp:516
const char * name
Definition: sv_user.cpp:193
Definition: server.h:99
#define CL_PRECACHE
Definition: q_shared.h:601
char * SV_GetConfigString(int index)
Definition: sv_main.cpp:77
server_state_t SV_GetServerState(void)
Definition: sv_user.cpp:312
#define NET_STATE_DISCONNECT
Definition: q_shared.h:611
#define DEBUG_SERVER
Definition: defines.h:60
SDL_mutex * serverMutex
Definition: server.h:86
const char * Cvar_Serverinfo(char *info, size_t infoSize)
Returns an info string containing all the CVAR_SERVERINFO cvars.
Definition: cvar.cpp:977
char userinfo[MAX_INFO_STRING]
Definition: server.h:157
void SV_SetServerState(server_state_t state)
Definition: sv_user.cpp:317
enum server_state_e server_state_t
void NET_WriteString(dbuffer *buf, const char *str)
Definition: netpack.cpp:59
client_state_t
Definition: server.h:139
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 Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
static void SV_Disconnect_f(client_t *cl)
The client is going to disconnect, so remove the connection immediately.
Definition: sv_user.cpp:176
#define CS_POSITIONS
Definition: q_shared.h:326
int lastmessage
Definition: server.h:161
#define Q_strvalid(string)
Definition: shared.h:141
client_t * SV_GetClient(int index)
Definition: sv_main.cpp:174
serverInstanceGame_t * sv
Definition: sv_init.cpp:36
#define CS_MODELS
Definition: q_shared.h:327
#define MAX_INFO_STRING
Definition: infostring.h:36
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
int NET_ReadString(dbuffer *buf, char *string, size_t length)
Definition: netpack.cpp:302
static const ucmd_t ucmds[]
Definition: sv_user.cpp:197
static void SV_ShowServerinfo_f(client_t *cl)
Dumps the serverinfo info string.
Definition: sv_user.cpp:185
#define NET_STATE_BEGIN
Definition: q_shared.h:609
#define CS_NAME
Definition: q_shared.h:309
void NET_WriteLong(dbuffer *buf, int c)
Definition: netpack.cpp:52
Main server include file.
clientBattleScape_t cl
#define NET_STATE_NEW
Definition: q_shared.h:608
server_state_t state
Definition: server.h:107
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
static void SV_New_f(client_t *cl)
Sends the first message from the server to a connected client. This will be sent on the initial conne...
Definition: sv_user.cpp:56
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
#define MAX_CONFIGSTRINGS
Definition: q_shared.h:330
#define NET_STATE_STARTMATCH
Definition: q_shared.h:610
void SV_SetClientState(client_t *client, client_state_t state)
Set the client state.
Definition: sv_user.cpp:36
char name[32]
Definition: server.h:159
const GLuint *typedef void(APIENTRY *GenRenderbuffersEXT_t)(GLsizei
Definition: r_gl.h:189
static void SV_Begin_f(client_t *cl)
Definition: sv_user.cpp:123
static void SV_ExecuteUserCommand(client_t *cl, const char *s)
Definition: sv_user.cpp:214
void SV_ClientCommand(client_t *client, const char *fmt,...) __attribute__((format(__printf__
QGL_EXTERN GLint i
Definition: r_gl.h:113
struct net_stream * stream
Definition: server.h:163
void NET_WriteByte(dbuffer *buf, byte c)
Definition: netpack.cpp:39
#define CS_TILES
Definition: q_shared.h:325
client_state_t state
Definition: server.h:156
void Info_Print(const char *s)
Prints info strings (like userinfo or serverinfo - CVAR_USERINFO, CVAR_SERVERINFO) ...
Definition: infostring.cpp:209
dbuffer * messageBuffer
Definition: server.h:119
#define Q_streq(a, b)
Definition: shared.h:136
void Cbuf_InsertFromDefer(void)
Copies back any deferred commands.
Definition: cmd.cpp:201
#define PROTOCOL_VERSION
Definition: common.h:134
int Com_ServerState(void)
Check whether we are the server or have a singleplayer tactical mission.
Definition: common.cpp:538
serverInstanceStatic_t svs
Definition: sv_init.cpp:35
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
void NET_WriteShort(dbuffer *buf, int c)
Definition: netpack.cpp:45
#define MAX_CLC_STRINGCMD
Definition: common.h:163
#define NET_STATE_INFO
Definition: q_shared.h:612
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