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