Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

841 lines
17 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. sensapi.cxx
  5. Abstract:
  6. Implementation of the SENS Connectivity APIs. These are just stubs
  7. which call into SENS to do the actual work.
  8. Author:
  9. Gopal Parupudi <GopalP>
  10. [Notes:]
  11. optional-notes
  12. Revision History:
  13. GopalP 12/4/1997 Start.
  14. --*/
  15. #include <common.hxx>
  16. #include <windows.h>
  17. #include <api.h>
  18. #include <sensapi.h>
  19. #include <sensapi.hxx>
  20. #include <cache.hxx>
  21. //
  22. // Globals
  23. //
  24. RPC_BINDING_HANDLE ghSens;
  25. CRITICAL_SECTION gSensapiLock;
  26. DWORD gdwCacheLastUpdatedTime;
  27. DWORD gdwCacheFirstReadTime;
  28. HANDLE ghSensFileMap;
  29. PSENS_CACHE gpSensCache;
  30. BOOL
  31. IsNetworkAlive(
  32. OUT LPDWORD lpdwFlags
  33. )
  34. /*++
  35. Routine Description:
  36. We try to find out if this machine has any network connectivity.
  37. Arguments:
  38. lpdwFlags - Receives information regarding the nature of the machine's
  39. network connectivity. It can be on of the following:
  40. o NETWORK_ALIVE_WAN
  41. o NETWORK_ALIVE_LAN
  42. Notes:
  43. a. This is available only for TCP/IP
  44. b. This API does not generate any Network traffic.
  45. Return Value:
  46. TRUE, if there is network connectivity
  47. FALSE, otherwise. Use GetLastError() to retrieve more error information.
  48. --*/
  49. {
  50. BOOL bNetState;
  51. RPC_STATUS RpcStatus;
  52. DWORD fNetNature;
  53. DWORD dwLastError;
  54. // Basic parameter checks
  55. if (lpdwFlags == NULL)
  56. {
  57. SetLastError(ERROR_INVALID_PARAMETER);
  58. return FALSE;
  59. }
  60. // OUT parameter intialization.
  61. *lpdwFlags = 0x0;
  62. fNetNature = 0x0;
  63. dwLastError = ERROR_SUCCESS;
  64. bNetState = FALSE;
  65. if (TRUE == ReadConnectivityCache(lpdwFlags))
  66. {
  67. return TRUE;
  68. }
  69. //
  70. // Need to contact SENS for information.
  71. //
  72. RpcStatus = DoRpcSetup();
  73. //
  74. // Try to get the state information.
  75. //
  76. if (RPC_S_OK == RpcStatus)
  77. {
  78. RpcStatus = RPC_IsNetworkAlive(
  79. ghSens,
  80. &fNetNature,
  81. &bNetState,
  82. &dwLastError
  83. );
  84. }
  85. if ( (RPC_S_OK != RpcStatus)
  86. || (RPC_S_SERVER_UNAVAILABLE == dwLastError))
  87. {
  88. //
  89. // An RPC failure occurred. We treat this as a success and
  90. // set to return values to default values.
  91. //
  92. bNetState = TRUE;
  93. fNetNature = NETWORK_ALIVE_LAN;
  94. if (RPC_S_OK != RpcStatus)
  95. {
  96. dwLastError = RpcStatus;
  97. }
  98. }
  99. ASSERT((bNetState == TRUE) || (bNetState == FALSE));
  100. ASSERT(fNetNature <= (NETWORK_ALIVE_LAN | NETWORK_ALIVE_WAN | NETWORK_ALIVE_AOL));
  101. *lpdwFlags = fNetNature;
  102. SetLastError(dwLastError);
  103. // Since we retrieved information from SENS directly, reset the flag that
  104. // that indicates that we read from the cache.
  105. gdwCacheFirstReadTime = 0x0;
  106. return (bNetState);
  107. }
  108. #if !defined(SENS_CHICAGO)
  109. BOOL
  110. IsDestinationReachableA(
  111. LPCSTR lpszDestination,
  112. LPQOCINFO lpQOCInfo
  113. )
  114. /*++
  115. Routine Description:
  116. Given the name of a destination (IP Address, UNC, URL etc), we try to
  117. see if it is reachable.
  118. Arguments:
  119. lpszDestination - The destination (an ANSI string) whose rechability
  120. is of interest.
  121. lpQOCInfo - Pointer to a buffer that will receive Quality of Connection
  122. (QOC) Information. Can be NULL if QOC is not desired.
  123. Notes:
  124. a. This is available only for TCP/IP
  125. Return Value:
  126. TRUE, if the destination is reachable.
  127. FALSE, otherwise. Use GetLastError() to retrieve more error information.
  128. --*/
  129. {
  130. BOOL bReachable;
  131. NTSTATUS NtStatus;
  132. ANSI_STRING AnsiString;
  133. UNICODE_STRING UnicodeString;
  134. size_t uiLength;
  135. // Basic parameter checks
  136. if ( (lpszDestination == NULL)
  137. || ((uiLength = strlen(lpszDestination)) > MAX_DESTINATION_LENGTH)
  138. || (uiLength == 0))
  139. {
  140. SetLastError(ERROR_INVALID_PARAMETER);
  141. return FALSE;
  142. }
  143. // OUT parameter intialization.
  144. bReachable = FALSE;
  145. RtlInitAnsiString(&AnsiString, (PSZ)lpszDestination);
  146. NtStatus = RtlAnsiStringToUnicodeString(
  147. &UnicodeString,
  148. &AnsiString,
  149. TRUE
  150. );
  151. if (!NT_SUCCESS(NtStatus))
  152. {
  153. SetLastError(ERROR_OUTOFMEMORY); // Only possible error.
  154. return bReachable;
  155. }
  156. // Call the Unicode version.
  157. bReachable = IsDestinationReachableW(
  158. UnicodeString.Buffer,
  159. lpQOCInfo
  160. );
  161. ASSERT((bReachable == TRUE) || (bReachable == FALSE));
  162. RtlFreeUnicodeString(&UnicodeString);
  163. return (bReachable);
  164. }
  165. BOOL
  166. IsDestinationReachableW(
  167. LPCWSTR lpszDestination,
  168. LPQOCINFO lpQOCInfo
  169. )
  170. /*++
  171. Routine Description:
  172. Given the name of a destination (IP Address, UNC, URL etc), we try to
  173. see if it is reachable.
  174. Arguments:
  175. lpszDestination - The destination (a UNICODE string) whose rechability
  176. is of interest.
  177. lpQOCInfo - Pointer to a buffer that will receive Quality of Connection
  178. (QOC) Information. Can be NULL if QOC is not desired.
  179. Notes:
  180. a. This is available only for TCP/IP
  181. Return Value:
  182. TRUE, if the destination is reachable.
  183. FALSE, otherwise. Use GetLastError() to retrieve more error information.
  184. --*/
  185. {
  186. BOOL bReachable;
  187. RPC_STATUS RpcStatus;
  188. DWORD dwLastError;
  189. DWORD dwCallerQOCInfoSize;
  190. size_t uiLength;
  191. // Basic parameter checks
  192. if ( (lpszDestination == NULL)
  193. || ((uiLength = wcslen(lpszDestination)) > MAX_DESTINATION_LENGTH)
  194. || (uiLength == 0))
  195. {
  196. SetLastError(ERROR_INVALID_PARAMETER);
  197. return FALSE;
  198. }
  199. // OUT parameter intialization.
  200. dwLastError = ERROR_SUCCESS;
  201. bReachable = FALSE;
  202. if (lpQOCInfo != NULL)
  203. {
  204. dwCallerQOCInfoSize = lpQOCInfo->dwSize;
  205. memset(lpQOCInfo, 0, lpQOCInfo->dwSize);
  206. lpQOCInfo->dwSize = dwCallerQOCInfoSize;
  207. }
  208. RpcStatus = DoRpcSetup();
  209. //
  210. // Try to get the state information.
  211. //
  212. if (RPC_S_OK == RpcStatus)
  213. {
  214. RpcStatus = RPC_IsDestinationReachableW(
  215. ghSens,
  216. (PSENS_CHAR) lpszDestination,
  217. lpQOCInfo,
  218. &bReachable,
  219. &dwLastError
  220. );
  221. }
  222. if ( (RPC_S_OK != RpcStatus)
  223. || (RPC_S_SERVER_UNAVAILABLE == dwLastError))
  224. {
  225. //
  226. // An RPC failure occurred. We treat this as a success and
  227. // set to return values to default values.
  228. //
  229. if (lpQOCInfo != NULL)
  230. {
  231. lpQOCInfo->dwFlags = NETWORK_ALIVE_LAN;
  232. lpQOCInfo->dwInSpeed = DEFAULT_LAN_BANDWIDTH;
  233. lpQOCInfo->dwOutSpeed = DEFAULT_LAN_BANDWIDTH;
  234. }
  235. bReachable = TRUE;
  236. if (RPC_S_OK != RpcStatus)
  237. {
  238. dwLastError = RpcStatus;
  239. }
  240. }
  241. ASSERT((bReachable == TRUE) || (bReachable == FALSE));
  242. SetLastError(dwLastError);
  243. return (bReachable);
  244. }
  245. #else // SENS_CHICAGO
  246. BOOL
  247. IsDestinationReachableA(
  248. LPCSTR lpszDestination,
  249. LPQOCINFO lpQOCInfo
  250. )
  251. /*++
  252. Routine Description:
  253. Given the name of a destination (IP Address, UNC, URL etc), we try to
  254. see if it is reachable.
  255. Arguments:
  256. lpszDestination - The destination (a UNICODE string) whose rechability
  257. is of interest.
  258. lpQOCInfo - Pointer to a buffer that will receive Quality of Connection
  259. (QOC) Information. Can be NULL if QOC is not desired.
  260. Notes:
  261. a. This is available only for TCP/IP
  262. Return Value:
  263. TRUE, if the destination is reachable.
  264. FALSE, otherwise. Use GetLastError() to retrieve more error information.
  265. --*/
  266. {
  267. BOOL bReachable;
  268. RPC_STATUS RpcStatus;
  269. DWORD dwLastError;
  270. DWORD dwCallerQOCInfoSize;
  271. size_t uiLength;
  272. // Basic parameter checks
  273. if ( (lpszDestination == NULL)
  274. || ((uiLength = strlen(lpszDestination)) > MAX_DESTINATION_LENGTH)
  275. || (uiLength == 0))
  276. {
  277. SetLastError(ERROR_INVALID_PARAMETER);
  278. return FALSE;
  279. }
  280. // OUT parameter intialization.
  281. dwLastError = ERROR_SUCCESS;
  282. bReachable = FALSE;
  283. if (lpQOCInfo != NULL)
  284. {
  285. dwCallerQOCInfoSize = lpQOCInfo->dwSize;
  286. memset(lpQOCInfo, 0, lpQOCInfo->dwSize);
  287. lpQOCInfo->dwSize = dwCallerQOCInfoSize;
  288. }
  289. RpcStatus = DoRpcSetup();
  290. //
  291. // Try to get the state information.
  292. //
  293. if (RPC_S_OK == RpcStatus)
  294. {
  295. RpcStatus = RPC_IsDestinationReachableA(
  296. ghSens,
  297. (LPSTR) lpszDestination,
  298. lpQOCInfo,
  299. &bReachable,
  300. &dwLastError
  301. );
  302. }
  303. if ( (RPC_S_OK != RpcStatus)
  304. || (RPC_S_SERVER_UNAVAILABLE == dwLastError))
  305. {
  306. //
  307. // An RPC failure occurred. We treat this as a success and
  308. // set to return values to default values.
  309. //
  310. if (lpQOCInfo != NULL)
  311. {
  312. lpQOCInfo->dwFlags = NETWORK_ALIVE_LAN;
  313. lpQOCInfo->dwInSpeed = DEFAULT_LAN_BANDWIDTH;
  314. lpQOCInfo->dwOutSpeed = DEFAULT_LAN_BANDWIDTH;
  315. }
  316. bReachable = TRUE;
  317. if (RPC_S_OK != RpcStatus)
  318. {
  319. dwLastError = RpcStatus;
  320. }
  321. }
  322. ASSERT((bReachable == TRUE) || (bReachable == FALSE));
  323. SetLastError(dwLastError);
  324. return (bReachable);
  325. }
  326. BOOL
  327. IsDestinationReachableW(
  328. LPCWSTR lpszDestination,
  329. LPQOCINFO lpQOCInfo
  330. )
  331. /*++
  332. Routine Description:
  333. This is just a stub on Win9x platforms. It returns FALSE always. This
  334. is provided for consistency between NT and Win9x platforms.
  335. Arguments:
  336. lpszDestination - The destination (a UNICODE string) whose rechability
  337. is of interest.
  338. lpQOCInfo - Pointer to a buffer that will receive Quality of Connection
  339. (QOC) Information. Can be NULL if QOC is not desired.
  340. Return Value:
  341. FALSE, always. Use GetLastError() to retrieve more error information.
  342. --*/
  343. {
  344. SetLastError(ERROR_NOT_SUPPORTED);
  345. return FALSE;
  346. }
  347. #endif // SENS_CHICAGO
  348. inline RPC_STATUS
  349. DoRpcSetup(
  350. void
  351. )
  352. /*++
  353. Routine Description:
  354. Do the miscellaneous work to talk to SENS via RPC.
  355. Arguments:
  356. None.
  357. Return Value:
  358. None.
  359. --*/
  360. {
  361. RPC_STATUS status;
  362. SENS_CHAR * BindingString;
  363. RPC_BINDING_HANDLE hServer = NULL;
  364. status = RPC_S_OK;
  365. BindingString = NULL;
  366. if (ghSens != NULL)
  367. {
  368. return (status);
  369. }
  370. RequestLock();
  371. if (ghSens != NULL)
  372. {
  373. ReleaseLock();
  374. return (status);
  375. }
  376. status = RpcStringBindingCompose(
  377. NULL, // NULL ObjUuid
  378. SENS_PROTSEQ,
  379. NULL, // Local machine
  380. SENS_ENDPOINT,
  381. NULL, // No Options
  382. &BindingString
  383. );
  384. if (BindingString)
  385. {
  386. status = RpcBindingFromStringBinding(BindingString, &hServer);
  387. }
  388. if (status == RPC_S_OK)
  389. {
  390. RPC_SECURITY_QOS RpcSecQos;
  391. RpcSecQos.Version= RPC_C_SECURITY_QOS_VERSION_1;
  392. RpcSecQos.ImpersonationType= RPC_C_IMP_LEVEL_IMPERSONATE;
  393. RpcSecQos.IdentityTracking= RPC_C_QOS_IDENTITY_DYNAMIC;
  394. RpcSecQos.Capabilities= RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  395. status= RpcBindingSetAuthInfoEx(hServer,
  396. L"NT Authority\\System",
  397. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  398. RPC_C_AUTHN_WINNT,
  399. NULL,
  400. RPC_C_AUTHZ_NONE,
  401. (RPC_SECURITY_QOS *)&RpcSecQos);
  402. if (RPC_S_OK != status)
  403. {
  404. RpcBindingFree(&hServer);
  405. hServer = NULL;
  406. }
  407. }
  408. ghSens = hServer;
  409. ReleaseLock();
  410. if (BindingString != NULL)
  411. {
  412. RpcStringFree(&BindingString);
  413. }
  414. return (status);
  415. }
  416. BOOL
  417. MapSensCacheView(
  418. void
  419. )
  420. /*++
  421. Routine Description:
  422. Prepare to read SENS information cache.
  423. Arguments:
  424. None.
  425. Notes:
  426. Should call it under a lock.
  427. Return Value:
  428. TRUE, if successful.
  429. FALSE, otherwise.
  430. --*/
  431. {
  432. //
  433. // First, open the SENS cache file mapping object
  434. //
  435. ghSensFileMap = OpenFileMapping(
  436. FILE_MAP_READ, // Protection for mapping object
  437. FALSE, // Inherit flag
  438. SENS_CACHE_NAME // Name of the file mapping object
  439. );
  440. if (NULL == ghSensFileMap)
  441. {
  442. goto Cleanup;
  443. }
  444. //
  445. // Map a view of SENS cache into the address space
  446. //
  447. gpSensCache = (PSENS_CACHE) MapViewOfFile(
  448. ghSensFileMap, // Map file object
  449. FILE_MAP_READ, // Access mode
  450. 0, // High-order 32 bits of file offset
  451. 0, // Low-order 32 bits of file offset
  452. 0 // Number of bytes to map
  453. );
  454. if (NULL == gpSensCache)
  455. {
  456. goto Cleanup;
  457. }
  458. ASSERT(gpSensCache->dwCacheVer >= SENS_CACHE_VERSION);
  459. ASSERT(gpSensCache->dwCacheSize >= sizeof(SENS_CACHE));
  460. return TRUE;
  461. Cleanup:
  462. //
  463. // Cleanup
  464. //
  465. if (ghSensFileMap != NULL)
  466. {
  467. CloseHandle(ghSensFileMap);
  468. }
  469. if (gpSensCache != NULL)
  470. {
  471. UnmapViewOfFile(gpSensCache);
  472. }
  473. ghSensFileMap = NULL;
  474. gpSensCache = NULL;
  475. return FALSE;
  476. }
  477. void
  478. UnmapSensCacheView(
  479. void
  480. )
  481. /*++
  482. Routine Description:
  483. Cleanup resources related to SENS information cache.
  484. Arguments:
  485. None.
  486. Notes:
  487. None.
  488. Return Value:
  489. None.
  490. --*/
  491. {
  492. BOOL bStatus;
  493. //
  494. // Unmap the view of SENS cache from the address space
  495. //
  496. if (gpSensCache != NULL)
  497. {
  498. bStatus = UnmapViewOfFile(gpSensCache);
  499. ASSERT(bStatus);
  500. }
  501. //
  502. // Close File Mapping object
  503. //
  504. if (ghSensFileMap != NULL)
  505. {
  506. bStatus = CloseHandle(ghSensFileMap);
  507. ASSERT(bStatus);
  508. }
  509. }
  510. BOOL
  511. ReadConnectivityCache(
  512. OUT LPDWORD lpdwFlags
  513. )
  514. /*++
  515. Routine Description:
  516. Try to read SENS connectivity cache. Talk to SENS iff one of the following
  517. conditions is TRUE:
  518. o Failed to read the connectivity cache.
  519. o Read the cache but connectivity state is FALSE.
  520. o Read the cache and connectivity state is TRUE but stale.
  521. o Read the cache and there is updated information available.
  522. Arguments:
  523. lpdwFlags - OUT parameter that contains the connectivity state.
  524. Return Value:
  525. TRUE, successfully got cached information.
  526. FALSE, SENS needs to be contacted.
  527. --*/
  528. {
  529. DWORD dwNow;
  530. dwNow = GetTickCount();
  531. RequestLock();
  532. // Failed to initialize/read Sens Cache
  533. if ( (NULL == gpSensCache)
  534. && (FALSE == MapSensCacheView()))
  535. {
  536. goto Cleanup;
  537. }
  538. // Cache has been updated since we last read. Note that dwLastUpdateTime
  539. // can wrap around.
  540. if (gpSensCache->dwLastUpdateTime != gdwCacheLastUpdatedTime)
  541. {
  542. gdwCacheLastUpdatedTime = gpSensCache->dwLastUpdateTime;
  543. goto Cleanup;
  544. }
  545. // It's been a while.
  546. if ( (gdwCacheFirstReadTime != 0x0)
  547. && (dwNow - gdwCacheFirstReadTime) > CACHE_VALID_INTERVAL)
  548. {
  549. goto Cleanup;
  550. }
  551. // Cached state is FALSE
  552. if (0x0 == gpSensCache->dwLastUpdateState)
  553. {
  554. goto Cleanup;
  555. }
  556. *lpdwFlags = gpSensCache->dwLastUpdateState;
  557. if (0 == gdwCacheFirstReadTime)
  558. {
  559. gdwCacheFirstReadTime = dwNow;
  560. }
  561. ASSERT(gdwCacheLastUpdatedTime == gpSensCache->dwLastUpdateTime);
  562. ReleaseLock();
  563. SetLastError(ERROR_SUCCESS);
  564. return TRUE;
  565. Cleanup:
  566. //
  567. // Cleanup
  568. //
  569. ReleaseLock();
  570. // Don't need to SetLastError() as we will go to SENS to retrieve it.
  571. return FALSE;
  572. }
  573. extern "C" int APIENTRY
  574. DllMain(
  575. IN HINSTANCE hInstance,
  576. IN DWORD dwReason,
  577. IN LPVOID lpvReserved
  578. )
  579. /*++
  580. Routine Description:
  581. This routine will get called either when a process attaches to this dll
  582. or when a process detaches from this dll.
  583. Return Value:
  584. TRUE - Initialization successfully occurred.
  585. FALSE - Insufficient memory is available for the process to attach to
  586. this dll.
  587. --*/
  588. {
  589. BOOL bSuccess;
  590. RPC_STATUS RpcStatus;
  591. switch (dwReason)
  592. {
  593. case DLL_PROCESS_ATTACH:
  594. // Disable Thread attach/detach calls
  595. bSuccess = DisableThreadLibraryCalls(hInstance);
  596. ASSERT(bSuccess == TRUE);
  597. // Initialize the lock
  598. InitializeCriticalSection(&gSensapiLock);
  599. break;
  600. case DLL_PROCESS_DETACH:
  601. // Clean the lock
  602. DeleteCriticalSection(&gSensapiLock);
  603. // Cleanup cache related resources
  604. UnmapSensCacheView();
  605. // Cleanup RPC Binding handle
  606. if (ghSens != NULL)
  607. {
  608. RpcStatus = RpcBindingFree(&ghSens);
  609. ASSERT(RPC_S_OK == RpcStatus);
  610. }
  611. break;
  612. }
  613. return(TRUE);
  614. }