Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

sv_client.c File Reference

#include "server.h"

Include dependency graph for sv_client.c:

Include dependency graph

Go to the source code of this file.

Data Structures

struct  ucmd_t

Defines

#define PB_MESSAGE

Functions

void SV_AuthorizeIpPacket (netadr_t from)
void SV_BeginDownload_f (client_t *cl)
qboolean SV_ClientCommand (client_t *cl, msg_t *msg)
void SV_ClientEnterWorld (client_t *client, usercmd_t *cmd)
void SV_ClientThink (client_t *cl, usercmd_t *cmd)
void SV_CloseDownload (client_t *cl)
void SV_DirectConnect (netadr_t from)
void SV_Disconnect_f (client_t *cl)
void SV_DoneDownload_f (client_t *cl)
void SV_DropClient (client_t *drop, const char *reason)
void SV_ExecuteClientCommand (client_t *cl, const char *s, qboolean clientOK)
void SV_ExecuteClientMessage (client_t *cl, msg_t *msg)
void SV_GetChallenge (netadr_t from)
void SV_NextDownload_f (client_t *cl)
void SV_ResetPureClient_f (client_t *cl)
void SV_SendClientGameState (client_t *client)
void SV_StopDownload_f (client_t *cl)
void SV_UpdateUserinfo_f (client_t *cl)
void SV_UserinfoChanged (client_t *cl)
void SV_UserMove (client_t *cl, msg_t *msg, qboolean delta)
void SV_VerifyPaks_f (client_t *cl)
void SV_WriteDownloadToClient (client_t *cl, msg_t *msg)

Variables

ucmd_t ucmds []


Define Documentation

#define PB_MESSAGE
 

Value:

"PunkBuster Anti-Cheat software must be installed " \
                "and Enabled in order to join this server. An updated game patch can be downloaded from " \
                "www.idsoftware.com"

Definition at line 226 of file sv_client.c.


Function Documentation

void SV_AuthorizeIpPacket netadr_t  from  ) 
 

Definition at line 147 of file sv_client.c.

References challenge_t::adr, atoi, serverStatic_t::authorizeAddress, challenge_t::challenge, serverStatic_t::challenges, Cmd_Argv(), Com_Memset(), Com_Printf(), Cvar_VariableValue(), i, NET_CompareBaseAdr(), NET_OutOfBandPrint(), NS_SERVER, challenge_t::pingTime, Q_stricmp(), r, s, sprintf(), svs, and serverStatic_t::time.

Referenced by SV_ConnectionlessPacket().

00147                                            {
00148     int     challenge;
00149     int     i;
00150     char    *s;
00151     char    *r;
00152     char    ret[1024];
00153 
00154     if ( !NET_CompareBaseAdr( from, svs.authorizeAddress ) ) {
00155         Com_Printf( "SV_AuthorizeIpPacket: not from authorize server\n" );
00156         return;
00157     }
00158 
00159     challenge = atoi( Cmd_Argv( 1 ) );
00160 
00161     for (i = 0 ; i < MAX_CHALLENGES ; i++) {
00162         if ( svs.challenges[i].challenge == challenge ) {
00163             break;
00164         }
00165     }
00166     if ( i == MAX_CHALLENGES ) {
00167         Com_Printf( "SV_AuthorizeIpPacket: challenge not found\n" );
00168         return;
00169     }
00170 
00171     // send a packet back to the original client
00172     svs.challenges[i].pingTime = svs.time;
00173     s = Cmd_Argv( 2 );
00174     r = Cmd_Argv( 3 );          // reason
00175 
00176     if ( !Q_stricmp( s, "demo" ) ) {
00177         if ( Cvar_VariableValue( "fs_restrict" ) ) {
00178             // a demo client connecting to a demo server
00179             NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, 
00180                 "challengeResponse %i", svs.challenges[i].challenge );
00181             return;
00182         }
00183         // they are a demo client trying to connect to a real server
00184         NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nServer is not a demo server\n" );
00185         // clear the challenge record so it won't timeout and let them through
00186         Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );
00187         return;
00188     }
00189     if ( !Q_stricmp( s, "accept" ) ) {
00190         NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, 
00191             "challengeResponse %i", svs.challenges[i].challenge );
00192         return;
00193     }
00194     if ( !Q_stricmp( s, "unknown" ) ) {
00195         if (!r) {
00196             NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nAwaiting CD key authorization\n" );
00197         } else {
00198             sprintf(ret, "print\n%s\n", r);
00199             NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret );
00200         }
00201         // clear the challenge record so it won't timeout and let them through
00202         Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );
00203         return;
00204     }
00205 
00206     // authorization failed
00207     if (!r) {
00208         NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nSomeone is using this CD Key\n" );
00209     } else {
00210         sprintf(ret, "print\n%s\n", r);
00211         NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret );
00212     }
00213 
00214     // clear the challenge record so it won't timeout and let them through
00215     Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );
00216 }

