new NXSL function inList
[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();
803d47be 1059 if (pTransport == NULL)
35f836fe 1060 DbgPrintf(6, _T("StatusPoll(%s): cannot create SNMP transport"), m_szName);
803d47be 1061
35f836fe 1062 SetPollerInfo(nPoller, _T("check SNMP"));
21c9acce 1063 sendPollerMsg(dwRqId, _T("Checking SNMP agent connectivity\r\n"));
d525c9ed 1064 dwResult = SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.1.2.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0);
5039dede
AK
1065 if ((dwResult == SNMP_ERR_SUCCESS) || (dwResult == SNMP_ERR_NO_OBJECT))
1066 {
1067 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
1068 {
1069 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1070 PostEventEx(pQueue, EVENT_SNMP_OK, m_dwId, NULL);
21c9acce 1071 sendPollerMsg(dwRqId, POLLER_INFO _T("Connectivity with SNMP agent restored\r\n"));
5039dede
AK
1072 }
1073 }
1074 else
1075 {
21c9acce 1076 sendPollerMsg(dwRqId, POLLER_ERROR _T("SNMP agent unreachable\r\n"));
5039dede
AK
1077 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
1078 {
8573e935 1079 if ((tNow > m_failTimeSNMP + tExpire) &&
5039dede
AK
1080 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
1081 {
1082 m_dwFlags &= ~NF_IS_SNMP;
1083 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1084 m_szObjectId[0] = 0;
21c9acce 1085 sendPollerMsg(dwRqId, POLLER_WARNING _T("Attribute isSNMP set to FALSE\r\n"));
5039dede
AK
1086 }
1087 }
1088 else
1089 {
1090 m_dwDynamicFlags |= NDF_SNMP_UNREACHABLE;
1091 PostEventEx(pQueue, EVENT_SNMP_FAIL, m_dwId, NULL);
8573e935 1092 m_failTimeSNMP = tNow;
5039dede
AK
1093 }
1094 }
1095 delete pTransport;
35f836fe 1096 DbgPrintf(6, _T("StatusPoll(%s): SNMP check finished"), m_szName);
5039dede
AK
1097 }
1098
1099 // Check native agent connectivity
15d6f8c9 1100 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)) && (m_dwIpAddr != 0))
5039dede 1101 {
35f836fe
VK
1102 DbgPrintf(6, _T("StatusPoll(%s): checking agent"), m_szName);
1103 SetPollerInfo(nPoller, _T("check agent"));
21c9acce 1104 sendPollerMsg(dwRqId, _T("Checking NetXMS agent connectivity\r\n"));
c3acd0f6 1105
967893bb 1106 UINT32 error, socketError;
a4569c4d
VK
1107 agentLock();
1108 if (connectToAgent(&error, &socketError))
5039dede 1109 {
35f836fe 1110 DbgPrintf(7, _T("StatusPoll(%s): connected to agent"), m_szName);
5039dede
AK
1111 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1112 {
1113 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1114 PostEventEx(pQueue, EVENT_AGENT_OK, m_dwId, NULL);
21c9acce 1115 sendPollerMsg(dwRqId, POLLER_INFO _T("Connectivity with NetXMS agent restored\r\n"));
5039dede 1116 }
5039dede
AK
1117 }
1118 else
1119 {
35f836fe 1120 DbgPrintf(6, _T("StatusPoll(%s): agent unreachable, error=%d, socketError=%d"), m_szName, (int)error, (int)socketError);
21c9acce 1121 sendPollerMsg(dwRqId, POLLER_ERROR _T("NetXMS agent unreachable\r\n"));
5039dede
AK
1122 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1123 {
71e4ed3a 1124 if ((tNow > m_failTimeAgent + tExpire) && !(m_dwDynamicFlags & NDF_UNREACHABLE))
5039dede
AK
1125 {
1126 m_dwFlags &= ~NF_IS_NATIVE_AGENT;
1127 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1128 m_szPlatformName[0] = 0;
1129 m_szAgentVersion[0] = 0;
21c9acce 1130 sendPollerMsg(dwRqId, POLLER_WARNING _T("Attribute isNetXMSAgent set to FALSE\r\n"));
5039dede
AK
1131 }
1132 }
1133 else
1134 {
1135 m_dwDynamicFlags |= NDF_AGENT_UNREACHABLE;
1136 PostEventEx(pQueue, EVENT_AGENT_FAIL, m_dwId, NULL);
8573e935 1137 m_failTimeAgent = tNow;
0ab347c0 1138 //cancel file monitoring locally(on agent it is canceled if agent have fallen)
76b4edb5 1139 g_monitoringList.removeDisconectedNode(m_dwId);
5039dede
AK
1140 }
1141 }
a4569c4d 1142 agentUnlock();
35f836fe 1143 DbgPrintf(7, _T("StatusPoll(%s): agent check finished"), m_szName);
5039dede
AK
1144 }
1145
35f836fe 1146 SetPollerInfo(nPoller, _T("prepare polling list"));
5039dede
AK
1147
1148 // Find service poller node object
1149 LockData();
1150 if (m_dwPollerNode != 0)
1151 {
967893bb 1152 UINT32 id = m_dwPollerNode;
f3218755
VK
1153 UnlockData();
1154 pPollerNode = FindObjectById(id);
5039dede
AK
1155 if (pPollerNode != NULL)
1156 {
1157 if (pPollerNode->Type() != OBJECT_NODE)
1158 pPollerNode = NULL;
1159 }
1160 }
f3218755
VK
1161 else
1162 {
1163 UnlockData();
1164 }
5039dede
AK
1165
1166 // If nothing found, use management server
1167 if (pPollerNode == NULL)
1168 {
1169 pPollerNode = FindObjectById(g_dwMgmtNode);
1170 if (pPollerNode != NULL)
21c9acce 1171 pPollerNode->incRefCount();
5039dede
AK
1172 }
1173 else
1174 {
21c9acce 1175 pPollerNode->incRefCount();
5039dede
AK
1176 }
1177
1178 // Create polling list
1179 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_dwChildCount);
1180 LockChildList(FALSE);
1181 for(i = 0, dwPollListSize = 0; i < m_dwChildCount; i++)
1182 if (m_pChildList[i]->Status() != STATUS_UNMANAGED)
1183 {
21c9acce 1184 m_pChildList[i]->incRefCount();
5039dede
AK
1185 ppPollList[dwPollListSize++] = m_pChildList[i];
1186 }
1187 UnlockChildList();
1188
1189 // Poll interfaces and services
35f836fe
VK
1190 SetPollerInfo(nPoller, _T("child poll"));
1191 DbgPrintf(7, _T("StatusPoll(%s): starting child object poll"), m_szName);
7c521895 1192 pCluster = getMyCluster();
cd9f247e 1193 pTransport = createSnmpTransport();
5039dede
AK
1194 for(i = 0; i < dwPollListSize; i++)
1195 {
1196 switch(ppPollList[i]->Type())
1197 {
1198 case OBJECT_INTERFACE:
35f836fe 1199 DbgPrintf(7, _T("StatusPoll(%s): polling interface %d [%s]"), m_szName, ppPollList[i]->Id(), ppPollList[i]->Name());
c59466d2 1200 ((Interface *)ppPollList[i])->statusPoll(pSession, dwRqId, pQueue,
58b3e451 1201 (pCluster != NULL) ? pCluster->isSyncAddr(((Interface *)ppPollList[i])->IpAddr()) : FALSE,
5039dede
AK
1202 pTransport);
1203 break;
1204 case OBJECT_NETWORKSERVICE:
35f836fe 1205 DbgPrintf(7, _T("StatusPoll(%s): polling network service %d [%s]"), m_szName, ppPollList[i]->Id(), ppPollList[i]->Name());
c59466d2 1206 ((NetworkService *)ppPollList[i])->statusPoll(pSession, dwRqId,
5039dede
AK
1207 (Node *)pPollerNode, pQueue);
1208 break;
1209 default:
1210 break;
1211 }
21c9acce 1212 ppPollList[i]->decRefCount();
5039dede
AK
1213 }
1214 delete pTransport;
1215 safe_free(ppPollList);
35f836fe 1216 DbgPrintf(7, _T("StatusPoll(%s): finished child object poll"), m_szName);
5039dede
AK
1217
1218 // Check if entire node is down
15d6f8c9
VK
1219 // This check is disabled for nodes without IP address
1220 if (m_dwIpAddr != 0)
5039dede 1221 {
15d6f8c9
VK
1222 LockChildList(FALSE);
1223 if (m_dwChildCount > 0)
1224 {
1225 for(i = 0, bAllDown = TRUE; i < m_dwChildCount; i++)
1226 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1227 (m_pChildList[i]->Status() != STATUS_CRITICAL) &&
1228 (m_pChildList[i]->Status() != STATUS_UNKNOWN) &&
1229 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
1230 (m_pChildList[i]->Status() != STATUS_DISABLED))
1231 {
1232 bAllDown = FALSE;
1233 break;
1234 }
1235 }
1236 else
1237 {
1238 bAllDown = FALSE;
1239 }
1240 UnlockChildList();
1241 if (bAllDown && (m_dwFlags & NF_IS_NATIVE_AGENT) &&
1242 (!(m_dwFlags & NF_DISABLE_NXCP)))
1243 if (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))
1244 bAllDown = FALSE;
1245 if (bAllDown && (m_dwFlags & NF_IS_SNMP) &&
1246 (!(m_dwFlags & NF_DISABLE_SNMP)))
1247 if (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))
1248 bAllDown = FALSE;
c1482463
VK
1249
1250 DbgPrintf(6, _T("StatusPoll(%s): bAllDown=%s, dynFlags=0x%08X"), m_szName, bAllDown ? _T("true") : _T("false"), m_dwDynamicFlags);
15d6f8c9
VK
1251 if (bAllDown)
1252 {
1253 if (!(m_dwDynamicFlags & NDF_UNREACHABLE))
1254 {
1255 m_dwDynamicFlags |= NDF_UNREACHABLE;
8573e935 1256 m_downSince = time(NULL);
7946bd7c 1257 SetPollerInfo(nPoller, _T("check network path"));
c1482463
VK
1258 if (checkNetworkPath(dwRqId))
1259 {
1260 m_dwDynamicFlags |= NDF_NETWORK_PATH_PROBLEM;
1261
1262 // Set interfaces and network services to UNKNOWN state
1263 LockChildList(FALSE);
1264 for(i = 0, bAllDown = TRUE; i < m_dwChildCount; i++)
1265 if (((m_pChildList[i]->Type() == OBJECT_INTERFACE) || (m_pChildList[i]->Type() == OBJECT_NETWORKSERVICE)) &&
1266 (m_pChildList[i]->Status() == STATUS_CRITICAL))
1267 {
1268 m_pChildList[i]->resetStatus();
1269 }
1270 UnlockChildList();
1271
1272 // Clear delayed event queue
1273 while(1)
1274 {
1275 Event *pEvent = (Event *)pQueue->Get();
1276 if (pEvent == NULL)
1277 break;
1278 delete pEvent;
1279 }
1280 delete_and_null(pQueue);
1281
1282 PostEvent(EVENT_NODE_UNREACHABLE, m_dwId, NULL);
1283 }
1284 else
1285 {
1286 PostEvent(EVENT_NODE_DOWN, m_dwId, NULL);
1287 }
21c9acce 1288 sendPollerMsg(dwRqId, POLLER_ERROR _T("Node is unreachable\r\n"));
15d6f8c9
VK
1289 }
1290 else
1291 {
21c9acce 1292 sendPollerMsg(dwRqId, POLLER_WARNING _T("Node is still unreachable\r\n"));
15d6f8c9
VK
1293 }
1294 }
1295 else
1296 {
8573e935 1297 m_downSince = 0;
15d6f8c9
VK
1298 if (m_dwDynamicFlags & NDF_UNREACHABLE)
1299 {
c1482463 1300 m_dwDynamicFlags &= ~(NDF_UNREACHABLE | NDF_SNMP_UNREACHABLE | NDF_AGENT_UNREACHABLE | NDF_NETWORK_PATH_PROBLEM);
15d6f8c9 1301 PostEvent(EVENT_NODE_UP, m_dwId, NULL);
21c9acce 1302 sendPollerMsg(dwRqId, POLLER_INFO _T("Node recovered from unreachable state\r\n"));
15d6f8c9
VK
1303 goto restart_agent_check;
1304 }
1305 else
1306 {
21c9acce 1307 sendPollerMsg(dwRqId, POLLER_INFO _T("Node is connected\r\n"));
15d6f8c9
VK
1308 }
1309 }
5039dede 1310 }
5039dede 1311
0ab347c0 1312
71e4ed3a
VK
1313 // Get uptime and update boot time
1314 if (!(m_dwDynamicFlags & NDF_UNREACHABLE))
1315 {
1316 TCHAR buffer[MAX_RESULT_LENGTH];
1317 if (getItemFromAgent(_T("System.Uptime"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1318 {
1319 m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0);
05c9a2f9 1320 DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from agent"), m_szName, m_dwId, (UINT32)m_bootTime);
71e4ed3a
VK
1321 }
1322 else if (getItemFromSNMP(m_wSNMPPort, _T(".1.3.6.1.2.1.1.3.0"), MAX_RESULT_LENGTH, buffer, SNMP_RAWTYPE_NONE) == DCE_SUCCESS)
1323 {
1324 m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0) / 100; // sysUpTime is in hundredths of a second
05c9a2f9 1325 DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from SNMP"), m_szName, m_dwId, (UINT32)m_bootTime);
71e4ed3a
VK
1326 }
1327 else
1328 {
1329 DbgPrintf(5, _T("StatusPoll(%s [%d]): unable to get system uptime"), m_szName, m_dwId);
1330 }
1331 }
1332 else
1333 {
1334 m_bootTime = 0;
1335 }
1336
0ab347c0 1337 // Get agent uptime to check if it was restared
1338 if (!(m_dwDynamicFlags & NDF_UNREACHABLE))
1339 {
1340 TCHAR buffer[MAX_RESULT_LENGTH];
1341 if (getItemFromAgent(_T("Agent.Uptime"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1342 {
1343 time_t oldAgentuptime = m_agentUpTime;
1344 m_agentUpTime = _tcstol(buffer, NULL, 0);
1345 if((UINT32)oldAgentuptime > (UINT32)m_agentUpTime)
1346 {
1347 //cancel file monitoring locally(on agent it is canceled if agent have fallen)
1348 g_monitoringList.removeDisconectedNode(m_dwId);
1349 }
1350 }
1351 else
1352 {
1353 DbgPrintf(5, _T("StatusPoll(%s [%d]): unable to get agent uptime"), m_szName, m_dwId);
1354 g_monitoringList.removeDisconectedNode(m_dwId);
1355 m_agentUpTime = 0;
1356 }
1357 }
1358 else
1359 {
1360 g_monitoringList.removeDisconectedNode(m_dwId);
1361 m_agentUpTime = 0;
1362 }
1363
5039dede 1364 // Send delayed events and destroy delayed event queue
c1482463
VK
1365 if (pQueue != NULL)
1366 {
1367 ResendEvents(pQueue);
1368 delete pQueue;
1369 }
a5ee7b3b
VK
1370
1371 // Call hooks in loaded modules
967893bb 1372 for(UINT32 i = 0; i < g_dwNumModules; i++)
a5ee7b3b
VK
1373 {
1374 if (g_pModuleList[i].pfStatusPollHook != NULL)
1375 {
1376 DbgPrintf(5, _T("StatusPoll(%s [%d]): calling hook in module %s"), m_szName, m_dwId, g_pModuleList[i].szName);
1377 g_pModuleList[i].pfStatusPollHook(this, pSession, dwRqId, nPoller);
1378 }
1379 }
4d2c3a54 1380
a5ee7b3b
VK
1381 // Execute hook script
1382 SetPollerInfo(nPoller, _T("hook"));
1383 executeHookScript(_T("StatusPoll"));
1384
35f836fe 1385 SetPollerInfo(nPoller, _T("cleanup"));
5039dede 1386 if (pPollerNode != NULL)
21c9acce 1387 pPollerNode->decRefCount();
5039dede
AK
1388
1389 if (dwOldFlags != m_dwFlags)
1390 {
1391 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
1392 LockData();
1393 Modify();
1394 UnlockData();
1395 }
1396
27f9598d 1397 calculateCompoundStatus();
8573e935 1398 m_lastStatusPoll = time(NULL);
21c9acce
VK
1399 sendPollerMsg(dwRqId, _T("Finished status poll for node %s\r\n"), m_szName);
1400 sendPollerMsg(dwRqId, _T("Node status after poll is %s\r\n"), g_szStatusText[m_iStatus]);
c59466d2 1401 m_pollRequestor = NULL;
5039dede
AK
1402 if (dwRqId == 0)
1403 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_STATUS_POLL;
7c521895 1404 pollerUnlock();
35f836fe 1405 DbgPrintf(5, _T("Finished status poll for node %s (ID: %d)"), m_szName, m_dwId);
5039dede
AK
1406}
1407
7946bd7c 1408/**
beae365a
VK
1409 * Check single elementof network path
1410 */
967893bb 1411bool Node::checkNetworkPathElement(UINT32 nodeId, const TCHAR *nodeType, bool isProxy, UINT32 dwRqId)
beae365a
VK
1412{
1413 Node *node = (Node *)FindObjectById(nodeId, OBJECT_NODE);
1414 if (node == NULL)
1415 return false;
1416
1417 DbgPrintf(6, _T("Node::checkNetworkPathElement(%s [%d]): found %s: %s [%d]"), m_szName, m_dwId, nodeType, node->Name(), node->Id());
1418 if (node->isDown())
1419 {
1420 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): %s %s [%d] is down"),
1421 m_szName, m_dwId, nodeType, node->Name(), node->Id());
1422 sendPollerMsg(dwRqId, POLLER_WARNING _T(" %s %s is down\r\n"), nodeType, node->Name());
1423 return true;
1424 }
66d15dff
VK
1425 if (isProxy && node->isNativeAgent() && (node->getRuntimeFlags() & NDF_AGENT_UNREACHABLE))
1426 {
1427 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): agent on %s %s [%d] is down"),
1428 m_szName, m_dwId, nodeType, node->Name(), node->Id());
1429 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Agent on %s %s is down\r\n"), nodeType, node->Name());
1430 return true;
1431 }
8573e935 1432 if (node->m_lastStatusPoll < time(NULL) - 1)
beae365a
VK
1433 {
1434 DbgPrintf(6, _T("Node::checkNetworkPathElement(%s [%d]): forced status poll on node %s [%d]"),
1435 m_szName, m_dwId, node->Name(), node->Id());
1436 node->statusPoll(NULL, 0, 0);
1437 if (node->isDown())
1438 {
1439 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): %s %s [%d] is down"),
1440 m_szName, m_dwId, nodeType, node->Name(), node->Id());
1441 sendPollerMsg(dwRqId, POLLER_WARNING _T(" %s %s is down\r\n"), nodeType, node->Name());
1442 return true;
1443 }
66d15dff
VK
1444 if (isProxy && node->isNativeAgent() && (node->getRuntimeFlags() & NDF_AGENT_UNREACHABLE))
1445 {
1446 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): agent on %s %s [%d] is down"),
1447 m_szName, m_dwId, nodeType, node->Name(), node->Id());
1448 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Agent on %s %s is down\r\n"), nodeType, node->Name());
1449 return true;
1450 }
beae365a
VK
1451 }
1452 return false;
1453}
1454
1455/**
7946bd7c 1456 * Check network path between node and management server to detect possible intermediate node failure
c1482463
VK
1457 *
1458 * @return true if network path problems found
7946bd7c 1459 */
967893bb 1460bool Node::checkNetworkPath(UINT32 dwRqId)
7946bd7c 1461{
67c45b4d
VK
1462 time_t now = time(NULL);
1463
beae365a
VK
1464 // Check proxy node(s)
1465 if (IsZoningEnabled() && (m_zoneId != 0))
1466 {
1467 Zone *zone = (Zone *)g_idxZoneByGUID.get(m_zoneId);
1468 if ((zone != NULL) && ((zone->getAgentProxy() != 0) || (zone->getSnmpProxy() != 0) || (zone->getIcmpProxy() != 0)))
1469 {
1470 bool allProxyDown = true;
1471 if (zone->getIcmpProxy() != 0)
66d15dff 1472 allProxyDown = checkNetworkPathElement(zone->getIcmpProxy(), _T("ICMP proxy"), true, dwRqId);
beae365a 1473 if (allProxyDown && (zone->getSnmpProxy() != 0) && (zone->getSnmpProxy() != zone->getIcmpProxy()))
66d15dff 1474 allProxyDown = checkNetworkPathElement(zone->getSnmpProxy(), _T("SNMP proxy"), true, dwRqId);
beae365a 1475 if (allProxyDown && (zone->getAgentProxy() != 0) && (zone->getAgentProxy() != zone->getIcmpProxy()) && (zone->getAgentProxy() != zone->getSnmpProxy()))
66d15dff 1476 allProxyDown = checkNetworkPathElement(zone->getAgentProxy(), _T("agent proxy"), true, dwRqId);
beae365a
VK
1477 if (allProxyDown)
1478 return true;
1479 }
1480 }
1481
67c45b4d
VK
1482 // Check directly connected switch
1483 sendPollerMsg(dwRqId, _T("Checking ethernet connectivity...\r\n"));
664b42a4
VK
1484 Interface *iface = findInterface(INVALID_INDEX, m_dwIpAddr);
1485 if ((iface != NULL) && (iface->getPeerNodeId() != 0))
67c45b4d 1486 {
664b42a4 1487 DbgPrintf(6, _T("Node::checkNetworkPath(%s [%d]): found interface object for primary IP: %s [%d]"), m_szName, m_dwId, iface->Name(), iface->Id());
66d15dff 1488 if (checkNetworkPathElement(iface->getPeerNodeId(), _T("upstream switch"), false, dwRqId))
beae365a 1489 return true;
67c45b4d 1490 }
664b42a4
VK
1491 else
1492 {
1493 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): cannot find interface object for primary IP"), m_szName, m_dwId);
1494 }
67c45b4d 1495
7946bd7c
VK
1496 Node *mgmtNode = (Node *)FindObjectById(g_dwMgmtNode);
1497 if (mgmtNode == NULL)
1498 {
1499 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): cannot find management node"), m_szName, m_dwId);
c1482463 1500 return false;
7946bd7c 1501 }
5039dede 1502
7946bd7c
VK
1503 NetworkPath *trace = TraceRoute(mgmtNode, this);
1504 if (trace == NULL)
1505 {
1506 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): trace not available"), m_szName, m_dwId);
c1482463 1507 return false;
7946bd7c
VK
1508 }
1509 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): trace available, %d hops, %s"),
1510 m_szName, m_dwId, trace->getHopCount(), trace->isComplete() ? _T("complete") : _T("incomplete"));
1511
1512 // We will do path check in two passes
1513 // If unreachable intermediate node will be found on first pass,
1514 // then method will just return true. Otherwise, we will do
1515 // second pass, this time forcing status poll on each node in the path.
21c9acce 1516 sendPollerMsg(dwRqId, _T("Checking network path...\r\n"));
7946bd7c
VK
1517 bool secondPass = false;
1518 bool pathProblemFound = false;
1519restart:
1520 for(int i = 0; i < trace->getHopCount(); i++)
1521 {
1522 HOP_INFO *hop = trace->getHopInfo(i);
1523 if ((hop->object == NULL) || (hop->object == this) || (hop->object->Type() != OBJECT_NODE))
1524 continue;
1525
1526 DbgPrintf(6, _T("Node::checkNetworkPath(%s [%d]): checking upstream node %s [%d]"),
1527 m_szName, m_dwId, hop->object->Name(), hop->object->Id());
8573e935 1528 if (secondPass && !((Node *)hop->object)->isDown() && (((Node *)hop->object)->m_lastStatusPoll < now - 1))
7946bd7c
VK
1529 {
1530 DbgPrintf(6, _T("Node::checkNetworkPath(%s [%d]): forced status poll on node %s [%d]"),
1531 m_szName, m_dwId, hop->object->Name(), hop->object->Id());
1532 ((Node *)hop->object)->statusPoll(NULL, 0, 0);
1533 }
1f385e47 1534
7946bd7c
VK
1535 if (((Node *)hop->object)->isDown())
1536 {
1537 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): upstream node %s [%d] is down"),
1538 m_szName, m_dwId, hop->object->Name(), hop->object->Id());
21c9acce 1539 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Upstream node %s is down\r\n"), hop->object->Name());
7946bd7c
VK
1540 pathProblemFound = true;
1541 break;
1542 }
1543 }
1544 if (!secondPass && !pathProblemFound)
1545 {
1546 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): will do second pass"), m_szName, m_dwId);
1547 secondPass = true;
1548 goto restart;
1549 }
1550 delete trace;
c1482463 1551 return pathProblemFound;
7946bd7c
VK
1552}
1553
1554/**
1555 * Check agent policy binding
1556 * Intended to be called only from configuration poller
1557 */
1f385e47
VK
1558void Node::checkAgentPolicyBinding(AgentConnection *conn)
1559{
1560 AgentPolicyInfo *ap;
967893bb 1561 UINT32 rcc = conn->getPolicyInventory(&ap);
1f385e47
VK
1562 if (rcc == ERR_SUCCESS)
1563 {
1564 // Check for unbound but installed policies
1565 for(int i = 0; i < ap->getSize(); i++)
1566 {
1567 uuid_t guid;
1568 ap->getGuid(i, guid);
1569 NetObj *object = FindObjectByGUID(guid, -1);
21c9acce 1570 if ((object != NULL) && (!object->isChild(m_dwId)))
1f385e47
VK
1571 {
1572 object->AddChild(this);
1573 AddParent(object);
1574 DbgPrintf(5, _T("ConfPoll(%s): bound to policy object %s [%d]"), m_szName, object->Name(), object->Id());
1575 }
1576 }
1577
1578 // Check for bound but not installed policies
1579 LockParentList(FALSE);
1580 NetObj **unbindList = (NetObj **)malloc(sizeof(NetObj *) * m_dwParentCount);
1581 int unbindListSize = 0;
967893bb 1582 for(UINT32 i = 0; i < m_dwParentCount; i++)
1f385e47
VK
1583 {
1584 if (IsAgentPolicyObject(m_pParentList[i]))
1585 {
1586 uuid_t guid1, guid2;
1587 int j;
1588
1589 m_pParentList[i]->getGuid(guid1);
1590 for(j = 0; j < ap->getSize(); j++)
1591 {
1592 ap->getGuid(j, guid2);
1593 if (!uuid_compare(guid1, guid2))
1594 break;
1595 }
1596 if (j == ap->getSize())
1597 unbindList[unbindListSize++] = m_pParentList[i];
1598 }
1599 }
1600 UnlockParentList();
1601
1602 for(int i = 0; i < unbindListSize; i++)
1603 {
1604 unbindList[i]->DeleteChild(this);
1605 DeleteParent(unbindList[i]);
1606 DbgPrintf(5, _T("ConfPoll(%s): unbound from policy object %s [%d]"), m_szName, unbindList[i]->Name(), unbindList[i]->Id());
1607 }
1608 safe_free(unbindList);
1609
1610 delete ap;
1611 }
1612 else
1613 {
1614 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getPolicyInventory() failed: rcc=%d"), m_szName, rcc);
1615 }
1616}
1617
a3050773
VK
1618/**
1619 * Update primary IP address from primary name
1620 */
5a7d6a10
VK
1621void Node::updatePrimaryIpAddr()
1622{
1623 if (m_primaryName[0] == 0)
1624 return;
1625
967893bb 1626 UINT32 ipAddr = ntohl(ResolveHostName(m_primaryName));
5a7d6a10
VK
1627 if ((ipAddr != m_dwIpAddr) && (ipAddr != INADDR_ANY) && (ipAddr != INADDR_NONE))
1628 {
1629 TCHAR buffer1[32], buffer2[32];
1630
4d2c3a54 1631 DbgPrintf(4, _T("IP address for node %s [%d] changed from %s to %s"),
5a7d6a10
VK
1632 m_szName, (int)m_dwId, IpToStr(m_dwIpAddr, buffer1), IpToStr(ipAddr, buffer2));
1633 PostEvent(EVENT_IP_ADDRESS_CHANGED, m_dwId, "aa", ipAddr, m_dwIpAddr);
2467ed57
VK
1634
1635
1636 setPrimaryIPAddress(ipAddr);
a3050773
VK
1637
1638 agentLock();
1639 delete_and_null(m_pAgentConnection);
1640 agentUnlock();
5a7d6a10
VK
1641 }
1642}
1643
76720a09
VK
1644/**
1645 * Perform configuration poll on node
1646 */
967893bb 1647void Node::configurationPoll(ClientSession *pSession, UINT32 dwRqId, int nPoller, UINT32 dwNetMask)
5039dede 1648{
46117060
VK
1649 if (m_dwDynamicFlags & NDF_DELETE_IN_PROGRESS)
1650 {
1651 if (dwRqId == 0)
1652 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1653 return;
1654 }
1655
967893bb 1656 UINT32 dwOldFlags = m_dwFlags;
35f836fe 1657 TCHAR szBuffer[4096];
5039dede 1658 SNMP_Transport *pTransport;
76720a09 1659 bool hasChanges = false;
5039dede 1660
35f836fe 1661 SetPollerInfo(nPoller, _T("wait for lock"));
7c521895 1662 pollerLock();
c59466d2 1663 m_pollRequestor = pSession;
21c9acce 1664 sendPollerMsg(dwRqId, _T("Starting configuration poll for node %s\r\n"), m_szName);
35f836fe 1665 DbgPrintf(4, _T("Starting configuration poll for node %s (ID: %d)"), m_szName, m_dwId);
5039dede
AK
1666
1667 // Check for forced capabilities recheck
1668 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
1669 {
1670 m_dwFlags &= ~(NF_IS_NATIVE_AGENT | NF_IS_SNMP | NF_IS_CPSNMP |
0ecc2200 1671 NF_IS_BRIDGE | NF_IS_ROUTER | NF_IS_OSPF | NF_IS_PRINTER |
76720a09 1672 NF_IS_CDP | NF_IS_LLDP | NF_IS_SONMP | NF_IS_VRRP | NF_HAS_VLANS |
46ee6286
VK
1673 NF_IS_8021X | NF_IS_STP | NF_HAS_ENTITY_MIB | NF_HAS_IFXTABLE |
1674 NF_HAS_WINPDH);
e4a64da2 1675 m_dwDynamicFlags &= ~NDF_CONFIGURATION_POLL_PASSED;
5039dede
AK
1676 m_szObjectId[0] = 0;
1677 m_szPlatformName[0] = 0;
1678 m_szAgentVersion[0] = 0;
0ecc2200
VK
1679 safe_free_and_null(m_sysDescription);
1680 safe_free_and_null(m_sysName);
1681 safe_free_and_null(m_lldpNodeId);
5039dede
AK
1682 }
1683
1684 // Check if node is marked as unreachable
1685 if ((m_dwDynamicFlags & NDF_UNREACHABLE) && !(m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES))
1686 {
21c9acce 1687 sendPollerMsg(dwRqId, POLLER_WARNING _T("Node is marked as unreachable, configuration poll aborted\r\n"));
35f836fe 1688 DbgPrintf(4, _T("Node is marked as unreachable, configuration poll aborted"));
8573e935 1689 m_lastConfigurationPoll = time(NULL);
5039dede
AK
1690 }
1691 else
1692 {
5a7d6a10
VK
1693 updatePrimaryIpAddr();
1694
35f836fe 1695 SetPollerInfo(nPoller, _T("capability check"));
21c9acce 1696 sendPollerMsg(dwRqId, _T("Checking node's capabilities...\r\n"));
5039dede 1697
99058170
VK
1698 if (confPollAgent(dwRqId))
1699 hasChanges = true;
1700 if (confPollSnmp(dwRqId))
1701 hasChanges = true;
5039dede
AK
1702
1703 // Check for CheckPoint SNMP agent on port 260
9a1f7c45 1704 if (ConfigReadInt(_T("EnableCheckPointSNMP"), 0))
5039dede 1705 {
9a1f7c45
VK
1706 DbgPrintf(5, _T("ConfPoll(%s): checking for CheckPoint SNMP on port 260"), m_szName);
1707 if (!((m_dwFlags & NF_IS_CPSNMP) && (m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE)) && (m_dwIpAddr != 0))
5039dede 1708 {
9a1f7c45
VK
1709 pTransport = new SNMP_UDPTransport;
1710 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
1711 if (SnmpGet(SNMP_VERSION_1, pTransport,
1712 _T(".1.3.6.1.4.1.2620.1.1.10.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
1713 {
1714 LockData();
1715 m_dwFlags |= NF_IS_CPSNMP | NF_IS_ROUTER;
1716 m_dwDynamicFlags &= ~NDF_CPSNMP_UNREACHABLE;
1717 UnlockData();
1718 sendPollerMsg(dwRqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 260 is active\r\n"));
1719 }
1720 delete pTransport;
5039dede 1721 }
5039dede
AK
1722 }
1723
1724 // Generate event if node flags has been changed
1725 if (dwOldFlags != m_dwFlags)
1726 {
1727 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
76720a09 1728 hasChanges = true;
5039dede
AK
1729 }
1730
5039dede 1731 // Retrieve interface list
35f836fe 1732 SetPollerInfo(nPoller, _T("interface check"));
21c9acce 1733 sendPollerMsg(dwRqId, _T("Capability check finished\r\n"));
5039dede 1734
eec253a8 1735 if (updateInterfaceConfiguration(dwRqId, dwNetMask))
76720a09 1736 hasChanges = true;
5039dede 1737
8573e935 1738 m_lastConfigurationPoll = time(NULL);
5039dede
AK
1739
1740 // Check node name
21c9acce 1741 sendPollerMsg(dwRqId, _T("Checking node name\r\n"));
967893bb 1742 UINT32 dwAddr = ntohl(_t_inet_addr(m_szName));
5039dede 1743 if ((g_dwFlags & AF_RESOLVE_NODE_NAMES) &&
4d2c3a54 1744 (dwAddr != INADDR_NONE) &&
5039dede 1745 (dwAddr != INADDR_ANY) &&
58b3e451 1746 isMyIP(dwAddr))
5039dede 1747 {
21c9acce 1748 sendPollerMsg(dwRqId, _T("Node name is an IP address and need to be resolved\r\n"));
35f836fe 1749 SetPollerInfo(nPoller, _T("resolving name"));
024c3faf 1750 if (resolveName(FALSE))
5039dede 1751 {
21c9acce 1752 sendPollerMsg(dwRqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_szName);
76720a09 1753 hasChanges = true;
5039dede
AK
1754 }
1755 else
1756 {
21c9acce 1757 sendPollerMsg(dwRqId, POLLER_WARNING _T("Node name cannot be resolved\r\n"));
5039dede
AK
1758 }
1759 }
1760 else
1761 {
1762 if (g_dwFlags & AF_SYNC_NODE_NAMES_WITH_DNS)
1763 {
21c9acce 1764 sendPollerMsg(dwRqId, _T("Syncing node name with DNS\r\n"));
35f836fe 1765 SetPollerInfo(nPoller, _T("resolving name"));
024c3faf 1766 if (resolveName(TRUE))
5039dede 1767 {
21c9acce 1768 sendPollerMsg(dwRqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_szName);
76720a09 1769 hasChanges = true;
5039dede
AK
1770 }
1771 }
1772 else
1773 {
21c9acce 1774 sendPollerMsg(dwRqId, _T("Node name is OK\r\n"));
5039dede
AK
1775 }
1776 }
1777
6fd6de0a 1778 applyUserTemplates();
7c521895 1779 updateContainerMembership();
d51f2182 1780 doInstanceDiscovery();
4d0c32f3 1781
caa04e26
VK
1782 // Get list of installed products
1783 if (m_dwFlags & NF_IS_NATIVE_AGENT)
1784 {
1785 SetPollerInfo(nPoller, _T("software check"));
1786 sendPollerMsg(dwRqId, _T("Reading list of installed software packages\r\n"));
1787
1788 Table *table;
1789 if (getTableFromAgent(_T("System.InstalledProducts"), &table) == DCE_SUCCESS)
1790 {
1791 LockData();
1792 delete m_softwarePackages;
1793 m_softwarePackages = new ObjectArray<SoftwarePackage>(table->getNumRows(), 16, true);
1794 for(int i = 0; i < table->getNumRows(); i++)
1795 m_softwarePackages->add(new SoftwarePackage(table, i));
1796 UnlockData();
1797 delete table;
1798 sendPollerMsg(dwRqId, POLLER_INFO _T("Got information about %d installed software packages\r\n"), m_softwarePackages->size());
1799 }
1800 else
1801 {
1802 delete_and_null(m_softwarePackages);
1803 sendPollerMsg(dwRqId, POLLER_WARNING _T("Unable to get information about installed software packages\r\n"));
1804 }
1805 }
1806
21c9acce
VK
1807 sendPollerMsg(dwRqId, _T("Finished configuration poll for node %s\r\n"), m_szName);
1808 sendPollerMsg(dwRqId, _T("Node configuration was%schanged after poll\r\n"), hasChanges ? _T(" ") : _T(" not "));
e4a64da2 1809
a3050773 1810 // Call hooks in loaded modules
967893bb 1811 for(UINT32 i = 0; i < g_dwNumModules; i++)
a5ee7b3b 1812 {
a3050773
VK
1813 if (g_pModuleList[i].pfConfPollHook != NULL)
1814 {
1815 DbgPrintf(5, _T("ConfigurationPoll(%s [%d]): calling hook in module %s"), m_szName, m_dwId, g_pModuleList[i].szName);
1816 g_pModuleList[i].pfConfPollHook(this, pSession, dwRqId, nPoller);
1817 }
a5ee7b3b 1818 }
a5ee7b3b 1819
a3050773
VK
1820 // Execute hook script
1821 SetPollerInfo(nPoller, _T("hook"));
1822 executeHookScript(_T("ConfigurationPoll"));
1823
1824 m_dwDynamicFlags |= NDF_CONFIGURATION_POLL_PASSED;
1825 }
1824629a 1826
4d0c32f3 1827 // Finish configuration poll
35f836fe 1828 SetPollerInfo(nPoller, _T("cleanup"));
4d0c32f3
VK
1829 if (dwRqId == 0)
1830 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1831 m_dwDynamicFlags &= ~NDF_RECHECK_CAPABILITIES;
7c521895 1832 pollerUnlock();
35f836fe 1833 DbgPrintf(4, _T("Finished configuration poll for node %s (ID: %d)"), m_szName, m_dwId);
4d0c32f3 1834
76720a09 1835 if (hasChanges)
4d0c32f3
VK
1836 {
1837 LockData();
1838 Modify();
1839 UnlockData();
1840 }
1841}
1842
76720a09
VK
1843/**
1844 * Configuration poll: check for NetXMS agent
1845 */
967893bb 1846bool Node::confPollAgent(UINT32 dwRqId)
76720a09
VK
1847{
1848 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent Flags={%08X} DynamicFlags={%08X}"), m_szName, m_dwFlags, m_dwDynamicFlags);
1849 if (((m_dwFlags & NF_IS_NATIVE_AGENT) && (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)) ||
1850 (m_dwIpAddr == 0) || (m_dwFlags & NF_DISABLE_NXCP))
1851 return false;
1852
1853 bool hasChanges = false;
1854
21c9acce 1855 sendPollerMsg(dwRqId, _T(" Checking NetXMS agent...\r\n"));
af21affe 1856 AgentConnection *pAgentConn = new AgentConnectionEx(m_dwId, htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
76720a09
VK
1857 setAgentProxy(pAgentConn);
1858 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - connecting"), m_szName);
af21affe
VK
1859
1860 // Try to connect to agent
1861 UINT32 rcc;
1862 if (!pAgentConn->connect(g_pServerKey, FALSE, &rcc))
1863 {
1864 // If there are authentication problem, try default shared secret
1865 if ((rcc == ERR_AUTH_REQUIRED) || (rcc == ERR_AUTH_FAILED))
1866 {
1867 TCHAR secret[MAX_SECRET_LENGTH];
1868 ConfigReadStr(_T("AgentDefaultSharedSecret"), secret, MAX_SECRET_LENGTH, _T("netxms"));
1869 pAgentConn->setAuthData(AUTH_SHA1_HASH, secret);
1870 if (pAgentConn->connect(g_pServerKey, FALSE, &rcc))
1871 {
1872 m_wAuthMethod = AUTH_SHA1_HASH;
1873 nx_strncpy(m_szSharedSecret, secret, MAX_SECRET_LENGTH);
1874 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - shared secret changed to system default"), m_szName);
1875 }
1876 }
1877 }
1878
1879 if (rcc == ERR_SUCCESS)
76720a09
VK
1880 {
1881 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - connected"), m_szName);
1882 LockData();
1883 m_dwFlags |= NF_IS_NATIVE_AGENT;
1884 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1885 {
1886 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1887 PostEvent(EVENT_AGENT_OK, m_dwId, NULL);
21c9acce 1888 sendPollerMsg(dwRqId, POLLER_INFO _T(" Connectivity with NetXMS agent restored\r\n"));
76720a09
VK
1889 }
1890 else
1891 {
21c9acce 1892 sendPollerMsg(dwRqId, POLLER_INFO _T(" NetXMS native agent is active\r\n"));
76720a09
VK
1893 }
1894 UnlockData();
4d0c32f3 1895
76720a09
VK
1896 TCHAR buffer[MAX_RESULT_LENGTH];
1897 if (pAgentConn->getParameter(_T("Agent.Version"), MAX_AGENT_VERSION_LEN, buffer) == ERR_SUCCESS)
1898 {
1899 LockData();
1900 if (_tcscmp(m_szAgentVersion, buffer))
1901 {
1902 _tcscpy(m_szAgentVersion, buffer);
1903 hasChanges = true;
21c9acce 1904 sendPollerMsg(dwRqId, _T(" NetXMS agent version changed to %s\r\n"), m_szAgentVersion);
76720a09
VK
1905 }
1906 UnlockData();
1907 }
1908
1909 if (pAgentConn->getParameter(_T("System.PlatformName"), MAX_PLATFORM_NAME_LEN, buffer) == ERR_SUCCESS)
1910 {
1911 LockData();
1912 if (_tcscmp(m_szPlatformName, buffer))
1913 {
1914 _tcscpy(m_szPlatformName, buffer);
1915 hasChanges = true;
21c9acce 1916 sendPollerMsg(dwRqId, _T(" Platform name changed to %s\r\n"), m_szPlatformName);
76720a09
VK
1917 }
1918 UnlockData();
1919 }
1920
1921 // Check IP forwarding status
1922 if (pAgentConn->getParameter(_T("Net.IP.Forwarding"), 16, buffer) == ERR_SUCCESS)
1923 {
1924 if (_tcstoul(buffer, NULL, 10) != 0)
1925 m_dwFlags |= NF_IS_ROUTER;
1926 else
1927 m_dwFlags &= ~NF_IS_ROUTER;
1928 }
1929
1930 // Get uname
1931 if (pAgentConn->getParameter(_T("System.Uname"), MAX_DB_STRING, buffer) == ERR_SUCCESS)
1932 {
1933 TranslateStr(buffer, _T("\r\n"), _T(" "));
1934 TranslateStr(buffer, _T("\n"), _T(" "));
1935 TranslateStr(buffer, _T("\r"), _T(" "));
1936 LockData();
1937 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, buffer))
1938 {
1939 safe_free(m_sysDescription);
1940 m_sysDescription = _tcsdup(buffer);
1941 hasChanges = true;
21c9acce 1942 sendPollerMsg(dwRqId, _T(" System description changed to %s\r\n"), m_sysDescription);
76720a09
VK
1943 }
1944 UnlockData();
1945 }
1946
86c126f5
VK
1947 ObjectArray<AgentParameterDefinition> *plist;
1948 ObjectArray<AgentTableDefinition> *tlist;
967893bb 1949 UINT32 rcc = pAgentConn->getSupportedParameters(&plist, &tlist);
76720a09
VK
1950 if (rcc == ERR_SUCCESS)
1951 {
1952 LockData();
1953 delete m_paramList;
1954 delete m_tableList;
1955 m_paramList = plist;
1956 m_tableList = tlist;
084fb4c1
VK
1957
1958 // Check for 64-bit interface counters
1959 m_dwFlags &= ~NF_HAS_AGENT_IFXCOUNTERS;
1960 for(int i = 0; i < plist->size(); i++)
1961 {
86c126f5 1962 if (!_tcsicmp(plist->get(i)->getName(), _T("Net.Interface.BytesIn64(*)")))
084fb4c1
VK
1963 {
1964 m_dwFlags |= NF_HAS_AGENT_IFXCOUNTERS;
1965 }
1966 }
1967
76720a09
VK
1968 UnlockData();
1969 }
1970 else
1971 {
1972 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getSupportedParameters() failed: rcc=%d"), m_szName, rcc);
1973 }
1974
46ee6286
VK
1975 // Get supported Windows Performance Counters
1976 if (!_tcsncmp(m_szPlatformName, _T("windows-"), 8))
1977 {
1978 sendPollerMsg(dwRqId, _T(" Reading list of available Windows Performance Counters...\r\n"));
1979 ObjectArray<WinPerfObject> *perfObjects = WinPerfObject::getWinPerfObjectsFromNode(this, pAgentConn);
1980 LockData();
1981 delete m_winPerfObjects;
1982 m_winPerfObjects = perfObjects;
1983 if (m_winPerfObjects != NULL)
1984 {
1985 sendPollerMsg(dwRqId, POLLER_INFO _T(" %d counters read\r\n"), m_winPerfObjects->size());
1986 if (!(m_dwFlags & NF_HAS_WINPDH))
1987 {
1988 m_dwFlags |= NF_HAS_WINPDH;
1989 hasChanges = true;
1990 }
1991 }
1992 else
1993 {
1994 sendPollerMsg(dwRqId, POLLER_ERROR _T(" unable to get Windows Performance Counters list\r\n"));
1995 if (m_dwFlags & NF_HAS_WINPDH)
1996 {
1997 m_dwFlags &= ~NF_HAS_WINPDH;
1998 hasChanges = true;
1999 }
2000 }
2001 UnlockData();
2002 }
2003
76720a09
VK
2004 checkAgentPolicyBinding(pAgentConn);
2005
2006 pAgentConn->disconnect();
2007 }
2008 else
2009 {
af21affe 2010 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - failed to connect (error %d)"), m_szName, rcc);
76720a09
VK
2011 }
2012 delete pAgentConn;
2013 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - finished"), m_szName);
2014 return hasChanges;
2015}
2016
2017/**
2018 * SNMP walker callback which just counts number of varbinds
2019 */
967893bb 2020static UINT32 CountingSnmpWalkerCallback(UINT32 version, SNMP_Variable *var, SNMP_Transport *transport, void *arg)
76720a09
VK
2021{
2022 (*((int *)arg))++;
2023 return SNMP_ERR_SUCCESS;
2024}
2025
2026/**
2027 * Configuration poll: check for SNMP
2028 */
967893bb 2029bool Node::confPollSnmp(UINT32 dwRqId)
76720a09
VK
2030{
2031 if (((m_dwFlags & NF_IS_SNMP) && (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)) ||
2032 (m_dwIpAddr == 0) || (m_dwFlags & NF_DISABLE_SNMP))
2033 return false;
2034
2035 bool hasChanges = false;
2036
21c9acce 2037 sendPollerMsg(dwRqId, _T(" Checking SNMP...\r\n"));
76720a09
VK
2038 DbgPrintf(5, _T("ConfPoll(%s): calling SnmpCheckCommSettings()"), m_szName);
2039 SNMP_Transport *pTransport = createSnmpTransport();
2040 if (pTransport == NULL)
2041 {
2042 DbgPrintf(5, _T("ConfPoll(%s): unable to create SNMP transport"), m_szName);
2043 return false;
2044 }
2045
1f4c37ee
VK
2046 StringList oids;
2047 const TCHAR *customOid = m_customAttributes.get(_T("snmp.testoid"));
2048 if (customOid != NULL)
2049 oids.add(customOid);
2050 oids.add(_T(".1.3.6.1.2.1.1.2.0"));
2051 oids.add(_T(".1.3.6.1.2.1.1.1.0"));
2052 AddDriverSpecificOids(&oids);
2053 SNMP_SecurityContext *newCtx = SnmpCheckCommSettings(pTransport, &m_snmpVersion, m_snmpSecurity, &oids);
76720a09
VK
2054 if (newCtx != NULL)
2055 {
2056 LockData();
2057 delete m_snmpSecurity;
2058 m_snmpSecurity = newCtx;
2059 m_dwFlags |= NF_IS_SNMP;
2060 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
2061 {
2062 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
2063 PostEvent(EVENT_SNMP_OK, m_dwId, NULL);
21c9acce 2064 sendPollerMsg(dwRqId, POLLER_INFO _T(" Connectivity with SNMP agent restored\r\n"));
76720a09
VK
2065 }
2066 UnlockData();
21c9acce 2067 sendPollerMsg(dwRqId, _T(" SNMP agent is active (version %s)\r\n"),
76720a09
VK
2068 (m_snmpVersion == SNMP_VERSION_3) ? _T("3") : ((m_snmpVersion == SNMP_VERSION_2C) ? _T("2c") : _T("1")));
2069
2070 TCHAR szBuffer[4096];
d525c9ed 2071 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 2072 {
3b2d5932
VK
2073 // Set snmp object ID to .0.0 if it cannot be read
2074 _tcscpy(szBuffer, _T(".0.0"));
76720a09 2075 }
3b2d5932
VK
2076 LockData();
2077 if (_tcscmp(m_szObjectId, szBuffer))
2078 {
2079 nx_strncpy(m_szObjectId, szBuffer, MAX_OID_LEN * 4);
2080 hasChanges = true;
2081 }
2082 UnlockData();
76720a09
VK
2083
2084 // Get system description
d525c9ed 2085 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
2086 {
2087 TranslateStr(szBuffer, _T("\r\n"), _T(" "));
2088 TranslateStr(szBuffer, _T("\n"), _T(" "));
2089 TranslateStr(szBuffer, _T("\r"), _T(" "));
2090 LockData();
2091 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, szBuffer))
2092 {
2093 safe_free(m_sysDescription);
2094 m_sysDescription = _tcsdup(szBuffer);
2095 hasChanges = true;
21c9acce 2096 sendPollerMsg(dwRqId, _T(" System description changed to %s\r\n"), m_sysDescription);
76720a09
VK
2097 }
2098 UnlockData();
2099 }
2100
2101 // Select device driver
2102 NetworkDeviceDriver *driver = FindDriverForNode(this, pTransport);
2103 DbgPrintf(5, _T("ConfPoll(%s): selected device driver %s"), m_szName, driver->getName());
2104 LockData();
2105 if (driver != m_driver)
2106 {
2107 m_driver = driver;
21c9acce 2108 sendPollerMsg(dwRqId, _T(" New network device driver selected: %s\r\n"), m_driver->getName());
76720a09
VK
2109 }
2110 UnlockData();
2111
2112 // Allow driver to gather additional info
ae32341d 2113 m_driver->analyzeDevice(pTransport, m_szObjectId, &m_customAttributes, &m_driverData);
76720a09
VK
2114
2115 // Get sysName
2116 if (SnmpGet(m_snmpVersion, pTransport,
d525c9ed 2117 _T(".1.3.6.1.2.1.1.5.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
76720a09
VK
2118 {
2119 LockData();
2120 if ((m_sysName == NULL) || _tcscmp(m_sysName, szBuffer))
2121 {
2122 safe_free(m_sysName);
2123 m_sysName = _tcsdup(szBuffer);
2124 hasChanges = true;
21c9acce 2125 sendPollerMsg(dwRqId, _T(" System name changed to %s\r\n"), m_sysName);
76720a09
VK
2126 }
2127 UnlockData();
2128 }
2129
2130 // Check IP forwarding
074498ac 2131 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.2.1.4.1.0"), 1))
76720a09
VK
2132 {
2133 LockData();
2134 m_dwFlags |= NF_IS_ROUTER;
2135 UnlockData();
2136 }
2137 else
2138 {
2139 LockData();
2140 m_dwFlags &= ~NF_IS_ROUTER;
2141 UnlockData();
2142 }
2143
2144 checkIfXTable(pTransport);
2145 checkBridgeMib(pTransport);
eec253a8 2146
76720a09 2147 // Check for ENTITY-MIB support
d525c9ed 2148 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
2149 {
2150 LockData();
2151 m_dwFlags |= NF_HAS_ENTITY_MIB;
2152 UnlockData();
2153
2154 ComponentTree *components = BuildComponentTree(this, pTransport);
2155 LockData();
2156 if (m_components != NULL)
2157 m_components->decRefCount();
2158 m_components = components;
2159 UnlockData();
2160 }
2161 else
2162 {
2163 LockData();
2164 m_dwFlags &= ~NF_HAS_ENTITY_MIB;
2165 if (m_components != NULL)
2166 {
2167 m_components->decRefCount();
2168 m_components = NULL;
2169 }
2170 UnlockData();
2171 }
2172
2173 // Check for printer MIB support
2174 int count = 0;
46b7166d 2175 SnmpWalk(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.43.5.1.1.17"), CountingSnmpWalkerCallback, &count, FALSE);
76720a09
VK
2176 if (count > 0)
2177 {
2178 LockData();
2179 m_dwFlags |= NF_IS_PRINTER;
2180 UnlockData();
2181 }
2182 else
2183 {
2184 LockData();
2185 m_dwFlags &= ~NF_IS_PRINTER;
2186 UnlockData();
2187 }
2188
2189 // Check for CDP (Cisco Discovery Protocol) support
074498ac 2190 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.9.9.23.1.3.1.0"), 1))
76720a09
VK
2191 {
2192 LockData();
2193 m_dwFlags |= NF_IS_CDP;
2194 UnlockData();
2195 }
2196 else
2197 {
2198 LockData();
2199 m_dwFlags &= ~NF_IS_CDP;
2200 UnlockData();
2201 }
2202
2203 // Check for NDP (Nortel Discovery Protocol) support
074498ac 2204 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.45.1.6.13.1.2.0"), 1))
76720a09
VK
2205 {
2206 LockData();
2207 m_dwFlags |= NF_IS_NDP;
2208 UnlockData();
2209 }
2210 else
2211 {
2212 LockData();
2213 m_dwFlags &= ~NF_IS_NDP;
2214 UnlockData();
2215 }
2216
2217 // Check for LLDP (Link Layer Discovery Protocol) support
d525c9ed 2218 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
2219 {
2220 LockData();
2221 m_dwFlags |= NF_IS_LLDP;
2222 UnlockData();
2223
20c7bdf7
VK
2224 INT32 type;
2225 BYTE data[256];
2226 UINT32 dataLen;
2227 if ((SnmpGetEx(pTransport, _T(".1.0.8802.1.1.2.1.3.1.0"), NULL, 0, &type, sizeof(INT32), 0, NULL) == SNMP_ERR_SUCCESS) &&
2228 (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 2229 {
20c7bdf7
VK
2230 BuildLldpId(type, data, dataLen, szBuffer, 1024);
2231 LockData();
2232 if ((m_lldpNodeId == NULL) || _tcscmp(m_lldpNodeId, szBuffer))
76720a09 2233 {
20c7bdf7
VK
2234 safe_free(m_lldpNodeId);
2235 m_lldpNodeId = _tcsdup(szBuffer);
2236 hasChanges = true;
2237 sendPollerMsg(dwRqId, _T(" LLDP node ID changed to %s\r\n"), m_lldpNodeId);
76720a09 2238 }
20c7bdf7 2239 UnlockData();
76720a09 2240 }
3a82d5ae
VK
2241
2242 ObjectArray<LLDP_LOCAL_PORT_INFO> *lldpPorts = GetLLDPLocalPortInfo(pTransport);
2243 LockData();
2244 delete m_lldpLocalPortInfo;
2245 m_lldpLocalPortInfo = lldpPorts;
2246 UnlockData();
76720a09
VK
2247 }
2248 else
2249 {
2250 LockData();
2251 m_dwFlags &= ~NF_IS_LLDP;
2252 UnlockData();
2253 }
2254
2255 // Check for 802.1x support
074498ac 2256 if (checkSNMPIntegerValue(pTransport, _T(".1.0.8802.1.1.1.1.1.1.0"), 1))
76720a09
VK
2257 {
2258 LockData();
2259 m_dwFlags |= NF_IS_8021X;
2260 UnlockData();
2261 }
2262 else
2263 {
2264 LockData();
2265 m_dwFlags &= ~NF_IS_8021X;
2266 UnlockData();
2267 }
2268
074498ac 2269 checkOSPFSupport(pTransport);
76720a09
VK
2270
2271 // Get VRRP information
2272 VrrpInfo *vrrpInfo = GetVRRPInfo(this);
2273 if (vrrpInfo != NULL)
2274 {
2275 LockData();
2276 m_dwFlags |= NF_IS_VRRP;
2277 delete m_vrrpInfo;
2278 m_vrrpInfo = vrrpInfo;
2279 UnlockData();
2280 }
2281 else
2282 {
2283 LockData();
2284 m_dwFlags &= ~NF_IS_VRRP;
2285 UnlockData();
2286 }
c6afd26a
VK
2287
2288 // Get wireless controller data
2289 if ((m_driver != NULL) && m_driver->isWirelessController(pTransport, &m_customAttributes, m_driverData))
2290 {
2587b41b
VK
2291 DbgPrintf(5, _T("ConfPoll(%s): node is wireless controller, reading access point information"), m_szName);
2292 sendPollerMsg(dwRqId, _T(" Reading wireless access point information\r\n"));
c6afd26a
VK
2293 LockData();
2294 m_dwFlags |= NF_IS_WIFI_CONTROLLER;
2295 UnlockData();
2296
2297 ObjectArray<AccessPointInfo> *aps = m_driver->getAccessPoints(pTransport, &m_customAttributes, m_driverData);
2298 if (aps != NULL)
2299 {
2587b41b
VK
2300 sendPollerMsg(dwRqId, POLLER_INFO _T(" %d wireless access points found\r\n"), aps->size());
2301 DbgPrintf(5, _T("ConfPoll(%s): got information about %d access points"), m_szName, aps->size());
f1989a3a 2302 int adopted = 0;
c6afd26a
VK
2303 for(int i = 0; i < aps->size(); i++)
2304 {
2305 AccessPointInfo *info = aps->get(i);
f1989a3a
VK
2306 if (info->getState() != AP_ADOPTED)
2307 continue;
2308
2309 adopted++;
c6afd26a 2310 AccessPoint *ap = FindAccessPointByMAC(info->getMacAddr());
d5de1d1d 2311 if (ap == NULL)
c6afd26a 2312 {
d5de1d1d 2313 String name;
4d2c3a54 2314
ffb44442
VK
2315 if (info->getName() != NULL)
2316 {
2317 name = info->getName();
2318 }
2319 else
2320 {
2321 for(int j = 0; j < info->getRadioInterfaces()->size(); j++)
2322 {
2323 if (j > 0)
2324 name += _T("/");
2325 name += info->getRadioInterfaces()->get(j)->name;
2326 }
2327 }
f1989a3a
VK
2328 ap = new AccessPoint((const TCHAR *)name, info->getMacAddr());
2329 NetObjInsert(ap, TRUE);
2330 DbgPrintf(5, _T("ConfPoll(%s): created new access point object %s [%d]"), m_szName, ap->Name(), ap->Id());
c6afd26a 2331 }
d5de1d1d
VK
2332 ap->attachToNode(m_dwId);
2333 ap->updateRadioInterfaces(info->getRadioInterfaces());
f1989a3a
VK
2334 ap->updateInfo(NULL, info->getModel(), info->getSerial());
2335 ap->unhide();
c6afd26a 2336 }
f1989a3a
VK
2337
2338 LockData();
2339 m_adoptedApCount = adopted;
2340 m_totalApCount = aps->size();
2341 UnlockData();
2342
c6afd26a
VK
2343 delete aps;
2344 }
2587b41b
VK
2345 else
2346 {
2347 DbgPrintf(5, _T("ConfPoll(%s): failed to read access point information"), m_szName);
2348 sendPollerMsg(dwRqId, POLLER_ERROR _T(" Failed to read access point information\r\n"));
2349 }
c6afd26a
VK
2350 }
2351 else
2352 {
2353 LockData();
2354 m_dwFlags &= ~NF_IS_WIFI_CONTROLLER;
2355 UnlockData();
2356 }
76720a09 2357 }
9a1f7c45 2358 else if (ConfigReadInt(_T("EnableCheckPointSNMP"), 0))
76720a09
VK
2359 {
2360 // Check for CheckPoint SNMP agent on port 161
2361 DbgPrintf(5, _T("ConfPoll(%s): checking for CheckPoint SNMP"), m_szName);
2362 TCHAR szBuffer[4096];
d525c9ed 2363 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
2364 {
2365 LockData();
2366 if (_tcscmp(m_szObjectId, _T(".1.3.6.1.4.1.2620.1.1")))
2367 {
2368 nx_strncpy(m_szObjectId, _T(".1.3.6.1.4.1.2620.1.1"), MAX_OID_LEN * 4);
2369 hasChanges = true;
2370 }
2371
2372 m_dwFlags |= NF_IS_SNMP | NF_IS_ROUTER;
2373 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
2374 UnlockData();
21c9acce 2375 sendPollerMsg(dwRqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 161 is active\r\n"));
76720a09
VK
2376 }
2377 }
2378 delete pTransport;
2379 return hasChanges;
2380}
2381
2382/**
2383 * Configuration poll: check for BRIDGE MIB
2384 */
2385void Node::checkBridgeMib(SNMP_Transport *pTransport)
2386{
2387 TCHAR szBuffer[4096];
d525c9ed 2388 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
2389 {
2390 LockData();
2391 m_dwFlags |= NF_IS_BRIDGE;
2392 memcpy(m_baseBridgeAddress, szBuffer, 6);
2393 UnlockData();
2394
2395 // Check for Spanning Tree (IEEE 802.1d) MIB support
074498ac 2396 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.2.1.17.2.1.0"), 3))
76720a09
VK
2397 {
2398 LockData();
2399 m_dwFlags |= NF_IS_STP;
2400 UnlockData();
2401 }
2402 else
2403 {
2404 LockData();
2405 m_dwFlags &= ~NF_IS_STP;
2406 UnlockData();
2407 }
2408 }
2409 else
2410 {
2411 LockData();
2412 m_dwFlags &= ~(NF_IS_BRIDGE | NF_IS_STP);
2413 UnlockData();
2414 }
2415}
2416
2417/**
2418 * Configuration poll: check for ifXTable
2419 */
2420void Node::checkIfXTable(SNMP_Transport *pTransport)
2421{
2422 int count = 0;
46b7166d 2423 SnmpWalk(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.31.1.1.1.1"), CountingSnmpWalkerCallback, &count, FALSE);
76720a09
VK
2424 if (count > 0)
2425 {
2426 LockData();
2427 m_dwFlags |= NF_HAS_IFXTABLE;
2428 UnlockData();
2429 }
2430 else
2431 {
2432 LockData();
2433 m_dwFlags &= ~NF_HAS_IFXTABLE;
2434 UnlockData();
2435 }
2436}
2437
2438/**
2439 * Update interface configuration
2440 */
967893bb 2441BOOL Node::updateInterfaceConfiguration(UINT32 dwRqId, UINT32 dwNetMask)
eec253a8 2442{
98762401 2443 InterfaceList *pIfList;
eec253a8
VK
2444 Interface **ppDeleteList;
2445 int i, j, iDelCount;
2446 BOOL hasChanges = FALSE;
2447 Cluster *pCluster = getMyCluster();
2448
21c9acce 2449 sendPollerMsg(dwRqId, _T("Checking interface configuration...\r\n"));
eec253a8
VK
2450 pIfList = getInterfaceList();
2451 if (pIfList != NULL)
2452 {
22d657d2 2453 DbgPrintf(6, _T("Node::updateInterfaceConfiguration(%s [%u]): got %d interfaces"), m_szName, m_dwId, pIfList->getSize());
eec253a8
VK
2454 // Remove cluster virtual interfaces from list
2455 if (pCluster != NULL)
2456 {
98762401 2457 for(i = 0; i < pIfList->getSize(); i++)
eec253a8 2458 {
98762401 2459 if (pCluster->isVirtualAddr(pIfList->get(i)->dwIpAddr))
eec253a8 2460 {
98762401 2461 pIfList->remove(i);
eec253a8
VK
2462 i--;
2463 }
2464 }
2465 }
2466
2467 // Find non-existing interfaces
2468 LockChildList(FALSE);
2469 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
2470 for(i = 0, iDelCount = 0; i < (int)m_dwChildCount; i++)
2471 {
2472 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2473 {
2474 Interface *pInterface = (Interface *)m_pChildList[i];
9214177b
VK
2475 if (!pInterface->isManuallyCreated())
2476 {
2477 for(j = 0; j < pIfList->getSize(); j++)
2478 {
2479 if ((pIfList->get(j)->dwIndex == pInterface->getIfIndex()) &&
2480 (pIfList->get(j)->dwIpAddr == pInterface->IpAddr()))
2481 break;
2482 }
eec253a8 2483
9214177b
VK
2484 if (j == pIfList->getSize())
2485 {
2486 // No such interface in current configuration, add it to delete list
2487 ppDeleteList[iDelCount++] = pInterface;
2488 }
2489 }
eec253a8
VK
2490 }
2491 }
2492 UnlockChildList();
2493
2494 // Delete non-existent interfaces
2495 if (iDelCount > 0)
2496 {
2497 for(j = 0; j < iDelCount; j++)
2498 {
21c9acce 2499 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Interface \"%s\" is no longer exist\r\n"),
eec253a8
VK
2500 ppDeleteList[j]->Name());
2501 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->getIfIndex(),
2502 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->getIpNetMask());
2503 deleteInterface(ppDeleteList[j]);
2504 }
2505 hasChanges = TRUE;
2506 }
2507 safe_free(ppDeleteList);
2508
2509 // Add new interfaces and check configuration of existing
98762401 2510 for(j = 0; j < pIfList->getSize(); j++)
eec253a8 2511 {
60557d06 2512 NX_INTERFACE_INFO *ifInfo = pIfList->get(j);
eec253a8
VK
2513 BOOL bNewInterface = TRUE;
2514
2515 LockChildList(FALSE);
2516 for(i = 0; i < (int)m_dwChildCount; i++)
2517 {
2518 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2519 {
2520 Interface *pInterface = (Interface *)m_pChildList[i];
2521
98762401
VK
2522 if ((ifInfo->dwIndex == pInterface->getIfIndex()) &&
2523 (ifInfo->dwIpAddr == pInterface->IpAddr()))
eec253a8
VK
2524 {
2525 // Existing interface, check configuration
22d657d2 2526 if (memcmp(ifInfo->bMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) && memcmp(ifInfo->bMacAddr, pInterface->getMacAddr(), MAC_ADDR_LENGTH))
eec253a8
VK
2527 {
2528 TCHAR szOldMac[16], szNewMac[16];
2529
2530 BinToStr((BYTE *)pInterface->getMacAddr(), MAC_ADDR_LENGTH, szOldMac);
98762401 2531 BinToStr(ifInfo->bMacAddr, MAC_ADDR_LENGTH, szNewMac);
eec253a8
VK
2532 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
2533 pInterface->Id(), pInterface->getIfIndex(),
2534 pInterface->Name(), szOldMac, szNewMac);
98762401 2535 pInterface->setMacAddr(ifInfo->bMacAddr);
eec253a8 2536 }
98762401 2537 if (_tcscmp(ifInfo->szName, pInterface->Name()))
eec253a8 2538 {
98762401 2539 pInterface->setName(ifInfo->szName);
eec253a8 2540 }
478d4ff4
VK
2541 if (_tcscmp(ifInfo->szDescription, pInterface->getDescription()))
2542 {
2543 pInterface->setDescription(ifInfo->szDescription);
2544 }
98762401 2545 if (ifInfo->dwBridgePortNumber != pInterface->getBridgePortNumber())
eec253a8 2546 {
98762401 2547 pInterface->setBridgePortNumber(ifInfo->dwBridgePortNumber);
eec253a8 2548 }
98762401 2549 if (ifInfo->dwSlotNumber != pInterface->getSlotNumber())
76f9abfd 2550 {
98762401 2551 pInterface->setSlotNumber(ifInfo->dwSlotNumber);
76f9abfd 2552 }
98762401 2553 if (ifInfo->dwPortNumber != pInterface->getPortNumber())
76f9abfd 2554 {
98762401 2555 pInterface->setPortNumber(ifInfo->dwPortNumber);
76f9abfd 2556 }
4c16cdc7
VK
2557 if (ifInfo->isPhysicalPort != pInterface->isPhysicalPort())
2558 {
2559 pInterface->setPhysicalPortFlag(ifInfo->isPhysicalPort);
2560 }
98762401 2561 if ((ifInfo->dwIpNetMask != 0) && (ifInfo->dwIpNetMask != pInterface->getIpNetMask()))
dfb38baf 2562 {
98762401 2563 pInterface->setIpNetMask(ifInfo->dwIpNetMask);
dfb38baf 2564 }
eec253a8
VK
2565 bNewInterface = FALSE;
2566 break;
2567 }
2568 }
2569 }
2570 UnlockChildList();
2571
2572 if (bNewInterface)
2573 {
2574 // New interface
21c9acce 2575 sendPollerMsg(dwRqId, POLLER_INFO _T(" Found new interface \"%s\"\r\n"), ifInfo->szName);
4d2c3a54 2576 createNewInterface(ifInfo->dwIpAddr,
98762401
VK
2577 ifInfo->dwIpNetMask,
2578 ifInfo->szName,
478d4ff4 2579 ifInfo->szDescription,
98762401
VK
2580 ifInfo->dwIndex,
2581 ifInfo->dwType,
2582 ifInfo->bMacAddr,
2583 ifInfo->dwBridgePortNumber,
2584 ifInfo->dwSlotNumber,
4c16cdc7 2585 ifInfo->dwPortNumber,
01152a54 2586 ifInfo->isPhysicalPort,
68820776 2587 false,
01152a54 2588 ifInfo->isSystem);
eec253a8
VK
2589 hasChanges = TRUE;
2590 }
2591 }
eec253a8
VK
2592 }
2593 else /* pIfList == NULL */
2594 {
2595 Interface *pInterface;
967893bb 2596 UINT32 dwCount;
eec253a8 2597
21c9acce 2598 sendPollerMsg(dwRqId, POLLER_ERROR _T("Unable to get interface list from node\r\n"));
22d657d2 2599 DbgPrintf(6, _T("Node::updateInterfaceConfiguration(%s [%u]): Unable to get interface list from node"), m_szName, m_dwId);
eec253a8
VK
2600
2601 // Delete all existing interfaces in case of forced capability recheck
2602 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
2603 {
2604 LockChildList(FALSE);
2605 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
2606 for(i = 0, iDelCount = 0; i < (int)m_dwChildCount; i++)
2607 {
9214177b 2608 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) && !((Interface *)m_pChildList[i])->isManuallyCreated())
eec253a8
VK
2609 ppDeleteList[iDelCount++] = (Interface *)m_pChildList[i];
2610 }
2611 UnlockChildList();
2612 for(j = 0; j < iDelCount; j++)
2613 {
21c9acce 2614 sendPollerMsg(dwRqId, POLLER_WARNING _T(" Interface \"%s\" is no longer exist\r\n"),
eec253a8
VK
2615 ppDeleteList[j]->Name());
2616 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->getIfIndex(),
2617 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->getIpNetMask());
2618 deleteInterface(ppDeleteList[j]);
2619 }
2620 safe_free(ppDeleteList);
2621 }
2622
2623 // Check if we have pseudo-interface object
baa5324c
AK
2624 BYTE macAddr[MAC_ADDR_LENGTH];
2625 BYTE *pMacAddr;
eec253a8
VK
2626 dwCount = getInterfaceCount(&pInterface);
2627 if (dwCount == 1)
2628 {
2629 if (pInterface->isFake())
2630 {
2631 // Check if primary IP is different from interface's IP
2632 if (pInterface->IpAddr() != m_dwIpAddr)
2633 {
2634 deleteInterface(pInterface);
2635 if (m_dwIpAddr != 0)
baa5324c
AK
2636 {
2637 memset(macAddr, 0, MAC_ADDR_LENGTH);
2638 Subnet *pSubnet = FindSubnetForNode(m_zoneId, m_dwIpAddr);
2639 if (pSubnet != NULL)
2640 pSubnet->findMacAddress(m_dwIpAddr, macAddr);
22d657d2 2641 pMacAddr = !memcmp(macAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) ? NULL : macAddr;
baa5324c
AK
2642 TCHAR szMac[20];
2643 MACToStr(macAddr, szMac);
dab4332d 2644 DbgPrintf(5, _T("Node::updateInterfaceConfiguration(%s [%u]): got MAC for unknown interface: %s"), m_szName, m_dwId, szMac);
baa5324c
AK
2645 createNewInterface(m_dwIpAddr, dwNetMask, NULL, NULL, 0, 0, pMacAddr);
2646 }
eec253a8 2647 }
22d657d2
VK
2648 else
2649 {
2650 // check MAC address
2651 memset(macAddr, 0, MAC_ADDR_LENGTH);
2652 Subnet *pSubnet = FindSubnetForNode(m_zoneId, m_dwIpAddr);
2653 if (pSubnet != NULL)
2654 pSubnet->findMacAddress(m_dwIpAddr, macAddr);
2655 if (memcmp(macAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) && memcmp(macAddr, pInterface->getMacAddr(), MAC_ADDR_LENGTH))
2656 {
2657 TCHAR szOldMac[16], szNewMac[16];
2658
2659 BinToStr((BYTE *)pInterface->getMacAddr(), MAC_ADDR_LENGTH, szOldMac);
2660 BinToStr(macAddr, MAC_ADDR_LENGTH, szNewMac);
dab4332d 2661 DbgPrintf(5, _T("Node::updateInterfaceConfiguration(%s [%u]): MAC change for unknown interface: %s to %s"),
22d657d2
VK
2662 m_szName, m_dwId, szOldMac, szNewMac);
2663 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
2664 pInterface->Id(), pInterface->getIfIndex(),
2665 pInterface->Name(), szOldMac, szNewMac);
2666 pInterface->setMacAddr(macAddr);
2667 }
2668 }
eec253a8
VK
2669 }
2670 }
2671 else if (dwCount == 0)
2672 {
2673 // No interfaces at all, create pseudo-interface
2674 if (m_dwIpAddr != 0)
baa5324c
AK
2675 {
2676 memset(macAddr, 0, MAC_ADDR_LENGTH);
2677 Subnet *pSubnet = FindSubnetForNode(m_zoneId, m_dwIpAddr);
2678 if (pSubnet != NULL)
2679 pSubnet->findMacAddress(m_dwIpAddr, macAddr);
22d657d2 2680 pMacAddr = !memcmp(macAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) ? NULL : macAddr;
baa5324c
AK
2681 TCHAR szMac[20];
2682 MACToStr(macAddr, szMac);
d51f2182 2683 DbgPrintf(5, _T("Node::updateInterfaceConfiguration(%s [%u]): got MAC for unknown interface: %s"), m_szName, m_dwId, szMac);
baa5324c
AK
2684 createNewInterface(m_dwIpAddr, dwNetMask, NULL, NULL, 0, 0, pMacAddr);
2685 }
eec253a8 2686 }
05c9a2f9 2687 DbgPrintf(6, _T("Node::updateInterfaceConfiguration(%s [%u]): pflist == NULL, dwCount = %u"), m_szName, m_dwId, dwCount);
eec253a8
VK
2688 }
2689
72e97d1c
VK
2690 checkSubnetBinding(pIfList);
2691 delete pIfList;
2692
21c9acce 2693 sendPollerMsg(dwRqId, _T("Interface configuration check finished\r\n"));
eec253a8
VK
2694 return hasChanges;
2695}
2696
6fd6de0a 2697/**
7aad6641 2698 * Callback: apply template to nodes
6fd6de0a 2699 */
27de5dab 2700static void ApplyTemplate(NetObj *object, void *node)
4d0c32f3 2701{
6ff21d27 2702 if ((object->Type() == OBJECT_TEMPLATE) && !object->isDeleted())
4d0c32f3 2703 {
27de5dab
VK
2704 Template *pTemplate = (Template *)object;
2705 if (pTemplate->isApplicable((Node *)node))
2706 {
21c9acce 2707 if (!pTemplate->isChild(((Node *)node)->Id()))
5039dede 2708 {
27de5dab
VK
2709 DbgPrintf(4, _T("Node::ApplyUserTemplates(): applying template %d \"%s\" to node %d \"%s\""),
2710 pTemplate->Id(), pTemplate->Name(), ((Node *)node)->Id(), ((Node *)node)->Name());
6fd6de0a 2711 pTemplate->applyToTarget((Node *)node);
9b64b406 2712 PostEvent(EVENT_TEMPLATE_AUTOAPPLY, g_dwMgmtNode, "isis", ((Node *)node)->Id(), ((Node *)node)->Name(), pTemplate->Id(), pTemplate->Name());
5039dede 2713 }
27de5dab
VK
2714 }
2715 else
2716 {
21c9acce 2717 if (pTemplate->isAutoRemoveEnabled() && pTemplate->isChild(((Node *)node)->Id()))
5039dede 2718 {
27de5dab
VK
2719 DbgPrintf(4, _T("Node::ApplyUserTemplates(): removing template %d \"%s\" from node %d \"%s\""),
2720 pTemplate->Id(), pTemplate->Name(), ((Node *)node)->Id(), ((Node *)node)->Name());
2721 pTemplate->DeleteChild((Node *)node);
2722 ((Node *)node)->DeleteParent(pTemplate);
6fd6de0a 2723 pTemplate->queueRemoveFromTarget(((Node *)node)->Id(), TRUE);
9b64b406 2724 PostEvent(EVENT_TEMPLATE_AUTOREMOVE, g_dwMgmtNode, "isis", ((Node *)node)->Id(), ((Node *)node)->Name(), pTemplate->Id(), pTemplate->Name());
5039dede 2725 }
27de5dab 2726 }
5039dede 2727 }
27de5dab
VK
2728}
2729
7aad6641
VK
2730/**
2731 * Apply user templates
2732 */
6fd6de0a 2733void Node::applyUserTemplates()
27de5dab
VK
2734{
2735 g_idxObjectById.forEach(ApplyTemplate, this);
4d0c32f3 2736}
5039dede 2737
6fd6de0a 2738/**
7aad6641 2739 * Callback: update container membership
6fd6de0a 2740 */
27de5dab 2741static void UpdateContainerBinding(NetObj *object, void *node)
4d0c32f3 2742{
6ff21d27 2743 if ((object->Type() == OBJECT_CONTAINER) && !object->isDeleted())
5039dede 2744 {
27de5dab 2745 Container *pContainer = (Container *)object;
926e8ce7 2746 if (pContainer->isSuitableForNode((Node *)node))
27de5dab 2747 {
21c9acce 2748 if (!pContainer->isChild(((Node *)node)->Id()))
4d0c32f3 2749 {
27de5dab
VK
2750 DbgPrintf(4, _T("Node::UpdateContainerMembership(): binding node %d \"%s\" to container %d \"%s\""),
2751 ((Node *)node)->Id(), ((Node *)node)->Name(), pContainer->Id(), pContainer->Name());
2752 pContainer->AddChild((Node *)node);
2753 ((Node *)node)->AddParent(pContainer);
9b64b406 2754 PostEvent(EVENT_CONTAINER_AUTOBIND, g_dwMgmtNode, "isis", ((Node *)node)->Id(), ((Node *)node)->Name(), pContainer->Id(), pContainer->Name());
4d0c32f3 2755 }
27de5dab
VK
2756 }
2757 else
2758 {
21c9acce 2759 if (pContainer->isAutoUnbindEnabled() && pContainer->isChild(((Node *)node)->Id()))
4d0c32f3 2760 {
27de5dab
VK
2761 DbgPrintf(4, _T("Node::UpdateContainerMembership(): removing node %d \"%s\" from container %d \"%s\""),
2762 ((Node *)node)->Id(), ((Node *)node)->Name(), pContainer->Id(), pContainer->Name());
2763 pContainer->DeleteChild((Node *)node);
2764 ((Node *)node)->DeleteParent(pContainer);
9b64b406 2765 PostEvent(EVENT_CONTAINER_AUTOUNBIND, g_dwMgmtNode, "isis", ((Node *)node)->Id(), ((Node *)node)->Name(), pContainer->Id(), pContainer->Name());
4d0c32f3 2766 }
27de5dab 2767 }
5039dede 2768 }
27de5dab
VK
2769}
2770
7aad6641
VK
2771/**
2772 * Update container membership
2773 */
27de5dab
VK
2774void Node::updateContainerMembership()
2775{
2776 g_idxObjectById.forEach(UpdateContainerBinding, this);
5039dede
AK
2777}
2778
a3050773 2779/**
d51f2182
VK
2780 * Do instance discovery
2781 */
2782void Node::doInstanceDiscovery()
2783{
2784 // collect instance discovery DCIs
2785 ObjectArray<DCItem> rootItems;
b06436f4 2786 lockDciAccess(false);
d51f2182
VK
2787 for(int i = 0; i < m_dcObjects->size(); i++)
2788 {
2789 DCObject *object = m_dcObjects->get(i);
2790 if ((object->getType() == DCO_TYPE_ITEM) && (((DCItem *)object)->getInstanceDiscoveryMethod() != IDM_NONE))
2791 {
2792 object->setBusyFlag(TRUE);
2793 rootItems.add((DCItem *)object);
2794 }
2795 }
2796 unlockDciAccess();
2797
2798 // process instance discovery DCIs
2799 // it should be done that way to prevent DCI list lock for long time
2800 for(int i = 0; i < rootItems.size(); i++)
2801 {
2802 DCItem *dci = rootItems.get(i);
2803 DbgPrintf(5, _T("Node::doInstanceDiscovery(%s [%u]): Updating instances for instance discovery DCI %s [%d]"),
2804 m_szName, m_dwId, dci->getName(), dci->getId());
2805 StringList *instances = getInstanceList(dci);
2806 if (instances != NULL)
2807 {
2808 DbgPrintf(5, _T("Node::doInstanceDiscovery(%s [%u]): read %d values"), m_szName, m_dwId, instances->getSize());
27bbb906 2809 dci->filterInstanceList(instances);
d51f2182
VK
2810 updateInstances(dci, instances);
2811 delete instances;
2812 }
2813 else
2814 {
2815 DbgPrintf(5, _T("Node::doInstanceDiscovery(%s [%u]): failed to get instance list for DCI %s [%d]"),
2816 m_szName, m_dwId, dci->getName(), dci->getId());
2817 }
2818 dci->setBusyFlag(FALSE);
2819 }
2820}
2821
2822/**
2823 * Get instances for instance discovery DCI
2824 */
2825StringList *Node::getInstanceList(DCItem *dci)
2826{
2827 if (dci->getInstanceDiscoveryData() == NULL)
2828 return NULL;
2829
2830 StringList *instances;
2831 switch(dci->getInstanceDiscoveryMethod())
2832 {
2833 case IDM_AGENT_LIST:
2834 getListFromAgent(dci->getInstanceDiscoveryData(), &instances);
2835 break;
7aad6641
VK
2836 case IDM_SNMP_WALK_VALUES:
2837 getListFromSNMP(dci->getSnmpPort(), dci->getInstanceDiscoveryData(), &instances);
2838 break;
2839 case IDM_SNMP_WALK_OIDS:
2840 getOIDSuffixListFromSNMP(dci->getSnmpPort(), dci->getInstanceDiscoveryData(), &instances);
2841 break;
d51f2182
VK
2842 default:
2843 instances = NULL;
2844 break;
2845 }
2846 return instances;
2847}
2848
2849/**
2850 * Update instance DCIs created from instance discovery DCI
2851 */
2852void Node::updateInstances(DCItem *root, StringList *instances)
2853{
b06436f4 2854 lockDciAccess(true);
d51f2182
VK
2855
2856 // Delete DCIs for missing instances and update existing
967893bb 2857 IntegerArray<UINT32> deleteList;
d51f2182
VK
2858 for(int i = 0; i < m_dcObjects->size(); i++)
2859 {
2860 DCObject *object = m_dcObjects->get(i);
4d2c3a54 2861 if ((object->getType() != DCO_TYPE_ITEM) ||
2862 (object->getTemplateId() != m_dwId) ||
d51f2182
VK
2863 (object->getTemplateItemId() != root->getId()))
2864 continue;
2865
2866 int j;
2867 for(j = 0; j < instances->getSize(); j++)
2868 if (!_tcscmp(((DCItem *)object)->getInstance(), instances->getValue(j)))
2869 break;
2870
2871 if (j < instances->getSize())
2872 {
2873 // found, remove value from instances
2874 DbgPrintf(5, _T("Node::updateInstances(%s [%u], %s [%u]): instance \"%s\" found"),
2875 m_szName, m_dwId, root->getName(), root->getId(), instances->getValue(j));
2876 instances->remove(j);
2877 }
2878 else
2879 {
2880 // not found, delete DCI
2881 DbgPrintf(5, _T("Node::updateInstances(%s [%u], %s [%u]): instance \"%s\" not found, instance DCI will be deleted"),
27bbb906 2882 m_szName, m_dwId, root->getName(), root->getId(), ((DCItem *)object)->getInstance());
e8e76b4f 2883 deleteList.add(object->getId());
d51f2182
VK
2884 }
2885 }
2886
2887 for(int i = 0; i < deleteList.size(); i++)
e8e76b4f 2888 deleteDCObject(deleteList.get(i), false);
d51f2182
VK
2889
2890 // Create new instances
2891 for(int i = 0; i < instances->getSize(); i++)
2892 {
27bbb906
VK
2893 DbgPrintf(5, _T("Node::updateInstances(%s [%u], %s [%u]): creating new DCI for instance \"%s\""),
2894 m_szName, m_dwId, root->getName(), root->getId(), instances->getValue(i));
2895
d51f2182
VK
2896 DCItem *dci = new DCItem(root);
2897 dci->setTemplateId(m_dwId, root->getId());
2898 dci->setInstance(instances->getValue(i));
2899 dci->setInstanceDiscoveryMethod(IDM_NONE);
2900 dci->setInstanceDiscoveryData(NULL);
2901 dci->setInstanceFilter(NULL);
2902 dci->expandInstance();
2903 dci->changeBinding(CreateUniqueId(IDG_ITEM), this, FALSE);
2904 addDCObject(dci, true);
2905 }
2906
2907 unlockDciAccess();
2908}
2909
2910/**
1d0d82b3
VK
2911 * Connect to SM-CLP agent. Assumes that access to SM-CLP connection is already locked.
2912 */
2913bool Node::connectToSMCLP()
2914{
2915 // Create new connection object if needed
2916 if (m_smclpConnection == NULL)
2917 {
2918 m_smclpConnection = new SMCLP_Connection(m_dwIpAddr, 23);
2919 DbgPrintf(7, _T("Node::connectToSMCLP(%s [%d]): new connection created"), m_szName, m_dwId);
2920 }
2921 else
2922 {
2923 // Check if we already connected
2924 if (m_smclpConnection->checkConnection())
2925 {
2926 DbgPrintf(7, _T("Node::connectToSMCLP(%s [%d]): already connected"), m_szName, m_dwId);
2927 return true;
2928 }
2929
2930 // Close current connection or clean up after broken connection
2931 m_smclpConnection->disconnect();
2932 delete m_smclpConnection;
2933 m_smclpConnection = new SMCLP_Connection(m_dwIpAddr, 23);
2934 DbgPrintf(7, _T("Node::connectToSMCLP(%s [%d]): existing connection reset"), m_szName, m_dwId);
2935 }
2936
2937 const TCHAR *login = getCustomAttribute(_T("iLO.login"));
2938 const TCHAR *password = getCustomAttribute(_T("iLO.password"));
2939
2940 if ((login != NULL) && (password != NULL))
2941 return m_smclpConnection->connect(login, password);
2942 return false;
2943}
2944
2945/**
a3050773
VK
2946 * Connect to native agent. Assumes that access to agent connection is already locked.
2947 */
967893bb 2948BOOL Node::connectToAgent(UINT32 *error, UINT32 *socketError)
5039dede
AK
2949{
2950 BOOL bRet;
2951
2952 // Create new agent connection object if needed
2953 if (m_pAgentConnection == NULL)
4b91844f 2954 {
d1c1c522 2955 m_pAgentConnection = new AgentConnectionEx(m_dwId, htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
4b91844f
VK
2956 DbgPrintf(7, _T("Node::connectToAgent(%s [%d]): new agent connection created"), m_szName, m_dwId);
2957 }
2958 else
2959 {
2960 // Check if we already connected
2961 if (m_pAgentConnection->nop() == ERR_SUCCESS)
2962 {
2963 DbgPrintf(7, _T("Node::connectToAgent(%s [%d]): already connected"), m_szName, m_dwId);
2964 return TRUE;
2965 }
5039dede 2966
4b91844f
VK
2967 // Close current connection or clean up after broken connection
2968 m_pAgentConnection->disconnect();
2969 DbgPrintf(7, _T("Node::connectToAgent(%s [%d]): existing connection reset"), m_szName, m_dwId);
2970 }
7c521895
VK
2971 m_pAgentConnection->setPort(m_wAgentPort);
2972 m_pAgentConnection->setAuthData(m_wAuthMethod, m_szSharedSecret);
2973 setAgentProxy(m_pAgentConnection);
4b91844f 2974 DbgPrintf(7, _T("Node::connectToAgent(%s [%d]): calling connect on port %d"), m_szName, m_dwId, (int)m_wAgentPort);
a4569c4d 2975 bRet = m_pAgentConnection->connect(g_pServerKey, FALSE, error, socketError);
5039dede
AK
2976 if (bRet)
2977 {
c59466d2 2978 m_pAgentConnection->setCommandTimeout(g_agentCommandTimeout);
45d84f8a 2979 m_pAgentConnection->enableTraps();
5039dede
AK
2980 }
2981 return bRet;
2982}
2983
a3050773
VK
2984/**
2985 * Get DCI value via SNMP
2986 */
967893bb 2987UINT32 Node::getItemFromSNMP(WORD port, const TCHAR *szParam, UINT32 dwBufSize, TCHAR *szBuffer, int interpretRawValue)
5039dede 2988{
967893bb 2989 UINT32 dwResult;
5039dede 2990
2fd7144f 2991 if ((((m_dwDynamicFlags & NDF_SNMP_UNREACHABLE) || !(m_dwFlags & NF_IS_SNMP)) && (port == 0)) ||
6b2bb22c
VK
2992 (m_dwDynamicFlags & NDF_UNREACHABLE) ||
2993 (m_dwFlags & NF_DISABLE_SNMP))
5039dede
AK
2994 {
2995 dwResult = SNMP_ERR_COMM;
2996 }
2997 else
2998 {
2999 SNMP_Transport *pTransport;
3000
65e2005b 3001 pTransport = createSnmpTransport(port);
803d47be
VK
3002 if (pTransport != NULL)
3003 {
e320f8ce
VK
3004 if (interpretRawValue == SNMP_RAWTYPE_NONE)
3005 {
d525c9ed 3006 dwResult = SnmpGet(m_snmpVersion, pTransport, szParam, NULL, 0, szBuffer, dwBufSize * sizeof(TCHAR), SG_PSTRING_RESULT);
e320f8ce
VK
3007 }
3008 else
3009 {
3010 BYTE rawValue[1024];
3011 memset(rawValue, 0, 1024);
3012 dwResult = SnmpGet(m_snmpVersion, pTransport, szParam, NULL, 0, rawValue, 1024, SG_RAW_RESULT);
3013 if (dwResult == SNMP_ERR_SUCCESS)
3014 {
3015 switch(interpretRawValue)
3016 {
3017 case SNMP_RAWTYPE_INT32:
3018 _sntprintf(szBuffer, dwBufSize, _T("%d"), ntohl(*((LONG *)rawValue)));
3019 break;
3020 case SNMP_RAWTYPE_UINT32:
967893bb 3021 _sntprintf(szBuffer, dwBufSize, _T("%u"), ntohl(*((UINT32 *)rawValue)));
e320f8ce
VK
3022 break;
3023 case SNMP_RAWTYPE_INT64:
7aad6641 3024 _sntprintf(szBuffer, dwBufSize, INT64_FMT, (INT64)ntohq(*((INT64 *)rawValue)));
e320f8ce
VK
3025 break;
3026 case SNMP_RAWTYPE_UINT64:
3027 _sntprintf(szBuffer, dwBufSize, UINT64_FMT, ntohq(*((QWORD *)rawValue)));
3028 break;
3029 case SNMP_RAWTYPE_DOUBLE:
3030 _sntprintf(szBuffer, dwBufSize, _T("%f"), ntohd(*((double *)rawValue)));
3031 break;
3032 case SNMP_RAWTYPE_IP_ADDR:
967893bb 3033 IpToStr(ntohl(*((UINT32 *)rawValue)), szBuffer);
e320f8ce
VK
3034 break;
3035 case SNMP_RAWTYPE_MAC_ADDR:
3036 MACToStr(rawValue, szBuffer);
3037 break;
3038 default:
3039 szBuffer[0] = 0;
3040 break;
3041 }
3042 }
3043 }
803d47be
VK
3044 delete pTransport;
3045 }
3046 else
3047 {
3048 dwResult = SNMP_ERR_COMM;
3049 }
5039dede 3050 }
35f836fe 3051 DbgPrintf(7, _T("Node(%s)->GetItemFromSNMP(%s): dwResult=%d"), m_szName, szParam, dwResult);
4d2c3a54 3052 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
5039dede
AK
3053 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3054}
3055
6fd6de0a 3056/**
db117859
VK
3057 * Read one row for SNMP table
3058 */
4d2c3a54 3059static UINT32 ReadSNMPTableRow(SNMP_Transport *snmp, SNMP_ObjectId *rowOid, UINT32 baseOidLen, UINT32 index,
db117859
VK
3060 ObjectArray<DCTableColumn> *columns, Table *table)
3061{
3062 SNMP_PDU request(SNMP_GET_REQUEST, SnmpNewRequestId(), snmp->getSnmpVersion());
3063 for(int i = 0; i < columns->size(); i++)
3064 {
3065 DCTableColumn *c = columns->get(i);
3066 if (c->getSnmpOid() != NULL)
3067 {
3068 UINT32 oid[MAX_OID_LEN];
3069 UINT32 oidLen = c->getSnmpOid()->getLength();
3070 memcpy(oid, c->getSnmpOid()->getValue(), oidLen * sizeof(UINT32));
3071 if (rowOid != NULL)
3072 {
3073 UINT32 suffixLen = rowOid->getLength() - baseOidLen;
3074 memcpy(&oid[oidLen], rowOid->getValue() + baseOidLen, suffixLen * sizeof(UINT32));
3075 oidLen += suffixLen;
3076 }
3077 else
3078 {
3079 oid[oidLen++] = index;
3080 }
3081 request.bindVariable(new SNMP_Variable(oid, oidLen));
3082 }
3083 }
3084
3085 SNMP_PDU *response;
3086 UINT32 rc = snmp->doRequest(&request, &response, g_dwSNMPTimeout, 3);
3087 if (rc == SNMP_ERR_SUCCESS)
3088 {
3089 if (((int)response->getNumVariables() >= columns->size()) &&
3090 (response->getErrorCode() == SNMP_PDU_ERR_SUCCESS))
3091 {
3092 table->addRow();
3093 for(UINT32 i = 0; i < response->getNumVariables(); i++)
3094 {
3095 SNMP_Variable *v = response->getVariable(i);
3096 if ((v != NULL) && (v->GetType() != ASN_NO_SUCH_OBJECT) && (v->GetType() != ASN_NO_SUCH_INSTANCE))
3097 {
3098 bool convert = false;
3099 TCHAR buffer[256];
3100 table->set((int)i, v->getValueAsPrintableString(buffer, 256, &convert));
3101 }
3102 }
3103 }
3104 delete response;
3105 }
3106 return rc;
3107}
3108
3109/**
3110 * Callback for SnmpWalk in Node::getTableFromSNMP
3111 */
3112static UINT32 SNMPGetTableCallback(UINT32 snmpVersion, SNMP_Variable *varbind, SNMP_Transport *snmp, void *arg)
3113{
3114 ((ObjectArray<SNMP_ObjectId> *)arg)->add(new SNMP_ObjectId(varbind->GetName()));
3115 return SNMP_ERR_SUCCESS;
3116}
3117
3118/**
3119 * Get table from SNMP
3120 */
3121UINT32 Node::getTableFromSNMP(WORD port, const TCHAR *oid, ObjectArray<DCTableColumn> *columns, Table **table)
3122{
3123 *table = NULL;
3124
3125 SNMP_Transport *snmp = createSnmpTransport(port);
3126 if (snmp == NULL)
3127 return DCE_COMM_ERROR;
3128
3129 ObjectArray<SNMP_ObjectId> oidList(64, 64, true);
3130 UINT32 rc = SnmpWalk(snmp->getSnmpVersion(), snmp, oid, SNMPGetTableCallback, &oidList, FALSE);
3131 if (rc == SNMP_ERR_SUCCESS)
3132 {
3133 *table = new Table;
3134 for(int i = 0; i < columns->size(); i++)
3135 {
3136 DCTableColumn *c = columns->get(i);
3137 if (c->getSnmpOid() != NULL)
3138 (*table)->addColumn(c->getName(), c->getDataType(), c->getDisplayName(), c->isInstanceColumn());
3139 }
3140
3141 UINT32 baseOidLen = SNMPGetOIDLength(oid);
3142 for(int i = 0; i < oidList.size(); i++)
3143 {
3144 rc = ReadSNMPTableRow(snmp, oidList.get(i), baseOidLen, 0, columns, *table);
3145 if (rc != SNMP_ERR_SUCCESS)
3146 break;
3147 }
3148 }
3149 delete snmp;
3150 return (rc == SNMP_ERR_SUCCESS) ? DCE_SUCCESS : ((rc == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3151}
3152
3153/**
46b7166d 3154 * Callback for SnmpWalk in Node::getListFromSNMP
7aad6641 3155 */
967893bb 3156static UINT32 SNMPGetListCallback(UINT32 snmpVersion, SNMP_Variable *varbind, SNMP_Transport *snmp, void *arg)
7aad6641
VK
3157{
3158 bool convert = false;
3159 TCHAR buffer[256];
3160 ((StringList *)arg)->add(varbind->getValueAsPrintableString(buffer, 256, &convert));
3161 return SNMP_ERR_SUCCESS;
3162}
3163
3164/**
3165 * Get list of values from SNMP
3166 */
967893bb 3167UINT32 Node::getListFromSNMP(WORD port, const TCHAR *oid, StringList **list)
7aad6641
VK
3168{
3169 *list = NULL;
3170 SNMP_Transport *snmp = createSnmpTransport(port);
3171 if (snmp == NULL)
3172 return DCE_COMM_ERROR;
3173
3174 *list = new StringList;
967893bb 3175 UINT32 rc = SnmpWalk(snmp->getSnmpVersion(), snmp, oid, SNMPGetListCallback, *list, FALSE);
7aad6641
VK
3176 delete snmp;
3177 if (rc != SNMP_ERR_SUCCESS)
3178 {
3179 delete *list;
3180 *list = NULL;
3181 }
3182 return (rc == SNMP_ERR_SUCCESS) ? DCE_SUCCESS : ((rc == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3183}
3184
3185/**
3186 * Information for SNMPOIDSuffixListCallback
3187 */
3188struct SNMPOIDSuffixListCallback_Data
3189{
967893bb 3190 UINT32 oidLen;
7aad6641
VK
3191 StringList *values;
3192};
3193
3194/**
46b7166d 3195 * Callback for SnmpWalk in Node::getOIDSuffixListFromSNMP
7aad6641 3196 */
967893bb 3197static UINT32 SNMPOIDSuffixListCallback(UINT32 snmpVersion, SNMP_Variable *varbind, SNMP_Transport *snmp, void *arg)
7aad6641
VK
3198{
3199 SNMPOIDSuffixListCallback_Data *data = (SNMPOIDSuffixListCallback_Data *)arg;
3200 SNMP_ObjectId *oid = varbind->GetName();
3201 if (oid->getLength() <= data->oidLen)
3202 return SNMP_ERR_SUCCESS;
3203 TCHAR buffer[256];
3204 SNMPConvertOIDToText(oid->getLength() - data->oidLen, &(oid->getValue()[data->oidLen]), buffer, 256);
3205 data->values->add((buffer[0] == _T('.')) ? &buffer[1] : buffer);
3206 return SNMP_ERR_SUCCESS;
3207}
3208
3209/**
3210 * Get list of OID suffixes from SNMP
3211 */
967893bb 3212UINT32 Node::getOIDSuffixListFromSNMP(WORD port, const TCHAR *oid, StringList **list)
7aad6641
VK
3213{
3214 *list = NULL;
3215 SNMP_Transport *snmp = createSnmpTransport(port);
3216 if (snmp == NULL)
3217 return DCE_COMM_ERROR;
3218
3219 SNMPOIDSuffixListCallback_Data data;
967893bb 3220 UINT32 oidBin[256];
7aad6641
VK
3221 data.oidLen = SNMPParseOID(oid, oidBin, 256);
3222 if (data.oidLen == 0)
3223 {
3224 delete snmp;
3225 return DCE_NOT_SUPPORTED;
3226 }
3227
3228 data.values = new StringList;
967893bb 3229 UINT32 rc = SnmpWalk(snmp->getSnmpVersion(), snmp, oid, SNMPOIDSuffixListCallback, &data, FALSE);
7aad6641
VK
3230 delete snmp;
3231 if (rc == SNMP_ERR_SUCCESS)
3232 {
3233 *list = data.values;
3234 }
3235 else
3236 {
3237 delete data.values;
3238 }
3239 return (rc == SNMP_ERR_SUCCESS) ? DCE_SUCCESS : ((rc == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3240}
3241
3242/**
6fd6de0a
VK
3243 * Get item's value via SNMP from CheckPoint's agent
3244 */
967893bb 3245UINT32 Node::getItemFromCheckPointSNMP(const TCHAR *szParam, UINT32 dwBufSize, TCHAR *szBuffer)
5039dede 3246{
967893bb 3247 UINT32 dwResult;
5039dede
AK
3248
3249 if ((m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE) ||
3250 (m_dwDynamicFlags & NDF_UNREACHABLE))
3251 {
3252 dwResult = SNMP_ERR_COMM;
3253 }
3254 else
3255 {
3256 SNMP_Transport *pTransport;
3257
3258 pTransport = new SNMP_UDPTransport;
c4366266 3259 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
d525c9ed 3260 dwResult = SnmpGet(SNMP_VERSION_1, pTransport, szParam, NULL, 0, szBuffer, dwBufSize * sizeof(TCHAR), SG_STRING_RESULT);
5039dede
AK
3261 delete pTransport;
3262 }
35f836fe 3263 DbgPrintf(7, _T("Node(%s)->GetItemFromCheckPointSNMP(%s): dwResult=%d"), m_szName, szParam, dwResult);
4d2c3a54 3264 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
5039dede
AK
3265 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
3266}
3267
6fd6de0a
VK
3268/**
3269 * Get item's value via native agent
3270 */
967893bb 3271UINT32 Node::getItemFromAgent(const TCHAR *szParam, UINT32 dwBufSize, TCHAR *szBuffer)
5039dede 3272{
967893bb
VK
3273 UINT32 dwError = ERR_NOT_CONNECTED, dwResult = DCE_COMM_ERROR;
3274 UINT32 dwTries = 3;
5039dede
AK
3275
3276 if ((m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
2fd7144f
VK
3277 (m_dwDynamicFlags & NDF_UNREACHABLE) ||
3278 (m_dwFlags & NF_DISABLE_NXCP) ||
3279 !(m_dwFlags & NF_IS_NATIVE_AGENT))
5039dede
AK
3280 return DCE_COMM_ERROR;
3281
7c521895 3282 agentLock();
5039dede
AK
3283
3284 // Establish connection if needed
3285 if (m_pAgentConnection == NULL)
7c521895 3286 if (!connectToAgent())
5039dede
AK
3287 goto end_loop;
3288
3289 // Get parameter from agent
3290 while(dwTries-- > 0)
3291 {
4687826e 3292 dwError = m_pAgentConnection->getParameter(szParam, dwBufSize, szBuffer);
5039dede
AK
3293 switch(dwError)
3294 {
3295 case ERR_SUCCESS:
3296 dwResult = DCE_SUCCESS;
3297 goto end_loop;
3298 case ERR_UNKNOWN_PARAMETER:
3299 dwResult = DCE_NOT_SUPPORTED;
3300 goto end_loop;
3301 case ERR_NOT_CONNECTED:
3302 case ERR_CONNECTION_BROKEN:
7c521895 3303 if (!connectToAgent())
5039dede
AK
3304 goto end_loop;