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