Files
FC1/CryNetwork/Client.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

584 lines
14 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// 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
}
}