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