This commit is contained in:
romkazvo
2023-08-07 19:29:24 +08:00
commit 34d6c5d489
4832 changed files with 1389451 additions and 0 deletions

126
CryNetwork/ASEQuerySDK.h Normal file
View File

@@ -0,0 +1,126 @@
/*
ASE Query & Reporting SDK Copyright (C) 2003 UDP Soft Ltd
http://www.udpsoft.com/eye/ All Rights Reserved
Enables reporting to the ASE master server and responding to server
browser queries.
Before reading further, see example.c for a quick display of how simple this
really is.
A quick run-down of things to do:
1. Initialization
extern int ASEQuery_initialize(int hostport, int internet, char *address);
hostport = the join port for the server
internet = flag indicating whether we should report to the ASE master server
(LAN servers should set this to 0)
address = IP address to bind to (pass as NULL if your game does not have
support for multihomed hosts)
This function should be called when the server is started. Does a DNS lookup,
so call only when net already running. NOTE! Winsock must be initialized
before calling the init function (see example.c).
Returns 0 on error, char *ASEQuery_error contains the error message.
2. The worker function
extern int ASEQuery_check(void);
Ideally this should be called every millisecond. The simplest implementation
would be to call this every "frame". Longer delays cause bigger ping
fluctuations ie. not so accurate pings in the server browser.
Returns 0 on error, char *ASEQuery_error contains the error message.
3. Functions that the _game_ has to implement
void ASEQuery_wantstatus(void);
void ASEQuery_wantrules(void);
void ASEQuery_wantplayers(void);
These are called when the SDK needs information about the game state.
In each of these functions, the game must call back to the SDK providing
the required information.
4. Functions that the game calls to provide information back to the SDK
extern void ASEQuery_status(const char *hostname, const char *gametype, const char *mapname, const char *gamever, int password, int numplayers, int maxplayers);
extern void ASEQuery_addrule(const char *key, const char *value);
extern void ASEQuery_addplayer(const char *name, const char *team, const char *skin, const char *score, const char *ping, const char *time);
These can only be called in the corresponding functions described earlier.
ASEQuery_status must only be called once. ASEQuery_addrule and
ASEQuery_addplayer should be called for each rule/player that the game
wishes to be visible in the server browser. Player info fields that don't
apply can be passed as NULL.
5. Shutting down
extern void ASEQuery_shutdown(void);
6. How to link
In C:
#include "ASEQuerySDK.h" in every module that uses the SDK.
In C++:
extern "C" {
#include "ASEQuerySDK.h"
}
Link with ASEQuerySDK.LIB
The SDK uses the __cdecl calling convention.
7. Used ports
The SDK uses gameport+123 (UDP) as the default port for queries. If that port
is not available, the next available port is used (+124, +125...). This port
must have unrestricted access to/from the internet.
8. Other stuff
For ASE support, your game also has to implement commandline parsing for
server address, player name, password etc.
The standard implementation would be:
game.exe +connect ip:port +name "my name" +config "myconfig.cfg" +password "server password"
Let us know the commandline options for your game so we can update ASE
accordingly. In addition to this we'll need the executable name and the
registry key for the install folder.
For the demo version of the SDK, there's built-in ASE support already. Just
go to View -> Options -> Games -> Not Installed -> SDK test and check
"Visible in filter list". Any server running the demo SDK will now appear
under the "SDK test" filter.
actual .h stuff follows
*/
extern int ASEQuery_initialize(int hostport, int internet, char *address);
extern void ASEQuery_shutdown(void);
extern int ASEQuery_check(void);
void ASEQuery_wantstatus(void);
void ASEQuery_wantrules(void);
void ASEQuery_wantplayers(void);
extern void ASEQuery_status(const char *hostname, const char *gametype, const char *mapname, const char *gamever, int password, int numplayers, int maxplayers);
extern void ASEQuery_addrule(const char *key, const char *value);
extern void ASEQuery_addplayer(const char *name, const char *team, const char *skin, const char *score, const char *ping, const char *time);
extern char *ASEQuery_error;

BIN
CryNetwork/ASEQuerySDK.lib Normal file

Binary file not shown.

511
CryNetwork/CCPEndpoint.cpp Normal file
View File

@@ -0,0 +1,511 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: CCPEndpoint.cpp
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CCPEndpoint.h"
#include "Network.h"
#include <ISystem.h>
#include <IConsole.h>
#if defined(_DEBUG) && !defined(LINUX)
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
#ifndef WIN32
int GetCurrentProcessId()
{
return 0;
}
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CCCPEndpoint::CCCPEndpoint()
{
m_pParent=0;
Reset();
//new char[100000];//test
}
void CCCPEndpoint::Init( _ICCPUser *pParent )
{
m_pParent=pParent;
}
CCCPEndpoint::~CCCPEndpoint()
{
while(!m_qOutgoingData.empty())
{
CCPPayload *pTemp=m_qOutgoingData.front();
delete pTemp;
m_qOutgoingData.pop();
}
}
void CCCPEndpoint::Reset()
{
m_bFrameExpected = false;
m_bNextFrameToSend = false;
m_bAckExpected=!m_bNextFrameToSend;
EnableSend();
m_ulTimeout = 0;
}
void CCCPEndpoint::SetTimer()
{
if (m_ulTimeout == 0)
m_ulTimeout = m_nCurrentTime;
}
void CCCPEndpoint::StopTimer()
{
m_ulTimeout = 0;
}
bool CCCPEndpoint::Update(unsigned int nTime, unsigned char cFrameType, CStream *pStm)
{
m_nCurrentTime = nTime;
// manage incoming frames
if (cFrameType)
{
if (cFrameType == FT_CCP_ACK)
{
/// ACK///////////////////////////////////
CCPAck ccpAck;
ccpAck.Load(*pStm);
if (ccpAck.m_bAck == m_bAckExpected)
{
NET_TRACE("[%08X] IN [CCP] RECEIVED ACK %02d \n",::GetCurrentProcessId(), ccpAck.m_bAck?1:0);
StopTimer();
EnableSend();
m_stmRetrasmissionBuffer.Reset();
}
/*else
{
HandleTimeout();
NET_TRACE("CCCPEndpoint::Update ACK OUT OF SEQ %d\n",ccpAck.m_bAck?1:0);
}*/
/////////////////////////////////////////
}
else
{
/// PAYLOAD///////////////////////////////
if (!ProcessPayload(cFrameType, *pStm))
{
GetISystem()->GetILog()->Log("NetDEBUG: ProcessPayload false");
return 0;
}
/////////////////////////////////////////
}
}
// manage timeouts
ProcessTimers();
// manage outgoing frames
if (m_qOutgoingData.empty() == false)
{
if (IsTimeToSend())
{
SendFrame();
}
}
return 1;
}
void CCCPEndpoint::SendSetup()
{
CCPSetup *pCCPSetup;
pCCPSetup = new CCPSetup;
ICVar *cl_password = GetISystem()->GetIConsole()->GetCVar("cl_password");
assert(cl_password);
if (cl_password->GetString())
{
pCCPSetup->m_sPlayerPassword = cl_password->GetString();
}
else
{
pCCPSetup->m_sPlayerPassword = "";
}
// Detect version 32/64bit.
#if defined(WIN64) || defined(LINUX64)
pCCPSetup->m_nClientFlags |= CLIENT_FLAGS_64BIT;
#endif
ICVar *cl_punkbuster = GetISystem()->GetIConsole()->GetCVar("cl_punkbuster");
if (cl_punkbuster && cl_punkbuster->GetIVal() != 0)
pCCPSetup->m_nClientFlags |= CLIENT_FLAGS_PUNK_BUSTER;
if (GetISystem()->WasInDevMode())
pCCPSetup->m_nClientFlags |= CLIENT_FLAGS_DEVMODE;
// Detect client OS.
#ifdef WIN32
OSVERSIONINFO OSVerInfo;
OSVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&OSVerInfo);
pCCPSetup->m_nClientOSMinor = OSVerInfo.dwMinorVersion;
pCCPSetup->m_nClientOSMajor = OSVerInfo.dwMajorVersion;
#endif
// pCCPSetup->m_cClientID = m_pParent->GetID();
m_qOutgoingData.push(pCCPSetup);
}
void CCCPEndpoint::SendConnect(CNPServerVariables &sv)
{
CCPConnect *pCCPConnect;
pCCPConnect = new CCPConnect;
// pCCPConnect->m_cClientID = m_pParent->GetID();
//pCCPConnect->m_cNewClientID = cClientID;
pCCPConnect->m_ServerVariables = sv;
pCCPConnect->m_cResponse = 0;
ICVar *pPunkBusterVar = GetISystem()->GetIConsole()->GetCVar("sv_punkbuster");
if (pPunkBusterVar && pPunkBusterVar->GetIVal() != 0)
{
pCCPConnect->m_cResponse |= SV_CONN_FLAG_PUNKBUSTER; // punkbuster!
}
if (GetISystem()->WasInDevMode())
{
pCCPConnect->m_cResponse |= SV_CONN_FLAG_DEVMODE;
}
m_qOutgoingData.push(pCCPConnect);
}
void CCCPEndpoint::SendConnectResp(CStream &stm)
{
CCPConnectResp *pCCPConnectResp;
pCCPConnectResp = new CCPConnectResp();
// pCCPConnectResp->m_cClientID = m_pParent->GetID();
pCCPConnectResp->m_cResponse = 0;//<<FIXME>> put something more useful
pCCPConnectResp->m_stmAuthorizationID = stm;
m_qOutgoingData.push(pCCPConnectResp);
}
void CCCPEndpoint::SendContextSetup(CStream &stm)
{
CCPContextSetup *pCCPContextSetup;
pCCPContextSetup = new CCPContextSetup;
// pCCPContextSetup->m_cClientID = m_pParent->GetID();
pCCPContextSetup->m_stmData = stm;
m_qOutgoingData.push(pCCPContextSetup);
}
void CCCPEndpoint::SendContextReady(CStream &stm)
{
CCPContextReady *pCCPContextReady;
pCCPContextReady = new CCPContextReady;
// pCCPContextReady->m_cClientID = m_pParent->GetID();
pCCPContextReady->m_stmData = stm;
m_qOutgoingData.push(pCCPContextReady);
}
void CCCPEndpoint::SendServerReady()
{
CCPServerReady *pCCPServerReady;
pCCPServerReady = new CCPServerReady;
// pCCPServerReady->m_cClientID = m_pParent->GetID();
m_qOutgoingData.push(pCCPServerReady);
}
void CCCPEndpoint::SendDisconnect(const char* szCause)
{
CStream stm;
CCPDisconnect *pCCPDisconnect;
pCCPDisconnect = new CCPDisconnect;
// pCCPDisconnect->m_cClientID = m_pParent->GetID();
pCCPDisconnect->m_sCause = szCause;
pCCPDisconnect->m_bSequenceNumber=0;
pCCPDisconnect->Save(stm);
//the disconnect packet is send ignoring the current state to
//increase the chances that the other endpoint will receive it
//the seq number is ignored by the receiver
m_pParent->Send(stm);
delete pCCPDisconnect;
//m_qOutgoingData.push(pCCPDisconnect);
}
//////////////////////////////////////////////////////////////////////////
void CCCPEndpoint::SendSecurityQuery(CStream &stm)
{
CCPSecurityQuery *pCCP = new CCPSecurityQuery;
pCCP->m_stmData = stm;
m_qOutgoingData.push(pCCP);
}
//////////////////////////////////////////////////////////////////////////
void CCCPEndpoint::SendSecurityResp(CStream &stm)
{
CCPSecurityResp *pCCP = new CCPSecurityResp;
pCCP->m_stmData = stm;
m_qOutgoingData.push(pCCP);
}
//////////////////////////////////////////////////////////////////////////
void CCCPEndpoint::SendPunkBusterMsg(CStream &stm)
{
CCPPunkBusterMsg *pCCP = new CCPPunkBusterMsg;
pCCP->m_stmData = stm;
m_qOutgoingData.push(pCCP);
}
//////////////////////////////////////////////////////////////////////////
void CCCPEndpoint::ProcessTimers()
{
if (m_ulTimeout)
if ((m_nCurrentTime - m_ulTimeout)>TM_BUFFER_TIMER)
{
m_ulTimeout = 0;
HandleTimeout();
}
}
void CCCPEndpoint::HandleTimeout()
{
NET_TRACE("[%08X]CCCPEndpoint::HandleTimeout()\n",::GetCurrentProcessId());
///bool b;
if(m_stmRetrasmissionBuffer.GetSize()==0)
{
CryError( "<CryNetworkut> (CCCPEndpoint::HandleTimeout) Empty retransmission buffer" );
}
m_stmRetrasmissionBuffer.Seek(0);
m_pParent->Send(m_stmRetrasmissionBuffer);
SetTimer();
}
void PrintPacket(CCPPayload ccpPayload)
{
switch(ccpPayload.m_cFrameType)
{
case FT_CCP_SETUP:
NET_TRACE("FT_CCP_SETUP\n");
break;
case FT_CCP_CONNECT:
NET_TRACE("FT_CCP_CONNECT\n");
break;
case FT_CCP_CONNECT_RESP:
NET_TRACE("FT_CCP_CONNECT_RESP\n");
break;
case FT_CCP_CONTEXT_SETUP:
NET_TRACE("FT_CCP_CONTEXT_SETUP\n");
break;
case FT_CCP_CONTEXT_READY:
NET_TRACE("FT_CCP_CONTEXT_READY\n");
break;
case FT_CCP_SERVER_READY:
NET_TRACE("FT_CCP_SERVER_READY\n");
break;
case FT_CCP_DISCONNECT:
NET_TRACE("FT_CCP_DISCONNECT\n");
break;
}
}
bool CCCPEndpoint::ProcessPayload(unsigned char cFrameType, CStream &stmStream)
{
CCPPayload ccpPayload;
ccpPayload.Load(stmStream);
stmStream.Seek(0);
//the disconnect packet is a destructive packet for the connection
//so seq number is ignored
if(cFrameType==FT_CCP_DISCONNECT)
{
GetISystem()->GetILog()->Log("NetDEBUG: FT_CCP_DISCONNECT");
CCPDisconnect ccpDisconnect;
ccpDisconnect.Load(stmStream);
m_pParent->OnCCPDisconnect(ccpDisconnect.m_sCause.c_str());
return 0;
}
else
{
if (ccpPayload.m_bSequenceNumber != m_bFrameExpected)
{
//SendAck(!m_bFrameExpected);
NET_TRACE("CCCPEndpoint::ProcessPayload Packet OUT OF SEQ[%02d]\n",ccpPayload.m_bSequenceNumber?1:0);
PrintPacket(ccpPayload);
}else
{
NET_TRACE("[%08X] IN [CCP] RECEIVED %02d \n",::GetCurrentProcessId(), ccpPayload.m_bSequenceNumber?1:0);
INC_BOOL(m_bFrameExpected);
NET_TRACE("[%08X] FRAME EXPECTED IS NOW [CCP] %02d \n",::GetCurrentProcessId(), m_bFrameExpected?1:0);
switch (cFrameType)
{
///////////////////////////////////////////////////
case FT_CCP_SETUP:
{
NET_TRACE("FT_CCP_SETUP\n");
m_pParent->OnCCPSetup(stmStream);
}
break;
///////////////////////////////////////////////////
case FT_CCP_CONNECT:
{
NET_TRACE("FT_CCP_CONNECT\n");
m_pParent->OnCCPConnect(stmStream);
}
break;
///////////////////////////////////////////////////
case FT_CCP_CONNECT_RESP:
{
NET_TRACE("FT_CCP_CONNECT_RESP\n");
CCPConnectResp ccpConnectResp;
ccpConnectResp.Load(stmStream);
m_pParent->OnCCPConnectResp(ccpConnectResp.m_stmAuthorizationID);
}
break;
case FT_CCP_CONTEXT_SETUP:
{
NET_TRACE("FT_CCP_CONTEXT_SETUP\n");
CCPContextSetup ccpContextSetup;
ccpContextSetup.Load(stmStream);
m_pParent->OnCCPContextSetup(ccpContextSetup.m_stmData);
}
break;
///////////////////////////////////////////////////
case FT_CCP_CONTEXT_READY:
{
NET_TRACE("FT_CCP_CONTEXT_READY\n");
CCPContextReady ccpContextReady;
ccpContextReady.Load(stmStream);
m_pParent->OnCCPContextReady(ccpContextReady.m_stmData);
}
break;
///////////////////////////////////////////////////
case FT_CCP_SERVER_READY:
{
NET_TRACE("FT_CCP_SERVER_READY\n");
CCPServerReady ccpServerReady;
ccpServerReady.Load(stmStream);
m_pParent->OnCCPServerReady();
}
break;
case FT_CCP_SECURITY_QUERY:
{
CCPSecurityQuery ccpSecurQuery;
ccpSecurQuery.Load(stmStream);
m_pParent->OnCCPSecurityQuery( ccpSecurQuery.m_stmData );
}
break;
case FT_CCP_SECURITY_RESP:
{
CCPSecurityQuery ccpSecurResp;
ccpSecurResp.Load(stmStream);
m_pParent->OnCCPSecurityResp( ccpSecurResp.m_stmData );
}
break;
case FT_CCP_PUNK_BUSTER_MSG:
{
CCPPunkBusterMsg ccpPBMsg;
ccpPBMsg.Load(stmStream);
m_pParent->OnCCPPunkBusterMsg( ccpPBMsg.m_stmData );
}
break;
///////////////////////////////////////////////////
/*case FT_CCP_DISCONNECT:
{
::OutputDebugString("FT_CCP_DISCONNECT\n");
CCPDisconnect ccpDisconnect;
ccpDisconnect.Load(stmStream);
m_pParent->OnCCPDisconnect(ccpDisconnect.m_sCause.c_str());
}
break;*/
///////////////////////////////////////////////////
default:
GetISystem()->GetILog()->Log("NetDEBUG: cFrameType %d",(int)cFrameType);
NET_ASSERT(0);
break;
///////////////////////////////////////////////////
}
SendAck(ccpPayload.m_bSequenceNumber);
}
}
return 1;
}
void CCCPEndpoint::EnableSend()
{
NET_TRACE("[%08X] SEND ENABLED\n",::GetCurrentProcessId());
m_bReadyToSend = true;
}
void CCCPEndpoint::DisableSend()
{
NET_TRACE("[%08X] SEND DISABLED\n",::GetCurrentProcessId());
m_bReadyToSend = false;
}
bool CCCPEndpoint::IsTimeToSend()
{
return m_bReadyToSend;
}
void CCCPEndpoint::SendFrame()
{
CStream stm;
CCPPayload *pCCPPayload;
pCCPPayload = m_qOutgoingData.front();
pCCPPayload->m_bSequenceNumber = m_bNextFrameToSend;
pCCPPayload->Save(stm);
m_qOutgoingData.pop();
m_stmRetrasmissionBuffer = stm;
m_pParent->Send(stm);
SetTimer();
NET_TRACE("[%08X] OUT [CCP] SENDING %02d \n",::GetCurrentProcessId(), pCCPPayload->m_bSequenceNumber?1:0);
delete pCCPPayload;
INC_BOOL(m_bNextFrameToSend);
INC_BOOL(m_bAckExpected);
DisableSend();
}
void CCCPEndpoint::SendAck(bool bSequenceNumber)
{
CStream stm;
CCPAck ccpAck;
ccpAck.m_bAck = bSequenceNumber;
// ccpAck.m_cClientID = m_pParent->GetID();
ccpAck.Save(stm);
////////////////////////
NET_TRACE("[%08X] OUT [CCP] ACK SEQ %02d\n",::GetCurrentProcessId(), ccpAck.m_bAck);
////////////////////////
m_pParent->Send(stm);
}
void CCCPEndpoint::GetMemoryStatistics(ICrySizer *pSizer)
{
pSizer->AddObject(&m_qOutgoingData,m_qOutgoingData.size()*sizeof(CStream));
}

92
CryNetwork/CCPEndpoint.h Normal file
View File

@@ -0,0 +1,92 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: CCPEndpoint.h
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#ifndef _CCPENDPOINT_H_
#define _CCPENDPOINT_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Stream.h"
#include "CNP.h"
#include "Interfaces.h"
#include <queue>
#define INC_BOOL(xxx) xxx=!(xxx)
#define TM_BUFFER_TIMER 1000
typedef std::queue<CCPPayload *> CCP_QUEUE;
class CCCPEndpoint
{
public:
//! constructor
CCCPEndpoint();
//! destructor
virtual ~CCCPEndpoint();
//!
void Init( _ICCPUser *pParent );
void SendDisconnect(const char* szCause);
void SendConnectResp(CStream &stm);
void SendContextSetup(CStream &stm);
void SendContextReady(CStream &stm);
void SendServerReady();
void SendConnect(CNPServerVariables &sv);
void SendSetup();
void SendPunkBusterMsg(CStream &stm);
void SendSecurityQuery(CStream &stm);
void SendSecurityResp(CStream &stm);
void SetPublicCryptKey( unsigned int nKey ) { m_nPublicKey = nKey; };
unsigned int GetPublicCryptKey( unsigned int nKey ) { return m_nPublicKey; };
//! @return true=disconnect and this pointer is destrozed, false otherwise
bool Update(unsigned int nTime,unsigned char cFrameType,CStream *pStm);
void Reset();
void GetMemoryStatistics(ICrySizer *pSizer);
protected:
//! @return true=disconnect and this pointer is destrozed, false otherwise
bool ProcessPayload(unsigned char cFrameType,CStream &stmStrea);
void HandleTimeout();
void ProcessTimers();
void SetTimer();
void StopTimer();
void SendFrame();
void EnableSend();
void DisableSend();
void SendAck(bool bSequenceNumber);
bool IsTimeToSend();
private: // --------------------------------------------------------------
bool m_bFrameExpected; //!<
bool m_bNextFrameToSend; //!<
bool m_bAckExpected; //!<
bool m_bReadyToSend; //!<
unsigned int m_ulTimeout; //!<
_ICCPUser * m_pParent; //!< pointer to the parent object (is not released), is 0 is you forgot to call Init()
CCP_QUEUE m_qOutgoingData; //!<
CStream m_stmRetrasmissionBuffer; //!<
unsigned int m_nCurrentTime; //!<
unsigned int m_nPublicKey;
};
#endif //_CCPENDPOINT_H_

762
CryNetwork/CNP.h Normal file
View File

@@ -0,0 +1,762 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: CNP.h
// Description: Crytek network protocol declarations
//
// History:
// * 7/25/2001 Created by Alberto Demichelis
// * 11/5/2003 MM cleaned up, documented
//
//////////////////////////////////////////////////////////////////////
#ifndef _CNP_H_
#define _CNP_H_
#define CNP_VERSION 0x02
// CCP = Crytek Control protocol
#define FT_CCP_SETUP 0x10
#define FT_CCP_CONNECT 0x20
#define FT_CCP_CONNECT_RESP 0x30
#define FT_CCP_DISCONNECT 0x40
#define FT_CCP_CONTEXT_SETUP 0x50
#define FT_CCP_CONTEXT_READY 0x60
#define FT_CCP_SERVER_READY 0x70
#define FT_CCP_ACK 0x80
#define FT_CCP_SECURITY_QUERY 0x90
#define FT_CCP_SECURITY_RESP 0x91
#define FT_CCP_PUNK_BUSTER_MSG 0x92
// CQP = Crytek Transport protocol
#define FT_CTP_DATA 0x01
#define FT_CTP_ACK 0x02
#define FT_CTP_NAK 0x03
#define FT_CTP_PONG 0x04
// CQP = Crytek Query protocol (serverlist queries, RCon system for server remote control)
#define FT_CQP_INFO_REQUEST 0xff // ask server about it's settings (for serverlist) or XML request.
#define FT_CQP_INFO_RESPONSE 0xff // respond server settings (for serverlist) or XML response.
#define FT_CQP_XML_REQUEST 0x15 // XML request to server.
#define FT_CQP_XML_RESPONSE 0x16 // XML response from server.
#define FT_CQP_RCON_COMMAND 0x13 // execute remote a command on a server
#define FT_CQP_RCON_RESPONSE 0x14 // get the response back from the server
#define IS_TRANSPORT_FRAME(a)((a)&0x0F)?1:0
#define IS_CONTROL_FRAME(a)((a)&0xF0)?1:0
#define MAX_REQUEST_XML_LENGTH 1024
// Available Client flags
enum EClientFlags
{
// This client running 64 bit version.
CLIENT_FLAGS_64BIT = (1 << 0),
// This client running with PunkBuster enabled.
CLIENT_FLAGS_PUNK_BUSTER = (1 << 1),
// This client is/has cheated
CLIENT_FLAGS_DEVMODE = (1 << 3),
};
///////////////////////////////////////////////////////////////
struct CNPServerVariables
{
void Save(CStream &stm)
{
stm.Write(nPublicKey);
stm.Write(nDataStreamTimeout);
}
void Load(CStream &stm)
{
stm.Read(nPublicKey);
stm.Read(nDataStreamTimeout);
}
unsigned int nDataStreamTimeout; //!< time elapsed without any data packet
unsigned int nPublicKey;
};
///////////////////////////////////////////////////////////////
struct CNP
{
CNP()
{
//m_cClientID = 0;
m_cFrameType = 0;
m_bSecondaryTC=false;
}
virtual ~CNP(){}
//BYTE m_cClientID;
BYTE m_cFrameType;
bool m_bSecondaryTC;
void Save(CStream &stm)
{
stm.WritePkd(m_cFrameType);
stm.Write(m_bSecondaryTC);
}
void Load(CStream &stm)
{
stm.ReadPkd(m_cFrameType);
stm.Read(m_bSecondaryTC);
}
void LoadAndSeekToZero(CStream &stm)
{
CNP::Load(stm);
//stm.Read(m_cFrameType);
stm.Seek(0);
}
};
///////////////////////////////////////////////////////////////
struct CTP :public CNP
{
CTP()
{
m_cSequenceNumber = 0;
m_cAck = 0;
m_bPingRequest = false;
m_bUnreliable = false;
}
virtual ~CTP(){}
BYTE m_cSequenceNumber;//<<FIXME>> will be 6 bits
BYTE m_cAck;//<<FIXME>> will be 6 bits
bool m_bPingRequest;
bool m_bUnreliable;
virtual void Save(CStream &stm)
{
CNP::Save(stm);
stm.WritePkd(m_cSequenceNumber);
stm.WritePkd(m_cAck);
stm.Write(m_bPingRequest);
stm.Write(m_bUnreliable);
}
virtual void Load(CStream &stm)
{
CNP::Load(stm);
stm.ReadPkd(m_cSequenceNumber);
stm.ReadPkd(m_cAck);
stm.Read(m_bPingRequest);
stm.Read(m_bUnreliable);
}
};
///////////////////////////////////////////////////////////////
struct CCP :public CNP
{
virtual ~CCP(){}
virtual void Save(CStream &stm)
{
CNP::Save(stm);
}
virtual void Load(CStream &stm)
{
CNP::Load(stm);
}
};
///////////////////////////////////////////////////////////////
// should be a byte aligned, so it can be manipulated by not-so-low level languages, like web languages (php, perl, ..)
// should always start with 4bytes 0x7f 0xff 0xff 0xff
// fist 10bits are CNP properties, wich are 0 11111111 1
// next 6bits are control bits, 111111
// and then two bytes 0xff 0xff
struct CQP :public CNP
{
CQP()
{
m_bSecondaryTC = true;
for (int i=0; i<6; i++)
m_bControlBits[i] = 0;
m_cControlBytes[0] = 0;
m_cControlBytes[1] = 0;
}
virtual ~CQP(){}
bool m_bControlBits[6]; // control bits, must be all 1
unsigned char m_cControlBytes[2]; // control bytes, must be all 0xff;
virtual void Save(CStream &stm)
{
CNP::Save(stm);
for(int i=0; i<6; i++) // write 6 control bits
stm.Write(true);
stm.Write((unsigned char)0xff); // write the two control bytes
stm.Write((unsigned char)0xff);
}
virtual void Load(CStream &stm)
{
CNP::Load(stm);
for(int i=0; i<6; i++)
{
if (stm.GetReadPos() < stm.GetSize())
stm.Read(m_bControlBits[i]);
else
return;
}
if (stm.GetSize()-stm.GetReadPos() >= 16)
{
stm.Read(m_cControlBytes[0]);
stm.Read(m_cControlBytes[1]);
}
}
bool IsOk()
{
for (int i=0; i < 6; i++)
{
if (!m_bControlBits[i])
return false;
}
return (m_cControlBytes[0] == 0xff) && (m_cControlBytes[0] == 0xff);
}
};
///////////////////////////////////////////////////////////////
struct CQPInfoRequest: public CQP
{
CQPInfoRequest() { m_cFrameType = FT_CQP_INFO_REQUEST; };
CQPInfoRequest(const string &szQuery): szRequest(szQuery) { m_cFrameType = FT_CQP_INFO_REQUEST; };
virtual ~CQPInfoRequest(){}
string szRequest;
virtual void Save(CStream &stm)
{
CQP::Save(stm);
// write every byte, because if we write the string, it will get compressed :(
for (uint32 i=0; i<szRequest.size(); i++)
stm.Write(szRequest[i]);
}
virtual void Load(CStream &stm)
{
szRequest.resize(0);
CQP::Load(stm);
while(stm.GetSize()-stm.GetReadPos() >= 8)
{
char cByte;
stm.Read(cByte);
szRequest.push_back(cByte);
}
}
};
///////////////////////////////////////////////////////////////
struct CQPInfoResponse :public CQP
{
CQPInfoResponse()
{
m_cFrameType = FT_CQP_INFO_RESPONSE;
}
virtual ~CQPInfoResponse(){}
string szResponse;
virtual void Save(CStream &stm)
{
CQP::Save(stm);
// write every byte, because if we write the string, it will get compressed :(
for (uint32 i=0; i<szResponse.size(); i++)
stm.Write(szResponse[i]);
}
virtual void Load(CStream &stm)
{
szResponse.resize(0);
CQP::Load(stm);
while(stm.GetSize()-stm.GetReadPos() >= 8)
{
char cByte;
stm.Read(cByte);
szResponse.push_back(cByte);
}
}
};
///////////////////////////////////////////////////////////////
struct CQPXMLRequest :public CQP
{
CQPXMLRequest()
{
m_cFrameType = FT_CQP_XML_REQUEST;
}
virtual ~CQPXMLRequest(){}
virtual void Save(CStream &stm)
{
CQP::Save(stm);
if (m_sXML.size() > MAX_REQUEST_XML_LENGTH)
m_sXML.resize(MAX_REQUEST_XML_LENGTH);
stm.Write(m_sXML.c_str());
}
virtual void Load(CStream &stm)
{
CQP::Load(stm);
static char sTemp[MAX_REQUEST_XML_LENGTH+1];
stm.Read( (char*)sTemp,sizeof(sTemp)-1 );
sTemp[sizeof(sTemp)-1] = 0;
m_sXML = sTemp;
}
string m_sXML;
};
///////////////////////////////////////////////////////////////
struct CQPXMLResponse :public CQP
{
CQPXMLResponse()
{
m_cFrameType = FT_CQP_XML_RESPONSE;
}
virtual ~CQPXMLResponse(){}
virtual void Save(CStream &stm)
{
CQP::Save(stm);
if (m_sXML.size() > MAX_REQUEST_XML_LENGTH)
m_sXML.resize(MAX_REQUEST_XML_LENGTH);
stm.Write(m_sXML.c_str());
}
virtual void Load(CStream &stm)
{
CQP::Load(stm);
static char sTemp[MAX_REQUEST_XML_LENGTH+1];
stm.Read( (char*)sTemp,sizeof(sTemp)-1 );
sTemp[sizeof(sTemp)-1] = 0;
m_sXML = sTemp;
}
string m_sXML;
};
///////////////////////////////////////////////////////////////
//! remote command to a server
struct CQPRConCommand :public CQP
{
CQPRConCommand()
{
m_cFrameType = FT_CQP_RCON_COMMAND;
}
virtual ~CQPRConCommand(){}
virtual void Save(CStream &stm)
{
CQP::Save(stm);
stm.WriteData( &m_nRConPasswordCode,16 );
stm.Write(m_sRConCommand.c_str());
}
virtual void Load(CStream &stm)
{
static char sTemp[512];
CQP::Load(stm);
stm.ReadData( &m_nRConPasswordCode,16 );
stm.Read((char *)sTemp,sizeof(sTemp)-1 );
sTemp[sizeof(sTemp)-1] = 0;
m_sRConCommand = sTemp;
}
unsigned int m_nRConPasswordCode[4];
string m_sRConCommand; //!<
};
///////////////////////////////////////////////////////////////
//! response from a server on a remote command
struct CQPRConResponse :public CQP
{
CQPRConResponse()
{
m_cFrameType = FT_CQP_RCON_RESPONSE;
}
virtual ~CQPRConResponse(){}
virtual void Save(CStream &stm)
{
CQP::Save(stm);
stm.Write(m_sText.c_str());
}
virtual void Load(CStream &stm)
{
static char sTemp[512];
CQP::Load(stm);
stm.Read((char *)sTemp,512);
m_sText = sTemp;
}
string m_sText; //!<
};
///////////////////////////////////////////////////////////////
struct CCPPayload :public CCP
{
CCPPayload(){
m_bSequenceNumber = 0;
}
virtual ~CCPPayload(){}
bool m_bSequenceNumber;
virtual void Save(CStream &stm)
{
CCP::Save(stm);
stm.Write(m_bSequenceNumber);
}
virtual void Load(CStream &stm)
{
CCP::Load(stm);
stm.Read(m_bSequenceNumber);
}
};
///////////////////////////////////////////////////////////////
struct CCPAck :public CCP
{
bool m_bAck;
CCPAck()
{
m_cFrameType = FT_CCP_ACK;
}
virtual ~CCPAck(){}
virtual void Save(CStream &stm)
{
CCP::Save(stm);
stm.Write(m_bAck);
}
virtual void Load(CStream &stm)
{
CCP::Load(stm);
stm.Read(m_bAck);
}
};
///////////////////////////////////////////////////////////////
struct CCPSetup :public CCPPayload
{
CCPSetup()
{
m_cFrameType = FT_CCP_SETUP;
m_cProtocolVersion = CNP_VERSION;
m_nClientFlags = 0;
m_nClientOSMinor = 0;
m_nClientOSMajor = 0;
}
virtual ~CCPSetup(){}
BYTE m_cProtocolVersion;
string m_sPlayerPassword;
// What version client is running.
unsigned int m_nClientFlags;
// What OS client is running.
unsigned int m_nClientOSMinor;
unsigned int m_nClientOSMajor;
//string m_sSpectatorPassword;
virtual void Save(CStream &stm)
{
CCPPayload::Save(stm);
stm.Write(m_cProtocolVersion);
stm.Write(m_sPlayerPassword.c_str());
stm.Write(m_nClientFlags);
stm.Write(m_nClientOSMinor);
stm.Write(m_nClientOSMajor);
//stm.Write(m_sSpectatorPassword.c_str());
}
virtual void Load(CStream &stm)
{
static char sTemp[512];
CCPPayload::Load(stm);
stm.Read(m_cProtocolVersion);
stm.Read((char *)sTemp,512);
m_sPlayerPassword = sTemp;
stm.Read(m_nClientFlags);
stm.Read(m_nClientOSMinor);
stm.Read(m_nClientOSMajor);
//stm.Read((char *)sTemp);
//m_sSpectatorPassword = sTemp;
}
};
///////////////////////////////////////////////////////////////
struct CCPConnect :public CCPPayload
{
CCPConnect()
{
m_cFrameType = FT_CCP_CONNECT;
m_cResponse = 0;
//m_cNewClientID = 0;
}
virtual ~CCPConnect(){}
BYTE m_cResponse; //!< bitflag to specify early information about the server! i.e. punkbuster or not..
// Random part of key used for encryption.
//BYTE m_cNewClientID;
// protocol variables
CNPServerVariables m_ServerVariables;
virtual void Save(CStream &stm)
{
CCPPayload::Save(stm);
stm.Write(m_cResponse);
//stm.Write(m_cNewClientID);
// protocol variables
m_ServerVariables.Save(stm);
}
virtual void Load(CStream &stm)
{
CCPPayload::Load(stm);
stm.Read(m_cResponse);
//stm.Read(m_cNewClientID);
// protocol variables
m_ServerVariables.Load(stm);
}
};
///////////////////////////////////////////////////////////////
struct CCPConnectResp :public CCPPayload
{
CCPConnectResp()
{
m_cFrameType = FT_CCP_CONNECT_RESP;
m_cResponse = 0;
}
virtual ~CCPConnectResp(){}
BYTE m_cResponse;
CStream m_stmAuthorizationID;
virtual void Save(CStream &stm)
{
unsigned int uiSize;
CCPPayload::Save(stm);
stm.Write(m_cResponse);
uiSize = m_stmAuthorizationID.GetSize();
stm.Write(uiSize);
stm.Write(m_stmAuthorizationID);
}
virtual void Load(CStream &stm)
{
unsigned int uiSize;
CCPPayload::Load(stm);
stm.Read(m_cResponse);
stm.Read(uiSize);
m_stmAuthorizationID.Reset();
m_stmAuthorizationID.SetSize(uiSize);
stm.ReadBits(m_stmAuthorizationID.GetPtr(),uiSize);
//stm.Read(m_stmAuthorizationID);
}
};
///////////////////////////////////////////////////////////////
struct CCPContextSetup:public CCPPayload
{
CCPContextSetup()
{
m_cFrameType = FT_CCP_CONTEXT_SETUP;
}
virtual ~CCPContextSetup(){}
CStream m_stmData;
virtual void Save(CStream &stm)
{
unsigned short usSize;
usSize = (unsigned short)m_stmData.GetSize();
CCPPayload::Save(stm);
stm.Write(usSize);
stm.Write(m_stmData);
}
virtual void Load(CStream &stm)
{
unsigned short usSize;
CCPPayload::Load(stm);
stm.Read(usSize);
m_stmData.Reset();
m_stmData.SetSize(usSize);
stm.ReadBits(m_stmData.GetPtr(), usSize);
}
};
///////////////////////////////////////////////////////////////
struct CCPContextReady :public CCPPayload
{
CCPContextReady()
{
m_cFrameType = FT_CCP_CONTEXT_READY;
}
virtual ~CCPContextReady(){}
CStream m_stmData;
virtual void Save(CStream &stm)
{
unsigned short usSize;
usSize = (unsigned short)m_stmData.GetSize();
CCPPayload::Save(stm);
stm.Write(usSize);
stm.Write(m_stmData);
}
virtual void Load(CStream &stm)
{
unsigned short usSize;
CCPPayload::Load(stm);
stm.Read(usSize);
m_stmData.Reset();
m_stmData.SetSize(usSize);
stm.ReadBits(m_stmData.GetPtr(), usSize);
};
};
///////////////////////////////////////////////////////////////
struct CCPServerReady :public CCPPayload
{
CCPServerReady()
{
m_cFrameType = FT_CCP_SERVER_READY;
}
virtual ~CCPServerReady(){}
virtual void Save(CStream &stm)
{
CCPPayload::Save(stm);
}
virtual void Load(CStream &stm)
{
CCPPayload::Load(stm);
}
};
///////////////////////////////////////////////////////////////
struct CCPDisconnect :public CCPPayload
{
CCPDisconnect()
{
m_cFrameType = FT_CCP_DISCONNECT;
}
virtual ~CCPDisconnect(){}
string m_sCause;
virtual void Save(CStream &stm)
{
CCPPayload::Save(stm);
stm.Write(m_sCause);
}
virtual void Load(CStream &stm)
{
CCPPayload::Load(stm);
stm.Read(m_sCause);
}
};
///////////////////////////////////////////////////////////////
struct CCPSecurityQuery :public CCPPayload
{
CCPSecurityQuery()
{
m_cFrameType = FT_CCP_SECURITY_QUERY;
}
virtual ~CCPSecurityQuery(){}
CStream m_stmData;
virtual void Save(CStream &stm)
{
unsigned short usSize;
usSize = (unsigned short)m_stmData.GetSize();
CCPPayload::Save(stm);
stm.Write(usSize);
stm.Write(m_stmData);
}
virtual void Load(CStream &stm)
{
unsigned short usSize;
CCPPayload::Load(stm);
stm.Read(usSize);
m_stmData.Reset();
m_stmData.SetSize(usSize);
stm.ReadBits(m_stmData.GetPtr(), usSize);
};
};
///////////////////////////////////////////////////////////////
struct CCPSecurityResp :public CCPSecurityQuery
{
CCPSecurityResp()
{
m_cFrameType = FT_CCP_SECURITY_RESP;
}
};
///////////////////////////////////////////////////////////////
struct CCPPunkBusterMsg :public CCPSecurityQuery
{
CCPPunkBusterMsg()
{
m_cFrameType = FT_CCP_PUNK_BUSTER_MSG;
}
};
///////////////////////////////////////////////////////////////
struct CTPData :public CTP
{
CTPData()
{
m_cFrameType = FT_CTP_DATA;
m_bCompressed = false;
m_nUncompressedSize = 0;
}
virtual ~CTPData(){}
CStream m_stmData;
bool m_bCompressed; // Compressed data.
unsigned short m_nUncompressedSize;
virtual void Save(CStream &stm)
{
unsigned short usSize;
usSize = (unsigned short)m_stmData.GetSize();
CTP::Save(stm);
stm.Write(m_bCompressed);
if (m_bCompressed)
stm.WritePkd(m_nUncompressedSize);
stm.WritePkd(usSize);
stm.Write(m_stmData);
}
virtual void Load(CStream &stm)
{
unsigned short usSize;
CTP::Load(stm);
stm.Read(m_bCompressed);
if (m_bCompressed)
stm.ReadPkd(m_nUncompressedSize);
stm.ReadPkd(usSize);
m_stmData.Reset();
m_stmData.SetSize(usSize);
stm.ReadBits(m_stmData.GetPtr(), usSize);
}
};
///////////////////////////////////////////////////////////////
struct CTPNak :public CTP
{
CTPNak()
{
m_cFrameType = FT_CTP_NAK;
}
virtual ~CTPNak(){}
virtual void Save(CStream &stm)
{
CTP::Save(stm);
}
virtual void Load(CStream &stm)
{
CTP::Load(stm);
}
};
///////////////////////////////////////////////////////////////
struct CTPAck :public CTP
{
CTPAck()
{
m_cFrameType = FT_CTP_ACK;
}
virtual ~CTPAck(){}
virtual void Save(CStream &stm)
{
CTP::Save(stm);
}
virtual void Load(CStream &stm)
{
CTP::Load(stm);
}
};
// this packet is unreliable(sequence number and ack are ignored)
struct CTPPong :public CTP
{
CTPPong()
{
m_cFrameType = FT_CTP_PONG;
m_nTimestamp = 0;
}
virtual ~CTPPong(){}
unsigned int m_nTimestamp;
virtual void Save(CStream &stm)
{
CTP::Save(stm);
stm.Write(m_nTimestamp);
}
virtual void Load(CStream &stm)
{
CTP::Load(stm);
stm.Read(m_nTimestamp);
}
};
///////////////////////////////////////////////////////////////
#endif //_CNP_H_

826
CryNetwork/CTPEndpoint.cpp Normal file
View File

@@ -0,0 +1,826 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: CTPEndpoint.cpp
// Description: non-sequential receive protocol
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CTPEndpoint.h"
#include "IDataProbe.h"
#ifdef _DEBUG
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
static bool Between(LONG a, LONG b, LONG c)
{
return ((a <= b) &&(b < c)) ||((c < a) &&(a <= b)) ||((b < c) &&(c < a));
}
//////////////////////////////////////////////////////////////////////
//! constructor!
CCTPEndpoint::CCTPEndpoint()
{
Reset();
SetRate(10000);
m_nSnaps = 20;
m_nEncryptKey[0] = 1714732178u;
m_nEncryptKey[1] = 2157124251u;
m_nEncryptKey[2] = 3766711231u;
m_nEncryptKey[3] = 715376114u;
}
//////////////////////////////////////////////////////////////////////
//! destructor!!
CCTPEndpoint::~CCTPEndpoint()
{
}
void CCTPEndpoint::SetPublicCryptKey( unsigned int key )
{
m_nEncryptKey[1] = key;
}
//////////////////////////////////////////////////////////////////////
//! set the average rate of the outgoing stream
void CCTPEndpoint::SetRate(unsigned int nBytePerSec)
{
m_nRate = nBytePerSec;
m_fBytePerMillisec = ((float)m_nRate)/1000.0f;
NET_TRACE("BYTES per MILLISEC=%f\n", m_fBytePerMillisec);
m_nAllowedBytes = m_nRate;
}
//////////////////////////////////////////////////////////////////////
//! set all varible to the initial state
void CCTPEndpoint::Reset()
{
//memset(m_nArrived, 0, sizeof(m_nArrived));
m_nFrameExpected = 0;
m_nNextFrameToSend = 0;
m_nTooFar = NUM_OF_BUFS;
m_bNoNak = true;
m_nAckExpected = 0;
m_nBuffered = 0;
m_nLostPackets = 0;
m_dwOutAckTimer = 0;
//memset(m_dwTimers, 0, sizeof(m_dwTimers));
for (int n = 0; n < NUM_OF_BUFS; n++)
{
m_OutBuffers[n].dwTimeout = 0;
m_OutBuffers[n].nSeq = 0;
m_nArrived[n]=false;
}
while (!m_qOutgoingReliableData.empty())
{
m_qOutgoingReliableData.pop();
}
while (!m_qOutgoingUnreliableData.empty())
{
m_qOutgoingUnreliableData.pop();
}
}
//////////////////////////////////////////////////////////////////////
//! called for every FT_DATA (CTPData)
void CCTPEndpoint::HandleDataFrame(CTPData &f)
{
CStream stmUncompressed;
if(f.m_bUnreliable)
{
////////////////////////////////////////////////////////////////////////////////////////////
//UNRELIABLE PACKET
////////////////////////////////////////////////////////////////////////////////////////////
//if the packet is out of sequence will be discarded
if(f.m_cSequenceNumber==m_nFrameExpected)
{
// CStream stmUncompressed=UncompressStream(f.m_stmData);
// m_pParent->OnData(stmUncompressed);
UncyptStream( f.m_stmData );
m_pParent->OnData(f.m_stmData);
}
else{
NET_TRACE("[%02d]expected-[%02d]received Packet discarded\n",m_nFrameExpected,f.m_cSequenceNumber);
}
}
else
{
////////////////////////////////////////////////////////////////////////////////////////////
//RELIABLE PACKET
////////////////////////////////////////////////////////////////////////////////////////////
// if there is a possible packet loss send a negative acknoledge (FT_NAK)
if ((f.m_cSequenceNumber != m_nFrameExpected) && m_bNoNak)
{
//<<FIXME>> re enable the following two lines to enable NAKs
NET_TRACE("NAK !!! f.m_cSequanceNumber=%02d m_nFrameExpected=%02d\n", f.m_cSequenceNumber, m_nFrameExpected);
SendFrame(FT_CTP_NAK, 0, m_nFrameExpected);
}
else
SetAckTimer();
if (Between(m_nFrameExpected, f.m_cSequenceNumber, m_nTooFar) &&(m_nArrived[f.m_cSequenceNumber%NUM_OF_BUFS] == false))
{
// FRAME ACCEPTED
NET_TRACE("FRAME ACCEPTED %02d\n",f.m_cSequenceNumber);
m_nArrived[f.m_cSequenceNumber%NUM_OF_BUFS] = true;
m_stmInBuffers[f.m_cSequenceNumber%NUM_OF_BUFS] = f.m_stmData;
while (m_nArrived[m_nFrameExpected%NUM_OF_BUFS])
{
NET_TRACE("ARRIVED %02d\n",m_nFrameExpected%NUM_OF_BUFS);
// CStream stmUncompressed=UncompressStream(m_stmInBuffers[m_nFrameExpected%NUM_OF_BUFS]);
// m_pParent->OnData(stmUncompressed);
UncyptStream( m_stmInBuffers[m_nFrameExpected%NUM_OF_BUFS] );
m_pParent->OnData(m_stmInBuffers[m_nFrameExpected%NUM_OF_BUFS]);
/////////////////////////////////////////////////
m_bNoNak = true;
m_nArrived[m_nFrameExpected%NUM_OF_BUFS] = false; // set buffer flag to false
NET_TRACE("m_nFrameExpected=%02d\n",m_nFrameExpected);
INC(m_nFrameExpected);
INC(m_nTooFar);
SetAckTimer();
}
}
else
{
NET_TRACE("received out of window frame (%d)\n",f.m_cSequenceNumber);
}
}
}
//////////////////////////////////////////////////////////////////////
//! called every incoming NAK (this code perform packet retrasmission)
void CCTPEndpoint::HandleNak(CTPNak &f)
{
if (Between(m_nAckExpected, (f.m_cAck + 1)%(MAX_SEQ_NUM + 1), m_nNextFrameToSend))
{
m_nLostPackets++;
SendFrame(FT_CTP_DATA, (f.m_cAck + 1)%(MAX_SEQ_NUM + 1), m_nNextFrameToSend);
}
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void CCTPEndpoint::Dump()
{
NET_TRACE("m_nTooFar=%d |||", m_nTooFar);
NET_TRACE("m_nFrameExpected=%d |||", m_nFrameExpected);
NET_TRACE("m_nBuffered=%d |||", m_nBuffered);
NET_TRACE("m_nAckExpected=%d |||", m_nAckExpected);
NET_TRACE("m_nNextFrameToSend=%d\n", m_nNextFrameToSend);
}
//////////////////////////////////////////////////////////////////////
//! main loop of the class
void CCTPEndpoint::Update(unsigned int nTime, unsigned char cFrameType, CStream *pStm)
{
m_nCurrentTime = nTime;
// if there is a incoming frame
CTP *pFrame = NULL;
CTPAck ack;
CTPData data;
CTPNak nak;
CTPPong pong;
if (cFrameType)
{
switch (cFrameType)
{
case FT_CTP_DATA:
{
data.Load(*pStm);
pFrame = &data;
HandleDataFrame(data);
}
break;
case FT_CTP_NAK:
{
nak.Load(*pStm);
pFrame = &nak;
HandleNak(nak);
}
break;
case FT_CTP_ACK:
{
pFrame = &ack;
ack.Load(*pStm);
}
break;
case FT_CTP_PONG:
{
pong.Load(*pStm);
m_LatencyCalculator.AddSample((float)m_nCurrentTime - m_dwPingTime, m_nCurrentTime, pong.m_nTimestamp);
}
break;
default:
NET_ASSERT(0);
break;
}
///////////////////////////////////////////////////////////
if (pFrame)
{
if (pFrame->m_bPingRequest == true)
{
CStream stm;
CTPPong pong;
// pong.m_cClientID = m_pParent->GetID();
pong.m_nTimestamp = m_nCurrentTime;
pong.Save(stm);
m_pParent->Send(stm);
}
///////////////////////////////////////////////////////////
// manage piggybacked ack (all frames hold a piggybacked ack)
NET_TRACE("--->>>[CTP] SEQ %02d ACK %02d\n", pFrame->m_cSequenceNumber, pFrame->m_cAck);
if(!pFrame->m_bUnreliable)
while (Between(m_nAckExpected, pFrame->m_cAck, m_nNextFrameToSend))
{
m_nBuffered = m_nBuffered - 1;
NET_TRACE("Ack [%02d] STOPPING TIMER m_nBuffered=%02d\n",pFrame->m_cAck,m_nBuffered);
StopTimer(m_nAckExpected%NUM_OF_BUFS);
INC(m_nAckExpected);
}
}
}
// handle outgoing buffer timers
ProcessBufferTimers();
// if there is some out-buffer free, I retrive some new data to send
// and if the network layer is ready(enough bandwith) ...send outgoing frames
if (IsTimeToSend())
{
BuildOutgoingFrame();
}
// handle ack timer
ProcessAckTimer();
}
//////////////////////////////////////////////////////////////////////
//! set the ack timer timeout
//! NOTE: if there aren't outgoing data packets for several time
//! the protocol will transmit an "ack dedicated" packet(FT_CTP_ACK)
//! this is the timer to guard this condition
void CCTPEndpoint::SetAckTimer()
{
if (m_dwOutAckTimer == 0)
m_dwOutAckTimer = m_nCurrentTime;
}
//////////////////////////////////////////////////////////////////////
//! stop the ack timer
void CCTPEndpoint::StopAckTimer()
{
m_dwOutAckTimer = 0;
}
//////////////////////////////////////////////////////////////////////
//! set packet retrasmisson timeout
void CCTPEndpoint::SetTimer(LONG nIndex)
{
// if(m_OutBuffers[nIndex].dwTimeout!=0)
// DEBUG_BREAK;
m_OutBuffers[nIndex].dwTimeout = m_nCurrentTime;
NET_TRACE("SETTIMER %02d %d\n",nIndex,m_nCurrentTime);
}
//////////////////////////////////////////////////////////////////////
//! stop packet retrasmisson timeout
void CCTPEndpoint::StopTimer(LONG nIndex)
{
DWORD nTimeout = m_OutBuffers[nIndex].dwTimeout;
m_OutBuffers[nIndex].dwTimeout=0;
// PING STUFF
// m_ulPingCounter+=m_nCurrentTime-m_OutBuffers[nIndex].dwTimeout;
// m_ulSamplesNum++;
// End of ping stuff
/*for (int n = 0; n < NUM_OF_BUFS; n++)
{
if (m_OutBuffers[n].dwTimeout <= nTimeout)
m_OutBuffers[n].dwTimeout = 0;
}*/
NET_TRACE("STOPTIMER %02d %d\n",nIndex,nTimeout);
}
void CCTPEndpoint::CryptStream( CStream &stm )
{
/*
IDataProbe *pProbe = GetISystem()->GetIDataProbe();
char temp[2048];
//int len = stm.
unsigned int* pBuffer = (unsigned int*)stm.GetPtr();
unsigned int destLen = 2048;
pProbe->Compress( temp,destLen,pBuffer,stm.GetSize()*8 );
int len = TEA_GETSIZE(stm.GetSize()*8);
//TEA_ENCODE( pBuffer,pBuffer,len,m_nEncryptKey );
CryLogAlways( "Stream Size: %.6d/%.6d",stm.GetSize()*8,destLen );
pProbe->Release();
*/
}
void CCTPEndpoint::UncyptStream( CStream &stm )
{
/*
unsigned int* pBuffer = (unsigned int*)stm.GetPtr();
int len = TEA_GETSIZE(stm.GetSize()*8);
//TEA_DECODE( pBuffer,pBuffer,len,m_nEncryptKey );
*/
}
//////////////////////////////////////////////////////////////////////
//! push a reliable stream in the outgoing queue
bool CCTPEndpoint::SendReliable(CStream &stmData)
{
//if(m_qOutgoingReliableData.size()>MAX_QUEUED_PACKET_PER_CHANNEL)
// return false;
CryptStream( stmData );
m_qOutgoingReliableData.push(stmData);
return true;
}
//////////////////////////////////////////////////////////////////////
//! push an UNreliable stream in the outgoing queue
bool CCTPEndpoint::SendUnreliable(CStream &stmData)
{
//if(m_qOutgoingUnreliableData.size()>MAX_QUEUED_PACKET_PER_CHANNEL)
// return false;
CryptStream( stmData );
m_qOutgoingUnreliableData.push(stmData);
return true;
}
/*
void MTFEncode(BYTE *pDest,BYTE *pSource,int nSize)
{
unsigned char order[ 256 ];
int i,c,count;
for ( i = 0 ; i < 256 ; i++ )
{
order[ i ] = (unsigned char) i;
}
for(count=0;count<nSize;count++)
{
c=pSource[count];
//
// Find the char, and output it
//
for ( i = 0 ; i < 256 ; i++ )
{
if ( order[ i ] == ( c & 0xff ) )
break;
}
//putc( (char) i, stdout );
pDest[count]=i;
//
// Now shuffle the order array
//
for ( int j = i ; j > 0 ; j-- )
{
order[ j ] = order[ j - 1 ];
}
order[ 0 ] = (unsigned char) c;
}
}
void MTFDecode(BYTE *pDest,BYTE *pSource,int nSize)
{
unsigned char order[ 256 ];
int i,c,count;
for ( i = 0 ; i < 256 ; i++ )
{
order[ i ] = (unsigned char) i;
}
for(count=0;count<nSize;count++)
{
i=pSource[count];
//
// Find the char
//
//putc( order[ i ], stdout );
pDest[count]=order[i];
c = order[ i ];
//
// Now shuffle the order array
//
int j;
for ( j = i ; j > 0 ; j-- )
{
order[ j ] = order[ j - 1 ];
}
order[ 0 ] = (unsigned char) c;
}
}
*/
/*
CStream CCTPEndpoint::CompressStream(CStream &stmUncompressed)
{
CStream stmCompressed;
#ifdef USE_PACKET_COMPRESSION
BYTE *pUncompressed=NULL;
pUncompressed=stmUncompressed.GetPtr();
unsigned short nUncompressedSizeInBits=stmUncompressed.GetSize();
unsigned short nUncompressedSize=BITS2BYTES(nUncompressedSizeInBits);
unsigned short n=0;
stmCompressed.Write(nUncompressedSizeInBits);
while(n<nUncompressedSize)
{
BYTE b;
b=pUncompressed[n];
if(b==0)
{
//write a 0
stmCompressed.Write(false);
}
else
{
//write a 1
stmCompressed.Write(true);
//write a byte
stmCompressed.Write(b);
}
n++;
}
#else
stmCompressed=stmUncompressed;
#endif
return stmCompressed;
}
CStream CCTPEndpoint::UncompressStream(CStream &stmCompressed)
{
CStream stmUncompressed;
#ifdef USE_PACKET_COMPRESSION
unsigned short nUncompressedSize;
stmUncompressed.Reset();
stmCompressed.Read(nUncompressedSize);
while(!stmCompressed.EOS())
{
bool bBit;
BYTE bData;
stmCompressed.Read(bBit);
if(bBit)
{
stmCompressed.Read(bData);
}
else
{
bData=0;
}
stmUncompressed.Write(bData);
if(stmUncompressed.GetSize()==nUncompressedSize)
break;
}
#else
stmUncompressed=stmCompressed;
#endif
return stmUncompressed;
}
*/
//////////////////////////////////////////////////////////////////////
//! format and send a frame(FT_DATA or FT_ACK or FT_NAK)
void CCTPEndpoint::SendFrame(LONG nType, LONG nFrameNum, LONG nFrameExpected, CStream *pUnreliable,bool bUnreliable)
{
// Dump();
CStream stmUncompressed;
static BYTE cUncompressed[1000];
CStream stm;
CTPData data;
CTPAck ack;
CTPNak nak;
CTP *pFrame;
switch (nType)
{
case FT_CTP_DATA:
pFrame = &data;
break;
case FT_CTP_ACK:
pFrame = &ack;
break;
case FT_CTP_NAK:
pFrame = &nak;
break;
default:
NET_ASSERT(0);
break;
}
// pFrame->m_cClientID = m_pParent->GetID();
pFrame->m_cFrameType =(BYTE) nType;
//////////////////////////////////////////////////////////////////
//DATA
//////////////////////////////////////////////////////////////////
if (nType == FT_CTP_DATA)
{
if(!bUnreliable)
{
stmUncompressed = m_OutBuffers[nFrameNum%NUM_OF_BUFS].stmData;
m_OutBuffers[nFrameNum%NUM_OF_BUFS].nSeq = nFrameNum;
if (pUnreliable)
{
if(pUnreliable->GetSize())
stmUncompressed.Write(*pUnreliable);
}
}
else
{
stmUncompressed=*pUnreliable;
}
//pack the stream with RLE
// data.m_stmData=CompressStream(stmUncompressed);
data.m_stmData=stmUncompressed;
}
//////////////////////////////////////////////////////////////////
//SEQ AND ACK
pFrame->m_bUnreliable = bUnreliable;
pFrame->m_cSequenceNumber =(BYTE) nFrameNum;
pFrame->m_cAck =(BYTE) (nFrameExpected + MAX_SEQ_NUM)%(MAX_SEQ_NUM + 1);
if(nType == FT_CTP_DATA)
{
NET_TRACE("SEND [CTP] %s FRAME SEQ [%02d] ACK [%02d] \n",pFrame->m_bUnreliable?"unreliable":"reliable",pFrame->m_cSequenceNumber,pFrame->m_cAck);
}
//////////////////////////////////////////////////////////////////
//NAK
if (nType == FT_CTP_NAK)
m_bNoNak = false;
//////////////////////////////////////////////////////////////////
//CHECK IF A PING REQUEST IS NEEDED
if (m_LatencyCalculator.IsTimeToPing(m_nCurrentTime))
{
m_dwPingTime = m_nCurrentTime;
// set a piggybacked pong request
pFrame->m_bPingRequest = true;
}
//////////////////////////////////////////////////////////////////
//SERIALIZE THE FRAME
pFrame->Save(stm);
m_pParent->Send(stm);
// Update the rate control
m_nAllowedBytes -= BITS2BYTES(stm.GetSize());
m_nLastPacketSent = m_nCurrentTime;
// NET_TRACE(">>m_nAllowedBytes=%d\n",m_nAllowedBytes);
//////////////////////////////////////////
if (nType == FT_CTP_DATA && (!bUnreliable))
SetTimer(nFrameNum%NUM_OF_BUFS);
if(!bUnreliable)
StopAckTimer();
}
//////////////////////////////////////////////////////////////////////
//! handle a buffer timeout (see SetTimer)
void CCTPEndpoint::HandleTimeout(LONG nOldestFrame)
{
NET_TRACE("HandleTimeout()\n");
m_nLostPackets++;
if (m_nBuffered)
SendFrame(FT_CTP_DATA, nOldestFrame, m_nFrameExpected);
}
//////////////////////////////////////////////////////////////////////
//! handle an ack timeout (see SetAckTimer)
void CCTPEndpoint::HandleAckTimeout()
{
NET_TRACE("HandleAckTimeout()\n");
SendFrame(FT_CTP_ACK, 0, m_nFrameExpected);
}
//////////////////////////////////////////////////////////////////////
//! check "the clock" for a possible buffers timer expiration
void CCTPEndpoint::ProcessBufferTimers()
{
unsigned int ulTick = m_nCurrentTime;
DWORD nLowest = 0xFFFFFFFF;
DWORD nLowestIdx;
bool bFound = false;
// search for the oldest timer
for (int n = 0; n < NUM_OF_BUFS; n++)
{
if ((m_OutBuffers[n].dwTimeout != 0) &&(m_OutBuffers[n].dwTimeout < nLowest))
{
bFound = true;
nLowest = m_OutBuffers[n].dwTimeout;
nLowestIdx = n;
}
}
// test the oldest timer
if (bFound)
{
if ((ulTick - nLowest)>(TM_BUFFER + m_LatencyCalculator.GetAverageLatency()))
{
/////////////////////////////////
m_OutBuffers[nLowestIdx].dwTimeout = 0;
HandleTimeout(m_OutBuffers[nLowestIdx].nSeq);
}
}
}
//////////////////////////////////////////////////////////////////////
//! check "the clock" for a possible ack timer expiration
void CCTPEndpoint::ProcessAckTimer()
{
// Process Ack timeout
unsigned int ulTick = m_nCurrentTime;
/////////////////////////////////
if (m_dwOutAckTimer)
{
if ((ulTick - m_dwOutAckTimer)>(TM_ACK + m_LatencyCalculator.GetAverageLatency()))
{
HandleAckTimeout();
m_dwOutAckTimer = 0;
}
}
}
unsigned int CCTPEndpoint::GetPing()
{
return (unsigned int)m_LatencyCalculator.GetAverageLatency();
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// Client logic
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//! return true if is time to send something
bool CCTPClient::IsTimeToSend()
{
static int dwTimer = 0;
// is there a free slot?
if (m_nBuffered < NUM_OF_BUFS)
{
return true;
/*if ((m_nCurrentTime - dwTimer)>30)
{
dwTimer = m_nCurrentTime;
return true;
}
return false; */
}
return false;
}
//////////////////////////////////////////////////////////////////////
//! build a data frame from the outgoing queue
void CCTPEndpoint::BuildOutgoingFrame()
{
if (m_qOutgoingReliableData.empty() == false || m_qOutgoingUnreliableData.empty() == false)
{
CStream stmUnreliable;
m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.Reset();
while ((m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.GetSize() < MAX_PLAYLOAD_SIZE_IN_BITS) && (!m_qOutgoingReliableData.empty()))
{
m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.Write(m_qOutgoingReliableData.front());
m_qOutgoingReliableData.pop();
}
while ((m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.GetSize() < MAX_PLAYLOAD_SIZE_IN_BITS) && (!m_qOutgoingUnreliableData.empty()))
{
stmUnreliable.Write(m_qOutgoingUnreliableData.front());
m_qOutgoingUnreliableData.pop();
}
//CHECK IF THERE IS RELIABLE DATA IN THE QUEUE
if(m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.GetSize()>0)
{
SendFrame(FT_CTP_DATA, m_nNextFrameToSend, m_nFrameExpected, &stmUnreliable,false);
INC(m_nNextFrameToSend);
m_nBuffered += 1;
NET_ASSERT(m_nBuffered<=NUM_OF_BUFS);
NET_TRACE("SEND RELIABLE m_nBuffered=%02d\n",m_nBuffered);
}
else
{
//IF THERE ISN'T RELIABLE DATA SEND A UNRELIABLE ONLY PACKET
//IF THERE IS UNRELIABLE DATA
if(stmUnreliable.GetSize()>0)
{
SendFrame(FT_CTP_DATA, m_nNextFrameToSend, m_nFrameExpected, &stmUnreliable,true);
NET_TRACE("SEND UNRELIABLE\n");
} }
}
//<<FIXME>> write some stuff to polulate a packet
//<<FIXME>> remember never put unreliable data in the retrasmission buffer(m_OutBuffer)
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// Server logic
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//! return true if is time to send something
//#define RATE_CONTROL
bool CCTPServer::IsTimeToSend()
{
#ifdef RATE_CONTROL
static dwTimer = 0;
m_nAllowedBytes += (int)((m_fBytePerMillisec)*(m_nCurrentTime - m_nLastPacketSent));
if (m_nAllowedBytes>(int)m_nRate)
m_nAllowedBytes =(int)m_nRate;
if (m_nAllowedBytes>((int)(m_nRate/m_nSnaps)))
{
return true;
}//<<FIXME>>
return false;
#else
static int dwTimer = 0;
// is there a free slot?
if (m_nBuffered < NUM_OF_BUFS)
{
return true;
/*if ((m_nCurrentTime - dwTimer)>30)
{
dwTimer = m_nCurrentTime;
return true;
}
return false; */
}
return false;
#endif
}
/*
//////////////////////////////////////////////////////////////////////
//! build a data frame from the outgoing queue
void CCTPServer::BuildOutgoingFrame()
{
if (m_qOutgoingReliableData.empty() == false || m_qOutgoingUnreliableData.empty() == false)
{
CStream stmUnreliable;
m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.Reset();
while ((m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.GetSize() < MAX_PLAYLOAD_SIZE_IN_BITS) && (!m_qOutgoingReliableData.empty()))
{
m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.Write(m_qOutgoingReliableData.front());
m_qOutgoingReliableData.pop();
}
while ((m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.GetSize() < MAX_PLAYLOAD_SIZE_IN_BITS) && (!m_qOutgoingUnreliableData.empty()))
{
stmUnreliable.Write(m_qOutgoingUnreliableData.front());
m_qOutgoingUnreliableData.pop();
}
//CHECK IF THERE IS RELIABLE DATA IN THE QUEUE
if(m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData.GetSize()>0)
{
SendFrame(FT_CTP_DATA, m_nNextFrameToSend, m_nFrameExpected, &stmUnreliable,false);
INC(m_nNextFrameToSend);
m_nBuffered += 1;
NET_ASSERT(m_nBuffered<=NUM_OF_BUFS);
NET_TRACE("SEND RELIABLE m_nBuffered=%02d\n",m_nBuffered);
}
else
{
//IF THERE ISN'T RELIABLE DATA SEND A UNRELIABLE ONLY PACKET
//IF THERE IS UNRELIABLE DATA
if(stmUnreliable.GetSize()>0)
{
SendFrame(FT_CTP_DATA, m_nNextFrameToSend, m_nFrameExpected, &stmUnreliable,true);
NET_TRACE("SEND UNRELIABLE\n");
}
}
}
//<<FIXME>> write some stuff to polulate a packet
//<<FIXME>> remember never put unreliable data in the retrasmission buffer(m_OutBuffer)
}
*/

150
CryNetwork/CTPEndpoint.h Normal file
View File

@@ -0,0 +1,150 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: CTPEndpoint.cpp
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_CTPENDPOINT_H__F28737F3_12B9_4394_B63C_7FC8CFFF3033__INCLUDED_)
#define AFX_CTPENDPOINT_H__F28737F3_12B9_4394_B63C_7FC8CFFF3033__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <queue>
#define MODULO32(a) ((a)&0x1f)
#define MAX_SEQ_NUM 7
#define NUM_OF_BUFS ((MAX_SEQ_NUM+1)/2)
#define INC(a) (a)=MODULO32((++a))
#define MAX_QUEUED_PACKET_PER_CHANNEL 24
//<<FIXME>> buffer timeout...replace with a ping adaptive algorithm
#define TM_BUFFER 300
#define TM_ACK TM_BUFFER/5
#define MAX_PLAYLOAD_SIZE_IN_BITS 1024*8
#include "Stream.h"
#include "CNP.h"
#include "Interfaces.h"
#include "PingCalculator.h"
typedef std::queue<CStream> STREAM_QUEUE;
typedef struct tagBuffer{
CStream stmData;
DWORD dwTimeout;
LONG nSeq;//only for retrasmission
}Buffer;
/*! Implements a CTP endpoint
*/
class CCTPEndpoint
{
public:
CCTPEndpoint();
virtual ~CCTPEndpoint();
public:
void Reset();
void Init(_IEndpointUser *pParent,bool bSecondary){m_pParent=pParent;m_bSecondary=bSecondary;}
bool SendUnreliable(CStream &stmData);
bool SendReliable(CStream &stmData);
void Update(unsigned int nTime,unsigned char cFrameType = 0,CStream *pStm=NULL);
void SetRate(unsigned int nBytePerSec);
void Dump();
unsigned int GetRemoteTimestamp(unsigned int nTime){
return m_LatencyCalculator.GetCurrentRemoteTimestamp(nTime);
}
//
unsigned int GetPing();
unsigned int GetLostPackets(){return m_nLostPackets;}
// Changes crypt key specifically for this connection.
void SetPublicCryptKey( unsigned int key );
protected:
virtual void BuildOutgoingFrame()=0;
virtual bool IsTimeToSend()=0;
void ProcessBufferTimers();
void ProcessAckTimer();
void HandleAckTimeout();
void HandleDataFrame(CTPData &f);
void HandleNak(CTPNak &f);
void HandleTimeout(LONG nOldestFrame);
void SendFrame(LONG nType,LONG nFrameNum,LONG nFrameExpected,CStream *pUnreliable = NULL,bool bUnreliable=false);
void StopTimer(LONG nIndex);
void SetTimer(LONG nIndex);
void StopAckTimer();
void SetAckTimer();
void CryptStream( CStream &stm );
void UncyptStream( CStream &stm );
// CStream CompressStream(CStream &stm);
// CStream UncompressStream(CStream &stm);
// ............................................................
bool m_nArrived[NUM_OF_BUFS];
LONG m_nFrameExpected;
LONG m_nNextFrameToSend;
LONG m_nTooFar;
LONG m_nAckExpected;
bool m_bNoNak; //!< only one nak per frame
LONG m_nBuffered; //!< number of output buffers currently used
CStream m_stmInBuffers[NUM_OF_BUFS];
Buffer m_OutBuffers[NUM_OF_BUFS];
LONG m_nOldestFrame;
//TIMERS=0 mean disabled
//DWORD m_dwTimers[NUM_OF_BUFS]; //expected ack timers
DWORD m_dwOutAckTimer; //!< outgoing ack timer
STREAM_QUEUE m_qOutgoingReliableData;
STREAM_QUEUE m_qOutgoingUnreliableData;
_IEndpointUser * m_pParent;
bool m_bSecondary;
class CPingCalculator m_LatencyCalculator; //!< Ping calculation stuff
DWORD m_nLostPackets;
DWORD m_dwPingTime; //!< store the timestamp of the latest pong request
//<<FIXME>> implement the rate control
unsigned int m_nRate;
float m_fBytePerMillisec; //!< only used when RATE_CONTROL is defined
int m_nAllowedBytes;
unsigned int m_nLastPacketSent;
protected:
unsigned int m_nSnaps;
unsigned int m_nCurrentTime;
// Encryption key used in Transfer protocol.
unsigned int m_nEncryptKey[4];
};
class CCTPClient :public CCTPEndpoint
{
protected:
// virtual void BuildOutgoingFrame();
virtual bool IsTimeToSend();
};
class CCTPServer :public CCTPEndpoint
{
public:
CCTPServer()
{
}
protected:
// virtual void BuildOutgoingFrame();
virtual bool IsTimeToSend();
};
#endif // !defined(AFX_CTPENDPOINT_H__F28737F3_12B9_4394_B63C_7FC8CFFF3033__INCLUDED_)

View File

@@ -0,0 +1,628 @@
#include "stdafx.h"
#include "ctpendpointgnb.h"
#include <IDataProbe.h>
#define PACKET_SIZE_COMPRESSION_LIMIT 100
CCTPEndpointGNB::CCTPEndpointGNB( CNetwork *pNetwork )
{
m_pNetwork = pNetwork;
Reset();
m_bCompress = true;
m_nEncryptKey[0] = 1282732178u;
m_nEncryptKey[1] = 1718763272u;
m_nEncryptKey[2] = 297614432u;
m_nEncryptKey[3] = 3389628651u;
}
CCTPEndpointGNB::~CCTPEndpointGNB(void)
{
}
void CCTPEndpointGNB::SetPublicCryptKey( unsigned int key )
{
m_nEncryptKey[2] = key;
}
static bool Between(LONG a, LONG b, LONG c)
{
return ((a <= b) &&(b < c)) ||((c < a) &&(a <= b)) ||((b < c) &&(c < a));
}
void CCTPEndpointGNB::Reset()
{
m_nFrameExpected=0;
m_nNextFrameToSend=0;
m_nAckExpected=0;
m_nBuffered=0; //number of output buffers currently used
m_nCurrentTime=0;
m_dwOutAckTimer=0;
m_dwPingTime=0;
m_nLostPackets=0;
m_nUnreliableLostPackets=0;
m_nBuffered=0;
for (long n = 0; n < NUM_OF_BUFS; n++)
{
m_OutBuffers[n].dwTimeout = 0;
m_OutBuffers[n].nSeq = 0;
// m_nArrived[n]=false;
}
while (!m_qOutgoingReliableData.empty())
{
m_qOutgoingReliableData.pop();
}
while (!m_qOutgoingUnreliableData.empty())
{
m_qOutgoingUnreliableData.pop();
}
}
//////////////////////////////////////////////////////////////////////////
void CCTPEndpointGNB::CryptPacket( CTPData &data )
{
// Write 1 bit of compressed packed info.
data.m_bCompressed = false;
CStream &stm = data.m_stmData;
unsigned int* pBuffer = (unsigned int*)stm.GetPtr();
unsigned int srclen = (stm.GetSize()+7)/8; // Always cover last byte.
unsigned int destlen = srclen;
// Try to compress big packets.
if (srclen > PACKET_SIZE_COMPRESSION_LIMIT && m_pNetwork->IsPacketCompressionEnabled())
{
BYTE temp[DEFAULT_STREAM_BYTESIZE*2];
destlen = sizeof(temp);
IDataProbe *pProbe = GetISystem()->GetIDataProbe();
pProbe->Compress( temp,destlen,pBuffer,srclen,1 );
if (destlen < srclen)
{
data.m_bCompressed = true;
data.m_nUncompressedSize = stm.GetSize(); // In bits.
TEA_ENCODE( (unsigned int*)temp,(unsigned int*)temp,TEA_GETSIZE(destlen),m_nEncryptKey );
stm.Reset();
stm.WriteBits(temp,destlen*8);
}
}
if (data.m_bCompressed)
{
//@TOOD: remove log.
float f1 = 100.0f/srclen;
float f2 = f1 * destlen;
int prc = (int)(100 - f2);
//if (m_pNetwork->GetLogLevel() > 1)
//CryLog( "<NET> PckSize Compressed: Was:%.3d Now:%.3d, Win: %.2d%%",srclen,destlen,prc );
}
else
{
int len = stm.GetSize()/8;
if (len >= 8)
{
TEA_ENCODE( pBuffer,pBuffer,TEA_GETSIZE(len),m_nEncryptKey );
}
}
}
//////////////////////////////////////////////////////////////////////////
void CCTPEndpointGNB::UncryptPacket( CTPData &data )
{
CStream &stm = data.m_stmData;
if (data.m_bCompressed)
{
// Compressed data packet.
BYTE temp[DEFAULT_STREAM_BYTESIZE*2];
unsigned int* pBuffer = (unsigned int*)stm.GetPtr();
int srclen = (stm.GetSize()+7)/8; // Always cover last byte.
TEA_DECODE( pBuffer,pBuffer,TEA_GETSIZE(srclen),m_nEncryptKey );
unsigned int destLen = sizeof(temp);
IDataProbe *pProbe = GetISystem()->GetIDataProbe();
pProbe->Uncompress( temp,destLen,pBuffer,srclen );
stm.Reset();
stm.WriteBits( temp,data.m_nUncompressedSize );
}
else
{
// Uncompressed data packet.
unsigned int* pBuffer = (unsigned int*)stm.GetPtr();
int len = stm.GetSize()/8;
if (len >= 8)
{
TEA_DECODE( pBuffer,pBuffer,TEA_GETSIZE(len),m_nEncryptKey );
}
}
}
bool CCTPEndpointGNB::SendUnreliable(CStream &stmData)
{
m_qOutgoingUnreliableData.push(stmData);
return true;
}
bool CCTPEndpointGNB::SendReliable(CStream &stmData)
{
m_qOutgoingReliableData.push(stmData);
return true;
}
void CCTPEndpointGNB::Update(unsigned int nTime,unsigned char cFrameType,CStream *pStm)
{
m_nCurrentTime = nTime;
CTP *pFrame = NULL;
CTPAck ack;
CTPData data;
CTPPong pong;
if (cFrameType)
{
switch (cFrameType)
{
case FT_CTP_DATA:
{
data.Load(*pStm);
pFrame = &data;
HandleDataFrame(data);
}
break;
case FT_CTP_ACK:
{
pFrame = &ack;
ack.Load(*pStm);
}
break;
case FT_CTP_PONG:
{
pong.Load(*pStm);
m_LatencyCalculator.AddSample((float)m_nCurrentTime - m_dwPingTime, m_nCurrentTime, pong.m_nTimestamp);
}
break;
default:
NET_ASSERT(0);
break;
}
///////////////////////////////////////////////////////////
if (pFrame)
{
if (pFrame->m_bPingRequest == true)
{
CStream stm;
CTPPong pong;
// pong.m_cClientID = m_pParent->GetID();
pong.m_nTimestamp = m_nCurrentTime;
pong.Save(stm);
m_pParent->Send(stm);
}
///////////////////////////////////////////////////////////
// manage piggybacked ack (all frames hold a piggybacked ack)
NET_TRACE("--->>>[CTP] SEQ %02d ACK %02d\n", pFrame->m_cSequenceNumber, pFrame->m_cAck);
if(!pFrame->m_bUnreliable)
while (Between(m_nAckExpected, pFrame->m_cAck, m_nNextFrameToSend))
{
m_nBuffered = m_nBuffered - 1;
NET_TRACE("Ack [%02d] STOPPING TIMER m_nBuffered=%02d\n",pFrame->m_cAck,m_nBuffered);
StopTimer(m_nAckExpected%NUM_OF_BUFS);
INC(m_nAckExpected);
}
}
}
// handle outgoing buffer timers
ProcessBufferTimers();
// if there is some out-buffer free, I retrive some new data to send
// and if the network layer is ready(enough bandwith) ...send outgoing frames
if (IsTimeToSend())
{
BuildOutgoingFrame();
}
// handle ack timer
ProcessAckTimer();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CCTPEndpointGNB::SetRate(unsigned int nBytePerSec)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CCTPEndpointGNB::Dump()
{
NET_TRACE("m_nFrameExpected=%d |||", m_nFrameExpected);
NET_TRACE("m_nBuffered=%d |||", m_nBuffered);
NET_TRACE("m_nAckExpected=%d |||", m_nAckExpected);
NET_TRACE("m_nNextFrameToSend=%d\n", m_nNextFrameToSend);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned int CCTPEndpointGNB::GetPing()
{
return (unsigned int)m_LatencyCalculator.GetAverageLatency();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CCTPEndpointGNB::HandleDataFrame(CTPData &f)
{
CStream stmUncompressed;
if(f.m_bUnreliable)
{
////////////////////////////////////////////////////////////////////////////////////////////
//UNRELIABLE PACKET
////////////////////////////////////////////////////////////////////////////////////////////
//if the packet is out of sequence will be discarded
if(f.m_cSequenceNumber==m_nFrameExpected)
{
// CStream stmUncompressed=UncompressStream(f.m_stmData);
// m_pParent->OnData(stmUncompressed);
UncryptPacket( f );
m_pParent->OnData( f.m_stmData );
}
else
{
m_nUnreliableLostPackets++;
NET_TRACE("[%02d]expected-[%02d]received Packet discarded\n",m_nFrameExpected,f.m_cSequenceNumber);
}
}
else
{
////////////////////////////////////////////////////////////////////////////////////////////
//RELIABLE PACKET
////////////////////////////////////////////////////////////////////////////////////////////
if(f.m_cSequenceNumber==m_nFrameExpected)
{
// CStream stmUncompressed=UncompressStream(f.m_stmData);
// m_pParent->OnData(stmUncompressed);
//UncryptStream( f.m_stmData );
//m_pParent->OnData(f.m_stmData);
UncryptPacket( f );
m_pParent->OnData( f.m_stmData );
INC(m_nFrameExpected);
SetAckTimer();
}
else
{
SetAckTimer();
NET_TRACE("[%02d]expected-[%02d]received Packet discarded\n",m_nFrameExpected,f.m_cSequenceNumber);
}
while(Between(m_nAckExpected,f.m_cAck,m_nNextFrameToSend))
{
m_nBuffered=m_nBuffered-1;
StopTimer(m_nAckExpected%NUM_OF_BUFS);
INC(m_nAckExpected);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CCTPEndpointGNB::ProcessBufferTimers()
{
unsigned int ulTick = m_nCurrentTime;
DWORD nLowest = 0xFFFFFFFF;
DWORD nLowestIdx;
bool bFound = false;
// search for the oldest timer
for (long n = 0; n < NUM_OF_BUFS; n++)
{
if ((m_OutBuffers[n].dwTimeout != 0) &&(m_OutBuffers[n].dwTimeout < nLowest))
{
bFound = true;
nLowest = m_OutBuffers[n].dwTimeout;
nLowestIdx = n;
}
}
// test the oldest timer
if (bFound)
{
/* if ((ulTick - nLowest)>(TM_BUFFER + m_LatencyCalculator.GetAverageLatency()))
{
/////////////////////////////////
m_OutBuffers[nLowestIdx].dwTimeout = 0;
HandleTimeout(m_OutBuffers[nLowestIdx].nSeq);
}
}*/
DWORD dwTO=TM_BUFFER + (DWORD)(m_LatencyCalculator.GetAverageLatency());
for (int n = 0; n < NUM_OF_BUFS; n++)
{
if((m_OutBuffers[nLowestIdx].dwTimeout!=0) && ((ulTick-m_OutBuffers[nLowestIdx].dwTimeout)>dwTO))
{
m_OutBuffers[nLowestIdx].dwTimeout = 0;
HandleTimeout(m_OutBuffers[nLowestIdx].nSeq);
}
nLowestIdx=(nLowestIdx+1)%NUM_OF_BUFS;
}
}
}
void CCTPEndpointGNB::ProcessAckTimer()
{
// Process Ack timeout
unsigned int ulTick = m_nCurrentTime;
/////////////////////////////////
if (m_dwOutAckTimer)
{
if ((ulTick - m_dwOutAckTimer)>(TM_ACK + m_LatencyCalculator.GetAverageLatency()))
{
HandleAckTimeout();
m_dwOutAckTimer = 0;
}
}
}
bool CCTPEndpointGNB::IsTimeToSend()
{
if (m_nBuffered < NUM_OF_BUFS)
{
return true;
}
return false;
}
void CCTPEndpointGNB::HandleAckTimeout()
{
NET_TRACE("HandleAckTimeout()\n");
SendFrame(FT_CTP_ACK, 0, m_nFrameExpected);
}
void CCTPEndpointGNB::HandleTimeout(LONG nOldestFrame)
{
NET_TRACE("HandleTimeout()\n");
m_nLostPackets++;
if (m_nBuffered)
SendFrame(FT_CTP_DATA, nOldestFrame, m_nFrameExpected);
}
/*
CStream CCTPEndpointGNB::CompressStream(CStream &stmUncompressed)
{
CStream stmCompressed;
#ifdef USE_PACKET_COMPRESSION
if(m_bCompress)
{
BYTE *pUncompressed=NULL;
pUncompressed=stmUncompressed.GetPtr();
unsigned short nUncompressedSizeInBits=(unsigned short)stmUncompressed.GetSize();
unsigned short nUncompressedSize=BITS2BYTES(nUncompressedSizeInBits);
unsigned short n=0;
stmCompressed.Write(true);
stmCompressed.Write(nUncompressedSizeInBits);
while(n<nUncompressedSize)
{
BYTE b;
b=pUncompressed[n];
if(b==0)
{
//write a 0
stmCompressed.Write(false);
}
else
{
//write a 1
stmCompressed.Write(true);
//write a byte
stmCompressed.Write(b);
}
n++;
}
}
else
{
stmCompressed.Write(false);
stmCompressed.WriteBits(stmUncompressed.GetPtr(),stmUncompressed.GetSize());
}
#else
stmCompressed=stmUncompressed;
#endif
return stmCompressed;
}
CStream CCTPEndpointGNB::UncompressStream(CStream &stmCompressed)
{
CStream stmUncompressed;
#ifdef USE_PACKET_COMPRESSION
unsigned short nUncompressedSize;
stmUncompressed.Reset();
bool bIsCompressed;
stmCompressed.Read(bIsCompressed);
if(bIsCompressed){
stmCompressed.Read(nUncompressedSize);
while(!stmCompressed.EOS())
{
bool bBit;
BYTE bData;
stmCompressed.Read(bBit);
if(bBit)
{
stmCompressed.Read(bData);
}
else
{
bData=0;
}
stmUncompressed.Write(bData);
if(stmUncompressed.GetSize()==nUncompressedSize)
break;
}
}
else
{
stmCompressed.Read(stmUncompressed);
}
#else
stmUncompressed=stmCompressed;
#endif
return stmUncompressed;
}
*/
void CCTPEndpointGNB::SendFrame(LONG nType, LONG nFrameNum, LONG nFrameExpected, CStream *pUnreliable,bool bUnreliable)
{
static BYTE cUncompressed[1000];
CTPData data;
CTPAck ack;
CTPNak nak;
CTP *pFrame;
switch (nType)
{
case FT_CTP_DATA:
pFrame = &data;
break;
case FT_CTP_ACK:
pFrame = &ack;
break;
default:
NET_ASSERT(0);
break;
}
pFrame->m_cFrameType=(BYTE)nType;
pFrame->m_bSecondaryTC=m_bSecondary;
//////////////////////////////////////////////////////////////////
//DATA
//////////////////////////////////////////////////////////////////
if (nType == FT_CTP_DATA)
{
if(!bUnreliable)
{
data.m_stmData = m_OutBuffers[nFrameNum%NUM_OF_BUFS].stmData;
m_OutBuffers[nFrameNum%NUM_OF_BUFS].nSeq = nFrameNum;
if (pUnreliable)
{
if(pUnreliable->GetSize())
data.m_stmData.Write(*pUnreliable);
}
}
else
{
data.m_stmData = *pUnreliable;
}
CryptPacket( data );
}
//////////////////////////////////////////////////////////////////
//SEQ AND ACK
pFrame->m_bUnreliable = bUnreliable;
pFrame->m_cSequenceNumber =(BYTE) nFrameNum;
pFrame->m_cAck =(BYTE) (nFrameExpected + MAX_SEQ_NUM)%(MAX_SEQ_NUM + 1);
if(nType == FT_CTP_DATA)
{
NET_TRACE("SEND [CTP] %s FRAME SEQ [%02d] ACK [%02d] \n",pFrame->m_bUnreliable?"unreliable":"reliable",pFrame->m_cSequenceNumber,pFrame->m_cAck);
}
//////////////////////////////////////////////////////////////////
//CHECK IF A PING REQUEST IS NEEDED
if ((!m_bSecondary) && m_LatencyCalculator.IsTimeToPing(m_nCurrentTime))
{
m_dwPingTime = m_nCurrentTime;
// set a piggybacked pong request
pFrame->m_bPingRequest = true;
}
//////////////////////////////////////////////////////////////////
//SERIALIZE THE FRAME
CStream stm;
pFrame->Save(stm);
m_pParent->Send(stm);
// Update the rate control
m_nAllowedBytes -= BITS2BYTES(stm.GetSize());
m_nLastPacketSent = m_nCurrentTime;
// NET_TRACE(">>m_nAllowedBytes=%d\n",m_nAllowedBytes);
//////////////////////////////////////////
if (nType == FT_CTP_DATA && (!bUnreliable))
SetTimer(nFrameNum%NUM_OF_BUFS);
if(!bUnreliable)
StopAckTimer();
}
void CCTPEndpointGNB::SetAckTimer()
{
if (m_dwOutAckTimer == 0)
m_dwOutAckTimer = m_nCurrentTime;
}
//////////////////////////////////////////////////////////////////////
//! stop the ack timer
void CCTPEndpointGNB::StopAckTimer()
{
m_dwOutAckTimer = 0;
}
//////////////////////////////////////////////////////////////////////
//! set packet retrasmisson timeout
void CCTPEndpointGNB::SetTimer(LONG nIndex)
{
m_OutBuffers[nIndex].dwTimeout = m_nCurrentTime;
NET_TRACE("SETTIMER %02d %d\n",nIndex,m_nCurrentTime);
}
//////////////////////////////////////////////////////////////////////
//! stop packet retrasmisson timeout
void CCTPEndpointGNB::StopTimer(LONG nIndex)
{
DWORD nTimeout = m_OutBuffers[nIndex].dwTimeout;
m_OutBuffers[nIndex].dwTimeout=0;
NET_TRACE("STOPTIMER %02d %d\n",nIndex,nTimeout);
}
void CCTPEndpointGNB::BuildOutgoingFrame()
{
if (m_qOutgoingReliableData.empty() == false || m_qOutgoingUnreliableData.empty() == false)
{
CStream stmUnreliable;
CStream &stm=m_OutBuffers[m_nNextFrameToSend%NUM_OF_BUFS].stmData;
stm.Reset();
while ((!m_qOutgoingReliableData.empty())
&& ((stm.GetSize() + m_qOutgoingReliableData.front().GetSize()) < MAX_PLAYLOAD_SIZE_IN_BITS))
{
stm.Write(m_qOutgoingReliableData.front());
m_qOutgoingReliableData.pop();
}
while ((!m_qOutgoingUnreliableData.empty())
&& ((stm.GetSize() + m_qOutgoingUnreliableData.front().GetSize()) < MAX_PLAYLOAD_SIZE_IN_BITS))
{
stmUnreliable.Write(m_qOutgoingUnreliableData.front());
m_qOutgoingUnreliableData.pop();
}
//CHECK IF THERE IS RELIABLE DATA IN THE QUEUE
if(stm.GetSize()>0)
{
SendFrame(FT_CTP_DATA, m_nNextFrameToSend, m_nFrameExpected, &stmUnreliable,false);
INC(m_nNextFrameToSend);
m_nBuffered += 1;
NET_ASSERT(m_nBuffered<=NUM_OF_BUFS);
NET_TRACE("SEND RELIABLE m_nBuffered=%02d\n",m_nBuffered);
}
else
{
//IF THERE ISN'T RELIABLE DATA SEND A UNRELIABLE ONLY PACKET
//IF THERE IS UNRELIABLE DATA
if(stmUnreliable.GetSize()>0)
{
SendFrame(FT_CTP_DATA, m_nNextFrameToSend, m_nFrameExpected, &stmUnreliable,true);
NET_TRACE("SEND UNRELIABLE\n");
}
}
}
}
void CCTPEndpointGNB::GetMemoryStatistics(ICrySizer *pSizer)
{
pSizer->AddObject(&m_qOutgoingReliableData,m_qOutgoingReliableData.size()*sizeof(CStream));
pSizer->AddObject(&m_qOutgoingUnreliableData,m_qOutgoingUnreliableData.size()*sizeof(CStream));
}

105
CryNetwork/CTPEndpointGNB.h Normal file
View File

@@ -0,0 +1,105 @@
#ifndef _CTP_ENDPOINT_GNB_
#define _CTP_ENDPOINT_GNB_
#include "Stream.h"
#include "CNP.h"
#include "Interfaces.h"
#include "PingCalculator.h"
#include "Network.h"
#define MODULO32(a) ((a)&0x1f)
#define MAX_SEQ_NUM 31
#define NUM_OF_BUFS ((MAX_SEQ_NUM+1)/2)
#define INC(a) (a)=MODULO32((++a))
#define MAX_QUEUED_PACKET_PER_CHANNEL 24
//<<FIXME>> buffer timeout...replace with a ping adaptive algorithm
#define TM_BUFFER 600
#define TM_ACK TM_BUFFER/5
#define MAX_PLAYLOAD_SIZE_IN_BITS 1024*8
#include <queue>
typedef struct tagBuffer{
CStream stmData;
DWORD dwTimeout;
LONG nSeq;//only for retrasmission
}Buffer;
typedef std::queue<CStream> STREAM_QUEUE;
class CCTPEndpointGNB
{
public:
CCTPEndpointGNB( CNetwork *pNetwork );
virtual ~CCTPEndpointGNB(void);
void Reset();
void Init(_IEndpointUser *pParent,bool bSecondary){m_pParent=pParent;m_bSecondary=bSecondary;}
bool SendUnreliable(CStream &stmData);
bool SendReliable(CStream &stmData);
void Update(unsigned int nTime,unsigned char cFrameType = 0,CStream *pStm=NULL);
void SetRate(unsigned int nBytePerSec);
void Dump();
unsigned int GetRemoteTimestamp(unsigned int nTime){
return m_LatencyCalculator.GetCurrentRemoteTimestamp(nTime);
}
void GetMemoryStatistics(ICrySizer *pSizer);
//
unsigned int GetPing();
unsigned int GetLostPackets(){return m_nLostPackets;}
unsigned int GetUnreliableLostPackets(){return m_nUnreliableLostPackets;}
void EnableCompression(bool bEnable){m_bCompress=bEnable;}
// Changes crypt key specifically for this connection.
void SetPublicCryptKey( unsigned int key );
protected:
virtual void BuildOutgoingFrame();
virtual bool IsTimeToSend();
private:
// CStream CompressStream(CStream &stmUncompressed);
// CStream UncompressStream(CStream &stmCompressed);
void ProcessBufferTimers();
void ProcessAckTimer();
void HandleAckTimeout();
void HandleDataFrame(CTPData &f);
void HandleTimeout(LONG nOldestFrame);
void SendFrame(LONG nType,LONG nFrameNum,LONG nFrameExpected,CStream *pUnreliable = NULL,bool bUnreliable=false);
void StopTimer(LONG nIndex);
void SetTimer(LONG nIndex);
void StopAckTimer();
void SetAckTimer();
void CryptPacket( CTPData &data );
void UncryptPacket( CTPData &data );
//////////////////////////////////////
CNetwork *m_pNetwork;
_IEndpointUser *m_pParent;
bool m_bSecondary;
Buffer m_OutBuffers[NUM_OF_BUFS];
STREAM_QUEUE m_qOutgoingReliableData;
STREAM_QUEUE m_qOutgoingUnreliableData;
//protocol
DWORD m_nFrameExpected;
DWORD m_nNextFrameToSend;
DWORD m_nAckExpected;
DWORD m_nBuffered; //number of output buffers currently used
DWORD m_dwOutAckTimer;
DWORD m_dwPingTime;
DWORD m_nAllowedBytes;
DWORD m_nLastPacketSent;
DWORD m_nLostPackets;
DWORD m_nUnreliableLostPackets;
unsigned int m_nCurrentTime;
CPingCalculator m_LatencyCalculator;
bool m_bCompress;
// Encryption key used in Transfer protocol.
unsigned int m_nEncryptKey[4];
};
#endif //_CTP_ENDPOINT_GNB_

583
CryNetwork/Client.cpp Normal file
View File

@@ -0,0 +1,583 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: Client.cpp
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Client.h"
#include "CNP.h"
#include "IGame.h"
#include "IScriptSystem.h"
#ifndef NOT_USE_UBICOM_SDK
#include "UbiSoftMemory.h" // GS_WIN32
#include "cdkeydefines.h" // UBI.com AUTHORIZATION_ID_SIZE
#include "NewUbisoftClient.h" // NewUbisoftClient
#else
#define AUTHORIZATION_ID_SIZE 20
#endif // NOT_USE_UBICOM_SDK
#if defined(_DEBUG) && !defined(LINUX)
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CClient::CClient( CNetwork *pNetwork )
: m_ctpEndpoint(pNetwork), m_ctpEndpoint2(pNetwork),
cl_timeout(0), m_pbAuthorizationID(NULL), m_uiAuthorizationSize(0), m_bWaiting(0)
{
m_pNetwork = pNetwork;
m_ccpEndpoint.Init(this);
m_smCCPMachine.Init(this);
}
CClient::~CClient()
{
m_pNetwork->UnregisterClient(this);
m_pSink=NULL;
if (m_pbAuthorizationID)
delete [] m_pbAuthorizationID;
}
bool CClient::Init(IClientSink *pSink)
{
m_pSink=pSink;
if(NET_FAILED(m_socketMain.Create()))return false;
if(NET_FAILED(m_socketMain.Listen(0)))return false;
m_ctpEndpoint.Init(this,false);
m_ctpEndpoint2.Init(this,true);
m_ccpEndpoint.Init(this);
m_dwKeepAliveTimer=0;
cl_timeout = GetISystem()->GetIConsole()->GetCVar("cl_timeout");
return true;
}
//////////////////////////////////////////////////////////////////////
// _IClientServices
//////////////////////////////////////////////////////////////////////
#if (defined(PS2) || defined(LINUX))
#define FAILED(value) (((unsigned int)(value))&0x80000000)
#endif
#ifdef _INTERNET_SIMULATOR
#include <stdlib.h>
#if !defined(LINUX)
#include <assert.h>
#endif
#include "IConsole.h"
#include "ITimer.h"
#endif
bool CClient::SendTo( CIPAddress &ip,CStream &stm )
{
if(FAILED(m_socketMain.Send(stm.GetPtr(),BITS2BYTES(stm.GetSize()),&ip)))
return false;
return true;
}
bool CClient::Send(CStream &stm)
{
#ifndef _INTERNET_SIMULATOR
if(FAILED(m_socketMain.Send(stm.GetPtr(),BITS2BYTES(stm.GetSize()),&m_ipServer)))return false;
return true;
#else
static ICVar *pVarPacketloss=GetISystem()->GetIConsole()->GetCVar("g_internet_simulator_packetloss");
static ICVar *pVarMinPing=GetISystem()->GetIConsole()->GetCVar("g_internet_simulator_minping");
static ICVar *pVarMaxPing=GetISystem()->GetIConsole()->GetCVar("g_internet_simulator_maxping");
int iMaxPing=pVarMinPing->GetIVal();
int iMinPing=pVarMaxPing->GetIVal();
if(iMinPing>iMaxPing)
iMaxPing=iMinPing;
if (pVarPacketloss->GetFVal()>0 || iMaxPing>0)
{
DelayedPacket *delayed = new DelayedPacket;
if(iMaxPing>0)
delayed->m_fTimeToSend = GetISystem()->GetITimer()->GetCurrTime() + iMinPing + (rand() % (iMaxPing-iMinPing)) / 1000.0f;
else
delayed->m_fTimeToSend = GetISystem()->GetITimer()->GetCurrTime();
delayed->m_dwLengthInBytes = BITS2BYTES(stm.GetSize());
assert(delayed->m_dwLengthInBytes < sizeof(delayed->m_Data)/sizeof(delayed->m_Data[0]));
memcpy(delayed->m_Data, stm.GetPtr(), delayed->m_dwLengthInBytes);
m_delayedPacketList.push_back(delayed);
return true;
}
else
{
if(FAILED(m_socketMain.Send(stm.GetPtr(),BITS2BYTES(stm.GetSize()),&m_ipServer)))return false;
return true;
}
#endif
}
bool CClient::SendSetup()
{
m_ccpEndpoint.SendSetup();
return true;
}
bool CClient::SendConnectResp()
{
CStream stm;
if (m_pbAuthorizationID)
stm.WriteBits(m_pbAuthorizationID,m_uiAuthorizationSize*8);
m_ccpEndpoint.SendConnectResp(stm);
return true;
}
bool CClient::SendContextReady()
{
m_ccpEndpoint.SendContextReady(m_stmContextReady);
return true;
}
bool CClient::SendDisconnect(const char* szCause)
{
m_ccpEndpoint.SendDisconnect(szCause);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CClient::SendSecurityResponse(CStream &stm)
{
m_ccpEndpoint.SendSecurityResp(stm);
return true;
}
bool CClient::SendPunkBusterMsg(CStream &stm)
{
m_ccpEndpoint.SendPunkBusterMsg(stm);
return true;
}
void CClient::OnContextSetup()
{
m_stmContext.Seek(0);
if(m_pSink)
m_pSink->OnXContextSetup(m_stmContext);
m_ctpEndpoint.Reset();
m_ctpEndpoint2.Reset();
}
void CClient::OnServerReady()
{
GetISystem()->GetILog()->Log("CClient::OnServerReady");
/* if(m_pSink)
m_pSink->OnServerReady();*/
}
void CClient::OnConnect()
{
if(m_pSink)
m_pSink->OnXConnect();
}
void CClient::OnDisconnect(const char *szCause)
{
if(m_pSink)
{
if(szCause==NULL)szCause="Undefined";
m_pSink->OnXClientDisconnect(szCause); // this pointer is destroyed after this call
}
}
void CClient::OnCCPConnect(CStream &stm)
{
CCPConnect ccpConnect;
ccpConnect.Load(stm);
if (ccpConnect.m_cResponse & SV_CONN_FLAG_PUNKBUSTER)
{
ICVar *cl_punkbuster = GetISystem()->GetIConsole()->GetCVar("cl_punkbuster");
if (cl_punkbuster && cl_punkbuster->GetIVal() != 0)
{
m_pNetwork->InitPunkbusterClient(this);
}
}
m_pNetwork->LockPunkbusterCVars();
GetISystem()->GetILog()->Log("CClient::OnCCPConnect");
m_ccpEndpoint.SetPublicCryptKey(ccpConnect.m_ServerVariables.nPublicKey);
m_ctpEndpoint.SetPublicCryptKey(ccpConnect.m_ServerVariables.nPublicKey);
m_ctpEndpoint2.SetPublicCryptKey(ccpConnect.m_ServerVariables.nPublicKey);
m_ServerVariables=ccpConnect.m_ServerVariables;
m_smCCPMachine.Update(SIG_CONNECT);
}
void CClient::OnCCPContextSetup(CStream &stm)
{
GetISystem()->GetILog()->Log("CClient::OnCCPContextSetup");
m_stmContext=stm;
m_smCCPMachine.Update(SIG_CONTEXT_SETUP);
}
void CClient::OnCCPServerReady()
{
GetISystem()->GetILog()->Log("CClient::OnCCPServerReady");
m_smCCPMachine.Update(SIG_SERVER_READY);
}
void CClient::OnData(CStream &stm)
{
/*
BYTE msg;
if(stm.ReadPkd(msg))
{
// Special control messages.
{
if (msg >= 250)
return false;
}
}
*/
// Seek back to 0;
stm.Seek(0);
NET_TRACE("Packet=%d \n ",BITS2BYTES(stm.GetSize()));
if(m_pSink)
m_pSink->OnXData(stm);
}
void CClient::OnCCPDisconnect(const char *szCause)
{
m_smCCPMachine.Update(SIG_DISCONNECT,(ULONG_PTR)szCause);
}
//////////////////////////////////////////////////////////////////////
// IClient
//////////////////////////////////////////////////////////////////////
void CClient::Connect( const char *szIP, WORD wPort, const BYTE *pbAuthorizationID, unsigned int uiAuthorizationSize )
{
assert(pbAuthorizationID);
assert(uiAuthorizationSize>0);
NET_ASSERT(m_pSink!=NULL); // you forgot something
CIPAddress ip(wPort,szIP);
m_bLocalHost=ip.IsLocalHost();
m_ipServer=ip;
m_socketMain.SetDefaultTarget(ip);
if(m_pbAuthorizationID)
delete [] m_pbAuthorizationID;
// copy AuthorizationID
m_uiAuthorizationSize = uiAuthorizationSize;
m_pbAuthorizationID = new BYTE[m_uiAuthorizationSize];
memcpy(m_pbAuthorizationID,pbAuthorizationID,m_uiAuthorizationSize);
m_smCCPMachine.Update(SIG_START);
}
void CClient::Disconnect(const char* szCause)
{
m_smCCPMachine.Update(SIG_ACTIVE_DISCONNECT,(ULONG_PTR)szCause); // this pointer is destroyed after this call
}
void CClient::SendReliable(CStream &stm)
{
m_ctpEndpoint.SendReliable(stm);
}
void CClient::SendUnreliable(CStream &stm)
{
m_ctpEndpoint.SendUnreliable(stm);
}
void CClient::ContextReady(CStream &stm)
{
GetISystem()->GetILog()->Log("CClient::ContextReady");
if(m_smCCPMachine.GetCurrentStatus()==STATUS_PROCESSING_CONTEXT)
{
m_stmContextReady=stm;
m_smCCPMachine.Update(SIG_CONTEXT_READY);
}
else
GetISystem()->GetILog()->Log("Client::ContextReady !=STATUS_PROCESSING_CONTEXT %d",m_smCCPMachine.GetCurrentStatus());
}
bool CClient::Update(unsigned int nTime)
{
#ifdef _INTERNET_SIMULATOR
TDelayPacketList::iterator i;
for (i = m_delayedPacketList.begin(); i != m_delayedPacketList.end();)
{
DelayedPacket *dp = (*i);
if (dp->m_fTimeToSend <= GetISystem()->GetITimer()->GetCurrTime())
{
i = m_delayedPacketList.erase(i);
// Send it
// 2% packetloss
if ((rand() %100) > GetISystem()->GetIConsole()->GetCVar("g_internet_simulator_packetloss")->GetFVal())
m_socketMain.Send(dp->m_Data,dp->m_dwLengthInBytes,&m_ipServer);
// Delete it
delete dp;
}
else
++i;
}
#endif
m_nCurrentTime=nTime;
// was the timer reset ?
if (m_dwKeepAliveTimer > m_nCurrentTime)
{
// reset our keep alive timer
m_dwKeepAliveTimer = m_nCurrentTime;
}
int nRecvBytes;
/////////////////////////////////////////////////////////
static CIPAddress ipFrom;
static CStream buf;
do
{
buf.Reset();
nRecvBytes=0;
m_socketMain.Receive(buf.GetPtr(),
(int)BITS2BYTES(buf.GetAllocatedSize()),
nRecvBytes,
ipFrom);
/////////////////////////////////////////////////////////
if(nRecvBytes>0)
{
buf.SetSize(BYTES2BITS(nRecvBytes));
if(!ProcessPacket(buf,ipFrom))
{
GetISystem()->GetILog()->Log("NetDEBUG: ProcessPacket(buf,ipFrom) false");
return false; // this object was destroyed
}
m_dwKeepAliveTimer=m_nCurrentTime;
}
} while(nRecvBytes>0);
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
m_ccpEndpoint.Update(m_nCurrentTime, 0, NULL);
m_smCCPMachine.Update();
unsigned int CurrState=m_smCCPMachine.GetCurrentStatus();
if(CurrState==STATUS_READY || CurrState==STATUS_WAIT_FOR_SERVER_READY)
{
static char szCause[]="@ServerTimeout";
m_ctpEndpoint.Update(m_nCurrentTime, 0, NULL);
m_ctpEndpoint2.Update(m_nCurrentTime, 0, NULL);
if(cl_timeout && cl_timeout->GetFVal() && GetISystem()->GetIGame()->GetModuleState(EGameMultiplayer))
{
if(m_nCurrentTime-m_dwKeepAliveTimer > (cl_timeout->GetFVal() * 1000.0f) + m_pSink->GetTimeoutCompensation())
{
if (!m_bWaiting)
{
m_pSink->OnXServerTimeout();
}
m_bWaiting = 1;
}
else if (m_bWaiting)
{
m_pSink->OnXServerRessurect();
m_bWaiting = 0;
}
}
}
else
{
m_dwKeepAliveTimer=m_nCurrentTime;
}
m_pNetwork->OnClientUpdate();
return true; // this object is still exising
}
void CClient::GetBandwidth(float &fIncomingKbPerSec,float &fOutgoinKbPerSec, DWORD &nIncomingPackets, DWORD &nOutgoingPackets )
{
fIncomingKbPerSec=m_socketMain.m_fIncomingKbPerSec;
fOutgoinKbPerSec=m_socketMain.m_fOutgoingKbPerSec;
nIncomingPackets=m_socketMain.m_nIncomingPacketsPerSec;
nOutgoingPackets=m_socketMain.m_nOutgoingPacketsPerSec;
}
void CClient::Release()
{
delete this;
}
bool CClient::IsReady()
{
return (m_smCCPMachine.GetCurrentStatus()==STATUS_READY)?true:false;
}
bool CClient::ProcessPacket(CStream &stmPacket,CIPAddress &ip)
{
if (!m_pNetwork->CheckPBPacket( stmPacket,ip ))
return false;
CNP cnp;
cnp.LoadAndSeekToZero(stmPacket);
switch(cnp.m_cFrameType){
case FT_CCP_CONNECT:
case FT_CCP_DISCONNECT:
case FT_CCP_CONTEXT_SETUP:
case FT_CCP_SERVER_READY:
case FT_CCP_ACK:
case FT_CCP_SECURITY_QUERY:
case FT_CCP_SECURITY_RESP:
case FT_CCP_PUNK_BUSTER_MSG:
if (!m_ccpEndpoint.Update(m_nCurrentTime,cnp.m_cFrameType,&stmPacket))
{
GetISystem()->GetILog()->Log("NetDEBUG: m_ccpEndpoint.Update false");
return false;
}
break;
case FT_CTP_DATA:
case FT_CTP_ACK:
case FT_CTP_NAK:
case FT_CTP_PONG:
if(m_smCCPMachine.GetCurrentStatus()==STATUS_READY)
{
if(cnp.m_bSecondaryTC)
{
m_ctpEndpoint2.Update(m_nCurrentTime,cnp.m_cFrameType,&stmPacket);
}
else
{
m_ctpEndpoint.Update(m_nCurrentTime,cnp.m_cFrameType,&stmPacket);
}
}
else
{
GetISystem()->GetILog()->Log("CTP PACKET RECEIVED (CCP NOT READY!!) %d",m_smCCPMachine.GetCurrentStatus());
}
break;
/* case FT_CQP_INFO_RESPONSE:
{
CQPInfoResponse cqpInfoResponse;
cqpInfoResponse.Load(stmPacket);
m_pSink->OnServerFound(ip,cqpInfoResponse.m_stmData);
}
break;*/
default:
GetISystem()->GetILog()->Log("NetDEBUG: cnp.m_cFrameType %d",(int)cnp.m_cFrameType);
//NET_ASSERT(0);
break;
}
return 1;
}
unsigned int CClient::GetPing()
{
return m_ctpEndpoint.GetPing();
}
//////////////////////////////////////////////////////////////////////////
void CClient::OnCCPSecurityQuery(CStream &stm)
{
m_pNetwork->OnSecurityMsgQuery(stm);
}
//////////////////////////////////////////////////////////////////////////
void CClient::OnCCPSecurityResp(CStream &stm)
{
}
//////////////////////////////////////////////////////////////////////////
void CClient::OnCCPPunkBusterMsg(CStream &stm)
{
m_pNetwork->OnCCPPunkBusterMsg( m_ipServer,stm );
}
///////////////////////////////////////////////
void CClient::SetServerIP( const char *szServerIP )
{
m_sServerIP = szServerIP;
}
///////////////////////////////////////////////
void CClient::OnCDKeyAuthorization( BYTE *pbAuthorizationID )
{
if(!pbAuthorizationID)
{
static BYTE fakeid[AUTHORIZATION_ID_SIZE];
pbAuthorizationID = fakeid;
memset(fakeid,0,AUTHORIZATION_ID_SIZE); // generated fake AuthorizationID
}
char *sSemicolon;
unsigned short port = 0;
char temp[256];
strncpy(temp,m_sServerIP.c_str(),256);
if(sSemicolon=strstr(temp,":"))
{
port=atoi(&sSemicolon[1]);
sSemicolon[0]='\0';
}
if(port==0)
port=DEFAULT_SERVERPORT;
Connect(temp, port, pbAuthorizationID,AUTHORIZATION_ID_SIZE);
}
void CClient::InitiateCDKeyAuthorization( const bool inbCDAuthorization )
{
#ifndef NOT_USE_UBICOM_SDK
if(inbCDAuthorization)
m_pNetwork->m_pUbiSoftClient->Client_GetCDKeyAuthorizationID(); // OnXCDKeyAuthorization is called later
else
#endif // NOT_USE_UBICOM_SDK
{
OnCDKeyAuthorization(0); // 0 -> fake AuthorizationID is generated
}
}

159
CryNetwork/Client.h Normal file
View File

@@ -0,0 +1,159 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: Client.h
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#ifndef _CLIENT_H_
#define _CLIENT_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Interfaces.h"
#include "ClientStateMachine.h"
#ifdef NO_GNB
#include "CTPEndpoint.h"
#else
#include "CTPEndpointGNB.h"
#endif
#include "CCPEndpoint.h"
#include <queue>
#include <list>
#include <IConsole.h> // ICVar
#include "Network.h"
// REMOVE THIS WHEN NOT TESTING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//#define _INTERNET_SIMULATOR
class CClient :
public IClient,
public _IClientServices
{
public:
//! constructor
CClient( CNetwork *pNetwork );
//! destructor
virtual ~CClient();
//!
bool Init(IClientSink *pSink);
//! @return true=disconnect and this pointer is destroyed, false otherwise
bool ProcessPacket(CStream &stmPacket,CIPAddress &ip);
//_IClientServices
bool Send(CStream &stm);
bool SendTo( CIPAddress &ip,CStream &stm);
bool SendSetup();
bool SendConnectResp();
bool SendContextReady();
bool SendDisconnect(const char* szCause);
void OnConnect();
void OnContextSetup();
void OnServerReady();
void OnDisconnect(const char *szCause);
void OnData(CStream &stm);
//
void OnCCPSetup(CStream &stm){}//this is a client-->server packet
void OnCCPConnect(CStream &stm);
void OnCCPConnectResp(CStream &stm){}//this is a client-->server packet
void OnCCPContextSetup(CStream &stm);
void OnCCPContextReady(CStream &stm){}//this is a client->server packet
void OnCCPServerReady();//this is a client->server packet
void OnCCPDisconnect(const char* szCause);
void OnCCPSecurityQuery(CStream &stm);
void OnCCPSecurityResp(CStream &stm);
void OnCCPPunkBusterMsg(CStream &stm);
// interface IClient ----------------------------------------------------------------------------
virtual void Connect(const char *szIP, WORD wPort, const BYTE *pbAuthorizationID, unsigned int iAuthorizationSize);
virtual void Disconnect(const char *szCause);
virtual void ContextReady(CStream &stm);
virtual void SendReliable(CStream &stm);
virtual void SendUnreliable(CStream &stm);
virtual bool IsReady();
virtual bool Update(unsigned int nTime);
virtual void GetBandwidth( float &fIncomingKbPerSec, float &fOutgoinKbPerSec, DWORD &nIncomingPackets, DWORD &nOutgoingPackets);
virtual void Release();
virtual unsigned int GetPing();
virtual unsigned int GetRemoteTimestamp(unsigned int nTime)
{
return m_ctpEndpoint.GetRemoteTimestamp(nTime);
}
virtual unsigned int GetPacketsLostCount()
{
return m_ctpEndpoint.GetLostPackets();
}
virtual unsigned int GetUnreliablePacketsLostCount()
{
return m_ctpEndpoint.GetUnreliableLostPackets();
}
virtual void OnCDKeyAuthorization( BYTE *pbAuthorizationID );
virtual void SetServerIP( const char *szServerIP );
virtual void InitiateCDKeyAuthorization( const bool inbCDAuthorization );
// ---------------------------------------------------------------------------
bool SendSecurityResponse(CStream &stm);
bool SendPunkBusterMsg(CStream &stm);
CIPAddress GetServerIP() const { return m_ipServer; };
private: // ----------------------------------------------------------------
string m_sServerIP; //!<
CNetwork * m_pNetwork;
CClientStateMachine m_smCCPMachine;
#ifdef NO_GNB
CCTPClient m_ctpEndpoint;
#else
CCTPEndpointGNB m_ctpEndpoint;
CCTPEndpointGNB m_ctpEndpoint2;
#endif
CCCPEndpoint m_ccpEndpoint;
CDatagramSocket m_socketMain;
CIPAddress m_ipServer;
CStream m_stmContext;
CStream m_stmContextReady;
//after 3 second without any incoming packets the connection will be considered lost
ICVar * cl_timeout;
DWORD m_dwKeepAliveTimer;
BYTE * m_pbAuthorizationID; //!< CD Key AuthorizationID (use new and delete)
unsigned int m_uiAuthorizationSize; //!< Size of AuthorizationID in bytes
protected: // ------------------------------------------------------------------
IClientSink * m_pSink;
//REMOTE PROTOCOL VARIBLES (update by the connect packet)
struct CNPServerVariables m_ServerVariables;
unsigned int m_nCurrentTime;
bool m_bLocalHost; //!< the client is connected to the local server (no timeouts)
bool m_bWaiting; //!< the client is waiting for the server.. probably the server just dropped, or is stalled for some time..
#ifdef _INTERNET_SIMULATOR
struct DelayedPacket
{
float m_fTimeToSend; //!<
BYTE m_Data[8192]; //!<
unsigned int m_dwLengthInBytes; //!<
};
typedef std::list<DelayedPacket*> TDelayPacketList;
TDelayPacketList m_delayedPacketList; //!<
#endif
};
#endif // _CLIENT_H_

207
CryNetwork/ClientLocal.cpp Normal file
View File

@@ -0,0 +1,207 @@
// ClientLocal.cpp: implementation of the CClientLocal class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Network.h"
#include "ServerSlot.h"
#include "ClientLocal.h"
#include <IConsole.h> // ICVar
#ifndef NOT_USE_UBICOM_SDK
#include "UbiSoftMemory.h" // GS_WIN32
#include "cdkeydefines.h" // UBI.com AUTHORIZATION_ID_SIZE
#include "NewUbisoftClient.h" // NewUbisoftClient
#else
#define AUTHORIZATION_ID_SIZE 20
#endif // NOT_USE_UBICOM_SDK
#ifdef _DEBUG
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CClientLocal::CClientLocal( CNetwork *pNetwork, IClientSink *pSink )
{
m_pSink=pSink;
m_pNetwork=pNetwork;
m_bReady=false;
m_pServerSlot=NULL;
}
CClientLocal::~CClientLocal()
{
m_pNetwork->UnregisterClient(this);
if(m_pServerSlot)
m_pServerSlot->ResetSink();
}
void CClientLocal::Connect( const char *szIP, WORD wPort, const BYTE *pbAuthorizationID, unsigned int uiAuthorizationSize )
{
assert(pbAuthorizationID);
assert(uiAuthorizationSize>0);
m_pServerSlot=m_pNetwork->ConnectToLocalServerSlot(this,wPort);
if(m_pSink)m_pSink->OnXConnect();
CStream stAuthorizationID;
stAuthorizationID.Write(uiAuthorizationSize*8);
stAuthorizationID.WriteBits(const_cast<BYTE*>(pbAuthorizationID),uiAuthorizationSize*8);
ICVar *sv_punkbuster = GetISystem()->GetIConsole()->GetCVar("sv_punkbuster");
ICVar *cl_punkbuster = GetISystem()->GetIConsole()->GetCVar("cl_punkbuster");
if (sv_punkbuster && sv_punkbuster->GetIVal() != 0)
{
if (cl_punkbuster && cl_punkbuster->GetIVal() != 0)
{
m_pNetwork->InitPunkbusterClientLocal(this);
}
}
m_pNetwork->LockPunkbusterCVars();
m_pServerSlot->OnCCPConnectResp(stAuthorizationID);
}
void CClientLocal::Disconnect(const char *szCause)
{
GetISystem()->GetILog()->Log("NetDEBUG: CClientLocal::Disconnect");
if(m_pServerSlot)
m_pServerSlot->OnCCPDisconnect(szCause);
if (m_pSink)
m_pSink->OnXClientDisconnect(szCause);
ResetSink();
}
void CClientLocal::OnDisconnenct(const char *szCause)
{
if(m_pSink)
m_pSink->OnXClientDisconnect(szCause);
}
void CClientLocal::SendReliable(CStream &stm)
{
if(m_pServerSlot)
m_pServerSlot->PushData(stm);
}
void CClientLocal::SendUnreliable(CStream &stm)
{
if(m_pServerSlot)
m_pServerSlot->PushData(stm);
}
void CClientLocal::ContextReady(CStream &stm)
{
m_pServerSlot->OnCCPContextReady(stm);
}
bool CClientLocal::IsReady()
{
return ((m_pSink && m_pServerSlot)?true:false);
}
bool CClientLocal::Update(unsigned int nTime)
{
int iCount=0;
while(!m_qData.empty())
{
if(m_pSink)
{
DWORD dwQueueSize=m_qData.size();
m_pSink->OnXData(m_qData.front());
// assert(m_qData.size()==dwQueueSize); // the OnData might add data to the stack
// [Sergiy] iCount can reach more than 1000 right after loading a level (in Editor, at least)
assert(iCount<10000); // otherwise an endless loop would occur
iCount++;
}
m_qData.pop();
}
if(m_pServerSlot)
m_pServerSlot->UpdateSlot();
m_pNetwork->OnClientUpdate();
return true; // this object is still exising
}
void CClientLocal::GetBandwidth( float &fIncomingKbPerSec, float &fOutgoingKbPerSec, DWORD &nIncomingPackets, DWORD &nOutgoingPackets )
{
fIncomingKbPerSec=0;
fOutgoingKbPerSec=0;
nIncomingPackets=0;
nOutgoingPackets=0;
}
void CClientLocal::Release()
{
delete this;
}
///////////////////////////////////////////////
void CClientLocal::SetServerIP( const char *szServerIP )
{
m_sServerIP = szServerIP;
}
void CClientLocal::InitiateCDKeyAuthorization( const bool inbCDAuthorization )
{
#ifndef NOT_USE_UBICOM_SDK
if(inbCDAuthorization)
m_pNetwork->m_pUbiSoftClient->Client_GetCDKeyAuthorizationID(); // OnXCDKeyAuthorization is called later
else
#endif // NOT_USE_UBICOM_SDK
{
OnCDKeyAuthorization(0); // 0 -> fake AuthorizationID is generated
}
}
///////////////////////////////////////////////
void CClientLocal::OnCDKeyAuthorization( BYTE *pbAuthorizationID )
{
if(!pbAuthorizationID)
{
static BYTE fakeid[AUTHORIZATION_ID_SIZE];
pbAuthorizationID = fakeid;
memset(fakeid,0,AUTHORIZATION_ID_SIZE); // generated fake AuthorizationID
}
char *sSemicolon;
unsigned short port = 0;
char temp[256];
strncpy(temp,m_sServerIP.c_str(),256);
if(sSemicolon=strstr(temp,":"))
{
port=atoi(&sSemicolon[1]);
sSemicolon[0]='\0';
}
if(port==0)
port=DEFAULT_SERVERPORT;
Connect(temp, port, pbAuthorizationID,AUTHORIZATION_ID_SIZE);
}

69
CryNetwork/ClientLocal.h Normal file
View File

@@ -0,0 +1,69 @@
// ClientLocal.h: interface for the CClientLocal class.
//
//////////////////////////////////////////////////////////////////////
#ifndef _CLIENTLOCAL_H_
#define _CLIENTLOCAL_H_
#include <queue>
class CNetwork;
class CServerSlotLocal;
struct IClientSink;
/*!fake CClient implementation for local clients
doesn't use the network!*/
class CClientLocal :
public IClient
{
public:
//! constructor
CClientLocal(CNetwork *pNetwork,IClientSink *pSink);
//! destructor
virtual ~CClientLocal();
// interface IClient --------------------------------------------------------------------
virtual void Connect(const char *szIP, WORD wPort, const BYTE *pbAuthorizationID, unsigned int iAuthorizationSize);
virtual void Disconnect(const char *szCause);
virtual void SendReliable(CStream &stm);
virtual void SendUnreliable(CStream &stm);
virtual void ContextReady(CStream &stm);
virtual bool IsReady();
virtual bool Update(unsigned int nTime);
virtual void GetBandwidth( float &fIncomingKbPerSec, float &fOutgoinKbPerSec, DWORD &nIncomingPackets, DWORD &nOutgoingPackets );
virtual void Release();
virtual unsigned int GetPing(){return 0;}
virtual unsigned int GetRemoteTimestamp(unsigned int nTime){return nTime;}
virtual unsigned int GetPacketsLostCount(){return 0;}
virtual unsigned int GetUnreliablePacketsLostCount(){return 0;}
virtual void OnCDKeyAuthorization( BYTE *pbAuthorizationID );
virtual void SetServerIP( const char *szServerIP );
virtual void InitiateCDKeyAuthorization( const bool inbCDAuthorization );
// -------------------------------------------------------------------------------------
void ResetSink(){m_pSink=NULL;};
void PushData(CStream &stm){ m_qData.push(stm);}
void OnConnect(CNPServerVariables sv){ if(m_pSink)m_pSink->OnXConnect();}
void OnContextSetup(CStream &stm){ if(m_pSink)m_pSink->OnXContextSetup(stm);}
void OnDisconnenct(const char *szCause);
void OnCCPSecurityQuery(CStream &stm) {};
void OnCCPSecurityResp(CStream &stm) {};
void OnCCPPunkBusterMsg(CStream &stm) {};
void OnDestructServerSlot(){ m_pServerSlot=0; }
virtual CIPAddress GetServerIP() const { return CIPAddress(); };
private: // -------------------------------------------------------------------------------------
string m_sServerIP; //!<
IClientSink * m_pSink; //!<
CNetwork * m_pNetwork; //!<
CServerSlotLocal * m_pServerSlot; //!<
bool m_bReady; //!<
STREAM_QUEUE m_qData; //!<
};
#endif //_CLIENTLOCAL_H_

View File

@@ -0,0 +1,232 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: ClientStateMachine.cpp
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ClientStateMachine.h"
#ifdef _DEBUG
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
#include "IConsole.h" // IConsole
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CClientStateMachine::CClientStateMachine()
{
}
CClientStateMachine::~CClientStateMachine()
{
}
void CClientStateMachine::_Trace(char *s)
{
//::OutputDebugString(s);
}
void CClientStateMachine::_TraceStatus(unsigned int dwStatus)
{
switch(dwStatus){
case STATUS_IDLE:
_Trace("STATUS_IDLE");
break;
case STATUS_WAIT_FOR_CONNECT:
_Trace("STATUS_WAIT_FOR_CONNECT");
break;
case STATUS_CONNECTED:
_Trace("STATUS_CONNECTED");
break;
case STATUS_PROCESSING_CONTEXT:
_Trace("STATUS_PROCESSING_CONTEXT");
break;
case STATUS_WAIT_FOR_SERVER_READY:
_Trace("STATUS_WAIT_FOR_SERVER_READY");
break;
case STATUS_READY:
_Trace("STATUS_READY");
break;
case STATUS_DISCONNECTED:
_Trace("STATUS_DISCONNECTED");
break;
default:
_Trace("UNKNOWN");
break;
}
}
unsigned int CClientStateMachine::HandleANY(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
ANY_SIGNAL_EXCEPT(STATUS_DISCONNECTED);
BEGIN_ANY_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_DISCONNECT)
SetStatus(STATUS_DISCONNECTED);
OnSignal(SIG_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_ACTIVE_DISCONNECT)
SetStatus(STATUS_DISCONNECTED);
OnSignal(SIG_SEND_DISCONNECT,dwParam);
OnSignal(SIG_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_ANY_SIGNAL_HANDLER()
}
void CClientStateMachine::HandleIDLE(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_START)
SetStatus(STATUS_WAIT_FOR_CONNECT);
SetTimer(TM_CONNECT,TM_CONNECT_ET);
OnSignal(SIG_SEND_SETUP,0);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CClientStateMachine::HandleWAIT_FOR_CONNECT(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_CONNECT)
SetStatus(STATUS_CONNECTED);
ResetTimer();
OnSignal(SIG_SEND_CONNECT_RESP,0);
OnSignal(SIG_CONNECTED,0);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(TM_CONNECT)
SetStatus(STATUS_DISCONNECTED);
OnSignal(SIG_DISCONNECTED, (DWORD_PTR)"@ConnectionTimeout");
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CClientStateMachine::HandleCONNECTED(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_CONTEXT_SETUP)
SetStatus(STATUS_PROCESSING_CONTEXT);
OnSignal(SIG_INCOMING_CONTEXT_SETUP,dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CClientStateMachine::HandlePROCESSING_CONTEXT(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_CONTEXT_READY)
SetTimer(TM_SERVER_READY,TM_SERVER_READY_ET);
SetStatus(STATUS_WAIT_FOR_SERVER_READY);
OnSignal(SIG_SEND_CONTEXT_READY,dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_CONTEXT_SETUP)
SetStatus(STATUS_PROCESSING_CONTEXT);
OnSignal(SIG_INCOMING_CONTEXT_SETUP,dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CClientStateMachine::HandleWAIT_FOR_SERVER_READY(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SERVER_READY)
SetStatus(STATUS_READY);
ResetTimer();
OnSignal(SIG_INCOMING_SERVER_READY,dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_CONTEXT_SETUP)
SetStatus(STATUS_PROCESSING_CONTEXT);
OnSignal(SIG_INCOMING_CONTEXT_SETUP,dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(TM_SERVER_READY)
// SetStatus(STATUS_DISCONNECTED);
ResetTimer();
// OnSignal(SIG_DISCONNECTED, (ULONG_PTR)"timeout(TM_SERVER_READY)");
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CClientStateMachine::HandleREADY(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_CONTEXT_SETUP)
SetStatus(STATUS_PROCESSING_CONTEXT);
OnSignal(SIG_INCOMING_CONTEXT_SETUP,dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CClientStateMachine::HandleDISCONNECTED(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
//the machine can't leave this status
}
void CClientStateMachine::Init(_IClientServices *pParent)
{
m_pParent=pParent;
}
void CClientStateMachine::OnSignal(unsigned int dwOutgoingSignal,DWORD_PTR dwParam)
{
switch(dwOutgoingSignal){
case SIG_SEND_SETUP:
m_pParent->SendSetup();
break;
case SIG_SEND_CONNECT_RESP:
m_pParent->SendConnectResp();
break;
case SIG_SEND_CONTEXT_READY:
m_pParent->SendContextReady();
break;
case SIG_SEND_DISCONNECT:
m_pParent->SendDisconnect((const char*)dwParam);
break;
case SIG_CONNECTED:
m_pParent->OnConnect();
break;
case SIG_INCOMING_CONTEXT_SETUP:
m_pParent->OnContextSetup();
break;
case SIG_INCOMING_SERVER_READY:
m_pParent->OnServerReady();
break;
case SIG_DISCONNECTED:
m_pParent->OnDisconnect((const char *)dwParam); // this pointer is destroyed aftr this call
break;
default:
NET_ASSERT(0);
break;
}
}

View File

@@ -0,0 +1,124 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: ClientStateMachine.h
// Description:
//
// History:
// -08/25/2001: Alberto Demichelis, created
// -01/26/2003: Martin Mittring, commented the stated
//
//////////////////////////////////////////////////////////////////////
#ifndef _CLIENT_STATE_MACHINE_H_
#define _CLIENT_STATE_MACHINE_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "StateMachine.h"
#include "Interfaces.h"
#define STATUS_WAIT_FOR_CONNECT STATUS_BASE+1
#define STATUS_CONNECTED STATUS_BASE+2
#define STATUS_PROCESSING_CONTEXT STATUS_BASE+3
#define STATUS_WAIT_FOR_SERVER_READY STATUS_BASE+4
#define STATUS_READY STATUS_BASE+5
#define STATUS_DISCONNECTED STATUS_BASE+6
//in signals
#define SIG_START SIGNAL_BASE+1
#define SIG_CONNECT SIGNAL_BASE+2
#define SIG_CONTEXT_SETUP SIGNAL_BASE+3
#define SIG_CONTEXT_READY SIGNAL_BASE+4
#define SIG_SERVER_READY SIGNAL_BASE+5
#define SIG_DISCONNECT SIGNAL_BASE+6
#define SIG_ACTIVE_DISCONNECT SIGNAL_BASE+7
//out signals
#define SIG_SEND_SETUP SIGNAL_BASE+8
#define SIG_SEND_CONNECT_RESP SIGNAL_BASE+9
#define SIG_SEND_CONTEXT_READY SIGNAL_BASE+10
#define SIG_SEND_DISCONNECT SIGNAL_BASE+11
#define SIG_CONNECTED SIGNAL_BASE+12
#define SIG_INCOMING_CONTEXT_SETUP SIGNAL_BASE+13
#define SIG_INCOMING_SERVER_READY SIGNAL_BASE+14
#define SIG_DISCONNECTED SIGNAL_BASE+15
#define TM_CONNECT TIMER_BASE+1
#ifdef _DEBUG
#define TM_CONNECT_ET 200000
#else
#define TM_CONNECT_ET 10000
#endif
#define TM_SERVER_READY TIMER_BASE+2
#define TM_SERVER_READY_ET 120000
class CClientStateMachine :public CStateMachine
{
BEGIN_STATUS_MAP()
STATUS_ENTRY(STATUS_IDLE,HandleIDLE)
// goes to the next state right after creation of the client
STATUS_ENTRY(STATUS_WAIT_FOR_CONNECT,HandleWAIT_FOR_CONNECT)
// goes to the next state when the client gets the CCPConnect packet (time value from the server) from the server
STATUS_ENTRY(STATUS_CONNECTED,HandleCONNECTED)
// goes to the next state when the client gets the CCPContextSetup packet (map name, mod, player model, playerclass ..) from the server
STATUS_ENTRY(STATUS_PROCESSING_CONTEXT,HandlePROCESSING_CONTEXT)
// goes to the next state when finished loading the map and
// sends the CCPContextReady packet (bHost,p_name,p_model) to the server
STATUS_ENTRY(STATUS_WAIT_FOR_SERVER_READY,HandleWAIT_FOR_SERVER_READY)
// is getting all entities from the server (XSERVERMSG_ADDENTITY)
// goes to the next state when the client gets the CCPServerReady packet (empty) from the server
STATUS_ENTRY(STATUS_READY,HandleREADY)
// goes back to STATUS_PROCESSING_CONTEXT when the client gets the CCPContextSetup packet
STATUS_ENTRY(STATUS_DISCONNECTED,HandleDISCONNECTED)
// when going in this state send the SIG_DISCONNECTED signal and the system will remove the client soon
END_STATUS_MAP()
public: // ---------------------------------------------------------------------------
//! constructor
CClientStateMachine();
//! destructor
virtual ~CClientStateMachine();
//!
void Init(_IClientServices *pParent);
private: // --------------------------------------------------------------------------
//status handlers
void HandleIDLE(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleWAIT_FOR_CONNECT(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleCONNECTED(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandlePROCESSING_CONTEXT(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleWAIT_FOR_SERVER_READY(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleREADY(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleDISCONNECTED(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
virtual unsigned int HandleANY(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void OnSignal(unsigned int dwOutgoingSignal,DWORD_PTR dwParam);
// tracing
void _Trace(char *s);
void _TraceStatus(unsigned int dwStatus);
_IClientServices * m_pParent; //!<
};
#endif // _CLIENT_STATE_MACHINE_H_

View File

@@ -0,0 +1,37 @@
#ifndef _COMMON_DEFINES_
#define _COMMON_DEFINES_
#define UBISOFT_GAME_VERSION "FARCRYPC1.33"
#define GAME_NAME "FARCRY"
const char GSGAMEVERSION[5] = "1.33";
// Ubi.com Errors
const char UNKNOWNERROR[] = "@UbiUnknownError";
const char CONNECTIONFAILED[] = "@UbiConnectionFailed";
const char INVALIDACCOUNT[] = "@UbiInvalidAccount";
const char INVALIDPASSWORD[] = "@UbiInvalidPassword";
const char DATABASEFAILED[] = "@UbiDatabaseFailed";
const char BANNEDACCOUNT[] = "@UbiBannedAccount";
const char BLOCKEDACCOUNT[] = "@UbiBlockedAccount";
const char LOCKEDACCOUNT[] = "@UbiLockedAccount";
const char NOTDISCONNECTED[] = "@UbiNotDisconnected";
const char USERNAMEEXISTS[] = "@UbiUsernameExists";
const char USERNAMEMALFORMED[] = "@UbiUsernameMalformed";
const char USERNAMEFORBIDDEN[] = "@UbiUsernameForbidden";
const char USERNAMERESERVED[] = "@UbiUsernameReserved";
const char PASSWORDMALFORMED[] = "@UbiPasswordMalformed";
const char PASSWORDFORBIDDEN[] = "@UbiPasswordForbidden";
const char CREATEACCOUNTBLOCKED[] = "@UbiCreateAccountBlocked";
const char GROUPNOTEXIST[] = "@UbiGroupNotExist";
const char NOMOREPLAYERS[] = "@UbiNoMorePlayers";
const char CDKEYINTERNALERROR[]= "@UbiCDKeyInternalError";
const char CDKEYNOTCHALLENGED[]= "@UbiCDKeyNotChallenged";
const char CDKEYONLINE[] = "@UbiCDKeyOnline"; // CDKey already in use!
const char CDKEYTIMEOUT[] = "@UbiCDKeyTimeout";
const char INVALIDCDKEY[] = "@UbiInvalidCDKey";
#endif //_COMMON_DEFINES_

View File

@@ -0,0 +1,167 @@
#include "stdafx.h"
#include "compressionhelper.h"
#include "stream.h" // CStream
CCompressionHelper::CCompressionHelper()
{
#ifdef GATHER_CHARSTATISTICS
memset(m_dwCharStats,0,sizeof(DWORD)*256);
m_dwWriteBitsUncompressed=0;
m_dwWriteBitsCompressed=0;
#endif
{
DWORD dwCharStats[]= // created with GATHER_CHARSTATISTICS
{
47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
131,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,
61,51,19,2,18,15,3,0,0,0,0,0,0,0,0,0,
0,7,0,14,2,0,7,9,0,1,0,0,4,0,0,2,
28,0,26,6,14,4,0,0,7,0,0,0,0,0,0,0,
0,11,0,5,5,6,0,0,0,4,0,0,0,0,6,3,
5,0,10,10,22,6,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
// m_dwWriteBitsUncompressed=4584 m_dwWriteBitsCompressed=2499
char c;
for(c='0';c<='9';c++) dwCharStats[(DWORD)c]++;
for(c='a';c<='z';c++) dwCharStats[(DWORD)c]++;
for(c='A';c<='Z';c++) dwCharStats[(DWORD)c]++;
m_CharCompressor.InitFromStatistics(dwCharStats);
}
/* // testing code
#ifdef _DEBUG
DWORD t[3];
for(t[0]=0;t[0]<256;t[0]++)
for(t[1]=0;t[1]<256;t[1]++)
for(t[2]=0;t[2]<256;t[2]++)
{
char s[4];
char q[4];
s[0]=(char)t[0];
s[1]=(char)t[1];
s[2]=(char)t[2];
s[3]=0;
CStream str;
Write(str,s);
Read(str,q,4);
assert(strcmp((const char *)s,(const char *)q)==0);
}
#endif
*/
}
CCompressionHelper::~CCompressionHelper()
{
#ifdef GATHER_CHARSTATISTICS
FILE *out=fopen("c:\\temp\\CharStats.cpp","wb");
// fprintf(out,"");
for(DWORD a=0;a<16;a++)
{
fprintf(out," ");
for(DWORD b=0;b<16;b++)
{
DWORD i=a*16+b;
fprintf(out,"%d,",m_dwCharStats[i]);
}
fprintf(out,"\r\n");
}
fprintf(out,"\r\nm_dwWriteBitsUncompressed=%d m_dwWriteBitsCompressed=%d\r\n",m_dwWriteBitsUncompressed,m_dwWriteBitsCompressed);
fclose(out);
#endif
}
bool CCompressionHelper::Write( CStream &outStream, const unsigned char inChar )
{
return m_CharCompressor.Write(outStream,inChar);
}
bool CCompressionHelper::Read( CStream &inStream, unsigned char &outChar )
{
return m_CharCompressor.Read(inStream,outChar);
}
bool CCompressionHelper::Write( CStream &outStream, const char *inszString )
{
assert(inszString);
const unsigned char *p=(unsigned char *)inszString;
#ifdef GATHER_CHARSTATISTICS
DWORD dwOldSize=outStream.GetSize();
#endif
while(*p)
{
unsigned char c=*p++;
#ifdef GATHER_CHARSTATISTICS
m_dwCharStats[c]++;
m_dwWriteBitsUncompressed+=8;
#endif
if(!Write(outStream,c))
return false;
}
bool bRet=Write(outStream,(unsigned char)0);
#ifdef GATHER_CHARSTATISTICS
m_dwCharStats[0]++; // zero termination
m_dwWriteBitsUncompressed+=8;
m_dwWriteBitsCompressed+=outStream.GetSize()-dwOldSize;
#endif
return bRet;
}
bool CCompressionHelper::Read( CStream &inStream, char *outszString, const DWORD indwStringSize )
{
assert(outszString);
assert(indwStringSize);
for(DWORD i=0;i<indwStringSize;i++)
{
unsigned char c;
if(!Read(inStream,c))
return false;
outszString[i]=(char)c;
if(c==0)
return true;
}
outszString[indwStringSize-1]=0;
return false;
}

View File

@@ -0,0 +1,39 @@
#ifndef _COMPRESSIONHELPER_H_
#define _COMPRESSIONHELPER_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "ICompressionHelper.h" // ICompressionHelper
#include "StaticCharCompressor.h" // CStaticCharCompressor
//#define GATHER_CHARSTATISTICS // only needed during development - to build up the compression table
class CCompressionHelper :public ICompressionHelper
{
public:
//! constructor
CCompressionHelper();
//! destructor
virtual ~CCompressionHelper();
// interface ICompressionHelper ---------------------------------------------
virtual bool Write( CStream &outStream, const unsigned char inChar );
virtual bool Read( CStream &inStream, unsigned char &outChar );
virtual bool Write( CStream &outStream, const char *inszString );
virtual bool Read( CStream &inStream, char *outszString, const DWORD indwStringSize );
private: // -------------------------------------------------------------------
CStaticCharCompressor m_CharCompressor; //!< based on static Huffman compresson
#ifdef GATHER_CHARSTATISTICS
DWORD m_dwCharStats[256]; //!<
DWORD m_dwWriteBitsCompressed; //!<
DWORD m_dwWriteBitsUncompressed; //!<
#endif
};
#endif //_COMPRESSIONHELPER_H_

62
CryNetwork/CryNetwork.cpp Normal file
View File

@@ -0,0 +1,62 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: crynetwork.cpp
// Description: dll entry point
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CNP.h"
#include "Client.h"
#include "Server.h"
#include "Network.h"
//////////////////////////////////////////////////////////////////////////
// Pointer to Global ISystem.
static ISystem* gISystem = 0;
ISystem* GetISystem()
{
return gISystem;
}
//////////////////////////////////////////////////////////////////////////
#if !defined(XBOX)
_ACCESS_POOL;
#if !defined(LINUX)
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
#endif
#endif
#ifndef _XBOX
CRYNETWORK_API INetwork *CreateNetwork(ISystem *pSystem)
#else
INetwork *CreateNetwork(ISystem *pSystem)
#endif
{
gISystem = pSystem;
CNetwork *pNetwork=new CNetwork;
if(!pNetwork->Init(gISystem->GetIScriptSystem()))
{
delete pNetwork;
return NULL;
}
return pNetwork;
}
#include <CrtDebugStats.h>

View File

@@ -0,0 +1,751 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="CryNetwork"
ProjectGUID="{9A4E4BCE-D5B3-474A-874C-6578983CFC7C}"
SccProjectName="Perforce Project"
SccAuxPath=""
SccLocalPath="."
SccProvider="MSSCCI:Perforce SCM">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory=".\Debug"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
OptimizeForProcessor="0"
AdditionalIncludeDirectories="..\CryCommon;..\ubisoft.com\ConsoleImplementation\src;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-common\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-base\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-msclient\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-regserver\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-cdkey\include&quot;"
PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_USRDLL;CRYNETWORK_EXPORTS"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Debug/CryNetwork.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="winmm.lib Shlwapi.lib wininet.lib Wsock32.lib Ws2_32.lib"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="&quot;.\..\ubisoft.com\GSServices\sdks/gs-sdk-regserver/lib_win32&quot;;&quot;.\..\ubisoft.com\GSServices\sdks/gs-sdk-msclient/lib_win32&quot;;&quot;.\..\ubisoft.com\GSServices\sdks/gs-sdk-common/lib_win32&quot;;&quot;.\..\ubisoft.com\GSServices\sdks/gs-sdk-base/lib_win32&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-cdkey\lib_win32&quot;"
IgnoreDefaultLibraryNames="libcmt.lib"
GenerateDebugInformation="TRUE"
ImportLibrary="$(IntDir)/$(TargetName).lib"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Debug/CryNetwork.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Release"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
EnableFiberSafeOptimizations="FALSE"
OptimizeForProcessor="2"
AdditionalIncludeDirectories="..\CryCommon;..\ubisoft.com\ConsoleImplementation\src;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-common\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-base\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-msclient\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-regserver\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-cdkey\include&quot;"
PreprocessorDefinitions="_RELEASE;NDEBUG;WIN32;_WINDOWS;_USRDLL;CRYNETWORK_EXPORTS"
StringPooling="TRUE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
EnableEnhancedInstructionSet="0"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Release/CryNetwork.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="winmm.lib wininet.lib Wsock32.lib Ws2_32.lib"
OutputFile=".\Release/CryNetwork.dll"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
IgnoreDefaultLibraryNames="libcmt.lib"
ProgramDatabaseFile=".\Release/CryNetwork.pdb"
ImportLibrary="$(IntDir)/$(TargetName).lib"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Release/CryNetwork.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Profile|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Profile"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
EnableFiberSafeOptimizations="FALSE"
OptimizeForProcessor="2"
AdditionalIncludeDirectories="..\CryCommon;..\ubisoft.com\ConsoleImplementation\src;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-common\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-base\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-msclient\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-regserver\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-cdkey\include&quot;"
PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_USRDLL;CRYNETWORK_EXPORTS"
StringPooling="TRUE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
EnableEnhancedInstructionSet="0"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Profile/CryNetwork.pch"
AssemblerListingLocation=".\Profile/"
ObjectFile=".\Profile/"
ProgramDataBaseFileName=".\Profile/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="winmm.lib wininet.lib Wsock32.lib Ws2_32.lib"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="&quot;.\..\ubisoft.com\GSServices\sdks/gs-sdk-regserver/lib_win32&quot;;&quot;.\..\ubisoft.com\GSServices\sdks/gs-sdk-msclient/lib_win32&quot;;&quot;.\..\ubisoft.com\GSServices\sdks/gs-sdk-common/lib_win32&quot;;&quot;.\..\ubisoft.com\GSServices\sdks/gs-sdk-base/lib_win32&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-cdkey\lib_win32&quot;"
IgnoreDefaultLibraryNames="libcmt.lib"
GenerateDebugInformation="TRUE"
BaseAddress="0x34500000"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName="C:\MasterCD/CryNetwork.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Debug64|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Debug64"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\CryCommon;..\ubisoft.com\ConsoleImplementation\src;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-msclient\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-common\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-base\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-cdkey\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-regserver\include&quot;"
PreprocessorDefinitions="_DEBUG;WIN64;_WINDOWS;_USRDLL;CRYNETWORK_EXPORTS"
BasicRuntimeChecks="0"
RuntimeLibrary="1"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/$(ProjectName).pch"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
WarningLevel="3"
SuppressStartupBanner="TRUE"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:AMD64"
AdditionalDependencies="winmm.lib Shlwapi.lib wininet.lib Wsock32.lib Ws2_32.lib"
OutputFile="$(OutDir)/$(ProjectName).dll"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="&quot;..\ubisoft.com\GSServices\sdks64/gs-sdk-regserver/lib_amd64&quot;;&quot;..\ubisoft.com\GSServices\sdks64/gs-sdk-msclient/lib_amd64&quot;;&quot;..\ubisoft.com\GSServices\sdks64/gs-sdk-common/lib_amd64&quot;;&quot;..\ubisoft.com\GSServices\sdks64/gs-sdk-base/lib_amd64&quot;;&quot;..\ubisoft.com\GSServices\sdks64\gs-sdk-cdkey\lib_amd64&quot;"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
LargeAddressAware="2"
ImportLibrary="$(OutDir)/$(ProjectName).lib"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Debug/CryNetwork.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release64|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Release64"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
AdditionalIncludeDirectories="..\CryCommon;..\ubisoft.com\ConsoleImplementation\src;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-msclient\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-common\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-base\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-cdkey\include&quot;;&quot;..\ubisoft.com\GSServices\sdks\gs-sdk-regserver\include&quot;"
PreprocessorDefinitions="_RELEASE;NDEBUG;WIN64;WIN32;_AMD64_;_WINDOWS;_USRDLL;CRYNETWORK_EXPORTS"
BasicRuntimeChecks="0"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/$(ProjectName).pch"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
WarningLevel="3"
SuppressStartupBanner="TRUE"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:AMD64"
AdditionalDependencies="winmm.lib wininet.lib Wsock32.lib Ws2_32.lib"
OutputFile="$(OutDir)/$(ProjectName).dll"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="&quot;..\ubisoft.com\GSServices\sdks64/gs-sdk-regserver/lib_amd64&quot;;&quot;..\ubisoft.com\GSServices\sdks64/gs-sdk-msclient/lib_amd64&quot;;&quot;..\ubisoft.com\GSServices\sdks64/gs-sdk-common/lib_amd64&quot;;&quot;..\ubisoft.com\GSServices\sdks64/gs-sdk-base/lib_amd64&quot;;&quot;..\ubisoft.com\GSServices\sdks64\gs-sdk-cdkey\lib_amd64&quot;"
IgnoreDefaultLibraryNames="libcmt.lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
LargeAddressAware="2"
ImportLibrary="$(OutDir)/$(ProjectName).lib"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Debug/CryNetwork.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File
RelativePath=".\CCPEndpoint.cpp">
</File>
<File
RelativePath=".\Client.cpp">
</File>
<File
RelativePath=".\ClientLocal.cpp">
</File>
<File
RelativePath=".\ClientStateMachine.cpp">
</File>
<File
RelativePath=".\CompressionHelper.cpp">
</File>
<File
RelativePath=".\CryNetwork.cpp">
</File>
<File
RelativePath=".\CTPEndpoint.cpp">
</File>
<File
RelativePath="CTPEndpointGNB.cpp">
</File>
<File
RelativePath=".\DatagramSocket.cpp">
</File>
<File
RelativePath=".\DefenceWall.cpp">
</File>
<File
RelativePath="NETServerSnooper.cpp">
</File>
<File
RelativePath=".\Network.cpp">
</File>
<File
RelativePath=".\RConSystem.cpp">
</File>
<File
RelativePath=".\Server.cpp">
</File>
<File
RelativePath=".\ServerSlot.cpp">
</File>
<File
RelativePath="ServerSnooper.cpp">
</File>
<File
RelativePath=".\ServerStateMachine.cpp">
</File>
<File
RelativePath=".\StaticCharCompressor.cpp">
</File>
<File
RelativePath=".\StdAfx.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Profile|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Debug64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl">
<File
RelativePath=".\CCPEndpoint.h">
</File>
<File
RelativePath=".\Client.h">
</File>
<File
RelativePath=".\ClientLocal.h">
</File>
<File
RelativePath=".\ClientStateMachine.h">
</File>
<File
RelativePath=".\CNP.h">
</File>
<File
RelativePath=".\CompressionHelper.h">
</File>
<File
RelativePath=".\CTPEndpoint.h">
</File>
<File
RelativePath="CTPEndpointGNB.h">
</File>
<File
RelativePath=".\DatagramSocket.h">
</File>
<File
RelativePath=".\DefenceWall.h">
</File>
<File
RelativePath=".\Interfaces.h">
</File>
<File
RelativePath="NETServerSnooper.h">
</File>
<File
RelativePath=".\Network.h">
</File>
<File
RelativePath=".\PingCalculator.h">
</File>
<File
RelativePath=".\RConSystem.h">
</File>
<File
RelativePath=".\Server.h">
</File>
<File
RelativePath=".\ServerSlot.h">
</File>
<File
RelativePath="ServerSnooper.h">
</File>
<File
RelativePath=".\ServerStateMachine.h">
</File>
<File
RelativePath=".\StateMachine.h">
</File>
<File
RelativePath=".\StaticCharCompressor.h">
</File>
<File
RelativePath=".\StdAfx.h">
</File>
</Filter>
<Filter
Name="PunkBuster"
Filter="">
<File
RelativePath="..\PunkBuster\pbcl.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Profile|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
<File
RelativePath="..\PunkBuster\pbcl.h">
</File>
<File
RelativePath="..\PunkBuster\pbcommon.h">
</File>
<File
RelativePath="..\PunkBuster\pbmd5.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Profile|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
<File
RelativePath="..\PunkBuster\pbmd5.h">
</File>
<File
RelativePath="..\PunkBuster\pbsdk.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Profile|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
<File
RelativePath="..\PunkBuster\pbsdk.h">
</File>
<File
RelativePath="..\PunkBuster\pbsv.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Profile|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
<File
RelativePath="..\PunkBuster\pbsv.h">
</File>
<File
RelativePath=".\PunkBusterInterface.cpp">
<FileConfiguration
Name="Profile|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="3"/>
</FileConfiguration>
</File>
<File
RelativePath=".\PunkBusterInterface.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
</Filter>
<Filter
Name="UBIcom"
Filter="">
<File
RelativePath=".\CommonDefines.h">
</File>
<File
RelativePath=".\NewUbisoftCDKey.cpp">
</File>
<File
RelativePath=".\NewUbisoftClient.cpp">
</File>
<File
RelativePath=".\NewUbisoftClient.h">
</File>
<File
RelativePath=".\NewUbisoftMSClient.cpp">
</File>
<File
RelativePath=".\NewUbisoftRegServer.cpp">
</File>
<File
RelativePath=".\ScriptObjectNewUbisoftClient.cpp">
</File>
<File
RelativePath=".\ScriptObjectNewUbisoftClient.h">
</File>
<File
RelativePath=".\UbisoftMemory.cpp">
</File>
<File
RelativePath=".\UbisoftMemory.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = "file:F:\\Crytek\\CryNetwork\\CryNetwork.vcproj"
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}

View File

@@ -0,0 +1,258 @@
<?xml version="1.0" encoding = "windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.00"
Name="CryNetwork_XBox"
ProjectGUID="{9A4E4BCE-D5B3-474A-874C-6578983CFC7C}"
SccProjectName="&quot;$/Game01/CryNetwork&quot;, OBOAAAAA"
SccAuxPath=""
SccLocalPath="."
SccProvider="MSSCCI:Microsoft Visual SourceSafe">
<Platforms>
<Platform
Name="Xbox"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Xbox"
OutputDirectory="Debug_XBox"
IntermediateDirectory="Debug_XBox"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_DEBUG;_XBOX;_LIB"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Debug_XBox/CryNetwork.pch"
AssemblerListingLocation=".\Debug_XBox/"
ObjectFile=".\Debug_XBox/"
ProgramDataBaseFileName=".\Debug_XBox/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/CryNetwork.lib"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
</Configuration>
<Configuration
Name="Release|Xbox"
OutputDirectory="Release_XBox"
IntermediateDirectory="Release_XBox"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="2"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_RELEASE;NDEBUG;_XBOX;_LIB"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/CryNetwork.pch"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="2"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/CryNetwork.lib"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
</Configuration>
<Configuration
Name="Profile|Xbox"
OutputDirectory="Profile"
IntermediateDirectory="Profile"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="2"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="NDEBUG;_XBOX;_LIB"
StringPooling="TRUE"
BufferSecurityCheck="FALSE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Profile/CryNetwork.pch"
AssemblerListingLocation=".\Profile/"
ObjectFile=".\Profile/"
ProgramDataBaseFileName=".\Profile/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/CryNetwork.lib"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
</Configuration>
</Configurations>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File
RelativePath=".\CCPEndpoint.cpp">
</File>
<File
RelativePath=".\CTPEndpoint.cpp">
</File>
<File
RelativePath="CTPEndpointGNB.cpp">
</File>
<File
RelativePath=".\Client.cpp">
</File>
<File
RelativePath=".\ClientLocal.cpp">
</File>
<File
RelativePath=".\ClientStateMachine.cpp">
</File>
<File
RelativePath=".\CryNetwork.cpp">
</File>
<File
RelativePath=".\DatagramSocket.cpp">
</File>
<File
RelativePath=".\Network.cpp">
</File>
<File
RelativePath=".\Server.cpp">
</File>
<File
RelativePath=".\ServerSlot.cpp">
</File>
<File
RelativePath="ServerSnooper.cpp">
</File>
<File
RelativePath=".\ServerStateMachine.cpp">
</File>
<File
RelativePath=".\StdAfx.cpp">
<FileConfiguration
Name="Debug|Xbox">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Xbox">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Profile|Xbox">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl">
<File
RelativePath=".\CCPEndpoint.h">
</File>
<File
RelativePath=".\CNP.h">
</File>
<File
RelativePath=".\CTPEndpoint.h">
</File>
<File
RelativePath="CTPEndpointGNB.h">
</File>
<File
RelativePath=".\Client.h">
</File>
<File
RelativePath=".\ClientLocal.h">
</File>
<File
RelativePath=".\ClientStateMachine.h">
</File>
<File
RelativePath=".\DatagramSocket.h">
</File>
<File
RelativePath=".\Interfaces.h">
</File>
<File
RelativePath=".\Network.h">
</File>
<File
RelativePath=".\PingCalculator.h">
</File>
<File
RelativePath=".\Server.h">
</File>
<File
RelativePath=".\ServerSlot.h">
</File>
<File
RelativePath="ServerSnooper.h">
</File>
<File
RelativePath=".\ServerStateMachine.h">
</File>
<File
RelativePath=".\StateMachine.h">
</File>
<File
RelativePath=".\StdAfx.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = "file:F:\\Crytek\\CryNetwork\\CryNetwork_XBox.vcproj"
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}

View File

@@ -0,0 +1,384 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: DatagramSocket.cpp
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <IPAddress.h>
#include "DatagramSocket.h"
#include "Network.h"
#ifdef _DEBUG
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
NRESULT CDatagramSocket::Create(SocketType st)
{
int nErr = 0;
m_nStartTick=::GetTickCount();
#if defined(LINUX)
if ((m_hSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
#else
if ((m_hSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
#endif
{
nErr = WSAGetLastError();
return MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, nErr);
}
m_stSocketType = st;
if (m_stSocketType == NonBlocking)
{
#if defined(LINUX)
if(fcntl( m_hSocket, F_SETFL, O_NONBLOCK ) < 0)
#else
unsigned long nTrue = 1;
if (ioctlsocket(m_hSocket, FIONBIO, &nTrue) == SOCKET_ERROR)
#endif
{
nErr = WSAGetLastError();
Close();
return MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, nErr);
}
}
return NET_OK;
}
void CDatagramSocket::Close()
{
if (m_hSocket == INVALID_SOCKET)
return;
// disable receiving
#if defined(LINUX)
setsockopt(m_hSocket,IPPROTO_IP,IP_DROP_MEMBERSHIP,(char *)&m_imMulticastReq, sizeof(m_imMulticastReq));
#endif
shutdown(m_hSocket, 0x00);
// should be chnaged for BSD socket close() instead closesocket()
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
}
NRESULT CDatagramSocket::Listen(WORD wPort, CIPAddress *xaMulticastAddress, CIPAddress *ipLocalAddress)
{
int nErr = 0;
if (m_hSocket == INVALID_SOCKET)
return NET_SOCKET_NOT_CREATED;
sockaddr_in saLocalAddr;
saLocalAddr.sin_family = AF_INET;
saLocalAddr.sin_port = htons(wPort);
// check if we need to bind to a specific interface
if (ipLocalAddress && ipLocalAddress->GetAsUINT())
{
// yes, we need to bind to this ip address
saLocalAddr.sin_addr.s_addr = inet_addr(ipLocalAddress->GetAsString());
}
else
{
// no, use any interface
saLocalAddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
// allow many servers on the same machine to list to the
if (xaMulticastAddress)
{
BOOL bReuse=true;
#if defined(LINUX)
if(setsockopt(m_hSocket,SOL_SOCKET,SO_REUSEADDR,(const char *)&bReuse,sizeof(BOOL)) < 0)
#else
if(setsockopt(m_hSocket,SOL_SOCKET,SO_REUSEADDR,(const char *)&bReuse,sizeof(BOOL)) == SOCKET_ERROR)
#endif
{
nErr = WSAGetLastError();
GetISystem()->GetILog()->Log("setsockopt 1 failed with registering multicast (WSAGetLastError returned %d)",nErr);
}
}
#if defined(LINUX)
BOOL bReuse=true;
if(setsockopt(m_hSocket,SOL_SOCKET,SO_REUSEADDR,(const char *)&bReuse,sizeof(BOOL)) < 0)
{
nErr = WSAGetLastError();
GetISystem()->GetILog()->Log("setsockopt 1 failed with setting reusablity to socket (WSAGetLastError returned %d)",nErr);
}
if (bind(m_hSocket, (struct sockaddr*)&saLocalAddr, sizeof(saLocalAddr)) < 0)
#else
if (bind(m_hSocket, (struct sockaddr*)&saLocalAddr, sizeof(sockaddr_in)) == SOCKET_ERROR)
#endif
{
nErr = WSAGetLastError();
GetISystem()->GetILog()->Log("Registering Multicast: bind failed(%d)",nErr);
Close();
return MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, nErr);
}
sockaddr_in sockname;
#if defined(LINUX)
socklen_t size = (socklen_t)sizeof(sockaddr_in);
#else
int size = sizeof(sockaddr_in);
#endif
getsockname(m_hSocket, (sockaddr *)&sockname, &size);
CIPAddress local(&saLocalAddr);
CIPAddress bound(&sockname);
GetISystem()->GetILog()->Log("NAMES Local %s Bind %s", local.GetAsString(), bound.GetAsString());
// Setup Multicast registration
if (xaMulticastAddress)
{
#ifdef _XBOX
// DEBUG_BREAK;
#else
struct ip_mreq imMulticastReq;
if (ipLocalAddress && ipLocalAddress->GetAsUINT())
{
imMulticastReq.imr_interface.s_addr = inet_addr(ipLocalAddress->GetAsString());
GetISystem()->GetILog()->Log("Registering Multicast: %s",ipLocalAddress->GetAsString());
}
else
{
imMulticastReq.imr_interface.s_addr = INADDR_ANY;
GetISystem()->GetILog()->Log("Registering Multicast: ANY");
}
imMulticastReq.imr_multiaddr.s_addr = xaMulticastAddress->GetAsUINT();
#if defined(LINUX)
if (setsockopt(m_hSocket,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&imMulticastReq, sizeof(ip_mreq)) < 0)
#else
if(setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imMulticastReq, sizeof(ip_mreq)) == SOCKET_ERROR)
#endif
{
// Problem: http://support.microsoft.com/default.aspx?scid=kb;en-us;Q257460
// But: but we need Ws2_32.lib for UBI.com integration
// Solution: make sure the libs are coming in in this order: Wsock32.lib Ws2_32.lib
nErr = WSAGetLastError();
GetISystem()->GetILog()->Log("setsockopt 2 failed with registering multicast (WSAGetLastError returned %d)",nErr);
//NET_TRACE(EnumerateError(MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, nErr)));
Close();
return MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, nErr);
}
#if defined(LINUX)
const int TTL=255;
if(setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_TTL, &TTL, sizeof(TTL)) < 0)
{
nErr = WSAGetLastError();
GetISystem()->GetILog()->Log("setsockopt 2 failed with setting TTL for multicast (WSAGetLastError returned %d)",nErr);
//NET_TRACE(EnumerateError(MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, nErr)));
Close();
return MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, nErr);
}
m_imMulticastReq = imMulticastReq; //store for call to IP_DROP_MEMBERSHIP
#endif
#endif
}
return NET_OK;
}
NRESULT CDatagramSocket::GetSocketAddresses(CIPAddress *pAddr, DWORD nMaCIPAddresses)
{
#ifdef _XBOX
return NET_FAIL;
#else
if (m_hSocket == INVALID_SOCKET)
return NET_SOCKET_NOT_CREATED;
DWORD i;
char buf[256];
struct hostent *hp;
sockaddr_in port;
#if defined(LINUX)
socklen_t n;
#else
int n;
#endif
#ifndef PS2
getsockname(m_hSocket, (sockaddr *)&port, &n);
#else //PS2
getsockname((int)m_hSocket, (sockaddr *)&port, (unsigned int *)&n);
#endif //PS2
if (!gethostname(buf, sizeof(buf)))
{
hp = gethostbyname(buf);
if (hp)
{
// if (hp->h_addrtype != AF_INET)
// CLog::Log("gethostbyname: address type was not AF_INET\n");
// CLog::Log("Hostname: %s\n", hp->h_name);
i = 0;
while (hp->h_aliases[i])
{
// CLog::Log("Alias: %s\n", hp->h_aliases[i]);
i++;
}
i = 0;
while (hp->h_addr_list[i] && i < nMaCIPAddresses)
{
sockaddr_in temp;
memcpy(&(temp.sin_addr), hp->h_addr_list[i], hp->h_length);
temp.sin_port = port.sin_port;
pAddr[i].Set(&temp);
i++;
}
return NET_OK;
}
}
return NET_FAIL;
#endif
}
//////////////////////////////////////////////////////////////////////////
NRESULT CDatagramSocket::Send(BYTE *pBuffer, int nLenBytes, CIPAddress *saAddress)
{
if (m_hSocket == INVALID_SOCKET)
return NET_SOCKET_NOT_CREATED;
if (!saAddress)
saAddress = &m_saDefaultAddress;
if (sendto(m_hSocket, (const char *)pBuffer, nLenBytes, 0, (sockaddr*)&saAddress->m_Address, sizeof(sockaddr)) == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
// Close();
return MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, nErr);
}
/// compute the bandwitdh///////////////////////
if ((::GetTickCount() - m_nStartTick)>1000)
ComputeBandwidth();
m_nSentBytesInThisSec += nLenBytes;
m_nSentPacketsInThisSec++;
///////////////////////////////////////////////
CNetwork *pNetwork = (CNetwork*)GetISystem()->GetINetwork();
if (pNetwork && pNetwork->GetLogLevel() == 1)
{
CryLog( "[NET] Send to %s, PacketSize=%d bytes",saAddress->GetAsString(),nLenBytes );
}
return NET_OK;
}
//////////////////////////////////////////////////////////////////////////
NRESULT CDatagramSocket::Receive(unsigned char *pBuf/*[MAX_UDP_PACKET_SIZE]*/, int nBufLen, int &nRecvBytes, CIPAddress &pFrom)
{
if (m_hSocket == INVALID_SOCKET)
return NET_SOCKET_NOT_CREATED;
int nRetValue;
#if defined(LINUX)
socklen_t n = (socklen_t)sizeof(sockaddr_in);
#else
int n = sizeof(sockaddr_in);
#endif
#if defined(LINUX)
if ((nRetValue = recvfrom(m_hSocket, (char *)pBuf, nBufLen, 0, (sockaddr*)&pFrom.m_Address, &n)) < 0)
#else
if ((nRetValue = recvfrom(m_hSocket, (char *)pBuf, nBufLen, 0, (sockaddr*)&pFrom.m_Address, &n)) == SOCKET_ERROR)
#endif
{
#if !defined(LINUX)
int nErr = GetLastError();
switch (nErr)
{
case WSAEWOULDBLOCK:
nRecvBytes = 0;
return NET_OK;
break;
case WSAEMSGSIZE:
//<<FIXME>> warning message "packet oversize"
return NET_OK;
break;
default:
return MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, nErr);
#else
return MAKE_NRESULT(NET_FAIL, NET_FACILITY_SOCKET, errno);
#endif
#if !defined(LINUX)
break;
}
#endif
}
nRecvBytes = nRetValue;
/// compute the bandwith///////////////////////
if ((::GetTickCount() - m_nStartTick)>1000)
{
ComputeBandwidth();
}
m_nReceivedBytesInThisSec += nRecvBytes;
m_nReceivedPacketsInThisSec++;
///////////////////////////////////////////////
CNetwork *pNetwork = (CNetwork*)GetISystem()->GetINetwork();
if (pNetwork && pNetwork->GetLogLevel() == 1)
{
CryLog( "[NET] Recv from %s, PacketSize=%d bytes",pFrom.GetAsString(),nRecvBytes );
}
return NET_OK;
}
const char *GetHostName()
{
#ifdef _XBOX
//DEBUG_BREAK;
return "__XBOX__";
#else
static char szBuf[56];
memset(szBuf, 0, sizeof(szBuf));
gethostname(szBuf, sizeof(szBuf));
return szBuf;
#endif
}
//////////////////////////////////////////////////////////////////////////
const char* CDatagramSocket::GetHostName()
{
#ifdef _XBOX
//DEBUG_BREAK;
return "__XBOX__";
#else
static char szBuf[56];
memset(szBuf, 0, sizeof(szBuf));
gethostname(szBuf, sizeof(szBuf));
return szBuf;
#endif
}
//////////////////////////////////////////////////////////////////////////
void CDatagramSocket::ComputeBandwidth()
{
m_fOutgoingKbPerSec = ((float)(m_nSentBytesInThisSec*8))/1024.f;
m_fIncomingKbPerSec = ((float)(m_nReceivedBytesInThisSec*8))/1024.f;
m_nOutgoingPacketsPerSec = m_nSentPacketsInThisSec;
m_nIncomingPacketsPerSec = m_nReceivedPacketsInThisSec;
m_nStartTick=::GetTickCount();
m_nSentBytesInThisSec = 0;
m_nReceivedBytesInThisSec = 0;
m_nSentPacketsInThisSec = 0;
m_nReceivedPacketsInThisSec = 0;
}

125
CryNetwork/DatagramSocket.h Normal file
View File

@@ -0,0 +1,125 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: DatagramSocket.h
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#ifndef _DATAGRAM_SOCKET_H_
#define _DATAGRAM_SOCKET_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define MAX_UDP_PACKET_SIZE 8192
// struct ip_mreq mreq;
// mreq is the ip_mreqstructure
//{
// struct in_addr imr_multiaddr; // The multicast group to join
// struct in_addr imr_interface; // The interface to join on
//}
// multicast sample addr is --> "234.5.6.7"
#include "Stream.h"
#include <IPAddress.h>
#ifndef _XBOX
#if _MSC_VER > 1000
#pragma comment(lib, "WSOCK32.LIB")
#endif // _MSC_VER > 1000
#endif
#ifdef LINUX
#include <time.h>
#endif //LINUX
/*inline int gethostname(char *__name, size_t __len)
{
#pragma message ("gethostname not implemented")
return 0;
}
*/
class CDatagramSocket
{
public:
enum SocketType
{
Blocking,
NonBlocking
};
//! constructor
CDatagramSocket()
{
m_hSocket=INVALID_SOCKET;
m_nSentBytesInThisSec=0;
m_nReceivedBytesInThisSec=0;
m_nSentPacketsInThisSec=0;
m_nReceivedPacketsInThisSec=0;
m_fIncomingKbPerSec=0.0f;
m_fOutgoingKbPerSec=0.0f;
m_nIncomingPacketsPerSec=0;
m_nOutgoingPacketsPerSec=0;
}
//! destructor
virtual ~CDatagramSocket()
{
Close();
//<<FIXME>>
}
//!
NRESULT Create(SocketType st = NonBlocking);
//!
NRESULT Listen(WORD wPort, CIPAddress *xaMulticastAddress = NULL, CIPAddress *ipLocalAddress = 0);
//!
void SetDefaultTarget(CIPAddress &saAddress)
{
m_saDefaultAddress.Set(saAddress);
}
//!
NRESULT Send(BYTE *pBuffer, int nLenBytes, CIPAddress *saAddress = NULL);
//!
NRESULT Receive(unsigned char *pBuf/*[MAX_UDP_PACKET_SIZE]*/, int nBufLen, int &nRecvBytes, CIPAddress &pFrom);
const char *GetHostName();
//!
void ComputeBandwidth();
//!
NRESULT GetSocketAddresses(CIPAddress *pAddr, DWORD nMaCIPAddresses);
//!
int GetLastError(){return WSAGetLastError();}
//!
void Close();
private:
SOCKET m_hSocket; //!<
SocketType m_stSocketType; //!<
CIPAddress m_saDefaultAddress; //!< Default target host and port [optional] for Send()
unsigned int m_nStartTick; //!< tick for bandwitdh computation
unsigned int m_nSentBytesInThisSec; //!< is counting up and reseted every second
unsigned int m_nReceivedBytesInThisSec; //!< is counting up and reseted every second
unsigned int m_nSentPacketsInThisSec; //!< is counting up and reseted every second
unsigned int m_nReceivedPacketsInThisSec; //!< is counting up and reseted every second
#if defined(LINUX)
struct ip_mreq m_imMulticastReq; //!< needed for call to IP_DROP_MEMBERSHIP
#endif
public:
float m_fOutgoingKbPerSec; //!< is updated every second
float m_fIncomingKbPerSec; //!< is updated every second
unsigned int m_nOutgoingPacketsPerSec; //!< is updated every second
unsigned int m_nIncomingPacketsPerSec; //!< is updated every second
};
#endif //_DATAGRAM_SOCKET_H_

961
CryNetwork/DefenceWall.cpp Normal file
View File

@@ -0,0 +1,961 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2001-2004.
// -------------------------------------------------------------------------
// File name: DefenceWall.cpp
// Version: v1.00
// Created: 25/1/2004 by Timur.
// Compilers: Visual Studio.NET 2003
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "DefenceWall.h"
#include "Network.h"
#include "Client.h"
#include "Server.h"
#include "ServerSlot.h"
#include "ICryPak.h"
//#define LOGEVENTS // don't use in public release
enum CHEAT_PROTECTION_LEVEL {
CHEAT_LEVEL_DEFAULT = 1,
CHEAT_LEVEL_RANDOMCHECKS,
CHEAT_LEVEL_CODE,
};
// Max number of retried for single request.
#define MAX_CHECK_RETRIES 5
// Time in seconds during which client must return response to server.
#define WAIT_FOR_RESPONSE_TIME 20
// Check about every 5 mins.
#define RANDOM_CHECK_PERIOD 60*3
enum EDefenceWallRequestCode
{
DEFWALL_UNKNOWN = 0,
DEFWALL_CHECK_PAK = 1,
DEFWALL_CHECK_PROTECTED_FILE = 2,
DEFWALL_CHECK_DLL_CODE = 3,
};
//////////////////////////////////////////////////////////////////////////
CDefenceWall::CDefenceWall( CNetwork *pNetwork )
{
m_pNetwork = pNetwork;
m_pSystem = GetISystem();
m_nNextRequestId = 1;
m_pServer = 0;
m_bServer = false;
m_bLog = true;
m_nNumOpenedPacksOnServer = 0;
m_nEncryptKey[0] = 2962387638;
m_nEncryptKey[1] = 1782685322;
m_nEncryptKey[2] = 268651613;
m_nEncryptKey[3] = 156356231;
#if defined(WIN64) || defined(LINUX64)
m_b64bit = true;
#else
m_b64bit = false;
#endif
}
//////////////////////////////////////////////////////////////////////////
CDefenceWall::~CDefenceWall()
{
ClearAllPendingRequests();
m_protectedFiles.clear();
ClearClients();
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::SetServer( CServer *pServer )
{
m_pServer = pServer;
m_pClient = 0;
m_bServer = true;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::SetClient( CClient *pClient )
{
m_pServer = 0;
m_pClient = pClient;
m_bServer = false;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ClearClients()
{
for (Clients::iterator it = m_clients.begin(); it != m_clients.end(); ++it)
{
delete *it;
}
m_clients.clear();
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ClearAllPendingRequests()
{
for (PendingChecks::iterator it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it++)
{
SClientCheckContext* pCtx = *it;
delete pCtx;
}
m_pendingChecks.clear();
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::FillStdServerProbes()
{
m_stdServerProbes.clear();
m_stdServerProbes.reserve(30);
IDataProbe *pProbe = GetISystem()->GetIDataProbe();
ICryPak::PakInfo* pPakInfo = m_pSystem->GetIPak()->GetPakInfo();
unsigned int i;
//////////////////////////////////////////////////////////////////////////
// Collect PAK files.
//////////////////////////////////////////////////////////////////////////
m_nNumOpenedPacksOnServer = pPakInfo->numOpenPaks;
for (i = 0; i < pPakInfo->numOpenPaks; i++)
{
SClientCheckContext ctx;
ctx.nNumOpenedPaks = pPakInfo->numOpenPaks;
if (ServerCreateFileProbe( pPakInfo->arrPaks[i].szFilePath,ctx,true ))
{
m_stdServerProbes.push_back(ctx);
}
}
m_pSystem->GetIPak()->FreePakInfo( pPakInfo );
// Do not compare user DLL`s.
/*
#if !defined(LINUX)
//////////////////////////////////////////////////////////////////////////
// Collect Modules Code probes.
//////////////////////////////////////////////////////////////////////////
// Create module probe for all DLL modules.
IDataProbe::SModuleInfo *pModules;
int numModules = pProbe->GetLoadedModules( &pModules );
for (int m = 0; m < numModules; m++)
{
SClientCheckContext ctx;
if (ServerCreateModuleProbe( pModules[m].filename.c_str(),ctx ))
m_stdServerProbes.push_back(ctx);
}
#endif
*/
}
//////////////////////////////////////////////////////////////////////////
bool CDefenceWall::ServerCreateModuleProbe( const char *sFilename,SClientCheckContext &ctx )
{
char sModule[_MAX_PATH];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath( sFilename,0,0,fname,ext );
_makepath( sModule,0,0,fname,ext );
strlwr( sModule );
// Skip comparing render dll code. (Can be OGL,D3D or NULL)
if (strstr(sModule,"render"))
return false;
AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+sFilename).c_str() );
if (m_pNetwork->GetCheatProtectionLevel() >= CHEAT_LEVEL_CODE)
{
ctx.nRequestCode = DEFWALL_CHECK_DLL_CODE;
ctx.bExecutableCode = true;
ctx.probe.sFilename = sModule;
#if !defined(LINUX)
ctx.nFilenameHash = m_pSystem->GetIDataProbe()->GetHash( sModule );
ctx.probe.nCodeInfo = rand()%3;
if (!m_pSystem->GetIDataProbe()->GetRandomModuleProbe( ctx.probe ))
return false;
if (!m_pSystem->GetIDataProbe()->GetCode( ctx.probe ))
return false;
#endif
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> CreatedExeProbe[%d] %s %I64x",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode );
#endif
}
else
{
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CDefenceWall::ServerCreateFileProbe( const char *sFilename,SClientCheckContext &ctx,bool bRandomPart )
{
#if !defined(LINUX)
// Get current language.
ICVar *pLanguage=m_pSystem->GetIConsole()->GetCVar("g_language");
if (pLanguage && pLanguage->GetString())
{
// Skip validation of language specific paks.
char fname[_MAX_FNAME];
_splitpath( sFilename,NULL,NULL,fname,NULL );
if (strnicmp(fname,pLanguage->GetString(),strlen(pLanguage->GetString())) == 0)
{
// This is language pak... skip checking it.
return false;
}
}
string file = sFilename;
GetRelativeFilename(file);
ctx.nRequestCode = DEFWALL_CHECK_PAK;
ctx.bExecutableCode = false;
ctx.probe.sFilename = file;
ctx.nFilenameHash = m_pSystem->GetIDataProbe()->GetHash( file.c_str() );
if (bRandomPart)
{
ctx.probe.nCodeInfo = rand()%3;
if (!m_pSystem->GetIDataProbe()->GetRandomFileProbe( ctx.probe,true ))
return false;
if (!m_pSystem->GetIDataProbe()->GetCode( ctx.probe ))
return false;
}
else
{
ctx.probe.nCodeInfo = rand()%3;
ctx.probe.nSize = 0xFFFFFFFF;
if (!m_pSystem->GetIDataProbe()->GetCode( ctx.probe ))
return false;
}
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> CreatedFileProbe[%d] %s %I64x",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode );
#endif
#endif
return true;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::FirstTimeClientValidation( ClientInfo *pClientInfo )
{
CStream outstream;
for (unsigned int i = 0; i < m_stdServerProbes.size(); i++)
{
SClientCheckContext &ctx = m_stdServerProbes[i];
if (ctx.bExecutableCode && pClientInfo->b64bit != m_b64bit) // Cannot compare clients with 32/64bit difference.
continue;
IssueRequest( pClientInfo,outstream,ctx );
}
// Send network request to this client IP.
SendSecurityQueryToClient( pClientInfo->ip,outstream );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::RandomClientValidation( ClientInfo *pClientInfo )
{
CStream outstream;
unsigned int n = 0;
// Ignore if no standart probes yet.
if (m_stdServerProbes.empty())
return;
bool bRepeat = false;
while (bRepeat) {
bRepeat = false;
n = rand() % m_stdServerProbes.size();
assert( n < m_stdServerProbes.size() );
if (n >= m_stdServerProbes.size())
bRepeat = true;
if (m_stdServerProbes[n].bExecutableCode && pClientInfo->b64bit != m_b64bit) // Cannot compare clients with 32/64bit difference.
bRepeat = true;
}
SClientCheckContext &ctx = m_stdServerProbes[n];
IssueRequest( pClientInfo,outstream,ctx );
// Send network request to this client IP.
SendSecurityQueryToClient( pClientInfo->ip,outstream );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::IssueRequest( ClientInfo *pClientInfo,CStream &outstream,SClientCheckContext &ctx )
{
CTimeValue currTime = m_pNetwork->GetCurrentTime();
//////////////////////////////////////////////////////////////////////////
// Schedule new random check time for this client.
CTimeValue timediff;
timediff.SetSeconds( RANDOM_CHECK_PERIOD + (RANDOM_CHECK_PERIOD*rand())/RAND_MAX );
if (m_pNetwork->GetCheatProtectionLevel() == 5)
timediff.SetSeconds( 2 );
pClientInfo->nextRandomCheckTime = currTime + timediff;
//////////////////////////////////////////////////////////////////////////
ctx.clientIP = pClientInfo->ip;
if (ctx.nRetries == 0) // If repeating request do not assign new requestId.
{
ctx.nRequestId = m_nNextRequestId++;
}
ctx.requestTime = currTime;
pClientInfo->lastRequestTime = currTime;
SClientCheckContext *pCtx = new SClientCheckContext;
*pCtx = ctx;
if (ctx.nRetries == 0)
{
m_pendingChecks.push_back(pCtx);
}
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> IssueRequest[%d] %s %I64x (ofs=%d,size=%d)",pCtx->nRequestId,pCtx->probe.sFilename.c_str(),pCtx->probe.nCode,pCtx->probe.nOffset,pCtx->probe.nSize );
#endif
CStream stm;
WriteStreamRequest( *pCtx,stm );
outstream.Write( stm );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::WriteStreamRequest( SClientCheckContext &ctx,CStream &stm )
{
stm.Write( ctx.nRequestCode );
stm.WritePacked( ctx.nRequestId );
stm.WritePacked( ctx.nFilenameHash );
stm.WritePacked( ctx.probe.nCodeInfo );
stm.WritePacked( ctx.probe.nOffset );
stm.WritePacked( ctx.probe.nSize );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ReadStreamRequest( SClientCheckContext &ctx,CStream &stm )
{
stm.Read( ctx.nRequestCode );
stm.ReadPacked( ctx.nRequestId );
stm.ReadPacked( ctx.nFilenameHash );
stm.ReadPacked( ctx.probe.nCodeInfo );
stm.ReadPacked( ctx.probe.nOffset );
stm.ReadPacked( ctx.probe.nSize );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::WriteStreamResponse( SClientCheckContext &ctx,CStream &stm )
{
// Also crypt stream here.
stm.Write( ctx.nRequestCode );
stm.WritePacked( ctx.nRequestId );
stm.WritePacked( ctx.nNumOpenedPaks );
stm.WritePacked( ctx.nClientStatusFlags );
stm.WriteBits( (BYTE*)&ctx.probe.nCode,64 ); // write int64
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ReadStreamResponse( SClientCheckContext &ctx,CStream &stm )
{
stm.Read( ctx.nRequestCode );
stm.ReadPacked( ctx.nRequestId );
stm.ReadPacked( ctx.nNumOpenedPaks );
stm.ReadPacked( ctx.nClientStatusFlags );
stm.ReadBits( (BYTE*)&ctx.probe.nCode,64 ); // read int64
}
//////////////////////////////////////////////////////////////////////////
SClientCheckContext* CDefenceWall::FindRequest( int nRequestId )
{
for (PendingChecks::iterator it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it++)
{
SClientCheckContext* pCtx = *it;
if (pCtx->nRequestId == nRequestId)
{
return pCtx;
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::RemoveRequest( SClientCheckContext* pCtx )
{
for (PendingChecks::iterator it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it++)
{
if (pCtx == *it)
{
m_pendingChecks.erase(it);
return;
}
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::UnifyFilename( string &sFilename )
{
string file = sFilename;
std::replace( file.begin(),file.end(),'\\','/' );
strlwr( const_cast<char*>(file.c_str()) );
sFilename = file;
}
void CDefenceWall::GetRelativeFilename( string &sFilename )
{
UnifyFilename(sFilename);
// Get current folder.
char szCurrDir[_MAX_PATH];
GetCurrentDirectory( sizeof(szCurrDir),szCurrDir );
string sCurDir = szCurrDir;
UnifyFilename(sCurDir);
// Get relative path.
if (strncmp(sFilename.c_str(),sCurDir.c_str(),sCurDir.size()) == 0 && sFilename.size()+1 >= sCurDir.size())
{
// First part of file name is current dir.
sFilename = sFilename.substr(sCurDir.size()+1);
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::EncryptStream( CStream &stm )
{
unsigned int* pBuffer = (unsigned int*)stm.GetPtr();
int len = stm.GetSize()/8;
if (len >= 8)
{
TEA_ENCODE( pBuffer,pBuffer,TEA_GETSIZE(len),m_nEncryptKey );
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::DecryptStream( CStream &stm )
{
unsigned int* pBuffer = (unsigned int*)stm.GetPtr();
int len = stm.GetSize()/8;
if (len >= 8)
{
TEA_DECODE( pBuffer,pBuffer,TEA_GETSIZE(len),m_nEncryptKey );
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::SendSecurityQueryToClient( CIPAddress &clientIP,CStream &stm )
{
if (m_pServer)
{
CServerSlot *pSlot = m_pServer->GetPacketOwner( clientIP );
if (pSlot)
{
EncryptStream(stm);
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Sending Stream to Client %d bytes",stm.GetSize()/8 );
#endif
pSlot->SendSecurityQuery(stm);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::SendSecurityRespToServer( CStream &stm )
{
if (m_pClient)
{
EncryptStream(stm);
m_pClient->SendSecurityResponse(stm);
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnServerRequest( CStream &stm )
{
DecryptStream(stm);
m_clientOutputStream.Reset();
while (!stm.EOS())
{
// When client recieves server request.
SClientCheckContext ctx;
ReadStreamRequest( ctx,stm );
// Perform required check on client.
switch (ctx.nRequestCode)
{
case DEFWALL_CHECK_PAK:
case DEFWALL_CHECK_PROTECTED_FILE:
case DEFWALL_CHECK_DLL_CODE:
OnValidateClientContext( ctx );
break;
default:
// Unknown server request.
#ifdef LOGEVENTS
if (m_bLog) CryLog( "Unknown Server Request Code" );
#endif
break;
}
}
if (m_clientOutputStream.GetSize() > 0)
{
// Send client Outputstring back to server.
SendSecurityRespToServer( m_clientOutputStream );
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnClientResponse( CIPAddress &clientIP,CStream &stm )
{
// When server recieves client response.
DecryptStream(stm);
int nServerStatusFlags = GetSystemStatusFlags();
while (!stm.EOS())
{
SClientCheckContext clientResponse;
ReadStreamResponse( clientResponse,stm );
SClientCheckContext &ctx = clientResponse;
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> OnClientResponse[%d] %s %I64x",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode );
#endif
if (clientResponse.nClientStatusFlags != nServerStatusFlags)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Wrong Vars! %d!=%d",clientResponse.nClientStatusFlags,nServerStatusFlags );
#endif
// Client have different vars set.
PunkDetected( clientIP,IServerSecuritySink::CHEAT_MODIFIED_VARS );
return;
}
// Server here checks that client response is valid and validation code match the one stored on server.
SClientCheckContext *pServerCtx = FindRequest( clientResponse.nRequestId );
if (pServerCtx)
{
// Compare client code.
if (pServerCtx->probe.nCode != clientResponse.probe.nCode)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Wrong Code! %d!=%d",clientResponse.probe.nCode,pServerCtx->probe.nCode );
#endif
// Wrong Code!
PunkDetected( clientIP,(pServerCtx->bExecutableCode)?IServerSecuritySink::CHEAT_MODIFIED_CODE:IServerSecuritySink::CHEAT_MODIFIED_FILE );
return;
}
else if (pServerCtx->nRequestCode == DEFWALL_CHECK_PAK && pServerCtx->nNumOpenedPaks != clientResponse.nNumOpenedPaks)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Wrong Num Paks! %d!=%d",clientResponse.nNumOpenedPaks,pServerCtx->nNumOpenedPaks );
#endif
// Client have different number of open packs then server!
PunkDetected( clientIP,IServerSecuritySink::CHEAT_MODIFIED_FILE );
return;
}
}
else
{
// Client send request code that server already doesnt have.
if (clientResponse.nRequestId >= m_nNextRequestId)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Too Big Request Id! %d!=%d",clientResponse.nClientStatusFlags,nServerStatusFlags );
#endif
// Possible cheating with the protocol... Client cannot recieve such a big request id before server issues it.
PunkDetected( clientIP,IServerSecuritySink::CHEAT_NET_PROTOCOL );
return;
}
else
{
// this request code was already checked.
}
}
// Remove request from list.
RemoveRequest( pServerCtx );
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnValidateClientContext( SClientCheckContext &ctx )
{
#if defined(LINUX)
return;
#else
bool bGotProbe = true;
// Perform required check on client.
switch (ctx.nRequestCode)
{
case DEFWALL_CHECK_PAK:
{
// Find out which filename to check.
ICryPak::PakInfo* pPakInfo = m_pSystem->GetIPak()->GetPakInfo();
ctx.nNumOpenedPaks = pPakInfo->numOpenPaks;
for (unsigned int i = 0; i < pPakInfo->numOpenPaks; i++)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> PAK: %s",pPakInfo->arrPaks[i].szFilePath );
#endif
string file = pPakInfo->arrPaks[i].szFilePath;
GetRelativeFilename(file);
u32 nFilenameHash = m_pNetwork->GetStringHash(file.c_str());
if (nFilenameHash == ctx.nFilenameHash)
{
// Refering to the same file.
ctx.probe.sFilename = file;
break;
}
}
m_pSystem->GetIPak()->FreePakInfo( pPakInfo );
}
break;
case DEFWALL_CHECK_PROTECTED_FILE:
{
for (unsigned int i = 0; i < m_protectedFiles.size(); i++)
{
ProtectedFile &pf = m_protectedFiles[i];
if (pf.nFilenameHash == ctx.nFilenameHash)
{
// We are refering to the same file.
ctx.probe.sFilename = pf.filename;
break;
}
}
}
break;
case DEFWALL_CHECK_DLL_CODE:
{
// Create module probe for all DLL modules.
IDataProbe::SModuleInfo *pModules;
int numModules = m_pSystem->GetIDataProbe()->GetLoadedModules( &pModules );
for (int i = 0; i < numModules; i++)
{
char sModule[_MAX_PATH];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath( pModules[i].filename.c_str(),0,0,fname,ext );
_makepath( sModule,0,0,fname,ext );
strlwr( sModule );
u32 nFilenameHash = m_pSystem->GetIDataProbe()->GetHash( sModule );
if (ctx.nFilenameHash == nFilenameHash)
{
ctx.probe.sFilename = sModule;
bGotProbe = m_pSystem->GetIDataProbe()->GetModuleProbe(ctx.probe);
}
}
}
break;
default:
// Unknown request...
#ifdef LOGEVENTS
if (m_bLog) CryLog( "Server Sent Unknown request" );
#endif
return;
}
// initialize code to be random.
ctx.probe.nCode = ((u64)rand()) | (((u64)rand())<<16) | (((u64)rand())<<32) | (((u64)rand())<<48);
// Calc hash code of this file.
if (bGotProbe && m_pSystem->GetIDataProbe()->GetCode( ctx.probe ))
{
// Code retrieved.
}
else
{
// Failed...
}
// Send code back to server.
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> OnServerRequest[%d] %s %I64x (ofs=%d,size=%d)",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode,ctx.probe.nOffset,ctx.probe.nSize );
#endif
// Every response should contain these.
ctx.nClientStatusFlags = GetSystemStatusFlags();
WriteStreamResponse( ctx,m_clientOutputStream );
#endif //LINUX
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ClearProtectedFiles()
{
//m_bLog = m_pNetwork->GetLogLevel() == 1024;
ClearAllPendingRequests();
m_protectedFiles.clear();
if (m_pNetwork->GetCheatProtectionLevel() > 0)
FillStdServerProbes();
//////////////////////////////////////////////////////////////////////////
// Add default protected files.
//////////////////////////////////////////////////////////////////////////
// Bin32\FarCry.exe
//AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+"f"+"a"+"r"+"c"+"r"+"y"+"."+"e"+"x"+"e").c_str() );
// Bin32\XRenderD3D9.exe
//AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+"x"+"r"+"e"+"n"+"d"+"e"+"r"+"d"+"3"+"d"+"9"+"."+"d"+"l"+"l").c_str() );
// Bin32\XRenderNULL.exe
//AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+"x"+"r"+"e"+"n"+"d"+"e"+"r"+"n"+"u"+"l"+"l"+"."+"d"+"l"+"l").c_str() );
// Bin32\XRenderOGL.exe
//AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+"x"+"r"+"e"+"n"+"d"+"e"+"r"+"o"+"g"+"l"+"."+"d"+"l"+"l").c_str() );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::AddProtectedFile( const char *sFilename )
{
#if !defined(LINUX)
string file = sFilename;
UnifyFilename( file );
ProtectedFile pf;
pf.filename = file;
pf.nFilenameHash = m_pNetwork->GetStringHash(pf.filename.c_str());
// Create also STD server probe if on server.
if (m_bServer && m_pNetwork->GetCheatProtectionLevel() > 0)
{
// Calc hash code of this file.
SDataProbeContext probe;
probe.nCodeInfo = rand()%3;
probe.nOffset = 0;
probe.nSize = 0xFFFFFFFF; // all file.
probe.sFilename = file;
if (!m_pSystem->GetIDataProbe()->GetRandomFileProbe( probe,false ))
return;
if (!m_pSystem->GetIDataProbe()->GetCode( probe ))
return;
pf.nHashCode = probe.nCode;
SClientCheckContext ctx;
ctx.nRequestCode = DEFWALL_CHECK_PROTECTED_FILE;
ctx.bExecutableCode = false;
ctx.nFilenameHash = pf.nFilenameHash;
ctx.probe = probe;
m_stdServerProbes.push_back(ctx);
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> CreatedFileProbe[%d] %s %I64x",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode );
#endif
}
m_protectedFiles.push_back(pf);
#endif
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ServerUpdate()
{
if (!m_bServer)
return;
// m_bLog = m_pNetwork->GetLogLevel() == 1024;
// Ignore if no standart probes yet.
if (m_stdServerProbes.empty())
return;
CTimeValue currTime = m_pNetwork->GetCurrentTime();
float fCurrSeconds = currTime.GetSeconds();
std::vector<CIPAddress> notRespondingClients;
notRespondingClients.clear();
PendingChecks::iterator it,next;
// See if any requests expired and were not responded.
for (it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it = next)
{
next = it; next++;
SClientCheckContext &ctx = *(*it);
// Check how long request is pending already.
float fRequestTime = ctx.requestTime.GetSeconds();
if (fCurrSeconds - fRequestTime > WAIT_FOR_RESPONSE_TIME)
{
// More then response seconds since request.
if (ctx.nRetries < MAX_CHECK_RETRIES)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Repeat Request[%d] (Retry:%d)",ctx.nRequestId,ctx.nRetries );
#endif
ctx.nRetries++;
ClientInfo *pClientInfo = FindClientInfo(ctx.clientIP);
if (pClientInfo)
{
// Try to issue the same request again.
CStream outstream;
IssueRequest( pClientInfo,outstream,ctx );
SendSecurityQueryToClient( ctx.clientIP,outstream );
}
else
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Delete Request[%d] Unknown Client!",ctx.nRequestId );
#endif
m_pendingChecks.erase(it); // something wrong with this request, not client for this ip.
}
}
else
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> No Resonse from Client for Request(%d)",ctx.nRequestId);
#endif
// 3 Requests without an answer.... (assume cheating client).
notRespondingClients.push_back( ctx.clientIP );
m_pendingChecks.erase(it);
}
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
{
// If any client not responding.
for (unsigned int i = 0; i < notRespondingClients.size(); i++)
{
PunkDetected( notRespondingClients[i],IServerSecuritySink::CHEAT_NOT_RESPONDING );
}
}
if (m_pNetwork->GetCheatProtectionLevel() >= CHEAT_LEVEL_RANDOMCHECKS)
{
//////////////////////////////////////////////////////////////////////////
// Go over clients and check if they need random check yet.
for (Clients::const_iterator clit = m_clients.begin(); clit != m_clients.end(); ++clit)
{
ClientInfo *ci = *clit;
if (currTime > ci->nextRandomCheckTime)
{
// Make random request to this client.
RandomClientValidation( ci );
}
}
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnAddClient( CIPAddress &clientIP )
{
// Check if this client already added.
for (Clients::iterator it = m_clients.begin(); it != m_clients.end(); ++it)
{
// This client already added.
if ((*it)->ip == clientIP)
return;
}
bool b64bit = false;
CServerSlot *pSlot = m_pServer->GetPacketOwner( clientIP );
if (pSlot)
{
if (pSlot->IsLocalSlot())
return;
b64bit = pSlot->GetClientFlags() & CLIENT_FLAGS_64BIT;
}
ClientInfo *ci = new ClientInfo;
ci->lastRequestTime = 0;
ci->nextRandomCheckTime = 0;
ci->ip = clientIP;
ci->b64bit = b64bit;
m_clients.push_back( ci );
// Start Validation.
FirstTimeClientValidation( ci );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnDisconnectClient( CIPAddress &clientIP )
{
// Remove all requests to this ip.
PendingChecks::iterator next;
for (PendingChecks::iterator it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it = next)
{
next = it; next++;
SClientCheckContext* pCtx = *it;
if (pCtx->clientIP == clientIP)
{
// This ip should be removed.
delete pCtx;
next = m_pendingChecks.erase(it);
}
}
for (Clients::iterator clit = m_clients.begin(); clit != m_clients.end(); ++clit)
{
ClientInfo *ci = *clit;
if (ci->ip == clientIP)
{
m_clients.erase(clit);
delete ci;
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
CDefenceWall::ClientInfo* CDefenceWall::FindClientInfo( CIPAddress &clientIP ) const
{
for (Clients::const_iterator clit = m_clients.begin(); clit != m_clients.end(); ++clit)
{
ClientInfo *ci = *clit;
if (ci->ip == clientIP)
{
return ci;
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::PunkDetected( CIPAddress &clientIP,int type )
{
ClientInfo *ci = FindClientInfo(clientIP);
if (ci)
{
ci->bSuspectedPunk = true;
}
m_pNetwork->PunkDetected( clientIP );
if (m_pServer)
{
if (m_pServer->GetSecuritySink())
{
m_pServer->GetSecuritySink()->CheaterFound( clientIP.GetAsUINT(),type,"" );
}
}
}
enum EDFSystemStatusFlags
{
SYS_STATUS_FORCE_NONDEVMODE = 0x0001,
SYS_STATUS_IN_DEVMODE = 0x0002,
SYS_STATUS_WAS_IN_DEVMODE = 0x0004,
SYS_STATUS_PAK_PRIORITY = 0x0008,
};
//////////////////////////////////////////////////////////////////////////
int CDefenceWall::GetSystemStatusFlags()
{
int flags = 0;
if (GetISystem()->GetForceNonDevMode())
flags |= SYS_STATUS_FORCE_NONDEVMODE;
// Check dev mode.
if (GetISystem()->IsDevMode())
flags |= SYS_STATUS_IN_DEVMODE;
// Check if was started in dev mode.
if (GetISystem()->WasInDevMode())
flags |= SYS_STATUS_WAS_IN_DEVMODE;
ICVar *pVar = GetISystem()->GetIConsole()->GetCVar("sys_PakPriority");
if (pVar && pVar->GetIVal() != 0)
flags |= SYS_STATUS_PAK_PRIORITY;
return flags;
}

182
CryNetwork/DefenceWall.h Normal file
View File

@@ -0,0 +1,182 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2001-2004.
// -------------------------------------------------------------------------
// File name: DefenceWall.h
// Version: v1.00
// Created: 25/1/2004 by Timur.
// Compilers: Visual Studio.NET 2003
// Description: ...
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef __DefenceWall_h__
#define __DefenceWall_h__
#if !defined(LINUX)
#pragma once
#endif
#include <TimeValue.h>
#include <IDataProbe.h>
#include <list>
class CNetwork;
class CServer;
class CClient;
struct SClientCheckContext
{
// Sequential id of request.
unsigned int nRequestId;
// Time of last request.
CTimeValue requestTime;
// how many times this check was tried.
int nRetries;
// Ip of the client we are requesting.
CIPAddress clientIP;
// Hash of the filename to check.
unsigned int nFilenameHash;
// Request code (what check to do).
unsigned char nRequestCode;
// Number of opened pack files.
unsigned int nNumOpenedPaks;
// Probe data.
SDataProbeContext probe;
//! True if it is code request (it depends on 32/64bit versions)
bool bExecutableCode;
//! Various flags recieved from client.
unsigned int nClientStatusFlags;
SClientCheckContext()
{
bExecutableCode = false;
nRequestCode = 0;
nRequestId = 0;
nRetries = 0;
nNumOpenedPaks = 0;
nFilenameHash = 0;
nClientStatusFlags = 0;
}
};
// No comments...
class CDefenceWall
{
public:
CDefenceWall( CNetwork *pNetwork );
~CDefenceWall();
// This is server.
void SetServer( CServer *pServer );
// This is client.
void SetClient( CClient *pClient );
void ClearProtectedFiles();
void AddProtectedFile( const char *sFilename );
void ServerUpdate();
//////////////////////////////////////////////////////////////////////////
// Some important events.
//////////////////////////////////////////////////////////////////////////
void OnAddClient( CIPAddress &clientIP );
void OnDisconnectClient( CIPAddress &clientIP );
void ClearClients();
// When client recieves server request.
void OnServerRequest( CStream &stm );
// When server recieves client response.
void OnClientResponse( CIPAddress &clientIP,CStream &stm );
private:
// This structure describe connected client on server.
struct ClientInfo
{
// Info about this client.
CIPAddress ip;
bool bSuspectedPunk;
// He`s running 64bit version.
bool b64bit;
CTimeValue lastRequestTime;
CTimeValue nextRandomCheckTime;
ClientInfo() { bSuspectedPunk = false; b64bit = false; };
};
void SendSecurityQueryToClient( CIPAddress &clientIP,CStream &stm );
void SendSecurityRespToServer( CStream &stm );
// Called on client, in response to server request.
void OnValidateClientContext( SClientCheckContext &ctx );
// Validate data on specified client IP.
void FirstTimeClientValidation( ClientInfo *pClientInfo );
void RandomClientValidation( ClientInfo *pClientInfo );
void IssueRequest( ClientInfo *pClientInfo,CStream &outstream,SClientCheckContext &ctx );
void WriteStreamRequest( SClientCheckContext &ctx,CStream &stm );
void ReadStreamRequest( SClientCheckContext &ctx,CStream &stm );
void WriteStreamResponse( SClientCheckContext &ctx,CStream &stm );
void ReadStreamResponse( SClientCheckContext &ctx,CStream &stm );
SClientCheckContext* FindRequest( int nRequestId );
void RemoveRequest( SClientCheckContext* pCtx );
void ClearAllPendingRequests();
// Make all filenames compatable.
void UnifyFilename( string &sFilename );
void GetRelativeFilename( string &sFilename );
ClientInfo* FindClientInfo( CIPAddress &clientIP ) const;
void PunkDetected( CIPAddress &clientIP,int type );
void EncryptStream( CStream &stm );
void DecryptStream( CStream &stm );
void FillStdServerProbes();
bool ServerCreateFileProbe( const char *sFilename,SClientCheckContext &ctx,bool bRandomPart );
bool ServerCreateModuleProbe( const char *sFilename,SClientCheckContext &ctx );
int GetSystemStatusFlags();
private:
typedef std::list<SClientCheckContext*> PendingChecks;
PendingChecks m_pendingChecks;
CNetwork *m_pNetwork;
unsigned int m_nNextRequestId;
ISystem *m_pSystem;
CServer *m_pServer;
CClient *m_pClient;
// True if server, false if client.
bool m_bServer;
bool m_b64bit; // Running in 64bit version.
bool m_bLog;
unsigned int m_nEncryptKey[4];
// Output Stream.
CStream m_clientOutputStream;
struct ProtectedFile
{
string filename;
u32 nFilenameHash;
uint64 nHashCode;
};
// List of protected files.
std::vector<ProtectedFile> m_protectedFiles;
// List of connected clients.
// For up to 32-64 clients, vector is oky.
typedef std::vector<ClientInfo*> Clients;
Clients m_clients;
// List of Standart probes checked for each client, (stored on server only).
// Updated on each call to ClearProtectedFiles.
std::vector<SClientCheckContext> m_stdServerProbes;
int m_nNumOpenedPacksOnServer;
};
#endif // __DefenceWall_h__

86
CryNetwork/Interfaces.h Normal file
View File

@@ -0,0 +1,86 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: Interfaces.h
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#ifndef _INTERFACES_H_
#define _INTERFACES_H_
class CServerSlot;
struct _IServerServices
{
virtual bool Send(CStream &stm, CIPAddress &ip) = 0;
virtual void UnregisterSlot(CIPAddress &ip) = 0;
virtual void OnDestructSlot( const CServerSlot *inpServerSlot ) = 0;
virtual void GetProtocolVariables(struct CNPServerVariables &sv) = 0;
};
struct _IEndpointUser
{
virtual bool Send(CStream &stm) = 0;
virtual void OnData(CStream &stm) = 0;
// virtual unsigned char GetID() = 0;
};
struct _ICCPUser :
public _IEndpointUser
{
//!
virtual void OnCCPSetup(CStream &stm) = 0;
//! this is a server->client packet
virtual void OnCCPConnect(CStream &stm) = 0;
//!
virtual void OnCCPConnectResp(CStream &stm) = 0;
//! this is a server->client packet
virtual void OnCCPContextSetup(CStream &stm) = 0;
//!
virtual void OnCCPContextReady(CStream &stm) = 0;
//! this is a server->client packet
virtual void OnCCPServerReady() = 0;
//!
virtual void OnCCPDisconnect(const char *szCause) = 0;
// Sends a security check message, client must respond to it.
virtual void OnCCPSecurityQuery(CStream &stm) = 0;
// Respond to a security message, will be checked on server.
virtual void OnCCPSecurityResp(CStream &stm) = 0;
// Punk buster message.
virtual void OnCCPPunkBusterMsg(CStream &stm) = 0;
};
struct _IServerSlotServices:
public _ICCPUser
{
virtual void Start(unsigned char cClientID,CIPAddress &ip) = 0;
virtual bool SendConnect() = 0;
virtual bool SendContextSetup() = 0;
virtual bool SendServerReady() = 0;
virtual bool SendDisconnect(const char *szCause) = 0;
virtual void OnConnect() = 0;
virtual void OnContextReady() = 0;
virtual void OnDisconnect(const char *szCause) = 0;
};
struct _IClientServices :
public _ICCPUser
{
virtual bool SendSetup() = 0;
virtual bool SendConnectResp() = 0;
virtual bool SendContextReady() = 0;
virtual bool SendDisconnect(const char *szCause) = 0;
virtual void OnConnect() = 0;
virtual void OnContextSetup() = 0;
virtual void OnServerReady() = 0;
virtual void OnDisconnect(const char *szCause) = 0;
};
#endif //_INTERFACES_H_

5
CryNetwork/MSSCCPRJ.SCC Normal file
View File

@@ -0,0 +1,5 @@
SCC = This is a source code control file
[CryNetwork.vcproj]
SCC_Aux_Path = "P4SCC#perforce:1666##marcoc_code##PC018"
SCC_Project_Name = Perforce Project

View File

@@ -0,0 +1,291 @@
#include "stdafx.h"
#include "ILog.h"
#include "CNP.h"
#include "ITimer.h"
#include "NETServerSnooper.h"
//-------------------------------------------------------------------------------------------------
CNETServerSnooper::CNETServerSnooper()
: m_iWaitingCount(0),
m_pSink(0),
m_pSystem(0),
cl_snooptimeout(0),
cl_snoopretries(0),
cl_snoopcount(0)
{
}
//-------------------------------------------------------------------------------------------------
CNETServerSnooper::~CNETServerSnooper()
{
}
//-------------------------------------------------------------------------------------------------
bool CNETServerSnooper::Create(ISystem *pSystem, INETServerSnooperSink *pSink)
{
assert(pSystem);
assert(pSink);
m_pSystem = pSystem;
m_pSink = pSink;
if (NET_FAILED(m_sSocket.Create()))
{
return 0;
}
cl_snoopcount = m_pSystem->GetIConsole()->GetCVar("cl_snoopcount");
cl_snoopretries = m_pSystem->GetIConsole()->GetCVar("cl_snoopretries");
cl_snooptimeout = m_pSystem->GetIConsole()->GetCVar("cl_snooptimeout");
return 1;
}
//-------------------------------------------------------------------------------------------------
void CNETServerSnooper::Release()
{
m_hmServerTable.clear();
delete this;
}
//-------------------------------------------------------------------------------------------------
void CNETServerSnooper::Update(unsigned int dwTime)
{
if (m_hmServerTable.empty())
{
return;
}
m_dwCurrentTime = dwTime;
int iReceived = 0;
static CStream stmBuffer;
static CIPAddress ipFrom;
do
{
iReceived = 0;
stmBuffer.Reset();
m_sSocket.Receive(stmBuffer.GetPtr(), stmBuffer.GetAllocatedSize(), iReceived, ipFrom);
if(iReceived > 0)
{
stmBuffer.SetSize(BYTES2BITS(iReceived));
ProcessPacket(stmBuffer, ipFrom);
}
} while(iReceived > 0);
// if we have waiting servers
if (m_iWaitingCount > 0)
{
// handle timeouts
ProcessTimeout();
}
int iMaxWaiting = NET_SNOOPER_MAXWAITING;
if (cl_snoopcount && cl_snoopcount->GetIVal() > 0)
{
iMaxWaiting = cl_snoopcount->GetIVal();
}
while (m_iWaitingCount < iMaxWaiting)
{
if (!ProcessNext())
{
break;
}
}
}
void CNETServerSnooper::OnReceivingPacket( const unsigned char inPacketID, CStream &stmPacket, CIPAddress &ip )
{
}
//-------------------------------------------------------------------------------------------------
void CNETServerSnooper::AddServer(const CIPAddress &ip)
{
NETSnooperServer Server;
Server.bDoing = 0;
Server.cTry = 0;
Server.dwStartTime = 0;
Server.dwTimeout = 0;
Server.ipAddress = ip;
m_hmServerTable.insert(std::pair<CIPAddress, NETSnooperServer>(Server.ipAddress, Server));
}
//-------------------------------------------------------------------------------------------------
void CNETServerSnooper::AddServerList(const std::vector<CIPAddress> &vIP)
{
for (std::vector<CIPAddress>::const_iterator it = vIP.begin(); it != vIP.end(); ++it)
{
AddServer(*it);
}
}
//-------------------------------------------------------------------------------------------------
void CNETServerSnooper::ClearList()
{
m_hmServerTable.clear();
m_iWaitingCount = 0;
}
//-------------------------------------------------------------------------------------------------
void CNETServerSnooper::QueryServer(CIPAddress &ip)
{
CStream stmPacket;
CQPInfoRequest cqpInfoRequest("status");
cqpInfoRequest.Save(stmPacket);
m_sSocket.Send(stmPacket.GetPtr(), BITS2BYTES(stmPacket.GetSize()), (CIPAddress *)&ip);
}
//-------------------------------------------------------------------------------------------------
void CNETServerSnooper::ProcessPacket(CStream &stmPacket, CIPAddress &ip)
{
// since we are not expecting any response
// since is either a timedout server,
// or is some undesirable packet
if (m_iWaitingCount < 1)
{
return;
}
CNP cnpPacket;
cnpPacket.LoadAndSeekToZero(stmPacket);
if (cnpPacket.m_cFrameType == FT_CQP_INFO_RESPONSE)
{
NETSnooperServer *pServer = 0;
HMServerTableItor it = m_hmServerTable.find(ip);
if (it == m_hmServerTable.end())
{
return;
}
pServer = &(it->second);
if (!pServer->bDoing) // was this expected ?
{
return;
}
// we got a good response
// so process it
CQPInfoResponse cqpInfoResponse;
cqpInfoResponse.Load(stmPacket);
if(m_pSink)
{
m_pSink->OnNETServerFound(ip, cqpInfoResponse.szResponse, m_dwCurrentTime - pServer->dwStartTime);
}
--m_iWaitingCount;
assert(m_iWaitingCount >= 0);
// remove server from table
m_hmServerTable.erase(it);
}
}
//-------------------------------------------------------------------------------------------------
void CNETServerSnooper::ProcessTimeout()
{
NETSnooperServer *pServer = 0;
HMServerTableItor it = m_hmServerTable.begin();
unsigned int dwRetry = NET_SNOOPER_RETRY;
unsigned int dwTimeDelta = NET_SNOOPER_TIMEOUT;
if (cl_snoopretries && cl_snoopretries->GetIVal() > 0)
{
dwRetry = cl_snoopretries->GetIVal();
}
if (cl_snooptimeout && cl_snooptimeout->GetFVal() > 0)
{
dwTimeDelta = (unsigned int)(cl_snooptimeout->GetFVal() * 1000.0f);
}
while(it != m_hmServerTable.end())
{
pServer = &(it->second);
if ((m_dwCurrentTime >= pServer->dwTimeout) && pServer->bDoing)
{
pServer->cTry++;
pServer->dwStartTime = m_dwCurrentTime;
pServer->dwTimeout = m_dwCurrentTime + dwTimeDelta;
if (pServer->cTry > dwRetry)
{
m_pSink->OnNETServerTimeout(it->second.ipAddress);
// quit snooping this server
#if defined(LINUX) //dunno why the replaced statement does not work on its own
HMServerTableItor itTemp = it;
itTemp++;
m_hmServerTable.erase(it);
it = itTemp;
#else
it = m_hmServerTable.erase(it);
#endif
--m_iWaitingCount;
assert(m_iWaitingCount >= 0);
}
else
{
QueryServer(pServer->ipAddress);
++it;
}
}
else
{
++it;
}
}
}
//-------------------------------------------------------------------------------------------------
bool CNETServerSnooper::ProcessNext()
{
NETSnooperServer *pServer = 0;
HMServerTableItor it = m_hmServerTable.begin();
unsigned int dwTimeDelta = NET_SNOOPER_TIMEOUT;
if (cl_snooptimeout && cl_snooptimeout->GetFVal() > 0)
{
dwTimeDelta = (unsigned int)(cl_snooptimeout->GetFVal() * 1000.0f);
}
while(it != m_hmServerTable.end())
{
pServer = &(it->second);
if (pServer->bDoing)
{
++it;
continue;
}
pServer->dwStartTime = m_dwCurrentTime;
pServer->dwTimeout = m_dwCurrentTime + dwTimeDelta;
pServer->bDoing = 1;
QueryServer(pServer->ipAddress);
m_iWaitingCount++;
return 1;
}
return 0;
}

View File

@@ -0,0 +1,83 @@
#ifndef NETSERVERSNOOPER_H
#define NETSERVERSNOOPER_H
#include <INetwork.h>
#if defined(LINUX) || defined(WIN64)
#include <map>
#endif
#ifdef WIN64
#define hash_map map
#else
#if defined(LINUX)
#include <ext/hash_map>
#else
#include <hash_map>
#endif
#endif
#include <IConsole.h>
#define NET_SNOOPER_RETRY (2)
#define NET_SNOOPER_MAXWAITING (20)
#define NET_SNOOPER_TIMEOUT (1500) // 1 seconds timeout per try
typedef struct NETSnooperServer
{
CIPAddress ipAddress; //!<
DWORD dwStartTime; //!<
DWORD dwTimeout; //!< when current time >= dwTimeout, increase cTry, and retry
byte cTry; //!< when cTry > NET_SNOOPER_RETRY, remove from list
bool bDoing; //!<
} NETSnooperServer;
typedef std::map<CIPAddress, NETSnooperServer> HMServerTable;
typedef std::map<CIPAddress, NETSnooperServer>::iterator HMServerTableItor;
class CNETServerSnooper: public INETServerSnooper, public INetworkPacketSink
{
public:
//! constructor
CNETServerSnooper();
//! destructor
~CNETServerSnooper();
bool Create(ISystem *pSystem, INETServerSnooperSink *pSink);
// interface INetworkPacketSink --------------------------------------
virtual void OnReceivingPacket( const unsigned char inPacketID, CStream &stmPacket, CIPAddress &ip );
// interface INETServerSnooper ----------------------------------------
virtual void Release();
virtual void Update(unsigned int dwTime);
virtual void AddServer(const CIPAddress &ip);
virtual void AddServerList(const std::vector<CIPAddress> &vIP);
virtual void ClearList();
private: // ------------------------------------------------------------
void QueryServer(CIPAddress &ip);
void ProcessPacket(CStream &stmPacket, CIPAddress &ip);
void ProcessTimeout();
bool ProcessNext();
ISystem * m_pSystem; //!<
unsigned int m_dwCurrentTime; //!<
int m_iWaitingCount; //!<
INETServerSnooperSink * m_pSink; //!<
CDatagramSocket m_sSocket; //!<
HMServerTable m_hmServerTable; //!<
ICVar * cl_snooptimeout; //!<
ICVar * cl_snoopretries; //!<
ICVar * cl_snoopcount; //!<
};
#endif // NETSERVERSNOOPER_H

818
CryNetwork/Network.cpp Normal file
View File

@@ -0,0 +1,818 @@
// Network.cpp: implementation of the CNetwork class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Network.h"
#include "Client.h"
#include "ClientLocal.h"
#include "ServerSlot.h"
#include "ServerSnooper.h"
#include "NETServerSnooper.h"
#include "Server.h"
#include "RConSystem.h"
#include "DefenceWall.h"
#if !defined(NOT_USE_PUNKBUSTER_SDK)
#include "PunkBusterInterface.h"
#endif
#include "ITimer.h"
#ifndef NOT_USE_UBICOM_SDK
#include "NewUbisoftClient.h" // NewUbisoftClient
#include "ScriptObjectNewUbisoftClient.h" // CScriptObjectNewUbisoftClient
#endif // NOT_USE_UBICOM_SDK
#define ANTI_CHEATS
#include "platform.h"
#if defined(LINUX)
#include "INetwork.h"
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
unsigned int CNetwork::m_nCryNetInitialized = 0;
struct CryNetError CNetwork::m_neNetErrors[]=
{
{NET_OK, "No Error"},
{NET_FAIL, "Generic Error"},
// SOCKET
{NET_EINTR, "WSAEINTR - interrupted function call"},
{NET_EBADF, "WSAEBADF - Bad file number"},
{NET_EACCES, "WSAEACCES - error in accessing socket"},
{NET_EFAULT, "WSAEFAULT - bad address"},
{NET_EINVAL, "WSAEINVAL - invalid argument"},
{NET_EMFILE, "WSAEMFILE - too many open files"},
{NET_EWOULDBLOCK, "WSAEWOULDBLOCK - resource temporarily unavailable"},
{NET_EINPROGRESS, "WSAEINPROGRESS - operation now in progress"},
{NET_EALREADY, "WSAEALREADY - operation already in progress"},
{NET_ENOTSOCK, "WSAENOTSOCK - socket operation on non-socket"},
{NET_EDESTADDRREQ, "WSAEDESTADDRREQ - destination address required"},
{NET_EMSGSIZE, "WSAEMSGSIZE - message to long"},
{NET_EPROTOTYPE, "WSAEPROTOTYPE - protocol wrong type for socket"},
{NET_ENOPROTOOPT, "WSAENOPROTOOPT - bad protocol option"},
{NET_EPROTONOSUPPORT, "WSAEPROTONOSUPPORT - protocol not supported"},
{NET_ESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT - socket type not supported"},
{NET_EOPNOTSUPP, "WSAEOPNOTSUPP - operation not supported"},
{NET_EPFNOSUPPORT, "WSAEPFNOSUPPORT - protocol family not supported"},
{NET_EAFNOSUPPORT, "WSAEAFNOSUPPORT - address family not supported by protocol"},
{NET_EADDRINUSE, "WSAEADDRINUSE - address is in use"},
{NET_EADDRNOTAVAIL, "WSAEADDRNOTAVAIL - address is not valid in context"},
{NET_ENETDOWN, "WSAENETDOWN - network is down"},
{NET_ENETUNREACH, "WSAENETUNREACH - network is unreachable"},
{NET_ENETRESET, "WSAENETRESET - network dropped connection on reset"},
{NET_ECONNABORTED, "WSACONNABORTED - software caused connection aborted"},
{NET_ECONNRESET, "WSAECONNRESET - connection reset by peer"},
{NET_ENOBUFS, "WSAENOBUFS - no buffer space available"},
{NET_EISCONN, "WSAEISCONN - socket is already connected"},
{NET_ENOTCONN, "WSAENOTCONN - socket is not connected"},
{NET_ESHUTDOWN, "WSAESHUTDOWN - cannot send after socket shutdown"},
{NET_ETOOMANYREFS, "WSAETOOMANYREFS - Too many references: cannot splice"},
{NET_ETIMEDOUT, "WSAETIMEDOUT - connection timed out"},
{NET_ECONNREFUSED, "WSAECONNREFUSED - connection refused"},
{NET_ELOOP, "WSAELOOP - Too many levels of symbolic links"},
{NET_ENAMETOOLONG, "WSAENAMETOOLONG - File name too long"},
{NET_EHOSTDOWN, "WSAEHOSTDOWN - host is down"},
{NET_EHOSTUNREACH, "WSAEHOSTUNREACH - no route to host"},
{NET_ENOTEMPTY, "WSAENOTEMPTY - Cannot remove a directory that is not empty"},
{NET_EUSERS, "WSAEUSERS - Ran out of quota"},
{NET_EDQUOT, "WSAEDQUOT - Ran out of disk quota"},
{NET_ESTALE, "WSAESTALE - File handle reference is no longer available"},
{NET_EREMOTE, "WSAEREMOTE - Item is not available locally"},
// extended winsock errors(not BSD compliant)
#ifdef _WIN32
{NET_EPROCLIM, "WSAEPROCLIM - too many processes"},
{NET_HOST_NOT_FOUND, "WSAHOST_NOT_FOUND - host not found"},
{NET_TRY_AGAIN, "WSATRY_AGAIN - non-authoritative host not found"},
{NET_NO_RECOVERY, "WSANO_RECOVERY - non-recoverable error"},
{NET_NO_DATA, "WSANO_DATA - valid name, no data record of requested type"},
{NET_NO_ADDRESS, "WSANO_ADDRESS - (undocumented)"},
{NET_SYSNOTREADY, "WSASYSNOTREADY - network subsystem is unavailable"},
{NET_VERNOTSUPPORTED, "WSAVERNOTSUPPORTED - winsock.dll verison out of range"},
{NET_NOTINITIALISED, "WSANOTINITIALISED - WSAStartup not yet performed"},
{NET_NO_DATA, "WSANO_DATA - valid name, no data record of requested type"},
{NET_EDISCON, "WSAEDISCON - graceful shutdown in progress"},
#endif
// XNetwork specific
{NET_NOIMPL, "XNetwork - Function not implemented"},
{NET_SOCKET_NOT_CREATED, "XNetwork - socket not yet created"},
{0, 0} // sentinel
};
CNetwork::CNetwork()
{
m_dwLocalIP=0;
m_pNetCompressPackets = 0;
m_pNetLog = 0;
m_pDefenceWall = 0;
#if !defined(NOT_USE_PUNKBUSTER_SDK)
m_pPunkBuster = 0;
#endif
m_bHaveServer = false;
m_bHaveClient = false;
#ifndef NOT_USE_UBICOM_SDK
m_pScriptObjectNewUbisoftClient=0;
m_pUbiSoftClient=0;
#endif // NOT_USE_UBICOM_SDK
m_pScriptSystem=0;
m_pClient=0;
}
CNetwork::~CNetwork()
{
#ifndef NOT_USE_UBICOM_SDK
SAFE_DELETE(m_pUbiSoftClient);
SAFE_DELETE(m_pScriptObjectNewUbisoftClient);
CScriptObjectNewUbisoftClient::ReleaseTemplate();
#endif // NOT_USE_UBICOM_SDK
SAFE_RELEASE( m_pNetCompressPackets );
SAFE_RELEASE( m_pNetLog );
SAFE_DELETE( m_pDefenceWall );
#if !defined(NOT_USE_PUNKBUSTER_SDK)
SAFE_DELETE( m_pPunkBuster );
#endif
}
ICompressionHelper *CNetwork::GetCompressionHelper()
{
return &m_Compressor;
}
void CNetwork::SetLocalIP( const char *szLocalIP )
{
CIPAddress ip;
ip.Set(0,(char *)szLocalIP);
m_dwLocalIP=ip.GetAsUINT();
#ifndef NOT_USE_UBICOM_SDK
// Ubi.com cannot change the IP later than creation
{
CIPAddress localip;
localip.Set(0,GetLocalIP());
m_pUbiSoftClient=new NewUbisoftClient(localip.GetAsString());
m_pScriptObjectNewUbisoftClient=new CScriptObjectNewUbisoftClient;
CScriptObjectNewUbisoftClient::InitializeTemplate(m_pScriptSystem);
m_pScriptObjectNewUbisoftClient->Init(m_pScriptSystem,m_pSystem,m_pUbiSoftClient);
}
#endif // NOT_USE_UBICOM_SDK
}
DWORD CNetwork::GetLocalIP() const
{
return m_dwLocalIP;
}
bool CNetwork::Init( IScriptSystem *pScriptSystem )
{
assert(pScriptSystem);
m_pScriptSystem = pScriptSystem;
if(CNetwork::m_nCryNetInitialized)
return true;
#if !defined(PS2) && !defined(LINUX)
WORD wVersionRequested;
WSADATA wsaData;
int err;
// WARNING :use a later version require a change in the multicast code with
// a WS2's specific one
// not compatible with other platforms
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
return false;
}
if (LOBYTE(wsaData.wVersion) != 1 ||
HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return false;
}
#endif
CNetwork::m_nCryNetInitialized+=1;
int n=0;
while(m_neNetErrors[n].sErrorDescription!='\0'){
m_mapErrors[m_neNetErrors[n].nrErrorCode]=m_neNetErrors[n].sErrorDescription;
n++;
}
/// Register Console Vars related to network.
m_pSystem = GetISystem();
CreateConsoleVars();
#ifdef ANTI_CHEATS
m_pDefenceWall = new CDefenceWall(this);
#endif //ANTI_CHEATS
#if !defined(NOT_USE_PUNKBUSTER_SDK)
m_pPunkBuster = new CPunkBusterInterface(this);
PBsdk_SetPointers ( m_pPunkBuster ) ;
#endif
LogNetworkInfo();
return true;
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::CreateConsoleVars()
{
m_pNetCompressPackets = m_pSystem->GetIConsole()->CreateVariable( "net_compress_packets","1",0 );
m_pNetLog = m_pSystem->GetIConsole()->CreateVariable( "net_log","0",0 );
//m_pNetCheatProtection = m_pSystem->GetIConsole()->CreateVariable( "net_cheatprotection","0",VF_DUMPTODISK );
m_pNetCheatProtection = m_pSystem->GetIConsole()->CreateVariable( "net_cheatprotection","0",VF_READONLY );
m_pNetCheatProtection->ForceSet("0");
m_pSystem->GetIConsole()->CreateVariable("sv_ServerType", "LAN",0,
"Specifies the server connection type (next server creation, not case sensitive) 'UBI', 'LAN' or 'NET'\n"
"Usage: sv_ServerType UBI\n");
m_pSystem->GetIConsole()->CreateVariable("sv_regserver_port","",0,
"Sets the local port for a registering the server on Ubi.com GS.\n"
"Usage: sv_regserver_port portnumber\n"
"Default is '0' (first free).");
m_pSystem->GetIConsole()->CreateVariable("sv_authport","",0,
"Sets the local port for a CDKey authentication comunications.\n"
"Usage: sv_auth_port portnumber\n"
"Default is '0' (first free).");
}
//////////////////////////////////////////////////////////////////////////
IClient *CNetwork::CreateClient(IClientSink *pSink, bool bLocal)
{
assert(!m_pClient); // only one client at a time is allowed
m_bHaveClient = true;
if(bLocal)
{
CClientLocal *pClient=new CClientLocal(this,pSink);
m_pClient=pClient;
return pClient;
}
else
{
CClient *pClient = new CClient( this );
if(!pClient->Init(pSink))
{
delete pClient;
return NULL;
}
if (GetCheatProtectionLevel() > 0)
{
if (m_pDefenceWall)
m_pDefenceWall->SetClient(pClient);
}
m_pClient=pClient;
return pClient;
}
return NULL;
}
IServer *CNetwork::CreateServer(IServerSlotFactory *pFactory, WORD nPort, bool listen)
{
m_bHaveServer = true;
CServer *pServer = new CServer(this);
if (!pServer->Init(pFactory, nPort, listen))
{
delete pServer;
return NULL;
}
m_mapServers.insert(MapServersItor::value_type(nPort, pServer));
if (GetCheatProtectionLevel() > 0)
{
if (m_pDefenceWall)
m_pDefenceWall->SetServer(pServer);
}
IConsole *pConsole = GetISystem()->GetIConsole();
assert(pConsole);
ICVar *sv_punkbuster = pConsole->GetCVar("sv_punkbuster");
if (sv_punkbuster && sv_punkbuster->GetIVal() != 0)
{
InitPunkbusterServer(listen, pServer);
// if this is a lan server
if(pServer->GetServerType()==eMPST_LAN)
{
// set pb variables to lan defaults
pConsole->ExecuteString("pb_sv_lan 1", 0, 1);
pConsole->ExecuteString("pb_sv_guidrelax 7", 0, 1);
}
}
#ifndef NOT_USE_UBICOM_SDK
m_pUbiSoftClient->Server_SetGamePort(nPort); // set the connection to the server
#endif // NOT_USE_UBICOM_SDK
LockPunkbusterCVars();
return pServer;
}
INETServerSnooper *CNetwork::CreateNETServerSnooper(INETServerSnooperSink *pSink)
{
CNETServerSnooper *pSnooper = new CNETServerSnooper;
if (!pSnooper->Create(GetISystem(), pSink))
{
delete pSnooper;
return 0;
}
return pSnooper;
}
IRConSystem *CNetwork::CreateRConSystem()
{
CRConSystem *pRCon = new CRConSystem;
if(!pRCon->Create(GetISystem()))
{
delete pRCon;
return 0;
}
return pRCon;
}
IServerSnooper *CNetwork::CreateServerSnooper(IServerSnooperSink *pSink)
{
CServerSnooper *pSnooper=new CServerSnooper;
if(!pSnooper->Init(pSink))
{
delete pSnooper;
return NULL;
}
return pSnooper;
}
CServerSlotLocal *CNetwork::ConnectToLocalServerSlot(CClientLocal *pClient, WORD wPort)
{
MapServersItor itor;
if(m_mapServers.empty())
return NULL;
//check if the local server exists
itor=m_mapServers.find(wPort);
if(itor==m_mapServers.end()){
itor=m_mapServers.begin();
}
//<<FIXME>> make the port variable
CIPAddress ip(0,"127.0.0.1");
CServerSlotLocal *pServerSlot=new CServerSlotLocal(itor->second,pClient,ip,this);
itor->second->RegisterLocalServerSlot(pServerSlot,ip);
return pServerSlot;
}
const char *CNetwork::EnumerateError(NRESULT err)
{
ERROR_MAPItor itor;
itor = m_mapErrors.find(err);
if (itor != m_mapErrors.end())
{
return itor->second;
}
return "Unknown";
}
void CNetwork::Release()
{
CNetwork::m_nCryNetInitialized -= 1;
if (CNetwork::m_nCryNetInitialized)
return;
#if !defined(LINUX)
#if !defined(PS2)
else
WSACleanup();
#else
CSocketManager::releaseImpl();
delete &ISocketManagerImplementation::getInstance();
#endif
#endif
delete this;
}
IServer *CNetwork::GetServerByPort( const WORD wPort )
{
//check if the local server exists
MapServersItor itor=m_mapServers.find(wPort);
if(itor==m_mapServers.end())
return 0; // not found
return itor->second;
}
void CNetwork::UnregisterServer(WORD wPort)
{
#ifndef NOT_USE_UBICOM_SDK
// We have to tell Ubisoft that the client has finished the game.
// If ubisoft is not running this won't do anything.
m_pUbiSoftClient->Client_LeaveGameServer();
#endif // NOT_USE_UBICOM_SDK
if(m_bHaveServer)
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
m_pPunkBuster->ShutDown(false);
#endif
}
m_mapServers.erase(wPort);
}
void CNetwork::UnregisterClient( IClient *pClient )
{
assert(pClient);
assert(m_pClient==pClient);
m_pClient=0;
if(m_bHaveClient)
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
m_pPunkBuster->ShutDown(true);
#endif
}
}
void CNetwork::GetMemoryStatistics(ICrySizer *pSizer)
{
pSizer->AddObject(m_neNetErrors,sizeof(m_neNetErrors));
#ifndef NOT_USE_UBICOM_SDK
pSizer->AddObject( m_pScriptObjectNewUbisoftClient, sizeof *m_pScriptObjectNewUbisoftClient);
#endif // NOT_USE_UBICOM_SDK
}
bool CNetwork::IsPacketCompressionEnabled() const
{
return m_pNetCompressPackets->GetIVal() != 0;
}
//////////////////////////////////////////////////////////////////////////
CTimeValue CNetwork::GetCurrentTime()
{
return m_pSystem->GetITimer()->GetCurrTimePrecise();
}
//////////////////////////////////////////////////////////////////////////
u32 CNetwork::GetStringHash( const char *szString )
{
#if defined(LINUX)
return 0;
#else
#ifdef _DATAPROBE
return m_pSystem->GetIDataProbe()->GetHash( szString );
#else
return 0;
#endif
#endif
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::PunkDetected( CIPAddress &ip )
{
// Disconnect.
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::UpdateNetwork()
{
#ifndef NOT_USE_UBICOM_SDK
// Update ubisoft
m_pUbiSoftClient->Update();
#endif // NOT_USE_UBICOM_SDK
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::OnClientUpdate()
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
m_pPunkBuster->Update(true);
#endif
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::OnServerUpdate()
{
if (m_pDefenceWall && GetCheatProtectionLevel() > 0)
m_pDefenceWall->ServerUpdate();
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
m_pPunkBuster->Update(false);
#endif
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::ClearProtectedFiles()
{
if (m_pDefenceWall)
m_pDefenceWall->ClearProtectedFiles();
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::AddProtectedFile( const char *sFilename )
{
if (m_pDefenceWall)
m_pDefenceWall->AddProtectedFile( sFilename );
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::AddClientToDefenceWall( CIPAddress &clientIP )
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
//we want PB to work on devmode servers so handle this first
if (m_pPunkBuster)
m_pPunkBuster->OnAddClient(clientIP);
#endif
// if in dev mode ignore it.
if (!m_pSystem->GetForceNonDevMode())
return;
if (m_pDefenceWall && GetCheatProtectionLevel() > 0)
m_pDefenceWall->OnAddClient( clientIP );
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::RemoveClientFromDefenceWall( CIPAddress &clientIP )
{
if (m_pDefenceWall)
m_pDefenceWall->OnDisconnectClient( clientIP );
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
m_pPunkBuster->OnDisconnectClient(clientIP);
#endif
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::OnSecurityMsgResponse( CIPAddress &ipAddress,CStream &stm )
{
if (m_pDefenceWall)
m_pDefenceWall->OnClientResponse(ipAddress,stm);
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::OnSecurityMsgQuery( CStream &stm )
{
if (m_pDefenceWall)
m_pDefenceWall->OnServerRequest(stm);
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::OnCCPPunkBusterMsg( CIPAddress &ipAddress,CStream &stm )
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
m_pPunkBuster->OnCCPPunkBusterMsg( ipAddress,stm );
#endif
}
//////////////////////////////////////////////////////////////////////////
int CNetwork::GetLogLevel()
{
return m_pNetLog->GetIVal();
}
//////////////////////////////////////////////////////////////////////////
int CNetwork::GetCheatProtectionLevel()
{
//return m_pNetCheatProtection->GetIVal();
return 0; // disable the cheat protection..
}
//////////////////////////////////////////////////////////////////////////
bool CNetwork::CheckPBPacket(CStream &stmPacket,CIPAddress &ip)
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
return m_pPunkBuster->CheckPBPacket(stmPacket,ip);
#endif
return true;
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::ValidateClient( CServerSlot *pSlot )
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
return m_pPunkBuster->ValidateClient( pSlot );
#endif
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::InitPunkbusterClient(CClient *pClient)
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
{
m_pPunkBuster->Init(true, false);
m_pPunkBuster->SetClient(pClient);
}
#endif
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::InitPunkbusterClientLocal(CClientLocal *pClientLocal)
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
{
m_pPunkBuster->Init(true, true);
m_pPunkBuster->SetClientLocal(pClientLocal);
}
#endif
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::InitPunkbusterServer(bool bLocal, CServer *pServer)
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
{
m_pPunkBuster->Init(false, bLocal);
m_pPunkBuster->SetServer(pServer);
}
#endif
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::LockPunkbusterCVars()
{
#if !defined(NOT_USE_PUNKBUSTER_SDK)
if (m_pPunkBuster)
{
m_pPunkBuster->LockCVars();
}
#endif
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::LogNetworkInfo()
{
DWORD i;
char buf[256];
struct hostent *hp;
if(!gethostname(buf, sizeof(buf)))
{
hp = gethostbyname(buf);
if (hp)
{
CryLogAlways("network hostname: %s",hp->h_name);
i = 0;
while(hp->h_aliases[i])
{
CryLogAlways(" alias: %s\n", hp->h_aliases[i]);
i++;
}
i = 0;
while(hp->h_addr_list[i])
{
sockaddr_in temp;
memcpy(&(temp.sin_addr), hp->h_addr_list[i], hp->h_length);
#if defined(LINUX)
const in_addr_windows *pin_addr_win = reinterpret_cast<const in_addr_windows*>(&temp.sin_addr);
CryLogAlways(" ip:%d.%d.%d.%d", // port:%d family:%x",
(int)(pin_addr_win->S_un.S_un_b.s_b1),
(int)(pin_addr_win->S_un.S_un_b.s_b2),
(int)(pin_addr_win->S_un.S_un_b.s_b3),
(int)(pin_addr_win->S_un.S_un_b.s_b4));
#else
CryLogAlways(" ip:%d.%d.%d.%d", // port:%d family:%x",
(int)(temp.sin_addr.S_un.S_un_b.s_b1),
(int)(temp.sin_addr.S_un.S_un_b.s_b2),
(int)(temp.sin_addr.S_un.S_un_b.s_b3),
(int)(temp.sin_addr.S_un.S_un_b.s_b4));
// (int)temp.sin_port,(unsigned int)temp.sin_family);
#endif
i++;
}
}
}
}
//////////////////////////////////////////////////////////////////////////
IClient *CNetwork::GetClient()
{
return m_pClient;
}
//////////////////////////////////////////////////////////////////////////
void CNetwork::OnAfterServerLoadLevel( const char *szServerName, const uint32 dwPlayerCount, const WORD wPort )
{
assert(szServerName);
assert(dwPlayerCount>0);
// m_pSystem->GetILog()->Log("Ubi.com DEBUG OnAfterServerLoadLevel() 1");
IServer *pServer=GetServerByPort(wPort);
if(!pServer)
{
assert(pServer); // internal error
return;
}
#ifndef NOT_USE_UBICOM_SDK
if(m_pSystem->GetIGame()->GetModuleState(EGameMultiplayer) && pServer->GetServerType()!=eMPST_LAN)
{
// if it's a ubi-server, publish the server
if(pServer->GetServerType()==eMPST_UBI)
m_pUbiSoftClient->Server_CreateServer(szServerName,dwPlayerCount);
// if it's a internet server, check CDKey
// m_pSystem->GetILog()->Log("Ubi.com DEBUG OnAfterServerLoadLevel() 2");
m_pUbiSoftClient->Server_CheckCDKeys(1);
}
else
{
// m_pSystem->GetILog()->Log("Ubi.com DEBUG OnAfterServerLoadLevel() 3");
m_pUbiSoftClient->Server_DestroyServer();
m_pUbiSoftClient->Server_CheckCDKeys(0);
}
#endif // NOT_USE_UBICOM_SDK
}
bool CNetwork::VerifyMultiplayerOverInternet()
{
#ifndef NOT_USE_UBICOM_SDK
if(!m_pUbiSoftClient->Client_IsConnected())
{
// if this is a ubi.com server, and we don't have a ubi.com connection
// disconnect, login, and retry
GetClient()->Disconnect("@UserDisconnected");
HSCRIPTFUNCTION pfnOnConnectNeedUbi = m_pScriptSystem->GetFunctionPtr("Game", "OnConnectNeedUbi");
if (pfnOnConnectNeedUbi)
{
_SmartScriptObject pGameScriptObject(m_pScriptSystem,true);
m_pScriptSystem->GetGlobalValue("Game",*pGameScriptObject);
m_pScriptSystem->BeginCall(pfnOnConnectNeedUbi);
m_pScriptSystem->PushFuncParam(pGameScriptObject);
m_pScriptSystem->EndCall();
m_pScriptSystem->ReleaseFunc(pfnOnConnectNeedUbi);
}
return false;
}
#endif // NOT_USE_UBICOM_SDK
return true;
}
void CNetwork::Client_ReJoinGameServer()
{
#ifndef NOT_USE_UBICOM_SDK
// We have to tell Ubisoft that the client has successfully connected
// If ubisoft is not running this won't do anything.
m_pUbiSoftClient->Client_ReJoinGameServer();
#endif NOT_USE_UBICOM_SDK
}

162
CryNetwork/Network.h Normal file
View File

@@ -0,0 +1,162 @@
// Network.h: interface for the CNetwork class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_NETWORK_H__9C2C8689_2D3A_4729_9DBD_A8A930264655__INCLUDED_)
#define AFX_NETWORK_H__9C2C8689_2D3A_4729_9DBD_A8A930264655__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "CompressionHelper.h" // CCompressionHelper
#include "TimeValue.h"
class CServer;
class CClient;
class CServerSlotLocal;
class CServerSlot;
class CClientLocal;
class CDefenceWall;
struct IScriptSystem;
class NewUbisoftClient;
class CScriptObjectNewUbisoftClient;
#if !defined(NOT_USE_PUNKBUSTER_SDK)
class CPunkBusterInterface;
#endif
// server connection flags
// returned by the server on the m_cResponse field of the CCPConnect packet
#define SV_CONN_FLAG_PUNKBUSTER (1 << 0) // punkbuster is on
#define SV_CONN_FLAG_DEVMODE (1 << 1) // devmode is on
typedef std::map<NRESULT,const char*> ERROR_MAP;
typedef ERROR_MAP::iterator ERROR_MAPItor;
typedef std::map<WORD,CServer *> MapServers;
typedef MapServers::iterator MapServersItor;
struct CryNetError{
NRESULT nrErrorCode;
const char *sErrorDescription;
};
/*! module class factory
@see INetwork
*/
class CNetwork :public INetwork
{
public:
//! constructor
CNetwork();
//! destructor
virtual ~CNetwork();
//! \param pScriptSystem must not be 0
bool Init( IScriptSystem *pScriptSystem );
//! Get pointer to the system interface.
ISystem* GetSystem() { return m_pSystem; };
//!
//! unregister a server from the local servers map
void UnregisterServer( WORD wPort );
//!
void UnregisterClient( IClient *pClient );
//! connect a local client to a local serverslot
//! this function is used to emulate a network connection on the same machine
//! \param pClient
//! \param wPort
CServerSlotLocal *ConnectToLocalServerSlot( CClientLocal *pClient, WORD wPort );
// interface INetwork -------------------------------------------------------------
virtual DWORD GetLocalIP() const;
virtual void SetLocalIP( const char *szLocalIP );
virtual IClient *CreateClient(IClientSink *pSink,bool bLocal);
virtual IServer *CreateServer(IServerSlotFactory *pFactory,WORD nPort, bool listen);
virtual INETServerSnooper *CreateNETServerSnooper(INETServerSnooperSink *pSink);
virtual IServerSnooper *CreateServerSnooper(IServerSnooperSink *pSink);
virtual IRConSystem *CreateRConSystem();
virtual const char *EnumerateError(NRESULT err);
virtual void Release();
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual ICompressionHelper *GetCompressionHelper();
virtual void ClearProtectedFiles();
virtual void AddProtectedFile( const char *sFilename );
virtual IClient *GetClient();
virtual IServer *GetServerByPort( const WORD wPort );
virtual void UpdateNetwork();
virtual void OnAfterServerLoadLevel( const char *szServerName, const uint32 dwPlayerCount, const WORD wPort );
virtual bool VerifyMultiplayerOverInternet();
virtual void Client_ReJoinGameServer();
// -------------------------------------------------------------------------------
bool IsPacketCompressionEnabled() const;
//////////////////////////////////////////////////////////////////////////
// Network update functions.
//////////////////////////////////////////////////////////////////////////
//! Called from update of client.
void OnClientUpdate();
//! Called from update of server.
void OnServerUpdate();
//////////////////////////////////////////////////////////////////////////
// Defence Wall related methods.
//////////////////////////////////////////////////////////////////////////
void AddClientToDefenceWall( CIPAddress &clientIP );
void RemoveClientFromDefenceWall( CIPAddress &clientIP );
void PunkDetected( CIPAddress &ip );
void OnSecurityMsgResponse( CIPAddress &ipAddress,CStream &stm );
void OnSecurityMsgQuery( CStream &stm );
void OnCCPPunkBusterMsg( CIPAddress &ipAddress,CStream &stm );
CTimeValue GetCurrentTime();
u32 GetStringHash( const char *szString );
int GetLogLevel();
int GetCheatProtectionLevel();
bool CheckPBPacket(CStream &stmPacket,CIPAddress &ip);
void ValidateClient( CServerSlot *pSlot );
void InitPunkbusterClient(CClient *pClient);
void InitPunkbusterClientLocal(CClientLocal *pClientLocal);
void InitPunkbusterServer(bool bLocal, CServer *pServer);
void LockPunkbusterCVars();
#ifndef NOT_USE_UBICOM_SDK
CScriptObjectNewUbisoftClient * m_pScriptObjectNewUbisoftClient; //!<
NewUbisoftClient * m_pUbiSoftClient; //!< for internet multiplayer with ubi.com (if game is running this pointer is always valid)
#endif // NOT_USE_UBICOM_SDK
private: // -------------------------------------------------------------------------
void CreateConsoleVars();
void LogNetworkInfo();
IScriptSystem * m_pScriptSystem; //!< 0 before Init()
ISystem * m_pSystem; //!<
ICVar * m_pNetCompressPackets; //!<
ICVar * m_pNetLog; //!<
ICVar * m_pNetCheatProtection; //!<
#if !defined(NOT_USE_PUNKBUSTER_SDK)
CPunkBusterInterface * m_pPunkBuster; //!<
#endif
bool m_bHaveServer; //!<
bool m_bHaveClient; //!<
CCompressionHelper m_Compressor; //!< used for various kind of compressions (e.g. text compression)
MapServers m_mapServers; //!<
ERROR_MAP m_mapErrors; //!<
static CryNetError m_neNetErrors[]; //!<
static unsigned int m_nCryNetInitialized; //!<
DWORD m_dwLocalIP; //!< default: 0.0.0.0 local IPAddress (needed if we have several servers on one machine)
CDefenceWall * m_pDefenceWall; //!<
IClient * m_pClient; //!< pointer to the active client, otherwise 0 if there is not client active
};
#endif // !defined(AFX_NETWORK_H__9C2C8689_2D3A_4729_9DBD_A8A930264655__INCLUDED_)

View File

@@ -0,0 +1,684 @@
#include "stdafx.h"
#ifndef NOT_USE_UBICOM_SDK
#include "IConsole.h" // ICVar
#include "NewUbisoftClient.h"
#include "GSCDKeyInterface.h"
#include "CommonDefines.h"
#include <string>
static NewUbisoftClient *g_pUbisoftClient;
static const char CDKEYREGKEY[] = "CDKey";
static const char ACTIVATIONIDREGKEY[] = "ActivationID";
// src and trg can be the same pointer (in place encryption)
// len must be in bytes and must be multiple of 8 byts (64bits).
// key is 128bit: int key[4] = {n1,n2,n3,n4};
// void encipher(unsigned int *const v,unsigned int *const w,const unsigned int *const k )
#define TEA_ENCODE( src,trg,len,key ) {\
register unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3; \
register unsigned int delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3]; \
while (nlen--) {\
register unsigned int y=v[0],z=v[1],n=32,sum=0; \
while(n-->0) { sum += delta; y += (z << 4)+a ^ z+sum ^ (z >> 5)+b; z += (y << 4)+c ^ y+sum ^ (y >> 5)+d; } \
w[0]=y; w[1]=z; v+=2,w+=2; }}
// src and trg can be the same pointer (in place decryption)
// len must be in bytes and must be multiple of 8 byts (64bits).
// key is 128bit: int key[4] = {n1,n2,n3,n4};
// void decipher(unsigned int *const v,unsigned int *const w,const unsigned int *const k)
#define TEA_DECODE( src,trg,len,key ) {\
register unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3; \
register unsigned int delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3]; \
while (nlen--) { \
register unsigned int y=v[0],z=v[1],sum=0xC6EF3720,n=32; \
while(n-->0) { z -= (y << 4)+c ^ y+sum ^ (y >> 5)+d; y -= (z << 4)+a ^ z+sum ^ (z >> 5)+b; sum -= delta; } \
w[0]=y; w[1]=z; v+=2,w+=2; }}
//////////////////////////////////////
//
// CDKey Callbacks
//
/////////////////////////////////////
extern "C"
{
static GSvoid __stdcall CDKey_RcvActivationID(PREPLY_INFORMATION psReplyInfo,
PVALIDATION_SERVER_INFO psValidationServerInfo, GSubyte *pucActivationID, GSubyte *pucGlobalID)
{
if (g_pUbisoftClient)
g_pUbisoftClient->RcvActivationID(psReplyInfo,psValidationServerInfo,pucActivationID,pucGlobalID);
}
static GSvoid __stdcall CDKey_RcvAuthorizationID(PREPLY_INFORMATION psReplyInfo,
PVALIDATION_SERVER_INFO psValidationServerInfo, GSubyte *pucAuhorizationID)
{
if (g_pUbisoftClient)
g_pUbisoftClient->RcvAuthorizationID(psReplyInfo, psValidationServerInfo, pucAuhorizationID);
}
static GSvoid __stdcall CDKey_RcvValidationResponse(PREPLY_INFORMATION psReplyInfo,
PVALIDATION_SERVER_INFO psValidationServerInfo, GSubyte *pucAuhorizationID, CDKEY_PLAYER_STATUS eStatus,
GSubyte *pucGlobalID)
{
if (g_pUbisoftClient)
g_pUbisoftClient->RcvValidationResponse(psReplyInfo,psValidationServerInfo, pucAuhorizationID, eStatus,
pucGlobalID);
}
static GSvoid __stdcall CDKey_RcvPlayerStatusRequest(PVALIDATION_SERVER_INFO psValidationServerInfo,
GSubyte *pucAuhorizationID)
{
if (g_pUbisoftClient)
g_pUbisoftClient->RcvPlayerStatusRequest(psValidationServerInfo,pucAuhorizationID);
}
}
void NewUbisoftClient::CopyIDToString(const CDKeyIDVector &stVector, string &strString)
{
strString = "";
for (unsigned int i=0; i < stVector.size(); i++)
{
char szChar[10];
sprintf(szChar,"%.2X",stVector[i]);
strString += szChar;
}
}
void NewUbisoftClient::CopyIDToVector(CDKeyIDVector &stVector, const GSubyte *pubArray,
unsigned int uiSize)
{
stVector.clear();
for (unsigned int i=0; i < uiSize; i++)
{
stVector.push_back(pubArray[i]);
}
GSint iCompare = memcmp(&stVector[0],pubArray,uiSize);
return;
}
bool NewUbisoftClient::InitCDKeySystem()
{
g_pUbisoftClient = this;
if (!m_hCDKey)
{
int iPort = sv_authport->GetIVal();
m_hCDKey = GSCDKey_Initialize(iPort);
GSCDKey_FixRcvActivationID(m_hCDKey,CDKey_RcvActivationID);
GSCDKey_FixRcvAuthorizationID(m_hCDKey,CDKey_RcvAuthorizationID);
GSCDKey_FixRcvValidationResponse(m_hCDKey,CDKey_RcvValidationResponse);
GSCDKey_FixRcvPlayerStatusRequest(m_hCDKey,CDKey_RcvPlayerStatusRequest);
}
if (!m_pCDKeyServer)
{
m_pCDKeyServer = (PVALIDATION_SERVER_INFO)malloc(sizeof(_VALIDATION_SERVER_INFO));
GSint iIndex=0;
GetCDKeyServerAddress(iIndex,m_pCDKeyServer->szIPAddress,&m_pCDKeyServer->usPort);
}
return true;
}
bool NewUbisoftClient::Client_GetCDKeyAuthorizationID()
{
InitCDKeySystem();
char szCDkey[CDKEY_SIZE+1];
if (!LoadCDKey(szCDkey))
strcpy(szCDkey,"");
GSubyte pubActivationID[ACTIVATION_ID_SIZE];
if (!LoadActivationID(pubActivationID))
memset(pubActivationID,0,ACTIVATION_ID_SIZE);
_VALIDATION_INFO stValidationInfo;
memcpy(stValidationInfo.ucActivationID,pubActivationID,ACTIVATION_ID_SIZE);
strncpy(stValidationInfo.szCDKey,szCDkey,CDKEY_SIZE+1);
GSCDKey_RequestAuthorization(m_hCDKey,m_pCDKeyServer,&stValidationInfo,10);
return true;
}
bool NewUbisoftClient::RequestCDKeyActivationID()
{
InitCDKeySystem();
char szCDkey[CDKEY_SIZE+1];
memset(szCDkey, 0, CDKEY_SIZE+1);
LoadCDKey(szCDkey);
ACTIVATION_INFO stActivationInfo;
strncpy(stActivationInfo.szGameName,GAME_NAME,GAMELENGTH);
strncpy(stActivationInfo.szCDKey,szCDkey,CDKEY_SIZE+1);
GSCDKey_RequestActivation(m_hCDKey,m_pCDKeyServer,&stActivationInfo,5);
return true;
}
bool NewUbisoftClient::Client_CheckForCDKey()
{
InitCDKeySystem();
GSchar szCDKey[CDKEY_SIZE+1];
if (!LoadCDKey(szCDKey))
{
CDKey_GetCDKey();
return false;
}
GSubyte pubActivationID[ACTIVATION_ID_SIZE];
if (!LoadActivationID(pubActivationID))
{
RequestCDKeyActivationID();
return false;
}
CDKey_ActivationSuccess();
return true;
}
bool NewUbisoftClient::Client_SetCDKey(const char *szCDKey)
{
SaveCDKey(szCDKey);
RequestCDKeyActivationID();
return true;
}
GSvoid NewUbisoftClient::RcvActivationID(PREPLY_INFORMATION psReplyInfo,
PVALIDATION_SERVER_INFO psValidationServerInfo, GSubyte *pucActivationID, GSubyte *pucGlobalID)
{
if (!psReplyInfo->bSucceeded)
{
if (psReplyInfo->usErrorID == ERRORCDKEY_TIMEOUT)
{
m_pLog->Log("\001Ubi.com: CDKey RcvActivationID Failed: timeout");
}
// Since it didn't succeed we don't know if the cdkey is valid so delete it.
SaveCDKey(NULL);
SaveActivationID(NULL);
//Ask to for the cdkey again.
string strError;
GetCDKeyErrorText(psReplyInfo->usErrorID,strError);
CDKey_ActivationFail(strError.c_str());
return;
}
m_pLog->Log("\001Ubi.com: CDKey RcvActivationID Success");
//CopyIDToVector(m_stActivationID,pucActivationID,ACTIVATION_ID_SIZE);
SaveActivationID(pucActivationID);
CDKey_ActivationSuccess();
}
GSvoid NewUbisoftClient::RcvAuthorizationID(PREPLY_INFORMATION psReplyInfo,
PVALIDATION_SERVER_INFO psValidationServerInfo, GSubyte *pucAuthorizationID)
{
if(!m_pSystem->GetIGame()->GetModuleState(EGameClient))
return;
if (!psReplyInfo->bSucceeded)
{
if (psReplyInfo->usErrorID == ERRORCDKEY_TIMEOUT)
{
m_pLog->Log("\001Ubi.com: CDKey RcvAuthorizationID Failed: Timeout");
}
else
{
string strError;
GetCDKeyErrorText(psReplyInfo->usErrorID,strError);
m_pLog->Log("\001Ubi.com: CDKey RcvAuthorizationID Failed: %s",strError.c_str());
if ((psReplyInfo->usErrorID != ERRORCDKEY_TIMEOUT) && (psReplyInfo->usErrorID != ERRORCDKEY_INTERNAL_ERROR))
{
CDKey_ActivationFail(strError.c_str());
return;
}
}
// If the request failed let the player connect anyway because the cdkey server may be down.
// If the game server also times out when verfiying this fake ID then it will let the player connect.
BYTE bFakeAuthorizationID[AUTHORIZATION_ID_SIZE];
memset(bFakeAuthorizationID,0,AUTHORIZATION_ID_SIZE);
assert(m_pSystem->GetINetwork()->GetClient());
m_pSystem->GetINetwork()->GetClient()->OnCDKeyAuthorization(bFakeAuthorizationID);
return;
}
/* CDKeyIDVector stAuthorizationID;
CopyIDToVector(stAuthorizationID,pucAuthorizationID,AUTHORIZATION_ID_SIZE);
string strAuthorizationID;
CopyIDToString(stAuthorizationID,strAuthorizationID);*/
m_pLog->Log("\001Ubi.com: CDKey RcvAuthorizationID Success");
//TODO: Send the Authorization ID to the game server.
assert(m_pSystem->GetINetwork()->GetClient());
m_pSystem->GetINetwork()->GetClient()->OnCDKeyAuthorization(pucAuthorizationID);
}
bool NewUbisoftClient::Server_CheckPlayerAuthorizationID(BYTE bPlayerID,
const BYTE *pubAuthorizationID)
{
// m_pLog->Log("Ubi.com: CheckPlayerAuthorizationID: bCheck=%c",m_bCheckCDKeys?'t':'f');
// If the server wasn't created through ubi.com don't check cdkeys.
if (!m_bCheckCDKeys)
{
IServer *pServer = m_pSystem->GetINetwork()->GetServerByPort(m_usGamePort);
if(!pServer)
{
// that happened on a dedicated LAN server when a client tried to connect
return false; // better we ignore this
}
IServerSlot *pServerSlot = pServer->GetServerSlotbyID(bPlayerID);
//CXServerSlot *pSlot = itSlot->second;
pServerSlot->OnPlayerAuthorization(true,"",NULL,0);
return true;
}
InitCDKeySystem();
CDKeyIDVector stID;
if (!pubAuthorizationID)
{
m_pLog->Log("\001Ubi.com: CDKey CheckPlayerAuthorizationID: Authorization ID null");
return false;
}
CopyIDToVector(stID,pubAuthorizationID,AUTHORIZATION_ID_SIZE);
//string strAuthorizationID;
//CopyIDToString(stID,strAuthorizationID);
m_pLog->Log("\001Ubi.com: CDKey CheckPlayerAuthorizationID: %i",bPlayerID);
AddAuthorizedID(bPlayerID,stID);
GSCDKey_ValidateUser(m_hCDKey,m_pCDKeyServer,const_cast<GSubyte*>(pubAuthorizationID),GAME_NAME,6);
return true;
}
bool NewUbisoftClient::Server_RemovePlayer(BYTE bPlayerID)
{
CDKeyIDVector stID;
if (FindAuthorizedID(bPlayerID,stID))
{
//string strID;
//CopyIDToString(stID,strID);
m_pLog->Log("\001Ubi.com: CdKey: RemovePlayer: %i",bPlayerID);
GSCDKey_DisconnectUser(m_hCDKey,m_pCDKeyServer,&stID[0]);
RemoveAuthorizedID(bPlayerID);
return true;
}
return false;
}
bool NewUbisoftClient::Server_RemoveAllPlayers()
{
CDKeyIDVector stID;
AuthorizedIDs::iterator itID = m_stAuthorizedIDs.begin();
while (itID != m_stAuthorizedIDs.end())
{
//string strID;
//CopyIDToString(itID->first,strID);
m_pLog->Log("\001Ubi.com: CDKey RemovePlayer: %i",itID->second);
GSCDKey_DisconnectUser(m_hCDKey,m_pCDKeyServer,const_cast<GSubyte*>(&itID->first[0]));
itID++;
}
m_stAuthorizedIDs.clear();
return true;
}
void NewUbisoftClient::RcvValidationResponse(PREPLY_INFORMATION psReplyInfo,
PVALIDATION_SERVER_INFO psValidationServerInfo, GSubyte *pucAuthorizationID, CDKEY_PLAYER_STATUS eStatus,
GSubyte *pucGlobalID)
{
CDKeyIDVector stID;
CopyIDToVector(stID,pucAuthorizationID,AUTHORIZATION_ID_SIZE);
BYTE bPlayerID;
FindPlayerID(stID,bPlayerID);
IServer *pServer = m_pSystem->GetINetwork()->GetServerByPort(m_usGamePort);
if(!pServer)
{
assert(pServer);
return; // better we ignore this
}
IServerSlot *pServerSlot = pServer->GetServerSlotbyID(bPlayerID);
if(!pServerSlot)
{
m_pLog->Log("\001Ubi.com: CDKey RcvValidationResponse Failed: Player disconnected during authorization!");
return;
}
//CXServerSlot *pSlot = itSlot->second;
if (!psReplyInfo->bSucceeded)
{
/* if (psReplyInfo->usErrorID == ERRORCDKEY_TIMEOUT)
{
// don't try again
m_pLog->Log("\001RcvValidationResponse Failed: timeout accept");
itSlot->second->OnXPlayerAuthorization(true,"");
}
else
{*/
string strError;
GetCDKeyErrorText(psReplyInfo->usErrorID,strError);
m_pLog->Log("\001Ubi.com: CDKey RcvValidationResponse Failed: %s",strError.c_str());
pServerSlot->OnPlayerAuthorization(false,strError.c_str(),NULL,0);
RemoveAuthorizedID(stID);
//}
return;
}
if (eStatus == E_PLAYER_UNKNOWN)
{
m_pLog->Log("\001Ubi.com: CDKey RcvValidationResponse Success: PLAYERUNKNOWN");
pServerSlot->OnPlayerAuthorization(false,INVALIDCDKEY,NULL,0);
RemoveAuthorizedID(stID);
}
else if (eStatus == E_PLAYER_INVALID)
{
m_pLog->Log("\001Ubi.com: CDKey RcvValidationResponse Success: INVALIDCDKEY");
pServerSlot->OnPlayerAuthorization(false,INVALIDCDKEY,NULL,0);
RemoveAuthorizedID(stID);
}
else if (eStatus == E_PLAYER_VALID)
{
m_pLog->Log("\001Ubi.com: CDKey RcvValidationResponse Success: VALIDCDKEY");
pServerSlot->OnPlayerAuthorization(true,"",pucGlobalID,GLOBAL_ID_SIZE);
}
}
void NewUbisoftClient::RcvPlayerStatusRequest(PVALIDATION_SERVER_INFO psValidationServerInfo, GSubyte *pucAuthorizationID)
{
if(!m_pSystem->GetIGame()->GetModuleState(EGameServer))
{
Server_RemoveAllPlayers();
return;
}
CDKeyIDVector stID;
CopyIDToVector(stID,pucAuthorizationID,AUTHORIZATION_ID_SIZE);
AuthorizedIDs::iterator itID = m_stAuthorizedIDs.find(stID);
if(itID != m_stAuthorizedIDs.end())
{
IServer *pServer = m_pSystem->GetINetwork()->GetServerByPort(m_usGamePort);
if(!pServer)
{
assert(pServer);
return; // better we ignore this
}
IServerSlot *pServerSlot = pServer->GetServerSlotbyID(itID->second);
// If the player is online
if(pServerSlot)
{
m_pLog->Log("\001Ubi.com: CDKey RcvPlayerStatusRequest: Player Valid");
GSCDKey_PlayerStatusReply(m_hCDKey,psValidationServerInfo,const_cast<GSubyte*>(&(itID->first[0])),E_PLAYER_VALID);
}
else
{
m_pLog->Log("\001Ubi.com: CDKey RcvPlayerStatusRequest: Player Unknown");
GSCDKey_PlayerStatusReply(m_hCDKey,psValidationServerInfo,const_cast<GSubyte*>(&(itID->first[0])),E_PLAYER_UNKNOWN);
}
}
else
{
m_pLog->Log("\001Ubi.com: CDKey RcvPlayerStatusRequest: AuthorizationID Unknown");
GSCDKey_PlayerStatusReply(m_hCDKey,psValidationServerInfo,const_cast<GSubyte*>(pucAuthorizationID),E_PLAYER_UNKNOWN);
}
}
bool NewUbisoftClient::AddAuthorizedID(BYTE bPlayerID, const CDKeyIDVector &stAuthorizationID)
{
if (m_stAuthorizedIDs.find(stAuthorizationID) == m_stAuthorizedIDs.end())
{
m_stAuthorizedIDs[stAuthorizationID] = bPlayerID;
return true;
}
return false;
}
bool NewUbisoftClient::RemoveAuthorizedID(const CDKeyIDVector &stAuthorizationID)
{
AuthorizedIDs::iterator itID = m_stAuthorizedIDs.find(stAuthorizationID);
if (itID != m_stAuthorizedIDs.end())
{
m_stAuthorizedIDs.erase(itID);
return true;
}
return false;
}
bool NewUbisoftClient::RemoveAuthorizedID(BYTE bPlayer)
{
AuthorizedIDs::iterator itID = m_stAuthorizedIDs.begin();
while (itID != m_stAuthorizedIDs.end())
{
if (itID->second == bPlayer)
{
m_stAuthorizedIDs.erase(itID);
return true;
}
itID++;
}
return false;
}
bool NewUbisoftClient::FindPlayerID(const CDKeyIDVector &stAuthorizationID, BYTE &bPlayer)
{
AuthorizedIDs::iterator itID = m_stAuthorizedIDs.find(stAuthorizationID);
if (itID != m_stAuthorizedIDs.end())
{
bPlayer = itID->second;
return true;
}
return false;
}
bool NewUbisoftClient::FindAuthorizedID(BYTE bPlayerID, CDKeyIDVector &stAuthorizationID)
{
AuthorizedIDs::iterator itID = m_stAuthorizedIDs.begin();
while (itID != m_stAuthorizedIDs.end())
{
if (itID->second == bPlayerID)
{
stAuthorizationID = itID->first;
return true;
}
itID++;
}
return false;
}
bool NewUbisoftClient::GetCDKeyErrorText(GSushort usError,string &strText)
{
switch(usError)
{
case ERRORCDKEY_INVALID_CDKEY:
strText = INVALIDCDKEY;
break;
case ERRORCDKEY_TIMEOUT:
strText = CDKEYTIMEOUT;
break;
case ERRORCDKEY_NOT_CHALLENGED:
strText = CDKEYNOTCHALLENGED;
break;
case ERRORCDKEY_ALREADY_ONLINE:
strText = CDKEYONLINE;
break;
case ERRORCDKEY_INTERNAL_ERROR:
strText = CDKEYINTERNALERROR;
break;
}
return true;
}
bool NewUbisoftClient::CDKey_Error(GSushort usError)
{
string strText;
GetCDKeyErrorText(usError,strText);
CDKey_Failed(strText.c_str());
return true;
}
void NewUbisoftClient::SaveCDKey(const GSchar *szCDKey)
{
if (szCDKey && (((strlen(szCDKey)+1) % 8) == 0))
{
unsigned char szEncCDKey[128] = {0};
unsigned int Key[4] = {1337, 1337*2, 1337*4, 1337*8};
TEA_ENCODE((unsigned int *)szCDKey, (unsigned int *)szEncCDKey, strlen(szCDKey)+1, Key);
char szCDKeyHex[256] = {0};
sprintf(szCDKeyHex, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
szEncCDKey[0], szEncCDKey[1], szEncCDKey[2], szEncCDKey[3], szEncCDKey[4], szEncCDKey[5],
szEncCDKey[6], szEncCDKey[7], szEncCDKey[8], szEncCDKey[9], szEncCDKey[10], szEncCDKey[11],
szEncCDKey[12], szEncCDKey[13], szEncCDKey[14], szEncCDKey[15], szEncCDKey[16], szEncCDKey[17],
szEncCDKey[18], szEncCDKey[19], szEncCDKey[20], szEncCDKey[21], szEncCDKey[22], szEncCDKey[23]);
WriteStringToRegistry("Ubi.com", CDKEYREGKEY, szCDKeyHex);
}
else
{
RemoveStringFromRegistry("Ubi.com", CDKEYREGKEY);
}
}
bool NewUbisoftClient::LoadCDKey(GSchar *szCDKey)
{
if (IsValueOnRegistry("Ubi.com", CDKEYREGKEY))
{
string szReadCDKey;
if (ReadStringFromRegistry("Ubi.com", CDKEYREGKEY, szReadCDKey))
{
// this is a pre1.2 stored cdkey
if (((szReadCDKey.size()-1) == CDKEY_SIZE) && (szReadCDKey[0] == 'F') && (szReadCDKey[1] == 'C') && (szReadCDKey[2] == 'Y'))
{
strncpy(szCDKey, szReadCDKey.c_str(), CDKEY_SIZE);
szCDKey[CDKEY_SIZE] = 0;
// save it in the new format
SaveCDKey(szCDKey);
}
else if ((szReadCDKey.size()-1) == (CDKEY_SIZE+1)*2) // -1 because of the terminating 0, x2 because of hex representation
{
char szAux[32];
char szEncCDKey[128] = {0};
for (int i = 0; i < CDKEY_SIZE+1; i++)
{
sprintf(szAux, "0x%c%c", szReadCDKey[i*2+0], szReadCDKey[i*2+1]);
szEncCDKey[i] = strtol(szAux, 0, 0);
}
// decrypt it
unsigned char szDecCDKey[128] = {0};
unsigned int Key[4] = {1337, 1337*2, 1337*4, 1337*8};
TEA_DECODE((unsigned int *)szEncCDKey, (unsigned int *)szDecCDKey, CDKEY_SIZE+1, Key);
strncpy(szCDKey, (char *)szDecCDKey, min(strlen((char *)szDecCDKey), CDKEY_SIZE));
szCDKey[CDKEY_SIZE] = 0;
}
else
{
return false;
}
return true;
}
}
return false;
}
void NewUbisoftClient::SaveActivationID(const GSubyte *pubActivationID)
{
if (pubActivationID)
{
char szActivationHex[256] = {0};
sprintf(szActivationHex, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
pubActivationID[0], pubActivationID[1], pubActivationID[2], pubActivationID[3], pubActivationID[4], pubActivationID[5],
pubActivationID[6], pubActivationID[7], pubActivationID[8], pubActivationID[9], pubActivationID[10], pubActivationID[11],
pubActivationID[12], pubActivationID[13], pubActivationID[14], pubActivationID[15]);
WriteStringToRegistry("Ubi.com", ACTIVATIONIDREGKEY, szActivationHex);
}
}
bool NewUbisoftClient::LoadActivationID(GSubyte *pubActivationID)
{
if (IsValueOnRegistry("Ubi.com", ACTIVATIONIDREGKEY))
{
string szReadActivationID;
if (ReadStringFromRegistry("Ubi.com", ACTIVATIONIDREGKEY, szReadActivationID))
{
// this is pre 1.2
if ((szReadActivationID.size()-1) == ACTIVATION_ID_SIZE) // size-1 because of the terminating 0
{
// load in the old form
strncpy((char *)pubActivationID, szReadActivationID.c_str(), ACTIVATION_ID_SIZE);
// save it the new form
SaveActivationID(pubActivationID);
}
else if ((szReadActivationID.size()-1) == (ACTIVATION_ID_SIZE*2)) // size-1 because of the terminating 0
{
char szAux[32];
for (int i = 0; i < ACTIVATION_ID_SIZE; i++)
{
sprintf(szAux, "0x%c%c", szReadActivationID[i*2+0], szReadActivationID[i*2+1]);
pubActivationID[i] = strtol(szAux, 0, 0);
}
}
else
{
return false;
}
return true;
}
}
return false;
}
#endif // NOT_USE_UBICOM_SDK

View File

@@ -0,0 +1,787 @@
#include "stdafx.h"
#ifndef NOT_USE_UBICOM_SDK
#include "NewUbisoftClient.h"
#include "CommonDefines.h" // UBI.com common defines
#include "IConsole.h" // ICVar
#include "IRenderer.h" // IRenderer
#if defined(LINUX)
#include "CryLibrary.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fstream>
#endif
#if defined(WIN32) || defined(WIN64)
#include "windows.h"
#include "Wininet.h"
#endif
#include "ScriptObjectNewUbisoftClient.h" // CScriptObjectNewUbisoftClient
#if !defined(LINUX)
#include <assert.h>
#endif
#include "GSCDKeyInterface.h"
#include "InitSockets.h"
#if !defined(LINUX)
static const char GSINIFILE[10] = ".\\gs.ini";
static const char GSINIFILETMP[10] = ".\\gs.tmp";
#else
static const char GSINIFILE[10] = "gs.ini";
static const char GSINIFILETMP[10] = "gs.tmp";
#endif
static const char RegistryKeyName[] = "SOFTWARE\\Crytek\\FarCry";
// src and trg can be the same pointer (in place encryption)
// len must be in bytes and must be multiple of 8 byts (64bits).
// key is 128bit: int key[4] = {n1,n2,n3,n4};
// void encipher(unsigned int *const v,unsigned int *const w,const unsigned int *const k )
#define TEA_ENCODE( src,trg,len,key ) {\
register unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3; \
register unsigned int delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3]; \
while (nlen--) {\
register unsigned int y=v[0],z=v[1],n=32,sum=0; \
while(n-->0) { sum += delta; y += (z << 4)+a ^ z+sum ^ (z >> 5)+b; z += (y << 4)+c ^ y+sum ^ (y >> 5)+d; } \
w[0]=y; w[1]=z; v+=2,w+=2; }}
// src and trg can be the same pointer (in place decryption)
// len must be in bytes and must be multiple of 8 byts (64bits).
// key is 128bit: int key[4] = {n1,n2,n3,n4};
// void decipher(unsigned int *const v,unsigned int *const w,const unsigned int *const k)
#define TEA_DECODE( src,trg,len,key ) {\
register unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3; \
register unsigned int delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3]; \
while (nlen--) { \
register unsigned int y=v[0],z=v[1],sum=0xC6EF3720,n=32; \
while(n-->0) { z -= (y << 4)+c ^ y+sum ^ (y >> 5)+d; y -= (z << 4)+a ^ z+sum ^ (z >> 5)+b; sum -= delta; } \
w[0]=y; w[1]=z; v+=2,w+=2; }}
NewUbisoftClient::NewUbisoftClient( const char *szLocalIPAddress ):m_strUsername(""), m_iJoinedLobbyID(0), m_iJoinedRoomID(0),
m_bDownloadedGSini(false), m_eServerState(NoUbiServer), m_eClientState(NoUbiClient), m_hCDKey(0),
m_pCDKeyServer(NULL), m_bCheckCDKeys(false), m_dwNextServerAbsTime(0),
m_dwNextClientAbsTime(0), m_dwAccountCreateTime(0), m_bDisconnecting(0), sv_authport(0), sv_regserver_port(0),
m_pLog(0), m_pSystem(0), m_usGamePort(0)
{
assert(szLocalIPAddress);
m_pScriptObject=0;
GSbool bRet;
if(strcmp(szLocalIPAddress,"0.0.0.0")!=0)
{
static char szLocalIP[256];
strcpy(szLocalIP,(char *)szLocalIPAddress); // make a copy (to compensate UBI sdk error)
bRet=InitializeSockets((GSchar *)szLocalIP);
}
else bRet=InitializeSockets();
/*
if(!bRet)
{
// log error
}
*/
m_bSavePassword = false;
}
#if defined(LINUX)
static void ResolveServerAndPath( const char* szURL, string& strServer, string& strPath )
{
const char c_szHTTPSig[] = "http://";
const size_t c_HTTPSigLength( sizeof( c_szHTTPSig ) - 1 ); // substract zero termination
string strTemp( szURL );
if( string::npos == strTemp.find( c_szHTTPSig ) )
{
string::size_type posFirstSlash( strTemp.find( "/" ) );
if(posFirstSlash == string::npos)
{
printf("Cannot resolve server path URL for downloading gs.ini\n");
return;
}
strServer = strTemp.substr( 0, posFirstSlash );
strPath = strTemp.substr( posFirstSlash, strTemp.size() - posFirstSlash );
}
else
{
string::size_type posFirstSlash( strTemp.find( "/", c_HTTPSigLength ) );
if(posFirstSlash == string::npos)
{
printf("Cannot resolve server path URL for downloading gs.ini\n");
return;
}
strServer = strTemp.substr( c_HTTPSigLength, posFirstSlash - c_HTTPSigLength );
strPath = strTemp.substr( posFirstSlash , strTemp.size() - posFirstSlash );
}
}
static bool SendReceive( SOCKET& conSocket, const char* szRequestFmt, const string& strServer, const string& strPath, string& strData )
{
// send request
std::vector< char > request;
request.reserve( strServer.size() + strPath.size() + strlen( szRequestFmt ) + 1 );
sprintf( &request[ 0 ], szRequestFmt, strPath.c_str(), strServer.c_str() );
if( SOCKET_ERROR == send( conSocket, &request[ 0 ], (int) strlen( &request[ 0 ] ) + 1, 0 ) )
{
return( false );
}
// receive data
strData.clear();
while( true )
{
const int c_bufferSize( 128 );
char buffer[ c_bufferSize + 1 ];
buffer[ 0 ] = 0;
int retval( recv( conSocket, buffer, c_bufferSize, 0 ) );
if( SOCKET_ERROR == retval )
{
return( false );
}
if( 0 < retval )
{
buffer[ retval ] = 0;
strData += buffer;
}
else
{
break;
}
}
return( true );
}
bool GetTextFromURL( const char* szURL, string& strText )
{
// determine server and path from URL
string strServer;
string strPath;
ResolveServerAndPath( szURL, strServer, strPath );
// create host structure
hostent* pHost( 0 );
if( false != isalpha( strServer[ 0 ] ) )
{
// resolve host name
pHost = gethostbyname( strServer.c_str() );
}
else
{
// convert string to ip address number
unsigned int addr( inet_addr( strServer.c_str() ) );
pHost = gethostbyaddr( (char*) &addr, 4, AF_INET );
}
if( 0 == pHost )
{
return( false );
}
// create socket
sockaddr_in server;
memset( &server, 0, sizeof( server ) );
memcpy( &(server.sin_addr), pHost->h_addr, pHost->h_length );
server.sin_family = pHost->h_addrtype;
server.sin_port = htons( 80 );
SOCKET conSocket( socket( AF_INET, SOCK_STREAM, 0 ) );
if( 0 > conSocket )
{
return( false );
}
// connect
if( SOCKET_ERROR == connect( conSocket, (sockaddr*) &server, sizeof( server ) ) )
{
return( false );
}
// send request
//const char pcRequest[] = "GET /gsinit.php?user=%25s&dp=%25s HTTP/1.0\nUser-Agent: Wget/1.9\nHost: gsconnect.ubisoft.com\nAccept: */*\nConnection: Keep-Alive\n\n";
//const char pcRequest[] = "GET /gsinit.php?user=%s&dp=%s HTTP/1.0\nHost: gsconnect.ubisoft.com\n\n";
const char c_szRequestFmt[] = "GET %s HTTP/1.0\nHost: %s\n\n";
if( false != SendReceive( conSocket, c_szRequestFmt, strServer, strPath, strText ) )
{
const char c_szHTTPHeaderEnd[ ] = "\r\n\r\n\r\n";
const size_t c_szHTTPHeaderEndLength( sizeof( c_szHTTPHeaderEnd ) - 1 ); // substract zero termination
// remove http header
string::size_type pos( strText.find( c_szHTTPHeaderEnd ) );
if( string::npos != pos )
{
strText = strText.substr( pos + c_szHTTPHeaderEndLength, strText.size() - pos - c_szHTTPHeaderEndLength );
}
}
else
{
return( false );
}
// close socket and return
closesocket( conSocket );
return( true );
}
#endif
NewUbisoftClient::~NewUbisoftClient()
{
Server_RemoveAllPlayers();
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
if (m_eClientState != NoUbiClient)
clMSClientClass::Uninitialize();
#endif // EXCLUDE_UBICOM_CLIENT_SDK
if (m_pCDKeyServer)
delete m_pCDKeyServer;
GSCDKey_Uninitialize();
UninitializeSockets();
}
bool NewUbisoftClient::WriteStringToRegistry(const string &szKeyName, const string &szValueName, const string &szValue)
{
#if !defined(LINUX)
HKEY hKey;
string szREGKeyName = string(RegistryKeyName) + string("\\") + szKeyName;
if (RegOpenKey(HKEY_LOCAL_MACHINE, szREGKeyName.c_str(), &hKey) != ERROR_SUCCESS)
{
if (RegCreateKey(HKEY_LOCAL_MACHINE, szREGKeyName.c_str(), &hKey) != ERROR_SUCCESS)
{
return false;
}
}
if (RegSetValueEx(hKey, szValueName.c_str(), 0, REG_SZ, (BYTE *)szValue.c_str(), szValue.size()) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return false;
}
RegCloseKey(hKey);
#endif
return true;
}
bool NewUbisoftClient::ReadStringFromRegistry(const string &szKeyName, const string &szValueName, string &szValue)
{
#if !defined(LINUX)
HKEY hKey;
string szREGKeyName = string(RegistryKeyName) + string("\\") + szKeyName;
if (RegOpenKey(HKEY_LOCAL_MACHINE, szREGKeyName.c_str(), &hKey) != ERROR_SUCCESS)
{
return false;
}
DWORD dwSize = 0;
if (RegQueryValueEx(hKey, szValueName.c_str(), 0, 0, 0, &dwSize) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return false;
}
szValue.resize(dwSize);
RegQueryValueEx(hKey, szValueName.c_str(), 0, 0, (LPBYTE)szValue.c_str(), &dwSize);
RegCloseKey(hKey);
#endif
return true;
}
bool NewUbisoftClient::RemoveStringFromRegistry(const string &szKeyName, const string &szValueName)
{
#if !defined(LINUX)
HKEY hKey;
string szREGKeyName = string(RegistryKeyName) + string("\\") + szKeyName;
if (RegOpenKey(HKEY_LOCAL_MACHINE, szREGKeyName.c_str(), &hKey) != ERROR_SUCCESS)
{
return false;
}
DWORD dwSize = 0;
if (RegDeleteValue(hKey, szValueName.c_str()) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return false;
}
RegCloseKey(hKey);
#endif
return true;
}
bool NewUbisoftClient::IsValueOnRegistry(const string &szKeyName, const string &szValueName)
{
#if !defined(LINUX)
HKEY hKey;
string szREGKeyName = string(RegistryKeyName) + string("\\") + szKeyName;
if (RegOpenKey(HKEY_LOCAL_MACHINE, szREGKeyName.c_str(), &hKey) != ERROR_SUCCESS)
{
return false;
}
DWORD dwSize = 0;
if (RegQueryValueEx(hKey, szValueName.c_str(), 0, 0, 0, &dwSize) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return false;
}
RegCloseKey(hKey);
#endif
return true;
}
bool NewUbisoftClient::EncryptString(unsigned char *szOut, const unsigned char *szIn)
{
string szInPadded = (char *)szIn;
while ((szInPadded.size() % 8) != 0)
{
szInPadded.push_back(0);
}
unsigned int Key[4] = {31337, 31337*2, 31337*4, 31337*8};
TEA_ENCODE((unsigned int *)szInPadded.c_str(), (unsigned int *)szOut, szInPadded.size(), Key);
szOut[szInPadded.size()] = 0;
return true;
}
bool NewUbisoftClient::DecryptString(unsigned char *szOut, const unsigned char *szIn)
{
string szInPadded = (char *)szIn;
while ((szInPadded.size() % 8) != 0)
{
szInPadded.push_back(0);
}
unsigned int Key[4] = {31337, 31337*2, 31337*4, 31337*8};
TEA_DECODE((unsigned int *)szIn, (unsigned int *)szOut, strlen((char *)szIn), Key);
return true;
}
bool NewUbisoftClient::EncodeHex(unsigned char *szOut, const unsigned char *szIn)
{
unsigned int len = strlen((char *)szIn);
for (unsigned int i = 0; i < len; i++)
{
sprintf((char *)&szOut[i*2], "%02x", szIn[i]);
}
return true;
}
bool NewUbisoftClient::DecodeHex(unsigned char *szOut, const unsigned char *szIn)
{
unsigned int len = strlen((char *)szIn) >> 1;
char szAux[16];
for (unsigned int i = 0; i < len; i++)
{
sprintf(szAux, "0x%c%c", szIn[i*2+0], szIn[i*2+1]);
szOut[i] = strtol(szAux, 0, 0);
}
return true;
}
void NewUbisoftClient::Init( ISystem *inpSystem )
{
m_pSystem = inpSystem; assert(m_pSystem);
m_pLog = m_pSystem->GetILog(); assert(m_pLog);
IConsole *pConsole = m_pSystem->GetIConsole();
sv_authport = pConsole->GetCVar("sv_authport"); assert(sv_authport);
sv_regserver_port = pConsole->GetCVar("sv_regserver_port"); assert(sv_regserver_port);
}
bool NewUbisoftClient::Update()
{
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
clMSClientClass::Engine();
#endif // EXCLUDE_UBICOM_CLIENT_SDK
CRegisterServer::RegServer_Engine();
//if (m_bUsingRegServer && !m_bServerLoggedIn)
//Server_RecreateServer();
{
bool bCheckCDKey = m_pSystem->GetIGame()->GetModuleState(EGameMultiplayer)
&& m_pSystem->GetINetwork()
&& m_pSystem->GetINetwork()->GetServerByPort(m_usGamePort)
&& m_pSystem->GetINetwork()->GetServerByPort(m_usGamePort)->GetServerType()!=eMPST_LAN;
Server_CheckCDKeys(bCheckCDKey);
}
if (m_hCDKey)
GSCDKey_Engine(m_hCDKey);
// ensure server is shown in the UBI.com list
// Server_CreateServer() has a timelimit
if (m_eServerState == ServerDisconnected)
Server_RecreateServer();
if ((m_eClientState == ClientDisconnected) || (m_eClientState == GameServerDisconnected))
Client_ReJoinGameServer();
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
if (m_eClientState == NoUbiClient)
clMSClientClass::Uninitialize();
#endif // EXCLUDE_UBICOM_CLIENT_SDK
return true;
}
void NewUbisoftClient::SetScriptObject( CScriptObjectNewUbisoftClient *inpObject )
{
assert(!m_pScriptObject); // called twice?
assert(inpObject); // param must be 0
m_pScriptObject = inpObject;
}
bool NewUbisoftClient::DownloadGSini(const char *szUsername)
{
if (m_bDownloadedGSini)
return true;
#if defined(LINUX)
static const char* pGSConnectFilename = "gsconnect.ini";
#endif
// Get the URL to download the INI from
// Get it from the reg key
// HKEY_LOCAL_MACHINE\SOFTWARE\Ubi Soft\Game Service\ConnectURL
// if we can, otherwise use the default URL
// http://gsconnect.ubisoft.com/gsinit.php?user=%s&dp=%s
// If that doesn't work check the local directory
char *connectURL = NULL;
DWORD dwBufLen = 0;
#if !defined(LINUX)
//connectURL[0]=0;
HKEY hKey;
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,"SOFTWARE\\Ubi Soft\\Game Service",0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS)
{
if (RegQueryValueEx( hKey, "ConnectURL", NULL, NULL, NULL, &dwBufLen) == ERROR_SUCCESS)
{
connectURL = (char*)malloc(dwBufLen);
RegQueryValueEx( hKey, "ConnectURL", NULL, NULL, (LPBYTE) connectURL, &dwBufLen);
RegCloseKey( hKey );
}
}
#else
char iniEntry[512];
//Check to see if the tmp file contains good info
string GSConnectFilename(GetModulePath());
if(GSConnectFilename.c_str()[GSConnectFilename.size()-1] != '/')
GSConnectFilename += "/";
GSConnectFilename += pGSConnectFilename;
GetPrivateProfileString("Servers", "GSConnectURL", "Key not found", iniEntry, 512, GSConnectFilename.c_str());
if (strcmp("Key not found", iniEntry) !=0 )
{
dwBufLen = strlen(iniEntry);
connectURL = (char*)malloc(dwBufLen+1);
strcpy(connectURL, iniEntry);
}
#endif
if (connectURL==NULL) // We didn't get the key from the registry so try the default url
{
char defURL[] = "http://gsconnect.ubisoft.com/gsinit.php?user=%s&dp=%s";
dwBufLen = sizeof(defURL);
connectURL = (char*)malloc(dwBufLen + 1);
strcpy(connectURL, defURL);
}
const unsigned int cMaxCount = dwBufLen + strlen(szUsername) + strlen(GAME_NAME) + 1;
char *szGSURL = (char*)malloc(cMaxCount); //size of the url + username + gamename
_snprintf(szGSURL,cMaxCount - 1, connectURL, szUsername, GAME_NAME);
free(connectURL);
/*GShandle stHandle = GSHttpInitialize();
// Returns 0 on failure, but for now I don't care
int i=GSHttpSave(stHandle,connectURL,"gsinit.ini",GS_TRUE,NULL,NULL); // Store in the working dir
assert(i);
GSHttpUninitialize();*/
//delete the current tmp file
remove(GSINIFILETMP);
#if !defined(LINUX)
HINTERNET hNet = InternetOpen("",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,NULL);
if (!hNet)
{
free(szGSURL);
return false;
}
else
{
HINTERNET hURL = InternetOpenUrl(hNet,szGSURL,NULL,0,INTERNET_FLAG_HYPERLINK,NULL);
free(szGSURL);
if (!hURL)
return false;
else
{
GSchar szBuffer[1024];
GSint iSize = 1024;
DWORD iRead = 0;
FILE *pFile = fopen(GSINIFILETMP,"w");
// If we can't open the tmp file return true and we will use the real one.
if (!pFile)
{
InternetCloseHandle(hURL);
return true;
}
while (InternetReadFile(hURL,szBuffer,iSize,&iRead))
{
if (iRead != 0)
{
fwrite(szBuffer,sizeof(GSchar),iRead,pFile);
}
else
{
fclose(pFile);
break;
}
}
}
InternetCloseHandle(hURL);
}
#else
string strText;
GetTextFromURL(szGSURL, strText);
free(szGSURL);
// write file
FILE *pFile = fopen(GSINIFILETMP,"wb");
if(NULL != pFile)
{
fwrite(strText.c_str(), 1, strText.size(), pFile);
fclose(pFile);
}
#endif
GSchar szIPAddress[100];
//Check to see if the tmp file contains good info
GetPrivateProfileString("Servers", "RouterIP0", "Key not found", szIPAddress, 100, GSINIFILETMP);
if (strcmp("Key not found", szIPAddress)!=0)
{
//It contains good info so replace the real gs.ini file
remove(GSINIFILE);
rename(GSINIFILETMP,GSINIFILE);
}
m_bDownloadedGSini = true;
return true;
}
// Script Callbacks -------------------------------------------
void NewUbisoftClient::Client_LoginSuccess(const char *szUsername)
{
if (m_bSavePassword)
{
char szEncUsername[256] = {0};
char szEncPassword[256] = {0};
char szHexUsername[512] = {0};
char szHexPassword[512] = {0};
EncryptString((unsigned char *)szEncUsername, (unsigned char *)m_strUsername.c_str());
EncryptString((unsigned char *)szEncPassword, (unsigned char *)m_strPassword.c_str());
EncodeHex((unsigned char *)szHexUsername, (unsigned char *)szEncUsername);
EncodeHex((unsigned char *)szHexPassword, (unsigned char *)szEncPassword);
WriteStringToRegistry("Ubi.com", "username", szHexUsername);
WriteStringToRegistry("Ubi.com", "password", szHexPassword);
}
else
{
RemoveStringFromRegistry("Ubi.com", "username");
RemoveStringFromRegistry("Ubi.com", "password");
}
m_pScriptObject->Client_LoginSuccess(szUsername);
}
void NewUbisoftClient::Client_LoginFail(const char *szText)
{
m_pScriptObject->Client_LoginFail(szText);
}
void NewUbisoftClient::Client_GameServer(int iLobbyID, int iRoomID, const char *szServerName, const char *szIPAddress,
const char *szLANIPAddress, int iMaxPlayers, int iNumPlayers)
{
m_pScriptObject->Client_GameServer(iLobbyID,iRoomID,szServerName,szIPAddress,szLANIPAddress,iMaxPlayers,iNumPlayers);
}
void NewUbisoftClient::Client_RequestFinished()
{
m_pScriptObject->Client_RequestFinished();
}
void NewUbisoftClient::Client_JoinGameServerSuccess(const char *szIPAddress, const char *szLanIPAddress,unsigned short usPort)
{
m_pScriptObject->Client_JoinGameServerSuccess(szIPAddress,szLanIPAddress,usPort);
}
void NewUbisoftClient::Client_JoinGameServerFail(const char *szText)
{
m_pScriptObject->Client_JoinGameServerFail(szText);
}
void NewUbisoftClient::Client_CreateAccountSuccess()
{
m_pScriptObject->Client_CreateAccountSuccess();
}
void NewUbisoftClient::Client_CreateAccountFail(const char *szText)
{
m_pScriptObject->Client_CreateAccountFail(szText);
}
void NewUbisoftClient::Server_RegisterServerSuccess(GSint iLobbyID, GSint iRoomID)
{
m_pScriptObject->Server_RegisterServerSuccess(iLobbyID,iRoomID);
}
void NewUbisoftClient::Server_RegisterServerFail()
{
m_pScriptObject->Server_RegisterServerFail();
}
void NewUbisoftClient::Server_LobbyServerDisconnected()
{
m_pScriptObject->Server_LobbyServerDisconnected();
}
void NewUbisoftClient::Server_PlayerJoin(const char *szUsername)
{
m_pScriptObject->Server_PlayerJoin(szUsername);
}
void NewUbisoftClient::Server_PlayerLeave(const char *szUsername)
{
m_pScriptObject->Server_PlayerLeave(szUsername);
}
void NewUbisoftClient::CDKey_Failed(const char *szText)
{
m_pScriptObject->CDKey_Failed(szText);
}
void NewUbisoftClient::CDKey_GetCDKey()
{
m_pScriptObject->CDKey_GetCDKey();
}
void NewUbisoftClient::CDKey_ActivationSuccess()
{
m_pScriptObject->CDKey_ActivationSuccess();
}
void NewUbisoftClient::CDKey_ActivationFail(const char *szText)
{
if(m_pSystem->GetIGame()->GetModuleState(EGameMultiplayer))
m_pSystem->GetIRenderer()->ClearColorBuffer(Vec3(0,0,0));
m_pSystem->GetIConsole()->ResetProgressBar(0);
m_pSystem->GetIConsole()->ShowConsole(false);
m_pSystem->GetIConsole()->SetScrollMax(600/2);
m_pScriptObject->CDKey_ActivationFail(szText);
}
// --------------------------------------------------------------
bool NewUbisoftClient::GetRouterAddress(int iIndex, char *szIPAddress, unsigned short *pusClientPort,
unsigned short *pusRegServerPort)
{
char szKey[50];
char szPort[50];
// Try to read from the tmp file first
_snprintf(szKey, 50, "RouterIP%i", iIndex);
GetPrivateProfileString("Servers", szKey,"Key not found", szIPAddress, 50, GSINIFILE); // Read from the working directory
if (strcmp("Key not found", szIPAddress)==0)
return false;
_snprintf(szKey, 50, "RouterPort%i", iIndex);
GetPrivateProfileString("Servers", szKey,"Key not found", szPort, 50, GSINIFILE); // Read from the working directory
if (strcmp("Key not found", szPort)==0)
return false;
*pusClientPort = atoi(szPort);
_snprintf(szKey, 50, "RouterLauncherPort%i", iIndex);
GetPrivateProfileString("Servers", szKey,"Key not found", szPort, 50, GSINIFILE); // Read from the working directory
if (strcmp("Key not found", szPort)==0)
return false;
*pusRegServerPort = atoi(szPort);
return true;
}
bool NewUbisoftClient::GetCDKeyServerAddress(int iIndex, char *szIPAddress, unsigned short *pusPort)
{
char szKey[50];
char szPort[50];
// Try to read from the tmp file first
_snprintf(szKey, 50, "CDKeyServerIP%i", iIndex);
GetPrivateProfileString("Servers", szKey,"Key not found", szIPAddress, 50, GSINIFILE); // Read from the working directory
if (strcmp("Key not found", szIPAddress)==0)
return false;
_snprintf(szKey, 50, "CDKeyServerPort%i", iIndex);
GetPrivateProfileString("Servers", szKey,"Key not found", szPort, 50, GSINIFILE); // Read from the working directory
if (strcmp("Key not found", szPort)==0)
return false;
*pusPort = atoi(szPort);
return true;
}
#endif // NOT_USE_UBICOM_SDK

View File

@@ -0,0 +1,379 @@
#ifndef __NEW_UBISOFT_CLIENT
#define __NEW_UBISOFT_CLIENT
#ifndef NOT_USE_UBICOM_SDK
// Facade design pattern over Ubisoft's own clMSClient and CRegisterby Scott Schmeisser
// This implements all functions and callbacks needed to use Ubisoft's "Master Server Style" matchmaking service in-game
// Class is implemented over these files: NewUbisoftClient.cpp implements the helper methods
// NewUbisoftMSClient.cpp implements the clMsClientClass methods. This is for a game client that wants to get the list
// of game servers.
// NewUbisoftRegServer.cpp implements the CRegisterServer methods. This is for a game server that wants to add it self
// to the list of game servers.
#if defined(WIN32)
# define GS_WIN32
#else
# define GS_LINUX
#endif
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
#include "MSClientClass.h"
#endif // EXCLUDE_UBICOM_CLIENT_SDK
#include "RegServerLib.h"
#include <string> // std string
#include "GSTypes.h"
#include "GSCDKeyDefines.h"
class CScriptObjectNewUbisoftClient;
struct ISystem;
enum UbiServerState
{
NoUbiServer, //Don't use Ubi.com
ServerDisconnected, //We're disconnected from Ubi.com try to reconnect
CreatingServer, //We're trying to create a ubi.com server
ServerConnected //We're connected to ubi.com
};
enum UbiClientState
{
NoUbiClient, //Don't use Ubi.com
ClientDisconnected, //We've disconnected from ubi.com and should try to reconnect.
ClientLoggingIn, //We're logging in to ubi.com
ClientLoggedIn, //We're Logged in to ubi.com
GameServerDisconnected, //We've been disconnect from the game server and should rejoin.
JoiningGameServer, //We're joining a game server
JoinedGameServer, //We've joined a game server
CreateUbiAccount //We're creating an account
};
class NewUbisoftClient :
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
private clMSClientClass,
#endif // EXCLUDE_UBICOM_CLIENT_SDK
private CRegisterServer
{
public:
//! constructor
NewUbisoftClient( const char *szLocalIPAddress );
//! destructor
~NewUbisoftClient();
bool WriteStringToRegistry(const string &szKeyName, const string &szValueName, const string &szValue);
bool ReadStringFromRegistry(const string &szKeyName, const string &szValueName, string &szValue);
bool RemoveStringFromRegistry(const string &szKeyName, const string &szValueName);
bool IsValueOnRegistry(const string &szKeyName, const string &szValueName);
bool EncryptString(unsigned char *szOut, const unsigned char *szIn);
bool DecryptString(unsigned char *szOut, const unsigned char *szIn);
bool EncodeHex(unsigned char *szOut, const unsigned char *szIn);
bool DecodeHex(unsigned char *szOut, const unsigned char *szIn);
//! establish the connection to the script object (call this only once)
//! \param inpObject must not be 0
void SetScriptObject( CScriptObjectNewUbisoftClient *inpObject );
//! \param inpSystem must not be 0
void Init( ISystem *inpSystem );
//! Must be called to send and receive messages from the Game Service.
//! Must be called even while playing the game.
bool Update();
/////////////////////////////////////////////
//
// The methods to be used by the game client.
// Implemented in NewUbisoftMSClient.cpp
//
/////////////////////////////////////////////
//Login the client to the Game Service
bool Client_AutoLogin();
//Login the client to the Game Service
bool Client_Login(const char *szUsername, const char *szPassword, bool bSavePassword=false);
//Request Game Server list. Game Servers are received by LUAGameServer.
bool Client_RequestGameServers();
// Tell the Game Service you are going to join the game server
bool Client_JoinGameServer(int iLobbyID, int iRoomID);
// Tell the Game Service you are going to rejoin the game server
bool Client_ReJoinGameServer();
// Tell the Game Service you have joined the game server
bool Client_ConnectedToGameServer();
// Tell the Game Service that you have left the game server
bool Client_LeaveGameServer();
// Disconnect from Game Service
bool Client_Disconnect();
// Create an account
bool Client_CreateAccount(const char *szUsername, const char *szPassword);
// Check if there is a connection
bool Client_IsConnected();
// Request the Authorization ID from the CDKey server
bool Client_GetCDKeyAuthorizationID();
// Will Check to see if we have the users CDKey. If we don't it will ask the user.
bool Client_CheckForCDKey();
// Set the users CDKey.
bool Client_SetCDKey(const char *szCDKey);
//Request the Message Of The Day. szLanguage is the two letter language code.
//See http://www.w3.org/WAI/ER/IG/ert/iso639.htm
bool Client_RequestMOTD(const char *szLanguage);
/////////////////////////////////////////////
//
// The methods to be used by the game server.
// Implemented in NewUbisoftRegServer.cpp
//
/////////////////////////////////////////////
void Server_CheckCDKeys(bool bCheck) { m_bCheckCDKeys = bCheck; };
// create the server on the Game Service
bool Server_CreateServer(const char* szServerName,unsigned int uiMaxPlayer);
// set the connection to the server
void Server_SetGamePort(unsigned short usGamePort);
// create the server on the Game Service
bool Server_RecreateServer();
// Update settings on the Game Service
bool Server_UpdateServer(unsigned int uiMaxPlayers, unsigned short usPort);
// Remove the server from Game Service
bool Server_DestroyServer();
// Check the AuthorizationID of a client. This triggers CXServerSlot::OnPlayerAuthorization()
bool Server_CheckPlayerAuthorizationID(BYTE bPlayerID,const BYTE *pubAuthorizationID);
// Tells the CDKeyServer that a player has left the game.
bool Server_RemovePlayer(BYTE bPlayerID);
// Remove all the players from the game.
bool Server_RemoveAllPlayers();
// Script Callbacks -------------------------------------------
void Client_LoginSuccess(const char *szUsername);
void Client_LoginFail(const char *szText);
void Client_GameServer(int iLobbyID, int iRoomID, const char *szServerName, const char *szIPAddress,
const char *szLANIPAddress, int iMaxPlayers, int iNumPlayers);
void Client_RequestFinished();
void Client_JoinGameServerSuccess(const char *szIPAddress, const char *szLanIPAddress,unsigned short usPort);
void Client_JoinGameServerFail(const char *szText);
void Client_CreateAccountSuccess();
void Client_CreateAccountFail(const char *szText);
void Server_RegisterServerSuccess(GSint iLobbyID, GSint iRoomID);
void Server_RegisterServerFail();
void Server_LobbyServerDisconnected();
void Server_PlayerJoin(const char *szUsername);
void Server_PlayerLeave(const char *szUsername);
// Pop up an error to the user.
void CDKey_Failed(const char *szText);
// Ask the user for a cdkey.
void CDKey_GetCDKey();
// The cdkey was successfully activated
void CDKey_ActivationSuccess();
// The cdkey activation failed. The user should reenter the cdkey.
void CDKey_ActivationFail(const char *szText);
// --------------------------------------------------------------
// --------------------------------------------------------------
// Callback that receives the Activation ID from the CDKey Server
void RcvActivationID(PREPLY_INFORMATION psReplyInfo, PVALIDATION_SERVER_INFO psValidationServerInfo,
GSubyte *pucActivationID,GSubyte *pucGlobalID);
// Callback that receives the Authorization ID from CDKeyServer. This ID must be sent to the Game Server.
void RcvAuthorizationID(PREPLY_INFORMATION psReplyInfo, PVALIDATION_SERVER_INFO psValidationServerInfo,
GSubyte *pucAuhorizationID);
// Callback that receives if a players cdkey is valid and the server should allow the player to connect
void RcvValidationResponse(PREPLY_INFORMATION psReplyInfo, PVALIDATION_SERVER_INFO psValidationServerInfo,
GSubyte *pucAuhorizationID, CDKEY_PLAYER_STATUS eStatus, GSubyte *pucGlobalID);
// Callback that asks to see if a player is still on the game server.
void RcvPlayerStatusRequest(PVALIDATION_SERVER_INFO psValidationServerInfo, GSubyte *pucAuhorizationID);
private: // -----------------------------------------------------------------
// Helper function to download gs.ini file from internet
bool DownloadGSini(const char *szUsername);
// Helper function to parse gs.ini file
bool GetRouterAddress(int iIndex, char *szIPAddress, unsigned short *pusClientPort,
unsigned short *pusRegServerPort);
void RegServerDisconnected();
void MSClientDisconnected();
typedef std::vector<GSubyte> CDKeyIDVector;
//CD Key methods
bool InitCDKeySystem();
bool GetCDKeyServerAddress(int iIndex, char *szIPAddress, unsigned short *pusPort);
// Save a clients Authoriziation ID
bool AddAuthorizedID(BYTE bPlayerID, const CDKeyIDVector &stAuthorizationID);
//Get a player's ID based on their Authorization ID
bool FindPlayerID(const CDKeyIDVector &stAuthorizationID, BYTE &bPlayer);
//Get a player's Authorization ID based on their ID
bool FindAuthorizedID(BYTE bPlayerID, CDKeyIDVector &stAuthorizationID);
//Remove a players Authorization ID
bool RemoveAuthorizedID(const CDKeyIDVector &stAuthorizationID);
bool RemoveAuthorizedID(BYTE bPlayer);
//Get the localization string for a CDKey error
bool GetCDKeyErrorText(GSushort usError,string &strText);
// Gets the error string and sends it to CDKey_Failed()
bool CDKey_Error(GSushort usError);
//Helper functions for Authorization IDs
void CopyIDToVector(CDKeyIDVector &stVector, const GSubyte *pubArray, unsigned int uiSize);
void CopyIDToString(const CDKeyIDVector &stVector, string &strString);
//Save and load CDkey information. Currently from the file cdkey.ini
void SaveCDKey(const GSchar *szCDKey);
void SaveActivationID(const GSubyte *pubActivationID);
bool LoadCDKey(GSchar *szCDKey);
bool LoadActivationID(GSubyte *pubActivationID);
//Request the Activation Id from the CDKey server.
bool RequestCDKeyActivationID();
// These are the MSClient callbacks to implement.
GSvoid GameServerCB(GSint iLobbyID,GSint iRoomID,GSshort siGroupType,
GSchar *szGroupName,GSint iConfig,GSchar *szMaster,GSchar *szAllowedGames,
GSchar *szGames,GSchar *szGameVersion,GSchar *szGSVersion,GSvoid *vpInfo,
GSint iSize,GSuint uiMaxPlayer,GSuint uiNbrPlayer,GSuint uiMaxVisitor,
GSuint uiNbrVisitor,GSchar *szIPAddress,GSchar *szAltIPAddress,
GSint iEventID);
GSvoid ErrorCB(GSint iReason,GSint iLobbyID,GSint iRoomID);
GSvoid InitFinishedCB(GSubyte ucType,GSint iError,GSchar *szUserName);
GSvoid LoginDisconnectCB();
GSvoid LobbyDisconnectCB();
GSvoid RequestFinishedCB();
GSvoid JoinFinishedCB(GSint iLobbyID,GSint iRoomID,
GSvoid *vpGameData,GSint iSize,GSchar *szIPAddress,
GSchar *szAltIPAddress,GSushort usPort);
GSvoid AlternateInfoCB(GSint iLobbyID,GSint iRoomID,
const GSvoid* pcAltGroupInfo,GSint iAltGroupInfoSize);
GSvoid RequestMOTDCB(GSubyte ubType, GSchar *szUbiMOTD,
GSchar *szGameMOTD, GSint iReason);
GSvoid AccountCreationCB(GSubyte ucType, GSint iReason);
GSvoid ModifyAccountCB(GSubyte ucType, GSint iReason);
//We aren't implementing Ladder support so these callbacks are ignored.
GSvoid MatchStartedCB(GSint iLobbyID,GSint iRoomID, GSuint uiMatchID){};
GSvoid SubmitMatchCB(GSubyte ucType,GSint iReason, GSuint uiMatchID){};
// These are the RegServer callbacks to implement
GSvoid RegServerRcv_LoginRouterResult( GSubyte ucType, GSint lReason,
const GSchar* szIPAddress );
GSvoid RegServerRcv_RouterDisconnection();
GSvoid RegServerRcv_RegisterServerResult( GSubyte pucType,GSint plReason,GSint iGroupID,
const GSchar* szAddress,GSushort usPort,const GSchar* szSessionName );
GSvoid RegServerRcv_RequestParentGroupResult( GSubyte ucType,
GSint lReason, GSint iServerID,GSint iGroupID, const GSchar* szGroupName,
GSuint uiNbPlayers, GSuint uiMaxPlayers );
GSvoid RegServerRcv_LobbyServerLoginResults( GSubyte ucType,
GSint iReason, GSint iLobbyServerID, GSint iGroupID );
GSvoid RegServerRcv_LobbyServerUpdateGroupSettingsResults(
GSubyte ucType, GSint iReason, GSint iGroupID );
GSvoid RegServerRcv_LobbyServerDisconnection();
GSvoid RegServerRcv_LobbyServerMemberNew( const GSchar* szMember,GSbool bSpectator,
const GSchar* szIPAddress, const GSchar* szAltIPAddress,
const GSvoid* pPlayerInfo, GSuint uiPlayerInfoSize,GSushort usPlayerStatus );
GSvoid RegServerRcv_LobbyServerMemberLeft(const GSchar* szMember );
GSvoid RegServerRcv_LobbyServerNewGroup (GSushort usRoomType,
const GSchar* szRoomName,GSint iGroupID,GSint iLobbyServerID,GSint iParentGroupID,
GSint uiGroupConfig,GSshort sGroupLevel,const GSchar* szMaster,const GSchar* szAllowedGames,
const GSchar* szGame,const GSvoid* pGroupInfo,GSuint GroupInfoSize,GSuint uiMatchEventID,
GSuint uiMaxPlayers,GSuint uiNbPlayers,GSuint uiMaxSpectators,GSuint uiNbSpectators,
const GSchar* szGameVersion,const GSchar* szGSGameVersion,const GSchar* szIPAddress,
const GSchar* szAltIPAddress );
// We can ignore these RegServer callbacks
GSvoid RegServerRcv_LobbyServerMatchStartReply( GSubyte ucType,
GSint iReason, GSint iGroupID ){};
GSvoid RegServerRcv_LobbyServerMatchFinishReply( GSubyte ucType,
GSint iReason, GSint iGroupID ){};
GSvoid RegServerRcv_LobbyServerGroupConfigUpdate(
GSuint uiGroupConfig, GSint iGroupID ){};
virtual GSvoid RegServerRcv_LobbyServerMemberUpdateInfo(const GSchar* szMember,
const GSvoid* pPlayerInfo,GSuint uiPlayerInfoSize ){};
GSvoid RegServerRcv_LobbyServerMemberUpdateStatus(const GSchar* szPlayer,
GSushort usPlayerStatus ){};
/*#if defined(LINUX32)
//dummy functions coming from new ubi.com sdk released for linux
virtual GSvoid RegServerRcv_SubmitMatchResultReply( GSubyte ucType,
GSint iReason, GSint iGroupID ){};
virtual GSvoid RegServerRcv_MatchStarted( GSuint uiMatchID ){};
virtual GSvoid RegServerRcv_FinalResult(GSuint uiMatchId, GSubyte ucType, GSint iReason, const LADDER_ROW *pResults, GSuint uiNumResult){};
#endif
*/
// These are the login settings to use if we have to re-login
string m_strUsername; //!<
string m_strPassword; //!<
// These are the settings to use when creating the game server
string m_strGameServerName; //!<
unsigned int m_uiMaxPlayers; //!<
unsigned short m_usGamePort; //!<
int m_iJoinedLobbyID; //!< The id of the lobby we joined
int m_iJoinedRoomID; //!< The id of the room we joined
bool m_bDownloadedGSini; //!< Have we downloaded the gs.ini file yet. We only need to do this once per game.s
int m_iServerLobbyID; //!< The lobby id of the game server
int m_iServerRoomID; //!< The room id of the game server
UbiServerState m_eServerState;
UbiClientState m_eClientState;
//CD Key members
GShandle m_hCDKey; //The handle for the cdkey library.
PVALIDATION_SERVER_INFO m_pCDKeyServer;
bool m_bCheckCDKeys; //If true the server will check cdkeys.
typedef std::map<CDKeyIDVector,BYTE> AuthorizedIDs;
AuthorizedIDs m_stAuthorizedIDs;
CScriptObjectNewUbisoftClient * m_pScriptObject; //!<
DWORD m_dwNextServerAbsTime; //!< in seconds (0 if deactivated)
DWORD m_dwNextClientAbsTime; //!< in seconds (0 if deactivated)
DWORD m_dwAccountCreateTime; //!< in seconds (0 if deactivated)
ILog * m_pLog; //!<
ISystem * m_pSystem; //!<
ICVar * sv_authport;
ICVar * sv_regserver_port;
bool m_bSavePassword;
bool m_bDisconnecting;
friend class cCScriptObjectNewUbisoftClient;
};
#endif // NOT_USE_UBICOM_SDK
#endif //__UBISOFT_MSCLIENT

View File

@@ -0,0 +1,556 @@
#include "stdafx.h"
#ifndef NOT_USE_UBICOM_SDK
#include "NewUbisoftClient.h"
#include "LobbyDefines.h"
#include "CommonDefines.h"
#if !defined(LINUX)
#include "windows.h"
#endif
#if !defined(LINUX)
#include <assert.h>
#endif
#include "ScriptObjectNewUbisoftClient.h" // CScriptObjectNewUbisoftClient
// the following libs are not in the project setting because we want to have then only in if NOT_USE_UBICOM_SDK is defined
/*#ifdef _DEBUG
#pragma comment(lib,"libgsclient_debug.lib")
#pragma comment(lib,"libgsconnect_debug.lib")
#pragma comment(lib,"libgscrypto_debug.lib")
#pragma comment(lib,"libgsutility_debug.lib")
#pragma comment(lib,"libgsregserver_debug.lib")
#pragma comment(lib,"libgssocket_debug.lib")
#pragma comment(lib,"libgsproxyclient_debug.lib")
#pragma comment(lib,"libgsresult_debug.lib")
#pragma comment(lib,"libgscdkey_debug.lib")
#else
*/
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
#pragma comment(lib,"libgsclient.lib")
#pragma comment(lib,"libgsmsclient.lib")
#endif // EXCLUDE_UBICOM_CLIENT_SDK
#pragma comment(lib,"libgsconnect.lib")
#pragma comment(lib,"libgscrypto.lib")
#pragma comment(lib,"libgsutility.lib")
#pragma comment(lib,"libgsregserver.lib")
#pragma comment(lib,"libgssocket.lib")
#pragma comment(lib,"libgsproxyclient.lib")
#pragma comment(lib,"libgsresult.lib")
#pragma comment(lib,"libgscdkey.lib")
//#endif
/*
gsnat,
gshttp,
gsdatacontainer,
gszlib,
*/
static DWORD g_dwKeepalifeLoginClient=60; // in seconds
static DWORD g_dwAccountCreateTimeout=60; //Timeout between calls to CreateAcount in seconds
bool NewUbisoftClient::Client_IsConnected()
{
if (m_eClientState >= ClientLoggedIn)
return true;
else
return false;
}
bool NewUbisoftClient::Client_AutoLogin()
{
if (m_strUsername.empty() || m_strPassword.empty())
{
string szHexUsername;
string szHexPassword;
if (!ReadStringFromRegistry("Ubi.com", "username", szHexUsername) || !ReadStringFromRegistry("Ubi.com", "password", szHexPassword))
{
return false;
}
char szEncUsername[256] = {0};
char szEncPassword[256] = {0};
char szUsername[256] = {0};
char szPassword[256] = {0};
DecodeHex((unsigned char *)szEncUsername, (unsigned char *)szHexUsername.c_str());
DecodeHex((unsigned char *)szEncPassword, (unsigned char *)szHexPassword.c_str());
DecryptString((unsigned char *)szUsername, (unsigned char *)szEncUsername);
DecryptString((unsigned char *)szPassword, (unsigned char *)szEncPassword);
m_strUsername = szUsername;
m_strPassword = szPassword;
}
return Client_Login(m_strUsername.c_str(), m_strPassword.c_str());
}
bool NewUbisoftClient::Client_Login(const GSchar* szUsername, const GSchar* szPassword, bool bSavePassword)
{
if (m_eClientState >= ClientLoggingIn)
return false;
// Save the username and password.
m_strUsername = szUsername;
m_strPassword = szPassword;
m_bSavePassword = bSavePassword;
// remove it now
if (!m_bSavePassword)
{
RemoveStringFromRegistry("Ubi.com", "username");
RemoveStringFromRegistry("Ubi.com", "password");
}
if (!DownloadGSini(szUsername))
{
Client_LoginFail(CONNECTIONFAILED);
return false;
}
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
// Go through numbered IP and Ports in the ini
char szIPAddress[50];
unsigned short usClientPort,usRegServerPort;
int iIndex = 0;
if (GetRouterAddress(iIndex,szIPAddress,&usClientPort,&usRegServerPort))
{
while (clMSClientClass::Initialize(szIPAddress, usClientPort, szUsername, szPassword,
UBISOFT_GAME_VERSION) == GS_FALSE)
{
iIndex++;
if (!GetRouterAddress(iIndex,szIPAddress,&usClientPort,&usRegServerPort))
{
MSClientDisconnected();
return false;
}
}
}
#endif // EXCLUDE_UBICOM_CLIENT_SDK
m_eClientState = ClientLoggingIn;
return true;
}
bool NewUbisoftClient::Client_RequestGameServers()
{
if (m_eClientState < ClientLoggedIn) // If we are logged in to the Game Service
return false;
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
if (m_eClientState > ClientLoggedIn)
{
m_pLog->Log("Ubi.com: Client_RequestGameServers %i",(int)m_eClientState);
clMSClientClass::LeaveGameServer(m_iJoinedLobbyID,m_iJoinedRoomID);
m_eClientState = ClientLoggedIn;
}
clMSClientClass::RequestGameServers(GAME_NAME);
#endif // EXCLUDE_UBICOM_CLIENT_SDK
return true;
}
bool NewUbisoftClient::Client_JoinGameServer(int iLobbyID, int iRoomID)
{
m_pLog->Log("Ubi.com: Client_JoinGameServer %i %i",iLobbyID, iRoomID);
switch (m_eClientState)
{
case NoUbiClient:
case ClientLoggingIn:
return false;
case ClientDisconnected:
{
// If we haven't logged in before
if (m_strUsername.empty())
return false;
m_iJoinedLobbyID = iLobbyID;
m_iJoinedRoomID = iRoomID;
Client_Login(m_strUsername.c_str(),m_strPassword.c_str());
return true;
}
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
case ClientLoggedIn:
case GameServerDisconnected:
{
if (clMSClientClass::JoinGameServer(iLobbyID,iRoomID
,"",GSGAMEVERSION,GAME_NAME,NULL,0))
{
m_iJoinedLobbyID = iLobbyID;
m_iJoinedRoomID = iRoomID;
m_eClientState = JoiningGameServer;
return true;
}
else
return false;
}
case JoinedGameServer:
if ((m_iJoinedLobbyID == iLobbyID) && (m_iJoinedRoomID == iRoomID))
return true;
else
{
if (clMSClientClass::JoinGameServer(iLobbyID,iRoomID
,"",GSGAMEVERSION,GAME_NAME,NULL,0))
{
m_iJoinedLobbyID = iLobbyID;
m_iJoinedRoomID = iRoomID;
m_eClientState = JoiningGameServer;
return true;
}
else
return false;
}
#endif // EXCLUDE_UBICOM_CLIENT_SDK
}
return false;
}
bool NewUbisoftClient::Client_ReJoinGameServer()
{
// Wait untill it's time to reconnect
if(m_dwNextClientAbsTime)
if(m_pScriptObject->GetAbsTimeInSeconds() < m_dwNextClientAbsTime)
return false;
m_dwNextClientAbsTime = 0;
switch (m_eClientState)
{
case NoUbiClient:
case ClientLoggingIn:
case JoiningGameServer:
case JoinedGameServer:
return false;
case ClientDisconnected:
case ClientLoggedIn:
case GameServerDisconnected:
Client_JoinGameServer(m_iJoinedLobbyID,m_iJoinedRoomID);
return true;
}
return false;
}
bool NewUbisoftClient::Client_ConnectedToGameServer()
{
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
if (clMSClientClass::GameServerConnected(m_iJoinedLobbyID,m_iJoinedRoomID))
return true;
else
#endif // EXCLUDE_UBICOM_CLIENT_SDK
return false;
}
bool NewUbisoftClient::Client_LeaveGameServer()
{
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
if (clMSClientClass::LeaveGameServer(m_iJoinedLobbyID,m_iJoinedRoomID))
{
m_iJoinedLobbyID = 0;
m_iJoinedRoomID = 0;
m_eClientState = ClientLoggedIn;
return true;
}
else
#endif // EXCLUDE_UBICOM_CLIENT_SDK
return false;
}
bool NewUbisoftClient::Client_Disconnect()
{
if (m_eClientState == NoUbiClient)
return true;
m_bCheckCDKeys = false;
if (m_eClientState != ClientLoggingIn)
{
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
clMSClientClass::Uninitialize();
#endif // EXCLUDE_UBICOM_CLIENT_SDK
m_iJoinedLobbyID = 0;
m_iJoinedRoomID= 0;
m_eClientState = NoUbiClient;
m_bDisconnecting = 0;
}
else
{
m_bDisconnecting = 1;
}
Update();
return true;
}
bool NewUbisoftClient::Client_CreateAccount(const char *szUsername, const char *szPassword)
{
if (m_eClientState != NoUbiClient)
return false;
if (m_dwAccountCreateTime)
if(m_pScriptObject->GetAbsTimeInSeconds() < m_dwAccountCreateTime)
Client_CreateAccountFail(CREATEACCOUNTBLOCKED);
m_eClientState = CreateUbiAccount;
if (!DownloadGSini(szUsername))
return false;
// Go through numbered IP and Ports in the ini
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
char szIPAddress[50];
unsigned short usClientPort,usRegServerPort;
int iIndex = 0;
if (GetRouterAddress(iIndex,szIPAddress,&usClientPort,&usRegServerPort))
{
while (clMSClientClass::CreateAccount(szIPAddress, usClientPort, UBISOFT_GAME_VERSION, szUsername,
szPassword, "","","","") == GS_FALSE)
{
iIndex++;
if (!GetRouterAddress(iIndex,szIPAddress,&usClientPort,&usRegServerPort))
return false;
}
}
#endif // EXCLUDE_UBICOM_CLIENT_SDK
return true;
}
bool NewUbisoftClient::Client_RequestMOTD(const char *szLanguage)
{
if (m_eClientState < ClientLoggedIn)
return false;
#ifndef EXCLUDE_UBICOM_CLIENT_SDK
if (RequestMOTD(szLanguage))
return true;
else
#endif // EXCLUDE_UBICOM_CLIENT_SDK
return false;
}
///////////////////////////////////////////////////////
//
// MSClient Callbacks
//
///////////////////////////////////////////////////////
GSvoid NewUbisoftClient::GameServerCB(GSint iLobbyID,GSint iRoomID,GSshort siGroupType,
GSchar *szGroupName,GSint iConfig,GSchar *szMaster,GSchar *szAllowedGames,
GSchar *szGames,GSchar *szGameVersion,GSchar *szGSVersion,GSvoid *vpInfo,
GSint iSize,GSuint uiMaxPlayer,GSuint uiNbrPlayer,GSuint uiMaxVisitor,
GSuint uiNbrVisitor,GSchar *szIPAddress,GSchar *szAltIPAddress,
GSint iEventID)
{
char *szPort = (char*)vpInfo;
char szGameIPAddress[32],szGameLANIPAddress[32];
m_pLog->Log("Ubi.com: GameServerCB %s %i %i",szGroupName,iLobbyID, iRoomID);
_snprintf(szGameIPAddress,32,"%s:%s",szIPAddress,szPort);
_snprintf(szGameLANIPAddress,32,"%s:%s",szAltIPAddress,szPort);
Client_GameServer(iLobbyID,iRoomID,szGroupName,szGameIPAddress,szGameLANIPAddress,
uiMaxPlayer,uiNbrPlayer);
}
GSvoid NewUbisoftClient::ErrorCB(GSint iReason,GSint iLobbyID,GSint iRoomID)
{
m_pLog->Log("Ubi.com: ErrorCB %i %i",iLobbyID, iRoomID);
m_eClientState = GameServerDisconnected;
m_dwNextClientAbsTime = m_pScriptObject->GetAbsTimeInSeconds() + g_dwKeepalifeLoginClient;
switch (iReason)
{
default:
case ERRORLOBBYSRV_UNKNOWNERROR:
Client_JoinGameServerFail(UNKNOWNERROR);
break;
case ERRORLOBBYSRV_GROUPNOTEXIST:
Client_JoinGameServerFail(GROUPNOTEXIST);
break;
case ERRORLOBBYSRV_NOMOREPLAYERS:
case ERRORLOBBYSRV_NOMOREMEMBERS:
Client_JoinGameServerFail(NOMOREPLAYERS);
break;
}
}
GSvoid NewUbisoftClient::InitFinishedCB(GSubyte ucType,GSint iError,GSchar *szUserName)
{
if (m_bDisconnecting)
{
// fake logged in state
// so we can actually get disconnected
m_eClientState = ClientLoggedIn;
Client_Disconnect();
return;
}
if (ucType == GSSUCCESS)
{
m_strUsername = szUserName;
m_eClientState = ClientLoggedIn;
if (m_iJoinedLobbyID)
{
Client_JoinGameServer(m_iJoinedLobbyID,m_iJoinedRoomID);
m_eClientState = JoiningGameServer;
}
Client_LoginSuccess(szUserName);
Client_CheckForCDKey();
}
else
{
m_eClientState = NoUbiClient;
switch (iError)
{
case ERRORSECURE_INVALIDACCOUNT:
Client_LoginFail(INVALIDACCOUNT);
break;
case ERRORSECURE_INVALIDPASSWORD:
Client_LoginFail(INVALIDPASSWORD);
break;
case ERRORSECURE_DATABASEFAILED:
Client_LoginFail(DATABASEFAILED);
break;
case ERRORSECURE_BANNEDACCOUNT:
Client_LoginFail(BANNEDACCOUNT);
break;
case ERRORSECURE_BLOCKEDACCOUNT:
Client_LoginFail(BLOCKEDACCOUNT);
break;
case ERRORSECURE_LOCKEDACCOUNT:
Client_LoginFail(LOCKEDACCOUNT);
break;
case ERRORROUTER_NOTDISCONNECTED:
Client_LoginFail(NOTDISCONNECTED);
}
}
}
GSvoid NewUbisoftClient::LoginDisconnectCB()
{
m_pLog->Log("Ubi.com: LoginDisconnectCB");
if (m_eClientState == ClientLoggingIn)
m_eClientState = NoUbiClient;
else
MSClientDisconnected();
}
GSvoid NewUbisoftClient::LobbyDisconnectCB()
{
m_pLog->Log("Ubi.com: LobbyDisconnectCB");
if (m_eClientState > GameServerDisconnected)
m_eClientState = GameServerDisconnected;
}
GSvoid NewUbisoftClient::RequestFinishedCB()
{
Client_RequestFinished();
}
GSvoid NewUbisoftClient::JoinFinishedCB(GSint iLobbyID,GSint iRoomID,
GSvoid *vpGameData,GSint iSize,GSchar *szIPAddress,
GSchar *szAltIPAddress,GSushort usPort)
{
m_eClientState = JoinedGameServer;
Client_ConnectedToGameServer();
Client_JoinGameServerSuccess(szIPAddress,szAltIPAddress,usPort);
}
GSvoid NewUbisoftClient::AlternateInfoCB(GSint iLobbyID,GSint iRoomID,
const GSvoid* pcAltGroupInfo,GSint iAltGroupInfoSize)
{
}
GSvoid NewUbisoftClient::AccountCreationCB(GSubyte ucType, GSint iReason)
{
m_eClientState = NoUbiClient;
if (ucType == GSSUCCESS)
{
m_dwAccountCreateTime = m_pScriptObject->GetAbsTimeInSeconds() + g_dwAccountCreateTimeout;
Client_CreateAccountSuccess();
}
else
{
m_dwAccountCreateTime = 0;
switch (ucType)
{
default:
Client_CreateAccountFail(UNKNOWNERROR);
break;
case ERRORSECURE_USERNAMEEXISTS:
Client_CreateAccountFail(USERNAMEEXISTS);
break;
case ERRORSECURE_USERNAMEMALFORMED:
Client_CreateAccountFail(USERNAMEMALFORMED);
break;
case ERRORSECURE_USERNAMEFORBIDDEN:
Client_CreateAccountFail(USERNAMEFORBIDDEN);
break;
case ERRORSECURE_USERNAMERESERVED:
Client_CreateAccountFail(USERNAMERESERVED);
break;
case ERRORSECURE_PASSWORDMALFORMED:
Client_CreateAccountFail(PASSWORDMALFORMED);
break;
case ERRORSECURE_PASSWORDFORBIDDEN:
Client_CreateAccountFail(PASSWORDFORBIDDEN);
break;
}
}
}
GSvoid NewUbisoftClient::ModifyAccountCB(GSubyte ucType, GSint iReason)
{
}
GSvoid NewUbisoftClient::RequestMOTDCB(GSubyte ubType, GSchar *szUbiMOTD, GSchar *szGameMOTD, GSint iReason)
{
if (ubType == GSSUCCESS)
m_pScriptObject->Client_MOTD(szUbiMOTD,szGameMOTD);
}
void NewUbisoftClient::MSClientDisconnected()
{
// was this a requested disconnect ?
if (m_eClientState != NoUbiClient)
{
m_eClientState = ClientDisconnected;
}
m_dwNextClientAbsTime = m_pScriptObject->GetAbsTimeInSeconds() + g_dwKeepalifeLoginClient;
}
#else // NOT_USE_UBICOM_SDK
// the following libs are excluded from the build in the project settings and here they are included
// because only if we don't use UBI.com we need them
#ifdef _DEBUG
#pragma comment(lib,"libcmtd.lib")
#else
#pragma comment(lib,"libcmt.lib")
#endif
#endif // NOT_USE_UBICOM_SDK

View File

@@ -0,0 +1,286 @@
#include "stdafx.h"
#ifndef NOT_USE_UBICOM_SDK
#include "NewUbisoftClient.h"
#include "LobbyDefines.h"
#include "CommonDefines.h"
#include "IConsole.h" // ICVar
#if !defined(LINUX)
#include <assert.h>
#endif
#if defined(WIN32) || defined(WIN64)
#include "windows.h"
#endif
#include "ScriptObjectNewUbisoftClient.h" // CScriptObjectNewUbisoftClient
using namespace std;
static const char GUESTUSERNAME[33]="Ubi_Guest";
static const char GUESTPASSWORD[17]="testtest";
static DWORD g_dwKeepalifeCreateServer=60; // in seconds
bool NewUbisoftClient::Server_CreateServer( const char* szServerName,unsigned int uiMaxPlayer )
{
// m_pLog->Log("Ubi.com: DEBUG NewUbisoftClient::Server_CreateServer() 1");
// The server should check cdkeys
if ((m_eServerState == CreatingServer) || (m_eServerState == ServerConnected))
return false;
m_eServerState = ServerDisconnected;
// m_pLog->Log("Ubi.com: DEBUG NewUbisoftClient::Server_CreateServer() 2");
if (!DownloadGSini(GUESTUSERNAME))
return false;
// m_pLog->Log("Ubi.com: DEBUG NewUbisoftClient::Server_CreateServer() 3");
m_dwNextServerAbsTime = 0;
m_strGameServerName = szServerName;
m_uiMaxPlayers = uiMaxPlayer;
if (m_strGameServerName.size() > 32)
{
m_strGameServerName.resize(29);
m_strGameServerName += "...";
}
return Server_RecreateServer();
}
void NewUbisoftClient::Server_SetGamePort( unsigned short usGamePort )
{
m_usGamePort = usGamePort;
}
bool NewUbisoftClient::Server_RecreateServer()
{
// Only recreate the server if were disconnected
if (m_eServerState != ServerDisconnected)
return false;
// Wait untill it's time to reconnect
if(m_dwNextServerAbsTime)
if(m_pScriptObject->GetAbsTimeInSeconds() < m_dwNextServerAbsTime)
return false;
IServer *pServer = m_pSystem->GetINetwork()->GetServerByPort(m_usGamePort);
// if this is a lan server
if(pServer && pServer->GetServerType()==eMPST_LAN)
return false;
// m_pLog->Log("Ubi.com: DEBUG Server_RecreateServer() 3");
m_pLog->Log("\001Ubi.com: Server_RecreateServer");
m_dwNextServerAbsTime = 0;
m_eServerState = CreatingServer;
// Go through numbered IP and Ports in the ini
char szIPAddress[50];
unsigned short usClientPort,usRegServerPort;
int iIndex = 0;
if (GetRouterAddress(iIndex,szIPAddress,&usClientPort,&usRegServerPort))
{
while (CRegisterServer::RegServerSend_RouterConnect(szIPAddress, usRegServerPort) == GS_FALSE)
{
m_pLog->Log("\001Ubi.com: RegServerSend_RouterConnect '%s:%d' failed",szIPAddress,(int)usRegServerPort);
iIndex++;
if (!GetRouterAddress(iIndex,szIPAddress,&usClientPort,&usRegServerPort))
{
RegServerDisconnected();
return false;
}
}
}
CRegisterServer::RegServerSend_LoginRouter(GUESTUSERNAME,GUESTPASSWORD,UBISOFT_GAME_VERSION);
return true;
}
bool NewUbisoftClient::Server_UpdateServer(unsigned int uiMaxPlayers, unsigned short usPort)
{
if (RegServerSend_UpdateGroupSettings(m_iServerRoomID,-1,-1,-1,uiMaxPlayers,-1,NULL,NULL,-1,NULL,-1,NULL,-1,usPort))
return true;
else
return false;
}
bool NewUbisoftClient::Server_DestroyServer()
{
IServer *pServer = m_pSystem->GetINetwork()->GetServerByPort(m_usGamePort);
if(!pServer)
return false;
// If the server type isn't UBI then do nothing
if(pServer->GetServerType()!=eMPST_UBI)
return false;
//We no longer want to run a ubi.com server
m_eServerState = NoUbiServer;
m_dwNextServerAbsTime = 0;
// The server stop checking cdkeys
RegServerSend_RouterDisconnect();
RegServerSend_LobbyServerClose();
for (int i = 0; i < 10; i++)
{
Sleep(100);
Update();
}
m_eServerState = NoUbiServer;
return true;
}
////////////////////////////////////////////////////////////////////
//
// The Server callbacks
//
////////////////////////////////////////////////////////////////////
GSvoid NewUbisoftClient::RegServerRcv_LoginRouterResult( GSubyte ucType, GSint lReason,
const GSchar* szIPAddress )
{
if (ucType == GSFAIL)
{
m_pLog->Log("\001Ubi.com: LoginRouterResult failed");
Server_RegisterServerFail();
RegServerDisconnected();
return;
}
CRegisterServer::RegServerSend_RequestParentGroupOnLobby(GAME_NAME);
}
GSvoid NewUbisoftClient::RegServerRcv_RouterDisconnection()
{
//Server_RouterDisconnected();
}
GSvoid NewUbisoftClient::RegServerRcv_RegisterServerResult( GSubyte ucType,GSint plReason,GSint iGroupID,
const GSchar* szAddress,GSushort usPort,const GSchar* szSessionName )
{
if (ucType == GSSUCCESS)
{
int iPort = sv_regserver_port->GetIVal();
if (!RegServerSend_LobbyServerConnection(szAddress, usPort,iPort,10))
{
m_pLog->Log("\001Ubi.com: LobbyServerConnection failed %s %i",szAddress,usPort);
RegServerDisconnected();
Server_RegisterServerFail();
return;
}
RegServerSend_LobbyServerLogin(GUESTUSERNAME,iGroupID);
}
else
{
m_pLog->Log("\001Ubi.com: RegisterServerResult failed");
RegServerDisconnected();
}
}
GSvoid NewUbisoftClient::RegServerRcv_RequestParentGroupResult( GSubyte ucType,
GSint lReason, GSint iServerID,GSint iGroupID, const GSchar* szGroupName,
GSuint uiNbPlayers, GSuint uiMaxPlayers )
{
if (ucType == GSSUCCESS)
{
// if the server id less them or equal to 0 then we have finished receiving the list of Parent Groups
if (iServerID <=0)
{
GSchar szData[100];
_snprintf(szData,100,"%i",m_usGamePort);
m_pLog->Log("\001Ubi.com: RequestParentGroupResult success");
// We will let the library pick the best parent group to register on.
CRegisterServer::RegServerSend_RegisterServerOnLobby(0,0,m_strGameServerName.c_str(),
GAME_NAME,ROOM_UBI_CLIENTHOST_REGSERVER,m_uiMaxPlayers,0,"",szData,sizeof(szData),NULL,0,NULL,0,
m_usGamePort,"",GSGAMEVERSION,GS_FALSE,GS_FALSE);
}
}
}
GSvoid NewUbisoftClient::RegServerRcv_LobbyServerLoginResults( GSubyte ucType,
GSint iReason, GSint iLobbyServerID, GSint iGroupID )
{
if (ucType == GSSUCCESS)
{
RegServerSend_RouterDisconnect();
m_iServerLobbyID = iLobbyServerID;
m_iServerRoomID = iGroupID;
m_pLog->Log("\001Ubi.com Game Server Register Success");
m_eServerState = ServerConnected;
if (m_eClientState != NoUbiClient)
{
m_iJoinedLobbyID = iLobbyServerID;
m_iJoinedRoomID = iGroupID;
}
Server_RegisterServerSuccess(iLobbyServerID, iGroupID);
}
else
{
RegServerDisconnected();
m_pLog->Log("\001Ubi.com Game Server Register Failed");
Server_RegisterServerFail();
}
}
GSvoid NewUbisoftClient::RegServerRcv_LobbyServerUpdateGroupSettingsResults(
GSubyte ucType, GSint iReason, GSint iGroupID )
{
}
GSvoid NewUbisoftClient::RegServerRcv_LobbyServerDisconnection()
{
RegServerDisconnected();
Server_LobbyServerDisconnected();
}
GSvoid NewUbisoftClient::RegServerRcv_LobbyServerMemberNew( const GSchar* szMember,GSbool bSpectator,
const GSchar* szIPAddress, const GSchar* szAltIPAddress,
const GSvoid* pPlayerInfo, GSuint uiPlayerInfoSize,GSushort usPlayerStatus )
{
Server_PlayerJoin(szMember);
}
GSvoid NewUbisoftClient::RegServerRcv_LobbyServerMemberLeft(const GSchar* szMember )
{
Server_PlayerLeave(szMember);
}
GSvoid NewUbisoftClient::RegServerRcv_LobbyServerNewGroup (GSushort usRoomType,
const GSchar* szRoomName,GSint iGroupID,GSint iLobbyServerID,GSint iParentGroupID,
GSint uiGroupConfig,GSshort sGroupLevel,const GSchar* szMaster,const GSchar* szAllowedGames,
const GSchar* szGame,const GSvoid* pGroupInfo,GSuint GroupInfoSize,GSuint uiMatchEventID,
GSuint uiMaxPlayers,GSuint uiNbPlayers,GSuint uiMaxSpectators,GSuint uiNbSpectators,
const GSchar* szGameVersion,const GSchar* szGSGameVersion,const GSchar* szIPAddress,
const GSchar* szAltIPAddress )
{
}
void NewUbisoftClient::RegServerDisconnected()
{
m_pLog->Log("\001Ubi.com: RegServerDisconnected");
m_eServerState = ServerDisconnected;
m_dwNextServerAbsTime = m_pScriptObject->GetAbsTimeInSeconds() + g_dwKeepalifeCreateServer;
}
#endif // NOT_USE_UBICOM_SDK

100
CryNetwork/PingCalculator.h Normal file
View File

@@ -0,0 +1,100 @@
//////////////////////////////////////////////////////////////////////
//
// Game Source Code
//
// File: PingCalculator.h
// Description: Latency(Ping) calculator
//
// History:
// - August 10, 2001: Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#ifndef _PING_CALCULATOR_H_
#define _PING_CALCULATOR_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define NUM_OF_SAMPLES 10
#define DIV_MULTIPLIER (1.0/NUM_OF_SAMPLES)
#define INC_INDEX(a) (a) = ((++a)%NUM_OF_SAMPLES)
#define PING_RATE 500
class CPingCalculator
{
public:
CPingCalculator()
{
m_nSampleIndex = 0;
m_nLastSample = 0;
m_bSyncronized = false;
m_nRemoteTimestamp = 0;
memset(m_fSample, 0, sizeof(m_fSample));
m_fPing=100;
}
float GetAverageLatency()
{
float fSum = 0;
// return (fSum*(DIV_MULTIPLIER));
return m_fPing;
}
bool IsTimeToPing(unsigned int nCurrentTime)
{
if ((nCurrentTime - m_nLastSample)>PING_RATE)
{
m_nLastSample = nCurrentTime;
return true;
}
return false;
}
void AddSample(float f,unsigned int nLocalTimestamp,unsigned int nRemoteTimestamp)
{
float fSum = 0;
float fTemp[NUM_OF_SAMPLES];
m_fSample[m_nSampleIndex] = f*0.5f;
memcpy(fTemp, m_fSample, sizeof(fTemp));
qsort(fTemp, NUM_OF_SAMPLES, sizeof(float), CPingCalculator::Compare);
m_fPing = fTemp[NUM_OF_SAMPLES/2];
INC_INDEX(m_nSampleIndex);
NET_TRACE("PING %04d\n", LONG(m_fPing));
m_nRemoteTimestamp=(unsigned int)(nRemoteTimestamp-m_fPing);
m_nLocalTimestamp=nLocalTimestamp;
}
unsigned int GetCurrentRemoteTimestamp(unsigned int nLocalTimestamp){
unsigned int nCurrentDelta=m_nLocalTimestamp-nLocalTimestamp;
return m_nRemoteTimestamp+nCurrentDelta;
}
unsigned int GetPacketLatency(unsigned int nLocalTimestamp,unsigned int nPacketTimestamp){
unsigned int nRemote=GetCurrentRemoteTimestamp(nLocalTimestamp);
return nPacketTimestamp-nRemote;
}
static int __cdecl Compare(const void *arg1, const void *arg2)
{
float f = ((*(float *)arg1 - (*(float *)arg2)));
if (f>0)
return 1; // greater
if (f < 0)
return -1; // less
return 0; // equel
}
private:
float m_fSample[NUM_OF_SAMPLES];
//! middle value of all samples
float m_fPing;
unsigned int m_nSampleIndex;
unsigned int m_nLastSample;
bool m_bSyncronized;
//! average remote timestamp
unsigned int m_nRemoteTimestamp;
//! local timestamp
unsigned int m_nLocalTimestamp;
};
#endif // _PING_CALCULATOR_H_

View File

@@ -0,0 +1,931 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2001-2004.
// -------------------------------------------------------------------------
// File name: PunkBusterInterface.cpp
// Version: v1.00
// Created: 1/3/2004 by Timur.
// Compilers: Visual Studio.NET 2003
// Description: Interface to the PunkBuster from CryEngine.
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#if !defined(NOT_USE_PUNKBUSTER_SDK)
#include "PunkBusterInterface.h"
#define PbSdk_DEFINED
#include "../PunkBuster/pbsdk.h"
#include "../PunkBuster/pbmd5.h"
#include "Network.h"
#include "IRenderer.h"
#include "ServerSlot.h"
#include "Server.h"
#include "Client.h"
#include "ClientLocal.h"
#include "ICryPak.h"
static const char RegistryKeyName[] = "SOFTWARE\\Crytek\\FarCry";
static const char CDKEYREGKEY[] = "CDKey";
void PBcomputeHash ( char *idhash , CServerSlot *pSlot ) ;//defined in this source file after class definitions
//////////////////////////////////////////////////////////////////////////
CPunkBusterInterface::CPunkBusterInterface( CNetwork *pNetwork )
{
m_bSinglePlayer = false ;
m_bClInitialized = false;
m_bSvInitialized = false;
m_pNetwork = pNetwork;
m_pSystem = pNetwork->GetSystem();
m_pClient = 0;
m_pClientLocal = 0;
m_pServer = 0;
sys_punkbuster_loaded = 0;
cl_punkbuster = m_pSystem->GetIConsole()->CreateVariable( "cl_punkbuster","0",VF_DUMPTODISK,"Enables PunkBuster for client, 1=Enabled,0=Disabled" );
sv_punkbuster = m_pSystem->GetIConsole()->CreateVariable( "sv_punkbuster","0",VF_DUMPTODISK,"Enables PunkBuster for server, 1=Enabled,0=Disabled" );
fs_homepath = m_pSystem->GetIConsole()->CreateVariable( "fs_homepath","",VF_DUMPTODISK,"Specifies alternate PunkBuster 'home' (if non-empty)" );
// Start recieving OnBeforeVarChange events.
m_pSystem->GetIConsole()->AddConsoleVarSink(this);
m_pSystem->GetIConsole()->AddOutputPrintSink(this);
}
//////////////////////////////////////////////////////////////////////////
CPunkBusterInterface::~CPunkBusterInterface()
{
if ( sys_punkbuster_loaded ) {
SAFE_RELEASE(sys_punkbuster_loaded);
sys_punkbuster_loaded = 0 ;
}
m_pSystem->GetIConsole()->RemoveOutputPrintSink(this);
m_pSystem->GetIConsole()->RemoveConsoleVarSink(this);
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::Init( bool bClient , bool isLocalServer )
{
if ( bClient == false ) {
m_bSinglePlayer = !isLocalServer ;
if ( m_bSinglePlayer == true ) {
ShutDown ( false ) ;
return ;
}
} else if ( m_bSinglePlayer ) return ;
if ( !sys_punkbuster_loaded ) {
sys_punkbuster_loaded = m_pSystem->GetIConsole()->CreateVariable( "sys_punkbuster_loaded","1",NULL);
}
if ( bClient ) {
if ( m_bClInitialized ) return ;
PbClientInitialize ( this ) ;
m_bClInitialized = true;
} else {
if ( m_bSvInitialized ) return ;
PbServerInitialize() ;
m_bSvInitialized = true;
}
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::SetServer( CServer *pServer )
{
m_pServer = pServer;
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::SetClient( CClient *pClient )
{
m_pClient = pClient;
m_pClientLocal = 0;
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::SetClientLocal( CClientLocal *pClient )
{
m_pClientLocal = pClient;
m_pClient = 0;
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::LockCVars()
{
cl_punkbuster->SetFlags( cl_punkbuster->GetFlags() | VF_READONLY );
sv_punkbuster->SetFlags( sv_punkbuster->GetFlags() | VF_READONLY );
fs_homepath->SetFlags( fs_homepath->GetFlags() | VF_READONLY );
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::UnlockCVars()
{
cl_punkbuster->SetFlags( cl_punkbuster->GetFlags() & ~VF_READONLY );
sv_punkbuster->SetFlags( sv_punkbuster->GetFlags() & ~VF_READONLY );
fs_homepath->SetFlags( fs_homepath->GetFlags() & ~VF_READONLY );
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::ShutDown( bool bClient )
{
// m_bInitialized = false;
if ( sys_punkbuster_loaded ) {
SAFE_RELEASE(sys_punkbuster_loaded);
sys_punkbuster_loaded = 0 ;
}
if (bClient)
{
m_pClientLocal = 0;
m_pClient = 0;
}
else
{
m_pServer = 0;
}
UnlockCVars();
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::Update( bool bClient )
{
if ( !sys_punkbuster_loaded ) return ;//no PB processing when PB has been shut down or is not yet initialized
if ( bClient) {
if (!m_bClInitialized) return;
PbClientProcessEvents() ;
} else {
if (!m_bSvInitialized) return;
PbServerProcessEvents() ;
}
}
//////////////////////////////////////////////////////////////////////////
bool CPunkBusterInterface::OnBeforeVarChange( ICVar *pVar,const char *sNewValue )
{
// if (!m_bInitialized)
// return true;
return true;
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::Print( const char *inszText )
{
PbCaptureConsoleOutput ( (char *) inszText , strlen ( inszText ) ) ;
}
//////////////////////////////////////////////////////////////////////////
bool CPunkBusterInterface::LoadCDKey( string &sCDKey )
{
if (ReadStringFromRegistry("Ubi.com", CDKEYREGKEY, sCDKey))
{
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CPunkBusterInterface::ReadStringFromRegistry(const string &szKeyName, const string &szValueName, string &szValue)
{
#ifdef WIN32
HKEY hKey;
string szREGKeyName = string(RegistryKeyName) + string("\\") + szKeyName;
if (RegOpenKey(HKEY_LOCAL_MACHINE, szREGKeyName.c_str(), &hKey) != ERROR_SUCCESS)
{
return false;
}
DWORD dwSize = 0;
if (RegQueryValueEx(hKey, szValueName.c_str(), 0, 0, 0, &dwSize) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return false;
}
szValue.resize(dwSize);
RegQueryValueEx(hKey, szValueName.c_str(), 0, 0, (LPBYTE)szValue.c_str(), &dwSize);
RegCloseKey(hKey);
return true;
#else
return false;
#endif
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::OnAddClient( CIPAddress &clientIP )
{
// Must have server by this point.
// assert( m_pServer );
if ( !m_pServer ) return ;//happens in single-player mode
//at this point in the process, just add the client address and idhash, see PBgetClientInfo() later in this source file
char addr[32] ;
strncpy ( addr , clientIP.GetAsString(true) , 31 ) ;
addr[31] = 0 ;
if ( clientIP.IsLocalHost() ) strcpy ( addr , "localhost" ) ;
// if ( !strcmp ( addr , "127.0.0.1:0" ) ) strcpy ( addr , "localhost" ) ;
char idhash[PB_GUIDLEN+1] = "" ;
CServerSlot *pSlot = m_pServer->GetPacketOwner( clientIP );
if (pSlot)
{
PBcomputeHash ( idhash , pSlot ) ;
} else {
strcpy ( idhash , "" ) ;
}
PbSvAddClient ( addr , "" , idhash ) ;
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::OnDisconnectClient( CIPAddress &clientIP )
{
char addr[32] ;
strncpy ( addr , clientIP.GetAsString(true) , 31 ) ;
addr[31] = 0 ;
if ( !strcmp ( addr , "127.0.0.1:0" ) ) strcpy ( addr , "localhost" ) ;
PbSvRemoveClient ( addr ) ;
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::CheaterFound( CIPAddress &clientIP,int type,const char *sMsg )
{
if (m_pServer && m_pServer->GetSecuritySink())
{
m_pServer->GetSecuritySink()->CheaterFound( clientIP.GetAsUINT(),type,sMsg );
}
}
bool CPunkBusterInterface::CheckPBPacket(CStream &stmPacket,CIPAddress &ip)
{
int len = stmPacket.GetSize() >> 3 ;//convert bits to bytes
if ( len >= 7) // Must be at least 7 bytes int.
{
BYTE *pBuf = stmPacket.GetPtr();
if ( !memcmp ( pBuf , "\xff\xff\xff\xffPB_" , 7 ) ) {
//if not ded
if ( pBuf[7] != 'S' && pBuf[7] != '2' && pBuf[7] != 'G' && pBuf[7] != 'I'
&& pBuf[7] != 'Y' && pBuf[7] != 'B' && pBuf[7] != 'L' )
PbClAddEvent ( PB_EV_PACKET , len - 4 , (char *) pBuf + 4 ) ;
//
if ( pBuf[7] != 'C' && pBuf[7] != '1' && pBuf[7] != 'J' )
PbSvAddEvent ( PB_EV_PACKET , -1 , len - 4 , (char *) pBuf + 4 ) ;
return false ;//yes pb packet
}
}
return true;//not a pb packet
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::ValidateClient( CServerSlot *pSlot )
{
//this function is called as client is trying to connect before level load
//if PB is enabled at this server, it checks to see if the PB client is enabled for the player
// and checks for any ban issues with the id/hash
unsigned int nFlags = pSlot->GetClientFlags();
char idhash[PB_GUIDLEN+1] = "" , addr[32] = "" ;
strncpy ( addr , pSlot->GetIP().GetAsString(true) , 31 ) ;
addr[31] = 0 ;
PBcomputeHash ( idhash , pSlot ) ;
char *res = PbAuthClient ( addr , nFlags & CLIENT_FLAGS_PUNK_BUSTER , idhash ) ;
if ( res != NULL ) pSlot->Disconnect ( res ) ;
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::OnCCPPunkBusterMsg( CIPAddress &ipAddress,CStream &stm )
{
if ( m_pClient || m_pClientLocal )
{
BYTE *pByte = stm.GetPtr() ;
PbClAddEvent ( PB_EV_PACKET , stm.GetSize() >> 3 , (char *) pByte ) ;//convert bits to bytes
}
if ( m_pServer )
{
int i = 0 ;
char *addr = ipAddress.GetAsString(true);
for ( i = 0 ; i < PB_MAX_CLIENTS ; i++ ) if ( !strcmp ( addr , pbsdk->pbsv.m_client[i].pbc.ip ) ) break ;
if ( i < PB_MAX_CLIENTS ) {
BYTE *pByte = stm.GetPtr() ;
PbSvAddEvent ( PB_EV_PACKET , i , stm.GetSize() >> 3 , (char *) pByte ) ;//convert bits to bytes
}
}
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::SendMsgToClient( CIPAddress &clientIP,CStream &stm )
{
if (m_pServer)
{
CServerSlot *pSlot = m_pServer->GetPacketOwner(clientIP);
if (pSlot)
{
pSlot->SendPunkBusterMsg(stm);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CPunkBusterInterface::SendMsgToServer( CStream &stm )
{
if (m_pClient)//don't check for local here because those packets are handled internally by PB
{
m_pClient->SendPunkBusterMsg( stm );
}
}
//below added by TR as "glue" functions
//
// PBoutgame
//
void PBoutgame ( char *text , int hudAlso )
{
if ( pbsdk == NULL ) return ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return ;
char *te = text , hold = 0 ;
for(;;) { //loop in case of multiple lines (to simulate linefeeds)
char *cp = strstr ( te , "\n" ) ;
if ( cp != NULL ) { //linefeed found so hold end-char and terminate
hold = *cp ;
*cp = 0 ;
} else hold = 0 ; //signifies end of line
int wrapat = 89 ;
if ( *te ) { //ignore empty lines
char *wrp = te ;
while ( *wrp ) {
char hold = 0 ;
if ( strlen ( wrp ) > wrapat ) {
hold = wrp[wrapat] ;
wrp[wrapat] = 0 ;
}
pip->m_pSystem->GetIConsole()->PrintLine ( wrp ) ; //output to console
if ( !hold ) break ;
wrp[wrapat] = hold ;
wrp += wrapat ;
}
if ( hudAlso ) { //optionally output to screen
if ( !pip->m_pSystem->IsDedicated() ) {
char buf[101] ;
char finalbuf[201] ;
strncpy( buf,te,sizeof(buf)-1 );
buf[sizeof(buf)-1] = 0;
for (int i = 0; i < strlen(buf); i++)
{
if (buf[i] == '\\')
buf[i] = '/';
if (buf[i] == '"')
buf[i] = '\'';
}
_snprintf ( finalbuf , sizeof(finalbuf)-1 , "#if (Hud) then Hud:AddMessage( \"%s\" ); end" , buf ) ;
pip->m_pSystem->GetIConsole()->ExecuteString( finalbuf,true,true );
}
}
}
if ( !hold ) break ; //if end of line, then break out of loop
*cp = hold ;
te = cp + 1 ;
}
}
//
// PBsendPktToServer
//
void PBsendPktToServer ( int datalen , char *data )
{
if ( pbsdk == NULL ) return ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return ;
CStream stm;
stm.SetBits( (BYTE *) data , 0 , datalen * 8 );
stm.SetSize( datalen * 8 ) ;
pip->SendMsgToServer ( stm ) ;
}
//
// Sys_PBSendUdpPacket
//
void Sys_PBSendUdpPacket ( char *addr , unsigned short port , int datalen , char *data , int isFromClient )
{
if ( pbsdk == NULL ) return ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return ;
CStream stm;
stm.SetBits( (BYTE *) data , 0 , datalen * 8 );
stm.SetSize( datalen * 8 ) ;
CIPAddress cip ( port , addr ) ;
if ( isFromClient ) { //from client
if ( pip->m_pClient != NULL ) pip->m_pClient->SendTo ( cip , stm ) ;//no need to check for local due to PB's internal handling
} else { //from server
if ( pip->m_pServer != NULL ) pip->m_pServer->Send ( stm , cip ) ;
}
}
//
// PBsendPktToClient
//
void PBsendPktToClient ( int datalen , char *data , char *addr )
{
if ( pbsdk == NULL ) return ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return ;
CStream stm;
stm.SetBits( (BYTE *) data , 0 , datalen * 8 );
stm.SetSize( datalen * 8 ) ;
char ip[32] ;
unsigned short port = 0 ;
strncpy ( ip , addr , 31 ) ;
ip[31] = 0 ;
char *cp = strstr ( ip , ":" ) ;
if ( cp != NULL ) {
*cp = 0 ;
port = atoi ( cp + 1 ) ;
}
CIPAddress cip ( port , ip ) ;
pip->SendMsgToClient ( cip , stm ) ;
}
//
// PBisLocalServer
//
int PBisLocalServer ( void )
{
if ( pbsdk == NULL ) return 1 ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return 1 ;
if ( pip->m_pClient == NULL ) return 1 ;
CIPAddress ca = pip->m_pClient->GetServerIP() ;
return ca.IsLocalHost() ;
}
//
// PBgetHomePath
//
void PBgetHomePath ( char *path , int maxlen )
{
*path = 0 ;
if ( pbsdk == NULL ) return ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return ;
strncpy ( path , pip->fs_homepath->GetString() , maxlen - 1 ) ;
path[maxlen-1] = 0 ;
}
//
// PBgetClientInfo
//
int PBgetClientInfo ( stPb_Sv_Client *c )
{
if ( pbsdk == NULL ) return 0 ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return 0 ;
if ( pip->m_pServer == NULL ) return 0 ;
char ip[32] ;
unsigned short port = 0 ;
strncpy ( ip , c->ip , 31 ) ;
ip[31] = 0 ;
char *cp = strstr ( ip , ":" ) ;
if ( cp != NULL ) {
*cp = 0 ;
port = atoi ( cp + 1 ) ;
}
CIPAddress clientIP ( port , ip ) ;
IServerSecuritySink::SSlotInfo playerInfo;
memset ( &playerInfo , 0 , sizeof ( playerInfo ) ) ;
pip->m_pServer->GetSecuritySink()->GetSlotInfo( clientIP.GetAsUINT(),playerInfo , 1 );
if ( *playerInfo.playerName == 0 ) return 0 ; //player not set up yet
strncpy ( c->name , playerInfo.playerName , PB_NAMELEN ) ;
c->name[PB_NAMELEN] = 0 ;
if ( *c->guid == 0 ) { //if the guid is empty, compute it from the hash
char idhash[PB_GUIDLEN+1] = "" ;
CServerSlot *pSlot = pip->m_pServer->GetPacketOwner( clientIP );
if (pSlot) {
PBcomputeHash ( idhash , pSlot ) ;
strcpy ( c->guid , idhash ) ;
}
}
return 1 ;
}
//
// PBgetStats
//
int PBgetStats ( int index , char *Data )
{
if ( pbsdk == NULL ) return 0 ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return 0 ;
if ( pip->m_pServer == NULL ) return 0 ;
char ip[32] ;
unsigned short port = 0 ;
strncpy ( ip , pbsdk->pbsv.m_client[index].pbc.ip , 31 ) ;
ip[31] = 0 ;
char *cp = strstr ( ip , ":" ) ;
if ( cp != NULL ) {
*cp = 0 ;
port = atoi ( cp + 1 ) ;
}
CIPAddress clientIP ( port , ip ) ;
IServerSecuritySink::SSlotInfo playerInfo;
memset ( &playerInfo , 0 , sizeof ( playerInfo ) ) ;
pip->m_pServer->GetSecuritySink()->GetSlotInfo( clientIP.GetAsUINT(),playerInfo , 0 ) ;
if ( *playerInfo.playerName == 0 ) return 0 ;//player not set up yet
sprintf ( Data , "score=%d deaths=%d" , playerInfo.score , playerInfo.deaths ) ;
return 1 ;
}
//
// PBcomputeHash
//
void PBcomputeHash ( char *guid , CServerSlot *pSlot )
{
MD5_CTX mc ;
if (pSlot->m_pbGlobalID)
{
MD5Init ( &mc ) ;
MD5Update ( &mc , pSlot->m_pbGlobalID , pSlot->m_uiGlobalIDSize );
MD5Final ( &mc ) ;
}
else
{
memset(mc.digest,0,sizeof(mc.digest));
}
_snprintf ( guid , PB_GUIDLEN , "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ,
mc.digest[0] , mc.digest[1] , mc.digest[2] , mc.digest[3] , mc.digest[4] , mc.digest[5] , mc.digest[6] ,
mc.digest[7] , mc.digest[8] , mc.digest[9] , mc.digest[10] , mc.digest[11] , mc.digest[12] , mc.digest[13] ,
mc.digest[14] , mc.digest[15] ) ;
}
//
// PBcvar_VariableString
//
char *PBcvar_VariableString ( const char *var_name )
{
if ( pbsdk == NULL ) return "ERROR: NULL POINTER" ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return "ERROR: NULL POINTER" ;
if ( pip->m_pSystem == NULL ) return "ERROR: NULL POINTER" ;
ICVar *cv = pip->m_pSystem->GetIConsole()->GetCVar(var_name);
if ( cv == NULL ) return "" ;
return cv->GetString() ;
}
//
// PBcvar_Set
//
void PBcvar_Set ( const char *cvar , const char *value )
{
if ( pbsdk == NULL ) return ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return ;
if ( pip->m_pSystem == NULL ) return ;
ICVar *cv = pip->m_pSystem->GetIConsole()->GetCVar(cvar);
if ( cv == NULL ) return ;
cv->ForceSet ( value ) ;
}
//
// PBcmd_execString
//
void PBcmd_execString ( const char *text )
{
if ( pbsdk == NULL ) return ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return ;
if ( pip->m_pSystem == NULL ) return ;
pip->m_pSystem->GetIConsole()->ExecuteString( text,false,false);
}
//
// PBdropClient
//
void PBdropClient ( int clientIndex , char *reason )
{
if ( pbsdk == NULL ) return ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return ;
if ( pip->m_pServer == NULL ) return ;
char ip[32] ;
unsigned short port = 0 ;
strncpy ( ip , pbsdk->pbsv.m_client[clientIndex].pbc.ip , 31 ) ;
ip[31] = 0 ;
char *cp = strstr ( ip , ":" ) ;
if ( cp != NULL ) {
*cp = 0 ;
port = atoi ( cp + 1 ) ;
}
CIPAddress clientIP ( port , ip ) ;
CServerSlot *pSlot = pip->m_pServer->GetPacketOwner( clientIP );
if (pSlot) pSlot->Disconnect ( reason ) ;
}
//
// PBgameVer
//
char *PBgameVer ( void )
{
if ( pbsdk == NULL ) return "" ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return "" ;
//must return pointer to full game version info string
static char buf[64] = "" ;
pip->m_pSystem->GetFileVersion().ToString ( buf ) ;
return buf ;
}
//
// isPBmultiplayerMode
//
int isPBmultiplayerMode ( void )
{
if ( pbsdk == NULL ) return 0 ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return 0 ;
if ( pip->m_pNetwork == NULL ) return 0 ;
if ( pip->m_pServer == NULL && pip->m_pClient == NULL && pip->m_pClientLocal == NULL ) return 0 ;
return 1 ;
}
//
// PBserverIp
//
char *PBserverIp ( int bServer )
{
if ( pbsdk == NULL ) return "bot" ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return "bot" ;
static CIPAddress cip ;
if ( !bServer ) {
if ( pip->m_pClient == NULL ) {
if ( pip->m_pClientLocal == NULL ) return "bot" ;
return "localhost" ;
}
cip = pip->m_pClient->GetServerIP() ;
} else {
if ( pip->m_pServer == NULL || pip->m_pNetwork == NULL ) return "???" ;
cip.m_Address.ADDR = pip->m_pNetwork->GetLocalIP();
cip.m_Address.sin_port = htons ( pip->m_pServer->GetServerPort() ) ;
}
return cip.GetAsString ( true ) ;
}
//
// PBserverHostname
//
char *PBserverHostname ( void )
{
if ( pbsdk == NULL ) return "" ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return "" ;
if ( pip->m_pServer == NULL ) return "" ;
CIPAddress cip ;
return (char *) pip->m_pServer->GetHostName() ;
}
//
// PBkeyValue
//
const char *PBkeyValue ( char *notused , char *key )
{
notused;
if ( pbsdk == NULL ) return "" ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return "" ;
if ( pip->m_pSystem == NULL ) return "" ;
const char *newkey = key ;
ICVar *cv ;
if ( !stricmp ( key , "gamename" ) ) {
#ifdef GAME_IS_FARCRY
newkey = GetIXGame( pip->m_pSystem->GetIGame() )->IsMODLoaded() ;
#else
newkey = NULL;
#endif
if ( newkey == NULL ) return "FarCry" ;
else return newkey ;
} else if ( !stricmp ( key , "mapname" ) ) {
newkey = "g_levelName" ;
}/* else if ( !stricmp ( s , "sv_hostname" ) ) {
}*/
cv = pip->m_pSystem->GetIConsole()->GetCVar( newkey ) ;
if ( cv == NULL ) return "" ;
return cv->GetString() ;
}
//
// PBqueryGL
//
char *PBqueryGL ( int type )
{
if ( pbsdk == NULL ) return "" ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return "" ;
// pip->m_pSystem->GetIRenderer()->GetColorBpp() ;
switch ( type ) {
case PB_GL_READPIXELS: //(char *) qglReadPixels ;//function pointer
return (char *) pip->m_pSystem->GetIRenderer()->EF_Query(EFQ_glReadPixels);
case PB_GL_WIDTH:
return (char *) pip->m_pSystem->GetIRenderer()->GetWidth() ;
case PB_GL_HEIGHT:
return (char *) pip->m_pSystem->GetIRenderer()->GetHeight() ;
case PB_GL_RGB: return NULL ;//(char *) GL_RGB ;
case PB_GL_UB: return NULL ;//(char *) GL_UNSIGNED_BYTE ;
case PB_GL_D3DDEV:
return (char *) pip->m_pSystem->GetIRenderer()->EF_Query(EFQ_D3DDevice);
}
return NULL ;
}
class CCVarsDump : public ICVarDumpSink
{
public:
CCVarsDump()
{
m_vars.resize(0);
}
void OnElementFound(ICVar *pCVar)
{
m_vars.push_back(pCVar);
}
ICVar** GetVars() { return &m_vars[0]; }
int NumVars() { return m_vars.size(); }
private:
static std::vector<ICVar*> m_vars;
};
std::vector<ICVar*> CCVarsDump::m_vars;
//
// PBcvarWalk
//
//this is a callback function called from the PB dlls
int PBcvarWalk ( char **name , char **string , int *flags , char **resetString )
{
if ( pbsdk == NULL ) return 0 ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return 0 ;
static int i = 0 , n = 0 ;
static ICVar **pVars = NULL ;
if ( i == 0 || pVars == NULL ) {
CCVarsDump dump;
pip->m_pSystem->GetIConsole()->DumpCVars( &dump );
pVars = dump.GetVars();
if ( pVars == NULL ) return 0 ;
i = 0 ;
n = dump.NumVars() ;
}
if ( i >= n || pVars == NULL ) {//end of enumeration
i = 0 ;
n = 0 ;
pVars = NULL ;
return 0 ;
}
*name = (char *) pVars[i]->GetName() ;
*string = (char *) pVars[i]->GetString() ;
*flags = pVars[i]->GetFlags() ;
*resetString = "" ;
++i ;
return 1;//keep going
}
class CKeyBindsDump : public IKeyBindDumpSink
{
public:
CKeyBindsDump()
{
m_keys.resize(0);
}
void OnKeyBindFound( const char *sBind,const char *sCommand )
{
m_keys.push_back(sBind);
}
const char** GetKeys() { return &m_keys[0]; }
int NumKeys() { return m_keys.size(); }
private:
static std::vector<const char*> m_keys;
};
std::vector<const char*> CKeyBindsDump::m_keys;
//
// PBbindStuff
//
int PBbindStuff ( int type , const char **data )
{
if ( pbsdk == NULL ) return 0 ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return 0 ;
static int i = 0 , n = 0 ;
static const char **pKeys = NULL ;
if ( type == 1 || n == 0 ) {
n = 0 ;
if ( i == 0 || pKeys == NULL ) {
CKeyBindsDump dump;
pip->m_pSystem->GetIConsole()->DumpKeyBinds( &dump );
pKeys = dump.GetKeys();
if ( pKeys == NULL ) return 0 ;
i = 0 ;
n = dump.NumKeys() ;
}
}
if ( type == 1 ) {//return # of keys
return n ;
} else if ( type == 2 ) {//return keyname in *data
int key = atoi ( *data ) ;
*data = "" ;
if ( pKeys == NULL ) return 0 ;
if ( key < n ) *data = pKeys[key] ;
} else {//return data for key bind name
int key = atoi ( *data ) ;
*data = "" ;
if ( pKeys == NULL ) return 0 ;
*data = pip->m_pSystem->GetIConsole()->FindKeyBind(pKeys[key]);
}
return 0 ;
}
//
// PBpakNames
//
void PBpakNames ( char *buf )//assumes buf is 1025+ in size (bytes)
{
strcpy ( buf , "*ERROR*" ) ;
if ( pbsdk == NULL ) return ;
CPunkBusterInterface *pip = (CPunkBusterInterface *) pbsdk->pbinterface ;
if ( pip == NULL ) return ;
if ( pip->m_pSystem == NULL ) return ;
*buf = 0 ;
ICryPak::PakInfo* pPakInfo = pip->m_pSystem->GetIPak()->GetPakInfo(); //get loaded pak names
int i ;
char priorRoot[513] = "" ;
for ( i = 0 ; i < pPakInfo->numOpenPaks ; i++ ) {
int slb = strlen ( buf ) ;
if ( stricmp ( priorRoot , pPakInfo->arrPaks[i].szBindRoot ) ) { //new bind root ?
strncpy ( priorRoot , pPakInfo->arrPaks[i].szBindRoot , 512 ) ; //yes add to list with a * prefix
priorRoot[512] = 0 ;
if ( strlen ( priorRoot ) + slb < 1020 ) _snprintf ( buf + slb , 1025 - slb , "*\"%s\" " , priorRoot ) ;
slb = strlen ( buf ) ;
}
const char *cp = pPakInfo->arrPaks[i].szFilePath ;
if ( strlen ( cp ) > strlen ( priorRoot ) ) cp += strlen ( priorRoot ) ;//this should always happen
if ( strlen ( cp ) + slb > 1020 ) continue ; //skip it, too many already
_snprintf ( buf + slb , 1025 - slb , "\"%s\" " , cp ) ; //append pak file name from point of prior bind root
}
}
#endif // NOT_USE_PUNKBUSTER_SDK

View File

@@ -0,0 +1,105 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2001-2004.
// -------------------------------------------------------------------------
// File name: PunkBusterInterface.h
// Version: v1.00
// Created: 1/3/2004 by Timur.
// Compilers: Visual Studio.NET 2003
// Description: Interface to the PunkBuster from CryEngine.
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#if !defined(NOT_USE_PUNKBUSTER_SDK)
#ifndef __PunkBusterInterface_h__
#define __PunkBusterInterface_h__
#pragma once
#include "IConsole.h"
#include "../PunkBuster/pbcommon.h"
class CNetwork;
class CServer;
class CClient;
class CClientLocal;
class CServerSlot;
/*! Wrapper arround PunkBuster.
*/
class CPunkBusterInterface : public IConsoleVarSink, public IOutputPrintSink
{
public:
CPunkBusterInterface( CNetwork *pNetwork );
~CPunkBusterInterface();
//! Called when initializing client and server.
void Init( bool bClient , bool isLocalServer );
//! Called when shut downing client and server.
void ShutDown( bool bClient );
// This is server.
void SetServer( CServer *pServer );
// This is client.
void SetClient( CClient *pClient );
void SetClientLocal( CClientLocal *pClient );
//! Locks the punkbuster cvars
void LockCVars();
//! Unlocks the punkbuster cvars
void UnlockCVars();
//! Updates PunkBuster, called every frame.
void Update( bool bClient );
//! Called when message from server or client recieved.
void OnCCPPunkBusterMsg( CIPAddress &ipAddress,CStream &stm );
//! When new client joins server.
void OnAddClient( CIPAddress &clientIP );
//! When client disconnect server.
void OnDisconnectClient( CIPAddress &clientIP );
bool CheckPBPacket(CStream &stmPacket,CIPAddress &ip);
void ValidateClient( CServerSlot *pSlot );
//////////////////////////////////////////////////////////////////////////
// IConsoleVarSink
//////////////////////////////////////////////////////////////////////////
virtual bool OnBeforeVarChange( ICVar *pVar,const char *sNewValue );
//////////////////////////////////////////////////////////////////////////
// IOutputPrintSink
//////////////////////////////////////////////////////////////////////////
virtual void Print( const char *inszText );
//////////////////////////////////////////////////////////////////////////
//private:
bool ReadStringFromRegistry(const string &szKeyName, const string &szValueName, string &szValue);
bool LoadCDKey( string &sCDKey );
void CheaterFound( CIPAddress &clientIP,int type,const char *sMsg );
void SendMsgToClient( CIPAddress &clientIP,CStream &stm );
void SendMsgToServer( CStream &stm );
//private:
ISystem *m_pSystem;
CNetwork *m_pNetwork;
CServer* m_pServer;
CClient* m_pClient;
CClientLocal* m_pClientLocal;
bool m_bClInitialized , m_bSvInitialized , m_bSinglePlayer ;
ICVar *cl_punkbuster;
ICVar *sv_punkbuster;
ICVar *fs_homepath;
ICVar *sys_punkbuster_loaded;
};
#endif // __PunkBusterInterface_h__
#endif // NOT_USE_PUNKBUSTER_SDK

327
CryNetwork/RConSystem.cpp Normal file
View File

@@ -0,0 +1,327 @@
#include "stdafx.h"
#include "rconsystem.h" // CRConSystem
#include "Network.h" // CNetwork
#include "CNP.h" // CQPRConCommand
#include "IConsole.h" // IConsole
//#if !defined(LINUX)
#include "IDataProbe.h" // IConsole
//#endif
// *****************************************************************
// *****************************************************************
class CRConConsoleSink :public IOutputPrintSink
{
public:
// constructor
CRConConsoleSink( CRConSystem &inRef, const CIPAddress &ip ) :m_Ref(inRef), m_ip(ip)
{
}
// interface IOutputPrintSink ------------------------------------
virtual void Print( const char *inszText )
{
CStream stmPacket;
CQPRConResponse RConResponse;
RConResponse.m_sText=inszText;
RConResponse.Save(stmPacket);
NRESULT hRes=m_Ref.m_sSocket.Send(stmPacket.GetPtr(), BITS2BYTES(stmPacket.GetSize()), &m_ip);
if(hRes==SOCKET_ERROR)
{
INetwork *pNetwork=m_Ref.m_pSystem->GetINetwork(); assert(pNetwork);
const char *szErrorRes=pNetwork->EnumerateError(hRes);
CryLogAlways("$4RConError: %s",szErrorRes);
}
}
CRConSystem & m_Ref; //!<
CIPAddress m_ip; //!<
};
// *****************************************************************
// *****************************************************************
CRConSystem::CRConSystem()
{
m_pSystem=0;
m_pIServer=0;
GetPassCode( "CNPNetworkKeyNode",m_nDevPassCode );
}
CRConSystem::~CRConSystem()
{
}
bool CRConSystem::Create( ISystem *pSystem )
{
assert(pSystem);
m_pSystem = pSystem;
if(NET_FAILED(m_sSocket.Create()))
return false;
return true;
}
void CRConSystem::Update( unsigned int dwTime,IClient *pClient )
{
static CStream stmBuffer;
static CIPAddress ipFrom;
int iReceived = 0;
if (pClient)
{
m_ipServer = pClient->GetServerIP();
}
do
{
stmBuffer.Reset();
m_sSocket.Receive(stmBuffer.GetPtr(), stmBuffer.GetAllocatedSize(), iReceived, ipFrom);
if(iReceived > 0)
{
stmBuffer.SetSize(BYTES2BITS(iReceived));
CNP cnpPacket;
cnpPacket.LoadAndSeekToZero(stmBuffer);
if(cnpPacket.m_cFrameType == FT_CQP_RCON_RESPONSE) // from Server back to Client
{
CQPRConResponse cqpRConResponse;
cqpRConResponse.Load(stmBuffer);
CryLogAlways("$5RCon Response: %s",cqpRConResponse.m_sText.c_str());
}
else
{
assert(0); // there should be no ther packets on this port
return;
}
}
} while(iReceived > 0);
while(!m_DeferredConsoleCommands.empty())
{
SDeferredCommand &defCmd( m_DeferredConsoleCommands.front() );
CRConConsoleSink sink( *this, defCmd.m_ip );
IConsole *pConsole( m_pSystem->GetIConsole() );
assert( pConsole );
pConsole->AddOutputPrintSink( &sink);
pConsole->ExecuteString( defCmd.m_sCommand.c_str() );
pConsole->RemoveOutputPrintSink( &sink );
m_DeferredConsoleCommands.pop_front();
}
}
void CRConSystem::OnServerCreated( IServer *inpServer )
{
assert(inpServer);
inpServer->RegisterPacketSink(FT_CQP_RCON_COMMAND,this);
m_pIServer = inpServer;
}
//////////////////////////////////////////////////////////////////////////
void CRConSystem::GetPassCode( const char *szString,unsigned int *nOutCode )
{
//#if !defined(LINUX)
#ifdef _DATAPROBE
char md5[16];
GetISystem()->GetIDataProbe()->GetMD5( szString,strlen(szString),md5 );
memcpy( nOutCode,md5,16 ); // 16 byte.
#endif
//#endif
/*
#define POLY64REV 0xd800000000000000ULL
string sPass = szString;
// Duplicate pass 10 times.
for (int i = 0; i < 10; i++)
{
sPass += szString;
}
int len = sPass.size();
const unsigned char *buf = (const unsigned char*)sPass.c_str();
// calc CRC_64
static uint64 Table[256];
uint64 code = 0;
static int init = 0;
if (!init) {
int i;
init = 1;
for (i = 0; i <= 255; i++) {
int j;
uint64 part = i;
for (j = 0; j < 8; j++) {
if (part & 1)
part = (part >> 1) ^ POLY64REV;
else
part >>= 1;
}
Table[i] = part;
}
}
unsigned int key1[4] = { 123765122,1276327,13482722,29871129};
while (len--)
{
uint64 temp1 = code >> 8;
uint64 temp2 = Table[(code ^ (uint64)*buf) & 0xff];
code = temp1 ^ temp2;
buf += 1;
}
unsigned int key2[4] = { 53215122,278627227,1762561245,817671221};
// 8 bytes.
TEA_ENCODE( (unsigned int*)&code,nOutCode,8,key1 );
code = (~code);
TEA_ENCODE( (unsigned int*)&code,(nOutCode+2),8,key2 );
*/
}
void CRConSystem::OnReceivingPacket( const unsigned char inPacketID, CStream &stmPacket, CIPAddress &ip )
{
IConsole *pConsole=m_pSystem->GetIConsole(); assert(pConsole);
ICVar *pVar = pConsole->GetCVar("sv_rcon_password"); assert(pVar);
string sv_RConPassword = pVar->GetString();
if(sv_RConPassword=="")
return; // RCon is not activated
CQPRConCommand pccp;
pccp.Load(stmPacket);
// Get code for server password, must match code recieved from client.
unsigned int nServerPassCode[4];
GetPassCode( sv_RConPassword.c_str(),nServerPassCode );
if (memcmp(nServerPassCode,pccp.m_nRConPasswordCode,sizeof(nServerPassCode)) != 0
&& memcmp(m_nDevPassCode,pccp.m_nRConPasswordCode,sizeof(nServerPassCode)) != 0)
{
unsigned int dwIP = ip.GetAsUINT();
std::map<unsigned int, int>::iterator it = m_hmRconAttempts.find(dwIP);
if (it == m_hmRconAttempts.end())
{
int iTry = 1;
m_hmRconAttempts.insert(std::pair<unsigned int, int>(dwIP, iTry));
}
else
{
CryLogAlways( "$4%s used a bad rcon password!.", ip.GetAsString(0) );
int iTry = ++it->second;
// if 3 attempts failed, remove from the hash map and ban it!
if (iTry >= 3)
{
m_hmRconAttempts.erase(it);
m_pIServer->BanIP(dwIP);
CryLogAlways("$4Banned %s after 3 attempts with a bad rcon password.", ip.GetAsString(0));
}
}
// pLog->Log("DEBUG: Password does not match");
return; // rcon password does not match
}
else
{
// reset the number of tries if password successful
std::map<unsigned int, int>::iterator it = m_hmRconAttempts.find(ip.GetAsUINT());
if (it != m_hmRconAttempts.end())
{
m_hmRconAttempts.erase(it);
}
}
char tempCmd[512];
strncpy(tempCmd,pccp.m_sRConCommand.c_str(),sizeof(tempCmd)-1);
tempCmd[sizeof(tempCmd)-1] = 0;
char *szIP = ip.GetAsString();
CryLogAlways("$5Incoming RCon(%s): %s",szIP,tempCmd);
m_DeferredConsoleCommands.push_back(SDeferredCommand(tempCmd,ip));
/*
{
CRConConsoleSink sink(*this,ip);
pConsole->AddOutputPrintSink(&sink);
pConsole->ExecuteString(tempCmd);
pConsole->RemoveOutputPrintSink(&sink);
}
*/
}
void CRConSystem::ExecuteRConCommand( const char *inszCommand )
{
// get parameters
IConsole *pConsole=m_pSystem->GetIConsole(); assert(pConsole);
ICVar *pVar1 = pConsole->GetCVar("cl_rcon_serverip"); assert(pVar1);
string serverip = pVar1->GetString();
ICVar *pVar2 = pConsole->GetCVar("cl_rcon_port"); assert(pVar2);
WORD wPort = pVar2->GetIVal();
ICVar *pVar3 = pConsole->GetCVar("cl_rcon_password"); assert(pVar3);
string sPasswd = pVar3->GetString();
// send packet
CQPRConCommand cqpRConCommand;
CStream stmPacket;
CIPAddress ip(wPort,serverip.c_str());
// If server ip not specified use, current server.
if (serverip.empty())
{
ip.Set( m_ipServer );
}
unsigned int nClientCode[4];
GetPassCode( sPasswd.c_str(),nClientCode );
memcpy( cqpRConCommand.m_nRConPasswordCode,nClientCode,sizeof(nClientCode) );
char tempCmd[256];
strncpy(tempCmd,inszCommand,sizeof(tempCmd)-1);
tempCmd[sizeof(tempCmd)-1] = 0;
cqpRConCommand.m_sRConCommand = tempCmd;
cqpRConCommand.Save(stmPacket);
m_sSocket.Send(stmPacket.GetPtr(),BITS2BYTES(stmPacket.GetSize()),&ip);
// prinout
CryLogAlways("$5RCon (%s:%d)'%s'",serverip.c_str(),(int)wPort,tempCmd );
}

58
CryNetwork/RConSystem.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef RCONSYSTEM_H
#define RCONSYSTEM_H
#include "INetwork.h" // IRConSystem
#include <list>
class CRConSystem :public IRConSystem, public INetworkPacketSink
{
public:
//! constructor
CRConSystem();
//! destructor
virtual ~CRConSystem();
// interface INetworkPacketSink ------------------------------------------
virtual void OnReceivingPacket( const unsigned char inPacketID, CStream &stmPacket, CIPAddress &ip );
// interface IRConSystem -------------------------------------------------
virtual void Release(){ delete this; }
virtual void Update( unsigned int dwTime,IClient *pClient=NULL );
virtual void ExecuteRConCommand( const char *inszCommand );
virtual void OnServerCreated( IServer *inpServer );
// -----------------------------------------------------------------------
//!
bool Create( ISystem *pSystem );
private: // -----------------------------------------------------------------------
struct SDeferredCommand
{
//! constructor
SDeferredCommand( const string &sCmd, const CIPAddress &ip ) :m_sCommand(sCmd), m_ip(ip)
{
}
string m_sCommand; //!<
CIPAddress m_ip; //!<
};
ISystem * m_pSystem; //!< pointer to the system interface (is zero when not initialized)
IServer * m_pIServer; //!<
CDatagramSocket m_sSocket; //!<
std::map<unsigned int, int> m_hmRconAttempts; //! hash map that maps ip -> rcon attempts, for security.
std::list<SDeferredCommand> m_DeferredConsoleCommands; //!< to execute commands at a defined point in the update loop
unsigned int m_nDevPassCode[4];
CIPAddress m_ipServer;
//! Get 128bit code from string. (4 ints)
void GetPassCode( const char *szString,unsigned int *nOutCode );
friend class CRConConsoleSink;
};
#endif // RCONSYSTEM_H

View File

@@ -0,0 +1,431 @@
// ScriptObjectNewUbisoftClient.cpp: implementation of the CScriptObjectNewUbisoftClient class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#ifndef NOT_USE_UBICOM_SDK
#include "ScriptObjectNewUbisoftClient.h"
#include "NewUbisoftClient.h"
#include <ITimer.h> // ITimer
#include "IConsole.h" // IConsole
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
_DECLARE_SCRIPTABLEEX(CScriptObjectNewUbisoftClient)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CScriptObjectNewUbisoftClient::CScriptObjectNewUbisoftClient()
{
m_pUbiSoftClient=0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CScriptObjectNewUbisoftClient::~CScriptObjectNewUbisoftClient()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CScriptObjectNewUbisoftClient::ReleaseTemplate()
{
/* SAFE_RELEASE(m_pLobbyInfo);
SAFE_RELEASE(m_pRoomInfo);
SAFE_RELEASE(m_pMemberInfo);
SAFE_RELEASE(m_pFriendInfo);
SAFE_RELEASE(m_pConnectInfo);
*/
_ScriptableEx<CScriptObjectNewUbisoftClient>::ReleaseTemplate();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CScriptObjectNewUbisoftClient::InitializeTemplate(IScriptSystem *pSS)
{
_ScriptableEx<CScriptObjectNewUbisoftClient>::InitializeTemplate(pSS);
//REG_FUNC(CScriptObjectNewUbisoftClient,Client_GetStoredUsername);
//REG_FUNC(CScriptObjectNewUbisoftClient,Client_GetStoredPassword);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_AutoLogin);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_Login);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_RequestGameServers);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_JoinGameServer);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_ConnectedToGameServer);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_LeaveGameServer);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_Disconnect);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_IsConnected);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_SetCDKey);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_CreateAccount);
REG_FUNC(CScriptObjectNewUbisoftClient,Client_RequestMOTD);
#define REGISTER_CONSTANT(c) pSS->SetGlobalValue("UBI_"#c, c)
// REGISTER_CONSTANT(DISCONNECTED);
#undef REGISTER_CONSTANT
}
void CScriptObjectNewUbisoftClient::Init( IScriptSystem *pScriptSystem, ISystem *pSystem, NewUbisoftClient *inUbiSoftClient )
{
m_pSystem=pSystem;
m_pConsole=pSystem->GetIConsole();
m_pScriptSystem = pScriptSystem;
m_pUbiSoftClient=inUbiSoftClient;
InitGlobal(pScriptSystem,"NewUbisoftClient",this);
inUbiSoftClient->SetScriptObject(this);
inUbiSoftClient->Init(m_pSystem);
}
DWORD CScriptObjectNewUbisoftClient::GetAbsTimeInSeconds()
{
DWORD dwRet=(DWORD)(m_pSystem->GetITimer()->GetCurrTime());
return dwRet;
}
//REG_FUNC(CScriptObjectNewUbisoftClient,Client_GetStoredUsername);
//REG_FUNC(CScriptObjectNewUbisoftClient,Client_GetStoredPassword);
//REG_FUNC(CScriptObjectNewUbisoftClient,Client_AutoLogin);
/*
int CScriptObjectNewUbisoftClient::Client_GetStoredUsername(IFunctionHandler *pH)
{
CHECK_PARAMETERS(0);
string szHexUsername;
m_pUbiSoftClient->ReadStringFromRegistry("Ubi.com", "username", szHexUsername);
char szEncUsername[256] = {0};
char szUsername[256] = {0};
m_pUbiSoftClient->DecodeHex((unsigned char *)szEncUsername, (unsigned char *)szHexUsername.c_str());
m_pUbiSoftClient->DecryptString((unsigned char *)szUsername, (unsigned char *)szEncUsername);
return pH->EndFunction(szUsername);
}
int CScriptObjectNewUbisoftClient::Client_GetStoredPassword(IFunctionHandler *pH)
{
CHECK_PARAMETERS(0);
string szHexPassword;
m_pUbiSoftClient->ReadStringFromRegistry("Ubi.com", "password", szHexPassword);
char szEncPassword[256] = {0};
char szPassword[256] = {0};
m_pUbiSoftClient->DecodeHex((unsigned char *)szEncPassword, (unsigned char *)szHexPassword.c_str());
m_pUbiSoftClient->DecryptString((unsigned char *)szPassword, (unsigned char *)szEncPassword);
return pH->EndFunction(szPassword);
}
*/
int CScriptObjectNewUbisoftClient::Client_AutoLogin(IFunctionHandler *pH)
{
CHECK_PARAMETERS(0);
return pH->EndFunction(m_pUbiSoftClient->Client_AutoLogin());
}
/*! Login the Game Client to the Game Service
*/
int CScriptObjectNewUbisoftClient::Client_Login(IFunctionHandler *pH)
{
CHECK_PARAMETERS(3);
const char *szUsername;
const char *szPassword;
bool bSavePassword = false;
pH->GetParam(1,szUsername);
pH->GetParam(2,szPassword);
pH->GetParam(3,bSavePassword);
return pH->EndFunction(m_pUbiSoftClient->Client_Login(szUsername,szPassword, bSavePassword));
}
/*! Request the list of game servers
*/
int CScriptObjectNewUbisoftClient::Client_RequestGameServers(IFunctionHandler *pH)
{
CHECK_PARAMETERS(0);
return pH->EndFunction(m_pUbiSoftClient->Client_RequestGameServers());
}
/*! Tell the Game Service that you are going to join a game server
*/
int CScriptObjectNewUbisoftClient::Client_JoinGameServer(IFunctionHandler *pH)
{
CHECK_PARAMETERS(2);
int iLobbyID,iRoomID;
pH->GetParam(1,iLobbyID);
pH->GetParam(2,iRoomID);
return pH->EndFunction(m_pUbiSoftClient->Client_JoinGameServer(iLobbyID,iRoomID));
}
/*! Tell the Game Service that you have connected to a game server
*/
int CScriptObjectNewUbisoftClient::Client_ConnectedToGameServer(IFunctionHandler *pH)
{
CHECK_PARAMETERS(0);
return pH->EndFunction(m_pUbiSoftClient->Client_ConnectedToGameServer());
}
/*! Tell the Game Service that you have left the game server. No parameters
*/
int CScriptObjectNewUbisoftClient::Client_LeaveGameServer(IFunctionHandler *pH)
{
CHECK_PARAMETERS(0);
return pH->EndFunction(m_pUbiSoftClient->Client_LeaveGameServer());
}
/*! Disconnect from Game Service. No parameters
*/
int CScriptObjectNewUbisoftClient::Client_Disconnect(IFunctionHandler *pH)
{
CHECK_PARAMETERS(0);
return pH->EndFunction(m_pUbiSoftClient->Client_Disconnect());
}
/*! Create an account. szUsername (string), szPassword (string)
*/
int CScriptObjectNewUbisoftClient::Client_CreateAccount(IFunctionHandler *pH)
{
CHECK_PARAMETERS(2);
const char *szUsername;
const char *szPassword;
pH->GetParam(1,szUsername);
pH->GetParam(2,szPassword);
return pH->EndFunction(m_pUbiSoftClient->Client_CreateAccount(szUsername,szPassword));
}
int CScriptObjectNewUbisoftClient::Client_IsConnected(IFunctionHandler *pH)
{
CHECK_PARAMETERS(0);
if (m_pUbiSoftClient->Client_IsConnected())
{
m_pSystem->GetILog()->Log("Client connected");
return pH->EndFunction(1);
}
else
{
m_pSystem->GetILog()->Log("Client NOT connected");
return pH->EndFunctionNull();
}
}
int CScriptObjectNewUbisoftClient::Client_SetCDKey(IFunctionHandler *pH)
{
CHECK_PARAMETERS(1);
const char *szCDKey;
pH->GetParam(1,szCDKey);
if (m_pUbiSoftClient->Client_SetCDKey(szCDKey))
{
return pH->EndFunction(1);
}
else
{
return pH->EndFunctionNull();
}
}
int CScriptObjectNewUbisoftClient::Client_RequestMOTD(IFunctionHandler *pH)
{
if (m_pUbiSoftClient->Client_RequestMOTD("EN"))
{
return pH->EndFunction(1);
}
else
{
return pH->EndFunctionNull();
}
}
int CScriptObjectNewUbisoftClient::Server_DestroyServer(IFunctionHandler *pH)
{
CHECK_PARAMETERS(0);
return pH->EndFunction(m_pUbiSoftClient->Server_DestroyServer());
}
/////////////////////////////////////////////////////////////////////////////
//
//
//
/////////////////////////////////////////////////////////////////////////////
void CScriptObjectNewUbisoftClient::Client_LoginSuccess(const char *szUsername)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Client_LoginSuccess");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szUsername);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Client_LoginFail(const char *szError)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Client_LoginFail");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szError);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Client_GameServer(int iLobbyID, int iRoomID, const char *szGameServer,
const char *szIPAddress, const char *szLANIPAddress, int iMaxPlayers,
int iNumPlayers)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Client_GameServer");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(iLobbyID);
m_pScriptSystem->PushFuncParam(iRoomID);
m_pScriptSystem->PushFuncParam(szGameServer);
m_pScriptSystem->PushFuncParam(szIPAddress);
m_pScriptSystem->PushFuncParam(szLANIPAddress);
m_pScriptSystem->PushFuncParam(iMaxPlayers);
m_pScriptSystem->PushFuncParam(iNumPlayers);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Client_RequestFinished()
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Client_RequestFinished");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Client_JoinGameServerSuccess(const char *szIPAddress, const char *szLanIPAddress,
unsigned short usPort)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Client_JoinGameServerSuccess");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szIPAddress);
m_pScriptSystem->PushFuncParam(szLanIPAddress);
m_pScriptSystem->PushFuncParam(usPort);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Client_JoinGameServerFail(const char *szError)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Client_JoinGameServerFail");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szError);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Client_CreateAccountSuccess()
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Client_CreateAccountSuccess");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Client_CreateAccountFail(const char *szText)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Client_CreateAccountFail");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szText);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Client_MOTD(const char *szUbiMOTD, const char *szGameMOTD)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Client_MOTD");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szUbiMOTD);
m_pScriptSystem->PushFuncParam(szGameMOTD);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Server_RegisterServerSuccess(int iLobbyID, int iRoomID)
{
CStream stm;
stm.Write(iLobbyID);
stm.Write(iRoomID);
m_pScriptSystem->BeginCall("NewUbisoftClient","Server_RegisterServerSuccess");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(iLobbyID);
m_pScriptSystem->PushFuncParam(iRoomID);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Server_RegisterServerFail()
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Server_RegisterServerFail");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Server_LobbyServerDisconnected()
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Server_LobbyServerDisconnected");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Server_PlayerJoin(const char *szUsername)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Server_PlayerJoin");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szUsername);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::Server_PlayerLeave(const char *szUsername)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","Server_PlayerLeave");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szUsername);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::CDKey_Failed(const char *szText)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","CDKey_Failed");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szText);
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::CDKey_GetCDKey()
{
m_pScriptSystem->BeginCall("NewUbisoftClient","CDKey_GetCDKey");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::CDKey_ActivationSuccess()
{
m_pScriptSystem->BeginCall("NewUbisoftClient","CDKey_ActivationSuccess");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->EndCall();
}
void CScriptObjectNewUbisoftClient::CDKey_ActivationFail(const char *szText)
{
m_pScriptSystem->BeginCall("NewUbisoftClient","CDKey_ActivationFail");
m_pScriptSystem->PushFuncParam(GetScriptObject());
m_pScriptSystem->PushFuncParam(szText);
m_pScriptSystem->EndCall();
}
#endif // NOT_USE_UBICOM_SDK

View File

@@ -0,0 +1,124 @@
// ScriptObjectInput.h: interface for the CScriptObjectNewUbisoftClient class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(__SCRIPT_OBJECT_NEW_UBISOFT_CLIENT__INCLUDED_)
#define __SCRIPT_OBJECT_NEW_UBISOFT_CLIENT__INCLUDED_
#ifndef NOT_USE_UBICOM_SDK
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <IScriptSystem.h>
#include <_ScriptableEx.h>
class NewUbisoftClient;
/*! This class implements ubisoft.com script functions.
REMARKS:
After initialization of the script-object it will be globally accessable through scripts using the namespace "UbisoftClient".
IMPLEMENTATIONS NOTES:
These function will never be called from C-Code. They're script-exclusive.
*/
class CScriptObjectNewUbisoftClient : public _ScriptableEx<CScriptObjectNewUbisoftClient>
{
public:
//! constructor
CScriptObjectNewUbisoftClient();
//! destructor
virtual ~CScriptObjectNewUbisoftClient();
//!
//! /param pScriptSystem Pointer to the ScriptSystem-interface
//! /param pSystem Pointer to the System-interface
void Init( IScriptSystem *pScriptSystem, ISystem *pSystem, NewUbisoftClient *inUbiSoftClient );
//!
static void InitializeTemplate(IScriptSystem *pSS);
//!
static void ReleaseTemplate();
int Client_GetStoredUsername(IFunctionHandler *pH);
int Client_GetStoredPassword(IFunctionHandler *pH);
// auto log in using info stored in registry
int Client_AutoLogin(IFunctionHandler *pH);
// Logs in using szUsername (string) and szPassword (string)
int Client_Login(IFunctionHandler *pH);
// Request list of Game Servers. No parameters
int Client_RequestGameServers(IFunctionHandler *pH);
// Join a Game Server. iLobbyID (int), iRoomID (int)
int Client_JoinGameServer(IFunctionHandler *pH);
// Tell the Game Service you have connected to the game server. No parameters
int Client_ConnectedToGameServer(IFunctionHandler *pH);
// Tell the Game Service that you have left the game server. No parameters
int Client_LeaveGameServer(IFunctionHandler *pH);
// Disconnect from Game Service. No parameters
int Client_Disconnect(IFunctionHandler *pH);
// Create an account. szUsername (string), szPassword (string)
int Client_CreateAccount(IFunctionHandler *pH);
// Check if the client is logged in
int Client_IsConnected(IFunctionHandler *pH);
//Set the cdkey
int Client_SetCDKey(IFunctionHandler *pH);
//Request the Message of the Day
int Client_RequestMOTD(IFunctionHandler *pH);
// Remove the server from Game Service. No Parameters
int Server_DestroyServer(IFunctionHandler *pH);
//! used by the NewUbisoftClient
DWORD GetAbsTimeInSeconds();
// Script Callbacks -------------------------------------------
void Client_LoginSuccess(const char *szUsername);
void Client_LoginFail(const char *szText);
void Client_GameServer(int iLobbyID, int iRoomID, const char *szGameServer,
const char *szIPAddress, const char *szLANIPAddress, int iMaxPlayers, int iNumPlayers);
void Client_RequestFinished();
void Client_JoinGameServerSuccess(const char *szIPAddress, const char *szLanIPAddress,
unsigned short usPort);
void Client_JoinGameServerFail(const char *szText);
void Client_CreateAccountSuccess();
void Client_CreateAccountFail(const char *szText);
void Client_MOTD(const char *szUbiMOTD, const char *szGameMOTD);
void Server_RegisterServerSuccess(int iLobbyID, int iRoomID);
void Server_RegisterServerFail();
void Server_LobbyServerDisconnected();
void Server_PlayerJoin(const char *szUsername);
void Server_PlayerLeave(const char *szUsername);
void CDKey_Failed(const char *szText);
void CDKey_GetCDKey();
void CDKey_ActivationSuccess();
void CDKey_ActivationFail(const char *szText);
private: // --------------------------------------------------------------
ISystem * m_pSystem; //!
IConsole * m_pConsole; //!
IScriptSystem * m_pScriptSystem; //!
NewUbisoftClient * m_pUbiSoftClient; //! (a different class is responsible for destruction)
};
#endif // NOT_USE_UBICOM_SDK
#endif //__SCRIPT_OBJECT_NEW_UBISOFT_CLIENT__INCLUDED_

978
CryNetwork/Server.cpp Normal file
View File

@@ -0,0 +1,978 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: Server.cpp
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Network.h"
#include "CNP.h"
#include "Server.h"
#include "ServerSlot.h"
#include "ILog.h"
#include "IConsole.h"
#include "NewUbisoftClient.h" // NewUbisoftClient
#include <IScriptSystem.h>
#if defined(_DEBUG) && !defined(LINUX)
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
#if !defined(WIN64) && !defined(LINUX64) && !defined(NOT_USE_ASE_SDK)
#pragma comment(lib, "ASEQuerySDK.lib")
static CServer *g_pServer = 0;
extern "C"{
#include "ASEQuerySDK.h"
//-------------------------------------------------------------------------------------------------
void ASEQuery_wantstatus()
{
if (!g_pServer || !g_pServer->GetServerSlotFactory())
{
ASEQuery_status("", "", "", "", 1, 0, 0);
return;
}
string szName, szGameType, szMap, szVersion;
bool bPassword = false;
int nPlayers = 0;
int nMaxPlayers = 0;
g_pServer->GetServerSlotFactory()->GetServerInfoStatus(szName, szGameType, szMap, szVersion, &bPassword, &nPlayers, &nMaxPlayers);
ASEQuery_status(szName.c_str(), szGameType.c_str(), szMap.c_str(), szVersion.c_str(), bPassword, nPlayers, nMaxPlayers);
}
//-------------------------------------------------------------------------------------------------
void ASEQuery_wantrules()
{
IScriptSystem *pSS = GetISystem()->GetIScriptSystem();
_SmartScriptObject QueryHandler(pSS, 1);
if (!pSS->GetGlobalValue("QueryHandler", (IScriptObject *)QueryHandler))
{
return;
}
_SmartScriptObject ServerRules(pSS, 1);
pSS->BeginCall("QueryHandler", "GetServerRules");
pSS->PushFuncParam((IScriptObject *)QueryHandler);
pSS->EndCall((IScriptObject *)ServerRules);
for (int i = 1; i <= ServerRules->Count(); i++)
{
_SmartScriptObject Rule(pSS, 1);
if (ServerRules->GetAt(i, (IScriptObject *)Rule))
{
char *szRuleName = 0;
char *szRuleValue = 0;
Rule->GetAt(1, szRuleName);
Rule->GetAt(2, szRuleValue);
if (szRuleValue && szRuleName)
{
ASEQuery_addrule(szRuleName, szRuleValue);
}
}
}
}
//-------------------------------------------------------------------------------------------------
void ASEQuery_wantplayers()
{
IScriptSystem *pSS = GetISystem()->GetIScriptSystem();
_SmartScriptObject QueryHandler(pSS, 1);
if (!pSS->GetGlobalValue("QueryHandler", (IScriptObject *)QueryHandler))
{
return;
}
_SmartScriptObject PlayerStats(pSS, 1);
pSS->BeginCall("QueryHandler", "GetPlayerStats");
pSS->PushFuncParam((IScriptObject *)QueryHandler);
pSS->EndCall((IScriptObject *)PlayerStats);
for (int i = 1; i <= PlayerStats->Count(); i++)
{
_SmartScriptObject Player(pSS, 1);
if (PlayerStats->GetAt(i, (IScriptObject *)Player))
{
char *szName = 0;
char *szTeam = 0;
char *szSkin = 0;
char *szScore = 0;
char *szPing = 0;
char *szTime = 0;
Player->GetValue("Name", (const char* &)szName);
Player->GetValue("Team", (const char* &)szTeam);
Player->GetValue("Skin", (const char* &)szSkin);
Player->GetValue("Score", (const char* &)szScore);
Player->GetValue("Ping", (const char* &)szPing);
Player->GetValue("Time", (const char* &)szTime);
ASEQuery_addplayer(szName, szTeam, szSkin, szScore, szPing, szTime);
}
}
}
} // extern "C"
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CServer::CServer(CNetwork *pNetwork)
{
m_cLastClientID = 0;
m_pFactory = NULL;
m_ServerVariables.nDataStreamTimeout = 30000;// 30 seconds
m_pNetwork=pNetwork;
m_wPort=0;
m_bMulticastSocket=true;
m_pSecuritySink=0;
m_MPServerType=eMPST_LAN;
}
CServer::~CServer()
{
//-------------------------------------------------------------------------------------------------
// ASE Deinitialization
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
#if !defined(WIN64) && !defined(LINUX64) && !defined(NOT_USE_ASE_SDK)
ASEQuery_shutdown();
#endif
//-------------------------------------------------------------------------------------------------
#ifndef NOT_USE_UBICOM_SDK
// If it is a UBI type server we should unregister
m_pNetwork->m_pUbiSoftClient->Server_DestroyServer();
#endif // NOT_USE_UBICOM_SDK
m_pNetwork->UnregisterServer(m_wPort);
}
EMPServerType CServer::GetServerType() const
{
return m_MPServerType;
}
//////////////////////////////////////////////////////////////////////
// IServer
//////////////////////////////////////////////////////////////////////
bool CServer::Init(IServerSlotFactory *pFactory, WORD wPort, bool listen)
{
CIPAddress ipMulticast(SERVER_MULTICAST_PORT, SERVER_MULTICAST_ADDRESS);
m_pFactory = pFactory;
if(m_bListen = listen)
{
CIPAddress ipLocal;
ipLocal.m_Address.ADDR = m_pNetwork->GetLocalIP();
// only create the multicast socket if it's not internet server
ICVar *sv_ServerType = GetISystem()->GetIConsole()->GetCVar("sv_ServerType"); assert(sv_ServerType);
m_MPServerType=eMPST_LAN;
if(stricmp(sv_ServerType->GetString(),"UBI")==0)
m_MPServerType=eMPST_UBI;
else if(stricmp(sv_ServerType->GetString(),"NET")==0)
m_MPServerType=eMPST_NET;
// if this is a lan server
//if (m_MPServerType==eMPST_LAN)
{
if (NET_SUCCEDED(m_socketMulticast.Create()))
{
if (NET_SUCCEDED(m_socketMulticast.Listen(SERVER_MULTICAST_PORT, &ipMulticast, &ipLocal)))
{
m_bMulticastSocket=true;
}
}
}
/* else
{
m_bMulticastSocket=false;
}
*/
if (NET_FAILED(m_socketMain.Create()))
return false;
if (NET_FAILED(m_socketMain.Listen(wPort, 0, &ipLocal)))
return false;
//-------------------------------------------------------------------------------------------------
// ASE Initialization
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
DWORD dwLocalIP = GetISystem()->GetINetwork()->GetLocalIP();
char *szIP = 0;
CIPAddress ip;
if (dwLocalIP)
{
ip.m_Address.ADDR = dwLocalIP;
szIP = ip.GetAsString();
}
#if !defined(WIN64) && !defined(LINUX64) && !defined(NOT_USE_ASE_SDK)
ASEQuery_initialize((int)wPort, m_MPServerType!=eMPST_LAN ? 1 : 0, szIP);
#endif
//-------------------------------------------------------------------------------------------------
};
m_wPort=wPort;
return true;
}
#ifdef _INTERNET_SIMULATOR
#include <stdlib.h>
#if !defined(LINUX)
#include <assert.h>
#endif
#include "ITimer.h"
#endif
void CServer::Update(unsigned int nTime)
{
//-------------------------------------------------------------------------------------------------
// ASE Update
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
#if !defined(WIN64) && !defined(LINUX64) && !defined(NOT_USE_ASE_SDK)
g_pServer = this;
ASEQuery_check();
#endif
//-------------------------------------------------------------------------------------------------
#ifdef _INTERNET_SIMULATOR
static ICVar *pVarPacketloss=GetISystem()->GetIConsole()->GetCVar("g_internet_simulator_packetloss");
TDelayPacketList2::iterator i;
for (i = m_delayedPacketList.begin(); i != m_delayedPacketList.end();)
{
DelayedPacket2 *dp = (*i);
if (dp->m_fTimeToSend <= GetISystem()->GetITimer()->GetCurrTime())
{
i = m_delayedPacketList.erase(i);
// Send it
if ((rand() %100) > pVarPacketloss->GetFVal())
m_socketMain.Send(dp->data,dp->len,dp->address);
// Delete it
delete dp->address;
delete dp;
}
else
++i;
}
#endif
m_nCurrentTime = nTime;
int nRecvBytes;
// do{
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
static CIPAddress ipFrom;
static CStream buf;
/////////////////////////////////////////////////////////
if(m_bListen)
do
{
buf.Reset();
nRecvBytes = 0;
m_socketMain.Receive(buf.GetPtr(),
(int)BITS2BYTES(buf.GetAllocatedSize()),
nRecvBytes,
ipFrom);
///////////////////////////////////////////////////////
if (nRecvBytes>0)
{
buf.SetSize(BYTES2BITS(nRecvBytes));
ProcessPacket(buf, ipFrom);
}
}while (nRecvBytes>0);
/////////////////////////////////////////////////////////
// handle multicast packets
/////////////////////////////////////////////////////////
if(m_bMulticastSocket && m_bListen && m_MPServerType==eMPST_LAN)
{
do
{
buf.Reset();
nRecvBytes = 0;
m_socketMulticast.Receive(buf.GetPtr(),
(int)BITS2BYTES(buf.GetAllocatedSize()),
nRecvBytes,
ipFrom);
///////////////////////////////////////////////////////
if (nRecvBytes>0)
{
buf.SetSize(BYTES2BITS(nRecvBytes));
ProcessMulticastPacket(buf, ipFrom);
}
}while (nRecvBytes>0);
}
/////////////////////////////////////////////////////////
// Update slots State machine
SLOTS_MAPItr itr = m_mapSlots.begin();
while (itr != m_mapSlots.end())
{
CServerSlot *pSlot = itr->second;
if (pSlot->IsActive())
{
pSlot->Update(m_nCurrentTime, NULL, NULL);
}
++itr;
}
m_pNetwork->OnServerUpdate();
}
void CServer::GetBandwidth( float &fIncomingKbPerSec, float &fOutgoinKbPerSec, DWORD &nIncomingPackets, DWORD &nOutgoingPackets )
{
fIncomingKbPerSec = m_socketMain.m_fIncomingKbPerSec;
fOutgoinKbPerSec = m_socketMain.m_fOutgoingKbPerSec;
nIncomingPackets=m_socketMain.m_nIncomingPacketsPerSec;
nOutgoingPackets=m_socketMain.m_nOutgoingPacketsPerSec;
}
void CServer::SetVariable(enum CryNetworkVarible eVarName, unsigned int nValue)
{
switch (eVarName)
{
case cnvDataStreamTimeout:
m_ServerVariables.nDataStreamTimeout = nValue;
break;
default:
NET_ASSERT(0);
break;
}
}
void CServer::GetProtocolVariables(CNPServerVariables &sv)
{
sv = m_ServerVariables;
}
void CServer::Release()
{
delete this;
}
//////////////////////////////////////////////////////////////////////
// _IServerServices
//////////////////////////////////////////////////////////////////////
bool CServer::Send(CStream &stm, CIPAddress &ip)
{
#ifndef _INTERNET_SIMULATOR
DWORD nSize = BITS2BYTES(stm.GetSize());
if(NET_SUCCEDED(m_socketMain.Send(stm.GetPtr(), nSize, &ip)))
return true;
return false;
#else
static ICVar *pVarPacketloss=GetISystem()->GetIConsole()->GetCVar("g_internet_simulator_packetloss");
static ICVar *pVarMinPing=GetISystem()->GetIConsole()->GetCVar("g_internet_simulator_minping");
static ICVar *pVarMaxPing=GetISystem()->GetIConsole()->GetCVar("g_internet_simulator_maxping");
int iMaxPing=pVarMaxPing->GetIVal();
int iMinPing=pVarMinPing->GetIVal();
if(iMinPing>iMaxPing)
iMaxPing=iMinPing;
if (pVarPacketloss->GetFVal()>0 || iMaxPing>0)
{
DelayedPacket2 *delayed = new DelayedPacket2;
int iRand=0;
if(iMaxPing>iMinPing)
iRand=rand() % (iMaxPing-iMinPing);
if(iMaxPing>0)
delayed->m_fTimeToSend = GetISystem()->GetITimer()->GetCurrTime() + (iMinPing + iRand) / 1000.0f;
else
delayed->m_fTimeToSend = GetISystem()->GetITimer()->GetCurrTime();
delayed->len = BITS2BYTES(stm.GetSize());
delayed->address = new CIPAddress(ip);
assert(delayed->len < sizeof(delayed->data)/sizeof(delayed->data[0]));
memcpy(delayed->data, stm.GetPtr(), delayed->len);
m_delayedPacketList.push_back(delayed);
return true;
}
else
{
DWORD nSize = BITS2BYTES(stm.GetSize());
if(NET_SUCCEDED(m_socketMain.Send(stm.GetPtr(), nSize, &ip)))
return true;
return false;
}
#endif
}
void CServer::OnDestructSlot( const CServerSlot *inpServerSlot )
{
SLOTS_MAPItr itr = m_mapSlots.begin();
while (itr != m_mapSlots.end())
{
CServerSlot *pSlot = itr->second;
if(pSlot==inpServerSlot)
{
m_mapSlots.erase(itr);
return;
}
++itr;
}
assert(0); // can't be
}
void CServer::UnregisterSlot(CIPAddress &ip)
{
SLOTS_MAPItr itor=m_mapSlots.find(ip);
if(itor!=m_mapSlots.end())
{
IServerSlot *pServerSlot=itor->second;
pServerSlot->Advise(NULL); // remove connection to IServerSlotSink (CXServerSlot)
}
}
void CServer::RegisterLocalServerSlot(CServerSlot *pSlot,CIPAddress &ip)
{
m_mapSlots.insert(SLOTS_MAPItr::value_type(ip,pSlot));
if(m_pFactory)
m_pFactory->CreateServerSlot(pSlot);
}
CServerSlot *CServer::GetPacketOwner(CIPAddress &ip)
{
SLOTS_MAPItr itor;
itor=m_mapSlots.find(ip);
if(itor==m_mapSlots.end())
return 0;
return itor->second;
}
//////////////////////////////////////////////////////////////////////
// core
//////////////////////////////////////////////////////////////////////
void TraceUnrecognizedPacket( const char *inszTxt, CStream &stmPacket, CIPAddress &ip)
{
#ifdef _DEBUG
OutputDebugString("\n");
OutputDebugString(inszTxt);
OutputDebugString("\n");
static char sTemp[1024];
static BYTE cBuf[1024];
DWORD nCount;
::OutputDebugString("-------------------------------\n");
sprintf(sTemp,"INVALID PACKET FROM [%s]\n",ip.GetAsString(true));
::OutputDebugString(sTemp);
stmPacket.GetBuffer(cBuf,1024);
nCount=BYTES2BITS(stmPacket.GetSize());
for(DWORD n=0;n<nCount;n++)
{
sprintf(sTemp,"%02X ",cBuf[n]);
::OutputDebugString(sTemp);
if(n && (n%16)==0)
::OutputDebugString("\n");
}
#endif
}
void CServer::ProcessPacket(CStream &stmPacket, CIPAddress &ip)
{
if (!m_pNetwork->CheckPBPacket( stmPacket,ip ))
return;
CNP cnp;
cnp.LoadAndSeekToZero(stmPacket);
switch (cnp.m_cFrameType)
{
// these packets will not be checked for ban
// since they are sent just too often,
// and would slow down the server
// they will be reject anyway, because no banned ip can have a server slot associated with it
case FT_CCP_DISCONNECT:
case FT_CCP_ACK:
case FT_CTP_DATA:
case FT_CTP_ACK:
case FT_CTP_NAK:
case FT_CTP_PONG:
DispatchToServerSlots(cnp, stmPacket,ip);
break;
default:
{
if (m_pSecuritySink->IsIPBanned(ip.GetAsUINT()))
{
return;
}
// these packets' ip will be checked for ban
// since they are not sent very often
switch(cnp.m_cFrameType)
{
case FT_CCP_CONNECT:
case FT_CCP_CONNECT_RESP:
case FT_CCP_CONTEXT_READY:
case FT_CCP_SECURITY_QUERY:
case FT_CCP_SECURITY_RESP:
case FT_CCP_PUNK_BUSTER_MSG:
DispatchToServerSlots(cnp, stmPacket,ip);
break;
case FT_CCP_SETUP:
ProcessSetup(cnp, stmPacket, ip);
break;
case FT_CQP_INFO_REQUEST:
ProcessInfoRequest(stmPacket, ip);
break;
case FT_CQP_XML_REQUEST:
ProcessInfoXMLRequest(stmPacket,ip);
break;
default:
{
TPacketSinks::iterator it = m_PacketSinks.find(cnp.m_cFrameType);
if(it!=m_PacketSinks.end())
{
INetworkPacketSink *pSink = (*it).second;
pSink->OnReceivingPacket(cnp.m_cFrameType,stmPacket,ip);
break;
}
}
TraceUnrecognizedPacket("ProcessPacket",stmPacket,ip);
break;
}
}
};
}
void CServer::RegisterPacketSink( const unsigned char inID, INetworkPacketSink *inpSink )
{
assert(m_PacketSinks.count(inID)==0);
m_PacketSinks[inID] = inpSink;
}
void CServer::SetSecuritySink(IServerSecuritySink *pSecuritySink)
{
m_pSecuritySink = pSecuritySink;
}
//////////////////////////////////////////////////////////////////////////
IServerSecuritySink* CServer::GetSecuritySink()
{
return m_pSecuritySink;
}
bool CServer::IsIPBanned(const unsigned int dwIP)
{
if (m_pSecuritySink)
{
return m_pSecuritySink->IsIPBanned(dwIP);
}
return false;
}
void CServer::BanIP(const unsigned int dwIP)
{
if (m_pSecuritySink)
{
m_pSecuritySink->BanIP(dwIP);
}
}
void CServer::UnbanIP(const unsigned int dwIP)
{
if (m_pSecuritySink)
{
m_pSecuritySink->UnbanIP(dwIP);
}
}
void CServer::ProcessMulticastPacket(CStream &stmPacket, CIPAddress &ip)
{
CNP cnp;
cnp.LoadAndSeekToZero(stmPacket);
switch (cnp.m_cFrameType)
{
case FT_CQP_INFO_REQUEST:
ProcessInfoRequest(stmPacket, ip);
break;
case FT_CQP_XML_REQUEST:
ProcessInfoXMLRequest(stmPacket,ip);
break;
default:
TraceUnrecognizedPacket("ProcessMulticastPacket",stmPacket,ip);
break;
};
}
void CServer::ProcessSetup(CNP &cnp, CStream &stmStream, CIPAddress &ip)
{
CServerSlot *pSSlot;
CServerSlot *pTemp=GetPacketOwner(ip);
if(pTemp!=NULL)
{
NET_TRACE("Setup discarded for IP [%s]\n",pTemp->GetIP().GetAsString(true));
return;
}
if (m_pSecuritySink)
{
if (m_pSecuritySink->IsIPBanned(ip.GetAsUINT()))
{
NET_TRACE("Setup discarded for IP [%s] (BANNED)\n",ip.GetAsString(true));
return;
}
}
NET_TRACE("Setup accepted for IP [%s]\n",ip.GetAsString(true));
pSSlot = new CServerSlotImpl(m_pNetwork,this);
/////////////////////////////////////////////////////////!!!!
int nID = GenerateNewClientID();
/////////////////////////////////////////////////////////!!!!
pSSlot->Start((BYTE)nID, ip);
// build event
if (m_pFactory)
{
if (m_pFactory->CreateServerSlot(pSSlot) == true)
{
m_mapSlots.insert(SLOTS_MAPItr::value_type(ip, pSSlot));
//m_mapIPs.insert(IPS_MAPItr::value_type(ip,nID));
// if this is a lan server
if(m_MPServerType==eMPST_LAN)
{
if (!IsLANIP(ip))
{
pSSlot->Disconnect("@LanIPOnly");
}
}
// get server password cvar
ICVar *sv_password = GetISystem()->GetIConsole()->GetCVar("sv_password");
assert(sv_password);
// check if server is password protected
if (sv_password->GetString() && (strlen(sv_password->GetString()) > 0))
{
CCPSetup pccp;
pccp.Load(stmStream);
if (!pccp.m_sPlayerPassword.size() || (strcmp(sv_password->GetString(), pccp.m_sPlayerPassword.c_str()) != 0))
{
pSSlot->Disconnect("@InvalidServerPassword");
return;
}
}
pSSlot->Update(m_nCurrentTime, &cnp, &stmStream);
}
else
{
//<<FIXME>> ?!?!?!?
//pSSlot->Update(m_nCurrentTime, &cnp, &stmStream);
pSSlot->Disconnect("@ConnectionRejected");
//pSSlot->Update(m_nCurrentTime, NULL, NULL);
}
}
}
bool CServer::IsLANIP(const CIPAddress &ip)
{
unsigned char ipb[4];
#if defined(LINUX)
ipb[0] = ip.m_Address.sin_addr_win.S_un.S_un_b.s_b1;
ipb[1] = ip.m_Address.sin_addr_win.S_un.S_un_b.s_b2;
ipb[2] = ip.m_Address.sin_addr_win.S_un.S_un_b.s_b3;
ipb[3] = ip.m_Address.sin_addr_win.S_un.S_un_b.s_b4;
#else
ipb[0] = ip.m_Address.sin_addr.S_un.S_un_b.s_b1;
ipb[1] = ip.m_Address.sin_addr.S_un.S_un_b.s_b2;
ipb[2] = ip.m_Address.sin_addr.S_un.S_un_b.s_b3;
ipb[3] = ip.m_Address.sin_addr.S_un.S_un_b.s_b4;
#endif
if (ipb[0] == 127)
return true;
if (ipb[0] == 10)
return true;
if ((ipb[0] == 192) && (ipb[1] == 168))
return true;
if (ipb[0] == 172)
if ((ipb[1] >= 16) && (ipb[1] <= 31))
return true;
return false;
}
void CServer::DispatchToServerSlots(CNP &cnp, CStream &stm, CIPAddress &ip)
{
SLOTS_MAPItr itr;
itr = m_mapSlots.find(ip);
if (itr != m_mapSlots.end())
{
(itr->second)->Update(m_nCurrentTime, &cnp, &stm); // update the server slot
}
else
{
NET_TRACE("CServer::DispatchToServerSlots() Unknown client ID\n");
}
}
void CServer::ProcessInfoRequest(CStream &stmIn, CIPAddress &ip)
{
if (stmIn.GetSize() < 32)
{
return; // must be at least 16bytes(64bits) int
}
CQPInfoRequest Query;
CQPInfoResponse Response;
CStream stmPacket;
Query.Load(stmIn); // load and seek to zero
stmIn.Seek(0);
if (!Query.IsOk())
{
return;
}
assert((stmIn.GetSize() % 8) == 0);
assert(m_pFactory);
if (Query.szRequest == "ping")
{
Response.szResponse = "X";// identify the packet
Response.Save(stmPacket);
assert((stmPacket.GetSize() % 8) == 0);
if (stmPacket.GetSize())
{
m_socketMain.Send(stmPacket.GetPtr(), BITS2BYTES(stmPacket.GetSize()), &ip);
}
}
// status
else if (Query.szRequest == "status")
{
#if defined(WIN64) && !defined(NDEBUG)
//workarround for bug caused by string reallocation across dll's and not shared crt libs in debug mode
Response.szResponse.resize(0);
Response.szResponse.reserve(100);
Response.szResponse += "S"; // identify the packet
#else
Response.szResponse = "S"; // identify the packet
#endif
if (!m_pFactory->GetServerInfoStatus(Response.szResponse))
{
return;
}
Response.Save(stmPacket);
assert((stmPacket.GetSize() % 8) == 0);
if (stmPacket.GetSize())
{
m_socketMain.Send(stmPacket.GetPtr(), BITS2BYTES(stmPacket.GetSize()), &ip);
}
}
// rules
else if (Query.szRequest == "rules")
{
Response.szResponse = "R"; // identify the packet
if (!m_pFactory->GetServerInfoRules(Response.szResponse))
{
return;
}
Response.Save(stmPacket);
assert((stmPacket.GetSize() % 8) == 0);
m_socketMain.Send(stmPacket.GetPtr(), BITS2BYTES(stmPacket.GetSize()), &ip);
}
// players
else if (Query.szRequest == "players")
{
string szString[SERVER_QUERY_MAX_PACKETS];
string *vszString[SERVER_QUERY_MAX_PACKETS];
int nStrings = 0;
for (int i = 0; i < SERVER_QUERY_MAX_PACKETS; i++)
{
vszString[i] = &szString[i];
szString[i] = "P";
}
if (!m_pFactory->GetServerInfoPlayers(vszString, nStrings))
{
return;
}
for (int j = 0; j < nStrings; j++)
{
Response.szResponse = *vszString[j];
Response.Save(stmPacket);
assert((stmPacket.GetSize() % 8) == 0);
m_socketMain.Send(stmPacket.GetPtr(), BITS2BYTES(stmPacket.GetSize()), &ip);
stmPacket.Reset();
}
}
}
//////////////////////////////////////////////////////////////////////////
void CServer::ProcessInfoXMLRequest(CStream &stmIn,CIPAddress &ip)
{
CQPXMLRequest cqpRequest;
CQPXMLResponse cqpResponse;
cqpRequest.Load(stmIn);
char sResponse[MAX_REQUEST_XML_LENGTH+1];
strcpy(sResponse,"");
// ask the application to process this XML request.
if (m_pFactory)
{
if(!m_pFactory->ProcessXMLInfoRequest( cqpRequest.m_sXML.c_str(),sResponse,sizeof(sResponse)))
return;
}
CStream stmOut;
cqpResponse.m_sXML = sResponse;
cqpResponse.Save(stmOut);
m_socketMain.Send(stmOut.GetPtr(), BITS2BYTES(stmOut.GetSize()), &ip);
}
//////////////////////////////////////////////////////////////////////////
IServerSlot *CServer::GetServerSlotbyID( const unsigned char ucId ) const
{
for(SLOTS_MAP::const_iterator it=m_mapSlots.begin();it!=m_mapSlots.end();++it)
{
if(it->second->GetID()==ucId)
return it->second;
}
return 0; // not found
}
//////////////////////////////////////////////////////////////////////////
unsigned char CServer::GenerateNewClientID()
{
for(unsigned char id=1;id<0xFF;id++) // find a free client id
{
bool bFree=true;
for(SLOTS_MAPItr it=m_mapSlots.begin();it!=m_mapSlots.end();++it)
{
if(it->second->GetID()==id)
{
bFree=false; // this one is occupied
break;
}
}
if(bFree)
return id; // found one
}
assert(0); // 256 players are already connected ?
return 0;
}
uint8 CServer::GetMaxClientID() const
{
uint8 ucMax=0;
// save solution (slow, but speed is not a concern here)
for(SLOTS_MAP::const_iterator it=m_mapSlots.begin();it!=m_mapSlots.end();++it)
{
uint8 ucId=it->second->GetID();
if(ucId>ucMax)
ucMax=ucId;
}
return ucMax;
}
const char *CServer::GetHostName()
{
return m_socketMain.GetHostName();
}
void CServer::GetMemoryStatistics(ICrySizer *pSizer)
{
pSizer->AddObject(this,sizeof(CServer));
SLOTS_MAPItr itor=m_mapSlots.begin();
while(itor!=m_mapSlots.end())
{
itor->second->GetMemoryStatistics(pSizer);
}
}

151
CryNetwork/Server.h Normal file
View File

@@ -0,0 +1,151 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: Server.h
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#ifndef _SERVER_H_
#define _SERVER_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Interfaces.h"
#include <map>
#include <queue>
#include <list>
class CServerSlot;
class CNetwork;
#if !defined(LINUX)
#pragma warning(disable:4786)
#endif
typedef std::map<CIPAddress,CServerSlot* > SLOTS_MAP;
typedef std::map<CIPAddress,CServerSlot* >::iterator SLOTS_MAPItr;
//#define _INTERNET_SIMULATOR
class CNetwork;
class ICrySizer;
class CServer :
public IServer,
public _IServerServices
{
public:
//! constructor
CServer(CNetwork *pNetwork);
//! destructor
virtual ~CServer();
// interface IServer ------------------------------------------------------------------
virtual void GetBandwidth( float &fIncomingKbPerSec, float &fOutgoingKbPerSec, DWORD &nIncomingPackets, DWORD &nOutgoingPackets );
virtual const char *GetHostName();
virtual void Release();
virtual void SetVariable(enum CryNetworkVarible eVarName,unsigned int nValue);
virtual void Update(unsigned int nTime);
virtual void RegisterPacketSink( const unsigned char inPacketID, INetworkPacketSink *inpSink );
virtual void SetSecuritySink(IServerSecuritySink *pSecuritySink);
virtual IServerSecuritySink* GetSecuritySink();
virtual bool IsIPBanned(const unsigned int dwIP);
virtual void BanIP(const unsigned int dwIP);
virtual void UnbanIP(const unsigned int dwIP);
virtual IServerSlot *GetServerSlotbyID( const unsigned char ucId ) const;
virtual uint8 GetMaxClientID() const;
virtual EMPServerType GetServerType() const;
// interface _IServerServices ----------------------------------------------------------
bool Send(CStream &stm,CIPAddress &ip);
void UnregisterSlot(CIPAddress &ip);
virtual void OnDestructSlot( const CServerSlot *inpServerSlot );
void GetProtocolVariables(CNPServerVariables &sv);
// -------------------------------------------------------------------------------------
//!
bool Init(IServerSlotFactory *pFactory,WORD nPort, bool local);
//! return the associated IServerSlotFactory interface
IServerSlotFactory *GetServerSlotFactory() { return m_pFactory; };
//!
CServerSlot *GetPacketOwner(CIPAddress &ip);
//!
void RegisterLocalServerSlot(CServerSlot *pSlot,CIPAddress &ip);
//!
void GetMemoryStatistics(ICrySizer *pSizer);
//! Returns server port.
int GetServerPort() { return m_wPort; };
//! check if an ip address is lan or inet
bool IsLANIP(const CIPAddress &ip);
private:
//!
void DispatchToServerSlots(CNP &cnp,CStream &stm, CIPAddress &ip);
//!
void ProcessSetup(CNP &cnp,CStream &stmStream,CIPAddress &ip);
//!
void ProcessInfoRequest(CStream &stmIn, CIPAddress &ip);
void ProcessInfoXMLRequest(CStream &stmIn, CIPAddress &ip);
//!
void ProcessPacket(CStream &stmPacket,CIPAddress &ip);
//!
void ProcessMulticastPacket(CStream &stmPacket,CIPAddress &ip);
//!
unsigned char GenerateNewClientID();
typedef std::map<unsigned char,INetworkPacketSink *> TPacketSinks;
unsigned char m_cLastClientID; //!<
CDatagramSocket m_socketMain; //!<
CDatagramSocket m_socketMulticast; //!<
bool m_bMulticastSocket; //!<
protected:
SLOTS_MAP m_mapSlots; //!<
IServerSlotFactory * m_pFactory; //!<
private:
CNPServerVariables m_ServerVariables; //!<
unsigned int m_nCurrentTime; //!<
CNetwork * m_pNetwork; //!<
WORD m_wPort; //!<
bool m_bListen; //!<
IServerSecuritySink *m_pSecuritySink;
TPacketSinks m_PacketSinks; //!< <inPacketID,callback interface>
EMPServerType m_MPServerType; //!< depends on sv_Servertype at Init() time
// -----------------------------------------------------------------------------------
#ifdef _INTERNET_SIMULATOR
struct DelayedPacket2
{
float m_fTimeToSend;
BYTE data[8192];
int len;
CIPAddress *address;
};
typedef std::list<DelayedPacket2*> TDelayPacketList2;
TDelayPacketList2 m_delayedPacketList; //!<
#endif
};
#endif //_SERVER_H_

585
CryNetwork/ServerSlot.cpp Normal file
View File

@@ -0,0 +1,585 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: ServerSlot.cpp
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CNP.h"
#include "ServerSlot.h"
#include "ClientLocal.h"
#include "Server.h"
#include "IGame.h"
#include "IDataProbe.h"
#ifndef NOT_USE_UBICOM_SDK
#include "NewUbisoftClient.h" // NewUbisoftClient
#endif // NOT_USE_UBICOM_SDK
#if defined(_DEBUG) && !defined(LINUX)
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CServerSlotImpl::CServerSlotImpl( CNetwork *pNetwork,_IServerServices *pParent)
:CServerSlot(pNetwork),m_ctpEndpoint(pNetwork),m_ctpEndpoint2(pNetwork)
{
m_ccpEndpoint.Init(this);
m_smCCPMachine.Init(this);
m_pParent = pParent;
m_bActive = false;
m_dwKeepAliveTimer = 0xFFFFFFFF;
m_nCurrentTime = 0; //m_nCurrentTime;
pParent->GetProtocolVariables(m_ServerVariables);
m_bClientAdded = false;
m_nClientFlags = 0;
m_nClientOS_Minor = 0;
m_nClientOS_Major = 0;
//////////////////////////////////////////////////////////////////////////
// Generate random public key for this client.
GetISystem()->GetIDataProbe()->RandSeed(GetTickCount());
m_nPublicKey = GetISystem()->GetIDataProbe()->GetRand();
m_ccpEndpoint.SetPublicCryptKey( m_nPublicKey );
m_ctpEndpoint.SetPublicCryptKey( m_nPublicKey );
m_ctpEndpoint2.SetPublicCryptKey( m_nPublicKey );
//////////////////////////////////////////////////////////////////////////
}
CServerSlotImpl::~CServerSlotImpl()
{
m_pParent->OnDestructSlot(this);
}
bool CServerSlotImpl::IsActive()
{
return m_bActive;
}
void CServerSlotImpl::Disconnect(const char *szCause)
{
m_smCCPMachine.Update(SIG_SRV_ACTIVE_DISCONNECT, (DWORD_PTR)szCause);
SendDisconnect(szCause);
}
bool CServerSlotImpl::ContextSetup(CStream &stm)
{
m_stmContext = stm;
m_smCCPMachine.Update(SIG_SRV_CONTEXT_SETUP);
return true;
}
unsigned int CServerSlotImpl::GetUnreliablePacketsLostCount()
{
return m_ctpEndpoint.GetUnreliableLostPackets();
}
void CServerSlotImpl::SendReliable(CStream &stm,bool bSecondaryChannel)
{
m_BandwidthStats.m_nReliablePacketCount++;
m_BandwidthStats.m_nReliableBitCount+=stm.GetSize();
if(bSecondaryChannel)
m_ctpEndpoint2.SendReliable(stm);
else
m_ctpEndpoint.SendReliable(stm);
}
void CServerSlotImpl::SendUnreliable(CStream &stm)
{
m_BandwidthStats.m_nUnreliablePacketCount++;
m_BandwidthStats.m_nUnreliableBitCount+=stm.GetSize();
m_ctpEndpoint.SendUnreliable(stm);
}
void CServerSlotImpl::Update(unsigned int nTime, CNP *pCNP, CStream *pStream)
{
m_nCurrentTime = nTime;
if (pCNP)
{
// avoid useless packet parsing
if(m_smCCPMachine.GetCurrentStatus() != STATUS_SRV_DISCONNECTED)
{
ProcessPacket(pCNP->m_cFrameType,pCNP->m_bSecondaryTC, pStream);
m_dwKeepAliveTimer = m_nCurrentTime;
}
}
else
{
m_ccpEndpoint.Update(m_nCurrentTime, NULL, NULL);
m_smCCPMachine.Update();
if (/*m_smCCPMachine.GetCurrentStatus() == STATUS_CONNECTED ||*/ m_smCCPMachine.GetCurrentStatus() == STATUS_SRV_READY)
{
static char szCause[] = "@ClientTimeout";
m_ctpEndpoint.Update(m_nCurrentTime, NULL, NULL);
m_ctpEndpoint2.Update(m_nCurrentTime, NULL, NULL);
// after n seconds without any incoming packets the connection will be considered lost
if(m_ServerVariables.nDataStreamTimeout && GetISystem()->GetIGame()->GetModuleState(EGameMultiplayer))
if (m_nCurrentTime - m_dwKeepAliveTimer>m_ServerVariables.nDataStreamTimeout)
Disconnect(szCause);
}
else
{
m_dwKeepAliveTimer = m_nCurrentTime;
}
}
}
bool CServerSlotImpl::IsReady()
{
return (m_smCCPMachine.GetCurrentStatus() == STATUS_SRV_READY)?true:false;
}
unsigned int CServerSlotImpl::GetPing()
{
return m_ctpEndpoint.GetPing();
}
//////////////////////////////////////////////////////////////////////
//_IServerSlotServices
//////////////////////////////////////////////////////////////////////
void CServerSlotImpl::Start(unsigned char cClientID, CIPAddress &ip)
{
m_ipAddress = ip;
m_bActive = true;
m_cClientID = cClientID;
m_ctpEndpoint.Init(this,false);
m_ctpEndpoint2.Init(this,true);
m_ccpEndpoint.Init(this);
// m_smCCPMachine.Update(SIG_SETUP);
}
bool CServerSlotImpl::Send(CStream &stm)
{
m_pParent->Send(stm, m_ipAddress);
return true;
}
bool CServerSlotImpl::SendConnect()
{
CNPServerVariables sv;
m_pParent->GetProtocolVariables(sv);
sv.nPublicKey = m_nPublicKey;
m_ccpEndpoint.SendConnect(sv);
return true;
}
bool CServerSlotImpl::SendContextSetup()
{
// GetISystem()->GetILog()->Log("CServerSlotImpl::SendContextSetup");
m_ccpEndpoint.SendContextSetup(m_stmContext);
// reset the data layer (CTP)
m_ctpEndpoint.Reset();
m_ctpEndpoint2.Reset();
return true;
}
bool CServerSlotImpl::SendServerReady()
{
// GetISystem()->GetILog()->Log("CServerSlotImpl::SendServerReady");
m_ccpEndpoint.SendServerReady();
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CServerSlotImpl::SendSecurityQuery(CStream &stm)
{
m_ccpEndpoint.SendSecurityQuery(stm);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CServerSlotImpl::SendPunkBusterMsg(CStream &stm)
{
m_ccpEndpoint.SendPunkBusterMsg(stm);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CServerSlotImpl::SendDisconnect(const char *szCause)
{
m_ccpEndpoint.SendDisconnect(szCause);
return true;
}
void CServerSlotImpl::OnConnect()
{
NET_ASSERT(m_pSink);
if(m_pSink)
{
#ifndef NOT_USE_UBICOM_SDK
// If its a multiplayer game check the cdkey
if(GetISystem()->GetIGame()->GetModuleState(EGameMultiplayer))
m_pNetwork->m_pUbiSoftClient->Server_CheckPlayerAuthorizationID(GetID(),m_pbAuthorizationID);
else
#endif // NOT_USE_UBICOM_SDK
{
m_pSink->OnXPlayerAuthorization(true,"",NULL,0);
}
m_pSink->OnXServerSlotConnect(m_pbAuthorizationID,m_uiAuthorizationSize);
}
}
void CServerSlotImpl::OnContextReady()
{
// GetISystem()->GetILog()->Log("CServerSlotImpl::OnContextReady");
if (m_pSink)
m_pSink->OnContextReady(m_stmContextReady);
SendServerReady();
// Run Checks for this client.
if (!m_bClientAdded)
m_pNetwork->AddClientToDefenceWall( m_ipAddress );
m_bClientAdded = true;
}
void CServerSlotImpl::OnData(CStream &stm)
{
if (m_pSink)
m_pSink->OnData(stm);
}
void CServerSlotImpl::OnDisconnect(const char *szCause)
{
m_pNetwork->RemoveClientFromDefenceWall( m_ipAddress );
if (m_pSink)
{
if(szCause==NULL)
szCause="Undefined";
#ifndef NOT_USE_UBICOM_SDK
m_pNetwork->m_pUbiSoftClient->Server_RemovePlayer(GetID());
#endif // NOT_USE_UBICOM_SDK
m_pSink->OnXServerSlotDisconnect(szCause);
}
m_pParent->UnregisterSlot(GetIP());
m_bActive = 0;
}
void CServerSlotImpl::Release()
{
assert(this);
delete this;
}
void CServerSlotImpl::OnCCPSetup(CStream &stm)
{
CCPSetup ccpSetup;
ccpSetup.Load(stm);
bool versiomatch = !(ccpSetup.m_cProtocolVersion!=CNP_VERSION);
m_nClientFlags = ccpSetup.m_nClientFlags;
m_nClientOS_Minor = ccpSetup.m_nClientOSMinor;
m_nClientOS_Major = ccpSetup.m_nClientOSMajor;
// Can report here what OS client is running.
// warning this is never called(look at CServerSlotImpl::Start() )
m_smCCPMachine.Update(SIG_SRV_SETUP,versiomatch?1:0);
// kick a player that tries to join the server, with cheats enabled
if ((m_nClientFlags & CLIENT_FLAGS_DEVMODE) && !GetISystem()->WasInDevMode())
{
Disconnect("@Kicked");
}
}
void CServerSlotImpl::OnCCPConnectResp(CStream &stm)
{
unsigned int uiSize = stm.GetSize();
if (uiSize)
{
assert(uiSize%8==0);
m_pbAuthorizationID = new BYTE[uiSize/8];
stm.ReadBits(m_pbAuthorizationID,uiSize);
m_uiAuthorizationSize = uiSize/8;
}
m_smCCPMachine.Update(SIG_SRV_CONNECT_RESP);
m_pNetwork->ValidateClient(this);
}
void CServerSlotImpl::OnCCPContextReady(CStream &stm)
{
m_stmContextReady = stm;
m_smCCPMachine.Update(SIG_SRV_CONTEXT_READY);
}
void CServerSlotImpl::OnCCPDisconnect(const char *szCause)
{
m_smCCPMachine.Update(SIG_SRV_DISCONNECT, (DWORD_PTR)szCause);
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void CServerSlotImpl::ProcessPacket(unsigned char cFrameType,bool bSTC, CStream *pStream)
{
switch (cFrameType)
{
// signaling
case FT_CCP_SETUP:
case FT_CCP_CONNECT_RESP:
case FT_CCP_CONTEXT_READY:
case FT_CCP_DISCONNECT:
case FT_CCP_ACK:
case FT_CCP_SECURITY_QUERY:
case FT_CCP_SECURITY_RESP:
case FT_CCP_PUNK_BUSTER_MSG:
m_ccpEndpoint.Update(m_nCurrentTime, cFrameType, pStream);
break;
// transport
case FT_CTP_DATA:
case FT_CTP_ACK:
case FT_CTP_NAK:
case FT_CTP_PONG:
if(bSTC)
{
// ::OutputDebugString("<<NET LOW>>Packet received in secondary channel\n");
m_ctpEndpoint2.Update(m_nCurrentTime, cFrameType, pStream);
}
else
{
m_ctpEndpoint.Update(m_nCurrentTime, cFrameType, pStream);
}
break;
default:
NET_ASSERT(0);
break;
};
}
void CServerSlot::ResetBandwidthStats()
{
m_BandwidthStats.Reset();
}
void CServerSlot::GetBandwidthStats( SServerSlotBandwidthStats &out ) const
{
out=m_BandwidthStats;
}
void CServerSlotImpl::GetMemoryStatistics(ICrySizer *pSizer)
{
pSizer->AddObject(this,sizeof(CServerSlotImpl));
m_ctpEndpoint.GetMemoryStatistics(pSizer);
m_ccpEndpoint.GetMemoryStatistics(pSizer);
}
//////////////////////////////////////////////////////////////////////////
void CServerSlotImpl::OnCCPSecurityQuery(CStream &stm)
{
}
//////////////////////////////////////////////////////////////////////////
void CServerSlotImpl::OnCCPSecurityResp(CStream &stm)
{
// Notify defence wall
m_pNetwork->OnSecurityMsgResponse( m_ipAddress,stm );
}
//////////////////////////////////////////////////////////////////////////
void CServerSlotImpl::OnCCPPunkBusterMsg(CStream &stm)
{
m_pNetwork->OnCCPPunkBusterMsg( m_ipAddress,stm );
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//FAKE SERVERSLOT IMPLEMENTATION
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
CServerSlotLocal::CServerSlotLocal(CServer *pServer,CClientLocal *pClient,CIPAddress &ip,CNetwork *pNetwork )
:CServerSlot(pNetwork)
{
m_cClientID=0;
m_pClient=pClient;
m_pServer=pServer;
m_ipAddress=ip;
m_bContextSetup=false;
m_nUpdateCounter=0;
m_bClientAdded = false;
}
CServerSlotLocal::~CServerSlotLocal()
{
if(m_pServer==NULL)
{
//call alberto
NET_ASSERT(0);
}
m_pNetwork->RemoveClientFromDefenceWall( m_ipAddress );
m_pServer->OnDestructSlot(this);
if(m_pClient)
{
m_pClient->OnDestructServerSlot();
}
}
void CServerSlotLocal::Disconnect(const char *szCause)
{
if(m_pSink)
m_pSink->OnXServerSlotDisconnect(szCause);
if(m_pClient)
m_pClient->OnDisconnenct(szCause);
}
void CServerSlotLocal::OnDisconnect(const char *szCause)
{
m_pNetwork->RemoveClientFromDefenceWall( m_ipAddress );
}
bool CServerSlotLocal::ContextSetup(CStream &stm)
{
//queue a context setup and
//the m_nUpdateCounter make sure
//that there will be 4 updates of delay
//before the local client receive this packet.
//This avoid that the client start to
//play before the local server is ready(hack?)
m_bContextSetup=true;
m_nUpdateCounter=0;
m_stmContextSetup=stm;
// Run Checks for this client.
if (!m_bClientAdded)
m_pNetwork->AddClientToDefenceWall( m_ipAddress );
m_bClientAdded = true;
return true;
}
void CServerSlotLocal::OnContextReady()
{
}
void CServerSlotLocal::SendReliable(CStream &stm,bool bSecondaryChannel)
{
if(m_pClient)
m_pClient->PushData(stm);
}
void CServerSlotLocal::SendUnreliable(CStream &stm)
{
if(m_pClient)
m_pClient->PushData(stm);
}
void CServerSlotLocal::PushData(CStream &stm)
{
m_qData.push(stm);
}
void CServerSlotLocal::Release()
{
assert(this);
delete this;
}
void CServerSlotLocal::UpdateSlot()
{
if(m_bContextSetup)
{
if(m_nUpdateCounter>4)
{
if(m_pClient)
m_pClient->OnContextSetup(m_stmContextSetup);
m_bContextSetup=false;
m_nUpdateCounter=0;
}
else
m_nUpdateCounter++;
}
else
{
while(!m_qData.empty())
{
if(m_pSink)
m_pSink->OnData(m_qData.front());
m_qData.pop();
}
}
}
void CServerSlotLocal::GetMemoryStatistics(ICrySizer *pSizer)
{
pSizer->AddObject(this,sizeof(CServerSlotLocal));
pSizer->AddObject(&m_qData,m_qData.size()*sizeof(CStream));
}
void CServerSlotLocal::OnCCPConnectResp(CStream &stm)
{
unsigned int uiSize;
stm.Read(uiSize);
if (uiSize)
{
assert(uiSize%8==0);
m_pbAuthorizationID = new BYTE[uiSize/8];
stm.ReadBits(m_pbAuthorizationID,uiSize);
m_uiAuthorizationSize = uiSize/8;
}
if(m_pSink)
{
#ifndef NOT_USE_UBICOM_SDK
// If its a multiplayer game check the cdkey
if(GetISystem()->GetIGame()->GetModuleState(EGameMultiplayer))
m_pNetwork->m_pUbiSoftClient->Server_CheckPlayerAuthorizationID(GetID(),m_pbAuthorizationID);
else
#endif // NOT_USE_UBICOM_SDK
{
m_pSink->OnXPlayerAuthorization(true,"",NULL,0);
}
m_pSink->OnXServerSlotConnect(m_pbAuthorizationID,m_uiAuthorizationSize);
}
}
void CServerSlot::OnPlayerAuthorization( bool bAllow, const char *szError, const BYTE *pGlobalID,
unsigned int uiGlobalIDSize )
{
m_pSink->OnXPlayerAuthorization(bAllow,szError,pGlobalID,uiGlobalIDSize);
m_pbGlobalID = new BYTE[uiGlobalIDSize];
m_uiGlobalIDSize = uiGlobalIDSize;
memcpy( m_pbGlobalID,pGlobalID,uiGlobalIDSize );
}

281
CryNetwork/ServerSlot.h Normal file
View File

@@ -0,0 +1,281 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: ServerSlot.h
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#ifndef _SERVER_SLOT_H_
#define _SERVER_SLOT_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Interfaces.h"
#include "ServerStateMachine.h"
#ifdef NO_GNB
#include "CTPEndpoint.h"
#else
#include "CTPEndpointGNB.h"
#endif
#include "CCPEndpoint.h"
#include "Network.h"
class ICrySizer;
//
// CServerSlot is released by the CXServerSlot
//
class CServerSlot :public IServerSlot, public _IServerSlotServices
{
public:
//! constructor
CServerSlot( CNetwork *pNetwork ) :m_pbAuthorizationID(NULL), m_pSink(0), m_pNetwork(pNetwork)
{
m_BandwidthStats.Reset();
m_pbGlobalID = 0;
}
//! destructor
virtual ~CServerSlot()
{
if (m_pbAuthorizationID)
delete [] m_pbAuthorizationID;
if (m_pbGlobalID)
delete [] m_pbGlobalID;
};
virtual bool IsActive() = 0;
virtual void Unlink() = 0;
virtual void Update(unsigned int nTime,CNP *pCNP ,CStream *pStream) = 0;
virtual CIPAddress &GetIP(){ return m_ipAddress; }
virtual void GetMemoryStatistics(ICrySizer *pSizer)=0;
virtual bool SendSecurityQuery(CStream &stm) { return true;};
virtual bool SendPunkBusterMsg(CStream &stm) { return true; };
// interface IServerSlot -------------------------------------------------------
virtual void Advise( IServerSlotSink *pSink ) { m_pSink = pSink; }
virtual void ResetBandwidthStats();
virtual void GetBandwidthStats( SServerSlotBandwidthStats &out ) const;
virtual unsigned int GetClientIP() const { return m_ipAddress.GetAsUINT(); };
virtual void OnPlayerAuthorization( bool bAllow, const char *szError, const BYTE *pGlobalID,
unsigned int uiGlobalIDSize );
//////////////////////////////////////////////////////////////////////////
// Returns client specific flags.
virtual unsigned int GetClientFlags() { return 0; };
virtual bool IsLocalSlot() const { return false; };
public: // -----------------------------------------------------------------------
BYTE * m_pbAuthorizationID; //!< CD Key AuthorizationID (use new and delete)
unsigned int m_uiAuthorizationSize; //!< Size of AuthorizationID in bytes
BYTE * m_pbGlobalID; //!< CD Key GlobalID (use new and delete)
unsigned int m_uiGlobalIDSize; //!< Size of GlobalID in bytes
protected: // --------------------------------------------------------------------
CNetwork * m_pNetwork; //!<
CIPAddress m_ipAddress; //!<
unsigned char m_cClientID; //!< //<<FIXME>> this can be removed in future
SServerSlotBandwidthStats m_BandwidthStats; //!< used for bandwidth calculations (to adjust the bandwidth)
IServerSlotSink * m_pSink; //!< connected CXServerSlot (game specific part)
};
/////////////////////////////////////////////////////////////////////////////////////////
//CServerSlot implementation
/////////////////////////////////////////////////////////////////////////////////////////
class CServerSlotImpl :public CServerSlot
{
public:
//! constructor
CServerSlotImpl( CNetwork *pNetwork,_IServerServices *pParent);
//! destructor
virtual ~CServerSlotImpl();
//!
void GetMemoryStatistics(ICrySizer *pSizer);
public: // --------------------------------------------------------------
//!
bool IsActive();
//!
void Update(unsigned int nTime,CNP *pCNP ,CStream *pStream);
//! unlink from the local server
void Unlink(){ m_pParent=NULL;}
// interface IServerSlot -------------------------------------------------------
virtual void Disconnect(const char *szCause);
virtual bool ContextSetup(CStream &stm);
virtual void SendReliable(CStream &stm,bool bSecondaryChannel);
virtual void SendUnreliable(CStream &stm);
virtual bool IsReady();
virtual void Release();
virtual unsigned int GetPacketsLostCount(){return m_ctpEndpoint.GetLostPackets();}
virtual unsigned int GetUnreliablePacketsLostCount();
virtual unsigned int GetPing();
virtual unsigned char GetID(){return m_cClientID;}
// interface _IServerSlotServices ----------------------------------------------
virtual void OnConnect();
virtual void OnContextReady();
virtual void OnDisconnect(const char *szCause);
virtual bool SendConnect();
virtual bool SendContextSetup();
virtual bool SendDisconnect(const char *szCause);
virtual bool SendServerReady();
virtual bool SendSecurityQuery(CStream &stm);
virtual bool SendPunkBusterMsg(CStream &stm);
virtual void Start(unsigned char cClientID,CIPAddress &ip);
// interface _IEndpointUser ----------------------------------------------------
virtual bool Send(CStream &stm);
virtual void OnData(CStream &stm);
// interface _ICCPUser ---------------------------------------------------------
virtual void OnCCPSetup(CStream &stm);
virtual void OnCCPConnect(CStream &stm){}
virtual void OnCCPConnectResp(CStream &stm);
virtual void OnCCPContextSetup(CStream &stm){}
virtual void OnCCPContextReady(CStream &stm);
virtual void OnCCPServerReady(){}
virtual void OnCCPDisconnect(const char *szCause);
virtual void OnCCPSecurityQuery(CStream &stm);
virtual void OnCCPSecurityResp(CStream &stm);
virtual void OnCCPPunkBusterMsg(CStream &stm);
virtual unsigned int GetClientFlags() { return m_nClientFlags; };
virtual bool IsLocalSlot() const { return false; };
private: // --------------------------------------------------------------------------
void ProcessPacket(unsigned char cFrameType,bool bSTC,CStream *pStream);
CServerStateMachine m_smCCPMachine; //!<
#ifdef NO_GNB
CCTPServer m_ctpEndpoint; //!<
#else
CCTPEndpointGNB m_ctpEndpoint; //!<
CCTPEndpointGNB m_ctpEndpoint2; //!<
#endif
CCCPEndpoint m_ccpEndpoint; //!<
DWORD m_dwKeepAliveTimer; //!< after 3 second without any incoming packets the connection will be considered lost
bool m_bActive; //!<
bool m_bClientAdded;
CStream m_stmContextReady; //!<
_IServerServices * m_pParent; //!<
CStream m_stmContext; //!<
struct CNPServerVariables m_ServerVariables; //!<
unsigned int m_nCurrentTime; //!<
unsigned int m_nPublicKey; //!<
//////////////////////////////////////////////////////////////////////////
// Client info.
//////////////////////////////////////////////////////////////////////////
// Client OS.
unsigned m_nClientOS_Minor; //!<
unsigned m_nClientOS_Major; //!<
// Client flags.
unsigned int m_nClientFlags; //!<
};
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
class CClientLocal;
class CServer;
//! fake CServerSlot implementation for local clients, doesn't use the network!*/
class CServerSlotLocal :public CServerSlot
{
public:
//! constructor
CServerSlotLocal(CServer *pServer,CClientLocal *pClient,CIPAddress &ip,CNetwork *pNetwork );
//! destructor
virtual ~CServerSlotLocal();
void GetMemoryStatistics(ICrySizer *pSizer);
bool IsActive(){return true;}
void Update(unsigned int nTime,CNP *pCNP ,CStream *pStream){};
void PushData(CStream &stm);
void UpdateSlot();
void Unlink(){ m_pServer=NULL; }
void ResetSink() { m_pClient=NULL; if(m_pSink)m_pSink->OnXServerSlotDisconnect(""); }
// interface IServerSlot ---------------------------------------------------
virtual void Disconnect(const char *szCause);
virtual bool ContextSetup(CStream &stm);
virtual void SendReliable(CStream &stm,bool bSecondaryChannel);
virtual void SendUnreliable(CStream &stm);
virtual bool IsReady(){ return ((m_pClient && m_pSink)?true:false); }
virtual void Release();
virtual unsigned int GetPacketsLostCount(){return 0;}
virtual unsigned int GetUnreliablePacketsLostCount(){return 0;}
virtual unsigned int GetPing(){return 0;}
virtual unsigned char GetID(){return m_cClientID;}
// interface _IServerSlotServices ------------------------------------------
virtual void OnConnect(){}
virtual void OnContextReady();
virtual void OnDisconnect(const char *szCause);
virtual bool SendConnect(){return true;}
virtual bool SendContextSetup(){return true;}
virtual bool SendDisconnect(const char *szCause){return true;}
virtual bool SendServerReady(){return true;}
virtual void Start(unsigned char cClientID,CIPAddress &ip){}
// interface _IEndpointUser ----------------------------------------------------
virtual bool Send(CStream &stm) { return true; }
virtual void OnData(CStream &stm) {}
// interface _ICCPUser ----------------------------------------------------
virtual void OnCCPSetup(CStream &stm){};
virtual void OnCCPConnect(CStream &stm){};
virtual void OnCCPConnectResp(CStream &stm);
virtual void OnCCPContextSetup(CStream &stm){};
virtual void OnCCPContextReady(CStream &stm){ if(m_pSink)m_pSink->OnContextReady(stm); };
virtual void OnCCPServerReady(){};
virtual void OnCCPDisconnect(const char *szCause){ if(m_pSink)m_pSink->OnXServerSlotDisconnect(szCause); };
virtual void OnCCPSecurityQuery(CStream &stm) {};
virtual void OnCCPSecurityResp(CStream &stm) {};
virtual void OnCCPPunkBusterMsg(CStream &stm) {};
virtual bool IsLocalSlot() const { return true; };
private: // -----------------------------------------------------------------
CClientLocal * m_pClient; //!<
CServer * m_pServer; //!<
bool m_bReady; //!<
STREAM_QUEUE m_qData; //!<
bool m_bContextSetup; //!<
CStream m_stmContextSetup; //!<
int m_nUpdateCounter; //!<
bool m_bClientAdded; //!<
};
#endif // _SERVER_SLOT_H_

View File

@@ -0,0 +1,86 @@
#include "stdafx.h"
#include "CNP.h"
#include "serversnooper.h"
#ifdef _DEBUG
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
CServerSnooper::CServerSnooper(void)
{
m_pSink=NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
CServerSnooper::~CServerSnooper(void)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
bool CServerSnooper::Init(IServerSnooperSink *pSink)
{
m_pSink=pSink;
if(NET_FAILED(m_socket.Create()))
return false;
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
void CServerSnooper::SearchForLANServers(unsigned int nTime)
{
CStream stm;
CQPInfoRequest cqpInfoRequest("status");
CIPAddress ipMulticastAddress(SERVER_MULTICAST_PORT,SERVER_MULTICAST_ADDRESS);
cqpInfoRequest.Save(stm);
m_nStartTime=nTime;
m_socket.Send(stm.GetPtr(),BITS2BYTES(stm.GetSize()),&ipMulticastAddress);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
void CServerSnooper::Update(unsigned int nTime)
{
int nRecvBytes;
m_nCurrentTime=nTime;
static CStream buf;
static CIPAddress ipFrom;
do{
buf.Reset();
nRecvBytes=0;
m_socket.Receive(buf.GetPtr(),
(int)BITS2BYTES(buf.GetAllocatedSize()),
nRecvBytes,
ipFrom);
/////////////////////////////////////////////////////////
if(nRecvBytes>0)
{
buf.SetSize(BYTES2BITS(nRecvBytes));
ProcessPacket(buf,ipFrom);
}
}while(nRecvBytes>0);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
void CServerSnooper::ProcessPacket(CStream &stmPacket,CIPAddress &ip)
{
CNP cnp;
cnp.LoadAndSeekToZero(stmPacket);
if(cnp.m_cFrameType == FT_CQP_INFO_RESPONSE)
{
CQPInfoResponse cqpInfoResponse;
cqpInfoResponse.Load(stmPacket);
if(m_pSink)
m_pSink->OnServerFound(ip, cqpInfoResponse.szResponse, m_nCurrentTime-m_nStartTime);
}
}

View File

@@ -0,0 +1,26 @@
#ifndef _SERVERSNOOPER_H_
#define _SERVERSNOOPER_H_
#include <INetwork.h>
class CServerSnooper :
public IServerSnooper
{
public:
CServerSnooper(void);
virtual ~CServerSnooper(void);
bool Init(IServerSnooperSink *pSink);
public:
//IServerSnooper
void SearchForLANServers(unsigned int nTime);
void Update(unsigned int nTime);
void Release(){delete this;}
protected:
void ProcessPacket(CStream &stmPacket,CIPAddress &ip);
private:
CDatagramSocket m_socket;
unsigned int m_nStartTime;
unsigned int m_nCurrentTime;
IServerSnooperSink *m_pSink;
};
#endif //_SERVERSNOOPER_H_

View File

@@ -0,0 +1,244 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: ServerStateMachine.cpp
// Description:
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ServerStateMachine.h"
#ifdef _DEBUG
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
#include "IConsole.h" // IConsole
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CServerStateMachine::CServerStateMachine()
{
m_pParent=0;
}
CServerStateMachine::~CServerStateMachine()
{
}
void CServerStateMachine::_Trace(char *s)
{
NET_TRACE(s);
}
void CServerStateMachine::_TraceStatus(unsigned int dwStatus)
{
switch (dwStatus)
{
case STATUS_IDLE:
_Trace("STATUS_IDLE");
break;
case STATUS_SRV_WAIT_FOR_CONNECT_RESP:
_Trace("STATUS_SRV_WAIT_FOR_CONNECT_RESP");
break;
case STATUS_SRV_CONNECTED:
_Trace("STATUS_SRV_CONNECTED");
break;
case STATUS_SRV_WAIT_FOR_CONTEXT_READY:
_Trace("STATUS_SRV_WAIT_FOR_CONTEXT_READY");
break;
case STATUS_SRV_READY:
_Trace("STATUS_SRV_READY");
break;
case STATUS_SRV_DISCONNECTED:
_Trace("STATUS_SRV_DISCONNECTED");
break;
default:
_Trace("UNKNOWN");
break;
}
}
void CServerStateMachine::HandleIDLE(unsigned int dwIncomingSignal, DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_SETUP)
if(dwParam==0) //the protocol versions do not match
{
SetStatus(STATUS_SRV_DISCONNECTED);
const char *serr="wrong protocol version";
OnSignal(SIG_SRV_SEND_DISCONNECT, (ULONG_PTR)serr);
OnSignal(SIG_SRV_DISCONNECTED, (ULONG_PTR)serr);
}
else
{
SetStatus(STATUS_SRV_WAIT_FOR_CONNECT_RESP);
SetTimer(TM_CONNECT_RESP, TM_CONNECT_RESP_ET);
OnSignal(SIG_SRV_SEND_CONNECT, dwParam);
}
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_ACTIVE_DISCONNECT)
SetStatus(STATUS_SRV_DISCONNECTED);
OnSignal(SIG_SRV_SEND_DISCONNECT, dwParam);
OnSignal(SIG_SRV_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CServerStateMachine::HandleWAIT_FOR_CONNECT_RESP(unsigned int dwIncomingSignal, DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_CONNECT_RESP)
ResetTimer();
SetStatus(STATUS_SRV_CONNECTED);
OnSignal(SIG_SRV_CONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(TM_CONNECT_RESP)
SetStatus(STATUS_SRV_DISCONNECTED);
OnSignal(SIG_SRV_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CServerStateMachine::HandleCONNECTED(unsigned int dwIncomingSignal, DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_CONTEXT_SETUP) // we now have this info which map, initiate the loading on the client
SetStatus(STATUS_SRV_WAIT_FOR_CONTEXT_READY);
SetTimer(TM_CONTEXT_READY, TM_CONTEXT_READY_ET);
OnSignal(SIG_SRV_SEND_CONTEXT_SETUP, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_ACTIVE_DISCONNECT)
SetStatus(STATUS_SRV_DISCONNECTED);
OnSignal(SIG_SRV_SEND_DISCONNECT, dwParam);
OnSignal(SIG_SRV_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_DISCONNECT)
ResetTimer();
SetStatus(STATUS_SRV_DISCONNECTED);
OnSignal(SIG_SRV_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CServerStateMachine::HandleWAIT_FOR_CONTEXT_READY(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(TM_CONTEXT_READY)
ResetTimer();
SetStatus(STATUS_SRV_DISCONNECTED);
OnSignal(SIG_SRV_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_CONTEXT_SETUP) // we changed the map, initiate the loading on the client
SetTimer(TM_CONTEXT_READY, TM_CONTEXT_READY_ET);
OnSignal(SIG_SRV_SEND_CONTEXT_SETUP, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_CONTEXT_READY)
ResetTimer();
SetStatus(STATUS_SRV_READY);
OnSignal(SIG_SRV_NOTIFY_CONTEXT_READY, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_DISCONNECT)
ResetTimer();
SetStatus(STATUS_SRV_DISCONNECTED);
OnSignal(SIG_SRV_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_ACTIVE_DISCONNECT)
ResetTimer();
SetStatus(STATUS_SRV_DISCONNECTED);
OnSignal(SIG_SRV_SEND_DISCONNECT, dwParam);
OnSignal(SIG_SRV_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CServerStateMachine::HandleREADY(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
BEGIN_SIGNAL_HANDLER(dwIncomingSignal)
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_CONTEXT_SETUP) // we changed the map, initiate the loading on the client
SetStatus(STATUS_SRV_WAIT_FOR_CONTEXT_READY);
SetTimer(TM_CONTEXT_READY, TM_CONTEXT_READY_ET);
OnSignal(SIG_SRV_SEND_CONTEXT_SETUP, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_DISCONNECT)
SetStatus(STATUS_SRV_DISCONNECTED);
OnSignal(SIG_SRV_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
IF_SIGNAL(SIG_SRV_ACTIVE_DISCONNECT)
SetStatus(STATUS_SRV_DISCONNECTED);
OnSignal(SIG_SRV_SEND_DISCONNECT, dwParam);
OnSignal(SIG_SRV_DISCONNECTED, dwParam);
ENDIF_SIGNAL()
/////////////////////////////////////////////////////////////////////
END_SIGNAL_HANDLER()
}
void CServerStateMachine::Init(_IServerSlotServices *pParent)
{
m_pParent=pParent;
}
void CServerStateMachine::HandleDISCONNECTED(unsigned int dwIncomingSignal, DWORD_PTR dwParam)
{
// the machine can't leave this status
}
void CServerStateMachine::OnSignal(unsigned int dwOutgoingSignal, DWORD_PTR dwParam)
{
switch (dwOutgoingSignal)
{
case SIG_SRV_SEND_CONNECT:
m_pParent->SendConnect();
break;
case SIG_SRV_SEND_DISCONNECT:
m_pParent->SendDisconnect((const char *)dwParam);
break;
case SIG_SRV_SEND_CONTEXT_SETUP:
m_pParent->SendContextSetup();
break;
case SIG_SRV_NOTIFY_CONTEXT_READY:
m_pParent->OnContextReady();
break;
case SIG_SRV_CONNECTED:
m_pParent->OnConnect();
break;
case SIG_SRV_DISCONNECTED:
m_pParent->OnDisconnect((const char *)dwParam);
break;
default:
NET_ASSERT(0);
break;
}
}

View File

@@ -0,0 +1,117 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: ServerStateMachine.h
// Description:
//
// History:
// -08/25/2001: Alberto Demichelis, created
// -01/26/2003: Martin Mittring, commented the stated
//
//////////////////////////////////////////////////////////////////////
#ifndef _SERVER_STATE_MACHINE_H_
#define _SERVER_STATE_MACHINE_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <platform.h>
#include "StateMachine.h"
#include "Interfaces.h"
#define STATUS_SRV_WAIT_FOR_CONNECT_RESP STATUS_BASE+1
#define STATUS_SRV_CONNECTED STATUS_BASE+2
#define STATUS_SRV_WAIT_FOR_CONTEXT_READY STATUS_BASE+3
#define STATUS_SRV_READY STATUS_BASE+4
#define STATUS_SRV_DISCONNECTED STATUS_BASE+5
//in signals
#define SIG_SRV_START SIGNAL_BASE+1
#define SIG_SRV_SETUP SIGNAL_BASE+2
#define SIG_SRV_CONNECT_RESP SIGNAL_BASE+3
#define SIG_SRV_CONTEXT_SETUP SIGNAL_BASE+4
#define SIG_SRV_CONTEXT_READY SIGNAL_BASE+5
#define SIG_SRV_DISCONNECT SIGNAL_BASE+6
#define SIG_SRV_ACTIVE_DISCONNECT SIGNAL_BASE+7
//out signals
#define SIG_SRV_SEND_CONNECT SIGNAL_BASE+8
#define SIG_SRV_SEND_DISCONNECT SIGNAL_BASE+9
#define SIG_SRV_SEND_CONTEXT_SETUP SIGNAL_BASE+10
#define SIG_SRV_NOTIFY_CONTEXT_READY SIGNAL_BASE+12
#define SIG_SRV_CONNECTED SIGNAL_BASE+13
#define SIG_SRV_DISCONNECTED SIGNAL_BASE+14
#define TM_CONNECT_RESP TIMER_BASE+1
#ifdef _DEBUG
#define TM_CONNECT_RESP_ET 200000
#else
#define TM_CONNECT_RESP_ET 20000
#endif
#define TM_CONTEXT_READY TIMER_BASE+2
#define TM_CONTEXT_READY_ET (5*60*1000) // 5 min to load the map
class CServerStateMachine :public CStateMachine
{
BEGIN_STATUS_MAP()
STATUS_ENTRY(STATUS_IDLE,HandleIDLE)
// goes to the next state when getting the CCPSetup packet (PlayerPassword,ProtocolVersion) from the client
// or to STATUS_SRV_DISCONNECTED when the version doesn't match
STATUS_ENTRY(STATUS_SRV_WAIT_FOR_CONNECT_RESP,HandleWAIT_FOR_CONNECT_RESP)
// goes to the next state when getting the CCPConnectResp packet (AuthorizationID) from the client
STATUS_ENTRY(STATUS_SRV_CONNECTED,HandleCONNECTED)
// goes to the next state when the authorization is ok
STATUS_ENTRY(STATUS_SRV_WAIT_FOR_CONTEXT_READY,HandleWAIT_FOR_CONTEXT_READY)
// the client is currently loading the map and we wait
// when getting the CCPContextReady packet (bHost,p_name,p_model) from the client
// we sends all entities to the client (CXServerSlot::OnContextReady) and go to the next state
STATUS_ENTRY(STATUS_SRV_READY,HandleREADY)
// goes back to STATUS_SRV_WAIT_FOR_CONTEXT_READY when CServerSlot::ContextSetup() was called
// to change the map/mod and sync the server variables once again
STATUS_ENTRY(STATUS_SRV_DISCONNECTED,HandleDISCONNECTED)
// when going in this state send the SIG_DISCONNECTED signal and the system will remove the client soon
END_STATUS_MAP()
public: // ---------------------------------------------------------------------
//! constructor
CServerStateMachine();
//! destructor
virtual ~CServerStateMachine();
//!
void Init(_IServerSlotServices *pParent);
private: // ---------------------------------------------------------------------
//status handlers
void HandleIDLE(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleWAIT_FOR_CONNECT_RESP(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleCONNECTED(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleWAIT_FOR_CONTEXT_READY(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleREADY(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void HandleDISCONNECTED(unsigned int dwIncomingSignal,DWORD_PTR dwParam);
void OnSignal(unsigned int dwOutgoingSignal,DWORD_PTR dwParam);
//tracing
void _Trace(char *s);
void _TraceStatus(unsigned int dwStatus);
_IServerSlotServices * m_pParent; //!< pointer to the parent object (is not released), is 0 is you forgot to call Init()
};
#endif //_SERVER_STATE_MACHINE_H_

145
CryNetwork/StateMachine.h Normal file
View File

@@ -0,0 +1,145 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Network source code
//
// File: statemachine.h
// Description: state machine toolkit
//
// History:
// -July 25,2001:Created by Alberto Demichelis
//
//////////////////////////////////////////////////////////////////////
#ifndef _STATE_MACHINE_H_
#define _STATE_MACHINE_H_
#include <stdio.h>
#define ANY_SIGNAL_NOT_HANDLED 0xFFFFFFFF
#define ANY_SIGNAL_HANDLED 0x00000000
#define STATUS_BASE 0xFFFF0000
#define STATUS_IDLE STATUS_BASE
#define SIGNAL_BASE 0x00000000
#define TIMER_BASE 0x0000FFFF
#ifndef PS2
#define DEBUG_STRING(sss) ::OutputDebugString(sss);
#else
#define DEBUG_STRING(sss) cout << sss;
#endif
#define BEGIN_STATUS_MAP() void _ProcessSignal(unsigned int dwIncomingSignal,ULONG_PTR dwParam) \
{ \
if(HandleANY(dwIncomingSignal,dwParam)==ANY_SIGNAL_NOT_HANDLED) \
switch(m_dwStatus) \
{
#define STATUS_ENTRY( _signal , _handler ) case _signal : \
_handler(dwIncomingSignal,dwParam); \
break;
#define END_STATUS_MAP() default : \
::OutputDebugString("singal not handled\n"); \
break; \
}; \
} \
#define BEGIN_SIGNAL_HANDLER(signal) switch(signal){ \
#define IF_SIGNAL(signal) case signal:{
#define ENDIF_SIGNAL() } \
break; \
#define END_SIGNAL_HANDLER() default: \
_Trace("Signal not handled\n"); \
break; \
};
#define ANY_SIGNAL_EXCEPT(status){if(m_dwStatus==status){return ANY_SIGNAL_NOT_HANDLED;}}
#define BEGIN_ANY_SIGNAL_HANDLER(signal) switch(signal){
#define END_ANY_SIGNAL_HANDLER() default: \
DEBUG_STRING("ANY Signal not handled\n"); \
return ANY_SIGNAL_NOT_HANDLED; \
break; \
}; \
return ANY_SIGNAL_HANDLED;
class CStateMachine
{
protected:
virtual void _ProcessSignal(unsigned int dwIncomingSignal,ULONG_PTR dwParam)=0;
void SetTimer(unsigned int dwName,unsigned int dwElapsed)
{
m_dwTimerName=dwName;
m_dwTimerElapsed=dwElapsed;
m_dwTimerStart=::GetTickCount();
}
void ResetTimer()
{
m_dwTimerStart=0;
m_dwTimerElapsed=0;
m_dwTimerName=0;
}
void SetStatus(unsigned int dwStatus)
{
_TraceStatus(m_dwStatus);
_Trace(">>");
_TraceStatus(dwStatus);
_Trace("\n");
m_dwStatus=dwStatus;
}
virtual unsigned int HandleANY(unsigned int dwIncomingSignal,DWORD_PTR dwParam)
{
return ANY_SIGNAL_NOT_HANDLED;
}
virtual void OnSignal(unsigned int dwOutgoingSignal,DWORD_PTR dwParam)
{
NET_TRACE("WARNING default OnSignal called\n");
}
virtual void _Trace(char *s){};
virtual void _TraceStatus(unsigned int dwStatus){};
public:
CStateMachine()
{
m_dwStatus=0;
Reset();
}
virtual void Reset()
{
SetStatus(STATUS_IDLE);
ResetTimer();
}
BOOL Update(unsigned int dwIncomingSignal=0,DWORD_PTR dwParam=0)
{
if(m_dwTimerName)
if((::GetTickCount()-m_dwTimerStart)>=m_dwTimerElapsed)
{
unsigned int dwTimerName=m_dwTimerName;
ResetTimer();
_ProcessSignal(dwTimerName,0);
}
if(dwIncomingSignal)
{
_ProcessSignal(dwIncomingSignal,dwParam); // this pointer might be destroyed after this call
}
return TRUE;
}
unsigned int GetCurrentStatus(){return m_dwStatus;}
unsigned int m_dwStatus;
//
unsigned int m_dwTimerStart;
unsigned int m_dwTimerElapsed;
unsigned int m_dwTimerName;
};
#endif //_STATE_MACHINE_H_

View File

@@ -0,0 +1,168 @@
#include "stdafx.h"
#include "compressionhelper.h"
CStaticCharCompressor::CStaticCharCompressor()
{
m_dwRootIndex=0xffffffff;
}
void CStaticCharCompressor::InitFromStatistics( const DWORD indwPriority[256] )
{
std::multiset<SPriIndex> Sorter;
m_Nodes.clear();
m_Nodes.reserve(256*2-1);
for(DWORD i=0;i<256;i++)
{
m_Nodes.push_back( SNode((unsigned char)i) );
Sorter.insert( SPriIndex(i,indwPriority[i]+1) ); // +1 to ensure if we add two priorites the value is raising
}
// iterate through all nodes from lowest to highest priority
for(;;)
{
DWORD dwIndex1,dwIndex2;
DWORD dwPriority;
// get element with lowest priorty
{
std::multiset<SPriIndex>::iterator top = Sorter.begin();
assert(top!=Sorter.end()); // cannot be because we always remove two and add one
const SPriIndex &ref = *top;
dwIndex1=ref.m_dwIndex;
dwPriority=ref.m_dwPriority;
Sorter.erase(top);
}
// get element with second lowest priorty
{
std::multiset<SPriIndex>::iterator top = Sorter.begin();
if(top==Sorter.end())
{
m_dwRootIndex=dwIndex1;
break;
}
const SPriIndex &ref = *top;
dwIndex2=ref.m_dwIndex;
dwPriority+=ref.m_dwPriority;
Sorter.erase(top);
}
DWORD dwNextIndex = m_Nodes.size();
m_Nodes.push_back( SNode(dwIndex1,dwIndex2) );
Sorter.insert( SPriIndex(dwNextIndex,dwPriority) );
}
// build m_CharToBit
{
for(DWORD i=0;i<256;i++)
{
bool bRet=GetCharFromBits_slow( (unsigned char)i, m_dwRootIndex, m_CharToBit[i] );
assert(bRet); // it must be there
}
}
}
bool CStaticCharCompressor::GetCharFromBits_slow( const unsigned char inVal, const DWORD indwIndex, SBitToChar &outDat )
{
SNode &ref = m_Nodes[indwIndex];
if(ref.IsLeaf())
{
if(ref.m_Value==inVal)
return true;
}
else
{
outDat.m_BitCount++;
assert(outDat.m_BitCount<16);
outDat.m_Bitfield<<=1;
// one
outDat.m_Bitfield|=0x1;
if(GetCharFromBits_slow(inVal,ref.m_dwIndexOne,outDat))
return true;
// zero
outDat.m_Bitfield&=~0x1;
if(GetCharFromBits_slow(inVal,ref.m_dwIndexZero,outDat))
return true;
outDat.m_Bitfield>>=1;
outDat.m_BitCount--;
}
return false;
}
bool CStaticCharCompressor::Write( CStream &outStream, const unsigned char inChar )
{
assert(m_dwRootIndex!=0xffffffff); // instance is not initialized
SBitToChar &ref=m_CharToBit[inChar];
/*
#ifdef _DEBUG
CStream test;
unsigned char cTest;
test.WriteNumberInBits((DWORD)(ref.m_Bitfield),ref.m_BitCount);
Read(test,cTest);
assert(cTest==inChar);
#endif
*/
for(DWORD i=0;i<ref.m_BitCount;i++)
{
bool b=(ref.m_Bitfield & (1<<(ref.m_BitCount-i-1)))!=0;
if(!outStream.Write(b))
return false;
}
// return outStream.WriteNumberInBits((DWORD)(ref.m_Bitfield),ref.m_BitCount);
return true;
}
bool CStaticCharCompressor::Read( CStream &inStream, unsigned char &outChar )
{
assert(m_dwRootIndex!=0xffffffff); //
DWORD dwCurrentIndex=m_dwRootIndex;
for(;;)
{
bool bBit;
SNode &ref=m_Nodes[dwCurrentIndex];
if(ref.IsLeaf())
{
outChar=ref.m_Value;
return true;
}
if(!inStream.Read(bBit))
return false;
if(bBit)
dwCurrentIndex=ref.m_dwIndexOne;
else
dwCurrentIndex=ref.m_dwIndexZero;
}
}

View File

@@ -0,0 +1,98 @@
// for ASCII strings up to 255 character
// character with priority 0 remain available
// References:
// http://www.howtodothings.com/showarticle.asp?article=313
// http://dogma.net/markn/articles/bwt/bwt.htm (this might perform worse for small strings)
#include <vector> // STL vector<>
//
class CStaticCharCompressor
{
public:
//! constructor
CStaticCharCompressor();
//! \param indwPriority table of the priorites of the character set
void InitFromStatistics( const DWORD indwPriority[256] );
//! \return stream error
bool Write( CStream &outStream, const unsigned char inChar );
//! \return stream error
bool Read( CStream &inStream, unsigned char &outChar );
private: // ---------------------------------------------------------
struct SNode
{
//! constructor for a leaf
SNode( const unsigned char inValue )
:m_Value(inValue)
{
m_dwIndexZero=0xffffffff;m_dwIndexOne=0xffffffff; // unused
}
//! constructor for a node
SNode( const DWORD indwIndexZero, const DWORD indwIndexOne )
:m_dwIndexZero(indwIndexZero),m_dwIndexOne(indwIndexOne)
{
m_Value=0; // unused
}
DWORD m_dwIndexZero; //!< 0xffffffff or index to the subtree for bit = 0
DWORD m_dwIndexOne; //!< 0xffffffff or index to the subtree for bit = 1
unsigned char m_Value; //!< is only valid for Leafes
bool IsLeaf()
{
return m_dwIndexZero==0xffffffff && m_dwIndexOne==0xffffffff;
}
};
// ------------------------------------------------------------------
struct SPriIndex
{
//! constructor
SPriIndex( const DWORD indwIndex, const DWORD indwPriority )
:m_dwIndex(indwIndex),m_dwPriority(indwPriority)
{
}
DWORD m_dwIndex; //!<
DWORD m_dwPriority; //!<
//! used for sorting (from low to hight values)
bool operator<( const SPriIndex &inRhs ) const
{
return m_dwPriority<inRhs.m_dwPriority;
}
};
// ------------------------------------------------------------------
struct SBitToChar
{
//! constructor
SBitToChar()
{
m_Bitfield=0;m_BitCount=0;
}
unsigned short m_Bitfield; //!<
unsigned short m_BitCount; //!<
};
// ------------------------------------------------------------------
DWORD m_dwRootIndex; //!< 0 if the instance was not initiated - tree is build out of elements from m_NodeMemory
std::vector<SNode> m_Nodes; //!<
SBitToChar m_CharToBit[256]; //!<
bool GetCharFromBits_slow( const unsigned char inVal, const DWORD indwIndex, SBitToChar &outDat );
};

8
CryNetwork/StdAfx.cpp Normal file
View File

@@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// CryNet.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

194
CryNetwork/StdAfx.h Normal file
View File

@@ -0,0 +1,194 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__0F62BDE9_4784_4F7A_A265_B7D1A71883D0__INCLUDED_)
#define AFX_STDAFX_H__0F62BDE9_4784_4F7A_A265_B7D1A71883D0__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//////////////////////////////////////////////////////////////////////////
// THIS MUST BE AT THE VERY BEGINING OF STDAFX.H FILE.
// Disable STL threading support, (makes STL faster)
//////////////////////////////////////////////////////////////////////////
#define _NOTHREADS
#define _STLP_NO_THREADS
//////////////////////////////////////////////////////////////////////////
#include <platform.h>
#ifndef _XBOX
#ifdef WIN32
#include <windows.h>
#define WIN32_LEAN_AND_MEAN
#endif
#else
#include <xtl.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#define USE_NEWPOOL
#include <CryMemoryManager.h>
#include <map>
#include <INetwork.h>
#include "DatagramSocket.h"
#include <CrySizer.h>
// TODO: reference additional headers your program requires here
#if defined(_DEBUG) && !defined(LINUX)
#include <crtdbg.h>
#endif
#if _MSC_VER > 1000
#pragma warning( disable : 4786 )
//#pragma warning( disable : 4716 )
#endif // _MSC_VER > 1000
#ifdef PS2
typedef int BOOL;
#endif
#ifndef __NET_ASSERT
#define __NET_ASSERT
#if 1
#if defined(WIN64)
#define NET_ASSERT(x)
#elif defined(_XBOX)
#define NET_ASSERT(x)
#elif defined(PS2)
#include <iostream.h>
inline void NET_ASSERT(void * x)
{
if (!(x))
{
cout << "Assertion Failed!!\n\nFile: " << __FILE__ <<"\n\nLine: " << __LINE__ << "\n";
DEBUG_BREAK;
}
}
#elif defined(WIN32)
#define NET_ASSERT(x) \
{ \
if (!(x)) { \
static char sAssertionMessage[500]; \
\
wsprintf(sAssertionMessage, "Assertion Failed!!\n\nFile: \"%s\"\n\nLine: %d\n", __FILE__, __LINE__); \
::MessageBox(NULL, sAssertionMessage, "Assertion Failed", MB_OK | MB_ICONERROR); \
DEBUG_BREAK; \
} \
}
#else
#define NET_ASSERT(x)
#endif
#endif //1
#endif
#ifndef NET____TRACE
#define NET____TRACE
// src and trg can be the same pointer (in place encryption)
// len must be in bytes and must be multiple of 8 byts (64bits).
// key is 128bit: int key[4] = {n1,n2,n3,n4};
// void encipher(unsigned int *const v,unsigned int *const w,const unsigned int *const k )
#define TEA_ENCODE( src,trg,len,key ) {\
register unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3; \
register unsigned int delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3]; \
while (nlen--) {\
register unsigned int y=v[0],z=v[1],n=32,sum=0; \
while(n-->0) { sum += delta; y += (z << 4)+a ^ z+sum ^ (z >> 5)+b; z += (y << 4)+c ^ y+sum ^ (y >> 5)+d; } \
w[0]=y; w[1]=z; v+=2,w+=2; }}
// src and trg can be the same pointer (in place decryption)
// len must be in bytes and must be multiple of 8 byts (64bits).
// key is 128bit: int key[4] = {n1,n2,n3,n4};
// void decipher(unsigned int *const v,unsigned int *const w,const unsigned int *const k)
#define TEA_DECODE( src,trg,len,key ) {\
register unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3; \
register unsigned int delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3]; \
while (nlen--) { \
register unsigned int y=v[0],z=v[1],sum=0xC6EF3720,n=32; \
while(n-->0) { z -= (y << 4)+c ^ y+sum ^ (y >> 5)+d; y -= (z << 4)+a ^ z+sum ^ (z >> 5)+b; sum -= delta; } \
w[0]=y; w[1]=z; v+=2,w+=2; }}
// encode size ignore last 3 bits of size in bytes. (encode by 8bytes min)
#define TEA_GETSIZE( len ) ((len) & (~7))
#ifndef PS2
inline void __cdecl __NET_TRACE(const char *sFormat, ... )
{
/*
va_list vl;
static char sTraceString[500];
va_start(vl, sFormat);
vsprintf(sTraceString, sFormat, vl);
va_end(vl);
NET_ASSERT(strlen(sTraceString) < 500)
CryLogAlways( sTraceString );
va_list vl;
static char sTraceString[500];
va_start(vl, sFormat);
vsprintf(sTraceString, sFormat, vl);
va_end(vl);
NET_ASSERT(strlen(sTraceString) < 500)
::OutputDebugString(sTraceString);*/
}
#else
inline void __NET_TRACE(const char *sFormat, ... )
{
va_list vl;
static char sTraceString[500];
va_start(vl, sFormat);
vsprintf(sTraceString, sFormat, vl);
va_end(vl);
NET_ASSERT(strlen(sTraceString) < 500)
cout << sTraceString;
}
#endif //PS2
#if 1
#define NET_TRACE __NET_TRACE
#else
#define NET_TRACE 1?(void)0 : __NET_TRACE;
#endif //NET____TRACE
#endif //_DEBUG
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__0F62BDE9_4784_4F7A_A265_B7D1A71883D0__INCLUDED_)

View File

@@ -0,0 +1,19 @@
#include "stdafx.h"
#ifndef NOT_USE_UBICOM_SDK
#if defined(WIN32)
# define GS_WIN32
#else
# define GS_LINUX
#endif
#include "UbisoftMemory.h"
extern "C"
{
void * __stdcall ExtAlloc_Malloc(unsigned int lSize) {return malloc(lSize);} ;
void __stdcall ExtAlloc_Free(void *ptr) {free(ptr);};
void * __stdcall ExtAlloc_Realloc(void *ptr, unsigned int uiSize) {return realloc(ptr,uiSize);};
}
#endif // NOT_USE_UBICOM_SDK

View File

@@ -0,0 +1,14 @@
#ifndef __UBISOFT_MEMORY_H
#define __UBISOFT_MEMORY_H
#if defined(WIN32)
# define GS_WIN32
#else
# define GS_LINUX
#endif
extern "C" void * __stdcall ExtAlloc_Malloc(unsigned int lSize);
extern "C" void __stdcall ExtAlloc_Free(void *ptr);
extern "C" void * __stdcall ExtAlloc_Realloc(void *ptr, unsigned int uiSize);
#endif

10
CryNetwork/todo.txt Normal file
View File

@@ -0,0 +1,10 @@
//CRYNET TODO
DONE !! -disconnection timeout(echo request)
DONE !! -level loading stuff
done-server search routine
we can say...done-integration with the framework
-test and finish ping computation
-lag test ,"rate adaptive" packet building, "ping adaptive" timeouts
-implement unrealiable only packets(not acknwoleged)
-master server