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