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