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