Added comment "Each command must be ended with \r\n" to Server-agent communication...
[public/netxms.git] / src / server / core / session.cpp
CommitLineData
21e4b6f0
VK
1/*
2** NetXMS - Network Management System
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 "nms_core.h"
24
25
26//
27// Client session class constructor
28//
29
30ClientSession::ClientSession(SOCKET hSocket)
31{
32 m_pSendQueue = new Queue;
33 m_pMessageQueue = new Queue;
34 m_hSocket = hSocket;
35 m_dwIndex = INVALID_INDEX;
36 m_iState = STATE_CONNECTED;
37 m_pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
38}
39
40
41//
42// Destructor
43//
44
45ClientSession::~ClientSession()
46{
47 shutdown(m_hSocket, 2);
48 closesocket(m_hSocket);
49 delete m_pSendQueue;
50 delete m_pMessageQueue;
51 if (m_pMsgBuffer != NULL)
52 free(m_pMsgBuffer);
53}
54
55
56//
57// Print debug information
58//
59
60void ClientSession::DebugPrintf(char *szFormat, ...)
61{
62 if ((g_dwFlags & AF_STANDALONE) && (g_dwFlags & AF_DEBUG_CSCP))
63 {
64 va_list args;
65
66 printf("*CSCP(%d)* ", m_dwIndex);
67 va_start(args, szFormat);
68 vprintf(szFormat, args);
69 va_end(args);
70 }
71}
72
73
74//
75// Post message to send queue
76//
77
78void ClientSession::SendMessage(CSCPMessage *pMsg)
79{
80 m_pSendQueue->Put(pMsg->CreateMessage());
81}
82
83
84//
85// ReadThread()
86//
87
88void ClientSession::ReadThread(void)
89{
90 CSCP_MESSAGE *pRawMsg;
91 CSCPMessage *pMsg;
92 int iErr;
93
94 // Initialize raw message receiving function
95 RecvCSCPMessage(0, NULL, m_pMsgBuffer);
96
97 pRawMsg = (CSCP_MESSAGE *)malloc(65536);
98 while(1)
99 {
100 if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer)) <= 0)
101 break;
102
103 // Check that actual received packet size is equal to encoded in packet
104 if (ntohs(pRawMsg->wSize) != iErr)
105 {
106 DebugPrintf("Actual message size doesn't match wSize value (%d,%d)\n", iErr, ntohs(pRawMsg->wSize));
107 continue; // Bad packet, wait for next
108 }
109
110 // Create message object from raw message
111 pMsg = new CSCPMessage(pRawMsg);
112 m_pMessageQueue->Put(pMsg);
113 }
114 if (iErr < 0)
115 WriteLog(MSG_SESSION_CLOSED, EVENTLOG_WARNING_TYPE, "e", WSAGetLastError());
116 free(pRawMsg);
117
118 // Notify other threads to exit
119 m_pSendQueue->Put(NULL);
20177e8e 120 m_pMessageQueue->Put(NULL);
21e4b6f0
VK
121}
122
123
124//
125// WriteThread()
126//
127
128void ClientSession::WriteThread(void)
129{
130 CSCP_MESSAGE *pMsg;
131
132 while(1)
133 {
134 pMsg = (CSCP_MESSAGE *)m_pSendQueue->GetOrBlock();
135 if (pMsg == NULL) // Session termination indicator
136 break;
137
138 if (send(m_hSocket, (const char *)pMsg, ntohs(pMsg->wSize), 0) <= 0)
139 {
7968a52d 140 MemFree(pMsg);
21e4b6f0
VK
141 break;
142 }
7968a52d 143 MemFree(pMsg);
21e4b6f0
VK
144 }
145}
146
147
148//
149// Message processing thread
150//
151
152void ClientSession::ProcessingThread(void)
153{
154 CSCPMessage *pMsg, *pReply;
155
156 while(1)
157 {
158 pMsg = (CSCPMessage *)m_pMessageQueue->GetOrBlock();
159 if (pMsg == NULL) // Session termination indicator
160 break;
161
162 DebugPrintf("Received message with code %d\n", pMsg->GetCode());
163 if ((m_iState != STATE_AUTHENTICATED) && (pMsg->GetCode() != CMD_LOGIN))
164 {
165 delete pMsg;
166 continue;
167 }
168
169 switch(pMsg->GetCode())
170 {
171 case CMD_LOGIN:
172 if (m_iState != STATE_AUTHENTICATED)
173 {
a5f8dbb8
VK
174 char *pszLogin = pMsg->GetVariableStr(VID_LOGIN_NAME);
175 char *pszPassword = pMsg->GetVariableStr(VID_PASSWORD);
21e4b6f0
VK
176
177 if (AuthenticateUser(pszLogin, pszPassword, &m_dwUserId, &m_dwSystemAccess))
178 m_iState = STATE_AUTHENTICATED;
179
7968a52d
VK
180 MemFree(pszLogin);
181 MemFree(pszPassword);
21e4b6f0
VK
182
183 // Send reply
184 pReply = new CSCPMessage;
185 pReply->SetCode(CMD_LOGIN_RESP);
186 pReply->SetId(pMsg->GetId());
a5f8dbb8 187 pReply->SetVariable(VID_LOGIN_RESULT, (DWORD)(m_iState == STATE_AUTHENTICATED));
21e4b6f0
VK
188 SendMessage(pReply);
189 delete pReply;
190 }
191 else
192 {
193 }
194 break;
195 case CMD_GET_OBJECTS:
196 SendAllObjects();
197 break;
198 case CMD_GET_EVENTS:
199 SendAllEvents();
200 break;
201 case CMD_GET_CONFIG_VARLIST:
202 SendAllConfigVars();
203 break;
204 default:
205 break;
206 }
207 delete pMsg;
208 }
209}
210
211
212//
213// Send all objects to client
214//
215
216void ClientSession::SendAllObjects(void)
217{
218 DWORD i;
219 CSCPMessage msg;
220
221 // Prepare message
222 msg.SetCode(CMD_OBJECT);
223
224 // Send objects, one per message
225 ObjectsGlobalLock();
226 for(i = 0; i < g_dwIdIndexSize; i++)
227 {
228 g_pIndexById[i].pObject->CreateMessage(&msg);
229 SendMessage(&msg);
230 msg.DeleteAllVariables();
231 }
232 ObjectsGlobalUnlock();
233
234 // Send end of list notification
235 msg.SetCode(CMD_OBJECT_LIST_END);
236 SendMessage(&msg);
237}
238
239
240//
241// Send all events to client
242//
243
244void ClientSession::SendAllEvents(void)
245{
21e4b6f0 246 CSCPMessage msg;
20177e8e 247 DB_ASYNC_RESULT hResult;
9c36ef66 248 NXC_EVENT event;
21e4b6f0 249
21e4b6f0 250 // Retrieve events from database
20177e8e 251 hResult = DBAsyncSelect(g_hCoreDB, "SELECT event_id,timestamp,source,severity,message FROM EventLog ORDER BY timestamp");
21e4b6f0
VK
252 if (hResult != NULL)
253 {
254 // Send events, one per message
20177e8e 255 while(DBFetch(hResult))
21e4b6f0 256 {
20177e8e
VK
257 event.dwEventId = htonl(DBGetFieldAsyncULong(hResult, 0));
258 event.dwTimeStamp = htonl(DBGetFieldAsyncULong(hResult, 1));
259 event.dwSourceId = htonl(DBGetFieldAsyncULong(hResult, 2));
260 event.dwSeverity = htonl(DBGetFieldAsyncULong(hResult, 3));
261 DBGetFieldAsync(hResult, 4, event.szMessage, MAX_EVENT_MSG_LENGTH);
9c36ef66
VK
262 m_pSendQueue->Put(CreateRawCSCPMessage(CMD_EVENT, 0, sizeof(NXC_EVENT), &event, NULL));
263 }
20177e8e 264 DBFreeAsyncResult(hResult);
21e4b6f0
VK
265 }
266
267 // Send end of list notification
268 msg.SetCode(CMD_EVENT_LIST_END);
269 SendMessage(&msg);
270}
271
272
273//
274// Send all configuration variables to client
275//
276
277void ClientSession::SendAllConfigVars(void)
278{
279 DWORD i, dwNumRecords;
280 CSCPMessage msg;
281 DB_RESULT hResult;
282
283 // Check user rights
284 if ((m_dwUserId != 0) && ((m_dwSystemAccess & SYSTEM_ACCESS_VIEW_CONFIG) == 0))
285 {
286 // Access denied
287 msg.SetCode(CMD_CONFIG_VARLIST_END);
a5f8dbb8 288 msg.SetVariable(VID_ERROR, (DWORD)1);
21e4b6f0
VK
289 SendMessage(&msg);
290 }
291 else
292 {
293 // Prepare message
294 msg.SetCode(CMD_CONFIG_VARIABLE);
295
296 // Retrieve configuration variables from database
297 hResult = DBSelect(g_hCoreDB, "SELECT name,value FROM config");
298 if (hResult != NULL)
299 {
300 // Send events, one per message
301 dwNumRecords = DBGetNumRows(hResult);
302 for(i = 0; i < dwNumRecords; i++)
303 {
a5f8dbb8
VK
304 msg.SetVariable(VID_NAME, DBGetField(hResult, i, 0));
305 msg.SetVariable(VID_VALUE, DBGetField(hResult, i, 1));
21e4b6f0
VK
306 SendMessage(&msg);
307 msg.DeleteAllVariables();
308 }
20177e8e 309 DBFreeResult(hResult);
21e4b6f0
VK
310 }
311
312 // Send end of list notification
313 msg.SetCode(CMD_CONFIG_VARLIST_END);
a5f8dbb8 314 msg.SetVariable(VID_ERROR, (DWORD)0);
21e4b6f0
VK
315 SendMessage(&msg);
316 }
317}
20177e8e
VK
318
319
320//
321// Close session forcibly
322//
323
324void ClientSession::Kill(void)
325{
326 // We shutdown socket connection, which will cause
327 // read thread to stop, and other threads will follow
328 shutdown(m_hSocket, 2);
329}