Implemented DB driver call PrepareString; alarms table converted to new format
[public/netxms.git] / src / server / core / alarm.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Victor Kirhenshtein
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** File: alarm.cpp
20**
21**/
22
23#include "nxcore.h"
24
25
26//
27// Global instance of alarm manager
28//
29
30AlarmManager g_alarmMgr;
31
32
33//
34// Fill CSCP message with alarm data
35//
36
37void FillAlarmInfoMessage(CSCPMessage *pMsg, NXC_ALARM *pAlarm)
38{
39 pMsg->SetVariable(VID_ALARM_ID, pAlarm->dwAlarmId);
40 pMsg->SetVariable(VID_ACK_BY_USER, pAlarm->dwAckByUser);
41 pMsg->SetVariable(VID_TERMINATED_BY_USER, pAlarm->dwTermByUser);
42 pMsg->SetVariable(VID_EVENT_CODE, pAlarm->dwSourceEventCode);
43 pMsg->SetVariable(VID_EVENT_ID, pAlarm->qwSourceEventId);
44 pMsg->SetVariable(VID_OBJECT_ID, pAlarm->dwSourceObject);
45 pMsg->SetVariable(VID_CREATION_TIME, pAlarm->dwCreationTime);
46 pMsg->SetVariable(VID_LAST_CHANGE_TIME, pAlarm->dwLastChangeTime);
47 pMsg->SetVariable(VID_ALARM_KEY, pAlarm->szKey);
48 pMsg->SetVariable(VID_ALARM_MESSAGE, pAlarm->szMessage);
49 pMsg->SetVariable(VID_STATE, (WORD)pAlarm->nState);
50 pMsg->SetVariable(VID_CURRENT_SEVERITY, (WORD)pAlarm->nCurrentSeverity);
51 pMsg->SetVariable(VID_ORIGINAL_SEVERITY, (WORD)pAlarm->nOriginalSeverity);
52 pMsg->SetVariable(VID_HELPDESK_STATE, (WORD)pAlarm->nHelpDeskState);
53 pMsg->SetVariable(VID_HELPDESK_REF, pAlarm->szHelpDeskRef);
54 pMsg->SetVariable(VID_REPEAT_COUNT, pAlarm->dwRepeatCount);
55 pMsg->SetVariable(VID_ALARM_TIMEOUT, pAlarm->dwTimeout);
56 pMsg->SetVariable(VID_ALARM_TIMEOUT_EVENT, pAlarm->dwTimeoutEvent);
57}
58
59
60//
61// Alarm manager constructor
62//
63
64AlarmManager::AlarmManager()
65{
66 m_dwNumAlarms = 0;
67 m_pAlarmList = NULL;
68 m_mutex = MutexCreate();
69 m_condShutdown = ConditionCreate(FALSE);
70 m_hWatchdogThread = INVALID_THREAD_HANDLE;
71}
72
73
74//
75// Alarm manager destructor
76//
77
78AlarmManager::~AlarmManager()
79{
80 safe_free(m_pAlarmList);
81 MutexDestroy(m_mutex);
82 ConditionSet(m_condShutdown);
83 ThreadJoin(m_hWatchdogThread);
84}
85
86
87//
88// Watchdog thread starter
89//
90
91static THREAD_RESULT THREAD_CALL WatchdogThreadStarter(void *pArg)
92{
93 ((AlarmManager *)pArg)->WatchdogThread();
94 return THREAD_OK;
95}
96
97
98//
99// Initialize alarm manager at system startup
100//
101
102BOOL AlarmManager::Init(void)
103{
104 DB_RESULT hResult;
105 DWORD i;
106
107 // Load unacknowledged alarms into memory
108 hResult = DBSelect(g_hCoreDB, "SELECT alarm_id,source_object_id,"
109 "source_event_code,source_event_id,message,"
110 "original_severity,current_severity,"
111 "alarm_key,creation_time,last_change_time,"
112 "hd_state,hd_ref,ack_by,repeat_count,"
113 "alarm_state,timeout,timeout_event "
114 "FROM alarms WHERE alarm_state<2");
115 if (hResult == NULL)
116 return FALSE;
117
118 m_dwNumAlarms = DBGetNumRows(hResult);
119 if (m_dwNumAlarms > 0)
120 {
121 m_pAlarmList = (NXC_ALARM *)malloc(sizeof(NXC_ALARM) * m_dwNumAlarms);
122 memset(m_pAlarmList, 0, sizeof(NXC_ALARM) * m_dwNumAlarms);
123 for(i = 0; i < m_dwNumAlarms; i++)
124 {
125 m_pAlarmList[i].dwAlarmId = DBGetFieldULong(hResult, i, 0);
126 m_pAlarmList[i].dwSourceObject = DBGetFieldULong(hResult, i, 1);
127 m_pAlarmList[i].dwSourceEventCode = DBGetFieldULong(hResult, i, 2);
128 m_pAlarmList[i].qwSourceEventId = DBGetFieldUInt64(hResult, i, 3);
129 DBGetField(hResult, i, 4, m_pAlarmList[i].szMessage, MAX_DB_STRING);
5039dede
AK
130 m_pAlarmList[i].nOriginalSeverity = (BYTE)DBGetFieldLong(hResult, i, 5);
131 m_pAlarmList[i].nCurrentSeverity = (BYTE)DBGetFieldLong(hResult, i, 6);
132 DBGetField(hResult, i, 7, m_pAlarmList[i].szKey, MAX_DB_STRING);
5039dede
AK
133 m_pAlarmList[i].dwCreationTime = DBGetFieldULong(hResult, i, 8);
134 m_pAlarmList[i].dwLastChangeTime = DBGetFieldULong(hResult, i, 9);
135 m_pAlarmList[i].nHelpDeskState = (BYTE)DBGetFieldLong(hResult, i, 10);
136 DBGetField(hResult, i, 11, m_pAlarmList[i].szHelpDeskRef, MAX_HELPDESK_REF_LEN);
5039dede
AK
137 m_pAlarmList[i].dwAckByUser = DBGetFieldULong(hResult, i, 12);
138 m_pAlarmList[i].dwRepeatCount = DBGetFieldULong(hResult, i, 13);
139 m_pAlarmList[i].nState = (BYTE)DBGetFieldLong(hResult, i, 14);
140 m_pAlarmList[i].dwTimeout = DBGetFieldULong(hResult, i, 15);
141 m_pAlarmList[i].dwTimeoutEvent = DBGetFieldULong(hResult, i, 16);
142 }
143 }
144
145 DBFreeResult(hResult);
146
147 m_hWatchdogThread = ThreadCreateEx(WatchdogThreadStarter, 0, this);
148 return TRUE;
149}
150
151
152//
153// Create new alarm
154//
155
156void AlarmManager::NewAlarm(TCHAR *pszMsg, TCHAR *pszKey, int nState,
157 int iSeverity, DWORD dwTimeout,
158 DWORD dwTimeoutEvent, Event *pEvent)
159{
160 NXC_ALARM alarm;
161 TCHAR *pszExpMsg, *pszExpKey, *pszEscRef, szQuery[2048];
162 DWORD i, dwObjectId = 0;
163 BOOL bNewAlarm = TRUE;
164
165 // Expand alarm's message and key
210642a1
VK
166 pszExpMsg = pEvent->expandText(pszMsg);
167 pszExpKey = pEvent->expandText(pszKey);
5039dede
AK
168
169 // Check if we have a duplicate alarm
170 if ((nState != ALARM_STATE_TERMINATED) && (*pszExpKey != 0))
171 {
172 Lock();
173
174 for(i = 0; i < m_dwNumAlarms; i++)
175 if (!_tcscmp(pszExpKey, m_pAlarmList[i].szKey))
176 {
177 m_pAlarmList[i].dwRepeatCount++;
178 m_pAlarmList[i].dwLastChangeTime = (DWORD)time(NULL);
210642a1 179 m_pAlarmList[i].dwSourceObject = pEvent->getSourceId();
5039dede
AK
180 m_pAlarmList[i].nState = nState;
181 m_pAlarmList[i].nCurrentSeverity = iSeverity;
182 m_pAlarmList[i].dwTimeout = dwTimeout;
183 m_pAlarmList[i].dwTimeoutEvent = dwTimeoutEvent;
184 nx_strncpy(m_pAlarmList[i].szMessage, pszExpMsg, MAX_DB_STRING);
185
186 NotifyClients(NX_NOTIFY_ALARM_CHANGED, &m_pAlarmList[i]);
187 UpdateAlarmInDB(&m_pAlarmList[i]);
188
189 bNewAlarm = FALSE;
190 break;
191 }
192
193 Unlock();
194 }
195
196 if (bNewAlarm)
197 {
198 // Create new alarm structure
199 memset(&alarm, 0, sizeof(NXC_ALARM));
200 alarm.dwAlarmId = CreateUniqueId(IDG_ALARM);
210642a1
VK
201 alarm.qwSourceEventId = pEvent->getId();
202 alarm.dwSourceEventCode = pEvent->getCode();
203 alarm.dwSourceObject = pEvent->getSourceId();
5039dede
AK
204 alarm.dwCreationTime = (DWORD)time(NULL);
205 alarm.dwLastChangeTime = alarm.dwCreationTime;
206 alarm.nState = nState;
207 alarm.nOriginalSeverity = iSeverity;
208 alarm.nCurrentSeverity = iSeverity;
209 alarm.dwRepeatCount = 1;
210 alarm.nHelpDeskState = ALARM_HELPDESK_IGNORED;
211 alarm.dwTimeout = dwTimeout;
212 alarm.dwTimeoutEvent = dwTimeoutEvent;
213 nx_strncpy(alarm.szMessage, pszExpMsg, MAX_DB_STRING);
214 nx_strncpy(alarm.szKey, pszExpKey, MAX_DB_STRING);
215 free(pszExpMsg);
216 free(pszExpKey);
217
218 // Add new alarm to active alarm list if needed
219 if (alarm.nState != ALARM_STATE_TERMINATED)
220 {
221 Lock();
222
223 m_dwNumAlarms++;
224 m_pAlarmList = (NXC_ALARM *)realloc(m_pAlarmList, sizeof(NXC_ALARM) * m_dwNumAlarms);
225 memcpy(&m_pAlarmList[m_dwNumAlarms - 1], &alarm, sizeof(NXC_ALARM));
226 dwObjectId = alarm.dwSourceObject;
227
228 Unlock();
229 }
230
231 // Save alarm to database
5039dede
AK
232 sprintf(szQuery, "INSERT INTO alarms (alarm_id,creation_time,last_change_time,"
233 "source_object_id,source_event_code,message,original_severity,"
234 "current_severity,alarm_key,alarm_state,ack_by,hd_state,"
235 "hd_ref,repeat_count,term_by,timeout,timeout_event,source_event_id) VALUES "
643c9dcb 236 "(%d,%d,%d,%d,%d,%s,%d,%d,%s,%d,%d,%d,%s,%d,%d,%d,%d," UINT64_FMT ")",
5039dede 237 alarm.dwAlarmId, alarm.dwCreationTime, alarm.dwLastChangeTime,
643c9dcb
VK
238 alarm.dwSourceObject, alarm.dwSourceEventCode,
239 (const TCHAR *)DBPrepareString(alarm.szMessage),
240 alarm.nOriginalSeverity, alarm.nCurrentSeverity,
241 (const TCHAR *)DBPrepareString(alarm.szKey),
242 alarm.nState, alarm.dwAckByUser, alarm.nHelpDeskState,
243 (const TCHAR *)DBPrepareString(alarm.szHelpDeskRef),
5039dede
AK
244 alarm.dwRepeatCount, alarm.dwTermByUser, alarm.dwTimeout,
245 alarm.dwTimeoutEvent, alarm.qwSourceEventId);
5039dede
AK
246 QueueSQLRequest(szQuery);
247
248 // Notify connected clients about new alarm
249 NotifyClients(NX_NOTIFY_NEW_ALARM, &alarm);
250 }
251
252 // Update status of related object if needed
253 if ((dwObjectId != 0) && (alarm.nState != ALARM_STATE_TERMINATED))
254 UpdateObjectStatus(dwObjectId);
255}
256
257
258//
259// Acknowledge alarm with given ID
260//
261
262DWORD AlarmManager::AckById(DWORD dwAlarmId, DWORD dwUserId)
263{
264 DWORD i, dwObject, dwRet = RCC_INVALID_ALARM_ID;
265
266 Lock();
267 for(i = 0; i < m_dwNumAlarms; i++)
268 if (m_pAlarmList[i].dwAlarmId == dwAlarmId)
269 {
270 if (m_pAlarmList[i].nState == ALARM_STATE_OUTSTANDING)
271 {
272 m_pAlarmList[i].nState = ALARM_STATE_ACKNOWLEDGED;
273 m_pAlarmList[i].dwAckByUser = dwUserId;
274 m_pAlarmList[i].dwLastChangeTime = (DWORD)time(NULL);
275 dwObject = m_pAlarmList[i].dwSourceObject;
276 NotifyClients(NX_NOTIFY_ALARM_CHANGED, &m_pAlarmList[i]);
277 UpdateAlarmInDB(&m_pAlarmList[i]);
278 dwRet = RCC_SUCCESS;
279 }
280 else
281 {
282 dwRet = RCC_ALARM_NOT_OUTSTANDING;
283 }
284 break;
285 }
286 Unlock();
287
288 if (dwRet == RCC_SUCCESS)
289 UpdateObjectStatus(dwObject);
290 return dwRet;
291}
292
293
294//
295// Terminate alarm with given ID
296// Should return RCC which can be sent to client
297//
298
299DWORD AlarmManager::TerminateById(DWORD dwAlarmId, DWORD dwUserId)
300{
301 DWORD i, dwObject, dwRet = RCC_INVALID_ALARM_ID;
302
303 Lock();
304 for(i = 0; i < m_dwNumAlarms; i++)
305 if (m_pAlarmList[i].dwAlarmId == dwAlarmId)
306 {
307 // If alarm is open in helpdesk, it cannot be terminated
308 if (m_pAlarmList[i].nHelpDeskState != ALARM_HELPDESK_OPEN)
309 {
310 dwObject = m_pAlarmList[i].dwSourceObject;
311 m_pAlarmList[i].dwTermByUser = dwUserId;
312 m_pAlarmList[i].dwLastChangeTime = (DWORD)time(NULL);
313 m_pAlarmList[i].nState = ALARM_STATE_TERMINATED;
314 NotifyClients(NX_NOTIFY_ALARM_TERMINATED, &m_pAlarmList[i]);
315 UpdateAlarmInDB(&m_pAlarmList[i]);
316 m_dwNumAlarms--;
317 memmove(&m_pAlarmList[i], &m_pAlarmList[i + 1], sizeof(NXC_ALARM) * (m_dwNumAlarms - i));
318 dwRet = RCC_SUCCESS;
319 }
320 else
321 {
322 dwRet = RCC_ALARM_OPEN_IN_HELPDESK;
323 }
324 break;
325 }
326 Unlock();
327
328 if (dwRet == RCC_SUCCESS)
329 UpdateObjectStatus(dwObject);
330 return dwRet;
331}
332
333
334//
335// Terminate all alarms with given key
336//
337
338void AlarmManager::TerminateByKey(char *pszKey)
339{
340 DWORD i, j, dwNumObjects, *pdwObjectList, dwCurrTime;
341
342 pdwObjectList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumAlarms);
343
344 Lock();
345 dwCurrTime = (DWORD)time(NULL);
346 for(i = 0, dwNumObjects = 0; i < m_dwNumAlarms; i++)
347 if ((!strcmp(pszKey, m_pAlarmList[i].szKey)) &&
348 (m_pAlarmList[i].nHelpDeskState != ALARM_HELPDESK_OPEN))
349 {
350 // Add alarm's source object to update list
351 for(j = 0; j < dwNumObjects; j++)
352 {
353 if (pdwObjectList[j] == m_pAlarmList[i].dwSourceObject)
354 break;
355 }
356 if (j == dwNumObjects)
357 {
358 pdwObjectList[dwNumObjects++] = m_pAlarmList[i].dwSourceObject;
359 }
360
361 // Terminate alarm
362 m_pAlarmList[i].nState = ALARM_STATE_TERMINATED;
363 m_pAlarmList[i].dwLastChangeTime = dwCurrTime;
364 m_pAlarmList[i].dwTermByUser = 0;
365 NotifyClients(NX_NOTIFY_ALARM_TERMINATED, &m_pAlarmList[i]);
366 UpdateAlarmInDB(&m_pAlarmList[i]);
367 m_dwNumAlarms--;
368 memmove(&m_pAlarmList[i], &m_pAlarmList[i + 1], sizeof(NXC_ALARM) * (m_dwNumAlarms - i));
369 i--;
370 }
371 Unlock();
372
373 // Update status of objects
374 for(i = 0; i < dwNumObjects; i++)
375 UpdateObjectStatus(pdwObjectList[i]);
376 free(pdwObjectList);
377}
378
379
380//
381// Delete alarm with given ID
382//
383
384void AlarmManager::DeleteAlarm(DWORD dwAlarmId)
385{
386 DWORD i, dwObject;
387 char szQuery[256];
388
389 // Delete alarm from in-memory list
390 Lock();
391 for(i = 0; i < m_dwNumAlarms; i++)
392 if (m_pAlarmList[i].dwAlarmId == dwAlarmId)
393 {
394 dwObject = m_pAlarmList[i].dwSourceObject;
395 NotifyClients(NX_NOTIFY_ALARM_DELETED, &m_pAlarmList[i]);
396 m_dwNumAlarms--;
397 memmove(&m_pAlarmList[i], &m_pAlarmList[i + 1], sizeof(NXC_ALARM) * (m_dwNumAlarms - i));
398 break;
399 }
400 Unlock();
401
402 // Delete from database
403 sprintf(szQuery, "DELETE FROM alarms WHERE alarm_id=%d", dwAlarmId);
404 //DBQuery(g_hCoreDB, szQuery);
405 QueueSQLRequest(szQuery);
406
407 UpdateObjectStatus(dwObject);
408}
409
410
411//
412// Update alarm information in database
413//
414
415void AlarmManager::UpdateAlarmInDB(NXC_ALARM *pAlarm)
416{
643c9dcb 417 char szQuery[1024];
5039dede 418
5039dede
AK
419 sprintf(szQuery, "UPDATE alarms SET alarm_state=%d,ack_by=%d,term_by=%d,"
420 "last_change_time=%d,current_severity=%d,repeat_count=%d,"
643c9dcb 421 "hd_state=%d,hd_ref=%s,timeout=%d,timeout_event=%d WHERE alarm_id=%d",
5039dede
AK
422 pAlarm->nState, pAlarm->dwAckByUser, pAlarm->dwTermByUser,
423 pAlarm->dwLastChangeTime, pAlarm->nCurrentSeverity,
643c9dcb
VK
424 pAlarm->dwRepeatCount, pAlarm->nHelpDeskState,
425 (const TCHAR *)DBPrepareString(pAlarm->szHelpDeskRef),
5039dede 426 pAlarm->dwTimeout, pAlarm->dwTimeoutEvent, pAlarm->dwAlarmId);
5039dede
AK
427 QueueSQLRequest(szQuery);
428}
429
430
431//
432// Callback for client session enumeration
433//
434
435void AlarmManager::SendAlarmNotification(ClientSession *pSession, void *pArg)
436{
437 pSession->OnAlarmUpdate(((AlarmManager *)pArg)->m_dwNotifyCode,
438 ((AlarmManager *)pArg)->m_pNotifyAlarmInfo);
439}
440
441
442//
443// Notify connected clients about changes
444//
445
446void AlarmManager::NotifyClients(DWORD dwCode, NXC_ALARM *pAlarm)
447{
448 m_dwNotifyCode = dwCode;
449 m_pNotifyAlarmInfo = pAlarm;
450 EnumerateClientSessions(SendAlarmNotification, this);
451}
452
453
454//
455// Send all alarms to client
456//
457
458void AlarmManager::SendAlarmsToClient(DWORD dwRqId, BOOL bIncludeAck, ClientSession *pSession)
459{
460 DWORD i, dwUserId;
461 NetObj *pObject;
462 CSCPMessage msg;
463
464 dwUserId = pSession->GetUserId();
465
466 // Prepare message
467 msg.SetCode(CMD_ALARM_DATA);
468 msg.SetId(dwRqId);
469
470 if (bIncludeAck)
471 {
472 // Request for all alarms including acknowledged,
473 // so we have to load them from database
474 }
475 else
476 {
477 // Unacknowledged alarms can be sent directly from memory
478 Lock();
479
480 for(i = 0; i < m_dwNumAlarms; i++)
481 {
482 pObject = FindObjectById(m_pAlarmList[i].dwSourceObject);
483 if (pObject != NULL)
484 {
485 if (pObject->CheckAccessRights(dwUserId, OBJECT_ACCESS_READ_ALARMS))
486 {
487 FillAlarmInfoMessage(&msg, &m_pAlarmList[i]);
488 pSession->SendMessage(&msg);
489 msg.DeleteAllVariables();
490 }
491 }
492 }
493
494 Unlock();
495 }
496
497 // Send end-of-list indicator
498 msg.SetVariable(VID_ALARM_ID, (DWORD)0);
499 pSession->SendMessage(&msg);
500}
501
502
503//
504// Get source object for given alarm id
505//
506
507NetObj *AlarmManager::GetAlarmSourceObject(DWORD dwAlarmId)
508{
509 DWORD i, dwObjectId = 0;
510 char szQuery[256];
511 DB_RESULT hResult;
512
513 // First, look at our in-memory list
514 Lock();
515 for(i = 0; i < m_dwNumAlarms; i++)
516 if (m_pAlarmList[i].dwAlarmId == dwAlarmId)
517 {
518 dwObjectId = m_pAlarmList[i].dwSourceObject;
519 break;
520 }
521 Unlock();
522
523 // If not found, search database
524 if (i == m_dwNumAlarms)
525 {
526 sprintf(szQuery, "SELECT source_object_id FROM alarms WHERE alarm_id=%d", dwAlarmId);
527 hResult = DBSelect(g_hCoreDB, szQuery);
528 if (hResult != NULL)
529 {
530 if (DBGetNumRows(hResult) > 0)
531 {
532 dwObjectId = DBGetFieldULong(hResult, 0, 0);
533 }
534 DBFreeResult(hResult);
535 }
536 }
537
538 return FindObjectById(dwObjectId);
539}
540
541
542//
543// Get most critical status among active alarms for given object
544// Will return STATUS_UNKNOWN if there are no active alarms
545//
546
547int AlarmManager::GetMostCriticalStatusForObject(DWORD dwObjectId)
548{
549 DWORD i;
550 int iStatus = STATUS_UNKNOWN;
551
552 Lock();
553
554 for(i = 0; i < m_dwNumAlarms; i++)
555 {
556 if ((m_pAlarmList[i].dwSourceObject == dwObjectId) &&
557 ((m_pAlarmList[i].nCurrentSeverity > iStatus) || (iStatus == STATUS_UNKNOWN)))
558 {
559 iStatus = (int)m_pAlarmList[i].nCurrentSeverity;
560 }
561 }
562
563 Unlock();
564 return iStatus;
565}
566
567
568//
569// Update object status after alarm acknowledgement or deletion
570//
571
572void AlarmManager::UpdateObjectStatus(DWORD dwObjectId)
573{
574 NetObj *pObject;
575
576 pObject = FindObjectById(dwObjectId);
577 if (pObject != NULL)
578 pObject->CalculateCompoundStatus();
579}
580
581
582//
583// Fill message with alarm stats
584//
585
586void AlarmManager::GetAlarmStats(CSCPMessage *pMsg)
587{
588 DWORD i, dwCount[5];
589
590 Lock();
591 pMsg->SetVariable(VID_NUM_ALARMS, m_dwNumAlarms);
592 memset(dwCount, 0, sizeof(DWORD) * 5);
593 for(i = 0; i < m_dwNumAlarms; i++)
594 dwCount[m_pAlarmList[i].nCurrentSeverity]++;
595 Unlock();
596 pMsg->SetVariableToInt32Array(VID_ALARMS_BY_SEVERITY, 5, dwCount);
597}
598
599
600//
601// Watchdog thread
602//
603
604void AlarmManager::WatchdogThread(void)
605{
606 DWORD i;
607 time_t now;
608
609 while(1)
610 {
611 if (ConditionWait(m_condShutdown, 1000))
612 break;
613
614 Lock();
615 now = time(NULL);
616 for(i = 0; i < m_dwNumAlarms; i++)
617 {
618 if ((m_pAlarmList[i].dwTimeout > 0) &&
619 (m_pAlarmList[i].nState == ALARM_STATE_OUTSTANDING) &&
620 (((time_t)m_pAlarmList[i].dwLastChangeTime + (time_t)m_pAlarmList[i].dwTimeout) < now))
621 {
622 DbgPrintf(5, _T("Alarm timeout: alarm_id=%d, last_change=%d, timeout=%d, now=%d"),
623 m_pAlarmList[i].dwAlarmId, m_pAlarmList[i].dwLastChangeTime,
624 m_pAlarmList[i].dwTimeout, now);
625
626 PostEvent(m_pAlarmList[i].dwTimeoutEvent, m_pAlarmList[i].dwSourceObject, "dssd",
627 m_pAlarmList[i].dwAlarmId, m_pAlarmList[i].szMessage,
628 m_pAlarmList[i].szKey, m_pAlarmList[i].dwSourceEventCode);
629 m_pAlarmList[i].dwTimeout = 0; // Disable repeated timeout events
630 UpdateAlarmInDB(&m_pAlarmList[i]);
631 }
632 }
633 Unlock();
634 }
635}