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

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