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