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