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.

3753 lines
98 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. getaddr.c
  5. Abstract:
  6. This module contains the code to support NPGetAddressByName.
  7. Author:
  8. Yi-Hsin Sung (yihsins) 18-Apr-94
  9. Glenn A. Curtis (glennc) 31-Jul-95
  10. Arnold Miller (ArnoldM) 7-Dec-95
  11. Revision History:
  12. yihsins Created
  13. glennc Modified 31-Jul-95
  14. ArnoldM Modified 7-Dec-95
  15. --*/
  16. #include <nwclient.h>
  17. #include <winsock.h>
  18. #include <wsipx.h>
  19. #include <nspapi.h>
  20. #include <nspapip.h>
  21. #include <wsnwlink.h>
  22. #include <svcguid.h>
  23. #include <nwsap.h>
  24. #include <align.h>
  25. #include <nwmisc.h>
  26. #include <rnrdefs.h>
  27. //-------------------------------------------------------------------//
  28. // //
  29. // Local Function Prototypes //
  30. // //
  31. //-------------------------------------------------------------------//
  32. #define NW_SAP_PRIORITY_VALUE_NAME L"SapPriority"
  33. #define NW_WORKSTATION_SVCPROVIDER_REGKEY L"System\\CurrentControlSet\\Services\\NWCWorkstation\\ServiceProvider"
  34. #define NW_GUID_VALUE_NAME L"GUID"
  35. #define NW_SERVICETYPES_KEY_NAME L"ServiceTypes"
  36. #define NW_SERVICE_TYPES_REGKEY L"System\\CurrentControlSet\\Control\\ServiceProvider\\ServiceTypes"
  37. #define DLL_VERSION 1
  38. #define WSOCK_VER_REQD 0x0101
  39. //
  40. // critical sections used
  41. //
  42. extern CRITICAL_SECTION NwServiceListCriticalSection;
  43. extern HANDLE NwServiceListDoneEvent;
  44. // have been returned
  45. BOOL
  46. OldRnRCheckCancel(
  47. PVOID pvArg
  48. );
  49. DWORD
  50. OldRnRCheckSapData(
  51. PSAP_BCAST_CONTROL psbc,
  52. PSAP_IDENT_HEADER pSap,
  53. PDWORD pdwErr
  54. );
  55. DWORD
  56. SapGetSapForType(
  57. PSAP_BCAST_CONTROL psbc,
  58. WORD nServiceType
  59. );
  60. DWORD
  61. SapFreeSapSocket(
  62. SOCKET s
  63. );
  64. DWORD
  65. SapGetSapSocket(
  66. SOCKET * ppsocket
  67. );
  68. VOID
  69. pFreeAllContexts();
  70. PSAP_RNR_CONTEXT
  71. SapGetContext(
  72. IN HANDLE Handle
  73. );
  74. PSAP_RNR_CONTEXT
  75. SapMakeContext(
  76. IN HANDLE Handle,
  77. IN DWORD dwExcess
  78. );
  79. VOID
  80. SapReleaseContext(
  81. PSAP_RNR_CONTEXT psrcContext
  82. );
  83. INT
  84. SapGetAddressByName(
  85. IN LPGUID lpServiceType,
  86. IN LPWSTR lpServiceName,
  87. IN LPDWORD lpdwProtocols,
  88. IN DWORD dwResolution,
  89. IN OUT LPVOID lpCsAddrBuffer,
  90. IN OUT LPDWORD lpdwBufferLength,
  91. IN OUT LPWSTR lpAliasBuffer,
  92. IN OUT LPDWORD lpdwAliasBufferLength,
  93. IN HANDLE hCancellationEvent
  94. );
  95. DWORD
  96. SapGetService (
  97. IN LPGUID lpServiceType,
  98. IN LPWSTR lpServiceName,
  99. IN DWORD dwProperties,
  100. IN BOOL fUnicodeBlob,
  101. OUT LPSERVICE_INFO lpServiceInfo,
  102. IN OUT LPDWORD lpdwBufferLen
  103. );
  104. DWORD
  105. SapSetService (
  106. IN DWORD dwOperation,
  107. IN DWORD dwFlags,
  108. IN BOOL fUnicodeBlob,
  109. IN LPSERVICE_INFO lpServiceInfo
  110. );
  111. DWORD
  112. NwpGetAddressViaSap(
  113. IN WORD nServiceType,
  114. IN LPWSTR lpServiceName,
  115. IN DWORD nProt,
  116. IN OUT LPVOID lpCsAddrBuffer,
  117. IN OUT LPDWORD lpdwBufferLength,
  118. IN HANDLE hCancellationEvent,
  119. OUT LPDWORD lpcAddress
  120. );
  121. BOOL
  122. NwpLookupSapInRegistry(
  123. IN LPGUID lpServiceType,
  124. OUT PWORD pnSapType,
  125. OUT PWORD pwPort,
  126. IN OUT PDWORD pfConnectionOriented
  127. );
  128. DWORD
  129. NwpRnR2AddServiceType(
  130. IN LPWSTR lpServiceTypeName,
  131. IN LPGUID lpClassType,
  132. IN WORD wSapId,
  133. IN WORD wPort
  134. );
  135. BOOL
  136. NwpRnR2RemoveServiceType(
  137. IN LPGUID lpServiceType
  138. );
  139. DWORD
  140. NwpAddServiceType(
  141. IN LPSERVICE_INFO lpServiceInfo,
  142. IN BOOL fUnicodeBlob
  143. );
  144. DWORD
  145. NwpDeleteServiceType(
  146. IN LPSERVICE_INFO lpServiceInfo,
  147. IN BOOL fUnicodeBlob
  148. );
  149. DWORD
  150. FillBufferWithCsAddr(
  151. IN LPBYTE pAddress,
  152. IN DWORD nProt,
  153. IN OUT LPVOID lpCsAddrBuffer,
  154. IN OUT LPDWORD lpdwBufferLength,
  155. OUT LPDWORD pcAddress
  156. );
  157. DWORD
  158. AddServiceToList(
  159. IN LPSERVICE_INFO lpServiceInfo,
  160. IN WORD nSapType,
  161. IN BOOL fAdvertiseBySap,
  162. IN INT nIndexIPXAddress
  163. );
  164. VOID
  165. RemoveServiceFromList(
  166. IN PREGISTERED_SERVICE pSvc
  167. );
  168. DWORD
  169. pSapSetService2(
  170. IN DWORD dwOperation,
  171. IN LPWSTR lpszServiceInstance,
  172. IN PBYTE pbAddress,
  173. IN LPGUID pType,
  174. IN WORD nServiceType
  175. );
  176. DWORD
  177. pSapSetService(
  178. IN DWORD dwOperation,
  179. IN LPSERVICE_INFO lpServiceInfo,
  180. IN WORD nServiceType
  181. );
  182. //
  183. // Misc Functions
  184. //
  185. DWORD NwInitializeSocket(
  186. IN HANDLE hEventHandle
  187. );
  188. DWORD
  189. NwAdvertiseService(
  190. IN LPWSTR pServiceName,
  191. IN WORD nSapType,
  192. IN LPSOCKADDR_IPX pAddr,
  193. IN HANDLE hEventHandle
  194. );
  195. DWORD SapFunc(
  196. IN HANDLE hEventHandle
  197. );
  198. DWORD
  199. NwpGetAddressByName(
  200. IN LPWSTR Reserved,
  201. IN WORD nServiceType,
  202. IN LPWSTR lpServiceName,
  203. IN OUT LPSOCKADDR_IPX lpsockaddr
  204. );
  205. //-------------------------------------------------------------------//
  206. // //
  207. // Global variables //
  208. // //
  209. //-------------------------------------------------------------------//
  210. //
  211. // This is the address we send to
  212. //
  213. UCHAR SapBroadcastAddress[] = {
  214. AF_IPX, 0, // Address Family
  215. 0x00, 0x00, 0x00, 0x00, // Dest. Net Number
  216. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Dest. Node Number
  217. 0x04, 0x52, // Dest. Socket
  218. 0x04 // Packet type
  219. };
  220. PSAP_RNR_CONTEXT psrcSapContexts;
  221. //
  222. // Misc. variables used if we need to advertise ourselves, i.e.
  223. // when the SAP service is not installed/active.
  224. //
  225. BOOL fInitSocket = FALSE; // TRUE if we have created the second thread
  226. SOCKET socketSap; // Socket used to send SAP advertise packets
  227. PREGISTERED_SERVICE pServiceListHead = NULL; // Points to head of link list
  228. PREGISTERED_SERVICE pServiceListTail = NULL; // Points to tail of link list
  229. //
  230. // needed to map old and new RnR functions
  231. //
  232. DWORD oldRnRServiceRegister = SERVICE_REGISTER;
  233. DWORD oldRnRServiceDeRegister = SERVICE_DEREGISTER;
  234. HMODULE hThisDll = INVALID_HANDLE_VALUE;
  235. //-------------------------------------------------------------------//
  236. // //
  237. // Function Bodies //
  238. // //
  239. //-------------------------------------------------------------------//
  240. VOID
  241. pFreeAllContexts()
  242. /*++
  243. Routine Description:
  244. Called at Cleanup time to free all NSP resource
  245. --*/
  246. {
  247. PSAP_RNR_CONTEXT psrcContext;
  248. EnterCriticalSection( &NwServiceListCriticalSection );
  249. while(psrcContext = psrcSapContexts)
  250. {
  251. (VOID)SapReleaseContext(psrcContext);
  252. }
  253. LeaveCriticalSection( &NwServiceListCriticalSection );
  254. }
  255. PSAP_RNR_CONTEXT
  256. SapGetContext(HANDLE Handle)
  257. /*++
  258. Routine Description:
  259. This routine checks the existing SAP contexts to see if we have one
  260. for this calll.
  261. Arguments:
  262. Handle - the RnR handle, if appropriate
  263. --*/
  264. {
  265. PSAP_RNR_CONTEXT psrcContext;
  266. EnterCriticalSection( &NwServiceListCriticalSection );
  267. for(psrcContext = psrcSapContexts;
  268. psrcContext && (psrcContext->Handle != Handle);
  269. psrcContext = psrcContext->pNextContext);
  270. if(psrcContext)
  271. {
  272. ++psrcContext->lInUse;
  273. }
  274. LeaveCriticalSection( &NwServiceListCriticalSection );
  275. return(psrcContext);
  276. }
  277. PSAP_RNR_CONTEXT
  278. SapMakeContext(
  279. IN HANDLE Handle,
  280. IN DWORD dwExcess
  281. )
  282. {
  283. /*++
  284. Routine Description:
  285. This routine makes a SAP conext for a given RnR handle
  286. Arguments:
  287. Handle - the RnR handle. If NULL, use the context as the handle
  288. dwType - the type of the context
  289. --*/
  290. PSAP_RNR_CONTEXT psrcContext;
  291. psrcContext = (PSAP_RNR_CONTEXT)
  292. LocalAlloc(LPTR, sizeof(SAP_RNR_CONTEXT) +
  293. dwExcess);
  294. if(psrcContext)
  295. {
  296. InitializeCriticalSection(&psrcContext->u_type.sbc.csMonitor);
  297. psrcContext->lInUse = 2;
  298. psrcContext->Handle = (Handle ? Handle : (HANDLE)psrcContext);
  299. psrcContext->lSig = RNR_SIG;
  300. EnterCriticalSection( &NwServiceListCriticalSection );
  301. psrcContext->pNextContext = psrcSapContexts;
  302. psrcSapContexts = psrcContext;
  303. LeaveCriticalSection( &NwServiceListCriticalSection );
  304. }
  305. return(psrcContext);
  306. }
  307. VOID
  308. SapReleaseContext(PSAP_RNR_CONTEXT psrcContext)
  309. /*++
  310. Routine Description:
  311. Dereference an RNR Context and free it if it is no longer referenced.
  312. Determining no referneces is a bit tricky because we try to avoid
  313. obtaining the CritSec unless we think the context may be unneeded. Hence
  314. the code goes through some fuss. It could be much simpler if we always
  315. obtained the CritSec whenever we changed the reference count, but
  316. this is faster for the nominal case.
  317. Arguments:
  318. psrcContext -- The context
  319. --*/
  320. {
  321. EnterCriticalSection( &NwServiceListCriticalSection );
  322. if(--psrcContext->lInUse == 0)
  323. {
  324. PSAP_RNR_CONTEXT psrcX, psrcPrev;
  325. PSAP_DATA psdData;
  326. //
  327. // Done with it. Remove from the lisgt
  328. //
  329. psrcPrev = 0;
  330. for(psrcX = psrcSapContexts;
  331. psrcX;
  332. psrcX = psrcX->pNextContext)
  333. {
  334. if(psrcX == psrcContext)
  335. {
  336. //
  337. // Found it.
  338. //
  339. if(psrcPrev)
  340. {
  341. psrcPrev->pNextContext = psrcContext->pNextContext;
  342. }
  343. else
  344. {
  345. psrcSapContexts = psrcContext->pNextContext;
  346. }
  347. break;
  348. }
  349. psrcPrev = psrcX;
  350. }
  351. ASSERT(psrcX);
  352. //
  353. // release SAP data, if any
  354. //
  355. if(psrcContext->dwUnionType == LOOKUP_TYPE_SAP)
  356. {
  357. for(psdData = psrcContext->u_type.sbc.psdHead;
  358. psdData;)
  359. {
  360. PSAP_DATA psdTemp = psdData->sapNext;
  361. LocalFree(psdData);
  362. psdData = psdTemp;
  363. }
  364. if(psrcContext->u_type.sbc.s)
  365. {
  366. SapFreeSapSocket(psrcContext->u_type.sbc.s);
  367. }
  368. }
  369. DeleteCriticalSection(&psrcContext->u_type.sbc.csMonitor);
  370. if(psrcContext->hServer)
  371. {
  372. CloseHandle(psrcContext->hServer);
  373. }
  374. LocalFree(psrcContext);
  375. }
  376. LeaveCriticalSection( &NwServiceListCriticalSection );
  377. }
  378. INT
  379. APIENTRY
  380. NPLoadNameSpaces(
  381. IN OUT LPDWORD lpdwVersion,
  382. IN OUT LPNS_ROUTINE nsrBuffer,
  383. IN OUT LPDWORD lpdwBufferLength
  384. )
  385. {
  386. /*++
  387. Routine Description:
  388. This routine returns name space info and functions supported in this
  389. dll.
  390. Arguments:
  391. lpdwVersion - dll version
  392. nsrBuffer - on return, this will be filled with an array of
  393. NS_ROUTINE structures
  394. lpdwBufferLength - on input, the number of bytes contained in the buffer
  395. pointed to by nsrBuffer. On output, the minimum number of bytes
  396. to pass for the nsrBuffer to retrieve all the requested info
  397. Return Value:
  398. The number of NS_ROUTINE structures returned, or SOCKET_ERROR (-1) if
  399. the nsrBuffer is too small. Use GetLastError() to retrieve the
  400. error code.
  401. --*/
  402. DWORD err;
  403. DWORD dwLengthNeeded;
  404. HKEY providerKey;
  405. DWORD dwSapPriority = NS_STANDARD_FAST_PRIORITY;
  406. *lpdwVersion = DLL_VERSION;
  407. //
  408. // Check to see if the buffer is large enough
  409. //
  410. dwLengthNeeded = sizeof(NS_ROUTINE) + 4 * sizeof(LPFN_NSPAPI);
  411. if ( ( *lpdwBufferLength < dwLengthNeeded )
  412. || ( nsrBuffer == NULL )
  413. )
  414. {
  415. *lpdwBufferLength = dwLengthNeeded;
  416. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  417. return (DWORD) SOCKET_ERROR;
  418. }
  419. //
  420. // Get the Sap priority from the registry. We will ignore all errors
  421. // from the registry and have a default priority if we failed to read
  422. // the value.
  423. //
  424. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  425. NW_WORKSTATION_SVCPROVIDER_REGKEY,
  426. 0,
  427. KEY_READ,
  428. &providerKey );
  429. if ( !err )
  430. {
  431. DWORD BytesNeeded = sizeof( dwSapPriority );
  432. DWORD ValueType;
  433. err = RegQueryValueExW( providerKey,
  434. NW_SAP_PRIORITY_VALUE_NAME,
  435. NULL,
  436. &ValueType,
  437. (LPBYTE) &dwSapPriority,
  438. &BytesNeeded );
  439. if ( err ) // set default priority if error occurred
  440. dwSapPriority = NS_STANDARD_FAST_PRIORITY;
  441. }
  442. //
  443. // We only support 1 name space for now, so fill in the NS_ROUTINE.
  444. //
  445. nsrBuffer->dwFunctionCount = 3;
  446. nsrBuffer->alpfnFunctions = (LPFN_NSPAPI *)
  447. ((BYTE *) nsrBuffer + sizeof(NS_ROUTINE));
  448. (nsrBuffer->alpfnFunctions)[NSPAPI_GET_ADDRESS_BY_NAME] =
  449. (LPFN_NSPAPI) SapGetAddressByName;
  450. (nsrBuffer->alpfnFunctions)[NSPAPI_GET_SERVICE] =
  451. (LPFN_NSPAPI) SapGetService;
  452. (nsrBuffer->alpfnFunctions)[NSPAPI_SET_SERVICE] =
  453. (LPFN_NSPAPI) SapSetService;
  454. (nsrBuffer->alpfnFunctions)[3] = NULL;
  455. nsrBuffer->dwNameSpace = NS_SAP;
  456. nsrBuffer->dwPriority = dwSapPriority;
  457. return 1; // number of namespaces
  458. }
  459. INT
  460. SapGetAddressByName(
  461. IN LPGUID lpServiceType,
  462. IN LPWSTR lpServiceName,
  463. IN LPDWORD lpdwProtocols,
  464. IN DWORD dwResolution,
  465. IN OUT LPVOID lpCsAddrBuffer,
  466. IN OUT LPDWORD lpdwBufferLength,
  467. IN OUT LPWSTR lpAliasBuffer,
  468. IN OUT LPDWORD lpdwAliasBufferLength,
  469. IN HANDLE hCancellationEvent
  470. )
  471. /*++
  472. Routine Description:
  473. This routine returns address information about a specific service.
  474. Arguments:
  475. lpServiceType - pointer to the GUID for the service type
  476. lpServiceName - unique string representing the service name, in the
  477. Netware case, this is the server name
  478. lpdwProtocols - a zero terminated array of protocol ids. This parameter
  479. is optional; if lpdwProtocols is NULL, information on all available
  480. Protocols is returned
  481. dwResolution - can be one of the following values:
  482. RES_SOFT_SEARCH, RES_FIND_MULTIPLE
  483. lpCsAddrBuffer - on return, will be filled with CSADDR_INFO structures
  484. lpdwBufferLength - on input, the number of bytes contained in the buffer
  485. pointed to by lpCsAddrBuffer. On output, the minimum number of bytes
  486. to pass for the lpCsAddrBuffer to retrieve all the requested info
  487. lpAliasBuffer - not used
  488. lpdwAliasBufferLength - not used
  489. hCancellationEvent - the event which signals us to cancel the request
  490. Return Value:
  491. The number of CSADDR_INFO structures returned, or SOCKET_ERROR (-1) if
  492. the lpCsAddrBuffer is too small. Use GetLastError() to retrieve the
  493. error code.
  494. --*/
  495. {
  496. DWORD err;
  497. WORD nServiceType;
  498. DWORD cAddress = 0; // Count of the number of address returned
  499. // in lpCsAddrBuffer
  500. DWORD cProtocols = 0; // Count of the number of protocols contained
  501. // in lpdwProtocols + 1 ( for zero terminate )
  502. DWORD nProt = IPX_BIT | SPXII_BIT;
  503. DWORD fConnectionOriented = (DWORD) -1;
  504. SOCKADDR_IPX sockaddr;
  505. if ( ARGUMENT_PRESENT( lpdwAliasBufferLength )
  506. && ARGUMENT_PRESENT( lpAliasBuffer )
  507. )
  508. {
  509. if ( *lpdwAliasBufferLength >= sizeof(WCHAR) )
  510. *lpAliasBuffer = 0;
  511. }
  512. //
  513. // Check for invalid parameters
  514. //
  515. if ( ( lpServiceType == NULL )
  516. || ( lpServiceName == NULL )
  517. || ( lpdwBufferLength == NULL )
  518. )
  519. {
  520. SetLastError( ERROR_INVALID_PARAMETER );
  521. return SOCKET_ERROR;
  522. }
  523. //
  524. // If an array of protocol ids is passed in, check to see if
  525. // the IPX protocol is requested. If not, return 0 since
  526. // we only support IPX.
  527. //
  528. if ( lpdwProtocols != NULL )
  529. {
  530. INT i = -1;
  531. nProt = 0;
  532. while ( lpdwProtocols[++i] != 0 )
  533. {
  534. if ( lpdwProtocols[i] == NSPROTO_IPX )
  535. nProt |= IPX_BIT;
  536. if ( lpdwProtocols[i] == NSPROTO_SPX )
  537. nProt |= SPX_BIT;
  538. if ( lpdwProtocols[i] == NSPROTO_SPXII )
  539. nProt |= SPXII_BIT;
  540. }
  541. if ( nProt == 0 )
  542. return 0; // No address found
  543. cProtocols = i+1;
  544. }
  545. //
  546. // Check to see if the service type is supported in NetWare
  547. //
  548. if ( NwpLookupSapInRegistry( lpServiceType, &nServiceType, NULL,
  549. &fConnectionOriented ))
  550. {
  551. if ( fConnectionOriented != -1 ) // Got value from registry
  552. {
  553. if ( fConnectionOriented )
  554. {
  555. nProt &= ~IPX_BIT;
  556. }
  557. else // connectionless
  558. {
  559. nProt &= ~(SPX_BIT | SPXII_BIT );
  560. }
  561. if ( nProt == 0 )
  562. return 0; // No address found
  563. }
  564. }
  565. else
  566. {
  567. //
  568. // Couldn't find it in the registry, see if it is a well-known GUID
  569. //
  570. if ( IS_SVCID_NETWARE( lpServiceType ))
  571. {
  572. nServiceType = SAPID_FROM_SVCID_NETWARE( lpServiceType );
  573. }
  574. else
  575. {
  576. //
  577. // Not a well-known GUID either
  578. //
  579. return 0; // No address found
  580. }
  581. }
  582. if ((dwResolution & RES_SERVICE) != 0)
  583. {
  584. err = FillBufferWithCsAddr( NULL,
  585. nProt,
  586. lpCsAddrBuffer,
  587. lpdwBufferLength,
  588. &cAddress );
  589. if ( err )
  590. {
  591. SetLastError( err );
  592. return SOCKET_ERROR;
  593. }
  594. return cAddress;
  595. }
  596. //
  597. // Try to get the address from the bindery first
  598. //
  599. err = NwpGetAddressByName( NULL,
  600. nServiceType,
  601. lpServiceName,
  602. &sockaddr );
  603. if ( err == NO_ERROR )
  604. {
  605. err = FillBufferWithCsAddr( sockaddr.sa_netnum,
  606. nProt,
  607. lpCsAddrBuffer,
  608. lpdwBufferLength,
  609. &cAddress );
  610. }
  611. if ( err && ( err != ERROR_INSUFFICIENT_BUFFER ) )
  612. {
  613. if ( err == ERROR_SERVICE_NOT_ACTIVE )
  614. {
  615. //
  616. // We could not find the service name in the bindery, and we
  617. // need to try harder ( RES_SOFT_SEARCH not defined ), so send out
  618. // SAP query packets to see if we can find it.
  619. //
  620. err = NwpGetAddressViaSap(
  621. nServiceType,
  622. lpServiceName,
  623. nProt,
  624. lpCsAddrBuffer,
  625. lpdwBufferLength,
  626. hCancellationEvent,
  627. &cAddress );
  628. #if DBG
  629. IF_DEBUG(OTHER)
  630. {
  631. if ( err == NO_ERROR )
  632. {
  633. KdPrint(("Successfully got %d address for %ws from SAP.\n",
  634. cAddress, lpServiceName ));
  635. }
  636. else
  637. {
  638. KdPrint(("Failed with err %d when getting address for %ws from SAP.\n", err, lpServiceName ));
  639. }
  640. }
  641. #endif
  642. }
  643. else
  644. {
  645. err = NO_ERROR;
  646. cAddress = 0;
  647. }
  648. }
  649. if ( err )
  650. {
  651. SetLastError( err );
  652. return SOCKET_ERROR;
  653. }
  654. return cAddress;
  655. }
  656. DWORD
  657. SapGetService (
  658. IN LPGUID lpServiceType,
  659. IN LPWSTR lpServiceName,
  660. IN DWORD dwProperties,
  661. IN BOOL fUnicodeBlob,
  662. OUT LPSERVICE_INFO lpServiceInfo,
  663. IN OUT LPDWORD lpdwBufferLen
  664. )
  665. /*++
  666. Routine Description:
  667. This routine returns the service info for the given service type/name.
  668. Arguments:
  669. lpServiceType - pointer to the GUID for the service type
  670. lpServiceName - service name
  671. dwProperties - the properties of the service to return
  672. lpServiceInfo - points to a buffer to return store the return info
  673. lpdwBufferLen - on input, the count of bytes in lpServiceInfo. On output,
  674. the minimum buffer size that can be passed to this API
  675. to retrieve all the requested information
  676. Return Value:
  677. Win32 error code.
  678. --*/
  679. {
  680. DWORD err;
  681. WORD nServiceType;
  682. //
  683. // Check for invalid parameters
  684. //
  685. if ( ( dwProperties == 0 )
  686. || ( lpServiceType == NULL )
  687. || ( lpServiceName == NULL )
  688. || ( lpServiceName[0] == 0 )
  689. || ( lpdwBufferLen == NULL )
  690. )
  691. {
  692. return ERROR_INVALID_PARAMETER;
  693. }
  694. //
  695. // Check to see if the service type is supported in NetWare
  696. //
  697. if ( !(NwpLookupSapInRegistry( lpServiceType, &nServiceType, NULL, NULL )))
  698. {
  699. //
  700. // Couldn't find it in the registry, see if it is a well-known GUID
  701. //
  702. if ( IS_SVCID_NETWARE( lpServiceType ))
  703. {
  704. nServiceType = SAPID_FROM_SVCID_NETWARE( lpServiceType );
  705. }
  706. else
  707. {
  708. //
  709. // Not a well-known GUID either, return error
  710. //
  711. return ERROR_SERVICE_NOT_FOUND;
  712. }
  713. }
  714. UNREFERENCED_PARAMETER(fUnicodeBlob) ;
  715. RpcTryExcept
  716. {
  717. err = NwrGetService( NULL,
  718. nServiceType,
  719. lpServiceName,
  720. dwProperties,
  721. (LPBYTE) lpServiceInfo,
  722. *lpdwBufferLen,
  723. lpdwBufferLen );
  724. if ( err == NO_ERROR )
  725. {
  726. INT i ;
  727. LPSERVICE_INFO p = (LPSERVICE_INFO) lpServiceInfo;
  728. LPSERVICE_ADDRESS lpAddress ;
  729. //
  730. // fix up pointers n main structure (convert from offsets)
  731. //
  732. if ( p->lpServiceType != NULL )
  733. p->lpServiceType = (LPGUID) ((DWORD_PTR) p->lpServiceType +
  734. (LPBYTE) p);
  735. if ( p->lpServiceName != NULL )
  736. p->lpServiceName = (LPWSTR)
  737. ((DWORD_PTR) p->lpServiceName + (LPBYTE) p);
  738. if ( p->lpComment != NULL )
  739. p->lpComment = (LPWSTR) ((DWORD_PTR) p->lpComment + (LPBYTE) p);
  740. if ( p->lpLocale != NULL )
  741. p->lpLocale = (LPWSTR) ((DWORD_PTR) p->lpLocale + (LPBYTE) p);
  742. if ( p->lpMachineName != NULL )
  743. p->lpMachineName = (LPWSTR)
  744. ((DWORD_PTR) p->lpMachineName + (LPBYTE)p);
  745. if ( p->lpServiceAddress != NULL )
  746. p->lpServiceAddress = (LPSERVICE_ADDRESSES)
  747. ((DWORD_PTR) p->lpServiceAddress + (LPBYTE) p);
  748. if ( p->ServiceSpecificInfo.pBlobData != NULL )
  749. p->ServiceSpecificInfo.pBlobData = (LPBYTE)
  750. ((DWORD_PTR) p->ServiceSpecificInfo.pBlobData + (LPBYTE) p);
  751. //
  752. // fix up pointers in the array of addresses
  753. //
  754. for (i = p->lpServiceAddress->dwAddressCount;
  755. i > 0;
  756. i--)
  757. {
  758. lpAddress =
  759. &(p->lpServiceAddress->Addresses[i-1]) ;
  760. lpAddress->lpAddress =
  761. ((LPBYTE)p) + (DWORD_PTR)lpAddress->lpAddress ;
  762. lpAddress->lpPrincipal =
  763. ((LPBYTE)p) + (DWORD_PTR)lpAddress->lpPrincipal ;
  764. }
  765. }
  766. }
  767. RpcExcept(1)
  768. {
  769. err = ERROR_SERVICE_NOT_ACTIVE;
  770. #if 0 // the following is a good idea, but hard to get right
  771. DWORD code = RpcExceptionCode();
  772. if ( (code == RPC_S_SERVER_UNAVAILABLE)
  773. ||
  774. (code == RPC_S_UNKNOWN_IF) )
  775. err
  776. err = ERROR_SERVICE_NOT_ACTIVE;
  777. else
  778. err = NwpMapRpcError( code );
  779. #endif
  780. }
  781. RpcEndExcept
  782. if ( err == ERROR_SERVICE_NOT_ACTIVE )
  783. {
  784. //
  785. //CSNW not available, going to get it ourselves
  786. //
  787. err = NwGetService( NULL,
  788. nServiceType,
  789. lpServiceName,
  790. dwProperties,
  791. (LPBYTE) lpServiceInfo,
  792. *lpdwBufferLen,
  793. lpdwBufferLen );
  794. if ( err == NO_ERROR )
  795. {
  796. INT i ;
  797. LPSERVICE_INFO p = (LPSERVICE_INFO) lpServiceInfo;
  798. LPSERVICE_ADDRESS lpAddress ;
  799. //
  800. // fix up pointers n main structure (convert from offsets)
  801. //
  802. if ( p->lpServiceType != NULL )
  803. p->lpServiceType = (LPGUID) ((DWORD_PTR) p->lpServiceType +
  804. (LPBYTE) p);
  805. if ( p->lpServiceName != NULL )
  806. p->lpServiceName = (LPWSTR)
  807. ((DWORD_PTR) p->lpServiceName + (LPBYTE) p);
  808. if ( p->lpComment != NULL )
  809. p->lpComment = (LPWSTR) ((DWORD_PTR) p->lpComment + (LPBYTE) p);
  810. if ( p->lpLocale != NULL )
  811. p->lpLocale = (LPWSTR) ((DWORD_PTR) p->lpLocale + (LPBYTE) p);
  812. if ( p->lpMachineName != NULL )
  813. p->lpMachineName = (LPWSTR)
  814. ((DWORD_PTR) p->lpMachineName + (LPBYTE)p);
  815. if ( p->lpServiceAddress != NULL )
  816. p->lpServiceAddress = (LPSERVICE_ADDRESSES)
  817. ((DWORD_PTR) p->lpServiceAddress + (LPBYTE) p);
  818. if ( p->ServiceSpecificInfo.pBlobData != NULL )
  819. p->ServiceSpecificInfo.pBlobData = (LPBYTE)
  820. ((DWORD_PTR) p->ServiceSpecificInfo.pBlobData + (LPBYTE) p);
  821. //
  822. // fix up pointers in the array of addresses
  823. //
  824. for (i = p->lpServiceAddress->dwAddressCount;
  825. i > 0;
  826. i--)
  827. {
  828. lpAddress =
  829. &(p->lpServiceAddress->Addresses[i-1]) ;
  830. lpAddress->lpAddress =
  831. ((LPBYTE)p) + (DWORD_PTR)lpAddress->lpAddress ;
  832. lpAddress->lpPrincipal =
  833. ((LPBYTE)p) + (DWORD_PTR)lpAddress->lpPrincipal ;
  834. }
  835. }
  836. }
  837. return err;
  838. }
  839. DWORD
  840. SapSetService (
  841. IN DWORD dwOperation,
  842. IN DWORD dwFlags,
  843. IN BOOL fUnicodeBlob,
  844. IN LPSERVICE_INFO lpServiceInfo
  845. )
  846. /*++
  847. Routine Description:
  848. This routine registers or deregisters the given service type/name.
  849. Arguments:
  850. dwOperation - Either SERVICE_REGISTER, SERVICE_DEREGISTER,
  851. SERVICE_ADD_TYPE, SERVICE_DELETE_TYPE,
  852. or SERVICE_FLUSH
  853. dwFlags - ignored
  854. lpServiceInfo - Pointer to a SERVICE_INFO structure containing all info
  855. about the service.
  856. Return Value:
  857. Win32 error code.
  858. --*/
  859. {
  860. DWORD err;
  861. WORD nServiceType;
  862. UNREFERENCED_PARAMETER( dwFlags );
  863. //
  864. // Check for invalid parameters
  865. //
  866. switch ( dwOperation )
  867. {
  868. case SERVICE_REGISTER:
  869. case SERVICE_DEREGISTER:
  870. case SERVICE_ADD_TYPE:
  871. case SERVICE_DELETE_TYPE:
  872. break;
  873. case SERVICE_FLUSH:
  874. //
  875. // This is a no-op in our provider, so just return success
  876. //
  877. return NO_ERROR;
  878. default:
  879. //
  880. // We can probably say all other operations which we have no
  881. // knowledge of are ignored by us. So, just return success.
  882. //
  883. return NO_ERROR;
  884. }
  885. if ( ( lpServiceInfo == NULL )
  886. || ( lpServiceInfo->lpServiceType == NULL )
  887. || ( ((lpServiceInfo->lpServiceName == NULL) ||
  888. (lpServiceInfo->lpServiceName[0] == 0 )) &&
  889. ((dwOperation != SERVICE_ADD_TYPE) &&
  890. (dwOperation != SERVICE_DELETE_TYPE))
  891. )
  892. )
  893. {
  894. return ERROR_INVALID_PARAMETER;
  895. }
  896. //
  897. // See if operation is adding or deleting a service type
  898. //
  899. if ( dwOperation == SERVICE_ADD_TYPE )
  900. {
  901. return NwpAddServiceType( lpServiceInfo, fUnicodeBlob );
  902. }
  903. else if ( dwOperation == SERVICE_DELETE_TYPE )
  904. {
  905. return NwpDeleteServiceType( lpServiceInfo, fUnicodeBlob );
  906. }
  907. //
  908. // Check to see if the service type is supported in NetWare
  909. //
  910. if ( !(NwpLookupSapInRegistry( lpServiceInfo->lpServiceType, &nServiceType, NULL, NULL )))
  911. {
  912. //
  913. // Couldn't find it in the registry, see if it is a well-known GUID
  914. //
  915. if ( IS_SVCID_NETWARE( lpServiceInfo->lpServiceType ))
  916. {
  917. nServiceType = SAPID_FROM_SVCID_NETWARE( lpServiceInfo->lpServiceType );
  918. }
  919. else
  920. {
  921. //
  922. // Not a well-known GUID either, return error
  923. //
  924. return ERROR_SERVICE_NOT_FOUND;
  925. }
  926. }
  927. //
  928. // Operation is either SERVICE_REGISTER or SERVICE_DEREGISTER.
  929. // Pass it on to the common code used by this and the RnR2
  930. // SetService
  931. //
  932. err = pSapSetService(dwOperation, lpServiceInfo, nServiceType);
  933. return(err);
  934. }
  935. DWORD
  936. pSapSetService2(
  937. IN DWORD dwOperation,
  938. IN LPWSTR lpszServiceInstance,
  939. IN PBYTE pbAddress,
  940. IN LPGUID pType,
  941. IN WORD nServiceType
  942. )
  943. /*++
  944. Routine Description:
  945. Jacket routine called by the RnR2 SetService. This routine is
  946. an impedance matcher to coerce data structures. It winds
  947. up calling pSapSetService2 once it has constructed the
  948. SERVICE_INFO structure.
  949. --*/
  950. {
  951. SERVICE_INFO siInfo;
  952. SERVICE_ADDRESSES ServiceAddresses;
  953. LPSERVICE_ADDRESS psa = &ServiceAddresses.Addresses[0];
  954. ServiceAddresses.dwAddressCount = 1;
  955. memset(&siInfo, 0, sizeof(siInfo));
  956. siInfo.lpServiceName = lpszServiceInstance;
  957. siInfo.lpServiceAddress = &ServiceAddresses;
  958. psa->dwAddressType = AF_IPX;
  959. psa->dwAddressFlags = psa->dwPrincipalLength = 0;
  960. psa->dwAddressLength = sizeof(SOCKADDR_IPX);
  961. psa->lpPrincipal = 0;
  962. psa->lpAddress = pbAddress;
  963. siInfo.lpServiceType = pType;
  964. return(pSapSetService(dwOperation, &siInfo, nServiceType));
  965. }
  966. DWORD
  967. pSapSetService(
  968. IN DWORD dwOperation,
  969. IN LPSERVICE_INFO lpServiceInfo,
  970. IN WORD nServiceType)
  971. /*++
  972. Routine Description:
  973. Common routine to do the SAP advertisement.
  974. --*/
  975. {
  976. DWORD err;
  977. RpcTryExcept
  978. {
  979. err = NwrSetService( NULL, dwOperation, lpServiceInfo, nServiceType );
  980. }
  981. RpcExcept(1)
  982. {
  983. err = ERROR_SERVICE_NOT_ACTIVE;
  984. #if 0
  985. DWORD code = RpcExceptionCode();
  986. if ( (code == RPC_S_SERVER_UNAVAILABLE)
  987. ||
  988. (code == RPC_S_UNKNOWN_IF) )
  989. {
  990. err = ERROR_SERVICE_NOT_ACTIVE;
  991. }
  992. else
  993. {
  994. err = NwpMapRpcError( code );
  995. }
  996. #endif
  997. }
  998. RpcEndExcept
  999. if ( err == ERROR_SERVICE_NOT_ACTIVE )
  1000. {
  1001. //
  1002. //CSNW not available, going to try use the SAP agent, else we do it ourselves
  1003. //
  1004. err = NO_ERROR;
  1005. //
  1006. // Check if all parameters passed in are valid
  1007. //
  1008. if ( wcslen( lpServiceInfo->lpServiceName ) > SAP_OBJECT_NAME_MAX_LENGTH-1 )
  1009. {
  1010. return ERROR_INVALID_PARAMETER;
  1011. }
  1012. switch ( dwOperation )
  1013. {
  1014. case SERVICE_REGISTER:
  1015. err = NwRegisterService( lpServiceInfo,
  1016. nServiceType,
  1017. NwServiceListDoneEvent );
  1018. break;
  1019. case SERVICE_DEREGISTER:
  1020. err = NwDeregisterService( lpServiceInfo, nServiceType );
  1021. break;
  1022. default: //this should never occur, but just in case . . .
  1023. err = ERROR_INVALID_PARAMETER;
  1024. break;
  1025. }
  1026. }
  1027. return err;
  1028. }
  1029. DWORD
  1030. SapFreeSapSocket(SOCKET s)
  1031. {
  1032. /*++
  1033. Routine Description:
  1034. Release the socket and clean up
  1035. --*/
  1036. DWORD err = NO_ERROR;
  1037. closesocket( s );
  1038. return(err);
  1039. }
  1040. DWORD
  1041. SapGetSapSocket(SOCKET * ps)
  1042. {
  1043. /*++
  1044. Routine Description:
  1045. Get a socket suitable for making SAP queries
  1046. Arguments: None
  1047. --*/
  1048. SOCKET socketSap;
  1049. WSADATA wsaData;
  1050. SOCKADDR_IPX socketAddr;
  1051. DWORD err = NO_ERROR;
  1052. INT nValue;
  1053. DWORD dwNonBlocking = 1;
  1054. //
  1055. // Initialize the socket interface
  1056. //
  1057. // err = WSAStartup( WSOCK_VER_REQD, &wsaData );
  1058. // if ( err )
  1059. // {
  1060. // return err;
  1061. // }
  1062. //
  1063. // Open an IPX datagram socket
  1064. //
  1065. socketSap = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
  1066. if ( socketSap == INVALID_SOCKET )
  1067. {
  1068. err = WSAGetLastError();
  1069. // (VOID) WSACleanup();
  1070. return err;
  1071. }
  1072. //
  1073. // Set the socket to non-blocking
  1074. //
  1075. if ( ioctlsocket( socketSap, FIONBIO, &dwNonBlocking ) == SOCKET_ERROR )
  1076. {
  1077. err = WSAGetLastError();
  1078. goto ErrExit;
  1079. }
  1080. //
  1081. // Allow sending of broadcasts
  1082. //
  1083. nValue = 1;
  1084. if ( setsockopt( socketSap,
  1085. SOL_SOCKET,
  1086. SO_BROADCAST,
  1087. (PVOID) &nValue,
  1088. sizeof(INT)) == SOCKET_ERROR )
  1089. {
  1090. err = WSAGetLastError();
  1091. goto ErrExit;
  1092. }
  1093. //
  1094. // Bind the socket
  1095. //
  1096. memset( &socketAddr, 0, sizeof( SOCKADDR_IPX));
  1097. socketAddr.sa_family = AF_IPX;
  1098. socketAddr.sa_socket = 0; // no specific port
  1099. if ( bind( socketSap,
  1100. (PSOCKADDR) &socketAddr,
  1101. sizeof( SOCKADDR_IPX)) == SOCKET_ERROR )
  1102. {
  1103. err = WSAGetLastError();
  1104. goto ErrExit;
  1105. }
  1106. //
  1107. // Set the extended address option
  1108. //
  1109. nValue = 1;
  1110. if ( setsockopt( socketSap, // Socket Handle
  1111. NSPROTO_IPX, // Option Level
  1112. IPX_EXTENDED_ADDRESS, // Option Name
  1113. (PUCHAR)&nValue, // Ptr to on/off flag
  1114. sizeof(INT)) == SOCKET_ERROR ) // Length of flag
  1115. {
  1116. err = WSAGetLastError();
  1117. goto ErrExit;
  1118. }
  1119. *ps = socketSap;
  1120. return(err);
  1121. ErrExit:
  1122. SapFreeSapSocket(socketSap); // cleans up lots of stuff
  1123. return(err);
  1124. }
  1125. DWORD
  1126. NwpGetAddressForRnRViaSap(
  1127. IN HANDLE hRnRHandle,
  1128. IN WORD nServiceType,
  1129. IN LPWSTR lpServiceName,
  1130. IN DWORD nProt,
  1131. IN OUT LPVOID lpCsAddrBuffer,
  1132. IN OUT LPDWORD lpdwBufferLength,
  1133. IN HANDLE hCancellationEvent,
  1134. OUT LPDWORD lpcAddress
  1135. )
  1136. {
  1137. /*++
  1138. Routine Description:
  1139. This routine uses SAP requests to find the address of the given service
  1140. name/type. It can handle looking up by type only, or by name and type.
  1141. The latter case is the same as the old RnR code, see below for
  1142. it and for a description of the arguments
  1143. --*/
  1144. return(0);
  1145. }
  1146. #define MAX_LOOPS_FOR_SAP 4
  1147. DWORD
  1148. SapGetSapForType(
  1149. PSAP_BCAST_CONTROL psbc,
  1150. WORD nServiceType)
  1151. {
  1152. /*++
  1153. Routine Description:
  1154. Does the work of send Sap queries and fetching results.
  1155. The first message sent is done according to the requester, and
  1156. may be limited to the local LAN or not.
  1157. Arguments:
  1158. psbc -- pointer to the control information
  1159. wSapType -- Sap type
  1160. --*/
  1161. SAP_REQUEST sapRequest;
  1162. UCHAR destAddr[SAP_ADDRESS_LENGTH];
  1163. DWORD startTickCount;
  1164. UCHAR recvBuffer[SAP_MAXRECV_LENGTH];
  1165. INT bytesReceived;
  1166. BOOL fFound = FALSE;
  1167. DWORD err = NO_ERROR;
  1168. sapRequest.QueryType = htons( psbc->wQueryType );
  1169. sapRequest.ServerType = htons( nServiceType );
  1170. //
  1171. // Set the address to send to
  1172. //
  1173. memcpy( destAddr, SapBroadcastAddress, SAP_ADDRESS_LENGTH );
  1174. //
  1175. // Ready to go. This might be the inital call, in which case
  1176. // we start off by sending. In all other cases, we start
  1177. // out receiving.
  1178. //
  1179. //
  1180. // In the full case,
  1181. // we will send out SAP requests 3 times and wait 1 sec for
  1182. // Sap responses the first time, 2 sec the second and 4 sec the
  1183. // third time.
  1184. //
  1185. for (; !fFound && (psbc->dwIndex < MAX_LOOPS_FOR_SAP); psbc->dwIndex++ )
  1186. {
  1187. DWORD dwRet;
  1188. DWORD dwTimeOut = (1 << psbc->dwIndex) * 1000;
  1189. if(psbc->dwTickCount)
  1190. {
  1191. dwRet = dwrcNil;
  1192. //
  1193. // Need to do some reading ...
  1194. //
  1195. do
  1196. {
  1197. PSAP_IDENT_HEADER pSap;
  1198. if((psbc->psrc->fFlags & SAP_F_END_CALLED)
  1199. ||
  1200. psbc->fCheckCancel(psbc->pvArg))
  1201. {
  1202. err = dwrcCancel;
  1203. goto CleanExit;
  1204. }
  1205. //
  1206. // Sleeps for 50 ms so that we might get something on first read
  1207. //
  1208. Sleep( 50 );
  1209. bytesReceived = recvfrom( psbc->s,
  1210. recvBuffer,
  1211. SAP_MAXRECV_LENGTH,
  1212. 0,
  1213. NULL,
  1214. NULL );
  1215. if ( bytesReceived == SOCKET_ERROR )
  1216. {
  1217. err = WSAGetLastError();
  1218. if ( err == WSAEWOULDBLOCK ) // no data on socket, continue looping
  1219. {
  1220. if(dwRet == dwrcNoWait)
  1221. {
  1222. fFound = TRUE;
  1223. }
  1224. err = NO_ERROR;
  1225. continue;
  1226. }
  1227. }
  1228. if ( ( err != NO_ERROR ) // err occurred in recvfrom
  1229. || ( bytesReceived == 0 ) // or socket closed
  1230. )
  1231. {
  1232. goto CleanExit;
  1233. }
  1234. //
  1235. // Skip over query type
  1236. //
  1237. bytesReceived -= sizeof(USHORT);
  1238. pSap = (PSAP_IDENT_HEADER) &(recvBuffer[sizeof(USHORT)]);
  1239. //
  1240. // Tell the caller we've something to look over
  1241. //
  1242. while ( bytesReceived >= sizeof( SAP_IDENT_HEADER ))
  1243. {
  1244. dwRet = psbc->Func(psbc, pSap, &err);
  1245. if((dwRet == dwrcDone)
  1246. ||
  1247. (dwRet == dwrcCancel))
  1248. {
  1249. fFound = TRUE;
  1250. break;
  1251. }
  1252. pSap++;
  1253. bytesReceived -= sizeof( SAP_IDENT_HEADER );
  1254. }
  1255. }
  1256. while ( !fFound
  1257. && ((GetTickCount() - psbc->dwTickCount) < dwTimeOut )
  1258. );
  1259. }
  1260. // Send the packet out
  1261. //
  1262. if((fFound && (dwRet == dwrcNoWait))
  1263. ||
  1264. (psbc->dwIndex == (MAX_LOOPS_FOR_SAP -1)))
  1265. {
  1266. goto CleanExit;
  1267. }
  1268. if ( sendto( psbc->s,
  1269. (PVOID) &sapRequest,
  1270. sizeof( sapRequest ),
  1271. 0,
  1272. (PSOCKADDR) destAddr,
  1273. SAP_ADDRESS_LENGTH ) == SOCKET_ERROR )
  1274. {
  1275. err = WSAGetLastError();
  1276. goto CleanExit;
  1277. }
  1278. psbc->dwTickCount = GetTickCount();
  1279. }
  1280. if(!fFound)
  1281. {
  1282. err = WSAEADDRNOTAVAIL;
  1283. }
  1284. CleanExit:
  1285. return err;
  1286. }
  1287. BOOL
  1288. NwpLookupSapInRegistry(
  1289. IN LPGUID lpServiceType,
  1290. OUT PWORD pnSapType,
  1291. OUT PWORD pwPort,
  1292. IN OUT PDWORD pfConnectionOriented
  1293. )
  1294. /*++
  1295. Routine Description:
  1296. This routine looks up the GUID in the registry under
  1297. Control\ServiceProvider\ServiceTypes and trys to read the SAP type
  1298. from the registry.
  1299. Arguments:
  1300. lpServiceType - the GUID to look for
  1301. pnSapType - on return, contains the SAP type
  1302. Return Value:
  1303. Returns FALSE if we can't get the SAP type, TRUE otherwise
  1304. --*/
  1305. {
  1306. DWORD err;
  1307. BOOL fFound = FALSE;
  1308. HKEY hkey = NULL;
  1309. HKEY hkeyServiceType = NULL;
  1310. DWORD dwIndex = 0;
  1311. WCHAR szBuffer[ MAX_PATH + 1];
  1312. DWORD dwLen;
  1313. FILETIME ftLastWrite;
  1314. //
  1315. // Open the service types key
  1316. //
  1317. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  1318. NW_SERVICE_TYPES_REGKEY,
  1319. 0,
  1320. KEY_READ,
  1321. &hkey );
  1322. if ( err )
  1323. {
  1324. // Cannot find the key because it is not created yet since no
  1325. // one called Add service type. We return FALSE indicating
  1326. // Sap type not found.
  1327. return FALSE;
  1328. }
  1329. //
  1330. // Loop through all subkey of service types to find the GUID
  1331. //
  1332. for ( dwIndex = 0; ; dwIndex++ )
  1333. {
  1334. GUID guid;
  1335. dwLen = sizeof( szBuffer ) / sizeof( WCHAR );
  1336. err = RegEnumKeyExW( hkey,
  1337. dwIndex,
  1338. szBuffer, // Buffer big enough to
  1339. // hold any key name
  1340. &dwLen, // in characters
  1341. NULL,
  1342. NULL,
  1343. NULL,
  1344. &ftLastWrite );
  1345. //
  1346. // We will break out of here on any error, this includes
  1347. // the error ERROR_NO_MORE_ITEMS which means that we have finish
  1348. // enumerating all the keys.
  1349. //
  1350. if ( err )
  1351. {
  1352. if ( err == ERROR_NO_MORE_ITEMS ) // No more to enumerate
  1353. err = NO_ERROR;
  1354. break;
  1355. }
  1356. err = RegOpenKeyExW( hkey,
  1357. szBuffer,
  1358. 0,
  1359. KEY_READ,
  1360. &hkeyServiceType );
  1361. if ( err )
  1362. break;
  1363. dwLen = sizeof( szBuffer );
  1364. err = RegQueryValueExW( hkeyServiceType,
  1365. NW_GUID_VALUE_NAME,
  1366. NULL,
  1367. NULL,
  1368. (LPBYTE) szBuffer, // Buffer big enough to
  1369. // hold any GUID
  1370. &dwLen ); // in bytes
  1371. if ( err == ERROR_FILE_NOT_FOUND )
  1372. continue; // continue with the next key
  1373. else if ( err )
  1374. break;
  1375. // Get rid of the end curly brace
  1376. szBuffer[ dwLen/sizeof(WCHAR) - 2] = 0;
  1377. err = UuidFromStringW( szBuffer + 1, // go past the first curly brace
  1378. &guid );
  1379. if ( err )
  1380. continue; // continue with the next key, err might be returned
  1381. // if buffer does not contain a valid GUID
  1382. if ( !memcmp( lpServiceType, &guid, sizeof(GUID)))
  1383. {
  1384. DWORD dwTmp;
  1385. dwLen = sizeof( dwTmp );
  1386. err = RegQueryValueExW( hkeyServiceType,
  1387. SERVICE_TYPE_VALUE_SAPID,
  1388. NULL,
  1389. NULL,
  1390. (LPBYTE) &dwTmp,
  1391. &dwLen ); // in bytes
  1392. if ( !err )
  1393. {
  1394. fFound = TRUE;
  1395. *pnSapType = (WORD) dwTmp;
  1396. if ( ARGUMENT_PRESENT( pwPort ))
  1397. {
  1398. err = RegQueryValueExW( hkeyServiceType,
  1399. L"Port",
  1400. NULL,
  1401. NULL,
  1402. (LPBYTE) &dwTmp,
  1403. &dwLen ); // in bytes
  1404. if ( !err )
  1405. {
  1406. *pwPort = (WORD)dwTmp;
  1407. }
  1408. }
  1409. if ( ARGUMENT_PRESENT( pfConnectionOriented ))
  1410. {
  1411. err = RegQueryValueExW( hkeyServiceType,
  1412. SERVICE_TYPE_VALUE_CONN,
  1413. NULL,
  1414. NULL,
  1415. (LPBYTE) &dwTmp,
  1416. &dwLen ); // in bytes
  1417. if ( !err )
  1418. *pfConnectionOriented = dwTmp? 1: 0;
  1419. }
  1420. }
  1421. else if ( err == ERROR_FILE_NOT_FOUND )
  1422. {
  1423. continue; // continue with the next key since we can't
  1424. // find Sap Id
  1425. }
  1426. break;
  1427. }
  1428. RegCloseKey( hkeyServiceType );
  1429. hkeyServiceType = NULL;
  1430. }
  1431. if ( hkeyServiceType != NULL )
  1432. RegCloseKey( hkeyServiceType );
  1433. if ( hkey != NULL )
  1434. RegCloseKey( hkey );
  1435. return fFound;
  1436. }
  1437. DWORD
  1438. NwpRnR2AddServiceType(
  1439. IN LPWSTR lpServiceTypeName,
  1440. IN LPGUID lpClassType,
  1441. IN WORD wSapId,
  1442. IN WORD wPort
  1443. )
  1444. {
  1445. HKEY hKey, hKeyService;
  1446. PWCHAR pwszUuid;
  1447. DWORD dwDisposition, err;
  1448. DWORD dwValue = (DWORD)wSapId;
  1449. WCHAR wszUuid[36 + 1 + 2]; // to hold the GUID
  1450. err = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  1451. NW_SERVICE_TYPES_REGKEY,
  1452. 0,
  1453. TEXT(""),
  1454. REG_OPTION_NON_VOLATILE,
  1455. KEY_READ | KEY_WRITE,
  1456. NULL,
  1457. &hKey,
  1458. &dwDisposition );
  1459. if(err)
  1460. {
  1461. return(GetLastError());
  1462. }
  1463. //
  1464. // Open the key corresponding to the service (create if not there).
  1465. //
  1466. err = RegCreateKeyEx(
  1467. hKey,
  1468. lpServiceTypeName,
  1469. 0,
  1470. TEXT(""),
  1471. REG_OPTION_NON_VOLATILE,
  1472. KEY_READ | KEY_WRITE,
  1473. NULL,
  1474. &hKeyService,
  1475. &dwDisposition
  1476. );
  1477. if(!err)
  1478. {
  1479. //
  1480. // ready to put the GUID value in.
  1481. //
  1482. UuidToString(
  1483. lpClassType,
  1484. &pwszUuid);
  1485. wszUuid[0] = L'{';
  1486. memcpy(&wszUuid[1], pwszUuid, 36 * sizeof(WCHAR));
  1487. wszUuid[37] = L'}';
  1488. wszUuid[38] = 0;
  1489. RpcStringFree(&pwszUuid);
  1490. //
  1491. // write it
  1492. //
  1493. err = RegSetValueEx(
  1494. hKeyService,
  1495. L"GUID",
  1496. 0,
  1497. REG_SZ,
  1498. (LPBYTE)wszUuid,
  1499. 39 * sizeof(WCHAR));
  1500. if(!err)
  1501. {
  1502. err = RegSetValueEx(
  1503. hKeyService,
  1504. L"SAPID",
  1505. 0,
  1506. REG_DWORD,
  1507. (LPBYTE)&dwValue,
  1508. sizeof(DWORD));
  1509. dwValue = (DWORD)wPort;
  1510. err = RegSetValueEx(
  1511. hKeyService,
  1512. L"PORT",
  1513. 0,
  1514. REG_DWORD,
  1515. (LPBYTE)&dwValue,
  1516. sizeof(DWORD));
  1517. }
  1518. RegCloseKey(hKeyService);
  1519. }
  1520. RegCloseKey(hKey);
  1521. if(err)
  1522. {
  1523. err = GetLastError();
  1524. }
  1525. return(err);
  1526. }
  1527. BOOL
  1528. NwpRnR2RemoveServiceType(
  1529. IN LPGUID lpServiceType
  1530. )
  1531. {
  1532. DWORD err;
  1533. BOOL fFound = FALSE;
  1534. HKEY hkey = NULL;
  1535. HKEY hkeyServiceType = NULL;
  1536. DWORD dwIndex = 0;
  1537. WCHAR szBuffer[ MAX_PATH + 1];
  1538. WCHAR szGuid[ MAX_PATH + 1];
  1539. DWORD dwLen;
  1540. FILETIME ftLastWrite;
  1541. //
  1542. // Open the service types key
  1543. //
  1544. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  1545. NW_SERVICE_TYPES_REGKEY,
  1546. 0,
  1547. KEY_READ,
  1548. &hkey );
  1549. if ( err )
  1550. {
  1551. // Cannot find the key because it is not created yet since no
  1552. // one called Add service type. We return FALSE indicating
  1553. // Sap type not found.
  1554. return FALSE;
  1555. }
  1556. //
  1557. // Loop through all subkey of service types to find the GUID
  1558. //
  1559. for ( dwIndex = 0; ; dwIndex++ )
  1560. {
  1561. GUID guid;
  1562. dwLen = sizeof( szBuffer ) / sizeof( WCHAR );
  1563. err = RegEnumKeyExW( hkey,
  1564. dwIndex,
  1565. szBuffer, // Buffer big enough to
  1566. // hold any key name
  1567. &dwLen, // in characters
  1568. NULL,
  1569. NULL,
  1570. NULL,
  1571. &ftLastWrite );
  1572. //
  1573. // We will break out of here on any error, this includes
  1574. // the error ERROR_NO_MORE_ITEMS which means that we have finish
  1575. // enumerating all the keys.
  1576. //
  1577. if ( err )
  1578. {
  1579. if ( err == ERROR_NO_MORE_ITEMS ) // No more to enumerate
  1580. err = NO_ERROR;
  1581. break;
  1582. }
  1583. err = RegOpenKeyExW( hkey,
  1584. szBuffer,
  1585. 0,
  1586. KEY_READ,
  1587. &hkeyServiceType );
  1588. if ( err )
  1589. break;
  1590. dwLen = sizeof( szGuid );
  1591. err = RegQueryValueExW( hkeyServiceType,
  1592. NW_GUID_VALUE_NAME,
  1593. NULL,
  1594. NULL,
  1595. (LPBYTE) szGuid, // Buffer big enough to
  1596. // hold any GUID
  1597. &dwLen ); // in bytes
  1598. RegCloseKey( hkeyServiceType );
  1599. hkeyServiceType = NULL;
  1600. if ( err == ERROR_FILE_NOT_FOUND )
  1601. continue; // continue with the next key
  1602. else if ( err )
  1603. break;
  1604. // Get rid of the end curly brace
  1605. szGuid[ dwLen/sizeof(WCHAR) - 2] = 0;
  1606. err = UuidFromStringW( szGuid + 1, // go past the first curly brace
  1607. &guid );
  1608. if ( err )
  1609. continue; // continue with the next key, err might be returned
  1610. // if buffer does not contain a valid GUID
  1611. if ( !memcmp( lpServiceType, &guid, sizeof(GUID)))
  1612. {
  1613. (void) RegDeleteKey( hkey, szBuffer );
  1614. fFound = TRUE;
  1615. }
  1616. }
  1617. if ( hkeyServiceType != NULL )
  1618. RegCloseKey( hkeyServiceType );
  1619. if ( hkey != NULL )
  1620. RegCloseKey( hkey );
  1621. return fFound;
  1622. }
  1623. DWORD
  1624. NwpAddServiceType(
  1625. IN LPSERVICE_INFO lpServiceInfo,
  1626. IN BOOL fUnicodeBlob
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. This routine adds a new service type and its info to the registry under
  1631. Control\ServiceProvider\ServiceTypes
  1632. Arguments:
  1633. lpServiceInfo - the ServiceSpecificInfo contains the service type info
  1634. fUnicodeBlob - TRUE if the above field contains unicode data,
  1635. FALSE otherwise
  1636. Return Value:
  1637. Win32 error
  1638. --*/
  1639. {
  1640. DWORD err;
  1641. HKEY hkey = NULL;
  1642. HKEY hkeyType = NULL;
  1643. SERVICE_TYPE_INFO *pSvcTypeInfo = (SERVICE_TYPE_INFO *)
  1644. lpServiceInfo->ServiceSpecificInfo.pBlobData;
  1645. LPWSTR pszSvcTypeName;
  1646. UNICODE_STRING uniStr;
  1647. DWORD i;
  1648. PSERVICE_TYPE_VALUE pVal;
  1649. //
  1650. // Get the new service type name
  1651. //
  1652. if ( fUnicodeBlob )
  1653. {
  1654. pszSvcTypeName = (LPWSTR) (((LPBYTE) pSvcTypeInfo) +
  1655. pSvcTypeInfo->dwTypeNameOffset );
  1656. }
  1657. else
  1658. {
  1659. ANSI_STRING ansiStr;
  1660. RtlInitAnsiString( &ansiStr,
  1661. (LPSTR) (((LPBYTE) pSvcTypeInfo) +
  1662. pSvcTypeInfo->dwTypeNameOffset ));
  1663. err = RtlAnsiStringToUnicodeString( &uniStr, &ansiStr, TRUE );
  1664. if ( err )
  1665. return err;
  1666. pszSvcTypeName = uniStr.Buffer;
  1667. }
  1668. //
  1669. // If the service type name is an empty string, return error.
  1670. //
  1671. if ( ( pSvcTypeInfo->dwTypeNameOffset == 0 )
  1672. || ( pszSvcTypeName == NULL )
  1673. || ( *pszSvcTypeName == 0 ) // empty string
  1674. )
  1675. {
  1676. err = ERROR_INVALID_PARAMETER;
  1677. goto CleanExit;
  1678. }
  1679. //
  1680. // The following keys should have already been created
  1681. //
  1682. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  1683. NW_SERVICE_TYPES_REGKEY,
  1684. 0,
  1685. KEY_READ | KEY_WRITE,
  1686. &hkey );
  1687. if ( err )
  1688. goto CleanExit;
  1689. err = RegOpenKeyExW( hkey,
  1690. pszSvcTypeName,
  1691. 0,
  1692. KEY_READ | KEY_WRITE,
  1693. &hkeyType );
  1694. if ( err )
  1695. goto CleanExit;
  1696. //
  1697. // Loop through all values in the specific and add them one by one
  1698. // to the registry if it belongs to our name space
  1699. //
  1700. for ( i = 0, pVal = pSvcTypeInfo->Values;
  1701. i < pSvcTypeInfo->dwValueCount;
  1702. i++, pVal++ )
  1703. {
  1704. if ( ! ((pVal->dwNameSpace == NS_SAP) ||
  1705. (pVal->dwNameSpace == NS_DEFAULT)) )
  1706. {
  1707. continue; // ignore values not in our name space
  1708. }
  1709. if ( fUnicodeBlob )
  1710. {
  1711. err = RegSetValueExW(
  1712. hkeyType,
  1713. (LPWSTR) ( ((LPBYTE) pSvcTypeInfo) + pVal->dwValueNameOffset),
  1714. 0,
  1715. pVal->dwValueType,
  1716. (LPBYTE) ( ((LPBYTE) pSvcTypeInfo) + pVal->dwValueOffset),
  1717. pVal->dwValueSize
  1718. );
  1719. }
  1720. else
  1721. {
  1722. err = RegSetValueExA(
  1723. hkeyType,
  1724. (LPSTR) ( ((LPBYTE) pSvcTypeInfo) + pVal->dwValueNameOffset),
  1725. 0,
  1726. pVal->dwValueType,
  1727. (LPBYTE) ( ((LPBYTE) pSvcTypeInfo) + pVal->dwValueOffset),
  1728. pVal->dwValueSize
  1729. );
  1730. }
  1731. }
  1732. CleanExit:
  1733. if ( !fUnicodeBlob )
  1734. RtlFreeUnicodeString( &uniStr );
  1735. if ( hkeyType != NULL )
  1736. RegCloseKey( hkeyType );
  1737. if ( hkey != NULL )
  1738. RegCloseKey( hkey );
  1739. return err;
  1740. }
  1741. DWORD
  1742. NwpDeleteServiceType(
  1743. IN LPSERVICE_INFO lpServiceInfo,
  1744. IN BOOL fUnicodeBlob
  1745. )
  1746. /*++
  1747. Routine Description:
  1748. This routine deletes a service type and its info from the registry under
  1749. Control\ServiceProvider\ServiceTypes
  1750. Arguments:
  1751. lpServiceInfo - the ServiceSpecificInfo contains the service type info
  1752. fUnicodeBlob - TRUE if the above field contains unicode data,
  1753. FALSE otherwise
  1754. Return Value:
  1755. Win32 error
  1756. --*/
  1757. {
  1758. DWORD err;
  1759. HKEY hkey = NULL;
  1760. SERVICE_TYPE_INFO *pSvcTypeInfo = (SERVICE_TYPE_INFO *)
  1761. lpServiceInfo->ServiceSpecificInfo.pBlobData;
  1762. LPWSTR pszSvcTypeName;
  1763. UNICODE_STRING uniStr;
  1764. //
  1765. // Get the service type name to be deleted
  1766. //
  1767. if ( fUnicodeBlob )
  1768. {
  1769. pszSvcTypeName = (LPWSTR) (((LPBYTE) pSvcTypeInfo) +
  1770. pSvcTypeInfo->dwTypeNameOffset );
  1771. }
  1772. else
  1773. {
  1774. ANSI_STRING ansiStr;
  1775. RtlInitAnsiString( &ansiStr,
  1776. (LPSTR) (((LPBYTE) pSvcTypeInfo) +
  1777. pSvcTypeInfo->dwTypeNameOffset ));
  1778. err = RtlAnsiStringToUnicodeString( &uniStr, &ansiStr, TRUE );
  1779. if ( err )
  1780. return err;
  1781. pszSvcTypeName = uniStr.Buffer;
  1782. }
  1783. //
  1784. // If the service type name is an empty string, return error.
  1785. //
  1786. if ( ( pSvcTypeInfo->dwTypeNameOffset == 0 )
  1787. || ( pszSvcTypeName == NULL )
  1788. || ( *pszSvcTypeName == 0 ) // empty string
  1789. )
  1790. {
  1791. err = ERROR_INVALID_PARAMETER;
  1792. goto CleanExit;
  1793. }
  1794. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  1795. NW_SERVICE_TYPES_REGKEY,
  1796. 0,
  1797. KEY_READ | KEY_WRITE,
  1798. &hkey );
  1799. if ( !err )
  1800. {
  1801. err = RegDeleteKey( hkey,
  1802. pszSvcTypeName );
  1803. }
  1804. if ( err == ERROR_FILE_NOT_FOUND )
  1805. {
  1806. // Perhaps before calling my provider, the router already deleted the
  1807. // this key, hence just return success;
  1808. err = NO_ERROR;
  1809. }
  1810. CleanExit:
  1811. if ( !fUnicodeBlob )
  1812. RtlFreeUnicodeString( &uniStr );
  1813. if ( hkey != NULL )
  1814. RegCloseKey( hkey );
  1815. return err;
  1816. }
  1817. #define SOCKSIZE (sizeof(SOCKADDR_IPX) + sizeof(DWORD) - 1)
  1818. DWORD
  1819. FillBufferWithCsAddr(
  1820. IN LPBYTE pAddress,
  1821. IN DWORD nProt,
  1822. IN OUT LPVOID lpCsAddrBuffer,
  1823. IN OUT LPDWORD lpdwBufferLength,
  1824. OUT LPDWORD pcAddress
  1825. )
  1826. {
  1827. DWORD nAddrCount = 0;
  1828. CSADDR_INFO *pCsAddr;
  1829. SOCKADDR_IPX *pAddrLocal, *pAddrRemote;
  1830. DWORD i;
  1831. LPBYTE pBuffer;
  1832. if ( nProt & SPXII_BIT )
  1833. nAddrCount++;
  1834. if ( nProt & IPX_BIT )
  1835. nAddrCount++;
  1836. if ( nProt & SPX_BIT )
  1837. nAddrCount++;
  1838. if ( *lpdwBufferLength <
  1839. nAddrCount * ( sizeof( CSADDR_INFO) + (2*SOCKSIZE)))
  1840. {
  1841. *lpdwBufferLength = sizeof(DWORD) -1 + (nAddrCount *
  1842. ( sizeof( CSADDR_INFO) + (2 * SOCKSIZE)));
  1843. return ERROR_INSUFFICIENT_BUFFER;
  1844. }
  1845. pBuffer = ((LPBYTE) lpCsAddrBuffer) + sizeof( CSADDR_INFO) * nAddrCount;
  1846. for ( i = 0, pCsAddr = (CSADDR_INFO *)lpCsAddrBuffer;
  1847. (i < nAddrCount) && ( nProt != 0 );
  1848. i++, pCsAddr++ )
  1849. {
  1850. if ( nProt & SPXII_BIT )
  1851. {
  1852. pCsAddr->iSocketType = SOCK_SEQPACKET;
  1853. pCsAddr->iProtocol = NSPROTO_SPXII;
  1854. nProt &= ~SPXII_BIT;
  1855. }
  1856. else if ( nProt & IPX_BIT )
  1857. {
  1858. pCsAddr->iSocketType = SOCK_DGRAM;
  1859. pCsAddr->iProtocol = NSPROTO_IPX;
  1860. nProt &= ~IPX_BIT;
  1861. }
  1862. else if ( nProt & SPX_BIT )
  1863. {
  1864. pCsAddr->iSocketType = SOCK_SEQPACKET;
  1865. pCsAddr->iProtocol = NSPROTO_SPX;
  1866. nProt &= ~SPX_BIT;
  1867. }
  1868. else
  1869. {
  1870. break;
  1871. }
  1872. pCsAddr->LocalAddr.iSockaddrLength = sizeof( SOCKADDR_IPX );
  1873. pCsAddr->RemoteAddr.iSockaddrLength = sizeof( SOCKADDR_IPX );
  1874. pCsAddr->LocalAddr.lpSockaddr =
  1875. (LPSOCKADDR) pBuffer;
  1876. pCsAddr->RemoteAddr.lpSockaddr =
  1877. (LPSOCKADDR) ( pBuffer + sizeof(SOCKADDR_IPX));
  1878. pBuffer += 2 * sizeof( SOCKADDR_IPX );
  1879. pAddrLocal = (SOCKADDR_IPX *) pCsAddr->LocalAddr.lpSockaddr;
  1880. pAddrRemote = (SOCKADDR_IPX *) pCsAddr->RemoteAddr.lpSockaddr;
  1881. pAddrLocal->sa_family = AF_IPX;
  1882. pAddrRemote->sa_family = AF_IPX;
  1883. //
  1884. // The default local sockaddr is for IPX is
  1885. // sa_family = AF_IPX and all other bytes = 0.
  1886. //
  1887. RtlZeroMemory( pAddrLocal->sa_netnum,
  1888. IPX_ADDRESS_LENGTH );
  1889. //
  1890. // If pAddress is NULL, i.e. we are doing RES_SERVICE,
  1891. // just make all bytes in remote address zero.
  1892. //
  1893. if ( pAddress == NULL )
  1894. {
  1895. RtlZeroMemory( pAddrRemote->sa_netnum,
  1896. IPX_ADDRESS_LENGTH );
  1897. }
  1898. else
  1899. {
  1900. RtlCopyMemory( pAddrRemote->sa_netnum,
  1901. pAddress,
  1902. IPX_ADDRESS_LENGTH );
  1903. }
  1904. }
  1905. *pcAddress = nAddrCount;
  1906. return NO_ERROR;
  1907. }
  1908. VOID
  1909. NwInitializeServiceProvider(
  1910. VOID
  1911. )
  1912. /*++
  1913. Routine Description:
  1914. This routine initializes the service provider.
  1915. Arguments:
  1916. None.
  1917. Return Value:
  1918. None.
  1919. --*/
  1920. {
  1921. // nothing more to do
  1922. }
  1923. VOID
  1924. NwTerminateServiceProvider(
  1925. VOID
  1926. )
  1927. /*++
  1928. Routine Description:
  1929. This routine cleans up the service provider.
  1930. Arguments:
  1931. None.
  1932. Return Value:
  1933. None.
  1934. --*/
  1935. {
  1936. PREGISTERED_SERVICE pSvc, pNext;
  1937. //
  1938. // Clean up the link list and stop sending all SAP advertise packets
  1939. //
  1940. EnterCriticalSection( &NwServiceListCriticalSection );
  1941. SetEvent( NwServiceListDoneEvent );
  1942. for ( pSvc = pServiceListHead; pSvc != NULL; pSvc = pNext )
  1943. {
  1944. pNext = pSvc->Next;
  1945. if ( pSvc->fAdvertiseBySap )
  1946. {
  1947. UNICODE_STRING uServer;
  1948. OEM_STRING oemServer;
  1949. NTSTATUS ntstatus;
  1950. RtlInitUnicodeString( &uServer, pSvc->pServiceInfo->lpServiceName );
  1951. ntstatus = RtlUnicodeStringToOemString( &oemServer, &uServer, TRUE);
  1952. if ( NT_SUCCESS( ntstatus ) )
  1953. {
  1954. (VOID) SapRemoveAdvertise( oemServer.Buffer,
  1955. pSvc->nSapType );
  1956. RtlFreeOemString( &oemServer );
  1957. }
  1958. }
  1959. (VOID) LocalFree( pSvc->pServiceInfo );
  1960. (VOID) LocalFree( pSvc );
  1961. }
  1962. LeaveCriticalSection( &NwServiceListCriticalSection );
  1963. //
  1964. // Clean up the SAP interface
  1965. //
  1966. (VOID) SapLibShutdown();
  1967. //
  1968. // Clean up the socket interface
  1969. //
  1970. if ( fInitSocket )
  1971. {
  1972. closesocket( socketSap );
  1973. // (VOID) WSACleanup();
  1974. }
  1975. }
  1976. DWORD
  1977. NwRegisterService(
  1978. IN LPSERVICE_INFO lpServiceInfo,
  1979. IN WORD nSapType,
  1980. IN HANDLE hEventHandle
  1981. )
  1982. /*++
  1983. Routine Description:
  1984. This routine registers the given service.
  1985. Arguments:
  1986. lpServiceInfo - contains the service information
  1987. nSapType - The SAP type to advertise
  1988. hEventHandle - A handle to the NwDoneEvent if this code is running in
  1989. the context of Client Services for NetWare. If this is NULL,
  1990. then CSNW is not available and this code is running in the
  1991. context of a regular executable.
  1992. Return Value:
  1993. Win32 error.
  1994. --*/
  1995. {
  1996. DWORD err = NO_ERROR;
  1997. NTSTATUS ntstatus;
  1998. DWORD i;
  1999. INT nIPX = -1;
  2000. //
  2001. // Check to see if the service address array contains IPX address,
  2002. // we will only use the first ipx address contained in the array.
  2003. //
  2004. if ( lpServiceInfo->lpServiceAddress == NULL )
  2005. return ERROR_INCORRECT_ADDRESS;
  2006. for ( i = 0; i < lpServiceInfo->lpServiceAddress->dwAddressCount; i++)
  2007. {
  2008. if ( lpServiceInfo->lpServiceAddress->Addresses[i].dwAddressType
  2009. == AF_IPX )
  2010. {
  2011. nIPX = (INT) i;
  2012. break;
  2013. }
  2014. }
  2015. //
  2016. // If we cannot find a IPX address, return error
  2017. //
  2018. if ( nIPX == -1 )
  2019. return ERROR_INCORRECT_ADDRESS;
  2020. //
  2021. // Try to deregister the service since the service might have
  2022. // been registered but not deregistered
  2023. //
  2024. err = NwDeregisterService( lpServiceInfo, nSapType );
  2025. if ( ( err != NO_ERROR ) // deregister successfully
  2026. && ( err != ERROR_SERVICE_NOT_FOUND ) // service not registered before
  2027. )
  2028. {
  2029. return err;
  2030. }
  2031. err = NO_ERROR;
  2032. //
  2033. // Try and see if SAP service can advertise the service for us.
  2034. //
  2035. ntstatus = SapLibInit();
  2036. if ( NT_SUCCESS( ntstatus ))
  2037. {
  2038. UNICODE_STRING uServer;
  2039. OEM_STRING oemServer;
  2040. INT sapRet;
  2041. BOOL fContinueLoop = FALSE;
  2042. RtlInitUnicodeString( &uServer, lpServiceInfo->lpServiceName );
  2043. ntstatus = RtlUnicodeStringToOemString( &oemServer, &uServer, TRUE );
  2044. if ( !NT_SUCCESS( ntstatus ))
  2045. return RtlNtStatusToDosError( ntstatus );
  2046. do
  2047. {
  2048. fContinueLoop = FALSE;
  2049. sapRet = SapAddAdvertise( oemServer.Buffer,
  2050. nSapType,
  2051. (LPBYTE) (((LPSOCKADDR_IPX) lpServiceInfo->lpServiceAddress->Addresses[nIPX].lpAddress)->sa_netnum),
  2052. FALSE );
  2053. switch ( sapRet )
  2054. {
  2055. case SAPRETURN_SUCCESS:
  2056. {
  2057. err = AddServiceToList( lpServiceInfo, nSapType, TRUE, nIPX );
  2058. if ( err )
  2059. (VOID) SapRemoveAdvertise( oemServer.Buffer, nSapType );
  2060. RtlFreeOemString( &oemServer );
  2061. return err;
  2062. }
  2063. case SAPRETURN_NOMEMORY:
  2064. err = ERROR_NOT_ENOUGH_MEMORY;
  2065. break;
  2066. case SAPRETURN_EXISTS:
  2067. {
  2068. //
  2069. // Someone else is already advertising the service
  2070. // directly through SAP service. Remove it and
  2071. // readvertise with the new information.
  2072. //
  2073. sapRet = SapRemoveAdvertise( oemServer.Buffer, nSapType );
  2074. switch ( sapRet )
  2075. {
  2076. case SAPRETURN_SUCCESS:
  2077. fContinueLoop = TRUE; // go thru once more
  2078. break;
  2079. case SAPRETURN_NOMEMORY:
  2080. err = ERROR_NOT_ENOUGH_MEMORY;
  2081. break;
  2082. case SAPRETURN_NOTEXIST:
  2083. case SAPRETURN_INVALIDNAME:
  2084. default: // Should not have any other errors
  2085. err = ERROR_INVALID_PARAMETER;
  2086. break;
  2087. }
  2088. break;
  2089. }
  2090. case SAPRETURN_INVALIDNAME:
  2091. err = ERROR_INVALID_PARAMETER;
  2092. break;
  2093. case SAPRETURN_DUPLICATE:
  2094. err = NO_ERROR;
  2095. break;
  2096. default: // Should not have any other errors
  2097. err = ERROR_INVALID_PARAMETER;
  2098. break;
  2099. }
  2100. } while ( fContinueLoop );
  2101. RtlFreeOemString( &oemServer );
  2102. if ( err )
  2103. {
  2104. return err;
  2105. }
  2106. }
  2107. //
  2108. // At this point, we failed to ask Sap service to advertise the
  2109. // service for us. So we advertise it ourselves.
  2110. //
  2111. if ( !fInitSocket )
  2112. {
  2113. err = NwInitializeSocket( hEventHandle );
  2114. }
  2115. if ( err == NO_ERROR )
  2116. {
  2117. err = NwAdvertiseService( lpServiceInfo->lpServiceName,
  2118. nSapType,
  2119. ((LPSOCKADDR_IPX) lpServiceInfo->lpServiceAddress->Addresses[nIPX].lpAddress),
  2120. hEventHandle );
  2121. //
  2122. // Adding the service to the list will result in a resend
  2123. // of advertising packets every 60 seconds
  2124. //
  2125. if ( err == NO_ERROR )
  2126. {
  2127. err = AddServiceToList( lpServiceInfo, nSapType, FALSE, nIPX );
  2128. }
  2129. }
  2130. return err;
  2131. }
  2132. DWORD
  2133. NwDeregisterService(
  2134. IN LPSERVICE_INFO lpServiceInfo,
  2135. IN WORD nSapType
  2136. )
  2137. /*++
  2138. Routine Description:
  2139. This routine deregisters the given service.
  2140. Arguments:
  2141. lpServiceInfo - contains the service information
  2142. nSapType - SAP type to deregister
  2143. Return Value:
  2144. Win32 error.
  2145. --*/
  2146. {
  2147. PREGISTERED_SERVICE pSvc;
  2148. //
  2149. // Check if the requested service type and name has already been registered.
  2150. // If yes, then return error.
  2151. //
  2152. pSvc = GetServiceItemFromList( nSapType, lpServiceInfo->lpServiceName );
  2153. if ( pSvc == NULL )
  2154. return ERROR_SERVICE_NOT_FOUND;
  2155. //
  2156. // If SAP service is advertising the service for us, ask
  2157. // the SAP service to stop advertising.
  2158. //
  2159. if ( pSvc->fAdvertiseBySap )
  2160. {
  2161. UNICODE_STRING uServer;
  2162. OEM_STRING oemServer;
  2163. NTSTATUS ntstatus;
  2164. INT sapRet;
  2165. RtlInitUnicodeString( &uServer, lpServiceInfo->lpServiceName );
  2166. ntstatus = RtlUnicodeStringToOemString( &oemServer, &uServer, TRUE );
  2167. if ( !NT_SUCCESS( ntstatus ) )
  2168. return RtlNtStatusToDosError( ntstatus );
  2169. sapRet = SapRemoveAdvertise( oemServer.Buffer, nSapType );
  2170. RtlFreeOemString( &oemServer );
  2171. switch ( sapRet )
  2172. {
  2173. case SAPRETURN_NOMEMORY:
  2174. return ERROR_NOT_ENOUGH_MEMORY;
  2175. case SAPRETURN_NOTEXIST:
  2176. case SAPRETURN_INVALIDNAME:
  2177. return ERROR_INVALID_PARAMETER;
  2178. case SAPRETURN_SUCCESS:
  2179. break;
  2180. // Should not have any other errors
  2181. default:
  2182. break;
  2183. }
  2184. }
  2185. //
  2186. // Remove the service item from the link list
  2187. //
  2188. RemoveServiceFromList( pSvc );
  2189. return NO_ERROR;
  2190. }
  2191. BOOL
  2192. OldRnRCheckCancel(
  2193. PVOID pvArg
  2194. )
  2195. /*++
  2196. Routine Description:
  2197. Determine if the cancel event is signaled
  2198. --*/
  2199. {
  2200. POLDRNRSAP porns = (POLDRNRSAP)pvArg;
  2201. if ((porns->hCancel) == NULL)
  2202. return(FALSE);
  2203. else if(!WaitForSingleObject(porns->hCancel, 0))
  2204. {
  2205. return(TRUE);
  2206. }
  2207. return(FALSE);
  2208. }
  2209. DWORD
  2210. OldRnRCheckSapData(
  2211. PSAP_BCAST_CONTROL psbc,
  2212. PSAP_IDENT_HEADER pSap,
  2213. PDWORD pdwErr
  2214. )
  2215. {
  2216. /*++
  2217. Routine Description:
  2218. Coroutine called when a SAP reply is recevied. This checks to see
  2219. if the reply satisfies the request.
  2220. Argument:
  2221. pvArg -- actually a pointer to an SAP_BCAST_CONTROL
  2222. --*/
  2223. POLDRNRSAP porns = (POLDRNRSAP)psbc->pvArg;
  2224. if(strcmp(porns->poem->Buffer, pSap->ServerName) == 0)
  2225. {
  2226. //
  2227. // it matches. We are done!
  2228. //
  2229. *pdwErr = FillBufferWithCsAddr(pSap->Address,
  2230. porns->nProt,
  2231. porns->lpCsAddrBuffer,
  2232. porns->lpdwBufferLength,
  2233. porns->lpcAddress);
  2234. return(dwrcDone);
  2235. }
  2236. return(dwrcNil);
  2237. }
  2238. DWORD
  2239. NwpGetAddressViaSap(
  2240. IN WORD nServiceType,
  2241. IN LPWSTR lpServiceName,
  2242. IN DWORD nProt,
  2243. IN OUT LPVOID lpCsAddrBuffer,
  2244. IN OUT LPDWORD lpdwBufferLength,
  2245. IN HANDLE hCancellationEvent,
  2246. OUT LPDWORD lpcAddress
  2247. )
  2248. /*++
  2249. Routine Description:
  2250. This routine uses SAP requests to find the address of the given service
  2251. name/type. It can handle looking up by name and type alone.
  2252. Arguments:
  2253. Handle - the RnR handle, if appropriate
  2254. nServiceType - service type
  2255. lpServiceName - unique string representing the service name
  2256. lpCsAddrBuffer - on return, will be filled with CSADDR_INFO structures
  2257. lpdwBufferLength - on input, the number of bytes contained in the buffer
  2258. pointed to by lpCsAddrBuffer. On output, the minimum number of bytes
  2259. to pass for the lpCsAddrBuffer to retrieve all the requested info
  2260. hCancellationEvent - the event which signals us to cancel the request
  2261. lpcAddress - on output, the number of CSADDR_INFO structures returned
  2262. Return Value:
  2263. Win32 error code.
  2264. --*/
  2265. {
  2266. DWORD err = NO_ERROR;
  2267. NTSTATUS ntstatus;
  2268. UNICODE_STRING UServiceName;
  2269. OEM_STRING OemServiceName;
  2270. SOCKET socketSap;
  2271. SAP_RNR_CONTEXT src;
  2272. PSAP_BCAST_CONTROL psbc = &src.u_type.sbc;
  2273. OLDRNRSAP ors;
  2274. *lpcAddress = 0;
  2275. _wcsupr( lpServiceName );
  2276. RtlInitUnicodeString( &UServiceName, lpServiceName );
  2277. ntstatus = RtlUnicodeStringToOemString( &OemServiceName,
  2278. &UServiceName,
  2279. TRUE );
  2280. if ( !NT_SUCCESS( ntstatus ))
  2281. return RtlNtStatusToDosError( ntstatus );
  2282. memset(&src, 0, sizeof(src));
  2283. err = SapGetSapSocket(&psbc->s);
  2284. if ( err )
  2285. {
  2286. RtlFreeOemString( &OemServiceName );
  2287. return err;
  2288. }
  2289. psbc->psrc = &src;
  2290. psbc->dwIndex = 0;
  2291. psbc->dwTickCount = 0;
  2292. psbc->pvArg = (PVOID)&ors;
  2293. psbc->Func = OldRnRCheckSapData;
  2294. psbc->fCheckCancel = OldRnRCheckCancel;
  2295. psbc->fFlags = 0;
  2296. psbc->wQueryType = QT_GENERAL_QUERY;
  2297. ors.poem = &OemServiceName;
  2298. ors.hCancel = hCancellationEvent,
  2299. ors.lpCsAddrBuffer = lpCsAddrBuffer;
  2300. ors.lpdwBufferLength = lpdwBufferLength;
  2301. ors.lpcAddress = lpcAddress;
  2302. ors.nProt = nProt;
  2303. err = SapGetSapForType(psbc, nServiceType);
  2304. RtlFreeOemString( &OemServiceName );
  2305. //
  2306. // Clean up the socket interface
  2307. //
  2308. (VOID)SapFreeSapSocket(psbc->s);
  2309. return err;
  2310. }
  2311. DWORD
  2312. NwGetService(
  2313. IN LPWSTR Reserved,
  2314. IN WORD nSapType,
  2315. IN LPWSTR lpServiceName,
  2316. IN DWORD dwProperties,
  2317. OUT LPBYTE lpServiceInfo,
  2318. IN DWORD dwBufferLength,
  2319. OUT LPDWORD lpdwBytesNeeded
  2320. )
  2321. /*++
  2322. Routine Description:
  2323. This routine gets the service info.
  2324. Arguments:
  2325. Reserved - unused
  2326. nSapType - SAP type
  2327. lpServiceName - service name
  2328. dwProperties - specifys the properties of the service info needed
  2329. lpServiceInfo - on output, contains the SERVICE_INFO
  2330. dwBufferLength - size of buffer pointed by lpServiceInfo
  2331. lpdwBytesNeeded - if the buffer pointed by lpServiceInfo is not large
  2332. enough, this will contain the bytes needed on output
  2333. Return Value:
  2334. Win32 error.
  2335. --*/
  2336. {
  2337. DWORD err = NO_ERROR;
  2338. DWORD nSize = sizeof(SERVICE_INFO);
  2339. PREGISTERED_SERVICE pSvc;
  2340. PSERVICE_INFO pSvcInfo = (PSERVICE_INFO) lpServiceInfo;
  2341. LPBYTE pBufferStart;
  2342. UNREFERENCED_PARAMETER( Reserved );
  2343. //
  2344. // Check if all parameters passed in are valid
  2345. //
  2346. if ( lpServiceInfo == NULL || lpServiceName == NULL ||
  2347. wcslen( lpServiceName ) > SAP_OBJECT_NAME_MAX_LENGTH-1 )
  2348. return ERROR_INVALID_PARAMETER;
  2349. pSvc = GetServiceItemFromList( nSapType, lpServiceName );
  2350. if ( pSvc == NULL )
  2351. return ERROR_SERVICE_NOT_FOUND;
  2352. //
  2353. // Calculate the size needed to return the requested info
  2354. //
  2355. if ( (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_COMMENT ))
  2356. && ( pSvc->pServiceInfo->lpComment != NULL )
  2357. )
  2358. {
  2359. nSize += ( wcslen( pSvc->pServiceInfo->lpComment) + 1) * sizeof(WCHAR);
  2360. }
  2361. if ( (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_LOCALE ))
  2362. && ( pSvc->pServiceInfo->lpLocale != NULL )
  2363. )
  2364. {
  2365. nSize += ( wcslen( pSvc->pServiceInfo->lpLocale) + 1) * sizeof(WCHAR);
  2366. }
  2367. if ( (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_MACHINE ))
  2368. && ( pSvc->pServiceInfo->lpMachineName != NULL )
  2369. )
  2370. {
  2371. nSize += ( wcslen( pSvc->pServiceInfo->lpMachineName) + 1) * sizeof(WCHAR);
  2372. }
  2373. if (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_ADDRESSES ))
  2374. {
  2375. DWORD i;
  2376. DWORD dwCount = pSvc->pServiceInfo->lpServiceAddress->dwAddressCount;
  2377. nSize = ROUND_UP_COUNT( nSize, ALIGN_QUAD );
  2378. nSize += sizeof( SERVICE_ADDRESSES );
  2379. if ( dwCount > 1 )
  2380. nSize += ( dwCount - 1 ) * sizeof( SERVICE_ADDRESS );
  2381. for ( i = 0; i < dwCount; i++ )
  2382. {
  2383. SERVICE_ADDRESS *pAddr =
  2384. &(pSvc->pServiceInfo->lpServiceAddress->Addresses[i]);
  2385. nSize = ROUND_UP_COUNT( nSize, ALIGN_QUAD );
  2386. nSize += pAddr->dwAddressLength;
  2387. nSize = ROUND_UP_COUNT( nSize, ALIGN_QUAD );
  2388. nSize += pAddr->dwPrincipalLength;
  2389. }
  2390. }
  2391. if (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_SD ))
  2392. {
  2393. nSize = ROUND_UP_COUNT( nSize, ALIGN_QUAD );
  2394. nSize += pSvc->pServiceInfo->ServiceSpecificInfo.cbSize;
  2395. }
  2396. //
  2397. // Return error if the buffer passed in is not big enough
  2398. //
  2399. if ( dwBufferLength < nSize )
  2400. {
  2401. *lpdwBytesNeeded = nSize;
  2402. return ERROR_INSUFFICIENT_BUFFER;
  2403. }
  2404. //
  2405. // Fill in all requested service info
  2406. //
  2407. memset( pSvcInfo, 0, sizeof(*pSvcInfo)); // Make all fields 0 i.e.
  2408. // all pointer fields NULL
  2409. pSvcInfo->dwDisplayHint = pSvc->pServiceInfo->dwDisplayHint;
  2410. pSvcInfo->dwVersion = pSvc->pServiceInfo->dwVersion;
  2411. pSvcInfo->dwTime = pSvc->pServiceInfo->dwTime;
  2412. pBufferStart = ((LPBYTE) pSvcInfo) + sizeof( *pSvcInfo );
  2413. if ( (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_COMMENT ))
  2414. && ( pSvc->pServiceInfo->lpComment != NULL )
  2415. )
  2416. {
  2417. pSvcInfo->lpComment = (LPWSTR) pBufferStart;
  2418. wcscpy( pSvcInfo->lpComment, pSvc->pServiceInfo->lpComment );
  2419. pBufferStart += ( wcslen( pSvcInfo->lpComment ) + 1) * sizeof(WCHAR);
  2420. pSvcInfo->lpComment = (LPWSTR) ((LPBYTE) pSvcInfo->lpComment - lpServiceInfo );
  2421. }
  2422. if ( (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_LOCALE ))
  2423. && ( pSvc->pServiceInfo->lpLocale != NULL )
  2424. )
  2425. {
  2426. pSvcInfo->lpLocale = (LPWSTR) pBufferStart;
  2427. wcscpy( pSvcInfo->lpLocale, pSvc->pServiceInfo->lpLocale );
  2428. pBufferStart += ( wcslen( pSvcInfo->lpLocale ) + 1) * sizeof(WCHAR);
  2429. pSvcInfo->lpLocale = (LPWSTR) ((LPBYTE) pSvcInfo->lpLocale - lpServiceInfo);
  2430. }
  2431. if ( (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_MACHINE ))
  2432. && ( pSvc->pServiceInfo->lpMachineName != NULL )
  2433. )
  2434. {
  2435. pSvcInfo->lpMachineName = (LPWSTR) pBufferStart;
  2436. wcscpy( pSvcInfo->lpMachineName, pSvc->pServiceInfo->lpMachineName );
  2437. pBufferStart += ( wcslen( pSvcInfo->lpMachineName) + 1) * sizeof(WCHAR);
  2438. pSvcInfo->lpMachineName = (LPWSTR) ((LPBYTE) pSvcInfo->lpMachineName -
  2439. lpServiceInfo );
  2440. }
  2441. if (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_ADDRESSES ))
  2442. {
  2443. DWORD i, dwCount, dwLen;
  2444. pBufferStart = ROUND_UP_POINTER( pBufferStart, ALIGN_QUAD );
  2445. pSvcInfo->lpServiceAddress = (LPSERVICE_ADDRESSES) pBufferStart;
  2446. dwCount = pSvcInfo->lpServiceAddress->dwAddressCount =
  2447. pSvc->pServiceInfo->lpServiceAddress->dwAddressCount;
  2448. pBufferStart += sizeof( SERVICE_ADDRESSES );
  2449. for ( i = 0; i < dwCount; i++ )
  2450. {
  2451. SERVICE_ADDRESS *pTmpAddr =
  2452. &( pSvcInfo->lpServiceAddress->Addresses[i]);
  2453. SERVICE_ADDRESS *pAddr =
  2454. &( pSvc->pServiceInfo->lpServiceAddress->Addresses[i]);
  2455. pTmpAddr->dwAddressType = pAddr->dwAddressType;
  2456. pTmpAddr->dwAddressFlags = pAddr->dwAddressFlags;
  2457. //
  2458. // setup Address
  2459. //
  2460. pBufferStart = ROUND_UP_POINTER( pBufferStart, ALIGN_QUAD );
  2461. pTmpAddr->lpAddress = (LPBYTE) ( pBufferStart - lpServiceInfo );
  2462. pTmpAddr->dwAddressLength = pAddr->dwAddressLength;
  2463. memcpy( pBufferStart, pAddr->lpAddress, pAddr->dwAddressLength );
  2464. pBufferStart += pAddr->dwAddressLength;
  2465. //
  2466. // setup Principal
  2467. //
  2468. pBufferStart = ROUND_UP_POINTER( pBufferStart, ALIGN_QUAD );
  2469. pTmpAddr->lpPrincipal = (LPBYTE) ( pBufferStart - lpServiceInfo );
  2470. pTmpAddr->dwPrincipalLength = pAddr->dwPrincipalLength;
  2471. memcpy(pBufferStart, pAddr->lpPrincipal, pAddr->dwPrincipalLength );
  2472. pBufferStart += pAddr->dwPrincipalLength;
  2473. }
  2474. pSvcInfo->lpServiceAddress = (LPSERVICE_ADDRESSES)
  2475. ((LPBYTE) pSvcInfo->lpServiceAddress - lpServiceInfo);
  2476. }
  2477. if (( dwProperties == PROP_ALL ) || ( dwProperties & PROP_SD ))
  2478. {
  2479. pBufferStart = ROUND_UP_POINTER( pBufferStart, ALIGN_QUAD );
  2480. pSvcInfo->ServiceSpecificInfo.cbSize =
  2481. pSvc->pServiceInfo->ServiceSpecificInfo.cbSize;
  2482. pSvcInfo->ServiceSpecificInfo.pBlobData = pBufferStart;
  2483. RtlCopyMemory( pSvcInfo->ServiceSpecificInfo.pBlobData,
  2484. pSvc->pServiceInfo->ServiceSpecificInfo.pBlobData,
  2485. pSvcInfo->ServiceSpecificInfo.cbSize );
  2486. pSvcInfo->ServiceSpecificInfo.pBlobData =
  2487. (LPBYTE) ( pSvcInfo->ServiceSpecificInfo.pBlobData - lpServiceInfo);
  2488. }
  2489. return NO_ERROR;
  2490. }
  2491. DWORD
  2492. NwInitializeSocket(
  2493. IN HANDLE hEventHandle
  2494. )
  2495. /*++
  2496. Routine Description:
  2497. This routine initializes the socket needed for us to do the
  2498. SAP advertise ourselves.
  2499. Arguments:
  2500. hEventHandle - A handle to the NwDoneEvent if this code is running in
  2501. the context of a service. Otherwise this code is running
  2502. in the context of a regular executable.
  2503. Return Value:
  2504. Win32 error.
  2505. --*/
  2506. {
  2507. DWORD err = NO_ERROR;
  2508. WSADATA wsaData;
  2509. SOCKADDR_IPX socketAddr;
  2510. INT nValue;
  2511. HANDLE hThread;
  2512. DWORD dwThreadId;
  2513. if ( fInitSocket )
  2514. return NO_ERROR;
  2515. //
  2516. // Initialize the socket interface
  2517. //
  2518. // err = WSAStartup( WSOCK_VER_REQD, &wsaData );
  2519. // if ( err )
  2520. // return err;
  2521. //
  2522. // Open an IPX datagram socket
  2523. //
  2524. socketSap = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
  2525. if ( socketSap == INVALID_SOCKET )
  2526. return WSAGetLastError();
  2527. //
  2528. // Allow sending of broadcasts
  2529. //
  2530. nValue = 1;
  2531. if ( setsockopt( socketSap,
  2532. SOL_SOCKET,
  2533. SO_BROADCAST,
  2534. (PVOID) &nValue,
  2535. sizeof(INT)) == SOCKET_ERROR )
  2536. {
  2537. err = WSAGetLastError();
  2538. goto CleanExit;
  2539. }
  2540. //
  2541. // Bind the socket
  2542. //
  2543. memset( &socketAddr, 0, sizeof( SOCKADDR_IPX));
  2544. socketAddr.sa_family = AF_IPX;
  2545. socketAddr.sa_socket = 0; // no specific port
  2546. if ( bind( socketSap,
  2547. (PSOCKADDR) &socketAddr,
  2548. sizeof( SOCKADDR_IPX)) == SOCKET_ERROR )
  2549. {
  2550. err = WSAGetLastError();
  2551. goto CleanExit;
  2552. }
  2553. //
  2554. // Set the extended address option
  2555. //
  2556. nValue = 1;
  2557. if ( setsockopt( socketSap, // Socket Handle
  2558. NSPROTO_IPX, // Option Level
  2559. IPX_EXTENDED_ADDRESS, // Option Name
  2560. (PUCHAR)&nValue, // Ptr to on/off flag
  2561. sizeof(INT)) == SOCKET_ERROR ) // Length of flag
  2562. {
  2563. err = WSAGetLastError();
  2564. goto CleanExit;
  2565. }
  2566. //
  2567. // tommye - MS bug 98946
  2568. // Load ourselves to increment the ref count. This is a fix
  2569. // for a bug where we would exit, then the SapFunc would wake
  2570. // up and AV because we were no more.
  2571. //
  2572. hThisDll = LoadLibrary(L"nwprovau.dll");
  2573. //
  2574. // Create the thread that loops through the registered service
  2575. // link list and send out SAP advertise packets for each one of them
  2576. //
  2577. hThread = CreateThread( NULL, // no security attributes
  2578. 0, // default stack size
  2579. SapFunc, // thread function
  2580. hEventHandle, // argument to SapFunc
  2581. 0, // default creation flags
  2582. &dwThreadId );
  2583. if ( hThread == NULL )
  2584. {
  2585. err = GetLastError();
  2586. goto CleanExit;
  2587. }
  2588. fInitSocket = TRUE;
  2589. CleanExit:
  2590. if ( err )
  2591. closesocket( socketSap );
  2592. return err;
  2593. }
  2594. DWORD
  2595. NwAdvertiseService(
  2596. IN LPWSTR lpServiceName,
  2597. IN WORD nSapType,
  2598. IN LPSOCKADDR_IPX pAddr,
  2599. IN HANDLE hEventHandle
  2600. )
  2601. /*++
  2602. Routine Description:
  2603. This routine sends out SAP identification packets for the
  2604. given service name and type.
  2605. Arguments:
  2606. lpServiceName - unique string representing the service name
  2607. nSapType - SAP type
  2608. pAddr - address of the service
  2609. hEventHandle - A handle to the NwDoneEvent if this code is running in
  2610. the context of a service. Otherwise this code is running
  2611. in the context of a regular executable.
  2612. Return Value:
  2613. Win32 error.
  2614. --*/
  2615. {
  2616. NTSTATUS ntstatus;
  2617. UNICODE_STRING uServiceName;
  2618. OEM_STRING oemServiceName;
  2619. SAP_IDENT_HEADER_EX sapIdent;
  2620. UCHAR destAddr[SAP_ADDRESS_LENGTH];
  2621. PSOCKADDR_IPX pAddrTmp = pAddr;
  2622. SOCKADDR_IPX newAddr;
  2623. SOCKADDR_IPX bindAddr;
  2624. DWORD len = sizeof( SOCKADDR_IPX );
  2625. DWORD getsockname_rc ;
  2626. if ( !fInitSocket )
  2627. {
  2628. DWORD err = NwInitializeSocket( hEventHandle );
  2629. if ( err )
  2630. return err;
  2631. }
  2632. //
  2633. // get local addressing info. we are only interested in the net number.
  2634. //
  2635. getsockname_rc = getsockname( socketSap,
  2636. (PSOCKADDR) &bindAddr,
  2637. &len );
  2638. //
  2639. // Convert the service name to OEM string
  2640. //
  2641. RtlInitUnicodeString( &uServiceName, lpServiceName );
  2642. ntstatus = RtlUnicodeStringToOemString( &oemServiceName,
  2643. &uServiceName,
  2644. TRUE );
  2645. if ( !NT_SUCCESS( ntstatus ))
  2646. return RtlNtStatusToDosError( ntstatus );
  2647. _strupr( (LPSTR) oemServiceName.Buffer );
  2648. if ( !memcmp( pAddr->sa_netnum,
  2649. "\x00\x00\x00\x00",
  2650. IPX_ADDRESS_NETNUM_LENGTH ))
  2651. {
  2652. if ( getsockname_rc != SOCKET_ERROR )
  2653. {
  2654. // copy the ipx address to advertise
  2655. memcpy( &newAddr,
  2656. pAddr,
  2657. sizeof( SOCKADDR_IPX));
  2658. // replace the net number with the correct one
  2659. memcpy( &(newAddr.sa_netnum),
  2660. &(bindAddr.sa_netnum),
  2661. IPX_ADDRESS_NETNUM_LENGTH );
  2662. pAddrTmp = &newAddr;
  2663. }
  2664. }
  2665. //
  2666. // Format the SAP identification packet
  2667. //
  2668. sapIdent.ResponseType = htons( 2 );
  2669. sapIdent.ServerType = htons( nSapType );
  2670. memset( sapIdent.ServerName, '\0', SAP_OBJECT_NAME_MAX_LENGTH );
  2671. strcpy( sapIdent.ServerName, oemServiceName.Buffer );
  2672. RtlCopyMemory( sapIdent.Address, pAddrTmp->sa_netnum, IPX_ADDRESS_LENGTH );
  2673. sapIdent.HopCount = htons( 1 );
  2674. RtlFreeOemString( &oemServiceName );
  2675. //
  2676. // Set the address to send to
  2677. //
  2678. memcpy( destAddr, SapBroadcastAddress, SAP_ADDRESS_LENGTH );
  2679. if ( getsockname_rc != SOCKET_ERROR )
  2680. {
  2681. LPSOCKADDR_IPX newDestAddr = (LPSOCKADDR_IPX)destAddr ;
  2682. //
  2683. // replace the net number with the correct one
  2684. //
  2685. memcpy( &(newDestAddr->sa_netnum),
  2686. &(bindAddr.sa_netnum),
  2687. IPX_ADDRESS_NETNUM_LENGTH );
  2688. }
  2689. //
  2690. // Send the packet out
  2691. //
  2692. if ( sendto( socketSap,
  2693. (PVOID) &sapIdent,
  2694. sizeof( sapIdent ),
  2695. 0,
  2696. (PSOCKADDR) destAddr,
  2697. SAP_ADDRESS_LENGTH ) == SOCKET_ERROR )
  2698. {
  2699. return WSAGetLastError();
  2700. }
  2701. return NO_ERROR;
  2702. }
  2703. DWORD
  2704. AddServiceToList(
  2705. IN LPSERVICE_INFO lpServiceInfo,
  2706. IN WORD nSapType,
  2707. IN BOOL fAdvertiseBySap,
  2708. IN INT nIndexIPXAddress
  2709. )
  2710. /*++
  2711. Routine Description:
  2712. This routine adds the service to the link list of services
  2713. we advertised.
  2714. Arguments:
  2715. lpServiceInfo - service information
  2716. nSapType - SAP type
  2717. fAdvertiseBySap - TRUE if this service is advertised by SAP service,
  2718. FALSE if we are advertising ourselves.
  2719. nIndexIPXAddress - index of the ipx address
  2720. Return Value:
  2721. Win32 error.
  2722. --*/
  2723. {
  2724. PREGISTERED_SERVICE pSvcNew;
  2725. PSERVICE_INFO pSI;
  2726. LPBYTE pBufferStart;
  2727. DWORD nSize = 0;
  2728. //
  2729. // Allocate a new entry for the service list
  2730. //
  2731. pSvcNew = LocalAlloc( LMEM_ZEROINIT, sizeof( REGISTERED_SERVICE ));
  2732. if ( pSvcNew == NULL )
  2733. return ERROR_NOT_ENOUGH_MEMORY;
  2734. //
  2735. // Calculate the size needed for the SERVICE_INFO structure
  2736. //
  2737. nSize = sizeof( *lpServiceInfo)
  2738. + sizeof( *(lpServiceInfo->lpServiceType));
  2739. if ( lpServiceInfo->lpServiceName != NULL )
  2740. nSize += ( wcslen( lpServiceInfo->lpServiceName) + 1) * sizeof(WCHAR);
  2741. if ( lpServiceInfo->lpComment != NULL )
  2742. nSize += ( wcslen( lpServiceInfo->lpComment) + 1) * sizeof(WCHAR);
  2743. if ( lpServiceInfo->lpLocale != NULL )
  2744. nSize += ( wcslen( lpServiceInfo->lpLocale) + 1) * sizeof(WCHAR);
  2745. if ( lpServiceInfo->lpMachineName != NULL )
  2746. nSize += ( wcslen( lpServiceInfo->lpMachineName) + 1) * sizeof(WCHAR);
  2747. nSize = ROUND_UP_COUNT( nSize, ALIGN_QUAD );
  2748. if ( lpServiceInfo->lpServiceAddress != NULL )
  2749. {
  2750. nSize += sizeof( SERVICE_ADDRESSES );
  2751. nSize = ROUND_UP_COUNT( nSize, ALIGN_QUAD );
  2752. nSize += lpServiceInfo->lpServiceAddress->Addresses[nIndexIPXAddress].dwAddressLength;
  2753. nSize = ROUND_UP_COUNT( nSize, ALIGN_QUAD );
  2754. nSize += lpServiceInfo->lpServiceAddress->Addresses[nIndexIPXAddress].dwPrincipalLength;
  2755. nSize = ROUND_UP_COUNT( nSize, ALIGN_QUAD );
  2756. }
  2757. nSize += lpServiceInfo->ServiceSpecificInfo.cbSize ;
  2758. //
  2759. // Allocate a SERVICE_INFO structure for the new list entry
  2760. //
  2761. pSI = LocalAlloc( LMEM_ZEROINIT, nSize );
  2762. if ( pSI == NULL )
  2763. {
  2764. LocalFree( pSvcNew );
  2765. return ERROR_NOT_ENOUGH_MEMORY;
  2766. }
  2767. //
  2768. // Copy the information of SERVICE_INFO into list entry
  2769. //
  2770. *pSI = *lpServiceInfo;
  2771. pBufferStart = (( (LPBYTE) pSI) + sizeof( *lpServiceInfo ));
  2772. pSI->lpServiceType = (LPGUID) pBufferStart;
  2773. *(pSI->lpServiceType) = *(lpServiceInfo->lpServiceType);
  2774. pBufferStart += sizeof( *(lpServiceInfo->lpServiceType) );
  2775. if ( lpServiceInfo->lpServiceName != NULL )
  2776. {
  2777. pSI->lpServiceName = (LPWSTR) pBufferStart;
  2778. wcscpy( pSI->lpServiceName, lpServiceInfo->lpServiceName );
  2779. _wcsupr( pSI->lpServiceName );
  2780. pBufferStart += ( wcslen( lpServiceInfo->lpServiceName ) + 1 )
  2781. * sizeof(WCHAR);
  2782. }
  2783. if ( lpServiceInfo->lpComment != NULL )
  2784. {
  2785. pSI->lpComment = (LPWSTR) pBufferStart;
  2786. wcscpy( pSI->lpComment, lpServiceInfo->lpComment );
  2787. pBufferStart += ( wcslen( lpServiceInfo->lpComment ) + 1 )
  2788. * sizeof(WCHAR);
  2789. }
  2790. if ( lpServiceInfo->lpLocale != NULL )
  2791. {
  2792. pSI->lpLocale = (LPWSTR) pBufferStart;
  2793. wcscpy( pSI->lpLocale, lpServiceInfo->lpLocale );
  2794. pBufferStart += ( wcslen( lpServiceInfo->lpLocale ) + 1 )
  2795. * sizeof(WCHAR);
  2796. }
  2797. if ( lpServiceInfo->lpMachineName != NULL )
  2798. {
  2799. pSI->lpMachineName = (LPWSTR) pBufferStart;
  2800. wcscpy( pSI->lpMachineName, lpServiceInfo->lpMachineName );
  2801. pBufferStart += (wcslen( lpServiceInfo->lpMachineName ) + 1)
  2802. * sizeof(WCHAR);
  2803. }
  2804. pBufferStart = ROUND_UP_POINTER( pBufferStart, ALIGN_QUAD) ;
  2805. if ( lpServiceInfo->lpServiceAddress != NULL )
  2806. {
  2807. DWORD nSize;
  2808. pSI->lpServiceAddress = (LPSERVICE_ADDRESSES) pBufferStart;
  2809. pSI->lpServiceAddress->dwAddressCount = 1; // Just 1 IPX address
  2810. memcpy( &(pSI->lpServiceAddress->Addresses[0]),
  2811. &(lpServiceInfo->lpServiceAddress->Addresses[nIndexIPXAddress]),
  2812. sizeof( SERVICE_ADDRESS) );
  2813. pBufferStart += sizeof( SERVICE_ADDRESSES);
  2814. pBufferStart = ROUND_UP_POINTER( pBufferStart, ALIGN_QUAD) ;
  2815. nSize = pSI->lpServiceAddress->Addresses[0].dwAddressLength;
  2816. pSI->lpServiceAddress->Addresses[0].lpAddress = pBufferStart;
  2817. memcpy( pBufferStart,
  2818. lpServiceInfo->lpServiceAddress->Addresses[nIndexIPXAddress].lpAddress,
  2819. nSize );
  2820. pBufferStart += nSize;
  2821. pBufferStart = ROUND_UP_POINTER( pBufferStart, ALIGN_QUAD) ;
  2822. nSize = pSI->lpServiceAddress->Addresses[0].dwPrincipalLength;
  2823. pSI->lpServiceAddress->Addresses[0].lpPrincipal = pBufferStart;
  2824. memcpy( pBufferStart,
  2825. lpServiceInfo->lpServiceAddress->Addresses[nIndexIPXAddress].lpPrincipal,
  2826. nSize );
  2827. pBufferStart += nSize;
  2828. pBufferStart = ROUND_UP_POINTER( pBufferStart, ALIGN_QUAD) ;
  2829. }
  2830. pSI->ServiceSpecificInfo.pBlobData = pBufferStart;
  2831. RtlCopyMemory( pSI->ServiceSpecificInfo.pBlobData,
  2832. lpServiceInfo->ServiceSpecificInfo.pBlobData,
  2833. pSI->ServiceSpecificInfo.cbSize );
  2834. //
  2835. // Fill in the data in the list entry
  2836. //
  2837. pSvcNew->nSapType = nSapType;
  2838. pSvcNew->fAdvertiseBySap = fAdvertiseBySap;
  2839. pSvcNew->Next = NULL;
  2840. pSvcNew->pServiceInfo = pSI;
  2841. //
  2842. // Add the newly created list entry into the service list
  2843. //
  2844. EnterCriticalSection( &NwServiceListCriticalSection );
  2845. if ( pServiceListHead == NULL )
  2846. pServiceListHead = pSvcNew;
  2847. else
  2848. pServiceListTail->Next = pSvcNew;
  2849. pServiceListTail = pSvcNew;
  2850. LeaveCriticalSection( &NwServiceListCriticalSection );
  2851. return NO_ERROR;
  2852. }
  2853. VOID
  2854. RemoveServiceFromList(
  2855. PREGISTERED_SERVICE pSvc
  2856. )
  2857. /*++
  2858. Routine Description:
  2859. This routine removes the service from the link list of services
  2860. we advertised.
  2861. Arguments:
  2862. pSvc - the registered service node to remove
  2863. Return Value:
  2864. None.
  2865. --*/
  2866. {
  2867. PREGISTERED_SERVICE pCur, pPrev;
  2868. EnterCriticalSection( &NwServiceListCriticalSection );
  2869. for ( pCur = pServiceListHead, pPrev = NULL ; pCur != NULL;
  2870. pPrev = pCur, pCur = pCur->Next )
  2871. {
  2872. if ( pCur == pSvc )
  2873. {
  2874. if ( pPrev == NULL ) // i.e. pCur == pSvc == pServiceListHead
  2875. {
  2876. pServiceListHead = pSvc->Next;
  2877. if ( pServiceListTail == pSvc )
  2878. pServiceListTail = NULL;
  2879. }
  2880. else
  2881. {
  2882. pPrev->Next = pSvc->Next;
  2883. if ( pServiceListTail == pSvc )
  2884. pServiceListTail = pPrev;
  2885. }
  2886. (VOID) LocalFree( pCur->pServiceInfo );
  2887. (VOID) LocalFree( pCur );
  2888. break;
  2889. }
  2890. }
  2891. LeaveCriticalSection( &NwServiceListCriticalSection );
  2892. }
  2893. PREGISTERED_SERVICE
  2894. GetServiceItemFromList(
  2895. IN WORD nSapType,
  2896. IN LPWSTR pServiceName
  2897. )
  2898. /*++
  2899. Routine Description:
  2900. This routine returns the registered service node with the given
  2901. service name and type.
  2902. Arguments:
  2903. nSapType - SAP type
  2904. pServiceName - service name
  2905. Return Value:
  2906. Returns the pointer to the registered service node,
  2907. NULL if we cannot find the service type/name.
  2908. --*/
  2909. {
  2910. PREGISTERED_SERVICE pSvc;
  2911. EnterCriticalSection( &NwServiceListCriticalSection );
  2912. for ( pSvc = pServiceListHead; pSvc != NULL; pSvc = pSvc->Next )
  2913. {
  2914. if ( ( pSvc->nSapType == nSapType )
  2915. && ( _wcsicmp( pSvc->pServiceInfo->lpServiceName, pServiceName ) == 0)
  2916. )
  2917. {
  2918. LeaveCriticalSection( &NwServiceListCriticalSection );
  2919. return pSvc;
  2920. }
  2921. }
  2922. LeaveCriticalSection( &NwServiceListCriticalSection );
  2923. return NULL;
  2924. }
  2925. DWORD
  2926. SapFunc(
  2927. HANDLE hEventHandle
  2928. )
  2929. /*++
  2930. Routine Description:
  2931. This routine is a separate thread that wakes up every 60 seconds
  2932. and advertise all the service contained in the service link list
  2933. that are not advertised by the SAP service.
  2934. Arguments:
  2935. hEventHandle - used to notify thread that server is stopping
  2936. Return Value:
  2937. Win32 error.
  2938. --*/
  2939. {
  2940. DWORD err = NO_ERROR;
  2941. //
  2942. // This thread loops until the service is shut down or when some error
  2943. // occurred in WaitForSingleObject
  2944. //
  2945. while ( TRUE )
  2946. {
  2947. DWORD rc;
  2948. if ( hEventHandle != NULL )
  2949. {
  2950. rc = WaitForSingleObject( hEventHandle, SAP_ADVERTISE_FREQUENCY );
  2951. }
  2952. else
  2953. {
  2954. // Sleep( SAP_ADVERTISE_FREQUENCY );
  2955. // rc = WAIT_TIMEOUT;
  2956. return ERROR_INVALID_PARAMETER;
  2957. }
  2958. if ( rc == WAIT_FAILED )
  2959. {
  2960. err = GetLastError();
  2961. break;
  2962. }
  2963. else if ( rc == WAIT_OBJECT_0 )
  2964. {
  2965. //
  2966. // The service is stopping, break out of the loop and
  2967. // return, thus terminating the thread
  2968. //
  2969. break;
  2970. }
  2971. else if ( rc == WAIT_TIMEOUT )
  2972. {
  2973. PREGISTERED_SERVICE pSvc;
  2974. SOCKADDR_IPX bindAddr;
  2975. DWORD fGetAddr;
  2976. fGetAddr = FALSE;
  2977. //
  2978. // Time out occurred, time to send the SAP advertise packets
  2979. //
  2980. EnterCriticalSection( &NwServiceListCriticalSection );
  2981. if ( pServiceListHead == NULL )
  2982. {
  2983. LeaveCriticalSection( &NwServiceListCriticalSection );
  2984. //
  2985. // Clean up the SAP interface
  2986. //
  2987. (VOID) SapLibShutdown();
  2988. //
  2989. // Clean up the socket interface
  2990. //
  2991. if ( fInitSocket )
  2992. {
  2993. closesocket( socketSap );
  2994. // (VOID) WSACleanup();
  2995. }
  2996. break;
  2997. }
  2998. for ( pSvc = pServiceListHead; pSvc != NULL; pSvc = pSvc->Next )
  2999. {
  3000. if ( !pSvc->fAdvertiseBySap )
  3001. {
  3002. //
  3003. // Ignore the error since we can't return
  3004. // nor pop up the error
  3005. //
  3006. SOCKADDR_IPX *pAddr = (SOCKADDR_IPX *)
  3007. pSvc->pServiceInfo->lpServiceAddress->Addresses[0].lpAddress;
  3008. SOCKADDR_IPX *pAddrToAdvertise = pAddr;
  3009. SOCKADDR_IPX newAddr;
  3010. if ( !memcmp( pAddr->sa_netnum,
  3011. "\x00\x00\x00\x00",
  3012. IPX_ADDRESS_NETNUM_LENGTH ))
  3013. {
  3014. if ( !fGetAddr )
  3015. {
  3016. DWORD len = sizeof( SOCKADDR_IPX );
  3017. rc = getsockname( socketSap,
  3018. (PSOCKADDR) &bindAddr,
  3019. &len );
  3020. if ( rc != SOCKET_ERROR )
  3021. fGetAddr = TRUE;
  3022. }
  3023. if ( fGetAddr )
  3024. {
  3025. // copy the ipx address to advertise
  3026. memcpy( &newAddr,
  3027. pAddr,
  3028. sizeof( SOCKADDR_IPX));
  3029. // replace the net number with the correct one
  3030. memcpy( &(newAddr.sa_netnum),
  3031. &(bindAddr.sa_netnum),
  3032. IPX_ADDRESS_NETNUM_LENGTH );
  3033. pAddr = &newAddr;
  3034. }
  3035. }
  3036. (VOID) NwAdvertiseService(
  3037. pSvc->pServiceInfo->lpServiceName,
  3038. pSvc->nSapType,
  3039. pAddr,
  3040. hEventHandle );
  3041. }
  3042. }
  3043. LeaveCriticalSection( &NwServiceListCriticalSection );
  3044. }
  3045. }
  3046. //
  3047. // tommye - Part of the bug fix above in NwInitializeSocket.
  3048. // This will deref the DLL that we loaded so that we don't
  3049. // unload out from under ourselves.
  3050. //
  3051. FreeLibraryAndExitThread(hThisDll, err);
  3052. return err;
  3053. }