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