- Added component locks
[public/netxms.git] / src / server / core / events.cpp
CommitLineData
f9b7e653
VK
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
31Queue *g_pEventQueue = NULL;
c7ca9142 32EventPolicy *g_pEventPolicy = NULL;
f9b7e653
VK
33
34
35//
36// Static data
37//
38
39static DWORD m_dwNumTemplates = 0;
40static EVENT_TEMPLATE *m_pEventTemplates = NULL;
41
42
43//
44// Default constructor for event
45//
46
47Event::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
64Event::Event(EVENT_TEMPLATE *pTemplate, DWORD dwSourceId, char *szFormat, va_list args)
65{
66 m_tTimeStamp = time(NULL);
67 m_dwId = pTemplate->dwId;
f9b7e653
VK
68 m_dwSeverity = pTemplate->dwSeverity;
69 m_dwFlags = pTemplate->dwFlags;
be0a5a53 70 m_dwSource = dwSourceId;
f9b7e653
VK
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);
f00307b7 101 sprintf(m_pszParameters[i], "BAD FORMAT \"%c\" [value = 0x%08X]", szFormat[i], va_arg(args, DWORD));
f9b7e653
VK
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
121Event::~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
141void 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
62f5857f
VK
250//
251// Fill NXC_EVENT structure with event data
252//
253
254void 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
f9b7e653
VK
264//
265// Inilialize event handling subsystem
266//
267
268BOOL InitEventSubsystem(void)
269{
270 DB_RESULT hResult;
271 DWORD i;
c7ca9142 272 BOOL bSuccess = FALSE;
f9b7e653
VK
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");
c7ca9142 279 if (hResult != NULL)
f9b7e653 280 {
c7ca9142
VK
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);
f9b7e653 293
c7ca9142
VK
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
f9b7e653 302 {
c7ca9142 303 WriteLog(MSG_EVENT_LOAD_ERROR, EVENTLOG_ERROR_TYPE, NULL);
f9b7e653
VK
304 }
305
c7ca9142 306 return bSuccess;
f9b7e653
VK
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
315static 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
356BOOL 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}