f17aae16171c31ff7fb31926b993959d65dbf7a4
[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 ** $module: netobj.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25
26 //
27 // NetObj class constructor
28 //
29
30 NetObj::NetObj()
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_bIsModified = FALSE;
41 m_bIsDeleted = FALSE;
42 m_bIsHidden = FALSE;
43 m_dwIpAddr = 0;
44 m_dwChildCount = 0;
45 m_pChildList = NULL;
46 m_dwParentCount = 0;
47 m_pParentList = NULL;
48 m_pAccessList = new AccessList;
49 m_bInheritAccessRights = TRUE;
50 m_dwImageId = IMG_DEFAULT; // Default image
51 m_pPollRequestor = NULL;
52 m_iStatusCalcAlg = SA_CALCULATE_DEFAULT;
53 m_iStatusPropAlg = SA_PROPAGATE_DEFAULT;
54 }
55
56
57 //
58 // NetObj class destructor
59 //
60
61 NetObj::~NetObj()
62 {
63 MutexDestroy(m_mutexData);
64 MutexDestroy(m_mutexRefCount);
65 MutexDestroy(m_mutexACL);
66 RWLockDestroy(m_rwlockParentList);
67 RWLockDestroy(m_rwlockChildList);
68 if (m_pChildList != NULL)
69 free(m_pChildList);
70 if (m_pParentList != NULL)
71 free(m_pParentList);
72 delete m_pAccessList;
73 }
74
75
76 //
77 // Create object from database data
78 //
79
80 BOOL NetObj::CreateFromDB(DWORD dwId)
81 {
82 return FALSE; // Abstract objects cannot be loaded from database
83 }
84
85
86 //
87 // Save object to database
88 //
89
90 BOOL NetObj::SaveToDB(DB_HANDLE hdb)
91 {
92 return FALSE; // Abstract objects cannot be saved to database
93 }
94
95
96 //
97 // Delete object from database
98 //
99
100 BOOL NetObj::DeleteFromDB(void)
101 {
102 char szQuery[256];
103
104 // Delete ACL
105 sprintf(szQuery, "DELETE FROM acl WHERE object_id=%d", m_dwId);
106 QueueSQLRequest(szQuery);
107 sprintf(szQuery, "DELETE FROM object_properties WHERE object_id=%d", m_dwId);
108 QueueSQLRequest(szQuery);
109 return TRUE;
110 }
111
112
113 //
114 // Load common object properties from database
115 //
116
117 BOOL NetObj::LoadCommonProperties(void)
118 {
119 DB_RESULT hResult;
120 TCHAR szQuery[256];
121 BOOL bResult = FALSE;
122
123 // Load access options
124 _sntprintf(szQuery, 256, _T("SELECT name,status,is_deleted,image_id,"
125 "inherit_access_rights,last_modified,status_calc_alg,"
126 "status_prop_alg,status_fixed_val,status_shift,"
127 "status_translation,status_single_threshold,"
128 "status_thresholds FROM object_properties "
129 "WHERE object_id=%ld"), m_dwId);
130 hResult = DBSelect(g_hCoreDB, szQuery);
131 if (hResult != NULL)
132 {
133 if (DBGetNumRows(hResult) > 0)
134 {
135 nx_strncpy(m_szName, DBGetField(hResult, 0, 0), MAX_OBJECT_NAME);
136 m_iStatus = DBGetFieldLong(hResult, 0, 1);
137 m_bIsDeleted = DBGetFieldLong(hResult, 0, 2) ? TRUE : FALSE;
138 m_dwImageId = DBGetFieldULong(hResult, 0, 3);
139 m_bInheritAccessRights = DBGetFieldLong(hResult, 0, 4) ? TRUE : FALSE;
140 m_dwTimeStamp = DBGetFieldULong(hResult, 0, 5);
141 m_iStatusCalcAlg = DBGetFieldLong(hResult, 0, 6);
142 m_iStatusPropAlg = DBGetFieldLong(hResult, 0, 7);
143 m_iFixedStatus = DBGetFieldLong(hResult, 0, 8);
144 m_iStatusShift = DBGetFieldLong(hResult, 0, 9);
145 DBGetFieldByteArray(hResult, 0, 10, m_iStatusTranslation, 4, STATUS_WARNING);
146 m_iStatusSingleThreshold = DBGetFieldLong(hResult, 0, 11);
147 DBGetFieldByteArray(hResult, 0, 12, m_iStatusThresholds, 4, 50);
148 bResult = TRUE;
149 }
150 DBFreeResult(hResult);
151 }
152 return bResult;
153 }
154
155
156 //
157 // Save common object properties to database
158 //
159
160 BOOL NetObj::SaveCommonProperties(DB_HANDLE hdb)
161 {
162 TCHAR szQuery[512], szTranslation[16], szThresholds[16];
163 DB_RESULT hResult;
164 BOOL bResult = FALSE;
165 int i, j;
166
167 // Save access options
168 _sntprintf(szQuery, 512, _T("SELECT object_id FROM object_properties WHERE object_id=%ld"), m_dwId);
169 hResult = DBSelect(hdb, szQuery);
170 if (hResult != NULL)
171 {
172 for(i = 0, j = 0; i < 4; i++, j += 2)
173 {
174 _stprintf(&szTranslation[j], _T("%02X"), (char)m_iStatusTranslation[i]);
175 _stprintf(&szThresholds[j], _T("%02X"), (char)m_iStatusThresholds[i]);
176 }
177 if (DBGetNumRows(hResult) > 0)
178 _sntprintf(szQuery, 512,
179 _T("UPDATE object_properties SET name='%s',status=%d,"
180 "is_deleted=%d,image_id=%ld,inherit_access_rights=%d,"
181 "last_modified=%ld,status_calc_alg=%d,status_prop_alg=%d,"
182 "status_fixed_val=%d,status_shift=%d,status_translation='%s',"
183 "status_single_threshold=%d,status_thresholds='%s' WHERE object_id=%ld"),
184 m_szName, m_iStatus, m_bIsDeleted, m_dwImageId,
185 m_bInheritAccessRights, m_dwTimeStamp, m_iStatusCalcAlg,
186 m_iStatusPropAlg, m_iFixedStatus, m_iStatusShift,
187 szTranslation, m_iStatusSingleThreshold, szThresholds, m_dwId);
188 else
189 _sntprintf(szQuery, 512,
190 _T("INSERT INTO object_properties (object_id,name,status,is_deleted,"
191 "image_id,inherit_access_rights,last_modified,status_calc_alg,"
192 "status_prop_alg,status_fixed_val,status_shift,status_translation,"
193 "status_single_threshold,status_thresholds) "
194 "VALUES (%ld,'%s',%d,%d,%ld,%d,%ld,%d,%d,%d,%d,'%s',%d,'%s')"),
195 m_dwId, m_szName, m_iStatus, m_bIsDeleted, m_dwImageId,
196 m_bInheritAccessRights, m_dwTimeStamp, m_iStatusCalcAlg,
197 m_iStatusPropAlg, m_iFixedStatus, m_iStatusShift,
198 szTranslation, m_iStatusSingleThreshold, szThresholds);
199 DBFreeResult(hResult);
200 bResult = DBQuery(hdb, szQuery);
201 }
202 return bResult;
203 }
204
205
206 //
207 // Add reference to the new child object
208 //
209
210 void NetObj::AddChild(NetObj *pObject)
211 {
212 DWORD i;
213
214 LockChildList(TRUE);
215 for(i = 0; i < m_dwChildCount; i++)
216 if (m_pChildList[i] == pObject)
217 {
218 UnlockChildList();
219 return; // Already in the child list
220 }
221 m_pChildList = (NetObj **)realloc(m_pChildList, sizeof(NetObj *) * (m_dwChildCount + 1));
222 m_pChildList[m_dwChildCount++] = pObject;
223 UnlockChildList();
224 Modify();
225 }
226
227
228 //
229 // Add reference to parent object
230 //
231
232 void NetObj::AddParent(NetObj *pObject)
233 {
234 DWORD i;
235
236 LockParentList(TRUE);
237 for(i = 0; i < m_dwParentCount; i++)
238 if (m_pParentList[i] == pObject)
239 {
240 UnlockParentList();
241 return; // Already in the parents list
242 }
243 m_pParentList = (NetObj **)realloc(m_pParentList, sizeof(NetObj *) * (m_dwParentCount + 1));
244 m_pParentList[m_dwParentCount++] = pObject;
245 UnlockParentList();
246 Modify();
247 }
248
249
250 //
251 // Delete reference to child object
252 //
253
254 void NetObj::DeleteChild(NetObj *pObject)
255 {
256 DWORD i;
257
258 LockChildList(TRUE);
259 for(i = 0; i < m_dwChildCount; i++)
260 if (m_pChildList[i] == pObject)
261 break;
262
263 if (i == m_dwChildCount) // No such object
264 {
265 UnlockChildList();
266 return;
267 }
268 m_dwChildCount--;
269 if (m_dwChildCount > 0)
270 {
271 memmove(&m_pChildList[i], &m_pChildList[i + 1], sizeof(NetObj *) * (m_dwChildCount - i));
272 m_pChildList = (NetObj **)realloc(m_pChildList, sizeof(NetObj *) * m_dwChildCount);
273 }
274 else
275 {
276 free(m_pChildList);
277 m_pChildList = NULL;
278 }
279 UnlockChildList();
280 Modify();
281 }
282
283
284 //
285 // Delete reference to parent object
286 //
287
288 void NetObj::DeleteParent(NetObj *pObject)
289 {
290 DWORD i;
291
292 LockParentList(TRUE);
293 for(i = 0; i < m_dwParentCount; i++)
294 if (m_pParentList[i] == pObject)
295 break;
296 if (i == m_dwParentCount) // No such object
297 {
298 UnlockParentList();
299 return;
300 }
301 m_dwParentCount--;
302 if (m_dwParentCount > 0)
303 {
304 memmove(&m_pParentList[i], &m_pParentList[i + 1], sizeof(NetObj *) * (m_dwParentCount - i));
305 m_pParentList = (NetObj **)realloc(m_pParentList, sizeof(NetObj *) * m_dwParentCount);
306 }
307 else
308 {
309 free(m_pParentList);
310 m_pParentList = NULL;
311 }
312 UnlockParentList();
313 Modify();
314 }
315
316
317 //
318 // Prepare object for deletion - remove all references, etc.
319 // bIndexLocked should be TRUE if object index by ID is already locked
320 // by current thread
321 //
322
323 void NetObj::Delete(BOOL bIndexLocked)
324 {
325 DWORD i;
326
327 DbgPrintf(AF_DEBUG_OBJECTS, "Deleting object %d [%s]", m_dwId, m_szName);
328
329 LockData();
330
331 // Remove references to this object from parent objects
332 DbgPrintf(AF_DEBUG_OBJECTS, "NetObj::Delete(): clearing parent list for object %d", m_dwId);
333 LockParentList(TRUE);
334 for(i = 0; i < m_dwParentCount; i++)
335 {
336 m_pParentList[i]->DeleteChild(this);
337 m_pParentList[i]->CalculateCompoundStatus();
338 }
339 free(m_pParentList);
340 m_pParentList = NULL;
341 m_dwParentCount = 0;
342 UnlockParentList();
343
344 // Delete references to this object from child objects
345 DbgPrintf(AF_DEBUG_OBJECTS, "NetObj::Delete(): clearing child list for object %d", m_dwId);
346 LockChildList(TRUE);
347 for(i = 0; i < m_dwChildCount; i++)
348 {
349 m_pChildList[i]->DeleteParent(this);
350 if (m_pChildList[i]->IsOrphaned())
351 m_pChildList[i]->Delete(bIndexLocked);
352 }
353 free(m_pChildList);
354 m_pChildList = NULL;
355 m_dwChildCount = 0;
356 UnlockChildList();
357
358 m_bIsDeleted = TRUE;
359 Modify();
360 UnlockData();
361
362 DbgPrintf(AF_DEBUG_OBJECTS, "NetObj::Delete(): deleting object %d from indexes", m_dwId);
363 NetObjDeleteFromIndexes(this);
364
365 // Notify all other objects about object deletion
366 DbgPrintf(AF_DEBUG_OBJECTS, "NetObj::Delete(): calling OnObjectDelete(%d)", m_dwId);
367 if (!bIndexLocked)
368 RWLockReadLock(g_rwlockIdIndex, INFINITE);
369 for(i = 0; i < g_dwIdIndexSize; i++)
370 {
371 if (g_pIndexById[i].dwKey != m_dwId)
372 g_pIndexById[i].pObject->OnObjectDelete(m_dwId);
373 }
374 if (!bIndexLocked)
375 RWLockUnlock(g_rwlockIdIndex);
376
377 DbgPrintf(AF_DEBUG_OBJECTS, "Object %d successfully deleted", m_dwId);
378 }
379
380
381 //
382 // Default handler for object deletion notification
383 //
384
385 void NetObj::OnObjectDelete(DWORD dwObjectId)
386 {
387 }
388
389
390 //
391 // Print childs IDs
392 //
393
394 const char *NetObj::ChildList(char *szBuffer)
395 {
396 DWORD i;
397 char *pBuf = szBuffer;
398
399 *pBuf = 0;
400 LockChildList(FALSE);
401 for(i = 0, pBuf = szBuffer; i < m_dwChildCount; i++)
402 {
403 sprintf(pBuf, "%d ", m_pChildList[i]->Id());
404 while(*pBuf)
405 pBuf++;
406 }
407 UnlockChildList();
408 if (pBuf != szBuffer)
409 *(pBuf - 1) = 0;
410 return szBuffer;
411 }
412
413
414 //
415 // Print parents IDs
416 //
417
418 const char *NetObj::ParentList(char *szBuffer)
419 {
420 DWORD i;
421 char *pBuf = szBuffer;
422
423 *pBuf = 0;
424 LockParentList(FALSE);
425 for(i = 0; i < m_dwParentCount; i++)
426 {
427 sprintf(pBuf, "%d ", m_pParentList[i]->Id());
428 while(*pBuf)
429 pBuf++;
430 }
431 UnlockParentList();
432 if (pBuf != szBuffer)
433 *(pBuf - 1) = 0;
434 return szBuffer;
435 }
436
437
438 //
439 // Calculate status for compound object based on childs' status
440 //
441
442 void NetObj::CalculateCompoundStatus(void)
443 {
444 DWORD i;
445 int iMostCriticalAlarm, iMostCriticalStatus, iCount, iStatusAlg;
446 int nSingleThreshold, *pnThresholds, iOldStatus = m_iStatus;
447 int nRating[5], iChildStatus, nThresholds[4];
448
449 if (m_iStatus != STATUS_UNMANAGED)
450 {
451 iMostCriticalAlarm = g_alarmMgr.GetMostCriticalStatusForObject(m_dwId);
452
453 LockData();
454 if (m_iStatusCalcAlg == SA_CALCULATE_DEFAULT)
455 {
456 iStatusAlg = GetDefaultStatusCalculation(&nSingleThreshold, &pnThresholds);
457 }
458 else
459 {
460 iStatusAlg = m_iStatusCalcAlg;
461 nSingleThreshold = m_iStatusSingleThreshold;
462 pnThresholds = m_iStatusThresholds;
463 }
464 if (iStatusAlg == SA_CALCULATE_SINGLE_THRESHOLD)
465 {
466 for(i = 0; i < 4; i++)
467 nThresholds[i] = nSingleThreshold;
468 pnThresholds = nThresholds;
469 }
470
471 switch(iStatusAlg)
472 {
473 case SA_CALCULATE_MOST_CRITICAL:
474 LockChildList(FALSE);
475 for(i = 0, iCount = 0, iMostCriticalStatus = -1; i < m_dwChildCount; i++)
476 {
477 iChildStatus = m_pChildList[i]->PropagatedStatus();
478 if ((iChildStatus < STATUS_UNKNOWN) &&
479 (iChildStatus > iMostCriticalStatus))
480 {
481 iMostCriticalStatus = iChildStatus;
482 iCount++;
483 }
484 }
485 m_iStatus = (iCount > 0) ? iMostCriticalStatus : STATUS_UNKNOWN;
486 UnlockChildList();
487 break;
488 case SA_CALCULATE_SINGLE_THRESHOLD:
489 case SA_CALCULATE_MULTIPLE_THRESHOLDS:
490 // Step 1: calculate severity raitings
491 memset(nRating, 0, sizeof(int) * 5);
492 LockChildList(FALSE);
493 for(i = 0, iCount = 0; i < m_dwChildCount; i++)
494 {
495 iChildStatus = m_pChildList[i]->PropagatedStatus();
496 if (iChildStatus < STATUS_UNKNOWN)
497 {
498 while(iChildStatus >= 0)
499 nRating[iChildStatus--]++;
500 iCount++;
501 }
502 }
503 UnlockChildList();
504
505 // Step 2: check what severity rating is above threshold
506 if (iCount > 0)
507 {
508 for(i = 4; i > 0; i--)
509 if (nRating[i] * 100 / iCount >= pnThresholds[i - 1])
510 break;
511 m_iStatus = i;
512 }
513 else
514 {
515 m_iStatus = STATUS_UNKNOWN;
516 }
517 break;
518 default:
519 m_iStatus = STATUS_UNKNOWN;
520 break;
521 }
522
523 // If alarms exist for object, apply alarm severity to object's status
524 if (iMostCriticalAlarm != STATUS_UNKNOWN)
525 {
526 if (m_iStatus == STATUS_UNKNOWN)
527 {
528 m_iStatus = iMostCriticalAlarm;
529 }
530 else
531 {
532 m_iStatus = max(m_iStatus, iMostCriticalAlarm);
533 }
534 }
535 UnlockData();
536
537 // Cause parent object(s) to recalculate it's status
538 if (iOldStatus != m_iStatus)
539 {
540 LockParentList(FALSE);
541 for(i = 0; i < m_dwParentCount; i++)
542 m_pParentList[i]->CalculateCompoundStatus();
543 UnlockParentList();
544 Modify(); /* LOCK? */
545 }
546 }
547 }
548
549
550 //
551 // Load ACL from database
552 //
553
554 BOOL NetObj::LoadACLFromDB(void)
555 {
556 char szQuery[256];
557 DB_RESULT hResult;
558 BOOL bSuccess = FALSE;
559
560 // Load access list
561 sprintf(szQuery, "SELECT user_id,access_rights FROM acl WHERE object_id=%d", m_dwId);
562 hResult = DBSelect(g_hCoreDB, szQuery);
563 if (hResult != NULL)
564 {
565 int i, iNumRows;
566
567 iNumRows = DBGetNumRows(hResult);
568 for(i = 0; i < iNumRows; i++)
569 m_pAccessList->AddElement(DBGetFieldULong(hResult, i, 0),
570 DBGetFieldULong(hResult, i, 1));
571 DBFreeResult(hResult);
572 bSuccess = TRUE;
573 }
574
575 return bSuccess;
576 }
577
578
579 //
580 // Enumeration parameters structure
581 //
582
583 struct SAVE_PARAM
584 {
585 DB_HANDLE hdb;
586 DWORD dwObjectId;
587 };
588
589
590 //
591 // Handler for ACL elements enumeration
592 //
593
594 static void EnumerationHandler(DWORD dwUserId, DWORD dwAccessRights, void *pArg)
595 {
596 char szQuery[256];
597
598 sprintf(szQuery, "INSERT INTO acl (object_id,user_id,access_rights) VALUES (%d,%d,%d)",
599 ((SAVE_PARAM *)pArg)->dwObjectId, dwUserId, dwAccessRights);
600 DBQuery(((SAVE_PARAM *)pArg)->hdb, szQuery);
601 }
602
603
604 //
605 // Save ACL to database
606 //
607
608 BOOL NetObj::SaveACLToDB(DB_HANDLE hdb)
609 {
610 char szQuery[256];
611 BOOL bSuccess = FALSE;
612 SAVE_PARAM sp;
613
614 // Save access list
615 LockACL();
616 sprintf(szQuery, "DELETE FROM acl WHERE object_id=%d", m_dwId);
617 if (DBQuery(hdb, szQuery))
618 {
619 sp.dwObjectId = m_dwId;
620 sp.hdb = hdb;
621 m_pAccessList->EnumerateElements(EnumerationHandler, &sp);
622 bSuccess = TRUE;
623 }
624 UnlockACL();
625 return bSuccess;
626 }
627
628
629 //
630 // Create CSCP message with object's data
631 //
632
633 void NetObj::CreateMessage(CSCPMessage *pMsg)
634 {
635 DWORD i, dwId;
636
637 pMsg->SetVariable(VID_OBJECT_CLASS, (WORD)Type());
638 pMsg->SetVariable(VID_OBJECT_ID, m_dwId);
639 pMsg->SetVariable(VID_OBJECT_NAME, m_szName);
640 pMsg->SetVariable(VID_OBJECT_STATUS, (WORD)m_iStatus);
641 pMsg->SetVariable(VID_IP_ADDRESS, m_dwIpAddr);
642 pMsg->SetVariable(VID_PARENT_CNT, m_dwParentCount);
643 pMsg->SetVariable(VID_CHILD_CNT, m_dwChildCount);
644 pMsg->SetVariable(VID_IS_DELETED, (WORD)m_bIsDeleted);
645 for(i = 0, dwId = VID_PARENT_ID_BASE; i < m_dwParentCount; i++, dwId++)
646 pMsg->SetVariable(dwId, m_pParentList[i]->Id());
647 for(i = 0, dwId = VID_CHILD_ID_BASE; i < m_dwChildCount; i++, dwId++)
648 pMsg->SetVariable(dwId, m_pChildList[i]->Id());
649 pMsg->SetVariable(VID_INHERIT_RIGHTS, (WORD)m_bInheritAccessRights);
650 pMsg->SetVariable(VID_IMAGE_ID, m_dwImageId);
651 pMsg->SetVariable(VID_STATUS_CALCULATION_ALG, (WORD)m_iStatusCalcAlg);
652 pMsg->SetVariable(VID_STATUS_PROPAGATION_ALG, (WORD)m_iStatusPropAlg);
653 pMsg->SetVariable(VID_FIXED_STATUS, (WORD)m_iFixedStatus);
654 pMsg->SetVariable(VID_STATUS_SHIFT, (WORD)m_iStatusShift);
655 pMsg->SetVariable(VID_STATUS_TRANSLATION_1, (WORD)m_iStatusTranslation[0]);
656 pMsg->SetVariable(VID_STATUS_TRANSLATION_2, (WORD)m_iStatusTranslation[1]);
657 pMsg->SetVariable(VID_STATUS_TRANSLATION_3, (WORD)m_iStatusTranslation[2]);
658 pMsg->SetVariable(VID_STATUS_TRANSLATION_4, (WORD)m_iStatusTranslation[3]);
659 pMsg->SetVariable(VID_STATUS_SINGLE_THRESHOLD, (WORD)m_iStatusSingleThreshold);
660 pMsg->SetVariable(VID_STATUS_THRESHOLD_1, (WORD)m_iStatusThresholds[0]);
661 pMsg->SetVariable(VID_STATUS_THRESHOLD_2, (WORD)m_iStatusThresholds[1]);
662 pMsg->SetVariable(VID_STATUS_THRESHOLD_3, (WORD)m_iStatusThresholds[2]);
663 pMsg->SetVariable(VID_STATUS_THRESHOLD_4, (WORD)m_iStatusThresholds[3]);
664 m_pAccessList->CreateMessage(pMsg);
665 }
666
667
668 //
669 // Handler for EnumerateSessions()
670 //
671
672 static void BroadcastObjectChange(ClientSession *pSession, void *pArg)
673 {
674 if (pSession->IsAuthenticated())
675 pSession->OnObjectChange((NetObj *)pArg);
676 }
677
678
679 //
680 // Mark object as modified and put on client's notification queue
681 // We assume that object is locked at the time of function call
682 //
683
684 void NetObj::Modify(void)
685 {
686 if (g_bModificationsLocked)
687 return;
688
689 m_bIsModified = TRUE;
690 m_dwTimeStamp = time(NULL);
691
692 // Send event to all connected clients
693 if (!m_bIsHidden)
694 EnumerateClientSessions(BroadcastObjectChange, this);
695 }
696
697
698 //
699 // Modify object from message
700 //
701
702 DWORD NetObj::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
703 {
704 if (!bAlreadyLocked)
705 LockData();
706
707 // Change object's name
708 if (pRequest->IsVariableExist(VID_OBJECT_NAME))
709 pRequest->GetVariableStr(VID_OBJECT_NAME, m_szName, MAX_OBJECT_NAME);
710
711 // Change object's image (icon)
712 if (pRequest->IsVariableExist(VID_IMAGE_ID))
713 m_dwImageId = pRequest->GetVariableLong(VID_IMAGE_ID);
714
715 // Change object's status calculation/propagation algorithms
716 if (pRequest->IsVariableExist(VID_STATUS_CALCULATION_ALG))
717 {
718 m_iStatusCalcAlg = (int)pRequest->GetVariableShort(VID_STATUS_CALCULATION_ALG);
719 m_iStatusPropAlg = (int)pRequest->GetVariableShort(VID_STATUS_PROPAGATION_ALG);
720 m_iFixedStatus = (int)pRequest->GetVariableShort(VID_FIXED_STATUS);
721 m_iStatusShift = (int)pRequest->GetVariableShort(VID_STATUS_SHIFT);
722 m_iStatusTranslation[0] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_1);
723 m_iStatusTranslation[1] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_2);
724 m_iStatusTranslation[2] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_3);
725 m_iStatusTranslation[3] = (int)pRequest->GetVariableShort(VID_STATUS_TRANSLATION_4);
726 m_iStatusSingleThreshold = (int)pRequest->GetVariableShort(VID_STATUS_SINGLE_THRESHOLD);
727 m_iStatusThresholds[0] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_1);
728 m_iStatusThresholds[1] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_2);
729 m_iStatusThresholds[2] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_3);
730 m_iStatusThresholds[3] = (int)pRequest->GetVariableShort(VID_STATUS_THRESHOLD_4);
731 }
732
733 // Change object's ACL
734 if (pRequest->IsVariableExist(VID_ACL_SIZE))
735 {
736 DWORD i, dwNumElements;
737
738 LockACL();
739 dwNumElements = pRequest->GetVariableLong(VID_ACL_SIZE);
740 m_bInheritAccessRights = pRequest->GetVariableShort(VID_INHERIT_RIGHTS);
741 m_pAccessList->DeleteAll();
742 for(i = 0; i < dwNumElements; i++)
743 m_pAccessList->AddElement(pRequest->GetVariableLong(VID_ACL_USER_BASE + i),
744 pRequest->GetVariableLong(VID_ACL_RIGHTS_BASE +i));
745 UnlockACL();
746 }
747
748 Modify();
749 UnlockData();
750
751 return RCC_SUCCESS;
752 }
753
754
755 //
756 // Get rights to object for specific user
757 //
758
759 DWORD NetObj::GetUserRights(DWORD dwUserId)
760 {
761 DWORD dwRights;
762
763 // Admin always has all rights to any object
764 if (dwUserId == 0)
765 return 0xFFFFFFFF;
766
767 LockACL();
768
769 // Check if have direct right assignment
770 if (!m_pAccessList->GetUserRights(dwUserId, &dwRights))
771 {
772 // We don't. If this object inherit rights from parents, get them
773 if (m_bInheritAccessRights)
774 {
775 DWORD i;
776
777 LockParentList(FALSE);
778 for(i = 0, dwRights = 0; i < m_dwParentCount; i++)
779 dwRights |= m_pParentList[i]->GetUserRights(dwUserId);
780 UnlockParentList();
781 }
782 }
783
784 UnlockACL();
785 return dwRights;
786 }
787
788
789 //
790 // Check if given user has specific rights on this object
791 //
792
793 BOOL NetObj::CheckAccessRights(DWORD dwUserId, DWORD dwRequiredRights)
794 {
795 DWORD dwRights = GetUserRights(dwUserId);
796 return (dwRights & dwRequiredRights) == dwRequiredRights;
797 }
798
799
800 //
801 // Drop all user privileges on current object
802 //
803
804 void NetObj::DropUserAccess(DWORD dwUserId)
805 {
806 LockACL();
807 if (m_pAccessList->DeleteElement(dwUserId))
808 Modify();
809 UnlockACL();
810 }
811
812
813 //
814 // Set object's management status
815 //
816
817 void NetObj::SetMgmtStatus(BOOL bIsManaged)
818 {
819 DWORD i;
820 int iOldStatus;
821
822 LockData();
823
824 if ((bIsManaged && (m_iStatus != STATUS_UNMANAGED)) ||
825 ((!bIsManaged) && (m_iStatus == STATUS_UNMANAGED)))
826 {
827 UnlockData();
828 return; // Status is already correct
829 }
830
831 iOldStatus = m_iStatus;
832 m_iStatus = (bIsManaged ? STATUS_UNKNOWN : STATUS_UNMANAGED);
833
834 // Generate event if current object is a node
835 if (Type() == OBJECT_NODE)
836 PostEvent(bIsManaged ? EVENT_NODE_UNKNOWN : EVENT_NODE_UNMANAGED, m_dwId, "d", iOldStatus);
837
838 // Change status for child objects also
839 LockChildList(FALSE);
840 for(i = 0; i < m_dwChildCount; i++)
841 m_pChildList[i]->SetMgmtStatus(bIsManaged);
842 UnlockChildList();
843
844 // Cause parent object(s) to recalculate it's status
845 LockParentList(FALSE);
846 for(i = 0; i < m_dwParentCount; i++)
847 m_pParentList[i]->CalculateCompoundStatus();
848 UnlockParentList();
849
850 Modify();
851 UnlockData();
852 }
853
854
855 //
856 // Check if given object is an our child (possibly indirect, i.e child of child)
857 //
858
859 BOOL NetObj::IsChild(DWORD dwObjectId)
860 {
861 DWORD i;
862 BOOL bResult = FALSE;
863
864 // Check for our own ID (object ID should never change, so we may not lock object's data)
865 if (m_dwId == dwObjectId)
866 bResult = TRUE;
867
868 // First, walk through our own child list
869 if (!bResult)
870 {
871 LockChildList(FALSE);
872 for(i = 0; i < m_dwChildCount; i++)
873 if (m_pChildList[i]->Id() == dwObjectId)
874 {
875 bResult = TRUE;
876 break;
877 }
878 UnlockChildList();
879 }
880
881 // If given object is not in child list, check if it is indirect child
882 if (!bResult)
883 {
884 LockChildList(FALSE);
885 for(i = 0; i < m_dwChildCount; i++)
886 if (m_pChildList[i]->IsChild(dwObjectId))
887 {
888 bResult = TRUE;
889 break;
890 }
891 UnlockChildList();
892 }
893
894 return bResult;
895 }
896
897
898 //
899 // Send message to client, who requests poll, if any
900 // This method is used by Node and Interface class objects
901 //
902
903 void NetObj::SendPollerMsg(DWORD dwRqId, TCHAR *pszFormat, ...)
904 {
905 if (m_pPollRequestor != NULL)
906 {
907 va_list args;
908 TCHAR szBuffer[1024];
909
910 va_start(args, pszFormat);
911 _vsntprintf(szBuffer, 1024, pszFormat, args);
912 va_end(args);
913 m_pPollRequestor->SendPollerMsg(dwRqId, szBuffer);
914 }
915 }
916
917
918 //
919 // Add child node objects (direct and indirect childs) to list
920 //
921
922 void NetObj::AddChildNodesToList(DWORD *pdwNumNodes, Node ***pppNodeList, DWORD dwUserId)
923 {
924 DWORD i, j;
925
926 LockChildList(FALSE);
927
928 // Walk through our own child list
929 for(i = 0; i < m_dwChildCount; i++)
930 {
931 if (m_pChildList[i]->Type() == OBJECT_NODE)
932 {
933 // Check if this node already in the list
934 for(j = 0; j < *pdwNumNodes; j++)
935 if ((*pppNodeList)[j]->Id() == m_pChildList[i]->Id())
936 break;
937 if (j == *pdwNumNodes)
938 {
939 m_pChildList[i]->IncRefCount();
940 *pppNodeList = (Node **)realloc(*pppNodeList, sizeof(Node *) * (*pdwNumNodes + 1));
941 (*pppNodeList)[*pdwNumNodes] = (Node *)m_pChildList[i];
942 (*pdwNumNodes)++;
943 }
944 }
945 else
946 {
947 if (m_pChildList[i]->CheckAccessRights(dwUserId, OBJECT_ACCESS_READ))
948 m_pChildList[i]->AddChildNodesToList(pdwNumNodes, pppNodeList, dwUserId);
949 }
950 }
951
952 UnlockChildList();
953 }
954
955
956 //
957 // Hide object and all its childs
958 //
959
960 void NetObj::Hide(void)
961 {
962 DWORD i;
963
964 LockData();
965 LockChildList(FALSE);
966
967 for(i = 0; i < m_dwChildCount; i++)
968 m_pChildList[i]->Hide();
969 m_bIsHidden = TRUE;
970
971 UnlockChildList();
972 UnlockData();
973 }
974
975
976 //
977 // Unhide object and all its childs
978 //
979
980 void NetObj::Unhide(void)
981 {
982 DWORD i;
983
984 LockData();
985
986 m_bIsHidden = FALSE;
987 EnumerateClientSessions(BroadcastObjectChange, this);
988
989 LockChildList(FALSE);
990 for(i = 0; i < m_dwChildCount; i++)
991 m_pChildList[i]->Unhide();
992
993 UnlockChildList();
994 UnlockData();
995 }
996
997
998 //
999 // Return status propagated to parent
1000 //
1001
1002 int NetObj::PropagatedStatus(void)
1003 {
1004 int iStatus;
1005
1006 if (m_iStatusPropAlg == SA_PROPAGATE_DEFAULT)
1007 {
1008 iStatus = DefaultPropagatedStatus(m_iStatus);
1009 }
1010 else
1011 {
1012 switch(m_iStatusPropAlg)
1013 {
1014 case SA_PROPAGATE_UNCHANGED:
1015 iStatus = m_iStatus;
1016 break;
1017 case SA_PROPAGATE_FIXED:
1018 iStatus = (m_iStatus < STATUS_UNKNOWN) ? m_iFixedStatus : m_iStatus;
1019 break;
1020 case SA_PROPAGATE_RELATIVE:
1021 if (m_iStatus < STATUS_UNKNOWN)
1022 {
1023 iStatus = m_iStatus + m_iStatusShift;
1024 if (iStatus < 0)
1025 iStatus = 0;
1026 if (iStatus > STATUS_CRITICAL)
1027 iStatus = STATUS_CRITICAL;
1028 }
1029 else
1030 {
1031 iStatus = m_iStatus;
1032 }
1033 break;
1034 case SA_PROPAGATE_TRANSLATED:
1035 if ((m_iStatus > STATUS_NORMAL) && (m_iStatus < STATUS_UNKNOWN))
1036 {
1037 iStatus = m_iStatusTranslation[m_iStatus - 1];
1038 }
1039 else
1040 {
1041 iStatus = m_iStatus;
1042 }
1043 break;
1044 default:
1045 iStatus = STATUS_UNKNOWN;
1046 break;
1047 }
1048 }
1049 return iStatus;
1050 }