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.

323 lines
9.6 KiB

  1. /* Copyright 1999 American Power Conversion, All Rights Reserved
  2. *
  3. * Description:
  4. * The file implements the Notifier. The Notifier is reponsible
  5. * for broadcasting power-related and shutdown messages to the
  6. * local machine.
  7. *
  8. *
  9. * Revision History:
  10. * sberard 30Mar1999 initial revision.
  11. * mholly 27Apr1999 create and recycle a single thread for repeat
  12. * notifications - use two separate events to signal
  13. * either pause or resume of the thread state
  14. * mholly 27Apr1999 make sure to clear the pause event when resuming
  15. * and to clear the resume event when pausing
  16. * mholly 28May1999 send all messages in _theNotifierThread, also
  17. * have this thread do any delaying for the callee,
  18. * and keep track of whether a power out message
  19. * was sent, so we know when to send a power restored
  20. * v-stebe 17Dec2001 added check to ensure the SetEvent and ResetEvent are not
  21. * called with NULL.
  22. */
  23. #include "notifier.h"
  24. #include "service.h"
  25. #include "upsmsg.h"
  26. //
  27. // Function prototypes
  28. //
  29. static void sendSingleNotification(DWORD aMsgId);
  30. static void sendRepeatingNotification(void);
  31. static void setupNotifierThread(void);
  32. //
  33. // Globals
  34. //
  35. static HANDLE _theNotifierThread = NULL;
  36. static HANDLE _theNotificationPause = NULL;
  37. static HANDLE _theNotificationResume = NULL;
  38. static DWORD _theMessageId;
  39. static DWORD _theNotificationInterval;
  40. static DWORD _theMessageDelay;
  41. static DWORD _theLastMessageSent = 0;
  42. //
  43. // Constats
  44. //
  45. static const int kMilliSeconds = 1000; // Used to convert seconds to milliseconds
  46. /**
  47. * SendNotification
  48. *
  49. * Description:
  50. * This function sends a broadcast message to the local machine. The
  51. * message is specified by aMsgId. The parameter anInterval specifies
  52. * the amount of time to wait between consecutive messages. If this
  53. * value is zero the message is only sent once, otherwise the message
  54. * will repeat until SendNotification(..) or CancelNotification() is
  55. * called. aDelay specifies that the message should be send aDelay
  56. * seconds in the future - note that this method will not block for aDelay
  57. * seconds, it returns immediately and sends the message on a separate
  58. * thread. Any current previously executing periodic notifications
  59. * are canceled as a result of this call.
  60. *
  61. * This method also keeps track of whether the power out message had
  62. * been sent to users. This is done in order to squelch a power return
  63. * message if a power out message had not already been sent.
  64. *
  65. * Parameters:
  66. * aMsgId - the message to send
  67. * anInterval - the amount of time, in seconds, between messages
  68. * aDelay - the amount of time, in seconds to wait to send message
  69. *
  70. * Returns:
  71. * nothing
  72. */
  73. void SendNotification(DWORD aMsgId, DWORD anInterval, DWORD aDelay)
  74. {
  75. //
  76. // Cancel any current periodic notifications
  77. //
  78. CancelNotification();
  79. //
  80. // only sent the power back message if
  81. // the power out message had already
  82. // been broadcast to the users
  83. //
  84. if ((APE2_UPS_POWER_BACK == aMsgId) &&
  85. (APE2_UPS_POWER_OUT != _theLastMessageSent)) {
  86. //
  87. // the last message sent was not power out
  88. // so simply return
  89. //
  90. return;
  91. }
  92. //
  93. // Set the message parameters for _theNotifierThread
  94. //
  95. _theMessageId = aMsgId;
  96. _theNotificationInterval = anInterval;
  97. _theMessageDelay = aDelay;
  98. //
  99. // setup the thread events and thread
  100. //
  101. setupNotifierThread();
  102. //
  103. // tell _theNotificationThread to run by
  104. // signalling the resume event - must make
  105. // sure to clear the pause event before
  106. // signalling the resume
  107. //
  108. if (_theNotificationPause) {
  109. ResetEvent(_theNotificationPause);
  110. }
  111. if (_theNotificationResume){
  112. SetEvent(_theNotificationResume);
  113. }
  114. }
  115. /**
  116. * CancelNotification
  117. *
  118. * Description:
  119. * This function cancels the periodic messaging initiated through a call
  120. * to the SendNotification(..) function.
  121. *
  122. * Parameters:
  123. * none
  124. *
  125. * Returns:
  126. * nothing
  127. */
  128. void CancelNotification()
  129. {
  130. //
  131. // tell _theNotificationThread to pause
  132. // by signalling the pause event - must make
  133. // sure to clear the resume event before
  134. // signalling the pause event
  135. //
  136. if (_theNotificationResume) {
  137. ResetEvent(_theNotificationResume);
  138. }
  139. if (_theNotificationPause) {
  140. SetEvent(_theNotificationPause);
  141. }
  142. }
  143. /**
  144. * setupNotifierThread
  145. *
  146. * Description:
  147. * Creates the thread on which the notifications will
  148. * actually be sent. It also creates the events that
  149. * are used to signal the start and end of notifications
  150. *
  151. * Parameters:
  152. * none
  153. *
  154. * Returns:
  155. * nothing
  156. */
  157. void setupNotifierThread(void)
  158. {
  159. if (!_theNotificationPause) {
  160. //
  161. // Create the pause event
  162. //
  163. _theNotificationPause = CreateEvent(NULL, FALSE, FALSE, NULL);
  164. }
  165. if (!_theNotificationResume) {
  166. //
  167. // create the resume event
  168. //
  169. _theNotificationResume = CreateEvent(NULL, FALSE, FALSE, NULL);
  170. }
  171. if (!_theNotifierThread) {
  172. //
  173. // create the notification thread
  174. //
  175. _theNotifierThread = CreateThread(NULL, // no security attributes
  176. 0, // default stack
  177. (LPTHREAD_START_ROUTINE)
  178. sendRepeatingNotification,
  179. NULL,
  180. 0,
  181. NULL);
  182. }
  183. }
  184. /**
  185. * sendSingleNotification
  186. *
  187. * Description:
  188. * This function sends a single broadcast message to the local machine.
  189. * The message is specified by aMsgId.
  190. *
  191. * Parameters:
  192. * aMsgId - the message to send
  193. *
  194. * Returns:
  195. * nothing
  196. */
  197. static void sendSingleNotification(DWORD aMsgId)
  198. {
  199. DWORD status;
  200. TCHAR computer_name[MAX_COMPUTERNAME_LENGTH + 1];
  201. DWORD computer_name_len = MAX_COMPUTERNAME_LENGTH + 1;
  202. LPTSTR msg_buf, additional_args[1];
  203. DWORD buf_len;
  204. // Get the computer name and pass it as additional
  205. // information for the message
  206. GetComputerName(computer_name, &computer_name_len);
  207. additional_args[0] = computer_name;
  208. buf_len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  209. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  210. FORMAT_MESSAGE_FROM_SYSTEM ,
  211. NULL, // NULL means get message from system
  212. aMsgId,
  213. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  214. (LPTSTR) &msg_buf,
  215. 0, // buffer size
  216. (va_list *)additional_args); // additional arguements
  217. if (buf_len > 0) {
  218. _theLastMessageSent = aMsgId;
  219. // Display the message
  220. status = NetMessageBufferSend(NULL,
  221. computer_name,
  222. computer_name,
  223. (LPBYTE) msg_buf,
  224. buf_len * 2); // multiply by 2 because the string is Unicodeh
  225. // Free the memory allocated by FormatMessage
  226. LocalFree(msg_buf);
  227. }
  228. }
  229. /**
  230. * sendRepeatingNotification
  231. *
  232. * Description:
  233. * This function sends notifications repeatedly to the local machine.
  234. * This function calls sendSingleNotification(..) to perform the actual
  235. * notification. The message will be sent after _theMessageDelay seconds
  236. * has elapsed after _theNotificationResume event is signaled. If
  237. * _theMessageDelay is zero, a message is sent immediately. Messages are
  238. * repeated, if _theNotificationInterval is not zero, until the Event
  239. * _theNotificationPause is signaled. The message Id and the notification
  240. * interval are specified by the global variables _theMessageId and
  241. * _theNotificationInterval.
  242. *
  243. * To restart notifications using this thread signal _theNotificationResume
  244. * event. This thread will remain idle until this event is signalled
  245. *
  246. * Parameters:
  247. * none
  248. *
  249. * Returns:
  250. * nothing
  251. */
  252. static void sendRepeatingNotification(void)
  253. {
  254. //
  255. // wait for _theNotificationResume to become signaled
  256. // this becomes signaled when a notification should be sent
  257. //
  258. while (WAIT_OBJECT_0 ==
  259. WaitForSingleObject(_theNotificationResume, INFINITE)) {
  260. //
  261. // Send the initial message after the message delay
  262. // seconds has elapsed - if _theNotificationPause becomes
  263. // signaled before the delay seconds has elapsed then
  264. // this notification has been cancelled
  265. //
  266. if (WAIT_TIMEOUT == WaitForSingleObject(_theNotificationPause,
  267. _theMessageDelay * kMilliSeconds)) {
  268. //
  269. // send the message that was requested
  270. //
  271. sendSingleNotification(_theMessageId);
  272. //
  273. // now send repeating notifications
  274. // if necessary - if _theNotificationInterval
  275. // is set to zero, then only send the single
  276. // message above
  277. //
  278. if (0 != _theNotificationInterval) {
  279. //
  280. // wait for either _theNotificationPause to become
  281. // signalled or until it is time to notify again
  282. //
  283. DWORD interval = _theNotificationInterval * kMilliSeconds;
  284. while (WAIT_TIMEOUT ==
  285. WaitForSingleObject(_theNotificationPause, interval)) {
  286. sendSingleNotification(_theMessageId);
  287. }
  288. }
  289. }
  290. }
  291. }