Fixed download file canceling
[public/netxms.git] / src / libnetxms / nxcp.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2017 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 <nxcpapi.h>
26 #include <nxstat.h>
27 #include <zlib.h>
28
29 /**
30 * Additional message name resolvers
31 */
32 static Array s_resolvers(4, 4, false);
33 static Mutex s_resolversLock;
34
35 /**
36 * Get symbolic name for message code
37 */
38 TCHAR LIBNETXMS_EXPORTABLE *NXCPMessageCodeName(WORD code, TCHAR *pszBuffer)
39 {
40 static const TCHAR *pszMsgNames[] =
41 {
42 _T("CMD_LOGIN"),
43 _T("CMD_LOGIN_RESP"),
44 _T("CMD_KEEPALIVE"),
45 _T("CMD_OPEN_HELPDESK_ISSUE"),
46 _T("CMD_GET_OBJECTS"),
47 _T("CMD_OBJECT"),
48 _T("CMD_DELETE_OBJECT"),
49 _T("CMD_MODIFY_OBJECT"),
50 _T("CMD_OBJECT_LIST_END"),
51 _T("CMD_OBJECT_UPDATE"),
52 _T("<unused>0x000B"),
53 _T("CMD_EVENTLOG_RECORDS"),
54 _T("CMD_GET_CONFIG_VARLIST"),
55 _T("CMD_SET_CONFIG_VARIABLE"),
56 _T("CMD_GET_OBJECT_TOOLS"),
57 _T("CMD_EXECUTE_ACTION"),
58 _T("CMD_DELETE_CONFIG_VARIABLE"),
59 _T("CMD_NOTIFY"),
60 _T("CMD_TRAP"),
61 _T("CMD_OPEN_EPP"),
62 _T("CMD_CLOSE_EPP"),
63 _T("CMD_SAVE_EPP"),
64 _T("CMD_EPP_RECORD"),
65 _T("CMD_EVENT_DB_UPDATE"),
66 _T("CMD_TRAP_CFG_UPDATE"),
67 _T("CMD_SET_EVENT_INFO"),
68 _T("CMD_EVENT_DB_RECORD"),
69 _T("CMD_LOAD_EVENT_DB"),
70 _T("CMD_REQUEST_COMPLETED"),
71 _T("CMD_LOAD_USER_DB"),
72 _T("CMD_USER_DATA"),
73 _T("CMD_GROUP_DATA"),
74 _T("CMD_USER_DB_EOF"),
75 _T("CMD_UPDATE_USER"),
76 _T("CMD_DELETE_USER"),
77 _T("CMD_CREATE_USER"),
78 _T("CMD_LOCK_USER_DB"),
79 _T("CMD_UNLOCK_USER_DB"),
80 _T("CMD_USER_DB_UPDATE"),
81 _T("CMD_SET_PASSWORD"),
82 _T("CMD_GET_NODE_DCI_LIST"),
83 _T("CMD_NODE_DCI"),
84 _T("CMD_GET_LOG_DATA"),
85 _T("CMD_DELETE_NODE_DCI"),
86 _T("CMD_MODIFY_NODE_DCI"),
87 _T("CMD_UNLOCK_NODE_DCI_LIST"),
88 _T("CMD_SET_OBJECT_MGMT_STATUS"),
89 _T("CMD_CREATE_NEW_DCI"),
90 _T("CMD_GET_DCI_DATA"),
91 _T("CMD_DCI_DATA"),
92 _T("CMD_GET_MIB_TIMESTAMP"),
93 _T("CMD_GET_MIB"),
94 _T("CMD_TEST_DCI_TRANSFORMATION"),
95 _T("CMD_GET_JOB_LIST"),
96 _T("CMD_CREATE_OBJECT"),
97 _T("CMD_GET_EVENT_NAMES"),
98 _T("CMD_EVENT_NAME_LIST"),
99 _T("CMD_BIND_OBJECT"),
100 _T("CMD_UNBIND_OBJECT"),
101 _T("CMD_UNINSTALL_AGENT_POLICY"),
102 _T("CMD_OPEN_SERVER_LOG"),
103 _T("CMD_CLOSE_SERVER_LOG"),
104 _T("CMD_QUERY_LOG"),
105 _T("CMD_AUTHENTICATE"),
106 _T("CMD_GET_PARAMETER"),
107 _T("CMD_GET_LIST"),
108 _T("CMD_ACTION"),
109 _T("CMD_GET_CURRENT_USER_ATTR"),
110 _T("CMD_SET_CURRENT_USER_ATTR"),
111 _T("CMD_GET_ALL_ALARMS"),
112 _T("CMD_GET_ALARM_COMMENTS"),
113 _T("CMD_ACK_ALARM"),
114 _T("CMD_ALARM_UPDATE"),
115 _T("CMD_ALARM_DATA"),
116 _T("CMD_DELETE_ALARM"),
117 _T("CMD_ADD_CLUSTER_NODE"),
118 _T("CMD_GET_POLICY_INVENTORY"),
119 _T("CMD_LOAD_ACTIONS"),
120 _T("CMD_ACTION_DB_UPDATE"),
121 _T("CMD_MODIFY_ACTION"),
122 _T("CMD_CREATE_ACTION"),
123 _T("CMD_DELETE_ACTION"),
124 _T("CMD_ACTION_DATA"),
125 _T("CMD_SETUP_AGENT_TUNNEL"),
126 _T("CMD_EXECUTE_LIBRARY_SCRIPT"),
127 _T("CMD_GET_PREDICTION_ENGINES"),
128 _T("CMD_GET_PREDICTED_DATA"),
129 _T("CMD_STOP_SERVER_COMMAND"),
130 _T("CMD_POLL_NODE"),
131 _T("CMD_POLLING_INFO"),
132 _T("CMD_COPY_DCI"),
133 _T("CMD_WAKEUP_NODE"),
134 _T("CMD_DELETE_EVENT_TEMPLATE"),
135 _T("CMD_GENERATE_EVENT_CODE"),
136 _T("CMD_FIND_NODE_CONNECTION"),
137 _T("CMD_FIND_MAC_LOCATION"),
138 _T("CMD_CREATE_TRAP"),
139 _T("CMD_MODIFY_TRAP"),
140 _T("CMD_DELETE_TRAP"),
141 _T("CMD_LOAD_TRAP_CFG"),
142 _T("CMD_TRAP_CFG_RECORD"),
143 _T("CMD_QUERY_PARAMETER"),
144 _T("CMD_GET_SERVER_INFO"),
145 _T("CMD_SET_DCI_STATUS"),
146 _T("CMD_FILE_DATA"),
147 _T("CMD_TRANSFER_FILE"),
148 _T("CMD_UPGRADE_AGENT"),
149 _T("CMD_GET_PACKAGE_LIST"),
150 _T("CMD_PACKAGE_INFO"),
151 _T("CMD_REMOVE_PACKAGE"),
152 _T("CMD_INSTALL_PACKAGE"),
153 _T("CMD_LOCK_PACKAGE_DB"),
154 _T("CMD_UNLOCK_PACKAGE_DB"),
155 _T("CMD_ABORT_FILE_TRANSFER"),
156 _T("CMD_CHECK_NETWORK_SERVICE"),
157 _T("CMD_GET_AGENT_CONFIG"),
158 _T("CMD_UPDATE_AGENT_CONFIG"),
159 _T("CMD_GET_PARAMETER_LIST"),
160 _T("CMD_DEPLOY_PACKAGE"),
161 _T("CMD_INSTALLER_INFO"),
162 _T("CMD_GET_LAST_VALUES"),
163 _T("CMD_APPLY_TEMPLATE"),
164 _T("CMD_SET_USER_VARIABLE"),
165 _T("CMD_GET_USER_VARIABLE"),
166 _T("CMD_ENUM_USER_VARIABLES"),
167 _T("CMD_DELETE_USER_VARIABLE"),
168 _T("CMD_ADM_MESSAGE"),
169 _T("CMD_ADM_REQUEST"),
170 _T("CMD_GET_NETWORK_PATH"),
171 _T("CMD_REQUEST_SESSION_KEY"),
172 _T("CMD_ENCRYPTED_MESSAGE"),
173 _T("CMD_SESSION_KEY"),
174 _T("CMD_REQUEST_ENCRYPTION"),
175 _T("CMD_GET_ROUTING_TABLE"),
176 _T("CMD_EXEC_TABLE_TOOL"),
177 _T("CMD_TABLE_DATA"),
178 _T("CMD_CANCEL_JOB"),
179 _T("CMD_CHANGE_SUBSCRIPTION"),
180 _T("CMD_SET_CONFIG_TO_DEFAULT"),
181 _T("CMD_SYSLOG_RECORDS"),
182 _T("CMD_JOB_CHANGE_NOTIFICATION"),
183 _T("CMD_DEPLOY_AGENT_POLICY"),
184 _T("CMD_LOG_DATA"),
185 _T("CMD_GET_OBJECT_TOOL_DETAILS"),
186 _T("CMD_EXECUTE_SERVER_COMMAND"),
187 _T("CMD_UPLOAD_FILE_TO_AGENT"),
188 _T("CMD_UPDATE_OBJECT_TOOL"),
189 _T("CMD_DELETE_OBJECT_TOOL"),
190 _T("CMD_SETUP_PROXY_CONNECTION"),
191 _T("CMD_GENERATE_OBJECT_TOOL_ID"),
192 _T("CMD_GET_SERVER_STATS"),
193 _T("CMD_GET_SCRIPT_LIST"),
194 _T("CMD_GET_SCRIPT"),
195 _T("CMD_UPDATE_SCRIPT"),
196 _T("CMD_DELETE_SCRIPT"),
197 _T("CMD_RENAME_SCRIPT"),
198 _T("CMD_GET_SESSION_LIST"),
199 _T("CMD_KILL_SESSION"),
200 _T("<unused>0x009F"),
201 _T("CMD_TRAP_LOG_RECORDS"),
202 _T("CMD_START_SNMP_WALK"),
203 _T("CMD_SNMP_WALK_DATA"),
204 _T("CMD_GET_MAP_LIST"),
205 _T("CMD_LOAD_MAP"),
206 _T("CMD_SAVE_MAP"),
207 _T("CMD_DELETE_MAP"),
208 _T("CMD_RESOLVE_MAP_NAME"),
209 _T("CMD_SUBMAP_DATA"),
210 _T("CMD_UPLOAD_SUBMAP_BK_IMAGE"),
211 _T("CMD_GET_SUBMAP_BK_IMAGE"),
212 _T("CMD_GET_MODULE_LIST"),
213 _T("CMD_UPDATE_MODULE_INFO"),
214 _T("CMD_COPY_USER_VARIABLE"),
215 _T("CMD_RESOLVE_DCI_NAMES"),
216 _T("CMD_GET_MY_CONFIG"),
217 _T("CMD_GET_AGENT_CFG_LIST"),
218 _T("CMD_OPEN_AGENT_CONFIG"),
219 _T("CMD_SAVE_AGENT_CONFIG"),
220 _T("CMD_DELETE_AGENT_CONFIG"),
221 _T("CMD_SWAP_AGENT_CONFIGS"),
222 _T("CMD_TERMINATE_ALARM"),
223 _T("CMD_GET_NXCP_CAPS"),
224 _T("CMD_NXCP_CAPS"),
225 _T("CMD_GET_OBJECT_COMMENTS"),
226 _T("CMD_UPDATE_OBJECT_COMMENTS"),
227 _T("CMD_ENABLE_AGENT_TRAPS"),
228 _T("CMD_PUSH_DCI_DATA"),
229 _T("CMD_GET_ADDR_LIST"),
230 _T("CMD_SET_ADDR_LIST"),
231 _T("CMD_RESET_COMPONENT"),
232 _T("CMD_GET_DCI_EVENTS_LIST"),
233 _T("CMD_EXPORT_CONFIGURATION"),
234 _T("CMD_IMPORT_CONFIGURATION"),
235 _T("CMD_GET_TRAP_CFG_RO"),
236 _T("CMD_SNMP_REQUEST"),
237 _T("CMD_GET_DCI_INFO"),
238 _T("CMD_GET_GRAPH_LIST"),
239 _T("CMD_SAVE_GRAPH"),
240 _T("CMD_DELETE_GRAPH"),
241 _T("CMD_GET_PERFTAB_DCI_LIST"),
242 _T("CMD_ADD_CA_CERTIFICATE"),
243 _T("CMD_DELETE_CERTIFICATE"),
244 _T("CMD_GET_CERT_LIST"),
245 _T("CMD_UPDATE_CERT_COMMENTS"),
246 _T("CMD_QUERY_L2_TOPOLOGY"),
247 _T("CMD_AUDIT_RECORD"),
248 _T("CMD_GET_AUDIT_LOG"),
249 _T("CMD_SEND_SMS"),
250 _T("CMD_GET_COMMUNITY_LIST"),
251 _T("CMD_UPDATE_COMMUNITY_LIST"),
252 _T("CMD_GET_PERSISTENT_STORAGE"),
253 _T("CMD_DELETE_PSTORAGE_VALUE"),
254 _T("CMD_UPDATE_PSTORAGE_VALUE"),
255 _T("CMD_GET_AGENT_TUNNELS"),
256 _T("CMD_BIND_AGENT_TUNNEL"),
257 _T("CMD_REQUEST_CERTIFICATE"),
258 _T("CMD_NEW_CERTIFICATE"),
259 _T("CMD_CREATE_MAP"),
260 _T("CMD_UPLOAD_FILE"),
261 _T("CMD_DELETE_FILE"),
262 _T("CMD_DELETE_REPORT_RESULTS"),
263 _T("CMD_RENDER_REPORT"),
264 _T("CMD_EXECUTE_REPORT"),
265 _T("CMD_GET_REPORT_RESULTS"),
266 _T("CMD_CONFIG_SET_CLOB"),
267 _T("CMD_CONFIG_GET_CLOB"),
268 _T("CMD_RENAME_MAP"),
269 _T("CMD_CLEAR_DCI_DATA"),
270 _T("CMD_GET_LICENSE"),
271 _T("CMD_CHECK_LICENSE"),
272 _T("CMD_RELEASE_LICENSE"),
273 _T("CMD_ISC_CONNECT_TO_SERVICE"),
274 _T("CMD_REGISTER_AGENT"),
275 _T("CMD_GET_SERVER_FILE"),
276 _T("CMD_FORWARD_EVENT"),
277 _T("CMD_GET_USM_CREDENTIALS"),
278 _T("CMD_UPDATE_USM_CREDENTIALS"),
279 _T("CMD_GET_DCI_THRESHOLDS"),
280 _T("CMD_GET_IMAGE"),
281 _T("CMD_CREATE_IMAGE"),
282 _T("CMD_DELETE_IMAGE"),
283 _T("CMD_MODIFY_IMAGE"),
284 _T("CMD_LIST_IMAGES"),
285 _T("CMD_LIST_SERVER_FILES"),
286 _T("CMD_GET_TABLE"),
287 _T("CMD_QUERY_TABLE"),
288 _T("CMD_OPEN_CONSOLE"),
289 _T("CMD_CLOSE_CONSOLE"),
290 _T("CMD_GET_SELECTED_OBJECTS"),
291 _T("CMD_GET_VLANS"),
292 _T("CMD_HOLD_JOB"),
293 _T("CMD_UNHOLD_JOB"),
294 _T("CMD_CHANGE_ZONE"),
295 _T("CMD_GET_AGENT_FILE"),
296 _T("CMD_GET_FILE_DETAILS"),
297 _T("CMD_IMAGE_LIBRARY_UPDATE"),
298 _T("CMD_GET_NODE_COMPONENTS"),
299 _T("CMD_UPDATE_ALARM_COMMENT"),
300 _T("CMD_GET_ALARM"),
301 _T("CMD_GET_TABLE_LAST_VALUES"),
302 _T("CMD_GET_TABLE_DCI_DATA"),
303 _T("CMD_GET_THRESHOLD_SUMMARY"),
304 _T("CMD_RESOLVE_ALARM"),
305 _T("CMD_FIND_IP_LOCATION"),
306 _T("CMD_REPORT_DEVICE_STATUS"),
307 _T("CMD_REPORT_DEVICE_INFO"),
308 _T("CMD_GET_ALARM_EVENTS"),
309 _T("CMD_GET_ENUM_LIST"),
310 _T("CMD_GET_TABLE_LIST"),
311 _T("CMD_GET_MAPPING_TABLE"),
312 _T("CMD_UPDATE_MAPPING_TABLE"),
313 _T("CMD_DELETE_MAPPING_TABLE"),
314 _T("CMD_LIST_MAPPING_TABLES"),
315 _T("CMD_GET_NODE_SOFTWARE"),
316 _T("CMD_GET_WINPERF_OBJECTS"),
317 _T("CMD_GET_WIRELESS_STATIONS"),
318 _T("CMD_GET_SUMMARY_TABLES"),
319 _T("CMD_MODIFY_SUMMARY_TABLE"),
320 _T("CMD_DELETE_SUMMARY_TABLE"),
321 _T("CMD_GET_SUMMARY_TABLE_DETAILS"),
322 _T("CMD_QUERY_SUMMARY_TABLE"),
323 _T("CMD_SHUTDOWN"),
324 _T("CMD_SNMP_TRAP"),
325 _T("CMD_GET_SUBNET_ADDRESS_MAP"),
326 _T("CMD_FILE_MONITORING"),
327 _T("CMD_CANCEL_FILE_MONITORING"),
328 _T("CMD_CHANGE_OBJECT_TOOL_STATUS"),
329 _T("CMD_SET_ALARM_STATUS_FLOW"),
330 _T("CMD_DELETE_ALARM_COMMENT"),
331 _T("CMD_GET_EFFECTIVE_RIGHTS"),
332 _T("CMD_GET_DCI_VALUES"),
333 _T("CMD_GET_HELPDESK_URL"),
334 _T("CMD_UNLINK_HELPDESK_ISSUE"),
335 _T("CMD_GET_FOLDER_CONTENT"),
336 _T("CMD_FILEMGR_DELETE_FILE"),
337 _T("CMD_FILEMGR_RENAME_FILE"),
338 _T("CMD_FILEMGR_MOVE_FILE"),
339 _T("CMD_FILEMGR_UPLOAD"),
340 _T("CMD_GET_SWITCH_FDB"),
341 _T("CMD_COMMAND_OUTPUT"),
342 _T("CMD_GET_LOC_HISTORY"),
343 _T("CMD_TAKE_SCREENSHOT"),
344 _T("CMD_EXECUTE_SCRIPT"),
345 _T("CMD_EXECUTE_SCRIPT_UPDATE"),
346 _T("CMD_FILEMGR_CREATE_FOLDER"),
347 _T("CMD_QUERY_ADHOC_SUMMARY_TABLE"),
348 _T("CMD_GRAPH_UPDATE"),
349 _T("CMD_SET_SERVER_CAPABILITIES"),
350 _T("CMD_FORCE_DCI_POLL"),
351 _T("CMD_GET_DCI_SCRIPT_LIST"),
352 _T("CMD_DATA_COLLECTION_CONFIG"),
353 _T("CMD_SET_SERVER_ID"),
354 _T("CMD_GET_PUBLIC_CONFIG_VAR"),
355 _T("CMD_ENABLE_FILE_UPDATES"),
356 _T("CMD_DETACH_LDAP_USER"),
357 _T("CMD_VALIDATE_PASSWORD"),
358 _T("CMD_COMPILE_SCRIPT"),
359 _T("CMD_CLEAN_AGENT_DCI_CONF"),
360 _T("CMD_RESYNC_AGENT_DCI_CONF"),
361 _T("CMD_LIST_SCHEDULE_CALLBACKS"),
362 _T("CMD_LIST_SCHEDULES"),
363 _T("CMD_ADD_SCHEDULE"),
364 _T("CMD_UPDATE_SCHEDULE"),
365 _T("CMD_REMOVE_SCHEDULE"),
366 _T("CMD_ENTER_MAINT_MODE"),
367 _T("CMD_LEAVE_MAINT_MODE"),
368 _T("CMD_JOIN_CLUSTER"),
369 _T("CMD_CLUSTER_NOTIFY"),
370 _T("CMD_ZMQ_SUBSCRIBE_EVENT"),
371 _T("CMD_ZMQ_UNSUBSCRIBE_EVENT"),
372 _T("CMD_ZMQ_SUBSCRIBE_DATA"),
373 _T("CMD_ZMQ_UNSUBSCRIBE_DATA"),
374 _T("CMD_ZMQ_GET_EVT_SUBSCRIPTIONS"),
375 _T("CMD_ZMQ_GET_DATA_SUBSCRIPTIONS"),
376 _T("CMD_GET_REPOSITORIES"),
377 _T("CMD_ADD_REPOSITORY"),
378 _T("CMD_MODIFY_REPOSITORY"),
379 _T("CMD_DELETE_REPOSITORY"),
380 _T("CMD_GET_ALARM_CATEGORIES"),
381 _T("CMD_MODIFY_ALARM_CATEGORY"),
382 _T("CMD_DELETE_ALARM_CATEGORY"),
383 _T("CMD_ALARM_CATEGORY_UPDATE"),
384 _T("CMD_BULK_TERMINATE_ALARMS"),
385 _T("CMD_BULK_RESOLVE_ALARMS"),
386 _T("CMD_BULK_ALARM_STATE_CHANGE"),
387 _T("CMD_GET_FOLDER_SIZE"),
388 _T("CMD_FIND_HOSTNAME_LOCATION"),
389 _T("CMD_RESET_TUNNEL"),
390 _T("CMD_CREATE_CHANNEL"),
391 _T("CMD_CHANNEL_DATA"),
392 _T("CMD_CLOSE_CHANNEL"),
393 _T("CMD_CREATE_OBJECT_ACCESS_SNAPSHOT"),
394 _T("CMD_UNBIND_AGENT_TUNNEL"),
395 _T("CMD_RESTART"),
396 _T("CMD_REGISTER_LORAWAN_SENSOR"),
397 _T("CMD_UNREGISTER_LORAWAN_SENSOR"),
398 _T("CMD_EXPAND_MACROS"),
399 _T("CMD_EXECUTE_ACTION_WITH_EXPANSION"),
400 _T("CMD_HOST_BY_IP"),
401 _T("CMD_CANCEL_FILE_DOWNLOAD")
402 };
403
404 if ((code >= CMD_LOGIN) && (code <= CMD_CANCEL_FILE_DOWNLOAD))
405 {
406 _tcscpy(pszBuffer, pszMsgNames[code - CMD_LOGIN]);
407 }
408 else
409 {
410 bool resolved = false;
411 s_resolversLock.lock();
412 for(int i = 0; i < s_resolvers.size(); i++)
413 if (((NXCPMessageNameResolver)s_resolvers.get(i))(code, pszBuffer))
414 {
415 resolved = true;
416 break;
417 }
418 s_resolversLock.unlock();
419 if (!resolved)
420 _sntprintf(pszBuffer, 64, _T("CMD_0x%04X"), code);
421 }
422 return pszBuffer;
423 }
424
425 /**
426 * Register NXCP message name resolver
427 */
428 void LIBNETXMS_EXPORTABLE NXCPRegisterMessageNameResolver(NXCPMessageNameResolver r)
429 {
430 s_resolversLock.lock();
431 if (s_resolvers.indexOf((void *)r) == -1)
432 s_resolvers.add((void *)r);
433 s_resolversLock.unlock();
434 }
435
436 /**
437 * Unregister NXCP message name resolver
438 */
439 void LIBNETXMS_EXPORTABLE NXCPUnregisterMessageNameResolver(NXCPMessageNameResolver r)
440 {
441 s_resolversLock.lock();
442 s_resolvers.remove((void *)r);
443 s_resolversLock.unlock();
444 }
445
446 /**
447 * Init NXCP receiver buffer
448 */
449 void LIBNETXMS_EXPORTABLE NXCPInitBuffer(NXCP_BUFFER *nxcpBuffer)
450 {
451 nxcpBuffer->bufferSize = 0;
452 nxcpBuffer->bufferPos = 0;
453 }
454
455 /**
456 * Receive raw CSCP message from network
457 * If pMsg is NULL, temporary buffer will be re-initialized
458 * Returns message size on success or:
459 * 0 if connection is closed
460 * <0 on socket errors
461 * 1 if message is too large to fit in buffer (normal messages is at least 16
462 * bytes long, so we never get length of 1 for valid message)
463 * In this case, only message header will be copied into buffer
464 * 2 Message decryption failed
465 * 3 Receive timeout
466 */
467 int LIBNETXMS_EXPORTABLE RecvNXCPMessageEx(AbstractCommChannel *channel, NXCP_MESSAGE **msgBuffer,
468 NXCP_BUFFER *nxcpBuffer, UINT32 *bufferSize,
469 NXCPEncryptionContext **ppCtx,
470 BYTE **decryptionBuffer, UINT32 dwTimeout,
471 UINT32 maxMsgSize)
472 {
473 UINT32 dwMsgSize = 0, dwBytesRead = 0, dwBytesToCopy;
474 int iErr;
475 BOOL bSkipMsg = FALSE;
476
477 // Initialize buffer if requested
478 if (msgBuffer == NULL)
479 {
480 nxcpBuffer->bufferSize = 0;
481 nxcpBuffer->bufferPos = 0;
482 return 0;
483 }
484
485 // Check if we have something in buffer
486 if (nxcpBuffer->bufferSize > 0)
487 {
488 // Handle the case when entire message header have not been read into the buffer
489 if (nxcpBuffer->bufferSize < NXCP_HEADER_SIZE)
490 {
491 // Most likely we are at the buffer end, so move content
492 // to the beginning
493 memmove(nxcpBuffer->buffer, &nxcpBuffer->buffer[nxcpBuffer->bufferPos], nxcpBuffer->bufferSize);
494 nxcpBuffer->bufferPos = 0;
495
496 // Receive new portion of data from the network
497 // and append it to existing data in buffer
498 iErr = channel->recv(&nxcpBuffer->buffer[nxcpBuffer->bufferSize],
499 NXCP_TEMP_BUF_SIZE - nxcpBuffer->bufferSize, dwTimeout);
500 if (iErr <= 0)
501 return (iErr == -2) ? 3 : iErr;
502 nxcpBuffer->bufferSize += (UINT32)iErr;
503 }
504
505 // Get message size from message header and copy available
506 // message bytes from buffer
507 dwMsgSize = ntohl(((NXCP_MESSAGE *)(&nxcpBuffer->buffer[nxcpBuffer->bufferPos]))->size);
508 if (dwMsgSize > *bufferSize)
509 {
510 if ((*bufferSize >= maxMsgSize) || (dwMsgSize > maxMsgSize))
511 {
512 bSkipMsg = TRUE; // Message is too large, will skip it
513 memcpy(*msgBuffer, &nxcpBuffer->buffer[nxcpBuffer->bufferPos], NXCP_HEADER_SIZE);
514 }
515 else
516 {
517 // Increase buffer
518 *bufferSize = dwMsgSize;
519 *msgBuffer = (NXCP_MESSAGE *)realloc(*msgBuffer, *bufferSize);
520 if (decryptionBuffer != NULL)
521 *decryptionBuffer = (BYTE *)realloc(*decryptionBuffer, *bufferSize);
522 }
523 }
524 dwBytesRead = std::min(dwMsgSize, nxcpBuffer->bufferSize);
525 if (!bSkipMsg)
526 memcpy(*msgBuffer, &nxcpBuffer->buffer[nxcpBuffer->bufferPos], dwBytesRead);
527 nxcpBuffer->bufferSize -= dwBytesRead;
528 nxcpBuffer->bufferPos = (nxcpBuffer->bufferSize > 0) ? (nxcpBuffer->bufferPos + dwBytesRead) : 0;
529 if (dwBytesRead == dwMsgSize)
530 goto decrypt_message;
531 }
532
533 // Receive rest of message from the network
534 // Buffer is empty now
535 nxcpBuffer->bufferSize = 0;
536 nxcpBuffer->bufferPos = 0;
537 do
538 {
539 iErr = channel->recv(&nxcpBuffer->buffer[nxcpBuffer->bufferSize],
540 NXCP_TEMP_BUF_SIZE - nxcpBuffer->bufferSize, dwTimeout);
541 if (iErr <= 0)
542 return (iErr == -2) ? 3 : iErr;
543
544 if (dwBytesRead == 0) // New message?
545 {
546 if ((iErr + nxcpBuffer->bufferSize) < NXCP_HEADER_SIZE)
547 {
548 // Header not received completely
549 nxcpBuffer->bufferSize += iErr;
550 continue;
551 }
552 iErr += nxcpBuffer->bufferSize;
553 nxcpBuffer->bufferSize = 0;
554
555 dwMsgSize = ntohl(((NXCP_MESSAGE *)(nxcpBuffer->buffer))->size);
556 if (dwMsgSize > *bufferSize)
557 {
558 if ((*bufferSize >= maxMsgSize) || (dwMsgSize > maxMsgSize))
559 {
560 bSkipMsg = TRUE; // Message is too large, will skip it
561 memcpy(*msgBuffer, nxcpBuffer->buffer, NXCP_HEADER_SIZE);
562 }
563 else
564 {
565 // Increase buffer
566 *bufferSize = dwMsgSize;
567 *msgBuffer = (NXCP_MESSAGE *)realloc(*msgBuffer, *bufferSize);
568 if (decryptionBuffer != NULL)
569 *decryptionBuffer = (BYTE *)realloc(*decryptionBuffer, *bufferSize);
570 }
571 }
572 }
573 dwBytesToCopy = std::min((UINT32)iErr, dwMsgSize - dwBytesRead);
574 if (!bSkipMsg)
575 memcpy(((char *)(*msgBuffer)) + dwBytesRead, nxcpBuffer->buffer, dwBytesToCopy);
576 dwBytesRead += dwBytesToCopy;
577 }
578 while((dwBytesRead < dwMsgSize) || (dwBytesRead < NXCP_HEADER_SIZE));
579
580 // Check if we have something left in buffer
581 if (dwBytesToCopy < (UINT32)iErr)
582 {
583 nxcpBuffer->bufferPos = dwBytesToCopy;
584 nxcpBuffer->bufferSize = (UINT32)iErr - dwBytesToCopy;
585 }
586
587 // Check for encrypted message
588 decrypt_message:
589 if ((!bSkipMsg) && (ntohs((*msgBuffer)->code) == CMD_ENCRYPTED_MESSAGE))
590 {
591 if ((*ppCtx != NULL) && (*ppCtx != PROXY_ENCRYPTION_CTX))
592 {
593 if ((*ppCtx)->decryptMessage((NXCP_ENCRYPTED_MESSAGE *)(*msgBuffer), *decryptionBuffer))
594 {
595 dwMsgSize = ntohl((*msgBuffer)->size);
596 }
597 else
598 {
599 dwMsgSize = 2; // Decryption failed
600 }
601 }
602 else
603 {
604 if (*ppCtx != PROXY_ENCRYPTION_CTX)
605 dwMsgSize = 2;
606 }
607 }
608
609 return bSkipMsg ? 1 : (int)dwMsgSize;
610 }
611
612 int LIBNETXMS_EXPORTABLE RecvNXCPMessageEx(SOCKET hSocket, NXCP_MESSAGE **msgBuffer,
613 NXCP_BUFFER *nxcpBuffer, UINT32 *bufferSize,
614 NXCPEncryptionContext **ppCtx,
615 BYTE **decryptionBuffer, UINT32 dwTimeout,
616 UINT32 maxMsgSize)
617 {
618 SocketCommChannel *channel = new SocketCommChannel(hSocket, false);
619 int result = RecvNXCPMessageEx(channel, msgBuffer, nxcpBuffer, bufferSize, ppCtx, decryptionBuffer, dwTimeout, maxMsgSize);
620 channel->decRefCount();
621 return result;
622 }
623
624 int LIBNETXMS_EXPORTABLE RecvNXCPMessage(SOCKET hSocket, NXCP_MESSAGE *msgBuffer,
625 NXCP_BUFFER *nxcpBuffer, UINT32 bufferSize,
626 NXCPEncryptionContext **ppCtx,
627 BYTE *decryptionBuffer, UINT32 dwTimeout)
628 {
629 NXCP_MESSAGE *mb = msgBuffer;
630 UINT32 bs = bufferSize;
631 BYTE *db = decryptionBuffer;
632 return RecvNXCPMessageEx(hSocket, (msgBuffer != NULL) ? &mb : NULL, nxcpBuffer, &bs, ppCtx,
633 (decryptionBuffer != NULL) ? &db : NULL, dwTimeout, bufferSize);
634 }
635
636 int LIBNETXMS_EXPORTABLE RecvNXCPMessage(AbstractCommChannel *channel, NXCP_MESSAGE *msgBuffer,
637 NXCP_BUFFER *nxcpBuffer, UINT32 bufferSize,
638 NXCPEncryptionContext **ppCtx,
639 BYTE *decryptionBuffer, UINT32 dwTimeout)
640 {
641 NXCP_MESSAGE *mb = msgBuffer;
642 UINT32 bs = bufferSize;
643 BYTE *db = decryptionBuffer;
644 return RecvNXCPMessageEx(channel, (msgBuffer != NULL) ? &mb : NULL, nxcpBuffer, &bs, ppCtx,
645 (decryptionBuffer != NULL) ? &db : NULL, dwTimeout, bufferSize);
646 }
647
648 /**
649 * Create NXCP message with raw data (MF_BINARY flag)
650 * If buffer is NULL, new buffer is allocated with malloc()
651 * Buffer should be at least dataSize + NXCP_HEADER_SIZE + 8 bytes.
652 */
653 NXCP_MESSAGE LIBNETXMS_EXPORTABLE *CreateRawNXCPMessage(UINT16 code, UINT32 id, UINT16 flags,
654 const void *data, size_t dataSize,
655 NXCP_MESSAGE *buffer, bool allowCompression)
656 {
657 NXCP_MESSAGE *msg = (buffer == NULL) ? (NXCP_MESSAGE *)malloc(dataSize + NXCP_HEADER_SIZE + 8) : buffer;
658
659 // Message should be aligned to 8 bytes boundary
660 size_t padding = (8 - ((dataSize + NXCP_HEADER_SIZE) % 8)) & 7;
661
662 msg->code = htons(code);
663 msg->flags = htons(MF_BINARY | flags);
664 msg->id = htonl(id);
665 size_t msgSize = dataSize + NXCP_HEADER_SIZE + padding;
666 msg->size = htonl((UINT32)msgSize);
667 msg->numFields = htonl((UINT32)dataSize); // numFields contains actual data size for binary message
668
669 if (allowCompression)
670 {
671 z_stream stream;
672 stream.zalloc = Z_NULL;
673 stream.zfree = Z_NULL;
674 stream.opaque = Z_NULL;
675 stream.avail_in = 0;
676 stream.next_in = Z_NULL;
677 if (deflateInit(&stream, 9) == Z_OK)
678 {
679 stream.next_in = (BYTE *)data;
680 stream.avail_in = (UINT32)dataSize;
681 stream.next_out = (BYTE *)msg->fields + 4;
682 stream.avail_out = (UINT32)(dataSize + padding - 4);
683 if (deflate(&stream, Z_FINISH) == Z_STREAM_END)
684 {
685 size_t compMsgSize = dataSize - stream.avail_out + NXCP_HEADER_SIZE + 4;
686 // Message should be aligned to 8 bytes boundary
687 compMsgSize += (8 - (compMsgSize % 8)) & 7;
688 if (compMsgSize < msgSize - 4)
689 {
690 msg->flags |= htons(MF_COMPRESSED);
691 memcpy((BYTE *)msg + NXCP_HEADER_SIZE, &msg->size, 4); // Save size of uncompressed message
692 msg->size = htonl((UINT32)compMsgSize);
693 }
694 else
695 {
696 // compression produce message of same size
697 memcpy(msg->fields, data, dataSize);
698 }
699 }
700 else
701 {
702 // compression failed, send uncompressed message
703 memcpy(msg->fields, data, dataSize);
704 }
705 deflateEnd(&stream);
706 }
707 }
708 else
709 {
710 memcpy(msg->fields, data, dataSize);
711 }
712 return msg;
713 }
714
715 /**
716 * Send file over NXCP
717 */
718 bool LIBNETXMS_EXPORTABLE SendFileOverNXCP(SOCKET hSocket, UINT32 id, const TCHAR *pszFile,
719 NXCPEncryptionContext *pCtx, long offset,
720 void (* progressCallback)(INT64, void *), void *cbArg,
721 MUTEX mutex, NXCPStreamCompressionMethod compressionMethod)
722 {
723 SocketCommChannel *ch = new SocketCommChannel(hSocket, false);
724 bool result = SendFileOverNXCP(ch, id, pszFile, pCtx, offset, progressCallback, cbArg, mutex, compressionMethod, NULL);
725 ch->decRefCount();
726 return result;
727 }
728
729 /**
730 * Send file over NXCP
731 */
732 bool LIBNETXMS_EXPORTABLE SendFileOverNXCP(AbstractCommChannel *channel, UINT32 id, const TCHAR *pszFile,
733 NXCPEncryptionContext *pCtx, long offset,
734 void (* progressCallback)(INT64, void *), void *cbArg,
735 MUTEX mutex, NXCPStreamCompressionMethod compressionMethod,
736 VolatileCounter *cancelationFlag)
737 {
738 int hFile, iBytes;
739 INT64 bytesTransferred = 0;
740 UINT32 dwPadding;
741 bool success = false;
742 NXCP_MESSAGE *pMsg;
743 NXCP_ENCRYPTED_MESSAGE *pEnMsg;
744
745 StreamCompressor *compressor = (compressionMethod != NXCP_STREAM_COMPRESSION_NONE) ? StreamCompressor::create(compressionMethod, true, FILE_BUFFER_SIZE) : NULL;
746 BYTE *compBuffer = (compressor != NULL) ? (BYTE *)malloc(FILE_BUFFER_SIZE) : NULL;
747
748 hFile = _topen(pszFile, O_RDONLY | O_BINARY);
749 if (hFile != -1)
750 {
751 NX_STAT_STRUCT st;
752 NX_FSTAT(hFile, &st);
753 long fileSize = (long)st.st_size;
754 if (labs(offset) > fileSize)
755 offset = 0;
756 long bytesToRead = (offset < 0) ? (0 - offset) : (fileSize - offset);
757
758 if (lseek(hFile, offset, (offset < 0) ? SEEK_END : SEEK_SET) != -1)
759 {
760 // Allocate message and prepare it's header
761 pMsg = (NXCP_MESSAGE *)malloc(NXCP_HEADER_SIZE + 8 + ((compressor != NULL) ? compressor->compressBufferSize(FILE_BUFFER_SIZE) + 4 : FILE_BUFFER_SIZE));
762 pMsg->id = htonl(id);
763 pMsg->code = htons(CMD_FILE_DATA);
764 pMsg->flags = htons(MF_BINARY | MF_STREAM | ((compressionMethod != NXCP_STREAM_COMPRESSION_NONE) ? MF_COMPRESSED : 0));
765
766 while(true)
767 {
768 if(cancelationFlag != NULL && (*cancelationFlag) > 0)
769 break;
770
771 if (compressor != NULL)
772 {
773 iBytes = _read(hFile, compBuffer, MIN(FILE_BUFFER_SIZE, bytesToRead));
774 if (iBytes < 0)
775 break;
776 bytesToRead -= iBytes;
777 // Each compressed data block prepended with 4 bytes header
778 // First byte contains compression method, second is always 0,
779 // third and fourth contains uncompressed block size in network byte order
780 *((BYTE *)pMsg->fields) = (BYTE)compressionMethod;
781 *((BYTE *)pMsg->fields + 1) = 0;
782 *((UINT16 *)((BYTE *)pMsg->fields + 2)) = htons((UINT16)iBytes);
783 iBytes = (int)compressor->compress(compBuffer, iBytes, (BYTE *)pMsg->fields + 4, compressor->compressBufferSize(FILE_BUFFER_SIZE)) + 4;
784 }
785 else
786 {
787 iBytes = _read(hFile, pMsg->fields, MIN(FILE_BUFFER_SIZE, bytesToRead));
788 if (iBytes < 0)
789 break;
790 bytesToRead -= iBytes;
791 }
792
793 // Message should be aligned to 8 bytes boundary
794 dwPadding = (8 - (((UINT32)iBytes + NXCP_HEADER_SIZE) % 8)) & 7;
795 pMsg->size = htonl((UINT32)iBytes + NXCP_HEADER_SIZE + dwPadding);
796 pMsg->numFields = htonl((UINT32)iBytes); // numFields contains actual data size for binary message
797 if (bytesToRead <= 0)
798 pMsg->flags |= htons(MF_END_OF_FILE);
799
800 if (pCtx != NULL)
801 {
802 pEnMsg = pCtx->encryptMessage(pMsg);
803 if (pEnMsg != NULL)
804 {
805 channel->send(pEnMsg, ntohl(pEnMsg->size), mutex);
806 free(pEnMsg);
807 }
808 }
809 else
810 {
811 if (channel->send(pMsg, (UINT32)iBytes + NXCP_HEADER_SIZE + dwPadding, mutex) <= 0)
812 break; // Send error
813 }
814 if (progressCallback != NULL)
815 {
816 bytesTransferred += iBytes;
817 progressCallback(bytesTransferred, cbArg);
818 }
819
820 if (bytesToRead <= 0)
821 {
822 // End of file
823 success = true;
824 break;
825 }
826 }
827
828 free(pMsg);
829 }
830 _close(hFile);
831 }
832
833 free(compBuffer);
834 delete compressor;
835
836 // If file upload failed, send CMD_ABORT_FILE_TRANSFER
837 if (!success)
838 {
839 NXCP_MESSAGE msg;
840
841 msg.id = htonl(id);
842 msg.code = htons(CMD_ABORT_FILE_TRANSFER);
843 msg.flags = htons(MF_BINARY);
844 msg.numFields = 0;
845 msg.size = htonl(NXCP_HEADER_SIZE);
846 if (pCtx != NULL)
847 {
848 pEnMsg = pCtx->encryptMessage(&msg);
849 if (pEnMsg != NULL)
850 {
851 channel->send(pEnMsg, ntohl(pEnMsg->size), mutex);
852 free(pEnMsg);
853 }
854 }
855 else
856 {
857 channel->send(&msg, NXCP_HEADER_SIZE, mutex);
858 }
859 }
860
861 return success;
862 }
863
864 /**
865 * Get version of NXCP used by peer
866 */
867 bool LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(AbstractCommChannel *channel, int *pnVersion, MUTEX mutex)
868 {
869 NXCP_MESSAGE msg;
870 NXCPEncryptionContext *pDummyCtx = NULL;
871 NXCP_BUFFER *pBuffer;
872 bool success = false;
873 int nSize;
874
875 msg.id = 0;
876 msg.numFields = 0;
877 msg.size = htonl(NXCP_HEADER_SIZE);
878 msg.code = htons(CMD_GET_NXCP_CAPS);
879 msg.flags = htons(MF_CONTROL);
880 if (channel->send(&msg, NXCP_HEADER_SIZE, mutex) == NXCP_HEADER_SIZE)
881 {
882 pBuffer = (NXCP_BUFFER *)malloc(sizeof(NXCP_BUFFER));
883 NXCPInitBuffer(pBuffer);
884 nSize = RecvNXCPMessage(channel, &msg, pBuffer, NXCP_HEADER_SIZE, &pDummyCtx, NULL, 30000);
885 if ((nSize == NXCP_HEADER_SIZE) &&
886 (ntohs(msg.code) == CMD_NXCP_CAPS) &&
887 (ntohs(msg.flags) & MF_CONTROL))
888 {
889 success = true;
890 *pnVersion = ntohl(msg.numFields) >> 24;
891 }
892 else if ((nSize == 1) || (nSize == 3) || (nSize >= NXCP_HEADER_SIZE))
893 {
894 // We don't receive any answer or receive invalid answer -
895 // assume that peer doesn't understand CMD_GET_NXCP_CAPS message
896 // and set version number to 1
897 success = true;
898 *pnVersion = 1;
899 }
900 free(pBuffer);
901 }
902 return success;
903 }
904
905 /**
906 * Get version of NXCP used by peer
907 */
908 bool LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(SOCKET s, int *pnVersion, MUTEX mutex)
909 {
910 SocketCommChannel *channel = new SocketCommChannel(s, false);
911 bool success = NXCPGetPeerProtocolVersion(channel, pnVersion, mutex);
912 channel->decRefCount();
913 return success;
914 }