53cf48b6fd68e69ebd4ebb2cbbb6992d023eeb31
[public/netxms.git] / src / libnetxms / nxcp.cpp
1 /* $Id: nxcp.cpp,v 1.20 2008-01-17 09:07:12 victor Exp $ */
2 /*
3 ** NetXMS - Network Management System
4 ** NetXMS Foundation Library
5 ** Copyright (C) 2003, 2004, 2005, 2006 Victor Kirhenshtein
6 **
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 **
21 ** File: nxcp.cpp
22 **
23 **/
24
25 #include "libnetxms.h"
26
27
28 //
29 // Constants
30 //
31
32 #define FILE_BUFFER_SIZE 32768
33
34
35 //
36 // Get symbolic name for message code
37 //
38
39 TCHAR LIBNETXMS_EXPORTABLE *NXCPMessageCodeName(WORD wCode, TCHAR *pszBuffer)
40 {
41 static const TCHAR *pszMsgNames[] =
42 {
43 _T("CMD_LOGIN"),
44 _T("CMD_LOGIN_RESP"),
45 _T("CMD_KEEPALIVE"),
46 _T("CMD_EVENT"),
47 _T("CMD_GET_OBJECTS"),
48 _T("CMD_OBJECT"),
49 _T("CMD_DELETE_OBJECT"),
50 _T("CMD_MODIFY_OBJECT"),
51 _T("CMD_OBJECT_LIST_END"),
52 _T("CMD_OBJECT_UPDATE"),
53 _T("CMD_GET_EVENTS"),
54 _T("CMD_EVENT_LIST_END"),
55 _T("CMD_GET_CONFIG_VARLIST"),
56 _T("CMD_SET_CONFIG_VARIABLE"),
57 _T("CMD_GET_OBJECT_TOOLS"),
58 _T("CMD_EXECUTE_ACTION"),
59 _T("CMD_DELETE_CONFIG_VARIABLE"),
60 _T("CMD_NOTIFY"),
61 _T("CMD_TRAP"),
62 _T("CMD_OPEN_EPP"),
63 _T("CMD_CLOSE_EPP"),
64 _T("CMD_SAVE_EPP"),
65 _T("CMD_EPP_RECORD"),
66 _T("CMD_LOCK_EVENT_DB"),
67 _T("CMD_UNLOCK_EVENT_DB"),
68 _T("CMD_SET_EVENT_INFO"),
69 _T("CMD_EVENT_DB_RECORD"),
70 _T("CMD_LOAD_EVENT_DB"),
71 _T("CMD_REQUEST_COMPLETED"),
72 _T("CMD_LOAD_USER_DB"),
73 _T("CMD_USER_DATA"),
74 _T("CMD_GROUP_DATA"),
75 _T("CMD_USER_DB_EOF"),
76 _T("CMD_UPDATE_USER"),
77 _T("CMD_DELETE_USER"),
78 _T("CMD_CREATE_USER"),
79 _T("CMD_LOCK_USER_DB"),
80 _T("CMD_UNLOCK_USER_DB"),
81 _T("CMD_USER_DB_UPDATE"),
82 _T("CMD_SET_PASSWORD"),
83 _T("CMD_GET_NODE_DCI_LIST"),
84 _T("CMD_NODE_DCI"),
85 _T("CMD_NODE_DCI_LIST_END"),
86 _T("CMD_DELETE_NODE_DCI"),
87 _T("CMD_MODIFY_NODE_DCI"),
88 _T("CMD_UNLOCK_NODE_DCI_LIST"),
89 _T("CMD_SET_OBJECT_MGMT_STATUS"),
90 _T("CMD_CREATE_NEW_DCI"),
91 _T("CMD_GET_DCI_DATA"),
92 _T("CMD_DCI_DATA"),
93 _T("CMD_GET_MIB_TIMESTAMP"),
94 _T("CMD_GET_MIB"),
95 _T("CMD_REQUEST_NEW_LPP_ID"),
96 _T("CMD_OPEN_LPP"),
97 _T("CMD_CREATE_OBJECT"),
98 _T("CMD_GET_EVENT_NAMES"),
99 _T("CMD_EVENT_NAME_LIST"),
100 _T("CMD_BIND_OBJECT"),
101 _T("CMD_UNBIND_OBJECT"),
102 _T("CMD_GET_IMAGE_LIST"),
103 _T("CMD_LOAD_IMAGE_FILE"),
104 _T("CMD_IMAGE_LIST"),
105 _T("CMD_IMAGE_FILE"),
106 _T("CMD_AUTHENTICATE"),
107 _T("CMD_GET_PARAMETER"),
108 _T("CMD_GET_LIST"),
109 _T("CMD_ACTION"),
110 _T("CMD_GET_DEFAULT_IMAGE_LIST"),
111 _T("CMD_DEFAULT_IMAGE_LIST"),
112 _T("CMD_GET_ALL_ALARMS"),
113 _T("CMD_GET_ALARM"),
114 _T("CMD_ACK_ALARM"),
115 _T("CMD_ALARM_UPDATE"),
116 _T("CMD_ALARM_DATA"),
117 _T("CMD_DELETE_ALARM"),
118 _T("CMD_LOCK_ACTION_DB"),
119 _T("CMD_UNLOCK_ACTION_DB"),
120 _T("CMD_LOAD_ACTIONS"),
121 _T("CMD_ACTION_DB_UPDATE"),
122 _T("CMD_MODIFY_ACTION"),
123 _T("CMD_CREATE_ACTION"),
124 _T("CMD_DELETE_ACTION"),
125 _T("CMD_ACTION_DATA"),
126 _T("CMD_GET_CONTAINER_CAT_LIST"),
127 _T("CMD_CONTAINER_CAT_DATA"),
128 _T("CMD_DELETE_CONTAINER_CAT"),
129 _T("CMD_CREATE_CONTAINER_CAT"),
130 _T("CMD_MODIFY_CONTAINER_CAT"),
131 _T("CMD_POLL_NODE"),
132 _T("CMD_POLLING_INFO"),
133 _T("CMD_COPY_DCI"),
134 _T("CMD_WAKEUP_NODE"),
135 _T("CMD_DELETE_EVENT_TEMPLATE"),
136 _T("CMD_GENERATE_EVENT_CODE"),
137 _T("CMD_LOCK_TRAP_CFG"),
138 _T("CMD_UNLOCK_TRAP_CFG"),
139 _T("CMD_CREATE_TRAP"),
140 _T("CMD_MODIFY_TRAP"),
141 _T("CMD_DELETE_TRAP"),
142 _T("CMD_LOAD_TRAP_CFG"),
143 _T("CMD_TRAP_CFG_RECORD"),
144 _T("CMD_QUERY_PARAMETER"),
145 _T("CMD_GET_SERVER_INFO"),
146 _T("CMD_SET_DCI_STATUS"),
147 _T("CMD_FILE_DATA"),
148 _T("CMD_TRANSFER_FILE"),
149 _T("CMD_UPGRADE_AGENT"),
150 _T("CMD_GET_PACKAGE_LIST"),
151 _T("CMD_PACKAGE_INFO"),
152 _T("CMD_REMOVE_PACKAGE"),
153 _T("CMD_INSTALL_PACKAGE"),
154 _T("CMD_LOCK_PACKAGE_DB"),
155 _T("CMD_UNLOCK_PACKAGE_DB"),
156 _T("CMD_ABORT_FILE_TRANSFER"),
157 _T("CMD_CHECK_NETWORK_SERVICE"),
158 _T("CMD_GET_AGENT_CONFIG"),
159 _T("CMD_UPDATE_AGENT_CONFIG"),
160 _T("CMD_GET_PARAMETER_LIST"),
161 _T("CMD_DEPLOY_PACKAGE"),
162 _T("CMD_INSTALLER_INFO"),
163 _T("CMD_GET_LAST_VALUES"),
164 _T("CMD_APPLY_TEMPLATE"),
165 _T("CMD_SET_USER_VARIABLE"),
166 _T("CMD_GET_USER_VARIABLE"),
167 _T("CMD_ENUM_USER_VARIABLES"),
168 _T("CMD_DELETE_USER_VARIABLE"),
169 _T("CMD_ADM_MESSAGE"),
170 _T("CMD_ADM_REQUEST"),
171 _T("CMD_CHANGE_IP_ADDR"),
172 _T("CMD_REQUEST_SESSION_KEY"),
173 _T("CMD_ENCRYPTED_MESSAGE"),
174 _T("CMD_SESSION_KEY"),
175 _T("CMD_REQUEST_ENCRYPTION"),
176 _T("CMD_GET_ROUTING_TABLE"),
177 _T("CMD_EXEC_TABLE_TOOL"),
178 _T("CMD_TABLE_DATA"),
179 _T("CMD_APPLY_LOG_POLICY"),
180 _T("CMD_CHANGE_SUBSCRIPTION"),
181 _T("CMD_GET_SYSLOG"),
182 _T("CMD_SYSLOG_RECORDS"),
183 _T("CMD_GET_LPP_LIST"),
184 _T("CMD_OPEN_LOG_POLICY"),
185 _T("CMD_CLOSE_LOG_POLICY"),
186 _T("CMD_GET_OBJECT_TOOL_DETAILS"),
187 _T("CMD_LOCK_OBJECT_TOOLS"),
188 _T("CMD_UNLOCK_OBJECT_TOOLS"),
189 _T("CMD_UPDATE_OBJECT_TOOL"),
190 _T("CMD_DELETE_OBJECT_TOOL"),
191 _T("CMD_SETUP_PROXY_CONNECTION"),
192 _T("CMD_GENERATE_OBJECT_TOOL_ID"),
193 _T("CMD_GET_SERVER_STATS"),
194 _T("CMD_GET_SCRIPT_LIST"),
195 _T("CMD_GET_SCRIPT"),
196 _T("CMD_UPDATE_SCRIPT"),
197 _T("CMD_DELETE_SCRIPT"),
198 _T("CMD_RENAME_SCRIPT"),
199 _T("CMD_GET_SESSION_LIST"),
200 _T("CMD_KILL_SESSION"),
201 _T("CMD_GET_TRAP_LOG"),
202 _T("CMD_TRAP_LOG_RECORDS"),
203 _T("CMD_START_SNMP_WALK"),
204 _T("CMD_SNMP_WALK_DATA"),
205 _T("CMD_GET_MAP_LIST"),
206 _T("CMD_LOAD_MAP"),
207 _T("CMD_SAVE_MAP"),
208 _T("CMD_DELETE_MAP"),
209 _T("CMD_RESOLVE_MAP_NAME"),
210 _T("CMD_SUBMAP_DATA"),
211 _T("CMD_UPLOAD_SUBMAP_BK_IMAGE"),
212 _T("CMD_GET_SUBMAP_BK_IMAGE"),
213 _T("CMD_GET_MODULE_LIST"),
214 _T("CMD_UPDATE_MODULE_INFO"),
215 _T("CMD_COPY_USER_VARIABLE"),
216 _T("CMD_RESOLVE_DCI_NAMES"),
217 _T("CMD_GET_MY_CONFIG"),
218 _T("CMD_GET_AGENT_CFG_LIST"),
219 _T("CMD_OPEN_AGENT_CONFIG"),
220 _T("CMD_SAVE_AGENT_CONFIG"),
221 _T("CMD_DELETE_AGENT_CONFIG"),
222 _T("CMD_SWAP_AGENT_CONFIGS"),
223 _T("CMD_TERMINATE_ALARM"),
224 _T("CMD_GET_NXCP_CAPS"),
225 _T("CMD_NXCP_CAPS"),
226 _T("CMD_GET_OBJECT_COMMENTS"),
227 _T("CMD_UPDATE_OBJECT_COMMENTS"),
228 _T("CMD_ENABLE_AGENT_TRAPS"),
229 _T("CMD_PUSH_DCI_DATA"),
230 _T("CMD_GET_ADDR_LIST"),
231 _T("CMD_SET_ADDR_LIST"),
232 _T("CMD_RESET_COMPONENT"),
233 _T("CMD_GET_DCI_EVENTS_LIST"),
234 _T("CMD_CREATE_MGMT_PACK"),
235 _T("CMD_INSTALL_MGMT_PACK"),
236 _T("CMD_GET_TRAP_CFG_RO"),
237 _T("CMD_SNMP_REQUEST"),
238 _T("CMD_GET_DCI_INFO"),
239 _T("CMD_GET_GRAPH_LIST"),
240 _T("CMD_DEFINE_GRAPH"),
241 _T("CMD_DELETE_GRAPH"),
242 _T("CMD_GET_SYSTEM_DCI_LIST"),
243 _T("CMD_ADD_CA_CERTIFICATE"),
244 _T("CMD_DELETE_CERTIFICATE"),
245 _T("CMD_GET_CERT_LIST"),
246 _T("CMD_UPDATE_CERT_COMMENTS"),
247 _T("CMD_QUERY_L2_TOPOLOGY"),
248 _T("CMD_AUDIT_RECORD"),
249 _T("CMD_GET_AUDIT_LOG"),
250 _T("CMD_SEND_SMS")
251 };
252
253 if ((wCode >= CMD_LOGIN) && (wCode <= CMD_SEND_SMS))
254 _tcscpy(pszBuffer, pszMsgNames[wCode - CMD_LOGIN]);
255 else
256 _stprintf(pszBuffer, _T("CMD_UNKNOWN(%d)"), wCode);
257 return pszBuffer;
258 }
259
260
261 //
262 // Receive raw CSCP message from network
263 // If pMsg is NULL, temporary buffer will be re-initialized
264 // Returns message size on success or:
265 // 0 if connection is closed
266 // <0 on socket errors
267 // 1 if message is too large to fit in buffer (normal messages is at least 16
268 // bytes long, so we never get length of 1 for valid message)
269 // In this case, only message header will be copied into buffer
270 // 2 Message decryption failed
271 // 3 Receive timeout
272 //
273
274 int LIBNETXMS_EXPORTABLE RecvNXCPMessage(SOCKET hSocket, CSCP_MESSAGE *pMsg,
275 CSCP_BUFFER *pBuffer, DWORD dwMaxMsgSize,
276 CSCP_ENCRYPTION_CONTEXT **ppCtx,
277 BYTE *pDecryptionBuffer, DWORD dwTimeout)
278 {
279 DWORD dwMsgSize = 0, dwBytesRead = 0, dwBytesToCopy;
280 int iErr;
281 BOOL bSkipMsg = FALSE;
282
283 // Initialize buffer if requested
284 if (pMsg == NULL)
285 {
286 pBuffer->dwBufSize = 0;
287 pBuffer->dwBufPos = 0;
288 return 0;
289 }
290
291 // Check if we have something in buffer
292 if (pBuffer->dwBufSize > 0)
293 {
294 // Handle the case when entire message header have not been read into the buffer
295 if (pBuffer->dwBufSize < CSCP_HEADER_SIZE)
296 {
297 // Most likely we are at the buffer end, so move content
298 // to the beginning
299 memmove(pBuffer->szBuffer, &pBuffer->szBuffer[pBuffer->dwBufPos], pBuffer->dwBufSize);
300 pBuffer->dwBufPos = 0;
301
302 // Receive new portion of data from the network
303 // and append it to existing data in buffer
304 iErr = RecvEx(hSocket, &pBuffer->szBuffer[pBuffer->dwBufSize],
305 CSCP_TEMP_BUF_SIZE - pBuffer->dwBufSize, 0, dwTimeout);
306 if (iErr <= 0)
307 return (iErr == -2) ? 3 : iErr;
308 pBuffer->dwBufSize += (DWORD)iErr;
309 }
310
311 // Get message size from message header and copy available
312 // message bytes from buffer
313 dwMsgSize = ntohl(((CSCP_MESSAGE *)(&pBuffer->szBuffer[pBuffer->dwBufPos]))->dwSize);
314 if (dwMsgSize > dwMaxMsgSize)
315 {
316 bSkipMsg = TRUE; // Message is too large, will skip it
317 memcpy(pMsg, &pBuffer->szBuffer[pBuffer->dwBufPos], CSCP_HEADER_SIZE);
318 }
319 dwBytesRead = min(dwMsgSize, pBuffer->dwBufSize);
320 if (!bSkipMsg)
321 memcpy(pMsg, &pBuffer->szBuffer[pBuffer->dwBufPos], dwBytesRead);
322 pBuffer->dwBufSize -= dwBytesRead;
323 pBuffer->dwBufPos = (pBuffer->dwBufSize > 0) ? (pBuffer->dwBufPos + dwBytesRead) : 0;
324 if (dwBytesRead == dwMsgSize)
325 goto decrypt_message;
326 }
327
328 // Receive rest of message from the network
329 do
330 {
331 iErr = RecvEx(hSocket, pBuffer->szBuffer, CSCP_TEMP_BUF_SIZE, 0, dwTimeout);
332 if (iErr <= 0)
333 return (iErr == -2) ? 3 : iErr;
334
335 if (dwBytesRead == 0 &&
336 iErr >= (sizeof(((CSCP_MESSAGE *)(pBuffer->szBuffer))->dwSize))) // New message?
337 {
338 dwMsgSize = ntohl(((CSCP_MESSAGE *)(pBuffer->szBuffer))->dwSize);
339 if (dwMsgSize > dwMaxMsgSize)
340 {
341 bSkipMsg = TRUE; // Message is too large, just skip it
342 memcpy(pMsg, pBuffer->szBuffer, CSCP_HEADER_SIZE);
343 }
344 }
345 dwBytesToCopy = min((DWORD)iErr, dwMsgSize - dwBytesRead);
346 if (!bSkipMsg)
347 memcpy(((char *)pMsg) + dwBytesRead, pBuffer->szBuffer, dwBytesToCopy);
348 dwBytesRead += dwBytesToCopy;
349 }
350 while(dwBytesRead < dwMsgSize);
351
352 // Check if we have something left in buffer
353 if (dwBytesToCopy < (DWORD)iErr)
354 {
355 pBuffer->dwBufPos = dwBytesToCopy;
356 pBuffer->dwBufSize = (DWORD)iErr - dwBytesToCopy;
357 }
358
359 // Check for encrypted message
360 decrypt_message:
361 if ((!bSkipMsg) && (ntohs(pMsg->wCode) == CMD_ENCRYPTED_MESSAGE))
362 {
363 if ((*ppCtx != NULL) && (*ppCtx != PROXY_ENCRYPTION_CTX))
364 {
365 if (CSCPDecryptMessage(*ppCtx, (CSCP_ENCRYPTED_MESSAGE *)pMsg, pDecryptionBuffer))
366 {
367 dwMsgSize = ntohl(pMsg->dwSize);
368 }
369 else
370 {
371 dwMsgSize = 2; // Decryption failed
372 }
373 }
374 else
375 {
376 if (*ppCtx != PROXY_ENCRYPTION_CTX)
377 dwMsgSize = 2;
378 }
379 }
380
381 return bSkipMsg ? 1 : (int)dwMsgSize;
382 }
383
384
385 //
386 // Create CSCP message with raw data (MF_BINARY flag)
387 // If pBuffer is NULL, new buffer is allocated with malloc()
388 // Buffer should be of dwDataSize + CSCP_HEADER_SIZE + 8 bytes.
389 //
390
391 CSCP_MESSAGE LIBNETXMS_EXPORTABLE *CreateRawNXCPMessage(WORD wCode, DWORD dwId, WORD wFlags,
392 DWORD dwDataSize, void *pData,
393 CSCP_MESSAGE *pBuffer)
394 {
395 CSCP_MESSAGE *pMsg;
396 DWORD dwPadding;
397
398 if (pBuffer == NULL)
399 pMsg = (CSCP_MESSAGE *)malloc(dwDataSize + CSCP_HEADER_SIZE + 8);
400 else
401 pMsg = pBuffer;
402
403 // Message should be aligned to 8 bytes boundary
404 dwPadding = (8 - ((dwDataSize + CSCP_HEADER_SIZE) % 8)) & 7;
405
406 pMsg->wCode = htons(wCode);
407 pMsg->wFlags = htons(MF_BINARY | wFlags);
408 pMsg->dwId = htonl(dwId);
409 pMsg->dwSize = htonl(dwDataSize + CSCP_HEADER_SIZE + dwPadding);
410 pMsg->dwNumVars = htonl(dwDataSize); // dwNumVars contains actual data size for binary message
411 memcpy(pMsg->df, pData, dwDataSize);
412
413 return pMsg;
414 }
415
416
417 //
418 // Send file over CSCP
419 //
420
421 BOOL LIBNETXMS_EXPORTABLE SendFileOverNXCP(SOCKET hSocket, DWORD dwId, const TCHAR *pszFile,
422 CSCP_ENCRYPTION_CONTEXT *pCtx)
423 {
424 #ifndef UNDER_CE
425 int hFile, iBytes;
426 #else
427 FILE *hFile;
428 int iBytes;
429 #endif
430 DWORD dwPadding;
431 BOOL bResult = FALSE;
432 CSCP_MESSAGE *pMsg;
433 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
434
435 #ifndef UNDER_CE
436 hFile = _topen(pszFile, O_RDONLY | O_BINARY);
437 if (hFile != -1)
438 #else
439 hFile = _tfopen(pszFile, _T("rb"));
440 if (hFile != NULL)
441 #endif
442 {
443 // Allocate message and prepare it's header
444 pMsg = (CSCP_MESSAGE *)malloc(FILE_BUFFER_SIZE + CSCP_HEADER_SIZE + 8);
445 pMsg->dwId = htonl(dwId);
446 pMsg->wCode = htons(CMD_FILE_DATA);
447 pMsg->wFlags = htons(MF_BINARY);
448
449 while(1)
450 {
451 #ifndef UNDER_CE
452 iBytes = read(hFile, pMsg->df, FILE_BUFFER_SIZE);
453 if (iBytes < 0)
454 break;
455 #else
456 iBytes = fread(pMsg->df, 1, FILE_BUFFER_SIZE, hFile);
457 if (ferror(hFile))
458 break;
459 #endif
460
461 // Message should be aligned to 8 bytes boundary
462 dwPadding = (8 - (((DWORD)iBytes + CSCP_HEADER_SIZE) % 8)) & 7;
463 pMsg->dwSize = htonl((DWORD)iBytes + CSCP_HEADER_SIZE + dwPadding);
464 pMsg->dwNumVars = htonl((DWORD)iBytes); // dwNumVars contains actual data size for binary message
465 if (iBytes < FILE_BUFFER_SIZE)
466 pMsg->wFlags |= htons(MF_END_OF_FILE);
467
468 if (pCtx != NULL)
469 {
470 pEnMsg = CSCPEncryptMessage(pCtx, pMsg);
471 if (pEnMsg != NULL)
472 {
473 SendEx(hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0);
474 free(pEnMsg);
475 }
476 }
477 else
478 {
479 SendEx(hSocket, (char *)pMsg, (DWORD)iBytes + CSCP_HEADER_SIZE + dwPadding, 0);
480 }
481
482 if (iBytes < FILE_BUFFER_SIZE)
483 {
484 // End of file
485 bResult = TRUE;
486 break;
487 }
488 }
489
490 free(pMsg);
491 #ifndef UNDER_CE
492 close(hFile);
493 #else
494 fclose(hFile);
495 #endif
496 }
497
498 // If file upload failed, send CMD_ABORT_FILE_TRANSFER
499 if (!bResult)
500 {
501 CSCP_MESSAGE msg;
502
503 msg.dwId = htonl(dwId);
504 msg.wCode = htons(CMD_ABORT_FILE_TRANSFER);
505 msg.wFlags = htons(MF_BINARY);
506 msg.dwNumVars = 0;
507 msg.dwSize = htonl(CSCP_HEADER_SIZE);
508 if (pCtx != NULL)
509 {
510 pEnMsg = CSCPEncryptMessage(pCtx, &msg);
511 if (pEnMsg != NULL)
512 {
513 SendEx(hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0);
514 free(pEnMsg);
515 }
516 }
517 else
518 {
519 SendEx(hSocket, (char *)&msg, CSCP_HEADER_SIZE, 0);
520 }
521 }
522
523 return bResult;
524 }
525
526
527 //
528 // Get version of NXCP used by peer
529 //
530
531 BOOL LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(SOCKET hSocket, int *pnVersion)
532 {
533 CSCP_MESSAGE msg;
534 CSCP_ENCRYPTION_CONTEXT *pDummyCtx = NULL;
535 CSCP_BUFFER *pBuffer;
536 BOOL bRet = FALSE;
537 int nSize;
538
539 msg.dwId = 0;
540 msg.dwNumVars = 0;
541 msg.dwSize = htonl(CSCP_HEADER_SIZE);
542 msg.wCode = htons(CMD_GET_NXCP_CAPS);
543 msg.wFlags = htons(MF_CONTROL);
544 if (SendEx(hSocket, &msg, CSCP_HEADER_SIZE, 0) == CSCP_HEADER_SIZE)
545 {
546 pBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
547 RecvNXCPMessage(0, NULL, pBuffer, 0, NULL, NULL, 0);
548 nSize = RecvNXCPMessage(hSocket, &msg, pBuffer, CSCP_HEADER_SIZE, &pDummyCtx, NULL, 30000);
549 if ((nSize == CSCP_HEADER_SIZE) &&
550 (ntohs(msg.wCode) == CMD_NXCP_CAPS) &&
551 (ntohs(msg.wFlags) & MF_CONTROL))
552 {
553 bRet = TRUE;
554 *pnVersion = ntohl(msg.dwNumVars) >> 24;
555 }
556 else if ((nSize == 1) || (nSize == 3) || (nSize >= CSCP_HEADER_SIZE))
557 {
558 // We don't receive any answer or receive invalid answer -
559 // assume that peer doesn't understand CMD_GET_NXCP_CAPS message
560 // and set version number to 1
561 bRet = TRUE;
562 *pnVersion = 1;
563 }
564 free(pBuffer);
565 }
566 return bRet;
567 }