6b2575486981e6621a7964c50a0b8e2b3c43a2cc
[public/netxms.git] / src / libnetxms / nxcp.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2013 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
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
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 Lesser 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 ** File: nxcp.cpp
21 **
22 **/
23
24 #include "libnetxms.h"
25 #include <nxstat.h>
26
27 #ifdef _WIN32
28 #define read _read
29 #define close _close
30 #endif
31
32 /**
33 * Get symbolic name for message code
34 */
35 TCHAR LIBNETXMS_EXPORTABLE *NXCPMessageCodeName(WORD wCode, TCHAR *pszBuffer)
36 {
37 static const TCHAR *pszMsgNames[] =
38 {
39 _T("CMD_LOGIN"),
40 _T("CMD_LOGIN_RESP"),
41 _T("CMD_KEEPALIVE"),
42 _T("CMD_OPEN_HELPDESK_ISSUE"),
43 _T("CMD_GET_OBJECTS"),
44 _T("CMD_OBJECT"),
45 _T("CMD_DELETE_OBJECT"),
46 _T("CMD_MODIFY_OBJECT"),
47 _T("CMD_OBJECT_LIST_END"),
48 _T("CMD_OBJECT_UPDATE"),
49 _T("CMD_GET_EVENTS"),
50 _T("CMD_EVENTLOG_RECORDS"),
51 _T("CMD_GET_CONFIG_VARLIST"),
52 _T("CMD_SET_CONFIG_VARIABLE"),
53 _T("CMD_GET_OBJECT_TOOLS"),
54 _T("CMD_EXECUTE_ACTION"),
55 _T("CMD_DELETE_CONFIG_VARIABLE"),
56 _T("CMD_NOTIFY"),
57 _T("CMD_TRAP"),
58 _T("CMD_OPEN_EPP"),
59 _T("CMD_CLOSE_EPP"),
60 _T("CMD_SAVE_EPP"),
61 _T("CMD_EPP_RECORD"),
62 _T("CMD_EVENT_DB_UPDATE"),
63 _T("CMD_TRAP_CFG_UPDATE"),
64 _T("CMD_SET_EVENT_INFO"),
65 _T("CMD_EVENT_DB_RECORD"),
66 _T("CMD_LOAD_EVENT_DB"),
67 _T("CMD_REQUEST_COMPLETED"),
68 _T("CMD_LOAD_USER_DB"),
69 _T("CMD_USER_DATA"),
70 _T("CMD_GROUP_DATA"),
71 _T("CMD_USER_DB_EOF"),
72 _T("CMD_UPDATE_USER"),
73 _T("CMD_DELETE_USER"),
74 _T("CMD_CREATE_USER"),
75 _T("CMD_LOCK_USER_DB"),
76 _T("CMD_UNLOCK_USER_DB"),
77 _T("CMD_USER_DB_UPDATE"),
78 _T("CMD_SET_PASSWORD"),
79 _T("CMD_GET_NODE_DCI_LIST"),
80 _T("CMD_NODE_DCI"),
81 _T("CMD_GET_LOG_DATA"),
82 _T("CMD_DELETE_NODE_DCI"),
83 _T("CMD_MODIFY_NODE_DCI"),
84 _T("CMD_UNLOCK_NODE_DCI_LIST"),
85 _T("CMD_SET_OBJECT_MGMT_STATUS"),
86 _T("CMD_CREATE_NEW_DCI"),
87 _T("CMD_GET_DCI_DATA"),
88 _T("CMD_DCI_DATA"),
89 _T("CMD_GET_MIB_TIMESTAMP"),
90 _T("CMD_GET_MIB"),
91 _T("CMD_TEST_DCI_TRANSFORMATION"),
92 _T("CMD_GET_JOB_LIST"),
93 _T("CMD_CREATE_OBJECT"),
94 _T("CMD_GET_EVENT_NAMES"),
95 _T("CMD_EVENT_NAME_LIST"),
96 _T("CMD_BIND_OBJECT"),
97 _T("CMD_UNBIND_OBJECT"),
98 _T("CMD_UNINSTALL_AGENT_POLICY"),
99 _T("CMD_OPEN_SERVER_LOG"),
100 _T("CMD_CLOSE_SERVER_LOG"),
101 _T("CMD_QUERY_LOG"),
102 _T("CMD_AUTHENTICATE"),
103 _T("CMD_GET_PARAMETER"),
104 _T("CMD_GET_LIST"),
105 _T("CMD_ACTION"),
106 _T("CMD_GET_CURRENT_USER_ATTR"),
107 _T("CMD_SET_CURRENT_USER_ATTR"),
108 _T("CMD_GET_ALL_ALARMS"),
109 _T("CMD_GET_ALARM_COMMENTS"),
110 _T("CMD_ACK_ALARM"),
111 _T("CMD_ALARM_UPDATE"),
112 _T("CMD_ALARM_DATA"),
113 _T("CMD_DELETE_ALARM"),
114 _T("CMD_ADD_CLUSTER_NODE"),
115 _T("CMD_GET_POLICY_INVENTORY"),
116 _T("CMD_LOAD_ACTIONS"),
117 _T("CMD_ACTION_DB_UPDATE"),
118 _T("CMD_MODIFY_ACTION"),
119 _T("CMD_CREATE_ACTION"),
120 _T("CMD_DELETE_ACTION"),
121 _T("CMD_ACTION_DATA"),
122 _T("CMD_GET_CONTAINER_CAT_LIST"),
123 _T("CMD_CONTAINER_CAT_DATA"),
124 _T("CMD_DELETE_CONTAINER_CAT"),
125 _T("CMD_CREATE_CONTAINER_CAT"),
126 _T("CMD_MODIFY_CONTAINER_CAT"),
127 _T("CMD_POLL_NODE"),
128 _T("CMD_POLLING_INFO"),
129 _T("CMD_COPY_DCI"),
130 _T("CMD_WAKEUP_NODE"),
131 _T("CMD_DELETE_EVENT_TEMPLATE"),
132 _T("CMD_GENERATE_EVENT_CODE"),
133 _T("CMD_FIND_NODE_CONNECTION"),
134 _T("CMD_FIND_MAC_LOCATION"),
135 _T("CMD_CREATE_TRAP"),
136 _T("CMD_MODIFY_TRAP"),
137 _T("CMD_DELETE_TRAP"),
138 _T("CMD_LOAD_TRAP_CFG"),
139 _T("CMD_TRAP_CFG_RECORD"),
140 _T("CMD_QUERY_PARAMETER"),
141 _T("CMD_GET_SERVER_INFO"),
142 _T("CMD_SET_DCI_STATUS"),
143 _T("CMD_FILE_DATA"),
144 _T("CMD_TRANSFER_FILE"),
145 _T("CMD_UPGRADE_AGENT"),
146 _T("CMD_GET_PACKAGE_LIST"),
147 _T("CMD_PACKAGE_INFO"),
148 _T("CMD_REMOVE_PACKAGE"),
149 _T("CMD_INSTALL_PACKAGE"),
150 _T("CMD_LOCK_PACKAGE_DB"),
151 _T("CMD_UNLOCK_PACKAGE_DB"),
152 _T("CMD_ABORT_FILE_TRANSFER"),
153 _T("CMD_CHECK_NETWORK_SERVICE"),
154 _T("CMD_GET_AGENT_CONFIG"),
155 _T("CMD_UPDATE_AGENT_CONFIG"),
156 _T("CMD_GET_PARAMETER_LIST"),
157 _T("CMD_DEPLOY_PACKAGE"),
158 _T("CMD_INSTALLER_INFO"),
159 _T("CMD_GET_LAST_VALUES"),
160 _T("CMD_APPLY_TEMPLATE"),
161 _T("CMD_SET_USER_VARIABLE"),
162 _T("CMD_GET_USER_VARIABLE"),
163 _T("CMD_ENUM_USER_VARIABLES"),
164 _T("CMD_DELETE_USER_VARIABLE"),
165 _T("CMD_ADM_MESSAGE"),
166 _T("CMD_ADM_REQUEST"),
167 _T("CMD_GET_NETWORK_PATH"),
168 _T("CMD_REQUEST_SESSION_KEY"),
169 _T("CMD_ENCRYPTED_MESSAGE"),
170 _T("CMD_SESSION_KEY"),
171 _T("CMD_REQUEST_ENCRYPTION"),
172 _T("CMD_GET_ROUTING_TABLE"),
173 _T("CMD_EXEC_TABLE_TOOL"),
174 _T("CMD_TABLE_DATA"),
175 _T("CMD_CANCEL_JOB"),
176 _T("CMD_CHANGE_SUBSCRIPTION"),
177 _T("CMD_GET_SYSLOG"),
178 _T("CMD_SYSLOG_RECORDS"),
179 _T("CMD_JOB_CHANGE_NOTIFICATION"),
180 _T("CMD_DEPLOY_AGENT_POLICY"),
181 _T("CMD_LOG_DATA"),
182 _T("CMD_GET_OBJECT_TOOL_DETAILS"),
183 _T("CMD_EXECUTE_SERVER_COMMAND"),
184 _T("CMD_UPLOAD_FILE_TO_AGENT"),
185 _T("CMD_UPDATE_OBJECT_TOOL"),
186 _T("CMD_DELETE_OBJECT_TOOL"),
187 _T("CMD_SETUP_PROXY_CONNECTION"),
188 _T("CMD_GENERATE_OBJECT_TOOL_ID"),
189 _T("CMD_GET_SERVER_STATS"),
190 _T("CMD_GET_SCRIPT_LIST"),
191 _T("CMD_GET_SCRIPT"),
192 _T("CMD_UPDATE_SCRIPT"),
193 _T("CMD_DELETE_SCRIPT"),
194 _T("CMD_RENAME_SCRIPT"),
195 _T("CMD_GET_SESSION_LIST"),
196 _T("CMD_KILL_SESSION"),
197 _T("CMD_GET_TRAP_LOG"),
198 _T("CMD_TRAP_LOG_RECORDS"),
199 _T("CMD_START_SNMP_WALK"),
200 _T("CMD_SNMP_WALK_DATA"),
201 _T("CMD_GET_MAP_LIST"),
202 _T("CMD_LOAD_MAP"),
203 _T("CMD_SAVE_MAP"),
204 _T("CMD_DELETE_MAP"),
205 _T("CMD_RESOLVE_MAP_NAME"),
206 _T("CMD_SUBMAP_DATA"),
207 _T("CMD_UPLOAD_SUBMAP_BK_IMAGE"),
208 _T("CMD_GET_SUBMAP_BK_IMAGE"),
209 _T("CMD_GET_MODULE_LIST"),
210 _T("CMD_UPDATE_MODULE_INFO"),
211 _T("CMD_COPY_USER_VARIABLE"),
212 _T("CMD_RESOLVE_DCI_NAMES"),
213 _T("CMD_GET_MY_CONFIG"),
214 _T("CMD_GET_AGENT_CFG_LIST"),
215 _T("CMD_OPEN_AGENT_CONFIG"),
216 _T("CMD_SAVE_AGENT_CONFIG"),
217 _T("CMD_DELETE_AGENT_CONFIG"),
218 _T("CMD_SWAP_AGENT_CONFIGS"),
219 _T("CMD_TERMINATE_ALARM"),
220 _T("CMD_GET_NXCP_CAPS"),
221 _T("CMD_NXCP_CAPS"),
222 _T("CMD_GET_OBJECT_COMMENTS"),
223 _T("CMD_UPDATE_OBJECT_COMMENTS"),
224 _T("CMD_ENABLE_AGENT_TRAPS"),
225 _T("CMD_PUSH_DCI_DATA"),
226 _T("CMD_GET_ADDR_LIST"),
227 _T("CMD_SET_ADDR_LIST"),
228 _T("CMD_RESET_COMPONENT"),
229 _T("CMD_GET_DCI_EVENTS_LIST"),
230 _T("CMD_EXPORT_CONFIGURATION"),
231 _T("CMD_IMPORT_CONFIGURATION"),
232 _T("CMD_GET_TRAP_CFG_RO"),
233 _T("CMD_SNMP_REQUEST"),
234 _T("CMD_GET_DCI_INFO"),
235 _T("CMD_GET_GRAPH_LIST"),
236 _T("CMD_SAVE_GRAPH"),
237 _T("CMD_DELETE_GRAPH"),
238 _T("CMD_GET_PERFTAB_DCI_LIST"),
239 _T("CMD_ADD_CA_CERTIFICATE"),
240 _T("CMD_DELETE_CERTIFICATE"),
241 _T("CMD_GET_CERT_LIST"),
242 _T("CMD_UPDATE_CERT_COMMENTS"),
243 _T("CMD_QUERY_L2_TOPOLOGY"),
244 _T("CMD_AUDIT_RECORD"),
245 _T("CMD_GET_AUDIT_LOG"),
246 _T("CMD_SEND_SMS"),
247 _T("CMD_GET_COMMUNITY_LIST"),
248 _T("CMD_UPDATE_COMMUNITY_LIST"),
249 _T("CMD_GET_SITUATION_LIST"),
250 _T("CMD_DELETE_SITUATION"),
251 _T("CMD_CREATE_SITUATION"),
252 _T("CMD_DEL_SITUATION_INSTANCE"),
253 _T("CMD_UPDATE_SITUATION"),
254 _T("CMD_SITUATION_DATA"),
255 _T("CMD_SITUATION_CHANGE"),
256 _T("CMD_CREATE_MAP"),
257 _T("CMD_UPLOAD_FILE"),
258 _T("CMD_DELETE_FILE"),
259 _T("CMD_DELETE_REPORT_RESULTS"),
260 _T("CMD_RENDER_REPORT"),
261 _T("CMD_EXECUTE_REPORT"),
262 _T("CMD_GET_REPORT_RESULTS"),
263 _T("CMD_CONFIG_SET_CLOB"),
264 _T("CMD_CONFIG_GET_CLOB"),
265 _T("CMD_RENAME_MAP"),
266 _T("CMD_CLEAR_DCI_DATA"),
267 _T("CMD_GET_LICENSE"),
268 _T("CMD_CHECK_LICENSE"),
269 _T("CMD_RELEASE_LICENSE"),
270 _T("CMD_ISC_CONNECT_TO_SERVICE"),
271 _T("CMD_REGISTER_AGENT"),
272 _T("CMD_GET_SERVER_FILE"),
273 _T("CMD_FORWARD_EVENT"),
274 _T("CMD_GET_USM_CREDENTIALS"),
275 _T("CMD_UPDATE_USM_CREDENTIALS"),
276 _T("CMD_GET_DCI_THRESHOLDS"),
277 _T("CMD_GET_IMAGE"),
278 _T("CMD_CREATE_IMAGE"),
279 _T("CMD_DELETE_IMAGE"),
280 _T("CMD_MODIFY_IMAGE"),
281 _T("CMD_LIST_IMAGES"),
282 _T("CMD_LIST_SERVER_FILES"),
283 _T("CMD_GET_TABLE"),
284 _T("CMD_QUERY_TABLE"),
285 _T("CMD_OPEN_CONSOLE"),
286 _T("CMD_CLOSE_CONSOLE"),
287 _T("CMD_GET_SELECTED_OBJECTS"),
288 _T("CMD_GET_VLANS"),
289 _T("CMD_HOLD_JOB"),
290 _T("CMD_UNHOLD_JOB"),
291 _T("CMD_CHANGE_ZONE"),
292 _T("CMD_GET_AGENT_FILE"),
293 _T("CMD_GET_FILE_DETAILS"),
294 _T("CMD_IMAGE_LIBRARY_UPDATE"),
295 _T("CMD_GET_NODE_COMPONENTS"),
296 _T("CMD_UPDATE_ALARM_COMMENT"),
297 _T("CMD_GET_ALARM"),
298 _T("CMD_GET_TABLE_LAST_VALUES"),
299 _T("CMD_GET_TABLE_DCI_DATA"),
300 _T("CMD_GET_THRESHOLD_SUMMARY"),
301 _T("CMD_RESOLVE_ALARM"),
302 _T("CMD_FIND_IP_LOCATION"),
303 _T("CMD_REPORT_DEVICE_STATUS"),
304 _T("CMD_REPORT_DEVICE_INFO"),
305 _T("CMD_GET_ALARM_EVENTS"),
306 _T("CMD_GET_ENUM_LIST"),
307 _T("CMD_GET_TABLE_LIST"),
308 _T("CMD_GET_MAPPING_TABLE"),
309 _T("CMD_UPDATE_MAPPING_TABLE"),
310 _T("CMD_DELETE_MAPPING_TABLE"),
311 _T("CMD_LIST_MAPPING_TABLES"),
312 _T("CMD_GET_NODE_SOFTWARE"),
313 _T("CMD_GET_WINPERF_OBJECTS"),
314 _T("CMD_GET_WIRELESS_STATIONS"),
315 _T("CMD_GET_SUMMARY_TABLES"),
316 _T("CMD_MODIFY_SUMMARY_TABLE"),
317 _T("CMD_DELETE_SUMMARY_TABLE"),
318 _T("CMD_GET_SUMMARY_TABLE_DETAILS"),
319 _T("CMD_QUERY_SUMMARY_TABLE"),
320 _T("CMD_SHUTDOWN"),
321 _T("CMD_SNMP_TRAP"),
322 _T("CMD_GET_SUBNET_ADDRESS_MAP"),
323 _T("CMD_FILE_MONITORING"),
324 _T("CMD_CANCEL_FILE_MONITORING"),
325 _T("CMD_CHANGE_OBJECT_TOOL_STATUS"),
326 _T("CMD_SET_ALARM_STATUS_FLOW"),
327 _T("CMD_DELETE_ALARM_COMMENT"),
328 _T("CMD_GET_EFFECTIVE_RIGHTS"),
329 _T("CMD_GET_DCI_VALUES"),
330 _T("CMD_GET_HELPDESK_URL"),
331 _T("CMD_UNLINK_HELPDESK_ISSUE"),
332 _T("CMD_GET_FOLDER_CONTENT"),
333 _T("CMD_FILEMGR_DELETE_FILE"),
334 _T("CMD_FILEMGR_RENAME_FILE"),
335 _T("CMD_FILEMGR_MOVE_FILE"),
336 _T("CMD_FILEMGR_UPLOAD")
337 };
338
339 if ((wCode >= CMD_LOGIN) && (wCode <= CMD_FILEMGR_UPLOAD))
340 _tcscpy(pszBuffer, pszMsgNames[wCode - CMD_LOGIN]);
341 else
342 _sntprintf(pszBuffer, 64, _T("CMD_0x%04X"), wCode);
343 return pszBuffer;
344 }
345
346 /**
347 * Receive raw CSCP message from network
348 * If pMsg is NULL, temporary buffer will be re-initialized
349 * Returns message size on success or:
350 * 0 if connection is closed
351 * <0 on socket errors
352 * 1 if message is too large to fit in buffer (normal messages is at least 16
353 * bytes long, so we never get length of 1 for valid message)
354 * In this case, only message header will be copied into buffer
355 * 2 Message decryption failed
356 * 3 Receive timeout
357 */
358 int LIBNETXMS_EXPORTABLE RecvNXCPMessageEx(SOCKET hSocket, CSCP_MESSAGE **msgBuffer,
359 CSCP_BUFFER *nxcpBuffer, UINT32 *bufferSize,
360 NXCPEncryptionContext **ppCtx,
361 BYTE **decryptionBuffer, UINT32 dwTimeout,
362 UINT32 maxMsgSize)
363 {
364 UINT32 dwMsgSize = 0, dwBytesRead = 0, dwBytesToCopy;
365 int iErr;
366 BOOL bSkipMsg = FALSE;
367
368 // Initialize buffer if requested
369 if (msgBuffer == NULL)
370 {
371 nxcpBuffer->dwBufSize = 0;
372 nxcpBuffer->dwBufPos = 0;
373 return 0;
374 }
375
376 // Check if we have something in buffer
377 if (nxcpBuffer->dwBufSize > 0)
378 {
379 // Handle the case when entire message header have not been read into the buffer
380 if (nxcpBuffer->dwBufSize < CSCP_HEADER_SIZE)
381 {
382 // Most likely we are at the buffer end, so move content
383 // to the beginning
384 memmove(nxcpBuffer->szBuffer, &nxcpBuffer->szBuffer[nxcpBuffer->dwBufPos], nxcpBuffer->dwBufSize);
385 nxcpBuffer->dwBufPos = 0;
386
387 // Receive new portion of data from the network
388 // and append it to existing data in buffer
389 iErr = RecvEx(hSocket, &nxcpBuffer->szBuffer[nxcpBuffer->dwBufSize],
390 CSCP_TEMP_BUF_SIZE - nxcpBuffer->dwBufSize, 0, dwTimeout);
391 if (iErr <= 0)
392 return (iErr == -2) ? 3 : iErr;
393 nxcpBuffer->dwBufSize += (UINT32)iErr;
394 }
395
396 // Get message size from message header and copy available
397 // message bytes from buffer
398 dwMsgSize = ntohl(((CSCP_MESSAGE *)(&nxcpBuffer->szBuffer[nxcpBuffer->dwBufPos]))->dwSize);
399 if (dwMsgSize > *bufferSize)
400 {
401 if ((*bufferSize >= maxMsgSize) || (dwMsgSize > maxMsgSize))
402 {
403 bSkipMsg = TRUE; // Message is too large, will skip it
404 memcpy(*msgBuffer, &nxcpBuffer->szBuffer[nxcpBuffer->dwBufPos], CSCP_HEADER_SIZE);
405 }
406 else
407 {
408 // Increase buffer
409 *bufferSize = dwMsgSize;
410 *msgBuffer = (CSCP_MESSAGE *)realloc(*msgBuffer, *bufferSize);
411 if (decryptionBuffer != NULL)
412 *decryptionBuffer = (BYTE *)realloc(*decryptionBuffer, *bufferSize);
413 }
414 }
415 dwBytesRead = min(dwMsgSize, nxcpBuffer->dwBufSize);
416 if (!bSkipMsg)
417 memcpy(*msgBuffer, &nxcpBuffer->szBuffer[nxcpBuffer->dwBufPos], dwBytesRead);
418 nxcpBuffer->dwBufSize -= dwBytesRead;
419 nxcpBuffer->dwBufPos = (nxcpBuffer->dwBufSize > 0) ? (nxcpBuffer->dwBufPos + dwBytesRead) : 0;
420 if (dwBytesRead == dwMsgSize)
421 goto decrypt_message;
422 }
423
424 // Receive rest of message from the network
425 // Buffer is empty now
426 nxcpBuffer->dwBufSize = 0;
427 nxcpBuffer->dwBufPos = 0;
428 do
429 {
430 iErr = RecvEx(hSocket, &nxcpBuffer->szBuffer[nxcpBuffer->dwBufSize],
431 CSCP_TEMP_BUF_SIZE - nxcpBuffer->dwBufSize, 0, dwTimeout);
432 if (iErr <= 0)
433 return (iErr == -2) ? 3 : iErr;
434
435 if (dwBytesRead == 0) // New message?
436 {
437 if ((iErr + nxcpBuffer->dwBufSize) < CSCP_HEADER_SIZE)
438 {
439 // Header not received completely
440 nxcpBuffer->dwBufSize += iErr;
441 continue;
442 }
443 iErr += nxcpBuffer->dwBufSize;
444 nxcpBuffer->dwBufSize = 0;
445
446 dwMsgSize = ntohl(((CSCP_MESSAGE *)(nxcpBuffer->szBuffer))->dwSize);
447 if (dwMsgSize > *bufferSize)
448 {
449 if ((*bufferSize >= maxMsgSize) || (dwMsgSize > maxMsgSize))
450 {
451 bSkipMsg = TRUE; // Message is too large, will skip it
452 memcpy(*msgBuffer, nxcpBuffer->szBuffer, CSCP_HEADER_SIZE);
453 }
454 else
455 {
456 // Increase buffer
457 *bufferSize = dwMsgSize;
458 *msgBuffer = (CSCP_MESSAGE *)realloc(*msgBuffer, *bufferSize);
459 if (decryptionBuffer != NULL)
460 *decryptionBuffer = (BYTE *)realloc(*decryptionBuffer, *bufferSize);
461 }
462 }
463 }
464 dwBytesToCopy = min((UINT32)iErr, dwMsgSize - dwBytesRead);
465 if (!bSkipMsg)
466 memcpy(((char *)(*msgBuffer)) + dwBytesRead, nxcpBuffer->szBuffer, dwBytesToCopy);
467 dwBytesRead += dwBytesToCopy;
468 }
469 while((dwBytesRead < dwMsgSize) || (dwBytesRead < CSCP_HEADER_SIZE));
470
471 // Check if we have something left in buffer
472 if (dwBytesToCopy < (UINT32)iErr)
473 {
474 nxcpBuffer->dwBufPos = dwBytesToCopy;
475 nxcpBuffer->dwBufSize = (UINT32)iErr - dwBytesToCopy;
476 }
477
478 // Check for encrypted message
479 decrypt_message:
480 if ((!bSkipMsg) && (ntohs((*msgBuffer)->wCode) == CMD_ENCRYPTED_MESSAGE))
481 {
482 if ((*ppCtx != NULL) && (*ppCtx != PROXY_ENCRYPTION_CTX))
483 {
484 if (CSCPDecryptMessage(*ppCtx, (CSCP_ENCRYPTED_MESSAGE *)(*msgBuffer), *decryptionBuffer))
485 {
486 dwMsgSize = ntohl((*msgBuffer)->dwSize);
487 }
488 else
489 {
490 dwMsgSize = 2; // Decryption failed
491 }
492 }
493 else
494 {
495 if (*ppCtx != PROXY_ENCRYPTION_CTX)
496 dwMsgSize = 2;
497 }
498 }
499
500 return bSkipMsg ? 1 : (int)dwMsgSize;
501 }
502
503 int LIBNETXMS_EXPORTABLE RecvNXCPMessage(SOCKET hSocket, CSCP_MESSAGE *msgBuffer,
504 CSCP_BUFFER *nxcpBuffer, UINT32 bufferSize,
505 NXCPEncryptionContext **ppCtx,
506 BYTE *decryptionBuffer, UINT32 dwTimeout)
507 {
508 CSCP_MESSAGE *mb = msgBuffer;
509 UINT32 bs = bufferSize;
510 BYTE *db = decryptionBuffer;
511 return RecvNXCPMessageEx(hSocket, (msgBuffer != NULL) ? &mb : NULL, nxcpBuffer, &bs, ppCtx,
512 (decryptionBuffer != NULL) ? &db : NULL, dwTimeout, bufferSize);
513 }
514
515 /**
516 * Create NXCP message with raw data (MF_BINARY flag)
517 * If pBuffer is NULL, new buffer is allocated with malloc()
518 * Buffer should be of dwDataSize + CSCP_HEADER_SIZE + 8 bytes.
519 */
520 CSCP_MESSAGE LIBNETXMS_EXPORTABLE *CreateRawNXCPMessage(WORD wCode, UINT32 dwId, WORD wFlags,
521 UINT32 dwDataSize, void *pData,
522 CSCP_MESSAGE *pBuffer)
523 {
524 CSCP_MESSAGE *pMsg;
525 UINT32 dwPadding;
526
527 if (pBuffer == NULL)
528 pMsg = (CSCP_MESSAGE *)malloc(dwDataSize + CSCP_HEADER_SIZE + 8);
529 else
530 pMsg = pBuffer;
531
532 // Message should be aligned to 8 bytes boundary
533 dwPadding = (8 - ((dwDataSize + CSCP_HEADER_SIZE) % 8)) & 7;
534
535 pMsg->wCode = htons(wCode);
536 pMsg->wFlags = htons(MF_BINARY | wFlags);
537 pMsg->dwId = htonl(dwId);
538 pMsg->dwSize = htonl(dwDataSize + CSCP_HEADER_SIZE + dwPadding);
539 pMsg->dwNumVars = htonl(dwDataSize); // dwNumVars contains actual data size for binary message
540 memcpy(pMsg->df, pData, dwDataSize);
541
542 return pMsg;
543 }
544
545 /**
546 * Send file over CSCP
547 */
548 BOOL LIBNETXMS_EXPORTABLE SendFileOverNXCP(SOCKET hSocket, UINT32 dwId, const TCHAR *pszFile,
549 NXCPEncryptionContext *pCtx, long offset,
550 void (* progressCallback)(INT64, void *), void *cbArg,
551 MUTEX mutex)
552 {
553 int hFile, iBytes;
554 INT64 bytesTransferred = 0;
555 UINT32 dwPadding;
556 BOOL bResult = FALSE;
557 CSCP_MESSAGE *pMsg;
558 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
559
560 hFile = _topen(pszFile, O_RDONLY | O_BINARY);
561 if (hFile != -1)
562 {
563 NX_STAT_STRUCT st;
564 NX_FSTAT(hFile, &st);
565 long fileSize = (long)st.st_size;
566 if (labs(offset) > fileSize)
567 offset = 0;
568 long bytesToRead = (offset < 0) ? (0 - offset) : (fileSize - offset);
569
570 if (lseek(hFile, offset, (offset < 0) ? SEEK_END : SEEK_SET) != -1)
571 {
572 // Allocate message and prepare it's header
573 pMsg = (CSCP_MESSAGE *)malloc(FILE_BUFFER_SIZE + CSCP_HEADER_SIZE + 8);
574 pMsg->dwId = htonl(dwId);
575 pMsg->wCode = htons(CMD_FILE_DATA);
576 pMsg->wFlags = htons(MF_BINARY);
577
578 while(1)
579 {
580 iBytes = read(hFile, pMsg->df, min(FILE_BUFFER_SIZE, bytesToRead));
581 if (iBytes < 0)
582 break;
583
584 // Message should be aligned to 8 bytes boundary
585 dwPadding = (8 - (((UINT32)iBytes + CSCP_HEADER_SIZE) % 8)) & 7;
586 pMsg->dwSize = htonl((UINT32)iBytes + CSCP_HEADER_SIZE + dwPadding);
587 pMsg->dwNumVars = htonl((UINT32)iBytes); // dwNumVars contains actual data size for binary message
588 bytesToRead -= iBytes;
589 if (bytesToRead <= 0)
590 pMsg->wFlags |= htons(MF_END_OF_FILE);
591
592 if (pCtx != NULL)
593 {
594 pEnMsg = CSCPEncryptMessage(pCtx, pMsg);
595 if (pEnMsg != NULL)
596 {
597 SendEx(hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0, mutex);
598 free(pEnMsg);
599 }
600 }
601 else
602 {
603 if (SendEx(hSocket, (char *)pMsg, (UINT32)iBytes + CSCP_HEADER_SIZE + dwPadding, 0, mutex) <= 0)
604 break; // Send error
605 }
606 if (progressCallback != NULL)
607 {
608 bytesTransferred += iBytes;
609 progressCallback(bytesTransferred, cbArg);
610 }
611
612 if (bytesToRead <= 0)
613 {
614 // End of file
615 bResult = TRUE;
616 break;
617 }
618 }
619
620 free(pMsg);
621 }
622 close(hFile);
623 }
624
625 // If file upload failed, send CMD_ABORT_FILE_TRANSFER
626 if (!bResult)
627 {
628 CSCP_MESSAGE msg;
629
630 msg.dwId = htonl(dwId);
631 msg.wCode = htons(CMD_ABORT_FILE_TRANSFER);
632 msg.wFlags = htons(MF_BINARY);
633 msg.dwNumVars = 0;
634 msg.dwSize = htonl(CSCP_HEADER_SIZE);
635 if (pCtx != NULL)
636 {
637 pEnMsg = CSCPEncryptMessage(pCtx, &msg);
638 if (pEnMsg != NULL)
639 {
640 SendEx(hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0, mutex);
641 free(pEnMsg);
642 }
643 }
644 else
645 {
646 SendEx(hSocket, (char *)&msg, CSCP_HEADER_SIZE, 0, mutex);
647 }
648 }
649
650 return bResult;
651 }
652
653 /**
654 * Get version of NXCP used by peer
655 */
656 BOOL LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(SOCKET hSocket, int *pnVersion, MUTEX mutex)
657 {
658 CSCP_MESSAGE msg;
659 NXCPEncryptionContext *pDummyCtx = NULL;
660 CSCP_BUFFER *pBuffer;
661 BOOL bRet = FALSE;
662 int nSize;
663
664 msg.dwId = 0;
665 msg.dwNumVars = 0;
666 msg.dwSize = htonl(CSCP_HEADER_SIZE);
667 msg.wCode = htons(CMD_GET_NXCP_CAPS);
668 msg.wFlags = htons(MF_CONTROL);
669 if (SendEx(hSocket, &msg, CSCP_HEADER_SIZE, 0, mutex) == CSCP_HEADER_SIZE)
670 {
671 pBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
672 RecvNXCPMessage(0, NULL, pBuffer, 0, NULL, NULL, 0);
673 nSize = RecvNXCPMessage(hSocket, &msg, pBuffer, CSCP_HEADER_SIZE, &pDummyCtx, NULL, 30000);
674 if ((nSize == CSCP_HEADER_SIZE) &&
675 (ntohs(msg.wCode) == CMD_NXCP_CAPS) &&
676 (ntohs(msg.wFlags) & MF_CONTROL))
677 {
678 bRet = TRUE;
679 *pnVersion = ntohl(msg.dwNumVars) >> 24;
680 }
681 else if ((nSize == 1) || (nSize == 3) || (nSize >= CSCP_HEADER_SIZE))
682 {
683 // We don't receive any answer or receive invalid answer -
684 // assume that peer doesn't understand CMD_GET_NXCP_CAPS message
685 // and set version number to 1
686 bRet = TRUE;
687 *pnVersion = 1;
688 }
689 free(pBuffer);
690 }
691 return bRet;
692 }