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