Added internal parameter AgentStatus
[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;
d3fb2858 57 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
eefe7d68
VK
58}
59
60
61//
62// Constructor for new node object
63//
64
65Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwDiscoveryFlags)
b50f1100 66 :Template()
eefe7d68
VK
67{
68 m_dwIpAddr = dwAddr;
69 m_dwFlags = dwFlags;
4e839863 70 m_dwDynamicFlags = 0;
18e26ff8 71 m_dwNodeType = NODE_TYPE_GENERIC;
eefe7d68 72 m_dwDiscoveryFlags = dwDiscoveryFlags;
2da1357c
VK
73 m_wAgentPort = AGENT_LISTEN_PORT;
74 m_wAuthMethod = AUTH_NONE;
75 m_szSharedSecret[0] = 0;
76 m_iStatusPollType = POLL_ICMP_PING;
469b937c 77 m_iSNMPVersion = SNMP_VERSION_1;
2da1357c 78 strcpy(m_szCommunityString, "public");
cc140cce 79 IpToStr(dwAddr, m_szName); // Make default name from IP address
469b937c 80 m_szObjectId[0] = 0;
48b1c0ac 81 m_tLastDiscoveryPoll = 0;
f00307b7 82 m_tLastStatusPoll = 0;
364aa19a
VK
83 m_tLastConfigurationPoll = 0;
84 m_iSnmpAgentFails = 0;
85 m_iNativeAgentFails = 0;
323f8bec 86 m_hPollerMutex = MutexCreate();
3ea35b38 87 m_hAgentAccessMutex = MutexCreate();
1275c750 88 m_pAgentConnection = NULL;
ae3a55d9 89 m_szAgentVersion[0] = 0;
1c8b8363 90 m_szPlatformName[0] = 0;
89235715
VK
91 m_dwNumParams = 0;
92 m_pParamList = NULL;
1a735d7c 93 m_dwPollerNode = 0;
d3fb2858 94 memset(m_qwLastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
eefe7d68
VK
95}
96
97
98//
99// Node destructor
100//
101
102Node::~Node()
103{
323f8bec 104 MutexDestroy(m_hPollerMutex);
3ea35b38 105 MutexDestroy(m_hAgentAccessMutex);
1275c750
VK
106 if (m_pAgentConnection != NULL)
107 delete m_pAgentConnection;
89235715 108 safe_free(m_pParamList);
eefe7d68
VK
109}
110
111
2da1357c
VK
112//
113// Create object from database data
114//
115
116BOOL Node::CreateFromDB(DWORD dwId)
117{
ae3a55d9 118 char szQuery[512];
2da1357c
VK
119 DB_RESULT hResult;
120 int i, iNumRows;
121 DWORD dwSubnetId;
122 NetObj *pObject;
333ece94 123 BOOL bResult = FALSE;
2da1357c 124
a3f23550
VK
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,"
d4c266b6 128 "image_id,is_deleted,description,node_type,agent_version,"
1a735d7c 129 "platform_name,poller_node_id FROM nodes WHERE id=%d", dwId);
2da1357c
VK
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;
5eba0220
VK
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);
a3f23550
VK
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)));
18e26ff8 156 DecodeSQLString(m_pszDescription);
a3f23550
VK
157 m_dwNodeType = DBGetFieldULong(hResult, 0, 15);
158 _tcsncpy(m_szAgentVersion, CHECK_NULL_EX(DBGetField(hResult, 0, 16)), MAX_AGENT_VERSION_LEN);
ae3a55d9 159 DecodeSQLString(m_szAgentVersion);
a3f23550 160 _tcsncpy(m_szPlatformName, CHECK_NULL_EX(DBGetField(hResult, 0, 17)), MAX_PLATFORM_NAME_LEN);
d4c266b6 161 DecodeSQLString(m_szPlatformName);
a3f23550 162 m_dwPollerNode = DBGetFieldULong(hResult, 0, 18);
2da1357c
VK
163
164 DBFreeResult(hResult);
165
333ece94 166 if (!m_bIsDeleted)
2da1357c 167 {
333ece94 168 // Link node to subnets
748f71f5 169 sprintf(szQuery, "SELECT subnet_id FROM nsmap WHERE node_id=%ld", dwId);
333ece94
VK
170 hResult = DBSelect(g_hCoreDB, szQuery);
171 if (hResult == NULL)
172 return FALSE; // Query failed
2da1357c 173
748f71f5
VK
174 iNumRows = DBGetNumRows(hResult);
175 if (iNumRows == 0)
2da1357c 176 {
333ece94
VK
177 DBFreeResult(hResult);
178 return FALSE; // No parents - it shouldn't happen if database isn't corrupted
2da1357c 179 }
333ece94 180
333ece94 181 for(i = 0; i < iNumRows; i++)
2da1357c 182 {
333ece94
VK
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 }
2da1357c 201 }
2da1357c 202
333ece94
VK
203 DBFreeResult(hResult);
204 LoadItemsFromDB();
205 LoadACLFromDB();
3ea35b38 206
333ece94
VK
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 }
3ea35b38 216
cc140cce 217 return bResult;
2da1357c
VK
218}
219
220
eefe7d68
VK
221//
222// Save object to database
223//
224
225BOOL Node::SaveToDB(void)
226{
d4c266b6
VK
227 TCHAR *pszEscDescr, *pszEscVersion, *pszEscPlatform;
228 TCHAR szQuery[4096], szIpAddr[16];
eefe7d68
VK
229 DB_RESULT hResult;
230 BOOL bNewObject = TRUE;
3ea35b38 231 BOOL bResult;
eefe7d68
VK
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
18e26ff8 247 pszEscDescr = EncodeSQLString(CHECK_NULL_EX(m_pszDescription));
ae3a55d9 248 pszEscVersion = EncodeSQLString(m_szAgentVersion);
d4c266b6 249 pszEscPlatform = EncodeSQLString(m_szPlatformName);
eefe7d68 250 if (bNewObject)
d4c266b6
VK
251 snprintf(szQuery, 4096,
252 "INSERT INTO nodes (id,name,status,is_deleted,primary_ip,"
a3f23550
VK
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)",
d4c266b6 258 m_dwId, m_szName, m_iStatus, m_bIsDeleted,
a3f23550 259 IpToStr(m_dwIpAddr, szIpAddr), m_dwFlags,
d4c266b6 260 m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags, m_iStatusPollType,
a3f23550
VK
261 m_wAgentPort, m_wAuthMethod, m_szSharedSecret, m_szObjectId,
262 m_dwImageId, pszEscDescr, m_dwNodeType, pszEscVersion, pszEscPlatform,
263 m_dwPollerNode);
eefe7d68 264 else
d4c266b6
VK
265 snprintf(szQuery, 4096,
266 "UPDATE nodes SET name='%s',status=%d,is_deleted=%d,primary_ip='%s',"
a3f23550
VK
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",
d4c266b6
VK
271 m_szName, m_iStatus, m_bIsDeleted,
272 IpToStr(m_dwIpAddr, szIpAddr),
a3f23550 273 m_dwFlags, m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags,
d4c266b6 274 m_iStatusPollType, m_wAgentPort, m_wAuthMethod, m_szSharedSecret,
a3f23550
VK
275 m_szObjectId, m_dwImageId, pszEscDescr, m_dwNodeType,
276 pszEscVersion, pszEscPlatform, m_dwPollerNode, m_dwId);
3ea35b38 277 bResult = DBQuery(g_hCoreDB, szQuery);
18e26ff8 278 free(pszEscDescr);
ae3a55d9 279 free(pszEscVersion);
d4c266b6 280 free(pszEscPlatform);
3ea35b38
VK
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 }
eefe7d68 290
de78f964
VK
291 // Save access list
292 SaveACLToDB();
293
eefe7d68
VK
294 // Clear modifications flag and unlock object
295 m_bIsModified = FALSE;
296 Unlock();
297
3ea35b38 298 return bResult;
eefe7d68
VK
299}
300
301
302//
303// Delete object from database
304//
305
306BOOL Node::DeleteFromDB(void)
307{
308 char szQuery[256];
ef44d5ea 309 BOOL bSuccess;
eefe7d68 310
b50f1100 311 bSuccess = Template::DeleteFromDB();
ef44d5ea
VK
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;
eefe7d68 322}
469b937c
VK
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
1a4e3eff 331void Node::NewNodePoll(DWORD dwNetMask)
469b937c 332{
5811233f
VK
333 AgentConnection *pAgentConn;
334
be0a5a53
VK
335 PollerLock();
336
469b937c 337 // Determine node's capabilities
3d1cb7d6 338 if (SnmpGet(SNMP_VERSION_2C, m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0,
80de4676 339 m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE) == SNMP_ERR_SUCCESS)
18e26ff8
VK
340 {
341 DWORD dwNodeFlags;
342
343 m_dwNodeType = OidToType(m_szObjectId, &dwNodeFlags);
344 m_dwFlags |= NF_IS_SNMP | dwNodeFlags;
3d1cb7d6 345 m_iSNMPVersion = SNMP_VERSION_2C;
37c4d6aa
VK
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,
80de4676 350 m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE) == SNMP_ERR_SUCCESS)
37c4d6aa
VK
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 }
18e26ff8 358 }
469b937c 359
0ff9b273
VK
360 // Check OSPF capabilities
361 if (m_dwFlags & NF_IS_SNMP)
362 {
363 CheckOSPFSupport();
364 }
365
205acaf4 366 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod,
a7b85168 367 m_szSharedSecret);
5811233f 368 if (pAgentConn->Connect())
ae3a55d9 369 {
5811233f 370 m_dwFlags |= NF_IS_NATIVE_AGENT;
ae3a55d9 371 pAgentConn->GetParameter("Agent.Version", MAX_AGENT_VERSION_LEN, m_szAgentVersion);
1c8b8363 372 pAgentConn->GetParameter("System.PlatformName", MAX_PLATFORM_NAME_LEN, m_szPlatformName);
89235715
VK
373
374 pAgentConn->GetSupportedParameters(&m_dwNumParams, &m_pParamList);
ae3a55d9 375 }
5811233f 376
469b937c 377 // Get interface list
a7b85168
VK
378 if ((m_dwFlags & NF_IS_SNMP) || (m_dwFlags & NF_IS_NATIVE_AGENT) ||
379 (m_dwFlags & NF_IS_LOCAL_MGMT))
469b937c 380 {
5811233f 381 INTERFACE_LIST *pIfList = NULL;
a0495b6e
VK
382 int i;
383
ce19c304
VK
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
fd5aa295 387 {
5811233f 388 pIfList = pAgentConn->GetInterfaceList();
fd5aa295
VK
389 CleanInterfaceList(pIfList);
390 }
5811233f 391 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP)) // Use SNMP if we cannot get interfaces via agent
37c4d6aa 392 pIfList = SnmpGetInterfaceList(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString, m_dwNodeType);
5811233f
VK
393
394 if (pIfList != NULL)
a0495b6e 395 {
5811233f 396 for(i = 0; i < pIfList->iNumEntries; i++)
323f8bec
VK
397 CreateNewInterface(pIfList->pInterfaces[i].dwIpAddr,
398 pIfList->pInterfaces[i].dwIpNetMask,
399 pIfList->pInterfaces[i].szName,
400 pIfList->pInterfaces[i].dwIndex,
b50f1100
VK
401 pIfList->pInterfaces[i].dwType,
402 pIfList->pInterfaces[i].bMacAddr);
251659b6
VK
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
5811233f 423 DestroyInterfaceList(pIfList);
a0495b6e 424 }
9437ca82
VK
425 else
426 {
427 // We cannot get interface list from node for some reasons, create dummy one
323f8bec 428 CreateNewInterface(m_dwIpAddr, dwNetMask);
9437ca82 429 }
469b937c
VK
430 }
431 else // No SNMP, no native agent - create pseudo interface object
432 {
323f8bec 433 CreateNewInterface(m_dwIpAddr, dwNetMask);
469b937c
VK
434 }
435
5811233f
VK
436 // Clean up agent connection
437 if (m_dwFlags & NF_IS_NATIVE_AGENT)
438 pAgentConn->Disconnect();
439 delete pAgentConn;
440
be0a5a53 441 PollerUnlock();
469b937c 442}
ce19c304
VK
443
444
445//
c8b1f788 446// Get ARP cache from node
ce19c304
VK
447//
448
c8b1f788 449ARP_CACHE *Node::GetArpCache(void)
ce19c304
VK
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 {
3ea35b38 459 AgentLock();
1275c750
VK
460 if (ConnectToAgent())
461 pArpCache = m_pAgentConnection->GetArpCache();
3ea35b38 462 AgentUnlock();
ce19c304
VK
463 }
464 else if (m_dwFlags & NF_IS_SNMP)
465 {
37c4d6aa 466 pArpCache = SnmpGetArpCache(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString);
ce19c304
VK
467 }
468
469 return pArpCache;
470}
471
472
473//
474// Get list of interfaces from node
475//
476
477INTERFACE_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 {
1c62be36
VK
487 AgentLock();
488 if (ConnectToAgent())
ce19c304 489 {
1c62be36 490 pIfList = m_pAgentConnection->GetInterfaceList();
fd5aa295 491 CleanInterfaceList(pIfList);
ce19c304 492 }
1c62be36 493 AgentUnlock();
ce19c304
VK
494 }
495 else if (m_dwFlags & NF_IS_SNMP)
496 {
37c4d6aa 497 pIfList = SnmpGetInterfaceList(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString, m_dwNodeType);
ce19c304
VK
498 }
499
500 return pIfList;
501}
48b1c0ac
VK
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
509Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
510{
511 DWORD i;
512 Interface *pInterface;
513
c695e7e3 514 Lock();
48b1c0ac
VK
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)
205acaf4 520 {
48b1c0ac
VK
521 if ((pInterface->IpAddr() & pInterface->IpNetMask()) ==
522 (dwHostAddr & pInterface->IpNetMask()))
c695e7e3
VK
523 {
524 Unlock();
48b1c0ac 525 return pInterface;
c695e7e3 526 }
205acaf4 527 }
48b1c0ac 528 }
c695e7e3 529 Unlock();
48b1c0ac
VK
530 return NULL;
531}
f00307b7
VK
532
533
323f8bec
VK
534//
535// Create new interface
536//
537
b50f1100
VK
538void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName,
539 DWORD dwIndex, DWORD dwType, BYTE *pbMacAddr)
323f8bec
VK
540{
541 Interface *pInterface;
28fbe2be 542 Subnet *pSubnet = NULL;
323f8bec 543
c695e7e3
VK
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 {
205acaf4
VK
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
c695e7e3
VK
560 else
561 {
28fbe2be
VK
562 TCHAR szBuffer[16];
563
c695e7e3
VK
564 // Multicast address??
565 DbgPrintf(AF_DEBUG_DISCOVERY,
566 "Attempt to create interface object with multicast address %s",
28fbe2be 567 IpToStr(dwIpAddr, szBuffer));
c695e7e3
VK
568 }
569 }
570
571 // Create new subnet object
205acaf4 572 if (dwIpAddr < 0xE0000000)
28fbe2be
VK
573 {
574 pSubnet = new Subnet(dwIpAddr & dwNetMask, dwNetMask);
575 NetObjInsert(pSubnet, TRUE);
576 g_pEntireNet->AddSubnet(pSubnet);
577 }
c695e7e3
VK
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
323f8bec
VK
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);
b50f1100
VK
594 if (pbMacAddr != NULL)
595 pInterface->SetMacAddr(pbMacAddr);
323f8bec
VK
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
28fbe2be 605 if (pSubnet != NULL)
323f8bec 606 {
323f8bec 607 pSubnet->AddNode(this);
28fbe2be
VK
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());
323f8bec
VK
614 }
615}
616
617
618//
619// Delete interface from node
620//
621
622void 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());
3ea35b38 639 DeleteParent(pSubnet);
323f8bec 640 if (pSubnet != NULL)
3ea35b38 641 {
323f8bec 642 pSubnet->DeleteChild(this);
3ea35b38
VK
643 if ((pSubnet->IsEmpty()) && (g_dwFlags & AF_DELETE_EMPTY_SUBNETS))
644 {
645 PostEvent(EVENT_SUBNET_DELETED, pSubnet->Id(), NULL);
9a029be8 646 pSubnet->Delete(FALSE);
3ea35b38
VK
647 }
648 }
323f8bec
VK
649 }
650 }
9a029be8 651 pInterface->Delete(FALSE);
323f8bec
VK
652}
653
654
f00307b7
VK
655//
656// Calculate node status based on child objects status
657//
658
659void 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
d966d18a 676void Node::StatusPoll(ClientSession *pSession, DWORD dwRqId)
f00307b7 677{
41d79918
VK
678 DWORD i, dwPollListSize;
679 NetObj *pPollerNode = NULL, **ppPollList;
f00307b7 680
323f8bec 681 PollerLock();
eb8b1960 682 m_pPollRequestor = pSession;
0ba90743 683 SendPollerMsg(dwRqId, _T("Starting status poll for node %s\r\n"), m_szName);
6c60ff91 684 Lock();
1a735d7c
VK
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
41d79918
VK
709 // Create polling list
710 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_dwChildCount);
711 for(i = 0, dwPollListSize = 0; i < m_dwChildCount; i++)
6c60ff91
VK
712 if (m_pChildList[i]->Status() != STATUS_UNMANAGED)
713 {
41d79918
VK
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;
6c60ff91 732 }
41d79918
VK
733 ppPollList[i]->DecRefCount();
734 }
735 safe_free(ppPollList);
1a735d7c
VK
736
737 if (pPollerNode != NULL)
738 pPollerNode->DecRefCount();
1a735d7c 739
f00307b7
VK
740 CalculateCompoundStatus();
741 m_tLastStatusPoll = time(NULL);
d966d18a
VK
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]);
eb8b1960 744 m_pPollRequestor = NULL;
4e839863 745 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_STATUS_POLL;
323f8bec 746 PollerUnlock();
f00307b7 747}
364aa19a
VK
748
749
750//
751// Perform configuration poll on node
752//
753
0ba90743 754void Node::ConfigurationPoll(ClientSession *pSession, DWORD dwRqId)
364aa19a
VK
755{
756 DWORD dwOldFlags = m_dwFlags;
757 AgentConnection *pAgentConn;
758 INTERFACE_LIST *pIfList;
8665a594 759 char szBuffer[4096];
6159a875 760 BOOL bHasChanges = FALSE;
364aa19a 761
323f8bec 762 PollerLock();
0ba90743 763 m_pPollRequestor = pSession;
a098be0b 764 SendPollerMsg(dwRqId, _T("Starting configuration poll for node %s\r\n"), m_szName);
b1dd534d 765 DbgPrintf(AF_DEBUG_DISCOVERY, "Starting configuration poll for node %s (ID: %d)", m_szName, m_dwId);
323f8bec 766
364aa19a 767 // Check node's capabilities
0ba90743 768 SendPollerMsg(dwRqId, _T("Checking node's capabilities...\r\n"));
498ccc60 769 if (SnmpGet(m_iSNMPVersion, m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0,
d819ea0d 770 szBuffer, 4096, FALSE, FALSE) == SNMP_ERR_SUCCESS)
364aa19a 771 {
18e26ff8
VK
772 DWORD dwNodeFlags, dwNodeType;
773
8665a594
VK
774 if (strcmp(m_szObjectId, szBuffer))
775 {
776 strncpy(m_szObjectId, szBuffer, MAX_OID_LEN * 4);
777 bHasChanges = TRUE;
778 }
779
364aa19a 780 m_dwFlags |= NF_IS_SNMP;
04af194e 781 m_dwDynamicFlags &= ~NDF_SNMP_UNREACHEABLE;
364aa19a 782 m_iSnmpAgentFails = 0;
0ba90743 783 SendPollerMsg(dwRqId, _T(" SNMP agent is active\r\n"));
18e26ff8
VK
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);
8665a594 792 bHasChanges = TRUE;
18e26ff8 793 }
0ff9b273
VK
794
795 CheckOSPFSupport();
364aa19a
VK
796 }
797 else
798 {
4ea67c99
VK
799 if (m_dwFlags & NF_IS_SNMP)
800 {
801 if (m_iSnmpAgentFails == 0)
802 PostEvent(EVENT_SNMP_FAIL, m_dwId, NULL);
803 m_iSnmpAgentFails++;
04af194e 804 m_dwDynamicFlags |= NDF_SNMP_UNREACHEABLE;
4ea67c99 805 }
0ba90743 806 SendPollerMsg(dwRqId, _T(" SNMP agent is not responding\r\n"));
364aa19a
VK
807 }
808
205acaf4 809 pAgentConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
364aa19a
VK
810 if (pAgentConn->Connect())
811 {
812 m_dwFlags |= NF_IS_NATIVE_AGENT;
04af194e 813 m_dwDynamicFlags &= ~NDF_AGENT_UNREACHEABLE;
364aa19a 814 m_iNativeAgentFails = 0;
89235715
VK
815
816 Lock();
8665a594 817
d819ea0d 818 if (pAgentConn->GetParameter("Agent.Version", MAX_AGENT_VERSION_LEN, szBuffer) == ERR_SUCCESS)
8665a594 819 {
d819ea0d
VK
820 if (strcmp(m_szAgentVersion, szBuffer))
821 {
822 strcpy(m_szAgentVersion, szBuffer);
823 bHasChanges = TRUE;
8d9d77a2 824 SendPollerMsg(dwRqId, _T(" NetXMS agent version changed to %s\r\n"), m_szAgentVersion);
d819ea0d 825 }
8665a594
VK
826 }
827
d819ea0d 828 if (pAgentConn->GetParameter("System.PlatformName", MAX_PLATFORM_NAME_LEN, szBuffer) == ERR_SUCCESS)
8665a594 829 {
d819ea0d
VK
830 if (strcmp(m_szPlatformName, szBuffer))
831 {
832 strcpy(m_szPlatformName, szBuffer);
833 bHasChanges = TRUE;
8d9d77a2 834 SendPollerMsg(dwRqId, _T(" Platform name changed to %s\r\n"), m_szAgentVersion);
d819ea0d 835 }
8665a594 836 }
89235715
VK
837
838 safe_free(m_pParamList);
839 pAgentConn->GetSupportedParameters(&m_dwNumParams, &m_pParamList);
840
841 Unlock();
f91fa4c2 842 pAgentConn->Disconnect();
0ba90743 843 SendPollerMsg(dwRqId, _T(" NetXMS native agent is active\r\n"));
364aa19a
VK
844 }
845 else
846 {
4ea67c99
VK
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++;
04af194e 852 m_dwDynamicFlags |= NDF_AGENT_UNREACHEABLE;
4ea67c99 853 }
0ba90743 854 SendPollerMsg(dwRqId, _T(" NetXMS native agent is not responding\r\n"));
364aa19a 855 }
f91fa4c2 856 delete pAgentConn;
364aa19a
VK
857
858 // Generate event if node flags has been changed
859 if (dwOldFlags != m_dwFlags)
6159a875 860 {
364aa19a 861 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
6159a875
VK
862 bHasChanges = TRUE;
863 }
364aa19a
VK
864
865 // Retrieve interface list
0ba90743
VK
866 SendPollerMsg(dwRqId, _T("Capability check finished\r\n"
867 "Checking interface configuration...\r\n"));
364aa19a
VK
868 pIfList = GetInterfaceList();
869 if (pIfList != NULL)
870 {
871 DWORD i;
323f8bec 872 int j;
364aa19a
VK
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];
364aa19a 879
251659b6 880 if (pInterface->IfType() != IFTYPE_NETXMS_NAT_ADAPTER)
364aa19a 881 {
251659b6
VK
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 }
364aa19a
VK
898 }
899 }
900
b50f1100 901 // Add new interfaces and check configuration of existing
323f8bec
VK
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()))
b50f1100
VK
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);
28fbe2be 920 PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "idsss",
b50f1100
VK
921 pInterface->Id(), pInterface->IfIndex(),
922 pInterface->Name(), szOldMac, szNewMac);
923 pInterface->SetMacAddr(pIfList->pInterfaces[j].bMacAddr);
924 }
323f8bec 925 break;
b50f1100 926 }
323f8bec
VK
927 }
928 if (i == m_dwChildCount)
929 {
930 // New interface
0ba90743
VK
931 SendPollerMsg(dwRqId, _T(" Found new interface \"%s\"\r\n"),
932 pIfList->pInterfaces[j].szName);
323f8bec
VK
933 CreateNewInterface(pIfList->pInterfaces[j].dwIpAddr,
934 pIfList->pInterfaces[j].dwIpNetMask,
935 pIfList->pInterfaces[j].szName,
936 pIfList->pInterfaces[j].dwIndex,
b50f1100
VK
937 pIfList->pInterfaces[j].dwType,
938 pIfList->pInterfaces[j].bMacAddr);
6159a875 939 bHasChanges = TRUE;
323f8bec
VK
940 }
941 }
e0d3b217 942
251659b6
VK
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);
8d9d77a2
VK
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;
251659b6
VK
1000 }
1001 }
1002
e0d3b217 1003 DestroyInterfaceList(pIfList);
364aa19a 1004 }
e7b47627
VK
1005 else
1006 {
1007 SendPollerMsg(dwRqId, _T(" Unable to get interface list from node\r\n"));
1008 }
323f8bec 1009
8bff53f6 1010 m_tLastConfigurationPoll = time(NULL);
0ba90743
VK
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 "));
89235715
VK
1015
1016 // Finish configuration poll
4e839863 1017 m_dwDynamicFlags &= ~NDF_QUEUED_FOR_CONFIG_POLL;
323f8bec 1018 PollerUnlock();
b1dd534d 1019 DbgPrintf(AF_DEBUG_DISCOVERY, "Finished configuration poll for node %s (ID: %d)", m_szName, m_dwId);
6159a875
VK
1020
1021 if (bHasChanges)
1022 {
1023 Lock();
1024 Modify();
1025 Unlock();
1026 }
364aa19a 1027}
6f595ce2
VK
1028
1029
1275c750
VK
1030//
1031// Connect to native agent
1032//
1033
1034BOOL Node::ConnectToAgent(void)
1035{
1036 // Create new agent connection object if needed
1037 if (m_pAgentConnection == NULL)
205acaf4 1038 m_pAgentConnection = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
1275c750
VK
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
3ea35b38 1054DWORD Node::GetItemFromSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1275c750 1055{
80de4676
VK
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);
1275c750
VK
1062}
1063
1064
1065//
1066// Get item's value via native agent
1067//
1068
3ea35b38 1069DWORD Node::GetItemFromAgent(const char *szParam, DWORD dwBufSize, char *szBuffer)
1275c750 1070{
3ea35b38 1071 DWORD dwError, dwResult = DCE_COMM_ERROR;
1275c750
VK
1072 DWORD dwTries = 5;
1073
3ea35b38
VK
1074 AgentLock();
1075
1275c750
VK
1076 // Establish connection if needed
1077 if (m_pAgentConnection == NULL)
1078 if (!ConnectToAgent())
3ea35b38 1079 goto end_loop;
1275c750
VK
1080
1081 // Get parameter from agent
1082 while(dwTries-- > 0)
1083 {
901c96c7 1084 dwError = m_pAgentConnection->GetParameter((char *)szParam, dwBufSize, szBuffer);
1275c750
VK
1085 switch(dwError)
1086 {
1087 case ERR_SUCCESS:
3ea35b38
VK
1088 dwResult = DCE_SUCCESS;
1089 goto end_loop;
1275c750 1090 case ERR_UNKNOWN_PARAMETER:
3ea35b38
VK
1091 dwResult = DCE_NOT_SUPPORTED;
1092 goto end_loop;
1275c750
VK
1093 case ERR_NOT_CONNECTED:
1094 case ERR_CONNECTION_BROKEN:
1095 if (!ConnectToAgent())
3ea35b38 1096 goto end_loop;
1275c750
VK
1097 break;
1098 case ERR_REQUEST_TIMEOUT:
1099 break;
1100 }
1101 }
3ea35b38
VK
1102
1103end_loop:
1104 AgentUnlock();
1105 return dwResult;
1275c750 1106}
8e99117a
VK
1107
1108
1109//
1110// Get value for server's internal parameter
1111//
1112
3ea35b38 1113DWORD Node::GetInternalItem(const char *szParam, DWORD dwBufSize, char *szBuffer)
8e99117a
VK
1114{
1115 DWORD dwError = DCE_SUCCESS;
1116
1117 if (!stricmp(szParam, "status"))
1118 {
1119 sprintf(szBuffer, "%d", m_iStatus);
1120 }
04af194e
VK
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 }
282edbb5
VK
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 }
0fd7132e
VK
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 }
4e839863
VK
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 }
0fd7132e
VK
1191 else
1192 {
1193 dwError = DCE_NOT_SUPPORTED;
1194 }
1195 }
8e99117a
VK
1196 else
1197 {
1198 dwError = DCE_NOT_SUPPORTED;
1199 }
1200
1201 return dwError;
1202}
129f8f7b
VK
1203
1204
80de4676
VK
1205//
1206// Get item's value for client
1207//
1208
1209DWORD 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
129f8f7b
VK
1254//
1255// Put items which requires polling into the queue
1256//
1257
1258void 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 {
3ea35b38 1268 if (m_ppItems[i]->ReadyForPolling(currTime))
129f8f7b 1269 {
3ea35b38 1270 m_ppItems[i]->SetBusyFlag(TRUE);
4e839863 1271 m_dwRefCount++; // Increment reference count for each queued DCI
5add75d8 1272 pPollerQueue->Put(m_ppItems[i]);
067f2689
VK
1273 }
1274 }
1275 Unlock();
1276}
1277
1278
b81249b7
VK
1279//
1280// Create CSCP message with object's data
1281//
1282
1283void Node::CreateMessage(CSCPMessage *pMsg)
1284{
70573ffe 1285 Template::CreateMessage(pMsg);
a5f8dbb8
VK
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);
18e26ff8 1293 pMsg->SetVariable(VID_NODE_TYPE, m_dwNodeType);
37c4d6aa 1294 pMsg->SetVariable(VID_SNMP_VERSION, (WORD)m_iSNMPVersion);
ae3a55d9 1295 pMsg->SetVariable(VID_AGENT_VERSION, m_szAgentVersion);
1c8b8363 1296 pMsg->SetVariable(VID_PLATFORM_NAME, m_szPlatformName);
1a735d7c 1297 pMsg->SetVariable(VID_POLLER_NODE_ID, m_dwPollerNode);
b81249b7 1298}
24156e90
VK
1299
1300
1301//
1302// Modify object from message
1303//
1304
1305DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
1306{
1307 if (!bAlreadyLocked)
1308 Lock();
1309
6c60ff91
VK
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
1a735d7c
VK
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
24156e90
VK
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
37c4d6aa
VK
1367 // Change SNMP protocol version
1368 if (pRequest->IsVariableExist(VID_SNMP_VERSION))
1369 m_iSNMPVersion = pRequest->GetVariableShort(VID_SNMP_VERSION);
1370
24156e90
VK
1371 // Change SNMP community string
1372 if (pRequest->IsVariableExist(VID_COMMUNITY_STRING))
1373 pRequest->GetVariableStr(VID_COMMUNITY_STRING, m_szCommunityString, MAX_COMMUNITY_LENGTH);
1374
70573ffe 1375 return Template::ModifyFromMessage(pRequest, TRUE);
24156e90 1376}
ed1140dc
VK
1377
1378
1379//
1380// Wakeup node using magic packet
1381//
1382
1383DWORD 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}
80de4676
VK
1401
1402
1403//
1404// Get status of interface with given index from SNMP agent
1405//
1406
1407int 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
1417int 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 }
251659b6 1448 break;
80de4676
VK
1449 default:
1450 iStatus = STATUS_UNKNOWN;
1451 break;
1452 }
1453 }
1454 else
1455 {
1456 iStatus = STATUS_UNKNOWN;
1457 }
1458
1459 return iStatus;
1460}
89235715
VK
1461
1462
1463//
1464// Put list of supported parameters into CSCP message
1465//
1466
1467void 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}
1a735d7c
VK
1488
1489
1490//
1491// Check status of network service
1492//
1493
1494DWORD Node::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
1495 WORD wPort, WORD wProto, TCHAR *pszRequest,
1496 TCHAR *pszResponce)
1497{
5eba0220 1498 DWORD dwError = ERR_NOT_CONNECTED;
1a735d7c 1499 DWORD dwTries = 3;
5eba0220 1500 AgentConnection conn(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
1a735d7c 1501
5eba0220
VK
1502 // Establish connection with agent
1503 if (conn.Connect())
1a735d7c 1504 {
5eba0220
VK
1505 dwError = conn.CheckNetworkService(pdwStatus, dwIpAddr, iServiceType,
1506 wPort, wProto, pszRequest, pszResponce);
1507 conn.Disconnect();
1a735d7c 1508 }
1a735d7c
VK
1509 return dwError;
1510}
9a029be8
VK
1511
1512
1513//
1514// Handler for object deletion
1515//
1516
1517void 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}
0ff9b273
VK
1529
1530
1531//
1532// Check node for OSPF support
1533//
1534
1535void 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}
28531273
VK
1552
1553
1554//
1555// Create ready to use agent connection
1556//
1557
1558AgentConnection *Node::CreateAgentConnection(void)
1559{
1560 AgentConnection *pConn;
1561
094b9fa8 1562 if (!(m_dwFlags & NF_IS_NATIVE_AGENT))
28531273
VK
1563 return NULL;
1564
094b9fa8 1565 pConn = new AgentConnection(htonl(m_dwIpAddr), m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
28531273
VK
1566 if (!pConn->Connect())
1567 {
1568 delete pConn;
1569 pConn = NULL;
1570 }
1571 return pConn;
1572}
20aaa307
VK
1573
1574
1575//
1576// Get last collected values of all DCIs
1577//
1578
1579DWORD 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}
5bece02a
VK
1592
1593
1594//
1595// Clean expired DCI data
1596//
1597
1598void 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}