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.

642 lines
13 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. PSENS_CACHE gpSensCache;
  29. BOOL
  30. IsNetworkAlive(
  31. OUT LPDWORD lpdwFlags
  32. )
  33. /*++
  34. Routine Description:
  35. We try to find out if this machine has any network connectivity.
  36. Arguments:
  37. lpdwFlags - Receives information regarding the nature of the machine's
  38. network connectivity. It can be on of the following:
  39. o NETWORK_ALIVE_WAN
  40. o NETWORK_ALIVE_LAN
  41. Notes:
  42. a. This is available only for TCP/IP
  43. b. This API does not generate any Network traffic.
  44. Return Value:
  45. TRUE, if there is network connectivity
  46. FALSE, otherwise. Use GetLastError() to retrieve more error information.
  47. --*/
  48. {
  49. BOOL bNetState;
  50. RPC_STATUS RpcStatus;
  51. DWORD fNetNature;
  52. DWORD dwLastError;
  53. // Basic parameter checks
  54. if (lpdwFlags == NULL)
  55. {
  56. SetLastError(ERROR_INVALID_PARAMETER);
  57. return FALSE;
  58. }
  59. // OUT parameter intialization.
  60. *lpdwFlags = 0x0;
  61. fNetNature = 0x0;
  62. dwLastError = ERROR_SUCCESS;
  63. bNetState = FALSE;
  64. if (TRUE == ReadConnectivityCache(lpdwFlags))
  65. {
  66. return TRUE;
  67. }
  68. //
  69. // Need to contact SENS for information.
  70. //
  71. RpcStatus = DoRpcSetup();
  72. //
  73. // Try to get the state information.
  74. //
  75. if (RPC_S_OK == RpcStatus)
  76. {
  77. RpcStatus = RPC_IsNetworkAlive(
  78. ghSens,
  79. &fNetNature,
  80. &bNetState,
  81. &dwLastError
  82. );
  83. }
  84. if ( (RPC_S_OK != RpcStatus)
  85. || (RPC_S_SERVER_UNAVAILABLE == dwLastError))
  86. {
  87. //
  88. // An RPC failure occurred. We treat this as a success and
  89. // set to return values to default values.
  90. //
  91. bNetState = TRUE;
  92. fNetNature = NETWORK_ALIVE_LAN;
  93. if (RPC_S_OK != RpcStatus)
  94. {
  95. dwLastError = RpcStatus;
  96. }
  97. }
  98. ASSERT((bNetState == TRUE) || (bNetState == FALSE));
  99. ASSERT(fNetNature <= (NETWORK_ALIVE_LAN | NETWORK_ALIVE_WAN));
  100. *lpdwFlags = fNetNature;
  101. SetLastError(dwLastError);
  102. // Since we retrieved information from SENS directly, reset the flag that
  103. // that indicates that we read from the cache.
  104. gdwCacheFirstReadTime = 0x0;
  105. return (bNetState);
  106. }
  107. BOOL
  108. IsDestinationReachableA(
  109. LPCSTR lpszDestination,
  110. LPQOCINFO lpQOCInfo
  111. )
  112. /*++
  113. Routine Description:
  114. Given the name of a destination (IP Address, UNC, URL etc), we try to
  115. see if it is reachable.
  116. Arguments:
  117. lpszDestination - The destination (an ANSI string) whose rechability
  118. is of interest.
  119. lpQOCInfo - Pointer to a buffer that will receive Quality of Connection
  120. (QOC) Information. Can be NULL if QOC is not desired.
  121. Notes:
  122. a. This is available only for TCP/IP
  123. Return Value:
  124. TRUE, if the destination is reachable.
  125. FALSE, otherwise. Use GetLastError() to retrieve more error information.
  126. --*/
  127. {
  128. BOOL bReachable;
  129. NTSTATUS NtStatus;
  130. ANSI_STRING AnsiString;
  131. UNICODE_STRING UnicodeString;
  132. size_t uiLength;
  133. // Basic parameter checks
  134. if ( (lpszDestination == NULL)
  135. || ((uiLength = strlen(lpszDestination)) > MAX_DESTINATION_LENGTH)
  136. || (uiLength == 0))
  137. {
  138. SetLastError(ERROR_INVALID_PARAMETER);
  139. return FALSE;
  140. }
  141. // OUT parameter intialization.
  142. bReachable = FALSE;
  143. RtlInitAnsiString(&AnsiString, (PSZ)lpszDestination);
  144. NtStatus = RtlAnsiStringToUnicodeString(
  145. &UnicodeString,
  146. &AnsiString,
  147. TRUE
  148. );
  149. if (!NT_SUCCESS(NtStatus))
  150. {
  151. SetLastError(ERROR_OUTOFMEMORY); // Only possible error.
  152. return bReachable;
  153. }
  154. // Call the Unicode version.
  155. bReachable = IsDestinationReachableW(
  156. UnicodeString.Buffer,
  157. lpQOCInfo
  158. );
  159. ASSERT((bReachable == TRUE) || (bReachable == FALSE));
  160. RtlFreeUnicodeString(&UnicodeString);
  161. return (bReachable);
  162. }
  163. BOOL
  164. IsDestinationReachableW(
  165. LPCWSTR lpszDestination,
  166. LPQOCINFO lpQOCInfo
  167. )
  168. /*++
  169. Routine Description:
  170. Given the name of a destination (IP Address, UNC, URL etc), we try to
  171. see if it is reachable.
  172. Arguments:
  173. lpszDestination - The destination (a UNICODE string) whose rechability
  174. is of interest.
  175. lpQOCInfo - Pointer to a buffer that will receive Quality of Connection
  176. (QOC) Information. Can be NULL if QOC is not desired.
  177. Notes:
  178. a. This is available only for TCP/IP
  179. Return Value:
  180. TRUE, if the destination is reachable.
  181. FALSE, otherwise. Use GetLastError() to retrieve more error information.
  182. --*/
  183. {
  184. BOOL bReachable;
  185. RPC_STATUS RpcStatus;
  186. DWORD dwLastError;
  187. DWORD dwCallerQOCInfoSize;
  188. size_t uiLength;
  189. // Basic parameter checks
  190. if ( (lpszDestination == NULL)
  191. || ((uiLength = wcslen(lpszDestination)) > MAX_DESTINATION_LENGTH)
  192. || (uiLength == 0)
  193. || ( (lpQOCInfo != NULL) && (lpQOCInfo->dwSize < sizeof(QOCINFO)) ) )
  194. {
  195. SetLastError(ERROR_INVALID_PARAMETER);
  196. return FALSE;
  197. }
  198. // OUT parameter intialization.
  199. dwLastError = ERROR_SUCCESS;
  200. bReachable = FALSE;
  201. if (lpQOCInfo != NULL)
  202. {
  203. dwCallerQOCInfoSize = lpQOCInfo->dwSize;
  204. memset(lpQOCInfo, 0, lpQOCInfo->dwSize);
  205. lpQOCInfo->dwSize = dwCallerQOCInfoSize;
  206. }
  207. RpcStatus = DoRpcSetup();
  208. //
  209. // Try to get the state information.
  210. //
  211. if (RPC_S_OK == RpcStatus)
  212. {
  213. RpcStatus = RPC_IsDestinationReachableW(
  214. ghSens,
  215. (PSENS_CHAR) lpszDestination,
  216. lpQOCInfo,
  217. &bReachable,
  218. &dwLastError
  219. );
  220. }
  221. if ( (RPC_S_OK != RpcStatus)
  222. || (RPC_S_SERVER_UNAVAILABLE == dwLastError))
  223. {
  224. //
  225. // An RPC failure occurred. We treat this as a success and
  226. // set to return values to default values.
  227. //
  228. if (lpQOCInfo != NULL)
  229. {
  230. lpQOCInfo->dwFlags = NETWORK_ALIVE_LAN;
  231. lpQOCInfo->dwInSpeed = DEFAULT_LAN_BANDWIDTH;
  232. lpQOCInfo->dwOutSpeed = DEFAULT_LAN_BANDWIDTH;
  233. }
  234. bReachable = TRUE;
  235. if (RPC_S_OK != RpcStatus)
  236. {
  237. dwLastError = RpcStatus;
  238. }
  239. }
  240. ASSERT((bReachable == TRUE) || (bReachable == FALSE));
  241. SetLastError(dwLastError);
  242. return (bReachable);
  243. }
  244. inline RPC_STATUS
  245. DoRpcSetup(
  246. void
  247. )
  248. /*++
  249. Routine Description:
  250. Do the miscellaneous work to talk to SENS via RPC.
  251. Arguments:
  252. None.
  253. Return Value:
  254. None.
  255. --*/
  256. {
  257. RPC_BINDING_HANDLE bh = NULL;
  258. RPC_STATUS status = RPC_S_OK;
  259. if (ghSens != NULL)
  260. {
  261. return (status);
  262. }
  263. RequestLock();
  264. if (ghSens != NULL)
  265. {
  266. ReleaseLock();
  267. return (status);
  268. }
  269. status = BindToSensService(bh);
  270. if (status == RPC_S_OK)
  271. {
  272. ASSERT(bh);
  273. ghSens = bh;
  274. }
  275. ReleaseLock();
  276. return status;
  277. }
  278. BOOL
  279. MapSensCacheView(
  280. void
  281. )
  282. /*++
  283. Routine Description:
  284. Prepare to read SENS information cache.
  285. Arguments:
  286. None.
  287. Notes:
  288. Should call it under a lock.
  289. Return Value:
  290. TRUE, if successful.
  291. FALSE, otherwise.
  292. --*/
  293. {
  294. HANDLE hSensFile = NULL;
  295. //
  296. // First, open the SENS cache file mapping object
  297. //
  298. hSensFile = OpenFileMapping(
  299. FILE_MAP_READ, // Protection for mapping object
  300. FALSE, // Inherit flag
  301. SENS_CACHE_NAME // Name of the file mapping object
  302. );
  303. if (NULL == hSensFile)
  304. {
  305. goto Cleanup;
  306. }
  307. //
  308. // Map a view of SENS cache into the address space
  309. //
  310. gpSensCache = (PSENS_CACHE) MapViewOfFile(
  311. hSensFile, // Map file object
  312. FILE_MAP_READ, // Access mode
  313. 0, // High-order 32 bits of file offset
  314. 0, // Low-order 32 bits of file offset
  315. 0 // Number of bytes to map
  316. );
  317. //
  318. // Close the file handle in all cases; we don't need it anymore.
  319. //
  320. CloseHandle(hSensFile);
  321. if (NULL == gpSensCache)
  322. {
  323. goto Cleanup;
  324. }
  325. ASSERT(gpSensCache->dwCacheVer >= SENS_CACHE_VERSION);
  326. ASSERT(gpSensCache->dwCacheSize >= sizeof(SENS_CACHE));
  327. return TRUE;
  328. Cleanup:
  329. //
  330. // Cleanup
  331. //
  332. UnmapSensCacheView();
  333. return FALSE;
  334. }
  335. void
  336. UnmapSensCacheView(
  337. void
  338. )
  339. /*++
  340. Routine Description:
  341. Cleanup resources related to SENS information cache.
  342. Arguments:
  343. None.
  344. Notes:
  345. None.
  346. Return Value:
  347. None.
  348. --*/
  349. {
  350. BOOL bStatus;
  351. //
  352. // Unmap the view of SENS cache from the address space
  353. //
  354. if (gpSensCache != NULL)
  355. {
  356. bStatus = UnmapViewOfFile(gpSensCache);
  357. ASSERT(bStatus);
  358. }
  359. gpSensCache = NULL;
  360. }
  361. BOOL
  362. ReadConnectivityCache(
  363. OUT LPDWORD lpdwFlags
  364. )
  365. /*++
  366. Routine Description:
  367. Try to read SENS connectivity cache. Talk to SENS iff one of the following
  368. conditions is TRUE:
  369. o Failed to read the connectivity cache.
  370. o Read the cache but connectivity state is FALSE.
  371. o Read the cache and connectivity state is TRUE but stale.
  372. o Read the cache and there is updated information available.
  373. Arguments:
  374. lpdwFlags - OUT parameter that contains the connectivity state.
  375. Return Value:
  376. TRUE, successfully got cached information.
  377. FALSE, SENS needs to be contacted.
  378. --*/
  379. {
  380. DWORD dwNow;
  381. dwNow = GetTickCount();
  382. RequestLock();
  383. // Failed to initialize/read Sens Cache
  384. if ( (NULL == gpSensCache)
  385. && (FALSE == MapSensCacheView()))
  386. {
  387. goto Cleanup;
  388. }
  389. // Cache has been updated since we last read. Note that dwLastUpdateTime
  390. // can wrap around.
  391. if (gpSensCache->dwLastUpdateTime != gdwCacheLastUpdatedTime)
  392. {
  393. gdwCacheLastUpdatedTime = gpSensCache->dwLastUpdateTime;
  394. goto Cleanup;
  395. }
  396. // It's been a while.
  397. if ( (gdwCacheFirstReadTime != 0x0)
  398. && (dwNow - gdwCacheFirstReadTime) > CACHE_VALID_INTERVAL)
  399. {
  400. goto Cleanup;
  401. }
  402. // Cached state is FALSE
  403. if (0x0 == gpSensCache->dwLastUpdateState)
  404. {
  405. goto Cleanup;
  406. }
  407. *lpdwFlags = gpSensCache->dwLastUpdateState;
  408. if (0 == gdwCacheFirstReadTime)
  409. {
  410. gdwCacheFirstReadTime = dwNow;
  411. }
  412. ASSERT(gdwCacheLastUpdatedTime == gpSensCache->dwLastUpdateTime);
  413. ReleaseLock();
  414. SetLastError(ERROR_SUCCESS);
  415. return TRUE;
  416. Cleanup:
  417. //
  418. // Cleanup
  419. //
  420. ReleaseLock();
  421. // Don't need to SetLastError() as we will go to SENS to retrieve it.
  422. return FALSE;
  423. }
  424. extern "C" int APIENTRY
  425. DllMain(
  426. IN HINSTANCE hInstance,
  427. IN DWORD dwReason,
  428. IN LPVOID lpvReserved
  429. )
  430. /*++
  431. Routine Description:
  432. This routine will get called either when a process attaches to this dll
  433. or when a process detaches from this dll.
  434. Return Value:
  435. TRUE - Initialization successfully occurred.
  436. FALSE - Insufficient memory is available for the process to attach to
  437. this dll.
  438. --*/
  439. {
  440. BOOL bSuccess;
  441. RPC_STATUS RpcStatus;
  442. switch (dwReason)
  443. {
  444. case DLL_PROCESS_ATTACH:
  445. // Disable Thread attach/detach calls
  446. bSuccess = DisableThreadLibraryCalls(hInstance);
  447. ASSERT(bSuccess == TRUE);
  448. // Initialize the lock
  449. InitializeCriticalSection(&gSensapiLock);
  450. break;
  451. case DLL_PROCESS_DETACH:
  452. // Clean the lock
  453. DeleteCriticalSection(&gSensapiLock);
  454. // Cleanup cache related resources
  455. UnmapSensCacheView();
  456. // Cleanup RPC Binding handle
  457. if (ghSens != NULL)
  458. {
  459. RpcStatus = RpcBindingFree(&ghSens);
  460. ASSERT(RPC_S_OK == RpcStatus);
  461. }
  462. break;
  463. }
  464. return(TRUE);
  465. }