Here is the call graph for this function:

void SV_BeginDownload_f client_t cl  ) 
 

Definition at line 736 of file sv_client.c.

References cl, client_t, Cmd_Argv(), Q_strncpyz(), and SV_CloseDownload().

00736                                         {
00737 
00738     // Kill any existing download
00739     SV_CloseDownload( cl );
00740 
00741     // cl->downloadName is non-zero now, SV_WriteDownloadToClient will see this and open
00742     // the file itself
00743     Q_strncpyz( cl->downloadName, Cmd_Argv(1), sizeof(cl->downloadName) );
00744 }

Here is the call graph for this function:

qboolean SV_ClientCommand client_t cl,
msg_t msg
[static]
 

Definition at line 1249 of file sv_client.c.

References cl, client_t, com_cl_running, Com_DPrintf(), Com_Printf(), Com_sprintf(), CS_ACTIVE, cvar_s::integer, MSG_ReadLong(), MSG_ReadString(), qboolean, s, SV_DropClient(), SV_ExecuteClientCommand(), sv_floodProtect, svs, and serverStatic_t::time.

Referenced by SV_ExecuteClientMessage().

01249                                                              {
01250     int     seq;
01251     const char  *s;
01252     qboolean clientOk = qtrue;
01253 
01254     seq = MSG_ReadLong( msg );
01255     s = MSG_ReadString( msg );
01256 
01257     // see if we have already executed it
01258     if ( cl->lastClientCommand >= seq ) {
01259         return qtrue;
01260     }
01261 
01262     Com_DPrintf( "clientCommand: %s : %i : %s\n", cl->name, seq, s );
01263 
01264     // drop the connection if we have somehow lost commands
01265     if ( seq > cl->lastClientCommand + 1 ) {
01266         Com_Printf( "Client %s lost %i clientCommands\n", cl->name, 
01267             seq - cl->lastClientCommand + 1 );
01268         SV_DropClient( cl, "Lost reliable commands" );
01269         return qfalse;
01270     }
01271 
01272     // malicious users may try using too many string commands
01273     // to lag other players.  If we decide that we want to stall
01274     // the command, we will stop processing the rest of the packet,
01275     // including the usercmd.  This causes flooders to lag themselves
01276     // but not other people
01277     // We don't do this when the client hasn't been active yet since its
01278     // normal to spam a lot of commands when downloading
01279     if ( !com_cl_running->integer && 
01280         cl->state >= CS_ACTIVE &&
01281         sv_floodProtect->integer && 
01282         svs.time < cl->nextReliableTime ) {
01283         // ignore any other text messages from this client but let them keep playing
01284         // TTimo - moved the ignored verbose to the actual processing in SV_ExecuteClientCommand, only printing if the core doesn't intercept
01285         clientOk = qfalse;
01286     } 
01287 
01288     // don't allow another command for one second
01289     cl->nextReliableTime = svs.time + 1000;
01290 
01291     SV_ExecuteClientCommand( cl, s, clientOk );
01292 
01293     cl->lastClientCommand = seq;
01294     Com_sprintf(cl->lastClientCommandString, sizeof(cl->lastClientCommandString), "%s", s);
01295 
01296     return qtrue;       // continue procesing
01297 }

Here is the call graph for this function:

void SV_ClientEnterWorld client_t client,
usercmd_t cmd
 

Definition at line 616 of file sv_client.c.

References client_t, serverStatic_t::clients, Com_DPrintf(), client_s::deltaMessage, GAME_CLIENT_BEGIN, client_s::gentity, gvm, client_s::lastUsercmd, client_s::name, client_s::nextSnapshotTime, entityState_s::number, sharedEntity_t::s, client_s::state, SV_GentityNum(), svs, serverStatic_t::time, usercmd_t, and VM_Call().

