- bugfix: SYS_NODE_UP event was not sent after changing IP address of node which...
[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_dwFlags &= ~(NF_IS_NATIVE_AGENT | NF_IS_SNMP | NF_IS_CPSNMP |
865 NF_IS_BRIDGE | NF_IS_ROUTER | NF_IS_OSPF);
866 m_szObjectId[0] = 0;
867 m_szPlatformName[0] = 0;
868 m_szAgentVersion[0] = 0;
869 }
870
871 // Check if node is marked as unreachable
872 if ((m_dwDynamicFlags & NDF_UNREACHABLE) && !(m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES))
873 {
874 SendPollerMsg(dwRqId, _T("Node is marked as unreachable, configuration poll aborted\r\n"));
875 DbgPrintf(AF_DEBUG_DISCOVERY, "Node is marked as unreachable, configuration poll aborted");
876 m_tLastConfigurationPoll = time(NULL);
877 }
878 else
879 {
880 // Check node's capabilities
881 SetPollerInfo(nPoller, "capability check");
882 SendPollerMsg(dwRqId, _T("Checking node's capabilities...\r\n"));
883 if ((!((m_dwFlags & NF_IS_SNMP) && (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE))) &&
884 (!(m_dwFlags & NF_DISABLE_SNMP)))
885 {
886 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): trying SNMP GET", m_szName);
887 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
888 ".1.3.6.1.2.1.1.2.0", NULL, 0, szBuffer, 4096,
889 FALSE, FALSE) == SNMP_ERR_SUCCESS)
890 {
891 DWORD dwNodeFlags, dwNodeType;
892
893 LockData();
894
895 if (strcmp(m_szObjectId, szBuffer))
896 {
897 nx_strncpy(m_szObjectId, szBuffer, MAX_OID_LEN * 4);
898 bHasChanges = TRUE;
899 }
900
901 m_dwFlags |= NF_IS_SNMP;
902 if (m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)
903 {
904 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
905 PostEvent(EVENT_SNMP_OK, m_dwId, NULL);
906 SendPollerMsg(dwRqId, " Connectivity with SNMP agent restored\r\n");
907 }
908 SendPollerMsg(dwRqId, _T(" SNMP agent is active\r\n"));
909
910 // Check node type
911 dwNodeType = OidToType(m_szObjectId, &dwNodeFlags);
912 if (m_dwNodeType != dwNodeType)
913 {
914 m_dwFlags |= dwNodeFlags;
915 m_dwNodeType = dwNodeType;
916 SendPollerMsg(dwRqId, _T(" Node type has been changed to %d\r\n"), m_dwNodeType);
917 bHasChanges = TRUE;
918 }
919
920 // Check IP forwarding
921 if (CheckSNMPIntegerValue(".1.3.6.1.2.1.4.1.0", 1))
922 {
923 m_dwFlags |= NF_IS_ROUTER;
924 }
925 else
926 {
927 m_dwFlags &= ~NF_IS_ROUTER;
928 }
929
930 // Check for bridge MIB support
931 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
932 ".1.3.6.1.2.1.17.1.1.0", NULL, 0, szBuffer, 4096,
933 FALSE, FALSE) == SNMP_ERR_SUCCESS)
934 {
935 m_dwFlags |= NF_IS_BRIDGE;
936 }
937 else
938 {
939 m_dwFlags &= ~NF_IS_BRIDGE;
940 }
941
942 // Check for CDP (Cisco Discovery Protocol) support
943 if (CheckSNMPIntegerValue(".1.3.6.1.4.1.9.9.23.1.3.1.0", 1))
944 {
945 m_dwFlags |= NF_IS_CDP;
946 }
947 else
948 {
949 m_dwFlags &= ~NF_IS_CDP;
950 }
951
952 // Check for Nortel topology discovery support
953 if (CheckSNMPIntegerValue(".1.3.6.1.4.1.45.1.6.13.1.2.0", 1))
954 {
955 m_dwFlags |= NF_IS_NORTEL_TOPO;
956 }
957 else
958 {
959 m_dwFlags &= ~NF_IS_NORTEL_TOPO;
960 }
961
962 UnlockData();
963
964 CheckOSPFSupport();
965 }
966 else
967 {
968 // Check for CheckPoint SNMP agent on port 161
969 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for CheckPoint SNMP", m_szName);
970 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
971 ".1.3.6.1.4.1.2620.1.1.10.0", NULL, 0,
972 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
973 {
974 LockData();
975 if (strcmp(m_szObjectId, ".1.3.6.1.4.1.2620.1.1"))
976 {
977 nx_strncpy(m_szObjectId, ".1.3.6.1.4.1.2620.1.1", MAX_OID_LEN * 4);
978 bHasChanges = TRUE;
979 }
980
981 m_dwFlags |= NF_IS_SNMP | NF_IS_ROUTER;
982 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHABLE;
983 UnlockData();
984 SendPollerMsg(dwRqId, _T(" CheckPoint SNMP agent on port 161 is active\r\n"));
985 }
986 }
987 }
988
989 // Check for CheckPoint SNMP agent on port 260
990 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for CheckPoint SNMP on port 260", m_szName);
991 if (!((m_dwFlags & NF_IS_CPSNMP) && (m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE)))
992 {
993 if (SnmpGet(SNMP_VERSION_1, m_dwIpAddr, CHECKPOINT_SNMP_PORT, m_szCommunityString,
994 ".1.3.6.1.4.1.2620.1.1.10.0", NULL, 0,
995 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
996 {
997 LockData();
998 m_dwFlags |= NF_IS_CPSNMP | NF_IS_ROUTER;
999 m_dwDynamicFlags &= ~NDF_CPSNMP_UNREACHABLE;
1000 UnlockData();
1001 SendPollerMsg(dwRqId, _T(" CheckPoint SNMP agent on port 260 is active\r\n"));
1002 }
1003 }
1004
1005 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for NetXMS agent Flags={%08X} DynamicFlags={%08X}", m_szName, m_dwFlags, m_dwDynamicFlags);
1006 if ((!((m_dwFlags & NF_IS_NATIVE_AGENT) && (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE))) &&
1007 (!(m_dwFlags & NF_DISABLE_NXCP)))
1008 {
1009 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
1010 m_wAuthMethod, m_szSharedSecret);
1011 SetAgentProxy(pAgentConn);
1012 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for NetXMS agent - connecting", m_szName);
1013 if (pAgentConn->Connect(g_pServerKey))
1014 {
1015 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for NetXMS agent - connected", m_szName);
1016 LockData();
1017 m_dwFlags |= NF_IS_NATIVE_AGENT;
1018 if (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)
1019 {
1020 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHABLE;
1021 PostEvent(EVENT_AGENT_OK, m_dwId, NULL);
1022 SendPollerMsg(dwRqId, " Connectivity with NetXMS agent restored\r\n");
1023 }
1024 UnlockData();
1025
1026 if (pAgentConn->GetParameter("Agent.Version", MAX_AGENT_VERSION_LEN, szBuffer) == ERR_SUCCESS)
1027 {
1028 LockData();
1029 if (strcmp(m_szAgentVersion, szBuffer))
1030 {
1031 strcpy(m_szAgentVersion, szBuffer);
1032 bHasChanges = TRUE;
1033 SendPollerMsg(dwRqId, _T(" NetXMS agent version changed to %s\r\n"), m_szAgentVersion);
1034 }
1035 UnlockData();
1036 }
1037
1038 if (pAgentConn->GetParameter("System.PlatformName", MAX_PLATFORM_NAME_LEN, szBuffer) == ERR_SUCCESS)
1039 {
1040 LockData();
1041 if (strcmp(m_szPlatformName, szBuffer))
1042 {
1043 strcpy(m_szPlatformName, szBuffer);
1044 bHasChanges = TRUE;
1045 SendPollerMsg(dwRqId, _T(" Platform name changed to %s\r\n"), m_szPlatformName);
1046 }
1047 UnlockData();
1048 }
1049
1050 // Check IP forwarding status
1051 if (pAgentConn->GetParameter("Net.IP.Forwarding", 16, szBuffer) == ERR_SUCCESS)
1052 {
1053 if (_tcstoul(szBuffer, NULL, 10) != 0)
1054 m_dwFlags |= NF_IS_ROUTER;
1055 else
1056 m_dwFlags &= ~NF_IS_ROUTER;
1057 }
1058
1059 /* LOCK? */
1060 safe_free(m_pParamList);
1061 pAgentConn->GetSupportedParameters(&m_dwNumParams, &m_pParamList);
1062
1063 pAgentConn->Disconnect();
1064 SendPollerMsg(dwRqId, _T(" NetXMS native agent is active\r\n"));
1065 }
1066 delete pAgentConn;
1067 DbgPrintf(AF_DEBUG_DISCOVERY, "ConfPoll(%s): checking for NetXMS agent - finished", m_szName);
1068 }
1069
1070 // Generate event if node flags has been changed
1071 if (dwOldFlags != m_dwFlags)
1072 {
1073 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
1074 bHasChanges = TRUE;
1075 }
1076
1077 // Retrieve interface list
1078 SetPollerInfo(nPoller, "interface check");
1079 SendPollerMsg(dwRqId, _T("Capability check finished\r\n"
1080 "Checking interface configuration...\r\n"));
1081 pIfList = GetInterfaceList();
1082 if (pIfList != NULL)
1083 {
1084 // Find non-existing interfaces
1085 LockChildList(FALSE);
1086 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
1087 for(i = 0, iDelCount = 0; i < m_dwChildCount; i++)
1088 {
1089 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1090 {
1091 Interface *pInterface = (Interface *)m_pChildList[i];
1092
1093 if (pInterface->IfType() != IFTYPE_NETXMS_NAT_ADAPTER)
1094 {
1095 for(j = 0; j < pIfList->iNumEntries; j++)
1096 {
1097 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
1098 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
1099 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
1100 break;
1101 }
1102
1103 if (j == pIfList->iNumEntries)
1104 {
1105 // No such interface in current configuration, add it to delete list
1106 ppDeleteList[iDelCount++] = pInterface;
1107 }
1108 }
1109 }
1110 }
1111 UnlockChildList();
1112
1113 // Delete non-existent interfaces
1114 if (iDelCount > 0)
1115 {
1116 for(j = 0; j < iDelCount; j++)
1117 {
1118 SendPollerMsg(dwRqId, _T(" Interface \"%s\" is no longer exist\r\n"),
1119 ppDeleteList[j]->Name());
1120 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->IfIndex(),
1121 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->IpNetMask());
1122 DeleteInterface(ppDeleteList[j]);
1123 }
1124 bHasChanges = TRUE;
1125 }
1126 safe_free(ppDeleteList);
1127
1128 // Add new interfaces and check configuration of existing
1129 for(j = 0; j < pIfList->iNumEntries; j++)
1130 {
1131 BOOL bNewInterface = TRUE;
1132
1133 LockChildList(FALSE);
1134 for(i = 0; i < m_dwChildCount; i++)
1135 {
1136 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1137 {
1138 Interface *pInterface = (Interface *)m_pChildList[i];
1139
1140 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
1141 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
1142 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
1143 {
1144 // Existing interface, check configuration
1145 if (memcmp(pIfList->pInterfaces[j].bMacAddr, pInterface->MacAddr(), MAC_ADDR_LENGTH))
1146 {
1147 char szOldMac[16], szNewMac[16];
1148
1149 BinToStr((BYTE *)pInterface->MacAddr(), MAC_ADDR_LENGTH, szOldMac);
1150 BinToStr(pIfList->pInterfaces[j].bMacAddr, MAC_ADDR_LENGTH, szNewMac);
1151 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
1152 pInterface->Id(), pInterface->IfIndex(),
1153 pInterface->Name(), szOldMac, szNewMac);
1154 pInterface->SetMacAddr(pIfList->pInterfaces[j].bMacAddr);
1155 }
1156 if (strcmp(pIfList->pInterfaces[j].szName, pInterface->Name()))
1157 {
1158 pInterface->SetName(pIfList->pInterfaces[j].szName);
1159 }
1160 bNewInterface = FALSE;
1161 break;
1162 }
1163 }
1164 }
1165 UnlockChildList();
1166
1167 if (bNewInterface)
1168 {
1169 // New interface
1170 SendPollerMsg(dwRqId, _T(" Found new interface \"%s\"\r\n"),
1171 pIfList->pInterfaces[j].szName);
1172 CreateNewInterface(pIfList->pInterfaces[j].dwIpAddr,
1173 pIfList->pInterfaces[j].dwIpNetMask,
1174 pIfList->pInterfaces[j].szName,
1175 pIfList->pInterfaces[j].dwIndex,
1176 pIfList->pInterfaces[j].dwType,
1177 pIfList->pInterfaces[j].bMacAddr);
1178 bHasChanges = TRUE;
1179 }
1180 }
1181
1182 // Check if address we are using to communicate with node
1183 // is configured on one of node's interfaces
1184 for(i = 0; i < (DWORD)pIfList->iNumEntries; i++)
1185 if (pIfList->pInterfaces[i].dwIpAddr == m_dwIpAddr)
1186 break;
1187
1188 if (i == (DWORD)pIfList->iNumEntries)
1189 {
1190 BOOL bCreate = TRUE;
1191
1192 // Node is behind NAT
1193 m_dwFlags |= NF_BEHIND_NAT;
1194
1195 // Check if we already have NAT interface
1196 LockChildList(FALSE);
1197 for(i = 0; i < m_dwChildCount; i++)
1198 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1199 {
1200 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1201 {
1202 bCreate = FALSE;
1203 break;
1204 }
1205 }
1206 UnlockChildList();
1207
1208 if (bCreate)
1209 {
1210 char szBuffer[MAX_OBJECT_NAME];
1211
1212 // Create pseudo interface for NAT
1213 ConfigReadStr("NATAdapterName", szBuffer, MAX_OBJECT_NAME, "NetXMS NAT Adapter");
1214 CreateNewInterface(m_dwIpAddr, 0, szBuffer,
1215 0x7FFFFFFF, IFTYPE_NETXMS_NAT_ADAPTER);
1216 bHasChanges = TRUE;
1217 }
1218 }
1219 else
1220 {
1221 // Check if NF_BEHIND_NAT flag set incorrectly
1222 if (m_dwFlags & NF_BEHIND_NAT)
1223 {
1224 Interface *pIfNat;
1225
1226 // Remove NAT interface
1227 LockChildList(FALSE);
1228 for(i = 0, pIfNat = NULL; i < m_dwChildCount; i++)
1229 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1230 {
1231 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
1232 {
1233 pIfNat = (Interface *)m_pChildList[i];
1234 break;
1235 }
1236 }
1237 UnlockChildList();
1238
1239 if (pIfNat != NULL)
1240 DeleteInterface(pIfNat);
1241
1242 m_dwFlags &= ~NF_BEHIND_NAT;
1243 bHasChanges = TRUE;
1244 }
1245 }
1246
1247 DestroyInterfaceList(pIfList);
1248 }
1249 else /* pIfList == NULL */
1250 {
1251 Interface *pInterface;
1252 DWORD dwCount;
1253
1254 SendPollerMsg(dwRqId, _T(" Unable to get interface list from node\r\n"));
1255
1256 // Delete all existing interfaces in case of forced capability recheck
1257 if (m_dwDynamicFlags & NDF_RECHECK_CAPABILITIES)
1258 {
1259 LockChildList(FALSE);
1260 ppDeleteList = (Interface **)malloc(sizeof(Interface *) * m_dwChildCount);
1261 for(i = 0, iDelCount = 0; i < m_dwChildCount; i++)
1262 {
1263 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
1264 ppDeleteList[iDelCount++] = (Interface *)m_pChildList[i];
1265 }
1266 UnlockChildList();
1267 for(j = 0; j < iDelCount; j++)
1268 {
1269 SendPollerMsg(dwRqId, _T(" Interface \"%s\" is no longer exist\r\n"),
1270 ppDeleteList[j]->Name());
1271 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", ppDeleteList[j]->IfIndex(),
1272 ppDeleteList[j]->Name(), ppDeleteList[j]->IpAddr(), ppDeleteList[j]->IpNetMask());
1273 DeleteInterface(ppDeleteList[j]);
1274 }
1275 safe_free(ppDeleteList);
1276 }
1277
1278 // Check if we have pseudo-interface object
1279 dwCount = GetInterfaceCount(&pInterface);
1280 if (dwCount == 1)
1281 {
1282 if (pInterface->IsFake())
1283 {
1284 // Check if primary IP is different from interface's IP
1285 if (pInterface->IpAddr() != m_dwIpAddr)
1286 {
1287 DeleteInterface(pInterface);
1288 CreateNewInterface(m_dwIpAddr, dwNetMask);
1289 }
1290 }
1291 }
1292 else if (dwCount == 0)
1293 {
1294 // No interfaces at all, create pseudo-interface
1295 CreateNewInterface(m_dwIpAddr, dwNetMask);
1296 }
1297 }
1298
1299 m_tLastConfigurationPoll = time(NULL);
1300 SendPollerMsg(dwRqId, _T("Interface configuration check finished\r\n"
1301 "Finished configuration poll for node %s\r\n"
1302 "Node configuration was%schanged after poll\r\n"),
1303 m_szName, bHasChanges ? _T(" ") : _T(" not "));
1304 }
1305
1306 // Finish configuration poll
1307 SetPollerInfo(nPoller, "cleanup");
1308 if (dwRqId == 0)
1309 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1310 m_dwDynamicFlags &= ~NDF_RECHECK_CAPABILITIES;
1311 PollerUnlock();
1312 DbgPrintf(AF_DEBUG_DISCOVERY, "Finished configuration poll for node %s (ID: %d)", m_szName, m_dwId);
1313
1314 if (bHasChanges)
1315 {
1316 LockData();
1317 Modify();
1318 UnlockData();
1319 }
1320 }
1321
1322
1323 //
1324 // Connect to native agent
1325 //
1326
1327 BOOL Node::ConnectToAgent(void)
1328 {
1329 BOOL bRet;
1330
1331 // Create new agent connection object if needed
1332 if (m_pAgentConnection == NULL)
1333 m_pAgentConnection = new AgentConnectionEx(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
1334
1335 // Check if we already connected
1336 if (m_pAgentConnection->Nop() == ERR_SUCCESS)
1337 return TRUE;
1338
1339 // Close current connection or clean up after broken connection
1340 m_pAgentConnection->Disconnect();
1341 m_pAgentConnection->SetPort(m_wAgentPort);
1342 m_pAgentConnection->SetAuthData(m_wAuthMethod, m_szSharedSecret);
1343 SetAgentProxy(m_pAgentConnection);
1344 bRet = m_pAgentConnection->Connect(g_pServerKey);
1345 if (bRet)
1346 m_pAgentConnection->EnableTraps();
1347 return bRet;
1348 }
1349
1350
1351 //
1352 // Get item's value via SNMP
1353 //
1354
1355 DWORD Node::GetItemFromSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1356 {
1357 DWORD dwResult;
1358
1359 if ((m_dwDynamicFlags & NDF_SNMP_UNREACHABLE) ||
1360 (m_dwDynamicFlags & NDF_UNREACHABLE))
1361 {
1362 dwResult = SNMP_ERR_COMM;
1363 }
1364 else
1365 {
1366 dwResult = SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
1367 szParam, NULL, 0, szBuffer, dwBufSize, FALSE, TRUE);
1368 }
1369 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
1370 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
1371 }
1372
1373
1374 //
1375 // Get item's value via SNMP from CheckPoint's agent
1376 //
1377
1378 DWORD Node::GetItemFromCheckPointSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1379 {
1380 DWORD dwResult;
1381
1382 if ((m_dwDynamicFlags & NDF_CPSNMP_UNREACHABLE) ||
1383 (m_dwDynamicFlags & NDF_UNREACHABLE))
1384 {
1385 dwResult = SNMP_ERR_COMM;
1386 }
1387 else
1388 {
1389 dwResult = SnmpGet(SNMP_VERSION_1, m_dwIpAddr, CHECKPOINT_SNMP_PORT,
1390 m_szCommunityString, szParam, NULL, 0, szBuffer,
1391 dwBufSize, FALSE, TRUE);
1392 }
1393 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
1394 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
1395 }
1396
1397
1398 //
1399 // Get item's value via native agent
1400 //
1401
1402 DWORD Node::GetItemFromAgent(const char *szParam, DWORD dwBufSize, char *szBuffer)
1403 {
1404 DWORD dwError, dwResult = DCE_COMM_ERROR;
1405 DWORD dwTries = 5;
1406
1407 if ((m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
1408 (m_dwDynamicFlags & NDF_UNREACHABLE))
1409 return DCE_COMM_ERROR;
1410
1411 AgentLock();
1412
1413 // Establish connection if needed
1414 if (m_pAgentConnection == NULL)
1415 if (!ConnectToAgent())
1416 goto end_loop;
1417
1418 // Get parameter from agent
1419 while(dwTries-- > 0)
1420 {
1421 dwError = m_pAgentConnection->GetParameter((char *)szParam, dwBufSize, szBuffer);
1422 switch(dwError)
1423 {
1424 case ERR_SUCCESS:
1425 dwResult = DCE_SUCCESS;
1426 goto end_loop;
1427 case ERR_UNKNOWN_PARAMETER:
1428 dwResult = DCE_NOT_SUPPORTED;
1429 goto end_loop;
1430 case ERR_NOT_CONNECTED:
1431 case ERR_CONNECTION_BROKEN:
1432 if (!ConnectToAgent())
1433 goto end_loop;
1434 break;
1435 case ERR_REQUEST_TIMEOUT:
1436 break;
1437 }
1438 }
1439
1440 end_loop:
1441 AgentUnlock();
1442 DbgPrintf(AF_DEBUG_DC, "Node(%s)->GetItemFromAgent(%s): dwError=%d dwResult=%d",
1443 m_szName, szParam, dwError, dwResult);
1444 return dwResult;
1445 }
1446
1447
1448 //
1449 // Get value for server's internal parameter
1450 //
1451
1452 DWORD Node::GetInternalItem(const char *szParam, DWORD dwBufSize, char *szBuffer)
1453 {
1454 DWORD dwError = DCE_SUCCESS;
1455
1456 if (!stricmp(szParam, "status"))
1457 {
1458 sprintf(szBuffer, "%d", m_iStatus);
1459 }
1460 else if (!stricmp(szParam, "AgentStatus"))
1461 {
1462 if (m_dwFlags & NF_IS_NATIVE_AGENT)
1463 {
1464 szBuffer[0] = (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ? '1' : '0';
1465 szBuffer[1] = 0;
1466 }
1467 else
1468 {
1469 dwError = DCE_NOT_SUPPORTED;
1470 }
1471 }
1472 else if (MatchString("ChildStatus(*)", szParam, FALSE))
1473 {
1474 char *pEnd, szArg[256];
1475 DWORD i, dwId;
1476 NetObj *pObject = NULL;
1477
1478 NxGetParameterArg((char *)szParam, 1, szArg, 256);
1479 dwId = strtoul(szArg, &pEnd, 0);
1480 if (*pEnd != 0)
1481 {
1482 // Argument is object's name
1483 dwId = 0;
1484 }
1485
1486 // Find child object with requested ID or name
1487 LockChildList(FALSE);
1488 for(i = 0; i < m_dwChildCount; i++)
1489 {
1490 if (((dwId == 0) && (!stricmp(m_pChildList[i]->Name(), szArg))) ||
1491 (dwId == m_pChildList[i]->Id()))
1492 {
1493 pObject = m_pChildList[i];
1494 break;
1495 }
1496 }
1497 UnlockChildList();
1498
1499 if (pObject != NULL)
1500 {
1501 sprintf(szBuffer, "%d", pObject->Status());
1502 }
1503 else
1504 {
1505 dwError = DCE_NOT_SUPPORTED;
1506 }
1507 }
1508 else if (m_dwFlags & NF_IS_LOCAL_MGMT)
1509 {
1510 if (!stricmp(szParam, "Server.AverageDCPollerQueueSize"))
1511 {
1512 sprintf(szBuffer, "%f", g_dAvgPollerQueueSize);
1513 }
1514 else if (!stricmp(szParam, "Server.AverageDBWriterQueueSize"))
1515 {
1516 sprintf(szBuffer, "%f", g_dAvgDBWriterQueueSize);
1517 }
1518 else if (!stricmp(szParam, "Server.AverageStatusPollerQueueSize"))
1519 {
1520 sprintf(szBuffer, "%f", g_dAvgStatusPollerQueueSize);
1521 }
1522 else if (!stricmp(szParam, "Server.AverageConfigurationPollerQueueSize"))
1523 {
1524 sprintf(szBuffer, "%f", g_dAvgConfigPollerQueueSize);
1525 }
1526 else if (!stricmp(szParam, "Server.AverageDCIQueuingTime"))
1527 {
1528 sprintf(szBuffer, "%u", g_dwAvgDCIQueuingTime);
1529 }
1530 else
1531 {
1532 dwError = DCE_NOT_SUPPORTED;
1533 }
1534 }
1535 else
1536 {
1537 dwError = DCE_NOT_SUPPORTED;
1538 }
1539
1540 return dwError;
1541 }
1542
1543
1544 //
1545 // Get item's value for client
1546 //
1547
1548 DWORD Node::GetItemForClient(int iOrigin, const char *pszParam, char *pszBuffer, DWORD dwBufSize)
1549 {
1550 DWORD dwResult = 0, dwRetCode;
1551
1552 // Get data from node
1553 switch(iOrigin)
1554 {
1555 case DS_INTERNAL:
1556 dwRetCode = GetInternalItem(pszParam, dwBufSize, pszBuffer);
1557 break;
1558 case DS_NATIVE_AGENT:
1559 dwRetCode = GetItemFromAgent(pszParam, dwBufSize, pszBuffer);
1560 break;
1561 case DS_SNMP_AGENT:
1562 dwRetCode = GetItemFromSNMP(pszParam, dwBufSize, pszBuffer);
1563 break;
1564 case DS_CHECKPOINT_AGENT:
1565 dwRetCode = GetItemFromCheckPointSNMP(pszParam, dwBufSize, pszBuffer);
1566 break;
1567 default:
1568 dwResult = RCC_INVALID_ARGUMENT;
1569 break;
1570 }
1571
1572 // Translate return code to RCC
1573 if (dwResult != RCC_INVALID_ARGUMENT)
1574 {
1575 switch(dwRetCode)
1576 {
1577 case DCE_SUCCESS:
1578 dwResult = RCC_SUCCESS;
1579 break;
1580 case DCE_COMM_ERROR:
1581 dwResult = RCC_COMM_FAILURE;
1582 break;
1583 case DCE_NOT_SUPPORTED:
1584 dwResult = RCC_DCI_NOT_SUPPORTED;
1585 break;
1586 default:
1587 dwResult = RCC_SYSTEM_FAILURE;
1588 break;
1589 }
1590 }
1591
1592 return dwResult;
1593 }
1594
1595
1596 //
1597 // Put items which requires polling into the queue
1598 //
1599
1600 void Node::QueueItemsForPolling(Queue *pPollerQueue)
1601 {
1602 DWORD i;
1603 time_t currTime;
1604
1605 if (m_iStatus == STATUS_UNMANAGED)
1606 return; // Do not collect data for unmanaged nodes
1607
1608 currTime = time(NULL);
1609
1610 LockData();
1611 for(i = 0; i < m_dwNumItems; i++)
1612 {
1613 if (m_ppItems[i]->ReadyForPolling(currTime))
1614 {
1615 m_ppItems[i]->SetBusyFlag(TRUE);
1616 IncRefCount(); // Increment reference count for each queued DCI
1617 pPollerQueue->Put(m_ppItems[i]);
1618 }
1619 }
1620 UnlockData();
1621 }
1622
1623
1624 //
1625 // Create CSCP message with object's data
1626 //
1627
1628 void Node::CreateMessage(CSCPMessage *pMsg)
1629 {
1630 Template::CreateMessage(pMsg);
1631 pMsg->SetVariable(VID_FLAGS, m_dwFlags);
1632 pMsg->SetVariable(VID_AGENT_PORT, m_wAgentPort);
1633 pMsg->SetVariable(VID_AUTH_METHOD, m_wAuthMethod);
1634 pMsg->SetVariable(VID_SHARED_SECRET, m_szSharedSecret);
1635 pMsg->SetVariable(VID_COMMUNITY_STRING, m_szCommunityString);
1636 pMsg->SetVariable(VID_SNMP_OID, m_szObjectId);
1637 pMsg->SetVariable(VID_NODE_TYPE, m_dwNodeType);
1638 pMsg->SetVariable(VID_SNMP_VERSION, (WORD)m_iSNMPVersion);
1639 pMsg->SetVariable(VID_AGENT_VERSION, m_szAgentVersion);
1640 pMsg->SetVariable(VID_PLATFORM_NAME, m_szPlatformName);
1641 pMsg->SetVariable(VID_POLLER_NODE_ID, m_dwPollerNode);
1642 pMsg->SetVariable(VID_ZONE_GUID, m_dwZoneGUID);
1643 pMsg->SetVariable(VID_PROXY_NODE, m_dwProxyNode);
1644 }
1645
1646
1647 //
1648 // Modify object from message
1649 //
1650
1651 DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
1652 {
1653 if (!bAlreadyLocked)
1654 LockData();
1655
1656 // Change primary IP address
1657 if (pRequest->IsVariableExist(VID_IP_ADDRESS))
1658 {
1659 DWORD i, dwIpAddr;
1660
1661 dwIpAddr = pRequest->GetVariableLong(VID_IP_ADDRESS);
1662
1663 // Check if received IP address is one of node's interface addresses
1664 LockChildList(FALSE);
1665 for(i = 0; i < m_dwChildCount; i++)
1666 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1667 (m_pChildList[i]->IpAddr() == dwIpAddr))
1668 break;
1669 UnlockChildList();
1670 if (i == m_dwChildCount)
1671 {
1672 UnlockData();
1673 return RCC_INVALID_IP_ADDR;
1674 }
1675
1676 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
1677 m_dwIpAddr = dwIpAddr;
1678 }
1679
1680 // Poller node ID
1681 if (pRequest->IsVariableExist(VID_POLLER_NODE_ID))
1682 {
1683 DWORD dwNodeId;
1684 NetObj *pObject;
1685
1686 dwNodeId = pRequest->GetVariableLong(VID_POLLER_NODE_ID);
1687 pObject = FindObjectById(dwNodeId);
1688
1689 // Check if received id is a valid node id
1690 if (pObject == NULL)
1691 {
1692 UnlockData();
1693 return RCC_INVALID_OBJECT_ID;
1694 }
1695 if (pObject->Type() != OBJECT_NODE)
1696 {
1697 UnlockData();
1698 return RCC_INVALID_OBJECT_ID;
1699 }
1700
1701 m_dwPollerNode = dwNodeId;
1702 }
1703
1704 // Change listen port of native agent
1705 if (pRequest->IsVariableExist(VID_AGENT_PORT))
1706 m_wAgentPort = pRequest->GetVariableShort(VID_AGENT_PORT);
1707
1708 // Change authentication method of native agent
1709 if (pRequest->IsVariableExist(VID_AUTH_METHOD))
1710 m_wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
1711
1712 // Change shared secret of native agent
1713 if (pRequest->IsVariableExist(VID_SHARED_SECRET))
1714 pRequest->GetVariableStr(VID_SHARED_SECRET, m_szSharedSecret, MAX_SECRET_LENGTH);
1715
1716 // Change SNMP protocol version
1717 if (pRequest->IsVariableExist(VID_SNMP_VERSION))
1718 m_iSNMPVersion = pRequest->GetVariableShort(VID_SNMP_VERSION);
1719
1720 // Change SNMP community string
1721 if (pRequest->IsVariableExist(VID_COMMUNITY_STRING))
1722 pRequest->GetVariableStr(VID_COMMUNITY_STRING, m_szCommunityString, MAX_COMMUNITY_LENGTH);
1723
1724 // Change proxy node
1725 if (pRequest->IsVariableExist(VID_PROXY_NODE))
1726 m_dwProxyNode = pRequest->GetVariableLong(VID_PROXY_NODE);
1727
1728 // Change flags
1729 if (pRequest->IsVariableExist(VID_FLAGS))
1730 {
1731 m_dwFlags &= NF_SYSTEM_FLAGS;
1732 m_dwFlags |= pRequest->GetVariableLong(VID_FLAGS) & NF_USER_FLAGS;
1733 }
1734
1735 return Template::ModifyFromMessage(pRequest, TRUE);
1736 }
1737
1738
1739 //
1740 // Wakeup node using magic packet
1741 //
1742
1743 DWORD Node::WakeUp(void)
1744 {
1745 DWORD i, dwResult = RCC_NO_WOL_INTERFACES;
1746
1747 LockChildList(FALSE);
1748
1749 for(i = 0; i < m_dwChildCount; i++)
1750 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1751 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
1752 (m_pChildList[i]->IpAddr() != 0))
1753 {
1754 dwResult = ((Interface *)m_pChildList[i])->WakeUp();
1755 break;
1756 }
1757
1758 UnlockChildList();
1759 return dwResult;
1760 }
1761
1762
1763 //
1764 // Get status of interface with given index from SNMP agent
1765 //
1766
1767 int Node::GetInterfaceStatusFromSNMP(DWORD dwIndex)
1768 {
1769 return SnmpGetInterfaceStatus(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort,
1770 m_szCommunityString, dwIndex);
1771 }
1772
1773
1774 //
1775 // Get status of interface with given index from native agent
1776 //
1777
1778 int Node::GetInterfaceStatusFromAgent(DWORD dwIndex)
1779 {
1780 char szParam[128], szBuffer[32];
1781 DWORD dwAdminStatus, dwLinkState;
1782 int iStatus;
1783
1784 // Get administrative status
1785 sprintf(szParam, "Net.Interface.AdminStatus(%u)", dwIndex);
1786 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
1787 {
1788 dwAdminStatus = strtoul(szBuffer, NULL, 0);
1789
1790 switch(dwAdminStatus)
1791 {
1792 case 3:
1793 iStatus = STATUS_TESTING;
1794 break;
1795 case 2:
1796 case 0: // Agents before 0.2.1 may return 0 instead of 2
1797 iStatus = STATUS_DISABLED;
1798 break;
1799 case 1: // Interface administratively up, check link state
1800 sprintf(szParam, "Net.Interface.Link(%u)", dwIndex);
1801 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
1802 {
1803 dwLinkState = strtoul(szBuffer, NULL, 0);
1804 iStatus = (dwLinkState == 0) ? STATUS_CRITICAL : STATUS_NORMAL;
1805 }
1806 else
1807 {
1808 iStatus = STATUS_UNKNOWN;
1809 }
1810 break;
1811 default:
1812 iStatus = STATUS_UNKNOWN;
1813 break;
1814 }
1815 }
1816 else
1817 {
1818 iStatus = STATUS_UNKNOWN;
1819 }
1820
1821 return iStatus;
1822 }
1823
1824
1825 //
1826 // Put list of supported parameters into CSCP message
1827 //
1828
1829 void Node::WriteParamListToMessage(CSCPMessage *pMsg)
1830 {
1831 DWORD i, dwId;
1832
1833 LockData();
1834 if (m_pParamList != NULL)
1835 {
1836 pMsg->SetVariable(VID_NUM_PARAMETERS, m_dwNumParams);
1837 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < m_dwNumParams; i++)
1838 {
1839 pMsg->SetVariable(dwId++, m_pParamList[i].szName);
1840 pMsg->SetVariable(dwId++, m_pParamList[i].szDescription);
1841 pMsg->SetVariable(dwId++, (WORD)m_pParamList[i].iDataType);
1842 }
1843 }
1844 else
1845 {
1846 pMsg->SetVariable(VID_NUM_PARAMETERS, (DWORD)0);
1847 }
1848 UnlockData();
1849 }
1850
1851
1852 //
1853 // Open list of supported parameters for reading
1854 //
1855
1856 void Node::OpenParamList(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
1857 {
1858 LockData();
1859 *pdwNumParams = m_dwNumParams;
1860 *ppParamList = m_pParamList;
1861 }
1862
1863
1864 //
1865 // Check status of network service
1866 //
1867
1868 DWORD Node::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
1869 WORD wPort, WORD wProto, TCHAR *pszRequest,
1870 TCHAR *pszResponse)
1871 {
1872 DWORD dwError = ERR_NOT_CONNECTED;
1873
1874 if ((m_dwFlags & NF_IS_NATIVE_AGENT) &&
1875 (!(m_dwDynamicFlags & NDF_AGENT_UNREACHABLE)) &&
1876 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
1877 {
1878 AgentConnection *pConn;
1879
1880 pConn = CreateAgentConnection();
1881 if (pConn != NULL)
1882 {
1883 dwError = pConn->CheckNetworkService(pdwStatus, dwIpAddr, iServiceType,
1884 wPort, wProto, pszRequest, pszResponse);
1885 pConn->Disconnect();
1886 delete pConn;
1887 }
1888 }
1889 return dwError;
1890 }
1891
1892
1893 //
1894 // Handler for object deletion
1895 //
1896
1897 void Node::OnObjectDelete(DWORD dwObjectId)
1898 {
1899 if (dwObjectId == m_dwPollerNode)
1900 {
1901 // If deleted object is our poller node, change it to default
1902 /* LOCK? */
1903 m_dwPollerNode = 0;
1904 Modify();
1905 DbgPrintf(AF_DEBUG_MISC, _T("Node \"%s\": poller node %d deleted"), m_szName, dwObjectId);
1906 }
1907 }
1908
1909
1910 //
1911 // Check node for OSPF support
1912 //
1913
1914 void Node::CheckOSPFSupport(void)
1915 {
1916 LONG nAdminStatus;
1917
1918 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
1919 ".1.3.6.1.2.1.14.1.2.0", NULL, 0, &nAdminStatus, sizeof(LONG),
1920 FALSE, FALSE) == SNMP_ERR_SUCCESS)
1921 {
1922 if (nAdminStatus)
1923 {
1924 m_dwFlags |= NF_IS_OSPF;
1925 }
1926 else
1927 {
1928 m_dwFlags &= ~NF_IS_OSPF;
1929 }
1930 }
1931 }
1932
1933
1934 //
1935 // Create ready to use agent connection
1936 //
1937
1938 AgentConnection *Node::CreateAgentConnection(void)
1939 {
1940 AgentConnection *pConn;
1941
1942 if ((!(m_dwFlags & NF_IS_NATIVE_AGENT)) ||
1943 (m_dwDynamicFlags & NDF_AGENT_UNREACHABLE) ||
1944 (m_dwDynamicFlags & NDF_UNREACHABLE))
1945 return NULL;
1946
1947 pConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort,
1948 m_wAuthMethod, m_szSharedSecret);
1949 SetAgentProxy(pConn);
1950 if (!pConn->Connect(g_pServerKey))
1951 {
1952 delete pConn;
1953 pConn = NULL;
1954 }
1955 return pConn;
1956 }
1957
1958
1959 //
1960 // Get last collected values of all DCIs
1961 //
1962
1963 DWORD Node::GetLastValues(CSCPMessage *pMsg)
1964 {
1965 DWORD i, dwId;
1966
1967 LockData();
1968
1969 pMsg->SetVariable(VID_NUM_ITEMS, m_dwNumItems);
1970 for(i = 0, dwId = VID_DCI_VALUES_BASE; i < m_dwNumItems; i++, dwId += 7)
1971 m_ppItems[i]->GetLastValue(pMsg, dwId);
1972
1973 UnlockData();
1974 return RCC_SUCCESS;
1975 }
1976
1977
1978 //
1979 // Clean expired DCI data
1980 //
1981
1982 void Node::CleanDCIData(void)
1983 {
1984 DWORD i;
1985
1986 LockData();
1987 for(i = 0; i < m_dwNumItems; i++)
1988 m_ppItems[i]->CleanData();
1989 UnlockData();
1990 }
1991
1992
1993 //
1994 // Apply DCI from template
1995 // pItem passed to this method should be a template's DCI
1996 //
1997
1998 BOOL Node::ApplyTemplateItem(DWORD dwTemplateId, DCItem *pItem)
1999 {
2000 BOOL bResult = TRUE;
2001 DWORD i;
2002 DCItem *pNewItem;
2003
2004 LockData();
2005
2006 DbgPrintf(AF_DEBUG_DC, "Applying item \"%s\" to node \"%s\"", pItem->Name(), m_szName);
2007
2008 // Check if that template item exists
2009 for(i = 0; i < m_dwNumItems; i++)
2010 if ((m_ppItems[i]->TemplateId() == dwTemplateId) &&
2011 (m_ppItems[i]->TemplateItemId() == pItem->Id()))
2012 break; // Item with specified id already exist
2013
2014 if (i == m_dwNumItems)
2015 {
2016 // New item from template, just add it
2017 pNewItem = new DCItem(pItem);
2018 pNewItem->SetTemplateId(dwTemplateId, pItem->Id());
2019 pNewItem->ChangeBinding(CreateUniqueId(IDG_ITEM), this);
2020 bResult = AddItem(pNewItem, TRUE);
2021 }
2022 else
2023 {
2024 // Update existing item
2025 m_ppItems[i]->UpdateFromTemplate(pItem);
2026 Modify();
2027 }
2028
2029 UnlockData();
2030 return bResult;
2031 }
2032
2033
2034 //
2035 // Clean deleted template items from node's DCI list
2036 // Arguments is template id and list of valid template item ids.
2037 // all items related to given template and not presented in list should be deleted.
2038 //
2039
2040 void Node::CleanDeletedTemplateItems(DWORD dwTemplateId, DWORD dwNumItems, DWORD *pdwItemList)
2041 {
2042 DWORD i, j, dwNumDeleted, *pdwDeleteList;
2043
2044 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
2045 dwNumDeleted = 0;
2046
2047 LockData();
2048
2049 for(i = 0; i < m_dwNumItems; i++)
2050 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2051 {
2052 for(j = 0; j < dwNumItems; j++)
2053 if (m_ppItems[i]->TemplateItemId() == pdwItemList[j])
2054 break;
2055
2056 // Delete DCI if it's not in list
2057 if (j == dwNumItems)
2058 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->Id();
2059 }
2060
2061 UnlockData();
2062
2063 for(i = 0; i < dwNumDeleted; i++)
2064 DeleteItem(pdwDeleteList[i]);
2065 free(pdwDeleteList);
2066 }
2067
2068
2069 //
2070 // Unbind node from template, i.e either remove DCI association with template
2071 // or remove these DCIs at all
2072 //
2073
2074 void Node::UnbindFromTemplate(DWORD dwTemplateId, BOOL bRemoveDCI)
2075 {
2076 DWORD i;
2077
2078 if (bRemoveDCI)
2079 {
2080 DWORD dwNumDeleted, *pdwDeleteList;
2081
2082 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * m_dwNumItems);
2083 dwNumDeleted = 0;
2084
2085 LockData();
2086
2087 for(i = 0; i < m_dwNumItems; i++)
2088 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2089 {
2090 pdwDeleteList[dwNumDeleted++] = m_ppItems[i]->Id();
2091 }
2092
2093 UnlockData();
2094
2095 for(i = 0; i < dwNumDeleted; i++)
2096 DeleteItem(pdwDeleteList[i]);
2097 free(pdwDeleteList);
2098 }
2099 else
2100 {
2101 LockData();
2102
2103 for(i = 0; i < m_dwNumItems; i++)
2104 if (m_ppItems[i]->TemplateId() == dwTemplateId)
2105 {
2106 m_ppItems[i]->SetTemplateId(0, 0);
2107 }
2108
2109 UnlockData();
2110 }
2111 }
2112
2113
2114 //
2115 // Change node's IP address
2116 //
2117
2118 void Node::ChangeIPAddress(DWORD dwIpAddr)
2119 {
2120 DWORD i;
2121
2122 PollerLock();
2123
2124 LockData();
2125
2126 UpdateNodeIndex(m_dwIpAddr, dwIpAddr, this);
2127 m_dwIpAddr = dwIpAddr;
2128 m_dwDynamicFlags |= NDF_FORCE_CONFIGURATION_POLL | NDF_RECHECK_CAPABILITIES;
2129
2130 // Change status of node and all it's childs to UNKNOWN
2131 m_iStatus = STATUS_UNKNOWN;
2132 LockChildList(FALSE);
2133 for(i = 0; i < m_dwChildCount; i++)
2134 {
2135 m_pChildList[i]->ResetStatus();
2136 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2137 {
2138 if (((Interface *)m_pChildList[i])->IsFake())
2139 {
2140 ((Interface *)m_pChildList[i])->SetIpAddr(dwIpAddr);
2141 }
2142 }
2143 }
2144 UnlockChildList();
2145
2146 Modify();
2147 UnlockData();
2148
2149 AgentLock();
2150 delete_and_null(m_pAgentConnection);
2151 AgentUnlock();
2152
2153 PollerUnlock();
2154 }
2155
2156
2157 //
2158 // Get number of interface objects and pointer to the last one
2159 //
2160
2161 DWORD Node::GetInterfaceCount(Interface **ppInterface)
2162 {
2163 DWORD i, dwCount;
2164
2165 LockChildList(FALSE);
2166 for(i = 0, dwCount = 0; i < m_dwChildCount; i++)
2167 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
2168 {
2169 dwCount++;
2170 *ppInterface = (Interface *)m_pChildList[i];
2171 }
2172 UnlockChildList();
2173 return dwCount;
2174 }
2175
2176
2177 //
2178 // Update cache for all DCI's
2179 //
2180
2181 void Node::UpdateDCICache(void)
2182 {
2183 DWORD i;
2184
2185 /* LOCK? */
2186 for(i = 0; i < m_dwNumItems; i++)
2187 m_ppItems[i]->UpdateCacheSize();
2188 }
2189
2190
2191 //
2192 // Get routing table from node
2193 //
2194
2195 ROUTING_TABLE *Node::GetRoutingTable(void)
2196 {
2197 ROUTING_TABLE *pRT = NULL;
2198
2199 if ((m_dwFlags & NF_IS_NATIVE_AGENT) && (!(m_dwFlags & NF_DISABLE_NXCP)))
2200 {
2201 AgentLock();
2202 if (ConnectToAgent())
2203 {
2204 pRT = m_pAgentConnection->GetRoutingTable();
2205 }
2206 AgentUnlock();
2207 }
2208 if ((pRT == NULL) && (m_dwFlags & NF_IS_SNMP) && (!(m_dwFlags & NF_DISABLE_SNMP)))
2209 {
2210 pRT = SnmpGetRoutingTable(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString);
2211 }
2212
2213 if (pRT != NULL)
2214 {
2215 SortRoutingTable(pRT);
2216 }
2217 return pRT;
2218 }
2219
2220
2221 //
2222 // Get next hop for given destination address
2223 //
2224
2225 BOOL Node::GetNextHop(DWORD dwSrcAddr, DWORD dwDestAddr, DWORD *pdwNextHop,
2226 DWORD *pdwIfIndex, BOOL *pbIsVPN)
2227 {
2228 DWORD i;
2229 BOOL bResult = FALSE;
2230
2231 // Check VPN connectors
2232 LockChildList(FALSE);
2233 for(i = 0; i < m_dwChildCount; i++)
2234 if (m_pChildList[i]->Type() == OBJECT_VPNCONNECTOR)
2235 {
2236 if (((VPNConnector *)m_pChildList[i])->IsRemoteAddr(dwDestAddr) &&
2237 ((VPNConnector *)m_pChildList[i])->IsLocalAddr(dwSrcAddr))
2238 {
2239 *pdwNextHop = ((VPNConnector *)m_pChildList[i])->GetPeerGatewayAddr();
2240 *pdwIfIndex = m_pChildList[i]->Id();
2241 *pbIsVPN = TRUE;
2242 bResult = TRUE;
2243 break;
2244 }
2245 }
2246 UnlockChildList();
2247
2248 // Check routing table
2249 if (!bResult)
2250 {
2251 RTLock();
2252 if (m_pRoutingTable != NULL)
2253 {
2254 for(i = 0; i < (DWORD)m_pRoutingTable->iNumEntries; i++)
2255 if ((dwDestAddr & m_pRoutingTable->pRoutes[i].dwDestMask) == m_pRoutingTable->pRoutes[i].dwDestAddr)
2256 {
2257 *pdwNextHop = m_pRoutingTable->pRoutes[i].dwNextHop;
2258 *pdwIfIndex = m_pRoutingTable->pRoutes[i].dwIfIndex;
2259 *pbIsVPN = FALSE;
2260 bResult = TRUE;
2261 break;
2262 }
2263 }
2264 RTUnlock();
2265 }
2266
2267 return bResult;
2268 }
2269
2270
2271 //
2272 // Update cached routing table
2273 //
2274
2275 void Node::UpdateRoutingTable(void)
2276 {
2277 ROUTING_TABLE *pRT;
2278
2279 pRT = GetRoutingTable();
2280 if (pRT != NULL)
2281 {
2282 RTLock();
2283 DestroyRoutingTable(m_pRoutingTable);
2284 m_pRoutingTable = pRT;
2285 RTUnlock();
2286 }
2287 m_tLastRTUpdate = time(NULL);
2288 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_ROUTE_POLL;
2289 }
2290
2291
2292 //
2293 // Call SNMP Enumerate with node's SNMP parameters
2294 //
2295
2296 DWORD Node::CallSnmpEnumerate(char *pszRootOid,
2297 DWORD (* pHandler)(DWORD, DWORD, WORD, const char *, SNMP_Variable *, SNMP_Transport *, void *),
2298 void *pArg)
2299 {
2300 if ((m_dwFlags & NF_IS_SNMP) &&
2301 (!(m_dwDynamicFlags & NDF_SNMP_UNREACHABLE)) &&
2302 (!(m_dwDynamicFlags & NDF_UNREACHABLE)))
2303 return SnmpEnumerate(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort,
2304 m_szCommunityString, pszRootOid, pHandler, pArg, FALSE);
2305 else
2306 return SNMP_ERR_COMM;
2307 }
2308
2309
2310 //
2311 // Set proxy information for agent's connection
2312 //
2313
2314 void Node::SetAgentProxy(AgentConnection *pConn)
2315 {
2316 if (m_dwProxyNode != 0)
2317 {
2318 Node *pNode;
2319
2320 pNode = (Node *)FindObjectById(m_dwProxyNode);
2321 if (pNode != NULL)
2322 {
2323 pConn->SetProxy(htonl(pNode->m_dwIpAddr), pNode->m_wAgentPort,
2324 pNode->m_wAuthMethod, pNode->m_szSharedSecret);
2325 }
2326 }
2327 }
2328
2329
2330 //
2331 // Prepare node object for deletion
2332 //
2333
2334 void Node::PrepareForDeletion(void)
2335 {
2336 // Prevent node from being queued for polling
2337 LockData();
2338 m_dwDynamicFlags |= NDF_POLLING_DISABLED;
2339 UnlockData();
2340
2341 // Wait for all pending polls
2342 while(1)
2343 {
2344 LockData();
2345 if ((m_dwDynamicFlags &
2346 (NDF_QUEUED_FOR_STATUS_POLL | NDF_QUEUED_FOR_CONFIG_POLL |
2347 NDF_QUEUED_FOR_DISCOVERY_POLL | NDF_QUEUED_FOR_ROUTE_POLL)) == 0)
2348 {
2349 UnlockData();
2350 break;
2351 }
2352 UnlockData();
2353 ThreadSleepMs(100);
2354 }
2355 }
2356
2357
2358 //
2359 // Check if specified SNMP variable set to specified value.
2360 // If variable doesn't exist at all, will return FALSE
2361 //
2362
2363 BOOL Node::CheckSNMPIntegerValue(char *pszOID, int nValue)
2364 {
2365 DWORD dwTemp;
2366
2367 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_wSNMPPort, m_szCommunityString,
2368 pszOID, NULL, 0, &dwTemp, sizeof(DWORD), FALSE, FALSE) == SNMP_ERR_SUCCESS)
2369 return (int)dwTemp == nValue;
2370 return FALSE;
2371 }
2372
2373
2374 //
2375 // Check and update if needed interface names
2376 //
2377
2378 void Node::CheckInterfaceNames(INTERFACE_LIST *pIfList)
2379 {
2380 int i;
2381 TCHAR *ptr;
2382
2383 if (m_dwNodeType == NODE_TYPE_NORTEL_BAYSTACK)
2384 {
2385 // Translate interface names
2386 for(i = 0; i < pIfList->iNumEntries; i++)
2387 {
2388 if ((_tcsstr(pIfList->pInterfaces[i].szName, _T("BayStack")) != NULL) ||
2389 (_tcsstr(pIfList->pInterfaces[i].szName, _T("Nortel Ethernet Switch")) != NULL))
2390 {
2391 ptr = _tcsrchr(pIfList->pInterfaces[i].szName, _T('-'));
2392 if (ptr != NULL)
2393 {
2394 ptr++;
2395 while(*ptr == _T(' '))
2396 ptr++;
2397 memmove(pIfList->pInterfaces[i].szName, ptr, _tcslen(ptr) + 1);
2398 }
2399 }
2400 }
2401 }
2402
2403 // Cut interface names to MAX_OBJECT_NAME and check for unnamed interfaces
2404 for(i = 0; i < pIfList->iNumEntries; i++)
2405 {
2406 pIfList->pInterfaces[i].szName[MAX_OBJECT_NAME - 1] = 0;
2407 if (pIfList->pInterfaces[i].szName[0] == 0)
2408 _stprintf(pIfList->pInterfaces[i].szName, _T("%d"), pIfList->pInterfaces[i].dwIndex);
2409 }
2410 }