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