Timeout increased from 1sec to 30sec
[public/netxms.git] / src / server / libnxsrv / agent.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Server Library
4** Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Victor Kirhenshtein
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
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**
16** You should have received a copy of the GNU General Public License
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
5039dede
AK
35
36//
37// Constants
38//
39
40#define RECEIVER_BUFFER_SIZE 262144
41
42
43//
44// Static data
45//
46
47#ifdef _WITH_ENCRYPTION
48static int m_iDefaultEncryptionPolicy = ENCRYPTION_ALLOWED;
49#else
50static int m_iDefaultEncryptionPolicy = ENCRYPTION_DISABLED;
51#endif
52
53
54//
55// Set default encryption policy for agent communication
56//
57
58void LIBNXSRV_EXPORTABLE SetAgentDEP(int iPolicy)
59{
60#ifdef _WITH_ENCRYPTION
61 m_iDefaultEncryptionPolicy = iPolicy;
62#endif
63}
64
65
66//
67// Receiver thread starter
68//
69
70THREAD_RESULT THREAD_CALL AgentConnection::ReceiverThreadStarter(void *pArg)
71{
72 ((AgentConnection *)pArg)->ReceiverThread();
73 return THREAD_OK;
74}
75
76
77//
78// Default constructor for AgentConnection - normally shouldn't be used
79//
80
81AgentConnection::AgentConnection()
82{
83 m_dwAddr = inet_addr("127.0.0.1");
84 m_wPort = AGENT_LISTEN_PORT;
85 m_iAuthMethod = AUTH_NONE;
86 m_szSecret[0] = 0;
87 m_hSocket = -1;
88 m_tLastCommandTime = 0;
89 m_dwNumDataLines = 0;
90 m_ppDataLines = NULL;
91 m_pMsgWaitQueue = new MsgWaitQueue;
92 m_dwRequestId = 1;
93 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
94 m_bIsConnected = FALSE;
95 m_mutexDataLock = MutexCreate();
96 m_hReceiverThread = INVALID_THREAD_HANDLE;
97 m_pCtx = NULL;
98 m_iEncryptionPolicy = m_iDefaultEncryptionPolicy;
99 m_bUseProxy = FALSE;
100 m_dwRecvTimeout = 420000; // 7 minutes
101 m_nProtocolVersion = NXCP_VERSION;
102 m_hCurrFile = -1;
901a5a9b 103 m_deleteFileOnDownloadFailure = true;
bb85e341 104 m_condFileDownload = ConditionCreate(TRUE);
5039dede
AK
105}
106
107
108//
109// Normal constructor for AgentConnection
110//
111
112AgentConnection::AgentConnection(DWORD dwAddr, WORD wPort,
113 int iAuthMethod, const TCHAR *pszSecret)
114{
115 m_dwAddr = dwAddr;
116 m_wPort = wPort;
117 m_iAuthMethod = iAuthMethod;
118 if (pszSecret != NULL)
119 {
120#ifdef UNICODE
121 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
122 pszSecret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
123#else
124 nx_strncpy(m_szSecret, pszSecret, MAX_SECRET_LENGTH);
125#endif
126 }
127 else
128 {
129 m_szSecret[0] = 0;
130 }
131 m_hSocket = -1;
132 m_tLastCommandTime = 0;
133 m_dwNumDataLines = 0;
134 m_ppDataLines = NULL;
135 m_pMsgWaitQueue = new MsgWaitQueue;
136 m_dwRequestId = 1;
137 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
138 m_bIsConnected = FALSE;
139 m_mutexDataLock = MutexCreate();
140 m_hReceiverThread = INVALID_THREAD_HANDLE;
141 m_pCtx = NULL;
142 m_iEncryptionPolicy = m_iDefaultEncryptionPolicy;
143 m_bUseProxy = FALSE;
144 m_dwRecvTimeout = 420000; // 7 minutes
145 m_nProtocolVersion = NXCP_VERSION;
146 m_hCurrFile = -1;
901a5a9b 147 m_deleteFileOnDownloadFailure = true;
bb85e341 148 m_condFileDownload = ConditionCreate(TRUE);
5039dede
AK
149}
150
151
152//
153// Destructor
154//
155
156AgentConnection::~AgentConnection()
157{
158 // Disconnect from peer
159 Disconnect();
160
161 // Wait for receiver thread termination
162 ThreadJoin(m_hReceiverThread);
163
164 // Close socket if active
165 Lock();
166 if (m_hSocket != -1)
167 {
168 closesocket(m_hSocket);
169 m_hSocket = -1;
170 }
171 Unlock();
172
173 Lock();
174 DestroyResultData();
175 Unlock();
176
177 delete m_pMsgWaitQueue;
178 DestroyEncryptionContext(m_pCtx);
179
180 if (m_hCurrFile != -1)
9f6d453a 181 {
5039dede 182 close(m_hCurrFile);
9f6d453a
VK
183 OnFileDownload(FALSE);
184 }
5039dede
AK
185
186 MutexDestroy(m_mutexDataLock);
bb85e341 187 ConditionDestroy(m_condFileDownload);
5039dede
AK
188}
189
190
191//
192// Print message. This function is virtual and can be overrided in
193// derived classes. Default implementation will print message to stdout.
194//
195
196void AgentConnection::PrintMsg(const TCHAR *pszFormat, ...)
197{
198 va_list args;
199
200 va_start(args, pszFormat);
201 _vtprintf(pszFormat, args);
202 va_end(args);
203 _tprintf(_T("\n"));
204}
205
206
207//
208// Receiver thread
209//
210
211void AgentConnection::ReceiverThread(void)
212{
213 CSCPMessage *pMsg;
214 CSCP_MESSAGE *pRawMsg;
215 CSCP_BUFFER *pMsgBuffer;
216 BYTE *pDecryptionBuffer = NULL;
217 int iErr;
218 TCHAR szBuffer[128], szIpAddr[16];
219 SOCKET nSocket;
220
221 // Initialize raw message receiving function
222 pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
223 RecvNXCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL, 0);
224
225 // Allocate space for raw message
226 pRawMsg = (CSCP_MESSAGE *)malloc(RECEIVER_BUFFER_SIZE);
227#ifdef _WITH_ENCRYPTION
228 pDecryptionBuffer = (BYTE *)malloc(RECEIVER_BUFFER_SIZE);
229#endif
230
231 // Message receiving loop
232 while(1)
233 {
234 // Receive raw message
235 Lock();
236 nSocket = m_hSocket;
237 Unlock();
238 if ((iErr = RecvNXCPMessage(nSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE,
239 &m_pCtx, pDecryptionBuffer, m_dwRecvTimeout)) <= 0)
240 {
241 DbgPrintf(6, _T("AgentConnection::ReceiverThread(): RecvNXCPMessage() failed: error=%d, socket_error=%d"), iErr, WSAGetLastError());
242 break;
243 }
244
245 // Check if we get too large message
246 if (iErr == 1)
247 {
248 PrintMsg(_T("Received too large message %s (%d bytes)"),
249 NXCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
250 ntohl(pRawMsg->dwSize));
251 continue;
252 }
253
254 // Check if we are unable to decrypt message
255 if (iErr == 2)
256 {
257 PrintMsg(_T("Unable to decrypt received message"));
258 continue;
259 }
260
261 // Check for timeout
262 if (iErr == 3)
263 {
264 PrintMsg(_T("Timed out waiting for message"));
265 break;
266 }
267
268 // Check that actual received packet size is equal to encoded in packet
269 if ((int)ntohl(pRawMsg->dwSize) != iErr)
270 {
271 PrintMsg(_T("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]"), ntohl(pRawMsg->dwSize), iErr);
272 continue; // Bad packet, wait for next
273 }
274
275 if (ntohs(pRawMsg->wFlags) & MF_BINARY)
276 {
277 // Convert message header to host format
278 pRawMsg->dwId = ntohl(pRawMsg->dwId);
279 pRawMsg->wCode = ntohs(pRawMsg->wCode);
280 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
281 DbgPrintf(6, "Received raw message %s from agent at %s",
282 NXCPMessageCodeName(pRawMsg->wCode, szBuffer), IpToStr(GetIpAddr(), szIpAddr));
283
284 if ((pRawMsg->wCode == CMD_FILE_DATA) &&
bb85e341 285 (m_hCurrFile != -1) && (pRawMsg->dwId == m_dwDownloadRequestId))
5039dede
AK
286 {
287 if (write(m_hCurrFile, pRawMsg->df, pRawMsg->dwNumVars) == (int)pRawMsg->dwNumVars)
288 {
289 if (ntohs(pRawMsg->wFlags) & MF_END_OF_FILE)
290 {
291 close(m_hCurrFile);
292 m_hCurrFile = -1;
293
bb85e341 294 OnFileDownload(TRUE);
5039dede 295 }
bb85e341
VK
296 else
297 {
298 if (m_downloadProgressCallback != NULL)
299 {
901a5a9b 300 m_downloadProgressCallback(_tell(m_hCurrFile), m_downloadProgressCallbackArg);
bb85e341
VK
301 }
302 }
5039dede
AK
303 }
304 else
305 {
306 // I/O error
307 close(m_hCurrFile);
308 m_hCurrFile = -1;
309
bb85e341 310 OnFileDownload(FALSE);
5039dede
AK
311 }
312 }
313 }
314 else
315 {
316 // Create message object from raw message
317 pMsg = new CSCPMessage(pRawMsg, m_nProtocolVersion);
318 if (pMsg->GetCode() == CMD_TRAP)
319 {
320 OnTrap(pMsg);
321 delete pMsg;
322 }
323 else
324 {
325 m_pMsgWaitQueue->Put(pMsg);
326 }
327 }
328 }
329
330 // Close socket and mark connection as disconnected
331 Lock();
f2665675
VK
332 if (m_hCurrFile != -1)
333 {
334 close(m_hCurrFile);
335 m_hCurrFile = -1;
336 OnFileDownload(FALSE);
337 }
338
339 if (iErr == 0)
5039dede
AK
340 shutdown(m_hSocket, SHUT_RDWR);
341 closesocket(m_hSocket);
342 m_hSocket = -1;
343 DestroyEncryptionContext(m_pCtx);
344 m_pCtx = NULL;
345 m_bIsConnected = FALSE;
346 Unlock();
347
348 free(pRawMsg);
349 free(pMsgBuffer);
350#ifdef _WITH_ENCRYPTION
351 free(pDecryptionBuffer);
352#endif
353}
354
355
356//
357// Connect to agent
358//
359
360BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose, DWORD *pdwError)
361{
362 struct sockaddr_in sa;
363 TCHAR szBuffer[256];
364 BOOL bSuccess = FALSE, bForceEncryption = FALSE, bSecondPass = FALSE;
365 DWORD dwError = 0;
366
367 if (pdwError != NULL)
368 *pdwError = ERR_INTERNAL_ERROR;
369
370 // Check if already connected
371 if (m_bIsConnected)
372 return FALSE;
373
374 // Wait for receiver thread from previous connection, if any
375 ThreadJoin(m_hReceiverThread);
376 m_hReceiverThread = INVALID_THREAD_HANDLE;
377
378 // Check if we need to close existing socket
379 if (m_hSocket != -1)
380 closesocket(m_hSocket);
381
382 // Create socket
383 m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
384 if (m_hSocket == -1)
385 {
386 PrintMsg(_T("Call to socket() failed"));
387 goto connect_cleanup;
388 }
389
390 // Fill in address structure
391 memset(&sa, 0, sizeof(sa));
392 sa.sin_family = AF_INET;
393 if (m_bUseProxy)
394 {
395 sa.sin_addr.s_addr = m_dwProxyAddr;
396 sa.sin_port = htons(m_wProxyPort);
397 }
398 else
399 {
400 sa.sin_addr.s_addr = m_dwAddr;
401 sa.sin_port = htons(m_wPort);
402 }
403
404 // Connect to server
405 if (connect(m_hSocket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
406 {
407 if (bVerbose)
408 PrintMsg(_T("Cannot establish connection with agent %s"),
409 IpToStr(ntohl(m_bUseProxy ? m_dwProxyAddr : m_dwAddr), szBuffer));
410 dwError = ERR_CONNECT_FAILED;
411 goto connect_cleanup;
412 }
413
414 // Set non-blocking mode
415 SetSocketNonBlocking(m_hSocket);
416
417 if (!NXCPGetPeerProtocolVersion(m_hSocket, &m_nProtocolVersion))
418 {
419 dwError = ERR_INTERNAL_ERROR;
420 goto connect_cleanup;
421 }
422
423 // Start receiver thread
424 m_hReceiverThread = ThreadCreateEx(ReceiverThreadStarter, 0, this);
425
426 // Setup encryption
427setup_encryption:
428 if ((m_iEncryptionPolicy == ENCRYPTION_PREFERRED) ||
429 (m_iEncryptionPolicy == ENCRYPTION_REQUIRED) ||
430 (bForceEncryption)) // Agent require encryption
431 {
432 if (pServerKey != NULL)
433 {
434 dwError = SetupEncryption(pServerKey);
435 if ((dwError != ERR_SUCCESS) &&
436 ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption))
437 goto connect_cleanup;
438 }
439 else
440 {
441 if ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption)
442 {
443 dwError = ERR_ENCRYPTION_REQUIRED;
444 goto connect_cleanup;
445 }
446 }
447 }
448
449 // Authenticate itself to agent
450 if ((dwError = Authenticate(m_bUseProxy && !bSecondPass)) != ERR_SUCCESS)
451 {
452 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
453 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
454 {
455 bForceEncryption = TRUE;
456 goto setup_encryption;
457 }
458 PrintMsg(_T("Authentication to agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
459 AgentErrorCodeToText(dwError));
460 goto connect_cleanup;
461 }
462
463 // Test connectivity
45d84f8a 464 if ((dwError = nop()) != ERR_SUCCESS)
5039dede
AK
465 {
466 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
467 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
468 {
469 bForceEncryption = TRUE;
470 goto setup_encryption;
471 }
472 PrintMsg(_T("Communication with agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
473 AgentErrorCodeToText(dwError));
474 goto connect_cleanup;
475 }
476
477 if (m_bUseProxy && !bSecondPass)
478 {
479 dwError = SetupProxyConnection();
480 if (dwError != ERR_SUCCESS)
481 goto connect_cleanup;
482 DestroyEncryptionContext(m_pCtx);
483 m_pCtx = NULL;
484 bSecondPass = TRUE;
485 bForceEncryption = FALSE;
486 goto setup_encryption;
487 }
488
489 bSuccess = TRUE;
490 dwError = ERR_SUCCESS;
491
492connect_cleanup:
493 if (!bSuccess)
494 {
495 Lock();
496 if (m_hSocket != -1)
497 shutdown(m_hSocket, SHUT_RDWR);
498 Unlock();
499 ThreadJoin(m_hReceiverThread);
500 m_hReceiverThread = INVALID_THREAD_HANDLE;
501
502 Lock();
503 if (m_hSocket != -1)
504 {
505 closesocket(m_hSocket);
506 m_hSocket = -1;
507 }
508
509 DestroyEncryptionContext(m_pCtx);
510 m_pCtx = NULL;
511
512 Unlock();
513 }
514 m_bIsConnected = bSuccess;
515 if (pdwError != NULL)
516 *pdwError = dwError;
517 return bSuccess;
518}
519
520
521//
522// Disconnect from agent
523//
524
525void AgentConnection::Disconnect(void)
526{
527 Lock();
f2665675
VK
528 if (m_hCurrFile != -1)
529 {
530 close(m_hCurrFile);
531 m_hCurrFile = -1;
532 OnFileDownload(FALSE);
533 }
534
5039dede
AK
535 if (m_hSocket != -1)
536 {
537 shutdown(m_hSocket, SHUT_RDWR);
538 }
539 DestroyResultData();
540 m_bIsConnected = FALSE;
541 Unlock();
542}
543
544
545//
546// Destroy command execuion results data
547//
548
549void AgentConnection::DestroyResultData(void)
550{
551 DWORD i;
552
553 if (m_ppDataLines != NULL)
554 {
555 for(i = 0; i < m_dwNumDataLines; i++)
556 if (m_ppDataLines[i] != NULL)
557 free(m_ppDataLines[i]);
558 free(m_ppDataLines);
559 m_ppDataLines = NULL;
560 }
561 m_dwNumDataLines = 0;
562}
563
564
565//
566// Get interface list from agent
567//
568
569INTERFACE_LIST *AgentConnection::GetInterfaceList(void)
570{
571 INTERFACE_LIST *pIfList = NULL;
572 DWORD i, dwBits;
573 TCHAR *pChar, *pBuf;
574
575 if (GetList(_T("Net.InterfaceList")) == ERR_SUCCESS)
576 {
577 pIfList = (INTERFACE_LIST *)malloc(sizeof(INTERFACE_LIST));
578 pIfList->iNumEntries = m_dwNumDataLines;
579 pIfList->pInterfaces = (INTERFACE_INFO *)malloc(sizeof(INTERFACE_INFO) * m_dwNumDataLines);
580 memset(pIfList->pInterfaces, 0, sizeof(INTERFACE_INFO) * m_dwNumDataLines);
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];
587
588 // Index
589 pChar = _tcschr(pBuf, ' ');
590 if (pChar != NULL)
591 {
592 *pChar = 0;
593 pIfList->pInterfaces[i].dwIndex = _tcstoul(pBuf, NULL, 10);
594 pBuf = pChar + 1;
595 }
596
597 // Address and mask
598 pChar = _tcschr(pBuf, _T(' '));
599 if (pChar != NULL)
600 {
601 TCHAR *pSlash;
602 static TCHAR defaultMask[] = _T("24");
603
604 *pChar = 0;
605 pSlash = _tcschr(pBuf, _T('/'));
606 if (pSlash != NULL)
607 {
608 *pSlash = 0;
609 pSlash++;
610 }
611 else // Just a paranoia protection, should'n happen if agent working correctly
612 {
613 pSlash = defaultMask;
614 }
615 pIfList->pInterfaces[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
616 dwBits = _tcstoul(pSlash, NULL, 10);
617 pIfList->pInterfaces[i].dwIpNetMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
618 pBuf = pChar + 1;
619 }
620
621 // Interface type
622 pChar = _tcschr(pBuf, ' ');
623 if (pChar != NULL)
624 {
625 *pChar = 0;
626 pIfList->pInterfaces[i].dwType = _tcstoul(pBuf, NULL, 10);
627 pBuf = pChar + 1;
628 }
629
630 // MAC address
631 pChar = _tcschr(pBuf, ' ');
632 if (pChar != NULL)
633 {
634 *pChar = 0;
635 StrToBin(pBuf, pIfList->pInterfaces[i].bMacAddr, MAC_ADDR_LENGTH);
636 pBuf = pChar + 1;
637 }
638
639 // Name
640 nx_strncpy(pIfList->pInterfaces[i].szName, pBuf, MAX_OBJECT_NAME - 1);
641 }
642
643 Lock();
644 DestroyResultData();
645 Unlock();
646 }
647
648 return pIfList;
649}
650
651
652//
653// Get parameter value
654//
655
656DWORD AgentConnection::GetParameter(const TCHAR *pszParam, DWORD dwBufSize, TCHAR *pszBuffer)
657{
658 CSCPMessage msg(m_nProtocolVersion), *pResponse;
659 DWORD dwRqId, dwRetCode;
660
661 if (m_bIsConnected)
662 {
663 dwRqId = m_dwRequestId++;
664 msg.SetCode(CMD_GET_PARAMETER);
665 msg.SetId(dwRqId);
666 msg.SetVariable(VID_PARAMETER, pszParam);
667 if (SendMessage(&msg))
668 {
669 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
670 if (pResponse != NULL)
671 {
672 dwRetCode = pResponse->GetVariableLong(VID_RCC);
673 if (dwRetCode == ERR_SUCCESS)
674 pResponse->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
675 delete pResponse;
676 }
677 else
678 {
679 dwRetCode = ERR_REQUEST_TIMEOUT;
680 }
681 }
682 else
683 {
684 dwRetCode = ERR_CONNECTION_BROKEN;
685 }
686 }
687 else
688 {
689 dwRetCode = ERR_NOT_CONNECTED;
690 }
691
692 return dwRetCode;
693}
694
695
696//
697// Get ARP cache
698//
699
700ARP_CACHE *AgentConnection::GetArpCache(void)
701{
702 ARP_CACHE *pArpCache = NULL;
703 TCHAR szByte[4], *pBuf, *pChar;
704 DWORD i, j;
705
706 if (GetList(_T("Net.ArpCache")) == ERR_SUCCESS)
707 {
708 // Create empty structure
709 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
710 pArpCache->dwNumEntries = m_dwNumDataLines;
711 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
712 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
713
714 szByte[2] = 0;
715
716 // Parse data lines
717 // Each line has form of XXXXXXXXXXXX a.b.c.d n
718 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
719 // a.b.c.d is an IP address in decimal dotted notation
720 // n is an interface index
721 for(i = 0; i < m_dwNumDataLines; i++)
722 {
723 pBuf = m_ppDataLines[i];
724 if (_tcslen(pBuf) < 20) // Invalid line
725 continue;
726
727 // MAC address
728 for(j = 0; j < 6; j++)
729 {
730 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
731 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
732 pBuf+=2;
733 }
734
735 // IP address
736 while(*pBuf == ' ')
737 pBuf++;
738 pChar = _tcschr(pBuf, _T(' '));
739 if (pChar != NULL)
740 *pChar = 0;
741 pArpCache->pEntries[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
742
743 // Interface index
744 if (pChar != NULL)
745 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
746 }
747
748 Lock();
749 DestroyResultData();
750 Unlock();
751 }
752 return pArpCache;
753}
754
755
756//
757// Send dummy command to agent (can be used for keepalive)
758//
759
45d84f8a 760DWORD AgentConnection::nop(void)
5039dede
AK
761{
762 CSCPMessage msg(m_nProtocolVersion);
763 DWORD dwRqId;
764
765 dwRqId = m_dwRequestId++;
766 msg.SetCode(CMD_KEEPALIVE);
767 msg.SetId(dwRqId);
768 if (SendMessage(&msg))
769 return WaitForRCC(dwRqId, m_dwCommandTimeout);
770 else
771 return ERR_CONNECTION_BROKEN;
772}
773
774
775//
776// Wait for request completion code
777//
778
779DWORD AgentConnection::WaitForRCC(DWORD dwRqId, DWORD dwTimeOut)
780{
781 CSCPMessage *pMsg;
782 DWORD dwRetCode;
783
784 pMsg = m_pMsgWaitQueue->WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
785 if (pMsg != NULL)
786 {
787 dwRetCode = pMsg->GetVariableLong(VID_RCC);
788 delete pMsg;
789 }
790 else
791 {
792 dwRetCode = ERR_REQUEST_TIMEOUT;
793 }
794 return dwRetCode;
795}
796
797
798//
799// Send message to agent
800//
801
802BOOL AgentConnection::SendMessage(CSCPMessage *pMsg)
803{
804 CSCP_MESSAGE *pRawMsg;
805 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
806 BOOL bResult;
807
808 pRawMsg = pMsg->CreateMessage();
809 if (m_pCtx != NULL)
810 {
811 pEnMsg = CSCPEncryptMessage(m_pCtx, pRawMsg);
812 if (pEnMsg != NULL)
813 {
814 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) == (int)ntohl(pEnMsg->dwSize));
815 free(pEnMsg);
816 }
817 else
818 {
819 bResult = FALSE;
820 }
821 }
822 else
823 {
824 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
825 }
826 free(pRawMsg);
827 return bResult;
828}
829
830
831//
832// Trap handler. Should be overriden in derived classes to implement
833// actual trap processing. Default implementation do nothing.
834//
835
836void AgentConnection::OnTrap(CSCPMessage *pMsg)
837{
838}
839
840
841//
842// Get list of values
843//
844
845DWORD AgentConnection::GetList(const TCHAR *pszParam)
846{
847 CSCPMessage msg(m_nProtocolVersion), *pResponse;
848 DWORD i, dwRqId, dwRetCode;
849
850 if (m_bIsConnected)
851 {
852 DestroyResultData();
853 dwRqId = m_dwRequestId++;
854 msg.SetCode(CMD_GET_LIST);
855 msg.SetId(dwRqId);
856 msg.SetVariable(VID_PARAMETER, pszParam);
857 if (SendMessage(&msg))
858 {
859 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
860 if (pResponse != NULL)
861 {
862 dwRetCode = pResponse->GetVariableLong(VID_RCC);
863 if (dwRetCode == ERR_SUCCESS)
864 {
865 m_dwNumDataLines = pResponse->GetVariableLong(VID_NUM_STRINGS);
866 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
867 for(i = 0; i < m_dwNumDataLines; i++)
868 m_ppDataLines[i] = pResponse->GetVariableStr(VID_ENUM_VALUE_BASE + i);
869 }
870 delete pResponse;
871 }
872 else
873 {
874 dwRetCode = ERR_REQUEST_TIMEOUT;
875 }
876 }
877 else
878 {
879 dwRetCode = ERR_CONNECTION_BROKEN;
880 }
881 }
882 else
883 {
884 dwRetCode = ERR_NOT_CONNECTED;
885 }
886
887 return dwRetCode;
888}
889
890
891//
892// Authenticate to agent
893//
894
895DWORD AgentConnection::Authenticate(BOOL bProxyData)
896{
897 CSCPMessage msg(m_nProtocolVersion);
898 DWORD dwRqId;
899 BYTE hash[32];
900 int iAuthMethod = bProxyData ? m_iProxyAuth : m_iAuthMethod;
901 char *pszSecret = bProxyData ? m_szProxySecret : m_szSecret;
902#ifdef UNICODE
903 WCHAR szBuffer[MAX_SECRET_LENGTH];
904#endif
905
906 if (iAuthMethod == AUTH_NONE)
907 return ERR_SUCCESS; // No authentication required
908
909 dwRqId = m_dwRequestId++;
910 msg.SetCode(CMD_AUTHENTICATE);
911 msg.SetId(dwRqId);
912 msg.SetVariable(VID_AUTH_METHOD, (WORD)iAuthMethod);
913 switch(iAuthMethod)
914 {
915 case AUTH_PLAINTEXT:
916#ifdef UNICODE
917 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszSecret, -1, szBuffer, MAX_SECRET_LENGTH);
918 msg.SetVariable(VID_SHARED_SECRET, szBuffer);
919#else
920 msg.SetVariable(VID_SHARED_SECRET, pszSecret);
921#endif
922 break;
923 case AUTH_MD5_HASH:
924 CalculateMD5Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
925 msg.SetVariable(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
926 break;
927 case AUTH_SHA1_HASH:
928 CalculateSHA1Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
929 msg.SetVariable(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
930 break;
931 default:
932 break;
933 }
934 if (SendMessage(&msg))
935 return WaitForRCC(dwRqId, m_dwCommandTimeout);
936 else
937 return ERR_CONNECTION_BROKEN;
938}
939
940
941//
942// Execute action on agent
943//
944
945DWORD AgentConnection::ExecAction(const TCHAR *pszAction, int argc, TCHAR **argv)
946{
947 CSCPMessage msg(m_nProtocolVersion);
948 DWORD dwRqId;
949 int i;
950
951 if (!m_bIsConnected)
952 return ERR_NOT_CONNECTED;
953
954 dwRqId = m_dwRequestId++;
955 msg.SetCode(CMD_ACTION);
956 msg.SetId(dwRqId);
957 msg.SetVariable(VID_ACTION_NAME, pszAction);
958 msg.SetVariable(VID_NUM_ARGS, (DWORD)argc);
959 for(i = 0; i < argc; i++)
960 msg.SetVariable(VID_ACTION_ARG_BASE + i, argv[i]);
961
962 if (SendMessage(&msg))
963 return WaitForRCC(dwRqId, m_dwCommandTimeout);
964 else
965 return ERR_CONNECTION_BROKEN;
966}
967
968
969//
970// Upload file to agent
971//
972
6173bea8 973DWORD AgentConnection::UploadFile(const TCHAR *pszFile, void (* progressCallback)(INT64, void *), void *cbArg)
5039dede
AK
974{
975 DWORD dwRqId, dwResult;
976 CSCPMessage msg(m_nProtocolVersion);
977 int i;
978
979 if (!m_bIsConnected)
980 return ERR_NOT_CONNECTED;
981
982 dwRqId = m_dwRequestId++;
983
984 msg.SetCode(CMD_TRANSFER_FILE);
985 msg.SetId(dwRqId);
986 for(i = (int)_tcslen(pszFile) - 1;
987 (i >= 0) && (pszFile[i] != '\\') && (pszFile[i] != '/'); i--);
988 msg.SetVariable(VID_FILE_NAME, &pszFile[i + 1]);
989
990 if (SendMessage(&msg))
991 {
992 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
993 }
994 else
995 {
996 dwResult = ERR_CONNECTION_BROKEN;
997 }
998
999 if (dwResult == ERR_SUCCESS)
1000 {
6173bea8 1001 if (SendFileOverNXCP(m_hSocket, dwRqId, pszFile, m_pCtx, 0, progressCallback, cbArg))
5039dede
AK
1002 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
1003 else
1004 dwResult = ERR_IO_FAILURE;
1005 }
1006
1007 return dwResult;
1008}
1009
1010
1011//
1012// Send upgrade command
1013//
1014
1015DWORD AgentConnection::StartUpgrade(const TCHAR *pszPkgName)
1016{
1017 DWORD dwRqId, dwResult;
1018 CSCPMessage msg(m_nProtocolVersion);
1019 int i;
1020
1021 if (!m_bIsConnected)
1022 return ERR_NOT_CONNECTED;
1023
1024 dwRqId = m_dwRequestId++;
1025
1026 msg.SetCode(CMD_UPGRADE_AGENT);
1027 msg.SetId(dwRqId);
1028 for(i = (int)_tcslen(pszPkgName) - 1;
1029 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
1030 msg.SetVariable(VID_FILE_NAME, &pszPkgName[i + 1]);
1031
1032 if (SendMessage(&msg))
1033 {
1034 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
1035 }
1036 else
1037 {
1038 dwResult = ERR_CONNECTION_BROKEN;
1039 }
1040
1041 return dwResult;
1042}
1043
1044
1045//
1046// Check status of network service via agent
1047//
1048
1049DWORD AgentConnection::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
1050 WORD wPort, WORD wProto,
1051 const TCHAR *pszRequest, const TCHAR *pszResponse)
1052{
1053 DWORD dwRqId, dwResult;
1054 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1055 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80 };
1056
1057 if (!m_bIsConnected)
1058 return ERR_NOT_CONNECTED;
1059
1060 dwRqId = m_dwRequestId++;
1061
1062 msg.SetCode(CMD_CHECK_NETWORK_SERVICE);
1063 msg.SetId(dwRqId);
1064 msg.SetVariable(VID_IP_ADDRESS, dwIpAddr);
1065 msg.SetVariable(VID_SERVICE_TYPE, (WORD)iServiceType);
1066 msg.SetVariable(VID_IP_PORT,
1067 (wPort != 0) ? wPort :
1068 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
1069 (iServiceType <= NETSRV_HTTP)) ? iServiceType : 0]);
1070 msg.SetVariable(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
1071 msg.SetVariable(VID_SERVICE_REQUEST, pszRequest);
1072 msg.SetVariable(VID_SERVICE_RESPONSE, pszResponse);
1073
1074 if (SendMessage(&msg))
1075 {
1076 // Wait up to 90 seconds for results
1077 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
1078 if (pResponse != NULL)
1079 {
1080 dwResult = pResponse->GetVariableLong(VID_RCC);
1081 if (dwResult == ERR_SUCCESS)
1082 {
1083 *pdwStatus = pResponse->GetVariableLong(VID_SERVICE_STATUS);
1084 }
1085 delete pResponse;
1086 }
1087 else
1088 {
1089 dwResult = ERR_REQUEST_TIMEOUT;
1090 }
1091 }
1092 else
1093 {
1094 dwResult = ERR_CONNECTION_BROKEN;
1095 }
1096
1097 return dwResult;
1098}
1099
1100
1101//
1102// Get list of supported parameters from subagent
1103//
1104
1105DWORD AgentConnection::GetSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
1106{
1107 DWORD i, dwId, dwRqId, dwResult;
1108 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1109
1110 *pdwNumParams = 0;
1111 *ppParamList = NULL;
1112
1113 if (!m_bIsConnected)
1114 return ERR_NOT_CONNECTED;
1115
1116 dwRqId = m_dwRequestId++;
1117
1118 msg.SetCode(CMD_GET_PARAMETER_LIST);
1119 msg.SetId(dwRqId);
1120
1121 if (SendMessage(&msg))
1122 {
1123 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1124 if (pResponse != NULL)
1125 {
1126 dwResult = pResponse->GetVariableLong(VID_RCC);
1127 DbgPrintf(6, _T("AgentConnection::GetSupportedParameters(): RCC=%d"), dwResult);
1128 if (dwResult == ERR_SUCCESS)
1129 {
1130 *pdwNumParams = pResponse->GetVariableLong(VID_NUM_PARAMETERS);
1131 *ppParamList = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * (*pdwNumParams));
1132 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < *pdwNumParams; i++)
1133 {
1134 pResponse->GetVariableStr(dwId++, (*ppParamList)[i].szName, MAX_PARAM_NAME);
1135 pResponse->GetVariableStr(dwId++, (*ppParamList)[i].szDescription, MAX_DB_STRING);
1136 (*ppParamList)[i].iDataType = (int)pResponse->GetVariableShort(dwId++);
1137 }
1138 DbgPrintf(6, _T("AgentConnection::GetSupportedParameters(): %d parameters received from agent"), *pdwNumParams);
1139 }
1140 delete pResponse;
1141 }
1142 else
1143 {
1144 dwResult = ERR_REQUEST_TIMEOUT;
1145 }
1146 }
1147 else
1148 {
1149 dwResult = ERR_CONNECTION_BROKEN;
1150 }
1151
1152 return dwResult;
1153}
1154
1155
1156//
1157// Setup encryption
1158//
1159
1160DWORD AgentConnection::SetupEncryption(RSA *pServerKey)
1161{
1162#ifdef _WITH_ENCRYPTION
1163 CSCPMessage msg(m_nProtocolVersion), *pResp;
1164 DWORD dwRqId, dwError, dwResult;
1165
1166 dwRqId = m_dwRequestId++;
1167
1168 PrepareKeyRequestMsg(&msg, pServerKey);
1169 msg.SetId(dwRqId);
1170 if (SendMessage(&msg))
1171 {
1172 pResp = WaitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
1173 if (pResp != NULL)
1174 {
1175 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey, m_nProtocolVersion);
1176 switch(dwResult)
1177 {
1178 case RCC_SUCCESS:
1179 dwError = ERR_SUCCESS;
1180 break;
1181 case RCC_NO_CIPHERS:
1182 dwError = ERR_NO_CIPHERS;
1183 break;
1184 case RCC_INVALID_PUBLIC_KEY:
1185 dwError = ERR_INVALID_PUBLIC_KEY;
1186 break;
1187 case RCC_INVALID_SESSION_KEY:
1188 dwError = ERR_INVALID_SESSION_KEY;
1189 break;
1190 default:
1191 dwError = ERR_INTERNAL_ERROR;
1192 break;
1193 }
1194 delete pResp;
1195 }
1196 else
1197 {
1198 dwError = ERR_REQUEST_TIMEOUT;
1199 }
1200 }
1201 else
1202 {
1203 dwError = ERR_CONNECTION_BROKEN;
1204 }
1205
1206 return dwError;
1207#else
1208 return ERR_NOT_IMPLEMENTED;
1209#endif
1210}
1211
1212
1213//
1214// Get configuration file from agent
1215//
1216
1217DWORD AgentConnection::GetConfigFile(TCHAR **ppszConfig, DWORD *pdwSize)
1218{
1219 DWORD i, dwRqId, dwResult;
1220 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1221#ifdef UNICODE
1222 BYTE *pBuffer;
1223#endif
1224
1225 *ppszConfig = NULL;
1226 *pdwSize = 0;
1227
1228 if (!m_bIsConnected)
1229 return ERR_NOT_CONNECTED;
1230
1231 dwRqId = m_dwRequestId++;
1232
1233 msg.SetCode(CMD_GET_AGENT_CONFIG);
1234 msg.SetId(dwRqId);
1235
1236 if (SendMessage(&msg))
1237 {
1238 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1239 if (pResponse != NULL)
1240 {
1241 dwResult = pResponse->GetVariableLong(VID_RCC);
1242 if (dwResult == ERR_SUCCESS)
1243 {
1244 *pdwSize = pResponse->GetVariableBinary(VID_CONFIG_FILE, NULL, 0);
1245 *ppszConfig = (TCHAR *)malloc((*pdwSize + 1) * sizeof(TCHAR));
1246#ifdef UNICODE
1247 pBuffer = (BYTE *)malloc(*pdwSize + 1);
1248 pResponse->GetVariableBinary(VID_CONFIG_FILE, pBuffer, *pdwSize);
1249 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pBuffer, *pdwSize, *ppszConfig, *pdwSize);
1250 free(pBuffer);
1251#else
1252 pResponse->GetVariableBinary(VID_CONFIG_FILE, (BYTE *)(*ppszConfig), *pdwSize);
1253#endif
1254 (*ppszConfig)[*pdwSize] = 0;
1255
1256 // We expect text file, so replace all non-printable characters with spaces
1257 for(i = 0; i < *pdwSize; i++)
1258 if (((*ppszConfig)[i] < _T(' ')) &&
1259 ((*ppszConfig)[i] != _T('\t')) &&
1260 ((*ppszConfig)[i] != _T('\r')) &&
1261 ((*ppszConfig)[i] != _T('\n')))
1262 (*ppszConfig)[i] = _T(' ');
1263 }
1264 delete pResponse;
1265 }
1266 else
1267 {
1268 dwResult = ERR_REQUEST_TIMEOUT;
1269 }
1270 }
1271 else
1272 {
1273 dwResult = ERR_CONNECTION_BROKEN;
1274 }
1275
1276 return dwResult;
1277}
1278
1279
1280//
1281// Get configuration file from agent
1282//
1283
45d84f8a 1284DWORD AgentConnection::updateConfigFile(const TCHAR *pszConfig)
5039dede
AK
1285{
1286 DWORD dwRqId, dwResult;
1287 CSCPMessage msg(m_nProtocolVersion);
1288#ifdef UNICODE
1289 int nChars;
1290 BYTE *pBuffer;
1291#endif
1292
1293 if (!m_bIsConnected)
1294 return ERR_NOT_CONNECTED;
1295
1296 dwRqId = m_dwRequestId++;
1297
1298 msg.SetCode(CMD_UPDATE_AGENT_CONFIG);
1299 msg.SetId(dwRqId);
1300#ifdef UNICODE
1301 nChars = _tcslen(pszConfig);
1302 pBuffer = (BYTE *)malloc(nChars + 1);
1303 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1304 pszConfig, nChars, pBuffer, nChars + 1, NULL, NULL);
1305 msg.SetVariable(VID_CONFIG_FILE, pBuffer, nChars);
1306 free(pBuffer);
1307#else
1308 msg.SetVariable(VID_CONFIG_FILE, (BYTE *)pszConfig, (DWORD)strlen(pszConfig));
1309#endif
1310
1311 if (SendMessage(&msg))
1312 {
1313 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
1314 }
1315 else
1316 {
1317 dwResult = ERR_CONNECTION_BROKEN;
1318 }
1319
1320 return dwResult;
1321}
1322
1323
1324//
1325// Get routing table from agent
1326//
1327
1328ROUTING_TABLE *AgentConnection::GetRoutingTable(void)
1329{
1330 ROUTING_TABLE *pRT = NULL;
1331 DWORD i, dwBits;
1332 TCHAR *pChar, *pBuf;
1333
1334 if (GetList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS)
1335 {
1336 pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
1337 pRT->iNumEntries = m_dwNumDataLines;
1338 pRT->pRoutes = (ROUTE *)malloc(sizeof(ROUTE) * m_dwNumDataLines);
1339 memset(pRT->pRoutes, 0, sizeof(ROUTE) * m_dwNumDataLines);
1340 for(i = 0; i < m_dwNumDataLines; i++)
1341 {
1342 pBuf = m_ppDataLines[i];
1343
1344 // Destination address and mask
1345 pChar = _tcschr(pBuf, _T(' '));
1346 if (pChar != NULL)
1347 {
1348 TCHAR *pSlash;
1349 static TCHAR defaultMask[] = _T("24");
1350
1351 *pChar = 0;
1352 pSlash = _tcschr(pBuf, _T('/'));
1353 if (pSlash != NULL)
1354 {
1355 *pSlash = 0;
1356 pSlash++;
1357 }
1358 else // Just a paranoia protection, should'n happen if agent working correctly
1359 {
1360 pSlash = defaultMask;
1361 }
1362 pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
1363 dwBits = _tcstoul(pSlash, NULL, 10);
1364 pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
1365 pBuf = pChar + 1;
1366 }
1367
1368 // Next hop address
1369 pChar = _tcschr(pBuf, _T(' '));
1370 if (pChar != NULL)
1371 {
1372 *pChar = 0;
1373 pRT->pRoutes[i].dwNextHop = ntohl(_t_inet_addr(pBuf));
1374 pBuf = pChar + 1;
1375 }
1376
1377 // Interface index
1378 pChar = _tcschr(pBuf, ' ');
1379 if (pChar != NULL)
1380 {
1381 *pChar = 0;
1382 pRT->pRoutes[i].dwIfIndex = _tcstoul(pBuf, NULL, 10);
1383 pBuf = pChar + 1;
1384 }
1385
1386 // Route type
1387 pRT->pRoutes[i].dwRouteType = _tcstoul(pBuf, NULL, 10);
1388 }
1389
1390 Lock();
1391 DestroyResultData();
1392 Unlock();
1393 }
1394
1395 return pRT;
1396}
1397
1398
1399//
1400// Set proxy information
1401//
1402
1403void AgentConnection::SetProxy(DWORD dwAddr, WORD wPort, int iAuthMethod, const TCHAR *pszSecret)
1404{
1405 m_dwProxyAddr = dwAddr;
1406 m_wProxyPort = wPort;
1407 m_iProxyAuth = iAuthMethod;
1408 if (pszSecret != NULL)
1409 {
1410#ifdef UNICODE
1411 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1412 pszSecret, -1, m_szProxySecret, MAX_SECRET_LENGTH, NULL, NULL);
1413#else
1414 nx_strncpy(m_szProxySecret, pszSecret, MAX_SECRET_LENGTH);
1415#endif
1416 }
1417 else
1418 {
1419 m_szProxySecret[0] = 0;
1420 }
1421 m_bUseProxy = TRUE;
1422}
1423
1424
1425//
1426// Setup proxy connection
1427//
1428
1429DWORD AgentConnection::SetupProxyConnection(void)
1430{
1431 CSCPMessage msg(m_nProtocolVersion);
1432 DWORD dwRqId;
1433
1434 dwRqId = m_dwRequestId++;
1435 msg.SetCode(CMD_SETUP_PROXY_CONNECTION);
1436 msg.SetId(dwRqId);
1437 msg.SetVariable(VID_IP_ADDRESS, (DWORD)ntohl(m_dwAddr));
1438 msg.SetVariable(VID_AGENT_PORT, m_wPort);
1439 if (SendMessage(&msg))
1440 return WaitForRCC(dwRqId, 60000); // Wait 60 seconds for remote connect
1441 else
1442 return ERR_CONNECTION_BROKEN;
1443}
1444
1445
1446//
1447// Enable trap receiving on connection
1448//
1449
45d84f8a 1450DWORD AgentConnection::enableTraps(void)
5039dede
AK
1451{
1452 CSCPMessage msg(m_nProtocolVersion);
1453 DWORD dwRqId;
1454
1455 dwRqId = m_dwRequestId++;
1456 msg.SetCode(CMD_ENABLE_AGENT_TRAPS);
1457 msg.SetId(dwRqId);
1458 if (SendMessage(&msg))
1459 return WaitForRCC(dwRqId, m_dwCommandTimeout);
1460 else
1461 return ERR_CONNECTION_BROKEN;
1462}
1463
1464
1465//
1466// Send custom request to agent
1467//
1468
45d84f8a 1469CSCPMessage *AgentConnection::customRequest(CSCPMessage *pRequest, const TCHAR *recvFile, bool appendFile,
bb85e341 1470 void (*downloadProgressCallback)(size_t, void *), void *cbArg)
5039dede
AK
1471{
1472 DWORD dwRqId, rcc;
1473 CSCPMessage *msg = NULL;
1474
1475 dwRqId = m_dwRequestId++;
1476 pRequest->SetId(dwRqId);
1477 if (recvFile != NULL)
1478 {
f2665675 1479 rcc = PrepareFileDownload(recvFile, dwRqId, appendFile, downloadProgressCallback, cbArg);
5039dede
AK
1480 if (rcc != ERR_SUCCESS)
1481 {
1482 // Create fake response message
1483 msg = new CSCPMessage;
1484 msg->SetCode(CMD_REQUEST_COMPLETED);
1485 msg->SetId(dwRqId);
1486 msg->SetVariable(VID_RCC, rcc);
1487 }
1488 }
1489
1490 if (msg == NULL)
1491 {
1492 if (SendMessage(pRequest))
1493 {
1494 msg = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1495 if ((msg != NULL) && (recvFile != NULL))
1496 {
1497 if (msg->GetVariableLong(VID_RCC) == ERR_SUCCESS)
1498 {
bb85e341 1499 if (ConditionWait(m_condFileDownload, 1800000)) // 30 min timeout
5039dede 1500 {
bb85e341 1501 if (!m_fileDownloadSucceeded)
5039dede
AK
1502 {
1503 msg->SetVariable(VID_RCC, ERR_IO_FAILURE);
901a5a9b
VK
1504 if (m_deleteFileOnDownloadFailure)
1505 remove(recvFile);
5039dede
AK
1506 }
1507 }
1508 else
1509 {
1510 msg->SetVariable(VID_RCC, ERR_REQUEST_TIMEOUT);
1511 }
1512 }
1513 else
1514 {
1515 close(m_hCurrFile);
1516 m_hCurrFile = -1;
1517 remove(recvFile);
1518 }
1519 }
1520 }
1521 }
1522
1523 return msg;
1524}
1525
1526
1527//
1528// Prepare for file upload
1529//
1530
f2665675 1531DWORD AgentConnection::PrepareFileDownload(const TCHAR *fileName, DWORD rqId, bool append,
bb85e341 1532 void (*downloadProgressCallback)(size_t, void *), void *cbArg)
5039dede
AK
1533{
1534 if (m_hCurrFile != -1)
1535 return ERR_RESOURCE_BUSY;
1536
9f6d453a 1537 nx_strncpy(m_currentFileName, fileName, MAX_PATH);
bb85e341 1538 ConditionReset(m_condFileDownload);
901a5a9b
VK
1539 m_hCurrFile = open(fileName, (append ? 0 : (O_CREAT | O_TRUNC)) | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
1540 if (m_hCurrFile == -1)
1541 {
1542 DbgPrintf(4, _T("AgentConnection::PrepareFileDownload(): cannot open file %s (%s); append=%d rqId=%d"),
1543 fileName, _tcserror(errno), append, rqId);
1544 }
1545 else
1546 {
1547 if (append)
1548 lseek(m_hCurrFile, 0, SEEK_END);
1549 }
bb85e341
VK
1550 m_dwDownloadRequestId = rqId;
1551 m_downloadProgressCallback = downloadProgressCallback;
1552 m_downloadProgressCallbackArg = cbArg;
5039dede
AK
1553 return (m_hCurrFile != -1) ? ERR_SUCCESS : ERR_FILE_OPEN_ERROR;
1554}
1555
1556
1557//
1558// File upload completion handler
1559//
1560
bb85e341 1561void AgentConnection::OnFileDownload(BOOL success)
5039dede 1562{
901a5a9b
VK
1563 if (!success && m_deleteFileOnDownloadFailure)
1564 _tremove(m_currentFileName);
bb85e341
VK
1565 m_fileDownloadSucceeded = success;
1566 ConditionSet(m_condFileDownload);
5039dede 1567}