new db schema
[public/netxms.git] / src / server / core / node.cpp
CommitLineData
5039dede
AK
1/* $Id$ */
2/*
3** NetXMS - Network Management System
4** Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Victor Kirhenshtein
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: node.cpp
21**
22**/
23
24#include "nxcore.h"
25
26
27//
28// Prefixes for poller messages
29//
30
31#define POLLER_ERROR "\x7F" "e"
32#define POLLER_WARNING "\x7Fw"
33#define POLLER_INFO "\x7Fi"
34
35
36//
37// Node class default constructor
38//
39
40Node::Node()
41 :Template()
42{
43 m_dwFlags = 0;
44 m_dwDynamicFlags = 0;
45 m_dwZoneGUID = 0;
46 m_dwNodeType = NODE_TYPE_GENERIC;
47 m_wAgentPort = AGENT_LISTEN_PORT;
48 m_wAuthMethod = AUTH_NONE;
49 m_szSharedSecret[0] = 0;
50 m_iStatusPollType = POLL_ICMP_PING;
51 m_iSNMPVersion = SNMP_VERSION_1;
52 m_wSNMPPort = SNMP_DEFAULT_PORT;
53 ConfigReadStr("DefaultCommunityString", m_szCommunityString,
54 MAX_COMMUNITY_LENGTH, "public");
55 m_szObjectId[0] = 0;
56 m_tLastDiscoveryPoll = 0;
57 m_tLastStatusPoll = 0;
58 m_tLastConfigurationPoll = 0;
59 m_tLastRTUpdate = 0;
60 m_hPollerMutex = MutexCreate();
61 m_hAgentAccessMutex = MutexCreate();
62 m_mutexRTAccess = MutexCreate();
63 m_mutexTopoAccess = MutexCreate();
64 m_pAgentConnection = NULL;
65 m_szAgentVersion[0] = 0;
66 m_szPlatformName[0] = 0;
67 m_szSysDescription[0] = 0;
68 m_dwNumParams = 0;
69 m_pParamList = NULL;
70 m_dwPollerNode = 0;
71 m_dwProxyNode = 0;
72 m_dwSNMPProxy = 0;
73 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
74 m_pRoutingTable = NULL;
75 m_tFailTimeSNMP = 0;
76 m_tFailTimeAgent = 0;
77 m_pTopology = NULL;
78 m_tLastTopologyPoll = 0;
79 m_iPendingStatus = -1;
80 m_iPollCount = 0;
81 m_iRequiredPollCount = 0; // Use system default
82 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
ab621f39 83 m_jobQueue = new ServerJobQueue();
5039dede
AK
84}
85
86
87//
88// Constructor for new node object
89//
90
91Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwProxyNode, DWORD dwSNMPProxy, DWORD dwZone)
92 :Template()
93{
94 m_dwIpAddr = dwAddr;
95 m_dwFlags = dwFlags;
96 m_dwDynamicFlags = 0;
97 m_dwZoneGUID = dwZone;
98 m_dwNodeType = NODE_TYPE_GENERIC;
99 m_wAgentPort = AGENT_LISTEN_PORT;
100 m_wAuthMethod = AUTH_NONE;
101 m_szSharedSecret[0] = 0;
102 m_iStatusPollType = POLL_ICMP_PING;
103 m_iSNMPVersion = SNMP_VERSION_1;
104 m_wSNMPPort = SNMP_DEFAULT_PORT;
105 ConfigReadStr("DefaultCommunityString", m_szCommunityString,
106 MAX_COMMUNITY_LENGTH, "public");
107 IpToStr(dwAddr, m_szName); // Make default name from IP address
108 m_szObjectId[0] = 0;
109 m_tLastDiscoveryPoll = 0;
110 m_tLastStatusPoll = 0;
111 m_tLastConfigurationPoll = 0;
112 m_tLastRTUpdate = 0;
113 m_hPollerMutex = MutexCreate();
114 m_hAgentAccessMutex = MutexCreate();
115 m_mutexRTAccess = MutexCreate();
116 m_mutexTopoAccess = MutexCreate();
117 m_pAgentConnection = NULL;
118 m_szAgentVersion[0] = 0;
119 m_szPlatformName[0] = 0;
120 m_szSysDescription[0] = 0;
121 m_dwNumParams = 0;
122 m_pParamList = NULL;
123 m_dwPollerNode = 0;
124 m_dwProxyNode = dwProxyNode;
125 m_dwSNMPProxy = dwSNMPProxy;
126 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
127 m_bIsHidden = TRUE;
128 m_pRoutingTable = NULL;
129 m_tFailTimeSNMP = 0;
130 m_tFailTimeAgent = 0;
131 m_pTopology = NULL;
132 m_tLastTopologyPoll = 0;
133 m_iPendingStatus = -1;
134 m_iPollCount = 0;
135 m_iRequiredPollCount = 0; // Use system default
136 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
ab621f39 137 m_jobQueue = new ServerJobQueue();
5039dede
AK
138}
139
140
141//
142// Node destructor
143//
144
145Node::~Node()
146{
147 MutexDestroy(m_hPollerMutex);
148 MutexDestroy(m_hAgentAccessMutex);
149 MutexDestroy(m_mutexRTAccess);
150 MutexDestroy(m_mutexTopoAccess);
151 delete m_pAgentConnection;
152 safe_free(m_pParamList);
153 DestroyRoutingTable(m_pRoutingTable);
154 delete m_pTopology;
ab621f39 155 delete m_jobQueue;
5039dede
AK
156}
157
158
159//
160// Create object from database data
161//
162
163BOOL Node::CreateFromDB(DWORD dwId)
164{
165 char szQuery[512];
166 DB_RESULT hResult;
167 int i, iNumRows;
168 DWORD dwSubnetId;
169 NetObj *pObject;
170 BOOL bResult = FALSE;
171
172 m_dwId = dwId;
173
174 if (!LoadCommonProperties())
175 {
176 DbgPrintf(2, "Cannot load common properties for node object %d", dwId);
177 return FALSE;
178 }
179
180 _sntprintf(szQuery, 512, "SELECT primary_ip,node_flags,"
181 "snmp_version,auth_method,secret,"
182 "agent_port,status_poll_type,community,snmp_oid,"
183 "node_type,agent_version,"
184 "platform_name,poller_node_id,zone_guid,"
185 "proxy_node,snmp_proxy,required_polls,uname,"
186 "use_ifxtable"
187 " FROM nodes WHERE id=%d", dwId);
188 hResult = DBSelect(g_hCoreDB, szQuery);
189 if (hResult == 0)
190 return FALSE; // Query failed
191
192 if (DBGetNumRows(hResult) == 0)
193 {
194 DBFreeResult(hResult);
195 DbgPrintf(2, "Missing record in \"nodes\" table for node object %d", dwId);
196 return FALSE;
197 }
198
199 m_dwIpAddr = DBGetFieldIPAddr(hResult, 0, 0);
200 m_dwFlags = DBGetFieldULong(hResult, 0, 1);
201 m_iSNMPVersion = DBGetFieldLong(hResult, 0, 2);
202 m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 3);
203 DBGetField(hResult, 0, 4, m_szSharedSecret, MAX_SECRET_LENGTH);
204 DecodeSQLString(m_szSharedSecret);
205 m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 5);
206 m_iStatusPollType = DBGetFieldLong(hResult, 0, 6);
207 DBGetField(hResult, 0, 7, m_szCommunityString, MAX_COMMUNITY_LENGTH);
208 DecodeSQLString(m_szCommunityString);
209 DBGetField(hResult, 0, 8, m_szObjectId, MAX_OID_LEN * 4);
47db58c2 210 DecodeSQLString(m_szObjectId);
5039dede
AK
211 m_dwNodeType = DBGetFieldULong(hResult, 0, 9);
212 DBGetField(hResult, 0, 10, m_szAgentVersion, MAX_AGENT_VERSION_LEN);
213 DecodeSQLString(m_szAgentVersion);
214 DBGetField(hResult, 0, 11, m_szPlatformName, MAX_PLATFORM_NAME_LEN);
215 DecodeSQLString(m_szPlatformName);
216 m_dwPollerNode = DBGetFieldULong(hResult, 0, 12);
217 m_dwZoneGUID = DBGetFieldULong(hResult, 0, 13);
218 m_dwProxyNode = DBGetFieldULong(hResult, 0, 14);
219 m_dwSNMPProxy = DBGetFieldULong(hResult, 0, 15);
220 m_iRequiredPollCount = DBGetFieldLong(hResult, 0, 16);
221 DBGetField(hResult, 0, 17, m_szSysDescription, MAX_DB_STRING);
222 m_nUseIfXTable = (BYTE)DBGetFieldLong(hResult, 0, 18);
223 DecodeSQLString(m_szSysDescription);
224
225 DBFreeResult(hResult);
226
227 if (!m_bIsDeleted)
228 {
229 // Link node to subnets
230 sprintf(szQuery, "SELECT subnet_id FROM nsmap WHERE node_id=%d", dwId);
231 hResult = DBSelect(g_hCoreDB, szQuery);
232 if (hResult == NULL)
233 return FALSE; // Query failed
234
235 iNumRows = DBGetNumRows(hResult);
5039dede
AK
236 for(i = 0; i < iNumRows; i++)
237 {
238 dwSubnetId = DBGetFieldULong(hResult, i, 0);
239 pObject = FindObjectById(dwSubnetId);
240 if (pObject == NULL)
241 {
242 nxlog_write(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
243 break;
244 }
245 else if (pObject->Type() != OBJECT_SUBNET)
246 {
247 nxlog_write(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
248 break;
249 }
250 else
251 {
252 pObject->AddChild(this);
253 AddParent(pObject);
254 bResult = TRUE;
255 }
256 }
257
258 DBFreeResult(hResult);
259 LoadItemsFromDB();
260 LoadACLFromDB();
261
262 // Walk through all items in the node and load appropriate thresholds
263 for(i = 0; i < (int)m_dwNumItems; i++)
264 if (!m_ppItems[i]->LoadThresholdsFromDB())
265 {
266 DbgPrintf(3, "Cannot load thresholds for DCI %d of node %d (%s)",
267 m_ppItems[i]->Id(), dwId, m_szName);
268 bResult = FALSE;
269 }
270 }
271 else
272 {
273 bResult = TRUE;
274 }
275
276 return bResult;
277}
278
279
280//
281// Save object to database
282//
283
284BOOL Node::SaveToDB(DB_HANDLE hdb)
285{
286 TCHAR *pszEscVersion, *pszEscPlatform, *pszEscSecret;
47db58c2 287 TCHAR *pszEscCommunity, *escObjectId, szQuery[4096], szIpAddr[16];
5039dede
AK
288 TCHAR *pszEscDescr;
289 DB_RESULT hResult;
290 BOOL bNewObject = TRUE;
291 BOOL bResult;
292
293 // Lock object's access
294 LockData();
295
296 SaveCommonProperties(hdb);
297
298 // Check for object's existence in database
299 sprintf(szQuery, "SELECT id FROM nodes WHERE id=%d", m_dwId);
300 hResult = DBSelect(hdb, szQuery);
301 if (hResult != 0)
302 {
303 if (DBGetNumRows(hResult) > 0)
304 bNewObject = FALSE;
305 DBFreeResult(hResult);
306 }
307
308 // Form and execute INSERT or UPDATE query
309 pszEscVersion = EncodeSQLString(m_szAgentVersion);
310 pszEscPlatform = EncodeSQLString(m_szPlatformName);
311 pszEscSecret = EncodeSQLString(m_szSharedSecret);
312 pszEscCommunity = EncodeSQLString(m_szCommunityString);
47db58c2 313 escObjectId = EncodeSQLString(m_szObjectId);
5039dede
AK
314 pszEscDescr = EncodeSQLString(m_szSysDescription);
315 if (bNewObject)
316 snprintf(szQuery, 4096,
317 "INSERT INTO nodes (id,primary_ip,"
318 "node_flags,snmp_version,community,status_poll_type,"
319 "agent_port,auth_method,secret,snmp_oid,proxy_node,"
320 "node_type,agent_version,platform_name,uname,"
321 "poller_node_id,zone_guid,snmp_proxy,required_polls,"
322 "use_ifxtable) VALUES "
323 "(%d,'%s',%d,%d,'%s',%d,%d,%d,'%s','%s',%d,%d,'%s','%s','%s',%d,%d,%d,%d,%d)",
324 m_dwId, IpToStr(m_dwIpAddr, szIpAddr), m_dwFlags,
325 m_iSNMPVersion, pszEscCommunity, m_iStatusPollType,
47db58c2 326 m_wAgentPort, m_wAuthMethod, pszEscSecret, escObjectId,
5039dede
AK
327 m_dwProxyNode, m_dwNodeType, pszEscVersion,
328 pszEscPlatform, pszEscDescr, m_dwPollerNode, m_dwZoneGUID,
329 m_dwSNMPProxy, m_iRequiredPollCount,m_nUseIfXTable);
330 else
331 snprintf(szQuery, 4096,
332 "UPDATE nodes SET primary_ip='%s',"
333 "node_flags=%d,snmp_version=%d,community='%s',"
334 "status_poll_type=%d,agent_port=%d,auth_method=%d,secret='%s',"
335 "snmp_oid='%s',node_type=%d,uname='%s',"
336 "agent_version='%s',platform_name='%s',poller_node_id=%d,"
337 "zone_guid=%d,proxy_node=%d,snmp_proxy=%d,"
338 "required_polls=%d,use_ifxtable=%d WHERE id=%d",
339 IpToStr(m_dwIpAddr, szIpAddr),
340 m_dwFlags, m_iSNMPVersion, pszEscCommunity,
341 m_iStatusPollType, m_wAgentPort, m_wAuthMethod, pszEscSecret,
47db58c2 342 escObjectId, m_dwNodeType, pszEscDescr,
5039dede
AK
343 pszEscVersion, pszEscPlatform, m_dwPollerNode, m_dwZoneGUID,
344 m_dwProxyNode, m_dwSNMPProxy, m_iRequiredPollCount,
345 m_nUseIfXTable, m_dwId);
346 bResult = DBQuery(hdb, szQuery);
347 free(pszEscVersion);
348 free(pszEscPlatform);
349 free(pszEscSecret);
350 free(pszEscCommunity);
47db58c2 351 free(escObjectId);
5039dede
AK
352 free(pszEscDescr);
353
354 // Save data collection items
355 if (bResult)
356 {
357 DWORD i;
358
359 for(i = 0; i < m_dwNumItems; i++)
360 m_ppItems[i]->SaveToDB(hdb);
361 }
362
363 // Save access list
364 SaveACLToDB(hdb);
365
366 // Clear modifications flag and unlock object
367 m_bIsModified = FALSE;
368 UnlockData();
369
370 return bResult;
371}
372
373
374//
375// Delete object from database
376//
377
378BOOL Node::DeleteFromDB(void)
379{
380 char szQuery[256];
381 BOOL bSuccess;
382
383 bSuccess = Template::DeleteFromDB();
384 if (bSuccess)
385 {
386 sprintf(szQuery, "DELETE FROM nodes WHERE id=%d", m_dwId);
387 QueueSQLRequest(szQuery);
388 sprintf(szQuery, "DELETE FROM nsmap WHERE node_id=%d", m_dwId);
389 QueueSQLRequest(szQuery);
390 sprintf(szQuery, "DROP TABLE idata_%d", m_dwId);
391 QueueSQLRequest(szQuery);
392 }
393 return bSuccess;
394}
395
396
397//
398// Get ARP cache from node
399//
400
401ARP_CACHE *Node::GetArpCache(void)
402{
403 ARP_CACHE *pArpCache = NULL;
404
405 if (m_dwFlags & NF_IS_LOCAL_MGMT)
406 {
407 pArpCache = GetLocalArpCache();
408 }
409 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
410 {
411 AgentLock();
412 if (ConnectToAgent())
413 pArpCache = m_pAgentConnection->GetArpCache();
414 AgentUnlock();
415 }
416 else if (m_dwFlags & NF_IS_SNMP)
417 {
418 SNMP_Transport *pTransport;
419
420 pTransport = CreateSNMPTransport();
421 pArpCache = SnmpGetArpCache(m_iSNMPVersion, pTransport,
422 m_szCommunityString);
423 delete pTransport;
424 }
425
426 return pArpCache;
427}
428
429
430//
431// Get list of interfaces from node
432//
433
434INTERFACE_LIST *Node::GetInterfaceList(void)
435{
436 INTERFACE_LIST *pIfList = NULL;
437
438 if (m_dwFlags & NF_IS_LOCAL_MGMT)
439 {
440 pIfList = GetLocalInterfaceList();
441 }
442 if ((pIfList == NULL) && (m_dwFlags & NF_IS_NATIVE_AGENT) &&
443 (!(m_dwFlags & NF_DISABLE_NXCP)))
444 {
445 AgentLock();
446 if (ConnectToAgent())
447 {
448 pIfList = m_pAgentConnection->GetInterfaceList();
449 CleanInterfaceList(pIfList);
450 }
451 AgentUnlock();
452 }
453 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP) &&
454 (!(m_dwFlags & NF_DISABLE_SNMP)))
455 {
456 SNMP_Transport *pTransport;
457 BOOL useIfXTable;
458
459 pTransport = CreateSNMPTransport();
460 if (m_nUseIfXTable == IFXTABLE_DEFAULT)
461 {
462 useIfXTable = (ConfigReadInt(_T("UseIfXTable"), 1) != 0);
463 }
464 else
465 {
466 useIfXTable = (m_nUseIfXTable == IFXTABLE_ENABLED);
467 }
468 pIfList = SnmpGetInterfaceList(m_iSNMPVersion, pTransport,
469 m_szCommunityString, m_dwNodeType,
470 useIfXTable);
471 delete pTransport;
472 }
473
474 if (pIfList != NULL)
475 CheckInterfaceNames(pIfList);
476
477 return pIfList;
478}
479
480
481//
482// Find interface by index and node IP
483// Returns pointer to interface object or NULL if appropriate interface couldn't be found
484//
485
486Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
487{
488 DWORD i;
489 Interface *pInterface;
490
491 LockChildList(FALSE);
492 for(i = 0; i < m_dwChildCount; i++)
493 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
494 {
495 pInterface = (Interface *)m_pChildList[i];
496 if (pInterface->IfIndex() == dwIndex)
497 {
498 if (((pInterface->IpAddr() & pInterface->IpNetMask()) ==
499 (dwHostAddr & pInterface->IpNetMask())) ||
500 (dwHostAddr == INADDR_ANY))
501 {
502 UnlockChildList();
503 return pInterface;
504 }
505 }
506 }
507 UnlockChildList();
508 return NULL;
509}
510
511
512//
513// Check if given IP address is one of node's interfaces
514//
515
516BOOL Node::IsMyIP(DWORD dwIpAddr)
517{
518 DWORD i;
519
520 LockChildList(FALSE);
521 for(i = 0; i < m_dwChildCount; i++)
522 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
523 {
524 if (((Interface *)m_pChildList[i])->IpAddr() == dwIpAddr)
525 {
526 UnlockChildList();
527 return TRUE;
528 }
529 }
530 UnlockChildList();
531 return FALSE;
532}
533
534
535//
536// Create new interface
537//
538
539void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName,
540 DWORD dwIndex, DWORD dwType, BYTE *pbMacAddr)
541{
542 Interface *pInterface;
543 Subnet *pSubnet = NULL;
544 Cluster *pCluster;
545 BOOL bAddToSubnet, bSyntheticMask = FALSE;
546
547 DbgPrintf(5, _T("Node::CreateNewInterface(%08X, %08X, %s, %d, %d) called for node %s [%d]"),
548 dwIpAddr, dwNetMask, szName, dwIndex, dwType, m_szName, m_dwId);
549
550 // Find subnet to place interface object to
551 if (dwIpAddr != 0)
552 {
553 pCluster = GetMyCluster();
554 bAddToSubnet = (pCluster != NULL) ? !pCluster->IsSyncAddr(dwIpAddr) : TRUE;
555 DbgPrintf(5, _T("Node::CreateNewInterface: node=%s [%d] cluster=%s [%d] add=%d"),
556 m_szName, m_dwId, (pCluster != NULL) ? pCluster->Name() : _T("(null)"),
557 (pCluster != NULL) ? pCluster->Id() : 0, bAddToSubnet);
558 if (bAddToSubnet)
559 {
560 pSubnet = FindSubnetForNode(dwIpAddr);
561 if (pSubnet == NULL)
562 {
563 // Check if netmask is 0 (detect), and if yes, create
564 // new subnet with class mask
565 if (dwNetMask == 0)
566 {
567 bSyntheticMask = TRUE;
568 if (dwIpAddr < 0xE0000000)
569 {
570 dwNetMask = 0xFFFFFF00; // Class A, B or C
571 }
572 else
573 {
574 TCHAR szBuffer[16];
575
576 // Multicast address??
577 DbgPrintf(2, _T("Attempt to create interface object with multicast address %s"),
578 IpToStr(dwIpAddr, szBuffer));
579 }
580 }
581
582 // Create new subnet object
583 if (dwIpAddr < 0xE0000000)
584 {
585 pSubnet = new Subnet(dwIpAddr & dwNetMask, dwNetMask, m_dwZoneGUID, bSyntheticMask);
586 NetObjInsert(pSubnet, TRUE);
587 g_pEntireNet->AddSubnet(pSubnet);
588 }
589 }
590 else
591 {
592 // Set correct netmask if we was asked for it
593 if (dwNetMask == 0)
594 {
595 dwNetMask = pSubnet->IpNetMask();
596 bSyntheticMask = pSubnet->IsSyntheticMask();
597 }
598 }
599 }
600 }
601
602 // Create interface object
603 if (szName != NULL)
604 pInterface = new Interface(szName, dwIndex, dwIpAddr, dwNetMask, dwType);
605 else
606 pInterface = new Interface(dwIpAddr, dwNetMask, bSyntheticMask);
607 if (pbMacAddr != NULL)
608 pInterface->SetMacAddr(pbMacAddr);
609
610 // Insert to objects' list and generate event
611 NetObjInsert(pInterface, TRUE);
612 AddInterface(pInterface);
613 if (!m_bIsHidden)
614 pInterface->Unhide();
615 PostEvent(EVENT_INTERFACE_ADDED, m_dwId, "dsaad", pInterface->Id(),
616 pInterface->Name(), pInterface->IpAddr(),
617 pInterface->IpNetMask(), pInterface->IfIndex());
618
619 // Bind node to appropriate subnet
620 if (pSubnet != NULL)
621 {
622 pSubnet->AddNode(this);
623
624 // Check if subnet mask is correct on interface
625 if ((pSubnet->IpNetMask() != pInterface->IpNetMask()) &&
626 (!pSubnet->IsSyntheticMask()))
627 {
628 PostEvent(EVENT_INCORRECT_NETMASK, m_dwId, "idsaa", pInterface->Id(),
629 pInterface->IfIndex(), pInterface->Name(),
630 pInterface->IpNetMask(), pSubnet->IpNetMask());
631 }
632 }
633}
634
635
636//
637// Delete interface from node
638//
639
640void Node::DeleteInterface(Interface *pInterface)
641{
642 DWORD i;
643
644 // Check if we should unlink node from interface's subnet
645 if (pInterface->IpAddr() != 0)
646 {
647 BOOL bUnlink = TRUE;
648
649 LockChildList(FALSE);
650 for(i = 0; i < m_dwChildCount; i++)
651 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
652 if (m_pChildList[i] != pInterface)
653 if ((((Interface *)m_pChildList[i])->IpAddr() & ((Interface *)m_pChildList[i])->IpNetMask()) ==
654 (pInterface->IpAddr() & pInterface->IpNetMask()))
655 {
656 bUnlink = FALSE;
657 break;
658 }
659 UnlockChildList();
660
661 if (bUnlink)
662 {
663 // Last interface in subnet, should unlink node
664 Subnet *pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
665 if (pSubnet != NULL)
666 {
667 DeleteParent(pSubnet);
668 pSubnet->DeleteChild(this);
669 }
670 }
671 }
672 pInterface->Delete(FALSE);
673}
674
675
676//
677// Calculate node status based on child objects status
678//
679
680void Node::CalculateCompoundStatus(BOOL bForcedRecalc)
681{
682 int iOldStatus = m_iStatus;
683 static DWORD dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_MINOR,
684 EVENT_NODE_WARNING, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
685 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
686
687 NetObj::CalculateCompoundStatus(bForcedRecalc);
688 if (m_iStatus != iOldStatus)
689 PostEvent(dwEventCodes[m_iStatus], m_dwId, "d", iOldStatus);
690}
691
692
693//
694// Perform status poll on node
695//
696
697void Node::StatusPoll(ClientSession *pSession, DWORD dwRqId, int nPoller)
698{
699 DWORD i, dwPollListSize, dwOldFlags = m_dwFlags;
700 NetObj *pPollerNode = NULL, **ppPollList;
701 BOOL bAllDown;
702 Queue *pQueue; // Delayed event queue
703 SNMP_Transport *pTransport;
704 Cluster *pCluster;
705 time_t tNow, tExpire;
706
707 pQueue = new Queue;
708 SetPollerInfo(nPoller, "wait for lock");
709 PollerLock();
710 m_pPollRequestor = pSession;
711 SendPollerMsg(dwRqId, "Starting status poll for node %s\r\n", m_szName);
712 DbgPrintf(5, "Starting status poll for node %s (ID: %d)", m_szName, m_dwId);
713
714 // Read capability expiration time and current time
715 tExpire = (time_t)ConfigReadULong(_T("CapabilityExpirationTime"), 604800);
716 tNow = time(NULL);
717
718 // Check SNMP agent connectivity
719restart_agent_check:
15d6f8c9 720 if ((m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)) && (m_dwIpAddr != 0))
5039dede
AK
721 {
722 TCHAR szBuffer[256];
723 DWORD dwResult;
724
725 DbgPrintf(6, "StatusPoll(%s): check SNMP", m_szName);
726 pTransport = CreateSNMPTransport();
727 SetPollerInfo(nPoller, "check SNMP");
728 SendPollerMsg(dwRqId, "Checking SNMP agent connectivity\r\n");
729 dwResult = SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
730 ".1.3.6.1.2.1.1.2.0", NULL, 0, szBuffer, 256,
731 FALSE, FALSE);
732 if ((dwResult == SNMP_ERR_SUCCESS) || (dwResult == SNMP_ERR_NO_OBJECT))
733 {
734 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
735 {
736 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
737 PostEventEx(pQueue, EVENT_SNMP_OK, m_dwId, NULL);
738 SendPollerMsg(dwRqId, POLLER_INFO "Connectivity with SNMP agent restored\r\n");
739 }
740 }
741 else
742 {
743 SendPollerMsg(dwRqId, POLLER_ERROR "SNMP agent unreachable\r\n");
744 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
745 {
746 if ((tNow > m_tFailTimeSNMP + tExpire) &&
747 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
748 {
749 m_dwFlags &= ~NF_IS_SNMP;
750 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
751 m_szObjectId[0] = 0;
752 SendPollerMsg(dwRqId, POLLER_WARNING "Attribute isSNMP set to FALSE\r\n");
753 }
754 }
755 else
756 {
757 m_dwDynamicFlags |= NDF_SNMP_UNREACHABLE;
758 PostEventEx(pQueue, EVENT_SNMP_FAIL, m_dwId, NULL);
759 m_tFailTimeSNMP = tNow;
760 }
761 }
762 delete pTransport;
763 DbgPrintf(6, "StatusPoll(%s): SNMP check finished", m_szName);
764 }
765
766 // Check native agent connectivity
15d6f8c9 767 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)) && (m_dwIpAddr != 0))
5039dede
AK
768 {
769 AgentConnection *pAgentConn;
770
771 DbgPrintf(6, "StatusPoll(%s): checking agent", m_szName);
772 SetPollerInfo(nPoller, "check agent");
773 SendPollerMsg(dwRqId, "Checking NetXMS agent connectivity\r\n");
774 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
775 m_wAuthMethod, m_szSharedSecret);
776 SetAgentProxy(pAgentConn);
777 if (pAgentConn->Connect(g_pServerKey))
778 {
779 DbgPrintf(7, "StatusPoll(%s): connected to agent", m_szName);
780 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
781 {
782 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
783 PostEventEx(pQueue, EVENT_AGENT_OK, m_dwId, NULL);
784 SendPollerMsg(dwRqId, POLLER_INFO "Connectivity with NetXMS agent restored\r\n");
785 }
786 pAgentConn->Disconnect();
787 DbgPrintf(7, "StatusPoll(%s): disconnected from agent", m_szName);
788 }
789 else
790 {
791 DbgPrintf(7, "StatusPoll(%s): agent unreachable", m_szName);
792 SendPollerMsg(dwRqId, POLLER_ERROR "NetXMS agent unreachable\r\n");
793 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
794 {
795 if ((tNow > m_tFailTimeAgent + tExpire) &&
796 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
797 {
798 m_dwFlags &= ~NF_IS_NATIVE_AGENT;
799 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
800 m_szPlatformName[0] = 0;
801 m_szAgentVersion[0] = 0;
802 SendPollerMsg(dwRqId, POLLER_WARNING "Attribute isNetXMSAgent set to FALSE\r\n");
803 }
804 }
805 else
806 {
807 m_dwDynamicFlags |= NDF_AGENT_UNREACHABLE;
808 PostEventEx(pQueue, EVENT_AGENT_FAIL, m_dwId, NULL);
809 m_tFailTimeAgent = tNow;
810 }
811 }
812 DbgPrintf(7, "StatusPoll(%s): deleting agent connection", m_szName);
813 delete pAgentConn;
814 DbgPrintf(7, "StatusPoll(%s): agent connection deleted", m_szName);
815 }
816
817 SetPollerInfo(nPoller, "prepare polling list");
818
819 // Find service poller node object
820 LockData();
821 if (m_dwPollerNode != 0)
822 {
823 pPollerNode = FindObjectById(m_dwPollerNode);
824 if (pPollerNode != NULL)
825 {
826 if (pPollerNode->Type() != OBJECT_NODE)
827 pPollerNode = NULL;
828 }
829 }
830 UnlockData();
831
832 // If nothing found, use management server
833 if (pPollerNode == NULL)
834 {
835 pPollerNode = FindObjectById(g_dwMgmtNode);
836 if (pPollerNode != NULL)
837 pPollerNode->IncRefCount();
838 }
839 else
840 {
841 pPollerNode->IncRefCount();
842 }
843
844 // Create polling list
845 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_dwChildCount);
846 LockChildList(FALSE);
847 for(i = 0, dwPollListSize = 0; i < m_dwChildCount; i++)
848 if (m_pChildList[i]->Status() != STATUS_UNMANAGED)
849 {
850 m_pChildList[i]->IncRefCount();
851 ppPollList[dwPollListSize++] = m_pChildList[i];
852 }
853 UnlockChildList();
854
855 // Poll interfaces and services
856 SetPollerInfo(nPoller, "child poll");
857 DbgPrintf(7, "StatusPoll(%s): starting child object poll", m_szName);
858 pCluster = GetMyCluster();
859 pTransport = CreateSNMPTransport();
860 for(i = 0; i < dwPollListSize; i++)
861 {
862 switch(ppPollList[i]->Type())
863 {
864 case OBJECT_INTERFACE:
865 DbgPrintf(7, "StatusPoll(%s): polling interface %d [%s]", m_szName, ppPollList[i]->Id(), ppPollList[i]->Name());
866 ((Interface *)ppPollList[i])->StatusPoll(pSession, dwRqId, pQueue,
867 (pCluster != NULL) ? pCluster->IsSyncAddr(((Interface *)ppPollList[i])->IpAddr()) : FALSE,
868 pTransport);
869 break;
870 case OBJECT_NETWORKSERVICE:
871 DbgPrintf(7, "StatusPoll(%s): polling network service %d [%s]", m_szName, ppPollList[i]->Id(), ppPollList[i]->Name());
872 ((NetworkService *)ppPollList[i])->StatusPoll(pSession, dwRqId,
873 (Node *)pPollerNode, pQueue);
874 break;
875 default:
876 break;
877 }
878 ppPollList[i]->DecRefCount();
879 }
880 delete pTransport;
881 safe_free(ppPollList);
882 DbgPrintf(7, "StatusPoll(%s): finished child object poll", m_szName);
883
884 // Check if entire node is down
15d6f8c9
VK
885 // This check is disabled for nodes without IP address
886 if (m_dwIpAddr != 0)
5039dede 887 {
15d6f8c9
VK
888 LockChildList(FALSE);
889 if (m_dwChildCount > 0)
890 {
891 for(i = 0, bAllDown = TRUE; i < m_dwChildCount; i++)
892 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
893 (m_pChildList[i]->Status() != STATUS_CRITICAL) &&
894 (m_pChildList[i]->Status() != STATUS_UNKNOWN) &&
895 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
896 (m_pChildList[i]->Status() != STATUS_DISABLED))
897 {
898 bAllDown = FALSE;
899 break;
900 }
901 }
902 else
903 {
904 bAllDown = FALSE;
905 }
906 UnlockChildList();
907 if (bAllDown && (m_dwFlags & NF_IS_NATIVE_AGENT) &&
908 (!(m_dwFlags & NF_DISABLE_NXCP)))
909 if (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))
910 bAllDown = FALSE;
911 if (bAllDown && (m_dwFlags & NF_IS_SNMP) &&
912 (!(m_dwFlags & NF_DISABLE_SNMP)))
913 if (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))
914 bAllDown = FALSE;
915 if (bAllDown)
916 {
917 if (!(m_dwDynamicFlags & NDF_UNREACHABLE))
918 {
919 m_dwDynamicFlags |= NDF_UNREACHABLE;
920 PostEvent(EVENT_NODE_DOWN, m_dwId, NULL);
921 SendPollerMsg(dwRqId, POLLER_ERROR "Node is unreachable\r\n");
922 }
923 else
924 {
925 SendPollerMsg(dwRqId, POLLER_WARNING "Node is still unreachable\r\n");
926 }
927 }
928 else
929 {
930 if (m_dwDynamicFlags & NDF_UNREACHABLE)
931 {
932 m_dwDynamicFlags &= ~(NDF_UNREACHABLE | NDF_SNMP_UNREACHABLE | NDF_AGENT_UNREACHABLE);
933 PostEvent(EVENT_NODE_UP, m_dwId, NULL);
934 SendPollerMsg(dwRqId, POLLER_INFO "Node recovered from unreachable state\r\n");
935 goto restart_agent_check;
936 }
937 else
938 {
939 SendPollerMsg(dwRqId, POLLER_INFO "Node is connected\r\n");
940 }
941 }
5039dede 942 }
5039dede
AK
943
944 // Send delayed events and destroy delayed event queue
945 ResendEvents(pQueue);
946 delete pQueue;
947
948 SetPollerInfo(nPoller, "cleanup");
949 if (pPollerNode != NULL)
950 pPollerNode->DecRefCount();
951
952 if (dwOldFlags != m_dwFlags)
953 {
954 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
955 LockData();
956 Modify();
957 UnlockData();
958 }
959
960 CalculateCompoundStatus();
961 m_tLastStatusPoll = time(NULL);
962 SendPollerMsg(dwRqId, "Finished status poll for node %s\r\n"
963 "Node status after poll is %s\r\n", m_szName, g_szStatusTextSmall[m_iStatus]);
964 m_pPollRequestor = NULL;
965 if (dwRqId == 0)
966 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_STATUS_POLL;
967 PollerUnlock();
968 DbgPrintf(5, "Finished status poll for node %s (ID: %d)", m_szName, m_dwId);
969}
970
971
972//
973// Perform configuration poll on node
974//
975
976void Node::ConfigurationPoll(ClientSession *pSession, DWORD dwRqId,
977 int nPoller, DWORD dwNetMask)
978{
979 DWORD i, dwOldFlags = m_dwFlags, dwAddr, rcc, dwNumParams;
980 NXC_AGENT_PARAM *pParamList;
981 Interface **ppDeleteList;
982 int j, iDelCount;
983 AgentConnection *pAgentConn;
984 INTERFACE_LIST *pIfList;
985 char szBuffer[4096];
986 Cluster *pCluster;
987 SNMP_Transport *pTransport;
5039dede
AK
988 BOOL bHasChanges = FALSE;
989
990 SetPollerInfo(nPoller, "wait for lock");
991 PollerLock();
992 m_pPollRequestor = pSession;
993 SendPollerMsg(dwRqId, _T("Starting configuration poll for node %s\r\n"), m_szName);
994 DbgPrintf(4, "Starting configuration poll for node %s (ID: %d)", m_szName, m_dwId);
995
996 // Check for forced capabilities recheck
997 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
998 {
999 m_dwFlags &= ~(NF_IS_NATIVE_AGENT | NF_IS_SNMP | NF_IS_CPSNMP |
1000 NF_IS_BRIDGE | NF_IS_ROUTER | NF_IS_OSPF);
1001 m_szObjectId[0] = 0;
1002 m_szPlatformName[0] = 0;
1003 m_szAgentVersion[0] = 0;
1004 m_szSysDescription[0] = 0;
1005 }
1006
1007 // Check if node is marked as unreachable
1008 if ((m_dwDynamicFlags & NDF_UNREACHABLE) && !(m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES))
1009 {
1010 SendPollerMsg(dwRqId, POLLER_WARNING _T("Node is marked as unreachable, configuration poll aborted\r\n"));
1011 DbgPrintf(4, "Node is marked as unreachable, configuration poll aborted");
1012 m_tLastConfigurationPoll = time(NULL);
1013 }
1014 else
1015 {
1016 // Check node's capabilities
1017 SetPollerInfo(nPoller, "capability check");
1018 SendPollerMsg(dwRqId, _T("Checking node's capabilities...\r\n"));
1019
1020 // ***** NetXMS agent check *****
1021 DbgPrintf(5, "ConfPoll(%s): checking for NetXMS agent Flags={%08X} DynamicFlags={%08X}", m_szName, m_dwFlags, m_dwDynamicFlags);
1022 if ((!((m_dwFlags & NF_IS_NATIVE_AGENT) && (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))) &&
15d6f8c9 1023 (!(m_dwFlags & NF_DISABLE_NXCP)) && (m_dwIpAddr != 0))
5039dede
AK
1024 {
1025 SendPollerMsg(dwRqId, _T(" Checking NetXMS agent...\r\n"));
1026 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
1027 m_wAuthMethod, m_szSharedSecret);
1028 SetAgentProxy(pAgentConn);
1029 DbgPrintf(5, "ConfPoll(%s): checking for NetXMS agent - connecting", m_szName);
1030 if (pAgentConn->Connect(g_pServerKey))
1031 {
1032 DbgPrintf(5, "ConfPoll(%s): checking for NetXMS agent - connected", m_szName);
1033 LockData();
1034 m_dwFlags |= NF_IS_NATIVE_AGENT;
1035 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1036 {
1037 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1038 PostEvent(EVENT_AGENT_OK, m_dwId, NULL);
1039 SendPollerMsg(dwRqId, POLLER_INFO _T(" Connectivity with NetXMS agent restored\r\n"));
1040 }
1041 UnlockData();
1042
1043 if (pAgentConn->GetParameter("Agent.Version", MAX_AGENT_VERSION_LEN, szBuffer) == ERR_SUCCESS)
1044 {
1045 LockData();
1046 if (strcmp(m_szAgentVersion, szBuffer))
1047 {
1048 strcpy(m_szAgentVersion, szBuffer);
1049 bHasChanges = TRUE;
1050 SendPollerMsg(dwRqId, _T(" NetXMS agent version changed to %s\r\n"), m_szAgentVersion);
1051 }
1052 UnlockData();
1053 }
1054
1055 if (pAgentConn->GetParameter("System.PlatformName", MAX_PLATFORM_NAME_LEN, szBuffer) == ERR_SUCCESS)
1056 {
1057 LockData();
1058 if (strcmp(m_szPlatformName, szBuffer))
1059 {
1060 strcpy(m_szPlatformName, szBuffer);
1061 bHasChanges = TRUE;
1062 SendPollerMsg(dwRqId, _T(" Platform name changed to %s\r\n"), m_szPlatformName);
1063 }
1064 UnlockData();
1065 }
1066
1067 // Check IP forwarding status
1068 if (pAgentConn->GetParameter("Net.IP.Forwarding", 16, szBuffer) == ERR_SUCCESS)
1069 {
1070 if (_tcstoul(szBuffer, NULL, 10) != 0)
1071 m_dwFlags |= NF_IS_ROUTER;
1072 else
1073 m_dwFlags &= ~NF_IS_ROUTER;
1074 }
1075
1076 // Get uname
1077 if (pAgentConn->GetParameter("System.Uname", MAX_DB_STRING, szBuffer) == ERR_SUCCESS)
1078 {
1079 TranslateStr(szBuffer, "\r\n", " ");
1080 TranslateStr(szBuffer, "\n", " ");
1081 TranslateStr(szBuffer, "\r", " ");
1082 LockData();
1083 if (strcmp(m_szSysDescription, szBuffer))
1084 {
1085 strcpy(m_szSysDescription, szBuffer);
1086 bHasChanges = TRUE;
1087 SendPollerMsg(dwRqId, _T(" System description changed to %s\r\n"), m_szSysDescription);
1088 }
1089 UnlockData();
1090 }
1091
1092 rcc = pAgentConn->GetSupportedParameters(&dwNumParams, &pParamList);
1093 if (rcc == ERR_SUCCESS)
1094 {
1095 LockData();
1096 safe_free(m_pParamList);
1097 m_dwNumParams = dwNumParams;
1098 m_pParamList = pParamList;
1099 UnlockData();
1100 }
1101 else
1102 {
1103 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::GetSupportedParameters() failed: rcc=%d"), m_szName, rcc);
1104 }
1105
1106 pAgentConn->Disconnect();
1107 SendPollerMsg(dwRqId, POLLER_INFO _T(" NetXMS native agent is active\r\n"));
1108 }
1109 delete pAgentConn;
1110 DbgPrintf(5, "ConfPoll(%s): checking for NetXMS agent - finished", m_szName);
1111 }
1112
1113 // ***** SNMP check *****
1114 if ((!((m_dwFlags & NF_IS_SNMP) && (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))) &&
15d6f8c9 1115 (!(m_dwFlags & NF_DISABLE_SNMP)) && (m_dwIpAddr != 0))
5039dede
AK
1116 {
1117 SendPollerMsg(dwRqId, _T(" Checking SNMP...\r\n"));
1118 DbgPrintf(5, "ConfPoll(%s): trying SNMP GET", m_szName);
1119 pTransport = CreateSNMPTransport();
1120
1121 strcpy(szBuffer, m_szCommunityString);
1122 if (SnmpCheckCommSettings(pTransport, szBuffer, &m_iSNMPVersion, m_szCommunityString))
1123 {
1124 DWORD dwNodeFlags, dwNodeType;
1125
1126 LockData();
1127 m_dwFlags |= NF_IS_SNMP;
1128 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
1129 {
1130 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1131 PostEvent(EVENT_SNMP_OK, m_dwId, NULL);
1132 SendPollerMsg(dwRqId, POLLER_WARNING " Connectivity with SNMP agent restored\r\n");
1133 }
1134 UnlockData();
1135 SendPollerMsg(dwRqId, _T(" SNMP agent is active (version %s)\r\n"), (m_iSNMPVersion == SNMP_VERSION_2C) ? _T("2c") : _T("1"));
1136
1137 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1138 ".1.3.6.1.2.1.1.2.0", NULL, 0, szBuffer, 4096,
1139 FALSE, FALSE) == SNMP_ERR_SUCCESS)
1140 {
1141 LockData();
1142 if (strcmp(m_szObjectId, szBuffer))
1143 {
1144 nx_strncpy(m_szObjectId, szBuffer, MAX_OID_LEN * 4);
1145 bHasChanges = TRUE;
1146 }
1147 UnlockData();
1148 }
1149
1150 // Check node type
1151 LockData();
1152 dwNodeType = OidToType(m_szObjectId, &dwNodeFlags);
1153 if (m_dwNodeType != dwNodeType)
1154 {
1155 m_dwFlags |= dwNodeFlags;
1156 m_dwNodeType = dwNodeType;
1157 SendPollerMsg(dwRqId, POLLER_WARNING _T(" Node type has been changed to %d\r\n"), m_dwNodeType);
1158 bHasChanges = TRUE;
1159 }
1160 UnlockData();
1161
1162 // Check IP forwarding
1163 if (CheckSNMPIntegerValue(pTransport, ".1.3.6.1.2.1.4.1.0", 1))
1164 {
1165 LockData();
1166 m_dwFlags |= NF_IS_ROUTER;
1167 UnlockData();
1168 }
1169 else
1170 {
1171 LockData();
1172 m_dwFlags &= ~NF_IS_ROUTER;
1173 UnlockData();
1174 }
1175
1176 // Check for bridge MIB support
1177 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1178 ".1.3.6.1.2.1.17.1.1.0", NULL, 0, szBuffer, 4096,
1179 FALSE, FALSE) == SNMP_ERR_SUCCESS)
1180 {
1181 LockData();
1182 m_dwFlags |= NF_IS_BRIDGE;
1183 UnlockData();
1184 }
1185 else
1186 {
1187 LockData();
1188 m_dwFlags &= ~NF_IS_BRIDGE;
1189 UnlockData();
1190 }
1191
1192 // Check for CDP (Cisco Discovery Protocol) support
1193 if (CheckSNMPIntegerValue(pTransport, ".1.3.6.1.4.1.9.9.23.1.3.1.0", 1))
1194 {
1195 LockData();
1196 m_dwFlags |= NF_IS_CDP;
1197 UnlockData();
1198 }
1199 else
1200 {
1201 LockData();
1202 m_dwFlags &= ~NF_IS_CDP;
1203 UnlockData();
1204 }
1205
1206 // Check for SONMP (Nortel topology discovery discovery protocol) support
1207 if (CheckSNMPIntegerValue(pTransport, ".1.3.6.1.4.1.45.1.6.13.1.2.0", 1))
1208 {
1209 LockData();
1210 m_dwFlags |= NF_IS_SONMP;
1211 UnlockData();
1212 }
1213 else
1214 {
1215 LockData();
1216 m_dwFlags &= ~NF_IS_SONMP;
1217 UnlockData();
1218 }
1219
1220 // Check for LLDP (Link Layer Discovery Protocol) support
1221 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1222 ".1.0.8802.1.1.2.1.3.2.0", NULL, 0, szBuffer, 4096,
1223 FALSE, FALSE) == SNMP_ERR_SUCCESS)
1224 {
1225 LockData();
1226 m_dwFlags |= NF_IS_LLDP;
1227 UnlockData();
1228 }
1229 else
1230 {
1231 LockData();
1232 m_dwFlags &= ~NF_IS_LLDP;
1233 UnlockData();
1234 }
1235
1236 // Get system description
1237 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1238 ".1.3.6.1.2.1.1.1.0", NULL, 0, szBuffer,
1239 MAX_DB_STRING, FALSE, FALSE) == SNMP_ERR_SUCCESS)
1240 {
1241 TranslateStr(szBuffer, "\r\n", " ");
1242 TranslateStr(szBuffer, "\n", " ");
1243 TranslateStr(szBuffer, "\r", " ");
1244 LockData();
1245 if (strcmp(m_szSysDescription, szBuffer))
1246 {
1247 strcpy(m_szSysDescription, szBuffer);
1248 bHasChanges = TRUE;
1249 SendPollerMsg(dwRqId, _T(" System description changed to %s\r\n"), m_szSysDescription);
1250 }
1251 UnlockData();
1252 }
1253
1254 CheckOSPFSupport(pTransport);
1255 }
1256 else
1257 {
1258 // Check for CheckPoint SNMP agent on port 161
1259 DbgPrintf(5, "ConfPoll(%s): checking for CheckPoint SNMP", m_szName);
1260 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1261 ".1.3.6.1.4.1.2620.1.1.10.0", NULL, 0,
1262 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
1263 {
1264 LockData();
1265 if (strcmp(m_szObjectId, ".1.3.6.1.4.1.2620.1.1"))
1266 {
1267 nx_strncpy(m_szObjectId, ".1.3.6.1.4.1.2620.1.1", MAX_OID_LEN * 4);
1268 bHasChanges = TRUE;
1269 }
1270
1271 m_dwFlags |= NF_IS_SNMP | NF_IS_ROUTER;
1272 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1273 UnlockData();
1274 SendPollerMsg(dwRqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 161 is active\r\n"));
1275 }
1276 }
1277 delete pTransport;
1278 }
1279
1280 // Check for CheckPoint SNMP agent on port 260
1281 DbgPrintf(5, "ConfPoll(%s): checking for CheckPoint SNMP on port 260", m_szName);
15d6f8c9 1282 if (!((m_dwFlags & NF_IS_CPSNMP) && (m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE)) && (m_dwIpAddr != 0))
5039dede
AK
1283 {
1284 pTransport = new SNMP_UDPTransport;
c4366266 1285 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
5039dede
AK
1286 if (SnmpGet(SNMP_VERSION_1, pTransport, m_szCommunityString,
1287 ".1.3.6.1.4.1.2620.1.1.10.0", NULL, 0,
1288 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
1289 {
1290 LockData();
1291 m_dwFlags |= NF_IS_CPSNMP | NF_IS_ROUTER;
1292 m_dwDynamicFlags &= ~NDF_CPSNMP_UNREACHABLE;
1293 UnlockData();
1294 SendPollerMsg(dwRqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 260 is active\r\n"));
1295 }
1296 delete pTransport;
1297 }
1298
1299 // Generate event if node flags has been changed
1300 if (dwOldFlags != m_dwFlags)
1301 {
1302 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
1303 bHasChanges = TRUE;
1304 }
1305
1306 // Get parent cluster object, if any
1307 pCluster = GetMyCluster();
1308
1309 // Retrieve interface list
1310 SetPollerInfo(nPoller, "interface check");
1311 SendPollerMsg(dwRqId, _T("Capability check finished\r\n"
1312 "Checking interface configuration...\r\n"));
1313 pIfList = GetInterfaceList();
1314 if (pIfList != NULL)
1315 {
1316 // Remove cluster virtual interfaces from list
1317 if (pCluster != NULL)
1318 {
1319 for(i = 0; i < (DWORD)pIfList->iNumEntries; i++)
1320 {
1321 if (pCluster->IsVirtualAddr(pIfList->pInterfaces[i].dwIpAddr))
1322 {
1323 pIfList->iNumEntries--;
1324 memmove(&pIfList->pInterfaces[i], &pIfList->pInterfaces[i + 1],
1325 sizeof(INTERFACE_INFO) * (pIfList->iNumEntries - i));
1326 i--;
1327 }
1328 }
1329 }
1330
1331 // Find non-existing interfaces
1332 LockChildList(FALSE);
1333 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
1334 for(i = 0, iDelCount = 0; i < m_dwChildCount; i++)
1335 {
1336 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1337 {
1338 Interface *pInterface = (Interface *)m_pChildList[i];
1339
1340 if (pInterface->IfType() != IFTYPE_NETXMS_NAT_ADAPTER)
1341 {
1342 for(j = 0; j < pIfList->iNumEntries; j++)
1343 {
1344 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
1345 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
1346 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
1347 break;
1348 }
1349
1350 if (j == pIfList->iNumEntries)
1351 {
1352 // No such interface in current configuration, add it to delete list
1353 ppDeleteList[iDelCount++] = pInterface;
1354 }
1355 }
1356 }
1357 }
1358 UnlockChildList();
1359
1360 // Delete non-existent interfaces
1361 if (iDelCount > 0)
1362 {
1363 for(j = 0; j < iDelCount; j++)
1364 {
1365 SendPollerMsg(dwRqId, POLLER_WARNING _T(" Interface \"%s\" is no longer exist\r\n"),
1366 ppDeleteList[j]->Name());
1367 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->IfIndex(),
1368 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->IpNetMask());
1369 DeleteInterface(ppDeleteList[j]);
1370 }
1371 bHasChanges = TRUE;
1372 }
1373 safe_free(ppDeleteList);
1374
1375 // Add new interfaces and check configuration of existing
1376 for(j = 0; j < pIfList->iNumEntries; j++)
1377 {
1378 BOOL bNewInterface = TRUE;
1379
1380 LockChildList(FALSE);
1381 for(i = 0; i < m_dwChildCount; i++)
1382 {
1383 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1384 {
1385 Interface *pInterface = (Interface *)m_pChildList[i];
1386
1387 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
1388 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
1389 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
1390 {
1391 // Existing interface, check configuration
1392 if (memcmp(pIfList->pInterfaces[j].bMacAddr, pInterface->MacAddr(), MAC_ADDR_LENGTH))
1393 {
1394 char szOldMac[16], szNewMac[16];
1395
1396 BinToStr((BYTE *)pInterface->MacAddr(), MAC_ADDR_LENGTH, szOldMac);
1397 BinToStr(pIfList->pInterfaces[j].bMacAddr, MAC_ADDR_LENGTH, szNewMac);
1398 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
1399 pInterface->Id(), pInterface->IfIndex(),
1400 pInterface->Name(), szOldMac, szNewMac);
1401 pInterface->SetMacAddr(pIfList->pInterfaces[j].bMacAddr);
1402 }
1403 if (strcmp(pIfList->pInterfaces[j].szName, pInterface->Name()))
1404 {
1405 pInterface->SetName(pIfList->pInterfaces[j].szName);
1406 }
1407 bNewInterface = FALSE;
1408 break;
1409 }
1410 }
1411 }
1412 UnlockChildList();
1413
1414 if (bNewInterface)
1415 {
1416 // New interface
1417 SendPollerMsg(dwRqId, POLLER_INFO _T(" Found new interface \"%s\"\r\n"),
1418 pIfList->pInterfaces[j].szName);
1419 CreateNewInterface(pIfList->pInterfaces[j].dwIpAddr,
1420 pIfList->pInterfaces[j].dwIpNetMask,
1421 pIfList->pInterfaces[j].szName,
1422 pIfList->pInterfaces[j].dwIndex,
1423 pIfList->pInterfaces[j].dwType,
1424 pIfList->pInterfaces[j].bMacAddr);
1425 bHasChanges = TRUE;
1426 }
1427 }
1428
1429 // Check if address we are using to communicate with node
1430 // is configured on one of node's interfaces
1431 for(i = 0; i < (DWORD)pIfList->iNumEntries; i++)
1432 if (pIfList->pInterfaces[i].dwIpAddr == m_dwIpAddr)
1433 break;
1434
1435 if (i == (DWORD)pIfList->iNumEntries)
1436 {
1437 BOOL bCreate = TRUE;
1438
1439 // Node is behind NAT
1440 m_dwFlags |= NF_BEHIND_NAT;
1441
1442 // Check if we already have NAT interface
1443 LockChildList(FALSE);
1444 for(i = 0; i < m_dwChildCount; i++)
1445 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1446 {
1447 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1448 {
1449 bCreate = FALSE;
1450 break;
1451 }
1452 }
1453 UnlockChildList();
1454
1455 if (bCreate)
1456 {
1457 char szBuffer[MAX_OBJECT_NAME];
1458
1459 // Create pseudo interface for NAT
1460 ConfigReadStr("NATAdapterName", szBuffer, MAX_OBJECT_NAME, "NetXMS NAT Adapter");
1461 CreateNewInterface(m_dwIpAddr, 0, szBuffer,
1462 0x7FFFFFFF, IFTYPE_NETXMS_NAT_ADAPTER);
1463 bHasChanges = TRUE;
1464 }
1465 }
1466 else
1467 {
1468 // Check if NF_BEHIND_NAT flag set incorrectly
1469 if (m_dwFlags & NF_BEHIND_NAT)
1470 {
1471 Interface *pIfNat;
1472
1473 // Remove NAT interface
1474 LockChildList(FALSE);
1475 for(i = 0, pIfNat = NULL; i < m_dwChildCount; i++)
1476 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1477 {
1478 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1479 {
1480 pIfNat = (Interface *)m_pChildList[i];
1481 break;
1482 }
1483 }
1484 UnlockChildList();
1485
1486 if (pIfNat != NULL)
1487 DeleteInterface(pIfNat);
1488
1489 m_dwFlags &= ~NF_BEHIND_NAT;
1490 bHasChanges = TRUE;
1491 }
1492 }
1493
1494 CheckSubnetBinding(pIfList);
1495
1496 DestroyInterfaceList(pIfList);
1497 }
1498 else /* pIfList == NULL */
1499 {
1500 Interface *pInterface;
1501 DWORD dwCount;
1502
1503 SendPollerMsg(dwRqId, POLLER_ERROR _T("Unable to get interface list from node\r\n"));
1504
1505 // Delete all existing interfaces in case of forced capability recheck
1506 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
1507 {
1508 LockChildList(FALSE);
1509 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
1510 for(i = 0, iDelCount = 0; i < m_dwChildCount; i++)
1511 {
1512 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1513 ppDeleteList[iDelCount++] = (Interface *)m_pChildList[i];
1514 }
1515 UnlockChildList();
1516 for(j = 0; j < iDelCount; j++)
1517 {
1518 SendPollerMsg(dwRqId, POLLER_WARNING _T(" Interface \"%s\" is no longer exist\r\n"),
1519 ppDeleteList[j]->Name());
1520 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->IfIndex(),
1521 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->IpNetMask());
1522 DeleteInterface(ppDeleteList[j]);
1523 }
1524 safe_free(ppDeleteList);
1525 }
1526
1527 // Check if we have pseudo-interface object
1528 dwCount = GetInterfaceCount(&pInterface);
1529 if (dwCount == 1)
1530 {
1531 if (pInterface->IsFake())
1532 {
1533 // Check if primary IP is different from interface's IP
1534 if (pInterface->IpAddr() != m_dwIpAddr)
1535 {
1536 DeleteInterface(pInterface);
15d6f8c9
VK
1537 if (m_dwIpAddr != 0)
1538 CreateNewInterface(m_dwIpAddr, dwNetMask);
5039dede
AK
1539 }
1540 }
1541 }
1542 else if (dwCount == 0)
1543 {
1544 // No interfaces at all, create pseudo-interface
15d6f8c9
VK
1545 if (m_dwIpAddr != 0)
1546 CreateNewInterface(m_dwIpAddr, dwNetMask);
5039dede
AK
1547 }
1548 }
1549
1550 m_tLastConfigurationPoll = time(NULL);
1551 SendPollerMsg(dwRqId, _T("Interface configuration check finished\r\n"));
1552
1553 // Check node name
1554 SendPollerMsg(dwRqId, _T("Checking node name\r\n"));
1555 dwAddr = ntohl(_t_inet_addr(m_szName));
1556 if ((g_dwFlags & AF_RESOLVE_NODE_NAMES) &&
1557 (dwAddr != INADDR_NONE) &&
1558 (dwAddr != INADDR_ANY) &&
1559 IsMyIP(dwAddr))
1560 {
1561 SendPollerMsg(dwRqId, _T("Node name is an IP address and need to be resolved\r\n"));
1562 SetPollerInfo(nPoller, "resolving name");
1563 if (ResolveName(FALSE))
1564 {
1565 SendPollerMsg(dwRqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_szName);
1566 bHasChanges = TRUE;
1567 }
1568 else
1569 {
1570 SendPollerMsg(dwRqId, POLLER_WARNING _T("Node name cannot be resolved\r\n"));
1571 }
1572 }
1573 else
1574 {
1575 if (g_dwFlags & AF_SYNC_NODE_NAMES_WITH_DNS)
1576 {
1577 SendPollerMsg(dwRqId, _T("Syncing node name with DNS\r\n"));
1578 SetPollerInfo(nPoller, "resolving name");
1579 if (ResolveName(TRUE))
1580 {
1581 SendPollerMsg(dwRqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_szName);
1582 bHasChanges = TRUE;
1583 }
1584 }
1585 else
1586 {
1587 SendPollerMsg(dwRqId, _T("Node name is OK\r\n"));
1588 }
1589 }
1590
4d0c32f3
VK
1591 // Apply templates
1592 ApplySystemTemplates();
1593 ApplyUserTemplates();
1594
1595 UpdateContainerMembership();
1596
1597 SendPollerMsg(dwRqId, _T("Finished configuration poll for node %s\r\n")
1598 _T("Node configuration was%schanged after poll\r\n"),
1599 m_szName, bHasChanges ? _T(" ") : _T(" not "));
1600 }
1601
1602 // Finish configuration poll
1603 SetPollerInfo(nPoller, "cleanup");
1604 if (dwRqId == 0)
1605 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1606 m_dwDynamicFlags &= ~NDF_RECHECK_CAPABILITIES;
1607 PollerUnlock();
1608 DbgPrintf(4, "Finished configuration poll for node %s (ID: %d)", m_szName, m_dwId);
1609
1610 if (bHasChanges)
1611 {
1612 LockData();
1613 Modify();
1614 UnlockData();
1615 }
1616}
1617
1618
1619//
1620// Apply system templates
1621//
1622
1623void Node::ApplySystemTemplates()
1624{
1625 Template *pTemplate;
1626
1627 pTemplate = FindTemplateByName(_T("@System.Agent"));
1628 if (pTemplate != NULL)
1629 {
1630 if (IsNativeAgent())
5039dede 1631 {
4d0c32f3 1632 if (!pTemplate->IsChild(m_dwId))
5039dede 1633 {
4d0c32f3
VK
1634 DbgPrintf(4, _T("Node::ApplySystemTemplates(): applying template %d \"%s\" to node %d \"%s\""),
1635 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
1636 pTemplate->ApplyToNode(this);
5039dede 1637 }
4d0c32f3
VK
1638 }
1639 else
1640 {
1641 if (pTemplate->IsChild(m_dwId))
5039dede 1642 {
4d0c32f3
VK
1643 DbgPrintf(4, _T("Node::ApplySystemTemplates(): removing template %d \"%s\" from node %d \"%s\""),
1644 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
1645 pTemplate->DeleteChild(this);
1646 DeleteParent(pTemplate);
1647 pTemplate->QueueRemoveFromNode(m_dwId, TRUE);
5039dede
AK
1648 }
1649 }
4d0c32f3 1650 }
5039dede 1651
4d0c32f3
VK
1652 pTemplate = FindTemplateByName(_T("@System.SNMP"));
1653 if (pTemplate != NULL)
1654 {
1655 if (IsSNMPSupported())
1656 {
1657 if (!pTemplate->IsChild(m_dwId))
1658 {
1659 DbgPrintf(4, _T("Node::ApplySystemTemplates(): applying template %d \"%s\" to node %d \"%s\""),
1660 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
1661 pTemplate->ApplyToNode(this);
1662 }
1663 }
1664 else
5039dede 1665 {
4d0c32f3
VK
1666 if (pTemplate->IsChild(m_dwId))
1667 {
1668 DbgPrintf(4, _T("Node::ApplySystemTemplates(): removing template %d \"%s\" from node %d \"%s\""),
1669 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
1670 pTemplate->DeleteChild(this);
1671 DeleteParent(pTemplate);
1672 pTemplate->QueueRemoveFromNode(m_dwId, TRUE);
1673 }
1674 }
1675 }
1676}
1677
1678
1679//
1680// Apply user templates
1681//
1682
1683void Node::ApplyUserTemplates()
1684{
1685 DWORD i;
1686 Template *pTemplate;
1687
1688 if (g_pIndexById == NULL)
1689 return;
1690
1691 RWLockReadLock(g_rwlockIdIndex, INFINITE);
1692 for(i = 0; i < g_dwIdIndexSize; i++)
1693 {
1694 if ((((NetObj *)g_pIndexById[i].pObject)->Type() == OBJECT_TEMPLATE) &&
1695 (!((NetObj *)g_pIndexById[i].pObject)->IsDeleted()))
1696 {
1697 pTemplate = (Template *)g_pIndexById[i].pObject;
1698 if (pTemplate->IsApplicable(this))
5039dede
AK
1699 {
1700 if (!pTemplate->IsChild(m_dwId))
1701 {
4d0c32f3
VK
1702 DbgPrintf(4, _T("Node::ApplyUserTemplates(): applying template %d \"%s\" to node %d \"%s\""),
1703 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
5039dede
AK
1704 pTemplate->ApplyToNode(this);
1705 }
1706 }
1707 else
1708 {
4d0c32f3 1709 if (pTemplate->IsAutoApplyEnabled() && pTemplate->IsChild(m_dwId))
5039dede 1710 {
4d0c32f3
VK
1711 DbgPrintf(4, _T("Node::ApplyUserTemplates(): removing template %d \"%s\" from node %d \"%s\""),
1712 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
5039dede
AK
1713 pTemplate->DeleteChild(this);
1714 DeleteParent(pTemplate);
1715 pTemplate->QueueRemoveFromNode(m_dwId, TRUE);
1716 }
1717 }
4d0c32f3 1718 }
5039dede 1719 }
4d0c32f3
VK
1720 RWLockUnlock(g_rwlockIdIndex);
1721}
5039dede 1722
5039dede 1723
4d0c32f3
VK
1724//
1725// Update container membership
1726//
1727
1728void Node::UpdateContainerMembership()
1729{
1730 DWORD i;
1731 Container *pContainer;
1732
1733 if (g_pIndexById == NULL)
1734 return;
1735
1736 RWLockReadLock(g_rwlockIdIndex, INFINITE);
1737 for(i = 0; i < g_dwIdIndexSize; i++)
5039dede 1738 {
4d0c32f3
VK
1739 if ((((NetObj *)g_pIndexById[i].pObject)->Type() == OBJECT_CONTAINER) &&
1740 (!((NetObj *)g_pIndexById[i].pObject)->IsDeleted()))
1741 {
1742 pContainer = (Container *)g_pIndexById[i].pObject;
1743 if (pContainer->IsSuitableForNode(this))
1744 {
1745 if (!pContainer->IsChild(m_dwId))
1746 {
1747 DbgPrintf(4, _T("Node::UpdateContainerMembership(): binding node %d \"%s\" to container %d \"%s\""),
1748 m_dwId, m_szName, pContainer->Id(), pContainer->Name());
1749 pContainer->AddChild(this);
1750 AddParent(pContainer);
1751 }
1752 }
1753 else
1754 {
1755 if (pContainer->IsAutoBindEnabled() && pContainer->IsChild(m_dwId))
1756 {
1757 DbgPrintf(4, _T("Node::UpdateContainerMembership(): removing node %d \"%s\" from container %d \"%s\""),
1758 m_dwId, m_szName, pContainer->Id(), pContainer->Name());
1759 pContainer->DeleteChild(this);
1760 DeleteParent(pContainer);
1761 }
1762 }
1763 }
5039dede 1764 }
4d0c32f3 1765 RWLockUnlock(g_rwlockIdIndex);
5039dede
AK
1766}
1767
1768
1769//
1770// Connect to native agent
1771//
1772
1773BOOL Node::ConnectToAgent(void)
1774{
1775 BOOL bRet;
1776
1777 // Create new agent connection object if needed
1778 if (m_pAgentConnection == NULL)
1779 m_pAgentConnection = new AgentConnectionEx(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
1780
1781 // Check if we already connected
45d84f8a 1782 if (m_pAgentConnection->nop() == ERR_SUCCESS)
5039dede
AK
1783 return TRUE;
1784
1785 // Close current connection or clean up after broken connection
1786 m_pAgentConnection->Disconnect();
1787 m_pAgentConnection->SetPort(m_wAgentPort);
1788 m_pAgentConnection->SetAuthData(m_wAuthMethod, m_szSharedSecret);
1789 SetAgentProxy(m_pAgentConnection);
1790 bRet = m_pAgentConnection->Connect(g_pServerKey);
1791 if (bRet)
1792 {
45d84f8a
VK
1793 m_pAgentConnection->setCommandTimeout(g_dwAgentCommandTimeout);
1794 m_pAgentConnection->enableTraps();
5039dede
AK
1795 }
1796 return bRet;
1797}
1798
1799
1800//
1801// Get item's value via SNMP
1802//
1803
1804DWORD Node::GetItemFromSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1805{
1806 DWORD dwResult;
1807
1808 if ((m_dwDynamicFlags & NDF_SNMP_UNREACHABLE) ||
1809 (m_dwDynamicFlags & NDF_UNREACHABLE))
1810 {
1811 dwResult = SNMP_ERR_COMM;
1812 }
1813 else
1814 {
1815 SNMP_Transport *pTransport;
1816
1817 pTransport = CreateSNMPTransport();
1818 dwResult = SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1819 szParam, NULL, 0, szBuffer, dwBufSize, FALSE, TRUE);
1820 delete pTransport;
1821 }
1822 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
1823 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
1824}
1825
1826
1827//
1828// Get item's value via SNMP from CheckPoint's agent
1829//
1830
1831DWORD Node::GetItemFromCheckPointSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1832{
1833 DWORD dwResult;
1834
1835 if ((m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE) ||
1836 (m_dwDynamicFlags & NDF_UNREACHABLE))
1837 {
1838 dwResult = SNMP_ERR_COMM;
1839 }
1840 else
1841 {
1842 SNMP_Transport *pTransport;
1843
1844 pTransport = new SNMP_UDPTransport;
c4366266 1845 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
5039dede
AK
1846 dwResult = SnmpGet(SNMP_VERSION_1, pTransport,
1847 m_szCommunityString, szParam, NULL, 0, szBuffer,
1848 dwBufSize, FALSE, TRUE);
1849 delete pTransport;
1850 }
1851 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
1852 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
1853}
1854
1855
1856//
1857// Get item's value via native agent
1858//
1859
1860DWORD Node::GetItemFromAgent(const char *szParam, DWORD dwBufSize, char *szBuffer)
1861{
912b994d 1862 DWORD dwError = ERR_NOT_CONNECTED, dwResult = DCE_COMM_ERROR;
5039dede
AK
1863 DWORD dwTries = 3;
1864
1865 if ((m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
1866 (m_dwDynamicFlags & NDF_UNREACHABLE))
1867 return DCE_COMM_ERROR;
1868
1869 AgentLock();
1870
1871 // Establish connection if needed
1872 if (m_pAgentConnection == NULL)
1873 if (!ConnectToAgent())
1874 goto end_loop;
1875
1876 // Get parameter from agent
1877 while(dwTries-- > 0)
1878 {
1879 dwError = m_pAgentConnection->GetParameter((char *)szParam, dwBufSize, szBuffer);
1880 switch(dwError)
1881 {
1882 case ERR_SUCCESS:
1883 dwResult = DCE_SUCCESS;
1884 goto end_loop;
1885 case ERR_UNKNOWN_PARAMETER:
1886 dwResult = DCE_NOT_SUPPORTED;
1887 goto end_loop;
1888 case ERR_NOT_CONNECTED:
1889 case ERR_CONNECTION_BROKEN:
1890 if (!ConnectToAgent())
1891 goto end_loop;
1892 break;
1893 case ERR_REQUEST_TIMEOUT:
1894 // Reset connection to agent after timeout
1895 DbgPrintf(7, _T("Node(%s)->GetItemFromAgent(%s): timeout; resetting connection to agent..."), m_szName, szParam);
1896 delete_and_null(m_pAgentConnection);
1897 if (!ConnectToAgent())
1898 goto end_loop;
1899 DbgPrintf(7, _T("Node(%s)->GetItemFromAgent(%s): connection to agent restored successfully"), m_szName, szParam);
1900 break;
1901 }
1902 }
1903
1904end_loop:
1905 AgentUnlock();
1906 DbgPrintf(7, "Node(%s)->GetItemFromAgent(%s): dwError=%d dwResult=%d",
1907 m_szName, szParam, dwError, dwResult);
1908 return dwResult;
1909}
1910
1911
1912//
1913// Get value for server's internal parameter
1914//
1915
1916DWORD Node::GetInternalItem(const char *szParam, DWORD dwBufSize, char *szBuffer)
1917{
1918 DWORD dwError = DCE_SUCCESS;
1919
1920 if (!stricmp(szParam, "Status"))
1921 {
1922 sprintf(szBuffer, "%d", m_iStatus);
1923 }
1924 else if (!stricmp(szParam, "Dummy"))
1925 {
1926 _tcscpy(szBuffer, _T("0"));
1927 }
1928 else if (!stricmp(szParam, "AgentStatus"))
1929 {
1930 if (m_dwFlags & NF_IS_NATIVE_AGENT)
1931 {
1932 szBuffer[0] = (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ? '1' : '0';
1933 szBuffer[1] = 0;
1934 }
1935 else
1936 {
1937 dwError = DCE_NOT_SUPPORTED;
1938 }
1939 }
1940 else if (MatchString("ChildStatus(*)", szParam, FALSE))
1941 {
1942 char *pEnd, szArg[256];
1943 DWORD i, dwId;
1944 NetObj *pObject = NULL;
1945
1946 NxGetParameterArg((char *)szParam, 1, szArg, 256);
1947 dwId = strtoul(szArg, &pEnd, 0);
1948 if (*pEnd != 0)
1949 {
1950 // Argument is object's name
1951 dwId = 0;
1952 }
1953
1954 // Find child object with requested ID or name
1955 LockChildList(FALSE);
1956 for(i = 0; i < m_dwChildCount; i++)
1957 {
1958 if (((dwId == 0) && (!stricmp(m_pChildList[i]->Name(), szArg))) ||
1959 (dwId == m_pChildList[i]->Id()))
1960 {
1961 pObject = m_pChildList[i];
1962 break;
1963 }
1964 }
1965 UnlockChildList();
1966
1967 if (pObject != NULL)
1968 {
1969 sprintf(szBuffer, "%d", pObject->Status());
1970 }
1971 else
1972 {
1973 dwError = DCE_NOT_SUPPORTED;
1974 }
1975 }
1976 else if (MatchString("ConditionStatus(*)", szParam, FALSE))
1977 {
1978 char *pEnd, szArg[256];
1979 DWORD dwId;
1980 NetObj *pObject = NULL;
1981
1982 NxGetParameterArg((char *)szParam, 1, szArg, 256);
1983 dwId = strtoul(szArg, &pEnd, 0);
1984 if (*pEnd == 0)
1985 {
1986 pObject = FindObjectById(dwId);
1987 if (pObject != NULL)
1988 if (pObject->Type() != OBJECT_CONDITION)
1989 pObject = NULL;
1990 }
1991 else
1992 {
1993 // Argument is object's name
1994 pObject = FindObjectByName(szArg, OBJECT_CONDITION);
1995 }
1996
1997 if (pObject != NULL)
1998 {
1999 if (pObject->IsTrustedNode(m_dwId))
2000 {
2001 sprintf(szBuffer, "%d", pObject->Status());
2002 }
2003 else
2004 {
2005 dwError = DCE_NOT_SUPPORTED;
2006 }
2007 }
2008 else
2009 {
2010 dwError = DCE_NOT_SUPPORTED;
2011 }
2012 }
2013 else if (m_dwFlags & NF_IS_LOCAL_MGMT)
2014 {
2015 if (!stricmp(szParam, "Server.AverageDCPollerQueueSize"))
2016 {
2017 sprintf(szBuffer, "%f", g_dAvgPollerQueueSize);
2018 }
2019 else if (!stricmp(szParam, "Server.AverageDBWriterQueueSize"))
2020 {
2021 sprintf(szBuffer, "%f", g_dAvgDBWriterQueueSize);
2022 }
2023 else if (!stricmp(szParam, "Server.AverageStatusPollerQueueSize"))
2024 {
2025 sprintf(szBuffer, "%f", g_dAvgStatusPollerQueueSize);
2026 }
2027 else if (!stricmp(szParam, "Server.AverageConfigurationPollerQueueSize"))
2028 {
2029 sprintf(szBuffer, "%f", g_dAvgConfigPollerQueueSize);
2030 }
2031 else if (!stricmp(szParam, "Server.AverageDCIQueuingTime"))
2032 {
2033 sprintf(szBuffer, "%u", g_dwAvgDCIQueuingTime);
2034 }
2035 else if (!stricmp(szParam, "Server.TotalEventsProcessed"))
2036 {
2037 sprintf(szBuffer, INT64_FMT, g_totalEventsProcessed);
2038 }
2039 else
2040 {
2041 dwError = DCE_NOT_SUPPORTED;
2042 }
2043 }
2044 else
2045 {
2046 dwError = DCE_NOT_SUPPORTED;
2047 }
2048
2049 return dwError;
2050}
2051
2052
2053//
2054// Get item's value for client
2055//
2056
2057DWORD Node::GetItemForClient(int iOrigin, const char *pszParam, char *pszBuffer, DWORD dwBufSize)
2058{
2059 DWORD dwResult = 0, dwRetCode;
2060
2061 // Get data from node
2062 switch(iOrigin)
2063 {
2064 case DS_INTERNAL:
2065 dwRetCode = GetInternalItem(pszParam, dwBufSize, pszBuffer);
2066 break;
2067 case DS_NATIVE_AGENT:
2068 dwRetCode = GetItemFromAgent(pszParam, dwBufSize, pszBuffer);
2069 break;
2070 case DS_SNMP_AGENT:
2071 dwRetCode = GetItemFromSNMP(pszParam, dwBufSize, pszBuffer);
2072 break;
2073 case DS_CHECKPOINT_AGENT:
2074 dwRetCode = GetItemFromCheckPointSNMP(pszParam, dwBufSize, pszBuffer);
2075 break;
2076 default:
2077 dwResult = RCC_INVALID_ARGUMENT;
2078 break;
2079 }
2080
2081 // Translate return code to RCC
2082 if (dwResult != RCC_INVALID_ARGUMENT)
2083 {
2084 switch(dwRetCode)
2085 {
2086 case DCE_SUCCESS:
2087 dwResult = RCC_SUCCESS;
2088 break;
2089 case DCE_COMM_ERROR:
2090 dwResult = RCC_COMM_FAILURE;
2091 break;
2092 case DCE_NOT_SUPPORTED:
2093 dwResult = RCC_DCI_NOT_SUPPORTED;
2094 break;
2095 default:
2096 dwResult = RCC_SYSTEM_FAILURE;
2097 break;
2098 }
2099 }
2100
2101 return dwResult;
2102}
2103
2104
2105//
2106// Put items which requires polling into the queue
2107//
2108
2109void Node::QueueItemsForPolling(Queue *pPollerQueue)
2110{
2111 DWORD i;
2112 time_t currTime;
2113
2114 if ((m_iStatus == STATUS_UNMANAGED) ||
2115 (m_dwFlags & NF_DISABLE_DATA_COLLECT) ||
2116 (m_bIsDeleted))
2117 return; // Do not collect data for unmanaged nodes or if data collection is disabled
2118
2119 currTime = time(NULL);
2120
2121 LockData();
2122 for(i = 0; i < m_dwNumItems; i++)
2123 {
2124 if (m_ppItems[i]->ReadyForPolling(currTime))
2125 {
2126 m_ppItems[i]->SetBusyFlag(TRUE);
2127 IncRefCount(); // Increment reference count for each queued DCI
2128 pPollerQueue->Put(m_ppItems[i]);
2129 }
2130 }
2131 UnlockData();
2132}
2133
2134
2135//
2136// Create CSCP message with object's data
2137//
2138
2139void Node::CreateMessage(CSCPMessage *pMsg)
2140{
2141 Template::CreateMessage(pMsg);
2142 pMsg->SetVariable(VID_FLAGS, m_dwFlags);
2143 pMsg->SetVariable(VID_AGENT_PORT, m_wAgentPort);
2144 pMsg->SetVariable(VID_AUTH_METHOD, m_wAuthMethod);
2145 pMsg->SetVariable(VID_SHARED_SECRET, m_szSharedSecret);
2146 pMsg->SetVariable(VID_COMMUNITY_STRING, m_szCommunityString);
2147 pMsg->SetVariable(VID_SNMP_OID, m_szObjectId);
2148 pMsg->SetVariable(VID_NODE_TYPE, m_dwNodeType);
2149 pMsg->SetVariable(VID_SNMP_VERSION, (WORD)m_iSNMPVersion);
2150 pMsg->SetVariable(VID_AGENT_VERSION, m_szAgentVersion);
2151 pMsg->SetVariable(VID_PLATFORM_NAME, m_szPlatformName);
2152 pMsg->SetVariable(VID_POLLER_NODE_ID, m_dwPollerNode);
2153 pMsg->SetVariable(VID_ZONE_GUID, m_dwZoneGUID);
2154 pMsg->SetVariable(VID_PROXY_NODE, m_dwProxyNode);
2155 pMsg->SetVariable(VID_SNMP_PROXY, m_dwSNMPProxy);
2156 pMsg->SetVariable(VID_REQUIRED_POLLS, (WORD)m_iRequiredPollCount);
2157 pMsg->SetVariable(VID_SYS_DESCRIPTION, m_szSysDescription);
2158 pMsg->SetVariable(VID_USE_IFXTABLE, (WORD)m_nUseIfXTable);
2159}
2160
2161
2162//
2163// Modify object from message
2164//
2165
2166DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
2167{
2168 if (!bAlreadyLocked)
2169 LockData();
2170
2171 // Change primary IP address
2172 if (pRequest->IsVariableExist(VID_IP_ADDRESS))
2173 {
2174 DWORD i, dwIpAddr;
2175
2176 dwIpAddr = pRequest->GetVariableLong(VID_IP_ADDRESS);
2177
2178 // Check if received IP address is one of node's interface addresses
2179 LockChildList(FALSE);
2180 for(i = 0; i < m_dwChildCount; i++)
2181 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
2182 (m_pChildList[i]->IpAddr() == dwIpAddr))
2183 break;
2184 UnlockChildList();
2185 if (i == m_dwChildCount)
2186 {
2187 UnlockData();
2188 return RCC_INVALID_IP_ADDR;
2189 }
2190
2191 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
2192 m_dwIpAddr = dwIpAddr;
2193 }
2194
2195 // Poller node ID
2196 if (pRequest->IsVariableExist(VID_POLLER_NODE_ID))
2197 {
2198 DWORD dwNodeId;
2199 NetObj *pObject;
2200
2201 dwNodeId = pRequest->GetVariableLong(VID_POLLER_NODE_ID);
2202 pObject = FindObjectById(dwNodeId);
2203
2204 // Check if received id is a valid node id
2205 if (pObject == NULL)
2206 {
2207 UnlockData();
2208 return RCC_INVALID_OBJECT_ID;
2209 }
2210 if (pObject->Type() != OBJECT_NODE)
2211 {
2212 UnlockData();
2213 return RCC_INVALID_OBJECT_ID;
2214 }
2215
2216 m_dwPollerNode = dwNodeId;
2217 }
2218
2219 // Change listen port of native agent
2220 if (pRequest->IsVariableExist(VID_AGENT_PORT))
2221 m_wAgentPort = pRequest->GetVariableShort(VID_AGENT_PORT);
2222
2223 // Change authentication method of native agent
2224 if (pRequest->IsVariableExist(VID_AUTH_METHOD))
2225 m_wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
2226
2227 // Change shared secret of native agent
2228 if (pRequest->IsVariableExist(VID_SHARED_SECRET))
2229 pRequest->GetVariableStr(VID_SHARED_SECRET, m_szSharedSecret, MAX_SECRET_LENGTH);
2230
2231 // Change SNMP protocol version
2232 if (pRequest->IsVariableExist(VID_SNMP_VERSION))
2233 m_iSNMPVersion = pRequest->GetVariableShort(VID_SNMP_VERSION);
2234
2235 // Change SNMP community string
2236 if (pRequest->IsVariableExist(VID_COMMUNITY_STRING))
2237 pRequest->GetVariableStr(VID_COMMUNITY_STRING, m_szCommunityString, MAX_COMMUNITY_LENGTH);
2238
2239 // Change proxy node
2240 if (pRequest->IsVariableExist(VID_PROXY_NODE))
2241 m_dwProxyNode = pRequest->GetVariableLong(VID_PROXY_NODE);
2242
2243 // Change SNMP proxy node
2244 if (pRequest->IsVariableExist(VID_SNMP_PROXY))
2245 m_dwSNMPProxy = pRequest->GetVariableLong(VID_SNMP_PROXY);
2246
2247 // Number of required polls
2248 if (pRequest->IsVariableExist(VID_REQUIRED_POLLS))
2249 m_iRequiredPollCount = (int)pRequest->GetVariableShort(VID_REQUIRED_POLLS);
2250
2251 // Enable/disable usage of ifXTable
2252 if (pRequest->IsVariableExist(VID_USE_IFXTABLE))
2253 m_nUseIfXTable = (BYTE)pRequest->GetVariableShort(VID_USE_IFXTABLE);
2254
2255 // Change flags
2256 if (pRequest->IsVariableExist(VID_FLAGS))
2257 {
2258 m_dwFlags &= NF_SYSTEM_FLAGS;
2259 m_dwFlags |= pRequest->GetVariableLong(VID_FLAGS) & NF_USER_FLAGS;
2260 }
2261
2262 return Template::ModifyFromMessage(pRequest, TRUE);
2263}
2264
2265
2266//
2267// Wakeup node using magic packet
2268//
2269
2270DWORD Node::WakeUp(void)
2271{
2272 DWORD i, dwResult = RCC_NO_WOL_INTERFACES;
2273
2274 LockChildList(FALSE);
2275
2276 for(i = 0; i < m_dwChildCount; i++)
2277 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
2278 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
2279 (m_pChildList[i]->IpAddr() != 0))
2280 {
2281 dwResult = ((Interface *)m_pChildList[i])->WakeUp();
2282 break;
2283 }
2284
2285 UnlockChildList();
2286 return dwResult;
2287}
2288
2289
2290//
2291// Get status of interface with given index from SNMP agent
2292//
2293
2294int Node::GetInterfaceStatusFromSNMP(SNMP_Transport *pTransport, DWORD dwIndex)
2295{
2296 return SnmpGetInterfaceStatus(m_iSNMPVersion, pTransport, m_szCommunityString, dwIndex);
2297}
2298
2299
2300//
2301// Get status of interface with given index from native agent
2302//
2303
2304int Node::GetInterfaceStatusFromAgent(DWORD dwIndex)
2305{
2306 char szParam[128], szBuffer[32];
2307 DWORD dwAdminStatus, dwLinkState;
2308 int iStatus;
2309
2310 // Get administrative status
2311 sprintf(szParam, "Net.Interface.AdminStatus(%u)", dwIndex);
2312 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
2313 {
2314 dwAdminStatus = strtoul(szBuffer, NULL, 0);
2315
2316 switch(dwAdminStatus)
2317 {
2318 case 3:
2319 iStatus = STATUS_TESTING;
2320 break;
2321 case 2:
2322 case 0: // Agents before 0.2.1 may return 0 instead of 2
2323 iStatus = STATUS_DISABLED;
2324 break;
2325 case 1: // Interface administratively up, check link state
2326 sprintf(szParam, "Net.Interface.Link(%u)", dwIndex);
2327 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
2328 {
2329 dwLinkState = strtoul(szBuffer, NULL, 0);
2330 iStatus = (dwLinkState == 0) ? STATUS_CRITICAL : STATUS_NORMAL;
2331 }
2332 else
2333 {
2334 iStatus = STATUS_UNKNOWN;
2335 }
2336 break;
2337 default:
2338 iStatus = STATUS_UNKNOWN;
2339 break;
2340 }
2341 }
2342 else
2343 {
2344 iStatus = STATUS_UNKNOWN;
2345 }
2346
2347 return iStatus;
2348}
2349
2350
2351//
2352// Put list of supported parameters into CSCP message
2353//
2354
2355void Node::WriteParamListToMessage(CSCPMessage *pMsg)
2356{
2357 DWORD i, dwId;
2358
2359 LockData();
2360 if (m_pParamList != NULL)
2361 {
2362 pMsg->SetVariable(VID_NUM_PARAMETERS, m_dwNumParams);
2363 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < m_dwNumParams; i++)
2364 {
2365 pMsg->SetVariable(dwId++, m_pParamList[i].szName);
2366 pMsg->SetVariable(dwId++, m_pParamList[i].szDescription);
2367 pMsg->SetVariable(dwId++, (WORD)m_pParamList[i].iDataType);
2368 }
2369 DbgPrintf(6, _T("Node[%s]::WriteParamListToMessage(): sending %d parameters"), m_szName, m_dwNumParams);
2370 }
2371 else
2372 {
2373 DbgPrintf(6, _T("Node[%s]::WriteParamListToMessage(): m_pParamList == NULL"), m_szName);
2374 pMsg->SetVariable(VID_NUM_PARAMETERS, (DWORD)0);
2375 }
2376 UnlockData();
2377}
2378
2379
2380//
2381// Open list of supported parameters for reading
2382//
2383
2384void Node::OpenParamList(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
2385{
2386 LockData();
2387 *pdwNumParams = m_dwNumParams;
2388 *ppParamList = m_pParamList;
2389}
2390
2391
2392//
2393// Check status of network service
2394//
2395
2396DWORD Node::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
2397 WORD wPort, WORD wProto, TCHAR *pszRequest,
2398 TCHAR *pszResponse)
2399{
2400 DWORD dwError = ERR_NOT_CONNECTED;
2401
2402 if ((m_dwFlags & NF_IS_NATIVE_AGENT) &&
2403 (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)) &&
2404 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
2405 {
2406 AgentConnection *pConn;
2407
2408 pConn = CreateAgentConnection();
2409 if (pConn != NULL)
2410 {
2411 dwError = pConn->CheckNetworkService(pdwStatus, dwIpAddr, iServiceType,
2412 wPort, wProto, pszRequest, pszResponse);
2413 pConn->Disconnect();
2414 delete pConn;
2415 }
2416 }
2417 return dwError;
2418}
2419
2420
2421//
2422// Handler for object deletion
2423//
2424
2425void Node::OnObjectDelete(DWORD dwObjectId)
2426{
2427 if (dwObjectId == m_dwPollerNode)
2428 {
2429 // If deleted object is our poller node, change it to default
2430 /* LOCK? */
2431 m_dwPollerNode = 0;
2432 Modify();
2433 DbgPrintf(3, _T("Node \"%s\": poller node %d deleted"), m_szName, dwObjectId);
2434 }
2435}
2436
2437
2438//
2439// Check node for OSPF support
2440//
2441
2442void Node::CheckOSPFSupport(SNMP_Transport *pTransport)
2443{
2444 LONG nAdminStatus;
2445
2446 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
2447 ".1.3.6.1.2.1.14.1.2.0", NULL, 0, &nAdminStatus, sizeof(LONG),
2448 FALSE, FALSE) == SNMP_ERR_SUCCESS)
2449 {
2450 LockData();
2451 if (nAdminStatus)
2452 {
2453 m_dwFlags |= NF_IS_OSPF;
2454 }
2455 else
2456 {
2457 m_dwFlags &= ~NF_IS_OSPF;
2458 }
2459 UnlockData();
2460 }
2461}
2462
2463
2464//
2465// Create ready to use agent connection
2466//
2467
45d84f8a 2468AgentConnectionEx *Node::CreateAgentConnection(void)
5039dede 2469{
45d84f8a 2470 AgentConnectionEx *conn;
5039dede
AK
2471
2472 if ((!(m_dwFlags & NF_IS_NATIVE_AGENT)) ||
2473 (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
2474 (m_dwDynamicFlags & NDF_UNREACHABLE))
2475 return NULL;
2476
45d84f8a
VK
2477 conn = new AgentConnectionEx(htonl(m_dwIpAddr), m_wAgentPort,
2478 m_wAuthMethod, m_szSharedSecret);
2479 SetAgentProxy(conn);
2480 if (!conn->Connect(g_pServerKey))
5039dede 2481 {
45d84f8a
VK
2482 delete conn;
2483 conn = NULL;
5039dede 2484 }
45d84f8a 2485 return conn;
5039dede
AK
2486}
2487
2488
2489//
2490// Get last collected values of all DCIs
2491//
2492
2493DWORD Node::GetLastValues(CSCPMessage *pMsg)
2494{
2495 DWORD i, dwId, dwCount;
2496
2497 LockData();
2498
2499 for(i = 0, dwId = VID_DCI_VALUES_BASE, dwCount = 0; i < m_dwNumItems; i++)
2500 {
2501 if (_tcsnicmp(m_ppItems[i]->Description(), _T("@system."), 8))
2502 {
2503 m_ppItems[i]->GetLastValue(pMsg, dwId);
2504 dwId += 10;
2505 dwCount++;
2506 }
2507 }
2508 pMsg->SetVariable(VID_NUM_ITEMS, dwCount);
2509
2510 UnlockData();
2511 return RCC_SUCCESS;
2512}
2513
2514
2515//
2516// Clean expired DCI data
2517//
2518
2519void Node::CleanDCIData(void)
2520{
2521 DWORD i;
2522
2523 LockData();
2524 for(i = 0; i < m_dwNumItems; i++)
2525 m_ppItems[i]->DeleteExpiredData();
2526 UnlockData();
2527}
2528
2529
2530//
2531// Apply DCI from template
2532// pItem passed to this method should be a template's DCI
2533//
2534
2535BOOL Node::ApplyTemplateItem(DWORD dwTemplateId, DCItem *pItem)
2536{
2537 BOOL bResult = TRUE;
2538 DWORD i;
2539 DCItem *pNewItem;
2540
2541 LockData();
2542
2543 DbgPrintf(5, "Applying item \"%s\" to node \"%s\"", pItem->Name(), m_szName);
2544
2545 // Check if that template item exists
2546 for(i = 0; i < m_dwNumItems; i++)
2547 if ((m_ppItems[i]->TemplateId() == dwTemplateId) &&
2548 (m_ppItems[i]->TemplateItemId() == pItem->Id()))
2549 break; // Item with specified id already exist
2550
2551 if (i == m_dwNumItems)
2552 {
2553 // New item from template, just add it
2554 pNewItem = new DCItem(pItem);
2555 pNewItem->SetTemplateId(dwTemplateId, pItem->Id());
2556 pNewItem->ChangeBinding(CreateUniqueId(IDG_ITEM), this, TRUE);
2557 bResult = AddItem(pNewItem, TRUE);
2558 }
2559 else
2560 {
2561 // Update existing item
2562 m_ppItems[i]->UpdateFromTemplate(pItem);
2563 Modify();
2564 }
2565
2566 UnlockData();
2567 return bResult;
2568}
2569
2570
2571//
2572// Clean deleted template items from node's DCI list
2573// Arguments is template id and list of valid template item ids.
2574// all items related to given template and not presented in list should be deleted.
2575//
2576
2577void Node::CleanDeletedTemplateItems(DWORD dwTemplateId, DWORD dwNumItems, DWORD *pdwItemList)
2578{
2579 DWORD i, j, dwNumDeleted, *pdwDeleteList;
2580
2581 LockData();
2582
2583 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
2584 dwNumDeleted = 0;
2585
2586 for(i = 0; i < m_dwNumItems; i++)
2587 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2588 {
2589 for(j = 0; j < dwNumItems; j++)
2590 if (m_ppItems[i]->TemplateItemId() == pdwItemList[j])
2591 break;
2592
2593 // Delete DCI if it's not in list
2594 if (j == dwNumItems)
2595 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->Id();
2596 }
2597
2598 for(i = 0; i < dwNumDeleted; i++)
2599 DeleteItem(pdwDeleteList[i], FALSE);
2600
2601 UnlockData();
2602 free(pdwDeleteList);
2603}
2604
2605
2606//
2607// Unbind node from template, i.e either remove DCI association with template
2608// or remove these DCIs at all
2609//
2610
2611void Node::UnbindFromTemplate(DWORD dwTemplateId, BOOL bRemoveDCI)
2612{
2613 DWORD i, dwNumDeleted, *pdwDeleteList;
2614
2615 if (bRemoveDCI)
2616 {
2617 LockData();
2618
2619 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
2620 dwNumDeleted = 0;
2621
2622 for(i = 0; i < m_dwNumItems; i++)
2623 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2624 {
2625 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->Id();
2626 }
2627
2628 for(i = 0; i < dwNumDeleted; i++)
2629 DeleteItem(pdwDeleteList[i], FALSE);
2630
2631 UnlockData();
2632 }
2633 else
2634 {
2635 LockData();
2636
2637 for(i = 0; i < m_dwNumItems; i++)
2638 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2639 {
2640 m_ppItems[i]->SetTemplateId(0, 0);
2641 }
2642
2643 UnlockData();
2644 }
2645}
2646
2647
2648//
2649// Change node's IP address
2650//
2651
2652void Node::ChangeIPAddress(DWORD dwIpAddr)
2653{
2654 DWORD i;
2655
2656 PollerLock();
2657
2658 LockData();
2659
2660 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
2661 m_dwIpAddr = dwIpAddr;
2662 m_dwDynamicFlags |= NDF_FORCE_CONFIGURATION_POLL | NDF_RECHECK_CAPABILITIES;
2663
2664 // Change status of node and all it's childs to UNKNOWN
2665 m_iStatus = STATUS_UNKNOWN;
2666 LockChildList(FALSE);
2667 for(i = 0; i < m_dwChildCount; i++)
2668 {
2669 m_pChildList[i]->ResetStatus();
2670 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2671 {
2672 if (((Interface *)m_pChildList[i])->IsFake())
2673 {
2674 ((Interface *)m_pChildList[i])->SetIpAddr(dwIpAddr);
2675 }
2676 }
2677 }
2678 UnlockChildList();
2679
2680 Modify();
2681 UnlockData();
2682
2683 AgentLock();
2684 delete_and_null(m_pAgentConnection);
2685 AgentUnlock();
2686
2687 PollerUnlock();
2688}
2689
2690
2691//
2692// Get number of interface objects and pointer to the last one
2693//
2694
2695DWORD Node::GetInterfaceCount(Interface **ppInterface)
2696{
2697 DWORD i, dwCount;
2698
2699 LockChildList(FALSE);
2700 for(i = 0, dwCount = 0; i < m_dwChildCount; i++)
2701 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2702 {
2703 dwCount++;
2704 *ppInterface = (Interface *)m_pChildList[i];
2705 }
2706 UnlockChildList();
2707 return dwCount;
2708}
2709
2710
2711//
2712// Update cache for all DCI's
2713//
2714
2715void Node::UpdateDCICache(void)
2716{
2717 DWORD i;
2718
2719 /* LOCK? */
2720 for(i = 0; i < m_dwNumItems; i++)
2721 m_ppItems[i]->UpdateCacheSize();
2722}
2723
2724
2725//
2726// Get routing table from node
2727//
2728
2729ROUTING_TABLE *Node::GetRoutingTable(void)
2730{
2731 ROUTING_TABLE *pRT = NULL;
2732
2733 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)))
2734 {
2735 AgentLock();
2736 if (ConnectToAgent())
2737 {
2738 pRT = m_pAgentConnection->GetRoutingTable();
2739 }
2740 AgentUnlock();
2741 }
2742 if ((pRT == NULL) && (m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)))
2743 {
2744 SNMP_Transport *pTransport;
2745
2746 pTransport = CreateSNMPTransport();
2747 pRT = SnmpGetRoutingTable(m_iSNMPVersion, pTransport, m_szCommunityString);
2748 delete pTransport;
2749 }
2750
2751 if (pRT != NULL)
2752 {
2753 SortRoutingTable(pRT);
2754 }
2755 return pRT;
2756}
2757
2758
2759//
2760// Get next hop for given destination address
2761//
2762
2763BOOL Node::GetNextHop(DWORD dwSrcAddr, DWORD dwDestAddr, DWORD *pdwNextHop,
2764 DWORD *pdwIfIndex, BOOL *pbIsVPN)
2765{
2766 DWORD i;
2767 BOOL bResult = FALSE;
2768
2769 // Check VPN connectors
2770 LockChildList(FALSE);
2771 for(i = 0; i < m_dwChildCount; i++)
2772 if (m_pChildList[i]->Type() == OBJECT_VPNCONNECTOR)
2773 {
2774 if (((VPNConnector *)m_pChildList[i])->IsRemoteAddr(dwDestAddr) &&
2775 ((VPNConnector *)m_pChildList[i])->IsLocalAddr(dwSrcAddr))
2776 {
2777 *pdwNextHop = ((VPNConnector *)m_pChildList[i])->GetPeerGatewayAddr();
2778 *pdwIfIndex = m_pChildList[i]->Id();
2779 *pbIsVPN = TRUE;
2780 bResult = TRUE;
2781 break;
2782 }
2783 }
2784 UnlockChildList();
2785
2786 // Check routing table
2787 if (!bResult)
2788 {
2789 RTLock();
2790 if (m_pRoutingTable != NULL)
2791 {
2792 for(i = 0; i < (DWORD)m_pRoutingTable->iNumEntries; i++)
2793 if ((dwDestAddr & m_pRoutingTable->pRoutes[i].dwDestMask) == m_pRoutingTable->pRoutes[i].dwDestAddr)
2794 {
2795 *pdwNextHop = m_pRoutingTable->pRoutes[i].dwNextHop;
2796 *pdwIfIndex = m_pRoutingTable->pRoutes[i].dwIfIndex;
2797 *pbIsVPN = FALSE;
2798 bResult = TRUE;
2799 break;
2800 }
2801 }
2802 RTUnlock();
2803 }
2804
2805 return bResult;
2806}
2807
2808
2809//
2810// Update cached routing table
2811//
2812
2813void Node::UpdateRoutingTable(void)
2814{
2815 ROUTING_TABLE *pRT;
2816
2817 pRT = GetRoutingTable();
2818 if (pRT != NULL)
2819 {
2820 RTLock();
2821 DestroyRoutingTable(m_pRoutingTable);
2822 m_pRoutingTable = pRT;
2823 RTUnlock();
2824 }
2825 m_tLastRTUpdate = time(NULL);
2826 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_ROUTE_POLL;
2827}
2828
2829
2830//
2831// Call SNMP Enumerate with node's SNMP parameters
2832//
2833
2834DWORD Node::CallSnmpEnumerate(const char *pszRootOid,
2835 DWORD (* pHandler)(DWORD, const char *, SNMP_Variable *, SNMP_Transport *, void *),
2836 void *pArg)
2837{
2838 if ((m_dwFlags & NF_IS_SNMP) &&
2839 (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)) &&
2840 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
2841 {
2842 SNMP_Transport *pTransport;
2843 DWORD dwResult;
2844
2845 pTransport = CreateSNMPTransport();
2846 dwResult = SnmpEnumerate(m_iSNMPVersion, pTransport,
2847 m_szCommunityString, pszRootOid, pHandler, pArg, FALSE);
2848 delete pTransport;
2849 return dwResult;
2850 }
2851 else
2852 {
2853 return SNMP_ERR_COMM;
2854 }
2855}
2856
2857
2858//
2859// Set proxy information for agent's connection
2860//
2861
2862void Node::SetAgentProxy(AgentConnection *pConn)
2863{
2864 if (m_dwProxyNode != 0)
2865 {
2866 Node *pNode;
2867
2868 pNode = (Node *)FindObjectById(m_dwProxyNode);
2869 if (pNode != NULL)
2870 {
2871 pConn->SetProxy(htonl(pNode->m_dwIpAddr), pNode->m_wAgentPort,
2872 pNode->m_wAuthMethod, pNode->m_szSharedSecret);
2873 }
2874 }
2875}
2876
2877
2878//
2879// Prepare node object for deletion
2880//
2881
2882void Node::PrepareForDeletion(void)
2883{
2884 // Prevent node from being queued for polling
2885 LockData();
2886 m_dwDynamicFlags |= NDF_POLLING_DISABLED;
2887 UnlockData();
2888
2889 // Wait for all pending polls
2890 while(1)
2891 {
2892 LockData();
2893 if ((m_dwDynamicFlags &
2894 (NDF_QUEUED_FOR_STATUS_POLL | NDF_QUEUED_FOR_CONFIG_POLL |
2895 NDF_QUEUED_FOR_DISCOVERY_POLL | NDF_QUEUED_FOR_ROUTE_POLL)) == 0)
2896 {
2897 UnlockData();
2898 break;
2899 }
2900 UnlockData();
2901 ThreadSleepMs(100);
2902 }
2903 Template::PrepareForDeletion();
2904}
2905
2906
2907//
2908// Check if specified SNMP variable set to specified value.
2909// If variable doesn't exist at all, will return FALSE
2910//
2911
2912BOOL Node::CheckSNMPIntegerValue(SNMP_Transport *pTransport, const char *pszOID, int nValue)
2913{
2914 DWORD dwTemp;
2915
2916 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
2917 pszOID, NULL, 0, &dwTemp, sizeof(DWORD), FALSE, FALSE) == SNMP_ERR_SUCCESS)
2918 return (int)dwTemp == nValue;
2919 return FALSE;
2920}
2921
2922
2923//
2924// Check and update if needed interface names
2925//
2926
2927void Node::CheckInterfaceNames(INTERFACE_LIST *pIfList)
2928{
2929 int i;
2930 TCHAR *ptr;
2931
2932 if ((m_dwNodeType == NODE_TYPE_NORTEL_BAYSTACK) ||
2933 (m_dwNodeType == NODE_TYPE_NORTEL_OPTERA))
2934 {
2935 // Translate interface names
2936 for(i = 0; i < pIfList->iNumEntries; i++)
2937 {
2938 if ((ptr = _tcsstr(pIfList->pInterfaces[i].szName, _T("- Port"))) != NULL)
2939 {
2940 ptr += 2;
2941 memmove(pIfList->pInterfaces[i].szName, ptr, _tcslen(ptr) + 1);
2942 }
2943 else if ((ptr = _tcsstr(pIfList->pInterfaces[i].szName, _T("- Unit"))) != NULL)
2944 {
2945 ptr += 2;
2946 memmove(pIfList->pInterfaces[i].szName, ptr, _tcslen(ptr) + 1);
2947 }
2948 else if ((_tcsstr(pIfList->pInterfaces[i].szName, _T("BayStack")) != NULL) ||
2949 (_tcsstr(pIfList->pInterfaces[i].szName, _T("Nortel Ethernet Switch")) != NULL))
2950 {
2951 ptr = _tcsrchr(pIfList->pInterfaces[i].szName, _T('-'));
2952 if (ptr != NULL)
2953 {
2954 ptr++;
2955 while(*ptr == _T(' '))
2956 ptr++;
2957 memmove(pIfList->pInterfaces[i].szName, ptr, _tcslen(ptr) + 1);
2958 }
2959 }
2960 StrStrip(pIfList->pInterfaces[i].szName);
2961 }
2962 }
2963
2964 // Cut interface names to MAX_OBJECT_NAME and check for unnamed interfaces
2965 for(i = 0; i < pIfList->iNumEntries; i++)
2966 {
2967 pIfList->pInterfaces[i].szName[MAX_OBJECT_NAME - 1] = 0;
2968 if (pIfList->pInterfaces[i].szName[0] == 0)
2969 _stprintf(pIfList->pInterfaces[i].szName, _T("%d"), pIfList->pInterfaces[i].dwIndex);
2970 }
2971}
2972
2973
2974//
2975// Get cluster object this node belongs to, if any
2976//
2977
2978Cluster *Node::GetMyCluster(void)
2979{
2980 DWORD i;
2981 Cluster *pCluster = NULL;
2982
2983 LockParentList(FALSE);
2984 for(i = 0; i < m_dwParentCount; i++)
2985 if (m_pParentList[i]->Type() == OBJECT_CLUSTER)
2986 {
2987 pCluster = (Cluster *)m_pParentList[i];
2988 break;
2989 }
2990 UnlockParentList();
2991 return pCluster;
2992}
2993
2994
2995//
2996// Create SNMP transport
2997//
2998
2999SNMP_Transport *Node::CreateSNMPTransport(void)
3000{
3001 SNMP_Transport *pTransport = NULL;
3002
3003 if (m_dwSNMPProxy == 0)
3004 {
3005 pTransport = new SNMP_UDPTransport;
c4366266 3006 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), m_wSNMPPort);
5039dede
AK
3007 }
3008 else
3009 {
3010 NetObj *pObject;
3011
3012 pObject = FindObjectById(m_dwSNMPProxy);
3013 if (pObject != NULL)
3014 {
3015 if (pObject->Type() == OBJECT_NODE)
3016 {
3017 AgentConnection *pConn;
3018
3019 pConn = ((Node *)pObject)->CreateAgentConnection();
3020 if (pConn != NULL)
3021 {
3022 pTransport = new SNMP_ProxyTransport(pConn, m_dwIpAddr, m_wSNMPPort);
3023 }
3024 }
3025 }
3026 }
3027 return pTransport;
3028}
3029
3030
3031//
3032// Resolve node's name
3033//
3034
3035BOOL Node::ResolveName(BOOL useOnlyDNS)
3036{
3037 BOOL bSuccess = FALSE;
3038 HOSTENT *hs;
3039 DWORD i, dwAddr;
3040 TCHAR szBuffer[256];
3041
3042 DbgPrintf(4, _T("Resolving name for node %d [%s]..."), m_dwId, m_szName);
3043
3044 // Try to resolve primary IP
3045 dwAddr = htonl(m_dwIpAddr);
3046 hs = gethostbyaddr((const char *)&dwAddr, 4, AF_INET);
3047 if (hs != NULL)
3048 {
3049 nx_strncpy(m_szName, hs->h_name, MAX_OBJECT_NAME);
3050 bSuccess = TRUE;
3051 }
3052 else
3053 {
3054 // Try to resolve each interface's IP address
3055 LockChildList(FALSE);
3056 for(i = 0; i < m_dwChildCount; i++)
3057 {
3058 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
3059 {
3060 dwAddr = htonl(m_pChildList[i]->IpAddr());
3061 if (dwAddr != 0)
3062 {
3063 hs = gethostbyaddr((const char *)&dwAddr, 4, AF_INET);
3064 if (hs != NULL)
3065 {
3066 nx_strncpy(m_szName, hs->h_name, MAX_OBJECT_NAME);
3067 bSuccess = TRUE;
3068 break;
3069 }
3070 }
3071 }
3072 }
3073 UnlockChildList();
3074
3075 // Try to get hostname from agent if address resolution fails
3076 if (!(bSuccess || useOnlyDNS))
3077 {
3078 DbgPrintf(4, _T("Resolving name for node %d [%s] via agent..."), m_dwId, m_szName);
3079 if (GetItemFromAgent("System.Hostname", 256, szBuffer) == DCE_SUCCESS)
3080 {
3081 StrStrip(szBuffer);
3082 if (szBuffer[0] != 0)
3083 {
3084 nx_strncpy(m_szName, szBuffer, MAX_OBJECT_NAME);
3085 bSuccess = TRUE;
3086 }
3087 }
3088 }
3089
3090 // Try to get hostname from SNMP if other methods fails
3091 if (!(bSuccess || useOnlyDNS))
3092 {
3093 DbgPrintf(4, _T("Resolving name for node %d [%s] via SNMP..."), m_dwId, m_szName);
3094 if (GetItemFromSNMP(".1.3.6.1.2.1.1.5.0", 256, szBuffer) == DCE_SUCCESS)
3095 {
3096 StrStrip(szBuffer);
3097 if (szBuffer[0] != 0)
3098 {
3099 nx_strncpy(m_szName, szBuffer, MAX_OBJECT_NAME);
3100 bSuccess = TRUE;
3101 }
3102 }
3103 }
3104 }
3105
3106 if (bSuccess)
3107 DbgPrintf(4, _T("Name for node %d was resolved to %s"), m_dwId, m_szName);
3108 else
3109 DbgPrintf(4, _T("Name for node %d was not resolved"), m_dwId, m_szName);
3110 return bSuccess;
3111}
3112
3113
3114//
3115// Send list of system DCIs
3116//
3117
3118DWORD Node::GetSystemDCIList(CSCPMessage *pMsg)
3119{
3120 DWORD i, dwId, dwCount;
3121
3122 LockData();
3123
3124 for(i = 0, dwId = VID_SYSDCI_LIST_BASE, dwCount = 0; i < m_dwNumItems; i++)
3125 {
3126 if (!_tcsnicmp(m_ppItems[i]->Description(), _T("@System."), 8))
3127 {
3128 pMsg->SetVariable(dwId++, m_ppItems[i]->Id());
3129 pMsg->SetVariable(dwId++, (TCHAR *)m_ppItems[i]->Description());
3130 pMsg->SetVariable(dwId++, (WORD)m_ppItems[i]->Status());
3131 dwId += 7;
3132 dwCount++;
3133 }
3134 }
3135 pMsg->SetVariable(VID_NUM_ITEMS, dwCount);
3136
3137 UnlockData();
3138 return RCC_SUCCESS;
3139}
3140
3141
3142//
3143// Get current layer 2 topology (as dynamically created list which should be destroyed by caller)
3144// Will return NULL if there are no topology information or it is expired
3145//
3146
3147nxmap_ObjList *Node::GetL2Topology(void)
3148{
3149 nxmap_ObjList *pResult;
3150 DWORD dwExpTime;
3151
3152 dwExpTime = ConfigReadULong(_T("TopologyExpirationTime"), 900);
3153 MutexLock(m_mutexTopoAccess, INFINITE);
3154 if ((m_pTopology == NULL) || (m_tLastTopologyPoll + (time_t)dwExpTime < time(NULL)))
3155 {
3156 pResult = NULL;
3157 }
3158 else
3159 {
3160 pResult = new nxmap_ObjList(m_pTopology);
3161 }
3162 MutexUnlock(m_mutexTopoAccess);
3163 return pResult;
3164}
3165
3166
3167//
3168// Rebuild layer 2 topology and return it as dynamically reated list which should be destroyed by caller
3169//
3170
3171nxmap_ObjList *Node::BuildL2Topology(DWORD *pdwStatus)
3172{
3173 nxmap_ObjList *pResult;
3174 int nDepth;
3175
3176 nDepth = ConfigReadInt(_T("TopologyDiscoveryRadius"), 5);
3177 MutexLock(m_mutexTopoAccess, INFINITE);
3178 delete m_pTopology;
3179 if ((m_dwFlags & NF_IS_CDP) || (m_dwFlags & NF_IS_SONMP) || (m_dwFlags & NF_IS_LLDP))
3180 {
3181 m_pTopology = new nxmap_ObjList;
3182 if ((*pdwStatus = ::BuildL2Topology(*m_pTopology, this, NULL, nDepth, NULL)) == RCC_SUCCESS)
3183 {
3184 m_tLastTopologyPoll = time(NULL);
3185 pResult = new nxmap_ObjList(m_pTopology);
3186 }
3187 else
3188 {
3189 delete_and_null(m_pTopology);
3190 pResult = NULL;
3191 }
3192 }
3193 else
3194 {
3195 pResult = NULL;
3196 m_pTopology = NULL;
3197 *pdwStatus = RCC_NO_L2_TOPOLOGY_SUPPORT;
3198 }
3199 MutexUnlock(m_mutexTopoAccess);
3200 return pResult;
3201}
3202
3203
3204//
3205// Check subnet bindings
3206//
3207
3208void Node::CheckSubnetBinding(INTERFACE_LIST *pIfList)
3209{
3210 Subnet *pSubnet;
3211 Interface *pInterface;
3212 Cluster *pCluster;
3213 NetObj **ppUnlinkList;
3214 int i, j, count;
3215 BOOL isSync;
3216
3217 pCluster = GetMyCluster();
3218
3219 // Check if we have subnet bindings for all interfaces
3220 for(i = 0; i < pIfList->iNumEntries; i++)
3221 {
3222 if (pIfList->pInterfaces[i].dwIpAddr != 0)
3223 {
3224 pInterface = FindInterface(pIfList->pInterfaces[i].dwIndex, pIfList->pInterfaces[i].dwIpAddr);
3225 if (pInterface == NULL)
3226 {
3227 nxlog_write(MSG_INTERNAL_ERROR, EVENTLOG_WARNING_TYPE, "s", _T("Cannot find interface object in Node::CheckSubnetBinding()"));
3228 break; // Something goes really wrong
3229 }
3230
3231 // Is cluster interconnect interface?
3232 isSync = (pCluster != NULL) ? pCluster->IsSyncAddr(pInterface->IpAddr()) : FALSE;
3233
3234 pSubnet = FindSubnetForNode(pIfList->pInterfaces[i].dwIpAddr);
3235 if (pSubnet != NULL)
3236 {
3237 if (isSync)
3238 {
3239 pSubnet = NULL; // No further checks on this subnet
3240 }
3241 else
3242 {
3243 if (pSubnet->IsSyntheticMask())
3244 {
3245 DbgPrintf(4, _T("Setting correct netmask for subnet %s [%d] from node %s [%d]"),
3246 pSubnet->Name(), pSubnet->Id(), m_szName, m_dwId);
3247 pSubnet->SetCorrectMask(pInterface->IpAddr() & pInterface->IpNetMask(), pInterface->IpNetMask());
3248 }
3249 }
3250 }
3251 else if (!isSync)
3252 {
3253 // Create subnet
3254 pSubnet = new Subnet(pIfList->pInterfaces[i].dwIpAddr & pIfList->pInterfaces[i].dwIpNetMask,
3255 pIfList->pInterfaces[i].dwIpNetMask, m_dwZoneGUID, FALSE);
3256 NetObjInsert(pSubnet, TRUE);
3257 g_pEntireNet->AddSubnet(pSubnet);
3258 pSubnet->AddNode(this);
3259 DbgPrintf(4, _T("Node::CheckSubnetBinding(): Creating new subnet %s [%d] for node %s [%d]"),
3260 pSubnet->Name(), pSubnet->Id(), m_szName, m_dwId);
3261 }
3262
3263 // Check if subnet mask is correct on interface
3264 if ((pSubnet != NULL) && (pSubnet->IpNetMask() != pIfList->pInterfaces[i].dwIpNetMask))
3265 {
3266 PostEvent(EVENT_INCORRECT_NETMASK, m_dwId, "idsaa", pInterface->Id(),
3267 pInterface->IfIndex(), pInterface->Name(),
3268 pInterface->IpNetMask(), pSubnet->IpNetMask());
3269 }
3270 }
3271 }
3272
3273 // Check if we have incorrect subnets as parents
3274 LockParentList(FALSE);
3275 LockChildList(FALSE);
3276 ppUnlinkList = (NetObj **)malloc(sizeof(NetObj *) * m_dwParentCount);
3277 for(i = 0, count = 0; i < (int)m_dwParentCount; i++)
3278 {
3279 if (m_pParentList[i]->Type() == OBJECT_SUBNET)
3280 {
3281 pSubnet = (Subnet *)m_pParentList[i];
3282 for(j = 0; j < (int)m_dwChildCount; j++)
3283 {
3284 if (m_pChildList[j]->Type() == OBJECT_INTERFACE)
3285 {
3286 if (pSubnet->IpAddr() == (m_pChildList[j]->IpAddr() & pSubnet->IpNetMask()))
3287 {
3288 if (pCluster != NULL)
3289 {
3290 if (pCluster->IsSyncAddr(m_pChildList[j]->IpAddr()))
3291 {
3292 j = (int)m_dwChildCount; // Cause to unbind from this subnet
3293 }
3294 }
3295 break;
3296 }
3297 }
3298 }
3299 if (j == (int)m_dwChildCount)
3300 {
3301 DbgPrintf(4, _T("Node::CheckSubnetBinding(): Subnet %s [%d] is incorrect for node %s [%d]"),
3302 pSubnet->Name(), pSubnet->Id(), m_szName, m_dwId);
3303 ppUnlinkList[count++] = pSubnet;
3304 }
3305 }
3306 }
3307 UnlockChildList();
3308 UnlockParentList();
3309
3310 // Unlink for incorrect subnet objects
3311 for(i = 0; i < count; i++)
3312 {
3313 ppUnlinkList[i]->DeleteChild(this);
3314 DeleteParent(ppUnlinkList[i]);
3315 }
3316 safe_free(ppUnlinkList);
3317}
3318
3319
3320//
3321// Update interface names
3322//
3323
3324void Node::UpdateInterfaceNames(ClientSession *pSession, DWORD dwRqId)
3325{
3326 INTERFACE_LIST *pIfList;
3327 DWORD i;
3328 int j;
3329
3330 PollerLock();
3331 m_pPollRequestor = pSession;
3332 SendPollerMsg(dwRqId, _T("Starting interface names poll for node %s\r\n"), m_szName);
3333 DbgPrintf(4, "Starting interface names poll for node %s (ID: %d)", m_szName, m_dwId);
3334
3335 // Retrieve interface list
3336 pIfList = GetInterfaceList();
3337 if (pIfList != NULL)
3338 {
3339 // Check names of existing interfaces
3340 for(j = 0; j < pIfList->iNumEntries; j++)
3341 {
3342 LockChildList(FALSE);
3343 for(i = 0; i < m_dwChildCount; i++)
3344 {
3345 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
3346 {
3347 Interface *pInterface = (Interface *)m_pChildList[i];
3348
3349 if (pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex())
3350 {
3351 SendPollerMsg(dwRqId, _T(" Checking interface %d (%s)\r\n"), pInterface->IfIndex(), pInterface->Name());
3352 if (strcmp(pIfList->pInterfaces[j].szName, pInterface->Name()))
3353 {
3354 pInterface->SetName(pIfList->pInterfaces[j].szName);
3355 SendPollerMsg(dwRqId, POLLER_WARNING _T(" Name of interface %d changed to %s\r\n"), pInterface->IfIndex(), pIfList->pInterfaces[j].szName);
3356 }
3357 break;
3358 }
3359 }
3360 }
3361 UnlockChildList();
3362 }
3363
3364 DestroyInterfaceList(pIfList);
3365 }
3366 else /* pIfList == NULL */
3367 {
3368 SendPollerMsg(dwRqId, POLLER_ERROR _T(" Unable to get interface list from node\r\n"));
3369 }
3370
3371 // Finish poll
3372 SendPollerMsg(dwRqId, _T("Finished interface names poll for node %s\r\n"), m_szName);
3373 PollerUnlock();
3374 DbgPrintf(4, "Finished interface names poll for node %s (ID: %d)", m_szName, m_dwId);
3375}