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