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