Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5368 lines
154 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: SocketPort.cpp
  6. * Content: Winsock socket port that manages data flow on a given adapter,
  7. * address and port.
  8. *
  9. *
  10. * History:
  11. * Date By Reason
  12. * ==== == ======
  13. * 01/20/1999 jtk Created
  14. * 05/12/1999 jtk Derived from modem endpoint class
  15. * 03/22/2000 jtk Updated with changes to interface names
  16. ***************************************************************************/
  17. #include "dnwsocki.h"
  18. //**********************************************************************
  19. // Constant definitions
  20. //**********************************************************************
  21. #define SOCKET_RECEIVE_BUFFER_SIZE ( 128 * 1024 )
  22. #ifndef DPNBUILD_NONATHELP
  23. #define NAT_LEASE_TIME 3600000 // ask for 1 hour, in milliseconds
  24. #endif // ! DPNBUILD_NONATHELP
  25. //**********************************************************************
  26. // Macro definitions
  27. //**********************************************************************
  28. //**********************************************************************
  29. // Structure definitions
  30. //**********************************************************************
  31. //**********************************************************************
  32. // Variable definitions
  33. //**********************************************************************
  34. //**********************************************************************
  35. // Function prototypes
  36. //**********************************************************************
  37. //**********************************************************************
  38. // Function definitions
  39. //**********************************************************************
  40. //**********************************************************************
  41. // ------------------------------
  42. // CSocketPort::Initialize - initialize this socket port
  43. //
  44. // Entry: Pointer to CSPData
  45. // Pointer to address to bind to
  46. //
  47. // Exit: Error code
  48. // ------------------------------
  49. #undef DPF_MODNAME
  50. #define DPF_MODNAME "CSocketPort::Initialize"
  51. HRESULT CSocketPort::Initialize( CSocketData *const pSocketData,
  52. CThreadPool *const pThreadPool,
  53. CSocketAddress *const pAddress )
  54. {
  55. HRESULT hr;
  56. HRESULT hTempResult;
  57. DNASSERT( pSocketData != NULL );
  58. DNASSERT( pThreadPool != NULL );
  59. DNASSERT( pAddress != NULL );
  60. DPFX(DPFPREP, 6, "(0x%p) Parameters (0x%p, 0x%p)",
  61. this, pSocketData, pThreadPool, pAddress);
  62. //
  63. // initialize
  64. //
  65. hr = DPN_OK;
  66. pSocketData->AddSocketPortRef();
  67. m_pSocketData = pSocketData;
  68. pThreadPool->AddRef();
  69. m_pThreadPool = pThreadPool;
  70. // Deinitialize will assert that these are set in the fail cases, so we set them up front
  71. DEBUG_ONLY( m_fInitialized = TRUE );
  72. DNASSERT( m_State == SOCKET_PORT_STATE_UNKNOWN );
  73. m_State = SOCKET_PORT_STATE_INITIALIZED;
  74. //
  75. // attempt to initialize the internal critical sections
  76. //
  77. if ( DNInitializeCriticalSection( &m_Lock ) == FALSE )
  78. {
  79. // CReadWriteLock::Deinitialize requires that CReadWriteLock::Initialize was called.
  80. m_EndpointDataRWLock.Initialize();
  81. hr = DPNERR_OUTOFMEMORY;
  82. DPFX(DPFPREP, 0, "Failed to initialize critical section for socket port!" );
  83. goto Failure;
  84. }
  85. DebugSetCriticalSectionRecursionCount( &m_Lock, 0 );
  86. DebugSetCriticalSectionGroup( &m_Lock, &g_blDPNWSockCritSecsHeld ); // separate dpnwsock CSes from the rest of DPlay's CSes
  87. if ( m_EndpointDataRWLock.Initialize() == FALSE )
  88. {
  89. hr = DPNERR_OUTOFMEMORY;
  90. DPFX(DPFPREP, 0, "Failed to initialize EndpointDataRWLock read/write lock!" );
  91. goto Failure;
  92. }
  93. //
  94. // allocate addresses:
  95. // local address this socket is binding to
  96. // address of received messages
  97. //
  98. DNASSERT( m_pNetworkSocketAddress == NULL );
  99. m_pNetworkSocketAddress = pAddress;
  100. #ifndef DPNBUILD_ONLYONEPROCESSOR
  101. //
  102. // Initially assume it can be used on any CPU.
  103. //
  104. m_dwCPU = -1;
  105. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  106. Exit:
  107. if ( hr != DPN_OK )
  108. {
  109. DPFX(DPFPREP, 0, "Problem in CSocketPort::Initialize()" );
  110. DisplayDNError( 0, hr );
  111. }
  112. DPFX(DPFPREP, 6, "(0x%p) Leave [0x%lx]", this, hr);
  113. return hr;
  114. Failure:
  115. DEBUG_ONLY( m_fInitialized = FALSE );
  116. hTempResult = Deinitialize();
  117. if ( hTempResult != DPN_OK )
  118. {
  119. DPFX(DPFPREP, 0, "Problem deinitializing CSocketPort on failed Initialize!" );
  120. DisplayDNError( 0, hTempResult );
  121. }
  122. m_pNetworkSocketAddress = NULL;
  123. goto Exit;
  124. }
  125. //**********************************************************************
  126. //**********************************************************************
  127. // ------------------------------
  128. // CSocketPort::Deinitialize - deinitialize this socket port
  129. //
  130. // Entry: Nothing
  131. //
  132. // Exit: Error code
  133. // ------------------------------
  134. #undef DPF_MODNAME
  135. #define DPF_MODNAME "CSocketPort::Deinitialize"
  136. HRESULT CSocketPort::Deinitialize( void )
  137. {
  138. HRESULT hr;
  139. DPFX(DPFPREP, 6, "(0x%p) Enter", this);
  140. //
  141. // initialize
  142. //
  143. hr = DPN_OK;
  144. Lock();
  145. DNASSERT( ( m_State == SOCKET_PORT_STATE_INITIALIZED ) ||
  146. ( m_State == SOCKET_PORT_STATE_UNBOUND ) );
  147. DEBUG_ONLY( m_fInitialized = FALSE );
  148. DNASSERT( m_iEndpointRefCount == 0 );
  149. DNASSERT( m_iRefCount == 0 );
  150. //
  151. // return base network socket addresses
  152. //
  153. if ( m_pNetworkSocketAddress != NULL )
  154. {
  155. g_SocketAddressPool.Release( m_pNetworkSocketAddress );
  156. m_pNetworkSocketAddress = NULL;
  157. }
  158. #ifdef DBG
  159. #ifndef DPNBUILD_NONATHELP
  160. DWORD dwTemp;
  161. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  162. {
  163. DNASSERT( m_ahNATHelpPorts[dwTemp] == NULL );
  164. }
  165. #endif // DPNBUILD_NONATHELP
  166. #endif // DBG
  167. Unlock();
  168. // Calling this is only safe if CReadWriteLock::Initialize was called, regardless of
  169. // whether or not it succeeded.
  170. m_EndpointDataRWLock.Deinitialize();
  171. DNDeleteCriticalSection( &m_Lock );
  172. if (m_pThreadPool != NULL)
  173. {
  174. m_pThreadPool->DecRef();
  175. m_pThreadPool = NULL;
  176. }
  177. if (m_pSocketData != NULL)
  178. {
  179. m_pSocketData->DecSocketPortRef();
  180. m_pSocketData = NULL;
  181. }
  182. DPFX(DPFPREP, 6, "(0x%p) Leave [0x%lx]", this, hr);
  183. return hr;
  184. }
  185. //**********************************************************************
  186. //**********************************************************************
  187. // ------------------------------
  188. // CSocketPort::PoolAllocFunction - initializes a newly allocated socket port
  189. //
  190. // Entry: Pointer to item
  191. // Context
  192. //
  193. // Exit: TRUE if successful, FALSE otherwise
  194. // ------------------------------
  195. #undef DPF_MODNAME
  196. #define DPF_MODNAME "CSocketPort::PoolAllocFunction"
  197. BOOL CSocketPort::PoolAllocFunction( void* pvItem, void* pvContext )
  198. {
  199. CSocketPort* pSocketPort = (CSocketPort*) pvItem;
  200. BOOL fConnectEndpointHashTableInitted = FALSE;
  201. BOOL fEnumEndpointHashTableInitted = FALSE;
  202. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  203. XDP8CREATE_PARAMS * pDP8CreateParams = (XDP8CREATE_PARAMS*) pvContext;
  204. #endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
  205. pSocketPort->m_pSocketData = NULL;
  206. pSocketPort->m_pThreadPool = NULL;
  207. pSocketPort->m_iRefCount = 0;
  208. pSocketPort->m_iEndpointRefCount = 0;
  209. pSocketPort->m_State = SOCKET_PORT_STATE_UNKNOWN;
  210. pSocketPort->m_pNetworkSocketAddress = NULL;
  211. #ifndef DPNBUILD_ONLYONEADAPTER
  212. pSocketPort->m_pAdapterEntry = NULL;
  213. #endif // ! DPNBUILD_ONLYONEADAPTER
  214. pSocketPort->m_Socket = INVALID_SOCKET;
  215. pSocketPort->m_pListenEndpoint = NULL;
  216. pSocketPort->m_iEnumKey = DNGetFastRandomNumber(); // pick an arbitrary starting point for the key value
  217. pSocketPort->m_dwSocketPortID = 0;
  218. #ifndef DPNBUILD_NOWINSOCK2
  219. pSocketPort->m_fUsingProxyWinSockLSP = FALSE;
  220. #endif // !DPNBUILD_NOWINSOCK2
  221. #if ((! defined(DPNBUILD_ONLYONETHREAD)) || (defined(DBG)))
  222. pSocketPort->m_iThreadsInReceive = 0;
  223. #endif // ! DPNBUILD_ONLYONETHREAD or DBG
  224. pSocketPort->m_Sig[0] = 'S';
  225. pSocketPort->m_Sig[1] = 'O';
  226. pSocketPort->m_Sig[2] = 'K';
  227. pSocketPort->m_Sig[3] = 'P';
  228. DEBUG_ONLY( pSocketPort->m_fInitialized = FALSE );
  229. pSocketPort->m_ActiveListLinkage.Initialize();
  230. pSocketPort->m_blConnectEndpointList.Initialize();
  231. #ifndef DPNBUILD_NONATHELP
  232. ZeroMemory( pSocketPort->m_ahNATHelpPorts, sizeof(pSocketPort->m_ahNATHelpPorts) );
  233. #endif // DPNBUILD_NONATHELP
  234. #ifndef DPNBUILD_NOMULTICAST
  235. pSocketPort->m_bMulticastTTL = 0;
  236. #endif // ! DPNBUILD_NOMULTICAST
  237. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  238. //
  239. // Initialize the connect endpoint hash with the desired number of entries,
  240. // rounded up to a power of 2. Keep in mind we don't care about the local
  241. // player (-1).
  242. //
  243. #pragma BUGBUG(vanceo, "Don't use loop")
  244. DWORD dwTemp;
  245. BYTE bPowerOfTwo;
  246. dwTemp = pDP8CreateParams->dwMaxNumPlayers - 1;
  247. bPowerOfTwo = 0;
  248. while (dwTemp > 0)
  249. {
  250. dwTemp = dwTemp >> 1;
  251. bPowerOfTwo++;
  252. }
  253. if ((pDP8CreateParams->dwMaxNumPlayers - 1) != (1 << (DWORD) bPowerOfTwo))
  254. {
  255. bPowerOfTwo++;
  256. }
  257. if (! (pSocketPort->m_ConnectEndpointHash.Initialize(bPowerOfTwo,
  258. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  259. //
  260. // Initialize the connect endpoint hash with 16 entries and grow by a factor of 8.
  261. //
  262. if (! (pSocketPort->m_ConnectEndpointHash.Initialize(4,
  263. 3,
  264. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  265. CSocketAddress::CompareFunction,
  266. CSocketAddress::HashFunction)))
  267. {
  268. DPFX(DPFPREP, 0, "Could not initialize the connect endpoint list!");
  269. goto Failure;
  270. }
  271. fConnectEndpointHashTableInitted = TRUE;
  272. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  273. //
  274. // Initialize the connect endpoint hash with the desired number of entries.
  275. //
  276. if (! (pSocketPort->m_EnumEndpointHash.Initialize(1,
  277. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  278. //
  279. // Initialize the enum endpoint hash with 2 entries and grow by a factor of 2.
  280. //
  281. if (! (pSocketPort->m_EnumEndpointHash.Initialize(1,
  282. 1,
  283. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  284. CEndpointEnumKey::CompareFunction,
  285. CEndpointEnumKey::HashFunction)))
  286. {
  287. DPFX(DPFPREP, 0, "Could not initialize the enum endpoint list!");
  288. goto Failure;
  289. }
  290. fEnumEndpointHashTableInitted = TRUE;
  291. return TRUE;
  292. Failure:
  293. if (fEnumEndpointHashTableInitted)
  294. {
  295. pSocketPort->m_EnumEndpointHash.Deinitialize();
  296. fEnumEndpointHashTableInitted = FALSE;
  297. }
  298. if (fConnectEndpointHashTableInitted)
  299. {
  300. pSocketPort->m_ConnectEndpointHash.Deinitialize();
  301. fConnectEndpointHashTableInitted = FALSE;
  302. }
  303. return FALSE;
  304. }
  305. //**********************************************************************
  306. //**********************************************************************
  307. // ------------------------------
  308. // CSocketPort::PoolInitFunction - initializes a socket port being retrieved from the pool
  309. //
  310. // Entry: Pointer to item
  311. // Context
  312. //
  313. // Exit: None
  314. // ------------------------------
  315. #undef DPF_MODNAME
  316. #define DPF_MODNAME "CSocketPort::PoolInitFunction"
  317. void CSocketPort::PoolInitFunction( void* pvItem, void* pvContext )
  318. {
  319. CSocketPort* pSocketPort = (CSocketPort*) pvItem;
  320. #ifdef DBG
  321. DNASSERT( pSocketPort->m_fInitialized == FALSE );
  322. DNASSERT( pSocketPort->m_iRefCount == 0 );
  323. DNASSERT( pSocketPort->m_iEndpointRefCount == 0 );
  324. #endif // DBG
  325. pSocketPort->m_iRefCount = 1;
  326. pSocketPort->m_iEndpointRefCount = 1;
  327. }
  328. //**********************************************************************
  329. #ifdef DBG
  330. //**********************************************************************
  331. // ------------------------------
  332. // CSocketPort::PoolDeinitFunction - returns a socket port to the pool
  333. //
  334. // Entry: Pointer to item
  335. //
  336. // Exit: None
  337. // ------------------------------
  338. #undef DPF_MODNAME
  339. #define DPF_MODNAME "CSocketPort::PoolDeinitFunction"
  340. void CSocketPort::PoolDeinitFunction( void* pvItem )
  341. {
  342. const CSocketPort* pSocketPort = (CSocketPort*) pvItem;
  343. DNASSERT( pSocketPort->m_fInitialized == FALSE );
  344. DNASSERT( pSocketPort->m_iRefCount == 0 );
  345. DNASSERT( pSocketPort->m_iEndpointRefCount == 0 );
  346. }
  347. //**********************************************************************
  348. #endif // DBG
  349. //**********************************************************************
  350. // ------------------------------
  351. // CSocketPort::PoolDeallocFunction - frees a socket port
  352. //
  353. // Entry: Pointer to item
  354. //
  355. // Exit: None
  356. // ------------------------------
  357. #undef DPF_MODNAME
  358. #define DPF_MODNAME "CSocketPort::PoolDeallocFunction"
  359. void CSocketPort::PoolDeallocFunction( void* pvItem )
  360. {
  361. CSocketPort* pSocketPort = (CSocketPort*) pvItem;
  362. #ifdef DBG
  363. //
  364. // m_pThis needs to be around for the life of the endpoint
  365. // it should be part of the constructor, but can't be since we're using
  366. // a pool manager
  367. //
  368. DNASSERT( pSocketPort->m_fInitialized == FALSE );
  369. DNASSERT( pSocketPort->m_iRefCount == 0 );
  370. DNASSERT( pSocketPort->m_iEndpointRefCount == 0 );
  371. DNASSERT( pSocketPort->m_State == SOCKET_PORT_STATE_UNKNOWN );
  372. DNASSERT( pSocketPort->GetSocket() == INVALID_SOCKET );
  373. DNASSERT( pSocketPort->m_pNetworkSocketAddress == NULL );
  374. #ifndef DPNBUILD_ONLYONEADAPTER
  375. DNASSERT( pSocketPort->m_pAdapterEntry == NULL );
  376. #endif // ! DPNBUILD_ONLYONEADAPTER
  377. #ifndef DPNBUILD_NONATHELP
  378. DWORD dwTemp;
  379. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  380. {
  381. DNASSERT( pSocketPort->m_ahNATHelpPorts[dwTemp] == NULL );
  382. }
  383. #endif // DPNBUILD_NONATHELP
  384. DNASSERT( pSocketPort->m_ActiveListLinkage.IsEmpty() != FALSE );
  385. DNASSERT( pSocketPort->m_blConnectEndpointList.IsEmpty() != FALSE );
  386. DNASSERT( pSocketPort->m_pListenEndpoint == NULL );
  387. DNASSERT( pSocketPort->m_pThreadPool == NULL );
  388. DNASSERT( pSocketPort->m_pSocketData == NULL );
  389. DNASSERT( pSocketPort->m_iThreadsInReceive == 0);
  390. #endif // DBG
  391. pSocketPort->m_EnumEndpointHash.Deinitialize();
  392. pSocketPort->m_ConnectEndpointHash.Deinitialize();
  393. }
  394. //**********************************************************************
  395. //**********************************************************************
  396. // ------------------------------
  397. // CSocketPort::EndpointAddRef - increment endpoint reference count, unless socketport is unbinding
  398. //
  399. // Entry: Nothing
  400. //
  401. // Exit: TRUE if endpoint ref added, FALSE if socketport is unbinding.
  402. // ------------------------------
  403. #undef DPF_MODNAME
  404. #define DPF_MODNAME "CSocketPort::EndpointAddRef"
  405. BOOL CSocketPort::EndpointAddRef( void )
  406. {
  407. BOOL fResult;
  408. Lock();
  409. //
  410. // add a global reference and then add an endpoint reference, unless it's 0
  411. //
  412. DNASSERT( m_iEndpointRefCount != -1 );
  413. if (m_iEndpointRefCount > 0)
  414. {
  415. m_iEndpointRefCount++;
  416. AddRef();
  417. DPFX(DPFPREP, 9, "(0x%p) Endpoint refcount is now %i.",
  418. this, m_iEndpointRefCount );
  419. fResult = TRUE;
  420. }
  421. else
  422. {
  423. DPFX(DPFPREP, 9, "(0x%p) Endpoint refcount is 0, not adding endpoint ref.",
  424. this );
  425. fResult = FALSE;
  426. }
  427. Unlock();
  428. return fResult;
  429. }
  430. //**********************************************************************
  431. //**********************************************************************
  432. // ------------------------------
  433. // CSocketPort::EndpointDecRef - decrement endpoint reference count
  434. //
  435. // Entry: Nothing
  436. //
  437. // Exit: Endpoint reference count
  438. // ------------------------------
  439. #undef DPF_MODNAME
  440. #define DPF_MODNAME "CSocketPort::EndpointDecRef"
  441. DWORD CSocketPort::EndpointDecRef( void )
  442. {
  443. DWORD dwReturn;
  444. Lock();
  445. DNASSERT( m_iEndpointRefCount != 0 );
  446. m_iEndpointRefCount--;
  447. dwReturn = m_iEndpointRefCount;
  448. if ( m_iEndpointRefCount == 0 )
  449. {
  450. HRESULT hr;
  451. SOCKET_PORT_STATE PreviousState;
  452. #ifndef DPNBUILD_ONLYONETHREAD
  453. DWORD dwInterval;
  454. #endif // ! DPNBUILD_ONLYONETHREAD
  455. DPFX(DPFPREP, 7, "(0x%p) Endpoint refcount hit 0, beginning to unbind from network.", this );
  456. //
  457. // No more endpoints are referencing this item, unbind this socket port
  458. // from the network and then remove it from the active socket port list.
  459. // If we're on Winsock1, tell the other thread that this socket needs to
  460. // be removed so we can get rid of our outstanding I/O reference.
  461. //
  462. #ifdef WINCE
  463. m_pThreadPool->RemoveSocketPort( this );
  464. #endif // WINCE
  465. #ifdef WIN95
  466. if ( ( LOWORD( GetWinsockVersion() ) == 1 )
  467. #ifndef DPNBUILD_NOIPX
  468. || ( m_pNetworkSocketAddress->GetFamily() == AF_IPX )
  469. #endif // DPNBUILD_NOIPX
  470. )
  471. {
  472. m_pThreadPool->RemoveSocketPort( this );
  473. }
  474. #endif // WIN95
  475. PreviousState = m_State;
  476. // Don't allow any more receives through
  477. m_State = SOCKET_PORT_STATE_UNBOUND;
  478. Unlock();
  479. #ifdef DPNBUILD_ONLYONETHREAD
  480. #ifdef DBG
  481. DNASSERT(m_iThreadsInReceive == 0);
  482. #endif // DBG
  483. #else // ! DPNBUILD_ONLYONETHREAD
  484. // Wait for any receives that were already in to get out
  485. dwInterval = 10;
  486. while (m_iThreadsInReceive != 0)
  487. {
  488. DPFX(DPFPREP, 9, "There are %i threads still receiving for socketport 0x%p...", m_iThreadsInReceive, this);
  489. IDirectPlay8ThreadPoolWork_SleepWhileWorking(m_pThreadPool->GetDPThreadPoolWork(),
  490. dwInterval,
  491. 0);
  492. dwInterval += 5; // next time wait a bit longer
  493. DNASSERT(dwInterval < 600);
  494. }
  495. #endif // ! DPNBUILD_ONLYONETHREAD
  496. //
  497. // If we didn't failing before completing the bind, unbind.
  498. //
  499. if ( PreviousState == SOCKET_PORT_STATE_BOUND )
  500. {
  501. hr = UnbindFromNetwork();
  502. if ( hr != DPN_OK )
  503. {
  504. DPFX(DPFPREP, 0, "Problem unbinding from network when final endpoint has disconnected!" );
  505. DisplayDNError( 0, hr );
  506. }
  507. }
  508. DNASSERT( m_pNetworkSocketAddress != NULL );
  509. }
  510. else
  511. {
  512. Unlock();
  513. DPFX(DPFPREP, 9, "(0x%p) Endpoint refcount is %i, not unbinding from network.",
  514. this, m_iEndpointRefCount );
  515. }
  516. //
  517. // Decrement global reference count. This normally doesn't result in this
  518. // socketport being returned to the pool because there is always at least
  519. // one more regular reference than an endpoint reference. However, there
  520. // are race conditions where this could be our caller's last reference.
  521. //
  522. DecRef();
  523. return dwReturn;
  524. }
  525. //**********************************************************************
  526. //**********************************************************************
  527. // ------------------------------
  528. // CSocketPort::BindEndpoint - add an endpoint to this SP's list
  529. //
  530. // Entry: Pointer to endpoint
  531. // Gateway bind type
  532. //
  533. // Exit: Error code
  534. // ------------------------------
  535. #undef DPF_MODNAME
  536. #define DPF_MODNAME "CSocketPort::BindEndpoint"
  537. HRESULT CSocketPort::BindEndpoint( CEndpoint *const pEndpoint, GATEWAY_BIND_TYPE GatewayBindType )
  538. {
  539. HRESULT hr;
  540. CEndpoint * pExistingEndpoint;
  541. #ifdef DBG
  542. const CSocketAddress * pSocketAddress;
  543. const SOCKADDR * pSockAddr;
  544. #endif // DBG
  545. DPFX(DPFPREP, 6, "(0x%p) Parameters (0x%p, %i)",
  546. this, pEndpoint, GatewayBindType);
  547. //
  548. // initialize
  549. //
  550. hr = DPN_OK;
  551. DNASSERT( m_iRefCount != 0 );
  552. DNASSERT( m_iEndpointRefCount != 0 );
  553. //
  554. // Munge/convert the loopback address to the local device address.
  555. //
  556. // Note that doing this causes all other multiplexed operations to use this first
  557. // adapter because we indicate the modified address info, not the original
  558. // loopback address.
  559. //
  560. pEndpoint->ChangeLoopbackAlias( GetNetworkAddress() );
  561. WriteLockEndpointData();
  562. switch ( pEndpoint->GetType() )
  563. {
  564. //
  565. // Treat 'connect', 'connect on listen', and multicast receive endpoints
  566. // as the same type.
  567. //
  568. case ENDPOINT_TYPE_CONNECT:
  569. case ENDPOINT_TYPE_CONNECT_ON_LISTEN:
  570. #ifndef DPNBUILD_NOMULTICAST
  571. case ENDPOINT_TYPE_MULTICAST_SEND:
  572. case ENDPOINT_TYPE_MULTICAST_RECEIVE:
  573. #endif // ! DPNBUILD_NOMULTICAST
  574. {
  575. #ifdef DBG
  576. //
  577. // Make sure it's a valid address. Be aware that we may be trying
  578. // to bind an IPv4 address to an IPv6 socket, or vice versa. We
  579. // will detect and handle this later (CEndpoint::CompleteConnect).
  580. //
  581. pSocketAddress = pEndpoint->GetRemoteAddressPointer();
  582. DNASSERT(pSocketAddress != NULL);
  583. pSockAddr = pSocketAddress->GetAddress();
  584. DNASSERT(pSockAddr != NULL);
  585. if (pSocketAddress->GetFamily() == AF_INET)
  586. {
  587. DNASSERT( ((SOCKADDR_IN*) pSockAddr)->sin_addr.S_un.S_addr != 0 );
  588. DNASSERT( ((SOCKADDR_IN*) pSockAddr)->sin_addr.S_un.S_addr != INADDR_BROADCAST );
  589. #ifndef DPNBUILD_NOMULTICAST
  590. if ( pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_SEND )
  591. {
  592. //
  593. // Make sure it's a multicast address.
  594. //
  595. DNASSERT(IS_CLASSD_IPV4_ADDRESS((SOCKADDR_IN*) pSockAddr)->sin_addr.S_un.S_addr));
  596. }
  597. #endif // ! DPNBUILD_NOMULTICAST
  598. }
  599. DNASSERT( pSocketAddress->GetPort() != 0 );
  600. #endif // DBG
  601. #ifndef DPNBUILD_NOMULTICAST
  602. //
  603. // Multicast send endpoints need to know their multicast TTL settings.
  604. // We can only set the multicast TTL once, so if it's been set to
  605. // something different already, we have to fail.
  606. //
  607. if ( pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_SEND )
  608. {
  609. GUID guidScope;
  610. int iMulticastTTL;
  611. int iSocketOption;
  612. pEndpoint->GetScopeGuid( &guidScope );
  613. if ( memcmp( &guidScope, &GUID_DP8MULTICASTSCOPE_PRIVATE, sizeof(guidScope) ) == 0 )
  614. {
  615. iMulticastTTL = MULTICAST_TTL_PRIVATE;
  616. }
  617. else if ( memcmp( &guidScope, &GUID_DP8MULTICASTSCOPE_LOCAL, sizeof(guidScope) ) == 0 )
  618. {
  619. iMulticastTTL = MULTICAST_TTL_LOCAL;
  620. }
  621. else if ( memcmp( &guidScope, &GUID_DP8MULTICASTSCOPE_GLOBAL, sizeof(guidScope) ) == 0 )
  622. {
  623. iMulticastTTL = MULTICAST_TTL_GLOBAL;
  624. }
  625. else
  626. {
  627. //
  628. // Assume it's a valid MADCAP scope. Even on non-NT platforms
  629. // where we don't know about MADCAP, we can still parse out the
  630. // TTL value.
  631. //
  632. iMulticastTTL = CSocketAddress::GetScopeGuidTTL( &guidScope );
  633. }
  634. if ( ( GetMulticastTTL() != 0 ) && ( GetMulticastTTL() != (BYTE) iMulticastTTL ) )
  635. {
  636. hr = DPNERR_ALREADYINITIALIZED;
  637. DPFX(DPFPREP, 0, "Attempted to reuse port with a different multicast scope!" );
  638. goto Failure;
  639. }
  640. //
  641. // Since the IP multicast constants are different for Winsock1 vs. Winsock2,
  642. // make sure we use the proper constant.
  643. //
  644. #ifdef DPNBUILD_ONLYWINSOCK2
  645. iSocketOption = 10;
  646. #else // ! DPNBUILD_ONLYWINSOCK2
  647. #ifndef DPNBUILD_NOWINSOCK2
  648. switch (GetWinsockVersion())
  649. {
  650. //
  651. // Winsock1, use the IP_MULTICAST_TTL value for Winsock1.
  652. // See WINSOCK.H
  653. //
  654. case 1:
  655. {
  656. #endif // ! DPNBUILD_NOWINSOCK2
  657. iSocketOption = 3;
  658. #ifndef DPNBUILD_NOWINSOCK2
  659. break;
  660. }
  661. //
  662. // Winsock2, or greater, use the IP_MULTICAST_TTL value for Winsock2.
  663. // See WS2TCPIP.H
  664. //
  665. case 2:
  666. default:
  667. {
  668. DNASSERT(GetWinsockVersion() == 2);
  669. iSocketOption = 10;
  670. break;
  671. }
  672. }
  673. #endif // ! DPNBUILD_NOWINSOCK2
  674. #endif // ! DPNBUILD_ONLYWINSOCK2
  675. DPFX(DPFPREP, 3, "Socketport 0x%p setting IP_MULTICAST_TTL option (%i) to %i.",
  676. this, iSocketOption, iMulticastTTL);
  677. DNASSERT((iMulticastTTL > 0) && (iMulticastTTL < 255));
  678. if (setsockopt(GetSocket(),
  679. IPPROTO_IP,
  680. iSocketOption,
  681. (char*) (&iMulticastTTL),
  682. sizeof(iMulticastTTL)) == SOCKET_ERROR)
  683. {
  684. #ifdef DBG
  685. DWORD dwError;
  686. dwError = WSAGetLastError();
  687. DPFX(DPFPREP, 0, "Failed to set multicast TTL to %i (err = %u)!",
  688. iMulticastTTL, dwError);
  689. DisplayWinsockError(0, dwError);
  690. #endif // DBG
  691. hr = DPNERR_GENERIC;
  692. goto Failure;
  693. }
  694. //
  695. // Save the TTL setting. It's now carved in stone so no one else
  696. // can change it for this socket ever again.
  697. //
  698. m_bMulticastTTL = (BYTE) iMulticastTTL;
  699. }
  700. #endif // ! DPNBUILD_NOMULTICAST
  701. //
  702. // We don't care how many connections are made through this socket port,
  703. // just make sure we're not connecting to the same place more than once.
  704. //
  705. if ( m_ConnectEndpointHash.Find( (PVOID)pEndpoint->GetRemoteAddressPointer(), (PVOID*)&pExistingEndpoint ) != FALSE )
  706. {
  707. hr = DPNERR_ALREADYINITIALIZED;
  708. DPFX(DPFPREP, 0, "Attempted to connect twice to the same destination address!" );
  709. DumpSocketAddress( 0, pEndpoint->GetRemoteAddressPointer()->GetAddress(), pEndpoint->GetRemoteAddressPointer()->GetFamily() );
  710. goto Failure;
  711. }
  712. DNASSERT( hr == DPN_OK );
  713. if ( m_ConnectEndpointHash.Insert( (PVOID)pEndpoint->GetRemoteAddressPointer(), pEndpoint ) == FALSE )
  714. {
  715. hr = DPNERR_OUTOFMEMORY;
  716. DPFX(DPFPREP, 0, "Problem adding endpoint to connect socket port hash!" );
  717. goto Failure;
  718. }
  719. #ifdef DPNBUILD_NOMULTICAST
  720. if (pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT)
  721. #else // ! DPNBUILD_NOMULTICAST
  722. if ((pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT) ||
  723. (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_SEND) ||
  724. (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_RECEIVE))
  725. #endif // ! DPNBUILD_NOMULTICAST
  726. {
  727. pEndpoint->AddToSocketPortList(&m_blConnectEndpointList);
  728. //
  729. // CONNECT, MULTICAST_SEND, and MULTICAST_RECEIVE, endpoints must be
  730. // on a DPlay selected or fixed port. They can't be shared but the
  731. // underlying socketport should be mapped on the gateway (or in the
  732. // case of MULTICAST_RECEIVE, it shouldn't hurt if it is).
  733. //
  734. DNASSERT((GatewayBindType == GATEWAY_BIND_TYPE_DEFAULT) || (GatewayBindType == GATEWAY_BIND_TYPE_SPECIFIC));
  735. }
  736. else
  737. {
  738. //
  739. // CONNECT_ON_LISTEN endpoints should always be bound as NONE since
  740. // they should not need port mappings on the gateway.
  741. //
  742. DNASSERT(GatewayBindType == GATEWAY_BIND_TYPE_NONE);
  743. }
  744. pEndpoint->SetSocketPort( this );
  745. pEndpoint->AddRef();
  746. break;
  747. }
  748. case ENDPOINT_TYPE_LISTEN:
  749. #ifndef DPNBUILD_NOMULTICAST
  750. case ENDPOINT_TYPE_MULTICAST_LISTEN:
  751. #endif // ! DPNBUILD_NOMULTICAST
  752. {
  753. //
  754. // We only allow one listen or multicast listen endpoint on a
  755. // socketport.
  756. //
  757. if ( m_pListenEndpoint != NULL )
  758. {
  759. hr = DPNERR_ALREADYINITIALIZED;
  760. DPFX(DPFPREP, 0, "Attempted to listen/receive multicasts more than once on a given SocketPort!" );
  761. goto Failure;
  762. }
  763. #ifndef DPNBUILD_NOMULTICAST
  764. //
  765. // If this is a multicast listen, subscribe to multicast group
  766. //
  767. if ( pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_LISTEN )
  768. {
  769. hr = pEndpoint->EnableMulticastReceive( this );
  770. if ( hr != DPN_OK )
  771. {
  772. DPFX(DPFPREP, 0, "Couldn't enable multicast receive!");
  773. goto Failure;
  774. }
  775. }
  776. #endif // ! DPNBUILD_NOMULTICAST
  777. //
  778. // LISTENs can be on a DPlay selected or fixed port, and the fixed port
  779. // may be shared.
  780. //
  781. DNASSERT((GatewayBindType == GATEWAY_BIND_TYPE_DEFAULT) || (GatewayBindType == GATEWAY_BIND_TYPE_SPECIFIC) || (GatewayBindType == GATEWAY_BIND_TYPE_SPECIFIC_SHARED));
  782. m_pListenEndpoint = pEndpoint;
  783. pEndpoint->SetSocketPort( this );
  784. pEndpoint->AddRef();
  785. break;
  786. }
  787. case ENDPOINT_TYPE_ENUM:
  788. {
  789. #ifdef DBG
  790. //
  791. // Make sure it's a valid address. Be aware that we may be trying
  792. // to bind an IPv4 address to an IPv6 socket, or vice versa. We
  793. // will detect and handle this later (CEndpoint::CompleteEnumQuery).
  794. //
  795. pSocketAddress = pEndpoint->GetRemoteAddressPointer();
  796. DNASSERT(pSocketAddress != NULL);
  797. pSockAddr = pSocketAddress->GetAddress();
  798. DNASSERT(pSockAddr != NULL);
  799. if (pSocketAddress->GetFamily() == AF_INET)
  800. {
  801. DNASSERT( ((SOCKADDR_IN*) pSockAddr)->sin_addr.S_un.S_addr != 0 );
  802. }
  803. DNASSERT( pSocketAddress->GetPort() != 0 );
  804. #endif // DBG
  805. //
  806. // We don't allow duplicate enum endpoints.
  807. //
  808. pEndpoint->SetEnumKey( GetNewEnumKey() );
  809. if ( m_EnumEndpointHash.Find( (PVOID)pEndpoint->GetEnumKey(), (PVOID*)&pExistingEndpoint ) != FALSE )
  810. {
  811. hr = DPNERR_ALREADYINITIALIZED;
  812. DPFX(DPFPREP, 0, "Attempted to enum twice to the same endpoint!" );
  813. goto Failure;
  814. }
  815. DNASSERT( hr == DPN_OK );
  816. if ( m_EnumEndpointHash.Insert( (PVOID)pEndpoint->GetEnumKey(), pEndpoint ) == FALSE )
  817. {
  818. hr = DPNERR_OUTOFMEMORY;
  819. DPFX(DPFPREP, 0, "Problem adding endpoint to enum socket port hash!" );
  820. goto Failure;
  821. }
  822. //
  823. // ENUMs must be on a DPlay selected or fixed port. They can't be
  824. // shared, but the underlying socketport should be mapped on the gateway.
  825. //
  826. DNASSERT((GatewayBindType == GATEWAY_BIND_TYPE_DEFAULT) || (GatewayBindType == GATEWAY_BIND_TYPE_SPECIFIC));
  827. pEndpoint->SetSocketPort( this );
  828. pEndpoint->AddRef();
  829. break;
  830. }
  831. //
  832. // unknown endpoint type
  833. //
  834. default:
  835. {
  836. DNASSERT( FALSE );
  837. hr = DPNERR_GENERIC;
  838. goto Failure;
  839. break;
  840. }
  841. }
  842. pEndpoint->SetGatewayBindType(GatewayBindType);
  843. Exit:
  844. UnlockEndpointData();
  845. DPFX(DPFPREP, 6, "(0x%p) Returning [0x%lx]", this, hr);
  846. return hr;
  847. Failure:
  848. goto Exit;
  849. }
  850. //**********************************************************************
  851. //**********************************************************************
  852. // ------------------------------
  853. // CSocketPort::UnbindEndpoint - remove an endpoint from the SP's list
  854. //
  855. // Entry: Pointer to endpoint
  856. //
  857. // Exit: Nothing
  858. // ------------------------------
  859. #undef DPF_MODNAME
  860. #define DPF_MODNAME "CSocketPort::UnbindEndpoint"
  861. void CSocketPort::UnbindEndpoint( CEndpoint *const pEndpoint )
  862. {
  863. #ifndef DPNBUILD_ONLYONEADAPTER
  864. BOOL fRemoveFromMultiplex = FALSE;
  865. #endif // ! DPNBUILD_ONLYONEADAPTER
  866. #ifdef DBG
  867. CEndpoint * pFindTemp;
  868. #endif // DBG
  869. DPFX(DPFPREP, 6, "(0x%p) Parameters (0x%p)", this, pEndpoint);
  870. WriteLockEndpointData();
  871. pEndpoint->SetGatewayBindType(GATEWAY_BIND_TYPE_UNKNOWN);
  872. //
  873. // adjust any special pointers before removing endpoint
  874. //
  875. switch ( pEndpoint->GetType() )
  876. {
  877. //
  878. // Connect, connect-on-listen, multicast send and multicast receive endpoints are
  879. // treated the same. Remove endpoint from connect list.
  880. //
  881. case ENDPOINT_TYPE_CONNECT:
  882. case ENDPOINT_TYPE_CONNECT_ON_LISTEN:
  883. #ifndef DPNBUILD_NOMULTICAST
  884. case ENDPOINT_TYPE_MULTICAST_SEND:
  885. case ENDPOINT_TYPE_MULTICAST_RECEIVE:
  886. #endif // ! DPNBUILD_NOMULTICAST
  887. {
  888. #ifdef DBG
  889. DNASSERT( m_ConnectEndpointHash.Find( (PVOID)pEndpoint->GetRemoteAddressPointer(), (PVOID*)&pFindTemp ) );
  890. DNASSERT( pFindTemp == pEndpoint );
  891. #endif // DBG
  892. m_ConnectEndpointHash.Remove( (PVOID)pEndpoint->GetRemoteAddressPointer() );
  893. #ifdef DPNBUILD_NOMULTICAST
  894. if (pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT)
  895. #else // ! DPNBUILD_NOMULTICAST
  896. if ((pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT) ||
  897. (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_SEND) ||
  898. (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_RECEIVE))
  899. #endif // ! DPNBUILD_NOMULTICAST
  900. {
  901. pEndpoint->RemoveFromSocketPortList();
  902. }
  903. pEndpoint->SetSocketPort( NULL );
  904. #ifdef DPNBUILD_ONLYONEADAPTER
  905. pEndpoint->DecRef();
  906. #else // ! DPNBUILD_ONLYONEADAPTER
  907. fRemoveFromMultiplex = TRUE;
  908. #endif // ! DPNBUILD_ONLYONEADAPTER
  909. break;
  910. }
  911. //
  912. // Make sure this is really the active listen/multicast listen and
  913. // then remove it.
  914. //
  915. #ifndef DPNBUILD_NOMULTICAST
  916. case ENDPOINT_TYPE_MULTICAST_LISTEN:
  917. #endif // ! DPNBUILD_NOMULTICAST
  918. case ENDPOINT_TYPE_LISTEN:
  919. {
  920. DNASSERT( m_pListenEndpoint == pEndpoint );
  921. m_pListenEndpoint = NULL;
  922. #ifndef DPNBUILD_NOMULTICAST
  923. //
  924. // If this is a multicast listen, subscribe to multicast group
  925. //
  926. if (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_LISTEN)
  927. {
  928. HRESULT hr;
  929. hr = pEndpoint->DisableMulticastReceive();
  930. if (hr != DPN_OK)
  931. {
  932. DPFX(DPFPREP, 0, "Couldn't disable multicast receive (err = 0x%lx)!", hr);
  933. DisplayDNError(0, hr);
  934. }
  935. }
  936. #endif // ! DPNBUILD_NOMULTICAST
  937. pEndpoint->SetSocketPort( NULL );
  938. pEndpoint->DecRef();
  939. break;
  940. }
  941. //
  942. // Remove endpoint from enum list.
  943. //
  944. case ENDPOINT_TYPE_ENUM:
  945. {
  946. #ifdef DBG
  947. DNASSERT( m_EnumEndpointHash.Find( (PVOID)pEndpoint->GetEnumKey(), (PVOID*)&pFindTemp ) );
  948. DNASSERT( pFindTemp == pEndpoint );
  949. #endif // DBG
  950. m_EnumEndpointHash.Remove( (PVOID)pEndpoint->GetEnumKey() );
  951. pEndpoint->SetSocketPort( NULL );
  952. #ifdef DPNBUILD_ONLYONEADAPTER
  953. pEndpoint->DecRef();
  954. #else // ! DPNBUILD_ONLYONEADAPTER
  955. fRemoveFromMultiplex = TRUE;
  956. #endif // ! DPNBUILD_ONLYONEADAPTER
  957. break;
  958. }
  959. default:
  960. {
  961. DNASSERT( FALSE );
  962. break;
  963. }
  964. }
  965. UnlockEndpointData();
  966. #ifndef DPNBUILD_ONLYONEADAPTER
  967. if (fRemoveFromMultiplex)
  968. {
  969. //
  970. // The multiplex list is protected by the SPData's socket data lock which
  971. // we must take now.
  972. // Removing from a list when not in a list does not cause any problems.
  973. //
  974. DNASSERT(m_pSocketData != NULL);
  975. m_pSocketData->Lock();
  976. pEndpoint->RemoveFromMultiplexList();
  977. m_pSocketData->Unlock();
  978. fRemoveFromMultiplex = FALSE;
  979. pEndpoint->DecRef();
  980. }
  981. #endif // ! DPNBUILD_ONLYONEADAPTER
  982. DPFX(DPFPREP, 6, "(0x%p) Leave", this);
  983. }
  984. //**********************************************************************
  985. //**********************************************************************
  986. // ------------------------------
  987. // CSocketPort::SendData - send data
  988. //
  989. // Entry: Pointer to write data buffer
  990. // Buffer count
  991. // Pointer to destination socket address
  992. //
  993. // Exit: Nothing
  994. // ------------------------------
  995. #undef DPF_MODNAME
  996. #define DPF_MODNAME "CSocketPort::SendData"
  997. #ifdef DPNBUILD_ASYNCSPSENDS
  998. void CSocketPort::SendData( BUFFERDESC *pBuffers, UINT_PTR uiBufferCount, const CSocketAddress *pDestinationSocketAddress, OVERLAPPED * pOverlapped )
  999. #else // ! DPNBUILD_ASYNCSPSENDS
  1000. void CSocketPort::SendData( BUFFERDESC *pBuffers, UINT_PTR uiBufferCount, const CSocketAddress *pDestinationSocketAddress )
  1001. #endif // ! DPNBUILD_ASYNCSPSENDS
  1002. {
  1003. INT iSendToReturn;
  1004. #ifdef DPNBUILD_WINSOCKSTATISTICS
  1005. DWORD dwStartTime;
  1006. #endif // DPNBUILD_WINSOCKSTATISTICS
  1007. DNASSERT(pBuffers != NULL);
  1008. DNASSERT( uiBufferCount != 0 );
  1009. DNASSERT( pDestinationSocketAddress != NULL );
  1010. DNASSERT( m_State == SOCKET_PORT_STATE_BOUND );
  1011. //
  1012. // Win9x WinSock 1 only systems or Win9x WinSock2 systems running IPX
  1013. // need to use the WinSock 1 code path. Everyone else should use the
  1014. // WinSock 2 code path.
  1015. //
  1016. #ifndef DPNBUILD_ONLYWINSOCK2
  1017. #ifndef DPNBUILD_NOWINSOCK2
  1018. if ( ( LOWORD( GetWinsockVersion() ) < 2 )
  1019. #ifndef DPNBUILD_NOIPX
  1020. || ( m_pNetworkSocketAddress->GetFamily() != AF_INET )
  1021. #endif // ! DPNBUILD_NOIPX
  1022. )
  1023. #endif // ! DPNBUILD_NOWINSOCK2
  1024. {
  1025. UINT_PTR uOutputBufferIndex;
  1026. INT iOutputByteCount;
  1027. char TempBuffer[ MAX_SEND_FRAME_SIZE ];
  1028. //
  1029. // flatten output data
  1030. //
  1031. iOutputByteCount = 0;
  1032. uOutputBufferIndex = 0;
  1033. do
  1034. {
  1035. DNASSERT( ( iOutputByteCount + pBuffers[ uOutputBufferIndex ].dwBufferSize ) <= LENGTHOF( TempBuffer ) );
  1036. memcpy( &TempBuffer[ iOutputByteCount ], pBuffers[ uOutputBufferIndex ].pBufferData, pBuffers[ uOutputBufferIndex ].dwBufferSize );
  1037. iOutputByteCount += pBuffers[ uOutputBufferIndex ].dwBufferSize;
  1038. uOutputBufferIndex++;
  1039. } while( uOutputBufferIndex < uiBufferCount );
  1040. #ifdef DBG
  1041. DPFX(DPFPREP, 7, "(0x%p) Winsock1 sending %i bytes (in 0x%p's %u buffers) from + to:",
  1042. this, iOutputByteCount, pBuffers, uOutputBufferIndex );
  1043. DumpSocketAddress( 7, GetNetworkAddress()->GetAddress(), GetNetworkAddress()->GetFamily() );
  1044. DumpSocketAddress( 7, pDestinationSocketAddress->GetAddress(), pDestinationSocketAddress->GetFamily() );
  1045. DNASSERT(iOutputByteCount > 0);
  1046. #endif // DBG
  1047. #ifdef DPNBUILD_WINSOCKSTATISTICS
  1048. dwStartTime = GETTIMESTAMP();
  1049. #endif // DPNBUILD_WINSOCKSTATISTICS
  1050. //
  1051. // there is no need to note an I/O reference because our Winsock1 I/O is synchronous
  1052. //
  1053. iSendToReturn = sendto( GetSocket(), // socket
  1054. TempBuffer, // data to send
  1055. iOutputByteCount, // number of bytes to send
  1056. 0, // flags (none)
  1057. pDestinationSocketAddress->GetAddress(), // pointer to destination address
  1058. pDestinationSocketAddress->GetAddressSize() // size of destination address
  1059. );
  1060. #ifdef DPNBUILD_WINSOCKSTATISTICS
  1061. #ifndef WINCE
  1062. DNInterlockedExchangeAdd((LPLONG) (&g_dwWinsockStatSendCallTime),
  1063. (GETTIMESTAMP() - dwStartTime));
  1064. #endif // ! WINCE
  1065. DNInterlockedIncrement((LPLONG) (&g_dwWinsockStatNumSends));
  1066. #endif // DPNBUILD_WINSOCKSTATISTICS
  1067. }
  1068. #ifndef DPNBUILD_NOWINSOCK2
  1069. else
  1070. #endif // ! DPNBUILD_NOWINSOCK2
  1071. #endif // ! DPNBUILD_ONLYWINSOCK2
  1072. #ifndef DPNBUILD_NOWINSOCK2
  1073. {
  1074. DWORD dwBytesSent;
  1075. DBG_CASSERT( sizeof( pBuffers ) == sizeof( WSABUF* ) );
  1076. DBG_CASSERT( sizeof( *pBuffers ) == sizeof( WSABUF ) );
  1077. #ifdef DBG
  1078. {
  1079. UINT_PTR uiBuffer;
  1080. UINT_PTR uiTotalSize;
  1081. uiTotalSize = 0;
  1082. for(uiBuffer = 0; uiBuffer < uiBufferCount; uiBuffer++)
  1083. {
  1084. DNASSERT(pBuffers[uiBuffer].pBufferData != NULL);
  1085. DNASSERT(pBuffers[uiBuffer].dwBufferSize != 0);
  1086. uiTotalSize += pBuffers[uiBuffer].dwBufferSize;
  1087. }
  1088. DPFX(DPFPREP, 7, "(0x%p) Winsock2 sending %u bytes (in 0x%p's %u buffers) from + to:",
  1089. this, uiTotalSize, pBuffers, uiBufferCount );
  1090. DumpSocketAddress( 7, GetNetworkAddress()->GetAddress(), GetNetworkAddress()->GetFamily() );
  1091. DumpSocketAddress( 7, pDestinationSocketAddress->GetAddress(), pDestinationSocketAddress->GetFamily() );
  1092. DNASSERT(uiTotalSize > 0);
  1093. if (pBuffers[0].pBufferData[0] == 0)
  1094. {
  1095. PREPEND_BUFFER * pPrependBuffer;
  1096. //
  1097. // Make sure the data is formed correctly.
  1098. //
  1099. DNASSERT(uiBufferCount > 1);
  1100. pPrependBuffer = (PREPEND_BUFFER*) pBuffers[0].pBufferData;
  1101. switch (pPrependBuffer->GenericHeader.bSPCommandByte)
  1102. {
  1103. case ENUM_DATA_KIND:
  1104. case ENUM_RESPONSE_DATA_KIND:
  1105. #ifndef DPNBUILD_SINGLEPROCESS
  1106. case PROXIED_ENUM_DATA_KIND:
  1107. #endif // ! DPNBUILD_SINGLEPROCESS
  1108. #ifdef DPNBUILD_XNETSECURITY
  1109. case XNETSEC_ENUM_RESPONSE_DATA_KIND:
  1110. #endif // DPNBUILD_XNETSECURITY
  1111. {
  1112. DNASSERT(pBuffers[1].dwBufferSize > 0);
  1113. break;
  1114. }
  1115. default:
  1116. {
  1117. DNASSERT(FALSE);
  1118. break;
  1119. }
  1120. }
  1121. }
  1122. switch (pDestinationSocketAddress->GetFamily() )
  1123. {
  1124. case AF_INET:
  1125. {
  1126. SOCKADDR_IN * psaddrin;
  1127. psaddrin = (SOCKADDR_IN *) pDestinationSocketAddress->GetAddress();
  1128. DNASSERT( psaddrin->sin_addr.S_un.S_addr != 0 );
  1129. DNASSERT( psaddrin->sin_port != 0 );
  1130. break;
  1131. }
  1132. #ifndef DPNBUILD_NOIPX
  1133. case AF_IPX:
  1134. {
  1135. break;
  1136. }
  1137. #endif // ! DPNBUILD_NOIPX
  1138. #ifndef DPNBUILD_NOIPV6
  1139. case AF_INET6:
  1140. {
  1141. SOCKADDR_IN6 * psaddrin6;
  1142. psaddrin6 = (SOCKADDR_IN6 *) pDestinationSocketAddress->GetAddress();
  1143. DNASSERT (! IN6_IS_ADDR_UNSPECIFIED(&psaddrin6->sin6_addr));
  1144. DNASSERT( psaddrin6->sin6_port != 0 );
  1145. break;
  1146. }
  1147. #endif // ! DPNBUILD_NOIPV6
  1148. default:
  1149. {
  1150. DNASSERT( FALSE );
  1151. break;
  1152. }
  1153. }
  1154. }
  1155. #endif // DBG
  1156. DNASSERT( uiBufferCount <= UINT32_MAX );
  1157. #ifdef DPNBUILD_WINSOCKSTATISTICS
  1158. dwStartTime = GETTIMESTAMP();
  1159. #endif // DPNBUILD_WINSOCKSTATISTICS
  1160. #ifdef DPNBUILD_ASYNCSPSENDS
  1161. iSendToReturn = p_WSASendTo( GetSocket(), // socket
  1162. reinterpret_cast<WSABUF*>( pBuffers ), // buffers
  1163. static_cast<DWORD>( uiBufferCount ), // count of buffers
  1164. &dwBytesSent, // pointer to number of bytes sent
  1165. 0, // send flags
  1166. pDestinationSocketAddress->GetAddress(), // pointer to destination address
  1167. pDestinationSocketAddress->GetAddressSize(), // size of destination address
  1168. pOverlapped, // pointer to overlap structure
  1169. NULL); // APC callback (unused)
  1170. #else // ! DPNBUILD_ASYNCSPSENDS
  1171. iSendToReturn = p_WSASendTo( GetSocket(), // socket
  1172. reinterpret_cast<WSABUF*>( pBuffers ), // buffers
  1173. static_cast<DWORD>( uiBufferCount ), // count of buffers
  1174. &dwBytesSent, // pointer to number of bytes sent
  1175. 0, // send flags
  1176. pDestinationSocketAddress->GetAddress(), // pointer to destination address
  1177. pDestinationSocketAddress->GetAddressSize(), // size of destination address
  1178. NULL, // pointer to overlap structure
  1179. NULL); // APC callback (unused)
  1180. #endif // ! DPNBUILD_ASYNCSPSENDS
  1181. #ifdef DPNBUILD_WINSOCKSTATISTICS
  1182. DNInterlockedExchangeAdd((LPLONG) (&g_dwWinsockStatSendCallTime),
  1183. (GETTIMESTAMP() - dwStartTime));
  1184. DNInterlockedIncrement((LPLONG) (&g_dwWinsockStatNumSends));
  1185. #endif // DPNBUILD_WINSOCKSTATISTICS
  1186. }
  1187. #endif // ! DPNBUILD_NOWINSOCK2
  1188. #ifdef DBG
  1189. if ( iSendToReturn == SOCKET_ERROR )
  1190. {
  1191. DWORD dwWinsockError;
  1192. dwWinsockError = WSAGetLastError();
  1193. #ifdef DPNBUILD_ASYNCSPSENDS
  1194. if (dwWinsockError == ERROR_IO_PENDING)
  1195. {
  1196. DPFX(DPFPREP, 8, "(0x%p) Overlapped 0x%p send is pending.",
  1197. this, pOverlapped);
  1198. DNASSERT(pOverlapped != NULL);
  1199. }
  1200. else
  1201. #endif // DPNBUILD_ASYNCSPSENDS
  1202. {
  1203. DPFX(DPFPREP, 0, "Problem with sendto (err = %u)!", dwWinsockError );
  1204. DisplayWinsockError( 0, dwWinsockError );
  1205. DNASSERTX(! "SendTo failed!", 3);
  1206. }
  1207. //
  1208. // Continue anyway, send failures are ignored.
  1209. // For async sends, our overlapped structure should always get signalled.
  1210. //
  1211. }
  1212. #endif // DBG
  1213. }
  1214. //**********************************************************************
  1215. #ifndef DPNBUILD_ONLYWINSOCK2
  1216. //**********************************************************************
  1217. // ------------------------------
  1218. // CSocketPort::Winsock1ReadService - service a read request on a socket
  1219. //
  1220. // Entry: Nothing
  1221. //
  1222. // Exit: Boolean indicating whether I/O was serviced
  1223. // TRUE = I/O serviced
  1224. // FALSE = I/O not serviced
  1225. // ------------------------------
  1226. #undef DPF_MODNAME
  1227. #define DPF_MODNAME "CSocketPort::Winsock1ReadService"
  1228. BOOL CSocketPort::Winsock1ReadService( void )
  1229. {
  1230. BOOL fIOServiced;
  1231. INT iSocketReturn;
  1232. CReadIOData *pReadData;
  1233. READ_IO_DATA_POOL_CONTEXT PoolContext;
  1234. //
  1235. // initialize
  1236. //
  1237. fIOServiced = FALSE;
  1238. //
  1239. // Attempt to get a new receive buffer from the pool. If we fail, we'll
  1240. // just fail to service this read and the socket will still be labeled
  1241. // as ready to receive so we'll try again later.
  1242. //
  1243. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  1244. PoolContext.sSPType = m_pNetworkSocketAddress->GetFamily();
  1245. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  1246. #ifndef DPNBUILD_ONLYONEPROCESSOR
  1247. PoolContext.dwCPU = 0; // we always only use CPU 0, systems using Winsock 1 should only have 1 CPU anyway
  1248. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  1249. #ifdef DPNBUILD_NOWINSOCK2
  1250. pReadData = m_pThreadPool->GetNewReadIOData( &PoolContext );
  1251. #else // ! DPNBUILD_NOWINSOCK2
  1252. pReadData = m_pThreadPool->GetNewReadIOData( &PoolContext, FALSE );
  1253. #endif // ! DPNBUILD_NOWINSOCK2
  1254. if ( pReadData == NULL )
  1255. {
  1256. DPFX(DPFPREP, 0, "Could not get read data to perform a Winsock1 read!" );
  1257. goto Exit;
  1258. }
  1259. DBG_CASSERT( sizeof( pReadData->ReceivedBuffer()->BufferDesc.pBufferData ) == sizeof( char* ) );
  1260. pReadData->m_iSocketAddressSize = pReadData->m_pSourceSocketAddress->GetAddressSize();
  1261. pReadData->SetSocketPort( NULL );
  1262. iSocketReturn = recvfrom( GetSocket(), // socket to read from
  1263. reinterpret_cast<char*>( pReadData->ReceivedBuffer()->BufferDesc.pBufferData ), // pointer to receive buffer
  1264. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize, // size of receive buffer
  1265. 0, // flags (none)
  1266. pReadData->m_pSourceSocketAddress->GetWritableAddress(), // address of sending socket
  1267. &pReadData->m_iSocketAddressSize // size of address of sending socket
  1268. );
  1269. #ifdef WINCE
  1270. //
  1271. // On a Pocket PC 2002 machine recvfrom() can stomp the from address,
  1272. // causing the address family to be invalid. This is not good, so to
  1273. // workaround, we will forcefully restore it.
  1274. //
  1275. pReadData->m_pSourceSocketAddress->GetWritableAddress()->sa_family = m_pNetworkSocketAddress->GetFamily();
  1276. #endif // WINCE
  1277. switch ( iSocketReturn )
  1278. {
  1279. //
  1280. // socket has been closed
  1281. //
  1282. case 0:
  1283. {
  1284. break;
  1285. }
  1286. //
  1287. // problem
  1288. //
  1289. case SOCKET_ERROR:
  1290. {
  1291. DWORD dwWinsockError;
  1292. dwWinsockError = WSAGetLastError();
  1293. switch ( dwWinsockError )
  1294. {
  1295. //
  1296. // one of our previous sends failed to get through,
  1297. // and we don't really care anymore
  1298. //
  1299. case WSAECONNRESET:
  1300. {
  1301. DPFX(DPFPREP, 7, "(0x%p) Send failure reported from + to:", this);
  1302. DumpSocketAddress(7, pReadData->m_pSourceSocketAddress->GetAddress(), pReadData->m_pSourceSocketAddress->GetFamily());
  1303. DumpSocketAddress(7, GetNetworkAddress()->GetAddress(), GetNetworkAddress()->GetFamily());
  1304. break;
  1305. }
  1306. //
  1307. // the socket isn't valid, it was probably closed
  1308. //
  1309. case WSAENOTSOCK:
  1310. {
  1311. DPFX(DPFPREP, 1, "Winsock1 reporting 'Not a socket' on receive." );
  1312. break;
  1313. }
  1314. //
  1315. // the socket appears to have been shut down
  1316. //
  1317. case WSAESHUTDOWN:
  1318. {
  1319. DPFX(DPFPREP, 1, "Winsock1 reporting socket was shut down." );
  1320. break;
  1321. }
  1322. //
  1323. // there is no data to read
  1324. //
  1325. case WSAEWOULDBLOCK:
  1326. {
  1327. DPFX(DPFPREP, 1, "Winsock1 reporting there is no data to receive on a socket." );
  1328. break;
  1329. }
  1330. //
  1331. // read operation was interrupted
  1332. //
  1333. case WSAEINTR:
  1334. {
  1335. DPFX(DPFPREP, 1, "Winsock1 reporting receive was interrupted." );
  1336. break;
  1337. }
  1338. //
  1339. // something bad happened
  1340. //
  1341. default:
  1342. {
  1343. DPFX(DPFPREP, 0, "Problem with Winsock1 recvfrom!" );
  1344. DisplayWinsockError( 0, dwWinsockError );
  1345. DNASSERT( FALSE );
  1346. break;
  1347. }
  1348. }
  1349. break;
  1350. }
  1351. //
  1352. // bytes were read
  1353. //
  1354. default:
  1355. {
  1356. fIOServiced = TRUE;
  1357. if (pReadData->m_pSourceSocketAddress->IsValidUnicastAddress(FALSE))
  1358. {
  1359. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize = iSocketReturn;
  1360. ProcessReceivedData( pReadData );
  1361. }
  1362. else
  1363. {
  1364. DPFX(DPFPREP, 7, "(0x%p) Invalid source address, ignoring %i bytes of data from + to:",
  1365. this, iSocketReturn);
  1366. DumpSocketAddress(7, pReadData->m_pSourceSocketAddress->GetAddress(), pReadData->m_pSourceSocketAddress->GetFamily());
  1367. DumpSocketAddress(7, GetNetworkAddress()->GetAddress(), GetNetworkAddress()->GetFamily());
  1368. }
  1369. break;
  1370. }
  1371. }
  1372. DNASSERT( pReadData != NULL );
  1373. pReadData->DecRef();
  1374. Exit:
  1375. return fIOServiced;
  1376. }
  1377. //**********************************************************************
  1378. //**********************************************************************
  1379. // ------------------------------
  1380. // CSocketPort::Winsock1ErrorService - service an error on this socket
  1381. //
  1382. // Entry: Nothing
  1383. //
  1384. // Exit: Boolean indicating whether I/O was serviced
  1385. // TRUE = I/O serviced
  1386. // FALSE = I/O not serviced
  1387. // ------------------------------
  1388. #undef DPF_MODNAME
  1389. #define DPF_MODNAME "CSocketPort::Winsock1ErrorService"
  1390. BOOL CSocketPort::Winsock1ErrorService( void )
  1391. {
  1392. //
  1393. // this function doesn't do anything because errors on sockets will usually
  1394. // result in the socket being closed soon
  1395. //
  1396. return FALSE;
  1397. }
  1398. //**********************************************************************
  1399. #endif // ! DPNBUILD_ONLYWINSOCK2
  1400. #ifndef DPNBUILD_NOWINSOCK2
  1401. //**********************************************************************
  1402. // ------------------------------
  1403. // CSocketPort::Winsock2Receive - receive data in a Winsock 2.0 fashion
  1404. //
  1405. // Entry: CPU number on which to receive (multi-proc builds only)
  1406. //
  1407. // Exit: Error code
  1408. // ------------------------------
  1409. #undef DPF_MODNAME
  1410. #define DPF_MODNAME "CSocketPort::Winsock2Receive"
  1411. #ifdef DPNBUILD_ONLYONEPROCESSOR
  1412. HRESULT CSocketPort::Winsock2Receive( void )
  1413. #else // ! DPNBUILD_ONLYONEPROCESSOR
  1414. HRESULT CSocketPort::Winsock2Receive( const DWORD dwCPU )
  1415. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  1416. {
  1417. HRESULT hr;
  1418. INT iWSAReturn;
  1419. READ_IO_DATA_POOL_CONTEXT PoolContext;
  1420. CReadIOData *pReadData;
  1421. DWORD dwFlags;
  1422. //
  1423. // initialize
  1424. //
  1425. hr = DPN_OK;
  1426. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  1427. PoolContext.sSPType = m_pNetworkSocketAddress->GetFamily();
  1428. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  1429. #ifndef DPNBUILD_ONLYONEPROCESSOR
  1430. PoolContext.dwCPU = dwCPU;
  1431. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  1432. #ifdef DPNBUILD_ONLYWINSOCK2
  1433. pReadData = m_pThreadPool->GetNewReadIOData( &PoolContext );
  1434. #else // ! DPNBUILD_ONLYWINSOCK2
  1435. pReadData = m_pThreadPool->GetNewReadIOData( &PoolContext, TRUE );
  1436. #endif // ! DPNBUILD_ONLYWINSOCK2
  1437. if ( pReadData == NULL )
  1438. {
  1439. hr = DPNERR_OUTOFMEMORY;
  1440. DPFX(DPFPREP, 0, "Out of memory attempting Winsock2 read!" );
  1441. goto Exit;
  1442. }
  1443. //
  1444. // pReadData has one reference so far, the one for this function.
  1445. //
  1446. //
  1447. // note the IO reference before attempting the read
  1448. //
  1449. AddRef();
  1450. DNASSERT( pReadData->m_pSourceSocketAddress != NULL );
  1451. DNASSERT( pReadData->SocketPort() == NULL );
  1452. DBG_CASSERT( sizeof( pReadData->ReceivedBuffer()->BufferDesc ) == sizeof( WSABUF ) );
  1453. DBG_CASSERT( OFFSETOF( BUFFERDESC, dwBufferSize ) == OFFSETOF( WSABUF, len ) );
  1454. DBG_CASSERT( OFFSETOF( BUFFERDESC, pBufferData ) == OFFSETOF( WSABUF, buf ) );
  1455. pReadData->m_iSocketAddressSize = pReadData->m_pSourceSocketAddress->GetAddressSize();
  1456. pReadData->SetSocketPort( this );
  1457. DPFX(DPFPREP, 8, "Submitting read 0x%p (socketport 0x%p, socket 0x%p).",
  1458. pReadData, this, GetSocket());
  1459. //
  1460. // Add a reference for submitting the read to WinSock. This should be
  1461. // removed when the receive completes.
  1462. //
  1463. pReadData->AddRef();
  1464. DNASSERT( pReadData->m_dwOverlappedBytesReceived == 0 );
  1465. Reread:
  1466. dwFlags = 0;
  1467. if ( GetSocket() == INVALID_SOCKET )
  1468. {
  1469. DPFX(DPFPREP, 1, "Attempting to submit read 0x%p on socketport (0x%p) that does not have a valid handle.",
  1470. pReadData, this);
  1471. }
  1472. iWSAReturn = p_WSARecvFrom( GetSocket(), // socket
  1473. reinterpret_cast<WSABUF*>(&pReadData->ReceivedBuffer()->BufferDesc), // pointer to receive buffers
  1474. 1, // number of receive buffers
  1475. &pReadData->m_dwBytesRead, // pointer to bytes received (if command completes immediately)
  1476. &dwFlags, // flags (none)
  1477. pReadData->m_pSourceSocketAddress->GetWritableAddress(), // address of sending socket
  1478. &pReadData->m_iSocketAddressSize, // size of address of sending socket
  1479. (WSAOVERLAPPED*) pReadData->GetOverlapped(), // pointer to overlapped structure
  1480. NULL // APC callback (unused)
  1481. );
  1482. if ( iWSAReturn == 0 )
  1483. {
  1484. DPFX(DPFPREP, 8, "WSARecvFrom for read data 0x%p completed immediately.",
  1485. pReadData );
  1486. #ifdef DPNBUILD_USEIOCOMPLETIONPORTS
  1487. //
  1488. // Winsock still generates a completion, even though it returned a
  1489. // result immediately.
  1490. //
  1491. #else // ! DPNBUILD_USEIOCOMPLETIONPORTS
  1492. //
  1493. // Return the read data's overlapped structure since it won't be used
  1494. // but we can't wait for the read data pool release function to return
  1495. // the overlapped structure (because the
  1496. // CSocketPort::Winsock2ReceiveComplete call assumes it was invoked by
  1497. // the I/O completion where this isn't necessary).
  1498. //
  1499. // First retrieve the overlapped result, though.
  1500. //
  1501. if (! p_WSAGetOverlappedResult(GetSocket(),
  1502. (WSAOVERLAPPED*) pReadData->GetOverlapped(),
  1503. &pReadData->m_dwOverlappedBytesReceived,
  1504. FALSE,
  1505. &dwFlags))
  1506. {
  1507. pReadData->m_ReceiveWSAReturn = WSAGetLastError();
  1508. }
  1509. else
  1510. {
  1511. pReadData->m_ReceiveWSAReturn = ERROR_SUCCESS;
  1512. }
  1513. hr = IDirectPlay8ThreadPoolWork_ReleaseOverlapped(m_pThreadPool->GetDPThreadPoolWork(),
  1514. pReadData->GetOverlapped(),
  1515. 0);
  1516. if (hr != DPN_OK)
  1517. {
  1518. DPFX(DPFPREP, 0, "Couldn't release overlapped structure 0x%p for read data 0x%p!",
  1519. pReadData->GetOverlapped(), pReadData);
  1520. DNASSERT(FALSE);
  1521. }
  1522. pReadData->SetOverlapped(NULL);
  1523. pReadData->m_ReceiveWSAReturn = iWSAReturn;
  1524. //
  1525. // Queue a job up so that the receive gets processed. Technically we
  1526. // could just handle it here, but since new receives get submitted
  1527. // when handling a previous receive *prior* to actually processing the
  1528. // data, that would cause unnecessary out-of-order receives.
  1529. //
  1530. // We transfer our read data object reference to the delayed completion.
  1531. //
  1532. #ifdef DPNBUILD_ONLYONEPROCESSOR
  1533. hr = m_pThreadPool->SubmitDelayedCommand( CSocketPort::Winsock2ReceiveComplete, // callback function
  1534. pReadData ); // callback context
  1535. #else // ! DPNBUILD_ONLYONEPROCESSOR
  1536. hr = m_pThreadPool->SubmitDelayedCommand( dwCPU, // CPU
  1537. CSocketPort::Winsock2ReceiveComplete, // callback function
  1538. pReadData ); // callback context
  1539. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  1540. if (hr != DPN_OK)
  1541. {
  1542. DPFX(DPFPREP, 0, "Couldn't submit delayed processing command for read data 0x%p!",
  1543. pReadData);
  1544. DNASSERT(FALSE);
  1545. }
  1546. #endif // ! DPNBUILD_USEIOCOMPLETIONPORTS
  1547. }
  1548. else
  1549. {
  1550. DWORD dwWSAReceiveError;
  1551. //
  1552. // failure, check for pending operation
  1553. //
  1554. dwWSAReceiveError = WSAGetLastError();
  1555. switch ( dwWSAReceiveError )
  1556. {
  1557. //
  1558. // the send is pending, nothing to do
  1559. //
  1560. case ERROR_IO_PENDING:
  1561. {
  1562. hr = IDirectPlay8ThreadPoolWork_SubmitIoOperation(m_pThreadPool->GetDPThreadPoolWork(),
  1563. pReadData->GetOverlapped(),
  1564. 0);
  1565. if (hr != DPN_OK)
  1566. {
  1567. DPFX(DPFPREP, 0, "Couldn't start monitoring read data 0x%p!",
  1568. pReadData);
  1569. DNASSERT(FALSE);
  1570. }
  1571. //
  1572. // We transfer the read data reference to the I/O
  1573. // monitoring code.
  1574. //
  1575. break;
  1576. }
  1577. //
  1578. // Since this is a UDP socket, this is an indication
  1579. // that a previous send failed. Ignore it and move
  1580. // on.
  1581. //
  1582. case WSAECONNRESET:
  1583. {
  1584. DPFX(DPFPREP, 8, "WSARecvFrom issued a WSACONNRESET." );
  1585. goto Reread;
  1586. break;
  1587. }
  1588. case WSAENOTSOCK:
  1589. {
  1590. DPFX(DPFPREP, 8, "Got WSAENOTSOCK on RecvFrom." );
  1591. hr = DPNERR_GENERIC;
  1592. DNASSERT( pReadData != NULL );
  1593. //
  1594. // Remove the WinSock reference.
  1595. //
  1596. pReadData->DecRef();
  1597. //
  1598. // the following DecRef may result in this object being returned to the
  1599. // pool, make sure we don't access member variables after this point!
  1600. //
  1601. DecRef();
  1602. goto Exit;
  1603. }
  1604. //
  1605. // there was a problem, no completion notification will
  1606. // be given, decrement our IO reference count
  1607. //
  1608. default:
  1609. {
  1610. hr = DPNERR_GENERIC;
  1611. //
  1612. // 'Known Errors' that we don't want to ASSERT on.
  1613. //
  1614. // WSAEINTR: the socket has been shut down and is about to be/has been closed
  1615. // WSAESHUTDOWN: the socket has been shut down and is about to be/has been closed
  1616. // WSAENOBUFS: out of memory (stress condition)
  1617. //
  1618. switch ( dwWSAReceiveError )
  1619. {
  1620. case WSAEINTR:
  1621. {
  1622. DPFX(DPFPREP, 1, "Got WSAEINTR while trying to RecvFrom." );
  1623. break;
  1624. }
  1625. case WSAESHUTDOWN:
  1626. {
  1627. DPFX(DPFPREP, 1, "Got WSAESHUTDOWN while trying to RecvFrom." );
  1628. break;
  1629. }
  1630. case WSAENOBUFS:
  1631. {
  1632. DPFX(DPFPREP, 1, "Got WSAENOBUFS while trying to RecvFrom." );
  1633. break;
  1634. }
  1635. default:
  1636. {
  1637. DPFX(DPFPREP, 0, "Unknown WinSock error when issuing read!" );
  1638. DisplayWinsockError( 0, dwWSAReceiveError );
  1639. DNASSERT( FALSE );
  1640. }
  1641. }
  1642. DNASSERT( pReadData != NULL );
  1643. //
  1644. // Remove the WinSock reference.
  1645. //
  1646. pReadData->DecRef();
  1647. //
  1648. // the following DecRef may result in this object being returned to the
  1649. // pool, make sure we don't access member variables after this point!
  1650. //
  1651. DecRef();
  1652. goto Exit;
  1653. }
  1654. }
  1655. }
  1656. Exit:
  1657. if ( pReadData != NULL )
  1658. {
  1659. pReadData->DecRef();
  1660. }
  1661. return hr;
  1662. }
  1663. //**********************************************************************
  1664. #endif // DPNBUILD_NOWINSOCK2
  1665. #ifndef WINCE
  1666. //**********************************************************************
  1667. // ------------------------------
  1668. // CSocketPort::SetWinsockBufferSize - set the buffer size used by Winsock for
  1669. // this socket.
  1670. //
  1671. // Entry: Buffer size
  1672. //
  1673. // Exit: Nothing
  1674. // ------------------------------
  1675. #undef DPF_MODNAME
  1676. #define DPF_MODNAME "CSocketPort::SetWinsockBufferSize"
  1677. void CSocketPort::SetWinsockBufferSize( const INT iBufferSize ) const
  1678. {
  1679. INT iReturnValue;
  1680. DPFX(DPFPREP, 3, "(0x%p) Setting socket 0x%p receive buffer size to: %d",
  1681. this, GetSocket(), g_iWinsockReceiveBufferSize );
  1682. iReturnValue = setsockopt( GetSocket(),
  1683. SOL_SOCKET,
  1684. SO_RCVBUF,
  1685. reinterpret_cast<char*>( &g_iWinsockReceiveBufferSize ),
  1686. sizeof( g_iWinsockReceiveBufferSize )
  1687. );
  1688. if ( iReturnValue == SOCKET_ERROR )
  1689. {
  1690. DWORD dwErrorCode;
  1691. dwErrorCode = WSAGetLastError();
  1692. DPFX(DPFPREP, 0, "Failed to set the socket buffer receive size!" );
  1693. DisplayWinsockError( 0, dwErrorCode );
  1694. }
  1695. }
  1696. //**********************************************************************
  1697. #endif // ! WINCE
  1698. //**********************************************************************
  1699. // ------------------------------
  1700. // CSocketPort::BindToNetwork - bind this socket port to the network
  1701. //
  1702. // Entry: Handle of I/O completion port (NT old thread pool only)
  1703. // CPU number (mult-proc builds only)
  1704. // How to map socket on gateway
  1705. //
  1706. // Exit: Error code
  1707. // ------------------------------
  1708. #undef DPF_MODNAME
  1709. #define DPF_MODNAME "CSocketPort::BindToNetwork"
  1710. #ifdef DPNBUILD_ONLYONEPROCESSOR
  1711. HRESULT CSocketPort::BindToNetwork( const GATEWAY_BIND_TYPE GatewayBindType )
  1712. #else // ! DPNBUILD_ONLYONEPROCESSOR
  1713. HRESULT CSocketPort::BindToNetwork( const DWORD dwCPU, const GATEWAY_BIND_TYPE GatewayBindType )
  1714. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  1715. {
  1716. HRESULT hr;
  1717. INT iReturnValue;
  1718. BOOL fTemp;
  1719. #ifndef WINCE
  1720. INT iSendBufferSize;
  1721. #endif // !WINCE
  1722. CSocketAddress * pBoundSocketAddress;
  1723. WORD wBasePort;
  1724. DWORD dwErrorCode;
  1725. DWORD * pdwAddressChunk;
  1726. DWORD * pdwLastAddressChunk;
  1727. #if ((! defined(DPNBUILD_ONLYWINSOCK2)) || (defined(WINNT)))
  1728. DWORD dwTemp;
  1729. #endif // ! DPNBUILD_ONLYWINSOCK2 or WINNT
  1730. DPFX(DPFPREP, 7, "(0x%p) Parameters: (%i)", this, GatewayBindType );
  1731. //
  1732. // initialize
  1733. //
  1734. hr = DPN_OK;
  1735. pBoundSocketAddress = NULL;
  1736. //
  1737. // If we're picking a port, start at the base port. If we're on the
  1738. // ICS machine itself. pick a different starting point to workaround
  1739. // port stealing.
  1740. //
  1741. #ifdef DPNBUILD_NOREGISTRY
  1742. wBasePort = BASE_DPLAY8_PORT;
  1743. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_NOLOCALNAT)))
  1744. if ((IsNATTraversalEnabled()) &&
  1745. (g_fLocalNATDetectedAtStartup))
  1746. {
  1747. #if ((! defined(DPNBUILD_NOIPX)) || (! defined(DPNBUILD_NOIPV6)))
  1748. if (m_pNetworkSocketAddress->GetFamily() == AF_INET)
  1749. #endif // ! DPNBUILD_NOIPX or ! DPNBUILD_NOIPV6
  1750. {
  1751. wBasePort += (MAX_DPLAY8_PORT - BASE_DPLAY8_PORT) / 2;
  1752. }
  1753. }
  1754. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_NOLOCALNAT
  1755. #else // ! DPNBUILD_NOREGISTRY
  1756. wBasePort = g_wBaseDPlayPort;
  1757. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_NOLOCALNAT)))
  1758. if ((GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE) &&
  1759. (g_fLocalNATDetectedAtStartup))
  1760. {
  1761. #if ((! defined(DPNBUILD_NOIPX)) || (! defined(DPNBUILD_NOIPV6)))
  1762. if (m_pNetworkSocketAddress->GetFamily() == AF_INET)
  1763. #endif // ! DPNBUILD_NOIPX or ! DPNBUILD_NOIPV6
  1764. {
  1765. wBasePort += (g_wMaxDPlayPort - g_wBaseDPlayPort) / 2;
  1766. }
  1767. }
  1768. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_NOLOCALNAT
  1769. #endif // ! DPNBUILD_NOREGISTRY
  1770. #ifndef DPNBUILD_ONLYONEPROCESSOR
  1771. //
  1772. // Save the CPU to use.
  1773. //
  1774. m_dwCPU = dwCPU;
  1775. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  1776. #ifndef DPNBUILD_NONATHELP
  1777. RebindToNextPort:
  1778. #endif // ! DPNBUILD_NONATHELP
  1779. #ifdef DBG
  1780. DNASSERT( m_fInitialized != FALSE );
  1781. DNASSERT( m_State == SOCKET_PORT_STATE_INITIALIZED );
  1782. #endif // DBG
  1783. //
  1784. // get a socket for this socket port
  1785. //
  1786. DNASSERT( GetSocket() == INVALID_SOCKET );
  1787. m_Socket = socket( m_pNetworkSocketAddress->GetFamily(), // address family
  1788. SOCK_DGRAM, // datagram (connectionless) socket
  1789. m_pNetworkSocketAddress->GetProtocol() ); // protocol
  1790. if ( GetSocket() == INVALID_SOCKET )
  1791. {
  1792. hr = DPNERR_NOCONNECTION;
  1793. DPFX(DPFPREP, 0, "Failed to bind to socket!" );
  1794. goto Failure;
  1795. }
  1796. DPFX(DPFPREP, 5, "Created socketport 0x%p socket 0x%p.", this, m_Socket);
  1797. //
  1798. // set socket to allow broadcasts
  1799. //
  1800. fTemp = TRUE;
  1801. DBG_CASSERT( sizeof( &fTemp ) == sizeof( char * ) );
  1802. iReturnValue = setsockopt( GetSocket(), // socket
  1803. SOL_SOCKET, // level (set socket options)
  1804. SO_BROADCAST, // set broadcast option
  1805. reinterpret_cast<char *>( &fTemp ), // allow broadcast
  1806. sizeof( fTemp ) // size of parameter
  1807. );
  1808. if ( iReturnValue == SOCKET_ERROR )
  1809. {
  1810. dwErrorCode = WSAGetLastError();
  1811. DPFX(DPFPREP, 0, "Unable to set broadcast socket option (err = %u)!",
  1812. dwErrorCode );
  1813. DisplayWinsockError( 0, dwErrorCode );
  1814. hr = DPNERR_GENERIC;
  1815. goto Failure;
  1816. }
  1817. #ifndef WINCE // WinCE fails these with WSAENOPROTOOPT
  1818. //
  1819. // set socket receive buffer space if the user overrode it
  1820. // Failing this is a preformance hit so ignore and errors.
  1821. //
  1822. if ( g_fWinsockReceiveBufferSizeOverridden != FALSE )
  1823. {
  1824. SetWinsockBufferSize( g_iWinsockReceiveBufferSize );
  1825. }
  1826. //
  1827. // set socket send buffer space to 0 (we will supply all buffers).
  1828. // Failing this is only a performance hit so ignore any errors.
  1829. //
  1830. iSendBufferSize = 0;
  1831. iReturnValue = setsockopt( GetSocket(),
  1832. SOL_SOCKET,
  1833. SO_SNDBUF,
  1834. reinterpret_cast<char*>( &iSendBufferSize ),
  1835. sizeof( iSendBufferSize )
  1836. );
  1837. if ( iReturnValue == SOCKET_ERROR )
  1838. {
  1839. dwErrorCode = WSAGetLastError();
  1840. DPFX(DPFPREP, 0, "Failed to set the socket buffer send size (err = %u)!", dwErrorCode );
  1841. DisplayWinsockError( 0, dwErrorCode );
  1842. }
  1843. #endif // ! WINCE
  1844. #ifndef DPNBUILD_ONLYWINSOCK2
  1845. //
  1846. // put socket into non-blocking mode, if WinSock 1 or 9x IPX
  1847. //
  1848. #ifndef DPNBUILD_NOWINSOCK2
  1849. if ( ( LOWORD( GetWinsockVersion() ) == 1 )
  1850. #ifndef DPNBUILD_NOIPX
  1851. || ( m_pNetworkSocketAddress->GetFamily() == AF_IPX )
  1852. #endif // ! DPNBUILD_NOIPX
  1853. )
  1854. #endif // ! DPNBUILD_NOWINSOCK2
  1855. {
  1856. DPFX(DPFPREP, 5, "Marking socket as non-blocking." );
  1857. dwTemp = 1;
  1858. iReturnValue = ioctlsocket( GetSocket(), // socket
  1859. FIONBIO, // I/O option to set (blocking mode)
  1860. &dwTemp // I/O option value (non-zero puts socket into non-block mode)
  1861. );
  1862. if ( iReturnValue == SOCKET_ERROR )
  1863. {
  1864. dwErrorCode = WSAGetLastError();
  1865. DPFX(DPFPREP, 0, "Could not set socket into non-blocking mode (err = %u)!",
  1866. dwErrorCode );
  1867. DisplayWinsockError( 0, dwErrorCode );
  1868. hr = DPNERR_GENERIC;
  1869. goto Failure;
  1870. }
  1871. }
  1872. #else // DPNBUILD_ONLYWINSOCK2
  1873. #ifdef WINNT
  1874. //
  1875. // Attempt to make buffer circular.
  1876. //
  1877. iReturnValue = p_WSAIoctl(GetSocket(), // socket
  1878. SIO_ENABLE_CIRCULAR_QUEUEING, // io control code
  1879. NULL, // in buffer
  1880. 0, // in buffer size
  1881. NULL, // out buffer
  1882. 0, // out buffer size
  1883. &dwTemp, // pointer to bytes returned
  1884. NULL, // overlapped
  1885. NULL // completion routine
  1886. );
  1887. if ( iReturnValue == SOCKET_ERROR )
  1888. {
  1889. dwErrorCode = WSAGetLastError();
  1890. DPFX(DPFPREP, 1, "Could not enable circular queuing (err = %u), ignoring.",
  1891. dwErrorCode );
  1892. DisplayWinsockError( 1, dwErrorCode );
  1893. }
  1894. #if ((! defined(DPNBUILD_NOIPX)) || (! defined(DPNBUILD_NOIPV6)))
  1895. if ( m_pNetworkSocketAddress->GetFamily() == AF_INET )
  1896. #endif // ! DPNBUILD_NOIPX or ! DPNBUILD_NOIPV6
  1897. {
  1898. //
  1899. // Make broadcasts only go out on the interface on which they were sent
  1900. // (as opposed to all interfaces).
  1901. //
  1902. fTemp = TRUE;
  1903. iReturnValue = p_WSAIoctl(GetSocket(), // socket
  1904. SIO_LIMIT_BROADCASTS, // io control code
  1905. &fTemp, // in buffer
  1906. sizeof(fTemp), // in buffer size
  1907. NULL, // out buffer
  1908. 0, // out buffer size
  1909. &dwTemp, // pointer to bytes returned
  1910. NULL, // overlapped
  1911. NULL // completion routine
  1912. );
  1913. if ( iReturnValue == SOCKET_ERROR )
  1914. {
  1915. dwErrorCode = WSAGetLastError();
  1916. DPFX(DPFPREP, 1, "Could not limit broadcasts (err = %u), ignoring.",
  1917. dwErrorCode );
  1918. DisplayWinsockError( 1, dwErrorCode );
  1919. }
  1920. }
  1921. #endif // WINNT
  1922. #endif // DPNBUILD_ONLYWINSOCK2
  1923. //
  1924. // bind socket
  1925. //
  1926. DPFX(DPFPREP, 1, "Binding to socket addess:" );
  1927. DumpSocketAddress( 1, m_pNetworkSocketAddress->GetAddress(), m_pNetworkSocketAddress->GetFamily() );
  1928. DNASSERT( GetSocket() != INVALID_SOCKET );
  1929. hr = BindToNextAvailablePort( m_pNetworkSocketAddress, wBasePort );
  1930. if ( hr != DPN_OK )
  1931. {
  1932. DPFX(DPFPREP, 0, "Failed to bind to network!" );
  1933. DisplayDNError( 0, hr );
  1934. goto Failure;
  1935. }
  1936. DNASSERT( m_State == SOCKET_PORT_STATE_INITIALIZED );
  1937. m_State = SOCKET_PORT_STATE_BOUND;
  1938. //
  1939. // Find out what address we really bound to. This information is needed to
  1940. // talk to the Internet gateway and will be needed when someone above queries for
  1941. // what the local network address is.
  1942. //
  1943. pBoundSocketAddress = GetBoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT );
  1944. if ( pBoundSocketAddress == NULL )
  1945. {
  1946. hr = DPNERR_OUTOFMEMORY;
  1947. DPFX(DPFPREP, 0, "Failed to get bound adapter address!" );
  1948. goto Failure;
  1949. }
  1950. DPFX(DPFPREP, 1, "Socket we really bound to:" );
  1951. DumpSocketAddress( 1, pBoundSocketAddress->GetAddress(), pBoundSocketAddress->GetFamily() );
  1952. #ifndef DPNBUILD_NONATHELP
  1953. //
  1954. // Perform the same error handling twice for two different functions.
  1955. // 0 = check for an existing mapping
  1956. // 1 = attempt to create a new mapping
  1957. //
  1958. #ifdef DPNBUILD_NOLOCALNAT
  1959. for(dwTemp = 1; dwTemp < 2; dwTemp++)
  1960. #else // ! DPNBUILD_NOLOCALNAT
  1961. for(dwTemp = 0; dwTemp < 2; dwTemp++)
  1962. #endif // ! DPNBUILD_NOLOCALNAT
  1963. {
  1964. if (dwTemp == 0)
  1965. {
  1966. #ifdef DPNBUILD_NOLOCALNAT
  1967. DNASSERT( FALSE );
  1968. #else // ! DPNBUILD_NOLOCALNAT
  1969. //
  1970. // Make sure we're not slipping under an existing Internet gateway mapping.
  1971. // We have to do this because the current Windows NAT implementations do
  1972. // not mark the port as "in use", so if you bound to a port on the public
  1973. // adapter that had a mapping, you'd never receive any data. It would all
  1974. // be forwarded according to the mapping.
  1975. //
  1976. hr = CheckForOverridingMapping( pBoundSocketAddress );
  1977. #endif // ! DPNBUILD_NOLOCALNAT
  1978. }
  1979. else
  1980. {
  1981. //
  1982. // Attempt to bind to an Internet gateway.
  1983. //
  1984. hr = BindToInternetGateway( pBoundSocketAddress, GatewayBindType );
  1985. }
  1986. switch (hr)
  1987. {
  1988. case DPN_OK:
  1989. {
  1990. //
  1991. // 0 = there's no existing mapping that would override our socket
  1992. // 1 = mapping on Internet gateway (if any) was successful
  1993. //
  1994. break;
  1995. }
  1996. case DPNERR_ALREADYINITIALIZED:
  1997. {
  1998. //
  1999. // 0 = there's an existing mapping that would override our socket
  2000. // 1 = Internet gateway already had a conflicting mapping
  2001. //
  2002. // If we can, try binding to a different port. Otherwise we have to fail.
  2003. //
  2004. if (GatewayBindType == GATEWAY_BIND_TYPE_DEFAULT)
  2005. {
  2006. DPFX(DPFPREP, 1, "%s address already in use on Internet gateway (port = %u), rebinding.",
  2007. ((dwTemp == 0) ? _T("Private") : _T("Public")),
  2008. NTOHS(pBoundSocketAddress->GetPort()));
  2009. //
  2010. // Whether we succeed in unbinding or not, don't consider this bound anymore.
  2011. //
  2012. DNASSERT( m_State == SOCKET_PORT_STATE_BOUND );
  2013. m_State = SOCKET_PORT_STATE_INITIALIZED;
  2014. hr = UnbindFromNetwork();
  2015. if (hr != DPN_OK)
  2016. {
  2017. DPFX(DPFPREP, 0, "Couldn't unbind network socket address 0x%p from network before rebind attempt!",
  2018. this );
  2019. goto Failure;
  2020. }
  2021. //
  2022. // Move to the next port and try again.
  2023. //
  2024. wBasePort = NTOHS(pBoundSocketAddress->GetPort()) + 1;
  2025. //
  2026. // If we weren't in the DPlay range, then we must have gone through all
  2027. // of the DPlay range, plus let WinSock pick at least once. Since we can't
  2028. // trust WinSock to not keep picking the same port, we need to manually
  2029. // increase the port number.
  2030. //
  2031. #pragma TODO(vanceo, "Don't limit ICS machines to only half the ports in the range")
  2032. #ifdef DPNBUILD_NOREGISTRY
  2033. if ((NTOHS(pBoundSocketAddress->GetPort()) < BASE_DPLAY8_PORT) || (NTOHS(pBoundSocketAddress->GetPort()) > MAX_DPLAY8_PORT))
  2034. #else // ! DPNBUILD_NOREGISTRY
  2035. if ((NTOHS(pBoundSocketAddress->GetPort()) < g_wBaseDPlayPort) || (NTOHS(pBoundSocketAddress->GetPort()) > g_wMaxDPlayPort))
  2036. #endif // ! DPNBUILD_NOREGISTRY
  2037. {
  2038. //
  2039. // If we just walked back into the DPlay range, skip over it.
  2040. //
  2041. #ifdef DPNBUILD_NOREGISTRY
  2042. if ((wBasePort >= BASE_DPLAY8_PORT) && (wBasePort <= MAX_DPLAY8_PORT))
  2043. {
  2044. wBasePort = MAX_DPLAY8_PORT + 1;
  2045. }
  2046. #else // ! DPNBUILD_NOREGISTRY
  2047. if ((wBasePort >= g_wBaseDPlayPort) && (wBasePort <= g_wMaxDPlayPort))
  2048. {
  2049. wBasePort = g_wMaxDPlayPort + 1;
  2050. }
  2051. #endif // ! DPNBUILD_NOREGISTRY
  2052. //
  2053. // If we have wrapped all the way back to 0 (!) then fail, to prevent
  2054. // infinite looping.
  2055. //
  2056. if (wBasePort == 0)
  2057. {
  2058. DPFX(DPFPREP, 0, "Managed to fail binding socket address 0x%p to every port, aborting!",
  2059. this );
  2060. hr = DPNERR_ALREADYINITIALIZED;
  2061. goto Failure;
  2062. }
  2063. //
  2064. // Force the "fixed port" code path in BindToNextAvailablePort, even
  2065. // though it isn't really fixed.
  2066. //
  2067. DPFX(DPFPREP, 5, "Forcing port %u.", wBasePort );
  2068. m_pNetworkSocketAddress->SetPort(HTONS(wBasePort));
  2069. }
  2070. //
  2071. // Return the previous address and try again.
  2072. //
  2073. g_SocketAddressPool.Release( pBoundSocketAddress );
  2074. pBoundSocketAddress = NULL;
  2075. goto RebindToNextPort;
  2076. }
  2077. DPFX(DPFPREP, 0, "%s address already in use on Internet gateway (port = %u)!",
  2078. ((dwTemp == 0) ? _T("Private") : _T("Public")),
  2079. NTOHS(pBoundSocketAddress->GetPort()));
  2080. goto Failure;
  2081. break;
  2082. }
  2083. case DPNERR_UNSUPPORTED:
  2084. {
  2085. //
  2086. // 0 & 1 = NATHelp not loaded or isn't supported for SP
  2087. //
  2088. if (dwTemp == 0)
  2089. {
  2090. DPFX(DPFPREP, 2, "Not able to find existing private mapping for socketport 0x%p on local Internet gateway, unsupported/not necessary.",
  2091. this);
  2092. }
  2093. else
  2094. {
  2095. DPFX(DPFPREP, 2, "Didn't bind socketport 0x%p to Internet gateway, unsupported/not necessary.",
  2096. this);
  2097. }
  2098. //
  2099. // Ignore the error.
  2100. //
  2101. break;
  2102. }
  2103. default:
  2104. {
  2105. //
  2106. // 0 & 1 = ?
  2107. //
  2108. if (dwTemp == 0)
  2109. {
  2110. DPFX(DPFPREP, 1, "Unable to look for existing private mapping for socketport 0x%p on local Internet gateway (error = 0x%lx), ignoring.",
  2111. this, hr);
  2112. }
  2113. else
  2114. {
  2115. DPFX(DPFPREP, 1, "Unable to bind socketport 0x%p to Internet gateway (error = 0x%lx), ignoring.",
  2116. this, hr);
  2117. }
  2118. //
  2119. // Ignore the error, we can survive without the mapping.
  2120. //
  2121. break;
  2122. }
  2123. }
  2124. //
  2125. // Go to the next function to be handled in this manner.
  2126. //
  2127. }
  2128. #endif // ! DPNBUILD_NONATHELP
  2129. //
  2130. // Save the address we actually ended up with.
  2131. //
  2132. g_SocketAddressPool.Release( m_pNetworkSocketAddress );
  2133. m_pNetworkSocketAddress = pBoundSocketAddress;
  2134. pBoundSocketAddress = NULL;
  2135. #ifndef DPNBUILD_NOMULTICAST
  2136. //
  2137. // If IP, set socket option that makes broadcasts go out the device we
  2138. // intended instead of the primary device. Failing this is not fatal, it only
  2139. // applies to multihomed machines with devices on different networks, and
  2140. // might already work the way the user wants.
  2141. //
  2142. // We do this here because we want the socket to be bound so we can
  2143. // use its address for the setsockopt call.
  2144. //
  2145. #ifndef DPNBUILD_NOIPX
  2146. if (m_pNetworkSocketAddress->GetFamily() == AF_INET)
  2147. #endif // ! DPNBUILD_NOIPX
  2148. {
  2149. int iSocketOption;
  2150. SOCKADDR_IN * psaddrin;
  2151. //
  2152. // Since the IP multicast constants are different for Winsock1 vs. Winsock2,
  2153. // make sure we use the proper constant.
  2154. //
  2155. #ifdef DPNBUILD_ONLYWINSOCK2
  2156. iSocketOption = 9;
  2157. #else // ! DPNBUILD_ONLYWINSOCK2
  2158. #ifndef DPNBUILD_NOWINSOCK2
  2159. switch ( GetWinsockVersion() )
  2160. {
  2161. //
  2162. // Winsock1, use the IP_MULTICAST_IF value for Winsock1
  2163. // see WINSOCK.H
  2164. //
  2165. case 1:
  2166. {
  2167. #endif // ! DPNBUILD_NOWINSOCK2
  2168. iSocketOption = 2;
  2169. #ifndef DPNBUILD_NOWINSOCK2
  2170. break;
  2171. }
  2172. //
  2173. // Winsock2, or greater, use the IP_MULTICAST_IF value for Winsock2
  2174. // see WS2TCPIP.H
  2175. //
  2176. case 2:
  2177. default:
  2178. {
  2179. DNASSERT( GetWinsockVersion() == 2 );
  2180. iSocketOption = 9;
  2181. break;
  2182. }
  2183. }
  2184. #endif // ! DPNBUILD_NOWINSOCK2
  2185. #endif // ! DPNBUILD_ONLYWINSOCK2
  2186. psaddrin = (SOCKADDR_IN*) m_pNetworkSocketAddress->GetWritableAddress();
  2187. DPFX(DPFPREP, 9, "Setting IP_MULTICAST_IF option (%i).", iSocketOption);
  2188. iReturnValue = setsockopt( GetSocket(),
  2189. IPPROTO_IP,
  2190. iSocketOption,
  2191. reinterpret_cast<char*>( &psaddrin->sin_addr ),
  2192. sizeof( psaddrin->sin_addr )
  2193. );
  2194. if ( iReturnValue == SOCKET_ERROR )
  2195. {
  2196. dwErrorCode = WSAGetLastError();
  2197. DPFX(DPFPREP, 0, "Failed to set the multicast interface socket option (err = %u)!", dwErrorCode );
  2198. DisplayWinsockError( 0, dwErrorCode );
  2199. }
  2200. }
  2201. #endif // ! DPNBUILD_NOMULTICAST
  2202. //
  2203. // Generate a unique socketport ID. Start with the current time and
  2204. // combine in the address.
  2205. //
  2206. m_dwSocketPortID = GETTIMESTAMP();
  2207. pdwAddressChunk = (DWORD*) m_pNetworkSocketAddress->GetAddress();
  2208. pdwLastAddressChunk = (DWORD*) (((BYTE*) pdwAddressChunk) + m_pNetworkSocketAddress->GetAddressSize() - sizeof(DWORD));
  2209. while (pdwAddressChunk <= pdwLastAddressChunk)
  2210. {
  2211. m_dwSocketPortID ^= (*pdwAddressChunk);
  2212. pdwAddressChunk++;
  2213. }
  2214. #ifndef _XBOX
  2215. #ifndef DPNBUILD_NOWINSOCK2
  2216. #ifndef DPNBUILD_NOIPX
  2217. if (m_pNetworkSocketAddress->GetFamily() == AF_IPX)
  2218. {
  2219. //
  2220. // IPX, don't worry about proxies.
  2221. //
  2222. }
  2223. else
  2224. #endif // ! DPNBUILD_NOIPX
  2225. {
  2226. //
  2227. // Detect whether this socket has WinSock Proxy Client a.k.a. ISA Firewall
  2228. // Client installed (unless the user turned auto-detection off in the
  2229. // registry). We do this by looking at the name of the protocol that got
  2230. // bound to the socket. If it contains "Proxy", consider it proxied.
  2231. //
  2232. // Ignore failure (WinSock 1 probably doesn't have this socket option), and
  2233. // assume the proxy client isn't installed.
  2234. //
  2235. #ifndef DPNBUILD_NOREGISTRY
  2236. if (! g_fDontAutoDetectProxyLSP)
  2237. #endif // ! DPNBUILD_NOREGISTRY
  2238. {
  2239. #ifndef DPNBUILD_ONLYWINSOCK2
  2240. if (GetWinsockVersion() != 2)
  2241. {
  2242. //
  2243. // WinSock 1 doesn't have the required entry point.
  2244. //
  2245. DPFX(DPFPREP, 1, "Unable to auto-detect proxy client on WinSock 1, assuming not present.");
  2246. }
  2247. else
  2248. #endif // ! DPNBUILD_ONLYWINSOCK2
  2249. {
  2250. int aiProtocols[2];
  2251. WSAPROTOCOL_INFO * pwsapi;
  2252. DWORD dwBufferSize;
  2253. int i;
  2254. #ifdef DBG
  2255. #ifdef UNICODE
  2256. WCHAR wszProtocol[WSAPROTOCOL_LEN+1];
  2257. #else // ! UNICODE
  2258. char szProtocol[WSAPROTOCOL_LEN+1];
  2259. #endif // ! UNICODE
  2260. #endif // DBG
  2261. aiProtocols[0] = IPPROTO_UDP;
  2262. aiProtocols[1] = 0;
  2263. pwsapi = NULL;
  2264. dwBufferSize = 0;
  2265. //
  2266. // Keep trying to get the list of protocols until we get no error or some
  2267. // error other than WSAENOBUFS.
  2268. //
  2269. do
  2270. {
  2271. #ifdef UNICODE
  2272. iReturnValue = p_WSAEnumProtocolsW(aiProtocols, pwsapi, &dwBufferSize);
  2273. #else // ! UNICODE
  2274. iReturnValue = p_WSAEnumProtocolsA(aiProtocols, pwsapi, &dwBufferSize);
  2275. #endif // ! UNICODE
  2276. if (iReturnValue != SOCKET_ERROR)
  2277. {
  2278. //
  2279. // We succeeded, drop out of the loop.
  2280. //
  2281. break;
  2282. }
  2283. dwErrorCode = WSAGetLastError();
  2284. if (dwErrorCode != WSAENOBUFS)
  2285. {
  2286. DPFX(DPFPREP, 0, "Unable to enumerate protocols (error = 0x%lx)! Continuing.",
  2287. dwErrorCode);
  2288. DisplayWinsockError(0, dwErrorCode);
  2289. iReturnValue = 0;
  2290. break;
  2291. }
  2292. //
  2293. // We need more space. Make sure the size is valid.
  2294. //
  2295. if (dwBufferSize < sizeof(WSAPROTOCOL_INFO))
  2296. {
  2297. DPFX(DPFPREP, 0, "Enumerating protocols didn't return any items (%u < %u)! Continuing",
  2298. dwBufferSize, sizeof(WSAPROTOCOL_INFO));
  2299. iReturnValue = 0;
  2300. break;
  2301. }
  2302. //
  2303. // If we previously had a buffer, free it.
  2304. //
  2305. if (pwsapi != NULL)
  2306. {
  2307. DNFree(pwsapi);
  2308. }
  2309. //
  2310. // Allocate the buffer.
  2311. //
  2312. pwsapi = (WSAPROTOCOL_INFO*) DNMalloc(dwBufferSize);
  2313. if (pwsapi == NULL)
  2314. {
  2315. DPFX(DPFPREP, 0, "Unable to allocate memory for protocol list! Continuing.");
  2316. iReturnValue = 0;
  2317. break;
  2318. }
  2319. }
  2320. while (TRUE);
  2321. //
  2322. // If we read a valid buffer, parse it.
  2323. //
  2324. if ((iReturnValue > 0) &&
  2325. (dwBufferSize >= (sizeof(WSAPROTOCOL_INFO) * iReturnValue)))
  2326. {
  2327. //
  2328. // Loop through all the UDP protocols installed.
  2329. //
  2330. for(i = 0; i < iReturnValue; i++)
  2331. {
  2332. //
  2333. // See if the name contains "Proxy", case insensitive.
  2334. // Save the original string in debug so we can print it.
  2335. //
  2336. #ifdef UNICODE
  2337. #ifdef DBG
  2338. wcsncpy(wszProtocol, pwsapi[i].szProtocol, WSAPROTOCOL_LEN);
  2339. wszProtocol[WSAPROTOCOL_LEN] = 0; // ensure it's NULL terminated
  2340. #endif // DBG
  2341. _wcslwr(pwsapi[i].szProtocol);
  2342. if (wcsstr(pwsapi[i].szProtocol, L"proxy") != NULL)
  2343. {
  2344. DPFX(DPFPREP, 5, "Socketport 0x%p (ID 0x%x) appears to be using proxy client (protocol %i = \"%ls\").",
  2345. this, m_dwSocketPortID, i, wszProtocol);
  2346. m_fUsingProxyWinSockLSP = TRUE;
  2347. //
  2348. // Stop searching.
  2349. //
  2350. break;
  2351. }
  2352. DPFX(DPFPREP, 5, "Socketport 0x%p (ID 0x%x) protocol %i (\"%ls\") does not contain \"proxy\".",
  2353. this, m_dwSocketPortID, i, wszProtocol);
  2354. #else // ! UNICODE
  2355. #ifdef DBG
  2356. strncpy(szProtocol, pwsapi[i].szProtocol, WSAPROTOCOL_LEN);
  2357. szProtocol[WSAPROTOCOL_LEN] = 0; // ensure it's NULL terminated
  2358. #endif // DBG
  2359. _strlwr(pwsapi[i].szProtocol);
  2360. if (strstr(pwsapi[i].szProtocol, "proxy") != NULL)
  2361. {
  2362. DPFX(DPFPREP, 5, "Socketport 0x%p (ID 0x%x) appears to be using proxy client (protocol %i = \"%hs\").",
  2363. this, m_dwSocketPortID, i, szProtocol);
  2364. m_fUsingProxyWinSockLSP = TRUE;
  2365. //
  2366. // Stop searching.
  2367. //
  2368. break;
  2369. }
  2370. DPFX(DPFPREP, 5, "Socketport 0x%p (ID 0x%x) protocol %i (\"%hs\") does not contain \"proxy\".",
  2371. this, m_dwSocketPortID, i, szProtocol);
  2372. #endif // ! UNICODE
  2373. } // end for (each returned protocol)
  2374. }
  2375. else
  2376. {
  2377. DPFX(DPFPREP, 1, "Couldn't enumerate UDP protocols for socketport 0x%p ID 0x%x, assuming not using proxy client (return = %i, size = %u).",
  2378. this, m_dwSocketPortID, iReturnValue, dwBufferSize);
  2379. }
  2380. if (pwsapi != NULL)
  2381. {
  2382. DNFree(pwsapi);
  2383. }
  2384. } // end else (Winsock 2)
  2385. }
  2386. #ifndef DPNBUILD_NOREGISTRY
  2387. else
  2388. {
  2389. DPFX(DPFPREP, 5, "Not auto-detecting whether socketport 0x%p (ID 0x%x) is using proxy client.",
  2390. this, m_dwSocketPortID);
  2391. }
  2392. #endif // ! DPNBUILD_NOREGISTRY
  2393. }
  2394. #endif // ! DPNBUILD_NOWINSOCK2
  2395. #endif // ! _XBOX
  2396. //
  2397. // start processing input messages
  2398. // It's possible that messages will arrive before an endpoint is officially
  2399. // bound to this socket port, but that's not a problem, the contents will
  2400. // be lost
  2401. //
  2402. hr = StartReceiving();
  2403. if ( hr != DPN_OK )
  2404. {
  2405. DPFX(DPFPREP, 0, "Problem starting endpoint receiving!" );
  2406. DisplayDNError( 0, hr );
  2407. goto Failure;
  2408. }
  2409. DNASSERT( m_State == SOCKET_PORT_STATE_BOUND );
  2410. Exit:
  2411. if ( hr != DPN_OK )
  2412. {
  2413. DPFX(DPFPREP, 0, "Problem in CSocketPort::BindToNetwork()" );
  2414. DisplayDNError( 0, hr );
  2415. }
  2416. if ( pBoundSocketAddress != NULL )
  2417. {
  2418. g_SocketAddressPool.Release( pBoundSocketAddress );
  2419. pBoundSocketAddress = NULL;
  2420. }
  2421. DPFX(DPFPREP, 7, "(0x%p) Returning [0x%lx]", this, hr );
  2422. return hr;
  2423. Failure:
  2424. DEBUG_ONLY( m_fInitialized = FALSE );
  2425. if ( m_State == SOCKET_PORT_STATE_BOUND )
  2426. {
  2427. UnbindFromNetwork();
  2428. m_State = SOCKET_PORT_STATE_INITIALIZED;
  2429. }
  2430. else
  2431. {
  2432. DNASSERT( m_State == SOCKET_PORT_STATE_INITIALIZED );
  2433. //
  2434. // If we were bound to network, m_Socket will be reset to
  2435. // INVALID_SOCKET.
  2436. // Otherwise, we will take care of this ourselves (!)
  2437. //
  2438. if ( m_Socket != INVALID_SOCKET )
  2439. {
  2440. DPFX(DPFPREP, 5, "Closing socketport 0x%p socket 0x%p.", this, m_Socket);
  2441. iReturnValue = closesocket( m_Socket );
  2442. if ( iReturnValue == SOCKET_ERROR )
  2443. {
  2444. dwErrorCode = WSAGetLastError();
  2445. DPFX(DPFPREP, 0, "Problem closing socket!" );
  2446. DisplayWinsockError( 0, dwErrorCode );
  2447. }
  2448. m_Socket = INVALID_SOCKET;
  2449. }
  2450. }
  2451. goto Exit;
  2452. }
  2453. //**********************************************************************
  2454. //**********************************************************************
  2455. // ------------------------------
  2456. // CSocketPort::UnbindFromNetwork - unbind this socket port from the network
  2457. //
  2458. // Entry: Nothing
  2459. //
  2460. // Exit: Error code
  2461. //
  2462. // Note: It is assumed that this socket port's information is locked!
  2463. // ------------------------------
  2464. #undef DPF_MODNAME
  2465. #define DPF_MODNAME "CSocketPort::UnbindFromNetwork"
  2466. HRESULT CSocketPort::UnbindFromNetwork( void )
  2467. {
  2468. INT iWSAReturn;
  2469. SOCKET TempSocket;
  2470. DWORD dwErrorCode;
  2471. #ifndef DPNBUILD_NONATHELP
  2472. DWORD dwTemp;
  2473. #endif // DPNBUILD_NONATHELP
  2474. DPFX(DPFPREP, 7, "(0x%p) Enter", this );
  2475. TempSocket = GetSocket();
  2476. m_Socket = INVALID_SOCKET;
  2477. DNASSERT( TempSocket != INVALID_SOCKET );
  2478. iWSAReturn = shutdown( TempSocket, 0 );
  2479. if ( iWSAReturn == SOCKET_ERROR )
  2480. {
  2481. dwErrorCode = WSAGetLastError();
  2482. DPFX(DPFPREP, 0, "Problem shutting down socket!" );
  2483. DisplayWinsockError( 0, dwErrorCode );
  2484. }
  2485. DPFX(DPFPREP, 5, "Closing socketport 0x%p socket 0x%p.", this, TempSocket);
  2486. iWSAReturn = closesocket( TempSocket );
  2487. if ( iWSAReturn == SOCKET_ERROR )
  2488. {
  2489. dwErrorCode = WSAGetLastError();
  2490. DPFX(DPFPREP, 0, "Problem closing socket!" );
  2491. DisplayWinsockError( 0, dwErrorCode );
  2492. }
  2493. #ifndef DPNBUILD_NONATHELP
  2494. //
  2495. // Unbind with all DirectPlayNATHelp instances.
  2496. //
  2497. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  2498. {
  2499. if ( m_ahNATHelpPorts[dwTemp] != NULL )
  2500. {
  2501. DNASSERT( m_pThreadPool != NULL );
  2502. DNASSERT( m_pThreadPool->IsNATHelpLoaded() );
  2503. //
  2504. // Ignore error.
  2505. //
  2506. IDirectPlayNATHelp_DeregisterPorts( g_papNATHelpObjects[dwTemp], m_ahNATHelpPorts[dwTemp], 0 );
  2507. m_ahNATHelpPorts[dwTemp] = NULL;
  2508. }
  2509. }
  2510. #endif // DPNBUILD_NONATHELP
  2511. #ifndef DPNBUILD_NOWINSOCK2
  2512. #ifndef DPNBUILD_ONLYWINSOCK2
  2513. if (
  2514. (GetWinsockVersion() == 2)
  2515. #ifndef DPNBUILD_NOIPX
  2516. && ( m_pNetworkSocketAddress->GetFamily() != AF_IPX )
  2517. #endif // ! DPNBUILD_NOIPX
  2518. )
  2519. #endif // ! DPNBUILD_ONLYWINSOCK2
  2520. {
  2521. HRESULT hr;
  2522. #ifdef DPNBUILD_ONLYONEPROCESSOR
  2523. hr = IDirectPlay8ThreadPoolWork_StopTrackingFileIo(m_pThreadPool->GetDPThreadPoolWork(),
  2524. 0,
  2525. (HANDLE) TempSocket,
  2526. 0);
  2527. #else // ! DPNBUILD_ONLYONEPROCESSOR
  2528. hr = IDirectPlay8ThreadPoolWork_StopTrackingFileIo(m_pThreadPool->GetDPThreadPoolWork(),
  2529. m_dwCPU,
  2530. (HANDLE) TempSocket,
  2531. 0);
  2532. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  2533. if (hr != DPN_OK)
  2534. {
  2535. DPFX(DPFPREP, 0, "Couldn't stop tracking socket 0x%p I/O (err = 0x%lx)! Ignoring.",
  2536. TempSocket, hr);
  2537. }
  2538. }
  2539. #endif // ! DPNBUILD_NOWINSOCK2
  2540. DPFX(DPFPREP, 7, "(0x%p) Returning [DPN_OK]", this );
  2541. return DPN_OK;
  2542. }
  2543. //**********************************************************************
  2544. //**********************************************************************
  2545. // ------------------------------
  2546. // CSocketPort::BindToNextAvailablePort - bind to next available port
  2547. //
  2548. // Entry: Pointer adapter address to bind to
  2549. // Base port to try assigning.
  2550. //
  2551. // Exit: Error code
  2552. // ------------------------------
  2553. #undef DPF_MODNAME
  2554. #define DPF_MODNAME "CSocketPort::BindToNextAvailablePort"
  2555. HRESULT CSocketPort::BindToNextAvailablePort( const CSocketAddress *const pNetworkAddress,
  2556. const WORD wBasePort) const
  2557. {
  2558. HRESULT hr;
  2559. INT iSocketReturn;
  2560. CSocketAddress * pDuplicateNetworkAddress;
  2561. #ifdef _XBOX
  2562. SOCKADDR_IN * psaddrin;
  2563. #endif // _XBOX
  2564. DNASSERT( pNetworkAddress != NULL );
  2565. //
  2566. // initialize
  2567. //
  2568. hr = DPN_OK;
  2569. pDuplicateNetworkAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) pNetworkAddress->GetFamily()));
  2570. if ( pDuplicateNetworkAddress == NULL )
  2571. {
  2572. hr = DPNERR_OUTOFMEMORY;
  2573. DPFX(DPFPREP, 0, "Failed to get address for walking DPlay port range!" );
  2574. goto Failure;
  2575. }
  2576. pDuplicateNetworkAddress->CopyAddressSettings( pNetworkAddress );
  2577. #ifdef _XBOX
  2578. //
  2579. // Xbox doesn't want you to bind to anything other than INADDR_ANY
  2580. // so in case we discovered our IP address, force it 0.0.0.0 at bind time.
  2581. //
  2582. psaddrin = (SOCKADDR_IN*) pDuplicateNetworkAddress->GetWritableAddress();
  2583. DNASSERT(psaddrin->sin_family == AF_INET);
  2584. psaddrin->sin_addr.S_un.S_addr = INADDR_ANY;
  2585. #endif // _XBOX
  2586. //
  2587. // If a port was specified, try to bind to that port. If no port was
  2588. // specified, start walking the reserved DPlay port range looking for an
  2589. // available port. If none is found, let Winsock choose the port.
  2590. //
  2591. if ( pNetworkAddress->GetPort() != ANY_PORT )
  2592. {
  2593. iSocketReturn = bind( GetSocket(),
  2594. pDuplicateNetworkAddress->GetAddress(),
  2595. pDuplicateNetworkAddress->GetAddressSize()
  2596. );
  2597. if ( iSocketReturn == SOCKET_ERROR )
  2598. {
  2599. DWORD dwErrorCode;
  2600. hr = DPNERR_ALREADYINITIALIZED;
  2601. dwErrorCode = WSAGetLastError();
  2602. DPFX(DPFPREP, 0, "Failed to bind socket to fixed port!" );
  2603. DumpSocketAddress(0, pDuplicateNetworkAddress->GetAddress(), pDuplicateNetworkAddress->GetFamily() );
  2604. DisplayWinsockError( 0, dwErrorCode );
  2605. goto Failure;
  2606. }
  2607. }
  2608. else
  2609. {
  2610. WORD wPort;
  2611. BOOL fBound;
  2612. wPort = wBasePort;
  2613. fBound = FALSE;
  2614. //
  2615. // Try picking the next port in the DPlay range.
  2616. //
  2617. #ifdef DPNBUILD_NOREGISTRY
  2618. while ( ( wPort >= BASE_DPLAY8_PORT ) && ( wPort <= MAX_DPLAY8_PORT ) && ( fBound == FALSE ) )
  2619. #else // ! DPNBUILD_NOREGISTRY
  2620. while ( ( wPort >= g_wBaseDPlayPort ) && ( wPort <= g_wMaxDPlayPort ) && ( fBound == FALSE ) )
  2621. #endif // ! DPNBUILD_NOREGISTRY
  2622. {
  2623. pDuplicateNetworkAddress->SetPort( HTONS( wPort ) );
  2624. iSocketReturn = bind( GetSocket(),
  2625. pDuplicateNetworkAddress->GetAddress(),
  2626. pDuplicateNetworkAddress->GetAddressSize()
  2627. );
  2628. if ( iSocketReturn == SOCKET_ERROR )
  2629. {
  2630. DWORD dwErrorCode;
  2631. dwErrorCode = WSAGetLastError();
  2632. switch ( dwErrorCode )
  2633. {
  2634. case WSAEADDRINUSE:
  2635. {
  2636. DPFX(DPFPREP, 8, "Port %u in use, skipping to next port.", wPort );
  2637. break;
  2638. }
  2639. default:
  2640. {
  2641. hr = DPNERR_NOCONNECTION;
  2642. DPFX(DPFPREP, 0, "Failed to bind socket to port in DPlay range!" );
  2643. DumpSocketAddress(0, pDuplicateNetworkAddress->GetAddress(), pDuplicateNetworkAddress->GetFamily() );
  2644. DisplayWinsockError( 0, dwErrorCode );
  2645. goto Failure;
  2646. break;
  2647. }
  2648. }
  2649. }
  2650. else
  2651. {
  2652. DNASSERT( hr == DPN_OK );
  2653. fBound = TRUE;
  2654. }
  2655. wPort++;
  2656. }
  2657. //
  2658. // For some reason, all of the default DPlay ports were in use, let
  2659. // Winsock choose. We can use the network address passed because it
  2660. // has 'ANY_PORT'.
  2661. //
  2662. if ( fBound == FALSE )
  2663. {
  2664. DNASSERT( pNetworkAddress->GetPort() == ANY_PORT );
  2665. iSocketReturn = bind( GetSocket(),
  2666. pNetworkAddress->GetAddress(),
  2667. pNetworkAddress->GetAddressSize()
  2668. );
  2669. if ( iSocketReturn == SOCKET_ERROR )
  2670. {
  2671. DWORD dwErrorCode;
  2672. hr = DPNERR_NOCONNECTION;
  2673. dwErrorCode = WSAGetLastError();
  2674. DPFX(DPFPREP, 0, "Failed to bind socket (any port)!" );
  2675. DumpSocketAddress(0, pNetworkAddress->GetAddress(), pNetworkAddress->GetFamily() );
  2676. DisplayWinsockError( 0, dwErrorCode );
  2677. goto Failure;
  2678. }
  2679. }
  2680. }
  2681. Exit:
  2682. if ( pDuplicateNetworkAddress != NULL )
  2683. {
  2684. g_SocketAddressPool.Release( pDuplicateNetworkAddress );
  2685. pDuplicateNetworkAddress = NULL;
  2686. }
  2687. return hr;
  2688. Failure:
  2689. goto Exit;
  2690. }
  2691. //**********************************************************************
  2692. #ifndef DPNBUILD_NONATHELP
  2693. #ifndef DPNBUILD_NOLOCALNAT
  2694. //**********************************************************************
  2695. // ------------------------------
  2696. // CSocketPort::CheckForOverridingMapping - looks for an existing mapping if there's a local NAT
  2697. //
  2698. // Entry: Pointer to SocketAddress to query
  2699. //
  2700. // Exit: Error code
  2701. // ------------------------------
  2702. #undef DPF_MODNAME
  2703. #define DPF_MODNAME "CSocketPort::CheckForOverridingMapping"
  2704. HRESULT CSocketPort::CheckForOverridingMapping( const CSocketAddress *const pBoundSocketAddress )
  2705. {
  2706. HRESULT hr;
  2707. DWORD dwTemp;
  2708. SOCKADDR saddrSource;
  2709. SOCKADDR saddrPublic;
  2710. DNASSERT( pBoundSocketAddress != NULL );
  2711. DNASSERT( GetAdapterEntry() != NULL );
  2712. DNASSERT( m_pThreadPool != NULL );
  2713. if ((pBoundSocketAddress->GetFamily() != AF_INET) ||
  2714. ( ! m_pThreadPool->IsNATHelpLoaded() ) ||
  2715. ( GetUserTraversalMode() == DPNA_TRAVERSALMODE_NONE ))
  2716. {
  2717. //
  2718. // We skipped initializing NAT Help, it failed starting up, or this is just
  2719. // not an IP socket.
  2720. //
  2721. hr = DPNERR_UNSUPPORTED;
  2722. goto Exit;
  2723. }
  2724. //
  2725. // Query using INADDR_ANY. This will ensure that the best device is picked
  2726. // (i.e. the private interface on a NAT, whose public mappings matter when
  2727. // we're looking for overriding mappings on the public adapter).
  2728. // Alternatively, we could query on every device, but this should do the trick.
  2729. //
  2730. ZeroMemory(&saddrSource, sizeof(saddrSource));
  2731. saddrSource.sa_family = AF_INET;
  2732. //saddrinSource.sin_addr.S_un.S_addr = INADDR_ANY;
  2733. //saddrinSource.sin_port = 0;
  2734. //
  2735. // Query all DirectPlayNATHelp instances for the port. We might break
  2736. // out of the loop if we detect a gateway mapping.
  2737. //
  2738. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  2739. {
  2740. DNASSERT(m_ahNATHelpPorts[dwTemp] == NULL);
  2741. if ( g_papNATHelpObjects[dwTemp] != NULL )
  2742. {
  2743. hr = IDirectPlayNATHelp_QueryAddress( g_papNATHelpObjects[dwTemp],
  2744. &saddrSource,
  2745. pBoundSocketAddress->GetAddress(),
  2746. &saddrPublic,
  2747. sizeof (saddrPublic),
  2748. 0 );
  2749. switch ( hr )
  2750. {
  2751. case DPNH_OK:
  2752. {
  2753. //
  2754. // Uh oh, this address is in use.
  2755. //
  2756. DPFX(DPFPREP, 0, "Private address already in use according to NAT Help object %u!", dwTemp );
  2757. DumpSocketAddress( 0, pBoundSocketAddress->GetAddress(), pBoundSocketAddress->GetFamily() );
  2758. DumpSocketAddress( 0, &saddrPublic, pBoundSocketAddress->GetFamily() );
  2759. hr = DPNERR_ALREADYINITIALIZED;
  2760. goto Exit;
  2761. break;
  2762. }
  2763. case DPNHERR_NOMAPPING:
  2764. {
  2765. //
  2766. // It's not in use.
  2767. //
  2768. DPFX(DPFPREP, 8, "Private address not in use according to NAT Help object %u.", dwTemp );
  2769. break;
  2770. }
  2771. case DPNHERR_SERVERNOTAVAILABLE:
  2772. {
  2773. //
  2774. // There's no server.
  2775. //
  2776. DPFX(DPFPREP, 8, "Private address not in use because NAT Help object %u didn't detect any servers.",
  2777. dwTemp );
  2778. break;
  2779. }
  2780. default:
  2781. {
  2782. //
  2783. // Something else. Assume it's not in use.
  2784. //
  2785. DPFX(DPFPREP, 1, "NAT Help object %u failed private address lookup (err = 0x%lx), assuming not in use.",
  2786. dwTemp, hr );
  2787. break;
  2788. }
  2789. }
  2790. }
  2791. else
  2792. {
  2793. //
  2794. // No NAT Help object.
  2795. //
  2796. }
  2797. }
  2798. //
  2799. // If we're here, no Internet gateways reported the port as in use.
  2800. //
  2801. DPFX(DPFPREP, 2, "No NAT Help object reported private address as in use." );
  2802. hr = DPN_OK;
  2803. Exit:
  2804. return hr;
  2805. }
  2806. //**********************************************************************
  2807. #endif // ! DPNBUILD_NOLOCALNAT
  2808. //**********************************************************************
  2809. // ------------------------------
  2810. // CSocketPort::BindToInternetGateway - binds a socket to a NAT, if available
  2811. //
  2812. // Entry: Pointer to SocketAddress we bound to
  2813. // Gateway bind type
  2814. //
  2815. // Exit: Error code
  2816. // ------------------------------
  2817. #undef DPF_MODNAME
  2818. #define DPF_MODNAME "CSocketPort::BindToInternetGateway"
  2819. HRESULT CSocketPort::BindToInternetGateway( const CSocketAddress *const pBoundSocketAddress,
  2820. const GATEWAY_BIND_TYPE GatewayBindType )
  2821. {
  2822. HRESULT hr;
  2823. DWORD dwTemp;
  2824. DWORD dwRegisterFlags;
  2825. DWORD dwAddressTypeFlags;
  2826. BOOL fUnavailable;
  2827. #ifdef DBG
  2828. BOOL fFirewallMapping;
  2829. #endif // DBG
  2830. DNASSERT( pBoundSocketAddress != NULL );
  2831. DNASSERT( GetAdapterEntry() != NULL );
  2832. DNASSERT( m_pThreadPool != NULL );
  2833. if (
  2834. #if ((! defined(DPNBUILD_NOIPX)) || (! defined(DPNBUILD_NOIPV6)))
  2835. (pBoundSocketAddress->GetFamily() != AF_INET) ||
  2836. #endif // ! DPNBUILD_NOIPX or ! DPNBUILD_NOIPV6
  2837. ( ! m_pThreadPool->IsNATHelpLoaded() ) ||
  2838. ( GetUserTraversalMode() == DPNA_TRAVERSALMODE_NONE ) )
  2839. {
  2840. //
  2841. // We skipped initializing NAT Help, it failed starting up, or this is just
  2842. // not an IP socket.
  2843. //
  2844. DPFX(DPFPREP, 5, "Not using NAT traversal, socket family = %u, NAT Help loaded = %i, traversal mode = %u.",
  2845. pBoundSocketAddress->GetFamily(), m_pThreadPool->IsNATHelpLoaded(), GetUserTraversalMode());
  2846. hr = DPNERR_UNSUPPORTED;
  2847. goto Exit;
  2848. }
  2849. DNASSERT(m_pThreadPool->IsNATHelpLoaded());
  2850. switch ( GatewayBindType )
  2851. {
  2852. //
  2853. // just ask the server to open a generic port for us (connect, listen, enum)
  2854. //
  2855. case GATEWAY_BIND_TYPE_DEFAULT:
  2856. {
  2857. dwRegisterFlags = 0;
  2858. break;
  2859. }
  2860. //
  2861. // ask the NAT to open a fixed port for us (address is specified)
  2862. //
  2863. case GATEWAY_BIND_TYPE_SPECIFIC:
  2864. {
  2865. dwRegisterFlags = DPNHREGISTERPORTS_FIXEDPORTS;
  2866. break;
  2867. }
  2868. //
  2869. // ask the NAT to share the listen for us (this should be DPNSVR only)
  2870. //
  2871. case GATEWAY_BIND_TYPE_SPECIFIC_SHARED:
  2872. {
  2873. dwRegisterFlags = DPNHREGISTERPORTS_FIXEDPORTS | DPNHREGISTERPORTS_SHAREDPORTS;
  2874. break;
  2875. }
  2876. //
  2877. // no binding
  2878. //
  2879. case GATEWAY_BIND_TYPE_NONE:
  2880. {
  2881. DPFX(DPFPREP, 8, "Not binding socket address 0x%p to NAT because bind type is NONE.",
  2882. pBoundSocketAddress);
  2883. hr = DPNERR_UNSUPPORTED;
  2884. goto Exit;
  2885. break;
  2886. }
  2887. //
  2888. // unknown condition, someone broke the code!
  2889. //
  2890. default:
  2891. {
  2892. DNASSERT( FALSE );
  2893. hr = DPNERR_GENERIC;
  2894. goto Failure;
  2895. break;
  2896. }
  2897. }
  2898. RetryMapping:
  2899. //
  2900. // Detect whether any servers said the port was unavailable.
  2901. //
  2902. fUnavailable = FALSE;
  2903. #ifdef DBG
  2904. fFirewallMapping = FALSE;
  2905. #endif // DBG
  2906. //
  2907. // Register the ports with all DirectPlayNATHelp instances. We might break
  2908. // out of the loop if we detect a gateway mapping.
  2909. //
  2910. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  2911. {
  2912. DNASSERT(m_ahNATHelpPorts[dwTemp] == NULL);
  2913. if ( g_papNATHelpObjects[dwTemp] != NULL )
  2914. {
  2915. hr = IDirectPlayNATHelp_RegisterPorts( g_papNATHelpObjects[dwTemp],
  2916. pBoundSocketAddress->GetAddress(),
  2917. sizeof (SOCKADDR),
  2918. 1,
  2919. NAT_LEASE_TIME,
  2920. &m_ahNATHelpPorts[dwTemp],
  2921. dwRegisterFlags );
  2922. if ( hr != DPNH_OK )
  2923. {
  2924. DNASSERT(m_ahNATHelpPorts[dwTemp] == NULL);
  2925. DPFX(DPFPREP, 0, "Failed to register port with NAT Help object %u! Ignoring.", dwTemp );
  2926. DumpSocketAddress( 0, pBoundSocketAddress->GetAddress(), pBoundSocketAddress->GetFamily() );
  2927. DisplayDNError( 0, hr );
  2928. hr = DPN_OK;
  2929. }
  2930. else
  2931. {
  2932. //
  2933. // There might be an Internet gateway device already present. If so,
  2934. // then DPNATHelp already tried to register the port mapping with it, which
  2935. // might have failed because the port is already in use. If we're not
  2936. // binding to a fixed port, then we could just pick a different port and try
  2937. // again. So check if there's a UPnP device but DPNATHelp couldn't map
  2938. // the port and return that error to the caller so he can make the
  2939. // decision to retry or not.
  2940. //
  2941. // IDirectPlayNATHelp::GetCaps had better have been called with the
  2942. // DPNHGETCAPS_UPDATESERVERSTATUS flag at least once prior to this.
  2943. // See CThreadPool::EnsureNATHelpLoaded
  2944. //
  2945. hr = IDirectPlayNATHelp_GetRegisteredAddresses( g_papNATHelpObjects[dwTemp], // object
  2946. m_ahNATHelpPorts[dwTemp], // port binding
  2947. NULL, // don't need address
  2948. NULL, // don't need address buffer size
  2949. &dwAddressTypeFlags, // get address type flags
  2950. NULL, // don't need lease time remaining
  2951. 0 ); // no flags
  2952. switch (hr)
  2953. {
  2954. case DPNH_OK:
  2955. {
  2956. //
  2957. // If this is a mapping on a gateway, then we're done.
  2958. // We don't need to try to make any more NAT mappings.
  2959. //
  2960. if (dwAddressTypeFlags & DPNHADDRESSTYPE_GATEWAY)
  2961. {
  2962. DPFX(DPFPREP, 4, "Address has already successfully been registered with gateway using object index %u (type flags = 0x%lx), not trying additional mappings.",
  2963. dwTemp, dwAddressTypeFlags);
  2964. goto Exit;
  2965. }
  2966. DNASSERT(dwAddressTypeFlags & DPNHADDRESSTYPE_LOCALFIREWALL);
  2967. DPFX(DPFPREP, 4, "Address has already successfully been registered with firewall using object index %u (type flags = 0x%lx), looking for gateways.",
  2968. dwTemp, dwAddressTypeFlags);
  2969. #ifdef DBG
  2970. fFirewallMapping = TRUE;
  2971. #endif // DBG
  2972. break;
  2973. }
  2974. case DPNHERR_NOMAPPING:
  2975. {
  2976. DPFX(DPFPREP, 4, "Address already registered with Internet gateway index %u, but it does not have a public address (type flags = 0x%lx).",
  2977. dwTemp, dwAddressTypeFlags);
  2978. //
  2979. // It doesn't make any sense for a firewall not to have a
  2980. // mapping.
  2981. //
  2982. DNASSERT(dwAddressTypeFlags & DPNHADDRESSTYPE_GATEWAY);
  2983. DNASSERT(! (dwAddressTypeFlags & DPNHADDRESSTYPE_LOCALFIREWALL));
  2984. //
  2985. // Since it is a gateway (that might have a public address
  2986. // at some point, we don't need to try to make any more
  2987. // NAT mappings.
  2988. //
  2989. goto Exit;
  2990. break;
  2991. }
  2992. case DPNHERR_PORTUNAVAILABLE:
  2993. {
  2994. DPFX(DPFPREP, 1, "Port is unavailable on Internet gateway device index %u (type flags = 0x%lx).",
  2995. dwTemp, dwAddressTypeFlags);
  2996. fUnavailable = TRUE;
  2997. break;
  2998. }
  2999. case DPNHERR_SERVERNOTAVAILABLE:
  3000. {
  3001. DPFX(DPFPREP, 6, "No Internet gateway detected by object index %u at this time.", dwTemp);
  3002. break;
  3003. }
  3004. default:
  3005. {
  3006. DPFX(DPFPREP, 1, "An error (0x%lx) occurred while getting registered address mapping (index %u)! Ignoring.",
  3007. hr, dwTemp);
  3008. break;
  3009. }
  3010. }
  3011. }
  3012. }
  3013. else
  3014. {
  3015. //
  3016. // No NAT Help object.
  3017. //
  3018. }
  3019. }
  3020. //
  3021. // If we're here, no Internet gateways were detected, or if one was, the
  3022. // mapping was already in use there. If it's the latter, fail so our caller
  3023. // can unbind locally and possibly try again. Note that we are ignoring
  3024. // firewall mappings, since it's assumed we can make those with pretty
  3025. // much any port, so there's no point in hanging on to those mappings
  3026. // if the NAT port is in use.
  3027. //
  3028. if (fUnavailable)
  3029. {
  3030. //
  3031. // If the user wanted to try the fixed port first, but could handle
  3032. // using a different port if the fixed port was in use, try again
  3033. // without the FIXEDPORTS flag.
  3034. //
  3035. if ((dwRegisterFlags & DPNHREGISTERPORTS_FIXEDPORTS) &&
  3036. (GetUserTraversalMode() == DPNA_TRAVERSALMODE_PORTRECOMMENDED))
  3037. {
  3038. DPFX(DPFPREP, 1, "At least one Internet gateway reported port as unavailable, trying a different port.");
  3039. dwRegisterFlags &= ~DPNHREGISTERPORTS_FIXEDPORTS;
  3040. goto RetryMapping;
  3041. }
  3042. DPFX(DPFPREP, 2, "At least one Internet gateway reported port as unavailable, failing.");
  3043. hr = DPNERR_ALREADYINITIALIZED;
  3044. }
  3045. else
  3046. {
  3047. #ifdef DBG
  3048. if (fFirewallMapping)
  3049. {
  3050. DPFX(DPFPREP, 2, "No gateway mappings but there is at least one firewall mapping.");
  3051. }
  3052. else
  3053. {
  3054. DPFX(DPFPREP, 2, "No gateway or firewall mappings detected.");
  3055. }
  3056. #endif // DBG
  3057. hr = DPN_OK;
  3058. }
  3059. Exit:
  3060. return hr;
  3061. Failure:
  3062. goto Exit;
  3063. }
  3064. //**********************************************************************
  3065. #endif // ! DPNBUILD_NONATHELP
  3066. //**********************************************************************
  3067. // ------------------------------
  3068. // CSocketPort::StartReceiving - start receiving data on this socket port
  3069. //
  3070. // Entry: Handle of I/O completion port to bind to (NT old threadpool only)
  3071. //
  3072. // Exit: Error code
  3073. //
  3074. // Notes: There is no 'Failure' label in this function because failures need
  3075. // to be cleaned up for each OS variant.
  3076. // ------------------------------
  3077. #undef DPF_MODNAME
  3078. #define DPF_MODNAME "CSocketPort::StartReceiving"
  3079. HRESULT CSocketPort::StartReceiving( void )
  3080. {
  3081. HRESULT hr;
  3082. #ifndef DPNBUILD_NOWINSOCK2
  3083. DWORD dwNumReceivesStarted = 0;
  3084. DWORD dwStartCPU;
  3085. DWORD dwEndCPU;
  3086. DWORD dwCPU;
  3087. #ifndef DPNBUILD_ONLYONETHREAD
  3088. DWORD dwReceiveNum;
  3089. DWORD dwThreadCount;
  3090. #endif // ! DPNBUILD_ONLYONETHREAD
  3091. #ifndef DPNBUILD_ONLYONEPROCESSOR
  3092. SYSTEM_INFO SystemInfo;
  3093. GetSystemInfo(&SystemInfo);
  3094. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  3095. #endif // ! DPNBUILD_NOWINSOCK2
  3096. //
  3097. // On Win9x, if this is an IPX socket and Winsock 2 is not available,
  3098. // use the Winsock 1 non-overlapped I/O routines.
  3099. //
  3100. // CE without Winsock 2 has the same limitation.
  3101. //
  3102. // On NT, we can always use overlapped I/O.
  3103. //
  3104. #ifndef DPNBUILD_ONLYWINSOCK2
  3105. #ifndef DPNBUILD_NOWINSOCK2
  3106. if ( ( LOWORD( GetWinsockVersion() ) < 2 )
  3107. #ifndef DPNBUILD_NOIPX
  3108. || ( m_pNetworkSocketAddress->GetFamily() == AF_IPX )
  3109. #endif // ! DPNBUILD_NOIPX
  3110. )
  3111. #endif // ! DPNBUILD_NOWINSOCK2
  3112. {
  3113. hr = m_pThreadPool->AddSocketPort( this );
  3114. if ( hr != DPN_OK )
  3115. {
  3116. DPFX(DPFPREP, 0, "Failed to add to active socket list!" );
  3117. DisplayDNError( 0, hr );
  3118. goto Failure;
  3119. }
  3120. }
  3121. #ifndef DPNBUILD_NOWINSOCK2
  3122. else
  3123. #endif // ! DPNBUILD_NOWINSOCK2
  3124. #endif // ! DPNBUILD_ONLYWINSOCK2
  3125. #ifndef DPNBUILD_NOWINSOCK2
  3126. {
  3127. #ifdef DPNBUILD_ONLYONEPROCESSOR
  3128. dwStartCPU = 0;
  3129. dwEndCPU = 1;
  3130. #else // ! DPNBUILD_ONLYONEPROCESSOR
  3131. if (m_dwCPU == -1)
  3132. {
  3133. dwStartCPU = 0;
  3134. dwEndCPU = SystemInfo.dwNumberOfProcessors;
  3135. }
  3136. else
  3137. {
  3138. dwStartCPU = m_dwCPU;
  3139. dwEndCPU = dwStartCPU + 1;
  3140. }
  3141. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  3142. for(dwCPU = dwStartCPU; dwCPU < dwEndCPU; dwCPU++)
  3143. {
  3144. hr = IDirectPlay8ThreadPoolWork_StartTrackingFileIo(m_pThreadPool->GetDPThreadPoolWork(),
  3145. dwCPU,
  3146. (HANDLE) GetSocket(),
  3147. 0);
  3148. if (hr != DPN_OK)
  3149. {
  3150. DPFX(DPFPREP, 0, "Couldn't start tracking file I/O on CPU %u! Ignoring.", dwCPU);
  3151. DisplayDNError(0, hr);
  3152. }
  3153. else
  3154. {
  3155. #ifndef DPNBUILD_ONLYONETHREAD
  3156. DNASSERT(! m_pThreadPool->IsThreadCountReductionAllowed());
  3157. hr = IDirectPlay8ThreadPoolWork_GetThreadCount(m_pThreadPool->GetDPThreadPoolWork(),
  3158. dwCPU,
  3159. &dwThreadCount,
  3160. 0);
  3161. DNASSERT((hr == DPN_OK) || (hr == DPNSUCCESS_PENDING));
  3162. //
  3163. // Always start at least one receive, even in DoWork mode.
  3164. //
  3165. if (dwThreadCount == 0)
  3166. {
  3167. dwThreadCount++;
  3168. }
  3169. for(dwReceiveNum = 0; dwReceiveNum < dwThreadCount; dwReceiveNum++)
  3170. #endif // ! DPNBUILD_ONLYONETHREAD
  3171. {
  3172. #ifdef DPNBUILD_ONLYONEPROCESSOR
  3173. hr = Winsock2Receive();
  3174. #else // ! DPNBUILD_ONLYONEPROCESSOR
  3175. hr = Winsock2Receive(dwCPU);
  3176. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  3177. if (hr != DPN_OK)
  3178. {
  3179. DPFX(DPFPREP, 0, "Couldn't submit receive on CPU %u! Ignoring.", dwCPU);
  3180. DisplayDNError(0, hr);
  3181. break;
  3182. }
  3183. dwNumReceivesStarted++;
  3184. }
  3185. }
  3186. }
  3187. if (dwNumReceivesStarted == 0)
  3188. {
  3189. DPFX(DPFPREP, 0, "Didn't start any receives!");
  3190. hr = DPNERR_OUTOFMEMORY;
  3191. }
  3192. else
  3193. {
  3194. DPFX(DPFPREP, 5, "Started %u receives.", dwNumReceivesStarted);
  3195. hr = DPN_OK;
  3196. }
  3197. }
  3198. #endif // ! DPNBUILD_NOWINSOCK2
  3199. #ifdef DPNBUILD_ONLYWINSOCK2
  3200. return hr;
  3201. #else // ! DPNBUILD_ONLYWINSOCK2
  3202. Exit:
  3203. return hr;
  3204. Failure:
  3205. goto Exit;
  3206. #endif // ! DPNBUILD_ONLYWINSOCK2
  3207. }
  3208. //**********************************************************************
  3209. //**********************************************************************
  3210. // ------------------------------
  3211. // CSocketPort::GetBoundNetworkAddress - get the full network address that
  3212. // this socket port was really bound to
  3213. //
  3214. // Entry: Address type for bound address
  3215. //
  3216. // Exit: Pointer to network address
  3217. //
  3218. // Note: Since this function creates a local address to derive the network
  3219. // address from, it needs to know what kind of address to derive. This
  3220. // address type is supplied as the function parameter.
  3221. // ------------------------------
  3222. #undef DPF_MODNAME
  3223. #define DPF_MODNAME "CSocketPort::GetBoundNetworkAddress"
  3224. CSocketAddress *CSocketPort::GetBoundNetworkAddress( const SP_ADDRESS_TYPE AddressType ) const
  3225. {
  3226. CSocketAddress *pTempSocketAddress;
  3227. #ifdef DPNBUILD_NOIPV6
  3228. SOCKADDR BoundSocketAddress;
  3229. #else // ! DPNBUILD_NOIPV6
  3230. SOCKADDR_STORAGE BoundSocketAddress;
  3231. #endif // ! DPNBUILD_NOIPV6
  3232. INT_PTR iReturnValue;
  3233. INT iBoundSocketAddressSize;
  3234. #ifdef _XBOX
  3235. SOCKADDR_IN * psaddrinOriginal;
  3236. SOCKADDR_IN * psaddrinTemp;
  3237. #endif // _XBOX
  3238. //
  3239. // initialize
  3240. //
  3241. pTempSocketAddress = NULL;
  3242. //
  3243. // create addresses
  3244. //
  3245. pTempSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) m_pNetworkSocketAddress->GetFamily()));
  3246. if ( pTempSocketAddress == NULL )
  3247. {
  3248. DPFX(DPFPREP, 0, "GetBoundNetworkAddress: Failed to create socket address!" );
  3249. goto Failure;
  3250. }
  3251. //
  3252. // find out what address we really bound to and reset the information for
  3253. // this socket port
  3254. //
  3255. iBoundSocketAddressSize = pTempSocketAddress->GetAddressSize();
  3256. DNASSERT(iBoundSocketAddressSize <= sizeof(BoundSocketAddress));
  3257. iReturnValue = getsockname( GetSocket(), (SOCKADDR*) (&BoundSocketAddress), &iBoundSocketAddressSize );
  3258. if ( iReturnValue == SOCKET_ERROR )
  3259. {
  3260. DWORD dwErrorCode;
  3261. dwErrorCode = WSAGetLastError();
  3262. DPFX(DPFPREP, 0, "GetBoundNetworkAddress: Failed to get local socket name after bind!" );
  3263. DisplayWinsockError( 0, dwErrorCode );
  3264. goto Failure;
  3265. }
  3266. pTempSocketAddress->SetAddressFromSOCKADDR( (SOCKADDR*) (&BoundSocketAddress), iBoundSocketAddressSize );
  3267. DNASSERT( iBoundSocketAddressSize == pTempSocketAddress->GetAddressSize() );
  3268. #ifdef _XBOX
  3269. //
  3270. // On Xbox, we'll always be told we bound to 0.0.0.0, even though we might
  3271. // have determined the real IP address. Mash the original IP back in.
  3272. //
  3273. psaddrinOriginal = (SOCKADDR_IN*) m_pNetworkSocketAddress->GetWritableAddress();
  3274. psaddrinTemp = (SOCKADDR_IN*) pTempSocketAddress->GetWritableAddress();
  3275. psaddrinTemp->sin_addr.S_un.S_addr = psaddrinOriginal->sin_addr.S_un.S_addr;
  3276. #endif // _XBOX
  3277. //
  3278. // Since this address was created locally, we need to tell it what type of
  3279. // address to export according to the input.
  3280. //
  3281. switch ( AddressType )
  3282. {
  3283. //
  3284. // known types
  3285. //
  3286. case SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT:
  3287. case SP_ADDRESS_TYPE_DEVICE:
  3288. case SP_ADDRESS_TYPE_HOST:
  3289. case SP_ADDRESS_TYPE_READ_HOST:
  3290. #ifndef DPNBUILD_NOMULTICAST
  3291. case SP_ADDRESS_TYPE_MULTICAST_GROUP:
  3292. #endif // ! DPNBUILD_NOMULTICAST
  3293. {
  3294. break;
  3295. }
  3296. //
  3297. // if we're looking for a public address, we need to make sure that this
  3298. // is not an undefined address. If it is, don't return an address.
  3299. // Otherwise, remap the address type to a 'host' address.
  3300. //
  3301. case SP_ADDRESS_TYPE_PUBLIC_HOST_ADDRESS:
  3302. {
  3303. if ( pTempSocketAddress->IsUndefinedHostAddress() != FALSE )
  3304. {
  3305. g_SocketAddressPool.Release( pTempSocketAddress );
  3306. pTempSocketAddress = NULL;
  3307. }
  3308. break;
  3309. }
  3310. //
  3311. // unknown address type, fix the code!
  3312. //
  3313. default:
  3314. {
  3315. DNASSERT( FALSE );
  3316. break;
  3317. }
  3318. }
  3319. Exit:
  3320. return pTempSocketAddress;
  3321. Failure:
  3322. if ( pTempSocketAddress != NULL )
  3323. {
  3324. g_SocketAddressPool.Release( pTempSocketAddress );
  3325. pTempSocketAddress = NULL;
  3326. }
  3327. goto Exit;
  3328. }
  3329. //**********************************************************************
  3330. //**********************************************************************
  3331. // ------------------------------
  3332. // CSocketPort::GetDP8BoundNetworkAddress - get the network address this machine
  3333. // is bound to according to the input parameter. If the requested address
  3334. // for the public address and an Internet gateway are available, use the
  3335. // public address. If a public address is requested but is unavailable,
  3336. // fall back to the bound network address for local host-style device
  3337. // addresses. If a public address is unavailable but we're explicitly
  3338. // looking for a public address, return NULL.
  3339. //
  3340. // Entry: Type of address to get (local adapter vs. host)
  3341. //
  3342. // Exit: Pointer to network address
  3343. // ------------------------------
  3344. #undef DPF_MODNAME
  3345. #define DPF_MODNAME "CSocketPort::GetDP8BoundNetworkAddress"
  3346. IDirectPlay8Address *CSocketPort::GetDP8BoundNetworkAddress( const SP_ADDRESS_TYPE AddressType,
  3347. #ifdef DPNBUILD_XNETSECURITY
  3348. ULONGLONG * const pullKeyID,
  3349. #endif // DPNBUILD_XNETSECURITY
  3350. const GATEWAY_BIND_TYPE GatewayBindType ) const
  3351. {
  3352. #if ((! defined(DPNBUILD_ONLYONEADAPTER)) || (! defined(DPNBUILD_ONLYONEPROCESSOR)) || (! defined(DPNBUILD_NONATHELP)))
  3353. HRESULT hr;
  3354. #endif // ! DPNBUILD_ONLYONEADAPTER or ! DPNBUILD_ONLYONEPROCESSOR or ! DPNBUILD_NONATHELP
  3355. IDirectPlay8Address * pAddress;
  3356. CSocketAddress * pTempAddress = NULL;
  3357. #if ((defined(DBG)) || (defined(DPNBUILD_XNETSECURITY)))
  3358. SOCKADDR_IN * psaddrin;
  3359. #endif // DBG or DPNBUILD_XNETSECURITY
  3360. #if ((defined(DBG)) && (! defined(DPNBUILD_NONATHELP)))
  3361. DWORD dwAddressTypeFlags;
  3362. #endif // DBG and ! DPNBUILD_NONATHELP
  3363. #ifndef DPNBUILD_NONATHELP
  3364. SOCKADDR saddr;
  3365. DWORD dwAddressSize;
  3366. DWORD dwTemp;
  3367. #endif // DPNBUILD_NONATHELP
  3368. DPFX(DPFPREP, 8, "(0x%p) Parameters: (0x%i)", this, AddressType );
  3369. //
  3370. // initialize
  3371. //
  3372. pAddress = NULL;
  3373. DNASSERT( m_pThreadPool != NULL );
  3374. DNASSERT( m_pNetworkSocketAddress != NULL );
  3375. #ifdef DBG
  3376. switch ( m_pNetworkSocketAddress->GetFamily() )
  3377. {
  3378. case AF_INET:
  3379. {
  3380. psaddrin = (SOCKADDR_IN *) m_pNetworkSocketAddress->GetAddress();
  3381. #ifndef DPNBUILD_ONLYONEADAPTER
  3382. DNASSERT( psaddrin->sin_addr.S_un.S_addr != 0 );
  3383. #endif // ! DPNBUILD_ONLYONEADAPTER
  3384. DNASSERT( psaddrin->sin_addr.S_un.S_addr != INADDR_BROADCAST );
  3385. DNASSERT( psaddrin->sin_port != 0 );
  3386. break;
  3387. }
  3388. #ifndef DPNBUILD_NOIPX
  3389. case AF_IPX:
  3390. {
  3391. break;
  3392. }
  3393. #endif // ! DPNBUILD_NOIPX
  3394. #ifndef DPNBUILD_NOIPV6
  3395. case AF_INET6:
  3396. {
  3397. DNASSERT (! IN6_IS_ADDR_UNSPECIFIED(&(((SOCKADDR_IN6*) m_pNetworkSocketAddress->GetAddress())->sin6_addr)));
  3398. DNASSERT( m_pNetworkSocketAddress->GetPort() != 0 );
  3399. break;
  3400. }
  3401. #endif // ! DPNBUILD_NOIPV6
  3402. default:
  3403. {
  3404. DNASSERT( FALSE );
  3405. break;
  3406. }
  3407. }
  3408. #endif // DBG
  3409. switch ( AddressType )
  3410. {
  3411. case SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT:
  3412. case SP_ADDRESS_TYPE_DEVICE:
  3413. {
  3414. #ifdef DPNBUILD_XNETSECURITY
  3415. pAddress = m_pNetworkSocketAddress->DP8AddressFromSocketAddress( pullKeyID, NULL, AddressType );
  3416. #else // ! DPNBUILD_XNETSECURITY
  3417. pAddress = m_pNetworkSocketAddress->DP8AddressFromSocketAddress( AddressType );
  3418. #endif // ! DPNBUILD_XNETSECURITY
  3419. if (pAddress == NULL)
  3420. {
  3421. break;
  3422. }
  3423. //
  3424. // We hand up the exact device address we ended up using for this adapter.
  3425. //
  3426. #ifndef DPNBUILD_ONLYONEADAPTER
  3427. //
  3428. // Special case where any port will do:
  3429. // In multi-adapter systems, our user is probably going to switch in a different
  3430. // device GUID and pass it back down for another connect attempt (because
  3431. // we told them we support ALL_ADAPTERS). This can pose a problem since
  3432. // we include the specific port in this address. If the port was available on this
  3433. // adapter but not on others. The other attempts will fail. This can also cause
  3434. // problems when indicating the device with enum responses. If the application
  3435. // allowed us to select a local port, enumerated and got a response, shutdown
  3436. // the interface (or just the enum), then connected with the device address, we
  3437. // would try to use that port again, even though it may now be in use by
  3438. // another local application (or more likely, on the NAT).
  3439. //
  3440. // We are not required to use the same port on all adapters if the caller did
  3441. // not choose a specific port in the first place, so there's no reason why we
  3442. // couldn't try a different one.
  3443. //
  3444. // We know whether the port was specified or not, because GatewayBindType
  3445. // will be GATEWAY_BIND_TYPE_DEFAULT if the port can float, _SPECIFIC or
  3446. // _SPECIFIC_SHARED if not.
  3447. //
  3448. // So we can add a special key to the device address indicating that while it
  3449. // does contain a port, don't take that too seriously. That way, if this device
  3450. // address is reused, we can detect the special key and handle port-in-use
  3451. // problems gracefully by trying a different one.
  3452. //
  3453. // This special key is not documented and should not be used by anyone but
  3454. // us. We'll use the socketport ID as the value so that it's seemingly random,
  3455. // just to try to scare anyone off from mimicking it in addresses they generate.
  3456. // But we're not going to actually use the value. If the component is present
  3457. // and the value is the right size, we'll use it. If someone puts this into an
  3458. // address on their own, they get what they deserve (not like this will cause
  3459. // us to blow up or anything)...
  3460. //
  3461. // Look in CSPData::BindEndpoint for where this gets read back in.
  3462. //
  3463. if (( AddressType == SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT ) &&
  3464. ( GatewayBindType == GATEWAY_BIND_TYPE_DEFAULT ))
  3465. {
  3466. //
  3467. // Add the component, but ignore failure, we can still survive without it.
  3468. //
  3469. hr = IDirectPlay8Address_AddComponent( pAddress, // interface
  3470. DPNA_PRIVATEKEY_PORT_NOT_SPECIFIC, // tag
  3471. &(m_dwSocketPortID), // component data
  3472. sizeof(m_dwSocketPortID), // component data size
  3473. DPNA_DATATYPE_DWORD // component data type
  3474. );
  3475. if ( hr != DPN_OK )
  3476. {
  3477. DPFX(DPFPREP, 0, "Couldn't add private port-not-specific component (err = 0x%lx)! Ignoring.", hr);
  3478. //hr = DPN_OK;
  3479. }
  3480. }
  3481. #endif // ! DPNBUILD_ONLYONEADAPTER
  3482. #ifndef DPNBUILD_NONATHELP
  3483. //
  3484. // Add the traversal mode component, but ignore failure, we can still
  3485. // survive without it.
  3486. //
  3487. hr = IDirectPlay8Address_AddComponent( pAddress, // interface
  3488. DPNA_KEY_TRAVERSALMODE, // tag
  3489. &(m_dwUserTraversalMode), // component data
  3490. sizeof(m_dwUserTraversalMode), // component data size
  3491. DPNA_DATATYPE_DWORD // component data type
  3492. );
  3493. if ( hr != DPN_OK )
  3494. {
  3495. DPFX(DPFPREP, 0, "Couldn't add traversal mode component (err = 0x%lx)! Ignoring.", hr);
  3496. //hr = DPN_OK;
  3497. }
  3498. #endif // ! DPNBUILD_NONATHELP
  3499. #ifndef DPNBUILD_ONLYONEPROCESSOR
  3500. //
  3501. // If we're using a specific CPU, add that information.
  3502. //
  3503. if ( m_dwCPU != -1 )
  3504. {
  3505. //
  3506. // Add the component, but ignore failure, we can still survive without it.
  3507. //
  3508. hr = IDirectPlay8Address_AddComponent( pAddress, // interface
  3509. DPNA_KEY_PROCESSOR, // tag
  3510. &(m_dwCPU), // component data
  3511. sizeof(m_dwCPU), // component data size
  3512. DPNA_DATATYPE_DWORD // component data type
  3513. );
  3514. if ( hr != DPN_OK )
  3515. {
  3516. DPFX(DPFPREP, 0, "Couldn't add processor component (err = 0x%lx)! Ignoring.", hr);
  3517. //hr = DPN_OK;
  3518. }
  3519. }
  3520. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  3521. break;
  3522. }
  3523. case SP_ADDRESS_TYPE_HOST:
  3524. case SP_ADDRESS_TYPE_PUBLIC_HOST_ADDRESS:
  3525. {
  3526. #ifndef DPNBUILD_NONATHELP
  3527. //
  3528. // Try to get the public address, if we have one.
  3529. //
  3530. if ( ( m_pNetworkSocketAddress->GetFamily() == AF_INET ) &&
  3531. ( m_pThreadPool->IsNATHelpLoaded() ) &&
  3532. ( GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE ) )
  3533. {
  3534. pTempAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) m_pNetworkSocketAddress->GetFamily()));
  3535. if ( pTempAddress != NULL)
  3536. {
  3537. //
  3538. // IDirectPlayNATHelp::GetCaps had better have been called with the
  3539. // DPNHGETCAPS_UPDATESERVERSTATUS flag at least once prior to this.
  3540. // See CThreadPool::EnsureNATHelpLoaded
  3541. //
  3542. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  3543. {
  3544. if (g_papNATHelpObjects[dwTemp] != NULL)
  3545. {
  3546. dwAddressSize = sizeof(saddr);
  3547. #ifdef DBG
  3548. hr = IDirectPlayNATHelp_GetRegisteredAddresses( g_papNATHelpObjects[dwTemp], // object
  3549. m_ahNATHelpPorts[dwTemp], // port binding
  3550. &saddr, // place to store address
  3551. &dwAddressSize, // address buffer size
  3552. &dwAddressTypeFlags, // get type flags for printing in debug
  3553. NULL, // don't need lease time remaining
  3554. 0 ); // no flags
  3555. #else
  3556. hr = IDirectPlayNATHelp_GetRegisteredAddresses( g_papNATHelpObjects[dwTemp], // object
  3557. m_ahNATHelpPorts[dwTemp], // port binding
  3558. &saddr, // place to store address
  3559. &dwAddressSize, // address buffer size
  3560. NULL, // don't bother getting type flags in retail
  3561. NULL, // don't need lease time remaining
  3562. 0 ); // no flags
  3563. #endif // DBG
  3564. if (hr == DPNH_OK)
  3565. {
  3566. pTempAddress->SetAddressFromSOCKADDR( &saddr, sizeof(saddr) );
  3567. DPFX(DPFPREP, 2, "Internet gateway index %u currently maps address (type flags = 0x%lx):",
  3568. dwTemp, dwAddressTypeFlags);
  3569. DumpSocketAddress( 2, m_pNetworkSocketAddress->GetAddress(), m_pNetworkSocketAddress->GetFamily() );
  3570. DumpSocketAddress( 2, pTempAddress->GetAddress(), pTempAddress->GetFamily() );
  3571. //
  3572. // Double check that the address we got was valid.
  3573. //
  3574. DNASSERT( ((SOCKADDR_IN*) (&saddr))->sin_addr.S_un.S_addr != 0 );
  3575. //
  3576. // Get out of the loop since we have a mapping.
  3577. //
  3578. break;
  3579. }
  3580. #ifdef DBG
  3581. switch (hr)
  3582. {
  3583. case DPNHERR_NOMAPPING:
  3584. {
  3585. DPFX(DPFPREP, 1, "Internet gateway (index %u, type flags = 0x%lx) does not have a public address.",
  3586. dwTemp, dwAddressTypeFlags);
  3587. break;
  3588. }
  3589. case DPNHERR_PORTUNAVAILABLE:
  3590. {
  3591. DPFX(DPFPREP, 1, "Port is unavailable on Internet gateway (index %u).", dwTemp );
  3592. break;
  3593. }
  3594. case DPNHERR_SERVERNOTAVAILABLE:
  3595. {
  3596. DPFX(DPFPREP, 1, "No Internet gateway (index %u).", dwTemp );
  3597. break;
  3598. }
  3599. default:
  3600. {
  3601. DPFX(DPFPREP, 1, "An error (0x%lx) occurred while getting registered address mapping index %u.",
  3602. hr, dwTemp);
  3603. break;
  3604. }
  3605. }
  3606. #endif // DBG
  3607. }
  3608. else
  3609. {
  3610. //
  3611. // No object in this slot.
  3612. //
  3613. }
  3614. } // end for (each DPNATHelp object)
  3615. //
  3616. // If we found a mapping, pTempAddress is not NULL and contains the mapping's
  3617. // address. If we couldn't find any mappings with any of the NAT Help objects,
  3618. // pTempAddress will be non-NULL, but bogus. We should return the local address
  3619. // if it's a HOST address, or NULL if the caller was trying to get the public
  3620. // address.
  3621. //
  3622. if (hr != DPNH_OK)
  3623. {
  3624. if (AddressType == SP_ADDRESS_TYPE_HOST)
  3625. {
  3626. DPFX(DPFPREP, 1, "No NAT Help mappings exist, using regular address:");
  3627. DumpSocketAddress( 1, m_pNetworkSocketAddress->GetAddress(), m_pNetworkSocketAddress->GetFamily() );
  3628. pTempAddress->CopyAddressSettings( m_pNetworkSocketAddress );
  3629. }
  3630. else
  3631. {
  3632. DPFX(DPFPREP, 1, "No NAT Help mappings exist, not returning address.");
  3633. g_SocketAddressPool.Release( pTempAddress );
  3634. pTempAddress = NULL;
  3635. }
  3636. }
  3637. else
  3638. {
  3639. //
  3640. // We found a mapping.
  3641. //
  3642. }
  3643. }
  3644. else
  3645. {
  3646. //
  3647. // Couldn't get temporary address object, we won't return an address.
  3648. //
  3649. }
  3650. }
  3651. else
  3652. #endif DPNBUILD_NONATHELP
  3653. {
  3654. //
  3655. // NAT Help not loaded or not necessary.
  3656. //
  3657. if (AddressType == SP_ADDRESS_TYPE_HOST)
  3658. {
  3659. pTempAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) m_pNetworkSocketAddress->GetFamily()));
  3660. if ( pTempAddress != NULL )
  3661. {
  3662. pTempAddress->CopyAddressSettings( m_pNetworkSocketAddress );
  3663. #ifdef DPNBUILD_XNETSECURITY
  3664. //
  3665. // Force the IP address to the loopback address for
  3666. // secure mode, since it barfs when looking up the
  3667. // real local IP.
  3668. //
  3669. if (pullKeyID != NULL)
  3670. {
  3671. DNASSERT(pTempAddress->GetFamily() == AF_INET);
  3672. psaddrin = (SOCKADDR_IN *) pTempAddress->GetWritableAddress();
  3673. psaddrin->sin_addr.S_un.S_addr = IP_LOOPBACK_ADDRESS;
  3674. }
  3675. #endif // ! DPNBUILD_XNETSECURITY
  3676. }
  3677. else
  3678. {
  3679. //
  3680. // Couldn't allocate memory, we won't return an address.
  3681. //
  3682. }
  3683. }
  3684. else
  3685. {
  3686. //
  3687. // Public host address requested. NAT Help not available, so of course
  3688. // there won't be a public address. Return NULL.
  3689. //
  3690. }
  3691. }
  3692. //
  3693. // If we determined we had an address to return, convert it to the
  3694. // IDirectPlay8Address object our caller is expecting.
  3695. //
  3696. if ( pTempAddress != NULL )
  3697. {
  3698. //
  3699. // We have an address to return.
  3700. //
  3701. #ifdef DBG
  3702. #if ((! defined (DPNBUILD_NOIPX)) || (! defined (DPNBUILD_NOIPV6)))
  3703. if (pTempAddress->GetFamily() == AF_INET)
  3704. #endif // ! DPNBUILD_NOIPX or ! DPNBUILD_NOIPV6
  3705. {
  3706. psaddrin = (SOCKADDR_IN *) pTempAddress->GetAddress();
  3707. #ifndef DPNBUILD_ONLYONEADAPTER
  3708. DNASSERT( psaddrin->sin_addr.S_un.S_addr != 0 );
  3709. #endif // ! DPNBUILD_ONLYONEADAPTER
  3710. DNASSERT( psaddrin->sin_addr.S_un.S_addr != INADDR_BROADCAST );
  3711. DNASSERT( psaddrin->sin_port != 0 );
  3712. }
  3713. #endif // DBG
  3714. //
  3715. // Convert the socket address to an IDirectPlay8Address
  3716. //
  3717. #ifdef DPNBUILD_XNETSECURITY
  3718. pAddress = pTempAddress->DP8AddressFromSocketAddress( pullKeyID, NULL, SP_ADDRESS_TYPE_HOST );
  3719. #else // ! DPNBUILD_XNETSECURITY
  3720. pAddress = pTempAddress->DP8AddressFromSocketAddress( SP_ADDRESS_TYPE_HOST );
  3721. #endif // ! DPNBUILD_XNETSECURITY
  3722. g_SocketAddressPool.Release( pTempAddress );
  3723. pTempAddress = NULL;
  3724. }
  3725. else
  3726. {
  3727. //
  3728. // Not returning an address.
  3729. //
  3730. DNASSERT( pAddress == NULL );
  3731. }
  3732. break;
  3733. }
  3734. default:
  3735. {
  3736. //
  3737. // shouldn't be here
  3738. //
  3739. DNASSERT( FALSE );
  3740. break;
  3741. }
  3742. }
  3743. DPFX(DPFPREP, 8, "(0x%p) Returning [0x%p]", this, pAddress );
  3744. return pAddress;
  3745. }
  3746. //**********************************************************************
  3747. #ifndef DPNBUILD_NOWINSOCK2
  3748. //**********************************************************************
  3749. // ------------------------------
  3750. // CSocketPort::Winsock2ReceiveComplete - a Winsock2 socket receive completed
  3751. //
  3752. // Entry: Pointer to read data
  3753. //
  3754. // Exit: Nothing
  3755. // ------------------------------
  3756. #undef DPF_MODNAME
  3757. #define DPF_MODNAME "CSocketPort::Winsock2ReceiveComplete"
  3758. void CSocketPort::Winsock2ReceiveComplete( void * const pvContext, void * const pvTimerData, const UINT uiTimerUnique )
  3759. {
  3760. CReadIOData * pReadData;
  3761. CSocketPort * pThisSocketPort;
  3762. DWORD dwFlags;
  3763. DNASSERT( pvContext != NULL );
  3764. pReadData = (CReadIOData*) pvContext;
  3765. DNASSERT( pReadData->m_pSocketPort != NULL );
  3766. pThisSocketPort = pReadData->m_pSocketPort;
  3767. //
  3768. // If we are handling an I/O completion via the threadpool, get the result
  3769. // and clear the overlapped field because it has been reclaimed already.
  3770. //
  3771. if (pReadData->GetOverlapped() != NULL)
  3772. {
  3773. if (pThisSocketPort->GetSocket() != INVALID_SOCKET)
  3774. {
  3775. if (! p_WSAGetOverlappedResult(pThisSocketPort->GetSocket(),
  3776. (WSAOVERLAPPED*) pReadData->GetOverlapped(),
  3777. &pReadData->m_dwOverlappedBytesReceived,
  3778. FALSE,
  3779. &dwFlags))
  3780. {
  3781. pReadData->m_ReceiveWSAReturn = WSAGetLastError();
  3782. }
  3783. else
  3784. {
  3785. pReadData->m_ReceiveWSAReturn = ERROR_SUCCESS;
  3786. }
  3787. }
  3788. else
  3789. {
  3790. DNASSERT(pThisSocketPort->m_State == SOCKET_PORT_STATE_UNBOUND);
  3791. pReadData->m_ReceiveWSAReturn = WSAENOTSOCK;
  3792. }
  3793. pReadData->SetOverlapped(NULL);
  3794. }
  3795. DPFX(DPFPREP, 8, "Socket port 0x%p completing read data 0x%p with result %i, bytes %u.",
  3796. pThisSocketPort, pReadData, pReadData->m_ReceiveWSAReturn, pReadData->m_dwOverlappedBytesReceived);
  3797. #ifdef WIN95
  3798. if ((pReadData->m_ReceiveWSAReturn == ERROR_SUCCESS) &&
  3799. (pReadData->m_dwOverlappedBytesReceived == 0))
  3800. {
  3801. DPFX(DPFPREP, 2, "Marking 0 byte success read data 0x%p as aborted.",
  3802. pReadData);
  3803. pReadData->m_ReceiveWSAReturn = ERROR_OPERATION_ABORTED;
  3804. }
  3805. #endif // WIN95
  3806. //
  3807. // figure out what's happening with this socket port
  3808. //
  3809. pThisSocketPort->Lock();
  3810. switch ( pThisSocketPort->m_State )
  3811. {
  3812. //
  3813. // we're unbound, discard this message and don't ask for any more
  3814. //
  3815. case SOCKET_PORT_STATE_UNBOUND:
  3816. {
  3817. DPFX(DPFPREP, 1, "Socket port 0x%p is unbound ignoring result %i (%u bytes).",
  3818. pThisSocketPort, pReadData->m_ReceiveWSAReturn, pReadData->m_dwOverlappedBytesReceived );
  3819. pThisSocketPort->Unlock();
  3820. break;
  3821. }
  3822. //
  3823. // we're initialized, process input data and submit a new receive if
  3824. // applicable
  3825. //
  3826. case SOCKET_PORT_STATE_BOUND:
  3827. {
  3828. //
  3829. // success, or non-socket closing error, submit another receive
  3830. // and process data if applicable
  3831. //
  3832. #if ((! defined(DPNBUILD_ONLYONETHREAD)) || (defined(DBG)))
  3833. //
  3834. // The socket state must not go to UNBOUND while we are in a
  3835. // receive or we will be using an invalid socket handle.
  3836. //
  3837. pThisSocketPort->m_iThreadsInReceive++;
  3838. #endif // ! DPNBUILD_ONLYONETHREAD or DBG
  3839. pThisSocketPort->Unlock();
  3840. //
  3841. // Resubmit a receive for the same CPU as this one that's completing.
  3842. //
  3843. #ifdef DPNBUILD_ONLYONEPROCESSOR
  3844. pThisSocketPort->Winsock2Receive();
  3845. #else // ! DPNBUILD_ONLYONEPROCESSOR
  3846. pThisSocketPort->Winsock2Receive(pReadData->GetCPU());
  3847. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  3848. #if ((! defined(DPNBUILD_ONLYONETHREAD)) || (defined(DBG)))
  3849. pThisSocketPort->Lock();
  3850. pThisSocketPort->m_iThreadsInReceive--;
  3851. pThisSocketPort->Unlock();
  3852. #endif // ! DPNBUILD_ONLYONETHREAD or DBG
  3853. switch ( pReadData->m_ReceiveWSAReturn )
  3854. {
  3855. //
  3856. // ERROR_SUCCESS = no problem (process received data)
  3857. //
  3858. case ERROR_SUCCESS:
  3859. {
  3860. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize = pReadData->m_dwOverlappedBytesReceived;
  3861. pThisSocketPort->ProcessReceivedData( pReadData );
  3862. break;
  3863. }
  3864. //
  3865. // WSAECONNRESET = previous send failed (process received data with the intention of disconnecting endpoint)
  3866. // ERROR_PORT_UNREACHABLE = same
  3867. //
  3868. case WSAECONNRESET:
  3869. case ERROR_PORT_UNREACHABLE:
  3870. {
  3871. DPFX(DPFPREP, 7, "(0x%p) Send failure reported from + to:", pThisSocketPort);
  3872. DNASSERT(pReadData->m_dwOverlappedBytesReceived == 0);
  3873. DumpSocketAddress(7, pReadData->m_pSourceSocketAddress->GetAddress(), pReadData->m_pSourceSocketAddress->GetFamily());
  3874. DumpSocketAddress(7, pThisSocketPort->GetNetworkAddress()->GetAddress(), pThisSocketPort->GetNetworkAddress()->GetFamily());
  3875. #ifndef DPNBUILD_NOREGISTRY
  3876. if (g_fDisconnectOnICMP)
  3877. {
  3878. HRESULT hr;
  3879. CEndpoint * pEndpoint;
  3880. //
  3881. // Look for an active connection for which the disconnection was
  3882. // indicated.
  3883. //
  3884. pThisSocketPort->ReadLockEndpointData();
  3885. if ( pThisSocketPort->m_ConnectEndpointHash.Find( (PVOID)pReadData->m_pSourceSocketAddress, (PVOID*)&pEndpoint ) )
  3886. {
  3887. if ( pEndpoint->AddCommandRef() )
  3888. {
  3889. pThisSocketPort->UnlockEndpointData();
  3890. DPFX(DPFPREP, 7, "(0x%p) Disconnecting endpoint 0x%p.", pThisSocketPort, pEndpoint);
  3891. hr = pEndpoint->Disconnect();
  3892. if ( hr != DPN_OK )
  3893. {
  3894. DPFX(DPFPREP, 0, "Couldn't disconnect endpoint 0x%p (err = 0x%lx)!", pEndpoint, hr);
  3895. }
  3896. pEndpoint->DecCommandRef();
  3897. }
  3898. else
  3899. {
  3900. pThisSocketPort->UnlockEndpointData();
  3901. DPFX(DPFPREP, 3, "Not disconnecting endpoint 0x%p, it's already unbinding.",
  3902. pEndpoint );
  3903. }
  3904. }
  3905. else
  3906. {
  3907. //
  3908. // No active connection, we won't bother handling proxy case.
  3909. //
  3910. pThisSocketPort->UnlockEndpointData();
  3911. DPFX(DPFPREP, 7, "(0x%p) No corresponding endpoint found.", pThisSocketPort);
  3912. }
  3913. }
  3914. #endif // ! DPNBUILD_NOREGISTRY
  3915. break;
  3916. }
  3917. //
  3918. // ERROR_FILE_NOT_FOUND = socket was closed or previous send failed
  3919. // ERROR_MORE_DATA = datagram was sent that was too large
  3920. // ERROR_NO_SYSTEM_RESOURCES = out of memory
  3921. //
  3922. case ERROR_FILE_NOT_FOUND:
  3923. case ERROR_MORE_DATA:
  3924. case ERROR_NO_SYSTEM_RESOURCES:
  3925. {
  3926. DPFX(DPFPREP, 1, "Ignoring known receive err 0x%lx.", pReadData->m_ReceiveWSAReturn );
  3927. break;
  3928. }
  3929. //
  3930. // ERROR_OPERATION_ABORTED = I/O was cancelled for a thread (it also is the same
  3931. // as 9x "socket closed", but we assume that's not
  3932. // happening and would be caught by socket bind
  3933. // state above)
  3934. //
  3935. case ERROR_OPERATION_ABORTED:
  3936. {
  3937. DPFX(DPFPREP, 1, "Thread I/O cancelled, ignoring receive err %u/0x%lx.",
  3938. pReadData->m_ReceiveWSAReturn, pReadData->m_ReceiveWSAReturn );
  3939. break;
  3940. }
  3941. default:
  3942. {
  3943. DPFX(DPFPREP, 0, "Unexpected return from WSARecvFrom() 0x%lx.", pReadData->m_ReceiveWSAReturn );
  3944. DisplayErrorCode( 0, pReadData->m_ReceiveWSAReturn );
  3945. DNASSERT( FALSE );
  3946. break;
  3947. }
  3948. }
  3949. break;
  3950. }
  3951. //
  3952. // other state
  3953. //
  3954. default:
  3955. {
  3956. DNASSERT( FALSE );
  3957. pThisSocketPort->Unlock();
  3958. break;
  3959. }
  3960. }
  3961. //
  3962. // Return the current data to the pool and note that this I/O operation is
  3963. // complete. Clear the overlapped bytes received so they aren't misinterpreted
  3964. // if this item is reused from the pool.
  3965. //
  3966. DNASSERT( pReadData != NULL );
  3967. pReadData->m_dwOverlappedBytesReceived = 0;
  3968. pReadData->DecRef();
  3969. pThisSocketPort->DecRef();
  3970. return;
  3971. }
  3972. //**********************************************************************
  3973. #endif // DPNBUILD_NOWINSOCK2
  3974. //**********************************************************************
  3975. // ------------------------------
  3976. // CSocketPort::ProcessReceivedData - process received data
  3977. //
  3978. // Entry: Pointer to CReadIOData
  3979. //
  3980. // Exit: Nothing
  3981. // ------------------------------
  3982. #undef DPF_MODNAME
  3983. #define DPF_MODNAME "CSocketPort::ProcessReceivedData"
  3984. void CSocketPort::ProcessReceivedData( CReadIOData *const pReadData )
  3985. {
  3986. PREPEND_BUFFER * pPrependBuffer;
  3987. CEndpoint * pEndpoint;
  3988. BOOL fDataClaimed;
  3989. CBilink * pBilink;
  3990. CEndpoint * pCurrentEndpoint;
  3991. CSocketAddress * pSocketAddress;
  3992. DNASSERT( pReadData != NULL );
  3993. DPFX(DPFPREP, 7, "(0x%p) Processing %u bytes of data from + to:", this, pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  3994. DumpSocketAddress(7, pReadData->m_pSourceSocketAddress->GetAddress(), pReadData->m_pSourceSocketAddress->GetFamily());
  3995. DumpSocketAddress(7, GetNetworkAddress()->GetAddress(), GetNetworkAddress()->GetFamily());
  3996. DBG_CASSERT( sizeof( pReadData->ReceivedBuffer()->BufferDesc.pBufferData ) == sizeof( PREPEND_BUFFER* ) );
  3997. pPrependBuffer = reinterpret_cast<PREPEND_BUFFER*>( pReadData->ReceivedBuffer()->BufferDesc.pBufferData );
  3998. //
  3999. // Check data for integrity and decide what to do with it. If there is
  4000. // enough data to determine an SP command type, try that. If there isn't
  4001. // enough data, and it looks spoofed, reject it.
  4002. //
  4003. DNASSERT( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize > 0 );
  4004. if ( pPrependBuffer->GenericHeader.bSPLeadByte != SP_HEADER_LEAD_BYTE )
  4005. {
  4006. goto ProcessUserData;
  4007. }
  4008. if ( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize < sizeof( pPrependBuffer->GenericHeader ) )
  4009. {
  4010. DPFX(DPFPREP, 7, "Ignoring %u bytes of malformed SP command data.",
  4011. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize );
  4012. DNASSERTX(! "Received malformed message using invalid SP command!", 2);
  4013. goto Exit;
  4014. }
  4015. switch ( pPrependBuffer->GenericHeader.bSPCommandByte )
  4016. {
  4017. //
  4018. // Enum data, send it to the active listen (if there is one).
  4019. //
  4020. case ENUM_DATA_KIND:
  4021. {
  4022. if (! pReadData->m_pSourceSocketAddress->IsValidUnicastAddress(FALSE))
  4023. {
  4024. DPFX(DPFPREP, 7, "Invalid source address, ignoring %u byte enum.",
  4025. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4026. goto Exit;
  4027. }
  4028. #ifndef DPNBUILD_NOREGISTRY
  4029. if ( g_fIgnoreEnums )
  4030. {
  4031. DPFX(DPFPREP, 7, "Ignoring enumeration attempt." );
  4032. DNASSERTX(! "Received enum message when ignoring enums!", 2);
  4033. goto Exit;
  4034. }
  4035. if ( pReadData->m_pSourceSocketAddress->IsBannedAddress() )
  4036. {
  4037. DPFX(DPFPREP, 6, "Ignoring %u byte enum sent by banned address.",
  4038. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4039. goto Exit;
  4040. }
  4041. #endif // ! DPNBUILD_NOREGISTRY
  4042. //
  4043. // Validate size. We use <= instead of < because there must be a user payload.
  4044. //
  4045. if ( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize <= sizeof( pPrependBuffer->EnumDataHeader ) )
  4046. {
  4047. DPFX(DPFPREP, 7, "Ignoring data, not large enough to be a valid enum (%u <= %u).",
  4048. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize, sizeof( pPrependBuffer->EnumDataHeader ));
  4049. DNASSERTX(! "Received invalid enum message!", 2);
  4050. goto Exit;
  4051. }
  4052. ReadLockEndpointData();
  4053. //
  4054. // Make sure there is a listen, and isn't going away.
  4055. //
  4056. if ( m_pListenEndpoint != NULL )
  4057. {
  4058. //
  4059. // Try to add a reference to this endpoint so it doesn't go away while we're
  4060. // processing this data. If the endpoint is already being unbound, this can fail.
  4061. //
  4062. if ( m_pListenEndpoint->AddCommandRef() )
  4063. {
  4064. pEndpoint = m_pListenEndpoint;
  4065. UnlockEndpointData();
  4066. if ( pEndpoint->IsEnumAllowedOnListen() )
  4067. {
  4068. //
  4069. // skip prepended enum header
  4070. //
  4071. pReadData->ReceivedBuffer()->BufferDesc.pBufferData = &pReadData->ReceivedBuffer()->BufferDesc.pBufferData[ sizeof( pPrependBuffer->EnumDataHeader ) ];
  4072. DNASSERT( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize >= sizeof( pPrependBuffer->EnumDataHeader ) );
  4073. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize -= sizeof( pPrependBuffer->EnumDataHeader );
  4074. //
  4075. // process data
  4076. //
  4077. pEndpoint->ProcessEnumData( pReadData->ReceivedBuffer(),
  4078. pPrependBuffer->EnumDataHeader.wEnumPayload,
  4079. pReadData->m_pSourceSocketAddress );
  4080. }
  4081. else
  4082. {
  4083. DPFX(DPFPREP, 7, "Ignoring enumeration because not allowed on listen endpoint 0x%p.",
  4084. m_pListenEndpoint );
  4085. }
  4086. pEndpoint->DecCommandRef();
  4087. }
  4088. else
  4089. {
  4090. //
  4091. // the listen is being unbound, return the receive buffer to the pool
  4092. //
  4093. UnlockEndpointData();
  4094. DPFX(DPFPREP, 3, "Ignoring enumeration, listen endpoint 0x%p is unbinding.",
  4095. m_pListenEndpoint );
  4096. }
  4097. }
  4098. else
  4099. {
  4100. //
  4101. // there's no listen active, return the receive buffer to the pool
  4102. //
  4103. UnlockEndpointData();
  4104. DPFX(DPFPREP, 7, "Ignoring enumeration, no associated listen." );
  4105. }
  4106. break;
  4107. }
  4108. //
  4109. // Enum response data, find the appropriate enum and pass it on.
  4110. //
  4111. case ENUM_RESPONSE_DATA_KIND:
  4112. #ifdef DPNBUILD_XNETSECURITY
  4113. case XNETSEC_ENUM_RESPONSE_DATA_KIND:
  4114. #endif // DPNBUILD_XNETSECURITY
  4115. {
  4116. CEndpointEnumKey Key;
  4117. #ifdef DPNBUILD_XNETSECURITY
  4118. XNADDR * pxnaddr;
  4119. #endif // DPNBUILD_XNETSECURITY
  4120. if (! pReadData->m_pSourceSocketAddress->IsValidUnicastAddress(FALSE))
  4121. {
  4122. DPFX(DPFPREP, 7, "Invalid source address, ignoring %u byte enum response.",
  4123. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4124. goto Exit;
  4125. }
  4126. #ifndef DPNBUILD_NOREGISTRY
  4127. if ( g_fIgnoreEnums )
  4128. {
  4129. DPFX(DPFPREP, 7, "Ignoring enumeration response attempt." );
  4130. DNASSERTX(! "Received enum response message when ignoring enums!", 2);
  4131. goto Exit;
  4132. }
  4133. if ( pReadData->m_pSourceSocketAddress->IsBannedAddress() )
  4134. {
  4135. DPFX(DPFPREP, 6, "Ignoring %u byte enum response sent by banned address.",
  4136. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4137. goto Exit;
  4138. }
  4139. #endif // ! DPNBUILD_NOREGISTRY
  4140. //
  4141. // Validate size. We use <= instead of < because there must be a user payload.
  4142. //
  4143. if ( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize <= sizeof( pPrependBuffer->EnumResponseDataHeader ) )
  4144. {
  4145. DPFX(DPFPREP, 7, "Ignoring data, not large enough to be a valid enum response (%u <= %u).",
  4146. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize, sizeof( pPrependBuffer->EnumResponseDataHeader ));
  4147. DNASSERTX(! "Received invalid enum response message!", 2);
  4148. }
  4149. #ifdef DPNBUILD_XNETSECURITY
  4150. //
  4151. // Secure transport enum replies also include an address.
  4152. //
  4153. if ( pPrependBuffer->GenericHeader.bSPCommandByte == XNETSEC_ENUM_RESPONSE_DATA_KIND )
  4154. {
  4155. //
  4156. // Validate size. We use <= instead of < because there must be a user payload.
  4157. //
  4158. if ( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize <= sizeof( pPrependBuffer->XNetSecEnumResponseDataHeader ) )
  4159. {
  4160. DPFX(DPFPREP, 7, "Ignoring data, not large enough to be a valid secure enum response (%u < %u).",
  4161. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize, sizeof( pPrependBuffer->XNetSecEnumResponseDataHeader ));
  4162. DNASSERTX(! "Received invalid secure enum response message!", 2);
  4163. goto Exit;
  4164. }
  4165. pReadData->ReceivedBuffer()->BufferDesc.pBufferData = &pReadData->ReceivedBuffer()->BufferDesc.pBufferData[ sizeof( pPrependBuffer->XNetSecEnumResponseDataHeader ) ];
  4166. DNASSERT( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize > sizeof( pPrependBuffer->XNetSecEnumResponseDataHeader ) );
  4167. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize -= sizeof( pPrependBuffer->XNetSecEnumResponseDataHeader );
  4168. pxnaddr = &pPrependBuffer->XNetSecEnumResponseDataHeader.xnaddr;
  4169. }
  4170. else
  4171. #endif // DPNBUILD_XNETSECURITY
  4172. {
  4173. pReadData->ReceivedBuffer()->BufferDesc.pBufferData = &pReadData->ReceivedBuffer()->BufferDesc.pBufferData[ sizeof( pPrependBuffer->EnumResponseDataHeader ) ];
  4174. DNASSERT( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize > sizeof( pPrependBuffer->EnumResponseDataHeader ) );
  4175. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize -= sizeof( pPrependBuffer->EnumResponseDataHeader );
  4176. #ifdef DPNBUILD_XNETSECURITY
  4177. pxnaddr = NULL;
  4178. #endif // DPNBUILD_XNETSECURITY
  4179. }
  4180. Key.SetKey( pPrependBuffer->EnumResponseDataHeader.wEnumResponsePayload );
  4181. ReadLockEndpointData();
  4182. if ( m_EnumEndpointHash.Find( (PVOID)&Key, (PVOID*)&pEndpoint ) )
  4183. {
  4184. //
  4185. // Try to add a reference to this endpoint so it doesn't go away while we're
  4186. // processing this data. If the endpoint is already being unbound, this can fail.
  4187. //
  4188. if ( pEndpoint->AddCommandRef() )
  4189. {
  4190. UnlockEndpointData();
  4191. pEndpoint->ProcessEnumResponseData( pReadData->ReceivedBuffer(),
  4192. pReadData->m_pSourceSocketAddress,
  4193. #ifdef DPNBUILD_XNETSECURITY
  4194. pxnaddr,
  4195. #endif // DPNBUILD_XNETSECURITY
  4196. ( pPrependBuffer->EnumResponseDataHeader.wEnumResponsePayload & ENUM_RTT_MASK ) );
  4197. pEndpoint->DecCommandRef();
  4198. }
  4199. else
  4200. {
  4201. //
  4202. // the associated ENUM is being unbound, return the receive buffer
  4203. //
  4204. UnlockEndpointData();
  4205. DPFX(DPFPREP, 3, "Ignoring enumeration response, enum endpoint 0x%p is unbinding.",
  4206. pEndpoint );
  4207. }
  4208. }
  4209. else
  4210. {
  4211. //
  4212. // the associated ENUM doesn't exist, return the receive buffer
  4213. //
  4214. UnlockEndpointData();
  4215. DPFX(DPFPREP, 7, "Ignoring enumeration response, no enum associated with key (%u).",
  4216. pPrependBuffer->EnumResponseDataHeader.wEnumResponsePayload );
  4217. DNASSERTX(! "Received enum response with unrecognized key!", 3);
  4218. }
  4219. break;
  4220. }
  4221. #ifndef DPNBUILD_SINGLEPROCESS
  4222. //
  4223. // proxied query data, this data was forwarded from another port. Munge
  4224. // the return address, modify the buffer pointer and then send it up
  4225. // through the normal enum data processing pipeline.
  4226. //
  4227. case PROXIED_ENUM_DATA_KIND:
  4228. {
  4229. //
  4230. // Ignore the message if it wasn't sent by the local IP address from
  4231. // the DPNSVR port.
  4232. //
  4233. if ((pReadData->m_pSourceSocketAddress->GetPort() != HTONS(DPNA_DPNSVR_PORT)) ||
  4234. (pReadData->m_pSourceSocketAddress->CompareToBaseAddress(m_pNetworkSocketAddress->GetAddress()) != 0))
  4235. {
  4236. DPFX(DPFPREP, 7, "Ignoring %u byte proxied enum not sent by local DPNSVR.",
  4237. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4238. goto Exit;
  4239. }
  4240. #ifndef DPNBUILD_NOREGISTRY
  4241. if ( g_fIgnoreEnums )
  4242. {
  4243. DPFX(DPFPREP, 7, "Ignoring proxied enumeration attempt." );
  4244. DNASSERTX(! "Received proxied enum message when ignoring enums!", 2);
  4245. goto Exit;
  4246. }
  4247. #endif // ! DPNBUILD_NOREGISTRY
  4248. //
  4249. // Validate size. We use <= instead of < because there must be a user payload.
  4250. //
  4251. if ( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize <= sizeof( pPrependBuffer->ProxiedEnumDataHeader ) )
  4252. {
  4253. DPFX(DPFPREP, 7, "Ignoring data, not large enough to be a valid proxied enum (%u <= %u).",
  4254. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize, sizeof( pPrependBuffer->ProxiedEnumDataHeader ));
  4255. DNASSERTX(! "Received invalid proxied enum message!", 2);
  4256. goto Exit;
  4257. }
  4258. //
  4259. // Make sure the original socket address family is expected.
  4260. //
  4261. if (pPrependBuffer->ProxiedEnumDataHeader.ReturnAddress.AddressGeneric.sa_family != pReadData->m_pSourceSocketAddress->GetFamily())
  4262. {
  4263. DPFX(DPFPREP, 7, "Original address is not correct family, (%u <> %u), ignoring proxied enum.",
  4264. pPrependBuffer->ProxiedEnumDataHeader.ReturnAddress.AddressGeneric.sa_family, pReadData->m_pSourceSocketAddress->GetFamily());
  4265. DNASSERTX(! "Received proxied enum message with invalid original address family!", 2);
  4266. goto Exit;
  4267. }
  4268. //
  4269. // Find out who really sent the message. Overwrite the received address since
  4270. // we don't care about that (it was DPNSVR). Normally these checks shouldn't
  4271. // fail because DPNSVR ought to be doing similar validation when it receives
  4272. // the original. However, someone could potentially spoof the local address
  4273. // and port so we should validate it here, too.
  4274. //
  4275. pReadData->m_pSourceSocketAddress->SetAddressFromSOCKADDR( &pPrependBuffer->ProxiedEnumDataHeader.ReturnAddress.AddressGeneric,
  4276. pReadData->m_pSourceSocketAddress->GetAddressSize() );
  4277. if (! pReadData->m_pSourceSocketAddress->IsValidUnicastAddress(FALSE))
  4278. {
  4279. DPFX(DPFPREP, 7, "Invalid original address, ignoring %u byte proxied enum from:",
  4280. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4281. DumpSocketAddress(7, pReadData->m_pSourceSocketAddress->GetAddress(), pReadData->m_pSourceSocketAddress->GetFamily());
  4282. DNASSERTX(! "Received proxied enum message with invalid original address!", 2);
  4283. goto Exit;
  4284. }
  4285. #ifndef DPNBUILD_NOREGISTRY
  4286. if ( pReadData->m_pSourceSocketAddress->IsBannedAddress() )
  4287. {
  4288. DPFX(DPFPREP, 6, "Ignoring %u byte proxied enum originally sent by banned address:",
  4289. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4290. DumpSocketAddress(6, pReadData->m_pSourceSocketAddress->GetAddress(), pReadData->m_pSourceSocketAddress->GetFamily());
  4291. goto Exit;
  4292. }
  4293. #endif // ! DPNBUILD_NOREGISTRY
  4294. ReadLockEndpointData();
  4295. //
  4296. // Make sure there is a listen, and isn't going away.
  4297. //
  4298. if ( m_pListenEndpoint != NULL )
  4299. {
  4300. //
  4301. // Try to add a reference to this endpoint so it doesn't go away while we're
  4302. // processing this data. If the endpoint is already being unbound, this can fail.
  4303. //
  4304. if ( m_pListenEndpoint->AddCommandRef() )
  4305. {
  4306. pEndpoint = m_pListenEndpoint;
  4307. UnlockEndpointData();
  4308. if ( pEndpoint->IsEnumAllowedOnListen() )
  4309. {
  4310. pReadData->ReceivedBuffer()->BufferDesc.pBufferData = &pReadData->ReceivedBuffer()->BufferDesc.pBufferData[ sizeof( pPrependBuffer->ProxiedEnumDataHeader ) ];
  4311. DNASSERT( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize > sizeof( pPrependBuffer->ProxiedEnumDataHeader ) );
  4312. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize -= sizeof( pPrependBuffer->ProxiedEnumDataHeader );
  4313. pEndpoint->ProcessEnumData( pReadData->ReceivedBuffer(),
  4314. pPrependBuffer->ProxiedEnumDataHeader.wEnumKey,
  4315. pReadData->m_pSourceSocketAddress );
  4316. }
  4317. else
  4318. {
  4319. DPFX(DPFPREP, 7, "Ignoring enumeration because not allowed on listen endpoint 0x%p.",
  4320. m_pListenEndpoint );
  4321. }
  4322. pEndpoint->DecCommandRef();
  4323. }
  4324. else
  4325. {
  4326. //
  4327. // the listen is being unbound, return the receive buffer to the pool
  4328. //
  4329. UnlockEndpointData();
  4330. DPFX(DPFPREP, 3, "Ignoring proxied enumeration, listen endpoint 0x%p is unbinding.",
  4331. m_pListenEndpoint );
  4332. }
  4333. }
  4334. else
  4335. {
  4336. //
  4337. // there's no listen active, return the receive buffer to the pool
  4338. //
  4339. UnlockEndpointData();
  4340. DPFX(DPFPREP, 7, "Ignoring proxied enumeration, no associated listen." );
  4341. DNASSERTX(! "Received proxied enum response without a listen!", 3);
  4342. }
  4343. break;
  4344. }
  4345. #endif // ! DPNBUILD_SINGLEPROCESS
  4346. default:
  4347. {
  4348. DPFX(DPFPREP, 7, "Ignoring %u bytes of data using invalid SP command %u.",
  4349. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize, pPrependBuffer->GenericHeader.bSPCommandByte);
  4350. DNASSERTX(! "Received message using invalid SP command!", 3);
  4351. break;
  4352. }
  4353. }
  4354. Exit:
  4355. return;
  4356. ProcessUserData:
  4357. //
  4358. // If there's an active connection, send it to the connection. If there's
  4359. // no active connection, send it to an available 'listen' to indicate a
  4360. // potential new connection.
  4361. //
  4362. ReadLockEndpointData();
  4363. DNASSERT( pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize != 0 );
  4364. if ( m_ConnectEndpointHash.Find( (PVOID)pReadData->m_pSourceSocketAddress, (PVOID*)&pEndpoint ) )
  4365. {
  4366. //
  4367. // Try to add a reference to this endpoint so it doesn't go away while we're
  4368. // processing this data. If the endpoint is already being unbound, this can fail.
  4369. //
  4370. if ( pEndpoint->AddCommandRef() )
  4371. {
  4372. pEndpoint->IncNumReceives();
  4373. UnlockEndpointData();
  4374. pEndpoint->ProcessUserData( pReadData );
  4375. pEndpoint->DecCommandRef();
  4376. }
  4377. else
  4378. {
  4379. //
  4380. // the endpoint is being unbound, return the receive buffer to the pool
  4381. //
  4382. UnlockEndpointData();
  4383. DPFX(DPFPREP, 3, "Ignoring user data, endpoint 0x%p is unbinding.",
  4384. pEndpoint );
  4385. }
  4386. goto Exit;
  4387. }
  4388. //
  4389. // Next see if the data is a proxied response
  4390. //
  4391. #if ((! defined(DPNBUILD_NOWINSOCK2)) || (! defined(DPNBUILD_NOREGISTRY)))
  4392. if (
  4393. #ifndef DPNBUILD_NOWINSOCK2
  4394. (IsUsingProxyWinSockLSP())
  4395. #endif // ! DPNBUILD_NOWINSOCK2
  4396. #if ((! defined(DPNBUILD_NOWINSOCK2)) && (! defined(DPNBUILD_NOREGISTRY)))
  4397. ||
  4398. #endif // ! DPNBUILD_NOWINSOCK2 and ! DPNBUILD_NOREGISTRY
  4399. #ifndef DPNBUILD_NOREGISTRY
  4400. (g_fTreatAllResponsesAsProxied)
  4401. #endif // ! DPNBUILD_NOREGISTRY
  4402. )
  4403. {
  4404. pEndpoint = NULL;
  4405. pBilink = m_blConnectEndpointList.GetNext();
  4406. while (pBilink != &m_blConnectEndpointList)
  4407. {
  4408. pCurrentEndpoint = CEndpoint::EndpointFromSocketPortListBilink(pBilink);
  4409. if ((pCurrentEndpoint->GetNumReceives() == 0) &&
  4410. (pCurrentEndpoint->GetType() == ENDPOINT_TYPE_CONNECT))
  4411. {
  4412. if (pEndpoint != NULL)
  4413. {
  4414. DPFX(DPFPREP, 1, "Receiving data from unknown source, but two or more connects are pending on socketport 0x%p, no proxied association can be made.",
  4415. this);
  4416. pEndpoint = NULL;
  4417. break;
  4418. }
  4419. pEndpoint = pCurrentEndpoint;
  4420. //
  4421. // Continue, so we can verify there aren't two simultaneous
  4422. // connects going on.
  4423. //
  4424. }
  4425. else
  4426. {
  4427. //
  4428. // This endpoint has already received some data or it's not
  4429. // a CONNECT endpoint. It can't have been proxied.
  4430. //
  4431. }
  4432. pBilink = pBilink->GetNext();
  4433. }
  4434. if ( pEndpoint != NULL )
  4435. {
  4436. //
  4437. // Try to add a reference to this endpoint so it doesn't go away while we're
  4438. // processing this data. If the endpoint is already being unbound, this can fail.
  4439. //
  4440. if ( pEndpoint->AddCommandRef() )
  4441. {
  4442. #ifdef DBG
  4443. CEndpoint * pTempEndpoint;
  4444. #endif // DBG
  4445. //
  4446. // Prevent other threads from doing the same thing while we drop the
  4447. // lock.
  4448. //
  4449. pEndpoint->IncNumReceives();
  4450. //
  4451. // Drop the lock so we can retake it in write mode. The endpoint shouldn't
  4452. // go away because we took a command reference.
  4453. //
  4454. UnlockEndpointData();
  4455. //
  4456. // Make sure the source address is valid.
  4457. //
  4458. if (! pReadData->m_pSourceSocketAddress->IsValidUnicastAddress(FALSE))
  4459. {
  4460. DPFX(DPFPREP, 7, "Invalid source address, ignoring %u bytes of potentially proxied user connect data.",
  4461. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4462. pEndpoint->DecCommandRef();
  4463. goto Exit;
  4464. }
  4465. #ifndef DPNBUILD_NOREGISTRY
  4466. //
  4467. // Make sure this wasn't sent by any banned address.
  4468. //
  4469. if (pReadData->m_pSourceSocketAddress->IsBannedAddress())
  4470. {
  4471. DPFX(DPFPREP, 6, "Ignoring %u byte user message sent by potentially proxied but banned address.",
  4472. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4473. pEndpoint->DecCommandRef();
  4474. goto Exit;
  4475. }
  4476. #endif // ! DPNBUILD_NOREGISTRY
  4477. pSocketAddress = pEndpoint->GetWritableRemoteAddressPointer();
  4478. DPFX(DPFPREP, 1, "Found connecting endpoint 0x%p off socketport 0x%p, assuming data from unknown source is a proxied response. Changing target (was + now):",
  4479. pEndpoint, this);
  4480. DumpSocketAddress(1, pSocketAddress->GetAddress(), pSocketAddress->GetFamily());
  4481. DumpSocketAddress(1, pReadData->m_pSourceSocketAddress->GetAddress(), pReadData->m_pSourceSocketAddress->GetFamily());
  4482. //
  4483. // We could have a regkey to leave the target socketaddress the same
  4484. // so outbound always goes to that address and inbound always comes
  4485. // in via the different one, however that means adding a variable to
  4486. // hold the original target address because we currently pull the
  4487. // endpoint out of the hash table by its remoteaddress pointer (if that
  4488. // differed from what was in the hash, we would fail to find the object.
  4489. // Since we're not trying to enable that scenario for now (we're just
  4490. // doing this for ISA Server proxy), I'm not doing that work yet. See
  4491. // CSPData::BindEndpoint.
  4492. //
  4493. WriteLockEndpointData();
  4494. #ifdef DBG
  4495. DNASSERT( m_ConnectEndpointHash.Find( (PVOID)pSocketAddress, (PVOID*)&pTempEndpoint ) );
  4496. DNASSERT( pTempEndpoint == pEndpoint );
  4497. #endif // DBG
  4498. m_ConnectEndpointHash.Remove( pSocketAddress );
  4499. pSocketAddress->CopyAddressSettings( pReadData->m_pSourceSocketAddress );
  4500. if ( m_ConnectEndpointHash.Insert( (PVOID)pSocketAddress, pEndpoint ) == FALSE )
  4501. {
  4502. UnlockEndpointData();
  4503. DPFX(DPFPREP, 0, "Problem adding endpoint 0x%p to connect socket port hash!",
  4504. pEndpoint );
  4505. //
  4506. // Nothing we can really do... We're hosed.
  4507. //
  4508. }
  4509. else
  4510. {
  4511. //
  4512. // Indicate the data via the new address.
  4513. //
  4514. UnlockEndpointData();
  4515. pEndpoint->ProcessUserData( pReadData );
  4516. pEndpoint->DecCommandRef();
  4517. }
  4518. }
  4519. else
  4520. {
  4521. UnlockEndpointData();
  4522. DPFX(DPFPREP, 3, "Endpoint 0x%p unbinding, not indicating data as proxied response.",
  4523. pEndpoint );
  4524. }
  4525. fDataClaimed = TRUE;
  4526. }
  4527. else
  4528. {
  4529. //
  4530. // Either there weren't any connects pending, or there
  4531. // were 2 or more so we couldn't pick.
  4532. //
  4533. fDataClaimed = FALSE;
  4534. }
  4535. }
  4536. else
  4537. #endif // ! DPNBUILD_NOWINSOCK2 or ! DPNBUILD_NOREGISTRY
  4538. {
  4539. //
  4540. // Not considering data as proxied.
  4541. //
  4542. fDataClaimed = FALSE;
  4543. }
  4544. if (! fDataClaimed)
  4545. {
  4546. //
  4547. // Make sure there is a listen, and isn't going away.
  4548. //
  4549. if ( m_pListenEndpoint != NULL )
  4550. {
  4551. if ( m_pListenEndpoint->AddCommandRef() )
  4552. {
  4553. pEndpoint = m_pListenEndpoint;
  4554. UnlockEndpointData();
  4555. //
  4556. // Make sure the source address is valid.
  4557. //
  4558. if (! pReadData->m_pSourceSocketAddress->IsValidUnicastAddress(FALSE))
  4559. {
  4560. pEndpoint->DecCommandRef();
  4561. DPFX(DPFPREP, 7, "Invalid source address, ignoring %u bytes of user data on listen.",
  4562. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4563. goto Exit;
  4564. }
  4565. #ifndef DPNBUILD_NOREGISTRY
  4566. //
  4567. // Make sure this wasn't sent by any banned address.
  4568. //
  4569. if (pReadData->m_pSourceSocketAddress->IsBannedAddress())
  4570. {
  4571. pEndpoint->DecCommandRef();
  4572. DPFX(DPFPREP, 6, "Ignoring %u bytes of user data on listen sent by banned address.",
  4573. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4574. goto Exit;
  4575. }
  4576. #endif // ! DPNBUILD_NOREGISTRY
  4577. pEndpoint->ProcessUserDataOnListen( pReadData, pReadData->m_pSourceSocketAddress );
  4578. pEndpoint->DecCommandRef();
  4579. }
  4580. else
  4581. {
  4582. UnlockEndpointData();
  4583. DPFX(DPFPREP, 3, "Listen endpoint 0x%p unbinding, not indicating new connection.",
  4584. m_pListenEndpoint );
  4585. }
  4586. }
  4587. else
  4588. {
  4589. //
  4590. // Nobody claimed this data.
  4591. //
  4592. UnlockEndpointData();
  4593. DPFX(DPFPREP, 1, "Ignoring %u bytes of user data, no listen is active.",
  4594. pReadData->ReceivedBuffer()->BufferDesc.dwBufferSize);
  4595. }
  4596. }
  4597. goto Exit;
  4598. }
  4599. //**********************************************************************