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