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.

471 lines
12 KiB

  1. /*++
  2. Copyright (c) 1999, Microsoft Corporation
  3. Module Name:
  4. sample\configurationmanager.c
  5. Abstract:
  6. The file contains global configuration related functions,
  7. implementing the configuration manager.
  8. --*/
  9. #include "pchsample.h"
  10. #pragma hdrstop
  11. // global variables...
  12. CONFIGURATION_ENTRY g_ce;
  13. // functions...
  14. BOOL
  15. ValidateGlobalConfig (
  16. IN PIPSAMPLE_GLOBAL_CONFIG pigc)
  17. /*++
  18. Routine Description
  19. Checks to see if the global configuration is OK. It is good practice to
  20. do this because a corrupt registry can change configuration causing all
  21. sorts of debugging headaches if it is not found early
  22. Locks
  23. None
  24. Arguments
  25. pigc pointer to ip sample's global configuration
  26. Return Value
  27. TRUE if the configuration is good
  28. FALSE o/w
  29. --*/
  30. {
  31. DWORD dwErr = NO_ERROR;
  32. do // breakout loop
  33. {
  34. if (pigc is NULL)
  35. {
  36. dwErr = ERROR_INVALID_PARAMETER;
  37. TRACE0(CONFIGURATION, "Error null global config");
  38. break;
  39. }
  40. //
  41. // check range of each field
  42. //
  43. // ensure that the logging level is within bounds
  44. if((pigc->dwLoggingLevel < IPSAMPLE_LOGGING_NONE) or
  45. (pigc->dwLoggingLevel > IPSAMPLE_LOGGING_INFO))
  46. {
  47. dwErr = ERROR_INVALID_PARAMETER;
  48. TRACE0(CONFIGURATION, "Error log level out of range");
  49. break;
  50. }
  51. // add more here...
  52. } while (FALSE);
  53. if (!(dwErr is NO_ERROR))
  54. {
  55. TRACE0(CONFIGURATION, "Error corrupt global config");
  56. LOGERR0(CORRUPT_GLOBAL_CONFIG, dwErr);
  57. return FALSE;
  58. }
  59. return TRUE;
  60. }
  61. ////////////////////////////////////////
  62. // WORKERFUNCTIONS
  63. ////////////////////////////////////////
  64. VOID
  65. CM_WorkerFinishStopProtocol (
  66. IN PVOID pvContext)
  67. /*++
  68. Routine Description
  69. WORKERFUNCTION. Queued by CM_StopProtocol.
  70. Waits for all active and queued threads to exit and cleans up
  71. configuration entry.
  72. Locks
  73. Acquires exclusively g_ce.rwlLock
  74. Releases g_ce.rwlLock
  75. Arguments
  76. pvContext ulActivityCount
  77. Return Value
  78. None
  79. --*/
  80. {
  81. DWORD dwErr = NO_ERROR;
  82. MESSAGE mMessage;
  83. ULONG ulThreadCount = 0;
  84. ulThreadCount = (ULONG)pvContext;
  85. TRACE1(ENTER, "Entering WorkerFinishStopProtocol: active threads %u",
  86. ulThreadCount);
  87. // NOTE: since this is called while the router is stopping, there is no
  88. // need for it to use ENTER_SAMPLE_WORKER()/LEAVE_SAMPLE_WORKER()
  89. // waits for all threads to stop
  90. while (ulThreadCount-- > 0)
  91. WaitForSingleObject(g_ce.hActivitySemaphore, INFINITE);
  92. // acquire the lock and release it, just to be sure that all threads
  93. // have quit their calls to LeaveSampleWorker()
  94. ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
  95. RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
  96. // NOTE: there is no need to acquire g_ce.rwlLock for the call to
  97. // CE_Cleanup since there are no threads competing for access to the
  98. // fields being cleaned up. new competing threads aren't created till
  99. // CE_Cleanup sets the protocol state to IPSAMPLE_STATUS_STOPPED, which
  100. // is the last thing it does.
  101. CE_Cleanup(&g_ce, TRUE);
  102. LOGINFO0(SAMPLE_STOPPED, NO_ERROR);
  103. // inform router manager that we are done
  104. ZeroMemory(&mMessage, sizeof(MESSAGE));
  105. if (EnqueueEvent(ROUTER_STOPPED, mMessage) is NO_ERROR)
  106. SetEvent(g_ce.hMgrNotificationEvent);
  107. TRACE0(LEAVE, "Leaving WorkerFinishStopProtocol");
  108. }
  109. ////////////////////////////////////////
  110. // APIFUNCTIONS
  111. ////////////////////////////////////////
  112. DWORD
  113. CM_StartProtocol (
  114. IN HANDLE hMgrNotificationEvent,
  115. IN PSUPPORT_FUNCTIONS psfSupportFunctions,
  116. IN PVOID pvGlobalInfo)
  117. /*++
  118. Routine Description
  119. Called by StartProtocol. Initializes configuration entry.
  120. Locks
  121. Acquires exclusively g_ce.rwlLock
  122. Releases g_ce.rwlLock
  123. Arguments
  124. hMgrNotificationEvent event used to notify ip router manager
  125. psfSupportFunctions functions exported by ip router manager
  126. pvGlobalInfo global configuration set in registry
  127. Return Value
  128. NO_ERROR if successfully initiailzed
  129. Failure code o/w
  130. --*/
  131. {
  132. DWORD dwErr = NO_ERROR;
  133. // NOTE: since this is called when SAMPLE is stopped, there is no need
  134. // for it to use ENTER_SAMPLE_API()/LEAVE_SAMPLE_API()
  135. ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
  136. do // breakout loop
  137. {
  138. if (g_ce.iscStatus != IPSAMPLE_STATUS_STOPPED)
  139. {
  140. TRACE0(CONFIGURATION, "Error ip sample already installed");
  141. LOGWARN0(SAMPLE_ALREADY_STARTED, NO_ERROR);
  142. dwErr = ERROR_CAN_NOT_COMPLETE;
  143. break;
  144. }
  145. if (!ValidateGlobalConfig((PIPSAMPLE_GLOBAL_CONFIG) pvGlobalInfo))
  146. {
  147. dwErr = ERROR_INVALID_PARAMETER;
  148. break;
  149. }
  150. dwErr = CE_Initialize(&g_ce,
  151. hMgrNotificationEvent,
  152. psfSupportFunctions,
  153. (PIPSAMPLE_GLOBAL_CONFIG) pvGlobalInfo);
  154. } while (FALSE);
  155. RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
  156. if (dwErr is NO_ERROR)
  157. {
  158. TRACE0(CONFIGURATION, "ip sample has successfully started");
  159. LOGINFO0(SAMPLE_STARTED, dwErr);
  160. }
  161. else
  162. {
  163. TRACE1(CONFIGURATION, "Error ip sample failed to start", dwErr);
  164. LOGERR0(SAMPLE_START_FAILED, dwErr);
  165. }
  166. return dwErr;
  167. }
  168. DWORD
  169. CM_StopProtocol (
  170. )
  171. /*++
  172. Routine Description
  173. Called by StopProtocol. It queues a WORKERFUNCTION which waits for all
  174. active threads to exit and then cleans up the configuration entry.
  175. Locks
  176. Acquires exclusively g_ce.rwlLock
  177. Releases g_ce.rwlLock
  178. Arguments
  179. None
  180. Return Value
  181. ERROR_PROTOCOL_STOP_PENDING if successfully queued
  182. Failure code o/w
  183. --*/
  184. {
  185. DWORD dwErr = NO_ERROR;
  186. BOOL bSuccess = FALSE;
  187. ULONG ulThreadCount = 0;
  188. // NOTE: no need to use ENTER_SAMPLE_API()/LEAVE_SAMPLE_API()
  189. // Does not use QueueSampleWorker
  190. ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
  191. do // breakout loop
  192. {
  193. // cannot stop if already stopped
  194. if (g_ce.iscStatus != IPSAMPLE_STATUS_RUNNING)
  195. {
  196. TRACE0(CONFIGURATION, "Error ip sample already stopped");
  197. LOGWARN0(SAMPLE_ALREADY_STOPPED, NO_ERROR);
  198. dwErr = ERROR_CAN_NOT_COMPLETE;
  199. break;
  200. }
  201. // set IPSAMPLE's status to STOPPING; this prevents any more
  202. // work-items from being queued, and it prevents the ones already
  203. // queued from executing
  204. g_ce.iscStatus = IPSAMPLE_STATUS_STOPPING;
  205. // find out how many threads are either queued or active in SAMPLE;
  206. // we will have to wait for this many threads to exit before we
  207. // clean up SAMPLE's resources
  208. ulThreadCount = g_ce.ulActivityCount;
  209. TRACE1(CONFIGURATION,
  210. "%u threads are active in SAMPLE", ulThreadCount);
  211. } while (FALSE);
  212. RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
  213. if (dwErr is NO_ERROR)
  214. {
  215. bSuccess = QueueUserWorkItem(
  216. (LPTHREAD_START_ROUTINE)CM_WorkerFinishStopProtocol,
  217. (PVOID) ulThreadCount,
  218. 0); // no flags
  219. dwErr = (bSuccess) ? ERROR_PROTOCOL_STOP_PENDING : GetLastError();
  220. }
  221. return dwErr;
  222. }
  223. DWORD
  224. CM_GetGlobalInfo (
  225. IN PVOID pvGlobalInfo,
  226. IN OUT PULONG pulBufferSize,
  227. OUT PULONG pulStructureVersion,
  228. OUT PULONG pulStructureSize,
  229. OUT PULONG pulStructureCount)
  230. /*++
  231. Routine Description
  232. See if there's space enough to return ip sample global config. If yes,
  233. we return it, otherwise return the size needed.
  234. Locks
  235. Acquires shared g_ce.rwlLock
  236. Releases g_ce.rwlLock
  237. Arguments
  238. pvGlobalInfo pointer to allocated buffer to store our config
  239. pulBufferSize IN size of buffer received
  240. OUT size of our global config
  241. Return Value
  242. NO_ERROR if success
  243. Failure code o/w
  244. --*/
  245. {
  246. DWORD dwErr = NO_ERROR;
  247. PIPSAMPLE_GLOBAL_CONFIG pigc;
  248. ULONG ulSize = sizeof(IPSAMPLE_GLOBAL_CONFIG);
  249. if (!ENTER_SAMPLE_API()) { return ERROR_CAN_NOT_COMPLETE; }
  250. do // breakout loop
  251. {
  252. if((*pulBufferSize < ulSize) or (pvGlobalInfo is NULL))
  253. {
  254. // either the size was too small or there was no storage
  255. dwErr = ERROR_INSUFFICIENT_BUFFER;
  256. TRACE1(CONFIGURATION,
  257. "CM_GetGlobalInfo: *ulBufferSize %u",
  258. *pulBufferSize);
  259. *pulBufferSize = ulSize;
  260. break;
  261. }
  262. *pulBufferSize = ulSize;
  263. if (pulStructureVersion) *pulStructureVersion = 1;
  264. if (pulStructureSize) *pulStructureSize = ulSize;
  265. if (pulStructureCount) *pulStructureCount = 1;
  266. // so we have a good buffer to write our info into...
  267. pigc = (PIPSAMPLE_GLOBAL_CONFIG) pvGlobalInfo;
  268. // copy out the global configuration
  269. ACQUIRE_READ_LOCK(&(g_ce.rwlLock));
  270. pigc->dwLoggingLevel = g_ce.dwLogLevel;
  271. RELEASE_READ_LOCK(&(g_ce.rwlLock));
  272. } while (FALSE);
  273. LEAVE_SAMPLE_API();
  274. return dwErr;
  275. }
  276. DWORD
  277. CM_SetGlobalInfo (
  278. IN PVOID pvGlobalInfo)
  279. /*++
  280. Routine Description
  281. Set ip sample's global configuration.
  282. Locks
  283. Acquires exclusively g_ce.rwlLock
  284. Releases g_ce.rwlLock
  285. Arguments
  286. pvGlobalInfo buffer with new global configuration
  287. Return Value
  288. NO_ERROR if success
  289. Failure code o/w
  290. --*/
  291. {
  292. DWORD dwErr = NO_ERROR;
  293. PIPSAMPLE_GLOBAL_CONFIG pigc;
  294. if (!ENTER_SAMPLE_API()) { return ERROR_CAN_NOT_COMPLETE; }
  295. do // breakout loop
  296. {
  297. pigc = (PIPSAMPLE_GLOBAL_CONFIG) pvGlobalInfo;
  298. if (!ValidateGlobalConfig(pigc))
  299. {
  300. dwErr = ERROR_INVALID_PARAMETER;
  301. break;
  302. }
  303. // copy in the global configuration
  304. ACQUIRE_WRITE_LOCK(&(g_ce.rwlLock));
  305. g_ce.dwLogLevel = pigc->dwLoggingLevel;
  306. RELEASE_WRITE_LOCK(&(g_ce.rwlLock));
  307. } while (FALSE);
  308. LEAVE_SAMPLE_API();
  309. return dwErr;
  310. }
  311. DWORD
  312. CM_GetEventMessage (
  313. OUT ROUTING_PROTOCOL_EVENTS *prpeEvent,
  314. OUT MESSAGE *pmMessage)
  315. /*++
  316. Routine Description
  317. Get the next event in queue for the ip router manager.
  318. Locks
  319. None
  320. Arguments
  321. prpeEvent routing protocol event type
  322. pmMessage message associated with the event
  323. Return Value
  324. NO_ERROR if success
  325. Failure code o/w
  326. --*/
  327. {
  328. DWORD dwErr = NO_ERROR;
  329. // NOTE: this can be called after the protocol is stopped, as in when
  330. // the ip router manager is retrieving the ROUTER_STOPPED message, so
  331. // we do not call ENTER_SAMPLE_API()/LEAVE_SAMPLE_API()
  332. dwErr = DequeueEvent(prpeEvent, pmMessage);
  333. return dwErr;
  334. }