Referenced by SV_MapRestart_f(), and SV_UserMove().

00616                                                              {
00617     int     clientNum;
00618     sharedEntity_t *ent;
00619 
00620     Com_DPrintf( "Going from CS_PRIMED to CS_ACTIVE for %s\n", client->name );
00621     client->state = CS_ACTIVE;
00622 
00623     // set up the entity for the client
00624     clientNum = client - svs.clients;
00625     ent = SV_GentityNum( clientNum );
00626     ent->s.number = clientNum;
00627     client->gentity = ent;
00628 
00629     client->deltaMessage = -1;
00630     client->nextSnapshotTime = svs.time;    // generate a snapshot immediately
00631     client->lastUsercmd = *cmd;
00632 
00633     // call the game begin function
00634     VM_Call( gvm, GAME_CLIENT_BEGIN, client - svs.clients );
00635 }

Here is the call graph for this function:

void SV_ClientThink client_t cl,
usercmd_t cmd
 

Definition at line 1310 of file sv_client.c.

References cl, client_t, serverStatic_t::clients, GAME_CLIENT_THINK, gvm, svs, usercmd_t, and VM_Call().

Referenced by SV_GameSystemCalls(), and SV_UserMove().

01310                                                    {
01311     cl->lastUsercmd = *cmd;
01312 
01313     if ( cl->state != CS_ACTIVE ) {
01314         return;     // may have been kicked during the last usercmd
01315     }
01316 
01317     VM_Call( gvm, GAME_CLIENT_THINK, cl - svs.clients );
01318 }

Here is the call graph for this function:

void SV_CloseDownload client_t cl  )  [static]
 

Definition at line 652 of file sv_client.c.

References cl, client_t, FS_FCloseFile(), i, and Z_Free().

Referenced by SV_BeginDownload_f(), SV_DropClient(), SV_NextDownload_f(), and SV_StopDownload_f().

00652                                              {
00653     int i;
00654 
00655     // EOF
00656     if (cl->download) {
00657         FS_FCloseFile( cl->download );
00658     }
00659     cl->download = 0;
00660     *cl->downloadName = 0;
00661 
00662     // Free the temporary buffer space
00663     for (i = 0; i < MAX_DOWNLOAD_WINDOW; i++) {
00664         if (cl->downloadBlocks[i]) {
00665             Z_Free( cl->downloadBlocks[i] );
00666             cl->downloadBlocks[i] = NULL;
00667         }
00668     }
00669 
00670 }

Here is the call graph for this function:

void SV_DirectConnect netadr_t  from  ) 
 

Definition at line 230 of file sv_client.c.

References challenge_t::adr, atoi, client_s::challenge, challenge_t::challenge, serverStatic_t::challenges, cl, client_t, serverStatic_t::clients, Cmd_Argv(), Com_DPrintf(), Com_Error(), Com_Memset(), Com_Printf(), challenge_t::connected, count, ERR_FATAL, GAME_CLIENT_CONNECT, client_s::gamestateMessageNum, client_s::gentity, gvm, i, Info_SetValueForKey(), Info_ValueForKey(), cvar_s::integer, client_s::lastConnectTime, client_s::lastPacketTime, client_s::name, NET_AdrToString(), NET_CompareAdr(), NET_CompareBaseAdr(), NET_IsLocalAddress(), NET_OutOfBandPrint(), client_s::netchan, client_s::netchan_end_queue, Netchan_Setup(), client_s::netchan_start_queue, client_s::nextSnapshotTime, NS_SERVER, challenge_t::pingTime, netadr_t::port, PROTOCOL_VERSION, Q_strncpyz(), qfalse, qport, qtrue, client_s::state, strcmp(), cvar_s::string, SV_DropClient(), SV_GentityNum(), SV_Heartbeat_f(), sv_maxclients, sv_maxPing, sv_minPing, sv_privateClients, sv_privatePassword, sv_reconnectlimit, SV_UserinfoChanged(), svs, Sys_IsLANAddress(), serverStatic_t::time, client_s::userinfo, cvar_s::value, VM_Call(), and VM_ExplicitArgPtr().

