- New event codes added
[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();
6f595ce2
VK
48 m_dwNumItems = 0;
49 m_pItems = NULL;
1275c750 50 m_pAgentConnection = NULL;
eefe7d68
VK
51}
52
53
54//
55// Constructor for new node object
56//
57
58Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwDiscoveryFlags)
59 :NetObj()
60{
61 m_dwIpAddr = dwAddr;
62 m_dwFlags = dwFlags;
63 m_dwDiscoveryFlags = dwDiscoveryFlags;
2da1357c
VK
64 m_wAgentPort = AGENT_LISTEN_PORT;
65 m_wAuthMethod = AUTH_NONE;
66 m_szSharedSecret[0] = 0;
67 m_iStatusPollType = POLL_ICMP_PING;
469b937c 68 m_iSNMPVersion = SNMP_VERSION_1;
2da1357c 69 strcpy(m_szCommunityString, "public");
cc140cce 70 IpToStr(dwAddr, m_szName); // Make default name from IP address
469b937c 71 m_szObjectId[0] = 0;
48b1c0ac 72 m_tLastDiscoveryPoll = 0;
f00307b7 73 m_tLastStatusPoll = 0;
364aa19a
VK
74 m_tLastConfigurationPoll = 0;
75 m_iSnmpAgentFails = 0;
76 m_iNativeAgentFails = 0;
323f8bec 77 m_hPollerMutex = MutexCreate();
6f595ce2
VK
78 m_dwNumItems = 0;
79 m_pItems = NULL;
1275c750 80 m_pAgentConnection = NULL;
eefe7d68
VK
81}
82
83
84//
85// Node destructor
86//
87
88Node::~Node()
89{
323f8bec 90 MutexDestroy(m_hPollerMutex);
6f595ce2
VK
91 if (m_pItems != NULL)
92 free(m_pItems);
1275c750
VK
93 if (m_pAgentConnection != NULL)
94 delete m_pAgentConnection;
eefe7d68
VK
95}
96
97
2da1357c
VK
98//
99// Create object from database data
100//
101
102BOOL Node::CreateFromDB(DWORD dwId)
103{
104 char szQuery[256];
105 DB_RESULT hResult;
106 int i, iNumRows;
107 DWORD dwSubnetId;
108 NetObj *pObject;
109
110 sprintf(szQuery, "SELECT id,name,status,primary_ip,is_snmp,is_agent,is_bridge,"
111 "is_router,snmp_version,discovery_flags,auth_method,secret,"
ce19c304 112 "agent_port,status_poll_type,community,snmp_oid,is_local_mgmt FROM nodes WHERE id=%d", dwId);
2da1357c
VK
113 hResult = DBSelect(g_hCoreDB, szQuery);
114 if (hResult == 0)
115 return FALSE; // Query failed
116
117 if (DBGetNumRows(hResult) == 0)
118 {
119 DBFreeResult(hResult);
120 return FALSE;
121 }
122
123 m_dwId = dwId;
124 strncpy(m_szName, DBGetField(hResult, 0, 1), MAX_OBJECT_NAME);
125 m_iStatus = DBGetFieldLong(hResult, 0, 2);
126 m_dwIpAddr = DBGetFieldULong(hResult, 0, 3);
127
128 // Flags
129 if (DBGetFieldLong(hResult, 0, 4))
130 m_dwFlags |= NF_IS_SNMP;
131 if (DBGetFieldLong(hResult, 0, 5))
132 m_dwFlags |= NF_IS_NATIVE_AGENT;
133 if (DBGetFieldLong(hResult, 0, 6))
134 m_dwFlags |= NF_IS_BRIDGE;
135 if (DBGetFieldLong(hResult, 0, 7))
136 m_dwFlags |= NF_IS_ROUTER;
ce19c304
VK
137 if (DBGetFieldLong(hResult, 0, 16))
138 m_dwFlags |= NF_IS_LOCAL_MGMT;
2da1357c
VK
139
140 m_iSNMPVersion = DBGetFieldLong(hResult, 0, 8);
141 m_dwDiscoveryFlags = DBGetFieldULong(hResult, 0, 9);
142 m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 10);
143 strncpy(m_szSharedSecret, DBGetField(hResult, 0, 11), MAX_SECRET_LENGTH);
144 m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 12);
145 m_iStatusPollType = DBGetFieldLong(hResult, 0, 13);
146 strncpy(m_szCommunityString, DBGetField(hResult, 0, 14), MAX_COMMUNITY_LENGTH);
a0495b6e 147 strncpy(m_szObjectId, DBGetField(hResult, 0, 15), MAX_OID_LEN * 4);
2da1357c
VK
148
149 DBFreeResult(hResult);
150
151 // Link node to subnets
152 sprintf(szQuery, "SELECT subnet_id FROM nsmap WHERE node_id=%d", dwId);
cc140cce 153 hResult = DBSelect(g_hCoreDB, szQuery);
2da1357c
VK
154 if (hResult == 0)
155 return FALSE; // Query failed
156
157 if (DBGetNumRows(hResult) == 0)
158 {
159 DBFreeResult(hResult);
160 return FALSE; // No parents - it shouldn't happen if database isn't corrupted
161 }
162
cc140cce 163 BOOL bResult = FALSE;
2da1357c
VK
164 iNumRows = DBGetNumRows(hResult);
165 for(i = 0; i < iNumRows; i++)
166 {
167 dwSubnetId = DBGetFieldULong(hResult, i, 0);
168 pObject = FindObjectById(dwSubnetId);
169 if (pObject == NULL)
170 {
171 WriteLog(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
cc140cce 172 break;
2da1357c
VK
173 }
174 else if (pObject->Type() != OBJECT_SUBNET)
175 {
176 WriteLog(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
cc140cce 177 break;
2da1357c
VK
178 }
179 else
180 {
181 pObject->AddChild(this);
182 AddParent(pObject);
cc140cce 183 bResult = TRUE;
2da1357c
VK
184 }
185 }
186
187 DBFreeResult(hResult);
6f595ce2 188 LoadItemsFromDB();
3e4e127f 189 LoadACLFromDB();
cc140cce 190 return bResult;
2da1357c
VK
191}
192
193
eefe7d68
VK
194//
195// Save object to database
196//
197
198BOOL Node::SaveToDB(void)
199{
a0495b6e 200 char szQuery[4096];
eefe7d68
VK
201 DB_RESULT hResult;
202 BOOL bNewObject = TRUE;
203
204 // Lock object's access
205 Lock();
206
207 // Check for object's existence in database
208 sprintf(szQuery, "SELECT id FROM nodes WHERE id=%ld", m_dwId);
209 hResult = DBSelect(g_hCoreDB, szQuery);
210 if (hResult != 0)
211 {
212 if (DBGetNumRows(hResult) > 0)
213 bNewObject = FALSE;
214 DBFreeResult(hResult);
215 }
216
217 // Form and execute INSERT or UPDATE query
218 if (bNewObject)
2da1357c
VK
219 sprintf(szQuery, "INSERT INTO nodes (id,name,status,is_deleted,primary_ip,"
220 "is_snmp,is_agent,is_bridge,is_router,snmp_version,community,"
a0495b6e 221 "discovery_flags,status_poll_type,agent_port,auth_method,secret,"
ce19c304
VK
222 "snmp_oid,is_local_mgmt)"
223 " VALUES (%d,'%s',%d,%d,%d,%d,%d,%d,%d,%d,'%s',%d,%d,%d,%d,'%s','%s',%d)",
eefe7d68
VK
224 m_dwId, m_szName, m_iStatus, m_bIsDeleted, m_dwIpAddr,
225 m_dwFlags & NF_IS_SNMP ? 1 : 0,
226 m_dwFlags & NF_IS_NATIVE_AGENT ? 1 : 0,
227 m_dwFlags & NF_IS_BRIDGE ? 1 : 0,
228 m_dwFlags & NF_IS_ROUTER ? 1 : 0,
2da1357c 229 m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags, m_iStatusPollType,
ce19c304
VK
230 m_wAgentPort,m_wAuthMethod,m_szSharedSecret, m_szObjectId,
231 m_dwFlags & NF_IS_LOCAL_MGMT ? 1 : 0);
eefe7d68
VK
232 else
233 sprintf(szQuery, "UPDATE nodes SET name='%s',status=%d,is_deleted=%d,primary_ip=%d,"
234 "is_snmp=%d,is_agent=%d,is_bridge=%d,is_router=%d,snmp_version=%d,"
2da1357c 235 "community='%s',discovery_flags=%d,status_poll_type=%d,agent_port=%d,"
ce19c304 236 "auth_method=%d,secret='%s',snmp_oid='%s',is_local_mgmt=%d WHERE id=%d",
eefe7d68
VK
237 m_szName, m_iStatus, m_bIsDeleted, m_dwIpAddr,
238 m_dwFlags & NF_IS_SNMP ? 1 : 0,
239 m_dwFlags & NF_IS_NATIVE_AGENT ? 1 : 0,
240 m_dwFlags & NF_IS_BRIDGE ? 1 : 0,
241 m_dwFlags & NF_IS_ROUTER ? 1 : 0,
2da1357c 242 m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags,
a0495b6e 243 m_iStatusPollType, m_wAgentPort, m_wAuthMethod, m_szSharedSecret,
ce19c304 244 m_szObjectId, m_dwFlags & NF_IS_LOCAL_MGMT ? 1 : 0, m_dwId);
eefe7d68
VK
245 DBQuery(g_hCoreDB, szQuery);
246
247 // Clear modifications flag and unlock object
248 m_bIsModified = FALSE;
249 Unlock();
250
251 return TRUE;
252}
253
254
255//
256// Delete object from database
257//
258
259BOOL Node::DeleteFromDB(void)
260{
261 char szQuery[256];
262
263 sprintf(szQuery, "DELETE FROM nodes WHERE id=%ld", m_dwId);
fb2ef88c
VK
264 QueueSQLRequest(szQuery);
265 sprintf(szQuery, "DELETE FROM nsmap WHERE node_id=%ld", m_dwId);
266 QueueSQLRequest(szQuery);
8e99117a 267 sprintf(szQuery, "DROP TABLE idata_%ld", m_dwId);
fb2ef88c 268 QueueSQLRequest(szQuery);
eefe7d68
VK
269 return TRUE;
270}
469b937c
VK
271
272
273//
274// Poll newly discovered node
275// Usually called once by node poller thread when new node is discovered
276// and object for it is created
277//
278
279BOOL Node::NewNodePoll(DWORD dwNetMask)
280{
5811233f
VK
281 AgentConnection *pAgentConn;
282
be0a5a53
VK
283 PollerLock();
284
469b937c 285 // Determine node's capabilities
1275c750 286 if (SnmpGet(m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0, m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE))
469b937c
VK
287 m_dwFlags |= NF_IS_SNMP;
288
5811233f
VK
289 pAgentConn = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
290 if (pAgentConn->Connect())
291 m_dwFlags |= NF_IS_NATIVE_AGENT;
292
469b937c 293 // Get interface list
ce19c304 294 if ((m_dwFlags & NF_IS_SNMP) || (m_dwFlags & NF_IS_NATIVE_AGENT) || (m_dwFlags & NF_IS_LOCAL_MGMT))
469b937c 295 {
5811233f 296 INTERFACE_LIST *pIfList = NULL;
a0495b6e
VK
297 int i;
298
ce19c304
VK
299 if (m_dwFlags & NF_IS_LOCAL_MGMT) // For local machine
300 pIfList = GetLocalInterfaceList();
301 else if (m_dwFlags & NF_IS_NATIVE_AGENT) // For others prefer native agent
5811233f
VK
302 pIfList = pAgentConn->GetInterfaceList();
303 if ((pIfList == NULL) && (m_dwFlags & NF_IS_SNMP)) // Use SNMP if we cannot get interfaces via agent
304 pIfList = SnmpGetInterfaceList(m_dwIpAddr, m_szCommunityString);
305
306 if (pIfList != NULL)
a0495b6e 307 {
5811233f 308 for(i = 0; i < pIfList->iNumEntries; i++)
323f8bec
VK
309 CreateNewInterface(pIfList->pInterfaces[i].dwIpAddr,
310 pIfList->pInterfaces[i].dwIpNetMask,
311 pIfList->pInterfaces[i].szName,
312 pIfList->pInterfaces[i].dwIndex,
313 pIfList->pInterfaces[i].dwType);
5811233f 314 DestroyInterfaceList(pIfList);
a0495b6e 315 }
9437ca82
VK
316 else
317 {
318 // We cannot get interface list from node for some reasons, create dummy one
323f8bec 319 CreateNewInterface(m_dwIpAddr, dwNetMask);
9437ca82 320 }
469b937c
VK
321 }
322 else // No SNMP, no native agent - create pseudo interface object
323 {
323f8bec 324 CreateNewInterface(m_dwIpAddr, dwNetMask);
469b937c
VK
325 }
326
5811233f
VK
327 // Clean up agent connection
328 if (m_dwFlags & NF_IS_NATIVE_AGENT)
329 pAgentConn->Disconnect();
330 delete pAgentConn;
331
be0a5a53
VK
332 PollerUnlock();
333
469b937c
VK
334 return TRUE;
335}
ce19c304
VK
336
337
338//
c8b1f788 339// Get ARP cache from node
ce19c304
VK
340//
341
c8b1f788 342ARP_CACHE *Node::GetArpCache(void)
ce19c304
VK
343{
344 ARP_CACHE *pArpCache = NULL;
345
346 if (m_dwFlags & NF_IS_LOCAL_MGMT)
347 {
348 pArpCache = GetLocalArpCache();
349 }
350 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
351 {
1275c750
VK
352 if (ConnectToAgent())
353 pArpCache = m_pAgentConnection->GetArpCache();
ce19c304
VK
354 }
355 else if (m_dwFlags & NF_IS_SNMP)
356 {
357 pArpCache = SnmpGetArpCache(m_dwIpAddr, m_szCommunityString);
358 }
359
360 return pArpCache;
361}
362
363
364//
365// Get list of interfaces from node
366//
367
368INTERFACE_LIST *Node::GetInterfaceList(void)
369{
370 INTERFACE_LIST *pIfList = NULL;
371
372 if (m_dwFlags & NF_IS_LOCAL_MGMT)
373 {
374 pIfList = GetLocalInterfaceList();
375 }
376 else if (m_dwFlags & NF_IS_NATIVE_AGENT)
377 {
378 AgentConnection *pAgentConn = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
379 if (pAgentConn->Connect())
380 {
381 pIfList = pAgentConn->GetInterfaceList();
382 pAgentConn->Disconnect();
383 }
384 delete pAgentConn;
385 }
386 else if (m_dwFlags & NF_IS_SNMP)
387 {
388 pIfList = SnmpGetInterfaceList(m_dwIpAddr, m_szCommunityString);
389 }
390
391 return pIfList;
392}
48b1c0ac
VK
393
394
395//
396// Find interface by index and node IP
397// Returns pointer to interface object or NULL if appropriate interface couldn't be found
398//
399
400Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
401{
402 DWORD i;
403 Interface *pInterface;
404
405 for(i = 0; i < m_dwChildCount; i++)
406 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
407 {
408 pInterface = (Interface *)m_pChildList[i];
409 if (pInterface->IfIndex() == dwIndex)
410 if ((pInterface->IpAddr() & pInterface->IpNetMask()) ==
411 (dwHostAddr & pInterface->IpNetMask()))
412 return pInterface;
413 }
414 return NULL;
415}
f00307b7
VK
416
417
323f8bec
VK
418//
419// Create new interface
420//
421
422void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName, DWORD dwIndex, DWORD dwType)
423{
424 Interface *pInterface;
425 Subnet *pSubnet;
426
427 // Create interface object
428 if (szName != NULL)
429 pInterface = new Interface(szName, dwIndex, dwIpAddr, dwNetMask, dwType);
430 else
431 pInterface = new Interface(dwIpAddr, dwNetMask);
432
433 // Insert to objects' list and generate event
434 NetObjInsert(pInterface, TRUE);
435 AddInterface(pInterface);
436 PostEvent(EVENT_INTERFACE_ADDED, m_dwId, "dsaad", pInterface->Id(),
437 pInterface->Name(), pInterface->IpAddr(),
438 pInterface->IpNetMask(), pInterface->IfIndex());
439
440 // Bind node to appropriate subnet
441 if (pInterface->IpAddr() != 0) // Do not link non-IP interfaces to 0.0.0.0 subnet
442 {
443 pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
444 if (pSubnet == NULL)
445 {
446 // Create new subnet object
447 pSubnet = new Subnet(pInterface->IpAddr() & pInterface->IpNetMask(), pInterface->IpNetMask());
448 NetObjInsert(pSubnet, TRUE);
449 g_pEntireNet->AddSubnet(pSubnet);
450 }
451 pSubnet->AddNode(this);
452 }
453}
454
455
456//
457// Delete interface from node
458//
459
460void Node::DeleteInterface(Interface *pInterface)
461{
462 DWORD i;
463
464 // Check if we should unlink node from interface's subnet
465 if (pInterface->IpAddr() != 0)
466 {
467 for(i = 0; i < m_dwChildCount; i++)
468 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
469 if (m_pChildList[i] != pInterface)
470 if ((((Interface *)m_pChildList[i])->IpAddr() & ((Interface *)m_pChildList[i])->IpNetMask()) ==
471 (pInterface->IpAddr() & pInterface->IpNetMask()))
472 break;
473 if (i == m_dwChildCount)
474 {
475 // Last interface in subnet, should unlink node
476 Subnet *pSubnet = FindSubnetByIP(pInterface->IpAddr() & pInterface->IpNetMask());
477 if (pSubnet != NULL)
478 pSubnet->DeleteChild(this);
479 DeleteParent(pSubnet);
480 }
481 }
482 pInterface->Delete();
483}
484
485
f00307b7
VK
486//
487// Calculate node status based on child objects status
488//
489
490void Node::CalculateCompoundStatus(void)
491{
492 int iOldStatus = m_iStatus;
493 static DWORD dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_MINOR,
494 EVENT_NODE_WARNING, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
495 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
496
497 NetObj::CalculateCompoundStatus();
498 if (m_iStatus != iOldStatus)
499 PostEvent(dwEventCodes[m_iStatus], m_dwId, "d", iOldStatus);
500}
501
502
503//
504// Perform status poll on node
505//
506
507void Node::StatusPoll(void)
508{
509 DWORD i;
510
323f8bec 511 PollerLock();
f00307b7
VK
512 for(i = 0; i < m_dwChildCount; i++)
513 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
514 ((Interface *)m_pChildList[i])->StatusPoll();
515 CalculateCompoundStatus();
516 m_tLastStatusPoll = time(NULL);
323f8bec 517 PollerUnlock();
f00307b7 518}
364aa19a
VK
519
520
521//
522// Perform configuration poll on node
523//
524
525void Node::ConfigurationPoll(void)
526{
527 DWORD dwOldFlags = m_dwFlags;
528 AgentConnection *pAgentConn;
529 INTERFACE_LIST *pIfList;
530
323f8bec
VK
531 PollerLock();
532
364aa19a 533 // Check node's capabilities
1275c750 534 if (SnmpGet(m_dwIpAddr, m_szCommunityString, ".1.3.6.1.2.1.1.2.0", NULL, 0, m_szObjectId, MAX_OID_LEN * 4, FALSE, FALSE))
364aa19a
VK
535 {
536 m_dwFlags |= NF_IS_SNMP;
537 m_iSnmpAgentFails = 0;
538 }
539 else
540 {
4ea67c99
VK
541 if (m_dwFlags & NF_IS_SNMP)
542 {
543 if (m_iSnmpAgentFails == 0)
544 PostEvent(EVENT_SNMP_FAIL, m_dwId, NULL);
545 m_iSnmpAgentFails++;
546 }
364aa19a
VK
547 }
548
549 pAgentConn = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
550 if (pAgentConn->Connect())
551 {
552 m_dwFlags |= NF_IS_NATIVE_AGENT;
553 m_iNativeAgentFails = 0;
f91fa4c2 554 pAgentConn->Disconnect();
364aa19a
VK
555 }
556 else
557 {
4ea67c99
VK
558 if (m_dwFlags & NF_IS_NATIVE_AGENT)
559 {
560 if (m_iNativeAgentFails == 0)
561 PostEvent(EVENT_AGENT_FAIL, m_dwId, NULL);
562 m_iNativeAgentFails++;
563 }
364aa19a 564 }
f91fa4c2 565 delete pAgentConn;
364aa19a
VK
566
567 // Generate event if node flags has been changed
568 if (dwOldFlags != m_dwFlags)
569 PostEvent(EVENT_NODE_FLAGS_CHANGED, m_dwId, "xx", dwOldFlags, m_dwFlags);
570
571 // Retrieve interface list
572 pIfList = GetInterfaceList();
573 if (pIfList != NULL)
574 {
575 DWORD i;
323f8bec 576 int j;
364aa19a
VK
577
578 // Find non-existing interfaces
579 for(i = 0; i < m_dwChildCount; i++)
580 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
581 {
582 Interface *pInterface = (Interface *)m_pChildList[i];
364aa19a
VK
583
584 for(j = 0; j < pIfList->iNumEntries; j++)
585 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
586 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
587 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
588 break;
589 if (j == pIfList->iNumEntries)
590 {
591 // No such interface in current configuration, delete it
592 PostEvent(EVENT_INTERFACE_DELETED, m_dwId, "dsaa", pInterface->IfIndex(),
593 pInterface->Name(), pInterface->IpAddr(), pInterface->IpNetMask());
323f8bec 594 DeleteInterface(pInterface);
364aa19a
VK
595 i = 0; // Restart loop
596 }
597 }
598
323f8bec
VK
599 // Add new interfaces
600 for(j = 0; j < pIfList->iNumEntries; j++)
601 {
602 for(i = 0; i < m_dwChildCount; i++)
603 if (m_pChildList[i]->Type() == OBJECT_INTERFACE)
604 {
605 Interface *pInterface = (Interface *)m_pChildList[i];
606
607 if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
608 (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
609 (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
610 break;
611 }
612 if (i == m_dwChildCount)
613 {
614 // New interface
615 CreateNewInterface(pIfList->pInterfaces[j].dwIpAddr,
616 pIfList->pInterfaces[j].dwIpNetMask,
617 pIfList->pInterfaces[j].szName,
618 pIfList->pInterfaces[j].dwIndex,
619 pIfList->pInterfaces[j].dwType);
620 }
621 }
364aa19a 622 }
323f8bec
VK
623
624 PollerUnlock();
364aa19a 625}
6f595ce2
VK
626
627
628//
629// Load data collection items from database
630//
631
632void Node::LoadItemsFromDB(void)
633{
634 char szQuery[256];
635 DB_RESULT hResult;
636
637 if (m_pItems != NULL)
638 {
639 free(m_pItems);
640 m_pItems = NULL;
641 }
642 m_dwNumItems = NULL;
643
644 sprintf(szQuery, "SELECT id,name,source,datatype,polling_interval,retention_time FROM items WHERE node_id=%d", m_dwId);
645 hResult = DBSelect(g_hCoreDB, szQuery);
646
647 if (hResult != 0)
648 {
649 int i, iRows;
650
651 iRows = DBGetNumRows(hResult);
652 if (iRows > 0)
653 {
654 m_dwNumItems = iRows;
655 m_pItems = (DC_ITEM *)malloc(sizeof(DC_ITEM) * iRows);
656 for(i = 0; i < iRows; i++)
657 {
658 m_pItems[i].dwId = DBGetFieldULong(hResult, i, 0);
659 strcpy(m_pItems[i].szName, DBGetField(hResult, i, 1));
660 m_pItems[i].iSource = (BYTE)DBGetFieldLong(hResult, i, 2);
661 m_pItems[i].iDataType = (BYTE)DBGetFieldLong(hResult, i, 3);
662 m_pItems[i].iPollingInterval = DBGetFieldLong(hResult, i, 4);
663 m_pItems[i].iRetentionTime = DBGetFieldLong(hResult, i, 5);
129f8f7b 664 m_pItems[i].tLastPoll = 0;
067f2689 665 m_pItems[i].iBusy = 0;
6f595ce2
VK
666 }
667 }
668 DBFreeResult(hResult);
669 }
670}
1275c750
VK
671
672
673//
674// Connect to native agent
675//
676
677BOOL Node::ConnectToAgent(void)
678{
679 // Create new agent connection object if needed
680 if (m_pAgentConnection == NULL)
681 m_pAgentConnection = new AgentConnection(m_dwIpAddr, m_wAgentPort, m_wAuthMethod, m_szSharedSecret);
682
683 // Check if we already connected
684 if (m_pAgentConnection->Nop() == ERR_SUCCESS)
685 return TRUE;
686
687 // Close current connection or clean up after broken connection
688 m_pAgentConnection->Disconnect();
689 return m_pAgentConnection->Connect();
690}
691
692
693//
694// Get item's value via SNMP
695//
696
697DWORD Node::GetItemFromSNMP(char *szParam, DWORD dwBufSize, char *szBuffer)
698{
699 return SnmpGet(m_dwIpAddr, m_szCommunityString, szParam, NULL, 0,
700 szBuffer, dwBufSize, FALSE, TRUE) ? DCE_SUCCESS : DCE_COMM_ERROR;
701}
702
703
704//
705// Get item's value via native agent
706//
707
708DWORD Node::GetItemFromAgent(char *szParam, DWORD dwBufSize, char *szBuffer)
709{
710 DWORD dwError;
711 DWORD dwTries = 5;
712
713 // Establish connection if needed
714 if (m_pAgentConnection == NULL)
715 if (!ConnectToAgent())
716 return DCE_COMM_ERROR;
717
718 // Get parameter from agent
719 while(dwTries-- > 0)
720 {
721 dwError = m_pAgentConnection->GetParameter(szParam, dwBufSize, szBuffer);
722 switch(dwError)
723 {
724 case ERR_SUCCESS:
725 return DCE_SUCCESS;
726 case ERR_UNKNOWN_PARAMETER:
727 return DCE_NOT_SUPPORTED;
728 case ERR_NOT_CONNECTED:
729 case ERR_CONNECTION_BROKEN:
730 if (!ConnectToAgent())
731 return DCE_COMM_ERROR;
732 break;
733 case ERR_REQUEST_TIMEOUT:
734 break;
735 }
736 }
737 return DCE_COMM_ERROR;
738}
8e99117a
VK
739
740
741//
742// Get value for server's internal parameter
743//
744
745DWORD Node::GetInternalItem(char *szParam, DWORD dwBufSize, char *szBuffer)
746{
747 DWORD dwError = DCE_SUCCESS;
748
749 if (!stricmp(szParam, "status"))
750 {
751 sprintf(szBuffer, "%d", m_iStatus);
752 }
067f2689
VK
753 else if (!memicmp(szParam, "debug.", 6))
754 {
755 strcpy(szBuffer, "0");
756 }
8e99117a
VK
757 else
758 {
759 dwError = DCE_NOT_SUPPORTED;
760 }
761
762 return dwError;
763}
129f8f7b
VK
764
765
766//
767// Put items which requires polling into the queue
768//
769
770void Node::QueueItemsForPolling(Queue *pPollerQueue)
771{
772 DWORD i;
773 time_t currTime;
774
775 currTime = time(NULL);
776
777 Lock();
778 for(i = 0; i < m_dwNumItems; i++)
779 {
067f2689
VK
780 if ((m_pItems[i].iStatus == ITEM_STATUS_ACTIVE) &&
781 (m_pItems[i].tLastPoll + m_pItems[i].iPollingInterval < currTime) &&
782 (m_pItems[i].iBusy == 0))
129f8f7b
VK
783 {
784 DCI_ENVELOPE *pEnv;
785
786 // Create envelope for item
787 pEnv = (DCI_ENVELOPE *)malloc(sizeof(DCI_ENVELOPE));
788 pEnv->dwItemId = m_pItems[i].dwId;
789 pEnv->dwNodeId = m_dwId;
790 pEnv->iDataSource = m_pItems[i].iSource;
791 strcpy(pEnv->szItemName, m_pItems[i].szName);
792
793 // Put request into queue
794 pPollerQueue->Put(pEnv);
067f2689
VK
795 m_pItems[i].iBusy = 1;
796 }
797 }
798 Unlock();
799}
800
801
802//
803// Set item's status
804//
805
806void Node::SetItemStatus(DWORD dwItemId, int iStatus)
807{
808 DWORD i;
809
810 Lock();
811 for(i = 0; i < m_dwNumItems; i++)
812 {
813 if (m_pItems[i].dwId == dwItemId)
814 {
815 if (m_pItems[i].iStatus != iStatus)
816 {
817 m_pItems[i].iStatus = iStatus;
818 m_bIsModified = TRUE;
819 }
820 break;
129f8f7b
VK
821 }
822 }
823 Unlock();
824}
067f2689
VK
825
826
827//
828// Set item's last poll time
829//
830
831void Node::SetItemLastPollTime(DWORD dwItemId, time_t tLastPoll)
832{
833 DWORD i;
834
835 Lock();
836 for(i = 0; i < m_dwNumItems; i++)
837 {
838 if (m_pItems[i].dwId == dwItemId)
839 {
840 m_pItems[i].tLastPoll = tLastPoll;
841 m_pItems[i].iBusy = 0;
842 break;
843 }
844 }
845 Unlock();
846}
847
848
849//
850// Add item to node
851//
852
853BOOL Node::AddItem(DC_ITEM *pItem)
854{
855 DWORD i;
856 BOOL bResult = FALSE;
857
858 Lock();
859 // Check if that item exists
860 for(i = 0; i < m_dwNumItems; i++)
861 if ((m_pItems[i].dwId == pItem->dwId) ||
862 (!stricmp(m_pItems[i].szName, pItem->szName)))
863 break; // Item with specified name or id already exist
864
865 if (i == m_dwNumItems) // Add new item
866 {
867 m_dwNumItems++;
868 m_pItems = (DC_ITEM *)realloc(m_pItems, sizeof(DC_ITEM) * m_dwNumItems);
869 memcpy(&m_pItems[i], pItem, sizeof(DC_ITEM));
870 m_pItems[i].tLastPoll = 0; // Cause item to be polled immediatelly
871 m_pItems[i].iStatus = ITEM_STATUS_ACTIVE;
872 m_pItems[i].iBusy = 0;
873 m_bIsModified = TRUE;
874 bResult = TRUE;
875 }
876
877 Unlock();
878 return bResult;
879}
b81249b7
VK
880
881
882//
883// Create CSCP message with object's data
884//
885
886void Node::CreateMessage(CSCPMessage *pMsg)
887{
888 NetObj::CreateMessage(pMsg);
a5f8dbb8
VK
889 pMsg->SetVariable(VID_FLAGS, m_dwFlags);
890 pMsg->SetVariable(VID_DISCOVERY_FLAGS, m_dwDiscoveryFlags);
891 pMsg->SetVariable(VID_AGENT_PORT, m_wAgentPort);
892 pMsg->SetVariable(VID_AUTH_METHOD, m_wAuthMethod);
893 pMsg->SetVariable(VID_SHARED_SECRET, m_szSharedSecret);
894 pMsg->SetVariable(VID_COMMUNITY_STRING, m_szCommunityString);
895 pMsg->SetVariable(VID_SNMP_OID, m_szObjectId);
b81249b7 896}