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