outdated object image stuff removed
[public/netxms.git] / src / server / core / netobj.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003, 2004, 2005 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 //
27 // NetObj class constructor
28 //
29
30 NetObj::NetObj()
31 {
32 int i;
33
34 m_dwRefCount = 0;
35 m_mutexData = MutexCreate();
36 m_mutexRefCount = MutexCreate();
37 m_mutexACL = MutexCreate();
38 m_rwlockParentList = RWLockCreate();
39 m_rwlockChildList = RWLockCreate();
40 m_iStatus = STATUS_UNKNOWN;
41 m_szName[0] = 0;
42 m_pszComments = NULL;
43 m_bIsModified = FALSE;
44 m_bIsDeleted = FALSE;
45 m_bIsHidden = FALSE;
46 m_bIsSystem = FALSE;
47 m_dwIpAddr = 0;
48 m_dwChildCount = 0;
49 m_pChildList = NULL;
50 m_dwParentCount = 0;
51 m_pParentList = NULL;
52 m_pAccessList = new AccessList;
53 m_bInheritAccessRights = TRUE;
54 m_dwNumTrustedNodes = 0;
55 m_pdwTrustedNodes = NULL;
56 m_dwImageId = 0; // Default image
57 m_pPollRequestor = NULL;
58 m_iStatusCalcAlg = SA_CALCULATE_DEFAULT;
59 m_iStatusPropAlg = SA_PROPAGATE_DEFAULT;
60 m_iFixedStatus = STATUS_WARNING;
61 m_iStatusShift = 0;
62 m_iStatusSingleThreshold = 75;
63 m_dwTimeStamp = 0;
64 for(i = 0; i < 4; i++)
65 {
66 m_iStatusTranslation[i] = i + 1;
67 m_iStatusThresholds[i] = 80 - i * 20;
68 }
69 }
70
71
72 //
73 // NetObj class destructor
74 //
75
76 NetObj::~NetObj()
77 {
78 MutexDestroy(m_mutexData);
79 MutexDestroy(m_mutexRefCount);
80 MutexDestroy(m_mutexACL);
81 RWLockDestroy(m_rwlockParentList);
82 RWLockDestroy(m_rwlockChildList);
83 safe_free(m_pChildList);
84 safe_free(m_pParentList);
85 delete m_pAccessList;
86 safe_free(m_pdwTrustedNodes);
87 safe_free(m_pszComments);
88 }
89
90
91 //
92 // Create object from database data
93 //
94
95 BOOL NetObj::CreateFromDB(DWORD dwId)
96 {
97 return FALSE; // Abstract objects cannot be loaded from database
98 }
99
100
101 //
102 // Save object to database
103 //
104
105 BOOL NetObj::SaveToDB(DB_HANDLE hdb)
106 {
107 return FALSE; // Abstract objects cannot be saved to database
108 }
109
110
111 //
112 // Delete object from database
113 //
114
115 BOOL NetObj::DeleteFromDB(void)
116 {
117 char szQuery[256];
118
119 // Delete ACL
120 sprintf(szQuery, "DELETE FROM acl WHERE object_id=%d", m_dwId);
121 QueueSQLRequest(szQuery);
122 sprintf(szQuery, "DELETE FROM object_properties WHERE object_id=%d", m_dwId);
123 QueueSQLRequest(szQuery);
124 sprintf(szQuery, "DELETE FROM object_custom_attributes WHERE object_id=%d", m_dwId);
125 QueueSQLRequest(szQuery);
126 return TRUE;
127 }
128
129
130 //
131 // Load common object properties from database
132 //
133
134 BOOL NetObj::LoadCommonProperties(void)
135 {
136 DB_RESULT hResult;
137 TCHAR szQuery[1024];
138 BOOL bResult = FALSE;
139
140 // Load access options
141 _sntprintf(szQuery, 1024, _T("SELECT name,status,is_deleted,image_id,")
142 _T("inherit_access_rights,last_modified,status_calc_alg,")
143 _T("status_prop_alg,status_fixed_val,status_shift,")
144 _T("status_translation,status_single_threshold,")
145 _T("status_thresholds,comments,is_system FROM object_properties ")
146 _T("WHERE object_id=%d"), m_dwId);
147 hResult = DBSelect(g_hCoreDB, szQuery);
148 if (hResult != NULL)
149 {
150 if (DBGetNumRows(hResult) > 0)
151 {
152 DBGetField(hResult, 0, 0, m_szName, MAX_OBJECT_NAME);
153 m_iStatus = DBGetFieldLong(hResult, 0, 1);
154 m_bIsDeleted = DBGetFieldLong(hResult, 0, 2) ? TRUE : FALSE;
155 m_dwImageId = DBGetFieldULong(hResult, 0, 3);
156 m_bInheritAccessRights = DBGetFieldLong(hResult, 0, 4) ? TRUE : FALSE;
157 m_dwTimeStamp = DBGetFieldULong(hResult, 0, 5);
158 m_iStatusCalcAlg = DBGetFieldLong(hResult, 0, 6);
159 m_iStatusPropAlg = DBGetFieldLong(hResult, 0, 7);
160 m_iFixedStatus = DBGetFieldLong(hResult, 0, 8);
161 m_iStatusShift = DBGetFieldLong(hResult, 0, 9);
162 DBGetFieldByteArray(hResult, 0, 10, m_iStatusTranslation, 4, STATUS_WARNING);
163 m_iStatusSingleThreshold = DBGetFieldLong(hResult, 0, 11);
164 DBGetFieldByteArray(hResult, 0, 12, m_iStatusThresholds, 4, 50);
165 safe_free(m_pszComments);
166 m_pszComments = DBGetField(hResult, 0, 13, NULL, 0);
167 DecodeSQLString(m_pszComments);
168 m_bIsSystem = DBGetFieldLong(hResult, 0, 14) ? TRUE : FALSE;
169 bResult = TRUE;
170 }
171 DBFreeResult(hResult);
172 }
173
174 // Load custom attributes
175 if (bResult)
176 {
177 _sntprintf(szQuery, 1024, _T("SELECT attr_name,attr_value FROM object_custom_attributes WHERE object_id=%d"), m_dwId);
178 hResult = DBSelect(g_hCoreDB, szQuery);
179 if (hResult != NULL)
180 {
181 int i, count;
182 TCHAR *name, *value;
183
184 count = DBGetNumRows(hResult);
185 for(i = 0; i < count; i++)
186 {
187 name = DBGetField(hResult, i, 0, NULL, 0);
188 if (name != NULL)
189 {
190 DecodeSQLString(name);
191 value = DBGetField(hResult, i, 1, NULL, 0);
192 if (value != NULL)
193 {
194 DecodeSQLString(value);
195 m_customAttributes.SetPreallocated(name, value);
196 }
197 }
198 }
199 DBFreeResult(hResult);
200 }
201 else
202 {
203 bResult = FALSE;
204 }
205 }
206
207 if (bResult)
208 bResult = LoadTrustedNodes();
209
210 return bResult;
211 }
212
213
214 //
215 // Save common object properties to database
216 //
217
218 BOOL NetObj::SaveCommonProperties(DB_HANDLE hdb)
219 {
220 TCHAR szQuery[16384], szTranslation[16], szThresholds[16], *pszEscComments;
221 DB_RESULT hResult;
222 BOOL bResult = FALSE;
223 int i, j;
224
225 // Save access options
226 _sntprintf(szQuery, 512, _T("SELECT object_id FROM object_properties WHERE object_id=%d"), m_dwId);
227 hResult = DBSelect(hdb, szQuery);
228 if (hResult != NULL)
229 {
230 for(i = 0, j = 0; i < 4; i++, j += 2)
231 {
232 _sntprintf(&szTranslation[j], 16 - j, _T("%02X"), (BYTE)m_iStatusTranslation[i]);
233 _sntprintf(&szThresholds[j], 16 - j, _T("%02X"), (BYTE)m_iStatusThresholds[i]);
234 }
235 pszEscComments = EncodeSQLString(CHECK_NULL_EX(m_pszComments));
236 if (_tcslen(pszEscComments) > 15500)
237 pszEscComments[15500] = 0;
238 if (DBGetNumRows(hResult) > 0)
239 {
240 _sntprintf(szQuery, 16384,
241 _T("UPDATE object_properties SET name='%s',status=%d,")
242 _T("is_deleted=%d,image_id=%d,inherit_access_rights=%d,")
243 _T("last_modified=%d,status_calc_alg=%d,status_prop_alg=%d,")
244 _T("status_fixed_val=%d,status_shift=%d,status_translation='%s',")
245 _T("status_single_threshold=%d,status_thresholds='%s',")
246 _T("comments='%s',is_system=%d WHERE object_id=%d"),
247 m_szName, m_iStatus, m_bIsDeleted, m_dwImageId,
248 m_bInheritAccessRights, m_dwTimeStamp, m_iStatusCalcAlg,
249 m_iStatusPropAlg, m_iFixedStatus, m_iStatusShift,
250 szTranslation, m_iStatusSingleThreshold, szThresholds,
251 pszEscComments, m_bIsSystem, m_dwId);
252 }
253 else
254 {
255 _sntprintf(szQuery, 16384,
256 _T("INSERT INTO object_properties (object_id,name,status,is_deleted,")
257 _T("image_id,inherit_access_rights,last_modified,status_calc_alg,")
258 _T("status_prop_alg,status_fixed_val,status_shift,status_translation,")
259 _T("status_single_threshold,status_thresholds,comments,is_system) ")
260 _T("VALUES (%d,'%s',%d,%d,%d,%d,%d,%d,%d,%d,%d,'%s',%d,'%s','%s',%d)"),
261 m_dwId, m_szName, m_iStatus, m_bIsDeleted, m_dwImageId,
262 m_bInheritAccessRights, m_dwTimeStamp, m_iStatusCalcAlg,
263 m_iStatusPropAlg, m_iFixedStatus, m_iStatusShift,
264 szTranslation, m_iStatusSingleThreshold, szThresholds,
265 pszEscComments, m_bIsSystem);
266 }
267 free(pszEscComments);
268 DBFreeResult(hResult);
269 bResult = DBQuery(hdb, szQuery);
270 }
271
272 // Save custom attributes
273 if (bResult)
274 {
275 _sntprintf(szQuery, 512, _T("DELETE FROM object_custom_attributes WHERE object_id=%d"), m_dwId);
276 bResult = DBQuery(hdb, szQuery);
277 if (bResult)
278 {
279 TCHAR *escName, *escValue;
280
281 for(i = 0; i < (int)m_customAttributes.Size(); i++)
282 {
283 escName = EncodeSQLString(m_customAttributes.GetKeyByIndex(i));
284 escValue = EncodeSQLString(m_customAttributes.GetValueByIndex(i));
285 _sntprintf(szQuery, 16384, _T("INSERT INTO object_custom_attributes (object_id,attr_name,attr_value) VALUES (%d,'%s','%s')"),
286 m_dwId, escName, escValue);
287 free(escName);
288 free(escValue);
289 bResult = DBQuery(hdb, szQuery);
290 if (!bResult)
291 break;
292 }
293 }
294 }
295
296 if (bResult)
297 bResult = SaveTrustedNodes(hdb);
298
299 return bResult;
300 }
301
302
303 //
304 // Add reference to the new child object
305 //
306
307 void NetObj::AddChild(NetObj *pObject)
308 {
309 DWORD i;
310
311 LockChildList(TRUE);
312 for(i = 0; i < m_dwChildCount; i++)
313 if (m_pChildList[i] == pObject)
314 {
315 UnlockChildList();
316 return; // Already in the child list
317 }
318 m_pChildList = (NetObj **)realloc(m_pChildList, sizeof(NetObj *) * (m_dwChildCount + 1));
319 m_pChildList[m_dwChildCount++] = pObject;
320 UnlockChildList();
321 Modify();
322 }
323
324
325 //
326 // Add reference to parent object
327 //
328
329 void NetObj::AddParent(NetObj *pObject)
330 {
331 DWORD i;
332
333 LockParentList(TRUE);
334 for(i = 0; i < m_dwParentCount; i++)
335 if (m_pParentList[i] == pObject)
336 {
337 UnlockParentList();
338 return; // Already in the parents list
339 }
340 m_pParentList = (NetObj **)realloc(m_pParentList, sizeof(NetObj *) * (m_dwParentCount + 1));
341 m_pParentList[m_dwParentCount++] = pObject;
342 UnlockParentList();
343 Modify();
344 }
345
346
347 //
348 // Delete reference to child object
349 //
350
351 void NetObj::DeleteChild(NetObj *pObject)
352 {
353 DWORD i;
354
355 LockChildList(TRUE);
356 for(i = 0; i < m_dwChildCount; i++)
357 if (m_pChildList[i] == pObject)
358 break;
359
360 if (i == m_dwChildCount) // No such object
361 {
362 UnlockChildList();
363 return;
364 }
365 m_dwChildCount--;
366 if (m_dwChildCount > 0)
367 {
368 memmove(&m_pChildList[i], &m_pChildList[i + 1], sizeof(NetObj *) * (m_dwChildCount - i));
369 m_pChildList = (NetObj **)realloc(m_pChildList, sizeof(NetObj *) * m_dwChildCount);
370 }
371 else
372 {
373 free(m_pChildList);
374 m_pChildList = NULL;
375 }
376 UnlockChildList();
377 Modify();
378 }
379
380
381 //
382 // Delete reference to parent object
383 //
384
385 void NetObj::DeleteParent(NetObj *pObject)
386 {
387 DWORD i;
388
389 LockParentList(TRUE);
390 for(i = 0; i < m_dwParentCount; i++)
391 if (m_pParentList[i] == pObject)
392 break;
393 if (i == m_dwParentCount) // No such object
394 {
395 UnlockParentList();
396 return;
397 }
398 m_dwParentCount--;
399 if (m_dwParentCount > 0)
400 {
401 memmove(&m_pParentList[i], &m_pParentList[i + 1], sizeof(NetObj *) * (m_dwParentCount - i));
402 m_pParentList = (NetObj **)realloc(m_pParentList, sizeof(NetObj *) * m_dwParentCount);
403 }
404 else
405 {
406 free(m_pParentList);
407 m_pParentList = NULL;
408 }
409 UnlockParentList();
410 Modify();
411 }
412
413
414 //
415 // Prepare object for deletion - remove all references, etc.
416 // bIndexLocked should be TRUE if object index by ID is already locked
417 // by current thread
418 //
419
420 void NetObj::Delete(BOOL bIndexLocked)
421 {
422 DWORD i;
423
424 DbgPrintf(4, "Deleting object %d [%s]", m_dwId, m_szName);
425
426 PrepareForDeletion();
427
428 LockData();
429
430 // Remove references to this object from parent objects
431 DbgPrintf(5, "NetObj::Delete(): clearing parent list for object %d", m_dwId);
432 LockParentList(TRUE);
433 for(i = 0; i < m_dwParentCount; i++)
434 {
435 m_pParentList[i]->DeleteChild(this);
436 m_pParentList[i]->CalculateCompoundStatus();
437 }
438 free(m_pParentList);
439 m_pParentList = NULL;
440 m_dwParentCount = 0;
441 UnlockParentList();
442
443 // Delete references to this object from child objects
444 DbgPrintf(5, "NetObj::Delete(): clearing child list for object %d", m_dwId);
445 LockChildList(TRUE);
446 for(i = 0; i < m_dwChildCount; i++)
447 {
448 m_pChildList[i]->DeleteParent(this);
449 if (m_pChildList[i]->IsOrphaned())
450 m_pChildList[i]->Delete(bIndexLocked);
451 }
452 free(m_pChildList);
453 m_pChildList = NULL;
454 m_dwChildCount = 0;
455 UnlockChildList();
456
457 m_bIsDeleted = TRUE;
458 Modify();
459 UnlockData();
460
461 DbgPrintf(5, "NetObj::Delete(): deleting object %d from indexes", m_dwId);
462 NetObjDeleteFromIndexes(this);
463
464 // Notify all other objects about object deletion
465 DbgPrintf(5, "NetObj::Delete(): calling OnObjectDelete(%d)", m_dwId);
466 if (!bIndexLocked)
467 RWLockReadLock(g_rwlockIdIndex, INFINITE);
468 for(i = 0; i < g_dwIdIndexSize; i++)
469 {
470 if (g_pIndexById[i].dwKey != m_dwId)
471 ((NetObj *)g_pIndexById[i].pObject)->OnObjectDelete(m_dwId);
472 }
473 if (!bIndexLocked)
474 RWLockUnlock(g_rwlockIdIndex);
475
476 DbgPrintf(4, "Object %d successfully deleted", m_dwId);
477 }
478
479
480 //
481 // Default handler for object deletion notification
482 //
483
484 void NetObj::OnObjectDelete(DWORD dwObjectId)
485 {
486 }
487
488
489 //
490 // Print childs IDs
491 //
492
493 const char *NetObj::ChildList(char *szBuffer)
494 {
495 DWORD i;
496 char *pBuf = szBuffer;
497
498 *pBuf = 0;
499 LockChildList(FALSE);
500 for(i = 0, pBuf = szBuffer; i < m_dwChildCount; i++)
501 {
502 sprintf(pBuf, "%d ", m_pChildList[i]->Id());
503 while(*pBuf)
504 pBuf++;
505 }
506 UnlockChildList();
507 if (pBuf != szBuffer)
508 *(pBuf - 1) = 0;
509 return szBuffer;
510 }
511
512
513 //
514 // Print parents IDs
515 //
516
517 const char *NetObj::ParentList(char *szBuffer)
518 {
519 DWORD i;
520 char *pBuf = szBuffer;
521
522 *pBuf = 0;
523 LockParentList(FALSE);
524 for(i = 0; i < m_dwParentCount; i++)
525 {
526 sprintf(pBuf, "%d ", m_pParentList[i]->Id());
527 while(*pBuf)
528 pBuf++;
529 }
530 UnlockParentList();
531 if (pBuf != szBuffer)
532 *(pBuf - 1) = 0;
533 return szBuffer;
534 }
535
536
537 //
538 // Calculate status for compound object based on childs' status
539 //
540
541 void NetObj::CalculateCompoundStatus(BOOL bForcedRecalc)
542 {
543 DWORD i;
544 int iMostCriticalAlarm, iMostCriticalStatus, iCount, iStatusAlg;
545 int nSingleThreshold, *pnThresholds, iOldStatus = m_iStatus;
546 int nRating[5], iChildStatus, nThresholds[4];
547
548 if (m_iStatus != STATUS_UNMANAGED)
549 {
550 iMostCriticalAlarm = g_alarmMgr.GetMostCriticalStatusForObject(m_dwId);
551
552 LockData();
553 if (m_iStatusCalcAlg == SA_CALCULATE_DEFAULT)
554 {
555 iStatusAlg = GetDefaultStatusCalculation(&nSingleThreshold, &pnThresholds);
556 }
557 else
558 {
559 iStatusAlg = m_iStatusCalcAlg;
560 nSingleThreshold = m_iStatusSingleThreshold;
561 pnThresholds = m_iStatusThresholds;
562 }
563 if (iStatusAlg == SA_CALCULATE_SINGLE_THRESHOLD)
564 {
565 for(i = 0; i < 4; i++)
566 nThresholds[i] = nSingleThreshold;
567 pnThresholds = nThresholds;
568 }
569
570 switch(iStatusAlg)
571 {
572 case SA_CALCULATE_MOST_CRITICAL:
573 LockChildList(FALSE);
574 for(i = 0, iCount = 0, iMostCriticalStatus = -1; i < m_dwChildCount; i++)
575 {
576 iChildStatus = m_pChildList[i]->PropagatedStatus();
577 if ((iChildStatus < STATUS_UNKNOWN) &&
578 (iChildStatus > iMostCriticalStatus))
579 {
580 iMostCriticalStatus = iChildStatus;
581 iCount++;
582 }
583 }
584 m_iStatus = (iCount > 0) ? iMostCriticalStatus : STATUS_UNKNOWN;
585 UnlockChildList();
586 break;
587 case SA_CALCULATE_SINGLE_THRESHOLD:
588 case SA_CALCULATE_MULTIPLE_THRESHOLDS:
589 // Step 1: calculate severity raitings
590 memset(nRating, 0, sizeof(int) * 5);
591 LockChildList(FALSE);
592 for(i = 0, iCount = 0; i < m_dwChildCount; i++)
593 {
594 iChildStatus = m_pChildList[i]->PropagatedStatus();
595 if (iChildStatus < STATUS_UNKNOWN)
596 {
597 while(iChildStatus >= 0)
598 nRating[iChildStatus--]++;
599 iCount++;
600 }
601 }
602 UnlockChildList();
603
604 // Step 2: check what severity rating is above threshold
605 if (iCount > 0)
606 {
607 for(i = 4; i > 0; i--)
608 if (nRating[i] * 100 / iCount >= pnThresholds[i - 1])
609 break;
610 m_iStatus = i;
611 }
612 else
613 {
614 m_iStatus = STATUS_UNKNOWN;
615 }
616 break;
617 default:
618 m_iStatus = STATUS_UNKNOWN;
619 break;
620 }
621
622 // If alarms exist for object, apply alarm severity to object's status
623 if (iMostCriticalAlarm != STATUS_UNKNOWN)
624 {
625 if (m_iStatus == STATUS_UNKNOWN)
626 {
627 m_iStatus = iMostCriticalAlarm;
628 }
629 else
630 {
631 m_iStatus = max(m_iStatus, iMostCriticalAlarm);
632 }
633 }
634 UnlockData();
635
636 // Cause parent object(s) to recalculate it's status
637 if ((iOldStatus != m_iStatus) || bForcedRecalc)
638 {
639 LockParentList(FALSE);
640 for(i = 0; i < m_dwParentCount; i++)
641 m_pParentList[i]->CalculateCompoundStatus();
642 UnlockParentList();
643 Modify(); /* LOCK? */
644 }
645 }
646 }
647
648
649 //
650 // Load ACL from database
651 //
652
653 BOOL NetObj::LoadACLFromDB(void)
654 {
655 char szQuery[256];
656 DB_RESULT hResult;
657 BOOL bSuccess = FALSE;
658
659 // Load access list
660 sprintf(szQuery, "SELECT user_id,access_rights FROM acl WHERE object_id=%d", m_dwId);
661 hResult = DBSelect(g_hCoreDB, szQuery);
662 if (hResult != NULL)
663 {
664 int i, iNumRows;
665
666 iNumRows = DBGetNumRows(hResult);
667 for(i = 0; i < iNumRows; i++)
668 m_pAccessList->AddElement(DBGetFieldULong(hResult, i, 0),
669 DBGetFieldULong(hResult, i, 1));
670 DBFreeResult(hResult);
671 bSuccess = TRUE;
672 }
673
674 return bSuccess;
675 }
676
677
678 //
679 // Enumeration parameters structure
680 //
681
682 struct SAVE_PARAM
683 {
684 DB_HANDLE hdb;
685 DWORD dwObjectId;
686 };
687
688
689 //
690 // Handler for ACL elements enumeration
691 //
692
693 static void EnumerationHandler(DWORD dwUserId, DWORD dwAccessRights, void *pArg)
694 {
695 char szQuery[256];
696
697 sprintf(szQuery, "INSERT INTO acl (object_id,user_id,access_rights) VALUES (%d,%d,%d)",
698 ((SAVE_PARAM *)pArg)->dwObjectId, dwUserId, dwAccessRights);
699 DBQuery(((SAVE_PARAM *)pArg)->hdb, szQuery);
700 }
701
702
703 //
704 // Save ACL to database
705 //
706
707 BOOL NetObj::SaveACLToDB(DB_HANDLE hdb)
708 {
709 char szQuery[256];
710 BOOL bSuccess = FALSE;
711 SAVE_PARAM sp;
712
713 // Save access list
714 LockACL();
715 sprintf(szQuery, "DELETE FROM acl WHERE object_id=%d", m_dwId);
716 if (DBQuery(hdb, szQuery))
717 {
718 sp.dwObjectId = m_dwId;
719 sp.hdb = hdb;
720 m_pAccessList->EnumerateElements(EnumerationHandler, &sp);
721 bSuccess = TRUE;
722 }
723 UnlockACL();
724 return bSuccess;
725 }
726
727
728 //
729 // Create CSCP message with object's data
730 //
731
732 void NetObj::CreateMessage(CSCPMessage *pMsg)
733 {
734 DWORD i, dwId;
735
736 pMsg->SetVariable(VID_OBJECT_CLASS, (WORD)Type());
737 pMsg->SetVariable(VID_OBJECT_ID, m_dwId);
738 pMsg->SetVariable(VID_OBJECT_NAME, m_szName);
739 pMsg->SetVariable(VID_OBJECT_STATUS, (WORD)m_iStatus);
740 pMsg->SetVariable(VID_IP_ADDRESS, m_dwIpAddr);
741 pMsg->SetVariable(VID_PARENT_CNT, m_dwParentCount);
742 pMsg->SetVariable(VID_CHILD_CNT, m_dwChildCount);
743 pMsg->SetVariable(VID_IS_DELETED, (WORD)m_bIsDeleted);
744 pMsg->SetVariable(VID_IS_SYSTEM, (WORD)m_bIsSystem);
745 for(i = 0, dwId = VID_PARENT_ID_BASE; i < m_dwParentCount; i++, dwId++)
746 pMsg->SetVariable(dwId, m_pParentList[i]->Id());
747 for(i = 0, dwId = VID_CHILD_ID_BASE; i < m_dwChildCount; i++, dwId++)
748 pMsg->SetVariable(dwId, m_pChildList[i]->Id());
749 pMsg->SetVariable(VID_INHERIT_RIGHTS, (WORD)m_bInheritAccessRights);
750 pMsg->SetVariable(VID_STATUS_CALCULATION_ALG, (WORD)m_iStatusCalcAlg);
751 pMsg->SetVariable(VID_STATUS_PROPAGATION_ALG, (WORD)m_iStatusPropAlg);
752 pMsg->SetVariable(VID_FIXED_STATUS, (WORD)m_iFixedStatus);
753 pMsg->SetVariable(VID_STATUS_SHIFT, (WORD)m_iStatusShift);
754 pMsg->SetVariable(VID_STATUS_TRANSLATION_1, (WORD)m_iStatusTranslation[0]);
755 pMsg->SetVariable(VID_STATUS_TRANSLATION_2, (WORD)m_iStatusTranslation[1]);
756 pMsg->SetVariable(VID_STATUS_TRANSLATION_3, (WORD)m_iStatusTranslation[2]);
757 pMsg->SetVariable(VID_STATUS_TRANSLATION_4, (WORD)m_iStatusTranslation[3]);
758 pMsg->SetVariable(VID_STATUS_SINGLE_THRESHOLD, (WORD)m_iStatusSingleThreshold);
759 pMsg->SetVariable(VID_STATUS_THRESHOLD_1, (WORD)m_iStatusThresholds[0]);
760 pMsg->SetVariable(VID_STATUS_THRESHOLD_2, (WORD)m_iStatusThresholds[1]);
761 pMsg->SetVariable(VID_STATUS_THRESHOLD_3, (WORD)m_iStatusThresholds[2]);
762 pMsg->SetVariable(VID_STATUS_THRESHOLD_4, (WORD)m_iStatusThresholds[3]);
763 pMsg->SetVariable(VID_COMMENTS, CHECK_NULL_EX(m_pszComments));
764 pMsg->SetVariable(VID_NUM_TRUSTED_NODES, m_dwNumTrustedNodes);
765 if (m_dwNumTrustedNodes > 0)
766 pMsg->SetVariableToInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
767
768 pMsg->SetVariable(VID_NUM_CUSTOM_ATTRIBUTES, m_customAttributes.Size());
769 for(i = 0, dwId = VID_CUSTOM_ATTRIBUTES_BASE; i < m_customAttributes.Size(); i++)
770 {
771 pMsg->SetVariable(dwId++, m_customAttributes.GetKeyByIndex(i));
772 pMsg->SetVariable(dwId++, m_customAttributes.GetValueByIndex(i));
773 }
774
775 m_pAccessList->CreateMessage(pMsg);
776 }
777
778
779 //
780 // Handler for EnumerateSessions()
781 //
782
783 static void BroadcastObjectChange(ClientSession *pSession, void *pArg)
784 {
785 if (pSession->IsAuthenticated())
786 pSession->OnObjectChange((NetObj *)pArg);
787 }
788
789
790 //
791 // Mark object as modified and put on client's notification queue
792 // We assume that object is locked at the time of function call
793 //
794
795 void NetObj::Modify(void)
796 {
797 if (g_bModificationsLocked)
798 return;
799
800 m_bIsModified = TRUE;
801 m_dwTimeStamp = (DWORD)time(NULL);
802
803 // Send event to all connected clients
804 if (!m_bIsHidden)
805 EnumerateClientSessions(BroadcastObjectChange, this);
806 }
807
808
809 //
810 // Modify object from message
811 //
812
813 DWORD NetObj::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
814 {
815 BOOL bRecalcStatus = FALSE;
816
817 if (!bAlreadyLocked)
818 LockData();
819
820 // Change object's name
821 if (pRequest->IsVariableExist(VID_OBJECT_NAME))
822 pRequest->GetVariableStr(VID_OBJECT_NAME, m_szName, MAX_OBJECT_NAME);
823
824 // Change object's status calculation/propagation algorithms
825 if (pRequest->IsVariableExist(VID_STATUS_CALCULATION_ALG))
826 {
827 m_iStatusCalcAlg = (int)pRequest->GetVariableShort(VID_STATUS_CALCULATION_ALG);
828 m_iStatusPropAlg = (int)pRequest->GetVariableShort(VID_STATUS_PROPAGATION_ALG);
829 m_iFixedStatus = (int)pRequest->GetVariableShort(VID_FIXED_STATUS);
830 m_iStatusShift = pRequest->GetVariableShortAsInt32(VID_STATUS_SHIFT);
831 m_iStatusTranslation[0] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_1);
832 m_iStatusTranslation[1] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_2);
833 m_iStatusTranslation[2] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_3);
834 m_iStatusTranslation[3] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_4);
835 m_iStatusSingleThreshold = (int)pRequest->GetVariableShort(VID_STATUS_SINGLE_THRESHOLD);
836 m_iStatusThresholds[0] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_1);
837 m_iStatusThresholds[1] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_2);
838 m_iStatusThresholds[2] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_3);
839 m_iStatusThresholds[3] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_4);
840 bRecalcStatus = TRUE;
841 }
842
843 // Change object's ACL
844 if (pRequest->IsVariableExist(VID_ACL_SIZE))
845 {
846 DWORD i, dwNumElements;
847
848 LockACL();
849 dwNumElements = pRequest->GetVariableLong(VID_ACL_SIZE);
850 m_bInheritAccessRights = pRequest->GetVariableShort(VID_INHERIT_RIGHTS);
851 m_pAccessList->DeleteAll();
852 for(i = 0; i < dwNumElements; i++)
853 m_pAccessList->AddElement(pRequest->GetVariableLong(VID_ACL_USER_BASE + i),
854 pRequest->GetVariableLong(VID_ACL_RIGHTS_BASE +i));
855 UnlockACL();
856 }
857
858 // Change trusted nodes list
859 if (pRequest->IsVariableExist(VID_NUM_TRUSTED_NODES))
860 {
861 m_dwNumTrustedNodes = pRequest->GetVariableLong(VID_NUM_TRUSTED_NODES);
862 m_pdwTrustedNodes = (DWORD *)realloc(m_pdwTrustedNodes, sizeof(DWORD) * m_dwNumTrustedNodes);
863 pRequest->GetVariableInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
864 }
865
866 // Change custom attributes
867 if (pRequest->IsVariableExist(VID_NUM_CUSTOM_ATTRIBUTES))
868 {
869 DWORD i, dwId, dwNumElements;
870 TCHAR *name, *value;
871
872 dwNumElements = pRequest->GetVariableLong(VID_NUM_CUSTOM_ATTRIBUTES);
873 m_customAttributes.Clear();
874 for(i = 0, dwId = VID_CUSTOM_ATTRIBUTES_BASE; i < dwNumElements; i++)
875 {
876 name = pRequest->GetVariableStr(dwId++);
877 value = pRequest->GetVariableStr(dwId++);
878 if ((name != NULL) && (value != NULL))
879 m_customAttributes.SetPreallocated(name, value);
880 }
881 }
882
883 Modify();
884 UnlockData();
885
886 if (bRecalcStatus)
887 CalculateCompoundStatus(TRUE);
888
889 return RCC_SUCCESS;
890 }
891
892
893 //
894 // Get rights to object for specific user
895 //
896
897 DWORD NetObj::GetUserRights(DWORD dwUserId)
898 {
899 DWORD dwRights;
900
901 // Admin always has all rights to any object
902 if (dwUserId == 0)
903 return 0xFFFFFFFF;
904
905 // Non-admin users have no rights to system objects
906 if (m_bIsSystem)
907 return 0;
908
909 LockACL();
910
911 // Check if have direct right assignment
912 if (!m_pAccessList->GetUserRights(dwUserId, &dwRights))
913 {
914 // We don't. If this object inherit rights from parents, get them
915 if (m_bInheritAccessRights)
916 {
917 DWORD i;
918
919 LockParentList(FALSE);
920 for(i = 0, dwRights = 0; i < m_dwParentCount; i++)
921 dwRights |= m_pParentList[i]->GetUserRights(dwUserId);
922 UnlockParentList();
923 }
924 }
925
926 UnlockACL();
927 return dwRights;
928 }
929
930
931 //
932 // Check if given user has specific rights on this object
933 //
934
935 BOOL NetObj::CheckAccessRights(DWORD dwUserId, DWORD dwRequiredRights)
936 {
937 DWORD dwRights = GetUserRights(dwUserId);
938 return (dwRights & dwRequiredRights) == dwRequiredRights;
939 }
940
941
942 //
943 // Drop all user privileges on current object
944 //
945
946 void NetObj::DropUserAccess(DWORD dwUserId)
947 {
948 LockACL();
949 if (m_pAccessList->DeleteElement(dwUserId))
950 Modify();
951 UnlockACL();
952 }
953
954
955 //
956 // Set object's management status
957 //
958
959 void NetObj::SetMgmtStatus(BOOL bIsManaged)
960 {
961 DWORD i;
962 int iOldStatus;
963
964 LockData();
965
966 if ((bIsManaged && (m_iStatus != STATUS_UNMANAGED)) ||
967 ((!bIsManaged) && (m_iStatus == STATUS_UNMANAGED)))
968 {
969 UnlockData();
970 return; // Status is already correct
971 }
972
973 iOldStatus = m_iStatus;
974 m_iStatus = (bIsManaged ? STATUS_UNKNOWN : STATUS_UNMANAGED);
975
976 // Generate event if current object is a node
977 if (Type() == OBJECT_NODE)
978 PostEvent(bIsManaged ? EVENT_NODE_UNKNOWN : EVENT_NODE_UNMANAGED, m_dwId, "d", iOldStatus);
979
980 Modify();
981 UnlockData();
982
983 // Change status for child objects also
984 LockChildList(FALSE);
985 for(i = 0; i < m_dwChildCount; i++)
986 m_pChildList[i]->SetMgmtStatus(bIsManaged);
987 UnlockChildList();
988
989 // Cause parent object(s) to recalculate it's status
990 LockParentList(FALSE);
991 for(i = 0; i < m_dwParentCount; i++)
992 m_pParentList[i]->CalculateCompoundStatus();
993 UnlockParentList();
994 }
995
996
997 //
998 // Check if given object is an our child (possibly indirect, i.e child of child)
999 //
1000
1001 BOOL NetObj::IsChild(DWORD dwObjectId)
1002 {
1003 DWORD i;
1004 BOOL bResult = FALSE;
1005
1006 // Check for our own ID (object ID should never change, so we may not lock object's data)
1007 if (m_dwId == dwObjectId)
1008 bResult = TRUE;
1009
1010 // First, walk through our own child list
1011 if (!bResult)
1012 {
1013 LockChildList(FALSE);
1014 for(i = 0; i < m_dwChildCount; i++)
1015 if (m_pChildList[i]->Id() == dwObjectId)
1016 {
1017 bResult = TRUE;
1018 break;
1019 }
1020 UnlockChildList();
1021 }
1022
1023 // If given object is not in child list, check if it is indirect child
1024 if (!bResult)
1025 {
1026 LockChildList(FALSE);
1027 for(i = 0; i < m_dwChildCount; i++)
1028 if (m_pChildList[i]->IsChild(dwObjectId))
1029 {
1030 bResult = TRUE;
1031 break;
1032 }
1033 UnlockChildList();
1034 }
1035
1036 return bResult;
1037 }
1038
1039
1040 //
1041 // Send message to client, who requests poll, if any
1042 // This method is used by Node and Interface class objects
1043 //
1044
1045 void NetObj::SendPollerMsg(DWORD dwRqId, const TCHAR *pszFormat, ...)
1046 {
1047 if (m_pPollRequestor != NULL)
1048 {
1049 va_list args;
1050 TCHAR szBuffer[1024];
1051
1052 va_start(args, pszFormat);
1053 _vsntprintf(szBuffer, 1024, pszFormat, args);
1054 va_end(args);
1055 m_pPollRequestor->SendPollerMsg(dwRqId, szBuffer);
1056 }
1057 }
1058
1059
1060 //
1061 // Add child node objects (direct and indirect childs) to list
1062 //
1063
1064 void NetObj::AddChildNodesToList(DWORD *pdwNumNodes, Node ***pppNodeList, DWORD dwUserId)
1065 {
1066 DWORD i, j;
1067
1068 LockChildList(FALSE);
1069
1070 // Walk through our own child list
1071 for(i = 0; i < m_dwChildCount; i++)
1072 {
1073 if (m_pChildList[i]->Type() == OBJECT_NODE)
1074 {
1075 // Check if this node already in the list
1076 for(j = 0; j < *pdwNumNodes; j++)
1077 if ((*pppNodeList)[j]->Id() == m_pChildList[i]->Id())
1078 break;
1079 if (j == *pdwNumNodes)
1080 {
1081 m_pChildList[i]->IncRefCount();
1082 *pppNodeList = (Node **)realloc(*pppNodeList, sizeof(Node *) * (*pdwNumNodes + 1));
1083 (*pppNodeList)[*pdwNumNodes] = (Node *)m_pChildList[i];
1084 (*pdwNumNodes)++;
1085 }
1086 }
1087 else
1088 {
1089 if (m_pChildList[i]->CheckAccessRights(dwUserId, OBJECT_ACCESS_READ))
1090 m_pChildList[i]->AddChildNodesToList(pdwNumNodes, pppNodeList, dwUserId);
1091 }
1092 }
1093
1094 UnlockChildList();
1095 }
1096
1097
1098 //
1099 // Hide object and all its childs
1100 //
1101
1102 void NetObj::Hide(void)
1103 {
1104 DWORD i;
1105
1106 LockData();
1107 LockChildList(FALSE);
1108
1109 for(i = 0; i < m_dwChildCount; i++)
1110 m_pChildList[i]->Hide();
1111 m_bIsHidden = TRUE;
1112
1113 UnlockChildList();
1114 UnlockData();
1115 }
1116
1117
1118 //
1119 // Unhide object and all its childs
1120 //
1121
1122 void NetObj::Unhide(void)
1123 {
1124 DWORD i;
1125
1126 LockData();
1127
1128 m_bIsHidden = FALSE;
1129 EnumerateClientSessions(BroadcastObjectChange, this);
1130
1131 LockChildList(FALSE);
1132 for(i = 0; i < m_dwChildCount; i++)
1133 m_pChildList[i]->Unhide();
1134
1135 UnlockChildList();
1136 UnlockData();
1137 }
1138
1139
1140 //
1141 // Return status propagated to parent
1142 //
1143
1144 int NetObj::PropagatedStatus(void)
1145 {
1146 int iStatus;
1147
1148 if (m_iStatusPropAlg == SA_PROPAGATE_DEFAULT)
1149 {
1150 iStatus = DefaultPropagatedStatus(m_iStatus);
1151 }
1152 else
1153 {
1154 switch(m_iStatusPropAlg)
1155 {
1156 case SA_PROPAGATE_UNCHANGED:
1157 iStatus = m_iStatus;
1158 break;
1159 case SA_PROPAGATE_FIXED:
1160 iStatus = ((m_iStatus > STATUS_NORMAL) && (m_iStatus < STATUS_UNKNOWN)) ? m_iFixedStatus : m_iStatus;
1161 break;
1162 case SA_PROPAGATE_RELATIVE:
1163 if ((m_iStatus > STATUS_NORMAL) && (m_iStatus < STATUS_UNKNOWN))
1164 {
1165 iStatus = m_iStatus + m_iStatusShift;
1166 if (iStatus < 0)
1167 iStatus = 0;
1168 if (iStatus > STATUS_CRITICAL)
1169 iStatus = STATUS_CRITICAL;
1170 }
1171 else
1172 {
1173 iStatus = m_iStatus;
1174 }
1175 break;
1176 case SA_PROPAGATE_TRANSLATED:
1177 if ((m_iStatus > STATUS_NORMAL) && (m_iStatus < STATUS_UNKNOWN))
1178 {
1179 iStatus = m_iStatusTranslation[m_iStatus - 1];
1180 }
1181 else
1182 {
1183 iStatus = m_iStatus;
1184 }
1185 break;
1186 default:
1187 iStatus = STATUS_UNKNOWN;
1188 break;
1189 }
1190 }
1191 return iStatus;
1192 }
1193
1194
1195 //
1196 // Prepare object for deletion. Function should return only
1197 // when object deletion is safe
1198 //
1199
1200 void NetObj::PrepareForDeletion(void)
1201 {
1202 }
1203
1204
1205 //
1206 // Set object's comments.
1207 // NOTE: pszText should be dynamically allocated or NULL
1208 //
1209
1210 void NetObj::SetComments(TCHAR *pszText)
1211 {
1212 LockData();
1213 safe_free(m_pszComments);
1214 m_pszComments = pszText;
1215 Modify();
1216 UnlockData();
1217 }
1218
1219
1220 //
1221 // Get object's comments
1222 //
1223
1224 void NetObj::CommentsToMessage(CSCPMessage *pMsg)
1225 {
1226 LockData();
1227 pMsg->SetVariable(VID_COMMENTS, CHECK_NULL_EX(m_pszComments));
1228 UnlockData();
1229 }
1230
1231
1232 //
1233 // Load trusted nodes list from database
1234 //
1235
1236 BOOL NetObj::LoadTrustedNodes(void)
1237 {
1238 DB_RESULT hResult;
1239 TCHAR query[256];
1240 int i, count;
1241
1242 _sntprintf(query, 256, _T("SELECT target_node_id FROM trusted_nodes WHERE source_object_id=%d"), m_dwId);
1243 hResult = DBSelect(g_hCoreDB, query);
1244 if (hResult != NULL)
1245 {
1246 count = DBGetNumRows(hResult);
1247 if (count > 0)
1248 {
1249 m_dwNumTrustedNodes = count;
1250 m_pdwTrustedNodes = (DWORD *)malloc(sizeof(DWORD) * count);
1251 for(i = 0; i < count; i++)
1252 {
1253 m_pdwTrustedNodes[i] = DBGetFieldULong(hResult, i, 0);
1254 }
1255 }
1256 DBFreeResult(hResult);
1257 }
1258 return (hResult != NULL);
1259 }
1260
1261
1262 //
1263 // Save list of trusted nodes to database
1264 //
1265
1266 BOOL NetObj::SaveTrustedNodes(DB_HANDLE hdb)
1267 {
1268 TCHAR query[256];
1269 DWORD i;
1270 BOOL rc = FALSE;
1271
1272 _sntprintf(query, 256, _T("DELETE FROM trusted_nodes WHERE source_object_id=%d"), m_dwId);
1273 if (DBQuery(hdb, query))
1274 {
1275 for(i = 0; i < m_dwNumTrustedNodes; i++)
1276 {
1277 _sntprintf(query, 256, _T("INSERT INTO trusted_nodes (source_object_id,target_node_id) VALUES (%d,%d)"),
1278 m_dwId, m_pdwTrustedNodes[i]);
1279 if (!DBQuery(hdb, query))
1280 break;
1281 }
1282 if (i == m_dwNumTrustedNodes)
1283 rc = TRUE;
1284 }
1285 return rc;
1286 }
1287
1288
1289 //
1290 // Check if given node is in trust list
1291 // Will always return TRUE if system parameter CheckTrustedNodes set to 0
1292 //
1293
1294 BOOL NetObj::IsTrustedNode(DWORD id)
1295 {
1296 BOOL rc;
1297
1298 if (g_dwFlags & AF_CHECK_TRUSTED_NODES)
1299 {
1300 DWORD i;
1301
1302 LockData();
1303 for(i = 0, rc = FALSE; i < m_dwNumTrustedNodes; i++)
1304 {
1305 if (m_pdwTrustedNodes[i] == id)
1306 {
1307 rc = TRUE;
1308 break;
1309 }
1310 }
1311 UnlockData();
1312 }
1313 else
1314 {
1315 rc = TRUE;
1316 }
1317 return rc;
1318 }