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.

642 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. config.c
  5. Abstract:
  6. DNS Resolver Service.
  7. Network configuration info
  8. Author:
  9. Jim Gilroy (jamesg) March 2000
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. //
  14. // Network info
  15. //
  16. PDNS_NETINFO g_NetworkInfo = NULL;
  17. DWORD g_TimeOfLastPnPUpdate;
  18. DWORD g_NetInfoTag = 0;
  19. DWORD g_ResetServerPriorityTime = 0;
  20. //
  21. // Network failure caching
  22. //
  23. DWORD g_NetFailureTime;
  24. DNS_STATUS g_NetFailureStatus;
  25. DWORD g_TimedOutAdapterTime;
  26. BOOL g_fTimedOutAdapter;
  27. DNS_STATUS g_PreviousNetFailureStatus;
  28. DWORD g_MessagePopupStrikes;
  29. DWORD g_NumberOfMessagePopups;
  30. //
  31. // Config globals
  32. //
  33. // DCR: eliminate useless config globals
  34. //
  35. DWORD g_HashTableSize;
  36. DWORD g_MaxSOACacheEntryTtlLimit;
  37. DWORD g_NegativeSOACacheTime;
  38. DWORD g_NetFailureCacheTime;
  39. DWORD g_MessagePopupLimit;
  40. //
  41. // Network Info reread time
  42. // - currently fifteen minutes
  43. //
  44. #define NETWORK_INFO_REREAD_TIME (900)
  45. //
  46. // Network info configuration
  47. //
  48. VOID
  49. UpdateNetworkInfo(
  50. IN PDNS_NETINFO pNetInfo OPTIONAL
  51. )
  52. /*++
  53. Routine Description:
  54. Update network info global.
  55. Arguments:
  56. pNetInfo -- desired network info; if NULL clear cached copy
  57. Return Value:
  58. None
  59. --*/
  60. {
  61. PDNS_NETINFO poldInfo = NULL;
  62. DNSDBG( TRACE, (
  63. "UpdateNetworkInfo( %p )\n",
  64. pNetInfo ));
  65. LOCK_NET_LIST();
  66. //
  67. // cache previous netinfo to pickup server priority changes
  68. // - don't cache if not same version
  69. // - kills copy that was created before last build
  70. // - kills copy that was before last PnP (cache clear)
  71. // - don't cache if never reset priorities
  72. //
  73. if ( pNetInfo )
  74. {
  75. if ( pNetInfo->Tag != g_NetInfoTag )
  76. {
  77. DNSDBG( INIT, (
  78. "Skip netinfo update -- previous version"
  79. "\tptr = %p\n"
  80. "\tversion = %d\n"
  81. "\tcurrent version = %d\n",
  82. pNetInfo,
  83. pNetInfo->Tag,
  84. g_NetInfoTag ));
  85. poldInfo = pNetInfo;
  86. DNS_ASSERT( pNetInfo->Tag < g_NetInfoTag );
  87. goto Cleanup;
  88. }
  89. if ( g_ServerPriorityTimeLimit == 0 )
  90. {
  91. DNSDBG( INIT, (
  92. "Skip netinfo update -- no priority reset!\n" ));
  93. poldInfo = pNetInfo;
  94. goto Cleanup;
  95. }
  96. NetInfo_Clean(
  97. pNetInfo,
  98. CLEAR_LEVEL_QUERY
  99. );
  100. }
  101. //
  102. // no netinfo means clear cached copy
  103. // - push up tag count, so no copy out for update can
  104. // come back and be reused through path above
  105. else
  106. {
  107. g_NetInfoTag++;
  108. }
  109. //
  110. // swap -- caches copy or clears
  111. //
  112. poldInfo = g_NetworkInfo;
  113. g_NetworkInfo = pNetInfo;
  114. Cleanup:
  115. UNLOCK_NET_LIST();
  116. NetInfo_Free( poldInfo );
  117. }
  118. PDNS_NETINFO
  119. GrabNetworkInfo(
  120. VOID
  121. )
  122. /*++
  123. Routine Description:
  124. Get copy of network info.
  125. Named it "Grab" to avoid confusion with GetNetworkInfo()
  126. in dnsapi.dll.
  127. Arguments:
  128. None
  129. Return Value:
  130. Ptr to copy of network info (caller must free).
  131. NULL on error.
  132. --*/
  133. {
  134. PDNS_NETINFO poldInfo = NULL;
  135. PDNS_NETINFO pnewInfo = NULL;
  136. DWORD currentTime = Dns_GetCurrentTimeInSeconds();
  137. DNSDBG( TRACE, ( "GrabNetworkInfo()\n" ));
  138. //
  139. // check for valid network info global
  140. // - within forced reread time
  141. // - reset server priorities if
  142. //
  143. LOCK_NET_LIST();
  144. if ( g_NetworkInfo &&
  145. g_NetworkInfo->TimeStamp + NETWORK_INFO_REREAD_TIME > currentTime )
  146. {
  147. if ( g_ResetServerPriorityTime < currentTime )
  148. {
  149. NetInfo_ResetServerPriorities( g_NetworkInfo, TRUE );
  150. g_ResetServerPriorityTime = currentTime + g_ServerPriorityTimeLimit;
  151. }
  152. }
  153. //
  154. // current global expired
  155. // - build new netinfo
  156. // - tag it with unique monotonically increasing id
  157. // this makes sure we never use older version
  158. // - push forward priorities reset time
  159. // - make newinfo the global copy
  160. //
  161. // Do not hold lock during build
  162. // - IpHlpApi doing routing info call RPCs to router which can
  163. // depend on PnP notifications, which in turn can be causing calls
  164. // back into resolver indicating config change; overall the loss
  165. // of control is too large
  166. //
  167. //
  168. // Two separate issues:
  169. //
  170. // There are ways to make the config change issue go away (ex setting
  171. // some sort of "invalid" flag under interlock), but they basically boil
  172. // down to introducing some other sort of lock.
  173. //
  174. // The bottom line is there are two separate issues here:
  175. // 1) Access to cache netinfo, which may be invalidated.
  176. // 2) Single build of netinfo for perf.
  177. //
  178. // Implementation wise, you can have the invalidation\clear under a
  179. // separate interlock, and thus have a single lock for copy-access\build,
  180. // but the reality is the same.
  181. //
  182. //
  183. // Solution
  184. // - get our tag first
  185. // - clear lock
  186. // - make build call
  187. // - on return check that tag is still valid, if not we can
  188. // USE the result, but we don't cache it, as the global tag
  189. // could be higher because of config change, and in any case
  190. // we let the last builder win
  191. //
  192. // DCR: netinfo build lock for perf, independent of protecting global
  193. // could have "timed-lock" using event that waits for a short interval to
  194. // to try to allow first guy to complete
  195. //
  196. else
  197. {
  198. DWORD newTag = ++g_NetInfoTag;
  199. UNLOCK_NET_LIST();
  200. pnewInfo = NetInfo_Build( TRUE );
  201. if ( !pnewInfo )
  202. {
  203. DNSDBG( ANY, ( "ERROR: GrabNetworkInfo() failed -- no netinfo blob!\n" ));
  204. goto Done;
  205. }
  206. LOCK_NET_LIST();
  207. pnewInfo->Tag = newTag;
  208. if ( newTag != g_NetInfoTag )
  209. {
  210. DNS_ASSERT( newTag < g_NetInfoTag );
  211. DNSDBG( ANY, (
  212. "WARNING: New netinfo uncacheable -- tag is old!\n"
  213. "\tour tag = %d\n"
  214. "\tcurrent tag = %d\n",
  215. newTag,
  216. g_NetInfoTag ));
  217. goto Unlock;
  218. }
  219. // if tag still current cache this new netinfo
  220. g_ResetServerPriorityTime = currentTime + g_ServerPriorityTimeLimit;
  221. g_TimedOutAdapterTime = 0;
  222. g_fTimedOutAdapter = FALSE;
  223. poldInfo = g_NetworkInfo;
  224. g_NetworkInfo = pnewInfo;
  225. }
  226. //
  227. // make copy of global (new or reset)
  228. //
  229. pnewInfo = NetInfo_Copy( g_NetworkInfo );
  230. Unlock:
  231. UNLOCK_NET_LIST();
  232. NetInfo_Free( poldInfo );
  233. Done:
  234. return pnewInfo;
  235. }
  236. VOID
  237. ZeroNetworkConfigGlobals(
  238. VOID
  239. )
  240. /*++
  241. Routine Description:
  242. Zero init network globals.
  243. Arguments:
  244. None
  245. Return Value:
  246. None
  247. --*/
  248. {
  249. // net failure
  250. g_NetFailureTime = 0;
  251. g_NetFailureStatus = NO_ERROR;
  252. g_PreviousNetFailureStatus = NO_ERROR;
  253. g_fTimedOutAdapter = FALSE;
  254. g_TimedOutAdapterTime = 0;
  255. g_MessagePopupStrikes = 0;
  256. g_NumberOfMessagePopups = 0;
  257. // network info
  258. g_TimeOfLastPnPUpdate = 0;
  259. g_NetworkInfo = NULL;
  260. }
  261. VOID
  262. CleanupNetworkInfo(
  263. VOID
  264. )
  265. /*++
  266. Routine Description:
  267. Cleanup network info.
  268. Arguments:
  269. None
  270. Return Value:
  271. None
  272. --*/
  273. {
  274. LOCK_NET_LIST();
  275. if ( g_NetworkInfo )
  276. {
  277. NetInfo_Free( g_NetworkInfo );
  278. g_NetworkInfo = NULL;
  279. }
  280. UNLOCK_NET_LIST();
  281. }
  282. //
  283. // General configuration
  284. //
  285. VOID
  286. ReadRegistryConfig(
  287. VOID
  288. )
  289. {
  290. //
  291. // re-read full DNS registry info
  292. //
  293. Reg_ReadGlobalsEx( 0, NULL );
  294. //
  295. // set "we are the resolver" global
  296. //
  297. g_InResolver = TRUE;
  298. //
  299. // just default old config globals until remove
  300. //
  301. // DCR: status of old config globals?
  302. //
  303. g_MaxSOACacheEntryTtlLimit = DNS_DEFAULT_MAX_SOA_TTL_LIMIT;
  304. g_NegativeSOACacheTime = DNS_DEFAULT_NEGATIVE_SOA_CACHE_TIME;
  305. g_NetFailureCacheTime = DNS_DEFAULT_NET_FAILURE_CACHE_TIME;
  306. g_HashTableSize = DNS_DEFAULT_HASH_TABLE_SIZE;
  307. g_MessagePopupLimit = DNS_DEFAULT_MESSAGE_POPUP_LIMIT;
  308. }
  309. VOID
  310. HandleConfigChange(
  311. IN PSTR pszReason,
  312. IN BOOL fCacheFlush
  313. )
  314. /*++
  315. Routine Description:
  316. Response to configuration change.
  317. Arguments:
  318. fCache_Flush -- flush if config change requires cache flush
  319. Return Value:
  320. None
  321. --*/
  322. {
  323. DNSDBG( INIT, (
  324. "\n"
  325. "HandleConfigChange() => %s\n"
  326. "\tflush = %d\n",
  327. pszReason,
  328. fCacheFlush ));
  329. //
  330. // lock out all work while tear down everything
  331. // - lock with no start option so if we are already torn
  332. // down we don't rebuild
  333. // - optionally flush cache
  334. // - dump IP list
  335. // - dump network info
  336. //
  337. LOCK_CACHE_NO_START();
  338. //
  339. // cache flush?
  340. //
  341. // all config changes don't necessarily require cache flush;
  342. // if not required just rebuild local list and config
  343. //
  344. if ( fCacheFlush )
  345. {
  346. Cache_Flush();
  347. }
  348. else
  349. {
  350. ClearLocalAddrArray();
  351. }
  352. //
  353. // clear network info
  354. // save PnP time
  355. // clear net failure flags
  356. //
  357. UpdateNetworkInfo( NULL );
  358. g_TimeOfLastPnPUpdate = Dns_GetCurrentTimeInSeconds();
  359. g_NetFailureTime = 0;
  360. g_NetFailureStatus = NO_ERROR;
  361. DNSDBG( INIT, (
  362. "Leave HandleConfigChange() => %s\n"
  363. "\tflush = %d\n\n",
  364. pszReason,
  365. fCacheFlush ));
  366. UNLOCK_CACHE();
  367. }
  368. //
  369. // Remote APIs
  370. //
  371. VOID
  372. R_ResolverGetConfig(
  373. IN DNS_RPC_HANDLE Handle,
  374. IN DWORD Cookie,
  375. OUT PRPC_DNS_NETINFO * ppNetInfo,
  376. OUT PDNS_GLOBALS_BLOB * ppGlobals
  377. )
  378. /*++
  379. Routine Description:
  380. Make the query to remote DNS server.
  381. Arguments:
  382. Handle -- RPC handle
  383. Cookie -- cookie of last succesful config transfer
  384. zero indicates no previous successful transfer
  385. ppNetInfo -- addr to receive ptr to network info
  386. ppGlobals -- addr to receive ptr to globals blob
  387. Return Value:
  388. None
  389. --*/
  390. {
  391. PDNS_GLOBALS_BLOB pblob;
  392. DNSLOG_F1( "R_ResolverGetConfig" );
  393. DNSDBG( RPC, (
  394. "R_ResolverGetConfig\n"
  395. "\tcookie = %p\n",
  396. Cookie ));
  397. if ( !ppNetInfo || !ppGlobals )
  398. {
  399. return;
  400. }
  401. //
  402. // DCR: config cookie check
  403. // - no need to get data if client has current copy
  404. //
  405. //
  406. // copy network info global
  407. //
  408. // note: currently RPC is using same allocator (dnslib)
  409. // as GrabNetworkInfo(); so we are ok just passing
  410. // NETINFO blob as is
  411. //
  412. // note: could build on "no-global" but since we create on
  413. // cache start we should always have global or be
  414. // just starting
  415. //
  416. *ppNetInfo = (PRPC_DNS_NETINFO) GrabNetworkInfo();
  417. pblob = (PDNS_GLOBALS_BLOB) RPC_HEAP_ALLOC( sizeof(*pblob) );
  418. if ( pblob )
  419. {
  420. RtlCopyMemory(
  421. pblob,
  422. & DnsGlobals,
  423. sizeof(DnsGlobals) );
  424. // clear "in resolver" flag
  425. pblob->InResolver = FALSE;
  426. }
  427. *ppGlobals = pblob;
  428. DNSDBG( RPC, ( "Leave R_ResolverGetConfig\n\n" ));
  429. }
  430. VOID
  431. R_ResolverPoke(
  432. IN DNS_RPC_HANDLE Handle,
  433. IN DWORD Cookie,
  434. IN DWORD Id
  435. )
  436. /*++
  437. Routine Description:
  438. Test interface to poke resolver to update.
  439. Arguments:
  440. Handle -- RPC handle
  441. Cookie -- cookie
  442. Id -- operation Id
  443. Return Value:
  444. None
  445. --*/
  446. {
  447. DNSLOG_F1( "R_ResolverPoke" );
  448. DNSDBG( RPC, (
  449. "R_ResolverPoke\n"
  450. "\tcookie = %08x\n"
  451. "\tid = %d\n",
  452. Cookie,
  453. Id ));
  454. //
  455. // do operation for particular id
  456. // - update netinfo clears cached copy
  457. if ( Id == POKE_OP_UPDATE_NETINFO )
  458. {
  459. if ( Cookie == POKE_COOKIE_UPDATE_NETINFO )
  460. {
  461. UpdateNetworkInfo( NULL );
  462. }
  463. }
  464. }
  465. //
  466. // End config.c
  467. //