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