Source code of Windows XP (NT5)
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.

3089 lines
93 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. wshrm.c
  5. Abstract:
  6. This module contains necessary routines for the Pragmatic General Multicast
  7. (PGM) Windows Sockets Helper DLL. This DLL provides the transport-specific
  8. support necessary for the Windows Sockets DLL to use the PGM Transport.
  9. This file is largely a clone of the TCP/IP helper code.
  10. Author:
  11. Mohammad Shabbir Alam (MAlam) 30-March-2000
  12. Revision History:
  13. --*/
  14. #define UNICODE
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windef.h>
  19. #include <winbase.h>
  20. #include <stdio.h>
  21. #include <tdi.h>
  22. #include <winsock2.h>
  23. #include <wsahelp.h>
  24. #include <nspapi.h>
  25. #include <nspapip.h>
  26. #include <wsRm.h>
  27. #include <rmcommon.h>
  28. // #define TRACE_ON 1
  29. #if defined(DBG) && defined(TRACE_ON)
  30. #define PgmLog DbgPrint
  31. #define PgmError DbgPrint
  32. #else
  33. #if defined(DBG)
  34. #define PgmError DbgPrint
  35. #else
  36. #define PgmError
  37. #endif // DBG
  38. #define PgmLog
  39. #endif // DBG && TRACE_ON
  40. //----------------------------------------------------------------------------
  41. //
  42. // Structure and variables to define the triples supported by the
  43. // Pgm Transport. The first entry of each array is considered
  44. // the canonical triple for that socket type; the other entries are
  45. // synonyms for the first.
  46. //
  47. typedef struct _MAPPING_TRIPLE {
  48. INT AddressFamily;
  49. INT SocketType;
  50. INT Protocol;
  51. } MAPPING_TRIPLE, *PMAPPING_TRIPLE;
  52. MAPPING_TRIPLE PgmMappingTriples[] = { AF_INET, SOCK_RDM, IPPROTO_RM,
  53. AF_INET, SOCK_STREAM, IPPROTO_RM };
  54. //
  55. // Define valid flags for WSHOpenSocket2().
  56. //
  57. #define VALID_PGM_FLAGS (WSA_FLAG_OVERLAPPED | \
  58. WSA_FLAG_MULTIPOINT_C_LEAF | \
  59. WSA_FLAG_MULTIPOINT_D_LEAF)
  60. #define DD_PGM_DEVICE_NAME L"\\Device\\Pgm"
  61. #define PGM_NAME L"WSHRM"
  62. #define DEFAULT_RECEIVE_BUFFER_SIZE 8192
  63. #define DEFAULT_MULTICAST_TTL 1
  64. #define DEFAULT_MULTICAST_INTERFACE INADDR_ANY
  65. #define DEFAULT_MULTICAST_LOOPBACK TRUE
  66. #define WINSOCK_SPI_VERSION 2
  67. #define PGM_MESSAGE_SIZE (((ULONG)-1) / 2)
  68. #define IS_DGRAM_SOCK(type) (((type) == SOCK_DGRAM) || ((type) == SOCK_RAW))
  69. //
  70. // The GUID identifying this provider.
  71. //
  72. GUID PgmProviderGuid = { /* c845f828-500f-4e1e-87c2-5dfca19b5348 */
  73. 0xc845f828,
  74. 0x500f,
  75. 0x4e1e,
  76. {0x87, 0xc2, 0x5d, 0xfc, 0xa1, 0x9b, 0x53, 0x48}
  77. };
  78. /* ****
  79. XP1_CONNECTIONLESS ==> Sock type can only be: SOCK_DGRAM
  80. SOCK_RAW
  81. XP1_MESSAGE_ORIENTED ==> Sock type can only be: SOCK_DGRAM
  82. SOCK_RAW
  83. SOCK_RDM
  84. SOCK_SEQPACKET
  85. XP1_PSEUDO_STREAM <==> SOCK_STREAM
  86. **** */
  87. WSAPROTOCOL_INFOW Winsock2Protocols[] =
  88. {
  89. //
  90. // PGM RDM (SOCK_RDM cannot be CONNECTIONLESS)
  91. //
  92. {
  93. PGM_RDM_SERVICE_FLAGS, // dwServiceFlags1
  94. 0, // dwServiceFlags2
  95. 0, // dwServiceFlags3
  96. 0, // dwServiceFlags4
  97. PFL_MATCHES_PROTOCOL_ZERO, // dwProviderFlags
  98. { // gProviderId
  99. 0, 0, 0,
  100. { 0, 0, 0, 0, 0, 0, 0, 0 }
  101. },
  102. 0, // dwCatalogEntryId
  103. { // ProtocolChain
  104. BASE_PROTOCOL, // ChainLen
  105. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  106. },
  107. WINSOCK_SPI_VERSION, // iVersion
  108. AF_INET, // iAddressFamily
  109. sizeof(SOCKADDR_IN), // iMaxSockAddr
  110. sizeof(SOCKADDR_IN), // iMinSockAddr
  111. SOCK_RDM, // iSocketType
  112. IPPROTO_RM, // iProtocol
  113. 0, // iProtocolMaxOffset
  114. BIGENDIAN, // iNetworkByteOrder
  115. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  116. PGM_MESSAGE_SIZE, // dwMessageSize
  117. 0, // dwProviderReserved
  118. L"MSAFD Pgm (RDM)" // szProtocol
  119. },
  120. //
  121. // PGM Stream
  122. //
  123. {
  124. PGM_STREAM_SERVICE_FLAGS, // dwServiceFlags1
  125. 0, // dwServiceFlags2
  126. 0, // dwServiceFlags3
  127. 0, // dwServiceFlags4
  128. PFL_MATCHES_PROTOCOL_ZERO, // dwProviderFlags
  129. { // gProviderId
  130. 0, 0, 0,
  131. { 0, 0, 0, 0, 0, 0, 0, 0 }
  132. },
  133. 0, // dwCatalogEntryId
  134. { // ProtocolChain
  135. BASE_PROTOCOL, // ChainLen
  136. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  137. },
  138. WINSOCK_SPI_VERSION, // iVersion
  139. AF_INET, // iAddressFamily
  140. sizeof(SOCKADDR_IN), // iMaxSockAddr
  141. sizeof(SOCKADDR_IN), // iMinSockAddr
  142. SOCK_STREAM, // iSocketType
  143. IPPROTO_RM, // iProtocol
  144. 0, // iProtocolMaxOffset
  145. BIGENDIAN, // iNetworkByteOrder
  146. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  147. 0, // dwMessageSize
  148. 0, // dwProviderReserved
  149. L"MSAFD Pgm (Stream)" // szProtocol
  150. },
  151. };
  152. #define NUM_WINSOCK2_PROTOCOLS \
  153. (sizeof(Winsock2Protocols) / sizeof(Winsock2Protocols[0]))
  154. //
  155. // The socket context structure for this DLL. Each open TCP/IP socket
  156. // will have one of these context structures, which is used to maintain
  157. // information about the socket.
  158. //
  159. typedef struct _WSHPGM_SOCKET_CONTEXT {
  160. INT AddressFamily;
  161. INT SocketType;
  162. INT Protocol;
  163. INT ReceiveBufferSize;
  164. DWORD Flags;
  165. INT MulticastTtl;
  166. tIPADDRESS MulticastOutInterface;
  167. tIPADDRESS MulticastInInterface;
  168. tIPADDRESS MultipointTarget;
  169. USHORT MultipointPort;
  170. BOOLEAN MulticastLoopback;
  171. BOOLEAN MultipointLeaf;
  172. } WSHPGM_SOCKET_CONTEXT, *PWSHPGM_SOCKET_CONTEXT;
  173. //----------------------------------------------------------------------------
  174. //
  175. // Forward declarations of internal routines.
  176. //
  177. BOOLEAN
  178. IsTripleInList (
  179. IN PMAPPING_TRIPLE List,
  180. IN ULONG ListLength,
  181. IN INT AddressFamily,
  182. IN INT SocketType,
  183. IN INT Protocol
  184. );
  185. INT
  186. SetTdiInformation (
  187. IN HANDLE TdiConnectionObjectHandle,
  188. IN ULONG Ioctl,
  189. IN PVOID InputBuffer,
  190. IN ULONG InputBufferLength,
  191. IN PVOID OutputBuffer,
  192. IN ULONG OutputBufferLength,
  193. IN BOOLEAN WaitForCompletion
  194. );
  195. //----------------------------------------------------------------------------
  196. BOOLEAN
  197. DllInitialize(
  198. IN PVOID DllHandle,
  199. IN ULONG Reason,
  200. IN PVOID Context OPTIONAL
  201. )
  202. {
  203. PgmLog ("WSHPgm.DllInitialize: Reason=<%x> ...\n", Reason);
  204. switch (Reason)
  205. {
  206. case DLL_PROCESS_ATTACH:
  207. //
  208. // We don't need to receive thread attach and detach
  209. // notifications, so disable them to help application
  210. // performance.
  211. //
  212. DisableThreadLibraryCalls( DllHandle );
  213. return TRUE;
  214. case DLL_THREAD_ATTACH:
  215. break;
  216. case DLL_PROCESS_DETACH:
  217. break;
  218. case DLL_THREAD_DETACH:
  219. break;
  220. }
  221. return TRUE;
  222. } // DllInitialize
  223. //----------------------------------------------------------------------------
  224. INT
  225. WSHOpenSocket(
  226. IN OUT PINT AddressFamily,
  227. IN OUT PINT SocketType,
  228. IN OUT PINT Protocol,
  229. OUT PUNICODE_STRING TransportDeviceName,
  230. OUT PVOID *HelperDllSocketContext,
  231. OUT PDWORD NotificationEvents
  232. )
  233. {
  234. INT RetVal;
  235. RetVal = WSHOpenSocket2 (AddressFamily,
  236. SocketType,
  237. Protocol,
  238. 0, // Group
  239. 0, // Flags
  240. TransportDeviceName,
  241. HelperDllSocketContext,
  242. NotificationEvents);
  243. return (RetVal);
  244. } // WSHOpenSocket
  245. INT
  246. WSHOpenSocket2(
  247. IN OUT PINT AddressFamily,
  248. IN OUT PINT SocketType,
  249. IN OUT PINT Protocol,
  250. IN GROUP Group,
  251. IN DWORD Flags,
  252. OUT PUNICODE_STRING TransportDeviceName,
  253. OUT PVOID *HelperDllSocketContext,
  254. OUT PDWORD NotificationEvents
  255. )
  256. /*++
  257. Routine Description:
  258. Does the necessary work for this helper DLL to open a socket and is
  259. called by the winsock DLL in the socket() routine. This routine
  260. verifies that the specified triple is valid, determines the NT
  261. device name of the TDI provider that will support that triple,
  262. allocates space to hold the socket's context block, and
  263. canonicalizes the triple.
  264. Arguments:
  265. AddressFamily - on input, the address family specified in the
  266. socket() call. On output, the canonicalized value for the
  267. address family.
  268. SocketType - on input, the socket type specified in the socket()
  269. call. On output, the canonicalized value for the socket type.
  270. Protocol - on input, the protocol specified in the socket() call.
  271. On output, the canonicalized value for the protocol.
  272. Group - Identifies the group for the new socket.
  273. Flags - Zero or more WSA_FLAG_* flags as passed into WSASocket().
  274. TransportDeviceName - receives the name of the TDI provider that
  275. will support the specified triple.
  276. HelperDllSocketContext - receives a context pointer that the winsock
  277. DLL will return to this helper DLL on future calls involving
  278. this socket.
  279. NotificationEvents - receives a bitmask of those state transitions
  280. this helper DLL should be notified on.
  281. Return Value:
  282. INT - a winsock error code indicating the status of the operation, or
  283. NO_ERROR if the operation succeeded.
  284. --*/
  285. {
  286. PWSHPGM_SOCKET_CONTEXT context;
  287. if (IsTripleInList (PgmMappingTriples,
  288. sizeof(PgmMappingTriples) / sizeof(PgmMappingTriples[0]),
  289. *AddressFamily,
  290. *SocketType,
  291. *Protocol))
  292. {
  293. //
  294. // It's an Rdm PGM socket. Check the flags.
  295. //
  296. if ((Flags & ~VALID_PGM_FLAGS) != 0)
  297. {
  298. PgmError ("\tWSHPgm.WSHOpenSocket2: ERROR: Flags=<%x> & VALID_PGM_FLAGS=<%x>\n",
  299. Flags, (ULONG)~VALID_PGM_FLAGS);
  300. return WSAEINVAL;
  301. }
  302. //
  303. // Return the canonical form of a CDP socket triple.
  304. //
  305. *AddressFamily = PgmMappingTriples[0].AddressFamily;
  306. *SocketType = PgmMappingTriples[0].SocketType;
  307. *Protocol = PgmMappingTriples[0].Protocol;
  308. //
  309. // Indicate the name of the TDI device that will service
  310. // SOCK_RDM sockets for PGM.
  311. //
  312. RtlInitUnicodeString (TransportDeviceName, DD_PGM_DEVICE_NAME);
  313. }
  314. else
  315. {
  316. //
  317. // This should never happen if the registry information about this
  318. // helper DLL is correct. If somehow this did happen, just return
  319. // an error.
  320. //
  321. PgmError ("\tWSHPgm.WSHOpenSocket2: Invalid Triple AddrFamily=<%d>, SockType=<%d>, Protocol=<%d>!\n",
  322. *AddressFamily, *SocketType, *Protocol);
  323. return WSAEINVAL;
  324. }
  325. //
  326. // Allocate context for this socket. The Windows Sockets DLL will
  327. // return this value to us when it asks us to get/set socket options.
  328. //
  329. context = RtlAllocateHeap (RtlProcessHeap( ), 0, sizeof(*context));
  330. if (context == NULL)
  331. {
  332. PgmError ("WSHPgm.WSHOpenSocket2: WSAENOBUFS -- <%d> bytes\n", sizeof(*context));
  333. return WSAENOBUFS;
  334. }
  335. RtlZeroMemory (context, sizeof(*context));
  336. //
  337. // Initialize the context for the socket.
  338. //
  339. context->AddressFamily = *AddressFamily;
  340. context->SocketType = *SocketType;
  341. context->Protocol = *Protocol;
  342. context->ReceiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
  343. context->Flags = Flags;
  344. context->MulticastTtl = DEFAULT_MULTICAST_TTL;
  345. context->MulticastOutInterface = DEFAULT_MULTICAST_INTERFACE;
  346. context->MulticastInInterface = DEFAULT_MULTICAST_INTERFACE;
  347. context->MulticastLoopback = DEFAULT_MULTICAST_LOOPBACK;
  348. context->MultipointLeaf = FALSE;
  349. //
  350. // Tell the Windows Sockets DLL which state transitions we're
  351. // interested in being notified of. The only times we need to be
  352. // called is after a connect has completed so that we can turn on
  353. // the sending of keepalives if SO_KEEPALIVE was set before the
  354. // socket was connected, when the socket is closed so that we can
  355. // free context information, and when a connect fails so that we
  356. // can, if appropriate, dial in to the network that will support the
  357. // connect attempt.
  358. //
  359. if (*SocketType == SOCK_RDM)
  360. {
  361. *NotificationEvents = WSH_NOTIFY_LISTEN | WSH_NOTIFY_CONNECT | WSH_NOTIFY_CLOSE
  362. | WSH_NOTIFY_CONNECT_ERROR | WSH_NOTIFY_BIND;
  363. }
  364. else // *SocketType == SOCK_STREAM
  365. {
  366. *NotificationEvents = WSH_NOTIFY_LISTEN | WSH_NOTIFY_CONNECT | WSH_NOTIFY_CLOSE
  367. | WSH_NOTIFY_CONNECT_ERROR;
  368. }
  369. PgmLog ("WSHPgm.WSHOpenSocket2: Succeeded -- %s\n",
  370. (*SocketType == SOCK_RDM ? "SOCK_RDM" : "SOCK_STREAM"));
  371. //
  372. // Everything worked, return success.
  373. //
  374. *HelperDllSocketContext = context;
  375. return NO_ERROR;
  376. } // WSHOpenSocket2
  377. //----------------------------------------------------------------------------
  378. INT
  379. WSHNotify (
  380. IN PVOID HelperDllSocketContext,
  381. IN SOCKET SocketHandle,
  382. IN HANDLE TdiAddressObjectHandle,
  383. IN HANDLE TdiConnectionObjectHandle,
  384. IN DWORD NotifyEvent
  385. )
  386. /*++
  387. Routine Description:
  388. This routine is called by the winsock DLL after a state transition
  389. of the socket. Only state transitions returned in the
  390. NotificationEvents parameter of WSHOpenSocket() are notified here.
  391. This routine allows a winsock helper DLL to track the state of
  392. socket and perform necessary actions corresponding to state
  393. transitions.
  394. Arguments:
  395. HelperDllSocketContext - the context pointer given to the winsock
  396. DLL by WSHOpenSocket().
  397. SocketHandle - the handle for the socket.
  398. TdiAddressObjectHandle - the TDI address object of the socket, if
  399. any. If the socket is not yet bound to an address, then
  400. it does not have a TDI address object and this parameter
  401. will be NULL.
  402. TdiConnectionObjectHandle - the TDI connection object of the socket,
  403. if any. If the socket is not yet connected, then it does not
  404. have a TDI connection object and this parameter will be NULL.
  405. NotifyEvent - indicates the state transition for which we're being
  406. called.
  407. Return Value:
  408. INT - a winsock error code indicating the status of the operation, or
  409. NO_ERROR if the operation succeeded.
  410. --*/
  411. {
  412. PWSHPGM_SOCKET_CONTEXT context = HelperDllSocketContext;
  413. INT err;
  414. //
  415. // We should only be called after a connect() completes or when the
  416. // socket is being closed.
  417. //
  418. if (NotifyEvent == WSH_NOTIFY_BIND)
  419. {
  420. //
  421. // Set options for Address handle
  422. //
  423. PgmLog ("WSHPgm.WSHNotify[WSH_NOTIFY_BIND]: ...\n");
  424. if (!context->MultipointLeaf)
  425. {
  426. tPGM_MCAST_REQUEST MCastRequest;
  427. PgmLog ("WSH_NOTIFY_BIND: Address=<%x>, Connection=<%x>, OutIf=<%x>, InIf=<%x>\n",
  428. TdiAddressObjectHandle, TdiConnectionObjectHandle, context->MulticastOutInterface,
  429. context->MulticastInInterface);
  430. if (context->MulticastOutInterface)
  431. {
  432. MCastRequest.MCastOutIf = context->MulticastOutInterface;
  433. err = SetTdiInformation (TdiAddressObjectHandle,
  434. IOCTL_PGM_WSH_SET_SEND_IF,
  435. &MCastRequest,
  436. sizeof (MCastRequest),
  437. NULL,
  438. 0,
  439. TRUE);
  440. if (err != NO_ERROR)
  441. {
  442. PgmError ("WSHPgm.WSHNotify: Error=<%x> setting MCastIf on Bind\n", err);
  443. return err;
  444. }
  445. }
  446. if (context->MulticastInInterface)
  447. {
  448. MCastRequest.MCastInfo.MCastInIf = context->MulticastInInterface;
  449. err = SetTdiInformation (TdiAddressObjectHandle,
  450. IOCTL_PGM_WSH_ADD_RECEIVE_IF,
  451. &MCastRequest,
  452. sizeof (MCastRequest),
  453. NULL,
  454. 0,
  455. TRUE);
  456. if (err != NO_ERROR)
  457. {
  458. PgmError ("WSHPgm.WSHNotify: Error=<%x> setting MCastIf on Bind\n", err);
  459. return err;
  460. }
  461. }
  462. context->MultipointLeaf = TRUE;
  463. }
  464. }
  465. else if (NotifyEvent == WSH_NOTIFY_CONNECT)
  466. {
  467. //
  468. // If a connection-object option was set on the socket before
  469. // it was connected, set the option for real now.
  470. //
  471. PgmLog ("WSHPgm.WSHNotify[WSH_NOTIFY_CONNECT]: ...\n");
  472. }
  473. else if (NotifyEvent == WSH_NOTIFY_CONNECT_ERROR)
  474. {
  475. //
  476. // Return WSATRY_AGAIN to get wsock32 to attempt the connect
  477. // again. Any other return code is ignored.
  478. //
  479. PgmLog ("WSHPgm.WSHNotify[WSH_NOTIFY_CONNECT_ERROR]: ...\n");
  480. }
  481. else if (NotifyEvent == WSH_NOTIFY_LISTEN)
  482. {
  483. //
  484. // If a connection-object option was set on the socket before
  485. // it was connected, set the option for real now.
  486. //
  487. PgmLog ("WSHPgm.WSHNotify[WSH_NOTIFY_LISTEN]: ...\n");
  488. }
  489. else if (NotifyEvent == WSH_NOTIFY_CLOSE)
  490. {
  491. //
  492. // Free the socket context.
  493. //
  494. PgmLog ("WSHPgm.WSHNotify[WSH_NOTIFY_CONNECT_CLOSE]: ...\n");
  495. RtlFreeHeap (RtlProcessHeap( ), 0, context);
  496. }
  497. else
  498. {
  499. PgmError ("WSHPgm.WSHNotify: Unknown Event: <%x> ...\n", NotifyEvent);
  500. return WSAEINVAL;
  501. }
  502. return NO_ERROR;
  503. } // WSHNotify
  504. //----------------------------------------------------------------------------
  505. INT
  506. WSHSetSocketInformation (
  507. IN PVOID HelperDllSocketContext,
  508. IN SOCKET SocketHandle,
  509. IN HANDLE TdiAddressObjectHandle,
  510. IN HANDLE TdiConnectionObjectHandle,
  511. IN INT Level,
  512. IN INT OptionName,
  513. IN PCHAR OptionValue,
  514. IN INT OptionLength
  515. )
  516. /*++
  517. Routine Description:
  518. This routine sets information about a socket for those socket
  519. options supported in this helper DLL. This routine is
  520. called by the winsock DLL when a level/option name combination is
  521. passed to setsockopt() that the winsock DLL does not understand.
  522. Arguments:
  523. HelperDllSocketContext - the context pointer returned from
  524. WSHOpenSocket().
  525. SocketHandle - the handle of the socket for which we're getting
  526. information.
  527. TdiAddressObjectHandle - the TDI address object of the socket, if
  528. any. If the socket is not yet bound to an address, then
  529. it does not have a TDI address object and this parameter
  530. will be NULL.
  531. TdiConnectionObjectHandle - the TDI connection object of the socket,
  532. if any. If the socket is not yet connected, then it does not
  533. have a TDI connection object and this parameter will be NULL.
  534. Level - the level parameter passed to setsockopt().
  535. OptionName - the optname parameter passed to setsockopt().
  536. OptionValue - the optval parameter passed to setsockopt().
  537. OptionLength - the optlen parameter passed to setsockopt().
  538. Return Value:
  539. INT - a winsock error code indicating the status of the operation, or
  540. NO_ERROR if the operation succeeded.
  541. --*/
  542. {
  543. PWSHPGM_SOCKET_CONTEXT context = HelperDllSocketContext;
  544. PWSHPGM_SOCKET_CONTEXT ParentContext = (PWSHPGM_SOCKET_CONTEXT) OptionValue;
  545. tPGM_MCAST_REQUEST MCastRequest;
  546. INT error;
  547. INT optionValue;
  548. RM_SEND_WINDOW UNALIGNED *pSetWindowInfo;
  549. RM_FEC_INFO *pFECInfo;
  550. UNREFERENCED_PARAMETER( SocketHandle );
  551. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  552. //
  553. // Check if this is an internal request for context information.
  554. //
  555. if (Level == SOL_INTERNAL && OptionName == SO_CONTEXT)
  556. {
  557. //
  558. // Insure that the context information being passed to us is
  559. // sufficiently large.
  560. //
  561. if (OptionLength < sizeof(*context))
  562. {
  563. PgmError ("WSHPgm.WSHSetSocketInformation: WSAEINVAL -- <%d> < <%d>\n",
  564. OptionLength, sizeof(*context));
  565. return WSAEINVAL;
  566. }
  567. if (HelperDllSocketContext == NULL)
  568. {
  569. //
  570. // This is our notification that a socket handle was
  571. // inherited or duped into this process. Allocate a context
  572. // structure for the new socket.
  573. //
  574. context = RtlAllocateHeap (RtlProcessHeap( ), 0, sizeof(*context));
  575. if (context == NULL)
  576. {
  577. PgmError ("WSHPgm.WSHSetSocketInformation: WSAENOBUFS -- <%d> bytes\n", sizeof(*context));
  578. return WSAENOBUFS;
  579. }
  580. //
  581. // Copy over information into the context block.
  582. //
  583. RtlCopyMemory (context, OptionValue, sizeof(*context) );
  584. //
  585. // Tell the Windows Sockets DLL where our context information is
  586. // stored so that it can return the context pointer in future
  587. // calls.
  588. //
  589. *(PWSHPGM_SOCKET_CONTEXT *)OptionValue = context;
  590. PgmLog ("WSHPgm.WSHSetSocketInformation[SOL_INTERNAL:SO_CONTEXT] Inherited socket handle\n");
  591. return NO_ERROR;
  592. }
  593. //
  594. // The socket was accept()'ed and it needs to have the same
  595. // properties as it's parent. The OptionValue buffer
  596. // contains the context information of this socket's parent.
  597. //
  598. ParentContext = (PWSHPGM_SOCKET_CONTEXT)OptionValue;
  599. ASSERT( context->AddressFamily == ParentContext->AddressFamily );
  600. ASSERT( context->SocketType == ParentContext->SocketType );
  601. ASSERT( context->Protocol == ParentContext->Protocol );
  602. //
  603. // Record this fact in the leaf socket so we can drop membership
  604. // when the leaf socket is closed.
  605. //
  606. context->MultipointLeaf = ParentContext->MultipointLeaf;
  607. context->MultipointTarget = ParentContext->MultipointTarget;
  608. context->MultipointPort = ParentContext->MultipointPort;
  609. context->MulticastOutInterface = ParentContext->MulticastOutInterface;
  610. context->MulticastInInterface = ParentContext->MulticastInInterface;
  611. PgmLog ("WSHPgm.WSHSetSocketInformation[SOL_INTERNAL:SO_CONTEXT] Accepted socket handle\n");
  612. return NO_ERROR;
  613. }
  614. //
  615. // The only other levels we support here are SOL_SOCKET and IPPROTO_RM
  616. //
  617. if (Level != SOL_SOCKET &&
  618. Level != IPPROTO_RM)
  619. {
  620. PgmError ("WSHPgm.WSHSetSocketInformation: Unsupported Level=<%d>\n", Level);
  621. return WSAEINVAL;
  622. }
  623. //
  624. // Make sure that the option length is sufficient.
  625. //
  626. if (OptionLength < sizeof(char))
  627. {
  628. PgmError ("WSHPgm.WSHSetSocketInformation: OptionLength=<%d> < <%d>\n", OptionLength, sizeof(char));
  629. return WSAEFAULT;
  630. }
  631. if (OptionLength >= sizeof (int))
  632. {
  633. optionValue = *((INT UNALIGNED *)OptionValue);
  634. }
  635. else
  636. {
  637. optionValue = (UCHAR)*OptionValue;
  638. }
  639. if (Level == IPPROTO_RM)
  640. {
  641. //
  642. // Act based on the specific option.
  643. //
  644. switch (OptionName)
  645. {
  646. case RM_RATE_WINDOW_SIZE:
  647. {
  648. if ((!TdiAddressObjectHandle) ||
  649. (OptionLength < sizeof(RM_SEND_WINDOW)))
  650. {
  651. return WSAEINVAL;
  652. }
  653. pSetWindowInfo = (RM_SEND_WINDOW UNALIGNED *) OptionValue;
  654. MCastRequest.TransmitWindowInfo.RateKbitsPerSec = pSetWindowInfo->RateKbitsPerSec;
  655. MCastRequest.TransmitWindowInfo.WindowSizeInMSecs = pSetWindowInfo->WindowSizeInMSecs;
  656. MCastRequest.TransmitWindowInfo.WindowSizeInBytes = pSetWindowInfo->WindowSizeInBytes;
  657. error = SetTdiInformation (TdiAddressObjectHandle,
  658. IOCTL_PGM_WSH_SET_WINDOW_SIZE_RATE,
  659. &MCastRequest,
  660. sizeof (MCastRequest),
  661. NULL,
  662. 0,
  663. TRUE);
  664. if (error != NO_ERROR)
  665. {
  666. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> setting Window Rate Size=<%x>\n",
  667. error, optionValue);
  668. return error;
  669. }
  670. PgmLog ("WSHSetSocketInformation[RATE_WINDOW_SIZE]: Set Window Rate Size\n");
  671. return (NO_ERROR);
  672. }
  673. case RM_SEND_WINDOW_ADV_RATE:
  674. {
  675. if (!TdiAddressObjectHandle)
  676. {
  677. return WSAEINVAL;
  678. }
  679. MCastRequest.WindowAdvancePercentage = (ULONG) optionValue;
  680. error = SetTdiInformation (TdiAddressObjectHandle,
  681. IOCTL_PGM_WSH_SET_ADVANCE_WINDOW_RATE,
  682. &MCastRequest,
  683. sizeof (MCastRequest),
  684. NULL,
  685. 0,
  686. TRUE);
  687. if (error != NO_ERROR)
  688. {
  689. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> setting Window Adv. Rate=<%x>\n",
  690. error, optionValue);
  691. return error;
  692. }
  693. PgmLog ("WSHSetSocketInformation[SEND_WINDOW_ADV_RATE]: Set Window Adv. Rate\n");
  694. return (NO_ERROR);
  695. }
  696. case RM_LATEJOIN:
  697. {
  698. if (!TdiAddressObjectHandle)
  699. {
  700. return WSAEINVAL;
  701. }
  702. MCastRequest.LateJoinerPercentage = (ULONG) optionValue;
  703. error = SetTdiInformation (TdiAddressObjectHandle,
  704. IOCTL_PGM_WSH_SET_LATE_JOINER_PERCENTAGE,
  705. &MCastRequest,
  706. sizeof (MCastRequest),
  707. NULL,
  708. 0,
  709. TRUE);
  710. if (error != NO_ERROR)
  711. {
  712. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> setting LATEJOIN=<%x>\n",
  713. error, optionValue);
  714. return error;
  715. }
  716. PgmLog ("WSHSetSocketInformation[LATEJOIN]: <%d %%>\n", MCastRequest.LateJoinerPercentage);
  717. return (NO_ERROR);
  718. }
  719. case RM_SET_MESSAGE_BOUNDARY:
  720. {
  721. if (!TdiConnectionObjectHandle)
  722. {
  723. return WSAEINVAL;
  724. }
  725. MCastRequest.NextMessageBoundary = (ULONG) optionValue;
  726. error = SetTdiInformation (TdiConnectionObjectHandle,
  727. IOCTL_PGM_WSH_SET_NEXT_MESSAGE_BOUNDARY,
  728. &MCastRequest,
  729. sizeof (MCastRequest),
  730. NULL,
  731. 0,
  732. TRUE);
  733. if (error != NO_ERROR)
  734. {
  735. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> setting NextMessageBoundary=<%x>\n",
  736. error, optionValue);
  737. return error;
  738. }
  739. PgmLog ("WSHSetSocketInformation[MESSAGE_BOUNDARY]: Set next message boundary = <%d>\n",
  740. MCastRequest.NextMessageBoundary);
  741. return (NO_ERROR);
  742. }
  743. case RM_SET_SEND_IF:
  744. {
  745. //
  746. // If we have a TDI address object, set this option to
  747. // the address object. If we don't have a TDI address
  748. // object then we'll have to wait until after the socket
  749. // is bound.
  750. //
  751. PgmLog ("WSHSetSocketInformation[SEND_IF]: Address=<%x>, Connection=<%x>, OutIf=<%x>\n",
  752. TdiAddressObjectHandle, TdiConnectionObjectHandle, optionValue);
  753. if (TdiAddressObjectHandle != NULL)
  754. {
  755. MCastRequest.MCastOutIf = * ((tIPADDRESS *) &optionValue);
  756. error = SetTdiInformation (TdiAddressObjectHandle,
  757. IOCTL_PGM_WSH_SET_SEND_IF,
  758. &MCastRequest,
  759. sizeof (MCastRequest),
  760. NULL,
  761. 0,
  762. TRUE);
  763. if (error != NO_ERROR)
  764. {
  765. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> setting MCastOutIf=<%x>\n",
  766. error, optionValue);
  767. return error;
  768. }
  769. PgmLog ("WSHPgm.WSHSetSocketInformation[SEND_IF]: Set MCastIf=<%x>\n",optionValue);
  770. context->MulticastOutInterface = optionValue;
  771. }
  772. else
  773. {
  774. //
  775. // Save the Interface for now!
  776. //
  777. context->MulticastOutInterface = optionValue;
  778. PgmError ("WSHPgm.WSHSetSocketInformation[SET_SEND_IF]: WARNING -- NULL Address!\n");
  779. }
  780. return (NO_ERROR);
  781. }
  782. case RM_ADD_RECEIVE_IF:
  783. {
  784. PgmLog ("WSHSetSocketInformation[ADD_RECEIVE_IF]: Address=<%x>, Connection=<%x>, If=<%x>\n",
  785. TdiAddressObjectHandle, TdiConnectionObjectHandle, optionValue);
  786. //
  787. // If we have a TDI address object, set this option to
  788. // the address object. If we don't have a TDI address
  789. // object then we'll have to wait until after the socket
  790. // is bound.
  791. //
  792. if (TdiAddressObjectHandle != NULL)
  793. {
  794. MCastRequest.MCastInfo.MCastInIf = * ((tIPADDRESS *) &optionValue);
  795. error = SetTdiInformation (TdiAddressObjectHandle,
  796. IOCTL_PGM_WSH_ADD_RECEIVE_IF,
  797. &MCastRequest,
  798. sizeof (MCastRequest),
  799. NULL,
  800. 0,
  801. TRUE);
  802. if (error != NO_ERROR)
  803. {
  804. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> adding MCastInIf=<%x>\n",
  805. error, optionValue);
  806. return error;
  807. }
  808. PgmLog ("WSHSetSocketInformation[ADD_RECEIVE_IF]: Set MCastIf=<%x>\n",optionValue);
  809. context->MulticastInInterface = optionValue;
  810. }
  811. else
  812. {
  813. //
  814. // Save the Interface for now!
  815. //
  816. context->MulticastInInterface = optionValue;
  817. PgmError ("WSHPgm.WSHSetSocketInformation[ADD_RECEIVE_IF]: WARNING-- NULL Address!\n");
  818. }
  819. return (NO_ERROR);
  820. }
  821. case RM_DEL_RECEIVE_IF:
  822. {
  823. PgmLog ("WSHSetSocketInformation[DEL_RECEIVE_IF]: Address=<%x>, Connection=<%x>, InIf=<%x>\n",
  824. TdiAddressObjectHandle, TdiConnectionObjectHandle, optionValue);
  825. //
  826. // If we have a TDI address object, set this option to
  827. // the address object. If we don't have a TDI address
  828. // object then we'll have to wait until after the socket
  829. // is bound.
  830. //
  831. if (TdiAddressObjectHandle != NULL)
  832. {
  833. MCastRequest.MCastInfo.MCastInIf = * ((tIPADDRESS *) &optionValue);
  834. error = SetTdiInformation (TdiAddressObjectHandle,
  835. IOCTL_PGM_WSH_DEL_RECEIVE_IF,
  836. &MCastRequest,
  837. sizeof (MCastRequest),
  838. NULL,
  839. 0,
  840. TRUE);
  841. if (error != NO_ERROR)
  842. {
  843. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> deleting MCastInIf=<%x>\n",
  844. error, optionValue);
  845. return error;
  846. }
  847. PgmLog ("WSHSetSocketInformation[DEL_RECEIVE_IF]: Set MCastIf=<%x>\n",optionValue);
  848. context->MulticastInInterface = optionValue;
  849. }
  850. else
  851. {
  852. if (context->MulticastInInterface == (tIPADDRESS) optionValue)
  853. {
  854. context->MulticastInInterface = 0;
  855. }
  856. PgmError ("WSHPgm.WSHSetSocketInformation[DEL_RECEIVE_IF]: WARNING-- NULL Address!\n");
  857. }
  858. return (NO_ERROR);
  859. }
  860. case RM_USE_FEC:
  861. {
  862. if ((!TdiAddressObjectHandle) ||
  863. (OptionLength < sizeof(RM_FEC_INFO)))
  864. {
  865. return WSAEINVAL;
  866. }
  867. pFECInfo = (RM_FEC_INFO *) OptionValue;
  868. MCastRequest.FECInfo.FECBlockSize = pFECInfo->FECBlockSize;
  869. MCastRequest.FECInfo.FECProActivePackets = pFECInfo->FECProActivePackets;
  870. MCastRequest.FECInfo.FECGroupSize = pFECInfo->FECGroupSize;
  871. MCastRequest.FECInfo.fFECOnDemandParityEnabled = pFECInfo->fFECOnDemandParityEnabled;
  872. error = SetTdiInformation (TdiAddressObjectHandle,
  873. IOCTL_PGM_WSH_USE_FEC,
  874. &MCastRequest,
  875. sizeof (MCastRequest),
  876. NULL,
  877. 0,
  878. TRUE);
  879. if (error != NO_ERROR)
  880. {
  881. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> setting FEC = <%x>\n",
  882. error, optionValue);
  883. return error;
  884. }
  885. PgmLog ("WSHSetSocketInformation[RATE_WINDOW_SIZE]: Set FEC Info\n");
  886. return (NO_ERROR);
  887. }
  888. case RM_SET_MCAST_TTL:
  889. {
  890. if (!TdiAddressObjectHandle)
  891. {
  892. return WSAEINVAL;
  893. }
  894. MCastRequest.MCastTtl = (ULONG) optionValue;
  895. error = SetTdiInformation (TdiAddressObjectHandle,
  896. IOCTL_PGM_WSH_SET_MCAST_TTL,
  897. &MCastRequest,
  898. sizeof (MCastRequest),
  899. NULL,
  900. 0,
  901. TRUE);
  902. if (error != NO_ERROR)
  903. {
  904. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> setting MCastTtl=<%x>\n",
  905. error, optionValue);
  906. return error;
  907. }
  908. PgmLog ("WSHSetSocketInformation[MESSAGE_BOUNDARY]: Set MCastTtl = <%d>\n",
  909. MCastRequest.MCastTtl);
  910. return (NO_ERROR);
  911. }
  912. case RM_SENDER_WINDOW_ADVANCE_METHOD:
  913. {
  914. if (!TdiAddressObjectHandle)
  915. {
  916. return WSAEINVAL;
  917. }
  918. MCastRequest.WindowAdvanceMethod = (ULONG) optionValue;
  919. error = SetTdiInformation (TdiAddressObjectHandle,
  920. IOCTL_PGM_WSH_SET_WINDOW_ADVANCE_METHOD,
  921. &MCastRequest,
  922. sizeof (MCastRequest),
  923. NULL,
  924. 0,
  925. TRUE);
  926. if (error != NO_ERROR)
  927. {
  928. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> setting WindowAdvanceMethod=<%x>\n",
  929. error, optionValue);
  930. return error;
  931. }
  932. PgmLog ("WSHSetSocketInformation[WINDOW_ADVANCE_METHOD]: Set WindowAdvanceMethod = <%d>\n",
  933. MCastRequest.WindowAdvanceMethod);
  934. return (NO_ERROR);
  935. }
  936. default:
  937. {
  938. PgmError ("WSHPgm.WSHSetSocketInformation[IPPROTO_RM]: Unsupported option=<%d>\n",OptionName);
  939. error = WSAENOPROTOOPT;
  940. break;
  941. }
  942. }
  943. }
  944. else
  945. {
  946. //
  947. // Handle socket-level options.
  948. //
  949. switch (OptionName)
  950. {
  951. case SO_RCVBUF:
  952. {
  953. //
  954. // If the receive buffer size is being changed, tell PGM about
  955. // it. Do nothing if this is a datagram.
  956. //
  957. if (context->ReceiveBufferSize == optionValue ||
  958. IS_DGRAM_SOCK(context->SocketType))
  959. {
  960. error = NO_ERROR;
  961. break;
  962. }
  963. PgmLog ("WSHSetSocketInformation[SO_RCVBUF]: Address=<%x>, Connection=<%x>, BuffLen=<%x>\n",
  964. TdiAddressObjectHandle, TdiConnectionObjectHandle, optionValue);
  965. if ((TdiConnectionObjectHandle != NULL) &&
  966. (OptionLength <= sizeof (int)))
  967. {
  968. MCastRequest.RcvBufferLength = optionValue;
  969. error = SetTdiInformation (TdiConnectionObjectHandle,
  970. IOCTL_PGM_WSH_SET_RCV_BUFF_LEN,
  971. &MCastRequest,
  972. sizeof (MCastRequest),
  973. NULL,
  974. 0,
  975. TRUE);
  976. if (error != NO_ERROR)
  977. {
  978. PgmError ("WSHPgm.WSHSetSocketInformation: ERROR=<%d> setting SO_RCVBUF=<%x>\n",
  979. error, optionValue);
  980. return error;
  981. }
  982. }
  983. PgmLog ("WSHSetSocketInformation[SOL_SOCKET]: Set SO_RCVBUF=<%x>\n", optionValue);
  984. context->ReceiveBufferSize = optionValue;
  985. break;
  986. }
  987. default:
  988. {
  989. PgmError ("WSHPgm.WSHSetSocketInformation[SOL_SOCKET]: Unsupported Option=<%d>\n",OptionName);
  990. error = WSAENOPROTOOPT;
  991. break;
  992. }
  993. }
  994. }
  995. return error;
  996. } // WSHSetSocketInformation
  997. //----------------------------------------------------------------------------
  998. INT
  999. WSHGetSocketInformation (
  1000. IN PVOID HelperDllSocketContext,
  1001. IN SOCKET SocketHandle,
  1002. IN HANDLE TdiAddressObjectHandle,
  1003. IN HANDLE TdiConnectionObjectHandle,
  1004. IN INT Level,
  1005. IN INT OptionName,
  1006. OUT PCHAR OptionValue,
  1007. OUT PINT OptionLength
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. This routine retrieves information about a socket for those socket
  1012. options supported in this helper DLL. This routine is
  1013. called by the winsock DLL when a level/option name combination is
  1014. passed to getsockopt() that the winsock DLL does not understand.
  1015. Arguments:
  1016. HelperDllSocketContext - the context pointer returned from
  1017. WSHOpenSocket().
  1018. SocketHandle - the handle of the socket for which we're getting
  1019. information.
  1020. TdiAddressObjectHandle - the TDI address object of the socket, if
  1021. any. If the socket is not yet bound to an address, then
  1022. it does not have a TDI address object and this parameter
  1023. will be NULL.
  1024. TdiConnectionObjectHandle - the TDI connection object of the socket,
  1025. if any. If the socket is not yet connected, then it does not
  1026. have a TDI connection object and this parameter will be NULL.
  1027. Level - the level parameter passed to getsockopt().
  1028. OptionName - the optname parameter passed to getsockopt().
  1029. OptionValue - the optval parameter passed to getsockopt().
  1030. OptionLength - the optlen parameter passed to getsockopt().
  1031. Return Value:
  1032. INT - a winsock error code indicating the status of the operation, or
  1033. NO_ERROR if the operation succeeded.
  1034. --*/
  1035. {
  1036. PWSHPGM_SOCKET_CONTEXT context = HelperDllSocketContext;
  1037. tPGM_MCAST_REQUEST MCastRequest;
  1038. RM_SEND_WINDOW UNALIGNED *pSetWindowInfo;
  1039. RM_FEC_INFO UNALIGNED *pFECInfo;
  1040. RM_SENDER_STATS UNALIGNED *pSenderStats;
  1041. RM_RECEIVER_STATS UNALIGNED *pReceiverStats;
  1042. INT error;
  1043. UNREFERENCED_PARAMETER( HelperDllSocketContext );
  1044. UNREFERENCED_PARAMETER( SocketHandle );
  1045. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  1046. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  1047. //
  1048. // Check if this is an internal request for context information.
  1049. //
  1050. if (Level == SOL_INTERNAL && OptionName == SO_CONTEXT)
  1051. {
  1052. //
  1053. // The Windows Sockets DLL is requesting context information
  1054. // from us. If an output buffer was not supplied, the Windows
  1055. // Sockets DLL is just requesting the size of our context
  1056. // information.
  1057. //
  1058. if (OptionValue != NULL)
  1059. {
  1060. //
  1061. // Make sure that the buffer is sufficient to hold all the
  1062. // context information.
  1063. //
  1064. if (*OptionLength < sizeof(*context))
  1065. {
  1066. PgmLog ("WSHPgm.WSHGetSocketInformation: OptionLength=<%d> < ContextLength=<%d>\n",
  1067. *OptionLength, sizeof(*context));
  1068. return WSAEFAULT;
  1069. }
  1070. //
  1071. // Copy in the context information.
  1072. //
  1073. RtlCopyMemory( OptionValue, context, sizeof(*context) );
  1074. }
  1075. *OptionLength = sizeof(*context);
  1076. PgmLog ("WSHPgm.WSHGetSocketInformation[SOL_INTERNAL:SO_CONTEXT]: OptionLength=<%d>\n",
  1077. *OptionLength);
  1078. return NO_ERROR;
  1079. }
  1080. //
  1081. // The only other levels we support here are SOL_SOCKET and IPPROTO_RM
  1082. //
  1083. if (Level != SOL_SOCKET &&
  1084. Level != IPPROTO_RM)
  1085. {
  1086. PgmError ("WSHPgm.WSHGetSocketInformation: Unsupported Level=<%d>\n", Level);
  1087. return WSAEINVAL;
  1088. }
  1089. //
  1090. // Make sure that the output buffer is sufficiently large.
  1091. //
  1092. if (*OptionLength < sizeof(char))
  1093. {
  1094. return WSAEFAULT;
  1095. }
  1096. __try
  1097. {
  1098. RtlZeroMemory (OptionValue, *OptionLength);
  1099. }
  1100. __except (EXCEPTION_EXECUTE_HANDLER)
  1101. {
  1102. return WSAEFAULT;
  1103. }
  1104. if (Level == IPPROTO_RM)
  1105. {
  1106. switch (OptionName)
  1107. {
  1108. case RM_RATE_WINDOW_SIZE:
  1109. {
  1110. if ((!TdiAddressObjectHandle) ||
  1111. (*OptionLength < sizeof(RM_SEND_WINDOW)))
  1112. {
  1113. return WSAEINVAL;
  1114. }
  1115. error = SetTdiInformation (TdiAddressObjectHandle,
  1116. IOCTL_PGM_WSH_QUERY_WINDOW_SIZE_RATE,
  1117. NULL,
  1118. 0,
  1119. &MCastRequest,
  1120. sizeof (MCastRequest),
  1121. TRUE);
  1122. if (error == NO_ERROR)
  1123. {
  1124. pSetWindowInfo = (RM_SEND_WINDOW UNALIGNED *) OptionValue;
  1125. pSetWindowInfo->RateKbitsPerSec = MCastRequest.TransmitWindowInfo.RateKbitsPerSec;
  1126. pSetWindowInfo->WindowSizeInMSecs = MCastRequest.TransmitWindowInfo.WindowSizeInMSecs;
  1127. pSetWindowInfo->WindowSizeInBytes = MCastRequest.TransmitWindowInfo.WindowSizeInBytes;
  1128. }
  1129. else
  1130. {
  1131. PgmError ("WSHPgm.WSHGetSocketInformation: ERROR=<%d> Querying Window RateSize\n",error);
  1132. return error;
  1133. }
  1134. PgmLog ("WSHPgm.WSHGetSocketInformation[RATE_WINDOW_SIZE]: Get Window Rate Size\n");
  1135. return (NO_ERROR);
  1136. }
  1137. case RM_SEND_WINDOW_ADV_RATE:
  1138. {
  1139. if ((!TdiAddressObjectHandle) ||
  1140. (*OptionLength < sizeof(ULONG)))
  1141. {
  1142. return WSAEINVAL;
  1143. }
  1144. error = SetTdiInformation (TdiAddressObjectHandle,
  1145. IOCTL_PGM_WSH_QUERY_ADVANCE_WINDOW_RATE,
  1146. NULL,
  1147. 0,
  1148. &MCastRequest,
  1149. sizeof (MCastRequest),
  1150. TRUE);
  1151. if (error == NO_ERROR)
  1152. {
  1153. * ((PULONG) OptionValue) = MCastRequest.WindowAdvancePercentage;
  1154. }
  1155. else
  1156. {
  1157. PgmError ("WSHPgm.WSHGetSocketInformation: ERROR=<%d> Querying WindowAdvRate\n", error);
  1158. return error;
  1159. }
  1160. PgmLog ("WSHPgm.WSHGetSocketInformation[WINDOW_ADV_RATE]: %d\n",
  1161. MCastRequest.WindowAdvancePercentage);
  1162. return (NO_ERROR);
  1163. }
  1164. case RM_LATEJOIN:
  1165. {
  1166. if ((!TdiAddressObjectHandle) ||
  1167. (*OptionLength < sizeof(ULONG)))
  1168. {
  1169. return WSAEINVAL;
  1170. }
  1171. error = SetTdiInformation (TdiAddressObjectHandle,
  1172. IOCTL_PGM_WSH_QUERY_LATE_JOINER_PERCENTAGE,
  1173. NULL,
  1174. 0,
  1175. &MCastRequest,
  1176. sizeof (MCastRequest),
  1177. TRUE);
  1178. if (error == NO_ERROR)
  1179. {
  1180. * ((PULONG) OptionValue) = MCastRequest.LateJoinerPercentage;
  1181. }
  1182. else
  1183. {
  1184. PgmError ("WSHGetSocketInformation: ERROR=<%d> Querying LateJoinerPercentage\n", error);
  1185. return error;
  1186. }
  1187. PgmLog ("WSHPgm.WSHGetSocketInformation[LATEJOIN]: <%d>\n",
  1188. MCastRequest.LateJoinerPercentage);
  1189. return (NO_ERROR);
  1190. }
  1191. case RM_SENDER_WINDOW_ADVANCE_METHOD:
  1192. {
  1193. if ((!TdiAddressObjectHandle) ||
  1194. (*OptionLength < sizeof(ULONG)))
  1195. {
  1196. return WSAEINVAL;
  1197. }
  1198. error = SetTdiInformation (TdiAddressObjectHandle,
  1199. IOCTL_PGM_WSH_QUERY_WINDOW_ADVANCE_METHOD,
  1200. NULL,
  1201. 0,
  1202. &MCastRequest,
  1203. sizeof (MCastRequest),
  1204. TRUE);
  1205. if (error == NO_ERROR)
  1206. {
  1207. * ((PULONG) OptionValue) = MCastRequest.WindowAdvanceMethod;
  1208. }
  1209. else
  1210. {
  1211. PgmError ("WSHGetSocketInformation: ERROR=<%d> Querying WindowAdvanceMethod\n", error);
  1212. return error;
  1213. }
  1214. PgmLog ("WSHPgm.WSHGetSocketInformation[WINDOW_ADVANCE_METHOD]: <%d>\n",
  1215. MCastRequest.WindowAdvanceMethod);
  1216. return (NO_ERROR);
  1217. }
  1218. case RM_USE_FEC:
  1219. {
  1220. if ((!TdiAddressObjectHandle) ||
  1221. (*OptionLength < sizeof(RM_FEC_INFO)))
  1222. {
  1223. return WSAEINVAL;
  1224. }
  1225. PgmLog ("WSHPgm.WSHGetSocketInformation[FEC_INFO]: Get FEC_INFO\n");
  1226. error = SetTdiInformation (TdiAddressObjectHandle,
  1227. IOCTL_PGM_WSH_QUERY_FEC_INFO,
  1228. NULL,
  1229. 0,
  1230. &MCastRequest,
  1231. sizeof (MCastRequest),
  1232. TRUE);
  1233. if (error == NO_ERROR)
  1234. {
  1235. pFECInfo = (RM_FEC_INFO UNALIGNED *) OptionValue;
  1236. RtlCopyMemory (pFECInfo, &MCastRequest.FECInfo, sizeof(RM_FEC_INFO));
  1237. }
  1238. else
  1239. {
  1240. PgmError ("WSHGetSocketInformation: ERROR=<%d> Querying FEC_INFO\n", error);
  1241. return error;
  1242. }
  1243. return (NO_ERROR);
  1244. }
  1245. case RM_SENDER_STATISTICS:
  1246. {
  1247. if ((!TdiConnectionObjectHandle) ||
  1248. (*OptionLength < sizeof(RM_SENDER_STATS)))
  1249. {
  1250. return WSAEINVAL;
  1251. }
  1252. error = SetTdiInformation (TdiConnectionObjectHandle,
  1253. IOCTL_PGM_WSH_QUERY_SENDER_STATS,
  1254. NULL,
  1255. 0,
  1256. &MCastRequest,
  1257. sizeof (MCastRequest),
  1258. TRUE);
  1259. if (error == NO_ERROR)
  1260. {
  1261. pSenderStats = (RM_SENDER_STATS UNALIGNED *) OptionValue;
  1262. RtlCopyMemory (pSenderStats, &MCastRequest.SenderStats, sizeof(RM_SENDER_STATS));
  1263. }
  1264. else
  1265. {
  1266. PgmError ("WSHGetSocketInformation: ERROR=<%d> Querying SENDER_STATS\n", error);
  1267. return error;
  1268. }
  1269. PgmLog ("WSHPgm.WSHGetSocketInformation[SENDER_STATS]: Get SENDER_STATS\n");
  1270. return (NO_ERROR);
  1271. }
  1272. case RM_RECEIVER_STATISTICS:
  1273. {
  1274. if ((!TdiConnectionObjectHandle) ||
  1275. (*OptionLength < sizeof(RM_RECEIVER_STATS)))
  1276. {
  1277. return WSAEINVAL;
  1278. }
  1279. error = SetTdiInformation (TdiConnectionObjectHandle,
  1280. IOCTL_PGM_WSH_QUERY_RECEIVER_STATS,
  1281. NULL,
  1282. 0,
  1283. &MCastRequest,
  1284. sizeof (MCastRequest),
  1285. TRUE);
  1286. if (error == NO_ERROR)
  1287. {
  1288. pReceiverStats = (RM_RECEIVER_STATS UNALIGNED *) OptionValue;
  1289. RtlCopyMemory (pReceiverStats, &MCastRequest.ReceiverStats, sizeof(RM_RECEIVER_STATS));
  1290. }
  1291. else
  1292. {
  1293. PgmError ("WSHGetSocketInformation: ERROR=<%d> Querying RECEIVER_STATS\n", error);
  1294. return error;
  1295. }
  1296. PgmLog ("WSHPgm.WSHGetSocketInformation[RECEIVER_STATS]: Get RECEIVER_STATS\n");
  1297. return (NO_ERROR);
  1298. }
  1299. default:
  1300. {
  1301. return WSAEINVAL;
  1302. }
  1303. }
  1304. }
  1305. PgmError ("WSHPgm.WSHGetSocketInformation[%s]: Unsupported OptionName=<%d>\n",
  1306. (Level == SOL_SOCKET ? "SOL_SOCKET" : "IPPROTO_RM"), OptionName);
  1307. return WSAENOPROTOOPT;
  1308. } // WSHGetSocketInformation
  1309. //----------------------------------------------------------------------------
  1310. INT
  1311. WSHGetSockaddrType (
  1312. IN PSOCKADDR Sockaddr,
  1313. IN DWORD SockaddrLength,
  1314. OUT PSOCKADDR_INFO SockaddrInfo
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. This routine parses a sockaddr to determine the type of the
  1319. machine address and endpoint address portions of the sockaddr.
  1320. This is called by the winsock DLL whenever it needs to interpret
  1321. a sockaddr.
  1322. Arguments:
  1323. Sockaddr - a pointer to the sockaddr structure to evaluate.
  1324. SockaddrLength - the number of bytes in the sockaddr structure.
  1325. SockaddrInfo - a pointer to a structure that will receive information
  1326. about the specified sockaddr.
  1327. Return Value:
  1328. INT - a winsock error code indicating the status of the operation, or
  1329. NO_ERROR if the operation succeeded.
  1330. --*/
  1331. {
  1332. UNALIGNED SOCKADDR_IN *sockaddr = (PSOCKADDR_IN)Sockaddr;
  1333. ULONG i;
  1334. //
  1335. // Make sure that the address family is correct.
  1336. //
  1337. if (sockaddr->sin_family != AF_INET)
  1338. {
  1339. return WSAEAFNOSUPPORT;
  1340. }
  1341. //
  1342. // Make sure that the length is correct.
  1343. //
  1344. if (SockaddrLength < sizeof(SOCKADDR_IN))
  1345. {
  1346. return WSAEFAULT;
  1347. }
  1348. //
  1349. // The address passed the tests, looks like a good address.
  1350. // Determine the type of the address portion of the sockaddr.
  1351. //
  1352. if (sockaddr->sin_addr.s_addr == INADDR_ANY)
  1353. {
  1354. SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
  1355. }
  1356. else if (sockaddr->sin_addr.s_addr == INADDR_BROADCAST)
  1357. {
  1358. SockaddrInfo->AddressInfo = SockaddrAddressInfoBroadcast;
  1359. }
  1360. else if (sockaddr->sin_addr.s_addr == INADDR_LOOPBACK)
  1361. {
  1362. SockaddrInfo->AddressInfo = SockaddrAddressInfoLoopback;
  1363. }
  1364. else
  1365. {
  1366. SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
  1367. }
  1368. //
  1369. // Determine the type of the port (endpoint) in the sockaddr.
  1370. //
  1371. if (sockaddr->sin_port == 0)
  1372. {
  1373. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
  1374. }
  1375. else if (ntohs (sockaddr->sin_port) < 2000)
  1376. {
  1377. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoReserved;
  1378. }
  1379. else
  1380. {
  1381. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
  1382. }
  1383. //
  1384. // Zero out the sin_reserved_mbz part of the address. We silently allow
  1385. // nonzero values in this field.
  1386. //
  1387. for (i = 0; i < sizeof(sockaddr->sin_zero); i++)
  1388. {
  1389. sockaddr->sin_zero[i] = 0;
  1390. }
  1391. PgmLog ("WSHPgm.WSHGetSockAddrType: Addr=<%x>=><%x>, Port=<%x>=><%x>\n",
  1392. sockaddr->sin_addr.s_addr, SockaddrInfo->AddressInfo, sockaddr->sin_port, SockaddrInfo->EndpointInfo);
  1393. return NO_ERROR;
  1394. } // WSHGetSockaddrType
  1395. INT
  1396. WSHEnumProtocols (
  1397. IN LPINT lpiProtocols,
  1398. IN LPWSTR lpTransportKeyName,
  1399. IN OUT LPVOID lpProtocolBuffer,
  1400. IN OUT LPDWORD lpdwBufferLength
  1401. )
  1402. /*++
  1403. Routine Description:
  1404. Enumerates the protocols supported by this helper.
  1405. Arguments:
  1406. lpiProtocols - Pointer to a NULL-terminated array of protocol
  1407. identifiers. Only protocols specified in this array will
  1408. be returned by this function. If this pointer is NULL,
  1409. all protocols are returned.
  1410. lpTransportKeyName -
  1411. lpProtocolBuffer - Pointer to a buffer to fill with PROTOCOL_INFO
  1412. structures.
  1413. lpdwBufferLength - Pointer to a variable that, on input, contains
  1414. the size of lpProtocolBuffer. On output, this value will be
  1415. updated with the size of the data actually written to the buffer.
  1416. Return Value:
  1417. INT - The number of protocols returned if successful, -1 if not.
  1418. --*/
  1419. {
  1420. DWORD bytesRequired;
  1421. PPROTOCOL_INFO PgmProtocolInfo;
  1422. BOOL useRM = FALSE;
  1423. DWORD i;
  1424. UNREFERENCED_PARAMETER(lpTransportKeyName);
  1425. //
  1426. // Make sure that the caller cares about RM.
  1427. //
  1428. if (ARGUMENT_PRESENT (lpiProtocols))
  1429. {
  1430. for (i = 0; lpiProtocols[i] != 0; i++)
  1431. {
  1432. if (lpiProtocols[i] == IPPROTO_RM)
  1433. {
  1434. useRM = TRUE;
  1435. }
  1436. }
  1437. }
  1438. else
  1439. {
  1440. useRM = TRUE;
  1441. }
  1442. if (!useRM)
  1443. {
  1444. *lpdwBufferLength = 0;
  1445. return 0;
  1446. }
  1447. //
  1448. // Make sure that the caller has specified a sufficiently large
  1449. // buffer.
  1450. //
  1451. bytesRequired = (DWORD)((sizeof(PROTOCOL_INFO) * 1) + ((wcslen (PGM_NAME) + 1) * sizeof(WCHAR)));
  1452. if (bytesRequired > *lpdwBufferLength)
  1453. {
  1454. *lpdwBufferLength = bytesRequired;
  1455. return -1;
  1456. }
  1457. //
  1458. // Fill in PGM info
  1459. //
  1460. PgmProtocolInfo = lpProtocolBuffer;
  1461. PgmProtocolInfo->lpProtocol = (LPWSTR) ((PBYTE)lpProtocolBuffer + *lpdwBufferLength -
  1462. ((wcslen(PGM_NAME) + 1) * sizeof(WCHAR)));
  1463. PgmProtocolInfo->dwServiceFlags = PGM_RDM_SERVICE_FLAGS;
  1464. PgmProtocolInfo->iAddressFamily = AF_INET;
  1465. PgmProtocolInfo->iSocketType = SOCK_RDM;
  1466. PgmProtocolInfo->iProtocol = IPPROTO_RM;
  1467. PgmProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_IN);
  1468. PgmProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_IN);
  1469. PgmProtocolInfo->dwMessageSize = PGM_MESSAGE_SIZE;
  1470. wcscpy (PgmProtocolInfo->lpProtocol, PGM_NAME);
  1471. *lpdwBufferLength = bytesRequired;
  1472. PgmLog ("WSHPgm.WSHEnumProtocols: ServiceFlags=<%x>, <%x>...\n",
  1473. PGM_RDM_SERVICE_FLAGS, PGM_STREAM_SERVICE_FLAGS);
  1474. return 1;
  1475. } // WSHEnumProtocols
  1476. //----------------------------------------------------------------------------
  1477. INT
  1478. WSHGetWildcardSockaddr (
  1479. IN PVOID HelperDllSocketContext,
  1480. OUT PSOCKADDR Sockaddr,
  1481. OUT PINT SockaddrLength
  1482. )
  1483. /*++
  1484. Routine Description:
  1485. This routine returns a wildcard socket address. A wildcard address
  1486. is one which will bind the socket to an endpoint of the transport's
  1487. choosing. For TCP/IP, a wildcard address has IP address ==
  1488. 0.0.0.0 and port = 0.
  1489. Arguments:
  1490. HelperDllSocketContext - the context pointer returned from
  1491. WSHOpenSocket() for the socket for which we need a wildcard
  1492. address.
  1493. Sockaddr - points to a buffer which will receive the wildcard socket
  1494. address.
  1495. SockaddrLength - receives the length of the wioldcard sockaddr.
  1496. Return Value:
  1497. INT - a winsock error code indicating the status of the operation, or
  1498. NO_ERROR if the operation succeeded.
  1499. --*/
  1500. {
  1501. if (*SockaddrLength < sizeof(SOCKADDR_IN))
  1502. {
  1503. return WSAEFAULT;
  1504. }
  1505. *SockaddrLength = sizeof(SOCKADDR_IN);
  1506. //
  1507. // Just zero out the address and set the family to AF_INET
  1508. //
  1509. RtlZeroMemory (Sockaddr, sizeof(SOCKADDR_IN));
  1510. Sockaddr->sa_family = AF_INET;
  1511. PgmLog ("WSHPgm.WSHGetWildcardSockaddr: ...\n");
  1512. return NO_ERROR;
  1513. } // WSAGetWildcardSockaddr
  1514. //----------------------------------------------------------------------------
  1515. DWORD
  1516. WSHGetWinsockMapping (
  1517. OUT PWINSOCK_MAPPING Mapping,
  1518. IN DWORD MappingLength
  1519. )
  1520. /*++
  1521. Routine Description:
  1522. Returns the list of address family/socket type/protocol triples
  1523. supported by this helper DLL.
  1524. Arguments:
  1525. Mapping - receives a pointer to a WINSOCK_MAPPING structure that
  1526. describes the triples supported here.
  1527. MappingLength - the length, in bytes, of the passed-in Mapping buffer.
  1528. Return Value:
  1529. DWORD - the length, in bytes, of a WINSOCK_MAPPING structure for this
  1530. helper DLL. If the passed-in buffer is too small, the return
  1531. value will indicate the size of a buffer needed to contain
  1532. the WINSOCK_MAPPING structure.
  1533. --*/
  1534. {
  1535. DWORD mappingLength;
  1536. mappingLength = sizeof(WINSOCK_MAPPING) - sizeof(MAPPING_TRIPLE) + sizeof(PgmMappingTriples);
  1537. //
  1538. // If the passed-in buffer is too small, return the length needed
  1539. // now without writing to the buffer. The caller should allocate
  1540. // enough memory and call this routine again.
  1541. //
  1542. if (mappingLength > MappingLength)
  1543. {
  1544. return mappingLength;
  1545. }
  1546. //
  1547. // Fill in the output mapping buffer with the list of triples
  1548. // supported in this helper DLL.
  1549. //
  1550. Mapping->Rows = sizeof(PgmMappingTriples) / sizeof(PgmMappingTriples[0]);
  1551. Mapping->Columns = sizeof(MAPPING_TRIPLE) / sizeof(DWORD);
  1552. RtlMoveMemory (Mapping->Mapping, PgmMappingTriples, sizeof(PgmMappingTriples));
  1553. PgmLog ("WSHPgm.WSHGetWinsockMapping: MappingLength=<%d>\n", mappingLength);
  1554. //
  1555. // Return the number of bytes we wrote.
  1556. //
  1557. return mappingLength;
  1558. } // WSHGetWinsockMapping
  1559. //----------------------------------------------------------------------------
  1560. INT
  1561. WINAPI
  1562. WSHAddressToString (
  1563. IN LPSOCKADDR Address,
  1564. IN INT AddressLength,
  1565. IN LPWSAPROTOCOL_INFOW ProtocolInfo,
  1566. OUT LPWSTR AddressString,
  1567. IN OUT LPDWORD AddressStringLength
  1568. )
  1569. /*++
  1570. Routine Description:
  1571. Converts a SOCKADDR to a human-readable form.
  1572. Arguments:
  1573. Address - The SOCKADDR to convert.
  1574. AddressLength - The length of Address.
  1575. ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
  1576. AddressString - Receives the formatted address string.
  1577. AddressStringLength - On input, contains the length of AddressString.
  1578. On output, contains the number of characters actually written
  1579. to AddressString.
  1580. Return Value:
  1581. INT - 0 if successful, WinSock error code if not.
  1582. --*/
  1583. {
  1584. WCHAR string[32];
  1585. INT length;
  1586. LPSOCKADDR_IN addr;
  1587. INT err = NO_ERROR;
  1588. //
  1589. // Quick sanity checks.
  1590. //
  1591. if( AddressLength < sizeof(SOCKADDR_IN))
  1592. {
  1593. return WSAEFAULT;
  1594. }
  1595. __try {
  1596. addr = (LPSOCKADDR_IN)Address;
  1597. if (addr->sin_family != AF_INET)
  1598. {
  1599. return WSAEINVAL;
  1600. }
  1601. //
  1602. // Do the converstion.
  1603. //
  1604. // BUGBUG: We should really use the DavidTr huge-but-fast
  1605. // table based lookup for this, but we already have two copies
  1606. // of that 1K table in the system (one in WSOCK32.DLL, and one it
  1607. // WS2_32.DLL). I really don't want to see Yet Another Copy here.
  1608. //
  1609. length = swprintf (string, L"%d.%d.%d.%d", (addr->sin_addr.s_addr >> 0) & 0xFF,
  1610. (addr->sin_addr.s_addr >> 8) & 0xFF,
  1611. (addr->sin_addr.s_addr >> 16) & 0xFF,
  1612. (addr->sin_addr.s_addr >> 24) & 0xFF);
  1613. if (addr->sin_port != 0)
  1614. {
  1615. length += swprintf (string + length, L":%u", ntohs (addr->sin_port));
  1616. }
  1617. length++; // account for terminator
  1618. if (*AddressStringLength >= (DWORD)length)
  1619. {
  1620. RtlCopyMemory (AddressString, string, length * sizeof(WCHAR));
  1621. }
  1622. else
  1623. {
  1624. err = WSAEFAULT;
  1625. }
  1626. *AddressStringLength = length;
  1627. }
  1628. __except (EXCEPTION_EXECUTE_HANDLER)
  1629. {
  1630. err = WSAEFAULT;
  1631. }
  1632. PgmLog ("WSHPgm.WSHAddressToString: status=<%d>\n", err);
  1633. return err;
  1634. } // WSHAddressToString
  1635. //----------------------------------------------------------------------------
  1636. INT
  1637. WINAPI
  1638. WSHStringToAddress (
  1639. IN LPWSTR AddressString,
  1640. IN DWORD AddressFamily,
  1641. IN LPWSAPROTOCOL_INFOW ProtocolInfo,
  1642. OUT LPSOCKADDR Address,
  1643. IN OUT LPINT AddressLength
  1644. )
  1645. /*++
  1646. Routine Description:
  1647. Fills in a SOCKADDR structure by parsing a human-readable string.
  1648. Arguments:
  1649. AddressString - Points to the zero-terminated human-readable string.
  1650. AddressFamily - The address family to which the string belongs.
  1651. ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
  1652. Address - Receives the SOCKADDR structure.
  1653. AddressLength - On input, contains the length of Address. On output,
  1654. contains the number of bytes actually written to Address.
  1655. Return Value:
  1656. INT - 0 if successful, WinSock error code if not.
  1657. --*/
  1658. {
  1659. LPWSTR terminator;
  1660. ULONG ipAddress;
  1661. USHORT port;
  1662. LPSOCKADDR_IN addr;
  1663. __try {
  1664. //
  1665. // Quick sanity checks.
  1666. //
  1667. if (*AddressLength < sizeof(SOCKADDR_IN))
  1668. {
  1669. *AddressLength = sizeof(SOCKADDR_IN);
  1670. return WSAEFAULT;
  1671. }
  1672. if (AddressFamily != AF_INET)
  1673. {
  1674. return WSAEINVAL;
  1675. }
  1676. //
  1677. // Convert it.
  1678. //
  1679. if (!NT_SUCCESS(RtlIpv4StringToAddressW(AddressString, FALSE, &terminator,
  1680. (IN_ADDR*)&ipAddress))) {
  1681. return WSAEINVAL;
  1682. }
  1683. if (ipAddress == INADDR_NONE)
  1684. {
  1685. return WSAEINVAL;
  1686. }
  1687. if (*terminator == L':')
  1688. {
  1689. WCHAR ch;
  1690. USHORT base;
  1691. terminator++;
  1692. port = 0;
  1693. base = 10;
  1694. if (*terminator == L'0')
  1695. {
  1696. base = 8;
  1697. terminator++;
  1698. if (*terminator == L'x')
  1699. {
  1700. base = 16;
  1701. terminator++;
  1702. }
  1703. }
  1704. while (ch = *terminator++)
  1705. {
  1706. if (iswdigit(ch))
  1707. {
  1708. port = (port * base) + (ch - L'0');
  1709. }
  1710. else if (base == 16 && iswxdigit(ch))
  1711. {
  1712. port = (port << 4);
  1713. port += ch + 10 - (iswlower(ch) ? L'a' : L'A');
  1714. }
  1715. else
  1716. {
  1717. return WSAEINVAL;
  1718. }
  1719. }
  1720. }
  1721. else if (*terminator == 0)
  1722. {
  1723. port = 0;
  1724. }
  1725. else
  1726. {
  1727. return WSAEINVAL;
  1728. }
  1729. //
  1730. // Build the address.
  1731. //
  1732. RtlZeroMemory (Address, sizeof(SOCKADDR_IN));
  1733. addr = (LPSOCKADDR_IN)Address;
  1734. *AddressLength = sizeof(SOCKADDR_IN);
  1735. addr->sin_family = AF_INET;
  1736. addr->sin_port = htons (port);
  1737. addr->sin_addr.s_addr = ipAddress;
  1738. }
  1739. __except (EXCEPTION_EXECUTE_HANDLER) {
  1740. return WSAEFAULT;
  1741. }
  1742. PgmLog ("WSHPgm.WSHStringToAddress:\n");
  1743. return NO_ERROR;
  1744. } // WSHStringToAddress
  1745. //----------------------------------------------------------------------------
  1746. INT
  1747. WINAPI
  1748. WSHGetBroadcastSockaddr (
  1749. IN PVOID HelperDllSocketContext,
  1750. OUT PSOCKADDR Sockaddr,
  1751. OUT PINT SockaddrLength
  1752. )
  1753. /*++
  1754. Routine Description:
  1755. This routine returns a broadcast socket address. A broadcast address
  1756. may be used as a destination for the sendto() API to send a datagram
  1757. to all interested clients.
  1758. Arguments:
  1759. HelperDllSocketContext - the context pointer returned from
  1760. WSHOpenSocket() for the socket for which we need a broadcast
  1761. address.
  1762. Sockaddr - points to a buffer which will receive the broadcast socket
  1763. address.
  1764. SockaddrLength - receives the length of the broadcast sockaddr.
  1765. Return Value:
  1766. INT - a winsock error code indicating the status of the operation, or
  1767. NO_ERROR if the operation succeeded.
  1768. --*/
  1769. {
  1770. LPSOCKADDR_IN addr;
  1771. PgmError ("WSHPgm.WSHGetBroadcastSockaddr: Not Supported!\n");
  1772. return (WSAEOPNOTSUPP);
  1773. if (*SockaddrLength < sizeof(SOCKADDR_IN))
  1774. {
  1775. return WSAEFAULT;
  1776. }
  1777. *SockaddrLength = sizeof(SOCKADDR_IN);
  1778. //
  1779. // Build the broadcast address.
  1780. //
  1781. addr = (LPSOCKADDR_IN) Sockaddr;
  1782. RtlZeroMemory (addr, sizeof(*addr));
  1783. addr->sin_family = AF_INET;
  1784. addr->sin_addr.s_addr = htonl (INADDR_BROADCAST);
  1785. return NO_ERROR;
  1786. } // WSAGetBroadcastSockaddr
  1787. //----------------------------------------------------------------------------
  1788. INT
  1789. WINAPI
  1790. WSHGetProviderGuid (
  1791. IN LPWSTR ProviderName,
  1792. OUT LPGUID ProviderGuid
  1793. )
  1794. /*++
  1795. Routine Description:
  1796. Returns the GUID identifying the protocols supported by this helper.
  1797. Arguments:
  1798. ProviderName - Contains the name of the provider, such as "Pgm".
  1799. ProviderGuid - Points to a buffer that receives the provider's GUID.
  1800. Return Value:
  1801. INT - 0 if successful, WinSock error code if not.
  1802. --*/
  1803. {
  1804. INT RetVal = WSAEINVAL;
  1805. if (ProviderName == NULL || ProviderGuid == NULL)
  1806. {
  1807. RetVal = WSAEFAULT;
  1808. }
  1809. else if (_wcsicmp (ProviderName, L"Pgm") == 0)
  1810. {
  1811. RtlCopyMemory (ProviderGuid, &PgmProviderGuid, sizeof(GUID));
  1812. RetVal = NO_ERROR;
  1813. }
  1814. PgmLog ("WSHPgm.WSHGetProviderGuid: ProviderName=<%ws>, RetVal=<%x>\n", ProviderName, RetVal);
  1815. return (RetVal);
  1816. } // WSHGetProviderGuid
  1817. //----------------------------------------------------------------------------
  1818. INT
  1819. WINAPI
  1820. WSHGetWSAProtocolInfo (
  1821. IN LPWSTR ProviderName,
  1822. OUT LPWSAPROTOCOL_INFOW * ProtocolInfo,
  1823. OUT LPDWORD ProtocolInfoEntries
  1824. )
  1825. /*++
  1826. Routine Description:
  1827. Retrieves a pointer to the WSAPROTOCOL_INFOW structure(s) describing
  1828. the protocol(s) supported by this helper.
  1829. Arguments:
  1830. ProviderName - Contains the name of the provider, such as "TcpIp".
  1831. ProtocolInfo - Receives a pointer to the WSAPROTOCOL_INFOW array.
  1832. ProtocolInfoEntries - Receives the number of entries in the array.
  1833. Return Value:
  1834. INT - 0 if successful, WinSock error code if not.
  1835. --*/
  1836. {
  1837. INT RetVal = WSAEINVAL;
  1838. if (ProviderName == NULL || ProtocolInfo == NULL || ProtocolInfoEntries == NULL)
  1839. {
  1840. RetVal = WSAEFAULT;
  1841. }
  1842. else if (_wcsicmp (ProviderName, L"RMCast") == 0)
  1843. {
  1844. *ProtocolInfo = Winsock2Protocols;
  1845. *ProtocolInfoEntries = NUM_WINSOCK2_PROTOCOLS;
  1846. RetVal = NO_ERROR;
  1847. }
  1848. PgmLog ("WSHPgm.WSHGetWSAProtocolInfo: ProviderName=<%ws>, RetVal=<%x>\n", ProviderName, RetVal);
  1849. return (RetVal);
  1850. } // WSHGetWSAProtocolInfo
  1851. //----------------------------------------------------------------------------
  1852. INT
  1853. WINAPI
  1854. WSHIoctl (
  1855. IN PVOID HelperDllSocketContext,
  1856. IN SOCKET SocketHandle,
  1857. IN HANDLE TdiAddressObjectHandle,
  1858. IN HANDLE TdiConnectionObjectHandle,
  1859. IN DWORD IoControlCode,
  1860. IN LPVOID InputBuffer,
  1861. IN DWORD InputBufferLength,
  1862. IN LPVOID OutputBuffer,
  1863. IN DWORD OutputBufferLength,
  1864. OUT LPDWORD NumberOfBytesReturned,
  1865. IN LPWSAOVERLAPPED Overlapped,
  1866. IN LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine,
  1867. OUT LPBOOL NeedsCompletion
  1868. )
  1869. /*++
  1870. Routine Description:
  1871. Performs queries & controls on the socket. This is basically an
  1872. "escape hatch" for IOCTLs not supported by MSAFD.DLL. Any unknown
  1873. IOCTLs are routed to the socket's helper DLL for protocol-specific
  1874. processing.
  1875. Arguments:
  1876. HelperDllSocketContext - the context pointer returned from
  1877. WSHOpenSocket().
  1878. SocketHandle - the handle of the socket for which we're controlling.
  1879. TdiAddressObjectHandle - the TDI address object of the socket, if
  1880. any. If the socket is not yet bound to an address, then
  1881. it does not have a TDI address object and this parameter
  1882. will be NULL.
  1883. TdiConnectionObjectHandle - the TDI connection object of the socket,
  1884. if any. If the socket is not yet connected, then it does not
  1885. have a TDI connection object and this parameter will be NULL.
  1886. IoControlCode - Control code of the operation to perform.
  1887. InputBuffer - Address of the input buffer.
  1888. InputBufferLength - The length of InputBuffer.
  1889. OutputBuffer - Address of the output buffer.
  1890. OutputBufferLength - The length of OutputBuffer.
  1891. NumberOfBytesReturned - Receives the number of bytes actually written
  1892. to the output buffer.
  1893. Overlapped - Pointer to a WSAOVERLAPPED structure for overlapped
  1894. operations.
  1895. CompletionRoutine - Pointer to a completion routine to call when
  1896. the operation is completed.
  1897. NeedsCompletion - WSAIoctl() can be overlapped, with all the gory
  1898. details that involves, such as setting events, queuing completion
  1899. routines, and posting to IO completion ports. Since the majority
  1900. of the IOCTL codes can be completed quickly "in-line", MSAFD.DLL
  1901. can optionally perform the overlapped completion of the operation.
  1902. Setting *NeedsCompletion to TRUE (the default) causes MSAFD.DLL
  1903. to handle all of the IO completion details iff this is an
  1904. overlapped operation on an overlapped socket.
  1905. Setting *NeedsCompletion to FALSE tells MSAFD.DLL to take no
  1906. further action because the helper DLL will perform any necessary
  1907. IO completion.
  1908. Note that if a helper performs its own IO completion, the helper
  1909. is responsible for maintaining the "overlapped" mode of the socket
  1910. at socket creation time and NOT performing overlapped IO completion
  1911. on non-overlapped sockets.
  1912. Return Value:
  1913. INT - 0 if successful, WinSock error code if not.
  1914. --*/
  1915. {
  1916. INT err;
  1917. NTSTATUS status;
  1918. //
  1919. // Quick sanity checks.
  1920. //
  1921. if (HelperDllSocketContext == NULL ||
  1922. SocketHandle == INVALID_SOCKET ||
  1923. NumberOfBytesReturned == NULL ||
  1924. NeedsCompletion == NULL)
  1925. {
  1926. return WSAEINVAL;
  1927. }
  1928. *NeedsCompletion = TRUE;
  1929. switch (IoControlCode)
  1930. {
  1931. default:
  1932. err = WSAEINVAL;
  1933. break;
  1934. }
  1935. PgmLog ("WSHPgm.WSHIoctl: Returning <%d>\n", err);
  1936. return err;
  1937. } // WSHIoctl
  1938. //----------------------------------------------------------------------------
  1939. INT
  1940. WINAPI
  1941. WSHJoinLeaf (
  1942. IN PVOID HelperDllSocketContext,
  1943. IN SOCKET SocketHandle,
  1944. IN HANDLE TdiAddressObjectHandle,
  1945. IN HANDLE TdiConnectionObjectHandle,
  1946. IN PVOID LeafHelperDllSocketContext,
  1947. IN SOCKET LeafSocketHandle,
  1948. IN PSOCKADDR Sockaddr,
  1949. IN DWORD SockaddrLength,
  1950. IN LPWSABUF CallerData,
  1951. IN LPWSABUF CalleeData,
  1952. IN LPQOS SocketQOS,
  1953. IN LPQOS GroupQOS,
  1954. IN DWORD Flags
  1955. )
  1956. /*++
  1957. Routine Description:
  1958. Performs the protocol-dependent portion of creating a multicast
  1959. socket.
  1960. Arguments:
  1961. The following four parameters correspond to the socket passed into
  1962. the WSAJoinLeaf() API:
  1963. HelperDllSocketContext - The context pointer returned from
  1964. WSHOpenSocket().
  1965. SocketHandle - The handle of the socket used to establish the
  1966. multicast "session".
  1967. TdiAddressObjectHandle - The TDI address object of the socket, if
  1968. any. If the socket is not yet bound to an address, then
  1969. it does not have a TDI address object and this parameter
  1970. will be NULL.
  1971. TdiConnectionObjectHandle - The TDI connection object of the socket,
  1972. if any. If the socket is not yet connected, then it does not
  1973. have a TDI connection object and this parameter will be NULL.
  1974. The next two parameters correspond to the newly created socket that
  1975. identifies the multicast "session":
  1976. LeafHelperDllSocketContext - The context pointer returned from
  1977. WSHOpenSocket().
  1978. LeafSocketHandle - The handle of the socket that identifies the
  1979. multicast "session".
  1980. Sockaddr - The name of the peer to which the socket is to be joined.
  1981. SockaddrLength - The length of Sockaddr.
  1982. CallerData - Pointer to user data to be transferred to the peer
  1983. during multipoint session establishment.
  1984. CalleeData - Pointer to user data to be transferred back from
  1985. the peer during multipoint session establishment.
  1986. SocketQOS - Pointer to the flowspecs for SocketHandle, one in each
  1987. direction.
  1988. GroupQOS - Pointer to the flowspecs for the socket group, if any.
  1989. Flags - Flags to indicate if the socket is acting as sender,
  1990. receiver, or both.
  1991. Return Value:
  1992. INT - 0 if successful, a WinSock error code if not.
  1993. --*/
  1994. {
  1995. tPGM_MCAST_REQUEST MCastRequest;
  1996. INT err;
  1997. BOOL bSet_RM_MULTICAST_IF = FALSE;
  1998. PWSHPGM_SOCKET_CONTEXT context;
  1999. //
  2000. // Note: at this time we only support non-rooted control schemes,
  2001. // and therefore no leaf socket is created
  2002. //
  2003. //
  2004. // Quick sanity checks.
  2005. //
  2006. if (HelperDllSocketContext == NULL ||
  2007. SocketHandle == INVALID_SOCKET ||
  2008. TdiAddressObjectHandle == NULL ||
  2009. LeafHelperDllSocketContext != NULL ||
  2010. LeafSocketHandle != INVALID_SOCKET ||
  2011. Sockaddr == NULL ||
  2012. Sockaddr->sa_family != AF_INET ||
  2013. SockaddrLength < sizeof(SOCKADDR_IN) ||
  2014. ( CallerData != NULL && CallerData->len > 0 ) ||
  2015. ( CalleeData != NULL && CalleeData->len > 0 ) ||
  2016. SocketQOS != NULL ||
  2017. GroupQOS != NULL)
  2018. {
  2019. return WSAEINVAL;
  2020. }
  2021. context = HelperDllSocketContext;
  2022. MCastRequest.MCastInfo.MCastIpAddr = ((LPSOCKADDR_IN)Sockaddr)->sin_addr.s_addr; // MCast group to join...
  2023. MCastRequest.MCastInfo.MCastInIf = context->MulticastInInterface; // Multicast If to rcv packets on
  2024. MCastRequest.MCastOutIf = context->MulticastOutInterface; // Multicast If to send packets on
  2025. //
  2026. // Now figure out the local interface. Note that the local interface
  2027. // specified in IP_ADD_MEMBERSHIP applies to that on which you wish
  2028. // to receive datagrams, while the local interface specified in
  2029. // RM_MULTICAST_IF applies to that from which to send multicast
  2030. // packets. If there is >1 local interface then we want to be
  2031. // consistent regarding the send/recv interfaces.
  2032. //
  2033. if (context->MulticastInInterface == DEFAULT_MULTICAST_INTERFACE)
  2034. {
  2035. TDI_REQUEST_QUERY_INFORMATION query;
  2036. char tdiAddressInfo[FIELD_OFFSET (TDI_ADDRESS_INFO, Address)
  2037. + sizeof (TA_IP_ADDRESS)];
  2038. NTSTATUS status;
  2039. IO_STATUS_BLOCK ioStatusBlock;
  2040. //
  2041. // App hasn't set RM_MULTICAST_IF, so retrieve the bound
  2042. // address and use that for the send & recv interfaces
  2043. //
  2044. RtlZeroMemory (&query, sizeof (query));
  2045. query.QueryType = TDI_QUERY_ADDRESS_INFO;
  2046. status = NtDeviceIoControlFile (TdiAddressObjectHandle,
  2047. NULL,
  2048. NULL,
  2049. NULL,
  2050. &ioStatusBlock,
  2051. IOCTL_TDI_QUERY_INFORMATION,
  2052. &query,
  2053. sizeof (query),
  2054. tdiAddressInfo,
  2055. sizeof(tdiAddressInfo));
  2056. if (NT_SUCCESS(status))
  2057. {
  2058. PTA_IP_ADDRESS pIpAddress = (PTA_IP_ADDRESS)
  2059. (tdiAddressInfo+FIELD_OFFSET (TDI_ADDRESS_INFO, Address));
  2060. if (MCastRequest.MCastInfo.MCastInIf != DEFAULT_MULTICAST_INTERFACE)
  2061. {
  2062. bSet_RM_MULTICAST_IF = TRUE;
  2063. MCastRequest.MCastInfo.MCastInIf = pIpAddress->Address[0].Address[0].in_addr;
  2064. context->MulticastInInterface = MCastRequest.MCastInfo.MCastInIf;
  2065. }
  2066. }
  2067. else
  2068. {
  2069. PgmError ("WSHPgm!WSHJoinLeaf: DeviceIoCtrl failed to QueryInformation, status=<%x>\n",
  2070. status);
  2071. }
  2072. }
  2073. err = NO_ERROR;
  2074. //
  2075. // If the Flags param indicates that caller is a sender only,
  2076. // then there's no point in actually joining the group (anyone
  2077. // can send to a multicast group, but it's only members of the
  2078. // group who recv the packets). So, just check to see if it
  2079. // is necessary to set the RM_MULTICAST_IF to remain consistent
  2080. // with the bound address.
  2081. //
  2082. // Otherwise, caller is a receiver (possibly a sender too), so
  2083. // we really do want to join the group.
  2084. //
  2085. if (Flags != JL_SENDER_ONLY)
  2086. {
  2087. PgmLog ("WSHJoinLeaf[JL_RECEIVER]: Address=<%x>, Connection=<%x>\n",
  2088. TdiAddressObjectHandle, TdiConnectionObjectHandle);
  2089. //
  2090. // Add ourselves as a receiver
  2091. //
  2092. MCastRequest.MCastPort = ((LPSOCKADDR_IN)Sockaddr)->sin_port;
  2093. err = SetTdiInformation (TdiAddressObjectHandle,
  2094. IOCTL_PGM_WSH_JOIN_MCAST_LEAF,
  2095. &MCastRequest,
  2096. sizeof (MCastRequest),
  2097. NULL,
  2098. 0,
  2099. TRUE);
  2100. if (err == NO_ERROR)
  2101. {
  2102. //
  2103. // Record this fact in the leaf socket so we can drop membership
  2104. // when the leaf socket is closed.
  2105. //
  2106. context->MultipointLeaf = TRUE;
  2107. context->MultipointTarget = MCastRequest.MCastInfo.MCastIpAddr;
  2108. context->MultipointPort = ((LPSOCKADDR_IN)Sockaddr)->sin_port;
  2109. PgmLog ("WSHPgm!WSHJoinLeaf: JoinLeaf to <%x:%x> SUCCEEDed\n",
  2110. MCastRequest.MCastInfo.MCastIpAddr);
  2111. }
  2112. else
  2113. {
  2114. PgmError ("WSHPgm!WSHJoinLeaf: JoinLeaf to <%x> FAILed, err=<%d>\n",
  2115. MCastRequest.MCastInfo.MCastIpAddr, err);
  2116. }
  2117. }
  2118. if ((TdiConnectionObjectHandle) &&
  2119. (err == NO_ERROR) &&
  2120. (bSet_RM_MULTICAST_IF))
  2121. {
  2122. //
  2123. // If we have a TDI address object, set this option to
  2124. // the address object. If we don't have a TDI address
  2125. // object then we'll have to wait until after the socket
  2126. // is bound.
  2127. //
  2128. PgmLog ("WSHJoinLeaf[bSet_RM_MULTICAST_IF]: Address=<%x>, Connection=<%x>\n",
  2129. TdiAddressObjectHandle, TdiConnectionObjectHandle);
  2130. err = SetTdiInformation (TdiAddressObjectHandle,
  2131. IOCTL_PGM_WSH_ADD_RECEIVE_IF,
  2132. &MCastRequest,
  2133. sizeof (MCastRequest),
  2134. NULL,
  2135. 0,
  2136. TRUE);
  2137. if (err == NO_ERROR)
  2138. {
  2139. PgmLog ("WSHPgm!WSHJoinLeaf: Set MCastIf=<%x> SUCCEEDed\n", MCastRequest.MCastInfo.MCastInIf);
  2140. context->MulticastInInterface = MCastRequest.MCastInfo.MCastInIf;
  2141. }
  2142. else
  2143. {
  2144. PgmLog ("WSHPgm!WSHJoinLeaf: Set MCastIf=<%x> FAILed, err=<%d>\n",
  2145. MCastRequest.MCastInfo.MCastInIf, err);
  2146. }
  2147. }
  2148. return err;
  2149. } // WSHJoinLeaf
  2150. //----------------------------------------------------------------------------
  2151. //
  2152. // Internal routines
  2153. //
  2154. //----------------------------------------------------------------------------
  2155. BOOLEAN
  2156. IsTripleInList (
  2157. IN PMAPPING_TRIPLE List,
  2158. IN ULONG ListLength,
  2159. IN INT AddressFamily,
  2160. IN INT SocketType,
  2161. IN INT Protocol
  2162. )
  2163. /*++
  2164. Routine Description:
  2165. Determines whether the specified triple has an exact match in the
  2166. list of triples.
  2167. Arguments:
  2168. List - a list of triples (address family/socket type/protocol) to
  2169. search.
  2170. ListLength - the number of triples in the list.
  2171. AddressFamily - the address family to look for in the list.
  2172. SocketType - the socket type to look for in the list.
  2173. Protocol - the protocol to look for in the list.
  2174. Return Value:
  2175. BOOLEAN - TRUE if the triple was found in the list, false if not.
  2176. --*/
  2177. {
  2178. ULONG i;
  2179. //
  2180. // Walk through the list searching for an exact match.
  2181. //
  2182. for (i = 0; i < ListLength; i++)
  2183. {
  2184. //
  2185. // If all three elements of the triple match, return indicating
  2186. // that the triple did exist in the list.
  2187. //
  2188. if (AddressFamily == List[i].AddressFamily &&
  2189. SocketType == List[i].SocketType &&
  2190. Protocol == List[i].Protocol)
  2191. {
  2192. return TRUE;
  2193. }
  2194. }
  2195. //
  2196. // The triple was not found in the list.
  2197. //
  2198. return FALSE;
  2199. } // IsTripleInList
  2200. //----------------------------------------------------------------------------
  2201. INT
  2202. NtStatusToSocketError (
  2203. IN NTSTATUS Status
  2204. )
  2205. {
  2206. switch ( Status ) {
  2207. case STATUS_PENDING:
  2208. ASSERT (FALSE);
  2209. return WSASYSCALLFAILURE;
  2210. case STATUS_INVALID_HANDLE:
  2211. case STATUS_OBJECT_TYPE_MISMATCH:
  2212. return WSAENOTSOCK;
  2213. case STATUS_INSUFFICIENT_RESOURCES:
  2214. case STATUS_PAGEFILE_QUOTA:
  2215. case STATUS_COMMITMENT_LIMIT:
  2216. case STATUS_WORKING_SET_QUOTA:
  2217. case STATUS_NO_MEMORY:
  2218. case STATUS_CONFLICTING_ADDRESSES:
  2219. case STATUS_QUOTA_EXCEEDED:
  2220. case STATUS_TOO_MANY_PAGING_FILES:
  2221. case STATUS_REMOTE_RESOURCES:
  2222. case STATUS_TOO_MANY_ADDRESSES:
  2223. return WSAENOBUFS;
  2224. case STATUS_SHARING_VIOLATION:
  2225. case STATUS_ADDRESS_ALREADY_EXISTS:
  2226. return WSAEADDRINUSE;
  2227. case STATUS_LINK_TIMEOUT:
  2228. case STATUS_IO_TIMEOUT:
  2229. case STATUS_TIMEOUT:
  2230. return WSAETIMEDOUT;
  2231. case STATUS_GRACEFUL_DISCONNECT:
  2232. return WSAEDISCON;
  2233. case STATUS_REMOTE_DISCONNECT:
  2234. case STATUS_CONNECTION_RESET:
  2235. case STATUS_LINK_FAILED:
  2236. case STATUS_CONNECTION_DISCONNECTED:
  2237. case STATUS_PORT_UNREACHABLE:
  2238. return WSAECONNRESET;
  2239. case STATUS_LOCAL_DISCONNECT:
  2240. case STATUS_TRANSACTION_ABORTED:
  2241. case STATUS_CONNECTION_ABORTED:
  2242. return WSAECONNABORTED;
  2243. case STATUS_BAD_NETWORK_PATH:
  2244. case STATUS_NETWORK_UNREACHABLE:
  2245. case STATUS_PROTOCOL_UNREACHABLE:
  2246. return WSAENETUNREACH;
  2247. case STATUS_HOST_UNREACHABLE:
  2248. return WSAEHOSTUNREACH;
  2249. case STATUS_CANCELLED:
  2250. case STATUS_REQUEST_ABORTED:
  2251. return WSAEINTR;
  2252. case STATUS_BUFFER_OVERFLOW:
  2253. case STATUS_INVALID_BUFFER_SIZE:
  2254. return WSAEMSGSIZE;
  2255. case STATUS_BUFFER_TOO_SMALL:
  2256. case STATUS_ACCESS_VIOLATION:
  2257. return WSAEFAULT;
  2258. case STATUS_DEVICE_NOT_READY:
  2259. case STATUS_REQUEST_NOT_ACCEPTED:
  2260. return WSAEWOULDBLOCK;
  2261. case STATUS_INVALID_NETWORK_RESPONSE:
  2262. case STATUS_NETWORK_BUSY:
  2263. case STATUS_NO_SUCH_DEVICE:
  2264. case STATUS_NO_SUCH_FILE:
  2265. case STATUS_OBJECT_PATH_NOT_FOUND:
  2266. case STATUS_OBJECT_NAME_NOT_FOUND:
  2267. case STATUS_UNEXPECTED_NETWORK_ERROR:
  2268. return WSAENETDOWN;
  2269. case STATUS_INVALID_CONNECTION:
  2270. return WSAENOTCONN;
  2271. case STATUS_REMOTE_NOT_LISTENING:
  2272. case STATUS_CONNECTION_REFUSED:
  2273. return WSAECONNREFUSED;
  2274. case STATUS_PIPE_DISCONNECTED:
  2275. return WSAESHUTDOWN;
  2276. case STATUS_INVALID_ADDRESS:
  2277. case STATUS_INVALID_ADDRESS_COMPONENT:
  2278. return WSAEADDRNOTAVAIL;
  2279. case STATUS_NOT_SUPPORTED:
  2280. case STATUS_NOT_IMPLEMENTED:
  2281. return WSAEOPNOTSUPP;
  2282. case STATUS_ACCESS_DENIED:
  2283. return WSAEACCES;
  2284. default:
  2285. if ( NT_SUCCESS(Status) ) {
  2286. #if DBG
  2287. DbgPrint ("SockNtStatusToSocketError: success status %lx "
  2288. "not mapped\n", Status );
  2289. #endif
  2290. return NO_ERROR;
  2291. }
  2292. #if DBG
  2293. DbgPrint ("SockNtStatusToSocketError: unable to map 0x%lX, returning\n", Status );
  2294. #endif
  2295. return WSAENOBUFS;
  2296. case STATUS_UNSUCCESSFUL:
  2297. case STATUS_INVALID_PARAMETER:
  2298. case STATUS_ADDRESS_CLOSED:
  2299. case STATUS_CONNECTION_INVALID:
  2300. case STATUS_ADDRESS_ALREADY_ASSOCIATED:
  2301. case STATUS_ADDRESS_NOT_ASSOCIATED:
  2302. case STATUS_CONNECTION_ACTIVE:
  2303. case STATUS_INVALID_DEVICE_STATE:
  2304. case STATUS_INVALID_DEVICE_REQUEST:
  2305. return WSAEINVAL;
  2306. }
  2307. } // NtStatusToSocketError
  2308. VOID
  2309. CompleteTdiActionApc (
  2310. IN PVOID ApcContext,
  2311. IN PIO_STATUS_BLOCK IoStatusBlock
  2312. )
  2313. {
  2314. //
  2315. // Just free the heap we allocated to hold the IO status block and
  2316. // the TDI action buffer. There is nothing we can do if the call
  2317. // failed.
  2318. //
  2319. RtlFreeHeap( RtlProcessHeap( ), 0, ApcContext );
  2320. } // CompleteTdiActionApc
  2321. INT
  2322. SetTdiInformation (
  2323. IN HANDLE TdiObjectHandle,
  2324. IN ULONG Ioctl,
  2325. IN PVOID InputBuffer,
  2326. IN ULONG InputBufferLength,
  2327. IN PVOID OutputBuffer,
  2328. IN ULONG OutputBufferLength,
  2329. IN BOOLEAN WaitForCompletion
  2330. )
  2331. /*++
  2332. Routine Description:
  2333. Performs a TDI action to the TCP/IP driver. A TDI action translates
  2334. into a streams T_OPTMGMT_REQ.
  2335. Arguments:
  2336. TdiConnectionObjectHandle - a TDI connection object on which to perform
  2337. the TDI action.
  2338. Entity - value to put in the tei_entity field of the TDIObjectID
  2339. structure.
  2340. Class - value to put in the toi_class field of the TDIObjectID
  2341. structure.
  2342. Type - value to put in the toi_type field of the TDIObjectID
  2343. structure.
  2344. Id - value to put in the toi_id field of the TDIObjectID structure.
  2345. InputBuffer - a pointer to a buffer to set as the information.
  2346. InputBufferLength - the length of the buffer.
  2347. WaitForCompletion - TRUE if we should wait for the TDI action to
  2348. complete, FALSE if we're at APC level and cannot do a wait.
  2349. Return Value:
  2350. INT - NO_ERROR, or a Windows Sockets error code.
  2351. --*/
  2352. {
  2353. NTSTATUS status;
  2354. PVOID completionApc;
  2355. PVOID apcContext;
  2356. IO_STATUS_BLOCK IoStatusBlock;
  2357. IO_STATUS_BLOCK *pIoStatusBlock;
  2358. if (WaitForCompletion || InputBufferLength>32)
  2359. {
  2360. //
  2361. // Allocate space to hold the TDI set information buffers and the IO
  2362. // status block. These cannot be stack variables in case we must
  2363. // return before the operation is complete.
  2364. //
  2365. pIoStatusBlock = RtlAllocateHeap (RtlProcessHeap( ),
  2366. 0,
  2367. sizeof (*pIoStatusBlock));
  2368. if (pIoStatusBlock == NULL)
  2369. {
  2370. return WSAENOBUFS;
  2371. }
  2372. }
  2373. else
  2374. {
  2375. pIoStatusBlock = (PIO_STATUS_BLOCK) &IoStatusBlock;
  2376. }
  2377. //
  2378. // If we need to wait for completion of the operation, create an
  2379. // event to wait on. If we can't wait for completion because we
  2380. // are being called at APC level, we'll use an APC routine to
  2381. // free the heap we allocated above.
  2382. //
  2383. if (WaitForCompletion)
  2384. {
  2385. completionApc = NULL;
  2386. apcContext = NULL;
  2387. }
  2388. else
  2389. {
  2390. completionApc = CompleteTdiActionApc;
  2391. apcContext = pIoStatusBlock;
  2392. }
  2393. //
  2394. // Make the actual TDI action call. The Streams TDI mapper will
  2395. // translate this into a TPI option management request for us and
  2396. // give it to .
  2397. //
  2398. IoStatusBlock.Status = STATUS_PENDING;
  2399. status = NtDeviceIoControlFile (TdiObjectHandle,
  2400. NULL,
  2401. completionApc,
  2402. apcContext,
  2403. pIoStatusBlock,
  2404. Ioctl,
  2405. InputBuffer,
  2406. InputBufferLength,
  2407. OutputBuffer, // Use same buffer as output buffer!
  2408. OutputBufferLength);
  2409. //
  2410. // If the call pended and we were supposed to wait for completion,
  2411. // then wait.
  2412. //
  2413. if ( status == STATUS_PENDING && WaitForCompletion)
  2414. {
  2415. #if DBG
  2416. INT count=0;
  2417. #endif
  2418. while (pIoStatusBlock->Status==STATUS_PENDING)
  2419. {
  2420. LARGE_INTEGER timeout;
  2421. //
  2422. // Wait one millisecond
  2423. //
  2424. timeout.QuadPart = -1i64*1000i64*10i64;
  2425. NtDelayExecution (FALSE, &timeout);
  2426. #if DBG
  2427. if (count++>10*1000)
  2428. {
  2429. DbgPrint ("WSHPGM: Waiting for PGM IOCTL completion for more than 10 seconds!!!!\n");
  2430. DbgBreakPoint ();
  2431. }
  2432. #endif
  2433. }
  2434. status = pIoStatusBlock->Status;
  2435. }
  2436. if ((pIoStatusBlock != (PIO_STATUS_BLOCK) &IoStatusBlock) &&
  2437. (WaitForCompletion || !NT_SUCCESS(status)))
  2438. {
  2439. RtlFreeHeap (RtlProcessHeap( ), 0, pIoStatusBlock);
  2440. }
  2441. if (NT_SUCCESS (status))
  2442. {
  2443. return NO_ERROR;
  2444. }
  2445. else
  2446. {
  2447. return NtStatusToSocketError (status);
  2448. }
  2449. } // SetTdiInformation
  2450. //----------------------------------------------------------------------------
  2451. //----------------------------------------------------------------------------