Referenced by SV_ConnectionlessPacket().

00230                                        {
00231     char        userinfo[MAX_INFO_STRING];
00232     int         i;
00233     client_t    *cl, *newcl;
00234     MAC_STATIC client_t temp;
00235     sharedEntity_t *ent;
00236     int         clientNum;
00237     int         version;
00238     int         qport;
00239     int         challenge;
00240     char        *password;
00241     int         startIndex;
00242     char        *denied;
00243     int         count;
00244 
00245     Com_DPrintf ("SVC_DirectConnect ()\n");
00246 
00247     Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) );
00248 
00249     version = atoi( Info_ValueForKey( userinfo, "protocol" ) );
00250     if ( version != PROTOCOL_VERSION ) {
00251         NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION );
00252         Com_DPrintf ("    rejected connect from version %i\n", version);
00253         return;
00254     }
00255 
00256     challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) );
00257     qport = atoi( Info_ValueForKey( userinfo, "qport" ) );
00258 
00259     // quick reject
00260     for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
00261         if ( cl->state == CS_FREE ) {
00262             continue;
00263         }
00264         if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
00265             && ( cl->netchan.qport == qport 
00266             || from.port == cl->netchan.remoteAddress.port ) ) {
00267             if (( svs.time - cl->lastConnectTime) 
00268                 < (sv_reconnectlimit->integer * 1000)) {
00269                 Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (from));
00270                 return;
00271             }
00272             break;
00273         }
00274     }
00275 
00276     // see if the challenge is valid (LAN clients don't need to challenge)
00277     if ( !NET_IsLocalAddress (from) ) {
00278         int     ping;
00279 
00280         for (i=0 ; i<MAX_CHALLENGES ; i++) {
00281             if (NET_CompareAdr(from, svs.challenges[i].adr)) {
00282                 if ( challenge == svs.challenges[i].challenge ) {
00283                     break;      // good
00284                 }
00285             }
00286         }
00287         if (i == MAX_CHALLENGES) {
00288             NET_OutOfBandPrint( NS_SERVER, from, "print\nNo or bad challenge for address.\n" );
00289             return;
00290         }
00291         // force the IP key/value pair so the game can filter based on ip
00292         Info_SetValueForKey( userinfo, "ip", NET_AdrToString( from ) );
00293 
00294         ping = svs.time - svs.challenges[i].pingTime;
00295         Com_Printf( "Client %i connecting with %i challenge ping\n", i, ping );
00296         svs.challenges[i].connected = qtrue;
00297 
00298         // never reject a LAN client based on ping
00299         if ( !Sys_IsLANAddress( from ) ) {
00300             if ( sv_minPing->value && ping < sv_minPing->value ) {
00301                 // don't let them keep trying until they get a big delay
00302                 NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for high pings only\n" );
00303                 Com_DPrintf ("Client %i rejected on a too low ping\n", i);
00304                 // reset the address otherwise their ping will keep increasing
00305                 // with each connect message and they'd eventually be able to connect
00306                 svs.challenges[i].adr.port = 0;
00307                 return;
00308             }
00309             if ( sv_maxPing->value && ping > sv_maxPing->value ) {
00310                 NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for low pings only\n" );
00311                 Com_DPrintf ("Client %i rejected on a too high ping\n", i);
00312                 return;
00313             }
00314         }
00315     } else {
00316         // force the "ip" info key to "localhost"
00317         Info_SetValueForKey( userinfo, "ip", "localhost" );
00318     }
00319 
00320     newcl = &temp;
00321     Com_Memset (newcl, 0, sizeof(client_t));
00322 
00323     // if there is already a slot for this ip, reuse it
00324     for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
00325         if ( cl->state == CS_FREE ) {
00326             continue;
00327         }
00328         if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
00329             && ( cl->netchan.qport == qport 
00330             || from.port == cl->netchan.remoteAddress.port ) ) {
00331             Com_Printf ("%s:reconnect\n", NET_AdrToString (from));
00332             newcl = cl;
00333 
00334             // this doesn't work because it nukes the players userinfo
00335 
00336 //          // disconnect the client from the game first so any flags the
00337 //          // player might have are dropped
00338 //          VM_Call( gvm, GAME_CLIENT_DISCONNECT, newcl - svs.clients );
00339             //
00340             goto gotnewcl;
00341         }
00342     }
00343 
00344     // find a client slot
00345     // if "sv_privateClients" is set > 0, then that number
00346     // of client slots will be reserved for connections that
00347     // have "password" set to the value of "sv_privatePassword"
00348     // Info requests will report the maxclients as if the private
00349     // slots didn't exist, to prevent people from trying to connect
00350     // to a full server.
00351     // This is to allow us to reserve a couple slots here on our
00352     // servers so we can play without having to kick people.
00353 
00354     // check for privateClient password
00355     password = Info_ValueForKey( userinfo, "password" );
00356     if ( !strcmp( password, sv_privatePassword->string ) ) {
00357         startIndex = 0;
00358     } else {
00359         // skip past the reserved slots
00360         startIndex = sv_privateClients->integer;
00361     }
00362 
00363     newcl = NULL;
00364     for ( i = startIndex; i < sv_maxclients->integer ; i++ ) {
00365         cl = &svs.clients[i];
00366         if (cl->state == CS_FREE) {
00367             newcl = cl;
00368             break;
00369         }
00370     }
00371 
00372     if ( !newcl ) {
00373         if ( NET_IsLocalAddress( from ) ) {
00374             count = 0;
00375             for ( i = startIndex; i < sv_maxclients->integer ; i++ ) {
00376                 cl = &svs.clients[i];
00377                 if (cl->netchan.remoteAddress.type == NA_BOT) {
00378                     count++;
00379                 }
00380             }
00381             // if they're all bots
00382             if (count >= sv_maxclients->integer - startIndex) {
00383                 SV_DropClient(&svs.clients[sv_maxclients->integer - 1], "only bots on server");
00384                 newcl = &svs.clients[sv_maxclients->integer - 1];
00385             }
00386             else {
00387                 Com_Error( ERR_FATAL, "server is full on local connect\n" );
00388                 return;
00389             }
00390         }
00391         else {
00392             NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is full.\n" );
00393             Com_DPrintf ("Rejected a connection.\n");
00394             return;
00395         }
00396     }
00397 
00398     // we got a newcl, so reset the reliableSequence and reliableAcknowledge
00399     cl->reliableAcknowledge = 0;
00400     cl->reliableSequence = 0;
00401 
00402 gotnewcl:   
00403     // build a new connection
00404     // accept the new client
00405     // this is the only place a client_t is ever initialized
00406     *newcl = temp;
00407     clientNum = newcl - svs.clients;
00408     ent = SV_GentityNum( clientNum );
00409     newcl->gentity = ent;
00410 
00411     // save the challenge
00412     newcl->challenge = challenge;
00413 
00414     // save the address
00415     Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport);
00416     // init the netchan queue
00417     newcl->netchan_end_queue = &newcl->netchan_start_queue;
00418 
00419     // save the userinfo
00420     Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) );
00421 
00422     // get the game a chance to reject this connection or modify the userinfo
00423     denied = (char *)VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, qtrue, qfalse ); // firstTime = qtrue
00424     if ( denied ) {
00425         // we can't just use VM_ArgPtr, because that is only valid inside a VM_Call
00426         denied = VM_ExplicitArgPtr( gvm, (int)denied );
00427 
00428         NET_OutOfBandPrint( NS_SERVER, from, "print\n%s\n", denied );
00429         Com_DPrintf ("Game rejected a connection: %s.\n", denied);
00430         return;
00431     }
00432 
00433     SV_UserinfoChanged( newcl );
00434 
00435     // send the connect packet to the client
00436     NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" );
00437 
00438     Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name );
00439 
00440     newcl->state = CS_CONNECTED;
00441     newcl->nextSnapshotTime = svs.time;
00442     newcl->lastPacketTime = svs.time;
00443     newcl->lastConnectTime = svs.time;
00444     
00445     // when we receive the first packet from the client, we will
00446     // notice that it is from a different serverid and that the
00447     // gamestate message was not just sent, forcing a retransmit
00448     newcl->gamestateMessageNum = -1;
00449 
00450     // if this was the first client on the server, or the last client
00451     // the server can hold, send a heartbeat to the master.
00452     count = 0;
00453     for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
00454         if ( svs.clients[i].state >= CS_CONNECTED ) {
00455             count++;
00456         }
00457     }
00458     if ( count == 1 || count == sv_maxclients->integer ) {
00459         SV_Heartbeat_f();
00460     }
00461 }

