additional agent metrics for self-monitoring (SNMP proxy and syslog proxy stats)
[public/netxms.git] / src / agent / core / snmpproxy.cpp
1 /*
2 ** NetXMS multiplatform core agent
3 ** Copyright (C) 2003-2015 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 ** File: snmpproxy.cpp
20 **
21 **/
22
23 #include "nxagentd.h"
24
25 /**
26 * SNMP buffer size
27 */
28 #define SNMP_BUFFER_SIZE 65536
29
30 /**
31 * SNMP proxy stats
32 */
33 static UINT64 s_serverRequests = 0;
34 static UINT64 s_snmpRequests = 0;
35 static UINT64 s_snmpResponses = 0;
36
37 /**
38 * Handler for SNMP proxy information parameters
39 */
40 LONG 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
59 /**
60 * Read PDU from network
61 */
62 static BOOL ReadPDU(SOCKET hSocket, BYTE *pdu, UINT32 *pdwSize)
63 {
64 fd_set rdfs;
65 struct timeval tv;
66 int nBytes;
67 #ifndef _WIN32
68 int iErr;
69 UINT32 dwTimeout = g_dwSNMPTimeout;
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
98 dwTimeout -= min(((UINT32)qwTime), dwTimeout);
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
111 /**
112 * Send SNMP request to target, receive response, and send it to server
113 */
114 void CommSession::proxySnmpRequest(NXCPMessage *request)
115 {
116 NXCPMessage response;
117 response.setCode(CMD_REQUEST_COMPLETED);
118 response.setId(request->getId());
119
120 s_serverRequests++;
121 UINT32 dwSizeIn = request->getFieldAsUInt32(VID_PDU_SIZE);
122 if (dwSizeIn > 0)
123 {
124 BYTE *pduIn = (BYTE *)malloc(dwSizeIn);
125 if (pduIn != NULL)
126 {
127 request->getFieldAsBinary(VID_PDU, pduIn, dwSizeIn);
128
129 SOCKET hSocket = socket(AF_INET, SOCK_DGRAM, 0);
130 if (hSocket != INVALID_SOCKET)
131 {
132 InetAddress addr = request->getFieldAsInetAddress(VID_IP_ADDRESS);
133 SockAddrBuffer sa;
134 addr.fillSockAddr(&sa, request->getFieldAsUInt16(VID_PORT));
135 if (connect(hSocket, (struct sockaddr *)&sa, SA_LEN((struct sockaddr *)&sa)) != -1)
136 {
137 BYTE *pduOut = (BYTE *)malloc(SNMP_BUFFER_SIZE);
138 if (pduOut != NULL)
139 {
140 int nRetries;
141 for(nRetries = 0; nRetries < 3; nRetries++)
142 {
143 if (send(hSocket, (char *)pduIn, dwSizeIn, 0) == (int)dwSizeIn)
144 {
145 s_snmpRequests++;
146 UINT32 dwSizeOut;
147 if (ReadPDU(hSocket, pduOut, &dwSizeOut))
148 {
149 s_snmpResponses++;
150 response.setField(VID_PDU_SIZE, dwSizeOut);
151 response.setField(VID_PDU, pduOut, dwSizeOut);
152 break;
153 }
154 }
155 }
156 free(pduOut);
157 response.setField(VID_RCC, (nRetries == 3) ? ERR_REQUEST_TIMEOUT : ERR_SUCCESS);
158 }
159 else
160 {
161 response.setField(VID_RCC, ERR_OUT_OF_RESOURCES);
162 }
163 }
164 else
165 {
166 response.setField(VID_RCC, ERR_SOCKET_ERROR);
167 }
168 closesocket(hSocket);
169 }
170 else
171 {
172 response.setField(VID_RCC, ERR_SOCKET_ERROR);
173 }
174 free(pduIn);
175 }
176 else
177 {
178 response.setField(VID_RCC, ERR_OUT_OF_RESOURCES);
179 }
180 }
181 else
182 {
183 response.setField(VID_RCC, ERR_MALFORMED_COMMAND);
184 }
185 sendMessage(&response);
186 delete request;
187 decRefCount();
188 }