712 lines
17 KiB
C++
712 lines
17 KiB
C++
|
|
#include <cassert>
|
|
|
|
#include "../../include/network/XIOCPConnection.h"
|
|
#include "../../include/network/XIOCPStruct.h"
|
|
#include "../../include/network/XNetworkUtil.h"
|
|
#include "../../include/toolkit/IQueue.h"
|
|
#include "../../include/dump/XException.h"
|
|
#include "../../include/toolkit/XEnv.h"
|
|
#include "../../include/cipher/XRC4Cipher.h"
|
|
|
|
|
|
volatile LONG g_nConnectionCount;
|
|
|
|
XIOCPConnection::XIOCPConnection( OverlappedAllocator *pAllocator, bool bUseCipher ) : m_closeCS( ".XIOCPConnection_Close" ), m_recvCS( ".XIOCPConnection_Recv" ), m_sendCS( ".XIOCPConnection_Send" )
|
|
{
|
|
init( pAllocator, bUseCipher );
|
|
|
|
InterlockedIncrement( &g_nConnectionCount );
|
|
}
|
|
|
|
XIOCPConnection::XIOCPConnection( OverlappedAllocator *pAllocator, XSocket sock, bool bUseCipher ) : IStreamSocketConnection( sock ), m_closeCS( ".XIOCPConnection_Close" ), m_recvCS( ".XIOCPConnection_Recv" ), m_sendCS( ".XIOCPConnection_Send" )
|
|
{
|
|
init( pAllocator, bUseCipher );
|
|
|
|
InterlockedIncrement( &g_nConnectionCount );
|
|
}
|
|
|
|
XIOCPConnection::~XIOCPConnection()
|
|
{
|
|
//_oprint( "delete connection 0x%08X\n", this );
|
|
|
|
if( m_pSendQueue != NULL )
|
|
{
|
|
int nRestSize = m_pSendQueue->Size();
|
|
InterlockedExchangeAdd( &(XIOCPIOStat::GetInstance().nSendRestBytes), -nRestSize );
|
|
}
|
|
|
|
delete m_pSendQueue;
|
|
delete m_pRecvQueue;
|
|
|
|
delete m_pSendCipher;
|
|
delete m_pRecvCipher;
|
|
|
|
delete [] m_pRecvOverlapped->pBuf;
|
|
|
|
if( m_pAllocator )
|
|
{
|
|
THREAD_SYNCRONIZE( m_pAllocator );
|
|
|
|
m_pAllocator->freeOverlapped( m_pRecvOverlapped );
|
|
m_pAllocator->freeOverlapped( m_pSendOverlapped );
|
|
}
|
|
else
|
|
{
|
|
delete m_pRecvOverlapped;
|
|
delete m_pSendOverlapped;
|
|
}
|
|
|
|
if( m_pConnectOverlapped )
|
|
{
|
|
if( m_pAllocator )
|
|
{
|
|
THREAD_SYNCRONIZE( m_pAllocator );
|
|
m_pAllocator->freeOverlapped( m_pConnectOverlapped );
|
|
}
|
|
else
|
|
{
|
|
delete m_pConnectOverlapped;
|
|
}
|
|
}
|
|
|
|
InterlockedDecrement( &g_nConnectionCount );
|
|
}
|
|
|
|
void XIOCPConnection::init( OverlappedAllocator *pAllocator, bool bUseCipher )
|
|
{
|
|
m_nVar = 0;
|
|
m_nFlag = 0;
|
|
|
|
m_pAllocator = pAllocator;
|
|
|
|
// * Queue 생성에 관한 노트
|
|
//
|
|
// 1. SendQueue는 꼭 PLAIN 스타일의 큐여야 한다. 암호화 관련해서 Queue::GetBuf() 를 사용하기 때문.
|
|
// 2. 펑션 단위에서 lock 을 하기 때문에 thread_safe 할 필요가 없음.
|
|
XIOCPQueueInfo::GetInstance().Update();
|
|
m_pSendQueue = IQueue::MakeQueue( XIOCPQueueInfo::GetInstance().nSendQueueSize, IQueue::PLAIN );
|
|
m_pRecvQueue = IQueue::MakeQueue( XIOCPQueueInfo::GetInstance().nRecvQueueSize, IQueue::PLAIN );
|
|
|
|
|
|
// { OVERLAPPED 구조체 생성
|
|
{
|
|
if( m_pAllocator )
|
|
{
|
|
THREAD_SYNCRONIZE( m_pAllocator );
|
|
m_pRecvOverlapped = m_pAllocator->allocOverlapped();
|
|
m_pSendOverlapped = m_pAllocator->allocOverlapped();
|
|
}
|
|
else
|
|
{
|
|
m_pRecvOverlapped = new XOVERLAPPED;
|
|
m_pSendOverlapped = new XOVERLAPPED;
|
|
}
|
|
|
|
// receive overlapped structure 초기화
|
|
m_pRecvOverlapped->Init( reinterpret_cast< HANDLE >( m_socket.GetSocketHandle() ), this, new char[ IOCP_BUFFER_SIZE ] );
|
|
m_pRecvOverlapped->cFlag = XIOCP_RECV;
|
|
|
|
// send overlapped structure 초기화
|
|
m_pSendOverlapped->Init( reinterpret_cast< HANDLE >( m_socket.GetSocketHandle() ), this );
|
|
m_pSendOverlapped->cFlag = XIOCP_SEND;
|
|
|
|
m_pConnectOverlapped = NULL;
|
|
}
|
|
// }
|
|
|
|
|
|
m_bSendPending = false;
|
|
m_nPendingQueryCount = 0;
|
|
m_nSendIndicator = 0;
|
|
|
|
m_nPendingRecvQueryCount = 0;
|
|
m_nPendingSendQueryCount = 0;
|
|
|
|
m_hIOCP = NULL;
|
|
|
|
m_bDisconnectSignal = false;
|
|
m_bIsPostedDisconnectEvent = false;
|
|
|
|
if( bUseCipher )
|
|
{
|
|
m_pSendCipher = new XRC4Cipher;
|
|
m_pRecvCipher = new XRC4Cipher;
|
|
|
|
static_cast< XRC4Cipher * >( m_pSendCipher )->SetKey( "}h79q~B%al;k'y $E" );
|
|
static_cast< XRC4Cipher * >( m_pRecvCipher )->SetKey( "}h79q~B%al;k'y $E" );
|
|
}
|
|
else
|
|
{
|
|
m_pSendCipher = new IDummyCipher;
|
|
m_pRecvCipher = new IDummyCipher;
|
|
}
|
|
}
|
|
|
|
bool XIOCPConnection::Create()
|
|
{
|
|
// 소켓이 정상이 아니면
|
|
if( !m_socket.IsValidSocket() )
|
|
{
|
|
// 새로 소켓을 생성
|
|
if( !m_socket.CreateStreamSocket() )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool XIOCPConnection::Close()
|
|
{
|
|
if( m_bIsConnected ) onDisconnect( -999 );
|
|
|
|
// cipher 초기화
|
|
if( m_pSendCipher ) m_pSendCipher->Clear();
|
|
if( m_pRecvCipher ) m_pRecvCipher->Clear();
|
|
|
|
m_bIsConnected = false;
|
|
m_socket.Destroy();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool XIOCPConnection::Connect( const XAddr & addr )
|
|
{
|
|
// 이미 연결되어 있으면 실패
|
|
if( m_bIsConnected ) return false;
|
|
|
|
if( !m_pConnectOverlapped )
|
|
{
|
|
if( m_pSendOverlapped )
|
|
{
|
|
THREAD_SYNCRONIZE( m_pAllocator );
|
|
m_pConnectOverlapped = m_pAllocator->allocOverlapped();
|
|
}
|
|
else
|
|
{
|
|
m_pConnectOverlapped = new XOVERLAPPED;
|
|
}
|
|
|
|
m_pConnectOverlapped->Init( reinterpret_cast< HANDLE >( m_socket.GetSocketHandle() ), this );
|
|
m_pConnectOverlapped->cFlag = XIOCP_CONNECT;
|
|
}
|
|
|
|
// 소켓이 정상이 아니면
|
|
if( !m_socket.IsValidSocket() )
|
|
{
|
|
// 새로 소켓을 생성
|
|
if( !m_socket.CreateStreamSocket() ) return false;
|
|
}
|
|
|
|
// 주소가 명확하지 않으면 실패
|
|
struct sockaddr_in addr_in;
|
|
if( !XNetworkUtil::ConvAddr( addr, addr_in ) ) return false;
|
|
|
|
// { ConnectEx 의 주소를 얻어옴.
|
|
static LPFN_CONNECTEX lpfnConnectEx;
|
|
if( !lpfnConnectEx )
|
|
{
|
|
DWORD dw = 0;
|
|
GUID GuidConnectEx=WSAID_CONNECTEX;
|
|
int nErr = WSAIoctl( m_socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidConnectEx, sizeof(GuidConnectEx), &lpfnConnectEx, sizeof(lpfnConnectEx), &dw, NULL, NULL );
|
|
|
|
if( nErr ) return false;
|
|
}
|
|
// }
|
|
|
|
// { 주소 변환
|
|
struct sockaddr_in addr_in_local;
|
|
ZeroMemory( &addr_in_local, sizeof(addr_in_local) );
|
|
addr_in_local.sin_addr.S_un.S_addr = INADDR_ANY;
|
|
addr_in_local.sin_family = AF_INET;
|
|
// }
|
|
|
|
// cipher 초기화
|
|
if( m_pSendCipher ) m_pSendCipher->Clear();
|
|
if( m_pRecvCipher ) m_pRecvCipher->Clear();
|
|
|
|
// bind
|
|
if( bind( m_socket.GetSocketHandle(), (struct sockaddr*)&addr_in_local, sizeof(addr_in_local) ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// call
|
|
BOOL bRtn = (*lpfnConnectEx)( m_socket.GetSocketHandle(), reinterpret_cast< struct sockaddr* >( &addr_in ), sizeof( addr_in ), NULL, 0, NULL, m_pConnectOverlapped );
|
|
|
|
if( !bRtn && WSAGetLastError() == WSA_IO_PENDING ) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool XIOCPConnection::SyncConnect( const XAddr & addr )
|
|
{
|
|
// 이미 연결되어 있으면 실패
|
|
if( m_bIsConnected ) return false;
|
|
|
|
// 소켓이 정상이 아니면
|
|
if( !m_socket.IsValidSocket() )
|
|
{
|
|
// 새로 소켓을 생성
|
|
if( !m_socket.CreateStreamSocket() ) return false;
|
|
}
|
|
|
|
// 주소가 명확하지 않으면 실패
|
|
struct sockaddr_in addr_in;
|
|
if( !XNetworkUtil::ConvAddr( addr, addr_in ) ) return false;
|
|
|
|
// 연결
|
|
int nRtn = connect( m_socket, reinterpret_cast< struct sockaddr* >( &addr_in ), sizeof( struct sockaddr_in ) );
|
|
|
|
if( nRtn != SOCKET_ERROR ) m_bIsConnected = true;
|
|
|
|
return m_bIsConnected;
|
|
}
|
|
|
|
bool XIOCPConnection::Reset()
|
|
{
|
|
if( m_bIsConnected ) m_bIsConnected = false;
|
|
|
|
if( m_socket.IsValidSocket() ) m_socket.Destroy();
|
|
|
|
m_bSendPending = false;
|
|
|
|
m_nSendIndicator = 0;
|
|
|
|
m_nPendingQueryCount = m_nPendingRecvQueryCount = m_nPendingSendQueryCount = 0;
|
|
|
|
m_hIOCP = NULL;
|
|
|
|
m_bIsPostedDisconnectEvent = false;
|
|
|
|
m_bDisconnectSignal = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
int XIOCPConnection::Peek( void *szBuf, size_t nLen )
|
|
{
|
|
THREAD_SYNCRONIZE( m_recvCS );
|
|
|
|
// 읽을 크기 얻는다
|
|
unsigned nReadableSize = (std::min)( ( unsigned int )nLen, m_pRecvQueue->Size() );
|
|
|
|
// 암호화 풀고
|
|
m_pRecvCipher->Decode( m_pRecvQueue->GetBuf(), szBuf, nReadableSize, true );
|
|
|
|
// 읽은길이 리턴
|
|
return nReadableSize;
|
|
}
|
|
|
|
int XIOCPConnection::Read( void* szBuf, size_t nLen )
|
|
{
|
|
THREAD_SYNCRONIZE( m_recvCS );
|
|
|
|
// 읽을 크기 얻는다
|
|
unsigned nReadableSize = (std::min)( ( unsigned int )nLen, m_pRecvQueue->Size() );
|
|
|
|
// 암호화 풀고
|
|
m_pRecvCipher->Decode( m_pRecvQueue->GetBuf(), szBuf, nReadableSize );
|
|
|
|
// 읽은만큼 버린다
|
|
m_pRecvQueue->Read( NULL, nReadableSize );
|
|
|
|
// 읽은길이 리턴
|
|
return nReadableSize;
|
|
}
|
|
|
|
int XIOCPConnection::Write( const void * szBuf, size_t nLen )
|
|
{
|
|
if( !IsConnected() )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if( CheckDisconnectSignal() )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if( !nLen ) return 0;
|
|
|
|
THREAD_SYNCRONIZE( &m_sendCS );
|
|
|
|
if( m_pSendQueue->FreeSize() < nLen )
|
|
{
|
|
unsigned int nReserveSize = XIOCPQueueInfo::GetInstance().nBaseQueueSize;
|
|
if( nReserveSize < nLen )
|
|
{
|
|
nReserveSize = static_cast< unsigned int >( nLen );
|
|
}
|
|
|
|
m_pSendQueue->Reserve( nReserveSize );
|
|
|
|
if( XIOCPQueueInfo::GetInstance().nMaxReallocSize < (int)m_pSendQueue->GetReservedSize() )
|
|
{
|
|
XIOCPQueueInfo::GetInstance().nMaxReallocSize = m_pSendQueue->GetReservedSize();
|
|
}
|
|
}
|
|
|
|
unsigned int unPrevSize = m_pSendQueue->Size();
|
|
if( m_pSendQueue->Write( szBuf, static_cast< unsigned int >( nLen ) ) != static_cast< unsigned int >( nLen ) )
|
|
{
|
|
assert(0);
|
|
onDisconnect( -1 );
|
|
return -1;
|
|
}
|
|
|
|
m_pSendCipher->Encode( m_pSendQueue->GetBuf() + unPrevSize, const_cast< char* >( m_pSendQueue->GetBuf() + unPrevSize ), static_cast< unsigned int >( nLen ) );
|
|
|
|
InterlockedExchangeAdd( &(XIOCPIOStat::GetInstance().nSendRestBytes), (int)nLen );
|
|
if( !m_bSendPending )
|
|
{
|
|
procWriteFile();
|
|
}
|
|
|
|
return ( int )nLen;
|
|
}
|
|
|
|
|
|
void XIOCPConnection::onSendCompletionEvent( int nSize )
|
|
{
|
|
InterlockedDecrement( &m_nPendingSendQueryCount );
|
|
|
|
if( nSize < 1 ) return;
|
|
|
|
THREAD_SYNCRONIZE( &m_sendCS );
|
|
|
|
InterlockedIncrement( &(XIOCPIOStat::GetInstance().nSendCount) );
|
|
InterlockedExchangeAdd( &(XIOCPIOStat::GetInstance().nSendTraffic), nSize );
|
|
InterlockedExchangeAdd( &(XIOCPIOStat::GetInstance().nSendRestBytes), -nSize );
|
|
|
|
assert( nSize <= (int)m_pSendQueue->Size() );
|
|
|
|
m_pSendQueue->Read( NULL, nSize );
|
|
|
|
m_nSendIndicator -= nSize;
|
|
m_bSendPending = false;
|
|
|
|
/*
|
|
// 버퍼가 원래 크기보다 크고, 남은 양이 원래 크기보다 작으면(축소 시킬 수 있다면)
|
|
unsigned int nOrginalSize = XIOCPQueueInfo::GetInstance().nSendQueueSize;
|
|
if( m_pSendQueue->GetReservedSize() > nOrginalSize &&
|
|
m_pSendQueue->Size() < nOrginalSize )
|
|
{
|
|
// 여유분이 충분하다면(50%) 버퍼를 축소 시킨다.
|
|
if( m_pSendQueue->FreeSize() >= (nOrginalSize / 2) )
|
|
{
|
|
m_pSendQueue->ResetReservedSize( nOrginalSize );
|
|
}
|
|
}
|
|
*/
|
|
|
|
int nRestSize = m_pSendQueue->Size();
|
|
|
|
// Send Queue 에 있으나 WriteFile() 되지 않은 부분이 있다면 처리
|
|
if( nRestSize - m_nSendIndicator > 0 )
|
|
{
|
|
if( !m_bDisconnectSignal && m_bIsConnected && !m_bIsPostedDisconnectEvent )
|
|
{
|
|
procWriteFile();
|
|
}
|
|
}
|
|
}
|
|
|
|
void XIOCPConnection::decreaseQueryCount()
|
|
{
|
|
InterlockedDecrement( &m_nPendingQueryCount );
|
|
}
|
|
|
|
void XIOCPConnection::onRecvCompletionEvent( int nSize )
|
|
{
|
|
InterlockedDecrement( &m_nPendingRecvQueryCount );
|
|
|
|
if( nSize < 1 ) {
|
|
m_recvCS.UnLock();
|
|
return;
|
|
}
|
|
|
|
InterlockedIncrement( &(XIOCPIOStat::GetInstance().nRecvCount) );
|
|
InterlockedExchangeAdd( &(XIOCPIOStat::GetInstance().nRecvTraffic), nSize );
|
|
|
|
if( !m_pRecvQueue->Resize( m_pRecvQueue->Size() + nSize ) ) throw XException( "XIOCPConnection _procPushRecvQueue Error!!" );
|
|
|
|
m_recvCS.UnLock();
|
|
}
|
|
|
|
void XIOCPConnection::onConnect( void *pBuf )
|
|
{
|
|
struct sockaddr_in * pMyAddr = NULL;
|
|
struct sockaddr_in * pPeerAddr = NULL;
|
|
int nMyLen, nPeerLen;
|
|
|
|
GetAcceptExSockaddrs( pBuf, 0, sizeof( sockaddr_in ) + 16, sizeof( sockaddr_in ) + 16,
|
|
reinterpret_cast< sockaddr ** >( &pMyAddr ), &nMyLen, reinterpret_cast< sockaddr ** >( &pPeerAddr ), &nPeerLen );
|
|
|
|
m_myAddr.SetAddr( inet_ntoa( pMyAddr->sin_addr ) );
|
|
m_myAddr.SetPortNum( ntohs( pMyAddr->sin_port ) );
|
|
|
|
m_peerAddr.SetAddr( inet_ntoa( pPeerAddr->sin_addr ) );
|
|
m_peerAddr.SetPortNum( ntohs( pPeerAddr->sin_port ) );
|
|
|
|
m_bIsConnected = true;
|
|
}
|
|
|
|
#include <set>
|
|
|
|
void XIOCPConnection::onDisconnect( int nFlag )
|
|
{
|
|
bool bNotifyClosed = false;
|
|
|
|
{
|
|
THREAD_SYNCRONIZE( m_closeCS );
|
|
|
|
// 같은 쓰레드의 critical section 재진입은 허용된다.
|
|
/*
|
|
THREAD_SYNCRONIZE1( m_recvCS );
|
|
THREAD_SYNCRONIZE2( m_sendCS );*/
|
|
|
|
// 첫 연결끊어짐 통지라면..
|
|
if( !m_bDisconnectSignal )
|
|
{
|
|
m_bDisconnectSignal = true;
|
|
m_nFlag = nFlag;
|
|
}
|
|
|
|
// 쿼리 갯수가 0이라면?
|
|
if( !m_nPendingQueryCount )
|
|
{
|
|
if( !m_bIsPostedDisconnectEvent )
|
|
{
|
|
if( IsConnected() )
|
|
{
|
|
m_bIsConnected = false;
|
|
|
|
if( !Close() )
|
|
{
|
|
throw XException( "XIOCPConnection::onDisconnect - CloseSocket() Error!" );
|
|
}
|
|
}
|
|
|
|
// _oprint( "Before Post Disconnect Event : 0x%08X (%d) (%04x)\n", this, nFlag, nRandKey );
|
|
|
|
m_bIsPostedDisconnectEvent = true;
|
|
|
|
bNotifyClosed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bNotifyClosed )
|
|
{
|
|
PostQueuedCompletionStatus( this->m_hIOCP, 0, static_cast< ULONG_PTR >( XIOCP_EVENT_CONNECTION_CLOSED ), m_pRecvOverlapped );
|
|
}
|
|
|
|
// _oprint( "After Post Disconnect Event : 0x%08X (%d:%d:%d) (%04x)\n", this, nFlag, nTmp, nProgKey, nRandKey );
|
|
}
|
|
|
|
bool XIOCPConnection::pendRecvRequest()
|
|
{
|
|
if( !IsConnected() ) return false;
|
|
|
|
m_recvCS.Lock();
|
|
|
|
bool bRtn = true;
|
|
|
|
if( m_pRecvQueue->Size() + m_pRecvQueue->FreeSize() > m_pRecvQueue->GetReservedSize() )
|
|
{
|
|
throw XException( "XIOCPConnection QUEUE OVERFLOW!!" );
|
|
}
|
|
|
|
// 버퍼가 가득 찼다면..
|
|
if( m_pRecvQueue->FreeSize() == 0 )
|
|
{
|
|
m_pRecvQueue->Reserve( m_pRecvQueue->GetReservedSize() );
|
|
}
|
|
|
|
// IOCP 에서, WSARecv() 호출은 GetCompletionStatus() 와 함께 대개의 CPU 시간을 소모한다. 마음에 안드는군~
|
|
m_RecvWSABUF.buf = const_cast< char* >(m_pRecvQueue->GetBuf() + m_pRecvQueue->Size());
|
|
m_RecvWSABUF.len = m_pRecvQueue->FreeSize();
|
|
|
|
assert( m_nPendingRecvQueryCount < 1 );
|
|
|
|
InterlockedIncrement( &m_nPendingQueryCount );
|
|
InterlockedIncrement( &m_nPendingRecvQueryCount );
|
|
|
|
m_dwRecvFlag = 0;
|
|
// _oprint( "WSARecv() : 0x%08X\n", this );
|
|
int nRtn = WSARecv( GetSocketHandle(), &m_RecvWSABUF, 1, &m_pRecvOverlapped->dwSize, &m_dwRecvFlag, m_pRecvOverlapped, NULL );
|
|
/*
|
|
int nRtn = ReadFile( reinterpret_cast< HANDLE >( GetXSocket().GetSocketHandle() ),
|
|
const_cast< char* >(m_pRecvQueue->GetBuf() + m_pRecvQueue->Size()), m_pRecvQueue->FreeSize(),
|
|
&m_pRecvOverlapped->dwSize, m_pRecvOverlapped );
|
|
*/
|
|
|
|
if( nRtn == SOCKET_ERROR )
|
|
{
|
|
int nErr = WSAGetLastError();
|
|
if( nErr == WSA_IO_PENDING )
|
|
{
|
|
}
|
|
else
|
|
{
|
|
bRtn = false;
|
|
InterlockedDecrement( &m_nPendingQueryCount );
|
|
InterlockedDecrement( &m_nPendingRecvQueryCount );
|
|
|
|
|
|
onDisconnect( -2 );
|
|
}
|
|
}
|
|
|
|
return bRtn;
|
|
}
|
|
|
|
bool XIOCPConnection::onConnectCompletionEvent( bool bFlag )
|
|
{
|
|
m_bIsConnected = bFlag;
|
|
|
|
if( m_bIsConnected ) return pendRecvRequest();
|
|
|
|
return false;
|
|
}
|
|
|
|
bool XIOCPConnection::procWriteFile()
|
|
{
|
|
if( !IsConnected() ) return false;
|
|
|
|
if( m_bDisconnectSignal ) return false;
|
|
if( m_bIsPostedDisconnectEvent ) return false;
|
|
|
|
int nLen = m_pSendQueue->Size() - m_nSendIndicator;
|
|
|
|
int nSendSize = ( IOCP_BUFFER_SIZE > nLen ? nLen : IOCP_BUFFER_SIZE );
|
|
|
|
XOVERLAPPED * pSendOverlapped = m_pSendOverlapped;
|
|
|
|
// 주의 : 꼭 m_pSendQueue 의 GetBuf() 를 받아서 사용할것.
|
|
// (암호화가 SendQueue 에 Write 될때 일어나기 때문)
|
|
//
|
|
// 덧붙임 : 스트림 압축 알고리즘을 Queue 에 구현시
|
|
// GetBuf() 뿐만 아니라 size 도 Queue 의것을 사용할 필요가 있다.
|
|
|
|
InterlockedIncrement( &m_nPendingQueryCount );
|
|
InterlockedIncrement( &m_nPendingSendQueryCount );
|
|
|
|
int nRtn;
|
|
m_dwSendFlag = 0;
|
|
m_SendWSABUF.buf = const_cast< char* >( m_pSendQueue->GetBuf() + m_nSendIndicator );
|
|
m_SendWSABUF.len = nSendSize;
|
|
nRtn = WSASend( GetSocketHandle(), &m_SendWSABUF, 1, &pSendOverlapped->dwSize, m_dwSendFlag, pSendOverlapped, NULL );
|
|
/*
|
|
nRtn = WriteFile( reinterpret_cast< HANDLE >( m_socket.GetSocketHandle() ),
|
|
m_pSendQueue->GetBuf() + m_nSendIndicator, nSendSize,
|
|
&pSendOverlapped->dwSize, pSendOverlapped );
|
|
*/
|
|
|
|
if( nRtn == SOCKET_ERROR )
|
|
{
|
|
DWORD nErr = WSAGetLastError();
|
|
|
|
if( nErr == WSA_IO_PENDING )
|
|
{
|
|
}
|
|
else
|
|
{
|
|
InterlockedDecrement( &m_nPendingQueryCount );
|
|
InterlockedDecrement( &m_nPendingSendQueryCount );
|
|
|
|
onDisconnect( -3 );
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
m_bSendPending = true;
|
|
|
|
m_nSendIndicator += nSendSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
const char* XIOCPConnection::GetBuf() { return m_pRecvQueue->GetBuf(); }
|
|
int XIOCPConnection::Size() { return m_pRecvQueue->Size(); }
|
|
|
|
|
|
|
|
XIOCPConnectionCloser::XIOCPConnectionCloser( XIOCPConnectionCloser::DeleteHandler* pDel ) : m_cs( ".XIOCPConnectionCloser" )
|
|
{
|
|
m_pDel = pDel;
|
|
}
|
|
|
|
XIOCPConnectionCloser::~XIOCPConnectionCloser()
|
|
{
|
|
DeInit();
|
|
}
|
|
|
|
void XIOCPConnectionCloser::DeInit()
|
|
{
|
|
THREAD_SYNCHRONIZE( m_cs );
|
|
|
|
for ( std::list< XIOCPConnection* >::iterator it = m_closingConns.begin(); it != m_closingConns.end(); ++it )
|
|
{
|
|
if ( m_pDel )
|
|
m_pDel->onDelete( *it );
|
|
else
|
|
delete *it;
|
|
}
|
|
m_closingConns.clear();
|
|
}
|
|
|
|
bool XIOCPConnectionCloser::Has( XIOCPConnection* pConn )
|
|
{
|
|
THREAD_SYNCHRONIZE( m_cs );
|
|
|
|
return std::find( m_closingConns.begin(), m_closingConns.end(), pConn ) != m_closingConns.end();
|
|
}
|
|
|
|
void XIOCPConnectionCloser::Add( XIOCPConnection* pConn )
|
|
{
|
|
THREAD_SYNCHRONIZE( m_cs );
|
|
|
|
if ( !pConn || Has( pConn ) )
|
|
return;
|
|
|
|
if ( pConn->IsConnected() )
|
|
pConn->Close();
|
|
|
|
if ( pConn->GetPendingQueryCount() == 0 )
|
|
{
|
|
if ( m_pDel )
|
|
m_pDel->onDelete( pConn );
|
|
else
|
|
delete pConn;
|
|
return;
|
|
}
|
|
|
|
m_closingConns.push_back( pConn );
|
|
}
|
|
|
|
void XIOCPConnectionCloser::Process()
|
|
{
|
|
THREAD_SYNCHRONIZE( m_cs );
|
|
|
|
for ( std::list< XIOCPConnection* >::iterator it = m_closingConns.begin(); it != m_closingConns.end(); )
|
|
{
|
|
if ( (*it)->GetPendingQueryCount() == 0 )
|
|
{
|
|
if ( m_pDel )
|
|
m_pDel->onDelete( *it );
|
|
else
|
|
delete *it;
|
|
it = m_closingConns.erase( it );
|
|
}
|
|
else
|
|
++it;
|
|
}
|
|
}
|