Here is the call graph for this function:

void SV_Disconnect_f client_t cl  )  [static]
 

Definition at line 930 of file sv_client.c.

References cl, client_t, and SV_DropClient().

00930                                             {
00931     SV_DropClient( cl, "disconnected" );
00932 }

Here is the call graph for this function:

void SV_DoneDownload_f client_t cl  ) 
 

Definition at line 693 of file sv_client.c.

References cl, client_t, Com_DPrintf(), and SV_SendClientGameState().

00693                                        {
00694     Com_DPrintf( "clientDownload: %s Done\n", cl->name);
00695     // resend the game state to update any clients that entered during the download
00696     SV_SendClientGameState(cl);
00697 }

Here is the call graph for this function:

void SV_DropClient client_t drop,
const char *  reason
 

Definition at line 473 of file sv_client.c.

References challenge_t::adr, serverStatic_t::challenges, client_t, serverStatic_t::clients, Com_DPrintf(), challenge_t::connected, client_s::download, FS_FCloseFile(), GAME_CLIENT_DISCONNECT, client_s::gentity, gvm, i, cvar_s::integer, client_s::name, NET_CompareAdr(), client_s::netchan, NULL, sharedEntity_t::r, netchan_t::remoteAddress, S_COLOR_WHITE, client_s::state, SV_BotFreeClient(), SV_CloseDownload(), SV_Heartbeat_f(), sv_maxclients, SV_SendServerCommand(), SV_SetUserinfo(), entityShared_t::svFlags, svs, netadr_t::type, and VM_Call().

