additional agent metrics for self-monitoring (SNMP proxy and syslog proxy stats)
[public/netxms.git] / src / agent / core / snmpproxy.cpp
CommitLineData
489b117b 1/*
5039dede 2** NetXMS multiplatform core agent
845303de 3** Copyright (C) 2003-2015 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: snmpproxy.cpp
20**
21**/
22
23#include "nxagentd.h"
24
489b117b 25/**
845303de 26 * SNMP buffer size
489b117b 27 */
5039dede
AK
28#define SNMP_BUFFER_SIZE 65536
29
786773f7
VK
30/**
31 * SNMP proxy stats
32 */
33static UINT64 s_serverRequests = 0;
34static UINT64 s_snmpRequests = 0;
35static UINT64 s_snmpResponses = 0;
36
37/**
38 * Handler for SNMP proxy information parameters
39 */
40LONG H_SNMPProxyStats(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
41{
42 switch(*arg)
43 {
44 case 'R': // SNMP requests
45 ret_uint64(value, s_snmpRequests);
46 break;
47 case 'r': // SNMP responses
48 ret_uint64(value, s_snmpResponses);
49 break;
50 case 'S': // server requests
51 ret_uint64(value, s_serverRequests);
52 break;
53 default:
54 return SYSINFO_RC_UNSUPPORTED;
55 }
56 return SYSINFO_RC_SUCCESS;
57}
58
489b117b 59/**
60 * Read PDU from network
61 */
967893bb 62static BOOL ReadPDU(SOCKET hSocket, BYTE *pdu, UINT32 *pdwSize)
5039dede
AK
63{
64 fd_set rdfs;
65 struct timeval tv;
66 int nBytes;
67#ifndef _WIN32
68 int iErr;
967893bb 69 UINT32 dwTimeout = g_dwSNMPTimeout;
5039dede
AK
70 QWORD qwTime;
71
72 do
73 {
74#endif
75 FD_ZERO(&rdfs);
76 FD_SET(hSocket, &rdfs);
77#ifdef _WIN32
78 tv.tv_sec = g_dwSNMPTimeout / 1000;
79 tv.tv_usec = (g_dwSNMPTimeout % 1000) * 1000;
80#else
81 tv.tv_sec = dwTimeout / 1000;
82 tv.tv_usec = (dwTimeout % 1000) * 1000;
83#endif
84#ifdef _WIN32
85 if (select(SELECT_NFDS(hSocket + 1), &rdfs, NULL, NULL, &tv) <= 0)
86 return FALSE;
87#else
88 qwTime = GetCurrentTimeMs();
89 if ((iErr = select(SELECT_NFDS(hSocket + 1), &rdfs, NULL, NULL, &tv)) <= 0)
90 {
91 if (((iErr == -1) && (errno != EINTR)) ||
92 (iErr == 0))
93 {
94 return FALSE;
95 }
96 }
97 qwTime = GetCurrentTimeMs() - qwTime; // Elapsed time
967893bb 98 dwTimeout -= min(((UINT32)qwTime), dwTimeout);
5039dede
AK
99 } while(iErr < 0);
100#endif
101
102 nBytes = recv(hSocket, (char *)pdu, SNMP_BUFFER_SIZE, 0);
103 if (nBytes >= 0)
104 {
105 *pdwSize = nBytes;
106 return TRUE;
107 }
108 return FALSE;
109}
110
489b117b 111/**
112 * Send SNMP request to target, receive response, and send it to server
113 */
83191808 114void CommSession::proxySnmpRequest(NXCPMessage *request)
5039dede 115{
83191808
VK
116 NXCPMessage response;
117 response.setCode(CMD_REQUEST_COMPLETED);
118 response.setId(request->getId());
119
786773f7 120 s_serverRequests++;
83191808 121 UINT32 dwSizeIn = request->getFieldAsUInt32(VID_PDU_SIZE);
5039dede
AK
122 if (dwSizeIn > 0)
123 {
845303de 124 BYTE *pduIn = (BYTE *)malloc(dwSizeIn);
5039dede
AK
125 if (pduIn != NULL)
126 {
83191808 127 request->getFieldAsBinary(VID_PDU, pduIn, dwSizeIn);
5039dede 128
845303de 129 SOCKET hSocket = socket(AF_INET, SOCK_DGRAM, 0);
4c0c75c7 130 if (hSocket != INVALID_SOCKET)
5039dede 131 {
83191808 132 InetAddress addr = request->getFieldAsInetAddress(VID_IP_ADDRESS);
845303de 133 SockAddrBuffer sa;
83191808 134 addr.fillSockAddr(&sa, request->getFieldAsUInt16(VID_PORT));
845303de 135 if (connect(hSocket, (struct sockaddr *)&sa, SA_LEN((struct sockaddr *)&sa)) != -1)
5039dede 136 {
845303de 137 BYTE *pduOut = (BYTE *)malloc(SNMP_BUFFER_SIZE);
5039dede
AK
138 if (pduOut != NULL)
139 {
845303de 140 int nRetries;
5039dede
AK
141 for(nRetries = 0; nRetries < 3; nRetries++)
142 {
143 if (send(hSocket, (char *)pduIn, dwSizeIn, 0) == (int)dwSizeIn)
144 {
786773f7 145 s_snmpRequests++;
845303de 146 UINT32 dwSizeOut;
5039dede
AK
147 if (ReadPDU(hSocket, pduOut, &dwSizeOut))
148 {
786773f7 149 s_snmpResponses++;
83191808
VK
150 response.setField(VID_PDU_SIZE, dwSizeOut);
151 response.setField(VID_PDU, pduOut, dwSizeOut);
5039dede
AK
152 break;
153 }
154 }
155 }
156 free(pduOut);
83191808 157 response.setField(VID_RCC, (nRetries == 3) ? ERR_REQUEST_TIMEOUT : ERR_SUCCESS);
5039dede
AK
158 }
159 else
160 {
83191808 161 response.setField(VID_RCC, ERR_OUT_OF_RESOURCES);
5039dede
AK
162 }
163 }
164 else
165 {
83191808 166 response.setField(VID_RCC, ERR_SOCKET_ERROR);
5039dede
AK
167 }
168 closesocket(hSocket);
169 }
170 else
171 {
83191808 172 response.setField(VID_RCC, ERR_SOCKET_ERROR);
5039dede
AK
173 }
174 free(pduIn);
175 }
176 else
177 {
83191808 178 response.setField(VID_RCC, ERR_OUT_OF_RESOURCES);
5039dede
AK
179 }
180 }
181 else
182 {
83191808 183 response.setField(VID_RCC, ERR_MALFORMED_COMMAND);
5039dede 184 }
83191808
VK
185 sendMessage(&response);
186 delete request;
8ea0475c 187 decRefCount();
5039dede 188}