intermediate changes
[public/netxms.git] / src / server / core / node.cpp
CommitLineData
4d2c3a54 1/*
5039dede 2** NetXMS - Network Management System
7aad6641 3** Copyright (C) 2003-2013 Victor Kirhenshtein
5039dede
AK
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** File: node.cpp
20**
21**/
22
23#include "nxcore.h"
24
7aad6641
VK
25/**
26 * Externals
27 */
46117060
VK
28extern Queue g_statusPollQueue;
29extern Queue g_configPollQueue;
30extern Queue g_topologyPollQueue;
31extern Queue g_routePollQueue;
32extern Queue g_discoveryPollQueue;
33
c50f77f7
VK
34/**
35 * Node class default constructor
36 */
6fd6de0a 37Node::Node() : DataCollectionTarget()
5039dede 38{
5ad2167d 39 m_primaryName[0] = 0;
a65c1819 40 m_iStatus = STATUS_UNKNOWN;
5039dede
AK
41 m_dwFlags = 0;
42 m_dwDynamicFlags = 0;
52c31148 43 m_zoneId = 0;
5039dede
AK
44 m_wAgentPort = AGENT_LISTEN_PORT;
45 m_wAuthMethod = AUTH_NONE;
46 m_szSharedSecret[0] = 0;
47 m_iStatusPollType = POLL_ICMP_PING;
5d2c5741 48 m_snmpVersion = SNMP_VERSION_1;
5039dede 49 m_wSNMPPort = SNMP_DEFAULT_PORT;
35f836fe
VK
50 char community[MAX_COMMUNITY_LENGTH];
51 ConfigReadStrA(_T("DefaultCommunityString"), community, MAX_COMMUNITY_LENGTH, "public");
5d2c5741 52 m_snmpSecurity = new SNMP_SecurityContext(community);
5039dede 53 m_szObjectId[0] = 0;
8573e935
VK
54 m_lastDiscoveryPoll = 0;
55 m_lastStatusPoll = 0;
56 m_lastConfigurationPoll = 0;
57 m_lastTopologyPoll = 0;
58 m_lastRTUpdate = 0;
59 m_downSince = 0;
71e4ed3a 60 m_bootTime = 0;
5039dede
AK
61 m_hPollerMutex = MutexCreate();
62 m_hAgentAccessMutex = MutexCreate();
1d0d82b3 63 m_hSmclpAccessMutex = MutexCreate();
5039dede
AK
64 m_mutexRTAccess = MutexCreate();
65 m_mutexTopoAccess = MutexCreate();
66 m_pAgentConnection = NULL;
1d0d82b3 67 m_smclpConnection = NULL;
fed33789 68 m_lastAgentTrapId = 0;
42a3be4f 69 m_lastAgentPushRequestId = 0;
5039dede
AK
70 m_szAgentVersion[0] = 0;
71 m_szPlatformName[0] = 0;
0ecc2200
VK
72 m_sysDescription = NULL;
73 m_sysName = NULL;
74 m_lldpNodeId = NULL;
3a82d5ae 75 m_lldpLocalPortInfo = NULL;
cc8ce218
VK
76 m_paramList = NULL;
77 m_tableList = NULL;
5039dede
AK
78 m_dwPollerNode = 0;
79 m_dwProxyNode = 0;
80 m_dwSNMPProxy = 0;
81 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
82 m_pRoutingTable = NULL;
8573e935
VK
83 m_failTimeSNMP = 0;
84 m_failTimeAgent = 0;
040c45fa 85 m_linkLayerNeighbors = NULL;
0d75ea88 86 m_vrrpInfo = NULL;
8573e935 87 m_lastTopologyPoll = 0;
040c45fa
VK
88 m_pTopology = NULL;
89 m_topologyRebuildTimestamp = 0;
5039dede
AK
90 m_iPendingStatus = -1;
91 m_iPollCount = 0;
92 m_iRequiredPollCount = 0; // Use system default
93 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
ab621f39 94 m_jobQueue = new ServerJobQueue();
f42b8099 95 m_fdb = NULL;
7f632dfe 96 m_vlans = NULL;
d5de1d1d 97 m_wirelessStations = NULL;
f1989a3a
VK
98 m_adoptedApCount = 0;
99 m_totalApCount = 0;
9796ce45 100 m_driver = NULL;
ae32341d 101 m_driverData = NULL;
50d0de67 102 m_components = NULL;
caa04e26 103 m_softwarePackages = NULL;
46ee6286 104 m_winPerfObjects = NULL;
3eab63f2 105 memset(m_baseBridgeAddress, 0, MAC_ADDR_LENGTH);
5039dede
AK
106}
107
c50f77f7
VK
108/**
109 * Constructor for new node object
110 */
967893bb 111Node::Node(UINT32 dwAddr, UINT32 dwFlags, UINT32 dwProxyNode, UINT32 dwSNMPProxy, UINT32 dwZone) : DataCollectionTarget()
5039dede 112{
5ad2167d 113 IpToStr(dwAddr, m_primaryName);
a65c1819 114 m_iStatus = STATUS_UNKNOWN;
5039dede
AK
115 m_dwIpAddr = dwAddr;
116 m_dwFlags = dwFlags;
117 m_dwDynamicFlags = 0;
52c31148 118 m_zoneId = dwZone;
5039dede
AK
119 m_wAgentPort = AGENT_LISTEN_PORT;
120 m_wAuthMethod = AUTH_NONE;
121 m_szSharedSecret[0] = 0;
122 m_iStatusPollType = POLL_ICMP_PING;
5d2c5741 123 m_snmpVersion = SNMP_VERSION_1;
5039dede 124 m_wSNMPPort = SNMP_DEFAULT_PORT;
35f836fe
VK
125 char community[MAX_COMMUNITY_LENGTH];
126 ConfigReadStrA(_T("DefaultCommunityString"), community, MAX_COMMUNITY_LENGTH, "public");
5d2c5741 127 m_snmpSecurity = new SNMP_SecurityContext(community);
5039dede
AK
128 IpToStr(dwAddr, m_szName); // Make default name from IP address
129 m_szObjectId[0] = 0;
8573e935
VK
130 m_lastDiscoveryPoll = 0;
131 m_lastStatusPoll = 0;
132 m_lastConfigurationPoll = 0;
133 m_lastTopologyPoll = 0;
134 m_lastRTUpdate = 0;
135 m_downSince = 0;
71e4ed3a 136 m_bootTime = 0;
5039dede
AK
137 m_hPollerMutex = MutexCreate();
138 m_hAgentAccessMutex = MutexCreate();
1d0d82b3 139 m_hSmclpAccessMutex = MutexCreate();
5039dede
AK
140 m_mutexRTAccess = MutexCreate();
141 m_mutexTopoAccess = MutexCreate();
142 m_pAgentConnection = NULL;
1d0d82b3 143 m_smclpConnection = NULL;
fed33789 144 m_lastAgentTrapId = 0;
42a3be4f 145 m_lastAgentPushRequestId = 0;
5039dede
AK
146 m_szAgentVersion[0] = 0;
147 m_szPlatformName[0] = 0;
0ecc2200
VK
148 m_sysDescription = NULL;
149 m_sysName = NULL;
150 m_lldpNodeId = NULL;
3a82d5ae 151 m_lldpLocalPortInfo = NULL;
cc8ce218
VK
152 m_paramList = NULL;
153 m_tableList = NULL;
5039dede
AK
154 m_dwPollerNode = 0;
155 m_dwProxyNode = dwProxyNode;
156 m_dwSNMPProxy = dwSNMPProxy;
157 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
01152a54 158 m_isHidden = true;
5039dede 159 m_pRoutingTable = NULL;
8573e935
VK
160 m_failTimeSNMP = 0;
161 m_failTimeAgent = 0;
040c45fa 162 m_linkLayerNeighbors = NULL;
0d75ea88 163 m_vrrpInfo = NULL;
8573e935 164 m_lastTopologyPoll = 0;
040c45fa
VK
165 m_pTopology = NULL;
166 m_topologyRebuildTimestamp = 0;
5039dede
AK
167 m_iPendingStatus = -1;
168 m_iPollCount = 0;
169 m_iRequiredPollCount = 0; // Use system default
170 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
ab621f39 171 m_jobQueue = new ServerJobQueue();
f42b8099 172 m_fdb = NULL;
7f632dfe 173 m_vlans = NULL;
d5de1d1d 174 m_wirelessStations = NULL;
f1989a3a
VK
175 m_adoptedApCount = 0;
176 m_totalApCount = 0;
9796ce45 177 m_driver = NULL;
ae32341d 178 m_driverData = NULL;
50d0de67 179 m_components = NULL;
caa04e26 180 m_softwarePackages = NULL;
46ee6286 181 m_winPerfObjects = NULL;
3eab63f2 182 memset(m_baseBridgeAddress, 0, MAC_ADDR_LENGTH);
5039dede
AK
183}
184
c50f77f7
VK
185/**
186 * Node destructor
187 */
5039dede
AK
188Node::~Node()
189{
ae32341d
VK
190 if ((m_driver != NULL) && (m_driverData != NULL))
191 m_driver->destroyDriverData(m_driverData);
5039dede
AK
192 MutexDestroy(m_hPollerMutex);
193 MutexDestroy(m_hAgentAccessMutex);
1d0d82b3 194 MutexDestroy(m_hSmclpAccessMutex);
5039dede
AK
195 MutexDestroy(m_mutexRTAccess);
196 MutexDestroy(m_mutexTopoAccess);
197 delete m_pAgentConnection;
1d0d82b3 198 delete m_smclpConnection;
cc8ce218
VK
199 delete m_paramList;
200 delete m_tableList;
bb151059 201 safe_free(m_sysDescription);
5039dede 202 DestroyRoutingTable(m_pRoutingTable);
a9ad9f61
VK
203 if (m_linkLayerNeighbors != NULL)
204 m_linkLayerNeighbors->decRefCount();
0d75ea88 205 delete m_vrrpInfo;
5039dede 206 delete m_pTopology;
ab621f39 207 delete m_jobQueue;
5d2c5741 208 delete m_snmpSecurity;
f42b8099
VK
209 if (m_fdb != NULL)
210 m_fdb->decRefCount();
7f632dfe
VK
211 if (m_vlans != NULL)
212 m_vlans->decRefCount();
d5de1d1d 213 delete m_wirelessStations;
50d0de67 214 delete m_components;
3a82d5ae 215 delete m_lldpLocalPortInfo;
caa04e26 216 delete m_softwarePackages;
46ee6286 217 delete m_winPerfObjects;
5039dede
AK
218}
219
c50f77f7
VK
220/**
221 * Create object from database data
222 */
967893bb 223BOOL Node::CreateFromDB(UINT32 dwId)
5039dede 224{
5039dede 225 int i, iNumRows;
967893bb 226 UINT32 dwSubnetId;
5039dede
AK
227 NetObj *pObject;
228 BOOL bResult = FALSE;
229
230 m_dwId = dwId;
231
89135050 232 if (!loadCommonProperties())
5039dede 233 {
35f836fe 234 DbgPrintf(2, _T("Cannot load common properties for node object %d"), dwId);
5039dede
AK
235 return FALSE;
236 }
237
4d2c3a54 238 DB_STATEMENT hStmt = DBPrepare(g_hCoreDB,
4866d57b
VK
239 _T("SELECT primary_name,primary_ip,node_flags,")
240 _T("snmp_version,auth_method,secret,")
241 _T("agent_port,status_poll_type,snmp_oid,agent_version,")
242 _T("platform_name,poller_node_id,zone_guid,")
243 _T("proxy_node,snmp_proxy,required_polls,uname,")
244 _T("use_ifxtable,snmp_port,community,usm_auth_password,")
245 _T("usm_priv_password,usm_methods,snmp_sys_name,bridge_base_addr,")
71e4ed3a 246 _T("runtime_flags,down_since,boot_time,driver_name FROM nodes WHERE id=?"));
4866d57b
VK
247 if (hStmt == NULL)
248 return FALSE;
249
250 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, dwId);
92c51b1d 251 DB_RESULT hResult = DBSelectPrepared(hStmt);
e2babedf 252 if (hResult == NULL)
b1789b80
VK
253 {
254 DBFreeStatement(hStmt);
5039dede 255 return FALSE; // Query failed
b1789b80 256 }
5039dede
AK
257
258 if (DBGetNumRows(hResult) == 0)
259 {
260 DBFreeResult(hResult);
b1789b80 261 DBFreeStatement(hStmt);
5d2c5741 262 DbgPrintf(2, _T("Missing record in \"nodes\" table for node object %d"), dwId);
5039dede
AK
263 return FALSE;
264 }
265
5ad2167d
VK
266 DBGetField(hResult, 0, 0, m_primaryName, MAX_DNS_NAME);
267 m_dwIpAddr = DBGetFieldIPAddr(hResult, 0, 1);
268 m_dwFlags = DBGetFieldULong(hResult, 0, 2);
269 m_snmpVersion = DBGetFieldLong(hResult, 0, 3);
270 m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 4);
271 DBGetField(hResult, 0, 5, m_szSharedSecret, MAX_SECRET_LENGTH);
272 m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 6);
273 m_iStatusPollType = DBGetFieldLong(hResult, 0, 7);
274 DBGetField(hResult, 0, 8, m_szObjectId, MAX_OID_LEN * 4);
5d2c5741 275 DBGetField(hResult, 0, 9, m_szAgentVersion, MAX_AGENT_VERSION_LEN);
5d2c5741 276 DBGetField(hResult, 0, 10, m_szPlatformName, MAX_PLATFORM_NAME_LEN);
5d2c5741 277 m_dwPollerNode = DBGetFieldULong(hResult, 0, 11);
52c31148 278 m_zoneId = DBGetFieldULong(hResult, 0, 12);
5d2c5741
VK
279 m_dwProxyNode = DBGetFieldULong(hResult, 0, 13);
280 m_dwSNMPProxy = DBGetFieldULong(hResult, 0, 14);
281 m_iRequiredPollCount = DBGetFieldLong(hResult, 0, 15);
0ecc2200 282 m_sysDescription = DBGetField(hResult, 0, 16, NULL, 0);
5d2c5741 283 m_nUseIfXTable = (BYTE)DBGetFieldLong(hResult, 0, 17);
65e2005b 284 m_wSNMPPort = (WORD)DBGetFieldLong(hResult, 0, 18);
5039dede 285
5d2c5741 286 // SNMP authentication parameters
35f836fe
VK
287 char snmpAuthObject[256], snmpAuthPassword[256], snmpPrivPassword[256];
288 DBGetFieldA(hResult, 0, 19, snmpAuthObject, 256);
289 DBGetFieldA(hResult, 0, 20, snmpAuthPassword, 256);
290 DBGetFieldA(hResult, 0, 21, snmpPrivPassword, 256);
3408b115 291 int snmpMethods = DBGetFieldLong(hResult, 0, 22);
5d2c5741
VK
292 delete m_snmpSecurity;
293 m_snmpSecurity = new SNMP_SecurityContext(snmpAuthObject, snmpAuthPassword, snmpPrivPassword, snmpMethods & 0xFF, snmpMethods >> 8);
14b98b3a 294 m_snmpSecurity->setSecurityModel((m_snmpVersion == SNMP_VERSION_3) ? SNMP_SECURITY_MODEL_USM : SNMP_SECURITY_MODEL_V2C);
5d2c5741 295
88ac8e88 296 m_sysName = DBGetField(hResult, 0, 23, NULL, 0);
d74c80ea 297
3eab63f2
VK
298 TCHAR baseAddr[16];
299 TCHAR *value = DBGetField(hResult, 0, 24, baseAddr, 16);
300 if (value != NULL)
301 StrToBin(value, m_baseBridgeAddress, MAC_ADDR_LENGTH);
302
4866d57b 303 m_dwDynamicFlags = DBGetFieldULong(hResult, 0, 25);
b6ead716 304 m_dwDynamicFlags &= NDF_PERSISTENT; // Clear out all non-persistent runtime flags
4866d57b 305
8573e935 306 m_downSince = DBGetFieldLong(hResult, 0, 26);
71e4ed3a 307 m_bootTime = DBGetFieldLong(hResult, 0, 27);
dd42ad0a 308
28e1575f
VK
309 // Setup driver
310 TCHAR driverName[34];
71e4ed3a 311 DBGetField(hResult, 0, 28, driverName, 34);
28e1575f
VK
312 StrStrip(driverName);
313 if (driverName[0] != 0)
314 m_driver = FindDriverByName(driverName);
315
5039dede 316 DBFreeResult(hResult);
b1789b80 317 DBFreeStatement(hStmt);
5039dede 318
01152a54 319 if (!m_isDeleted)
5039dede
AK
320 {
321 // Link node to subnets
92c51b1d
VK
322 hStmt = DBPrepare(g_hCoreDB, _T("SELECT subnet_id FROM nsmap WHERE node_id=?"));
323 if (hStmt == NULL)
324 return FALSE;
325
326 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_dwId);
327 hResult = DBSelectPrepared(hStmt);
5039dede 328 if (hResult == NULL)
92c51b1d
VK
329 {
330 DBFreeStatement(hStmt);
5039dede 331 return FALSE; // Query failed
92c51b1d 332 }
5039dede
AK
333
334 iNumRows = DBGetNumRows(hResult);
5039dede
AK
335 for(i = 0; i < iNumRows; i++)
336 {
337 dwSubnetId = DBGetFieldULong(hResult, i, 0);
338 pObject = FindObjectById(dwSubnetId);
339 if (pObject == NULL)
340 {
341 nxlog_write(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
342 break;
343 }
344 else if (pObject->Type() != OBJECT_SUBNET)
345 {
346 nxlog_write(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
347 break;
348 }
349 else
350 {
351 pObject->AddChild(this);
352 AddParent(pObject);
5039dede
AK
353 }
354 }
355
356 DBFreeResult(hResult);
92c51b1d
VK
357 DBFreeStatement(hStmt);
358
359 loadItemsFromDB();
89135050 360 loadACLFromDB();
5039dede
AK
361
362 // Walk through all items in the node and load appropriate thresholds
a6c1f07f 363 bResult = TRUE;
16d6f798
VK
364 for(i = 0; i < m_dcObjects->size(); i++)
365 if (!m_dcObjects->get(i)->loadThresholdsFromDB())
5039dede 366 {
5d2c5741 367 DbgPrintf(3, _T("Cannot load thresholds for DCI %d of node %d (%s)"),
16d6f798 368 m_dcObjects->get(i)->getId(), dwId, m_szName);
5039dede
AK
369 bResult = FALSE;
370 }
371 }
372 else
373 {
374 bResult = TRUE;
375 }
376
377 return bResult;
378}
379
c50f77f7
VK
380/**
381 * Save object to database
382 */
5039dede
AK
383BOOL Node::SaveToDB(DB_HANDLE hdb)
384{
5039dede
AK
385 // Lock object's access
386 LockData();
387
28e1575f
VK
388 if (!saveCommonProperties(hdb))
389 {
390 UnlockData();
391 return FALSE;
392 }
5039dede 393
5039dede 394 // Form and execute INSERT or UPDATE query
4b7d8903 395 int snmpMethods = m_snmpSecurity->getAuthMethod() | (m_snmpSecurity->getPrivMethod() << 8);
28e1575f 396 DB_STATEMENT hStmt;
ba89fed2
VK
397 if (IsDatabaseRecordExist(hdb, _T("nodes"), _T("id"), m_dwId))
398 {
28e1575f
VK
399 hStmt = DBPrepare(hdb,
400 _T("UPDATE nodes SET primary_ip=?,primary_name=?,snmp_port=?,node_flags=?,snmp_version=?,community=?,")
401 _T("status_poll_type=?,agent_port=?,auth_method=?,secret=?,snmp_oid=?,uname=?,agent_version=?,")
402 _T("platform_name=?,poller_node_id=?,zone_guid=?,proxy_node=?,snmp_proxy=?,required_polls=?,")
403 _T("use_ifxtable=?,usm_auth_password=?,usm_priv_password=?,usm_methods=?,snmp_sys_name=?,bridge_base_addr=?,")
71e4ed3a 404 _T("runtime_flags=?,down_since=?,driver_name=?,rack_image=?,rack_position=?,rack_id=?,boot_time=? WHERE id=?"));
ba89fed2
VK
405 }
406 else
65e2005b 407 {
28e1575f
VK
408 hStmt = DBPrepare(hdb,
409 _T("INSERT INTO nodes (primary_ip,primary_name,snmp_port,node_flags,snmp_version,community,status_poll_type,")
410 _T("agent_port,auth_method,secret,snmp_oid,uname,agent_version,platform_name,poller_node_id,zone_guid,")
411 _T("proxy_node,snmp_proxy,required_polls,use_ifxtable,usm_auth_password,usm_priv_password,usm_methods,")
71e4ed3a
VK
412 _T("snmp_sys_name,bridge_base_addr,runtime_flags,down_since,driver_name,rack_image,rack_position,rack_id,boot_time,id) ")
413 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
65e2005b 414 }
28e1575f
VK
415 if (hStmt == NULL)
416 {
417 UnlockData();
418 return FALSE;
419 }
420
421 TCHAR ipAddr[16], baseAddress[16];
422
423 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, IpToStr(m_dwIpAddr, ipAddr), DB_BIND_STATIC);
424 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, m_primaryName, DB_BIND_STATIC);
425 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)m_wSNMPPort);
426 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_dwFlags);
427 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_snmpVersion);
428#ifdef UNICODE
429 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, WideStringFromMBString(m_snmpSecurity->getCommunity()), DB_BIND_DYNAMIC);
430#else
431 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, m_snmpSecurity->getCommunity(), DB_BIND_STATIC);
432#endif
433 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (LONG)m_iStatusPollType);
434 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (LONG)m_wAgentPort);
435 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (LONG)m_wAuthMethod);
436 DBBind(hStmt, 10, DB_SQLTYPE_VARCHAR, m_szSharedSecret, DB_BIND_STATIC);
437 DBBind(hStmt, 11, DB_SQLTYPE_VARCHAR, m_szObjectId, DB_BIND_STATIC);
438 DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, m_sysDescription, DB_BIND_STATIC);
439 DBBind(hStmt, 13, DB_SQLTYPE_VARCHAR, m_szAgentVersion, DB_BIND_STATIC);
440 DBBind(hStmt, 14, DB_SQLTYPE_VARCHAR, m_szPlatformName, DB_BIND_STATIC);
441 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, m_dwPollerNode);
442 DBBind(hStmt, 16, DB_SQLTYPE_INTEGER, m_zoneId);
443 DBBind(hStmt, 17, DB_SQLTYPE_INTEGER, m_dwProxyNode);
444 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, m_dwSNMPProxy);
445 DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, (LONG)m_iRequiredPollCount);
446 DBBind(hStmt, 20, DB_SQLTYPE_INTEGER, (LONG)m_nUseIfXTable);
447#ifdef UNICODE
448 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, WideStringFromMBString(m_snmpSecurity->getAuthPassword()), DB_BIND_DYNAMIC);
449 DBBind(hStmt, 22, DB_SQLTYPE_VARCHAR, WideStringFromMBString(m_snmpSecurity->getPrivPassword()), DB_BIND_DYNAMIC);
450#else
451 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, m_snmpSecurity->getAuthPassword(), DB_BIND_STATIC);
452 DBBind(hStmt, 22, DB_SQLTYPE_VARCHAR, m_snmpSecurity->getPrivPassword(), DB_BIND_STATIC);
453#endif
454 DBBind(hStmt, 23, DB_SQLTYPE_INTEGER, (LONG)snmpMethods);
455 DBBind(hStmt, 24, DB_SQLTYPE_VARCHAR, m_sysName, DB_BIND_STATIC);
456 DBBind(hStmt, 25, DB_SQLTYPE_VARCHAR, BinToStr(m_baseBridgeAddress, MAC_ADDR_LENGTH, baseAddress), DB_BIND_STATIC);
457 DBBind(hStmt, 26, DB_SQLTYPE_INTEGER, m_dwDynamicFlags);
8573e935 458 DBBind(hStmt, 27, DB_SQLTYPE_INTEGER, (LONG)m_downSince);
28e1575f 459 DBBind(hStmt, 28, DB_SQLTYPE_VARCHAR, (m_driver != NULL) ? m_driver->getName() : _T(""), DB_BIND_STATIC);
f1989a3a
VK
460 DBBind(hStmt, 29, DB_SQLTYPE_VARCHAR, _T("00000000-0000-0000-0000-000000000000"), DB_BIND_STATIC); // rack image
461 DBBind(hStmt, 30, DB_SQLTYPE_INTEGER, (LONG)0); // rack position
462 DBBind(hStmt, 31, DB_SQLTYPE_INTEGER, (LONG)0); // rack ID
71e4ed3a
VK
463 DBBind(hStmt, 32, DB_SQLTYPE_INTEGER, (LONG)m_bootTime); // rack ID
464 DBBind(hStmt, 33, DB_SQLTYPE_INTEGER, m_dwId);
28e1575f
VK
465
466 BOOL bResult = DBExecute(hStmt);
467 DBFreeStatement(hStmt);
5039dede 468
7c521895 469 // Save access list
89135050 470 saveACLToDB(hdb);
7c521895
VK
471
472 UnlockData();
473
5039dede
AK
474 // Save data collection items
475 if (bResult)
476 {
b06436f4 477 lockDciAccess(false);
16d6f798
VK
478 for(int i = 0; i < m_dcObjects->size(); i++)
479 m_dcObjects->get(i)->saveToDB(hdb);
7c521895 480 unlockDciAccess();
5039dede
AK
481 }
482
7c521895
VK
483 // Clear modifications flag
484 LockData();
01152a54 485 m_isModified = false;
7c521895 486 UnlockData();
5039dede 487
7c521895 488 return bResult;
5039dede
AK
489}
490
171c2fd6
VK
491/**
492 * Delete object from database
493 */
22ee6d97 494bool Node::deleteFromDB(DB_HANDLE hdb)
5039dede 495{
22ee6d97
VK
496 bool success = DataCollectionTarget::deleteFromDB(hdb);
497 if (success)
498 success = executeQueryOnObject(hdb, _T("DELETE FROM nodes WHERE id=?"));
499 if (success)
500 success = executeQueryOnObject(hdb, _T("DELETE FROM nsmap WHERE node_id=?"));
501 return success;
5039dede
AK
502}
503
80e0db05
VK
504/**
505 * Get ARP cache from node
506 */
7c521895 507ARP_CACHE *Node::getArpCache()
5039dede
AK
508{
509 ARP_CACHE *pArpCache = NULL;
510
511 if (m_dwFlags & NF_IS_LOCAL_MGMT)
512 {
513 pArpCache = GetLocalArpCache();
514 }
515 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
516 {
7c521895
VK
517 agentLock();
518 if (connectToAgent())
4687826e 519 pArpCache = m_pAgentConnection->getArpCache();
7c521895 520 agentUnlock();
5039dede
AK
521 }
522 else if (m_dwFlags & NF_IS_SNMP)
523 {
524 SNMP_Transport *pTransport;
525
cd9f247e 526 pTransport = createSnmpTransport();
803d47be
VK
527 if (pTransport != NULL)
528 {
529 pArpCache = SnmpGetArpCache(m_snmpVersion, pTransport);
530 delete pTransport;
531 }
5039dede
AK
532 }
533
534 return pArpCache;
535}
536
80e0db05
VK
537/**
538 * Get list of interfaces from node
539 */
98762401 540InterfaceList *Node::getInterfaceList()
5039dede 541{
98762401 542 InterfaceList *pIfList = NULL;
5039dede 543
b741f151 544 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)))
5039dede 545 {
7c521895
VK
546 agentLock();
547 if (connectToAgent())
5039dede 548 {
4687826e 549 pIfList = m_pAgentConnection->getInterfaceList();
5039dede 550 }
7c521895 551 agentUnlock();
5039dede 552 }
b741f151
VK
553 if ((pIfList == NULL) && (m_dwFlags & NF_IS_LOCAL_MGMT))
554 {
555 pIfList = GetLocalInterfaceList();
556 }
5039dede 557 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP) &&
9796ce45 558 (!(m_dwFlags & NF_DISABLE_SNMP)) && (m_driver != NULL))
5039dede
AK
559 {
560 SNMP_Transport *pTransport;
9796ce45 561 bool useIfXTable;
5039dede 562
cd9f247e 563 pTransport = createSnmpTransport();
803d47be 564 if (pTransport != NULL)
5039dede 565 {
803d47be
VK
566 if (m_nUseIfXTable == IFXTABLE_DEFAULT)
567 {
9796ce45 568 useIfXTable = (ConfigReadInt(_T("UseIfXTable"), 1) != 0) ? true : false;
803d47be
VK
569 }
570 else
571 {
9796ce45 572 useIfXTable = (m_nUseIfXTable == IFXTABLE_ENABLED) ? true : false;
803d47be 573 }
9796ce45
VK
574
575 int useAliases = ConfigReadInt(_T("UseInterfaceAliases"), 0);
ae32341d 576 pIfList = m_driver->getInterfaces(pTransport, &m_customAttributes, m_driverData, useAliases, useIfXTable);
eec253a8 577
8792fe27 578 if ((pIfList != NULL) && (m_dwFlags & NF_IS_BRIDGE))
eec253a8
VK
579 {
580 BridgeMapPorts(m_snmpVersion, pTransport, pIfList);
581 }
803d47be 582 delete pTransport;
5039dede 583 }
5039dede
AK
584 }
585
586 if (pIfList != NULL)
0d75ea88 587 {
024c3faf 588 checkInterfaceNames(pIfList);
0d75ea88
VK
589 addVrrpInterfaces(pIfList);
590 }
5039dede
AK
591
592 return pIfList;
593}
594
6fd6de0a
VK
595/**
596 * Add VRRP interfaces to interface list
597 */
98762401 598void Node::addVrrpInterfaces(InterfaceList *ifList)
0d75ea88
VK
599{
600 int i, j, k;
601 TCHAR buffer[32];
602
603 LockData();
604 if (m_vrrpInfo != NULL)
605 {
606 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): m_vrrpInfo->getSize()=%d"), m_szName, (int)m_dwId, m_vrrpInfo->getSize());
607
608 for(i = 0; i < m_vrrpInfo->getSize(); i++)
609 {
610 VrrpRouter *router = m_vrrpInfo->getRouter(i);
611 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): vrouter %d state=%d"), m_szName, (int)m_dwId, i, router->getState());
612 if (router->getState() != VRRP_STATE_MASTER)
613 continue; // Do not add interfaces if router is not in master state
614
615 // Get netmask for this VR
967893bb 616 UINT32 netmask = 0;
98762401
VK
617 for(j = 0; j < ifList->getSize(); j++)
618 if (ifList->get(j)->dwIndex == router->getIfIndex())
0d75ea88 619 {
98762401 620 netmask = ifList->get(j)->dwIpNetMask;
0d75ea88
VK
621 break;
622 }
623
624 // Walk through all VR virtual IPs
625 for(j = 0; j < router->getVipCount(); j++)
626 {
967893bb 627 UINT32 vip = router->getVip(j);
0d75ea88
VK
628 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): checking VIP %s@%d"), m_szName, (int)m_dwId, IpToStr(vip, buffer), i);
629 if (vip != 0)
630 {
98762401
VK
631 for(k = 0; k < ifList->getSize(); k++)
632 if (ifList->get(k)->dwIpAddr == vip)
0d75ea88 633 break;
98762401 634 if (k == ifList->getSize())
0d75ea88 635 {
60557d06
VK
636 NX_INTERFACE_INFO iface;
637 memset(&iface, 0, sizeof(NX_INTERFACE_INFO));
98762401
VK
638 _sntprintf(iface.szName, MAX_DB_STRING, _T("vrrp.%u.%u.%d"), router->getId(), router->getIfIndex(), j);
639 memcpy(iface.bMacAddr, router->getVirtualMacAddr(), MAC_ADDR_LENGTH);
640 iface.dwIpAddr = vip;
641 iface.dwIpNetMask = netmask;
642 ifList->add(&iface);
643 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): added interface %s"), m_szName, (int)m_dwId, iface.szName);
0d75ea88
VK
644 }
645 }
646 }
647 }
648 }
649 UnlockData();
650}
651
7946bd7c
VK
652/**
653 * Find interface by index and node IP
654 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
655 */
967893bb 656Interface *Node::findInterface(UINT32 dwIndex, UINT32 dwHostAddr)
5039dede 657{
967893bb 658 UINT32 i;
5039dede
AK
659 Interface *pInterface;
660
661 LockChildList(FALSE);
662 for(i = 0; i < m_dwChildCount; i++)
663 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
664 {
665 pInterface = (Interface *)m_pChildList[i];
664b42a4 666 if ((pInterface->getIfIndex() == dwIndex) || (dwIndex == INVALID_INDEX))
5039dede 667 {
eec253a8
VK
668 if (((pInterface->IpAddr() & pInterface->getIpNetMask()) ==
669 (dwHostAddr & pInterface->getIpNetMask())) ||
5039dede
AK
670 (dwHostAddr == INADDR_ANY))
671 {
672 UnlockChildList();
673 return pInterface;
674 }
675 }
676 }
677 UnlockChildList();
678 return NULL;
679}
680
7946bd7c
VK
681/**
682 * Find interface by name or description
683 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
684 */
630e15d6
VK
685Interface *Node::findInterface(const TCHAR *name)
686{
967893bb 687 UINT32 i;
630e15d6
VK
688 Interface *pInterface;
689
690 LockChildList(FALSE);
691 for(i = 0; i < m_dwChildCount; i++)
692 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
693 {
694 pInterface = (Interface *)m_pChildList[i];
478d4ff4 695 if (!_tcsicmp(pInterface->Name(), name) || !_tcsicmp(pInterface->getDescription(), name))
630e15d6
VK
696 {
697 UnlockChildList();
698 return pInterface;
699 }
700 }
701 UnlockChildList();
702 return NULL;
703}
704
7946bd7c
VK
705/**
706 * Find interface by slot/port pair
707 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
708 */
967893bb 709Interface *Node::findInterfaceBySlotAndPort(UINT32 slot, UINT32 port)
3f8c54e7 710{
967893bb 711 UINT32 i;
3f8c54e7
VK
712 Interface *pInterface;
713
3f8c54e7
VK
714 LockChildList(FALSE);
715 for(i = 0; i < m_dwChildCount; i++)
716 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
717 {
718 pInterface = (Interface *)m_pChildList[i];
4c16cdc7 719 if (pInterface->isPhysicalPort() && (pInterface->getSlotNumber() == slot) && (pInterface->getPortNumber() == port))
3f8c54e7
VK
720 {
721 UnlockChildList();
722 return pInterface;
723 }
724 }
725 UnlockChildList();
726 return NULL;
727}
728
7946bd7c
VK
729/**
730 * Find interface by MAC address
731 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
732 */
eec253a8
VK
733Interface *Node::findInterfaceByMAC(const BYTE *macAddr)
734{
967893bb 735 UINT32 i;
eec253a8
VK
736 Interface *pInterface;
737
738 LockChildList(FALSE);
739 for(i = 0; i < m_dwChildCount; i++)
740 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
741 {
742 pInterface = (Interface *)m_pChildList[i];
743 if (!memcmp(pInterface->getMacAddr(), macAddr, MAC_ADDR_LENGTH))
744 {
745 UnlockChildList();
746 return pInterface;
747 }
748 }
749 UnlockChildList();
750 return NULL;
751}
752
7946bd7c
VK
753/**
754 * Find interface by IP address
755 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
756 */
967893bb 757Interface *Node::findInterfaceByIP(UINT32 ipAddr)
eec253a8 758{
967893bb 759 UINT32 i;
eec253a8
VK
760 Interface *pInterface;
761
762 if (ipAddr == 0)
763 return NULL;
764
765 LockChildList(FALSE);
766 for(i = 0; i < m_dwChildCount; i++)
767 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
768 {
769 pInterface = (Interface *)m_pChildList[i];
770 if (pInterface->IpAddr() == ipAddr)
771 {
772 UnlockChildList();
773 return pInterface;
774 }
775 }
776 UnlockChildList();
777 return NULL;
778}
779
7946bd7c
VK
780/**
781 * Find interface by bridge port number
782 */
967893bb 783Interface *Node::findBridgePort(UINT32 bridgePortNumber)
eec253a8 784{
967893bb 785 UINT32 i;
eec253a8
VK
786 Interface *pInterface;
787
788 LockChildList(FALSE);
789 for(i = 0; i < m_dwChildCount; i++)
790 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
791 {
792 pInterface = (Interface *)m_pChildList[i];
793 if (pInterface->getBridgePortNumber() == bridgePortNumber)
794 {
795 UnlockChildList();
796 return pInterface;
797 }
798 }
799 UnlockChildList();
800 return NULL;
801}
802
7946bd7c
VK
803/**
804 * Find connection point for node
805 */
967893bb 806Interface *Node::findConnectionPoint(UINT32 *localIfId, BYTE *localMacAddr, bool *exactMatch)
f42b8099
VK
807{
808 Interface *cp = NULL;
809 LockChildList(FALSE);
967893bb 810 for(UINT32 i = 0; i < m_dwChildCount; i++)
f42b8099
VK
811 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
812 {
813 Interface *iface = (Interface *)m_pChildList[i];
46117060 814 cp = FindInterfaceConnectionPoint(iface->getMacAddr(), exactMatch);
f42b8099 815 if (cp != NULL)
06a93345
VK
816 {
817 *localIfId = iface->Id();
eec253a8 818 memcpy(localMacAddr, iface->getMacAddr(), MAC_ADDR_LENGTH);
f42b8099 819 break;
06a93345 820 }
f42b8099
VK
821 }
822 UnlockChildList();
823 return cp;
824}
825
a3050773
VK
826/**
827 * Check if given IP address is one of node's interfaces
828 */
967893bb 829BOOL Node::isMyIP(UINT32 dwIpAddr)
5039dede 830{
967893bb 831 UINT32 i;
5039dede
AK
832
833 LockChildList(FALSE);
834 for(i = 0; i < m_dwChildCount; i++)
835 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
836 {
837 if (((Interface *)m_pChildList[i])->IpAddr() == dwIpAddr)
838 {
839 UnlockChildList();
840 return TRUE;
841 }
842 }
843 UnlockChildList();
844 return FALSE;
845}
846
a3050773
VK
847/**
848 * Create new interface
849 */
967893bb 850Interface *Node::createNewInterface(UINT32 dwIpAddr, UINT32 dwNetMask, const TCHAR *name, const TCHAR *descr,
4d2c3a54 851 UINT32 dwIndex, UINT32 dwType, BYTE *pbMacAddr, UINT32 bridgePort,
01152a54 852 UINT32 slot, UINT32 port, bool physPort, bool manuallyCreated, bool system)
5039dede
AK
853{
854 Interface *pInterface;
855 Subnet *pSubnet = NULL;
856 Cluster *pCluster;
eec253a8 857 bool bAddToSubnet, bSyntheticMask = false;
5039dede 858
f7694811
VK
859 DbgPrintf(5, _T("Node::createNewInterface(%08X, %08X, %s, %d, %d, bp=%d, slot=%d, port=%d) called for node %s [%d]"),
860 dwIpAddr, dwNetMask, CHECK_NULL(name), dwIndex, dwType, bridgePort, slot, port, m_szName, m_dwId);
5039dede
AK
861
862 // Find subnet to place interface object to
314c4f38 863 if ((dwIpAddr != 0) && (dwType != IFTYPE_SOFTWARE_LOOPBACK) && ((dwIpAddr & 0xFF000000) != 0x7F000000))
5039dede 864 {
7c521895 865 pCluster = getMyCluster();
58b3e451 866 bAddToSubnet = (pCluster != NULL) ? !pCluster->isSyncAddr(dwIpAddr) : TRUE;
f7694811 867 DbgPrintf(5, _T("Node::createNewInterface: node=%s [%d] cluster=%s [%d] add=%d"),
5039dede
AK
868 m_szName, m_dwId, (pCluster != NULL) ? pCluster->Name() : _T("(null)"),
869 (pCluster != NULL) ? pCluster->Id() : 0, bAddToSubnet);
870 if (bAddToSubnet)
871 {
89135050 872 pSubnet = FindSubnetForNode(m_zoneId, dwIpAddr);
5039dede
AK
873 if (pSubnet == NULL)
874 {
875 // Check if netmask is 0 (detect), and if yes, create
876 // new subnet with class mask
877 if (dwNetMask == 0)
878 {
53edf4dd 879 bSyntheticMask = true;
5039dede
AK
880 if (dwIpAddr < 0xE0000000)
881 {
882 dwNetMask = 0xFFFFFF00; // Class A, B or C
883 }
884 else
885 {
886 TCHAR szBuffer[16];
887
888 // Multicast address??
4d2c3a54 889 DbgPrintf(2, _T("Attempt to create interface object with multicast address %s"),
5039dede
AK
890 IpToStr(dwIpAddr, szBuffer));
891 }
892 }
893
894 // Create new subnet object
6449475d 895 // Ignore mask 255.255.255.255 - some point-to-point interfaces can have such mask
674164eb
VK
896 // Ignore mask 255.255.255.254 - it's invalid
897 if ((dwIpAddr < 0xE0000000) && (dwNetMask != 0xFFFFFFFF) && (dwNetMask != 0xFFFFFFFE))
5039dede 898 {
4d2c3a54 899 pSubnet = createSubnet(dwIpAddr, dwNetMask, bSyntheticMask);
5039dede
AK
900 }
901 }
902 else
903 {
904 // Set correct netmask if we was asked for it
905 if (dwNetMask == 0)
906 {
eec253a8
VK
907 dwNetMask = pSubnet->getIpNetMask();
908 bSyntheticMask = pSubnet->isSyntheticMask();
5039dede
AK
909 }
910 }
911 }
912 }
913
914 // Create interface object
35f836fe 915 if (name != NULL)
4ecd55b3 916 pInterface = new Interface(name, (descr != NULL) ? descr : name, dwIndex, dwIpAddr, dwNetMask, dwType, m_zoneId);
5039dede 917 else
4ecd55b3 918 pInterface = new Interface(dwIpAddr, dwNetMask, m_zoneId, bSyntheticMask);
5039dede 919 if (pbMacAddr != NULL)
eec253a8
VK
920 pInterface->setMacAddr(pbMacAddr);
921 pInterface->setBridgePortNumber(bridgePort);
76f9abfd
VK
922 pInterface->setSlotNumber(slot);
923 pInterface->setPortNumber(port);
4c16cdc7 924 pInterface->setPhysicalPortFlag(physPort);
9214177b 925 pInterface->setManualCreationFlag(manuallyCreated);
01152a54 926 pInterface->setSystemFlag(system);
5039dede
AK
927
928 // Insert to objects' list and generate event
929 NetObjInsert(pInterface, TRUE);
eec253a8 930 addInterface(pInterface);
01152a54 931 if (!m_isHidden)
478d4ff4 932 pInterface->unhide();
01152a54
VK
933 if (!pInterface->isSystem())
934 PostEvent(EVENT_INTERFACE_ADDED, m_dwId, "dsaad", pInterface->Id(),
935 pInterface->Name(), pInterface->IpAddr(),
936 pInterface->getIpNetMask(), pInterface->getIfIndex());
5039dede
AK
937
938 // Bind node to appropriate subnet
939 if (pSubnet != NULL)
940 {
941 pSubnet->AddNode(this);
4d2c3a54 942
5039dede 943 // Check if subnet mask is correct on interface
eec253a8 944 if ((pSubnet->getIpNetMask() != pInterface->getIpNetMask()) && !pSubnet->isSyntheticMask())
5039dede
AK
945 {
946 PostEvent(EVENT_INCORRECT_NETMASK, m_dwId, "idsaa", pInterface->Id(),
eec253a8
VK
947 pInterface->getIfIndex(), pInterface->Name(),
948 pInterface->getIpNetMask(), pSubnet->getIpNetMask());
5039dede
AK
949 }
950 }
9214177b
VK
951
952 return pInterface;
5039dede
AK
953}
954
a3050773
VK
955/**
956 * Delete interface from node
957 */
eec253a8 958void Node::deleteInterface(Interface *pInterface)
5039dede 959{
967893bb 960 UINT32 i;
5039dede 961
dfb38baf
VK
962 DbgPrintf(5, _T("Node::deleteInterface(node=%s [%d], interface=%s [%d])"), m_szName, m_dwId, pInterface->Name(), pInterface->Id());
963
5039dede 964 // Check if we should unlink node from interface's subnet
314c4f38 965 if ((pInterface->IpAddr() != 0) && !pInterface->isExcludedFromTopology())
5039dede
AK
966 {
967 BOOL bUnlink = TRUE;
968
969 LockChildList(FALSE);
970 for(i = 0; i < m_dwChildCount; i++)
971 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
972 if (m_pChildList[i] != pInterface)
eec253a8
VK
973 if ((((Interface *)m_pChildList[i])->IpAddr() & ((Interface *)m_pChildList[i])->getIpNetMask()) ==
974 (pInterface->IpAddr() & pInterface->getIpNetMask()))
5039dede
AK
975 {
976 bUnlink = FALSE;
977 break;
978 }
979 UnlockChildList();
4d2c3a54 980
5039dede
AK
981 if (bUnlink)
982 {
983 // Last interface in subnet, should unlink node
89135050 984 Subnet *pSubnet = FindSubnetByIP(m_zoneId, pInterface->IpAddr() & pInterface->getIpNetMask());
5039dede
AK
985 if (pSubnet != NULL)
986 {
987 DeleteParent(pSubnet);
988 pSubnet->DeleteChild(this);
989 }
dfb38baf 990 DbgPrintf(5, _T("Node::deleteInterface(node=%s [%d], interface=%s [%d]): unlinked from subnet %s [%d]"),
2a1431bc 991 m_szName, m_dwId, pInterface->Name(), pInterface->Id(),
4d2c3a54 992 (pSubnet != NULL) ? pSubnet->Name() : _T("(null)"),
2a1431bc 993 (pSubnet != NULL) ? pSubnet->Id() : 0);
5039dede
AK
994 }
995 }
27de5dab 996 pInterface->deleteObject();
5039dede
AK
997}
998
7946bd7c
VK
999/**
1000 * Calculate node status based on child objects status
1001 */
27f9598d 1002void Node::calculateCompoundStatus(BOOL bForcedRecalc)
5039dede
AK
1003{
1004 int iOldStatus = m_iStatus;
967893bb 1005 static UINT32 dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_WARNING,
67c45b4d 1006 EVENT_NODE_MINOR, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
5039dede
AK
1007 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
1008
27f9598d 1009 NetObj::calculateCompoundStatus(bForcedRecalc);
5039dede
AK
1010 if (m_iStatus != iOldStatus)
1011 PostEvent(dwEventCodes[m_iStatus], m_dwId, "d", iOldStatus);
1012}
1013
a5ee7b3b
VK
1014/**
1015 * Perform status poll on node
1016 */
967893bb 1017void Node::statusPoll(ClientSession *pSession, UINT32 dwRqId, int nPoller)
5039dede 1018{
46117060
VK
1019 if (m_dwDynamicFlags & NDF_DELETE_IN_PROGRESS)
1020 {
1021 if (dwRqId == 0)
1022 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_STATUS_POLL;
1023 return;
1024 }
1025
967893bb 1026 UINT32 i, dwPollListSize, dwOldFlags = m_dwFlags;
5039dede
AK
1027 NetObj *pPollerNode = NULL, **ppPollList;
1028 BOOL bAllDown;
5039dede
AK
1029 SNMP_Transport *pTransport;
1030 Cluster *pCluster;
1031 time_t tNow, tExpire;
1032
c1482463 1033 Queue *pQueue = new Queue; // Delayed event queue
35f836fe 1034 SetPollerInfo(nPoller, _T("wait for lock"));
7c521895 1035 pollerLock();
c59466d2 1036 m_pollRequestor = pSession;
21c9acce 1037 sendPollerMsg(dwRqId, _T("Starting status poll for node %s\r\n"), m_szName);
35f836fe 1038 DbgPrintf(5, _T("Starting status poll for node %s (ID: %d)"), m_szName, m_dwId);
5039dede
AK
1039
1040 // Read capability expiration time and current time
1041 tExpire = (time_t)ConfigReadULong(_T("CapabilityExpirationTime"), 604800);
1042 tNow = time(NULL);
1043
1044 // Check SNMP agent connectivity
1045restart_agent_check:
15d6f8c9 1046 if ((m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)) && (m_dwIpAddr != 0))
5039dede
AK
1047 {
1048 TCHAR szBuffer[256];
967893bb 1049 UINT32 dwResult;
5039dede 1050
35f836fe 1051 DbgPrintf(6, _T("StatusPoll(%s): check SNMP"), m_szName);
cd9f247e 1052 pTransport = createSnmpTransport();
803d47be 1053 if (pTransport == NULL)
35f836fe 1054 DbgPrintf(6, _T("StatusPoll(%s): cannot create SNMP transport"), m_szName);
803d47be 1055
35f836fe 1056 SetPollerInfo(nPoller, _T("check SNMP"));
21c9acce 1057 sendPollerMsg(dwRqId, _T("Checking SNMP agent connectivity\r\n"));
d525c9ed 1058 dwResult = SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.1.2.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0);
5039dede
AK
1059 if ((dwResult == SNMP_ERR_SUCCESS) || (dwResult == SNMP_ERR_NO_OBJECT))
1060 {
1061 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
1062 {
1063 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1064 PostEventEx(pQueue, EVENT_SNMP_OK, m_dwId, NULL);
21c9acce 1065 sendPollerMsg(dwRqId, POLLER_INFO _T("Connectivity with SNMP agent restored\r\n"));
5039dede
AK
1066 }
1067 }
1068 else
1069 {
21c9acce 1070 sendPollerMsg(dwRqId, POLLER_ERROR _T("SNMP agent unreachable\r\n"));
5039dede
AK
1071 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
1072 {
8573e935 1073 if ((tNow > m_failTimeSNMP + tExpire) &&
5039dede
AK
1074 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
1075 {
1076 m_dwFlags &= ~NF_IS_SNMP;
1077 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1078 m_szObjectId[0] = 0;
21c9acce 1079 sendPollerMsg(dwRqId, POLLER_WARNING _T("Attribute isSNMP set to FALSE\r\n"));
5039dede
AK
1080 }
1081 }
1082 else
1083 {
1084 m_dwDynamicFlags |= NDF_SNMP_UNREACHABLE;
1085 PostEventEx(pQueue, EVENT_SNMP_FAIL, m_dwId, NULL);
8573e935 1086 m_failTimeSNMP = tNow;
5039dede
AK
1087 }
1088 }
1089 delete pTransport;
35f836fe 1090 DbgPrintf(6, _T("StatusPoll(%s): SNMP check finished"), m_szName);
5039dede
AK
1091 }
1092
1093 // Check native agent connectivity
15d6f8c9 1094 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)) && (m_dwIpAddr != 0))
5039dede 1095 {
35f836fe
VK
1096 DbgPrintf(6, _T("StatusPoll(%s): checking agent"), m_szName);
1097 SetPollerInfo(nPoller, _T("check agent"));
21c9acce 1098 sendPollerMsg(dwRqId, _T("Checking NetXMS agent connectivity\r\n"));
c3acd0f6 1099
967893bb 1100 UINT32 error, socketError;
a4569c4d
VK
1101 agentLock();
1102 if (connectToAgent(&error, &socketError))
5039dede 1103 {
35f836fe 1104 DbgPrintf(7, _T("StatusPoll(%s): connected to agent"), m_szName);
5039dede
AK
1105 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1106 {
1107 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1108 PostEventEx(pQueue, EVENT_AGENT_OK, m_dwId, NULL);
21c9acce 1109 sendPollerMsg(dwRqId, POLLER_INFO _T("Connectivity with NetXMS agent restored\r\n"));
5039dede 1110 }
5039dede
AK
1111 }
1112 else
1113 {
35f836fe 1114 DbgPrintf(6, _T("StatusPoll(%s): agent unreachable, error=%d, socketError=%d"), m_szName, (int)error, (int)socketError);
21c9acce 1115 sendPollerMsg(dwRqId, POLLER_ERROR _T("NetXMS agent unreachable\r\n"));
5039dede
AK
1116 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1117 {
71e4ed3a 1118 if ((tNow > m_failTimeAgent + tExpire) && !(m_dwDynamicFlags & NDF_UNREACHABLE))
5039dede
AK
1119 {
1120 m_dwFlags &= ~NF_IS_NATIVE_AGENT;
1121 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1122 m_szPlatformName[0] = 0;
1123 m_szAgentVersion[0] = 0;
21c9acce 1124 sendPollerMsg(dwRqId, POLLER_WARNING _T("Attribute isNetXMSAgent set to FALSE\r\n"));
5039dede
AK
1125 }
1126 }
1127 else
1128 {
1129 m_dwDynamicFlags |= NDF_AGENT_UNREACHABLE;
1130 PostEventEx(pQueue, EVENT_AGENT_FAIL, m_dwId, NULL);
8573e935 1131 m_failTimeAgent = tNow;
5039dede
AK
1132 }
1133 }
a4569c4d 1134 agentUnlock();
35f836fe 1135 DbgPrintf(7, _T("StatusPoll(%s): agent check finished"), m_szName);
5039dede
AK
1136 }
1137
35f836fe 1138 SetPollerInfo(nPoller, _T("prepare polling list"));
5039dede
AK
1139
1140 // Find service poller node object
1141 LockData();
1142 if (m_dwPollerNode != 0)
1143 {
967893bb 1144 UINT32 id = m_dwPollerNode;
f3218755
VK
1145 UnlockData();
1146 pPollerNode = FindObjectById(id);
5039dede
AK
1147 if (pPollerNode != NULL)
1148 {
1149 if (pPollerNode->Type() != OBJECT_NODE)
1150 pPollerNode = NULL;
1151 }
1152 }
f3218755
VK
1153 else
1154 {
1155 UnlockData();
1156 }
5039dede
AK
1157
1158 // If nothing found, use management server
1159 if (pPollerNode == NULL)
1160 {
1161 pPollerNode = FindObjectById(g_dwMgmtNode);
1162 if (pPollerNode != NULL)
21c9acce 1163 pPollerNode->incRefCount();
5039dede
AK
1164 }
1165 else
1166 {
21c9acce 1167 pPollerNode->incRefCount();
5039dede
AK
1168 }
1169
1170 // Create polling list
1171 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_dwChildCount);
1172 LockChildList(FALSE);
1173 for(i = 0, dwPollListSize = 0; i < m_dwChildCount; i++)
1174 if (m_pChildList[i]->Status() != STATUS_UNMANAGED)
1175 {
21c9acce 1176 m_pChildList[i]->incRefCount();
5039dede
AK
1177 ppPollList[dwPollListSize++] = m_pChildList[i];
1178 }
1179 UnlockChildList();
1180
1181 // Poll interfaces and services
35f836fe
VK
1182 SetPollerInfo(nPoller, _T("child poll"));
1183 DbgPrintf(7, _T("StatusPoll(%s): starting child object poll"), m_szName);
7c521895 1184 pCluster = getMyCluster();
cd9f247e 1185 pTransport = createSnmpTransport();
5039dede
AK
1186 for(i = 0; i < dwPollListSize; i++)
1187 {
1188 switch(ppPollList[i]->Type())
1189 {
1190 case OBJECT_INTERFACE:
35f836fe 1191 DbgPrintf(7, _T("StatusPoll(%s): polling interface %d [%s]"), m_szName, ppPollList[i]->Id(), ppPollList[i]->Name());
c59466d2 1192 ((Interface *)ppPollList[i])->statusPoll(pSession, dwRqId, pQueue,
58b3e451 1193 (pCluster != NULL) ? pCluster->isSyncAddr(((Interface *)ppPollList[i])->IpAddr()) : FALSE,
5039dede
AK
1194 pTransport);
1195 break;
1196 case OBJECT_NETWORKSERVICE:
35f836fe 1197 DbgPrintf(7, _T("StatusPoll(%s): polling network service %d [%s]"), m_szName, ppPollList[i]->Id(), ppPollList[i]->Name());
c59466d2 1198 ((NetworkService *)ppPollList[i])->statusPoll(pSession, dwRqId,
5039dede
AK
1199 (Node *)pPollerNode, pQueue);
1200 break;
1201 default:
1202 break;
1203 }
21c9acce 1204 ppPollList[i]->decRefCount();
5039dede
AK
1205 }
1206 delete pTransport;
1207 safe_free(ppPollList);
35f836fe 1208 DbgPrintf(7, _T("StatusPoll(%s): finished child object poll"), m_szName);
5039dede
AK
1209
1210 // Check if entire node is down
15d6f8c9
VK
1211 // This check is disabled for nodes without IP address
1212 if (m_dwIpAddr != 0)
5039dede 1213 {
15d6f8c9
VK
1214 LockChildList(FALSE);
1215 if (m_dwChildCount > 0)
1216 {
1217 for(i = 0, bAllDown = TRUE; i < m_dwChildCount; i++)
1218 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1219 (m_pChildList[i]->Status() != STATUS_CRITICAL) &&
1220 (m_pChildList[i]->Status() != STATUS_UNKNOWN) &&
1221 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
1222 (m_pChildList[i]->Status() != STATUS_DISABLED))
1223 {
1224 bAllDown = FALSE;
1225 break;
1226 }
1227 }
1228 else
1229 {
1230 bAllDown = FALSE;
1231 }
1232 UnlockChildList();
1233 if (bAllDown && (m_dwFlags & NF_IS_NATIVE_AGENT) &&
1234 (!(m_dwFlags & NF_DISABLE_NXCP)))
1235 if (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))
1236 bAllDown = FALSE;
1237 if (bAllDown && (m_dwFlags & NF_IS_SNMP) &&
1238 (!(m_dwFlags & NF_DISABLE_SNMP)))
1239 if (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))
1240 bAllDown = FALSE;
c1482463
VK
1241
1242 DbgPrintf(6, _T("StatusPoll(%s): bAllDown=%s, dynFlags=0x%08X"), m_szName, bAllDown ? _T("true") : _T("false"), m_dwDynamicFlags);
15d6f8c9
VK
1243 if (bAllDown)
1244 {
1245 if (!(m_dwDynamicFlags & NDF_UNREACHABLE))
1246 {
1247 m_dwDynamicFlags |= NDF_UNREACHABLE;
8573e935 1248 m_downSince = time(NULL);
7946bd7c 1249 SetPollerInfo(nPoller, _T("check network path"));
c1482463
VK
1250 if (checkNetworkPath(dwRqId))
1251 {
1252 m_dwDynamicFlags |= NDF_NETWORK_PATH_PROBLEM;
1253
1254 // Set interfaces and network services to UNKNOWN state
1255 LockChildList(FALSE);
1256 for(i = 0, bAllDown = TRUE; i < m_dwChildCount; i++)
1257 if (((m_pChildList[i]->Type() == OBJECT_INTERFACE) || (m_pChildList[i]->Type() == OBJECT_NETWORKSERVICE)) &&
1258 (m_pChildList[i]->Status() == STATUS_CRITICAL))
1259 {
1260 m_pChildList[i]->resetStatus();
1261 }
1262 UnlockChildList();
1263
1264 // Clear delayed event queue
1265 while(1)
1266 {
1267 Event *pEvent = (Event *)pQueue->Get();
1268 if (pEvent == NULL)
1269 break;
1270 delete pEvent;
1271 }
1272 delete_and_null(pQueue);
1273
1274 PostEvent(EVENT_NODE_UNREACHABLE, m_dwId, NULL);
1275 }
1276 else
1277 {
1278 PostEvent(EVENT_NODE_DOWN, m_dwId, NULL);
1279 }
21c9acce 1280 sendPollerMsg(dwRqId, POLLER_ERROR _T("Node is unreachable\r\n"));
15d6f8c9
VK
1281 }
1282 else
1283 {
21c9acce 1284 sendPollerMsg(dwRqId, POLLER_WARNING _T("Node is still unreachable\r\n"));
15d6f8c9
VK
1285 }
1286 }
1287 else
1288 {
8573e935 1289 m_downSince = 0;
15d6f8c9
VK
1290 if (m_dwDynamicFlags & NDF_UNREACHABLE)
1291 {
c1482463 1292 m_dwDynamicFlags &= ~(NDF_UNREACHABLE | NDF_SNMP_UNREACHABLE | NDF_AGENT_UNREACHABLE | NDF_NETWORK_PATH_PROBLEM);
15d6f8c9 1293 PostEvent(EVENT_NODE_UP, m_dwId, NULL);
21c9acce 1294 sendPollerMsg(dwRqId, POLLER_INFO _T("Node recovered from unreachable state\r\n"));
15d6f8c9
VK
1295 goto restart_agent_check;
1296 }
1297 else
1298 {
21c9acce 1299 sendPollerMsg(dwRqId, POLLER_INFO _T("Node is connected\r\n"));
15d6f8c9
VK
1300 }
1301 }
5039dede 1302 }
5039dede 1303
71e4ed3a
VK
1304 // Get uptime and update boot time
1305 if (!(m_dwDynamicFlags & NDF_UNREACHABLE))
1306 {
1307 TCHAR buffer[MAX_RESULT_LENGTH];
1308 if (getItemFromAgent(_T("System.Uptime"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1309 {
1310 m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0);
05c9a2f9 1311 DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from agent"), m_szName, m_dwId, (UINT32)m_bootTime);
71e4ed3a
VK
1312 }
1313 else if (getItemFromSNMP(m_wSNMPPort, _T(".1.3.6.1.2.1.1.3.0"), MAX_RESULT_LENGTH, buffer, SNMP_RAWTYPE_NONE) == DCE_SUCCESS)
1314 {
1315 m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0) / 100; // sysUpTime is in hundredths of a second
05c9a2f9 1316 DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from SNMP"), m_szName, m_dwId, (UINT32)m_bootTime);
71e4ed3a
VK
1317 }
1318 else
1319 {
1320 DbgPrintf(5, _T("StatusPoll(%s [%d]): unable to get system uptime"), m_szName, m_dwId);
1321 }
1322 }
1323 else
1324 {
1325 m_bootTime = 0;
1326 }
1327
5039dede 1328 // Send delayed events and destroy delayed event queue
c1482463
VK
1329 if (pQueue != NULL)
1330 {
1331 ResendEvents(pQueue);
1332 delete pQueue;
1333 }
a5ee7b3b
VK
1334
1335 // Call hooks in loaded modules
967893bb 1336 for(UINT32 i = 0; i < g_dwNumModules; i++)
a5ee7b3b
VK
1337 {
1338 if (g_pModuleList[i].pfStatusPollHook != NULL)
1339 {
1340 DbgPrintf(5, _T("StatusPoll(%s [%d]): calling hook in module %s"), m_szName, m_dwId, g_pModuleList[i].szName);
1341 g_pModuleList[i].pfStatusPollHook(this, pSession, dwRqId, nPoller);
1342 }
1343 }
4d2c3a54 1344
a5ee7b3b
VK
1345 // Execute hook script
1346 SetPollerInfo(nPoller, _T("hook"));
1347 executeHookScript(_T("StatusPoll"));
1348
35f836fe 1349 SetPollerInfo(nPoller, _T("cleanup"));
5039dede 1350 if (pPollerNode != NULL)
21c9acce 1351 pPollerNode->decRefCount();
5039dede
AK
1352
1353 if (dwOldFlags != m_dwFlags)
1354 {
1355 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
1356 LockData();
1357 Modify();
1358 UnlockData();
1359 }
1360
27f9598d 1361 calculateCompoundStatus();
8573e935 1362 m_lastStatusPoll = time(NULL);
21c9acce
VK
1363 sendPollerMsg(dwRqId, _T("Finished status poll for node %s\r\n"), m_szName);
1364 sendPollerMsg(dwRqId, _T("Node status after poll is %s\r\n"), g_szStatusText[m_iStatus]);
c59466d2 1365 m_pollRequestor = NULL;
5039dede
AK
1366 if (dwRqId == 0)
1367 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_STATUS_POLL;
7c521895 1368 pollerUnlock();
35f836fe 1369 DbgPrintf(5, _T("Finished status poll for node %s (ID: %d)"), m_szName, m_dwId);
5039dede
AK
1370}
1371
7946bd7c 1372/**
beae365a
VK
1373 * Check single elementof network path
1374 */
967893bb 1375bool Node::checkNetworkPathElement(UINT32 nodeId, const TCHAR *nodeType, bool isProxy, UINT32 dwRqId)
beae365a
VK
1376{
1377 Node *node = (Node *)FindObjectById(nodeId, OBJECT_NODE);
1378 if (node == NULL)
1379 return false;
1380
1381 DbgPrintf(6, _T("Node::checkNetworkPathElement(%s [%d]): found %s: %s [%d]"), m_szName, m_dwId, nodeType, node->Name(), node->Id());
1382 if (node->isDown())
1383 {
1384 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): %s %s [%d] is down"),
1385 m_szName, m_dwId, nodeType, node->Name(), node->Id());
1386 sendPollerMsg(dwRqId, POLLER_WARNING _T(" %s %s is down\r\n"), nodeType, node->Name());
1387 return true;
1388 }
66d15dff
VK
1389 if (isProxy && node->isNativeAgent() && (node->getRuntimeFlags() & NDF_AGENT_UNREACHABLE))
1390 {
1391 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): agent on %s %s [%d] is down"),
1392 m_szName, m_dwId, nodeType, node->Name(), node->Id());
1393 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Agent on %s %s is down\r\n"), nodeType, node->Name());
1394 return true;
1395 }
8573e935 1396 if (node->m_lastStatusPoll < time(NULL) - 1)
beae365a
VK
1397 {
1398 DbgPrintf(6, _T("Node::checkNetworkPathElement(%s [%d]): forced status poll on node %s [%d]"),
1399 m_szName, m_dwId, node->Name(), node->Id());
1400 node->statusPoll(NULL, 0, 0);
1401 if (node->isDown())
1402 {
1403 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): %s %s [%d] is down"),
1404 m_szName, m_dwId, nodeType, node->Name(), node->Id());
1405 sendPollerMsg(dwRqId, POLLER_WARNING _T(" %s %s is down\r\n"), nodeType, node->Name());
1406 return true;
1407 }
66d15dff
VK
1408 if (isProxy && node->isNativeAgent() && (node->getRuntimeFlags() & NDF_AGENT_UNREACHABLE))
1409 {
1410 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): agent on %s %s [%d] is down"),
1411 m_szName, m_dwId, nodeType, node->Name(), node->Id());
1412 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Agent on %s %s is down\r\n"), nodeType, node->Name());
1413 return true;
1414 }
beae365a
VK
1415 }
1416 return false;
1417}
1418
1419/**
7946bd7c 1420 * Check network path between node and management server to detect possible intermediate node failure
c1482463
VK
1421 *
1422 * @return true if network path problems found
7946bd7c 1423 */
967893bb 1424bool Node::checkNetworkPath(UINT32 dwRqId)
7946bd7c 1425{
67c45b4d
VK
1426 time_t now = time(NULL);
1427
beae365a
VK
1428 // Check proxy node(s)
1429 if (IsZoningEnabled() && (m_zoneId != 0))
1430 {
1431 Zone *zone = (Zone *)g_idxZoneByGUID.get(m_zoneId);
1432 if ((zone != NULL) && ((zone->getAgentProxy() != 0) || (zone->getSnmpProxy() != 0) || (zone->getIcmpProxy() != 0)))
1433 {
1434 bool allProxyDown = true;
1435 if (zone->getIcmpProxy() != 0)
66d15dff 1436 allProxyDown = checkNetworkPathElement(zone->getIcmpProxy(), _T("ICMP proxy"), true, dwRqId);
beae365a 1437 if (allProxyDown && (zone->getSnmpProxy() != 0) && (zone->getSnmpProxy() != zone->getIcmpProxy()))
66d15dff 1438 allProxyDown = checkNetworkPathElement(zone->getSnmpProxy(), _T("SNMP proxy"), true, dwRqId);
beae365a 1439 if (allProxyDown && (zone->getAgentProxy() != 0) && (zone->getAgentProxy() != zone->getIcmpProxy()) && (zone->getAgentProxy() != zone->getSnmpProxy()))
66d15dff 1440 allProxyDown = checkNetworkPathElement(zone->getAgentProxy(), _T("agent proxy"), true, dwRqId);
beae365a
VK
1441 if (allProxyDown)
1442 return true;
1443 }
1444 }
1445
67c45b4d
VK
1446 // Check directly connected switch
1447 sendPollerMsg(dwRqId, _T("Checking ethernet connectivity...\r\n"));
664b42a4
VK
1448 Interface *iface = findInterface(INVALID_INDEX, m_dwIpAddr);
1449 if ((iface != NULL) && (iface->getPeerNodeId() != 0))
67c45b4d 1450 {
664b42a4 1451 DbgPrintf(6, _T("Node::checkNetworkPath(%s [%d]): found interface object for primary IP: %s [%d]"), m_szName, m_dwId, iface->Name(), iface->Id());
66d15dff 1452 if (checkNetworkPathElement(iface->getPeerNodeId(), _T("upstream switch"), false, dwRqId))
beae365a 1453 return true;
67c45b4d 1454 }
664b42a4
VK
1455 else
1456 {
1457 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): cannot find interface object for primary IP"), m_szName, m_dwId);
1458 }
67c45b4d 1459
7946bd7c
VK
1460 Node *mgmtNode = (Node *)FindObjectById(g_dwMgmtNode);
1461 if (mgmtNode == NULL)
1462 {
1463 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): cannot find management node"), m_szName, m_dwId);
c1482463 1464 return false;
7946bd7c 1465 }
5039dede 1466
7946bd7c
VK
1467 NetworkPath *trace = TraceRoute(mgmtNode, this);
1468 if (trace == NULL)
1469 {
1470 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): trace not available"), m_szName, m_dwId);
c1482463 1471 return false;
7946bd7c
VK
1472 }
1473 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): trace available, %d hops, %s"),
1474 m_szName, m_dwId, trace->getHopCount(), trace->isComplete() ? _T("complete") : _T("incomplete"));
1475
1476 // We will do path check in two passes
1477 // If unreachable intermediate node will be found on first pass,
1478 // then method will just return true. Otherwise, we will do
1479 // second pass, this time forcing status poll on each node in the path.
21c9acce 1480 sendPollerMsg(dwRqId, _T("Checking network path...\r\n"));
7946bd7c
VK
1481 bool secondPass = false;
1482 bool pathProblemFound = false;
1483restart:
1484 for(int i = 0; i < trace->getHopCount(); i++)
1485 {
1486 HOP_INFO *hop = trace->getHopInfo(i);
1487 if ((hop->object == NULL) || (hop->object == this) || (hop->object->Type() != OBJECT_NODE))
1488 continue;
1489
1490 DbgPrintf(6, _T("Node::checkNetworkPath(%s [%d]): checking upstream node %s [%d]"),
1491 m_szName, m_dwId, hop->object->Name(), hop->object->Id());
8573e935 1492 if (secondPass && !((Node *)hop->object)->isDown() && (((Node *)hop->object)->m_lastStatusPoll < now - 1))
7946bd7c
VK
1493 {
1494 DbgPrintf(6, _T("Node::checkNetworkPath(%s [%d]): forced status poll on node %s [%d]"),
1495 m_szName, m_dwId, hop->object->Name(), hop->object->Id());
1496 ((Node *)hop->object)->statusPoll(NULL, 0, 0);
1497 }
1f385e47 1498
7946bd7c
VK
1499 if (((Node *)hop->object)->isDown())
1500 {
1501 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): upstream node %s [%d] is down"),
1502 m_szName, m_dwId, hop->object->Name(), hop->object->Id());
21c9acce 1503 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Upstream node %s is down\r\n"), hop->object->Name());
7946bd7c
VK
1504 pathProblemFound = true;
1505 break;
1506 }
1507 }
1508 if (!secondPass && !pathProblemFound)
1509 {
1510 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): will do second pass"), m_szName, m_dwId);
1511 secondPass = true;
1512 goto restart;
1513 }
1514 delete trace;
c1482463 1515 return pathProblemFound;
7946bd7c
VK
1516}
1517
1518/**
1519 * Check agent policy binding
1520 * Intended to be called only from configuration poller
1521 */
1f385e47
VK
1522void Node::checkAgentPolicyBinding(AgentConnection *conn)
1523{
1524 AgentPolicyInfo *ap;
967893bb 1525 UINT32 rcc = conn->getPolicyInventory(&ap);
1f385e47
VK
1526 if (rcc == ERR_SUCCESS)
1527 {
1528 // Check for unbound but installed policies
1529 for(int i = 0; i < ap->getSize(); i++)
1530 {
1531 uuid_t guid;
1532 ap->getGuid(i, guid);
1533 NetObj *object = FindObjectByGUID(guid, -1);
21c9acce 1534 if ((object != NULL) && (!object->isChild(m_dwId)))
1f385e47
VK
1535 {
1536 object->AddChild(this);
1537 AddParent(object);
1538 DbgPrintf(5, _T("ConfPoll(%s): bound to policy object %s [%d]"), m_szName, object->Name(), object->Id());
1539 }
1540 }
1541
1542 // Check for bound but not installed policies
1543 LockParentList(FALSE);
1544 NetObj **unbindList = (NetObj **)malloc(sizeof(NetObj *) * m_dwParentCount);
1545 int unbindListSize = 0;
967893bb 1546 for(UINT32 i = 0; i < m_dwParentCount; i++)
1f385e47
VK
1547 {
1548 if (IsAgentPolicyObject(m_pParentList[i]))
1549 {
1550 uuid_t guid1, guid2;
1551 int j;
1552
1553 m_pParentList[i]->getGuid(guid1);
1554 for(j = 0; j < ap->getSize(); j++)
1555 {
1556 ap->getGuid(j, guid2);
1557 if (!uuid_compare(guid1, guid2))
1558 break;
1559 }
1560 if (j == ap->getSize())
1561 unbindList[unbindListSize++] = m_pParentList[i];
1562 }
1563 }
1564 UnlockParentList();
1565
1566 for(int i = 0; i < unbindListSize; i++)
1567 {
1568 unbindList[i]->DeleteChild(this);
1569 DeleteParent(unbindList[i]);
1570 DbgPrintf(5, _T("ConfPoll(%s): unbound from policy object %s [%d]"), m_szName, unbindList[i]->Name(), unbindList[i]->Id());
1571 }
1572 safe_free(unbindList);
1573
1574 delete ap;
1575 }
1576 else
1577 {
1578 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getPolicyInventory() failed: rcc=%d"), m_szName, rcc);
1579 }
1580}
1581
a3050773
VK
1582/**
1583 * Update primary IP address from primary name
1584 */
5a7d6a10
VK
1585void Node::updatePrimaryIpAddr()
1586{
1587 if (m_primaryName[0] == 0)
1588 return;
1589
967893bb 1590 UINT32 ipAddr = ntohl(ResolveHostName(m_primaryName));
5a7d6a10
VK
1591 if ((ipAddr != m_dwIpAddr) && (ipAddr != INADDR_ANY) && (ipAddr != INADDR_NONE))
1592 {
1593 TCHAR buffer1[32], buffer2[32];
1594
4d2c3a54 1595 DbgPrintf(4, _T("IP address for node %s [%d] changed from %s to %s"),
5a7d6a10
VK
1596 m_szName, (int)m_dwId, IpToStr(m_dwIpAddr, buffer1), IpToStr(ipAddr, buffer2));
1597 PostEvent(EVENT_IP_ADDRESS_CHANGED, m_dwId, "aa", ipAddr, m_dwIpAddr);
2467ed57
VK
1598
1599
1600 setPrimaryIPAddress(ipAddr);
a3050773
VK
1601
1602 agentLock();
1603 delete_and_null(m_pAgentConnection);
1604 agentUnlock();
5a7d6a10
VK
1605 }
1606}
1607
76720a09
VK
1608/**
1609 * Perform configuration poll on node
1610 */
967893bb 1611void Node::configurationPoll(ClientSession *pSession, UINT32 dwRqId, int nPoller, UINT32 dwNetMask)
5039dede 1612{
46117060
VK
1613 if (m_dwDynamicFlags & NDF_DELETE_IN_PROGRESS)
1614 {
1615 if (dwRqId == 0)
1616 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1617 return;
1618 }
1619
967893bb 1620 UINT32 dwOldFlags = m_dwFlags;
35f836fe 1621 TCHAR szBuffer[4096];
5039dede 1622 SNMP_Transport *pTransport;
76720a09 1623 bool hasChanges = false;
5039dede 1624
35f836fe 1625 SetPollerInfo(nPoller, _T("wait for lock"));
7c521895 1626 pollerLock();
c59466d2 1627 m_pollRequestor = pSession;
21c9acce 1628 sendPollerMsg(dwRqId, _T("Starting configuration poll for node %s\r\n"), m_szName);
35f836fe 1629 DbgPrintf(4, _T("Starting configuration poll for node %s (ID: %d)"), m_szName, m_dwId);
5039dede
AK
1630
1631 // Check for forced capabilities recheck
1632 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
1633 {
1634 m_dwFlags &= ~(NF_IS_NATIVE_AGENT | NF_IS_SNMP | NF_IS_CPSNMP |
0ecc2200 1635 NF_IS_BRIDGE | NF_IS_ROUTER | NF_IS_OSPF | NF_IS_PRINTER |
76720a09 1636 NF_IS_CDP | NF_IS_LLDP | NF_IS_SONMP | NF_IS_VRRP | NF_HAS_VLANS |
46ee6286
VK
1637 NF_IS_8021X | NF_IS_STP | NF_HAS_ENTITY_MIB | NF_HAS_IFXTABLE |
1638 NF_HAS_WINPDH);
e4a64da2 1639 m_dwDynamicFlags &= ~NDF_CONFIGURATION_POLL_PASSED;
5039dede
AK
1640 m_szObjectId[0] = 0;
1641 m_szPlatformName[0] = 0;
1642 m_szAgentVersion[0] = 0;
0ecc2200
VK
1643 safe_free_and_null(m_sysDescription);
1644 safe_free_and_null(m_sysName);
1645 safe_free_and_null(m_lldpNodeId);
5039dede
AK
1646 }
1647
1648 // Check if node is marked as unreachable
1649 if ((m_dwDynamicFlags & NDF_UNREACHABLE) && !(m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES))
1650 {
21c9acce 1651 sendPollerMsg(dwRqId, POLLER_WARNING _T("Node is marked as unreachable, configuration poll aborted\r\n"));
35f836fe 1652 DbgPrintf(4, _T("Node is marked as unreachable, configuration poll aborted"));
8573e935 1653 m_lastConfigurationPoll = time(NULL);
5039dede
AK
1654 }
1655 else
1656 {
5a7d6a10
VK
1657 updatePrimaryIpAddr();
1658
35f836fe 1659 SetPollerInfo(nPoller, _T("capability check"));
21c9acce 1660 sendPollerMsg(dwRqId, _T("Checking node's capabilities...\r\n"));
5039dede 1661
99058170
VK
1662 if (confPollAgent(dwRqId))
1663 hasChanges = true;
1664 if (confPollSnmp(dwRqId))
1665 hasChanges = true;
5039dede
AK
1666
1667 // Check for CheckPoint SNMP agent on port 260
35f836fe 1668 DbgPrintf(5, _T("ConfPoll(%s): checking for CheckPoint SNMP on port 260"), m_szName);
15d6f8c9 1669 if (!((m_dwFlags & NF_IS_CPSNMP) && (m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE)) && (m_dwIpAddr != 0))
5039dede
AK
1670 {
1671 pTransport = new SNMP_UDPTransport;
c4366266 1672 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
5d2c5741 1673 if (SnmpGet(SNMP_VERSION_1, pTransport,
d525c9ed 1674 _T(".1.3.6.1.4.1.2620.1.1.10.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
5039dede
AK
1675 {
1676 LockData();
1677 m_dwFlags |= NF_IS_CPSNMP | NF_IS_ROUTER;
1678 m_dwDynamicFlags &= ~NDF_CPSNMP_UNREACHABLE;
1679 UnlockData();
21c9acce 1680 sendPollerMsg(dwRqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 260 is active\r\n"));
5039dede
AK
1681 }
1682 delete pTransport;
1683 }
1684
1685 // Generate event if node flags has been changed
1686 if (dwOldFlags != m_dwFlags)
1687 {
1688 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
76720a09 1689 hasChanges = true;
5039dede
AK
1690 }
1691
5039dede 1692 // Retrieve interface list
35f836fe 1693 SetPollerInfo(nPoller, _T("interface check"));
21c9acce 1694 sendPollerMsg(dwRqId, _T("Capability check finished\r\n"));
5039dede 1695
eec253a8 1696 if (updateInterfaceConfiguration(dwRqId, dwNetMask))
76720a09 1697 hasChanges = true;
5039dede 1698
8573e935 1699 m_lastConfigurationPoll = time(NULL);
5039dede
AK
1700
1701 // Check node name
21c9acce 1702 sendPollerMsg(dwRqId, _T("Checking node name\r\n"));
967893bb 1703 UINT32 dwAddr = ntohl(_t_inet_addr(m_szName));
5039dede 1704 if ((g_dwFlags & AF_RESOLVE_NODE_NAMES) &&
4d2c3a54 1705 (dwAddr != INADDR_NONE) &&
5039dede 1706 (dwAddr != INADDR_ANY) &&
58b3e451 1707 isMyIP(dwAddr))
5039dede 1708 {
21c9acce 1709 sendPollerMsg(dwRqId, _T("Node name is an IP address and need to be resolved\r\n"));
35f836fe 1710 SetPollerInfo(nPoller, _T("resolving name"));
024c3faf 1711 if (resolveName(FALSE))
5039dede 1712 {
21c9acce 1713 sendPollerMsg(dwRqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_szName);
76720a09 1714 hasChanges = true;
5039dede
AK
1715 }
1716 else
1717 {
21c9acce 1718 sendPollerMsg(dwRqId, POLLER_WARNING _T("Node name cannot be resolved\r\n"));
5039dede
AK
1719 }
1720 }
1721 else
1722 {
1723 if (g_dwFlags & AF_SYNC_NODE_NAMES_WITH_DNS)
1724 {
21c9acce 1725 sendPollerMsg(dwRqId, _T("Syncing node name with DNS\r\n"));
35f836fe 1726 SetPollerInfo(nPoller, _T("resolving name"));
024c3faf 1727 if (resolveName(TRUE))
5039dede 1728 {
21c9acce 1729 sendPollerMsg(dwRqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_szName);
76720a09 1730 hasChanges = true;
5039dede
AK
1731 }
1732 }
1733 else
1734 {
21c9acce 1735 sendPollerMsg(dwRqId, _T("Node name is OK\r\n"));
5039dede
AK
1736 }
1737 }
1738
6fd6de0a 1739 applyUserTemplates();
7c521895 1740 updateContainerMembership();
d51f2182 1741 doInstanceDiscovery();
4d0c32f3 1742
caa04e26
VK
1743 // Get list of installed products
1744 if (m_dwFlags & NF_IS_NATIVE_AGENT)
1745 {
1746 SetPollerInfo(nPoller, _T("software check"));
1747 sendPollerMsg(dwRqId, _T("Reading list of installed software packages\r\n"));
1748
1749 Table *table;
1750 if (getTableFromAgent(_T("System.InstalledProducts"), &table) == DCE_SUCCESS)
1751 {
1752 LockData();
1753 delete m_softwarePackages;
1754 m_softwarePackages = new ObjectArray<SoftwarePackage>(table->getNumRows(), 16, true);
1755 for(int i = 0; i < table->getNumRows(); i++)
1756 m_softwarePackages->add(new SoftwarePackage(table, i));
1757 UnlockData();
1758 delete table;
1759 sendPollerMsg(dwRqId, POLLER_INFO _T("Got information about %d installed software packages\r\n"), m_softwarePackages->size());
1760 }
1761 else
1762 {
1763 delete_and_null(m_softwarePackages);
1764 sendPollerMsg(dwRqId, POLLER_WARNING _T("Unable to get information about installed software packages\r\n"));
1765 }
1766 }
1767
21c9acce
VK
1768 sendPollerMsg(dwRqId, _T("Finished configuration poll for node %s\r\n"), m_szName);
1769 sendPollerMsg(dwRqId, _T("Node configuration was%schanged after poll\r\n"), hasChanges ? _T(" ") : _T(" not "));
e4a64da2 1770
a3050773 1771 // Call hooks in loaded modules
967893bb 1772 for(UINT32 i = 0; i < g_dwNumModules; i++)
a5ee7b3b 1773 {
a3050773
VK
1774 if (g_pModuleList[i].pfConfPollHook != NULL)
1775 {
1776 DbgPrintf(5, _T("ConfigurationPoll(%s [%d]): calling hook in module %s"), m_szName, m_dwId, g_pModuleList[i].szName);
1777 g_pModuleList[i].pfConfPollHook(this, pSession, dwRqId, nPoller);
1778 }
a5ee7b3b 1779 }
a5ee7b3b 1780
a3050773
VK
1781 // Execute hook script
1782 SetPollerInfo(nPoller, _T("hook"));
1783 executeHookScript(_T("ConfigurationPoll"));
1784
1785 m_dwDynamicFlags |= NDF_CONFIGURATION_POLL_PASSED;
1786 }
1824629a 1787
4d0c32f3 1788 // Finish configuration poll
35f836fe 1789 SetPollerInfo(nPoller, _T("cleanup"));
4d0c32f3
VK
1790 if (dwRqId == 0)
1791 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1792 m_dwDynamicFlags &= ~NDF_RECHECK_CAPABILITIES;
7c521895 1793 pollerUnlock();
35f836fe 1794 DbgPrintf(4, _T("Finished configuration poll for node %s (ID: %d)"), m_szName, m_dwId);
4d0c32f3 1795
76720a09 1796 if (hasChanges)
4d0c32f3
VK
1797 {
1798 LockData();
1799 Modify();
1800 UnlockData();
1801 }
1802}
1803
76720a09
VK
1804/**
1805 * Configuration poll: check for NetXMS agent
1806 */
967893bb 1807bool Node::confPollAgent(UINT32 dwRqId)
76720a09
VK
1808{
1809 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent Flags={%08X} DynamicFlags={%08X}"), m_szName, m_dwFlags, m_dwDynamicFlags);
1810 if (((m_dwFlags & NF_IS_NATIVE_AGENT) && (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)) ||
1811 (m_dwIpAddr == 0) || (m_dwFlags & NF_DISABLE_NXCP))
1812 return false;
1813
1814 bool hasChanges = false;
1815
21c9acce 1816 sendPollerMsg(dwRqId, _T(" Checking NetXMS agent...\r\n"));
af21affe 1817 AgentConnection *pAgentConn = new AgentConnectionEx(m_dwId, htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
76720a09
VK
1818 setAgentProxy(pAgentConn);
1819 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - connecting"), m_szName);
af21affe
VK
1820
1821 // Try to connect to agent
1822 UINT32 rcc;
1823 if (!pAgentConn->connect(g_pServerKey, FALSE, &rcc))
1824 {
1825 // If there are authentication problem, try default shared secret
1826 if ((rcc == ERR_AUTH_REQUIRED) || (rcc == ERR_AUTH_FAILED))
1827 {
1828 TCHAR secret[MAX_SECRET_LENGTH];
1829 ConfigReadStr(_T("AgentDefaultSharedSecret"), secret, MAX_SECRET_LENGTH, _T("netxms"));
1830 pAgentConn->setAuthData(AUTH_SHA1_HASH, secret);
1831 if (pAgentConn->connect(g_pServerKey, FALSE, &rcc))
1832 {
1833 m_wAuthMethod = AUTH_SHA1_HASH;
1834 nx_strncpy(m_szSharedSecret, secret, MAX_SECRET_LENGTH);
1835 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - shared secret changed to system default"), m_szName);
1836 }
1837 }
1838 }
1839
1840 if (rcc == ERR_SUCCESS)
76720a09
VK
1841 {
1842 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - connected"), m_szName);
1843 LockData();
1844 m_dwFlags |= NF_IS_NATIVE_AGENT;
1845 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1846 {
1847 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1848 PostEvent(EVENT_AGENT_OK, m_dwId, NULL);
21c9acce 1849 sendPollerMsg(dwRqId, POLLER_INFO _T(" Connectivity with NetXMS agent restored\r\n"));
76720a09
VK
1850 }
1851 else
1852 {
21c9acce 1853 sendPollerMsg(dwRqId, POLLER_INFO _T(" NetXMS native agent is active\r\n"));
76720a09
VK
1854 }
1855 UnlockData();
4d0c32f3 1856
76720a09
VK
1857 TCHAR buffer[MAX_RESULT_LENGTH];
1858 if (pAgentConn->getParameter(_T("Agent.Version"), MAX_AGENT_VERSION_LEN, buffer) == ERR_SUCCESS)
1859 {
1860 LockData();
1861 if (_tcscmp(m_szAgentVersion, buffer))
1862 {
1863 _tcscpy(m_szAgentVersion, buffer);
1864 hasChanges = true;
21c9acce 1865 sendPollerMsg(dwRqId, _T(" NetXMS agent version changed to %s\r\n"), m_szAgentVersion);
76720a09
VK
1866 }
1867 UnlockData();
1868 }
1869
1870 if (pAgentConn->getParameter(_T("System.PlatformName"), MAX_PLATFORM_NAME_LEN, buffer) == ERR_SUCCESS)
1871 {
1872 LockData();
1873 if (_tcscmp(m_szPlatformName, buffer))
1874 {
1875 _tcscpy(m_szPlatformName, buffer);
1876 hasChanges = true;
21c9acce 1877 sendPollerMsg(dwRqId, _T(" Platform name changed to %s\r\n"), m_szPlatformName);
76720a09
VK
1878 }
1879 UnlockData();
1880 }
1881
1882 // Check IP forwarding status
1883 if (pAgentConn->getParameter(_T("Net.IP.Forwarding"), 16, buffer) == ERR_SUCCESS)
1884 {
1885 if (_tcstoul(buffer, NULL, 10) != 0)
1886 m_dwFlags |= NF_IS_ROUTER;
1887 else
1888 m_dwFlags &= ~NF_IS_ROUTER;
1889 }
1890
1891 // Get uname
1892 if (pAgentConn->getParameter(_T("System.Uname"), MAX_DB_STRING, buffer) == ERR_SUCCESS)
1893 {
1894 TranslateStr(buffer, _T("\r\n"), _T(" "));
1895 TranslateStr(buffer, _T("\n"), _T(" "));
1896 TranslateStr(buffer, _T("\r"), _T(" "));
1897 LockData();
1898 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, buffer))
1899 {
1900 safe_free(m_sysDescription);
1901 m_sysDescription = _tcsdup(buffer);
1902 hasChanges = true;
21c9acce 1903 sendPollerMsg(dwRqId, _T(" System description changed to %s\r\n"), m_sysDescription);
76720a09
VK
1904 }
1905 UnlockData();
1906 }
1907
86c126f5
VK
1908 ObjectArray<AgentParameterDefinition> *plist;
1909 ObjectArray<AgentTableDefinition> *tlist;
967893bb 1910 UINT32 rcc = pAgentConn->getSupportedParameters(&plist, &tlist);
76720a09
VK
1911 if (rcc == ERR_SUCCESS)
1912 {
1913 LockData();
1914 delete m_paramList;
1915 delete m_tableList;
1916 m_paramList = plist;
1917 m_tableList = tlist;
084fb4c1
VK
1918
1919 // Check for 64-bit interface counters
1920 m_dwFlags &= ~NF_HAS_AGENT_IFXCOUNTERS;
1921 for(int i = 0; i < plist->size(); i++)
1922 {
86c126f5 1923 if (!_tcsicmp(plist->get(i)->getName(), _T("Net.Interface.BytesIn64(*)")))
084fb4c1
VK
1924 {
1925 m_dwFlags |= NF_HAS_AGENT_IFXCOUNTERS;
1926 }
1927 }
1928
76720a09
VK
1929 UnlockData();
1930 }
1931 else
1932 {
1933 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getSupportedParameters() failed: rcc=%d"), m_szName, rcc);
1934 }
1935
46ee6286
VK
1936 // Get supported Windows Performance Counters
1937 if (!_tcsncmp(m_szPlatformName, _T("windows-"), 8))
1938 {
1939 sendPollerMsg(dwRqId, _T(" Reading list of available Windows Performance Counters...\r\n"));
1940 ObjectArray<WinPerfObject> *perfObjects = WinPerfObject::getWinPerfObjectsFromNode(this, pAgentConn);
1941 LockData();
1942 delete m_winPerfObjects;
1943 m_winPerfObjects = perfObjects;
1944 if (m_winPerfObjects != NULL)
1945 {
1946 sendPollerMsg(dwRqId, POLLER_INFO _T(" %d counters read\r\n"), m_winPerfObjects->size());
1947 if (!(m_dwFlags & NF_HAS_WINPDH))
1948 {
1949 m_dwFlags |= NF_HAS_WINPDH;
1950 hasChanges = true;
1951 }
1952 }
1953 else
1954 {
1955 sendPollerMsg(dwRqId, POLLER_ERROR _T(" unable to get Windows Performance Counters list\r\n"));
1956 if (m_dwFlags & NF_HAS_WINPDH)
1957 {
1958 m_dwFlags &= ~NF_HAS_WINPDH;
1959 hasChanges = true;
1960 }
1961 }
1962 UnlockData();
1963 }
1964
76720a09
VK
1965 checkAgentPolicyBinding(pAgentConn);
1966
1967 pAgentConn->disconnect();
1968 }
1969 else
1970 {
af21affe 1971 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - failed to connect (error %d)"), m_szName, rcc);
76720a09
VK
1972 }
1973 delete pAgentConn;
1974 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - finished"), m_szName);
1975 return hasChanges;
1976}
1977
1978/**
1979 * SNMP walker callback which just counts number of varbinds
1980 */
967893bb 1981static UINT32 CountingSnmpWalkerCallback(UINT32 version, SNMP_Variable *var, SNMP_Transport *transport, void *arg)
76720a09
VK
1982{
1983 (*((int *)arg))++;
1984 return SNMP_ERR_SUCCESS;
1985}
1986
1987/**
1988 * Configuration poll: check for SNMP
1989 */
967893bb 1990bool Node::confPollSnmp(UINT32 dwRqId)
76720a09
VK
1991{
1992 if (((m_dwFlags & NF_IS_SNMP) && (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)) ||
1993 (m_dwIpAddr == 0) || (m_dwFlags & NF_DISABLE_SNMP))
1994 return false;
1995
1996 bool hasChanges = false;
1997
21c9acce 1998 sendPollerMsg(dwRqId, _T(" Checking SNMP...\r\n"));
76720a09
VK
1999 DbgPrintf(5, _T("ConfPoll(%s): calling SnmpCheckCommSettings()"), m_szName);
2000 SNMP_Transport *pTransport = createSnmpTransport();
2001 if (pTransport == NULL)
2002 {
2003 DbgPrintf(5, _T("ConfPoll(%s): unable to create SNMP transport"), m_szName);
2004 return false;
2005 }
2006
1f4c37ee
VK
2007 StringList oids;
2008 const TCHAR *customOid = m_customAttributes.get(_T("snmp.testoid"));
2009 if (customOid != NULL)
2010 oids.add(customOid);
2011 oids.add(_T(".1.3.6.1.2.1.1.2.0"));
2012 oids.add(_T(".1.3.6.1.2.1.1.1.0"));
2013 AddDriverSpecificOids(&oids);
2014 SNMP_SecurityContext *newCtx = SnmpCheckCommSettings(pTransport, &m_snmpVersion, m_snmpSecurity, &oids);
76720a09
VK
2015 if (newCtx != NULL)
2016 {
2017 LockData();
2018 delete m_snmpSecurity;
2019 m_snmpSecurity = newCtx;
2020 m_dwFlags |= NF_IS_SNMP;
2021 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
2022 {
2023 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
2024 PostEvent(EVENT_SNMP_OK, m_dwId, NULL);
21c9acce 2025 sendPollerMsg(dwRqId, POLLER_INFO _T(" Connectivity with SNMP agent restored\r\n"));
76720a09
VK
2026 }
2027 UnlockData();
21c9acce 2028 sendPollerMsg(dwRqId, _T(" SNMP agent is active (version %s)\r\n"),
76720a09
VK
2029 (m_snmpVersion == SNMP_VERSION_3) ? _T("3") : ((m_snmpVersion == SNMP_VERSION_2C) ? _T("2c") : _T("1")));
2030
2031 TCHAR szBuffer[4096];
d525c9ed 2032 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.1.2.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_STRING_RESULT) != SNMP_ERR_SUCCESS)
76720a09 2033 {
3b2d5932
VK
2034 // Set snmp object ID to .0.0 if it cannot be read
2035 _tcscpy(szBuffer, _T(".0.0"));
76720a09 2036 }
3b2d5932
VK
2037 LockData();
2038 if (_tcscmp(m_szObjectId, szBuffer))
2039 {
2040 nx_strncpy(m_szObjectId, szBuffer, MAX_OID_LEN * 4);
2041 hasChanges = true;
2042 }
2043 UnlockData();
76720a09
VK
2044
2045 // Get system description
d525c9ed 2046 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.1.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
76720a09
VK
2047 {
2048 TranslateStr(szBuffer, _T("\r\n"), _T(" "));
2049 TranslateStr(szBuffer, _T("\n"), _T(" "));
2050 TranslateStr(szBuffer, _T("\r"), _T(" "));
2051 LockData();
2052 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, szBuffer))
2053 {
2054 safe_free(m_sysDescription);
2055 m_sysDescription = _tcsdup(szBuffer);
2056 hasChanges = true;
21c9acce 2057 sendPollerMsg(dwRqId, _T(" System description changed to %s\r\n"), m_sysDescription);
76720a09
VK
2058 }
2059 UnlockData();
2060 }
2061
2062 // Select device driver
2063 NetworkDeviceDriver *driver = FindDriverForNode(this, pTransport);
2064 DbgPrintf(5, _T("ConfPoll(%s): selected device driver %s"), m_szName, driver->getName());
2065 LockData();
2066 if (driver != m_driver)
2067 {
2068 m_driver = driver;
21c9acce 2069 sendPollerMsg(dwRqId, _T(" New network device driver selected: %s\r\n"), m_driver->getName());
76720a09
VK
2070 }
2071 UnlockData();
2072
2073 // Allow driver to gather additional info
ae32341d 2074 m_driver->analyzeDevice(pTransport, m_szObjectId, &m_customAttributes, &m_driverData);
76720a09
VK
2075
2076 // Get sysName
2077 if (SnmpGet(m_snmpVersion, pTransport,
d525c9ed 2078 _T(".1.3.6.1.2.1.1.5.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
76720a09
VK
2079 {
2080 LockData();
2081 if ((m_sysName == NULL) || _tcscmp(m_sysName, szBuffer))
2082 {
2083 safe_free(m_sysName);
2084 m_sysName = _tcsdup(szBuffer);
2085 hasChanges = true;
21c9acce 2086 sendPollerMsg(dwRqId, _T(" System name changed to %s\r\n"), m_sysName);
76720a09
VK
2087 }
2088 UnlockData();
2089 }
2090
2091 // Check IP forwarding
074498ac 2092 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.2.1.4.1.0"), 1))
76720a09
VK
2093 {
2094 LockData();
2095 m_dwFlags |= NF_IS_ROUTER;
2096 UnlockData();
2097 }
2098 else
2099 {
2100 LockData();
2101 m_dwFlags &= ~NF_IS_ROUTER;
2102 UnlockData();
2103 }
2104
2105 checkIfXTable(pTransport);
2106 checkBridgeMib(pTransport);
eec253a8 2107
76720a09 2108 // Check for ENTITY-MIB support
d525c9ed 2109 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.47.1.4.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_RAW_RESULT) == SNMP_ERR_SUCCESS)
76720a09
VK
2110 {
2111 LockData();
2112 m_dwFlags |= NF_HAS_ENTITY_MIB;
2113 UnlockData();
2114
2115 ComponentTree *components = BuildComponentTree(this, pTransport);
2116 LockData();
2117 if (m_components != NULL)
2118 m_components->decRefCount();
2119 m_components = components;
2120 UnlockData();
2121 }
2122 else
2123 {
2124 LockData();
2125 m_dwFlags &= ~NF_HAS_ENTITY_MIB;
2126 if (m_components != NULL)
2127 {
2128 m_components->decRefCount();
2129 m_components = NULL;
2130 }
2131 UnlockData();
2132 }
2133
2134 // Check for printer MIB support
2135 int count = 0;
46b7166d 2136 SnmpWalk(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.43.5.1.1.17"), CountingSnmpWalkerCallback, &count, FALSE);
76720a09
VK
2137 if (count > 0)
2138 {
2139 LockData();
2140 m_dwFlags |= NF_IS_PRINTER;
2141 UnlockData();
2142 }
2143 else
2144 {
2145 LockData();
2146 m_dwFlags &= ~NF_IS_PRINTER;
2147 UnlockData();
2148 }
2149
2150 // Check for CDP (Cisco Discovery Protocol) support
074498ac 2151 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.9.9.23.1.3.1.0"), 1))
76720a09
VK
2152 {
2153 LockData();
2154 m_dwFlags |= NF_IS_CDP;
2155 UnlockData();
2156 }
2157 else
2158 {
2159 LockData();
2160 m_dwFlags &= ~NF_IS_CDP;
2161 UnlockData();
2162 }
2163
2164 // Check for NDP (Nortel Discovery Protocol) support
074498ac 2165 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.45.1.6.13.1.2.0"), 1))
76720a09
VK
2166 {
2167 LockData();
2168 m_dwFlags |= NF_IS_NDP;
2169 UnlockData();
2170 }
2171 else
2172 {
2173 LockData();
2174 m_dwFlags &= ~NF_IS_NDP;
2175 UnlockData();
2176 }
2177
2178 // Check for LLDP (Link Layer Discovery Protocol) support
d525c9ed 2179 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.0.8802.1.1.2.1.3.2.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
76720a09
VK
2180 {
2181 LockData();
2182 m_dwFlags |= NF_IS_LLDP;
2183 UnlockData();
2184
d525c9ed 2185 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.0.8802.1.1.2.1.3.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
76720a09
VK
2186 {
2187 _tcscat(szBuffer, _T("@"));
2188 int len = (int)_tcslen(szBuffer);
d525c9ed 2189 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.0.8802.1.1.2.1.3.2.0"), NULL, 0, &szBuffer[len], (4096 - len) * sizeof(TCHAR), SG_HSTRING_RESULT) == SNMP_ERR_SUCCESS)
76720a09
VK
2190 {
2191 LockData();
2192 if ((m_lldpNodeId == NULL) || _tcscmp(m_lldpNodeId, szBuffer))
2193 {
2194 safe_free(m_lldpNodeId);
2195 m_lldpNodeId = _tcsdup(szBuffer);
2196 hasChanges = true;
21c9acce 2197 sendPollerMsg(dwRqId, _T(" LLDP node ID changed to %s\r\n"), m_lldpNodeId);
76720a09
VK
2198 }
2199 UnlockData();
2200 }
2201 }
3a82d5ae
VK
2202
2203 ObjectArray<LLDP_LOCAL_PORT_INFO> *lldpPorts = GetLLDPLocalPortInfo(pTransport);
2204 LockData();
2205 delete m_lldpLocalPortInfo;
2206 m_lldpLocalPortInfo = lldpPorts;
2207 UnlockData();
76720a09
VK
2208 }
2209 else
2210 {
2211 LockData();
2212 m_dwFlags &= ~NF_IS_LLDP;
2213 UnlockData();
2214 }
2215
2216 // Check for 802.1x support
074498ac 2217 if (checkSNMPIntegerValue(pTransport, _T(".1.0.8802.1.1.1.1.1.1.0"), 1))
76720a09
VK
2218 {
2219 LockData();
2220 m_dwFlags |= NF_IS_8021X;
2221 UnlockData();
2222 }
2223 else
2224 {
2225 LockData();
2226 m_dwFlags &= ~NF_IS_8021X;
2227 UnlockData();
2228 }
2229
074498ac 2230 checkOSPFSupport(pTransport);
76720a09
VK
2231
2232 // Get VRRP information
2233 VrrpInfo *vrrpInfo = GetVRRPInfo(this);
2234 if (vrrpInfo != NULL)
2235 {
2236 LockData();
2237 m_dwFlags |= NF_IS_VRRP;
2238 delete m_vrrpInfo;
2239 m_vrrpInfo = vrrpInfo;
2240 UnlockData();
2241 }
2242 else
2243 {
2244 LockData();
2245 m_dwFlags &= ~NF_IS_VRRP;
2246 UnlockData();
2247 }
c6afd26a
VK
2248
2249 // Get wireless controller data
2250 if ((m_driver != NULL) && m_driver->isWirelessController(pTransport, &m_customAttributes, m_driverData))
2251 {
2587b41b
VK
2252 DbgPrintf(5, _T("ConfPoll(%s): node is wireless controller, reading access point information"), m_szName);
2253 sendPollerMsg(dwRqId, _T(" Reading wireless access point information\r\n"));
c6afd26a
VK
2254 LockData();
2255 m_dwFlags |= NF_IS_WIFI_CONTROLLER;
2256 UnlockData();
2257
2258 ObjectArray<AccessPointInfo> *aps = m_driver->getAccessPoints(pTransport, &m_customAttributes, m_driverData);
2259 if (aps != NULL)
2260 {
2587b41b
VK
2261 sendPollerMsg(dwRqId, POLLER_INFO _T(" %d wireless access points found\r\n"), aps->size());
2262 DbgPrintf(5, _T("ConfPoll(%s): got information about %d access points"), m_szName, aps->size());
f1989a3a 2263 int adopted = 0;
c6afd26a
VK
2264 for(int i = 0; i < aps->size(); i++)
2265 {
2266 AccessPointInfo *info = aps->get(i);
f1989a3a
VK
2267 if (info->getState() != AP_ADOPTED)
2268 continue;
2269
2270 adopted++;
c6afd26a 2271 AccessPoint *ap = FindAccessPointByMAC(info->getMacAddr());
d5de1d1d 2272 if (ap == NULL)
c6afd26a 2273 {
d5de1d1d 2274 String name;
4d2c3a54 2275
ffb44442
VK
2276 if (info->getName() != NULL)
2277 {
2278 name = info->getName();
2279 }
2280 else
2281 {
2282 for(int j = 0; j < info->getRadioInterfaces()->size(); j++)
2283 {
2284 if (j > 0)
2285 name += _T("/");
2286 name += info->getRadioInterfaces()->get(j)->name;
2287 }
2288 }
f1989a3a
VK
2289 ap = new AccessPoint((const TCHAR *)name, info->getMacAddr());
2290 NetObjInsert(ap, TRUE);
2291 DbgPrintf(5, _T("ConfPoll(%s): created new access point object %s [%d]"), m_szName, ap->Name(), ap->Id());
c6afd26a 2292 }
d5de1d1d
VK
2293 ap->attachToNode(m_dwId);
2294 ap->updateRadioInterfaces(info->getRadioInterfaces());
f1989a3a
VK
2295 ap->updateInfo(NULL, info->getModel(), info->getSerial());
2296 ap->unhide();
c6afd26a 2297 }
f1989a3a
VK
2298
2299 LockData();
2300 m_adoptedApCount = adopted;
2301 m_totalApCount = aps->size();
2302 UnlockData();
2303
c6afd26a
VK
2304 delete aps;
2305 }
2587b41b
VK
2306 else
2307 {
2308 DbgPrintf(5, _T("ConfPoll(%s): failed to read access point information"), m_szName);
2309 sendPollerMsg(dwRqId, POLLER_ERROR _T(" Failed to read access point information\r\n"));
2310 }
c6afd26a
VK
2311 }
2312 else
2313 {
2314 LockData();
2315 m_dwFlags &= ~NF_IS_WIFI_CONTROLLER;
2316 UnlockData();
2317 }
76720a09
VK
2318 }
2319 else
2320 {
2321 // Check for CheckPoint SNMP agent on port 161
2322 DbgPrintf(5, _T("ConfPoll(%s): checking for CheckPoint SNMP"), m_szName);
2323 TCHAR szBuffer[4096];
d525c9ed 2324 if (SnmpGet(SNMP_VERSION_1, pTransport, _T(".1.3.6.1.4.1.2620.1.1.10.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
76720a09
VK
2325 {
2326 LockData();
2327 if (_tcscmp(m_szObjectId, _T(".1.3.6.1.4.1.2620.1.1")))
2328 {
2329 nx_strncpy(m_szObjectId, _T(".1.3.6.1.4.1.2620.1.1"), MAX_OID_LEN * 4);
2330 hasChanges = true;
2331 }
2332
2333 m_dwFlags |= NF_IS_SNMP | NF_IS_ROUTER;
2334 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
2335 UnlockData();
21c9acce 2336 sendPollerMsg(dwRqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 161 is active\r\n"));
76720a09
VK
2337 }
2338 }
2339 delete pTransport;
2340 return hasChanges;
2341}
2342
2343/**
2344 * Configuration poll: check for BRIDGE MIB
2345 */
2346void Node::checkBridgeMib(SNMP_Transport *pTransport)
2347{
2348 TCHAR szBuffer[4096];
d525c9ed 2349 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.17.1.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_RAW_RESULT) == SNMP_ERR_SUCCESS)
76720a09
VK
2350 {
2351 LockData();
2352 m_dwFlags |= NF_IS_BRIDGE;
2353 memcpy(m_baseBridgeAddress, szBuffer, 6);
2354 UnlockData();
2355
2356 // Check for Spanning Tree (IEEE 802.1d) MIB support
074498ac 2357 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.2.1.17.2.1.0"), 3))
76720a09
VK
2358 {
2359 LockData();
2360 m_dwFlags |= NF_IS_STP;
2361 UnlockData();
2362 }
2363 else
2364 {
2365 LockData();
2366 m_dwFlags &= ~NF_IS_STP;
2367 UnlockData();
2368 }
2369 }
2370 else
2371 {
2372 LockData();
2373 m_dwFlags &= ~(NF_IS_BRIDGE | NF_IS_STP);
2374 UnlockData();
2375 }
2376}
2377
2378/**
2379 * Configuration poll: check for ifXTable
2380 */
2381void Node::checkIfXTable(SNMP_Transport *pTransport)
2382{
2383 int count = 0;
46b7166d 2384 SnmpWalk(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.31.1.1.1.1"), CountingSnmpWalkerCallback, &count, FALSE);
76720a09
VK
2385 if (count > 0)
2386 {
2387 LockData();
2388 m_dwFlags |= NF_HAS_IFXTABLE;
2389 UnlockData();
2390 }
2391 else
2392 {
2393 LockData();
2394 m_dwFlags &= ~NF_HAS_IFXTABLE;
2395 UnlockData();
2396 }
2397}
2398
2399/**
2400 * Update interface configuration
2401 */
967893bb 2402BOOL Node::updateInterfaceConfiguration(UINT32 dwRqId, UINT32 dwNetMask)
eec253a8 2403{
98762401 2404 InterfaceList *pIfList;
eec253a8
VK
2405 Interface **ppDeleteList;
2406 int i, j, iDelCount;
2407 BOOL hasChanges = FALSE;
2408 Cluster *pCluster = getMyCluster();
2409
21c9acce 2410 sendPollerMsg(dwRqId, _T("Checking interface configuration...\r\n"));
eec253a8
VK
2411 pIfList = getInterfaceList();
2412 if (pIfList != NULL)
2413 {
22d657d2 2414 DbgPrintf(6, _T("Node::updateInterfaceConfiguration(%s [%u]): got %d interfaces"), m_szName, m_dwId, pIfList->getSize());
eec253a8
VK
2415 // Remove cluster virtual interfaces from list
2416 if (pCluster != NULL)
2417 {
98762401 2418 for(i = 0; i < pIfList->getSize(); i++)
eec253a8 2419 {
98762401 2420 if (pCluster->isVirtualAddr(pIfList->get(i)->dwIpAddr))
eec253a8 2421 {
98762401 2422 pIfList->remove(i);
eec253a8
VK
2423 i--;
2424 }
2425 }
2426 }
2427
2428 // Find non-existing interfaces
2429 LockChildList(FALSE);
2430 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
2431 for(i = 0, iDelCount = 0; i < (int)m_dwChildCount; i++)
2432 {
2433 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2434 {
2435 Interface *pInterface = (Interface *)m_pChildList[i];
9214177b
VK
2436 if (!pInterface->isManuallyCreated())
2437 {
2438 for(j = 0; j < pIfList->getSize(); j++)
2439 {
2440 if ((pIfList->get(j)->dwIndex == pInterface->getIfIndex()) &&
2441 (pIfList->get(j)->dwIpAddr == pInterface->IpAddr()))
2442 break;
2443 }
eec253a8 2444
9214177b
VK
2445 if (j == pIfList->getSize())
2446 {
2447 // No such interface in current configuration, add it to delete list
2448 ppDeleteList[iDelCount++] = pInterface;
2449 }
2450 }
eec253a8
VK
2451 }
2452 }
2453 UnlockChildList();
2454
2455 // Delete non-existent interfaces
2456 if (iDelCount > 0)
2457 {
2458 for(j = 0; j < iDelCount; j++)
2459 {
21c9acce 2460 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Interface \"%s\" is no longer exist\r\n"),
eec253a8
VK
2461 ppDeleteList[j]->Name());
2462 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->getIfIndex(),
2463 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->getIpNetMask());
2464 deleteInterface(ppDeleteList[j]);
2465 }
2466 hasChanges = TRUE;
2467 }
2468 safe_free(ppDeleteList);
2469
2470 // Add new interfaces and check configuration of existing
98762401 2471 for(j = 0; j < pIfList->getSize(); j++)
eec253a8 2472 {
60557d06 2473 NX_INTERFACE_INFO *ifInfo = pIfList->get(j);
eec253a8
VK
2474 BOOL bNewInterface = TRUE;
2475
2476 LockChildList(FALSE);
2477 for(i = 0; i < (int)m_dwChildCount; i++)
2478 {
2479 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2480 {
2481 Interface *pInterface = (Interface *)m_pChildList[i];
2482
98762401
VK
2483 if ((ifInfo->dwIndex == pInterface->getIfIndex()) &&
2484 (ifInfo->dwIpAddr == pInterface->IpAddr()))
eec253a8
VK
2485 {
2486 // Existing interface, check configuration
22d657d2 2487 if (memcmp(ifInfo->bMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) && memcmp(ifInfo->bMacAddr, pInterface->getMacAddr(), MAC_ADDR_LENGTH))
eec253a8
VK
2488 {
2489 TCHAR szOldMac[16], szNewMac[16];
2490
2491 BinToStr((BYTE *)pInterface->getMacAddr(), MAC_ADDR_LENGTH, szOldMac);
98762401 2492 BinToStr(ifInfo->bMacAddr, MAC_ADDR_LENGTH, szNewMac);
eec253a8
VK
2493 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
2494 pInterface->Id(), pInterface->getIfIndex(),
2495 pInterface->Name(), szOldMac, szNewMac);
98762401 2496 pInterface->setMacAddr(ifInfo->bMacAddr);
eec253a8 2497 }
98762401 2498 if (_tcscmp(ifInfo->szName, pInterface->Name()))
eec253a8 2499 {
98762401 2500 pInterface->setName(ifInfo->szName);
eec253a8 2501 }
478d4ff4
VK
2502 if (_tcscmp(ifInfo->szDescription, pInterface->getDescription()))
2503 {
2504 pInterface->setDescription(ifInfo->szDescription);
2505 }
98762401 2506 if (ifInfo->dwBridgePortNumber != pInterface->getBridgePortNumber())
eec253a8 2507 {
98762401 2508 pInterface->setBridgePortNumber(ifInfo->dwBridgePortNumber);
eec253a8 2509 }
98762401 2510 if (ifInfo->dwSlotNumber != pInterface->getSlotNumber())
76f9abfd 2511 {
98762401 2512 pInterface->setSlotNumber(ifInfo->dwSlotNumber);
76f9abfd 2513 }
98762401 2514 if (ifInfo->dwPortNumber != pInterface->getPortNumber())
76f9abfd 2515 {
98762401 2516 pInterface->setPortNumber(ifInfo->dwPortNumber);
76f9abfd 2517 }
4c16cdc7
VK
2518 if (ifInfo->isPhysicalPort != pInterface->isPhysicalPort())
2519 {
2520 pInterface->setPhysicalPortFlag(ifInfo->isPhysicalPort);
2521 }
98762401 2522 if ((ifInfo->dwIpNetMask != 0) && (ifInfo->dwIpNetMask != pInterface->getIpNetMask()))
dfb38baf 2523 {
98762401 2524 pInterface->setIpNetMask(ifInfo->dwIpNetMask);
dfb38baf 2525 }
eec253a8
VK
2526 bNewInterface = FALSE;
2527 break;
2528 }
2529 }
2530 }
2531 UnlockChildList();
2532
2533 if (bNewInterface)
2534 {
2535 // New interface
21c9acce 2536 sendPollerMsg(dwRqId, POLLER_INFO _T(" Found new interface \"%s\"\r\n"), ifInfo->szName);
4d2c3a54 2537 createNewInterface(ifInfo->dwIpAddr,
98762401
VK
2538 ifInfo->dwIpNetMask,
2539 ifInfo->szName,
478d4ff4 2540 ifInfo->szDescription,
98762401
VK
2541 ifInfo->dwIndex,
2542 ifInfo->dwType,
2543 ifInfo->bMacAddr,
2544 ifInfo->dwBridgePortNumber,
2545 ifInfo->dwSlotNumber,
4c16cdc7 2546 ifInfo->dwPortNumber,
01152a54 2547 ifInfo->isPhysicalPort,
68820776 2548 false,
01152a54 2549 ifInfo->isSystem);
eec253a8
VK
2550 hasChanges = TRUE;
2551 }
2552 }
2553
2554 // Check if address we are using to communicate with node
2555 // is configured on one of node's interfaces
98762401
VK
2556 for(i = 0; i < pIfList->getSize(); i++)
2557 if (pIfList->get(i)->dwIpAddr == m_dwIpAddr)
eec253a8
VK
2558 break;
2559
967893bb 2560 if (i == (UINT32)pIfList->getSize())
eec253a8 2561 {
eec253a8 2562 // Node is behind NAT
563179bc 2563 if (!(m_dwFlags & NF_BEHIND_NAT))
eec253a8 2564 {
563179bc
VK
2565 m_dwFlags |= NF_BEHIND_NAT;
2566 hasChanges = TRUE;
2567 }
eec253a8
VK
2568 }
2569 else
2570 {
2571 // Check if NF_BEHIND_NAT flag set incorrectly
2572 if (m_dwFlags & NF_BEHIND_NAT)
2573 {
eec253a8
VK
2574 m_dwFlags &= ~NF_BEHIND_NAT;
2575 hasChanges = TRUE;
2576 }
2577 }
2578
024c3faf 2579 checkSubnetBinding(pIfList);
eec253a8 2580
98762401 2581 delete pIfList;
eec253a8
VK
2582 }
2583 else /* pIfList == NULL */
2584 {
2585 Interface *pInterface;
967893bb 2586 UINT32 dwCount;
eec253a8 2587
21c9acce 2588 sendPollerMsg(dwRqId, POLLER_ERROR _T("Unable to get interface list from node\r\n"));
22d657d2 2589 DbgPrintf(6, _T("Node::updateInterfaceConfiguration(%s [%u]): Unable to get interface list from node"), m_szName, m_dwId);
eec253a8
VK
2590
2591 // Delete all existing interfaces in case of forced capability recheck
2592 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
2593 {
2594 LockChildList(FALSE);
2595 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
2596 for(i = 0, iDelCount = 0; i < (int)m_dwChildCount; i++)
2597 {
9214177b 2598 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) && !((Interface *)m_pChildList[i])->isManuallyCreated())
eec253a8
VK
2599 ppDeleteList[iDelCount++] = (Interface *)m_pChildList[i];
2600 }
2601 UnlockChildList();
2602 for(j = 0; j < iDelCount; j++)
2603 {
21c9acce 2604 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Interface \"%s\" is no longer exist\r\n"),
eec253a8
VK
2605 ppDeleteList[j]->Name());
2606 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->getIfIndex(),
2607 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->getIpNetMask());
2608 deleteInterface(ppDeleteList[j]);
2609 }
2610 safe_free(ppDeleteList);
2611 }
2612
2613 // Check if we have pseudo-interface object
baa5324c
AK
2614 BYTE macAddr[MAC_ADDR_LENGTH];
2615 BYTE *pMacAddr;
eec253a8
VK
2616 dwCount = getInterfaceCount(&pInterface);
2617 if (dwCount == 1)
2618 {
2619 if (pInterface->isFake())
2620 {
2621 // Check if primary IP is different from interface's IP
2622 if (pInterface->IpAddr() != m_dwIpAddr)
2623 {
2624 deleteInterface(pInterface);
2625 if (m_dwIpAddr != 0)
baa5324c
AK
2626 {
2627 memset(macAddr, 0, MAC_ADDR_LENGTH);
2628 Subnet *pSubnet = FindSubnetForNode(m_zoneId, m_dwIpAddr);
2629 if (pSubnet != NULL)
2630 pSubnet->findMacAddress(m_dwIpAddr, macAddr);
22d657d2 2631 pMacAddr = !memcmp(macAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) ? NULL : macAddr;
baa5324c
AK
2632 TCHAR szMac[20];
2633 MACToStr(macAddr, szMac);
dab4332d 2634 DbgPrintf(5, _T("Node::updateInterfaceConfiguration(%s [%u]): got MAC for unknown interface: %s"), m_szName, m_dwId, szMac);
baa5324c
AK
2635 createNewInterface(m_dwIpAddr, dwNetMask, NULL, NULL, 0, 0, pMacAddr);
2636 }
eec253a8 2637 }
22d657d2
VK
2638 else
2639 {
2640 // check MAC address
2641 memset(macAddr, 0, MAC_ADDR_LENGTH);
2642 Subnet *pSubnet = FindSubnetForNode(m_zoneId, m_dwIpAddr);
2643 if (pSubnet != NULL)
2644 pSubnet->findMacAddress(m_dwIpAddr, macAddr);
2645 if (memcmp(macAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) && memcmp(macAddr, pInterface->getMacAddr(), MAC_ADDR_LENGTH))
2646 {
2647 TCHAR szOldMac[16], szNewMac[16];
2648
2649 BinToStr((BYTE *)pInterface->getMacAddr(), MAC_ADDR_LENGTH, szOldMac);
2650 BinToStr(macAddr, MAC_ADDR_LENGTH, szNewMac);
dab4332d 2651 DbgPrintf(5, _T("Node::updateInterfaceConfiguration(%s [%u]): MAC change for unknown interface: %s to %s"),
22d657d2
VK
2652 m_szName, m_dwId, szOldMac, szNewMac);
2653 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
2654 pInterface->Id(), pInterface->getIfIndex(),
2655 pInterface->Name(), szOldMac, szNewMac);
2656 pInterface->setMacAddr(macAddr);
2657 }
2658 }
eec253a8
VK
2659 }
2660 }
2661 else if (dwCount == 0)
2662 {
2663 // No interfaces at all, create pseudo-interface
2664 if (m_dwIpAddr != 0)
baa5324c
AK
2665 {
2666 memset(macAddr, 0, MAC_ADDR_LENGTH);
2667 Subnet *pSubnet = FindSubnetForNode(m_zoneId, m_dwIpAddr);
2668 if (pSubnet != NULL)
2669 pSubnet->findMacAddress(m_dwIpAddr, macAddr);
22d657d2 2670 pMacAddr = !memcmp(macAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) ? NULL : macAddr;
baa5324c
AK
2671 TCHAR szMac[20];
2672 MACToStr(macAddr, szMac);
d51f2182 2673 DbgPrintf(5, _T("Node::updateInterfaceConfiguration(%s [%u]): got MAC for unknown interface: %s"), m_szName, m_dwId, szMac);
baa5324c
AK
2674 createNewInterface(m_dwIpAddr, dwNetMask, NULL, NULL, 0, 0, pMacAddr);
2675 }
eec253a8 2676 }
05c9a2f9 2677 DbgPrintf(6, _T("Node::updateInterfaceConfiguration(%s [%u]): pflist == NULL, dwCount = %u"), m_szName, m_dwId, dwCount);
eec253a8
VK
2678 }
2679
21c9acce 2680 sendPollerMsg(dwRqId, _T("Interface configuration check finished\r\n"));
eec253a8
VK
2681 return hasChanges;
2682}
2683
6fd6de0a 2684/**
7aad6641 2685 * Callback: apply template to nodes
6fd6de0a 2686 */
27de5dab 2687static void ApplyTemplate(NetObj *object, void *node)
4d0c32f3 2688{
6ff21d27 2689 if ((object->Type() == OBJECT_TEMPLATE) && !object->isDeleted())
4d0c32f3 2690 {
27de5dab
VK
2691 Template *pTemplate = (Template *)object;
2692 if (pTemplate->isApplicable((Node *)node))
2693 {
21c9acce 2694 if (!pTemplate->isChild(((Node *)node)->Id()))
5039dede 2695 {
27de5dab
VK
2696 DbgPrintf(4, _T("Node::ApplyUserTemplates(): applying template %d \"%s\" to node %d \"%s\""),
2697 pTemplate->Id(), pTemplate->Name(), ((Node *)node)->Id(), ((Node *)node)->Name());
6fd6de0a 2698 pTemplate->applyToTarget((Node *)node);
9b64b406 2699 PostEvent(EVENT_TEMPLATE_AUTOAPPLY, g_dwMgmtNode, "isis", ((Node *)node)->Id(), ((Node *)node)->Name(), pTemplate->Id(), pTemplate->Name());
5039dede 2700 }
27de5dab
VK
2701 }
2702 else
2703 {
21c9acce 2704 if (pTemplate->isAutoRemoveEnabled() && pTemplate->isChild(((Node *)node)->Id()))
5039dede 2705 {
27de5dab
VK
2706 DbgPrintf(4, _T("Node::ApplyUserTemplates(): removing template %d \"%s\" from node %d \"%s\""),
2707 pTemplate->Id(), pTemplate->Name(), ((Node *)node)->Id(), ((Node *)node)->Name());
2708 pTemplate->DeleteChild((Node *)node);
2709 ((Node *)node)->DeleteParent(pTemplate);
6fd6de0a 2710 pTemplate->queueRemoveFromTarget(((Node *)node)->Id(), TRUE);
9b64b406 2711 PostEvent(EVENT_TEMPLATE_AUTOREMOVE, g_dwMgmtNode, "isis", ((Node *)node)->Id(), ((Node *)node)->Name(), pTemplate->Id(), pTemplate->Name());
5039dede 2712 }
27de5dab 2713 }
5039dede 2714 }
27de5dab
VK
2715}
2716
7aad6641
VK
2717/**
2718 * Apply user templates
2719 */
6fd6de0a 2720void Node::applyUserTemplates()
27de5dab
VK
2721{
2722 g_idxObjectById.forEach(ApplyTemplate, this);
4d0c32f3 2723}
5039dede 2724
6fd6de0a 2725/**
7aad6641 2726 * Callback: update container membership
6fd6de0a 2727 */
27de5dab 2728static void UpdateContainerBinding(NetObj *object, void *node)
4d0c32f3 2729{
6ff21d27 2730 if ((object->Type() == OBJECT_CONTAINER) && !object->isDeleted())
5039dede 2731 {
27de5dab 2732 Container *pContainer = (Container *)object;
926e8ce7 2733 if (pContainer->isSuitableForNode((Node *)node))
27de5dab 2734 {
21c9acce 2735 if (!pContainer->isChild(((Node *)node)->Id()))
4d0c32f3 2736 {
27de5dab
VK
2737 DbgPrintf(4, _T("Node::UpdateContainerMembership(): binding node %d \"%s\" to container %d \"%s\""),
2738 ((Node *)node)->Id(), ((Node *)node)->Name(), pContainer->Id(), pContainer->Name());
2739 pContainer->AddChild((Node *)node);
2740 ((Node *)node)->AddParent(pContainer);
9b64b406 2741 PostEvent(EVENT_CONTAINER_AUTOBIND, g_dwMgmtNode, "isis", ((Node *)node)->Id(), ((Node *)node)->Name(), pContainer->Id(), pContainer->Name());
4d0c32f3 2742 }
27de5dab
VK
2743 }
2744 else
2745 {
21c9acce 2746 if (pContainer->isAutoUnbindEnabled() && pContainer->isChild(((Node *)node)->Id()))
4d0c32f3 2747 {
27de5dab
VK
2748 DbgPrintf(4, _T("Node::UpdateContainerMembership(): removing node %d \"%s\" from container %d \"%s\""),
2749 ((Node *)node)->Id(), ((Node *)node)->Name(), pContainer->Id(), pContainer->Name());
2750 pContainer->DeleteChild((Node *)node);
2751 ((Node *)node)->DeleteParent(pContainer);
9b64b406 2752 PostEvent(EVENT_CONTAINER_AUTOUNBIND, g_dwMgmtNode, "isis", ((Node *)node)->Id(), ((Node *)node)->Name(), pContainer->Id(), pContainer->Name());
4d0c32f3 2753 }
27de5dab 2754 }
5039dede 2755 }
27de5dab
VK
2756}
2757
7aad6641
VK
2758/**
2759 * Update container membership
2760 */
27de5dab
VK
2761void Node::updateContainerMembership()
2762{
2763 g_idxObjectById.forEach(UpdateContainerBinding, this);
5039dede
AK
2764}
2765
a3050773 2766/**
d51f2182
VK
2767 * Do instance discovery
2768 */
2769void Node::doInstanceDiscovery()
2770{
2771 // collect instance discovery DCIs
2772 ObjectArray<DCItem> rootItems;
b06436f4 2773 lockDciAccess(false);
d51f2182
VK
2774 for(int i = 0; i < m_dcObjects->size(); i++)
2775 {
2776 DCObject *object = m_dcObjects->get(i);
2777 if ((object->getType() == DCO_TYPE_ITEM) && (((DCItem *)object)->getInstanceDiscoveryMethod() != IDM_NONE))
2778 {
2779 object->setBusyFlag(TRUE);
2780 rootItems.add((DCItem *)object);
2781 }
2782 }
2783 unlockDciAccess();
2784
2785 // process instance discovery DCIs
2786 // it should be done that way to prevent DCI list lock for long time
2787 for(int i = 0; i < rootItems.size(); i++)
2788 {
2789 DCItem *dci = rootItems.get(i);
2790 DbgPrintf(5, _T("Node::doInstanceDiscovery(%s [%u]): Updating instances for instance discovery DCI %s [%d]"),
2791 m_szName, m_dwId, dci->getName(), dci->getId());
2792 StringList *instances = getInstanceList(dci);
2793 if (instances != NULL)
2794 {
2795 DbgPrintf(5, _T("Node::doInstanceDiscovery(%s [%u]): read %d values"), m_szName, m_dwId, instances->getSize());
27bbb906 2796 dci->filterInstanceList(instances);
d51f2182
VK
2797 updateInstances(dci, instances);
2798 delete instances;
2799 }
2800 else
2801 {
2802 DbgPrintf(5, _T("Node::doInstanceDiscovery(%s [%u]): failed to get instance list for DCI %s [%d]"),
2803 m_szName, m_dwId, dci->getName(), dci->getId());
2804 }
2805 dci->setBusyFlag(FALSE);
2806 }
2807}
2808
2809/**
2810 * Get instances for instance discovery DCI
2811 */
2812StringList *Node::getInstanceList(DCItem *dci)
2813{
2814 if (dci->getInstanceDiscoveryData() == NULL)
2815 return NULL;
2816
2817 StringList *instances;
2818 switch(dci->getInstanceDiscoveryMethod())
2819 {
2820 case IDM_AGENT_LIST:
2821 getListFromAgent(dci->getInstanceDiscoveryData(), &instances);
2822 break;
7aad6641
VK
2823 case IDM_SNMP_WALK_VALUES:
2824 getListFromSNMP(dci->getSnmpPort(), dci->getInstanceDiscoveryData(), &instances);
2825 break;
2826 case IDM_SNMP_WALK_OIDS:
2827 getOIDSuffixListFromSNMP(dci->getSnmpPort(), dci->getInstanceDiscoveryData(), &instances);
2828 break;
d51f2182
VK
2829 default:
2830 instances = NULL;
2831 break;
2832 }
2833 return instances;
2834}
2835
2836/**
2837 * Update instance DCIs created from instance discovery DCI
2838 */
2839void Node::updateInstances(DCItem *root, StringList *instances)
2840{
b06436f4 2841 lockDciAccess(true);
d51f2182
VK
2842
2843 // Delete DCIs for missing instances and update existing
967893bb 2844 IntegerArray<UINT32> deleteList;
d51f2182
VK
2845 for(int i = 0; i < m_dcObjects->size(); i++)
2846 {
2847 DCObject *object = m_dcObjects->get(i);
4d2c3a54 2848 if ((object->getType() != DCO_TYPE_ITEM) ||
2849 (object->getTemplateId() != m_dwId) ||
d51f2182
VK
2850 (object->getTemplateItemId() != root->getId()))
2851 continue;
2852
2853 int j;
2854 for(j = 0; j < instances->getSize(); j++)
2855 if (!_tcscmp(((DCItem *)object)->getInstance(), instances->getValue(j)))
2856 break;
2857
2858 if (j < instances->getSize())
2859 {
2860 // found, remove value from instances
2861 DbgPrintf(5, _T("Node::updateInstances(%s [%u], %s [%u]): instance \"%s\" found"),
2862 m_szName, m_dwId, root->getName(), root->getId(), instances->getValue(j));
2863 instances->remove(j);
2864 }
2865 else
2866 {
2867 // not found, delete DCI
2868 DbgPrintf(5, _T("Node::updateInstances(%s [%u], %s [%u]): instance \"%s\" not found, instance DCI will be deleted"),
27bbb906 2869 m_szName, m_dwId, root->getName(), root->getId(), ((DCItem *)object)->getInstance());
e8e76b4f 2870 deleteList.add(object->getId());
d51f2182
VK
2871 }
2872 }
2873
2874 for(int i = 0; i < deleteList.size(); i++)
e8e76b4f 2875 deleteDCObject(deleteList.get(i), false);
d51f2182
VK
2876
2877 // Create new instances
2878 for(int i = 0; i < instances->getSize(); i++)
2879 {
27bbb906
VK
2880 DbgPrintf(5, _T("Node::updateInstances(%s [%u], %s [%u]): creating new DCI for instance \"%s\""),
2881 m_szName, m_dwId, root->getName(), root->getId(), instances->getValue(i));
2882
d51f2182
VK
2883 DCItem *dci = new DCItem(root);
2884 dci->setTemplateId(m_dwId, root->getId());
2885 dci->setInstance(instances->getValue(i));
2886 dci->setInstanceDiscoveryMethod(IDM_NONE);
2887 dci->setInstanceDiscoveryData(NULL);
2888 dci->setInstanceFilter(NULL);
2889 dci->expandInstance();
2890 dci->changeBinding(CreateUniqueId(IDG_ITEM), this, FALSE);
2891 addDCObject(dci, true);
2892 }
2893
2894 unlockDciAccess();
2895}
2896
2897/**
1d0d82b3
VK
2898 * Connect to SM-CLP agent. Assumes that access to SM-CLP connection is already locked.
2899 */
2900bool Node::connectToSMCLP()
2901{
2902 // Create new connection object if needed
2903 if (m_smclpConnection == NULL)
2904 {
2905 m_smclpConnection = new SMCLP_Connection(m_dwIpAddr, 23);
2906 DbgPrintf(7, _T("Node::connectToSMCLP(%s [%d]): new connection created"), m_szName, m_dwId);
2907 }
2908 else
2909 {
2910 // Check if we already connected
2911 if (m_smclpConnection->checkConnection())
2912 {
2913 DbgPrintf(7, _T("Node::connectToSMCLP(%s [%d]): already connected"), m_szName, m_dwId);
2914 return true;
2915 }
2916
2917 // Close current connection or clean up after broken connection
2918 m_smclpConnection->disconnect();
2919 delete m_smclpConnection;
2920 m_smclpConnection = new SMCLP_Connection(m_dwIpAddr, 23);
2921 DbgPrintf(7, _T("Node::connectToSMCLP(%s [%d]): existing connection reset"), m_szName, m_dwId);
2922 }
2923
2924 const TCHAR *login = getCustomAttribute(_T("iLO.login"));
2925 const TCHAR *password = getCustomAttribute(_T("iLO.password"));
2926
2927 if ((login != NULL) && (password != NULL))
2928 return m_smclpConnection->connect(login, password);
2929 return false;
2930}
2931
2932/**
a3050773
VK
2933 * Connect to native agent. Assumes that access to agent connection is already locked.
2934 */
967893bb 2935BOOL Node::connectToAgent(UINT32 *error, UINT32 *socketError)
5039dede
AK
2936{
2937 BOOL bRet;
2938
2939 // Create new agent connection object if needed
2940 if (m_pAgentConnection == NULL)
4b91844f 2941 {
d1c1c522 2942 m_pAgentConnection = new AgentConnectionEx(m_dwId, htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
4b91844f
VK
2943 DbgPrintf(7, _T("Node::connectToAgent(%s [%d]): new agent connection created"), m_szName, m_dwId);
2944 }
2945 else
2946 {
2947 // Check if we already connected
2948 if (m_pAgentConnection->nop() == ERR_SUCCESS)
2949 {
2950 DbgPrintf(7, _T("Node::connectToAgent(%s [%d]): already connected"), m_szName, m_dwId);
2951 return TRUE;
2952 }
5039dede 2953
4b91844f
VK
2954 // Close current connection or clean up after broken connection
2955 m_pAgentConnection->disconnect();
2956 DbgPrintf(7, _T("Node::connectToAgent(%s [%d]): existing connection reset"), m_szName, m_dwId);
2957 }
7c521895
VK
2958 m_pAgentConnection->setPort(m_wAgentPort);
2959 m_pAgentConnection->setAuthData(m_wAuthMethod, m_szSharedSecret);
2960 setAgentProxy(m_pAgentConnection);
4b91844f 2961 DbgPrintf(7, _T("Node::connectToAgent(%s [%d]): calling connect on port %d"), m_szName, m_dwId, (int)m_wAgentPort);
a4569c4d 2962 bRet = m_pAgentConnection->connect(g_pServerKey, FALSE, error, socketError);
5039dede
AK
2963 if (bRet)
2964 {
c59466d2 2965 m_pAgentConnection->setCommandTimeout(g_agentCommandTimeout);
45d84f8a 2966 m_pAgentConnection->enableTraps();
5039dede
AK
2967 }
2968 return bRet;
2969}
2970
a3050773
VK
2971/**
2972 * Get DCI value via SNMP
2973 */
967893bb 2974UINT32 Node::getItemFromSNMP(WORD port, const TCHAR *szParam, UINT32 dwBufSize, TCHAR *szBuffer, int interpretRawValue)
5039dede 2975{
967893bb 2976 UINT32 dwResult;
5039dede 2977
2fd7144f 2978 if ((((m_dwDynamicFlags & NDF_SNMP_UNREACHABLE) || !(m_dwFlags & NF_IS_SNMP)) && (port == 0)) ||
6b2bb22c
VK
2979 (m_dwDynamicFlags & NDF_UNREACHABLE) ||
2980 (m_dwFlags & NF_DISABLE_SNMP))
5039dede
AK
2981 {
2982 dwResult = SNMP_ERR_COMM;
2983 }
2984 else
2985 {
2986 SNMP_Transport *pTransport;
2987
65e2005b 2988 pTransport = createSnmpTransport(port);
803d47be
VK
2989 if (pTransport != NULL)
2990 {
e320f8ce
VK
2991 if (interpretRawValue == SNMP_RAWTYPE_NONE)
2992 {
d525c9ed 2993 dwResult = SnmpGet(m_snmpVersion, pTransport, szParam, NULL, 0, szBuffer, dwBufSize * sizeof(TCHAR), SG_PSTRING_RESULT);
e320f8ce
VK
2994 }
2995 else
2996 {
2997 BYTE rawValue[1024];
2998 memset(rawValue, 0, 1024);
2999 dwResult = SnmpGet(m_snmpVersion, pTransport, szParam, NULL, 0, rawValue, 1024, SG_RAW_RESULT);
3000 if (dwResult == SNMP_ERR_SUCCESS)
3001 {
3002 switch(interpretRawValue)
3003 {
3004 case SNMP_RAWTYPE_INT32:
3005 _sntprintf(szBuffer, dwBufSize, _T("%d"), ntohl(*((LONG *)rawValue)));
3006 break;
3007 case SNMP_RAWTYPE_UINT32:
967893bb 3008 _sntprintf(szBuffer, dwBufSize, _T("%u"), ntohl(*((UINT32 *)rawValue)));
e320f8ce
VK
3009 break;
3010 case SNMP_RAWTYPE_INT64:
7aad6641 3011 _sntprintf(szBuffer, dwBufSize, INT64_FMT, (INT64)ntohq(*((INT64 *)rawValue)));
e320f8ce
VK
3012 break;
3013 case SNMP_RAWTYPE_UINT64:
3014 _sntprintf(szBuffer, dwBufSize, UINT64_FMT, ntohq(*((QWORD *)rawValue)));
3015 break;
3016 case SNMP_RAWTYPE_DOUBLE:
3017 _sntprintf(szBuffer, dwBufSize, _T("%f"), ntohd(*((double *)rawValue)));
3018 break;
3019 case SNMP_RAWTYPE_IP_ADDR:
967893bb 3020 IpToStr(ntohl(*((UINT32 *)rawValue)), szBuffer);
e320f8ce
VK
3021 break;
3022 case SNMP_RAWTYPE_MAC_ADDR:
3023 MACToStr(rawValue, szBuffer);
3024 break;
3025 default:
3026 szBuffer[0] = 0;
3027 break;
3028 }
3029 }
3030 }
803d47be
VK
3031 delete pTransport;
3032 }
3033 else
3034 {
3035 dwResult = SNMP_ERR_COMM;
3036 }
5039dede 3037 }
35f836fe 3038 DbgPrintf(7, _T("Node(%s)->GetItemFromSNMP(%s): dwResult=%d"), m_szName, szParam, dwResult);
4d2c3a54 3039 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
5039dede
AK
3040 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3041}
3042
6fd6de0a 3043/**
db117859
VK
3044 * Read one row for SNMP table
3045 */
4d2c3a54 3046static UINT32 ReadSNMPTableRow(SNMP_Transport *snmp, SNMP_ObjectId *rowOid, UINT32 baseOidLen, UINT32 index,
db117859
VK
3047 ObjectArray<DCTableColumn> *columns, Table *table)
3048{
3049 SNMP_PDU request(SNMP_GET_REQUEST, SnmpNewRequestId(), snmp->getSnmpVersion());
3050 for(int i = 0; i < columns->size(); i++)
3051 {
3052 DCTableColumn *c = columns->get(i);
3053 if (c->getSnmpOid() != NULL)
3054 {
3055 UINT32 oid[MAX_OID_LEN];
3056 UINT32 oidLen = c->getSnmpOid()->getLength();
3057 memcpy(oid, c->getSnmpOid()->getValue(), oidLen * sizeof(UINT32));
3058 if (rowOid != NULL)
3059 {
3060 UINT32 suffixLen = rowOid->getLength() - baseOidLen;
3061 memcpy(&oid[oidLen], rowOid->getValue() + baseOidLen, suffixLen * sizeof(UINT32));
3062 oidLen += suffixLen;
3063 }
3064 else
3065 {
3066 oid[oidLen++] = index;
3067 }
3068 request.bindVariable(new SNMP_Variable(oid, oidLen));
3069 }
3070 }
3071
3072 SNMP_PDU *response;
3073 UINT32 rc = snmp->doRequest(&request, &response, g_dwSNMPTimeout, 3);
3074 if (rc == SNMP_ERR_SUCCESS)
3075 {
3076 if (((int)response->getNumVariables() >= columns->size()) &&
3077 (response->getErrorCode() == SNMP_PDU_ERR_SUCCESS))
3078 {
3079 table->addRow();
3080 for(UINT32 i = 0; i < response->getNumVariables(); i++)
3081 {
3082 SNMP_Variable *v = response->getVariable(i);
3083 if ((v != NULL) && (v->GetType() != ASN_NO_SUCH_OBJECT) && (v->GetType() != ASN_NO_SUCH_INSTANCE))
3084 {
3085 bool convert = false;
3086 TCHAR buffer[256];
3087 table->set((int)i, v->getValueAsPrintableString(buffer, 256, &convert));
3088 }
3089 }
3090 }
3091 delete response;
3092 }
3093 return rc;
3094}
3095
3096/**
3097 * Callback for SnmpWalk in Node::getTableFromSNMP
3098 */
3099static UINT32 SNMPGetTableCallback(UINT32 snmpVersion, SNMP_Variable *varbind, SNMP_Transport *snmp, void *arg)
3100{
3101 ((ObjectArray<SNMP_ObjectId> *)arg)->add(new SNMP_ObjectId(varbind->GetName()));
3102 return SNMP_ERR_SUCCESS;
3103}
3104
3105/**
3106 * Get table from SNMP
3107 */
3108UINT32 Node::getTableFromSNMP(WORD port, const TCHAR *oid, ObjectArray<DCTableColumn> *columns, Table **table)
3109{
3110 *table = NULL;
3111
3112 SNMP_Transport *snmp = createSnmpTransport(port);
3113 if (snmp == NULL)
3114 return DCE_COMM_ERROR;
3115
3116 ObjectArray<SNMP_ObjectId> oidList(64, 64, true);
3117 UINT32 rc = SnmpWalk(snmp->getSnmpVersion(), snmp, oid, SNMPGetTableCallback, &oidList, FALSE);
3118 if (rc == SNMP_ERR_SUCCESS)
3119 {
3120 *table = new Table;
3121 for(int i = 0; i < columns->size(); i++)
3122 {
3123 DCTableColumn *c = columns->get(i);
3124 if (c->getSnmpOid() != NULL)
3125 (*table)->addColumn(c->getName(), c->getDataType(), c->getDisplayName(), c->isInstanceColumn());
3126 }
3127
3128 UINT32 baseOidLen = SNMPGetOIDLength(oid);
3129 for(int i = 0; i < oidList.size(); i++)
3130 {
3131 rc = ReadSNMPTableRow(snmp, oidList.get(i), baseOidLen, 0, columns, *table);
3132 if (rc != SNMP_ERR_SUCCESS)
3133 break;
3134 }
3135 }
3136 delete snmp;
3137 return (rc == SNMP_ERR_SUCCESS) ? DCE_SUCCESS : ((rc == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3138}
3139
3140/**
46b7166d 3141 * Callback for SnmpWalk in Node::getListFromSNMP
7aad6641 3142 */
967893bb 3143static UINT32 SNMPGetListCallback(UINT32 snmpVersion, SNMP_Variable *varbind, SNMP_Transport *snmp, void *arg)
7aad6641
VK
3144{
3145 bool convert = false;
3146 TCHAR buffer[256];
3147 ((StringList *)arg)->add(varbind->getValueAsPrintableString(buffer, 256, &convert));
3148 return SNMP_ERR_SUCCESS;
3149}
3150
3151/**
3152 * Get list of values from SNMP
3153 */
967893bb 3154UINT32 Node::getListFromSNMP(WORD port, const TCHAR *oid, StringList **list)
7aad6641
VK
3155{
3156 *list = NULL;
3157 SNMP_Transport *snmp = createSnmpTransport(port);
3158 if (snmp == NULL)
3159 return DCE_COMM_ERROR;
3160
3161 *list = new StringList;
967893bb 3162 UINT32 rc = SnmpWalk(snmp->getSnmpVersion(), snmp, oid, SNMPGetListCallback, *list, FALSE);
7aad6641
VK
3163 delete snmp;
3164 if (rc != SNMP_ERR_SUCCESS)
3165 {
3166 delete *list;
3167 *list = NULL;
3168 }
3169 return (rc == SNMP_ERR_SUCCESS) ? DCE_SUCCESS : ((rc == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3170}
3171
3172/**
3173 * Information for SNMPOIDSuffixListCallback
3174 */
3175struct SNMPOIDSuffixListCallback_Data
3176{
967893bb 3177 UINT32 oidLen;
7aad6641
VK
3178 StringList *values;
3179};
3180
3181/**
46b7166d 3182 * Callback for SnmpWalk in Node::getOIDSuffixListFromSNMP
7aad6641 3183 */
967893bb 3184static UINT32 SNMPOIDSuffixListCallback(UINT32 snmpVersion, SNMP_Variable *varbind, SNMP_Transport *snmp, void *arg)
7aad6641
VK
3185{
3186 SNMPOIDSuffixListCallback_Data *data = (SNMPOIDSuffixListCallback_Data *)arg;
3187 SNMP_ObjectId *oid = varbind->GetName();
3188 if (oid->getLength() <= data->oidLen)
3189 return SNMP_ERR_SUCCESS;
3190 TCHAR buffer[256];
3191 SNMPConvertOIDToText(oid->getLength() - data->oidLen, &(oid->getValue()[data->oidLen]), buffer, 256);
3192 data->values->add((buffer[0] == _T('.')) ? &buffer[1] : buffer);
3193 return SNMP_ERR_SUCCESS;
3194}
3195
3196/**
3197 * Get list of OID suffixes from SNMP
3198 */
967893bb 3199UINT32 Node::getOIDSuffixListFromSNMP(WORD port, const TCHAR *oid, StringList **list)
7aad6641
VK
3200{
3201 *list = NULL;
3202 SNMP_Transport *snmp = createSnmpTransport(port);
3203 if (snmp == NULL)
3204 return DCE_COMM_ERROR;
3205
3206 SNMPOIDSuffixListCallback_Data data;
967893bb 3207 UINT32 oidBin[256];
7aad6641
VK
3208 data.oidLen = SNMPParseOID(oid, oidBin, 256);
3209 if (data.oidLen == 0)
3210 {
3211 delete snmp;
3212 return DCE_NOT_SUPPORTED;
3213 }
3214
3215 data.values = new StringList;
967893bb 3216 UINT32 rc = SnmpWalk(snmp->getSnmpVersion(), snmp, oid, SNMPOIDSuffixListCallback, &data, FALSE);
7aad6641
VK
3217 delete snmp;
3218 if (rc == SNMP_ERR_SUCCESS)
3219 {
3220 *list = data.values;
3221 }
3222 else
3223 {
3224 delete data.values;
3225 }
3226 return (rc == SNMP_ERR_SUCCESS) ? DCE_SUCCESS : ((rc == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3227}
3228
3229/**
6fd6de0a
VK
3230 * Get item's value via SNMP from CheckPoint's agent
3231 */
967893bb 3232UINT32 Node::getItemFromCheckPointSNMP(const TCHAR *szParam, UINT32 dwBufSize, TCHAR *szBuffer)
5039dede 3233{
967893bb 3234 UINT32 dwResult;
5039dede
AK
3235
3236 if ((m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE) ||
3237 (m_dwDynamicFlags & NDF_UNREACHABLE))
3238 {
3239 dwResult = SNMP_ERR_COMM;
3240 }
3241 else
3242 {
3243 SNMP_Transport *pTransport;
3244
3245 pTransport = new SNMP_UDPTransport;
c4366266 3246 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
d525c9ed 3247 dwResult = SnmpGet(SNMP_VERSION_1, pTransport, szParam, NULL, 0, szBuffer, dwBufSize * sizeof(TCHAR), SG_STRING_RESULT);
5039dede
AK
3248 delete pTransport;
3249 }
35f836fe 3250 DbgPrintf(7, _T("Node(%s)->GetItemFromCheckPointSNMP(%s): dwResult=%d"), m_szName, szParam, dwResult);
4d2c3a54 3251 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
5039dede
AK
3252 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3253}
3254
6fd6de0a
VK
3255/**
3256 * Get item's value via native agent
3257 */
967893bb 3258UINT32 Node::getItemFromAgent(const TCHAR *szParam, UINT32 dwBufSize, TCHAR *szBuffer)
5039dede 3259{
967893bb
VK
3260 UINT32 dwError = ERR_NOT_CONNECTED, dwResult = DCE_COMM_ERROR;
3261 UINT32 dwTries = 3;
5039dede
AK
3262
3263 if ((m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
2fd7144f
VK
3264 (m_dwDynamicFlags & NDF_UNREACHABLE) ||
3265 (m_dwFlags & NF_DISABLE_NXCP) ||
3266 !(m_dwFlags & NF_IS_NATIVE_AGENT))
5039dede
AK
3267 return DCE_COMM_ERROR;
3268
7c521895 3269 agentLock();
5039dede
AK
3270
3271 // Establish connection if needed
3272 if (m_pAgentConnection == NULL)
7c521895 3273 if (!connectToAgent())
5039dede
AK
3274 goto end_loop;
3275
3276 // Get parameter from agent
3277 while(dwTries-- > 0)
3278 {
4687826e 3279 dwError = m_pAgentConnection->getParameter(szParam, dwBufSize, szBuffer);
5039dede
AK
3280 switch(dwError)
3281 {
3282 case ERR_SUCCESS:
3283 dwResult = DCE_SUCCESS;
3284 goto end_loop;
3285 case ERR_UNKNOWN_PARAMETER:
3286 dwResult = DCE_NOT_SUPPORTED;
3287 goto end_loop;
3288 case ERR_NOT_CONNECTED:
3289 case ERR_CONNECTION_BROKEN:
7c521895 3290 if (!connectToAgent())
5039dede
AK
3291 goto end_loop;
3292 break;
3293 case ERR_REQUEST_TIMEOUT:
3294 // Reset connection to agent after timeout
3295 DbgPrintf(7, _T("Node(%s)->GetItemFromAgent(%s): timeout; resetting connection to agent..."), m_szName, szParam);
3296 delete_and_null(m_pAgentConnection);
7c521895 3297 if (!connectToAgent())
5039dede
AK
3298 goto end_loop;
3299 DbgPrintf(7, _T("Node(%s)->GetItemFromAgent(%s): connection to agent restored successfully"), m_szName, szParam);
3300 break;
3301 }
3302 }