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