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
27//
55198bf4 28// Unique message ID
05d9bba3
VK
29//
30
55198bf4 31DWORD g_dwMsgId;
05d9bba3
VK
32
33
1dd9669b 34//
55198bf4 35// Static data
1dd9669b
VK
36//
37
55198bf4
VK
38static SOCKET m_hSocket = -1;
39static MsgWaitQueue m_msgWaitQueue;
edbaa8c0 40static DWORD m_dwReceiverBufferSize = 4194304; // 4MB
1dd9669b
VK
41
42
05d9bba3
VK
43//
44// Send raw message
45//
46
47static BOOL SendRawMsg(CSCP_MESSAGE *pMsg)
48{
74dccebe 49 return send(m_hSocket, (char *)pMsg, ntohl(pMsg->dwSize), 0) == (int)ntohl(pMsg->dwSize);
05d9bba3
VK
50}
51
52
53//
54// Send message
55//
56
57BOOL SendMsg(CSCPMessage *pMsg)
58{
59 CSCP_MESSAGE *pRawMsg;
60 BOOL bResult;
55198bf4 61 char szBuffer[128];
05d9bba3 62
55198bf4 63 DebugPrintf("SendMsg(\"%s\", id:%ld)", CSCPMessageCodeName(pMsg->GetCode(), szBuffer), pMsg->GetId());
05d9bba3
VK
64 pRawMsg = pMsg->CreateMessage();
65 bResult = SendRawMsg(pRawMsg);
9d72bde1 66 free(pRawMsg);
05d9bba3
VK
67 return bResult;
68}
69
70
71//
72// Network receiver thread
73//
74
ccdbbb52 75static THREAD_RESULT THREAD_CALL NetReceiver(void *pArg)
05d9bba3
VK
76{
77 CSCPMessage *pMsg;
78 CSCP_MESSAGE *pRawMsg;
79 CSCP_BUFFER *pMsgBuffer;
80 int iErr;
d8d6e1a4 81 BOOL bMsgNotNeeded;
55198bf4 82 char szBuffer[128];
05d9bba3
VK
83
84 // Initialize raw message receiving function
9d72bde1 85 pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
edbaa8c0 86 RecvCSCPMessage(0, NULL, pMsgBuffer, 0);
05d9bba3
VK
87
88 // Allocate space for raw message
9d72bde1 89 pRawMsg = (CSCP_MESSAGE *)malloc(m_dwReceiverBufferSize);
05d9bba3
VK
90
91 // Message receiving loop
92 while(1)
93 {
94 // Receive raw message
edbaa8c0 95 if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, pMsgBuffer, m_dwReceiverBufferSize)) <= 0)
05d9bba3
VK
96 break;
97
edbaa8c0
VK
98 // Check if we get too large message
99 if (iErr == 1)
100 {
101 DebugPrintf("Received too large message %s (%ld bytes)",
102 CSCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
103 ntohl(pRawMsg->dwSize));
104 continue;
105 }
106
05d9bba3 107 // Check that actual received packet size is equal to encoded in packet
74dccebe 108 if ((int)ntohl(pRawMsg->dwSize) != iErr)
05d9bba3 109 {
74dccebe 110 DebugPrintf("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]", ntohl(pRawMsg->dwSize), iErr);
05d9bba3
VK
111 continue; // Bad packet, wait for next
112 }
113
114 // Create message object from raw message
f8e075ce
VK
115 if (IsBinaryMsg(pRawMsg))
116 {
117 // Convert numeric fields to host byte order
74dccebe
VK
118 pRawMsg->wCode = ntohs(pRawMsg->wCode);
119 pRawMsg->wFlags = ntohs(pRawMsg->wFlags);
120 pRawMsg->dwSize = ntohl(pRawMsg->dwSize);
f8e075ce 121 pRawMsg->dwId = ntohl(pRawMsg->dwId);
74dccebe 122 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
f8e075ce 123
55198bf4 124 DebugPrintf("RecvRawMsg(\"%s\", id:%ld)", CSCPMessageCodeName(pRawMsg->wCode, szBuffer), pRawMsg->dwId);
1dd9669b 125
f8e075ce
VK
126 // Process message
127 switch(pRawMsg->wCode)
128 {
129 case CMD_EVENT:
130 ProcessEvent(NULL, pRawMsg);
f8e075ce 131 break;
74dccebe 132 default: // Put unknown raw messages into the wait queue
edbaa8c0 133 m_msgWaitQueue.Put((CSCP_MESSAGE *)nx_memdup(pRawMsg, pRawMsg->dwSize));
f8e075ce
VK
134 break;
135 }
136 }
137 else
05d9bba3 138 {
f8e075ce 139 pMsg = new CSCPMessage(pRawMsg);
d8d6e1a4 140 bMsgNotNeeded = TRUE;
55198bf4 141 DebugPrintf("RecvMsg(\"%s\", id:%ld)", CSCPMessageCodeName(pMsg->GetCode(), szBuffer), pMsg->GetId());
f8e075ce
VK
142
143 // Process message
144 switch(pMsg->GetCode())
145 {
146 case CMD_KEEPALIVE: // Keepalive message, ignore it
f8e075ce
VK
147 break;
148 case CMD_OBJECT: // Object information
824615ef 149 case CMD_OBJECT_UPDATE:
f8e075ce
VK
150 case CMD_OBJECT_LIST_END:
151 ProcessObjectUpdate(pMsg);
f8e075ce
VK
152 break;
153 case CMD_EVENT_LIST_END:
154 ProcessEvent(pMsg, NULL);
f8e075ce 155 break;
f160ff09
VK
156 case CMD_EVENT_DB_RECORD:
157 case CMD_EVENT_DB_EOF:
158 ProcessEventDBRecord(pMsg);
159 break;
bb68f467
VK
160 case CMD_USER_DATA:
161 case CMD_GROUP_DATA:
162 case CMD_USER_DB_EOF:
163 ProcessUserDBRecord(pMsg);
164 break;
0779b7d3
VK
165 case CMD_USER_DB_UPDATE:
166 ProcessUserDBUpdate(pMsg);
167 break;
7ec6cca8
VK
168 case CMD_NODE_DCI:
169 case CMD_NODE_DCI_LIST_END:
170 ProcessDCI(pMsg);
171 break;
eb484131
VK
172 case CMD_ALARM_UPDATE:
173 ProcessAlarmUpdate(pMsg);
174 break;
5bfcf934
VK
175 case CMD_ACTION_DB_UPDATE:
176 ProcessActionUpdate(pMsg);
177 break;
3421c063
VK
178 case CMD_NOTIFY:
179 CallEventHandler(NXC_EVENT_NOTIFICATION,
4de204a3
VK
180 pMsg->GetVariableLong(VID_NOTIFICATION_CODE),
181 (void *)pMsg->GetVariableLong(VID_NOTIFICATION_DATA));
3421c063 182 break;
f8e075ce
VK
183 default:
184 m_msgWaitQueue.Put(pMsg);
d8d6e1a4 185 bMsgNotNeeded = FALSE;
f8e075ce
VK
186 break;
187 }
d8d6e1a4
VK
188 if (bMsgNotNeeded)
189 delete pMsg;
05d9bba3
VK
190 }
191 }
192
39d7a7ed 193 CompleteSync(RCC_COMM_FAILURE); // Abort active sync operation
3a32dee8 194 DebugPrintf("Network receiver thread stopped");
05d9bba3 195 ChangeState(STATE_DISCONNECTED);
9d72bde1
VK
196 free(pRawMsg);
197 free(pMsgBuffer);
8f7e2482
VK
198
199 // Close socket
200 shutdown(m_hSocket, SHUT_WR);
201 while(recv(m_hSocket, szBuffer, 128, 0) > 0);
202 shutdown(m_hSocket, SHUT_RD);
203 closesocket(m_hSocket);
ccdbbb52 204 return THREAD_OK;
05d9bba3
VK
205}
206
207
208//
209// Connect to server
210//
211
3a32dee8 212DWORD LIBNXCL_EXPORTABLE NXCConnect(char *szServer, char *szLogin, char *szPassword)
05d9bba3
VK
213{
214 struct sockaddr_in servAddr;
215 CSCPMessage msg, *pResp;
99eee1db 216 BYTE szPasswordHash[SHA1_DIGEST_SIZE];
3a32dee8 217 DWORD dwRetCode = RCC_COMM_FAILURE;
05d9bba3 218
55198bf4 219 if (g_dwState == STATE_DISCONNECTED)
05d9bba3 220 {
55198bf4 221 ChangeState(STATE_CONNECTING);
05d9bba3 222
55198bf4
VK
223 // Reset unique message ID
224 g_dwMsgId = 1;
05d9bba3 225
55198bf4
VK
226 // Prepare address structure
227 memset(&servAddr, 0, sizeof(struct sockaddr_in));
228 servAddr.sin_family = AF_INET;
229 servAddr.sin_port = htons((WORD)SERVER_LISTEN_PORT);
230 servAddr.sin_addr.s_addr = inet_addr(szServer);
231 if (servAddr.sin_addr.s_addr == INADDR_NONE)
232 {
233 struct hostent *hs;
05d9bba3 234
55198bf4
VK
235 hs = gethostbyname(szServer);
236 if (hs != NULL)
237 memcpy(&servAddr.sin_addr, hs->h_addr, hs->h_length);
238 }
05d9bba3 239
55198bf4
VK
240 if (servAddr.sin_addr.s_addr != INADDR_NONE)
241 {
242 // Create socket
243 if ((m_hSocket = socket(AF_INET, SOCK_STREAM, 0)) != -1)
244 {
245 // Connect to target
246 if (connect(m_hSocket, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) == 0)
247 {
248 // Start receiver thread
249 ThreadCreate(NetReceiver, 0, NULL);
05d9bba3 250
55198bf4
VK
251 // Prepare login message
252 msg.SetId(g_dwMsgId++);
253 msg.SetCode(CMD_LOGIN);
254 msg.SetVariable(VID_LOGIN_NAME, szLogin);
99eee1db
VK
255 CalculateSHA1Hash((BYTE *)szPassword, strlen(szPassword), szPasswordHash);
256 msg.SetVariable(VID_PASSWORD, szPasswordHash, SHA1_DIGEST_SIZE);
55198bf4
VK
257
258 if (SendMsg(&msg))
259 {
260 // Receive responce message
261 pResp = m_msgWaitQueue.WaitForMessage(CMD_LOGIN_RESP, msg.GetId(), 2000);
3a32dee8 262 if (pResp != NULL)
55198bf4 263 {
3a32dee8 264 dwRetCode = pResp->GetVariableLong(VID_RCC);
55198bf4
VK
265 delete pResp;
266 }
3a32dee8
VK
267 else
268 {
269 // Connection is broken or timed out
270 dwRetCode = RCC_TIMEOUT;
271 }
55198bf4
VK
272 }
273
3a32dee8
VK
274 if (dwRetCode != RCC_SUCCESS)
275 shutdown(m_hSocket, 2);
276 }
277
278 if (dwRetCode != RCC_SUCCESS)
279 {
280 closesocket(m_hSocket);
281 m_hSocket = -1;
55198bf4 282 }
55198bf4
VK
283 }
284 }
3a32dee8 285 CallEventHandler(NXC_EVENT_LOGIN_RESULT, dwRetCode, NULL);
39d7a7ed 286 ChangeState(dwRetCode == RCC_SUCCESS ? STATE_CONNECTED : STATE_DISCONNECTED);
3a32dee8
VK
287 }
288 else
289 {
290 dwRetCode = RCC_OUT_OF_STATE_REQUEST;
05d9bba3
VK
291 }
292
3a32dee8 293 return dwRetCode;
05d9bba3
VK
294}
295
296
05d9bba3
VK
297//
298// Disconnect from server
299//
300
8aeffdee 301void LIBNXCL_EXPORTABLE NXCDisconnect(void)
05d9bba3
VK
302{
303 // Close socket
8f7e2482 304 shutdown(m_hSocket, SHUT_RDWR);
05d9bba3
VK
305 closesocket(m_hSocket);
306
307 // Clear message wait queue
308 m_msgWaitQueue.Clear();
309}
d8d6e1a4
VK
310
311
312//
313// Wait for specific message
314//
315
74dccebe 316CSCPMessage *WaitForMessage(WORD wCode, DWORD dwId, DWORD dwTimeOut)
d8d6e1a4 317{
74dccebe
VK
318 return m_msgWaitQueue.WaitForMessage(wCode, dwId, dwTimeOut);
319}
320
321
322//
323// Wait for specific raw message
324//
325
326CSCP_MESSAGE *WaitForRawMessage(WORD wCode, DWORD dwId, DWORD dwTimeOut)
327{
328 return m_msgWaitQueue.WaitForRawMessage(wCode, dwId, dwTimeOut);
d8d6e1a4 329}
9ed4eaff
VK
330
331
332//
333// Wait for request completion notification and extract result code
334// from recived message
335//
336
337DWORD WaitForRCC(DWORD dwRqId)
338{
339 CSCPMessage *pResponce;
340 DWORD dwRetCode;
341
342 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 2000);
343 if (pResponce != NULL)
344 {
345 dwRetCode = pResponce->GetVariableLong(VID_RCC);
346 delete pResponce;
347 }
348 else
349 {
350 dwRetCode = RCC_TIMEOUT;
351 }
352 return dwRetCode;
353}