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