2011-11-22 21:28:15 +00:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
|
|
|
|
Doom 3 GPL Source Code
|
2011-12-06 18:20:15 +00:00
|
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
2011-11-22 21:28:15 +00:00
|
|
|
|
2011-12-06 16:14:59 +00:00
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
2011-11-22 21:28:15 +00:00
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
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__
|
|
|
|
|
2011-12-16 22:28:29 +00:00
|
|
|
#include "framework/UsercmdGen.h"
|
|
|
|
|
2011-11-22 21:28:15 +00:00
|
|
|
/*
|
|
|
|
===============================================================================
|
|
|
|
|
|
|
|
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;
|
2011-12-06 18:20:15 +00:00
|
|
|
|
2011-11-22 21:28:15 +00:00
|
|
|
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 );
|
2012-07-03 22:07:57 +00:00
|
|
|
bool SendPureServerMessage( const netadr_t to ); // returns false if no pure paks on the list
|
2011-11-22 21:28:15 +00:00
|
|
|
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 );
|
2012-07-03 22:07:57 +00:00
|
|
|
bool VerifyChecksumMessage( int clientNum, const netadr_t *from, const idBitMsg &msg, idStr &reply ); // if from is NULL, clientNum is used for error messages
|
2011-11-22 21:28:15 +00:00
|
|
|
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__ */
|