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