Changelog update
[public/netxms.git] / src / libnetxms / nxcp.cpp
CommitLineData
9fa031cd 1/*
5039dede
AK
2** NetXMS - Network Management System
3** NetXMS Foundation Library
3c463101 4** Copyright (C) 2003-2017 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"
c7c23e6d 25#include <nxcpapi.h>
390271e0 26#include <nxstat.h>
d3a20572 27#include <zlib.h>
5039dede 28
534e1b83 29/**
da9ac8fc
VK
30 * Additional message name resolvers
31 */
32static Array s_resolvers(4, 4, false);
33static Mutex s_resolversLock;
34
35/**
534e1b83
VK
36 * Get symbolic name for message code
37 */
b368969c 38TCHAR LIBNETXMS_EXPORTABLE *NXCPMessageCodeName(WORD code, TCHAR *pszBuffer)
5039dede
AK
39{
40 static const TCHAR *pszMsgNames[] =
41 {
42 _T("CMD_LOGIN"),
43 _T("CMD_LOGIN_RESP"),
44 _T("CMD_KEEPALIVE"),
3c35018e 45 _T("CMD_OPEN_HELPDESK_ISSUE"),
5039dede
AK
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"),
822b5878 52 _T("CMD_RECALCULATE_DCI_VALUES"),
5039dede
AK
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"),
870d2546 65 _T("CMD_EVENT_DB_UPDATE"),
15edffbf 66 _T("CMD_TRAP_CFG_UPDATE"),
5039dede
AK
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"),
f727d089 84 _T("CMD_GET_LOG_DATA"),
5039dede
AK
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"),
6d738067 94 _T("CMD_TEST_DCI_TRANSFORMATION"),
ab621f39 95 _T("CMD_GET_JOB_LIST"),
5039dede
AK
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"),
93599cfd 101 _T("CMD_UNINSTALL_AGENT_POLICY"),
f727d089
VK
102 _T("CMD_OPEN_SERVER_LOG"),
103 _T("CMD_CLOSE_SERVER_LOG"),
104 _T("CMD_QUERY_LOG"),
5039dede
AK
105 _T("CMD_AUTHENTICATE"),
106 _T("CMD_GET_PARAMETER"),
107 _T("CMD_GET_LIST"),
108 _T("CMD_ACTION"),
d83dc1f0
VK
109 _T("CMD_GET_CURRENT_USER_ATTR"),
110 _T("CMD_SET_CURRENT_USER_ATTR"),
5039dede 111 _T("CMD_GET_ALL_ALARMS"),
4644eee7 112 _T("CMD_GET_ALARM_COMMENTS"),
5039dede
AK
113 _T("CMD_ACK_ALARM"),
114 _T("CMD_ALARM_UPDATE"),
115 _T("CMD_ALARM_DATA"),
116 _T("CMD_DELETE_ALARM"),
1da08bc6 117 _T("CMD_ADD_CLUSTER_NODE"),
1f385e47 118 _T("CMD_GET_POLICY_INVENTORY"),
5039dede
AK
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"),
842378a4 125 _T("CMD_SETUP_AGENT_TUNNEL"),
e9bf9011 126 _T("CMD_EXECUTE_LIBRARY_SCRIPT"),
0cf6fcbd
VK
127 _T("CMD_GET_PREDICTION_ENGINES"),
128 _T("CMD_GET_PREDICTED_DATA"),
e5b8d60e 129 _T("CMD_STOP_SERVER_COMMAND"),
5039dede
AK
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"),
630e15d6 136 _T("CMD_FIND_NODE_CONNECTION"),
06a93345 137 _T("CMD_FIND_MAC_LOCATION"),
5039dede
AK
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"),
6d069676 170 _T("CMD_GET_NETWORK_PATH"),
5039dede
AK
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"),
f40831eb 178 _T("CMD_CANCEL_JOB"),
5039dede 179 _T("CMD_CHANGE_SUBSCRIPTION"),
c7aa788e 180 _T("CMD_SET_CONFIG_TO_DEFAULT"),
5039dede 181 _T("CMD_SYSLOG_RECORDS"),
ab621f39 182 _T("CMD_JOB_CHANGE_NOTIFICATION"),
fc61a868 183 _T("CMD_DEPLOY_AGENT_POLICY"),
f727d089 184 _T("CMD_LOG_DATA"),
5039dede 185 _T("CMD_GET_OBJECT_TOOL_DETAILS"),
f69c6203 186 _T("CMD_EXECUTE_SERVER_COMMAND"),
619e5c9b 187 _T("CMD_UPLOAD_FILE_TO_AGENT"),
5039dede
AK
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"),
2de8de66 200 _T("<unused>0x009F"),
5039dede
AK
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"),
a7ff20a5
VK
233 _T("CMD_EXPORT_CONFIGURATION"),
234 _T("CMD_IMPORT_CONFIGURATION"),
5039dede
AK
235 _T("CMD_GET_TRAP_CFG_RO"),
236 _T("CMD_SNMP_REQUEST"),
237 _T("CMD_GET_DCI_INFO"),
238 _T("CMD_GET_GRAPH_LIST"),
7a4c94ee 239 _T("CMD_SAVE_GRAPH"),
5039dede 240 _T("CMD_DELETE_GRAPH"),
74526d25 241 _T("CMD_GET_PERFTAB_DCI_LIST"),
5039dede
AK
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"),
00420032 252 _T("CMD_GET_PERSISTENT_STORAGE"),
253 _T("CMD_DELETE_PSTORAGE_VALUE"),
254 _T("CMD_UPDATE_PSTORAGE_VALUE"),
3c463101 255 _T("CMD_GET_AGENT_TUNNELS"),
3b89a4c1
VK
256 _T("CMD_BIND_AGENT_TUNNEL"),
257 _T("CMD_REQUEST_CERTIFICATE"),
258 _T("CMD_NEW_CERTIFICATE"),
5039dede 259 _T("CMD_CREATE_MAP"),
68f898c9
VK
260 _T("CMD_UPLOAD_FILE"),
261 _T("CMD_DELETE_FILE"),
3932fde6 262 _T("CMD_DELETE_REPORT_RESULTS"),
e12e1422 263 _T("CMD_RENDER_REPORT"),
8c5b6ed3
VK
264 _T("CMD_EXECUTE_REPORT"),
265 _T("CMD_GET_REPORT_RESULTS"),
5039dede
AK
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"),
df8a4ca2
VK
276 _T("CMD_FORWARD_EVENT"),
277 _T("CMD_GET_USM_CREDENTIALS"),
071fd171 278 _T("CMD_UPDATE_USM_CREDENTIALS"),
1a5e0c22
VK
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"),
810bd8c4 285 _T("CMD_LIST_SERVER_FILES"),
adac28be 286 _T("CMD_GET_TABLE"),
200d662d
VK
287 _T("CMD_QUERY_TABLE"),
288 _T("CMD_OPEN_CONSOLE"),
62768df3 289 _T("CMD_CLOSE_CONSOLE"),
7f632dfe 290 _T("CMD_GET_SELECTED_OBJECTS"),
509bb045
VK
291 _T("CMD_GET_VLANS"),
292 _T("CMD_HOLD_JOB"),
4c789f9e 293 _T("CMD_UNHOLD_JOB"),
6f16f12d
VK
294 _T("CMD_CHANGE_ZONE"),
295 _T("CMD_GET_AGENT_FILE"),
624f1165 296 _T("CMD_GET_FILE_DETAILS"),
8836184f 297 _T("CMD_IMAGE_LIBRARY_UPDATE"),
04f06779 298 _T("CMD_GET_NODE_COMPONENTS"),
4644eee7 299 _T("CMD_UPDATE_ALARM_COMMENT"),
b9a8e081 300 _T("CMD_GET_ALARM"),
92c51b1d 301 _T("CMD_GET_TABLE_LAST_VALUES"),
711e5e9a 302 _T("CMD_GET_TABLE_DCI_DATA"),
5f6bc78c 303 _T("CMD_GET_THRESHOLD_SUMMARY"),
534e1b83
VK
304 _T("CMD_RESOLVE_ALARM"),
305 _T("CMD_FIND_IP_LOCATION"),
306 _T("CMD_REPORT_DEVICE_STATUS"),
b1e9b6b3 307 _T("CMD_REPORT_DEVICE_INFO"),
0f506caa
VK
308 _T("CMD_GET_ALARM_EVENTS"),
309 _T("CMD_GET_ENUM_LIST"),
fdbee7f8
VK
310 _T("CMD_GET_TABLE_LIST"),
311 _T("CMD_GET_MAPPING_TABLE"),
312 _T("CMD_UPDATE_MAPPING_TABLE"),
313 _T("CMD_DELETE_MAPPING_TABLE"),
caa04e26 314 _T("CMD_LIST_MAPPING_TABLES"),
46ee6286 315 _T("CMD_GET_NODE_SOFTWARE"),
d5de1d1d 316 _T("CMD_GET_WINPERF_OBJECTS"),
b4c2a628
VK
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"),
f918b160 322 _T("CMD_QUERY_SUMMARY_TABLE"),
67ddc85e 323 _T("CMD_SHUTDOWN"),
ceb0fc8d 324 _T("CMD_SNMP_TRAP"),
9fa031cd 325 _T("CMD_GET_SUBNET_ADDRESS_MAP"),
326 _T("CMD_FILE_MONITORING"),
fce4295c 327 _T("CMD_CANCEL_FILE_MONITORING"),
9dd47420 328 _T("CMD_CHANGE_OBJECT_TOOL_STATUS"),
f82a8b5d 329 _T("CMD_SET_ALARM_STATUS_FLOW"),
4644eee7 330 _T("CMD_DELETE_ALARM_COMMENT"),
2ab9314f 331 _T("CMD_GET_EFFECTIVE_RIGHTS"),
6cedeb69 332 _T("CMD_GET_DCI_VALUES"),
1eb0b101 333 _T("CMD_GET_HELPDESK_URL"),
d9821bd7 334 _T("CMD_UNLINK_HELPDESK_ISSUE"),
7cf549ad 335 _T("CMD_GET_FOLDER_CONTENT"),
336 _T("CMD_FILEMGR_DELETE_FILE"),
337 _T("CMD_FILEMGR_RENAME_FILE"),
338 _T("CMD_FILEMGR_MOVE_FILE"),
c44cf458 339 _T("CMD_FILEMGR_UPLOAD"),
4899db4d 340 _T("CMD_GET_SWITCH_FDB"),
341 _T("CMD_COMMAND_OUTPUT"),
5944946e 342 _T("CMD_GET_LOC_HISTORY"),
529956a0 343 _T("CMD_TAKE_SCREENSHOT"),
344 _T("CMD_EXECUTE_SCRIPT"),
5de546a2 345 _T("CMD_EXECUTE_SCRIPT_UPDATE"),
5389f7b0 346 _T("CMD_FILEMGR_CREATE_FOLDER"),
32f372a5 347 _T("CMD_QUERY_ADHOC_SUMMARY_TABLE"),
ea3993c8 348 _T("CMD_GRAPH_UPDATE"),
1a5ddd2a 349 _T("CMD_SET_SERVER_CAPABILITIES"),
25a1e9d0 350 _T("CMD_FORCE_DCI_POLL"),
e9902466
VK
351 _T("CMD_GET_DCI_SCRIPT_LIST"),
352 _T("CMD_DATA_COLLECTION_CONFIG"),
c85c8ef2 353 _T("CMD_SET_SERVER_ID"),
2d8d8ea2 354 _T("CMD_GET_PUBLIC_CONFIG_VAR"),
355 _T("CMD_ENABLE_FILE_UPDATES"),
77a08c86 356 _T("CMD_DETACH_LDAP_USER"),
5f573844 357 _T("CMD_VALIDATE_PASSWORD"),
4b535d78 358 _T("CMD_COMPILE_SCRIPT"),
359 _T("CMD_CLEAN_AGENT_DCI_CONF"),
6b0abae2
Z
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"),
7e18667a
VK
365 _T("CMD_REMOVE_SCHEDULE"),
366 _T("CMD_ENTER_MAINT_MODE"),
5cf931e2 367 _T("CMD_LEAVE_MAINT_MODE"),
de12aebc 368 _T("CMD_JOIN_CLUSTER"),
badd6e08
VK
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"),
a881eafa
VK
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"),
1af3bfac 386 _T("CMD_BULK_ALARM_STATE_CHANGE"),
eae56922
VK
387 _T("CMD_GET_FOLDER_SIZE"),
388 _T("CMD_FIND_HOSTNAME_LOCATION"),
389 _T("CMD_RESET_TUNNEL"),
e3ff8ad1
VK
390 _T("CMD_CREATE_CHANNEL"),
391 _T("CMD_CHANNEL_DATA"),
5eabf181 392 _T("CMD_CLOSE_CHANNEL"),
c733fcc4 393 _T("CMD_CREATE_OBJECT_ACCESS_SNAPSHOT"),
eb17778f 394 _T("CMD_UNBIND_AGENT_TUNNEL"),
2649d20b 395 _T("CMD_RESTART"),
396 _T("CMD_REGISTER_LORAWAN_SENSOR"),
397 _T("CMD_UNREGISTER_LORAWAN_SENSOR"),
d447bf2f 398 _T("CMD_EXPAND_MACROS"),
399 _T("CMD_EXECUTE_ACTION_WITH_EXPANSION"),
400 _T("CMD_HOST_BY_IP"),
401 _T("CMD_CANCEL_FILE_DOWNLOAD")
5039dede
AK
402 };
403
d447bf2f 404 if ((code >= CMD_LOGIN) && (code <= CMD_CANCEL_FILE_DOWNLOAD))
da9ac8fc 405 {
b368969c 406 _tcscpy(pszBuffer, pszMsgNames[code - CMD_LOGIN]);
da9ac8fc 407 }
5039dede 408 else
da9ac8fc
VK
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 }
5039dede
AK
422 return pszBuffer;
423}
424
534e1b83 425/**
da9ac8fc
VK
426 * Register NXCP message name resolver
427 */
428void 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 */
439void LIBNETXMS_EXPORTABLE NXCPUnregisterMessageNameResolver(NXCPMessageNameResolver r)
440{
441 s_resolversLock.lock();
442 s_resolvers.remove((void *)r);
443 s_resolversLock.unlock();
444}
445
446/**
efe30b82
VK
447 * Init NXCP receiver buffer
448 */
449void LIBNETXMS_EXPORTABLE NXCPInitBuffer(NXCP_BUFFER *nxcpBuffer)
450{
451 nxcpBuffer->bufferSize = 0;
452 nxcpBuffer->bufferPos = 0;
453}
454
455/**
534e1b83
VK
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 */
e3ff8ad1 467int LIBNETXMS_EXPORTABLE RecvNXCPMessageEx(AbstractCommChannel *channel, NXCP_MESSAGE **msgBuffer,
b368969c 468 NXCP_BUFFER *nxcpBuffer, UINT32 *bufferSize,
fce4295c 469 NXCPEncryptionContext **ppCtx,
967893bb
VK
470 BYTE **decryptionBuffer, UINT32 dwTimeout,
471 UINT32 maxMsgSize)
5039dede 472{
967893bb 473 UINT32 dwMsgSize = 0, dwBytesRead = 0, dwBytesToCopy;
5039dede
AK
474 int iErr;
475 BOOL bSkipMsg = FALSE;
476
477 // Initialize buffer if requested
b9b2b87b 478 if (msgBuffer == NULL)
5039dede 479 {
b368969c
VK
480 nxcpBuffer->bufferSize = 0;
481 nxcpBuffer->bufferPos = 0;
5039dede
AK
482 return 0;
483 }
484
485 // Check if we have something in buffer
b368969c 486 if (nxcpBuffer->bufferSize > 0)
5039dede
AK
487 {
488 // Handle the case when entire message header have not been read into the buffer
b368969c 489 if (nxcpBuffer->bufferSize < NXCP_HEADER_SIZE)
5039dede
AK
490 {
491 // Most likely we are at the buffer end, so move content
492 // to the beginning
b368969c
VK
493 memmove(nxcpBuffer->buffer, &nxcpBuffer->buffer[nxcpBuffer->bufferPos], nxcpBuffer->bufferSize);
494 nxcpBuffer->bufferPos = 0;
5039dede 495
fce4295c 496 // Receive new portion of data from the network
5039dede 497 // and append it to existing data in buffer
e3ff8ad1
VK
498 iErr = channel->recv(&nxcpBuffer->buffer[nxcpBuffer->bufferSize],
499 NXCP_TEMP_BUF_SIZE - nxcpBuffer->bufferSize, dwTimeout);
5039dede
AK
500 if (iErr <= 0)
501 return (iErr == -2) ? 3 : iErr;
b368969c 502 nxcpBuffer->bufferSize += (UINT32)iErr;
5039dede
AK
503 }
504
fce4295c 505 // Get message size from message header and copy available
5039dede 506 // message bytes from buffer
b368969c 507 dwMsgSize = ntohl(((NXCP_MESSAGE *)(&nxcpBuffer->buffer[nxcpBuffer->bufferPos]))->size);
b9b2b87b 508 if (dwMsgSize > *bufferSize)
5039dede 509 {
b9b2b87b
VK
510 if ((*bufferSize >= maxMsgSize) || (dwMsgSize > maxMsgSize))
511 {
512 bSkipMsg = TRUE; // Message is too large, will skip it
b368969c 513 memcpy(*msgBuffer, &nxcpBuffer->buffer[nxcpBuffer->bufferPos], NXCP_HEADER_SIZE);
b9b2b87b
VK
514 }
515 else
516 {
517 // Increase buffer
518 *bufferSize = dwMsgSize;
b368969c 519 *msgBuffer = (NXCP_MESSAGE *)realloc(*msgBuffer, *bufferSize);
b9b2b87b
VK
520 if (decryptionBuffer != NULL)
521 *decryptionBuffer = (BYTE *)realloc(*decryptionBuffer, *bufferSize);
522 }
5039dede 523 }
78032263 524 dwBytesRead = std::min(dwMsgSize, nxcpBuffer->bufferSize);
5039dede 525 if (!bSkipMsg)
b368969c
VK
526 memcpy(*msgBuffer, &nxcpBuffer->buffer[nxcpBuffer->bufferPos], dwBytesRead);
527 nxcpBuffer->bufferSize -= dwBytesRead;
528 nxcpBuffer->bufferPos = (nxcpBuffer->bufferSize > 0) ? (nxcpBuffer->bufferPos + dwBytesRead) : 0;
5039dede
AK
529 if (dwBytesRead == dwMsgSize)
530 goto decrypt_message;
531 }
532
533 // Receive rest of message from the network
4a64261c 534 // Buffer is empty now
b368969c
VK
535 nxcpBuffer->bufferSize = 0;
536 nxcpBuffer->bufferPos = 0;
5039dede
AK
537 do
538 {
e3ff8ad1
VK
539 iErr = channel->recv(&nxcpBuffer->buffer[nxcpBuffer->bufferSize],
540 NXCP_TEMP_BUF_SIZE - nxcpBuffer->bufferSize, dwTimeout);
5039dede
AK
541 if (iErr <= 0)
542 return (iErr == -2) ? 3 : iErr;
543
4a64261c 544 if (dwBytesRead == 0) // New message?
5039dede 545 {
b368969c 546 if ((iErr + nxcpBuffer->bufferSize) < NXCP_HEADER_SIZE)
4a64261c
VK
547 {
548 // Header not received completely
b368969c 549 nxcpBuffer->bufferSize += iErr;
4a64261c
VK
550 continue;
551 }
b368969c
VK
552 iErr += nxcpBuffer->bufferSize;
553 nxcpBuffer->bufferSize = 0;
4a64261c 554
b368969c 555 dwMsgSize = ntohl(((NXCP_MESSAGE *)(nxcpBuffer->buffer))->size);
b9b2b87b 556 if (dwMsgSize > *bufferSize)
5039dede 557 {
b9b2b87b
VK
558 if ((*bufferSize >= maxMsgSize) || (dwMsgSize > maxMsgSize))
559 {
560 bSkipMsg = TRUE; // Message is too large, will skip it
b368969c 561 memcpy(*msgBuffer, nxcpBuffer->buffer, NXCP_HEADER_SIZE);
b9b2b87b
VK
562 }
563 else
564 {
565 // Increase buffer
566 *bufferSize = dwMsgSize;
b368969c 567 *msgBuffer = (NXCP_MESSAGE *)realloc(*msgBuffer, *bufferSize);
b9b2b87b
VK
568 if (decryptionBuffer != NULL)
569 *decryptionBuffer = (BYTE *)realloc(*decryptionBuffer, *bufferSize);
570 }
5039dede
AK
571 }
572 }
78032263 573 dwBytesToCopy = std::min((UINT32)iErr, dwMsgSize - dwBytesRead);
5039dede 574 if (!bSkipMsg)
b368969c 575 memcpy(((char *)(*msgBuffer)) + dwBytesRead, nxcpBuffer->buffer, dwBytesToCopy);
5039dede
AK
576 dwBytesRead += dwBytesToCopy;
577 }
6be0a20b 578 while((dwBytesRead < dwMsgSize) || (dwBytesRead < NXCP_HEADER_SIZE));
fce4295c 579
5039dede 580 // Check if we have something left in buffer
967893bb 581 if (dwBytesToCopy < (UINT32)iErr)
5039dede 582 {
b368969c
VK
583 nxcpBuffer->bufferPos = dwBytesToCopy;
584 nxcpBuffer->bufferSize = (UINT32)iErr - dwBytesToCopy;
5039dede
AK
585 }
586
587 // Check for encrypted message
588decrypt_message:
b368969c 589 if ((!bSkipMsg) && (ntohs((*msgBuffer)->code) == CMD_ENCRYPTED_MESSAGE))
5039dede
AK
590 {
591 if ((*ppCtx != NULL) && (*ppCtx != PROXY_ENCRYPTION_CTX))
592 {
b368969c 593 if ((*ppCtx)->decryptMessage((NXCP_ENCRYPTED_MESSAGE *)(*msgBuffer), *decryptionBuffer))
5039dede 594 {
b368969c 595 dwMsgSize = ntohl((*msgBuffer)->size);
5039dede
AK
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
e3ff8ad1
VK
612int 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
b368969c
VK
624int LIBNETXMS_EXPORTABLE RecvNXCPMessage(SOCKET hSocket, NXCP_MESSAGE *msgBuffer,
625 NXCP_BUFFER *nxcpBuffer, UINT32 bufferSize,
fce4295c 626 NXCPEncryptionContext **ppCtx,
967893bb 627 BYTE *decryptionBuffer, UINT32 dwTimeout)
b9b2b87b 628{
b368969c 629 NXCP_MESSAGE *mb = msgBuffer;
967893bb 630 UINT32 bs = bufferSize;
b9b2b87b
VK
631 BYTE *db = decryptionBuffer;
632 return RecvNXCPMessageEx(hSocket, (msgBuffer != NULL) ? &mb : NULL, nxcpBuffer, &bs, ppCtx,
633 (decryptionBuffer != NULL) ? &db : NULL, dwTimeout, bufferSize);
634}
635
e3ff8ad1
VK
636int 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
390271e0
VK
648/**
649 * Create NXCP message with raw data (MF_BINARY flag)
d3a20572
VK
650 * If buffer is NULL, new buffer is allocated with malloc()
651 * Buffer should be at least dataSize + NXCP_HEADER_SIZE + 8 bytes.
390271e0 652 */
d3a20572
VK
653NXCP_MESSAGE LIBNETXMS_EXPORTABLE *CreateRawNXCPMessage(UINT16 code, UINT32 id, UINT16 flags,
654 const void *data, size_t dataSize,
655 NXCP_MESSAGE *buffer, bool allowCompression)
5039dede 656{
d3a20572 657 NXCP_MESSAGE *msg = (buffer == NULL) ? (NXCP_MESSAGE *)malloc(dataSize + NXCP_HEADER_SIZE + 8) : buffer;
5039dede
AK
658
659 // Message should be aligned to 8 bytes boundary
d3a20572 660 size_t padding = (8 - ((dataSize + NXCP_HEADER_SIZE) % 8)) & 7;
5039dede 661
d3a20572
VK
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
5039dede 668
d3a20572
VK
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;
d55f77c8 680 stream.avail_in = (UINT32)dataSize;
d3a20572 681 stream.next_out = (BYTE *)msg->fields + 4;
d55f77c8 682 stream.avail_out = (UINT32)(dataSize + padding - 4);
d3a20572
VK
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;
5039dede
AK
713}
714
bd8cc790 715/**
eae56922 716 * Send file over NXCP
bd8cc790 717 */
eae56922
VK
718bool 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);
d447bf2f 724 bool result = SendFileOverNXCP(ch, id, pszFile, pCtx, offset, progressCallback, cbArg, mutex, compressionMethod, NULL);
eae56922
VK
725 ch->decRefCount();
726 return result;
727}
728
729/**
730 * Send file over NXCP
731 */
732bool LIBNETXMS_EXPORTABLE SendFileOverNXCP(AbstractCommChannel *channel, UINT32 id, const TCHAR *pszFile,
cc022855 733 NXCPEncryptionContext *pCtx, long offset,
7b8b337e 734 void (* progressCallback)(INT64, void *), void *cbArg,
d447bf2f 735 MUTEX mutex, NXCPStreamCompressionMethod compressionMethod,
736 VolatileCounter *cancelationFlag)
5039dede 737{
5039dede 738 int hFile, iBytes;
6173bea8 739 INT64 bytesTransferred = 0;
967893bb 740 UINT32 dwPadding;
eae56922 741 bool success = false;
b368969c 742 NXCP_MESSAGE *pMsg;
6be0a20b 743 NXCP_ENCRYPTED_MESSAGE *pEnMsg;
5039dede 744
d3a20572 745 StreamCompressor *compressor = (compressionMethod != NXCP_STREAM_COMPRESSION_NONE) ? StreamCompressor::create(compressionMethod, true, FILE_BUFFER_SIZE) : NULL;
503da871
VK
746 BYTE *compBuffer = (compressor != NULL) ? (BYTE *)malloc(FILE_BUFFER_SIZE) : NULL;
747
5039dede
AK
748 hFile = _topen(pszFile, O_RDONLY | O_BINARY);
749 if (hFile != -1)
c3a8e638 750 {
db05c2af
VK
751 NX_STAT_STRUCT st;
752 NX_FSTAT(hFile, &st);
753 long fileSize = (long)st.st_size;
cc022855 754 if (labs(offset) > fileSize)
755 offset = 0;
756 long bytesToRead = (offset < 0) ? (0 - offset) : (fileSize - offset);
db05c2af 757
cc022855 758 if (lseek(hFile, offset, (offset < 0) ? SEEK_END : SEEK_SET) != -1)
901a5a9b 759 {
901a5a9b 760 // Allocate message and prepare it's header
503da871 761 pMsg = (NXCP_MESSAGE *)malloc(NXCP_HEADER_SIZE + 8 + ((compressor != NULL) ? compressor->compressBufferSize(FILE_BUFFER_SIZE) + 4 : FILE_BUFFER_SIZE));
b368969c
VK
762 pMsg->id = htonl(id);
763 pMsg->code = htons(CMD_FILE_DATA);
3a1356ab 764 pMsg->flags = htons(MF_BINARY | MF_STREAM | ((compressionMethod != NXCP_STREAM_COMPRESSION_NONE) ? MF_COMPRESSED : 0));
901a5a9b 765
90ed558d 766 while(true)
901a5a9b 767 {
d447bf2f 768 if(cancelationFlag != NULL && (*cancelationFlag) > 0)
769 break;
770
503da871
VK
771 if (compressor != NULL)
772 {
78032263 773 iBytes = _read(hFile, compBuffer, MIN(FILE_BUFFER_SIZE, bytesToRead));
503da871
VK
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 {
78032263 787 iBytes = _read(hFile, pMsg->fields, MIN(FILE_BUFFER_SIZE, bytesToRead));
503da871
VK
788 if (iBytes < 0)
789 break;
790 bytesToRead -= iBytes;
791 }
5039dede 792
901a5a9b 793 // Message should be aligned to 8 bytes boundary
6be0a20b 794 dwPadding = (8 - (((UINT32)iBytes + NXCP_HEADER_SIZE) % 8)) & 7;
b368969c
VK
795 pMsg->size = htonl((UINT32)iBytes + NXCP_HEADER_SIZE + dwPadding);
796 pMsg->numFields = htonl((UINT32)iBytes); // numFields contains actual data size for binary message
db05c2af 797 if (bytesToRead <= 0)
b368969c 798 pMsg->flags |= htons(MF_END_OF_FILE);
901a5a9b
VK
799
800 if (pCtx != NULL)
5039dede 801 {
b368969c 802 pEnMsg = pCtx->encryptMessage(pMsg);
901a5a9b 803 if (pEnMsg != NULL)
c3a8e638 804 {
eae56922 805 channel->send(pEnMsg, ntohl(pEnMsg->size), mutex);
901a5a9b 806 free(pEnMsg);
c3a8e638 807 }
901a5a9b
VK
808 }
809 else
810 {
eae56922 811 if (channel->send(pMsg, (UINT32)iBytes + NXCP_HEADER_SIZE + dwPadding, mutex) <= 0)
901a5a9b
VK
812 break; // Send error
813 }
6173bea8
VK
814 if (progressCallback != NULL)
815 {
816 bytesTransferred += iBytes;
817 progressCallback(bytesTransferred, cbArg);
818 }
819
db05c2af 820 if (bytesToRead <= 0)
901a5a9b
VK
821 {
822 // End of file
eae56922 823 success = true;
901a5a9b
VK
824 break;
825 }
826 }
827
828 free(pMsg);
829 }
c90ea787 830 _close(hFile);
901a5a9b 831 }
5039dede 832
d3a20572 833 free(compBuffer);
503da871
VK
834 delete compressor;
835
5039dede 836 // If file upload failed, send CMD_ABORT_FILE_TRANSFER
eae56922 837 if (!success)
5039dede 838 {
b368969c 839 NXCP_MESSAGE msg;
5039dede 840
b368969c
VK
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);
5039dede
AK
846 if (pCtx != NULL)
847 {
b368969c 848 pEnMsg = pCtx->encryptMessage(&msg);
5039dede
AK
849 if (pEnMsg != NULL)
850 {
eae56922 851 channel->send(pEnMsg, ntohl(pEnMsg->size), mutex);
5039dede
AK
852 free(pEnMsg);
853 }
854 }
855 else
856 {
eae56922 857 channel->send(&msg, NXCP_HEADER_SIZE, mutex);
5039dede
AK
858 }
859 }
860
eae56922 861 return success;
5039dede
AK
862}
863
bd8cc790
VK
864/**
865 * Get version of NXCP used by peer
866 */
e3ff8ad1 867bool LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(AbstractCommChannel *channel, int *pnVersion, MUTEX mutex)
5039dede 868{
b368969c 869 NXCP_MESSAGE msg;
98abc9f1 870 NXCPEncryptionContext *pDummyCtx = NULL;
b368969c 871 NXCP_BUFFER *pBuffer;
eae56922 872 bool success = false;
5039dede
AK
873 int nSize;
874
b368969c
VK
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);
e3ff8ad1 880 if (channel->send(&msg, NXCP_HEADER_SIZE, mutex) == NXCP_HEADER_SIZE)
5039dede 881 {
b368969c 882 pBuffer = (NXCP_BUFFER *)malloc(sizeof(NXCP_BUFFER));
efe30b82 883 NXCPInitBuffer(pBuffer);
e3ff8ad1 884 nSize = RecvNXCPMessage(channel, &msg, pBuffer, NXCP_HEADER_SIZE, &pDummyCtx, NULL, 30000);
6be0a20b 885 if ((nSize == NXCP_HEADER_SIZE) &&
b368969c
VK
886 (ntohs(msg.code) == CMD_NXCP_CAPS) &&
887 (ntohs(msg.flags) & MF_CONTROL))
5039dede 888 {
eae56922 889 success = true;
b368969c 890 *pnVersion = ntohl(msg.numFields) >> 24;
5039dede 891 }
6be0a20b 892 else if ((nSize == 1) || (nSize == 3) || (nSize >= NXCP_HEADER_SIZE))
5039dede 893 {
fce4295c 894 // We don't receive any answer or receive invalid answer -
5039dede
AK
895 // assume that peer doesn't understand CMD_GET_NXCP_CAPS message
896 // and set version number to 1
eae56922 897 success = true;
5039dede
AK
898 *pnVersion = 1;
899 }
900 free(pBuffer);
901 }
eae56922 902 return success;
5039dede 903}
e3ff8ad1
VK
904
905/**
906 * Get version of NXCP used by peer
907 */
908bool 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}