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