- Initial DCI transformation support on server side
[public/netxms.git] / src / server / core / node.cpp
CommitLineData
eefe7d68 1/*
1275c750 2** NetXMS - Network Management System
eefe7d68
VK
3** Copyright (C) 2003 Victor Kirhenshtein
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** $module: node.cpp
20**
21**/
22
23#include "nms_core.h"
24
25
26//
27// Node class default constructor
28//
29
30Node::Node()
31 :NetObj()
32{
33 m_dwFlags = 0;
34 m_dwDiscoveryFlags = 0;
2da1357c
VK
35 m_wAgentPort = AGENT_LISTEN_PORT;
36 m_wAuthMethod = AUTH_NONE;
37 m_szSharedSecret[0] = 0;
38 m_iStatusPollType = POLL_ICMP_PING;
469b937c 39 m_iSNMPVersion = SNMP_VERSION_1;
2da1357c 40 strcpy(m_szCommunityString, "public");
469b937c 41 m_szObjectId[0] = 0;
48b1c0ac 42 m_tLastDiscoveryPoll = 0;
f00307b7 43 m_tLastStatusPoll = 0;
364aa19a
VK
44 m_tLastConfigurationPoll = 0;
45 m_iSnmpAgentFails = 0;
46 m_iNativeAgentFails = 0;
323f8bec 47 m_hPollerMutex = MutexCreate();
3ea35b38 48 m_hAgentAccessMutex = MutexCreate();
6f595ce2 49 m_dwNumItems = 0;
3ea35b38 50 m_ppItems = NULL;
1275c750 51 m_pAgentConnection = NULL;
3c55b85d 52 m_dwDCILockStatus = INVALID_INDEX;
eefe7d68
VK
53}
54
55
56//
57// Constructor for new node object
58//
59
60Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwDiscoveryFlags)
61 :NetObj()
62{
63 m_dwIpAddr = dwAddr;
64 m_dwFlags = dwFlags;
65 m_dwDiscoveryFlags = dwDiscoveryFlags;
2da1357c
VK
66 m_wAgentPort = AGENT_LISTEN_PORT;
67 m_wAuthMethod = AUTH_NONE;
68 m_szSharedSecret[0] = 0;
69 m_iStatusPollType = POLL_ICMP_PING;
469b937c 70 m_iSNMPVersion = SNMP_VERSION_1;
2da1357c 71 strcpy(m_szCommunityString, "public");
cc140cce 72 IpToStr(dwAddr, m_szName); // Make default name from IP address
469b937c 73 m_szObjectId[0] = 0;
48b1c0ac 74 m_tLastDiscoveryPoll = 0;
f00307b7 75 m_tLastStatusPoll = 0;
364aa19a
VK
76 m_tLastConfigurationPoll = 0;
77 m_iSnmpAgentFails = 0;
78 m_iNativeAgentFails = 0;
323f8bec 79 m_hPollerMutex = MutexCreate();
3ea35b38 80 m_hAgentAccessMutex = MutexCreate();
6f595ce2 81 m_dwNumItems = 0;
3ea35b38 82 m_ppItems = NULL;
1275c750 83 m_pAgentConnection = NULL;
3c55b85d 84 m_dwDCILockStatus = INVALID_INDEX;
eefe7d68
VK
85}
86
87
88//
89// Node destructor
90//
91
92Node::~Node()
93{
323f8bec 94 MutexDestroy(m_hPollerMutex);
3ea35b38
VK
95 MutexDestroy(m_hAgentAccessMutex);
96 DestroyItems();
1275c750
VK
97 if (m_pAgentConnection != NULL)
98 delete m_pAgentConnection;
eefe7d68
VK
99}
100
101
3ea35b38
VK
102//
103// Destroy all related data collection items
104//
105
106void Node::DestroyItems(void)
107{
108 DWORD i;
109
110 for(i = 0; i < m_dwNumItems; i++)
111 delete m_ppItems[i];
112 safe_free(m_ppItems);
113 m_dwNumItems = 0;
114 m_ppItems = NULL;
115}
116
117
2da1357c
VK
118//
119// Create object from database data
120//
121
122BOOL Node::CreateFromDB(DWORD dwId)
123{
124 char szQuery[256];
125 DB_RESULT hResult;
126 int i, iNumRows;
127 DWORD dwSubnetId;
128 NetObj *pObject;
333ece94 129 BOOL bResult = FALSE;
2da1357c
VK
130
131 sprintf(szQuery, "SELECT id,name,status,primary_ip,is_snmp,is_agent,is_bridge,"
132 "is_router,snmp_version,discovery_flags,auth_method,secret,"
2a41a4b5 133 "agent_port,status_poll_type,community,snmp_oid,is_local_mgmt,"
333ece94 134 "image_id,is_deleted FROM nodes WHERE id=%d", dwId);
2da1357c
VK
135 hResult = DBSelect(g_hCoreDB, szQuery);
136 if (hResult == 0)
137 return FALSE; // Query failed
138
139 if (DBGetNumRows(hResult) == 0)
140 {
141 DBFreeResult(hResult);
142 return FALSE;
143 }
144
145 m_dwId = dwId;
146 strncpy(m_szName, DBGetField(hResult, 0, 1), MAX_OBJECT_NAME);
147 m_iStatus = DBGetFieldLong(hResult, 0, 2);
148 m_dwIpAddr = DBGetFieldULong(hResult, 0, 3);
149
150 // Flags
151 if (DBGetFieldLong(hResult, 0, 4))
152 m_dwFlags |= NF_IS_SNMP;
153 if (DBGetFieldLong(hResult, 0, 5))
154 m_dwFlags |= NF_IS_NATIVE_AGENT;
155 if (DBGetFieldLong(hResult, 0, 6))
156 m_dwFlags |= NF_IS_BRIDGE;
157 if (DBGetFieldLong(hResult, 0, 7))
158 m_dwFlags |= NF_IS_ROUTER;
ce19c304
VK
159 if (DBGetFieldLong(hResult, 0, 16))
160 m_dwFlags |= NF_IS_LOCAL_MGMT;
2da1357c
VK
161
162 m_iSNMPVersion = DBGetFieldLong(hResult, 0, 8);
163 m_dwDiscoveryFlags = DBGetFieldULong(hResult, 0, 9);
164 m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 10);
165 strncpy(m_szSharedSecret, DBGetField(hResult, 0, 11), MAX_SECRET_LENGTH);
166 m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 12);
167 m_iStatusPollType = DBGetFieldLong(hResult, 0, 13);
168 strncpy(m_szCommunityString, DBGetField(hResult, 0, 14), MAX_COMMUNITY_LENGTH);
a0495b6e 169 strncpy(m_szObjectId, DBGetField(hResult, 0, 15), MAX_OID_LEN * 4);
cb151d1e 170 m_dwImageId = DBGetFieldULong(hResult, 0, 17);
333ece94 171 m_bIsDeleted = DBGetFieldLong(hResult, 0, 18);
2da1357c
VK
172
173 DBFreeResult(hResult);
174
333ece94 175 if (!m_bIsDeleted)
2da1357c 176 {
333ece94
VK
177 // Link node to subnets
178 sprintf(szQuery, "SELECT subnet_id FROM nsmap WHERE node_id=%d", dwId);
179 hResult = DBSelect(g_hCoreDB, szQuery);
180 if (hResult == NULL)
181 return FALSE; // Query failed
2da1357c 182
333ece94 183 if (DBGetNumRows(hResult) == 0)
2da1357c 184 {
333ece94
VK
185 DBFreeResult(hResult);
186 return FALSE; // No parents - it shouldn't happen if database isn't corrupted
2da1357c 187 }
333ece94
VK
188
189 iNumRows = DBGetNumRows(hResult);
190 for(i = 0; i < iNumRows; i++)
2da1357c 191 {
333ece94
VK
192 dwSubnetId = DBGetFieldULong(hResult, i, 0);
193 pObject = FindObjectById(dwSubnetId);
194 if (pObject == NULL)
195 {
196 WriteLog(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
197 break;
198 }
199 else if (pObject->Type() != OBJECT_SUBNET)
200 {
201 WriteLog(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
202 break;
203 }
204 else
205 {
206 pObject->AddChild(this);
207 AddParent(pObject);
208 bResult = TRUE;
209 }
2da1357c 210 }
2da1357c 211
333ece94
VK
212 DBFreeResult(hResult);
213 LoadItemsFromDB();
214 LoadACLFromDB();
3ea35b38 215
333ece94
VK
216 // Walk through all items in the node and load appropriate thresholds
217 for(i = 0; i < (int)m_dwNumItems; i++)
218 if (!m_ppItems[i]->LoadThresholdsFromDB())
219 bResult = FALSE;
220 }
221 else
222 {
223 bResult = TRUE;
224 }
3ea35b38 225
cc140cce 226 return bResult;
2da1357c
VK
227}
228
229
3ea35b38
VK
230//
231// Load data collection items from database
232//
233
234void Node::LoadItemsFromDB(void)
235{
236 char szQuery[256];
237 DB_RESULT hResult;
238
239 sprintf(szQuery, "SELECT item_id,name,source,datatype,polling_interval,retention_time,"
333ece94
VK
240 "status,delta_calculation,transformation,template_id "
241 "FROM items WHERE node_id=%d", m_dwId);
3ea35b38
VK
242 hResult = DBSelect(g_hCoreDB, szQuery);
243
244 if (hResult != 0)
245 {
246 int i, iRows;
247
248 iRows = DBGetNumRows(hResult);
249 if (iRows > 0)
250 {
251 m_dwNumItems = iRows;
252 m_ppItems = (DCItem **)malloc(sizeof(DCItem *) * iRows);
253 for(i = 0; i < iRows; i++)
254 m_ppItems[i] = new DCItem(hResult, i, this);
255 }
256 DBFreeResult(hResult);
257 }
258}
259
260
eefe7d68
VK
261//
262// Save object to database
263//
264
265BOOL Node::SaveToDB(void)
266{
a0495b6e 267 char szQuery[4096];
eefe7d68
VK
268 DB_RESULT hResult;
269 BOOL bNewObject = TRUE;
3ea35b38 270 BOOL bResult;
eefe7d68
VK
271
272 // Lock object's access
273 Lock();
274
275 // Check for object's existence in database
276 sprintf(szQuery, "SELECT id FROM nodes WHERE id=%ld", m_dwId);
277 hResult = DBSelect(g_hCoreDB, szQuery);
278 if (hResult != 0)
279 {
280 if (DBGetNumRows(hResult) > 0)
281 bNewObject = FALSE;
282 DBFreeResult(hResult);
283 }
284
285 // Form and execute INSERT or UPDATE query
286 if (bNewObject)
2da1357c
VK
287 sprintf(szQuery, "INSERT INTO nodes (id,name,status,is_deleted,primary_ip,"
288 "is_snmp,is_agent,is_bridge,is_router,snmp_version,community,"
a0495b6e 289 "discovery_flags,status_poll_type,agent_port,auth_method,secret,"
2a41a4b5
VK
290 "snmp_oid,is_local_mgmt,image_id)"
291 " VALUES (%d,'%s',%d,%d,%d,%d,%d,%d,%d,%d,'%s',%d,%d,%d,%d,'%s','%s',%d,%ld)",
eefe7d68
VK
292 m_dwId, m_szName, m_iStatus, m_bIsDeleted, m_dwIpAddr,
293 m_dwFlags & NF_IS_SNMP ? 1 : 0,
294 m_dwFlags & NF_IS_NATIVE_AGENT ? 1 : 0,
295 m_dwFlags & NF_IS_BRIDGE ? 1 : 0,
296 m_dwFlags & NF_IS_ROUTER ? 1 : 0,
2da1357c 297 m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags, m_iStatusPollType,
ce19c304 298 m_wAgentPort,m_wAuthMethod,m_szSharedSecret, m_szObjectId,
2a41a4b5 299 m_dwFlags & NF_IS_LOCAL_MGMT ? 1 : 0, m_dwImageId);
eefe7d68
VK
300 else
301 sprintf(szQuery, "UPDATE nodes SET name='%s',status=%d,is_deleted=%d,primary_ip=%d,"
302 "is_snmp=%d,is_agent=%d,is_bridge=%d,is_router=%d,snmp_version=%d,"
2da1357c 303 "community='%s',discovery_flags=%d,status_poll_type=%d,agent_port=%d,"
2a41a4b5
VK
304 "auth_method=%d,secret='%s',snmp_oid='%s',is_local_mgmt=%d,image_id=%ld"
305 " WHERE id=%ld",
eefe7d68
VK
306 m_szName, m_iStatus, m_bIsDeleted, m_dwIpAddr,
307 m_dwFlags & NF_IS_SNMP ? 1 : 0,
308 m_dwFlags & NF_IS_NATIVE_AGENT ? 1 : 0,
309 m_dwFlags & NF_IS_BRIDGE ? 1 : 0,
310 m_dwFlags & NF_IS_ROUTER ? 1 : 0,
2da1357c 311 m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags,
a0495b6e 312 m_iStatusPollType, m_wAgentPort, m_wAuthMethod, m_szSharedSecret,
2a41a4b5 313 m_szObjectId, m_dwFlags & NF_IS_LOCAL_MGMT ? 1 : 0, m_dwImageId, m_dwId);
3ea35b38
VK
314 bResult = DBQuery(g_hCoreDB, szQuery);
315
316 // Save data collection items
317 if (bResult)
318 {
319 DWORD i;
320
321 for(i = 0; i < m_dwNumItems; i++)
322 m_ppItems[i]->SaveToDB();
323 }
eefe7d68 324
de78f964
VK
325 // Save access list
326 SaveACLToDB();
327
eefe7d68
VK
328 // Clear modifications flag and unlock object
329 m_bIsModified = FALSE;
330 Unlock();
331
3ea35b38 332 return bResult;
eefe7d68
VK
333}
334
335
336//
337// Delete object from database
338//
339
340BOOL Node::DeleteFromDB(void)
341{
342 char szQuery[256];
ef44d5ea 343 BOOL bSuccess;
eefe7d68 344
ef44d5ea
VK
345 bSuccess = NetObj::DeleteFromDB();
346 if (bSuccess)
347 {
348 sprintf(szQuery, "DELETE FROM nodes WHERE id=%ld", m_dwId);
349 QueueSQLRequest(szQuery);
350 sprintf(szQuery, "DELETE FROM nsmap WHERE node_id=%ld", m_dwId);
351 QueueSQLRequest(szQuery);
352 sprintf(szQuery, "DROP TABLE idata_%ld", m_dwId);
353 QueueSQLRequest(szQuery);
354 }
355 return bSuccess;
eefe7d68 356}
469b937c
VK
357
358
359//
360// Poll newly discovered node
361// Usually called once by node poller thread when new node is discovered
362// and object for it is created
363//
364
365BOOL Node::NewNodePoll(DWORD dwNetMask)
366{
5811233f
VK
367 AgentConnection *pAgentConn;
368
be0a5a53
VK
369 PollerLock();
370
469b937c 371 // Determine node's capabilities
a7b85168 372 if (SnmpGet(m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0,
f92869c9 373 m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE))
469b937c
VK
374 m_dwFlags |= NF_IS_SNMP;
375
a7b85168
VK
376 pAgentConn = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod,
377 m_szSharedSecret);
5811233f
VK
378 if (pAgentConn->Connect())
379 m_dwFlags |= NF_IS_NATIVE_AGENT;
380
469b937c 381 // Get interface list
a7b85168
VK
382 if ((m_dwFlags & NF_IS_SNMP) || (m_dwFlags & NF_IS_NATIVE_AGENT) ||
383 (m_dwFlags & NF_IS_LOCAL_MGMT))
469b937c 384 {
5811233f 385 INTERFACE_LIST *pIfList = NULL;
a0495b6e
VK
386 int i;
387
ce19c304
VK
388 if (m_dwFlags & NF_IS_LOCAL_MGMT) // For local machine
389 pIfList = GetLocalInterfaceList();
390 else if (m_dwFlags & NF_IS_NATIVE_AGENT) // For others prefer native agent
5811233f
VK
391 pIfList = pAgentConn->GetInterfaceList();
392 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP)) // Use SNMP if we cannot get interfaces via agent
393 pIfList = SnmpGetInterfaceList(m_dwIpAddr, m_szCommunityString);
394
395 if (pIfList != NULL)
a0495b6e 396 {
5811233f 397 for(i = 0; i < pIfList->iNumEntries; i++)
323f8bec
VK
398 CreateNewInterface(pIfList->pInterfaces[i].dwIpAddr,
399 pIfList->pInterfaces[i].dwIpNetMask,
400 pIfList->pInterfaces[i].szName,
401 pIfList->pInterfaces[i].dwIndex,
402 pIfList->pInterfaces[i].dwType);
5811233f 403 DestroyInterfaceList(pIfList);
a0495b6e 404 }
9437ca82
VK
405 else
406 {
407 // We cannot get interface list from node for some reasons, create dummy one
323f8bec 408 CreateNewInterface(m_dwIpAddr, dwNetMask);
9437ca82 409 }
469b937c
VK
410 }
411 else // No SNMP, no native agent - create pseudo interface object
412 {
323f8bec 413 CreateNewInterface(m_dwIpAddr, dwNetMask);
469b937c
VK
414 }
415
5811233f
VK
416 // Clean up agent connection
417 if (m_dwFlags & NF_IS_NATIVE_AGENT)
418 pAgentConn->Disconnect();
419 delete pAgentConn;
420
be0a5a53
VK
421 PollerUnlock();
422
469b937c
VK
423 return TRUE;
424}
ce19c304
VK
425
426
427//
c8b1f788 428// Get ARP cache from node
ce19c304
VK
429//
430
c8b1f788 431ARP_CACHE *Node::GetArpCache(void)
ce19c304
VK
432{
433 ARP_CACHE *pArpCache = NULL;
434
435 if (m_dwFlags & NF_IS_LOCAL_MGMT)
436 {
437 pArpCache = GetLocalArpCache();
438 }
439 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
440 {
3ea35b38 441 AgentLock();
1275c750
VK
442 if (ConnectToAgent())
443 pArpCache = m_pAgentConnection->GetArpCache();
3ea35b38 444 AgentUnlock();
ce19c304
VK
445 }
446 else if (m_dwFlags & NF_IS_SNMP)
447 {
448 pArpCache = SnmpGetArpCache(m_dwIpAddr, m_szCommunityString);
449 }
450
451 return pArpCache;
452}
453
454
455//
456// Get list of interfaces from node
457//
458
459INTERFACE_LIST *Node::GetInterfaceList(void)
460{
461 INTERFACE_LIST *pIfList = NULL;
462
463 if (m_dwFlags & NF_IS_LOCAL_MGMT)
464 {
465 pIfList = GetLocalInterfaceList();
466 }
467 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
468 {
1c62be36
VK
469 AgentLock();
470 if (ConnectToAgent())
ce19c304 471 {
1c62be36
VK
472 CleanInterfaceList(pIfList);
473 pIfList = m_pAgentConnection->GetInterfaceList();
ce19c304 474 }
1c62be36 475 AgentUnlock();
ce19c304
VK
476 }
477 else if (m_dwFlags & NF_IS_SNMP)
478 {
479 pIfList = SnmpGetInterfaceList(m_dwIpAddr, m_szCommunityString);
480 }
481
482 return pIfList;
483}
48b1c0ac
VK
484
485
486//
487// Find interface by index and node IP
488// Returns pointer to interface object or NULL if appropriate interface couldn't be found
489//
490
491Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
492{
493 DWORD i;
494 Interface *pInterface;
495
496 for(i = 0; i < m_dwChildCount; i++)
497 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
498 {
499 pInterface = (Interface *)m_pChildList[i];
500 if (pInterface->IfIndex() == dwIndex)
501 if ((pInterface->IpAddr() & pInterface->IpNetMask()) ==
502 (dwHostAddr & pInterface->IpNetMask()))
503 return pInterface;
504 }
505 return NULL;
506}
f00307b7
VK
507
508
323f8bec
VK
509//
510// Create new interface
511//
512
513void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName, DWORD dwIndex, DWORD dwType)
514{
515 Interface *pInterface;
516 Subnet *pSubnet;
517
518 // Create interface object
519 if (szName != NULL)
520 pInterface = new Interface(szName, dwIndex, dwIpAddr, dwNetMask, dwType);
521 else
522 pInterface = new Interface(dwIpAddr, dwNetMask);
523
524 // Insert to objects' list and generate event
525 NetObjInsert(pInterface, TRUE);
526 AddInterface(pInterface);
527 PostEvent(EVENT_INTERFACE_ADDED, m_dwId, "dsaad", pInterface->Id(),
528 pInterface->Name(), pInterface->IpAddr(),
529 pInterface->IpNetMask(), pInterface->IfIndex());
530
531 // Bind node to appropriate subnet
532 if (pInterface->IpAddr() != 0) // Do not link non-IP interfaces to 0.0.0.0 subnet
533 {
534 pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
535 if (pSubnet == NULL)
536 {
537 // Create new subnet object
538 pSubnet = new Subnet(pInterface->IpAddr() & pInterface->IpNetMask(), pInterface->IpNetMask());
539 NetObjInsert(pSubnet, TRUE);
540 g_pEntireNet->AddSubnet(pSubnet);
541 }
542 pSubnet->AddNode(this);
543 }
544}
545
546
547//
548// Delete interface from node
549//
550
551void Node::DeleteInterface(Interface *pInterface)
552{
553 DWORD i;
554
555 // Check if we should unlink node from interface's subnet
556 if (pInterface->IpAddr() != 0)
557 {
558 for(i = 0; i < m_dwChildCount; i++)
559 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
560 if (m_pChildList[i] != pInterface)
561 if ((((Interface *)m_pChildList[i])->IpAddr() & ((Interface *)m_pChildList[i])->IpNetMask()) ==
562 (pInterface->IpAddr() & pInterface->IpNetMask()))
563 break;
564 if (i == m_dwChildCount)
565 {
566 // Last interface in subnet, should unlink node
567 Subnet *pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
3ea35b38 568 DeleteParent(pSubnet);
323f8bec 569 if (pSubnet != NULL)
3ea35b38 570 {
323f8bec 571 pSubnet->DeleteChild(this);
3ea35b38
VK
572 if ((pSubnet->IsEmpty()) && (g_dwFlags & AF_DELETE_EMPTY_SUBNETS))
573 {
574 PostEvent(EVENT_SUBNET_DELETED, pSubnet->Id(), NULL);
575 pSubnet->Delete();
576 }
577 }
323f8bec
VK
578 }
579 }
580 pInterface->Delete();
581}
582
583
f00307b7
VK
584//
585// Calculate node status based on child objects status
586//
587
588void Node::CalculateCompoundStatus(void)
589{
590 int iOldStatus = m_iStatus;
591 static DWORD dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_MINOR,
592 EVENT_NODE_WARNING, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
593 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
594
595 NetObj::CalculateCompoundStatus();
596 if (m_iStatus != iOldStatus)
597 PostEvent(dwEventCodes[m_iStatus], m_dwId, "d", iOldStatus);
598}
599
600
601//
602// Perform status poll on node
603//
604
605void Node::StatusPoll(void)
606{
607 DWORD i;
608
323f8bec 609 PollerLock();
f00307b7 610 for(i = 0; i < m_dwChildCount; i++)
c1c39152
VK
611 if ((m_pChildList[i]->Type() == OBJECT_INTERFACE) &&
612 (m_pChildList[i]->Status() != STATUS_UNMANAGED))
f00307b7
VK
613 ((Interface *)m_pChildList[i])->StatusPoll();
614 CalculateCompoundStatus();
615 m_tLastStatusPoll = time(NULL);
323f8bec 616 PollerUnlock();
f00307b7 617}
364aa19a
VK
618
619
620//
621// Perform configuration poll on node
622//
623
624void Node::ConfigurationPoll(void)
625{
626 DWORD dwOldFlags = m_dwFlags;
627 AgentConnection *pAgentConn;
628 INTERFACE_LIST *pIfList;
6159a875 629 BOOL bHasChanges = FALSE;
364aa19a 630
323f8bec 631 PollerLock();
8bff53f6 632 DbgPrintf(AF_DEBUG_DISCOVERY, "Starting configuration poll for node %s (ID: %d)\n", m_szName, m_dwId);
323f8bec 633
364aa19a 634 // Check node's capabilities
a7b85168 635 if (SnmpGet(m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0,
f92869c9 636 m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE))
364aa19a
VK
637 {
638 m_dwFlags |= NF_IS_SNMP;
639 m_iSnmpAgentFails = 0;
640 }
641 else
642 {
4ea67c99
VK
643 if (m_dwFlags & NF_IS_SNMP)
644 {
645 if (m_iSnmpAgentFails == 0)
646 PostEvent(EVENT_SNMP_FAIL, m_dwId, NULL);
647 m_iSnmpAgentFails++;
648 }
364aa19a
VK
649 }
650
651 pAgentConn = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
652 if (pAgentConn->Connect())
653 {
654 m_dwFlags |= NF_IS_NATIVE_AGENT;
655 m_iNativeAgentFails = 0;
f91fa4c2 656 pAgentConn->Disconnect();
364aa19a
VK
657 }
658 else
659 {
4ea67c99
VK
660 if (m_dwFlags & NF_IS_NATIVE_AGENT)
661 {
662 if (m_iNativeAgentFails == 0)
663 PostEvent(EVENT_AGENT_FAIL, m_dwId, NULL);
664 m_iNativeAgentFails++;
665 }
364aa19a 666 }
f91fa4c2 667 delete pAgentConn;
364aa19a
VK
668
669 // Generate event if node flags has been changed
670 if (dwOldFlags != m_dwFlags)
6159a875 671 {
364aa19a 672 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
6159a875
VK
673 bHasChanges = TRUE;
674 }
364aa19a
VK
675
676 // Retrieve interface list
677 pIfList = GetInterfaceList();
678 if (pIfList != NULL)
679 {
680 DWORD i;
323f8bec 681 int j;
364aa19a
VK
682
683 // Find non-existing interfaces
684 for(i = 0; i < m_dwChildCount; i++)
685 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
686 {
687 Interface *pInterface = (Interface *)m_pChildList[i];
364aa19a
VK
688
689 for(j = 0; j < pIfList->iNumEntries; j++)
690 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
691 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
692 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
693 break;
694 if (j == pIfList->iNumEntries)
695 {
696 // No such interface in current configuration, delete it
697 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", pInterface->IfIndex(),
698 pInterface->Name(), pInterface->IpAddr(), pInterface->IpNetMask());
323f8bec 699 DeleteInterface(pInterface);
364aa19a 700 i = 0; // Restart loop
6159a875 701 bHasChanges = TRUE;
364aa19a
VK
702 }
703 }
704
323f8bec
VK
705 // Add new interfaces
706 for(j = 0; j < pIfList->iNumEntries; j++)
707 {
708 for(i = 0; i < m_dwChildCount; i++)
709 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
710 {
711 Interface *pInterface = (Interface *)m_pChildList[i];
712
713 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
714 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
715 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
716 break;
717 }
718 if (i == m_dwChildCount)
719 {
720 // New interface
721 CreateNewInterface(pIfList->pInterfaces[j].dwIpAddr,
722 pIfList->pInterfaces[j].dwIpNetMask,
723 pIfList->pInterfaces[j].szName,
724 pIfList->pInterfaces[j].dwIndex,
725 pIfList->pInterfaces[j].dwType);
6159a875 726 bHasChanges = TRUE;
323f8bec
VK
727 }
728 }
e0d3b217
VK
729
730 DestroyInterfaceList(pIfList);
364aa19a 731 }
323f8bec 732
8bff53f6 733 m_tLastConfigurationPoll = time(NULL);
323f8bec 734 PollerUnlock();
ccdbbb52 735 DbgPrintf(AF_DEBUG_DISCOVERY, "Finished configuration poll for node %s (ID: %d)\n", m_szName, m_dwId);
6159a875
VK
736
737 if (bHasChanges)
738 {
739 Lock();
740 Modify();
741 Unlock();
742 }
364aa19a 743}
6f595ce2
VK
744
745
1275c750
VK
746//
747// Connect to native agent
748//
749
750BOOL Node::ConnectToAgent(void)
751{
752 // Create new agent connection object if needed
753 if (m_pAgentConnection == NULL)
754 m_pAgentConnection = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
755
756 // Check if we already connected
757 if (m_pAgentConnection->Nop() == ERR_SUCCESS)
758 return TRUE;
759
760 // Close current connection or clean up after broken connection
761 m_pAgentConnection->Disconnect();
762 return m_pAgentConnection->Connect();
763}
764
765
766//
767// Get item's value via SNMP
768//
769
3ea35b38 770DWORD Node::GetItemFromSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer)
1275c750
VK
771{
772 return SnmpGet(m_dwIpAddr, m_szCommunityString, szParam, NULL, 0,
f92869c9 773 szBuffer, dwBufSize, FALSE, TRUE) ? DCE_SUCCESS : DCE_COMM_ERROR;
1275c750
VK
774}
775
776
777//
778// Get item's value via native agent
779//
780
3ea35b38 781DWORD Node::GetItemFromAgent(const char *szParam, DWORD dwBufSize, char *szBuffer)
1275c750 782{
3ea35b38 783 DWORD dwError, dwResult = DCE_COMM_ERROR;
1275c750
VK
784 DWORD dwTries = 5;
785
3ea35b38
VK
786 AgentLock();
787
1275c750
VK
788 // Establish connection if needed
789 if (m_pAgentConnection == NULL)
790 if (!ConnectToAgent())
3ea35b38 791 goto end_loop;
1275c750
VK
792
793 // Get parameter from agent
794 while(dwTries-- > 0)
795 {
901c96c7 796 dwError = m_pAgentConnection->GetParameter((char *)szParam, dwBufSize, szBuffer);
1275c750
VK
797 switch(dwError)
798 {
799 case ERR_SUCCESS:
3ea35b38
VK
800 dwResult = DCE_SUCCESS;
801 goto end_loop;
1275c750 802 case ERR_UNKNOWN_PARAMETER:
3ea35b38
VK
803 dwResult = DCE_NOT_SUPPORTED;
804 goto end_loop;
1275c750
VK
805 case ERR_NOT_CONNECTED:
806 case ERR_CONNECTION_BROKEN:
807 if (!ConnectToAgent())
3ea35b38 808 goto end_loop;
1275c750
VK
809 break;
810 case ERR_REQUEST_TIMEOUT:
811 break;
812 }
813 }
3ea35b38
VK
814
815end_loop:
816 AgentUnlock();
817 return dwResult;
1275c750 818}
8e99117a
VK
819
820
821//
822// Get value for server's internal parameter
823//
824
3ea35b38 825DWORD Node::GetInternalItem(const char *szParam, DWORD dwBufSize, char *szBuffer)
8e99117a
VK
826{
827 DWORD dwError = DCE_SUCCESS;
828
829 if (!stricmp(szParam, "status"))
830 {
831 sprintf(szBuffer, "%d", m_iStatus);
832 }
833 else
834 {
835 dwError = DCE_NOT_SUPPORTED;
836 }
837
838 return dwError;
839}
129f8f7b
VK
840
841
842//
843// Put items which requires polling into the queue
844//
845
846void Node::QueueItemsForPolling(Queue *pPollerQueue)
847{
848 DWORD i;
849 time_t currTime;
850
851 currTime = time(NULL);
852
853 Lock();
854 for(i = 0; i < m_dwNumItems; i++)
855 {
3ea35b38 856 if (m_ppItems[i]->ReadyForPolling(currTime))
129f8f7b 857 {
3ea35b38 858 m_ppItems[i]->SetBusyFlag(TRUE);
5add75d8 859 pPollerQueue->Put(m_ppItems[i]);
067f2689
VK
860 }
861 }
862 Unlock();
863}
864
865
866//
867// Add item to node
868//
869
3ea35b38 870BOOL Node::AddItem(DCItem *pItem)
067f2689
VK
871{
872 DWORD i;
873 BOOL bResult = FALSE;
874
875 Lock();
876 // Check if that item exists
877 for(i = 0; i < m_dwNumItems; i++)
9ed4eaff
VK
878 if (m_ppItems[i]->Id() == pItem->Id())
879 break; // Item with specified id already exist
067f2689
VK
880
881 if (i == m_dwNumItems) // Add new item
882 {
883 m_dwNumItems++;
3ea35b38
VK
884 m_ppItems = (DCItem **)realloc(m_ppItems, sizeof(DCItem *) * m_dwNumItems);
885 m_ppItems[i] = pItem;
886 m_ppItems[i]->SetLastPollTime(0); // Cause item to be polled immediatelly
887 m_ppItems[i]->SetStatus(ITEM_STATUS_ACTIVE);
888 m_ppItems[i]->SetBusyFlag(FALSE);
53512272 889 Modify();
067f2689
VK
890 bResult = TRUE;
891 }
892
893 Unlock();
894 return bResult;
895}
b81249b7
VK
896
897
9ed4eaff
VK
898//
899// Delete item from node
900//
901
902BOOL Node::DeleteItem(DWORD dwItemId)
903{
904 DWORD i;
905 BOOL bResult = FALSE;
906
907 Lock();
908 // Check if that item exists
909 for(i = 0; i < m_dwNumItems; i++)
910 if (m_ppItems[i]->Id() == dwItemId)
911 {
912 // Destroy item
913 m_ppItems[i]->DeleteFromDB();
914 delete m_ppItems[i];
915 m_dwNumItems--;
916 memmove(&m_ppItems[i], &m_ppItems[i + 1], sizeof(DCItem *) * (m_dwNumItems - i));
917 bResult = TRUE;
bdce7422 918 break;
9ed4eaff
VK
919 }
920
921 Unlock();
922 return bResult;
923}
924
925
926//
927// Modify data collection item from CSCP message
928//
929
07a45e04
VK
930BOOL Node::UpdateItem(DWORD dwItemId, CSCPMessage *pMsg, DWORD *pdwNumMaps,
931 DWORD **ppdwMapIndex, DWORD **ppdwMapId)
9ed4eaff
VK
932{
933 DWORD i;
934 BOOL bResult = FALSE;
935
936 Lock();
937 // Check if that item exists
938 for(i = 0; i < m_dwNumItems; i++)
939 if (m_ppItems[i]->Id() == dwItemId)
940 {
07a45e04 941 m_ppItems[i]->UpdateFromMessage(pMsg, pdwNumMaps, ppdwMapIndex, ppdwMapId);
9ed4eaff 942 bResult = TRUE;
06e7be2f 943 m_bIsModified = TRUE;
bdce7422 944 break;
9ed4eaff
VK
945 }
946
947 Unlock();
948 return bResult;
949}
950
951
b81249b7
VK
952//
953// Create CSCP message with object's data
954//
955
956void Node::CreateMessage(CSCPMessage *pMsg)
957{
958 NetObj::CreateMessage(pMsg);
a5f8dbb8
VK
959 pMsg->SetVariable(VID_FLAGS, m_dwFlags);
960 pMsg->SetVariable(VID_DISCOVERY_FLAGS, m_dwDiscoveryFlags);
961 pMsg->SetVariable(VID_AGENT_PORT, m_wAgentPort);
962 pMsg->SetVariable(VID_AUTH_METHOD, m_wAuthMethod);
963 pMsg->SetVariable(VID_SHARED_SECRET, m_szSharedSecret);
964 pMsg->SetVariable(VID_COMMUNITY_STRING, m_szCommunityString);
965 pMsg->SetVariable(VID_SNMP_OID, m_szObjectId);
b81249b7 966}
24156e90
VK
967
968
969//
970// Modify object from message
971//
972
973DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
974{
975 if (!bAlreadyLocked)
976 Lock();
977
978 // Change listen port of native agent
979 if (pRequest->IsVariableExist(VID_AGENT_PORT))
980 m_wAgentPort = pRequest->GetVariableShort(VID_AGENT_PORT);
981
982 // Change authentication method of native agent
983 if (pRequest->IsVariableExist(VID_AUTH_METHOD))
984 m_wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
985
986 // Change shared secret of native agent
987 if (pRequest->IsVariableExist(VID_SHARED_SECRET))
988 pRequest->GetVariableStr(VID_SHARED_SECRET, m_szSharedSecret, MAX_SECRET_LENGTH);
989
990 // Change SNMP community string
991 if (pRequest->IsVariableExist(VID_COMMUNITY_STRING))
992 pRequest->GetVariableStr(VID_COMMUNITY_STRING, m_szCommunityString, MAX_COMMUNITY_LENGTH);
993
994 return NetObj::ModifyFromMessage(pRequest, TRUE);
995}
3c55b85d
VK
996
997
998//
999// Lock data collection items list
1000//
1001
1002BOOL Node::LockDCIList(DWORD dwSessionId)
1003{
1004 BOOL bSuccess = FALSE;
1005
1006 Lock();
1007 if (m_dwDCILockStatus == INVALID_INDEX)
1008 {
1009 m_dwDCILockStatus = dwSessionId;
1010 bSuccess = TRUE;
1011 }
1012 Unlock();
1013 return bSuccess;
1014}
1015
1016
1017//
1018// Unlock data collection items list
1019//
1020
1021BOOL Node::UnlockDCIList(DWORD dwSessionId)
1022{
1023 BOOL bSuccess = FALSE;
1024
1025 Lock();
1026 if (m_dwDCILockStatus == dwSessionId)
1027 {
1028 m_dwDCILockStatus = INVALID_INDEX;
1029 bSuccess = TRUE;
1030 }
1031 Unlock();
1032 return bSuccess;
1033}
1034
1035
1036//
1037// Send DCI list to client
1038//
1039
1040void Node::SendItemsToClient(ClientSession *pSession, DWORD dwRqId)
1041{
1042 CSCPMessage msg;
1043 DWORD i;
1044
1045 // Prepare message
3c55b85d 1046 msg.SetId(dwRqId);
07a45e04 1047 msg.SetCode(CMD_NODE_DCI);
3c55b85d
VK
1048
1049 // Walk through items list
1050 for(i = 0; i < m_dwNumItems; i++)
1051 {
1052 m_ppItems[i]->CreateMessage(&msg);
1053 pSession->SendMessage(&msg);
1054 msg.DeleteAllVariables();
1055 }
1056
1057 // Send end-of-list indicator
1058 msg.SetCode(CMD_NODE_DCI_LIST_END);
1059 pSession->SendMessage(&msg);
1060}
bdce7422
VK
1061
1062
1063//
1064// Get DCI item's type
1065//
1066
1067int Node::GetItemType(DWORD dwItemId)
1068{
1069 DWORD i;
1070 int iType = -1;
1071
1072 Lock();
1073 // Check if that item exists
1074 for(i = 0; i < m_dwNumItems; i++)
1075 if (m_ppItems[i]->Id() == dwItemId)
1076 {
1077 iType = m_ppItems[i]->DataType();
1078 break;
1079 }
1080
1081 Unlock();
1082 return iType;
1083}