Referenced by SV_AddServerCommand(), SV_CheckTimeouts(), SV_ClientCommand(), SV_DirectConnect(), SV_Disconnect_f(), SV_ExecuteClientMessage(), SV_GameDropClient(), SV_Kick_f(), SV_KickNum_f(), SV_MapRestart_f(), SV_NextDownload_f(), SV_SpawnServer(), SV_UserMove(), and SV_VerifyPaks_f().

00473                                                          {
00474     int     i;
00475     challenge_t *challenge;
00476 
00477     if ( drop->state == CS_ZOMBIE ) {
00478         return;     // already dropped
00479     }
00480 
00481     if ( !drop->gentity || !(drop->gentity->r.svFlags & SVF_BOT) ) {
00482         // see if we already have a challenge for this ip
00483         challenge = &svs.challenges[0];
00484 
00485         for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) {
00486             if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) {
00487                 challenge->connected = qfalse;
00488                 break;
00489             }
00490         }
00491     }
00492 
00493     // Kill any download
00494     SV_CloseDownload( drop );
00495 
00496     // tell everyone why they got dropped
00497     SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason );
00498 
00499     Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name );
00500     drop->state = CS_ZOMBIE;        // become free in a few seconds
00501 
00502     if (drop->download) {
00503         FS_FCloseFile( drop->download );
00504         drop->download = 0;
00505     }
00506 
00507     // call the prog function for removing a client
00508     // this will remove the body, among other things
00509     VM_Call( gvm, GAME_CLIENT_DISCONNECT, drop - svs.clients );
00510 
00511     // add the disconnect command
00512     SV_SendServerCommand( drop, "disconnect \"%s\"", reason);
00513 
00514     if ( drop->netchan.remoteAddress.type == NA_BOT ) {
00515         SV_BotFreeClient( drop - svs.clients );
00516     }
00517 
00518     // nuke user info
00519     SV_SetUserinfo( drop - svs.clients, "" );
00520 
00521     // if this was the last client on the server, send a heartbeat
00522     // to the master so it is known the server is empty
00523     // send a heartbeat now so the master will get up to date info
00524     // if there is already a slot for this ip, reuse it
00525     for (i=0 ; i < sv_maxclients->integer ; i++ ) {
00526         if ( svs.clients[i].state >= CS_CONNECTED ) {
00527             break;
00528         }
00529     }
00530     if ( i == sv_maxclients->integer ) {
00531         SV_Heartbeat_f();
00532     }
00533 }

Here is the call graph for this function:

void SV_ExecuteClientCommand client_t cl,
const char *  s,
qboolean  clientOK
 

