libnxmb removed from server build
[public/netxms.git] / src / server / libnxsrv / agent.cpp
CommitLineData
cc022855 1/*
5039dede
AK
2** NetXMS - Network Management System
3** Server Library
2ffad7c2 4** Copyright (C) 2003-2015 Victor Kirhenshtein
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
0702ed69
VK
7** it under the terms of the GNU Lesser General Public License as published by
8** 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**
0702ed69 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: agent.cpp
21**
22**/
23
24#include "libnxsrv.h"
25#include <stdarg.h>
26
f00612ba
VK
27#ifdef _WIN32
28#define open _open
29#define close _close
30#define write _write
8c1befb6 31#else
ff198273 32#define _tell(f) lseek(f,0,SEEK_CUR)
f00612ba
VK
33#endif
34
a3050773
VK
35/**
36 * Constants
37 */
8f4f648d 38#define MAX_MSG_SIZE 8388608
5039dede 39
a3050773
VK
40/**
41 * Static data
42 */
5039dede
AK
43#ifdef _WITH_ENCRYPTION
44static int m_iDefaultEncryptionPolicy = ENCRYPTION_ALLOWED;
45#else
46static int m_iDefaultEncryptionPolicy = ENCRYPTION_DISABLED;
47#endif
48
a3050773
VK
49/**
50 * Set default encryption policy for agent communication
51 */
5039dede
AK
52void LIBNXSRV_EXPORTABLE SetAgentDEP(int iPolicy)
53{
54#ifdef _WITH_ENCRYPTION
55 m_iDefaultEncryptionPolicy = iPolicy;
56#endif
57}
58
a3050773
VK
59/**
60 * Receiver thread starter
61 */
62THREAD_RESULT THREAD_CALL AgentConnection::receiverThreadStarter(void *pArg)
5039dede 63{
a3050773 64 ((AgentConnection *)pArg)->receiverThread();
5039dede
AK
65 return THREAD_OK;
66}
67
a3050773
VK
68/**
69 * Constructor for AgentConnection
70 */
c11eee9b 71AgentConnection::AgentConnection(InetAddress addr, WORD port, int authMethod, const TCHAR *secret)
5039dede 72{
c11eee9b 73 m_addr = addr;
69c6604d
VK
74 m_wPort = port;
75 m_iAuthMethod = authMethod;
76 if (secret != NULL)
5039dede
AK
77 {
78#ifdef UNICODE
69c6604d 79 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, secret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
08b214c6 80 m_szSecret[MAX_SECRET_LENGTH - 1] = 0;
5039dede 81#else
69c6604d 82 nx_strncpy(m_szSecret, secret, MAX_SECRET_LENGTH);
5039dede
AK
83#endif
84 }
85 else
86 {
87 m_szSecret[0] = 0;
88 }
89 m_hSocket = -1;
90 m_tLastCommandTime = 0;
91 m_dwNumDataLines = 0;
92 m_ppDataLines = NULL;
93 m_pMsgWaitQueue = new MsgWaitQueue;
94 m_dwRequestId = 1;
7c521895 95 m_connectionTimeout = 30000; // 30 seconds
5039dede
AK
96 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
97 m_bIsConnected = FALSE;
98 m_mutexDataLock = MutexCreate();
d3a7cf4c 99 m_mutexSocketWrite = MutexCreate();
5039dede
AK
100 m_hReceiverThread = INVALID_THREAD_HANDLE;
101 m_pCtx = NULL;
102 m_iEncryptionPolicy = m_iDefaultEncryptionPolicy;
103 m_bUseProxy = FALSE;
104 m_dwRecvTimeout = 420000; // 7 minutes
105 m_nProtocolVersion = NXCP_VERSION;
106 m_hCurrFile = -1;
76b4edb5 107 m_deleteFileOnDownloadFailure = true;
bb85e341 108 m_condFileDownload = ConditionCreate(TRUE);
4685a2ad 109 m_fileUploadInProgress = false;
9630fcd1 110 m_sendToClientMessageCallback = NULL;
5039dede
AK
111}
112
a3050773
VK
113/**
114 * Destructor
115 */
5039dede
AK
116AgentConnection::~AgentConnection()
117{
118 // Disconnect from peer
7c521895 119 disconnect();
5039dede
AK
120
121 // Wait for receiver thread termination
122 ThreadJoin(m_hReceiverThread);
cc022855 123
5039dede 124 // Close socket if active
a3050773 125 lock();
5039dede
AK
126 if (m_hSocket != -1)
127 {
128 closesocket(m_hSocket);
129 m_hSocket = -1;
130 }
a3050773 131 unlock();
5039dede 132
a3050773 133 lock();
7c521895 134 destroyResultData();
a3050773 135 unlock();
5039dede
AK
136
137 delete m_pMsgWaitQueue;
98abc9f1
VK
138 if (m_pCtx != NULL)
139 m_pCtx->decRefCount();
5039dede
AK
140
141 if (m_hCurrFile != -1)
9f6d453a 142 {
5039dede 143 close(m_hCurrFile);
f480bdd4 144 onFileDownload(FALSE);
9f6d453a 145 }
5039dede
AK
146
147 MutexDestroy(m_mutexDataLock);
d3a7cf4c 148 MutexDestroy(m_mutexSocketWrite);
bb85e341 149 ConditionDestroy(m_condFileDownload);
5039dede
AK
150}
151
a3050773
VK
152/**
153 * Print message. This method is virtual and can be overrided in
154 * derived classes. Default implementation will print message to stdout.
155 */
af21affe 156void AgentConnection::printMsg(const TCHAR *format, ...)
5039dede
AK
157{
158 va_list args;
159
af21affe
VK
160 va_start(args, format);
161 _vtprintf(format, args);
5039dede
AK
162 va_end(args);
163 _tprintf(_T("\n"));
164}
165
a3050773
VK
166/**
167 * Receiver thread
168 */
169void AgentConnection::receiverThread()
5039dede 170{
967893bb 171 UINT32 msgBufferSize = 1024;
b368969c
VK
172 NXCPMessage *pMsg;
173 NXCP_MESSAGE *pRawMsg;
174 NXCP_BUFFER *pMsgBuffer;
5039dede 175 BYTE *pDecryptionBuffer = NULL;
4685a2ad 176 int error;
c11eee9b 177 TCHAR szBuffer[128];
5039dede
AK
178 SOCKET nSocket;
179
180 // Initialize raw message receiving function
b368969c 181 pMsgBuffer = (NXCP_BUFFER *)malloc(sizeof(NXCP_BUFFER));
5039dede
AK
182 RecvNXCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL, 0);
183
184 // Allocate space for raw message
b368969c 185 pRawMsg = (NXCP_MESSAGE *)malloc(msgBufferSize);
5039dede 186#ifdef _WITH_ENCRYPTION
8f4f648d 187 pDecryptionBuffer = (BYTE *)malloc(msgBufferSize);
5039dede
AK
188#endif
189
190 // Message receiving loop
191 while(1)
192 {
8f4f648d
VK
193 // Shrink buffer after receiving large message
194 if (msgBufferSize > 131072)
195 {
196 msgBufferSize = 131072;
b368969c 197 pRawMsg = (NXCP_MESSAGE *)realloc(pRawMsg, msgBufferSize);
8f4f648d
VK
198 if (pDecryptionBuffer != NULL)
199 pDecryptionBuffer = (BYTE *)realloc(pDecryptionBuffer, msgBufferSize);
200 }
201
5039dede 202 // Receive raw message
a3050773 203 lock();
5039dede 204 nSocket = m_hSocket;
a3050773 205 unlock();
8f4f648d
VK
206 if ((error = RecvNXCPMessageEx(nSocket, &pRawMsg, pMsgBuffer, &msgBufferSize,
207 &m_pCtx, (pDecryptionBuffer != NULL) ? &pDecryptionBuffer : NULL,
208 m_dwRecvTimeout, MAX_MSG_SIZE)) <= 0)
5039dede 209 {
a2069340
VK
210 if (WSAGetLastError() != WSAESHUTDOWN)
211 DbgPrintf(6, _T("AgentConnection::ReceiverThread(): RecvNXCPMessage() failed: error=%d, socket_error=%d"), error, WSAGetLastError());
5039dede
AK
212 break;
213 }
214
215 // Check if we get too large message
4685a2ad 216 if (error == 1)
5039dede 217 {
cc022855 218 printMsg(_T("Received too large message %s (%d bytes)"),
b368969c
VK
219 NXCPMessageCodeName(ntohs(pRawMsg->code), szBuffer),
220 ntohl(pRawMsg->size));
5039dede
AK
221 continue;
222 }
223
224 // Check if we are unable to decrypt message
4685a2ad 225 if (error == 2)
5039dede 226 {
a3050773 227 printMsg(_T("Unable to decrypt received message"));
5039dede
AK
228 continue;
229 }
230
231 // Check for timeout
4685a2ad 232 if (error == 3)
5039dede 233 {
4685a2ad
VK
234 if (m_fileUploadInProgress)
235 continue; // Receive timeout may occur when uploading large files via slow links
a3050773 236 printMsg(_T("Timed out waiting for message"));
5039dede
AK
237 break;
238 }
239
240 // Check that actual received packet size is equal to encoded in packet
b368969c 241 if ((int)ntohl(pRawMsg->size) != error)
5039dede 242 {
b368969c 243 printMsg(_T("RecvMsg: Bad packet length [size=%d ActualSize=%d]"), ntohl(pRawMsg->size), error);
5039dede
AK
244 continue; // Bad packet, wait for next
245 }
246
b368969c 247 if (ntohs(pRawMsg->flags) & MF_BINARY)
5039dede
AK
248 {
249 // Convert message header to host format
b368969c
VK
250 pRawMsg->id = ntohl(pRawMsg->id);
251 pRawMsg->code = ntohs(pRawMsg->code);
252 pRawMsg->numFields = ntohl(pRawMsg->numFields);
08b214c6 253 DbgPrintf(6, _T("Received raw message %s from agent at %s"),
c11eee9b 254 NXCPMessageCodeName(pRawMsg->code, szBuffer), (const TCHAR *)m_addr.toString());
5039dede 255
b368969c 256 if ((pRawMsg->code == CMD_FILE_DATA) && (pRawMsg->id == m_dwDownloadRequestId))
5039dede 257 {
76b4edb5 258 if (m_sendToClientMessageCallback != NULL)
5039dede 259 {
b368969c
VK
260 pRawMsg->code = ntohs(pRawMsg->code);
261 pRawMsg->numFields = ntohl(pRawMsg->numFields);
76b4edb5 262 m_sendToClientMessageCallback(pRawMsg, m_downloadProgressCallbackArg);
263
b368969c 264 if (ntohs(pRawMsg->flags) & MF_END_OF_FILE)
5039dede 265 {
f480bdd4 266 onFileDownload(TRUE);
5039dede 267 }
76b4edb5 268 else
269 {
270 if (m_downloadProgressCallback != NULL)
271 {
b368969c 272 m_downloadProgressCallback(pRawMsg->size - (NXCP_HEADER_SIZE + 8), m_downloadProgressCallbackArg);
76b4edb5 273 }
274 }
5039dede
AK
275 }
276 else
277 {
76b4edb5 278 if (m_hCurrFile != -1)
279 {
b368969c 280 if (write(m_hCurrFile, pRawMsg->fields, pRawMsg->numFields) == (int)pRawMsg->numFields)
76b4edb5 281 {
b368969c 282 if (ntohs(pRawMsg->flags) & MF_END_OF_FILE)
76b4edb5 283 {
284 close(m_hCurrFile);
285 m_hCurrFile = -1;
286
287 onFileDownload(TRUE);
288 }
289 else
290 {
291 if (m_downloadProgressCallback != NULL)
292 {
293 m_downloadProgressCallback(_tell(m_hCurrFile), m_downloadProgressCallbackArg);
294 }
295 }
296 }
297 }
298 else
299 {
300 // I/O error
301 close(m_hCurrFile);
302 m_hCurrFile = -1;
cc022855 303
76b4edb5 304 onFileDownload(FALSE);
305 }
9a895fd6 306 }
307 }
308
b368969c 309 if((pRawMsg->code == CMD_ABORT_FILE_TRANSFER) && (pRawMsg->id == m_dwDownloadRequestId))
9a895fd6 310 {
311 if (m_sendToClientMessageCallback != NULL)
312 {
b368969c
VK
313 pRawMsg->code = ntohs(pRawMsg->code);
314 pRawMsg->numFields = ntohl(pRawMsg->numFields);
9a895fd6 315 m_sendToClientMessageCallback(pRawMsg, m_downloadProgressCallbackArg);
316
317 onFileDownload(FALSE);
318 }
319 else
320 {
321 //error on agent side
322 close(m_hCurrFile);
323 m_hCurrFile = -1;
324
325 onFileDownload(FALSE);
5039dede
AK
326 }
327 }
328 }
329 else
330 {
331 // Create message object from raw message
b368969c
VK
332 pMsg = new NXCPMessage(pRawMsg, m_nProtocolVersion);
333 switch(pMsg->getCode())
5039dede 334 {
f480bdd4
VK
335 case CMD_TRAP:
336 onTrap(pMsg);
337 delete pMsg;
338 break;
339 case CMD_PUSH_DCI_DATA:
340 onDataPush(pMsg);
341 delete pMsg;
342 break;
90284364 343 case CMD_REQUEST_COMPLETED:
c17f6cbc 344 m_pMsgWaitQueue->put(pMsg);
f480bdd4 345 break;
9fa031cd 346 case CMD_FILE_MONITORING:
347 onFileMonitoringData(pMsg);
348 delete pMsg;
489b117b 349 break;
350 case CMD_SNMP_TRAP:
351 onSnmpTrap(pMsg);
9fa031cd 352 break;
90284364
VK
353 default:
354 if (processCustomMessage(pMsg))
355 delete pMsg;
356 else
c17f6cbc 357 m_pMsgWaitQueue->put(pMsg);
90284364 358 break;
5039dede
AK
359 }
360 }
361 }
362
363 // Close socket and mark connection as disconnected
a3050773 364 lock();
f2665675
VK
365 if (m_hCurrFile != -1)
366 {
367 close(m_hCurrFile);
368 m_hCurrFile = -1;
f480bdd4 369 onFileDownload(FALSE);
f2665675 370 }
cc022855 371
4685a2ad 372 if (error == 0)
5039dede
AK
373 shutdown(m_hSocket, SHUT_RDWR);
374 closesocket(m_hSocket);
375 m_hSocket = -1;
98abc9f1
VK
376 if (m_pCtx != NULL)
377 {
378 m_pCtx->decRefCount();
379 m_pCtx = NULL;
380 }
5039dede 381 m_bIsConnected = FALSE;
a3050773 382 unlock();
5039dede
AK
383
384 free(pRawMsg);
385 free(pMsgBuffer);
386#ifdef _WITH_ENCRYPTION
387 free(pDecryptionBuffer);
388#endif
389}
390
a3050773
VK
391/**
392 * Connect to agent
393 */
967893bb 394BOOL AgentConnection::connect(RSA *pServerKey, BOOL bVerbose, UINT32 *pdwError, UINT32 *pdwSocketError)
5039dede 395{
5039dede
AK
396 TCHAR szBuffer[256];
397 BOOL bSuccess = FALSE, bForceEncryption = FALSE, bSecondPass = FALSE;
967893bb 398 UINT32 dwError = 0;
5039dede
AK
399
400 if (pdwError != NULL)
401 *pdwError = ERR_INTERNAL_ERROR;
402
c3acd0f6
VK
403 if (pdwSocketError != NULL)
404 *pdwSocketError = 0;
405
5039dede
AK
406 // Check if already connected
407 if (m_bIsConnected)
408 return FALSE;
409
410 // Wait for receiver thread from previous connection, if any
411 ThreadJoin(m_hReceiverThread);
412 m_hReceiverThread = INVALID_THREAD_HANDLE;
413
414 // Check if we need to close existing socket
415 if (m_hSocket != -1)
416 closesocket(m_hSocket);
417
4f89a15c
VK
418 struct sockaddr *sa;
419
5039dede 420 // Create socket
c11eee9b 421 m_hSocket = socket(m_bUseProxy ? m_proxyAddr.getFamily() : m_addr.getFamily(), SOCK_STREAM, 0);
4c0c75c7 422 if (m_hSocket == INVALID_SOCKET)
5039dede 423 {
a3050773 424 printMsg(_T("Call to socket() failed"));
5039dede
AK
425 goto connect_cleanup;
426 }
427
428 // Fill in address structure
c11eee9b 429 SockAddrBuffer sb;
4f89a15c 430 sa = m_bUseProxy ? m_proxyAddr.fillSockAddr(&sb, m_wProxyPort) : m_addr.fillSockAddr(&sb, m_wPort);
5039dede
AK
431
432 // Connect to server
c11eee9b 433 if ((sa == NULL) || (ConnectEx(m_hSocket, sa, SA_LEN(sa), m_connectionTimeout) == -1))
5039dede
AK
434 {
435 if (bVerbose)
c11eee9b
VK
436 printMsg(_T("Cannot establish connection with agent at %s:%d"),
437 m_bUseProxy ? m_proxyAddr.toString(szBuffer) : m_addr.toString(szBuffer),
438 (int)(m_bUseProxy ? m_wProxyPort : m_wPort));
5039dede
AK
439 dwError = ERR_CONNECT_FAILED;
440 goto connect_cleanup;
441 }
442
d3a7cf4c 443 if (!NXCPGetPeerProtocolVersion(m_hSocket, &m_nProtocolVersion, m_mutexSocketWrite))
5039dede
AK
444 {
445 dwError = ERR_INTERNAL_ERROR;
446 goto connect_cleanup;
447 }
448
449 // Start receiver thread
a3050773 450 m_hReceiverThread = ThreadCreateEx(receiverThreadStarter, 0, this);
5039dede
AK
451
452 // Setup encryption
453setup_encryption:
454 if ((m_iEncryptionPolicy == ENCRYPTION_PREFERRED) ||
455 (m_iEncryptionPolicy == ENCRYPTION_REQUIRED) ||
456 (bForceEncryption)) // Agent require encryption
457 {
458 if (pServerKey != NULL)
459 {
7c521895 460 dwError = setupEncryption(pServerKey);
5039dede
AK
461 if ((dwError != ERR_SUCCESS) &&
462 ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption))
463 goto connect_cleanup;
464 }
465 else
466 {
467 if ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption)
468 {
469 dwError = ERR_ENCRYPTION_REQUIRED;
470 goto connect_cleanup;
471 }
472 }
473 }
474
475 // Authenticate itself to agent
7c521895 476 if ((dwError = authenticate(m_bUseProxy && !bSecondPass)) != ERR_SUCCESS)
5039dede
AK
477 {
478 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
479 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
480 {
481 bForceEncryption = TRUE;
482 goto setup_encryption;
483 }
c11eee9b 484 printMsg(_T("Authentication to agent %s failed (%s)"), m_addr.toString(szBuffer),
5039dede
AK
485 AgentErrorCodeToText(dwError));
486 goto connect_cleanup;
487 }
488
ea3993c8
VK
489 // Test connectivity and enable IPv6 support
490 if ((dwError = enableIPv6()) != ERR_SUCCESS)
5039dede
AK
491 {
492 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
493 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
494 {
495 bForceEncryption = TRUE;
496 goto setup_encryption;
497 }
6de2ec52
VK
498 if (dwError != ERR_UNKNOWN_COMMAND) // Older agents may not support enable IPv6 command
499 {
500 printMsg(_T("Communication with agent %s failed (%s)"), m_addr.toString(szBuffer), AgentErrorCodeToText(dwError));
501 goto connect_cleanup;
502 }
5039dede
AK
503 }
504
505 if (m_bUseProxy && !bSecondPass)
506 {
7c521895 507 dwError = setupProxyConnection();
5039dede
AK
508 if (dwError != ERR_SUCCESS)
509 goto connect_cleanup;
a3050773 510 lock();
98abc9f1
VK
511 if (m_pCtx != NULL)
512 {
513 m_pCtx->decRefCount();
514 m_pCtx = NULL;
515 }
a3050773 516 unlock();
5039dede
AK
517 bSecondPass = TRUE;
518 bForceEncryption = FALSE;
519 goto setup_encryption;
520 }
521
522 bSuccess = TRUE;
523 dwError = ERR_SUCCESS;
524
525connect_cleanup:
526 if (!bSuccess)
527 {
c3acd0f6 528 if (pdwSocketError != NULL)
967893bb 529 *pdwSocketError = (UINT32)WSAGetLastError();
c3acd0f6 530
a3050773 531 lock();
5039dede
AK
532 if (m_hSocket != -1)
533 shutdown(m_hSocket, SHUT_RDWR);
a3050773 534 unlock();
5039dede
AK
535 ThreadJoin(m_hReceiverThread);
536 m_hReceiverThread = INVALID_THREAD_HANDLE;
537
a3050773 538 lock();
5039dede
AK
539 if (m_hSocket != -1)
540 {
541 closesocket(m_hSocket);
542 m_hSocket = -1;
543 }
544
98abc9f1
VK
545 if (m_pCtx != NULL)
546 {
547 m_pCtx->decRefCount();
548 m_pCtx = NULL;
549 }
5039dede 550
a3050773 551 unlock();
5039dede
AK
552 }
553 m_bIsConnected = bSuccess;
554 if (pdwError != NULL)
555 *pdwError = dwError;
556 return bSuccess;
557}
558
af21affe
VK
559/**
560 * Disconnect from agent
561 */
7c521895 562void AgentConnection::disconnect()
5039dede 563{
a3050773 564 lock();
f2665675
VK
565 if (m_hCurrFile != -1)
566 {
567 close(m_hCurrFile);
568 m_hCurrFile = -1;
f480bdd4 569 onFileDownload(FALSE);
f2665675 570 }
9fa031cd 571
5039dede
AK
572 if (m_hSocket != -1)
573 {
574 shutdown(m_hSocket, SHUT_RDWR);
575 }
7c521895 576 destroyResultData();
5039dede 577 m_bIsConnected = FALSE;
a3050773 578 unlock();
5039dede
AK
579}
580
af21affe
VK
581/**
582 * Set authentication data
583 */
584void AgentConnection::setAuthData(int method, const TCHAR *secret)
cc022855 585{
af21affe
VK
586 m_iAuthMethod = method;
587#ifdef UNICODE
588 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, secret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
589 m_szSecret[MAX_SECRET_LENGTH - 1] = 0;
590#else
591 nx_strncpy(m_szSecret, secret, MAX_SECRET_LENGTH);
592#endif
593}
5039dede 594
af21affe
VK
595/**
596 * Destroy command execuion results data
597 */
7c521895 598void AgentConnection::destroyResultData()
5039dede 599{
967893bb 600 UINT32 i;
5039dede
AK
601
602 if (m_ppDataLines != NULL)
603 {
604 for(i = 0; i < m_dwNumDataLines; i++)
605 if (m_ppDataLines[i] != NULL)
606 free(m_ppDataLines[i]);
607 free(m_ppDataLines);
608 m_ppDataLines = NULL;
609 }
610 m_dwNumDataLines = 0;
611}
612
d51f2182
VK
613/**
614 * Get interface list from agent
615 */
98762401 616InterfaceList *AgentConnection::getInterfaceList()
5039dede 617{
98762401 618 InterfaceList *pIfList = NULL;
5039dede
AK
619 TCHAR *pChar, *pBuf;
620
4687826e 621 if (getList(_T("Net.InterfaceList")) == ERR_SUCCESS)
5039dede 622 {
98762401 623 pIfList = new InterfaceList(m_dwNumDataLines);
5039dede
AK
624
625 // Parse result set. Each line should have the following format:
626 // index ip_address/mask_bits iftype mac_address name
914eb859 627 for(UINT32 i = 0; i < m_dwNumDataLines; i++)
5039dede
AK
628 {
629 pBuf = m_ppDataLines[i];
2ffad7c2 630 UINT32 ifIndex = 0;
5039dede
AK
631
632 // Index
633 pChar = _tcschr(pBuf, ' ');
634 if (pChar != NULL)
635 {
636 *pChar = 0;
2ffad7c2 637 ifIndex = _tcstoul(pBuf, NULL, 10);
5039dede
AK
638 pBuf = pChar + 1;
639 }
640
2ffad7c2
VK
641 bool newInterface = false;
642 InterfaceInfo *iface = pIfList->findByIfIndex(ifIndex);
643 if (iface == NULL)
644 {
645 iface = new InterfaceInfo(ifIndex);
646 newInterface = true;
647 }
648
5039dede
AK
649 // Address and mask
650 pChar = _tcschr(pBuf, _T(' '));
651 if (pChar != NULL)
652 {
653 TCHAR *pSlash;
654 static TCHAR defaultMask[] = _T("24");
655
656 *pChar = 0;
657 pSlash = _tcschr(pBuf, _T('/'));
658 if (pSlash != NULL)
659 {
660 *pSlash = 0;
661 pSlash++;
662 }
663 else // Just a paranoia protection, should'n happen if agent working correctly
664 {
665 pSlash = defaultMask;
666 }
c30c0c0f
VK
667 InetAddress addr = InetAddress::parse(pBuf);
668 addr.setMaskBits(_tcstol(pSlash, NULL, 10));
669 iface->ipAddrList.add(addr);
5039dede
AK
670 pBuf = pChar + 1;
671 }
672
2ffad7c2 673 if (newInterface)
5039dede 674 {
2ffad7c2
VK
675 // Interface type
676 pChar = _tcschr(pBuf, ' ');
677 if (pChar != NULL)
678 {
679 *pChar = 0;
33560996
VK
680
681 TCHAR *eptr;
682 iface->type = _tcstoul(pBuf, &eptr, 10);
683
684 // newer agents can return if_type(mtu)
685 if (*eptr == _T('('))
686 {
687 pBuf = eptr + 1;
688 eptr = _tcschr(pBuf, _T(')'));
689 if (eptr != NULL)
690 {
691 *eptr = 0;
692 iface->mtu = _tcstol(pBuf, NULL, 10);
693 }
694 }
695
2ffad7c2
VK
696 pBuf = pChar + 1;
697 }
5039dede 698
2ffad7c2
VK
699 // MAC address
700 pChar = _tcschr(pBuf, ' ');
701 if (pChar != NULL)
702 {
703 *pChar = 0;
704 StrToBin(pBuf, iface->macAddr, MAC_ADDR_LENGTH);
705 pBuf = pChar + 1;
706 }
5039dede 707
2ffad7c2
VK
708 // Name (set description to name)
709 nx_strncpy(iface->name, pBuf, MAX_DB_STRING);
710 nx_strncpy(iface->description, pBuf, MAX_DB_STRING);
98762401 711
2ffad7c2
VK
712 pIfList->add(iface);
713 }
5039dede
AK
714 }
715
a3050773 716 lock();
7c521895 717 destroyResultData();
a3050773 718 unlock();
5039dede
AK
719 }
720
721 return pIfList;
722}
723
724
489b117b 725/**
726 * Get parameter value
727 */
967893bb 728UINT32 AgentConnection::getParameter(const TCHAR *pszParam, UINT32 dwBufSize, TCHAR *pszBuffer)
5039dede 729{
b368969c 730 NXCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 731 UINT32 dwRqId, dwRetCode;
5039dede
AK
732
733 if (m_bIsConnected)
734 {
735 dwRqId = m_dwRequestId++;
b368969c
VK
736 msg.setCode(CMD_GET_PARAMETER);
737 msg.setId(dwRqId);
738 msg.setField(VID_PARAMETER, pszParam);
7c521895 739 if (sendMessage(&msg))
5039dede 740 {
7c521895 741 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
742 if (pResponse != NULL)
743 {
b368969c 744 dwRetCode = pResponse->getFieldAsUInt32(VID_RCC);
5039dede 745 if (dwRetCode == ERR_SUCCESS)
b368969c 746 pResponse->getFieldAsString(VID_VALUE, pszBuffer, dwBufSize);
5039dede
AK
747 delete pResponse;
748 }
749 else
750 {
751 dwRetCode = ERR_REQUEST_TIMEOUT;
752 }
753 }
754 else
755 {
756 dwRetCode = ERR_CONNECTION_BROKEN;
757 }
758 }
759 else
760 {
761 dwRetCode = ERR_NOT_CONNECTED;
762 }
763
764 return dwRetCode;
765}
766
489b117b 767/**
768 * Get ARP cache
769 */
4687826e 770ARP_CACHE *AgentConnection::getArpCache()
5039dede
AK
771{
772 ARP_CACHE *pArpCache = NULL;
773 TCHAR szByte[4], *pBuf, *pChar;
967893bb 774 UINT32 i, j;
5039dede 775
4687826e 776 if (getList(_T("Net.ArpCache")) == ERR_SUCCESS)
5039dede
AK
777 {
778 // Create empty structure
779 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
780 pArpCache->dwNumEntries = m_dwNumDataLines;
781 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
782 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
783
784 szByte[2] = 0;
785
786 // Parse data lines
787 // Each line has form of XXXXXXXXXXXX a.b.c.d n
788 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
789 // a.b.c.d is an IP address in decimal dotted notation
790 // n is an interface index
791 for(i = 0; i < m_dwNumDataLines; i++)
792 {
793 pBuf = m_ppDataLines[i];
794 if (_tcslen(pBuf) < 20) // Invalid line
795 continue;
796
797 // MAC address
798 for(j = 0; j < 6; j++)
799 {
800 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
801 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
802 pBuf+=2;
803 }
804
805 // IP address
806 while(*pBuf == ' ')
807 pBuf++;
808 pChar = _tcschr(pBuf, _T(' '));
809 if (pChar != NULL)
810 *pChar = 0;
c75e9ee4 811 pArpCache->pEntries[i].ipAddr = ntohl(_t_inet_addr(pBuf));
5039dede
AK
812
813 // Interface index
814 if (pChar != NULL)
815 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
816 }
817
a3050773 818 lock();
7c521895 819 destroyResultData();
a3050773 820 unlock();
5039dede
AK
821 }
822 return pArpCache;
823}
824
489b117b 825/**
826 * Send dummy command to agent (can be used for keepalive)
827 */
967893bb 828UINT32 AgentConnection::nop()
5039dede 829{
b368969c 830 NXCPMessage msg(m_nProtocolVersion);
967893bb 831 UINT32 dwRqId;
5039dede
AK
832
833 dwRqId = m_dwRequestId++;
b368969c
VK
834 msg.setCode(CMD_KEEPALIVE);
835 msg.setId(dwRqId);
7c521895
VK
836 if (sendMessage(&msg))
837 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
838 else
839 return ERR_CONNECTION_BROKEN;
840}
841
ea3993c8
VK
842/**
843 * Notify agent that server is IPv6 aware
844 */
845UINT32 AgentConnection::enableIPv6()
846{
847 NXCPMessage msg(m_nProtocolVersion);
848 UINT32 dwRqId;
849
850 dwRqId = m_dwRequestId++;
851 msg.setCode(CMD_ENABLE_IPV6);
852 msg.setField(VID_ENABLED, (INT16)1);
853 msg.setId(dwRqId);
854 if (sendMessage(&msg))
855 return waitForRCC(dwRqId, m_dwCommandTimeout);
856 else
857 return ERR_CONNECTION_BROKEN;
858}
859
489b117b 860/**
861 * Wait for request completion code
862 */
967893bb 863UINT32 AgentConnection::waitForRCC(UINT32 dwRqId, UINT32 dwTimeOut)
5039dede 864{
b368969c 865 NXCPMessage *pMsg;
967893bb 866 UINT32 dwRetCode;
5039dede 867
c17f6cbc 868 pMsg = m_pMsgWaitQueue->waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
5039dede
AK
869 if (pMsg != NULL)
870 {
b368969c 871 dwRetCode = pMsg->getFieldAsUInt32(VID_RCC);
5039dede
AK
872 delete pMsg;
873 }
874 else
875 {
876 dwRetCode = ERR_REQUEST_TIMEOUT;
877 }
878 return dwRetCode;
879}
880
5c44534b
VK
881/**
882 * Send message to agent
883 */
b368969c 884BOOL AgentConnection::sendMessage(NXCPMessage *pMsg)
5039dede 885{
5039dede
AK
886 BOOL bResult;
887
b368969c 888 NXCP_MESSAGE *pRawMsg = pMsg->createMessage();
98abc9f1
VK
889 NXCPEncryptionContext *pCtx = acquireEncryptionContext();
890 if (pCtx != NULL)
5039dede 891 {
b368969c 892 NXCP_ENCRYPTED_MESSAGE *pEnMsg = pCtx->encryptMessage(pRawMsg);
5039dede
AK
893 if (pEnMsg != NULL)
894 {
b368969c 895 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->size));
5039dede
AK
896 free(pEnMsg);
897 }
898 else
899 {
900 bResult = FALSE;
901 }
98abc9f1 902 pCtx->decRefCount();
5039dede
AK
903 }
904 else
905 {
b368969c 906 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->size));
5039dede
AK
907 }
908 free(pRawMsg);
909 return bResult;
910}
911
7cf549ad 912/**
913 * Send raw message to agent
914 */
b368969c 915BOOL AgentConnection::sendRawMessage(NXCP_MESSAGE *pMsg)
7cf549ad 916{
917 BOOL bResult;
918
b368969c 919 NXCP_MESSAGE *pRawMsg = pMsg;
7cf549ad 920 NXCPEncryptionContext *pCtx = acquireEncryptionContext();
921 if (pCtx != NULL)
922 {
b368969c 923 NXCP_ENCRYPTED_MESSAGE *pEnMsg = pCtx->encryptMessage(pRawMsg);
7cf549ad 924 if (pEnMsg != NULL)
925 {
b368969c 926 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->size));
7cf549ad 927 free(pEnMsg);
928 }
929 else
930 {
931 bResult = FALSE;
932 }
933 pCtx->decRefCount();
934 }
935 else
936 {
b368969c 937 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->size));
7cf549ad 938 }
939 return bResult;
940}
941
d51f2182
VK
942/**
943 * Trap handler. Should be overriden in derived classes to implement
944 * actual trap processing. Default implementation do nothing.
945 */
b368969c 946void AgentConnection::onTrap(NXCPMessage *pMsg)
f480bdd4
VK
947{
948}
949
d51f2182
VK
950/**
951 * Data push handler. Should be overriden in derived classes to implement
952 * actual data push processing. Default implementation do nothing.
953 */
b368969c 954void AgentConnection::onDataPush(NXCPMessage *pMsg)
5039dede
AK
955{
956}
957
9fa031cd 958/**
959 * Monitoring data handler. Should be overriden in derived classes to implement
960 * actual monitoring data processing. Default implementation do nothing.
961 */
b368969c 962void AgentConnection::onFileMonitoringData(NXCPMessage *pMsg)
9fa031cd 963{
964}
965
489b117b 966/**
967 * SNMP trap handler. Should be overriden in derived classes to implement
968 * actual SNMP trap processing. Default implementation do nothing.
969 */
b368969c 970void AgentConnection::onSnmpTrap(NXCPMessage *pMsg)
489b117b 971{
972}
973
d51f2182
VK
974/**
975 * Custom message handler
976 * If returns true, message considered as processed and will not be placed in wait queue
977 */
b368969c 978bool AgentConnection::processCustomMessage(NXCPMessage *pMsg)
90284364
VK
979{
980 return false;
981}
982
d51f2182
VK
983/**
984 * Get list of values
985 */
967893bb 986UINT32 AgentConnection::getList(const TCHAR *pszParam)
5039dede 987{
b368969c 988 NXCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 989 UINT32 i, dwRqId, dwRetCode;
5039dede
AK
990
991 if (m_bIsConnected)
992 {
7c521895 993 destroyResultData();
5039dede 994 dwRqId = m_dwRequestId++;
b368969c
VK
995 msg.setCode(CMD_GET_LIST);
996 msg.setId(dwRqId);
997 msg.setField(VID_PARAMETER, pszParam);
7c521895 998 if (sendMessage(&msg))
5039dede 999 {
7c521895 1000 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1001 if (pResponse != NULL)
1002 {
b368969c 1003 dwRetCode = pResponse->getFieldAsUInt32(VID_RCC);
5039dede
AK
1004 if (dwRetCode == ERR_SUCCESS)
1005 {
b368969c 1006 m_dwNumDataLines = pResponse->getFieldAsUInt32(VID_NUM_STRINGS);
5039dede
AK
1007 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
1008 for(i = 0; i < m_dwNumDataLines; i++)
b368969c 1009 m_ppDataLines[i] = pResponse->getFieldAsString(VID_ENUM_VALUE_BASE + i);
5039dede
AK
1010 }
1011 delete pResponse;
1012 }
1013 else
1014 {
1015 dwRetCode = ERR_REQUEST_TIMEOUT;
1016 }
1017 }
1018 else
1019 {
1020 dwRetCode = ERR_CONNECTION_BROKEN;
1021 }
1022 }
1023 else
1024 {
1025 dwRetCode = ERR_NOT_CONNECTED;
1026 }
1027
1028 return dwRetCode;
1029}
1030
d51f2182
VK
1031/**
1032 * Get table
1033 */
967893bb 1034UINT32 AgentConnection::getTable(const TCHAR *pszParam, Table **table)
4687826e 1035{
b368969c 1036 NXCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 1037 UINT32 dwRqId, dwRetCode;
4687826e
VK
1038
1039 *table = NULL;
1040 if (m_bIsConnected)
1041 {
1042 dwRqId = m_dwRequestId++;
b368969c
VK
1043 msg.setCode(CMD_GET_TABLE);
1044 msg.setId(dwRqId);
1045 msg.setField(VID_PARAMETER, pszParam);
4687826e
VK
1046 if (sendMessage(&msg))
1047 {
1048 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1049 if (pResponse != NULL)
1050 {
b368969c 1051 dwRetCode = pResponse->getFieldAsUInt32(VID_RCC);
4687826e
VK
1052 if (dwRetCode == ERR_SUCCESS)
1053 {
1054 *table = new Table(pResponse);
1055 }
1056 delete pResponse;
1057 }
1058 else
1059 {
1060 dwRetCode = ERR_REQUEST_TIMEOUT;
1061 }
1062 }
1063 else
1064 {
1065 dwRetCode = ERR_CONNECTION_BROKEN;
1066 }
1067 }
1068 else
1069 {
1070 dwRetCode = ERR_NOT_CONNECTED;
1071 }
1072
1073 return dwRetCode;
1074}
1075
975f38fc
VK
1076/**
1077 * Authenticate to agent
1078 */
967893bb 1079UINT32 AgentConnection::authenticate(BOOL bProxyData)
5039dede 1080{
b368969c 1081 NXCPMessage msg(m_nProtocolVersion);
967893bb 1082 UINT32 dwRqId;
5039dede
AK
1083 BYTE hash[32];
1084 int iAuthMethod = bProxyData ? m_iProxyAuth : m_iAuthMethod;
08b214c6 1085 const char *pszSecret = bProxyData ? m_szProxySecret : m_szSecret;
5039dede
AK
1086#ifdef UNICODE
1087 WCHAR szBuffer[MAX_SECRET_LENGTH];
1088#endif
1089
1090 if (iAuthMethod == AUTH_NONE)
1091 return ERR_SUCCESS; // No authentication required
1092
1093 dwRqId = m_dwRequestId++;
b368969c
VK
1094 msg.setCode(CMD_AUTHENTICATE);
1095 msg.setId(dwRqId);
1096 msg.setField(VID_AUTH_METHOD, (WORD)iAuthMethod);
5039dede
AK
1097 switch(iAuthMethod)
1098 {
1099 case AUTH_PLAINTEXT:
1100#ifdef UNICODE
1101 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszSecret, -1, szBuffer, MAX_SECRET_LENGTH);
b368969c 1102 msg.setField(VID_SHARED_SECRET, szBuffer);
5039dede 1103#else
b368969c 1104 msg.setField(VID_SHARED_SECRET, pszSecret);
5039dede
AK
1105#endif
1106 break;
1107 case AUTH_MD5_HASH:
1108 CalculateMD5Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
b368969c 1109 msg.setField(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
5039dede
AK
1110 break;
1111 case AUTH_SHA1_HASH:
1112 CalculateSHA1Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
b368969c 1113 msg.setField(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
5039dede
AK
1114 break;
1115 default:
1116 break;
1117 }
7c521895
VK
1118 if (sendMessage(&msg))
1119 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1120 else
1121 return ERR_CONNECTION_BROKEN;
1122}
1123
908d71bd
VK
1124/**
1125 * Execute action on agent
1126 */
1127UINT32 AgentConnection::execAction(const TCHAR *pszAction, int argc, TCHAR **argv,
1128 bool withOutput, void (* outputCallback)(ActionCallbackEvent, const TCHAR *, void *), void *cbData)
5039dede 1129{
b368969c 1130 NXCPMessage msg(m_nProtocolVersion);
967893bb 1131 UINT32 dwRqId;
5039dede
AK
1132 int i;
1133
1134 if (!m_bIsConnected)
1135 return ERR_NOT_CONNECTED;
1136
1137 dwRqId = m_dwRequestId++;
b368969c
VK
1138 msg.setCode(CMD_ACTION);
1139 msg.setId(dwRqId);
1140 msg.setField(VID_ACTION_NAME, pszAction);
1141 msg.setField(VID_RECEIVE_OUTPUT, (UINT16)(withOutput ? 1 : 0));
1142 msg.setField(VID_NUM_ARGS, (UINT32)argc);
5039dede 1143 for(i = 0; i < argc; i++)
b368969c 1144 msg.setField(VID_ACTION_ARG_BASE + i, argv[i]);
5039dede 1145
7c521895 1146 if (sendMessage(&msg))
908d71bd
VK
1147 {
1148 if (withOutput)
1149 {
1150 UINT32 rcc = waitForRCC(dwRqId, m_dwCommandTimeout);
1151 if (rcc == ERR_SUCCESS)
1152 {
1153 outputCallback(ACE_CONNECTED, NULL, cbData); // Indicate successful start
1154 bool eos = false;
1155 while(!eos)
1156 {
b368969c 1157 NXCPMessage *response = waitForMessage(CMD_COMMAND_OUTPUT, dwRqId, m_dwCommandTimeout);
908d71bd
VK
1158 if (response != NULL)
1159 {
1160 eos = response->isEndOfSequence();
1161 if (response->isFieldExist(VID_MESSAGE))
1162 {
1163 TCHAR line[4096];
b368969c 1164 response->getFieldAsString(VID_MESSAGE, line, 4096);
908d71bd
VK
1165 outputCallback(ACE_DATA, line, cbData);
1166 }
1167 delete response;
1168 }
1169 else
1170 {
1171 return ERR_REQUEST_TIMEOUT;
1172 }
1173 }
1174 outputCallback(ACE_DISCONNECTED, NULL, cbData);
1175 return ERR_SUCCESS;
1176 }
1177 else
1178 {
1179 return rcc;
1180 }
1181 }
1182 else
1183 {
1184 return waitForRCC(dwRqId, m_dwCommandTimeout);
1185 }
1186 }
5039dede 1187 else
908d71bd 1188 {
5039dede 1189 return ERR_CONNECTION_BROKEN;
908d71bd 1190 }
5039dede
AK
1191}
1192
74d2f1ea 1193/**
1194 * Upload file to agent
1195 */
967893bb 1196UINT32 AgentConnection::uploadFile(const TCHAR *localFile, const TCHAR *destinationFile, void (* progressCallback)(INT64, void *), void *cbArg)
5039dede 1197{
967893bb 1198 UINT32 dwRqId, dwResult;
b368969c 1199 NXCPMessage msg(m_nProtocolVersion);
5039dede
AK
1200
1201 if (!m_bIsConnected)
1202 return ERR_NOT_CONNECTED;
1203
1204 dwRqId = m_dwRequestId++;
b368969c 1205 msg.setId(dwRqId);
5039dede 1206
8581943e
VK
1207 // Use core agent if destination file name is not set and file manager subagent otherwise
1208 if ((destinationFile == NULL) || (*destinationFile == 0))
74d2f1ea 1209 {
b368969c 1210 msg.setCode(CMD_TRANSFER_FILE);
8581943e
VK
1211 int i;
1212 for(i = (int)_tcslen(localFile) - 1;
1213 (i >= 0) && (localFile[i] != '\\') && (localFile[i] != '/'); i--);
b368969c 1214 msg.setField(VID_FILE_NAME, &localFile[i + 1]);
74d2f1ea 1215 }
1216 else
1217 {
b368969c
VK
1218 msg.setCode(CMD_FILEMGR_UPLOAD);
1219 msg.setField(VID_FILE_NAME, destinationFile);
f0c1d2a4 1220 }
5039dede 1221
7c521895 1222 if (sendMessage(&msg))
5039dede 1223 {
7c521895 1224 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1225 }
1226 else
1227 {
1228 dwResult = ERR_CONNECTION_BROKEN;
1229 }
1230
1231 if (dwResult == ERR_SUCCESS)
1232 {
4685a2ad 1233 m_fileUploadInProgress = true;
98abc9f1 1234 NXCPEncryptionContext *ctx = acquireEncryptionContext();
cc022855 1235 if (SendFileOverNXCP(m_hSocket, dwRqId, localFile, ctx, 0, progressCallback, cbArg, m_mutexSocketWrite))
7c521895 1236 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1237 else
1238 dwResult = ERR_IO_FAILURE;
4685a2ad 1239 m_fileUploadInProgress = false;
5039dede
AK
1240 }
1241
1242 return dwResult;
1243}
1244
8581943e
VK
1245/**
1246 * Send upgrade command
1247 */
967893bb 1248UINT32 AgentConnection::startUpgrade(const TCHAR *pszPkgName)
5039dede 1249{
967893bb 1250 UINT32 dwRqId, dwResult;
b368969c 1251 NXCPMessage msg(m_nProtocolVersion);
5039dede
AK
1252 int i;
1253
1254 if (!m_bIsConnected)
1255 return ERR_NOT_CONNECTED;
1256
1257 dwRqId = m_dwRequestId++;
1258
b368969c
VK
1259 msg.setCode(CMD_UPGRADE_AGENT);
1260 msg.setId(dwRqId);
cc022855 1261 for(i = (int)_tcslen(pszPkgName) - 1;
5039dede 1262 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
b368969c 1263 msg.setField(VID_FILE_NAME, &pszPkgName[i + 1]);
5039dede 1264
7c521895 1265 if (sendMessage(&msg))
5039dede 1266 {
7c521895 1267 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1268 }
1269 else
1270 {
1271 dwResult = ERR_CONNECTION_BROKEN;
1272 }
1273
1274 return dwResult;
1275}
1276
a0e181dc
VK
1277/**
1278 * Check status of network service via agent
1279 */
c75e9ee4 1280UINT32 AgentConnection::checkNetworkService(UINT32 *pdwStatus, const InetAddress& addr, int iServiceType,
b8014eee
VK
1281 WORD wPort, WORD wProto, const TCHAR *pszRequest,
1282 const TCHAR *pszResponse, UINT32 *responseTime)
5039dede 1283{
967893bb 1284 UINT32 dwRqId, dwResult;
b368969c 1285 NXCPMessage msg(m_nProtocolVersion), *pResponse;
a0e181dc 1286 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80, 443, 23 };
5039dede
AK
1287
1288 if (!m_bIsConnected)
1289 return ERR_NOT_CONNECTED;
1290
1291 dwRqId = m_dwRequestId++;
1292
b368969c
VK
1293 msg.setCode(CMD_CHECK_NETWORK_SERVICE);
1294 msg.setId(dwRqId);
c75e9ee4 1295 msg.setField(VID_IP_ADDRESS, addr);
b368969c
VK
1296 msg.setField(VID_SERVICE_TYPE, (WORD)iServiceType);
1297 msg.setField(VID_IP_PORT,
cc022855 1298 (wPort != 0) ? wPort :
1299 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
a0e181dc 1300 (iServiceType <= NETSRV_TELNET)) ? iServiceType : 0]);
b368969c
VK
1301 msg.setField(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
1302 msg.setField(VID_SERVICE_REQUEST, pszRequest);
1303 msg.setField(VID_SERVICE_RESPONSE, pszResponse);
5039dede 1304
7c521895 1305 if (sendMessage(&msg))
5039dede
AK
1306 {
1307 // Wait up to 90 seconds for results
7c521895 1308 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
5039dede
AK
1309 if (pResponse != NULL)
1310 {
b368969c 1311 dwResult = pResponse->getFieldAsUInt32(VID_RCC);
5039dede
AK
1312 if (dwResult == ERR_SUCCESS)
1313 {
b368969c 1314 *pdwStatus = pResponse->getFieldAsUInt32(VID_SERVICE_STATUS);
b8014eee
VK
1315 if (responseTime != NULL)
1316 {
b368969c 1317 *responseTime = pResponse->getFieldAsUInt32(VID_RESPONSE_TIME);
b8014eee 1318 }
5039dede
AK
1319 }
1320 delete pResponse;
1321 }
1322 else
1323 {
1324 dwResult = ERR_REQUEST_TIMEOUT;
1325 }
1326 }
1327 else
1328 {
1329 dwResult = ERR_CONNECTION_BROKEN;
1330 }
1331
1332 return dwResult;
1333}
1334
074498ac 1335/**
86c126f5 1336 * Get list of supported parameters from agent
074498ac 1337 */
967893bb 1338UINT32 AgentConnection::getSupportedParameters(ObjectArray<AgentParameterDefinition> **paramList, ObjectArray<AgentTableDefinition> **tableList)
5039dede 1339{
967893bb 1340 UINT32 dwRqId, dwResult;
b368969c 1341 NXCPMessage msg(m_nProtocolVersion), *pResponse;
5039dede 1342
cc8ce218
VK
1343 *paramList = NULL;
1344 *tableList = NULL;
5039dede
AK
1345
1346 if (!m_bIsConnected)
1347 return ERR_NOT_CONNECTED;
1348
1349 dwRqId = m_dwRequestId++;
1350
b368969c
VK
1351 msg.setCode(CMD_GET_PARAMETER_LIST);
1352 msg.setId(dwRqId);
5039dede 1353
7c521895 1354 if (sendMessage(&msg))
5039dede 1355 {
7c521895 1356 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1357 if (pResponse != NULL)
1358 {
b368969c 1359 dwResult = pResponse->getFieldAsUInt32(VID_RCC);
cc8ce218 1360 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): RCC=%d"), dwResult);
5039dede
AK
1361 if (dwResult == ERR_SUCCESS)
1362 {
b368969c 1363 UINT32 count = pResponse->getFieldAsUInt32(VID_NUM_PARAMETERS);
86c126f5 1364 ObjectArray<AgentParameterDefinition> *plist = new ObjectArray<AgentParameterDefinition>(count, 16, true);
b368969c 1365 for(UINT32 i = 0, id = VID_PARAM_LIST_BASE; i < count; i++)
5039dede 1366 {
b368969c
VK
1367 plist->add(new AgentParameterDefinition(pResponse, id));
1368 id += 3;
5039dede 1369 }
86c126f5 1370 *paramList = plist;
cc8ce218
VK
1371 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d parameters received from agent"), count);
1372
b368969c 1373 count = pResponse->getFieldAsUInt32(VID_NUM_TABLES);
86c126f5 1374 ObjectArray<AgentTableDefinition> *tlist = new ObjectArray<AgentTableDefinition>(count, 16, true);
b368969c 1375 for(UINT32 i = 0, id = VID_TABLE_LIST_BASE; i < count; i++)
cc8ce218 1376 {
b368969c
VK
1377 tlist->add(new AgentTableDefinition(pResponse, id));
1378 id += 3;
cc8ce218 1379 }
86c126f5 1380 *tableList = tlist;
cc8ce218
VK
1381 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d tables received from agent"), count);
1382 }
5039dede
AK
1383 delete pResponse;
1384 }
1385 else
1386 {
1387 dwResult = ERR_REQUEST_TIMEOUT;
1388 }
1389 }
1390 else
1391 {
1392 dwResult = ERR_CONNECTION_BROKEN;
1393 }
1394
1395 return dwResult;
1396}
1397
074498ac
VK
1398/**
1399 * Setup encryption
1400 */
967893bb 1401UINT32 AgentConnection::setupEncryption(RSA *pServerKey)
5039dede
AK
1402{
1403#ifdef _WITH_ENCRYPTION
b368969c 1404 NXCPMessage msg(m_nProtocolVersion), *pResp;
967893bb 1405 UINT32 dwRqId, dwError, dwResult;
5039dede
AK
1406
1407 dwRqId = m_dwRequestId++;
1408
9e9d631e 1409 PrepareKeyRequestMsg(&msg, pServerKey, false);
b368969c 1410 msg.setId(dwRqId);
7c521895 1411 if (sendMessage(&msg))
5039dede 1412 {
7c521895 1413 pResp = waitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
5039dede
AK
1414 if (pResp != NULL)
1415 {
1416 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey, m_nProtocolVersion);
1417 switch(dwResult)
1418 {
1419 case RCC_SUCCESS:
1420 dwError = ERR_SUCCESS;
1421 break;
1422 case RCC_NO_CIPHERS:
1423 dwError = ERR_NO_CIPHERS;
1424 break;
1425 case RCC_INVALID_PUBLIC_KEY:
1426 dwError = ERR_INVALID_PUBLIC_KEY;
1427 break;
1428 case RCC_INVALID_SESSION_KEY:
1429 dwError = ERR_INVALID_SESSION_KEY;
1430 break;
1431 default:
1432 dwError = ERR_INTERNAL_ERROR;
1433 break;
1434 }
1435 delete pResp;
1436 }
1437 else
1438 {
1439 dwError = ERR_REQUEST_TIMEOUT;
1440 }
1441 }
1442 else
1443 {
1444 dwError = ERR_CONNECTION_BROKEN;
1445 }
1446
1447 return dwError;
1448#else
1449 return ERR_NOT_IMPLEMENTED;
1450#endif
1451}
1452
5944946e
VK
1453/**
1454 * Get configuration file from agent
1455 */
967893bb 1456UINT32 AgentConnection::getConfigFile(TCHAR **ppszConfig, UINT32 *pdwSize)
5039dede 1457{
967893bb 1458 UINT32 i, dwRqId, dwResult;
b368969c 1459 NXCPMessage msg(m_nProtocolVersion), *pResponse;
5039dede
AK
1460#ifdef UNICODE
1461 BYTE *pBuffer;
1462#endif
1463
1464 *ppszConfig = NULL;
1465 *pdwSize = 0;
1466
1467 if (!m_bIsConnected)
1468 return ERR_NOT_CONNECTED;
1469
1470 dwRqId = m_dwRequestId++;
1471
b368969c
VK
1472 msg.setCode(CMD_GET_AGENT_CONFIG);
1473 msg.setId(dwRqId);
5039dede 1474
7c521895 1475 if (sendMessage(&msg))
5039dede 1476 {
7c521895 1477 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1478 if (pResponse != NULL)
1479 {
b368969c 1480 dwResult = pResponse->getFieldAsUInt32(VID_RCC);
5039dede
AK
1481 if (dwResult == ERR_SUCCESS)
1482 {
b368969c 1483 *pdwSize = pResponse->getFieldAsBinary(VID_CONFIG_FILE, NULL, 0);
5039dede
AK
1484 *ppszConfig = (TCHAR *)malloc((*pdwSize + 1) * sizeof(TCHAR));
1485#ifdef UNICODE
1486 pBuffer = (BYTE *)malloc(*pdwSize + 1);
b368969c 1487 pResponse->getFieldAsBinary(VID_CONFIG_FILE, pBuffer, *pdwSize);
08b214c6 1488 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char *)pBuffer, *pdwSize, *ppszConfig, *pdwSize);
5039dede
AK
1489 free(pBuffer);
1490#else
b368969c 1491 pResponse->getFieldAsBinary(VID_CONFIG_FILE, (BYTE *)(*ppszConfig), *pdwSize);
5039dede
AK
1492#endif
1493 (*ppszConfig)[*pdwSize] = 0;
1494
1495 // We expect text file, so replace all non-printable characters with spaces
1496 for(i = 0; i < *pdwSize; i++)
cc022855 1497 if (((*ppszConfig)[i] < _T(' ')) &&
5039dede
AK
1498 ((*ppszConfig)[i] != _T('\t')) &&
1499 ((*ppszConfig)[i] != _T('\r')) &&
1500 ((*ppszConfig)[i] != _T('\n')))
1501 (*ppszConfig)[i] = _T(' ');
1502 }
1503 delete pResponse;
1504 }
1505 else
1506 {
1507 dwResult = ERR_REQUEST_TIMEOUT;
1508 }
1509 }
1510 else
1511 {
1512 dwResult = ERR_CONNECTION_BROKEN;
1513 }
1514
1515 return dwResult;
1516}
1517
5944946e
VK
1518/**
1519 * Update configuration file on agent
1520 */
967893bb 1521UINT32 AgentConnection::updateConfigFile(const TCHAR *pszConfig)
5039dede 1522{
967893bb 1523 UINT32 dwRqId, dwResult;
b368969c 1524 NXCPMessage msg(m_nProtocolVersion);
5039dede
AK
1525#ifdef UNICODE
1526 int nChars;
1527 BYTE *pBuffer;
1528#endif
1529
1530 if (!m_bIsConnected)
1531 return ERR_NOT_CONNECTED;
1532
1533 dwRqId = m_dwRequestId++;
1534
b368969c
VK
1535 msg.setCode(CMD_UPDATE_AGENT_CONFIG);
1536 msg.setId(dwRqId);
5039dede 1537#ifdef UNICODE
465b3f2d 1538 nChars = (int)_tcslen(pszConfig);
5039dede
AK
1539 pBuffer = (BYTE *)malloc(nChars + 1);
1540 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
08b214c6 1541 pszConfig, nChars, (char *)pBuffer, nChars + 1, NULL, NULL);
b368969c 1542 msg.setField(VID_CONFIG_FILE, pBuffer, nChars);
5039dede
AK
1543 free(pBuffer);
1544#else
b368969c 1545 msg.setField(VID_CONFIG_FILE, (BYTE *)pszConfig, (UINT32)strlen(pszConfig));
5039dede
AK
1546#endif
1547
7c521895 1548 if (sendMessage(&msg))
5039dede 1549 {
7c521895 1550 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1551 }
1552 else
1553 {
1554 dwResult = ERR_CONNECTION_BROKEN;
1555 }
1556
1557 return dwResult;
1558}
1559
5944946e
VK
1560/**
1561 * Get routing table from agent
1562 */
4687826e 1563ROUTING_TABLE *AgentConnection::getRoutingTable()
5039dede
AK
1564{
1565 ROUTING_TABLE *pRT = NULL;
967893bb 1566 UINT32 i, dwBits;
5039dede
AK
1567 TCHAR *pChar, *pBuf;
1568
4687826e 1569 if (getList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS)
5039dede
AK
1570 {
1571 pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
1572 pRT->iNumEntries = m_dwNumDataLines;
1573 pRT->pRoutes = (ROUTE *)malloc(sizeof(ROUTE) * m_dwNumDataLines);
1574 memset(pRT->pRoutes, 0, sizeof(ROUTE) * m_dwNumDataLines);
1575 for(i = 0; i < m_dwNumDataLines; i++)
1576 {
1577 pBuf = m_ppDataLines[i];
1578
1579 // Destination address and mask
1580 pChar = _tcschr(pBuf, _T(' '));
1581 if (pChar != NULL)
1582 {
1583 TCHAR *pSlash;
1584 static TCHAR defaultMask[] = _T("24");
1585
1586 *pChar = 0;
1587 pSlash = _tcschr(pBuf, _T('/'));
1588 if (pSlash != NULL)
1589 {
1590 *pSlash = 0;
1591 pSlash++;
1592 }
1593 else // Just a paranoia protection, should'n happen if agent working correctly
1594 {
1595 pSlash = defaultMask;
1596 }
1597 pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
1598 dwBits = _tcstoul(pSlash, NULL, 10);
1599 pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
1600 pBuf = pChar + 1;
1601 }
1602
1603 // Next hop address
1604 pChar = _tcschr(pBuf, _T(' '));
1605 if (pChar != NULL)
1606 {
1607 *pChar = 0;
1608 pRT->pRoutes[i].dwNextHop = ntohl(_t_inet_addr(pBuf));
1609 pBuf = pChar + 1;
1610 }
1611
1612 // Interface index
1613 pChar = _tcschr(pBuf, ' ');
1614 if (pChar != NULL)
1615 {
1616 *pChar = 0;
1617 pRT->pRoutes[i].dwIfIndex = _tcstoul(pBuf, NULL, 10);
1618 pBuf = pChar + 1;
1619 }
1620
1621 // Route type
1622 pRT->pRoutes[i].dwRouteType = _tcstoul(pBuf, NULL, 10);
1623 }
1624
a3050773 1625 lock();
7c521895 1626 destroyResultData();
a3050773 1627 unlock();
5039dede
AK
1628 }
1629
1630 return pRT;
1631}
1632
5944946e
VK
1633/**
1634 * Set proxy information
1635 */
c11eee9b 1636void AgentConnection::setProxy(InetAddress addr, WORD wPort, int iAuthMethod, const TCHAR *pszSecret)
5039dede 1637{
c11eee9b 1638 m_proxyAddr = addr;
5039dede
AK
1639 m_wProxyPort = wPort;
1640 m_iProxyAuth = iAuthMethod;
1641 if (pszSecret != NULL)
1642 {
1643#ifdef UNICODE
cc022855 1644 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
5039dede
AK
1645 pszSecret, -1, m_szProxySecret, MAX_SECRET_LENGTH, NULL, NULL);
1646#else
1647 nx_strncpy(m_szProxySecret, pszSecret, MAX_SECRET_LENGTH);
1648#endif
1649 }
1650 else
1651 {
1652 m_szProxySecret[0] = 0;
1653 }
1654 m_bUseProxy = TRUE;
1655}
1656
5944946e
VK
1657/**
1658 * Setup proxy connection
1659 */
967893bb 1660UINT32 AgentConnection::setupProxyConnection()
5039dede 1661{
b368969c 1662 NXCPMessage msg(m_nProtocolVersion);
967893bb 1663 UINT32 dwRqId;
5039dede
AK
1664
1665 dwRqId = m_dwRequestId++;
b368969c
VK
1666 msg.setCode(CMD_SETUP_PROXY_CONNECTION);
1667 msg.setId(dwRqId);
c11eee9b 1668 msg.setField(VID_IP_ADDRESS, m_addr.getAddressV4()); // FIXME: V6 support in proxy
b368969c 1669 msg.setField(VID_AGENT_PORT, m_wPort);
7c521895
VK
1670 if (sendMessage(&msg))
1671 return waitForRCC(dwRqId, 60000); // Wait 60 seconds for remote connect
5039dede
AK
1672 else
1673 return ERR_CONNECTION_BROKEN;
1674}
1675
ef8278f0
VK
1676/**
1677 * Enable trap receiving on connection
1678 */
967893bb 1679UINT32 AgentConnection::enableTraps()
5039dede 1680{
b368969c 1681 NXCPMessage msg(m_nProtocolVersion);
967893bb 1682 UINT32 dwRqId;
5039dede
AK
1683
1684 dwRqId = m_dwRequestId++;
b368969c
VK
1685 msg.setCode(CMD_ENABLE_AGENT_TRAPS);
1686 msg.setId(dwRqId);
7c521895
VK
1687 if (sendMessage(&msg))
1688 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1689 else
1690 return ERR_CONNECTION_BROKEN;
1691}
1692
5944946e
VK
1693/**
1694 * Take screenshot from remote system
1695 */
9c786c0f 1696UINT32 AgentConnection::takeScreenshot(const TCHAR *sessionName, BYTE **data, size_t *size)
5944946e 1697{
b368969c 1698 NXCPMessage msg(m_nProtocolVersion);
5944946e
VK
1699 UINT32 dwRqId;
1700
1701 dwRqId = m_dwRequestId++;
b368969c
VK
1702 msg.setCode(CMD_TAKE_SCREENSHOT);
1703 msg.setId(dwRqId);
1704 msg.setField(VID_NAME, sessionName);
5944946e
VK
1705 if (sendMessage(&msg))
1706 {
b368969c 1707 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5944946e
VK
1708 if (response != NULL)
1709 {
b368969c 1710 UINT32 rcc = response->getFieldAsUInt32(VID_RCC);
5944946e
VK
1711 if (rcc == ERR_SUCCESS)
1712 {
1713 BYTE *p = response->getBinaryFieldPtr(VID_FILE_DATA, size);
1714 if (p != NULL)
1715 {
1716 *data = (BYTE *)malloc(*size);
1717 memcpy(*data, p, *size);
1718 }
1719 else
1720 {
1721 *data = NULL;
1722 }
1723 }
1724 delete response;
1725 return rcc;
1726 }
1727 else
1728 {
1729 return ERR_REQUEST_TIMEOUT;
1730 }
1731 }
1732 else
1733 {
1734 return ERR_CONNECTION_BROKEN;
1735 }
1736}
1737
cc022855 1738/**
1739 * Send custom request to agent
1740 */
b368969c
VK
1741NXCPMessage *AgentConnection::customRequest(NXCPMessage *pRequest, const TCHAR *recvFile, bool append, void (*downloadProgressCallback)(size_t, void *),
1742 void (*fileResendCallback)(NXCP_MESSAGE*, void *), void *cbArg)
5039dede 1743{
967893bb 1744 UINT32 dwRqId, rcc;
b368969c 1745 NXCPMessage *msg = NULL;
5039dede
AK
1746
1747 dwRqId = m_dwRequestId++;
b368969c 1748 pRequest->setId(dwRqId);
5039dede
AK
1749 if (recvFile != NULL)
1750 {
76b4edb5 1751 rcc = prepareFileDownload(recvFile, dwRqId, append, downloadProgressCallback, fileResendCallback,cbArg);
5039dede
AK
1752 if (rcc != ERR_SUCCESS)
1753 {
1754 // Create fake response message
b368969c
VK
1755 msg = new NXCPMessage;
1756 msg->setCode(CMD_REQUEST_COMPLETED);
1757 msg->setId(dwRqId);
1758 msg->setField(VID_RCC, rcc);
5039dede
AK
1759 }
1760 }
1761
1762 if (msg == NULL)
1763 {
7c521895 1764 if (sendMessage(pRequest))
5039dede 1765 {
7c521895 1766 msg = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1767 if ((msg != NULL) && (recvFile != NULL))
1768 {
b368969c 1769 if (msg->getFieldAsUInt32(VID_RCC) == ERR_SUCCESS)
5039dede 1770 {
bb85e341 1771 if (ConditionWait(m_condFileDownload, 1800000)) // 30 min timeout
5039dede 1772 {
bb85e341 1773 if (!m_fileDownloadSucceeded)
5039dede 1774 {
b368969c 1775 msg->setField(VID_RCC, ERR_IO_FAILURE);
901a5a9b 1776 if (m_deleteFileOnDownloadFailure)
08b214c6 1777 _tremove(recvFile);
5039dede
AK
1778 }
1779 }
1780 else
1781 {
b368969c 1782 msg->setField(VID_RCC, ERR_REQUEST_TIMEOUT);
5039dede
AK
1783 }
1784 }
1785 else
1786 {
ef8278f0 1787 if (fileResendCallback != NULL)
76b4edb5 1788 {
1789 close(m_hCurrFile);
1790 m_hCurrFile = -1;
1791 _tremove(recvFile);
1792 }
5039dede
AK
1793 }
1794 }
76b4edb5 1795
5039dede
AK
1796 }
1797 }
1798
1799 return msg;
1800}
1801
76b4edb5 1802/**
ef8278f0 1803 * Prepare for file download
76b4edb5 1804 */
76b4edb5 1805UINT32 AgentConnection::prepareFileDownload(const TCHAR *fileName, UINT32 rqId, bool append, void (*downloadProgressCallback)(size_t, void *),
b368969c 1806 void (*fileResendCallback)(NXCP_MESSAGE *, void *), void *cbArg)
5039dede 1807{
ef8278f0 1808 if (fileResendCallback == NULL)
76b4edb5 1809 {
1810 if (m_hCurrFile != -1)
1811 return ERR_RESOURCE_BUSY;
5039dede 1812
76b4edb5 1813 nx_strncpy(m_currentFileName, fileName, MAX_PATH);
1814 ConditionReset(m_condFileDownload);
1815 m_hCurrFile = _topen(fileName, (append ? 0 : (O_CREAT | O_TRUNC)) | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
1816 if (m_hCurrFile == -1)
1817 {
1818 DbgPrintf(4, _T("AgentConnection::PrepareFileDownload(): cannot open file %s (%s); append=%d rqId=%d"),
1819 fileName, _tcserror(errno), append, rqId);
1820 }
1821 else
1822 {
1823 if (append)
1824 lseek(m_hCurrFile, 0, SEEK_END);
1825 }
1826
1827 m_dwDownloadRequestId = rqId;
1828 m_downloadProgressCallback = downloadProgressCallback;
1829 m_downloadProgressCallbackArg = cbArg;
1830
9630fcd1
AK
1831 m_sendToClientMessageCallback = NULL;
1832
76b4edb5 1833 return (m_hCurrFile != -1) ? ERR_SUCCESS : ERR_FILE_OPEN_ERROR;
1834 }
1835 else
1836 {
1837 ConditionReset(m_condFileDownload);
76b4edb5 1838
1839 m_dwDownloadRequestId = rqId;
1840 m_downloadProgressCallback = downloadProgressCallback;
1841 m_downloadProgressCallbackArg = cbArg;
1842
9630fcd1
AK
1843 m_sendToClientMessageCallback = fileResendCallback;
1844
76b4edb5 1845 return ERR_SUCCESS;
1846 }
5039dede
AK
1847}
1848
76b4edb5 1849/**
1850 * File upload completion handler
1851 */
f480bdd4 1852void AgentConnection::onFileDownload(BOOL success)
5039dede 1853{
76b4edb5 1854 if (!success && m_deleteFileOnDownloadFailure)
901a5a9b 1855 _tremove(m_currentFileName);
bb85e341
VK
1856 m_fileDownloadSucceeded = success;
1857 ConditionSet(m_condFileDownload);
5039dede 1858}
1f385e47 1859
ef8278f0
VK
1860/**
1861 * Enable trap receiving on connection
1862 */
967893bb 1863UINT32 AgentConnection::getPolicyInventory(AgentPolicyInfo **info)
1f385e47 1864{
b368969c 1865 NXCPMessage msg(m_nProtocolVersion);
967893bb 1866 UINT32 dwRqId, rcc;
1f385e47
VK
1867
1868 *info = NULL;
1869 dwRqId = m_dwRequestId++;
b368969c
VK
1870 msg.setCode(CMD_GET_POLICY_INVENTORY);
1871 msg.setId(dwRqId);
1f385e47
VK
1872 if (sendMessage(&msg))
1873 {
b368969c 1874 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1f385e47
VK
1875 if (response != NULL)
1876 {
b368969c 1877 rcc = response->getFieldAsUInt32(VID_RCC);
1f385e47
VK
1878 if (rcc == ERR_SUCCESS)
1879 *info = new AgentPolicyInfo(response);
1880 delete response;
1881 }
1882 else
1883 {
1884 rcc = ERR_REQUEST_TIMEOUT;
1885 }
1886 }
1887 else
1888 {
1889 rcc = ERR_CONNECTION_BROKEN;
1890 }
1891 return rcc;
1892}
1893
ef8278f0
VK
1894/**
1895 * Uninstall policy by GUID
1896 */
967893bb 1897UINT32 AgentConnection::uninstallPolicy(uuid_t guid)
1f385e47 1898{
967893bb 1899 UINT32 rqId, rcc;
b368969c 1900 NXCPMessage msg(m_nProtocolVersion);
1f385e47
VK
1901
1902 rqId = generateRequestId();
b368969c
VK
1903 msg.setId(rqId);
1904 msg.setCode(CMD_UNINSTALL_AGENT_POLICY);
1905 msg.setField(VID_GUID, guid, UUID_LENGTH);
1f385e47
VK
1906 if (sendMessage(&msg))
1907 {
1908 rcc = waitForRCC(rqId, m_dwCommandTimeout);
1909 }
1910 else
1911 {
1912 rcc = ERR_CONNECTION_BROKEN;
1913 }
1914 return rcc;
1915}
98abc9f1 1916
86c126f5
VK
1917/**
1918 * Acquire encryption context
1919 */
98abc9f1
VK
1920NXCPEncryptionContext *AgentConnection::acquireEncryptionContext()
1921{
a3050773 1922 lock();
98abc9f1
VK
1923 NXCPEncryptionContext *ctx = m_pCtx;
1924 if (ctx != NULL)
1925 ctx->incRefCount();
a3050773 1926 unlock();
98abc9f1
VK
1927 return ctx;
1928}
86c126f5
VK
1929
1930/**
1931 * Create new agent parameter definition from NXCP message
1932 */
b368969c 1933AgentParameterDefinition::AgentParameterDefinition(NXCPMessage *msg, UINT32 baseId)
86c126f5 1934{
b368969c
VK
1935 m_name = msg->getFieldAsString(baseId);
1936 m_description = msg->getFieldAsString(baseId + 1);
1937 m_dataType = (int)msg->getFieldAsUInt16(baseId + 2);
86c126f5
VK
1938}
1939
1940/**
1941 * Create new agent parameter definition from another definition object
1942 */
1943AgentParameterDefinition::AgentParameterDefinition(AgentParameterDefinition *src)
1944{
1945 m_name = (src->m_name != NULL) ? _tcsdup(src->m_name) : NULL;
1946 m_description = (src->m_description != NULL) ? _tcsdup(src->m_description) : NULL;
1947 m_dataType = src->m_dataType;
1948}
1949
1950/**
1951 * Destructor for agent parameter definition
1952 */
1953AgentParameterDefinition::~AgentParameterDefinition()
1954{
1955 safe_free(m_name);
1956 safe_free(m_description);
1957}
1958
1959/**
1960 * Fill NXCP message
1961 */
b368969c 1962UINT32 AgentParameterDefinition::fillMessage(NXCPMessage *msg, UINT32 baseId)
86c126f5 1963{
b368969c
VK
1964 msg->setField(baseId, m_name);
1965 msg->setField(baseId + 1, m_description);
1966 msg->setField(baseId + 2, (WORD)m_dataType);
86c126f5
VK
1967 return 3;
1968}
1969
1970/**
1971 * Create new agent table definition from NXCP message
1972 */
b368969c 1973AgentTableDefinition::AgentTableDefinition(NXCPMessage *msg, UINT32 baseId)
86c126f5 1974{
b368969c
VK
1975 m_name = msg->getFieldAsString(baseId);
1976 m_description = msg->getFieldAsString(baseId + 2);
86c126f5 1977
b368969c 1978 TCHAR *instanceColumns = msg->getFieldAsString(baseId + 1);
86c126f5
VK
1979 if (instanceColumns != NULL)
1980 {
1981 m_instanceColumns = new StringList(instanceColumns, _T("|"));
1982 free(instanceColumns);
1983 }
1984 else
1985 {
1986 m_instanceColumns = new StringList;
1987 }
1988
1989 m_columns = new ObjectArray<AgentTableColumnDefinition>(16, 16, true);
1990}
1991
1992/**
1993 * Create new agent table definition from another definition object
1994 */
1995AgentTableDefinition::AgentTableDefinition(AgentTableDefinition *src)
1996{
1997 m_name = (src->m_name != NULL) ? _tcsdup(src->m_name) : NULL;
1998 m_description = (src->m_description != NULL) ? _tcsdup(src->m_description) : NULL;
1999 m_instanceColumns = new StringList(src->m_instanceColumns);
2000 m_columns = new ObjectArray<AgentTableColumnDefinition>(16, 16, true);
2001 for(int i = 0; i < src->m_columns->size(); i++)
2002 {
2003 m_columns->add(new AgentTableColumnDefinition(src->m_columns->get(i)));
2004 }
2005}
2006/**
2007 * Destructor for agent table definition
2008 */
2009AgentTableDefinition::~AgentTableDefinition()
2010{
2011 safe_free(m_name);
2012 safe_free(m_description);
2013 delete m_instanceColumns;
2014 delete m_columns;
2015}
2016
2017/**
2018 * Fill NXCP message
2019 */
b368969c 2020UINT32 AgentTableDefinition::fillMessage(NXCPMessage *msg, UINT32 baseId)
86c126f5 2021{
b368969c
VK
2022 msg->setField(baseId + 1, m_name);
2023 msg->setField(baseId + 2, m_description);
86c126f5
VK
2024
2025 TCHAR *instanceColumns = m_instanceColumns->join(_T("|"));
b368969c 2026 msg->setField(baseId + 3, instanceColumns);
86c126f5
VK
2027 free(instanceColumns);
2028
967893bb 2029 UINT32 varId = baseId + 4;
86c126f5
VK
2030 for(int i = 0; i < m_columns->size(); i++)
2031 {
b368969c
VK
2032 msg->setField(varId++, m_columns->get(i)->m_name);
2033 msg->setField(varId++, (WORD)m_columns->get(i)->m_dataType);
86c126f5
VK
2034 }
2035
b368969c 2036 msg->setField(baseId, varId - baseId);
86c126f5
VK
2037 return varId - baseId;
2038}