hxnetapi.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:69k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: RCSL 1.0/RPSL 1.0
  3.  *
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
  5.  *
  6.  * The contents of this file, and the files included with this file, are
  7.  * subject to the current version of the RealNetworks Public Source License
  8.  * Version 1.0 (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the RealNetworks Community Source License Version 1.0
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
  12.  * in which case the RCSL will apply. You may also obtain the license terms
  13.  * directly from RealNetworks.  You may not use this file except in
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or
  16.  * RCSL for the rights, obligations and limitations governing use of the
  17.  * contents of the file.
  18.  *
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the
  20.  * developer of the Original Code and owns the copyrights in the portions
  21.  * it created.
  22.  *
  23.  * This file, and the files included with this file, is distributed and made
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  28.  *
  29.  * Technology Compatibility Kit Test Suite(s) Location:
  30.  *    http://www.helixcommunity.org/content/tck
  31.  *
  32.  * Contributor(s):
  33.  *
  34.  * ***** END LICENSE BLOCK ***** */
  35. #include "hxtypes.h"
  36. #include "hxresult.h"
  37. #include "hxcom.h"
  38. #include "hxcomm.h"
  39. #include "hxprefs.h"
  40. #include "hxerror.h"
  41. #if defined(_MACINTOSH)
  42. #include "hx_moreprocesses.h"
  43. #endif /* _MACINTOSH. */
  44. #include "ihxpckts.h"
  45. #include "hxfiles.h"
  46. #include "chxpckts.h"
  47. #include "hxengin.h"
  48. #include "hxpnets.h"
  49. #include "hxtick.h"
  50. #include "hxstrutl.h"
  51. #include "chxuuid.h"
  52. #include "rtsputil.h"
  53. #include "hxslist.h"
  54. #include "cbqueue.h"
  55. #include "growingq.h"
  56. #include "dbcs.h"
  57. #include "conn.h"
  58. #include "hxmarsh.h"
  59. #include "hxthread.h"
  60. #include "hxcore.h"
  61. #if defined (_UNIX)
  62. #include "unix_net.h"
  63. #include "platform/unix/hxsignal.h"
  64. #elif defined (_WIN32) || defined (_WINDOWS)
  65. #include "win_net.h"
  66. #elif defined(__TCS__)
  67. #include "platform/tm1/tm1_net.h"
  68. #elif defined (_MACINTOSH)
  69. #ifndef _MAC_MACHO
  70. #include "OpenTptInternet.h" //for AF_INET
  71. #endif
  72. #include "mac_net.h"
  73. #include "macsockets.h"
  74. #endif
  75. #include "threngin.h"
  76. #include "netbyte.h"
  77. #include "hxnetapi.h"
  78. #include "hxnetutil.h"
  79. #if defined(HELIX_FEATURE_HTTPCLOAK)
  80. #include "hxcloakedtcp.h"
  81. #endif /* HELIX_FEATURE_HTTPCLOAK */
  82. #include "hxheap.h"
  83. #include "hxprefs.h"
  84. #include "hxprefutil.h"
  85. #ifdef _DEBUG
  86. #undef HX_THIS_FILE
  87. static const char HX_THIS_FILE[] = __FILE__;
  88. #endif
  89. #ifdef _WIN16
  90. extern HINSTANCE g_hInstance;       // initialized inside DLLMAIN.CPP(core.dll)
  91. #endif
  92. const int UDP_CHUNK_SIZE = 1024;
  93. #define QUEUE_START_SIZE    512
  94. #if defined _WINDOWS && !defined _WIN32  // for win16
  95. #define DESIRED_RCV_BUFSIZE 0xFFFF  // ~ 525 KBits
  96. #else
  97. #define DESIRED_RCV_BUFSIZE 0x0002FFFF // ~ 1.5 MBits
  98. #endif //defined _WINDOWS && !defined _WIN32
  99. #ifdef _WINCE
  100. #define SCHED_GRANULARITY 10
  101. #else
  102. #define SCHED_GRANULARITY 50
  103. #endif
  104. // same for all the platforms...may need to tweak it, if necessary
  105. #define MAX_ITERATION_COUNT 200
  106. #if defined( _UNIX )
  107. BOOL ReadAsyncDNSPref( IUnknown* pContext )
  108. {
  109.     static BOOL bNoAsyncDNS  = FALSE;
  110.     static BOOL bNeedToLoad  = TRUE;
  111.     if( bNeedToLoad && NULL!=pContext)
  112.     {
  113.         IHXPreferences* pPreferences = NULL;
  114.         bNeedToLoad = FALSE;
  115.         pContext->QueryInterface(IID_IHXPreferences, (void **)&pPreferences);
  116.         IHXBuffer *pBuffer = NULL;
  117.         if( NULL!=pPreferences )
  118.         {
  119.             pPreferences->ReadPref("NoAsyncDNS", pBuffer);
  120.             if (pBuffer)
  121.             {
  122.                 bNoAsyncDNS = (atoi((const char*)pBuffer->GetBuffer()) == 1);
  123.                 HX_RELEASE(pBuffer);
  124.             }
  125.             HX_RELEASE( pPreferences );
  126.         } // NULL!=pPreferences
  127.     }//bNeedToLoad && NULL!=pContext
  128.     return bNoAsyncDNS;
  129. }
  130. BOOL ReadThreadedDNSPref( IUnknown* pContext )
  131. {
  132.     static BOOL bThreadedDNS = TRUE;
  133.     static BOOL bNeedToLoad  = TRUE;
  134.     if( bNeedToLoad && NULL!=pContext)
  135.     {
  136.         IHXPreferences* pPreferences = NULL;
  137.         bNeedToLoad = FALSE;
  138.         pContext->QueryInterface(IID_IHXPreferences, (void **)&pPreferences);
  139.         IHXBuffer *pBuffer = NULL;
  140.         if( NULL!=pPreferences )
  141.         {
  142.             pPreferences->ReadPref("ThreadedDNS", pBuffer);
  143.             if (pBuffer)
  144.             {
  145.                 bThreadedDNS = (atoi((const char*)pBuffer->GetBuffer()) == 1);
  146.                 HX_RELEASE(pBuffer);
  147.             }
  148.             else
  149.             {
  150.                 //XXXGFW HACK!! REMOVE AFTER RNC
  151.                 //Pref was not found. It defaults to ON now so lets see if we
  152.                 //are running under a player. If not, turn it off.
  153.                 IHXClientEngine* pEngine = NULL;
  154.                 if(HXR_OK == pContext->QueryInterface(IID_IHXClientEngine, (void**)&pEngine))
  155.                 {
  156.                     //We have client Engine. Do nothing.
  157.                     HX_RELEASE( pEngine );
  158.                 }
  159.                 else
  160.                 {
  161.                     //We don't have a client engine. Turn off threading...
  162.                     bThreadedDNS = FALSE;
  163.                 }
  164.             }
  165.             HX_RELEASE( pPreferences );
  166.         } // NULL!=pPreferences
  167.     }//bNeedToLoad && NULL!=pContext
  168.     return bThreadedDNS;
  169. }
  170. #endif
  171. #if !defined(HELIX_CONFIG_NOSTATICS)
  172. UINT16 HXNetworkServices::z_muNumDriverInstance = 0;
  173. #else
  174. #include "globals/hxglobals.h"
  175. const UINT16 HXNetworkServices::z_muNumDriverInstance = 0;
  176. #endif
  177. /* HXNetworkServices */
  178. HXNetworkServices::HXNetworkServices(IUnknown* pContext)
  179. {
  180.     m_bNeedToCleanupDrivers = FALSE;
  181.     m_lRefCount = 0;
  182.     m_pContext = pContext;
  183.     if (m_pContext)
  184.     {
  185. m_pContext->AddRef();
  186.     }
  187. }
  188. HXNetworkServices::~HXNetworkServices()
  189. {
  190.     Close();
  191. }
  192. STDMETHODIMP HXNetworkServices::QueryInterface(REFIID riid, void** ppvObj)
  193. {
  194.     QInterfaceList qiList[] =
  195.         {
  196.             { GET_IIDHANDLE(IID_IHXNetworkServices), (IHXNetworkServices*)this },
  197.             { GET_IIDHANDLE(IID_IHXNetworkInterfaceEnumerator), (IHXNetworkInterfaceEnumerator*)this },
  198. #if defined(HELIX_FEATURE_HTTPCLOAK)
  199.             { GET_IIDHANDLE(IID_IHXCloakedNetworkServices), (IHXCloakedNetworkServices*)this },
  200. #endif /* HELIX_FEATURE_HTTPCLOAK */
  201.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXNetworkServices*)this },
  202.         };
  203.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  204. }
  205. STDMETHODIMP_(ULONG32) HXNetworkServices::AddRef()
  206. {
  207.     return InterlockedIncrement(&m_lRefCount);
  208. }
  209. STDMETHODIMP_(ULONG32) HXNetworkServices::Release()
  210. {
  211.     if (InterlockedDecrement(&m_lRefCount) > 0)
  212.     {
  213.         return m_lRefCount;
  214.     }
  215.     delete this;
  216.     return 0;
  217. }
  218. void
  219. HXNetworkServices::UseDrivers()
  220. {
  221.     if (!m_bNeedToCleanupDrivers)
  222.     {
  223. m_bNeedToCleanupDrivers = TRUE;
  224. #if defined(HELIX_CONFIG_NOSTATICS)
  225. UINT16& z_muNumDriverInstance = (UINT16&)
  226.     HXGlobalInt16::Get(&HXNetworkServices::z_muNumDriverInstance);
  227. #endif
  228. z_muNumDriverInstance++;
  229.     }
  230. }
  231. void
  232. HXNetworkServices::Close()
  233. {
  234.     HX_RELEASE(m_pContext);
  235.     if (m_bNeedToCleanupDrivers)
  236.     {
  237. m_bNeedToCleanupDrivers = FALSE;
  238. #if defined(HELIX_CONFIG_NOSTATICS)
  239. UINT16& z_muNumDriverInstance = (UINT16&)
  240.     HXGlobalInt16::Get(&HXNetworkServices::z_muNumDriverInstance);
  241. #endif
  242. z_muNumDriverInstance--;
  243. if (z_muNumDriverInstance == 0)
  244. {
  245. #if defined(THREADS_SUPPORTED)
  246.             ThreadEngine::DestroyThreadEngine();
  247. #elif defined(_UNIX_THREADED_NETWORK_IO)
  248.             if( ReadNetworkThreadingPref((IUnknown*)m_pContext) )
  249.                 ThreadEngine::DestroyThreadEngine();
  250. #endif
  251.     conn::close_drivers(NULL);
  252. }
  253.     }
  254. }
  255. STDMETHODIMP
  256. HXNetworkServices::CreateTCPSocket(IHXTCPSocket** ppTCPSocket)
  257. {
  258.     *ppTCPSocket = new HXTCPSocket(m_pContext, this);
  259.     if (*ppTCPSocket == NULL)
  260.     {
  261. return HXR_OUTOFMEMORY;
  262.     }
  263.     (*ppTCPSocket)->AddRef();
  264.     return HXR_OK;
  265. }
  266. STDMETHODIMP
  267. HXNetworkServices::CreateUDPSocket(IHXUDPSocket** ppUDPSocket)
  268. {
  269.     *ppUDPSocket = new HXUDPSocket(m_pContext, this);
  270.     if (*ppUDPSocket == NULL)
  271.     {
  272. return HXR_OUTOFMEMORY;
  273.     }
  274.     (*ppUDPSocket)->AddRef();
  275.     return HXR_OK;
  276. }
  277. STDMETHODIMP
  278. HXNetworkServices::CreateListenSocket(IHXListenSocket** ppListenSocket)
  279. {
  280.     *ppListenSocket = new HXListenSocket(m_pContext, this);
  281.     if (*ppListenSocket == NULL)
  282.     {
  283. return HXR_OUTOFMEMORY;
  284.     }
  285.     (*ppListenSocket)->AddRef();
  286.     return HXR_OK;
  287. }
  288. STDMETHODIMP
  289. HXNetworkServices::CreateResolver(IHXResolver** ppResolver)
  290. {
  291.     *ppResolver = new HXResolver(this, m_pContext);
  292.     if(*ppResolver == NULL)
  293.     {
  294. return HXR_OUTOFMEMORY;
  295.     }
  296.     (*ppResolver)->AddRef();
  297.     return HXR_OK;
  298. }
  299. STDMETHODIMP
  300. HXNetworkServices::CreateClientCloakedSocket(IHXTCPSocket** ppTCPSocket)
  301. {
  302. #if defined(HELIX_FEATURE_HTTPCLOAK)
  303.     *ppTCPSocket = new HXClientCloakedTCPSocket(m_pContext);
  304.     if (*ppTCPSocket == NULL)
  305.     {
  306. return HXR_OUTOFMEMORY;
  307.     }
  308.     (*ppTCPSocket)->AddRef();
  309.     return HXR_OK;
  310. #else
  311.     return HXR_NOTIMPL;
  312. #endif /* HELIX_FEATURE_HTTPCLOAK */
  313. }
  314. STDMETHODIMP
  315. HXNetworkServices::CreateServerCloakedSocket(IHXListenSocket** ppListenSocket)
  316. {
  317.     return HXR_NOTIMPL;
  318. }
  319. /* IHXNetworkInterfaceEnumerator */
  320. STDMETHODIMP
  321. HXNetworkServices::EnumerateInterfaces
  322.     (REF(UINT32*) pulInterfaces, REF(UINT32) ulNumInterfaces)
  323. {
  324.     return conn::EnumerateInterfaces(pulInterfaces, ulNumInterfaces);
  325. }
  326. /* HXResolver */
  327. HXResolver::HXResolver(HXNetworkServices* pNetworkServices):
  328.      m_lRefCount(0)
  329.     ,m_pCallback(0)
  330.     ,m_pResp(0)
  331.     ,m_bResolverPending(FALSE)
  332.     ,m_pData(0)
  333.     ,m_pNetworkServices(NULL)
  334. {
  335.     m_pNetworkServices = pNetworkServices;
  336.     m_pNetworkServices->AddRef();
  337. }
  338. HXResolver::HXResolver( HXNetworkServices* pNetworkServices,
  339.                           IUnknown*           pContext):
  340.      m_lRefCount(0)
  341.     ,m_pCallback(0)
  342.     ,m_pResp(0)
  343.     ,m_bResolverPending(FALSE)
  344.     ,m_pData(0)
  345.     ,m_pNetworkServices(NULL)
  346.     ,m_pContext( pContext )
  347. {
  348.     m_pNetworkServices = pNetworkServices;
  349.     m_pNetworkServices->AddRef();
  350. }
  351. HXResolver::~HXResolver()
  352. {
  353.     if (m_pData)
  354.     {
  355. m_pData->done();
  356. m_pData->Release();
  357. m_pData = 0;
  358.     }
  359.     if (m_pCallback)
  360.     {
  361. delete m_pCallback;
  362. m_pCallback = 0;
  363.     }
  364.     if (m_pResp)
  365.     {
  366. m_pResp->Release();
  367. m_pResp = 0;
  368.     }
  369. #if defined( _WIN32 ) || defined( _WINDOWS )
  370.     win_net::ReleaseWinsockUsage(this);
  371. #endif
  372.     HX_RELEASE(m_pNetworkServices);
  373. }
  374. STDMETHODIMP
  375. HXResolver::QueryInterface(REFIID riid, void** ppvObj)
  376. {
  377.     QInterfaceList qiList[] =
  378.         {
  379.             { GET_IIDHANDLE(IID_IHXResolver), (IHXResolver*)this },
  380.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXResolver*)this },
  381.         };
  382.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  383. }
  384. STDMETHODIMP_(ULONG32) HXResolver::AddRef()
  385. {
  386.     return InterlockedIncrement(&m_lRefCount);
  387. }
  388. STDMETHODIMP_(ULONG32) HXResolver::Release()
  389. {
  390.     if (InterlockedDecrement(&m_lRefCount) > 0)
  391.     {
  392.         return m_lRefCount;
  393.     }
  394.     delete this;
  395.     return 0;
  396. }
  397. STDMETHODIMP HXResolver::Init(IHXResolverResponse* pResp)
  398. {
  399.     if (!pResp)
  400.     {
  401. return HXR_UNEXPECTED;
  402.     }
  403.     if (m_pResp)
  404.     {
  405. m_pResp->Release();
  406. m_pResp = 0;
  407.     }
  408.     m_pResp = pResp;
  409.     m_pResp->AddRef();
  410.     return HXR_OK;
  411. }
  412. STDMETHODIMP HXResolver::GetHostByName(const char* pHostName)
  413. {
  414.     HX_RESULT theErr = HXR_OK;
  415.     if (!pHostName || m_bResolverPending)
  416.     {
  417. return HXR_UNEXPECTED;
  418.     }
  419.     if (!m_pCallback)
  420.     {
  421. m_pCallback = new HXResolverCallback;
  422. if (!m_pCallback)
  423. {
  424.     return HXR_OUTOFMEMORY;
  425. }
  426. m_pCallback->m_pContext = this;
  427.     }
  428.     /* Is this the first time we are calling gethostbyname */
  429.     if (!m_pData)
  430.     {
  431. #if defined( _WIN32 ) || defined( _WINDOWS )
  432. // Have we been able to load and initialize the winsock stuff yet?
  433. if (!win_net::IsWinsockAvailable(this))
  434. {
  435.     return HXR_FAIL; // HXR_GENERAL_NONET;
  436. }
  437. #endif
  438. m_pNetworkServices->UseDrivers();
  439. conn::init_drivers(NULL);
  440.     }
  441.     if (m_pData)
  442.     {
  443. m_pData->done();
  444. m_pData->Release();
  445. m_pData = 0;
  446.     }
  447. #ifdef _UNIX
  448.     //This one has to be set before we create a new socket.
  449.     conn::SetNetworkThreadingPref( ReadNetworkThreadingPref((IUnknown*)m_pContext) );
  450.     conn::SetThreadedDNSPref( ReadThreadedDNSPref((IUnknown*)m_pContext) );
  451. #endif
  452.     m_pData = conn::new_socket(HX_UDP_SOCKET);
  453.     if (!m_pData)
  454.     {
  455. return HXR_OUTOFMEMORY;
  456.     }
  457. #ifdef _UNIX
  458.     m_pData->SetAsyncDNSPref( ReadAsyncDNSPref((IUnknown*)m_pContext) );
  459. #endif
  460.     // XXXAAK -- local addr binding stuff
  461.     theErr = m_pData->init(INADDR_ANY, 0);
  462.     m_pData->nonblocking();
  463.     m_pData->set_callback(m_pCallback);
  464. #ifdef _WINDOWS
  465. #if defined (_WIN32)
  466.     ULONG32 ulPlatformData = (ULONG32)GetModuleHandle(NULL);
  467. #elif defined (_WIN16)
  468.     ULONG32 ulPlatformData = (ULONG32)(int)g_hInstance;
  469. #endif
  470.     m_pData->SetWindowHandle(ulPlatformData);
  471. #endif /* defined (_WINDOWS) */
  472.     m_bResolverPending = TRUE;
  473. #ifndef _WINCE
  474.     m_pData->dns_find_ip_addr(pHostName);
  475. #else
  476.     // Only blocking DNS
  477.     m_pData->dns_find_ip_addr(pHostName, 1);
  478. #endif
  479.     return HXR_OK;
  480. }
  481. void
  482. HXResolver::DNSDone(BOOL bSuccess)
  483. {
  484.     ULONG32 ulAddr = 0;
  485.     BOOL bIsValid = TRUE;
  486.     char*   pDottedIP = 0;
  487.     m_bResolverPending = FALSE;
  488.     AddRef();
  489.     if (bSuccess)
  490.     {
  491. m_pData->dns_ip_addr_found(&bIsValid, &ulAddr);
  492. UINT32 ulHostAddr = DwToHost(ulAddr);
  493. m_pResp->GetHostByNameDone(HXR_OK, ulHostAddr);
  494.     }
  495.     else
  496.     {
  497. m_pResp->GetHostByNameDone(HXR_DNR, 0);
  498.     }
  499.     Release();
  500. }
  501. HX_RESULT
  502. HXResolver::HXResolverCallback::Func(NotificationType Type,
  503.        BOOL bSuccess, conn* pConn)
  504. {
  505.     if(m_pContext)
  506.     {
  507. switch (Type)
  508. {
  509. case DNS_NOTIFICATION:
  510.     m_pContext->DNSDone(bSuccess);
  511.     break;
  512. case READ_NOTIFICATION:
  513. case WRITE_NOTIFICATION:
  514. case CONNECT_NOTIFICATION:
  515. default:
  516.     break;
  517. }
  518.     }
  519.     return HXR_OK;
  520. }
  521. /* HXTCPSocket */
  522. HXTCPSocket::HXTCPSocket(IUnknown* pContext, HXNetworkServices* pNetworkServices):
  523.      m_lRefCount(0)
  524.     ,m_pTCPResponse(0)
  525.     ,m_pCtrl(0)
  526.     ,m_lForeignAddress(0)
  527.     ,m_nForeignPort(0)
  528.     ,m_bReadPending(FALSE)
  529.     ,m_nRequired(0)
  530.     ,mSendTCP(0)
  531.     ,mReceiveTCP(0)
  532.     ,m_pBuffer(0)
  533.     ,m_pCallback(0)
  534.     ,m_bConnected(FALSE)
  535.     ,m_bWantWritePending(FALSE)
  536.     ,m_bInitComplete(FALSE)
  537.     ,m_bWriteFlushPending(FALSE)
  538.     ,m_pScheduler(0)
  539.     ,m_pSchedulerReadCallback(0)
  540.     ,m_pSchedulerWriteCallback(0)
  541.     ,m_bInRead(FALSE)
  542.     ,m_bInWrite(FALSE)
  543.     ,m_bInDoRead(FALSE)
  544.     ,m_pInterruptState(NULL)
  545.     ,m_pResponseInterruptSafe(NULL)
  546.     ,m_pMutex(NULL)
  547.     ,m_bInDestructor(FALSE)
  548.     ,m_pNonInterruptReadCallback(NULL)
  549.     ,m_pNetworkServices(NULL)
  550.     ,m_pPreferences(NULL)
  551.     ,m_bReuseAddr(FALSE)
  552.     ,m_bReusePort(FALSE)
  553.     ,m_pContext(pContext)
  554.     ,m_bSecureSocket(FALSE)
  555. {
  556.     m_pNetworkServices = pNetworkServices;
  557.     m_pNetworkServices->AddRef();
  558. #ifdef _MACINTOSH
  559. m_pInterruptSafeMacWriteQueue = new InterruptSafeMacQueue();
  560. HX_ASSERT(m_pInterruptSafeMacWriteQueue != NULL);
  561. #endif
  562.     if (pContext)
  563.     {
  564. pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
  565. pContext->QueryInterface(IID_IHXInterruptState, (void**) &m_pInterruptState);
  566. pContext->QueryInterface(IID_IHXPreferences, (void**) &m_pPreferences);
  567.     }
  568.     if (m_pScheduler)
  569.     {
  570. m_pSchedulerReadCallback = new ScheduledSocketCallback(this, TRUE);
  571. m_pSchedulerReadCallback->AddRef();
  572. m_pSchedulerWriteCallback = new ScheduledSocketCallback(this, TRUE);
  573. m_pSchedulerWriteCallback->AddRef();
  574. m_pNonInterruptReadCallback = new ScheduledSocketCallback(this, FALSE);
  575. m_pNonInterruptReadCallback->AddRef();
  576. #ifdef _MACINTOSH
  577. m_pMacCommandCallback = new ScheduledSocketCallback(this, FALSE);
  578. m_pMacCommandCallback->AddRef();
  579. #endif
  580.     }
  581. #if defined(_UNIX) && defined(HELIX_FEATURE_IGNORE_SIGPIPE)
  582.         // When the connection is closed by the server, SIGPIPE will be thrown
  583.         // in next write() and terminates the program abruptly.
  584.         //
  585.         // In order to gracefully exists the program, it's recommended to:
  586.         // - ignore the SIGPIPE and
  587.         // - checks the return code(errno) from write()
  588.         //
  589.         // for read(), it simply returns 0 when the connection is closed.
  590.         SIGNAL(SIGPIPE, SIG_IGN);
  591. #endif /* _UNIX  && HELIX_FEATURE_IGNORE_SIGPIPE */
  592. #if defined(THREADS_SUPPORTED)
  593.     HXMutex::MakeMutex(m_pMutex);
  594. #elif defined(_UNIX_THREADED_NETWORK_IO)
  595.     if( ReadNetworkThreadingPref((IUnknown*)m_pContext) )
  596.         HXMutex::MakeMutex(m_pMutex);
  597.     else
  598.         HXMutex::MakeStubMutex(m_pMutex);
  599. #else
  600.     HXMutex::MakeStubMutex(m_pMutex);
  601. #endif
  602. }
  603. HXTCPSocket::~HXTCPSocket()
  604. {
  605.     m_bInDestructor = TRUE; // set it early
  606.     m_pMutex->Lock();
  607. #ifdef _MACINTOSH
  608. HX_DELETE(m_pInterruptSafeMacWriteQueue); // will release any objects in its nodes
  609. #endif
  610.    if (m_pSchedulerReadCallback)
  611. m_pSchedulerReadCallback->Unschedule(m_pScheduler);
  612.    if (m_pSchedulerWriteCallback)
  613. m_pSchedulerWriteCallback->Unschedule(m_pScheduler);
  614.    if (m_pNonInterruptReadCallback)
  615. m_pNonInterruptReadCallback->Unschedule(m_pScheduler);
  616. #ifdef _MACINTOSH
  617. if (m_pMacCommandCallback)
  618. m_pMacCommandCallback->Unschedule(m_pScheduler);
  619. #endif
  620.     /*
  621.      * XXX...While handling the m_pCtrl->done it's possible for the
  622.      *       DispatchMessage call in CancelSelect to cause an
  623.      *       asynchronous DoRead to occur. The resulting AddRef/Release
  624.      *       would cause this object to be deleted again, so to prevent
  625.      *       this we set the m_pCallback->m_pContext = 0
  626.      */
  627.    if (m_pCallback)
  628.     {
  629. m_pCallback->m_pContext = 0;
  630.     }
  631. //#ifndef _UNIX
  632.     /* XXXJR I feel certain this is related to the above comment somehow.
  633.      *       Deleting the ctrl here wreaks havoc on the encoder.
  634.      *       This is a bad solution, but I don't really know
  635.      *       what the right one is.  This at least prevents random crashes
  636.      *       in the encoder.
  637.      *
  638.      * XXXGH commented out the #ifndef because it was breaking my
  639.      *       connectionless control stuff
  640.      *
  641.      */
  642.     if (m_pCtrl)
  643.     {
  644. m_pCtrl->done();
  645. m_pCtrl->Release(); // A deleted (0xdddddddd) pointer was used here.
  646. m_pCtrl = 0;
  647.     }
  648. //#endif
  649.     HX_RELEASE(m_pTCPResponse);
  650.     HX_DELETE(m_pCallback);
  651.     HX_DELETE(mSendTCP);
  652.     HX_DELETE(mReceiveTCP);
  653.     HX_VECTOR_DELETE(m_pBuffer);
  654.     while (m_PendingWriteBuffers.GetCount() > 0)
  655.     {
  656. IHXBuffer* pBuffer =
  657.     (IHXBuffer*) m_PendingWriteBuffers.RemoveHead();
  658. pBuffer->Release();
  659.     }
  660.     if (m_pSchedulerReadCallback)
  661.     {
  662.      m_pSchedulerReadCallback->m_pSocket = NULL;
  663.      m_pSchedulerReadCallback->Release();
  664.      m_pSchedulerReadCallback = NULL;
  665.     }
  666.     if (m_pSchedulerWriteCallback)
  667.     {
  668.      m_pSchedulerWriteCallback->m_pSocket = NULL;
  669.      m_pSchedulerWriteCallback->Release();
  670.      m_pSchedulerWriteCallback = NULL;
  671.     }
  672.     if (m_pNonInterruptReadCallback)
  673.     {
  674.      m_pNonInterruptReadCallback->m_pSocket = NULL;
  675.      m_pNonInterruptReadCallback->Release();
  676.      m_pNonInterruptReadCallback = NULL;
  677.     }
  678. #ifdef _MACINTOSH
  679.    if (m_pMacCommandCallback)
  680.     {
  681. m_pMacCommandCallback->m_pSocket = NULL;
  682. m_pMacCommandCallback->Release();
  683. m_pMacCommandCallback = NULL;
  684.     }
  685. #endif
  686.     HX_RELEASE(m_pInterruptState);
  687.     HX_RELEASE(m_pResponseInterruptSafe);
  688.     HX_RELEASE(m_pScheduler);
  689.     m_pMutex->Unlock();
  690.     HX_DELETE(m_pMutex);
  691. #if defined( _WIN32 ) || defined( _WINDOWS )
  692.     win_net::ReleaseWinsockUsage(this);
  693. #endif
  694.     HX_RELEASE(m_pNetworkServices);
  695.     HX_RELEASE(m_pPreferences);
  696. }
  697. STDMETHODIMP HXTCPSocket::QueryInterface(REFIID riid, void** ppvObj)
  698. {
  699.     QInterfaceList qiList[] =
  700.         {
  701.             { GET_IIDHANDLE(IID_IHXTCPSocket), (IHXTCPSocket*)this },
  702.             { GET_IIDHANDLE(IID_IHXSetSocketOption), (IHXSetSocketOption*)this },
  703.             { GET_IIDHANDLE(IID_IHXTCPSecureSocket), (IHXTCPSecureSocket*)this },
  704.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXTCPSocket*)this },
  705.         };
  706.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  707. }
  708. STDMETHODIMP_(ULONG32) HXTCPSocket::AddRef()
  709. {
  710.     return InterlockedIncrement(&m_lRefCount);
  711. }
  712. STDMETHODIMP_(ULONG32) HXTCPSocket::Release()
  713. {
  714.     if (InterlockedDecrement(&m_lRefCount) > 0)
  715.     {
  716.         return m_lRefCount;
  717.     }
  718.     else if (m_lRefCount < 0)
  719.     {
  720.      // double delete
  721.      return 0;
  722.     }
  723.     delete this;
  724.     return 0;
  725. }
  726. STDMETHODIMP HXTCPSocket::Init(IHXTCPResponse* pTCPResponse)
  727. {
  728.     if (!pTCPResponse)
  729.     {
  730. return HXR_UNEXPECTED;
  731.     }
  732.     m_pTCPResponse = pTCPResponse;
  733.     m_pTCPResponse->AddRef();
  734.     m_pTCPResponse->QueryInterface(IID_IHXInterruptSafe,
  735.    (void**) &m_pResponseInterruptSafe);
  736.     // allocate TCP send and receive queue
  737.     mSendTCP = new CByteGrowingQueue(QUEUE_START_SIZE,1);
  738.     if (!mSendTCP || !mSendTCP->IsQueueValid())
  739.     {
  740. return HXR_OUTOFMEMORY;
  741.     }
  742.     mSendTCP->SetMaxSize(TCP_BUF_SIZE);
  743.     mReceiveTCP = new CByteGrowingQueue(QUEUE_START_SIZE,1);
  744.     if (!mReceiveTCP || !mReceiveTCP->IsQueueValid())
  745.     {
  746. return HXR_OUTOFMEMORY;
  747.     }
  748.     mReceiveTCP->SetMaxSize(TCP_BUF_SIZE);
  749.     m_pBuffer = new char[TCP_BUF_SIZE];
  750.     if (!m_pBuffer)
  751.     {
  752. return HXR_OUTOFMEMORY;
  753.     }
  754.     return HXR_OK;
  755. }
  756. STDMETHODIMP HXTCPSocket::SetResponse(IHXTCPResponse* pTCPResponse)
  757. {
  758.     m_pMutex->Lock();
  759.     HX_RELEASE(m_pTCPResponse);
  760.     m_pTCPResponse = pTCPResponse;
  761.     m_pTCPResponse->AddRef();
  762.     HX_RELEASE(m_pResponseInterruptSafe);
  763.     m_pTCPResponse->QueryInterface(IID_IHXInterruptSafe,
  764.    (void**) &m_pResponseInterruptSafe);
  765.     m_pMutex->Unlock();
  766.     return HXR_OK;
  767. }
  768. STDMETHODIMP HXTCPSocket::Bind(UINT32 ulLocalAddr, UINT16 nPort)
  769. {
  770.     UINT32 ulMaxBandwidth = 0;
  771.     BOOL bEnforceMaxBandwidth = TRUE;
  772.     BOOL        bLoadTest = FALSE;
  773.     IHXBuffer* pBuffer = NULL;
  774.     if (m_bInitComplete)
  775. return HXR_UNEXPECTED;
  776.     m_nLocalPort = nPort;
  777. #if defined( _WIN32 ) || defined( _WINDOWS )
  778.     // Have we been able to load and initialize the winsock stuff yet?
  779.     if (!win_net::IsWinsockAvailable(this))
  780.     {
  781. return HXR_FAIL; // HXR_GENERAL_NONET;
  782.     }
  783. #endif
  784.     m_pNetworkServices->UseDrivers();
  785.     HX_RESULT theErr = conn::init_drivers(NULL);
  786. #ifdef _UNIX
  787.     //This one has to be set before we create a new socket.
  788.     conn::SetNetworkThreadingPref( ReadNetworkThreadingPref((IUnknown*)m_pContext) );
  789.     conn::SetThreadedDNSPref( ReadThreadedDNSPref((IUnknown*)m_pContext) );
  790. #endif
  791.     m_pCtrl = NULL;
  792. #if defined(HELIX_FEATURE_SECURECONN)
  793.     if (m_bSecureSocket)
  794.     {
  795. IHXSSL* pHXSSL = NULL;
  796. IHXCommonClassFactory* pCCF = NULL;
  797. if (m_pContext)
  798. {
  799.     m_pContext->AddRef();
  800.     // get the CCF
  801.     m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&pCCF);
  802.     HX_RELEASE(m_pContext);
  803. }
  804. if (pCCF)
  805. {
  806.     pCCF->CreateInstance(IID_IHXSSL, (void**) &pHXSSL);
  807.     HX_RELEASE(pCCF);
  808. }
  809. if (pHXSSL)
  810. {
  811.     m_pCtrl = new secureconn(pHXSSL);
  812.     pHXSSL->Release();
  813. }
  814.     }
  815.     else
  816. #endif /* HELIX_FEATURE_SECURECONN */
  817.     {
  818. m_pCtrl  = conn::new_socket(HX_TCP_SOCKET);
  819.     }
  820.     if (!m_pCtrl)
  821.     {
  822. return HXR_OUTOFMEMORY;
  823.     }
  824.     // XXXGo - As it is implemented, this is the only way...
  825.     if (m_bReuseAddr)
  826.     {
  827. if (m_pCtrl->reuse_addr(m_bReuseAddr) != HXR_OK)
  828. {
  829.     // err...what do we need to do?
  830.     HX_ASSERT(!"reuse_addr() failed");
  831. }
  832.     }
  833.     if (m_bReusePort)
  834.     {
  835. if (m_pCtrl->reuse_port(m_bReusePort) != HXR_OK)
  836. {
  837.     // err...what do we need to do?
  838.     HX_ASSERT(!"reuse_port() failed");
  839. }
  840.     }
  841. #ifdef _UNIX
  842.     m_pCtrl->SetAsyncDNSPref( ReadAsyncDNSPref((IUnknown*)m_pContext) );
  843. #endif
  844.     m_pCtrl->nonblocking();
  845.     m_pCallback = new TCPSocketCallback;
  846.     if (!m_pCallback)
  847.     {
  848. return HXR_OUTOFMEMORY;
  849.     }
  850.     m_pCallback->m_pContext = this;
  851.     m_pCtrl->set_callback(m_pCallback);
  852.     m_bInitComplete = TRUE;
  853.     if (m_pPreferences)
  854.     {
  855. /* Get MaxBandwidth from Prefs */
  856. ReadPrefINT32(m_pPreferences, "MaxBandwidth", ulMaxBandwidth);
  857. ReadPrefBOOL(m_pPreferences, "LoadTest", bLoadTest);
  858. ReadPrefBOOL(m_pPreferences, "EnforceMaxBandwidth", bEnforceMaxBandwidth);
  859. //If we are in load test mode, never enforce the MaxBandwidth.
  860. bEnforceMaxBandwidth = bEnforceMaxBandwidth&&!bLoadTest;
  861. if (ulMaxBandwidth && bEnforceMaxBandwidth)
  862. {
  863.     conn::m_ulMaxBandwidth = ulMaxBandwidth / 8;
  864. }
  865. else if (!bEnforceMaxBandwidth)
  866. {
  867.     conn::m_ulMaxBandwidth = MAX_UINT32;
  868. }
  869.     }
  870.     return HXR_OK;
  871. }
  872. STDMETHODIMP HXTCPSocket::Connect(const char* pDestination,
  873.    UINT16 nPort)
  874. {
  875.     if (!m_bInitComplete)
  876.     {
  877. HX_RESULT ret = Bind(HXR_INADDR_ANY, 0);
  878. if (HXR_OK != ret)
  879. return ret;
  880.     }
  881.     HX_RESULT theErr = HXR_OK;
  882.     UINT32 ulPlatformData = 0;
  883. #if defined (_WIN32)
  884.     ulPlatformData = (UINT32)GetModuleHandle(NULL);
  885. #elif defined (_WIN16)
  886.     ulPlatformData = (UINT32)(int)g_hInstance;
  887. #endif
  888.     m_nForeignPort = nPort;
  889. #ifndef _WINCE
  890.     theErr = m_pCtrl->connect(pDestination,nPort,0,ulPlatformData);
  891. #else
  892.     theErr = m_pCtrl->connect(pDestination,nPort,1,ulPlatformData);
  893. #endif
  894.     theErr = ConvertNetworkError(theErr);
  895.     return theErr;
  896. }
  897. STDMETHODIMP HXTCPSocket::Read(UINT16 uSize)
  898. {
  899.     HX_RESULT theErr = HXR_OK;
  900.     HX_RESULT lResult = HXR_OK;
  901.     if (m_bReadPending)
  902.     {
  903. return HXR_UNEXPECTED;
  904.     }
  905.     m_bReadPending  = TRUE;
  906.     m_nRequired     = uSize;
  907.     m_pMutex->Lock();
  908.     theErr  = DoRead();
  909.     m_pMutex->Unlock();
  910.     lResult = ConvertNetworkError(theErr);
  911.     return lResult;
  912. }
  913. STDMETHODIMP HXTCPSocket::Write(IHXBuffer* pBuffer)
  914. {
  915.     HX_RESULT theErr = HXR_OK;
  916.     HX_RESULT lResult = HXR_OK;
  917. #ifdef _MACINTOSH
  918. if (m_pInterruptSafeMacWriteQueue)
  919. m_pInterruptSafeMacWriteQueue->AddTail(pBuffer); // AddRef called inside
  920. #else
  921. pBuffer->AddRef();
  922. m_PendingWriteBuffers.AddTail((void*) pBuffer);
  923.     /* Transfer pending buffers to TCP send queue */
  924.     TransferBuffers();
  925. #endif
  926. m_pMutex->Lock();
  927.     theErr = DoWrite();
  928.     m_pMutex->Unlock();
  929.     lResult = ConvertNetworkError(theErr);
  930.     return lResult;
  931. }
  932. STDMETHODIMP HXTCPSocket::WantWrite()
  933. {
  934.     if (mSendTCP->GetQueuedItemCount() == 0)
  935.     {
  936. m_pTCPResponse->WriteReady(HXR_OK);
  937.     }
  938.     else
  939.     {
  940. m_bWantWritePending = TRUE;
  941.     }
  942.     return HXR_OK;
  943. }
  944. STDMETHODIMP HXTCPSocket::GetLocalAddress(ULONG32& lAddress)
  945. {
  946.     return HXR_NOTIMPL;
  947. }
  948. STDMETHODIMP HXTCPSocket::GetForeignAddress(ULONG32& lAddress)
  949. {
  950.     if(m_bConnected && m_lForeignAddress)
  951.     {
  952. lAddress = m_lForeignAddress;
  953. return HXR_OK;
  954.     }
  955.     return HXR_FAIL;
  956. }
  957. STDMETHODIMP HXTCPSocket::GetLocalPort(UINT16& port)
  958. {
  959.     return HXR_NOTIMPL;
  960. }
  961. STDMETHODIMP HXTCPSocket::GetForeignPort(UINT16& port)
  962. {
  963.     if(m_bConnected)
  964.     {
  965. port = m_nForeignPort;
  966. return HXR_OK;
  967.     }
  968.     return HXR_FAIL;
  969. }
  970. // the tcp socket will still need to be inited
  971. STDMETHODIMP
  972. HXTCPSocket::AcceptConnection(conn* pNewConn)
  973. {
  974.     HX_ASSERT(!m_bConnected);
  975.     HX_ASSERT(!m_bInitComplete);
  976.     HX_ASSERT(m_pCtrl == NULL);
  977.     m_pCtrl = pNewConn;
  978.     m_pCtrl->AddRef();
  979.     m_pCtrl->nonblocking();
  980.     if ( m_pCallback )
  981.     {
  982. HX_DELETE(m_pCallback);
  983.     }
  984.     m_pCallback = new TCPSocketCallback;
  985.     if ( !m_pCallback )
  986.     {
  987. return HXR_OUTOFMEMORY;
  988.     }
  989.     m_pCallback->m_pContext = this;
  990.     m_pCtrl->set_callback(m_pCallback);
  991.     m_lForeignAddress = DwToHost(m_pCtrl->get_addr());
  992.     m_bInitComplete = TRUE;
  993.     m_bConnected = TRUE;
  994.     return HXR_OK;
  995. }
  996. HX_RESULT
  997. HXTCPSocket::DoRead()
  998. {
  999. #ifdef _MACINTOSH
  1000. if (m_bInDoRead)
  1001. {
  1002. return HXR_OK; // whatever needs to be done will be done by the caller that's already here.
  1003. // xxxbobclark the m_bInDoRead flag is hacked around calling ReadDone(), because
  1004. //             ReadDone() may call Read() which in turn calls us here, and we do
  1005. //             not want to bail out in that instance. (Otherwise we only remove
  1006. //             one packet at a time, which, given the scheduler granularity and
  1007. //             high bit rates, implies that our bandwidth would be too low.)
  1008. }
  1009. #endif
  1010. m_bInDoRead = TRUE;
  1011.     HX_RESULT theErr = HXR_OK;
  1012.     // check how much room we have in TCP receive queue
  1013.     UINT16 count = mReceiveTCP->GetMaxAvailableElements();
  1014.     if (count > 0)
  1015.     {
  1016. #if !defined(THREADS_SUPPORTED) && !defined(_UNIX_THREADED_NETWORK_IO)
  1017. UINT32 ulBytesToRead = conn::bytes_to_preparetcpread(m_pCtrl);
  1018. if (ulBytesToRead > 0)
  1019. {
  1020.     if ((UINT32)count > ulBytesToRead)
  1021.     {
  1022. count = (UINT16)ulBytesToRead;
  1023.     }
  1024.     // attempt to read data from TCP link
  1025.     theErr = m_pCtrl->read(m_pBuffer, &count);
  1026.     if (!theErr && count > 0)
  1027.     {
  1028. conn::bytes_to_actualtcpread(m_pCtrl, (UINT32)count);
  1029. mReceiveTCP->EnQueue(m_pBuffer, count);
  1030.     }
  1031.     else if (theErr)
  1032.     {
  1033. theErr = ConvertNetworkError(theErr);
  1034.     }
  1035. }
  1036. #elif defined(_UNIX_THREADED_NETWORK_IO)
  1037.         //XXXgfw duplicated code. Clean this up...
  1038.         if( ReadNetworkThreadingPref((IUnknown*)m_pContext) )
  1039.         {
  1040.             // in THREADS_SUPPORTED mode, this will be taken care by the thrdconn.cpp
  1041.             // attempt to read data from TCP link
  1042.             theErr = m_pCtrl->read(m_pBuffer, &count);
  1043.             if (!theErr && count > 0)
  1044.             {
  1045.                 mReceiveTCP->EnQueue(m_pBuffer, count);
  1046.             }
  1047.             else if (theErr)
  1048.             {
  1049.                 theErr = ConvertNetworkError(theErr);
  1050.             }
  1051.         }
  1052.         else
  1053.         {
  1054.             UINT32 ulBytesToRead = conn::bytes_to_preparetcpread(m_pCtrl);
  1055.             if (ulBytesToRead > 0)
  1056.             {
  1057.                 if ((UINT32)count > ulBytesToRead)
  1058.                 {
  1059.                     count = (UINT16)ulBytesToRead;
  1060.                 }
  1061.                 // attempt to read data from TCP link
  1062.                 theErr = m_pCtrl->read(m_pBuffer, &count);
  1063.                 if (!theErr && count > 0)
  1064.                 {
  1065.                     conn::bytes_to_actualtcpread(m_pCtrl, (UINT32)count);
  1066.                     mReceiveTCP->EnQueue(m_pBuffer, count);
  1067.                 }
  1068.                 else if (theErr)
  1069.                 {
  1070.                     theErr = ConvertNetworkError(theErr);
  1071.                 }
  1072.             }
  1073.         }
  1074. #else
  1075. // in THREADS_SUPPORTED mode, this will be taken care by the thrdconn.cpp
  1076. // attempt to read data from TCP link
  1077. theErr = m_pCtrl->read(m_pBuffer, &count);
  1078. if (!theErr && count > 0)
  1079. {
  1080.     mReceiveTCP->EnQueue(m_pBuffer, count);
  1081. }
  1082. else if (theErr)
  1083. {
  1084.     theErr = ConvertNetworkError(theErr);
  1085. }
  1086. #endif /* !THREADS_SUPPORTED */
  1087.     }
  1088.     count = mReceiveTCP->GetQueuedItemCount();
  1089.     if (m_bReadPending && count > 0)
  1090.     {
  1091. /* If we are at interrupt time and the response object is not interrupt safe,
  1092.  * schedule a callback to return back the data
  1093.  */
  1094. if (!IsSafe())
  1095. {
  1096. m_bInDoRead = FALSE;
  1097.     return HXR_OK;
  1098. }
  1099. m_bReadPending = FALSE;
  1100. if (m_nRequired < count)
  1101. {
  1102.     // XXXAAK -- UINT32 down to UINT16 - possible truncation???
  1103.     count = (UINT16)m_nRequired;
  1104. }
  1105. CHXBuffer* pBuffer = new CHXBuffer;
  1106. pBuffer->AddRef();
  1107. mReceiveTCP->DeQueue(m_pBuffer, count);
  1108. pBuffer->Set((UCHAR*) m_pBuffer, count);
  1109. m_bInDoRead = FALSE;
  1110. theErr = m_pTCPResponse->ReadDone(HXR_OK, pBuffer);
  1111. m_bInDoRead = TRUE;
  1112. pBuffer->Release();
  1113. /* mask any kind of errors */
  1114.         // Huh??? Don't mask OUTOFMEMORY errors!
  1115.         if( theErr != HXR_OUTOFMEMORY )
  1116.         {
  1117.     theErr = HXR_OK;
  1118.         }
  1119.     }
  1120.     if (theErr && m_bReadPending)
  1121.     {
  1122. /* If we are at interrupt time and the response object is not interrupt safe,
  1123.  * schedule a callback to return back the data
  1124.  */
  1125. if (!IsSafe())
  1126. {
  1127. m_bInDoRead = FALSE;
  1128.     return HXR_OK;
  1129. }
  1130. #ifdef _MACINTOSH
  1131. if (m_pMacCommandCallback && m_pMacCommandCallback->ScheduleCallback(TCP_READ_DONE_COMMAND, m_pScheduler, 0, theErr))
  1132. {
  1133.     m_bReadPending = FALSE;
  1134.          m_bInDoRead = FALSE;
  1135.     return HXR_OK;
  1136. }
  1137. else
  1138. {
  1139.     // failed to schedule a callback, notify the responser with error directly
  1140.     m_bReadPending = FALSE;
  1141.     m_pTCPResponse->ReadDone(theErr, NULL);
  1142. }
  1143. #else
  1144. m_bReadPending = FALSE;
  1145. m_pTCPResponse->ReadDone(theErr, NULL);
  1146. #endif
  1147.     }
  1148.     if (!theErr     &&
  1149. m_bReadPending     &&
  1150. m_pSchedulerReadCallback)
  1151. {
  1152.     m_pSchedulerReadCallback->ScheduleCallback(TCP_READ_COMMAND, m_pScheduler, SCHED_GRANULARITY);
  1153.     }
  1154.   m_bInDoRead = FALSE;
  1155.     return theErr;
  1156. }
  1157. HX_RESULT
  1158. HXTCPSocket::DoWrite()
  1159. {
  1160.     HX_RESULT theErr = HXR_OK;
  1161.     if (m_bInWrite) return HXR_OK;
  1162.     m_bInWrite = TRUE;
  1163. #ifdef _MACINTOSH
  1164. if (m_pInterruptSafeMacWriteQueue)
  1165. m_pInterruptSafeMacWriteQueue->TransferToSimpleList(m_PendingWriteBuffers);
  1166. TransferBuffers(); // PENDING_BUFFERS_ARE_EMPTIED_AT_START_OF_DO_WRITE
  1167. #endif
  1168.     // check how data we have in TCP send queue
  1169.     UINT16 count    = mSendTCP->GetQueuedItemCount();
  1170.     UINT16 actual   = count;
  1171.     if(count > 0)
  1172.     {
  1173. mSendTCP->DeQueue(m_pBuffer,count);
  1174. theErr = m_pCtrl->write(m_pBuffer, &actual);
  1175.     }
  1176.     switch(theErr)
  1177.     {
  1178. case HXR_AT_INTERRUPT:
  1179. case HXR_WOULD_BLOCK:
  1180. case HXR_OK:
  1181.     // enqueue the data that was not sent
  1182.     if(actual != count)
  1183.     {
  1184. mSendTCP->EnQueue(m_pBuffer + actual, count - actual);
  1185.     }
  1186.     // mask out these errors
  1187.     theErr = HXR_OK;
  1188.     break;
  1189. default:
  1190.     theErr = ConvertNetworkError(theErr);
  1191.     break;
  1192.     }
  1193.     if (!theErr && m_bWantWritePending && mSendTCP->GetQueuedItemCount() == 0)
  1194.     {
  1195. m_bWantWritePending = FALSE;
  1196. m_pTCPResponse->WriteReady(HXR_OK);
  1197.     }
  1198. #ifndef _MACINTOSH
  1199. // m_PendingWriteBuffers will always be empty due to the full buffer transfer at the top of this routine.
  1200. // see PENDING_BUFFERS_ARE_EMPTIED_AT_START_OF_DO_WRITE
  1201.     if (!theErr && m_PendingWriteBuffers.GetCount()  > 0)
  1202.     {
  1203. TransferBuffers();
  1204.     }
  1205. #endif
  1206.     if (!theErr &&
  1207. ((mSendTCP && mSendTCP->GetQueuedItemCount() > 0) ||
  1208. m_PendingWriteBuffers.GetCount() > 0)) // see PENDING_BUFFERS_ARE_EMPTIED_AT_START_OF_DO_WRITE
  1209.     {
  1210. if (m_pSchedulerWriteCallback)
  1211. {
  1212.     m_pSchedulerWriteCallback->ScheduleCallback(TCP_WRITE_COMMAND, m_pScheduler, SCHED_GRANULARITY);
  1213. }
  1214.     }
  1215.     if (m_bWriteFlushPending &&
  1216. ((mSendTCP->GetQueuedItemCount() == 0 &&
  1217.  m_PendingWriteBuffers.GetCount() == 0) ||
  1218.  theErr))
  1219.     {
  1220. m_bWriteFlushPending = FALSE;
  1221. Release();
  1222.     }
  1223.     else if (!theErr && !m_bWriteFlushPending &&
  1224. (mSendTCP->GetQueuedItemCount() > 0 || m_PendingWriteBuffers.GetCount() > 0))
  1225.     {
  1226. m_bWriteFlushPending = TRUE;
  1227. AddRef();
  1228.     }
  1229.     m_bInWrite = FALSE;
  1230.     return theErr;
  1231. }
  1232. /* If we are at interrupt time and the response object is not interrupt safe,
  1233.  * schedule a callback to return back the data
  1234.  */
  1235. BOOL
  1236. HXTCPSocket::IsSafe()
  1237. {
  1238.     if (m_pInterruptState && m_pInterruptState->AtInterruptTime() &&
  1239. (!m_pResponseInterruptSafe ||
  1240.  !m_pResponseInterruptSafe->IsInterruptSafe()))
  1241.     {
  1242. if (m_pNonInterruptReadCallback)
  1243. {
  1244.     m_pNonInterruptReadCallback->ScheduleCallback(TCP_READ_COMMAND, m_pScheduler, 0);
  1245. }
  1246. return FALSE;
  1247.     }
  1248.     return TRUE;
  1249. }
  1250. void
  1251. HXTCPSocket::ConnectDone(BOOL bResult)
  1252. {
  1253.     AddRef();
  1254.     if (bResult == TRUE)
  1255.     {
  1256. m_bConnected = TRUE;
  1257. //XXX need to set m_lForeignAddr here
  1258. //XXXJR hack!
  1259. m_lForeignAddress = DwToHost(m_pCtrl->get_addr());
  1260. m_pTCPResponse->ConnectDone(HXR_OK);
  1261.     }
  1262.     else
  1263.     {
  1264. #ifdef _MACINTOSH
  1265. if (!(m_pMacCommandCallback && m_pMacCommandCallback->ScheduleCallback(TCP_CONNECT_DONE_COMMAND, m_pScheduler, 0, HXR_NET_CONNECT)))
  1266. {
  1267. //note: only happens when there's a problem (e.g. macleod 1/2 server problem)
  1268. m_pTCPResponse->ConnectDone(HXR_NET_CONNECT); // couldn't use the delayed callback... take our chances.
  1269. }
  1270. #else
  1271. m_pTCPResponse->ConnectDone(HXR_NET_CONNECT);
  1272. #endif
  1273.     }
  1274.     Release();
  1275. }
  1276. void
  1277. HXTCPSocket::CloseDone()
  1278. {
  1279.     m_pTCPResponse->Closed(HXR_OK);
  1280. }
  1281. void
  1282. HXTCPSocket::DNSDone(BOOL bSuccess)
  1283. {
  1284.     AddRef();
  1285.     if (!bSuccess)
  1286.     {
  1287. m_pTCPResponse->ConnectDone(HXR_DNR);
  1288.     }
  1289.     Release();
  1290. }
  1291. void
  1292. HXTCPSocket::TransferBuffers()
  1293. {
  1294.     IHXBuffer* pBuffer = 0;
  1295.     while (m_PendingWriteBuffers.GetCount() > 0)
  1296.     {
  1297. pBuffer = (IHXBuffer*) m_PendingWriteBuffers.GetHead();
  1298. if ((UINT16) pBuffer->GetSize() < mSendTCP->GetMaxAvailableElements())
  1299. {
  1300.     mSendTCP->EnQueue( pBuffer->GetBuffer(),
  1301. (UINT16) pBuffer->GetSize());
  1302.     pBuffer->Release();
  1303.     m_PendingWriteBuffers.RemoveHead();
  1304. }
  1305. else
  1306. {
  1307.     break;
  1308. }
  1309.     }
  1310. }
  1311. STDMETHODIMP
  1312. HXTCPSocket::SetOption(HX_SOCKET_OPTION option, UINT32 ulValue)
  1313. {
  1314.     HX_RESULT res = HXR_OK;
  1315.     switch(option)
  1316.     {
  1317.     case HX_SOCKOPT_REUSE_ADDR:
  1318. m_bReuseAddr = (BOOL)ulValue;
  1319.     break;
  1320.     case HX_SOCKOPT_REUSE_PORT:
  1321. m_bReusePort = (BOOL)ulValue;
  1322.     break;
  1323.     case HX_SOCKOPT_MULTICAST_IF:
  1324. res = HXR_UNEXPECTED;
  1325.     break;
  1326.     default:
  1327. HX_ASSERT(!"I don't know this option");
  1328. res = HXR_FAIL;
  1329.     }
  1330.     return res;
  1331. }
  1332. STDMETHODIMP
  1333. HXTCPSocket::SetSecure(BOOL bSecure)
  1334. {
  1335.     HX_RESULT res = HXR_OK;
  1336.     m_bSecureSocket = bSecure;
  1337.     return res;
  1338. }
  1339. STDMETHODIMP HXTCPSocket::HandleCallback(INT32 theCommand, HX_RESULT theError)
  1340. {
  1341.     HX_RESULT theErr = HXR_OK;
  1342.     if (!m_bInDestructor)
  1343.     {
  1344. AddRef();
  1345. m_pMutex->Lock();
  1346. if (!m_bInDestructor)
  1347. {
  1348. switch(theCommand)
  1349. {
  1350. case TCP_READ_COMMAND:
  1351.     theErr = DoRead();
  1352.     break;
  1353. case TCP_WRITE_COMMAND:
  1354.     DoWrite(); // protected from re-entry by m_bInWrite
  1355.     break;
  1356. case TCP_READ_DONE_COMMAND:
  1357.      m_bReadPending = FALSE;
  1358. m_pTCPResponse->ReadDone(theError, NULL);
  1359.     break;
  1360. case TCP_CONNECT_DONE_COMMAND:
  1361. m_pTCPResponse->ConnectDone(theError);
  1362. break;
  1363. case TCP_BIND_COMMAND:
  1364. default:
  1365.     theErr = DoRead();
  1366.     DoWrite();
  1367.     break;
  1368.     }
  1369. }
  1370. m_pMutex->Unlock();
  1371.         // we want out of memory errors to be reported immediately
  1372.         // because fiddling around waiting for the error to propagate
  1373.         // normally will just make the situation worse; mask out all
  1374.         // other errors, as they will eventually get dealt with in
  1375.         // ReadDone() or similar functions.
  1376.         
  1377.         if (theErr != HXR_OUTOFMEMORY)
  1378.         {
  1379.             theErr = HXR_OK;
  1380.         }
  1381.         
  1382. if( theErr )
  1383. {
  1384.     IHXErrorMessages * pErrorNotifier = NULL;
  1385.     IUnknown * pPlayer = NULL;
  1386.     IHXClientEngine* pEngine = NULL;
  1387.     UINT32 nNumPlayers = 0;
  1388.     m_pContext->QueryInterface(IID_IHXClientEngine, (void**)&pEngine);
  1389.     if( pEngine )
  1390.     {
  1391. nNumPlayers = pEngine->GetPlayerCount();
  1392. for( int ii=0; ii<nNumPlayers; ii++ )
  1393. {
  1394.     pEngine->GetPlayer(ii,pPlayer);
  1395.     if( pPlayer )
  1396.     {
  1397. pPlayer->QueryInterface( IID_IHXErrorMessages, (void**)&pErrorNotifier );
  1398.     }
  1399.     if( pErrorNotifier )
  1400.     {
  1401. pErrorNotifier->Report( HXLOG_ERR, theErr, 0, NULL, NULL );
  1402. pErrorNotifier->Release();
  1403.     }
  1404.     HX_RELEASE( pPlayer );
  1405. }
  1406.     }
  1407.     HX_RELEASE( pEngine );
  1408. }
  1409. Release();
  1410.     }
  1411.     return theErr;
  1412. }
  1413. HX_RESULT HXTCPSocket::TCPSocketCallback::Func(NotificationType Type,
  1414.    BOOL bSuccess, conn* pConn)
  1415. {
  1416.     if(m_pContext)
  1417.     {
  1418. switch (Type)
  1419. {
  1420. case READ_NOTIFICATION:
  1421. //
  1422. //  This clears up a problem on the Macintosh where we were getting
  1423. //  interrupt callbacks from the Network device, and could possibly
  1424. //  collide when adding/removing data the same time from the same
  1425. //  socket, at interrupt time, and at system level time.
  1426. //
  1427. #if defined(_UNIX_THREADED_NETWORK_IO)
  1428.             if( !ReadNetworkThreadingPref((IUnknown*)(m_pContext->m_pContext) ))
  1429.             {
  1430.                 m_pContext->AddRef();
  1431.                 m_pContext->m_pMutex->Lock();
  1432.                 m_pContext->DoRead();
  1433.                 m_pContext->m_pMutex->Unlock();
  1434.                 m_pContext->Release();
  1435.             }
  1436. #elif !defined (THREADS_SUPPORTED) && !defined(_MACINTOSH)
  1437.     m_pContext->AddRef();
  1438.     m_pContext->m_pMutex->Lock();
  1439.     m_pContext->DoRead();
  1440.     m_pContext->m_pMutex->Unlock();
  1441.     m_pContext->Release();
  1442. #endif
  1443.     break;
  1444. case WRITE_NOTIFICATION:
  1445. #if defined(_UNIX_THREADED_NETWORK_IO)
  1446.             if( !ReadNetworkThreadingPref((IUnknown*)(m_pContext->m_pContext)) )
  1447.             {
  1448.                 m_pContext->AddRef();
  1449.                 m_pContext->m_pMutex->Lock();
  1450.                 m_pContext->DoWrite();
  1451.                 m_pContext->m_pMutex->Unlock();
  1452.                 m_pContext->Release();
  1453.             }
  1454. #elif !defined (THREADS_SUPPORTED) && !defined(_MACINTOSH)
  1455.     m_pContext->AddRef();
  1456.     m_pContext->m_pMutex->Lock();
  1457.     m_pContext->DoWrite();
  1458.     m_pContext->m_pMutex->Unlock();
  1459.     m_pContext->Release();
  1460. #endif
  1461.     break;
  1462. case CONNECT_NOTIFICATION:
  1463.     m_pContext->ConnectDone(bSuccess);
  1464.     break;
  1465. case CLOSE_NOTIFICATION:
  1466.     m_pContext->CloseDone();
  1467.     break;
  1468. case DNS_NOTIFICATION:
  1469.     m_pContext->DNSDone(bSuccess);
  1470.     break;
  1471. default:
  1472.     break;
  1473. }
  1474.     }
  1475.     return HXR_OK;
  1476. }
  1477. HXListenSocket::HXListenSocket(IUnknown* pContext,
  1478.  HXNetworkServices* pNetworkServices)
  1479. : m_pListenConn(NULL)
  1480. , m_pCallback(NULL)
  1481. , m_pContext(NULL)
  1482.   , m_bReuseAddr(FALSE)
  1483.   , m_bReusePort(FALSE)
  1484. {
  1485.     m_pContext = pContext;
  1486.     m_pContext->AddRef();
  1487.     m_pNetworkServices = pNetworkServices;
  1488.     m_pNetworkServices->AddRef();
  1489.     m_lRefCount = 0;
  1490.     m_pListenResponse = 0;
  1491. }
  1492. HXListenSocket::~HXListenSocket()
  1493. {
  1494.     if (m_pCallback)
  1495.     {
  1496. m_pCallback->m_pContext = 0;
  1497.     }
  1498.     if (m_pListenConn)
  1499.     {
  1500. m_pListenConn->done();
  1501.         m_pListenConn->Release();
  1502.         m_pListenConn = NULL;
  1503.     }
  1504.     HX_RELEASE(m_pContext);
  1505.     HX_DELETE(m_pCallback);
  1506.     HX_RELEASE(m_pListenResponse);
  1507.     HX_RELEASE(m_pNetworkServices);
  1508. }
  1509. STDMETHODIMP HXListenSocket::QueryInterface(REFIID riid, void** ppvObj)
  1510. {
  1511.     QInterfaceList qiList[] =
  1512.         {
  1513.             { GET_IIDHANDLE(IID_IHXListenSocket), (IHXListenSocket*)this },
  1514.             { GET_IIDHANDLE(IID_IHXSetSocketOption), (IHXSetSocketOption*)this },
  1515.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXListenSocket*)this },
  1516.         };
  1517.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  1518. }
  1519. STDMETHODIMP_(ULONG32) HXListenSocket::AddRef()
  1520. {
  1521.     return InterlockedIncrement(&m_lRefCount);
  1522. }
  1523. STDMETHODIMP_(ULONG32) HXListenSocket::Release()
  1524. {
  1525.     if (InterlockedDecrement(&m_lRefCount) > 0)
  1526.     {
  1527.         return m_lRefCount;
  1528.     }
  1529.     delete this;
  1530.     return HXR_OK;
  1531. }
  1532. STDMETHODIMP HXListenSocket::SetOption(HX_SOCKET_OPTION option,
  1533. UINT32 ulValue)
  1534. {
  1535.     HX_RESULT  ret = HXR_OK;
  1536.     switch (option)
  1537.     {
  1538.     case HX_SOCKOPT_REUSE_ADDR:
  1539. m_bReuseAddr = ulValue;
  1540. break;
  1541.     case HX_SOCKOPT_REUSE_PORT:
  1542. m_bReusePort = ulValue;
  1543. break;
  1544.     default:
  1545. ret = HXR_NOTIMPL;
  1546.     }
  1547.     return ret;
  1548. }
  1549. STDMETHODIMP HXListenSocket::Init(UINT32 ulLocalAddr, UINT16 port,
  1550.    IHXListenResponse* pListenResponse)
  1551. {
  1552.     if (!pListenResponse)
  1553.     {
  1554. return HXR_UNEXPECTED;
  1555.     }
  1556.     HX_RELEASE(m_pListenResponse);
  1557.     m_pListenResponse = pListenResponse;
  1558.     m_pListenResponse->AddRef();
  1559. #if defined( _WIN32 ) || defined( _WINDOWS )
  1560.     // Have we been able to load and initialize the winsock stuff yet?
  1561.     if (!win_net::IsWinsockAvailable(this))
  1562.     {
  1563. return HXR_FAIL; // HXR_GENERAL_NONET;
  1564.     }
  1565. #endif
  1566.     m_pNetworkServices->UseDrivers();
  1567. #ifdef _UNIX
  1568.     //This one has to be set before we create a new socket.
  1569.     conn::SetNetworkThreadingPref( ReadNetworkThreadingPref((IUnknown*)m_pContext) );
  1570.     conn::SetThreadedDNSPref( ReadThreadedDNSPref((IUnknown*)m_pContext) );
  1571. #endif
  1572.     HX_RESULT ret = conn::init_drivers(NULL);
  1573.     m_pListenConn = conn::new_socket(HX_TCP_SOCKET);
  1574.     if ( m_pListenConn == NULL )
  1575.     {
  1576. return HXR_OUTOFMEMORY;
  1577.     }
  1578. #ifdef _UNIX
  1579.     m_pListenConn->SetAsyncDNSPref( ReadAsyncDNSPref((IUnknown*)m_pContext) );
  1580. #endif
  1581.     m_pListenConn->nonblocking();
  1582.     m_pListenConn->reuse_addr(m_bReuseAddr);
  1583.     m_pListenConn->reuse_port(m_bReusePort);
  1584.     if ( m_pCallback == NULL)
  1585.     {
  1586. m_pCallback = new ListenSocketCallback();
  1587. m_pCallback->m_pContext = this;
  1588.     }
  1589.     m_pListenConn->set_callback(m_pCallback);
  1590.     UINT32 ulPlatformData = 0;
  1591. #if defined (_WIN32)
  1592.     ulPlatformData = (UINT32)GetModuleHandle(NULL);
  1593. #elif defined (_WIN16)
  1594.     ulPlatformData = (UINT32)(int)g_hInstance;
  1595. #endif
  1596.     return m_pListenConn->listen(ulLocalAddr, port, 2, 0, ulPlatformData);
  1597. }
  1598. HX_RESULT HXListenSocket::ListenSocketCallback::Func(NotificationType Type,
  1599.    BOOL bSuccess, conn* pConn)
  1600. {
  1601.     if(m_pContext)
  1602.     {
  1603. switch (Type)
  1604. {
  1605. case ACCEPT_NOTIFICATION:
  1606.     if ( bSuccess )
  1607.     {
  1608. HXTCPSocket* pSock = new HXTCPSocket(m_pContext->m_pContext,
  1609.     m_pContext->m_pNetworkServices);
  1610.         if ( pSock )
  1611. {
  1612.     pSock->AddRef();
  1613.     if ( SUCCEEDED(pSock->AcceptConnection(pConn)) )
  1614.     {
  1615. m_pContext->m_pListenResponse->NewConnection(HXR_OK,
  1616.     (IHXTCPSocket*)pSock);
  1617.     }
  1618.     HX_RELEASE(pSock);
  1619. }
  1620.     }
  1621.     break;
  1622. case CONNECT_NOTIFICATION:
  1623.     break;
  1624. case READ_NOTIFICATION:
  1625.     break;
  1626. case CLOSE_NOTIFICATION:
  1627.     break;
  1628. case DNS_NOTIFICATION:
  1629. default:
  1630.     break;
  1631. }
  1632.     }
  1633.     return HXR_OK;
  1634. }
  1635. HXUDPSocket::HXUDPSocket(IUnknown* pContext, HXNetworkServices* pNetworkServices):
  1636.     m_lRefCount(0),
  1637.     m_pCallback(0),
  1638.     m_pUDPResponse(0),
  1639.     m_pData(0),
  1640.     m_bReadPending(FALSE),
  1641.     m_bInRead(FALSE),
  1642.     m_bInDoRead(FALSE),
  1643.     m_bInWrite(FALSE),
  1644.     m_nRequired(0),
  1645.     m_pSchedulerReadCallback(NULL),
  1646.     m_pSchedulerWriteCallback(NULL),
  1647.     m_pNonInterruptReadCallback(NULL),
  1648.     m_pScheduler(0),
  1649.     m_nDestPort(0),
  1650.     m_bInitComplete(FALSE),
  1651.     m_pInterruptState(NULL),
  1652.     m_pResponseInterruptSafe(NULL),
  1653.     m_pMutex(NULL),
  1654.     m_bReuseAddr(FALSE),
  1655.     m_bReusePort(FALSE),
  1656.     m_bInDestructor(FALSE),
  1657.     m_pContext(pContext)
  1658. {
  1659. #ifdef _MACINTOSH
  1660. m_pInterruptSafeMacWriteQueue = new InterruptSafeMacQueue();
  1661. HX_ASSERT(m_pInterruptSafeMacWriteQueue != NULL);
  1662. #endif
  1663.     m_pNetworkServices = pNetworkServices;
  1664.     m_pNetworkServices->AddRef();
  1665.     if (pContext)
  1666.     {
  1667. pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
  1668. pContext->QueryInterface(IID_IHXInterruptState, (void**) &m_pInterruptState);
  1669.     }
  1670.     if (m_pScheduler)
  1671.     {
  1672. m_pSchedulerReadCallback = new ScheduledSocketCallback(this, TRUE);
  1673. m_pSchedulerReadCallback->AddRef();
  1674. m_pSchedulerWriteCallback = new ScheduledSocketCallback(this, TRUE);
  1675. m_pSchedulerWriteCallback->AddRef();
  1676. m_pNonInterruptReadCallback = new ScheduledSocketCallback(this, FALSE);
  1677. m_pNonInterruptReadCallback->AddRef();
  1678.     }
  1679. #if defined(THREADS_SUPPORTED)
  1680.     HXMutex::MakeMutex(m_pMutex);
  1681. #elif defined(_UNIX_THREADED_NETWORK_IO)
  1682.     if( ReadNetworkThreadingPref((IUnknown*)m_pContext) )
  1683.     {
  1684.         HXMutex::MakeMutex(m_pMutex);
  1685.     }
  1686.     else
  1687.     {
  1688.         HXMutex::MakeStubMutex(m_pMutex);
  1689.     }
  1690. #else
  1691.     HXMutex::MakeStubMutex(m_pMutex);
  1692. #endif
  1693. }
  1694. HXUDPSocket::~HXUDPSocket()
  1695. {
  1696.     m_bInDestructor = TRUE;
  1697. m_pMutex->Lock();
  1698. #ifdef _MACINTOSH
  1699. HX_DELETE(m_pInterruptSafeMacWriteQueue); // will release any objects in its nodes
  1700. #endif
  1701.     if (m_pSchedulerReadCallback)
  1702.     m_pSchedulerReadCallback->Unschedule(m_pScheduler);
  1703.     if (m_pSchedulerWriteCallback)
  1704.     m_pSchedulerWriteCallback->Unschedule(m_pScheduler);
  1705.     if (m_pNonInterruptReadCallback)
  1706.     m_pNonInterruptReadCallback->Unschedule(m_pScheduler);
  1707.     /*
  1708.      * XXX...While handling the m_pData->done it's possible for the
  1709.      *       DispatchMessage call in CancelSelect to cause an
  1710.      *       asynchronous DoRead to occur. The resulting AddRef/Release
  1711.      *       would cause this object to be deleted again, so to prevent
  1712.      *       this we set the m_pCallback->m_pContext = 0
  1713.      */
  1714.     if (m_pCallback)
  1715.     {
  1716. m_pCallback->m_pContext = 0;
  1717.     }
  1718.     if (m_pData)
  1719.     {
  1720. m_pData->done();
  1721. m_pData->Release();
  1722. m_pData = 0;
  1723.     }
  1724.     if(m_pUDPResponse)
  1725.     {
  1726. m_pUDPResponse->Release();
  1727. m_pUDPResponse = 0;
  1728.     }
  1729.     if (m_pCallback)
  1730.     {
  1731. delete m_pCallback;
  1732. m_pCallback = 0;
  1733.     }
  1734.     if (m_pScheduler)
  1735.     {
  1736. m_pScheduler->Release();
  1737. m_pScheduler = 0;
  1738.     }
  1739.     while (!m_ReadBuffers.IsEmpty())
  1740.     {
  1741. UDP_PACKET* pPacket = (UDP_PACKET*)m_ReadBuffers.RemoveHead();
  1742. HX_RELEASE(pPacket->pBuffer);
  1743. HX_DELETE(pPacket);
  1744.     }
  1745.     HX_RELEASE(m_pInterruptState);
  1746.     HX_RELEASE(m_pResponseInterruptSafe);
  1747.     if (m_pSchedulerReadCallback)
  1748.     {
  1749.      m_pSchedulerReadCallback->m_pSocket = NULL;
  1750.      m_pSchedulerReadCallback->Release();
  1751.      m_pSchedulerReadCallback = NULL;
  1752.     }
  1753.     if (m_pSchedulerWriteCallback)
  1754.     {
  1755.      m_pSchedulerWriteCallback->m_pSocket = NULL;
  1756.      m_pSchedulerWriteCallback->Release();
  1757.      m_pSchedulerWriteCallback = NULL;
  1758.     }
  1759.     if (m_pNonInterruptReadCallback)
  1760.     {
  1761.      m_pNonInterruptReadCallback->m_pSocket = NULL;
  1762.      m_pNonInterruptReadCallback->Release();
  1763.      m_pNonInterruptReadCallback = NULL;
  1764.     }
  1765.     m_pMutex->Unlock();
  1766.     HX_DELETE(m_pMutex);
  1767. #if defined( _WIN32 ) || defined( _WINDOWS )
  1768.     win_net::ReleaseWinsockUsage(this);
  1769. #endif
  1770.     HX_RELEASE(m_pNetworkServices);
  1771. }
  1772. STDMETHODIMP HXUDPSocket::QueryInterface(REFIID riid, void** ppvObj)
  1773. {
  1774.     QInterfaceList qiList[] =
  1775.         {
  1776.             { GET_IIDHANDLE(IID_IHXUDPSocket), (IHXUDPSocket*)this },
  1777.             { GET_IIDHANDLE(IID_IHXSetSocketOption), (IHXSetSocketOption*)this },
  1778.             { GET_IIDHANDLE(IID_IHXUDPMulticastInit), (IHXUDPMulticastInit*)this },
  1779.             { GET_IIDHANDLE(IID_IHXSetPrivateSocketOption), (IHXSetPrivateSocketOption*)this },
  1780.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXUDPSocket*)this },
  1781.         };
  1782.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  1783. }
  1784. STDMETHODIMP_(ULONG32) HXUDPSocket::AddRef()
  1785. {
  1786.     return InterlockedIncrement(&m_lRefCount);
  1787. }
  1788. STDMETHODIMP_(ULONG32) HXUDPSocket::Release()
  1789. {
  1790.     if (InterlockedDecrement(&m_lRefCount) > 0)
  1791.     {
  1792.         return m_lRefCount;
  1793.     }
  1794.     delete this;
  1795.     return 0;
  1796. }
  1797. STDMETHODIMP
  1798. HXUDPSocket::InitMulticast(UINT8 uTTL)
  1799. {
  1800.     if (HXR_OK != m_pData->set_multicast())
  1801.     {
  1802. return HXR_FAIL;
  1803.     }
  1804.     if (HXR_OK != m_pData->set_multicast_ttl(uTTL))
  1805.     {
  1806. return HXR_FAIL;
  1807.     }
  1808.     return HXR_OK;
  1809. }
  1810. STDMETHODIMP HXUDPSocket::Init(ULONG32 ulAddr, UINT16 nPort,
  1811. IHXUDPResponse* pUDPResponse)
  1812. {
  1813.     if (!pUDPResponse && !m_pUDPResponse)
  1814.     {
  1815.         /*
  1816.          * if the response object hasn't been set up yet, then
  1817.          * require a response object (i.e. the first call to Init
  1818.          * must always specify a response object
  1819.          */
  1820. return HXR_UNEXPECTED;
  1821.     }
  1822.     HX_RESULT theErr = HXR_OK;
  1823.     UINT32 ulPlatformData = 0;
  1824.     if (pUDPResponse != NULL)
  1825.     {
  1826.         HX_RELEASE(m_pUDPResponse);
  1827.         m_pUDPResponse = pUDPResponse;
  1828.         m_pUDPResponse->AddRef();
  1829.     }
  1830.     HX_RELEASE(m_pResponseInterruptSafe);
  1831.     m_pUDPResponse->QueryInterface(IID_IHXInterruptSafe,
  1832.    (void**) &m_pResponseInterruptSafe);
  1833.     m_sockAddr.sin_family = AF_INET;
  1834.     m_sockAddr.sin_addr.s_addr = DwToNet(ulAddr);  //*(long*)&ulAddr;
  1835.     m_sockAddr.sin_port = WToNet(nPort);
  1836.     m_nDestPort = nPort;
  1837.     return HXR_OK;
  1838. }
  1839. STDMETHODIMP HXUDPSocket::Bind(UINT32 ulLocalAddr, UINT16 nPort)
  1840. {
  1841.     if (m_bInitComplete)
  1842. return HXR_UNEXPECTED;
  1843. #if defined( _WIN32 ) || defined( _WINDOWS )
  1844.     // Have we been able to load and initialize the winsock stuff yet?
  1845.     if (!win_net::IsWinsockAvailable(this))
  1846.     {
  1847. return HXR_FAIL; // HXR_GENERAL_NONET;
  1848.     }
  1849. #endif
  1850.     m_pNetworkServices->UseDrivers();
  1851.     HX_RESULT theErr = conn::init_drivers(NULL);
  1852.     if (theErr)
  1853.     {
  1854. return (theErr);
  1855.     }
  1856.     theErr = HXR_OK;
  1857.     UINT32 ulPlatformData = 0;
  1858. #ifdef _UNIX
  1859.     //This one has to be set before we create a new socket.
  1860.     conn::SetNetworkThreadingPref( ReadNetworkThreadingPref((IUnknown*)m_pContext) );
  1861.     conn::SetThreadedDNSPref( ReadThreadedDNSPref((IUnknown*)m_pContext) );
  1862. #endif
  1863.     m_pData = conn::new_socket(HX_UDP_SOCKET);
  1864.     if (!m_pData)
  1865.     {
  1866. return HXR_OUTOFMEMORY;
  1867.     }
  1868.     // XXXGo - As it is implemented, this is the only way...
  1869.     if (m_bReuseAddr)
  1870.     {
  1871. if (m_pData->reuse_addr(m_bReuseAddr) != HXR_OK)
  1872. {
  1873.     // err...what do we need to do?
  1874.     HX_ASSERT(!"reuse_addr() failed");
  1875. }
  1876.     }
  1877.     if (m_bReusePort)
  1878.     {
  1879. if (m_pData->reuse_port(m_bReusePort) != HXR_OK)
  1880. {
  1881.     // err...what do we need to do?
  1882.     HX_ASSERT(!"reuse_port() failed");
  1883. }
  1884.     }
  1885. #ifdef _UNIX
  1886.     m_pData->SetAsyncDNSPref( ReadAsyncDNSPref((IUnknown*)m_pContext) );
  1887. #endif
  1888.     // XXXST -- local addr binding stuff, removed dependency to m_nLocalPort
  1889.     // 0 for local port will make the system choose a free port
  1890.     theErr = m_pData->init(ulLocalAddr, nPort);
  1891.     if (theErr)
  1892.     {
  1893. theErr = ConvertNetworkError(theErr);
  1894. if (theErr)
  1895. {
  1896.     m_pData->done();
  1897.     m_pData->Release();
  1898.     m_pData = 0;
  1899.     return theErr;
  1900. }
  1901.     }
  1902.     m_pData->nonblocking();
  1903.     m_pData->set_receive_buf_size(DESIRED_RCV_BUFSIZE);
  1904.     if (!m_pCallback)
  1905.     {
  1906. m_pCallback = new UDPSocketCallback;
  1907. m_pCallback->m_pContext = this;
  1908.     }
  1909.     m_pData->set_callback(m_pCallback);
  1910. #ifdef _WINDOWS
  1911. #if defined (_WIN32)
  1912.     ulPlatformData = (UINT32)GetModuleHandle(NULL);
  1913. #elif defined (_WIN16)
  1914.     ulPlatformData = (UINT32)(int)g_hInstance;
  1915. #endif
  1916.     m_pData->SetWindowHandle(ulPlatformData);
  1917. #endif /* defined (_WINDOWS) */
  1918.     if (m_pSchedulerReadCallback)
  1919.     {
  1920.     m_pSchedulerReadCallback->ScheduleCallback(UDP_BIND_COMMAND, m_pScheduler, SCHED_GRANULARITY);
  1921.     }
  1922.     m_bInitComplete = TRUE;
  1923.     return theErr;
  1924. }
  1925. STDMETHODIMP HXUDPSocket::Read(UINT16 nBytes)
  1926. {
  1927.     if (!m_bInitComplete)
  1928.     {
  1929. HX_RESULT ret = Bind(HXR_INADDR_ANY, 0);
  1930. if (HXR_OK != ret)
  1931.     return HXR_UNEXPECTED;
  1932.     }
  1933.     HX_RESULT theErr = HXR_OK;
  1934.     if(m_bReadPending)
  1935.     {
  1936. return HXR_UNEXPECTED;
  1937.     }
  1938.     m_bReadPending = TRUE;
  1939.     if (m_bInRead)
  1940.     {
  1941. return HXR_OK;
  1942.     }
  1943.     m_bInRead = TRUE;
  1944.     m_pMutex->Lock();
  1945.     UINT16 uNumIterations = 0;
  1946.     do
  1947.     {
  1948. theErr = DoRead();
  1949. uNumIterations++;
  1950.     } while (m_bReadPending && !theErr && m_ReadBuffers.GetCount() > 0 && uNumIterations < MAX_ITERATION_COUNT);
  1951.     m_pMutex->Unlock();
  1952.     theErr = ConvertNetworkError(theErr);
  1953.     if (m_bReadPending && m_pSchedulerReadCallback)
  1954.     m_pSchedulerReadCallback->ScheduleCallback(UDP_READ_COMMAND, m_pScheduler, SCHED_GRANULARITY);
  1955.     m_bInRead = FALSE;
  1956.     return theErr;
  1957. }
  1958. STDMETHODIMP HXUDPSocket::Write(IHXBuffer* pBuffer)
  1959. {
  1960.     if (!m_bInitComplete)
  1961.     {
  1962. HX_RESULT ret = Bind(HXR_INADDR_ANY, 0);
  1963. if (HXR_OK != ret)
  1964.     return HXR_UNEXPECTED;
  1965.     }
  1966.     HX_RESULT theErr = HXR_OK;
  1967.     HX_RESULT lResult = HXR_OK;
  1968. #if 0
  1969.     struct in_addr in;
  1970.     in.s_addr = m_sockAddr.sin_addr.s_addr;
  1971.     char* address = inet_ntoa(in);
  1972.     printf("address = %s:", address);
  1973.     UINT32 port = ntohl(m_sockAddr.sin_port);
  1974.     printf("%dn", port);
  1975. #endif /* 0 */
  1976. #ifdef _MACINTOSH
  1977. if (m_pInterruptSafeMacWriteQueue)
  1978. m_pInterruptSafeMacWriteQueue->AddTail(pBuffer); // AddRef called inside
  1979. #else
  1980. pBuffer->AddRef();
  1981. m_WriteBuffers.AddTail((void*) pBuffer);
  1982. #endif
  1983.     m_pMutex->Lock();
  1984.     theErr = DoWrite();
  1985.     m_pMutex->Unlock();
  1986.     lResult = ConvertNetworkError(theErr);
  1987.     return lResult;
  1988. }
  1989. STDMETHODIMP HXUDPSocket::WriteTo(ULONG32 ulAddr,
  1990.     UINT16 nPort, IHXBuffer* pBuffer)
  1991. {
  1992.     if (!m_bInitComplete)
  1993.     {
  1994. HX_RESULT ret = Bind(HXR_INADDR_ANY, 0);
  1995. if (HXR_OK != ret)
  1996.     return HXR_UNEXPECTED;
  1997.     }
  1998.     m_sockAddr.sin_family = AF_INET;
  1999.     m_sockAddr.sin_addr.s_addr = DwToNet(ulAddr);   //*(long*)&ulAddr;
  2000.     m_sockAddr.sin_port = WToNet(nPort);
  2001.     return (Write(pBuffer));
  2002. }
  2003. STDMETHODIMP HXUDPSocket::GetLocalPort(UINT16& nPort)
  2004. {
  2005.     // Get the local port from the socket info
  2006.     nPort = m_pData->get_local_port();
  2007.     return (INT16)nPort < 0 ? HXR_OK : HXR_FAIL;
  2008. }
  2009. STDMETHODIMP HXUDPSocket::JoinMulticastGroup(
  2010.     ULONG32     ulMulticastAddr,
  2011.     ULONG32     ulInterfaceAddr)
  2012. {
  2013. #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
  2014.     HX_RESULT theErr = HXR_OK;
  2015.     HX_RESULT lResult = HXR_OK;
  2016.     m_pMutex->Lock();
  2017.     theErr = m_pData->join_multicast_group(ulMulticastAddr, ulInterfaceAddr);
  2018.     lResult = ConvertNetworkError(theErr);
  2019.     m_pMutex->Unlock();
  2020.     return lResult;
  2021. #else
  2022.     return HXR_NOTIMPL;
  2023. #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
  2024. }
  2025. STDMETHODIMP HXUDPSocket::LeaveMulticastGroup(
  2026.     ULONG32     ulMulticastAddr,
  2027.     ULONG32     ulInterfaceAddr)
  2028. {
  2029. #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
  2030.     HX_RESULT theErr = HXR_OK;
  2031.     HX_RESULT lResult = HXR_OK;
  2032.     m_pMutex->Lock();
  2033.     theErr = m_pData->leave_multicast_group(ulMulticastAddr, ulInterfaceAddr);
  2034.     while (!m_ReadBuffers.IsEmpty())
  2035.     {
  2036. UDP_PACKET* pPacket = (UDP_PACKET*)m_ReadBuffers.RemoveHead();
  2037. HX_RELEASE(pPacket->pBuffer);
  2038. HX_DELETE(pPacket);
  2039.     }
  2040.     lResult = ConvertNetworkError(theErr);
  2041.     m_pMutex->Unlock();
  2042.     return lResult;
  2043. #else
  2044.     return HXR_NOTIMPL;
  2045. #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
  2046. }
  2047. HX_RESULT
  2048. HXUDPSocket::DoRead()
  2049. {
  2050. #ifdef _MACINTOSH
  2051. if (m_bInDoRead)
  2052. return HXR_OK; // whatever needs to be done will be done by the caller that's already here.
  2053. // xxxbobclark the m_bInDoRead flag is hacked around calling ReadDone(), because
  2054. //             ReadDone() may call Read() which in turn calls us here, and we do
  2055. //             not want to bail out in that instance. (Otherwise we only remove
  2056. //             one packet at a time, which, given the scheduler granularity and
  2057. //             high bit rates, implies that our bandwidth would be too low.)
  2058. #endif
  2059. m_bInDoRead = TRUE;
  2060.     HX_RESULT theErr = HXR_OK;
  2061.     IHXBuffer* pBuffer = 0;
  2062.     UINT32  ulAddress = 0;
  2063.     UINT16  ulPort = 0;
  2064.     UINT16  count = 0;
  2065.     do
  2066.     {
  2067. /*
  2068.  * Must reset count before every read
  2069.  */
  2070. count = TCP_BUF_SIZE;
  2071. theErr = m_pData->readfrom(pBuffer, ulAddress, ulPort);
  2072. if (!theErr && pBuffer)
  2073. {
  2074.     UDP_PACKET* pPacket = new UDP_PACKET;
  2075.     pPacket->pBuffer = pBuffer;
  2076.     pPacket->ulAddress = ulAddress;
  2077.     pPacket->ulPort = ulPort;
  2078.     m_ReadBuffers.AddTail((void*)pPacket);
  2079. }
  2080. else
  2081. {
  2082.     count = 0;
  2083. }
  2084.     } while (!theErr && count > 0);
  2085.     if (m_bReadPending && m_ReadBuffers.GetCount() > 0)
  2086.     {
  2087. /* If we are at interrupt time and the response object is not
  2088.  * interrupt safe, schedule a callback to return back the data
  2089.  */
  2090. if (!IsSafe())
  2091. {
  2092. m_bInDoRead = FALSE;
  2093.     return HXR_AT_INTERRUPT;
  2094. }
  2095. m_bReadPending = FALSE;
  2096. UDP_PACKET* pPacket = (UDP_PACKET*)m_ReadBuffers.RemoveHead();
  2097. pBuffer = pPacket->pBuffer;
  2098. ulAddress = pPacket->ulAddress;
  2099. ulPort = pPacket->ulPort;
  2100. AddRef();
  2101. m_bInDoRead = FALSE;
  2102. m_pUDPResponse->ReadDone(HXR_OK, pBuffer, ulAddress, ulPort);
  2103. m_bInDoRead = TRUE;
  2104. HX_RELEASE(pBuffer);
  2105. HX_DELETE(pPacket);
  2106. Release();
  2107. m_bInDoRead = FALSE;
  2108. return HXR_OK;
  2109.     }
  2110.     /* if we called from within Read(), we will schedule a callback there, if necessary */
  2111.     if (!m_bInRead && m_pSchedulerReadCallback)
  2112.     m_pSchedulerReadCallback->ScheduleCallback(UDP_READ_COMMAND, m_pScheduler, SCHED_GRANULARITY);
  2113. m_bInDoRead = FALSE;
  2114. return theErr;
  2115. }
  2116. HX_RESULT
  2117. HXUDPSocket::DoWrite()
  2118. {
  2119.     HX_RESULT theErr = HXR_OK;
  2120.     if (m_bInWrite) return HXR_OK;
  2121.     m_bInWrite = TRUE;
  2122. #ifdef _MACINTOSH
  2123. if (m_pInterruptSafeMacWriteQueue)
  2124. m_pInterruptSafeMacWriteQueue->TransferToSimpleList(m_WriteBuffers);
  2125. #endif
  2126.     while (!theErr && m_WriteBuffers.GetCount() > 0)
  2127.     {
  2128. IHXBuffer* pBuffer = (IHXBuffer*) m_WriteBuffers.GetHead();
  2129. UINT16 uLength = (UINT16) pBuffer->GetSize();
  2130. theErr = m_pData->writeto(  pBuffer->GetBuffer(),   // sendto
  2131.     &uLength,
  2132.     (UINT32) m_sockAddr.sin_addr.s_addr,
  2133.     WToHost(m_sockAddr.sin_port));
  2134. if (!theErr)
  2135. {
  2136.     pBuffer->Release();
  2137.     m_WriteBuffers.RemoveHead();
  2138. }
  2139.     }
  2140.     if (m_pSchedulerWriteCallback &&
  2141. m_WriteBuffers.GetCount() > 0)
  2142.     {
  2143.     m_pSchedulerWriteCallback->ScheduleCallback(UDP_WRITE_COMMAND, m_pScheduler, SCHED_GRANULARITY);
  2144.     }
  2145.     m_bInWrite = FALSE;
  2146.     return theErr;
  2147. }
  2148. /* If we are at interrupt time and the response object is not interrupt safe,
  2149.  * schedule a callback to return back the data
  2150.  */
  2151. BOOL
  2152. HXUDPSocket::IsSafe()
  2153. {
  2154.     if (m_pInterruptState && m_pInterruptState->AtInterruptTime() &&
  2155. (!m_pResponseInterruptSafe ||
  2156.  !m_pResponseInterruptSafe->IsInterruptSafe()))
  2157.     {
  2158. if (m_pNonInterruptReadCallback){
  2159. m_pNonInterruptReadCallback->ScheduleCallback(UDP_READ_COMMAND, m_pScheduler, 0);
  2160. }
  2161. return FALSE;
  2162.     }
  2163.     return TRUE;
  2164. }
  2165. STDMETHODIMP HXUDPSocket::HandleCallback(INT32  theCommand, HX_RESULT theError)
  2166. {
  2167.     HX_RESULT theErr = HXR_OK;
  2168.     if (!m_bInDestructor)
  2169.     {
  2170. AddRef();
  2171. m_pMutex->Lock();
  2172. if (!m_bInDestructor)
  2173. {
  2174. switch(theCommand)
  2175. {
  2176. case UDP_READ_COMMAND:
  2177.     theErr = DoRead();
  2178.     break;
  2179. case UDP_WRITE_COMMAND:
  2180.     theErr = DoWrite();  // protected from re-entry by m_bInWrite
  2181.     break;
  2182. default:
  2183.     theErr = DoRead();
  2184.                             if( theErr == HXR_OK )
  2185.                             {
  2186.         theErr = DoWrite();
  2187.                             }
  2188.     break;
  2189.     }
  2190. }
  2191. m_pMutex->Unlock();
  2192. Release();
  2193.     }
  2194.     return theErr;
  2195. }
  2196. HX_RESULT HXUDPSocket::UDPSocketCallback::Func(NotificationType Type,
  2197.        BOOL bSuccess, conn* pConn)
  2198. {
  2199.     if(m_pContext)
  2200.     {
  2201. switch (Type)
  2202. {
  2203. case READ_NOTIFICATION:
  2204. #if defined(_UNIX_THREADED_NETWORK_IO)
  2205.             if( !ReadNetworkThreadingPref((IUnknown*)(m_pContext->m_pContext)) )
  2206.             {
  2207.                 m_pContext->AddRef();
  2208.                 m_pContext->m_pMutex->Lock();
  2209.                 m_pContext->DoRead();
  2210.                 m_pContext->m_pMutex->Unlock();
  2211.                 m_pContext->Release();
  2212.             }
  2213. #elif !defined (THREADS_SUPPORTED) && !defined(_MACINTOSH)
  2214.     m_pContext->AddRef();
  2215.     m_pContext->m_pMutex->Lock();
  2216.     m_pContext->DoRead();
  2217.     m_pContext->m_pMutex->Unlock();
  2218.     m_pContext->Release();
  2219. #endif
  2220.     break;
  2221. case WRITE_NOTIFICATION:
  2222. #if defined(_UNIX_THREADED_NETWORK_IO)
  2223.             if( !ReadNetworkThreadingPref((IUnknown*)(m_pContext->m_pContext)) )
  2224.             {
  2225.                 m_pContext->AddRef();
  2226.                 m_pContext->m_pMutex->Lock();
  2227.                 m_pContext->DoWrite();
  2228.                 m_pContext->m_pMutex->Unlock();
  2229.                 m_pContext->Release();
  2230.             }
  2231. #elif !defined (THREADS_SUPPORTED) && !defined(_MACINTOSH)
  2232.     m_pContext->AddRef();
  2233.     m_pContext->m_pMutex->Lock();
  2234.     m_pContext->DoWrite();
  2235.     m_pContext->m_pMutex->Unlock();
  2236.     m_pContext->Release();
  2237. #endif
  2238.     break;
  2239. case CONNECT_NOTIFICATION:
  2240. default:
  2241.     break;
  2242. }
  2243.     }
  2244.     return HXR_OK;
  2245. }
  2246. STDMETHODIMP
  2247. HXUDPSocket::SetOption(HX_SOCKET_OPTION option, UINT32 ulValue)
  2248. {
  2249.     HX_RESULT res = HXR_OK;
  2250.     switch(option)
  2251.     {
  2252.     case HX_SOCKOPT_REUSE_ADDR:
  2253. m_bReuseAddr = (BOOL)ulValue;
  2254.     break;
  2255.     case HX_SOCKOPT_REUSE_PORT:
  2256. m_bReusePort = (BOOL)ulValue;
  2257.     break;
  2258. case HX_SOCKOPT_BROADCAST:
  2259. {
  2260. HX_RESULT theErr = HXR_OK;
  2261. if(m_pData)
  2262. {
  2263. m_pMutex->Lock();
  2264. theErr = m_pData->set_broadcast(ulValue);
  2265. res = ConvertNetworkError(theErr);
  2266. m_pMutex->Unlock();
  2267. }
  2268. }
  2269. break;
  2270.     case HX_SOCKOPT_MULTICAST_IF:
  2271. if (m_pData)
  2272. {
  2273.     res = m_pData->set_multicast_if(ulValue);
  2274. }
  2275. break;
  2276.     case HX_SOCKOPT_SET_SENDBUF_SIZE:
  2277.     {
  2278.       if (m_pData)
  2279.       {
  2280.           HX_RESULT theErr = HXR_OK;
  2281.            m_pMutex->Lock();
  2282.            theErr = m_pData->set_send_size(ulValue);
  2283.            res = ConvertNetworkError(theErr);
  2284.            m_pMutex->Unlock();
  2285.       }
  2286.       break;
  2287.     }
  2288.     default:
  2289. HX_ASSERT(!"I don't know this option");
  2290. res = HXR_FAIL;
  2291.     }
  2292.     return res;
  2293. }
  2294. STDMETHODIMP
  2295. HXUDPSocket::SetOption(HX_PRIVATE_SOCKET_OPTION option, UINT32 ulValue)
  2296. {
  2297.     HX_RESULT res = HXR_OK;
  2298.     switch(option)
  2299.     {
  2300.     case HX_PRIVATE_SOCKOPT_IGNORE_WSAECONNRESET:
  2301.     {
  2302. if (m_pData)
  2303. {
  2304.     m_pMutex->Lock();
  2305.     m_pData->IgnoreWSAECONNRESET((BOOL)ulValue);
  2306.     m_pMutex->Unlock();
  2307. }
  2308. break;
  2309.     }
  2310.     default:
  2311. HX_ASSERT(!"I don't know this option");
  2312. res = HXR_FAIL;
  2313.     }
  2314.     return HXR_OK;
  2315. }
  2316. #ifdef _MACINTOSH
  2317. /////////////////////////////////////////////////////////////////////////
  2318. //
  2319. // InterruptSafeMacQueue
  2320. //
  2321. // For passing data between an interrupt and anything else (mac only).
  2322. //
  2323. InterruptSafeMacQueue::InterruptSafeMacQueue()
  2324. {
  2325.   mQueueHeader.qFlags=0;
  2326. mQueueHeader.qHead=0;
  2327. mQueueHeader.qTail=0;
  2328. mDestructing = FALSE; // just a safety check
  2329. }
  2330. /////////////////////////////////////////////////////////////////////////
  2331. //
  2332. HX_RESULT InterruptSafeMacQueue::AddTail(IUnknown* pObject)
  2333. {
  2334. if (pObject && !mDestructing)
  2335. {
  2336.     IhxQueueElement * theElement = new IhxQueueElement();
  2337.     if (theElement)
  2338.     {
  2339.     theElement->mNextElementInQueue = NULL;
  2340.     theElement->mObject = pObject;
  2341.     theElement->mObject->AddRef();
  2342.     ::Enqueue((QElem *)theElement, &mQueueHeader);
  2343.     //
  2344.     // If someone interrupts and enters the destructor while we're in here,
  2345.     // then the pObject and the new node will be leaked.  This shouldn't
  2346.     // happen since we should have shut down all interrupts that would
  2347.     // be adding items to the queue long before we start destructing it.
  2348.     //
  2349.     HX_ASSERT(!mDestructing); // if we DID enter the destructor, let the programmer know...
  2350.     }
  2351.     return HXR_OK;
  2352.     }
  2353.     return HXR_FAILED;
  2354. }
  2355. /////////////////////////////////////////////////////////////////////////
  2356. //
  2357. IUnknown * InterruptSafeMacQueue::RemoveHead()
  2358. {
  2359. //
  2360.     // POINT A
  2361.     //
  2362.     // You can look at the qHead anytime you want, but you can't USE a
  2363.     // pointer unless it's OFF of the queue.  Basically you do a Dequeue,
  2364.     // and if it succeeds then you know nobody else has it.  If it fails,
  2365.     // an error is returned and you don't mess with it.
  2366.     //
  2367. if (mQueueHeader.qHead)
  2368.     {
  2369.   IhxQueueElement * theElement = (IhxQueueElement *) mQueueHeader.qHead;
  2370. if (theElement)
  2371. {
  2372. OSErr e = ::Dequeue( (QElemPtr) theElement, &mQueueHeader );
  2373. //
  2374. // Between points A and D, we can't be guaranteed that the queue header and theElement are valid.  But
  2375. // Dequeue will TELL us if that pointer is still valid by its return code.  If it can't remove the item
  2376. // from the queue, then somebody else did and the pointer is no longer ours.  If no error was returned
  2377. // from dequeue, then it's ours to mess with.
  2378. //
  2379. if (e == noErr)
  2380. {
  2381. // at this point we know that we can do whatever we need to with the object.
  2382. IUnknown * theObj = theElement->mObject;
  2383. delete theElement; // delete the node
  2384. return theObj;
  2385. }
  2386. }
  2387.    }
  2388.    return NULL;
  2389. }
  2390. /////////////////////////////////////////////////////////////////////////
  2391. //
  2392. HX_RESULT InterruptSafeMacQueue::TransferToSimpleList(CHXSimpleList &simpleList)
  2393. {
  2394. IUnknown * theObject;
  2395. // we did an AddRef in the AddTail call -- just pass it along to the simplelist
  2396. while ((theObject = RemoveHead()) != 0)
  2397. {
  2398. simpleList.AddTail((void *)theObject);
  2399. }
  2400.    return HXR_OK;
  2401. }
  2402. /////////////////////////////////////////////////////////////////////////
  2403. //
  2404. InterruptSafeMacQueue::~InterruptSafeMacQueue()
  2405. {
  2406. mDestructing = TRUE; // don't add anything else to the queue
  2407. IUnknown * theObject;
  2408. while ((theObject = RemoveHead()) != 0)
  2409.     {
  2410. theObject->Release();
  2411.     }
  2412.     // and just to be safe...
  2413. mQueueHeader.qHead=0;
  2414. mQueueHeader.qTail=0;
  2415. }
  2416. #endif // _MACINTOSH