Minor changes
[public/netxms.git] / src / libnxcl / comm.cpp
CommitLineData
05d9bba3
VK
1/*
2** NetXMS - Network Management System
3** Client Library
4** Copyright (C) 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: comm.cpp
21**
22**/
23
24#include "libnxcl.h"
25
26
05d9bba3
VK
27//
28// Network receiver thread
29//
30
4507063f 31THREAD_RESULT THREAD_CALL NetReceiver(NXCL_Session *pSession)
05d9bba3
VK
32{
33 CSCPMessage *pMsg;
34 CSCP_MESSAGE *pRawMsg;
35 CSCP_BUFFER *pMsgBuffer;
36 int iErr;
d8d6e1a4 37 BOOL bMsgNotNeeded;
b40371d4 38 TCHAR szBuffer[128];
05d9bba3
VK
39
40 // Initialize raw message receiving function
9d72bde1 41 pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
edbaa8c0 42 RecvCSCPMessage(0, NULL, pMsgBuffer, 0);
05d9bba3
VK
43
44 // Allocate space for raw message
41213c24 45 pRawMsg = (CSCP_MESSAGE *)malloc(pSession->m_dwReceiverBufferSize);
05d9bba3
VK
46
47 // Message receiving loop
48 while(1)
49 {
50 // Receive raw message
41213c24
VK
51 if ((iErr = RecvCSCPMessage(pSession->m_hSocket, pRawMsg,
52 pMsgBuffer, pSession->m_dwReceiverBufferSize)) <= 0)
05d9bba3
VK
53 break;
54
edbaa8c0
VK
55 // Check if we get too large message
56 if (iErr == 1)
57 {
b40371d4 58 DebugPrintf(_T("Received too large message %s (%ld bytes)"),
edbaa8c0
VK
59 CSCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
60 ntohl(pRawMsg->dwSize));
61 continue;
62 }
63
05d9bba3 64 // Check that actual received packet size is equal to encoded in packet
74dccebe 65 if ((int)ntohl(pRawMsg->dwSize) != iErr)
05d9bba3 66 {
b40371d4 67 DebugPrintf(_T("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]"), ntohl(pRawMsg->dwSize), iErr);
05d9bba3
VK
68 continue; // Bad packet, wait for next
69 }
70
71 // Create message object from raw message
f8e075ce
VK
72 if (IsBinaryMsg(pRawMsg))
73 {
74 // Convert numeric fields to host byte order
74dccebe
VK
75 pRawMsg->wCode = ntohs(pRawMsg->wCode);
76 pRawMsg->wFlags = ntohs(pRawMsg->wFlags);
77 pRawMsg->dwSize = ntohl(pRawMsg->dwSize);
f8e075ce 78 pRawMsg->dwId = ntohl(pRawMsg->dwId);
74dccebe 79 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
f8e075ce 80
b40371d4 81 DebugPrintf(_T("RecvRawMsg(\"%s\", id:%ld)"), CSCPMessageCodeName(pRawMsg->wCode, szBuffer), pRawMsg->dwId);
1dd9669b 82
f8e075ce
VK
83 // Process message
84 switch(pRawMsg->wCode)
85 {
86 case CMD_EVENT:
41213c24 87 ProcessEvent(pSession, NULL, pRawMsg);
f8e075ce 88 break;
74dccebe 89 default: // Put unknown raw messages into the wait queue
41213c24 90 pSession->m_msgWaitQueue.Put((CSCP_MESSAGE *)nx_memdup(pRawMsg, pRawMsg->dwSize));
f8e075ce
VK
91 break;
92 }
93 }
94 else
05d9bba3 95 {
f8e075ce 96 pMsg = new CSCPMessage(pRawMsg);
d8d6e1a4 97 bMsgNotNeeded = TRUE;
b40371d4 98 DebugPrintf(_T("RecvMsg(\"%s\", id:%ld)"), CSCPMessageCodeName(pMsg->GetCode(), szBuffer), pMsg->GetId());
f8e075ce
VK
99
100 // Process message
101 switch(pMsg->GetCode())
102 {
103 case CMD_KEEPALIVE: // Keepalive message, ignore it
f8e075ce
VK
104 break;
105 case CMD_OBJECT: // Object information
824615ef 106 case CMD_OBJECT_UPDATE:
f8e075ce 107 case CMD_OBJECT_LIST_END:
cce198f5 108 pSession->ProcessObjectUpdate(pMsg);
f8e075ce
VK
109 break;
110 case CMD_EVENT_LIST_END:
41213c24 111 ProcessEvent(pSession, pMsg, NULL);
f8e075ce 112 break;
f160ff09 113 case CMD_EVENT_DB_RECORD:
cce198f5 114 ProcessEventDBRecord(pSession, pMsg);
f160ff09 115 break;
bb68f467
VK
116 case CMD_USER_DATA:
117 case CMD_GROUP_DATA:
118 case CMD_USER_DB_EOF:
cce198f5 119 pSession->ProcessUserDBRecord(pMsg);
bb68f467 120 break;
0779b7d3 121 case CMD_USER_DB_UPDATE:
cce198f5 122 pSession->ProcessUserDBUpdate(pMsg);
0779b7d3 123 break;
7ec6cca8
VK
124 case CMD_NODE_DCI:
125 case CMD_NODE_DCI_LIST_END:
cce198f5 126 pSession->ProcessDCI(pMsg);
7ec6cca8 127 break;
eb484131 128 case CMD_ALARM_UPDATE:
41213c24 129 ProcessAlarmUpdate(pSession, pMsg);
eb484131 130 break;
5bfcf934 131 case CMD_ACTION_DB_UPDATE:
41213c24 132 ProcessActionUpdate(pSession, pMsg);
5bfcf934 133 break;
3421c063 134 case CMD_NOTIFY:
41213c24
VK
135 pSession->CallEventHandler(NXC_EVENT_NOTIFICATION,
136 pMsg->GetVariableLong(VID_NOTIFICATION_CODE),
137 (void *)pMsg->GetVariableLong(VID_NOTIFICATION_DATA));
3421c063 138 break;
f8e075ce 139 default:
41213c24 140 pSession->m_msgWaitQueue.Put(pMsg);
d8d6e1a4 141 bMsgNotNeeded = FALSE;
f8e075ce
VK
142 break;
143 }
d8d6e1a4
VK
144 if (bMsgNotNeeded)
145 delete pMsg;
05d9bba3
VK
146 }
147 }
148
cce198f5 149 pSession->CompleteSync(RCC_COMM_FAILURE); // Abort active sync operation
b40371d4 150 DebugPrintf(_T("Network receiver thread stopped"));
9d72bde1
VK
151 free(pRawMsg);
152 free(pMsgBuffer);
8f7e2482
VK
153
154 // Close socket
41213c24 155 shutdown(pSession->m_hSocket, SHUT_WR);
b40371d4
AK
156 {
157 char cTmp;
41213c24 158 while(recv(pSession->m_hSocket, &cTmp, 1, 0) > 0);
b40371d4 159 }
41213c24
VK
160 shutdown(pSession->m_hSocket, SHUT_RD);
161 closesocket(pSession->m_hSocket);
ccdbbb52 162 return THREAD_OK;
05d9bba3
VK
163}
164
165
166//
167// Connect to server
168//
169
41213c24
VK
170DWORD LIBNXCL_EXPORTABLE NXCConnect(TCHAR *pszServer, TCHAR *pszLogin,
171 TCHAR *pszPassword, NXC_SESSION *phSession)
05d9bba3
VK
172{
173 struct sockaddr_in servAddr;
174 CSCPMessage msg, *pResp;
99eee1db 175 BYTE szPasswordHash[SHA1_DIGEST_SIZE];
3a32dee8 176 DWORD dwRetCode = RCC_COMM_FAILURE;
41213c24 177 SOCKET hSocket;
b40371d4
AK
178 char *pServer;
179#ifdef UNICODE
180 char szMHost[64];
181
b40371d4 182 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
41213c24 183 pszServer, -1, szMHost, sizeof(szMHost), NULL, NULL);
b40371d4
AK
184 pServer = szMHost;
185#else
41213c24 186 pServer = pszServer;
b40371d4 187#endif
05d9bba3 188
41213c24
VK
189 // Prepare address structure
190 memset(&servAddr, 0, sizeof(struct sockaddr_in));
191 servAddr.sin_family = AF_INET;
192 servAddr.sin_port = htons((WORD)SERVER_LISTEN_PORT);
05d9bba3 193
41213c24 194 servAddr.sin_addr.s_addr = inet_addr(pServer);
05d9bba3 195
41213c24
VK
196 if (servAddr.sin_addr.s_addr == INADDR_NONE)
197 {
198 struct hostent *hs;
b40371d4 199
41213c24
VK
200 hs = gethostbyname(pServer);
201 if (hs != NULL)
202 memcpy(&servAddr.sin_addr, hs->h_addr, hs->h_length);
203 }
b40371d4 204
41213c24
VK
205 if (servAddr.sin_addr.s_addr != INADDR_NONE)
206 {
207 // Create socket
208 if ((hSocket = socket(AF_INET, SOCK_STREAM, 0)) != -1)
55198bf4 209 {
41213c24
VK
210 // Connect to target
211 if (connect(hSocket, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) == 0)
212 {
213 NXCL_Session *pSession;
05d9bba3 214
41213c24
VK
215 // Create new session and start receiver thread
216 pSession = new NXCL_Session;
217 pSession->Attach(hSocket);
218 ThreadCreate((THREAD_RESULT (THREAD_CALL *)(void *))NetReceiver, 0, pSession);
05d9bba3 219
41213c24
VK
220 // Query server information
221 msg.SetId(pSession->CreateRqId());
222 msg.SetCode(CMD_GET_SERVER_INFO);
223 if (pSession->SendMsg(&msg))
55198bf4 224 {
41213c24
VK
225 // Receive responce message
226 pResp = pSession->WaitForMessage(CMD_REQUEST_COMPLETED, msg.GetId());
227 if (pResp != NULL)
55198bf4 228 {
41213c24
VK
229 dwRetCode = pResp->GetVariableLong(VID_RCC);
230 if (dwRetCode == RCC_SUCCESS)
55198bf4 231 {
41213c24 232 TCHAR szServerVersion[64];
693119d6 233
41213c24
VK
234 pResp->GetVariableStr(VID_SERVER_VERSION, szServerVersion, 64);
235 if (_tcsncmp(szServerVersion, NETXMS_VERSION_STRING, 64))
236 dwRetCode = RCC_VERSION_MISMATCH;
237 }
238 delete pResp;
693119d6 239
41213c24
VK
240 if (dwRetCode == RCC_SUCCESS)
241 {
242 // Do login if we are requested to do so
243 // Login is not needed for web sessions
244 if (pszLogin != NULL)
693119d6
VK
245 {
246 // Prepare login message
247 msg.DeleteAllVariables();
41213c24 248 msg.SetId(pSession->CreateRqId());
693119d6 249 msg.SetCode(CMD_LOGIN);
41213c24
VK
250 msg.SetVariable(VID_LOGIN_NAME, pszLogin);
251 CalculateSHA1Hash((BYTE *)pszPassword, _tcslen(pszPassword), szPasswordHash);
693119d6
VK
252 msg.SetVariable(VID_PASSWORD, szPasswordHash, SHA1_DIGEST_SIZE);
253
41213c24 254 if (pSession->SendMsg(&msg))
693119d6
VK
255 {
256 // Receive responce message
41213c24 257 pResp = pSession->WaitForMessage(CMD_LOGIN_RESP, msg.GetId());
693119d6
VK
258 if (pResp != NULL)
259 {
260 dwRetCode = pResp->GetVariableLong(VID_RCC);
261 delete pResp;
262 }
263 else
264 {
265 // Connection is broken or timed out
266 dwRetCode = RCC_TIMEOUT;
267 }
268 }
269 }
55198bf4
VK
270 }
271 }
41213c24
VK
272 else
273 {
274 // Connection is broken or timed out
275 dwRetCode = RCC_TIMEOUT;
276 }
3a32dee8
VK
277 }
278
41213c24 279 if (dwRetCode == RCC_SUCCESS)
3a32dee8 280 {
41213c24
VK
281 *phSession = pSession;
282 }
283 else
284 {
285 delete pSession;
286 shutdown(hSocket, SHUT_RDWR);
55198bf4 287 }
55198bf4 288 }
41213c24
VK
289
290 if (dwRetCode != RCC_SUCCESS)
291 {
292 closesocket(hSocket);
293 }
55198bf4 294 }
05d9bba3
VK
295 }
296
3a32dee8 297 return dwRetCode;
05d9bba3
VK
298}
299
300
05d9bba3
VK
301//
302// Disconnect from server
303//
304
41213c24 305void LIBNXCL_EXPORTABLE NXCDisconnect(NXC_SESSION hSession)
05d9bba3 306{
41213c24
VK
307 ((NXCL_Session *)hSession)->Disconnect();
308 delete ((NXCL_Session *)hSession);
05d9bba3 309}