schema-related information (like schema version, DB syntax, etc.) moved from "config...
[public/netxms.git] / src / server / core / objects.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Copyright (C) 2003, 2004, 2005, 2006, 2007 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: objects.cpp
20**
21**/
22
23#include "nxcore.h"
24
25
26//
27// Global data
28//
29
30BOOL g_bModificationsLocked = FALSE;
31
32Network *g_pEntireNet = NULL;
33ServiceRoot *g_pServiceRoot = NULL;
34TemplateRoot *g_pTemplateRoot = NULL;
35
36DWORD NXCORE_EXPORTABLE g_dwMgmtNode = 0;
37INDEX NXCORE_EXPORTABLE *g_pIndexById = NULL;
38DWORD NXCORE_EXPORTABLE g_dwIdIndexSize = 0;
39INDEX NXCORE_EXPORTABLE *g_pSubnetIndexByAddr = NULL;
40DWORD NXCORE_EXPORTABLE g_dwSubnetAddrIndexSize = 0;
41INDEX NXCORE_EXPORTABLE *g_pNodeIndexByAddr = NULL;
42DWORD NXCORE_EXPORTABLE g_dwNodeAddrIndexSize = 0;
43INDEX NXCORE_EXPORTABLE *g_pInterfaceIndexByAddr = NULL;
44DWORD NXCORE_EXPORTABLE g_dwInterfaceAddrIndexSize = 0;
45INDEX NXCORE_EXPORTABLE *g_pZoneIndexByGUID = NULL;
46DWORD NXCORE_EXPORTABLE g_dwZoneGUIDIndexSize = 0;
47INDEX NXCORE_EXPORTABLE *g_pConditionIndex = NULL;
48DWORD NXCORE_EXPORTABLE g_dwConditionIndexSize = 0;
49
50RWLOCK NXCORE_EXPORTABLE g_rwlockIdIndex;
51RWLOCK NXCORE_EXPORTABLE g_rwlockNodeIndex;
52RWLOCK NXCORE_EXPORTABLE g_rwlockSubnetIndex;
53RWLOCK NXCORE_EXPORTABLE g_rwlockInterfaceIndex;
54RWLOCK NXCORE_EXPORTABLE g_rwlockZoneIndex;
55RWLOCK NXCORE_EXPORTABLE g_rwlockConditionIndex;
56
57DWORD g_dwNumCategories = 0;
58CONTAINER_CATEGORY *g_pContainerCatList = NULL;
59
60Queue *g_pTemplateUpdateQueue = NULL;
61
62const char *g_szClassName[]={ "Generic", "Subnet", "Node", "Interface",
63 "Network", "Container", "Zone", "ServiceRoot",
64 "Template", "TemplateGroup", "TemplateRoot",
65 "NetworkService", "VPNConnector", "Condition",
66 "Cluster" };
67
68
69//
70// Static data
71//
72
73static int m_iStatusCalcAlg = SA_CALCULATE_MOST_CRITICAL;
74static int m_iStatusPropAlg = SA_PROPAGATE_UNCHANGED;
75static int m_iFixedStatus; // Status if propagation is "Fixed"
76static int m_iStatusShift; // Shift value for "shifted" status propagation
77static int m_iStatusTranslation[4];
78static int m_iStatusSingleThreshold;
79static int m_iStatusThresholds[4];
80
81
82//
83// Thread which apply template updates
84//
85
86static THREAD_RESULT THREAD_CALL ApplyTemplateThread(void *pArg)
87{
88 TEMPLATE_UPDATE_INFO *pInfo;
89 NetObj *pNode;
90 BOOL bSuccess, bLock1, bLock2;
91
92 while(1)
93 {
94 pInfo = (TEMPLATE_UPDATE_INFO *)g_pTemplateUpdateQueue->GetOrBlock();
95 if (pInfo == INVALID_POINTER_VALUE)
96 break;
97
98 bSuccess = FALSE;
99 pNode = FindObjectById(pInfo->dwNodeId);
100 if (pNode != NULL)
101 {
102 if (pNode->Type() == OBJECT_NODE)
103 {
104 switch(pInfo->iUpdateType)
105 {
106 case APPLY_TEMPLATE:
107 bLock1 = pInfo->pTemplate->LockDCIList(0x7FFFFFFF, _T("SYSTEM"), NULL);
108 bLock2 = ((Node *)pNode)->LockDCIList(0x7FFFFFFF, _T("SYSTEM"), NULL);
109 if (bLock1 && bLock2)
110 {
111 pInfo->pTemplate->ApplyToNode((Node *)pNode);
112 bSuccess = TRUE;
113 }
114 if (bLock1)
115 pInfo->pTemplate->UnlockDCIList(0x7FFFFFFF);
116 if (bLock2)
117 ((Node *)pNode)->UnlockDCIList(0x7FFFFFFF);
118 break;
119 case REMOVE_TEMPLATE:
120 if (((Node *)pNode)->LockDCIList(0x7FFFFFFF, _T("SYSTEM"), NULL))
121 {
122 ((Node *)pNode)->UnbindFromTemplate(pInfo->pTemplate->Id(), pInfo->bRemoveDCI);
123 ((Node *)pNode)->UnlockDCIList(0x7FFFFFFF);
124 bSuccess = TRUE;
125 }
126 break;
127 default:
128 bSuccess = TRUE;
129 break;
130 }
131 }
132 }
133
134 if (bSuccess)
135 {
136 pInfo->pTemplate->DecRefCount();
137 free(pInfo);
138 }
139 else
140 {
141 g_pTemplateUpdateQueue->Put(pInfo); // Requeue
142 ThreadSleepMs(500);
143 }
144 }
145
146 return THREAD_OK;
147}
148
149
150//
151// DCI cache loading thread
152//
153
154static THREAD_RESULT THREAD_CALL CacheLoadingThread(void *pArg)
155{
156 DWORD i;
157
158 DbgPrintf(1, _T("Started caching of DCI values"));
159 RWLockReadLock(g_rwlockNodeIndex, INFINITE);
160 for(i = 0; i < g_dwNodeAddrIndexSize; i++)
161 {
162 ((Node *)g_pNodeIndexByAddr[i].pObject)->UpdateDCICache();
163 ThreadSleepMs(50); // Give a chance to other threads to do something with database
164 }
165 RWLockUnlock(g_rwlockNodeIndex);
166 DbgPrintf(1, _T("Finished caching of DCI values"));
167 return THREAD_OK;
168}
169
170
171//
172// Initialize objects infrastructure
173//
174
175void ObjectsInit(void)
176{
177 // Load default status calculation info
178 m_iStatusCalcAlg = ConfigReadInt("StatusCalculationAlgorithm", SA_CALCULATE_MOST_CRITICAL);
179 m_iStatusPropAlg = ConfigReadInt("StatusPropagationAlgorithm", SA_PROPAGATE_UNCHANGED);
180 m_iFixedStatus = ConfigReadInt("FixedStatusValue", STATUS_NORMAL);
181 m_iStatusShift = ConfigReadInt("StatusShift", 0);
182 ConfigReadByteArray("StatusTranslation", m_iStatusTranslation, 4, STATUS_WARNING);
183 m_iStatusSingleThreshold = ConfigReadInt("StatusSingleThreshold", 75);
184 ConfigReadByteArray("StatusThresholds", m_iStatusThresholds, 4, 50);
185
186 g_pTemplateUpdateQueue = new Queue;
187
188 g_rwlockIdIndex = RWLockCreate();
189 g_rwlockNodeIndex = RWLockCreate();
190 g_rwlockSubnetIndex = RWLockCreate();
191 g_rwlockInterfaceIndex = RWLockCreate();
192 g_rwlockZoneIndex = RWLockCreate();
193 g_rwlockConditionIndex = RWLockCreate();
194
195 // Create "Entire Network" object
196 g_pEntireNet = new Network;
197 NetObjInsert(g_pEntireNet, FALSE);
198
199 // Create "Service Root" object
200 g_pServiceRoot = new ServiceRoot;
201 NetObjInsert(g_pServiceRoot, FALSE);
202
203 // Create "Template Root" object
204 g_pTemplateRoot = new TemplateRoot;
205 NetObjInsert(g_pTemplateRoot, FALSE);
206 DbgPrintf(1, "Built-in objects created");
207
208 // Start template update applying thread
209 ThreadCreate(ApplyTemplateThread, 0, NULL);
210}
211
212
213//
214// Function to compare two indexes
215//
216
217static int IndexCompare(const void *pArg1, const void *pArg2)
218{
219 return (((INDEX *)pArg1)->dwKey < ((INDEX *)pArg2)->dwKey) ? -1 :
220 ((((INDEX *)pArg1)->dwKey > ((INDEX *)pArg2)->dwKey) ? 1 : 0);
221}
222
223
224//
225// Add new object to index
226//
227
228void AddObjectToIndex(INDEX **ppIndex, DWORD *pdwIndexSize, DWORD dwKey, void *pObject)
229{
230 *ppIndex = (INDEX *)realloc(*ppIndex, sizeof(INDEX) * ((*pdwIndexSize) + 1));
231 (*ppIndex)[*pdwIndexSize].dwKey = dwKey;
232 (*ppIndex)[*pdwIndexSize].pObject = pObject;
233 (*pdwIndexSize)++;
234 qsort(*ppIndex, *pdwIndexSize, sizeof(INDEX), IndexCompare);
235}
236
237
238//
239// Perform binary search on index
240// Returns INVALID_INDEX if key not found or position of appropriate network object
241// We assume that pIndex == NULL will not be passed
242//
243
244DWORD SearchIndex(INDEX *pIndex, DWORD dwIndexSize, DWORD dwKey)
245{
246 DWORD dwFirst, dwLast, dwMid;
247
248 dwFirst = 0;
249 dwLast = dwIndexSize - 1;
250
251 if ((dwKey < pIndex[0].dwKey) || (dwKey > pIndex[dwLast].dwKey))
252 return INVALID_INDEX;
253
254 while(dwFirst < dwLast)
255 {
256 dwMid = (dwFirst + dwLast) / 2;
257 if (dwKey == pIndex[dwMid].dwKey)
258 return dwMid;
259 if (dwKey < pIndex[dwMid].dwKey)
260 dwLast = dwMid - 1;
261 else
262 dwFirst = dwMid + 1;
263 }
264
265 if (dwKey == pIndex[dwLast].dwKey)
266 return dwLast;
267
268 return INVALID_INDEX;
269}
270
271
272//
273// Delete object from index
274//
275
276void DeleteObjectFromIndex(INDEX **ppIndex, DWORD *pdwIndexSize, DWORD dwKey)
277{
278 DWORD dwPos;
279 INDEX *pIndex = *ppIndex;
280
281 dwPos = SearchIndex(pIndex, *pdwIndexSize, dwKey);
282 if (dwPos != INVALID_INDEX)
283 {
284 (*pdwIndexSize)--;
285 memmove(&pIndex[dwPos], &pIndex[dwPos + 1], sizeof(INDEX) * (*pdwIndexSize - dwPos));
286 }
287}
288
289
290//
291// Insert new object into network
292//
293
294void NetObjInsert(NetObj *pObject, BOOL bNewObject)
295{
296 if (bNewObject)
297 {
298 // Assign unique ID to new object
299 pObject->SetId(CreateUniqueId(IDG_NETWORK_OBJECT));
300
301 // Create table for storing data collection values
302 if (pObject->Type() == OBJECT_NODE)
303 {
304 char szQuery[256], szQueryTemplate[256];
305 DWORD i;
306
28f5b9a4 307 MetaDataReadStr("IDataTableCreationCommand", szQueryTemplate, 255, "");
5039dede
AK
308 sprintf(szQuery, szQueryTemplate, pObject->Id());
309 DBQuery(g_hCoreDB, szQuery);
310
311 for(i = 0; i < 10; i++)
312 {
313 sprintf(szQuery, "IDataIndexCreationCommand_%d", i);
28f5b9a4 314 MetaDataReadStr(szQuery, szQueryTemplate, 255, "");
5039dede
AK
315 if (szQueryTemplate[0] != 0)
316 {
317 sprintf(szQuery, szQueryTemplate, pObject->Id(), pObject->Id());
318 DBQuery(g_hCoreDB, szQuery);
319 }
320 }
321 }
322 }
323 RWLockWriteLock(g_rwlockIdIndex, INFINITE);
324 AddObjectToIndex(&g_pIndexById, &g_dwIdIndexSize, pObject->Id(), pObject);
325 RWLockUnlock(g_rwlockIdIndex);
326 if (!pObject->IsDeleted())
327 {
328 switch(pObject->Type())
329 {
330 case OBJECT_GENERIC:
331 case OBJECT_NETWORK:
332 case OBJECT_CONTAINER:
333 case OBJECT_SERVICEROOT:
334 case OBJECT_NETWORKSERVICE:
335 case OBJECT_TEMPLATE:
336 case OBJECT_TEMPLATEGROUP:
337 case OBJECT_TEMPLATEROOT:
338 case OBJECT_CLUSTER:
339 break;
340 case OBJECT_SUBNET:
341 if (pObject->IpAddr() != 0)
342 {
343 RWLockWriteLock(g_rwlockSubnetIndex, INFINITE);
344 AddObjectToIndex(&g_pSubnetIndexByAddr, &g_dwSubnetAddrIndexSize, pObject->IpAddr(), pObject);
345 RWLockUnlock(g_rwlockSubnetIndex);
346 if (bNewObject)
347 PostEvent(EVENT_SUBNET_ADDED, pObject->Id(), NULL);
348 }
349 break;
350 case OBJECT_NODE:
351 if (pObject->IpAddr() != 0)
352 {
353 RWLockWriteLock(g_rwlockNodeIndex, INFINITE);
354 AddObjectToIndex(&g_pNodeIndexByAddr, &g_dwNodeAddrIndexSize, pObject->IpAddr(), pObject);
355 RWLockUnlock(g_rwlockNodeIndex);
356 }
357 break;
358 case OBJECT_INTERFACE:
359 if (pObject->IpAddr() != 0)
360 {
361 RWLockWriteLock(g_rwlockInterfaceIndex, INFINITE);
362 AddObjectToIndex(&g_pInterfaceIndexByAddr, &g_dwInterfaceAddrIndexSize, pObject->IpAddr(), pObject);
363 RWLockUnlock(g_rwlockInterfaceIndex);
364 }
365 break;
366 case OBJECT_ZONE:
367 RWLockWriteLock(g_rwlockZoneIndex, INFINITE);
368 AddObjectToIndex(&g_pZoneIndexByGUID, &g_dwZoneGUIDIndexSize, ((Zone *)pObject)->GUID(), pObject);
369 RWLockUnlock(g_rwlockZoneIndex);
370 break;
371 case OBJECT_CONDITION:
372 RWLockWriteLock(g_rwlockConditionIndex, INFINITE);
373 AddObjectToIndex(&g_pConditionIndex, &g_dwConditionIndexSize, pObject->Id(), pObject);
374 RWLockUnlock(g_rwlockConditionIndex);
375 break;
376 default:
377 nxlog_write(MSG_BAD_NETOBJ_TYPE, EVENTLOG_ERROR_TYPE, "d", pObject->Type());
378 break;
379 }
380 }
381}
382
383
384//
385// Delete object from indexes
386// If object has an IP address, this function will delete it from
387// appropriate index. Normally this function should be called from
388// NetObj::Delete() method.
389//
390
391void NetObjDeleteFromIndexes(NetObj *pObject)
392{
393 switch(pObject->Type())
394 {
395 case OBJECT_GENERIC:
396 case OBJECT_NETWORK:
397 case OBJECT_CONTAINER:
398 case OBJECT_SERVICEROOT:
399 case OBJECT_NETWORKSERVICE:
400 case OBJECT_TEMPLATE:
401 case OBJECT_TEMPLATEGROUP:
402 case OBJECT_TEMPLATEROOT:
403 case OBJECT_CLUSTER:
404 break;
405 case OBJECT_SUBNET:
406 if (pObject->IpAddr() != 0)
407 {
408 RWLockWriteLock(g_rwlockSubnetIndex, INFINITE);
409 DeleteObjectFromIndex(&g_pSubnetIndexByAddr, &g_dwSubnetAddrIndexSize, pObject->IpAddr());
410 RWLockUnlock(g_rwlockSubnetIndex);
411 }
412 break;
413 case OBJECT_NODE:
414 if (pObject->IpAddr() != 0)
415 {
416 RWLockWriteLock(g_rwlockNodeIndex, INFINITE);
417 DeleteObjectFromIndex(&g_pNodeIndexByAddr, &g_dwNodeAddrIndexSize, pObject->IpAddr());
418 RWLockUnlock(g_rwlockNodeIndex);
419 }
420 break;
421 case OBJECT_INTERFACE:
422 if (pObject->IpAddr() != 0)
423 {
424 RWLockWriteLock(g_rwlockInterfaceIndex, INFINITE);
425 DeleteObjectFromIndex(&g_pInterfaceIndexByAddr, &g_dwInterfaceAddrIndexSize, pObject->IpAddr());
426 RWLockUnlock(g_rwlockInterfaceIndex);
427 }
428 break;
429 case OBJECT_ZONE:
430 RWLockWriteLock(g_rwlockZoneIndex, INFINITE);
431 DeleteObjectFromIndex(&g_pZoneIndexByGUID, &g_dwZoneGUIDIndexSize, ((Zone *)pObject)->GUID());
432 RWLockUnlock(g_rwlockZoneIndex);
433 break;
434 case OBJECT_CONDITION:
435 RWLockWriteLock(g_rwlockConditionIndex, INFINITE);
436 DeleteObjectFromIndex(&g_pConditionIndex, &g_dwConditionIndexSize, pObject->Id());
437 RWLockUnlock(g_rwlockConditionIndex);
438 break;
439 default:
440 nxlog_write(MSG_BAD_NETOBJ_TYPE, EVENTLOG_ERROR_TYPE, "d", pObject->Type());
441 break;
442 }
443}
444
445
446//
447// Get IP netmask for object of any class
448//
449
450static DWORD GetObjectNetmask(NetObj *pObject)
451{
452 switch(pObject->Type())
453 {
454 case OBJECT_INTERFACE:
455 return ((Interface *)pObject)->IpNetMask();
456 case OBJECT_SUBNET:
457 return ((Subnet *)pObject)->IpNetMask();
458 default:
459 return 0;
460 }
461}
462
463
464//
465// Find node by IP address
466//
467
468Node NXCORE_EXPORTABLE *FindNodeByIP(DWORD dwAddr)
469{
470 DWORD dwPos;
471 Node *pNode;
472
473 if ((g_pInterfaceIndexByAddr == NULL) || (dwAddr == 0))
474 return NULL;
475
476 RWLockReadLock(g_rwlockInterfaceIndex, INFINITE);
477 dwPos = SearchIndex(g_pInterfaceIndexByAddr, g_dwInterfaceAddrIndexSize, dwAddr);
478 pNode = (dwPos == INVALID_INDEX) ? NULL : (Node *)((Interface *)g_pInterfaceIndexByAddr[dwPos].pObject)->GetParentNode();
479 RWLockUnlock(g_rwlockInterfaceIndex);
480 return pNode;
481}
482
483
484//
485// Find subnet by IP address
486//
487
488Subnet NXCORE_EXPORTABLE *FindSubnetByIP(DWORD dwAddr)
489{
490 DWORD dwPos;
491 Subnet *pSubnet;
492
493 if ((g_pSubnetIndexByAddr == NULL) || (dwAddr == 0))
494 return NULL;
495
496 RWLockReadLock(g_rwlockSubnetIndex, INFINITE);
497 dwPos = SearchIndex(g_pSubnetIndexByAddr, g_dwSubnetAddrIndexSize, dwAddr);
498 pSubnet = (dwPos == INVALID_INDEX) ? NULL : (Subnet *)g_pSubnetIndexByAddr[dwPos].pObject;
499 RWLockUnlock(g_rwlockSubnetIndex);
500 return pSubnet;
501}
502
503
504//
505// Find subnet for given IP address
506//
507
508Subnet NXCORE_EXPORTABLE *FindSubnetForNode(DWORD dwNodeAddr)
509{
510 DWORD i;
511 Subnet *pSubnet = NULL;
512
513 if ((g_pSubnetIndexByAddr == NULL) || (dwNodeAddr == 0))
514 return NULL;
515
516 RWLockReadLock(g_rwlockSubnetIndex, INFINITE);
517 for(i = 0; i < g_dwSubnetAddrIndexSize; i++)
518 if ((dwNodeAddr & ((Subnet *)g_pSubnetIndexByAddr[i].pObject)->IpNetMask()) ==
519 ((Subnet *)g_pSubnetIndexByAddr[i].pObject)->IpAddr())
520 {
521 pSubnet = (Subnet *)g_pSubnetIndexByAddr[i].pObject;
522 break;
523 }
524 RWLockUnlock(g_rwlockSubnetIndex);
525 return pSubnet;
526}
527
528
529//
530// Find object by ID
531//
532
533NetObj NXCORE_EXPORTABLE *FindObjectById(DWORD dwId)
534{
535 DWORD dwPos;
536 NetObj *pObject;
537
538 if (g_pIndexById == NULL)
539 return NULL;
540
541 RWLockReadLock(g_rwlockIdIndex, INFINITE);
542 dwPos = SearchIndex(g_pIndexById, g_dwIdIndexSize, dwId);
543 pObject = (dwPos == INVALID_INDEX) ? NULL : (NetObj *)g_pIndexById[dwPos].pObject;
544 RWLockUnlock(g_rwlockIdIndex);
545 return pObject;
546}
547
548
549//
550// Find object by name
551//
552
553NetObj NXCORE_EXPORTABLE *FindObjectByName(const TCHAR *name, int objClass)
554{
555 DWORD i;
556 NetObj *pObject = NULL;
557
558 if (g_pIndexById == NULL)
559 return NULL;
560
561 RWLockReadLock(g_rwlockIdIndex, INFINITE);
562 for(i = 0; i < g_dwIdIndexSize; i++)
563 {
564 if ((!_tcsicmp(((NetObj *)g_pIndexById[i].pObject)->Name(), name)) &&
565 ((objClass == -1) || (objClass == ((NetObj *)g_pIndexById[i].pObject)->Type())))
566 {
567 pObject = (NetObj *)g_pIndexById[i].pObject;
568 break;
569 }
570 }
571 RWLockUnlock(g_rwlockIdIndex);
572 return pObject;
573}
574
575
576//
577// Find template object by name
578//
579
580Template NXCORE_EXPORTABLE *FindTemplateByName(const TCHAR *pszName)
581{
582 DWORD i;
583 Template *pObject = NULL;
584
585 if (g_pIndexById == NULL)
586 return NULL;
587
588 RWLockReadLock(g_rwlockIdIndex, INFINITE);
589 for(i = 0; i < g_dwIdIndexSize; i++)
590 {
591 if ((((NetObj *)g_pIndexById[i].pObject)->Type() == OBJECT_TEMPLATE) &&
592 (!_tcsicmp(((NetObj *)g_pIndexById[i].pObject)->Name(), pszName)))
593 {
594 pObject = (Template *)g_pIndexById[i].pObject;
595 break;
596 }
597 }
598 RWLockUnlock(g_rwlockIdIndex);
599 return pObject;
600}
601
602
603//
604// Find zone object by GUID
605//
606
607Zone NXCORE_EXPORTABLE *FindZoneByGUID(DWORD dwZoneGUID)
608{
609 DWORD dwPos;
610 NetObj *pObject;
611
612 if (g_pZoneIndexByGUID == NULL)
613 return NULL;
614
615 RWLockReadLock(g_rwlockZoneIndex, INFINITE);
616 dwPos = SearchIndex(g_pZoneIndexByGUID, g_dwZoneGUIDIndexSize, dwZoneGUID);
617 pObject = (dwPos == INVALID_INDEX) ? NULL : (NetObj *)g_pZoneIndexByGUID[dwPos].pObject;
618 RWLockUnlock(g_rwlockZoneIndex);
619 return (pObject->Type() == OBJECT_ZONE) ? (Zone *)pObject : NULL;
620}
621
622
623//
624// Find local management node ID
625//
626
627DWORD FindLocalMgmtNode(void)
628{
629 DWORD i, dwId = 0;
630
631 if (g_pNodeIndexByAddr == NULL)
632 return 0;
633
634 RWLockReadLock(g_rwlockNodeIndex, INFINITE);
635 for(i = 0; i < g_dwNodeAddrIndexSize; i++)
636 if (((Node *)g_pNodeIndexByAddr[i].pObject)->Flags() & NF_IS_LOCAL_MGMT)
637 {
638 dwId = ((Node *)g_pNodeIndexByAddr[i].pObject)->Id();
639 break;
640 }
641 RWLockUnlock(g_rwlockNodeIndex);
642 return dwId;
643}
644
645
646//
647// Load objects from database at stratup
648//
649
650BOOL LoadObjects(void)
651{
652 DB_RESULT hResult;
653 DWORD i, j, dwNumRows;
654 DWORD dwId;
655 Template *pTemplate;
656 char szQuery[256];
657
658 // Prevent objects to change it's modification flag
659 g_bModificationsLocked = TRUE;
660
661 // Load container categories
662 DbgPrintf(2, "Loading container categories...");
663 hResult = DBSelect(g_hCoreDB, "SELECT category,name,image_id,description FROM container_categories");
664 if (hResult != NULL)
665 {
666 g_dwNumCategories = DBGetNumRows(hResult);
667 g_pContainerCatList = (CONTAINER_CATEGORY *)malloc(sizeof(CONTAINER_CATEGORY) * g_dwNumCategories);
668 for(i = 0; i < (int)g_dwNumCategories; i++)
669 {
670 g_pContainerCatList[i].dwCatId = DBGetFieldULong(hResult, i, 0);
671 DBGetField(hResult, i, 1, g_pContainerCatList[i].szName, MAX_OBJECT_NAME);
672 g_pContainerCatList[i].dwImageId = DBGetFieldULong(hResult, i, 2);
673 g_pContainerCatList[i].pszDescription = DBGetField(hResult, i, 3, NULL, 0);
674 DecodeSQLString(g_pContainerCatList[i].pszDescription);
675 }
676 DBFreeResult(hResult);
677 }
678
679 // Load built-in object properties
680 DbgPrintf(2, "Loading built-in object properties...");
681 g_pEntireNet->LoadFromDB();
682 g_pServiceRoot->LoadFromDB();
683 g_pTemplateRoot->LoadFromDB();
684
685 // Load zones
686 if (g_dwFlags & AF_ENABLE_ZONING)
687 {
688 Zone *pZone;
689
690 DbgPrintf(2, "Loading zones...");
691
692 // Load (or create) default zone
693 pZone = new Zone;
694 pZone->CreateFromDB(BUILTIN_OID_ZONE0);
695 NetObjInsert(pZone, FALSE);
696 g_pEntireNet->AddZone(pZone);
697
698 hResult = DBSelect(g_hCoreDB, "SELECT id FROM zones WHERE id<>4");
699 if (hResult != 0)
700 {
701 dwNumRows = DBGetNumRows(hResult);
702 for(i = 0; i < dwNumRows; i++)
703 {
704 dwId = DBGetFieldULong(hResult, i, 0);
705 pZone = new Zone;
706 if (pZone->CreateFromDB(dwId))
707 {
708 if (!pZone->IsDeleted())
709 g_pEntireNet->AddZone(pZone);
710 NetObjInsert(pZone, FALSE); // Insert into indexes
711 }
712 else // Object load failed
713 {
714 delete pZone;
715 nxlog_write(MSG_ZONE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
716 }
717 }
718 DBFreeResult(hResult);
719 }
720 }
721
722 // Load conditions
723 // We should load conditions before nodes because
724 // DCI cache size calculation uses information from condition objects
725 DbgPrintf(2, "Loading conditions...");
726 hResult = DBSelect(g_hCoreDB, "SELECT id FROM conditions");
727 if (hResult != NULL)
728 {
729 Condition *pCondition;
730
731 dwNumRows = DBGetNumRows(hResult);
732 for(i = 0; i < dwNumRows; i++)
733 {
734 dwId = DBGetFieldULong(hResult, i, 0);
735 pCondition = new Condition;
736 if (pCondition->CreateFromDB(dwId))
737 {
738 NetObjInsert(pCondition, FALSE); // Insert into indexes
739 }
740 else // Object load failed
741 {
742 delete pCondition;
743 nxlog_write(MSG_CONDITION_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
744 }
745 }
746 DBFreeResult(hResult);
747 }
748
749 // Load subnets
750 DbgPrintf(2, "Loading subnets...");
751 hResult = DBSelect(g_hCoreDB, "SELECT id FROM subnets");
752 if (hResult != 0)
753 {
754 Subnet *pSubnet;
755
756 dwNumRows = DBGetNumRows(hResult);
757 for(i = 0; i < dwNumRows; i++)
758 {
759 dwId = DBGetFieldULong(hResult, i, 0);
760 pSubnet = new Subnet;
761 if (pSubnet->CreateFromDB(dwId))
762 {
763 if (!pSubnet->IsDeleted())
764 {
765 if (g_dwFlags & AF_ENABLE_ZONING)
766 {
767 Zone *pZone;
768
769 pZone = FindZoneByGUID(pSubnet->ZoneGUID());
770 if (pZone != NULL)
771 pZone->AddSubnet(pSubnet);
772 }
773 else
774 {
775 g_pEntireNet->AddSubnet(pSubnet);
776 }
777 }
778 NetObjInsert(pSubnet, FALSE); // Insert into indexes
779 }
780 else // Object load failed
781 {
782 delete pSubnet;
783 nxlog_write(MSG_SUBNET_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
784 }
785 }
786 DBFreeResult(hResult);
787 }
788
789 // Load nodes
790 DbgPrintf(2, "Loading nodes...");
791 hResult = DBSelect(g_hCoreDB, "SELECT id FROM nodes");
792 if (hResult != 0)
793 {
794 Node *pNode;
795
796 dwNumRows = DBGetNumRows(hResult);
797 for(i = 0; i < dwNumRows; i++)
798 {
799 dwId = DBGetFieldULong(hResult, i, 0);
800 pNode = new Node;
801 if (pNode->CreateFromDB(dwId))
802 {
803 NetObjInsert(pNode, FALSE); // Insert into indexes
804 }
805 else // Object load failed
806 {
807 delete pNode;
808 nxlog_write(MSG_NODE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
809 }
810 }
811 DBFreeResult(hResult);
812
813 // Start cache loading thread
814 ThreadCreate(CacheLoadingThread, 0, NULL);
815 }
816
817 // Load interfaces
818 DbgPrintf(2, "Loading interfaces...");
819 hResult = DBSelect(g_hCoreDB, "SELECT id FROM interfaces");
820 if (hResult != 0)
821 {
822 Interface *pInterface;
823
824 dwNumRows = DBGetNumRows(hResult);
825 for(i = 0; i < dwNumRows; i++)
826 {
827 dwId = DBGetFieldULong(hResult, i, 0);
828 pInterface = new Interface;
829 if (pInterface->CreateFromDB(dwId))
830 {
831 NetObjInsert(pInterface, FALSE); // Insert into indexes
832 }
833 else // Object load failed
834 {
835 delete pInterface;
836 nxlog_write(MSG_INTERFACE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
837 }
838 }
839 DBFreeResult(hResult);
840 }
841
842 // Load network services
843 DbgPrintf(2, "Loading network services...");
844 hResult = DBSelect(g_hCoreDB, "SELECT id FROM network_services");
845 if (hResult != 0)
846 {
847 NetworkService *pService;
848
849 dwNumRows = DBGetNumRows(hResult);
850 for(i = 0; i < dwNumRows; i++)
851 {
852 dwId = DBGetFieldULong(hResult, i, 0);
853 pService = new NetworkService;
854 if (pService->CreateFromDB(dwId))
855 {
856 NetObjInsert(pService, FALSE); // Insert into indexes
857 }
858 else // Object load failed
859 {
860 delete pService;
861 nxlog_write(MSG_NETSRV_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
862 }
863 }
864 DBFreeResult(hResult);
865 }
866
867 // Load VPN connectors
868 DbgPrintf(2, "Loading VPN connectors...");
869 hResult = DBSelect(g_hCoreDB, "SELECT id FROM vpn_connectors");
870 if (hResult != NULL)
871 {
872 VPNConnector *pConnector;
873
874 dwNumRows = DBGetNumRows(hResult);
875 for(i = 0; i < dwNumRows; i++)
876 {
877 dwId = DBGetFieldULong(hResult, i, 0);
878 pConnector = new VPNConnector;
879 if (pConnector->CreateFromDB(dwId))
880 {
881 NetObjInsert(pConnector, FALSE); // Insert into indexes
882 }
883 else // Object load failed
884 {
885 delete pConnector;
886 nxlog_write(MSG_VPNC_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
887 }
888 }
889 DBFreeResult(hResult);
890 }
891
892 // Load clusters
893 DbgPrintf(2, "Loading clusters...");
894 hResult = DBSelect(g_hCoreDB, "SELECT id FROM clusters");
895 if (hResult != NULL)
896 {
897 Cluster *pCluster;
898
899 dwNumRows = DBGetNumRows(hResult);
900 for(i = 0; i < dwNumRows; i++)
901 {
902 dwId = DBGetFieldULong(hResult, i, 0);
903 pCluster = new Cluster;
904 if (pCluster->CreateFromDB(dwId))
905 {
906 NetObjInsert(pCluster, FALSE); // Insert into indexes
907 }
908 else // Object load failed
909 {
910 delete pCluster;
911 nxlog_write(MSG_CLUSTER_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
912 }
913 }
914 DBFreeResult(hResult);
915 }
916
917 // Load templates
918 DbgPrintf(2, "Loading templates...");
919 hResult = DBSelect(g_hCoreDB, "SELECT id FROM templates");
920 if (hResult != NULL)
921 {
922 dwNumRows = DBGetNumRows(hResult);
923 for(i = 0; i < dwNumRows; i++)
924 {
925 dwId = DBGetFieldULong(hResult, i, 0);
926 pTemplate = new Template;
927 if (pTemplate->CreateFromDB(dwId))
928 {
929 NetObjInsert(pTemplate, FALSE); // Insert into indexes
930 pTemplate->CalculateCompoundStatus(); // Force status change to NORMAL
931 }
932 else // Object load failed
933 {
934 delete pTemplate;
935 nxlog_write(MSG_TEMPLATE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
936 }
937 }
938 DBFreeResult(hResult);
939 }
940
941 // Load container objects
942 DbgPrintf(2, "Loading containers...");
943 sprintf(szQuery, "SELECT id FROM containers WHERE object_class=%d", OBJECT_CONTAINER);
944 hResult = DBSelect(g_hCoreDB, szQuery);
945 if (hResult != 0)
946 {
947 Container *pContainer;
948
949 dwNumRows = DBGetNumRows(hResult);
950 for(i = 0; i < dwNumRows; i++)
951 {
952 dwId = DBGetFieldULong(hResult, i, 0);
953 pContainer = new Container;
954 if (pContainer->CreateFromDB(dwId))
955 {
956 NetObjInsert(pContainer, FALSE); // Insert into indexes
957 }
958 else // Object load failed
959 {
960 delete pContainer;
961 nxlog_write(MSG_CONTAINER_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
962 }
963 }
964 DBFreeResult(hResult);
965 }
966
967 // Load template group objects
968 DbgPrintf(2, "Loading template groups...");
969 sprintf(szQuery, "SELECT id FROM containers WHERE object_class=%d", OBJECT_TEMPLATEGROUP);
970 hResult = DBSelect(g_hCoreDB, szQuery);
971 if (hResult != 0)
972 {
973 TemplateGroup *pGroup;
974
975 dwNumRows = DBGetNumRows(hResult);
976 for(i = 0; i < dwNumRows; i++)
977 {
978 dwId = DBGetFieldULong(hResult, i, 0);
979 pGroup = new TemplateGroup;
980 if (pGroup->CreateFromDB(dwId))
981 {
982 NetObjInsert(pGroup, FALSE); // Insert into indexes
983 }
984 else // Object load failed
985 {
986 delete pGroup;
987 nxlog_write(MSG_TG_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
988 }
989 }
990 DBFreeResult(hResult);
991 }
992
993 // Link childs to container and template group objects
994 DbgPrintf(2, "Linking objects...");
995 for(i = 0; i < g_dwIdIndexSize; i++)
996 if ((((NetObj *)g_pIndexById[i].pObject)->Type() == OBJECT_CONTAINER) ||
997 (((NetObj *)g_pIndexById[i].pObject)->Type() == OBJECT_TEMPLATEGROUP))
998 ((Container *)g_pIndexById[i].pObject)->LinkChildObjects();
999
1000 // Link childs to "Service Root" and "Template Root" objects
1001 g_pServiceRoot->LinkChildObjects();
1002 g_pTemplateRoot->LinkChildObjects();
1003
1004 // Allow objects to change it's modification flag
1005 g_bModificationsLocked = FALSE;
1006
1007 // Recalculate status for built-in objects
1008 g_pEntireNet->CalculateCompoundStatus();
1009 g_pServiceRoot->CalculateCompoundStatus();
1010 g_pTemplateRoot->CalculateCompoundStatus();
1011
1012 // Recalculate status for zone objects
1013 if (g_dwFlags & AF_ENABLE_ZONING)
1014 {
1015 for(i = 0; i < g_dwZoneGUIDIndexSize; i++)
1016 ((NetObj *)g_pZoneIndexByGUID[i].pObject)->CalculateCompoundStatus();
1017 }
1018
1019 // Apply system templates
1020 DbgPrintf(2, "Applying system templates...");
1021
1022 pTemplate = FindTemplateByName(_T("@System.Agent"));
1023 if (pTemplate == NULL)
1024 {
1025 pTemplate = new Template(_T("@System.Agent"));
1026 pTemplate->SetSystemFlag(TRUE);
1027 NetObjInsert(pTemplate, TRUE);
1028 g_pTemplateRoot->AddChild(pTemplate);
1029 pTemplate->AddParent(g_pTemplateRoot);
1030 pTemplate->CalculateCompoundStatus();
1031 pTemplate->Unhide();
1032 }
1033 pTemplate->ValidateSystemTemplate();
1034 RWLockReadLock(g_rwlockIdIndex, INFINITE);
1035 for(j = 0; j < g_dwIdIndexSize; j++)
1036 if (((NetObj *)g_pIndexById[j].pObject)->Type() == OBJECT_NODE)
1037 {
1038 if (((Node *)g_pIndexById[j].pObject)->IsNativeAgent())
1039 pTemplate->ApplyToNode((Node *)g_pIndexById[j].pObject);
1040 }
1041 RWLockUnlock(g_rwlockIdIndex);
1042
1043 pTemplate = FindTemplateByName(_T("@System.SNMP"));
1044 if (pTemplate == NULL)
1045 {
1046 pTemplate = new Template(_T("@System.SNMP"));
1047 pTemplate->SetSystemFlag(TRUE);
1048 NetObjInsert(pTemplate, TRUE);
1049 g_pTemplateRoot->AddChild(pTemplate);
1050 pTemplate->AddParent(g_pTemplateRoot);
1051 pTemplate->CalculateCompoundStatus();
1052 pTemplate->Unhide();
1053 }
1054 pTemplate->ValidateSystemTemplate();
1055 RWLockReadLock(g_rwlockIdIndex, INFINITE);
1056 for(j = 0; j < g_dwIdIndexSize; j++)
1057 if (((NetObj *)g_pIndexById[j].pObject)->Type() == OBJECT_NODE)
1058 {
1059 if (((Node *)g_pIndexById[j].pObject)->IsSNMPSupported())
1060 pTemplate->ApplyToNode((Node *)g_pIndexById[j].pObject);
1061 }
1062 RWLockUnlock(g_rwlockIdIndex);
1063
1064 return TRUE;
1065}
1066
1067
1068//
1069// Delete user or group from all objects' ACLs
1070//
1071
1072void DeleteUserFromAllObjects(DWORD dwUserId)
1073{
1074 DWORD i;
1075
1076 // Walk through all objects
1077 RWLockReadLock(g_rwlockIdIndex, INFINITE);
1078 for(i = 0; i < g_dwIdIndexSize; i++)
1079 ((NetObj *)g_pIndexById[i].pObject)->DropUserAccess(dwUserId);
1080 RWLockUnlock(g_rwlockIdIndex);
1081}
1082
1083
1084//
1085// Dump objects to console in standalone mode
1086//
1087
1088void DumpObjects(CONSOLE_CTX pCtx)
1089{
1090 DWORD i;
1091 char *pBuffer;
1092 CONTAINER_CATEGORY *pCat;
1093 NetObj *pObject;
1094
1095 pBuffer = (char *)malloc(128000);
1096 RWLockReadLock(g_rwlockIdIndex, INFINITE);
1097 for(i = 0; i < g_dwIdIndexSize; i++)
1098 {
1099 pObject = (NetObj *)g_pIndexById[i].pObject;
1100 ConsolePrintf(pCtx, "Object ID %d \"%s\"\n"
1101 " Class: %s Primary IP: %s Status: %s IsModified: %d IsDeleted: %d\n",
1102 pObject->Id(), pObject->Name(), g_szClassName[pObject->Type()],
1103 IpToStr(pObject->IpAddr(), pBuffer),
1104 g_szStatusTextSmall[pObject->Status()],
1105 pObject->IsModified(), pObject->IsDeleted());
1106 ConsolePrintf(pCtx, " Parents: <%s>\n Childs: <%s>\n",
1107 pObject->ParentList(pBuffer), pObject->ChildList(&pBuffer[4096]));
1108 ConsolePrintf(pCtx, " Last change: %s", pObject->TimeStampAsText());
1109 switch(pObject->Type())
1110 {
1111 case OBJECT_NODE:
1112 ConsolePrintf(pCtx, " IsSNMP: %d IsAgent: %d IsLocal: %d OID: %s\n",
1113 ((Node *)pObject)->IsSNMPSupported(),
1114 ((Node *)pObject)->IsNativeAgent(),
1115 ((Node *)pObject)->IsLocalManagement(),
1116 ((Node *)pObject)->ObjectId());
1117 break;
1118 case OBJECT_SUBNET:
1119 ConsolePrintf(pCtx, " Network mask: %s\n",
1120 IpToStr(((Subnet *)pObject)->IpNetMask(), pBuffer));
1121 break;
1122 case OBJECT_CONTAINER:
1123 pCat = FindContainerCategory(((Container *)pObject)->Category());
1124 ConsolePrintf(pCtx, " Category: %s\n", pCat ? pCat->szName : "<unknown>");
1125 break;
1126 case OBJECT_TEMPLATE:
1127 ConsolePrintf(pCtx, " Version: %d.%d\n",
1128 ((Template *)(pObject))->VersionMajor(),
1129 ((Template *)(pObject))->VersionMinor());
1130 break;
1131 }
1132 }
1133 RWLockUnlock(g_rwlockIdIndex);
1134 free(pBuffer);
1135}
1136
1137
1138//
1139// Check is given object class is a valid parent class for other object
1140// This function is used to check manually created bindings, so it won't
1141// return TRUE for node -- subnet for example
1142//
1143
1144BOOL IsValidParentClass(int iChildClass, int iParentClass)
1145{
1146 switch(iParentClass)
1147 {
1148 case OBJECT_SERVICEROOT:
1149 case OBJECT_CONTAINER:
1150 if ((iChildClass == OBJECT_CONTAINER) ||
1151 (iChildClass == OBJECT_NODE) ||
1152 (iChildClass == OBJECT_CLUSTER) ||
1153 (iChildClass == OBJECT_CONDITION))
1154 return TRUE;
1155 break;
1156 case OBJECT_TEMPLATEROOT:
1157 case OBJECT_TEMPLATEGROUP:
1158 if ((iChildClass == OBJECT_TEMPLATEGROUP) ||
1159 (iChildClass == OBJECT_TEMPLATE))
1160 return TRUE;
1161 break;
1162 case OBJECT_NODE:
1163 if ((iChildClass == OBJECT_NETWORKSERVICE) ||
1164 (iChildClass == OBJECT_VPNCONNECTOR))
1165 return TRUE;
1166 break;
1167 case OBJECT_CLUSTER:
1168 if (iChildClass == OBJECT_NODE)
1169 return TRUE;
1170 break;
1171 case -1: // Creating object without parent
1172 if (iChildClass == OBJECT_NODE)
1173 return TRUE; // OK only for nodes, because parent subnet will be created automatically
1174 break;
1175 }
1176 return FALSE;
1177}
1178
1179
1180//
1181// Delete object (final step)
1182// This function should be called ONLY from syncer thread
1183// Access to object index by id are write-locked when this function is called
1184// Object will be removed from index by ID and destroyed.
1185//
1186
1187void NetObjDelete(NetObj *pObject)
1188{
1189 TCHAR szQuery[256], szIpAddr[16], szNetMask[16];
1190
1191 // Write object to deleted objects table
1192 _sntprintf(szQuery, 256, _T("INSERT INTO deleted_objects (object_id,object_class,name,"
1193 "ip_addr,ip_netmask) VALUES (%d,%d,'%s','%s','%s')"),
1194 pObject->Id(), pObject->Type(), pObject->Name(),
1195 IpToStr(pObject->IpAddr(), szIpAddr),
1196 IpToStr(GetObjectNetmask(pObject), szNetMask));
1197 QueueSQLRequest(szQuery);
1198
1199 // Delete object from index by ID and object itself
1200 DeleteObjectFromIndex(&g_pIndexById, &g_dwIdIndexSize, pObject->Id());
1201 delete pObject;
1202}
1203
1204
1205//
1206// Update node index when primary IP address changes
1207//
1208
1209void UpdateNodeIndex(DWORD dwOldIpAddr, DWORD dwNewIpAddr, NetObj *pObject)
1210{
1211 DWORD dwPos;
1212
1213 RWLockWriteLock(g_rwlockNodeIndex, INFINITE);
1214 dwPos = SearchIndex(g_pNodeIndexByAddr, g_dwNodeAddrIndexSize, dwOldIpAddr);
1215 if (dwPos != INVALID_INDEX)
1216 {
1217 g_pNodeIndexByAddr[dwPos].dwKey = dwNewIpAddr;
1218 qsort(g_pNodeIndexByAddr, g_dwNodeAddrIndexSize, sizeof(INDEX), IndexCompare);
1219 }
1220 else
1221 {
1222 AddObjectToIndex(&g_pNodeIndexByAddr, &g_dwNodeAddrIndexSize, dwNewIpAddr, pObject);
1223 }
1224 RWLockUnlock(g_rwlockNodeIndex);
1225}
1226
1227
1228//
1229// Update interface index when IP address changes
1230//
1231
1232void UpdateInterfaceIndex(DWORD dwOldIpAddr, DWORD dwNewIpAddr, NetObj *pObject)
1233{
1234 DWORD dwPos;
1235
1236 RWLockWriteLock(g_rwlockInterfaceIndex, INFINITE);
1237 dwPos = SearchIndex(g_pInterfaceIndexByAddr, g_dwInterfaceAddrIndexSize, dwOldIpAddr);
1238 if (dwPos != INVALID_INDEX)
1239 {
1240 g_pInterfaceIndexByAddr[dwPos].dwKey = dwNewIpAddr;
1241 qsort(g_pInterfaceIndexByAddr, g_dwInterfaceAddrIndexSize, sizeof(INDEX), IndexCompare);
1242 }
1243 else
1244 {
1245 AddObjectToIndex(&g_pInterfaceIndexByAddr, &g_dwInterfaceAddrIndexSize, dwNewIpAddr, pObject);
1246 }
1247 RWLockUnlock(g_rwlockInterfaceIndex);
1248}
1249
1250
1251//
1252// Calculate propagated status for object using default algorithm
1253//
1254
1255int DefaultPropagatedStatus(int iObjectStatus)
1256{
1257 int iStatus;
1258
1259 switch(m_iStatusPropAlg)
1260 {
1261 case SA_PROPAGATE_UNCHANGED:
1262 iStatus = iObjectStatus;
1263 break;
1264 case SA_PROPAGATE_FIXED:
1265 iStatus = ((iObjectStatus > STATUS_NORMAL) && (iObjectStatus < STATUS_UNKNOWN)) ? m_iFixedStatus : iObjectStatus;
1266 break;
1267 case SA_PROPAGATE_RELATIVE:
1268 if ((iObjectStatus > STATUS_NORMAL) && (iObjectStatus < STATUS_UNKNOWN))
1269 {
1270 iStatus = iObjectStatus + m_iStatusShift;
1271 if (iStatus < 0)
1272 iStatus = 0;
1273 if (iStatus > STATUS_CRITICAL)
1274 iStatus = STATUS_CRITICAL;
1275 }
1276 else
1277 {
1278 iStatus = iObjectStatus;
1279 }
1280 break;
1281 case SA_PROPAGATE_TRANSLATED:
1282 if ((iObjectStatus > STATUS_NORMAL) && (iObjectStatus < STATUS_UNKNOWN))
1283 {
1284 iStatus = m_iStatusTranslation[iObjectStatus - 1];
1285 }
1286 else
1287 {
1288 iStatus = iObjectStatus;
1289 }
1290 break;
1291 default:
1292 iStatus = STATUS_UNKNOWN;
1293 break;
1294 }
1295 return iStatus;
1296}
1297
1298
1299//
1300// Get default data for status calculation
1301//
1302
1303int GetDefaultStatusCalculation(int *pnSingleThreshold, int **ppnThresholds)
1304{
1305 *pnSingleThreshold = m_iStatusSingleThreshold;
1306 *ppnThresholds = m_iStatusThresholds;
1307 return m_iStatusCalcAlg;
1308}