license headers in libnetxms changed to LGPL
[public/netxms.git] / src / libnetxms / nxcp.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** NetXMS Foundation Library
68f384ea 4** Copyright (C) 2003-2010 Victor Kirhenshtein
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
68f384ea
VK
7** it under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation; either version 3 of the License, or
5039dede
AK
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**
68f384ea 16** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: nxcp.cpp
21**
22**/
23
24#include "libnetxms.h"
25
7b33ff5d
VK
26#ifdef _WIN32
27#define read _read
28#define close _close
29#endif
30
5039dede
AK
31
32//
33// Constants
34//
35
36#define FILE_BUFFER_SIZE 32768
37
38
39//
40// Get symbolic name for message code
41//
42
43TCHAR LIBNETXMS_EXPORTABLE *NXCPMessageCodeName(WORD wCode, TCHAR *pszBuffer)
44{
45 static const TCHAR *pszMsgNames[] =
46 {
47 _T("CMD_LOGIN"),
48 _T("CMD_LOGIN_RESP"),
49 _T("CMD_KEEPALIVE"),
50 _T("CMD_SET_ALARM_HD_STATE"),
51 _T("CMD_GET_OBJECTS"),
52 _T("CMD_OBJECT"),
53 _T("CMD_DELETE_OBJECT"),
54 _T("CMD_MODIFY_OBJECT"),
55 _T("CMD_OBJECT_LIST_END"),
56 _T("CMD_OBJECT_UPDATE"),
57 _T("CMD_GET_EVENTS"),
58 _T("CMD_EVENTLOG_RECORDS"),
59 _T("CMD_GET_CONFIG_VARLIST"),
60 _T("CMD_SET_CONFIG_VARIABLE"),
61 _T("CMD_GET_OBJECT_TOOLS"),
62 _T("CMD_EXECUTE_ACTION"),
63 _T("CMD_DELETE_CONFIG_VARIABLE"),
64 _T("CMD_NOTIFY"),
65 _T("CMD_TRAP"),
66 _T("CMD_OPEN_EPP"),
67 _T("CMD_CLOSE_EPP"),
68 _T("CMD_SAVE_EPP"),
69 _T("CMD_EPP_RECORD"),
870d2546 70 _T("CMD_EVENT_DB_UPDATE"),
15edffbf 71 _T("CMD_TRAP_CFG_UPDATE"),
5039dede
AK
72 _T("CMD_SET_EVENT_INFO"),
73 _T("CMD_EVENT_DB_RECORD"),
74 _T("CMD_LOAD_EVENT_DB"),
75 _T("CMD_REQUEST_COMPLETED"),
76 _T("CMD_LOAD_USER_DB"),
77 _T("CMD_USER_DATA"),
78 _T("CMD_GROUP_DATA"),
79 _T("CMD_USER_DB_EOF"),
80 _T("CMD_UPDATE_USER"),
81 _T("CMD_DELETE_USER"),
82 _T("CMD_CREATE_USER"),
83 _T("CMD_LOCK_USER_DB"),
84 _T("CMD_UNLOCK_USER_DB"),
85 _T("CMD_USER_DB_UPDATE"),
86 _T("CMD_SET_PASSWORD"),
87 _T("CMD_GET_NODE_DCI_LIST"),
88 _T("CMD_NODE_DCI"),
f727d089 89 _T("CMD_GET_LOG_DATA"),
5039dede
AK
90 _T("CMD_DELETE_NODE_DCI"),
91 _T("CMD_MODIFY_NODE_DCI"),
92 _T("CMD_UNLOCK_NODE_DCI_LIST"),
93 _T("CMD_SET_OBJECT_MGMT_STATUS"),
94 _T("CMD_CREATE_NEW_DCI"),
95 _T("CMD_GET_DCI_DATA"),
96 _T("CMD_DCI_DATA"),
97 _T("CMD_GET_MIB_TIMESTAMP"),
98 _T("CMD_GET_MIB"),
6d738067 99 _T("CMD_TEST_DCI_TRANSFORMATION"),
ab621f39 100 _T("CMD_GET_JOB_LIST"),
5039dede
AK
101 _T("CMD_CREATE_OBJECT"),
102 _T("CMD_GET_EVENT_NAMES"),
103 _T("CMD_EVENT_NAME_LIST"),
104 _T("CMD_BIND_OBJECT"),
105 _T("CMD_UNBIND_OBJECT"),
93599cfd 106 _T("CMD_UNINSTALL_AGENT_POLICY"),
f727d089
VK
107 _T("CMD_OPEN_SERVER_LOG"),
108 _T("CMD_CLOSE_SERVER_LOG"),
109 _T("CMD_QUERY_LOG"),
5039dede
AK
110 _T("CMD_AUTHENTICATE"),
111 _T("CMD_GET_PARAMETER"),
112 _T("CMD_GET_LIST"),
113 _T("CMD_ACTION"),
d83dc1f0
VK
114 _T("CMD_GET_CURRENT_USER_ATTR"),
115 _T("CMD_SET_CURRENT_USER_ATTR"),
5039dede
AK
116 _T("CMD_GET_ALL_ALARMS"),
117 _T("CMD_GET_ALARM"),
118 _T("CMD_ACK_ALARM"),
119 _T("CMD_ALARM_UPDATE"),
120 _T("CMD_ALARM_DATA"),
121 _T("CMD_DELETE_ALARM"),
9d30afb8
VK
122 _T("0x004C"), // was CMD_LOCK_ACTION_DB
123 _T("0x004D"), // was CMD_UNLOCK_ACTION_DB
5039dede
AK
124 _T("CMD_LOAD_ACTIONS"),
125 _T("CMD_ACTION_DB_UPDATE"),
126 _T("CMD_MODIFY_ACTION"),
127 _T("CMD_CREATE_ACTION"),
128 _T("CMD_DELETE_ACTION"),
129 _T("CMD_ACTION_DATA"),
130 _T("CMD_GET_CONTAINER_CAT_LIST"),
131 _T("CMD_CONTAINER_CAT_DATA"),
132 _T("CMD_DELETE_CONTAINER_CAT"),
133 _T("CMD_CREATE_CONTAINER_CAT"),
134 _T("CMD_MODIFY_CONTAINER_CAT"),
135 _T("CMD_POLL_NODE"),
136 _T("CMD_POLLING_INFO"),
137 _T("CMD_COPY_DCI"),
138 _T("CMD_WAKEUP_NODE"),
139 _T("CMD_DELETE_EVENT_TEMPLATE"),
140 _T("CMD_GENERATE_EVENT_CODE"),
15edffbf
VK
141 _T("0x5F"), // was: CMD_LOCK_TRAP_CFG
142 _T("0x60"), // was: CMD_UNLOCK_TRAP_CFG
5039dede
AK
143 _T("CMD_CREATE_TRAP"),
144 _T("CMD_MODIFY_TRAP"),
145 _T("CMD_DELETE_TRAP"),
146 _T("CMD_LOAD_TRAP_CFG"),
147 _T("CMD_TRAP_CFG_RECORD"),
148 _T("CMD_QUERY_PARAMETER"),
149 _T("CMD_GET_SERVER_INFO"),
150 _T("CMD_SET_DCI_STATUS"),
151 _T("CMD_FILE_DATA"),
152 _T("CMD_TRANSFER_FILE"),
153 _T("CMD_UPGRADE_AGENT"),
154 _T("CMD_GET_PACKAGE_LIST"),
155 _T("CMD_PACKAGE_INFO"),
156 _T("CMD_REMOVE_PACKAGE"),
157 _T("CMD_INSTALL_PACKAGE"),
158 _T("CMD_LOCK_PACKAGE_DB"),
159 _T("CMD_UNLOCK_PACKAGE_DB"),
160 _T("CMD_ABORT_FILE_TRANSFER"),
161 _T("CMD_CHECK_NETWORK_SERVICE"),
162 _T("CMD_GET_AGENT_CONFIG"),
163 _T("CMD_UPDATE_AGENT_CONFIG"),
164 _T("CMD_GET_PARAMETER_LIST"),
165 _T("CMD_DEPLOY_PACKAGE"),
166 _T("CMD_INSTALLER_INFO"),
167 _T("CMD_GET_LAST_VALUES"),
168 _T("CMD_APPLY_TEMPLATE"),
169 _T("CMD_SET_USER_VARIABLE"),
170 _T("CMD_GET_USER_VARIABLE"),
171 _T("CMD_ENUM_USER_VARIABLES"),
172 _T("CMD_DELETE_USER_VARIABLE"),
173 _T("CMD_ADM_MESSAGE"),
174 _T("CMD_ADM_REQUEST"),
175 _T("CMD_CHANGE_IP_ADDR"),
176 _T("CMD_REQUEST_SESSION_KEY"),
177 _T("CMD_ENCRYPTED_MESSAGE"),
178 _T("CMD_SESSION_KEY"),
179 _T("CMD_REQUEST_ENCRYPTION"),
180 _T("CMD_GET_ROUTING_TABLE"),
181 _T("CMD_EXEC_TABLE_TOOL"),
182 _T("CMD_TABLE_DATA"),
f40831eb 183 _T("CMD_CANCEL_JOB"),
5039dede
AK
184 _T("CMD_CHANGE_SUBSCRIPTION"),
185 _T("CMD_GET_SYSLOG"),
186 _T("CMD_SYSLOG_RECORDS"),
ab621f39 187 _T("CMD_JOB_CHANGE_NOTIFICATION"),
fc61a868 188 _T("CMD_DEPLOY_AGENT_POLICY"),
f727d089 189 _T("CMD_LOG_DATA"),
5039dede 190 _T("CMD_GET_OBJECT_TOOL_DETAILS"),
0e950f45
VK
191 _T("0x0091"), // was: CMD_LOCK_OBJECT_TOOLS
192 _T("0x0092"), // was: CMD_UNLOCK_OBJECT_TOOLS
5039dede
AK
193 _T("CMD_UPDATE_OBJECT_TOOL"),
194 _T("CMD_DELETE_OBJECT_TOOL"),
195 _T("CMD_SETUP_PROXY_CONNECTION"),
196 _T("CMD_GENERATE_OBJECT_TOOL_ID"),
197 _T("CMD_GET_SERVER_STATS"),
198 _T("CMD_GET_SCRIPT_LIST"),
199 _T("CMD_GET_SCRIPT"),
200 _T("CMD_UPDATE_SCRIPT"),
201 _T("CMD_DELETE_SCRIPT"),
202 _T("CMD_RENAME_SCRIPT"),
203 _T("CMD_GET_SESSION_LIST"),
204 _T("CMD_KILL_SESSION"),
205 _T("CMD_GET_TRAP_LOG"),
206 _T("CMD_TRAP_LOG_RECORDS"),
207 _T("CMD_START_SNMP_WALK"),
208 _T("CMD_SNMP_WALK_DATA"),
209 _T("CMD_GET_MAP_LIST"),
210 _T("CMD_LOAD_MAP"),
211 _T("CMD_SAVE_MAP"),
212 _T("CMD_DELETE_MAP"),
213 _T("CMD_RESOLVE_MAP_NAME"),
214 _T("CMD_SUBMAP_DATA"),
215 _T("CMD_UPLOAD_SUBMAP_BK_IMAGE"),
216 _T("CMD_GET_SUBMAP_BK_IMAGE"),
217 _T("CMD_GET_MODULE_LIST"),
218 _T("CMD_UPDATE_MODULE_INFO"),
219 _T("CMD_COPY_USER_VARIABLE"),
220 _T("CMD_RESOLVE_DCI_NAMES"),
221 _T("CMD_GET_MY_CONFIG"),
222 _T("CMD_GET_AGENT_CFG_LIST"),
223 _T("CMD_OPEN_AGENT_CONFIG"),
224 _T("CMD_SAVE_AGENT_CONFIG"),
225 _T("CMD_DELETE_AGENT_CONFIG"),
226 _T("CMD_SWAP_AGENT_CONFIGS"),
227 _T("CMD_TERMINATE_ALARM"),
228 _T("CMD_GET_NXCP_CAPS"),
229 _T("CMD_NXCP_CAPS"),
230 _T("CMD_GET_OBJECT_COMMENTS"),
231 _T("CMD_UPDATE_OBJECT_COMMENTS"),
232 _T("CMD_ENABLE_AGENT_TRAPS"),
233 _T("CMD_PUSH_DCI_DATA"),
234 _T("CMD_GET_ADDR_LIST"),
235 _T("CMD_SET_ADDR_LIST"),
236 _T("CMD_RESET_COMPONENT"),
237 _T("CMD_GET_DCI_EVENTS_LIST"),
a7ff20a5
VK
238 _T("CMD_EXPORT_CONFIGURATION"),
239 _T("CMD_IMPORT_CONFIGURATION"),
5039dede
AK
240 _T("CMD_GET_TRAP_CFG_RO"),
241 _T("CMD_SNMP_REQUEST"),
242 _T("CMD_GET_DCI_INFO"),
243 _T("CMD_GET_GRAPH_LIST"),
244 _T("CMD_DEFINE_GRAPH"),
245 _T("CMD_DELETE_GRAPH"),
74526d25 246 _T("CMD_GET_PERFTAB_DCI_LIST"),
5039dede
AK
247 _T("CMD_ADD_CA_CERTIFICATE"),
248 _T("CMD_DELETE_CERTIFICATE"),
249 _T("CMD_GET_CERT_LIST"),
250 _T("CMD_UPDATE_CERT_COMMENTS"),
251 _T("CMD_QUERY_L2_TOPOLOGY"),
252 _T("CMD_AUDIT_RECORD"),
253 _T("CMD_GET_AUDIT_LOG"),
254 _T("CMD_SEND_SMS"),
255 _T("CMD_GET_COMMUNITY_LIST"),
256 _T("CMD_UPDATE_COMMUNITY_LIST"),
257 _T("CMD_GET_SITUATION_LIST"),
258 _T("CMD_DELETE_SITUATION"),
259 _T("CMD_CREATE_SITUATION"),
260 _T("CMD_DEL_SITUATION_INSTANCE"),
261 _T("CMD_UPDATE_SITUATION"),
262 _T("CMD_SITUATION_DATA"),
263 _T("CMD_SITUATION_CHANGE"),
264 _T("CMD_CREATE_MAP"),
265 _T("CMD_WEBMAP_ADD"),
266 _T("CMD_WEBMAP_UPDATE_PROPS"),
267 _T("CMD_WEBMAP_UPDATE_DATA"),
268 _T("CMD_WEBMAP_DELETE"),
269 _T("CMD_WEBMAP_GET_DATA"),
270 _T("CMD_WEBMAP_GET_LIST"),
271 _T("CMD_CONFIG_SET_CLOB"),
272 _T("CMD_CONFIG_GET_CLOB"),
273 _T("CMD_RENAME_MAP"),
274 _T("CMD_CLEAR_DCI_DATA"),
275 _T("CMD_GET_LICENSE"),
276 _T("CMD_CHECK_LICENSE"),
277 _T("CMD_RELEASE_LICENSE"),
278 _T("CMD_ISC_CONNECT_TO_SERVICE"),
279 _T("CMD_REGISTER_AGENT"),
280 _T("CMD_GET_SERVER_FILE"),
df8a4ca2
VK
281 _T("CMD_FORWARD_EVENT"),
282 _T("CMD_GET_USM_CREDENTIALS"),
071fd171
VK
283 _T("CMD_UPDATE_USM_CREDENTIALS"),
284 _T("CMD_GET_DCI_THRESHOLDS")
5039dede
AK
285 };
286
071fd171 287 if ((wCode >= CMD_LOGIN) && (wCode <= CMD_GET_DCI_THRESHOLDS))
5039dede
AK
288 _tcscpy(pszBuffer, pszMsgNames[wCode - CMD_LOGIN]);
289 else
ac4689a8 290 _sntprintf(pszBuffer, 64, _T("CMD_0x%04X"), wCode);
5039dede
AK
291 return pszBuffer;
292}
293
294
295//
296// Receive raw CSCP message from network
297// If pMsg is NULL, temporary buffer will be re-initialized
298// Returns message size on success or:
299// 0 if connection is closed
300// <0 on socket errors
301// 1 if message is too large to fit in buffer (normal messages is at least 16
302// bytes long, so we never get length of 1 for valid message)
303// In this case, only message header will be copied into buffer
304// 2 Message decryption failed
305// 3 Receive timeout
306//
307
308int LIBNETXMS_EXPORTABLE RecvNXCPMessage(SOCKET hSocket, CSCP_MESSAGE *pMsg,
309 CSCP_BUFFER *pBuffer, DWORD dwMaxMsgSize,
310 CSCP_ENCRYPTION_CONTEXT **ppCtx,
311 BYTE *pDecryptionBuffer, DWORD dwTimeout)
312{
313 DWORD dwMsgSize = 0, dwBytesRead = 0, dwBytesToCopy;
314 int iErr;
315 BOOL bSkipMsg = FALSE;
316
317 // Initialize buffer if requested
318 if (pMsg == NULL)
319 {
320 pBuffer->dwBufSize = 0;
321 pBuffer->dwBufPos = 0;
322 return 0;
323 }
324
325 // Check if we have something in buffer
326 if (pBuffer->dwBufSize > 0)
327 {
328 // Handle the case when entire message header have not been read into the buffer
329 if (pBuffer->dwBufSize < CSCP_HEADER_SIZE)
330 {
331 // Most likely we are at the buffer end, so move content
332 // to the beginning
333 memmove(pBuffer->szBuffer, &pBuffer->szBuffer[pBuffer->dwBufPos], pBuffer->dwBufSize);
334 pBuffer->dwBufPos = 0;
335
336 // Receive new portion of data from the network
337 // and append it to existing data in buffer
338 iErr = RecvEx(hSocket, &pBuffer->szBuffer[pBuffer->dwBufSize],
339 CSCP_TEMP_BUF_SIZE - pBuffer->dwBufSize, 0, dwTimeout);
340 if (iErr <= 0)
341 return (iErr == -2) ? 3 : iErr;
342 pBuffer->dwBufSize += (DWORD)iErr;
343 }
344
345 // Get message size from message header and copy available
346 // message bytes from buffer
347 dwMsgSize = ntohl(((CSCP_MESSAGE *)(&pBuffer->szBuffer[pBuffer->dwBufPos]))->dwSize);
348 if (dwMsgSize > dwMaxMsgSize)
349 {
350 bSkipMsg = TRUE; // Message is too large, will skip it
351 memcpy(pMsg, &pBuffer->szBuffer[pBuffer->dwBufPos], CSCP_HEADER_SIZE);
352 }
353 dwBytesRead = min(dwMsgSize, pBuffer->dwBufSize);
354 if (!bSkipMsg)
355 memcpy(pMsg, &pBuffer->szBuffer[pBuffer->dwBufPos], dwBytesRead);
356 pBuffer->dwBufSize -= dwBytesRead;
357 pBuffer->dwBufPos = (pBuffer->dwBufSize > 0) ? (pBuffer->dwBufPos + dwBytesRead) : 0;
358 if (dwBytesRead == dwMsgSize)
359 goto decrypt_message;
360 }
361
362 // Receive rest of message from the network
363 do
364 {
365 iErr = RecvEx(hSocket, pBuffer->szBuffer, CSCP_TEMP_BUF_SIZE, 0, dwTimeout);
366 if (iErr <= 0)
367 return (iErr == -2) ? 3 : iErr;
368
369 if (dwBytesRead == 0 &&
370 iErr >= (sizeof(((CSCP_MESSAGE *)(pBuffer->szBuffer))->dwSize))) // New message?
371 {
372 dwMsgSize = ntohl(((CSCP_MESSAGE *)(pBuffer->szBuffer))->dwSize);
373 if (dwMsgSize > dwMaxMsgSize)
374 {
375 bSkipMsg = TRUE; // Message is too large, just skip it
376 memcpy(pMsg, pBuffer->szBuffer, CSCP_HEADER_SIZE);
377 }
378 }
379 dwBytesToCopy = min((DWORD)iErr, dwMsgSize - dwBytesRead);
380 if (!bSkipMsg)
381 memcpy(((char *)pMsg) + dwBytesRead, pBuffer->szBuffer, dwBytesToCopy);
382 dwBytesRead += dwBytesToCopy;
383 }
384 while(dwBytesRead < dwMsgSize);
385
386 // Check if we have something left in buffer
387 if (dwBytesToCopy < (DWORD)iErr)
388 {
389 pBuffer->dwBufPos = dwBytesToCopy;
390 pBuffer->dwBufSize = (DWORD)iErr - dwBytesToCopy;
391 }
392
393 // Check for encrypted message
394decrypt_message:
395 if ((!bSkipMsg) && (ntohs(pMsg->wCode) == CMD_ENCRYPTED_MESSAGE))
396 {
397 if ((*ppCtx != NULL) && (*ppCtx != PROXY_ENCRYPTION_CTX))
398 {
399 if (CSCPDecryptMessage(*ppCtx, (CSCP_ENCRYPTED_MESSAGE *)pMsg, pDecryptionBuffer))
400 {
401 dwMsgSize = ntohl(pMsg->dwSize);
402 }
403 else
404 {
405 dwMsgSize = 2; // Decryption failed
406 }
407 }
408 else
409 {
410 if (*ppCtx != PROXY_ENCRYPTION_CTX)
411 dwMsgSize = 2;
412 }
413 }
414
415 return bSkipMsg ? 1 : (int)dwMsgSize;
416}
417
418
419//
420// Create CSCP message with raw data (MF_BINARY flag)
421// If pBuffer is NULL, new buffer is allocated with malloc()
422// Buffer should be of dwDataSize + CSCP_HEADER_SIZE + 8 bytes.
423//
424
425CSCP_MESSAGE LIBNETXMS_EXPORTABLE *CreateRawNXCPMessage(WORD wCode, DWORD dwId, WORD wFlags,
426 DWORD dwDataSize, void *pData,
427 CSCP_MESSAGE *pBuffer)
428{
429 CSCP_MESSAGE *pMsg;
430 DWORD dwPadding;
431
432 if (pBuffer == NULL)
433 pMsg = (CSCP_MESSAGE *)malloc(dwDataSize + CSCP_HEADER_SIZE + 8);
434 else
435 pMsg = pBuffer;
436
437 // Message should be aligned to 8 bytes boundary
438 dwPadding = (8 - ((dwDataSize + CSCP_HEADER_SIZE) % 8)) & 7;
439
440 pMsg->wCode = htons(wCode);
441 pMsg->wFlags = htons(MF_BINARY | wFlags);
442 pMsg->dwId = htonl(dwId);
443 pMsg->dwSize = htonl(dwDataSize + CSCP_HEADER_SIZE + dwPadding);
444 pMsg->dwNumVars = htonl(dwDataSize); // dwNumVars contains actual data size for binary message
445 memcpy(pMsg->df, pData, dwDataSize);
446
447 return pMsg;
448}
449
450
451//
452// Send file over CSCP
453//
454
455BOOL LIBNETXMS_EXPORTABLE SendFileOverNXCP(SOCKET hSocket, DWORD dwId, const TCHAR *pszFile,
6173bea8
VK
456 CSCP_ENCRYPTION_CONTEXT *pCtx, long offset,
457 void (* progressCallback)(INT64, void *), void *cbArg)
5039dede
AK
458{
459#ifndef UNDER_CE
460 int hFile, iBytes;
461#else
462 FILE *hFile;
463 int iBytes;
464#endif
6173bea8 465 INT64 bytesTransferred = 0;
5039dede
AK
466 DWORD dwPadding;
467 BOOL bResult = FALSE;
468 CSCP_MESSAGE *pMsg;
469 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
470
471#ifndef UNDER_CE
472 hFile = _topen(pszFile, O_RDONLY | O_BINARY);
473 if (hFile != -1)
c3a8e638 474 {
901a5a9b
VK
475 if (lseek(hFile, offset, offset < 0 ? SEEK_END : SEEK_SET) != -1)
476 {
5039dede
AK
477#else
478 hFile = _tfopen(pszFile, _T("rb"));
479 if (hFile != NULL)
5039dede 480 {
c3a8e638
AK
481 if (fseek(hFile, offset, offset < 0 ? SEEK_END : SEEK_SET) == 0)
482 {
483#endif
901a5a9b
VK
484 // Allocate message and prepare it's header
485 pMsg = (CSCP_MESSAGE *)malloc(FILE_BUFFER_SIZE + CSCP_HEADER_SIZE + 8);
486 pMsg->dwId = htonl(dwId);
487 pMsg->wCode = htons(CMD_FILE_DATA);
488 pMsg->wFlags = htons(MF_BINARY);
489
490 while(1)
491 {
5039dede 492#ifndef UNDER_CE
901a5a9b
VK
493 iBytes = read(hFile, pMsg->df, FILE_BUFFER_SIZE);
494 if (iBytes < 0)
495 break;
5039dede 496#else
901a5a9b
VK
497 iBytes = fread(pMsg->df, 1, FILE_BUFFER_SIZE, hFile);
498 if (ferror(hFile))
499 break; // Read error
5039dede
AK
500#endif
501
901a5a9b
VK
502 // Message should be aligned to 8 bytes boundary
503 dwPadding = (8 - (((DWORD)iBytes + CSCP_HEADER_SIZE) % 8)) & 7;
504 pMsg->dwSize = htonl((DWORD)iBytes + CSCP_HEADER_SIZE + dwPadding);
505 pMsg->dwNumVars = htonl((DWORD)iBytes); // dwNumVars contains actual data size for binary message
506 if (iBytes < FILE_BUFFER_SIZE)
507 pMsg->wFlags |= htons(MF_END_OF_FILE);
508
509 if (pCtx != NULL)
5039dede 510 {
901a5a9b
VK
511 pEnMsg = CSCPEncryptMessage(pCtx, pMsg);
512 if (pEnMsg != NULL)
c3a8e638 513 {
901a5a9b
VK
514 SendEx(hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0);
515 free(pEnMsg);
c3a8e638 516 }
901a5a9b
VK
517 }
518 else
519 {
520 if (SendEx(hSocket, (char *)pMsg, (DWORD)iBytes + CSCP_HEADER_SIZE + dwPadding, 0) <= 0)
521 break; // Send error
522 }
523
6173bea8
VK
524 if (progressCallback != NULL)
525 {
526 bytesTransferred += iBytes;
527 progressCallback(bytesTransferred, cbArg);
528 }
529
901a5a9b
VK
530 if (iBytes < FILE_BUFFER_SIZE)
531 {
532 // End of file
533 bResult = TRUE;
534 break;
535 }
536 }
537
538 free(pMsg);
539 }
5039dede 540#ifndef UNDER_CE
901a5a9b 541 close(hFile);
5039dede 542#else
901a5a9b 543 fclose(hFile);
5039dede 544#endif
901a5a9b 545 }
5039dede
AK
546
547 // If file upload failed, send CMD_ABORT_FILE_TRANSFER
548 if (!bResult)
549 {
550 CSCP_MESSAGE msg;
551
552 msg.dwId = htonl(dwId);
553 msg.wCode = htons(CMD_ABORT_FILE_TRANSFER);
554 msg.wFlags = htons(MF_BINARY);
555 msg.dwNumVars = 0;
556 msg.dwSize = htonl(CSCP_HEADER_SIZE);
557 if (pCtx != NULL)
558 {
559 pEnMsg = CSCPEncryptMessage(pCtx, &msg);
560 if (pEnMsg != NULL)
561 {
562 SendEx(hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0);
563 free(pEnMsg);
564 }
565 }
566 else
567 {
568 SendEx(hSocket, (char *)&msg, CSCP_HEADER_SIZE, 0);
569 }
570 }
571
572 return bResult;
573}
574
575
576//
577// Get version of NXCP used by peer
578//
579
580BOOL LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(SOCKET hSocket, int *pnVersion)
581{
582 CSCP_MESSAGE msg;
583 CSCP_ENCRYPTION_CONTEXT *pDummyCtx = NULL;
584 CSCP_BUFFER *pBuffer;
585 BOOL bRet = FALSE;
586 int nSize;
587
588 msg.dwId = 0;
589 msg.dwNumVars = 0;
590 msg.dwSize = htonl(CSCP_HEADER_SIZE);
591 msg.wCode = htons(CMD_GET_NXCP_CAPS);
592 msg.wFlags = htons(MF_CONTROL);
593 if (SendEx(hSocket, &msg, CSCP_HEADER_SIZE, 0) == CSCP_HEADER_SIZE)
594 {
595 pBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
596 RecvNXCPMessage(0, NULL, pBuffer, 0, NULL, NULL, 0);
597 nSize = RecvNXCPMessage(hSocket, &msg, pBuffer, CSCP_HEADER_SIZE, &pDummyCtx, NULL, 30000);
598 if ((nSize == CSCP_HEADER_SIZE) &&
599 (ntohs(msg.wCode) == CMD_NXCP_CAPS) &&
600 (ntohs(msg.wFlags) & MF_CONTROL))
601 {
602 bRet = TRUE;
603 *pnVersion = ntohl(msg.dwNumVars) >> 24;
604 }
605 else if ((nSize == 1) || (nSize == 3) || (nSize >= CSCP_HEADER_SIZE))
606 {
607 // We don't receive any answer or receive invalid answer -
608 // assume that peer doesn't understand CMD_GET_NXCP_CAPS message
609 // and set version number to 1
610 bRet = TRUE;
611 *pnVersion = 1;
612 }
613 free(pBuffer);
614 }
615 return bRet;
616}