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