sv_user.c

Go to the documentation of this file.
00001 
00006 /*
00007 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 Original file from Quake 2 v3.21: quake2-2.31/server/sv_users.c
00010 Copyright (C) 1997-2001 Id Software, Inc.
00011 
00012 This program is free software; you can redistribute it and/or
00013 modify it under the terms of the GNU General Public License
00014 as published by the Free Software Foundation; either version 2
00015 of the License, or (at your option) any later version.
00016 
00017 This program is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020 
00021 See the GNU General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; if not, write to the Free Software
00025 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00026 
00027 */
00028 
00029 #include "server.h"
00030 
00035 void SV_SetClientState (client_t* client, int state)
00036 {
00037     assert(client);
00038     Com_DPrintf(DEBUG_SERVER, "Set state for client '%s' to %i\n", client->name, state);
00039     client->state = state;
00040 }
00041 
00042 /*
00043 ============================================================
00044 USER STRINGCMD EXECUTION
00045 ============================================================
00046 */
00047 
00055 static void SV_New_f (client_t *cl)
00056 {
00057     Com_DPrintf(DEBUG_SERVER, "New() from %s\n", cl->name);
00058 
00059     if (cl->state != cs_connected) {
00060         if (cl->state == cs_spawning) {
00061             /* client typed 'reconnect/new' while connecting. */
00062             Com_Printf("SV_New_f: client typed 'reconnect/new' while connecting\n");
00063             SV_ClientCommand(cl, "\ndisconnect\nreconnect\n");
00064             SV_DropClient(cl, "");
00065         } else
00066             Com_DPrintf(DEBUG_SERVER, "WARNING: Illegal 'new' from %s, client state %d. This shouldn't happen...\n", cl->name, cl->state);
00067         return;
00068     }
00069 
00070     /* client state to prevent multiple new from causing high cpu / overflows. */
00071     SV_SetClientState(cl, cs_spawning);
00072 
00073     /* serverdata needs to go over for all types of servers
00074      * to make sure the protocol is right, and to set the gamedir */
00075 
00076     /* send the serverdata */
00077     {
00078         const int playernum = cl - SV_GetClient(0);
00079         struct dbuffer *msg = new_dbuffer();
00080         NET_WriteByte(msg, svc_serverdata);
00081         NET_WriteLong(msg, PROTOCOL_VERSION);
00082 
00083         NET_WriteShort(msg, playernum);
00084 
00085         /* send full levelname */
00086         NET_WriteString(msg, SV_GetConfigString(CS_NAME));
00087 
00088         NET_WriteMsg(cl->stream, msg);
00089     }
00090 
00091     /* game server */
00092     if (Com_ServerState() == ss_game) {
00093         int i;
00094         for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
00095             const char *configString = SV_GetConfigString(i);
00096             if (configString[0] != '\0') {
00097                 struct dbuffer *msg = new_dbuffer();
00098                 Com_DPrintf(DEBUG_SERVER, "sending configstring %d: %s\n", i, configString);
00099                 NET_WriteByte(msg, svc_configstring);
00100                 NET_WriteShort(msg, i);
00101                 NET_WriteString(msg, configString);
00102                 /* enqueue and free msg */
00103                 NET_WriteMsg(cl->stream, msg);
00104             }
00105         }
00106     }
00107 
00108     SV_ClientCommand(cl, "precache\n");
00109 }
00110 
00114 static void SV_Begin_f (client_t *cl)
00115 {
00116     qboolean began;
00117 
00118     Com_DPrintf(DEBUG_SERVER, "Begin() from %s\n", cl->name);
00119 
00120     /* could be abused to respawn or cause spam/other mod-specific problems */
00121     if (cl->state != cs_spawning) {
00122         Com_Printf("EXPLOIT: Illegal 'begin' from %s (already spawned), client dropped.\n", cl->name);
00123         SV_DropClient(cl, "Illegal begin\n");
00124         return;
00125     }
00126 
00127     /* call the game begin function */
00128     SDL_mutexP(svs.serverMutex);
00129     began = svs.ge->ClientBegin(cl->player);
00130     SDL_mutexV(svs.serverMutex);
00131 
00132     if (!began) {
00133         SV_DropClient(cl, "'begin' failed\n");
00134         return;
00135     }
00136     SV_SetClientState(cl, cs_began);
00137 
00138     Cbuf_InsertFromDefer();
00139 }
00140 
00144 static void SV_Spawn_f (client_t *cl)
00145 {
00146     Com_DPrintf(DEBUG_SERVER, "Spawn() from %s\n", cl->name);
00147 
00148     if (cl->state != cs_began) {
00149         SV_DropClient(cl, "Invalid state\n");
00150         return;
00151     }
00152 
00153     SDL_mutexP(svs.serverMutex);
00154     svs.ge->ClientSpawn(cl->player);
00155     SDL_mutexV(svs.serverMutex);
00156     SV_SetClientState(cl, cs_spawned);
00157 
00158     Cbuf_InsertFromDefer();
00159 }
00160 
00161 /*============================================================================ */
00162 
00166 static void SV_Disconnect_f (client_t *cl)
00167 {
00168     SV_DropClient(cl, "Disconnect\n");
00169 }
00170 
00171 
00175 static void SV_ShowServerinfo_f (client_t *cl)
00176 {
00177     Info_Print(Cvar_Serverinfo());
00178 }
00179 
00180 
00181 typedef struct {
00182     const char *name;
00183     void (*func) (client_t *client);
00184 } ucmd_t;
00185 
00186 static const ucmd_t ucmds[] = {
00187     /* auto issued */
00188     {"new", SV_New_f},
00189     {"begin", SV_Begin_f},
00190     {"spawn", SV_Spawn_f},
00191 
00192     {"disconnect", SV_Disconnect_f},
00193 
00194     /* issued by hand at client consoles */
00195     {"info", SV_ShowServerinfo_f},
00196 
00197     {NULL, NULL}
00198 };
00199 
00203 static void SV_ExecuteUserCommand (client_t * cl, const char *s)
00204 {
00205     const ucmd_t *u;
00206 
00207     Cmd_TokenizeString(s, qfalse);
00208 
00209     for (u = ucmds; u->name; u++)
00210         if (!strcmp(Cmd_Argv(0), u->name)) {
00211             Com_DPrintf(DEBUG_SERVER, "SV_ExecuteUserCommand: %s\n", s);
00212             u->func(cl);
00213             return;
00214         }
00215 
00216     if (Com_ServerState() == ss_game) {
00217         Com_DPrintf(DEBUG_SERVER, "SV_ExecuteUserCommand: client command: %s\n", s);
00218         SDL_mutexP(svs.serverMutex);
00219         svs.ge->ClientCommand(cl->player);
00220         SDL_mutexV(svs.serverMutex);
00221     }
00222 }
00223 
00227 void SV_ExecuteClientMessage (client_t * cl, int cmd, struct dbuffer *msg)
00228 {
00229     if (cmd == -1)
00230         return;
00231 
00232     switch (cmd) {
00233     default:
00234         Com_Printf("SV_ExecuteClientMessage: unknown command char '%d'\n", cmd);
00235         SV_DropClient(cl, "Unknown command\n");
00236         return;
00237 
00238     case clc_nop:
00239         break;
00240 
00241     case clc_userinfo:
00242         NET_ReadString(msg, cl->userinfo, sizeof(cl->userinfo));
00243         Com_DPrintf(DEBUG_SERVER, "userinfo from client: %s\n", cl->userinfo);
00244         SV_UserinfoChanged(cl);
00245         break;
00246 
00247     case clc_stringcmd:
00248     {
00249         char str[1024];
00250         NET_ReadString(msg, str, sizeof(str));
00251 
00252         Com_DPrintf(DEBUG_SERVER, "stringcmd from client: %s\n", str);
00253         SV_ExecuteUserCommand(cl, str);
00254 
00255         if (cl->state == cs_free)
00256             return;         /* disconnect command */
00257         break;
00258     }
00259 
00260     case clc_action:
00261         /* client actions are handled by the game module */
00262         sv.messageBuffer = msg;
00263         SDL_mutexP(svs.serverMutex);
00264         svs.ge->ClientAction(cl->player);
00265         SDL_mutexV(svs.serverMutex);
00266         sv.messageBuffer = NULL;
00267         break;
00268 
00269     case clc_endround:
00270         /* player wants to end round */
00271         sv.messageBuffer = msg;
00272         SDL_mutexP(svs.serverMutex);
00273         svs.ge->ClientEndRound(cl->player);
00274         SDL_mutexV(svs.serverMutex);
00275         sv.messageBuffer = NULL;
00276         break;
00277 
00278     case clc_teaminfo:
00279         /* player sends team info */
00280         /* actors spawn accordingly */
00281         sv.messageBuffer = msg;
00282         SDL_mutexP(svs.serverMutex);
00283         svs.ge->ClientTeamInfo(cl->player);
00284         SDL_mutexV(svs.serverMutex);
00285         sv.messageBuffer = NULL;
00286         break;
00287 
00288     case clc_initactorstates:
00289         /* player sends team info */
00290         /* actors spawn accordingly */
00291         sv.messageBuffer = msg;
00292         SDL_mutexP(svs.serverMutex);
00293         svs.ge->ClientInitActorStates(cl->player);
00294         SDL_mutexV(svs.serverMutex);
00295         sv.messageBuffer = NULL;
00296         break;
00297     }
00298 }

Generated by  doxygen 1.6.2