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