Added internal parameter AgentStatus
[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_dwDiscoveryFlags = 0;
35 m_dwDynamicFlags = 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 strcpy(m_szCommunityString, "public");
43 m_szObjectId[0] = 0;
44 m_tLastDiscoveryPoll = 0;
45 m_tLastStatusPoll = 0;
46 m_tLastConfigurationPoll = 0;
47 m_iSnmpAgentFails = 0;
48 m_iNativeAgentFails = 0;
49 m_hPollerMutex = MutexCreate();
50 m_hAgentAccessMutex = MutexCreate();
51 m_pAgentConnection = NULL;
52 m_szAgentVersion[0] = 0;
53 m_szPlatformName[0] = 0;
54 m_dwNumParams = 0;
55 m_pParamList = NULL;
56 m_dwPollerNode = 0;
57 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
58 }
59
60
61 //
62 // Constructor for new node object
63 //
64
65 Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwDiscoveryFlags)
66 :Template()
67 {
68 m_dwIpAddr = dwAddr;
69 m_dwFlags = dwFlags;
70 m_dwDynamicFlags = 0;
71 m_dwNodeType = NODE_TYPE_GENERIC;
72 m_dwDiscoveryFlags = dwDiscoveryFlags;
73 m_wAgentPort = AGENT_LISTEN_PORT;
74 m_wAuthMethod = AUTH_NONE;
75 m_szSharedSecret[0] = 0;
76 m_iStatusPollType = POLL_ICMP_PING;
77 m_iSNMPVersion = SNMP_VERSION_1;
78 strcpy(m_szCommunityString, "public");
79 IpToStr(dwAddr, m_szName); // Make default name from IP address
80 m_szObjectId[0] = 0;
81 m_tLastDiscoveryPoll = 0;
82 m_tLastStatusPoll = 0;
83 m_tLastConfigurationPoll = 0;
84 m_iSnmpAgentFails = 0;
85 m_iNativeAgentFails = 0;
86 m_hPollerMutex = MutexCreate();
87 m_hAgentAccessMutex = MutexCreate();
88 m_pAgentConnection = NULL;
89 m_szAgentVersion[0] = 0;
90 m_szPlatformName[0] = 0;
91 m_dwNumParams = 0;
92 m_pParamList = NULL;
93 m_dwPollerNode = 0;
94 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
95 }
96
97
98 //
99 // Node destructor
100 //
101
102 Node::~Node()
103 {
104 MutexDestroy(m_hPollerMutex);
105 MutexDestroy(m_hAgentAccessMutex);
106 if (m_pAgentConnection != NULL)
107 delete m_pAgentConnection;
108 safe_free(m_pParamList);
109 }
110
111
112 //
113 // Create object from database data
114 //
115
116 BOOL Node::CreateFromDB(DWORD dwId)
117 {
118 char szQuery[512];
119 DB_RESULT hResult;
120 int i, iNumRows;
121 DWORD dwSubnetId;
122 NetObj *pObject;
123 BOOL bResult = FALSE;
124
125 _sntprintf(szQuery, 512, "SELECT name,status,primary_ip,node_flags,"
126 "snmp_version,discovery_flags,auth_method,secret,"
127 "agent_port,status_poll_type,community,snmp_oid,"
128 "image_id,is_deleted,description,node_type,agent_version,"
129 "platform_name,poller_node_id FROM nodes WHERE id=%d", dwId);
130 hResult = DBSelect(g_hCoreDB, szQuery);
131 if (hResult == 0)
132 return FALSE; // Query failed
133
134 if (DBGetNumRows(hResult) == 0)
135 {
136 DBFreeResult(hResult);
137 return FALSE;
138 }
139
140 m_dwId = dwId;
141 strncpy(m_szName, DBGetField(hResult, 0, 0), MAX_OBJECT_NAME);
142 m_iStatus = DBGetFieldLong(hResult, 0, 1);
143 m_dwIpAddr = DBGetFieldIPAddr(hResult, 0, 2);
144 m_dwFlags = DBGetFieldULong(hResult, 0, 3);
145 m_iSNMPVersion = DBGetFieldLong(hResult, 0, 4);
146 m_dwDiscoveryFlags = DBGetFieldULong(hResult, 0, 5);
147 m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 6);
148 strncpy(m_szSharedSecret, DBGetField(hResult, 0, 7), MAX_SECRET_LENGTH);
149 m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 8);
150 m_iStatusPollType = DBGetFieldLong(hResult, 0, 9);
151 strncpy(m_szCommunityString, DBGetField(hResult, 0, 10), MAX_COMMUNITY_LENGTH);
152 strncpy(m_szObjectId, DBGetField(hResult, 0, 11), MAX_OID_LEN * 4);
153 m_dwImageId = DBGetFieldULong(hResult, 0, 12);
154 m_bIsDeleted = DBGetFieldLong(hResult, 0, 13);
155 m_pszDescription = _tcsdup(CHECK_NULL_EX(DBGetField(hResult, 0, 14)));
156 DecodeSQLString(m_pszDescription);
157 m_dwNodeType = DBGetFieldULong(hResult, 0, 15);
158 _tcsncpy(m_szAgentVersion, CHECK_NULL_EX(DBGetField(hResult, 0, 16)), MAX_AGENT_VERSION_LEN);
159 DecodeSQLString(m_szAgentVersion);
160 _tcsncpy(m_szPlatformName, CHECK_NULL_EX(DBGetField(hResult, 0, 17)), MAX_PLATFORM_NAME_LEN);
161 DecodeSQLString(m_szPlatformName);
162 m_dwPollerNode = DBGetFieldULong(hResult, 0, 18);
163
164 DBFreeResult(hResult);
165
166 if (!m_bIsDeleted)
167 {
168 // Link node to subnets
169 sprintf(szQuery, "SELECT subnet_id FROM nsmap WHERE node_id=%ld", dwId);
170 hResult = DBSelect(g_hCoreDB, szQuery);
171 if (hResult == NULL)
172 return FALSE; // Query failed
173
174 iNumRows = DBGetNumRows(hResult);
175 if (iNumRows == 0)
176 {
177 DBFreeResult(hResult);
178 return FALSE; // No parents - it shouldn't happen if database isn't corrupted
179 }
180
181 for(i = 0; i < iNumRows; i++)
182 {
183 dwSubnetId = DBGetFieldULong(hResult, i, 0);
184 pObject = FindObjectById(dwSubnetId);
185 if (pObject == NULL)
186 {
187 WriteLog(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
188 break;
189 }
190 else if (pObject->Type() != OBJECT_SUBNET)
191 {
192 WriteLog(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
193 break;
194 }
195 else
196 {
197 pObject->AddChild(this);
198 AddParent(pObject);
199 bResult = TRUE;
200 }
201 }
202
203 DBFreeResult(hResult);
204 LoadItemsFromDB();
205 LoadACLFromDB();
206
207 // Walk through all items in the node and load appropriate thresholds
208 for(i = 0; i < (int)m_dwNumItems; i++)
209 if (!m_ppItems[i]->LoadThresholdsFromDB())
210 bResult = FALSE;
211 }
212 else
213 {
214 bResult = TRUE;
215 }
216
217 return bResult;
218 }
219
220
221 //
222 // Save object to database
223 //
224
225 BOOL Node::SaveToDB(void)
226 {
227 TCHAR *pszEscDescr, *pszEscVersion, *pszEscPlatform;
228 TCHAR szQuery[4096], szIpAddr[16];
229 DB_RESULT hResult;
230 BOOL bNewObject = TRUE;
231 BOOL bResult;
232
233 // Lock object's access
234 Lock();
235
236 // Check for object's existence in database
237 sprintf(szQuery, "SELECT id FROM nodes WHERE id=%ld", m_dwId);
238 hResult = DBSelect(g_hCoreDB, szQuery);
239 if (hResult != 0)
240 {
241 if (DBGetNumRows(hResult) > 0)
242 bNewObject = FALSE;
243 DBFreeResult(hResult);
244 }
245
246 // Form and execute INSERT or UPDATE query
247 pszEscDescr = EncodeSQLString(CHECK_NULL_EX(m_pszDescription));
248 pszEscVersion = EncodeSQLString(m_szAgentVersion);
249 pszEscPlatform = EncodeSQLString(m_szPlatformName);
250 if (bNewObject)
251 snprintf(szQuery, 4096,
252 "INSERT INTO nodes (id,name,status,is_deleted,primary_ip,"
253 "node_flags,snmp_version,community,discovery_flags,status_poll_type,"
254 "agent_port,auth_method,secret,snmp_oid,image_id,"
255 "description,node_type,agent_version,platform_name,"
256 "poller_node_id) VALUES (%ld,'%s',%d,%d,'%s',%ld,%d,'%s',%ld,%d,%d,%d,"
257 "'%s','%s',%ld,'%s',%ld,'%s','%s',%ld)",
258 m_dwId, m_szName, m_iStatus, m_bIsDeleted,
259 IpToStr(m_dwIpAddr, szIpAddr), m_dwFlags,
260 m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags, m_iStatusPollType,
261 m_wAgentPort, m_wAuthMethod, m_szSharedSecret, m_szObjectId,
262 m_dwImageId, pszEscDescr, m_dwNodeType, pszEscVersion, pszEscPlatform,
263 m_dwPollerNode);
264 else
265 snprintf(szQuery, 4096,
266 "UPDATE nodes SET name='%s',status=%d,is_deleted=%d,primary_ip='%s',"
267 "node_flags=%ld,snmp_version=%d,community='%s',discovery_flags=%d,"
268 "status_poll_type=%d,agent_port=%d,auth_method=%d,secret='%s',"
269 "snmp_oid='%s',image_id=%ld,description='%s',node_type=%ld,"
270 "agent_version='%s',platform_name='%s',poller_node_id=%ld WHERE id=%ld",
271 m_szName, m_iStatus, m_bIsDeleted,
272 IpToStr(m_dwIpAddr, szIpAddr),
273 m_dwFlags, m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags,
274 m_iStatusPollType, m_wAgentPort, m_wAuthMethod, m_szSharedSecret,
275 m_szObjectId, m_dwImageId, pszEscDescr, m_dwNodeType,
276 pszEscVersion, pszEscPlatform, m_dwPollerNode, m_dwId);
277 bResult = DBQuery(g_hCoreDB, szQuery);
278 free(pszEscDescr);
279 free(pszEscVersion);
280 free(pszEscPlatform);
281
282 // Save data collection items
283 if (bResult)
284 {
285 DWORD i;
286
287 for(i = 0; i < m_dwNumItems; i++)
288 m_ppItems[i]->SaveToDB();
289 }
290
291 // Save access list
292 SaveACLToDB();
293
294 // Clear modifications flag and unlock object
295 m_bIsModified = FALSE;
296 Unlock();
297
298 return bResult;
299 }
300
301
302 //
303 // Delete object from database
304 //
305
306 BOOL Node::DeleteFromDB(void)
307 {
308 char szQuery[256];
309 BOOL bSuccess;
310
311 bSuccess = Template::DeleteFromDB();
312 if (bSuccess)
313 {
314 sprintf(szQuery, "DELETE FROM nodes WHERE id=%ld", m_dwId);
315 QueueSQLRequest(szQuery);
316 sprintf(szQuery, "DELETE FROM nsmap WHERE node_id=%ld", m_dwId);
317 QueueSQLRequest(szQuery);
318 sprintf(szQuery, "DROP TABLE idata_%ld", m_dwId);
319 QueueSQLRequest(szQuery);
320 }
321 return bSuccess;
322 }
323
324
325 //
326 // Poll newly discovered node
327 // Usually called once by node poller thread when new node is discovered
328 // and object for it is created
329 //
330
331 void Node::NewNodePoll(DWORD dwNetMask)
332 {
333 AgentConnection *pAgentConn;
334
335 PollerLock();
336
337 // Determine node's capabilities
338 if (SnmpGet(SNMP_VERSION_2C, m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0,
339 m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE) == SNMP_ERR_SUCCESS)
340 {
341 DWORD dwNodeFlags;
342
343 m_dwNodeType = OidToType(m_szObjectId, &dwNodeFlags);
344 m_dwFlags |= NF_IS_SNMP | dwNodeFlags;
345 m_iSNMPVersion = SNMP_VERSION_2C;
346 }
347 else
348 {
349 if (SnmpGet(SNMP_VERSION_1, m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0,
350 m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE) == SNMP_ERR_SUCCESS)
351 {
352 DWORD dwNodeFlags;
353
354 m_dwNodeType = OidToType(m_szObjectId, &dwNodeFlags);
355 m_dwFlags |= NF_IS_SNMP | dwNodeFlags;
356 m_iSNMPVersion = SNMP_VERSION_1;
357 }
358 }
359
360 // Check OSPF capabilities
361 if (m_dwFlags & NF_IS_SNMP)
362 {
363 CheckOSPFSupport();
364 }
365
366 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod,
367 m_szSharedSecret);
368 if (pAgentConn->Connect())
369 {
370 m_dwFlags |= NF_IS_NATIVE_AGENT;
371 pAgentConn->GetParameter("Agent.Version", MAX_AGENT_VERSION_LEN, m_szAgentVersion);
372 pAgentConn->GetParameter("System.PlatformName", MAX_PLATFORM_NAME_LEN, m_szPlatformName);
373
374 pAgentConn->GetSupportedParameters(&m_dwNumParams, &m_pParamList);
375 }
376
377 // Get interface list
378 if ((m_dwFlags & NF_IS_SNMP) || (m_dwFlags & NF_IS_NATIVE_AGENT) ||
379 (m_dwFlags & NF_IS_LOCAL_MGMT))
380 {
381 INTERFACE_LIST *pIfList = NULL;
382 int i;
383
384 if (m_dwFlags & NF_IS_LOCAL_MGMT) // For local machine
385 pIfList = GetLocalInterfaceList();
386 else if (m_dwFlags & NF_IS_NATIVE_AGENT) // For others prefer native agent
387 {
388 pIfList = pAgentConn->GetInterfaceList();
389 CleanInterfaceList(pIfList);
390 }
391 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP)) // Use SNMP if we cannot get interfaces via agent
392 pIfList = SnmpGetInterfaceList(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString, m_dwNodeType);
393
394 if (pIfList != NULL)
395 {
396 for(i = 0; i < pIfList->iNumEntries; i++)
397 CreateNewInterface(pIfList->pInterfaces[i].dwIpAddr,
398 pIfList->pInterfaces[i].dwIpNetMask,
399 pIfList->pInterfaces[i].szName,
400 pIfList->pInterfaces[i].dwIndex,
401 pIfList->pInterfaces[i].dwType,
402 pIfList->pInterfaces[i].bMacAddr);
403
404 // Check if address we are using to communicate with node
405 // is configured on one of node's interfaces
406 for(i = 0; i < pIfList->iNumEntries; i++)
407 if (pIfList->pInterfaces[i].dwIpAddr == m_dwIpAddr)
408 break;
409
410 if (i == pIfList->iNumEntries)
411 {
412 char szBuffer[MAX_OBJECT_NAME];
413
414 // Node is behind NAT
415 m_dwFlags |= NF_BEHIND_NAT;
416
417 // Create pseudo interface for NAT
418 ConfigReadStr("NATAdapterName", szBuffer, MAX_OBJECT_NAME, "NetXMS NAT Adapter");
419 CreateNewInterface(m_dwIpAddr, 0, szBuffer,
420 0x7FFFFFFF, IFTYPE_NETXMS_NAT_ADAPTER);
421 }
422
423 DestroyInterfaceList(pIfList);
424 }
425 else
426 {
427 // We cannot get interface list from node for some reasons, create dummy one
428 CreateNewInterface(m_dwIpAddr, dwNetMask);
429 }
430 }
431 else // No SNMP, no native agent - create pseudo interface object
432 {
433 CreateNewInterface(m_dwIpAddr, dwNetMask);
434 }
435
436 // Clean up agent connection
437 if (m_dwFlags & NF_IS_NATIVE_AGENT)
438 pAgentConn->Disconnect();
439 delete pAgentConn;
440
441 PollerUnlock();
442 }
443
444
445 //
446 // Get ARP cache from node
447 //
448
449 ARP_CACHE *Node::GetArpCache(void)
450 {
451 ARP_CACHE *pArpCache = NULL;
452
453 if (m_dwFlags & NF_IS_LOCAL_MGMT)
454 {
455 pArpCache = GetLocalArpCache();
456 }
457 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
458 {
459 AgentLock();
460 if (ConnectToAgent())
461 pArpCache = m_pAgentConnection->GetArpCache();
462 AgentUnlock();
463 }
464 else if (m_dwFlags & NF_IS_SNMP)
465 {
466 pArpCache = SnmpGetArpCache(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString);
467 }
468
469 return pArpCache;
470 }
471
472
473 //
474 // Get list of interfaces from node
475 //
476
477 INTERFACE_LIST *Node::GetInterfaceList(void)
478 {
479 INTERFACE_LIST *pIfList = NULL;
480
481 if (m_dwFlags & NF_IS_LOCAL_MGMT)
482 {
483 pIfList = GetLocalInterfaceList();
484 }
485 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
486 {
487 AgentLock();
488 if (ConnectToAgent())
489 {
490 pIfList = m_pAgentConnection->GetInterfaceList();
491 CleanInterfaceList(pIfList);
492 }
493 AgentUnlock();
494 }
495 else if (m_dwFlags & NF_IS_SNMP)
496 {
497 pIfList = SnmpGetInterfaceList(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString, m_dwNodeType);
498 }
499
500 return pIfList;
501 }
502
503
504 //
505 // Find interface by index and node IP
506 // Returns pointer to interface object or NULL if appropriate interface couldn't be found
507 //
508
509 Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
510 {
511 DWORD i;
512 Interface *pInterface;
513
514 Lock();
515 for(i = 0; i < m_dwChildCount; i++)
516 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
517 {
518 pInterface = (Interface *)m_pChildList[i];
519 if (pInterface->IfIndex() == dwIndex)
520 {
521 if ((pInterface->IpAddr() & pInterface->IpNetMask()) ==
522 (dwHostAddr & pInterface->IpNetMask()))
523 {
524 Unlock();
525 return pInterface;
526 }
527 }
528 }
529 Unlock();
530 return NULL;
531 }
532
533
534 //
535 // Create new interface
536 //
537
538 void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName,
539 DWORD dwIndex, DWORD dwType, BYTE *pbMacAddr)
540 {
541 Interface *pInterface;
542 Subnet *pSubnet = NULL;
543
544 // Find subnet to place interface object to
545 if (dwIpAddr != 0)
546 {
547 pSubnet = FindSubnetForNode(dwIpAddr);
548 if (pSubnet == NULL)
549 {
550 // Check if netmask is 0 (detect), and if yes, create
551 // new subnet with class mask
552 if (dwNetMask == 0)
553 {
554 if (dwIpAddr < 0x80000000)
555 dwNetMask = 0xFF000000; // Class A
556 else if (dwIpAddr < 0xC0000000)
557 dwNetMask = 0xFFFF0000; // Class B
558 else if (dwIpAddr < 0xE0000000)
559 dwNetMask = 0xFFFFFF00; // Class C
560 else
561 {
562 TCHAR szBuffer[16];
563
564 // Multicast address??
565 DbgPrintf(AF_DEBUG_DISCOVERY,
566 "Attempt to create interface object with multicast address %s",
567 IpToStr(dwIpAddr, szBuffer));
568 }
569 }
570
571 // Create new subnet object
572 if (dwIpAddr < 0xE0000000)
573 {
574 pSubnet = new Subnet(dwIpAddr & dwNetMask, dwNetMask);
575 NetObjInsert(pSubnet, TRUE);
576 g_pEntireNet->AddSubnet(pSubnet);
577 }
578 }
579 else
580 {
581 // Set correct netmask if we was asked for it
582 if (dwNetMask == 0)
583 {
584 dwNetMask = pSubnet->IpNetMask();
585 }
586 }
587 }
588
589 // Create interface object
590 if (szName != NULL)
591 pInterface = new Interface(szName, dwIndex, dwIpAddr, dwNetMask, dwType);
592 else
593 pInterface = new Interface(dwIpAddr, dwNetMask);
594 if (pbMacAddr != NULL)
595 pInterface->SetMacAddr(pbMacAddr);
596
597 // Insert to objects' list and generate event
598 NetObjInsert(pInterface, TRUE);
599 AddInterface(pInterface);
600 PostEvent(EVENT_INTERFACE_ADDED, m_dwId, "dsaad", pInterface->Id(),
601 pInterface->Name(), pInterface->IpAddr(),
602 pInterface->IpNetMask(), pInterface->IfIndex());
603
604 // Bind node to appropriate subnet
605 if (pSubnet != NULL)
606 {
607 pSubnet->AddNode(this);
608
609 // Check if subnet mask is correct on interface
610 if (pSubnet->IpNetMask() != dwNetMask)
611 PostEvent(EVENT_INCORRECT_NETMASK, m_dwId, "idsaa", pInterface->Id(),
612 pInterface->IfIndex(), pInterface->Name(),
613 pInterface->IpNetMask(), pSubnet->IpNetMask());
614 }
615 }
616
617
618 //
619 // Delete interface from node
620 //
621
622 void Node::DeleteInterface(Interface *pInterface)
623 {
624 DWORD i;
625
626 // Check if we should unlink node from interface's subnet
627 if (pInterface->IpAddr() != 0)
628 {
629 for(i = 0; i < m_dwChildCount; i++)
630 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
631 if (m_pChildList[i] != pInterface)
632 if ((((Interface *)m_pChildList[i])->IpAddr() & ((Interface *)m_pChildList[i])->IpNetMask()) ==
633 (pInterface->IpAddr() & pInterface->IpNetMask()))
634 break;
635 if (i == m_dwChildCount)
636 {
637 // Last interface in subnet, should unlink node
638 Subnet *pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
639 DeleteParent(pSubnet);
640 if (pSubnet != NULL)
641 {
642 pSubnet->DeleteChild(this);
643 if ((pSubnet->IsEmpty()) && (g_dwFlags & AF_DELETE_EMPTY_SUBNETS))
644 {
645 PostEvent(EVENT_SUBNET_DELETED, pSubnet->Id(), NULL);
646 pSubnet->Delete(FALSE);
647 }
648 }
649 }
650 }
651 pInterface->Delete(FALSE);
652 }
653
654
655 //
656 // Calculate node status based on child objects status
657 //
658
659 void Node::CalculateCompoundStatus(void)
660 {
661 int iOldStatus = m_iStatus;
662 static DWORD dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_MINOR,
663 EVENT_NODE_WARNING, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
664 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
665
666 NetObj::CalculateCompoundStatus();
667 if (m_iStatus != iOldStatus)
668 PostEvent(dwEventCodes[m_iStatus], m_dwId, "d", iOldStatus);
669 }
670
671
672 //
673 // Perform status poll on node
674 //
675
676 void Node::StatusPoll(ClientSession *pSession, DWORD dwRqId)
677 {
678 DWORD i, dwPollListSize;
679 NetObj *pPollerNode = NULL, **ppPollList;
680
681 PollerLock();
682 m_pPollRequestor = pSession;
683 SendPollerMsg(dwRqId, _T("Starting status poll for node %s\r\n"), m_szName);
684 Lock();
685
686 // Find service poller node object
687 if (m_dwPollerNode != 0)
688 {
689 pPollerNode = FindObjectById(m_dwPollerNode);
690 if (pPollerNode != NULL)
691 {
692 if (pPollerNode->Type() != OBJECT_NODE)
693 pPollerNode = NULL;
694 }
695 }
696
697 // If nothing found, use management server
698 if (pPollerNode == NULL)
699 {
700 pPollerNode = FindObjectById(g_dwMgmtNode);
701 if (pPollerNode != NULL)
702 pPollerNode->IncRefCount();
703 }
704 else
705 {
706 pPollerNode->IncRefCount();
707 }
708
709 // Create polling list
710 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_dwChildCount);
711 for(i = 0, dwPollListSize = 0; i < m_dwChildCount; i++)
712 if (m_pChildList[i]->Status() != STATUS_UNMANAGED)
713 {
714 m_pChildList[i]->IncRefCount();
715 ppPollList[dwPollListSize++] = m_pChildList[i];
716 }
717 Unlock();
718
719 // Poll interfaces and services
720 for(i = 0; i < dwPollListSize; i++)
721 {
722 switch(ppPollList[i]->Type())
723 {
724 case OBJECT_INTERFACE:
725 ((Interface *)ppPollList[i])->StatusPoll(pSession, dwRqId);
726 break;
727 case OBJECT_NETWORKSERVICE:
728 ((NetworkService *)ppPollList[i])->StatusPoll(pSession, dwRqId, (Node *)pPollerNode);
729 break;
730 default:
731 break;
732 }
733 ppPollList[i]->DecRefCount();
734 }
735 safe_free(ppPollList);
736
737 if (pPollerNode != NULL)
738 pPollerNode->DecRefCount();
739
740 CalculateCompoundStatus();
741 m_tLastStatusPoll = time(NULL);
742 SendPollerMsg(dwRqId, "Finished status poll for node %s\r\n"
743 "Node status after poll is %s\r\n", m_szName, g_pszStatusName[m_iStatus]);
744 m_pPollRequestor = NULL;
745 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_STATUS_POLL;
746 PollerUnlock();
747 }
748
749
750 //
751 // Perform configuration poll on node
752 //
753
754 void Node::ConfigurationPoll(ClientSession *pSession, DWORD dwRqId)
755 {
756 DWORD dwOldFlags = m_dwFlags;
757 AgentConnection *pAgentConn;
758 INTERFACE_LIST *pIfList;
759 char szBuffer[4096];
760 BOOL bHasChanges = FALSE;
761
762 PollerLock();
763 m_pPollRequestor = pSession;
764 SendPollerMsg(dwRqId, _T("Starting configuration poll for node %s\r\n"), m_szName);
765 DbgPrintf(AF_DEBUG_DISCOVERY, "Starting configuration poll for node %s (ID: %d)", m_szName, m_dwId);
766
767 // Check node's capabilities
768 SendPollerMsg(dwRqId, _T("Checking node's capabilities...\r\n"));
769 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0,
770 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
771 {
772 DWORD dwNodeFlags, dwNodeType;
773
774 if (strcmp(m_szObjectId, szBuffer))
775 {
776 strncpy(m_szObjectId, szBuffer, MAX_OID_LEN * 4);
777 bHasChanges = TRUE;
778 }
779
780 m_dwFlags |= NF_IS_SNMP;
781 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHEABLE;
782 m_iSnmpAgentFails = 0;
783 SendPollerMsg(dwRqId, _T(" SNMP agent is active\r\n"));
784
785 // Check node type
786 dwNodeType = OidToType(m_szObjectId, &dwNodeFlags);
787 if (m_dwNodeType != dwNodeType)
788 {
789 m_dwFlags |= dwNodeFlags;
790 m_dwNodeType = dwNodeType;
791 SendPollerMsg(dwRqId, _T(" Node type has been changed to %d\r\n"), m_dwNodeType);
792 bHasChanges = TRUE;
793 }
794
795 CheckOSPFSupport();
796 }
797 else
798 {
799 if (m_dwFlags & NF_IS_SNMP)
800 {
801 if (m_iSnmpAgentFails == 0)
802 PostEvent(EVENT_SNMP_FAIL, m_dwId, NULL);
803 m_iSnmpAgentFails++;
804 m_dwDynamicFlags |= NDF_SNMP_UNREACHEABLE;
805 }
806 SendPollerMsg(dwRqId, _T(" SNMP agent is not responding\r\n"));
807 }
808
809 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
810 if (pAgentConn->Connect())
811 {
812 m_dwFlags |= NF_IS_NATIVE_AGENT;
813 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHEABLE;
814 m_iNativeAgentFails = 0;
815
816 Lock();
817
818 if (pAgentConn->GetParameter("Agent.Version", MAX_AGENT_VERSION_LEN, szBuffer) == ERR_SUCCESS)
819 {
820 if (strcmp(m_szAgentVersion, szBuffer))
821 {
822 strcpy(m_szAgentVersion, szBuffer);
823 bHasChanges = TRUE;
824 SendPollerMsg(dwRqId, _T(" NetXMS agent version changed to %s\r\n"), m_szAgentVersion);
825 }
826 }
827
828 if (pAgentConn->GetParameter("System.PlatformName", MAX_PLATFORM_NAME_LEN, szBuffer) == ERR_SUCCESS)
829 {
830 if (strcmp(m_szPlatformName, szBuffer))
831 {
832 strcpy(m_szPlatformName, szBuffer);
833 bHasChanges = TRUE;
834 SendPollerMsg(dwRqId, _T(" Platform name changed to %s\r\n"), m_szAgentVersion);
835 }
836 }
837
838 safe_free(m_pParamList);
839 pAgentConn->GetSupportedParameters(&m_dwNumParams, &m_pParamList);
840
841 Unlock();
842 pAgentConn->Disconnect();
843 SendPollerMsg(dwRqId, _T(" NetXMS native agent is active\r\n"));
844 }
845 else
846 {
847 if (m_dwFlags & NF_IS_NATIVE_AGENT)
848 {
849 if (m_iNativeAgentFails == 0)
850 PostEvent(EVENT_AGENT_FAIL, m_dwId, NULL);
851 m_iNativeAgentFails++;
852 m_dwDynamicFlags |= NDF_AGENT_UNREACHEABLE;
853 }
854 SendPollerMsg(dwRqId, _T(" NetXMS native agent is not responding\r\n"));
855 }
856 delete pAgentConn;
857
858 // Generate event if node flags has been changed
859 if (dwOldFlags != m_dwFlags)
860 {
861 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
862 bHasChanges = TRUE;
863 }
864
865 // Retrieve interface list
866 SendPollerMsg(dwRqId, _T("Capability check finished\r\n"
867 "Checking interface configuration...\r\n"));
868 pIfList = GetInterfaceList();
869 if (pIfList != NULL)
870 {
871 DWORD i;
872 int j;
873
874 // Find non-existing interfaces
875 for(i = 0; i < m_dwChildCount; i++)
876 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
877 {
878 Interface *pInterface = (Interface *)m_pChildList[i];
879
880 if (pInterface->IfType() != IFTYPE_NETXMS_NAT_ADAPTER)
881 {
882 for(j = 0; j < pIfList->iNumEntries; j++)
883 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
884 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
885 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
886 break;
887 if (j == pIfList->iNumEntries)
888 {
889 // No such interface in current configuration, delete it
890 SendPollerMsg(dwRqId, _T(" Interface \"%s\" is no longer exist\r\n"),
891 pInterface->Name());
892 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", pInterface->IfIndex(),
893 pInterface->Name(), pInterface->IpAddr(), pInterface->IpNetMask());
894 DeleteInterface(pInterface);
895 i = 0xFFFFFFFF; // Restart loop
896 bHasChanges = TRUE;
897 }
898 }
899 }
900
901 // Add new interfaces and check configuration of existing
902 for(j = 0; j < pIfList->iNumEntries; j++)
903 {
904 for(i = 0; i < m_dwChildCount; i++)
905 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
906 {
907 Interface *pInterface = (Interface *)m_pChildList[i];
908
909 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
910 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
911 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
912 {
913 // Existing interface, check configuration
914 if (memcmp(pIfList->pInterfaces[j].bMacAddr, pInterface->MacAddr(), MAC_ADDR_LENGTH))
915 {
916 char szOldMac[16], szNewMac[16];
917
918 BinToStr((BYTE *)pInterface->MacAddr(), MAC_ADDR_LENGTH, szOldMac);
919 BinToStr(pIfList->pInterfaces[j].bMacAddr, MAC_ADDR_LENGTH, szNewMac);
920 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
921 pInterface->Id(), pInterface->IfIndex(),
922 pInterface->Name(), szOldMac, szNewMac);
923 pInterface->SetMacAddr(pIfList->pInterfaces[j].bMacAddr);
924 }
925 break;
926 }
927 }
928 if (i == m_dwChildCount)
929 {
930 // New interface
931 SendPollerMsg(dwRqId, _T(" Found new interface \"%s\"\r\n"),
932 pIfList->pInterfaces[j].szName);
933 CreateNewInterface(pIfList->pInterfaces[j].dwIpAddr,
934 pIfList->pInterfaces[j].dwIpNetMask,
935 pIfList->pInterfaces[j].szName,
936 pIfList->pInterfaces[j].dwIndex,
937 pIfList->pInterfaces[j].dwType,
938 pIfList->pInterfaces[j].bMacAddr);
939 bHasChanges = TRUE;
940 }
941 }
942
943 // Check if address we are using to communicate with node
944 // is configured on one of node's interfaces
945 for(i = 0; i < (DWORD)pIfList->iNumEntries; i++)
946 if (pIfList->pInterfaces[i].dwIpAddr == m_dwIpAddr)
947 break;
948
949 if (i == (DWORD)pIfList->iNumEntries)
950 {
951 // Node is behind NAT
952 m_dwFlags |= NF_BEHIND_NAT;
953
954 // Check if we already have NAT interface
955 Lock();
956 for(i = 0; i < m_dwChildCount; i++)
957 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
958 {
959 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
960 break;
961 }
962 Unlock();
963
964 if (i == m_dwChildCount)
965 {
966 char szBuffer[MAX_OBJECT_NAME];
967
968 // Create pseudo interface for NAT
969 ConfigReadStr("NATAdapterName", szBuffer, MAX_OBJECT_NAME, "NetXMS NAT Adapter");
970 CreateNewInterface(m_dwIpAddr, 0, szBuffer,
971 0x7FFFFFFF, IFTYPE_NETXMS_NAT_ADAPTER);
972 bHasChanges = TRUE;
973 }
974 }
975 else
976 {
977 // Check if NF_BEHIND_NAT flag set incorrectly
978 if (m_dwFlags & NF_BEHIND_NAT)
979 {
980 Interface *pIfNat;
981
982 // Remove NAT interface
983 Lock();
984 for(i = 0, pIfNat = NULL; i < m_dwChildCount; i++)
985 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
986 {
987 if (((Interface *)m_pChildList[i])->IfType() == IFTYPE_NETXMS_NAT_ADAPTER)
988 {
989 pIfNat = (Interface *)m_pChildList[i];
990 break;
991 }
992 }
993 Unlock();
994
995 if (pIfNat != NULL)
996 DeleteInterface(pIfNat);
997
998 m_dwFlags &= ~NF_BEHIND_NAT;
999 bHasChanges = TRUE;
1000 }
1001 }
1002
1003 DestroyInterfaceList(pIfList);
1004 }
1005 else
1006 {
1007 SendPollerMsg(dwRqId, _T(" Unable to get interface list from node\r\n"));
1008 }
1009
1010 m_tLastConfigurationPoll = time(NULL);
1011 SendPollerMsg(dwRqId, _T("Interface configuration check finished\r\n"
1012 "Finished configuration poll for node %s\r\n"
1013 "Node configuration was%schanged after poll\r\n"),
1014 m_szName, bHasChanges ? _T(" ") : _T(" not "));
1015
1016 // Finish configuration poll
1017 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
1018 PollerUnlock();
1019 DbgPrintf(AF_DEBUG_DISCOVERY, "Finished configuration poll for node %s (ID: %d)", m_szName, m_dwId);
1020
1021 if (bHasChanges)
1022 {
1023 Lock();
1024 Modify();
1025 Unlock();
1026 }
1027 }
1028
1029
1030 //
1031 // Connect to native agent
1032 //
1033
1034 BOOL Node::ConnectToAgent(void)
1035 {
1036 // Create new agent connection object if needed
1037 if (m_pAgentConnection == NULL)
1038 m_pAgentConnection = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
1039
1040 // Check if we already connected
1041 if (m_pAgentConnection->Nop() == ERR_SUCCESS)
1042 return TRUE;
1043
1044 // Close current connection or clean up after broken connection
1045 m_pAgentConnection->Disconnect();
1046 return m_pAgentConnection->Connect();
1047 }
1048
1049
1050 //
1051 // Get item's value via SNMP
1052 //
1053
1054 DWORD Node::GetItemFromSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1055 {
1056 DWORD dwResult;
1057
1058 dwResult = SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString, szParam, NULL, 0,
1059 szBuffer, dwBufSize, FALSE, TRUE);
1060 return (dwResult == SNMP_ERR_SUCCESS) ? DCE_SUCCESS :
1061 ((dwResult == SNMP_ERR_NO_OBJECT) ? DCE_NOT_SUPPORTED : DCE_COMM_ERROR);
1062 }
1063
1064
1065 //
1066 // Get item's value via native agent
1067 //
1068
1069 DWORD Node::GetItemFromAgent(const char *szParam, DWORD dwBufSize, char *szBuffer)
1070 {
1071 DWORD dwError, dwResult = DCE_COMM_ERROR;
1072 DWORD dwTries = 5;
1073
1074 AgentLock();
1075
1076 // Establish connection if needed
1077 if (m_pAgentConnection == NULL)
1078 if (!ConnectToAgent())
1079 goto end_loop;
1080
1081 // Get parameter from agent
1082 while(dwTries-- > 0)
1083 {
1084 dwError = m_pAgentConnection->GetParameter((char *)szParam, dwBufSize, szBuffer);
1085 switch(dwError)
1086 {
1087 case ERR_SUCCESS:
1088 dwResult = DCE_SUCCESS;
1089 goto end_loop;
1090 case ERR_UNKNOWN_PARAMETER:
1091 dwResult = DCE_NOT_SUPPORTED;
1092 goto end_loop;
1093 case ERR_NOT_CONNECTED:
1094 case ERR_CONNECTION_BROKEN:
1095 if (!ConnectToAgent())
1096 goto end_loop;
1097 break;
1098 case ERR_REQUEST_TIMEOUT:
1099 break;
1100 }
1101 }
1102
1103 end_loop:
1104 AgentUnlock();
1105 return dwResult;
1106 }
1107
1108
1109 //
1110 // Get value for server's internal parameter
1111 //
1112
1113 DWORD Node::GetInternalItem(const char *szParam, DWORD dwBufSize, char *szBuffer)
1114 {
1115 DWORD dwError = DCE_SUCCESS;
1116
1117 if (!stricmp(szParam, "status"))
1118 {
1119 sprintf(szBuffer, "%d", m_iStatus);
1120 }
1121 else if (!stricmp(szParam, "AgentStatus"))
1122 {
1123 if (m_dwFlags & NF_IS_NATIVE_AGENT)
1124 {
1125 szBuffer[0] = (m_dwDynamicFlags & NDF_AGENT_UNREACHEABLE) ? '1' : '0';
1126 szBuffer[1] = 0;
1127 }
1128 else
1129 {
1130 dwError = DCE_NOT_SUPPORTED;
1131 }
1132 }
1133 else if (MatchString("ChildStatus(*)", szParam, FALSE))
1134 {
1135 char *pEnd, szArg[256];
1136 DWORD i, dwId;
1137 NetObj *pObject = NULL;
1138
1139 NxGetParameterArg((char *)szParam, 1, szArg, 256);
1140 dwId = strtoul(szArg, &pEnd, 0);
1141 if (*pEnd != 0)
1142 {
1143 // Argument is object's name
1144 dwId = 0;
1145 }
1146
1147 // Find child object with requested ID or name
1148 Lock();
1149 for(i = 0; i < m_dwChildCount; i++)
1150 {
1151 if (((dwId == 0) && (!stricmp(m_pChildList[i]->Name(), szArg))) ||
1152 (dwId == m_pChildList[i]->Id()))
1153 {
1154 pObject = m_pChildList[i];
1155 break;
1156 }
1157 }
1158 Unlock();
1159
1160 if (pObject != NULL)
1161 {
1162 sprintf(szBuffer, "%d", pObject->Status());
1163 }
1164 else
1165 {
1166 dwError = DCE_NOT_SUPPORTED;
1167 }
1168 }
1169 else if (m_dwFlags & NF_IS_LOCAL_MGMT)
1170 {
1171 if (!stricmp(szParam, "Server.AverageDCPollerQueueSize"))
1172 {
1173 sprintf(szBuffer, "%f", g_dAvgPollerQueueSize);
1174 }
1175 else if (!stricmp(szParam, "Server.AverageDBWriterQueueSize"))
1176 {
1177 sprintf(szBuffer, "%f", g_dAvgDBWriterQueueSize);
1178 }
1179 else if (!stricmp(szParam, "Server.AverageStatusPollerQueueSize"))
1180 {
1181 sprintf(szBuffer, "%f", g_dAvgStatusPollerQueueSize);
1182 }
1183 else if (!stricmp(szParam, "Server.AverageConfigurationPollerQueueSize"))
1184 {
1185 sprintf(szBuffer, "%f", g_dAvgConfigPollerQueueSize);
1186 }
1187 else if (!stricmp(szParam, "Server.AverageDCIQueuingTime"))
1188 {
1189 sprintf(szBuffer, "%lu", g_dwAvgDCIQueuingTime);
1190 }
1191 else
1192 {
1193 dwError = DCE_NOT_SUPPORTED;
1194 }
1195 }
1196 else
1197 {
1198 dwError = DCE_NOT_SUPPORTED;
1199 }
1200
1201 return dwError;
1202 }
1203
1204
1205 //
1206 // Get item's value for client
1207 //
1208
1209 DWORD Node::GetItemForClient(int iOrigin, const char *pszParam, char *pszBuffer, DWORD dwBufSize)
1210 {
1211 DWORD dwResult = 0, dwRetCode;
1212
1213 // Get data from node
1214 switch(iOrigin)
1215 {
1216 case DS_INTERNAL:
1217 dwRetCode = GetInternalItem(pszParam, dwBufSize, pszBuffer);
1218 break;
1219 case DS_NATIVE_AGENT:
1220 dwRetCode = GetItemFromAgent(pszParam, dwBufSize, pszBuffer);
1221 break;
1222 case DS_SNMP_AGENT:
1223 dwRetCode = GetItemFromSNMP(pszParam, dwBufSize, pszBuffer);
1224 break;
1225 default:
1226 dwResult = RCC_INVALID_ARGUMENT;
1227 break;
1228 }
1229
1230 // Translate return code to RCC
1231 if (dwResult != RCC_INVALID_ARGUMENT)
1232 {
1233 switch(dwRetCode)
1234 {
1235 case DCE_SUCCESS:
1236 dwResult = RCC_SUCCESS;
1237 break;
1238 case DCE_COMM_ERROR:
1239 dwResult = RCC_COMM_FAILURE;
1240 break;
1241 case DCE_NOT_SUPPORTED:
1242 dwResult = RCC_DCI_NOT_SUPPORTED;
1243 break;
1244 default:
1245 dwResult = RCC_SYSTEM_FAILURE;
1246 break;
1247 }
1248 }
1249
1250 return dwResult;
1251 }
1252
1253
1254 //
1255 // Put items which requires polling into the queue
1256 //
1257
1258 void Node::QueueItemsForPolling(Queue *pPollerQueue)
1259 {
1260 DWORD i;
1261 time_t currTime;
1262
1263 currTime = time(NULL);
1264
1265 Lock();
1266 for(i = 0; i < m_dwNumItems; i++)
1267 {
1268 if (m_ppItems[i]->ReadyForPolling(currTime))
1269 {
1270 m_ppItems[i]->SetBusyFlag(TRUE);
1271 m_dwRefCount++; // Increment reference count for each queued DCI
1272 pPollerQueue->Put(m_ppItems[i]);
1273 }
1274 }
1275 Unlock();
1276 }
1277
1278
1279 //
1280 // Create CSCP message with object's data
1281 //
1282
1283 void Node::CreateMessage(CSCPMessage *pMsg)
1284 {
1285 Template::CreateMessage(pMsg);
1286 pMsg->SetVariable(VID_FLAGS, m_dwFlags);
1287 pMsg->SetVariable(VID_DISCOVERY_FLAGS, m_dwDiscoveryFlags);
1288 pMsg->SetVariable(VID_AGENT_PORT, m_wAgentPort);
1289 pMsg->SetVariable(VID_AUTH_METHOD, m_wAuthMethod);
1290 pMsg->SetVariable(VID_SHARED_SECRET, m_szSharedSecret);
1291 pMsg->SetVariable(VID_COMMUNITY_STRING, m_szCommunityString);
1292 pMsg->SetVariable(VID_SNMP_OID, m_szObjectId);
1293 pMsg->SetVariable(VID_NODE_TYPE, m_dwNodeType);
1294 pMsg->SetVariable(VID_SNMP_VERSION, (WORD)m_iSNMPVersion);
1295 pMsg->SetVariable(VID_AGENT_VERSION, m_szAgentVersion);
1296 pMsg->SetVariable(VID_PLATFORM_NAME, m_szPlatformName);
1297 pMsg->SetVariable(VID_POLLER_NODE_ID, m_dwPollerNode);
1298 }
1299
1300
1301 //
1302 // Modify object from message
1303 //
1304
1305 DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
1306 {
1307 if (!bAlreadyLocked)
1308 Lock();
1309
1310 // Change primary IP address
1311 if (pRequest->IsVariableExist(VID_IP_ADDRESS))
1312 {
1313 DWORD i, dwIpAddr;
1314
1315 dwIpAddr = pRequest->GetVariableLong(VID_IP_ADDRESS);
1316
1317 // Check if received IP address is one of node's interface addresses
1318 for(i = 0; i < m_dwChildCount; i++)
1319 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1320 (m_pChildList[i]->IpAddr() == dwIpAddr))
1321 break;
1322 if (i == m_dwChildCount)
1323 {
1324 Unlock();
1325 return RCC_INVALID_IP_ADDR;
1326 }
1327
1328 m_dwIpAddr = dwIpAddr;
1329 }
1330
1331 // Poller node ID
1332 if (pRequest->IsVariableExist(VID_POLLER_NODE_ID))
1333 {
1334 DWORD dwNodeId;
1335 NetObj *pObject;
1336
1337 dwNodeId = pRequest->GetVariableLong(VID_POLLER_NODE_ID);
1338 pObject = FindObjectById(dwNodeId);
1339
1340 // Check if received id is a valid node id
1341 if (pObject == NULL)
1342 {
1343 Unlock();
1344 return RCC_INVALID_OBJECT_ID;
1345 }
1346 if (pObject->Type() != OBJECT_NODE)
1347 {
1348 Unlock();
1349 return RCC_INVALID_OBJECT_ID;
1350 }
1351
1352 m_dwPollerNode = dwNodeId;
1353 }
1354
1355 // Change listen port of native agent
1356 if (pRequest->IsVariableExist(VID_AGENT_PORT))
1357 m_wAgentPort = pRequest->GetVariableShort(VID_AGENT_PORT);
1358
1359 // Change authentication method of native agent
1360 if (pRequest->IsVariableExist(VID_AUTH_METHOD))
1361 m_wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
1362
1363 // Change shared secret of native agent
1364 if (pRequest->IsVariableExist(VID_SHARED_SECRET))
1365 pRequest->GetVariableStr(VID_SHARED_SECRET, m_szSharedSecret, MAX_SECRET_LENGTH);
1366
1367 // Change SNMP protocol version
1368 if (pRequest->IsVariableExist(VID_SNMP_VERSION))
1369 m_iSNMPVersion = pRequest->GetVariableShort(VID_SNMP_VERSION);
1370
1371 // Change SNMP community string
1372 if (pRequest->IsVariableExist(VID_COMMUNITY_STRING))
1373 pRequest->GetVariableStr(VID_COMMUNITY_STRING, m_szCommunityString, MAX_COMMUNITY_LENGTH);
1374
1375 return Template::ModifyFromMessage(pRequest, TRUE);
1376 }
1377
1378
1379 //
1380 // Wakeup node using magic packet
1381 //
1382
1383 DWORD Node::WakeUp(void)
1384 {
1385 DWORD i, dwResult = RCC_NO_WOL_INTERFACES;
1386
1387 Lock();
1388
1389 for(i = 0; i < m_dwChildCount; i++)
1390 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
1391 (m_pChildList[i]->Status() != STATUS_UNMANAGED) &&
1392 (m_pChildList[i]->IpAddr() != 0))
1393 {
1394 dwResult = ((Interface *)m_pChildList[i])->WakeUp();
1395 break;
1396 }
1397
1398 Unlock();
1399 return dwResult;
1400 }
1401
1402
1403 //
1404 // Get status of interface with given index from SNMP agent
1405 //
1406
1407 int Node::GetInterfaceStatusFromSNMP(DWORD dwIndex)
1408 {
1409 return SnmpGetInterfaceStatus(m_dwIpAddr, m_iSNMPVersion, m_szCommunityString, dwIndex);
1410 }
1411
1412
1413 //
1414 // Get status of interface with given index from native agent
1415 //
1416
1417 int Node::GetInterfaceStatusFromAgent(DWORD dwIndex)
1418 {
1419 char szParam[128], szBuffer[32];
1420 DWORD dwAdminStatus, dwLinkState;
1421 int iStatus;
1422
1423 // Get administrative status
1424 sprintf(szParam, "Net.Interface.AdminStatus(%lu)", dwIndex);
1425 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
1426 {
1427 dwAdminStatus = strtoul(szBuffer, NULL, 0);
1428
1429 switch(dwAdminStatus)
1430 {
1431 case 3:
1432 iStatus = STATUS_TESTING;
1433 break;
1434 case 2:
1435 iStatus = STATUS_DISABLED;
1436 break;
1437 case 1: // Interface administratively up, check link state
1438 sprintf(szParam, "Net.Interface.Link(%lu)", dwIndex);
1439 if (GetItemFromAgent(szParam, 32, szBuffer) == DCE_SUCCESS)
1440 {
1441 dwLinkState = strtoul(szBuffer, NULL, 0);
1442 iStatus = (dwLinkState == 0) ? STATUS_CRITICAL : STATUS_NORMAL;
1443 }
1444 else
1445 {
1446 iStatus = STATUS_UNKNOWN;
1447 }
1448 break;
1449 default:
1450 iStatus = STATUS_UNKNOWN;
1451 break;
1452 }
1453 }
1454 else
1455 {
1456 iStatus = STATUS_UNKNOWN;
1457 }
1458
1459 return iStatus;
1460 }
1461
1462
1463 //
1464 // Put list of supported parameters into CSCP message
1465 //
1466
1467 void Node::WriteParamListToMessage(CSCPMessage *pMsg)
1468 {
1469 DWORD i, dwId;
1470
1471 Lock();
1472 if (m_pParamList != NULL)
1473 {
1474 pMsg->SetVariable(VID_NUM_PARAMETERS, m_dwNumParams);
1475 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < m_dwNumParams; i++)
1476 {
1477 pMsg->SetVariable(dwId++, m_pParamList[i].szName);
1478 pMsg->SetVariable(dwId++, m_pParamList[i].szDescription);
1479 pMsg->SetVariable(dwId++, (WORD)m_pParamList[i].iDataType);
1480 }
1481 }
1482 else
1483 {
1484 pMsg->SetVariable(VID_NUM_PARAMETERS, (DWORD)0);
1485 }
1486 Unlock();
1487 }
1488
1489
1490 //
1491 // Check status of network service
1492 //
1493
1494 DWORD Node::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
1495 WORD wPort, WORD wProto, TCHAR *pszRequest,
1496 TCHAR *pszResponce)
1497 {
1498 DWORD dwError = ERR_NOT_CONNECTED;
1499 DWORD dwTries = 3;
1500 AgentConnection conn(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
1501
1502 // Establish connection with agent
1503 if (conn.Connect())
1504 {
1505 dwError = conn.CheckNetworkService(pdwStatus, dwIpAddr, iServiceType,
1506 wPort, wProto, pszRequest, pszResponce);
1507 conn.Disconnect();
1508 }
1509 return dwError;
1510 }
1511
1512
1513 //
1514 // Handler for object deletion
1515 //
1516
1517 void Node::OnObjectDelete(DWORD dwObjectId)
1518 {
1519 Lock();
1520 if (dwObjectId == m_dwPollerNode)
1521 {
1522 // If deleted object is our poller node, change it to default
1523 m_dwPollerNode = 0;
1524 Modify();
1525 DbgPrintf(AF_DEBUG_MISC, _T("Node \"%s\": poller node %ld deleted"), m_szName, dwObjectId);
1526 }
1527 Unlock();
1528 }
1529
1530
1531 //
1532 // Check node for OSPF support
1533 //
1534
1535 void Node::CheckOSPFSupport(void)
1536 {
1537 long nAdminStatus;
1538
1539 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.14.1.2.0",
1540 NULL, 0, &nAdminStatus, sizeof(long), FALSE, FALSE) == SNMP_ERR_SUCCESS)
1541 {
1542 if (nAdminStatus)
1543 {
1544 m_dwFlags |= NF_IS_OSPF;
1545 }
1546 else
1547 {
1548 m_dwFlags &= ~NF_IS_OSPF;
1549 }
1550 }
1551 }
1552
1553
1554 //
1555 // Create ready to use agent connection
1556 //
1557
1558 AgentConnection *Node::CreateAgentConnection(void)
1559 {
1560 AgentConnection *pConn;
1561
1562 if (!(m_dwFlags & NF_IS_NATIVE_AGENT))
1563 return NULL;
1564
1565 pConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
1566 if (!pConn->Connect())
1567 {
1568 delete pConn;
1569 pConn = NULL;
1570 }
1571 return pConn;
1572 }
1573
1574
1575 //
1576 // Get last collected values of all DCIs
1577 //
1578
1579 DWORD Node::GetLastValues(CSCPMessage *pMsg)
1580 {
1581 DWORD i, dwId;
1582
1583 Lock();
1584
1585 pMsg->SetVariable(VID_NUM_ITEMS, m_dwNumItems);
1586 for(i = 0, dwId = VID_DCI_VALUES_BASE; i < m_dwNumItems; i++, dwId += 6)
1587 m_ppItems[i]->GetLastValue(pMsg, dwId);
1588
1589 Unlock();
1590 return RCC_SUCCESS;
1591 }
1592
1593
1594 //
1595 // Clean expired DCI data
1596 //
1597
1598 void Node::CleanDCIData(void)
1599 {
1600 DWORD i;
1601
1602 Lock();
1603 for(i = 0; i < m_dwNumItems; i++)
1604 m_ppItems[i]->CleanData();
1605 Unlock();
1606 }