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