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