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