Added new status for collection error. Communication error does not reset status...
[public/netxms.git] / src / server / core / agent.cpp
CommitLineData
9fa031cd 1/*
5039dede 2** NetXMS - Network Management System
2df047f4 3** Copyright (C) 2003-2016 Victor Kirhenshtein
5039dede
AK
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** File: agent.cpp
20**
21**/
22
23#include "nxcore.h"
24
489b117b 25/**
26 * Externals
27 */
3f635e1b 28void ProcessTrap(SNMP_PDU *pdu, const InetAddress& srcAddr, UINT32 zoneId, int srcPort, SNMP_Transport *pTransport, SNMP_Engine *localEngine, bool isInformRq);
685508a7 29void QueueProxiedSyslogMessage(const InetAddress &addr, UINT32 zoneId, time_t timestamp, const char *msg, int msgLen);
489b117b 30
d1c1c522
VK
31/**
32 * Destructor for extended agent connection class
33 */
5039dede
AK
34AgentConnectionEx::~AgentConnectionEx()
35{
36}
37
d1c1c522
VK
38/**
39 * Trap processor
40 */
b368969c 41void AgentConnectionEx::onTrap(NXCPMessage *pMsg)
5039dede 42{
967893bb 43 UINT32 dwEventCode;
5039dede 44 int i, iNumArgs;
d1c1c522 45 Node *pNode = NULL;
5039dede 46 TCHAR *pszArgList[32], szBuffer[32];
35f836fe 47 char szFormat[] = "ssssssssssssssssssssssssssssssss";
5039dede 48
c11eee9b 49 DbgPrintf(3, _T("AgentConnectionEx::onTrap(): Received trap message from agent at %s, node ID %d"), getIpAddr().toString(szBuffer), m_nodeId);
d1c1c522
VK
50 if (m_nodeId != 0)
51 pNode = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
52 if (pNode == NULL)
685508a7 53 pNode = FindNodeByIP(0, getIpAddr());
5039dede
AK
54 if (pNode != NULL)
55 {
db091a1f 56 if (pNode->getStatus() != STATUS_UNMANAGED)
5c5c7111
VK
57 {
58 // Check for duplicate traps - only accept traps with ID
59 // higher than last received
60 // agents prior to 1.1.6 will not send trap id
61 // we should accept trap in that case to maintain compatibility
62 bool acceptTrap;
b368969c 63 QWORD trapId = pMsg->getFieldAsUInt64(VID_TRAP_ID);
5c5c7111
VK
64 if (trapId != 0)
65 {
66 acceptTrap = pNode->checkAgentTrapId(trapId);
67 DbgPrintf(5, _T("AgentConnectionEx::onTrap(): trapID is%s valid"), acceptTrap ? _T("") : _T(" not"));
68 }
69 else
70 {
71 acceptTrap = true;
72 DbgPrintf(5, _T("AgentConnectionEx::onTrap(): trap ID not provided"));
73 }
fed33789 74
5c5c7111
VK
75 if (acceptTrap)
76 {
b368969c 77 dwEventCode = pMsg->getFieldAsUInt32(VID_EVENT_CODE);
5c5c7111
VK
78 if ((dwEventCode == 0) && pMsg->isFieldExist(VID_EVENT_NAME))
79 {
80 TCHAR eventName[256];
b368969c 81 pMsg->getFieldAsString(VID_EVENT_NAME, eventName, 256);
5c5c7111
VK
82 dwEventCode = EventCodeFromName(eventName, 0);
83 }
b368969c 84 iNumArgs = (int)pMsg->getFieldAsUInt16(VID_NUM_ARGS);
5c5c7111
VK
85 if (iNumArgs > 32)
86 iNumArgs = 32;
87 for(i = 0; i < iNumArgs; i++)
b368969c 88 pszArgList[i] = pMsg->getFieldAsString(VID_EVENT_ARG_BASE + i);
5c5c7111 89 DbgPrintf(3, _T("Event from trap: %d"), dwEventCode);
5039dede 90
5c5c7111 91 szFormat[iNumArgs] = 0;
c42b4551 92 PostEvent(dwEventCode, pNode->getId(), (iNumArgs > 0) ? szFormat : NULL,
5c5c7111
VK
93 pszArgList[0], pszArgList[1], pszArgList[2], pszArgList[3],
94 pszArgList[4], pszArgList[5], pszArgList[6], pszArgList[7],
95 pszArgList[8], pszArgList[9], pszArgList[10], pszArgList[11],
96 pszArgList[12], pszArgList[13], pszArgList[14], pszArgList[15],
97 pszArgList[16], pszArgList[17], pszArgList[18], pszArgList[19],
98 pszArgList[20], pszArgList[21], pszArgList[22], pszArgList[23],
99 pszArgList[24], pszArgList[25], pszArgList[26], pszArgList[27],
100 pszArgList[28], pszArgList[29], pszArgList[30], pszArgList[31]);
9fa031cd 101
5c5c7111
VK
102 // Cleanup
103 for(i = 0; i < iNumArgs; i++)
104 free(pszArgList[i]);
105 }
106 }
107 else
108 {
c42b4551 109 DbgPrintf(3, _T("AgentConnectionEx::onTrap(): node %s [%d] in in UNMANAGED state - trap ignored"), pNode->getName(), pNode->getId());
5c5c7111 110 }
5039dede
AK
111 }
112 else
113 {
c11eee9b 114 DbgPrintf(3, _T("AgentConnectionEx::onTrap(): Cannot find node for IP address %s"), getIpAddr().toString(szBuffer));
5039dede
AK
115 }
116}
45d84f8a 117
685508a7
VK
118/**
119 * Incoming syslog message processor
120 */
121void AgentConnectionEx::onSyslogMessage(NXCPMessage *msg)
122{
123 TCHAR buffer[64];
124 nxlog_debug(3, _T("AgentConnectionEx::onSyslogMessage(): Received message from agent at %s, node ID %d"), getIpAddr().toString(buffer), m_nodeId);
125
126 UINT32 zoneId = msg->getFieldAsUInt32(VID_ZONE_ID);
127 Node *node = NULL;
128 if (m_nodeId != 0)
129 node = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
130 if (node == NULL)
9278a2b9 131 node = FindNodeByIP(zoneId, getIpAddr());
685508a7
VK
132 if (node != NULL)
133 {
134 // Check for duplicate messages - only accept messages with ID
135 // higher than last received
136 if (node->checkSyslogMessageId(msg->getFieldAsUInt64(VID_REQUEST_ID)))
137 {
138 int msgLen = msg->getFieldAsInt32(VID_MESSAGE_LENGTH);
139 if (msgLen < 2048)
140 {
141 char message[2048];
142 msg->getFieldAsBinary(VID_MESSAGE, (BYTE *)message, msgLen + 1);
29b5c197 143 QueueProxiedSyslogMessage(msg->getFieldAsInetAddress(VID_IP_ADDRESS), zoneId,
685508a7
VK
144 msg->getFieldAsTime(VID_TIMESTAMP), message, msgLen);
145 }
146 }
147 else
148 {
149 nxlog_debug(5, _T("AgentConnectionEx::onSyslogMessage(): message ID is invalid (node %s [%d])"), node->getName(), node->getId());
150 }
151 }
152 else
153 {
154 nxlog_debug(5, _T("AgentConnectionEx::onSyslogMessage(): Cannot find node for IP address %s"), getIpAddr().toString(buffer));
155 }
156}
157
d1c1c522
VK
158/**
159 * Handler for data push
160 */
b368969c 161void AgentConnectionEx::onDataPush(NXCPMessage *msg)
f480bdd4 162{
1693f955
VK
163 if (g_flags & AF_SHUTDOWN)
164 return;
f480bdd4 165
1693f955 166 TCHAR name[MAX_PARAM_NAME], value[MAX_RESULT_LENGTH];
b368969c
VK
167 msg->getFieldAsString(VID_NAME, name, MAX_PARAM_NAME);
168 msg->getFieldAsString(VID_VALUE, value, MAX_RESULT_LENGTH);
f480bdd4 169
e3ee1478 170 Node *sender = NULL;
42a3be4f
VK
171 if (m_nodeId != 0)
172 sender = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
173 if (sender == NULL)
6fbaa926 174 sender = FindNodeByIP(0, getIpAddr());
42a3be4f 175
4e46505f 176 if (sender != NULL)
f480bdd4 177 {
42a3be4f
VK
178 // Check for duplicate data requests - only accept requests with ID
179 // higher than last received
180 // agents prior to 1.2.10 will not send request id
181 // we should accept data in that case to maintain compatibility
182 bool acceptRequest;
b368969c 183 QWORD requestId = msg->getFieldAsUInt64(VID_REQUEST_ID);
42a3be4f
VK
184 if (requestId != 0)
185 {
186 acceptRequest = sender->checkAgentPushRequestId(requestId);
187 DbgPrintf(5, _T("AgentConnectionEx::onDataPush(): requestId is%s valid"), acceptRequest ? _T("") : _T(" not"));
188 }
189 else
190 {
191 acceptRequest = true;
192 DbgPrintf(5, _T("AgentConnectionEx::onDataPush(): request ID not provided"));
193 }
194
195 if (acceptRequest)
196 {
197 Node *target;
b368969c 198 UINT32 objectId = msg->getFieldAsUInt32(VID_OBJECT_ID);
42a3be4f 199 if (objectId != 0)
4e46505f 200 {
42a3be4f
VK
201 // push on behalf of other node
202 target = (Node *)FindObjectById(objectId, OBJECT_NODE);
203 if (target != NULL)
4e46505f 204 {
c42b4551 205 if (target->isTrustedNode(sender->getId()))
42a3be4f 206 {
c42b4551 207 DbgPrintf(5, _T("%s: agent data push: target set to %s [%d]"), sender->getName(), target->getName(), target->getId());
42a3be4f
VK
208 }
209 else
210 {
c42b4551 211 DbgPrintf(5, _T("%s: agent data push: not in trusted node list for target %s [%d]"), sender->getName(), target->getName(), target->getId());
42a3be4f
VK
212 target = NULL;
213 }
4e46505f
VK
214 }
215 }
42a3be4f
VK
216 else
217 {
218 target = sender;
219 }
4e46505f 220
42a3be4f
VK
221 if (target != NULL)
222 {
c42b4551 223 DbgPrintf(5, _T("%s: agent data push: %s=%s"), target->getName(), name, value);
42a3be4f
VK
224 DCObject *dci = target->getDCObjectByName(name);
225 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM) && (dci->getDataSource() == DS_PUSH_AGENT) && (dci->getStatus() == ITEM_STATUS_ACTIVE))
226 {
c42b4551 227 DbgPrintf(5, _T("%s: agent data push: found DCI %d"), target->getName(), dci->getId());
b60584cf
VK
228 time_t t = msg->getFieldAsTime(VID_TIMESTAMP);
229 if (t == 0)
230 t = time(NULL);
42a3be4f 231 target->processNewDCValue(dci, t, value);
b60584cf
VK
232 if (t > dci->getLastPollTime())
233 dci->setLastPollTime(t);
42a3be4f
VK
234 }
235 else
236 {
c42b4551 237 DbgPrintf(5, _T("%s: agent data push: DCI not found for %s"), target->getName(), name);
42a3be4f
VK
238 }
239 }
240 else
241 {
c42b4551 242 DbgPrintf(5, _T("%s: agent data push: target node not found or not accessible"), sender->getName());
42a3be4f 243 }
4e46505f 244 }
f480bdd4
VK
245 }
246}
247
af21affe
VK
248/**
249 * Print message.
250 */
251void AgentConnectionEx::printMsg(const TCHAR *format, ...)
252{
253 va_list args;
af21affe 254 va_start(args, format);
2df047f4 255 nxlog_debug2(6, format, args);
af21affe
VK
256 va_end(args);
257}
258
1693f955
VK
259/**
260 * Cancel unknown file monitoring
261 */
262static void CancelUnknownFileMonitoring(Node *object,TCHAR *remoteFile)
a07511b5 263{
264 DbgPrintf(6, _T("AgentConnectionEx::onFileMonitoringData: unknown subscription will be canceled."));
265 AgentConnection *conn = object->createAgentConnection();
266 if(conn != NULL)
267 {
268 NXCPMessage request;
269 request.setId(conn->generateRequestId());
270 request.setCode(CMD_CANCEL_FILE_MONITORING);
271 request.setField(VID_FILE_NAME, remoteFile);
272 request.setField(VID_OBJECT_ID, object->getId());
273 NXCPMessage* response = conn->customRequest(&request);
274 delete response;
1693f955 275 conn->decRefCount();
a07511b5 276 }
a07511b5 277}
278
76b4edb5 279/**
9fa031cd 280 * Recieve file monitoring information and resend to all required user sessions
281 */
b368969c 282void AgentConnectionEx::onFileMonitoringData(NXCPMessage *pMsg)
9fa031cd 283{
489b117b 284 Node *object = NULL;
9fa031cd 285 if (m_nodeId != 0)
286 object = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
287 if (object != NULL)
288 {
18b237f7 289 TCHAR remoteFile[MAX_PATH];
b368969c 290 pMsg->getFieldAsString(VID_FILE_NAME, remoteFile, MAX_PATH);
c42b4551
VK
291 ObjectArray<ClientSession>* result = g_monitoringList.findClientByFNameAndNodeID(remoteFile, object->getId());
292 DbgPrintf(6, _T("AgentConnectionEx::onFileMonitoringData: found %d sessions for remote file %s on node %s [%d]"), result->size(), remoteFile, object->getName(), object->getId());
a07511b5 293 int validSessionCount = result->size();
9fa031cd 294 for(int i = 0; i < result->size(); i++)
295 {
a07511b5 296 if(!result->get(i)->sendMessage(pMsg))
297 {
298 MONITORED_FILE file;
299 _tcsncpy(file.fileName, remoteFile, MAX_PATH);
300 file.nodeID = m_nodeId;
301 file.session = result->get(i);
302 g_monitoringList.removeMonitoringFile(&file);
303 validSessionCount--;
304
1693f955
VK
305 if (validSessionCount == 0)
306 CancelUnknownFileMonitoring(object, remoteFile);
a07511b5 307 }
05e3ba32 308 }
1693f955 309 if (result->size() == 0)
05e3ba32 310 {
1693f955 311 CancelUnknownFileMonitoring(object, remoteFile);
9fa031cd 312 }
ece85e30 313 delete result;
9fa031cd 314 }
315 else
316 {
f9f79a93 317 g_monitoringList.removeDisconnectedNode(m_nodeId);
18b237f7 318 DbgPrintf(6, _T("AgentConnectionEx::onFileMonitoringData: node object not found"));
9fa031cd 319 }
320}
321
5bbb1485 322/**
323 * Ask modules if they can procress custom message
324 */
325bool AgentConnectionEx::processCustomMessage(NXCPMessage *msg)
326{
ac1a1de4 327 TCHAR buffer[128];
d7af297b 328 DbgPrintf(6, _T("AgentConnectionEx::processCustomMessage: processing message %s ID %d"),
ac1a1de4 329 NXCPMessageCodeName(msg->getCode(), buffer), msg->getId());
5bbb1485 330
ac1a1de4
VK
331 for(UINT32 i = 0; i < g_dwNumModules; i++)
332 {
333 if (g_pModuleList[i].pfOnAgentMessage != NULL)
334 {
335 if (g_pModuleList[i].pfOnAgentMessage(msg, m_nodeId))
336 return true; // accepted by module
337 }
338 }
5bbb1485 339 return false;
340}
341
cce2f2ef
VK
342/**
343 * Create SNMP proxy transport for sending trap response
344 */
345static SNMP_ProxyTransport *CreateSNMPProxyTransport(AgentConnectionEx *conn, Node *originNode, const InetAddress& originAddr, UINT16 port)
346{
347 conn->incRefCount();
348 SNMP_ProxyTransport *snmpTransport = new SNMP_ProxyTransport(conn, originAddr, port);
349 if (originNode != NULL)
350 {
351 snmpTransport->setSecurityContext(originNode->getSnmpSecurityContext());
352 }
353 return snmpTransport;
354}
355
489b117b 356/**
357 * Recieve trap sent throught proxy agent
358 */
b368969c 359void AgentConnectionEx::onSnmpTrap(NXCPMessage *msg)
489b117b 360{
361 Node *proxyNode = NULL;
362 TCHAR ipStringBuffer[4096];
363
364 static BYTE engineId[] = { 0x80, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00 };
365 SNMP_Engine localEngine(engineId, 12);
366
d7af297b 367 DbgPrintf(3, _T("AgentConnectionEx::onSnmpTrap(): Received SNMP trap message from agent at %s, node ID %d"),
ac1a1de4
VK
368 getIpAddr().toString(ipStringBuffer), m_nodeId);
369
489b117b 370 if (m_nodeId != 0)
371 proxyNode = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
372 if (proxyNode != NULL)
373 {
374 // Check for duplicate traps - only accept traps with ID
375 // higher than last received
376 bool acceptTrap;
b368969c 377 UINT32 trapId = msg->getId();
489b117b 378 if (trapId != 0)
379 {
380 acceptTrap = proxyNode->checkSNMPTrapId(trapId);
381 DbgPrintf(5, _T("AgentConnectionEx::onSnmpTrap(): SNMP trapID is%s valid"), acceptTrap ? _T("") : _T(" not"));
382 }
383 else
384 {
385 acceptTrap = false;
386 DbgPrintf(5, _T("AgentConnectionEx::onSnmpTrap(): SNMP trap ID not provided"));
387 }
388
389 if (acceptTrap)
390 {
c75e9ee4 391 InetAddress originSenderIP = msg->getFieldAsInetAddress(VID_IP_ADDRESS);
b368969c 392 UINT32 pduLenght = msg->getFieldAsUInt32(VID_PDU_SIZE);
489b117b 393 BYTE *pduBytes = (BYTE*)malloc(pduLenght);
b368969c 394 msg->getFieldAsBinary(VID_PDU, pduBytes, pduLenght);
3f635e1b
VK
395 UINT32 zoneId = IsZoningEnabled() ? msg->getFieldAsUInt32(VID_ZONE_ID) : 0;
396 Node *originNode = FindNodeByIP(zoneId, originSenderIP);
cce2f2ef 397 if ((originNode != NULL) || ConfigReadInt(_T("LogAllSNMPTraps"), FALSE))
489b117b 398 {
489b117b 399 SNMP_PDU *pdu = new SNMP_PDU;
aef85265 400 if (pdu->parse(pduBytes, pduLenght, (originNode != NULL) ? originNode->getSnmpSecurityContext() : NULL, true))
489b117b 401 {
402 DbgPrintf(6, _T("SNMPTrapReceiver: received PDU of type %d"), pdu->getCommand());
403 if ((pdu->getCommand() == SNMP_TRAP) || (pdu->getCommand() == SNMP_INFORM_REQUEST))
404 {
cce2f2ef
VK
405 bool isInformRequest = (pdu->getCommand() == SNMP_INFORM_REQUEST);
406 SNMP_ProxyTransport *snmpTransport = isInformRequest ? CreateSNMPProxyTransport(this, originNode, originSenderIP, msg->getFieldAsUInt16(VID_PORT)) : NULL;
489b117b 407 if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_INFORM_REQUEST))
408 {
cce2f2ef 409 SNMP_SecurityContext *context = snmpTransport->getSecurityContext();
489b117b 410 context->setAuthoritativeEngine(localEngine);
411 }
3f635e1b 412 ProcessTrap(pdu, originSenderIP, zoneId, msg->getFieldAsUInt16(VID_PORT), snmpTransport, &localEngine, isInformRequest);
cce2f2ef 413 delete snmpTransport;
489b117b 414 }
415 else if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_GET_REQUEST) && (pdu->getAuthoritativeEngine().getIdLen() == 0))
416 {
417 // Engine ID discovery
418 DbgPrintf(6, _T("SNMPTrapReceiver: EngineId discovery"));
419
cce2f2ef
VK
420 SNMP_ProxyTransport *snmpTransport = CreateSNMPProxyTransport(this, originNode, originSenderIP, msg->getFieldAsUInt16(VID_PORT));
421
489b117b 422 SNMP_PDU *response = new SNMP_PDU(SNMP_REPORT, pdu->getRequestId(), pdu->getVersion());
423 response->setReportable(false);
424 response->setMessageId(pdu->getMessageId());
425 response->setContextEngineId(localEngine.getId(), localEngine.getIdLen());
426
427 SNMP_Variable *var = new SNMP_Variable(_T(".1.3.6.1.6.3.15.1.1.4.0"));
428 var->setValueFromString(ASN_INTEGER, _T("2"));
429 response->bindVariable(var);
430
431 SNMP_SecurityContext *context = new SNMP_SecurityContext();
432 localEngine.setTime((int)time(NULL));
433 context->setAuthoritativeEngine(localEngine);
434 context->setSecurityModel(SNMP_SECURITY_MODEL_USM);
435 context->setAuthMethod(SNMP_AUTH_NONE);
436 context->setPrivMethod(SNMP_ENCRYPT_NONE);
cce2f2ef 437 snmpTransport->setSecurityContext(context);
489b117b 438
cce2f2ef
VK
439 snmpTransport->setWaitForResponse(false);
440 snmpTransport->sendMessage(response);
489b117b 441 delete response;
cce2f2ef 442 delete snmpTransport;
489b117b 443 }
444 else if (pdu->getCommand() == SNMP_REPORT)
445 {
9ceab287 446 DbgPrintf(6, _T("AgentConnectionEx::onSnmpTrap(): REPORT PDU with error %s"), (const TCHAR *)pdu->getVariable(0)->getName().toString());
489b117b 447 }
448 delete pdu;
449 }
450 else if (pdu->getCommand() == SNMP_REPORT)
451 {
9ceab287 452 DbgPrintf(6, _T("AgentConnectionEx::onSnmpTrap(): REPORT PDU with error %s"), (const TCHAR *)pdu->getVariable(0)->getName().toString());
489b117b 453 }
454 }
455 else
456 {
c75e9ee4 457 DbgPrintf(3, _T("AgentConnectionEx::onSnmpTrap(): cannot find origin node with IP %s and not accepting traps from unknown sources"), originSenderIP.toString(ipStringBuffer));
489b117b 458 }
459 }
460 }
461 else
462 {
c11eee9b 463 DbgPrintf(3, _T("AgentConnectionEx::onSnmpTrap(): Cannot find node for IP address %s"), getIpAddr().toString(ipStringBuffer));
489b117b 464 }
465}
466
d1c1c522
VK
467/**
468 * Deploy policy to agent
469 */
967893bb 470UINT32 AgentConnectionEx::deployPolicy(AgentPolicy *policy)
45d84f8a 471{
967893bb 472 UINT32 rqId, rcc;
b368969c 473 NXCPMessage msg(getProtocolVersion());
45d84f8a
VK
474
475 rqId = generateRequestId();
b368969c
VK
476 msg.setId(rqId);
477 msg.setCode(CMD_DEPLOY_AGENT_POLICY);
8051849b
VK
478 if (policy->createDeploymentMessage(&msg))
479 {
7c521895 480 if (sendMessage(&msg))
8051849b 481 {
7c521895 482 rcc = waitForRCC(rqId, getCommandTimeout());
8051849b
VK
483 }
484 else
485 {
486 rcc = ERR_CONNECTION_BROKEN;
487 }
488 }
489 else
490 {
491 rcc = ERR_INTERNAL_ERROR;
492 }
45d84f8a
VK
493 return rcc;
494}
93599cfd 495
d1c1c522
VK
496/**
497 * Uninstall policy from agent
498 */
967893bb 499UINT32 AgentConnectionEx::uninstallPolicy(AgentPolicy *policy)
93599cfd 500{
967893bb 501 UINT32 rqId, rcc;
b368969c 502 NXCPMessage msg(getProtocolVersion());
93599cfd
VK
503
504 rqId = generateRequestId();
b368969c
VK
505 msg.setId(rqId);
506 msg.setCode(CMD_UNINSTALL_AGENT_POLICY);
93599cfd
VK
507 if (policy->createUninstallMessage(&msg))
508 {
7c521895 509 if (sendMessage(&msg))
93599cfd 510 {
7c521895 511 rcc = waitForRCC(rqId, getCommandTimeout());
93599cfd
VK
512 }
513 else
514 {
515 rcc = ERR_CONNECTION_BROKEN;
516 }
517 }
518 else
519 {
520 rcc = ERR_INTERNAL_ERROR;
521 }
522 return rcc;
523}
6fbaa926
VK
524
525/**
526 * Process collected data information (for DCI with agent-side cache)
527 */
02d936bd 528UINT32 AgentConnectionEx::processCollectedData(NXCPMessage *msg)
6fbaa926 529{
1693f955
VK
530 if (g_flags & AF_SHUTDOWN)
531 return ERR_INTERNAL_ERROR;
532
02d936bd
VK
533 if (m_nodeId == 0)
534 {
535 DbgPrintf(5, _T("AgentConnectionEx::processCollectedData: node ID is 0 for agent session"));
536 return ERR_INTERNAL_ERROR;
537 }
538
539 Node *node = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
540 if (node == NULL)
541 {
542 DbgPrintf(5, _T("AgentConnectionEx::processCollectedData: cannot find node object (node ID = %d)"), m_nodeId);
543 return ERR_INTERNAL_ERROR;
544 }
545
546 int origin = msg->getFieldAsInt16(VID_DCI_SOURCE_TYPE);
547 if ((origin != DS_NATIVE_AGENT) && (origin != DS_SNMP_AGENT))
548 {
549 DbgPrintf(5, _T("AgentConnectionEx::processCollectedData: unsupported data source type %d"), origin);
550 return ERR_INTERNAL_ERROR;
551 }
552
46e2b370
VK
553 DataCollectionTarget *target;
554 uuid targetId = msg->getFieldAsGUID(VID_NODE_ID);
555 if (!targetId.isNull())
02d936bd 556 {
46e2b370
VK
557 NetObj *object = FindObjectByGUID(targetId, -1);
558 if (object == NULL)
02d936bd
VK
559 {
560 TCHAR buffer[64];
46e2b370 561 nxlog_debug(5, _T("AgentConnectionEx::processCollectedData: cannot find target node with GUID %s"), targetId.toString(buffer));
02d936bd
VK
562 return ERR_INTERNAL_ERROR;
563 }
46e2b370
VK
564 if (!object->isDataCollectionTarget())
565 {
566 TCHAR buffer[64];
567 nxlog_debug(5, _T("AgentConnectionEx::processCollectedData: object with GUID %s is not a data collection target"), targetId.toString(buffer));
568 return ERR_INTERNAL_ERROR;
569 }
570 target = (DataCollectionTarget *)object;
571 }
572 else
573 {
574 target = node;
02d936bd
VK
575 }
576
577 UINT32 dciId = msg->getFieldAsUInt32(VID_DCI_ID);
46e2b370 578 DCObject *dcObject = target->getDCObjectById(dciId);
02d936bd
VK
579 if (dcObject == NULL)
580 {
46e2b370
VK
581 nxlog_debug(5, _T("AgentConnectionEx::processCollectedData: cannot find DCI with ID %d on object %s [%d]"),
582 dciId, target->getName(), target->getId());
02d936bd
VK
583 return ERR_INTERNAL_ERROR;
584 }
585
586 int type = msg->getFieldAsInt16(VID_DCOBJECT_TYPE);
587 if ((dcObject->getType() != type) || (dcObject->getDataSource() != origin) || (dcObject->getAgentCacheMode() != AGENT_CACHE_ON))
588 {
46e2b370
VK
589 nxlog_debug(5, _T("AgentConnectionEx::processCollectedData: DCI %s [%d] on object %s [%d] configuration mismatch"),
590 dcObject->getName(), dciId, target->getName(), target->getId());
02d936bd
VK
591 return ERR_INTERNAL_ERROR;
592 }
593
df94243f 594 time_t t = msg->getFieldAsTime(VID_TIMESTAMP);
595 UINT32 status = msg->getFieldAsUInt32(VID_STATUS);
596 bool success = true;
597
02d936bd
VK
598 void *value;
599 switch(type)
600 {
601 case DCO_TYPE_ITEM:
602 value = msg->getFieldAsString(VID_VALUE);
603 break;
604 case DCO_TYPE_LIST:
605 value = new StringList();
606 break;
607 case DCO_TYPE_TABLE:
608 value = new Table(msg);
609 break;
610 default:
46e2b370
VK
611 nxlog_debug(5, _T("AgentConnectionEx::processCollectedData: invalid type %d of DCI %s [%d] on object %s [%d]"),
612 type, dcObject->getName(), dciId, target->getName(), target->getId());
02d936bd
VK
613 return ERR_INTERNAL_ERROR;
614 }
46e2b370
VK
615 nxlog_debug(7, _T("AgentConnectionEx::processCollectedData: processing DCI %s [%d] (type=%d) (status=%d) on object %s [%d]"),
616 dcObject->getName(), dciId, type, status, target->getName(), target->getId());
02d936bd 617
df94243f 618 switch(status)
619 {
620 case ERR_SUCCESS:
621 {
622 if (dcObject->getStatus() == ITEM_STATUS_NOT_SUPPORTED)
623 dcObject->setStatus(ITEM_STATUS_ACTIVE, true);
46e2b370 624 success = target->processNewDCValue(dcObject, t, value);
df94243f 625 if (t > dcObject->getLastPollTime())
626 dcObject->setLastPollTime(t);
627 break;
628 }
629 case ERR_UNKNOWN_PARAMETER:
630 if (dcObject->getStatus() == ITEM_STATUS_NOT_SUPPORTED)
631 dcObject->setStatus(ITEM_STATUS_ACTIVE, true);
632 dcObject->processNewError(false, t);
633 break;
634 case ERR_NO_SUCH_INSTANCE:
a8164c20 635 if (dcObject->getStatus() == ITEM_STATUS_NOT_SUPPORTED)
636 dcObject->setStatus(ITEM_STATUS_ACTIVE, true);
df94243f 637 dcObject->processNewError(true, t);
638 break;
639 case ERR_INTERNAL_ERROR:
640 dcObject->processNewError(true, t);
641 break;
642 }
02d936bd
VK
643
644 switch(type)
645 {
646 case DCO_TYPE_ITEM:
647 free(value);
648 break;
649 case DCO_TYPE_LIST:
650 delete (StringList *)value;
651 break;
02d936bd 652 }
366440e8 653
02d936bd 654 return success ? ERR_SUCCESS : ERR_INTERNAL_ERROR;
6fbaa926 655}
a1273b42
VK
656
657/**
658 * Process collected data information in bulk mode (for DCI with agent-side cache)
659 */
660UINT32 AgentConnectionEx::processBulkCollectedData(NXCPMessage *request, NXCPMessage *response)
661{
662 if (g_flags & AF_SHUTDOWN)
663 return ERR_INTERNAL_ERROR;
664
665 if (m_nodeId == 0)
666 {
667 DbgPrintf(5, _T("AgentConnectionEx::processBulkCollectedData: node ID is 0 for agent session"));
668 return ERR_INTERNAL_ERROR;
669 }
670
671 Node *node = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
672 if (node == NULL)
673 {
674 DbgPrintf(5, _T("AgentConnectionEx::processBulkCollectedData: cannot find node object (node ID = %d)"), m_nodeId);
675 return ERR_INTERNAL_ERROR;
676 }
677
678 int count = request->getFieldAsInt16(VID_NUM_ELEMENTS);
9cf1b53c
VK
679 if (count > MAX_BULK_DATA_BLOCK_SIZE)
680 count = MAX_BULK_DATA_BLOCK_SIZE;
a1273b42
VK
681 DbgPrintf(5, _T("AgentConnectionEx::processBulkCollectedData: %d elements from node %s [%d]"), count, node->getName(), node->getId());
682
9cf1b53c
VK
683 BYTE status[MAX_BULK_DATA_BLOCK_SIZE];
684 memset(status, 0, MAX_BULK_DATA_BLOCK_SIZE);
a1273b42
VK
685 UINT32 fieldId = VID_ELEMENT_LIST_BASE;
686 for(int i = 0; i < count; i++, fieldId += 10)
687 {
688 int origin = request->getFieldAsInt16(fieldId + 1);
689 if ((origin != DS_NATIVE_AGENT) && (origin != DS_SNMP_AGENT))
690 {
46e2b370 691 nxlog_debug(5, _T("AgentConnectionEx::processBulkCollectedData: unsupported data source type %d (element %d)"), origin, i);
a1273b42
VK
692 status[i] = BULK_DATA_REC_FAILURE;
693 continue;
694 }
695
46e2b370
VK
696 DataCollectionTarget *target;
697 uuid targetId = request->getFieldAsGUID(fieldId + 3);
698 if (!targetId.isNull())
a1273b42 699 {
46e2b370
VK
700 NetObj *object = FindObjectByGUID(targetId, -1);
701 if (object == NULL)
a1273b42
VK
702 {
703 TCHAR buffer[64];
46e2b370
VK
704 nxlog_debug(5, _T("AgentConnectionEx::processBulkCollectedData: cannot find target object with GUID %s (element %d)"),
705 targetId.toString(buffer), i);
a1273b42
VK
706 status[i] = BULK_DATA_REC_FAILURE;
707 continue;
708 }
46e2b370
VK
709 if (!object->isDataCollectionTarget())
710 {
711 TCHAR buffer[64];
712 nxlog_debug(5, _T("AgentConnectionEx::processBulkCollectedData: object with GUID %s (element %d) is not a data collection target"),
713 targetId.toString(buffer), i);
714 status[i] = BULK_DATA_REC_FAILURE;
715 continue;
716 }
717 target = (DataCollectionTarget *)object;
718 }
719 else
720 {
721 target = node;
a1273b42
VK
722 }
723
724 UINT32 dciId = request->getFieldAsUInt32(fieldId);
46e2b370 725 DCObject *dcObject = target->getDCObjectById(dciId);
a1273b42
VK
726 if (dcObject == NULL)
727 {
46e2b370
VK
728 nxlog_debug(5, _T("AgentConnectionEx::processBulkCollectedData: cannot find DCI with ID %d on object %s [%d] (element %d)"),
729 dciId, target->getName(), target->getId(), i);
a1273b42
VK
730 status[i] = BULK_DATA_REC_FAILURE;
731 continue;
732 }
733
734 int type = request->getFieldAsInt16(fieldId + 2);
735 if ((type != DCO_TYPE_ITEM) || (dcObject->getType() != type) || (dcObject->getDataSource() != origin) || (dcObject->getAgentCacheMode() != AGENT_CACHE_ON))
736 {
46e2b370
VK
737 nxlog_debug(5, _T("AgentConnectionEx::processBulkCollectedData: DCI %s [%d] on object %s [%d] configuration mismatch (element %d)"),
738 dcObject->getName(), dciId, target->getName(), target->getId(), i);
a1273b42
VK
739 status[i] = BULK_DATA_REC_FAILURE;
740 continue;
741 }
742
743 void *value = request->getFieldAsString(fieldId + 5);
df94243f 744 UINT32 status_code = request->getFieldAsUInt32(fieldId + 6);
46e2b370
VK
745 nxlog_debug(7, _T("AgentConnectionEx::processBulkCollectedData: processing DCI %s [%d] (type=%d) (status=%d) on object %s [%d] (element %d)"),
746 dcObject->getName(), dciId, type, status, target->getName(), target->getId(), i);
a1273b42 747 time_t t = request->getFieldAsTime(fieldId + 4);
df94243f 748 bool success = true;
749
750 switch(status_code)
751 {
752 case ERR_SUCCESS:
753 {
754 if (dcObject->getStatus() == ITEM_STATUS_NOT_SUPPORTED)
755 dcObject->setStatus(ITEM_STATUS_ACTIVE, true);
46e2b370 756 success = target->processNewDCValue(dcObject, t, value);
df94243f 757 if (t > dcObject->getLastPollTime())
758 dcObject->setLastPollTime(t);
759 break;
760 }
761 case ERR_UNKNOWN_PARAMETER:
762 if (dcObject->getStatus() == ITEM_STATUS_NOT_SUPPORTED)
763 dcObject->setStatus(ITEM_STATUS_ACTIVE, true);
764 dcObject->processNewError(false, t);
765 break;
766 case ERR_NO_SUCH_INSTANCE:
a8164c20 767 if (dcObject->getStatus() == ITEM_STATUS_NOT_SUPPORTED)
768 dcObject->setStatus(ITEM_STATUS_ACTIVE, true);
df94243f 769 dcObject->processNewError(true, t);
770 break;
771 case ERR_INTERNAL_ERROR:
772 dcObject->processNewError(true, t);
773 break;
774 }
a1273b42 775
df94243f 776
777 status[i] = success ? BULK_DATA_REC_SUCCESS : BULK_DATA_REC_FAILURE;
a1273b42
VK
778 free(value);
779 }
780
9cf1b53c 781 response->setField(VID_STATUS, status, count);
a1273b42
VK
782 return ERR_SUCCESS;
783}