#include "server.h"
Include dependency graph for sv_client.c:

Go to the source code of this file.
|
|
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. |
|
|
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:

|
|
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:

|
||||||||||||
|
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:

|
||||||||||||
|
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:

|
||||||||||||
|
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:

|
|
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:

|
|
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:

|
|
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:

|
|
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:

|
||||||||||||
|
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:

|
||||||||||||||||
|
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:

|
||||||||||||
|
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:

|
|
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. |