512 lines
12 KiB
C++
512 lines
12 KiB
C++
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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));
|
|
}
|