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