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.

655 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 - 98, Microsoft Corporation
  3. Module Name:
  4. rtmmain.c
  5. Abstract:
  6. Contains routines that are invoked when
  7. the RTMv2 DLL is loaded or unloaded.
  8. Author:
  9. Chaitanya Kodeboyina (chaitk) 17-Aug-1998
  10. Revision History:
  11. --*/
  12. #include "pchrtm.h"
  13. #pragma hdrstop
  14. // All Global variables
  15. RTMP_GLOBAL_INFO RtmGlobals;
  16. BOOL
  17. WINAPI
  18. DllMain(
  19. IN HINSTANCE Instance,
  20. IN DWORD Reason,
  21. IN PVOID Unused
  22. )
  23. /*++
  24. Routine Description:
  25. This is the DLL's main entrypoint handler which
  26. initializes RTMv1, RTMv2 and MGM components.
  27. Arguments:
  28. None
  29. Return Value:
  30. TRUE if successful, FALSE if not
  31. --*/
  32. {
  33. static BOOL Rtmv1Initialized = FALSE;
  34. static BOOL RtmInitialized = FALSE;
  35. static BOOL MgmInitialized = FALSE;
  36. BOOL Success;
  37. UNREFERENCED_PARAMETER(Unused);
  38. Success = FALSE;
  39. switch(Reason)
  40. {
  41. case DLL_PROCESS_ATTACH:
  42. DisableThreadLibraryCalls(Instance);
  43. //
  44. // Initialize the RTMv1, RTMv2 and MGM APIs
  45. //
  46. Rtmv1Initialized = Rtmv1DllStartup(Instance);
  47. if (Rtmv1Initialized)
  48. {
  49. RtmInitialized = RtmDllStartup();
  50. if (RtmInitialized)
  51. {
  52. MgmInitialized = MgmDllStartup();
  53. }
  54. }
  55. return MgmInitialized;
  56. case DLL_PROCESS_DETACH:
  57. //
  58. // Cleanup the MGM, RTMv2 and RTMv1 APIs
  59. //
  60. if (MgmInitialized)
  61. {
  62. MgmDllCleanup();
  63. }
  64. if (RtmInitialized)
  65. {
  66. Success = RtmDllCleanup();
  67. }
  68. if (Rtmv1Initialized)
  69. {
  70. Rtmv1DllCleanup();
  71. }
  72. break;
  73. default:
  74. Success = TRUE;
  75. break;
  76. }
  77. return Success;
  78. }
  79. BOOL
  80. RtmDllStartup(
  81. VOID
  82. )
  83. /*++
  84. Routine Description:
  85. Called by DLL Main when the process is attached.
  86. We do minimal initialization here like creating
  87. a lock that protects all globals (including the
  88. 'ApiInitialized' -- see RtmRegisterEntity func).
  89. Arguments:
  90. None
  91. Return Value:
  92. TRUE if successful, FALSE if not
  93. --*/
  94. {
  95. //
  96. // One can safely assume that globals have been set to 0
  97. //
  98. // ZeroMemory(&RtmGlobals, sizeof(RTMP_GLOBAL_INFO));
  99. //
  100. // Initialize lock to guard the global table of instances
  101. //
  102. try
  103. {
  104. CREATE_READ_WRITE_LOCK(&RtmGlobals.InstancesLock);
  105. }
  106. except(EXCEPTION_EXECUTE_HANDLER)
  107. {
  108. return FALSE;
  109. }
  110. return TRUE;
  111. }
  112. DWORD
  113. RtmApiStartup(
  114. VOID
  115. )
  116. /*++
  117. Routine Description:
  118. Initializes most global data structures in RTMv2.
  119. We initialize most variables here instead of in
  120. RtmDllStartup as it might not be safe to perform
  121. some operations in the context of DLL's DLLMain.
  122. For example, if we find no config information, we
  123. set up default config information in the registry.
  124. This function is called when the first RTMv2 API
  125. call, which is typically an entity registration,
  126. is made. See the invocation in RtmRegisterEntity.
  127. Arguments:
  128. None
  129. Return Value:
  130. Status of the operation
  131. --*/
  132. {
  133. RTM_INSTANCE_CONFIG InstanceConfig;
  134. BOOL ListLockInited;
  135. DWORD Status;
  136. UINT i;
  137. ListLockInited = FALSE;
  138. Status = NO_ERROR;
  139. ACQUIRE_INSTANCES_WRITE_LOCK();
  140. do
  141. {
  142. //
  143. // If API has already been initialized, work is done
  144. //
  145. if (RtmGlobals.ApiInitialized)
  146. {
  147. break;
  148. }
  149. //
  150. // Enable logging and tracing for debugging purposes
  151. //
  152. START_TRACING();
  153. START_LOGGING();
  154. #if DBG_TRACE
  155. RtmGlobals.TracingFlags = RTM_TRACE_ANY;
  156. #endif
  157. #if DBG_MEM
  158. //
  159. // Init a lock & list to hold mem allocs
  160. //
  161. try
  162. {
  163. InitializeCriticalSection(&RtmGlobals.AllocsLock);
  164. ListLockInited = TRUE;
  165. }
  166. except(EXCEPTION_EXECUTE_HANDLER)
  167. {
  168. Status = GetLastError();
  169. Trace1(ANY,
  170. "RTMApiStartup : Failed to init a critical section %x",
  171. Status);
  172. LOGERR0(INIT_CRITSEC_FAILED, Status);
  173. break;
  174. }
  175. InitializeListHead(&RtmGlobals.AllocsList);
  176. #endif
  177. //
  178. // Create a private heap for RTM's use
  179. //
  180. RtmGlobals.GlobalHeap = HeapCreate(0, 0, 0);
  181. if (RtmGlobals.GlobalHeap == NULL)
  182. {
  183. Status = GetLastError();
  184. Trace1(ANY,
  185. "RtmApiStartup: Failed to create a global private heap %x",
  186. Status);
  187. LOGERR0(HEAP_CREATE_FAILED, Status);
  188. break;
  189. }
  190. //
  191. // Initialize the root of RTM's registry information
  192. //
  193. RtmGlobals.RegistryPath = AllocNZeroMemory(MAX_CONFIG_KEY_SIZE);
  194. if (RtmGlobals.RegistryPath == NULL)
  195. {
  196. Status = ERROR_NOT_ENOUGH_MEMORY;
  197. break;
  198. }
  199. CopyMemory(RtmGlobals.RegistryPath,
  200. RTM_CONFIG_ROOT,
  201. RTM_CONFIG_ROOT_SIZE);
  202. //
  203. // Initialize the global hash table of RTM instances
  204. //
  205. RtmGlobals.NumInstances = 0;
  206. for (i = 0; i < INSTANCE_TABLE_SIZE; i++)
  207. {
  208. InitializeListHead(&RtmGlobals.InstanceTable[i]);
  209. }
  210. //
  211. // You need to set this value to TRUE to avoid
  212. // any more recursive calls into this function
  213. //
  214. RtmGlobals.ApiInitialized = TRUE;
  215. //
  216. // Read config info if present ; else pick default
  217. //
  218. Status = RtmReadInstanceConfig(DEFAULT_INSTANCE_ID, &InstanceConfig);
  219. if (Status != NO_ERROR)
  220. {
  221. Status = RtmWriteDefaultConfig(DEFAULT_INSTANCE_ID);
  222. if (Status != NO_ERROR)
  223. {
  224. break;
  225. }
  226. }
  227. }
  228. while (FALSE);
  229. if (Status != NO_ERROR)
  230. {
  231. //
  232. // Some error occured - clean up and return the error code
  233. //
  234. if (RtmGlobals.RegistryPath != NULL)
  235. {
  236. FreeMemory(RtmGlobals.RegistryPath);
  237. }
  238. if (RtmGlobals.GlobalHeap != NULL)
  239. {
  240. HeapDestroy(RtmGlobals.GlobalHeap);
  241. }
  242. #if DBG_MEM
  243. if (ListLockInited)
  244. {
  245. DeleteCriticalSection(&RtmGlobals.AllocsLock);
  246. }
  247. #endif
  248. STOP_LOGGING();
  249. STOP_TRACING();
  250. //
  251. // We had prematurely set the value to TRUE above, reset it
  252. //
  253. RtmGlobals.ApiInitialized = FALSE;
  254. }
  255. RELEASE_INSTANCES_WRITE_LOCK();
  256. return Status;
  257. }
  258. BOOL
  259. RtmDllCleanup(
  260. VOID
  261. )
  262. /*++
  263. Routine Description:
  264. Cleans up all global data structures at unload time.
  265. Arguments:
  266. None
  267. Return Value:
  268. TRUE if successful, FALSE if not
  269. --*/
  270. {
  271. PINSTANCE_INFO Instance;
  272. PLIST_ENTRY Instances, p, r;
  273. UINT NumInstances;
  274. PADDRFAM_INFO AddrFamilyInfo;
  275. PLIST_ENTRY AddrFamilies, q;
  276. PENTITY_INFO Entity;
  277. PLIST_ENTRY Entities, s;
  278. UINT NumEntities;
  279. UINT i, j, k, l;
  280. //
  281. // Do we have any instances and associated ref counts left ?
  282. //
  283. if (RtmGlobals.NumInstances != 0)
  284. {
  285. //
  286. // We need to stop all outstanding timers
  287. // on every address family as the RTM DLL
  288. // gets unloaded after this call returns.
  289. // We also forcefully destroy entities &
  290. // address families to reclaim resources.
  291. //
  292. ACQUIRE_INSTANCES_WRITE_LOCK();
  293. NumInstances = RtmGlobals.NumInstances;
  294. for (i = j = 0; i < INSTANCE_TABLE_SIZE; i++)
  295. {
  296. Instances = &RtmGlobals.InstanceTable[i];
  297. for (p = Instances->Flink; p != Instances; p = r)
  298. {
  299. Instance = CONTAINING_RECORD(p, INSTANCE_INFO, InstTableLE);
  300. AddrFamilies = &Instance->AddrFamilyTable;
  301. #if WRN
  302. r = p->Flink;
  303. #endif
  304. for (q = AddrFamilies->Flink; q != AddrFamilies; )
  305. {
  306. AddrFamilyInfo =
  307. CONTAINING_RECORD(q, ADDRFAM_INFO, AFTableLE);
  308. //
  309. // Holding the instances lock while deleting
  310. // timer queues (using blocking calls) can
  311. // result in a deadlock, so just reference
  312. // the address family and release the lock.
  313. //
  314. // Ref address family so that it does not disappear
  315. REFERENCE_ADDR_FAMILY(AddrFamilyInfo, TEMP_USE_REF);
  316. RELEASE_INSTANCES_WRITE_LOCK();
  317. //
  318. // Block until timers on address family are cleaned up
  319. //
  320. if (AddrFamilyInfo->RouteTimerQueue)
  321. {
  322. DeleteTimerQueueEx(AddrFamilyInfo->RouteTimerQueue,
  323. (HANDLE) -1);
  324. AddrFamilyInfo->RouteTimerQueue = NULL;
  325. }
  326. if (AddrFamilyInfo->NotifTimerQueue)
  327. {
  328. DeleteTimerQueueEx(AddrFamilyInfo->NotifTimerQueue,
  329. (HANDLE) -1);
  330. AddrFamilyInfo->NotifTimerQueue = NULL;
  331. }
  332. //
  333. // We assume that we have no other code paths that
  334. // access any data structures on this addr family
  335. //
  336. //
  337. // Force destroy each entity on the address family
  338. //
  339. NumEntities = AddrFamilyInfo->NumEntities;
  340. for (k = l = 0; k < ENTITY_TABLE_SIZE; k++)
  341. {
  342. Entities = &AddrFamilyInfo->EntityTable[k];
  343. for (s = Entities->Flink; s != Entities; )
  344. {
  345. Entity =
  346. CONTAINING_RECORD(s, ENTITY_INFO, EntityTableLE);
  347. s = s->Flink;
  348. // To satisfy the asserts in DestroyEntity
  349. Entity->ObjectHeader.RefCount = 0;
  350. DestroyEntity(Entity);
  351. l++;
  352. }
  353. if (l == NumEntities)
  354. {
  355. break;
  356. }
  357. }
  358. //
  359. // Also destroy entities that have deregistered
  360. // but haven't been destroyed due to ref counts
  361. //
  362. while (!IsListEmpty(&AddrFamilyInfo->DeregdEntities))
  363. {
  364. Entity =
  365. CONTAINING_RECORD(AddrFamilyInfo->DeregdEntities.Flink,
  366. ENTITY_INFO,
  367. EntityTableLE);
  368. // To satisfy the asserts in DestroyEntity
  369. Entity->ObjectHeader.RefCount = 0;
  370. DestroyEntity(Entity);
  371. }
  372. ACQUIRE_INSTANCES_WRITE_LOCK();
  373. // Get next address family before de-ref-ing current
  374. q = q->Flink;
  375. // Get next instance also as it might be deleted too
  376. r = p->Flink;
  377. // Remove the temporary reference use added earlier
  378. DEREFERENCE_ADDR_FAMILY(AddrFamilyInfo, TEMP_USE_REF);
  379. }
  380. j++;
  381. }
  382. if (j == NumInstances)
  383. {
  384. break;
  385. }
  386. }
  387. RELEASE_INSTANCES_WRITE_LOCK();
  388. }
  389. // We have freed all instances to avoid any leaks
  390. ASSERT(RtmGlobals.NumInstances == 0);
  391. //
  392. // Free resources allocated like locks and memory
  393. //
  394. if (RtmGlobals.ApiInitialized)
  395. {
  396. FreeMemory(RtmGlobals.RegistryPath);
  397. //
  398. // At this point we might have whole lots of dests,
  399. // routes, nexthops etc. that are have not been
  400. // freed because of outstanding ref counts; however
  401. // none of these objects have any locks (except
  402. // dest locks which are dynamic anyway and can
  403. // be unlocked and freed after deregistration),
  404. // so we can just blow the heap to reclaim memory.
  405. //
  406. HeapDestroy(RtmGlobals.GlobalHeap);
  407. #if DBG_MEM
  408. DeleteCriticalSection(&RtmGlobals.AllocsLock);
  409. #endif
  410. //
  411. // Stop debugging aids like tracing and logging
  412. //
  413. STOP_LOGGING();
  414. STOP_TRACING();
  415. }
  416. DELETE_READ_WRITE_LOCK(&RtmGlobals.InstancesLock);
  417. return TRUE;
  418. }
  419. #if DBG_MEM
  420. VOID
  421. DumpAllocs (VOID)
  422. /*++
  423. Routine Description:
  424. Debug tool to dump all objects that are
  425. allocated by RTMv2 at any instant.
  426. Arguments:
  427. None
  428. Return Value:
  429. None
  430. --*/
  431. {
  432. POBJECT_HEADER Object;
  433. PLIST_ENTRY p;
  434. UINT i;
  435. printf("\n\n----------------Allocs Left Over------------------------\n");
  436. ACQUIRE_ALLOCS_LIST_LOCK();
  437. for (p = RtmGlobals.AllocsList.Flink;
  438. p != &RtmGlobals.AllocsList;
  439. p = p->Flink)
  440. {
  441. Object = CONTAINING_RECORD(p, OBJECT_HEADER, AllocLE);
  442. printf("Object @ %p: \n", Object);
  443. #if DBG_HDL
  444. printf("Object Signature = %c%c%c%c\n",
  445. Object->Type,
  446. Object->Signature[0],
  447. Object->Signature[1],
  448. Object->Alloc);
  449. #endif
  450. #if DBG_REF
  451. printf("Object RefCounts: \n");
  452. for (i = 0; i < MAX_REFS; i++)
  453. {
  454. printf("%2lu", Object->RefTypes[i]);
  455. }
  456. #endif
  457. printf("\n");
  458. }
  459. RELEASE_ALLOCS_LIST_LOCK();
  460. printf("\n--------------------------------------------------------\n\n");
  461. }
  462. #endif