fixed linux build errors
[public/netxms.git] / src / server / core / condition.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
22aa5156 3** Copyright (C) 2003-2011 Victor Kirhenshtein
5039dede
AK
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: container.cpp
20**
21**/
22
23#include "nxcore.h"
24
21c9acce
VK
25/**
26 * Default constructor
27 */
28Condition::Condition() : NetObj()
5039dede
AK
29{
30 m_pszScript = NULL;
31 m_pDCIList = NULL;
32 m_dwDCICount = 0;
33 m_pszScript = 0;
34 m_dwSourceObject = 0;
35 m_nActiveStatus = STATUS_MAJOR;
36 m_nInactiveStatus = STATUS_NORMAL;
37 m_pCompiledScript = NULL;
38 m_bIsActive = FALSE;
39 m_tmLastPoll = 0;
40 m_bQueuedForPolling = FALSE;
41 m_dwActivationEventCode = EVENT_CONDITION_ACTIVATED;
42 m_dwDeactivationEventCode = EVENT_CONDITION_DEACTIVATED;
43}
44
21c9acce
VK
45/**
46 * Constructor for new objects
47 */
48Condition::Condition(BOOL bHidden) : NetObj()
5039dede
AK
49{
50 m_pszScript = NULL;
51 m_pDCIList = NULL;
52 m_dwDCICount = 0;
53 m_pszScript = 0;
54 m_dwSourceObject = 0;
55 m_nActiveStatus = STATUS_MAJOR;
56 m_nInactiveStatus = STATUS_NORMAL;
57 m_bIsHidden = bHidden;
58 m_pCompiledScript = NULL;
59 m_bIsActive = FALSE;
60 m_tmLastPoll = 0;
61 m_bQueuedForPolling = FALSE;
62 m_dwActivationEventCode = EVENT_CONDITION_ACTIVATED;
63 m_dwDeactivationEventCode = EVENT_CONDITION_DEACTIVATED;
64}
65
66
67//
68// Destructor
69//
70
71Condition::~Condition()
72{
73 safe_free(m_pDCIList);
74 safe_free(m_pszScript);
75 delete m_pCompiledScript;
76}
77
78
79//
80// Load object from database
81//
82
83BOOL Condition::CreateFromDB(DWORD dwId)
84{
85 TCHAR szQuery[512];
86 DB_RESULT hResult;
87 DWORD i;
88
89 m_dwId = dwId;
90
89135050 91 if (!loadCommonProperties())
5039dede
AK
92 return FALSE;
93
94 // Load properties
95 _sntprintf(szQuery, 512, _T("SELECT activation_event,deactivation_event,")
96 _T("source_object,active_status,inactive_status,")
97 _T("script FROM conditions WHERE id=%d"), dwId);
98 hResult = DBSelect(g_hCoreDB, szQuery);
99 if (hResult == NULL)
100 return FALSE; // Query failed
101
102 if (DBGetNumRows(hResult) == 0)
103 {
104 // No object with given ID in database
105 DBFreeResult(hResult);
106 return FALSE;
107 }
108
109 m_dwActivationEventCode = DBGetFieldULong(hResult, 0, 0);
110 m_dwDeactivationEventCode = DBGetFieldULong(hResult, 0, 1);
111 m_dwSourceObject = DBGetFieldULong(hResult, 0, 2);
112 m_nActiveStatus = DBGetFieldLong(hResult, 0, 3);
113 m_nInactiveStatus = DBGetFieldLong(hResult, 0, 4);
114 m_pszScript = DBGetField(hResult, 0, 5, NULL, 0);
115 DecodeSQLString(m_pszScript);
116
117 DBFreeResult(hResult);
118
119 // Compile script
120 m_pCompiledScript = (NXSL_Program *)NXSLCompile(m_pszScript, szQuery, 512);
121 if (m_pCompiledScript == NULL)
122 nxlog_write(MSG_COND_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE,
123 "dss", m_dwId, m_szName, szQuery);
124
125 // Load DCI map
126 _sntprintf(szQuery, 512, _T("SELECT dci_id,node_id,dci_func,num_polls ")
127 _T("FROM cond_dci_map WHERE condition_id=%d ORDER BY sequence_number"), dwId);
128 hResult = DBSelect(g_hCoreDB, szQuery);
129 if (hResult == NULL)
130 return FALSE; // Query failed
131
132 m_dwDCICount = DBGetNumRows(hResult);
133 if (m_dwDCICount > 0)
134 {
135 m_pDCIList = (INPUT_DCI *)malloc(sizeof(INPUT_DCI) * m_dwDCICount);
136 for(i = 0; i < m_dwDCICount; i++)
137 {
138 m_pDCIList[i].dwId = DBGetFieldULong(hResult, i, 0);
139 m_pDCIList[i].dwNodeId = DBGetFieldULong(hResult, i, 1);
140 m_pDCIList[i].nFunction = DBGetFieldLong(hResult, i, 2);
141 m_pDCIList[i].nPolls = DBGetFieldLong(hResult, i, 3);
142 }
143 }
144 DBFreeResult(hResult);
145
89135050 146 return loadACLFromDB();
5039dede
AK
147}
148
149
150//
151// Save object to database
152//
153
154BOOL Condition::SaveToDB(DB_HANDLE hdb)
155{
156 TCHAR *pszEscScript, *pszQuery;
157 DB_RESULT hResult;
158 BOOL bNewObject = TRUE;
159 DWORD i;
160
161 LockData();
162
89135050 163 saveCommonProperties(hdb);
5039dede
AK
164
165 pszEscScript = EncodeSQLString(CHECK_NULL_EX(m_pszScript));
35f836fe
VK
166 size_t qlen = _tcslen(pszEscScript) + 1024;
167 pszQuery = (TCHAR *)malloc(sizeof(TCHAR) * qlen);
5039dede
AK
168
169 // Check for object's existence in database
35f836fe 170 _sntprintf(pszQuery, qlen, _T("SELECT id FROM conditions WHERE id=%d"), m_dwId);
5039dede
AK
171 hResult = DBSelect(hdb, pszQuery);
172 if (hResult != NULL)
173 {
174 if (DBGetNumRows(hResult) > 0)
175 bNewObject = FALSE;
176 DBFreeResult(hResult);
177 }
178
179 // Form and execute INSERT or UPDATE query
180 if (bNewObject)
181 {
35f836fe
VK
182 _sntprintf(pszQuery, qlen,
183 _T("INSERT INTO conditions (id,activation_event,")
5039dede
AK
184 _T("deactivation_event,source_object,active_status,")
185 _T("inactive_status,script) VALUES (%d,%d,%d,%d,%d,%d,'%s')"),
186 m_dwId, m_dwActivationEventCode, m_dwDeactivationEventCode,
187 m_dwSourceObject, m_nActiveStatus, m_nInactiveStatus, pszEscScript);
188 }
189 else
190 {
35f836fe
VK
191 _sntprintf(pszQuery, qlen,
192 _T("UPDATE conditions SET activation_event=%d,")
5039dede
AK
193 _T("deactivation_event=%d,source_object=%d,active_status=%d,")
194 _T("inactive_status=%d,script='%s' WHERE id=%d"),
195 m_dwActivationEventCode, m_dwDeactivationEventCode, m_dwSourceObject,
196 m_nActiveStatus, m_nInactiveStatus, pszEscScript, m_dwId);
197 }
198 free(pszEscScript);
199 DBQuery(hdb, pszQuery);
200
201 // Save DCI mapping
35f836fe 202 _sntprintf(pszQuery, qlen, _T("DELETE FROM cond_dci_map WHERE condition_id=%d"), m_dwId);
5039dede
AK
203 DBQuery(hdb, pszQuery);
204 for(i = 0; i < m_dwDCICount; i++)
205 {
35f836fe
VK
206 _sntprintf(pszQuery, qlen, _T("INSERT INTO cond_dci_map (condition_id,sequence_number,dci_id,node_id,")
207 _T("dci_func,num_polls) VALUES (%d,%d,%d,%d,%d,%d)"),
5039dede
AK
208 m_dwId, i, m_pDCIList[i].dwId, m_pDCIList[i].dwNodeId,
209 m_pDCIList[i].nFunction, m_pDCIList[i].nPolls);
210 DBQuery(hdb, pszQuery);
211 }
212 free(pszQuery);
213
214 // Save access list
89135050 215 saveACLToDB(hdb);
5039dede
AK
216
217 // Unlock object and clear modification flag
218 m_bIsModified = FALSE;
219 UnlockData();
220 return TRUE;
221}
222
223
224//
225// Delete object from database
226//
227
22aa5156 228BOOL Condition::DeleteFromDB()
5039dede
AK
229{
230 TCHAR szQuery[128];
231 BOOL bSuccess;
232
233 bSuccess = NetObj::DeleteFromDB();
234 if (bSuccess)
235 {
236 _sntprintf(szQuery, 128, _T("DELETE FROM conditions WHERE id=%d"), m_dwId);
237 QueueSQLRequest(szQuery);
238 _sntprintf(szQuery, 128, _T("DELETE FROM cond_dci_map WHERE condition_id=%d"), m_dwId);
239 QueueSQLRequest(szQuery);
240 }
241 return bSuccess;
242}
243
244
245//
246// Create NXCP message from object
247//
248
249void Condition::CreateMessage(CSCPMessage *pMsg)
250{
251 DWORD i, dwId;
252
253 NetObj::CreateMessage(pMsg);
254 pMsg->SetVariable(VID_SCRIPT, CHECK_NULL_EX(m_pszScript));
255 pMsg->SetVariable(VID_ACTIVATION_EVENT, m_dwActivationEventCode);
256 pMsg->SetVariable(VID_DEACTIVATION_EVENT, m_dwDeactivationEventCode);
257 pMsg->SetVariable(VID_SOURCE_OBJECT, m_dwSourceObject);
258 pMsg->SetVariable(VID_ACTIVE_STATUS, (WORD)m_nActiveStatus);
259 pMsg->SetVariable(VID_INACTIVE_STATUS, (WORD)m_nInactiveStatus);
260 pMsg->SetVariable(VID_NUM_ITEMS, m_dwDCICount);
261 for(i = 0, dwId = VID_DCI_LIST_BASE; (i < m_dwDCICount) && (dwId < (VID_DCI_LIST_LAST + 1)); i++)
262 {
263 pMsg->SetVariable(dwId++, m_pDCIList[i].dwId);
264 pMsg->SetVariable(dwId++, m_pDCIList[i].dwNodeId);
265 pMsg->SetVariable(dwId++, (WORD)m_pDCIList[i].nFunction);
266 pMsg->SetVariable(dwId++, (WORD)m_pDCIList[i].nPolls);
267 dwId += 6;
268 }
269}
270
271
272//
273// Modify object from NXCP message
274//
275
276DWORD Condition::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
277{
278 DWORD i, dwId;
279 NetObj *pObject;
5039dede
AK
280
281 if (!bAlreadyLocked)
282 LockData();
283
284 // Change script
285 if (pRequest->IsVariableExist(VID_SCRIPT))
286 {
287 TCHAR szError[1024];
288
289 safe_free(m_pszScript);
290 delete m_pCompiledScript;
291 m_pszScript = pRequest->GetVariableStr(VID_SCRIPT);
292 m_pCompiledScript = (NXSL_Program *)NXSLCompile(m_pszScript, szError, 1024);
293 if (m_pCompiledScript == NULL)
294 nxlog_write(MSG_COND_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE,
295 "dss", m_dwId, m_szName, szError);
296 }
297
298 // Change activation event
299 if (pRequest->IsVariableExist(VID_ACTIVATION_EVENT))
300 m_dwActivationEventCode = pRequest->GetVariableLong(VID_ACTIVATION_EVENT);
301
302 // Change deactivation event
303 if (pRequest->IsVariableExist(VID_DEACTIVATION_EVENT))
304 m_dwDeactivationEventCode = pRequest->GetVariableLong(VID_DEACTIVATION_EVENT);
305
306 // Change source object
307 if (pRequest->IsVariableExist(VID_SOURCE_OBJECT))
308 m_dwSourceObject = pRequest->GetVariableLong(VID_SOURCE_OBJECT);
309
310 // Change active status
311 if (pRequest->IsVariableExist(VID_ACTIVE_STATUS))
312 m_nActiveStatus = pRequest->GetVariableShort(VID_ACTIVE_STATUS);
313
314 // Change inactive status
315 if (pRequest->IsVariableExist(VID_INACTIVE_STATUS))
316 m_nInactiveStatus = pRequest->GetVariableShort(VID_INACTIVE_STATUS);
317
318 // Change DCI list
319 if (pRequest->IsVariableExist(VID_NUM_ITEMS))
320 {
321 safe_free(m_pDCIList);
322 m_dwDCICount = pRequest->GetVariableLong(VID_NUM_ITEMS);
323 if (m_dwDCICount > 0)
324 {
325 m_pDCIList = (INPUT_DCI *)malloc(sizeof(INPUT_DCI) * m_dwDCICount);
326 for(i = 0, dwId = VID_DCI_LIST_BASE; (i < m_dwDCICount) && (dwId < (VID_DCI_LIST_LAST + 1)); i++)
327 {
328 m_pDCIList[i].dwId = pRequest->GetVariableLong(dwId++);
329 m_pDCIList[i].dwNodeId = pRequest->GetVariableLong(dwId++);
330 m_pDCIList[i].nFunction = pRequest->GetVariableShort(dwId++);
331 m_pDCIList[i].nPolls = pRequest->GetVariableShort(dwId++);
332 dwId += 6;
333 }
334
335 // Update cache size of DCIs
336 for(i = 0; i < m_dwDCICount; i++)
337 {
338 pObject = FindObjectById(m_pDCIList[i].dwNodeId);
339 if (pObject != NULL)
340 {
341 if (pObject->Type() == OBJECT_NODE)
342 {
16d6f798
VK
343 DCObject *pItem = ((Node *)pObject)->getDCObjectById(m_pDCIList[i].dwId);
344 if ((pItem != NULL) && (pItem->getType() == DCO_TYPE_ITEM))
5039dede 345 {
16d6f798 346 ((DCItem *)pItem)->updateCacheSize(m_dwId);
5039dede
AK
347 }
348 }
349 }
350 }
351 }
352 else
353 {
354 m_pDCIList = NULL;
355 }
356 }
357
358 return NetObj::ModifyFromMessage(pRequest, TRUE);
359}
360
21c9acce
VK
361/**
362 * Lock for polling
363 */
d5e8ff90 364void Condition::LockForPoll()
5039dede 365{
21c9acce 366 incRefCount();
5039dede
AK
367 m_bQueuedForPolling = TRUE;
368}
369
21c9acce
VK
370/**
371 * This method should be called by poller thread when poll finish
372 */
d5e8ff90 373void Condition::EndPoll()
5039dede
AK
374{
375 LockData();
376 m_bQueuedForPolling = FALSE;
377 m_tmLastPoll = time(NULL);
378 UnlockData();
21c9acce 379 decRefCount();
5039dede
AK
380}
381
21c9acce
VK
382/**
383 * Check condition
384 */
3f7c0fe4 385void Condition::check()
5039dede
AK
386{
387 NXSL_ServerEnv *pEnv;
388 NXSL_Value **ppValueList, *pValue;
389 NetObj *pObject;
5039dede
AK
390 DWORD i, dwNumValues;
391 int iOldStatus = m_iStatus;
392
393 if ((m_pCompiledScript == NULL) || (m_iStatus == STATUS_UNMANAGED))
394 return;
395
396 pEnv = new NXSL_ServerEnv;
397
398 LockData();
399 ppValueList = (NXSL_Value **)malloc(sizeof(NXSL_Value *) * m_dwDCICount);
400 memset(ppValueList, 0, sizeof(NXSL_Value *) * m_dwDCICount);
401 for(i = 0; i < m_dwDCICount; i++)
402 {
403 pObject = FindObjectById(m_pDCIList[i].dwNodeId);
404 if (pObject != NULL)
405 {
406 if (pObject->Type() == OBJECT_NODE)
407 {
16d6f798
VK
408 DCObject *pItem = ((Node *)pObject)->getDCObjectById(m_pDCIList[i].dwId);
409 if ((pItem != NULL) && (pItem->getType() == DCO_TYPE_ITEM))
5039dede 410 {
16d6f798 411 ppValueList[i] = ((DCItem *)pItem)->getValueForNXSL(m_pDCIList[i].nFunction, m_pDCIList[i].nPolls);
5039dede
AK
412 }
413 }
414 }
415 if (ppValueList[i] == NULL)
416 ppValueList[i] = new NXSL_Value;
417 }
418 dwNumValues = m_dwDCICount;
419 UnlockData();
420
22aa5156
VK
421 // Create array from values
422 NXSL_Array *array = new NXSL_Array;
423 for(i = 0; i < dwNumValues; i++)
424 {
425 array->set(i + 1, new NXSL_Value(ppValueList[i]));
426 }
427 m_pCompiledScript->setGlobalVariable(_T("$values"), new NXSL_Value(array));
428
5039dede
AK
429 DbgPrintf(6, _T("Running evaluation script for condition %d \"%s\""),
430 m_dwId, m_szName);
bb5365ed 431 if (m_pCompiledScript->run(pEnv, dwNumValues, ppValueList) == 0)
5039dede 432 {
bb5365ed
VK
433 pValue = m_pCompiledScript->getResult();
434 if (pValue->getValueAsInt32() == 0)
5039dede
AK
435 {
436 if (m_bIsActive)
437 {
438 // Deactivate condition
439 LockData();
440 m_iStatus = m_nInactiveStatus;
441 m_bIsActive = FALSE;
442 Modify();
443 UnlockData();
444
445 PostEvent(m_dwDeactivationEventCode,
446 (m_dwSourceObject == 0) ? g_dwMgmtNode : m_dwSourceObject,
447 "dsdd", m_dwId, m_szName, iOldStatus, m_iStatus);
448
449 DbgPrintf(6, _T("Condition %d \"%s\" deactivated"),
450 m_dwId, m_szName);
451 }
452 else
453 {
454 DbgPrintf(6, _T("Condition %d \"%s\" still inactive"),
455 m_dwId, m_szName);
456 LockData();
457 if (m_iStatus != m_nInactiveStatus)
458 {
459 m_iStatus = m_nInactiveStatus;
460 Modify();
461 }
462 UnlockData();
463 }
464 }
465 else
466 {
467 if (!m_bIsActive)
468 {
469 // Activate condition
470 LockData();
471 m_iStatus = m_nActiveStatus;
472 m_bIsActive = TRUE;
473 Modify();
474 UnlockData();
475
476 PostEvent(m_dwActivationEventCode,
477 (m_dwSourceObject == 0) ? g_dwMgmtNode : m_dwSourceObject,
478 "dsdd", m_dwId, m_szName, iOldStatus, m_iStatus);
479
480 DbgPrintf(6, _T("Condition %d \"%s\" activated"),
481 m_dwId, m_szName);
482 }
483 else
484 {
485 DbgPrintf(6, _T("Condition %d \"%s\" still active"),
486 m_dwId, m_szName);
487 LockData();
488 if (m_iStatus != m_nActiveStatus)
489 {
490 m_iStatus = m_nActiveStatus;
491 Modify();
492 }
493 UnlockData();
494 }
495 }
496 }
497 else
498 {
499 nxlog_write(MSG_COND_SCRIPT_EXECUTION_ERROR, EVENTLOG_ERROR_TYPE,
bb5365ed 500 "dss", m_dwId, m_szName, m_pCompiledScript->getErrorText());
5039dede
AK
501
502 LockData();
503 if (m_iStatus != STATUS_UNKNOWN)
504 {
505 m_iStatus = STATUS_UNKNOWN;
506 Modify();
507 }
508 UnlockData();
509 }
510 free(ppValueList);
511
512 // Cause parent object(s) to recalculate it's status
513 if (iOldStatus != m_iStatus)
514 {
515 LockParentList(FALSE);
516 for(i = 0; i < m_dwParentCount; i++)
27f9598d 517 m_pParentList[i]->calculateCompoundStatus();
5039dede
AK
518 UnlockParentList();
519 }
520}
521
522
523//
524// Determine DCI cache size required by condition object
525//
526
3f7c0fe4 527int Condition::getCacheSizeForDCI(DWORD dwItemId, BOOL bNoLock)
5039dede
AK
528{
529 DWORD i;
530 int nSize = 0;
531
532 if (!bNoLock)
533 LockData();
534 for(i = 0; i < m_dwDCICount; i++)
535 {
536 if (m_pDCIList[i].dwId == dwItemId)
537 {
538 switch(m_pDCIList[i].nFunction)
539 {
540 case F_LAST:
541 nSize = 1;
542 break;
543 case F_DIFF:
544 nSize = 2;
545 break;
546 default:
547 nSize = m_pDCIList[i].nPolls;
548 break;
549 }
550 break;
551 }
552 }
553 if (!bNoLock)
554 UnlockData();
555 return nSize;
556}