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