Initial support for object deletion by operator
[public/netxms.git] / src / server / core / node.cpp
CommitLineData
eefe7d68 1/*
1275c750 2** NetXMS - Network Management System
eefe7d68
VK
3** Copyright (C) 2003 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: node.cpp
20**
21**/
22
23#include "nms_core.h"
24
25
26//
27// Node class default constructor
28//
29
30Node::Node()
31 :NetObj()
32{
33 m_dwFlags = 0;
34 m_dwDiscoveryFlags = 0;
2da1357c
VK
35 m_wAgentPort = AGENT_LISTEN_PORT;
36 m_wAuthMethod = AUTH_NONE;
37 m_szSharedSecret[0] = 0;
38 m_iStatusPollType = POLL_ICMP_PING;
469b937c 39 m_iSNMPVersion = SNMP_VERSION_1;
2da1357c 40 strcpy(m_szCommunityString, "public");
469b937c 41 m_szObjectId[0] = 0;
48b1c0ac 42 m_tLastDiscoveryPoll = 0;
f00307b7 43 m_tLastStatusPoll = 0;
364aa19a
VK
44 m_tLastConfigurationPoll = 0;
45 m_iSnmpAgentFails = 0;
46 m_iNativeAgentFails = 0;
323f8bec 47 m_hPollerMutex = MutexCreate();
3ea35b38 48 m_hAgentAccessMutex = MutexCreate();
6f595ce2 49 m_dwNumItems = 0;
3ea35b38 50 m_ppItems = NULL;
1275c750 51 m_pAgentConnection = NULL;
3c55b85d 52 m_dwDCILockStatus = INVALID_INDEX;
eefe7d68
VK
53}
54
55
56//
57// Constructor for new node object
58//
59
60Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwDiscoveryFlags)
61 :NetObj()
62{
63 m_dwIpAddr = dwAddr;
64 m_dwFlags = dwFlags;
65 m_dwDiscoveryFlags = dwDiscoveryFlags;
2da1357c
VK
66 m_wAgentPort = AGENT_LISTEN_PORT;
67 m_wAuthMethod = AUTH_NONE;
68 m_szSharedSecret[0] = 0;
69 m_iStatusPollType = POLL_ICMP_PING;
469b937c 70 m_iSNMPVersion = SNMP_VERSION_1;
2da1357c 71 strcpy(m_szCommunityString, "public");
cc140cce 72 IpToStr(dwAddr, m_szName); // Make default name from IP address
469b937c 73 m_szObjectId[0] = 0;
48b1c0ac 74 m_tLastDiscoveryPoll = 0;
f00307b7 75 m_tLastStatusPoll = 0;
364aa19a
VK
76 m_tLastConfigurationPoll = 0;
77 m_iSnmpAgentFails = 0;
78 m_iNativeAgentFails = 0;
323f8bec 79 m_hPollerMutex = MutexCreate();
3ea35b38 80 m_hAgentAccessMutex = MutexCreate();
6f595ce2 81 m_dwNumItems = 0;
3ea35b38 82 m_ppItems = NULL;
1275c750 83 m_pAgentConnection = NULL;
3c55b85d 84 m_dwDCILockStatus = INVALID_INDEX;
eefe7d68
VK
85}
86
87
88//
89// Node destructor
90//
91
92Node::~Node()
93{
323f8bec 94 MutexDestroy(m_hPollerMutex);
3ea35b38
VK
95 MutexDestroy(m_hAgentAccessMutex);
96 DestroyItems();
1275c750
VK
97 if (m_pAgentConnection != NULL)
98 delete m_pAgentConnection;
eefe7d68
VK
99}
100
101
3ea35b38
VK
102//
103// Destroy all related data collection items
104//
105
106void Node::DestroyItems(void)
107{
108 DWORD i;
109
110 for(i = 0; i < m_dwNumItems; i++)
111 delete m_ppItems[i];
112 safe_free(m_ppItems);
113 m_dwNumItems = 0;
114 m_ppItems = NULL;
115}
116
117
2da1357c
VK
118//
119// Create object from database data
120//
121
122BOOL Node::CreateFromDB(DWORD dwId)
123{
124 char szQuery[256];
125 DB_RESULT hResult;
126 int i, iNumRows;
127 DWORD dwSubnetId;
128 NetObj *pObject;
129
130 sprintf(szQuery, "SELECT id,name,status,primary_ip,is_snmp,is_agent,is_bridge,"
131 "is_router,snmp_version,discovery_flags,auth_method,secret,"
2a41a4b5
VK
132 "agent_port,status_poll_type,community,snmp_oid,is_local_mgmt,"
133 "image_id FROM nodes WHERE id=%d", dwId);
2da1357c
VK
134 hResult = DBSelect(g_hCoreDB, szQuery);
135 if (hResult == 0)
136 return FALSE; // Query failed
137
138 if (DBGetNumRows(hResult) == 0)
139 {
140 DBFreeResult(hResult);
141 return FALSE;
142 }
143
144 m_dwId = dwId;
145 strncpy(m_szName, DBGetField(hResult, 0, 1), MAX_OBJECT_NAME);
146 m_iStatus = DBGetFieldLong(hResult, 0, 2);
147 m_dwIpAddr = DBGetFieldULong(hResult, 0, 3);
148
149 // Flags
150 if (DBGetFieldLong(hResult, 0, 4))
151 m_dwFlags |= NF_IS_SNMP;
152 if (DBGetFieldLong(hResult, 0, 5))
153 m_dwFlags |= NF_IS_NATIVE_AGENT;
154 if (DBGetFieldLong(hResult, 0, 6))
155 m_dwFlags |= NF_IS_BRIDGE;
156 if (DBGetFieldLong(hResult, 0, 7))
157 m_dwFlags |= NF_IS_ROUTER;
ce19c304
VK
158 if (DBGetFieldLong(hResult, 0, 16))
159 m_dwFlags |= NF_IS_LOCAL_MGMT;
2da1357c
VK
160
161 m_iSNMPVersion = DBGetFieldLong(hResult, 0, 8);
162 m_dwDiscoveryFlags = DBGetFieldULong(hResult, 0, 9);
163 m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 10);
164 strncpy(m_szSharedSecret, DBGetField(hResult, 0, 11), MAX_SECRET_LENGTH);
165 m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 12);
166 m_iStatusPollType = DBGetFieldLong(hResult, 0, 13);
167 strncpy(m_szCommunityString, DBGetField(hResult, 0, 14), MAX_COMMUNITY_LENGTH);
a0495b6e 168 strncpy(m_szObjectId, DBGetField(hResult, 0, 15), MAX_OID_LEN * 4);
cb151d1e 169 m_dwImageId = DBGetFieldULong(hResult, 0, 17);
2da1357c
VK
170
171 DBFreeResult(hResult);
172
173 // Link node to subnets
174 sprintf(szQuery, "SELECT subnet_id FROM nsmap WHERE node_id=%d", dwId);
cc140cce 175 hResult = DBSelect(g_hCoreDB, szQuery);
2da1357c
VK
176 if (hResult == 0)
177 return FALSE; // Query failed
178
179 if (DBGetNumRows(hResult) == 0)
180 {
181 DBFreeResult(hResult);
182 return FALSE; // No parents - it shouldn't happen if database isn't corrupted
183 }
184
cc140cce 185 BOOL bResult = FALSE;
2da1357c
VK
186 iNumRows = DBGetNumRows(hResult);
187 for(i = 0; i < iNumRows; i++)
188 {
189 dwSubnetId = DBGetFieldULong(hResult, i, 0);
190 pObject = FindObjectById(dwSubnetId);
191 if (pObject == NULL)
192 {
193 WriteLog(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
cc140cce 194 break;
2da1357c
VK
195 }
196 else if (pObject->Type() != OBJECT_SUBNET)
197 {
198 WriteLog(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
cc140cce 199 break;
2da1357c
VK
200 }
201 else
202 {
203 pObject->AddChild(this);
204 AddParent(pObject);
cc140cce 205 bResult = TRUE;
2da1357c
VK
206 }
207 }
208
209 DBFreeResult(hResult);
6f595ce2 210 LoadItemsFromDB();
3e4e127f 211 LoadACLFromDB();
3ea35b38
VK
212
213 // Walk through all items in the node and load appropriate thresholds
214 for(i = 0; i < (int)m_dwNumItems; i++)
215 if (!m_ppItems[i]->LoadThresholdsFromDB())
216 bResult = FALSE;
217
cc140cce 218 return bResult;
2da1357c
VK
219}
220
221
3ea35b38
VK
222//
223// Load data collection items from database
224//
225
226void Node::LoadItemsFromDB(void)
227{
228 char szQuery[256];
229 DB_RESULT hResult;
230
231 sprintf(szQuery, "SELECT item_id,name,source,datatype,polling_interval,retention_time,"
232 "status FROM items WHERE node_id=%d", m_dwId);
233 hResult = DBSelect(g_hCoreDB, szQuery);
234
235 if (hResult != 0)
236 {
237 int i, iRows;
238
239 iRows = DBGetNumRows(hResult);
240 if (iRows > 0)
241 {
242 m_dwNumItems = iRows;
243 m_ppItems = (DCItem **)malloc(sizeof(DCItem *) * iRows);
244 for(i = 0; i < iRows; i++)
245 m_ppItems[i] = new DCItem(hResult, i, this);
246 }
247 DBFreeResult(hResult);
248 }
249}
250
251
eefe7d68
VK
252//
253// Save object to database
254//
255
256BOOL Node::SaveToDB(void)
257{
a0495b6e 258 char szQuery[4096];
eefe7d68
VK
259 DB_RESULT hResult;
260 BOOL bNewObject = TRUE;
3ea35b38 261 BOOL bResult;
eefe7d68
VK
262
263 // Lock object's access
264 Lock();
265
266 // Check for object's existence in database
267 sprintf(szQuery, "SELECT id FROM nodes WHERE id=%ld", m_dwId);
268 hResult = DBSelect(g_hCoreDB, szQuery);
269 if (hResult != 0)
270 {
271 if (DBGetNumRows(hResult) > 0)
272 bNewObject = FALSE;
273 DBFreeResult(hResult);
274 }
275
276 // Form and execute INSERT or UPDATE query
277 if (bNewObject)
2da1357c
VK
278 sprintf(szQuery, "INSERT INTO nodes (id,name,status,is_deleted,primary_ip,"
279 "is_snmp,is_agent,is_bridge,is_router,snmp_version,community,"
a0495b6e 280 "discovery_flags,status_poll_type,agent_port,auth_method,secret,"
2a41a4b5
VK
281 "snmp_oid,is_local_mgmt,image_id)"
282 " VALUES (%d,'%s',%d,%d,%d,%d,%d,%d,%d,%d,'%s',%d,%d,%d,%d,'%s','%s',%d,%ld)",
eefe7d68
VK
283 m_dwId, m_szName, m_iStatus, m_bIsDeleted, m_dwIpAddr,
284 m_dwFlags & NF_IS_SNMP ? 1 : 0,
285 m_dwFlags & NF_IS_NATIVE_AGENT ? 1 : 0,
286 m_dwFlags & NF_IS_BRIDGE ? 1 : 0,
287 m_dwFlags & NF_IS_ROUTER ? 1 : 0,
2da1357c 288 m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags, m_iStatusPollType,
ce19c304 289 m_wAgentPort,m_wAuthMethod,m_szSharedSecret, m_szObjectId,
2a41a4b5 290 m_dwFlags & NF_IS_LOCAL_MGMT ? 1 : 0, m_dwImageId);
eefe7d68
VK
291 else
292 sprintf(szQuery, "UPDATE nodes SET name='%s',status=%d,is_deleted=%d,primary_ip=%d,"
293 "is_snmp=%d,is_agent=%d,is_bridge=%d,is_router=%d,snmp_version=%d,"
2da1357c 294 "community='%s',discovery_flags=%d,status_poll_type=%d,agent_port=%d,"
2a41a4b5
VK
295 "auth_method=%d,secret='%s',snmp_oid='%s',is_local_mgmt=%d,image_id=%ld"
296 " WHERE id=%ld",
eefe7d68
VK
297 m_szName, m_iStatus, m_bIsDeleted, m_dwIpAddr,
298 m_dwFlags & NF_IS_SNMP ? 1 : 0,
299 m_dwFlags & NF_IS_NATIVE_AGENT ? 1 : 0,
300 m_dwFlags & NF_IS_BRIDGE ? 1 : 0,
301 m_dwFlags & NF_IS_ROUTER ? 1 : 0,
2da1357c 302 m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags,
a0495b6e 303 m_iStatusPollType, m_wAgentPort, m_wAuthMethod, m_szSharedSecret,
2a41a4b5 304 m_szObjectId, m_dwFlags & NF_IS_LOCAL_MGMT ? 1 : 0, m_dwImageId, m_dwId);
3ea35b38
VK
305 bResult = DBQuery(g_hCoreDB, szQuery);
306
307 // Save data collection items
308 if (bResult)
309 {
310 DWORD i;
311
312 for(i = 0; i < m_dwNumItems; i++)
313 m_ppItems[i]->SaveToDB();
314 }
eefe7d68 315
de78f964
VK
316 // Save access list
317 SaveACLToDB();
318
eefe7d68
VK
319 // Clear modifications flag and unlock object
320 m_bIsModified = FALSE;
321 Unlock();
322
3ea35b38 323 return bResult;
eefe7d68
VK
324}
325
326
327//
328// Delete object from database
329//
330
331BOOL Node::DeleteFromDB(void)
332{
333 char szQuery[256];
ef44d5ea 334 BOOL bSuccess;
eefe7d68 335
ef44d5ea
VK
336 bSuccess = NetObj::DeleteFromDB();
337 if (bSuccess)
338 {
339 sprintf(szQuery, "DELETE FROM nodes WHERE id=%ld", m_dwId);
340 QueueSQLRequest(szQuery);
341 sprintf(szQuery, "DELETE FROM nsmap WHERE node_id=%ld", m_dwId);
342 QueueSQLRequest(szQuery);
343 sprintf(szQuery, "DROP TABLE idata_%ld", m_dwId);
344 QueueSQLRequest(szQuery);
345 }
346 return bSuccess;
eefe7d68 347}
469b937c
VK
348
349
350//
351// Poll newly discovered node
352// Usually called once by node poller thread when new node is discovered
353// and object for it is created
354//
355
356BOOL Node::NewNodePoll(DWORD dwNetMask)
357{
5811233f
VK
358 AgentConnection *pAgentConn;
359
be0a5a53
VK
360 PollerLock();
361
469b937c 362 // Determine node's capabilities
a7b85168 363 if (SnmpGet(m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0,
f92869c9 364 m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE))
469b937c
VK
365 m_dwFlags |= NF_IS_SNMP;
366
a7b85168
VK
367 pAgentConn = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod,
368 m_szSharedSecret);
5811233f
VK
369 if (pAgentConn->Connect())
370 m_dwFlags |= NF_IS_NATIVE_AGENT;
371
469b937c 372 // Get interface list
a7b85168
VK
373 if ((m_dwFlags & NF_IS_SNMP) || (m_dwFlags & NF_IS_NATIVE_AGENT) ||
374 (m_dwFlags & NF_IS_LOCAL_MGMT))
469b937c 375 {
5811233f 376 INTERFACE_LIST *pIfList = NULL;
a0495b6e
VK
377 int i;
378
ce19c304
VK
379 if (m_dwFlags & NF_IS_LOCAL_MGMT) // For local machine
380 pIfList = GetLocalInterfaceList();
381 else if (m_dwFlags & NF_IS_NATIVE_AGENT) // For others prefer native agent
5811233f
VK
382 pIfList = pAgentConn->GetInterfaceList();
383 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP)) // Use SNMP if we cannot get interfaces via agent
384 pIfList = SnmpGetInterfaceList(m_dwIpAddr, m_szCommunityString);
385
386 if (pIfList != NULL)
a0495b6e 387 {
5811233f 388 for(i = 0; i < pIfList->iNumEntries; i++)
323f8bec
VK
389 CreateNewInterface(pIfList->pInterfaces[i].dwIpAddr,
390 pIfList->pInterfaces[i].dwIpNetMask,
391 pIfList->pInterfaces[i].szName,
392 pIfList->pInterfaces[i].dwIndex,
393 pIfList->pInterfaces[i].dwType);
5811233f 394 DestroyInterfaceList(pIfList);
a0495b6e 395 }
9437ca82
VK
396 else
397 {
398 // We cannot get interface list from node for some reasons, create dummy one
323f8bec 399 CreateNewInterface(m_dwIpAddr, dwNetMask);
9437ca82 400 }
469b937c
VK
401 }
402 else // No SNMP, no native agent - create pseudo interface object
403 {
323f8bec 404 CreateNewInterface(m_dwIpAddr, dwNetMask);
469b937c
VK
405 }
406
5811233f
VK
407 // Clean up agent connection
408 if (m_dwFlags & NF_IS_NATIVE_AGENT)
409 pAgentConn->Disconnect();
410 delete pAgentConn;
411
be0a5a53
VK
412 PollerUnlock();
413
469b937c
VK
414 return TRUE;
415}
ce19c304
VK
416
417
418//
c8b1f788 419// Get ARP cache from node
ce19c304
VK
420//
421
c8b1f788 422ARP_CACHE *Node::GetArpCache(void)
ce19c304
VK
423{
424 ARP_CACHE *pArpCache = NULL;
425
426 if (m_dwFlags & NF_IS_LOCAL_MGMT)
427 {
428 pArpCache = GetLocalArpCache();
429 }
430 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
431 {
3ea35b38 432 AgentLock();
1275c750
VK
433 if (ConnectToAgent())
434 pArpCache = m_pAgentConnection->GetArpCache();
3ea35b38 435 AgentUnlock();
ce19c304
VK
436 }
437 else if (m_dwFlags & NF_IS_SNMP)
438 {
439 pArpCache = SnmpGetArpCache(m_dwIpAddr, m_szCommunityString);
440 }
441
442 return pArpCache;
443}
444
445
446//
447// Get list of interfaces from node
448//
449
450INTERFACE_LIST *Node::GetInterfaceList(void)
451{
452 INTERFACE_LIST *pIfList = NULL;
453
454 if (m_dwFlags & NF_IS_LOCAL_MGMT)
455 {
456 pIfList = GetLocalInterfaceList();
457 }
458 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
459 {
1c62be36
VK
460 AgentLock();
461 if (ConnectToAgent())
ce19c304 462 {
1c62be36
VK
463 CleanInterfaceList(pIfList);
464 pIfList = m_pAgentConnection->GetInterfaceList();
ce19c304 465 }
1c62be36 466 AgentUnlock();
ce19c304
VK
467 }
468 else if (m_dwFlags & NF_IS_SNMP)
469 {
470 pIfList = SnmpGetInterfaceList(m_dwIpAddr, m_szCommunityString);
471 }
472
473 return pIfList;
474}
48b1c0ac
VK
475
476
477//
478// Find interface by index and node IP
479// Returns pointer to interface object or NULL if appropriate interface couldn't be found
480//
481
482Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
483{
484 DWORD i;
485 Interface *pInterface;
486
487 for(i = 0; i < m_dwChildCount; i++)
488 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
489 {
490 pInterface = (Interface *)m_pChildList[i];
491 if (pInterface->IfIndex() == dwIndex)
492 if ((pInterface->IpAddr() & pInterface->IpNetMask()) ==
493 (dwHostAddr & pInterface->IpNetMask()))
494 return pInterface;
495 }
496 return NULL;
497}
f00307b7
VK
498
499
323f8bec
VK
500//
501// Create new interface
502//
503
504void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName, DWORD dwIndex, DWORD dwType)
505{
506 Interface *pInterface;
507 Subnet *pSubnet;
508
509 // Create interface object
510 if (szName != NULL)
511 pInterface = new Interface(szName, dwIndex, dwIpAddr, dwNetMask, dwType);
512 else
513 pInterface = new Interface(dwIpAddr, dwNetMask);
514
515 // Insert to objects' list and generate event
516 NetObjInsert(pInterface, TRUE);
517 AddInterface(pInterface);
518 PostEvent(EVENT_INTERFACE_ADDED, m_dwId, "dsaad", pInterface->Id(),
519 pInterface->Name(), pInterface->IpAddr(),
520 pInterface->IpNetMask(), pInterface->IfIndex());
521
522 // Bind node to appropriate subnet
523 if (pInterface->IpAddr() != 0) // Do not link non-IP interfaces to 0.0.0.0 subnet
524 {
525 pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
526 if (pSubnet == NULL)
527 {
528 // Create new subnet object
529 pSubnet = new Subnet(pInterface->IpAddr() & pInterface->IpNetMask(), pInterface->IpNetMask());
530 NetObjInsert(pSubnet, TRUE);
531 g_pEntireNet->AddSubnet(pSubnet);
532 }
533 pSubnet->AddNode(this);
534 }
535}
536
537
538//
539// Delete interface from node
540//
541
542void Node::DeleteInterface(Interface *pInterface)
543{
544 DWORD i;
545
546 // Check if we should unlink node from interface's subnet
547 if (pInterface->IpAddr() != 0)
548 {
549 for(i = 0; i < m_dwChildCount; i++)
550 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
551 if (m_pChildList[i] != pInterface)
552 if ((((Interface *)m_pChildList[i])->IpAddr() & ((Interface *)m_pChildList[i])->IpNetMask()) ==
553 (pInterface->IpAddr() & pInterface->IpNetMask()))
554 break;
555 if (i == m_dwChildCount)
556 {
557 // Last interface in subnet, should unlink node
558 Subnet *pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
3ea35b38 559 DeleteParent(pSubnet);
323f8bec 560 if (pSubnet != NULL)
3ea35b38 561 {
323f8bec 562 pSubnet->DeleteChild(this);
3ea35b38
VK
563 if ((pSubnet->IsEmpty()) && (g_dwFlags & AF_DELETE_EMPTY_SUBNETS))
564 {
565 PostEvent(EVENT_SUBNET_DELETED, pSubnet->Id(), NULL);
566 pSubnet->Delete();
567 }
568 }
323f8bec
VK
569 }
570 }
571 pInterface->Delete();
572}
573
574
f00307b7
VK
575//
576// Calculate node status based on child objects status
577//
578
579void Node::CalculateCompoundStatus(void)
580{
581 int iOldStatus = m_iStatus;
582 static DWORD dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_MINOR,
583 EVENT_NODE_WARNING, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
584 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
585
586 NetObj::CalculateCompoundStatus();
587 if (m_iStatus != iOldStatus)
588 PostEvent(dwEventCodes[m_iStatus], m_dwId, "d", iOldStatus);
589}
590
591
592//
593// Perform status poll on node
594//
595
596void Node::StatusPoll(void)
597{
598 DWORD i;
599
323f8bec 600 PollerLock();
f00307b7 601 for(i = 0; i < m_dwChildCount; i++)
c1c39152
VK
602 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
603 (m_pChildList[i]->Status() != STATUS_UNMANAGED))
f00307b7
VK
604 ((Interface *)m_pChildList[i])->StatusPoll();
605 CalculateCompoundStatus();
606 m_tLastStatusPoll = time(NULL);
323f8bec 607 PollerUnlock();
f00307b7 608}
364aa19a
VK
609
610
611//
612// Perform configuration poll on node
613//
614
615void Node::ConfigurationPoll(void)
616{
617 DWORD dwOldFlags = m_dwFlags;
618 AgentConnection *pAgentConn;
619 INTERFACE_LIST *pIfList;
6159a875 620 BOOL bHasChanges = FALSE;
364aa19a 621
323f8bec 622 PollerLock();
8bff53f6 623 DbgPrintf(AF_DEBUG_DISCOVERY, "Starting configuration poll for node %s (ID: %d)\n", m_szName, m_dwId);
323f8bec 624
364aa19a 625 // Check node's capabilities
a7b85168 626 if (SnmpGet(m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0,
f92869c9 627 m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE))
364aa19a
VK
628 {
629 m_dwFlags |= NF_IS_SNMP;
630 m_iSnmpAgentFails = 0;
631 }
632 else
633 {
4ea67c99
VK
634 if (m_dwFlags & NF_IS_SNMP)
635 {
636 if (m_iSnmpAgentFails == 0)
637 PostEvent(EVENT_SNMP_FAIL, m_dwId, NULL);
638 m_iSnmpAgentFails++;
639 }
364aa19a
VK
640 }
641
642 pAgentConn = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
643 if (pAgentConn->Connect())
644 {
645 m_dwFlags |= NF_IS_NATIVE_AGENT;
646 m_iNativeAgentFails = 0;
f91fa4c2 647 pAgentConn->Disconnect();
364aa19a
VK
648 }
649 else
650 {
4ea67c99
VK
651 if (m_dwFlags & NF_IS_NATIVE_AGENT)
652 {
653 if (m_iNativeAgentFails == 0)
654 PostEvent(EVENT_AGENT_FAIL, m_dwId, NULL);
655 m_iNativeAgentFails++;
656 }
364aa19a 657 }
f91fa4c2 658 delete pAgentConn;
364aa19a
VK
659
660 // Generate event if node flags has been changed
661 if (dwOldFlags != m_dwFlags)
6159a875 662 {
364aa19a 663 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
6159a875
VK
664 bHasChanges = TRUE;
665 }
364aa19a
VK
666
667 // Retrieve interface list
668 pIfList = GetInterfaceList();
669 if (pIfList != NULL)
670 {
671 DWORD i;
323f8bec 672 int j;
364aa19a
VK
673
674 // Find non-existing interfaces
675 for(i = 0; i < m_dwChildCount; i++)
676 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
677 {
678 Interface *pInterface = (Interface *)m_pChildList[i];
364aa19a
VK
679
680 for(j = 0; j < pIfList->iNumEntries; j++)
681 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
682 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
683 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
684 break;
685 if (j == pIfList->iNumEntries)
686 {
687 // No such interface in current configuration, delete it
688 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", pInterface->IfIndex(),
689 pInterface->Name(), pInterface->IpAddr(), pInterface->IpNetMask());
323f8bec 690 DeleteInterface(pInterface);
364aa19a 691 i = 0; // Restart loop
6159a875 692 bHasChanges = TRUE;
364aa19a
VK
693 }
694 }
695
323f8bec
VK
696 // Add new interfaces
697 for(j = 0; j < pIfList->iNumEntries; j++)
698 {
699 for(i = 0; i < m_dwChildCount; i++)
700 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
701 {
702 Interface *pInterface = (Interface *)m_pChildList[i];
703
704 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
705 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
706 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
707 break;
708 }
709 if (i == m_dwChildCount)
710 {
711 // New interface
712 CreateNewInterface(pIfList->pInterfaces[j].dwIpAddr,
713 pIfList->pInterfaces[j].dwIpNetMask,
714 pIfList->pInterfaces[j].szName,
715 pIfList->pInterfaces[j].dwIndex,
716 pIfList->pInterfaces[j].dwType);
6159a875 717 bHasChanges = TRUE;
323f8bec
VK
718 }
719 }
e0d3b217
VK
720
721 DestroyInterfaceList(pIfList);
364aa19a 722 }
323f8bec 723
8bff53f6 724 m_tLastConfigurationPoll = time(NULL);
323f8bec 725 PollerUnlock();
ccdbbb52 726 DbgPrintf(AF_DEBUG_DISCOVERY, "Finished configuration poll for node %s (ID: %d)\n", m_szName, m_dwId);
6159a875
VK
727
728 if (bHasChanges)
729 {
730 Lock();
731 Modify();
732 Unlock();
733 }
364aa19a 734}
6f595ce2
VK
735
736
1275c750
VK
737//
738// Connect to native agent
739//
740
741BOOL Node::ConnectToAgent(void)
742{
743 // Create new agent connection object if needed
744 if (m_pAgentConnection == NULL)
745 m_pAgentConnection = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
746
747 // Check if we already connected
748 if (m_pAgentConnection->Nop() == ERR_SUCCESS)
749 return TRUE;
750
751 // Close current connection or clean up after broken connection
752 m_pAgentConnection->Disconnect();
753 return m_pAgentConnection->Connect();
754}
755
756
757//
758// Get item's value via SNMP
759//
760
3ea35b38 761DWORD Node::GetItemFromSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1275c750
VK
762{
763 return SnmpGet(m_dwIpAddr, m_szCommunityString, szParam, NULL, 0,
f92869c9 764 szBuffer, dwBufSize, FALSE, TRUE) ? DCE_SUCCESS : DCE_COMM_ERROR;
1275c750
VK
765}
766
767
768//
769// Get item's value via native agent
770//
771
3ea35b38 772DWORD Node::GetItemFromAgent(const char *szParam, DWORD dwBufSize, char *szBuffer)
1275c750 773{
3ea35b38 774 DWORD dwError, dwResult = DCE_COMM_ERROR;
1275c750
VK
775 DWORD dwTries = 5;
776
3ea35b38
VK
777 AgentLock();
778
1275c750
VK
779 // Establish connection if needed
780 if (m_pAgentConnection == NULL)
781 if (!ConnectToAgent())
3ea35b38 782 goto end_loop;
1275c750
VK
783
784 // Get parameter from agent
785 while(dwTries-- > 0)
786 {
901c96c7 787 dwError = m_pAgentConnection->GetParameter((char *)szParam, dwBufSize, szBuffer);
1275c750
VK
788 switch(dwError)
789 {
790 case ERR_SUCCESS:
3ea35b38
VK
791 dwResult = DCE_SUCCESS;
792 goto end_loop;
1275c750 793 case ERR_UNKNOWN_PARAMETER:
3ea35b38
VK
794 dwResult = DCE_NOT_SUPPORTED;
795 goto end_loop;
1275c750
VK
796 case ERR_NOT_CONNECTED:
797 case ERR_CONNECTION_BROKEN:
798 if (!ConnectToAgent())
3ea35b38 799 goto end_loop;
1275c750
VK
800 break;
801 case ERR_REQUEST_TIMEOUT:
802 break;
803 }
804 }
3ea35b38
VK
805
806end_loop:
807 AgentUnlock();
808 return dwResult;
1275c750 809}
8e99117a
VK
810
811
812//
813// Get value for server's internal parameter
814//
815
3ea35b38 816DWORD Node::GetInternalItem(const char *szParam, DWORD dwBufSize, char *szBuffer)
8e99117a
VK
817{
818 DWORD dwError = DCE_SUCCESS;
819
820 if (!stricmp(szParam, "status"))
821 {
822 sprintf(szBuffer, "%d", m_iStatus);
823 }
824 else
825 {
826 dwError = DCE_NOT_SUPPORTED;
827 }
828
829 return dwError;
830}
129f8f7b
VK
831
832
833//
834// Put items which requires polling into the queue
835//
836
837void Node::QueueItemsForPolling(Queue *pPollerQueue)
838{
839 DWORD i;
840 time_t currTime;
841
842 currTime = time(NULL);
843
844 Lock();
845 for(i = 0; i < m_dwNumItems; i++)
846 {
3ea35b38 847 if (m_ppItems[i]->ReadyForPolling(currTime))
129f8f7b 848 {
3ea35b38 849 m_ppItems[i]->SetBusyFlag(TRUE);
5add75d8 850 pPollerQueue->Put(m_ppItems[i]);
067f2689
VK
851 }
852 }
853 Unlock();
854}
855
856
857//
858// Add item to node
859//
860
3ea35b38 861BOOL Node::AddItem(DCItem *pItem)
067f2689
VK
862{
863 DWORD i;
864 BOOL bResult = FALSE;
865
866 Lock();
867 // Check if that item exists
868 for(i = 0; i < m_dwNumItems; i++)
9ed4eaff
VK
869 if (m_ppItems[i]->Id() == pItem->Id())
870 break; // Item with specified id already exist
067f2689
VK
871
872 if (i == m_dwNumItems) // Add new item
873 {
874 m_dwNumItems++;
3ea35b38
VK
875 m_ppItems = (DCItem **)realloc(m_ppItems, sizeof(DCItem *) * m_dwNumItems);
876 m_ppItems[i] = pItem;
877 m_ppItems[i]->SetLastPollTime(0); // Cause item to be polled immediatelly
878 m_ppItems[i]->SetStatus(ITEM_STATUS_ACTIVE);
879 m_ppItems[i]->SetBusyFlag(FALSE);
53512272 880 Modify();
067f2689
VK
881 bResult = TRUE;
882 }
883
884 Unlock();
885 return bResult;
886}
b81249b7
VK
887
888
9ed4eaff
VK
889//
890// Delete item from node
891//
892
893BOOL Node::DeleteItem(DWORD dwItemId)
894{
895 DWORD i;
896 BOOL bResult = FALSE;
897
898 Lock();
899 // Check if that item exists
900 for(i = 0; i < m_dwNumItems; i++)
901 if (m_ppItems[i]->Id() == dwItemId)
902 {
903 // Destroy item
904 m_ppItems[i]->DeleteFromDB();
905 delete m_ppItems[i];
906 m_dwNumItems--;
907 memmove(&m_ppItems[i], &m_ppItems[i + 1], sizeof(DCItem *) * (m_dwNumItems - i));
908 bResult = TRUE;
bdce7422 909 break;
9ed4eaff
VK
910 }
911
912 Unlock();
913 return bResult;
914}
915
916
917//
918// Modify data collection item from CSCP message
919//
920
07a45e04
VK
921BOOL Node::UpdateItem(DWORD dwItemId, CSCPMessage *pMsg, DWORD *pdwNumMaps,
922 DWORD **ppdwMapIndex, DWORD **ppdwMapId)
9ed4eaff
VK
923{
924 DWORD i;
925 BOOL bResult = FALSE;
926
927 Lock();
928 // Check if that item exists
929 for(i = 0; i < m_dwNumItems; i++)
930 if (m_ppItems[i]->Id() == dwItemId)
931 {
07a45e04 932 m_ppItems[i]->UpdateFromMessage(pMsg, pdwNumMaps, ppdwMapIndex, ppdwMapId);
9ed4eaff 933 bResult = TRUE;
06e7be2f 934 m_bIsModified = TRUE;
bdce7422 935 break;
9ed4eaff
VK
936 }
937
938 Unlock();
939 return bResult;
940}
941
942
b81249b7
VK
943//
944// Create CSCP message with object's data
945//
946
947void Node::CreateMessage(CSCPMessage *pMsg)
948{
949 NetObj::CreateMessage(pMsg);
a5f8dbb8
VK
950 pMsg->SetVariable(VID_FLAGS, m_dwFlags);
951 pMsg->SetVariable(VID_DISCOVERY_FLAGS, m_dwDiscoveryFlags);
952 pMsg->SetVariable(VID_AGENT_PORT, m_wAgentPort);
953 pMsg->SetVariable(VID_AUTH_METHOD, m_wAuthMethod);
954 pMsg->SetVariable(VID_SHARED_SECRET, m_szSharedSecret);
955 pMsg->SetVariable(VID_COMMUNITY_STRING, m_szCommunityString);
956 pMsg->SetVariable(VID_SNMP_OID, m_szObjectId);
b81249b7 957}
24156e90
VK
958
959
960//
961// Modify object from message
962//
963
964DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
965{
966 if (!bAlreadyLocked)
967 Lock();
968
969 // Change listen port of native agent
970 if (pRequest->IsVariableExist(VID_AGENT_PORT))
971 m_wAgentPort = pRequest->GetVariableShort(VID_AGENT_PORT);
972
973 // Change authentication method of native agent
974 if (pRequest->IsVariableExist(VID_AUTH_METHOD))
975 m_wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
976
977 // Change shared secret of native agent
978 if (pRequest->IsVariableExist(VID_SHARED_SECRET))
979 pRequest->GetVariableStr(VID_SHARED_SECRET, m_szSharedSecret, MAX_SECRET_LENGTH);
980
981 // Change SNMP community string
982 if (pRequest->IsVariableExist(VID_COMMUNITY_STRING))
983 pRequest->GetVariableStr(VID_COMMUNITY_STRING, m_szCommunityString, MAX_COMMUNITY_LENGTH);
984
985 return NetObj::ModifyFromMessage(pRequest, TRUE);
986}
3c55b85d
VK
987
988
989//
990// Lock data collection items list
991//
992
993BOOL Node::LockDCIList(DWORD dwSessionId)
994{
995 BOOL bSuccess = FALSE;
996
997 Lock();
998 if (m_dwDCILockStatus == INVALID_INDEX)
999 {
1000 m_dwDCILockStatus = dwSessionId;
1001 bSuccess = TRUE;
1002 }
1003 Unlock();
1004 return bSuccess;
1005}
1006
1007
1008//
1009// Unlock data collection items list
1010//
1011
1012BOOL Node::UnlockDCIList(DWORD dwSessionId)
1013{
1014 BOOL bSuccess = FALSE;
1015
1016 Lock();
1017 if (m_dwDCILockStatus == dwSessionId)
1018 {
1019 m_dwDCILockStatus = INVALID_INDEX;
1020 bSuccess = TRUE;
1021 }
1022 Unlock();
1023 return bSuccess;
1024}
1025
1026
1027//
1028// Send DCI list to client
1029//
1030
1031void Node::SendItemsToClient(ClientSession *pSession, DWORD dwRqId)
1032{
1033 CSCPMessage msg;
1034 DWORD i;
1035
1036 // Prepare message
3c55b85d 1037 msg.SetId(dwRqId);
07a45e04 1038 msg.SetCode(CMD_NODE_DCI);
3c55b85d
VK
1039
1040 // Walk through items list
1041 for(i = 0; i < m_dwNumItems; i++)
1042 {
1043 m_ppItems[i]->CreateMessage(&msg);
1044 pSession->SendMessage(&msg);
1045 msg.DeleteAllVariables();
1046 }
1047
1048 // Send end-of-list indicator
1049 msg.SetCode(CMD_NODE_DCI_LIST_END);
1050 pSession->SendMessage(&msg);
1051}
bdce7422
VK
1052
1053
1054//
1055// Get DCI item's type
1056//
1057
1058int Node::GetItemType(DWORD dwItemId)
1059{
1060 DWORD i;
1061 int iType = -1;
1062
1063 Lock();
1064 // Check if that item exists
1065 for(i = 0; i < m_dwNumItems; i++)
1066 if (m_ppItems[i]->Id() == dwItemId)
1067 {
1068 iType = m_ppItems[i]->DataType();
1069 break;
1070 }
1071
1072 Unlock();
1073 return iType;
1074}