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