Definition at line 1219 of file sv_client.c.

References cl, client_t, serverStatic_t::clients, Cmd_Argv(), Cmd_TokenizeString(), Com_DPrintf(), ucmd_t::func, GAME_CLIENT_COMMAND, gvm, ucmd_t::name, qboolean, s, server_t::state, strcmp(), sv, svs, and VM_Call().

Referenced by BotClientCommand(), and SV_ClientCommand().

01219                                                                                {
01220     ucmd_t  *u;
01221     qboolean bProcessed = qfalse;
01222     
01223     Cmd_TokenizeString( s );
01224 
01225     // see if it is a server level command
01226     for (u=ucmds ; u->name ; u++) {
01227         if (!strcmp (Cmd_Argv(0), u->name) ) {
01228             u->func( cl );
01229             bProcessed = qtrue;
01230             break;
01231         }
01232     }
01233 
01234     if (clientOK) {
01235         // pass unknown strings to the game
01236         if (!u->name && sv.state == SS_GAME) {
01237             VM_Call( gvm, GAME_CLIENT_COMMAND, cl - svs.clients );
01238         }
01239     }
01240     else if (!bProcessed)
01241         Com_DPrintf( "client text ignored for %s: %s\n", cl->name, Cmd_Argv(0) );
01242 }

Here is the call graph for this function:

void SV_ExecuteClientMessage client_t cl,
msg_t msg
 

Definition at line 1444 of file sv_client.c.

References c, cl, client_t, serverStatic_t::clients, Com_DPrintf(), Com_Printf(), MSG_Bitstream(), MSG_ReadByte(), MSG_ReadLong(), qfalse, qtrue, server_t::restartedServerId, server_t::serverId, strstr(), sv, SV_ClientCommand(), SV_DropClient(), SV_SendClientGameState(), SV_UserMove(), and svs.

Referenced by SV_PacketEvent().

01444                                                          {
01445     int         c;
01446     int         serverId;
01447 
01448     MSG_Bitstream(msg);
01449 
01450     serverId = MSG_ReadLong( msg );
01451     cl->messageAcknowledge = MSG_ReadLong( msg );
01452 
01453     if (cl->messageAcknowledge < 0) {
01454         // usually only hackers create messages like this
01455         // it is more annoying for them to let them hanging
01456 #ifndef NDEBUG
01457         SV_DropClient( cl, "DEBUG: illegible client message" );
01458 #endif
01459         return;
01460     }
01461 
01462     cl->reliableAcknowledge = MSG_ReadLong( msg );
01463 
01464     // NOTE: when the client message is fux0red the acknowledgement numbers
01465     // can be out of range, this could cause the server to send thousands of server
01466     // commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient
01467     if (cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS) {
01468         // usually only hackers create messages like this
01469         // it is more annoying for them to let them hanging
01470 #ifndef NDEBUG
01471         SV_DropClient( cl, "DEBUG: illegible client message" );
01472 #endif
01473         cl->reliableAcknowledge = cl->reliableSequence;
01474         return;
01475     }
01476     // if this is a usercmd from a previous gamestate,
01477     // ignore it or retransmit the current gamestate
01478     // 
01479     // if the client was downloading, let it stay at whatever serverId and
01480     // gamestate it was at.  This allows it to keep downloading even when
01481     // the gamestate changes.  After the download is finished, we'll
01482     // notice and send it a new game state
01483     //
01484     // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=536
01485     // don't drop as long as previous command was a nextdl, after a dl is done, downloadName is set back to ""
01486     // but we still need to read the next message to move to next download or send gamestate
01487     // I don't like this hack though, it must have been working fine at some point, suspecting the fix is somewhere else
01488     if ( serverId != sv.serverId && !*cl->downloadName && !strstr(cl->lastClientCommandString, "nextdl") ) {
01489         if ( serverId >= sv.restartedServerId && serverId < sv.serverId ) { // TTimo - use a comparison here to catch multiple map_restart
01490             // they just haven't caught the map_restart yet
01491             Com_DPrintf("%s : ignoring pre map_restart / outdated client message\n", cl->name);
01492             return;
01493         }
01494         // if we can tell that the client has dropped the last
01495         // gamestate we sent them, resend it
01496         if ( cl->messageAcknowledge > cl->gamestateMessageNum ) {
01497             Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name );
01498             SV_SendClientGameState( cl );
01499         }
01500         return;
01501     }
01502 
01503     // read optional clientCommand strings
01504     do {
01505         c = MSG_ReadByte( msg );
01506         if ( c == clc_EOF ) {
01507             break;
01508         }
01509         if ( c != clc_clientCommand ) {
01510             break;
01511         }
01512         if ( !SV_ClientCommand( cl, msg ) ) {
01513             return; // we couldn't execute it because of the flood protection
01514         }
01515         if (cl->state == CS_ZOMBIE) {
01516             return; // disconnect command
01517         }
01518     } while ( 1 );
01519 
01520     // read the usercmd_t
01521     if ( c == clc_move ) {
01522         SV_UserMove( cl, msg, qtrue );
01523     } else if ( c == clc_moveNoDelta ) {
01524         SV_UserMove( cl, msg, qfalse );
01525     } else if ( c != clc_EOF ) {
01526         Com_Printf( "WARNING: bad command byte for client %i\n", cl - svs.clients );
01527     }
01528 //  if ( msg->readcount != msg->cursize ) {
01529 //      Com_Printf( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients );
01530 //  }
01531 }

