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