f3561d50cfa0deacda35f1297186c46965c28ec4
[public/netxms.git] / src / server / core / node.cpp
1 /* $Id: node.cpp,v 1.199 2008-02-17 11:07:57 victor Exp $ */
2 /*
3 ** NetXMS - Network Management System
4 ** Copyright (C) 2003, 2004, 2005, 2006, 2007 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: node.cpp
21 **
22 **/
23
24 #include "nxcore.h"
25
26
27 //
28 // Node class default constructor
29 //
30
31 Node::Node()
32 :Template()
33 {
34 m_dwFlags = 0;
35 m_dwDynamicFlags = 0;
36 m_dwZoneGUID = 0;
37 m_dwNodeType = NODE_TYPE_GENERIC;
38 m_wAgentPort = AGENT_LISTEN_PORT;
39 m_wAuthMethod = AUTH_NONE;
40 m_szSharedSecret[0] = 0;
41 m_iStatusPollType = POLL_ICMP_PING;
42 m_iSNMPVersion = SNMP_VERSION_1;
43 m_wSNMPPort = SNMP_DEFAULT_PORT;
44 ConfigReadStr("DefaultCommunityString", m_szCommunityString,
45 MAX_COMMUNITY_LENGTH, "public");
46 m_szObjectId[0] = 0;
47 m_tLastDiscoveryPoll = 0;
48 m_tLastStatusPoll = 0;
49 m_tLastConfigurationPoll = 0;
50 m_tLastRTUpdate = 0;
51 m_hPollerMutex = MutexCreate();
52 m_hAgentAccessMutex = MutexCreate();
53 m_mutexRTAccess = MutexCreate();
54 m_mutexTopoAccess = MutexCreate();
55 m_pAgentConnection = NULL;
56 m_szAgentVersion[0] = 0;
57 m_szPlatformName[0] = 0;
58 m_szSysDescription[0] = 0;
59 m_dwNumParams = 0;
60 m_pParamList = NULL;
61 m_dwPollerNode = 0;
62 m_dwProxyNode = 0;
63 m_dwSNMPProxy = 0;
64 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
65 m_pRoutingTable = NULL;
66 m_tFailTimeSNMP = 0;
67 m_tFailTimeAgent = 0;
68 m_pTopology = NULL;
69 m_tLastTopologyPoll = 0;
70 m_iPendingStatus = -1;
71 m_iPollCount = 0;
72 m_iRequiredPollCount = 0; // Use system default
73 }
74
75
76 //
77 // Constructor for new node object
78 //
79
80 Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwProxyNode, DWORD dwSNMPProxy, DWORD dwZone)
81 :Template()
82 {
83 m_dwIpAddr = dwAddr;
84 m_dwFlags = dwFlags;
85 m_dwDynamicFlags = 0;
86 m_dwZoneGUID = dwZone;
87 m_dwNodeType = NODE_TYPE_GENERIC;
88 m_wAgentPort = AGENT_LISTEN_PORT;
89 m_wAuthMethod = AUTH_NONE;
90 m_szSharedSecret[0] = 0;
91 m_iStatusPollType = POLL_ICMP_PING;
92 m_iSNMPVersion = SNMP_VERSION_1;
93 m_wSNMPPort = SNMP_DEFAULT_PORT;
94 ConfigReadStr("DefaultCommunityString", m_szCommunityString,
95 MAX_COMMUNITY_LENGTH, "public");
96 IpToStr(dwAddr, m_szName); // Make default name from IP address
97 m_szObjectId[0] = 0;
98 m_tLastDiscoveryPoll = 0;
99 m_tLastStatusPoll = 0;
100 m_tLastConfigurationPoll = 0;
101 m_tLastRTUpdate = 0;
102 m_hPollerMutex = MutexCreate();
103 m_hAgentAccessMutex = MutexCreate();
104 m_mutexRTAccess = MutexCreate();
105 m_mutexTopoAccess = MutexCreate();
106 m_pAgentConnection = NULL;
107 m_szAgentVersion[0] = 0;
108 m_szPlatformName[0] = 0;
109 m_szSysDescription[0] = 0;
110 m_dwNumParams = 0;
111 m_pParamList = NULL;
112 m_dwPollerNode = 0;
113 m_dwProxyNode = dwProxyNode;
114 m_dwSNMPProxy = dwSNMPProxy;
115 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
116 m_bIsHidden = TRUE;
117 m_pRoutingTable = NULL;
118 m_tFailTimeSNMP = 0;
119 m_tFailTimeAgent = 0;
120 m_pTopology = NULL;
121 m_tLastTopologyPoll = 0;
122 m_iPendingStatus = -1;
123 m_iPollCount = 0;
124 m_iRequiredPollCount = 0; // Use system default
125 }
126
127
128 //
129 // Node destructor
130 //
131
132 Node::~Node()
133 {
134 MutexDestroy(m_hPollerMutex);
135 MutexDestroy(m_hAgentAccessMutex);
136 MutexDestroy(m_mutexRTAccess);
137 MutexDestroy(m_mutexTopoAccess);
138 delete m_pAgentConnection;
139 safe_free(m_pParamList);
140 DestroyRoutingTable(m_pRoutingTable);
141 delete m_pTopology;
142 }
143
144
145 //
146 // Create object from database data
147 //
148
149 BOOL Node::CreateFromDB(DWORD dwId)
150 {
151 char szQuery[512];
152 DB_RESULT hResult;
153 int i, iNumRows;
154 DWORD dwSubnetId;
155 NetObj *pObject;
156 BOOL bResult = FALSE;
157
158 m_dwId = dwId;
159
160 if (!LoadCommonProperties())
161 {
162 DbgPrintf(2, "Cannot load common properties for node object %d", dwId);
163 return FALSE;
164 }
165
166 _sntprintf(szQuery, 512, "SELECT primary_ip,node_flags,"
167 "snmp_version,auth_method,secret,"
168 "agent_port,status_poll_type,community,snmp_oid,"
169 "node_type,agent_version,"
170 "platform_name,poller_node_id,zone_guid,"
171 "proxy_node,snmp_proxy,required_polls FROM nodes WHERE id=%d", dwId);
172 hResult = DBSelect(g_hCoreDB, szQuery);
173 if (hResult == 0)
174 return FALSE; // Query failed
175
176 if (DBGetNumRows(hResult) == 0)
177 {
178 DBFreeResult(hResult);
179 DbgPrintf(2, "Missing record in \"nodes\" table for node object %d", dwId);
180 return FALSE;
181 }
182
183 m_dwIpAddr = DBGetFieldIPAddr(hResult, 0, 0);
184 m_dwFlags = DBGetFieldULong(hResult, 0, 1);
185 m_iSNMPVersion = DBGetFieldLong(hResult, 0, 2);
186 m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 3);
187 DBGetField(hResult, 0, 4, m_szSharedSecret, MAX_SECRET_LENGTH);
188 DecodeSQLString(m_szSharedSecret);
189 m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 5);
190 m_iStatusPollType = DBGetFieldLong(hResult, 0, 6);
191 DBGetField(hResult, 0, 7, m_szCommunityString, MAX_COMMUNITY_LENGTH);
192 DecodeSQLString(m_szCommunityString);
193 DBGetField(hResult, 0, 8, m_szObjectId, MAX_OID_LEN * 4);
194 m_dwNodeType = DBGetFieldULong(hResult, 0, 9);
195 DBGetField(hResult, 0, 10, m_szAgentVersion, MAX_AGENT_VERSION_LEN);
196 DecodeSQLString(m_szAgentVersion);
197 DBGetField(hResult, 0, 11, m_szPlatformName, MAX_PLATFORM_NAME_LEN);
198 DecodeSQLString(m_szPlatformName);
199 m_dwPollerNode = DBGetFieldULong(hResult, 0, 12);
200 m_dwZoneGUID = DBGetFieldULong(hResult, 0, 13);
201 m_dwProxyNode = DBGetFieldULong(hResult, 0, 14);
202 m_dwSNMPProxy = DBGetFieldULong(hResult, 0, 15);
203 m_iRequiredPollCount = DBGetFieldLong(hResult, 0, 16);
204
205 DBFreeResult(hResult);
206
207 if (!m_bIsDeleted)
208 {
209 // Link node to subnets
210 sprintf(szQuery, "SELECT subnet_id FROM nsmap WHERE node_id=%d", dwId);
211 hResult = DBSelect(g_hCoreDB, szQuery);
212 if (hResult == NULL)
213 return FALSE; // Query failed
214
215 iNumRows = DBGetNumRows(hResult);
216 if (iNumRows == 0)
217 {
218 DBFreeResult(hResult);
219 DbgPrintf(3, "Unbound node object %d (%s)", dwId, m_szName);
220 return FALSE; // No parents - it shouldn't happen if database isn't corrupted
221 }
222
223 for(i = 0; i < iNumRows; i++)
224 {
225 dwSubnetId = DBGetFieldULong(hResult, i, 0);
226 pObject = FindObjectById(dwSubnetId);
227 if (pObject == NULL)
228 {
229 WriteLog(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
230 break;
231 }
232 else if (pObject->Type() != OBJECT_SUBNET)
233 {
234 WriteLog(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
235 break;
236 }
237 else
238 {
239 pObject->AddChild(this);
240 AddParent(pObject);
241 bResult = TRUE;
242 }
243 }
244
245 DBFreeResult(hResult);
246 LoadItemsFromDB();
247 LoadACLFromDB();
248
249 // Walk through all items in the node and load appropriate thresholds
250 for(i = 0; i < (int)m_dwNumItems; i++)
251 if (!m_ppItems[i]->LoadThresholdsFromDB())
252 {
253 DbgPrintf(3, "Cannot load thresholds for DCI %d of node %d (%s)",
254 m_ppItems[i]->Id(), dwId, m_szName);
255 bResult = FALSE;
256 }
257 }
258 else
259 {
260 bResult = TRUE;
261 }
262
263 return bResult;
264 }
265
266
267 //
268 // Save object to database
269 //
270
271 BOOL Node::SaveToDB(DB_HANDLE hdb)
272 {
273 TCHAR *pszEscVersion, *pszEscPlatform, *pszEscSecret;
274 TCHAR *pszEscCommunity, szQuery[4096], szIpAddr[16];
275 DB_RESULT hResult;
276 BOOL bNewObject = TRUE;
277 BOOL bResult;
278
279 // Lock object's access
280 LockData();
281
282 SaveCommonProperties(hdb);
283
284 // Check for object's existence in database
285 sprintf(szQuery, "SELECT id FROM nodes WHERE id=%d", m_dwId);
286 hResult = DBSelect(hdb, szQuery);
287 if (hResult != 0)
288 {
289 if (DBGetNumRows(hResult) > 0)
290 bNewObject = FALSE;
291 DBFreeResult(hResult);
292 }
293
294 // Form and execute INSERT or UPDATE query
295 pszEscVersion = EncodeSQLString(m_szAgentVersion);
296 pszEscPlatform = EncodeSQLString(m_szPlatformName);
297 pszEscSecret = EncodeSQLString(m_szSharedSecret);
298 pszEscCommunity = EncodeSQLString(m_szCommunityString);
299 if (bNewObject)
300 snprintf(szQuery, 4096,
301 "INSERT INTO nodes (id,primary_ip,"
302 "node_flags,snmp_version,community,status_poll_type,"
303 "agent_port,auth_method,secret,snmp_oid,proxy_node,"
304 "node_type,agent_version,platform_name,"
305 "poller_node_id,zone_guid,snmp_proxy,required_polls) VALUES "
306 "(%d,'%s',%d,%d,'%s',%d,%d,%d,'%s','%s',%d,%d,'%s','%s',%d,%d,%d,%d)",
307 m_dwId, IpToStr(m_dwIpAddr, szIpAddr), m_dwFlags,
308 m_iSNMPVersion, pszEscCommunity, m_iStatusPollType,
309 m_wAgentPort, m_wAuthMethod, pszEscSecret, m_szObjectId,
310 m_dwProxyNode, m_dwNodeType, pszEscVersion,
311 pszEscPlatform, m_dwPollerNode, m_dwZoneGUID,
312 m_dwSNMPProxy, m_iRequiredPollCount);
313 else
314 snprintf(szQuery, 4096,
315 "UPDATE nodes SET primary_ip='%s',"
316 "node_flags=%d,snmp_version=%d,community='%s',"
317 "status_poll_type=%d,agent_port=%d,auth_method=%d,secret='%s',"
318 "snmp_oid='%s',node_type=%d,"
319 "agent_version='%s',platform_name='%s',poller_node_id=%d,"
320 "zone_guid=%d,proxy_node=%d,snmp_proxy=%d,"
321 "required_polls=%d WHERE id=%d",
322 IpToStr(m_dwIpAddr, szIpAddr),
323 m_dwFlags, m_iSNMPVersion, pszEscCommunity,
324 m_iStatusPollType, m_wAgentPort, m_wAuthMethod, pszEscSecret,
325 m_szObjectId, m_dwNodeType,
326 pszEscVersion, pszEscPlatform, m_dwPollerNode, m_dwZoneGUID,
327 m_dwProxyNode, m_dwSNMPProxy, m_iRequiredPollCount, m_dwId);
328 bResult = DBQuery(hdb, szQuery);
329 free(pszEscVersion);
330 free(pszEscPlatform);
331 free(pszEscSecret);
332 free(pszEscCommunity);
333
334 // Save data collection items
335 if (bResult)
336 {
337 DWORD i;
338
339 for(i = 0; i < m_dwNumItems; i++)
340 m_ppItems[i]->SaveToDB(hdb);
341 }
342
343 // Save access list
344 SaveACLToDB(hdb);
345
346 // Clear modifications flag and unlock object
347 m_bIsModified = FALSE;
348 UnlockData();
349
350 return bResult;
351 }
352
353
354 //
355 // Delete object from database
356 //
357
358 BOOL Node::DeleteFromDB(void)
359 {
360 char szQuery[256];
361 BOOL bSuccess;
362
363 bSuccess = Template::DeleteFromDB();
364 if (bSuccess)
365 {
366 sprintf(szQuery, "DELETE FROM nodes WHERE id=%d", m_dwId);
367 QueueSQLRequest(szQuery);
368 sprintf(szQuery, "DELETE FROM nsmap WHERE node_id=%d", m_dwId);
369 QueueSQLRequest(szQuery);
370 sprintf(szQuery, "DROP TABLE idata_%d", m_dwId);
371 QueueSQLRequest(szQuery);
372 }
373 return bSuccess;
374 }
375
376
377 //
378 // Get ARP cache from node
379 //
380
381 ARP_CACHE *Node::GetArpCache(void)
382 {
383 ARP_CACHE *pArpCache = NULL;
384
385 if (m_dwFlags & NF_IS_LOCAL_MGMT)
386 {
387 pArpCache = GetLocalArpCache();
388 }
389 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
390 {
391 AgentLock();
392 if (ConnectToAgent())
393 pArpCache = m_pAgentConnection->GetArpCache();
394 AgentUnlock();
395 }
396 else if (m_dwFlags & NF_IS_SNMP)
397 {
398 SNMP_Transport *pTransport;
399
400 pTransport = CreateSNMPTransport();
401 pArpCache = SnmpGetArpCache(m_iSNMPVersion, pTransport,
402 m_szCommunityString);
403 delete pTransport;
404 }
405
406 return pArpCache;
407 }
408
409
410 //
411 // Get list of interfaces from node
412 //
413
414 INTERFACE_LIST *Node::GetInterfaceList(void)
415 {
416 INTERFACE_LIST *pIfList = NULL;
417
418 if (m_dwFlags & NF_IS_LOCAL_MGMT)
419 {
420 pIfList = GetLocalInterfaceList();
421 }
422 if ((pIfList == NULL) && (m_dwFlags & NF_IS_NATIVE_AGENT) &&
423 (!(m_dwFlags & NF_DISABLE_NXCP)))
424 {
425 AgentLock();
426 if (ConnectToAgent())
427 {
428 pIfList = m_pAgentConnection->GetInterfaceList();
429 CleanInterfaceList(pIfList);
430 }
431 AgentUnlock();
432 }
433 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP) &&
434 (!(m_dwFlags & NF_DISABLE_SNMP)))
435 {
436 SNMP_Transport *pTransport;
437
438 pTransport = CreateSNMPTransport();
439 pIfList = SnmpGetInterfaceList(m_iSNMPVersion, pTransport,
440 m_szCommunityString, m_dwNodeType);
441 delete pTransport;
442 }
443
444 if (pIfList != NULL)
445 CheckInterfaceNames(pIfList);
446
447 return pIfList;
448 }
449
450
451 //
452 // Find interface by index and node IP
453 // Returns pointer to interface object or NULL if appropriate interface couldn't be found
454 //
455
456 Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
457 {
458 DWORD i;
459 Interface *pInterface;
460
461 LockChildList(FALSE);
462 for(i = 0; i < m_dwChildCount; i++)
463 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
464 {
465 pInterface = (Interface *)m_pChildList[i];
466 if (pInterface->IfIndex() == dwIndex)
467 {
468 if (((pInterface->IpAddr() & pInterface->IpNetMask()) ==
469 (dwHostAddr & pInterface->IpNetMask())) ||
470 (dwHostAddr == INADDR_ANY))
471 {
472 UnlockChildList();
473 return pInterface;
474 }
475 }
476 }
477 UnlockChildList();
478 return NULL;
479 }
480
481
482 //
483 // Check if given IP address is one of node's interfaces
484 //
485
486 BOOL Node::IsMyIP(DWORD dwIpAddr)
487 {
488 DWORD i;
489
490 LockChildList(FALSE);
491 for(i = 0; i < m_dwChildCount; i++)
492 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
493 {
494 if (((Interface *)m_pChildList[i])->IpAddr() == dwIpAddr)
495 {
496 UnlockChildList();
497 return TRUE;
498 }
499 }
500 UnlockChildList();
501 return FALSE;
502 }
503
504
505 //
506 // Create new interface
507 //
508
509 void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName,
510 DWORD dwIndex, DWORD dwType, BYTE *pbMacAddr)
511 {
512 Interface *pInterface;
513 Subnet *pSubnet = NULL;
514 Cluster *pCluster;
515 BOOL bAddToSubnet, bSyntheticMask = FALSE;
516
517 // Find subnet to place interface object to
518 if (dwIpAddr != 0)
519 {
520 pCluster = GetMyCluster();
521 bAddToSubnet = (pCluster != NULL) ? !pCluster->IsSyncAddr(dwIpAddr) : TRUE;
522 if (bAddToSubnet)
523 {
524 pSubnet = FindSubnetForNode(dwIpAddr);
525 if (pSubnet == NULL)
526 {
527 // Check if netmask is 0 (detect), and if yes, create
528 // new subnet with class mask
529 if (dwNetMask == 0)
530 {
531 bSyntheticMask = TRUE;
532 if (dwIpAddr < 0xE0000000)
533 {
534 dwNetMask = 0xFFFFFF00; // Class A, B or C
535 }
536 else
537 {
538 TCHAR szBuffer[16];
539
540 // Multicast address??
541 DbgPrintf(2,
542 "Attempt to create interface object with multicast address %s",
543 IpToStr(dwIpAddr, szBuffer));
544 }
545 }
546
547 // Create new subnet object
548 if (dwIpAddr < 0xE0000000)
549 {
550 pSubnet = new Subnet(dwIpAddr & dwNetMask, dwNetMask, m_dwZoneGUID, bSyntheticMask);
551 NetObjInsert(pSubnet, TRUE);
552 g_pEntireNet->AddSubnet(pSubnet);
553 }
554 }
555 else
556 {
557 // Set correct netmask if we was asked for it
558 if (dwNetMask == 0)
559 {
560 dwNetMask = pSubnet->IpNetMask();
561 bSyntheticMask = pSubnet->IsSyntheticMask();
562 }
563 }
564 }
565 }
566
567 // Create interface object
568 if (szName != NULL)
569 pInterface = new Interface(szName, dwIndex, dwIpAddr, dwNetMask, dwType);
570 else
571 pInterface = new Interface(dwIpAddr, dwNetMask, bSyntheticMask);
572 if (pbMacAddr != NULL)
573 pInterface->SetMacAddr(pbMacAddr);
574
575 // Insert to objects' list and generate event
576 NetObjInsert(pInterface, TRUE);
577 AddInterface(pInterface);
578 if (!m_bIsHidden)
579 pInterface->Unhide();
580 PostEvent(EVENT_INTERFACE_ADDED, m_dwId, "dsaad", pInterface->Id(),
581 pInterface->Name(), pInterface->IpAddr(),
582 pInterface->IpNetMask(), pInterface->IfIndex());
583
584 // Bind node to appropriate subnet
585 if (pSubnet != NULL)
586 {
587 pSubnet->AddNode(this);
588
589 // Check if subnet mask is correct on interface
590 if ((pSubnet->IpNetMask() != pInterface->IpNetMask()) &&
591 (!pSubnet->IsSyntheticMask()))
592 {
593 PostEvent(EVENT_INCORRECT_NETMASK, m_dwId, "idsaa", pInterface->Id(),
594 pInterface->IfIndex(), pInterface->Name(),
595 pInterface->IpNetMask(), pSubnet->IpNetMask());
596 }
597 }
598 }
599
600
601 //
602 // Delete interface from node
603 //
604
605 void Node::DeleteInterface(Interface *pInterface)
606 {
607 DWORD i;
608
609 // Check if we should unlink node from interface's subnet
610 if (pInterface->IpAddr() != 0)
611 {
612 BOOL bUnlink = TRUE;
613
614 LockChildList(FALSE);
615 for(i = 0; i < m_dwChildCount; i++)
616 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
617 if (m_pChildList[i] != pInterface)
618 if ((((Interface *)m_pChildList[i])->IpAddr() & ((Interface *)m_pChildList[i])->IpNetMask()) ==
619 (pInterface->IpAddr() & pInterface->IpNetMask()))
620 {
621 bUnlink = FALSE;
622 break;
623 }
624 UnlockChildList();
625
626 if (bUnlink)
627 {
628 // Last interface in subnet, should unlink node
629 Subnet *pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
630 if (pSubnet != NULL)
631 {
632 DeleteParent(pSubnet);
633 pSubnet->DeleteChild(this);
634 }
635 }
636 }
637 pInterface->Delete(FALSE);
638 }
639
640
641 //
642 // Calculate node status based on child objects status
643 //
644
645 void Node::CalculateCompoundStatus(BOOL bForcedRecalc)
646 {
647 int iOldStatus = m_iStatus;
648 static DWORD dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_MINOR,
649 EVENT_NODE_WARNING, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
650 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
651
652 NetObj::CalculateCompoundStatus(bForcedRecalc);
653 if (m_iStatus != iOldStatus)
654 PostEvent(dwEventCodes[m_iStatus], m_dwId, "d", iOldStatus);
655 }
656
657
658 //
659 // Perform status poll on node
660 //
661
662 void Node::StatusPoll(ClientSession *pSession, DWORD dwRqId, int nPoller)
663 {
664 DWORD i, dwPollListSize, dwOldFlags = m_dwFlags;
665 NetObj *pPollerNode = NULL, **ppPollList;
666 BOOL bAllDown;
667 Queue *pQueue; // Delayed event queue
668 SNMP_Transport *pTransport;
669 Cluster *pCluster;
670 time_t tNow, tExpire;
671
672 pQueue = new Queue;
673 SetPollerInfo(nPoller, "wait for lock");
674 PollerLock();
675 m_pPollRequestor = pSession;
676 SendPollerMsg(dwRqId, "Starting status poll for node %s\r\n", m_szName);
677
678 // Read capability expiration time and current time
679 tExpire = (time_t)ConfigReadULong(_T("CapabilityExpirationTime"), 604800);
680 tNow = time(NULL);
681
682 // Check SNMP agent connectivity
683 if ((m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)))
684 {
685 TCHAR szBuffer[256];
686 DWORD dwResult;
687
688 pTransport = CreateSNMPTransport();
689 SetPollerInfo(nPoller, "check SNMP");
690 SendPollerMsg(dwRqId, "Checking SNMP agent connectivity\r\n");
691 dwResult = SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
692 ".1.3.6.1.2.1.1.2.0", NULL, 0, szBuffer, 256,
693 FALSE, FALSE);
694 if ((dwResult == SNMP_ERR_SUCCESS) || (dwResult == SNMP_ERR_NO_OBJECT))
695 {
696 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
697 {
698 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
699 PostEventEx(pQueue, EVENT_SNMP_OK, m_dwId, NULL);
700 SendPollerMsg(dwRqId, "\x7FiConnectivity with SNMP agent restored\r\n");
701 }
702 }
703 else
704 {
705 SendPollerMsg(dwRqId, "\x7F" "eSNMP agent unreachable\r\n");
706 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
707 {
708 if ((tNow > m_tFailTimeSNMP + tExpire) &&
709 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
710 {
711 m_dwFlags &= ~NF_IS_SNMP;
712 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
713 m_szObjectId[0] = 0;
714 SendPollerMsg(dwRqId, "\x7FwAttribute isSNMP set to FALSE\r\n");
715 }
716 }
717 else
718 {
719 m_dwDynamicFlags |= NDF_SNMP_UNREACHABLE;
720 PostEventEx(pQueue, EVENT_SNMP_FAIL, m_dwId, NULL);
721 m_tFailTimeSNMP = tNow;
722 }
723 }
724 delete pTransport;
725 }
726
727 // Check native agent connectivity
728 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)))
729 {
730 AgentConnection *pAgentConn;
731
732 SetPollerInfo(nPoller, "check agent");
733 SendPollerMsg(dwRqId, "Checking NetXMS agent connectivity\r\n");
734 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
735 m_wAuthMethod, m_szSharedSecret);
736 SetAgentProxy(pAgentConn);
737 if (pAgentConn->Connect(g_pServerKey))
738 {
739 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
740 {
741 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
742 PostEventEx(pQueue, EVENT_AGENT_OK, m_dwId, NULL);
743 SendPollerMsg(dwRqId, "\x7FiConnectivity with NetXMS agent restored\r\n");
744 }
745 pAgentConn->Disconnect();
746 }
747 else
748 {
749 SendPollerMsg(dwRqId, "\x7F" "eNetXMS agent unreachable\r\n");
750 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
751 {
752 if ((tNow > m_tFailTimeAgent + tExpire) &&
753 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
754 {
755 m_dwFlags &= ~NF_IS_NATIVE_AGENT;
756 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
757 m_szPlatformName[0] = 0;
758 m_szAgentVersion[0] = 0;
759 SendPollerMsg(dwRqId, "\x7FwAttribute isNetXMSAgent set to FALSE\r\n");
760 }
761 }
762 else
763 {
764 m_dwDynamicFlags |= NDF_AGENT_UNREACHABLE;
765 PostEventEx(pQueue, EVENT_AGENT_FAIL, m_dwId, NULL);
766 m_tFailTimeAgent = tNow;
767 }
768 }
769 delete pAgentConn;
770 }
771
772 SetPollerInfo(nPoller, "prepare polling list");
773
774 // Find service poller node object
775 LockData();
776 if (m_dwPollerNode != 0)
777 {
778 pPollerNode = FindObjectById(m_dwPollerNode);
779 if (pPollerNode != NULL)
780 {
781 if (pPollerNode->Type() != OBJECT_NODE)
782 pPollerNode = NULL;
783 }
784 }
785 UnlockData();
786
787 // If nothing found, use management server
788 if (pPollerNode == NULL)
789 {
790 pPollerNode = FindObjectById(g_dwMgmtNode);
791 if (pPollerNode != NULL)
792 pPollerNode->IncRefCount();
793 }
794 else
795 {
796 pPollerNode->IncRefCount();
797 }
798
799 // Create polling list
800 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_dwChildCount);
801 LockChildList(FALSE);
802 for(i = 0, dwPollListSize = 0; i < m_dwChildCount; i++)
803 if (m_pChildList[i]->Status() != STATUS_UNMANAGED)
804 {
805 m_pChildList[i]->IncRefCount();
806 ppPollList[dwPollListSize++] = m_pChildList[i];
807 }
808 UnlockChildList();
809
810 // Poll interfaces and services
811 SetPollerInfo(nPoller, "child poll");
812 pCluster = GetMyCluster();
813 pTransport = CreateSNMPTransport();
814 for(i = 0; i < dwPollListSize; i++)
815 {
816 switch(ppPollList[i]->Type())
817 {
818 case OBJECT_INTERFACE:
819 ((Interface *)ppPollList[i])->StatusPoll(pSession, dwRqId, pQueue,
820 (pCluster != NULL) ? pCluster->IsSyncAddr(((Interface *)ppPollList[i])->IpAddr()) : FALSE,
821 pTransport);
822 break;
823 case OBJECT_NETWORKSERVICE:
824 ((NetworkService *)ppPollList[i])->StatusPoll(pSession, dwRqId,
825 (Node *)pPollerNode, pQueue);
826 break;
827 default:
828 break;
829 }
830 ppPollList[i]->DecRefCount();
831 }
832 delete pTransport;
833 safe_free(ppPollList);
834
835 // Check if entire node is down
836 LockChildList(FALSE);
837 for(i = 0, bAllDown = TRUE; i < m_dwChildCount; i++)
838 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
839 (m_pChildList[i]->Status() != STATUS_CRITICAL) &&
840 (m_pChildList[i]->Status() != STATUS_UNKNOWN) &&
841 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
842 (m_pChildList[i]->Status() != STATUS_DISABLED))
843 {
844 bAllDown = FALSE;
845 break;
846 }
847 UnlockChildList();
848 if (bAllDown && (m_dwFlags & NF_IS_NATIVE_AGENT) &&
849 (!(m_dwFlags & NF_DISABLE_NXCP)))
850 if (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))
851 bAllDown = FALSE;
852 if (bAllDown && (m_dwFlags & NF_IS_SNMP) &&
853 (!(m_dwFlags & NF_DISABLE_SNMP)))
854 if (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))
855 bAllDown = FALSE;
856 if (bAllDown)
857 {
858 if (!(m_dwDynamicFlags & NDF_UNREACHABLE))
859 {
860 m_dwDynamicFlags |= NDF_UNREACHABLE;
861 PostEvent(EVENT_NODE_DOWN, m_dwId, NULL);
862 SendPollerMsg(dwRqId, "\x7F" "eNode is unreachable\r\n");
863 }
864 else
865 {
866 SendPollerMsg(dwRqId, "\x7FwNode is still unreachable\r\n");
867 }
868 }
869 else
870 {
871 if (m_dwDynamicFlags & NDF_UNREACHABLE)
872 {
873 m_dwDynamicFlags &= ~NDF_UNREACHABLE;
874 PostEvent(EVENT_NODE_UP, m_dwId, NULL);
875 SendPollerMsg(dwRqId, "\x7FiNode recovered from unreachable state\r\n");
876 }
877 else
878 {
879 SendPollerMsg(dwRqId, "\x7FiNode is connected\r\n");
880 }
881 }
882
883 // Send delayed events and destroy delayed event queue
884 ResendEvents(pQueue);
885 delete pQueue;
886
887 SetPollerInfo(nPoller, "cleanup");
888 if (pPollerNode != NULL)
889 pPollerNode->DecRefCount();
890
891 if (dwOldFlags != m_dwFlags)
892 {
893 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
894 LockData();
895 Modify();
896 UnlockData();
897 }
898
899 CalculateCompoundStatus();
900 m_tLastStatusPoll = time(NULL);
901 SendPollerMsg(dwRqId, "Finished status poll for node %s\r\n"
902 "Node status after poll is %s\r\n", m_szName, g_szStatusTextSmall[m_iStatus]);
903 m_pPollRequestor = NULL;
904 if (dwRqId == 0)
905 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_STATUS_POLL;
906 PollerUnlock();
907 }
908
909
910 //
911 // Perform configuration poll on node
912 //
913
914 void Node::ConfigurationPoll(ClientSession *pSession, DWORD dwRqId,
915 int nPoller, DWORD dwNetMask)
916 {
917 DWORD i, dwOldFlags = m_dwFlags, dwAddr;
918 Interface **ppDeleteList;
919 int j, iDelCount;
920 AgentConnection *pAgentConn;
921 INTERFACE_LIST *pIfList;
922 char szBuffer[4096];
923 Cluster *pCluster;
924 SNMP_Transport *pTransport;
925 Template *pTemplate;
926 BOOL bHasChanges = FALSE;
927
928 SetPollerInfo(nPoller, "wait for lock");
929 PollerLock();
930 m_pPollRequestor = pSession;
931 SendPollerMsg(dwRqId, _T("Starting configuration poll for node %s\r\n"), m_szName);
932 DbgPrintf(4, "Starting configuration poll for node %s (ID: %d)", m_szName, m_dwId);
933
934 // Check for forced capabilities recheck
935 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
936 {
937 m_dwFlags &= ~(NF_IS_NATIVE_AGENT | NF_IS_SNMP | NF_IS_CPSNMP |
938 NF_IS_BRIDGE | NF_IS_ROUTER | NF_IS_OSPF);
939 m_szObjectId[0] = 0;
940 m_szPlatformName[0] = 0;
941 m_szAgentVersion[0] = 0;
942 m_szSysDescription[0] = 0;
943 }
944
945 // Check if node is marked as unreachable
946 if ((m_dwDynamicFlags & NDF_UNREACHABLE) && !(m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES))
947 {
948 SendPollerMsg(dwRqId, _T("\x7FwNode is marked as unreachable, configuration poll aborted\r\n"));
949 DbgPrintf(4, "Node is marked as unreachable, configuration poll aborted");
950 m_tLastConfigurationPoll = time(NULL);
951 }
952 else
953 {
954 // Check node's capabilities
955 SetPollerInfo(nPoller, "capability check");
956 SendPollerMsg(dwRqId, _T("Checking node's capabilities...\r\n"));
957 if ((!((m_dwFlags & NF_IS_SNMP) && (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))) &&
958 (!(m_dwFlags & NF_DISABLE_SNMP)))
959 {
960 DbgPrintf(5, "ConfPoll(%s): trying SNMP GET", m_szName);
961 pTransport = CreateSNMPTransport();
962
963 strcpy(szBuffer, m_szCommunityString);
964 if (SnmpCheckCommSettings(pTransport, szBuffer, &m_iSNMPVersion, m_szCommunityString))
965 {
966 DWORD dwNodeFlags, dwNodeType;
967
968 LockData();
969
970 m_dwFlags |= NF_IS_SNMP;
971 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
972 {
973 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
974 PostEvent(EVENT_SNMP_OK, m_dwId, NULL);
975 SendPollerMsg(dwRqId, " \x7FiConnectivity with SNMP agent restored\r\n");
976 }
977 SendPollerMsg(dwRqId, _T(" SNMP agent is active (version %s)\r\n"), (m_iSNMPVersion == SNMP_VERSION_2C) ? _T("2c") : _T("1"));
978
979 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
980 ".1.3.6.1.2.1.1.2.0", NULL, 0, szBuffer, 4096,
981 FALSE, FALSE) == SNMP_ERR_SUCCESS)
982 {
983 if (strcmp(m_szObjectId, szBuffer))
984 {
985 nx_strncpy(m_szObjectId, szBuffer, MAX_OID_LEN * 4);
986 bHasChanges = TRUE;
987 }
988 }
989
990 // Check node type
991 dwNodeType = OidToType(m_szObjectId, &dwNodeFlags);
992 if (m_dwNodeType != dwNodeType)
993 {
994 m_dwFlags |= dwNodeFlags;
995 m_dwNodeType = dwNodeType;
996 SendPollerMsg(dwRqId, _T(" \x7FwNode type has been changed to %d\r\n"), m_dwNodeType);
997 bHasChanges = TRUE;
998 }
999
1000 // Check IP forwarding
1001 if (CheckSNMPIntegerValue(pTransport, ".1.3.6.1.2.1.4.1.0", 1))
1002 {
1003 m_dwFlags |= NF_IS_ROUTER;
1004 }
1005 else
1006 {
1007 m_dwFlags &= ~NF_IS_ROUTER;
1008 }
1009
1010 // Check for bridge MIB support
1011 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1012 ".1.3.6.1.2.1.17.1.1.0", NULL, 0, szBuffer, 4096,
1013 FALSE, FALSE) == SNMP_ERR_SUCCESS)
1014 {
1015 m_dwFlags |= NF_IS_BRIDGE;
1016 }
1017 else
1018 {
1019 m_dwFlags &= ~NF_IS_BRIDGE;
1020 }
1021
1022 // Check for CDP (Cisco Discovery Protocol) support
1023 if (CheckSNMPIntegerValue(pTransport, ".1.3.6.1.4.1.9.9.23.1.3.1.0", 1))
1024 {
1025 m_dwFlags |= NF_IS_CDP;
1026 }
1027 else
1028 {
1029 m_dwFlags &= ~NF_IS_CDP;
1030 }
1031
1032 // Check for SONMP (Nortel topology discovery discovery protocol) support
1033 if (CheckSNMPIntegerValue(pTransport, ".1.3.6.1.4.1.45.1.6.13.1.2.0", 1))
1034 {
1035 m_dwFlags |= NF_IS_SONMP;
1036 }
1037 else
1038 {
1039 m_dwFlags &= ~NF_IS_SONMP;
1040 }
1041
1042 // Check for LLDP (Link Layer Discovery Protocol) support
1043 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1044 ".1.0.8802.1.1.2.1.3.2.0", NULL, 0, szBuffer, 4096,
1045 FALSE, FALSE) == SNMP_ERR_SUCCESS)
1046 {
1047 m_dwFlags |= NF_IS_LLDP;
1048 }
1049 else
1050 {
1051 m_dwFlags &= ~NF_IS_LLDP;
1052 }
1053
1054 UnlockData();
1055
1056 CheckOSPFSupport(pTransport);
1057 }
1058 else
1059 {
1060 // Check for CheckPoint SNMP agent on port 161
1061 DbgPrintf(5, "ConfPoll(%s): checking for CheckPoint SNMP", m_szName);
1062 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1063 ".1.3.6.1.4.1.2620.1.1.10.0", NULL, 0,
1064 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
1065 {
1066 LockData();
1067 if (strcmp(m_szObjectId, ".1.3.6.1.4.1.2620.1.1"))
1068 {
1069 nx_strncpy(m_szObjectId, ".1.3.6.1.4.1.2620.1.1", MAX_OID_LEN * 4);
1070 bHasChanges = TRUE;
1071 }
1072
1073 m_dwFlags |= NF_IS_SNMP | NF_IS_ROUTER;
1074 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
1075 UnlockData();
1076 SendPollerMsg(dwRqId, _T(" \x7FiCheckPoint SNMP agent on port 161 is active\r\n"));
1077 }
1078 }
1079 delete pTransport;
1080 }
1081
1082 // Check for CheckPoint SNMP agent on port 260
1083 DbgPrintf(5, "ConfPoll(%s): checking for CheckPoint SNMP on port 260", m_szName);
1084 if (!((m_dwFlags & NF_IS_CPSNMP) && (m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE)))
1085 {
1086 pTransport = new SNMP_UDPTransport;
1087 ((SNMP_UDPTransport *)pTransport)->CreateUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
1088 if (SnmpGet(SNMP_VERSION_1, pTransport, m_szCommunityString,
1089 ".1.3.6.1.4.1.2620.1.1.10.0", NULL, 0,
1090 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
1091 {
1092 LockData();
1093 m_dwFlags |= NF_IS_CPSNMP | NF_IS_ROUTER;
1094 m_dwDynamicFlags &= ~NDF_CPSNMP_UNREACHABLE;
1095 UnlockData();
1096 SendPollerMsg(dwRqId, _T(" \x7FiCheckPoint SNMP agent on port 260 is active\r\n"));
1097 }
1098 delete pTransport;
1099 }
1100
1101 DbgPrintf(5, "ConfPoll(%s): checking for NetXMS agent Flags={%08X} DynamicFlags={%08X}", m_szName, m_dwFlags, m_dwDynamicFlags);
1102 if ((!((m_dwFlags & NF_IS_NATIVE_AGENT) && (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))) &&
1103 (!(m_dwFlags & NF_DISABLE_NXCP)))
1104 {
1105 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
1106 m_wAuthMethod, m_szSharedSecret);
1107 SetAgentProxy(pAgentConn);
1108 DbgPrintf(5, "ConfPoll(%s): checking for NetXMS agent - connecting", m_szName);
1109 if (pAgentConn->Connect(g_pServerKey))
1110 {
1111 DbgPrintf(5, "ConfPoll(%s): checking for NetXMS agent - connected", m_szName);
1112 LockData();
1113 m_dwFlags |= NF_IS_NATIVE_AGENT;
1114 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1115 {
1116 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1117 PostEvent(EVENT_AGENT_OK, m_dwId, NULL);
1118 SendPollerMsg(dwRqId, _T(" \x7FiConnectivity with NetXMS agent restored\r\n"));
1119 }
1120 UnlockData();
1121
1122 if (pAgentConn->GetParameter("Agent.Version", MAX_AGENT_VERSION_LEN, szBuffer) == ERR_SUCCESS)
1123 {
1124 LockData();
1125 if (strcmp(m_szAgentVersion, szBuffer))
1126 {
1127 strcpy(m_szAgentVersion, szBuffer);
1128 bHasChanges = TRUE;
1129 SendPollerMsg(dwRqId, _T(" NetXMS agent version changed to %s\r\n"), m_szAgentVersion);
1130 }
1131 UnlockData();
1132 }
1133
1134 if (pAgentConn->GetParameter("System.PlatformName", MAX_PLATFORM_NAME_LEN, szBuffer) == ERR_SUCCESS)
1135 {
1136 LockData();
1137 if (strcmp(m_szPlatformName, szBuffer))
1138 {
1139 strcpy(m_szPlatformName, szBuffer);
1140 bHasChanges = TRUE;
1141 SendPollerMsg(dwRqId, _T(" Platform name changed to %s\r\n"), m_szPlatformName);
1142 }
1143 UnlockData();
1144 }
1145
1146 // Check IP forwarding status
1147 if (pAgentConn->GetParameter("Net.IP.Forwarding", 16, szBuffer) == ERR_SUCCESS)
1148 {
1149 if (_tcstoul(szBuffer, NULL, 10) != 0)
1150 m_dwFlags |= NF_IS_ROUTER;
1151 else
1152 m_dwFlags &= ~NF_IS_ROUTER;
1153 }
1154
1155 /* LOCK? */
1156 safe_free(m_pParamList);
1157 pAgentConn->GetSupportedParameters(&m_dwNumParams, &m_pParamList);
1158
1159 pAgentConn->Disconnect();
1160 SendPollerMsg(dwRqId, _T(" \x7FiNetXMS native agent is active\r\n"));
1161 }
1162 delete pAgentConn;
1163 DbgPrintf(5, "ConfPoll(%s): checking for NetXMS agent - finished", m_szName);
1164 }
1165
1166 // Generate event if node flags has been changed
1167 if (dwOldFlags != m_dwFlags)
1168 {
1169 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
1170 bHasChanges = TRUE;
1171 }
1172
1173 // Get parent cluster object, if any
1174 pCluster = GetMyCluster();
1175
1176 // Retrieve interface list
1177 SetPollerInfo(nPoller, "interface check");
1178 SendPollerMsg(dwRqId, _T("Capability check finished\r\n"
1179 "Checking interface configuration...\r\n"));
1180 pIfList = GetInterfaceList();
1181 if (pIfList != NULL)
1182 {
1183 // Remove cluster virtual interfaces from list
1184 if (pCluster != NULL)
1185 {
1186 for(i = 0; i < (DWORD)pIfList->iNumEntries; i++)
1187 {
1188 if (pCluster->IsVirtualAddr(pIfList->pInterfaces[i].dwIpAddr))
1189 {
1190 pIfList->iNumEntries--;
1191 memmove(&pIfList->pInterfaces[i], &pIfList->pInterfaces[i + 1],
1192 sizeof(INTERFACE_INFO) * (pIfList->iNumEntries - i));
1193 i--;
1194 }
1195 }
1196 }
1197
1198 // Find non-existing interfaces
1199 LockChildList(FALSE);
1200 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
1201 for(i = 0, iDelCount = 0; i < m_dwChildCount; i++)
1202 {
1203 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1204 {
1205 Interface *pInterface = (Interface *)m_pChildList[i];
1206
1207 if (pInterface->IfType() != IFTYPE_NETXMS_NAT_ADAPTER)
1208 {
1209 for(j = 0; j < pIfList->iNumEntries; j++)
1210 {
1211 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
1212 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
1213 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
1214 break;
1215 }
1216
1217 if (j == pIfList->iNumEntries)
1218 {
1219 // No such interface in current configuration, add it to delete list
1220 ppDeleteList[iDelCount++] = pInterface;
1221 }
1222 }
1223 }
1224 }
1225 UnlockChildList();
1226
1227 // Delete non-existent interfaces
1228 if (iDelCount > 0)
1229 {
1230 for(j = 0; j < iDelCount; j++)
1231 {
1232 SendPollerMsg(dwRqId, _T(" \x7FwInterface \"%s\" is no longer exist\r\n"),
1233 ppDeleteList[j]->Name());
1234 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->IfIndex(),
1235 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->IpNetMask());
1236 DeleteInterface(ppDeleteList[j]);
1237 }
1238 bHasChanges = TRUE;
1239 }
1240 safe_free(ppDeleteList);
1241
1242 // Add new interfaces and check configuration of existing
1243 for(j = 0; j < pIfList->iNumEntries; j++)
1244 {
1245 BOOL bNewInterface = TRUE;
1246
1247 LockChildList(FALSE);
1248 for(i = 0; i < m_dwChildCount; i++)
1249 {
1250 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1251 {
1252 Interface *pInterface = (Interface *)m_pChildList[i];
1253
1254 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
1255 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
1256 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
1257 {
1258 // Existing interface, check configuration
1259 if (memcmp(pIfList->pInterfaces[j].bMacAddr, pInterface->MacAddr(), MAC_ADDR_LENGTH))
1260 {
1261 char szOldMac[16], szNewMac[16];
1262
1263 BinToStr((BYTE *)pInterface->MacAddr(), MAC_ADDR_LENGTH, szOldMac);
1264 BinToStr(pIfList->pInterfaces[j].bMacAddr, MAC_ADDR_LENGTH, szNewMac);
1265 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
1266 pInterface->Id(), pInterface->IfIndex(),
1267 pInterface->Name(), szOldMac, szNewMac);
1268 pInterface->SetMacAddr(pIfList->pInterfaces[j].bMacAddr);
1269 }
1270 if (strcmp(pIfList->pInterfaces[j].szName, pInterface->Name()))
1271 {
1272 pInterface->SetName(pIfList->pInterfaces[j].szName);
1273 }
1274 bNewInterface = FALSE;
1275 break;
1276 }
1277 }
1278 }
1279 UnlockChildList();
1280
1281 if (bNewInterface)
1282 {
1283 // New interface
1284 SendPollerMsg(dwRqId, _T(" \x7FiFound new interface \"%s\"\r\n"),
1285 pIfList->pInterfaces[j].szName);
1286 CreateNewInterface(pIfList->pInterfaces[j].dwIpAddr,
1287 pIfList->pInterfaces[j].dwIpNetMask,
1288 pIfList->pInterfaces[j].szName,
1289 pIfList->pInterfaces[j].dwIndex,
1290 pIfList->pInterfaces[j].dwType,
1291 pIfList->pInterfaces[j].bMacAddr);
1292 bHasChanges = TRUE;
1293 }
1294 }
1295
1296 // Check if address we are using to communicate with node
1297 // is configured on one of node's interfaces
1298 for(i = 0; i < (DWORD)pIfList->iNumEntries; i++)
1299 if (pIfList->pInterfaces[i].dwIpAddr == m_dwIpAddr)
1300 break;
1301
1302 if (i == (DWORD)pIfList->iNumEntries)
1303 {
1304 BOOL bCreate = TRUE;
1305
1306 // Node is behind NAT
1307 m_dwFlags |= NF_BEHIND_NAT;
1308
1309 // Check if we already have NAT interface
1310 LockChildList(FALSE);
1311 for(i = 0; i < m_dwChildCount; i++)
1312 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1313 {
1314 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1315 {
1316 bCreate = FALSE;
1317 break;
1318 }
1319 }
1320 UnlockChildList();
1321
1322 if (bCreate)
1323 {
1324 char szBuffer[MAX_OBJECT_NAME];
1325
1326 // Create pseudo interface for NAT
1327 ConfigReadStr("NATAdapterName", szBuffer, MAX_OBJECT_NAME, "NetXMS NAT Adapter");
1328 CreateNewInterface(m_dwIpAddr, 0, szBuffer,
1329 0x7FFFFFFF, IFTYPE_NETXMS_NAT_ADAPTER);
1330 bHasChanges = TRUE;
1331 }
1332 }
1333 else
1334 {
1335 // Check if NF_BEHIND_NAT flag set incorrectly
1336 if (m_dwFlags & NF_BEHIND_NAT)
1337 {
1338 Interface *pIfNat;
1339
1340 // Remove NAT interface
1341 LockChildList(FALSE);
1342 for(i = 0, pIfNat = NULL; i < m_dwChildCount; i++)
1343 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1344 {
1345 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1346 {
1347 pIfNat = (Interface *)m_pChildList[i];
1348 break;
1349 }
1350 }
1351 UnlockChildList();
1352
1353 if (pIfNat != NULL)
1354 DeleteInterface(pIfNat);
1355
1356 m_dwFlags &= ~NF_BEHIND_NAT;
1357 bHasChanges = TRUE;
1358 }
1359 }
1360
1361 CheckSubnetBinding(pIfList);
1362
1363 DestroyInterfaceList(pIfList);
1364 }
1365 else /* pIfList == NULL */
1366 {
1367 Interface *pInterface;
1368 DWORD dwCount;
1369
1370 SendPollerMsg(dwRqId, _T(" \x7F") _T("eUnable to get interface list from node\r\n"));
1371
1372 // Delete all existing interfaces in case of forced capability recheck
1373 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
1374 {
1375 LockChildList(FALSE);
1376 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
1377 for(i = 0, iDelCount = 0; i < m_dwChildCount; i++)
1378 {
1379 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1380 ppDeleteList[iDelCount++] = (Interface *)m_pChildList[i];
1381 }
1382 UnlockChildList();
1383 for(j = 0; j < iDelCount; j++)
1384 {
1385 SendPollerMsg(dwRqId, _T(" \x7FwInterface \"%s\" is no longer exist\r\n"),
1386 ppDeleteList[j]->Name());
1387 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->IfIndex(),
1388 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->IpNetMask());
1389 DeleteInterface(ppDeleteList[j]);
1390 }
1391 safe_free(ppDeleteList);
1392 }
1393
1394 // Check if we have pseudo-interface object
1395 dwCount = GetInterfaceCount(&pInterface);
1396 if (dwCount == 1)
1397 {
1398 if (pInterface->IsFake())
1399 {
1400 // Check if primary IP is different from interface's IP
1401 if (pInterface->IpAddr() != m_dwIpAddr)
1402 {
1403 DeleteInterface(pInterface);
1404 CreateNewInterface(m_dwIpAddr, dwNetMask);
1405 }
1406 }
1407 }
1408 else if (dwCount == 0)
1409 {
1410 // No interfaces at all, create pseudo-interface
1411 CreateNewInterface(m_dwIpAddr, dwNetMask);
1412 }
1413 }
1414
1415 m_tLastConfigurationPoll = time(NULL);
1416 SendPollerMsg(dwRqId, _T("Interface configuration check finished\r\n"));
1417
1418 // Check node name
1419 SendPollerMsg(dwRqId, _T("Checking node name\r\n"));
1420 dwAddr = ntohl(_t_inet_addr(m_szName));
1421 if ((g_dwFlags & AF_RESOLVE_NODE_NAMES) &&
1422 (dwAddr != INADDR_NONE) &&
1423 (dwAddr != INADDR_ANY) &&
1424 IsMyIP(dwAddr))
1425 {
1426 SendPollerMsg(dwRqId, _T("Node name is an IP address and need to be resolved\r\n"));
1427 SetPollerInfo(nPoller, "resolving name");
1428 if (ResolveName(FALSE))
1429 {
1430 SendPollerMsg(dwRqId, _T("\x7FiNode name resolved to %s\r\n"), m_szName);
1431 bHasChanges = TRUE;
1432 }
1433 else
1434 {
1435 SendPollerMsg(dwRqId, _T("\x7FwNode name cannot be resolved\r\n"));
1436 }
1437 }
1438 else
1439 {
1440 if (g_dwFlags & AF_SYNC_NODE_NAMES_WITH_DNS)
1441 {
1442 SendPollerMsg(dwRqId, _T("Syncing node name with DNS\r\n"));
1443 SetPollerInfo(nPoller, "resolving name");
1444 if (ResolveName(TRUE))
1445 {
1446 SendPollerMsg(dwRqId, _T("\x7FiNode name resolved to %s\r\n"), m_szName);
1447 bHasChanges = TRUE;
1448 }
1449 }
1450 else
1451 {
1452 SendPollerMsg(dwRqId, _T("Node name is OK\r\n"));
1453 }
1454 }
1455
1456 // Apply system templates
1457 pTemplate = FindTemplateByName(_T("@System.Agent"));
1458 if (pTemplate != NULL)
1459 {
1460 if (IsNativeAgent())
1461 {
1462 if (!pTemplate->IsChild(m_dwId))
1463 {
1464 pTemplate->ApplyToNode(this);
1465 }
1466 }
1467 else
1468 {
1469 if (pTemplate->IsChild(m_dwId))
1470 {
1471 pTemplate->DeleteChild(this);
1472 DeleteParent(pTemplate);
1473 pTemplate->QueueRemoveFromNode(m_dwId, TRUE);
1474 }
1475 }
1476 }
1477
1478 pTemplate = FindTemplateByName(_T("@System.SNMP"));
1479 if (pTemplate != NULL)
1480 {
1481 if (IsSNMPSupported())
1482 {
1483 if (!pTemplate->IsChild(m_dwId))
1484 {
1485 pTemplate->ApplyToNode(this);
1486 }
1487 }
1488 else
1489 {
1490 if (pTemplate->IsChild(m_dwId))
1491 {
1492 pTemplate->DeleteChild(this);
1493 DeleteParent(pTemplate);
1494 pTemplate->QueueRemoveFromNode(m_dwId, TRUE);
1495 }
1496 }
1497 }
1498
1499 SendPollerMsg(dwRqId, _T("Finished configuration poll for node %s\r\n")
1500 _T("Node configuration was%schanged after poll\r\n"),
1501 m_szName, bHasChanges ? _T(" ") : _T(" not "));
1502 }
1503
1504 // Finish configuration poll
1505 SetPollerInfo(nPoller, "cleanup");
1506 if (dwRqId == 0)
1507 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1508 m_dwDynamicFlags &= ~NDF_RECHECK_CAPABILITIES;
1509 PollerUnlock();
1510 DbgPrintf(4, "Finished configuration poll for node %s (ID: %d)", m_szName, m_dwId);
1511
1512 if (bHasChanges)
1513 {
1514 LockData();
1515 Modify();
1516 UnlockData();
1517 }
1518 }
1519
1520
1521 //
1522 // Connect to native agent
1523 //
1524
1525 BOOL Node::ConnectToAgent(void)
1526 {
1527 BOOL bRet;
1528
1529 // Create new agent connection object if needed
1530 if (m_pAgentConnection == NULL)
1531 m_pAgentConnection = new AgentConnectionEx(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
1532
1533 // Check if we already connected
1534 if (m_pAgentConnection->Nop() == ERR_SUCCESS)
1535 return TRUE;
1536
1537 // Close current connection or clean up after broken connection
1538 m_pAgentConnection->Disconnect();
1539 m_pAgentConnection->SetPort(m_wAgentPort);
1540 m_pAgentConnection->SetAuthData(m_wAuthMethod, m_szSharedSecret);
1541 SetAgentProxy(m_pAgentConnection);
1542 bRet = m_pAgentConnection->Connect(g_pServerKey);
1543 if (bRet)
1544 {
1545 m_pAgentConnection->SetCommandTimeout(g_dwAgentCommandTimeout);
1546 m_pAgentConnection->EnableTraps();
1547 }
1548 return bRet;
1549 }
1550
1551
1552 //
1553 // Get item's value via SNMP
1554 //
1555
1556 DWORD Node::GetItemFromSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1557 {
1558 DWORD dwResult;
1559
1560 if ((m_dwDynamicFlags & NDF_SNMP_UNREACHABLE) ||
1561 (m_dwDynamicFlags & NDF_UNREACHABLE))
1562 {
1563 dwResult = SNMP_ERR_COMM;
1564 }
1565 else
1566 {
1567 SNMP_Transport *pTransport;
1568
1569 pTransport = CreateSNMPTransport();
1570 dwResult = SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
1571 szParam, NULL, 0, szBuffer, dwBufSize, FALSE, TRUE);
1572 delete pTransport;
1573 }
1574 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
1575 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
1576 }
1577
1578
1579 //
1580 // Get item's value via SNMP from CheckPoint's agent
1581 //
1582
1583 DWORD Node::GetItemFromCheckPointSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1584 {
1585 DWORD dwResult;
1586
1587 if ((m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE) ||
1588 (m_dwDynamicFlags & NDF_UNREACHABLE))
1589 {
1590 dwResult = SNMP_ERR_COMM;
1591 }
1592 else
1593 {
1594 SNMP_Transport *pTransport;
1595
1596 pTransport = new SNMP_UDPTransport;
1597 ((SNMP_UDPTransport *)pTransport)->CreateUDPTransport(NULL, htonl(m_dwIpAddr), CHECKPOINT_SNMP_PORT);
1598 dwResult = SnmpGet(SNMP_VERSION_1, pTransport,
1599 m_szCommunityString, szParam, NULL, 0, szBuffer,
1600 dwBufSize, FALSE, TRUE);
1601 delete pTransport;
1602 }
1603 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
1604 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
1605 }
1606
1607
1608 //
1609 // Get item's value via native agent
1610 //
1611
1612 DWORD Node::GetItemFromAgent(const char *szParam, DWORD dwBufSize, char *szBuffer)
1613 {
1614 DWORD dwError, dwResult = DCE_COMM_ERROR;
1615 DWORD dwTries = 3;
1616
1617 if ((m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
1618 (m_dwDynamicFlags & NDF_UNREACHABLE))
1619 return DCE_COMM_ERROR;
1620
1621 AgentLock();
1622
1623 // Establish connection if needed
1624 if (m_pAgentConnection == NULL)
1625 if (!ConnectToAgent())
1626 goto end_loop;
1627
1628 // Get parameter from agent
1629 while(dwTries-- > 0)
1630 {
1631 dwError = m_pAgentConnection->GetParameter((char *)szParam, dwBufSize, szBuffer);
1632 switch(dwError)
1633 {
1634 case ERR_SUCCESS:
1635 dwResult = DCE_SUCCESS;
1636 goto end_loop;
1637 case ERR_UNKNOWN_PARAMETER:
1638 dwResult = DCE_NOT_SUPPORTED;
1639 goto end_loop;
1640 case ERR_NOT_CONNECTED:
1641 case ERR_CONNECTION_BROKEN:
1642 if (!ConnectToAgent())
1643 goto end_loop;
1644 break;
1645 case ERR_REQUEST_TIMEOUT:
1646 // Reset connection to agent after timeout
1647 DbgPrintf(6, _T("Node(%s)->GetItemFromAgent(%s): timeout; resetting connection to agent..."), m_szName, szParam);
1648 delete_and_null(m_pAgentConnection);
1649 if (!ConnectToAgent())
1650 goto end_loop;
1651 DbgPrintf(6, _T("Node(%s)->GetItemFromAgent(%s): connection to agent restored successfully"), m_szName, szParam);
1652 break;
1653 }
1654 }
1655
1656 end_loop:
1657 AgentUnlock();
1658 DbgPrintf(6, "Node(%s)->GetItemFromAgent(%s): dwError=%d dwResult=%d",
1659 m_szName, szParam, dwError, dwResult);
1660 return dwResult;
1661 }
1662
1663
1664 //
1665 // Get value for server's internal parameter
1666 //
1667
1668 DWORD Node::GetInternalItem(const char *szParam, DWORD dwBufSize, char *szBuffer)
1669 {
1670 DWORD dwError = DCE_SUCCESS;
1671
1672 if (!stricmp(szParam, "status"))
1673 {
1674 sprintf(szBuffer, "%d", m_iStatus);
1675 }
1676 else if (!stricmp(szParam, "AgentStatus"))
1677 {
1678 if (m_dwFlags & NF_IS_NATIVE_AGENT)
1679 {
1680 szBuffer[0] = (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ? '1' : '0';
1681 szBuffer[1] = 0;
1682 }
1683 else
1684 {
1685 dwError = DCE_NOT_SUPPORTED;
1686 }
1687 }
1688 else if (MatchString("ChildStatus(*)", szParam, FALSE))
1689 {
1690 char *pEnd, szArg[256];
1691 DWORD i, dwId;
1692 NetObj *pObject = NULL;
1693
1694 NxGetParameterArg((char *)szParam, 1, szArg, 256);
1695 dwId = strtoul(szArg, &pEnd, 0);
1696 if (*pEnd != 0)
1697 {
1698 // Argument is object's name
1699 dwId = 0;
1700 }
1701
1702 // Find child object with requested ID or name
1703 LockChildList(FALSE);
1704 for(i = 0; i < m_dwChildCount; i++)
1705 {
1706 if (((dwId == 0) && (!stricmp(m_pChildList[i]->Name(), szArg))) ||
1707 (dwId == m_pChildList[i]->Id()))
1708 {
1709 pObject = m_pChildList[i];
1710 break;
1711 }
1712 }
1713 UnlockChildList();
1714
1715 if (pObject != NULL)
1716 {
1717 sprintf(szBuffer, "%d", pObject->Status());
1718 }
1719 else
1720 {
1721 dwError = DCE_NOT_SUPPORTED;
1722 }
1723 }
1724 else if (m_dwFlags & NF_IS_LOCAL_MGMT)
1725 {
1726 if (!stricmp(szParam, "Server.AverageDCPollerQueueSize"))
1727 {
1728 sprintf(szBuffer, "%f", g_dAvgPollerQueueSize);
1729 }
1730 else if (!stricmp(szParam, "Server.AverageDBWriterQueueSize"))
1731 {
1732 sprintf(szBuffer, "%f", g_dAvgDBWriterQueueSize);
1733 }
1734 else if (!stricmp(szParam, "Server.AverageStatusPollerQueueSize"))
1735 {
1736 sprintf(szBuffer, "%f", g_dAvgStatusPollerQueueSize);
1737 }
1738 else if (!stricmp(szParam, "Server.AverageConfigurationPollerQueueSize"))
1739 {
1740 sprintf(szBuffer, "%f", g_dAvgConfigPollerQueueSize);
1741 }
1742 else if (!stricmp(szParam, "Server.AverageDCIQueuingTime"))
1743 {
1744 sprintf(szBuffer, "%u", g_dwAvgDCIQueuingTime);
1745 }
1746 else if (!stricmp(szParam, "Server.TotalEventsProcessed"))
1747 {
1748 sprintf(szBuffer, INT64_FMT, g_totalEventsProcessed);
1749 }
1750 else
1751 {
1752 dwError = DCE_NOT_SUPPORTED;
1753 }
1754 }
1755 else
1756 {
1757 dwError = DCE_NOT_SUPPORTED;
1758 }
1759
1760 return dwError;
1761 }
1762
1763
1764 //
1765 // Get item's value for client
1766 //
1767
1768 DWORD Node::GetItemForClient(int iOrigin, const char *pszParam, char *pszBuffer, DWORD dwBufSize)
1769 {
1770 DWORD dwResult = 0, dwRetCode;
1771
1772 // Get data from node
1773 switch(iOrigin)
1774 {
1775 case DS_INTERNAL:
1776 dwRetCode = GetInternalItem(pszParam, dwBufSize, pszBuffer);
1777 break;
1778 case DS_NATIVE_AGENT:
1779 dwRetCode = GetItemFromAgent(pszParam, dwBufSize, pszBuffer);
1780 break;
1781 case DS_SNMP_AGENT:
1782 dwRetCode = GetItemFromSNMP(pszParam, dwBufSize, pszBuffer);
1783 break;
1784 case DS_CHECKPOINT_AGENT:
1785 dwRetCode = GetItemFromCheckPointSNMP(pszParam, dwBufSize, pszBuffer);
1786 break;
1787 default:
1788 dwResult = RCC_INVALID_ARGUMENT;
1789 break;
1790 }
1791
1792 // Translate return code to RCC
1793 if (dwResult != RCC_INVALID_ARGUMENT)
1794 {
1795 switch(dwRetCode)
1796 {
1797 case DCE_SUCCESS:
1798 dwResult = RCC_SUCCESS;
1799 break;
1800 case DCE_COMM_ERROR:
1801 dwResult = RCC_COMM_FAILURE;
1802 break;
1803 case DCE_NOT_SUPPORTED:
1804 dwResult = RCC_DCI_NOT_SUPPORTED;
1805 break;
1806 default:
1807 dwResult = RCC_SYSTEM_FAILURE;
1808 break;
1809 }
1810 }
1811
1812 return dwResult;
1813 }
1814
1815
1816 //
1817 // Put items which requires polling into the queue
1818 //
1819
1820 void Node::QueueItemsForPolling(Queue *pPollerQueue)
1821 {
1822 DWORD i;
1823 time_t currTime;
1824
1825 if ((m_iStatus == STATUS_UNMANAGED) ||
1826 (m_dwFlags & NF_DISABLE_DATA_COLLECT))
1827 return; // Do not collect data for unmanaged nodes or if data collection is disabled
1828
1829 currTime = time(NULL);
1830
1831 LockData();
1832 for(i = 0; i < m_dwNumItems; i++)
1833 {
1834 if (m_ppItems[i]->ReadyForPolling(currTime))
1835 {
1836 m_ppItems[i]->SetBusyFlag(TRUE);
1837 IncRefCount(); // Increment reference count for each queued DCI
1838 pPollerQueue->Put(m_ppItems[i]);
1839 }
1840 }
1841 UnlockData();
1842 }
1843
1844
1845 //
1846 // Create CSCP message with object's data
1847 //
1848
1849 void Node::CreateMessage(CSCPMessage *pMsg)
1850 {
1851 Template::CreateMessage(pMsg);
1852 pMsg->SetVariable(VID_FLAGS, m_dwFlags);
1853 pMsg->SetVariable(VID_AGENT_PORT, m_wAgentPort);
1854 pMsg->SetVariable(VID_AUTH_METHOD, m_wAuthMethod);
1855 pMsg->SetVariable(VID_SHARED_SECRET, m_szSharedSecret);
1856 pMsg->SetVariable(VID_COMMUNITY_STRING, m_szCommunityString);
1857 pMsg->SetVariable(VID_SNMP_OID, m_szObjectId);
1858 pMsg->SetVariable(VID_NODE_TYPE, m_dwNodeType);
1859 pMsg->SetVariable(VID_SNMP_VERSION, (WORD)m_iSNMPVersion);
1860 pMsg->SetVariable(VID_AGENT_VERSION, m_szAgentVersion);
1861 pMsg->SetVariable(VID_PLATFORM_NAME, m_szPlatformName);
1862 pMsg->SetVariable(VID_POLLER_NODE_ID, m_dwPollerNode);
1863 pMsg->SetVariable(VID_ZONE_GUID, m_dwZoneGUID);
1864 pMsg->SetVariable(VID_PROXY_NODE, m_dwProxyNode);
1865 pMsg->SetVariable(VID_SNMP_PROXY, m_dwSNMPProxy);
1866 pMsg->SetVariable(VID_REQUIRED_POLLS, (WORD)m_iRequiredPollCount);
1867 pMsg->SetVariable(VID_SYS_DESCRIPTION, m_szSysDescription);
1868 }
1869
1870
1871 //
1872 // Modify object from message
1873 //
1874
1875 DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
1876 {
1877 if (!bAlreadyLocked)
1878 LockData();
1879
1880 // Change primary IP address
1881 if (pRequest->IsVariableExist(VID_IP_ADDRESS))
1882 {
1883 DWORD i, dwIpAddr;
1884
1885 dwIpAddr = pRequest->GetVariableLong(VID_IP_ADDRESS);
1886
1887 // Check if received IP address is one of node's interface addresses
1888 LockChildList(FALSE);
1889 for(i = 0; i < m_dwChildCount; i++)
1890 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1891 (m_pChildList[i]->IpAddr() == dwIpAddr))
1892 break;
1893 UnlockChildList();
1894 if (i == m_dwChildCount)
1895 {
1896 UnlockData();
1897 return RCC_INVALID_IP_ADDR;
1898 }
1899
1900 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
1901 m_dwIpAddr = dwIpAddr;
1902 }
1903
1904 // Poller node ID
1905 if (pRequest->IsVariableExist(VID_POLLER_NODE_ID))
1906 {
1907 DWORD dwNodeId;
1908 NetObj *pObject;
1909
1910 dwNodeId = pRequest->GetVariableLong(VID_POLLER_NODE_ID);
1911 pObject = FindObjectById(dwNodeId);
1912
1913 // Check if received id is a valid node id
1914 if (pObject == NULL)
1915 {
1916 UnlockData();
1917 return RCC_INVALID_OBJECT_ID;
1918 }
1919 if (pObject->Type() != OBJECT_NODE)
1920 {
1921 UnlockData();
1922 return RCC_INVALID_OBJECT_ID;
1923 }
1924
1925 m_dwPollerNode = dwNodeId;
1926 }
1927
1928 // Change listen port of native agent
1929 if (pRequest->IsVariableExist(VID_AGENT_PORT))
1930 m_wAgentPort = pRequest->GetVariableShort(VID_AGENT_PORT);
1931
1932 // Change authentication method of native agent
1933 if (pRequest->IsVariableExist(VID_AUTH_METHOD))
1934 m_wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
1935
1936 // Change shared secret of native agent
1937 if (pRequest->IsVariableExist(VID_SHARED_SECRET))
1938 pRequest->GetVariableStr(VID_SHARED_SECRET, m_szSharedSecret, MAX_SECRET_LENGTH);
1939
1940 // Change SNMP protocol version
1941 if (pRequest->IsVariableExist(VID_SNMP_VERSION))
1942 m_iSNMPVersion = pRequest->GetVariableShort(VID_SNMP_VERSION);
1943
1944 // Change SNMP community string
1945 if (pRequest->IsVariableExist(VID_COMMUNITY_STRING))
1946 pRequest->GetVariableStr(VID_COMMUNITY_STRING, m_szCommunityString, MAX_COMMUNITY_LENGTH);
1947
1948 // Change proxy node
1949 if (pRequest->IsVariableExist(VID_PROXY_NODE))
1950 m_dwProxyNode = pRequest->GetVariableLong(VID_PROXY_NODE);
1951
1952 // Change SNMP proxy node
1953 if (pRequest->IsVariableExist(VID_SNMP_PROXY))
1954 m_dwSNMPProxy = pRequest->GetVariableLong(VID_SNMP_PROXY);
1955
1956 // Number of required polls
1957 if (pRequest->IsVariableExist(VID_REQUIRED_POLLS))
1958 m_iRequiredPollCount = (int)pRequest->GetVariableShort(VID_REQUIRED_POLLS);
1959
1960 // Change flags
1961 if (pRequest->IsVariableExist(VID_FLAGS))
1962 {
1963 m_dwFlags &= NF_SYSTEM_FLAGS;
1964 m_dwFlags |= pRequest->GetVariableLong(VID_FLAGS) & NF_USER_FLAGS;
1965 }
1966
1967 return Template::ModifyFromMessage(pRequest, TRUE);
1968 }
1969
1970
1971 //
1972 // Wakeup node using magic packet
1973 //
1974
1975 DWORD Node::WakeUp(void)
1976 {
1977 DWORD i, dwResult = RCC_NO_WOL_INTERFACES;
1978
1979 LockChildList(FALSE);
1980
1981 for(i = 0; i < m_dwChildCount; i++)
1982 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1983 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
1984 (m_pChildList[i]->IpAddr() != 0))
1985 {
1986 dwResult = ((Interface *)m_pChildList[i])->WakeUp();
1987 break;
1988 }
1989
1990 UnlockChildList();
1991 return dwResult;
1992 }
1993
1994
1995 //
1996 // Get status of interface with given index from SNMP agent
1997 //
1998
1999 int Node::GetInterfaceStatusFromSNMP(SNMP_Transport *pTransport, DWORD dwIndex)
2000 {
2001 return SnmpGetInterfaceStatus(m_iSNMPVersion, pTransport, m_szCommunityString, dwIndex);
2002 }
2003
2004
2005 //
2006 // Get status of interface with given index from native agent
2007 //
2008
2009 int Node::GetInterfaceStatusFromAgent(DWORD dwIndex)
2010 {
2011 char szParam[128], szBuffer[32];
2012 DWORD dwAdminStatus, dwLinkState;
2013 int iStatus;
2014
2015 // Get administrative status
2016 sprintf(szParam, "Net.Interface.AdminStatus(%u)", dwIndex);
2017 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
2018 {
2019 dwAdminStatus = strtoul(szBuffer, NULL, 0);
2020
2021 switch(dwAdminStatus)
2022 {
2023 case 3:
2024 iStatus = STATUS_TESTING;
2025 break;
2026 case 2:
2027 case 0: // Agents before 0.2.1 may return 0 instead of 2
2028 iStatus = STATUS_DISABLED;
2029 break;
2030 case 1: // Interface administratively up, check link state
2031 sprintf(szParam, "Net.Interface.Link(%u)", dwIndex);
2032 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
2033 {
2034 dwLinkState = strtoul(szBuffer, NULL, 0);
2035 iStatus = (dwLinkState == 0) ? STATUS_CRITICAL : STATUS_NORMAL;
2036 }
2037 else
2038 {
2039 iStatus = STATUS_UNKNOWN;
2040 }
2041 break;
2042 default:
2043 iStatus = STATUS_UNKNOWN;
2044 break;
2045 }
2046 }
2047 else
2048 {
2049 iStatus = STATUS_UNKNOWN;
2050 }
2051
2052 return iStatus;
2053 }
2054
2055
2056 //
2057 // Put list of supported parameters into CSCP message
2058 //
2059
2060 void Node::WriteParamListToMessage(CSCPMessage *pMsg)
2061 {
2062 DWORD i, dwId;
2063
2064 LockData();
2065 if (m_pParamList != NULL)
2066 {
2067 pMsg->SetVariable(VID_NUM_PARAMETERS, m_dwNumParams);
2068 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < m_dwNumParams; i++)
2069 {
2070 pMsg->SetVariable(dwId++, m_pParamList[i].szName);
2071 pMsg->SetVariable(dwId++, m_pParamList[i].szDescription);
2072 pMsg->SetVariable(dwId++, (WORD)m_pParamList[i].iDataType);
2073 }
2074 }
2075 else
2076 {
2077 pMsg->SetVariable(VID_NUM_PARAMETERS, (DWORD)0);
2078 }
2079 UnlockData();
2080 }
2081
2082
2083 //
2084 // Open list of supported parameters for reading
2085 //
2086
2087 void Node::OpenParamList(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
2088 {
2089 LockData();
2090 *pdwNumParams = m_dwNumParams;
2091 *ppParamList = m_pParamList;
2092 }
2093
2094
2095 //
2096 // Check status of network service
2097 //
2098
2099 DWORD Node::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
2100 WORD wPort, WORD wProto, TCHAR *pszRequest,
2101 TCHAR *pszResponse)
2102 {
2103 DWORD dwError = ERR_NOT_CONNECTED;
2104
2105 if ((m_dwFlags & NF_IS_NATIVE_AGENT) &&
2106 (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)) &&
2107 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
2108 {
2109 AgentConnection *pConn;
2110
2111 pConn = CreateAgentConnection();
2112 if (pConn != NULL)
2113 {
2114 dwError = pConn->CheckNetworkService(pdwStatus, dwIpAddr, iServiceType,
2115 wPort, wProto, pszRequest, pszResponse);
2116 pConn->Disconnect();
2117 delete pConn;
2118 }
2119 }
2120 return dwError;
2121 }
2122
2123
2124 //
2125 // Handler for object deletion
2126 //
2127
2128 void Node::OnObjectDelete(DWORD dwObjectId)
2129 {
2130 if (dwObjectId == m_dwPollerNode)
2131 {
2132 // If deleted object is our poller node, change it to default
2133 /* LOCK? */
2134 m_dwPollerNode = 0;
2135 Modify();
2136 DbgPrintf(3, _T("Node \"%s\": poller node %d deleted"), m_szName, dwObjectId);
2137 }
2138 }
2139
2140
2141 //
2142 // Check node for OSPF support
2143 //
2144
2145 void Node::CheckOSPFSupport(SNMP_Transport *pTransport)
2146 {
2147 LONG nAdminStatus;
2148
2149 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
2150 ".1.3.6.1.2.1.14.1.2.0", NULL, 0, &nAdminStatus, sizeof(LONG),
2151 FALSE, FALSE) == SNMP_ERR_SUCCESS)
2152 {
2153 if (nAdminStatus)
2154 {
2155 m_dwFlags |= NF_IS_OSPF;
2156 }
2157 else
2158 {
2159 m_dwFlags &= ~NF_IS_OSPF;
2160 }
2161 }
2162 }
2163
2164
2165 //
2166 // Create ready to use agent connection
2167 //
2168
2169 AgentConnection *Node::CreateAgentConnection(void)
2170 {
2171 AgentConnection *pConn;
2172
2173 if ((!(m_dwFlags & NF_IS_NATIVE_AGENT)) ||
2174 (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
2175 (m_dwDynamicFlags & NDF_UNREACHABLE))
2176 return NULL;
2177
2178 pConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
2179 m_wAuthMethod, m_szSharedSecret);
2180 SetAgentProxy(pConn);
2181 if (!pConn->Connect(g_pServerKey))
2182 {
2183 delete pConn;
2184 pConn = NULL;
2185 }
2186 return pConn;
2187 }
2188
2189
2190 //
2191 // Get last collected values of all DCIs
2192 //
2193
2194 DWORD Node::GetLastValues(CSCPMessage *pMsg)
2195 {
2196 DWORD i, dwId, dwCount;
2197
2198 LockData();
2199
2200 for(i = 0, dwId = VID_DCI_VALUES_BASE, dwCount = 0; i < m_dwNumItems; i++)
2201 {
2202 if (_tcsnicmp(m_ppItems[i]->Description(), _T("@system."), 8))
2203 {
2204 m_ppItems[i]->GetLastValue(pMsg, dwId);
2205 dwId += 10;
2206 dwCount++;
2207 }
2208 }
2209 pMsg->SetVariable(VID_NUM_ITEMS, dwCount);
2210
2211 UnlockData();
2212 return RCC_SUCCESS;
2213 }
2214
2215
2216 //
2217 // Clean expired DCI data
2218 //
2219
2220 void Node::CleanDCIData(void)
2221 {
2222 DWORD i;
2223
2224 LockData();
2225 for(i = 0; i < m_dwNumItems; i++)
2226 m_ppItems[i]->CleanData();
2227 UnlockData();
2228 }
2229
2230
2231 //
2232 // Apply DCI from template
2233 // pItem passed to this method should be a template's DCI
2234 //
2235
2236 BOOL Node::ApplyTemplateItem(DWORD dwTemplateId, DCItem *pItem)
2237 {
2238 BOOL bResult = TRUE;
2239 DWORD i;
2240 DCItem *pNewItem;
2241
2242 LockData();
2243
2244 DbgPrintf(5, "Applying item \"%s\" to node \"%s\"", pItem->Name(), m_szName);
2245
2246 // Check if that template item exists
2247 for(i = 0; i < m_dwNumItems; i++)
2248 if ((m_ppItems[i]->TemplateId() == dwTemplateId) &&
2249 (m_ppItems[i]->TemplateItemId() == pItem->Id()))
2250 break; // Item with specified id already exist
2251
2252 if (i == m_dwNumItems)
2253 {
2254 // New item from template, just add it
2255 pNewItem = new DCItem(pItem);
2256 pNewItem->SetTemplateId(dwTemplateId, pItem->Id());
2257 pNewItem->ChangeBinding(CreateUniqueId(IDG_ITEM), this, TRUE);
2258 bResult = AddItem(pNewItem, TRUE);
2259 }
2260 else
2261 {
2262 // Update existing item
2263 m_ppItems[i]->UpdateFromTemplate(pItem);
2264 Modify();
2265 }
2266
2267 UnlockData();
2268 return bResult;
2269 }
2270
2271
2272 //
2273 // Clean deleted template items from node's DCI list
2274 // Arguments is template id and list of valid template item ids.
2275 // all items related to given template and not presented in list should be deleted.
2276 //
2277
2278 void Node::CleanDeletedTemplateItems(DWORD dwTemplateId, DWORD dwNumItems, DWORD *pdwItemList)
2279 {
2280 DWORD i, j, dwNumDeleted, *pdwDeleteList;
2281
2282 LockData();
2283
2284 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
2285 dwNumDeleted = 0;
2286
2287 for(i = 0; i < m_dwNumItems; i++)
2288 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2289 {
2290 for(j = 0; j < dwNumItems; j++)
2291 if (m_ppItems[i]->TemplateItemId() == pdwItemList[j])
2292 break;
2293
2294 // Delete DCI if it's not in list
2295 if (j == dwNumItems)
2296 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->Id();
2297 }
2298
2299 for(i = 0; i < dwNumDeleted; i++)
2300 DeleteItem(pdwDeleteList[i], FALSE);
2301
2302 UnlockData();
2303 free(pdwDeleteList);
2304 }
2305
2306
2307 //
2308 // Unbind node from template, i.e either remove DCI association with template
2309 // or remove these DCIs at all
2310 //
2311
2312 void Node::UnbindFromTemplate(DWORD dwTemplateId, BOOL bRemoveDCI)
2313 {
2314 DWORD i, dwNumDeleted, *pdwDeleteList;
2315
2316 if (bRemoveDCI)
2317 {
2318 LockData();
2319
2320 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
2321 dwNumDeleted = 0;
2322
2323 for(i = 0; i < m_dwNumItems; i++)
2324 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2325 {
2326 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->Id();
2327 }
2328
2329 for(i = 0; i < dwNumDeleted; i++)
2330 DeleteItem(pdwDeleteList[i], FALSE);
2331
2332 UnlockData();
2333 }
2334 else
2335 {
2336 LockData();
2337
2338 for(i = 0; i < m_dwNumItems; i++)
2339 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2340 {
2341 m_ppItems[i]->SetTemplateId(0, 0);
2342 }
2343
2344 UnlockData();
2345 }
2346 }
2347
2348
2349 //
2350 // Change node's IP address
2351 //
2352
2353 void Node::ChangeIPAddress(DWORD dwIpAddr)
2354 {
2355 DWORD i;
2356
2357 PollerLock();
2358
2359 LockData();
2360
2361 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
2362 m_dwIpAddr = dwIpAddr;
2363 m_dwDynamicFlags |= NDF_FORCE_CONFIGURATION_POLL | NDF_RECHECK_CAPABILITIES;
2364
2365 // Change status of node and all it's childs to UNKNOWN
2366 m_iStatus = STATUS_UNKNOWN;
2367 LockChildList(FALSE);
2368 for(i = 0; i < m_dwChildCount; i++)
2369 {
2370 m_pChildList[i]->ResetStatus();
2371 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2372 {
2373 if (((Interface *)m_pChildList[i])->IsFake())
2374 {
2375 ((Interface *)m_pChildList[i])->SetIpAddr(dwIpAddr);
2376 }
2377 }
2378 }
2379 UnlockChildList();
2380
2381 Modify();
2382 UnlockData();
2383
2384 AgentLock();
2385 delete_and_null(m_pAgentConnection);
2386 AgentUnlock();
2387
2388 PollerUnlock();
2389 }
2390
2391
2392 //
2393 // Get number of interface objects and pointer to the last one
2394 //
2395
2396 DWORD Node::GetInterfaceCount(Interface **ppInterface)
2397 {
2398 DWORD i, dwCount;
2399
2400 LockChildList(FALSE);
2401 for(i = 0, dwCount = 0; i < m_dwChildCount; i++)
2402 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2403 {
2404 dwCount++;
2405 *ppInterface = (Interface *)m_pChildList[i];
2406 }
2407 UnlockChildList();
2408 return dwCount;
2409 }
2410
2411
2412 //
2413 // Update cache for all DCI's
2414 //
2415
2416 void Node::UpdateDCICache(void)
2417 {
2418 DWORD i;
2419
2420 /* LOCK? */
2421 for(i = 0; i < m_dwNumItems; i++)
2422 m_ppItems[i]->UpdateCacheSize();
2423 }
2424
2425
2426 //
2427 // Get routing table from node
2428 //
2429
2430 ROUTING_TABLE *Node::GetRoutingTable(void)
2431 {
2432 ROUTING_TABLE *pRT = NULL;
2433
2434 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)))
2435 {
2436 AgentLock();
2437 if (ConnectToAgent())
2438 {
2439 pRT = m_pAgentConnection->GetRoutingTable();
2440 }
2441 AgentUnlock();
2442 }
2443 if ((pRT == NULL) && (m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)))
2444 {
2445 SNMP_Transport *pTransport;
2446
2447 pTransport = CreateSNMPTransport();
2448 pRT = SnmpGetRoutingTable(m_iSNMPVersion, pTransport, m_szCommunityString);
2449 delete pTransport;
2450 }
2451
2452 if (pRT != NULL)
2453 {
2454 SortRoutingTable(pRT);
2455 }
2456 return pRT;
2457 }
2458
2459
2460 //
2461 // Get next hop for given destination address
2462 //
2463
2464 BOOL Node::GetNextHop(DWORD dwSrcAddr, DWORD dwDestAddr, DWORD *pdwNextHop,
2465 DWORD *pdwIfIndex, BOOL *pbIsVPN)
2466 {
2467 DWORD i;
2468 BOOL bResult = FALSE;
2469
2470 // Check VPN connectors
2471 LockChildList(FALSE);
2472 for(i = 0; i < m_dwChildCount; i++)
2473 if (m_pChildList[i]->Type() == OBJECT_VPNCONNECTOR)
2474 {
2475 if (((VPNConnector *)m_pChildList[i])->IsRemoteAddr(dwDestAddr) &&
2476 ((VPNConnector *)m_pChildList[i])->IsLocalAddr(dwSrcAddr))
2477 {
2478 *pdwNextHop = ((VPNConnector *)m_pChildList[i])->GetPeerGatewayAddr();
2479 *pdwIfIndex = m_pChildList[i]->Id();
2480 *pbIsVPN = TRUE;
2481 bResult = TRUE;
2482 break;
2483 }
2484 }
2485 UnlockChildList();
2486
2487 // Check routing table
2488 if (!bResult)
2489 {
2490 RTLock();
2491 if (m_pRoutingTable != NULL)
2492 {
2493 for(i = 0; i < (DWORD)m_pRoutingTable->iNumEntries; i++)
2494 if ((dwDestAddr & m_pRoutingTable->pRoutes[i].dwDestMask) == m_pRoutingTable->pRoutes[i].dwDestAddr)
2495 {
2496 *pdwNextHop = m_pRoutingTable->pRoutes[i].dwNextHop;
2497 *pdwIfIndex = m_pRoutingTable->pRoutes[i].dwIfIndex;
2498 *pbIsVPN = FALSE;
2499 bResult = TRUE;
2500 break;
2501 }
2502 }
2503 RTUnlock();
2504 }
2505
2506 return bResult;
2507 }
2508
2509
2510 //
2511 // Update cached routing table
2512 //
2513
2514 void Node::UpdateRoutingTable(void)
2515 {
2516 ROUTING_TABLE *pRT;
2517
2518 pRT = GetRoutingTable();
2519 if (pRT != NULL)
2520 {
2521 RTLock();
2522 DestroyRoutingTable(m_pRoutingTable);
2523 m_pRoutingTable = pRT;
2524 RTUnlock();
2525 }
2526 m_tLastRTUpdate = time(NULL);
2527 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_ROUTE_POLL;
2528 }
2529
2530
2531 //
2532 // Call SNMP Enumerate with node's SNMP parameters
2533 //
2534
2535 DWORD Node::CallSnmpEnumerate(const char *pszRootOid,
2536 DWORD (* pHandler)(DWORD, const char *, SNMP_Variable *, SNMP_Transport *, void *),
2537 void *pArg)
2538 {
2539 if ((m_dwFlags & NF_IS_SNMP) &&
2540 (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)) &&
2541 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
2542 {
2543 SNMP_Transport *pTransport;
2544 DWORD dwResult;
2545
2546 pTransport = CreateSNMPTransport();
2547 dwResult = SnmpEnumerate(m_iSNMPVersion, pTransport,
2548 m_szCommunityString, pszRootOid, pHandler, pArg, FALSE);
2549 delete pTransport;
2550 return dwResult;
2551 }
2552 else
2553 {
2554 return SNMP_ERR_COMM;
2555 }
2556 }
2557
2558
2559 //
2560 // Set proxy information for agent's connection
2561 //
2562
2563 void Node::SetAgentProxy(AgentConnection *pConn)
2564 {
2565 if (m_dwProxyNode != 0)
2566 {
2567 Node *pNode;
2568
2569 pNode = (Node *)FindObjectById(m_dwProxyNode);
2570 if (pNode != NULL)
2571 {
2572 pConn->SetProxy(htonl(pNode->m_dwIpAddr), pNode->m_wAgentPort,
2573 pNode->m_wAuthMethod, pNode->m_szSharedSecret);
2574 }
2575 }
2576 }
2577
2578
2579 //
2580 // Prepare node object for deletion
2581 //
2582
2583 void Node::PrepareForDeletion(void)
2584 {
2585 // Prevent node from being queued for polling
2586 LockData();
2587 m_dwDynamicFlags |= NDF_POLLING_DISABLED;
2588 UnlockData();
2589
2590 // Wait for all pending polls
2591 while(1)
2592 {
2593 LockData();
2594 if ((m_dwDynamicFlags &
2595 (NDF_QUEUED_FOR_STATUS_POLL | NDF_QUEUED_FOR_CONFIG_POLL |
2596 NDF_QUEUED_FOR_DISCOVERY_POLL | NDF_QUEUED_FOR_ROUTE_POLL)) == 0)
2597 {
2598 UnlockData();
2599 break;
2600 }
2601 UnlockData();
2602 ThreadSleepMs(100);
2603 }
2604 }
2605
2606
2607 //
2608 // Check if specified SNMP variable set to specified value.
2609 // If variable doesn't exist at all, will return FALSE
2610 //
2611
2612 BOOL Node::CheckSNMPIntegerValue(SNMP_Transport *pTransport, const char *pszOID, int nValue)
2613 {
2614 DWORD dwTemp;
2615
2616 if (SnmpGet(m_iSNMPVersion, pTransport, m_szCommunityString,
2617 pszOID, NULL, 0, &dwTemp, sizeof(DWORD), FALSE, FALSE) == SNMP_ERR_SUCCESS)
2618 return (int)dwTemp == nValue;
2619 return FALSE;
2620 }
2621
2622
2623 //
2624 // Check and update if needed interface names
2625 //
2626
2627 void Node::CheckInterfaceNames(INTERFACE_LIST *pIfList)
2628 {
2629 int i;
2630 TCHAR *ptr;
2631
2632 if ((m_dwNodeType == NODE_TYPE_NORTEL_BAYSTACK) ||
2633 (m_dwNodeType == NODE_TYPE_NORTEL_OPTERA))
2634 {
2635 // Translate interface names
2636 for(i = 0; i < pIfList->iNumEntries; i++)
2637 {
2638 if ((ptr = _tcsstr(pIfList->pInterfaces[i].szName, _T("- Port"))) != NULL)
2639 {
2640 ptr += 2;
2641 memmove(pIfList->pInterfaces[i].szName, ptr, _tcslen(ptr) + 1);
2642 }
2643 else if ((ptr = _tcsstr(pIfList->pInterfaces[i].szName, _T("- Unit"))) != NULL)
2644 {
2645 ptr += 2;
2646 memmove(pIfList->pInterfaces[i].szName, ptr, _tcslen(ptr) + 1);
2647 }
2648 else if ((_tcsstr(pIfList->pInterfaces[i].szName, _T("BayStack")) != NULL) ||
2649 (_tcsstr(pIfList->pInterfaces[i].szName, _T("Nortel Ethernet Switch")) != NULL))
2650 {
2651 ptr = _tcsrchr(pIfList->pInterfaces[i].szName, _T('-'));
2652 if (ptr != NULL)
2653 {
2654 ptr++;
2655 while(*ptr == _T(' '))
2656 ptr++;
2657 memmove(pIfList->pInterfaces[i].szName, ptr, _tcslen(ptr) + 1);
2658 }
2659 }
2660 StrStrip(pIfList->pInterfaces[i].szName);
2661 }
2662 }
2663
2664 // Cut interface names to MAX_OBJECT_NAME and check for unnamed interfaces
2665 for(i = 0; i < pIfList->iNumEntries; i++)
2666 {
2667 pIfList->pInterfaces[i].szName[MAX_OBJECT_NAME - 1] = 0;
2668 if (pIfList->pInterfaces[i].szName[0] == 0)
2669 _stprintf(pIfList->pInterfaces[i].szName, _T("%d"), pIfList->pInterfaces[i].dwIndex);
2670 }
2671 }
2672
2673
2674 //
2675 // Get cluster object this node belongs to, if any
2676 //
2677
2678 Cluster *Node::GetMyCluster(void)
2679 {
2680 DWORD i;
2681 Cluster *pCluster = NULL;
2682
2683 LockParentList(FALSE);
2684 for(i = 0; i < m_dwParentCount; i++)
2685 if (m_pParentList[i]->Type() == OBJECT_CLUSTER)
2686 {
2687 pCluster = (Cluster *)m_pParentList[i];
2688 break;
2689 }
2690 UnlockParentList();
2691 return pCluster;
2692 }
2693
2694
2695 //
2696 // Create SNMP transport
2697 //
2698
2699 SNMP_Transport *Node::CreateSNMPTransport(void)
2700 {
2701 SNMP_Transport *pTransport = NULL;
2702
2703 if (m_dwSNMPProxy == 0)
2704 {
2705 pTransport = new SNMP_UDPTransport;
2706 ((SNMP_UDPTransport *)pTransport)->CreateUDPTransport(NULL, htonl(m_dwIpAddr), m_wSNMPPort);
2707 }
2708 else
2709 {
2710 NetObj *pObject;
2711
2712 pObject = FindObjectById(m_dwSNMPProxy);
2713 if (pObject != NULL)
2714 {
2715 if (pObject->Type() == OBJECT_NODE)
2716 {
2717 AgentConnection *pConn;
2718
2719 pConn = ((Node *)pObject)->CreateAgentConnection();
2720 if (pConn != NULL)
2721 {
2722 pTransport = new SNMP_ProxyTransport(pConn, m_dwIpAddr, m_wSNMPPort);
2723 }
2724 }
2725 }
2726 }
2727 return pTransport;
2728 }
2729
2730
2731 //
2732 // Resolve node's name
2733 //
2734
2735 BOOL Node::ResolveName(BOOL useOnlyDNS)
2736 {
2737 BOOL bSuccess = FALSE;
2738 HOSTENT *hs;
2739 DWORD i, dwAddr;
2740 TCHAR szBuffer[256];
2741
2742 DbgPrintf(4, _T("Resolving name for node %d [%s]..."), m_dwId, m_szName);
2743
2744 // Try to resolve primary IP
2745 dwAddr = htonl(m_dwIpAddr);
2746 hs = gethostbyaddr((const char *)&dwAddr, 4, AF_INET);
2747 if (hs != NULL)
2748 {
2749 nx_strncpy(m_szName, hs->h_name, MAX_OBJECT_NAME);
2750 bSuccess = TRUE;
2751 }
2752 else
2753 {
2754 // Try to resolve each interface's IP address
2755 LockChildList(FALSE);
2756 for(i = 0; i < m_dwChildCount; i++)
2757 {
2758 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2759 {
2760 dwAddr = htonl(m_pChildList[i]->IpAddr());
2761 if (dwAddr != 0)
2762 {
2763 hs = gethostbyaddr((const char *)&dwAddr, 4, AF_INET);
2764 if (hs != NULL)
2765 {
2766 nx_strncpy(m_szName, hs->h_name, MAX_OBJECT_NAME);
2767 bSuccess = TRUE;
2768 break;
2769 }
2770 }
2771 }
2772 }
2773 UnlockChildList();
2774
2775 // Try to get hostname from agent if address resolution fails
2776 if (!(bSuccess || useOnlyDNS))
2777 {
2778 DbgPrintf(4, _T("Resolving name for node %d [%s] via agent..."), m_dwId, m_szName);
2779 if (GetItemFromAgent("System.Hostname", 256, szBuffer) == DCE_SUCCESS)
2780 {
2781 StrStrip(szBuffer);
2782 if (szBuffer[0] != 0)
2783 {
2784 nx_strncpy(m_szName, szBuffer, MAX_OBJECT_NAME);
2785 bSuccess = TRUE;
2786 }
2787 }
2788 }
2789
2790 // Try to get hostname from SNMP if other methods fails
2791 if (!(bSuccess || useOnlyDNS))
2792 {
2793 DbgPrintf(4, _T("Resolving name for node %d [%s] via SNMP..."), m_dwId, m_szName);
2794 if (GetItemFromSNMP(".1.3.6.1.2.1.1.5.0", 256, szBuffer) == DCE_SUCCESS)
2795 {
2796 StrStrip(szBuffer);
2797 if (szBuffer[0] != 0)
2798 {
2799 nx_strncpy(m_szName, szBuffer, MAX_OBJECT_NAME);
2800 bSuccess = TRUE;
2801 }
2802 }
2803 }
2804 }
2805
2806 if (bSuccess)
2807 DbgPrintf(4, _T("Name for node %d was resolved to %s"), m_dwId, m_szName);
2808 else
2809 DbgPrintf(4, _T("Name for node %d was not resolved"), m_dwId, m_szName);
2810 return bSuccess;
2811 }
2812
2813
2814 //
2815 // Send list of system DCIs
2816 //
2817
2818 DWORD Node::GetSystemDCIList(CSCPMessage *pMsg)
2819 {
2820 DWORD i, dwId, dwCount;
2821
2822 LockData();
2823
2824 for(i = 0, dwId = VID_SYSDCI_LIST_BASE, dwCount = 0; i < m_dwNumItems; i++)
2825 {
2826 if (!_tcsnicmp(m_ppItems[i]->Description(), _T("@System."), 8))
2827 {
2828 pMsg->SetVariable(dwId++, m_ppItems[i]->Id());
2829 pMsg->SetVariable(dwId++, (TCHAR *)m_ppItems[i]->Description());
2830 pMsg->SetVariable(dwId++, (WORD)m_ppItems[i]->Status());
2831 dwId += 7;
2832 dwCount++;
2833 }
2834 }
2835 pMsg->SetVariable(VID_NUM_ITEMS, dwCount);
2836
2837 UnlockData();
2838 return RCC_SUCCESS;
2839 }
2840
2841
2842 //
2843 // Get current layer 2 topology (as dynamically created list which should be destroyed by caller)
2844 // Will return NULL if there are no topology information or it is expired
2845 //
2846
2847 nxObjList *Node::GetL2Topology(void)
2848 {
2849 nxObjList *pResult;
2850 DWORD dwExpTime;
2851
2852 dwExpTime = ConfigReadULong(_T("TopologyExpirationTime"), 900);
2853 MutexLock(m_mutexTopoAccess, INFINITE);
2854 if ((m_pTopology == NULL) || (m_tLastTopologyPoll + (time_t)dwExpTime < time(NULL)))
2855 {
2856 pResult = NULL;
2857 }
2858 else
2859 {
2860 pResult = new nxObjList(m_pTopology);
2861 }
2862 MutexUnlock(m_mutexTopoAccess);
2863 return pResult;
2864 }
2865
2866
2867 //
2868 // Rebuild layer 2 topology and return it as dynamically reated list which should be destroyed by caller
2869 //
2870
2871 nxObjList *Node::BuildL2Topology(DWORD *pdwStatus)
2872 {
2873 nxObjList *pResult;
2874 int nDepth;
2875
2876 nDepth = ConfigReadInt(_T("TopologyDiscoveryRadius"), 5);
2877 MutexLock(m_mutexTopoAccess, INFINITE);
2878 delete m_pTopology;
2879 if ((m_dwFlags & NF_IS_CDP) || (m_dwFlags & NF_IS_SONMP) || (m_dwFlags & NF_IS_LLDP))
2880 {
2881 m_pTopology = new nxObjList;
2882 if ((*pdwStatus = ::BuildL2Topology(*m_pTopology, this, NULL, nDepth, NULL)) == RCC_SUCCESS)
2883 {
2884 m_tLastTopologyPoll = time(NULL);
2885 pResult = new nxObjList(m_pTopology);
2886 }
2887 else
2888 {
2889 delete_and_null(m_pTopology);
2890 pResult = NULL;
2891 }
2892 }
2893 else
2894 {
2895 pResult = NULL;
2896 m_pTopology = NULL;
2897 *pdwStatus = RCC_NO_L2_TOPOLOGY_SUPPORT;
2898 }
2899 MutexUnlock(m_mutexTopoAccess);
2900 return pResult;
2901 }
2902
2903
2904 //
2905 // Check subnet bindings
2906 //
2907
2908 void Node::CheckSubnetBinding(INTERFACE_LIST *pIfList)
2909 {
2910 Subnet *pSubnet;
2911 Interface *pInterface;
2912 NetObj **ppUnlinkList;
2913 int i, j, count;
2914
2915 // Check if we have subnet bindings for all interfaces
2916 for(i = 0; i < pIfList->iNumEntries; i++)
2917 {
2918 if (pIfList->pInterfaces[i].dwIpAddr != 0)
2919 {
2920 pInterface = FindInterface(pIfList->pInterfaces[i].dwIndex, pIfList->pInterfaces[i].dwIpAddr);
2921 if (pInterface == NULL)
2922 {
2923 WriteLog(MSG_INTERNAL_ERROR, EVENTLOG_WARNING_TYPE, "s", _T("Cannot find interface object in Node::CheckSubnetBinding()"));
2924 break; // Something goes really wrong
2925 }
2926
2927 pSubnet = FindSubnetForNode(pIfList->pInterfaces[i].dwIpAddr);
2928 if (pSubnet != NULL)
2929 {
2930 if (pSubnet->IsSyntheticMask())
2931 {
2932 DbgPrintf(4, _T("Setting correct netmask for subnet %s [%d] from node %s [%d]"),
2933 pSubnet->Name(), pSubnet->Id(), m_szName, m_dwId);
2934 pSubnet->SetCorrectMask(pInterface->IpAddr() & pInterface->IpNetMask(), pInterface->IpNetMask());
2935 }
2936 }
2937 else
2938 {
2939 // Create subnet
2940 pSubnet = new Subnet(pIfList->pInterfaces[i].dwIpAddr & pIfList->pInterfaces[i].dwIpNetMask,
2941 pIfList->pInterfaces[i].dwIpNetMask, m_dwZoneGUID, FALSE);
2942 NetObjInsert(pSubnet, TRUE);
2943 g_pEntireNet->AddSubnet(pSubnet);
2944 pSubnet->AddNode(this);
2945 DbgPrintf(4, _T("Node::CheckSubnetBinding(): Creating new subnet %s [%d] for node %s [%d]"),
2946 pSubnet->Name(), pSubnet->Id(), m_szName, m_dwId);
2947 }
2948
2949 // Check if subnet mask is correct on interface
2950 if (pSubnet->IpNetMask() != pIfList->pInterfaces[i].dwIpNetMask)
2951 {
2952 PostEvent(EVENT_INCORRECT_NETMASK, m_dwId, "idsaa", pInterface->Id(),
2953 pInterface->IfIndex(), pInterface->Name(),
2954 pInterface->IpNetMask(), pSubnet->IpNetMask());
2955 }
2956 }
2957 }
2958
2959 // Check if we have incorrect subnets as parents
2960 LockParentList(FALSE);
2961 LockChildList(FALSE);
2962 ppUnlinkList = (NetObj **)malloc(sizeof(NetObj *) * m_dwParentCount);
2963 for(i = 0, count = 0; i < (int)m_dwParentCount; i++)
2964 {
2965 if (m_pParentList[i]->Type() == OBJECT_SUBNET)
2966 {
2967 pSubnet = (Subnet *)m_pParentList[i];
2968 for(j = 0; j < (int)m_dwChildCount; j++)
2969 {
2970 if (m_pChildList[j]->Type() == OBJECT_INTERFACE)
2971 {
2972 if (pSubnet->IpAddr() == (m_pChildList[j]->IpAddr() & pSubnet->IpNetMask()))
2973 {
2974 break;
2975 }
2976 }
2977 }
2978 if (j == (int)m_dwChildCount)
2979 {
2980 DbgPrintf(4, _T("Node::CheckSubnetBinding(): Subnet %s [%d] is incorrect for node %s [%d]"),
2981 pSubnet->Name(), pSubnet->Id(), m_szName, m_dwId);
2982 ppUnlinkList[count++] = pSubnet;
2983 }
2984 }
2985 }
2986 UnlockChildList();
2987 UnlockParentList();
2988
2989 // Unlink for incorrect subnet objects
2990 for(i = 0; i < count; i++)
2991 {
2992 ppUnlinkList[i]->DeleteChild(this);
2993 DeleteParent(ppUnlinkList[i]);
2994 }
2995 safe_free(ppUnlinkList);
2996 }
2997
2998
2999 //
3000 // Update interface names
3001 //
3002
3003 void Node::UpdateInterfaceNames(ClientSession *pSession, DWORD dwRqId)
3004 {
3005 INTERFACE_LIST *pIfList;
3006 DWORD i;
3007 int j;
3008
3009 PollerLock();
3010 m_pPollRequestor = pSession;
3011 SendPollerMsg(dwRqId, _T("Starting interface names poll for node %s\r\n"), m_szName);
3012 DbgPrintf(4, "Starting interface names poll for node %s (ID: %d)", m_szName, m_dwId);
3013
3014 // Retrieve interface list
3015 pIfList = GetInterfaceList();
3016 if (pIfList != NULL)
3017 {
3018 // Check names of existing interfaces
3019 for(j = 0; j < pIfList->iNumEntries; j++)
3020 {
3021 LockChildList(FALSE);
3022 for(i = 0; i < m_dwChildCount; i++)
3023 {
3024 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
3025 {
3026 Interface *pInterface = (Interface *)m_pChildList[i];
3027
3028 if (pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex())
3029 {
3030 SendPollerMsg(dwRqId, _T(" Checking interface %d (%s)\r\n"), pInterface->IfIndex(), pInterface->Name());
3031 if (strcmp(pIfList->pInterfaces[j].szName, pInterface->Name()))
3032 {
3033 pInterface->SetName(pIfList->pInterfaces[j].szName);
3034 SendPollerMsg(dwRqId, _T(" \x7FwName of interface %d changed to %s\r\n"), pInterface->IfIndex(), pIfList->pInterfaces[j].szName);
3035 }
3036 break;
3037 }
3038 }
3039 }
3040 UnlockChildList();
3041 }
3042
3043 DestroyInterfaceList(pIfList);
3044 }
3045 else /* pIfList == NULL */
3046 {
3047 SendPollerMsg(dwRqId, _T(" \x7F") _T("eUnable to get interface list from node\r\n"));
3048 }
3049
3050 // Finish poll
3051 SendPollerMsg(dwRqId, _T("Finished interface names poll for node %s\r\n"), m_szName);
3052 PollerUnlock();
3053 DbgPrintf(4, "Finished interface names poll for node %s (ID: %d)", m_szName, m_dwId);
3054 }