Here is the call graph for this function:

void SV_GetChallenge netadr_t  from  ) 
 

Definition at line 46 of file sv_client.c.

References challenge_t::adr, AUTHORIZE_SERVER_NAME, serverStatic_t::authorizeAddress, BASEGAME, BigShort(), challenge_t::challenge, serverStatic_t::challenges, Com_DPrintf(), Com_Printf(), challenge_t::connected, Cvar_Get(), CVAR_INIT, CVAR_SYSTEMINFO, cvar_t, Cvar_VariableValue(), challenge_t::firstTime, GT_SINGLE_PLAYER, i, netadr_t::ip, NET_AdrToString(), NET_CompareAdr(), NET_OutOfBandPrint(), NET_StringToAdr(), NS_SERVER, challenge_t::pingTime, netadr_t::port, PORT_AUTHORIZE, rand(), strcpy(), cvar_s::string, sv_strictAuth, svs, Sys_IsLANAddress(), serverStatic_t::time, challenge_t::time, and netadr_t::type.

Referenced by SV_ConnectionlessPacket().

00046                                       {
00047     int     i;
00048     int     oldest;
00049     int     oldestTime;
00050     challenge_t *challenge;
00051 
00052     // ignore if we are in single player
00053     if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) {
00054         return;
00055     }
00056 
00057     oldest = 0;
00058     oldestTime = 0x7fffffff;
00059 
00060     // see if we already have a challenge for this ip
00061     challenge = &svs.challenges[0];
00062     for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) {
00063         if ( !challenge->connected && NET_CompareAdr( from, challenge->adr ) ) {
00064             break;
00065         }
00066         if ( challenge->time < oldestTime ) {
00067             oldestTime = challenge->time;
00068             oldest = i;
00069         }
00070     }
00071 
00072     if (i == MAX_CHALLENGES) {
00073         // this is the first time this client has asked for a challenge
00074         challenge = &svs.challenges[oldest];
00075 
00076         challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time;
00077         challenge->adr = from;
00078         challenge->firstTime = svs.time;
00079         challenge->time = svs.time;
00080         challenge->connected = qfalse;
00081         i = oldest;
00082     }
00083 
00084     // if they are on a lan address, send the challengeResponse immediately
00085     if ( Sys_IsLANAddress( from ) ) {
00086         challenge->pingTime = svs.time;
00087         NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge );
00088         return;
00089     }
00090 
00091     // look up the authorize server's IP
00092     if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
00093         Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
00094         if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {
00095             Com_Printf( "Couldn't resolve address\n" );
00096             return;
00097         }
00098         svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
00099         Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
00100             svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
00101             svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
00102             BigShort( svs.authorizeAddress.port ) );
00103     }
00104 
00105     // if they have been challenging for a long time and we
00106     // haven't heard anything from the authorize server, go ahead and
00107     // let them in, assuming the id server is down
00108     if ( svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT ) {
00109         Com_DPrintf( "authorize server timed out\n" );
00110 
00111         challenge->pingTime = svs.