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