hxnetapi.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:69k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #include "hxtypes.h"
- #include "hxresult.h"
- #include "hxcom.h"
- #include "hxcomm.h"
- #include "hxprefs.h"
- #include "hxerror.h"
- #if defined(_MACINTOSH)
- #include "hx_moreprocesses.h"
- #endif /* _MACINTOSH. */
- #include "ihxpckts.h"
- #include "hxfiles.h"
- #include "chxpckts.h"
- #include "hxengin.h"
- #include "hxpnets.h"
- #include "hxtick.h"
- #include "hxstrutl.h"
- #include "chxuuid.h"
- #include "rtsputil.h"
- #include "hxslist.h"
- #include "cbqueue.h"
- #include "growingq.h"
- #include "dbcs.h"
- #include "conn.h"
- #include "hxmarsh.h"
- #include "hxthread.h"
- #include "hxcore.h"
- #if defined (_UNIX)
- #include "unix_net.h"
- #include "platform/unix/hxsignal.h"
- #elif defined (_WIN32) || defined (_WINDOWS)
- #include "win_net.h"
- #elif defined(__TCS__)
- #include "platform/tm1/tm1_net.h"
- #elif defined (_MACINTOSH)
- #ifndef _MAC_MACHO
- #include "OpenTptInternet.h" //for AF_INET
- #endif
- #include "mac_net.h"
- #include "macsockets.h"
- #endif
- #include "threngin.h"
- #include "netbyte.h"
- #include "hxnetapi.h"
- #include "hxnetutil.h"
- #if defined(HELIX_FEATURE_HTTPCLOAK)
- #include "hxcloakedtcp.h"
- #endif /* HELIX_FEATURE_HTTPCLOAK */
- #include "hxheap.h"
- #include "hxprefs.h"
- #include "hxprefutil.h"
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif
- #ifdef _WIN16
- extern HINSTANCE g_hInstance; // initialized inside DLLMAIN.CPP(core.dll)
- #endif
- const int UDP_CHUNK_SIZE = 1024;
- #define QUEUE_START_SIZE 512
- #if defined _WINDOWS && !defined _WIN32 // for win16
- #define DESIRED_RCV_BUFSIZE 0xFFFF // ~ 525 KBits
- #else
- #define DESIRED_RCV_BUFSIZE 0x0002FFFF // ~ 1.5 MBits
- #endif //defined _WINDOWS && !defined _WIN32
- #ifdef _WINCE
- #define SCHED_GRANULARITY 10
- #else
- #define SCHED_GRANULARITY 50
- #endif
- // same for all the platforms...may need to tweak it, if necessary
- #define MAX_ITERATION_COUNT 200
- #if defined( _UNIX )
- BOOL ReadAsyncDNSPref( IUnknown* pContext )
- {
- static BOOL bNoAsyncDNS = FALSE;
- static BOOL bNeedToLoad = TRUE;
- if( bNeedToLoad && NULL!=pContext)
- {
- IHXPreferences* pPreferences = NULL;
- bNeedToLoad = FALSE;
- pContext->QueryInterface(IID_IHXPreferences, (void **)&pPreferences);
- IHXBuffer *pBuffer = NULL;
- if( NULL!=pPreferences )
- {
- pPreferences->ReadPref("NoAsyncDNS", pBuffer);
- if (pBuffer)
- {
- bNoAsyncDNS = (atoi((const char*)pBuffer->GetBuffer()) == 1);
- HX_RELEASE(pBuffer);
- }
- HX_RELEASE( pPreferences );
- } // NULL!=pPreferences
- }//bNeedToLoad && NULL!=pContext
- return bNoAsyncDNS;
- }
- BOOL ReadThreadedDNSPref( IUnknown* pContext )
- {
- static BOOL bThreadedDNS = TRUE;
- static BOOL bNeedToLoad = TRUE;
- if( bNeedToLoad && NULL!=pContext)
- {
- IHXPreferences* pPreferences = NULL;
- bNeedToLoad = FALSE;
- pContext->QueryInterface(IID_IHXPreferences, (void **)&pPreferences);
- IHXBuffer *pBuffer = NULL;
- if( NULL!=pPreferences )
- {
- pPreferences->ReadPref("ThreadedDNS", pBuffer);
- if (pBuffer)
- {
- bThreadedDNS = (atoi((const char*)pBuffer->GetBuffer()) == 1);
- HX_RELEASE(pBuffer);
- }
- else
- {
- //XXXGFW HACK!! REMOVE AFTER RNC
- //Pref was not found. It defaults to ON now so lets see if we
- //are running under a player. If not, turn it off.
- IHXClientEngine* pEngine = NULL;
- if(HXR_OK == pContext->QueryInterface(IID_IHXClientEngine, (void**)&pEngine))
- {
- //We have client Engine. Do nothing.
- HX_RELEASE( pEngine );
- }
- else
- {
- //We don't have a client engine. Turn off threading...
- bThreadedDNS = FALSE;
- }
- }
- HX_RELEASE( pPreferences );
- } // NULL!=pPreferences
- }//bNeedToLoad && NULL!=pContext
- return bThreadedDNS;
- }
- #endif
- #if !defined(HELIX_CONFIG_NOSTATICS)
- UINT16 HXNetworkServices::z_muNumDriverInstance = 0;
- #else
- #include "globals/hxglobals.h"
- const UINT16 HXNetworkServices::z_muNumDriverInstance = 0;
- #endif
- /* HXNetworkServices */
- HXNetworkServices::HXNetworkServices(IUnknown* pContext)
- {
- m_bNeedToCleanupDrivers = FALSE;
- m_lRefCount = 0;
- m_pContext = pContext;
- if (m_pContext)
- {
- m_pContext->AddRef();
- }
- }
- HXNetworkServices::~HXNetworkServices()
- {
- Close();
- }
- STDMETHODIMP HXNetworkServices::QueryInterface(REFIID riid, void** ppvObj)
- {
- QInterfaceList qiList[] =
- {
- { GET_IIDHANDLE(IID_IHXNetworkServices), (IHXNetworkServices*)this },
- { GET_IIDHANDLE(IID_IHXNetworkInterfaceEnumerator), (IHXNetworkInterfaceEnumerator*)this },
- #if defined(HELIX_FEATURE_HTTPCLOAK)
- { GET_IIDHANDLE(IID_IHXCloakedNetworkServices), (IHXCloakedNetworkServices*)this },
- #endif /* HELIX_FEATURE_HTTPCLOAK */
- { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXNetworkServices*)this },
- };
- return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
- }
- STDMETHODIMP_(ULONG32) HXNetworkServices::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- STDMETHODIMP_(ULONG32) HXNetworkServices::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- void
- HXNetworkServices::UseDrivers()
- {
- if (!m_bNeedToCleanupDrivers)
- {
- m_bNeedToCleanupDrivers = TRUE;
- #if defined(HELIX_CONFIG_NOSTATICS)
- UINT16& z_muNumDriverInstance = (UINT16&)
- HXGlobalInt16::Get(&HXNetworkServices::z_muNumDriverInstance);
- #endif
- z_muNumDriverInstance++;
- }
- }
- void
- HXNetworkServices::Close()
- {
- HX_RELEASE(m_pContext);
- if (m_bNeedToCleanupDrivers)
- {
- m_bNeedToCleanupDrivers = FALSE;
- #if defined(HELIX_CONFIG_NOSTATICS)
- UINT16& z_muNumDriverInstance = (UINT16&)
- HXGlobalInt16::Get(&HXNetworkServices::z_muNumDriverInstance);
- #endif
- z_muNumDriverInstance--;
- if (z_muNumDriverInstance == 0)
- {
- #if defined(THREADS_SUPPORTED)
- ThreadEngine::DestroyThreadEngine();
- #elif defined(_UNIX_THREADED_NETWORK_IO)
- if( ReadNetworkThreadingPref((IUnknown*)m_pContext) )
- ThreadEngine::DestroyThreadEngine();
- #endif
- conn::close_drivers(NULL);
- }
- }
- }
- STDMETHODIMP
- HXNetworkServices::CreateTCPSocket(IHXTCPSocket** ppTCPSocket)
- {
- *ppTCPSocket = new HXTCPSocket(m_pContext, this);
- if (*ppTCPSocket == NULL)
- {
- return HXR_OUTOFMEMORY;
- }
- (*ppTCPSocket)->AddRef();
- return HXR_OK;
- }
- STDMETHODIMP
- HXNetworkServices::CreateUDPSocket(IHXUDPSocket** ppUDPSocket)
- {
- *ppUDPSocket = new HXUDPSocket(m_pContext, this);
- if (*ppUDPSocket == NULL)
- {
- return HXR_OUTOFMEMORY;
- }
- (*ppUDPSocket)->AddRef();
- return HXR_OK;
- }
- STDMETHODIMP
- HXNetworkServices::CreateListenSocket(IHXListenSocket** ppListenSocket)
- {
- *ppListenSocket = new HXListenSocket(m_pContext, this);
- if (*ppListenSocket == NULL)
- {
- return HXR_OUTOFMEMORY;
- }
- (*ppListenSocket)->AddRef();
- return HXR_OK;
- }
- STDMETHODIMP
- HXNetworkServices::CreateResolver(IHXResolver** ppResolver)
- {
- *ppResolver = new HXResolver(this, m_pContext);
- if(*ppResolver == NULL)
- {
- return HXR_OUTOFMEMORY;
- }
- (*ppResolver)->AddRef();
- return HXR_OK;
- }
- STDMETHODIMP
- HXNetworkServices::CreateClientCloakedSocket(IHXTCPSocket** ppTCPSocket)
- {
- #if defined(HELIX_FEATURE_HTTPCLOAK)
- *ppTCPSocket = new HXClientCloakedTCPSocket(m_pContext);
- if (*ppTCPSocket == NULL)
- {
- return HXR_OUTOFMEMORY;
- }
- (*ppTCPSocket)->AddRef();
- return HXR_OK;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_HTTPCLOAK */
- }
- STDMETHODIMP
- HXNetworkServices::CreateServerCloakedSocket(IHXListenSocket** ppListenSocket)
- {
- return HXR_NOTIMPL;
- }
- /* IHXNetworkInterfaceEnumerator */
- STDMETHODIMP
- HXNetworkServices::EnumerateInterfaces
- (REF(UINT32*) pulInterfaces, REF(UINT32) ulNumInterfaces)
- {
- return conn::EnumerateInterfaces(pulInterfaces, ulNumInterfaces);
- }
- /* HXResolver */
- HXResolver::HXResolver(HXNetworkServices* pNetworkServices):
- m_lRefCount(0)
- ,m_pCallback(0)
- ,m_pResp(0)
- ,m_bResolverPending(FALSE)
- ,m_pData(0)
- ,m_pNetworkServices(NULL)
- {
- m_pNetworkServices = pNetworkServices;
- m_pNetworkServices->AddRef();
- }
- HXResolver::HXResolver( HXNetworkServices* pNetworkServices,
- IUnknown* pContext):
- m_lRefCount(0)
- ,m_pCallback(0)
- ,m_pResp(0)
- ,m_bResolverPending(FALSE)
- ,m_pData(0)
- ,m_pNetworkServices(NULL)
- ,m_pContext( pContext )
- {
- m_pNetworkServices = pNetworkServices;
- m_pNetworkServices->AddRef();
- }
- HXResolver::~HXResolver()
- {
- if (m_pData)
- {
- m_pData->done();
- m_pData->Release();
- m_pData = 0;
- }
- if (m_pCallback)
- {
- delete m_pCallback;
- m_pCallback = 0;
- }
- if (m_pResp)
- {
- m_pResp->Release();
- m_pResp = 0;
- }
- #if defined( _WIN32 ) || defined( _WINDOWS )
- win_net::ReleaseWinsockUsage(this);
- #endif
- HX_RELEASE(m_pNetworkServices);
- }
- STDMETHODIMP
- HXResolver::QueryInterface(REFIID riid, void** ppvObj)
- {
- QInterfaceList qiList[] =
- {
- { GET_IIDHANDLE(IID_IHXResolver), (IHXResolver*)this },
- { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXResolver*)this },
- };
- return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
- }
- STDMETHODIMP_(ULONG32) HXResolver::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- STDMETHODIMP_(ULONG32) HXResolver::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- STDMETHODIMP HXResolver::Init(IHXResolverResponse* pResp)
- {
- if (!pResp)
- {
- return HXR_UNEXPECTED;
- }
- if (m_pResp)
- {
- m_pResp->Release();
- m_pResp = 0;
- }
- m_pResp = pResp;
- m_pResp->AddRef();
- return HXR_OK;
- }
- STDMETHODIMP HXResolver::GetHostByName(const char* pHostName)
- {
- HX_RESULT theErr = HXR_OK;
- if (!pHostName || m_bResolverPending)
- {
- return HXR_UNEXPECTED;
- }
- if (!m_pCallback)
- {
- m_pCallback = new HXResolverCallback;
- if (!m_pCallback)
- {
- return HXR_OUTOFMEMORY;
- }
- m_pCallback->m_pContext = this;
- }
- /* Is this the first time we are calling gethostbyname */
- if (!m_pData)
- {
- #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();
- conn::init_drivers(NULL);
- }
- if (m_pData)
- {
- m_pData->done();
- m_pData->Release();
- m_pData = 0;
- }
- #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
- m_pData = conn::new_socket(HX_UDP_SOCKET);
- if (!m_pData)
- {
- return HXR_OUTOFMEMORY;
- }
- #ifdef _UNIX
- m_pData->SetAsyncDNSPref( ReadAsyncDNSPref((IUnknown*)m_pContext) );
- #endif
- // XXXAAK -- local addr binding stuff
- theErr = m_pData->init(INADDR_ANY, 0);
- m_pData->nonblocking();
- m_pData->set_callback(m_pCallback);
- #ifdef _WINDOWS
- #if defined (_WIN32)
- ULONG32 ulPlatformData = (ULONG32)GetModuleHandle(NULL);
- #elif defined (_WIN16)
- ULONG32 ulPlatformData = (ULONG32)(int)g_hInstance;
- #endif
- m_pData->SetWindowHandle(ulPlatformData);
- #endif /* defined (_WINDOWS) */
- m_bResolverPending = TRUE;
- #ifndef _WINCE
- m_pData->dns_find_ip_addr(pHostName);
- #else
- // Only blocking DNS
- m_pData->dns_find_ip_addr(pHostName, 1);
- #endif
- return HXR_OK;
- }
- void
- HXResolver::DNSDone(BOOL bSuccess)
- {
- ULONG32 ulAddr = 0;
- BOOL bIsValid = TRUE;
- char* pDottedIP = 0;
- m_bResolverPending = FALSE;
- AddRef();
- if (bSuccess)
- {
- m_pData->dns_ip_addr_found(&bIsValid, &ulAddr);
- UINT32 ulHostAddr = DwToHost(ulAddr);
- m_pResp->GetHostByNameDone(HXR_OK, ulHostAddr);
- }
- else
- {
- m_pResp->GetHostByNameDone(HXR_DNR, 0);
- }
- Release();
- }
- HX_RESULT
- HXResolver::HXResolverCallback::Func(NotificationType Type,
- BOOL bSuccess, conn* pConn)
- {
- if(m_pContext)
- {
- switch (Type)
- {
- case DNS_NOTIFICATION:
- m_pContext->DNSDone(bSuccess);
- break;
- case READ_NOTIFICATION:
- case WRITE_NOTIFICATION:
- case CONNECT_NOTIFICATION:
- default:
- break;
- }
- }
- return HXR_OK;
- }
- /* HXTCPSocket */
- HXTCPSocket::HXTCPSocket(IUnknown* pContext, HXNetworkServices* pNetworkServices):
- m_lRefCount(0)
- ,m_pTCPResponse(0)
- ,m_pCtrl(0)
- ,m_lForeignAddress(0)
- ,m_nForeignPort(0)
- ,m_bReadPending(FALSE)
- ,m_nRequired(0)
- ,mSendTCP(0)
- ,mReceiveTCP(0)
- ,m_pBuffer(0)
- ,m_pCallback(0)
- ,m_bConnected(FALSE)
- ,m_bWantWritePending(FALSE)
- ,m_bInitComplete(FALSE)
- ,m_bWriteFlushPending(FALSE)
- ,m_pScheduler(0)
- ,m_pSchedulerReadCallback(0)
- ,m_pSchedulerWriteCallback(0)
- ,m_bInRead(FALSE)
- ,m_bInWrite(FALSE)
- ,m_bInDoRead(FALSE)
- ,m_pInterruptState(NULL)
- ,m_pResponseInterruptSafe(NULL)
- ,m_pMutex(NULL)
- ,m_bInDestructor(FALSE)
- ,m_pNonInterruptReadCallback(NULL)
- ,m_pNetworkServices(NULL)
- ,m_pPreferences(NULL)
- ,m_bReuseAddr(FALSE)
- ,m_bReusePort(FALSE)
- ,m_pContext(pContext)
- ,m_bSecureSocket(FALSE)
- {
- m_pNetworkServices = pNetworkServices;
- m_pNetworkServices->AddRef();
- #ifdef _MACINTOSH
- m_pInterruptSafeMacWriteQueue = new InterruptSafeMacQueue();
- HX_ASSERT(m_pInterruptSafeMacWriteQueue != NULL);
- #endif
- if (pContext)
- {
- pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
- pContext->QueryInterface(IID_IHXInterruptState, (void**) &m_pInterruptState);
- pContext->QueryInterface(IID_IHXPreferences, (void**) &m_pPreferences);
- }
- 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();
- #ifdef _MACINTOSH
- m_pMacCommandCallback = new ScheduledSocketCallback(this, FALSE);
- m_pMacCommandCallback->AddRef();
- #endif
- }
- #if defined(_UNIX) && defined(HELIX_FEATURE_IGNORE_SIGPIPE)
- // When the connection is closed by the server, SIGPIPE will be thrown
- // in next write() and terminates the program abruptly.
- //
- // In order to gracefully exists the program, it's recommended to:
- // - ignore the SIGPIPE and
- // - checks the return code(errno) from write()
- //
- // for read(), it simply returns 0 when the connection is closed.
- SIGNAL(SIGPIPE, SIG_IGN);
- #endif /* _UNIX && HELIX_FEATURE_IGNORE_SIGPIPE */
- #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
- }
- HXTCPSocket::~HXTCPSocket()
- {
- m_bInDestructor = TRUE; // set it early
- 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);
- #ifdef _MACINTOSH
- if (m_pMacCommandCallback)
- m_pMacCommandCallback->Unschedule(m_pScheduler);
- #endif
- /*
- * XXX...While handling the m_pCtrl->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;
- }
- //#ifndef _UNIX
- /* XXXJR I feel certain this is related to the above comment somehow.
- * Deleting the ctrl here wreaks havoc on the encoder.
- * This is a bad solution, but I don't really know
- * what the right one is. This at least prevents random crashes
- * in the encoder.
- *
- * XXXGH commented out the #ifndef because it was breaking my
- * connectionless control stuff
- *
- */
- if (m_pCtrl)
- {
- m_pCtrl->done();
- m_pCtrl->Release(); // A deleted (0xdddddddd) pointer was used here.
- m_pCtrl = 0;
- }
- //#endif
- HX_RELEASE(m_pTCPResponse);
- HX_DELETE(m_pCallback);
- HX_DELETE(mSendTCP);
- HX_DELETE(mReceiveTCP);
- HX_VECTOR_DELETE(m_pBuffer);
- while (m_PendingWriteBuffers.GetCount() > 0)
- {
- IHXBuffer* pBuffer =
- (IHXBuffer*) m_PendingWriteBuffers.RemoveHead();
- pBuffer->Release();
- }
- 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;
- }
- #ifdef _MACINTOSH
- if (m_pMacCommandCallback)
- {
- m_pMacCommandCallback->m_pSocket = NULL;
- m_pMacCommandCallback->Release();
- m_pMacCommandCallback = NULL;
- }
- #endif
- HX_RELEASE(m_pInterruptState);
- HX_RELEASE(m_pResponseInterruptSafe);
- HX_RELEASE(m_pScheduler);
- m_pMutex->Unlock();
- HX_DELETE(m_pMutex);
- #if defined( _WIN32 ) || defined( _WINDOWS )
- win_net::ReleaseWinsockUsage(this);
- #endif
- HX_RELEASE(m_pNetworkServices);
- HX_RELEASE(m_pPreferences);
- }
- STDMETHODIMP HXTCPSocket::QueryInterface(REFIID riid, void** ppvObj)
- {
- QInterfaceList qiList[] =
- {
- { GET_IIDHANDLE(IID_IHXTCPSocket), (IHXTCPSocket*)this },
- { GET_IIDHANDLE(IID_IHXSetSocketOption), (IHXSetSocketOption*)this },
- { GET_IIDHANDLE(IID_IHXTCPSecureSocket), (IHXTCPSecureSocket*)this },
- { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXTCPSocket*)this },
- };
- return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
- }
- STDMETHODIMP_(ULONG32) HXTCPSocket::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- STDMETHODIMP_(ULONG32) HXTCPSocket::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- else if (m_lRefCount < 0)
- {
- // double delete
- return 0;
- }
- delete this;
- return 0;
- }
- STDMETHODIMP HXTCPSocket::Init(IHXTCPResponse* pTCPResponse)
- {
- if (!pTCPResponse)
- {
- return HXR_UNEXPECTED;
- }
- m_pTCPResponse = pTCPResponse;
- m_pTCPResponse->AddRef();
- m_pTCPResponse->QueryInterface(IID_IHXInterruptSafe,
- (void**) &m_pResponseInterruptSafe);
- // allocate TCP send and receive queue
- mSendTCP = new CByteGrowingQueue(QUEUE_START_SIZE,1);
- if (!mSendTCP || !mSendTCP->IsQueueValid())
- {
- return HXR_OUTOFMEMORY;
- }
- mSendTCP->SetMaxSize(TCP_BUF_SIZE);
- mReceiveTCP = new CByteGrowingQueue(QUEUE_START_SIZE,1);
- if (!mReceiveTCP || !mReceiveTCP->IsQueueValid())
- {
- return HXR_OUTOFMEMORY;
- }
- mReceiveTCP->SetMaxSize(TCP_BUF_SIZE);
- m_pBuffer = new char[TCP_BUF_SIZE];
- if (!m_pBuffer)
- {
- return HXR_OUTOFMEMORY;
- }
- return HXR_OK;
- }
- STDMETHODIMP HXTCPSocket::SetResponse(IHXTCPResponse* pTCPResponse)
- {
- m_pMutex->Lock();
- HX_RELEASE(m_pTCPResponse);
- m_pTCPResponse = pTCPResponse;
- m_pTCPResponse->AddRef();
- HX_RELEASE(m_pResponseInterruptSafe);
- m_pTCPResponse->QueryInterface(IID_IHXInterruptSafe,
- (void**) &m_pResponseInterruptSafe);
- m_pMutex->Unlock();
- return HXR_OK;
- }
- STDMETHODIMP HXTCPSocket::Bind(UINT32 ulLocalAddr, UINT16 nPort)
- {
- UINT32 ulMaxBandwidth = 0;
- BOOL bEnforceMaxBandwidth = TRUE;
- BOOL bLoadTest = FALSE;
- IHXBuffer* pBuffer = NULL;
- if (m_bInitComplete)
- return HXR_UNEXPECTED;
- m_nLocalPort = nPort;
- #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();
- HX_RESULT theErr = conn::init_drivers(NULL);
- #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
- m_pCtrl = NULL;
- #if defined(HELIX_FEATURE_SECURECONN)
- if (m_bSecureSocket)
- {
- IHXSSL* pHXSSL = NULL;
- IHXCommonClassFactory* pCCF = NULL;
- if (m_pContext)
- {
- m_pContext->AddRef();
- // get the CCF
- m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&pCCF);
- HX_RELEASE(m_pContext);
- }
- if (pCCF)
- {
- pCCF->CreateInstance(IID_IHXSSL, (void**) &pHXSSL);
- HX_RELEASE(pCCF);
- }
- if (pHXSSL)
- {
- m_pCtrl = new secureconn(pHXSSL);
- pHXSSL->Release();
- }
- }
- else
- #endif /* HELIX_FEATURE_SECURECONN */
- {
- m_pCtrl = conn::new_socket(HX_TCP_SOCKET);
- }
- if (!m_pCtrl)
- {
- return HXR_OUTOFMEMORY;
- }
- // XXXGo - As it is implemented, this is the only way...
- if (m_bReuseAddr)
- {
- if (m_pCtrl->reuse_addr(m_bReuseAddr) != HXR_OK)
- {
- // err...what do we need to do?
- HX_ASSERT(!"reuse_addr() failed");
- }
- }
- if (m_bReusePort)
- {
- if (m_pCtrl->reuse_port(m_bReusePort) != HXR_OK)
- {
- // err...what do we need to do?
- HX_ASSERT(!"reuse_port() failed");
- }
- }
- #ifdef _UNIX
- m_pCtrl->SetAsyncDNSPref( ReadAsyncDNSPref((IUnknown*)m_pContext) );
- #endif
- m_pCtrl->nonblocking();
- m_pCallback = new TCPSocketCallback;
- if (!m_pCallback)
- {
- return HXR_OUTOFMEMORY;
- }
- m_pCallback->m_pContext = this;
- m_pCtrl->set_callback(m_pCallback);
- m_bInitComplete = TRUE;
- if (m_pPreferences)
- {
- /* Get MaxBandwidth from Prefs */
- ReadPrefINT32(m_pPreferences, "MaxBandwidth", ulMaxBandwidth);
- ReadPrefBOOL(m_pPreferences, "LoadTest", bLoadTest);
- ReadPrefBOOL(m_pPreferences, "EnforceMaxBandwidth", bEnforceMaxBandwidth);
- //If we are in load test mode, never enforce the MaxBandwidth.
- bEnforceMaxBandwidth = bEnforceMaxBandwidth&&!bLoadTest;
- if (ulMaxBandwidth && bEnforceMaxBandwidth)
- {
- conn::m_ulMaxBandwidth = ulMaxBandwidth / 8;
- }
- else if (!bEnforceMaxBandwidth)
- {
- conn::m_ulMaxBandwidth = MAX_UINT32;
- }
- }
- return HXR_OK;
- }
- STDMETHODIMP HXTCPSocket::Connect(const char* pDestination,
- UINT16 nPort)
- {
- if (!m_bInitComplete)
- {
- HX_RESULT ret = Bind(HXR_INADDR_ANY, 0);
- if (HXR_OK != ret)
- return ret;
- }
- HX_RESULT theErr = HXR_OK;
- UINT32 ulPlatformData = 0;
- #if defined (_WIN32)
- ulPlatformData = (UINT32)GetModuleHandle(NULL);
- #elif defined (_WIN16)
- ulPlatformData = (UINT32)(int)g_hInstance;
- #endif
- m_nForeignPort = nPort;
- #ifndef _WINCE
- theErr = m_pCtrl->connect(pDestination,nPort,0,ulPlatformData);
- #else
- theErr = m_pCtrl->connect(pDestination,nPort,1,ulPlatformData);
- #endif
- theErr = ConvertNetworkError(theErr);
- return theErr;
- }
- STDMETHODIMP HXTCPSocket::Read(UINT16 uSize)
- {
- HX_RESULT theErr = HXR_OK;
- HX_RESULT lResult = HXR_OK;
- if (m_bReadPending)
- {
- return HXR_UNEXPECTED;
- }
- m_bReadPending = TRUE;
- m_nRequired = uSize;
- m_pMutex->Lock();
- theErr = DoRead();
- m_pMutex->Unlock();
- lResult = ConvertNetworkError(theErr);
- return lResult;
- }
- STDMETHODIMP HXTCPSocket::Write(IHXBuffer* pBuffer)
- {
- HX_RESULT theErr = HXR_OK;
- HX_RESULT lResult = HXR_OK;
- #ifdef _MACINTOSH
- if (m_pInterruptSafeMacWriteQueue)
- m_pInterruptSafeMacWriteQueue->AddTail(pBuffer); // AddRef called inside
- #else
- pBuffer->AddRef();
- m_PendingWriteBuffers.AddTail((void*) pBuffer);
- /* Transfer pending buffers to TCP send queue */
- TransferBuffers();
- #endif
- m_pMutex->Lock();
- theErr = DoWrite();
- m_pMutex->Unlock();
- lResult = ConvertNetworkError(theErr);
- return lResult;
- }
- STDMETHODIMP HXTCPSocket::WantWrite()
- {
- if (mSendTCP->GetQueuedItemCount() == 0)
- {
- m_pTCPResponse->WriteReady(HXR_OK);
- }
- else
- {
- m_bWantWritePending = TRUE;
- }
- return HXR_OK;
- }
- STDMETHODIMP HXTCPSocket::GetLocalAddress(ULONG32& lAddress)
- {
- return HXR_NOTIMPL;
- }
- STDMETHODIMP HXTCPSocket::GetForeignAddress(ULONG32& lAddress)
- {
- if(m_bConnected && m_lForeignAddress)
- {
- lAddress = m_lForeignAddress;
- return HXR_OK;
- }
- return HXR_FAIL;
- }
- STDMETHODIMP HXTCPSocket::GetLocalPort(UINT16& port)
- {
- return HXR_NOTIMPL;
- }
- STDMETHODIMP HXTCPSocket::GetForeignPort(UINT16& port)
- {
- if(m_bConnected)
- {
- port = m_nForeignPort;
- return HXR_OK;
- }
- return HXR_FAIL;
- }
- // the tcp socket will still need to be inited
- STDMETHODIMP
- HXTCPSocket::AcceptConnection(conn* pNewConn)
- {
- HX_ASSERT(!m_bConnected);
- HX_ASSERT(!m_bInitComplete);
- HX_ASSERT(m_pCtrl == NULL);
- m_pCtrl = pNewConn;
- m_pCtrl->AddRef();
- m_pCtrl->nonblocking();
- if ( m_pCallback )
- {
- HX_DELETE(m_pCallback);
- }
- m_pCallback = new TCPSocketCallback;
- if ( !m_pCallback )
- {
- return HXR_OUTOFMEMORY;
- }
- m_pCallback->m_pContext = this;
- m_pCtrl->set_callback(m_pCallback);
- m_lForeignAddress = DwToHost(m_pCtrl->get_addr());
- m_bInitComplete = TRUE;
- m_bConnected = TRUE;
- return HXR_OK;
- }
- HX_RESULT
- HXTCPSocket::DoRead()
- {
- #ifdef _MACINTOSH
- if (m_bInDoRead)
- {
- return HXR_OK; // whatever needs to be done will be done by the caller that's already here.
- // xxxbobclark the m_bInDoRead flag is hacked around calling ReadDone(), because
- // ReadDone() may call Read() which in turn calls us here, and we do
- // not want to bail out in that instance. (Otherwise we only remove
- // one packet at a time, which, given the scheduler granularity and
- // high bit rates, implies that our bandwidth would be too low.)
- }
- #endif
- m_bInDoRead = TRUE;
- HX_RESULT theErr = HXR_OK;
- // check how much room we have in TCP receive queue
- UINT16 count = mReceiveTCP->GetMaxAvailableElements();
- if (count > 0)
- {
- #if !defined(THREADS_SUPPORTED) && !defined(_UNIX_THREADED_NETWORK_IO)
- UINT32 ulBytesToRead = conn::bytes_to_preparetcpread(m_pCtrl);
- if (ulBytesToRead > 0)
- {
- if ((UINT32)count > ulBytesToRead)
- {
- count = (UINT16)ulBytesToRead;
- }
- // attempt to read data from TCP link
- theErr = m_pCtrl->read(m_pBuffer, &count);
- if (!theErr && count > 0)
- {
- conn::bytes_to_actualtcpread(m_pCtrl, (UINT32)count);
- mReceiveTCP->EnQueue(m_pBuffer, count);
- }
- else if (theErr)
- {
- theErr = ConvertNetworkError(theErr);
- }
- }
- #elif defined(_UNIX_THREADED_NETWORK_IO)
- //XXXgfw duplicated code. Clean this up...
- if( ReadNetworkThreadingPref((IUnknown*)m_pContext) )
- {
- // in THREADS_SUPPORTED mode, this will be taken care by the thrdconn.cpp
- // attempt to read data from TCP link
- theErr = m_pCtrl->read(m_pBuffer, &count);
- if (!theErr && count > 0)
- {
- mReceiveTCP->EnQueue(m_pBuffer, count);
- }
- else if (theErr)
- {
- theErr = ConvertNetworkError(theErr);
- }
- }
- else
- {
- UINT32 ulBytesToRead = conn::bytes_to_preparetcpread(m_pCtrl);
- if (ulBytesToRead > 0)
- {
- if ((UINT32)count > ulBytesToRead)
- {
- count = (UINT16)ulBytesToRead;
- }
- // attempt to read data from TCP link
- theErr = m_pCtrl->read(m_pBuffer, &count);
- if (!theErr && count > 0)
- {
- conn::bytes_to_actualtcpread(m_pCtrl, (UINT32)count);
- mReceiveTCP->EnQueue(m_pBuffer, count);
- }
- else if (theErr)
- {
- theErr = ConvertNetworkError(theErr);
- }
- }
- }
- #else
- // in THREADS_SUPPORTED mode, this will be taken care by the thrdconn.cpp
- // attempt to read data from TCP link
- theErr = m_pCtrl->read(m_pBuffer, &count);
- if (!theErr && count > 0)
- {
- mReceiveTCP->EnQueue(m_pBuffer, count);
- }
- else if (theErr)
- {
- theErr = ConvertNetworkError(theErr);
- }
- #endif /* !THREADS_SUPPORTED */
- }
- count = mReceiveTCP->GetQueuedItemCount();
- if (m_bReadPending && count > 0)
- {
- /* If we are at interrupt time and the response object is not interrupt safe,
- * schedule a callback to return back the data
- */
- if (!IsSafe())
- {
- m_bInDoRead = FALSE;
- return HXR_OK;
- }
- m_bReadPending = FALSE;
- if (m_nRequired < count)
- {
- // XXXAAK -- UINT32 down to UINT16 - possible truncation???
- count = (UINT16)m_nRequired;
- }
- CHXBuffer* pBuffer = new CHXBuffer;
- pBuffer->AddRef();
- mReceiveTCP->DeQueue(m_pBuffer, count);
- pBuffer->Set((UCHAR*) m_pBuffer, count);
- m_bInDoRead = FALSE;
- theErr = m_pTCPResponse->ReadDone(HXR_OK, pBuffer);
- m_bInDoRead = TRUE;
- pBuffer->Release();
- /* mask any kind of errors */
- // Huh??? Don't mask OUTOFMEMORY errors!
- if( theErr != HXR_OUTOFMEMORY )
- {
- theErr = HXR_OK;
- }
- }
- if (theErr && m_bReadPending)
- {
- /* If we are at interrupt time and the response object is not interrupt safe,
- * schedule a callback to return back the data
- */
- if (!IsSafe())
- {
- m_bInDoRead = FALSE;
- return HXR_OK;
- }
- #ifdef _MACINTOSH
- if (m_pMacCommandCallback && m_pMacCommandCallback->ScheduleCallback(TCP_READ_DONE_COMMAND, m_pScheduler, 0, theErr))
- {
- m_bReadPending = FALSE;
- m_bInDoRead = FALSE;
- return HXR_OK;
- }
- else
- {
- // failed to schedule a callback, notify the responser with error directly
- m_bReadPending = FALSE;
- m_pTCPResponse->ReadDone(theErr, NULL);
- }
- #else
- m_bReadPending = FALSE;
- m_pTCPResponse->ReadDone(theErr, NULL);
- #endif
- }
- if (!theErr &&
- m_bReadPending &&
- m_pSchedulerReadCallback)
- {
- m_pSchedulerReadCallback->ScheduleCallback(TCP_READ_COMMAND, m_pScheduler, SCHED_GRANULARITY);
- }
- m_bInDoRead = FALSE;
- return theErr;
- }
- HX_RESULT
- HXTCPSocket::DoWrite()
- {
- HX_RESULT theErr = HXR_OK;
- if (m_bInWrite) return HXR_OK;
- m_bInWrite = TRUE;
- #ifdef _MACINTOSH
- if (m_pInterruptSafeMacWriteQueue)
- m_pInterruptSafeMacWriteQueue->TransferToSimpleList(m_PendingWriteBuffers);
- TransferBuffers(); // PENDING_BUFFERS_ARE_EMPTIED_AT_START_OF_DO_WRITE
- #endif
- // check how data we have in TCP send queue
- UINT16 count = mSendTCP->GetQueuedItemCount();
- UINT16 actual = count;
- if(count > 0)
- {
- mSendTCP->DeQueue(m_pBuffer,count);
- theErr = m_pCtrl->write(m_pBuffer, &actual);
- }
- switch(theErr)
- {
- case HXR_AT_INTERRUPT:
- case HXR_WOULD_BLOCK:
- case HXR_OK:
- // enqueue the data that was not sent
- if(actual != count)
- {
- mSendTCP->EnQueue(m_pBuffer + actual, count - actual);
- }
- // mask out these errors
- theErr = HXR_OK;
- break;
- default:
- theErr = ConvertNetworkError(theErr);
- break;
- }
- if (!theErr && m_bWantWritePending && mSendTCP->GetQueuedItemCount() == 0)
- {
- m_bWantWritePending = FALSE;
- m_pTCPResponse->WriteReady(HXR_OK);
- }
- #ifndef _MACINTOSH
- // m_PendingWriteBuffers will always be empty due to the full buffer transfer at the top of this routine.
- // see PENDING_BUFFERS_ARE_EMPTIED_AT_START_OF_DO_WRITE
- if (!theErr && m_PendingWriteBuffers.GetCount() > 0)
- {
- TransferBuffers();
- }
- #endif
- if (!theErr &&
- ((mSendTCP && mSendTCP->GetQueuedItemCount() > 0) ||
- m_PendingWriteBuffers.GetCount() > 0)) // see PENDING_BUFFERS_ARE_EMPTIED_AT_START_OF_DO_WRITE
- {
- if (m_pSchedulerWriteCallback)
- {
- m_pSchedulerWriteCallback->ScheduleCallback(TCP_WRITE_COMMAND, m_pScheduler, SCHED_GRANULARITY);
- }
- }
- if (m_bWriteFlushPending &&
- ((mSendTCP->GetQueuedItemCount() == 0 &&
- m_PendingWriteBuffers.GetCount() == 0) ||
- theErr))
- {
- m_bWriteFlushPending = FALSE;
- Release();
- }
- else if (!theErr && !m_bWriteFlushPending &&
- (mSendTCP->GetQueuedItemCount() > 0 || m_PendingWriteBuffers.GetCount() > 0))
- {
- m_bWriteFlushPending = TRUE;
- AddRef();
- }
- m_bInWrite = FALSE;
- return theErr;
- }
- /* If we are at interrupt time and the response object is not interrupt safe,
- * schedule a callback to return back the data
- */
- BOOL
- HXTCPSocket::IsSafe()
- {
- if (m_pInterruptState && m_pInterruptState->AtInterruptTime() &&
- (!m_pResponseInterruptSafe ||
- !m_pResponseInterruptSafe->IsInterruptSafe()))
- {
- if (m_pNonInterruptReadCallback)
- {
- m_pNonInterruptReadCallback->ScheduleCallback(TCP_READ_COMMAND, m_pScheduler, 0);
- }
- return FALSE;
- }
- return TRUE;
- }
- void
- HXTCPSocket::ConnectDone(BOOL bResult)
- {
- AddRef();
- if (bResult == TRUE)
- {
- m_bConnected = TRUE;
- //XXX need to set m_lForeignAddr here
- //XXXJR hack!
- m_lForeignAddress = DwToHost(m_pCtrl->get_addr());
- m_pTCPResponse->ConnectDone(HXR_OK);
- }
- else
- {
- #ifdef _MACINTOSH
- if (!(m_pMacCommandCallback && m_pMacCommandCallback->ScheduleCallback(TCP_CONNECT_DONE_COMMAND, m_pScheduler, 0, HXR_NET_CONNECT)))
- {
- //note: only happens when there's a problem (e.g. macleod 1/2 server problem)
- m_pTCPResponse->ConnectDone(HXR_NET_CONNECT); // couldn't use the delayed callback... take our chances.
- }
- #else
- m_pTCPResponse->ConnectDone(HXR_NET_CONNECT);
- #endif
- }
- Release();
- }
- void
- HXTCPSocket::CloseDone()
- {
- m_pTCPResponse->Closed(HXR_OK);
- }
- void
- HXTCPSocket::DNSDone(BOOL bSuccess)
- {
- AddRef();
- if (!bSuccess)
- {
- m_pTCPResponse->ConnectDone(HXR_DNR);
- }
- Release();
- }
- void
- HXTCPSocket::TransferBuffers()
- {
- IHXBuffer* pBuffer = 0;
- while (m_PendingWriteBuffers.GetCount() > 0)
- {
- pBuffer = (IHXBuffer*) m_PendingWriteBuffers.GetHead();
- if ((UINT16) pBuffer->GetSize() < mSendTCP->GetMaxAvailableElements())
- {
- mSendTCP->EnQueue( pBuffer->GetBuffer(),
- (UINT16) pBuffer->GetSize());
- pBuffer->Release();
- m_PendingWriteBuffers.RemoveHead();
- }
- else
- {
- break;
- }
- }
- }
- STDMETHODIMP
- HXTCPSocket::SetOption(HX_SOCKET_OPTION option, UINT32 ulValue)
- {
- HX_RESULT res = HXR_OK;
- switch(option)
- {
- case HX_SOCKOPT_REUSE_ADDR:
- m_bReuseAddr = (BOOL)ulValue;
- break;
- case HX_SOCKOPT_REUSE_PORT:
- m_bReusePort = (BOOL)ulValue;
- break;
- case HX_SOCKOPT_MULTICAST_IF:
- res = HXR_UNEXPECTED;
- break;
- default:
- HX_ASSERT(!"I don't know this option");
- res = HXR_FAIL;
- }
- return res;
- }
- STDMETHODIMP
- HXTCPSocket::SetSecure(BOOL bSecure)
- {
- HX_RESULT res = HXR_OK;
- m_bSecureSocket = bSecure;
- return res;
- }
- STDMETHODIMP HXTCPSocket::HandleCallback(INT32 theCommand, HX_RESULT theError)
- {
- HX_RESULT theErr = HXR_OK;
- if (!m_bInDestructor)
- {
- AddRef();
- m_pMutex->Lock();
- if (!m_bInDestructor)
- {
- switch(theCommand)
- {
- case TCP_READ_COMMAND:
- theErr = DoRead();
- break;
- case TCP_WRITE_COMMAND:
- DoWrite(); // protected from re-entry by m_bInWrite
- break;
- case TCP_READ_DONE_COMMAND:
- m_bReadPending = FALSE;
- m_pTCPResponse->ReadDone(theError, NULL);
- break;
- case TCP_CONNECT_DONE_COMMAND:
- 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
- */
- return HXR_UNEXPECTED;
- }
- HX_RESULT theErr = HXR_OK;
- UINT32 ulPlatformData = 0;
- if (pUDPResponse != NULL)
- {
- HX_RELEASE(m_pUDPResponse);
- m_pUDPResponse = pUDPResponse;
- m_pUDPResponse->AddRef();
- }
- HX_RELEASE(m_pResponseInterruptSafe);
- m_pUDPResponse->QueryInterface(IID_IHXInterruptSafe,
- (void**) &m_pResponseInterruptSafe);
- m_sockAddr.sin_family = AF_INET;
- m_sockAddr.sin_addr.s_addr = DwToNet(ulAddr); //*(long*)&ulAddr;
- m_sockAddr.sin_port = WToNet(nPort);
- m_nDestPort = nPort;
- return HXR_OK;
- }
- STDMETHODIMP HXUDPSocket::Bind(UINT32 ulLocalAddr, UINT16 nPort)
- {
- if (m_bInitComplete)
- return HXR_UNEXPECTED;
- #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();
- HX_RESULT theErr = conn::init_drivers(NULL);
- if (theErr)
- {
- return (theErr);
- }
- theErr = HXR_OK;
- UINT32 ulPlatformData = 0;
- #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
- m_pData = conn::new_socket(HX_UDP_SOCKET);
- if (!m_pData)
- {
- return HXR_OUTOFMEMORY;
- }
- // XXXGo - As it is implemented, this is the only way...
- if (m_bReuseAddr)
- {
- if (m_pData->reuse_addr(m_bReuseAddr) != HXR_OK)
- {
- // err...what do we need to do?
- HX_ASSERT(!"reuse_addr() failed");
- }
- }
- if (m_bReusePort)
- {
- if (m_pData->reuse_port(m_bReusePort) != HXR_OK)
- {
- // err...what do we need to do?
- HX_ASSERT(!"reuse_port() failed");
- }
- }
- #ifdef _UNIX
- m_pData->SetAsyncDNSPref( ReadAsyncDNSPref((IUnknown*)m_pContext) );
- #endif
- // XXXST -- local addr binding stuff, removed dependency to m_nLocalPort
- // 0 for local port will make the system choose a free port
- theErr = m_pData->init(ulLocalAddr, nPort);
- if (theErr)
- {
- theErr = ConvertNetworkError(theErr);
- if (theErr)
- {
- m_pData->done();
- m_pData->Release();
- m_pData = 0;
- return theErr;
- }
- }
- m_pData->nonblocking();
- m_pData->set_receive_buf_size(DESIRED_RCV_BUFSIZE);
- if (!m_pCallback)
- {
- m_pCallback = new UDPSocketCallback;
- m_pCallback->m_pContext = this;
- }
- m_pData->set_callback(m_pCallback);
- #ifdef _WINDOWS
- #if defined (_WIN32)
- ulPlatformData = (UINT32)GetModuleHandle(NULL);
- #elif defined (_WIN16)
- ulPlatformData = (UINT32)(int)g_hInstance;
- #endif
- m_pData->SetWindowHandle(ulPlatformData);
- #endif /* defined (_WINDOWS) */
- if (m_pSchedulerReadCallback)
- {
- m_pSchedulerReadCallback->ScheduleCallback(UDP_BIND_COMMAND, m_pScheduler, SCHED_GRANULARITY);
- }
- m_bInitComplete = TRUE;
- return theErr;
- }
- STDMETHODIMP HXUDPSocket::Read(UINT16 nBytes)
- {
- if (!m_bInitComplete)
- {
- HX_RESULT ret = Bind(HXR_INADDR_ANY, 0);
- if (HXR_OK != ret)
- return HXR_UNEXPECTED;
- }
- HX_RESULT theErr = HXR_OK;
- if(m_bReadPending)
- {
- return HXR_UNEXPECTED;
- }
- m_bReadPending = TRUE;
- if (m_bInRead)
- {
- return HXR_OK;
- }
- m_bInRead = TRUE;
- m_pMutex->Lock();
- UINT16 uNumIterations = 0;
- do
- {
- theErr = DoRead();
- uNumIterations++;
- } while (m_bReadPending && !theErr && m_ReadBuffers.GetCount() > 0 && uNumIterations < MAX_ITERATION_COUNT);
- m_pMutex->Unlock();
- theErr = ConvertNetworkError(theErr);
- if (m_bReadPending && m_pSchedulerReadCallback)
- m_pSchedulerReadCallback->ScheduleCallback(UDP_READ_COMMAND, m_pScheduler, SCHED_GRANULARITY);
- m_bInRead = FALSE;
- return theErr;
- }
- STDMETHODIMP HXUDPSocket::Write(IHXBuffer* pBuffer)
- {
- if (!m_bInitComplete)
- {
- HX_RESULT ret = Bind(HXR_INADDR_ANY, 0);
- if (HXR_OK != ret)
- return HXR_UNEXPECTED;
- }
- HX_RESULT theErr = HXR_OK;
- HX_RESULT lResult = HXR_OK;
- #if 0
- struct in_addr in;
- in.s_addr = m_sockAddr.sin_addr.s_addr;
- char* address = inet_ntoa(in);
- printf("address = %s:", address);
- UINT32 port = ntohl(m_sockAddr.sin_port);
- printf("%dn", port);
- #endif /* 0 */
- #ifdef _MACINTOSH
- if (m_pInterruptSafeMacWriteQueue)
- m_pInterruptSafeMacWriteQueue->AddTail(pBuffer); // AddRef called inside
- #else
- pBuffer->AddRef();
- m_WriteBuffers.AddTail((void*) pBuffer);
- #endif
- m_pMutex->Lock();
- theErr = DoWrite();
- m_pMutex->Unlock();
- lResult = ConvertNetworkError(theErr);
- return lResult;
- }
- STDMETHODIMP HXUDPSocket::WriteTo(ULONG32 ulAddr,
- UINT16 nPort, IHXBuffer* pBuffer)
- {
- if (!m_bInitComplete)
- {
- HX_RESULT ret = Bind(HXR_INADDR_ANY, 0);
- if (HXR_OK != ret)
- return HXR_UNEXPECTED;
- }
- m_sockAddr.sin_family = AF_INET;
- m_sockAddr.sin_addr.s_addr = DwToNet(ulAddr); //*(long*)&ulAddr;
- m_sockAddr.sin_port = WToNet(nPort);
- return (Write(pBuffer));
- }
- STDMETHODIMP HXUDPSocket::GetLocalPort(UINT16& nPort)
- {
- // Get the local port from the socket info
- nPort = m_pData->get_local_port();
- return (INT16)nPort < 0 ? HXR_OK : HXR_FAIL;
- }
- STDMETHODIMP HXUDPSocket::JoinMulticastGroup(
- ULONG32 ulMulticastAddr,
- ULONG32 ulInterfaceAddr)
- {
- #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
- HX_RESULT theErr = HXR_OK;
- HX_RESULT lResult = HXR_OK;
- m_pMutex->Lock();
- theErr = m_pData->join_multicast_group(ulMulticastAddr, ulInterfaceAddr);
- lResult = ConvertNetworkError(theErr);
- m_pMutex->Unlock();
- return lResult;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
- }
- STDMETHODIMP HXUDPSocket::LeaveMulticastGroup(
- ULONG32 ulMulticastAddr,
- ULONG32 ulInterfaceAddr)
- {
- #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
- HX_RESULT theErr = HXR_OK;
- HX_RESULT lResult = HXR_OK;
- m_pMutex->Lock();
- theErr = m_pData->leave_multicast_group(ulMulticastAddr, ulInterfaceAddr);
- while (!m_ReadBuffers.IsEmpty())
- {
- UDP_PACKET* pPacket = (UDP_PACKET*)m_ReadBuffers.RemoveHead();
- HX_RELEASE(pPacket->pBuffer);
- HX_DELETE(pPacket);
- }
- lResult = ConvertNetworkError(theErr);
- m_pMutex->Unlock();
- return lResult;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
- }
- HX_RESULT
- HXUDPSocket::DoRead()
- {
- #ifdef _MACINTOSH
- if (m_bInDoRead)
- return HXR_OK; // whatever needs to be done will be done by the caller that's already here.
- // xxxbobclark the m_bInDoRead flag is hacked around calling ReadDone(), because
- // ReadDone() may call Read() which in turn calls us here, and we do
- // not want to bail out in that instance. (Otherwise we only remove
- // one packet at a time, which, given the scheduler granularity and
- // high bit rates, implies that our bandwidth would be too low.)
- #endif
- m_bInDoRead = TRUE;
- HX_RESULT theErr = HXR_OK;
- IHXBuffer* pBuffer = 0;
- UINT32 ulAddress = 0;
- UINT16 ulPort = 0;
- UINT16 count = 0;
- do
- {
- /*
- * Must reset count before every read
- */
- count = TCP_BUF_SIZE;
- theErr = m_pData->readfrom(pBuffer, ulAddress, ulPort);
- if (!theErr && pBuffer)
- {
- UDP_PACKET* pPacket = new UDP_PACKET;
- pPacket->pBuffer = pBuffer;
- pPacket->ulAddress = ulAddress;
- pPacket->ulPort = ulPort;
- m_ReadBuffers.AddTail((void*)pPacket);
- }
- else
- {
- count = 0;
- }
- } while (!theErr && count > 0);
- if (m_bReadPending && m_ReadBuffers.GetCount() > 0)
- {
- /* If we are at interrupt time and the response object is not
- * interrupt safe, schedule a callback to return back the data
- */
- if (!IsSafe())
- {
- m_bInDoRead = FALSE;
- return HXR_AT_INTERRUPT;
- }
- m_bReadPending = FALSE;
- UDP_PACKET* pPacket = (UDP_PACKET*)m_ReadBuffers.RemoveHead();
- pBuffer = pPacket->pBuffer;
- ulAddress = pPacket->ulAddress;
- ulPort = pPacket->ulPort;
- AddRef();
- m_bInDoRead = FALSE;
- m_pUDPResponse->ReadDone(HXR_OK, pBuffer, ulAddress, ulPort);
- m_bInDoRead = TRUE;
- HX_RELEASE(pBuffer);
- HX_DELETE(pPacket);
- Release();
- m_bInDoRead = FALSE;
- return HXR_OK;
- }
- /* if we called from within Read(), we will schedule a callback there, if necessary */
- if (!m_bInRead && m_pSchedulerReadCallback)
- m_pSchedulerReadCallback->ScheduleCallback(UDP_READ_COMMAND, m_pScheduler, SCHED_GRANULARITY);
- m_bInDoRead = FALSE;
- return theErr;
- }
- HX_RESULT
- HXUDPSocket::DoWrite()
- {
- HX_RESULT theErr = HXR_OK;
- if (m_bInWrite) return HXR_OK;
- m_bInWrite = TRUE;
- #ifdef _MACINTOSH
- if (m_pInterruptSafeMacWriteQueue)
- m_pInterruptSafeMacWriteQueue->TransferToSimpleList(m_WriteBuffers);
- #endif
- while (!theErr && m_WriteBuffers.GetCount() > 0)
- {
- IHXBuffer* pBuffer = (IHXBuffer*) m_WriteBuffers.GetHead();
- UINT16 uLength = (UINT16) pBuffer->GetSize();
- theErr = m_pData->writeto( pBuffer->GetBuffer(), // sendto
- &uLength,
- (UINT32) m_sockAddr.sin_addr.s_addr,
- WToHost(m_sockAddr.sin_port));
- if (!theErr)
- {
- pBuffer->Release();
- m_WriteBuffers.RemoveHead();
- }
- }
- if (m_pSchedulerWriteCallback &&
- m_WriteBuffers.GetCount() > 0)
- {
- m_pSchedulerWriteCallback->ScheduleCallback(UDP_WRITE_COMMAND, m_pScheduler, SCHED_GRANULARITY);
- }
- m_bInWrite = FALSE;
- return theErr;
- }
- /* If we are at interrupt time and the response object is not interrupt safe,
- * schedule a callback to return back the data
- */
- BOOL
- HXUDPSocket::IsSafe()
- {
- if (m_pInterruptState && m_pInterruptState->AtInterruptTime() &&
- (!m_pResponseInterruptSafe ||
- !m_pResponseInterruptSafe->IsInterruptSafe()))
- {
- if (m_pNonInterruptReadCallback){
- m_pNonInterruptReadCallback->ScheduleCallback(UDP_READ_COMMAND, m_pScheduler, 0);
- }
- return FALSE;
- }
- return TRUE;
- }
- STDMETHODIMP HXUDPSocket::HandleCallback(INT32 theCommand, HX_RESULT theError)
- {
- HX_RESULT theErr = HXR_OK;
- if (!m_bInDestructor)
- {
- AddRef();
- m_pMutex->Lock();
- if (!m_bInDestructor)
- {
- switch(theCommand)
- {
- case UDP_READ_COMMAND:
- theErr = DoRead();
- break;
- case UDP_WRITE_COMMAND:
- theErr = DoWrite(); // protected from re-entry by m_bInWrite
- break;
- default:
- theErr = DoRead();
- if( theErr == HXR_OK )
- {
- theErr = DoWrite();
- }
- break;
- }
- }
- m_pMutex->Unlock();
- Release();
- }
- return theErr;
- }
- HX_RESULT HXUDPSocket::UDPSocketCallback::Func(NotificationType Type,
- BOOL bSuccess, conn* pConn)
- {
- if(m_pContext)
- {
- switch (Type)
- {
- case READ_NOTIFICATION:
- #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:
- default:
- break;
- }
- }
- return HXR_OK;
- }
- STDMETHODIMP
- HXUDPSocket::SetOption(HX_SOCKET_OPTION option, UINT32 ulValue)
- {
- HX_RESULT res = HXR_OK;
- switch(option)
- {
- case HX_SOCKOPT_REUSE_ADDR:
- m_bReuseAddr = (BOOL)ulValue;
- break;
- case HX_SOCKOPT_REUSE_PORT:
- m_bReusePort = (BOOL)ulValue;
- break;
- case HX_SOCKOPT_BROADCAST:
- {
- HX_RESULT theErr = HXR_OK;
- if(m_pData)
- {
- m_pMutex->Lock();
- theErr = m_pData->set_broadcast(ulValue);
- res = ConvertNetworkError(theErr);
- m_pMutex->Unlock();
- }
- }
- break;
- case HX_SOCKOPT_MULTICAST_IF:
- if (m_pData)
- {
- res = m_pData->set_multicast_if(ulValue);
- }
- break;
- case HX_SOCKOPT_SET_SENDBUF_SIZE:
- {
- if (m_pData)
- {
- HX_RESULT theErr = HXR_OK;
- m_pMutex->Lock();
- theErr = m_pData->set_send_size(ulValue);
- res = ConvertNetworkError(theErr);
- m_pMutex->Unlock();
- }
- break;
- }
- default:
- HX_ASSERT(!"I don't know this option");
- res = HXR_FAIL;
- }
- return res;
- }
- STDMETHODIMP
- HXUDPSocket::SetOption(HX_PRIVATE_SOCKET_OPTION option, UINT32 ulValue)
- {
- HX_RESULT res = HXR_OK;
- switch(option)
- {
- case HX_PRIVATE_SOCKOPT_IGNORE_WSAECONNRESET:
- {
- if (m_pData)
- {
- m_pMutex->Lock();
- m_pData->IgnoreWSAECONNRESET((BOOL)ulValue);
- m_pMutex->Unlock();
- }
- break;
- }
- default:
- HX_ASSERT(!"I don't know this option");
- res = HXR_FAIL;
- }
- return HXR_OK;
- }
- #ifdef _MACINTOSH
- /////////////////////////////////////////////////////////////////////////
- //
- // InterruptSafeMacQueue
- //
- // For passing data between an interrupt and anything else (mac only).
- //
- InterruptSafeMacQueue::InterruptSafeMacQueue()
- {
- mQueueHeader.qFlags=0;
- mQueueHeader.qHead=0;
- mQueueHeader.qTail=0;
- mDestructing = FALSE; // just a safety check
- }
- /////////////////////////////////////////////////////////////////////////
- //
- HX_RESULT InterruptSafeMacQueue::AddTail(IUnknown* pObject)
- {
- if (pObject && !mDestructing)
- {
- IhxQueueElement * theElement = new IhxQueueElement();
- if (theElement)
- {
- theElement->mNextElementInQueue = NULL;
- theElement->mObject = pObject;
- theElement->mObject->AddRef();
- ::Enqueue((QElem *)theElement, &mQueueHeader);
- //
- // If someone interrupts and enters the destructor while we're in here,
- // then the pObject and the new node will be leaked. This shouldn't
- // happen since we should have shut down all interrupts that would
- // be adding items to the queue long before we start destructing it.
- //
- HX_ASSERT(!mDestructing); // if we DID enter the destructor, let the programmer know...
- }
- return HXR_OK;
- }
- return HXR_FAILED;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- IUnknown * InterruptSafeMacQueue::RemoveHead()
- {
- //
- // POINT A
- //
- // You can look at the qHead anytime you want, but you can't USE a
- // pointer unless it's OFF of the queue. Basically you do a Dequeue,
- // and if it succeeds then you know nobody else has it. If it fails,
- // an error is returned and you don't mess with it.
- //
- if (mQueueHeader.qHead)
- {
- IhxQueueElement * theElement = (IhxQueueElement *) mQueueHeader.qHead;
- if (theElement)
- {
- OSErr e = ::Dequeue( (QElemPtr) theElement, &mQueueHeader );
- //
- // Between points A and D, we can't be guaranteed that the queue header and theElement are valid. But
- // Dequeue will TELL us if that pointer is still valid by its return code. If it can't remove the item
- // from the queue, then somebody else did and the pointer is no longer ours. If no error was returned
- // from dequeue, then it's ours to mess with.
- //
- if (e == noErr)
- {
- // at this point we know that we can do whatever we need to with the object.
- IUnknown * theObj = theElement->mObject;
- delete theElement; // delete the node
- return theObj;
- }
- }
- }
- return NULL;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- HX_RESULT InterruptSafeMacQueue::TransferToSimpleList(CHXSimpleList &simpleList)
- {
- IUnknown * theObject;
- // we did an AddRef in the AddTail call -- just pass it along to the simplelist
- while ((theObject = RemoveHead()) != 0)
- {
- simpleList.AddTail((void *)theObject);
- }
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- InterruptSafeMacQueue::~InterruptSafeMacQueue()
- {
- mDestructing = TRUE; // don't add anything else to the queue
- IUnknown * theObject;
- while ((theObject = RemoveHead()) != 0)
- {
- theObject->Release();
- }
- // and just to be safe...
- mQueueHeader.qHead=0;
- mQueueHeader.qTail=0;
- }
- #endif // _MACINTOSH