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.

519 lines
12 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. wan.cxx
  5. Abstract:
  6. This is the source file relating to the WAN-specific routines of the
  7. Connectivity APIs implementation.
  8. Author:
  9. Gopal Parupudi <GopalP>
  10. [Notes:]
  11. optional-notes
  12. Revision History:
  13. GopalP 10/11/1997 Start.
  14. --*/
  15. #include <precomp.hxx>
  16. //
  17. // Typedefs
  18. //
  19. typedef DWORD (APIENTRY *LPFN_RAS_ENUM)(LPRASCONN, LPDWORD, LPDWORD);
  20. typedef BOOL (APIENTRY *LPFN_DO_CONNECTOIDS_EXIST)(void);
  21. typedef DWORD (APIENTRY *LPFN_RAS_CONNECTION_NOTIFICATION)(HRASCONN, HANDLE, DWORD);
  22. typedef DWORD (APIENTRY *LPFN_RAS_GET_CONNECT_STATUS)(HRASCONN, LPRASCONNSTATUS);
  23. //
  24. // Constants
  25. //
  26. #define RAS_DLL SENS_STRING("RasApi32.dll")
  27. #define WININET_DLL SENS_STRING("Wininet.dll")
  28. #if !defined(SENS_CHICAGO)
  29. #define RAS_ENUM "RasEnumConnectionsW"
  30. #define RAS_CONNECTION_NOTIFICATION "RasConnectionNotificationW"
  31. #else // SENS_CHICAGO
  32. #define RAS_ENUM "RasEnumConnectionsA"
  33. #define RAS_CONNECTION_NOTIFICATION "RasConnectionNotificationA"
  34. #define RAS_GET_CONNECT_STATUS "RasGetConnectStatusA"
  35. #define DO_CONNECTOIDS_EXIST (LPCSTR) 101 // Ordinal 101
  36. #endif // SENS_CHICAGO
  37. #if (WINVER < 0x401)
  38. #define RASCN_Connection 0x00000001
  39. #define RASCN_Disconnection 0x00000002
  40. #endif // WINVER < 0x401
  41. //
  42. // Globals
  43. //
  44. // Common
  45. long gdwLastWANTime;
  46. long gdwWANState;
  47. BOOL gbIsRasInstalled;
  48. LPFN_RAS_ENUM glpfnRasEnumConnections;
  49. LPFN_RAS_CONNECTION_NOTIFICATION glpfnRasConnectionNotification;
  50. // IE5-specific
  51. #if !defined(SENS_NT5)
  52. HANDLE ghRasEvents[2];
  53. HANDLE ghConnectWait;
  54. HANDLE ghDisconnectWait;
  55. #endif // SENS_NT5
  56. // Win9x-specific
  57. #if defined(SENS_CHICAGO)
  58. LPFN_RAS_GET_CONNECT_STATUS glpfnRasGetConnectStatus;
  59. #endif // SENS_CHICAGO
  60. inline void
  61. LoadRasIfNecessary(
  62. void
  63. )
  64. /*++
  65. Routine Description:
  66. Load RAS DLL, if necessary.
  67. Arguments:
  68. None.
  69. Return Value:
  70. None.
  71. --*/
  72. {
  73. HMODULE hDLL;
  74. //
  75. // See if RAS DLL is already loaded.
  76. //
  77. if (NULL != glpfnRasEnumConnections)
  78. {
  79. return;
  80. }
  81. //
  82. // Do the necessary work.
  83. //
  84. hDLL = LoadLibrary(RAS_DLL);
  85. if (hDLL != NULL)
  86. {
  87. glpfnRasEnumConnections = (LPFN_RAS_ENUM) GetProcAddress(hDLL, RAS_ENUM);
  88. glpfnRasConnectionNotification = (LPFN_RAS_CONNECTION_NOTIFICATION)
  89. GetProcAddress(hDLL, RAS_CONNECTION_NOTIFICATION);
  90. #if defined(SENS_CHICAGO)
  91. glpfnRasGetConnectStatus = (LPFN_RAS_GET_CONNECT_STATUS)
  92. GetProcAddress(hDLL, RAS_GET_CONNECT_STATUS);
  93. #endif // SENS_CHICAGO
  94. if (
  95. (NULL == glpfnRasEnumConnections)
  96. #if defined(SENS_CHICAGO)
  97. && (NULL == glpfnRasGetConnectStatus)
  98. #endif // SENS_CHICAGO
  99. )
  100. {
  101. // Both entrypoints are NULL. Can't do much with RAS now.
  102. FreeLibrary(hDLL);
  103. }
  104. }
  105. SensPrintA(SENS_INFO, ("[SENS] LoadRasIfNecessary(): RAS DLL is %spresent.\n",
  106. (glpfnRasEnumConnections ? "" : "NOT ")));
  107. }
  108. BOOL
  109. DoWanSetup(
  110. void
  111. )
  112. /*++
  113. Routine Description:
  114. Do minimal WAN Setup.
  115. Arguments:
  116. None.
  117. Return Value:
  118. TRUE, if successful.
  119. FALSE, otherwise.
  120. --*/
  121. {
  122. DWORD dwLastError;
  123. DWORD dwCurrentRasState;
  124. BOOL bStatus;
  125. dwLastError = 0;
  126. dwCurrentRasState = 0;
  127. bStatus = FALSE;
  128. glpfnRasEnumConnections = NULL;
  129. glpfnRasConnectionNotification = NULL;
  130. gbIsRasInstalled = FALSE;
  131. bStatus = TRUE;
  132. Cleanup:
  133. //
  134. // Cleanup
  135. //
  136. return bStatus;
  137. }
  138. BOOL
  139. IsRasInstalled(
  140. OUT LPDWORD lpdwState,
  141. OUT LPDWORD lpdwLastError
  142. )
  143. /*++
  144. Routine Description:
  145. Check to see if RAS is installed. If so, return it's current state.
  146. Arguments:
  147. lpdwState - If Ras is installed, this parameter contains the current state
  148. of the RasMan service.
  149. lpdwLastError - If RAS is not active or installed, it retuns the GLE.
  150. Return Value:
  151. TRUE, if Ras is installed.
  152. FALSE, otherwise.
  153. --*/
  154. {
  155. if (TRUE == gbIsRasInstalled)
  156. {
  157. *lpdwState = SERVICE_RUNNING; // For NT
  158. *lpdwLastError = ERROR_SUCCESS;
  159. return TRUE;
  160. }
  161. static SC_HANDLE hSCM; // Cache the handle.
  162. static SC_HANDLE hRasMan; // Cache the handle.
  163. BOOL bRetValue;
  164. SERVICE_STATUS ServiceStatus;
  165. bRetValue = FALSE;
  166. *lpdwState = 0;
  167. *lpdwLastError = ERROR_SUCCESS;
  168. if (NULL == hSCM)
  169. {
  170. hSCM = OpenSCManager(
  171. NULL, // Local machine
  172. NULL, // Default database - SERVICES_ACTIVE_DATABASE
  173. SC_MANAGER_ALL_ACCESS // NOTE: Only for Administrators
  174. );
  175. if (NULL == hSCM)
  176. {
  177. SensPrintA(SENS_ERR, ("OpenSCManager() returned %d\n", *lpdwLastError));
  178. goto Cleanup;
  179. }
  180. }
  181. if (hRasMan == NULL)
  182. {
  183. hRasMan = OpenService(
  184. hSCM, // Handle to SCM database
  185. RAS_MANAGER, // Name of the service to start
  186. SERVICE_QUERY_STATUS // Type of access requested
  187. );
  188. if (NULL == hRasMan)
  189. {
  190. SensPrintA(SENS_ERR, ("OpenService() returned %d\n", *lpdwLastError));
  191. goto Cleanup;
  192. }
  193. }
  194. memset(&ServiceStatus, 0, sizeof(SERVICE_STATUS));
  195. bRetValue = QueryServiceStatus(
  196. hRasMan,
  197. &ServiceStatus
  198. );
  199. ASSERT(bRetValue == TRUE);
  200. if (FALSE == bRetValue)
  201. {
  202. goto Cleanup;
  203. }
  204. *lpdwState = ServiceStatus.dwCurrentState;
  205. gbIsRasInstalled = TRUE;
  206. SensPrintA(SENS_ERR, ("IsRasInstalled(): RASMAN state is %d\n",
  207. *lpdwState));
  208. return TRUE;
  209. Cleanup:
  210. //
  211. // Cleanup
  212. //
  213. *lpdwLastError = GetLastError();
  214. if (hSCM)
  215. {
  216. CloseServiceHandle(hSCM);
  217. hSCM = NULL;
  218. }
  219. if (hRasMan)
  220. {
  221. CloseServiceHandle(hRasMan);
  222. hRasMan = NULL;
  223. }
  224. return FALSE;
  225. }
  226. BOOL WINAPI
  227. EvaluateWanConnectivity(
  228. OUT LPDWORD lpdwLastError
  229. )
  230. /*++
  231. Routine Description:
  232. Arguments:
  233. Return Value:
  234. --*/
  235. {
  236. BOOL bWanAlive;
  237. BOOL bRasInstalled;
  238. DWORD dwNow;
  239. DWORD dwCurrentRasState;
  240. SERVICE_STATUS ServiceStatus;
  241. PWCHAR szEntryName;
  242. DWORD dwLocalLastError;
  243. dwNow = GetTickCount();
  244. bWanAlive = FALSE;
  245. dwCurrentRasState = 0;
  246. dwLocalLastError = ERROR_NO_NETWORK;
  247. if (lpdwLastError)
  248. {
  249. *lpdwLastError = dwLocalLastError;
  250. }
  251. else
  252. {
  253. lpdwLastError = &dwLocalLastError;
  254. }
  255. szEntryName = new WCHAR[RAS_MaxEntryName + 1];
  256. if (!szEntryName )
  257. {
  258. *lpdwLastError = ERROR_OUTOFMEMORY;
  259. return FALSE;
  260. }
  261. wcscpy(szEntryName, DEFAULT_WAN_CONNECTION_NAME);
  262. //
  263. // If RasManager is running, it implies that there "might" be one or more
  264. // active RAS connections.
  265. //
  266. bRasInstalled = IsRasInstalled(&dwCurrentRasState, lpdwLastError);
  267. if (TRUE == bRasInstalled)
  268. {
  269. LoadRasIfNecessary();
  270. }
  271. if ( (bRasInstalled)
  272. && (dwCurrentRasState == SERVICE_RUNNING)
  273. && (glpfnRasEnumConnections != NULL))
  274. {
  275. DWORD dwRasStatus;
  276. DWORD cBytes;
  277. DWORD cBytesOld;
  278. DWORD cConnections;
  279. RASCONN *pRasConn;
  280. dwRasStatus = 0x0;
  281. cConnections = 0;
  282. //
  283. // Start with loop with a single structure. Will loop and realloc if we need
  284. // a larger buffer.
  285. //
  286. cBytesOld = 0;
  287. cBytes = sizeof(RASCONN);
  288. pRasConn = NULL;
  289. dwRasStatus = ERROR_BUFFER_TOO_SMALL;
  290. //
  291. // Loop till RasEnumConnections() succeeds or returns with an error
  292. // other than ERROR_BUFFER_TOO_SMALL.
  293. //
  294. while (ERROR_BUFFER_TOO_SMALL == dwRasStatus)
  295. {
  296. ASSERT(cBytes > cBytesOld);
  297. ASSERT(pRasConn == NULL);
  298. // Allocate the buffer
  299. pRasConn = (RASCONN *) new char[cBytes];
  300. if (pRasConn == NULL)
  301. {
  302. delete szEntryName;
  303. *lpdwLastError = ERROR_OUTOFMEMORY;
  304. return FALSE;
  305. }
  306. pRasConn[0].dwSize = sizeof(RASCONN);
  307. cBytesOld = cBytes;
  308. dwRasStatus = (*glpfnRasEnumConnections)(
  309. pRasConn,
  310. &cBytes,
  311. &cConnections
  312. );
  313. // Free the too small buffer.
  314. if (ERROR_BUFFER_TOO_SMALL == dwRasStatus)
  315. {
  316. delete pRasConn;
  317. pRasConn = NULL;
  318. SensPrintA(SENS_WARN, ("RasEnumConnections(): reallocing buffer to be %d bytes\n", cBytes));
  319. }
  320. }
  321. if ((0 == dwRasStatus) &&
  322. (cConnections > 0))
  323. {
  324. bWanAlive = TRUE;
  325. SensPrintA(SENS_INFO, ("RasEnumConnections(%d) successful connections (%d)\n", cBytes, cConnections));
  326. // P3 BUG: we're only dealing with one RAS connection for now
  327. SensPrintA(SENS_INFO, ("\tConnection name: %s\n", pRasConn->szEntryName));
  328. wcscpy(szEntryName, pRasConn->szEntryName);
  329. }
  330. else
  331. {
  332. if (dwRasStatus != 0)
  333. {
  334. *lpdwLastError = dwRasStatus;
  335. }
  336. SensPrintA(SENS_ERR, ("RasEnumConnections() returned %d - "
  337. "connections (%d)\n", dwRasStatus, cConnections));
  338. }
  339. // Delete the RASCONN structure.
  340. delete pRasConn;
  341. } // if (bRasInstalled)
  342. SensPrintA(SENS_INFO, ("EvaluateWanConnectivity() returning %s, GLE of %d\n",
  343. bWanAlive ? "TRUE" : "FALSE", *lpdwLastError));
  344. if (InterlockedExchange(&gdwWANState, bWanAlive) != bWanAlive)
  345. {
  346. //
  347. // WAN Connectivity state changed.
  348. //
  349. BOOL bSuccess;
  350. DWORD dwActiveWanInterfaceSpeed;
  351. DWORD dwLastError;
  352. SENSEVENT_NETALIVE Data;
  353. dwLastError = ERROR_SUCCESS;
  354. dwActiveWanInterfaceSpeed = 0x0;
  355. if (bWanAlive)
  356. {
  357. bSuccess = GetActiveWanInterfaceStatistics(
  358. &dwLastError,
  359. &dwActiveWanInterfaceSpeed
  360. );
  361. #ifdef SENS_NT5
  362. // Will always fire on NT4/Win9x (due to bugs). Can fire on NT5.
  363. SensPrintA(SENS_WARN, ("GetActiveWanInterfaceStatistics() returned"
  364. " FALSE, using defaults!\n"));
  365. #endif // SENS_NT5
  366. }
  367. Data.eType = SENS_EVENT_NETALIVE;
  368. Data.bAlive = bWanAlive;
  369. memset(&Data.QocInfo, 0x0, sizeof(QOCINFO));
  370. Data.QocInfo.dwSize = sizeof(QOCINFO);
  371. Data.QocInfo.dwFlags = NETWORK_ALIVE_WAN;
  372. Data.QocInfo.dwInSpeed = dwActiveWanInterfaceSpeed;
  373. Data.QocInfo.dwOutSpeed = dwActiveWanInterfaceSpeed;
  374. Data.strConnection = szEntryName;
  375. UpdateSensCache(WAN);
  376. SensFireEvent((PVOID)&Data);
  377. }
  378. if (bWanAlive)
  379. {
  380. InterlockedExchange(&gdwLastWANTime, dwNow);
  381. }
  382. else
  383. {
  384. InterlockedExchange(&gdwLastWANTime, 0x0);
  385. }
  386. SensPrintA(SENS_INFO, ("RasEventNotifyRoutine(%d) - WAN Time is %d msec\n", dwNow, gdwLastWANTime));
  387. delete szEntryName;
  388. return bWanAlive;
  389. }