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

827 lines
22 KiB
C++

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