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.

2502 lines
65 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. wshatalk.c
  5. Abstract:
  6. This module contains necessary routines for the Appletalk Windows Sockets
  7. Helper DLL. This DLL provides the transport-specific support necessary
  8. for the Windows Sockets DLL to use Appletalk as a transport.
  9. Author:
  10. David Treadwell (davidtr) 19-Jul-1992 - TCP/IP version
  11. Nikhil Kamkolkar (nikhilk) 17-Nov- 1992 - Appletalk version
  12. Revision History:
  13. --*/
  14. #include "nspatalk.h"
  15. #include "wshdata.h"
  16. // GLOBAL - get the mac code page value from the registry.
  17. int WshMacCodePage = 0;
  18. #if 0
  19. VOID
  20. PrintByteString(
  21. PUCHAR pSrcOemString,
  22. USHORT SrcStringLen
  23. )
  24. {
  25. DbgPrint("%x - ", SrcStringLen);
  26. while (SrcStringLen-- > 0)
  27. {
  28. DbgPrint("%x", *pSrcOemString++);
  29. }
  30. DbgPrint("\n");
  31. }
  32. #define DBGPRINT0 DBGPRINT
  33. #else
  34. #define DBGPRINT0
  35. #endif
  36. INT
  37. WSHGetSockaddrType (
  38. IN PSOCKADDR Sockaddr,
  39. IN DWORD SockaddrLength,
  40. OUT PSOCKADDR_INFO SockaddrInfo
  41. )
  42. /*++
  43. Routine Description:
  44. This routine parses a sockaddr to determine the type of the
  45. machine address and endpoint address portions of the sockaddr.
  46. This is called by the winsock DLL whenever it needs to interpret
  47. a sockaddr.
  48. Arguments:
  49. Sockaddr - a pointer to the sockaddr structure to evaluate.
  50. SockaddrLength - the number of bytes in the sockaddr structure.
  51. SockaddrInfo - a pointer to a structure that will receive information
  52. about the specified sockaddr.
  53. Return Value:
  54. INT - a winsock error code indicating the status of the operation, or
  55. NO_ERROR if the operation succeeded.
  56. --*/
  57. {
  58. UNALIGNED SOCKADDR_AT *sockaddr = (PSOCKADDR_AT)Sockaddr;
  59. DBGPRINT0(("WSHGetSockAddrType: Entered\n"));
  60. //
  61. // Make sure that the address family is correct.
  62. //
  63. if ( sockaddr->sat_family != AF_APPLETALK )
  64. {
  65. return WSAEAFNOSUPPORT;
  66. }
  67. //
  68. // Make sure that the length is correct.
  69. //
  70. if ( SockaddrLength < sizeof(SOCKADDR_AT) )
  71. {
  72. return WSAEFAULT;
  73. }
  74. //
  75. // The address passed the tests, looks like a good address.
  76. // Determine the type of the address portion of the sockaddr.
  77. //
  78. if ( sockaddr->sat_socket == ATADDR_ANY )
  79. {
  80. SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
  81. }
  82. else if ( sockaddr->sat_node == ATADDR_BROADCAST )
  83. {
  84. SockaddrInfo->AddressInfo = SockaddrAddressInfoBroadcast;
  85. }
  86. else
  87. {
  88. SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
  89. }
  90. //
  91. // Determine the type of the port (endpoint) in the sockaddr.
  92. //
  93. if ( sockaddr->sat_socket == 0 )
  94. {
  95. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
  96. }
  97. else
  98. {
  99. SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
  100. }
  101. return NO_ERROR;
  102. } // WSHGetSockaddrType
  103. // Fix for bug 262107
  104. INT
  105. WSHGetWildcardSockaddr (
  106. IN PVOID HelperDllSocketContext,
  107. OUT PSOCKADDR Sockaddr,
  108. OUT PINT SockaddrLength
  109. )
  110. /*++
  111. Routine Description:
  112. This routine returns a wildcard socket address. A wildcard address
  113. is one which will bind the socket to an endpoint of the transport's
  114. choosing. For AppleTalk, we just blank out the address with zeros.
  115. Arguments:
  116. HelperDllSocketContext - the context pointer returned from
  117. WSHOpenSocket() for the socket for which we need a wildcard
  118. address.
  119. Sockaddr - points to a buffer which will receive the wildcard socket
  120. address.
  121. SockaddrLength - receives the length of the wioldcard sockaddr.
  122. Return Value:
  123. INT - a winsock error code indicating the status of the operation, or
  124. NO_ERROR if the operation succeeded.
  125. --*/
  126. {
  127. if ( *SockaddrLength < sizeof(SOCKADDR_AT) ) {
  128. return WSAEFAULT;
  129. }
  130. *SockaddrLength = sizeof(SOCKADDR_AT);
  131. //
  132. // Just zero out the address and set the family to AF_APPLETALK--this is
  133. // a wildcard address for AppleTalk.
  134. //
  135. RtlZeroMemory( Sockaddr, sizeof(SOCKADDR_AT) );
  136. Sockaddr->sa_family = AF_APPLETALK;
  137. return NO_ERROR;
  138. } // WSAGetWildcardSockaddr
  139. INT
  140. WSHGetSocketInformation (
  141. IN PVOID HelperDllSocketContext,
  142. IN SOCKET SocketHandle,
  143. IN HANDLE TdiAddressObjectHandle,
  144. IN HANDLE TdiConnectionObjectHandle,
  145. IN INT Level,
  146. IN INT OptionName,
  147. OUT PCHAR OptionValue,
  148. OUT PINT OptionLength
  149. )
  150. /*++
  151. Routine Description:
  152. This routine retrieves information about a socket for those socket
  153. options supported in this helper DLL. The options supported here
  154. are SO_LOOKUPNAME/SO_LOOKUPZONES.
  155. This routine is called by the winsock DLL when a level/option name
  156. combination is passed to getsockopt() that the winsock DLL does not
  157. understand.
  158. Arguments:
  159. HelperDllSocketContext - the context pointer returned from
  160. WSHOpenSocket().
  161. SocketHandle - the handle of the socket for which we're getting
  162. information.
  163. TdiAddressObjectHandle - the TDI address object of the socket, if
  164. any. If the socket is not yet bound to an address, then
  165. it does not have a TDI address object and this parameter
  166. will be NULL.
  167. TdiConnectionObjectHandle - the TDI connection object of the socket,
  168. if any. If the socket is not yet connected, then it does not
  169. have a TDI connection object and this parameter will be NULL.
  170. Level - the level parameter passed to getsockopt().
  171. OptionName - the optname parameter passed to getsockopt().
  172. OptionValue - the optval parameter passed to getsockopt().
  173. OptionLength - the optlen parameter passed to getsockopt().
  174. Return Value:
  175. INT - a winsock error code indicating the status of the operation, or
  176. NO_ERROR if the operation succeeded.
  177. --*/
  178. {
  179. NTSTATUS status;
  180. ULONG tdiActionLength;
  181. IO_STATUS_BLOCK ioStatusBlock;
  182. HANDLE eventHandle;
  183. PTDI_ACTION_HEADER tdiAction;
  184. INT error = NO_ERROR;
  185. UNREFERENCED_PARAMETER( SocketHandle );
  186. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  187. DBGPRINT0(("WSHGetSocketInformation: Entered, OptionName %ld\n", OptionName));
  188. if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT )
  189. {
  190. PWSHATALK_SOCKET_CONTEXT context = HelperDllSocketContext;
  191. //
  192. // The Windows Sockets DLL is requesting context information
  193. // from us. If an output buffer was not supplied, the Windows
  194. // Sockets DLL is just requesting the size of our context
  195. // information.
  196. //
  197. if ( OptionValue != NULL ) {
  198. //
  199. // Make sure that the buffer is sufficient to hold all the
  200. // context information.
  201. //
  202. if ( *OptionLength < sizeof(*context) )
  203. {
  204. *OptionLength = sizeof(*context);
  205. return WSAEFAULT;
  206. }
  207. //
  208. // Copy in the context information.
  209. //
  210. RtlCopyMemory( OptionValue, context, sizeof(*context) );
  211. }
  212. *OptionLength = sizeof(*context);
  213. return NO_ERROR;
  214. }
  215. //
  216. // The only level we support here is SOL_APPLETALK.
  217. //
  218. if ( Level != SOL_APPLETALK )
  219. {
  220. return WSAEINVAL;
  221. }
  222. //
  223. // Fill in the result based on the option name.
  224. //
  225. switch ( OptionName )
  226. {
  227. case SO_LOOKUP_NAME:
  228. if (( TdiAddressObjectHandle != NULL) &&
  229. (*OptionLength > sizeof(WSH_LOOKUP_NAME)))
  230. {
  231. // Due to the 'greater than' check we are guaranteed atleast
  232. // one byte after the parameters.
  233. tdiActionLength = sizeof(NBP_LOOKUP_ACTION) +
  234. *OptionLength -
  235. sizeof(WSH_LOOKUP_NAME);
  236. }
  237. else
  238. {
  239. error = WSAEINVAL;
  240. }
  241. break;
  242. case SO_CONFIRM_NAME:
  243. if (( TdiAddressObjectHandle != NULL) &&
  244. (*OptionLength >= sizeof(WSH_NBP_TUPLE)))
  245. {
  246. tdiActionLength = sizeof(NBP_CONFIRM_ACTION);
  247. }
  248. else
  249. {
  250. error = WSAEINVAL;
  251. }
  252. break;
  253. case SO_LOOKUP_MYZONE :
  254. if (( TdiAddressObjectHandle != NULL) &&
  255. (*OptionLength > 0))
  256. {
  257. // Due to the 'greater than' check we are guaranteed atleast
  258. // one byte after the parameters.
  259. tdiActionLength = sizeof(ZIP_GETMYZONE_ACTION) +
  260. *OptionLength;
  261. }
  262. else
  263. {
  264. error = WSAEINVAL;
  265. }
  266. break;
  267. case SO_LOOKUP_ZONES :
  268. if (( TdiAddressObjectHandle != NULL) &&
  269. (*OptionLength > sizeof(WSH_LOOKUP_ZONES)))
  270. {
  271. // Due to the 'greater than' check we are guaranteed atleast
  272. // one byte after the parameters.
  273. tdiActionLength = sizeof(ZIP_GETZONELIST_ACTION) +
  274. *OptionLength -
  275. sizeof(WSH_LOOKUP_ZONES);
  276. }
  277. else
  278. {
  279. error = WSAEINVAL;
  280. }
  281. break;
  282. case SO_LOOKUP_ZONES_ON_ADAPTER:
  283. if ((TdiAddressObjectHandle != NULL) &&
  284. (*OptionLength > sizeof(WSH_LOOKUP_ZONES)))
  285. {
  286. tdiActionLength = sizeof(ZIP_GETZONELIST_ACTION) +
  287. *OptionLength -
  288. sizeof(WSH_LOOKUP_ZONES);
  289. }
  290. else
  291. {
  292. error = WSAEINVAL;
  293. }
  294. break;
  295. case SO_LOOKUP_NETDEF_ON_ADAPTER:
  296. if ((TdiAddressObjectHandle != NULL) &&
  297. (*OptionLength > sizeof(WSH_LOOKUP_NETDEF_ON_ADAPTER)))
  298. {
  299. tdiActionLength = sizeof(ZIP_GETPORTDEF_ACTION) +
  300. *OptionLength -
  301. sizeof(WSH_LOOKUP_NETDEF_ON_ADAPTER);
  302. }
  303. else
  304. {
  305. error = WSAEINVAL;
  306. }
  307. break;
  308. case SO_PAP_GET_SERVER_STATUS:
  309. if (( TdiAddressObjectHandle != NULL ) &&
  310. ( *OptionLength >= sizeof(WSH_PAP_GET_SERVER_STATUS)))
  311. {
  312. tdiActionLength = sizeof(PAP_GETSTATUSSRV_ACTION) +
  313. *OptionLength -
  314. sizeof(SOCKADDR_AT);
  315. }
  316. else
  317. {
  318. error = WSAEINVAL;
  319. }
  320. break;
  321. default:
  322. error = WSAENOPROTOOPT;
  323. break;
  324. }
  325. if (error != NO_ERROR)
  326. {
  327. return(error);
  328. }
  329. tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
  330. if ( tdiAction == NULL )
  331. {
  332. return WSAENOBUFS;
  333. }
  334. tdiAction->TransportId = MATK;
  335. status = NtCreateEvent(
  336. &eventHandle,
  337. EVENT_ALL_ACCESS,
  338. NULL,
  339. SynchronizationEvent,
  340. FALSE);
  341. if ( !NT_SUCCESS(status) )
  342. {
  343. RtlFreeHeap( RtlProcessHeap( ), 0, tdiAction );
  344. return WSAENOBUFS;
  345. }
  346. switch ( OptionName )
  347. {
  348. case SO_LOOKUP_NAME:
  349. {
  350. PNBP_LOOKUP_ACTION nbpAction;
  351. nbpAction = (PNBP_LOOKUP_ACTION)tdiAction;
  352. nbpAction->ActionHeader.ActionCode = COMMON_ACTION_NBPLOOKUP;
  353. //
  354. // Copy the nbp name for lookup in the proper place
  355. //
  356. RtlCopyMemory(
  357. (PCHAR)&nbpAction->Params.LookupTuple,
  358. (PCHAR)(&((PWSH_LOOKUP_NAME)OptionValue)->LookupTuple),
  359. sizeof(((PWSH_LOOKUP_NAME)OptionValue)->LookupTuple));
  360. if (!WshNbpNameToMacCodePage(
  361. &((PWSH_LOOKUP_NAME)OptionValue)->LookupTuple.NbpName))
  362. {
  363. error = WSAEINVAL;
  364. break;
  365. }
  366. }
  367. break;
  368. case SO_CONFIRM_NAME:
  369. {
  370. PNBP_CONFIRM_ACTION nbpAction;
  371. nbpAction = (PNBP_CONFIRM_ACTION)tdiAction;
  372. nbpAction->ActionHeader.ActionCode = COMMON_ACTION_NBPCONFIRM;
  373. //
  374. // Copy the nbp name for confirm in the proper place
  375. //
  376. RtlCopyMemory(
  377. (PCHAR)&nbpAction->Params.ConfirmTuple,
  378. (PCHAR)OptionValue,
  379. sizeof(WSH_NBP_TUPLE));
  380. if (!WshNbpNameToMacCodePage(
  381. &((PWSH_NBP_TUPLE)OptionValue)->NbpName))
  382. {
  383. error = WSAEINVAL;
  384. break;
  385. }
  386. }
  387. break;
  388. case SO_LOOKUP_ZONES :
  389. {
  390. PZIP_GETZONELIST_ACTION zipAction;
  391. zipAction = (PZIP_GETZONELIST_ACTION)tdiAction;
  392. zipAction->ActionHeader.ActionCode = COMMON_ACTION_ZIPGETZONELIST;
  393. //
  394. // No parameters need to be passed
  395. //
  396. }
  397. break;
  398. case SO_LOOKUP_NETDEF_ON_ADAPTER:
  399. {
  400. PZIP_GETPORTDEF_ACTION zipAction;
  401. zipAction = (PZIP_GETPORTDEF_ACTION)tdiAction;
  402. zipAction->ActionHeader.ActionCode = COMMON_ACTION_ZIPGETADAPTERDEFAULTS;
  403. // If the string is not null-terminated, the calling process will *DIE*.
  404. wcsncpy(
  405. (PWCHAR)((PUCHAR)zipAction + sizeof(ZIP_GETPORTDEF_ACTION)),
  406. (PWCHAR)((PUCHAR)OptionValue + sizeof(WSH_LOOKUP_NETDEF_ON_ADAPTER)),
  407. ((tdiActionLength - sizeof(ZIP_GETPORTDEF_ACTION))/sizeof(WCHAR)));
  408. }
  409. break;
  410. case SO_LOOKUP_ZONES_ON_ADAPTER:
  411. {
  412. PZIP_GETZONELIST_ACTION zipAction;
  413. zipAction = (PZIP_GETZONELIST_ACTION)tdiAction;
  414. zipAction->ActionHeader.ActionCode = COMMON_ACTION_ZIPGETLZONESONADAPTER;
  415. // If the string is not null-terminated, the calling process will *DIE*.
  416. wcsncpy(
  417. (PWCHAR)((PUCHAR)zipAction + sizeof(ZIP_GETZONELIST_ACTION)),
  418. (PWCHAR)((PUCHAR)OptionValue + sizeof(WSH_LOOKUP_ZONES)),
  419. ((tdiActionLength - sizeof(ZIP_GETZONELIST_ACTION))/sizeof(WCHAR)));
  420. }
  421. break;
  422. case SO_LOOKUP_MYZONE :
  423. {
  424. PZIP_GETMYZONE_ACTION zipAction;
  425. zipAction = (PZIP_GETMYZONE_ACTION)tdiAction;
  426. zipAction->ActionHeader.ActionCode = COMMON_ACTION_ZIPGETMYZONE;
  427. }
  428. break;
  429. case SO_PAP_GET_SERVER_STATUS:
  430. {
  431. PPAP_GETSTATUSSRV_ACTION papAction;
  432. papAction = (PPAP_GETSTATUSSRV_ACTION)tdiAction;
  433. papAction->ActionHeader.ActionCode = ACTION_PAPGETSTATUSSRV;
  434. // Set the server address.
  435. SOCK_TO_TDI_ATALKADDR(
  436. &papAction->Params.ServerAddr,
  437. &((PWSH_PAP_GET_SERVER_STATUS)OptionValue)->ServerAddr);
  438. }
  439. break;
  440. default:
  441. //
  442. // Should have returned in the first switch statement
  443. //
  444. error = WSAENOPROTOOPT;
  445. break;
  446. }
  447. if (error != NO_ERROR)
  448. {
  449. RtlFreeHeap( RtlProcessHeap( ), 0, tdiAction );
  450. NtClose( eventHandle );
  451. return (error);
  452. }
  453. status = NtDeviceIoControlFile(
  454. TdiAddressObjectHandle,
  455. eventHandle,
  456. NULL,
  457. NULL,
  458. &ioStatusBlock,
  459. IOCTL_TDI_ACTION,
  460. NULL, // Input buffer
  461. 0, // Length of input buffer
  462. tdiAction,
  463. tdiActionLength);
  464. if ( status == STATUS_PENDING )
  465. {
  466. status = NtWaitForSingleObject( eventHandle, FALSE, NULL );
  467. ASSERT( NT_SUCCESS(status) );
  468. status = ioStatusBlock.Status;
  469. }
  470. error = WSHNtStatusToWinsockErr(status);
  471. // Only copy data over if the error code is no-error or buffer too small.
  472. // For a confirm, a new socket could be returned for the lookup.
  473. if ((error == NO_ERROR) || (error == WSAENOBUFS) ||
  474. ((error == WSAEADDRNOTAVAIL) && (OptionName == SO_CONFIRM_NAME)))
  475. {
  476. switch ( OptionName )
  477. {
  478. case SO_LOOKUP_NAME:
  479. //
  480. // We are guaranteed by checks in the beginning atleast one byte
  481. // following the buffer
  482. //
  483. {
  484. PNBP_LOOKUP_ACTION nbpAction;
  485. PWSH_NBP_TUPLE pNbpTuple;
  486. PUCHAR tdiBuffer = (PCHAR)tdiAction+sizeof(NBP_LOOKUP_ACTION);
  487. PUCHAR userBuffer = (PCHAR)OptionValue+sizeof(WSH_LOOKUP_NAME);
  488. INT copySize = *OptionLength - sizeof(WSH_LOOKUP_NAME);
  489. nbpAction = (PNBP_LOOKUP_ACTION)tdiAction;
  490. ((PWSH_LOOKUP_NAME)OptionValue)->NoTuples =
  491. nbpAction->Params.NoTuplesRead;
  492. RtlCopyMemory(
  493. userBuffer,
  494. tdiBuffer,
  495. copySize);
  496. //
  497. // Convert all tuples from MAC to OEM code page
  498. //
  499. pNbpTuple = (PWSH_NBP_TUPLE)userBuffer;
  500. while (nbpAction->Params.NoTuplesRead-- > 0)
  501. {
  502. if (!WshNbpNameToOemCodePage(
  503. &pNbpTuple->NbpName))
  504. {
  505. DBGPRINT(("WSHGetSocketInformation: ToOem failed %d\n!",
  506. (USHORT)((PWSH_LOOKUP_ZONES)OptionValue)->NoZones));
  507. error = WSAEINVAL;
  508. break;
  509. }
  510. pNbpTuple++;
  511. }
  512. }
  513. break;
  514. case SO_CONFIRM_NAME:
  515. {
  516. PNBP_CONFIRM_ACTION nbpAction;
  517. nbpAction = (PNBP_CONFIRM_ACTION)tdiAction;
  518. //
  519. // Copy the nbp name for confirm back into the option buffer
  520. //
  521. RtlCopyMemory(
  522. (PCHAR)OptionValue,
  523. (PCHAR)&nbpAction->Params.ConfirmTuple,
  524. sizeof(WSH_NBP_TUPLE));
  525. //
  526. // Convert NbpName from MAC to OEM code page
  527. //
  528. if (!WshNbpNameToOemCodePage(
  529. &((PWSH_NBP_TUPLE)OptionValue)->NbpName))
  530. {
  531. DBGPRINT(("WSHGetSocketInformation: ToOem failed %d\n!",
  532. (USHORT)((PWSH_LOOKUP_ZONES)OptionValue)->NoZones));
  533. error = WSAEINVAL;
  534. break;
  535. }
  536. }
  537. break;
  538. case SO_LOOKUP_ZONES:
  539. case SO_LOOKUP_ZONES_ON_ADAPTER:
  540. //
  541. // We are guaranteed by checks in the beginning atleast one byte
  542. // following the buffer
  543. //
  544. {
  545. PZIP_GETZONELIST_ACTION zipAction;
  546. PUCHAR tdiBuffer = (PCHAR)tdiAction + sizeof(ZIP_GETZONELIST_ACTION);
  547. PUCHAR userBuffer = (PCHAR)OptionValue + sizeof(WSH_LOOKUP_ZONES);
  548. INT copySize = *OptionLength - sizeof(WSH_LOOKUP_ZONES);
  549. zipAction = (PZIP_GETZONELIST_ACTION)tdiAction;
  550. ((PWSH_LOOKUP_ZONES)OptionValue)->NoZones=
  551. zipAction->Params.ZonesAvailable;
  552. RtlCopyMemory(
  553. userBuffer,
  554. tdiBuffer,
  555. copySize);
  556. if (!WshZoneListToOemCodePage(
  557. userBuffer,
  558. (USHORT)((PWSH_LOOKUP_ZONES)OptionValue)->NoZones))
  559. {
  560. DBGPRINT(("WSHGetSocketInformation: ToOem failed %d\n!",
  561. (USHORT)((PWSH_LOOKUP_ZONES)OptionValue)->NoZones));
  562. error = WSAEINVAL;
  563. break;
  564. }
  565. }
  566. break;
  567. case SO_LOOKUP_NETDEF_ON_ADAPTER:
  568. {
  569. PZIP_GETPORTDEF_ACTION zipAction;
  570. PUCHAR tdiBuffer = (PCHAR)tdiAction + sizeof(ZIP_GETPORTDEF_ACTION);
  571. PUCHAR userBuffer = (PCHAR)OptionValue +
  572. sizeof(WSH_LOOKUP_NETDEF_ON_ADAPTER);
  573. INT copySize = *OptionLength - sizeof(WSH_LOOKUP_NETDEF_ON_ADAPTER);
  574. zipAction = (PZIP_GETPORTDEF_ACTION)tdiAction;
  575. ((PWSH_LOOKUP_NETDEF_ON_ADAPTER)OptionValue)->NetworkRangeLowerEnd =
  576. zipAction->Params.NwRangeLowEnd;
  577. ((PWSH_LOOKUP_NETDEF_ON_ADAPTER)OptionValue)->NetworkRangeUpperEnd =
  578. zipAction->Params.NwRangeHighEnd;
  579. // Copy the rest of the buffer
  580. RtlCopyMemory(
  581. userBuffer,
  582. tdiBuffer,
  583. copySize);
  584. if (!WshZoneListToOemCodePage(
  585. userBuffer,
  586. 1))
  587. {
  588. DBGPRINT(("WSHGetSocketInformation: ToOem failed %d\n!",
  589. (USHORT)((PWSH_LOOKUP_ZONES)OptionValue)->NoZones));
  590. error = WSAEINVAL;
  591. break;
  592. }
  593. }
  594. break;
  595. case SO_LOOKUP_MYZONE :
  596. {
  597. PUCHAR tdiBuffer = (PCHAR)tdiAction+sizeof(ZIP_GETMYZONE_ACTION);
  598. PUCHAR userBuffer = (PCHAR)OptionValue;
  599. INT copySize = *OptionLength;
  600. RtlCopyMemory(
  601. userBuffer,
  602. tdiBuffer,
  603. copySize);
  604. if (!WshZoneListToOemCodePage(
  605. userBuffer,
  606. 1))
  607. {
  608. DBGPRINT(("WSHGetSocketInformation: ToOem failed %d\n!",
  609. (USHORT)((PWSH_LOOKUP_ZONES)OptionValue)->NoZones));
  610. error = WSAEINVAL;
  611. break;
  612. }
  613. }
  614. break;
  615. case SO_PAP_GET_SERVER_STATUS:
  616. {
  617. PUCHAR tdiBuffer = (PCHAR)tdiAction+sizeof(PAP_GETSTATUSSRV_ACTION);
  618. PUCHAR userBuffer = (PCHAR)OptionValue+sizeof(SOCKADDR_AT);
  619. INT copySize = *OptionLength - sizeof(SOCKADDR_AT);
  620. RtlCopyMemory(
  621. userBuffer,
  622. tdiBuffer,
  623. copySize);
  624. }
  625. break;
  626. default:
  627. error = WSAENOPROTOOPT;
  628. break;
  629. }
  630. }
  631. RtlFreeHeap( RtlProcessHeap( ), 0, tdiAction );
  632. NtClose( eventHandle );
  633. return error;
  634. } // WSHGetSocketInformation
  635. INT
  636. WSHSetSocketInformation (
  637. IN PVOID HelperDllSocketContext,
  638. IN SOCKET SocketHandle,
  639. IN HANDLE TdiAddressObjectHandle,
  640. IN HANDLE TdiConnectionObjectHandle,
  641. IN INT Level,
  642. IN INT OptionName,
  643. IN PCHAR OptionValue,
  644. IN INT OptionLength
  645. )
  646. /*++
  647. Routine Description:
  648. This routine sets information about a socket for those socket
  649. options supported in this helper DLL. The options supported here
  650. are SO_REGISTERNAME/SO_DEREGISTERNAME. This routine is called by the
  651. winsock DLL when a level/option name combination is passed to
  652. setsockopt() that the winsock DLL does not understand.
  653. Arguments:
  654. HelperDllSocketContext - the context pointer returned from
  655. WSHOpenSocket().
  656. SocketHandle - the handle of the socket for which we're getting
  657. information.
  658. TdiAddressObjectHandle - the TDI address object of the socket, if
  659. any. If the socket is not yet bound to an address, then
  660. it does not have a TDI address object and this parameter
  661. will be NULL.
  662. TdiConnectionObjectHandle - the TDI connection object of the socket,
  663. if any. If the socket is not yet connected, then it does not
  664. have a TDI connection object and this parameter will be NULL.
  665. Level - the level parameter passed to setsockopt().
  666. OptionName - the optname parameter passed to setsockopt().
  667. OptionValue - the optval parameter passed to setsockopt().
  668. OptionLength - the optlen parameter passed to setsockopt().
  669. Return Value:
  670. INT - a winsock error code indicating the status of the operation, or
  671. NO_ERROR if the operation succeeded.
  672. --*/
  673. {
  674. NTSTATUS status;
  675. ULONG tdiActionLength;
  676. HANDLE objectHandle;
  677. PIO_STATUS_BLOCK pIoStatusBlock;
  678. PTDI_ACTION_HEADER tdiAction;
  679. PWSHATALK_SOCKET_CONTEXT context = HelperDllSocketContext;
  680. HANDLE eventHandle = NULL;
  681. PVOID completionApc = NULL;
  682. PVOID apcContext = NULL;
  683. BOOLEAN freeTdiAction = FALSE;
  684. INT error = NO_ERROR;
  685. BOOLEAN waitForCompletion =(OptionName != SO_PAP_PRIME_READ);
  686. UNREFERENCED_PARAMETER( SocketHandle );
  687. DBGPRINT0(("WSHSetSocketInformation: Entered, OptionName %ld\n", OptionName));
  688. //
  689. // Check if this is an internal request for context information.
  690. //
  691. if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
  692. //
  693. // The Windows Sockets DLL is requesting that we set context
  694. // information for a new socket. If the new socket was
  695. // accept()'ed, then we have already been notified of the socket
  696. // and HelperDllSocketContext will be valid. If the new socket
  697. // was inherited or duped into this process, then this is our
  698. // first notification of the socket and HelperDllSocketContext
  699. // will be equal to NULL.
  700. //
  701. // Insure that the context information being passed to us is
  702. // sufficiently large.
  703. //
  704. if ( OptionLength < sizeof(*context) ) {
  705. return WSAEINVAL;
  706. }
  707. if ( HelperDllSocketContext == NULL ) {
  708. //
  709. // This is our notification that a socket handle was
  710. // inherited or duped into this process. Allocate a context
  711. // structure for the new socket.
  712. //
  713. context = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*context) );
  714. if ( context == NULL ) {
  715. return WSAENOBUFS;
  716. }
  717. //
  718. // Copy over information into the context block.
  719. //
  720. RtlCopyMemory( context, OptionValue, sizeof(*context) );
  721. //
  722. // Tell the Windows Sockets DLL where our context information is
  723. // stored so that it can return the context pointer in future
  724. // calls.
  725. //
  726. *(PWSHATALK_SOCKET_CONTEXT *)OptionValue = context;
  727. return NO_ERROR;
  728. }
  729. else
  730. {
  731. return NO_ERROR;
  732. }
  733. }
  734. //
  735. // The only level we support here is SOL_APPLETALK.
  736. //
  737. if ( Level != SOL_APPLETALK )
  738. {
  739. DBGPRINT0(("WSHSetSocketInformation: Level incorrect %d\n", Level));
  740. return WSAEINVAL;
  741. }
  742. //
  743. // Fill in the result based on the option name.
  744. // We support SO_REGISTERNAME/SO_DEREGISTERNAME only
  745. //
  746. pIoStatusBlock = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof(IO_STATUS_BLOCK));
  747. if (pIoStatusBlock == NULL)
  748. {
  749. return(WSAENOBUFS);
  750. }
  751. if (waitForCompletion)
  752. {
  753. status = NtCreateEvent(
  754. &eventHandle,
  755. EVENT_ALL_ACCESS,
  756. NULL,
  757. SynchronizationEvent,
  758. FALSE
  759. );
  760. if ( !NT_SUCCESS(status) )
  761. {
  762. RtlFreeHeap( RtlProcessHeap(), 0, pIoStatusBlock);
  763. DBGPRINT(("WSHSetSocketInformation: Create event failed\n"));
  764. return WSAENOBUFS;
  765. }
  766. }
  767. else
  768. {
  769. completionApc = CompleteTdiActionApc;
  770. apcContext = pIoStatusBlock;
  771. }
  772. switch (OptionName)
  773. {
  774. case SO_REGISTER_NAME:
  775. {
  776. PNBP_REGDEREG_ACTION nbpAction;
  777. if (( TdiAddressObjectHandle == NULL) ||
  778. (OptionLength != sizeof(WSH_REGISTER_NAME)))
  779. {
  780. error = WSAEINVAL;
  781. break;
  782. }
  783. // Operation is on the address handle
  784. objectHandle = TdiAddressObjectHandle;
  785. tdiActionLength = sizeof(NBP_REGDEREG_ACTION);
  786. tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
  787. if ( tdiAction == NULL )
  788. {
  789. error = WSAENOBUFS;
  790. break;
  791. }
  792. freeTdiAction = TRUE;
  793. tdiAction->TransportId = MATK;
  794. tdiAction->ActionCode = COMMON_ACTION_NBPREGISTER;
  795. nbpAction = (PNBP_REGDEREG_ACTION)tdiAction;
  796. //
  797. // Copy the nbp name to the proper place
  798. //
  799. RtlCopyMemory(
  800. (PCHAR)&nbpAction->Params.RegisterTuple.NbpName,
  801. OptionValue,
  802. OptionLength);
  803. //
  804. // Convert the tuple to MAC code page
  805. //
  806. if (!WshNbpNameToMacCodePage(
  807. (PWSH_REGISTER_NAME)OptionValue))
  808. {
  809. error = WSAEINVAL;
  810. break;
  811. }
  812. }
  813. break;
  814. case SO_DEREGISTER_NAME:
  815. {
  816. PNBP_REGDEREG_ACTION nbpAction;
  817. if (( TdiAddressObjectHandle == NULL) ||
  818. (OptionLength != sizeof(WSH_DEREGISTER_NAME)))
  819. {
  820. error = WSAEINVAL;
  821. break;
  822. }
  823. // Operation is on the address handle
  824. objectHandle = TdiAddressObjectHandle;
  825. tdiActionLength = sizeof(NBP_REGDEREG_ACTION);
  826. tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
  827. if ( tdiAction == NULL )
  828. {
  829. error = WSAENOBUFS;
  830. break;
  831. }
  832. freeTdiAction = TRUE;
  833. tdiAction->TransportId = MATK;
  834. tdiAction->ActionCode = COMMON_ACTION_NBPREMOVE;
  835. nbpAction = (PNBP_REGDEREG_ACTION)tdiAction;
  836. //
  837. // Copy the nbp name to the proper place
  838. //
  839. RtlCopyMemory(
  840. (PCHAR)&nbpAction->Params.RegisteredTuple.NbpName,
  841. OptionValue,
  842. OptionLength);
  843. //
  844. // Convert the tuple to MAC code page
  845. //
  846. if (!WshNbpNameToMacCodePage(
  847. (PWSH_DEREGISTER_NAME)OptionValue))
  848. {
  849. error = WSAEINVAL;
  850. break;
  851. }
  852. }
  853. break;
  854. case SO_PAP_SET_SERVER_STATUS:
  855. {
  856. PPAP_SETSTATUS_ACTION papAction;
  857. if (( TdiAddressObjectHandle == NULL) ||
  858. (OptionLength < 0))
  859. {
  860. error = WSAEINVAL;
  861. break;
  862. }
  863. // Operation is on the address handle
  864. objectHandle = TdiAddressObjectHandle;
  865. tdiActionLength = (ULONG)OptionLength +
  866. (ULONG)(sizeof(PAP_SETSTATUS_ACTION));
  867. DBGPRINT0(("ActionLen %lx\n", tdiActionLength));
  868. tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
  869. if ( tdiAction == NULL )
  870. {
  871. error = WSAENOBUFS;
  872. break;
  873. }
  874. freeTdiAction = TRUE;
  875. tdiAction->TransportId = MATK;
  876. tdiAction->ActionCode = ACTION_PAPSETSTATUS;
  877. papAction = (PPAP_SETSTATUS_ACTION)tdiAction;
  878. DBGPRINT0(("Setting Status len %lx\n", OptionLength));
  879. //
  880. // Copy the passed status into our buffer
  881. //
  882. if (OptionLength > 0)
  883. {
  884. RtlCopyMemory(
  885. (PCHAR)papAction + sizeof(PAP_SETSTATUS_ACTION),
  886. OptionValue,
  887. OptionLength);
  888. }
  889. }
  890. break;
  891. case SO_PAP_PRIME_READ :
  892. {
  893. tdiAction = (PTDI_ACTION_HEADER)OptionValue;
  894. tdiActionLength = OptionLength;
  895. ASSERT(waitForCompletion == FALSE);
  896. if ((TdiConnectionObjectHandle == NULL) ||
  897. (OptionLength < MIN_PAP_READ_BUF_SIZE))
  898. {
  899. error = WSAEINVAL;
  900. break;
  901. }
  902. // Operation is on the connection handle
  903. objectHandle = TdiConnectionObjectHandle;
  904. // These will get overwritten by the incoming data.
  905. tdiAction->TransportId = MATK;
  906. tdiAction->ActionCode = ACTION_PAPPRIMEREAD;
  907. // This is the caller's buffer! Dont free it! Also, we dont wait
  908. // for this to complete.
  909. freeTdiAction = FALSE;
  910. // We potentially have an APC waiting to be delivered from a
  911. // previous setsockopt(). Give it a chance
  912. NtTestAlert();
  913. }
  914. break;
  915. default:
  916. error = WSAENOPROTOOPT;
  917. break;
  918. }
  919. if (error != NO_ERROR)
  920. {
  921. if (freeTdiAction)
  922. {
  923. RtlFreeHeap( RtlProcessHeap( ), 0, tdiAction );
  924. }
  925. if (waitForCompletion)
  926. {
  927. NtClose(eventHandle);
  928. }
  929. RtlFreeHeap( RtlProcessHeap(), 0, pIoStatusBlock);
  930. return(error);
  931. }
  932. status = NtDeviceIoControlFile(
  933. objectHandle,
  934. eventHandle,
  935. completionApc,
  936. apcContext,
  937. pIoStatusBlock,
  938. IOCTL_TDI_ACTION,
  939. NULL, // Input buffer
  940. 0, // Length of input buffer
  941. tdiAction,
  942. tdiActionLength
  943. );
  944. if ( status == STATUS_PENDING )
  945. {
  946. if (waitForCompletion)
  947. {
  948. status = NtWaitForSingleObject( eventHandle, FALSE, NULL );
  949. ASSERT( NT_SUCCESS(status) );
  950. status = pIoStatusBlock->Status;
  951. }
  952. else
  953. {
  954. status = STATUS_SUCCESS;
  955. }
  956. }
  957. if (freeTdiAction)
  958. {
  959. RtlFreeHeap( RtlProcessHeap( ), 0, tdiAction );
  960. }
  961. // Close the event
  962. if (waitForCompletion)
  963. {
  964. NtClose(eventHandle);
  965. RtlFreeHeap( RtlProcessHeap( ), 0, pIoStatusBlock );
  966. }
  967. return (WSHNtStatusToWinsockErr(status));
  968. } // WSHSetSocketInformation
  969. DWORD
  970. WSHGetWinsockMapping (
  971. OUT PWINSOCK_MAPPING Mapping,
  972. IN DWORD MappingLength
  973. )
  974. /*++
  975. Routine Description:
  976. Returns the list of address family/socket type/protocol triples
  977. supported by this helper DLL.
  978. Arguments:
  979. Mapping - receives a pointer to a WINSOCK_MAPPING structure that
  980. describes the triples supported here.
  981. MappingLength - the length, in bytes, of the passed-in Mapping buffer.
  982. Return Value:
  983. DWORD - the length, in bytes, of a WINSOCK_MAPPING structure for this
  984. helper DLL. If the passed-in buffer is too small, the return
  985. value will indicate the size of a buffer needed to contain
  986. the WINSOCK_MAPPING structure.
  987. --*/
  988. {
  989. DWORD mappingLength;
  990. ULONG offset;
  991. DBGPRINT0(("WSHGetWinsockMapping: Entered\n"));
  992. mappingLength = sizeof(WINSOCK_MAPPING) -
  993. sizeof(MAPPING_TRIPLE) +
  994. sizeof(AdspStreamMappingTriples) +
  995. sizeof(AdspMsgMappingTriples) +
  996. sizeof(PapMsgMappingTriples) +
  997. sizeof(DdpMappingTriples);
  998. //
  999. // If the passed-in buffer is too small, return the length needed
  1000. // now without writing to the buffer. The caller should allocate
  1001. // enough memory and call this routine again.
  1002. //
  1003. if ( mappingLength > MappingLength )
  1004. {
  1005. return mappingLength;
  1006. }
  1007. //
  1008. // Fill in the output mapping buffer with the list of triples
  1009. // supported in this helper DLL.
  1010. //
  1011. Mapping->Rows =
  1012. sizeof(AdspStreamMappingTriples) / sizeof(AdspStreamMappingTriples[0]) +
  1013. sizeof(AdspMsgMappingTriples) / sizeof(AdspMsgMappingTriples[0]) +
  1014. sizeof(PapMsgMappingTriples) / sizeof(PapMsgMappingTriples[0]) +
  1015. sizeof(DdpMappingTriples) / sizeof(DdpMappingTriples[0]);
  1016. Mapping->Columns = sizeof(MAPPING_TRIPLE) / sizeof(DWORD);
  1017. offset = 0;
  1018. RtlCopyMemory(
  1019. Mapping->Mapping,
  1020. AdspStreamMappingTriples,
  1021. sizeof(AdspStreamMappingTriples));
  1022. offset += sizeof(AdspStreamMappingTriples);
  1023. RtlCopyMemory(
  1024. (PCHAR)Mapping->Mapping + offset,
  1025. AdspMsgMappingTriples,
  1026. sizeof(AdspMsgMappingTriples));
  1027. offset += sizeof(AdspMsgMappingTriples);
  1028. RtlCopyMemory(
  1029. (PCHAR)Mapping->Mapping + offset,
  1030. PapMsgMappingTriples,
  1031. sizeof(PapMsgMappingTriples));
  1032. offset += sizeof(PapMsgMappingTriples);
  1033. RtlCopyMemory(
  1034. (PCHAR)Mapping->Mapping + offset,
  1035. DdpMappingTriples,
  1036. sizeof(DdpMappingTriples));
  1037. //
  1038. // Return the number of bytes we wrote.
  1039. //
  1040. DBGPRINT0(("WSHGetWinsockMapping: Mapping Length = %d\n", mappingLength));
  1041. return mappingLength;
  1042. } // WSHGetWinsockMapping
  1043. INT
  1044. WSHOpenSocket (
  1045. IN OUT PINT AddressFamily,
  1046. IN OUT PINT SocketType,
  1047. IN OUT PINT Protocol,
  1048. OUT PUNICODE_STRING TransportDeviceName,
  1049. OUT PVOID * HelperDllSocketContext,
  1050. OUT PDWORD NotificationEvents
  1051. )
  1052. /*++
  1053. Routine Description:
  1054. Does the necessary work for this helper DLL to open a socket and is
  1055. called by the winsock DLL in the socket() routine. This routine
  1056. verifies that the specified triple is valid, determines the NT
  1057. device name of the TDI provider that will support that triple,
  1058. allocates space to hold the socket's context block, and
  1059. canonicalizes the triple.
  1060. Arguments:
  1061. AddressFamily - on input, the address family specified in the
  1062. socket() call. On output, the canonicalized value for the
  1063. address family.
  1064. SocketType - on input, the socket type specified in the socket()
  1065. call. On output, the canonicalized value for the socket type.
  1066. Protocol - on input, the protocol specified in the socket() call.
  1067. On output, the canonicalized value for the protocol.
  1068. TransportDeviceName - receives the name of the TDI provider that
  1069. will support the specified triple.
  1070. HelperDllSocketContext - receives a context pointer that the winsock
  1071. DLL will return to this helper DLL on future calls involving
  1072. this socket.
  1073. NotificationEvents - receives a bitmask of those state transitions
  1074. this helper DLL should be notified on.
  1075. Return Value:
  1076. INT - a winsock error code indicating the status of the operation, or
  1077. NO_ERROR if the operation succeeded.
  1078. --*/
  1079. {
  1080. PWSHATALK_SOCKET_CONTEXT context;
  1081. DBGPRINT0(("WSHOpenSocket: Entered\n"));
  1082. //
  1083. // Determine whether this is to be a TCP or UDP socket.
  1084. //
  1085. if ( IsTripleInList(
  1086. AdspStreamMappingTriples,
  1087. sizeof(AdspStreamMappingTriples) / sizeof(AdspStreamMappingTriples[0]),
  1088. *AddressFamily,
  1089. *SocketType,
  1090. *Protocol ) )
  1091. {
  1092. //
  1093. // Indicate the name of the TDI device that will service
  1094. // SOCK_STREAM sockets in the internet address family.
  1095. //
  1096. RtlInitUnicodeString( TransportDeviceName, WSH_ATALK_ADSPRDM );
  1097. }
  1098. else if ( IsTripleInList(
  1099. AdspMsgMappingTriples,
  1100. sizeof(AdspMsgMappingTriples) / sizeof(AdspMsgMappingTriples[0]),
  1101. *AddressFamily,
  1102. *SocketType,
  1103. *Protocol ) )
  1104. {
  1105. //
  1106. // Indicate the name of the TDI device that will service
  1107. // SOCK_RDM sockets in the internet address family.
  1108. //
  1109. RtlInitUnicodeString( TransportDeviceName, WSH_ATALK_ADSPRDM );
  1110. }
  1111. else if ( IsTripleInList(
  1112. PapMsgMappingTriples,
  1113. sizeof(PapMsgMappingTriples) / sizeof(PapMsgMappingTriples[0]),
  1114. *AddressFamily,
  1115. *SocketType,
  1116. *Protocol ) )
  1117. {
  1118. //
  1119. // Indicate the name of the TDI device that will service
  1120. // SOCK_RDM sockets in the appletalk address family.
  1121. //
  1122. RtlInitUnicodeString( TransportDeviceName, WSH_ATALK_PAPRDM );
  1123. }
  1124. else
  1125. {
  1126. BOOLEAN tripleFound = FALSE;
  1127. //
  1128. // Check the DDP triples
  1129. //
  1130. if ( IsTripleInList(
  1131. DdpMappingTriples,
  1132. sizeof(DdpMappingTriples) / sizeof(DdpMappingTriples[0]),
  1133. *AddressFamily,
  1134. *SocketType,
  1135. *Protocol ) )
  1136. {
  1137. tripleFound = TRUE;
  1138. //
  1139. // Indicate the name of the TDI device that will service
  1140. // SOCK_DGRAM sockets in the appletalk address family.
  1141. //
  1142. RtlInitUnicodeString(
  1143. TransportDeviceName,
  1144. WSH_ATALK_DGRAMDDP[(*Protocol) - ATPROTO_BASE - 1] );
  1145. DBGPRINT0(("WSHOpenSocket: Protocol number %d index %d\n",
  1146. (*Protocol) , (*Protocol) - ATPROTO_BASE - 1));
  1147. }
  1148. //
  1149. // This should never happen if the registry information about this
  1150. // helper DLL is correct. If somehow this did happen, just return
  1151. // an error.
  1152. //
  1153. if (!tripleFound)
  1154. {
  1155. return WSAEINVAL;
  1156. }
  1157. }
  1158. //
  1159. // Allocate context for this socket. The Windows Sockets DLL will
  1160. // return this value to us when it asks us to get/set socket options.
  1161. //
  1162. context = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*context) );
  1163. if ( context == NULL )
  1164. {
  1165. return WSAENOBUFS;
  1166. }
  1167. //
  1168. // Initialize the context for the socket.
  1169. //
  1170. context->AddressFamily = *AddressFamily;
  1171. context->SocketType = *SocketType;
  1172. context->Protocol = *Protocol;
  1173. //
  1174. // Tell the Windows Sockets DLL which state transitions we're
  1175. // interested in being notified of.
  1176. //
  1177. *NotificationEvents = WSH_NOTIFY_CONNECT | WSH_NOTIFY_CLOSE;
  1178. //
  1179. // Everything worked, return success.
  1180. //
  1181. *HelperDllSocketContext = context;
  1182. return NO_ERROR;
  1183. } // WSHOpenSocket
  1184. INT
  1185. WSHNotify (
  1186. IN PVOID HelperDllSocketContext,
  1187. IN SOCKET SocketHandle,
  1188. IN HANDLE TdiAddressObjectHandle,
  1189. IN HANDLE TdiConnectionObjectHandle,
  1190. IN DWORD NotifyEvent
  1191. )
  1192. /*++
  1193. Routine Description:
  1194. This routine is called by the winsock DLL after a state transition
  1195. of the socket. Only state transitions returned in the
  1196. NotificationEvents parameter of WSHOpenSocket() are notified here.
  1197. This routine allows a winsock helper DLL to track the state of
  1198. socket and perform necessary actions corresponding to state
  1199. transitions.
  1200. Arguments:
  1201. HelperDllSocketContext - the context pointer given to the winsock
  1202. DLL by WSHOpenSocket().
  1203. SocketHandle - the handle for the socket.
  1204. TdiAddressObjectHandle - the TDI address object of the socket, if
  1205. any. If the socket is not yet bound to an address, then
  1206. it does not have a TDI address object and this parameter
  1207. will be NULL.
  1208. TdiConnectionObjectHandle - the TDI connection object of the socket,
  1209. if any. If the socket is not yet connected, then it does not
  1210. have a TDI connection object and this parameter will be NULL.
  1211. NotifyEvent - indicates the state transition for which we're being
  1212. called.
  1213. Return Value:
  1214. INT - a winsock error code indicating the status of the operation, or
  1215. NO_ERROR if the operation succeeded.
  1216. --*/
  1217. {
  1218. PWSHATALK_SOCKET_CONTEXT context = HelperDllSocketContext;
  1219. //
  1220. // We should only be called after a connect() completes or when the
  1221. // socket is being closed.
  1222. //
  1223. if ( NotifyEvent == WSH_NOTIFY_CONNECT )
  1224. {
  1225. //
  1226. // Just for debugging right now
  1227. //
  1228. DBGPRINT0(("WSHNotify: Connect completed, notify called!\n"));
  1229. }
  1230. else if ( NotifyEvent == WSH_NOTIFY_CLOSE )
  1231. {
  1232. //
  1233. // Just free the socket context.
  1234. //
  1235. DBGPRINT0(("WSHNotify: Close notify called!\n"));
  1236. RtlFreeHeap( RtlProcessHeap( ), 0, HelperDllSocketContext );
  1237. }
  1238. else
  1239. {
  1240. return WSAEINVAL;
  1241. }
  1242. return NO_ERROR;
  1243. } // WSHNotify
  1244. INT
  1245. WSHNtStatusToWinsockErr(
  1246. IN NTSTATUS Status
  1247. )
  1248. /*++
  1249. Routine Description:
  1250. Arguments:
  1251. Return Value:
  1252. --*/
  1253. {
  1254. INT error;
  1255. switch (Status)
  1256. {
  1257. case STATUS_SUCCESS: error = NO_ERROR;
  1258. break;
  1259. case STATUS_BUFFER_OVERFLOW:
  1260. case STATUS_BUFFER_TOO_SMALL: error = WSAENOBUFS;
  1261. break;
  1262. case STATUS_INVALID_ADDRESS: error = WSAEADDRNOTAVAIL;
  1263. break;
  1264. case STATUS_SHARING_VIOLATION: error = WSAEADDRINUSE;
  1265. break;
  1266. default: error = WSAEINVAL;
  1267. break;
  1268. }
  1269. DBGPRINT0(("WSHNtStatusToWinsockErr: Converting %lx to %lx\n", Status, error));
  1270. return(error);
  1271. }
  1272. BOOLEAN
  1273. IsTripleInList (
  1274. IN PMAPPING_TRIPLE List,
  1275. IN ULONG ListLength,
  1276. IN INT AddressFamily,
  1277. IN INT SocketType,
  1278. IN INT Protocol
  1279. )
  1280. /*++
  1281. Routine Description:
  1282. Determines whether the specified triple has an exact match in the
  1283. list of triples.
  1284. Arguments:
  1285. List - a list of triples (address family/socket type/protocol) to
  1286. search.
  1287. ListLength - the number of triples in the list.
  1288. AddressFamily - the address family to look for in the list.
  1289. SocketType - the socket type to look for in the list.
  1290. Protocol - the protocol to look for in the list.
  1291. Return Value:
  1292. BOOLEAN - TRUE if the triple was found in the list, false if not.
  1293. --*/
  1294. {
  1295. ULONG i;
  1296. //
  1297. // Walk through the list searching for an exact match.
  1298. //
  1299. for ( i = 0; i < ListLength; i++ )
  1300. {
  1301. //
  1302. // If all three elements of the triple match, return indicating
  1303. // that the triple did exist in the list.
  1304. //
  1305. if ( AddressFamily == List[i].AddressFamily &&
  1306. SocketType == List[i].SocketType &&
  1307. Protocol == List[i].Protocol )
  1308. {
  1309. return TRUE;
  1310. }
  1311. }
  1312. //
  1313. // The triple was not found in the list.
  1314. //
  1315. return FALSE;
  1316. } // IsTripleInList
  1317. VOID
  1318. CompleteTdiActionApc (
  1319. IN PVOID ApcContext,
  1320. IN PIO_STATUS_BLOCK IoStatusBlock
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. Arguments:
  1325. Return Value:
  1326. --*/
  1327. {
  1328. //
  1329. // Just free the heap we allovcated to hold the IO status block and
  1330. // the TDI action buffer. There is nothing we can do if the call
  1331. // failed.
  1332. //
  1333. RtlFreeHeap( RtlProcessHeap( ), 0, ApcContext );
  1334. } // CompleteTdiActionApc
  1335. BOOLEAN
  1336. WshNbpNameToMacCodePage(
  1337. IN OUT PWSH_NBP_NAME pNbpName
  1338. )
  1339. /*++
  1340. Routine Description:
  1341. Arguments:
  1342. Return Value:
  1343. --*/
  1344. {
  1345. USHORT destLen;
  1346. BOOLEAN retVal = FALSE;
  1347. do
  1348. {
  1349. destLen = MAX_ENTITY;
  1350. if (!WshConvertStringOemToMac(
  1351. pNbpName->ObjectName,
  1352. pNbpName->ObjectNameLen,
  1353. pNbpName->ObjectName,
  1354. &destLen))
  1355. {
  1356. break;
  1357. }
  1358. pNbpName->ObjectNameLen = (CHAR)destLen;
  1359. destLen = MAX_ENTITY;
  1360. if (!WshConvertStringOemToMac(
  1361. pNbpName->TypeName,
  1362. pNbpName->TypeNameLen,
  1363. pNbpName->TypeName,
  1364. &destLen))
  1365. {
  1366. break;
  1367. }
  1368. pNbpName->TypeNameLen = (CHAR)destLen;
  1369. destLen = MAX_ENTITY;
  1370. if (!WshConvertStringOemToMac(
  1371. pNbpName->ZoneName,
  1372. pNbpName->ZoneNameLen,
  1373. pNbpName->ZoneName,
  1374. &destLen))
  1375. {
  1376. break;
  1377. }
  1378. pNbpName->ZoneNameLen = (CHAR)destLen;
  1379. retVal = TRUE;
  1380. } while (FALSE);
  1381. return(retVal);
  1382. }
  1383. BOOLEAN
  1384. WshNbpNameToOemCodePage(
  1385. IN OUT PWSH_NBP_NAME pNbpName
  1386. )
  1387. /*++
  1388. Routine Description:
  1389. Arguments:
  1390. Return Value:
  1391. --*/
  1392. {
  1393. USHORT destLen;
  1394. BOOLEAN retVal = FALSE;
  1395. do
  1396. {
  1397. destLen = MAX_ENTITY;
  1398. if (!WshConvertStringMacToOem(
  1399. pNbpName->ObjectName,
  1400. pNbpName->ObjectNameLen,
  1401. pNbpName->ObjectName,
  1402. &destLen))
  1403. {
  1404. break;
  1405. }
  1406. pNbpName->ObjectNameLen = (CHAR)destLen;
  1407. destLen = MAX_ENTITY;
  1408. if (!WshConvertStringMacToOem(
  1409. pNbpName->TypeName,
  1410. pNbpName->TypeNameLen,
  1411. pNbpName->TypeName,
  1412. &destLen))
  1413. {
  1414. break;
  1415. }
  1416. pNbpName->TypeNameLen = (CHAR)destLen;
  1417. destLen = MAX_ENTITY;
  1418. if (!WshConvertStringMacToOem(
  1419. pNbpName->ZoneName,
  1420. pNbpName->ZoneNameLen,
  1421. pNbpName->ZoneName,
  1422. &destLen))
  1423. {
  1424. break;
  1425. }
  1426. pNbpName->ZoneNameLen = (CHAR)destLen;
  1427. retVal = TRUE;
  1428. } while (FALSE);
  1429. return(retVal);
  1430. }
  1431. BOOLEAN
  1432. WshZoneListToOemCodePage(
  1433. IN OUT PUCHAR pZoneList,
  1434. IN USHORT NumZones
  1435. )
  1436. /*++
  1437. Routine Description:
  1438. Arguments:
  1439. Return Value:
  1440. --*/
  1441. {
  1442. USHORT zoneLen;
  1443. BOOLEAN retVal = TRUE;
  1444. PUCHAR pCurZone = pZoneList, pNextZone = NULL, pCopyZone = pZoneList;
  1445. while (NumZones-- > 0)
  1446. {
  1447. zoneLen = strlen(pCurZone) + 1;
  1448. pNextZone = pCurZone + zoneLen;
  1449. // Modify current zone. This could decrease its length
  1450. if (!WshConvertStringMacToOem(
  1451. pCurZone,
  1452. zoneLen,
  1453. pCopyZone,
  1454. &zoneLen))
  1455. {
  1456. DBGPRINT(("WshZoneListToOemCodePage: FAILED %s-%d\n",
  1457. pCurZone, zoneLen));
  1458. retVal = FALSE;
  1459. break;
  1460. }
  1461. pCopyZone += zoneLen;
  1462. pCurZone = pNextZone;
  1463. }
  1464. return(retVal);
  1465. }
  1466. BOOLEAN
  1467. WshConvertStringOemToMac(
  1468. IN PUCHAR pSrcOemString,
  1469. IN USHORT SrcStringLen,
  1470. OUT PUCHAR pDestMacString,
  1471. IN PUSHORT pDestStringLen
  1472. )
  1473. /*++
  1474. Routine Description:
  1475. Arguments:
  1476. Return Value:
  1477. --*/
  1478. {
  1479. WCHAR wcharBuf[MAX_ENTITY + 1];
  1480. INT wcharLen, destLen;
  1481. BOOLEAN retCode = TRUE;
  1482. do
  1483. {
  1484. if ((SrcStringLen > (MAX_ENTITY+1)) ||
  1485. (*pDestStringLen < SrcStringLen))
  1486. {
  1487. DBGPRINT(("WshConvertStringOemToMac: Invalid len %d.%d\n",
  1488. SrcStringLen, *pDestStringLen));
  1489. retCode = FALSE;
  1490. break;
  1491. }
  1492. // Convert the src string using the OEM codepage.
  1493. if ((wcharLen = MultiByteToWideChar(
  1494. CP_ACP,
  1495. MB_PRECOMPOSED,
  1496. pSrcOemString,
  1497. SrcStringLen,
  1498. wcharBuf,
  1499. MAX_ENTITY + 1)) == FALSE)
  1500. {
  1501. DBGPRINT(("WshConvertStringOemToMac: FAILED mbtowcs %s-%d\n",
  1502. pSrcOemString, SrcStringLen));
  1503. retCode = FALSE;
  1504. break;
  1505. }
  1506. DBGPRINT0(("WshConvertStringOemToMac: Converting mbtowcs %s-%d\n",
  1507. pSrcOemString, SrcStringLen));
  1508. // Convert the wide char string to mac ansi string.
  1509. if ((destLen = WideCharToMultiByte(
  1510. WshMacCodePage,
  1511. 0,
  1512. wcharBuf,
  1513. wcharLen,
  1514. pDestMacString,
  1515. *pDestStringLen,
  1516. NULL,
  1517. NULL)) == FALSE)
  1518. {
  1519. DBGPRINT(("WshConvertStringOemToMac: FAILED wctomb %s-%d\n",
  1520. pDestMacString, *pDestStringLen));
  1521. retCode = FALSE;
  1522. break;
  1523. }
  1524. *pDestStringLen = (USHORT)destLen;
  1525. DBGPRINT0(("WshConvertStringOemToMac: Converted mbtowcs %s-%d\n",
  1526. pDestMacString, *pDestStringLen));
  1527. } while (FALSE);
  1528. return(retCode);
  1529. }
  1530. BOOLEAN
  1531. WshConvertStringMacToOem(
  1532. IN PUCHAR pSrcMacString,
  1533. IN USHORT SrcStringLen,
  1534. OUT PUCHAR pDestOemString,
  1535. IN PUSHORT pDestStringLen
  1536. )
  1537. /*++
  1538. Routine Description:
  1539. Arguments:
  1540. Return Value:
  1541. --*/
  1542. {
  1543. WCHAR wcharBuf[MAX_ENTITY + 1];
  1544. INT wcharLen, destLen;
  1545. BOOLEAN retCode = TRUE;
  1546. do
  1547. {
  1548. if ((SrcStringLen > (MAX_ENTITY+1)) ||
  1549. (*pDestStringLen < SrcStringLen))
  1550. {
  1551. retCode = FALSE;
  1552. break;
  1553. }
  1554. // Convert the src string using the MAC codepage.
  1555. if ((wcharLen = MultiByteToWideChar(
  1556. WshMacCodePage,
  1557. MB_PRECOMPOSED,
  1558. pSrcMacString,
  1559. SrcStringLen,
  1560. wcharBuf,
  1561. MAX_ENTITY + 1)) == FALSE)
  1562. {
  1563. DBGPRINT(("WshConvertStringMacToOem: FAILED mbtowcs %s-%d\n",
  1564. pSrcMacString, SrcStringLen));
  1565. retCode = FALSE;
  1566. break;
  1567. }
  1568. DBGPRINT0(("WshConvertStringMacToOem: Converting mbtowcs %s-%d\n",
  1569. pSrcMacString, SrcStringLen));
  1570. // Convert the wide char string to mac ansi string.
  1571. if ((destLen = WideCharToMultiByte(
  1572. CP_ACP,
  1573. 0,
  1574. wcharBuf,
  1575. wcharLen,
  1576. pDestOemString,
  1577. *pDestStringLen,
  1578. NULL,
  1579. NULL)) == FALSE)
  1580. {
  1581. DBGPRINT(("WshConvertStringMacToOem: FAILED wctomb %s-%d\n",
  1582. pDestOemString, *pDestStringLen));
  1583. retCode = FALSE;
  1584. break;
  1585. }
  1586. *pDestStringLen = (USHORT)destLen;
  1587. DBGPRINT0(("WshConvertStringMacToOem: Converted mbtowcs %s-%d\n",
  1588. pDestOemString, *pDestStringLen));
  1589. } while (FALSE);
  1590. return(retCode);
  1591. }
  1592. BOOLEAN
  1593. WshRegGetCodePage(
  1594. VOID
  1595. )
  1596. /*++
  1597. Routine Description:
  1598. Arguments:
  1599. Return Value:
  1600. --*/
  1601. {
  1602. DWORD dwRetCode;
  1603. HKEY hkeyCodepagePath;
  1604. DWORD dwType;
  1605. DWORD dwBufSize;
  1606. WCHAR wchCodepageNum[60];
  1607. UNICODE_STRING wchUnicodeCodePage;
  1608. NTSTATUS status;
  1609. // Open the key
  1610. if (dwRetCode = RegOpenKeyEx(
  1611. HKEY_LOCAL_MACHINE,
  1612. WSH_KEYPATH_CODEPAGE,
  1613. 0,
  1614. KEY_QUERY_VALUE,
  1615. &hkeyCodepagePath))
  1616. return(FALSE);
  1617. // Get the Code page number value for the Mac
  1618. dwBufSize = sizeof(wchCodepageNum);
  1619. if (dwRetCode = RegQueryValueEx(
  1620. hkeyCodepagePath,
  1621. WSHREG_VALNAME_CODEPAGE,
  1622. NULL,
  1623. &dwType,
  1624. (LPBYTE)wchCodepageNum,
  1625. &dwBufSize))
  1626. return(FALSE);
  1627. // Close the key
  1628. RegCloseKey(hkeyCodepagePath);
  1629. // Convert the code page to a numerical value
  1630. RtlInitUnicodeString(&wchUnicodeCodePage, wchCodepageNum);
  1631. status = RtlUnicodeStringToInteger(
  1632. &wchUnicodeCodePage,
  1633. DECIMAL_BASE,
  1634. &WshMacCodePage);
  1635. DBGPRINT0(("WSHGetCodePage %lx.%d\n", WshMacCodePage, WshMacCodePage));
  1636. return(NT_SUCCESS(status));
  1637. }
  1638. INT
  1639. WSHEnumProtocols (
  1640. IN LPINT lpiProtocols,
  1641. IN LPTSTR lpTransportKeyName, // unused
  1642. IN OUT LPVOID lpProtocolBuffer,
  1643. IN OUT LPDWORD lpdwBufferLength
  1644. )
  1645. /*++
  1646. Routine Description:
  1647. This routine returns information about the protocols active on the local host.
  1648. Arguments:
  1649. lpiProtocols - a NULL terminated array of protocol ids. This parameter
  1650. is optional; if NULL, information on all available protocols is returned.
  1651. lpTransportKeyName - unused
  1652. lpProtocolBuffer - a buffer which is filled with PROTOCOL_INFO structures.
  1653. lpdwBufferLength - on input, the count of bytes in the lpProtocolBuffer passed
  1654. to EnumProtocols. On output, the minimum buffersize that can be passed to
  1655. EnumProtocols to retrieve all the requested information. This routine has
  1656. no ability to enumerate over multiple calls; the passed in buffer must be
  1657. large enough to hold all entries in order for the routine to succeed.
  1658. Return Value:
  1659. If no error occurs, it returns the number of PROTOCOL_INFO structures written to
  1660. the lpProtocolBuffer buffer. If there is an error, returns SOCKET_ERROR (-1) and
  1661. a specific error code is retrieved with the GetLastError() API.
  1662. --*/
  1663. {
  1664. DWORD bytesRequired;
  1665. PPROTOCOL_INFO NextProtocolInfo;
  1666. LPWSTR NextName;
  1667. BOOL usePap = FALSE;
  1668. BOOL useAdsp = FALSE;
  1669. BOOL useRtmp = FALSE;
  1670. BOOL useZip = FALSE;
  1671. DWORD i, numRequested = 0;
  1672. lpTransportKeyName; // Avoid compiler warnings for unused parm
  1673. //
  1674. // Make sure that the caller cares about PAP and/or ADSP
  1675. //
  1676. if ( ARGUMENT_PRESENT( lpiProtocols ) )
  1677. {
  1678. for ( i = 0; lpiProtocols[i] != 0; i++ )
  1679. {
  1680. if ( lpiProtocols[i] == ATPROTO_ADSP )
  1681. {
  1682. useAdsp = TRUE;
  1683. numRequested += 1;
  1684. }
  1685. if ( lpiProtocols[i] == ATPROTO_PAP )
  1686. {
  1687. usePap = TRUE;
  1688. numRequested += 1;
  1689. }
  1690. if ( lpiProtocols[i] == DDPPROTO_RTMP )
  1691. {
  1692. useRtmp = TRUE;
  1693. numRequested += 1;
  1694. }
  1695. if ( lpiProtocols[i] == DDPPROTO_ZIP )
  1696. {
  1697. useZip = TRUE;
  1698. numRequested += 1;
  1699. }
  1700. }
  1701. } else
  1702. {
  1703. usePap = TRUE;
  1704. useAdsp = TRUE;
  1705. useRtmp = TRUE;
  1706. useZip = TRUE;
  1707. numRequested = 4;
  1708. }
  1709. if ( !usePap && !useAdsp && !useRtmp && !useZip)
  1710. {
  1711. *lpdwBufferLength = 0;
  1712. return 0;
  1713. }
  1714. //
  1715. // Make sure that the caller has specified a sufficiently large
  1716. // buffer.
  1717. //
  1718. bytesRequired = (sizeof(PROTOCOL_INFO) * numRequested);
  1719. if (useAdsp)
  1720. {
  1721. bytesRequired += sizeof( ADSP_NAME );
  1722. }
  1723. if (usePap)
  1724. {
  1725. bytesRequired += sizeof( PAP_NAME );
  1726. }
  1727. if (useRtmp)
  1728. {
  1729. bytesRequired += sizeof( RTMP_NAME );
  1730. }
  1731. if (useZip)
  1732. {
  1733. bytesRequired += sizeof( ZIP_NAME );
  1734. }
  1735. if ( bytesRequired > *lpdwBufferLength )
  1736. {
  1737. *lpdwBufferLength = bytesRequired;
  1738. return -1;
  1739. }
  1740. NextProtocolInfo = lpProtocolBuffer;
  1741. NextName = (LPWSTR)( (LPBYTE)lpProtocolBuffer + *lpdwBufferLength );
  1742. //
  1743. // Fill in ADSP info, if requested.
  1744. //
  1745. if ( useAdsp ) {
  1746. // Adsp - note that even though we return iSocketType of SOCK_RDM, the
  1747. // fact that the XP_PSUEDO_STREAM service flag is set tells the caller
  1748. // they can actually open a adsp socket in SOCK_STREAM mode as well.
  1749. NextName -= sizeof( ADSP_NAME )/sizeof(WCHAR);
  1750. NextProtocolInfo->dwServiceFlags = XP_EXPEDITED_DATA |
  1751. XP_GUARANTEED_ORDER |
  1752. XP_GUARANTEED_DELIVERY |
  1753. XP_MESSAGE_ORIENTED |
  1754. XP_PSEUDO_STREAM |
  1755. XP_GRACEFUL_CLOSE;
  1756. NextProtocolInfo->iAddressFamily = AF_APPLETALK;
  1757. NextProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_AT);
  1758. NextProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_AT);
  1759. NextProtocolInfo->iSocketType = SOCK_RDM;
  1760. NextProtocolInfo->iProtocol = ATPROTO_ADSP;
  1761. NextProtocolInfo->dwMessageSize = 65535;
  1762. NextProtocolInfo->lpProtocol = NextName;
  1763. lstrcpyW( NextProtocolInfo->lpProtocol, ADSP_NAME );
  1764. NextProtocolInfo++;
  1765. }
  1766. //
  1767. // Fill in PAP info, if requested.
  1768. //
  1769. if ( usePap ) {
  1770. NextName -= sizeof( PAP_NAME )/sizeof(WCHAR);
  1771. NextProtocolInfo->dwServiceFlags = XP_MESSAGE_ORIENTED |
  1772. XP_GUARANTEED_DELIVERY |
  1773. XP_GUARANTEED_ORDER |
  1774. XP_GRACEFUL_CLOSE;
  1775. NextProtocolInfo->iAddressFamily = AF_APPLETALK;
  1776. NextProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_AT);
  1777. NextProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_AT);
  1778. NextProtocolInfo->iSocketType = SOCK_RDM;
  1779. NextProtocolInfo->iProtocol = ATPROTO_PAP;
  1780. NextProtocolInfo->dwMessageSize = 4096;
  1781. NextProtocolInfo->lpProtocol = NextName;
  1782. lstrcpyW( NextProtocolInfo->lpProtocol, PAP_NAME );
  1783. NextProtocolInfo++;
  1784. }
  1785. if ( useRtmp ) {
  1786. NextName -= sizeof( RTMP_NAME )/sizeof(WCHAR);
  1787. NextProtocolInfo->dwServiceFlags = XP_CONNECTIONLESS;
  1788. NextProtocolInfo->iAddressFamily = AF_APPLETALK;
  1789. NextProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_AT);
  1790. NextProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_AT);
  1791. NextProtocolInfo->iSocketType = SOCK_DGRAM;
  1792. NextProtocolInfo->iProtocol = DDPPROTO_RTMP;
  1793. NextProtocolInfo->dwMessageSize = 0;
  1794. NextProtocolInfo->lpProtocol = NextName;
  1795. lstrcpyW( NextProtocolInfo->lpProtocol, RTMP_NAME );
  1796. NextProtocolInfo++;
  1797. }
  1798. if ( useZip ) {
  1799. NextName -= sizeof( ZIP_NAME )/sizeof(WCHAR);
  1800. NextProtocolInfo->dwServiceFlags = XP_CONNECTIONLESS;
  1801. NextProtocolInfo->iAddressFamily = AF_APPLETALK;
  1802. NextProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_AT);
  1803. NextProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_AT);
  1804. NextProtocolInfo->iSocketType = SOCK_DGRAM;
  1805. NextProtocolInfo->iProtocol = DDPPROTO_ZIP;
  1806. NextProtocolInfo->dwMessageSize = 0;
  1807. NextProtocolInfo->lpProtocol = NextName;
  1808. lstrcpyW( NextProtocolInfo->lpProtocol, ZIP_NAME );
  1809. NextProtocolInfo++;
  1810. }
  1811. *lpdwBufferLength = bytesRequired;
  1812. return numRequested;
  1813. } // WSHEnumProtocols
  1814. BOOL FAR PASCAL
  1815. WshDllInitialize(
  1816. HINSTANCE hInstance,
  1817. DWORD nReason,
  1818. LPVOID pReserved
  1819. )
  1820. /*++
  1821. Routine Description:
  1822. SYNOPSIS: This DLL entry point is called when processes & threads
  1823. are initialized and terminated, or upon calls to
  1824. LoadLibrary() and FreeLibrary().
  1825. Arguments:
  1826. ENTRY: hInstance - A handle to the DLL.
  1827. nReason - Indicates why the DLL entry
  1828. point is being called.
  1829. pReserved - Reserved.
  1830. Return Value:
  1831. RETURNS: BOOL - TRUE = DLL init was successful.
  1832. FALSE = DLL init failed.
  1833. NOTES: The return value is only relevant during processing of
  1834. DLL_PROCESS_ATTACH notifications.
  1835. --*/
  1836. {
  1837. BOOL fResult = TRUE;
  1838. UNREFERENCED_PARAMETER( pReserved );
  1839. switch( nReason )
  1840. {
  1841. case DLL_PROCESS_ATTACH:
  1842. //
  1843. // This notification indicates that the DLL is attaching to
  1844. // the address space of the current process. This is either
  1845. // the result of the process starting up, or after a call to
  1846. // LoadLibrary(). The DLL should us this as a hook to
  1847. // initialize any instance data or to allocate a TLS index.
  1848. //
  1849. // This call is made in the context of the thread that
  1850. // caused the process address space to change.
  1851. //
  1852. fResult = WshRegGetCodePage();
  1853. break;
  1854. case DLL_PROCESS_DETACH:
  1855. //
  1856. // This notification indicates that the calling process is
  1857. // detaching the DLL from its address space. This is either
  1858. // due to a clean process exit or from a FreeLibrary() call.
  1859. // The DLL should use this opportunity to return any TLS
  1860. // indexes allocated and to free any thread local data.
  1861. //
  1862. // Note that this notification is posted only once per
  1863. // process. Individual threads do not invoke the
  1864. // DLL_THREAD_DETACH notification.
  1865. //
  1866. break;
  1867. case DLL_THREAD_ATTACH:
  1868. //
  1869. // This notfication indicates that a new thread is being
  1870. // created in the current process. All DLLs attached to
  1871. // the process at the time the thread starts will be
  1872. // notified. The DLL should use this opportunity to
  1873. // initialize a TLS slot for the thread.
  1874. //
  1875. // Note that the thread that posts the DLL_PROCESS_ATTACH
  1876. // notification will not post a DLL_THREAD_ATTACH.
  1877. //
  1878. // Note also that after a DLL is loaded with LoadLibrary,
  1879. // only threads created after the DLL is loaded will
  1880. // post this notification.
  1881. //
  1882. break;
  1883. case DLL_THREAD_DETACH:
  1884. //
  1885. // This notification indicates that a thread is exiting
  1886. // cleanly. The DLL should use this opportunity to
  1887. // free any data stored in TLS indices.
  1888. //
  1889. break;
  1890. default:
  1891. //
  1892. // Who knows? Just ignore it.
  1893. //
  1894. break;
  1895. }
  1896. return fResult;
  1897. }