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