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

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 );
}