Server shared library
[public/netxms.git] / src / server / libnxsrv / agent.cpp
CommitLineData
f77084bb
VK
1/*
2** NetXMS - Network Management System
3** Server Library
4** Copyright (C) 2003, 2004 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** $module: agent.cpp
21**
22**/
23
24#include "libnxsrv.h"
25
26
27//
28// Constants
29//
30
31#define RECEIVER_BUFFER_SIZE 262144
32
33
34//
35// Receiver thread starter
36//
37
38static void AgentReceiverThread(void *pArg)
39{
40 ((AgentConnection *)pArg)->ReceiverThread();
41}
42
43
44//
45// Default constructor for AgentConnection - normally shouldn't be used
46//
47
48AgentConnection::AgentConnection()
49{
50 m_dwAddr = inet_addr("127.0.0.1");
51 m_wPort = AGENT_LISTEN_PORT;
52 m_iAuthMethod = AUTH_NONE;
53 m_szSecret[0] = 0;
54 m_hSocket = -1;
55 m_tLastCommandTime = 0;
56 m_dwNumDataLines = 0;
57 m_ppDataLines = NULL;
58 m_pMsgWaitQueue = new MsgWaitQueue;
59 m_dwRequestId = 0;
60 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
61}
62
63
64//
65// Normal constructor for AgentConnection
66//
67
68AgentConnection::AgentConnection(DWORD dwAddr, WORD wPort, int iAuthMethod, char *szSecret)
69{
70 m_dwAddr = dwAddr;
71 m_wPort = wPort;
72 m_iAuthMethod = iAuthMethod;
73 if (szSecret != NULL)
74 strncpy(m_szSecret, szSecret, MAX_SECRET_LENGTH);
75 else
76 m_szSecret[0] = 0;
77 m_hSocket = -1;
78 m_tLastCommandTime = 0;
79 m_dwNumDataLines = 0;
80 m_ppDataLines = NULL;
81 m_pMsgWaitQueue = new MsgWaitQueue;
82 m_dwRequestId = 0;
83 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
84}
85
86
87//
88// Destructor
89//
90
91AgentConnection::~AgentConnection()
92{
93 if (m_hSocket != -1)
94 closesocket(m_hSocket);
95 DestroyResultData();
96 delete m_pMsgWaitQueue;
97}
98
99
100//
101// Print message. This function is virtual and can be overrided in derived classes.
102// Default implementation will print message to stdout.
103//
104
105void AgentConnection::PrintMsg(char *pszFormat, ...)
106{
107 va_list args;
108
109 va_start(args, pszFormat);
110 vprintf(pszFormat, args);
111 va_end(args);
112 printf("\n");
113}
114
115
116//
117// Receiver thread
118//
119
120void AgentConnection::ReceiverThread(void)
121{
122 CSCPMessage *pMsg;
123 CSCP_MESSAGE *pRawMsg;
124 CSCP_BUFFER *pMsgBuffer;
125 int iErr;
126 char szBuffer[128];
127
128 // Initialize raw message receiving function
129 pMsgBuffer = (CSCP_BUFFER *)MemAlloc(sizeof(CSCP_BUFFER));
130 RecvCSCPMessage(0, NULL, pMsgBuffer, 0);
131
132 // Allocate space for raw message
133 pRawMsg = (CSCP_MESSAGE *)MemAlloc(RECEIVER_BUFFER_SIZE);
134
135 // Message receiving loop
136 while(1)
137 {
138 // Receive raw message
139 if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE)) <= 0)
140 break;
141
142 // Check if we get too large message
143 if (iErr == 1)
144 {
145 PrintMsg("Received too large message %s (%ld bytes)",
146 CSCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
147 ntohl(pRawMsg->dwSize));
148 continue;
149 }
150
151 // Check that actual received packet size is equal to encoded in packet
152 if ((int)ntohl(pRawMsg->dwSize) != iErr)
153 {
154 PrintMsg("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]", ntohl(pRawMsg->dwSize), iErr);
155 continue; // Bad packet, wait for next
156 }
157
158 // Create message object from raw message
159 pMsg = new CSCPMessage(pRawMsg);
160 if (pMsg->GetCode() == CMD_TRAP)
161 {
162 delete pMsg;
163 }
164 else
165 {
166 m_pMsgWaitQueue->Put(pMsg);
167 }
168 }
169
170 MemFree(pRawMsg);
171 MemFree(pMsgBuffer);
172}
173
174
175//
176// Connect to agent
177//
178
179BOOL AgentConnection::Connect(BOOL bVerbose)
180{
181 struct sockaddr_in sa;
182 char szBuffer[256];
183 BOOL bSuccess = FALSE;
184
185 // Create socket
186 m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
187 if (m_hSocket == -1)
188 {
189 PrintMsg("Call to socket() failed");
190 goto connect_cleanup;
191 }
192
193 // Fill in address structure
194 memset(&sa, 0, sizeof(sa));
195 sa.sin_addr.s_addr = m_dwAddr;
196 sa.sin_family = AF_INET;
197 sa.sin_port = htons(m_wPort);
198
199 // Connect to server
200 if (connect(m_hSocket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
201 {
202 if (bVerbose)
203 PrintMsg("Cannot establish connection with agent %s", IpToStr(m_dwAddr, szBuffer));
204 goto connect_cleanup;
205 }
206
207 // Start receiver thread
208 ThreadCreate(AgentReceiverThread, 0, this);
209
210 // Authenticate itself to agent
211 switch(m_iAuthMethod)
212 {
213 case AUTH_PLAINTEXT:
214 break;
215 default:
216 break;
217 }
218
219 // Test connectivity
220 if (Nop() != ERR_SUCCESS)
221 {
222 PrintMsg("Communication with agent %s failed", IpToStr(m_dwAddr, szBuffer));
223 goto connect_cleanup;
224 }
225
226 bSuccess = TRUE;
227
228connect_cleanup:
229 if (!bSuccess)
230 {
231 if (m_hSocket != -1)
232 {
233 shutdown(m_hSocket, 2);
234 closesocket(m_hSocket);
235 m_hSocket = -1;
236 }
237 }
238 return bSuccess;
239}
240
241
242//
243// Disconnect from agent
244//
245
246void AgentConnection::Disconnect(void)
247{
248 if (m_hSocket != -1)
249 {
250 shutdown(m_hSocket, 2);
251 closesocket(m_hSocket);
252 m_hSocket = -1;
253 }
254 DestroyResultData();
255}
256
257
258//
259// Destroy command execuion results data
260//
261
262void AgentConnection::DestroyResultData(void)
263{
264 DWORD i;
265
266 if (m_ppDataLines != NULL)
267 {
268 for(i = 0; i < m_dwNumDataLines; i++)
269 if (m_ppDataLines[i] != NULL)
270 free(m_ppDataLines[i]);
271 free(m_ppDataLines);
272 m_ppDataLines = NULL;
273 }
274 m_dwNumDataLines = 0;
275}
276
277
278//
279// Get interface list from agent
280//
281
282INTERFACE_LIST *AgentConnection::GetInterfaceList(void)
283{
284 return NULL;
285}
286
287
288//
289// Get parameter value
290//
291
292DWORD AgentConnection::GetParameter(char *pszParam, DWORD dwBufSize, char *pszBuffer)
293{
294 CSCPMessage msg, *pResponce;
295 DWORD dwRqId, dwRetCode;
296
297 dwRqId = m_dwRequestId++;
298 msg.SetCode(CMD_GET_PARAMETER);
299 msg.SetId(dwRqId);
300 msg.SetVariable(VID_PARAMETER, pszParam);
301 if (SendMessage(&msg))
302 {
303 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
304 if (pResponce != NULL)
305 {
306 dwRetCode = pResponce->GetVariableLong(VID_RCC);
307 if (dwRetCode == ERR_SUCCESS)
308 pResponce->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
309 delete pResponce;
310 }
311 else
312 {
313 dwRetCode = ERR_REQUEST_TIMEOUT;
314 }
315 }
316 else
317 {
318 dwRetCode = ERR_CONNECTION_BROKEN;
319 }
320
321 return dwRetCode;
322}
323
324
325//
326// Get ARP cache
327//
328
329ARP_CACHE *AgentConnection::GetArpCache(void)
330{
331 return NULL;
332}
333
334
335//
336// Send dummy command to agent (can be used for keepalive)
337//
338
339DWORD AgentConnection::Nop(void)
340{
341 CSCPMessage msg;
342 DWORD dwRqId;
343
344 dwRqId = m_dwRequestId++;
345 msg.SetCode(CMD_KEEPALIVE);
346 msg.SetId(dwRqId);
347 if (SendMessage(&msg))
348 return WaitForRCC(dwRqId, m_dwCommandTimeout);
349 else
350 return ERR_CONNECTION_BROKEN;
351}
352
353
354//
355// Wait for request completion code
356//
357
358DWORD AgentConnection::WaitForRCC(DWORD dwRqId, DWORD dwTimeOut)
359{
360 CSCPMessage *pMsg;
361 DWORD dwRetCode;
362
363 pMsg = m_pMsgWaitQueue->WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
364 if (pMsg != NULL)
365 {
366 dwRetCode = pMsg->GetVariableLong(VID_RCC);
367 delete pMsg;
368 }
369 else
370 {
371 dwRetCode = ERR_REQUEST_TIMEOUT;
372 }
373 return dwRetCode;
374}
375
376
377//
378// Send message to agent
379//
380
381BOOL AgentConnection::SendMessage(CSCPMessage *pMsg)
382{
383 CSCP_MESSAGE *pRawMsg;
384 BOOL bResult;
385
386 pRawMsg = pMsg->CreateMessage();
387 bResult = (send(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
388 MemFree(pRawMsg);
389 return bResult;
390}