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