Templates fully implemented
[public/netxms.git] / src / server / core / objects.cpp
CommitLineData
67e0e2f7 1/*
7eb995db
VK
2** NetXMS - Network Management System
3** Copyright (C) 2003, 2004 Victor Kirhenshtein
67e0e2f7
VK
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
a551fe4d 23#include "nxcore.h"
67e0e2f7
VK
24
25
26//
a68e217b 27// Global data
67e0e2f7
VK
28//
29
f54e7096
VK
30BOOL g_bModificationsLocked = FALSE;
31
e3d954e5
VK
32Network *g_pEntireNet = NULL;
33ServiceRoot *g_pServiceRoot = NULL;
62d11997 34TemplateRoot *g_pTemplateRoot = NULL;
e3d954e5 35
be0a5a53 36DWORD g_dwMgmtNode = 0;
a68e217b
VK
37INDEX *g_pIndexById = NULL;
38DWORD g_dwIdIndexSize = 0;
39INDEX *g_pSubnetIndexByAddr = NULL;
40DWORD g_dwSubnetAddrIndexSize = 0;
41INDEX *g_pNodeIndexByAddr = NULL;
42DWORD g_dwNodeAddrIndexSize = 0;
43INDEX *g_pInterfaceIndexByAddr = NULL;
44DWORD g_dwInterfaceAddrIndexSize = 0;
67e0e2f7 45
dbe67493
VK
46RWLOCK g_rwlockIdIndex;
47RWLOCK g_rwlockNodeIndex;
48RWLOCK g_rwlockSubnetIndex;
49RWLOCK g_rwlockInterfaceIndex;
be0a5a53 50
ef44d5ea
VK
51DWORD g_dwNumCategories = 0;
52CONTAINER_CATEGORY *g_pContainerCatList = NULL;
53
1cc04a08
VK
54Queue *g_pTemplateUpdateQueue = NULL;
55
eb8b1960
VK
56char *g_pszStatusName[] = { "Normal", "Warning", "Minor", "Major", "Critical",
57 "Unknown", "Unmanaged", "Disabled", "Testing" };
62d11997
VK
58char *g_szClassName[]={ "Generic", "Subnet", "Node", "Interface",
59 "Network", "Container", "Zone", "ServiceRoot",
4e839863 60 "Template", "TemplateGroup", "TemplateRoot", "NetworkService" };
eb8b1960 61
67e0e2f7 62
1cc04a08
VK
63//
64// Thread which apply template updates
65//
66
67static THREAD_RESULT THREAD_CALL ApplyTemplateThread(void *pArg)
68{
69 TEMPLATE_UPDATE_INFO *pInfo;
70 NetObj *pNode;
87efbd11 71 BOOL bSuccess, bLock1, bLock2;
1cc04a08
VK
72
73 while(1)
74 {
75 pInfo = (TEMPLATE_UPDATE_INFO *)g_pTemplateUpdateQueue->GetOrBlock();
76 if (pInfo == INVALID_POINTER_VALUE)
77 break;
78
87efbd11 79 bSuccess = FALSE;
1cc04a08
VK
80 pNode = FindObjectById(pInfo->dwNodeId);
81 if (pNode != NULL)
82 {
83 if (pNode->Type() == OBJECT_NODE)
84 {
87efbd11
VK
85 bLock1 = pInfo->pTemplate->LockDCIList(0x7FFFFFFF);
86 bLock2 = ((Node *)pNode)->LockDCIList(0x7FFFFFFF);
87 if (bLock1 && bLock2)
88 {
89 pInfo->pTemplate->ApplyToNode((Node *)pNode);
90 bSuccess = TRUE;
91 }
92 if (bLock1)
93 pInfo->pTemplate->UnlockDCIList(0x7FFFFFFF);
94 if (bLock2)
95 ((Node *)pNode)->UnlockDCIList(0x7FFFFFFF);
1cc04a08
VK
96 }
97 }
98
87efbd11
VK
99 if (bSuccess)
100 {
101 free(pInfo);
102 }
103 else
104 {
105 g_pTemplateUpdateQueue->Put(pInfo); // Requeue
106 ThreadSleepMs(500);
107 }
1cc04a08
VK
108 }
109
110 return THREAD_OK;
111}
112
113
67e0e2f7 114//
a68e217b 115// Initialize objects infrastructure
67e0e2f7
VK
116//
117
a68e217b 118void ObjectsInit(void)
67e0e2f7 119{
1cc04a08
VK
120 g_pTemplateUpdateQueue = new Queue;
121
dbe67493
VK
122 g_rwlockIdIndex = RWLockCreate();
123 g_rwlockNodeIndex = RWLockCreate();
124 g_rwlockSubnetIndex = RWLockCreate();
125 g_rwlockInterfaceIndex = RWLockCreate();
2da1357c
VK
126
127 // Create "Entire Network" object
128 g_pEntireNet = new Network;
cc140cce 129 NetObjInsert(g_pEntireNet, FALSE);
e3d954e5
VK
130
131 // Create "Service Root" object
132 g_pServiceRoot = new ServiceRoot;
133 NetObjInsert(g_pServiceRoot, FALSE);
62d11997
VK
134
135 // Create "Template Root" object
136 g_pTemplateRoot = new TemplateRoot;
137 NetObjInsert(g_pTemplateRoot, FALSE);
505ca1ae 138 DbgPrintf(AF_DEBUG_MISC, "Built-in objects created");
1cc04a08
VK
139
140 // Start template update applying thread
141 ThreadCreate(ApplyTemplateThread, 0, NULL);
67e0e2f7
VK
142}
143
144
59057edc
VK
145//
146// Function to compare two indexes
147//
148
149static int IndexCompare(const void *pArg1, const void *pArg2)
150{
151 return (((INDEX *)pArg1)->dwKey < ((INDEX *)pArg2)->dwKey) ? -1 :
152 ((((INDEX *)pArg1)->dwKey > ((INDEX *)pArg2)->dwKey) ? 1 : 0);
153}
154
155
67e0e2f7 156//
a68e217b 157// Add new object to index
67e0e2f7
VK
158//
159
a68e217b 160static void AddObjectToIndex(INDEX **ppIndex, DWORD *pdwIndexSize, DWORD dwKey, NetObj *pObject)
67e0e2f7 161{
59057edc
VK
162 *ppIndex = (INDEX *)realloc(*ppIndex, sizeof(INDEX) * ((*pdwIndexSize) + 1));
163 (*ppIndex)[*pdwIndexSize].dwKey = dwKey;
164 (*ppIndex)[*pdwIndexSize].pObject = pObject;
a68e217b 165 (*pdwIndexSize)++;
59057edc 166 qsort(*ppIndex, *pdwIndexSize, sizeof(INDEX), IndexCompare);
67e0e2f7
VK
167}
168
169
170//
a68e217b
VK
171// Perform binary search on index
172// Returns INVALID_INDEX if key not found or position of appropriate network object
173// We assume that pIndex == NULL will not be passed
67e0e2f7
VK
174//
175
a68e217b 176static DWORD SearchIndex(INDEX *pIndex, DWORD dwIndexSize, DWORD dwKey)
67e0e2f7 177{
a68e217b 178 DWORD dwFirst, dwLast, dwMid;
67e0e2f7 179
a68e217b
VK
180 dwFirst = 0;
181 dwLast = dwIndexSize - 1;
67e0e2f7 182
a68e217b
VK
183 if ((dwKey < pIndex[0].dwKey) || (dwKey > pIndex[dwLast].dwKey))
184 return INVALID_INDEX;
67e0e2f7 185
a68e217b
VK
186 while(dwFirst < dwLast)
187 {
188 dwMid = (dwFirst + dwLast) / 2;
189 if (dwKey == pIndex[dwMid].dwKey)
190 return dwMid;
191 if (dwKey < pIndex[dwMid].dwKey)
192 dwLast = dwMid - 1;
193 else
194 dwFirst = dwMid + 1;
195 }
67e0e2f7 196
a68e217b
VK
197 if (dwKey == pIndex[dwLast].dwKey)
198 return dwLast;
67e0e2f7 199
a68e217b 200 return INVALID_INDEX;
67e0e2f7
VK
201}
202
203
204//
a68e217b 205// Delete object from index
67e0e2f7
VK
206//
207
a68e217b 208static void DeleteObjectFromIndex(INDEX **ppIndex, DWORD *pdwIndexSize, DWORD dwKey)
67e0e2f7 209{
a68e217b
VK
210 DWORD dwPos;
211 INDEX *pIndex = *ppIndex;
67e0e2f7 212
a68e217b
VK
213 dwPos = SearchIndex(pIndex, *pdwIndexSize, dwKey);
214 if (dwPos != INVALID_INDEX)
215 {
216 (*pdwIndexSize)--;
217 memmove(&pIndex[dwPos], &pIndex[dwPos + 1], sizeof(INDEX) * (*pdwIndexSize - dwPos));
218 }
67e0e2f7
VK
219}
220
221
222//
a68e217b 223// Insert new object into network
67e0e2f7
VK
224//
225
cc140cce 226void NetObjInsert(NetObj *pObject, BOOL bNewObject)
67e0e2f7 227{
1275c750
VK
228 if (bNewObject)
229 {
230 // Assign unique ID to new object
3ea35b38 231 pObject->SetId(CreateUniqueId(IDG_NETWORK_OBJECT));
1275c750
VK
232
233 // Create table for storing data collection values
234 if (pObject->Type() == OBJECT_NODE)
235 {
236 char szQuery[256], szQueryTemplate[256];
52fe5aa2 237 DWORD i;
1275c750
VK
238
239 ConfigReadStr("IDataTableCreationCommand", szQueryTemplate, 255, "");
240 sprintf(szQuery, szQueryTemplate, pObject->Id());
241 DBQuery(g_hCoreDB, szQuery);
336ea27e 242
52fe5aa2 243 for(i = 0; i < 10; i++)
336ea27e 244 {
52fe5aa2
VK
245 sprintf(szQuery, "IDataIndexCreationCommand_%d", i);
246 ConfigReadStr(szQuery, szQueryTemplate, 255, "");
247 if (szQueryTemplate[0] != 0)
248 {
c13cb4a5 249 sprintf(szQuery, szQueryTemplate, pObject->Id(), pObject->Id());
52fe5aa2
VK
250 DBQuery(g_hCoreDB, szQuery);
251 }
336ea27e 252 }
1275c750
VK
253 }
254 }
dbe67493 255 RWLockWriteLock(g_rwlockIdIndex, INFINITE);
eefe7d68 256 AddObjectToIndex(&g_pIndexById, &g_dwIdIndexSize, pObject->Id(), pObject);
dbe67493 257 RWLockUnlock(g_rwlockIdIndex);
333ece94
VK
258 if ((pObject->IpAddr() != 0) && (!pObject->IsDeleted()))
259 {
48b1c0ac
VK
260 switch(pObject->Type())
261 {
262 case OBJECT_GENERIC:
263 case OBJECT_NETWORK:
ef44d5ea 264 case OBJECT_CONTAINER:
e3d954e5 265 case OBJECT_SERVICEROOT:
1a4e3eff 266 case OBJECT_NETWORKSERVICE:
48b1c0ac
VK
267 break;
268 case OBJECT_SUBNET:
dbe67493 269 RWLockWriteLock(g_rwlockSubnetIndex, INFINITE);
48b1c0ac 270 AddObjectToIndex(&g_pSubnetIndexByAddr, &g_dwSubnetAddrIndexSize, pObject->IpAddr(), pObject);
dbe67493 271 RWLockUnlock(g_rwlockSubnetIndex);
f9b7e653
VK
272 if (bNewObject)
273 PostEvent(EVENT_SUBNET_ADDED, pObject->Id(), NULL);
48b1c0ac
VK
274 break;
275 case OBJECT_NODE:
dbe67493 276 RWLockWriteLock(g_rwlockNodeIndex, INFINITE);
48b1c0ac 277 AddObjectToIndex(&g_pNodeIndexByAddr, &g_dwNodeAddrIndexSize, pObject->IpAddr(), pObject);
dbe67493 278 RWLockUnlock(g_rwlockNodeIndex);
f9b7e653
VK
279 if (bNewObject)
280 PostEvent(EVENT_NODE_ADDED, pObject->Id(), NULL);
48b1c0ac
VK
281 break;
282 case OBJECT_INTERFACE:
dbe67493 283 RWLockWriteLock(g_rwlockInterfaceIndex, INFINITE);
48b1c0ac 284 AddObjectToIndex(&g_pInterfaceIndexByAddr, &g_dwInterfaceAddrIndexSize, pObject->IpAddr(), pObject);
dbe67493 285 RWLockUnlock(g_rwlockInterfaceIndex);
48b1c0ac
VK
286 break;
287 default:
288 WriteLog(MSG_BAD_NETOBJ_TYPE, EVENTLOG_ERROR_TYPE, "d", pObject->Type());
289 break;
290 }
333ece94 291 }
67e0e2f7
VK
292}
293
294
295//
fb2ef88c
VK
296// Delete object from indexes
297// If object has an IP address, this function will delete it from
298// appropriate index. Normally this function should be called from
299// NetObj::Delete() method.
67e0e2f7
VK
300//
301
fb2ef88c 302void NetObjDeleteFromIndexes(NetObj *pObject)
67e0e2f7 303{
48b1c0ac
VK
304 if (pObject->IpAddr() != 0)
305 switch(pObject->Type())
306 {
307 case OBJECT_GENERIC:
308 case OBJECT_NETWORK:
ef44d5ea 309 case OBJECT_CONTAINER:
e3d954e5 310 case OBJECT_SERVICEROOT:
1a4e3eff 311 case OBJECT_NETWORKSERVICE:
48b1c0ac
VK
312 break;
313 case OBJECT_SUBNET:
dbe67493 314 RWLockWriteLock(g_rwlockSubnetIndex, INFINITE);
48b1c0ac 315 DeleteObjectFromIndex(&g_pSubnetIndexByAddr, &g_dwSubnetAddrIndexSize, pObject->IpAddr());
dbe67493 316 RWLockUnlock(g_rwlockSubnetIndex);
48b1c0ac
VK
317 break;
318 case OBJECT_NODE:
dbe67493 319 RWLockWriteLock(g_rwlockNodeIndex, INFINITE);
48b1c0ac 320 DeleteObjectFromIndex(&g_pNodeIndexByAddr, &g_dwNodeAddrIndexSize, pObject->IpAddr());
dbe67493 321 RWLockUnlock(g_rwlockNodeIndex);
48b1c0ac
VK
322 break;
323 case OBJECT_INTERFACE:
dbe67493 324 RWLockWriteLock(g_rwlockInterfaceIndex, INFINITE);
48b1c0ac 325 DeleteObjectFromIndex(&g_pInterfaceIndexByAddr, &g_dwInterfaceAddrIndexSize, pObject->IpAddr());
dbe67493 326 RWLockUnlock(g_rwlockInterfaceIndex);
48b1c0ac
VK
327 break;
328 default:
329 WriteLog(MSG_BAD_NETOBJ_TYPE, EVENTLOG_ERROR_TYPE, "d", pObject->Type());
330 break;
331 }
67e0e2f7 332}
eefe7d68
VK
333
334
fb2ef88c
VK
335//
336// Get IP netmask for object of any class
337//
338
4e839863 339static DWORD GetObjectNetmask(NetObj *pObject)
fb2ef88c
VK
340{
341 switch(pObject->Type())
342 {
343 case OBJECT_INTERFACE:
344 return ((Interface *)pObject)->IpNetMask();
345 case OBJECT_SUBNET:
346 return ((Subnet *)pObject)->IpNetMask();
347 default:
348 return 0;
349 }
350}
351
352
eefe7d68
VK
353//
354// Find node by IP address
355//
356
ded831ac 357Node NXCORE_EXPORTABLE *FindNodeByIP(DWORD dwAddr)
eefe7d68
VK
358{
359 DWORD dwPos;
be0a5a53 360 Node *pNode;
eefe7d68 361
48b1c0ac 362 if ((g_pInterfaceIndexByAddr == NULL) || (dwAddr == 0))
eefe7d68
VK
363 return NULL;
364
dbe67493 365 RWLockReadLock(g_rwlockInterfaceIndex, INFINITE);
eefe7d68 366 dwPos = SearchIndex(g_pInterfaceIndexByAddr, g_dwInterfaceAddrIndexSize, dwAddr);
be0a5a53 367 pNode = (dwPos == INVALID_INDEX) ? NULL : (Node *)g_pInterfaceIndexByAddr[dwPos].pObject->GetParent();
dbe67493 368 RWLockUnlock(g_rwlockInterfaceIndex);
be0a5a53 369 return pNode;
eefe7d68
VK
370}
371
372
373//
374// Find subnet by IP address
375//
376
ded831ac 377Subnet NXCORE_EXPORTABLE *FindSubnetByIP(DWORD dwAddr)
eefe7d68
VK
378{
379 DWORD dwPos;
be0a5a53 380 Subnet *pSubnet;
eefe7d68 381
48b1c0ac 382 if ((g_pSubnetIndexByAddr == NULL) || (dwAddr == 0))
eefe7d68
VK
383 return NULL;
384
dbe67493 385 RWLockReadLock(g_rwlockSubnetIndex, INFINITE);
eefe7d68 386 dwPos = SearchIndex(g_pSubnetIndexByAddr, g_dwSubnetAddrIndexSize, dwAddr);
be0a5a53 387 pSubnet = (dwPos == INVALID_INDEX) ? NULL : (Subnet *)g_pSubnetIndexByAddr[dwPos].pObject;
dbe67493
VK
388 RWLockUnlock(g_rwlockSubnetIndex);
389 return pSubnet;
390}
391
392
393//
394// Find subnet for given IP address
395//
396
ded831ac 397Subnet NXCORE_EXPORTABLE *FindSubnetForNode(DWORD dwNodeAddr)
dbe67493
VK
398{
399 DWORD i;
400 Subnet *pSubnet = NULL;
401
402 if ((g_pSubnetIndexByAddr == NULL) || (dwNodeAddr == 0))
403 return NULL;
404
405 RWLockReadLock(g_rwlockSubnetIndex, INFINITE);
406 for(i = 0; i < g_dwSubnetAddrIndexSize; i++)
407 if ((dwNodeAddr & ((Subnet *)g_pSubnetIndexByAddr[i].pObject)->IpNetMask()) ==
408 ((Subnet *)g_pSubnetIndexByAddr[i].pObject)->IpAddr())
409 {
410 pSubnet = (Subnet *)g_pSubnetIndexByAddr[i].pObject;
411 break;
412 }
413 RWLockUnlock(g_rwlockSubnetIndex);
be0a5a53 414 return pSubnet;
eefe7d68 415}
2da1357c
VK
416
417
418//
419// Find object by ID
420//
421
ded831ac 422NetObj NXCORE_EXPORTABLE *FindObjectById(DWORD dwId)
2da1357c
VK
423{
424 DWORD dwPos;
be0a5a53 425 NetObj *pObject;
2da1357c
VK
426
427 if (g_pIndexById == NULL)
428 return NULL;
429
dbe67493 430 RWLockReadLock(g_rwlockIdIndex, INFINITE);
2da1357c 431 dwPos = SearchIndex(g_pIndexById, g_dwIdIndexSize, dwId);
be0a5a53 432 pObject = (dwPos == INVALID_INDEX) ? NULL : g_pIndexById[dwPos].pObject;
dbe67493 433 RWLockUnlock(g_rwlockIdIndex);
be0a5a53 434 return pObject;
2da1357c
VK
435}
436
437
f91fa4c2
VK
438//
439// Find local management node ID
440//
441
442DWORD FindLocalMgmtNode(void)
443{
be0a5a53 444 DWORD i, dwId = 0;
f91fa4c2
VK
445
446 if (g_pNodeIndexByAddr == NULL)
447 return 0;
448
dbe67493 449 RWLockReadLock(g_rwlockNodeIndex, INFINITE);
f91fa4c2
VK
450 for(i = 0; i < g_dwNodeAddrIndexSize; i++)
451 if (((Node *)g_pNodeIndexByAddr[i].pObject)->Flags() & NF_IS_LOCAL_MGMT)
be0a5a53
VK
452 {
453 dwId = g_pNodeIndexByAddr[i].pObject->Id();
454 break;
455 }
dbe67493 456 RWLockUnlock(g_rwlockNodeIndex);
be0a5a53 457 return dwId;
f91fa4c2
VK
458}
459
460
2da1357c
VK
461//
462// Load objects from database at stratup
463//
464
465BOOL LoadObjects(void)
466{
467 DB_RESULT hResult;
ef44d5ea 468 DWORD i, dwNumRows;
2da1357c 469 DWORD dwId;
62d11997 470 char szQuery[256];
2da1357c 471
f54e7096
VK
472 // Prevent objects to change it's modification flag
473 g_bModificationsLocked = TRUE;
474
ef44d5ea 475 // Load container categories
52fe5aa2 476 DbgPrintf(AF_DEBUG_MISC, "Loading container categories...");
ef44d5ea
VK
477 hResult = DBSelect(g_hCoreDB, "SELECT category,name,image_id,description FROM container_categories");
478 if (hResult != NULL)
479 {
480 g_dwNumCategories = DBGetNumRows(hResult);
481 g_pContainerCatList = (CONTAINER_CATEGORY *)malloc(sizeof(CONTAINER_CATEGORY) * g_dwNumCategories);
482 for(i = 0; i < (int)g_dwNumCategories; i++)
483 {
484 g_pContainerCatList[i].dwCatId = DBGetFieldULong(hResult, i, 0);
485 strncpy(g_pContainerCatList[i].szName, DBGetField(hResult, i, 1), MAX_OBJECT_NAME);
6849d9be 486 g_pContainerCatList[i].dwImageId = DBGetFieldULong(hResult, i, 2);
ef44d5ea
VK
487 g_pContainerCatList[i].pszDescription = strdup(DBGetField(hResult, i, 3));
488 }
489 DBFreeResult(hResult);
490 }
491
e3d954e5 492 // Load built-in object properties
52fe5aa2 493 DbgPrintf(AF_DEBUG_MISC, "Loading built-in object properties...");
de78f964 494 g_pEntireNet->LoadFromDB();
e3d954e5 495 g_pServiceRoot->LoadFromDB();
62d11997 496 g_pTemplateRoot->LoadFromDB();
de78f964 497
2da1357c 498 // Load subnets
52fe5aa2 499 DbgPrintf(AF_DEBUG_MISC, "Loading subnets...");
333ece94 500 hResult = DBSelect(g_hCoreDB, "SELECT id FROM subnets");
2da1357c
VK
501 if (hResult != 0)
502 {
503 Subnet *pSubnet;
504
ef44d5ea
VK
505 dwNumRows = DBGetNumRows(hResult);
506 for(i = 0; i < dwNumRows; i++)
2da1357c
VK
507 {
508 dwId = DBGetFieldULong(hResult, i, 0);
509 pSubnet = new Subnet;
510 if (pSubnet->CreateFromDB(dwId))
511 {
333ece94
VK
512 if (!pSubnet->IsDeleted())
513 g_pEntireNet->AddSubnet(pSubnet);
cc140cce 514 NetObjInsert(pSubnet, FALSE); // Insert into indexes
2da1357c
VK
515 }
516 else // Object load failed
517 {
518 delete pSubnet;
cc140cce 519 WriteLog(MSG_SUBNET_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
2da1357c
VK
520 }
521 }
522 DBFreeResult(hResult);
523 }
cc140cce
VK
524
525 // Load nodes
52fe5aa2 526 DbgPrintf(AF_DEBUG_MISC, "Loading nodes...");
333ece94 527 hResult = DBSelect(g_hCoreDB, "SELECT id FROM nodes");
cc140cce
VK
528 if (hResult != 0)
529 {
530 Node *pNode;
531
ef44d5ea
VK
532 dwNumRows = DBGetNumRows(hResult);
533 for(i = 0; i < dwNumRows; i++)
cc140cce
VK
534 {
535 dwId = DBGetFieldULong(hResult, i, 0);
536 pNode = new Node;
537 if (pNode->CreateFromDB(dwId))
538 {
539 NetObjInsert(pNode, FALSE); // Insert into indexes
540 }
541 else // Object load failed
542 {
543 delete pNode;
544 WriteLog(MSG_NODE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
545 }
546 }
547 DBFreeResult(hResult);
548 }
549
550 // Load interfaces
52fe5aa2 551 DbgPrintf(AF_DEBUG_MISC, "Loading interfaces...");
333ece94 552 hResult = DBSelect(g_hCoreDB, "SELECT id FROM interfaces");
cc140cce
VK
553 if (hResult != 0)
554 {
555 Interface *pInterface;
556
ef44d5ea
VK
557 dwNumRows = DBGetNumRows(hResult);
558 for(i = 0; i < dwNumRows; i++)
cc140cce
VK
559 {
560 dwId = DBGetFieldULong(hResult, i, 0);
561 pInterface = new Interface;
562 if (pInterface->CreateFromDB(dwId))
563 {
564 NetObjInsert(pInterface, FALSE); // Insert into indexes
565 }
566 else // Object load failed
567 {
568 delete pInterface;
569 WriteLog(MSG_INTERFACE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
570 }
571 }
572 DBFreeResult(hResult);
573 }
574
f382dc88 575 // Load network services
52fe5aa2 576 DbgPrintf(AF_DEBUG_MISC, "Loading network services...");
f382dc88
VK
577 hResult = DBSelect(g_hCoreDB, "SELECT id FROM network_services");
578 if (hResult != 0)
579 {
580 NetworkService *pService;
581
582 dwNumRows = DBGetNumRows(hResult);
583 for(i = 0; i < dwNumRows; i++)
584 {
585 dwId = DBGetFieldULong(hResult, i, 0);
586 pService = new NetworkService;
587 if (pService->CreateFromDB(dwId))
588 {
589 NetObjInsert(pService, FALSE); // Insert into indexes
590 }
591 else // Object load failed
592 {
593 delete pService;
594 WriteLog(MSG_NETSRV_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
595 }
596 }
597 DBFreeResult(hResult);
598 }
599
62d11997 600 // Load templates
52fe5aa2 601 DbgPrintf(AF_DEBUG_MISC, "Loading templates...");
62d11997
VK
602 hResult = DBSelect(g_hCoreDB, "SELECT id FROM templates");
603 if (hResult != 0)
604 {
605 Template *pTemplate;
606
607 dwNumRows = DBGetNumRows(hResult);
608 for(i = 0; i < dwNumRows; i++)
609 {
610 dwId = DBGetFieldULong(hResult, i, 0);
611 pTemplate = new Template;
612 if (pTemplate->CreateFromDB(dwId))
613 {
614 NetObjInsert(pTemplate, FALSE); // Insert into indexes
615 }
616 else // Object load failed
617 {
618 delete pTemplate;
619 WriteLog(MSG_TEMPLATE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
620 }
621 }
622 DBFreeResult(hResult);
623 }
624
ef44d5ea 625 // Load container objects
52fe5aa2 626 DbgPrintf(AF_DEBUG_MISC, "Loading containers...");
62d11997
VK
627 sprintf(szQuery, "SELECT id FROM containers WHERE object_class=%d", OBJECT_CONTAINER);
628 hResult = DBSelect(g_hCoreDB, szQuery);
ef44d5ea
VK
629 if (hResult != 0)
630 {
631 Container *pContainer;
632
633 dwNumRows = DBGetNumRows(hResult);
634 for(i = 0; i < dwNumRows; i++)
635 {
636 dwId = DBGetFieldULong(hResult, i, 0);
637 pContainer = new Container;
638 if (pContainer->CreateFromDB(dwId))
639 {
640 NetObjInsert(pContainer, FALSE); // Insert into indexes
641 }
642 else // Object load failed
643 {
644 delete pContainer;
645 WriteLog(MSG_CONTAINER_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
646 }
647 }
648 DBFreeResult(hResult);
649 }
650
62d11997 651 // Load template group objects
52fe5aa2 652 DbgPrintf(AF_DEBUG_MISC, "Loading template groups...");
62d11997
VK
653 sprintf(szQuery, "SELECT id FROM containers WHERE object_class=%d", OBJECT_TEMPLATEGROUP);
654 hResult = DBSelect(g_hCoreDB, szQuery);
655 if (hResult != 0)
656 {
657 TemplateGroup *pGroup;
658
659 dwNumRows = DBGetNumRows(hResult);
660 for(i = 0; i < dwNumRows; i++)
661 {
662 dwId = DBGetFieldULong(hResult, i, 0);
663 pGroup = new TemplateGroup;
664 if (pGroup->CreateFromDB(dwId))
665 {
666 NetObjInsert(pGroup, FALSE); // Insert into indexes
667 }
668 else // Object load failed
669 {
670 delete pGroup;
671 WriteLog(MSG_TG_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
672 }
673 }
674 DBFreeResult(hResult);
675 }
676
677 // Link childs to container and template group objects
52fe5aa2 678 DbgPrintf(AF_DEBUG_MISC, "Linking objects...");
ef44d5ea 679 for(i = 0; i < g_dwIdIndexSize; i++)
62d11997
VK
680 if ((g_pIndexById[i].pObject->Type() == OBJECT_CONTAINER) ||
681 (g_pIndexById[i].pObject->Type() == OBJECT_TEMPLATEGROUP))
ef44d5ea
VK
682 ((Container *)g_pIndexById[i].pObject)->LinkChildObjects();
683
62d11997 684 // Link childs to "Service Root" and "Template Root" objects
e3d954e5 685 g_pServiceRoot->LinkChildObjects();
62d11997 686 g_pTemplateRoot->LinkChildObjects();
e3d954e5 687
f54e7096
VK
688 // Allow objects to change it's modification flag
689 g_bModificationsLocked = FALSE;
690
62d11997 691 // Recalculate status for built-in objects
f00307b7 692 g_pEntireNet->CalculateCompoundStatus();
e3d954e5 693 g_pServiceRoot->CalculateCompoundStatus();
62d11997 694 g_pTemplateRoot->CalculateCompoundStatus();
f00307b7 695
2da1357c
VK
696 return TRUE;
697}
ff550544
VK
698
699
700//
701// Delete user or group from all objects' ACLs
702//
703
704void DeleteUserFromAllObjects(DWORD dwUserId)
705{
706 DWORD i;
707
ff550544 708 // Walk through all objects
dbe67493 709 RWLockReadLock(g_rwlockIdIndex, INFINITE);
ff550544
VK
710 for(i = 0; i < g_dwIdIndexSize; i++)
711 g_pIndexById[i].pObject->DropUserAccess(dwUserId);
dbe67493 712 RWLockUnlock(g_rwlockIdIndex);
ff550544 713}
04738fd8
VK
714
715
716//
717// Dump objects to console in standalone mode
718//
719
a63ffcdd 720void DumpObjects(CONSOLE_CTX pCtx)
04738fd8
VK
721{
722 DWORD i;
723 char *pBuffer;
ef44d5ea 724 CONTAINER_CATEGORY *pCat;
04738fd8
VK
725
726 pBuffer = (char *)malloc(128000);
dbe67493 727 RWLockReadLock(g_rwlockIdIndex, INFINITE);
04738fd8
VK
728 for(i = 0; i < g_dwIdIndexSize; i++)
729 {
a63ffcdd
VK
730 ConsolePrintf(pCtx, "Object ID %d \"%s\"\n"
731 " Class: %s Primary IP: %s Status: %s IsModified: %d IsDeleted: %d\n",
732 g_pIndexById[i].pObject->Id(),g_pIndexById[i].pObject->Name(),
733 g_szClassName[g_pIndexById[i].pObject->Type()],
734 IpToStr(g_pIndexById[i].pObject->IpAddr(), pBuffer),
735 g_pszStatusName[g_pIndexById[i].pObject->Status()],
736 g_pIndexById[i].pObject->IsModified(), g_pIndexById[i].pObject->IsDeleted());
737 ConsolePrintf(pCtx, " Parents: <%s>\n Childs: <%s>\n",
738 g_pIndexById[i].pObject->ParentList(pBuffer),
739 g_pIndexById[i].pObject->ChildList(&pBuffer[4096]));
740 ConsolePrintf(pCtx, " Last change: %s\n", g_pIndexById[i].pObject->TimeStampAsText());
04738fd8
VK
741 switch(g_pIndexById[i].pObject->Type())
742 {
743 case OBJECT_NODE:
a63ffcdd
VK
744 ConsolePrintf(pCtx, " IsSNMP: %d IsAgent: %d IsLocal: %d OID: %s\n",
745 ((Node *)(g_pIndexById[i].pObject))->IsSNMPSupported(),
746 ((Node *)(g_pIndexById[i].pObject))->IsNativeAgent(),
747 ((Node *)(g_pIndexById[i].pObject))->IsLocalManagement(),
748 ((Node *)(g_pIndexById[i].pObject))->ObjectId());
04738fd8
VK
749 break;
750 case OBJECT_SUBNET:
a63ffcdd
VK
751 ConsolePrintf(pCtx, " Network mask: %s\n",
752 IpToStr(((Subnet *)g_pIndexById[i].pObject)->IpNetMask(), pBuffer));
04738fd8 753 break;
ef44d5ea
VK
754 case OBJECT_CONTAINER:
755 pCat = FindContainerCategory(((Container *)g_pIndexById[i].pObject)->Category());
a63ffcdd
VK
756 ConsolePrintf(pCtx, " Category: %s\n Description: %s\n", pCat ? pCat->szName : "<unknown>",
757 ((Container *)g_pIndexById[i].pObject)->Description());
ef44d5ea 758 break;
70573ffe 759 case OBJECT_TEMPLATE:
a63ffcdd
VK
760 ConsolePrintf(pCtx, " Version: %d.%d\n Description: %s\n",
761 ((Template *)(g_pIndexById[i].pObject))->VersionMajor(),
762 ((Template *)(g_pIndexById[i].pObject))->VersionMinor(),
763 ((Template *)(g_pIndexById[i].pObject))->Description());
70573ffe 764 break;
04738fd8
VK
765 }
766 }
dbe67493 767 RWLockUnlock(g_rwlockIdIndex);
04738fd8
VK
768 free(pBuffer);
769}
62d11997
VK
770
771
772//
773// Check is given object class is a valid parent class for other object
774// This function is used to check manually created bindings, so i won't
775// return TRUE for node -- subnet for example
776//
777
778BOOL IsValidParentClass(int iChildClass, int iParentClass)
779{
780 switch(iParentClass)
781 {
782 case OBJECT_SERVICEROOT:
783 case OBJECT_CONTAINER:
784 if ((iChildClass == OBJECT_CONTAINER) ||
785 (iChildClass == OBJECT_NODE))
786 return TRUE;
787 break;
788 case OBJECT_TEMPLATEROOT:
789 case OBJECT_TEMPLATEGROUP:
790 if ((iChildClass == OBJECT_TEMPLATEGROUP) ||
791 (iChildClass == OBJECT_TEMPLATE))
792 return TRUE;
793 break;
b61fe31e
VK
794 case OBJECT_NODE:
795 if (iChildClass == OBJECT_NETWORKSERVICE)
796 return TRUE;
797 break;
b688074e
VK
798 case -1: // Creating object without parent
799 if (iChildClass == OBJECT_NODE)
800 return TRUE; // OK only for nodes, because parent subnet will be created automatically
801 break;
62d11997
VK
802 }
803 return FALSE;
804}
4e839863
VK
805
806
807//
808// Delete object (final step)
809// This function should be called ONLY from syncer thread
810// Access to object index by id are write-locked when this function is called
811// Object will be removed from index by ID and destroyed.
812//
813
814void NetObjDelete(NetObj *pObject)
815{
816 char szQuery[256], szIpAddr[16], szNetMask[16];
817
818 // Write object to deleted objects table
819 _sntprintf(szQuery, 256, _T("INSERT INTO deleted_objects (object_id,object_class,name,"
820 "ip_addr,ip_netmask) VALUES (%ld,%ld,'%s','%s','%s')"),
821 pObject->Id(), pObject->Type(), pObject->Name(),
822 IpToStr(pObject->IpAddr(), szIpAddr),
823 IpToStr(GetObjectNetmask(pObject), szNetMask));
824 DBQuery(g_hCoreDB, szQuery);
825
826 // Delete object from index by ID and object itself
827 DeleteObjectFromIndex(&g_pIndexById, &g_dwIdIndexSize, pObject->Id());
828 delete pObject;
829}