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