initial Timer class
[public/netxms.git] / src / server / core / events.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2012 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: events.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Global variables
27 */
28 Queue *g_pEventQueue = NULL;
29 EventPolicy *g_pEventPolicy = NULL;
30 const TCHAR *g_szStatusText[] = { _T("NORMAL"), _T("WARNING"), _T("MINOR"), _T("MAJOR"), _T("CRITICAL"), _T("UNKNOWN"), _T("UNMANAGED"), _T("DISABLED"), _T("TESTING") };
31 const TCHAR *g_szStatusTextSmall[] = { _T("Normal"), _T("Warning"), _T("Minor"), _T("Major"), _T("Critical"), _T("Unknown"), _T("Unmanaged"), _T("Disabled"), _T("Testing") };
32
33 /**
34 * Static data
35 */
36 static UINT32 m_dwNumTemplates = 0;
37 static EVENT_TEMPLATE *m_pEventTemplates = NULL;
38 static RWLOCK m_rwlockTemplateAccess;
39
40 /**
41 * Default constructor for event
42 */
43 Event::Event()
44 {
45 m_qwId = 0;
46 m_szName[0] = 0;
47 m_qwRootId = 0;
48 m_dwCode = 0;
49 m_dwSeverity = 0;
50 m_dwSource = 0;
51 m_dwFlags = 0;
52 m_pszMessageText = NULL;
53 m_pszMessageTemplate = NULL;
54 m_tTimeStamp = 0;
55 m_pszUserTag = NULL;
56 m_pszCustomMessage = NULL;
57 m_parameters.setOwner(true);
58 }
59
60 /**
61 * Copy constructor for event
62 */
63 Event::Event(Event *src)
64 {
65 m_qwId = src->m_qwId;
66 _tcscpy(m_szName, src->m_szName);
67 m_qwRootId = src->m_qwRootId;
68 m_dwCode = src->m_dwCode;
69 m_dwSeverity = src->m_dwSeverity;
70 m_dwSource = src->m_dwSource;
71 m_dwFlags = src->m_dwFlags;
72 m_pszMessageText = _tcsdup_ex(src->m_pszMessageText);
73 m_pszMessageTemplate = _tcsdup_ex(src->m_pszMessageTemplate);
74 m_tTimeStamp = src->m_tTimeStamp;
75 m_pszUserTag = _tcsdup_ex(src->m_pszUserTag);
76 m_pszCustomMessage = _tcsdup_ex(src->m_pszCustomMessage);
77 m_parameters.setOwner(true);
78 for(int i = 0; i < src->m_parameters.size(); i++)
79 {
80 m_parameters.add(_tcsdup_ex((TCHAR *)src->m_parameters.get(i)));
81 }
82 m_parameterNames.addAll(&src->m_parameterNames);
83 }
84
85 /**
86 * Construct event from template
87 */
88 Event::Event(EVENT_TEMPLATE *pTemplate, UINT32 sourceId, const TCHAR *userTag, const char *szFormat, const TCHAR **names, va_list args)
89 {
90 _tcscpy(m_szName, pTemplate->szName);
91 m_tTimeStamp = time(NULL);
92 m_qwId = CreateUniqueEventId();
93 m_qwRootId = 0;
94 m_dwCode = pTemplate->dwCode;
95 m_dwSeverity = pTemplate->dwSeverity;
96 m_dwFlags = pTemplate->dwFlags;
97 m_dwSource = sourceId;
98 m_pszMessageText = NULL;
99 m_pszUserTag = (userTag != NULL) ? _tcsdup(userTag) : NULL;
100 if ((m_pszUserTag != NULL) && (_tcslen(m_pszUserTag) >= MAX_USERTAG_LENGTH))
101 m_pszUserTag[MAX_USERTAG_LENGTH - 1] = 0;
102 m_pszCustomMessage = NULL;
103 m_parameters.setOwner(true);
104
105 // Create parameters
106 if (szFormat != NULL)
107 {
108 int count = (int)strlen(szFormat);
109 TCHAR *buffer;
110
111 for(int i = 0; i < count; i++)
112 {
113 switch(szFormat[i])
114 {
115 case 's':
116 m_parameters.add(_tcsdup(va_arg(args, TCHAR *)));
117 break;
118 case 'm': // multibyte string
119 #ifdef UNICODE
120 m_parameters.add(WideStringFromMBString(va_arg(args, char *)));
121 #else
122 m_parameters.add(strdup(va_arg(args, char *)));
123 #endif
124 break;
125 case 'u': // UNICODE string
126 #ifdef UNICODE
127 m_parameters.add(wcsdup(va_arg(args, WCHAR *)));
128 #else
129 m_parameters.add(MBStringFromWideString(va_arg(args, WCHAR *)));
130 #endif
131 break;
132 case 'd':
133 buffer = (TCHAR *)malloc(16 * sizeof(TCHAR));
134 _sntprintf(buffer, 16, _T("%d"), va_arg(args, LONG));
135 m_parameters.add(buffer);
136 break;
137 case 'D':
138 buffer = (TCHAR *)malloc(32 * sizeof(TCHAR));
139 _sntprintf(buffer, 32, INT64_FMT, va_arg(args, INT64));
140 m_parameters.add(buffer);
141 break;
142 case 't':
143 buffer = (TCHAR *)malloc(32 * sizeof(TCHAR));
144 _sntprintf(buffer, 32, INT64_FMT, (INT64)va_arg(args, time_t));
145 m_parameters.add(buffer);
146 break;
147 case 'x':
148 case 'i':
149 buffer = (TCHAR *)malloc(16 * sizeof(TCHAR));
150 _sntprintf(buffer, 16, _T("0x%08X"), va_arg(args, UINT32));
151 m_parameters.add(buffer);
152 break;
153 case 'a':
154 buffer = (TCHAR *)malloc(16 * sizeof(TCHAR));
155 IpToStr(va_arg(args, UINT32), buffer);
156 m_parameters.add(buffer);
157 break;
158 case 'h':
159 buffer = (TCHAR *)malloc(32 * sizeof(TCHAR));
160 MACToStr(va_arg(args, BYTE *), buffer);
161 m_parameters.add(buffer);
162 break;
163 default:
164 buffer = (TCHAR *)malloc(64 * sizeof(TCHAR));
165 _sntprintf(buffer, 64, _T("BAD FORMAT \"%c\" [value = 0x%08X]"), szFormat[i], va_arg(args, UINT32));
166 m_parameters.add(buffer);
167 break;
168 }
169 m_parameterNames.add(((names != NULL) && (names[i] != NULL)) ? names[i] : _T(""));
170 }
171 }
172
173 m_pszMessageTemplate = _tcsdup(pTemplate->pszMessageTemplate);
174 }
175
176 /**
177 * Destructor for event
178 */
179 Event::~Event()
180 {
181 safe_free(m_pszMessageText);
182 safe_free(m_pszMessageTemplate);
183 safe_free(m_pszUserTag);
184 safe_free(m_pszCustomMessage);
185 }
186
187 /**
188 * Create message text from template
189 */
190 void Event::expandMessageText()
191 {
192 if (m_pszMessageTemplate != NULL)
193 {
194 if (m_pszMessageText != NULL)
195 {
196 free(m_pszMessageText);
197 m_pszMessageText = NULL;
198 }
199 m_pszMessageText = expandText(m_pszMessageTemplate);
200 free(m_pszMessageTemplate);
201 m_pszMessageTemplate = NULL;
202 }
203 }
204
205 /**
206 * Substitute % macros in given text with actual values
207 */
208 TCHAR *Event::expandText(const TCHAR *textTemplate, const TCHAR *alarmMsg, const TCHAR *alarmKey)
209 {
210 return Event::expandText(this, m_dwSource, textTemplate, alarmMsg, alarmKey);
211 }
212
213 /**
214 * Substitute % macros in given text with actual values
215 */
216 TCHAR *Event::expandText(Event *event, UINT32 sourceObject, const TCHAR *textTemplate, const TCHAR *alarmMsg, const TCHAR *alarmKey)
217 {
218 const TCHAR *pCurr;
219 UINT32 dwPos, dwSize, dwParam;
220 UINT32 sourceId = (event != NULL) ? event->getSourceId() : sourceObject;
221 NetObj *pObject;
222 struct tm *lt;
223 TCHAR *pText, szBuffer[4], scriptName[256];
224 int i;
225 uuid_t guid;
226
227 DbgPrintf(8, _T("Event::expandText(event=%p sourceObject=%d template='%s' alarmMsg='%s' alarmKey='%s')"),
228 event, (int)sourceObject, CHECK_NULL(textTemplate), CHECK_NULL(alarmMsg), CHECK_NULL(alarmKey));
229
230 pObject = FindObjectById(sourceId);
231 if (pObject == NULL)
232 {
233 pObject = FindObjectById(g_dwMgmtNode);
234 if (pObject == NULL)
235 pObject = g_pEntireNet;
236 }
237 dwSize = (UINT32)_tcslen(textTemplate) + 1;
238 pText = (TCHAR *)malloc(dwSize * sizeof(TCHAR));
239 for(pCurr = textTemplate, dwPos = 0; *pCurr != 0; pCurr++)
240 {
241 switch(*pCurr)
242 {
243 case '%': // Metacharacter
244 pCurr++;
245 if (*pCurr == 0)
246 {
247 pCurr--;
248 break; // Abnormal loop termination
249 }
250 switch(*pCurr)
251 {
252 case '%':
253 pText[dwPos++] = '%';
254 break;
255 case 'n': // Name of event source
256 dwSize += (UINT32)_tcslen(pObject->Name());
257 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
258 _tcscpy(&pText[dwPos], pObject->Name());
259 dwPos += (UINT32)_tcslen(pObject->Name());
260 break;
261 case 'a': // IP address of event source
262 dwSize += 16;
263 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
264 IpToStr(pObject->IpAddr(), &pText[dwPos]);
265 dwPos = (UINT32)_tcslen(pText);
266 break;
267 case 'g': // Source object's GUID
268 dwSize += 36;
269 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
270 pObject->getGuid(guid);
271 uuid_to_string(guid, &pText[dwPos]);
272 dwPos = (UINT32)_tcslen(pText);
273 break;
274 case 'i': // Source object identifier in form 0xhhhhhhhh
275 dwSize += 10;
276 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
277 _sntprintf(&pText[dwPos], 11, _T("0x%08X"), sourceId);
278 dwPos = (UINT32)_tcslen(pText);
279 break;
280 case 'I': // Source object identifier in decimal form
281 dwSize += 10;
282 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
283 _sntprintf(&pText[dwPos], 11, _T("%u"), (unsigned int)sourceId);
284 dwPos = (UINT32)_tcslen(pText);
285 break;
286 case 't': // Event's timestamp
287 dwSize += 32;
288 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
289 if (event != NULL)
290 {
291 lt = localtime(&event->m_tTimeStamp);
292 }
293 else
294 {
295 time_t t = time(NULL);
296 lt = localtime(&t);
297 }
298 _tcsftime(&pText[dwPos], 32, _T("%d-%b-%Y %H:%M:%S"), lt);
299 dwPos = (UINT32)_tcslen(pText);
300 break;
301 case 'T': // Event's timestamp as number of seconds since epoch
302 dwSize += 16;
303 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
304 _sntprintf(&pText[dwPos], 16, _T("%lu"), (unsigned long)((event != NULL) ? event->m_tTimeStamp : time(NULL)));
305 dwPos = (UINT32)_tcslen(pText);
306 break;
307 case 'c': // Event code
308 dwSize += 16;
309 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
310 _sntprintf(&pText[dwPos], 16, _T("%u"), (unsigned int)((event != NULL) ? event->m_dwCode : 0));
311 dwPos = (UINT32)_tcslen(pText);
312 break;
313 case 'N': // Event name
314 if (event != NULL)
315 {
316 dwSize += (UINT32)_tcslen(event->m_szName);
317 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
318 _tcscpy(&pText[dwPos], event->m_szName);
319 dwPos += (UINT32)_tcslen(event->m_szName);
320 }
321 break;
322 case 's': // Severity code
323 if (event != NULL)
324 {
325 dwSize += 3;
326 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
327 _sntprintf(&pText[dwPos], 4, _T("%d"), (int)event->m_dwSeverity);
328 dwPos = (UINT32)_tcslen(pText);
329 }
330 break;
331 case 'S': // Severity text
332 if (event != NULL)
333 {
334 dwSize += (UINT32)_tcslen(g_szStatusTextSmall[event->m_dwSeverity]);
335 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
336 _tcscpy(&pText[dwPos], g_szStatusTextSmall[event->m_dwSeverity]);
337 dwPos += (UINT32)_tcslen(g_szStatusTextSmall[event->m_dwSeverity]);
338 }
339 break;
340 case 'v': // NetXMS server version
341 dwSize += (UINT32)_tcslen(NETXMS_VERSION_STRING);
342 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
343 _tcscpy(&pText[dwPos], NETXMS_VERSION_STRING);
344 dwPos += (UINT32)_tcslen(NETXMS_VERSION_STRING);
345 break;
346 case 'm':
347 if ((event != NULL) && (event->m_pszMessageText != NULL))
348 {
349 dwSize += (UINT32)_tcslen(event->m_pszMessageText);
350 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
351 _tcscpy(&pText[dwPos], event->m_pszMessageText);
352 dwPos += (UINT32)_tcslen(event->m_pszMessageText);
353 }
354 break;
355 case 'M': // Custom message (usually set by matching script in EPP)
356 if ((event != NULL) && (event->m_pszCustomMessage != NULL))
357 {
358 dwSize += (UINT32)_tcslen(event->m_pszCustomMessage);
359 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
360 _tcscpy(&pText[dwPos], event->m_pszCustomMessage);
361 dwPos += (UINT32)_tcslen(event->m_pszCustomMessage);
362 }
363 break;
364 case 'A': // Associated alarm message
365 if (alarmMsg != NULL)
366 {
367 dwSize += (UINT32)_tcslen(alarmMsg);
368 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
369 _tcscpy(&pText[dwPos], alarmMsg);
370 dwPos += (UINT32)_tcslen(alarmMsg);
371 }
372 break;
373 case 'K': // Associated alarm key
374 if (alarmKey != NULL)
375 {
376 dwSize += (UINT32)_tcslen(alarmKey);
377 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
378 _tcscpy(&pText[dwPos], alarmKey);
379 dwPos += (UINT32)_tcslen(alarmKey);
380 }
381 break;
382 case 'u': // User tag
383 if ((event != NULL) && (event->m_pszUserTag != NULL))
384 {
385 dwSize += (UINT32)_tcslen(event->m_pszUserTag);
386 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
387 _tcscpy(&pText[dwPos], event->m_pszUserTag);
388 dwPos += (UINT32)_tcslen(event->m_pszUserTag);
389 }
390 break;
391 case '0':
392 case '1':
393 case '2':
394 case '3':
395 case '4':
396 case '5':
397 case '6':
398 case '7':
399 case '8':
400 case '9':
401 if (event != NULL)
402 {
403 szBuffer[0] = *pCurr;
404 if (isdigit(*(pCurr + 1)))
405 {
406 pCurr++;
407 szBuffer[1] = *pCurr;
408 szBuffer[2] = 0;
409 }
410 else
411 {
412 szBuffer[1] = 0;
413 }
414 dwParam = _tcstoul(szBuffer, NULL, 10);
415 if ((dwParam > 0) && (dwParam <= (UINT32)event->m_parameters.size()))
416 {
417 const TCHAR *value = (TCHAR *)event->m_parameters.get(dwParam - 1);
418 if (value == NULL)
419 value = _T("");
420 dwSize += (UINT32)_tcslen(value);
421 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
422 _tcscpy(&pText[dwPos], value);
423 dwPos += (UINT32)_tcslen(value);
424 }
425 }
426 break;
427 case '[': // Script
428 for(i = 0, pCurr++; (*pCurr != ']') && (*pCurr != 0) && (i < 255); pCurr++)
429 {
430 scriptName[i++] = *pCurr;
431 }
432 if (*pCurr == 0) // no terminating ]
433 {
434 pCurr--;
435 }
436 else
437 {
438 scriptName[i] = 0;
439
440 // Entry point can be given in form script/entry_point
441 TCHAR *entryPoint = _tcschr(scriptName, _T('/'));
442 if (entryPoint != NULL)
443 {
444 *entryPoint = 0;
445 entryPoint++;
446 StrStrip(entryPoint);
447 }
448 StrStrip(scriptName);
449
450 NXSL_VM *vm = g_pScriptLibrary->createVM(scriptName, new NXSL_ServerEnv);
451 if (vm != NULL)
452 {
453 if (pObject->Type() == OBJECT_NODE)
454 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, pObject)));
455 vm->setGlobalVariable(_T("$event"), (event != NULL) ? new NXSL_Value(new NXSL_Object(&g_nxslEventClass, event)) : new NXSL_Value);
456 if (alarmMsg != NULL)
457 vm->setGlobalVariable(_T("$alarmMessage"), new NXSL_Value(alarmMsg));
458 if (alarmKey != NULL)
459 vm->setGlobalVariable(_T("$alarmKey"), new NXSL_Value(alarmKey));
460
461 if (vm->run(0, NULL, NULL, NULL, NULL, entryPoint))
462 {
463 NXSL_Value *result = vm->getResult();
464 if (result != NULL)
465 {
466 const TCHAR *temp = result->getValueAsCString();
467 if (temp != NULL)
468 {
469 dwSize += (UINT32)_tcslen(temp);
470 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
471 _tcscpy(&pText[dwPos], temp);
472 dwPos += (UINT32)_tcslen(temp);
473 DbgPrintf(4, _T("Event::ExpandText(%d, \"%s\"): Script %s executed successfully"),
474 (int)((event != NULL) ? event->m_dwCode : 0), textTemplate, scriptName);
475 }
476 }
477 }
478 else
479 {
480 DbgPrintf(4, _T("Event::ExpandText(%d, \"%s\"): Script %s execution error: %s"),
481 (int)((event != NULL) ? event->m_dwCode : 0), textTemplate, scriptName, vm->getErrorText());
482 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", scriptName, vm->getErrorText(), 0);
483 }
484 }
485 else
486 {
487 DbgPrintf(4, _T("Event::ExpandText(%d, \"%s\"): Cannot find script %s"),
488 (int)((event != NULL) ? event->m_dwCode : 0), textTemplate, scriptName);
489 }
490 }
491 break;
492 case '{': // Custom attribute
493 for(i = 0, pCurr++; (*pCurr != '}') && (*pCurr != 0) && (i < 255); pCurr++)
494 {
495 scriptName[i++] = *pCurr;
496 }
497 if (*pCurr == 0) // no terminating }
498 {
499 pCurr--;
500 }
501 else
502 {
503 scriptName[i] = 0;
504 StrStrip(scriptName);
505 const TCHAR *temp = pObject->getCustomAttribute(scriptName);
506 if (temp != NULL)
507 {
508 dwSize += (UINT32)_tcslen(temp);
509 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
510 _tcscpy(&pText[dwPos], temp);
511 dwPos += (UINT32)_tcslen(temp);
512 }
513 }
514 break;
515 case '<': // Named parameter
516 if (event != NULL)
517 {
518 for(i = 0, pCurr++; (*pCurr != '>') && (*pCurr != 0) && (i < 255); pCurr++)
519 {
520 scriptName[i++] = *pCurr;
521 }
522 if (*pCurr == 0) // no terminating >
523 {
524 pCurr--;
525 }
526 else
527 {
528 scriptName[i] = 0;
529 StrStrip(scriptName);
530 int index = event->m_parameterNames.indexOfIgnoreCase(scriptName);
531 if (index != -1)
532 {
533 const TCHAR *temp = (TCHAR *)event->m_parameters.get(index);
534 if (temp != NULL)
535 {
536 dwSize += (UINT32)_tcslen(temp);
537 pText = (TCHAR *)realloc(pText, dwSize * sizeof(TCHAR));
538 _tcscpy(&pText[dwPos], temp);
539 dwPos += (UINT32)_tcslen(temp);
540 }
541 }
542 }
543 }
544 break;
545 default: // All other characters are invalid, ignore
546 break;
547 }
548 break;
549 case '\\': // Escape character
550 pCurr++;
551 if (*pCurr == 0)
552 {
553 pCurr--;
554 break; // Abnormal loop termination
555 }
556 switch(*pCurr)
557 {
558 case 't':
559 pText[dwPos++] = '\t';
560 break;
561 case 'n':
562 pText[dwPos++] = 0x0D;
563 pText[dwPos++] = 0x0A;
564 break;
565 default:
566 pText[dwPos++] = *pCurr;
567 break;
568 }
569 break;
570 default:
571 pText[dwPos++] = *pCurr;
572 break;
573 }
574 }
575 pText[dwPos] = 0;
576 return pText;
577 }
578
579 /**
580 * Add new parameter to event
581 */
582 void Event::addParameter(const TCHAR *name, const TCHAR *value)
583 {
584 m_parameters.add(_tcsdup(value));
585 m_parameterNames.add(name);
586 }
587
588 /**
589 * Set value of named parameter
590 */
591 void Event::setNamedParameter(const TCHAR *name, const TCHAR *value)
592 {
593 int index = m_parameterNames.indexOfIgnoreCase(name);
594 if (index != -1)
595 {
596 m_parameters.replace(index, _tcsdup(value));
597 m_parameterNames.replace(index, name);
598 }
599 else
600 {
601 m_parameters.add(_tcsdup(value));
602 m_parameterNames.add(name);
603 }
604 }
605
606 /**
607 * Set value (and optionally name) of parameter at given index.
608 *
609 * @param index 0-based parameter index
610 * @param name parameter name (can be NULL)
611 * @param value new value
612 */
613 void Event::setParameter(int index, const TCHAR *name, const TCHAR *value)
614 {
615 if (index < 0)
616 return;
617
618 int addup = index - m_parameters.size();
619 for(int i = 0; i < addup; i++)
620 {
621 m_parameters.add(_tcsdup(_T("")));
622 m_parameterNames.add(_T(""));
623 }
624 if (index < m_parameters.size())
625 {
626 m_parameters.replace(index, _tcsdup(value));
627 m_parameterNames.replace(index, CHECK_NULL_EX(name));
628 }
629 else
630 {
631 m_parameters.add(_tcsdup(value));
632 m_parameterNames.add(CHECK_NULL_EX(name));
633 }
634 }
635
636 /**
637 * Fill message with event data
638 */
639 void Event::prepareMessage(CSCPMessage *pMsg)
640 {
641 UINT32 dwId = VID_EVENTLOG_MSG_BASE;
642
643 pMsg->SetVariable(VID_NUM_RECORDS, (UINT32)1);
644 pMsg->SetVariable(VID_RECORDS_ORDER, (WORD)RECORD_ORDER_NORMAL);
645 pMsg->SetVariable(dwId++, m_qwId);
646 pMsg->SetVariable(dwId++, m_dwCode);
647 pMsg->SetVariable(dwId++, (UINT32)m_tTimeStamp);
648 pMsg->SetVariable(dwId++, m_dwSource);
649 pMsg->SetVariable(dwId++, (WORD)m_dwSeverity);
650 pMsg->SetVariable(dwId++, CHECK_NULL(m_pszMessageText));
651 pMsg->SetVariable(dwId++, CHECK_NULL(m_pszUserTag));
652 pMsg->SetVariable(dwId++, (UINT32)m_parameters.size());
653 for(int i = 0; i < m_parameters.size(); i++)
654 pMsg->SetVariable(dwId++, (TCHAR *)m_parameters.get(i));
655 }
656
657 /**
658 * Load event configuration from database
659 */
660 static BOOL LoadEvents()
661 {
662 DB_RESULT hResult;
663 UINT32 i;
664 BOOL bSuccess = FALSE;
665
666 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
667 hResult = DBSelect(hdb, _T("SELECT event_code,severity,flags,message,description,event_name FROM event_cfg ORDER BY event_code"));
668 if (hResult != NULL)
669 {
670 m_dwNumTemplates = DBGetNumRows(hResult);
671 m_pEventTemplates = (EVENT_TEMPLATE *)malloc(sizeof(EVENT_TEMPLATE) * m_dwNumTemplates);
672 for(i = 0; i < m_dwNumTemplates; i++)
673 {
674 m_pEventTemplates[i].dwCode = DBGetFieldULong(hResult, i, 0);
675 m_pEventTemplates[i].dwSeverity = DBGetFieldLong(hResult, i, 1);
676 m_pEventTemplates[i].dwFlags = DBGetFieldLong(hResult, i, 2);
677 m_pEventTemplates[i].pszMessageTemplate = DBGetField(hResult, i, 3, NULL, 0);
678 m_pEventTemplates[i].pszDescription = DBGetField(hResult, i, 4, NULL, 0);
679 DBGetField(hResult, i, 5, m_pEventTemplates[i].szName, MAX_EVENT_NAME);
680 }
681
682 DBFreeResult(hResult);
683 bSuccess = TRUE;
684 }
685 else
686 {
687 nxlog_write(MSG_EVENT_LOAD_ERROR, EVENTLOG_ERROR_TYPE, NULL);
688 }
689
690 DBConnectionPoolReleaseConnection(hdb);
691 return bSuccess;
692 }
693
694 /**
695 * Inilialize event handling subsystem
696 */
697 BOOL InitEventSubsystem()
698 {
699 BOOL bSuccess;
700
701 // Create template access mutex
702 m_rwlockTemplateAccess = RWLockCreate();
703
704 // Create event queue
705 g_pEventQueue = new Queue;
706
707 // Load events from database
708 bSuccess = LoadEvents();
709
710 // Create and initialize event processing policy
711 if (bSuccess)
712 {
713 g_pEventPolicy = new EventPolicy;
714 if (!g_pEventPolicy->loadFromDB())
715 {
716 bSuccess = FALSE;
717 nxlog_write(MSG_EPP_LOAD_FAILED, EVENTLOG_ERROR_TYPE, NULL);
718 delete g_pEventPolicy;
719 }
720 }
721
722 return bSuccess;
723 }
724
725 /**
726 * Shutdown event subsystem
727 */
728 void ShutdownEventSubsystem()
729 {
730 delete g_pEventQueue;
731 delete g_pEventPolicy;
732
733 if (m_pEventTemplates != NULL)
734 {
735 UINT32 i;
736 for(i = 0; i < m_dwNumTemplates; i++)
737 {
738 safe_free(m_pEventTemplates[i].pszDescription);
739 safe_free(m_pEventTemplates[i].pszMessageTemplate);
740 }
741 free(m_pEventTemplates);
742 }
743 m_dwNumTemplates = 0;
744 m_pEventTemplates = NULL;
745
746 RWLockDestroy(m_rwlockTemplateAccess);
747 }
748
749 /**
750 * Reload event templates from database
751 */
752 void ReloadEvents()
753 {
754 UINT32 i;
755
756 RWLockWriteLock(m_rwlockTemplateAccess, INFINITE);
757 if (m_pEventTemplates != NULL)
758 {
759 for(i = 0; i < m_dwNumTemplates; i++)
760 {
761 safe_free(m_pEventTemplates[i].pszDescription);
762 safe_free(m_pEventTemplates[i].pszMessageTemplate);
763 }
764 free(m_pEventTemplates);
765 }
766 m_dwNumTemplates = 0;
767 m_pEventTemplates = NULL;
768 LoadEvents();
769 RWLockUnlock(m_rwlockTemplateAccess);
770 }
771
772 /**
773 * Delete event template from list
774 */
775 void DeleteEventTemplateFromList(UINT32 eventCode)
776 {
777 UINT32 i;
778
779 RWLockWriteLock(m_rwlockTemplateAccess, INFINITE);
780 for(i = 0; i < m_dwNumTemplates; i++)
781 {
782 if (m_pEventTemplates[i].dwCode == eventCode)
783 {
784 m_dwNumTemplates--;
785 safe_free(m_pEventTemplates[i].pszDescription);
786 safe_free(m_pEventTemplates[i].pszMessageTemplate);
787 memmove(&m_pEventTemplates[i], &m_pEventTemplates[i + 1],
788 sizeof(EVENT_TEMPLATE) * (m_dwNumTemplates - i));
789 break;
790 }
791 }
792 RWLockUnlock(m_rwlockTemplateAccess);
793 }
794
795 /**
796 * Perform binary search on event template by id
797 * Returns INULL if key not found or pointer to appropriate template
798 */
799 static EVENT_TEMPLATE *FindEventTemplate(UINT32 eventCode)
800 {
801 UINT32 dwFirst, dwLast, dwMid;
802
803 dwFirst = 0;
804 dwLast = m_dwNumTemplates - 1;
805
806 if ((eventCode < m_pEventTemplates[0].dwCode) || (eventCode > m_pEventTemplates[dwLast].dwCode))
807 return NULL;
808
809 while(dwFirst < dwLast)
810 {
811 dwMid = (dwFirst + dwLast) / 2;
812 if (eventCode == m_pEventTemplates[dwMid].dwCode)
813 return &m_pEventTemplates[dwMid];
814 if (eventCode < m_pEventTemplates[dwMid].dwCode)
815 dwLast = dwMid - 1;
816 else
817 dwFirst = dwMid + 1;
818 }
819
820 if (eventCode == m_pEventTemplates[dwLast].dwCode)
821 return &m_pEventTemplates[dwLast];
822
823 return NULL;
824 }
825
826 /**
827 * Post event to given event queue.
828 *
829 * @param queue event queue to post events to
830 * @param eventCode Event code
831 * @param sourceId Event source object ID
832 * @param userTag event's user tag
833 * @param format Parameter format string, each parameter represented by one character.
834 * The following format characters can be used:
835 * s - String
836 * m - Multibyte string
837 * u - UNICODE string
838 * d - Decimal integer
839 * D - 64-bit decimal integer
840 * x - Hex integer
841 * a - IP address
842 * h - MAC (hardware) address
843 * i - Object ID
844 * @param names names for parameters (NULL if parameters are unnamed)
845 * @param args event parameters
846 */
847 static BOOL RealPostEvent(Queue *queue, UINT32 eventCode, UINT32 sourceId,
848 const TCHAR *userTag, const char *format, const TCHAR **names, va_list args)
849 {
850 EVENT_TEMPLATE *pEventTemplate;
851 Event *pEvent;
852 BOOL bResult = FALSE;
853
854 RWLockReadLock(m_rwlockTemplateAccess, INFINITE);
855
856 // Find event template
857 if (m_dwNumTemplates > 0) // Is there any templates?
858 {
859 pEventTemplate = FindEventTemplate(eventCode);
860 if (pEventTemplate != NULL)
861 {
862 // Template found, create new event
863 pEvent = new Event(pEventTemplate, sourceId, userTag, format, names, args);
864
865 // Add new event to queue
866 queue->Put(pEvent);
867
868 bResult = TRUE;
869 }
870 }
871
872 RWLockUnlock(m_rwlockTemplateAccess);
873 return bResult;
874 }
875
876 /**
877 * Post event to system event queue.
878 *
879 * @param eventCode Event code
880 * @param sourceId Event source object ID
881 * @param format Parameter format string, each parameter represented by one character.
882 * The following format characters can be used:
883 * s - String
884 * m - Multibyte string
885 * u - UNICODE string
886 * d - Decimal integer
887 * D - 64-bit decimal integer
888 * x - Hex integer
889 * a - IP address
890 * h - MAC (hardware) address
891 * i - Object ID
892 * t - timestamp (time_t) as raw value (seconds since epoch)
893 */
894 BOOL NXCORE_EXPORTABLE PostEvent(UINT32 eventCode, UINT32 sourceId, const char *format, ...)
895 {
896 va_list args;
897 BOOL bResult;
898
899 va_start(args, format);
900 bResult = RealPostEvent(g_pEventQueue, eventCode, sourceId, NULL, format, NULL, args);
901 va_end(args);
902 return bResult;
903 }
904
905 /**
906 * Post event to system event queue.
907 *
908 * @param eventCode Event code
909 * @param sourceId Event source object ID
910 * @param format Parameter format string, each parameter represented by one character.
911 * The following format characters can be used:
912 * s - String
913 * m - Multibyte string
914 * u - UNICODE string
915 * d - Decimal integer
916 * D - 64-bit decimal integer
917 * x - Hex integer
918 * a - IP address
919 * h - MAC (hardware) address
920 * i - Object ID
921 * @param names names for parameters (NULL if parameters are unnamed)
922 */
923 BOOL NXCORE_EXPORTABLE PostEventWithNames(UINT32 eventCode, UINT32 sourceId, const char *format, const TCHAR **names, ...)
924 {
925 va_list args;
926 BOOL bResult;
927
928 va_start(args, names);
929 bResult = RealPostEvent(g_pEventQueue, eventCode, sourceId, NULL, format, names, args);
930 va_end(args);
931 return bResult;
932 }
933
934 /**
935 * Post event to system event queue.
936 *
937 * @param eventCode Event code
938 * @param sourceId Event source object ID
939 * @param parameters event parameters list
940 */
941 BOOL NXCORE_EXPORTABLE PostEventWithNames(UINT32 eventCode, UINT32 sourceId, StringMap *parameters)
942 {
943 int count = parameters->size();
944 if (count > 1023)
945 count = 1023;
946
947 char format[1024];
948 memset(format, 's', count);
949 format[count] = 0;
950
951 const TCHAR *names[1024];
952 const TCHAR *args[1024];
953 for(int i = 0; i < count; i++)
954 {
955 names[i] = parameters->getKeyByIndex(i);
956 args[i] = parameters->getValueByIndex(i);
957 }
958
959 // BOOL bResult = RealPostEvent(g_pEventQueue, eventCode, sourceId, NULL, format, names, args);
960 return bResult;
961 }
962
963 /**
964 * Post event to system event queue.
965 *
966 * @param eventCode Event code
967 * @param sourceId Event source object ID
968 * @param userTag event's user tag
969 * @param format Parameter format string, each parameter represented by one character.
970 * The following format characters can be used:
971 * s - String
972 * m - Multibyte string
973 * u - UNICODE string
974 * d - Decimal integer
975 * D - 64-bit decimal integer
976 * x - Hex integer
977 * a - IP address
978 * h - MAC (hardware) address
979 * i - Object ID
980 * @param names names for parameters (NULL if parameters are unnamed)
981 * @param args event parameters
982 */
983 BOOL NXCORE_EXPORTABLE PostEventWithTag(UINT32 eventCode, UINT32 sourceId, const TCHAR *userTag, const char *format, ...)
984 {
985 va_list args;
986 BOOL bResult;
987
988 va_start(args, format);
989 bResult = RealPostEvent(g_pEventQueue, eventCode, sourceId, userTag, format, NULL, args);
990 va_end(args);
991 return bResult;
992 }
993
994 /**
995 * Post event to given event queue.
996 *
997 * @param queue event queue to post events to
998 * @param eventCode Event code
999 * @param sourceId Event source object ID
1000 * @param format Parameter format string, each parameter represented by one character.
1001 * The following format characters can be used:
1002 * s - String
1003 * m - Multibyte string
1004 * u - UNICODE string
1005 * d - Decimal integer
1006 * D - 64-bit decimal integer
1007 * x - Hex integer
1008 * a - IP address
1009 * h - MAC (hardware) address
1010 * i - Object ID
1011 */
1012 BOOL NXCORE_EXPORTABLE PostEventEx(Queue *queue, UINT32 eventCode, UINT32 sourceId, const char *format, ...)
1013 {
1014 va_list args;
1015 BOOL bResult;
1016
1017 va_start(args, format);
1018 bResult = RealPostEvent(queue, eventCode, sourceId, NULL, format, NULL, args);
1019 va_end(args);
1020 return bResult;
1021 }
1022
1023 /**
1024 * Resend events from specific queue to system event queue
1025 */
1026 void NXCORE_EXPORTABLE ResendEvents(Queue *queue)
1027 {
1028 while(1)
1029 {
1030 void *pEvent = queue->Get();
1031 if (pEvent == NULL)
1032 break;
1033 g_pEventQueue->Put(pEvent);
1034 }
1035 }
1036
1037 /**
1038 * Create NXMP record for event
1039 */
1040 void CreateNXMPEventRecord(String &str, UINT32 eventCode)
1041 {
1042 EVENT_TEMPLATE *p;
1043 String strText, strDescr;
1044
1045 RWLockReadLock(m_rwlockTemplateAccess, INFINITE);
1046
1047 // Find event template
1048 if (m_dwNumTemplates > 0) // Is there any templates?
1049 {
1050 p = FindEventTemplate(eventCode);
1051 if (p != NULL)
1052 {
1053 str.addFormattedString(_T("\t\t<event id=\"%d\">\n")
1054 _T("\t\t\t<name>%s</name>\n")
1055 _T("\t\t\t<code>%d</code>\n")
1056 _T("\t\t\t<severity>%d</severity>\n")
1057 _T("\t\t\t<flags>%d</flags>\n")
1058 _T("\t\t\t<message>%s</message>\n")
1059 _T("\t\t\t<description>%s</description>\n")
1060 _T("\t\t</event>\n"),
1061 p->dwCode, (const TCHAR *)EscapeStringForXML2(p->szName), p->dwCode, p->dwSeverity,
1062 p->dwFlags, (const TCHAR *)EscapeStringForXML2(p->pszMessageTemplate),
1063 (const TCHAR *)EscapeStringForXML2(p->pszDescription));
1064 }
1065 }
1066
1067 RWLockUnlock(m_rwlockTemplateAccess);
1068 }
1069
1070 /**
1071 * Resolve event name
1072 */
1073 BOOL EventNameFromCode(UINT32 eventCode, TCHAR *pszBuffer)
1074 {
1075 EVENT_TEMPLATE *p;
1076 BOOL bRet = FALSE;
1077
1078 RWLockReadLock(m_rwlockTemplateAccess, INFINITE);
1079
1080 // Find event template
1081 if (m_dwNumTemplates > 0) // Is there any templates?
1082 {
1083 p = FindEventTemplate(eventCode);
1084 if (p != NULL)
1085 {
1086 _tcscpy(pszBuffer, p->szName);
1087 bRet = TRUE;
1088 }
1089 else
1090 {
1091 _tcscpy(pszBuffer, _T("UNKNOWN_EVENT"));
1092 }
1093 }
1094 else
1095 {
1096 _tcscpy(pszBuffer, _T("UNKNOWN_EVENT"));
1097 }
1098
1099 RWLockUnlock(m_rwlockTemplateAccess);
1100 return bRet;
1101 }
1102
1103 /**
1104 * Find event template by code - suitable for external call
1105 */
1106 EVENT_TEMPLATE *FindEventTemplateByCode(UINT32 eventCode)
1107 {
1108 EVENT_TEMPLATE *p = NULL;
1109
1110 RWLockReadLock(m_rwlockTemplateAccess, INFINITE);
1111 p = FindEventTemplate(eventCode);
1112 RWLockUnlock(m_rwlockTemplateAccess);
1113 return p;
1114 }
1115
1116 /**
1117 * Find event template by name - suitable for external call
1118 */
1119 EVENT_TEMPLATE *FindEventTemplateByName(const TCHAR *name)
1120 {
1121 EVENT_TEMPLATE *p = NULL;
1122 UINT32 i;
1123
1124 RWLockReadLock(m_rwlockTemplateAccess, INFINITE);
1125 for(i = 0; i < m_dwNumTemplates; i++)
1126 {
1127 if (!_tcscmp(m_pEventTemplates[i].szName, name))
1128 {
1129 p = &m_pEventTemplates[i];
1130 break;
1131 }
1132 }
1133 RWLockUnlock(m_rwlockTemplateAccess);
1134 return p;
1135 }
1136
1137 /**
1138 * Translate event name to code
1139 * If event with given name does not exist, returns supplied default value
1140 */
1141 UINT32 EventCodeFromName(const TCHAR *name, UINT32 defaultValue)
1142 {
1143 EVENT_TEMPLATE *p = FindEventTemplateByName(name);
1144 return (p != NULL) ? p->dwCode : defaultValue;
1145 }