123
This commit is contained in:
826
CryNetwork/CTPEndpoint.cpp
Normal file
826
CryNetwork/CTPEndpoint.cpp
Normal 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)
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user