11bf3fd58f7a35ddfae595425f1cc4e441d9c3df
[public/netxms.git] / src / server / core / node.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003, 2004 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 ** $module: 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_dwFlags = 0;
34 m_dwDynamicFlags = 0;
35 m_dwZoneGUID = 0;
36 m_dwNodeType = NODE_TYPE_GENERIC;
37 m_wAgentPort = AGENT_LISTEN_PORT;
38 m_wAuthMethod = AUTH_NONE;
39 m_szSharedSecret[0] = 0;
40 m_iStatusPollType = POLL_ICMP_PING;
41 m_iSNMPVersion = SNMP_VERSION_1;
42 m_wSNMPPort = SNMP_DEFAULT_PORT;
43 ConfigReadStr("DefaultCommunityString", m_szCommunityString,
44 MAX_COMMUNITY_LENGTH, "public");
45 m_szObjectId[0] = 0;
46 m_tLastDiscoveryPoll = 0;
47 m_tLastStatusPoll = 0;
48 m_tLastConfigurationPoll = 0;
49 m_tLastRTUpdate = 0;
50 m_hPollerMutex = MutexCreate();
51 m_hAgentAccessMutex = MutexCreate();
52 m_mutexRTAccess = MutexCreate();
53 m_pAgentConnection = NULL;
54 m_szAgentVersion[0] = 0;
55 m_szPlatformName[0] = 0;
56 m_dwNumParams = 0;
57 m_pParamList = NULL;
58 m_dwPollerNode = 0;
59 m_dwProxyNode = 0;
60 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
61 m_pRoutingTable = NULL;
62 m_tFailTimeSNMP = 0;
63 m_tFailTimeAgent = 0;
64 }
65
66
67 //
68 // Constructor for new node object
69 //
70
71 Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwProxyNode, DWORD dwZone)
72 :Template()
73 {
74 m_dwIpAddr = dwAddr;
75 m_dwFlags = dwFlags;
76 m_dwDynamicFlags = 0;
77 m_dwZoneGUID = dwZone;
78 m_dwNodeType = NODE_TYPE_GENERIC;
79 m_wAgentPort = AGENT_LISTEN_PORT;
80 m_wAuthMethod = AUTH_NONE;
81 m_szSharedSecret[0] = 0;
82 m_iStatusPollType = POLL_ICMP_PING;
83 m_iSNMPVersion = SNMP_VERSION_1;
84 m_wSNMPPort = SNMP_DEFAULT_PORT;
85 ConfigReadStr("DefaultCommunityString", m_szCommunityString,
86 MAX_COMMUNITY_LENGTH, "public");
87 IpToStr(dwAddr, m_szName); // Make default name from IP address
88 m_szObjectId[0] = 0;
89 m_tLastDiscoveryPoll = 0;
90 m_tLastStatusPoll = 0;
91 m_tLastConfigurationPoll = 0;
92 m_tLastRTUpdate = 0;
93 m_hPollerMutex = MutexCreate();
94 m_hAgentAccessMutex = MutexCreate();
95 m_mutexRTAccess = MutexCreate();
96 m_pAgentConnection = NULL;
97 m_szAgentVersion[0] = 0;
98 m_szPlatformName[0] = 0;
99 m_dwNumParams = 0;
100 m_pParamList = NULL;
101 m_dwPollerNode = 0;
102 m_dwProxyNode = dwProxyNode;
103 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
104 m_bIsHidden = TRUE;
105 m_pRoutingTable = NULL;
106 m_tFailTimeSNMP = 0;
107 m_tFailTimeAgent = 0;
108 }
109
110
111 //
112 // Node destructor
113 //
114
115 Node::~Node()
116 {
117 MutexDestroy(m_hPollerMutex);
118 MutexDestroy(m_hAgentAccessMutex);
119 MutexDestroy(m_mutexRTAccess);
120 if (m_pAgentConnection != NULL)
121 delete m_pAgentConnection;
122 safe_free(m_pParamList);
123 DestroyRoutingTable(m_pRoutingTable);
124 }
125
126
127 //
128 // Create object from database data
129 //
130
131 BOOL Node::CreateFromDB(DWORD dwId)
132 {
133 char szQuery[512];
134 DB_RESULT hResult;
135 int i, iNumRows;
136 DWORD dwSubnetId;
137 NetObj *pObject;
138 BOOL bResult = FALSE;
139
140 m_dwId = dwId;
141
142 if (!LoadCommonProperties())
143 {
144 DbgPrintf(AF_DEBUG_OBJECTS, "Cannot load common properties for node object %d", dwId);
145 return FALSE;
146 }
147
148 _sntprintf(szQuery, 512, "SELECT primary_ip,node_flags,"
149 "snmp_version,auth_method,secret,"
150 "agent_port,status_poll_type,community,snmp_oid,"
151 "description,node_type,agent_version,"
152 "platform_name,poller_node_id,zone_guid,"
153 "proxy_node FROM nodes WHERE id=%d", dwId);
154 hResult = DBSelect(g_hCoreDB, szQuery);
155 if (hResult == 0)
156 return FALSE; // Query failed
157
158 if (DBGetNumRows(hResult) == 0)
159 {
160 DBFreeResult(hResult);
161 DbgPrintf(AF_DEBUG_OBJECTS, "Missing record in \"nodes\" table for node object %d", dwId);
162 return FALSE;
163 }
164
165 m_dwIpAddr = DBGetFieldIPAddr(hResult, 0, 0);
166 m_dwFlags = DBGetFieldULong(hResult, 0, 1);
167 m_iSNMPVersion = DBGetFieldLong(hResult, 0, 2);
168 m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 3);
169 DBGetField(hResult, 0, 4, m_szSharedSecret, MAX_SECRET_LENGTH);
170 DecodeSQLString(m_szSharedSecret);
171 m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 5);
172 m_iStatusPollType = DBGetFieldLong(hResult, 0, 6);
173 DBGetField(hResult, 0, 7, m_szCommunityString, MAX_COMMUNITY_LENGTH);
174 DecodeSQLString(m_szCommunityString);
175 DBGetField(hResult, 0, 8, m_szObjectId, MAX_OID_LEN * 4);
176 m_pszDescription = DBGetField(hResult, 0, 9, NULL, 0);
177 DecodeSQLString(m_pszDescription);
178 m_dwNodeType = DBGetFieldULong(hResult, 0, 10);
179 DBGetField(hResult, 0, 11, m_szAgentVersion, MAX_AGENT_VERSION_LEN);
180 DecodeSQLString(m_szAgentVersion);
181 DBGetField(hResult, 0, 12, m_szPlatformName, MAX_PLATFORM_NAME_LEN);
182 DecodeSQLString(m_szPlatformName);
183 m_dwPollerNode = DBGetFieldULong(hResult, 0, 13);
184 m_dwZoneGUID = DBGetFieldULong(hResult, 0, 14);
185 m_dwProxyNode = DBGetFieldULong(hResult, 0, 15);
186
187 DBFreeResult(hResult);
188
189 if (!m_bIsDeleted)
190 {
191 // Link node to subnets
192 sprintf(szQuery, "SELECT subnet_id FROM nsmap WHERE node_id=%d", dwId);
193 hResult = DBSelect(g_hCoreDB, szQuery);
194 if (hResult == NULL)
195 return FALSE; // Query failed
196
197 iNumRows = DBGetNumRows(hResult);
198 if (iNumRows == 0)
199 {
200 DBFreeResult(hResult);
201 DbgPrintf(AF_DEBUG_OBJECTS, "Unbound node object %d (%s)", dwId, m_szName);
202 return FALSE; // No parents - it shouldn't happen if database isn't corrupted
203 }
204
205 for(i = 0; i < iNumRows; i++)
206 {
207 dwSubnetId = DBGetFieldULong(hResult, i, 0);
208 pObject = FindObjectById(dwSubnetId);
209 if (pObject == NULL)
210 {
211 WriteLog(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
212 break;
213 }
214 else if (pObject->Type() != OBJECT_SUBNET)
215 {
216 WriteLog(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
217 break;
218 }
219 else
220 {
221 pObject->AddChild(this);
222 AddParent(pObject);
223 bResult = TRUE;
224 }
225 }
226
227 DBFreeResult(hResult);
228 LoadItemsFromDB();
229 LoadACLFromDB();
230
231 // Walk through all items in the node and load appropriate thresholds
232 for(i = 0; i < (int)m_dwNumItems; i++)
233 if (!m_ppItems[i]->LoadThresholdsFromDB())
234 {
235 DbgPrintf(AF_DEBUG_OBJECTS, "Cannot load thresholds for DCI %d of node %d (%s)",
236 m_ppItems[i]->Id(), dwId, m_szName);
237 bResult = FALSE;
238 }
239 }
240 else
241 {
242 bResult = TRUE;
243 }
244
245 return bResult;
246 }
247
248
249 //
250 // Save object to database
251 //
252
253 BOOL Node::SaveToDB(DB_HANDLE hdb)
254 {
255 TCHAR *pszEscDescr, *pszEscVersion, *pszEscPlatform, *pszEscSecret;
256 TCHAR *pszEscCommunity, szQuery[4096], szIpAddr[16];
257 DB_RESULT hResult;
258 BOOL bNewObject = TRUE;
259 BOOL bResult;
260
261 // Lock object's access
262 LockData();
263
264 SaveCommonProperties(hdb);
265
266 // Check for object's existence in database
267 sprintf(szQuery, "SELECT id FROM nodes WHERE id=%d", m_dwId);
268 hResult = DBSelect(hdb, szQuery);
269 if (hResult != 0)
270 {
271 if (DBGetNumRows(hResult) > 0)
272 bNewObject = FALSE;
273 DBFreeResult(hResult);
274 }
275
276 // Form and execute INSERT or UPDATE query
277 pszEscDescr = EncodeSQLString(CHECK_NULL_EX(m_pszDescription));
278 pszEscVersion = EncodeSQLString(m_szAgentVersion);
279 pszEscPlatform = EncodeSQLString(m_szPlatformName);
280 pszEscSecret = EncodeSQLString(m_szSharedSecret);
281 pszEscCommunity = EncodeSQLString(m_szCommunityString);
282 if (bNewObject)
283 snprintf(szQuery, 4096,
284 "INSERT INTO nodes (id,primary_ip,"
285 "node_flags,snmp_version,community,status_poll_type,"
286 "agent_port,auth_method,secret,snmp_oid,proxy_node,"
287 "description,node_type,agent_version,platform_name,"
288 "poller_node_id,zone_guid) VALUES (%d,'%s',%d,%d,'%s',%d,%d,%d,"
289 "'%s','%s',%d,'%s',%d,'%s','%s',%d,%d)",
290 m_dwId, IpToStr(m_dwIpAddr, szIpAddr), m_dwFlags,
291 m_iSNMPVersion, pszEscCommunity, m_iStatusPollType,
292 m_wAgentPort, m_wAuthMethod, pszEscSecret, m_szObjectId,
293 m_dwProxyNode, pszEscDescr, m_dwNodeType, pszEscVersion,
294 pszEscPlatform, m_dwPollerNode, m_dwZoneGUID);
295 else
296 snprintf(szQuery, 4096,
297 "UPDATE nodes SET primary_ip='%s',"
298 "node_flags=%d,snmp_version=%d,community='%s',"
299 "status_poll_type=%d,agent_port=%d,auth_method=%d,secret='%s',"
300 "snmp_oid='%s',description='%s',node_type=%d,"
301 "agent_version='%s',platform_name='%s',poller_node_id=%d,"
302 "zone_guid=%d,proxy_node=%d WHERE id=%d",
303 IpToStr(m_dwIpAddr, szIpAddr),
304 m_dwFlags, m_iSNMPVersion, pszEscCommunity,
305 m_iStatusPollType, m_wAgentPort, m_wAuthMethod, pszEscSecret,
306 m_szObjectId, pszEscDescr, m_dwNodeType,
307 pszEscVersion, pszEscPlatform, m_dwPollerNode, m_dwZoneGUID,
308 m_dwProxyNode, m_dwId);
309 bResult = DBQuery(hdb, szQuery);
310 free(pszEscDescr);
311 free(pszEscVersion);
312 free(pszEscPlatform);
313 free(pszEscSecret);
314 free(pszEscCommunity);
315
316 // Save data collection items
317 if (bResult)
318 {
319 DWORD i;
320
321 for(i = 0; i < m_dwNumItems; i++)
322 m_ppItems[i]->SaveToDB(hdb);
323 }
324
325 // Save access list
326 SaveACLToDB(hdb);
327
328 // Clear modifications flag and unlock object
329 m_bIsModified = FALSE;
330 UnlockData();
331
332 return bResult;
333 }
334
335
336 //
337 // Delete object from database
338 //
339
340 BOOL Node::DeleteFromDB(void)
341 {
342 char szQuery[256];
343 BOOL bSuccess;
344
345 bSuccess = Template::DeleteFromDB();
346 if (bSuccess)
347 {
348 sprintf(szQuery, "DELETE FROM nodes WHERE id=%d", m_dwId);
349 QueueSQLRequest(szQuery);
350 sprintf(szQuery, "DELETE FROM nsmap WHERE node_id=%d", m_dwId);
351 QueueSQLRequest(szQuery);
352 sprintf(szQuery, "DROP TABLE idata_%d", m_dwId);
353 QueueSQLRequest(szQuery);
354 }
355 return bSuccess;
356 }
357
358
359 //
360 // Get ARP cache from node
361 //
362
363 ARP_CACHE *Node::GetArpCache(void)
364 {
365 ARP_CACHE *pArpCache = NULL;
366
367 if (m_dwFlags & NF_IS_LOCAL_MGMT)
368 {
369 pArpCache = GetLocalArpCache();
370 }
371 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
372 {
373 AgentLock();
374 if (ConnectToAgent())
375 pArpCache = m_pAgentConnection->GetArpCache();
376 AgentUnlock();
377 }
378 else if (m_dwFlags & NF_IS_SNMP)
379 {
380 pArpCache = SnmpGetArpCache(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort,
381 m_szCommunityString);
382 }
383
384 return pArpCache;
385 }
386
387
388 //
389 // Get list of interfaces from node
390 //
391
392 INTERFACE_LIST *Node::GetInterfaceList(void)
393 {
394 INTERFACE_LIST *pIfList = NULL;
395
396 if (m_dwFlags & NF_IS_LOCAL_MGMT)
397 {
398 pIfList = GetLocalInterfaceList();
399 }
400 if ((pIfList == NULL) && (m_dwFlags & NF_IS_NATIVE_AGENT) &&
401 (!(m_dwFlags & NF_DISABLE_NXCP)))
402 {
403 AgentLock();
404 if (ConnectToAgent())
405 {
406 pIfList = m_pAgentConnection->GetInterfaceList();
407 CleanInterfaceList(pIfList);
408 }
409 AgentUnlock();
410 }
411 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP) &&
412 (!(m_dwFlags & NF_DISABLE_SNMP)))
413 {
414 pIfList = SnmpGetInterfaceList(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort,
415 m_szCommunityString, m_dwNodeType);
416 }
417
418 if (pIfList != NULL)
419 CheckInterfaceNames(pIfList);
420
421 return pIfList;
422 }
423
424
425 //
426 // Find interface by index and node IP
427 // Returns pointer to interface object or NULL if appropriate interface couldn't be found
428 //
429
430 Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
431 {
432 DWORD i;
433 Interface *pInterface;
434
435 LockChildList(FALSE);
436 for(i = 0; i < m_dwChildCount; i++)
437 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
438 {
439 pInterface = (Interface *)m_pChildList[i];
440 if (pInterface->IfIndex() == dwIndex)
441 {
442 if (((pInterface->IpAddr() & pInterface->IpNetMask()) ==
443 (dwHostAddr & pInterface->IpNetMask())) ||
444 (dwHostAddr == INADDR_ANY))
445 {
446 UnlockChildList();
447 return pInterface;
448 }
449 }
450 }
451 UnlockChildList();
452 return NULL;
453 }
454
455
456 //
457 // Create new interface
458 //
459
460 void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName,
461 DWORD dwIndex, DWORD dwType, BYTE *pbMacAddr)
462 {
463 Interface *pInterface;
464 Subnet *pSubnet = NULL;
465
466 // Find subnet to place interface object to
467 if (dwIpAddr != 0)
468 {
469 pSubnet = FindSubnetForNode(dwIpAddr);
470 if (pSubnet == NULL)
471 {
472 // Check if netmask is 0 (detect), and if yes, create
473 // new subnet with class mask
474 if (dwNetMask == 0)
475 {
476 if (dwIpAddr < 0xE0000000)
477 {
478 dwNetMask = 0xFFFFFF00; // Class A, B or C
479 }
480 else
481 {
482 TCHAR szBuffer[16];
483
484 // Multicast address??
485 DbgPrintf(AF_DEBUG_DISCOVERY,
486 "Attempt to create interface object with multicast address %s",
487 IpToStr(dwIpAddr, szBuffer));
488 }
489 }
490
491 // Create new subnet object
492 if (dwIpAddr < 0xE0000000)
493 {
494 pSubnet = new Subnet(dwIpAddr & dwNetMask, dwNetMask, m_dwZoneGUID);
495 NetObjInsert(pSubnet, TRUE);
496 g_pEntireNet->AddSubnet(pSubnet);
497 }
498 }
499 else
500 {
501 // Set correct netmask if we was asked for it
502 if (dwNetMask == 0)
503 {
504 dwNetMask = pSubnet->IpNetMask();
505 }
506 }
507 }
508
509 // Create interface object
510 if (szName != NULL)
511 pInterface = new Interface(szName, dwIndex, dwIpAddr, dwNetMask, dwType);
512 else
513 pInterface = new Interface(dwIpAddr, dwNetMask);
514 if (pbMacAddr != NULL)
515 pInterface->SetMacAddr(pbMacAddr);
516
517 // Insert to objects' list and generate event
518 NetObjInsert(pInterface, TRUE);
519 AddInterface(pInterface);
520 if (!m_bIsHidden)
521 pInterface->Unhide();
522 PostEvent(EVENT_INTERFACE_ADDED, m_dwId, "dsaad", pInterface->Id(),
523 pInterface->Name(), pInterface->IpAddr(),
524 pInterface->IpNetMask(), pInterface->IfIndex());
525
526 // Bind node to appropriate subnet
527 if (pSubnet != NULL)
528 {
529 pSubnet->AddNode(this);
530
531 // Check if subnet mask is correct on interface
532 if (pSubnet->IpNetMask() != dwNetMask)
533 PostEvent(EVENT_INCORRECT_NETMASK, m_dwId, "idsaa", pInterface->Id(),
534 pInterface->IfIndex(), pInterface->Name(),
535 pInterface->IpNetMask(), pSubnet->IpNetMask());
536 }
537 }
538
539
540 //
541 // Delete interface from node
542 //
543
544 void Node::DeleteInterface(Interface *pInterface)
545 {
546 DWORD i;
547
548 // Check if we should unlink node from interface's subnet
549 if (pInterface->IpAddr() != 0)
550 {
551 BOOL bUnlink = TRUE;
552
553 LockChildList(FALSE);
554 for(i = 0; i < m_dwChildCount; i++)
555 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
556 if (m_pChildList[i] != pInterface)
557 if ((((Interface *)m_pChildList[i])->IpAddr() & ((Interface *)m_pChildList[i])->IpNetMask()) ==
558 (pInterface->IpAddr() & pInterface->IpNetMask()))
559 {
560 bUnlink = FALSE;
561 break;
562 }
563 UnlockChildList();
564
565 if (bUnlink)
566 {
567 // Last interface in subnet, should unlink node
568 Subnet *pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
569 if (pSubnet != NULL)
570 {
571 DeleteParent(pSubnet);
572 pSubnet->DeleteChild(this);
573 }
574 }
575 }
576 pInterface->Delete(FALSE);
577 }
578
579
580 //
581 // Calculate node status based on child objects status
582 //
583
584 void Node::CalculateCompoundStatus(void)
585 {
586 int iOldStatus = m_iStatus;
587 static DWORD dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_MINOR,
588 EVENT_NODE_WARNING, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
589 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
590
591 NetObj::CalculateCompoundStatus();
592 if (m_iStatus != iOldStatus)
593 PostEvent(dwEventCodes[m_iStatus], m_dwId, "d", iOldStatus);
594 }
595
596
597 //
598 // Perform status poll on node
599 //
600
601 void Node::StatusPoll(ClientSession *pSession, DWORD dwRqId, int nPoller)
602 {
603 DWORD i, dwPollListSize, dwOldFlags = m_dwFlags;
604 NetObj *pPollerNode = NULL, **ppPollList;
605 BOOL bAllDown;
606 Queue *pQueue; // Delayed event queue
607 time_t tNow, tExpire;
608
609 pQueue = new Queue;
610 SetPollerInfo(nPoller, "wait for lock");
611 PollerLock();
612 m_pPollRequestor = pSession;
613 SendPollerMsg(dwRqId, "Starting status poll for node %s\r\n", m_szName);
614
615 // Read capability expiration time and current time
616 tExpire = (time_t)ConfigReadULong(_T("CapabilityExpirationTime"), 604800);
617 tNow = time(NULL);
618
619 // Check SNMP agent connectivity
620 if ((m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)))
621 {
622 TCHAR szBuffer[256];
623 DWORD dwResult;
624
625 SetPollerInfo(nPoller, "check SNMP");
626 SendPollerMsg(dwRqId, "Checking SNMP agent connectivity\r\n");
627 dwResult = SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
628 ".1.3.6.1.2.1.1.2.0", NULL, 0, szBuffer, 256,
629 FALSE, FALSE);
630 if ((dwResult == SNMP_ERR_SUCCESS) || (dwResult == SNMP_ERR_NO_OBJECT))
631 {
632 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
633 {
634 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
635 PostEventEx(pQueue, EVENT_SNMP_OK, m_dwId, NULL);
636 SendPollerMsg(dwRqId, "Connectivity with SNMP agent restored\r\n");
637 }
638 }
639 else
640 {
641 SendPollerMsg(dwRqId, "SNMP agent unreachable\r\n");
642 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
643 {
644 if ((tNow > m_tFailTimeSNMP + tExpire) &&
645 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
646 {
647 m_dwFlags &= ~NF_IS_SNMP;
648 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
649 m_szObjectId[0] = 0;
650 SendPollerMsg(dwRqId, "Attribute isSNMP set to FALSE\r\n");
651 }
652 }
653 else
654 {
655 m_dwDynamicFlags |= NDF_SNMP_UNREACHABLE;
656 PostEventEx(pQueue, EVENT_SNMP_FAIL, m_dwId, NULL);
657 m_tFailTimeSNMP = tNow;
658 }
659 }
660 }
661
662 // Check native agent connectivity
663 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)))
664 {
665 AgentConnection *pAgentConn;
666
667 SetPollerInfo(nPoller, "check agent");
668 SendPollerMsg(dwRqId, "Checking NetXMS agent connectivity\r\n");
669 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
670 m_wAuthMethod, m_szSharedSecret);
671 SetAgentProxy(pAgentConn);
672 if (pAgentConn->Connect(g_pServerKey))
673 {
674 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
675 {
676 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
677 PostEventEx(pQueue, EVENT_AGENT_OK, m_dwId, NULL);
678 SendPollerMsg(dwRqId, "Connectivity with NetXMS agent restored\r\n");
679 }
680 pAgentConn->Disconnect();
681 }
682 else
683 {
684 SendPollerMsg(dwRqId, "NetXMS agent unreachable\r\n");
685 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
686 {
687 if ((tNow > m_tFailTimeAgent + tExpire) &&
688 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
689 {
690 m_dwFlags &= ~NF_IS_NATIVE_AGENT;
691 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
692 m_szPlatformName[0] = 0;
693 m_szAgentVersion[0] = 0;
694 SendPollerMsg(dwRqId, "Attribute isNetXMSAgent set to FALSE\r\n");
695 }
696 }
697 else
698 {
699 m_dwDynamicFlags |= NDF_AGENT_UNREACHABLE;
700 PostEventEx(pQueue, EVENT_AGENT_FAIL, m_dwId, NULL);
701 m_tFailTimeAgent = tNow;
702 }
703 }
704 delete pAgentConn;
705 }
706
707 SetPollerInfo(nPoller, "prepare polling list");
708
709 // Find service poller node object
710 LockData();
711 if (m_dwPollerNode != 0)
712 {
713 pPollerNode = FindObjectById(m_dwPollerNode);
714 if (pPollerNode != NULL)
715 {
716 if (pPollerNode->Type() != OBJECT_NODE)
717 pPollerNode = NULL;
718 }
719 }
720 UnlockData();
721
722 // If nothing found, use management server
723 if (pPollerNode == NULL)
724 {
725 pPollerNode = FindObjectById(g_dwMgmtNode);
726 if (pPollerNode != NULL)
727 pPollerNode->IncRefCount();
728 }
729 else
730 {
731 pPollerNode->IncRefCount();
732 }
733
734 // Create polling list
735 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_dwChildCount);
736 LockChildList(FALSE);
737 for(i = 0, dwPollListSize = 0; i < m_dwChildCount; i++)
738 if (m_pChildList[i]->Status() != STATUS_UNMANAGED)
739 {
740 m_pChildList[i]->IncRefCount();
741 ppPollList[dwPollListSize++] = m_pChildList[i];
742 }
743 UnlockChildList();
744
745 // Poll interfaces and services
746 SetPollerInfo(nPoller, "child poll");
747 for(i = 0; i < dwPollListSize; i++)
748 {
749 switch(ppPollList[i]->Type())
750 {
751 case OBJECT_INTERFACE:
752 ((Interface *)ppPollList[i])->StatusPoll(pSession, dwRqId, pQueue);
753 break;
754 case OBJECT_NETWORKSERVICE:
755 ((NetworkService *)ppPollList[i])->StatusPoll(pSession, dwRqId,
756 (Node *)pPollerNode, pQueue);
757 break;
758 default:
759 break;
760 }
761 ppPollList[i]->DecRefCount();
762 }
763 safe_free(ppPollList);
764
765 // Check if entire node is down
766 LockChildList(FALSE);
767 for(i = 0, bAllDown = TRUE; i < m_dwChildCount; i++)
768 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
769 (m_pChildList[i]->Status() != STATUS_CRITICAL) &&
770 (m_pChildList[i]->Status() != STATUS_UNKNOWN) &&
771 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
772 (m_pChildList[i]->Status() != STATUS_DISABLED))
773 {
774 bAllDown = FALSE;
775 break;
776 }
777 UnlockChildList();
778 if (bAllDown && (m_dwFlags & NF_IS_NATIVE_AGENT) &&
779 (!(m_dwFlags & NF_DISABLE_NXCP)))
780 if (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))
781 bAllDown = FALSE;
782 if (bAllDown && (m_dwFlags & NF_IS_SNMP) &&
783 (!(m_dwFlags & NF_DISABLE_SNMP)))
784 if (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))
785 bAllDown = FALSE;
786 if (bAllDown)
787 {
788 if (!(m_dwDynamicFlags & NDF_UNREACHABLE))
789 {
790 m_dwDynamicFlags |= NDF_UNREACHABLE;
791 PostEvent(EVENT_NODE_DOWN, m_dwId, NULL);
792 SendPollerMsg(dwRqId, "Node is unreachable\r\n");
793 }
794 else
795 {
796 SendPollerMsg(dwRqId, "Node is still unreachable\r\n");
797 }
798 }
799 else
800 {
801 if (m_dwDynamicFlags & NDF_UNREACHABLE)
802 {
803 m_dwDynamicFlags &= ~NDF_UNREACHABLE;
804 PostEvent(EVENT_NODE_UP, m_dwId, NULL);
805 SendPollerMsg(dwRqId, "Node recovered from unreachable state\r\n");
806 }
807 else
808 {
809 SendPollerMsg(dwRqId, "Node is connected\r\n");
810 }
811 }
812
813 // Send delayed events and destroy delayed event queue
814 ResendEvents(pQueue);
815 delete pQueue;
816
817 SetPollerInfo(nPoller, "cleanup");
818 if (pPollerNode != NULL)
819 pPollerNode->DecRefCount();
820
821 if (dwOldFlags != m_dwFlags)
822 {
823 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
824 LockData();
825 Modify();
826 UnlockData();
827 }
828
829 CalculateCompoundStatus();
830 m_tLastStatusPoll = time(NULL);
831 SendPollerMsg(dwRqId, "Finished status poll for node %s\r\n"
832 "Node status after poll is %s\r\n", m_szName, g_pszStatusName[m_iStatus]);
833 m_pPollRequestor = NULL;
834 if (dwRqId == 0)
835 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_STATUS_POLL;
836 PollerUnlock();
837 }
838
839
840 //
841 // Perform configuration poll on node
842 //
843
844 void Node::ConfigurationPoll(ClientSession *pSession, DWORD dwRqId,
845 int nPoller, DWORD dwNetMask)
846 {
847 DWORD i, dwOldFlags = m_dwFlags;
848 Interface **ppDeleteList;
849 int j, iDelCount;
850 AgentConnection *pAgentConn;
851 INTERFACE_LIST *pIfList;
852 char szBuffer[4096];
853 BOOL bHasChanges = FALSE;
854
855 SetPollerInfo(nPoller, "wait for lock");
856 PollerLock();
857 m_pPollRequestor = pSession;
858 SendPollerMsg(dwRqId, _T("Starting configuration poll for node %s\r\n"), m_szName);
859 DbgPrintf(AF_DEBUG_DISCOVERY, "Starting configuration poll for node %s (ID: %d)", m_szName, m_dwId);
860
861 // Check for forced capabilities recheck
862 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
863 {
864 m_dwDynamicFlags &= ~(NDF_UNREACHABLE | NDF_SNMP_UNREACHABLE |
865 NDF_CPSNMP_UNREACHABLE | NDF_AGENT_UNREACHABLE);
866 m_dwFlags &= ~(NF_IS_NATIVE_AGENT | NF_IS_SNMP | NF_IS_CPSNMP |
867 NF_IS_BRIDGE | NF_IS_ROUTER | NF_IS_OSPF);
868 m_szObjectId[0] = 0;
869 m_szPlatformName[0] = 0;
870 m_szAgentVersion[0] = 0;
871 }
872
873 // Check if node is marked as unreachable
874 if (m_dwDynamicFlags & NDF_UNREACHABLE)
875 {
876 SendPollerMsg(dwRqId, _T("Node is marked as unreachable, configuration poll aborted\r\n"));
877 DbgPrintf(AF_DEBUG_DISCOVERY, "Node is marked as unreachable, configuration poll aborted");
878 m_tLastConfigurationPoll = time(NULL);
879 }
880 else
881 {
882 // Check node's capabilities
883 SetPollerInfo(nPoller, "capability check");
884 SendPollerMsg(dwRqId, _T("Checking node's capabilities...\r\n"));
885 if ((!((m_dwFlags & NF_IS_SNMP) && (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))) &&
886 (!(m_dwFlags & NF_DISABLE_SNMP)))
887 {
888 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): trying SNMP GET", m_szName);
889 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
890 ".1.3.6.1.2.1.1.2.0", NULL, 0, szBuffer, 4096,
891 FALSE, FALSE) == SNMP_ERR_SUCCESS)
892 {
893 DWORD dwNodeFlags, dwNodeType;
894
895 LockData();
896
897 if (strcmp(m_szObjectId, szBuffer))
898 {
899 nx_strncpy(m_szObjectId, szBuffer, MAX_OID_LEN * 4);
900 bHasChanges = TRUE;
901 }
902
903 m_dwFlags |= NF_IS_SNMP;
904 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
905 SendPollerMsg(dwRqId, _T(" SNMP agent is active\r\n"));
906
907 // Check node type
908 dwNodeType = OidToType(m_szObjectId, &dwNodeFlags);
909 if (m_dwNodeType != dwNodeType)
910 {
911 m_dwFlags |= dwNodeFlags;
912 m_dwNodeType = dwNodeType;
913 SendPollerMsg(dwRqId, _T(" Node type has been changed to %d\r\n"), m_dwNodeType);
914 bHasChanges = TRUE;
915 }
916
917 // Check IP forwarding
918 if (CheckSNMPIntegerValue(".1.3.6.1.2.1.4.1.0", 1))
919 {
920 m_dwFlags |= NF_IS_ROUTER;
921 }
922 else
923 {
924 m_dwFlags &= ~NF_IS_ROUTER;
925 }
926
927 // Check for bridge MIB support
928 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
929 ".1.3.6.1.2.1.17.1.1.0", NULL, 0, szBuffer, 4096,
930 FALSE, FALSE) == SNMP_ERR_SUCCESS)
931 {
932 m_dwFlags |= NF_IS_BRIDGE;
933 }
934 else
935 {
936 m_dwFlags &= ~NF_IS_BRIDGE;
937 }
938
939 // Check for CDP (Cisco Discovery Protocol) support
940 if (CheckSNMPIntegerValue(".1.3.6.1.4.1.9.9.23.1.3.1.0", 1))
941 {
942 m_dwFlags |= NF_IS_CDP;
943 }
944 else
945 {
946 m_dwFlags &= ~NF_IS_CDP;
947 }
948
949 // Check for Nortel topology discovery support
950 if (CheckSNMPIntegerValue(".1.3.6.1.4.1.45.1.6.13.1.2.0", 1))
951 {
952 m_dwFlags |= NF_IS_NORTEL_TOPO;
953 }
954 else
955 {
956 m_dwFlags &= ~NF_IS_NORTEL_TOPO;
957 }
958
959 UnlockData();
960
961 CheckOSPFSupport();
962 }
963 else
964 {
965 // Check for CheckPoint SNMP agent on port 161
966 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for CheckPoint SNMP", m_szName);
967 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
968 ".1.3.6.1.4.1.2620.1.1.10.0", NULL, 0,
969 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
970 {
971 LockData();
972 if (strcmp(m_szObjectId, ".1.3.6.1.4.1.2620.1.1"))
973 {
974 nx_strncpy(m_szObjectId, ".1.3.6.1.4.1.2620.1.1", MAX_OID_LEN * 4);
975 bHasChanges = TRUE;
976 }
977
978 m_dwFlags |= NF_IS_SNMP | NF_IS_ROUTER;
979 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
980 UnlockData();
981 SendPollerMsg(dwRqId, _T(" CheckPoint SNMP agent on port 161 is active\r\n"));
982 }
983 }
984 }
985
986 // Check for CheckPoint SNMP agent on port 260
987 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for CheckPoint SNMP on port 260", m_szName);
988 if (!((m_dwFlags & NF_IS_CPSNMP) && (m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE)))
989 {
990 if (SnmpGet(SNMP_VERSION_1, m_dwIpAddr, CHECKPOINT_SNMP_PORT, m_szCommunityString,
991 ".1.3.6.1.4.1.2620.1.1.10.0", NULL, 0,
992 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
993 {
994 LockData();
995 m_dwFlags |= NF_IS_CPSNMP | NF_IS_ROUTER;
996 m_dwDynamicFlags &= ~NDF_CPSNMP_UNREACHABLE;
997 UnlockData();
998 SendPollerMsg(dwRqId, _T(" CheckPoint SNMP agent on port 260 is active\r\n"));
999 }
1000 }
1001
1002 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for NetXMS agent Flags={%08X} DynamicFlags={%08X}", m_szName, m_dwFlags, m_dwDynamicFlags);
1003 if ((!((m_dwFlags & NF_IS_NATIVE_AGENT) && (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))) &&
1004 (!(m_dwFlags & NF_DISABLE_NXCP)))
1005 {
1006 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
1007 m_wAuthMethod, m_szSharedSecret);
1008 SetAgentProxy(pAgentConn);
1009 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for NetXMS agent - connecting", m_szName);
1010 if (pAgentConn->Connect(g_pServerKey))
1011 {
1012 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for NetXMS agent - connected", m_szName);
1013 LockData();
1014 m_dwFlags |= NF_IS_NATIVE_AGENT;
1015 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1016 UnlockData();
1017
1018 if (pAgentConn->GetParameter("Agent.Version", MAX_AGENT_VERSION_LEN, szBuffer) == ERR_SUCCESS)
1019 {
1020 LockData();
1021 if (strcmp(m_szAgentVersion, szBuffer))
1022 {
1023 strcpy(m_szAgentVersion, szBuffer);
1024 bHasChanges = TRUE;
1025 SendPollerMsg(dwRqId, _T(" NetXMS agent version changed to %s\r\n"), m_szAgentVersion);
1026 }
1027 UnlockData();
1028 }
1029
1030 if (pAgentConn->GetParameter("System.PlatformName", MAX_PLATFORM_NAME_LEN, szBuffer) == ERR_SUCCESS)
1031 {
1032 LockData();
1033 if (strcmp(m_szPlatformName, szBuffer))
1034 {
1035 strcpy(m_szPlatformName, szBuffer);
1036 bHasChanges = TRUE;
1037 SendPollerMsg(dwRqId, _T(" Platform name changed to %s\r\n"), m_szPlatformName);
1038 }
1039 UnlockData();
1040 }
1041
1042 // Check IP forwarding status
1043 if (pAgentConn->GetParameter("Net.IP.Forwarding", 16, szBuffer) == ERR_SUCCESS)
1044 {
1045 if (_tcstoul(szBuffer, NULL, 10) != 0)
1046 m_dwFlags |= NF_IS_ROUTER;
1047 else
1048 m_dwFlags &= ~NF_IS_ROUTER;
1049 }
1050
1051 /* LOCK? */
1052 safe_free(m_pParamList);
1053 pAgentConn->GetSupportedParameters(&m_dwNumParams, &m_pParamList);
1054
1055 pAgentConn->Disconnect();
1056 SendPollerMsg(dwRqId, _T(" NetXMS native agent is active\r\n"));
1057 }
1058 delete pAgentConn;
1059 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for NetXMS agent - finished", m_szName);
1060 }
1061
1062 // Generate event if node flags has been changed
1063 if (dwOldFlags != m_dwFlags)
1064 {
1065 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
1066 bHasChanges = TRUE;
1067 }
1068
1069 // Retrieve interface list
1070 SetPollerInfo(nPoller, "interface check");
1071 SendPollerMsg(dwRqId, _T("Capability check finished\r\n"
1072 "Checking interface configuration...\r\n"));
1073 pIfList = GetInterfaceList();
1074 if (pIfList != NULL)
1075 {
1076 // Find non-existing interfaces
1077 LockChildList(FALSE);
1078 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
1079 for(i = 0, iDelCount = 0; i < m_dwChildCount; i++)
1080 {
1081 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1082 {
1083 Interface *pInterface = (Interface *)m_pChildList[i];
1084
1085 if (pInterface->IfType() != IFTYPE_NETXMS_NAT_ADAPTER)
1086 {
1087 for(j = 0; j < pIfList->iNumEntries; j++)
1088 {
1089 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
1090 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
1091 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
1092 break;
1093 }
1094
1095 if (j == pIfList->iNumEntries)
1096 {
1097 // No such interface in current configuration, add it to delete list
1098 ppDeleteList[iDelCount++] = pInterface;
1099 }
1100 }
1101 }
1102 }
1103 UnlockChildList();
1104
1105 // Delete non-existent interfaces
1106 if (iDelCount > 0)
1107 {
1108 for(j = 0; j < iDelCount; j++)
1109 {
1110 SendPollerMsg(dwRqId, _T(" Interface \"%s\" is no longer exist\r\n"),
1111 ppDeleteList[j]->Name());
1112 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->IfIndex(),
1113 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->IpNetMask());
1114 DeleteInterface(ppDeleteList[j]);
1115 }
1116 bHasChanges = TRUE;
1117 }
1118 safe_free(ppDeleteList);
1119
1120 // Add new interfaces and check configuration of existing
1121 for(j = 0; j < pIfList->iNumEntries; j++)
1122 {
1123 BOOL bNewInterface = TRUE;
1124
1125 LockChildList(FALSE);
1126 for(i = 0; i < m_dwChildCount; i++)
1127 {
1128 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1129 {
1130 Interface *pInterface = (Interface *)m_pChildList[i];
1131
1132 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
1133 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
1134 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
1135 {
1136 // Existing interface, check configuration
1137 if (memcmp(pIfList->pInterfaces[j].bMacAddr, pInterface->MacAddr(), MAC_ADDR_LENGTH))
1138 {
1139 char szOldMac[16], szNewMac[16];
1140
1141 BinToStr((BYTE *)pInterface->MacAddr(), MAC_ADDR_LENGTH, szOldMac);
1142 BinToStr(pIfList->pInterfaces[j].bMacAddr, MAC_ADDR_LENGTH, szNewMac);
1143 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
1144 pInterface->Id(), pInterface->IfIndex(),
1145 pInterface->Name(), szOldMac, szNewMac);
1146 pInterface->SetMacAddr(pIfList->pInterfaces[j].bMacAddr);
1147 }
1148 if (strcmp(pIfList->pInterfaces[j].szName, pInterface->Name()))
1149 {
1150 pInterface->SetName(pIfList->pInterfaces[j].szName);
1151 }
1152 bNewInterface = FALSE;
1153 break;
1154 }
1155 }
1156 }
1157 UnlockChildList();
1158
1159 if (bNewInterface)
1160 {
1161 // New interface
1162 SendPollerMsg(dwRqId, _T(" Found new interface \"%s\"\r\n"),
1163 pIfList->pInterfaces[j].szName);
1164 CreateNewInterface(pIfList->pInterfaces[j].dwIpAddr,
1165 pIfList->pInterfaces[j].dwIpNetMask,
1166 pIfList->pInterfaces[j].szName,
1167 pIfList->pInterfaces[j].dwIndex,
1168 pIfList->pInterfaces[j].dwType,
1169 pIfList->pInterfaces[j].bMacAddr);
1170 bHasChanges = TRUE;
1171 }
1172 }
1173
1174 // Check if address we are using to communicate with node
1175 // is configured on one of node's interfaces
1176 for(i = 0; i < (DWORD)pIfList->iNumEntries; i++)
1177 if (pIfList->pInterfaces[i].dwIpAddr == m_dwIpAddr)
1178 break;
1179
1180 if (i == (DWORD)pIfList->iNumEntries)
1181 {
1182 BOOL bCreate = TRUE;
1183
1184 // Node is behind NAT
1185 m_dwFlags |= NF_BEHIND_NAT;
1186
1187 // Check if we already have NAT interface
1188 LockChildList(FALSE);
1189 for(i = 0; i < m_dwChildCount; i++)
1190 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1191 {
1192 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1193 {
1194 bCreate = FALSE;
1195 break;
1196 }
1197 }
1198 UnlockChildList();
1199
1200 if (bCreate)
1201 {
1202 char szBuffer[MAX_OBJECT_NAME];
1203
1204 // Create pseudo interface for NAT
1205 ConfigReadStr("NATAdapterName", szBuffer, MAX_OBJECT_NAME, "NetXMS NAT Adapter");
1206 CreateNewInterface(m_dwIpAddr, 0, szBuffer,
1207 0x7FFFFFFF, IFTYPE_NETXMS_NAT_ADAPTER);
1208 bHasChanges = TRUE;
1209 }
1210 }
1211 else
1212 {
1213 // Check if NF_BEHIND_NAT flag set incorrectly
1214 if (m_dwFlags & NF_BEHIND_NAT)
1215 {
1216 Interface *pIfNat;
1217
1218 // Remove NAT interface
1219 LockChildList(FALSE);
1220 for(i = 0, pIfNat = NULL; i < m_dwChildCount; i++)
1221 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1222 {
1223 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1224 {
1225 pIfNat = (Interface *)m_pChildList[i];
1226 break;
1227 }
1228 }
1229 UnlockChildList();
1230
1231 if (pIfNat != NULL)
1232 DeleteInterface(pIfNat);
1233
1234 m_dwFlags &= ~NF_BEHIND_NAT;
1235 bHasChanges = TRUE;
1236 }
1237 }
1238
1239 DestroyInterfaceList(pIfList);
1240 }
1241 else /* pIfList == NULL */
1242 {
1243 Interface *pInterface;
1244 DWORD dwCount;
1245
1246 SendPollerMsg(dwRqId, _T(" Unable to get interface list from node\r\n"));
1247
1248 // Delete all existing interfaces in case of forced capability recheck
1249 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
1250 {
1251 LockChildList(FALSE);
1252 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
1253 for(i = 0, iDelCount = 0; i < m_dwChildCount; i++)
1254 {
1255 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1256 ppDeleteList[iDelCount++] = (Interface *)m_pChildList[i];
1257 }
1258 UnlockChildList();
1259 for(j = 0; j < iDelCount; j++)
1260 {
1261 SendPollerMsg(dwRqId, _T(" Interface \"%s\" is no longer exist\r\n"),
1262 ppDeleteList[j]->Name());
1263 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->IfIndex(),
1264 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->IpNetMask());
1265 DeleteInterface(ppDeleteList[j]);
1266 }
1267 safe_free(ppDeleteList);
1268 }
1269
1270 // Check if we have pseudo-interface object
1271 dwCount = GetInterfaceCount(&pInterface);
1272 if (dwCount == 1)
1273 {
1274 if (pInterface->IsFake())
1275 {
1276 // Check if primary IP is different from interface's IP
1277 if (pInterface->IpAddr() != m_dwIpAddr)
1278 {
1279 DeleteInterface(pInterface);
1280 CreateNewInterface(m_dwIpAddr, dwNetMask);
1281 }
1282 }
1283 }
1284 else if (dwCount == 0)
1285 {
1286 // No interfaces at all, create pseudo-interface
1287 CreateNewInterface(m_dwIpAddr, dwNetMask);
1288 }
1289 }
1290
1291 m_tLastConfigurationPoll = time(NULL);
1292 SendPollerMsg(dwRqId, _T("Interface configuration check finished\r\n"
1293 "Finished configuration poll for node %s\r\n"
1294 "Node configuration was%schanged after poll\r\n"),
1295 m_szName, bHasChanges ? _T(" ") : _T(" not "));
1296 }
1297
1298 // Finish configuration poll
1299 SetPollerInfo(nPoller, "cleanup");
1300 if (dwRqId == 0)
1301 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1302 m_dwDynamicFlags &= ~NDF_RECHECK_CAPABILITIES;
1303 PollerUnlock();
1304 DbgPrintf(AF_DEBUG_DISCOVERY, "Finished configuration poll for node %s (ID: %d)", m_szName, m_dwId);
1305
1306 if (bHasChanges)
1307 {
1308 LockData();
1309 Modify();
1310 UnlockData();
1311 }
1312 }
1313
1314
1315 //
1316 // Connect to native agent
1317 //
1318
1319 BOOL Node::ConnectToAgent(void)
1320 {
1321 BOOL bRet;
1322
1323 // Create new agent connection object if needed
1324 if (m_pAgentConnection == NULL)
1325 m_pAgentConnection = new AgentConnectionEx(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
1326
1327 // Check if we already connected
1328 if (m_pAgentConnection->Nop() == ERR_SUCCESS)
1329 return TRUE;
1330
1331 // Close current connection or clean up after broken connection
1332 m_pAgentConnection->Disconnect();
1333 m_pAgentConnection->SetPort(m_wAgentPort);
1334 m_pAgentConnection->SetAuthData(m_wAuthMethod, m_szSharedSecret);
1335 SetAgentProxy(m_pAgentConnection);
1336 bRet = m_pAgentConnection->Connect(g_pServerKey);
1337 if (bRet)
1338 m_pAgentConnection->EnableTraps();
1339 return bRet;
1340 }
1341
1342
1343 //
1344 // Get item's value via SNMP
1345 //
1346
1347 DWORD Node::GetItemFromSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1348 {
1349 DWORD dwResult;
1350
1351 if ((m_dwDynamicFlags & NDF_SNMP_UNREACHABLE) ||
1352 (m_dwDynamicFlags & NDF_UNREACHABLE))
1353 {
1354 dwResult = SNMP_ERR_COMM;
1355 }
1356 else
1357 {
1358 dwResult = SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
1359 szParam, NULL, 0, szBuffer, dwBufSize, FALSE, TRUE);
1360 }
1361 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
1362 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
1363 }
1364
1365
1366 //
1367 // Get item's value via SNMP from CheckPoint's agent
1368 //
1369
1370 DWORD Node::GetItemFromCheckPointSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1371 {
1372 DWORD dwResult;
1373
1374 if ((m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE) ||
1375 (m_dwDynamicFlags & NDF_UNREACHABLE))
1376 {
1377 dwResult = SNMP_ERR_COMM;
1378 }
1379 else
1380 {
1381 dwResult = SnmpGet(SNMP_VERSION_1, m_dwIpAddr, CHECKPOINT_SNMP_PORT,
1382 m_szCommunityString, szParam, NULL, 0, szBuffer,
1383 dwBufSize, FALSE, TRUE);
1384 }
1385 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
1386 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
1387 }
1388
1389
1390 //
1391 // Get item's value via native agent
1392 //
1393
1394 DWORD Node::GetItemFromAgent(const char *szParam, DWORD dwBufSize, char *szBuffer)
1395 {
1396 DWORD dwError, dwResult = DCE_COMM_ERROR;
1397 DWORD dwTries = 5;
1398
1399 if ((m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
1400 (m_dwDynamicFlags & NDF_UNREACHABLE))
1401 return DCE_COMM_ERROR;
1402
1403 AgentLock();
1404
1405 // Establish connection if needed
1406 if (m_pAgentConnection == NULL)
1407 if (!ConnectToAgent())
1408 goto end_loop;
1409
1410 // Get parameter from agent
1411 while(dwTries-- > 0)
1412 {
1413 dwError = m_pAgentConnection->GetParameter((char *)szParam, dwBufSize, szBuffer);
1414 switch(dwError)
1415 {
1416 case ERR_SUCCESS:
1417 dwResult = DCE_SUCCESS;
1418 goto end_loop;
1419 case ERR_UNKNOWN_PARAMETER:
1420 dwResult = DCE_NOT_SUPPORTED;
1421 goto end_loop;
1422 case ERR_NOT_CONNECTED:
1423 case ERR_CONNECTION_BROKEN:
1424 if (!ConnectToAgent())
1425 goto end_loop;
1426 break;
1427 case ERR_REQUEST_TIMEOUT:
1428 break;
1429 }
1430 }
1431
1432 end_loop:
1433 AgentUnlock();
1434 DbgPrintf(AF_DEBUG_DC, "Node(%s)->GetItemFromAgent(%s): dwError=%d dwResult=%d",
1435 m_szName, szParam, dwError, dwResult);
1436 return dwResult;
1437 }
1438
1439
1440 //
1441 // Get value for server's internal parameter
1442 //
1443
1444 DWORD Node::GetInternalItem(const char *szParam, DWORD dwBufSize, char *szBuffer)
1445 {
1446 DWORD dwError = DCE_SUCCESS;
1447
1448 if (!stricmp(szParam, "status"))
1449 {
1450 sprintf(szBuffer, "%d", m_iStatus);
1451 }
1452 else if (!stricmp(szParam, "AgentStatus"))
1453 {
1454 if (m_dwFlags & NF_IS_NATIVE_AGENT)
1455 {
1456 szBuffer[0] = (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ? '1' : '0';
1457 szBuffer[1] = 0;
1458 }
1459 else
1460 {
1461 dwError = DCE_NOT_SUPPORTED;
1462 }
1463 }
1464 else if (MatchString("ChildStatus(*)", szParam, FALSE))
1465 {
1466 char *pEnd, szArg[256];
1467 DWORD i, dwId;
1468 NetObj *pObject = NULL;
1469
1470 NxGetParameterArg((char *)szParam, 1, szArg, 256);
1471 dwId = strtoul(szArg, &pEnd, 0);
1472 if (*pEnd != 0)
1473 {
1474 // Argument is object's name
1475 dwId = 0;
1476 }
1477
1478 // Find child object with requested ID or name
1479 LockChildList(FALSE);
1480 for(i = 0; i < m_dwChildCount; i++)
1481 {
1482 if (((dwId == 0) && (!stricmp(m_pChildList[i]->Name(), szArg))) ||
1483 (dwId == m_pChildList[i]->Id()))
1484 {
1485 pObject = m_pChildList[i];
1486 break;
1487 }
1488 }
1489 UnlockChildList();
1490
1491 if (pObject != NULL)
1492 {
1493 sprintf(szBuffer, "%d", pObject->Status());
1494 }
1495 else
1496 {
1497 dwError = DCE_NOT_SUPPORTED;
1498 }
1499 }
1500 else if (m_dwFlags & NF_IS_LOCAL_MGMT)
1501 {
1502 if (!stricmp(szParam, "Server.AverageDCPollerQueueSize"))
1503 {
1504 sprintf(szBuffer, "%f", g_dAvgPollerQueueSize);
1505 }
1506 else if (!stricmp(szParam, "Server.AverageDBWriterQueueSize"))
1507 {
1508 sprintf(szBuffer, "%f", g_dAvgDBWriterQueueSize);
1509 }
1510 else if (!stricmp(szParam, "Server.AverageStatusPollerQueueSize"))
1511 {
1512 sprintf(szBuffer, "%f", g_dAvgStatusPollerQueueSize);
1513 }
1514 else if (!stricmp(szParam, "Server.AverageConfigurationPollerQueueSize"))
1515 {
1516 sprintf(szBuffer, "%f", g_dAvgConfigPollerQueueSize);
1517 }
1518 else if (!stricmp(szParam, "Server.AverageDCIQueuingTime"))
1519 {
1520 sprintf(szBuffer, "%u", g_dwAvgDCIQueuingTime);
1521 }
1522 else
1523 {
1524 dwError = DCE_NOT_SUPPORTED;
1525 }
1526 }
1527 else
1528 {
1529 dwError = DCE_NOT_SUPPORTED;
1530 }
1531
1532 return dwError;
1533 }
1534
1535
1536 //
1537 // Get item's value for client
1538 //
1539
1540 DWORD Node::GetItemForClient(int iOrigin, const char *pszParam, char *pszBuffer, DWORD dwBufSize)
1541 {
1542 DWORD dwResult = 0, dwRetCode;
1543
1544 // Get data from node
1545 switch(iOrigin)
1546 {
1547 case DS_INTERNAL:
1548 dwRetCode = GetInternalItem(pszParam, dwBufSize, pszBuffer);
1549 break;
1550 case DS_NATIVE_AGENT:
1551 dwRetCode = GetItemFromAgent(pszParam, dwBufSize, pszBuffer);
1552 break;
1553 case DS_SNMP_AGENT:
1554 dwRetCode = GetItemFromSNMP(pszParam, dwBufSize, pszBuffer);
1555 break;
1556 case DS_CHECKPOINT_AGENT:
1557 dwRetCode = GetItemFromCheckPointSNMP(pszParam, dwBufSize, pszBuffer);
1558 break;
1559 default:
1560 dwResult = RCC_INVALID_ARGUMENT;
1561 break;
1562 }
1563
1564 // Translate return code to RCC
1565 if (dwResult != RCC_INVALID_ARGUMENT)
1566 {
1567 switch(dwRetCode)
1568 {
1569 case DCE_SUCCESS:
1570 dwResult = RCC_SUCCESS;
1571 break;
1572 case DCE_COMM_ERROR:
1573 dwResult = RCC_COMM_FAILURE;
1574 break;
1575 case DCE_NOT_SUPPORTED:
1576 dwResult = RCC_DCI_NOT_SUPPORTED;
1577 break;
1578 default:
1579 dwResult = RCC_SYSTEM_FAILURE;
1580 break;
1581 }
1582 }
1583
1584 return dwResult;
1585 }
1586
1587
1588 //
1589 // Put items which requires polling into the queue
1590 //
1591
1592 void Node::QueueItemsForPolling(Queue *pPollerQueue)
1593 {
1594 DWORD i;
1595 time_t currTime;
1596
1597 if (m_iStatus == STATUS_UNMANAGED)
1598 return; // Do not collect data for unmanaged nodes
1599
1600 currTime = time(NULL);
1601
1602 LockData();
1603 for(i = 0; i < m_dwNumItems; i++)
1604 {
1605 if (m_ppItems[i]->ReadyForPolling(currTime))
1606 {
1607 m_ppItems[i]->SetBusyFlag(TRUE);
1608 IncRefCount(); // Increment reference count for each queued DCI
1609 pPollerQueue->Put(m_ppItems[i]);
1610 }
1611 }
1612 UnlockData();
1613 }
1614
1615
1616 //
1617 // Create CSCP message with object's data
1618 //
1619
1620 void Node::CreateMessage(CSCPMessage *pMsg)
1621 {
1622 Template::CreateMessage(pMsg);
1623 pMsg->SetVariable(VID_FLAGS, m_dwFlags);
1624 pMsg->SetVariable(VID_AGENT_PORT, m_wAgentPort);
1625 pMsg->SetVariable(VID_AUTH_METHOD, m_wAuthMethod);
1626 pMsg->SetVariable(VID_SHARED_SECRET, m_szSharedSecret);
1627 pMsg->SetVariable(VID_COMMUNITY_STRING, m_szCommunityString);
1628 pMsg->SetVariable(VID_SNMP_OID, m_szObjectId);
1629 pMsg->SetVariable(VID_NODE_TYPE, m_dwNodeType);
1630 pMsg->SetVariable(VID_SNMP_VERSION, (WORD)m_iSNMPVersion);
1631 pMsg->SetVariable(VID_AGENT_VERSION, m_szAgentVersion);
1632 pMsg->SetVariable(VID_PLATFORM_NAME, m_szPlatformName);
1633 pMsg->SetVariable(VID_POLLER_NODE_ID, m_dwPollerNode);
1634 pMsg->SetVariable(VID_ZONE_GUID, m_dwZoneGUID);
1635 pMsg->SetVariable(VID_PROXY_NODE, m_dwProxyNode);
1636 }
1637
1638
1639 //
1640 // Modify object from message
1641 //
1642
1643 DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
1644 {
1645 if (!bAlreadyLocked)
1646 LockData();
1647
1648 // Change primary IP address
1649 if (pRequest->IsVariableExist(VID_IP_ADDRESS))
1650 {
1651 DWORD i, dwIpAddr;
1652
1653 dwIpAddr = pRequest->GetVariableLong(VID_IP_ADDRESS);
1654
1655 // Check if received IP address is one of node's interface addresses
1656 LockChildList(FALSE);
1657 for(i = 0; i < m_dwChildCount; i++)
1658 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1659 (m_pChildList[i]->IpAddr() == dwIpAddr))
1660 break;
1661 UnlockChildList();
1662 if (i == m_dwChildCount)
1663 {
1664 UnlockData();
1665 return RCC_INVALID_IP_ADDR;
1666 }
1667
1668 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
1669 m_dwIpAddr = dwIpAddr;
1670 }
1671
1672 // Poller node ID
1673 if (pRequest->IsVariableExist(VID_POLLER_NODE_ID))
1674 {
1675 DWORD dwNodeId;
1676 NetObj *pObject;
1677
1678 dwNodeId = pRequest->GetVariableLong(VID_POLLER_NODE_ID);
1679 pObject = FindObjectById(dwNodeId);
1680
1681 // Check if received id is a valid node id
1682 if (pObject == NULL)
1683 {
1684 UnlockData();
1685 return RCC_INVALID_OBJECT_ID;
1686 }
1687 if (pObject->Type() != OBJECT_NODE)
1688 {
1689 UnlockData();
1690 return RCC_INVALID_OBJECT_ID;
1691 }
1692
1693 m_dwPollerNode = dwNodeId;
1694 }
1695
1696 // Change listen port of native agent
1697 if (pRequest->IsVariableExist(VID_AGENT_PORT))
1698 m_wAgentPort = pRequest->GetVariableShort(VID_AGENT_PORT);
1699
1700 // Change authentication method of native agent
1701 if (pRequest->IsVariableExist(VID_AUTH_METHOD))
1702 m_wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
1703
1704 // Change shared secret of native agent
1705 if (pRequest->IsVariableExist(VID_SHARED_SECRET))
1706 pRequest->GetVariableStr(VID_SHARED_SECRET, m_szSharedSecret, MAX_SECRET_LENGTH);
1707
1708 // Change SNMP protocol version
1709 if (pRequest->IsVariableExist(VID_SNMP_VERSION))
1710 m_iSNMPVersion = pRequest->GetVariableShort(VID_SNMP_VERSION);
1711
1712 // Change SNMP community string
1713 if (pRequest->IsVariableExist(VID_COMMUNITY_STRING))
1714 pRequest->GetVariableStr(VID_COMMUNITY_STRING, m_szCommunityString, MAX_COMMUNITY_LENGTH);
1715
1716 // Change proxy node
1717 if (pRequest->IsVariableExist(VID_PROXY_NODE))
1718 m_dwProxyNode = pRequest->GetVariableLong(VID_PROXY_NODE);
1719
1720 // Change flags
1721 if (pRequest->IsVariableExist(VID_FLAGS))
1722 {
1723 m_dwFlags &= NF_SYSTEM_FLAGS;
1724 m_dwFlags |= pRequest->GetVariableLong(VID_FLAGS) & NF_USER_FLAGS;
1725 }
1726
1727 return Template::ModifyFromMessage(pRequest, TRUE);
1728 }
1729
1730
1731 //
1732 // Wakeup node using magic packet
1733 //
1734
1735 DWORD Node::WakeUp(void)
1736 {
1737 DWORD i, dwResult = RCC_NO_WOL_INTERFACES;
1738
1739 LockChildList(FALSE);
1740
1741 for(i = 0; i < m_dwChildCount; i++)
1742 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1743 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
1744 (m_pChildList[i]->IpAddr() != 0))
1745 {
1746 dwResult = ((Interface *)m_pChildList[i])->WakeUp();
1747 break;
1748 }
1749
1750 UnlockChildList();
1751 return dwResult;
1752 }
1753
1754
1755 //
1756 // Get status of interface with given index from SNMP agent
1757 //
1758
1759 int Node::GetInterfaceStatusFromSNMP(DWORD dwIndex)
1760 {
1761 return SnmpGetInterfaceStatus(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort,
1762 m_szCommunityString, dwIndex);
1763 }
1764
1765
1766 //
1767 // Get status of interface with given index from native agent
1768 //
1769
1770 int Node::GetInterfaceStatusFromAgent(DWORD dwIndex)
1771 {
1772 char szParam[128], szBuffer[32];
1773 DWORD dwAdminStatus, dwLinkState;
1774 int iStatus;
1775
1776 // Get administrative status
1777 sprintf(szParam, "Net.Interface.AdminStatus(%u)", dwIndex);
1778 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
1779 {
1780 dwAdminStatus = strtoul(szBuffer, NULL, 0);
1781
1782 switch(dwAdminStatus)
1783 {
1784 case 3:
1785 iStatus = STATUS_TESTING;
1786 break;
1787 case 2:
1788 case 0: // Agents before 0.2.1 may return 0 instead of 2
1789 iStatus = STATUS_DISABLED;
1790 break;
1791 case 1: // Interface administratively up, check link state
1792 sprintf(szParam, "Net.Interface.Link(%u)", dwIndex);
1793 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
1794 {
1795 dwLinkState = strtoul(szBuffer, NULL, 0);
1796 iStatus = (dwLinkState == 0) ? STATUS_CRITICAL : STATUS_NORMAL;
1797 }
1798 else
1799 {
1800 iStatus = STATUS_UNKNOWN;
1801 }
1802 break;
1803 default:
1804 iStatus = STATUS_UNKNOWN;
1805 break;
1806 }
1807 }
1808 else
1809 {
1810 iStatus = STATUS_UNKNOWN;
1811 }
1812
1813 return iStatus;
1814 }
1815
1816
1817 //
1818 // Put list of supported parameters into CSCP message
1819 //
1820
1821 void Node::WriteParamListToMessage(CSCPMessage *pMsg)
1822 {
1823 DWORD i, dwId;
1824
1825 LockData();
1826 if (m_pParamList != NULL)
1827 {
1828 pMsg->SetVariable(VID_NUM_PARAMETERS, m_dwNumParams);
1829 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < m_dwNumParams; i++)
1830 {
1831 pMsg->SetVariable(dwId++, m_pParamList[i].szName);
1832 pMsg->SetVariable(dwId++, m_pParamList[i].szDescription);
1833 pMsg->SetVariable(dwId++, (WORD)m_pParamList[i].iDataType);
1834 }
1835 }
1836 else
1837 {
1838 pMsg->SetVariable(VID_NUM_PARAMETERS, (DWORD)0);
1839 }
1840 UnlockData();
1841 }
1842
1843
1844 //
1845 // Open list of supported parameters for reading
1846 //
1847
1848 void Node::OpenParamList(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
1849 {
1850 LockData();
1851 *pdwNumParams = m_dwNumParams;
1852 *ppParamList = m_pParamList;
1853 }
1854
1855
1856 //
1857 // Check status of network service
1858 //
1859
1860 DWORD Node::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
1861 WORD wPort, WORD wProto, TCHAR *pszRequest,
1862 TCHAR *pszResponse)
1863 {
1864 DWORD dwError = ERR_NOT_CONNECTED;
1865
1866 if ((m_dwFlags & NF_IS_NATIVE_AGENT) &&
1867 (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)) &&
1868 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
1869 {
1870 AgentConnection *pConn;
1871
1872 pConn = CreateAgentConnection();
1873 if (pConn != NULL)
1874 {
1875 dwError = pConn->CheckNetworkService(pdwStatus, dwIpAddr, iServiceType,
1876 wPort, wProto, pszRequest, pszResponse);
1877 pConn->Disconnect();
1878 delete pConn;
1879 }
1880 }
1881 return dwError;
1882 }
1883
1884
1885 //
1886 // Handler for object deletion
1887 //
1888
1889 void Node::OnObjectDelete(DWORD dwObjectId)
1890 {
1891 if (dwObjectId == m_dwPollerNode)
1892 {
1893 // If deleted object is our poller node, change it to default
1894 /* LOCK? */
1895 m_dwPollerNode = 0;
1896 Modify();
1897 DbgPrintf(AF_DEBUG_MISC, _T("Node \"%s\": poller node %d deleted"), m_szName, dwObjectId);
1898 }
1899 }
1900
1901
1902 //
1903 // Check node for OSPF support
1904 //
1905
1906 void Node::CheckOSPFSupport(void)
1907 {
1908 LONG nAdminStatus;
1909
1910 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
1911 ".1.3.6.1.2.1.14.1.2.0", NULL, 0, &nAdminStatus, sizeof(LONG),
1912 FALSE, FALSE) == SNMP_ERR_SUCCESS)
1913 {
1914 if (nAdminStatus)
1915 {
1916 m_dwFlags |= NF_IS_OSPF;
1917 }
1918 else
1919 {
1920 m_dwFlags &= ~NF_IS_OSPF;
1921 }
1922 }
1923 }
1924
1925
1926 //
1927 // Create ready to use agent connection
1928 //
1929
1930 AgentConnection *Node::CreateAgentConnection(void)
1931 {
1932 AgentConnection *pConn;
1933
1934 if ((!(m_dwFlags & NF_IS_NATIVE_AGENT)) ||
1935 (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
1936 (m_dwDynamicFlags & NDF_UNREACHABLE))
1937 return NULL;
1938
1939 pConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
1940 m_wAuthMethod, m_szSharedSecret);
1941 SetAgentProxy(pConn);
1942 if (!pConn->Connect(g_pServerKey))
1943 {
1944 delete pConn;
1945 pConn = NULL;
1946 }
1947 return pConn;
1948 }
1949
1950
1951 //
1952 // Get last collected values of all DCIs
1953 //
1954
1955 DWORD Node::GetLastValues(CSCPMessage *pMsg)
1956 {
1957 DWORD i, dwId;
1958
1959 LockData();
1960
1961 pMsg->SetVariable(VID_NUM_ITEMS, m_dwNumItems);
1962 for(i = 0, dwId = VID_DCI_VALUES_BASE; i < m_dwNumItems; i++, dwId += 7)
1963 m_ppItems[i]->GetLastValue(pMsg, dwId);
1964
1965 UnlockData();
1966 return RCC_SUCCESS;
1967 }
1968
1969
1970 //
1971 // Clean expired DCI data
1972 //
1973
1974 void Node::CleanDCIData(void)
1975 {
1976 DWORD i;
1977
1978 LockData();
1979 for(i = 0; i < m_dwNumItems; i++)
1980 m_ppItems[i]->CleanData();
1981 UnlockData();
1982 }
1983
1984
1985 //
1986 // Apply DCI from template
1987 // pItem passed to this method should be a template's DCI
1988 //
1989
1990 BOOL Node::ApplyTemplateItem(DWORD dwTemplateId, DCItem *pItem)
1991 {
1992 BOOL bResult = TRUE;
1993 DWORD i;
1994 DCItem *pNewItem;
1995
1996 LockData();
1997
1998 DbgPrintf(AF_DEBUG_DC, "Applying item \"%s\" to node \"%s\"", pItem->Name(), m_szName);
1999
2000 // Check if that template item exists
2001 for(i = 0; i < m_dwNumItems; i++)
2002 if ((m_ppItems[i]->TemplateId() == dwTemplateId) &&
2003 (m_ppItems[i]->TemplateItemId() == pItem->Id()))
2004 break; // Item with specified id already exist
2005
2006 if (i == m_dwNumItems)
2007 {
2008 // New item from template, just add it
2009 pNewItem = new DCItem(pItem);
2010 pNewItem->SetTemplateId(dwTemplateId, pItem->Id());
2011 pNewItem->ChangeBinding(CreateUniqueId(IDG_ITEM), this);
2012 bResult = AddItem(pNewItem, TRUE);
2013 }
2014 else
2015 {
2016 // Update existing item
2017 m_ppItems[i]->UpdateFromTemplate(pItem);
2018 Modify();
2019 }
2020
2021 UnlockData();
2022 return bResult;
2023 }
2024
2025
2026 //
2027 // Clean deleted template items from node's DCI list
2028 // Arguments is template id and list of valid template item ids.
2029 // all items related to given template and not presented in list should be deleted.
2030 //
2031
2032 void Node::CleanDeletedTemplateItems(DWORD dwTemplateId, DWORD dwNumItems, DWORD *pdwItemList)
2033 {
2034 DWORD i, j, dwNumDeleted, *pdwDeleteList;
2035
2036 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
2037 dwNumDeleted = 0;
2038
2039 LockData();
2040
2041 for(i = 0; i < m_dwNumItems; i++)
2042 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2043 {
2044 for(j = 0; j < dwNumItems; j++)
2045 if (m_ppItems[i]->TemplateItemId() == pdwItemList[j])
2046 break;
2047
2048 // Delete DCI if it's not in list
2049 if (j == dwNumItems)
2050 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->Id();
2051 }
2052
2053 UnlockData();
2054
2055 for(i = 0; i < dwNumDeleted; i++)
2056 DeleteItem(pdwDeleteList[i]);
2057 free(pdwDeleteList);
2058 }
2059
2060
2061 //
2062 // Unbind node from template, i.e either remove DCI association with template
2063 // or remove these DCIs at all
2064 //
2065
2066 void Node::UnbindFromTemplate(DWORD dwTemplateId, BOOL bRemoveDCI)
2067 {
2068 DWORD i;
2069
2070 if (bRemoveDCI)
2071 {
2072 DWORD dwNumDeleted, *pdwDeleteList;
2073
2074 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
2075 dwNumDeleted = 0;
2076
2077 LockData();
2078
2079 for(i = 0; i < m_dwNumItems; i++)
2080 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2081 {
2082 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->Id();
2083 }
2084
2085 UnlockData();
2086
2087 for(i = 0; i < dwNumDeleted; i++)
2088 DeleteItem(pdwDeleteList[i]);
2089 free(pdwDeleteList);
2090 }
2091 else
2092 {
2093 LockData();
2094
2095 for(i = 0; i < m_dwNumItems; i++)
2096 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2097 {
2098 m_ppItems[i]->SetTemplateId(0, 0);
2099 }
2100
2101 UnlockData();
2102 }
2103 }
2104
2105
2106 //
2107 // Change node's IP address
2108 //
2109
2110 void Node::ChangeIPAddress(DWORD dwIpAddr)
2111 {
2112 DWORD i;
2113
2114 PollerLock();
2115
2116 LockData();
2117
2118 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
2119 m_dwIpAddr = dwIpAddr;
2120 m_dwDynamicFlags |= NDF_FORCE_CONFIGURATION_POLL | NDF_RECHECK_CAPABILITIES;
2121
2122 // Change status of node and all it's childs to UNKNOWN
2123 m_iStatus = STATUS_UNKNOWN;
2124 LockChildList(FALSE);
2125 for(i = 0; i < m_dwChildCount; i++)
2126 {
2127 m_pChildList[i]->ResetStatus();
2128 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2129 {
2130 if (((Interface *)m_pChildList[i])->IsFake())
2131 {
2132 ((Interface *)m_pChildList[i])->SetIpAddr(dwIpAddr);
2133 }
2134 }
2135 }
2136 UnlockChildList();
2137
2138 Modify();
2139 UnlockData();
2140
2141 AgentLock();
2142 delete_and_null(m_pAgentConnection);
2143 AgentUnlock();
2144
2145 PollerUnlock();
2146 }
2147
2148
2149 //
2150 // Get number of interface objects and pointer to the last one
2151 //
2152
2153 DWORD Node::GetInterfaceCount(Interface **ppInterface)
2154 {
2155 DWORD i, dwCount;
2156
2157 LockChildList(FALSE);
2158 for(i = 0, dwCount = 0; i < m_dwChildCount; i++)
2159 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2160 {
2161 dwCount++;
2162 *ppInterface = (Interface *)m_pChildList[i];
2163 }
2164 UnlockChildList();
2165 return dwCount;
2166 }
2167
2168
2169 //
2170 // Update cache for all DCI's
2171 //
2172
2173 void Node::UpdateDCICache(void)
2174 {
2175 DWORD i;
2176
2177 /* LOCK? */
2178 for(i = 0; i < m_dwNumItems; i++)
2179 m_ppItems[i]->UpdateCacheSize();
2180 }
2181
2182
2183 //
2184 // Get routing table from node
2185 //
2186
2187 ROUTING_TABLE *Node::GetRoutingTable(void)
2188 {
2189 ROUTING_TABLE *pRT = NULL;
2190
2191 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)))
2192 {
2193 AgentLock();
2194 if (ConnectToAgent())
2195 {
2196 pRT = m_pAgentConnection->GetRoutingTable();
2197 }
2198 AgentUnlock();
2199 }
2200 if ((pRT == NULL) && (m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)))
2201 {
2202 pRT = SnmpGetRoutingTable(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString);
2203 }
2204
2205 if (pRT != NULL)
2206 {
2207 SortRoutingTable(pRT);
2208 }
2209 return pRT;
2210 }
2211
2212
2213 //
2214 // Get next hop for given destination address
2215 //
2216
2217 BOOL Node::GetNextHop(DWORD dwSrcAddr, DWORD dwDestAddr, DWORD *pdwNextHop,
2218 DWORD *pdwIfIndex, BOOL *pbIsVPN)
2219 {
2220 DWORD i;
2221 BOOL bResult = FALSE;
2222
2223 // Check VPN connectors
2224 LockChildList(FALSE);
2225 for(i = 0; i < m_dwChildCount; i++)
2226 if (m_pChildList[i]->Type() == OBJECT_VPNCONNECTOR)
2227 {
2228 if (((VPNConnector *)m_pChildList[i])->IsRemoteAddr(dwDestAddr) &&
2229 ((VPNConnector *)m_pChildList[i])->IsLocalAddr(dwSrcAddr))
2230 {
2231 *pdwNextHop = ((VPNConnector *)m_pChildList[i])->GetPeerGatewayAddr();
2232 *pdwIfIndex = m_pChildList[i]->Id();
2233 *pbIsVPN = TRUE;
2234 bResult = TRUE;
2235 break;
2236 }
2237 }
2238 UnlockChildList();
2239
2240 // Check routing table
2241 if (!bResult)
2242 {
2243 RTLock();
2244 if (m_pRoutingTable != NULL)
2245 {
2246 for(i = 0; i < (DWORD)m_pRoutingTable->iNumEntries; i++)
2247 if ((dwDestAddr & m_pRoutingTable->pRoutes[i].dwDestMask) == m_pRoutingTable->pRoutes[i].dwDestAddr)
2248 {
2249 *pdwNextHop = m_pRoutingTable->pRoutes[i].dwNextHop;
2250 *pdwIfIndex = m_pRoutingTable->pRoutes[i].dwIfIndex;
2251 *pbIsVPN = FALSE;
2252 bResult = TRUE;
2253 break;
2254 }
2255 }
2256 RTUnlock();
2257 }
2258
2259 return bResult;
2260 }
2261
2262
2263 //
2264 // Update cached routing table
2265 //
2266
2267 void Node::UpdateRoutingTable(void)
2268 {
2269 ROUTING_TABLE *pRT;
2270
2271 pRT = GetRoutingTable();
2272 if (pRT != NULL)
2273 {
2274 RTLock();
2275 DestroyRoutingTable(m_pRoutingTable);
2276 m_pRoutingTable = pRT;
2277 RTUnlock();
2278 }
2279 m_tLastRTUpdate = time(NULL);
2280 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_ROUTE_POLL;
2281 }
2282
2283
2284 //
2285 // Call SNMP Enumerate with node's SNMP parameters
2286 //
2287
2288 DWORD Node::CallSnmpEnumerate(char *pszRootOid,
2289 DWORD (* pHandler)(DWORD, DWORD, WORD, const char *, SNMP_Variable *, SNMP_Transport *, void *),
2290 void *pArg)
2291 {
2292 if ((m_dwFlags & NF_IS_SNMP) &&
2293 (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)) &&
2294 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
2295 return SnmpEnumerate(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort,
2296 m_szCommunityString, pszRootOid, pHandler, pArg, FALSE);
2297 else
2298 return SNMP_ERR_COMM;
2299 }
2300
2301
2302 //
2303 // Set proxy information for agent's connection
2304 //
2305
2306 void Node::SetAgentProxy(AgentConnection *pConn)
2307 {
2308 if (m_dwProxyNode != 0)
2309 {
2310 Node *pNode;
2311
2312 pNode = (Node *)FindObjectById(m_dwProxyNode);
2313 if (pNode != NULL)
2314 {
2315 pConn->SetProxy(htonl(pNode->m_dwIpAddr), pNode->m_wAgentPort,
2316 pNode->m_wAuthMethod, pNode->m_szSharedSecret);
2317 }
2318 }
2319 }
2320
2321
2322 //
2323 // Prepare node object for deletion
2324 //
2325
2326 void Node::PrepareForDeletion(void)
2327 {
2328 // Prevent node from being queued for polling
2329 LockData();
2330 m_dwDynamicFlags |= NDF_POLLING_DISABLED;
2331 UnlockData();
2332
2333 // Wait for all pending polls
2334 while(1)
2335 {
2336 LockData();
2337 if ((m_dwDynamicFlags &
2338 (NDF_QUEUED_FOR_STATUS_POLL | NDF_QUEUED_FOR_CONFIG_POLL |
2339 NDF_QUEUED_FOR_DISCOVERY_POLL | NDF_QUEUED_FOR_ROUTE_POLL)) == 0)
2340 {
2341 UnlockData();
2342 break;
2343 }
2344 UnlockData();
2345 ThreadSleepMs(100);
2346 }
2347 }
2348
2349
2350 //
2351 // Check if specified SNMP variable set to specified value.
2352 // If variable doesn't exist at all, will return FALSE
2353 //
2354
2355 BOOL Node::CheckSNMPIntegerValue(char *pszOID, int nValue)
2356 {
2357 DWORD dwTemp;
2358
2359 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
2360 pszOID, NULL, 0, &dwTemp, sizeof(DWORD), FALSE, FALSE) == SNMP_ERR_SUCCESS)
2361 return (int)dwTemp == nValue;
2362 return FALSE;
2363 }
2364
2365
2366 //
2367 // Check and update if needed interface names
2368 //
2369
2370 void Node::CheckInterfaceNames(INTERFACE_LIST *pIfList)
2371 {
2372 int i;
2373 TCHAR *ptr;
2374
2375 if (m_dwNodeType == NODE_TYPE_NORTEL_BAYSTACK)
2376 {
2377 // Translate interface names
2378 for(i = 0; i < pIfList->iNumEntries; i++)
2379 {
2380 if ((_tcsstr(pIfList->pInterfaces[i].szName, _T("BayStack")) != NULL) ||
2381 (_tcsstr(pIfList->pInterfaces[i].szName, _T("Nortel Ethernet Switch")) != NULL))
2382 {
2383 ptr = _tcsrchr(pIfList->pInterfaces[i].szName, _T('-'));
2384 if (ptr != NULL)
2385 {
2386 ptr++;
2387 while(*ptr == _T(' '))
2388 ptr++;
2389 memmove(pIfList->pInterfaces[i].szName, ptr, _tcslen(ptr) + 1);
2390 }
2391 }
2392 }
2393 }
2394
2395 // Cut interface names to MAX_OBJECT_NAME and check for unnamed interfaces
2396 for(i = 0; i < pIfList->iNumEntries; i++)
2397 {
2398 pIfList->pInterfaces[i].szName[MAX_OBJECT_NAME - 1] = 0;
2399 if (pIfList->pInterfaces[i].szName[0] == 0)
2400 _stprintf(pIfList->pInterfaces[i].szName, _T("%d"), pIfList->pInterfaces[i].dwIndex);
2401 }
2402 }