/* ================== SV_NextDownload_f The argument will be the last acknowledged block from the client, it should be the same as cl->downloadClientBlock ================== */ void SV_NextDownload_f( client_t *cl ) { int block = atoi( Cmd_Argv(1) ); if ( cl->state == CS_ACTIVE ) return; if (block == cl->downloadClientBlock) { Com_DPrintf( "clientDownload: %d : client acknowledge of block %d\n", cl - svs.clients, block ); // Find out if we are done. A zero-length block indicates EOF if (cl->downloadBlockSize[cl->downloadClientBlock % MAX_DOWNLOAD_WINDOW] == 0) { Com_Printf( "clientDownload: %d : file \"%s\" completed\n", cl - svs.clients, cl->downloadName ); SV_CloseDownload( cl ); return; } cl->downloadSendTime = svs.time; cl->downloadClientBlock++; return; } // We aren't getting an acknowledge for the correct block, drop the client // FIXME: this is bad... the client will never parse the disconnect message // because the cgame isn't loaded yet SV_DropClient( cl, "broken download" ); }
/* ================== SV_NextDownload_f The argument will be the last acknowledged block from the client, it should be the same as cl->downloadClientBlock ================== */ void SV_NextDownload_f( client_t *cl, const Cmd::Args& args ) { int block; if (args.Argc() < 2 or not Str::ParseInt(block, args.Argv(1))) { return; } if ( block == cl->downloadClientBlock ) { Log::Debug( "clientDownload: %d: client acknowledge of block %d", ( int )( cl - svs.clients ), block ); // Find out if we are done. A zero-length block indicates EOF if ( cl->downloadBlockSize[ cl->downloadClientBlock % MAX_DOWNLOAD_WINDOW ] == 0 ) { Log::Notice( "clientDownload: %d : file \"%s\" completed\n", ( int )( cl - svs.clients ), cl->downloadName ); SV_CloseDownload( cl ); return; } cl->downloadSendTime = svs.time; cl->downloadClientBlock++; return; } // We aren't getting an acknowledge for the correct block, drop the client // FIXME: this is bad... the client will never parse the disconnect message // because the cgame isn't loaded yet SV_DropClient( cl, "broken download" ); }
/* ================== SV_StopDownload_f Abort a download if in progress ================== */ void SV_StopDownload_f( client_t *cl, const Cmd::Args& ) { if ( *cl->downloadName ) { Log::Debug( "clientDownload: %d: file \"%s^7\" aborted", ( int )( cl - svs.clients ), cl->downloadName ); } SV_CloseDownload( cl ); }
/* ================== SV_StopDownload_f Abort a download if in progress ================== */ void SV_StopDownload_f(client_t *cl) { if(*cl->downloadName) { Com_DPrintf("clientDownload: %d : file \"%s\" aborted\n", cl - svs.clients, cl->downloadName); } SV_CloseDownload(cl); }
/* ================== SV_StopDownload_f Abort a download if in progress ================== */ void SV_StopDownload_f( client_t *cl ) { if ( cl->state == CS_ACTIVE ) return; if (*cl->downloadName) Com_DPrintf( "clientDownload: %d : file \"%s\" aborted\n", cl - svs.clients, cl->downloadName ); SV_CloseDownload( cl ); }
/* ================== SV_BeginDownload_f ================== */ static void SV_BeginDownload_f( client_t *cl ) { // Kill any existing download SV_CloseDownload( cl ); // cl->downloadName is non-zero now, SV_WriteDownloadToClient will see this and open // the file itself Q_strncpyz( cl->downloadName, Cmd_Argv(1), sizeof(cl->downloadName) ); }
/* ===================== SV_DropClient Called when the player is totally leaving the server, either willingly or unwillingly. This is NOT called if the entire server is quiting or crashing -- SV_FinalMessage() will handle that ===================== */ void SV_DropClient( client_t *drop, const char *reason ) { int i; challenge_t *challenge; if ( drop->state == CS_ZOMBIE ) { return; // already dropped } // see if we already have a challenge for this ip challenge = &svs.challenges[0]; for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { challenge->connected = qfalse; break; } } // Kill any download SV_CloseDownload( drop ); // tell everyone why they got dropped SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason ); if (drop->download) { FS_FCloseFile( drop->download ); drop->download = 0; } // call the prog function for removing a client // this will remove the body, among other things VM_Call( gvm, GAME_CLIENT_DISCONNECT, drop - svs.clients ); // add the disconnect command SV_SendServerCommand( drop, "disconnect \"%s\"", reason); // nuke user info SV_SetUserinfo( drop - svs.clients, "" ); Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name ); drop->state = CS_ZOMBIE; // become free in a few seconds // if this was the last client on the server, send a heartbeat // to the master so it is known the server is empty // send a heartbeat now so the master will get up to date info // if there is already a slot for this ip, reuse it for (i=0 ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { break; } } if ( i == sv_maxclients->integer ) { SV_Heartbeat_f(); } }
/* ===================== SV_DropClient Called when the player is totally leaving the server, either willingly or unwillingly. This is NOT called if the entire server is quiting or crashing -- SV_FinalMessage() will handle that ===================== */ void SV_DropClient( client_t *drop, const char *reason ) { int i; const bool isBot = drop->netchan.remoteAddress.type == NA_BOT; if ( drop->state == CS_ZOMBIE ) { return; // already dropped } // Kill any download SV_CloseDownload( drop ); // tell everyone why they got dropped SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason ); // call the prog function for removing a client // this will remove the body, among other things GVM_ClientDisconnect( drop - svs.clients ); // add the disconnect command SV_SendServerCommand( drop, "disconnect \"%s\"", reason ); if ( isBot ) { SV_BotFreeClient( drop - svs.clients ); } // nuke user info SV_SetUserinfo( drop - svs.clients, "" ); if ( isBot ) { // bots shouldn't go zombie, as there's no real net connection. drop->state = CS_FREE; } else { Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name ); drop->state = CS_ZOMBIE; // become free in a few seconds } if ( drop->demo.demorecording ) { SV_StopRecordDemo( drop ); } // if this was the last client on the server, send a heartbeat // to the master so it is known the server is empty // send a heartbeat now so the master will get up to date info // if there is already a slot for this ip, reuse it for (i=0 ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { break; } } if ( i == sv_maxclients->integer ) { SV_Heartbeat_f(); } }
/* ===================== SV_FreeClient Destructor for data allocated in a client structure ===================== */ void SV_FreeClient(client_t *client) { #ifdef USE_VOIP int index; for(index = client->queuedVoipIndex; index < client->queuedVoipPackets; index++) { index %= ARRAY_LEN(client->voipPacket); Z_Free(client->voipPacket[index]); } client->queuedVoipPackets = 0; #endif SV_Netchan_FreeQueue(client); SV_CloseDownload(client); }
/* ================== SV_BeginDownload_f ================== */ static void SV_BeginDownload_f( client_t *cl ) { if ( cl->state == CS_ACTIVE ) return; // Kill any existing download SV_CloseDownload( cl ); // Jedi Knight Galaxies -- download validation char *c = Cmd_Argv(1); if(strlen(c) < 4) return; // Do not allow blank file names else if(Q_stricmpn((c + strlen(c) - 4), ".pk3", 4)) return; // Do not allow anything except PK3s else if(strstr(c, "..")) return; // Do not traverse the directory // cl->downloadName is non-zero now, SV_WriteDownloadToClient will see this and open // the file itself Q_strncpyz( cl->downloadName, Cmd_Argv(1), sizeof(cl->downloadName) ); }
/* ================== SV_BeginDownload_f ================== */ void SV_BeginDownload_f( client_t *cl, const Cmd::Args& args ) { // Kill any existing download SV_CloseDownload( cl ); if (args.Argc() < 2) { return; } //bani - stop us from printing dupe messages if (args.Argv(1) != cl->downloadName) { cl->downloadnotify = DLNOTIFY_ALL; } // cl->downloadName is non-zero now, SV_WriteDownloadToClient will see this and open // the file itself Q_strncpyz( cl->downloadName, args.Argv(1).c_str(), sizeof( cl->downloadName ) ); }
/* ===================== SV_FreeClient Destructor for data allocated in a client structure ===================== */ void SV_FreeClient( client_t *client ) { // NA_BOT happens to be the default value for address types (value 0) and are // never for clients that send challenges. For NA_BOT, skip the checks for // challenges as it makes NET_CompareAdr yell at us. if (client->netchan.remoteAddress.type != netadrtype_t::NA_BOT) { // see if we already have a challenge for this IP address challenge_t* challenge = &svs.challenges[ 0 ]; for (int i = 0; i < MAX_CHALLENGES; i++, challenge++) { if ( NET_CompareAdr( client->netchan.remoteAddress, challenge->adr ) ) { challenge->connected = false; break; } } } SV_Netchan_FreeQueue( client ); SV_CloseDownload( client ); }
/* ===================== SV_FreeClient Destructor for data allocated in a client structure ===================== */ void SV_FreeClient( client_t *client ) { SV_Netchan_FreeQueue( client ); SV_CloseDownload( client ); }
/* ===================== SV_DropClient Called when the player is totally leaving the server, either willingly or unwillingly. This is NOT called if the entire server is quiting or crashing -- SV_FinalMessage() will handle that ===================== */ void SV_DropClient(client_t *drop, const char *reason) { int i; if(drop->state == CS_ZOMBIE) { return; // already dropped } // Kill any download SV_CloseDownload(drop); // Ridah, no need to tell the player if an AI drops if(!(drop->gentity && drop->gentity->r.svFlags & SVF_CASTAI)) { // tell everyone why they got dropped SV_SendServerCommand(NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason); } Com_DPrintf("Going to CS_ZOMBIE for %s\n", drop->name); drop->state = CS_ZOMBIE; // become free in a few seconds if(drop->download) { FS_FCloseFile(drop->download); drop->download = 0; } // call the prog function for removing a client // this will remove the body, among other things VM_Call(gvm, GAME_CLIENT_DISCONNECT, drop - svs.clients); // Ridah, no need to tell the player if an AI drops if(!(drop->gentity && drop->gentity->r.svFlags & SVF_CASTAI)) { // add the disconnect command SV_SendServerCommand(drop, "disconnect"); } // done. if(drop->netchan.remoteAddress.type == NA_BOT) { SV_BotFreeClient(drop - svs.clients); } // nuke user info SV_SetUserinfo(drop - svs.clients, ""); // RF, nuke reliable commands SV_FreeReliableCommandsForClient(drop); // if this was the last client on the server, send a heartbeat // to the master so it is known the server is empty // send a heartbeat now so the master will get up to date info // if there is already a slot for this ip, reuse it for(i = 0 ; i < sv_maxclients->integer ; i++) { if(svs.clients[i].state >= CS_CONNECTED) { break; } } if(i == sv_maxclients->integer) { SV_Heartbeat_f(); } }