fixed incorrect mutex unlock in Node::getAgentConnection
[public/netxms.git] / src / server / core / node.cpp
CommitLineData
4d2c3a54 1/*
5039dede 2** NetXMS - Network Management System
a2d1dcb1 3** Copyright (C) 2003-2017 Raden Solutions
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"
2f6c6597 24#include <agent_tunnel.h>
5039dede 25
7aad6641 26/**
ba756b1a
VK
27 * Externals
28 */
29extern UINT64 g_syslogMessagesReceived;
30extern UINT64 g_snmpTrapsReceived;
31
32/**
c50f77f7
VK
33 * Node class default constructor
34 */
6fd6de0a 35Node::Node() : DataCollectionTarget()
5039dede 36{
5f8890c1 37 m_primaryName[0] = 0;
db091a1f 38 m_status = STATUS_UNKNOWN;
e980db40
VK
39 m_type = NODE_TYPE_UNKNOWN;
40 m_subType[0] = 0;
91b3cba9 41 m_capabilities = 0;
a191c634 42 m_zoneUIN = 0;
c42b4551
VK
43 m_agentPort = AGENT_LISTEN_PORT;
44 m_agentAuthMethod = AUTH_NONE;
9708eff4 45 m_agentCacheMode = AGENT_CACHE_DEFAULT;
5039dede
AK
46 m_szSharedSecret[0] = 0;
47 m_iStatusPollType = POLL_ICMP_PING;
5d2c5741 48 m_snmpVersion = SNMP_VERSION_1;
296ae03d 49 m_snmpPort = SNMP_DEFAULT_PORT;
5f8890c1 50 m_snmpSecurity = new SNMP_SecurityContext("public");
53985424 51 m_snmpObjectId[0] = 0;
8573e935
VK
52 m_lastDiscoveryPoll = 0;
53 m_lastStatusPoll = 0;
54 m_lastConfigurationPoll = 0;
805171de 55 m_lastInstancePoll = 0;
5f8890c1 56 m_lastTopologyPoll = 0;
8573e935 57 m_lastRTUpdate = 0;
5f8890c1 58 m_downSince = 0;
71e4ed3a 59 m_bootTime = 0;
0ab347c0 60 m_agentUpTime = 0;
5039dede 61 m_hAgentAccessMutex = MutexCreate();
1d0d82b3 62 m_hSmclpAccessMutex = MutexCreate();
5039dede 63 m_mutexRTAccess = MutexCreate();
5f8890c1 64 m_mutexTopoAccess = MutexCreate();
83191808 65 m_agentConnection = NULL;
c0d97553 66 m_proxyConnections = new ObjectLock<AgentConnectionEx>[MAX_PROXY_TYPE];
1d0d82b3 67 m_smclpConnection = NULL;
5f8890c1
AK
68 m_lastAgentTrapId = 0;
69 m_lastSNMPTrapId = 0;
70 m_lastSyslogMessageId = 0;
42a3be4f 71 m_lastAgentPushRequestId = 0;
53985424
VK
72 m_agentVersion[0] = 0;
73 m_platformName[0] = 0;
5f8890c1
AK
74 m_sysDescription = NULL;
75 m_sysName = NULL;
76 m_sysContact = NULL;
77 m_sysLocation = NULL;
78 m_lldpNodeId = NULL;
79 m_lldpLocalPortInfo = NULL;
cc8ce218 80 m_paramList = NULL;
5f8890c1 81 m_tableList = NULL;
9208c84b
VK
82 m_pollerNode = 0;
83 m_agentProxy = 0;
5f8890c1 84 m_snmpProxy = 0;
9208c84b 85 m_icmpProxy = 0;
f4b2ebd3
VK
86 memset(m_lastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
87 m_routingLoopEvents = new ObjectArray<RoutingLoopEvent>(0, 16, true);
5039dede 88 m_pRoutingTable = NULL;
8573e935
VK
89 m_failTimeSNMP = 0;
90 m_failTimeAgent = 0;
4e3133ee 91 m_lastAgentCommTime = 0;
a01c2a20 92 m_lastAgentConnectAttempt = 0;
5f8890c1
AK
93 m_linkLayerNeighbors = NULL;
94 m_vrrpInfo = NULL;
3cd8c93a 95 m_topology = NULL;
5f8890c1 96 m_topologyRebuildTimestamp = 0;
3e7571a9
EJ
97 m_pendingState = -1;
98 m_pollCountAgent = 0;
99 m_pollCountSNMP = 0;
100 m_pollCountAllDown = 0;
101 m_requiredPollCount = 0; // Use system default
5f8890c1
AK
102 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
103 m_jobQueue = new ServerJobQueue();
104 m_fdb = NULL;
105 m_vlans = NULL;
106 m_wirelessStations = NULL;
107 m_adoptedApCount = 0;
108 m_totalApCount = 0;
109 m_driver = NULL;
110 m_driverData = NULL;
111 m_components = NULL;
112 m_softwarePackages = NULL;
113 m_winPerfObjects = NULL;
114 memset(m_baseBridgeAddress, 0, MAC_ADDR_LENGTH);
115 m_fileUpdateConn = NULL;
116 m_rackId = 0;
117 m_rackPosition = 0;
118 m_rackHeight = 1;
119 m_chassisId = 0;
120 m_syslogMessageCount = 0;
121 m_snmpTrapCount = 0;
122 m_sshLogin[0] = 0;
123 m_sshPassword[0] = 0;
124 m_sshProxy = 0;
191137b2
VK
125 m_portNumberingScheme = NDD_PN_UNKNOWN;
126 m_portRowCount = 0;
55d99dce 127 m_agentCompressionMode = NODE_AGENT_COMPRESSION_DEFAULT;
5039dede
AK
128}
129
c50f77f7
VK
130/**
131 * Constructor for new node object
132 */
91b3cba9 133Node::Node(const InetAddress& addr, UINT32 flags, UINT32 capabilities, UINT32 agentProxy, UINT32 snmpProxy, UINT32 icmpProxy, UINT32 sshProxy, UINT32 zoneUIN) : DataCollectionTarget()
5039dede 134{
688e0055 135 m_runtimeFlags |= DCDF_CONFIGURATION_POLL_PENDING;
c75e9ee4 136 addr.toString(m_primaryName);
db091a1f 137 m_status = STATUS_UNKNOWN;
e980db40
VK
138 m_type = NODE_TYPE_UNKNOWN;
139 m_subType[0] = 0;
c75e9ee4 140 m_ipAddress = addr;
91b3cba9 141 m_capabilities = capabilities;
142 m_flags = flags;
a191c634 143 m_zoneUIN = zoneUIN;
c42b4551
VK
144 m_agentPort = AGENT_LISTEN_PORT;
145 m_agentAuthMethod = AUTH_NONE;
9708eff4 146 m_agentCacheMode = AGENT_CACHE_DEFAULT;
5039dede
AK
147 m_szSharedSecret[0] = 0;
148 m_iStatusPollType = POLL_ICMP_PING;
5d2c5741 149 m_snmpVersion = SNMP_VERSION_1;
296ae03d 150 m_snmpPort = SNMP_DEFAULT_PORT;
5f8890c1 151 m_snmpSecurity = new SNMP_SecurityContext("public");
c75e9ee4 152 addr.toString(m_name); // Make default name from IP address
53985424 153 m_snmpObjectId[0] = 0;
8573e935
VK
154 m_lastDiscoveryPoll = 0;
155 m_lastStatusPoll = 0;
156 m_lastConfigurationPoll = 0;
805171de 157 m_lastInstancePoll = 0;
5f8890c1 158 m_lastTopologyPoll = 0;
8573e935 159 m_lastRTUpdate = 0;
5f8890c1 160 m_downSince = 0;
71e4ed3a 161 m_bootTime = 0;
0ab347c0 162 m_agentUpTime = 0;
5039dede 163 m_hAgentAccessMutex = MutexCreate();
1d0d82b3 164 m_hSmclpAccessMutex = MutexCreate();
5039dede 165 m_mutexRTAccess = MutexCreate();
5f8890c1 166 m_mutexTopoAccess = MutexCreate();
83191808 167 m_agentConnection = NULL;
c0d97553 168 m_proxyConnections = new ObjectLock<AgentConnectionEx>[MAX_PROXY_TYPE];
1d0d82b3 169 m_smclpConnection = NULL;
5f8890c1
AK
170 m_lastAgentTrapId = 0;
171 m_lastSNMPTrapId = 0;
172 m_lastSyslogMessageId = 0;
42a3be4f 173 m_lastAgentPushRequestId = 0;
53985424
VK
174 m_agentVersion[0] = 0;
175 m_platformName[0] = 0;
5f8890c1
AK
176 m_sysDescription = NULL;
177 m_sysName = NULL;
cf38357f
VK
178 m_sysContact = NULL;
179 m_sysLocation = NULL;
5f8890c1
AK
180 m_lldpNodeId = NULL;
181 m_lldpLocalPortInfo = NULL;
cc8ce218 182 m_paramList = NULL;
5f8890c1 183 m_tableList = NULL;
9208c84b
VK
184 m_pollerNode = 0;
185 m_agentProxy = agentProxy;
5f8890c1 186 m_snmpProxy = snmpProxy;
de4c3060 187 m_icmpProxy = icmpProxy;
f4b2ebd3
VK
188 memset(m_lastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
189 m_routingLoopEvents = new ObjectArray<RoutingLoopEvent>(0, 16, true);
01152a54 190 m_isHidden = true;
5039dede 191 m_pRoutingTable = NULL;
8573e935
VK
192 m_failTimeSNMP = 0;
193 m_failTimeAgent = 0;
4e3133ee 194 m_lastAgentCommTime = 0;
a01c2a20 195 m_lastAgentConnectAttempt = 0;
5f8890c1
AK
196 m_linkLayerNeighbors = NULL;
197 m_vrrpInfo = NULL;
3cd8c93a 198 m_topology = NULL;
5f8890c1 199 m_topologyRebuildTimestamp = 0;
3e7571a9
EJ
200 m_pendingState = -1;
201 m_pollCountAgent = 0;
202 m_pollCountSNMP = 0;
203 m_pollCountAllDown = 0;
204 m_requiredPollCount = 0; // Use system default
5f8890c1
AK
205 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
206 m_jobQueue = new ServerJobQueue();
207 m_fdb = NULL;
208 m_vlans = NULL;
209 m_wirelessStations = NULL;
210 m_adoptedApCount = 0;
211 m_totalApCount = 0;
212 m_driver = NULL;
213 m_driverData = NULL;
214 m_components = NULL;
215 m_softwarePackages = NULL;
216 m_winPerfObjects = NULL;
217 memset(m_baseBridgeAddress, 0, MAC_ADDR_LENGTH);
218 m_fileUpdateConn = NULL;
de674bb6
VK
219 m_rackId = 0;
220 m_rackPosition = 0;
221 m_rackHeight = 1;
e4926628 222 m_chassisId = 0;
ba756b1a
VK
223 m_syslogMessageCount = 0;
224 m_snmpTrapCount = 0;
241541f4
VK
225 m_sshLogin[0] = 0;
226 m_sshPassword[0] = 0;
de4c3060 227 m_sshProxy = sshProxy;
191137b2
VK
228 m_portNumberingScheme = NDD_PN_UNKNOWN;
229 m_portRowCount = 0;
55d99dce 230 m_agentCompressionMode = NODE_AGENT_COMPRESSION_DEFAULT;
5039dede
AK
231}
232
c50f77f7
VK
233/**
234 * Node destructor
235 */
5039dede
AK
236Node::~Node()
237{
5f8890c1 238 delete m_driverData;
5039dede 239 MutexDestroy(m_hAgentAccessMutex);
1d0d82b3 240 MutexDestroy(m_hSmclpAccessMutex);
5039dede 241 MutexDestroy(m_mutexRTAccess);
5f8890c1 242 MutexDestroy(m_mutexTopoAccess);
5f8890c1
AK
243 if (m_agentConnection != NULL)
244 m_agentConnection->decRefCount();
c0d97553 245 for(int i = 0; i < MAX_PROXY_TYPE; i++)
246 if(m_proxyConnections[i].get() != NULL)
247 m_proxyConnections[i].get()->decRefCount();
248 delete[] m_proxyConnections;
1d0d82b3 249 delete m_smclpConnection;
cc8ce218 250 delete m_paramList;
5f8890c1 251 delete m_tableList;
f4b2ebd3 252 free(m_sysDescription);
5039dede 253 DestroyRoutingTable(m_pRoutingTable);
5f8890c1
AK
254 if (m_linkLayerNeighbors != NULL)
255 m_linkLayerNeighbors->decRefCount();
256 delete m_vrrpInfo;
3cd8c93a 257 delete m_topology;
5f8890c1
AK
258 delete m_jobQueue;
259 delete m_snmpSecurity;
260 if (m_fdb != NULL)
261 m_fdb->decRefCount();
262 if (m_vlans != NULL)
263 m_vlans->decRefCount();
264 delete m_wirelessStations;
33dfe57e
VK
265 if (m_components != NULL)
266 m_components->decRefCount();
5f8890c1
AK
267 delete m_lldpLocalPortInfo;
268 delete m_softwarePackages;
269 delete m_winPerfObjects;
f4b2ebd3
VK
270 free(m_sysName);
271 free(m_sysContact);
272 free(m_sysLocation);
273 delete m_routingLoopEvents;
5039dede
AK
274}
275
c50f77f7
VK
276/**
277 * Create object from database data
278 */
9bd1bace 279bool Node::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
5039dede 280{
5039dede 281 int i, iNumRows;
967893bb 282 UINT32 dwSubnetId;
5039dede 283 NetObj *pObject;
9bd1bace 284 bool bResult = false;
5039dede 285
c42b4551 286 m_id = dwId;
5039dede 287
9bd1bace 288 if (!loadCommonProperties(hdb))
5039dede 289 {
35f836fe 290 DbgPrintf(2, _T("Cannot load common properties for node object %d"), dwId);
9bd1bace 291 return false;
5039dede
AK
292 }
293
5f8890c1 294 DB_STATEMENT hStmt = DBPrepare(hdb,
91b3cba9 295 _T("SELECT primary_name,primary_ip,")
4866d57b
VK
296 _T("snmp_version,auth_method,secret,")
297 _T("agent_port,status_poll_type,snmp_oid,agent_version,")
298 _T("platform_name,poller_node_id,zone_guid,")
299 _T("proxy_node,snmp_proxy,required_polls,uname,")
5f8890c1
AK
300 _T("use_ifxtable,snmp_port,community,usm_auth_password,")
301 _T("usm_priv_password,usm_methods,snmp_sys_name,bridge_base_addr,")
91b3cba9 302 _T("down_since,boot_time,driver_name,icmp_proxy,")
de674bb6 303 _T("agent_cache_mode,snmp_sys_contact,snmp_sys_location,")
4e3133ee 304 _T("rack_id,rack_image,rack_position,rack_height,")
e980db40 305 _T("last_agent_comm_time,syslog_msg_count,snmp_trap_count,")
55d99dce 306 _T("node_type,node_subtype,ssh_login,ssh_password,ssh_proxy,")
c48843a5 307 _T("port_rows,port_numbering_scheme,agent_comp_mode,")
588c88e6 308 _T("tunnel_id,lldp_id,capabilities,fail_time_snmp,fail_time_agent FROM nodes WHERE id=?"));
5f8890c1
AK
309 if (hStmt == NULL)
310 return false;
4866d57b 311
5f8890c1
AK
312 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, dwId);
313 DB_RESULT hResult = DBSelectPrepared(hStmt);
e2babedf 314 if (hResult == NULL)
5f8890c1
AK
315 {
316 DBFreeStatement(hStmt);
9bd1bace 317 return false; // Query failed
5f8890c1 318 }
5039dede
AK
319
320 if (DBGetNumRows(hResult) == 0)
321 {
322 DBFreeResult(hResult);
5f8890c1 323 DBFreeStatement(hStmt);
5d2c5741 324 DbgPrintf(2, _T("Missing record in \"nodes\" table for node object %d"), dwId);
9bd1bace 325 return false;
5039dede
AK
326 }
327
5ad2167d 328 DBGetField(hResult, 0, 0, m_primaryName, MAX_DNS_NAME);
c75e9ee4 329 m_ipAddress = DBGetFieldInetAddr(hResult, 0, 1);
91b3cba9 330 m_snmpVersion = DBGetFieldLong(hResult, 0, 2);
331 m_agentAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 3);
332 DBGetField(hResult, 0, 4, m_szSharedSecret, MAX_SECRET_LENGTH);
333 m_agentPort = (WORD)DBGetFieldLong(hResult, 0, 5);
334 m_iStatusPollType = DBGetFieldLong(hResult, 0, 6);
335 DBGetField(hResult, 0, 7, m_snmpObjectId, MAX_OID_LEN * 4);
336 DBGetField(hResult, 0, 8, m_agentVersion, MAX_AGENT_VERSION_LEN);
337 DBGetField(hResult, 0, 9, m_platformName, MAX_PLATFORM_NAME_LEN);
338 m_pollerNode = DBGetFieldULong(hResult, 0, 10);
339 m_zoneUIN = DBGetFieldULong(hResult, 0, 11);
340 m_agentProxy = DBGetFieldULong(hResult, 0, 12);
341 m_snmpProxy = DBGetFieldULong(hResult, 0, 13);
3e7571a9 342 m_requiredPollCount = DBGetFieldLong(hResult, 0, 14);
91b3cba9 343 m_sysDescription = DBGetField(hResult, 0, 15, NULL, 0);
344 m_nUseIfXTable = (BYTE)DBGetFieldLong(hResult, 0, 16);
345 m_snmpPort = (WORD)DBGetFieldLong(hResult, 0, 17);
5f8890c1
AK
346
347 // SNMP authentication parameters
348 char snmpAuthObject[256], snmpAuthPassword[256], snmpPrivPassword[256];
91b3cba9 349 DBGetFieldA(hResult, 0, 18, snmpAuthObject, 256);
350 DBGetFieldA(hResult, 0, 19, snmpAuthPassword, 256);
351 DBGetFieldA(hResult, 0, 20, snmpPrivPassword, 256);
352 int snmpMethods = DBGetFieldLong(hResult, 0, 21);
5f8890c1 353 delete m_snmpSecurity;
09468947
VK
354 if (m_snmpVersion == SNMP_VERSION_3)
355 {
356 m_snmpSecurity = new SNMP_SecurityContext(snmpAuthObject, snmpAuthPassword, snmpPrivPassword, snmpMethods & 0xFF, snmpMethods >> 8);
357 }
358 else
359 {
360 // This will create security context with V2C security model
361 // USM fields will be loaded but keys will not be calculated
362 m_snmpSecurity = new SNMP_SecurityContext(snmpAuthObject);
363 m_snmpSecurity->setAuthMethod(snmpMethods & 0xFF);
364 m_snmpSecurity->setAuthPassword(snmpAuthPassword);
365 m_snmpSecurity->setPrivMethod(snmpMethods >> 8);
366 m_snmpSecurity->setPrivPassword(snmpPrivPassword);
367 }
5d2c5741 368
91b3cba9 369 m_sysName = DBGetField(hResult, 0, 22, NULL, 0);
d74c80ea 370
5f8890c1 371 TCHAR baseAddr[16];
91b3cba9 372 TCHAR *value = DBGetField(hResult, 0, 23, baseAddr, 16);
5f8890c1
AK
373 if (value != NULL)
374 StrToBin(value, m_baseBridgeAddress, MAC_ADDR_LENGTH);
3eab63f2 375
91b3cba9 376 m_downSince = DBGetFieldLong(hResult, 0, 24);
377 m_bootTime = DBGetFieldLong(hResult, 0, 25);
dd42ad0a 378
5f8890c1
AK
379 // Setup driver
380 TCHAR driverName[34];
91b3cba9 381 DBGetField(hResult, 0, 26, driverName, 34);
5f8890c1
AK
382 StrStrip(driverName);
383 if (driverName[0] != 0)
384 m_driver = FindDriverByName(driverName);
28e1575f 385
91b3cba9 386 m_icmpProxy = DBGetFieldULong(hResult, 0, 27);
387 m_agentCacheMode = (INT16)DBGetFieldLong(hResult, 0, 28);
9708eff4
VK
388 if ((m_agentCacheMode != AGENT_CACHE_ON) && (m_agentCacheMode != AGENT_CACHE_OFF))
389 m_agentCacheMode = AGENT_CACHE_DEFAULT;
9208c84b 390
91b3cba9 391 m_sysContact = DBGetField(hResult, 0, 29, NULL, 0);
392 m_sysLocation = DBGetField(hResult, 0, 30, NULL, 0);
393
394 m_rackId = DBGetFieldULong(hResult, 0, 31);
395 m_rackImage = DBGetFieldGUID(hResult, 0, 32);
396 m_rackPosition = (INT16)DBGetFieldLong(hResult, 0, 33);
397 m_rackHeight = (INT16)DBGetFieldLong(hResult, 0, 34);
398 m_lastAgentCommTime = DBGetFieldLong(hResult, 0, 35);
399 m_syslogMessageCount = DBGetFieldInt64(hResult, 0, 36);
400 m_snmpTrapCount = DBGetFieldInt64(hResult, 0, 37);
401 m_type = (NodeType)DBGetFieldLong(hResult, 0, 38);
402 DBGetField(hResult, 0, 39, m_subType, MAX_NODE_SUBTYPE_LENGTH);
403 DBGetField(hResult, 0, 40, m_sshLogin, MAX_SSH_LOGIN_LEN);
404 DBGetField(hResult, 0, 41, m_sshPassword, MAX_SSH_PASSWORD_LEN);
405 m_sshProxy = DBGetFieldULong(hResult, 0, 42);
406 m_portRowCount = DBGetFieldULong(hResult, 0, 43);
407 m_portNumberingScheme = DBGetFieldULong(hResult, 0, 44);
408 m_agentCompressionMode = (INT16)DBGetFieldLong(hResult, 0, 45);
409 m_tunnelId = DBGetFieldGUID(hResult, 0, 46);
410 m_lldpNodeId = DBGetField(hResult, 0, 47, NULL, 0);
538ecea7
VK
411 if ((m_lldpNodeId != NULL) && (*m_lldpNodeId == 0))
412 safe_free_and_null(m_lldpNodeId);
a0cc56b3 413 m_capabilities = DBGetFieldULong(hResult, 0, 48);
588c88e6 414 m_failTimeSNMP = DBGetFieldLong(hResult, 0, 49);
415 m_failTimeAgent = DBGetFieldLong(hResult, 0, 50);
de674bb6 416
5039dede 417 DBFreeResult(hResult);
5f8890c1 418 DBFreeStatement(hStmt);
5039dede 419
01152a54 420 if (!m_isDeleted)
5039dede
AK
421 {
422 // Link node to subnets
5f8890c1
AK
423 hStmt = DBPrepare(hdb, _T("SELECT subnet_id FROM nsmap WHERE node_id=?"));
424 if (hStmt == NULL)
425 return false;
92c51b1d 426
5f8890c1 427 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
92c51b1d 428 hResult = DBSelectPrepared(hStmt);
5039dede 429 if (hResult == NULL)
5f8890c1
AK
430 {
431 DBFreeStatement(hStmt);
9bd1bace 432 return false; // Query failed
5f8890c1 433 }
5039dede
AK
434
435 iNumRows = DBGetNumRows(hResult);
5039dede
AK
436 for(i = 0; i < iNumRows; i++)
437 {
438 dwSubnetId = DBGetFieldULong(hResult, i, 0);
439 pObject = FindObjectById(dwSubnetId);
440 if (pObject == NULL)
441 {
442 nxlog_write(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
443 break;
444 }
c42b4551 445 else if (pObject->getObjectClass() != OBJECT_SUBNET)
5039dede
AK
446 {
447 nxlog_write(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
448 break;
449 }
450 else
451 {
1f8be1f4
VK
452 pObject->addChild(this);
453 addParent(pObject);
5039dede
AK
454 }
455 }
456
457 DBFreeResult(hResult);
5f8890c1 458 DBFreeStatement(hStmt);
92c51b1d 459
5f8890c1 460 loadItemsFromDB(hdb);
9bd1bace 461 loadACLFromDB(hdb);
5039dede
AK
462
463 // Walk through all items in the node and load appropriate thresholds
5f8890c1 464 bResult = true;
16d6f798 465 for(i = 0; i < m_dcObjects->size(); i++)
de674bb6 466 {
9bd1bace 467 if (!m_dcObjects->get(i)->loadThresholdsFromDB(hdb))
5039dede 468 {
5d2c5741 469 DbgPrintf(3, _T("Cannot load thresholds for DCI %d of node %d (%s)"),
c42b4551 470 m_dcObjects->get(i)->getId(), dwId, m_name);
9bd1bace 471 bResult = false;
5039dede 472 }
de674bb6
VK
473 }
474
e4926628
VK
475 updatePhysicalContainerBinding(OBJECT_RACK, m_rackId);
476 updatePhysicalContainerBinding(OBJECT_CHASSIS, m_chassisId);
5039dede
AK
477 }
478 else
479 {
9bd1bace 480 bResult = true;
5039dede
AK
481 }
482
483 return bResult;
484}
485
c50f77f7
VK
486/**
487 * Save object to database
488 */
b4277312 489bool Node::saveToDatabase(DB_HANDLE hdb)
5039dede 490{
5039dede 491 // Lock object's access
c42b4551 492 lockProperties();
5039dede 493
3d48d1b4 494 bool success = saveCommonProperties(hdb);
5039dede 495
3d48d1b4 496 if (success && (m_modified & MODIFY_NODE_PROPERTIES))
5f8890c1 497 {
3d48d1b4
VK
498 int snmpMethods = m_snmpSecurity->getAuthMethod() | (m_snmpSecurity->getPrivMethod() << 8);
499 DB_STATEMENT hStmt;
500 if (IsDatabaseRecordExist(hdb, _T("nodes"), _T("id"), m_id))
501 {
502 hStmt = DBPrepare(hdb,
503 _T("UPDATE nodes SET primary_ip=?,primary_name=?,snmp_port=?,capabilities=?,snmp_version=?,community=?,")
504 _T("status_poll_type=?,agent_port=?,auth_method=?,secret=?,snmp_oid=?,uname=?,agent_version=?,")
505 _T("platform_name=?,poller_node_id=?,zone_guid=?,proxy_node=?,snmp_proxy=?,icmp_proxy=?,required_polls=?,")
506 _T("use_ifxtable=?,usm_auth_password=?,usm_priv_password=?,usm_methods=?,snmp_sys_name=?,bridge_base_addr=?,")
507 _T("down_since=?,driver_name=?,rack_image=?,rack_position=?,rack_height=?,rack_id=?,boot_time=?,")
508 _T("agent_cache_mode=?,snmp_sys_contact=?,snmp_sys_location=?,last_agent_comm_time=?,")
509 _T("syslog_msg_count=?,snmp_trap_count=?,node_type=?,node_subtype=?,ssh_login=?,ssh_password=?,")
510 _T("ssh_proxy=?,chassis_id=?,port_rows=?,port_numbering_scheme=?,agent_comp_mode=?,tunnel_id=?,")
511 _T("lldp_id=?,fail_time_snmp=?,fail_time_agent=? WHERE id=?"));
512 }
513 else
514 {
515 hStmt = DBPrepare(hdb,
516 _T("INSERT INTO nodes (primary_ip,primary_name,snmp_port,capabilities,snmp_version,community,status_poll_type,")
517 _T("agent_port,auth_method,secret,snmp_oid,uname,agent_version,platform_name,poller_node_id,zone_guid,")
518 _T("proxy_node,snmp_proxy,icmp_proxy,required_polls,use_ifxtable,usm_auth_password,usm_priv_password,usm_methods,")
519 _T("snmp_sys_name,bridge_base_addr,down_since,driver_name,rack_image,rack_position,rack_height,rack_id,boot_time,")
520 _T("agent_cache_mode,snmp_sys_contact,snmp_sys_location,last_agent_comm_time,syslog_msg_count,snmp_trap_count,")
521 _T("node_type,node_subtype,ssh_login,ssh_password,ssh_proxy,chassis_id,port_rows,port_numbering_scheme,agent_comp_mode,")
522 _T("tunnel_id,lldp_id,fail_time_snmp,fail_time_agent,id) ")
523 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
524 }
525 if (hStmt != NULL)
526 {
527 TCHAR ipAddr[64], baseAddress[16], cacheMode[16], compressionMode[16];
528
529 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, m_ipAddress.toString(ipAddr), DB_BIND_STATIC);
530 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, m_primaryName, DB_BIND_STATIC);
531 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)m_snmpPort);
532 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_capabilities);
533 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_snmpVersion);
28e1575f 534#ifdef UNICODE
3d48d1b4 535 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, WideStringFromMBString(m_snmpSecurity->getCommunity()), DB_BIND_DYNAMIC);
28e1575f 536#else
3d48d1b4 537 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, m_snmpSecurity->getCommunity(), DB_BIND_STATIC);
28e1575f 538#endif
3d48d1b4
VK
539 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (LONG)m_iStatusPollType);
540 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (LONG)m_agentPort);
541 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (LONG)m_agentAuthMethod);
542 DBBind(hStmt, 10, DB_SQLTYPE_VARCHAR, m_szSharedSecret, DB_BIND_STATIC);
543 DBBind(hStmt, 11, DB_SQLTYPE_VARCHAR, m_snmpObjectId, DB_BIND_STATIC);
544 DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, m_sysDescription, DB_BIND_STATIC);
545 DBBind(hStmt, 13, DB_SQLTYPE_VARCHAR, m_agentVersion, DB_BIND_STATIC);
546 DBBind(hStmt, 14, DB_SQLTYPE_VARCHAR, m_platformName, DB_BIND_STATIC);
547 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, m_pollerNode);
548 DBBind(hStmt, 16, DB_SQLTYPE_INTEGER, m_zoneUIN);
549 DBBind(hStmt, 17, DB_SQLTYPE_INTEGER, m_agentProxy);
550 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, m_snmpProxy);
551 DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, m_icmpProxy);
552 DBBind(hStmt, 20, DB_SQLTYPE_INTEGER, (LONG)m_requiredPollCount);
553 DBBind(hStmt, 21, DB_SQLTYPE_INTEGER, (LONG)m_nUseIfXTable);
28e1575f 554#ifdef UNICODE
3d48d1b4
VK
555 DBBind(hStmt, 22, DB_SQLTYPE_VARCHAR, WideStringFromMBString(m_snmpSecurity->getAuthPassword()), DB_BIND_DYNAMIC);
556 DBBind(hStmt, 23, DB_SQLTYPE_VARCHAR, WideStringFromMBString(m_snmpSecurity->getPrivPassword()), DB_BIND_DYNAMIC);
28e1575f 557#else
3d48d1b4
VK
558 DBBind(hStmt, 22, DB_SQLTYPE_VARCHAR, m_snmpSecurity->getAuthPassword(), DB_BIND_STATIC);
559 DBBind(hStmt, 23, DB_SQLTYPE_VARCHAR, m_snmpSecurity->getPrivPassword(), DB_BIND_STATIC);
28e1575f 560#endif
3d48d1b4
VK
561 DBBind(hStmt, 24, DB_SQLTYPE_INTEGER, (LONG)snmpMethods);
562 DBBind(hStmt, 25, DB_SQLTYPE_VARCHAR, m_sysName, DB_BIND_STATIC);
563 DBBind(hStmt, 26, DB_SQLTYPE_VARCHAR, BinToStr(m_baseBridgeAddress, MAC_ADDR_LENGTH, baseAddress), DB_BIND_STATIC);
564 DBBind(hStmt, 27, DB_SQLTYPE_INTEGER, (LONG)m_downSince);
565 DBBind(hStmt, 28, DB_SQLTYPE_VARCHAR, (m_driver != NULL) ? m_driver->getName() : _T(""), DB_BIND_STATIC);
566 DBBind(hStmt, 29, DB_SQLTYPE_VARCHAR, m_rackImage); // rack image
567 DBBind(hStmt, 30, DB_SQLTYPE_INTEGER, m_rackPosition); // rack position
568 DBBind(hStmt, 31, DB_SQLTYPE_INTEGER, m_rackHeight); // device height in rack units
569 DBBind(hStmt, 32, DB_SQLTYPE_INTEGER, m_rackId); // rack ID
570 DBBind(hStmt, 33, DB_SQLTYPE_INTEGER, (LONG)m_bootTime);
571 DBBind(hStmt, 34, DB_SQLTYPE_VARCHAR, _itot(m_agentCacheMode, cacheMode, 10), DB_BIND_STATIC, 1);
572 DBBind(hStmt, 35, DB_SQLTYPE_VARCHAR, m_sysContact, DB_BIND_STATIC);
573 DBBind(hStmt, 36, DB_SQLTYPE_VARCHAR, m_sysLocation, DB_BIND_STATIC);
574 DBBind(hStmt, 37, DB_SQLTYPE_INTEGER, (LONG)m_lastAgentCommTime);
575 DBBind(hStmt, 38, DB_SQLTYPE_BIGINT, m_syslogMessageCount);
576 DBBind(hStmt, 39, DB_SQLTYPE_BIGINT, m_snmpTrapCount);
577 DBBind(hStmt, 40, DB_SQLTYPE_INTEGER, (INT32)m_type);
578 DBBind(hStmt, 41, DB_SQLTYPE_VARCHAR, m_subType, DB_BIND_STATIC);
579 DBBind(hStmt, 42, DB_SQLTYPE_VARCHAR, m_sshLogin, DB_BIND_STATIC);
580 DBBind(hStmt, 43, DB_SQLTYPE_VARCHAR, m_sshPassword, DB_BIND_STATIC);
581 DBBind(hStmt, 44, DB_SQLTYPE_INTEGER, m_sshProxy);
582 DBBind(hStmt, 45, DB_SQLTYPE_INTEGER, m_chassisId);
583 DBBind(hStmt, 46, DB_SQLTYPE_INTEGER, m_portRowCount);
584 DBBind(hStmt, 47, DB_SQLTYPE_INTEGER, m_portNumberingScheme);
585 DBBind(hStmt, 48, DB_SQLTYPE_VARCHAR, _itot(m_agentCompressionMode, compressionMode, 10), DB_BIND_STATIC, 1);
586 DBBind(hStmt, 49, DB_SQLTYPE_VARCHAR, m_tunnelId);
587 DBBind(hStmt, 50, DB_SQLTYPE_VARCHAR, m_lldpNodeId, DB_BIND_STATIC);
588 DBBind(hStmt, 51, DB_SQLTYPE_INTEGER, (LONG)m_failTimeSNMP);
589 DBBind(hStmt, 52, DB_SQLTYPE_INTEGER, (LONG)m_failTimeAgent);
590 DBBind(hStmt, 53, DB_SQLTYPE_INTEGER, m_id);
591
592 success = DBExecute(hStmt);
593 DBFreeStatement(hStmt);
594 }
595 else
596 {
597 success = false;
598 }
599 }
5039dede 600
7c521895 601 // Save access list
3d48d1b4
VK
602 if (success)
603 success = saveACLToDB(hdb);
7c521895 604
c42b4551 605 unlockProperties();
7c521895 606
5039dede 607 // Save data collection items
3d48d1b4 608 if (success && (m_modified & MODIFY_DATA_COLLECTION))
5039dede 609 {
5f8890c1 610 lockDciAccess(false);
3d48d1b4
VK
611 for(int i = 0; success && (i < m_dcObjects->size()); i++)
612 success = m_dcObjects->get(i)->saveToDatabase(hdb);
5f8890c1 613 unlockDciAccess();
5039dede
AK
614 }
615
5f8890c1
AK
616 // Clear modifications flag
617 lockProperties();
3d48d1b4 618 m_modified = 0;
5f8890c1 619 unlockProperties();
5039dede 620
3d48d1b4 621 return success;
5039dede
AK
622}
623
171c2fd6 624/**
b4277312
VK
625 * Save runtime data to database. Called only on server shutdown to save
626 * less important but frequently changing runtime data when it is not feasible
627 * to mark object as modified on each change of such data.
628 */
629bool Node::saveRuntimeData(DB_HANDLE hdb)
630{
631 if (!DataCollectionTarget::saveRuntimeData(hdb))
632 return false;
633
634 DB_STATEMENT hStmt = DBPrepare(hdb, _T("UPDATE nodes SET last_agent_comm_time=?,syslog_msg_count=?,snmp_trap_count=? WHERE id=?"));
635 if (hStmt == NULL)
636 return false;
637
638 lockProperties();
639 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (INT32)m_lastAgentCommTime);
640 DBBind(hStmt, 2, DB_SQLTYPE_BIGINT, m_syslogMessageCount);
641 DBBind(hStmt, 3, DB_SQLTYPE_BIGINT, m_snmpTrapCount);
642 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_id);
643 unlockProperties();
644
645 bool success = DBExecute(hStmt);
646 DBFreeStatement(hStmt);
647 return success;
648}
649
650/**
171c2fd6
VK
651 * Delete object from database
652 */
c42b4551 653bool Node::deleteFromDatabase(DB_HANDLE hdb)
5039dede 654{
c42b4551 655 bool success = DataCollectionTarget::deleteFromDatabase(hdb);
22ee6d97
VK
656 if (success)
657 success = executeQueryOnObject(hdb, _T("DELETE FROM nodes WHERE id=?"));
658 if (success)
659 success = executeQueryOnObject(hdb, _T("DELETE FROM nsmap WHERE node_id=?"));
660 return success;
5039dede
AK
661}
662
80e0db05
VK
663/**
664 * Get ARP cache from node
665 */
7c521895 666ARP_CACHE *Node::getArpCache()
5039dede
AK
667{
668 ARP_CACHE *pArpCache = NULL;
669
91b3cba9 670 if (m_capabilities & NC_IS_LOCAL_MGMT)
5039dede
AK
671 {
672 pArpCache = GetLocalArpCache();
673 }
91b3cba9 674 else if (m_capabilities & NC_IS_NATIVE_AGENT)
5039dede 675 {
25a05c8d
VK
676 AgentConnectionEx *conn = getAgentConnection();
677 if (conn != NULL)
678 {
679 pArpCache = conn->getArpCache();
680 conn->decRefCount();
681 }
5039dede 682 }
91b3cba9 683 else if (m_capabilities & NC_IS_SNMP)
5039dede 684 {
5f8890c1 685 SNMP_Transport *pTransport;
5039dede 686
5f8890c1
AK
687 pTransport = createSnmpTransport();
688 if (pTransport != NULL)
689 {
690 pArpCache = SnmpGetArpCache(m_snmpVersion, pTransport);
691 delete pTransport;
692 }
5039dede
AK
693 }
694
695 return pArpCache;
696}
697
80e0db05
VK
698/**
699 * Get list of interfaces from node
700 */
98762401 701InterfaceList *Node::getInterfaceList()
5039dede 702{
98762401 703 InterfaceList *pIfList = NULL;
5039dede 704
91b3cba9 705 if ((m_capabilities & NC_IS_NATIVE_AGENT) && (!(m_flags & NF_DISABLE_NXCP)))
5039dede 706 {
25a05c8d
VK
707 AgentConnectionEx *conn = getAgentConnection();
708 if (conn != NULL)
5039dede 709 {
25a05c8d
VK
710 pIfList = conn->getInterfaceList();
711 conn->decRefCount();
5039dede 712 }
5039dede 713 }
91b3cba9 714 if ((pIfList == NULL) && (m_capabilities & NC_IS_LOCAL_MGMT))
b741f151
VK
715 {
716 pIfList = GetLocalInterfaceList();
717 }
91b3cba9 718 if ((pIfList == NULL) && (m_capabilities & NC_IS_SNMP) &&
487cde95 719 (!(m_flags & NF_DISABLE_SNMP)) && (m_driver != NULL))
5039dede 720 {
5f8890c1
AK
721 SNMP_Transport *pTransport = createSnmpTransport();
722 if (pTransport != NULL)
723 {
724 bool useIfXTable;
725 if (m_nUseIfXTable == IFXTABLE_DEFAULT)
726 {
727 useIfXTable = (ConfigReadInt(_T("UseIfXTable"), 1) != 0) ? true : false;
728 }
729 else
730 {
731 useIfXTable = (m_nUseIfXTable == IFXTABLE_ENABLED) ? true : false;
732 }
733
734 int useAliases = ConfigReadInt(_T("UseInterfaceAliases"), 0);
735 pIfList = m_driver->getInterfaces(pTransport, &m_customAttributes, m_driverData, useAliases, useIfXTable);
736
91b3cba9 737 if ((pIfList != NULL) && (m_capabilities & NC_IS_BRIDGE))
5f8890c1
AK
738 {
739 BridgeMapPorts(pTransport, pIfList);
740 }
741 delete pTransport;
742 }
5039dede
AK
743 }
744
745 if (pIfList != NULL)
5f8890c1 746 {
024c3faf 747 checkInterfaceNames(pIfList);
5f8890c1
AK
748 addVrrpInterfaces(pIfList);
749 }
5039dede
AK
750
751 return pIfList;
752}
753
6fd6de0a
VK
754/**
755 * Add VRRP interfaces to interface list
756 */
98762401 757void Node::addVrrpInterfaces(InterfaceList *ifList)
0d75ea88 758{
5f8890c1
AK
759 int i, j, k;
760 TCHAR buffer[32];
0d75ea88 761
5f8890c1
AK
762 lockProperties();
763 if (m_vrrpInfo != NULL)
764 {
765 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): m_vrrpInfo->size()=%d"), m_name, (int)m_id, m_vrrpInfo->size());
0d75ea88 766
5f8890c1
AK
767 for(i = 0; i < m_vrrpInfo->size(); i++)
768 {
769 VrrpRouter *router = m_vrrpInfo->getRouter(i);
770 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): vrouter %d state=%d"), m_name, (int)m_id, i, router->getState());
771 if (router->getState() != VRRP_STATE_MASTER)
772 continue; // Do not add interfaces if router is not in master state
0d75ea88 773
5f8890c1
AK
774 // Get netmask for this VR
775 int maskBits = 0;
776 for(j = 0; j < ifList->size(); j++)
c30c0c0f
VK
777 {
778 InterfaceInfo *iface = ifList->get(j);
5f8890c1
AK
779 if (iface->index == router->getIfIndex())
780 {
c30c0c0f
VK
781 for(int k = 0; k < iface->ipAddrList.size(); k++)
782 {
783 const InetAddress& addr = iface->ipAddrList.get(k);
784 if (addr.getSubnetAddress().contain(router->getVip(0)))
785 {
786 maskBits = addr.getMaskBits();
787 }
788 }
5f8890c1
AK
789 break;
790 }
791 }
792
793 // Walk through all VR virtual IPs
794 for(j = 0; j < router->getVipCount(); j++)
795 {
796 UINT32 vip = router->getVip(j);
797 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): checking VIP %s@%d"), m_name, (int)m_id, IpToStr(vip, buffer), i);
798 if (vip != 0)
799 {
800 for(k = 0; k < ifList->size(); k++)
c30c0c0f 801 if (ifList->get(k)->hasAddress(vip))
5f8890c1
AK
802 break;
803 if (k == ifList->size())
804 {
805 InterfaceInfo *iface = new InterfaceInfo(0);
806 _sntprintf(iface->name, MAX_DB_STRING, _T("vrrp.%u.%u.%d"), router->getId(), router->getIfIndex(), j);
807 memcpy(iface->macAddr, router->getVirtualMacAddr(), MAC_ADDR_LENGTH);
c30c0c0f
VK
808 InetAddress addr(vip);
809 addr.setMaskBits(maskBits);
810 iface->ipAddrList.add(addr);
5f8890c1
AK
811 ifList->add(iface);
812 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): added interface %s"), m_name, (int)m_id, iface->name);
813 }
814 }
815 }
816 }
817 }
818 unlockProperties();
0d75ea88
VK
819}
820
7946bd7c 821/**
14228410 822 * Find interface by index.
71ea7674 823 *
14228410 824 * @param ifIndex interface index to match
71ea7674 825 * @return pointer to interface object or NULL if appropriate interface couldn't be found
7946bd7c 826 */
c75e9ee4 827Interface *Node::findInterfaceByIndex(UINT32 ifIndex)
5039dede 828{
db091a1f 829 lockChildList(false);
274d9c7a 830 for(int i = 0; i < m_childList->size(); i++)
db091a1f 831 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
5039dede 832 {
274d9c7a 833 Interface *pInterface = (Interface *)m_childList->get(i);
5f8890c1 834 if (pInterface->getIfIndex() == ifIndex)
5039dede 835 {
db091a1f 836 unlockChildList();
c75e9ee4 837 return pInterface;
5039dede
AK
838 }
839 }
db091a1f 840 unlockChildList();
5039dede
AK
841 return NULL;
842}
843
7946bd7c
VK
844/**
845 * Find interface by name or description
846 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
847 */
c75e9ee4 848Interface *Node::findInterfaceByName(const TCHAR *name)
630e15d6 849{
cf1d689e
VK
850 if ((name == NULL) || (name[0] == 0))
851 return NULL;
852
630e15d6
VK
853 Interface *pInterface;
854
db091a1f 855 lockChildList(false);
274d9c7a 856 for(int i = 0; i < m_childList->size(); i++)
db091a1f 857 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
630e15d6 858 {
db091a1f 859 pInterface = (Interface *)m_childList->get(i);
5f8890c1 860 if (!_tcsicmp(pInterface->getName(), name) || !_tcsicmp(pInterface->getDescription(), name))
630e15d6 861 {
db091a1f 862 unlockChildList();
630e15d6
VK
863 return pInterface;
864 }
865 }
db091a1f 866 unlockChildList();
630e15d6
VK
867 return NULL;
868}
869
7946bd7c
VK
870/**
871 * Find interface by slot/port pair
872 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
873 */
967893bb 874Interface *Node::findInterfaceBySlotAndPort(UINT32 slot, UINT32 port)
3f8c54e7 875{
db091a1f 876 lockChildList(false);
274d9c7a 877 for(int i = 0; i < m_childList->size(); i++)
db091a1f 878 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
3f8c54e7 879 {
274d9c7a 880 Interface *pInterface = (Interface *)m_childList->get(i);
5f8890c1 881 if (pInterface->isPhysicalPort() && (pInterface->getSlotNumber() == slot) && (pInterface->getPortNumber() == port))
3f8c54e7 882 {
db091a1f 883 unlockChildList();
3f8c54e7
VK
884 return pInterface;
885 }
886 }
db091a1f 887 unlockChildList();
3f8c54e7
VK
888 return NULL;
889}
890
7946bd7c
VK
891/**
892 * Find interface by MAC address
893 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
894 */
eec253a8
VK
895Interface *Node::findInterfaceByMAC(const BYTE *macAddr)
896{
8f26db67 897 Interface *iface = NULL;
db091a1f
VK
898 lockChildList(false);
899 for(int i = 0; i < m_childList->size(); i++)
900 {
901 NetObj *curr = m_childList->get(i);
902 if (curr->getObjectClass() == OBJECT_INTERFACE)
eec253a8 903 {
5f8890c1 904 if (!memcmp(((Interface *)curr)->getMacAddr(), macAddr, MAC_ADDR_LENGTH))
eec253a8 905 {
db091a1f 906 iface = (Interface *)curr;
8f26db67 907 break;
eec253a8
VK
908 }
909 }
db091a1f
VK
910 }
911 unlockChildList();
8f26db67 912 return iface;
eec253a8
VK
913}
914
7946bd7c
VK
915/**
916 * Find interface by IP address
917 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
918 */
c75e9ee4 919Interface *Node::findInterfaceByIP(const InetAddress& addr)
eec253a8 920{
c75e9ee4 921 if (!addr.isValid())
5f8890c1 922 return NULL;
eec253a8 923
db091a1f
VK
924 lockChildList(false);
925 for(int i = 0; i < m_childList->size(); i++)
926 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
eec253a8 927 {
db091a1f 928 Interface *pInterface = (Interface *)m_childList->get(i);
c30c0c0f 929 if (pInterface->getIpAddressList()->hasAddress(addr))
eec253a8 930 {
db091a1f 931 unlockChildList();
eec253a8
VK
932 return pInterface;
933 }
934 }
db091a1f 935 unlockChildList();
eec253a8
VK
936 return NULL;
937}
938
7946bd7c
VK
939/**
940 * Find interface by bridge port number
941 */
967893bb 942Interface *Node::findBridgePort(UINT32 bridgePortNumber)
eec253a8 943{
db091a1f
VK
944 lockChildList(false);
945 for(int i = 0; i < m_childList->size(); i++)
946 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
eec253a8 947 {
db091a1f 948 Interface *pInterface = (Interface *)m_childList->get(i);
5f8890c1 949 if (pInterface->getBridgePortNumber() == bridgePortNumber)
eec253a8 950 {
db091a1f 951 unlockChildList();
eec253a8
VK
952 return pInterface;
953 }
954 }
db091a1f 955 unlockChildList();
eec253a8
VK
956 return NULL;
957}
958
7946bd7c
VK
959/**
960 * Find connection point for node
961 */
75ebb063 962NetObj *Node::findConnectionPoint(UINT32 *localIfId, BYTE *localMacAddr, int *type)
f42b8099 963{
5f8890c1 964 NetObj *cp = NULL;
db091a1f
VK
965 lockChildList(false);
966 for(int i = 0; i < m_childList->size(); i++)
d0b5d358 967 {
db091a1f 968 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
f42b8099 969 {
db091a1f 970 Interface *iface = (Interface *)m_childList->get(i);
5f8890c1
AK
971 cp = FindInterfaceConnectionPoint(iface->getMacAddr(), type);
972 if (cp != NULL)
973 {
974 *localIfId = iface->getId();
975 memcpy(localMacAddr, iface->getMacAddr(), MAC_ADDR_LENGTH);
976 break;
977 }
978 }
d0b5d358 979 }
db091a1f 980 unlockChildList();
f42b8099
VK
981 return cp;
982}
983
a3050773 984/**
8f26db67
VK
985 * Find attached access point by MAC address
986 */
987AccessPoint *Node::findAccessPointByMAC(const BYTE *macAddr)
988{
989 AccessPoint *ap = NULL;
db091a1f
VK
990 lockChildList(false);
991 for(int i = 0; i < m_childList->size(); i++)
992 {
993 NetObj *curr = m_childList->get(i);
994 if (curr->getObjectClass() == OBJECT_ACCESSPOINT)
8f26db67 995 {
db091a1f 996 if (!memcmp(((AccessPoint *)curr)->getMacAddr(), macAddr, MAC_ADDR_LENGTH))
8f26db67 997 {
db091a1f 998 ap = (AccessPoint *)curr;
8f26db67
VK
999 break;
1000 }
1001 }
db091a1f
VK
1002 }
1003 unlockChildList();
8f26db67
VK
1004 return ap;
1005}
1006
1007/**
1008 * Find access point by radio ID (radio interface index)
1009 */
1010AccessPoint *Node::findAccessPointByRadioId(int rfIndex)
1011{
1012 AccessPoint *ap = NULL;
db091a1f
VK
1013 lockChildList(false);
1014 for(int i = 0; i < m_childList->size(); i++)
1015 {
1016 NetObj *curr = m_childList->get(i);
1017 if (curr->getObjectClass() == OBJECT_ACCESSPOINT)
8f26db67 1018 {
db091a1f 1019 if (((AccessPoint *)curr)->isMyRadio(rfIndex))
8f26db67 1020 {
db091a1f 1021 ap = (AccessPoint *)curr;
8f26db67
VK
1022 break;
1023 }
1024 }
db091a1f
VK
1025 }
1026 unlockChildList();
8f26db67
VK
1027 return ap;
1028}
1029
1030/**
386f88e3
VK
1031 * Find attached access point by BSSID
1032 */
1033AccessPoint *Node::findAccessPointByBSSID(const BYTE *bssid)
1034{
1035 AccessPoint *ap = NULL;
db091a1f
VK
1036 lockChildList(false);
1037 for(int i = 0; i < m_childList->size(); i++)
1038 {
1039 NetObj *curr = m_childList->get(i);
1040 if (curr->getObjectClass() == OBJECT_ACCESSPOINT)
386f88e3 1041 {
db091a1f
VK
1042 if (!memcmp(((AccessPoint *)curr)->getMacAddr(), bssid, MAC_ADDR_LENGTH) ||
1043 ((AccessPoint *)curr)->isMyRadio(bssid))
386f88e3 1044 {
db091a1f 1045 ap = (AccessPoint *)curr;
386f88e3
VK
1046 break;
1047 }
1048 }
db091a1f
VK
1049 }
1050 unlockChildList();
386f88e3
VK
1051 return ap;
1052}
1053
1054/**
a3050773
VK
1055 * Check if given IP address is one of node's interfaces
1056 */
c75e9ee4 1057bool Node::isMyIP(const InetAddress& addr)
5039dede 1058{
db091a1f
VK
1059 lockChildList(false);
1060 for(int i = 0; i < m_childList->size(); i++)
1061 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
5039dede 1062 {
db091a1f 1063 if (((Interface *)m_childList->get(i))->getIpAddressList()->hasAddress(addr))
5039dede 1064 {
db091a1f 1065 unlockChildList();
c75e9ee4 1066 return true;
5039dede
AK
1067 }
1068 }
db091a1f 1069 unlockChildList();
c75e9ee4 1070 return false;
5039dede
AK
1071}
1072
a3050773 1073/**
e55ff6f9
VK
1074 * Filter interface - should return true if system should proceed with interface creation
1075 */
1076bool Node::filterInterface(InterfaceInfo *info)
1077{
1dbf4905 1078 NXSL_VM *vm = CreateServerScriptVM(_T("Hook::CreateInterface"));
e55ff6f9
VK
1079 if (vm == NULL)
1080 {
1081 DbgPrintf(7, _T("Node::filterInterface(%s [%u]): hook script \"Hook::CreateInterface\" not found"), m_name, m_id);
1082 return true;
1083 }
1084
1085 Interface *iface;
1086 if (info->name[0] != 0)
26cfeea3 1087 {
e55ff6f9 1088 iface = new Interface(info->name, (info->description[0] != 0) ? info->description : info->name,
a191c634 1089 info->index, info->ipAddrList, info->type, m_zoneUIN);
26cfeea3 1090 }
e55ff6f9 1091 else
26cfeea3 1092 {
a191c634 1093 iface = new Interface(info->ipAddrList, m_zoneUIN, false);
26cfeea3 1094 }
e55ff6f9
VK
1095 iface->setMacAddr(info->macAddr, false);
1096 iface->setBridgePortNumber(info->bridgePort);
1097 iface->setSlotNumber(info->slot);
1098 iface->setPortNumber(info->port);
1099 iface->setPhysicalPortFlag(info->isPhysicalPort);
1100 iface->setManualCreationFlag(false);
1101 iface->setSystemFlag(info->isSystem);
1102 iface->setMTU(info->mtu);
1103 iface->setSpeed(info->speed);
1104 iface->setIfTableSuffix(info->ifTableSuffixLength, info->ifTableSuffix);
1105
1106 bool pass = true;
1107 NXSL_Value *argv = new NXSL_Value(new NXSL_Object(&g_nxslInterfaceClass, iface));
1108 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, this)));
1109 if (vm->run(1, &argv))
1110 {
1111 NXSL_Value *result = vm->getResult();
1112 if ((result != NULL) && result->isInteger())
1113 {
1114 pass = (result->getValueAsInt32() != 0);
1115 }
1116 }
1117 else
1118 {
1119 DbgPrintf(4, _T("Node::filterInterface(%s [%u]): hook script execution error: %s"), m_name, m_id, vm->getErrorText());
1120 }
1121 delete vm;
1122 delete iface;
1123
1124 DbgPrintf(6, _T("Node::filterInterface(%s [%u]): interface \"%s\" (ifIndex=%d) %s by filter"),
1125 m_name, m_id, info->name, info->index, pass ? _T("accepted") : _T("rejected"));
1126 return pass;
1127}
1128
1129/**
e95680e5
VK
1130 * Create new interface - convenience wrapper
1131 */
c77bdd19 1132Interface *Node::createNewInterface(const InetAddress& ipAddr, BYTE *macAddr, bool fakeInterface)
e95680e5 1133{
c30c0c0f
VK
1134 InterfaceInfo info(1);
1135 info.ipAddrList.add(ipAddr);
e95680e5
VK
1136 if (macAddr != NULL)
1137 memcpy(info.macAddr, macAddr, MAC_ADDR_LENGTH);
c77bdd19 1138 return createNewInterface(&info, false, fakeInterface);
e95680e5
VK
1139}
1140
1141/**
a3050773
VK
1142 * Create new interface
1143 */
c77bdd19 1144Interface *Node::createNewInterface(InterfaceInfo *info, bool manuallyCreated, bool fakeInterface)
5039dede 1145{
5f8890c1 1146 bool bSyntheticMask = false;
c30c0c0f 1147 TCHAR buffer[64];
5039dede 1148
5f8890c1 1149 DbgPrintf(5, _T("Node::createNewInterface(\"%s\", %d, %d, bp=%d, slot=%d, port=%d) called for node %s [%d]"),
c30c0c0f
VK
1150 info->name, info->index, info->type, info->bridgePort, info->slot, info->port, m_name, m_id);
1151 for(int i = 0; i < info->ipAddrList.size(); i++)
1152 {
1153 const InetAddress& addr = info->ipAddrList.get(i);
1154 DbgPrintf(5, _T("Node::createNewInterface(%s): IP address %s/%d"), info->name, addr.toString(buffer), addr.getMaskBits());
1155 }
5039dede
AK
1156
1157 // Find subnet to place interface object to
5f8890c1 1158 if (info->type != IFTYPE_SOFTWARE_LOOPBACK)
5039dede 1159 {
5f8890c1 1160 Cluster *pCluster = getMyCluster();
c30c0c0f
VK
1161 for(int i = 0; i < info->ipAddrList.size(); i++)
1162 {
1163 InetAddress addr = info->ipAddrList.get(i);
1164 bool addToSubnet = addr.isValidUnicast() && ((pCluster == NULL) || !pCluster->isSyncAddr(addr));
5f8890c1
AK
1165 DbgPrintf(5, _T("Node::createNewInterface: node=%s [%d] ip=%s/%d cluster=%s [%d] add=%s"),
1166 m_name, m_id, addr.toString(buffer), addr.getMaskBits(),
c30c0c0f
VK
1167 (pCluster != NULL) ? pCluster->getName() : _T("(null)"),
1168 (pCluster != NULL) ? pCluster->getId() : 0, addToSubnet ? _T("yes") : _T("no"));
5f8890c1
AK
1169 if (addToSubnet)
1170 {
a191c634 1171 Subnet *pSubnet = FindSubnetForNode(m_zoneUIN, addr);
5f8890c1
AK
1172 if (pSubnet == NULL)
1173 {
1174 // Check if netmask is 0 (detect), and if yes, create
1175 // new subnet with default mask
c30c0c0f 1176 if (addr.getMaskBits() == 0)
5f8890c1
AK
1177 {
1178 bSyntheticMask = true;
1179 addr.setMaskBits((addr.getFamily() == AF_INET) ? ConfigReadInt(_T("DefaultSubnetMaskIPv4"), 24) : ConfigReadInt(_T("DefaultSubnetMaskIPv6"), 64));
5cf8497c 1180 info->ipAddrList.replace(addr);
5f8890c1 1181 }
5039dede 1182
5f8890c1 1183 // Create new subnet object
c30c0c0f 1184 if (addr.getHostBits() >= 2)
5f8890c1
AK
1185 {
1186 pSubnet = createSubnet(addr, bSyntheticMask);
1187 if (bSyntheticMask)
1188 {
1189 // createSubnet may adjust address mask bits
1190 info->ipAddrList.replace(addr);
1191 }
1192 }
1193 }
1194 else
1195 {
1196 // Set correct netmask if we were asked for it
c30c0c0f 1197 if (addr.getMaskBits() == 0)
5f8890c1
AK
1198 {
1199 bSyntheticMask = pSubnet->isSyntheticMask();
5cf8497c
VK
1200 addr.setMaskBits(pSubnet->getIpAddress().getMaskBits());
1201 info->ipAddrList.replace(addr);
5f8890c1
AK
1202 }
1203 }
c30c0c0f
VK
1204 if (pSubnet != NULL)
1205 {
1206 pSubnet->addNode(this);
1207 }
1208 } // addToSubnet
5f8890c1 1209 } // loop by address list
5039dede
AK
1210 }
1211
1212 // Create interface object
acaa7447 1213 Interface *iface;
e95680e5 1214 if (info->name[0] != 0)
acaa7447 1215 iface = new Interface(info->name, (info->description[0] != 0) ? info->description : info->name,
a191c634 1216 info->index, info->ipAddrList, info->type, m_zoneUIN);
5039dede 1217 else
a191c634 1218 iface = new Interface(info->ipAddrList, m_zoneUIN, bSyntheticMask);
acaa7447
VK
1219 iface->setMacAddr(info->macAddr, false);
1220 iface->setBridgePortNumber(info->bridgePort);
1221 iface->setSlotNumber(info->slot);
1222 iface->setPortNumber(info->port);
1223 iface->setPhysicalPortFlag(info->isPhysicalPort);
1224 iface->setManualCreationFlag(manuallyCreated);
1225 iface->setSystemFlag(info->isSystem);
1226 iface->setMTU(info->mtu);
1227 iface->setSpeed(info->speed);
1228 iface->setIfTableSuffix(info->ifTableSuffixLength, info->ifTableSuffix);
5039dede 1229
c908b63b
VK
1230 int defaultExpectedState = ConfigReadInt(_T("DefaultInterfaceExpectedState"), IF_DEFAULT_EXPECTED_STATE_UP);
1231 switch(defaultExpectedState)
1232 {
1233 case IF_DEFAULT_EXPECTED_STATE_AUTO:
acaa7447 1234 iface->setExpectedState(fakeInterface ? IF_EXPECTED_STATE_UP : IF_EXPECTED_STATE_AUTO);
c908b63b
VK
1235 break;
1236 case IF_DEFAULT_EXPECTED_STATE_IGNORE:
acaa7447 1237 iface->setExpectedState(IF_EXPECTED_STATE_IGNORE);
c908b63b
VK
1238 break;
1239 default:
acaa7447 1240 iface->setExpectedState(IF_EXPECTED_STATE_UP);
c908b63b
VK
1241 break;
1242 }
1243
5039dede 1244 // Insert to objects' list and generate event
acaa7447
VK
1245 NetObjInsert(iface, true, false);
1246 addInterface(iface);
01152a54 1247 if (!m_isHidden)
acaa7447
VK
1248 iface->unhide();
1249 if (!iface->isSystem())
5039dede 1250 {
acaa7447
VK
1251 const InetAddress& addr = iface->getFirstIpAddress();
1252 PostEvent(EVENT_INTERFACE_ADDED, m_id, "dsAdd", iface->getId(),
1253 iface->getName(), &addr, addr.getMaskBits(), iface->getIfIndex());
5039dede 1254 }
9214177b 1255
acaa7447 1256 return iface;
5039dede
AK
1257}
1258
a3050773
VK
1259/**
1260 * Delete interface from node
1261 */
c30c0c0f 1262void Node::deleteInterface(Interface *iface)
5039dede 1263{
5f8890c1 1264 DbgPrintf(5, _T("Node::deleteInterface(node=%s [%d], interface=%s [%d])"), m_name, m_id, iface->getName(), iface->getId());
dfb38baf 1265
5039dede 1266 // Check if we should unlink node from interface's subnet
c30c0c0f 1267 if (!iface->isExcludedFromTopology())
5039dede 1268 {
c30c0c0f
VK
1269 const ObjectArray<InetAddress> *list = iface->getIpAddressList()->getList();
1270 for(int i = 0; i < list->size(); i++)
1271 {
1272 bool doUnlink = true;
1273 const InetAddress *addr = list->get(i);
5039dede 1274
db091a1f
VK
1275 lockChildList(false);
1276 for(int j = 0; j < m_childList->size(); j++)
1277 {
6e81bd95 1278 NetObj *curr = m_childList->get(j);
db091a1f
VK
1279 if ((curr->getObjectClass() == OBJECT_INTERFACE) && (curr != iface) &&
1280 ((Interface *)curr)->getIpAddressList()->findSameSubnetAddress(*addr).isValid())
c30c0c0f
VK
1281 {
1282 doUnlink = false;
1283 break;
1284 }
db091a1f
VK
1285 }
1286 unlockChildList();
4d2c3a54 1287
c30c0c0f 1288 if (doUnlink)
5039dede 1289 {
c30c0c0f 1290 // Last interface in subnet, should unlink node
a191c634 1291 Subnet *pSubnet = FindSubnetByIP(m_zoneUIN, addr->getSubnetAddress());
c30c0c0f
VK
1292 if (pSubnet != NULL)
1293 {
1f8be1f4
VK
1294 deleteParent(pSubnet);
1295 pSubnet->deleteChild(this);
c30c0c0f 1296 }
5f8890c1
AK
1297 DbgPrintf(5, _T("Node::deleteInterface(node=%s [%d], interface=%s [%d]): unlinked from subnet %s [%d]"),
1298 m_name, m_id, iface->getName(), iface->getId(),
1299 (pSubnet != NULL) ? pSubnet->getName() : _T("(null)"),
1300 (pSubnet != NULL) ? pSubnet->getId() : 0);
5039dede
AK
1301 }
1302 }
1303 }
5f8890c1 1304 iface->deleteObject();
5039dede
AK
1305}
1306
7946bd7c
VK
1307/**
1308 * Calculate node status based on child objects status
1309 */
27f9598d 1310void Node::calculateCompoundStatus(BOOL bForcedRecalc)
5039dede 1311{
db091a1f 1312 int iOldStatus = m_status;
967893bb 1313 static UINT32 dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_WARNING,
67c45b4d 1314 EVENT_NODE_MINOR, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
5039dede
AK
1315 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
1316
f94d5259 1317 DataCollectionTarget::calculateCompoundStatus(bForcedRecalc);
db091a1f
VK
1318 if (m_status != iOldStatus)
1319 PostEvent(dwEventCodes[m_status], m_id, "d", iOldStatus);
5039dede
AK
1320}
1321
a5ee7b3b
VK
1322/**
1323 * Perform status poll on node
1324 */
60e96280 1325void Node::statusPoll(PollerInfo *poller, ClientSession *pSession, UINT32 rqId)
5039dede 1326{
91b3cba9 1327 if (m_runtimeFlags & DCDF_DELETE_IN_PROGRESS)
5f8890c1 1328 {
60e96280 1329 if (rqId == 0)
91b3cba9 1330 m_runtimeFlags &= ~DCDF_QUEUED_FOR_STATUS_POLL;
5f8890c1
AK
1331 return;
1332 }
46117060 1333
5f8890c1
AK
1334 if (IsShutdownInProgress())
1335 return;
9fc9ec2c 1336
a0cc56b3 1337 UINT32 oldCapabilities = m_capabilities;
1338 UINT32 oldState = m_state;
5039dede 1339 NetObj *pPollerNode = NULL, **ppPollList;
5f8890c1
AK
1340 SNMP_Transport *pTransport;
1341 Cluster *pCluster;
5039dede
AK
1342 time_t tNow, tExpire;
1343
c1482463 1344 Queue *pQueue = new Queue; // Delayed event queue
208d7427 1345 poller->setStatus(_T("wait for lock"));
7c521895 1346 pollerLock();
88dc9091
VK
1347
1348 if (IsShutdownInProgress())
1349 {
1350 delete pQueue;
1351 pollerUnlock();
1352 return;
1353 }
1354
c59466d2 1355 m_pollRequestor = pSession;
60e96280 1356 sendPollerMsg(rqId, _T("Starting status poll for node %s\r\n"), m_name);
c0183539 1357 nxlog_debug(5, _T("Starting status poll for node %s (ID: %d)"), m_name, m_id);
5039dede
AK
1358
1359 // Read capability expiration time and current time
1360 tExpire = (time_t)ConfigReadULong(_T("CapabilityExpirationTime"), 604800);
1361 tNow = time(NULL);
1362
7b94bd4b
EJ
1363 bool agentConnected = false;
1364
c0183539
VK
1365 int retryCount = 5;
1366
5039dede 1367restart_agent_check:
69a4eaa6 1368 if (g_flags & AF_RESOLVE_IP_FOR_EACH_STATUS_POLL)
385b1f20 1369 {
1370 updatePrimaryIpAddr();
1371 }
1372
3e7571a9
EJ
1373 int requiredPolls = (m_requiredPollCount > 0) ? m_requiredPollCount : g_requiredPolls;
1374
385b1f20 1375 // Check SNMP agent connectivity
91b3cba9 1376 if ((m_capabilities & NC_IS_SNMP) && (!(m_flags & NF_DISABLE_SNMP)) && m_ipAddress.isValidUnicast())
5039dede
AK
1377 {
1378 TCHAR szBuffer[256];
967893bb 1379 UINT32 dwResult;
5039dede 1380
c0183539 1381 nxlog_debug(6, _T("StatusPoll(%s): check SNMP"), m_name);
5f8890c1
AK
1382 pTransport = createSnmpTransport();
1383 if (pTransport != NULL)
5039dede 1384 {
208d7427 1385 poller->setStatus(_T("check SNMP"));
60e96280 1386 sendPollerMsg(rqId, _T("Checking SNMP agent connectivity\r\n"));
9eeed592
VK
1387 const TCHAR *testOid = m_customAttributes.get(_T("snmp.testoid"));
1388 if (testOid == NULL)
1389 {
1390 testOid = _T(".1.3.6.1.2.1.1.2.0");
1391 }
5f8890c1 1392 dwResult = SnmpGet(m_snmpVersion, pTransport, testOid, NULL, 0, szBuffer, sizeof(szBuffer), 0);
61b359bc 1393 if ((dwResult == SNMP_ERR_SUCCESS) || (dwResult == SNMP_ERR_NO_OBJECT))
5039dede 1394 {
91b3cba9 1395 if (m_state & NSF_SNMP_UNREACHABLE)
5039dede 1396 {
3e7571a9
EJ
1397 m_pollCountSNMP++;
1398 if (m_pollCountSNMP >= requiredPolls)
1399 {
1400 m_state &= ~NSF_SNMP_UNREACHABLE;
1401 PostEventEx(pQueue, EVENT_SNMP_OK, m_id, NULL);
1a4b84a3 1402 sendPollerMsg(rqId, POLLER_INFO _T("Connectivity with SNMP agent restored\r\n"));
3e7571a9
EJ
1403 m_pollCountSNMP = 0;
1404 }
1405
5039dede 1406 }
3e7571a9
EJ
1407 else
1408 m_pollCountSNMP = 0;
aa379fa0
VK
1409
1410 // Update authoritative engine data for SNMPv3
1411 if ((pTransport->getSnmpVersion() == SNMP_VERSION_3) && (pTransport->getAuthoritativeEngine() != NULL))
1412 {
5f8890c1 1413 lockProperties();
aa379fa0
VK
1414 m_snmpSecurity->setAuthoritativeEngine(*pTransport->getAuthoritativeEngine());
1415 unlockProperties();
1416 }
5039dede 1417 }
c0183539 1418 else if ((dwResult == SNMP_ERR_ENGINE_ID) && (m_snmpVersion == SNMP_VERSION_3) && (retryCount > 0))
23c1cb5d
VK
1419 {
1420 // Reset authoritative engine data
1421 lockProperties();
1422 m_snmpSecurity->setAuthoritativeEngine(SNMP_Engine());
1423 unlockProperties();
c0183539
VK
1424 delete pTransport;
1425 retryCount--;
23c1cb5d
VK
1426 goto restart_agent_check;
1427 }
5039dede
AK
1428 else
1429 {
c0183539
VK
1430 if (pTransport->isProxyTransport() && (dwResult == SNMP_ERR_COMM))
1431 {
3e7571a9 1432
c0183539
VK
1433 AgentConnectionEx *pconn = acquireProxyConnection(SNMP_PROXY, true);
1434 if (pconn != NULL)
1435 {
1436 pconn->decRefCount();
1437 if (retryCount > 0)
1438 {
1439 retryCount--;
1440 delete pTransport;
1441 goto restart_agent_check;
1442 }
1443 }
1444 }
1445
3e7571a9 1446 nxlog_debug(6, _T("StatusPoll(%s): got communication error on proxy transport, checking connection to proxy. Poll count: %d of %d"), m_name, m_pollCountSNMP, m_requiredPollCount);
1a4b84a3 1447 sendPollerMsg(rqId, POLLER_ERROR _T("SNMP agent unreachable\r\n"));
91b3cba9 1448 if (m_state & NSF_SNMP_UNREACHABLE)
61b359bc 1449 {
a0cc56b3 1450 if ((tNow > m_failTimeSNMP + tExpire) && (!(m_state & DCSF_UNREACHABLE)))
61b359bc 1451 {
91b3cba9 1452 m_capabilities &= ~NC_IS_SNMP;
1453 m_state &= ~NSF_SNMP_UNREACHABLE;
53985424 1454 m_snmpObjectId[0] = 0;
60e96280 1455 sendPollerMsg(rqId, POLLER_WARNING _T("Attribute isSNMP set to FALSE\r\n"));
61b359bc
VK
1456 }
1457 }
1458 else
1459 {
3e7571a9
EJ
1460 m_pollCountSNMP++;
1461 if (m_pollCountSNMP >= requiredPolls)
1462 {
1463 m_state |= NSF_SNMP_UNREACHABLE;
1464 PostEventEx(pQueue, EVENT_SNMP_FAIL, m_id, NULL);
1465 m_failTimeSNMP = tNow;
1466 m_pollCountSNMP = 0;
1467 }
61b359bc 1468 }
5039dede 1469 }
5f8890c1 1470 delete pTransport;
61b359bc
VK
1471 }
1472 else
1473 {
c0183539 1474 nxlog_debug(6, _T("StatusPoll(%s): cannot create SNMP transport"), m_name);
5039dede 1475 }
c0183539 1476 nxlog_debug(6, _T("StatusPoll(%s): SNMP check finished"), m_name);
5039dede
AK
1477 }
1478
1479 // Check native agent connectivity
91b3cba9 1480 if ((m_capabilities & NC_IS_NATIVE_AGENT) && (!(m_flags & NF_DISABLE_NXCP)))
5039dede 1481 {
c0183539 1482 nxlog_debug(6, _T("StatusPoll(%s): checking agent"), m_name);
208d7427 1483 poller->setStatus(_T("check agent"));
60e96280 1484 sendPollerMsg(rqId, _T("Checking NetXMS agent connectivity\r\n"));
c3acd0f6 1485
5f8890c1 1486 UINT32 error, socketError;
a01c2a20 1487 bool newConnection;
5f8890c1 1488 agentLock();
a01c2a20 1489 if (connectToAgent(&error, &socketError, &newConnection, true))
5039dede 1490 {
c0183539 1491 nxlog_debug(7, _T("StatusPoll(%s): connected to agent"), m_name);
91b3cba9 1492 if (m_state & NSF_AGENT_UNREACHABLE)
5039dede 1493 {
3e7571a9
EJ
1494 m_pollCountAgent++;
1495 if (m_pollCountAgent >= requiredPolls)
1496 {
1497 m_state &= ~NSF_AGENT_UNREACHABLE;
1498 PostEventEx(pQueue, EVENT_AGENT_OK, m_id, NULL);
1a4b84a3 1499 sendPollerMsg(rqId, POLLER_INFO _T("Connectivity with NetXMS agent restored\r\n"));
3e7571a9
EJ
1500 m_pollCountAgent = 0;
1501 }
5039dede 1502 }
3e7571a9
EJ
1503 else
1504 m_pollCountAgent = 0;
7b94bd4b 1505 agentConnected = true;
5039dede
AK
1506 }
1507 else
1508 {
3e7571a9 1509 nxlog_debug(6, _T("StatusPoll(%s): agent unreachable, error=%d, socketError=%d. Poll count %d of %d"), m_name, (int)error, (int)socketError, m_pollCountAgent, m_requiredPollCount);
1a4b84a3 1510 sendPollerMsg(rqId, POLLER_ERROR _T("NetXMS agent unreachable\r\n"));
91b3cba9 1511 if (m_state & NSF_AGENT_UNREACHABLE)
5039dede 1512 {
a0cc56b3 1513 if ((tNow > m_failTimeAgent + tExpire) && !(m_state & DCSF_UNREACHABLE))
5039dede 1514 {
91b3cba9 1515 m_capabilities &= ~NC_IS_NATIVE_AGENT;
1516 m_state &= ~NSF_AGENT_UNREACHABLE;
53985424
VK
1517 m_platformName[0] = 0;
1518 m_agentVersion[0] = 0;
60e96280 1519 sendPollerMsg(rqId, POLLER_WARNING _T("Attribute isNetXMSAgent set to FALSE\r\n"));
5039dede
AK
1520 }
1521 }
1522 else
1523 {
3e7571a9
EJ
1524 m_pollCountAgent++;
1525 if (m_pollCountAgent >= requiredPolls)
1526 {
1527 m_state |= NSF_AGENT_UNREACHABLE;
1528 PostEventEx(pQueue, EVENT_AGENT_FAIL, m_id, NULL);
1529 m_failTimeAgent = tNow;
1530 //cancel file monitoring locally(on agent it is canceled if agent have fallen)
1531 g_monitoringList.removeDisconnectedNode(m_id);
1532 m_pollCountAgent = 0;
1533 }
5039dede
AK
1534 }
1535 }
5f8890c1 1536 agentUnlock();
c0183539 1537 nxlog_debug(7, _T("StatusPoll(%s): agent check finished"), m_name);
f9f79a93
VK
1538
1539 // If file update connection is active, send NOP command to prevent disconnection by idle timeout
1540 AgentConnection *fileUpdateConnection;
1541 lockProperties();
1542 fileUpdateConnection = m_fileUpdateConn;
1543 if (fileUpdateConnection != NULL)
1544 fileUpdateConnection->incRefCount();
1545 unlockProperties();
1546 if (fileUpdateConnection != NULL)
1547 {
1548 nxlog_debug(6, _T("StatusPoll(%s): sending keepalive command on file monitoring connection"), m_name);
1549 fileUpdateConnection->nop();
1550 fileUpdateConnection->decRefCount();
1551 }
5039dede
AK
1552 }
1553
208d7427 1554 poller->setStatus(_T("prepare polling list"));
5039dede
AK
1555
1556 // Find service poller node object
c42b4551 1557 lockProperties();
9208c84b 1558 if (m_pollerNode != 0)
5039dede 1559 {
5f8890c1
AK
1560 UINT32 id = m_pollerNode;
1561 unlockProperties();
f3218755 1562 pPollerNode = FindObjectById(id);
5039dede
AK
1563 if (pPollerNode != NULL)
1564 {
c42b4551 1565 if (pPollerNode->getObjectClass() != OBJECT_NODE)
5039dede
AK
1566 pPollerNode = NULL;
1567 }
1568 }
5f8890c1
AK
1569 else
1570 {
1571 unlockProperties();
1572 }
5039dede
AK
1573
1574 // If nothing found, use management server
1575 if (pPollerNode == NULL)
1576 {
1577 pPollerNode = FindObjectById(g_dwMgmtNode);
1578 if (pPollerNode != NULL)
21c9acce 1579 pPollerNode->incRefCount();
5039dede
AK
1580 }
1581 else
1582 {
21c9acce 1583 pPollerNode->incRefCount();
5039dede
AK
1584 }
1585
1586 // Create polling list
db091a1f
VK
1587 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_childList->size());
1588 lockChildList(false);
274d9c7a
VK
1589 int pollListSize = 0;
1590 for(int i = 0; i < m_childList->size(); i++)
db091a1f
VK
1591 {
1592 NetObj *curr = m_childList->get(i);
1593 if (curr->getStatus() != STATUS_UNMANAGED)
5039dede 1594 {
db091a1f 1595 curr->incRefCount();
274d9c7a 1596 ppPollList[pollListSize++] = curr;
5039dede 1597 }
db091a1f
VK
1598 }
1599 unlockChildList();
5039dede
AK
1600
1601 // Poll interfaces and services
208d7427 1602 poller->setStatus(_T("child poll"));
c42b4551 1603 DbgPrintf(7, _T("StatusPoll(%s): starting child object poll"), m_name);
5f8890c1
AK
1604 pCluster = getMyCluster();
1605 pTransport = createSnmpTransport();
274d9c7a 1606 for(int i = 0; i < pollListSize; i++)
5039dede 1607 {
c42b4551 1608 switch(ppPollList[i]->getObjectClass())
5039dede
AK
1609 {
1610 case OBJECT_INTERFACE:
5f8890c1 1611 DbgPrintf(7, _T("StatusPoll(%s): polling interface %d [%s]"), m_name, ppPollList[i]->getId(), ppPollList[i]->getName());
60e96280 1612 ((Interface *)ppPollList[i])->statusPoll(pSession, rqId, pQueue, pCluster, pTransport, m_icmpProxy);
5039dede
AK
1613 break;
1614 case OBJECT_NETWORKSERVICE:
5f8890c1 1615 DbgPrintf(7, _T("StatusPoll(%s): polling network service %d [%s]"), m_name, ppPollList[i]->getId(), ppPollList[i]->getName());
60e96280 1616 ((NetworkService *)ppPollList[i])->statusPoll(pSession, rqId, (Node *)pPollerNode, pQueue);
5039dede 1617 break;
56d5289b 1618 case OBJECT_ACCESSPOINT:
5f8890c1 1619 DbgPrintf(7, _T("StatusPoll(%s): polling access point %d [%s]"), m_name, ppPollList[i]->getId(), ppPollList[i]->getName());
60e96280 1620 ((AccessPoint *)ppPollList[i])->statusPollFromController(pSession, rqId, pQueue, this, pTransport);
56d5289b 1621 break;
5039dede 1622 default:
c42b4551 1623 DbgPrintf(7, _T("StatusPoll(%s): skipping object %d [%s] class %d"), m_name, ppPollList[i]->getId(), ppPollList[i]->getName(), ppPollList[i]->getObjectClass());
5039dede
AK
1624 break;
1625 }
21c9acce 1626 ppPollList[i]->decRefCount();
5039dede 1627 }
5f8890c1 1628 delete pTransport;
cad063a5 1629 free(ppPollList);
c42b4551 1630 DbgPrintf(7, _T("StatusPoll(%s): finished child object poll"), m_name);
5039dede
AK
1631
1632 // Check if entire node is down
5f8890c1 1633 // This check is disabled for nodes without IP address
7b94bd4b
EJ
1634 // The only exception is node without valid address connected via agent tunnel
1635 if (m_ipAddress.isValidUnicast() || agentConnected)
5f8890c1
AK
1636 {
1637 bool allDown = true;
1638 lockChildList(false);
274d9c7a 1639 for(int i = 0; i < m_childList->size(); i++)
db091a1f
VK
1640 {
1641 NetObj *curr = m_childList->get(i);
1642 if ((curr->getObjectClass() == OBJECT_INTERFACE) &&
1643 (((Interface *)curr)->getAdminState() != IF_ADMIN_STATE_DOWN) &&
1644 (((Interface *)curr)->getConfirmedOperState() == IF_OPER_STATE_UP) &&
1645 (curr->getStatus() != STATUS_UNMANAGED))
1646 {
1647 allDown = false;
1648 break;
1649 }
1650 }
5f8890c1 1651 unlockChildList();
91b3cba9 1652 if (allDown && (m_capabilities & NC_IS_NATIVE_AGENT) &&
5f8890c1 1653 (!(m_flags & NF_DISABLE_NXCP)))
91b3cba9 1654 if (!(m_state & NSF_AGENT_UNREACHABLE))
5f8890c1 1655 allDown = false;
91b3cba9 1656 if (allDown && (m_capabilities & NC_IS_SNMP) &&
5f8890c1 1657 (!(m_flags & NF_DISABLE_SNMP)))
91b3cba9 1658 if (!(m_state & NSF_SNMP_UNREACHABLE))
59176978 1659 allDown = false;
c1482463 1660
3e7571a9 1661 DbgPrintf(2, _T("StatusPoll(%s): allDown=%s, statFlags=0x%08X"), m_name, allDown ? _T("true") : _T("false"), m_state);
5f8890c1
AK
1662 if (allDown)
1663 {
a0cc56b3 1664 if (!(m_state & DCSF_UNREACHABLE))
5f8890c1 1665 {
a0cc56b3 1666 m_state |= DCSF_UNREACHABLE;
5f8890c1
AK
1667 m_downSince = time(NULL);
1668 poller->setStatus(_T("check network path"));
60e96280 1669 if (checkNetworkPath(rqId))
5f8890c1 1670 {
a0cc56b3 1671 m_state |= DCSF_NETWORK_PATH_PROBLEM;
5f8890c1
AK
1672
1673 // Set interfaces and network services to UNKNOWN state
1674 lockChildList(false);
1675 for(int i = 0; i < m_childList->size(); i++)
1676 {
1677 NetObj *curr = m_childList->get(i);
3f71633b 1678 if ((curr->getObjectClass() == OBJECT_INTERFACE) || (curr->getObjectClass() == OBJECT_NETWORKSERVICE))
5f8890c1
AK
1679 {
1680 curr->resetStatus();
1681 }
1682 }
1683 unlockChildList();
1684
1685 // Clear delayed event queue
f4b2ebd3 1686 while(true)
5f8890c1 1687 {
f4b2ebd3
VK
1688 Event *e = (Event *)pQueue->get();
1689 if (e == NULL)
5f8890c1 1690 break;
f4b2ebd3 1691 delete e;
5f8890c1
AK
1692 }
1693 delete_and_null(pQueue);
1694
1695 PostEvent(EVENT_NODE_UNREACHABLE, m_id, NULL);
1696 }
1697 else
1698 {
1699 PostEvent(EVENT_NODE_DOWN, m_id, NULL);
1700 }
35a9f4a3 1701 g_monitoringList.removeDisconnectedNode(m_id);
60e96280 1702 sendPollerMsg(rqId, POLLER_ERROR _T("Node is unreachable\r\n"));
5f8890c1
AK
1703 }
1704 else
1705 {
60e96280 1706 sendPollerMsg(rqId, POLLER_WARNING _T("Node is still unreachable\r\n"));
5f8890c1
AK
1707 }
1708 }
1709 else
1710 {
1711 m_downSince = 0;
a0cc56b3 1712 if (m_state & DCSF_UNREACHABLE)
5f8890c1 1713 {
a0cc56b3 1714 int reason = (m_state & DCSF_NETWORK_PATH_PROBLEM) ? 1 : 0;
1715 m_state &= ~(DCSF_UNREACHABLE | NSF_SNMP_UNREACHABLE | NSF_AGENT_UNREACHABLE | DCSF_NETWORK_PATH_PROBLEM);
5f8890c1 1716 PostEvent(EVENT_NODE_UP, m_id, "d", reason);
60e96280 1717 sendPollerMsg(rqId, POLLER_INFO _T("Node recovered from unreachable state\r\n"));
5f8890c1
AK
1718 goto restart_agent_check;
1719 }
1720 else
1721 {
60e96280 1722 sendPollerMsg(rqId, POLLER_INFO _T("Node is connected\r\n"));
5f8890c1
AK
1723 }
1724 }
1725 }
5039dede 1726
71e4ed3a 1727 // Get uptime and update boot time
a0cc56b3 1728 if (!(m_state & DCSF_UNREACHABLE))
71e4ed3a
VK
1729 {
1730 TCHAR buffer[MAX_RESULT_LENGTH];
1731 if (getItemFromAgent(_T("System.Uptime"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1732 {
1733 m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0);
5f8890c1 1734 DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from agent"), m_name, m_id, (UINT32)m_bootTime);
71e4ed3a 1735 }
296ae03d 1736 else if (getItemFromSNMP(m_snmpPort, _T(".1.3.6.1.2.1.1.3.0"), MAX_RESULT_LENGTH, buffer, SNMP_RAWTYPE_NONE) == DCE_SUCCESS)
71e4ed3a
VK
1737 {
1738 m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0) / 100; // sysUpTime is in hundredths of a second
5f8890c1 1739 DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from SNMP"), m_name, m_id, (UINT32)m_bootTime);
71e4ed3a
VK
1740 }
1741 else
1742 {
5f8890c1 1743 DbgPrintf(5, _T("StatusPoll(%s [%d]): unable to get system uptime"), m_name, m_id);
71e4ed3a
VK
1744 }
1745 }
1746 else
1747 {
1748 m_bootTime = 0;
1749 }
1750
0ab347c0 1751 // Get agent uptime to check if it was restared
a0cc56b3 1752 if (!(m_state & DCSF_UNREACHABLE) && isNativeAgent())
0ab347c0 1753 {
1754 TCHAR buffer[MAX_RESULT_LENGTH];
1755 if (getItemFromAgent(_T("Agent.Uptime"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1756 {
1757 time_t oldAgentuptime = m_agentUpTime;
1758 m_agentUpTime = _tcstol(buffer, NULL, 0);
2e22746d 1759 if ((UINT32)oldAgentuptime > (UINT32)m_agentUpTime)
0ab347c0 1760 {
1761 //cancel file monitoring locally(on agent it is canceled if agent have fallen)
f9f79a93 1762 g_monitoringList.removeDisconnectedNode(m_id);
0ab347c0 1763 }
1764 }
1765 else
1766 {
c42b4551 1767 DbgPrintf(5, _T("StatusPoll(%s [%d]): unable to get agent uptime"), m_name, m_id);
f9f79a93 1768 g_monitoringList.removeDisconnectedNode(m_id);
0ab347c0 1769 m_agentUpTime = 0;
1770 }
1771 }
1772 else
1773 {
0ab347c0 1774 m_agentUpTime = 0;
1775 }
1776
2e22746d 1777 // Get geolocation
a0cc56b3 1778 if (!(m_state & DCSF_UNREACHABLE) && isNativeAgent())
2e22746d
VK
1779 {
1780 TCHAR buffer[MAX_RESULT_LENGTH];
1781 if (getItemFromAgent(_T("GPS.LocationData"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1782 {
1783 GeoLocation loc = GeoLocation::parseAgentData(buffer);
1784 if (loc.getType() != GL_UNSET)
1785 {
1786 DbgPrintf(5, _T("StatusPoll(%s [%d]): location set to %s, %s from agent"), m_name, m_id, loc.getLatitudeAsString(), loc.getLongitudeAsString());
3d48d1b4 1787 setGeoLocation(loc);
2e22746d
VK
1788 }
1789 }
1790 else
1791 {
1792 DbgPrintf(5, _T("StatusPoll(%s [%d]): unable to get system location"), m_name, m_id);
1793 }
1794 }
1795
849e464d 1796 // Get agent log and agent local database status
a0cc56b3 1797 if (!(m_state & DCSF_UNREACHABLE) && isNativeAgent())
b123ecb3 1798 {
1799 TCHAR buffer[MAX_RESULT_LENGTH];
7b30e5ae 1800 if (getItemFromAgent(_T("Agent.LogFile.Status"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
b123ecb3 1801 {
1802 UINT32 status = _tcstol(buffer, NULL, 0);
7b30e5ae
VK
1803 if (status != 0)
1804 PostEvent(EVENT_AGENT_LOG_PROBLEM, m_id, "ds", status, _T("could not open"));
b123ecb3 1805 }
1806 else
1807 {
7b30e5ae 1808 nxlog_debug(5, _T("StatusPoll(%s [%d]): unable to get agent log status"), m_name, m_id);
b123ecb3 1809 }
1810
7b30e5ae 1811 if (getItemFromAgent(_T("Agent.LocalDatabase.Status"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
b123ecb3 1812 {
1813 UINT32 status = _tcstol(buffer, NULL, 0);
1814 const TCHAR *statusDescription[3]= {
1815 _T("normal"),
1816 _T("could not open database"),
1817 _T("could not update database"),
1818 };
7b30e5ae
VK
1819 if (status != 0)
1820 PostEvent(EVENT_AGENT_LOCAL_DATABASE_PROBLEM, m_id, "ds", status, statusDescription[status]);
b123ecb3 1821 }
1822 else
1823 {
7b30e5ae 1824 nxlog_debug(5, _T("StatusPoll(%s [%d]): unable to get agent local database status"), m_name, m_id);
b123ecb3 1825 }
1826 }
1827
5039dede 1828 // Send delayed events and destroy delayed event queue
5f8890c1
AK
1829 if (pQueue != NULL)
1830 {
1831 ResendEvents(pQueue);
1832 delete pQueue;
1833 }
a5ee7b3b
VK
1834
1835 // Call hooks in loaded modules
967893bb 1836 for(UINT32 i = 0; i < g_dwNumModules; i++)
5f8890c1
AK
1837 {
1838 if (g_pModuleList[i].pfStatusPollHook != NULL)
1839 {
1840 DbgPrintf(5, _T("StatusPoll(%s [%d]): calling hook in module %s"), m_name, m_id, g_pModuleList[i].szName);
60e96280 1841 g_pModuleList[i].pfStatusPollHook(this, pSession, rqId, poller);
5f8890c1
AK
1842 }
1843 }
1844
1845 // Execute hook script
208d7427 1846 poller->setStatus(_T("hook"));
5f8890c1 1847 executeHookScript(_T("StatusPoll"));
a5ee7b3b 1848
208d7427 1849 poller->setStatus(_T("cleanup"));
5039dede 1850 if (pPollerNode != NULL)
21c9acce 1851 pPollerNode->decRefCount();
5039dede 1852
3d48d1b4 1853 if (oldCapabilities != m_capabilities)
a0cc56b3 1854 PostEvent(EVENT_NODE_CAPABILITIES_CHANGED, m_id, "xx", oldCapabilities, m_capabilities);
1855
1856 if (oldState != m_state || oldCapabilities != m_capabilities)
5039dede 1857 {
c42b4551 1858 lockProperties();
3d48d1b4 1859 setModified(MODIFY_NODE_PROPERTIES);
c42b4551 1860 unlockProperties();
5039dede
AK
1861 }
1862
27f9598d 1863 calculateCompoundStatus();
8573e935 1864 m_lastStatusPoll = time(NULL);
60e96280
VK
1865 sendPollerMsg(rqId, _T("Finished status poll for node %s\r\n"), m_name);
1866 sendPollerMsg(rqId, _T("Node status after poll is %s\r\n"), GetStatusAsText(m_status, true));
c59466d2 1867 m_pollRequestor = NULL;
60e96280 1868 if (rqId == 0)
91b3cba9 1869 m_runtimeFlags &= ~DCDF_QUEUED_FOR_STATUS_POLL;
7c521895 1870 pollerUnlock();
c42b4551 1871 DbgPrintf(5, _T("Finished status poll for node %s (ID: %d)"), m_name, m_id);
60e96280
VK
1872
1873 // Check if the node has to be deleted due to long downtime
1874 if (rqId == 0)
1875 {
1876 time_t unreachableDeleteDays = (time_t)ConfigReadInt(_T("DeleteUnreachableNodesPeriod"), 0);
1877 if ((unreachableDeleteDays > 0) && (m_downSince > 0) &&
1878 (time(NULL) - m_downSince > unreachableDeleteDays * 24 * 3600))
1879 {
1880 deleteObject();
1881 }
1882 }
5039dede
AK
1883}
1884
7946bd7c 1885/**
1babf64d 1886 * Check single element of network path
beae365a 1887 */
a7b1e779 1888bool Node::checkNetworkPathElement(UINT32 nodeId, const TCHAR *nodeType, bool isProxy, UINT32 requestId, bool secondPass)
beae365a 1889{
5f8890c1
AK
1890 Node *node = (Node *)FindObjectById(nodeId, OBJECT_NODE);
1891 if (node == NULL)
1892 return false;
1893
a7b1e779
VK
1894 nxlog_debug(6, _T("Node::checkNetworkPathElement(%s [%d]): found %s: %s [%d]"), m_name, m_id, nodeType, node->getName(), node->getId());
1895
1896 if (secondPass && (node->m_lastStatusPoll < time(NULL) - 1))
1897 {
1898 DbgPrintf(6, _T("Node::checkNetworkPathElement(%s [%d]): forced status poll on node %s [%d]"),
1899 m_name, m_id, node->getName(), node->getId());
1900 PollerInfo *poller = RegisterPoller(POLLER_TYPE_STATUS, node);
1901 poller->startExecution();
60e96280 1902 node->statusPoll(poller, NULL, 0);
a7b1e779
VK
1903 delete poller;
1904 }
1905
5f8890c1
AK
1906 if (node->isDown())
1907 {
1908 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): %s %s [%d] is down"),
1909 m_name, m_id, nodeType, node->getName(), node->getId());
a7b1e779 1910 sendPollerMsg(requestId, POLLER_WARNING _T(" %s %s is down\r\n"), nodeType, node->getName());
5f8890c1
AK
1911 return true;
1912 }
91b3cba9 1913 if (isProxy && node->isNativeAgent() && (node->getState() & NSF_AGENT_UNREACHABLE))
5f8890c1
AK
1914 {
1915 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): agent on %s %s [%d] is down"),
1916 m_name, m_id, nodeType, node->getName(), node->getId());
a7b1e779 1917 sendPollerMsg(requestId, POLLER_WARNING _T(" Agent on %s %s is down\r\n"), nodeType, node->getName());
5f8890c1
AK
1918 return true;
1919 }
5f8890c1 1920 return false;
beae365a
VK
1921}
1922
1923/**
a7b1e779 1924 * Check network path between node and management server to detect possible intermediate node failure - layer 2
c1482463
VK
1925 *
1926 * @return true if network path problems found
7946bd7c 1927 */
a7b1e779 1928bool Node::checkNetworkPathLayer2(UINT32 requestId, bool secondPass)
7946bd7c 1929{
5f8890c1 1930 time_t now = time(NULL);
67c45b4d 1931
5f8890c1 1932 // Check proxy node(s)
a191c634 1933 if (IsZoningEnabled() && (m_zoneUIN != 0))
5f8890c1 1934 {
a191c634 1935 Zone *zone = FindZoneByUIN(m_zoneUIN);
a7b1e779
VK
1936 if ((zone != NULL) && (zone->getProxyNodeId() != 0) && (zone->getProxyNodeId() != m_id))
1937 {
1938 if (checkNetworkPathElement(zone->getProxyNodeId(), _T("zone proxy"), true, requestId, secondPass))
1939 return true;
1940 }
5f8890c1 1941 }
beae365a 1942
5f8890c1 1943 // Check directly connected switch
a7b1e779 1944 sendPollerMsg(requestId, _T("Checking ethernet connectivity...\r\n"));
5f8890c1 1945 Interface *iface = findInterfaceByIP(m_ipAddress);
a7b1e779 1946 if (iface != NULL)
5f8890c1 1947 {
a7b1e779
VK
1948 if (iface->getPeerNodeId() != 0)
1949 {
1950 nxlog_debug(6, _T("Node::checkNetworkPath(%s [%d]): found interface object for primary IP: %s [%d]"), m_name, m_id, iface->getName(), iface->getId());
1951 if (checkNetworkPathElement(iface->getPeerNodeId(), _T("upstream switch"), false, requestId, secondPass))
1952 return true;
1953
1954 Node *switchNode = (Node *)FindObjectById(iface->getPeerNodeId(), OBJECT_NODE);
1955 Interface *switchIface = (Interface *)FindObjectById(iface->getPeerInterfaceId(), OBJECT_INTERFACE);
e31d9b18 1956 if ((switchNode != NULL) && (switchIface != NULL) && (switchIface->getExpectedState() != IF_EXPECTED_STATE_IGNORE) &&
a7b1e779
VK
1957 ((switchIface->getAdminState() == IF_ADMIN_STATE_DOWN) || (switchIface->getAdminState() == IF_ADMIN_STATE_TESTING) ||
1958 (switchIface->getOperState() == IF_OPER_STATE_DOWN) || (switchIface->getOperState() == IF_OPER_STATE_TESTING)))
1959 {
1960 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): upstream interface %s [%d] on switch %s [%d] is down"),
1961 m_name, m_id, switchIface->getName(), switchIface->getId(), switchNode->getName(), switchNode->getId());
1962 sendPollerMsg(requestId, POLLER_WARNING _T(" Upstream interface %s on node %s is down\r\n"), switchIface->getName(), switchNode->getName());
1963 return true;
1964 }
1965 }
1966 else
1967 {
1968 BYTE localMacAddr[MAC_ADDR_LENGTH];
1969 memcpy(localMacAddr, iface->getMacAddr(), MAC_ADDR_LENGTH);
1970 int type = 0;
1971 NetObj *cp = FindInterfaceConnectionPoint(localMacAddr, &type);
1972 if (cp != NULL)
1973 {
1974 nxlog_debug(6, _T("Node::checkNetworkPath(%s [%d]): found connection point: %s [%d]"), m_name, m_id, cp->getName(), cp->getId());
1975 if (secondPass)
1976 {
1977 Node *node = (cp->getObjectClass() == OBJECT_INTERFACE) ? ((Interface *)cp)->getParentNode() : ((AccessPoint *)cp)->getParentNode();
1978 if ((node != NULL) && !node->isDown() && (node->m_lastStatusPoll < now - 1))
1979 {
1980 nxlog_debug(6, _T("Node::checkNetworkPath(%s [%d]): forced status poll on node %s [%d]"),
1981 m_name, m_id, node->getName(), node->getId());
b297011c 1982 node->statusPollWorkerEntry(RegisterPoller(POLLER_TYPE_STATUS, node), NULL, 0);
a7b1e779
VK
1983 }
1984 }
1985
1986 if (cp->getObjectClass() == OBJECT_INTERFACE)
1987 {
1988 Interface *iface = (Interface *)cp;
e31d9b18
VK
1989 if ((iface->getExpectedState() != IF_EXPECTED_STATE_IGNORE) &&
1990 ((iface->getAdminState() == IF_ADMIN_STATE_DOWN) || (iface->getAdminState() == IF_ADMIN_STATE_TESTING) ||
1991 (iface->getOperState() == IF_OPER_STATE_DOWN) || (iface->getOperState() == IF_OPER_STATE_TESTING)))
a7b1e779
VK
1992 {
1993 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): upstream interface %s [%d] on switch %s [%d] is down"),
1994 m_name, m_id, iface->getName(), iface->getId(), iface->getParentNode()->getName(), iface->getParentNode()->getId());
1995 sendPollerMsg(requestId, POLLER_WARNING _T(" Upstream interface %s on node %s is down\r\n"),
1996 iface->getName(), iface->getParentNode()->getName());
1997 return true;
1998 }
1999 }
2000 else if (cp->getObjectClass() == OBJECT_ACCESSPOINT)
2001 {
2002 AccessPoint *ap = (AccessPoint *)cp;
2003 if (ap->getStatus() == STATUS_CRITICAL) // FIXME: how to correctly determine if AP is down?
2004 {
2005 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): wireless access point %s [%d] is down"),
2006 m_name, m_id, ap->getName(), ap->getId());
2007 sendPollerMsg(requestId, POLLER_WARNING _T(" Wireless access point %s is down\r\n"), ap->getName());
2008 return true;
2009 }
2010 }
2011 }
2012 }
5f8890c1
AK
2013 }
2014 else
2015 {
2016 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): cannot find interface object for primary IP"), m_name, m_id);
2017 }
a7b1e779
VK
2018 return false;
2019}
67c45b4d 2020
a7b1e779
VK
2021/**
2022 * Check network path between node and management server to detect possible intermediate node failure - layer 3
2023 *
2024 * @return true if network path problems found
2025 */
2026bool Node::checkNetworkPathLayer3(UINT32 requestId, bool secondPass)
2027{
7946bd7c
VK
2028 Node *mgmtNode = (Node *)FindObjectById(g_dwMgmtNode);
2029 if (mgmtNode == NULL)
5f8890c1
AK
2030 {
2031 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): cannot find management node"), m_name, m_id);
2032 return false;
2033 }
5039dede 2034
5f8890c1 2035 NetworkPath *trace = TraceRoute(mgmtNode, this);
7946bd7c 2036 if (trace == NULL)
5f8890c1
AK
2037 {
2038 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): trace not available"), m_name, m_id);
2039 return false;
2040 }
2041 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): trace available, %d hops, %s"),
2042 m_name, m_id, trace->getHopCount(), trace->isComplete() ? _T("complete") : _T("incomplete"));
2043
2044 // We will do path check in two passes
2045 // If unreachable intermediate node will be found on first pass,
2046 // then method will just return true. Otherwise, we will do
2047 // second pass, this time forcing status poll on each node in the path.
a7b1e779 2048 sendPollerMsg(requestId, _T("Checking network path (%s pass)...\r\n"), secondPass ? _T("second") : _T("first"));
5f8890c1 2049 bool pathProblemFound = false;
7946bd7c
VK
2050 for(int i = 0; i < trace->getHopCount(); i++)
2051 {
5f8890c1 2052 HOP_INFO *hop = trace->getHopInfo(i);
c42b4551 2053 if ((hop->object == NULL) || (hop->object == this) || (hop->object->getObjectClass() != OBJECT_NODE))
5f8890c1 2054 continue;
7946bd7c 2055
f4b2ebd3
VK
2056 // Check for loops
2057 if (i > 0)
2058 {
2059 for(int j = i - 1; j >= 0; j--)
2060 {
2061 HOP_INFO *prevHop = trace->getHopInfo(j);
2062 if (prevHop->object == hop->object)
2063 {
2064 prevHop = trace->getHopInfo(i - 1);
2065 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): routing loop detected on upstream node %s [%d]"),
2066 m_name, m_id, prevHop->object->getName(), prevHop->object->getId());
a7b1e779 2067 sendPollerMsg(requestId, POLLER_WARNING _T(" Routing loop detected on upstream node %s\r\n"), prevHop->object->getName());
f4b2ebd3
VK
2068
2069 static const TCHAR *names[] =
2070 { _T("protocol"), _T("destNodeId"), _T("destAddress"),
2071 _T("sourceNodeId"), _T("sourceAddress"), _T("prefix"),
2072 _T("prefixLength"), _T("nextHopNodeId"), _T("nextHopAddress")
2073 };
2074 PostEventWithNames(EVENT_ROUTING_LOOP_DETECTED, prevHop->object->getId(), "siAiAAdiA", names,
2075 (trace->getSourceAddress().getFamily() == AF_INET6) ? _T("IPv6") : _T("IPv4"),
2076 m_id, &m_ipAddress, g_dwMgmtNode, &(trace->getSourceAddress()),
2077 &prevHop->route, prevHop->route.getMaskBits(), hop->object->getId(), &prevHop->nextHop);
2078
2079 pathProblemFound = true;
2080 break;
2081 }
2082 }
2083 if (pathProblemFound)
2084 break;
2085 }
2086
a7b1e779 2087 nxlog_debug(6, _T("Node::checkNetworkPath(%s [%d]): checking upstream router %s [%d]"),
f4b2ebd3 2088 m_name, m_id, hop->object->getName(), hop->object->getId());
a7b1e779 2089 if (checkNetworkPathElement(hop->object->getId(), _T("upstream router"), false, requestId, secondPass))
7946bd7c 2090 {
5f8890c1
AK
2091 pathProblemFound = true;
2092 break;
7946bd7c 2093 }
07350ec1
VK
2094
2095 if (hop->isVpn)
2096 {
2097 // Next hop is behind VPN tunnel
2098 VPNConnector *vpnConn = (VPNConnector *)FindObjectById(hop->ifIndex, OBJECT_VPNCONNECTOR);
2099 if ((vpnConn != NULL) && (vpnConn->getStatus() == STATUS_CRITICAL))
2100 {
a7b1e779 2101 /* TODO: mark as path problem */
07350ec1
VK
2102 }
2103 }
2104 else
2105 {
a7b1e779 2106 Interface *iface = ((Node *)hop->object)->findInterfaceByIndex(hop->ifIndex);
e31d9b18 2107 if ((iface != NULL) && (iface->getExpectedState() != IF_EXPECTED_STATE_IGNORE) &&
07350ec1
VK
2108 ((iface->getAdminState() == IF_ADMIN_STATE_DOWN) || (iface->getAdminState() == IF_ADMIN_STATE_TESTING) ||
2109 (iface->getOperState() == IF_OPER_STATE_DOWN) || (iface->getOperState() == IF_OPER_STATE_TESTING)))
2110 {
2111 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): upstream interface %s [%d] on node %s [%d] is down"),
2112 m_name, m_id, iface->getName(), iface->getId(), hop->object->getName(), hop->object->getId());
a7b1e779 2113 sendPollerMsg(requestId, POLLER_WARNING _T(" Upstream interface %s on node %s is down\r\n"), iface->getName(), hop->object->getName());
07350ec1
VK
2114 break;
2115 }
2116 }
7946bd7c 2117 }
a7b1e779 2118
7946bd7c 2119 delete trace;
5f8890c1 2120 return pathProblemFound;
7946bd7c
VK
2121}
2122
2123/**
a7b1e779
VK
2124 * Check network path between node and management server to detect possible intermediate node failure
2125 *
2126 * @return true if network path problems found
2127 */
2128bool Node::checkNetworkPath(UINT32 requestId)
2129{
2130 if (checkNetworkPathLayer2(requestId, false))
2131 return true;
2132
2133 if (checkNetworkPathLayer3(requestId, false))
2134 return true;
2135
2136 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): will do second pass"), m_name, m_id);
2137
2138 if (checkNetworkPathLayer2(requestId, true))
2139 return true;
2140
2141 if (checkNetworkPathLayer3(requestId, true))
2142 return true;
2143
2144 return false;
2145}
2146
2147/**
7946bd7c
VK
2148 * Check agent policy binding
2149 * Intended to be called only from configuration poller
2150 */
1f385e47
VK
2151void Node::checkAgentPolicyBinding(AgentConnection *conn)
2152{
5f8890c1
AK
2153 AgentPolicyInfo *ap;
2154 UINT32 rcc = conn->getPolicyInventory(&ap);
2155 if (rcc == ERR_SUCCESS)
2156 {
2157 // Check for unbound but installed policies
2158 for(int i = 0; i < ap->size(); i++)
2159 {
2160 uuid guid = ap->getGuid(i);
2161 NetObj *object = FindObjectByGUID(guid, -1);
2162 if ((object != NULL) && (!object->isChild(m_id)))
2163 {
2164 object->addChild(this);
2165 addParent(object);
2166 DbgPrintf(5, _T("ConfPoll(%s): bound to policy object %s [%d]"), m_name, object->getName(), object->getId());
2167 }
2168 }
2169
2170 // Check for bound but not installed policies and schedule it's installation again
2171 //Job will be unbound if it was not possible to add job
2172 lockParentList(false);
2173 NetObj **unbindList = (NetObj **)malloc(sizeof(NetObj *) * m_parentList->size());
2174 int unbindListSize = 0;
2175 for(int i = 0; i < m_parentList->size(); i++)
2176 {
2177 if (IsAgentPolicyObject(m_parentList->get(i)))
2178 {
2179 const uuid& guid = m_parentList->get(i)->getGuid();
de4af576 2180 int j;
5f8890c1
AK
2181 for(j = 0; j < ap->size(); j++)
2182 {
2183 if (ap->getGuid(j).equals(guid))
2184 break;
2185 }
2186 if (j == ap->size())
28e59088 2187 {
97cddb39 2188 ServerJob *job = new PolicyInstallJob(this, (AgentPolicy *)m_parentList->get(i), 0);
5f8890c1
AK
2189 if (AddJob(job))
2190 {
db091a1f 2191 DbgPrintf(5, _T("ConfPoll(%s): \"%s\" policy deploy scheduled for \"%s\" node"), m_name, m_parentList->get(i)->getName(), m_name );
5f8890c1
AK
2192 }
2193 else
2194 {
db091a1f 2195 DbgPrintf(5, _T("ConfPoll(%s): \"%s\" policy deploy is not possible to scheduled for \"%s\" node"), m_name, m_parentList->get(i)->getName(), m_name);
5f8890c1 2196 delete job;
db091a1f 2197 unbindList[unbindListSize++] = m_parentList->get(i);
5f8890c1 2198 }
28e59088 2199 }
5f8890c1
AK
2200 }
2201 }
2202 unlockParentList();
1f385e47 2203
5f8890c1
AK
2204 for(int i = 0; i < unbindListSize; i++)
2205 {
2206 unbindList[i]->deleteChild(this);
2207 deleteParent(unbindList[i]);
2208 DbgPrintf(5, _T("ConfPoll(%s): unbound from policy object %s [%d]"), m_name, unbindList[i]->getName(), unbindList[i]->getId());
2209 }
2210 safe_free(unbindList);
1f385e47 2211
5f8890c1
AK
2212 delete ap;
2213 }
2214 else
2215 {
2216 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getPolicyInventory() failed: rcc=%d"), m_name, rcc);
2217 }
1f385e47
VK
2218}
2219
a3050773
VK
2220/**
2221 * Update primary IP address from primary name
2222 */
5a7d6a10
VK
2223void Node::updatePrimaryIpAddr()
2224{
5f8890c1
AK
2225 if (m_primaryName[0] == 0)
2226 return;
5a7d6a10 2227
a191c634 2228 InetAddress ipAddr = ResolveHostName(m_zoneUIN, m_primaryName);
c75e9ee4 2229 if (!ipAddr.equals(m_ipAddress) && (ipAddr.isValidUnicast() || !_tcscmp(m_primaryName, _T("0.0.0.0"))))
5f8890c1
AK
2230 {
2231 TCHAR buffer1[64], buffer2[64];
5a7d6a10 2232
5f8890c1 2233 DbgPrintf(4, _T("IP address for node %s [%d] changed from %s to %s"),
c75e9ee4 2234 m_name, (int)m_id, m_ipAddress.toString(buffer1), ipAddr.toString(buffer2));
5f8890c1 2235 PostEvent(EVENT_IP_ADDRESS_CHANGED, m_id, "AA", &ipAddr, &m_ipAddress);
2467ed57 2236
487cde95 2237 if (m_flags & NF_REMOTE_AGENT)
dbe28185 2238 {
c42b4551 2239 lockProperties();
c75e9ee4 2240 m_ipAddress = ipAddr;
3d48d1b4 2241 setModified(MODIFY_NODE_PROPERTIES);
c42b4551 2242 unlockProperties();
dbe28185
VK
2243 }
2244 else
2245 {
5f8890c1 2246 setPrimaryIPAddress(ipAddr);
dbe28185 2247 }
a3050773 2248
5f8890c1
AK
2249 agentLock();
2250 deleteAgentConnection();
2251 agentUnlock();
2252 }
5a7d6a10
VK
2253}
2254
76720a09 2255/**
1d7917d5
VK
2256 * Comparator for package names
2257 */
2258static int PackageNameComparator(const SoftwarePackage **p1, const SoftwarePackage **p2)
2259{
2260 return _tcscmp((*p1)->getName(), (*p2)->getName());
2261}
2262
2263/**
2264 * Update list of software packages for node
2265 */
2266bool Node::updateSoftwarePackages(PollerInfo *poller, UINT32 requestId)
2267{
91b3cba9 2268 if (!(m_capabilities & NC_IS_NATIVE_AGENT))
1d7917d5
VK
2269 return false;
2270
2271 poller->setStatus(_T("software check"));
2272 sendPollerMsg(requestId, _T("Reading list of installed software packages\r\n"));
2273
2274 Table *table;
2275 if (getTableFromAgent(_T("System.InstalledProducts"), &table) != DCE_SUCCESS)
2276 {
2277 sendPollerMsg(requestId, POLLER_WARNING _T("Unable to get information about installed software packages\r\n"));
2278 return false;
2279 }
2280
2281 ObjectArray<SoftwarePackage> *packages = new ObjectArray<SoftwarePackage>(table->getNumRows(), 16, true);
2282 for(int i = 0; i < table->getNumRows(); i++)
3e050a0b
VK
2283 {
2284 SoftwarePackage *pkg = SoftwarePackage::createFromTableRow(table, i);
2285 if (pkg != NULL)
2286 packages->add(pkg);
2287 }
1d7917d5
VK
2288 packages->sort(PackageNameComparator);
2289 delete table;
2290 sendPollerMsg(requestId, POLLER_INFO _T("Got information about %d installed software packages\r\n"), packages->size());
2291
2292 lockProperties();
2293 if (m_softwarePackages != NULL)
2294 {
2295 // Check for removed and updated packages
2296 for(int i = 0; i < m_softwarePackages->size(); i++)
2297 {
2298 SoftwarePackage *p = m_softwarePackages->get(i);
2299 SoftwarePackage *np = (SoftwarePackage *)packages->find(p, PackageNameComparator);
2300 if (np != NULL)
2301 {
2302 if (_tcscmp(p->getVersion(), np->getVersion()))
2303 {
2304 nxlog_debug(5, _T("ConfPoll(%s): package %s updated (%s -> %s)"), m_name, p->getName(), p->getVersion(), np->getVersion());
2305 sendPollerMsg(requestId, _T(" Package %s updated (%s -> %s)\r\n"), p->getName(), p->getVersion(), np->getVersion());
2306
2307 static const TCHAR *names[] = { _T("name"), _T("version"), _T("previousVersion") };
2308 PostEventWithNames(EVENT_PACKAGE_UPDATED, m_id, "sss", names, p->getName(), np->getVersion(), p->getVersion());
2309 }
2310 }
2311 else
2312 {
2313 nxlog_debug(5, _T("ConfPoll(%s): package %s removed (last installed version was %s)"), m_name, p->getName(), p->getVersion());
2314 sendPollerMsg(requestId, _T(" Package %s removed (last installed version was %s)\r\n"), p->getName(), p->getVersion());
2315
2316 static const TCHAR *names[] = { _T("name"), _T("version") };
2317 PostEventWithNames(EVENT_PACKAGE_REMOVED, m_id, "ss", names, p->getName(), p->getVersion());
2318 }
2319 }
2320
2321 // Check for new packages
2322 for(int i = 0; i < packages->size(); i++)
2323 {
2324 SoftwarePackage *p = packages->get(i);
2325 if (m_softwarePackages->find(p, PackageNameComparator) == NULL)
2326 {
2327 nxlog_debug(5, _T("ConfPoll(%s): new package %s (version %s)"), m_name, p->getName(), p->getVersion());
2328 sendPollerMsg(requestId, _T(" New package %s (version %s)\r\n"), p->getName(), p->getVersion());
2329
2330 static const TCHAR *names[] = { _T("name"), _T("version") };
2331 PostEventWithNames(EVENT_PACKAGE_INSTALLED, m_id, "ss", names, p->getName(), p->getVersion());
2332 }
2333 }
2334
2335 delete m_softwarePackages;
2336 }
2337 m_softwarePackages = packages;
2338 unlockProperties();
2339 return true;
2340}
2341
91b3cba9 2342
1d7917d5 2343/**
76720a09
VK
2344 * Perform configuration poll on node
2345 */
60e96280 2346void Node::configurationPoll(PollerInfo *poller, ClientSession *session, UINT32 rqId)
5039dede 2347{
a0cc56b3 2348 if (m_runtimeFlags & DCDF_DELETE_IN_PROGRESS)
5f8890c1 2349 {
60e96280 2350 if (rqId == 0)
91b3cba9 2351 m_runtimeFlags &= ~DCDF_QUEUED_FOR_CONFIGURATION_POLL;
5f8890c1
AK
2352 return;
2353 }
46117060 2354
88dc9091 2355 if (IsShutdownInProgress())
9fc9ec2c
VK
2356 return;
2357
3d48d1b4 2358 UINT32 oldCapabilities = m_capabilities;
35f836fe 2359 TCHAR szBuffer[4096];
3d48d1b4 2360 UINT32 modified = 0;
5039dede 2361
208d7427 2362 poller->setStatus(_T("wait for lock"));
7c521895 2363 pollerLock();
88dc9091
VK
2364
2365 if (IsShutdownInProgress())
2366 {
2367 pollerUnlock();
2368 return;
2369 }
2370
60e96280
VK
2371 m_pollRequestor = session;
2372 sendPollerMsg(rqId, _T("Starting configuration poll for node %s\r\n"), m_name);
1d7917d5 2373 nxlog_debug(4, _T("Starting configuration poll for node %s (ID: %d)"), m_name, m_id);
5039dede
AK
2374
2375 // Check for forced capabilities recheck
91b3cba9 2376 if (m_runtimeFlags & NDF_RECHECK_CAPABILITIES)
5039dede 2377 {
60e96280 2378 sendPollerMsg(rqId, POLLER_WARNING _T("Capability reset\r\n"));
91b3cba9 2379 m_capabilities = 0;
2380 m_runtimeFlags &= ~DCDF_CONFIGURATION_POLL_PASSED;
53985424
VK
2381 m_snmpObjectId[0] = 0;
2382 m_platformName[0] = 0;
2383 m_agentVersion[0] = 0;
5f8890c1
AK
2384 safe_free_and_null(m_sysDescription);
2385 safe_free_and_null(m_sysName);
cf38357f
VK
2386 safe_free_and_null(m_sysContact);
2387 safe_free_and_null(m_sysLocation);
5f8890c1 2388 safe_free_and_null(m_lldpNodeId);
5039dede
AK
2389 }
2390
2391 // Check if node is marked as unreachable
a0cc56b3 2392 if ((m_state & DCSF_UNREACHABLE) && !(m_runtimeFlags & NDF_RECHECK_CAPABILITIES))
5039dede 2393 {
60e96280 2394 sendPollerMsg(rqId, POLLER_WARNING _T("Node is marked as unreachable, configuration poll aborted\r\n"));
35f836fe 2395 DbgPrintf(4, _T("Node is marked as unreachable, configuration poll aborted"));
8573e935 2396 m_lastConfigurationPoll = time(NULL);
5039dede
AK
2397 }
2398 else
2399 {
5f8890c1 2400 updatePrimaryIpAddr();
5a7d6a10 2401
208d7427 2402 poller->setStatus(_T("capability check"));
60e96280 2403 sendPollerMsg(rqId, _T("Checking node's capabilities...\r\n"));
5039dede 2404
60e96280 2405 if (confPollAgent(rqId))
3d48d1b4 2406 modified |= MODIFY_NODE_PROPERTIES;
60e96280 2407 if (confPollSnmp(rqId))
3d48d1b4 2408 modified |= MODIFY_NODE_PROPERTIES;
5039dede
AK
2409
2410 // Check for CheckPoint SNMP agent on port 260
9a1f7c45 2411 if (ConfigReadInt(_T("EnableCheckPointSNMP"), 0))
5039dede 2412 {
1d7917d5 2413 nxlog_debug(5, _T("ConfPoll(%s): checking for CheckPoint SNMP on port 260"), m_name);
91b3cba9 2414 if (!((m_capabilities & NC_IS_CPSNMP) && (m_state & NSF_CPSNMP_UNREACHABLE)) && m_ipAddress.isValidUnicast())
5039dede 2415 {
5f8890c1
AK
2416 SNMP_Transport *pTransport = new SNMP_UDPTransport;
2417 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(m_ipAddress, CHECKPOINT_SNMP_PORT);
9a1f7c45
VK
2418 if (SnmpGet(SNMP_VERSION_1, pTransport,
2419 _T(".1.3.6.1.4.1.2620.1.1.10.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
2420 {
c42b4551 2421 lockProperties();
91b3cba9 2422 m_capabilities |= NC_IS_CPSNMP | NC_IS_ROUTER;
2423 m_state &= ~NSF_CPSNMP_UNREACHABLE;
c42b4551 2424 unlockProperties();
60e96280 2425 sendPollerMsg(rqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 260 is active\r\n"));
9a1f7c45 2426 }
5f8890c1 2427 delete pTransport;
5039dede 2428 }
5039dede
AK
2429 }
2430
2431 // Generate event if node flags has been changed
3d48d1b4 2432 if (oldCapabilities != m_capabilities)
5039dede 2433 {
3d48d1b4
VK
2434 PostEvent(EVENT_NODE_CAPABILITIES_CHANGED, m_id, "xx", oldCapabilities, m_capabilities);
2435 modified |= MODIFY_NODE_PROPERTIES;
5039dede
AK
2436 }
2437
5039dede 2438 // Retrieve interface list
208d7427 2439 poller->setStatus(_T("interface check"));
60e96280 2440 sendPollerMsg(rqId, _T("Capability check finished\r\n"));
5039dede 2441
60e96280 2442 if (updateInterfaceConfiguration(rqId, 0)) // maskBits
3d48d1b4 2443 modified |= MODIFY_NODE_PROPERTIES;
5039dede 2444
8573e935 2445 m_lastConfigurationPoll = time(NULL);
5039dede 2446
5f8890c1 2447 // Check node name
60e96280 2448 sendPollerMsg(rqId, _T("Checking node name\r\n"));
5f8890c1
AK
2449 UINT32 dwAddr = ntohl(_t_inet_addr(m_name));
2450 if ((g_flags & AF_RESOLVE_NODE_NAMES) &&
2451 (dwAddr != INADDR_NONE) &&
2452 (dwAddr != INADDR_ANY) &&
2453 isMyIP(dwAddr))
2454 {
60e96280 2455 sendPollerMsg(rqId, _T("Node name is an IP address and need to be resolved\r\n"));
5f8890c1
AK
2456 poller->setStatus(_T("resolving name"));
2457 if (resolveName(FALSE))
2458 {
60e96280 2459 sendPollerMsg(rqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_name);
3d48d1b4 2460 modified |= MODIFY_COMMON_PROPERTIES;
5f8890c1
AK
2461 }
2462 else
2463 {
60e96280 2464 sendPollerMsg(rqId, POLLER_WARNING _T("Node name cannot be resolved\r\n"));
5f8890c1
AK
2465 }
2466 }
2467 else
2468 {
2469 if (g_flags & AF_SYNC_NODE_NAMES_WITH_DNS)
2470 {
60e96280 2471 sendPollerMsg(rqId, _T("Syncing node name with DNS\r\n"));
5f8890c1
AK
2472 poller->setStatus(_T("resolving name"));
2473 if (resolveName(TRUE))
2474 {
60e96280 2475 sendPollerMsg(rqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_name);
3d48d1b4 2476 modified |= MODIFY_COMMON_PROPERTIES;
5f8890c1
AK
2477 }
2478 }
2479 else
2480 {
60e96280 2481 sendPollerMsg(rqId, _T("Node name is OK\r\n"));
5f8890c1
AK
2482 }
2483 }
2484
2485 applyUserTemplates();
2486 updateContainerMembership();
60e96280 2487 updateSoftwarePackages(poller, rqId);
5f8890c1
AK
2488
2489 // Call hooks in loaded modules
2490 for(UINT32 i = 0; i < g_dwNumModules; i++)
2491 {
2492 if (g_pModuleList[i].pfConfPollHook != NULL)
2493 {
2494 DbgPrintf(5, _T("ConfigurationPoll(%s [%d]): calling hook in module %s"), m_name, m_id, g_pModuleList[i].szName);
60e96280 2495 if (g_pModuleList[i].pfConfPollHook(this, session, rqId, poller))
3d48d1b4 2496 modified |= MODIFY_ALL; // FIXME: change module call to get exact modifications
5f8890c1
AK
2497 }
2498 }
a5ee7b3b 2499
270c946c 2500 // Setup permanent connection to agent if not present (needed for proper configuration re-sync)
91b3cba9 2501 if (m_capabilities & NC_IS_NATIVE_AGENT)
5f8890c1 2502 {
270c946c
VK
2503 agentLock();
2504 connectToAgent();
2505 agentUnlock();
2506 }
2507
5f8890c1
AK
2508 // Update node type
2509 NodeType type = detectNodeType();
e980db40 2510 nxlog_debug(5, _T("ConfPoll(%s): detected node type: %d (%s)"), m_name, type, typeName(type));
5f8890c1
AK
2511 lockProperties();
2512 if ((type != NODE_TYPE_UNKNOWN) && (type != m_type))
2513 {
2514 m_type = type;
3d48d1b4 2515 modified |= MODIFY_NODE_PROPERTIES;
5f8890c1 2516 nxlog_debug(5, _T("ConfPoll(%s): node type set to %d (%s)"), m_name, type, typeName(type));
60e96280 2517 sendPollerMsg(rqId, _T(" Node type changed to %s\r\n"), typeName(type));
5f8890c1
AK
2518 }
2519 unlockProperties();
e980db40 2520
5f8890c1
AK
2521 // Execute hook script
2522 poller->setStatus(_T("hook"));
2523 executeHookScript(_T("ConfigurationPoll"));
a3050773 2524
60e96280 2525 sendPollerMsg(rqId, _T("Finished configuration poll for node %s\r\n"), m_name);
3d48d1b4 2526 sendPollerMsg(rqId, _T("Node configuration was%schanged after poll\r\n"), (modified != 0) ? _T(" ") : _T(" not "));
270c946c 2527
688e0055 2528 m_runtimeFlags &= ~DCDF_CONFIGURATION_POLL_PENDING;
91b3cba9 2529 m_runtimeFlags |= DCDF_CONFIGURATION_POLL_PASSED;
a3050773 2530 }
1824629a 2531
4d0c32f3 2532 // Finish configuration poll
208d7427 2533 poller->setStatus(_T("cleanup"));
60e96280 2534 if (rqId == 0)
91b3cba9 2535 m_runtimeFlags &= ~DCDF_QUEUED_FOR_CONFIGURATION_POLL;
2536 m_runtimeFlags &= ~NDF_RECHECK_CAPABILITIES;
7c521895 2537 pollerUnlock();
c42b4551 2538 DbgPrintf(4, _T("Finished configuration poll for node %s (ID: %d)"), m_name, m_id);
4d0c32f3 2539
3d48d1b4 2540 if (modified != 0)
4d0c32f3 2541 {
c42b4551 2542 lockProperties();
3d48d1b4 2543 setModified(modified);
c42b4551 2544 unlockProperties();
4d0c32f3
VK
2545 }
2546}
2547
76720a09 2548/**
e980db40
VK
2549 * Detect node type
2550 */
2551NodeType Node::detectNodeType()
2552{
2553 NodeType type = NODE_TYPE_UNKNOWN;
91b3cba9 2554 if (m_capabilities & NC_IS_SNMP)
e980db40
VK
2555 {
2556 nxlog_debug(6, _T("Node::detectNodeType(%s [%d]): SNMP node, driver name is %s"), m_name, m_id, m_driver->getName());
2557
2558 // Assume physical device if it supports SNMP and driver is not "GENERIC"
2559 // FIXME: add driver method to determine node type
2560 if (_tcscmp(m_driver->getName(), _T("GENERIC")))
2561 {
2562 type = NODE_TYPE_PHYSICAL;
2563 }
2564 else
2565 {
91b3cba9 2566 if (m_capabilities & NC_IS_PRINTER)
e980db40
VK
2567 {
2568 // Assume that printers are physical devices
2569 type = NODE_TYPE_PHYSICAL;
2570 }
2571 }
2572 }
2573 return type;
2574}
2575
2576/**
76720a09
VK
2577 * Configuration poll: check for NetXMS agent
2578 */
60e96280 2579bool Node::confPollAgent(UINT32 rqId)
76720a09 2580{
91b3cba9 2581 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent Flags={%08X} StateFlags={%08X} RuntimeFlags={%08X}"), m_name, m_flags, m_state, m_runtimeFlags);
2582 if (((m_capabilities & NC_IS_NATIVE_AGENT) && (m_state & NSF_AGENT_UNREACHABLE)) || (m_flags & NF_DISABLE_NXCP))
5f8890c1 2583 return false;
76720a09 2584
5f8890c1 2585 bool hasChanges = false;
76720a09 2586
60e96280 2587 sendPollerMsg(rqId, _T(" Checking NetXMS agent...\r\n"));
2f6c6597 2588 AgentTunnel *tunnel = GetTunnelForNode(m_id);
ed83ffcd 2589 AgentConnectionEx *pAgentConn;
2f6c6597
VK
2590 if (tunnel != NULL)
2591 {
2592 pAgentConn = new AgentConnectionEx(m_id, tunnel, m_agentAuthMethod, m_szSharedSecret, isAgentCompressionAllowed());
2593 tunnel->decRefCount();
2594 }
2595 else
2596 {
163d6a94
VK
2597 if (!m_ipAddress.isValidUnicast())
2598 {
60e96280 2599 sendPollerMsg(rqId, POLLER_ERROR _T(" Node primary IP is invalid and there are no active tunnels\r\n"));
163d6a94
VK
2600 nxlog_debug(5, _T("ConfPoll(%s): node primary IP is invalid and there are no active tunnels"), m_name);
2601 return false;
2602 }
2f6c6597
VK
2603 pAgentConn = new AgentConnectionEx(m_id, m_ipAddress, m_agentPort, m_agentAuthMethod, m_szSharedSecret, isAgentCompressionAllowed());
2604 setAgentProxy(pAgentConn);
2605 }
f6e04a96 2606 pAgentConn->setCommandTimeout(g_agentCommandTimeout);
163d6a94 2607 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - connecting"), m_name);
af21affe
VK
2608
2609 // Try to connect to agent
2610 UINT32 rcc;
a041f696 2611 if (!pAgentConn->connect(g_pServerKey, &rcc))
af21affe
VK
2612 {
2613 // If there are authentication problem, try default shared secret
2614 if ((rcc == ERR_AUTH_REQUIRED) || (rcc == ERR_AUTH_FAILED))
2615 {
2616 TCHAR secret[MAX_SECRET_LENGTH];
2617 ConfigReadStr(_T("AgentDefaultSharedSecret"), secret, MAX_SECRET_LENGTH, _T("netxms"));
ce9783d2 2618 DecryptPassword(_T("netxms"), secret, secret, MAX_SECRET_LENGTH);
af21affe 2619 pAgentConn->setAuthData(AUTH_SHA1_HASH, secret);
a041f696 2620 if (pAgentConn->connect(g_pServerKey, &rcc))
af21affe 2621 {
c42b4551 2622 m_agentAuthMethod = AUTH_SHA1_HASH;
af21affe 2623 nx_strncpy(m_szSharedSecret, secret, MAX_SECRET_LENGTH);
163d6a94 2624 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - shared secret changed to system default"), m_name);
af21affe
VK
2625 }
2626 }
2627 }
2628
2629 if (rcc == ERR_SUCCESS)
76720a09 2630 {
163d6a94 2631 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - connected"), m_name);
c42b4551 2632 lockProperties();
91b3cba9 2633 m_capabilities |= NC_IS_NATIVE_AGENT;
2634 if (m_state & NSF_AGENT_UNREACHABLE)
76720a09 2635 {
91b3cba9 2636 m_state &= ~NSF_AGENT_UNREACHABLE;
c42b4551 2637 PostEvent(EVENT_AGENT_OK, m_id, NULL);
60e96280 2638 sendPollerMsg(rqId, POLLER_INFO _T(" Connectivity with NetXMS agent restored\r\n"));
76720a09 2639 }
5f8890c1
AK
2640 else
2641 {
60e96280 2642 sendPollerMsg(rqId, POLLER_INFO _T(" NetXMS native agent is active\r\n"));
5f8890c1 2643 }
c42b4551 2644 unlockProperties();
4d0c32f3 2645
5f8890c1 2646 TCHAR buffer[MAX_RESULT_LENGTH];
76720a09
VK
2647 if (pAgentConn->getParameter(_T("Agent.Version"), MAX_AGENT_VERSION_LEN, buffer) == ERR_SUCCESS)
2648 {
c42b4551 2649 lockProperties();
53985424 2650 if (_tcscmp(m_agentVersion, buffer))
76720a09 2651 {
53985424 2652 _tcscpy(m_agentVersion, buffer);
76720a09 2653 hasChanges = true;
60e96280 2654 sendPollerMsg(rqId, _T(" NetXMS agent version changed to %s\r\n"), m_agentVersion);
76720a09 2655 }
c42b4551 2656 unlockProperties();
76720a09
VK
2657 }
2658
2659 if (pAgentConn->getParameter(_T("System.PlatformName"), MAX_PLATFORM_NAME_LEN, buffer) == ERR_SUCCESS)
2660 {
c42b4551 2661 lockProperties();
53985424 2662 if (_tcscmp(m_platformName, buffer))
76720a09 2663 {
53985424 2664 _tcscpy(m_platformName, buffer);
76720a09 2665 hasChanges = true;
60e96280 2666 sendPollerMsg(rqId, _T(" Platform name changed to %s\r\n"), m_platformName);
76720a09 2667 }
c42b4551 2668 unlockProperties();
76720a09
VK
2669 }
2670
2671 // Check IP forwarding status
2672 if (pAgentConn->getParameter(_T("Net.IP.Forwarding"), 16, buffer) == ERR_SUCCESS)
2673 {
2674 if (_tcstoul(buffer, NULL, 10) != 0)
91b3cba9 2675 m_capabilities |= NC_IS_ROUTER;
76720a09 2676 else
91b3cba9 2677 m_capabilities &= ~NC_IS_ROUTER;
76720a09
VK
2678 }
2679
5f8890c1
AK
2680 // Get uname
2681 if (pAgentConn->getParameter(_T("System.Uname"), MAX_DB_STRING, buffer) == ERR_SUCCESS)
2682 {
2683 TranslateStr(buffer, _T("\r\n"), _T(" "));
2684 TranslateStr(buffer, _T("\n"), _T(" "));
2685 TranslateStr(buffer, _T("\r"), _T(" "));
c42b4551 2686 lockProperties();
76720a09
VK
2687 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, buffer))
2688 {
3d48d1b4 2689 free(m_sysDescription);
76720a09
VK
2690 m_sysDescription = _tcsdup(buffer);
2691 hasChanges = true;
60e96280 2692 sendPollerMsg(rqId, _T(" System description changed to %s\r\n"), m_sysDescription);
76720a09 2693 }
c42b4551 2694 unlockProperties();
5f8890c1 2695 }
76720a09 2696
11b75b2e 2697 // Check for 64 bit counter support.
acf01215 2698 // if Net.Interface.64BitCounters not supported by agent then use
11b75b2e
VK
2699 // only presence of 64 bit parameters as indicator
2700 bool netIf64bitCounters = true;
5f8890c1 2701 if (pAgentConn->getParameter(_T("Net.Interface.64BitCounters"), MAX_DB_STRING, buffer) == ERR_SUCCESS)
11b75b2e
VK
2702 {
2703 netIf64bitCounters = _tcstol(buffer, NULL, 10) ? true : false;
2704 }
2705
5f8890c1 2706 ObjectArray<AgentParameterDefinition> *plist;
86c126f5 2707 ObjectArray<AgentTableDefinition> *tlist;
967893bb 2708 UINT32 rcc = pAgentConn->getSupportedParameters(&plist, &tlist);
5f8890c1
AK
2709 if (rcc == ERR_SUCCESS)
2710 {
2711 lockProperties();
2712 delete m_paramList;
2713 delete m_tableList;
2714 m_paramList = plist;
2715 m_tableList = tlist;
2716
2717 // Check for 64-bit interface counters
91b3cba9 2718 m_capabilities &= ~NC_HAS_AGENT_IFXCOUNTERS;
11b75b2e
VK
2719 if (netIf64bitCounters)
2720 {
5f8890c1
AK
2721 for(int i = 0; i < plist->size(); i++)
2722 {
2723 if (!_tcsicmp(plist->get(i)->getName(), _T("Net.Interface.BytesIn64(*)")))
2724 {
91b3cba9 2725 m_capabilities |= NC_HAS_AGENT_IFXCOUNTERS;
11b75b2e 2726 break;
5f8890c1
AK
2727 }
2728 }
11b75b2e 2729 }
084fb4c1 2730
5f8890c1
AK
2731 unlockProperties();
2732 }
2733 else
2734 {
2735 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getSupportedParameters() failed: rcc=%d"), m_name, rcc);
2736 }
76720a09 2737
5f8890c1 2738 // Get supported Windows Performance Counters
53985424 2739 if (!_tcsncmp(m_platformName, _T("windows-"), 8))
5f8890c1 2740 {
60e96280 2741 sendPollerMsg(rqId, _T(" Reading list of available Windows Performance Counters...\r\n"));
5f8890c1
AK
2742 ObjectArray<WinPerfObject> *perfObjects = WinPerfObject::getWinPerfObjectsFromNode(this, pAgentConn);
2743 lockProperties();
2744 delete m_winPerfObjects;
2745 m_winPerfObjects = perfObjects;
2746 if (m_winPerfObjects != NULL)
2747 {
60e96280 2748 sendPollerMsg(rqId, POLLER_INFO _T(" %d counters read\r\n"), m_winPerfObjects->size());
91b3cba9 2749 if (!(m_capabilities & NC_HAS_WINPDH))
5f8890c1 2750 {
91b3cba9 2751 m_capabilities |= NC_HAS_WINPDH;
5f8890c1
AK
2752 hasChanges = true;
2753 }
2754 }
2755 else
2756 {
60e96280 2757 sendPollerMsg(rqId, POLLER_ERROR _T(" unable to get Windows Performance Counters list\r\n"));
91b3cba9 2758 if (m_capabilities & NC_HAS_WINPDH)
5f8890c1 2759 {
91b3cba9 2760 m_capabilities &= ~NC_HAS_WINPDH;
5f8890c1
AK
2761 hasChanges = true;
2762 }
2763 }
2764 unlockProperties();
2765 }
2766
2767 checkAgentPolicyBinding(pAgentConn);
76720a09
VK
2768
2769 pAgentConn->disconnect();
2770 }
5f8890c1
AK
2771 else
2772 {
163d6a94 2773 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - failed to connect (error %d)"), m_name, rcc);
5f8890c1 2774 }
da4a8dfe 2775 pAgentConn->decRefCount();
163d6a94 2776 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - finished"), m_name);
5f8890c1 2777 return hasChanges;
76720a09
VK
2778}
2779
2780/**
a93aa634 2781 * SNMP walker callback which sets indicator to true after first varbind and aborts walk
76720a09 2782 */
9c5ebc32 2783static UINT32 IndicatorSnmpWalkerCallback(SNMP_Variable *var, SNMP_Transport *transport, void *arg)
76720a09 2784{
a93aa634
VK
2785 (*((bool *)arg)) = true;
2786 return SNMP_ERR_COMM;
76720a09
VK
2787}
2788
2789/**
2790 * Configuration poll: check for SNMP
2791 */
60e96280 2792bool Node::confPollSnmp(UINT32 rqId)
76720a09 2793{
91b3cba9 2794 if (((m_capabilities & NC_IS_SNMP) && (m_state & NSF_SNMP_UNREACHABLE)) ||
5f8890c1
AK
2795 !m_ipAddress.isValidUnicast() || (m_flags & NF_DISABLE_SNMP))
2796 return false;
76720a09 2797
5f8890c1 2798 bool hasChanges = false;
76720a09 2799
60e96280 2800 sendPollerMsg(rqId, _T(" Checking SNMP...\r\n"));
c42b4551 2801 DbgPrintf(5, _T("ConfPoll(%s): calling SnmpCheckCommSettings()"), m_name);
1f4c37ee
VK
2802 StringList oids;
2803 const TCHAR *customOid = m_customAttributes.get(_T("snmp.testoid"));
2804 if (customOid != NULL)
2805 oids.add(customOid);
2806 oids.add(_T(".1.3.6.1.2.1.1.2.0"));
2807 oids.add(_T(".1.3.6.1.2.1.1.1.0"));
2808 AddDriverSpecificOids(&oids);
d0a2ada6 2809 SNMP_Transport *pTransport = SnmpCheckCommSettings(getEffectiveSnmpProxy(), (getEffectiveSnmpProxy() == m_id) ? InetAddress::LOOPBACK : m_ipAddress, &m_snmpVersion, m_snmpPort, m_snmpSecurity, &oids);
af7ca382 2810 if (pTransport == NULL)
76720a09 2811 {
d0a2ada6 2812 DbgPrintf(5, _T("ConfPoll(%s): unable to create SNMP transport"), m_name);
2813 return false;
2814 }
76720a09 2815
d0a2ada6 2816 lockProperties();
2817 m_snmpPort = pTransport->getPort();
2818 delete m_snmpSecurity;
2819 m_snmpSecurity = new SNMP_SecurityContext(pTransport->getSecurityContext());
91b3cba9 2820 m_capabilities |= NC_IS_SNMP;
2821 if (m_state & NSF_SNMP_UNREACHABLE)
d0a2ada6 2822 {
91b3cba9 2823 m_state &= ~NSF_SNMP_UNREACHABLE;
d0a2ada6 2824 PostEvent(EVENT_SNMP_OK, m_id, NULL);
60e96280 2825 sendPollerMsg(rqId, POLLER_INFO _T(" Connectivity with SNMP agent restored\r\n"));
d0a2ada6 2826 }
2827 unlockProperties();
60e96280 2828 sendPollerMsg(rqId, _T(" SNMP agent is active (version %s)\r\n"),
d0a2ada6 2829 (m_snmpVersion == SNMP_VERSION_3) ? _T("3") : ((m_snmpVersion == SNMP_VERSION_2C) ? _T("2c") : _T("1")));
76720a09 2830
d0a2ada6 2831 TCHAR szBuffer[4096];
2832 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.1.2.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_STRING_RESULT) != SNMP_ERR_SUCCESS)
2833 {
2834 // Set snmp object ID to .0.0 if it cannot be read
2835 _tcscpy(szBuffer, _T(".0.0"));
2836 }
2837 lockProperties();
53985424 2838 if (_tcscmp(m_snmpObjectId, szBuffer))
d0a2ada6 2839 {
3d48d1b4 2840 _tcslcpy(m_snmpObjectId, szBuffer, MAX_OID_LEN * 4);
d0a2ada6 2841 hasChanges = true;
2842 }
2843 unlockProperties();
76720a09 2844
d0a2ada6 2845 // Get system description
2846 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.1.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
2847 {
2848 TranslateStr(szBuffer, _T("\r\n"), _T(" "));
2849 TranslateStr(szBuffer, _T("\n"), _T(" "));
2850 TranslateStr(szBuffer, _T("\r"), _T(" "));
2851 lockProperties();
2852 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, szBuffer))
76720a09 2853 {
d8fa3917 2854 free(m_sysDescription);
d0a2ada6 2855 m_sysDescription = _tcsdup(szBuffer);
2856 hasChanges = true;
60e96280 2857 sendPollerMsg(rqId, _T(" System description changed to %s\r\n"), m_sysDescription);
76720a09 2858 }
d0a2ada6 2859 unlockProperties();
2860 }
76720a09 2861
d0a2ada6 2862 // Select device driver
2863 NetworkDeviceDriver *driver = FindDriverForNode(this, pTransport);
2864 DbgPrintf(5, _T("ConfPoll(%s): selected device driver %s"), m_name, driver->getName());
2865 lockProperties();
2866 if (driver != m_driver)
2867 {
2868 m_driver = driver;
60e96280 2869 sendPollerMsg(rqId, _T(" New network device driver selected: %s\r\n"), m_driver->getName());
d0a2ada6 2870 }
2871 unlockProperties();
eec253a8 2872
d0a2ada6 2873 // Allow driver to gather additional info
53985424 2874 m_driver->analyzeDevice(pTransport, m_snmpObjectId, &m_customAttributes, &m_driverData);
291644e3
EJ
2875 NDD_MODULE_LAYOUT layout;
2876 m_driver->getModuleLayout(pTransport, &m_customAttributes, m_driverData, 1, &layout); // TODO module set to 1
fa9c1a51
VK
2877 if (layout.numberingScheme == NDD_PN_UNKNOWN)
2878 {
2879 // Try to find port numbering information in database
53985424 2880 LookupDevicePortLayout(SNMP_ObjectId::parse(m_snmpObjectId), &layout);
fa9c1a51 2881 }
191137b2
VK
2882 m_portRowCount = layout.rows;
2883 m_portNumberingScheme = layout.numberingScheme;
76720a09 2884
cf38357f 2885 // Get sysName, sysContact, sysLocation
60e96280 2886 if (querySnmpSysProperty(pTransport, _T(".1.3.6.1.2.1.1.5.0"), _T("name"), rqId, &m_sysName))
cf38357f 2887 hasChanges = true;
60e96280 2888 if (querySnmpSysProperty(pTransport, _T(".1.3.6.1.2.1.1.4.0"), _T("contact"), rqId, &m_sysContact))
cf38357f 2889 hasChanges = true;
60e96280 2890 if (querySnmpSysProperty(pTransport, _T(".1.3.6.1.2.1.1.6.0"), _T("location"), rqId, &m_sysLocation))
cf38357f 2891 hasChanges = true;
76720a09 2892
d0a2ada6 2893 // Check IP forwarding
2894 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.2.1.4.1.0"), 1))
2895 {
2896 lockProperties();
91b3cba9 2897 m_capabilities |= NC_IS_ROUTER;
d0a2ada6 2898 unlockProperties();
2899 }
2900 else
2901 {
2902 lockProperties();
91b3cba9 2903 m_capabilities &= ~NC_IS_ROUTER;
d0a2ada6 2904 unlockProperties();
2905 }
76720a09 2906
d0a2ada6 2907 checkIfXTable(pTransport);
2908 checkBridgeMib(pTransport);
76720a09 2909
d0a2ada6 2910 // Check for ENTITY-MIB support
2911 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.47.1.4.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_RAW_RESULT) == SNMP_ERR_SUCCESS)
2912 {
2913 lockProperties();
91b3cba9 2914 m_capabilities |= NC_HAS_ENTITY_MIB;
d0a2ada6 2915 unlockProperties();
2916
2917 ComponentTree *components = BuildComponentTree(this, pTransport);
2918 lockProperties();
2919 if (m_components != NULL)
2920 m_components->decRefCount();
2921 m_components = components;
2922 unlockProperties();
2923 }
2924 else
2925 {
2926 lockProperties();
91b3cba9 2927 m_capabilities &= ~NC_HAS_ENTITY_MIB;
d0a2ada6 2928 if (m_components != NULL)
76720a09 2929 {
d0a2ada6 2930 m_components->decRefCount();
2931 m_components = NULL;
76720a09 2932 }
d0a2ada6 2933 unlockProperties();
2934 }
76720a09 2935
d0a2ada6 2936 // Check for printer MIB support
a93aa634 2937 bool present = false;
9c5ebc32 2938 SnmpWalk(pTransport, _T(".1.3.6.1.2.1.43"), IndicatorSnmpWalkerCallback, &present);
a93aa634 2939 if (present)
d0a2ada6 2940 {
2941 lockProperties();
91b3cba9 2942 m_capabilities |= NC_IS_PRINTER;
d0a2ada6 2943 unlockProperties();
2944 }
2945 else
2946 {
2947 lockProperties();
91b3cba9 2948 m_capabilities &= ~NC_IS_PRINTER;
d0a2ada6 2949 unlockProperties();
2950 }
76720a09 2951
d0a2ada6 2952 // Check for CDP (Cisco Discovery Protocol) support
2953 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.9.9.23.1.3.1.0"), 1))
2954 {
2955 lockProperties();
91b3cba9 2956 m_capabilities |= NC_IS_CDP;
d0a2ada6 2957 unlockProperties();
2958 }
2959 else
2960 {
2961 lockProperties();
91b3cba9 2962 m_capabilities &= ~NC_IS_CDP;
d0a2ada6 2963 unlockProperties();
2964 }
3a82d5ae 2965
d0a2ada6 2966 // Check for NDP (Nortel Discovery Protocol) support
2967 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.45.1.6.13.1.2.0"), 1))
2968 {
2969 lockProperties();
91b3cba9 2970 m_capabilities |= NC_IS_NDP;
d0a2ada6 2971 unlockProperties();
2972 }
2973 else
2974 {
2975 lockProperties();
91b3cba9 2976 m_capabilities &= ~NC_IS_NDP;
d0a2ada6 2977 unlockProperties();
2978 }
76720a09 2979
d0a2ada6 2980 // Check for LLDP (Link Layer Discovery Protocol) support
2981 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.0.8802.1.1.2.1.3.2.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
2982 {
2983 lockProperties();
91b3cba9 2984 m_capabilities |= NC_IS_LLDP;
d0a2ada6 2985 unlockProperties();
2986
2987 INT32 type;
2988 BYTE data[256];
2989 UINT32 dataLen;
2990 if ((SnmpGetEx(pTransport, _T(".1.0.8802.1.1.2.1.3.1.0"), NULL, 0, &type, sizeof(INT32), 0, NULL) == SNMP_ERR_SUCCESS) &&
2991 (SnmpGetEx(pTransport, _T(".1.0.8802.1.1.2.1.3.2.0"), NULL, 0, data, 256, SG_RAW_RESULT, &dataLen) == SNMP_ERR_SUCCESS))
76720a09 2992 {
d0a2ada6 2993 BuildLldpId(type, data, dataLen, szBuffer, 1024);
2994 lockProperties();
2995 if ((m_lldpNodeId == NULL) || _tcscmp(m_lldpNodeId, szBuffer))
2996 {
538ecea7 2997 free(m_lldpNodeId);
d0a2ada6 2998 m_lldpNodeId = _tcsdup(szBuffer);
2999 hasChanges = true;
60e96280 3000 sendPollerMsg(rqId, _T(" LLDP node ID changed to %s\r\n"), m_lldpNodeId);
d0a2ada6 3001 }
3002 unlockProperties();
76720a09
VK
3003 }
3004
d0a2ada6 3005 ObjectArray<LLDP_LOCAL_PORT_INFO> *lldpPorts = GetLLDPLocalPortInfo(pTransport);
3006 lockProperties();
3007 delete m_lldpLocalPortInfo;
3008 m_lldpLocalPortInfo = lldpPorts;
3009 unlockProperties();
3010 }
3011 else
3012 {
3013 lockProperties();
91b3cba9 3014 m_capabilities &= ~NC_IS_LLDP;
d0a2ada6 3015 unlockProperties();
3016 }
76720a09 3017
d0a2ada6 3018 // Check for 802.1x support
3019 if (checkSNMPIntegerValue(pTransport, _T(".1.0.8802.1.1.1.1.1.1.0"), 1))
3020 {
3021 lockProperties();
91b3cba9 3022 m_capabilities |= NC_IS_8021X;
d0a2ada6 3023 unlockProperties();
3024 }
3025 else
3026 {
3027 lockProperties();
91b3cba9 3028 m_capabilities &= ~NC_IS_8021X;
d0a2ada6 3029 unlockProperties();
3030 }
c6afd26a 3031
d0a2ada6 3032 checkOSPFSupport(pTransport);
c6afd26a 3033
d0a2ada6 3034 // Get VRRP information
3035 VrrpInfo *vrrpInfo = GetVRRPInfo(this);
3036 if (vrrpInfo != NULL)
3037 {
3038 lockProperties();
91b3cba9 3039 m_capabilities |= NC_IS_VRRP;
d0a2ada6 3040 delete m_vrrpInfo;
3041 m_vrrpInfo = vrrpInfo;
3042 unlockProperties();
3043 }
3044 else
3045 {
3046 lockProperties();
91b3cba9 3047 m_capabilities &= ~NC_IS_VRRP;
d0a2ada6 3048 unlockProperties();
3049 }
8f26db67 3050
d0a2ada6 3051 // Get wireless controller data
3052 if ((m_driver != NULL) && m_driver->isWirelessController(pTransport, &m_customAttributes, m_driverData))
3053 {
3054 DbgPrintf(5, _T("ConfPoll(%s): node is wireless controller, reading access point information"), m_name);
60e96280 3055 sendPollerMsg(rqId, _T(" Reading wireless access point information\r\n"));