Implemented DB driver call PrepareString; alarms table converted to new format
[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 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);
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);
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
156 void 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
166 pszExpMsg = pEvent->expandText(pszMsg);
167 pszExpKey = pEvent->expandText(pszKey);
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);
179 m_pAlarmList[i].dwSourceObject = pEvent->getSourceId();
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);
201 alarm.qwSourceEventId = pEvent->getId();
202 alarm.dwSourceEventCode = pEvent->getCode();
203 alarm.dwSourceObject = pEvent->getSourceId();
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
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 "
236 "(%d,%d,%d,%d,%d,%s,%d,%d,%s,%d,%d,%d,%s,%d,%d,%d,%d," UINT64_FMT ")",
237 alarm.dwAlarmId, alarm.dwCreationTime, alarm.dwLastChangeTime,
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),
244 alarm.dwRepeatCount, alarm.dwTermByUser, alarm.dwTimeout,
245 alarm.dwTimeoutEvent, alarm.qwSourceEventId);
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
262 DWORD 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
299 DWORD 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
338 void 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
384 void 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
415 void AlarmManager::UpdateAlarmInDB(NXC_ALARM *pAlarm)
416 {
417 char szQuery[1024];
418
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,"
421 "hd_state=%d,hd_ref=%s,timeout=%d,timeout_event=%d WHERE alarm_id=%d",
422 pAlarm->nState, pAlarm->dwAckByUser, pAlarm->dwTermByUser,
423 pAlarm->dwLastChangeTime, pAlarm->nCurrentSeverity,
424 pAlarm->dwRepeatCount, pAlarm->nHelpDeskState,
425 (const TCHAR *)DBPrepareString(pAlarm->szHelpDeskRef),
426 pAlarm->dwTimeout, pAlarm->dwTimeoutEvent, pAlarm->dwAlarmId);
427 QueueSQLRequest(szQuery);
428 }
429
430
431 //
432 // Callback for client session enumeration
433 //
434
435 void 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
446 void 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
458 void 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
507 NetObj *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
547 int 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
572 void 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
586 void 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
604 void 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 }