code refactoring; preparation for zoning support
[public/netxms.git] / src / server / core / node.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2011 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: node.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25
26 //
27 // Node class default constructor
28 //
29
30 Node::Node()
31 :Template()
32 {
33 m_primaryName[0] = 0;
34 m_iStatus = STATUS_UNKNOWN;
35 m_dwFlags = 0;
36 m_dwDynamicFlags = 0;
37 m_zoneId = 0;
38 m_wAgentPort = AGENT_LISTEN_PORT;
39 m_wAuthMethod = AUTH_NONE;
40 m_szSharedSecret[0] = 0;
41 m_iStatusPollType = POLL_ICMP_PING;
42 m_snmpVersion = SNMP_VERSION_1;
43 m_wSNMPPort = SNMP_DEFAULT_PORT;
44 char community[MAX_COMMUNITY_LENGTH];
45 ConfigReadStrA(_T("DefaultCommunityString"), community, MAX_COMMUNITY_LENGTH, "public");
46 m_snmpSecurity = new SNMP_SecurityContext(community);
47 m_szObjectId[0] = 0;
48 m_tLastDiscoveryPoll = 0;
49 m_tLastStatusPoll = 0;
50 m_tLastConfigurationPoll = 0;
51 m_tLastRTUpdate = 0;
52 m_hPollerMutex = MutexCreate();
53 m_hAgentAccessMutex = MutexCreate();
54 m_mutexRTAccess = MutexCreate();
55 m_mutexTopoAccess = MutexCreate();
56 m_pAgentConnection = NULL;
57 m_szAgentVersion[0] = 0;
58 m_szPlatformName[0] = 0;
59 m_sysDescription = NULL;
60 m_sysName = NULL;
61 m_lldpNodeId = NULL;
62 m_dwNumParams = 0;
63 m_pParamList = NULL;
64 m_dwPollerNode = 0;
65 m_dwProxyNode = 0;
66 m_dwSNMPProxy = 0;
67 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
68 m_pRoutingTable = NULL;
69 m_tFailTimeSNMP = 0;
70 m_tFailTimeAgent = 0;
71 m_linkLayerNeighbors = NULL;
72 m_vrrpInfo = NULL;
73 m_tLastTopologyPoll = 0;
74 m_pTopology = NULL;
75 m_topologyRebuildTimestamp = 0;
76 m_iPendingStatus = -1;
77 m_iPollCount = 0;
78 m_iRequiredPollCount = 0; // Use system default
79 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
80 m_jobQueue = new ServerJobQueue();
81 m_fdb = NULL;
82 m_driver = NULL;
83 }
84
85
86 //
87 // Constructor for new node object
88 //
89
90 Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwProxyNode, DWORD dwSNMPProxy, DWORD dwZone)
91 :Template()
92 {
93 IpToStr(dwAddr, m_primaryName);
94 m_iStatus = STATUS_UNKNOWN;
95 m_dwIpAddr = dwAddr;
96 m_dwFlags = dwFlags;
97 m_dwDynamicFlags = 0;
98 m_zoneId = dwZone;
99 m_wAgentPort = AGENT_LISTEN_PORT;
100 m_wAuthMethod = AUTH_NONE;
101 m_szSharedSecret[0] = 0;
102 m_iStatusPollType = POLL_ICMP_PING;
103 m_snmpVersion = SNMP_VERSION_1;
104 m_wSNMPPort = SNMP_DEFAULT_PORT;
105 char community[MAX_COMMUNITY_LENGTH];
106 ConfigReadStrA(_T("DefaultCommunityString"), community, MAX_COMMUNITY_LENGTH, "public");
107 m_snmpSecurity = new SNMP_SecurityContext(community);
108 IpToStr(dwAddr, m_szName); // Make default name from IP address
109 m_szObjectId[0] = 0;
110 m_tLastDiscoveryPoll = 0;
111 m_tLastStatusPoll = 0;
112 m_tLastConfigurationPoll = 0;
113 m_tLastRTUpdate = 0;
114 m_hPollerMutex = MutexCreate();
115 m_hAgentAccessMutex = MutexCreate();
116 m_mutexRTAccess = MutexCreate();
117 m_mutexTopoAccess = MutexCreate();
118 m_pAgentConnection = NULL;
119 m_szAgentVersion[0] = 0;
120 m_szPlatformName[0] = 0;
121 m_sysDescription = NULL;
122 m_sysName = NULL;
123 m_lldpNodeId = NULL;
124 m_dwNumParams = 0;
125 m_pParamList = NULL;
126 m_dwPollerNode = 0;
127 m_dwProxyNode = dwProxyNode;
128 m_dwSNMPProxy = dwSNMPProxy;
129 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
130 m_bIsHidden = TRUE;
131 m_pRoutingTable = NULL;
132 m_tFailTimeSNMP = 0;
133 m_tFailTimeAgent = 0;
134 m_linkLayerNeighbors = NULL;
135 m_vrrpInfo = NULL;
136 m_tLastTopologyPoll = 0;
137 m_pTopology = NULL;
138 m_topologyRebuildTimestamp = 0;
139 m_iPendingStatus = -1;
140 m_iPollCount = 0;
141 m_iRequiredPollCount = 0; // Use system default
142 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
143 m_jobQueue = new ServerJobQueue();
144 m_fdb = NULL;
145 m_driver = NULL;
146 }
147
148
149 //
150 // Node destructor
151 //
152
153 Node::~Node()
154 {
155 MutexDestroy(m_hPollerMutex);
156 MutexDestroy(m_hAgentAccessMutex);
157 MutexDestroy(m_mutexRTAccess);
158 MutexDestroy(m_mutexTopoAccess);
159 delete m_pAgentConnection;
160 safe_free(m_pParamList);
161 DestroyRoutingTable(m_pRoutingTable);
162 if (m_linkLayerNeighbors != NULL)
163 m_linkLayerNeighbors->decRefCount();
164 delete m_vrrpInfo;
165 delete m_pTopology;
166 delete m_jobQueue;
167 delete m_snmpSecurity;
168 if (m_fdb != NULL)
169 m_fdb->decRefCount();
170 }
171
172
173 //
174 // Create object from database data
175 //
176
177 BOOL Node::CreateFromDB(DWORD dwId)
178 {
179 TCHAR query[1024];
180 DB_RESULT hResult;
181 int i, iNumRows;
182 DWORD dwSubnetId;
183 NetObj *pObject;
184 BOOL bResult = FALSE;
185
186 m_dwId = dwId;
187
188 if (!LoadCommonProperties())
189 {
190 DbgPrintf(2, _T("Cannot load common properties for node object %d"), dwId);
191 return FALSE;
192 }
193
194 _sntprintf(query, 1024, _T("SELECT primary_name,primary_ip,node_flags,")
195 _T("snmp_version,auth_method,secret,")
196 _T("agent_port,status_poll_type,snmp_oid,agent_version,")
197 _T("platform_name,poller_node_id,zone_guid,")
198 _T("proxy_node,snmp_proxy,required_polls,uname,")
199 _T("use_ifxtable,snmp_port,community,usm_auth_password,")
200 _T("usm_priv_password,usm_methods,snmp_sys_name")
201 _T(" FROM nodes WHERE id=%d"), dwId);
202 hResult = DBSelect(g_hCoreDB, query);
203 if (hResult == NULL)
204 return FALSE; // Query failed
205
206 if (DBGetNumRows(hResult) == 0)
207 {
208 DBFreeResult(hResult);
209 DbgPrintf(2, _T("Missing record in \"nodes\" table for node object %d"), dwId);
210 return FALSE;
211 }
212
213 DBGetField(hResult, 0, 0, m_primaryName, MAX_DNS_NAME);
214 m_dwIpAddr = DBGetFieldIPAddr(hResult, 0, 1);
215 m_dwFlags = DBGetFieldULong(hResult, 0, 2);
216 m_snmpVersion = DBGetFieldLong(hResult, 0, 3);
217 m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 4);
218 DBGetField(hResult, 0, 5, m_szSharedSecret, MAX_SECRET_LENGTH);
219 m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 6);
220 m_iStatusPollType = DBGetFieldLong(hResult, 0, 7);
221 DBGetField(hResult, 0, 8, m_szObjectId, MAX_OID_LEN * 4);
222 DBGetField(hResult, 0, 9, m_szAgentVersion, MAX_AGENT_VERSION_LEN);
223 DBGetField(hResult, 0, 10, m_szPlatformName, MAX_PLATFORM_NAME_LEN);
224 m_dwPollerNode = DBGetFieldULong(hResult, 0, 11);
225 m_zoneId = DBGetFieldULong(hResult, 0, 12);
226 m_dwProxyNode = DBGetFieldULong(hResult, 0, 13);
227 m_dwSNMPProxy = DBGetFieldULong(hResult, 0, 14);
228 m_iRequiredPollCount = DBGetFieldLong(hResult, 0, 15);
229 m_sysDescription = DBGetField(hResult, 0, 16, NULL, 0);
230 m_nUseIfXTable = (BYTE)DBGetFieldLong(hResult, 0, 17);
231 m_wSNMPPort = (WORD)DBGetFieldLong(hResult, 0, 18);
232
233 // SNMP authentication parameters
234 char snmpAuthObject[256], snmpAuthPassword[256], snmpPrivPassword[256];
235 DBGetFieldA(hResult, 0, 19, snmpAuthObject, 256);
236 DBGetFieldA(hResult, 0, 20, snmpAuthPassword, 256);
237 DBGetFieldA(hResult, 0, 21, snmpPrivPassword, 256);
238 int snmpMethods = DBGetFieldLong(hResult, 0, 21);
239 delete m_snmpSecurity;
240 m_snmpSecurity = new SNMP_SecurityContext(snmpAuthObject, snmpAuthPassword, snmpPrivPassword, snmpMethods & 0xFF, snmpMethods >> 8);
241 m_snmpSecurity->setSecurityModel((m_snmpVersion == SNMP_VERSION_3) ? SNMP_SECURITY_MODEL_USM : SNMP_SECURITY_MODEL_V2C);
242
243 m_sysName = DBGetField(hResult, 0, 22, NULL, 0);
244
245 DBFreeResult(hResult);
246
247 if (!m_bIsDeleted)
248 {
249 // Link node to subnets
250 _sntprintf(query, 1024, _T("SELECT subnet_id FROM nsmap WHERE node_id=%d"), dwId);
251 hResult = DBSelect(g_hCoreDB, query);
252 if (hResult == NULL)
253 return FALSE; // Query failed
254
255 iNumRows = DBGetNumRows(hResult);
256 for(i = 0; i < iNumRows; i++)
257 {
258 dwSubnetId = DBGetFieldULong(hResult, i, 0);
259 pObject = FindObjectById(dwSubnetId);
260 if (pObject == NULL)
261 {
262 nxlog_write(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
263 break;
264 }
265 else if (pObject->Type() != OBJECT_SUBNET)
266 {
267 nxlog_write(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
268 break;
269 }
270 else
271 {
272 pObject->AddChild(this);
273 AddParent(pObject);
274 }
275 }
276
277 DBFreeResult(hResult);
278 loadItemsFromDB();
279 LoadACLFromDB();
280
281 // Walk through all items in the node and load appropriate thresholds
282 bResult = TRUE;
283 for(i = 0; i < (int)m_dwNumItems; i++)
284 if (!m_ppItems[i]->loadThresholdsFromDB())
285 {
286 DbgPrintf(3, _T("Cannot load thresholds for DCI %d of node %d (%s)"),
287 m_ppItems[i]->getId(), dwId, m_szName);
288 bResult = FALSE;
289 }
290 }
291 else
292 {
293 bResult = TRUE;
294 }
295
296 return bResult;
297 }
298
299
300 //
301 // Save object to database
302 //
303
304 BOOL Node::SaveToDB(DB_HANDLE hdb)
305 {
306 TCHAR szQuery[4096], szIpAddr[16];
307 DB_RESULT hResult;
308 BOOL bNewObject = TRUE;
309 BOOL bResult;
310
311 // Lock object's access
312 LockData();
313
314 SaveCommonProperties(hdb);
315
316 // Check for object's existence in database
317 _sntprintf(szQuery, 4096, _T("SELECT id FROM nodes WHERE id=%d"), m_dwId);
318 hResult = DBSelect(hdb, szQuery);
319 if (hResult != 0)
320 {
321 if (DBGetNumRows(hResult) > 0)
322 bNewObject = FALSE;
323 DBFreeResult(hResult);
324 }
325
326 // Form and execute INSERT or UPDATE query
327 int snmpMethods = m_snmpSecurity->getAuthMethod() | (m_snmpSecurity->getPrivMethod() << 8);
328 if (bNewObject)
329 {
330 _sntprintf(szQuery, 4096,
331 _T("INSERT INTO nodes (id,primary_ip,primary_name,snmp_port,")
332 _T("node_flags,snmp_version,community,status_poll_type,")
333 _T("agent_port,auth_method,secret,snmp_oid,proxy_node,")
334 _T("agent_version,platform_name,uname,")
335 _T("poller_node_id,zone_guid,snmp_proxy,required_polls,")
336 _T("use_ifxtable,usm_auth_password,usm_priv_password,usm_methods,snmp_sys_name) VALUES ")
337 _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)"),
338 m_dwId, IpToStr(m_dwIpAddr, szIpAddr), (const TCHAR *)DBPrepareString(hdb, m_primaryName),
339 (int)m_wSNMPPort, m_dwFlags, m_snmpVersion, (
340 const TCHAR *)DBPrepareStringA(hdb, m_snmpSecurity->getCommunity()),
341 m_iStatusPollType, (int)m_wAgentPort, m_wAuthMethod,
342 (const TCHAR *)DBPrepareString(hdb, m_szSharedSecret),
343 (const TCHAR *)DBPrepareString(hdb, m_szObjectId),
344 m_dwProxyNode, (const TCHAR *)DBPrepareString(hdb, m_szAgentVersion),
345 (const TCHAR *)DBPrepareString(hdb, m_szPlatformName),
346 (const TCHAR *)DBPrepareString(hdb, m_sysDescription),
347 m_dwPollerNode, m_zoneId, m_dwSNMPProxy, m_iRequiredPollCount, m_nUseIfXTable,
348 (const TCHAR *)DBPrepareStringA(hdb, m_snmpSecurity->getAuthPassword()),
349 (const TCHAR *)DBPrepareStringA(hdb, m_snmpSecurity->getPrivPassword()), snmpMethods,
350 (const TCHAR *)DBPrepareString(hdb, m_sysName));
351 }
352 else
353 {
354 _sntprintf(szQuery, 4096,
355 _T("UPDATE nodes SET primary_ip='%s',primary_name=%s,snmp_port=%d,")
356 _T("node_flags=%d,snmp_version=%d,community=%s,")
357 _T("status_poll_type=%d,agent_port=%d,auth_method=%d,secret=%s,")
358 _T("snmp_oid=%s,uname=%s,agent_version=%s,platform_name=%s,poller_node_id=%d,")
359 _T("zone_guid=%d,proxy_node=%d,snmp_proxy=%d,")
360 _T("required_polls=%d,use_ifxtable=%d,usm_auth_password=%s,")
361 _T("usm_priv_password=%s,usm_methods=%d,snmp_sys_name=%s WHERE id=%d"),
362 IpToStr(m_dwIpAddr, szIpAddr), (const TCHAR *)DBPrepareString(hdb, m_primaryName), m_wSNMPPort,
363 m_dwFlags, m_snmpVersion, (const TCHAR *)DBPrepareStringA(hdb, m_snmpSecurity->getCommunity()),
364 m_iStatusPollType, m_wAgentPort, m_wAuthMethod,
365 (const TCHAR *)DBPrepareString(hdb, m_szSharedSecret),
366 (const TCHAR *)DBPrepareString(hdb, m_szObjectId),
367 (const TCHAR *)DBPrepareString(hdb, m_sysDescription),
368 (const TCHAR *)DBPrepareString(hdb, m_szAgentVersion),
369 (const TCHAR *)DBPrepareString(hdb, m_szPlatformName), m_dwPollerNode, m_zoneId,
370 m_dwProxyNode, m_dwSNMPProxy, m_iRequiredPollCount,
371 m_nUseIfXTable, (const TCHAR *)DBPrepareStringA(hdb, m_snmpSecurity->getAuthPassword()),
372 (const TCHAR *)DBPrepareStringA(hdb, m_snmpSecurity->getPrivPassword()), snmpMethods,
373 (const TCHAR *)DBPrepareString(hdb, m_sysName), m_dwId);
374 }
375 bResult = DBQuery(hdb, szQuery);
376
377 // Save access list
378 SaveACLToDB(hdb);
379
380 UnlockData();
381
382 // Save data collection items
383 if (bResult)
384 {
385 DWORD i;
386
387 lockDciAccess();
388 for(i = 0; i < m_dwNumItems; i++)
389 m_ppItems[i]->saveToDB(hdb);
390 unlockDciAccess();
391 }
392
393 // Clear modifications flag
394 LockData();
395 m_bIsModified = FALSE;
396 UnlockData();
397
398 return bResult;
399 }
400
401
402 //
403 // Delete object from database
404 //
405
406 BOOL Node::DeleteFromDB()
407 {
408 TCHAR szQuery[256];
409 BOOL bSuccess;
410
411 bSuccess = Template::DeleteFromDB();
412 if (bSuccess)
413 {
414 _sntprintf(szQuery, 256, _T("DELETE FROM nodes WHERE id=%d"), m_dwId);
415 QueueSQLRequest(szQuery);
416 _sntprintf(szQuery, 256, _T("DELETE FROM nsmap WHERE node_id=%d"), m_dwId);
417 QueueSQLRequest(szQuery);
418 _sntprintf(szQuery, 256, _T("DROP TABLE idata_%d"), m_dwId);
419 QueueSQLRequest(szQuery);
420 }
421 return bSuccess;
422 }
423
424
425 //
426 // Get ARP cache from node
427 //
428
429 ARP_CACHE *Node::getArpCache()
430 {
431 ARP_CACHE *pArpCache = NULL;
432
433 if (m_dwFlags & NF_IS_LOCAL_MGMT)
434 {
435 pArpCache = GetLocalArpCache();
436 }
437 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
438 {
439 agentLock();
440 if (connectToAgent())
441 pArpCache = m_pAgentConnection->getArpCache();
442 agentUnlock();
443 }
444 else if (m_dwFlags & NF_IS_SNMP)
445 {
446 SNMP_Transport *pTransport;
447
448 pTransport = createSnmpTransport();
449 if (pTransport != NULL)
450 {
451 pArpCache = SnmpGetArpCache(m_snmpVersion, pTransport);
452 delete pTransport;
453 }
454 }
455
456 return pArpCache;
457 }
458
459
460 //
461 // Get list of interfaces from node
462 //
463
464 InterfaceList *Node::getInterfaceList()
465 {
466 InterfaceList *pIfList = NULL;
467
468 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)))
469 {
470 agentLock();
471 if (connectToAgent())
472 {
473 pIfList = m_pAgentConnection->getInterfaceList();
474 }
475 agentUnlock();
476 }
477 if ((pIfList == NULL) && (m_dwFlags & NF_IS_LOCAL_MGMT))
478 {
479 pIfList = GetLocalInterfaceList();
480 }
481 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP) &&
482 (!(m_dwFlags & NF_DISABLE_SNMP)) && (m_driver != NULL))
483 {
484 SNMP_Transport *pTransport;
485 bool useIfXTable;
486
487 pTransport = createSnmpTransport();
488 if (pTransport != NULL)
489 {
490 if (m_nUseIfXTable == IFXTABLE_DEFAULT)
491 {
492 useIfXTable = (ConfigReadInt(_T("UseIfXTable"), 1) != 0) ? true : false;
493 }
494 else
495 {
496 useIfXTable = (m_nUseIfXTable == IFXTABLE_ENABLED) ? true : false;
497 }
498
499 int useAliases = ConfigReadInt(_T("UseInterfaceAliases"), 0);
500 pIfList = m_driver->getInterfaces(pTransport, &m_customAttributes, useAliases, useIfXTable);
501
502 if ((pIfList != NULL) && (m_dwFlags & NF_IS_BRIDGE))
503 {
504 BridgeMapPorts(m_snmpVersion, pTransport, pIfList);
505 }
506 delete pTransport;
507 }
508 }
509
510 if (pIfList != NULL)
511 {
512 pIfList->removeLoopbacks();
513 CheckInterfaceNames(pIfList);
514 addVrrpInterfaces(pIfList);
515 }
516
517 return pIfList;
518 }
519
520
521 //
522 // Add VRRP interfaces to interface list
523 //
524
525 void Node::addVrrpInterfaces(InterfaceList *ifList)
526 {
527 int i, j, k;
528 TCHAR buffer[32];
529
530 LockData();
531 if (m_vrrpInfo != NULL)
532 {
533 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): m_vrrpInfo->getSize()=%d"), m_szName, (int)m_dwId, m_vrrpInfo->getSize());
534
535 for(i = 0; i < m_vrrpInfo->getSize(); i++)
536 {
537 VrrpRouter *router = m_vrrpInfo->getRouter(i);
538 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): vrouter %d state=%d"), m_szName, (int)m_dwId, i, router->getState());
539 if (router->getState() != VRRP_STATE_MASTER)
540 continue; // Do not add interfaces if router is not in master state
541
542 // Get netmask for this VR
543 DWORD netmask = 0;
544 for(j = 0; j < ifList->getSize(); j++)
545 if (ifList->get(j)->dwIndex == router->getIfIndex())
546 {
547 netmask = ifList->get(j)->dwIpNetMask;
548 break;
549 }
550
551 // Walk through all VR virtual IPs
552 for(j = 0; j < router->getVipCount(); j++)
553 {
554 DWORD vip = router->getVip(j);
555 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): checking VIP %s@%d"), m_szName, (int)m_dwId, IpToStr(vip, buffer), i);
556 if (vip != 0)
557 {
558 for(k = 0; k < ifList->getSize(); k++)
559 if (ifList->get(k)->dwIpAddr == vip)
560 break;
561 if (k == ifList->getSize())
562 {
563 INTERFACE_INFO iface;
564 memset(&iface, 0, sizeof(INTERFACE_INFO));
565 _sntprintf(iface.szName, MAX_DB_STRING, _T("vrrp.%u.%u.%d"), router->getId(), router->getIfIndex(), j);
566 memcpy(iface.bMacAddr, router->getVirtualMacAddr(), MAC_ADDR_LENGTH);
567 iface.dwIpAddr = vip;
568 iface.dwIpNetMask = netmask;
569 ifList->add(&iface);
570 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): added interface %s"), m_szName, (int)m_dwId, iface.szName);
571 }
572 }
573 }
574 }
575 }
576 UnlockData();
577 }
578
579
580 //
581 // Find interface by index and node IP
582 // Returns pointer to interface object or NULL if appropriate interface couldn't be found
583 //
584
585 Interface *Node::findInterface(DWORD dwIndex, DWORD dwHostAddr)
586 {
587 DWORD i;
588 Interface *pInterface;
589
590 LockChildList(FALSE);
591 for(i = 0; i < m_dwChildCount; i++)
592 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
593 {
594 pInterface = (Interface *)m_pChildList[i];
595 if (pInterface->getIfIndex() == dwIndex)
596 {
597 if (((pInterface->IpAddr() & pInterface->getIpNetMask()) ==
598 (dwHostAddr & pInterface->getIpNetMask())) ||
599 (dwHostAddr == INADDR_ANY))
600 {
601 UnlockChildList();
602 return pInterface;
603 }
604 }
605 }
606 UnlockChildList();
607 return NULL;
608 }
609
610
611 //
612 // Find interface by name
613 // Returns pointer to interface object or NULL if appropriate interface couldn't be found
614 //
615
616 Interface *Node::findInterface(const TCHAR *name)
617 {
618 DWORD i;
619 Interface *pInterface;
620
621 LockChildList(FALSE);
622 for(i = 0; i < m_dwChildCount; i++)
623 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
624 {
625 pInterface = (Interface *)m_pChildList[i];
626 if (!_tcsicmp(pInterface->Name(), name))
627 {
628 UnlockChildList();
629 return pInterface;
630 }
631 }
632 UnlockChildList();
633 return NULL;
634 }
635
636
637 //
638 // Find interface by slot/port pair
639 // Returns pointer to interface object or NULL if appropriate interface couldn't be found
640 //
641
642 Interface *Node::findInterfaceBySlotAndPort(DWORD slot, DWORD port)
643 {
644 DWORD i;
645 Interface *pInterface;
646
647 if ((slot == 0) || (port == 0))
648 return NULL;
649
650 LockChildList(FALSE);
651 for(i = 0; i < m_dwChildCount; i++)
652 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
653 {
654 pInterface = (Interface *)m_pChildList[i];
655 if ((pInterface->getSlotNumber() == slot) && (pInterface->getPortNumber() == port))
656 {
657 UnlockChildList();
658 return pInterface;
659 }
660 }
661 UnlockChildList();
662 return NULL;
663 }
664
665
666 //
667 // Find interface by MAC address
668 // Returns pointer to interface object or NULL if appropriate interface couldn't be found
669 //
670
671 Interface *Node::findInterfaceByMAC(const BYTE *macAddr)
672 {
673 DWORD i;
674 Interface *pInterface;
675
676 LockChildList(FALSE);
677 for(i = 0; i < m_dwChildCount; i++)
678 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
679 {
680 pInterface = (Interface *)m_pChildList[i];
681 if (!memcmp(pInterface->getMacAddr(), macAddr, MAC_ADDR_LENGTH))
682 {
683 UnlockChildList();
684 return pInterface;
685 }
686 }
687 UnlockChildList();
688 return NULL;
689 }
690
691
692 //
693 // Find interface by IP address
694 // Returns pointer to interface object or NULL if appropriate interface couldn't be found
695 //
696
697 Interface *Node::findInterfaceByIP(DWORD ipAddr)
698 {
699 DWORD i;
700 Interface *pInterface;
701
702 if (ipAddr == 0)
703 return NULL;
704
705 LockChildList(FALSE);
706 for(i = 0; i < m_dwChildCount; i++)
707 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
708 {
709 pInterface = (Interface *)m_pChildList[i];
710 if (pInterface->IpAddr() == ipAddr)
711 {
712 UnlockChildList();
713 return pInterface;
714 }
715 }
716 UnlockChildList();
717 return NULL;
718 }
719
720
721 //
722 // Find interface by bridge port number
723 //
724
725 Interface *Node::findBridgePort(DWORD bridgePortNumber)
726 {
727 DWORD i;
728 Interface *pInterface;
729
730 LockChildList(FALSE);
731 for(i = 0; i < m_dwChildCount; i++)
732 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
733 {
734 pInterface = (Interface *)m_pChildList[i];
735 if (pInterface->getBridgePortNumber() == bridgePortNumber)
736 {
737 UnlockChildList();
738 return pInterface;
739 }
740 }
741 UnlockChildList();
742 return NULL;
743 }
744
745
746 //
747 // Find connection point for node
748 //
749
750 Interface *Node::findConnectionPoint(DWORD *localIfId, BYTE *localMacAddr)
751 {
752 Interface *cp = NULL;
753 LockChildList(FALSE);
754 for(DWORD i = 0; i < m_dwChildCount; i++)
755 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
756 {
757 Interface *iface = (Interface *)m_pChildList[i];
758 cp = FindInterfaceConnectionPoint(iface->getMacAddr());
759 if (cp != NULL)
760 {
761 *localIfId = iface->Id();
762 memcpy(localMacAddr, iface->getMacAddr(), MAC_ADDR_LENGTH);
763 break;
764 }
765 }
766 UnlockChildList();
767 return cp;
768 }
769
770
771 //
772 // Check if given IP address is one of node's interfaces
773 //
774
775 BOOL Node::isMyIP(DWORD dwIpAddr)
776 {
777 DWORD i;
778
779 LockChildList(FALSE);
780 for(i = 0; i < m_dwChildCount; i++)
781 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
782 {
783 if (((Interface *)m_pChildList[i])->IpAddr() == dwIpAddr)
784 {
785 UnlockChildList();
786 return TRUE;
787 }
788 }
789 UnlockChildList();
790 return FALSE;
791 }
792
793
794 //
795 // Create new interface
796 //
797
798 void Node::createNewInterface(DWORD dwIpAddr, DWORD dwNetMask, const TCHAR *name,
799 DWORD dwIndex, DWORD dwType, BYTE *pbMacAddr, DWORD bridgePort,
800 DWORD slot, DWORD port)
801 {
802 Interface *pInterface;
803 Subnet *pSubnet = NULL;
804 Cluster *pCluster;
805 bool bAddToSubnet, bSyntheticMask = false;
806
807 DbgPrintf(5, _T("Node::createNewInterface(%08X, %08X, %s, %d, %d, bp=%d, slot=%d, port=%d) called for node %s [%d]"),
808 dwIpAddr, dwNetMask, CHECK_NULL(name), dwIndex, dwType, bridgePort, slot, port, m_szName, m_dwId);
809
810 // Find subnet to place interface object to
811 if (dwIpAddr != 0)
812 {
813 pCluster = getMyCluster();
814 bAddToSubnet = (pCluster != NULL) ? !pCluster->isSyncAddr(dwIpAddr) : TRUE;
815 DbgPrintf(5, _T("Node::createNewInterface: node=%s [%d] cluster=%s [%d] add=%d"),
816 m_szName, m_dwId, (pCluster != NULL) ? pCluster->Name() : _T("(null)"),
817 (pCluster != NULL) ? pCluster->Id() : 0, bAddToSubnet);
818 if (bAddToSubnet)
819 {
820 pSubnet = FindSubnetForNode(dwIpAddr);
821 if (pSubnet == NULL)
822 {
823 // Check if netmask is 0 (detect), and if yes, create
824 // new subnet with class mask
825 if (dwNetMask == 0)
826 {
827 bSyntheticMask = TRUE;
828 if (dwIpAddr < 0xE0000000)
829 {
830 dwNetMask = 0xFFFFFF00; // Class A, B or C
831 }
832 else
833 {
834 TCHAR szBuffer[16];
835
836 // Multicast address??
837 DbgPrintf(2, _T("Attempt to create interface object with multicast address %s"),
838 IpToStr(dwIpAddr, szBuffer));
839 }
840 }
841
842 // Create new subnet object
843 if (dwIpAddr < 0xE0000000)
844 {
845 pSubnet = new Subnet(dwIpAddr & dwNetMask, dwNetMask, m_zoneId, bSyntheticMask);
846 NetObjInsert(pSubnet, TRUE);
847 g_pEntireNet->AddSubnet(pSubnet);
848 }
849 }
850 else
851 {
852 // Set correct netmask if we was asked for it
853 if (dwNetMask == 0)
854 {
855 dwNetMask = pSubnet->getIpNetMask();
856 bSyntheticMask = pSubnet->isSyntheticMask();
857 }
858 }
859 }
860 }
861
862 // Create interface object
863 if (name != NULL)
864 pInterface = new Interface(name, dwIndex, dwIpAddr, dwNetMask, dwType);
865 else
866 pInterface = new Interface(dwIpAddr, dwNetMask, bSyntheticMask);
867 if (pbMacAddr != NULL)
868 pInterface->setMacAddr(pbMacAddr);
869 pInterface->setBridgePortNumber(bridgePort);
870 pInterface->setSlotNumber(slot);
871 pInterface->setPortNumber(port);
872
873 // Insert to objects' list and generate event
874 NetObjInsert(pInterface, TRUE);
875 addInterface(pInterface);
876 if (!m_bIsHidden)
877 pInterface->Unhide();
878 PostEvent(EVENT_INTERFACE_ADDED, m_dwId, "dsaad", pInterface->Id(),
879 pInterface->Name(), pInterface->IpAddr(),
880 pInterface->getIpNetMask(), pInterface->getIfIndex());
881
882 // Bind node to appropriate subnet
883 if (pSubnet != NULL)
884 {
885 pSubnet->AddNode(this);
886
887 // Check if subnet mask is correct on interface
888 if ((pSubnet->getIpNetMask() != pInterface->getIpNetMask()) && !pSubnet->isSyntheticMask())
889 {
890 PostEvent(EVENT_INCORRECT_NETMASK, m_dwId, "idsaa", pInterface->Id(),
891 pInterface->getIfIndex(), pInterface->Name(),
892 pInterface->getIpNetMask(), pSubnet->getIpNetMask());
893 }
894 }
895 }
896
897
898 //
899 // Delete interface from node
900 //
901
902 void Node::deleteInterface(Interface *pInterface)
903 {
904 DWORD i;
905
906 DbgPrintf(5, _T("Node::deleteInterface(node=%s [%d], interface=%s [%d])"), m_szName, m_dwId, pInterface->Name(), pInterface->Id());
907
908 // Check if we should unlink node from interface's subnet
909 if (pInterface->IpAddr() != 0)
910 {
911 BOOL bUnlink = TRUE;
912
913 LockChildList(FALSE);
914 for(i = 0; i < m_dwChildCount; i++)
915 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
916 if (m_pChildList[i] != pInterface)
917 if ((((Interface *)m_pChildList[i])->IpAddr() & ((Interface *)m_pChildList[i])->getIpNetMask()) ==
918 (pInterface->IpAddr() & pInterface->getIpNetMask()))
919 {
920 bUnlink = FALSE;
921 break;
922 }
923 UnlockChildList();
924
925 if (bUnlink)
926 {
927 // Last interface in subnet, should unlink node
928 Subnet *pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->getIpNetMask());
929 if (pSubnet != NULL)
930 {
931 DeleteParent(pSubnet);
932 pSubnet->DeleteChild(this);
933 }
934 DbgPrintf(5, _T("Node::deleteInterface(node=%s [%d], interface=%s [%d]): unlinked from subnet %s [%d]"),
935 m_szName, m_dwId, pInterface->Name(), pInterface->Id(), pSubnet->Name(), pSubnet->Id());
936 }
937 }
938 pInterface->Delete(FALSE);
939 }
940
941
942 //
943 // Calculate node status based on child objects status
944 //
945
946 void Node::CalculateCompoundStatus(BOOL bForcedRecalc)
947 {
948 int iOldStatus = m_iStatus;
949 static DWORD dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_MINOR,
950 EVENT_NODE_WARNING, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
951 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
952
953 NetObj::CalculateCompoundStatus(bForcedRecalc);
954 if (m_iStatus != iOldStatus)
955 PostEvent(dwEventCodes[m_iStatus], m_dwId, "d", iOldStatus);
956 }
957
958
959 //
960 // Perform status poll on node
961 //
962
963 void Node::statusPoll(ClientSession *pSession, DWORD dwRqId, int nPoller)
964 {
965 DWORD i, dwPollListSize, dwOldFlags = m_dwFlags;
966 NetObj *pPollerNode = NULL, **ppPollList;
967 BOOL bAllDown;
968 Queue *pQueue; // Delayed event queue
969 SNMP_Transport *pTransport;
970 Cluster *pCluster;
971 time_t tNow, tExpire;
972
973 pQueue = new Queue;
974 SetPollerInfo(nPoller, _T("wait for lock"));
975 pollerLock();
976 m_pPollRequestor = pSession;
977 SendPollerMsg(dwRqId, _T("Starting status poll for node %s\r\n"), m_szName);
978 DbgPrintf(5, _T("Starting status poll for node %s (ID: %d)"), m_szName, m_dwId);
979
980 // Read capability expiration time and current time
981 tExpire = (time_t)ConfigReadULong(_T("CapabilityExpirationTime"), 604800);
982 tNow = time(NULL);
983
984 // Check SNMP agent connectivity
985 restart_agent_check:
986 if ((m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)) && (m_dwIpAddr != 0))
987 {
988 TCHAR szBuffer[256];
989 DWORD dwResult;
990
991 DbgPrintf(6, _T("StatusPoll(%s): check SNMP"), m_szName);
992 pTransport = createSnmpTransport();
993 if (pTransport == NULL)
994 {
995 DbgPrintf(6, _T("StatusPoll(%s): cannot create SNMP transport"), m_szName);
996 goto skip_snmp_check;
997 }
998
999 SetPollerInfo(nPoller, _T("check SNMP"));
1000 SendPollerMsg(dwRqId, _T("Checking SNMP agent connectivity\r\n"));
1001 dwResult = SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.1.2.0"), NULL, 0, szBuffer, 256, 0);
1002 if ((dwResult == SNMP_ERR_SUCCESS) || (dwResult == SNMP_ERR_NO_OBJECT))
1003 {
1004 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
1005 {
1006 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1007 PostEventEx(pQueue, EVENT_SNMP_OK, m_dwId, NULL);
1008 SendPollerMsg(dwRqId, POLLER_INFO _T("Connectivity with SNMP agent restored\r\n"));
1009 }
1010 }
1011 else
1012 {
1013 SendPollerMsg(dwRqId, POLLER_ERROR _T("SNMP agent unreachable\r\n"));
1014 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
1015 {
1016 if ((tNow > m_tFailTimeSNMP + tExpire) &&
1017 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
1018 {
1019 m_dwFlags &= ~NF_IS_SNMP;
1020 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1021 m_szObjectId[0] = 0;
1022 SendPollerMsg(dwRqId, POLLER_WARNING _T("Attribute isSNMP set to FALSE\r\n"));
1023 }
1024 }
1025 else
1026 {
1027 m_dwDynamicFlags |= NDF_SNMP_UNREACHABLE;
1028 PostEventEx(pQueue, EVENT_SNMP_FAIL, m_dwId, NULL);
1029 m_tFailTimeSNMP = tNow;
1030 }
1031 }
1032 delete pTransport;
1033 DbgPrintf(6, _T("StatusPoll(%s): SNMP check finished"), m_szName);
1034 }
1035
1036 skip_snmp_check:
1037 // Check native agent connectivity
1038 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)) && (m_dwIpAddr != 0))
1039 {
1040 DbgPrintf(6, _T("StatusPoll(%s): checking agent"), m_szName);
1041 SetPollerInfo(nPoller, _T("check agent"));
1042 SendPollerMsg(dwRqId, _T("Checking NetXMS agent connectivity\r\n"));
1043
1044 DWORD error, socketError;
1045 agentLock();
1046 if (connectToAgent(&error, &socketError))
1047 {
1048 DbgPrintf(7, _T("StatusPoll(%s): connected to agent"), m_szName);
1049 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1050 {
1051 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1052 PostEventEx(pQueue, EVENT_AGENT_OK, m_dwId, NULL);
1053 SendPollerMsg(dwRqId, POLLER_INFO _T("Connectivity with NetXMS agent restored\r\n"));
1054 }
1055 }
1056 else
1057 {
1058 DbgPrintf(6, _T("StatusPoll(%s): agent unreachable, error=%d, socketError=%d"), m_szName, (int)error, (int)socketError);
1059 SendPollerMsg(dwRqId, POLLER_ERROR _T("NetXMS agent unreachable\r\n"));
1060 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1061 {
1062 if ((tNow > m_tFailTimeAgent + tExpire) &&
1063 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
1064 {
1065 m_dwFlags &= ~NF_IS_NATIVE_AGENT;
1066 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1067 m_szPlatformName[0] = 0;
1068 m_szAgentVersion[0] = 0;
1069 SendPollerMsg(dwRqId, POLLER_WARNING _T("Attribute isNetXMSAgent set to FALSE\r\n"));
1070 }
1071 }
1072 else
1073 {
1074 m_dwDynamicFlags |= NDF_AGENT_UNREACHABLE;
1075 PostEventEx(pQueue, EVENT_AGENT_FAIL, m_dwId, NULL);
1076 m_tFailTimeAgent = tNow;
1077 }
1078 }
1079 agentUnlock();
1080 DbgPrintf(7, _T("StatusPoll(%s): agent check finished"), m_szName);
1081 }
1082
1083 SetPollerInfo(nPoller, _T("prepare polling list"));
1084
1085 // Find service poller node object
1086 LockData();
1087 if (m_dwPollerNode != 0)
1088 {
1089 pPollerNode = FindObjectById(m_dwPollerNode);
1090 if (pPollerNode != NULL)
1091 {
1092 if (pPollerNode->Type() != OBJECT_NODE)
1093 pPollerNode = NULL;
1094 }
1095 }
1096 UnlockData();
1097
1098 // If nothing found, use management server
1099 if (pPollerNode == NULL)
1100 {
1101 pPollerNode = FindObjectById(g_dwMgmtNode);
1102 if (pPollerNode != NULL)
1103 pPollerNode->IncRefCount();
1104 }
1105 else
1106 {
1107 pPollerNode->IncRefCount();
1108 }
1109
1110 // Create polling list
1111 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_dwChildCount);
1112 LockChildList(FALSE);
1113 for(i = 0, dwPollListSize = 0; i < m_dwChildCount; i++)
1114 if (m_pChildList[i]->Status() != STATUS_UNMANAGED)
1115 {
1116 m_pChildList[i]->IncRefCount();
1117 ppPollList[dwPollListSize++] = m_pChildList[i];
1118 }
1119 UnlockChildList();
1120
1121 // Poll interfaces and services
1122 SetPollerInfo(nPoller, _T("child poll"));
1123 DbgPrintf(7, _T("StatusPoll(%s): starting child object poll"), m_szName);
1124 pCluster = getMyCluster();
1125 pTransport = createSnmpTransport();
1126 for(i = 0; i < dwPollListSize; i++)
1127 {
1128 switch(ppPollList[i]->Type())
1129 {
1130 case OBJECT_INTERFACE:
1131 DbgPrintf(7, _T("StatusPoll(%s): polling interface %d [%s]"), m_szName, ppPollList[i]->Id(), ppPollList[i]->Name());
1132 ((Interface *)ppPollList[i])->StatusPoll(pSession, dwRqId, pQueue,
1133 (pCluster != NULL) ? pCluster->isSyncAddr(((Interface *)ppPollList[i])->IpAddr()) : FALSE,
1134 pTransport);
1135 break;
1136 case OBJECT_NETWORKSERVICE:
1137 DbgPrintf(7, _T("StatusPoll(%s): polling network service %d [%s]"), m_szName, ppPollList[i]->Id(), ppPollList[i]->Name());
1138 ((NetworkService *)ppPollList[i])->StatusPoll(pSession, dwRqId,
1139 (Node *)pPollerNode, pQueue);
1140 break;
1141 default:
1142 break;
1143 }
1144 ppPollList[i]->DecRefCount();
1145 }
1146 delete pTransport;
1147 safe_free(ppPollList);
1148 DbgPrintf(7, _T("StatusPoll(%s): finished child object poll"), m_szName);
1149
1150 // Check if entire node is down
1151 // This check is disabled for nodes without IP address
1152 if (m_dwIpAddr != 0)
1153 {
1154 LockChildList(FALSE);
1155 if (m_dwChildCount > 0)
1156 {
1157 for(i = 0, bAllDown = TRUE; i < m_dwChildCount; i++)
1158 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1159 (m_pChildList[i]->Status() != STATUS_CRITICAL) &&
1160 (m_pChildList[i]->Status() != STATUS_UNKNOWN) &&
1161 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
1162 (m_pChildList[i]->Status() != STATUS_DISABLED))
1163 {
1164 bAllDown = FALSE;
1165 break;
1166 }
1167 }
1168 else
1169 {
1170 bAllDown = FALSE;
1171 }
1172 UnlockChildList();
1173 if (bAllDown && (m_dwFlags & NF_IS_NATIVE_AGENT) &&
1174 (!(m_dwFlags & NF_DISABLE_NXCP)))
1175 if (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))
1176 bAllDown = FALSE;
1177 if (bAllDown && (m_dwFlags & NF_IS_SNMP) &&
1178 (!(m_dwFlags & NF_DISABLE_SNMP)))
1179 if (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))
1180 bAllDown = FALSE;
1181 if (bAllDown)
1182 {
1183 if (!(m_dwDynamicFlags & NDF_UNREACHABLE))
1184 {
1185 m_dwDynamicFlags |= NDF_UNREACHABLE;
1186 PostEvent(EVENT_NODE_DOWN, m_dwId, NULL);
1187 SendPollerMsg(dwRqId, POLLER_ERROR _T("Node is unreachable\r\n"));
1188 }
1189 else
1190 {
1191 SendPollerMsg(dwRqId, POLLER_WARNING _T("Node is still unreachable\r\n"));
1192 }
1193 }
1194 else
1195 {
1196 if (m_dwDynamicFlags & NDF_UNREACHABLE)
1197 {
1198 m_dwDynamicFlags &= ~(NDF_UNREACHABLE | NDF_SNMP_UNREACHABLE | NDF_AGENT_UNREACHABLE);
1199 PostEvent(EVENT_NODE_UP, m_dwId, NULL);
1200 SendPollerMsg(dwRqId, POLLER_INFO _T("Node recovered from unreachable state\r\n"));
1201 goto restart_agent_check;
1202 }
1203 else
1204 {
1205 SendPollerMsg(dwRqId, POLLER_INFO _T("Node is connected\r\n"));
1206 }
1207 }
1208 }
1209
1210 // Send delayed events and destroy delayed event queue
1211 ResendEvents(pQueue);
1212 delete pQueue;
1213
1214 SetPollerInfo(nPoller, _T("cleanup"));
1215 if (pPollerNode != NULL)
1216 pPollerNode->DecRefCount();
1217
1218 if (dwOldFlags != m_dwFlags)
1219 {
1220 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
1221 LockData();
1222 Modify();
1223 UnlockData();
1224 }
1225
1226 CalculateCompoundStatus();
1227 m_tLastStatusPoll = time(NULL);
1228 SendPollerMsg(dwRqId, _T("Finished status poll for node %s\r\n"), m_szName);
1229 SendPollerMsg(dwRqId, _T("Node status after poll is %s\r\n"), g_szStatusText[m_iStatus]);
1230 m_pPollRequestor = NULL;
1231 if (dwRqId == 0)
1232 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_STATUS_POLL;
1233 pollerUnlock();
1234 DbgPrintf(5, _T("Finished status poll for node %s (ID: %d)"), m_szName, m_dwId);
1235 }
1236
1237
1238 //
1239 // Check agent policy binding
1240 // Intended to be called only from configuration poller
1241 //
1242
1243 void Node::checkAgentPolicyBinding(AgentConnection *conn)
1244 {
1245 AgentPolicyInfo *ap;
1246 DWORD rcc = conn->getPolicyInventory(&ap);
1247 if (rcc == ERR_SUCCESS)
1248 {
1249 // Check for unbound but installed policies
1250 for(int i = 0; i < ap->getSize(); i++)
1251 {
1252 uuid_t guid;
1253 ap->getGuid(i, guid);
1254 NetObj *object = FindObjectByGUID(guid, -1);
1255 if ((object != NULL) && (!object->IsChild(m_dwId)))
1256 {
1257 object->AddChild(this);
1258 AddParent(object);
1259 DbgPrintf(5, _T("ConfPoll(%s): bound to policy object %s [%d]"), m_szName, object->Name(), object->Id());
1260 }
1261 }
1262
1263 // Check for bound but not installed policies
1264 LockParentList(FALSE);
1265 NetObj **unbindList = (NetObj **)malloc(sizeof(NetObj *) * m_dwParentCount);
1266 int unbindListSize = 0;
1267 for(DWORD i = 0; i < m_dwParentCount; i++)
1268 {
1269 if (IsAgentPolicyObject(m_pParentList[i]))
1270 {
1271 uuid_t guid1, guid2;
1272 int j;
1273
1274 m_pParentList[i]->getGuid(guid1);
1275 for(j = 0; j < ap->getSize(); j++)
1276 {
1277 ap->getGuid(j, guid2);
1278 if (!uuid_compare(guid1, guid2))
1279 break;
1280 }
1281 if (j == ap->getSize())
1282 unbindList[unbindListSize++] = m_pParentList[i];
1283 }
1284 }
1285 UnlockParentList();
1286
1287 for(int i = 0; i < unbindListSize; i++)
1288 {
1289 unbindList[i]->DeleteChild(this);
1290 DeleteParent(unbindList[i]);
1291 DbgPrintf(5, _T("ConfPoll(%s): unbound from policy object %s [%d]"), m_szName, unbindList[i]->Name(), unbindList[i]->Id());
1292 }
1293 safe_free(unbindList);
1294
1295 delete ap;
1296 }
1297 else
1298 {
1299 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getPolicyInventory() failed: rcc=%d"), m_szName, rcc);
1300 }
1301 }
1302
1303
1304 //
1305 // Walker callback for print MIB
1306 //
1307
1308 static DWORD PrintMIBWalkerCallback(DWORD version, SNMP_Variable *var, SNMP_Transport *transport, void *arg)
1309 {
1310 (*((int *)arg))++;
1311 return SNMP_ERR_SUCCESS;
1312 }
1313
1314
1315 //
1316 // Perform configuration poll on node
1317 //
1318
1319 void Node::configurationPoll(ClientSession *pSession, DWORD dwRqId,
1320 int nPoller, DWORD dwNetMask)
1321 {
1322 DWORD dwOldFlags = m_dwFlags, dwAddr, rcc, dwNumParams;
1323 NXC_AGENT_PARAM *pParamList;
1324 AgentConnection *pAgentConn;
1325 TCHAR szBuffer[4096];
1326 SNMP_Transport *pTransport;
1327 BOOL bHasChanges = FALSE;
1328
1329 SetPollerInfo(nPoller, _T("wait for lock"));
1330 pollerLock();
1331 m_pPollRequestor = pSession;
1332 SendPollerMsg(dwRqId, _T("Starting configuration poll for node %s\r\n"), m_szName);
1333 DbgPrintf(4, _T("Starting configuration poll for node %s (ID: %d)"), m_szName, m_dwId);
1334
1335 // Check for forced capabilities recheck
1336 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
1337 {
1338 m_dwFlags &= ~(NF_IS_NATIVE_AGENT | NF_IS_SNMP | NF_IS_CPSNMP |
1339 NF_IS_BRIDGE | NF_IS_ROUTER | NF_IS_OSPF | NF_IS_PRINTER |
1340 NF_IS_CDP | NF_IS_LLDP | NF_IS_SONMP);
1341 m_dwDynamicFlags &= ~NDF_CONFIGURATION_POLL_PASSED;
1342 m_szObjectId[0] = 0;
1343 m_szPlatformName[0] = 0;
1344 m_szAgentVersion[0] = 0;
1345 safe_free_and_null(m_sysDescription);
1346 safe_free_and_null(m_sysName);
1347 safe_free_and_null(m_lldpNodeId);
1348 }
1349
1350 // Check if node is marked as unreachable
1351 if ((m_dwDynamicFlags & NDF_UNREACHABLE) && !(m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES))
1352 {
1353 SendPollerMsg(dwRqId, POLLER_WARNING _T("Node is marked as unreachable, configuration poll aborted\r\n"));
1354 DbgPrintf(4, _T("Node is marked as unreachable, configuration poll aborted"));
1355 m_tLastConfigurationPoll = time(NULL);
1356 }
1357 else
1358 {
1359 // Check node's capabilities
1360 SetPollerInfo(nPoller, _T("capability check"));
1361 SendPollerMsg(dwRqId, _T("Checking node's capabilities...\r\n"));
1362
1363 // ***** NetXMS agent check *****
1364 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent Flags={%08X} DynamicFlags={%08X}"), m_szName, m_dwFlags, m_dwDynamicFlags);
1365 if ((!((m_dwFlags & NF_IS_NATIVE_AGENT) && (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))) &&
1366 (!(m_dwFlags & NF_DISABLE_NXCP)) && (m_dwIpAddr != 0))
1367 {
1368 SendPollerMsg(dwRqId, _T(" Checking NetXMS agent...\r\n"));
1369 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
1370 m_wAuthMethod, m_szSharedSecret);
1371 setAgentProxy(pAgentConn);
1372 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - connecting"), m_szName);
1373 if (pAgentConn->connect(g_pServerKey))
1374 {
1375 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - connected"), m_szName);
1376 LockData();
1377 m_dwFlags |= NF_IS_NATIVE_AGENT;
1378 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1379 {
1380 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1381 PostEvent(EVENT_AGENT_OK, m_dwId, NULL);
1382 SendPollerMsg(dwRqId, POLLER_INFO _T(" Connectivity with NetXMS agent restored\r\n"));
1383 }
1384 else
1385 {
1386 SendPollerMsg(dwRqId, POLLER_INFO _T(" NetXMS native agent is active\r\n"));
1387 }
1388 UnlockData();
1389
1390 if (pAgentConn->getParameter(_T("Agent.Version"), MAX_AGENT_VERSION_LEN, szBuffer) == ERR_SUCCESS)
1391 {
1392 LockData();
1393 if (_tcscmp(m_szAgentVersion, szBuffer))
1394 {
1395 _tcscpy(m_szAgentVersion, szBuffer);
1396 bHasChanges = TRUE;
1397 SendPollerMsg(dwRqId, _T(" NetXMS agent version changed to %s\r\n"), m_szAgentVersion);
1398 }
1399 UnlockData();
1400 }
1401
1402 if (pAgentConn->getParameter(_T("System.PlatformName"), MAX_PLATFORM_NAME_LEN, szBuffer) == ERR_SUCCESS)
1403 {
1404 LockData();
1405 if (_tcscmp(m_szPlatformName, szBuffer))
1406 {
1407 _tcscpy(m_szPlatformName, szBuffer);
1408 bHasChanges = TRUE;
1409 SendPollerMsg(dwRqId, _T(" Platform name changed to %s\r\n"), m_szPlatformName);
1410 }
1411 UnlockData();
1412 }
1413
1414 // Check IP forwarding status
1415 if (pAgentConn->getParameter(_T("Net.IP.Forwarding"), 16, szBuffer) == ERR_SUCCESS)
1416 {
1417 if (_tcstoul(szBuffer, NULL, 10) != 0)
1418 m_dwFlags |= NF_IS_ROUTER;
1419 else
1420 m_dwFlags &= ~NF_IS_ROUTER;
1421 }
1422
1423 // Get uname
1424 if (pAgentConn->getParameter(_T("System.Uname"), MAX_DB_STRING, szBuffer) == ERR_SUCCESS)
1425 {
1426 TranslateStr(szBuffer, _T("\r\n"), _T(" "));
1427 TranslateStr(szBuffer, _T("\n"), _T(" "));
1428 TranslateStr(szBuffer, _T("\r"), _T(" "));
1429 LockData();
1430 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, szBuffer))
1431 {
1432 m_sysDescription = _tcsdup(szBuffer);
1433 bHasChanges = TRUE;
1434 SendPollerMsg(dwRqId, _T(" System description changed to %s\r\n"), m_sysDescription);
1435 }
1436 UnlockData();
1437 }
1438
1439 rcc = pAgentConn->getSupportedParameters(&dwNumParams, &pParamList);
1440 if (rcc == ERR_SUCCESS)
1441 {
1442 LockData();
1443 safe_free(m_pParamList);
1444 m_dwNumParams = dwNumParams;
1445 m_pParamList = pParamList;
1446 UnlockData();
1447 }
1448 else
1449 {
1450 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::GetSupportedParameters() failed: rcc=%d"), m_szName, rcc);
1451 }
1452
1453 checkAgentPolicyBinding(pAgentConn);
1454
1455 pAgentConn->disconnect();
1456 }
1457 delete pAgentConn;
1458 DbgPrintf(5, _T("ConfPoll(%s): checking for NetXMS agent - finished"), m_szName);
1459 }
1460
1461 // ***** SNMP check *****
1462 if ((!((m_dwFlags & NF_IS_SNMP) && (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))) &&
1463 (!(m_dwFlags & NF_DISABLE_SNMP)) && (m_dwIpAddr != 0))
1464 {
1465 SendPollerMsg(dwRqId, _T(" Checking SNMP...\r\n"));
1466 DbgPrintf(5, _T("ConfPoll(%s): calling SnmpCheckCommSettings()"), m_szName);
1467 pTransport = createSnmpTransport();
1468 if (pTransport == NULL)
1469 {
1470 DbgPrintf(5, _T("ConfPoll(%s): unable to create SNMP transport"), m_szName);
1471 goto skip_snmp_checks;
1472 }
1473
1474 SNMP_SecurityContext *newCtx = SnmpCheckCommSettings(pTransport, &m_snmpVersion, m_snmpSecurity);
1475 if (newCtx != NULL)
1476 {
1477 LockData();
1478 delete m_snmpSecurity;
1479 m_snmpSecurity = newCtx;
1480 m_dwFlags |= NF_IS_SNMP;
1481 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
1482 {
1483 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1484 PostEvent(EVENT_SNMP_OK, m_dwId, NULL);
1485 SendPollerMsg(dwRqId, POLLER_INFO _T(" Connectivity with SNMP agent restored\r\n"));
1486 }
1487 UnlockData();
1488 SendPollerMsg(dwRqId, _T(" SNMP agent is active (version %s)\r\n"),
1489 (m_snmpVersion == SNMP_VERSION_3) ? _T("3") : ((m_snmpVersion == SNMP_VERSION_2C) ? _T("2c") : _T("1")));
1490
1491 if (SnmpGet(m_snmpVersion, pTransport,
1492 _T(".1.3.6.1.2.1.1.2.0"), NULL, 0, szBuffer, 4096, SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
1493 {
1494 LockData();
1495 if (_tcscmp(m_szObjectId, szBuffer))
1496 {
1497 nx_strncpy(m_szObjectId, szBuffer, MAX_OID_LEN * 4);
1498 bHasChanges = TRUE;
1499 }
1500 UnlockData();
1501 }
1502
1503 // Get system description
1504 if (SnmpGet(m_snmpVersion, pTransport,
1505 _T(".1.3.6.1.2.1.1.1.0"), NULL, 0, szBuffer, MAX_DB_STRING, SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
1506 {
1507 TranslateStr(szBuffer, _T("\r\n"), _T(" "));
1508 TranslateStr(szBuffer, _T("\n"), _T(" "));
1509 TranslateStr(szBuffer, _T("\r"), _T(" "));
1510 LockData();
1511 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, szBuffer))
1512 {
1513 safe_free(m_sysDescription);
1514 m_sysDescription = _tcsdup(szBuffer);
1515 bHasChanges = TRUE;
1516 SendPollerMsg(dwRqId, _T(" System description changed to %s\r\n"), m_sysDescription);
1517 }
1518 UnlockData();
1519 }
1520
1521 // Select device driver
1522 NetworkDeviceDriver *driver = FindDriverForNode(this);
1523 DbgPrintf(5, _T("ConfPoll(%s): selected device driver %s"), m_szName, driver->getName());
1524 LockData();
1525 if (driver != m_driver)
1526 {
1527 m_driver = driver;
1528 SendPollerMsg(dwRqId, _T(" New network device driver selected: %s\r\n"), m_driver->getName());
1529 }
1530 UnlockData();
1531
1532 // Allow driver to gather additional info
1533 m_driver->analyzeDevice(pTransport, m_szObjectId, &m_customAttributes);
1534
1535 // Get sysName
1536 if (SnmpGet(m_snmpVersion, pTransport,
1537 _T(".1.3.6.1.2.1.1.5.0"), NULL, 0, szBuffer, MAX_DB_STRING, SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
1538 {
1539 LockData();
1540 if ((m_sysName == NULL) || _tcscmp(m_sysName, szBuffer))
1541 {
1542 safe_free(m_sysName);
1543 m_sysName = _tcsdup(szBuffer);
1544 bHasChanges = TRUE;
1545 SendPollerMsg(dwRqId, _T(" System name changed to %s\r\n"), m_sysName);
1546 }
1547 UnlockData();
1548 }
1549
1550 // Check IP forwarding
1551 if (CheckSNMPIntegerValue(pTransport, _T(".1.3.6.1.2.1.4.1.0"), 1))
1552 {
1553 LockData();
1554 m_dwFlags |= NF_IS_ROUTER;
1555 UnlockData();
1556 }
1557 else
1558 {
1559 LockData();
1560 m_dwFlags &= ~NF_IS_ROUTER;
1561 UnlockData();
1562 }
1563
1564 // Check for bridge MIB support
1565 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.17.1.1.0"), NULL, 0, szBuffer, 4096, 0) == SNMP_ERR_SUCCESS)
1566 {
1567 LockData();
1568 m_dwFlags |= NF_IS_BRIDGE;
1569 UnlockData();
1570 }
1571 else
1572 {
1573 LockData();
1574 m_dwFlags &= ~NF_IS_BRIDGE;
1575 UnlockData();
1576 }
1577
1578 // Check for printer MIB support
1579 int count = 0;
1580 SnmpEnumerate(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.43.5.1.1.17"), PrintMIBWalkerCallback, &count, FALSE);
1581 if (count > 0)
1582 {
1583 LockData();
1584 m_dwFlags |= NF_IS_PRINTER;
1585 UnlockData();
1586 }
1587 else
1588 {
1589 LockData();
1590 m_dwFlags &= ~NF_IS_PRINTER;
1591 UnlockData();
1592 }
1593
1594 // Check for CDP (Cisco Discovery Protocol) support
1595 if (CheckSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.9.9.23.1.3.1.0"), 1))
1596 {
1597 LockData();
1598 m_dwFlags |= NF_IS_CDP;
1599 UnlockData();
1600 }
1601 else
1602 {
1603 LockData();
1604 m_dwFlags &= ~NF_IS_CDP;
1605 UnlockData();
1606 }
1607
1608 // Check for NDP (Nortel Discovery Protocol) support
1609 if (CheckSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.45.1.6.13.1.2.0"), 1))
1610 {
1611 LockData();
1612 m_dwFlags |= NF_IS_NDP;
1613 UnlockData();
1614 }
1615 else
1616 {
1617 LockData();
1618 m_dwFlags &= ~NF_IS_NDP;
1619 UnlockData();
1620 }
1621
1622 // Check for LLDP (Link Layer Discovery Protocol) support
1623 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.0.8802.1.1.2.1.3.2.0"), NULL, 0, szBuffer, 4096, 0) == SNMP_ERR_SUCCESS)
1624 {
1625 LockData();
1626 m_dwFlags |= NF_IS_LLDP;
1627 UnlockData();
1628
1629 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)
1630 {
1631 _tcscat(szBuffer, _T("@"));
1632 int len = (int)_tcslen(szBuffer);
1633 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)
1634 {
1635 LockData();
1636 if ((m_lldpNodeId == NULL) || _tcscmp(m_lldpNodeId, szBuffer))
1637 {
1638 safe_free(m_lldpNodeId);
1639 m_lldpNodeId = _tcsdup(szBuffer);
1640 bHasChanges = TRUE;
1641 SendPollerMsg(dwRqId, _T(" LLDP node ID changed to %s\r\n"), m_lldpNodeId);
1642 }
1643 UnlockData();
1644 }
1645 }
1646 }
1647 else
1648 {
1649 LockData();
1650 m_dwFlags &= ~NF_IS_LLDP;
1651 UnlockData();
1652 }
1653
1654 CheckOSPFSupport(pTransport);
1655
1656 // Get VRRP information
1657 VrrpInfo *vrrpInfo = GetVRRPInfo(this);
1658 if (vrrpInfo != NULL)
1659 {
1660 LockData();
1661 m_dwFlags |= NF_IS_VRRP;
1662 delete m_vrrpInfo;
1663 m_vrrpInfo = vrrpInfo;
1664 UnlockData();
1665 }
1666 else
1667 {
1668 LockData();
1669 m_dwFlags &= ~NF_IS_VRRP;
1670 UnlockData();
1671 }
1672 }
1673 else
1674 {
1675 // Check for CheckPoint SNMP agent on port 161
1676 DbgPrintf(5, _T("ConfPoll(%s): checking for CheckPoint SNMP"), m_szName);
1677 if (SnmpGet(m_snmpVersion, pTransport,
1678 _T(".1.3.6.1.4.1.2620.1.1.10.0"), NULL, 0, szBuffer, 4096, 0) == SNMP_ERR_SUCCESS)
1679 {
1680 LockData();
1681 if (_tcscmp(m_szObjectId, _T(".1.3.6.1.4.1.2620.1.1")))
1682 {
1683 nx_strncpy(m_szObjectId, _T(".1.3.6.1.4.1.2620.1.1"), MAX_OID_LEN * 4);
1684 bHasChanges = TRUE;
1685 }
1686
1687 m_dwFlags |= NF_IS_SNMP | NF_IS_ROUTER;
1688 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1689 UnlockData();
1690 SendPollerMsg(dwRqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 161 is active\r\n"));
1691 }
1692 }
1693 delete pTransport;
1694 }
1695
1696 skip_snmp_checks:
1697 // Check for CheckPoint SNMP agent on port 260
1698 DbgPrintf(5, _T("ConfPoll(%s): checking for CheckPoint SNMP on port 260"), m_szName);
1699 if (!((m_dwFlags & NF_IS_CPSNMP) && (m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE)) && (m_dwIpAddr != 0))
1700 {
1701 pTransport = new SNMP_UDPTransport;
1702 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
1703 if (SnmpGet(SNMP_VERSION_1, pTransport,
1704 _T(".1.3.6.1.4.1.2620.1.1.10.0"), NULL, 0, szBuffer, 4096, 0) == SNMP_ERR_SUCCESS)
1705 {
1706 LockData();
1707 m_dwFlags |= NF_IS_CPSNMP | NF_IS_ROUTER;
1708 m_dwDynamicFlags &= ~NDF_CPSNMP_UNREACHABLE;
1709 UnlockData();
1710 SendPollerMsg(dwRqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 260 is active\r\n"));
1711 }
1712 delete pTransport;
1713 }
1714
1715 // Generate event if node flags has been changed
1716 if (dwOldFlags != m_dwFlags)
1717 {
1718 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
1719 bHasChanges = TRUE;
1720 }
1721
1722 // Retrieve interface list
1723 SetPollerInfo(nPoller, _T("interface check"));
1724 SendPollerMsg(dwRqId, _T("Capability check finished\r\n"));
1725
1726 if (updateInterfaceConfiguration(dwRqId, dwNetMask))
1727 bHasChanges = TRUE;
1728
1729 m_tLastConfigurationPoll = time(NULL);
1730
1731 // Check node name
1732 SendPollerMsg(dwRqId, _T("Checking node name\r\n"));
1733 dwAddr = ntohl(_t_inet_addr(m_szName));
1734 if ((g_dwFlags & AF_RESOLVE_NODE_NAMES) &&
1735 (dwAddr != INADDR_NONE) &&
1736 (dwAddr != INADDR_ANY) &&
1737 isMyIP(dwAddr))
1738 {
1739 SendPollerMsg(dwRqId, _T("Node name is an IP address and need to be resolved\r\n"));
1740 SetPollerInfo(nPoller, _T("resolving name"));
1741 if (ResolveName(FALSE))
1742 {
1743 SendPollerMsg(dwRqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_szName);
1744 bHasChanges = TRUE;
1745 }
1746 else
1747 {
1748 SendPollerMsg(dwRqId, POLLER_WARNING _T("Node name cannot be resolved\r\n"));
1749 }
1750 }
1751 else
1752 {
1753 if (g_dwFlags & AF_SYNC_NODE_NAMES_WITH_DNS)
1754 {
1755 SendPollerMsg(dwRqId, _T("Syncing node name with DNS\r\n"));
1756 SetPollerInfo(nPoller, _T("resolving name"));
1757 if (ResolveName(TRUE))
1758 {
1759 SendPollerMsg(dwRqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_szName);
1760 bHasChanges = TRUE;
1761 }
1762 }
1763 else
1764 {
1765 SendPollerMsg(dwRqId, _T("Node name is OK\r\n"));
1766 }
1767 }
1768
1769 // Apply templates
1770 ApplySystemTemplates();
1771 ApplyUserTemplates();
1772
1773 updateContainerMembership();
1774
1775 SendPollerMsg(dwRqId, _T("Finished configuration poll for node %s\r\n"), m_szName);
1776 SendPollerMsg(dwRqId, _T("Node configuration was%schanged after poll\r\n"), bHasChanges ? _T(" ") : _T(" not "));
1777
1778 m_dwDynamicFlags |= NDF_CONFIGURATION_POLL_PASSED;
1779 }
1780
1781 // Finish configuration poll
1782 SetPollerInfo(nPoller, _T("cleanup"));
1783 if (dwRqId == 0)
1784 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1785 m_dwDynamicFlags &= ~NDF_RECHECK_CAPABILITIES;
1786 pollerUnlock();
1787 DbgPrintf(4, _T("Finished configuration poll for node %s (ID: %d)"), m_szName, m_dwId);
1788
1789 if (bHasChanges)
1790 {
1791 LockData();
1792 Modify();
1793 UnlockData();
1794 }
1795 }
1796
1797
1798 //
1799 // Update interface configuration
1800 //
1801
1802 BOOL Node::updateInterfaceConfiguration(DWORD dwRqId, DWORD dwNetMask)
1803 {
1804 InterfaceList *pIfList;
1805 Interface **ppDeleteList;
1806 int i, j, iDelCount;
1807 BOOL hasChanges = FALSE;
1808 Cluster *pCluster = getMyCluster();
1809
1810 SendPollerMsg(dwRqId, _T("Checking interface configuration...\r\n"));
1811 pIfList = getInterfaceList();
1812 if (pIfList != NULL)
1813 {
1814 // Remove cluster virtual interfaces from list
1815 if (pCluster != NULL)
1816 {
1817 for(i = 0; i < pIfList->getSize(); i++)
1818 {
1819 if (pCluster->isVirtualAddr(pIfList->get(i)->dwIpAddr))
1820 {
1821 pIfList->remove(i);
1822 i--;
1823 }
1824 }
1825 }
1826
1827 // Find non-existing interfaces
1828 LockChildList(FALSE);
1829 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
1830 for(i = 0, iDelCount = 0; i < (int)m_dwChildCount; i++)
1831 {
1832 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1833 {
1834 Interface *pInterface = (Interface *)m_pChildList[i];
1835
1836 if (pInterface->getIfType() != IFTYPE_NETXMS_NAT_ADAPTER)
1837 {
1838 for(j = 0; j < pIfList->getSize(); j++)
1839 {
1840 if ((pIfList->get(j)->dwIndex == pInterface->getIfIndex()) &&
1841 (pIfList->get(j)->dwIpAddr == pInterface->IpAddr()))
1842 break;
1843 }
1844
1845 if (j == pIfList->getSize())
1846 {
1847 // No such interface in current configuration, add it to delete list
1848 ppDeleteList[iDelCount++] = pInterface;
1849 }
1850 }
1851 }
1852 }
1853 UnlockChildList();
1854
1855 // Delete non-existent interfaces
1856 if (iDelCount > 0)
1857 {
1858 for(j = 0; j < iDelCount; j++)
1859 {
1860 SendPollerMsg(dwRqId, POLLER_WARNING _T(" Interface \"%s\" is no longer exist\r\n"),
1861 ppDeleteList[j]->Name());
1862 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->getIfIndex(),
1863 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->getIpNetMask());
1864 deleteInterface(ppDeleteList[j]);
1865 }
1866 hasChanges = TRUE;
1867 }
1868 safe_free(ppDeleteList);
1869
1870 // Add new interfaces and check configuration of existing
1871 for(j = 0; j < pIfList->getSize(); j++)
1872 {
1873 INTERFACE_INFO *ifInfo = pIfList->get(j);
1874 BOOL bNewInterface = TRUE;
1875
1876 LockChildList(FALSE);
1877 for(i = 0; i < (int)m_dwChildCount; i++)
1878 {
1879 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1880 {
1881 Interface *pInterface = (Interface *)m_pChildList[i];
1882
1883 if ((ifInfo->dwIndex == pInterface->getIfIndex()) &&
1884 (ifInfo->dwIpAddr == pInterface->IpAddr()))
1885 {
1886 // Existing interface, check configuration
1887 if (memcmp(ifInfo->bMacAddr, pInterface->getMacAddr(), MAC_ADDR_LENGTH))
1888 {
1889 TCHAR szOldMac[16], szNewMac[16];
1890
1891 BinToStr((BYTE *)pInterface->getMacAddr(), MAC_ADDR_LENGTH, szOldMac);
1892 BinToStr(ifInfo->bMacAddr, MAC_ADDR_LENGTH, szNewMac);
1893 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
1894 pInterface->Id(), pInterface->getIfIndex(),
1895 pInterface->Name(), szOldMac, szNewMac);
1896 pInterface->setMacAddr(ifInfo->bMacAddr);
1897 }
1898 if (_tcscmp(ifInfo->szName, pInterface->Name()))
1899 {
1900 pInterface->setName(ifInfo->szName);
1901 }
1902 if (ifInfo->dwBridgePortNumber != pInterface->getBridgePortNumber())
1903 {
1904 pInterface->setBridgePortNumber(ifInfo->dwBridgePortNumber);
1905 }
1906 if (ifInfo->dwSlotNumber != pInterface->getSlotNumber())
1907 {
1908 pInterface->setSlotNumber(ifInfo->dwSlotNumber);
1909 }
1910 if (ifInfo->dwPortNumber != pInterface->getPortNumber())
1911 {
1912 pInterface->setPortNumber(ifInfo->dwPortNumber);
1913 }
1914 if ((ifInfo->dwIpNetMask != 0) && (ifInfo->dwIpNetMask != pInterface->getIpNetMask()))
1915 {
1916 pInterface->setIpNetMask(ifInfo->dwIpNetMask);
1917 }
1918 bNewInterface = FALSE;
1919 break;
1920 }
1921 }
1922 }
1923 UnlockChildList();
1924
1925 if (bNewInterface)
1926 {
1927 // New interface
1928 SendPollerMsg(dwRqId, POLLER_INFO _T(" Found new interface \"%s\"\r\n"), ifInfo->szName);
1929 createNewInterface(ifInfo->dwIpAddr,
1930 ifInfo->dwIpNetMask,
1931 ifInfo->szName,
1932 ifInfo->dwIndex,
1933 ifInfo->dwType,
1934 ifInfo->bMacAddr,
1935 ifInfo->dwBridgePortNumber,
1936 ifInfo->dwSlotNumber,
1937 ifInfo->dwPortNumber);
1938 hasChanges = TRUE;
1939 }
1940 }
1941
1942 // Check if address we are using to communicate with node
1943 // is configured on one of node's interfaces
1944 for(i = 0; i < pIfList->getSize(); i++)
1945 if (pIfList->get(i)->dwIpAddr == m_dwIpAddr)
1946 break;
1947
1948 if (i == (DWORD)pIfList->getSize())
1949 {
1950 BOOL bCreate = TRUE;
1951
1952 // Node is behind NAT
1953 m_dwFlags |= NF_BEHIND_NAT;
1954
1955 // Check if we already have NAT interface
1956 LockChildList(FALSE);
1957 for(i = 0; i < (int)m_dwChildCount; i++)
1958 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1959 {
1960 if (((Interface *)m_pChildList[i])->getIfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1961 {
1962 bCreate = FALSE;
1963 break;
1964 }
1965 }
1966 UnlockChildList();
1967
1968 if (bCreate)
1969 {
1970 TCHAR szBuffer[MAX_OBJECT_NAME];
1971
1972 // Create pseudo interface for NAT
1973 ConfigReadStr(_T("NATAdapterName"), szBuffer, MAX_OBJECT_NAME, _T("NetXMS NAT Adapter"));
1974 createNewInterface(m_dwIpAddr, 0, szBuffer, 0x7FFFFFFF, IFTYPE_NETXMS_NAT_ADAPTER);
1975 hasChanges = TRUE;
1976 }
1977 }
1978 else
1979 {
1980 // Check if NF_BEHIND_NAT flag set incorrectly
1981 if (m_dwFlags & NF_BEHIND_NAT)
1982 {
1983 Interface *pIfNat;
1984
1985 // Remove NAT interface
1986 LockChildList(FALSE);
1987 for(i = 0, pIfNat = NULL; i < (int)m_dwChildCount; i++)
1988 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1989 {
1990 if (((Interface *)m_pChildList[i])->getIfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1991 {
1992 pIfNat = (Interface *)m_pChildList[i];
1993 break;
1994 }
1995 }
1996 UnlockChildList();
1997
1998 if (pIfNat != NULL)
1999 deleteInterface(pIfNat);
2000
2001 m_dwFlags &= ~NF_BEHIND_NAT;
2002 hasChanges = TRUE;
2003 }
2004 }
2005
2006 CheckSubnetBinding(pIfList);
2007
2008 delete pIfList;
2009 }
2010 else /* pIfList == NULL */
2011 {
2012 Interface *pInterface;
2013 DWORD dwCount;
2014
2015 SendPollerMsg(dwRqId, POLLER_ERROR _T("Unable to get interface list from node\r\n"));
2016
2017 // Delete all existing interfaces in case of forced capability recheck
2018 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
2019 {
2020 LockChildList(FALSE);
2021 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
2022 for(i = 0, iDelCount = 0; i < (int)m_dwChildCount; i++)
2023 {
2024 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2025 ppDeleteList[iDelCount++] = (Interface *)m_pChildList[i];
2026 }
2027 UnlockChildList();
2028 for(j = 0; j < iDelCount; j++)
2029 {
2030 SendPollerMsg(dwRqId, POLLER_WARNING _T(" Interface \"%s\" is no longer exist\r\n"),
2031 ppDeleteList[j]->Name());
2032 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->getIfIndex(),
2033 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->getIpNetMask());
2034 deleteInterface(ppDeleteList[j]);
2035 }
2036 safe_free(ppDeleteList);
2037 }
2038
2039 // Check if we have pseudo-interface object
2040 dwCount = getInterfaceCount(&pInterface);
2041 if (dwCount == 1)
2042 {
2043 if (pInterface->isFake())
2044 {
2045 // Check if primary IP is different from interface's IP
2046 if (pInterface->IpAddr() != m_dwIpAddr)
2047 {
2048 deleteInterface(pInterface);
2049 if (m_dwIpAddr != 0)
2050 createNewInterface(m_dwIpAddr, dwNetMask);
2051 }
2052 }
2053 }
2054 else if (dwCount == 0)
2055 {
2056 // No interfaces at all, create pseudo-interface
2057 if (m_dwIpAddr != 0)
2058 createNewInterface(m_dwIpAddr, dwNetMask);
2059 }
2060 }
2061
2062 SendPollerMsg(dwRqId, _T("Interface configuration check finished\r\n"));
2063 return hasChanges;
2064 }
2065
2066
2067 //
2068 // Apply system templates
2069 //
2070
2071 void Node::ApplySystemTemplates()
2072 {
2073 Template *pTemplate;
2074
2075 pTemplate = FindTemplateByName(_T("@System.Agent"));
2076 if (pTemplate != NULL)
2077 {
2078 if (isNativeAgent())
2079 {
2080 if (!pTemplate->IsChild(m_dwId))
2081 {
2082 DbgPrintf(4, _T("Node::ApplySystemTemplates(): applying template %d \"%s\" to node %d \"%s\""),
2083 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
2084 pTemplate->ApplyToNode(this);
2085 }
2086 }
2087 else
2088 {
2089 if (pTemplate->IsChild(m_dwId))
2090 {
2091 DbgPrintf(4, _T("Node::ApplySystemTemplates(): removing template %d \"%s\" from node %d \"%s\""),
2092 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
2093 pTemplate->DeleteChild(this);
2094 DeleteParent(pTemplate);
2095 pTemplate->queueRemoveFromNode(m_dwId, TRUE);
2096 }
2097 }
2098 }
2099 }
2100
2101
2102 //
2103 // Apply user templates
2104 //
2105
2106 void Node::ApplyUserTemplates()
2107 {
2108 DWORD i;
2109 Template *pTemplate;
2110
2111 if (g_pIndexById == NULL)
2112 return;
2113
2114 RWLockReadLock(g_rwlockIdIndex, INFINITE);
2115 for(i = 0; i < g_dwIdIndexSize; i++)
2116 {
2117 if ((((NetObj *)g_pIndexById[i].pObject)->Type() == OBJECT_TEMPLATE) &&
2118 (!((NetObj *)g_pIndexById[i].pObject)->IsDeleted()))
2119 {
2120 pTemplate = (Template *)g_pIndexById[i].pObject;
2121 if (pTemplate->isApplicable(this))
2122 {
2123 if (!pTemplate->IsChild(m_dwId))
2124 {
2125 DbgPrintf(4, _T("Node::ApplyUserTemplates(): applying template %d \"%s\" to node %d \"%s\""),
2126 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
2127 pTemplate->ApplyToNode(this);
2128 }
2129 }
2130 else
2131 {
2132 if (pTemplate->isAutoApplyEnabled() && pTemplate->IsChild(m_dwId))
2133 {
2134 DbgPrintf(4, _T("Node::ApplyUserTemplates(): removing template %d \"%s\" from node %d \"%s\""),
2135 pTemplate->Id(), pTemplate->Name(), m_dwId, m_szName);
2136 pTemplate->DeleteChild(this);
2137 DeleteParent(pTemplate);
2138 pTemplate->queueRemoveFromNode(m_dwId, TRUE);
2139 }
2140 }
2141 }
2142 }
2143 RWLockUnlock(g_rwlockIdIndex);
2144 }
2145
2146
2147 //
2148 // Update container membership
2149 //
2150
2151 void Node::updateContainerMembership()
2152 {
2153 DWORD i;
2154 Container *pContainer;
2155
2156 if (g_pIndexById == NULL)
2157 return;
2158
2159 RWLockReadLock(g_rwlockIdIndex, INFINITE);
2160 for(i = 0; i < g_dwIdIndexSize; i++)
2161 {
2162 if ((((NetObj *)g_pIndexById[i].pObject)->Type() == OBJECT_CONTAINER) &&
2163 (!((NetObj *)g_pIndexById[i].pObject)->IsDeleted()))
2164 {
2165 pContainer = (Container *)g_pIndexById[i].pObject;
2166 if (pContainer->IsSuitableForNode(this))
2167 {
2168 if (!pContainer->IsChild(m_dwId))
2169 {
2170 DbgPrintf(4, _T("Node::UpdateContainerMembership(): binding node %d \"%s\" to container %d \"%s\""),
2171 m_dwId, m_szName, pContainer->Id(), pContainer->Name());
2172 pContainer->AddChild(this);
2173 AddParent(pContainer);
2174 }
2175 }
2176 else
2177 {
2178 if (pContainer->IsAutoBindEnabled() && pContainer->IsChild(m_dwId))
2179 {
2180 DbgPrintf(4, _T("Node::UpdateContainerMembership(): removing node %d \"%s\" from container %d \"%s\""),
2181 m_dwId, m_szName, pContainer->Id(), pContainer->Name());
2182 pContainer->DeleteChild(this);
2183 DeleteParent(pContainer);
2184 }
2185 }
2186 }
2187 }
2188 RWLockUnlock(g_rwlockIdIndex);
2189 }
2190
2191
2192 //
2193 // Connect to native agent
2194 //
2195
2196 BOOL Node::connectToAgent(DWORD *error, DWORD *socketError)
2197 {
2198 BOOL bRet;
2199
2200 // Create new agent connection object if needed
2201 if (m_pAgentConnection == NULL)
2202 m_pAgentConnection = new AgentConnectionEx(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
2203
2204 // Check if we already connected
2205 if (m_pAgentConnection->nop() == ERR_SUCCESS)
2206 return TRUE;
2207
2208 // Close current connection or clean up after broken connection
2209 m_pAgentConnection->disconnect();
2210 m_pAgentConnection->setPort(m_wAgentPort);
2211 #ifdef UNICODE
2212 char mbSecret[MAX_SECRET_LENGTH];
2213 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, m_szSharedSecret, -1, mbSecret, MAX_SECRET_LENGTH, NULL, NULL);
2214 mbSecret[MAX_SECRET_LENGTH - 1] = 0;
2215 m_pAgentConnection->setAuthData(m_wAuthMethod, mbSecret);
2216 #else
2217 m_pAgentConnection->setAuthData(m_wAuthMethod, m_szSharedSecret);
2218 #endif
2219 setAgentProxy(m_pAgentConnection);
2220 bRet = m_pAgentConnection->connect(g_pServerKey, FALSE, error, socketError);
2221 if (bRet)
2222 {
2223 m_pAgentConnection->setCommandTimeout(g_dwAgentCommandTimeout);
2224 m_pAgentConnection->enableTraps();
2225 }
2226 return bRet;
2227 }
2228
2229
2230 //
2231 // Get item's value via SNMP
2232 //
2233
2234 DWORD Node::GetItemFromSNMP(WORD port, const TCHAR *szParam, DWORD dwBufSize, TCHAR *szBuffer)
2235 {
2236 DWORD dwResult;
2237
2238 if ((((m_dwDynamicFlags & NDF_SNMP_UNREACHABLE) || !(m_dwFlags & NF_IS_SNMP)) && (port == 0)) ||
2239 (m_dwDynamicFlags & NDF_UNREACHABLE) ||
2240 (m_dwFlags & NF_DISABLE_SNMP))
2241 {
2242 dwResult = SNMP_ERR_COMM;
2243 }
2244 else
2245 {
2246 SNMP_Transport *pTransport;
2247
2248 pTransport = createSnmpTransport(port);
2249 if (pTransport != NULL)
2250 {
2251 dwResult = SnmpGet(m_snmpVersion, pTransport,
2252 szParam, NULL, 0, szBuffer, dwBufSize, SG_STRING_RESULT);
2253 delete pTransport;
2254 }
2255 else
2256 {
2257 dwResult = SNMP_ERR_COMM;
2258 }
2259 }
2260 DbgPrintf(7, _T("Node(%s)->GetItemFromSNMP(%s): dwResult=%d"), m_szName, szParam, dwResult);
2261 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
2262 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
2263 }
2264
2265
2266 //
2267 // Get item's value via SNMP from CheckPoint's agent
2268 //
2269
2270 DWORD Node::GetItemFromCheckPointSNMP(const TCHAR *szParam, DWORD dwBufSize, TCHAR *szBuffer)
2271 {
2272 DWORD dwResult;
2273
2274 if ((m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE) ||
2275 (m_dwDynamicFlags & NDF_UNREACHABLE))
2276 {
2277 dwResult = SNMP_ERR_COMM;
2278 }
2279 else
2280 {
2281 SNMP_Transport *pTransport;
2282
2283 pTransport = new SNMP_UDPTransport;
2284 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
2285 dwResult = SnmpGet(SNMP_VERSION_1, pTransport, szParam, NULL, 0, szBuffer, dwBufSize, SG_STRING_RESULT);
2286 delete pTransport;
2287 }
2288 DbgPrintf(7, _T("Node(%s)->GetItemFromCheckPointSNMP(%s): dwResult=%d"), m_szName, szParam, dwResult);
2289 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
2290 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
2291 }
2292
2293
2294 //
2295 // Get item's value via native agent
2296 //
2297
2298 DWORD Node::GetItemFromAgent(const TCHAR *szParam, DWORD dwBufSize, TCHAR *szBuffer)
2299 {
2300 DWORD dwError = ERR_NOT_CONNECTED, dwResult = DCE_COMM_ERROR;
2301 DWORD dwTries = 3;
2302
2303 if ((m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
2304 (m_dwDynamicFlags & NDF_UNREACHABLE) ||
2305 (m_dwFlags & NF_DISABLE_NXCP) ||
2306 !(m_dwFlags & NF_IS_NATIVE_AGENT))
2307 return DCE_COMM_ERROR;
2308
2309 agentLock();
2310
2311 // Establish connection if needed
2312 if (m_pAgentConnection == NULL)
2313 if (!connectToAgent())
2314 goto end_loop;
2315
2316 // Get parameter from agent
2317 while(dwTries-- > 0)
2318 {
2319 dwError = m_pAgentConnection->getParameter(szParam, dwBufSize, szBuffer);
2320 switch(dwError)
2321 {
2322 case ERR_SUCCESS:
2323 dwResult = DCE_SUCCESS;
2324 goto end_loop;
2325 case ERR_UNKNOWN_PARAMETER:
2326 dwResult = DCE_NOT_SUPPORTED;
2327 goto end_loop;
2328 case ERR_NOT_CONNECTED:
2329 case ERR_CONNECTION_BROKEN:
2330 if (!connectToAgent())
2331 goto end_loop;
2332 break;
2333 case ERR_REQUEST_TIMEOUT:
2334 // Reset connection to agent after timeout
2335 DbgPrintf(7, _T("Node(%s)->GetItemFromAgent(%s): timeout; resetting connection to agent..."), m_szName, szParam);
2336 delete_and_null(m_pAgentConnection);
2337 if (!connectToAgent())
2338 goto end_loop;
2339 DbgPrintf(7, _T("Node(%s)->GetItemFromAgent(%s): connection to agent restored successfully"), m_szName, szParam);
2340 break;
2341 }
2342 }
2343
2344 end_loop:
2345 agentUnlock();
2346 DbgPrintf(7, _T("Node(%s)->GetItemFromAgent(%s): dwError=%d dwResult=%d"), m_szName, szParam, dwError, dwResult);
2347 return dwResult;
2348 }
2349
2350
2351 //
2352 // Get table from agent
2353 //
2354
2355 DWORD Node::getTableFromAgent(const TCHAR *name, Table **table)
2356 {
2357 DWORD dwError = ERR_NOT_CONNECTED, dwResult = DCE_COMM_ERROR;
2358 DWORD dwTries = 3;
2359
2360 *table = NULL;
2361
2362 if ((m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
2363 (m_dwDynamicFlags & NDF_UNREACHABLE) ||
2364 (m_dwFlags & NF_DISABLE_NXCP) ||
2365 !(m_dwFlags & NF_IS_NATIVE_AGENT))
2366 return DCE_COMM_ERROR;
2367
2368 agentLock();
2369
2370 // Establish connection if needed
2371 if (m_pAgentConnection == NULL)
2372 if (!connectToAgent())
2373 goto end_loop;
2374
2375 // Get parameter from agent
2376 while(dwTries-- > 0)
2377 {
2378 dwError = m_pAgentConnection->getTable(name, table);
2379 switch(dwError)
2380 {
2381 case ERR_SUCCESS:
2382 dwResult = DCE_SUCCESS;
2383 goto end_loop;
2384 case ERR_UNKNOWN_PARAMETER:
2385 dwResult = DCE_NOT_SUPPORTED;
2386 goto end_loop;
2387 case ERR_NOT_CONNECTED:
2388 case ERR_CONNECTION_BROKEN:
2389 if (!connectToAgent())
2390 goto end_loop;
2391 break;
2392 case ERR_REQUEST_TIMEOUT:
2393 // Reset connection to agent after timeout
2394 DbgPrintf(7, _T("Node(%s)->getTableFromAgent(%s): timeout; resetting connection to agent..."), m_szName, name);
2395 delete_and_null(m_pAgentConnection);
2396 if (!connectToAgent())
2397 goto end_loop;
2398 DbgPrintf(7, _T("Node(%s)->getTableFromAgent(%s): connection to agent restored successfully"), m_szName, name);
2399 break;
2400 }
2401 }
2402
2403 end_loop:
2404 agentUnlock();
2405 DbgPrintf(7, _T("Node(%s)->getTableFromAgent(%s): dwError=%d dwResult=%d"), m_szName, name, dwError, dwResult);
2406 return dwResult;
2407 }
2408
2409
2410 //
2411 // Get value for server's internal parameter
2412 //
2413
2414 DWORD Node::GetInternalItem(const TCHAR *szParam, DWORD dwBufSize, TCHAR *szBuffer)
2415 {
2416 DWORD dwError = DCE_SUCCESS;
2417
2418 if (!_tcsicmp(szParam, _T("Status")))
2419 {
2420 _sntprintf(szBuffer, dwBufSize, _T("%d"), m_iStatus);
2421 }
2422 else if (!_tcsicmp(szParam, _T("Dummy")))
2423 {
2424 _tcscpy(szBuffer, _T("0"));
2425 }
2426 else if (!_tcsicmp(szParam, _T("AgentStatus")))
2427 {
2428 if (m_dwFlags & NF_IS_NATIVE_AGENT)
2429 {
2430 szBuffer[0] = (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ? _T('1') : _T('0');
2431 szBuffer[1] = 0;
2432 }
2433 else
2434 {
2435 dwError = DCE_NOT_SUPPORTED;
2436 }
2437 }
2438 else if (MatchString(_T("ChildStatus(*)"), szParam, FALSE))
2439 {
2440 TCHAR *pEnd, szArg[256];
2441 DWORD i, dwId;
2442 NetObj *pObject = NULL;
2443
2444 AgentGetParameterArg(szParam, 1, szArg, 256);
2445 dwId = _tcstoul(szArg, &pEnd, 0);
2446 if (*pEnd != 0)
2447 {
2448 // Argument is object's name
2449 dwId = 0;
2450 }
2451
2452 // Find child object with requested ID or name
2453 LockChildList(FALSE);
2454 for(i = 0; i < m_dwChildCount; i++)
2455 {
2456 if (((dwId == 0) && (!_tcsicmp(m_pChildList[i]->Name(), szArg))) ||
2457 (dwId == m_pChildList[i]->Id()))
2458 {
2459 pObject = m_pChildList[i];
2460 break;
2461 }
2462 }
2463 UnlockChildList();
2464
2465 if (pObject != NULL)
2466 {
2467 _sntprintf(szBuffer, dwBufSize, _T("%d"), pObject->Status());
2468 }
2469 else
2470 {
2471 dwError = DCE_NOT_SUPPORTED;
2472 }
2473 }
2474 else if (MatchString(_T("ConditionStatus(*)"), szParam, FALSE))
2475 {
2476 TCHAR *pEnd, szArg[256];
2477 DWORD dwId;
2478 NetObj *pObject = NULL;
2479
2480 AgentGetParameterArg(szParam, 1, szArg, 256);
2481 dwId = _tcstoul(szArg, &pEnd, 0);
2482 if (*pEnd == 0)
2483 {
2484 pObject = FindObjectById(dwId);
2485 if (pObject != NULL)
2486 if (pObject->Type() != OBJECT_CONDITION)
2487 pObject = NULL;
2488 }
2489 else
2490 {
2491 // Argument is object's name
2492 pObject = FindObjectByName(szArg, OBJECT_CONDITION);
2493 }
2494
2495 if (pObject != NULL)
2496 {
2497 if (pObject->IsTrustedNode(m_dwId))
2498 {
2499 _sntprintf(szBuffer, dwBufSize, _T("%d"), pObject->Status());
2500 }
2501 else
2502 {
2503 dwError = DCE_NOT_SUPPORTED;
2504 }
2505 }
2506 else
2507 {
2508 dwError = DCE_NOT_SUPPORTED;
2509 }
2510 }
2511 else if (m_dwFlags & NF_IS_LOCAL_MGMT)
2512 {
2513 if (!_tcsicmp(szParam, _T("Server.AverageDCPollerQueueSize")))
2514 {
2515 _sntprintf(szBuffer, dwBufSize, _T("%f"), g_dAvgPollerQueueSize);
2516 }
2517 else if (!_tcsicmp(szParam, _T("Server.AverageDBWriterQueueSize")))
2518 {
2519 _sntprintf(szBuffer, dwBufSize, _T("%f"), g_dAvgDBWriterQueueSize);
2520 }
2521 else if (!_tcsicmp(szParam, _T("Server.AverageStatusPollerQueueSize")))
2522 {
2523 _sntprintf(szBuffer, dwBufSize, _T("%f"), g_dAvgStatusPollerQueueSize);
2524 }
2525 else if (!_tcsicmp(szParam, _T("Server.AverageConfigurationPollerQueueSize")))
2526 {
2527 _sntprintf(szBuffer, dwBufSize, _T("%f"), g_dAvgConfigPollerQueueSize);
2528 }
2529 else if (!_tcsicmp(szParam, _T("Server.AverageDCIQueuingTime")))
2530 {
2531 _sntprintf(szBuffer, dwBufSize, _T("%u"), g_dwAvgDCIQueuingTime);
2532 }
2533 else if (!_tcsicmp(szParam, _T("Server.TotalEventsProcessed")))
2534 {
2535 _sntprintf(szBuffer, dwBufSize, INT64_FMT, g_totalEventsProcessed);
2536 }
2537 else
2538 {
2539 dwError = DCE_NOT_SUPPORTED;
2540 }
2541 }
2542 else
2543 {
2544 dwError = DCE_NOT_SUPPORTED;
2545 }
2546
2547 return dwError;
2548 }
2549
2550
2551 //
2552 // Translate DCI error code into RCC
2553 //
2554
2555 static DWORD RCCFromDCIError(DWORD error)
2556 {
2557 switch(error)
2558 {
2559 case DCE_SUCCESS:
2560 return RCC_SUCCESS;
2561 case DCE_COMM_ERROR:
2562 return RCC_COMM_FAILURE;
2563 case DCE_NOT_SUPPORTED:
2564 return RCC_DCI_NOT_SUPPORTED;
2565 default:
2566 return RCC_SYSTEM_FAILURE;
2567 }
2568 }
2569
2570
2571 //
2572 // Get item's value for client
2573 //
2574
2575 DWORD Node::getItemForClient(int iOrigin, const TCHAR *pszParam, TCHAR *pszBuffer, DWORD dwBufSize)
2576 {
2577 DWORD dwResult = 0, dwRetCode;
2578
2579 // Get data from node
2580 switch(iOrigin)
2581 {
2582 case DS_INTERNAL:
2583 dwRetCode = GetInternalItem(pszParam, dwBufSize, pszBuffer);
2584 break;
2585 case DS_NATIVE_AGENT:
2586 dwRetCode = GetItemFromAgent(pszParam, dwBufSize, pszBuffer);
2587 break;
2588 case DS_SNMP_AGENT:
2589 dwRetCode = GetItemFromSNMP(0, pszParam, dwBufSize, pszBuffer);
2590 break;
2591 case DS_CHECKPOINT_AGENT:
2592 dwRetCode = GetItemFromCheckPointSNMP(pszParam, dwBufSize, pszBuffer);
2593 break;
2594 default:
2595 dwResult = RCC_INVALID_ARGUMENT;
2596 break;
2597 }
2598
2599 // Translate return code to RCC
2600 if (dwResult != RCC_INVALID_ARGUMENT)
2601 dwResult = RCCFromDCIError(dwRetCode);
2602
2603 return dwResult;
2604 }
2605
2606
2607 //
2608 // Get table for client
2609 //
2610
2611 DWORD Node::getTableForClient(const TCHAR *name, Table **table)
2612 {
2613 DWORD dwRetCode = getTableFromAgent(name, table);
2614 return RCCFromDCIError(dwRetCode);
2615 }
2616
2617
2618 //
2619 // Put items which requires polling into the queue
2620 //
2621
2622 void Node::queueItemsForPolling(Queue *pPollerQueue)
2623 {
2624 DWORD i;
2625 time_t currTime;
2626
2627 if ((m_iStatus == STATUS_UNMANAGED) ||
2628 (m_dwFlags & NF_DISABLE_DATA_COLLECT) ||
2629 (m_bIsDeleted))
2630 return; // Do not collect data for unmanaged nodes or if data collection is disabled
2631
2632 currTime = time(NULL);
2633
2634 lockDciAccess();
2635 for(i = 0; i < m_dwNumItems; i++)
2636 {
2637 if (m_ppItems[i]->isReadyForPolling(currTime))
2638 {
2639 m_ppItems[i]->setBusyFlag(TRUE);
2640 IncRefCount(); // Increment reference count for each queued DCI
2641 pPollerQueue->Put(m_ppItems[i]);
2642 DbgPrintf(8, _T("Node(%s)->QueueItemsForPolling(): item %d \"%s\" added to queue"), m_szName, m_ppItems[i]->getId(), m_ppItems[i]->getName());
2643 }
2644 }
2645 unlockDciAccess();
2646 }
2647
2648
2649 //
2650 // Create CSCP message with object's data
2651 //
2652
2653 void Node::CreateMessage(CSCPMessage *pMsg)
2654 {
2655 Template::CreateMessage(pMsg);
2656 pMsg->SetVariable(VID_FLAGS, m_dwFlags);
2657 pMsg->SetVariable(VID_RUNTIME_FLAGS, m_dwDynamicFlags);
2658 pMsg->SetVariable(VID_AGENT_PORT, m_wAgentPort);
2659 pMsg->SetVariable(VID_AUTH_METHOD, m_wAuthMethod);
2660 pMsg->SetVariable(VID_SHARED_SECRET, m_szSharedSecret);
2661 pMsg->SetVariableFromMBString(VID_SNMP_AUTH_OBJECT, m_snmpSecurity->getCommunity());
2662 pMsg->SetVariableFromMBString(VID_SNMP_AUTH_PASSWORD, m_snmpSecurity->getAuthPassword());
2663 pMsg->SetVariableFromMBString(VID_SNMP_PRIV_PASSWORD, m_snmpSecurity->getPrivPassword());
2664 pMsg->SetVariable(VID_SNMP_USM_METHODS, (WORD)((WORD)m_snmpSecurity->getAuthMethod() | ((WORD)m_snmpSecurity->getPrivMethod() << 8)));
2665 pMsg->SetVariable(VID_SNMP_OID, m_szObjectId);
2666 pMsg->SetVariable(VID_SNMP_PORT, m_wSNMPPort);
2667 pMsg->SetVariable(VID_SNMP_VERSION, (WORD)m_snmpVersion);
2668 pMsg->SetVariable(VID_AGENT_VERSION, m_szAgentVersion);
2669 pMsg->SetVariable(VID_PLATFORM_NAME, m_szPlatformName);
2670 pMsg->SetVariable(VID_POLLER_NODE_ID, m_dwPollerNode);
2671 pMsg->SetVariable(VID_ZONE_ID, m_zoneId);
2672 pMsg->SetVariable(VID_PROXY_NODE, m_dwProxyNode);
2673 pMsg->SetVariable(VID_SNMP_PROXY, m_dwSNMPProxy);
2674 pMsg->SetVariable(VID_REQUIRED_POLLS, (WORD)m_iRequiredPollCount);
2675 pMsg->SetVariable(VID_SYS_NAME, CHECK_NULL_EX(m_sysName));
2676 pMsg->SetVariable(VID_SYS_DESCRIPTION, CHECK_NULL_EX(m_sysDescription));
2677 if (m_lldpNodeId != NULL)
2678 pMsg->SetVariable(VID_LLDP_NODE_ID, m_lldpNodeId);
2679 pMsg->SetVariable(VID_USE_IFXTABLE, (WORD)m_nUseIfXTable);
2680 if (m_vrrpInfo != NULL)
2681 {
2682 pMsg->SetVariable(VID_VRRP_VERSION, (WORD)m_vrrpInfo->getVersion());
2683 pMsg->SetVariable(VID_VRRP_VR_COUNT, (WORD)m_vrrpInfo->getSize());
2684 }
2685 if (m_driver != NULL)
2686 {
2687 pMsg->SetVariable(VID_DRIVER_NAME, m_driver->getName());
2688 pMsg->SetVariable(VID_DRIVER_VERSION, m_driver->getVersion());
2689 }
2690 }
2691
2692
2693 //
2694 // Modify object from message
2695 //
2696
2697 DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
2698 {
2699 if (!bAlreadyLocked)
2700 LockData();
2701
2702 // Change primary IP address
2703 if (pRequest->IsVariableExist(VID_IP_ADDRESS))
2704 {
2705 DWORD i, dwIpAddr;
2706
2707 dwIpAddr = pRequest->GetVariableLong(VID_IP_ADDRESS);
2708
2709 // Check if received IP address is one of node's interface addresses
2710 LockChildList(FALSE);
2711 for(i = 0; i < m_dwChildCount; i++)
2712 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
2713 (m_pChildList[i]->IpAddr() == dwIpAddr))
2714 break;
2715 UnlockChildList();
2716 if (i == m_dwChildCount)
2717 {
2718 UnlockData();
2719 return RCC_INVALID_IP_ADDR;
2720 }
2721
2722 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
2723 m_dwIpAddr = dwIpAddr;
2724 }
2725
2726 // Poller node ID
2727 if (pRequest->IsVariableExist(VID_POLLER_NODE_ID))
2728 {
2729 DWORD dwNodeId;
2730 NetObj *pObject;
2731
2732 dwNodeId = pRequest->GetVariableLong(VID_POLLER_NODE_ID);
2733 pObject = FindObjectById(dwNodeId);
2734
2735 // Check if received id is a valid node id
2736 if (pObject == NULL)
2737 {
2738 UnlockData();
2739 return RCC_INVALID_OBJECT_ID;
2740 }
2741 if (pObject->Type() != OBJECT_NODE)
2742 {
2743 UnlockData();
2744 return RCC_INVALID_OBJECT_ID;
2745 }
2746
2747 m_dwPollerNode = dwNodeId;
2748 }
2749
2750 // Change listen port of native agent
2751 if (pRequest->IsVariableExist(VID_AGENT_PORT))
2752 m_wAgentPort = pRequest->GetVariableShort(VID_AGENT_PORT);
2753
2754 // Change authentication method of native agent
2755 if (pRequest->IsVariableExist(VID_AUTH_METHOD))
2756 m_wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
2757
2758 // Change shared secret of native agent
2759 if (pRequest->IsVariableExist(VID_SHARED_SECRET))
2760 pRequest->GetVariableStr(VID_SHARED_SECRET, m_szSharedSecret, MAX_SECRET_LENGTH);
2761
2762 // Change SNMP protocol version
2763 if (pRequest->IsVariableExist(VID_SNMP_VERSION))
2764 {
2765 m_snmpVersion = pRequest->GetVariableShort(VID_SNMP_VERSION);
2766 m_snmpSecurity->setSecurityModel((m_snmpVersion == SNMP_VERSION_3) ? SNMP_SECURITY_MODEL_USM : SNMP_SECURITY_MODEL_V2C);
2767 }
2768
2769 // Change SNMP port
2770 if (pRequest->IsVariableExist(VID_SNMP_PORT))
2771 m_wSNMPPort = pRequest->GetVariableShort(VID_SNMP_PORT);
2772
2773 // Change SNMP authentication data
2774 if (pRequest->IsVariableExist(VID_SNMP_AUTH_OBJECT))
2775 {
2776 char mbBuffer[256];
2777
2778 pRequest->GetVariableStrA(VID_SNMP_AUTH_OBJECT, mbBuffer, 256);
2779 m_snmpSecurity->setAuthName(mbBuffer);
2780
2781 pRequest->GetVariableStrA(VID_SNMP_AUTH_PASSWORD, mbBuffer, 256);
2782 m_snmpSecurity->setAuthPassword(mbBuffer);
2783
2784 pRequest->GetVariableStrA(VID_SNMP_PRIV_PASSWORD, mbBuffer, 256);
2785 m_snmpSecurity->setPrivPassword(mbBuffer);
2786
2787 WORD methods = pRequest->GetVariableShort(VID_SNMP_USM_METHODS);
2788 m_snmpSecurity->setAuthMethod((int)(methods & 0xFF));
2789 m_snmpSecurity->setPrivMethod((int)(methods >> 8));
2790 }
2791
2792 // Change proxy node
2793 if (pRequest->IsVariableExist(VID_PROXY_NODE))
2794 m_dwProxyNode = pRequest->GetVariableLong(VID_PROXY_NODE);
2795
2796 // Change SNMP proxy node
2797 if (pRequest->IsVariableExist(VID_SNMP_PROXY))
2798 m_dwSNMPProxy = pRequest->GetVariableLong(VID_SNMP_PROXY);
2799
2800 // Number of required polls
2801 if (pRequest->IsVariableExist(VID_REQUIRED_POLLS))
2802 m_iRequiredPollCount = (int)pRequest->GetVariableShort(VID_REQUIRED_POLLS);
2803
2804 // Enable/disable usage of ifXTable
2805 if (pRequest->IsVariableExist(VID_USE_IFXTABLE))
2806 m_nUseIfXTable = (BYTE)pRequest->GetVariableShort(VID_USE_IFXTABLE);
2807
2808 // Change flags
2809 if (pRequest->IsVariableExist(VID_FLAGS))
2810 {
2811 m_dwFlags &= NF_SYSTEM_FLAGS;
2812 m_dwFlags |= pRequest->GetVariableLong(VID_FLAGS) & NF_USER_FLAGS;
2813 }
2814
2815 return Template::ModifyFromMessage(pRequest, TRUE);
2816 }
2817
2818
2819 //
2820 // Wakeup node using magic packet
2821 //
2822
2823 DWORD Node::wakeUp()
2824 {
2825 DWORD i, dwResult = RCC_NO_WOL_INTERFACES;
2826
2827 LockChildList(FALSE);
2828
2829 for(i = 0; i < m_dwChildCount; i++)
2830 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
2831 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
2832 (m_pChildList[i]->IpAddr() != 0))
2833 {
2834 dwResult = ((Interface *)m_pChildList[i])->wakeUp();
2835 break;
2836 }
2837
2838 UnlockChildList();
2839 return dwResult;
2840 }
2841
2842
2843 //
2844 // Get status of interface with given index from SNMP agent
2845 //
2846
2847 int Node::getInterfaceStatusFromSNMP(SNMP_Transport *pTransport, DWORD dwIndex)
2848 {
2849 return SnmpGetInterfaceStatus(m_snmpVersion, pTransport, dwIndex);
2850 }
2851
2852
2853 //
2854 // Get status of interface with given index from native agent
2855 //
2856
2857 int Node::getInterfaceStatusFromAgent(DWORD dwIndex)
2858 {
2859 TCHAR szParam[128], szBuffer[32];
2860 DWORD dwAdminStatus, dwLinkState;
2861 int iStatus;
2862
2863 // Get administrative status
2864 _sntprintf(szParam, 128, _T("Net.Interface.AdminStatus(%u)"), dwIndex);
2865 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
2866 {
2867 dwAdminStatus = _tcstoul(szBuffer, NULL, 0);
2868
2869 switch(dwAdminStatus)
2870 {
2871 case 3:
2872 iStatus = STATUS_TESTING;
2873 break;
2874 case 2:
2875 case 0: // Agents before 0.2.1 may return 0 instead of 2
2876 iStatus = STATUS_DISABLED;
2877 break;
2878 case 1: // Interface administratively up, check link state
2879 _sntprintf(szParam, 128, _T("Net.Interface.Link(%u)"), dwIndex);
2880 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
2881 {
2882 dwLinkState = _tcstoul(szBuffer, NULL, 0);
2883 iStatus = (dwLinkState == 0) ? STATUS_CRITICAL : STATUS_NORMAL;
2884 }
2885 else
2886 {
2887 iStatus = STATUS_UNKNOWN;
2888 }
2889 break;
2890 default:
2891 iStatus = STATUS_UNKNOWN;
2892 break;
2893 }
2894 }
2895 else
2896 {
2897 iStatus = STATUS_UNKNOWN;
2898 }
2899
2900 return iStatus;
2901 }
2902
2903
2904 //
2905 // Put list of supported parameters into CSCP message
2906 //
2907
2908 void Node::WriteParamListToMessage(CSCPMessage *pMsg)
2909 {
2910 DWORD i, dwId;
2911
2912 LockData();
2913 if (m_pParamList != NULL)
2914 {
2915 pMsg->SetVariable(VID_NUM_PARAMETERS, m_dwNumParams);
2916 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < m_dwNumParams; i++)
2917 {
2918 pMsg->SetVariable(dwId++, m_pParamList[i].szName);
2919 pMsg->SetVariable(dwId++, m_pParamList[i].szDescription);
2920 pMsg->SetVariable(dwId++, (WORD)m_pParamList[i].iDataType);
2921 }
2922 DbgPrintf(6, _T("Node[%s]::WriteParamListToMessage(): sending %d parameters"), m_szName, m_dwNumParams);
2923 }
2924 else
2925 {
2926 DbgPrintf(6, _T("Node[%s]::WriteParamListToMessage(): m_pParamList == NULL"), m_szName);
2927 pMsg->SetVariable(VID_NUM_PARAMETERS, (DWORD)0);
2928 }
2929 UnlockData();
2930 }
2931
2932
2933 //
2934 // Open list of supported parameters for reading
2935 //
2936
2937 void Node::OpenParamList(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
2938 {
2939 LockData();
2940 *pdwNumParams = m_dwNumParams;
2941 *ppParamList = m_pParamList;
2942 }
2943
2944
2945 //
2946 // Check status of network service
2947 //
2948
2949 DWORD Node::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
2950 WORD wPort, WORD wProto, TCHAR *pszRequest,
2951 TCHAR *pszResponse)
2952 {
2953 DWORD dwError = ERR_NOT_CONNECTED;
2954
2955 if ((m_dwFlags & NF_IS_NATIVE_AGENT) &&
2956 (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)) &&
2957 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
2958 {
2959 AgentConnection *pConn;
2960
2961 pConn = createAgentConnection();
2962 if (pConn != NULL)
2963 {
2964 dwError = pConn->checkNetworkService(pdwStatus, dwIpAddr, iServiceType,
2965 wPort, wProto, pszRequest, pszResponse);
2966 pConn->disconnect();
2967 delete pConn;
2968 }
2969 }
2970 return dwError;
2971 }
2972
2973
2974 //
2975 // Handler for object deletion
2976 //
2977
2978 void Node::OnObjectDelete(DWORD dwObjectId)
2979 {
2980 LockData();
2981 if (dwObjectId == m_dwPollerNode)
2982 {
2983 // If deleted object is our poller node, change it to default
2984 m_dwPollerNode = 0;
2985 Modify();
2986 DbgPrintf(3, _T("Node \"%s\": poller node %d deleted"), m_szName, dwObjectId);
2987 }
2988 UnlockData();
2989 }
2990
2991
2992 //
2993 // Check node for OSPF support
2994 //
2995
2996 void Node::CheckOSPFSupport(SNMP_Transport *pTransport)
2997 {
2998 LONG nAdminStatus;
2999
3000 if (SnmpGet(m_snmpVersion, pTransport,
3001 _T(".1.3.6.1.2.1.14.1.2.0"), NULL, 0, &nAdminStatus, sizeof(LONG), 0) == SNMP_ERR_SUCCESS)
3002 {
3003 LockData();
3004 if (nAdminStatus)
3005 {
3006 m_dwFlags |= NF_IS_OSPF;
3007 }
3008 else
3009 {
3010 m_dwFlags &= ~NF_IS_OSPF;
3011 }
3012 UnlockData();
3013 }
3014 }
3015
3016
3017 //
3018 // Create ready to use agent connection
3019 //
3020
3021 AgentConnectionEx *Node::createAgentConnection()
3022 {
3023 AgentConnectionEx *conn;
3024
3025 if ((!(m_dwFlags & NF_IS_NATIVE_AGENT)) ||
3026 (m_dwFlags & NF_DISABLE_NXCP) ||
3027 (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
3028 (m_dwDynamicFlags & NDF_UNREACHABLE))
3029 return NULL;
3030
3031 conn = new AgentConnectionEx(htonl(m_dwIpAddr), m_wAgentPort,
3032 m_wAuthMethod, m_szSharedSecret);
3033 setAgentProxy(conn);
3034 if (!conn->connect(g_pServerKey))
3035 {
3036 delete conn;
3037 conn = NULL;
3038 }
3039 return conn;
3040 }
3041
3042
3043 //
3044 // Get last collected values of all DCIs
3045 //
3046
3047 DWORD Node::getLastValues(CSCPMessage *pMsg)
3048 {
3049 DWORD i, dwId, dwCount;
3050
3051 lockDciAccess();
3052
3053 for(i = 0, dwId = VID_DCI_VALUES_BASE, dwCount = 0; i < m_dwNumItems; i++)
3054 {
3055 if (_tcsnicmp(m_ppItems[i]->getDescription(), _T("@system."), 8))
3056 {
3057 m_ppItems[i]->getLastValue(pMsg, dwId);
3058 dwId += 10;
3059 dwCount++;
3060 }
3061 }
3062 pMsg->SetVariable(VID_NUM_ITEMS, dwCount);
3063
3064 unlockDciAccess();
3065 return RCC_SUCCESS;
3066 }
3067
3068
3069 //
3070 // Clean expired DCI data
3071 //
3072
3073 void Node::cleanDCIData()
3074 {
3075 DWORD i;
3076
3077 lockDciAccess();
3078 for(i = 0; i < m_dwNumItems; i++)
3079 m_ppItems[i]->deleteExpiredData();
3080 unlockDciAccess();
3081 }
3082
3083
3084 //
3085 // Apply DCI from template
3086 // pItem passed to this method should be a template's DCI
3087 //
3088
3089 BOOL Node::applyTemplateItem(DWORD dwTemplateId, DCItem *pItem)
3090 {
3091 BOOL bResult = TRUE;
3092 DWORD i;
3093 DCItem *pNewItem;
3094
3095 lockDciAccess(); // write lock
3096
3097 DbgPrintf(5, _T("Applying item \"%s\" to node \"%s\""), pItem->getName(), m_szName);
3098
3099 // Check if that template item exists
3100 for(i = 0; i < m_dwNumItems; i++)
3101 if ((m_ppItems[i]->getTemplateId() == dwTemplateId) &&
3102 (m_ppItems[i]->getTemplateItemId() == pItem->getId()))
3103 break; // Item with specified id already exist
3104
3105 if (i == m_dwNumItems)
3106 {
3107 // New item from template, just add it
3108 pNewItem = new DCItem(pItem);
3109 pNewItem->setTemplateId(dwTemplateId, pItem->getId());
3110 pNewItem->changeBinding(CreateUniqueId(IDG_ITEM), this, TRUE);
3111 bResult = addItem(pNewItem, true);
3112 }
3113 else
3114 {
3115 // Update existing item
3116 m_ppItems[i]->updateFromTemplate(pItem);
3117 }
3118
3119 unlockDciAccess();
3120
3121 if (bResult)
3122 {
3123 LockData();
3124 m_bIsModified = TRUE;
3125 UnlockData();
3126 }
3127 return bResult;
3128 }
3129
3130
3131 //
3132 // Clean deleted template items from node's DCI list
3133 // Arguments is template id and list of valid template item ids.
3134 // all items related to given template and not presented in list should be deleted.
3135 //
3136
3137 void Node::cleanDeletedTemplateItems(DWORD dwTemplateId, DWORD dwNumItems, DWORD *pdwItemList)
3138 {
3139 DWORD i, j, dwNumDeleted, *pdwDeleteList;
3140
3141 lockDciAccess(); // write lock
3142
3143 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
3144 dwNumDeleted = 0;
3145
3146 for(i = 0; i < m_dwNumItems; i++)
3147 if (m_ppItems[i]->getTemplateId() == dwTemplateId)
3148 {
3149 for(j = 0; j < dwNumItems; j++)
3150 if (m_ppItems[i]->getTemplateItemId() == pdwItemList[j])
3151 break;
3152
3153 // Delete DCI if it's not in list
3154 if (j == dwNumItems)
3155 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->getId();
3156 }
3157
3158 for(i = 0; i < dwNumDeleted; i++)
3159 deleteItem(pdwDeleteList[i], false);
3160
3161 unlockDciAccess();
3162 free(pdwDeleteList);
3163 }
3164
3165
3166 //
3167 // Unbind node from template, i.e either remove DCI association with template
3168 // or remove these DCIs at all
3169 //
3170
3171 void Node::unbindFromTemplate(DWORD dwTemplateId, BOOL bRemoveDCI)
3172 {
3173 DWORD i;
3174
3175 if (bRemoveDCI)
3176 {
3177 DWORD *pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
3178 DWORD dwNumDeleted = 0;
3179
3180 lockDciAccess(); // write lock
3181
3182 for(i = 0; i < m_dwNumItems; i++)
3183 if (m_ppItems[i]->getTemplateId() == dwTemplateId)
3184 {
3185 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->getId();
3186 }
3187
3188 for(i = 0; i < dwNumDeleted; i++)
3189 deleteItem(pdwDeleteList[i], false);
3190
3191 unlockDciAccess();
3192
3193 safe_free(pdwDeleteList);
3194 }
3195 else
3196 {
3197 lockDciAccess();
3198
3199 for(i = 0; i < m_dwNumItems; i++)
3200 if (m_ppItems[i]->getTemplateId() == dwTemplateId)
3201 {
3202 m_ppItems[i]->setTemplateId(0, 0);
3203 }
3204
3205 unlockDciAccess();
3206 }
3207 }
3208
3209
3210 //
3211 // Change node's IP address
3212 //
3213
3214 void Node::changeIPAddress(DWORD dwIpAddr)
3215 {
3216 DWORD i;
3217
3218 pollerLock();
3219
3220 LockData();
3221
3222 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
3223 m_dwIpAddr = dwIpAddr;
3224 m_dwDynamicFlags |= NDF_FORCE_CONFIGURATION_POLL | NDF_RECHECK_CAPABILITIES;
3225
3226 // Change status of node and all it's childs to UNKNOWN
3227 m_iStatus = STATUS_UNKNOWN;
3228 LockChildList(FALSE);
3229 for(i = 0; i < m_dwChildCount; i++)
3230 {
3231 m_pChildList[i]->resetStatus();
3232 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
3233 {
3234 if (((Interface *)m_pChildList[i])->isFake())
3235 {
3236 ((Interface *)m_pChildList[i])->setIpAddr(dwIpAddr);
3237 }
3238 }
3239 }
3240 UnlockChildList();
3241
3242 Modify();
3243 UnlockData();
3244
3245 agentLock();
3246 delete_and_null(m_pAgentConnection);
3247 agentUnlock();
3248
3249 pollerUnlock();
3250 }
3251
3252
3253 //
3254 // Get number of interface objects and pointer to the last one
3255 //
3256
3257 DWORD Node::getInterfaceCount(Interface **ppInterface)
3258 {
3259 DWORD i, dwCount;
3260
3261 LockChildList(FALSE);
3262 for(i = 0, dwCount = 0; i < m_dwChildCount; i++)
3263 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
3264 {
3265 dwCount++;
3266 *ppInterface = (Interface *)m_pChildList[i];
3267 }
3268 UnlockChildList();
3269 return dwCount;
3270 }
3271
3272
3273 //
3274 // Update cache for all DCI's
3275 //
3276
3277 void Node::updateDciCache()
3278 {
3279 DWORD i;
3280
3281 lockDciAccess();
3282 for(i = 0; i < m_dwNumItems; i++)
3283 m_ppItems[i]->updateCacheSize();
3284 unlockDciAccess();
3285 }
3286
3287
3288 //
3289 // Get routing table from node
3290 //
3291
3292 ROUTING_TABLE *Node::getRoutingTable()
3293 {
3294 ROUTING_TABLE *pRT = NULL;
3295
3296 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)))
3297 {
3298 agentLock();
3299 if (connectToAgent())
3300 {
3301 pRT = m_pAgentConnection->getRoutingTable();
3302 }
3303 agentUnlock();
3304 }
3305 if ((pRT == NULL) && (m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)))
3306 {
3307 SNMP_Transport *pTransport;
3308
3309 pTransport = createSnmpTransport();
3310 if (pTransport != NULL)
3311 {
3312 pRT = SnmpGetRoutingTable(m_snmpVersion, pTransport);
3313 delete pTransport;
3314 }
3315 }
3316
3317 if (pRT != NULL)
3318 {
3319 SortRoutingTable(pRT);
3320 }
3321 return pRT;
3322 }
3323
3324
3325 //
3326 // Get next hop for given destination address
3327 //
3328
3329 BOOL Node::getNextHop(DWORD dwSrcAddr, DWORD dwDestAddr, DWORD *pdwNextHop,
3330 DWORD *pdwIfIndex, BOOL *pbIsVPN)
3331 {
3332 DWORD i;
3333 BOOL bResult = FALSE;
3334
3335 // Check VPN connectors
3336 LockChildList(FALSE);
3337 for(i = 0; i < m_dwChildCount; i++)
3338 if (m_pChildList[i]->Type() == OBJECT_VPNCONNECTOR)
3339 {
3340 if (((VPNConnector *)m_pChildList[i])->IsRemoteAddr(dwDestAddr) &&
3341 ((VPNConnector *)m_pChildList[i])->IsLocalAddr(dwSrcAddr))
3342 {
3343 *pdwNextHop = ((VPNConnector *)m_pChildList[i])->GetPeerGatewayAddr();
3344 *pdwIfIndex = m_pChildList[i]->Id();
3345 *pbIsVPN = TRUE;
3346 bResult = TRUE;
3347 break;
3348 }
3349 }
3350 UnlockChildList();
3351
3352 // Check routing table
3353 if (!bResult)
3354 {
3355 routingTableLock();
3356 if (m_pRoutingTable != NULL)
3357 {
3358 for(i = 0; i < (DWORD)m_pRoutingTable->iNumEntries; i++)
3359 if ((dwDestAddr & m_pRoutingTable->pRoutes[i].dwDestMask) == m_pRoutingTable->pRoutes[i].dwDestAddr)
3360 {
3361 *pdwNextHop = m_pRoutingTable->pRoutes[i].dwNextHop;
3362 *pdwIfIndex = m_pRoutingTable->pRoutes[i].dwIfIndex;
3363 *pbIsVPN = FALSE;
3364 bResult = TRUE;
3365 break;
3366 }
3367 }
3368 routingTableUnlock();
3369 }
3370
3371 return bResult;
3372 }
3373
3374
3375 //
3376 // Update cached routing table
3377 //
3378
3379 void Node::updateRoutingTable()
3380 {
3381 ROUTING_TABLE *pRT;
3382
3383 pRT = getRoutingTable();
3384 if (pRT != NULL)
3385 {
3386 routingTableLock();
3387 DestroyRoutingTable(m_pRoutingTable);
3388 m_pRoutingTable = pRT;
3389 routingTableUnlock();
3390 }
3391 m_tLastRTUpdate = time(NULL);
3392 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_ROUTE_POLL;
3393 }
3394
3395
3396 //
3397 // Call SNMP Enumerate with node's SNMP parameters
3398 //
3399
3400 DWORD Node::CallSnmpEnumerate(const TCHAR *pszRootOid,
3401 DWORD (* pHandler)(DWORD, SNMP_Variable *, SNMP_Transport *, void *),
3402 void *pArg)
3403 {
3404 if ((m_dwFlags & NF_IS_SNMP) &&
3405 (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)) &&
3406 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
3407 {
3408 SNMP_Transport *pTransport;
3409 DWORD dwResult;
3410
3411 pTransport = createSnmpTransport();
3412 if (pTransport != NULL)
3413 {
3414 dwResult = SnmpEnumerate(m_snmpVersion, pTransport,
3415 pszRootOid, pHandler, pArg, FALSE);
3416 delete pTransport;
3417 }
3418 else
3419 {
3420 dwResult = SNMP_ERR_COMM;
3421 }
3422 return dwResult;
3423 }
3424 else
3425 {
3426 return SNMP_ERR_COMM;
3427 }
3428 }
3429
3430
3431 //
3432 // Set proxy information for agent's connection
3433 //
3434
3435 void Node::setAgentProxy(AgentConnection *pConn)
3436 {
3437 if (m_dwProxyNode != 0)
3438 {
3439 Node *pNode;
3440
3441 pNode = (Node *)FindObjectById(m_dwProxyNode);
3442 if (pNode != NULL)
3443 {
3444 pConn->setProxy(htonl(pNode->m_dwIpAddr), pNode->m_wAgentPort,
3445 pNode->m_wAuthMethod, pNode->m_szSharedSecret);
3446 }
3447 }
3448 }
3449
3450
3451 //
3452 // Prepare node object for deletion
3453 //
3454
3455 void Node::PrepareForDeletion()
3456 {
3457 // Prevent node from being queued for polling
3458 LockData();
3459 m_dwDynamicFlags |= NDF_POLLING_DISABLED;
3460 UnlockData();
3461
3462 // Wait for all pending polls
3463 while(1)
3464 {
3465 LockData();
3466 if ((m_dwDynamicFlags &
3467 (NDF_QUEUED_FOR_STATUS_POLL | NDF_QUEUED_FOR_CONFIG_POLL |
3468 NDF_QUEUED_FOR_DISCOVERY_POLL | NDF_QUEUED_FOR_ROUTE_POLL)) == 0)
3469 {
3470 UnlockData();
3471 break;
3472 }
3473 UnlockData();
3474 ThreadSleepMs(100);
3475 }
3476 Template::PrepareForDeletion();
3477 }
3478
3479
3480 //
3481 // Check if specified SNMP variable set to specified value.
3482 // If variable doesn't exist at all, will return FALSE
3483 //
3484
3485 BOOL Node::CheckSNMPIntegerValue(SNMP_Transport *pTransport, const TCHAR *pszOID, int nValue)
3486 {
3487 DWORD dwTemp;
3488
3489 if (SnmpGet(m_snmpVersion, pTransport, pszOID, NULL, 0, &dwTemp, sizeof(DWORD), 0) == SNMP_ERR_SUCCESS)
3490 return (int)dwTemp == nValue;
3491 return FALSE;
3492 }
3493
3494
3495 //
3496 // Check and update if needed interface names
3497 //
3498
3499 void Node::CheckInterfaceNames(InterfaceList *pIfList)
3500 {
3501 // Cut interface names to MAX_OBJECT_NAME and check for unnamed interfaces
3502 for(int i = 0; i < pIfList->getSize(); i++)
3503 {
3504 pIfList->get(i)->szName[MAX_OBJECT_NAME - 1] = 0;
3505 if (pIfList->get(i)->szName[0] == 0)
3506 _sntprintf(pIfList->get(i)->szName, MAX_OBJECT_NAME, _T("%d"), pIfList->get(i)->dwIndex);
3507 }
3508 }
3509
3510
3511 //
3512 // Get cluster object this node belongs to, if any
3513 //
3514
3515 Cluster *Node::getMyCluster()
3516 {
3517 DWORD i;
3518 Cluster *pCluster = NULL;
3519
3520 LockParentList(FALSE);
3521 for(i = 0; i < m_dwParentCount; i++)
3522 if (m_pParentList[i]->Type() == OBJECT_CLUSTER)
3523 {
3524 pCluster = (Cluster *)m_pParentList[i];
3525 break;
3526 }
3527 UnlockParentList();
3528 return pCluster;
3529 }
3530
3531
3532 //
3533 // Create SNMP transport
3534 //
3535
3536 SNMP_Transport *Node::createSnmpTransport(WORD port)
3537 {
3538 SNMP_Transport *pTransport = NULL;
3539
3540 if (m_dwSNMPProxy == 0)
3541 {
3542 pTransport = new SNMP_UDPTransport;
3543 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(NULL, htonl(m_dwIpAddr), (port != 0) ? port : m_wSNMPPort);
3544 }
3545 else
3546 {
3547 NetObj *pObject;
3548
3549 pObject = FindObjectById(m_dwSNMPProxy);
3550 if (pObject != NULL)
3551 {
3552 if (pObject->Type() == OBJECT_NODE)
3553 {
3554 AgentConnection *pConn;
3555
3556 pConn = ((Node *)pObject)->createAgentConnection();
3557 if (pConn != NULL)
3558 {
3559 pTransport = new SNMP_ProxyTransport(pConn, m_dwIpAddr, (port != 0) ? port : m_wSNMPPort);
3560 }
3561 }
3562 }
3563 }
3564
3565 // Set security
3566 if (pTransport != NULL)
3567 {
3568 LockData();
3569 pTransport->setSecurityContext(new SNMP_SecurityContext(m_snmpSecurity));
3570 pTransport->setSnmpVersion(m_snmpVersion);
3571 UnlockData();
3572 }
3573 return pTransport;
3574 }
3575
3576
3577 //
3578 // Get SNMP security context
3579 // ATTENTION: This method returns new copy of security context
3580 // which must be destroyed by the caller
3581 //
3582
3583 SNMP_SecurityContext *Node::getSnmpSecurityContext()
3584 {
3585 LockData();
3586 SNMP_SecurityContext *ctx = new SNMP_SecurityContext(m_snmpSecurity);
3587 UnlockData();
3588 return ctx;
3589 }
3590
3591
3592 //
3593 // Resolve node's name
3594 //
3595
3596 BOOL Node::ResolveName(BOOL useOnlyDNS)
3597 {
3598 BOOL bSuccess = FALSE;
3599 HOSTENT *hs;
3600 DWORD i, dwAddr;
3601 TCHAR szBuffer[256];
3602
3603 DbgPrintf(4, _T("Resolving name for node %d [%s]..."), m_dwId, m_szName);
3604
3605 // Try to resolve primary IP
3606 dwAddr = htonl(m_dwIpAddr);
3607 hs = gethostbyaddr((const char *)&dwAddr, 4, AF_INET);
3608 if (hs != NULL)
3609 {
3610 #ifdef UNICODE
3611 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, hs->h_name, -1, m_szName, MAX_OBJECT_NAME);
3612 m_szName[MAX_OBJECT_NAME - 1] = 0;
3613 #else
3614 nx_strncpy(m_szName, hs->h_name, MAX_OBJECT_NAME);
3615 #endif
3616 bSuccess = TRUE;
3617 }
3618 else
3619 {
3620 // Try to resolve each interface's IP address
3621 LockChildList(FALSE);
3622 for(i = 0; i < m_dwChildCount; i++)
3623 {
3624 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
3625 {
3626 dwAddr = htonl(m_pChildList[i]->IpAddr());
3627 if (dwAddr != 0)
3628 {
3629 hs = gethostbyaddr((const char *)&dwAddr, 4, AF_INET);
3630 if (hs != NULL)
3631 {
3632 #ifdef UNICODE
3633 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, hs->h_name, -1, m_szName, MAX_OBJECT_NAME);
3634 m_szName[MAX_OBJECT_NAME - 1] = 0;
3635 #else
3636 nx_strncpy(m_szName, hs->h_name, MAX_OBJECT_NAME);
3637 #endif
3638 bSuccess = TRUE;
3639 break;
3640 }
3641 }
3642 }
3643 }
3644 UnlockChildList();
3645
3646 // Try to get hostname from agent if address resolution fails
3647 if (!(bSuccess || useOnlyDNS))
3648 {
3649 DbgPrintf(4, _T("Resolving name for node %d [%s] via agent..."), m_dwId, m_szName);
3650 if (GetItemFromAgent(_T("System.Hostname"), 256, szBuffer) == DCE_SUCCESS)
3651 {
3652 StrStrip(szBuffer);
3653 if (szBuffer[0] != 0)
3654 {
3655 nx_strncpy(m_szName, szBuffer, MAX_OBJECT_NAME);
3656 bSuccess = TRUE;
3657 }
3658 }
3659 }
3660
3661 // Try to get hostname from SNMP if other methods fails
3662 if (!(bSuccess || useOnlyDNS))
3663 {
3664 DbgPrintf(4, _T("Resolving name for node %d [%s] via SNMP..."), m_dwId, m_szName);
3665 if (GetItemFromSNMP(0, _T(".1.3.6.1.2.1.1.5.0"), 256, szBuffer) == DCE_SUCCESS)
3666 {
3667 StrStrip(szBuffer);
3668 if (szBuffer[0] != 0)
3669 {
3670 nx_strncpy(m_szName, szBuffer, MAX_OBJECT_NAME);
3671 bSuccess = TRUE;
3672 }
3673 }
3674 }
3675 }
3676
3677 if (bSuccess)
3678 DbgPrintf(4, _T("Name for node %d was resolved to %s"), m_dwId, m_szName);
3679 else
3680 DbgPrintf(4, _T("Name for node %d was not resolved"), m_dwId, m_szName);
3681 return bSuccess;
3682 }
3683
3684
3685 //
3686 // Send list of system DCIs
3687 //
3688
3689 DWORD Node::getPerfTabDCIList(CSCPMessage *pMsg)
3690 {
3691 DWORD i, dwId, dwCount;
3692
3693 LockData();
3694
3695 for(i = 0, dwId = VID_SYSDCI_LIST_BASE, dwCount = 0; i < m_dwNumItems; i++)
3696 {
3697 if (!_tcsnicmp(m_ppItems[i]->getDescription(), _T("@System."), 8) ||
3698 (m_ppItems[i]->getPerfTabSettings() != NULL))
3699 {
3700 pMsg->SetVariable(dwId++, m_ppItems[i]->getId());
3701 pMsg->SetVariable(dwId++, (TCHAR *)m_ppItems[i]->getDescription());
3702 pMsg->SetVariable(dwId++, (WORD)m_ppItems[i]->getStatus());
3703 if (m_ppItems[i]->getPerfTabSettings() != NULL)
3704 {