DragonNest/Common/NetworkLib/RUDPSocketFrame.cpp
Cussrro 47f7895977 Revert "修复编码问题"
This reverts commit 9e69c01767.
2024-12-21 10:04:04 +08:00

1379 lines
34 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stdafx.h"
#include <crtdbg.h>
#include <process.h>
#include <MMSystem.h>
#include "RUDPSocketFrame.h"
#include "Log.h"
#include "MemPool.h"
#include "PerfCheck.h"
#include <fstream>
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
static unsigned long GetTimeTick()
{
static int pivot = timeGetTime();
return timeGetTime() - pivot;
}
CRUDPSocketFrame::CRUDPSocketFrame()
{
m_hSocket = INVALID_SOCKET;
#ifdef _SYNC_RUDP
InitializeCriticalSection(&m_CS);
#endif
m_hThread = NULL;
m_bAlive = true;
m_iNetIDCnt = 1;
memset(m_nLastCheckTime, 0, sizeof(m_nLastCheckTime));
m_nThreadid = 0;
memset(m_szPublicIP, 0, sizeof(m_szPublicIP));
memset(m_szPrivateIP, 0, sizeof(m_szPrivateIP));
m_nPort = 0;
m_nCurTick = 0;
#ifdef _DEBUG
#ifdef _SYNC_RUDP
m_ProtectedSync = false;
#endif
#endif
::srand(timeGetTime());
GetTimeTick();
#if defined( STRESS_TEST )
CRUDPConnect* pConnect = new CRUDPConnect( inet_addr("10.0.3.25"), htons(5000), 0 );
m_ConnectList[0] = pConnect;
#endif
m_dwAffinityNum = INT_MAX;
m_bEnableAffinityCheck = false;
m_bClient = false;
}
CRUDPSocketFrame::~CRUDPSocketFrame()
{
Close();
_ASSERT(m_hThread == NULL); // À̰÷¿¡¼­ Assert Çѹø ³µ½À´Ï´Ù...
_ASSERT(m_hSocket == INVALID_SOCKET);
#ifdef _SYNC_RUDP
DeleteCriticalSection(&m_CS);
#endif
}
unsigned int __stdcall CRUDPSocketFrame::_threadmain(void * pParam)
{
((CRUDPSocketFrame*)pParam)->ThreadMain();
return 0;
}
void CRUDPSocketFrame::ThreadMain()
{
#ifdef PRE_ADD_THREADAFFINITY
if (m_dwAffinityNum != INT_MAX)
{
DWORD dwNumber = GetCurrentProcessorNumber();
if (m_dwAffinityNum != dwNumber)
EnableAffinitySetting();
}
#endif //#ifdef PRE_ADD_THREADAFFINITY
char buffer[1024*4];
int readbytes, addrlen;
unsigned long totalbytes, i;
unsigned long busytime;
SOCKADDR_IN addr;
fd_set fdset;
timeval tm;
#ifndef _SKIP_THREAD
while (m_bAlive)
#endif
{
// PROFILE_TIME_TEST_BLOCK_START( "CRUDPSocketFrame::ThreadMain()" );
tm.tv_sec = 0;
tm.tv_usec = _SELECT_TIMEOUT_SRV;
FD_ZERO(&fdset);
FD_SET(m_hSocket, &fdset);
m_nCurTick = GetTimeTick();
if (select(FD_SETSIZE, (fd_set*)&fdset, (fd_set*)0, (fd_set*)0, &tm) != SOCKET_ERROR)
{
busytime = GetCurTick() + _SELECT_BUSYTIME; //ó¸®ÇÏ´Â µµÁß µ¥ÀÌŸ µµÂøÀÇ °æ¿ì 󸮸¦ ºü¸£°Ô ÇϱâÀ§Çؼ­ ·çÇÁ¸¦ ¸¸µç´Ù.
//´Ü ³Ê¹« µ¹¾Æ¼­ ÁÁÀ»°Ô ¾øÀ¸¹Ç·Î Àû´çÇÑ Áö¿¬½Ã°£À» °®´Â´Ù.
if (fdset.fd_count > 0)
{
do {
ioctlsocket(m_hSocket, FIONREAD, &totalbytes);
for (i = 0; i < totalbytes && m_bAlive == true;)
{
addrlen = sizeof(addr);
readbytes = recvfrom(m_hSocket, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, &addrlen);
if (readbytes == SOCKET_ERROR)
{
int lasterr = GetLastError();
if (lasterr == WSAECONNRESET)
{
Enter();
std::map <SOCKADDR_IN*, CRUDPConnect*, _addr_less_>::iterator ii = m_ConnectRef.find(&addr);
if (ii != m_ConnectRef.end() &&
(*ii).first->sin_addr.S_un.S_addr == addr.sin_addr.S_un.S_addr && (*ii).first->sin_port == addr.sin_port)
DisConnectPtr((*ii).second, false);
Leave();
#ifdef _DEBUG
_tprintf(_T("²÷°ÜºÎ·¶»ï!, %d (%d.%d.%d.%d)\n"), lasterr,
addr.sin_addr.S_un.S_un_b.s_b1, addr.sin_addr.S_un.S_un_b.s_b2,
addr.sin_addr.S_un.S_un_b.s_b3, addr.sin_addr.S_un.S_un_b.s_b4,
addr.sin_port);
#endif
}
else
{
#ifdef _DEBUG
_tprintf(_T("¾ÆÆÄ~~~, %d (%d.%d.%d.%d)\n"), lasterr,
addr.sin_addr.S_un.S_un_b.s_b1, addr.sin_addr.S_un.S_un_b.s_b2,
addr.sin_addr.S_un.S_un_b.s_b3, addr.sin_addr.S_un.S_un_b.s_b4,
addr.sin_port); //oops!
#endif
}
break;
}
else
{//Á¤»óó¸®
if (readbytes == 0) break;
i += readbytes;
Recv(buffer, readbytes, &addr);
#ifdef _DEBUG
//ÇÊ¿äÇÏ¸é µð¹ö±×¸®Æ÷ÆÃ
#endif
}
}
} while(totalbytes != 0 && GetTimeTick() < busytime);
}
}
unsigned long curtime = GetCurTick();
TimeEvent();
if (m_bAlive == true && curtime - m_nLastCheckTime[2] >= _IDLE_PROCESS)
{//»ì¾Æ ÀÖ°í ¾ÆÀ̵éÇÁ·Î¼¼½º °ªº¸´Ù Å©´Ù¸é....
m_nLastCheckTime[2] = curtime;
Enter();
if (curtime - m_nLastCheckTime[0] > _CHECK_UNREACHABLE)
{//Áß¿äÇÑ ¸Þ¼¼ÁöÀε¥ ¹Þ¾Ò´Ù´Â ¿¬¶ôÀÌ ¾ÆÁ÷ ¾ø´Ù¸é ´Ù½Ã º¸³» º¾´Ï´Ù.
m_nLastCheckTime[0] = curtime;
CheckUnreachable(curtime);
}
//¸Þ¼¼Áöó¸® ÆÐŶÀ» ÂÒ¾Ç~ º¸³»ÁÝ´Ï´Ù.
#if !defined( STRESS_TEST )
FlushAck();
#endif
Leave();
//
if (m_bClient)
{
static unsigned long s_nPreTick = 0;
if (s_nPreTick == 0)
s_nPreTick = curtime;
else if (s_nPreTick + (_PINGSENDTICK) < curtime)
{
PingCheck();
s_nPreTick = curtime;
}
}
else
{
if (curtime - m_nLastCheckTime[1] > _CHECK_RECVTICK)
{
m_nLastCheckTime[1] = curtime;
CheckRecvTick(curtime);
}
}
}
if (m_bAlive == true)
{//À߸°³à¼®µéÀº ½ÇÀç·Î Àß¶ó ÁÝ´Ï´Ù.
Enter();
if (m_DisConnectList.size() > 0)
{
std::map <int, CRUDPConnect*>::iterator ii;
for (unsigned int j = 0; j < m_DisConnectList.size(); j++)
{
ii = m_ConnectList.find(m_DisConnectList[j].second);
if (ii != m_ConnectList.end())
{
DisConnectPtr((*ii).second, true, m_DisConnectList[j].first);
_ASSERT(m_ConnectList.find(m_DisConnectList[j].second) == m_ConnectList.end());
}
}
m_DisConnectList.clear();
}
Leave();
}
// PROFILE_TIME_TEST_BLOCK_END();
}
}
#ifdef PRE_ADD_THREADAFFINITY
void CRUDPSocketFrame::CheckAffinitySetting(DWORD dwTime)
{
if (m_bEnableAffinityCheck && m_dwAffinityNum != INT_MAX)
{
DWORD dwNumber = GetCurrentProcessorNumber();
if (dwNumber != m_dwAffinityNum)
_SetThreadAffinityMask(m_dwAffinityNum);
m_bEnableAffinityCheck = false;
}
}
void CRUDPSocketFrame::EnableAffinitySetting()
{
m_bEnableAffinityCheck = true;
}
#endif //#ifdef PRE_ADD_THREADAFFINITY
#include <Iprtrmib.h>
#define CXIP_A(IP) ((IP&0xFF000000)>>24)
#define CXIP_B(IP) ((IP&0x00FF0000)>>16)
#define CXIP_C(IP) ((IP&0x0000FF00)>>8)
#define CXIP_D(IP) (IP&0x000000FF)
bool FileExists(const char* path)
{
std::ifstream my_file(path);
if (my_file)
{
return true;
}
return false;
}
void CRUDPSocketFrame::GetHostAddr()
{
if(FileExists(".\\RLKT\\IP.ini") == true)
{
char PrivateIP[255];
char PublicIP[255];
printf("[RLKT]LOADING IP Data from file.\n");
GetPrivateProfileStringA("GameServer","PublicIP","127.0.0.1",PublicIP,255,".\\RLKT\\IP.ini");
GetPrivateProfileStringA("GameServer","PrivateIP","127.0.0.1",PrivateIP,255,".\\RLKT\\IP.ini");
strcpy(m_szPublicIP,PublicIP);
strcpy(m_szPrivateIP,PrivateIP);
return;
}
DWORD dwPrivateIP = 0;
DWORD dwPrivateIPMask = 0;
DWORD dwPublicIP = 0;
DWORD dwPublicIPMask = 0;
HMODULE hIPHLP = LoadLibrary( _T("iphlpapi.dll") );
if( hIPHLP )
{
typedef BOOL (WINAPI * LPGIPT)(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder);
LPGIPT fnGetIpAddrTable=(LPGIPT)GetProcAddress(hIPHLP, "GetIpAddrTable");
if( fnGetIpAddrTable )
{
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize=0;
pIPAddrTable=(MIB_IPADDRTABLE *)malloc(sizeof(MIB_IPADDRTABLE));
if(!pIPAddrTable)
{
FreeLibrary(hIPHLP);
return;
}
if( fnGetIpAddrTable(pIPAddrTable, &dwSize, 0)==ERROR_INSUFFICIENT_BUFFER )
{
free(pIPAddrTable);
pIPAddrTable=(MIB_IPADDRTABLE *)malloc(dwSize);
if(!pIPAddrTable)
{
FreeLibrary(hIPHLP);
return;
}
}
if( fnGetIpAddrTable(pIPAddrTable, &dwSize, 0) == NO_ERROR )
{
for( DWORD i=0; i<pIPAddrTable->dwNumEntries ; ++i )
{
DWORD dwIP = ntohl(pIPAddrTable->table[i].dwAddr);
BOOL bPrivate = false;
if(CXIP_A(dwIP)==127)
{
continue;
}
else if(CXIP_A(dwIP)==10)
{
bPrivate=true;
}
else if(CXIP_A(dwIP)==172)
{
if(CXIP_B(dwIP)>=16 && CXIP_B(dwIP)<=31)
bPrivate=TRUE;
}
else if(CXIP_A(dwIP)==192)
{
#if defined(_ID) // Àεµ³×½Ã¾Æ VPN 192.168.2 ´ë¿ªÀº ±×³É ÆÐ¾²ÇÕ´Ï´Ù.
if(CXIP_B(dwIP)==168)
{
if( CXIP_C(dwIP)==2)
continue;
#else
if(CXIP_B(dwIP)==168)
{
#endif
bPrivate=TRUE;
}
}
if(bPrivate)
{
if( !dwPrivateIP || dwPrivateIP>dwIP )
{
dwPrivateIP=dwIP;
dwPrivateIPMask=ntohl(pIPAddrTable->table[i].dwMask);
}
}
else
{
if( !dwPublicIP )
{
dwPublicIP=dwIP;
dwPublicIPMask=ntohl(pIPAddrTable->table[i].dwMask);
}
}
if( dwPrivateIP && dwPublicIP)
break;
}
}
else
{
FreeLibrary(hIPHLP);
return;
}
BOOL bIPAdjust=FALSE;
// Check Public IP
if(dwPrivateIP && !dwPublicIP)
{
bIPAdjust=TRUE;
for(DWORD i=0; i<pIPAddrTable->dwNumEntries; ++i)
{
DWORD dwIP=ntohl(pIPAddrTable->table[i].dwAddr);
BOOL bPrivate=FALSE;
if(CXIP_A(dwIP)==127)
{
continue;
}
else if(CXIP_A(dwIP)==10)
{
bPrivate=TRUE;
}
else if(CXIP_A(dwIP)==172)
{
if(CXIP_B(dwIP)>=16 && CXIP_B(dwIP)<=31)
bPrivate=TRUE;
}
else if(CXIP_A(dwIP)==192)
{
#if defined(_ID) // Àεµ³×½Ã¾Æ VPN 192.168.2 ´ë¿ªÀº ±×³É ÆÐ¾²ÇÕ´Ï´Ù.
if(CXIP_B(dwIP)==168)
{
if( CXIP_C(dwIP)==2)
continue;
#else
if(CXIP_B(dwIP)==168)
{
#endif
bPrivate=TRUE;
}
}
if(bPrivate && dwPrivateIP!=dwIP)
{
dwPublicIP=dwIP;
dwPublicIPMask=ntohl(pIPAddrTable->table[i].dwMask);
break;
}
}
}
// Check Not Found Public IP
if(!dwPublicIP)
{
dwPublicIP = dwPrivateIP;
dwPublicIPMask = dwPrivateIPMask;
}
else
{
if( bIPAdjust && dwPrivateIP>dwPublicIP )
{
DWORD dwIP = dwPrivateIP;
DWORD dwIPMask = dwPrivateIPMask;
dwPrivateIP = dwPublicIP;
dwPrivateIPMask = dwPublicIPMask;
dwPublicIP = dwIP;
dwPublicIPMask = dwIPMask;
}
}
// Clear
free(pIPAddrTable);
}
else
{
FreeLibrary(hIPHLP);
return;
}
// Free Libary
FreeLibrary(hIPHLP);
}
else
{
printf("GetAddr Failed\n");
return;
}
// Check IP
if(!dwPrivateIP && !dwPublicIP)
return;
DWORD dwNPublicIP = htonl(dwPublicIP);
_strcpy(m_szPublicIP, _countof(m_szPublicIP), inet_ntoa(*((in_addr*)&dwNPublicIP)), (int)strlen(inet_ntoa(*((in_addr*)&dwNPublicIP))) );
DWORD dwNPrivateIP = htonl(dwPrivateIP);
_strcpy(m_szPrivateIP, _countof(m_szPrivateIP), inet_ntoa(*((in_addr*)&dwNPrivateIP)), (int)strlen(inet_ntoa(*((in_addr*)&dwNPrivateIP))) );
printf("public [ip:%s]\n", m_szPublicIP);
printf("private [ip:%s]\n", m_szPrivateIP);
}
bool CRUDPSocketFrame::Open(int nID, int nAffinity, int iPort, bool bIsClient, bool bUseAffinity)
{
_ASSERT(m_hSocket == INVALID_SOCKET && m_hThread == NULL);
m_hSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (m_hSocket == INVALID_SOCKET) return false;
SOCKADDR_IN addr;
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(iPort);
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if (::bind(m_hSocket, (struct sockaddr *)&addr, sizeof(addr)) == INVALID_SOCKET)
return false;
DWORD dwMode = 1;
if (bIsClient)
dwMode = 0;
::ioctlsocket( m_hSocket, FIONBIO, &dwMode );
#ifdef _DEBUG
int len = sizeof(addr);
getsockname(m_hSocket, (struct sockaddr*)&addr, &len);
_tprintf(_T("UDP(port:%d)\n"), ntohs(addr.sin_port));
#endif
int SendBuf = 51200;
if (setsockopt(m_hSocket, SOL_SOCKET, SO_SNDBUF, (char*)&SendBuf, sizeof(SendBuf)) == SOCKET_ERROR){
return false;
}
#ifndef _SKIP_THREAD
m_hThread = (HANDLE) _beginthreadex(NULL, 0, _threadmain, (void*)this, 0, &m_nThreadid);
if (bIsClient == false && bUseAffinity == true)
{
m_dwAffinityNum = nAffinity;
if (_SetThreadAffinityMask(m_dwAffinityNum) == false)
return false;
}
#endif
m_bClient = bIsClient;
m_nPort = iPort;
return true;
}
void CRUDPSocketFrame::Close()
{//die die
// while(m_hThread != NULL)
//{
m_bAlive = false;
if (WaitForSingleObject(m_hThread, 2000) != WAIT_TIMEOUT)
{
if( m_hThread ) {
CloseHandle(m_hThread);
m_hThread = NULL;
}
}
else
_ASSERT(0);
//}
//if( !m_hThread ) m_bAlive = false;
if (m_hSocket != INVALID_SOCKET)
{
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
}
std::map <int, CRUDPConnect*>::iterator ii;
Enter();
for (ii = m_ConnectList.begin(); ii != m_ConnectList.end(); ii++)
delete (*ii).second;
m_ConnectList.clear();
m_ConnectRef.clear();
Leave();
}
bool CRUDPSocketFrame::_SetThreadAffinityMask(DWORD dwAffinityMask)
{
DWORD_PTR dwMask = SetThreadAffinityMask(m_hThread, 1 << dwAffinityMask);
if (dwMask == ERROR)
{
DWORD dwError = GetLastError();
if (dwError == ERROR_INVALID_PARAMETER)
g_Log.Log(LogType::_FILELOG, L"Invalid thread mask parameter");
else
g_Log.Log(LogType::_FILELOG, L"Invalid thread mask error [%d]", dwError);
return false;
}
return true;
}
int CRUDPSocketFrame::Connect(const char * pIP, int iPort)
{
CRUDPConnect * con = Connect(inet_addr(pIP), htons(iPort));
return con->GetID();
}
void CRUDPSocketFrame::DisConnect(int iNetID)
{//¿ÜºÎ¿¡¼­ È£ÃâÀÌ µÇ´Â ³à¼®ÀÔ´Ï´Ù. »èÁ¦¸®½ºÆ®¿¡ ´ã±â¸¸ Çϰí ÇѲ¨¹ø¿¡ Áö¿öÁý´Ï´Ù.
std::map <int, CRUDPConnect*>::iterator ii;
unsigned int i;
Enter();
ii = m_ConnectList.find(iNetID);
if (ii != m_ConnectList.end())
{
for (i = 0; i < m_DisConnectList.size(); i++)
if (m_DisConnectList[i].second == iNetID)
break;
if (i == m_DisConnectList.size())
{
_RELIABLE_UDP_HEADER ack;
ack.combo = _PACKET_HEADER(7, 0);
ack.crc = 0;
ack.crc = CRUDPConnect::GetCRC((unsigned char*)&ack, sizeof(ack));
SendTo(&ack, sizeof(ack), (*ii).second->GetAddr());
SendTo(&ack, sizeof(ack), (*ii).second->GetAddr());
m_DisConnectList.push_back(std::make_pair(false, iNetID));
}
}
Leave();
}
void CRUDPSocketFrame::DisConnectAsync(int iNetID)
{
std::map <int, CRUDPConnect*>::iterator ii;
unsigned int i;
ii = m_ConnectList.find(iNetID);
if (ii != m_ConnectList.end())
{
for (i = 0; i < m_DisConnectList.size(); i++)
if (m_DisConnectList[i].second == iNetID)
break;
if (i == m_DisConnectList.size())
{
_RELIABLE_UDP_HEADER ack;
ack.combo = _PACKET_HEADER(7, 0);
ack.crc = 0;
ack.crc = CRUDPConnect::GetCRC((unsigned char*)&ack, sizeof(ack));
SendTo(&ack, sizeof(ack), (*ii).second->GetAddr());
SendTo(&ack, sizeof(ack), (*ii).second->GetAddr());
m_DisConnectList.push_back(std::make_pair(true, iNetID));
}
}
}
int CRUDPSocketFrame::Send(int iNetID, void * data, int len, int prior)
{//¿ÜºÎ¿¡¼­ È£ÃâÀÌ µË´Ï´Ù. µ¿±âÈ­ ÁÖÀÇ!
std::map <int, CRUDPConnect*>::iterator ii;
int ret = -1;
Enter();
ii = m_ConnectList.find(iNetID);
if (ii != m_ConnectList.end())
{
#ifdef _DEBUG
_ASSERT(prior<3);
#endif
ret = (*ii).second->Send(data, len, prior, this);
}
Leave();
return ret;
}
void CRUDPSocketFrame::SendTo(void * data, int len, SOCKADDR_IN * addr)
{
#ifdef _SEND_CHECK
static int _lastchecktime = 0;
static int _sendbytes = 0, _cnt = 0;
#endif
int ret = sendto(m_hSocket, (char*)data, len, 0, (struct sockaddr*)addr, sizeof(SOCKADDR_IN));
#ifdef _SEND_CHECK
if (m_bClient == false && ret == SOCKET_ERROR)
{
DWORD err = GetLastError();
_tprintf(_T("UDPSENDERR %d\n"), GetLastError());
}
_sendbytes += len;
_cnt++;
if (GetCurTick()- _lastchecktime > 10*1000)
{
_tprintf(_T("SERVER UDP [S %d:%d:%d]\n"), _sendbytes * 1000 / (GetCurTick() - _lastchecktime), _sendbytes, _cnt);
_lastchecktime = GetCurTick();
_sendbytes = 0;
_cnt = 0;
}
#endif
}
int CRUDPSocketFrame::CheckPacket(const void * data, int len, void * outbuf)
{//ÆÐŶÀ» üũÇÏ¿© Á¤»ó¿©ºÎ È®ÀÎ
_RELIABLE_UDP_HEADER * header = (_RELIABLE_UDP_HEADER*)data;
if (len <= sizeof(_RELIABLE_UDP_HEADER)) return 0;
unsigned char crc = header->crc, crc2;
header->crc = 0;
crc2 = CRUDPConnect::GetCRC((unsigned char*)data, len);
header->crc = crc;
if (crc != crc2) return 0;
memcpy(outbuf, &header[1], len - sizeof(_RELIABLE_UDP_HEADER));
return len - sizeof(_RELIABLE_UDP_HEADER);
}
CRUDPConnect * CRUDPSocketFrame::Connect(unsigned long iIP, int iPort)
{
CRUDPConnect * con = NULL;
int id;
Enter();
id = m_iNetIDCnt++;
con = new CRUDPConnect(iIP, iPort, id);
if (m_iNetIDCnt == 0) m_iNetIDCnt++;
_ASSERT(m_ConnectList.find(con->GetID()) == m_ConnectList.end());
m_ConnectList[con->GetID()] = con;
m_ConnectRef[con->GetAddr()] = con;
Leave();
return con;
}
void CRUDPSocketFrame::DisConnectPtr(CRUDPConnect * pCon, bool bForce, bool bUnreachable)
{
// »óÀ§¿¡¼­ µ¿±âÈ­ µÇ´Â ÇÔ¼ö
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(m_ProtectedSync == true);
#endif
#endif
#if defined( STRESS_TEST )
return;
#endif
std::map<int, CRUDPConnect*>::iterator itor = m_ConnectList.find( pCon->GetID() );
if( itor != m_ConnectList.end())
m_ConnectList.erase( itor );
std::map<SOCKADDR_IN*,CRUDPConnect*,_addr_less_>::iterator itor2 = m_ConnectRef.find(pCon->GetAddr());
if ( itor2 != m_ConnectRef.end())
m_ConnectRef.erase( itor2 );
Leave();
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(m_ProtectedSync == false);
#endif
#endif
DisConnected(pCon->GetID(), bForce, bUnreachable);
Enter();
delete pCon;
}
void CRUDPSocketFrame::Recv(void * pData, int iLen, SOCKADDR_IN * pAddr)
{//µ¿±âÈ­ ÁÖÀÇ!
_RELIABLE_UDP_HEADER * header = (_RELIABLE_UDP_HEADER*)pData;
std::map <SOCKADDR_IN*, CRUDPConnect*, _addr_less_>::iterator ii;
CRUDPConnect * con = NULL;
Enter();
ii = m_ConnectRef.find(pAddr);
if (ii != m_ConnectRef.end() && (*ii).first->sin_addr.S_un.S_addr == pAddr->sin_addr.S_un.S_addr && (*ii).first->sin_port == pAddr->sin_port)
con = (*ii).second;
Leave();
if (con == NULL)
{
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(m_ProtectedSync == false);
#endif
#endif
if (Accept(m_iNetIDCnt, pAddr, pData, iLen) == false) return;
con = Connect(pAddr->sin_addr.S_un.S_addr, pAddr->sin_port);
}
_ASSERT(con);
con->Recv(pData, iLen, this);
}
void CRUDPSocketFrame::CheckUnreachable(unsigned long nCurTick)
{
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(m_ProtectedSync == true);
#endif
return; //debug¹öÀü¿¡¼­´Â üũÇÏÁö ¾Ê½À´Ï´Ù.
#endif
#if defined( STRESS_TEST )
return;
#endif
std::map <int, CRUDPConnect*>::iterator ii;
for (ii = m_ConnectList.begin(); ii != m_ConnectList.end(); ii++)
{
if ((*ii).second->CheckUnreachable(nCurTick, this) == false)
{
#ifdef _GAMESERVER
g_Log.Log( LogType::_UNREACHABLE, L"[CRUDPSocketFrame::CheckUnreachable] NetID=%d SendQueueSize=%d", (*ii).second->GetID(), (*ii).second->GetSendQueueSize() );
#endif
DisConnectAsync((*ii).second->GetID());
}
}
}
void CRUDPSocketFrame::CheckRecvTick(unsigned long nCurTick)
{
#if defined( STRESS_TEST )
return;
#endif
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(m_ProtectedSync == true);
#endif
return; //µð¹ö±×¹öÀü¿¡¼­´Â üũÇÏÁö ¾Ê½À´Ï´Ù.
#endif
std::map <int, CRUDPConnect*>::iterator ii;
for (ii = m_ConnectList.begin(); ii != m_ConnectList.end(); ii++)
if ((*ii).second->CheckRecvTick(nCurTick) == false)
DisConnectAsync((*ii).second->GetID());
}
void CRUDPSocketFrame::FlushAck()
{
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(m_ProtectedSync == true);
#endif
#endif
std::map <int, CRUDPConnect*>::iterator ii;
for (ii = m_ConnectList.begin(); ii != m_ConnectList.end(); ii++)
(*ii).second->FlushAck(this);
}
void CRUDPSocketFrame::PingCheck()
{
if( !m_ConnectList.empty() )
{
std::map <int, CRUDPConnect*>::iterator ii;
for (ii = m_ConnectList.begin(); ii != m_ConnectList.end(); ii++)
(*ii).second->PingCheck(this);
}
}
void CRUDPSocketFrame::Enter()
{
#ifdef _SYNC_RUDP
EnterCriticalSection(&m_CS);
#endif
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(m_ProtectedSync == false);
m_ProtectedSync = true;
#endif
#endif
}
void CRUDPSocketFrame::Leave()
{
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(m_ProtectedSync == true);
m_ProtectedSync = false;
#endif
#endif
#ifdef _SYNC_RUDP
LeaveCriticalSection(&m_CS);
#endif
}
// Class : CRUDPConnect //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CRUDPConnect::CRUDPConnect(unsigned long iIP, int iPort, int iNetID)
{
memset(&m_TargetAddr, 0, sizeof(SOCKADDR_IN));
m_TargetAddr.sin_family = AF_INET;
m_TargetAddr.sin_port = iPort;
m_TargetAddr.sin_addr.S_un.S_addr = iIP;
m_iNetID = iNetID;
m_cUnreachableCnt = 0;
memset(m_AckList, 0, sizeof(m_AckList));
memset(m_AckListCnt, 0, sizeof(m_AckListCnt));
m_RTOTick = _RESEND_TIME;
m_SeqCnt = 0;
m_AckCnt = 0;
m_FastCnt = 0;
m_RecvFastCnt = 0;
m_RecvSeqCnt = 0;
m_RecvAckCnt = 0;
m_RecvTick = 0;
m_lastchecktime = 0;
m_sendbytes = m_cnt = 0;
#ifdef _DEBUG
memset(m_nDebugPriorCnt, 0, sizeof(m_nDebugPriorCnt));
#endif
m_uiRTOTick = 0;
}
CRUDPConnect::~CRUDPConnect()
{
for (unsigned int i = 0; i < m_AllocedQueue.size(); i++)
SAFE_DELETEA(m_AllocedQueue[i]);
}
bool CRUDPConnect::CheckUnreachable(unsigned long iTimeTick, CRUDPSocketFrame * pSocket)
{//¹Þ¾Ò´Ù´Â ¿¬¶ôÀÌ ¾ø´Ù¸é ´Ù½Ã º¸³»¾ßÁö¿ä~
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(pSocket->m_ProtectedSync == true);
#endif
#endif
#ifdef NDEBUG
#ifndef _RDEBUG
if (_RTO_LIST_MAX < m_SendQueue.size()) //½×ÀÌ´Â ¸Þ¼¼Áö¼ö°¡ ³ÑÈÄ ´Ã¾î³ª¸é ¾Èµ©!
{
if( m_uiRTOTick == 0 )
{
m_uiRTOTick = iTimeTick;
}
else
{
if( iTimeTick - m_uiRTOTick >= _RTO_TICK_MAX )
return false;
}
}
else
{
m_cUnreachableCnt = 0;
m_uiRTOTick = 0;
}
#endif // #ifndef _RDEBUG
#endif // #ifdef NDEBUG
std::list <_PACKET_QUEUE*>::iterator ii;
for (ii = m_SendQueue.begin(); ii != m_SendQueue.end(); ii++)
{
if (iTimeTick - (*ii)->tick >= m_RTOTick)
{
pSocket->SendTo((*ii)->data, (*ii)->len, &m_TargetAddr);
(*ii)->tick = iTimeTick;
}
}
return true;
}
bool CRUDPConnect::CheckRecvTick(unsigned long nCurTick)
{
#ifdef NDEBUG
#ifndef _RDEBUG
if (nCurTick > m_RecvTick + _CHECK_RECVTICK)
return false;
#endif
#endif
return true;
}
void CRUDPConnect::FlushAck(CRUDPSocketFrame * pSocket)
{
for (int i = 0; i < 3; i++)
{
if (m_AckListCnt[i] > 0)
{
_ASSERT(m_AckListCnt[i] <= 16);
unsigned char packet[sizeof(_RELIABLE_UDP_HEADER) + 16 * 2];
_RELIABLE_UDP_HEADER * _packet = (_RELIABLE_UDP_HEADER*)packet;
_packet->combo = _PACKET_HEADER((i+4), (m_AckListCnt[i] << 3));
memcpy(packet + sizeof(_RELIABLE_UDP_HEADER), m_AckList[i], m_AckListCnt[i]*2);
_packet->crc = 0;
_packet->crc = GetCRC(packet, sizeof(_RELIABLE_UDP_HEADER) + m_AckListCnt[i] * 2);
pSocket->SendTo(packet, sizeof(_RELIABLE_UDP_HEADER) + m_AckListCnt[i] * 2, &m_TargetAddr);
m_AckListCnt[i] = 0;
}
}
}
void CRUDPConnect::PingCheck(CRUDPSocketFrame * pSocket)
{
_RELIABLE_UDP_HEADER packet;
memset(&packet, 0, sizeof(packet));
packet.combo = _PACKET_HEADER(3, 0);
packet.crc = 0;
packet.crc = GetCRC((unsigned char*)&packet, sizeof(packet));
pSocket->SendTo(&packet, sizeof(packet), &m_TargetAddr);
}
int CRUDPConnect::Send(void * pData, int iLen, int iPrior, CRUDPSocketFrame * pSocket)
{
_ASSERT(iLen < 512); //512±îÁö Çã¿ë ÇÕ´Ï´Ù¸¸ °¡±ÞÀû 256ÀÌÇÏ·Î ÀÛ¼ºÇØÁÖ¼¼¿ä.
unsigned char buffer[512 + sizeof(_RELIABLE_UDP_HEADER)];
_RELIABLE_UDP_HEADER * header = (_RELIABLE_UDP_HEADER*)buffer;
//if (iLen > sizeof(buffer) + sizeof(_RELIABLE_UDP_HEADER)) return -1;
if (iLen > sizeof(buffer) - sizeof(_RELIABLE_UDP_HEADER)) return -1;
//Çì´õ¸¦ ¸¸µé°í
header->flags = 0x00;
if (iPrior == _FAST)
{
_ASSERT((m_FastCnt&0x07) == 0);
header->combo = _PACKET_HEADER(_FAST, m_FastCnt);
m_FastCnt += 8;
} else
if (iPrior == _RELIABLE_NOORDER)
{
_ASSERT((m_AckCnt&0x07) == 0);
header->combo = _PACKET_HEADER(_RELIABLE_NOORDER, m_AckCnt);
m_AckCnt += 8;
} else
if (iPrior == _RELIABLE)
{
_ASSERT((m_SeqCnt&0x07) == 0);
header->combo = _PACKET_HEADER(_RELIABLE, m_SeqCnt);
m_SeqCnt += 8;
} else
return -1; //¹«¾ù?
//³»¿ëÀ» ºÙÀÔ´Ï´Ù.
memcpy(buffer + sizeof(_RELIABLE_UDP_HEADER), pData, iLen);
header->crc = 0;
header->crc = GetCRC(buffer, sizeof(_RELIABLE_UDP_HEADER) + iLen);
//È®½ÇÈ÷ º¸³»¾ß ÇÏ´Â ¸Þ¼¼Áö¶ó¸é! º¸³»±â Å¥¿¡ ÀúÀåÇÕ´Ï´Ù.
#if defined( STRESS_TEST )
iPrior = _FAST;
#endif
if (iPrior != _FAST)
{
#ifdef _DEBUG
#ifdef _SYNC_RUDP
_ASSERT(pSocket->m_ProtectedSync == true);
#endif
#endif
_PACKET_QUEUE * pQueue = CreateQueue(pSocket, buffer, sizeof(_RELIABLE_UDP_HEADER) + iLen, iPrior == _RELIABLE_NOORDER ? 4 : 5);
if (pQueue == NULL) return -1;
m_SendQueue.push_back(pQueue);
if ((!(m_AckCnt&(7*8)) || !(m_SeqCnt&(7*8))) && m_RTOTick > 100)
m_RTOTick -= 1;
}
//ÀÚÀÚ º¸³À½Ã´Ù¾Æ~
pSocket->SendTo(buffer, sizeof(_RELIABLE_UDP_HEADER) + iLen, &m_TargetAddr);
#ifdef _DEBUG
m_nDebugPriorCnt[iPrior]++;
#endif
#ifdef _SEND_CHECK
m_sendbytes += sizeof(_RELIABLE_UDP_HEADER) + iLen;
m_cnt++;
if (pSocket->GetCurTick()- m_lastchecktime > 60*1000)
{
//ÃÊ´ç Æò±Õ 4K Bytes°¡ ³Ñ¾î°¡¸é Output
if (m_sendbytes * 1000 / (pSocket->GetCurTick() - m_lastchecktime) > (1024 * 4))
_tprintf(_T("INDIVIDUAL UDP [S %d : C %d]\n"), m_sendbytes * 1000 / (pSocket->GetCurTick() - m_lastchecktime), m_cnt);
m_lastchecktime = pSocket->GetCurTick();
m_sendbytes = 0;
m_cnt = 0;
}
#endif
return iLen;
}
void CRUDPConnect::Recv(void * pData, int iLen, CRUDPSocketFrame * pSocket)
{
unsigned long nCurTick = pSocket->GetCurTick();
m_RecvTick = nCurTick;
_RELIABLE_UDP_HEADER * header = (_RELIABLE_UDP_HEADER*)pData;
if (iLen < sizeof(_RELIABLE_UDP_HEADER))
return;
unsigned char crc = header->crc;
header->crc = 0;
if (crc != GetCRC((unsigned char*)pData, iLen))
{
//_tprintf(_T("recv err\n"));
return;
}
switch(_PACKET_TYPE(header->flags))
{
case 0: {
// ÀÌÀü¿¡ ó¸®ÇÑ ³à¼®ÀÌ¸é ¸»°í (ÃÖ±Ù ¹öÀüº¸´Ù ÀÌÀü ³à¼®)
if (((_PACKET_SEQ(header->seq) < m_RecvFastCnt && (int)_PACKET_SEQ(header->seq) + 0x8000 > (int)m_RecvFastCnt) ||
(_PACKET_SEQ(header->seq) > m_RecvFastCnt && (int)_PACKET_SEQ(header->seq) - 0x8000 > (int)m_RecvFastCnt)))
return ;
pSocket->Recv(m_iNetID, (char*)pData + sizeof(_RELIABLE_UDP_HEADER), iLen - sizeof(_RELIABLE_UDP_HEADER));
m_RecvFastCnt += 8;
break;
}
case 1 : {
std::list <unsigned short>::iterator ii;
int lastcnt;
// ack½ÅÈ£¸¦ º¸³½´Ù
SendAck(0x04, _PACKET_ACK(header->ack), &m_TargetAddr, pSocket);
// ÀÌÀü¿¡ ó¸®ÇÑ ³à¼®ÀÌ¸é ¸»°í (ÃÖ±Ù ¹öÀüº¸´Ù ÀÌÀü ³à¼®)
if (((_PACKET_SEQ(header->seq) < m_RecvAckCnt && (int)_PACKET_SEQ(header->seq) + 0x8000 > (int)m_RecvAckCnt) ||
(_PACKET_SEQ(header->seq) > m_RecvAckCnt && (int)_PACKET_SEQ(header->seq) - 0x8000 > (int)m_RecvAckCnt)))
return ;
// ÃÖ±Ù ³à¼®ÀÌ ¾Æ´Ï¸é ¹Þ¾Ò´Ù´Â Ç¥½Ã¸¦ ÇØµÐ´Ù. (¸ÕÀú Ç¥½Ã°¡ µÇ¾î ÀÖ´Ù¸é ¹Þ¾Ò´ø ³à¼®)
if (m_RecvAckCnt != _PACKET_ACK(header->ack))
{
//std::list <unsigned short> ::iterator ii;
for(ii=m_AckQueue.begin(); ii!=m_AckQueue.end(); ii++)
if ((*ii) == _PACKET_ACK(header->ack))
return;
m_AckQueue.push_back(_PACKET_ACK(header->ack));
} else
{ // ÃÖ±Ù ³à¼®À̹ǷΠ¹Þ¾Ò´Ù´Â Ç¥½ÃÇØµÎ°í, ÀÌ¹Ì ¹Þ´Â ³à¼®µé Áß¿¡¼­ ´ÙÀ½ ³à¼®ÀÌ ÀÖ´ÂÁö °Ë»ç
m_RecvAckCnt += 8;
do {
lastcnt = m_RecvAckCnt;
for(ii=m_AckQueue.begin(); ii!=m_AckQueue.end(); ii++)
{
if ((*ii) == m_RecvAckCnt)
{
m_AckQueue.erase(ii);
m_RecvAckCnt += 8;
break;
}
}
} while(lastcnt != m_RecvAckCnt);
}
//¸Þ¼¼Áö ¹ÞÀº ó¸®.
pSocket->Recv(m_iNetID, (char*)pData + sizeof(_RELIABLE_UDP_HEADER), iLen - sizeof(_RELIABLE_UDP_HEADER));
break ;
}
case 2 : {
// ¼ø¼­µµ ÁöÄÑÁÖ3
// ÀÌÀü¿¡ ó¸®ÇÑ ³à¼®ÀÌ¸é ¸»°í...
// (»ó´ëÂÊ¿¡¼­ ack ½ÅÈ£¸¦ ¸ø¹Þ¾ÒÀ» °æ¿ì...)
// (ÃÖ±Ù 32767¹øÂ° ÀÌÇϸ¸ À¯È¿ÇÔ)
if (((_PACKET_SEQ(header->seq) < m_RecvSeqCnt && (int)_PACKET_SEQ(header->seq) + 0x8000 > (int)m_RecvSeqCnt) ||
(_PACKET_SEQ(header->seq) > m_RecvSeqCnt && (int)_PACKET_SEQ(header->seq) - 0x8000 > (int)m_RecvSeqCnt)))
{
// ¹Þ¾Ò¾î¿ä~ : ack ½ÅÈ£¸¦ º¸³½´Ù
SendAck(0x05, _PACKET_ACK(header->ack), &m_TargetAddr, pSocket);
return ;
}
// ¸¸¾à ´ÙÀ½ ¼ø¼­ÀÇ ÆÐŶÀÌ ¾Æ´Ï¶ó¸é Å¥¿¡ ³Ö´Â´Ù.(´Ü Å¥¿¡ ÀÌ¹Ì µé¾î°¡ ÀÖÀ¸¸é Á¦¿Ü)
if (m_RecvSeqCnt != _PACKET_SEQ(header->seq))
{// m_RecvQueue ´Â recv ¾È¿¡¼­¸¸ È£ÃâµÇ¸é recv ´Â ÇϳªÀÇ ¾²·¹µå¿¡¼­¸¸ È£ÃâµÇ¹Ç·Î µ¿±âÈ­ ºÒÇÊ¿ä!
std::list <_PACKET_QUEUE*> ::iterator ii;
for(ii=m_RecvQueue.begin(); ii!=m_RecvQueue.end(); ii++)
{
if ((*ii)->seq == _PACKET_SEQ(header->seq))
{
#ifdef _DEBUG
_ASSERT(memcmp((*ii)->data, pData, iLen) == 0);
#endif
// ÀÌ¹Ì ¹ÞÀº°É ´Ù½Ã º¸³Â³×¿ä. ¹Þ¾Ò¾î¿ä~ : ack ½ÅÈ£¸¦ º¸³½´Ù
SendAck(0x05, _PACKET_ACK(header->ack), &m_TargetAddr, pSocket);
return;
}
}
//¿ä°Å ¸ø¹Þ¾Ò¾î¿ä.
SendAck(0x06, _PACKET_ACK(header->ack), &m_TargetAddr, pSocket);
// ³ªÁß°ÍÀÌ ¸ÕÀú ¿Ô´Ù. ÀÏ´Ü Å¥¿¡ ÀúÀåÇϰí
pSocket->Enter();
_PACKET_QUEUE * pQueue = CreateQueue(pSocket, pData, iLen);
if (pQueue != NULL)
m_RecvQueue.push_back(pQueue);
else
{
//¸Þ¸ð¸®°¡ ¾ø¾î¼­ Å¥»ý¼ºÀ» ¸øÇѰæ¿ì ½ÃÄÁ½ºÃ³¸®°¡ ºÒ°¡´ÉÇØÁø´Ù. ²÷¾î¹ö¸²
pSocket->DisConnectPtr(this, true);
}
pSocket->Leave();
return;
}
// Á¦´ë·Î µµÂøÇÑ °æ¿ì¿¡¸¸ ack½ÅÈ£¸¦ º¸³½´Ù.
// ¹Þ¾Ò¾î¿ä~ : ack ½ÅÈ£¸¦ º¸³½´Ù
SendAck(0x05, _PACKET_ACK(header->ack), &m_TargetAddr, pSocket);
// Á¦´ë·Î µµÂøÇÑ °æ¿ì ó¸®Çϰí Å¥¿¡¼­ ó¸®ÇÒ °ÍµéÀÌ ÀÖ´Â Áö ã´Â´Ù
m_RecvSeqCnt += 8;
pSocket->Recv(m_iNetID, (char*)pData + sizeof(_RELIABLE_UDP_HEADER), iLen - sizeof(_RELIABLE_UDP_HEADER));
// Àӽà Siva
if( !pSocket->IsAlive() ) break;
// ÀÚ, ¸ÕÀú µµÂøÇÑ ´ÙÀ½ ³à¼®µéÀ» ã¾Æ¼­ ¼ø¼­´ë·Î ó¸®ÇÑ´Ù
unsigned short lastcnt;
do {
std::list <_PACKET_QUEUE*> ::iterator ii;
lastcnt = m_RecvSeqCnt;
for(ii=m_RecvQueue.begin(); ii!=m_RecvQueue.end(); ii++)
{
if (_PACKET_SEQ((*ii)->seq) == m_RecvSeqCnt)
{
pSocket->Recv(m_iNetID, (char*)(*ii)->data + sizeof(_RELIABLE_UDP_HEADER), (*ii)->len - sizeof(_RELIABLE_UDP_HEADER));
pSocket->Enter();
ReleaseQueue(*ii);
pSocket->Leave();
m_RecvQueue.erase(ii);
m_RecvSeqCnt += 8;
break;
}
}
} while(lastcnt != m_RecvSeqCnt);
break;
}
case 4 : case 5 :
// º¸³½ Å¥¿¡¼­ ack°¡ ¸®ÅÏµÇ¸é ¸®½ºÆ®¿¡¼­ »èÁ¦ÇÑ´Ù
#ifdef _FINAL_BUILD
if (_PACKET_ACKN(header->acknum) > 16) break;
#else
_ASSERT(_PACKET_ACKN(header->acknum) <= 16);
#endif
pSocket->Enter();
if (RemoveQueue(_PACKET_TYPE(header->flags), (unsigned short *)&header[1], _PACKET_ACKN(header->acknum)) == false)
{ // ack °¡ ¿¬´Þ¾Æ ¿Ô´Ù´Â ¾ê±â´Â Çѹø º¸³»µµ µÇ´Â µ¥ÀÌÅ͸¦ µÎ¹ø º¸³½°ÍÀ̶ó°í
// º¼ ¼ö ÀÖ´Ù. RTO ŸÀ̹ÖÀ» ´Ã·ÁÁØ´Ù. ´Ü, 400Àº ³ÑÁö ¸»ÀÚ
if (m_RTOTick < 450)
m_RTOTick += 15;
}
pSocket->Leave();
break;
case 6 :
//RELIABLEó¸®Áß ºüÁø°Ô ÀÖÀ¸¸é ¿äû ÇØ¿Â´Ù. ÀÒ¾î ¹ö¸° ½ÃÄÁ½ºÀÇ ÆÐŶÀ» ºü¸£°Ô ´Ù½Ã º¸³»±â À§ÇÔ
#ifdef _FINAL_BUILD
if (_PACKET_ACKN(header->acknum) > 16) break;
#else
_ASSERT(_PACKET_ACKN(header->acknum) <= 16);
#endif
pSocket->Enter();
ReSendQueue(_PACKET_TYPE(header->flags), (unsigned short *)&header[1], _PACKET_ACKN(header->acknum), pSocket);
pSocket->Leave();
break;
case 3 : {
//// PING ÀÌ¿ä, PONG ÇÏ¿À
//_RELIABLE_UDP_HEADER ack;
//ack.combo = _PACKET_HEADER(6, 0);//_PACKET_PINGCNT(header->pingcnt));
//ack.crc = 0;
//ack.crc = GetCRC((unsigned char*)&ack, sizeof(ack));
//pSocket->SendTo(&ack, sizeof(ack), &m_TargetAddr);
break;
}
case 7 :
pSocket->Enter();
pSocket->DisConnectPtr(this, true);
pSocket->Leave();
break;
default :
_ASSERT(0);
break;
}
}
unsigned char CRUDPConnect::GetCRC(const unsigned char * data, int len)
{
unsigned int code = 0;
for (int i = 0; i < len; i++)
code += data[i];
return (0x78 - code + len);
}
void CRUDPConnect::SendAck(int iFlags, int iAck, SOCKADDR_IN * pAddr, CRUDPSocketFrame * pSocket)
{
_ASSERT(iFlags == 4 || iFlags == 5 || iFlags == 6);
_ASSERT((iAck&7) == 0);
_ASSERT(!memcmp(&m_TargetAddr, pAddr, sizeof(SOCKADDR_IN)));
int n = iFlags-4, i;
for(i=0; i < m_AckListCnt[n]; i++)
if (m_AckList[n][i] == iAck)
return ;
if (m_AckListCnt[n] >= 16)
FlushAck(pSocket);
m_AckList[n][m_AckListCnt[n]++] = iAck;
}
bool CRUDPConnect::ReSendQueue(unsigned short iType, unsigned short * iAckList, int iAckNum, CRUDPSocketFrame * pSocket)
{
std::list <_PACKET_QUEUE*>::iterator ii;
for (ii = m_SendQueue.begin(); ii != m_SendQueue.end(); ii++)
{
_PACKET_QUEUE * pq = (*ii);
for (int i = 0; i < iAckNum; i++)
{
_ASSERT((iAckList[i]&7) == 0);
//ÀÌ ½ÃÄÁ½º ÀÌÀü¿¡ °Íµé ³²¾Æ ÀÖ´Â°Ô ÀÖÀ¸¸é ÀÌŸÀֿ̹¡ ÈÄ´Ù´Ù´Ú º¸³½´Ù.
if (pq->seq < iAckList[i])
{
pSocket->SendTo(pq->data, pq->len, &m_TargetAddr);
pq->tick = pSocket->GetCurTick(); //³Ê¹« ªÀº ½Ã°£¿¡ ´Ù½Ã ½îÁö ¾Êµµ·Ï °»½Å
}
else if (pq->seq <= iAckList[i])
return true;
}
}
return false;
}
bool CRUDPConnect::RemoveQueue(unsigned short iType, unsigned short * iAckList, int iAckNum)
{
std::list <_PACKET_QUEUE*>::iterator ii;
int i , cnt = 0;
for (ii = m_SendQueue.begin(); ii != m_SendQueue.end() && cnt < iAckNum;)
{
_PACKET_QUEUE * pq = (*ii);
for (i = 0; i < iAckNum; i++)
{
_ASSERT((iAckList[i]&7) == 0);
if (pq->seq == iAckList[i] && pq->type == iType)
break;
}
if (i < iAckNum)
{
ReleaseQueue(pq);
m_SendQueue.erase(ii);
ii = m_SendQueue.begin();
cnt++;
}
else
ii++;
}
return cnt > 0 ? true : false;
}
_PACKET_QUEUE * CRUDPConnect::CreateQueue(CRUDPSocketFrame *pSocket, void * buffer, int len, int type)
{
_PACKET_QUEUE * q;
int lv, i;
_ASSERT(len < 512 - sizeof(_PACKET_QUEUE));
lv = MemLevel(sizeof(_PACKET_QUEUE) + len) ;
static const int _size[] = { 32, 64, 128, 256, 512 };
if( lv >= _countof(_size) )
return NULL;
if( m_EmptyQueue[lv].empty() )
{
char * ptr = new char [1024];
if (ptr == NULL) return NULL;
m_AllocedQueue.push_back(ptr);
for(i=0; i<1024; i+=_size[lv])
m_EmptyQueue[lv].push_back((_PACKET_QUEUE*)(ptr + i));
}
_ASSERT( !m_EmptyQueue[lv].empty() );
q = m_EmptyQueue[lv].back();
m_EmptyQueue[lv].pop_back();
q->seq = _PACKET_SEQ(((_RELIABLE_UDP_HEADER*)buffer)->seq);
q->type = type;
q->len = (unsigned short) len;
q->origintick = q->tick = pSocket->GetCurTick();
memcpy(q->data, buffer, len);
return q;
}
void CRUDPConnect::ReleaseQueue(_PACKET_QUEUE * pQueue)
{
int lv = MemLevel(sizeof(_PACKET_QUEUE) + pQueue->len) ;
m_EmptyQueue[lv].push_back(pQueue);
}
int CRUDPConnect::MemLevel(int size)
{
_ASSERT(size < 512);
if (size <= 64)
return size <= 32 ? 0 : 1;
if (size <= 256)
return size <= 128 ? 2 : 3;
return size <= 512 ? 4 : 5;
}