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