Support for creating nodes and containers from GUI
[public/netxms.git] / src / agent / core / session.cpp
CommitLineData
e9580fef
VK
1/*
2** NetXMS multiplatform core agent
3** Copyright (C) 2003, 2004 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** $module: session.cpp
20**
21**/
22
23#include "nxagentd.h"
24
25
0a147f4b
VK
26//
27// Constants
28//
29
30#define RAW_MSG_SIZE 262144
31
32
e9580fef
VK
33//
34// Client session class constructor
35//
36
37CommSession::CommSession(SOCKET hSocket, DWORD dwHostAddr)
38{
39 m_pSendQueue = new Queue;
40 m_pMessageQueue = new Queue;
41 m_hSocket = hSocket;
42 m_dwIndex = INVALID_INDEX;
43 m_pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
113829cc
VK
44 m_mutexWriteThreadRunning = MutexCreate();
45 m_mutexProcessingThreadRunning = MutexCreate();
e9580fef 46 m_dwHostAddr = dwHostAddr;
7c205c0c 47 m_bIsAuthenticated = (g_dwFlags & AF_REQUIRE_AUTH) ? FALSE : TRUE;
e9580fef
VK
48}
49
50
51//
52// Destructor
53//
54
55CommSession::~CommSession()
56{
57 shutdown(m_hSocket, 2);
58 closesocket(m_hSocket);
59 delete m_pSendQueue;
60 delete m_pMessageQueue;
61 safe_free(m_pMsgBuffer);
113829cc
VK
62 MutexDestroy(m_mutexWriteThreadRunning);
63 MutexDestroy(m_mutexProcessingThreadRunning);
e9580fef 64}
0a147f4b
VK
65
66
67//
68// Reading thread
69//
70
71void CommSession::ReadThread(void)
72{
73 CSCP_MESSAGE *pRawMsg;
74 CSCPMessage *pMsg;
75 int iErr;
7c205c0c 76 char szBuffer[32];
0a147f4b
VK
77
78 // Initialize raw message receiving function
79 RecvCSCPMessage(0, NULL, m_pMsgBuffer, 0);
80
81 pRawMsg = (CSCP_MESSAGE *)malloc(RAW_MSG_SIZE);
82 while(1)
83 {
84 if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer, RAW_MSG_SIZE)) <= 0)
85 break;
86
87 // Check if message is too large
88 if (iErr == 1)
89 continue;
90
91 // Check that actual received packet size is equal to encoded in packet
92 if ((int)ntohl(pRawMsg->dwSize) != iErr)
93 {
901c96c7 94 DebugPrintf("Actual message size doesn't match wSize value (%d,%d)", iErr, ntohl(pRawMsg->dwSize));
0a147f4b
VK
95 continue; // Bad packet, wait for next
96 }
97
98 // Create message object from raw message
99 pMsg = new CSCPMessage(pRawMsg);
100 m_pMessageQueue->Put(pMsg);
101 }
102 if (iErr < 0)
103 WriteLog(MSG_SESSION_BROKEN, EVENTLOG_WARNING_TYPE, "e", WSAGetLastError());
104 free(pRawMsg);
105
106 // Notify other threads to exit
107 m_pSendQueue->Put(INVALID_POINTER_VALUE);
108 m_pMessageQueue->Put(INVALID_POINTER_VALUE);
109
110 // Wait for other threads to finish
113829cc
VK
111 MutexLock(m_mutexWriteThreadRunning, INFINITE);
112 MutexUnlock(m_mutexWriteThreadRunning);
113
114 MutexLock(m_mutexProcessingThreadRunning, INFINITE);
115 MutexUnlock(m_mutexProcessingThreadRunning);
7c205c0c
VK
116
117 DebugPrintf("Session with %s closed", IpToStr(m_dwHostAddr, szBuffer));
0a147f4b
VK
118}
119
120
121//
122// Writing thread
123//
124
125void CommSession::WriteThread(void)
126{
127 CSCP_MESSAGE *pMsg;
128 char szBuffer[128];
129
113829cc 130 MutexLock(m_mutexWriteThreadRunning, INFINITE);
0a147f4b
VK
131 while(1)
132 {
133 pMsg = (CSCP_MESSAGE *)m_pSendQueue->GetOrBlock();
134 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
135 break;
136
901c96c7 137 DebugPrintf("Sending message %s", CSCPMessageCodeName(ntohs(pMsg->wCode), szBuffer));
0a147f4b
VK
138 if (send(m_hSocket, (const char *)pMsg, ntohl(pMsg->dwSize), 0) <= 0)
139 {
9d72bde1 140 free(pMsg);
0a147f4b
VK
141 break;
142 }
9d72bde1 143 free(pMsg);
0a147f4b 144 }
113829cc 145 MutexUnlock(m_mutexWriteThreadRunning);
0a147f4b
VK
146}
147
148
149//
150// Message processing thread
151//
152
153void CommSession::ProcessingThread(void)
154{
155 CSCPMessage *pMsg;
156 char szBuffer[128];
7c205c0c 157 CSCPMessage msg;
0a147f4b 158
113829cc 159 MutexLock(m_mutexProcessingThreadRunning, INFINITE);
0a147f4b
VK
160 while(1)
161 {
162 pMsg = (CSCPMessage *)m_pMessageQueue->GetOrBlock();
163 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
164 break;
901c96c7 165 DebugPrintf("Received message %s", CSCPMessageCodeName(pMsg->GetCode(), szBuffer));
7c205c0c
VK
166
167 // Prepare responce message
168 msg.SetCode(CMD_REQUEST_COMPLETED);
169 msg.SetId(pMsg->GetId());
170
171 // Check if authentication required
172 if ((!m_bIsAuthenticated) && (pMsg->GetCode() != CMD_AUTHENTICATE))
173 {
174 msg.SetVariable(VID_RCC, ERR_AUTH_REQUIRED);
175 }
176 else
177 {
178 switch(pMsg->GetCode())
179 {
180 case CMD_AUTHENTICATE:
181 Authenticate(pMsg, &msg);
182 break;
183 case CMD_GET_PARAMETER:
184 GetParameter(pMsg, &msg);
185 break;
186 case CMD_GET_LIST:
901c96c7 187 GetList(pMsg, &msg);
7c205c0c 188 break;
6c426e3a
VK
189 case CMD_KEEPALIVE:
190 msg.SetVariable(VID_RCC, ERR_SUCCESS);
191 break;
3c774461
VK
192 case CMD_ACTION:
193 Action(pMsg, &msg);
194 break;
7c205c0c
VK
195 default:
196 msg.SetVariable(VID_RCC, ERR_UNKNOWN_COMMAND);
197 break;
198 }
199 }
0a147f4b 200 delete pMsg;
7c205c0c
VK
201
202 // Send responce
203 SendMessage(&msg);
204 msg.DeleteAllVariables();
0a147f4b 205 }
113829cc 206 MutexUnlock(m_mutexProcessingThreadRunning);
0a147f4b 207}
7c205c0c
VK
208
209
210//
211// Authenticate peer
212//
213
214void CommSession::Authenticate(CSCPMessage *pRequest, CSCPMessage *pMsg)
215{
216 if (m_bIsAuthenticated)
217 {
218 // Already authenticated
219 pMsg->SetVariable(VID_RCC, (g_dwFlags & AF_REQUIRE_AUTH) ? ERR_ALREADY_AUTHENTICATED : ERR_AUTH_NOT_REQUIRED);
220 }
221 else
222 {
223 char szSecret[MAX_SECRET_LENGTH];
d1d0b3be 224 BYTE hash[32];
7c205c0c
VK
225 WORD wAuthMethod;
226
227 wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
228 switch(wAuthMethod)
229 {
230 case AUTH_PLAINTEXT:
231 pRequest->GetVariableStr(VID_SHARED_SECRET, szSecret, MAX_SECRET_LENGTH);
232 if (!strcmp(szSecret, g_szSharedSecret))
233 {
234 m_bIsAuthenticated = TRUE;
235 pMsg->SetVariable(VID_RCC, ERR_SUCCESS);
236 }
237 else
238 {
239 WriteLog(MSG_AUTH_FAILED, EVENTLOG_WARNING_TYPE, "as", m_dwHostAddr, "PLAIN");
240 pMsg->SetVariable(VID_RCC, ERR_AUTH_FAILED);
241 }
242 break;
d1d0b3be
VK
243 case AUTH_MD5_HASH:
244 pRequest->GetVariableBinary(VID_SHARED_SECRET, (BYTE *)szSecret, MD5_DIGEST_SIZE);
245 CalculateMD5Hash((BYTE *)g_szSharedSecret, strlen(g_szSharedSecret), hash);
246 if (!memcmp(szSecret, hash, MD5_DIGEST_SIZE))
247 {
248 m_bIsAuthenticated = TRUE;
249 pMsg->SetVariable(VID_RCC, ERR_SUCCESS);
250 }
251 else
252 {
253 WriteLog(MSG_AUTH_FAILED, EVENTLOG_WARNING_TYPE, "as", m_dwHostAddr, "MD5");
254 pMsg->SetVariable(VID_RCC, ERR_AUTH_FAILED);
255 }
256 break;
257 case AUTH_SHA1_HASH:
258 pRequest->GetVariableBinary(VID_SHARED_SECRET, (BYTE *)szSecret, SHA1_DIGEST_SIZE);
259 CalculateSHA1Hash((BYTE *)g_szSharedSecret, strlen(g_szSharedSecret), hash);
260 if (!memcmp(szSecret, hash, SHA1_DIGEST_SIZE))
261 {
262 m_bIsAuthenticated = TRUE;
263 pMsg->SetVariable(VID_RCC, ERR_SUCCESS);
264 }
265 else
266 {
267 WriteLog(MSG_AUTH_FAILED, EVENTLOG_WARNING_TYPE, "as", m_dwHostAddr, "SHA1");
268 pMsg->SetVariable(VID_RCC, ERR_AUTH_FAILED);
269 }
270 break;
7c205c0c
VK
271 default:
272 pMsg->SetVariable(VID_RCC, ERR_NOT_IMPLEMENTED);
273 break;
274 }
275 }
276}
277
278
279//
280// Get parameter's value
281//
282
283void CommSession::GetParameter(CSCPMessage *pRequest, CSCPMessage *pMsg)
284{
285 char szParameter[MAX_PARAM_NAME], szValue[MAX_RESULT_LENGTH];
286 DWORD dwErrorCode;
287
288 pRequest->GetVariableStr(VID_PARAMETER, szParameter, MAX_PARAM_NAME);
289 dwErrorCode = GetParameterValue(szParameter, szValue);
290 pMsg->SetVariable(VID_RCC, dwErrorCode);
291 if (dwErrorCode == ERR_SUCCESS)
292 pMsg->SetVariable(VID_VALUE, szValue);
293}
901c96c7
VK
294
295
296//
297// Get list of values
298//
299
300void CommSession::GetList(CSCPMessage *pRequest, CSCPMessage *pMsg)
301{
302 char szParameter[MAX_PARAM_NAME];
303 DWORD i, dwErrorCode;
304 NETXMS_VALUES_LIST value;
305
306 pRequest->GetVariableStr(VID_PARAMETER, szParameter, MAX_PARAM_NAME);
307 value.dwNumStrings = 0;
308 value.ppStringList = NULL;
309
310 dwErrorCode = GetEnumValue(szParameter, &value);
311 pMsg->SetVariable(VID_RCC, dwErrorCode);
312 if (dwErrorCode == ERR_SUCCESS)
313 {
314 pMsg->SetVariable(VID_NUM_STRINGS, value.dwNumStrings);
315 for(i = 0; i < value.dwNumStrings; i++)
316 pMsg->SetVariable(VID_ENUM_VALUE_BASE + i, value.ppStringList[i]);
317 }
318
319 for(i = 0; i < value.dwNumStrings; i++)
9d72bde1
VK
320 safe_free(value.ppStringList[i]);
321 safe_free(value.ppStringList);
901c96c7 322}
3c774461
VK
323
324
325//
326// Perform action on request
327//
328
329void CommSession::Action(CSCPMessage *pRequest, CSCPMessage *pMsg)
330{
331 char szAction[MAX_PARAM_NAME];
332 NETXMS_VALUES_LIST args;
333 DWORD i, dwRetCode;
334
335 // Get action name and arguments
336 pRequest->GetVariableStr(VID_ACTION_NAME, szAction, MAX_PARAM_NAME);
337 args.dwNumStrings = pRequest->GetVariableLong(VID_NUM_ARGS);
9d72bde1 338 args.ppStringList = (char **)malloc(sizeof(char *) * args.dwNumStrings);
3c774461
VK
339 for(i = 0; i < args.dwNumStrings; i++)
340 args.ppStringList[i] = pRequest->GetVariableStr(VID_ACTION_ARG_BASE + i);
341
342 // Execute action
343 dwRetCode = ExecAction(szAction, &args);
344 pMsg->SetVariable(VID_RCC, dwRetCode);
345
346 // Cleanup
347 for(i = 0; i < args.dwNumStrings; i++)
9d72bde1
VK
348 safe_free(args.ppStringList[i]);
349 safe_free(args.ppStringList);
3c774461 350}