📄 hxnetapi.cpp
字号:
m_pTCPResponse->ConnectDone(theError);
break;
case TCP_BIND_COMMAND:
default:
theErr = DoRead();
DoWrite();
break;
}
}
m_pMutex->Unlock();
// we want out of memory errors to be reported immediately
// because fiddling around waiting for the error to propagate
// normally will just make the situation worse; mask out all
// other errors, as they will eventually get dealt with in
// ReadDone() or similar functions.
if (theErr != HXR_OUTOFMEMORY)
{
theErr = HXR_OK;
}
if( theErr )
{
IHXErrorMessages * pErrorNotifier = NULL;
IUnknown * pPlayer = NULL;
IHXClientEngine* pEngine = NULL;
UINT32 nNumPlayers = 0;
m_pContext->QueryInterface(IID_IHXClientEngine, (void**)&pEngine);
if( pEngine )
{
nNumPlayers = pEngine->GetPlayerCount();
for( int ii=0; ii<nNumPlayers; ii++ )
{
pEngine->GetPlayer(ii,pPlayer);
if( pPlayer )
{
pPlayer->QueryInterface( IID_IHXErrorMessages, (void**)&pErrorNotifier );
}
if( pErrorNotifier )
{
pErrorNotifier->Report( HXLOG_ERR, theErr, 0, NULL, NULL );
pErrorNotifier->Release();
}
HX_RELEASE( pPlayer );
}
}
HX_RELEASE( pEngine );
}
Release();
}
return theErr;
}
HX_RESULT HXTCPSocket::TCPSocketCallback::Func(NotificationType Type,
BOOL bSuccess, conn* pConn)
{
if(m_pContext)
{
switch (Type)
{
case READ_NOTIFICATION:
//
// This clears up a problem on the Macintosh where we were getting
// interrupt callbacks from the Network device, and could possibly
// collide when adding/removing data the same time from the same
// socket, at interrupt time, and at system level time.
//
#if defined(_UNIX_THREADED_NETWORK_IO)
if( !ReadNetworkThreadingPref((IUnknown*)(m_pContext->m_pContext) ))
{
m_pContext->AddRef();
m_pContext->m_pMutex->Lock();
m_pContext->DoRead();
m_pContext->m_pMutex->Unlock();
m_pContext->Release();
}
#elif !defined (THREADS_SUPPORTED) && !defined(_MACINTOSH)
m_pContext->AddRef();
m_pContext->m_pMutex->Lock();
m_pContext->DoRead();
m_pContext->m_pMutex->Unlock();
m_pContext->Release();
#endif
break;
case WRITE_NOTIFICATION:
#if defined(_UNIX_THREADED_NETWORK_IO)
if( !ReadNetworkThreadingPref((IUnknown*)(m_pContext->m_pContext)) )
{
m_pContext->AddRef();
m_pContext->m_pMutex->Lock();
m_pContext->DoWrite();
m_pContext->m_pMutex->Unlock();
m_pContext->Release();
}
#elif !defined (THREADS_SUPPORTED) && !defined(_MACINTOSH)
m_pContext->AddRef();
m_pContext->m_pMutex->Lock();
m_pContext->DoWrite();
m_pContext->m_pMutex->Unlock();
m_pContext->Release();
#endif
break;
case CONNECT_NOTIFICATION:
m_pContext->ConnectDone(bSuccess);
break;
case CLOSE_NOTIFICATION:
m_pContext->CloseDone();
break;
case DNS_NOTIFICATION:
m_pContext->DNSDone(bSuccess);
break;
default:
break;
}
}
return HXR_OK;
}
HXListenSocket::HXListenSocket(IUnknown* pContext,
HXNetworkServices* pNetworkServices)
: m_pListenConn(NULL)
, m_pCallback(NULL)
, m_pContext(NULL)
, m_bReuseAddr(FALSE)
, m_bReusePort(FALSE)
{
m_pContext = pContext;
m_pContext->AddRef();
m_pNetworkServices = pNetworkServices;
m_pNetworkServices->AddRef();
m_lRefCount = 0;
m_pListenResponse = 0;
}
HXListenSocket::~HXListenSocket()
{
if (m_pCallback)
{
m_pCallback->m_pContext = 0;
}
if (m_pListenConn)
{
m_pListenConn->done();
m_pListenConn->Release();
m_pListenConn = NULL;
}
HX_RELEASE(m_pContext);
HX_DELETE(m_pCallback);
HX_RELEASE(m_pListenResponse);
HX_RELEASE(m_pNetworkServices);
}
STDMETHODIMP HXListenSocket::QueryInterface(REFIID riid, void** ppvObj)
{
QInterfaceList qiList[] =
{
{ GET_IIDHANDLE(IID_IHXListenSocket), (IHXListenSocket*)this },
{ GET_IIDHANDLE(IID_IHXSetSocketOption), (IHXSetSocketOption*)this },
{ GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXListenSocket*)this },
};
return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
}
STDMETHODIMP_(ULONG32) HXListenSocket::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
STDMETHODIMP_(ULONG32) HXListenSocket::Release()
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return HXR_OK;
}
STDMETHODIMP HXListenSocket::SetOption(HX_SOCKET_OPTION option,
UINT32 ulValue)
{
HX_RESULT ret = HXR_OK;
switch (option)
{
case HX_SOCKOPT_REUSE_ADDR:
m_bReuseAddr = ulValue;
break;
case HX_SOCKOPT_REUSE_PORT:
m_bReusePort = ulValue;
break;
default:
ret = HXR_NOTIMPL;
}
return ret;
}
STDMETHODIMP HXListenSocket::Init(UINT32 ulLocalAddr, UINT16 port,
IHXListenResponse* pListenResponse)
{
if (!pListenResponse)
{
return HXR_UNEXPECTED;
}
HX_RELEASE(m_pListenResponse);
m_pListenResponse = pListenResponse;
m_pListenResponse->AddRef();
#if defined( _WIN32 ) || defined( _WINDOWS )
// Have we been able to load and initialize the winsock stuff yet?
if (!win_net::IsWinsockAvailable(this))
{
return HXR_FAIL; // HXR_GENERAL_NONET;
}
#endif
m_pNetworkServices->UseDrivers();
#ifdef _UNIX
//This one has to be set before we create a new socket.
conn::SetNetworkThreadingPref( ReadNetworkThreadingPref((IUnknown*)m_pContext) );
conn::SetThreadedDNSPref( ReadThreadedDNSPref((IUnknown*)m_pContext) );
#endif
HX_RESULT ret = conn::init_drivers(NULL);
m_pListenConn = conn::new_socket(HX_TCP_SOCKET);
if ( m_pListenConn == NULL )
{
return HXR_OUTOFMEMORY;
}
#ifdef _UNIX
m_pListenConn->SetAsyncDNSPref( ReadAsyncDNSPref((IUnknown*)m_pContext) );
#endif
m_pListenConn->nonblocking();
m_pListenConn->reuse_addr(m_bReuseAddr);
m_pListenConn->reuse_port(m_bReusePort);
if ( m_pCallback == NULL)
{
m_pCallback = new ListenSocketCallback();
m_pCallback->m_pContext = this;
}
m_pListenConn->set_callback(m_pCallback);
UINT32 ulPlatformData = 0;
#if defined (_WIN32)
ulPlatformData = (UINT32)GetModuleHandle(NULL);
#elif defined (_WIN16)
ulPlatformData = (UINT32)(int)g_hInstance;
#endif
return m_pListenConn->listen(ulLocalAddr, port, 2, 0, ulPlatformData);
}
HX_RESULT HXListenSocket::ListenSocketCallback::Func(NotificationType Type,
BOOL bSuccess, conn* pConn)
{
if(m_pContext)
{
switch (Type)
{
case ACCEPT_NOTIFICATION:
if ( bSuccess )
{
HXTCPSocket* pSock = new HXTCPSocket(m_pContext->m_pContext,
m_pContext->m_pNetworkServices);
if ( pSock )
{
pSock->AddRef();
if ( SUCCEEDED(pSock->AcceptConnection(pConn)) )
{
m_pContext->m_pListenResponse->NewConnection(HXR_OK,
(IHXTCPSocket*)pSock);
}
HX_RELEASE(pSock);
}
}
break;
case CONNECT_NOTIFICATION:
break;
case READ_NOTIFICATION:
break;
case CLOSE_NOTIFICATION:
break;
case DNS_NOTIFICATION:
default:
break;
}
}
return HXR_OK;
}
HXUDPSocket::HXUDPSocket(IUnknown* pContext, HXNetworkServices* pNetworkServices):
m_lRefCount(0),
m_pCallback(0),
m_pUDPResponse(0),
m_pData(0),
m_bReadPending(FALSE),
m_bInRead(FALSE),
m_bInDoRead(FALSE),
m_bInWrite(FALSE),
m_nRequired(0),
m_pSchedulerReadCallback(NULL),
m_pSchedulerWriteCallback(NULL),
m_pNonInterruptReadCallback(NULL),
m_pScheduler(0),
m_nDestPort(0),
m_bInitComplete(FALSE),
m_pInterruptState(NULL),
m_pResponseInterruptSafe(NULL),
m_pMutex(NULL),
m_bReuseAddr(FALSE),
m_bReusePort(FALSE),
m_bInDestructor(FALSE),
m_pContext(pContext)
{
#ifdef _MACINTOSH
m_pInterruptSafeMacWriteQueue = new InterruptSafeMacQueue();
HX_ASSERT(m_pInterruptSafeMacWriteQueue != NULL);
#endif
m_pNetworkServices = pNetworkServices;
m_pNetworkServices->AddRef();
if (pContext)
{
pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
pContext->QueryInterface(IID_IHXInterruptState, (void**) &m_pInterruptState);
}
if (m_pScheduler)
{
m_pSchedulerReadCallback = new ScheduledSocketCallback(this, TRUE);
m_pSchedulerReadCallback->AddRef();
m_pSchedulerWriteCallback = new ScheduledSocketCallback(this, TRUE);
m_pSchedulerWriteCallback->AddRef();
m_pNonInterruptReadCallback = new ScheduledSocketCallback(this, FALSE);
m_pNonInterruptReadCallback->AddRef();
}
#if defined(THREADS_SUPPORTED)
HXMutex::MakeMutex(m_pMutex);
#elif defined(_UNIX_THREADED_NETWORK_IO)
if( ReadNetworkThreadingPref((IUnknown*)m_pContext) )
{
HXMutex::MakeMutex(m_pMutex);
}
else
{
HXMutex::MakeStubMutex(m_pMutex);
}
#else
HXMutex::MakeStubMutex(m_pMutex);
#endif
}
HXUDPSocket::~HXUDPSocket()
{
m_bInDestructor = TRUE;
m_pMutex->Lock();
#ifdef _MACINTOSH
HX_DELETE(m_pInterruptSafeMacWriteQueue); // will release any objects in its nodes
#endif
if (m_pSchedulerReadCallback)
m_pSchedulerReadCallback->Unschedule(m_pScheduler);
if (m_pSchedulerWriteCallback)
m_pSchedulerWriteCallback->Unschedule(m_pScheduler);
if (m_pNonInterruptReadCallback)
m_pNonInterruptReadCallback->Unschedule(m_pScheduler);
/*
* XXX...While handling the m_pData->done it's possible for the
* DispatchMessage call in CancelSelect to cause an
* asynchronous DoRead to occur. The resulting AddRef/Release
* would cause this object to be deleted again, so to prevent
* this we set the m_pCallback->m_pContext = 0
*/
if (m_pCallback)
{
m_pCallback->m_pContext = 0;
}
if (m_pData)
{
m_pData->done();
m_pData->Release();
m_pData = 0;
}
if(m_pUDPResponse)
{
m_pUDPResponse->Release();
m_pUDPResponse = 0;
}
if (m_pCallback)
{
delete m_pCallback;
m_pCallback = 0;
}
if (m_pScheduler)
{
m_pScheduler->Release();
m_pScheduler = 0;
}
while (!m_ReadBuffers.IsEmpty())
{
UDP_PACKET* pPacket = (UDP_PACKET*)m_ReadBuffers.RemoveHead();
HX_RELEASE(pPacket->pBuffer);
HX_DELETE(pPacket);
}
HX_RELEASE(m_pInterruptState);
HX_RELEASE(m_pResponseInterruptSafe);
if (m_pSchedulerReadCallback)
{
m_pSchedulerReadCallback->m_pSocket = NULL;
m_pSchedulerReadCallback->Release();
m_pSchedulerReadCallback = NULL;
}
if (m_pSchedulerWriteCallback)
{
m_pSchedulerWriteCallback->m_pSocket = NULL;
m_pSchedulerWriteCallback->Release();
m_pSchedulerWriteCallback = NULL;
}
if (m_pNonInterruptReadCallback)
{
m_pNonInterruptReadCallback->m_pSocket = NULL;
m_pNonInterruptReadCallback->Release();
m_pNonInterruptReadCallback = NULL;
}
m_pMutex->Unlock();
HX_DELETE(m_pMutex);
#if defined( _WIN32 ) || defined( _WINDOWS )
win_net::ReleaseWinsockUsage(this);
#endif
HX_RELEASE(m_pNetworkServices);
}
STDMETHODIMP HXUDPSocket::QueryInterface(REFIID riid, void** ppvObj)
{
QInterfaceList qiList[] =
{
{ GET_IIDHANDLE(IID_IHXUDPSocket), (IHXUDPSocket*)this },
{ GET_IIDHANDLE(IID_IHXSetSocketOption), (IHXSetSocketOption*)this },
{ GET_IIDHANDLE(IID_IHXUDPMulticastInit), (IHXUDPMulticastInit*)this },
{ GET_IIDHANDLE(IID_IHXSetPrivateSocketOption), (IHXSetPrivateSocketOption*)this },
{ GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXUDPSocket*)this },
};
return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
}
STDMETHODIMP_(ULONG32) HXUDPSocket::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
STDMETHODIMP_(ULONG32) HXUDPSocket::Release()
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return 0;
}
STDMETHODIMP
HXUDPSocket::InitMulticast(UINT8 uTTL)
{
if (HXR_OK != m_pData->set_multicast())
{
return HXR_FAIL;
}
if (HXR_OK != m_pData->set_multicast_ttl(uTTL))
{
return HXR_FAIL;
}
return HXR_OK;
}
STDMETHODIMP HXUDPSocket::Init(ULONG32 ulAddr, UINT16 nPort,
IHXUDPResponse* pUDPResponse)
{
if (!pUDPResponse && !m_pUDPResponse)
{
/*
* if the response object hasn't been set up yet, then
* require a response object (i.e. the first call to Init
* must always specify a response object
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -