- Added component locks
[public/netxms.git] / src / server / core / events.cpp
1 /*
2 ** Project X - Network Management System
3 ** Copyright (C) 2003 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 ** $module: events.cpp
20 **
21 **/
22
23 #include "nms_core.h"
24 #include <stdarg.h>
25
26
27 //
28 // Global variables
29 //
30
31 Queue *g_pEventQueue = NULL;
32 EventPolicy *g_pEventPolicy = NULL;
33
34
35 //
36 // Static data
37 //
38
39 static DWORD m_dwNumTemplates = 0;
40 static EVENT_TEMPLATE *m_pEventTemplates = NULL;
41
42
43 //
44 // Default constructor for event
45 //
46
47 Event::Event()
48 {
49 m_dwId = 0;
50 m_dwSeverity = 0;
51 m_dwSource = 0;
52 m_dwFlags = 0;
53 m_dwNumParameters = 0;
54 m_pszParameters = NULL;
55 m_szMessageText = NULL;
56 m_tTimeStamp = 0;
57 }
58
59
60 //
61 // Construct event from template
62 //
63
64 Event::Event(EVENT_TEMPLATE *pTemplate, DWORD dwSourceId, char *szFormat, va_list args)
65 {
66 m_tTimeStamp = time(NULL);
67 m_dwId = pTemplate->dwId;
68 m_dwSeverity = pTemplate->dwSeverity;
69 m_dwFlags = pTemplate->dwFlags;
70 m_dwSource = dwSourceId;
71
72 // Create parameters
73 if (szFormat != NULL)
74 {
75 DWORD i;
76
77 m_dwNumParameters = strlen(szFormat);
78 m_pszParameters = (char **)malloc(sizeof(char *) * m_dwNumParameters);
79
80 for(i = 0; i < m_dwNumParameters; i++)
81 {
82 switch(szFormat[i])
83 {
84 case 's':
85 m_pszParameters[i] = strdup(va_arg(args, char *));
86 break;
87 case 'd':
88 m_pszParameters[i] = (char *)malloc(16);
89 sprintf(m_pszParameters[i], "%d", va_arg(args, LONG));
90 break;
91 case 'x':
92 m_pszParameters[i] = (char *)malloc(16);
93 sprintf(m_pszParameters[i], "0x%08X", va_arg(args, DWORD));
94 break;
95 case 'a':
96 m_pszParameters[i] = (char *)malloc(16);
97 IpToStr(va_arg(args, DWORD), m_pszParameters[i]);
98 break;
99 default:
100 m_pszParameters[i] = (char *)malloc(64);
101 sprintf(m_pszParameters[i], "BAD FORMAT \"%c\" [value = 0x%08X]", szFormat[i], va_arg(args, DWORD));
102 break;
103 }
104 }
105 }
106 else
107 {
108 m_dwNumParameters = 0;
109 m_pszParameters = NULL;
110 }
111
112 // Create message text from template
113 ExpandMessageText(pTemplate->szMessageTemplate);
114 }
115
116
117 //
118 // Destructor for event
119 //
120
121 Event::~Event()
122 {
123 if (m_szMessageText != NULL)
124 free(m_szMessageText);
125 if (m_pszParameters != NULL)
126 {
127 DWORD i;
128
129 for(i = 0; i < m_dwNumParameters; i++)
130 if (m_pszParameters[i] != NULL)
131 free(m_pszParameters[i]);
132 free(m_pszParameters);
133 }
134 }
135
136
137 //
138 // Create message text from template
139 //
140
141 void Event::ExpandMessageText(char *szMessageTemplate)
142 {
143 char *pCurr;
144 DWORD dwPos, dwSize, dwParam;
145 NetObj *pObject;
146 struct tm *lt;
147 char szBuffer[4];
148
149 pObject = FindObjectById(m_dwSource);
150 if (pObject == NULL) // Normally shouldn't happen
151 {
152 pObject = g_pEntireNet;
153 }
154 dwSize = strlen(szMessageTemplate) + 1;
155 m_szMessageText = (char *)malloc(dwSize);
156 for(pCurr = szMessageTemplate, dwPos = 0; *pCurr != 0; pCurr++)
157 {
158 switch(*pCurr)
159 {
160 case '%': // Metacharacter
161 pCurr++;
162 if (*pCurr == 0)
163 {
164 pCurr--;
165 break; // Abnormal loop termination
166 }
167 switch(*pCurr)
168 {
169 case '%':
170 m_szMessageText[dwPos++] = '%';
171 break;
172 case 'n': // Name of event source
173 dwSize += strlen(pObject->Name());
174 m_szMessageText = (char *)realloc(m_szMessageText, dwSize);
175 strcpy(&m_szMessageText[dwPos], pObject->Name());
176 dwPos += strlen(pObject->Name());
177 break;
178 case 'a': // IP address of event source
179 dwSize += 16;
180 m_szMessageText = (char *)realloc(m_szMessageText, dwSize);
181 IpToStr(pObject->IpAddr(), &m_szMessageText[dwPos]);
182 dwPos = strlen(m_szMessageText);
183 break;
184 case 'i': // Source object identifier
185 dwSize += 10;
186 m_szMessageText = (char *)realloc(m_szMessageText, dwSize);
187 sprintf(&m_szMessageText[dwPos], "0x%08X", m_dwSource);
188 dwPos = strlen(m_szMessageText);
189 break;
190 case 't':
191 dwSize += 32;
192 m_szMessageText = (char *)realloc(m_szMessageText, dwSize);
193 lt = localtime(&m_tTimeStamp);
194 strftime(&m_szMessageText[dwPos], 32, "%d-%b-%Y %H:%M:%S", lt);
195 dwPos = strlen(m_szMessageText);
196 break;
197 case '0':
198 case '1':
199 case '2':
200 case '3':
201 case '4':
202 case '5':
203 case '6':
204 case '7':
205 case '8':
206 case '9':
207 szBuffer[0] = *pCurr;
208 if (isdigit(*(pCurr + 1)))
209 {
210 pCurr++;
211 szBuffer[1] = *pCurr;
212 szBuffer[2] = 0;
213 }
214 else
215 {
216 szBuffer[1] = 0;
217 }
218 dwParam = atol(szBuffer);
219 if ((dwParam > 0) && (dwParam <= m_dwNumParameters))
220 {
221 dwParam--;
222 dwSize += strlen(m_pszParameters[dwParam]);
223 m_szMessageText = (char *)realloc(m_szMessageText, dwSize);
224 strcpy(&m_szMessageText[dwPos], m_pszParameters[dwParam]);
225 dwPos += strlen(m_pszParameters[dwParam]);
226 }
227 break;
228 default: // All other characters are invalid, ignore
229 break;
230 }
231 break;
232 case '\\': // Escape character
233 pCurr++;
234 if (*pCurr == 0)
235 {
236 pCurr--;
237 break; // Abnormal loop termination
238 }
239 m_szMessageText[dwPos++] = *pCurr;
240 break;
241 default:
242 m_szMessageText[dwPos++] = *pCurr;
243 break;
244 }
245 }
246 m_szMessageText[dwPos] = 0;
247 }
248
249
250 //
251 // Fill NXC_EVENT structure with event data
252 //
253
254 void Event::PrepareMessage(NXC_EVENT *pEventData)
255 {
256 pEventData->dwTimeStamp = htonl(m_tTimeStamp);
257 pEventData->dwEventId = htonl(m_dwId);
258 pEventData->dwSeverity = htonl(m_dwSeverity);
259 pEventData->dwSourceId = htonl(m_dwSource);
260 strcpy(pEventData->szMessage, m_szMessageText);
261 }
262
263
264 //
265 // Inilialize event handling subsystem
266 //
267
268 BOOL InitEventSubsystem(void)
269 {
270 DB_RESULT hResult;
271 DWORD i;
272 BOOL bSuccess = FALSE;
273
274 // Create event queue
275 g_pEventQueue = new Queue;
276
277 // Load events from database
278 hResult = DBSelect(g_hCoreDB, "SELECT id,severity,flags,message,description FROM events ORDER BY id");
279 if (hResult != NULL)
280 {
281 m_dwNumTemplates = DBGetNumRows(hResult);
282 m_pEventTemplates = (EVENT_TEMPLATE *)malloc(sizeof(EVENT_TEMPLATE) * m_dwNumTemplates);
283 for(i = 0; i < m_dwNumTemplates; i++)
284 {
285 m_pEventTemplates[i].dwId = DBGetFieldULong(hResult, i, 0);
286 m_pEventTemplates[i].dwSeverity = DBGetFieldLong(hResult, i, 1);
287 m_pEventTemplates[i].dwFlags = DBGetFieldLong(hResult, i, 2);
288 m_pEventTemplates[i].szMessageTemplate = strdup(DBGetField(hResult, i, 3));
289 m_pEventTemplates[i].szDescription = strdup(DBGetField(hResult, i, 4));
290 }
291
292 DBFreeResult(hResult);
293
294 // Create and initialize event processing policy
295 g_pEventPolicy = new EventPolicy;
296 if (g_pEventPolicy->LoadFromDB())
297 bSuccess = TRUE;
298 else
299 WriteLog(MSG_EPP_LOAD_FAILED, EVENTLOG_ERROR_TYPE, NULL);
300 }
301 else
302 {
303 WriteLog(MSG_EVENT_LOAD_ERROR, EVENTLOG_ERROR_TYPE, NULL);
304 }
305
306 return bSuccess;
307 }
308
309
310 //
311 // Perform binary search on event template by id
312 // Returns INULL if key not found or pointer to appropriate template
313 //
314
315 static EVENT_TEMPLATE *FindEventTemplate(DWORD dwId)
316 {
317 DWORD dwFirst, dwLast, dwMid;
318
319 dwFirst = 0;
320 dwLast = m_dwNumTemplates - 1;
321
322 if ((dwId < m_pEventTemplates[0].dwId) || (dwId > m_pEventTemplates[dwLast].dwId))
323 return NULL;
324
325 while(dwFirst < dwLast)
326 {
327 dwMid = (dwFirst + dwLast) / 2;
328 if (dwId == m_pEventTemplates[dwMid].dwId)
329 return &m_pEventTemplates[dwMid];
330 if (dwId < m_pEventTemplates[dwMid].dwId)
331 dwLast = dwMid - 1;
332 else
333 dwFirst = dwMid + 1;
334 }
335
336 if (dwId == m_pEventTemplates[dwLast].dwId)
337 return &m_pEventTemplates[dwLast];
338
339 return NULL;
340 }
341
342
343 //
344 // Post event to the queue.
345 // Arguments:
346 // dwEventId - Event ID
347 // dwSourceId - Event source object ID
348 // szFormat - Parameter format string, each parameter represented by one character.
349 // The following format characters can be used:
350 // s - String
351 // d - Decimal integer
352 // x - Hex integer
353 // a - IP address
354 //
355
356 BOOL PostEvent(DWORD dwEventId, DWORD dwSourceId, char *szFormat, ...)
357 {
358 EVENT_TEMPLATE *pEventTemplate;
359 Event *pEvent;
360 va_list args;
361
362 // Find event template
363 if (m_dwNumTemplates == 0) // No event templates at all?
364 return FALSE;
365 pEventTemplate = FindEventTemplate(dwEventId);
366 if (pEventTemplate == NULL) // No event with such ID
367 return FALSE;
368
369 // Create new event
370 va_start(args, szFormat);
371 pEvent = new Event(pEventTemplate, dwSourceId, szFormat, args);
372 va_end(args);
373
374 // Add new event to queue
375 g_pEventQueue->Put(pEvent);
376
377 return TRUE;
378 }