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