/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 Source Code. If not, see . In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #ifndef __ASYNCSERVER_H__ #define __ASYNCSERVER_H__ #include "framework/UsercmdGen.h" /* =============================================================================== Network Server for asynchronous networking. =============================================================================== */ // MAX_CHALLENGES is made large to prevent a denial of service attack that could cycle // all of them out before legitimate users connected const int MAX_CHALLENGES = 1024; // if we don't hear from authorize server, assume it is down const int AUTHORIZE_TIMEOUT = 5000; // states for the server's authorization process typedef enum { CDK_WAIT = 0, // we are waiting for a confirm/deny from auth // this is subject to timeout if we don't hear from auth // or a permanent wait if auth said so CDK_OK, CDK_ONLYLAN, CDK_PUREWAIT, CDK_PUREOK, CDK_MAXSTATES } authState_t; // states from the auth server, while the client is in CDK_WAIT typedef enum { AUTH_NONE = 0, // no reply yet AUTH_OK, // this client is good AUTH_WAIT, // wait - keep sending me srvAuth though AUTH_DENY, // denied - don't send me anything about this client anymore AUTH_MAXSTATES } authReply_t; // message from auth to be forwarded back to the client // some are locally hardcoded to save space, auth has the possibility to send a custom reply typedef enum { AUTH_REPLY_WAITING = 0, // waiting on an initial reply from auth AUTH_REPLY_UNKNOWN, // client unknown to auth AUTH_REPLY_DENIED, // access denied AUTH_REPLY_PRINT, // custom message AUTH_REPLY_SRVWAIT, // auth server replied and tells us he's working on it AUTH_REPLY_MAXSTATES } authReplyMsg_t; typedef struct challenge_s { netadr_t address; // client address int clientId; // client identification int challenge; // challenge code int time; // time the challenge was created int pingTime; // time the challenge response was sent to client bool connected; // true if the client is connected authState_t authState; // local state regarding the client authReply_t authReply; // cd key check replies authReplyMsg_t authReplyMsg; // default auth messages idStr authReplyPrint; // custom msg char guid[12]; // guid } challenge_t; typedef enum { SCS_FREE, // can be reused for a new connection SCS_ZOMBIE, // client has been disconnected, but don't reuse connection for a couple seconds SCS_PUREWAIT, // client needs to update it's pure checksums before we can go further SCS_CONNECTED, // client is connected SCS_INGAME // client is in the game } serverClientState_t; typedef struct serverClient_s { int clientId; serverClientState_t clientState; int clientPrediction; int clientAheadTime; int clientRate; int clientPing; int gameInitSequence; int gameFrame; int gameTime; idMsgChannel channel; int lastConnectTime; int lastEmptyTime; int lastPingTime; int lastSnapshotTime; int lastPacketTime; int lastInputTime; int snapshotSequence; int acknowledgeSnapshotSequence; int numDuplicatedUsercmds; char guid[12]; // Even Balance - M. Quinn } serverClient_t; class idAsyncServer { public: idAsyncServer(); bool InitPort( void ); void ClosePort( void ); void Spawn( void ); void Kill( void ); void ExecuteMapChange( void ); int GetPort( void ) const; netadr_t GetBoundAdr( void ) const; bool IsActive( void ) const { return active; } int GetDelay( void ) const { return gameTimeResidual; } int GetOutgoingRate( void ) const; int GetIncomingRate( void ) const; bool IsClientInGame( int clientNum ) const; int GetClientPing( int clientNum ) const; int GetClientPrediction( int clientNum ) const; int GetClientTimeSinceLastPacket( int clientNum ) const; int GetClientTimeSinceLastInput( int clientNum ) const; int GetClientOutgoingRate( int clientNum ) const; int GetClientIncomingRate( int clientNum ) const; float GetClientOutgoingCompression( int clientNum ) const; float GetClientIncomingCompression( int clientNum ) const; float GetClientIncomingPacketLoss( int clientNum ) const; int GetNumClients( void ) const; int GetNumIdleClients( void ) const; int GetLocalClientNum( void ) const { return localClientNum; } void RunFrame( void ); void ProcessConnectionLessMessages( void ); void RemoteConsoleOutput( const char *string ); void SendReliableGameMessage( int clientNum, const idBitMsg &msg ); void SendReliableGameMessageExcluding( int clientNum, const idBitMsg &msg ); void LocalClientSendReliableMessage( const idBitMsg &msg ); void MasterHeartbeat( bool force = false ); void DropClient( int clientNum, const char *reason ); void PacifierUpdate( void ); void UpdateUI( int clientNum ); void UpdateAsyncStatsAvg( void ); void GetAsyncStatsAvgMsg( idStr &msg ); void PrintLocalServerInfo( void ); private: bool active; // true if server is active int realTime; // absolute time int serverTime; // local server time idPort serverPort; // UDP port int serverId; // server identification int serverDataChecksum; // checksum of the data used by the server int localClientNum; // local client on listen server challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting serverClient_t clients[MAX_ASYNC_CLIENTS]; // clients usercmd_t userCmds[MAX_USERCMD_BACKUP][MAX_ASYNC_CLIENTS]; int gameInitId; // game initialization identification int gameFrame; // local game frame int gameTime; // local game time int gameTimeResidual; // left over time from previous frame netadr_t rconAddress; int nextHeartbeatTime; int nextAsyncStatsTime; bool serverReloadingEngine; // flip-flop to not loop over when net_serverReloadEngine is on bool noRconOutput; // for default rcon response when command is silent int lastAuthTime; // global for auth server timeout // track the max outgoing rate over the last few secs to watch for spikes // dependent on net_serverSnapshotDelay. 50ms, for a 3 seconds backlog -> 60 samples static const int stats_numsamples = 60; int stats_outrate[ stats_numsamples ]; int stats_current; int stats_average_sum; int stats_max; int stats_max_index; void PrintOOB( const netadr_t to, int opcode, const char *string ); void DuplicateUsercmds( int frame, int time ); void ClearClient( int clientNum ); void InitClient( int clientNum, int clientId, int clientRate ); void InitLocalClient( int clientNum ); void BeginLocalClient( void ); void LocalClientInput( void ); void CheckClientTimeouts( void ); void SendPrintBroadcast( const char *string ); void SendPrintToClient( int clientNum, const char *string ); void SendUserInfoBroadcast( int userInfoNum, const idDict &info, bool sendToAll = false ); void SendUserInfoToClient( int clientNum, int userInfoNum, const idDict &info ); void SendSyncedCvarsBroadcast( const idDict &cvars ); void SendSyncedCvarsToClient( int clientNum, const idDict &cvars ); void SendApplySnapshotToClient( int clientNum, int sequence ); bool SendEmptyToClient( int clientNum, bool force = false ); bool SendPingToClient( int clientNum ); void SendGameInitToClient( int clientNum ); bool SendSnapshotToClient( int clientNum ); void ProcessUnreliableClientMessage( int clientNum, const idBitMsg &msg ); void ProcessReliableClientMessages( int clientNum ); void ProcessChallengeMessage( const netadr_t from, const idBitMsg &msg ); void ProcessConnectMessage( const netadr_t from, const idBitMsg &msg ); void ProcessRemoteConsoleMessage( const netadr_t from, const idBitMsg &msg ); void ProcessGetInfoMessage( const netadr_t from, const idBitMsg &msg ); bool ConnectionlessMessage( const netadr_t from, const idBitMsg &msg ); bool ProcessMessage( const netadr_t from, idBitMsg &msg ); void ProcessAuthMessage( const idBitMsg &msg ); bool SendPureServerMessage( const netadr_t to ); // returns false if no pure paks on the list void ProcessPureMessage( const netadr_t from, const idBitMsg &msg ); int ValidateChallenge( const netadr_t from, int challenge, int clientId ); // returns -1 if validate failed bool SendReliablePureToClient( int clientNum ); void ProcessReliablePure( int clientNum, const idBitMsg &msg ); bool VerifyChecksumMessage( int clientNum, const netadr_t *from, const idBitMsg &msg, idStr &reply ); // if from is NULL, clientNum is used for error messages void SendReliableMessage( int clientNum, const idBitMsg &msg ); // checks for overflow and disconnects the faulty client int UpdateTime( int clamp ); void SendEnterGameToClient( int clientNum ); void ProcessDownloadRequestMessage( const netadr_t from, const idBitMsg &msg ); }; #endif /* !__ASYNCSERVER_H__ */