5454f471627ff551d3f935f23921455e66f94236
[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 };
400
401 if ((code >= CMD_LOGIN) && (code <= CMD_EXPAND_MACROS))
402 {
403 _tcscpy(pszBuffer, pszMsgNames[code - CMD_LOGIN]);
404 }
405 else
406 {
407 bool resolved = false;
408 s_resolversLock.lock();
409 for(int i = 0; i < s_resolvers.size(); i++)
410 if (((NXCPMessageNameResolver)s_resolvers.get(i))(code, pszBuffer))
411 {
412 resolved = true;
413 break;
414 }
415 s_resolversLock.unlock();
416 if (!resolved)
417 _sntprintf(pszBuffer, 64, _T("CMD_0x%04X"), code);
418 }
419 return pszBuffer;
420 }
421
422 /**
423 * Register NXCP message name resolver
424 */
425 void LIBNETXMS_EXPORTABLE NXCPRegisterMessageNameResolver(NXCPMessageNameResolver r)
426 {
427 s_resolversLock.lock();
428 if (s_resolvers.indexOf((void *)r) == -1)
429 s_resolvers.add((void *)r);
430 s_resolversLock.unlock();
431 }
432
433 /**
434 * Unregister NXCP message name resolver
435 */
436 void LIBNETXMS_EXPORTABLE NXCPUnregisterMessageNameResolver(NXCPMessageNameResolver r)
437 {
438 s_resolversLock.lock();
439 s_resolvers.remove((void *)r);
440 s_resolversLock.unlock();
441 }
442
443 /**
444 * Init NXCP receiver buffer
445 */
446 void LIBNETXMS_EXPORTABLE NXCPInitBuffer(NXCP_BUFFER *nxcpBuffer)
447 {
448 nxcpBuffer->bufferSize = 0;
449 nxcpBuffer->bufferPos = 0;
450 }
451
452 /**
453 * Receive raw CSCP message from network
454 * If pMsg is NULL, temporary buffer will be re-initialized
455 * Returns message size on success or:
456 * 0 if connection is closed
457 * <0 on socket errors
458 * 1 if message is too large to fit in buffer (normal messages is at least 16
459 * bytes long, so we never get length of 1 for valid message)
460 * In this case, only message header will be copied into buffer
461 * 2 Message decryption failed
462 * 3 Receive timeout
463 */
464 int LIBNETXMS_EXPORTABLE RecvNXCPMessageEx(AbstractCommChannel *channel, NXCP_MESSAGE **msgBuffer,
465 NXCP_BUFFER *nxcpBuffer, UINT32 *bufferSize,
466 NXCPEncryptionContext **ppCtx,
467 BYTE **decryptionBuffer, UINT32 dwTimeout,
468 UINT32 maxMsgSize)
469 {
470 UINT32 dwMsgSize = 0, dwBytesRead = 0, dwBytesToCopy;
471 int iErr;
472 BOOL bSkipMsg = FALSE;
473
474 // Initialize buffer if requested
475 if (msgBuffer == NULL)
476 {
477 nxcpBuffer->bufferSize = 0;
478 nxcpBuffer->bufferPos = 0;
479 return 0;
480 }
481
482 // Check if we have something in buffer
483 if (nxcpBuffer->bufferSize > 0)
484 {
485 // Handle the case when entire message header have not been read into the buffer
486 if (nxcpBuffer->bufferSize < NXCP_HEADER_SIZE)
487 {
488 // Most likely we are at the buffer end, so move content
489 // to the beginning
490 memmove(nxcpBuffer->buffer, &nxcpBuffer->buffer[nxcpBuffer->bufferPos], nxcpBuffer->bufferSize);
491 nxcpBuffer->bufferPos = 0;
492
493 // Receive new portion of data from the network
494 // and append it to existing data in buffer
495 iErr = channel->recv(&nxcpBuffer->buffer[nxcpBuffer->bufferSize],
496 NXCP_TEMP_BUF_SIZE - nxcpBuffer->bufferSize, dwTimeout);
497 if (iErr <= 0)
498 return (iErr == -2) ? 3 : iErr;
499 nxcpBuffer->bufferSize += (UINT32)iErr;
500 }
501
502 // Get message size from message header and copy available
503 // message bytes from buffer
504 dwMsgSize = ntohl(((NXCP_MESSAGE *)(&nxcpBuffer->buffer[nxcpBuffer->bufferPos]))->size);
505 if (dwMsgSize > *bufferSize)
506 {
507 if ((*bufferSize >= maxMsgSize) || (dwMsgSize > maxMsgSize))
508 {
509 bSkipMsg = TRUE; // Message is too large, will skip it
510 memcpy(*msgBuffer, &nxcpBuffer->buffer[nxcpBuffer->bufferPos], NXCP_HEADER_SIZE);
511 }
512 else
513 {
514 // Increase buffer
515 *bufferSize = dwMsgSize;
516 *msgBuffer = (NXCP_MESSAGE *)realloc(*msgBuffer, *bufferSize);
517 if (decryptionBuffer != NULL)
518 *decryptionBuffer = (BYTE *)realloc(*decryptionBuffer, *bufferSize);
519 }
520 }
521 dwBytesRead = std::min(dwMsgSize, nxcpBuffer->bufferSize);
522 if (!bSkipMsg)
523 memcpy(*msgBuffer, &nxcpBuffer->buffer[nxcpBuffer->bufferPos], dwBytesRead);
524 nxcpBuffer->bufferSize -= dwBytesRead;
525 nxcpBuffer->bufferPos = (nxcpBuffer->bufferSize > 0) ? (nxcpBuffer->bufferPos + dwBytesRead) : 0;
526 if (dwBytesRead == dwMsgSize)
527 goto decrypt_message;
528 }
529
530 // Receive rest of message from the network
531 // Buffer is empty now
532 nxcpBuffer->bufferSize = 0;
533 nxcpBuffer->bufferPos = 0;
534 do
535 {
536 iErr = channel->recv(&nxcpBuffer->buffer[nxcpBuffer->bufferSize],
537 NXCP_TEMP_BUF_SIZE - nxcpBuffer->bufferSize, dwTimeout);
538 if (iErr <= 0)
539 return (iErr == -2) ? 3 : iErr;
540
541 if (dwBytesRead == 0) // New message?
542 {
543 if ((iErr + nxcpBuffer->bufferSize) < NXCP_HEADER_SIZE)
544 {
545 // Header not received completely
546 nxcpBuffer->bufferSize += iErr;
547 continue;
548 }
549 iErr += nxcpBuffer->bufferSize;
550 nxcpBuffer->bufferSize = 0;
551
552 dwMsgSize = ntohl(((NXCP_MESSAGE *)(nxcpBuffer->buffer))->size);
553 if (dwMsgSize > *bufferSize)
554 {
555 if ((*bufferSize >= maxMsgSize) || (dwMsgSize > maxMsgSize))
556 {
557 bSkipMsg = TRUE; // Message is too large, will skip it
558 memcpy(*msgBuffer, nxcpBuffer->buffer, NXCP_HEADER_SIZE);
559 }
560 else
561 {
562 // Increase buffer
563 *bufferSize = dwMsgSize;
564 *msgBuffer = (NXCP_MESSAGE *)realloc(*msgBuffer, *bufferSize);
565 if (decryptionBuffer != NULL)
566 *decryptionBuffer = (BYTE *)realloc(*decryptionBuffer, *bufferSize);
567 }
568 }
569 }
570 dwBytesToCopy = std::min((UINT32)iErr, dwMsgSize - dwBytesRead);
571 if (!bSkipMsg)
572 memcpy(((char *)(*msgBuffer)) + dwBytesRead, nxcpBuffer->buffer, dwBytesToCopy);
573 dwBytesRead += dwBytesToCopy;
574 }
575 while((dwBytesRead < dwMsgSize) || (dwBytesRead < NXCP_HEADER_SIZE));
576
577 // Check if we have something left in buffer
578 if (dwBytesToCopy < (UINT32)iErr)
579 {
580 nxcpBuffer->bufferPos = dwBytesToCopy;
581 nxcpBuffer->bufferSize = (UINT32)iErr - dwBytesToCopy;
582 }
583
584 // Check for encrypted message
585 decrypt_message:
586 if ((!bSkipMsg) && (ntohs((*msgBuffer)->code) == CMD_ENCRYPTED_MESSAGE))
587 {
588 if ((*ppCtx != NULL) && (*ppCtx != PROXY_ENCRYPTION_CTX))
589 {
590 if ((*ppCtx)->decryptMessage((NXCP_ENCRYPTED_MESSAGE *)(*msgBuffer), *decryptionBuffer))
591 {
592 dwMsgSize = ntohl((*msgBuffer)->size);
593 }
594 else
595 {
596 dwMsgSize = 2; // Decryption failed
597 }
598 }
599 else
600 {
601 if (*ppCtx != PROXY_ENCRYPTION_CTX)
602 dwMsgSize = 2;
603 }
604 }
605
606 return bSkipMsg ? 1 : (int)dwMsgSize;
607 }
608
609 int LIBNETXMS_EXPORTABLE RecvNXCPMessageEx(SOCKET hSocket, NXCP_MESSAGE **msgBuffer,
610 NXCP_BUFFER *nxcpBuffer, UINT32 *bufferSize,
611 NXCPEncryptionContext **ppCtx,
612 BYTE **decryptionBuffer, UINT32 dwTimeout,
613 UINT32 maxMsgSize)
614 {
615 SocketCommChannel *channel = new SocketCommChannel(hSocket, false);
616 int result = RecvNXCPMessageEx(channel, msgBuffer, nxcpBuffer, bufferSize, ppCtx, decryptionBuffer, dwTimeout, maxMsgSize);
617 channel->decRefCount();
618 return result;
619 }
620
621 int LIBNETXMS_EXPORTABLE RecvNXCPMessage(SOCKET hSocket, NXCP_MESSAGE *msgBuffer,
622 NXCP_BUFFER *nxcpBuffer, UINT32 bufferSize,
623 NXCPEncryptionContext **ppCtx,
624 BYTE *decryptionBuffer, UINT32 dwTimeout)
625 {
626 NXCP_MESSAGE *mb = msgBuffer;
627 UINT32 bs = bufferSize;
628 BYTE *db = decryptionBuffer;
629 return RecvNXCPMessageEx(hSocket, (msgBuffer != NULL) ? &mb : NULL, nxcpBuffer, &bs, ppCtx,
630 (decryptionBuffer != NULL) ? &db : NULL, dwTimeout, bufferSize);
631 }
632
633 int LIBNETXMS_EXPORTABLE RecvNXCPMessage(AbstractCommChannel *channel, NXCP_MESSAGE *msgBuffer,
634 NXCP_BUFFER *nxcpBuffer, UINT32 bufferSize,
635 NXCPEncryptionContext **ppCtx,
636 BYTE *decryptionBuffer, UINT32 dwTimeout)
637 {
638 NXCP_MESSAGE *mb = msgBuffer;
639 UINT32 bs = bufferSize;
640 BYTE *db = decryptionBuffer;
641 return RecvNXCPMessageEx(channel, (msgBuffer != NULL) ? &mb : NULL, nxcpBuffer, &bs, ppCtx,
642 (decryptionBuffer != NULL) ? &db : NULL, dwTimeout, bufferSize);
643 }
644
645 /**
646 * Create NXCP message with raw data (MF_BINARY flag)
647 * If buffer is NULL, new buffer is allocated with malloc()
648 * Buffer should be at least dataSize + NXCP_HEADER_SIZE + 8 bytes.
649 */
650 NXCP_MESSAGE LIBNETXMS_EXPORTABLE *CreateRawNXCPMessage(UINT16 code, UINT32 id, UINT16 flags,
651 const void *data, size_t dataSize,
652 NXCP_MESSAGE *buffer, bool allowCompression)
653 {
654 NXCP_MESSAGE *msg = (buffer == NULL) ? (NXCP_MESSAGE *)malloc(dataSize + NXCP_HEADER_SIZE + 8) : buffer;
655
656 // Message should be aligned to 8 bytes boundary
657 size_t padding = (8 - ((dataSize + NXCP_HEADER_SIZE) % 8)) & 7;
658
659 msg->code = htons(code);
660 msg->flags = htons(MF_BINARY | flags);
661 msg->id = htonl(id);
662 size_t msgSize = dataSize + NXCP_HEADER_SIZE + padding;
663 msg->size = htonl((UINT32)msgSize);
664 msg->numFields = htonl((UINT32)dataSize); // numFields contains actual data size for binary message
665
666 if (allowCompression)
667 {
668 z_stream stream;
669 stream.zalloc = Z_NULL;
670 stream.zfree = Z_NULL;
671 stream.opaque = Z_NULL;
672 stream.avail_in = 0;
673 stream.next_in = Z_NULL;
674 if (deflateInit(&stream, 9) == Z_OK)
675 {
676 stream.next_in = (BYTE *)data;
677 stream.avail_in = (UINT32)dataSize;
678 stream.next_out = (BYTE *)msg->fields + 4;
679 stream.avail_out = (UINT32)(dataSize + padding - 4);
680 if (deflate(&stream, Z_FINISH) == Z_STREAM_END)
681 {
682 size_t compMsgSize = dataSize - stream.avail_out + NXCP_HEADER_SIZE + 4;
683 // Message should be aligned to 8 bytes boundary
684 compMsgSize += (8 - (compMsgSize % 8)) & 7;
685 if (compMsgSize < msgSize - 4)
686 {
687 msg->flags |= htons(MF_COMPRESSED);
688 memcpy((BYTE *)msg + NXCP_HEADER_SIZE, &msg->size, 4); // Save size of uncompressed message
689 msg->size = htonl((UINT32)compMsgSize);
690 }
691 else
692 {
693 // compression produce message of same size
694 memcpy(msg->fields, data, dataSize);
695 }
696 }
697 else
698 {
699 // compression failed, send uncompressed message
700 memcpy(msg->fields, data, dataSize);
701 }
702 deflateEnd(&stream);
703 }
704 }
705 else
706 {
707 memcpy(msg->fields, data, dataSize);
708 }
709 return msg;
710 }
711
712 /**
713 * Send file over NXCP
714 */
715 bool LIBNETXMS_EXPORTABLE SendFileOverNXCP(SOCKET hSocket, UINT32 id, const TCHAR *pszFile,
716 NXCPEncryptionContext *pCtx, long offset,
717 void (* progressCallback)(INT64, void *), void *cbArg,
718 MUTEX mutex, NXCPStreamCompressionMethod compressionMethod)
719 {
720 SocketCommChannel *ch = new SocketCommChannel(hSocket, false);
721 bool result = SendFileOverNXCP(ch, id, pszFile, pCtx, offset, progressCallback, cbArg, mutex, compressionMethod);
722 ch->decRefCount();
723 return result;
724 }
725
726 /**
727 * Send file over NXCP
728 */
729 bool LIBNETXMS_EXPORTABLE SendFileOverNXCP(AbstractCommChannel *channel, UINT32 id, const TCHAR *pszFile,
730 NXCPEncryptionContext *pCtx, long offset,
731 void (* progressCallback)(INT64, void *), void *cbArg,
732 MUTEX mutex, NXCPStreamCompressionMethod compressionMethod)
733 {
734 int hFile, iBytes;
735 INT64 bytesTransferred = 0;
736 UINT32 dwPadding;
737 bool success = false;
738 NXCP_MESSAGE *pMsg;
739 NXCP_ENCRYPTED_MESSAGE *pEnMsg;
740
741 StreamCompressor *compressor = (compressionMethod != NXCP_STREAM_COMPRESSION_NONE) ? StreamCompressor::create(compressionMethod, true, FILE_BUFFER_SIZE) : NULL;
742 BYTE *compBuffer = (compressor != NULL) ? (BYTE *)malloc(FILE_BUFFER_SIZE) : NULL;
743
744 hFile = _topen(pszFile, O_RDONLY | O_BINARY);
745 if (hFile != -1)
746 {
747 NX_STAT_STRUCT st;
748 NX_FSTAT(hFile, &st);
749 long fileSize = (long)st.st_size;
750 if (labs(offset) > fileSize)
751 offset = 0;
752 long bytesToRead = (offset < 0) ? (0 - offset) : (fileSize - offset);
753
754 if (lseek(hFile, offset, (offset < 0) ? SEEK_END : SEEK_SET) != -1)
755 {
756 // Allocate message and prepare it's header
757 pMsg = (NXCP_MESSAGE *)malloc(NXCP_HEADER_SIZE + 8 + ((compressor != NULL) ? compressor->compressBufferSize(FILE_BUFFER_SIZE) + 4 : FILE_BUFFER_SIZE));
758 pMsg->id = htonl(id);
759 pMsg->code = htons(CMD_FILE_DATA);
760 pMsg->flags = htons(MF_BINARY | MF_STREAM | ((compressionMethod != NXCP_STREAM_COMPRESSION_NONE) ? MF_COMPRESSED : 0));
761
762 while(true)
763 {
764 if (compressor != NULL)
765 {
766 iBytes = _read(hFile, compBuffer, MIN(FILE_BUFFER_SIZE, bytesToRead));
767 if (iBytes < 0)
768 break;
769 bytesToRead -= iBytes;
770 // Each compressed data block prepended with 4 bytes header
771 // First byte contains compression method, second is always 0,
772 // third and fourth contains uncompressed block size in network byte order
773 *((BYTE *)pMsg->fields) = (BYTE)compressionMethod;
774 *((BYTE *)pMsg->fields + 1) = 0;
775 *((UINT16 *)((BYTE *)pMsg->fields + 2)) = htons((UINT16)iBytes);
776 iBytes = (int)compressor->compress(compBuffer, iBytes, (BYTE *)pMsg->fields + 4, compressor->compressBufferSize(FILE_BUFFER_SIZE)) + 4;
777 }
778 else
779 {
780 iBytes = _read(hFile, pMsg->fields, MIN(FILE_BUFFER_SIZE, bytesToRead));
781 if (iBytes < 0)
782 break;
783 bytesToRead -= iBytes;
784 }
785
786 // Message should be aligned to 8 bytes boundary
787 dwPadding = (8 - (((UINT32)iBytes + NXCP_HEADER_SIZE) % 8)) & 7;
788 pMsg->size = htonl((UINT32)iBytes + NXCP_HEADER_SIZE + dwPadding);
789 pMsg->numFields = htonl((UINT32)iBytes); // numFields contains actual data size for binary message
790 if (bytesToRead <= 0)
791 pMsg->flags |= htons(MF_END_OF_FILE);
792
793 if (pCtx != NULL)
794 {
795 pEnMsg = pCtx->encryptMessage(pMsg);
796 if (pEnMsg != NULL)
797 {
798 channel->send(pEnMsg, ntohl(pEnMsg->size), mutex);
799 free(pEnMsg);
800 }
801 }
802 else
803 {
804 if (channel->send(pMsg, (UINT32)iBytes + NXCP_HEADER_SIZE + dwPadding, mutex) <= 0)
805 break; // Send error
806 }
807 if (progressCallback != NULL)
808 {
809 bytesTransferred += iBytes;
810 progressCallback(bytesTransferred, cbArg);
811 }
812
813 if (bytesToRead <= 0)
814 {
815 // End of file
816 success = true;
817 break;
818 }
819 }
820
821 free(pMsg);
822 }
823 _close(hFile);
824 }
825
826 free(compBuffer);
827 delete compressor;
828
829 // If file upload failed, send CMD_ABORT_FILE_TRANSFER
830 if (!success)
831 {
832 NXCP_MESSAGE msg;
833
834 msg.id = htonl(id);
835 msg.code = htons(CMD_ABORT_FILE_TRANSFER);
836 msg.flags = htons(MF_BINARY);
837 msg.numFields = 0;
838 msg.size = htonl(NXCP_HEADER_SIZE);
839 if (pCtx != NULL)
840 {
841 pEnMsg = pCtx->encryptMessage(&msg);
842 if (pEnMsg != NULL)
843 {
844 channel->send(pEnMsg, ntohl(pEnMsg->size), mutex);
845 free(pEnMsg);
846 }
847 }
848 else
849 {
850 channel->send(&msg, NXCP_HEADER_SIZE, mutex);
851 }
852 }
853
854 return success;
855 }
856
857 /**
858 * Get version of NXCP used by peer
859 */
860 bool LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(AbstractCommChannel *channel, int *pnVersion, MUTEX mutex)
861 {
862 NXCP_MESSAGE msg;
863 NXCPEncryptionContext *pDummyCtx = NULL;
864 NXCP_BUFFER *pBuffer;
865 bool success = false;
866 int nSize;
867
868 msg.id = 0;
869 msg.numFields = 0;
870 msg.size = htonl(NXCP_HEADER_SIZE);
871 msg.code = htons(CMD_GET_NXCP_CAPS);
872 msg.flags = htons(MF_CONTROL);
873 if (channel->send(&msg, NXCP_HEADER_SIZE, mutex) == NXCP_HEADER_SIZE)
874 {
875 pBuffer = (NXCP_BUFFER *)malloc(sizeof(NXCP_BUFFER));
876 NXCPInitBuffer(pBuffer);
877 nSize = RecvNXCPMessage(channel, &msg, pBuffer, NXCP_HEADER_SIZE, &pDummyCtx, NULL, 30000);
878 if ((nSize == NXCP_HEADER_SIZE) &&
879 (ntohs(msg.code) == CMD_NXCP_CAPS) &&
880 (ntohs(msg.flags) & MF_CONTROL))
881 {
882 success = true;
883 *pnVersion = ntohl(msg.numFields) >> 24;
884 }
885 else if ((nSize == 1) || (nSize == 3) || (nSize >= NXCP_HEADER_SIZE))
886 {
887 // We don't receive any answer or receive invalid answer -
888 // assume that peer doesn't understand CMD_GET_NXCP_CAPS message
889 // and set version number to 1
890 success = true;
891 *pnVersion = 1;
892 }
893 free(pBuffer);
894 }
895 return success;
896 }
897
898 /**
899 * Get version of NXCP used by peer
900 */
901 bool LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(SOCKET s, int *pnVersion, MUTEX mutex)
902 {
903 SocketCommChannel *channel = new SocketCommChannel(s, false);
904 bool success = NXCPGetPeerProtocolVersion(channel, pnVersion, mutex);
905 channel->decRefCount();
906 return success;
907 }