302aadcb2dd3b78890ee2c58c56aa463e40e2350
[public/netxms.git] / src / server / core / alarm.cpp
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
30 AlarmManager g_alarmMgr;
31
32
33 //
34 // Fill CSCP message with alarm data
35 //
36
37 void 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
64 AlarmManager::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
78 AlarmManager::~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
91 static 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
102 BOOL 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);
130 DecodeSQLString(m_pAlarmList[i].szMessage);
131 m_pAlarmList[i].nOriginalSeverity = (BYTE)DBGetFieldLong(hResult, i, 5);
132 m_pAlarmList[i].nCurrentSeverity = (BYTE)DBGetFieldLong(hResult, i, 6);
133 DBGetField(hResult, i, 7, m_pAlarmList[i].szKey, MAX_DB_STRING);
134 DecodeSQLString(m_pAlarmList[i].szKey);
135 m_pAlarmList[i].dwCreationTime = DBGetFieldULong(hResult, i, 8);
136 m_pAlarmList[i].dwLastChangeTime = DBGetFieldULong(hResult, i, 9);
137 m_pAlarmList[i].nHelpDeskState = (BYTE)DBGetFieldLong(hResult, i, 10);
138 DBGetField(hResult, i, 11, m_pAlarmList[i].szHelpDeskRef, MAX_HELPDESK_REF_LEN);
139 DecodeSQLString(m_pAlarmList[i].szHelpDeskRef);
140 m_pAlarmList[i].dwAckByUser = DBGetFieldULong(hResult, i, 12);
141 m_pAlarmList[i].dwRepeatCount = DBGetFieldULong(hResult, i, 13);
142 m_pAlarmList[i].nState = (BYTE)DBGetFieldLong(hResult, i, 14);
143 m_pAlarmList[i].dwTimeout = DBGetFieldULong(hResult, i, 15);
144 m_pAlarmList[i].dwTimeoutEvent = DBGetFieldULong(hResult, i, 16);
145 }
146 }
147
148 DBFreeResult(hResult);
149
150 m_hWatchdogThread = ThreadCreateEx(WatchdogThreadStarter, 0, this);
151 return TRUE;
152 }
153
154
155 //
156 // Create new alarm
157 //
158
159 void AlarmManager::NewAlarm(TCHAR *pszMsg, TCHAR *pszKey, int nState,
160 int iSeverity, DWORD dwTimeout,
161 DWORD dwTimeoutEvent, Event *pEvent)
162 {
163 NXC_ALARM alarm;
164 TCHAR *pszExpMsg, *pszExpKey, *pszEscRef, szQuery[2048];
165 DWORD i, dwObjectId = 0;
166 BOOL bNewAlarm = TRUE;
167
168 // Expand alarm's message and key
169 pszExpMsg = pEvent->expandText(pszMsg);
170 pszExpKey = pEvent->expandText(pszKey);
171
172 // Check if we have a duplicate alarm
173 if ((nState != ALARM_STATE_TERMINATED) && (*pszExpKey != 0))
174 {
175 Lock();
176
177 for(i = 0; i < m_dwNumAlarms; i++)
178 if (!_tcscmp(pszExpKey, m_pAlarmList[i].szKey))
179 {
180 m_pAlarmList[i].dwRepeatCount++;
181 m_pAlarmList[i].dwLastChangeTime = (DWORD)time(NULL);
182 m_pAlarmList[i].dwSourceObject = pEvent->getSourceId();
183 m_pAlarmList[i].nState = nState;
184 m_pAlarmList[i].nCurrentSeverity = iSeverity;
185 m_pAlarmList[i].dwTimeout = dwTimeout;
186 m_pAlarmList[i].dwTimeoutEvent = dwTimeoutEvent;
187 nx_strncpy(m_pAlarmList[i].szMessage, pszExpMsg, MAX_DB_STRING);
188
189 NotifyClients(NX_NOTIFY_ALARM_CHANGED, &m_pAlarmList[i]);
190 UpdateAlarmInDB(&m_pAlarmList[i]);
191
192 bNewAlarm = FALSE;
193 break;
194 }
195
196 Unlock();
197 }
198
199 if (bNewAlarm)
200 {
201 // Create new alarm structure
202 memset(&alarm, 0, sizeof(NXC_ALARM));
203 alarm.dwAlarmId = CreateUniqueId(IDG_ALARM);
204 alarm.qwSourceEventId = pEvent->getId();
205 alarm.dwSourceEventCode = pEvent->getCode();
206 alarm.dwSourceObject = pEvent->getSourceId();
207 alarm.dwCreationTime = (DWORD)time(NULL);
208 alarm.dwLastChangeTime = alarm.dwCreationTime;
209 alarm.nState = nState;
210 alarm.nOriginalSeverity = iSeverity;
211 alarm.nCurrentSeverity = iSeverity;
212 alarm.dwRepeatCount = 1;
213 alarm.nHelpDeskState = ALARM_HELPDESK_IGNORED;
214 alarm.dwTimeout = dwTimeout;
215 alarm.dwTimeoutEvent = dwTimeoutEvent;
216 nx_strncpy(alarm.szMessage, pszExpMsg, MAX_DB_STRING);
217 nx_strncpy(alarm.szKey, pszExpKey, MAX_DB_STRING);
218 free(pszExpMsg);
219 free(pszExpKey);
220
221 // Add new alarm to active alarm list if needed
222 if (alarm.nState != ALARM_STATE_TERMINATED)
223 {
224 Lock();
225
226 m_dwNumAlarms++;
227 m_pAlarmList = (NXC_ALARM *)realloc(m_pAlarmList, sizeof(NXC_ALARM) * m_dwNumAlarms);
228 memcpy(&m_pAlarmList[m_dwNumAlarms - 1], &alarm, sizeof(NXC_ALARM));
229 dwObjectId = alarm.dwSourceObject;
230
231 Unlock();
232 }
233
234 // Save alarm to database
235 pszExpMsg = EncodeSQLString(alarm.szMessage);
236 pszExpKey = EncodeSQLString(alarm.szKey);
237 pszEscRef = EncodeSQLString(alarm.szHelpDeskRef);
238 sprintf(szQuery, "INSERT INTO alarms (alarm_id,creation_time,last_change_time,"
239 "source_object_id,source_event_code,message,original_severity,"
240 "current_severity,alarm_key,alarm_state,ack_by,hd_state,"
241 "hd_ref,repeat_count,term_by,timeout,timeout_event,source_event_id) VALUES "
242 "(%d,%d,%d,%d,%d,'%s',%d,%d,'%s',%d,%d,%d,'%s',%d,%d,%d,%d,"
243 #ifdef _WIN32
244 "%I64d)",
245 #else
246 "%lld)",
247 #endif
248 alarm.dwAlarmId, alarm.dwCreationTime, alarm.dwLastChangeTime,
249 alarm.dwSourceObject, alarm.dwSourceEventCode, pszExpMsg,
250 alarm.nOriginalSeverity, alarm.nCurrentSeverity, pszExpKey,
251 alarm.nState, alarm.dwAckByUser, alarm.nHelpDeskState, pszEscRef,
252 alarm.dwRepeatCount, alarm.dwTermByUser, alarm.dwTimeout,
253 alarm.dwTimeoutEvent, alarm.qwSourceEventId);
254 free(pszExpMsg);
255 free(pszExpKey);
256 free(pszEscRef);
257 QueueSQLRequest(szQuery);
258
259 // Notify connected clients about new alarm
260 NotifyClients(NX_NOTIFY_NEW_ALARM, &alarm);
261 }
262
263 // Update status of related object if needed
264 if ((dwObjectId != 0) && (alarm.nState != ALARM_STATE_TERMINATED))
265 UpdateObjectStatus(dwObjectId);
266 }
267
268
269 //
270 // Acknowledge alarm with given ID
271 //
272
273 DWORD AlarmManager::AckById(DWORD dwAlarmId, DWORD dwUserId)
274 {
275 DWORD i, dwObject, dwRet = RCC_INVALID_ALARM_ID;
276
277 Lock();
278 for(i = 0; i < m_dwNumAlarms; i++)
279 if (m_pAlarmList[i].dwAlarmId == dwAlarmId)
280 {
281 if (m_pAlarmList[i].nState == ALARM_STATE_OUTSTANDING)
282 {
283 m_pAlarmList[i].nState = ALARM_STATE_ACKNOWLEDGED;
284 m_pAlarmList[i].dwAckByUser = dwUserId;
285 m_pAlarmList[i].dwLastChangeTime = (DWORD)time(NULL);
286 dwObject = m_pAlarmList[i].dwSourceObject;
287 NotifyClients(NX_NOTIFY_ALARM_CHANGED, &m_pAlarmList[i]);
288 UpdateAlarmInDB(&m_pAlarmList[i]);
289 dwRet = RCC_SUCCESS;
290 }
291 else
292 {
293 dwRet = RCC_ALARM_NOT_OUTSTANDING;
294 }
295 break;
296 }
297 Unlock();
298
299 if (dwRet == RCC_SUCCESS)
300 UpdateObjectStatus(dwObject);
301 return dwRet;
302 }
303
304
305 //
306 // Terminate alarm with given ID
307 // Should return RCC which can be sent to client
308 //
309
310 DWORD AlarmManager::TerminateById(DWORD dwAlarmId, DWORD dwUserId)
311 {
312 DWORD i, dwObject, dwRet = RCC_INVALID_ALARM_ID;
313
314 Lock();
315 for(i = 0; i < m_dwNumAlarms; i++)
316 if (m_pAlarmList[i].dwAlarmId == dwAlarmId)
317 {
318 // If alarm is open in helpdesk, it cannot be terminated
319 if (m_pAlarmList[i].nHelpDeskState != ALARM_HELPDESK_OPEN)
320 {
321 dwObject = m_pAlarmList[i].dwSourceObject;
322 m_pAlarmList[i].dwTermByUser = dwUserId;
323 m_pAlarmList[i].dwLastChangeTime = (DWORD)time(NULL);
324 m_pAlarmList[i].nState = ALARM_STATE_TERMINATED;
325 NotifyClients(NX_NOTIFY_ALARM_TERMINATED, &m_pAlarmList[i]);
326 UpdateAlarmInDB(&m_pAlarmList[i]);
327 m_dwNumAlarms--;
328 memmove(&m_pAlarmList[i], &m_pAlarmList[i + 1], sizeof(NXC_ALARM) * (m_dwNumAlarms - i));
329 dwRet = RCC_SUCCESS;
330 }
331 else
332 {
333 dwRet = RCC_ALARM_OPEN_IN_HELPDESK;
334 }
335 break;
336 }
337 Unlock();
338
339 if (dwRet == RCC_SUCCESS)
340 UpdateObjectStatus(dwObject);
341 return dwRet;
342 }
343
344
345 //
346 // Terminate all alarms with given key
347 //
348
349 void AlarmManager::TerminateByKey(char *pszKey)
350 {
351 DWORD i, j, dwNumObjects, *pdwObjectList, dwCurrTime;
352
353 pdwObjectList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumAlarms);
354
355 Lock();
356 dwCurrTime = (DWORD)time(NULL);
357 for(i = 0, dwNumObjects = 0; i < m_dwNumAlarms; i++)
358 if ((!strcmp(pszKey, m_pAlarmList[i].szKey)) &&
359 (m_pAlarmList[i].nHelpDeskState != ALARM_HELPDESK_OPEN))
360 {
361 // Add alarm's source object to update list
362 for(j = 0; j < dwNumObjects; j++)
363 {
364 if (pdwObjectList[j] == m_pAlarmList[i].dwSourceObject)
365 break;
366 }
367 if (j == dwNumObjects)
368 {
369 pdwObjectList[dwNumObjects++] = m_pAlarmList[i].dwSourceObject;
370 }
371
372 // Terminate alarm
373 m_pAlarmList[i].nState = ALARM_STATE_TERMINATED;
374 m_pAlarmList[i].dwLastChangeTime = dwCurrTime;
375 m_pAlarmList[i].dwTermByUser = 0;
376 NotifyClients(NX_NOTIFY_ALARM_TERMINATED, &m_pAlarmList[i]);
377 UpdateAlarmInDB(&m_pAlarmList[i]);
378 m_dwNumAlarms--;
379 memmove(&m_pAlarmList[i], &m_pAlarmList[i + 1], sizeof(NXC_ALARM) * (m_dwNumAlarms - i));
380 i--;
381 }
382 Unlock();
383
384 // Update status of objects
385 for(i = 0; i < dwNumObjects; i++)
386 UpdateObjectStatus(pdwObjectList[i]);
387 free(pdwObjectList);
388 }
389
390
391 //
392 // Delete alarm with given ID
393 //
394
395 void AlarmManager::DeleteAlarm(DWORD dwAlarmId)
396 {
397 DWORD i, dwObject;
398 char szQuery[256];
399
400 // Delete alarm from in-memory list
401 Lock();
402 for(i = 0; i < m_dwNumAlarms; i++)
403 if (m_pAlarmList[i].dwAlarmId == dwAlarmId)
404 {
405 dwObject = m_pAlarmList[i].dwSourceObject;
406 NotifyClients(NX_NOTIFY_ALARM_DELETED, &m_pAlarmList[i]);
407 m_dwNumAlarms--;
408 memmove(&m_pAlarmList[i], &m_pAlarmList[i + 1], sizeof(NXC_ALARM) * (m_dwNumAlarms - i));
409 break;
410 }
411 Unlock();
412
413 // Delete from database
414 sprintf(szQuery, "DELETE FROM alarms WHERE alarm_id=%d", dwAlarmId);
415 //DBQuery(g_hCoreDB, szQuery);
416 QueueSQLRequest(szQuery);
417
418 UpdateObjectStatus(dwObject);
419 }
420
421
422 //
423 // Update alarm information in database
424 //
425
426 void AlarmManager::UpdateAlarmInDB(NXC_ALARM *pAlarm)
427 {
428 char szQuery[1024], *pszEscRef;
429
430 pszEscRef = EncodeSQLString(pAlarm->szHelpDeskRef);
431 sprintf(szQuery, "UPDATE alarms SET alarm_state=%d,ack_by=%d,term_by=%d,"
432 "last_change_time=%d,current_severity=%d,repeat_count=%d,"
433 "hd_state=%d,hd_ref='%s',timeout=%d,timeout_event=%d WHERE alarm_id=%d",
434 pAlarm->nState, pAlarm->dwAckByUser, pAlarm->dwTermByUser,
435 pAlarm->dwLastChangeTime, pAlarm->nCurrentSeverity,
436 pAlarm->dwRepeatCount, pAlarm->nHelpDeskState, pszEscRef,
437 pAlarm->dwTimeout, pAlarm->dwTimeoutEvent, pAlarm->dwAlarmId);
438 free(pszEscRef);
439 QueueSQLRequest(szQuery);
440 }
441
442
443 //
444 // Callback for client session enumeration
445 //
446
447 void AlarmManager::SendAlarmNotification(ClientSession *pSession, void *pArg)
448 {
449 pSession->OnAlarmUpdate(((AlarmManager *)pArg)->m_dwNotifyCode,
450 ((AlarmManager *)pArg)->m_pNotifyAlarmInfo);
451 }
452
453
454 //
455 // Notify connected clients about changes
456 //
457
458 void AlarmManager::NotifyClients(DWORD dwCode, NXC_ALARM *pAlarm)
459 {
460 m_dwNotifyCode = dwCode;
461 m_pNotifyAlarmInfo = pAlarm;
462 EnumerateClientSessions(SendAlarmNotification, this);
463 }
464
465
466 //
467 // Send all alarms to client
468 //
469
470 void AlarmManager::SendAlarmsToClient(DWORD dwRqId, BOOL bIncludeAck, ClientSession *pSession)
471 {
472 DWORD i, dwUserId;
473 NetObj *pObject;
474 CSCPMessage msg;
475
476 dwUserId = pSession->GetUserId();
477
478 // Prepare message
479 msg.SetCode(CMD_ALARM_DATA);
480 msg.SetId(dwRqId);
481
482 if (bIncludeAck)
483 {
484 // Request for all alarms including acknowledged,
485 // so we have to load them from database
486 }
487 else
488 {
489 // Unacknowledged alarms can be sent directly from memory
490 Lock();
491
492 for(i = 0; i < m_dwNumAlarms; i++)
493 {
494 pObject = FindObjectById(m_pAlarmList[i].dwSourceObject);
495 if (pObject != NULL)
496 {
497 if (pObject->CheckAccessRights(dwUserId, OBJECT_ACCESS_READ_ALARMS))
498 {
499 FillAlarmInfoMessage(&msg, &m_pAlarmList[i]);
500 pSession->SendMessage(&msg);
501 msg.DeleteAllVariables();
502 }
503 }
504 }
505
506 Unlock();
507 }
508
509 // Send end-of-list indicator
510 msg.SetVariable(VID_ALARM_ID, (DWORD)0);
511 pSession->SendMessage(&msg);
512 }
513
514
515 //
516 // Get source object for given alarm id
517 //
518
519 NetObj *AlarmManager::GetAlarmSourceObject(DWORD dwAlarmId)
520 {
521 DWORD i, dwObjectId = 0;
522 char szQuery[256];
523 DB_RESULT hResult;
524
525 // First, look at our in-memory list
526 Lock();
527 for(i = 0; i < m_dwNumAlarms; i++)
528 if (m_pAlarmList[i].dwAlarmId == dwAlarmId)
529 {
530 dwObjectId = m_pAlarmList[i].dwSourceObject;
531 break;
532 }
533 Unlock();
534
535 // If not found, search database
536 if (i == m_dwNumAlarms)
537 {
538 sprintf(szQuery, "SELECT source_object_id FROM alarms WHERE alarm_id=%d", dwAlarmId);
539 hResult = DBSelect(g_hCoreDB, szQuery);
540 if (hResult != NULL)
541 {
542 if (DBGetNumRows(hResult) > 0)
543 {
544 dwObjectId = DBGetFieldULong(hResult, 0, 0);
545 }
546 DBFreeResult(hResult);
547 }
548 }
549
550 return FindObjectById(dwObjectId);
551 }
552
553
554 //
555 // Get most critical status among active alarms for given object
556 // Will return STATUS_UNKNOWN if there are no active alarms
557 //
558
559 int AlarmManager::GetMostCriticalStatusForObject(DWORD dwObjectId)
560 {
561 DWORD i;
562 int iStatus = STATUS_UNKNOWN;
563
564 Lock();
565
566 for(i = 0; i < m_dwNumAlarms; i++)
567 {
568 if ((m_pAlarmList[i].dwSourceObject == dwObjectId) &&
569 ((m_pAlarmList[i].nCurrentSeverity > iStatus) || (iStatus == STATUS_UNKNOWN)))
570 {
571 iStatus = (int)m_pAlarmList[i].nCurrentSeverity;
572 }
573 }
574
575 Unlock();
576 return iStatus;
577 }
578
579
580 //
581 // Update object status after alarm acknowledgement or deletion
582 //
583
584 void AlarmManager::UpdateObjectStatus(DWORD dwObjectId)
585 {
586 NetObj *pObject;
587
588 pObject = FindObjectById(dwObjectId);
589 if (pObject != NULL)
590 pObject->CalculateCompoundStatus();
591 }
592
593
594 //
595 // Fill message with alarm stats
596 //
597
598 void AlarmManager::GetAlarmStats(CSCPMessage *pMsg)
599 {
600 DWORD i, dwCount[5];
601
602 Lock();
603 pMsg->SetVariable(VID_NUM_ALARMS, m_dwNumAlarms);
604 memset(dwCount, 0, sizeof(DWORD) * 5);
605 for(i = 0; i < m_dwNumAlarms; i++)
606 dwCount[m_pAlarmList[i].nCurrentSeverity]++;
607 Unlock();
608 pMsg->SetVariableToInt32Array(VID_ALARMS_BY_SEVERITY, 5, dwCount);
609 }
610
611
612 //
613 // Watchdog thread
614 //
615
616 void AlarmManager::WatchdogThread(void)
617 {
618 DWORD i;
619 time_t now;
620
621 while(1)
622 {
623 if (ConditionWait(m_condShutdown, 1000))
624 break;
625
626 Lock();
627 now = time(NULL);
628 for(i = 0; i < m_dwNumAlarms; i++)
629 {
630 if ((m_pAlarmList[i].dwTimeout > 0) &&
631 (m_pAlarmList[i].nState == ALARM_STATE_OUTSTANDING) &&
632 (((time_t)m_pAlarmList[i].dwLastChangeTime + (time_t)m_pAlarmList[i].dwTimeout) < now))
633 {
634 DbgPrintf(5, _T("Alarm timeout: alarm_id=%d, last_change=%d, timeout=%d, now=%d"),
635 m_pAlarmList[i].dwAlarmId, m_pAlarmList[i].dwLastChangeTime,
636 m_pAlarmList[i].dwTimeout, now);
637
638 PostEvent(m_pAlarmList[i].dwTimeoutEvent, m_pAlarmList[i].dwSourceObject, "dssd",
639 m_pAlarmList[i].dwAlarmId, m_pAlarmList[i].szMessage,
640 m_pAlarmList[i].szKey, m_pAlarmList[i].dwSourceEventCode);
641 m_pAlarmList[i].dwTimeout = 0; // Disable repeated timeout events
642 UpdateAlarmInDB(&m_pAlarmList[i]);
643 }
644 }
645 Unlock();
646 }
647 }