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