schema-related information (like schema version, DB syntax, etc.) moved from "config...
[public/netxms.git] / src / server / core / objects.cpp
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
30 BOOL g_bModificationsLocked = FALSE;
31
32 Network *g_pEntireNet = NULL;
33 ServiceRoot *g_pServiceRoot = NULL;
34 TemplateRoot *g_pTemplateRoot = NULL;
35
36 DWORD NXCORE_EXPORTABLE g_dwMgmtNode = 0;
37 INDEX NXCORE_EXPORTABLE *g_pIndexById = NULL;
38 DWORD NXCORE_EXPORTABLE g_dwIdIndexSize = 0;
39 INDEX NXCORE_EXPORTABLE *g_pSubnetIndexByAddr = NULL;
40 DWORD NXCORE_EXPORTABLE g_dwSubnetAddrIndexSize = 0;
41 INDEX NXCORE_EXPORTABLE *g_pNodeIndexByAddr = NULL;
42 DWORD NXCORE_EXPORTABLE g_dwNodeAddrIndexSize = 0;
43 INDEX NXCORE_EXPORTABLE *g_pInterfaceIndexByAddr = NULL;
44 DWORD NXCORE_EXPORTABLE g_dwInterfaceAddrIndexSize = 0;
45 INDEX NXCORE_EXPORTABLE *g_pZoneIndexByGUID = NULL;
46 DWORD NXCORE_EXPORTABLE g_dwZoneGUIDIndexSize = 0;
47 INDEX NXCORE_EXPORTABLE *g_pConditionIndex = NULL;
48 DWORD NXCORE_EXPORTABLE g_dwConditionIndexSize = 0;
49
50 RWLOCK NXCORE_EXPORTABLE g_rwlockIdIndex;
51 RWLOCK NXCORE_EXPORTABLE g_rwlockNodeIndex;
52 RWLOCK NXCORE_EXPORTABLE g_rwlockSubnetIndex;
53 RWLOCK NXCORE_EXPORTABLE g_rwlockInterfaceIndex;
54 RWLOCK NXCORE_EXPORTABLE g_rwlockZoneIndex;
55 RWLOCK NXCORE_EXPORTABLE g_rwlockConditionIndex;
56
57 DWORD g_dwNumCategories = 0;
58 CONTAINER_CATEGORY *g_pContainerCatList = NULL;
59
60 Queue *g_pTemplateUpdateQueue = NULL;
61
62 const 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
73 static int m_iStatusCalcAlg = SA_CALCULATE_MOST_CRITICAL;
74 static int m_iStatusPropAlg = SA_PROPAGATE_UNCHANGED;
75 static int m_iFixedStatus; // Status if propagation is "Fixed"
76 static int m_iStatusShift; // Shift value for "shifted" status propagation
77 static int m_iStatusTranslation[4];
78 static int m_iStatusSingleThreshold;
79 static int m_iStatusThresholds[4];
80
81
82 //
83 // Thread which apply template updates
84 //
85
86 static 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
154 static 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
175 void 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
217 static 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
228 void 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
244 DWORD 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
276 void 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
294 void 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
307 MetaDataReadStr("IDataTableCreationCommand", szQueryTemplate, 255, "");
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);
314 MetaDataReadStr(szQuery, szQueryTemplate, 255, "");
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
391 void 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
450 static 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
468 Node 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
488 Subnet 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
508 Subnet 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
533 NetObj 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
553 NetObj 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
580 Template 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
607 Zone 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
627 DWORD 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
650 BOOL 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
1072 void 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
1088 void 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
1144 BOOL 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
1187 void 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
1209 void 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
1232 void 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
1255 int 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
1303 int GetDefaultStatusCalculation(int *pnSingleThreshold, int **ppnThresholds)
1304 {
1305 *pnSingleThreshold = m_iStatusSingleThreshold;
1306 *ppnThresholds = m_iStatusThresholds;
1307 return m_iStatusCalcAlg;
1308 }