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