ICMP ping timeout made configurable; code refactoring
[public/netxms.git] / src / server / core / netobj.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2013 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: netobj.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Default constructor
27 */
28 NetObj::NetObj()
29 {
30 int i;
31
32 m_dwRefCount = 0;
33 m_mutexData = MutexCreate();
34 m_mutexRefCount = MutexCreate();
35 m_mutexACL = MutexCreate();
36 m_rwlockParentList = RWLockCreate();
37 m_rwlockChildList = RWLockCreate();
38 m_iStatus = STATUS_UNKNOWN;
39 m_szName[0] = 0;
40 m_pszComments = NULL;
41 m_isModified = false;
42 m_isDeleted = false;
43 m_isHidden = false;
44 m_isSystem = false;
45 m_dwIpAddr = 0;
46 m_dwChildCount = 0;
47 m_pChildList = NULL;
48 m_dwParentCount = 0;
49 m_pParentList = NULL;
50 m_pAccessList = new AccessList;
51 m_bInheritAccessRights = TRUE;
52 m_dwNumTrustedNodes = 0;
53 m_pdwTrustedNodes = NULL;
54 m_pollRequestor = NULL;
55 m_iStatusCalcAlg = SA_CALCULATE_DEFAULT;
56 m_iStatusPropAlg = SA_PROPAGATE_DEFAULT;
57 m_iFixedStatus = STATUS_WARNING;
58 m_iStatusShift = 0;
59 m_iStatusSingleThreshold = 75;
60 m_dwTimeStamp = 0;
61 for(i = 0; i < 4; i++)
62 {
63 m_iStatusTranslation[i] = i + 1;
64 m_iStatusThresholds[i] = 80 - i * 20;
65 }
66 uuid_clear(m_image);
67 m_submapId = 0;
68 }
69
70 /**
71 * Destructor
72 */
73 NetObj::~NetObj()
74 {
75 MutexDestroy(m_mutexData);
76 MutexDestroy(m_mutexRefCount);
77 MutexDestroy(m_mutexACL);
78 RWLockDestroy(m_rwlockParentList);
79 RWLockDestroy(m_rwlockChildList);
80 safe_free(m_pChildList);
81 safe_free(m_pParentList);
82 delete m_pAccessList;
83 safe_free(m_pdwTrustedNodes);
84 safe_free(m_pszComments);
85 }
86
87 /**
88 * Create object from database data
89 */
90 BOOL NetObj::CreateFromDB(UINT32 dwId)
91 {
92 return FALSE; // Abstract objects cannot be loaded from database
93 }
94
95 /**
96 * Save object to database
97 */
98 BOOL NetObj::SaveToDB(DB_HANDLE hdb)
99 {
100 return FALSE; // Abstract objects cannot be saved to database
101 }
102
103 /**
104 * Delete object from database
105 */
106 bool NetObj::deleteFromDB(DB_HANDLE hdb)
107 {
108 // Delete ACL
109 bool success = executeQueryOnObject(hdb, _T("DELETE FROM acl WHERE object_id=?"));
110 if (success)
111 success = executeQueryOnObject(hdb, _T("DELETE FROM object_properties WHERE object_id=?"));
112 if (success)
113 success = executeQueryOnObject(hdb, _T("DELETE FROM object_custom_attributes WHERE object_id=?"));
114
115 // Delete events
116 if (success && ConfigReadInt(_T("DeleteEventsOfDeletedObject"), 1))
117 {
118 success = executeQueryOnObject(hdb, _T("DELETE FROM event_log WHERE event_source=?"));
119 }
120
121 // Delete alarms
122 if (success && ConfigReadInt(_T("DeleteAlarmsOfDeletedObject"), 1))
123 {
124 success = g_alarmMgr.deleteObjectAlarms(m_dwId, hdb);
125 }
126
127 return success;
128 }
129
130 /**
131 * Prepare and execute SQL query with single binding - object ID.
132 */
133 bool NetObj::executeQueryOnObject(DB_HANDLE hdb, const TCHAR *query)
134 {
135 DB_STATEMENT hStmt = DBPrepare(hdb, query);
136 if (hStmt == NULL)
137 return false;
138 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_dwId);
139 bool success = DBExecute(hStmt) ? true : false;
140 DBFreeStatement(hStmt);
141 return success;
142 }
143
144 /**
145 * Load common object properties from database
146 */
147 BOOL NetObj::loadCommonProperties()
148 {
149 BOOL bResult = FALSE;
150
151 // Load access options
152 DB_STATEMENT hStmt = DBPrepare(g_hCoreDB,
153 _T("SELECT name,status,is_deleted,")
154 _T("inherit_access_rights,last_modified,status_calc_alg,")
155 _T("status_prop_alg,status_fixed_val,status_shift,")
156 _T("status_translation,status_single_threshold,")
157 _T("status_thresholds,comments,is_system,")
158 _T("location_type,latitude,longitude,location_accuracy,")
159 _T("location_timestamp,guid,image,submap_id FROM object_properties ")
160 _T("WHERE object_id=?"));
161 if (hStmt != NULL)
162 {
163 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_dwId);
164 DB_RESULT hResult = DBSelectPrepared(hStmt);
165 if (hResult != NULL)
166 {
167 if (DBGetNumRows(hResult) > 0)
168 {
169 DBGetField(hResult, 0, 0, m_szName, MAX_OBJECT_NAME);
170 m_iStatus = DBGetFieldLong(hResult, 0, 1);
171 m_isDeleted = DBGetFieldLong(hResult, 0, 2) ? TRUE : FALSE;
172 m_bInheritAccessRights = DBGetFieldLong(hResult, 0, 3) ? TRUE : FALSE;
173 m_dwTimeStamp = DBGetFieldULong(hResult, 0, 4);
174 m_iStatusCalcAlg = DBGetFieldLong(hResult, 0, 5);
175 m_iStatusPropAlg = DBGetFieldLong(hResult, 0, 6);
176 m_iFixedStatus = DBGetFieldLong(hResult, 0, 7);
177 m_iStatusShift = DBGetFieldLong(hResult, 0, 8);
178 DBGetFieldByteArray(hResult, 0, 9, m_iStatusTranslation, 4, STATUS_WARNING);
179 m_iStatusSingleThreshold = DBGetFieldLong(hResult, 0, 10);
180 DBGetFieldByteArray(hResult, 0, 11, m_iStatusThresholds, 4, 50);
181 safe_free(m_pszComments);
182 m_pszComments = DBGetField(hResult, 0, 12, NULL, 0);
183 m_isSystem = DBGetFieldLong(hResult, 0, 13) ? true : false;
184
185 int locType = DBGetFieldLong(hResult, 0, 14);
186 if (locType != GL_UNSET)
187 {
188 TCHAR lat[32], lon[32];
189
190 DBGetField(hResult, 0, 15, lat, 32);
191 DBGetField(hResult, 0, 16, lon, 32);
192 m_geoLocation = GeoLocation(locType, lat, lon, DBGetFieldLong(hResult, 0, 17), DBGetFieldULong(hResult, 0, 18));
193 }
194 else
195 {
196 m_geoLocation = GeoLocation();
197 }
198
199 DBGetFieldGUID(hResult, 0, 19, m_guid);
200 DBGetFieldGUID(hResult, 0, 20, m_image);
201 m_submapId = DBGetFieldULong(hResult, 0, 21);
202
203 bResult = TRUE;
204 }
205 DBFreeResult(hResult);
206 }
207 DBFreeStatement(hStmt);
208 }
209
210 // Load custom attributes
211 if (bResult)
212 {
213 hStmt = DBPrepare(g_hCoreDB, _T("SELECT attr_name,attr_value FROM object_custom_attributes WHERE object_id=?"));
214 if (hStmt != NULL)
215 {
216 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_dwId);
217 DB_RESULT hResult = DBSelectPrepared(hStmt);
218 if (hResult != NULL)
219 {
220 int i, count;
221 TCHAR *name, *value;
222
223 count = DBGetNumRows(hResult);
224 for(i = 0; i < count; i++)
225 {
226 name = DBGetField(hResult, i, 0, NULL, 0);
227 if (name != NULL)
228 {
229 value = DBGetField(hResult, i, 1, NULL, 0);
230 if (value != NULL)
231 {
232 m_customAttributes.setPreallocated(name, value);
233 }
234 }
235 }
236 DBFreeResult(hResult);
237 }
238 else
239 {
240 bResult = FALSE;
241 }
242 DBFreeStatement(hStmt);
243 }
244 else
245 {
246 bResult = FALSE;
247 }
248 }
249
250 if (bResult)
251 bResult = loadTrustedNodes();
252
253 if (!bResult)
254 DbgPrintf(4, _T("NetObj::loadCommonProperties() failed for object %s [%ld] class=%d"), m_szName, (long)m_dwId, Type());
255
256 return bResult;
257 }
258
259 /**
260 * Save common object properties to database
261 */
262 BOOL NetObj::saveCommonProperties(DB_HANDLE hdb)
263 {
264 DB_STATEMENT hStmt;
265 if (IsDatabaseRecordExist(hdb, _T("object_properties"), _T("object_id"), m_dwId))
266 {
267 hStmt = DBPrepare(hdb,
268 _T("UPDATE object_properties SET name=?,status=?,")
269 _T("is_deleted=?,inherit_access_rights=?,")
270 _T("last_modified=?,status_calc_alg=?,status_prop_alg=?,")
271 _T("status_fixed_val=?,status_shift=?,status_translation=?,")
272 _T("status_single_threshold=?,status_thresholds=?,")
273 _T("comments=?,is_system=?,location_type=?,latitude=?,")
274 _T("longitude=?,location_accuracy=?,location_timestamp=?,")
275 _T("guid=?,image=?,submap_id=? WHERE object_id=?"));
276 }
277 else
278 {
279 hStmt = DBPrepare(hdb,
280 _T("INSERT INTO object_properties (name,status,is_deleted,")
281 _T("inherit_access_rights,last_modified,status_calc_alg,")
282 _T("status_prop_alg,status_fixed_val,status_shift,status_translation,")
283 _T("status_single_threshold,status_thresholds,comments,is_system,")
284 _T("location_type,latitude,longitude,location_accuracy,location_timestamp,")
285 _T("guid,image,submap_id,object_id) ")
286 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
287 }
288 if (hStmt == NULL)
289 return FALSE;
290
291 TCHAR szTranslation[16], szThresholds[16], lat[32], lon[32], guid[64], image[64];
292 for(int i = 0, j = 0; i < 4; i++, j += 2)
293 {
294 _sntprintf(&szTranslation[j], 16 - j, _T("%02X"), (BYTE)m_iStatusTranslation[i]);
295 _sntprintf(&szThresholds[j], 16 - j, _T("%02X"), (BYTE)m_iStatusThresholds[i]);
296 }
297 _sntprintf(lat, 32, _T("%f"), m_geoLocation.getLatitude());
298 _sntprintf(lon, 32, _T("%f"), m_geoLocation.getLongitude());
299
300 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, m_szName, DB_BIND_STATIC);
301 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (LONG)m_iStatus);
302 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)(m_isDeleted ? 1 : 0));
303 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (LONG)m_bInheritAccessRights);
304 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_dwTimeStamp);
305 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, (LONG)m_iStatusCalcAlg);
306 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (LONG)m_iStatusPropAlg);
307 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (LONG)m_iFixedStatus);
308 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (LONG)m_iStatusShift);
309 DBBind(hStmt, 10, DB_SQLTYPE_VARCHAR, szTranslation, DB_BIND_STATIC);
310 DBBind(hStmt, 11, DB_SQLTYPE_INTEGER, (LONG)m_iStatusSingleThreshold);
311 DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, szThresholds, DB_BIND_STATIC);
312 DBBind(hStmt, 13, DB_SQLTYPE_VARCHAR, m_pszComments, DB_BIND_STATIC);
313 DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, (LONG)(m_isSystem ? 1 : 0));
314 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, (LONG)m_geoLocation.getType());
315 DBBind(hStmt, 16, DB_SQLTYPE_VARCHAR, lat, DB_BIND_STATIC);
316 DBBind(hStmt, 17, DB_SQLTYPE_VARCHAR, lon, DB_BIND_STATIC);
317 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, (LONG)m_geoLocation.getAccuracy());
318 DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, (UINT32)m_geoLocation.getTimestamp());
319 DBBind(hStmt, 20, DB_SQLTYPE_VARCHAR, uuid_to_string(m_guid, guid), DB_BIND_STATIC);
320 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, uuid_to_string(m_image, image), DB_BIND_STATIC);
321 DBBind(hStmt, 22, DB_SQLTYPE_INTEGER, m_submapId);
322 DBBind(hStmt, 23, DB_SQLTYPE_INTEGER, m_dwId);
323
324 BOOL bResult = DBExecute(hStmt);
325 DBFreeStatement(hStmt);
326
327 // Save custom attributes
328 if (bResult)
329 {
330 TCHAR szQuery[512];
331 _sntprintf(szQuery, 512, _T("DELETE FROM object_custom_attributes WHERE object_id=%d"), m_dwId);
332 bResult = DBQuery(hdb, szQuery);
333 if (bResult)
334 {
335 hStmt = DBPrepare(hdb, _T("INSERT INTO object_custom_attributes (object_id,attr_name,attr_value) VALUES (?,?,?)"));
336 if (hStmt != NULL)
337 {
338 for(UINT32 i = 0; i < m_customAttributes.getSize(); i++)
339 {
340 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_dwId);
341 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, m_customAttributes.getKeyByIndex(i), DB_BIND_STATIC);
342 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, m_customAttributes.getValueByIndex(i), DB_BIND_STATIC);
343 bResult = DBExecute(hStmt);
344 if (!bResult)
345 break;
346 }
347 DBFreeStatement(hStmt);
348 }
349 else
350 {
351 bResult = FALSE;
352 }
353 }
354 }
355
356 if (bResult)
357 bResult = saveTrustedNodes(hdb);
358
359 return bResult;
360 }
361
362 /**
363 * Add reference to the new child object
364 */
365 void NetObj::AddChild(NetObj *pObject)
366 {
367 UINT32 i;
368
369 LockChildList(TRUE);
370 for(i = 0; i < m_dwChildCount; i++)
371 if (m_pChildList[i] == pObject)
372 {
373 UnlockChildList();
374 return; // Already in the child list
375 }
376 m_pChildList = (NetObj **)realloc(m_pChildList, sizeof(NetObj *) * (m_dwChildCount + 1));
377 m_pChildList[m_dwChildCount++] = pObject;
378 UnlockChildList();
379 incRefCount();
380 Modify();
381 }
382
383 /**
384 * Add reference to parent object
385 */
386 void NetObj::AddParent(NetObj *pObject)
387 {
388 UINT32 i;
389
390 LockParentList(TRUE);
391 for(i = 0; i < m_dwParentCount; i++)
392 if (m_pParentList[i] == pObject)
393 {
394 UnlockParentList();
395 return; // Already in the parents list
396 }
397 m_pParentList = (NetObj **)realloc(m_pParentList, sizeof(NetObj *) * (m_dwParentCount + 1));
398 m_pParentList[m_dwParentCount++] = pObject;
399 UnlockParentList();
400 incRefCount();
401 Modify();
402 }
403
404 /**
405 * Delete reference to child object
406 */
407 void NetObj::DeleteChild(NetObj *pObject)
408 {
409 UINT32 i;
410
411 LockChildList(TRUE);
412 for(i = 0; i < m_dwChildCount; i++)
413 if (m_pChildList[i] == pObject)
414 break;
415
416 if (i == m_dwChildCount) // No such object
417 {
418 UnlockChildList();
419 return;
420 }
421 m_dwChildCount--;
422 if (m_dwChildCount > 0)
423 {
424 memmove(&m_pChildList[i], &m_pChildList[i + 1], sizeof(NetObj *) * (m_dwChildCount - i));
425 m_pChildList = (NetObj **)realloc(m_pChildList, sizeof(NetObj *) * m_dwChildCount);
426 }
427 else
428 {
429 free(m_pChildList);
430 m_pChildList = NULL;
431 }
432 UnlockChildList();
433 decRefCount();
434 Modify();
435 }
436
437 /**
438 * Delete reference to parent object
439 */
440 void NetObj::DeleteParent(NetObj *pObject)
441 {
442 UINT32 i;
443
444 LockParentList(TRUE);
445 for(i = 0; i < m_dwParentCount; i++)
446 if (m_pParentList[i] == pObject)
447 break;
448 if (i == m_dwParentCount) // No such object
449 {
450 UnlockParentList();
451 return;
452 }
453 m_dwParentCount--;
454 if (m_dwParentCount > 0)
455 {
456 memmove(&m_pParentList[i], &m_pParentList[i + 1], sizeof(NetObj *) * (m_dwParentCount - i));
457 m_pParentList = (NetObj **)realloc(m_pParentList, sizeof(NetObj *) * m_dwParentCount);
458 }
459 else
460 {
461 free(m_pParentList);
462 m_pParentList = NULL;
463 }
464 UnlockParentList();
465 decRefCount();
466 Modify();
467 }
468
469 /**
470 * Walker callback to call OnObjectDelete for each active object
471 */
472 void NetObj::onObjectDeleteCallback(NetObj *object, void *data)
473 {
474 UINT32 currId = ((NetObj *)data)->Id();
475 if ((object->Id() != currId) && !object->isDeleted())
476 object->onObjectDelete(currId);
477 }
478
479 /**
480 * Prepare object for deletion - remove all references, etc.
481 */
482 void NetObj::deleteObject()
483 {
484 UINT32 i;
485
486 DbgPrintf(4, _T("Deleting object %d [%s]"), m_dwId, m_szName);
487
488 // Prevent object change propagation util it marked as deleted
489 // (to prevent object re-appearance in GUI if client hides object
490 // after successful call to Session::deleteObject())
491 LockData();
492 m_isHidden = true;
493 UnlockData();
494
495 // Notify modules about object deletion
496 for(UINT32 i = 0; i < g_dwNumModules; i++)
497 {
498 if (g_pModuleList[i].pfPreObjectDelete != NULL)
499 g_pModuleList[i].pfPreObjectDelete(this);
500 }
501
502 prepareForDeletion();
503
504 // Remove references to this object from parent objects
505 DbgPrintf(5, _T("NetObj::Delete(): clearing parent list for object %d"), m_dwId);
506 LockParentList(TRUE);
507 for(i = 0; i < m_dwParentCount; i++)
508 {
509 m_pParentList[i]->DeleteChild(this);
510 m_pParentList[i]->calculateCompoundStatus();
511 decRefCount();
512 }
513 free(m_pParentList);
514 m_pParentList = NULL;
515 m_dwParentCount = 0;
516 UnlockParentList();
517
518 // Delete references to this object from child objects
519 DbgPrintf(5, _T("NetObj::Delete(): clearing child list for object %d"), m_dwId);
520 LockChildList(TRUE);
521 for(i = 0; i < m_dwChildCount; i++)
522 {
523 m_pChildList[i]->DeleteParent(this);
524 decRefCount();
525 if (m_pChildList[i]->isOrphaned())
526 m_pChildList[i]->deleteObject();
527 }
528 free(m_pChildList);
529 m_pChildList = NULL;
530 m_dwChildCount = 0;
531 UnlockChildList();
532
533 LockData();
534 m_isHidden = false;
535 m_isDeleted = true;
536 Modify();
537 UnlockData();
538
539 DbgPrintf(5, _T("NetObj::Delete(): deleting object %d from indexes"), m_dwId);
540 NetObjDeleteFromIndexes(this);
541
542 // Notify all other objects about object deletion
543 DbgPrintf(5, _T("NetObj::Delete(): calling OnObjectDelete(%d)"), m_dwId);
544 g_idxObjectById.forEach(onObjectDeleteCallback, this);
545
546 DbgPrintf(4, _T("Object %d successfully deleted"), m_dwId);
547 }
548
549 /**
550 * Default handler for object deletion notification
551 */
552 void NetObj::onObjectDelete(UINT32 dwObjectId)
553 {
554 }
555
556 /**
557 * Get childs IDs in printable form
558 */
559 const TCHAR *NetObj::dbgGetChildList(TCHAR *szBuffer)
560 {
561 UINT32 i;
562 TCHAR *pBuf = szBuffer;
563
564 *pBuf = 0;
565 LockChildList(FALSE);
566 for(i = 0, pBuf = szBuffer; i < m_dwChildCount; i++)
567 {
568 _sntprintf(pBuf, 10, _T("%d "), m_pChildList[i]->Id());
569 while(*pBuf)
570 pBuf++;
571 }
572 UnlockChildList();
573 if (pBuf != szBuffer)
574 *(pBuf - 1) = 0;
575 return szBuffer;
576 }
577
578 /**
579 * Get parents IDs in printable form
580 */
581 const TCHAR *NetObj::dbgGetParentList(TCHAR *szBuffer)
582 {
583 UINT32 i;
584 TCHAR *pBuf = szBuffer;
585
586 *pBuf = 0;
587 LockParentList(FALSE);
588 for(i = 0; i < m_dwParentCount; i++)
589 {
590 _sntprintf(pBuf, 10, _T("%d "), m_pParentList[i]->Id());
591 while(*pBuf)
592 pBuf++;
593 }
594 UnlockParentList();
595 if (pBuf != szBuffer)
596 *(pBuf - 1) = 0;
597 return szBuffer;
598 }
599
600 /**
601 * Calculate status for compound object based on childs' status
602 */
603 void NetObj::calculateCompoundStatus(BOOL bForcedRecalc)
604 {
605 UINT32 i;
606 int iMostCriticalAlarm, iMostCriticalStatus, iCount, iStatusAlg;
607 int nSingleThreshold, *pnThresholds, iOldStatus = m_iStatus;
608 int nRating[5], iChildStatus, nThresholds[4];
609
610 if (m_iStatus != STATUS_UNMANAGED)
611 {
612 iMostCriticalAlarm = g_alarmMgr.getMostCriticalStatusForObject(m_dwId);
613
614 LockData();
615 if (m_iStatusCalcAlg == SA_CALCULATE_DEFAULT)
616 {
617 iStatusAlg = GetDefaultStatusCalculation(&nSingleThreshold, &pnThresholds);
618 }
619 else
620 {
621 iStatusAlg = m_iStatusCalcAlg;
622 nSingleThreshold = m_iStatusSingleThreshold;
623 pnThresholds = m_iStatusThresholds;
624 }
625 if (iStatusAlg == SA_CALCULATE_SINGLE_THRESHOLD)
626 {
627 for(i = 0; i < 4; i++)
628 nThresholds[i] = nSingleThreshold;
629 pnThresholds = nThresholds;
630 }
631
632 switch(iStatusAlg)
633 {
634 case SA_CALCULATE_MOST_CRITICAL:
635 LockChildList(FALSE);
636 for(i = 0, iCount = 0, iMostCriticalStatus = -1; i < m_dwChildCount; i++)
637 {
638 iChildStatus = m_pChildList[i]->getPropagatedStatus();
639 if ((iChildStatus < STATUS_UNKNOWN) &&
640 (iChildStatus > iMostCriticalStatus))
641 {
642 iMostCriticalStatus = iChildStatus;
643 iCount++;
644 }
645 }
646 m_iStatus = (iCount > 0) ? iMostCriticalStatus : STATUS_UNKNOWN;
647 UnlockChildList();
648 break;
649 case SA_CALCULATE_SINGLE_THRESHOLD:
650 case SA_CALCULATE_MULTIPLE_THRESHOLDS:
651 // Step 1: calculate severity raitings
652 memset(nRating, 0, sizeof(int) * 5);
653 LockChildList(FALSE);
654 for(i = 0, iCount = 0; i < m_dwChildCount; i++)
655 {
656 iChildStatus = m_pChildList[i]->getPropagatedStatus();
657 if (iChildStatus < STATUS_UNKNOWN)
658 {
659 while(iChildStatus >= 0)
660 nRating[iChildStatus--]++;
661 iCount++;
662 }
663 }
664 UnlockChildList();
665
666 // Step 2: check what severity rating is above threshold
667 if (iCount > 0)
668 {
669 for(i = 4; i > 0; i--)
670 if (nRating[i] * 100 / iCount >= pnThresholds[i - 1])
671 break;
672 m_iStatus = i;
673 }
674 else
675 {
676 m_iStatus = STATUS_UNKNOWN;
677 }
678 break;
679 default:
680 m_iStatus = STATUS_UNKNOWN;
681 break;
682 }
683
684 // If alarms exist for object, apply alarm severity to object's status
685 if (iMostCriticalAlarm != STATUS_UNKNOWN)
686 {
687 if (m_iStatus == STATUS_UNKNOWN)
688 {
689 m_iStatus = iMostCriticalAlarm;
690 }
691 else
692 {
693 m_iStatus = max(m_iStatus, iMostCriticalAlarm);
694 }
695 }
696
697 // Query loaded modules for object status
698 for(i = 0; i < g_dwNumModules; i++)
699 {
700 if (g_pModuleList[i].pfCalculateObjectStatus != NULL)
701 {
702 int moduleStatus = g_pModuleList[i].pfCalculateObjectStatus(this);
703 if (moduleStatus != STATUS_UNKNOWN)
704 {
705 if (m_iStatus == STATUS_UNKNOWN)
706 {
707 m_iStatus = moduleStatus;
708 }
709 else
710 {
711 m_iStatus = max(m_iStatus, moduleStatus);
712 }
713 }
714 }
715 }
716
717 UnlockData();
718
719 // Cause parent object(s) to recalculate it's status
720 if ((iOldStatus != m_iStatus) || bForcedRecalc)
721 {
722 LockParentList(FALSE);
723 for(i = 0; i < m_dwParentCount; i++)
724 m_pParentList[i]->calculateCompoundStatus();
725 UnlockParentList();
726 LockData();
727 Modify();
728 UnlockData();
729 }
730 }
731 }
732
733 /**
734 * Load ACL from database
735 */
736 BOOL NetObj::loadACLFromDB()
737 {
738 BOOL bSuccess = FALSE;
739
740 DB_STATEMENT hStmt = DBPrepare(g_hCoreDB, _T("SELECT user_id,access_rights FROM acl WHERE object_id=?"));
741 if (hStmt != NULL)
742 {
743 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_dwId);
744 DB_RESULT hResult = DBSelectPrepared(hStmt);
745 if (hResult != NULL)
746 {
747 int i, iNumRows;
748
749 iNumRows = DBGetNumRows(hResult);
750 for(i = 0; i < iNumRows; i++)
751 m_pAccessList->addElement(DBGetFieldULong(hResult, i, 0),
752 DBGetFieldULong(hResult, i, 1));
753 DBFreeResult(hResult);
754 bSuccess = TRUE;
755 }
756 DBFreeStatement(hStmt);
757 }
758 return bSuccess;
759 }
760
761 /**
762 * ACL enumeration parameters structure
763 */
764 struct SAVE_PARAM
765 {
766 DB_HANDLE hdb;
767 UINT32 dwObjectId;
768 };
769
770 /**
771 * Handler for ACL elements enumeration
772 */
773 static void EnumerationHandler(UINT32 dwUserId, UINT32 dwAccessRights, void *pArg)
774 {
775 TCHAR szQuery[256];
776
777 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("INSERT INTO acl (object_id,user_id,access_rights) VALUES (%d,%d,%d)"),
778 ((SAVE_PARAM *)pArg)->dwObjectId, dwUserId, dwAccessRights);
779 DBQuery(((SAVE_PARAM *)pArg)->hdb, szQuery);
780 }
781
782 /**
783 * Save ACL to database
784 */
785 BOOL NetObj::saveACLToDB(DB_HANDLE hdb)
786 {
787 TCHAR szQuery[256];
788 BOOL bSuccess = FALSE;
789 SAVE_PARAM sp;
790
791 // Save access list
792 LockACL();
793 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM acl WHERE object_id=%d"), m_dwId);
794 if (DBQuery(hdb, szQuery))
795 {
796 sp.dwObjectId = m_dwId;
797 sp.hdb = hdb;
798 m_pAccessList->enumerateElements(EnumerationHandler, &sp);
799 bSuccess = TRUE;
800 }
801 UnlockACL();
802 return bSuccess;
803 }
804
805 /**
806 * Create NXCP message with object's data
807 */
808 void NetObj::CreateMessage(CSCPMessage *pMsg)
809 {
810 UINT32 i, dwId;
811
812 pMsg->SetVariable(VID_OBJECT_CLASS, (WORD)Type());
813 pMsg->SetVariable(VID_OBJECT_ID, m_dwId);
814 pMsg->SetVariable(VID_GUID, m_guid, UUID_LENGTH);
815 pMsg->SetVariable(VID_OBJECT_NAME, m_szName);
816 pMsg->SetVariable(VID_OBJECT_STATUS, (WORD)m_iStatus);
817 pMsg->SetVariable(VID_IP_ADDRESS, m_dwIpAddr);
818 pMsg->SetVariable(VID_IS_DELETED, (WORD)(m_isDeleted ? 1 : 0));
819 pMsg->SetVariable(VID_IS_SYSTEM, (WORD)(m_isSystem ? 1 : 0));
820
821 LockParentList(FALSE);
822 pMsg->SetVariable(VID_PARENT_CNT, m_dwParentCount);
823 for(i = 0, dwId = VID_PARENT_ID_BASE; i < m_dwParentCount; i++, dwId++)
824 pMsg->SetVariable(dwId, m_pParentList[i]->Id());
825 UnlockParentList();
826
827 LockChildList(FALSE);
828 pMsg->SetVariable(VID_CHILD_CNT, m_dwChildCount);
829 for(i = 0, dwId = VID_CHILD_ID_BASE; i < m_dwChildCount; i++, dwId++)
830 pMsg->SetVariable(dwId, m_pChildList[i]->Id());
831 UnlockChildList();
832
833 pMsg->SetVariable(VID_INHERIT_RIGHTS, (WORD)m_bInheritAccessRights);
834 pMsg->SetVariable(VID_STATUS_CALCULATION_ALG, (WORD)m_iStatusCalcAlg);
835 pMsg->SetVariable(VID_STATUS_PROPAGATION_ALG, (WORD)m_iStatusPropAlg);
836 pMsg->SetVariable(VID_FIXED_STATUS, (WORD)m_iFixedStatus);
837 pMsg->SetVariable(VID_STATUS_SHIFT, (WORD)m_iStatusShift);
838 pMsg->SetVariable(VID_STATUS_TRANSLATION_1, (WORD)m_iStatusTranslation[0]);
839 pMsg->SetVariable(VID_STATUS_TRANSLATION_2, (WORD)m_iStatusTranslation[1]);
840 pMsg->SetVariable(VID_STATUS_TRANSLATION_3, (WORD)m_iStatusTranslation[2]);
841 pMsg->SetVariable(VID_STATUS_TRANSLATION_4, (WORD)m_iStatusTranslation[3]);
842 pMsg->SetVariable(VID_STATUS_SINGLE_THRESHOLD, (WORD)m_iStatusSingleThreshold);
843 pMsg->SetVariable(VID_STATUS_THRESHOLD_1, (WORD)m_iStatusThresholds[0]);
844 pMsg->SetVariable(VID_STATUS_THRESHOLD_2, (WORD)m_iStatusThresholds[1]);
845 pMsg->SetVariable(VID_STATUS_THRESHOLD_3, (WORD)m_iStatusThresholds[2]);
846 pMsg->SetVariable(VID_STATUS_THRESHOLD_4, (WORD)m_iStatusThresholds[3]);
847 pMsg->SetVariable(VID_COMMENTS, CHECK_NULL_EX(m_pszComments));
848 pMsg->SetVariable(VID_IMAGE, m_image, UUID_LENGTH);
849 pMsg->SetVariable(VID_SUBMAP_ID, m_submapId);
850 pMsg->SetVariable(VID_NUM_TRUSTED_NODES, m_dwNumTrustedNodes);
851 if (m_dwNumTrustedNodes > 0)
852 pMsg->SetVariableToInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
853
854 pMsg->SetVariable(VID_NUM_CUSTOM_ATTRIBUTES, m_customAttributes.getSize());
855 for(i = 0, dwId = VID_CUSTOM_ATTRIBUTES_BASE; i < m_customAttributes.getSize(); i++)
856 {
857 pMsg->SetVariable(dwId++, m_customAttributes.getKeyByIndex(i));
858 pMsg->SetVariable(dwId++, m_customAttributes.getValueByIndex(i));
859 }
860
861 m_pAccessList->fillMessage(pMsg);
862 m_geoLocation.fillMessage(*pMsg);
863 }
864
865 /**
866 * Handler for EnumerateSessions()
867 */
868 static void BroadcastObjectChange(ClientSession *pSession, void *pArg)
869 {
870 if (pSession->isAuthenticated())
871 pSession->onObjectChange((NetObj *)pArg);
872 }
873
874 /**
875 * Mark object as modified and put on client's notification queue
876 * We assume that object is locked at the time of function call
877 */
878 void NetObj::Modify()
879 {
880 if (g_bModificationsLocked)
881 return;
882
883 m_isModified = true;
884 m_dwTimeStamp = (UINT32)time(NULL);
885
886 // Send event to all connected clients
887 if (!m_isHidden && !m_isSystem)
888 EnumerateClientSessions(BroadcastObjectChange, this);
889 }
890
891 /**
892 * Modify object from NXCP message
893 */
894 UINT32 NetObj::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
895 {
896 BOOL bRecalcStatus = FALSE;
897
898 if (!bAlreadyLocked)
899 LockData();
900
901 // Change object's name
902 if (pRequest->IsVariableExist(VID_OBJECT_NAME))
903 pRequest->GetVariableStr(VID_OBJECT_NAME, m_szName, MAX_OBJECT_NAME);
904
905 // Change object's status calculation/propagation algorithms
906 if (pRequest->IsVariableExist(VID_STATUS_CALCULATION_ALG))
907 {
908 m_iStatusCalcAlg = (int)pRequest->GetVariableShort(VID_STATUS_CALCULATION_ALG);
909 m_iStatusPropAlg = (int)pRequest->GetVariableShort(VID_STATUS_PROPAGATION_ALG);
910 m_iFixedStatus = (int)pRequest->GetVariableShort(VID_FIXED_STATUS);
911 m_iStatusShift = pRequest->GetVariableShortAsInt32(VID_STATUS_SHIFT);
912 m_iStatusTranslation[0] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_1);
913 m_iStatusTranslation[1] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_2);
914 m_iStatusTranslation[2] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_3);
915 m_iStatusTranslation[3] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_4);
916 m_iStatusSingleThreshold = (int)pRequest->GetVariableShort(VID_STATUS_SINGLE_THRESHOLD);
917 m_iStatusThresholds[0] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_1);
918 m_iStatusThresholds[1] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_2);
919 m_iStatusThresholds[2] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_3);
920 m_iStatusThresholds[3] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_4);
921 bRecalcStatus = TRUE;
922 }
923
924 // Change image
925 if (pRequest->IsVariableExist(VID_IMAGE))
926 pRequest->GetVariableBinary(VID_IMAGE, m_image, UUID_LENGTH);
927
928 // Change object's ACL
929 if (pRequest->IsVariableExist(VID_ACL_SIZE))
930 {
931 UINT32 i, dwNumElements;
932
933 LockACL();
934 dwNumElements = pRequest->GetVariableLong(VID_ACL_SIZE);
935 m_bInheritAccessRights = pRequest->GetVariableShort(VID_INHERIT_RIGHTS);
936 m_pAccessList->deleteAll();
937 for(i = 0; i < dwNumElements; i++)
938 m_pAccessList->addElement(pRequest->GetVariableLong(VID_ACL_USER_BASE + i),
939 pRequest->GetVariableLong(VID_ACL_RIGHTS_BASE +i));
940 UnlockACL();
941 }
942
943 // Change trusted nodes list
944 if (pRequest->IsVariableExist(VID_NUM_TRUSTED_NODES))
945 {
946 m_dwNumTrustedNodes = pRequest->GetVariableLong(VID_NUM_TRUSTED_NODES);
947 m_pdwTrustedNodes = (UINT32 *)realloc(m_pdwTrustedNodes, sizeof(UINT32) * m_dwNumTrustedNodes);
948 pRequest->GetVariableInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
949 }
950
951 // Change custom attributes
952 if (pRequest->IsVariableExist(VID_NUM_CUSTOM_ATTRIBUTES))
953 {
954 UINT32 i, dwId, dwNumElements;
955 TCHAR *name, *value;
956
957 dwNumElements = pRequest->GetVariableLong(VID_NUM_CUSTOM_ATTRIBUTES);
958 m_customAttributes.clear();
959 for(i = 0, dwId = VID_CUSTOM_ATTRIBUTES_BASE; i < dwNumElements; i++)
960 {
961 name = pRequest->GetVariableStr(dwId++);
962 value = pRequest->GetVariableStr(dwId++);
963 if ((name != NULL) && (value != NULL))
964 m_customAttributes.setPreallocated(name, value);
965 }
966 }
967
968 // Change geolocation
969 if (pRequest->IsVariableExist(VID_GEOLOCATION_TYPE))
970 {
971 m_geoLocation = GeoLocation(*pRequest);
972 }
973
974 if (pRequest->IsVariableExist(VID_SUBMAP_ID))
975 {
976 m_submapId = pRequest->GetVariableLong(VID_SUBMAP_ID);
977 }
978
979 Modify();
980 UnlockData();
981
982 if (bRecalcStatus)
983 calculateCompoundStatus(TRUE);
984
985 return RCC_SUCCESS;
986 }
987
988 /**
989 * Post-modify hook
990 */
991 void NetObj::postModify()
992 {
993 calculateCompoundStatus(TRUE);
994 }
995
996 /**
997 * Get rights to object for specific user
998 *
999 * @param userId user object ID
1000 */
1001 UINT32 NetObj::getUserRights(UINT32 userId)
1002 {
1003 UINT32 dwRights;
1004
1005 // Admin always has all rights to any object
1006 if (userId == 0)
1007 return 0xFFFFFFFF;
1008
1009 // Non-admin users have no rights to system objects
1010 if (m_isSystem)
1011 return 0;
1012
1013 // Check if have direct right assignment
1014 LockACL();
1015 bool hasDirectRights = m_pAccessList->getUserRights(userId, &dwRights);
1016 UnlockACL();
1017
1018 if (!hasDirectRights)
1019 {
1020 // We don't. If this object inherit rights from parents, get them
1021 if (m_bInheritAccessRights)
1022 {
1023 UINT32 i;
1024
1025 LockParentList(FALSE);
1026 for(i = 0, dwRights = 0; i < m_dwParentCount; i++)
1027 dwRights |= m_pParentList[i]->getUserRights(userId);
1028 UnlockParentList();
1029 }
1030 }
1031
1032 return dwRights;
1033 }
1034
1035 /**
1036 * Check if given user has specific rights on this object
1037 *
1038 * @param userId user object ID
1039 * @param requiredRights bit mask of requested right
1040 * @return true if user has all rights specified in requested rights bit mask
1041 */
1042 BOOL NetObj::checkAccessRights(UINT32 userId, UINT32 requiredRights)
1043 {
1044 UINT32 effectiveRights = getUserRights(userId);
1045 return (effectiveRights & requiredRights) == requiredRights;
1046 }
1047
1048 /**
1049 * Drop all user privileges on current object
1050 */
1051 void NetObj::dropUserAccess(UINT32 dwUserId)
1052 {
1053 LockACL();
1054 bool modified = m_pAccessList->deleteElement(dwUserId);
1055 UnlockACL();
1056 if (modified)
1057 {
1058 LockData();
1059 Modify();
1060 UnlockData();
1061 }
1062 }
1063
1064 /**
1065 * Set object's management status
1066 */
1067 void NetObj::setMgmtStatus(BOOL bIsManaged)
1068 {
1069 UINT32 i;
1070 int iOldStatus;
1071
1072 LockData();
1073
1074 if ((bIsManaged && (m_iStatus != STATUS_UNMANAGED)) ||
1075 ((!bIsManaged) && (m_iStatus == STATUS_UNMANAGED)))
1076 {
1077 UnlockData();
1078 return; // Status is already correct
1079 }
1080
1081 iOldStatus = m_iStatus;
1082 m_iStatus = (bIsManaged ? STATUS_UNKNOWN : STATUS_UNMANAGED);
1083
1084 // Generate event if current object is a node
1085 if (Type() == OBJECT_NODE)
1086 PostEvent(bIsManaged ? EVENT_NODE_UNKNOWN : EVENT_NODE_UNMANAGED, m_dwId, "d", iOldStatus);
1087
1088 Modify();
1089 UnlockData();
1090
1091 // Change status for child objects also
1092 LockChildList(FALSE);
1093 for(i = 0; i < m_dwChildCount; i++)
1094 m_pChildList[i]->setMgmtStatus(bIsManaged);
1095 UnlockChildList();
1096
1097 // Cause parent object(s) to recalculate it's status
1098 LockParentList(FALSE);
1099 for(i = 0; i < m_dwParentCount; i++)
1100 m_pParentList[i]->calculateCompoundStatus();
1101 UnlockParentList();
1102 }
1103
1104 /**
1105 * Check if given object is an our child (possibly indirect, i.e child of child)
1106 *
1107 * @param id object ID to test
1108 */
1109 bool NetObj::isChild(UINT32 id)
1110 {
1111 UINT32 i;
1112 bool bResult = false;
1113
1114 // Check for our own ID (object ID should never change, so we may not lock object's data)
1115 if (m_dwId == id)
1116 bResult = true;
1117
1118 // First, walk through our own child list
1119 if (!bResult)
1120 {
1121 LockChildList(FALSE);
1122 for(i = 0; i < m_dwChildCount; i++)
1123 if (m_pChildList[i]->Id() == id)
1124 {
1125 bResult = true;
1126 break;
1127 }
1128 UnlockChildList();
1129 }
1130
1131 // If given object is not in child list, check if it is indirect child
1132 if (!bResult)
1133 {
1134 LockChildList(FALSE);
1135 for(i = 0; i < m_dwChildCount; i++)
1136 if (m_pChildList[i]->isChild(id))
1137 {
1138 bResult = true;
1139 break;
1140 }
1141 UnlockChildList();
1142 }
1143
1144 return bResult;
1145 }
1146
1147 /**
1148 * Send message to client, who requests poll, if any
1149 * This method is used by Node and Interface class objects
1150 */
1151 void NetObj::sendPollerMsg(UINT32 dwRqId, const TCHAR *pszFormat, ...)
1152 {
1153 if (m_pollRequestor != NULL)
1154 {
1155 va_list args;
1156 TCHAR szBuffer[1024];
1157
1158 va_start(args, pszFormat);
1159 _vsntprintf(szBuffer, 1024, pszFormat, args);
1160 va_end(args);
1161 m_pollRequestor->sendPollerMsg(dwRqId, szBuffer);
1162 }
1163 }
1164
1165 /**
1166 * Add child node objects (direct and indirect childs) to list
1167 */
1168 void NetObj::addChildNodesToList(ObjectArray<Node> *nodeList, UINT32 dwUserId)
1169 {
1170 UINT32 i;
1171
1172 LockChildList(FALSE);
1173
1174 // Walk through our own child list
1175 for(i = 0; i < m_dwChildCount; i++)
1176 {
1177 if (m_pChildList[i]->Type() == OBJECT_NODE)
1178 {
1179 // Check if this node already in the list
1180 int j;
1181 for(j = 0; j < nodeList->size(); j++)
1182 if (nodeList->get(j)->Id() == m_pChildList[i]->Id())
1183 break;
1184 if (j == nodeList->size())
1185 {
1186 m_pChildList[i]->incRefCount();
1187 nodeList->add((Node *)m_pChildList[i]);
1188 }
1189 }
1190 else
1191 {
1192 if (m_pChildList[i]->checkAccessRights(dwUserId, OBJECT_ACCESS_READ))
1193 m_pChildList[i]->addChildNodesToList(nodeList, dwUserId);
1194 }
1195 }
1196
1197 UnlockChildList();
1198 }
1199
1200 /**
1201 * Add child data collection targets (direct and indirect childs) to list
1202 */
1203 void NetObj::addChildDCTargetsToList(ObjectArray<DataCollectionTarget> *dctList, UINT32 dwUserId)
1204 {
1205 UINT32 i;
1206
1207 LockChildList(FALSE);
1208
1209 // Walk through our own child list
1210 for(i = 0; i < m_dwChildCount; i++)
1211 {
1212 if ((m_pChildList[i]->Type() == OBJECT_NODE) || (m_pChildList[i]->Type() == OBJECT_MOBILEDEVICE))
1213 {
1214 // Check if this objects already in the list
1215 int j;
1216 for(j = 0; j < dctList->size(); j++)
1217 if (dctList->get(j)->Id() == m_pChildList[i]->Id())
1218 break;
1219 if (j == dctList->size())
1220 {
1221 m_pChildList[i]->incRefCount();
1222 dctList->add((DataCollectionTarget *)m_pChildList[i]);
1223 }
1224 }
1225 else
1226 {
1227 if (m_pChildList[i]->checkAccessRights(dwUserId, OBJECT_ACCESS_READ))
1228 m_pChildList[i]->addChildDCTargetsToList(dctList, dwUserId);
1229 }
1230 }
1231
1232 UnlockChildList();
1233 }
1234
1235 /**
1236 * Hide object and all its childs
1237 */
1238 void NetObj::hide()
1239 {
1240 UINT32 i;
1241
1242 LockChildList(FALSE);
1243 for(i = 0; i < m_dwChildCount; i++)
1244 m_pChildList[i]->hide();
1245 UnlockChildList();
1246
1247 LockData();
1248 m_isHidden = true;
1249 UnlockData();
1250 }
1251
1252 /**
1253 * Unhide object and all its childs
1254 */
1255 void NetObj::unhide()
1256 {
1257 UINT32 i;
1258
1259 LockData();
1260 m_isHidden = false;
1261 if (!m_isSystem)
1262 EnumerateClientSessions(BroadcastObjectChange, this);
1263 UnlockData();
1264
1265 LockChildList(FALSE);
1266 for(i = 0; i < m_dwChildCount; i++)
1267 m_pChildList[i]->unhide();
1268 UnlockChildList();
1269 }
1270
1271 /**
1272 * Return status propagated to parent
1273 */
1274 int NetObj::getPropagatedStatus()
1275 {
1276 int iStatus;
1277
1278 if (m_iStatusPropAlg == SA_PROPAGATE_DEFAULT)
1279 {
1280 iStatus = DefaultPropagatedStatus(m_iStatus);
1281 }
1282 else
1283 {
1284 switch(m_iStatusPropAlg)
1285 {
1286 case SA_PROPAGATE_UNCHANGED:
1287 iStatus = m_iStatus;
1288 break;
1289 case SA_PROPAGATE_FIXED:
1290 iStatus = ((m_iStatus > STATUS_NORMAL) && (m_iStatus < STATUS_UNKNOWN)) ? m_iFixedStatus : m_iStatus;
1291 break;
1292 case SA_PROPAGATE_RELATIVE:
1293 if ((m_iStatus > STATUS_NORMAL) && (m_iStatus < STATUS_UNKNOWN))
1294 {
1295 iStatus = m_iStatus + m_iStatusShift;
1296 if (iStatus < 0)
1297 iStatus = 0;
1298 if (iStatus > STATUS_CRITICAL)
1299 iStatus = STATUS_CRITICAL;
1300 }
1301 else
1302 {
1303 iStatus = m_iStatus;
1304 }
1305 break;
1306 case SA_PROPAGATE_TRANSLATED:
1307 if ((m_iStatus > STATUS_NORMAL) && (m_iStatus < STATUS_UNKNOWN))
1308 {
1309 iStatus = m_iStatusTranslation[m_iStatus - 1];
1310 }
1311 else
1312 {
1313 iStatus = m_iStatus;
1314 }
1315 break;
1316 default:
1317 iStatus = STATUS_UNKNOWN;
1318 break;
1319 }
1320 }
1321 return iStatus;
1322 }
1323
1324 /**
1325 * Prepare object for deletion. Method should return only
1326 * when object deletion is safe
1327 */
1328 void NetObj::prepareForDeletion()
1329 {
1330 }
1331
1332 /**
1333 * Set object's comments.
1334 * NOTE: pszText should be dynamically allocated or NULL
1335 */
1336 void NetObj::setComments(TCHAR *pszText)
1337 {
1338 LockData();
1339 safe_free(m_pszComments);
1340 m_pszComments = pszText;
1341 Modify();
1342 UnlockData();
1343 }
1344
1345 /**
1346 * Copy object's comments to NXCP message
1347 */
1348 void NetObj::commentsToMessage(CSCPMessage *pMsg)
1349 {
1350 LockData();
1351 pMsg->SetVariable(VID_COMMENTS, CHECK_NULL_EX(m_pszComments));
1352 UnlockData();
1353 }
1354
1355 /**
1356 * Load trusted nodes list from database
1357 */
1358 BOOL NetObj::loadTrustedNodes()
1359 {
1360 DB_RESULT hResult;
1361 TCHAR query[256];
1362 int i, count;
1363
1364 _sntprintf(query, 256, _T("SELECT target_node_id FROM trusted_nodes WHERE source_object_id=%d"), m_dwId);
1365 hResult = DBSelect(g_hCoreDB, query);
1366 if (hResult != NULL)
1367 {
1368 count = DBGetNumRows(hResult);
1369 if (count > 0)
1370 {
1371 m_dwNumTrustedNodes = count;
1372 m_pdwTrustedNodes = (UINT32 *)malloc(sizeof(UINT32) * count);
1373 for(i = 0; i < count; i++)
1374 {
1375 m_pdwTrustedNodes[i] = DBGetFieldULong(hResult, i, 0);
1376 }
1377 }
1378 DBFreeResult(hResult);
1379 }
1380 return (hResult != NULL);
1381 }
1382
1383 /**
1384 * Save list of trusted nodes to database
1385 */
1386 BOOL NetObj::saveTrustedNodes(DB_HANDLE hdb)
1387 {
1388 TCHAR query[256];
1389 UINT32 i;
1390 BOOL rc = FALSE;
1391
1392 _sntprintf(query, 256, _T("DELETE FROM trusted_nodes WHERE source_object_id=%d"), m_dwId);
1393 if (DBQuery(hdb, query))
1394 {
1395 for(i = 0; i < m_dwNumTrustedNodes; i++)
1396 {
1397 _sntprintf(query, 256, _T("INSERT INTO trusted_nodes (source_object_id,target_node_id) VALUES (%d,%d)"),
1398 m_dwId, m_pdwTrustedNodes[i]);
1399 if (!DBQuery(hdb, query))
1400 break;
1401 }
1402 if (i == m_dwNumTrustedNodes)
1403 rc = TRUE;
1404 }
1405 return rc;
1406 }
1407
1408 /**
1409 * Check if given node is in trust list
1410 * Will always return TRUE if system parameter CheckTrustedNodes set to 0
1411 */
1412 bool NetObj::isTrustedNode(UINT32 id)
1413 {
1414 bool rc;
1415
1416 if (g_dwFlags & AF_CHECK_TRUSTED_NODES)
1417 {
1418 UINT32 i;
1419
1420 LockData();
1421 for(i = 0, rc = false; i < m_dwNumTrustedNodes; i++)
1422 {
1423 if (m_pdwTrustedNodes[i] == id)
1424 {
1425 rc = true;
1426 break;
1427 }
1428 }
1429 UnlockData();
1430 }
1431 else
1432 {
1433 rc = true;
1434 }
1435 return rc;
1436 }
1437
1438 /**
1439 * Get list of parent objects for NXSL script
1440 */
1441 NXSL_Array *NetObj::getParentsForNXSL()
1442 {
1443 NXSL_Array *parents = new NXSL_Array;
1444 int index = 0;
1445
1446 LockParentList(FALSE);
1447 for(UINT32 i = 0; i < m_dwParentCount; i++)
1448 {
1449 if ((m_pParentList[i]->Type() == OBJECT_CONTAINER) ||
1450 (m_pParentList[i]->Type() == OBJECT_SERVICEROOT) ||
1451 (m_pParentList[i]->Type() == OBJECT_NETWORK))
1452 {
1453 parents->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass, m_pParentList[i])));
1454 }
1455 }
1456 UnlockParentList();
1457
1458 return parents;
1459 }
1460
1461 /**
1462 * Get list of child objects for NXSL script
1463 */
1464 NXSL_Array *NetObj::getChildrenForNXSL()
1465 {
1466 NXSL_Array *children = new NXSL_Array;
1467 int index = 0;
1468
1469 LockChildList(FALSE);
1470 for(UINT32 i = 0; i < m_dwChildCount; i++)
1471 {
1472 if (m_pChildList[i]->Type() == OBJECT_NODE)
1473 {
1474 children->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, m_pChildList[i])));
1475 }
1476 else if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1477 {
1478 children->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslInterfaceClass, m_pChildList[i])));
1479 }
1480 else
1481 {
1482 children->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass, m_pChildList[i])));
1483 }
1484 }
1485 UnlockChildList();
1486
1487 return children;
1488 }
1489
1490 /**
1491 * Get full list of child objects (including both direct and indirect childs)
1492 */
1493 void NetObj::getFullChildListInternal(ObjectIndex *list, bool eventSourceOnly)
1494 {
1495 LockChildList(FALSE);
1496 for(UINT32 i = 0; i < m_dwChildCount; i++)
1497 {
1498 if (!eventSourceOnly || IsEventSource(m_pChildList[i]->Type()))
1499 list->put(m_pChildList[i]->Id(), m_pChildList[i]);
1500 m_pChildList[i]->getFullChildListInternal(list, eventSourceOnly);
1501 }
1502 UnlockChildList();
1503 }
1504
1505 /**
1506 * Get full list of child objects (including both direct and indirect childs).
1507 * Returned array is dynamically allocated and must be deleted by the caller.
1508 *
1509 * @param eventSourceOnly if true, only objects that can be event source will be included
1510 */
1511 ObjectArray<NetObj> *NetObj::getFullChildList(bool eventSourceOnly, bool updateRefCount)
1512 {
1513 ObjectIndex list;
1514 getFullChildListInternal(&list, eventSourceOnly);
1515 return list.getObjects(updateRefCount);
1516 }
1517
1518 /**
1519 * Get list of child objects (direct only). Returned array is
1520 * dynamically allocated and must be deleted by the caller.
1521 *
1522 * @param typeFilter Only return objects with class ID equals given value.
1523 * Set to -1 to disable filtering.
1524 */
1525 ObjectArray<NetObj> *NetObj::getChildList(int typeFilter)
1526 {
1527 LockChildList(FALSE);
1528 ObjectArray<NetObj> *list = new ObjectArray<NetObj>((int)m_dwChildCount, 16, false);
1529 for(UINT32 i = 0; i < m_dwChildCount; i++)
1530 {
1531 if ((typeFilter == -1) || (typeFilter == m_pChildList[i]->Type()))
1532 list->add(m_pChildList[i]);
1533 }
1534 UnlockChildList();
1535 return list;
1536 }
1537
1538 /**
1539 * Called by client session handler to check if threshold summary should
1540 * be shown for this object. Default implementation always returns false.
1541 */
1542 bool NetObj::showThresholdSummary()
1543 {
1544 return false;
1545 }