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