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