1e6e34f765a63766bbe35d0a77f5030f67a23a7b
[public/netxms.git] / src / agent / core / snmpproxy.cpp
1 /* $Id: snmpproxy.cpp,v 1.4 2007-01-18 17:10:24 victor Exp $ */
2 /*
3 ** NetXMS multiplatform core agent
4 ** Copyright (C) 2003, 2004, 2005, 2006 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: snmpproxy.cpp
21 **
22 **/
23
24 #include "nxagentd.h"
25
26
27 //
28 // Constants
29 //
30
31 #define SNMP_BUFFER_SIZE 65536
32
33
34 //
35 // Read PDU from network
36 //
37
38 static BOOL ReadPDU(SOCKET hSocket, BYTE *pdu, DWORD *pdwSize)
39 {
40 fd_set rdfs;
41 struct timeval tv;
42 int nBytes;
43 #ifndef _WIN32
44 int iErr;
45 DWORD dwTimeout = g_dwSNMPTimeout;
46 QWORD qwTime;
47
48 do
49 {
50 #endif
51 FD_ZERO(&rdfs);
52 FD_SET(hSocket, &rdfs);
53 #ifdef _WIN32
54 tv.tv_sec = g_dwSNMPTimeout / 1000;
55 tv.tv_usec = (g_dwSNMPTimeout % 1000) * 1000;
56 #else
57 tv.tv_sec = dwTimeout / 1000;
58 tv.tv_usec = (dwTimeout % 1000) * 1000;
59 #endif
60 #ifdef _WIN32
61 if (select((int)(hSocket + 1), &rdfs, NULL, NULL, &tv) <= 0)
62 return FALSE;
63 #else
64 qwTime = GetCurrentTimeMs();
65 if ((iErr = select(hSocket + 1, &rdfs, NULL, NULL, &tv)) <= 0)
66 {
67 if (((iErr == -1) && (errno != EINTR)) ||
68 (iErr == 0))
69 {
70 return FALSE;
71 }
72 }
73 qwTime = GetCurrentTimeMs() - qwTime; // Elapsed time
74 dwTimeout -= min(((DWORD)qwTime), dwTimeout);
75 } while(iErr < 0);
76 #endif
77
78 nBytes = recv(hSocket, (char *)pdu, SNMP_BUFFER_SIZE, 0);
79 if (nBytes >= 0)
80 {
81 *pdwSize = nBytes;
82 return TRUE;
83 }
84 return FALSE;
85 }
86
87
88 //
89 // Send SNMP request to target, receive response, and send it to server
90 //
91
92 void ProxySNMPRequest(CSCPMessage *pRequest, CSCPMessage *pResponse)
93 {
94 BYTE *pduIn, *pduOut;
95 DWORD dwSize;
96 SOCKET hSocket;
97 int nRetries;
98 struct sockaddr_in addr;
99
100 dwSize = pRequest->GetVariableLong(VID_PDU_SIZE);
101 if (dwSize > 0)
102 {
103 pduIn = (BYTE *)malloc(dwSize);
104 pRequest->GetVariableBinary(VID_PDU, pduIn, dwSize);
105
106 hSocket = socket(AF_INET, SOCK_DGRAM, 0);
107 if (hSocket != -1)
108 {
109 memset(&addr, 0, sizeof(struct sockaddr_in));
110 addr.sin_family = AF_INET;
111 addr.sin_addr.s_addr = htonl(pRequest->GetVariableLong(VID_IP_ADDRESS));
112 addr.sin_port = htons(pRequest->GetVariableShort(VID_PORT));
113 if (connect(hSocket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != -1)
114 {
115 pduOut = (BYTE *)malloc(SNMP_BUFFER_SIZE);
116 for(nRetries = 0; nRetries < 3; nRetries++)
117 {
118 if (send(hSocket, (char *)pduIn, dwSize, 0) == (int)dwSize)
119 {
120 if (ReadPDU(hSocket, pduOut, &dwSize))
121 {
122 pResponse->SetVariable(VID_PDU_SIZE, dwSize);
123 pResponse->SetVariable(VID_PDU, pduOut, dwSize);
124 break;
125 }
126 }
127 }
128 free(pduOut);
129 pResponse->SetVariable(VID_RCC, (nRetries == 3) ? ERR_REQUEST_TIMEOUT : ERR_SUCCESS);
130 }
131 else
132 {
133 pResponse->SetVariable(VID_RCC, ERR_SOCKET_ERROR);
134 }
135 closesocket(hSocket);
136 }
137 else
138 {
139 pResponse->SetVariable(VID_RCC, ERR_SOCKET_ERROR);
140 }
141 free(pduIn);
142 }
143 else
144 {
145 pResponse->SetVariable(VID_RCC, ERR_MAILFORMED_COMMAND);
146 }
147 }