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