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