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