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