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.

1716 lines
42 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. wshclus.c
  5. Abstract:
  6. This module contains necessary routines for the Cluster Transport
  7. Windows Sockets Helper DLL. This DLL provides the transport-specific
  8. support necessary for the Windows Sockets DLL to use the Cluster
  9. Transport.
  10. This file is largely a clone of the TCP/IP helper code.
  11. Author:
  12. Mike Massa (mikemas) 21-Feb-1997
  13. Revision History:
  14. --*/
  15. #define UNICODE
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <wchar.h>
  23. #include <tdi.h>
  24. #include <winsock2.h>
  25. #include <wsahelp.h>
  26. #include <ws2spi.h>
  27. #include <basetyps.h>
  28. #include <nspapi.h>
  29. #include <nspapip.h>
  30. #include <wsclus.h>
  31. #include <clustdi.h>
  32. #include <clusdef.h>
  33. #include <ntddcnet.h>
  34. #include "clstrcmp.h"
  35. #define CDP_NAME L"CDP"
  36. #define IS_DGRAM_SOCK(type) ((type) == SOCK_DGRAM)
  37. //
  38. // Define valid flags for WSHOpenSocket2().
  39. //
  40. #define VALID_CDP_FLAGS (WSA_FLAG_OVERLAPPED)
  41. //
  42. // Structure and variables to define the triples supported by the
  43. // Cluster 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 CdpMappingTriples[] =
  53. { AF_CLUSTER, SOCK_DGRAM, CLUSPROTO_CDP,
  54. AF_CLUSTER, SOCK_DGRAM, 0,
  55. AF_CLUSTER, 0, CLUSPROTO_CDP,
  56. AF_UNSPEC, 0, CLUSPROTO_CDP,
  57. AF_UNSPEC, SOCK_DGRAM, CLUSPROTO_CDP
  58. };
  59. //
  60. // Winsock 2 WSAPROTOCOL_INFO structures for all supported protocols.
  61. //
  62. #define WINSOCK_SPI_VERSION 2
  63. #define CDP_MESSAGE_SIZE (65535-20-68)
  64. WSAPROTOCOL_INFOW Winsock2Protocols[] =
  65. {
  66. //
  67. // CDP
  68. //
  69. {
  70. XP1_CONNECTIONLESS // dwServiceFlags1
  71. | XP1_MESSAGE_ORIENTED
  72. | XP1_IFS_HANDLES,
  73. 0, // dwServiceFlags2
  74. 0, // dwServiceFlags3
  75. 0, // dwServiceFlags4
  76. PFL_MATCHES_PROTOCOL_ZERO // dwProviderFlags
  77. | PFL_HIDDEN,
  78. { // gProviderId
  79. 0, 0, 0,
  80. { 0, 0, 0, 0, 0, 0, 0, 0 }
  81. },
  82. 0, // dwCatalogEntryId
  83. { // ProtocolChain
  84. BASE_PROTOCOL, // ChainLen
  85. { 0, 0, 0, 0, 0, 0, 0 } // ChainEntries
  86. },
  87. WINSOCK_SPI_VERSION, // iVersion
  88. AF_CLUSTER, // iAddressFamily
  89. sizeof(SOCKADDR_CLUSTER), // iMaxSockAddr
  90. sizeof(SOCKADDR_CLUSTER), // iMinSockAddr
  91. SOCK_DGRAM, // iSocketType
  92. CLUSPROTO_CDP, // iProtocol
  93. 0, // iProtocolMaxOffset
  94. LITTLEENDIAN, // iNetworkByteOrder
  95. SECURITY_PROTOCOL_NONE, // iSecurityScheme
  96. CDP_MESSAGE_SIZE, // dwMessageSize
  97. 0, // dwProviderReserved
  98. L"MSAFD Cluster Datagram Protocol" // szProtocol
  99. }
  100. };
  101. #define NUM_WINSOCK2_PROTOCOLS \
  102. ( sizeof(Winsock2Protocols) / sizeof(Winsock2Protocols[0]) )
  103. //
  104. // The GUID identifying this provider.
  105. //
  106. GUID ClusnetProviderGuid = { /* 03614682-8c42-11d0-a8fc-00a0c9062993 */
  107. 0x03614682,
  108. 0x8c42,
  109. 0x11d0,
  110. {0x00, 0xa0, 0xc9, 0x06, 0x29, 0x93, 0x8c}
  111. };
  112. LPWSTR ClusnetProviderName = L"ClusNet";
  113. //
  114. // Forward declarations of internal routines.
  115. //
  116. BOOLEAN
  117. IsTripleInList (
  118. IN PMAPPING_TRIPLE List,
  119. IN ULONG ListLength,
  120. IN INT AddressFamily,
  121. IN INT SocketType,
  122. IN INT Protocol
  123. );
  124. NTSTATUS
  125. DoNtIoctl(
  126. HANDLE Handle,
  127. DWORD IoctlCode,
  128. PVOID Request,
  129. DWORD RequestSize,
  130. PVOID Response,
  131. PDWORD ResponseSize
  132. );
  133. //
  134. // The socket context structure for this DLL. Each open ClusNet socket
  135. // will have one of these context structures, which is used to maintain
  136. // information about the socket.
  137. //
  138. typedef struct _WSHSOCKET_CONTEXT {
  139. INT AddressFamily;
  140. INT SocketType;
  141. INT Protocol;
  142. INT ReceiveBufferSize;
  143. DWORD Flags;
  144. BOOLEAN IgnoreNodeState;
  145. } WSHSOCKET_CONTEXT, *PWSHSOCKET_CONTEXT;
  146. #define DEFAULT_RECEIVE_BUFFER_SIZE 8192
  147. BOOLEAN
  148. DllInitialize (
  149. IN PVOID DllHandle,
  150. IN ULONG Reason,
  151. IN PVOID Context OPTIONAL
  152. )
  153. {
  154. switch ( Reason ) {
  155. case DLL_PROCESS_ATTACH:
  156. //
  157. // We don't need to receive thread attach and detach
  158. // notifications, so disable them to help application
  159. // performance.
  160. //
  161. DisableThreadLibraryCalls( DllHandle );
  162. return TRUE;
  163. case DLL_THREAD_ATTACH:
  164. break;
  165. case DLL_PROCESS_DETACH:
  166. break;
  167. case DLL_THREAD_DETACH:
  168. break;
  169. }
  170. return TRUE;
  171. } // DllInitialize
  172. INT
  173. WSHGetSockaddrType (
  174. IN PSOCKADDR Sockaddr,
  175. IN DWORD SockaddrLength,
  176. OUT PSOCKADDR_INFO SockaddrInfo
  177. )
  178. /*++
  179. Routine Description:
  180. This routine parses a sockaddr to determine the type of the
  181. machine address and endpoint address portions of the sockaddr.
  182. This is called by the winsock DLL whenever it needs to interpret
  183. a sockaddr.
  184. Arguments:
  185. Sockaddr - a pointer to the sockaddr structure to evaluate.
  186. SockaddrLength - the number of bytes in the sockaddr structure.
  187. SockaddrInfo - a pointer to a structure that will receive information
  188. about the specified sockaddr.
  189. Return Value:
  190. INT - a winsock error code indicating the status of the operation, or
  191. NO_ERROR if the operation succeeded.
  192. --*/
  193. {
  194. UNALIGNED SOCKADDR_CLUSTER *sockaddr = (PSOCKADDR_CLUSTER)Sockaddr;
  195. ULONG i;
  196. //
  197. // Make sure that the address family is correct.
  198. //
  199. if ( sockaddr->sac_family != AF_CLUSTER ) {
  200. return WSAEAFNOSUPPORT;
  201. }
  202. //
  203. // Make sure that the length is correct.
  204. //
  205. if ( SockaddrLength < sizeof(SOCKADDR_CLUSTER) ) {
  206. return WSAEFAULT;
  207. }
  208. //
  209. // The address passed the tests, looks like a good address.
  210. // Determine the type of the address portion of the sockaddr.
  211. //
  212. if ( sockaddr->sac_node == CLUSADDR_ANY ) {
  213. SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
  214. } else {
  215. SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
  216. }
  217. //
  218. // Determine the type of the port (endpoint) in the sockaddr.
  219. //
  220. if ( sockaddr->sac_port == 0 ) {
  221. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
  222. } else {
  223. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
  224. }
  225. //
  226. // Zero out the sin_reserved_mbz part of the address. We silently allow
  227. // nonzero values in this field.
  228. //
  229. sockaddr->sac_zero = 0;
  230. return NO_ERROR;
  231. } // WSHGetSockaddrType
  232. INT
  233. WSHGetSocketInformation (
  234. IN PVOID HelperDllSocketContext,
  235. IN SOCKET SocketHandle,
  236. IN HANDLE TdiAddressObjectHandle,
  237. IN HANDLE TdiConnectionObjectHandle,
  238. IN INT Level,
  239. IN INT OptionName,
  240. OUT PCHAR OptionValue,
  241. OUT PINT OptionLength
  242. )
  243. /*++
  244. Routine Description:
  245. This routine retrieves information about a socket for those socket
  246. options supported in this helper DLL. This routine is
  247. called by the winsock DLL when a level/option name combination is
  248. passed to getsockopt() that the winsock DLL does not understand.
  249. Arguments:
  250. HelperDllSocketContext - the context pointer returned from
  251. WSHOpenSocket().
  252. SocketHandle - the handle of the socket for which we're getting
  253. information.
  254. TdiAddressObjectHandle - the TDI address object of the socket, if
  255. any. If the socket is not yet bound to an address, then
  256. it does not have a TDI address object and this parameter
  257. will be NULL.
  258. TdiConnectionObjectHandle - the TDI connection object of the socket,
  259. if any. If the socket is not yet connected, then it does not
  260. have a TDI connection object and this parameter will be NULL.
  261. Level - the level parameter passed to getsockopt().
  262. OptionName - the optname parameter passed to getsockopt().
  263. OptionValue - the optval parameter passed to getsockopt().
  264. OptionLength - the optlen parameter passed to getsockopt().
  265. Return Value:
  266. INT - a winsock error code indicating the status of the operation, or
  267. NO_ERROR if the operation succeeded.
  268. --*/
  269. {
  270. PWSHSOCKET_CONTEXT context = HelperDllSocketContext;
  271. UNREFERENCED_PARAMETER( SocketHandle );
  272. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  273. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  274. return WSAENOPROTOOPT;
  275. } // WSHGetSocketInformation
  276. INT
  277. WSHGetWildcardSockaddr (
  278. IN PVOID HelperDllSocketContext,
  279. OUT PSOCKADDR Sockaddr,
  280. OUT PINT SockaddrLength
  281. )
  282. /*++
  283. Routine Description:
  284. This routine returns a wildcard socket address. A wildcard address
  285. is one which will bind the socket to an endpoint of the transport's
  286. choosing. For the Cluster Network, a wildcard address has
  287. node ID == 0 and port = 0.
  288. Arguments:
  289. HelperDllSocketContext - the context pointer returned from
  290. WSHOpenSocket() for the socket for which we need a wildcard
  291. address.
  292. Sockaddr - points to a buffer which will receive the wildcard socket
  293. address.
  294. SockaddrLength - receives the length of the wioldcard sockaddr.
  295. Return Value:
  296. INT - a winsock error code indicating the status of the operation, or
  297. NO_ERROR if the operation succeeded.
  298. --*/
  299. {
  300. PSOCKADDR_CLUSTER ClusAddr = (PSOCKADDR_CLUSTER) Sockaddr;
  301. if ( *SockaddrLength < sizeof(SOCKADDR_CLUSTER) ) {
  302. return WSAEFAULT;
  303. }
  304. *SockaddrLength = sizeof(SOCKADDR_CLUSTER);
  305. ClusAddr->sac_family = AF_CLUSTER;
  306. ClusAddr->sac_port = 0;
  307. ClusAddr->sac_node = CLUSADDR_ANY;
  308. ClusAddr->sac_zero = 0;
  309. return NO_ERROR;
  310. } // WSAGetWildcardSockaddr
  311. DWORD
  312. WSHGetWinsockMapping (
  313. OUT PWINSOCK_MAPPING Mapping,
  314. IN DWORD MappingLength
  315. )
  316. /*++
  317. Routine Description:
  318. Returns the list of address family/socket type/protocol triples
  319. supported by this helper DLL.
  320. Arguments:
  321. Mapping - receives a pointer to a WINSOCK_MAPPING structure that
  322. describes the triples supported here.
  323. MappingLength - the length, in bytes, of the passed-in Mapping buffer.
  324. Return Value:
  325. DWORD - the length, in bytes, of a WINSOCK_MAPPING structure for this
  326. helper DLL. If the passed-in buffer is too small, the return
  327. value will indicate the size of a buffer needed to contain
  328. the WINSOCK_MAPPING structure.
  329. --*/
  330. {
  331. DWORD mappingLength;
  332. mappingLength = FIELD_OFFSET(WINSOCK_MAPPING, Mapping[0])
  333. + sizeof(CdpMappingTriples);
  334. //
  335. // If the passed-in buffer is too small, return the length needed
  336. // now without writing to the buffer. The caller should allocate
  337. // enough memory and call this routine again.
  338. //
  339. if ( mappingLength > MappingLength ) {
  340. return mappingLength;
  341. }
  342. //
  343. // Fill in the output mapping buffer with the list of triples
  344. // supported in this helper DLL.
  345. //
  346. Mapping->Rows = sizeof(CdpMappingTriples) / sizeof(CdpMappingTriples[0]);
  347. Mapping->Columns = sizeof(MAPPING_TRIPLE) / sizeof(DWORD);
  348. RtlMoveMemory(
  349. Mapping->Mapping,
  350. CdpMappingTriples,
  351. sizeof(CdpMappingTriples)
  352. );
  353. //
  354. // Return the number of bytes we wrote.
  355. //
  356. return mappingLength;
  357. } // WSHGetWinsockMapping
  358. INT
  359. WSHOpenSocket (
  360. IN OUT PINT AddressFamily,
  361. IN OUT PINT SocketType,
  362. IN OUT PINT Protocol,
  363. OUT PUNICODE_STRING TransportDeviceName,
  364. OUT PVOID *HelperDllSocketContext,
  365. OUT PDWORD NotificationEvents
  366. )
  367. {
  368. return WSHOpenSocket2(
  369. AddressFamily,
  370. SocketType,
  371. Protocol,
  372. 0, // Group
  373. 0, // Flags
  374. TransportDeviceName,
  375. HelperDllSocketContext,
  376. NotificationEvents
  377. );
  378. } // WSHOpenSocket
  379. INT
  380. WSHOpenSocket2 (
  381. IN OUT PINT AddressFamily,
  382. IN OUT PINT SocketType,
  383. IN OUT PINT Protocol,
  384. IN GROUP Group,
  385. IN DWORD Flags,
  386. OUT PUNICODE_STRING TransportDeviceName,
  387. OUT PVOID *HelperDllSocketContext,
  388. OUT PDWORD NotificationEvents
  389. )
  390. /*++
  391. Routine Description:
  392. Does the necessary work for this helper DLL to open a socket and is
  393. called by the winsock DLL in the socket() routine. This routine
  394. verifies that the specified triple is valid, determines the NT
  395. device name of the TDI provider that will support that triple,
  396. allocates space to hold the socket's context block, and
  397. canonicalizes the triple.
  398. Arguments:
  399. AddressFamily - on input, the address family specified in the
  400. socket() call. On output, the canonicalized value for the
  401. address family.
  402. SocketType - on input, the socket type specified in the socket()
  403. call. On output, the canonicalized value for the socket type.
  404. Protocol - on input, the protocol specified in the socket() call.
  405. On output, the canonicalized value for the protocol.
  406. Group - Identifies the group for the new socket.
  407. Flags - Zero or more WSA_FLAG_* flags as passed into WSASocket().
  408. TransportDeviceName - receives the name of the TDI provider that
  409. will support the specified triple.
  410. HelperDllSocketContext - receives a context pointer that the winsock
  411. DLL will return to this helper DLL on future calls involving
  412. this socket.
  413. NotificationEvents - receives a bitmask of those state transitions
  414. this helper DLL should be notified on.
  415. Return Value:
  416. INT - a winsock error code indicating the status of the operation, or
  417. NO_ERROR if the operation succeeded.
  418. --*/
  419. {
  420. PWSHSOCKET_CONTEXT context;
  421. if ( IsTripleInList(
  422. CdpMappingTriples,
  423. sizeof(CdpMappingTriples) / sizeof(CdpMappingTriples[0]),
  424. *AddressFamily,
  425. *SocketType,
  426. *Protocol ) ) {
  427. //
  428. // It's a CDP socket. Check the flags.
  429. //
  430. if( (Flags & ~VALID_CDP_FLAGS ) != 0) {
  431. return WSAEINVAL;
  432. }
  433. //
  434. // Return the canonical form of a CDP socket triple.
  435. //
  436. *AddressFamily = CdpMappingTriples[0].AddressFamily;
  437. *SocketType = CdpMappingTriples[0].SocketType;
  438. *Protocol = CdpMappingTriples[0].Protocol;
  439. //
  440. // Indicate the name of the TDI device that will service
  441. // SOCK_DGRAM sockets in the cluster address family.
  442. //
  443. RtlInitUnicodeString( TransportDeviceName, DD_CDP_DEVICE_NAME );
  444. } else {
  445. //
  446. // This should never happen if the registry information about this
  447. // helper DLL is correct. If somehow this did happen, just return
  448. // an error.
  449. //
  450. return WSAEINVAL;
  451. }
  452. //
  453. // Allocate context for this socket. The Windows Sockets DLL will
  454. // return this value to us when it asks us to get/set socket options.
  455. //
  456. context = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*context) );
  457. if ( context == NULL ) {
  458. return WSAENOBUFS;
  459. }
  460. //
  461. // Initialize the context for the socket.
  462. //
  463. context->AddressFamily = *AddressFamily;
  464. context->SocketType = *SocketType;
  465. context->Protocol = *Protocol;
  466. context->ReceiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
  467. context->Flags = Flags;
  468. context->IgnoreNodeState = FALSE;
  469. //
  470. // Tell the Windows Sockets DLL which state transitions we're
  471. // interested in being notified of.
  472. if (*SocketType == SOCK_DGRAM) {
  473. *NotificationEvents = WSH_NOTIFY_CLOSE | WSH_NOTIFY_BIND;
  474. }
  475. //
  476. // Everything worked, return success.
  477. //
  478. *HelperDllSocketContext = context;
  479. return NO_ERROR;
  480. } // WSHOpenSocket2
  481. INT
  482. WSHNotify (
  483. IN PVOID HelperDllSocketContext,
  484. IN SOCKET SocketHandle,
  485. IN HANDLE TdiAddressObjectHandle,
  486. IN HANDLE TdiConnectionObjectHandle,
  487. IN DWORD NotifyEvent
  488. )
  489. /*++
  490. Routine Description:
  491. This routine is called by the winsock DLL after a state transition
  492. of the socket. Only state transitions returned in the
  493. NotificationEvents parameter of WSHOpenSocket() are notified here.
  494. This routine allows a winsock helper DLL to track the state of
  495. socket and perform necessary actions corresponding to state
  496. transitions.
  497. Arguments:
  498. HelperDllSocketContext - the context pointer given to the winsock
  499. DLL by WSHOpenSocket().
  500. SocketHandle - the handle for the socket.
  501. TdiAddressObjectHandle - the TDI address object of the socket, if
  502. any. If the socket is not yet bound to an address, then
  503. it does not have a TDI address object and this parameter
  504. will be NULL.
  505. TdiConnectionObjectHandle - the TDI connection object of the socket,
  506. if any. If the socket is not yet connected, then it does not
  507. have a TDI connection object and this parameter will be NULL.
  508. NotifyEvent - indicates the state transition for which we're being
  509. called.
  510. Return Value:
  511. INT - a winsock error code indicating the status of the operation, or
  512. NO_ERROR if the operation succeeded.
  513. --*/
  514. {
  515. PWSHSOCKET_CONTEXT context = HelperDllSocketContext;
  516. INT err;
  517. if ( NotifyEvent == WSH_NOTIFY_CLOSE ) {
  518. //
  519. // Free the socket context.
  520. //
  521. RtlFreeHeap( RtlProcessHeap( ), 0, context );
  522. } else if ( NotifyEvent == WSH_NOTIFY_BIND ) {
  523. ULONG true = TRUE;
  524. if ( context->IgnoreNodeState ) {
  525. ULONG responseSize = 0;
  526. NTSTATUS status;
  527. status = DoNtIoctl(
  528. TdiAddressObjectHandle,
  529. IOCTL_CX_IGNORE_NODE_STATE,
  530. NULL,
  531. 0,
  532. NULL,
  533. &responseSize
  534. );
  535. if( !NT_SUCCESS(status)) {
  536. return(WSAENOPROTOOPT); // SWAG
  537. }
  538. }
  539. }
  540. else {
  541. return WSAEINVAL;
  542. }
  543. return NO_ERROR;
  544. } // WSHNotify
  545. INT
  546. WSHSetSocketInformation (
  547. IN PVOID HelperDllSocketContext,
  548. IN SOCKET SocketHandle,
  549. IN HANDLE TdiAddressObjectHandle,
  550. IN HANDLE TdiConnectionObjectHandle,
  551. IN INT Level,
  552. IN INT OptionName,
  553. IN PCHAR OptionValue,
  554. IN INT OptionLength
  555. )
  556. /*++
  557. Routine Description:
  558. This routine sets information about a socket for those socket
  559. options supported in this helper DLL. This routine is
  560. called by the winsock DLL when a level/option name combination is
  561. passed to setsockopt() that the winsock DLL does not understand.
  562. Arguments:
  563. HelperDllSocketContext - the context pointer returned from
  564. WSHOpenSocket().
  565. SocketHandle - the handle of the socket for which we're getting
  566. information.
  567. TdiAddressObjectHandle - the TDI address object of the socket, if
  568. any. If the socket is not yet bound to an address, then
  569. it does not have a TDI address object and this parameter
  570. will be NULL.
  571. TdiConnectionObjectHandle - the TDI connection object of the socket,
  572. if any. If the socket is not yet connected, then it does not
  573. have a TDI connection object and this parameter will be NULL.
  574. Level - the level parameter passed to setsockopt().
  575. OptionName - the optname parameter passed to setsockopt().
  576. OptionValue - the optval parameter passed to setsockopt().
  577. OptionLength - the optlen parameter passed to setsockopt().
  578. Return Value:
  579. INT - a winsock error code indicating the status of the operation, or
  580. NO_ERROR if the operation succeeded.
  581. --*/
  582. {
  583. PWSHSOCKET_CONTEXT context = HelperDllSocketContext;
  584. INT error;
  585. INT optionValue;
  586. UNREFERENCED_PARAMETER( SocketHandle );
  587. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  588. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  589. //
  590. // Check if this is an internal request for context information.
  591. //
  592. if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
  593. //
  594. // The Windows Sockets DLL is requesting that we set context
  595. // information for a new socket. If the new socket was
  596. // accept()'ed, then we have already been notified of the socket
  597. // and HelperDllSocketContext will be valid. If the new socket
  598. // was inherited or duped into this process, then this is our
  599. // first notification of the socket and HelperDllSocketContext
  600. // will be equal to NULL.
  601. //
  602. // Insure that the context information being passed to us is
  603. // sufficiently large.
  604. //
  605. if ( OptionLength < sizeof(*context) ) {
  606. return WSAEINVAL;
  607. }
  608. if ( HelperDllSocketContext == NULL ) {
  609. //
  610. // This is our notification that a socket handle was
  611. // inherited or duped into this process. Allocate a context
  612. // structure for the new socket.
  613. //
  614. context = RtlAllocateHeap(
  615. RtlProcessHeap( ),
  616. 0,
  617. sizeof(*context)
  618. );
  619. if ( context == NULL ) {
  620. return WSAENOBUFS;
  621. }
  622. //
  623. // Copy over information into the context block.
  624. //
  625. RtlCopyMemory( context, OptionValue, sizeof(*context) );
  626. //
  627. // Tell the Windows Sockets DLL where our context information is
  628. // stored so that it can return the context pointer in future
  629. // calls.
  630. //
  631. *(PWSHSOCKET_CONTEXT *)OptionValue = context;
  632. return NO_ERROR;
  633. }
  634. }
  635. return WSAENOPROTOOPT;
  636. } // WSHSetSocketInformation
  637. INT
  638. WSHEnumProtocols (
  639. IN LPINT lpiProtocols,
  640. IN LPWSTR lpTransportKeyName,
  641. IN OUT LPVOID lpProtocolBuffer,
  642. IN OUT LPDWORD lpdwBufferLength
  643. )
  644. /*++
  645. Routine Description:
  646. Enumerates the protocols supported by this helper.
  647. Arguments:
  648. lpiProtocols - Pointer to a NULL-terminated array of protocol
  649. identifiers. Only protocols specified in this array will
  650. be returned by this function. If this pointer is NULL,
  651. all protocols are returned.
  652. lpTransportKeyName -
  653. lpProtocolBuffer - Pointer to a buffer to fill with PROTOCOL_INFO
  654. structures.
  655. lpdwBufferLength - Pointer to a variable that, on input, contains
  656. the size of lpProtocolBuffer. On output, this value will be
  657. updated with the size of the data actually written to the buffer.
  658. Return Value:
  659. INT - The number of protocols returned if successful, -1 if not.
  660. --*/
  661. {
  662. DWORD bytesRequired;
  663. PPROTOCOL_INFO CdpProtocolInfo;
  664. BOOL useCdp = FALSE;
  665. DWORD i;
  666. UNREFERENCED_PARAMETER(lpTransportKeyName);
  667. //
  668. // Make sure that the caller cares about CDP.
  669. //
  670. if ( ARGUMENT_PRESENT( lpiProtocols ) ) {
  671. for ( i = 0; lpiProtocols[i] != 0; i++ ) {
  672. if ( lpiProtocols[i] == CLUSPROTO_CDP ) {
  673. useCdp = TRUE;
  674. }
  675. }
  676. } else {
  677. useCdp = TRUE;
  678. }
  679. if ( !useCdp ) {
  680. *lpdwBufferLength = 0;
  681. return 0;
  682. }
  683. //
  684. // Make sure that the caller has specified a sufficiently large
  685. // buffer.
  686. //
  687. bytesRequired = (DWORD)((sizeof(PROTOCOL_INFO) * 1) +
  688. ( (wcslen( CDP_NAME ) + 1) * sizeof(WCHAR)));
  689. if ( bytesRequired > *lpdwBufferLength ) {
  690. *lpdwBufferLength = bytesRequired;
  691. return -1;
  692. }
  693. //
  694. // Fill in CDP info, if requested.
  695. //
  696. if ( useCdp ) {
  697. CdpProtocolInfo = lpProtocolBuffer;
  698. CdpProtocolInfo->lpProtocol = (LPWSTR)
  699. ( (PBYTE)lpProtocolBuffer + *lpdwBufferLength -
  700. ( (wcslen( CDP_NAME ) + 1) * sizeof(WCHAR) ) );
  701. CdpProtocolInfo->dwServiceFlags = XP_CONNECTIONLESS |
  702. XP_MESSAGE_ORIENTED;
  703. CdpProtocolInfo->iAddressFamily = AF_CLUSTER;
  704. CdpProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_CLUSTER);
  705. CdpProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_CLUSTER);
  706. CdpProtocolInfo->iSocketType = SOCK_DGRAM;
  707. CdpProtocolInfo->iProtocol = CLUSPROTO_CDP;
  708. CdpProtocolInfo->dwMessageSize = CDP_MESSAGE_SIZE;
  709. wcscpy( CdpProtocolInfo->lpProtocol, CDP_NAME );
  710. }
  711. *lpdwBufferLength = bytesRequired;
  712. return 1;
  713. } // WSHEnumProtocols
  714. BOOLEAN
  715. IsTripleInList (
  716. IN PMAPPING_TRIPLE List,
  717. IN ULONG ListLength,
  718. IN INT AddressFamily,
  719. IN INT SocketType,
  720. IN INT Protocol
  721. )
  722. /*++
  723. Routine Description:
  724. Determines whether the specified triple has an exact match in the
  725. list of triples.
  726. Arguments:
  727. List - a list of triples (address family/socket type/protocol) to
  728. search.
  729. ListLength - the number of triples in the list.
  730. AddressFamily - the address family to look for in the list.
  731. SocketType - the socket type to look for in the list.
  732. Protocol - the protocol to look for in the list.
  733. Return Value:
  734. BOOLEAN - TRUE if the triple was found in the list, false if not.
  735. --*/
  736. {
  737. ULONG i;
  738. //
  739. // Walk through the list searching for an exact match.
  740. //
  741. for ( i = 0; i < ListLength; i++ ) {
  742. //
  743. // If all three elements of the triple match, return indicating
  744. // that the triple did exist in the list.
  745. //
  746. if ( AddressFamily == List[i].AddressFamily &&
  747. SocketType == List[i].SocketType &&
  748. Protocol == List[i].Protocol
  749. ) {
  750. return TRUE;
  751. }
  752. }
  753. //
  754. // The triple was not found in the list.
  755. //
  756. return FALSE;
  757. } // IsTripleInList
  758. #if 0
  759. INT
  760. WINAPI
  761. WSHGetBroadcastSockaddr (
  762. IN PVOID HelperDllSocketContext,
  763. OUT PSOCKADDR Sockaddr,
  764. OUT PINT SockaddrLength
  765. )
  766. /*++
  767. Routine Description:
  768. This routine returns a broadcast socket address. A broadcast address
  769. may be used as a destination for the sendto() API to send a datagram
  770. to all interested clients.
  771. Arguments:
  772. HelperDllSocketContext - the context pointer returned from
  773. WSHOpenSocket() for the socket for which we need a broadcast
  774. address.
  775. Sockaddr - points to a buffer which will receive the broadcast socket
  776. address.
  777. SockaddrLength - receives the length of the broadcast sockaddr.
  778. Return Value:
  779. INT - a winsock error code indicating the status of the operation, or
  780. NO_ERROR if the operation succeeded.
  781. --*/
  782. {
  783. LPSOCKADDR_CLUSTER addr;
  784. if( *SockaddrLength < sizeof(SOCKADDR_CLUSTER) ) {
  785. return WSAEFAULT;
  786. }
  787. *SockaddrLength = sizeof(SOCKADDR_CLUSTER);
  788. //
  789. // Build the broadcast address.
  790. //
  791. addr = (LPSOCKADDR_CLUSTER)Sockaddr;
  792. RtlZeroMemory( addr, sizeof(*addr));
  793. addr->sac_family = AF_CLUSTER;
  794. addr->sac_node = CLUSADDR_BROADCAST;
  795. return NO_ERROR;
  796. } // WSAGetBroadcastSockaddr
  797. #endif // 0
  798. INT
  799. WINAPI
  800. WSHGetWSAProtocolInfo (
  801. IN LPWSTR ProviderName,
  802. OUT LPWSAPROTOCOL_INFOW * ProtocolInfo,
  803. OUT LPDWORD ProtocolInfoEntries
  804. )
  805. /*++
  806. Routine Description:
  807. Retrieves a pointer to the WSAPROTOCOL_INFOW structure(s) describing
  808. the protocol(s) supported by this helper.
  809. Arguments:
  810. ProviderName - Contains the name of the provider, such as "TcpIp".
  811. ProtocolInfo - Receives a pointer to the WSAPROTOCOL_INFOW array.
  812. ProtocolInfoEntries - Receives the number of entries in the array.
  813. Return Value:
  814. INT - 0 if successful, WinSock error code if not.
  815. --*/
  816. {
  817. if( ProviderName == NULL ||
  818. ProtocolInfo == NULL ||
  819. ProtocolInfoEntries == NULL ) {
  820. return WSAEFAULT;
  821. }
  822. if( ClRtlStrICmp( ProviderName, ClusnetProviderName ) == 0 ) {
  823. *ProtocolInfo = Winsock2Protocols;
  824. *ProtocolInfoEntries = NUM_WINSOCK2_PROTOCOLS;
  825. return NO_ERROR;
  826. }
  827. return WSAEINVAL;
  828. } // WSHGetWSAProtocolInfo
  829. INT
  830. WINAPI
  831. WSHAddressToString (
  832. IN LPSOCKADDR Address,
  833. IN INT AddressLength,
  834. IN LPWSAPROTOCOL_INFOW ProtocolInfo,
  835. OUT LPWSTR AddressString,
  836. IN OUT LPDWORD AddressStringLength
  837. )
  838. /*++
  839. Routine Description:
  840. Converts a SOCKADDR to a human-readable form.
  841. Arguments:
  842. Address - The SOCKADDR to convert.
  843. AddressLength - The length of Address.
  844. ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
  845. AddressString - Receives the formatted address string.
  846. AddressStringLength - On input, contains the length of AddressString.
  847. On output, contains the number of characters actually written
  848. to AddressString.
  849. Return Value:
  850. INT - 0 if successful, WinSock error code if not.
  851. --*/
  852. {
  853. WCHAR string[32];
  854. INT length;
  855. LPSOCKADDR_CLUSTER addr;
  856. //
  857. // Quick sanity checks.
  858. //
  859. if( Address == NULL ||
  860. AddressLength < sizeof(SOCKADDR_CLUSTER) ||
  861. AddressString == NULL ||
  862. AddressStringLength == NULL ) {
  863. return WSAEFAULT;
  864. }
  865. addr = (LPSOCKADDR_CLUSTER)Address;
  866. if( addr->sac_family != AF_CLUSTER ) {
  867. return WSAEINVAL;
  868. }
  869. //
  870. // Do the converstion.
  871. //
  872. length = wsprintfW(string, L"%u", addr->sac_node);
  873. length += wsprintfW(string + length, L":%u", addr->sac_port);
  874. length++; // account for terminator
  875. if( *AddressStringLength < (DWORD)length ) {
  876. return WSAEFAULT;
  877. }
  878. *AddressStringLength = (DWORD)length;
  879. RtlCopyMemory(
  880. AddressString,
  881. string,
  882. length * sizeof(WCHAR)
  883. );
  884. return NO_ERROR;
  885. } // WSHAddressToString
  886. INT
  887. WINAPI
  888. WSHStringToAddress (
  889. IN LPWSTR AddressString,
  890. IN DWORD AddressFamily,
  891. IN LPWSAPROTOCOL_INFOW ProtocolInfo,
  892. OUT LPSOCKADDR Address,
  893. IN OUT LPINT AddressLength
  894. )
  895. /*++
  896. Routine Description:
  897. Fills in a SOCKADDR structure by parsing a human-readable string.
  898. Arguments:
  899. AddressString - Points to the zero-terminated human-readable string.
  900. AddressFamily - The address family to which the string belongs.
  901. ProtocolInfo - The WSAPROTOCOL_INFOW for a particular provider.
  902. Address - Receives the SOCKADDR structure.
  903. AddressLength - On input, contains the length of Address. On output,
  904. contains the number of bytes actually written to Address.
  905. Return Value:
  906. INT - 0 if successful, WinSock error code if not.
  907. --*/
  908. {
  909. LPWSTR terminator;
  910. WCHAR ch;
  911. USHORT base;
  912. USHORT port;
  913. ULONG node;
  914. LPSOCKADDR_CLUSTER addr;
  915. //
  916. // Quick sanity checks.
  917. //
  918. if( AddressString == NULL ||
  919. *AddressString == UNICODE_NULL ||
  920. Address == NULL ||
  921. AddressLength == NULL ||
  922. *AddressLength < sizeof(SOCKADDR_CLUSTER) ) {
  923. return WSAEFAULT;
  924. }
  925. if( AddressFamily != AF_CLUSTER ) {
  926. return WSAEINVAL;
  927. }
  928. //
  929. // Convert it. The format is node:port
  930. //
  931. node = 0;
  932. base = 10;
  933. terminator = AddressString;
  934. if( *terminator == L'0' ) {
  935. base = 8;
  936. terminator++;
  937. if( *terminator == UNICODE_NULL ) {
  938. return(WSAEINVAL);
  939. }
  940. if ( *terminator == L'x' ) {
  941. base = 16;
  942. terminator++;
  943. }
  944. }
  945. while( (ch = *terminator++) != L':' ) {
  946. if( iswdigit(ch) ) {
  947. node = ( node * base ) + ( ch - L'0' );
  948. } else if( base == 16 && iswxdigit(ch) ) {
  949. node = ( node << 4 );
  950. node += ch + 10 - ( iswlower(ch) ? L'a' : L'A' );
  951. } else {
  952. return WSAEINVAL;
  953. }
  954. }
  955. port = 0;
  956. base = 10;
  957. if( *terminator == L'0' ) {
  958. base = 8;
  959. terminator++;
  960. if( *terminator == UNICODE_NULL ) {
  961. return(WSAEINVAL);
  962. }
  963. if( *terminator == L'x' ) {
  964. base = 16;
  965. terminator++;
  966. }
  967. }
  968. while( (ch = *terminator++) != UNICODE_NULL ) {
  969. if( iswdigit(ch) ) {
  970. port = ( port * base ) + ( ch - L'0' );
  971. } else if( base == 16 && iswxdigit(ch) ) {
  972. port = ( port << 4 );
  973. port += ch + 10 - ( iswlower(ch) ? L'a' : L'A' );
  974. } else {
  975. return WSAEINVAL;
  976. }
  977. }
  978. //
  979. // Build the address.
  980. //
  981. RtlZeroMemory(
  982. Address,
  983. sizeof(SOCKADDR_CLUSTER)
  984. );
  985. addr = (LPSOCKADDR_CLUSTER)Address;
  986. *AddressLength = sizeof(SOCKADDR_CLUSTER);
  987. addr->sac_family = AF_CLUSTER;
  988. addr->sac_port = port;
  989. addr->sac_node = node;
  990. return NO_ERROR;
  991. } // WSHStringToAddress
  992. INT
  993. WINAPI
  994. WSHGetProviderGuid (
  995. IN LPWSTR ProviderName,
  996. OUT LPGUID ProviderGuid
  997. )
  998. /*++
  999. Routine Description:
  1000. Returns the GUID identifying the protocols supported by this helper.
  1001. Arguments:
  1002. ProviderName - Contains the name of the provider, such as "TcpIp".
  1003. ProviderGuid - Points to a buffer that receives the provider's GUID.
  1004. Return Value:
  1005. INT - 0 if successful, WinSock error code if not.
  1006. --*/
  1007. {
  1008. if( ProviderName == NULL ||
  1009. ProviderGuid == NULL ) {
  1010. return WSAEFAULT;
  1011. }
  1012. if( ClRtlStrICmp( ProviderName, ClusnetProviderName ) == 0 ) {
  1013. RtlCopyMemory(
  1014. ProviderGuid,
  1015. &ClusnetProviderGuid,
  1016. sizeof(GUID)
  1017. );
  1018. return NO_ERROR;
  1019. }
  1020. return WSAEINVAL;
  1021. } // WSHGetProviderGuid
  1022. INT
  1023. WINAPI
  1024. WSHIoctl (
  1025. IN PVOID HelperDllSocketContext,
  1026. IN SOCKET SocketHandle,
  1027. IN HANDLE TdiAddressObjectHandle,
  1028. IN HANDLE TdiConnectionObjectHandle,
  1029. IN DWORD IoControlCode,
  1030. IN LPVOID InputBuffer,
  1031. IN DWORD InputBufferLength,
  1032. IN LPVOID OutputBuffer,
  1033. IN DWORD OutputBufferLength,
  1034. OUT LPDWORD NumberOfBytesReturned,
  1035. IN LPWSAOVERLAPPED Overlapped,
  1036. IN LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine,
  1037. OUT LPBOOL NeedsCompletion
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. Performs queries & controls on the socket. This is basically an
  1042. "escape hatch" for IOCTLs not supported by MSAFD.DLL. Any unknown
  1043. IOCTLs are routed to the socket's helper DLL for protocol-specific
  1044. processing.
  1045. Arguments:
  1046. HelperDllSocketContext - the context pointer returned from
  1047. WSHOpenSocket().
  1048. SocketHandle - the handle of the socket for which we're controlling.
  1049. TdiAddressObjectHandle - the TDI address object of the socket, if
  1050. any. If the socket is not yet bound to an address, then
  1051. it does not have a TDI address object and this parameter
  1052. will be NULL.
  1053. TdiConnectionObjectHandle - the TDI connection object of the socket,
  1054. if any. If the socket is not yet connected, then it does not
  1055. have a TDI connection object and this parameter will be NULL.
  1056. IoControlCode - Control code of the operation to perform.
  1057. InputBuffer - Address of the input buffer.
  1058. InputBufferLength - The length of InputBuffer.
  1059. OutputBuffer - Address of the output buffer.
  1060. OutputBufferLength - The length of OutputBuffer.
  1061. NumberOfBytesReturned - Receives the number of bytes actually written
  1062. to the output buffer.
  1063. Overlapped - Pointer to a WSAOVERLAPPED structure for overlapped
  1064. operations.
  1065. CompletionRoutine - Pointer to a completion routine to call when
  1066. the operation is completed.
  1067. NeedsCompletion - WSAIoctl() can be overlapped, with all the gory
  1068. details that involves, such as setting events, queuing completion
  1069. routines, and posting to IO completion ports. Since the majority
  1070. of the IOCTL codes can be completed quickly "in-line", MSAFD.DLL
  1071. can optionally perform the overlapped completion of the operation.
  1072. Setting *NeedsCompletion to TRUE (the default) causes MSAFD.DLL
  1073. to handle all of the IO completion details iff this is an
  1074. overlapped operation on an overlapped socket.
  1075. Setting *NeedsCompletion to FALSE tells MSAFD.DLL to take no
  1076. further action because the helper DLL will perform any necessary
  1077. IO completion.
  1078. Note that if a helper performs its own IO completion, the helper
  1079. is responsible for maintaining the "overlapped" mode of the socket
  1080. at socket creation time and NOT performing overlapped IO completion
  1081. on non-overlapped sockets.
  1082. Return Value:
  1083. INT - 0 if successful, WinSock error code if not.
  1084. --*/
  1085. {
  1086. PWSHSOCKET_CONTEXT context = HelperDllSocketContext;
  1087. INT err;
  1088. //
  1089. // Quick sanity checks.
  1090. //
  1091. if( HelperDllSocketContext == NULL ||
  1092. SocketHandle == INVALID_SOCKET ||
  1093. NeedsCompletion == NULL ) {
  1094. return WSAEINVAL;
  1095. }
  1096. *NeedsCompletion = TRUE;
  1097. switch( IoControlCode ) {
  1098. case SIO_CLUS_IGNORE_NODE_STATE :
  1099. //
  1100. // This option is only valid for datagram sockets.
  1101. //
  1102. if ( !IS_DGRAM_SOCK(context->SocketType) ) {
  1103. return WSAENOPROTOOPT;
  1104. }
  1105. if( TdiAddressObjectHandle != NULL ) {
  1106. ULONG responseSize = 0;
  1107. NTSTATUS status;
  1108. status = DoNtIoctl(
  1109. TdiAddressObjectHandle,
  1110. IOCTL_CX_IGNORE_NODE_STATE,
  1111. NULL,
  1112. 0,
  1113. NULL,
  1114. &responseSize
  1115. );
  1116. if( NT_SUCCESS(status) ) {
  1117. err = NO_ERROR;
  1118. } else {
  1119. err = WSAENOPROTOOPT; // SWAG
  1120. }
  1121. }
  1122. else {
  1123. err = NO_ERROR;
  1124. }
  1125. context->IgnoreNodeState = TRUE;
  1126. break;
  1127. default :
  1128. err = WSAEINVAL;
  1129. break;
  1130. }
  1131. return err;
  1132. } // WSHIoctl
  1133. NTSTATUS
  1134. DoNtIoctl(
  1135. HANDLE Handle,
  1136. DWORD IoctlCode,
  1137. PVOID Request,
  1138. DWORD RequestSize,
  1139. PVOID Response,
  1140. PDWORD ResponseSize
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. Packages and issues an ioctl.
  1145. Arguments:
  1146. Handle - An open file Handle on which to issue the request.
  1147. IoctlCode - The IOCTL opcode.
  1148. Request - A pointer to the input buffer.
  1149. RequestSize - Size of the input buffer.
  1150. Response - A pointer to the output buffer.
  1151. ResponseSize - On input, the size in bytes of the output buffer.
  1152. On output, the number of bytes returned in the output buffer.
  1153. Return Value:
  1154. NT Status Code.
  1155. --*/
  1156. {
  1157. IO_STATUS_BLOCK ioStatusBlock;
  1158. NTSTATUS status = 0xaabbccdd;
  1159. HANDLE event;
  1160. event = CreateEvent(NULL, FALSE, FALSE, NULL);
  1161. if (event == NULL) {
  1162. return(GetLastError());
  1163. }
  1164. ioStatusBlock.Information = 0;
  1165. status = NtDeviceIoControlFile(
  1166. Handle, // Driver Handle
  1167. event, // Event
  1168. NULL, // APC Routine
  1169. NULL, // APC context
  1170. &ioStatusBlock, // Status block
  1171. IoctlCode, // Control code
  1172. Request, // Input buffer
  1173. RequestSize, // Input buffer size
  1174. Response, // Output buffer
  1175. *ResponseSize // Output buffer size
  1176. );
  1177. if (status == STATUS_PENDING) {
  1178. status = NtWaitForSingleObject(
  1179. event,
  1180. TRUE,
  1181. NULL
  1182. );
  1183. }
  1184. if (status == STATUS_SUCCESS) {
  1185. status = ioStatusBlock.Status;
  1186. // NOTENOTE: on 64 bit this truncates, might want to add > check code
  1187. *ResponseSize = (ULONG)ioStatusBlock.Information;
  1188. }
  1189. else {
  1190. *ResponseSize = 0;
  1191. }
  1192. CloseHandle(event);
  1193. return(status);
  1194. } // DoIoctl