hxnetapi.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:69k
源码类别:

Symbian

开发平台:

Visual C++

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