implemented waitForFile() API
[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;
101 m_condFileUpload = ConditionCreate(TRUE);
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;
144 m_condFileUpload = ConditionCreate(TRUE);
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)
177 close(m_hCurrFile);
178
179 MutexDestroy(m_mutexDataLock);
180 ConditionDestroy(m_condFileUpload);
181}
182
183
184//
185// Print message. This function is virtual and can be overrided in
186// derived classes. Default implementation will print message to stdout.
187//
188
189void AgentConnection::PrintMsg(const TCHAR *pszFormat, ...)
190{
191 va_list args;
192
193 va_start(args, pszFormat);
194 _vtprintf(pszFormat, args);
195 va_end(args);
196 _tprintf(_T("\n"));
197}
198
199
200//
201// Receiver thread
202//
203
204void AgentConnection::ReceiverThread(void)
205{
206 CSCPMessage *pMsg;
207 CSCP_MESSAGE *pRawMsg;
208 CSCP_BUFFER *pMsgBuffer;
209 BYTE *pDecryptionBuffer = NULL;
210 int iErr;
211 TCHAR szBuffer[128], szIpAddr[16];
212 SOCKET nSocket;
213
214 // Initialize raw message receiving function
215 pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
216 RecvNXCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL, 0);
217
218 // Allocate space for raw message
219 pRawMsg = (CSCP_MESSAGE *)malloc(RECEIVER_BUFFER_SIZE);
220#ifdef _WITH_ENCRYPTION
221 pDecryptionBuffer = (BYTE *)malloc(RECEIVER_BUFFER_SIZE);
222#endif
223
224 // Message receiving loop
225 while(1)
226 {
227 // Receive raw message
228 Lock();
229 nSocket = m_hSocket;
230 Unlock();
231 if ((iErr = RecvNXCPMessage(nSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE,
232 &m_pCtx, pDecryptionBuffer, m_dwRecvTimeout)) <= 0)
233 {
234 DbgPrintf(6, _T("AgentConnection::ReceiverThread(): RecvNXCPMessage() failed: error=%d, socket_error=%d"), iErr, WSAGetLastError());
235 break;
236 }
237
238 // Check if we get too large message
239 if (iErr == 1)
240 {
241 PrintMsg(_T("Received too large message %s (%d bytes)"),
242 NXCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
243 ntohl(pRawMsg->dwSize));
244 continue;
245 }
246
247 // Check if we are unable to decrypt message
248 if (iErr == 2)
249 {
250 PrintMsg(_T("Unable to decrypt received message"));
251 continue;
252 }
253
254 // Check for timeout
255 if (iErr == 3)
256 {
257 PrintMsg(_T("Timed out waiting for message"));
258 break;
259 }
260
261 // Check that actual received packet size is equal to encoded in packet
262 if ((int)ntohl(pRawMsg->dwSize) != iErr)
263 {
264 PrintMsg(_T("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]"), ntohl(pRawMsg->dwSize), iErr);
265 continue; // Bad packet, wait for next
266 }
267
268 if (ntohs(pRawMsg->wFlags) & MF_BINARY)
269 {
270 // Convert message header to host format
271 pRawMsg->dwId = ntohl(pRawMsg->dwId);
272 pRawMsg->wCode = ntohs(pRawMsg->wCode);
273 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
274 DbgPrintf(6, "Received raw message %s from agent at %s",
275 NXCPMessageCodeName(pRawMsg->wCode, szBuffer), IpToStr(GetIpAddr(), szIpAddr));
276
277 if ((pRawMsg->wCode == CMD_FILE_DATA) &&
278 (m_hCurrFile != -1) && (pRawMsg->dwId == m_dwUploadRequestId))
279 {
280 if (write(m_hCurrFile, pRawMsg->df, pRawMsg->dwNumVars) == (int)pRawMsg->dwNumVars)
281 {
282 if (ntohs(pRawMsg->wFlags) & MF_END_OF_FILE)
283 {
284 close(m_hCurrFile);
285 m_hCurrFile = -1;
286
287 OnFileUpload(TRUE);
288 }
289 }
290 else
291 {
292 // I/O error
293 close(m_hCurrFile);
294 m_hCurrFile = -1;
295
296 OnFileUpload(FALSE);
297 }
298 }
299 }
300 else
301 {
302 // Create message object from raw message
303 pMsg = new CSCPMessage(pRawMsg, m_nProtocolVersion);
304 if (pMsg->GetCode() == CMD_TRAP)
305 {
306 OnTrap(pMsg);
307 delete pMsg;
308 }
309 else
310 {
311 m_pMsgWaitQueue->Put(pMsg);
312 }
313 }
314 }
315
316 // Close socket and mark connection as disconnected
317 Lock();
318 if (iErr == 0)
319 shutdown(m_hSocket, SHUT_RDWR);
320 closesocket(m_hSocket);
321 m_hSocket = -1;
322 DestroyEncryptionContext(m_pCtx);
323 m_pCtx = NULL;
324 m_bIsConnected = FALSE;
325 Unlock();
326
327 free(pRawMsg);
328 free(pMsgBuffer);
329#ifdef _WITH_ENCRYPTION
330 free(pDecryptionBuffer);
331#endif
332}
333
334
335//
336// Connect to agent
337//
338
339BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose, DWORD *pdwError)
340{
341 struct sockaddr_in sa;
342 TCHAR szBuffer[256];
343 BOOL bSuccess = FALSE, bForceEncryption = FALSE, bSecondPass = FALSE;
344 DWORD dwError = 0;
345
346 if (pdwError != NULL)
347 *pdwError = ERR_INTERNAL_ERROR;
348
349 // Check if already connected
350 if (m_bIsConnected)
351 return FALSE;
352
353 // Wait for receiver thread from previous connection, if any
354 ThreadJoin(m_hReceiverThread);
355 m_hReceiverThread = INVALID_THREAD_HANDLE;
356
357 // Check if we need to close existing socket
358 if (m_hSocket != -1)
359 closesocket(m_hSocket);
360
361 // Create socket
362 m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
363 if (m_hSocket == -1)
364 {
365 PrintMsg(_T("Call to socket() failed"));
366 goto connect_cleanup;
367 }
368
369 // Fill in address structure
370 memset(&sa, 0, sizeof(sa));
371 sa.sin_family = AF_INET;
372 if (m_bUseProxy)
373 {
374 sa.sin_addr.s_addr = m_dwProxyAddr;
375 sa.sin_port = htons(m_wProxyPort);
376 }
377 else
378 {
379 sa.sin_addr.s_addr = m_dwAddr;
380 sa.sin_port = htons(m_wPort);
381 }
382
383 // Connect to server
384 if (connect(m_hSocket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
385 {
386 if (bVerbose)
387 PrintMsg(_T("Cannot establish connection with agent %s"),
388 IpToStr(ntohl(m_bUseProxy ? m_dwProxyAddr : m_dwAddr), szBuffer));
389 dwError = ERR_CONNECT_FAILED;
390 goto connect_cleanup;
391 }
392
393 // Set non-blocking mode
394 SetSocketNonBlocking(m_hSocket);
395
396 if (!NXCPGetPeerProtocolVersion(m_hSocket, &m_nProtocolVersion))
397 {
398 dwError = ERR_INTERNAL_ERROR;
399 goto connect_cleanup;
400 }
401
402 // Start receiver thread
403 m_hReceiverThread = ThreadCreateEx(ReceiverThreadStarter, 0, this);
404
405 // Setup encryption
406setup_encryption:
407 if ((m_iEncryptionPolicy == ENCRYPTION_PREFERRED) ||
408 (m_iEncryptionPolicy == ENCRYPTION_REQUIRED) ||
409 (bForceEncryption)) // Agent require encryption
410 {
411 if (pServerKey != NULL)
412 {
413 dwError = SetupEncryption(pServerKey);
414 if ((dwError != ERR_SUCCESS) &&
415 ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption))
416 goto connect_cleanup;
417 }
418 else
419 {
420 if ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption)
421 {
422 dwError = ERR_ENCRYPTION_REQUIRED;
423 goto connect_cleanup;
424 }
425 }
426 }
427
428 // Authenticate itself to agent
429 if ((dwError = Authenticate(m_bUseProxy && !bSecondPass)) != ERR_SUCCESS)
430 {
431 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
432 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
433 {
434 bForceEncryption = TRUE;
435 goto setup_encryption;
436 }
437 PrintMsg(_T("Authentication to agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
438 AgentErrorCodeToText(dwError));
439 goto connect_cleanup;
440 }
441
442 // Test connectivity
443 if ((dwError = Nop()) != ERR_SUCCESS)
444 {
445 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
446 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
447 {
448 bForceEncryption = TRUE;
449 goto setup_encryption;
450 }
451 PrintMsg(_T("Communication with agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
452 AgentErrorCodeToText(dwError));
453 goto connect_cleanup;
454 }
455
456 if (m_bUseProxy && !bSecondPass)
457 {
458 dwError = SetupProxyConnection();
459 if (dwError != ERR_SUCCESS)
460 goto connect_cleanup;
461 DestroyEncryptionContext(m_pCtx);
462 m_pCtx = NULL;
463 bSecondPass = TRUE;
464 bForceEncryption = FALSE;
465 goto setup_encryption;
466 }
467
468 bSuccess = TRUE;
469 dwError = ERR_SUCCESS;
470
471connect_cleanup:
472 if (!bSuccess)
473 {
474 Lock();
475 if (m_hSocket != -1)
476 shutdown(m_hSocket, SHUT_RDWR);
477 Unlock();
478 ThreadJoin(m_hReceiverThread);
479 m_hReceiverThread = INVALID_THREAD_HANDLE;
480
481 Lock();
482 if (m_hSocket != -1)
483 {
484 closesocket(m_hSocket);
485 m_hSocket = -1;
486 }
487
488 DestroyEncryptionContext(m_pCtx);
489 m_pCtx = NULL;
490
491 Unlock();
492 }
493 m_bIsConnected = bSuccess;
494 if (pdwError != NULL)
495 *pdwError = dwError;
496 return bSuccess;
497}
498
499
500//
501// Disconnect from agent
502//
503
504void AgentConnection::Disconnect(void)
505{
506 Lock();
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
732DWORD AgentConnection::Nop(void)
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
945DWORD AgentConnection::UploadFile(const TCHAR *pszFile)
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 {
973 if (SendFileOverNXCP(m_hSocket, dwRqId, pszFile, m_pCtx))
974 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
975 else
976 dwResult = ERR_IO_FAILURE;
977 }
978
979 return dwResult;
980}
981
982
983//
984// Send upgrade command
985//
986
987DWORD AgentConnection::StartUpgrade(const TCHAR *pszPkgName)
988{
989 DWORD dwRqId, dwResult;
990 CSCPMessage msg(m_nProtocolVersion);
991 int i;
992
993 if (!m_bIsConnected)
994 return ERR_NOT_CONNECTED;
995
996 dwRqId = m_dwRequestId++;
997
998 msg.SetCode(CMD_UPGRADE_AGENT);
999 msg.SetId(dwRqId);
1000 for(i = (int)_tcslen(pszPkgName) - 1;
1001 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
1002 msg.SetVariable(VID_FILE_NAME, &pszPkgName[i + 1]);
1003
1004 if (SendMessage(&msg))
1005 {
1006 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
1007 }
1008 else
1009 {
1010 dwResult = ERR_CONNECTION_BROKEN;
1011 }
1012
1013 return dwResult;
1014}
1015
1016
1017//
1018// Check status of network service via agent
1019//
1020
1021DWORD AgentConnection::CheckNetworkService(DWORD *pdwStatus, DWORD dwIpAddr, int iServiceType,
1022 WORD wPort, WORD wProto,
1023 const TCHAR *pszRequest, const TCHAR *pszResponse)
1024{
1025 DWORD dwRqId, dwResult;
1026 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1027 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80 };
1028
1029 if (!m_bIsConnected)
1030 return ERR_NOT_CONNECTED;
1031
1032 dwRqId = m_dwRequestId++;
1033
1034 msg.SetCode(CMD_CHECK_NETWORK_SERVICE);
1035 msg.SetId(dwRqId);
1036 msg.SetVariable(VID_IP_ADDRESS, dwIpAddr);
1037 msg.SetVariable(VID_SERVICE_TYPE, (WORD)iServiceType);
1038 msg.SetVariable(VID_IP_PORT,
1039 (wPort != 0) ? wPort :
1040 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
1041 (iServiceType <= NETSRV_HTTP)) ? iServiceType : 0]);
1042 msg.SetVariable(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
1043 msg.SetVariable(VID_SERVICE_REQUEST, pszRequest);
1044 msg.SetVariable(VID_SERVICE_RESPONSE, pszResponse);
1045
1046 if (SendMessage(&msg))
1047 {
1048 // Wait up to 90 seconds for results
1049 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
1050 if (pResponse != NULL)
1051 {
1052 dwResult = pResponse->GetVariableLong(VID_RCC);
1053 if (dwResult == ERR_SUCCESS)
1054 {
1055 *pdwStatus = pResponse->GetVariableLong(VID_SERVICE_STATUS);
1056 }
1057 delete pResponse;
1058 }
1059 else
1060 {
1061 dwResult = ERR_REQUEST_TIMEOUT;
1062 }
1063 }
1064 else
1065 {
1066 dwResult = ERR_CONNECTION_BROKEN;
1067 }
1068
1069 return dwResult;
1070}
1071
1072
1073//
1074// Get list of supported parameters from subagent
1075//
1076
1077DWORD AgentConnection::GetSupportedParameters(DWORD *pdwNumParams, NXC_AGENT_PARAM **ppParamList)
1078{
1079 DWORD i, dwId, dwRqId, dwResult;
1080 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1081
1082 *pdwNumParams = 0;
1083 *ppParamList = NULL;
1084
1085 if (!m_bIsConnected)
1086 return ERR_NOT_CONNECTED;
1087
1088 dwRqId = m_dwRequestId++;
1089
1090 msg.SetCode(CMD_GET_PARAMETER_LIST);
1091 msg.SetId(dwRqId);
1092
1093 if (SendMessage(&msg))
1094 {
1095 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1096 if (pResponse != NULL)
1097 {
1098 dwResult = pResponse->GetVariableLong(VID_RCC);
1099 DbgPrintf(6, _T("AgentConnection::GetSupportedParameters(): RCC=%d"), dwResult);
1100 if (dwResult == ERR_SUCCESS)
1101 {
1102 *pdwNumParams = pResponse->GetVariableLong(VID_NUM_PARAMETERS);
1103 *ppParamList = (NXC_AGENT_PARAM *)malloc(sizeof(NXC_AGENT_PARAM) * (*pdwNumParams));
1104 for(i = 0, dwId = VID_PARAM_LIST_BASE; i < *pdwNumParams; i++)
1105 {
1106 pResponse->GetVariableStr(dwId++, (*ppParamList)[i].szName, MAX_PARAM_NAME);
1107 pResponse->GetVariableStr(dwId++, (*ppParamList)[i].szDescription, MAX_DB_STRING);
1108 (*ppParamList)[i].iDataType = (int)pResponse->GetVariableShort(dwId++);
1109 }
1110 DbgPrintf(6, _T("AgentConnection::GetSupportedParameters(): %d parameters received from agent"), *pdwNumParams);
1111 }
1112 delete pResponse;
1113 }
1114 else
1115 {
1116 dwResult = ERR_REQUEST_TIMEOUT;
1117 }
1118 }
1119 else
1120 {
1121 dwResult = ERR_CONNECTION_BROKEN;
1122 }
1123
1124 return dwResult;
1125}
1126
1127
1128//
1129// Setup encryption
1130//
1131
1132DWORD AgentConnection::SetupEncryption(RSA *pServerKey)
1133{
1134#ifdef _WITH_ENCRYPTION
1135 CSCPMessage msg(m_nProtocolVersion), *pResp;
1136 DWORD dwRqId, dwError, dwResult;
1137
1138 dwRqId = m_dwRequestId++;
1139
1140 PrepareKeyRequestMsg(&msg, pServerKey);
1141 msg.SetId(dwRqId);
1142 if (SendMessage(&msg))
1143 {
1144 pResp = WaitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
1145 if (pResp != NULL)
1146 {
1147 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey, m_nProtocolVersion);
1148 switch(dwResult)
1149 {
1150 case RCC_SUCCESS:
1151 dwError = ERR_SUCCESS;
1152 break;
1153 case RCC_NO_CIPHERS:
1154 dwError = ERR_NO_CIPHERS;
1155 break;
1156 case RCC_INVALID_PUBLIC_KEY:
1157 dwError = ERR_INVALID_PUBLIC_KEY;
1158 break;
1159 case RCC_INVALID_SESSION_KEY:
1160 dwError = ERR_INVALID_SESSION_KEY;
1161 break;
1162 default:
1163 dwError = ERR_INTERNAL_ERROR;
1164 break;
1165 }
1166 delete pResp;
1167 }
1168 else
1169 {
1170 dwError = ERR_REQUEST_TIMEOUT;
1171 }
1172 }
1173 else
1174 {
1175 dwError = ERR_CONNECTION_BROKEN;
1176 }
1177
1178 return dwError;
1179#else
1180 return ERR_NOT_IMPLEMENTED;
1181#endif
1182}
1183
1184
1185//
1186// Get configuration file from agent
1187//
1188
1189DWORD AgentConnection::GetConfigFile(TCHAR **ppszConfig, DWORD *pdwSize)
1190{
1191 DWORD i, dwRqId, dwResult;
1192 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1193#ifdef UNICODE
1194 BYTE *pBuffer;
1195#endif
1196
1197 *ppszConfig = NULL;
1198 *pdwSize = 0;
1199
1200 if (!m_bIsConnected)
1201 return ERR_NOT_CONNECTED;
1202
1203 dwRqId = m_dwRequestId++;
1204
1205 msg.SetCode(CMD_GET_AGENT_CONFIG);
1206 msg.SetId(dwRqId);
1207
1208 if (SendMessage(&msg))
1209 {
1210 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1211 if (pResponse != NULL)
1212 {
1213 dwResult = pResponse->GetVariableLong(VID_RCC);
1214 if (dwResult == ERR_SUCCESS)
1215 {
1216 *pdwSize = pResponse->GetVariableBinary(VID_CONFIG_FILE, NULL, 0);
1217 *ppszConfig = (TCHAR *)malloc((*pdwSize + 1) * sizeof(TCHAR));
1218#ifdef UNICODE
1219 pBuffer = (BYTE *)malloc(*pdwSize + 1);
1220 pResponse->GetVariableBinary(VID_CONFIG_FILE, pBuffer, *pdwSize);
1221 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pBuffer, *pdwSize, *ppszConfig, *pdwSize);
1222 free(pBuffer);
1223#else
1224 pResponse->GetVariableBinary(VID_CONFIG_FILE, (BYTE *)(*ppszConfig), *pdwSize);
1225#endif
1226 (*ppszConfig)[*pdwSize] = 0;
1227
1228 // We expect text file, so replace all non-printable characters with spaces
1229 for(i = 0; i < *pdwSize; i++)
1230 if (((*ppszConfig)[i] < _T(' ')) &&
1231 ((*ppszConfig)[i] != _T('\t')) &&
1232 ((*ppszConfig)[i] != _T('\r')) &&
1233 ((*ppszConfig)[i] != _T('\n')))
1234 (*ppszConfig)[i] = _T(' ');
1235 }
1236 delete pResponse;
1237 }
1238 else
1239 {
1240 dwResult = ERR_REQUEST_TIMEOUT;
1241 }
1242 }
1243 else
1244 {
1245 dwResult = ERR_CONNECTION_BROKEN;
1246 }
1247
1248 return dwResult;
1249}
1250
1251
1252//
1253// Get configuration file from agent
1254//
1255
1256DWORD AgentConnection::UpdateConfigFile(const TCHAR *pszConfig)
1257{
1258 DWORD dwRqId, dwResult;
1259 CSCPMessage msg(m_nProtocolVersion);
1260#ifdef UNICODE
1261 int nChars;
1262 BYTE *pBuffer;
1263#endif
1264
1265 if (!m_bIsConnected)
1266 return ERR_NOT_CONNECTED;
1267
1268 dwRqId = m_dwRequestId++;
1269
1270 msg.SetCode(CMD_UPDATE_AGENT_CONFIG);
1271 msg.SetId(dwRqId);
1272#ifdef UNICODE
1273 nChars = _tcslen(pszConfig);
1274 pBuffer = (BYTE *)malloc(nChars + 1);
1275 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1276 pszConfig, nChars, pBuffer, nChars + 1, NULL, NULL);
1277 msg.SetVariable(VID_CONFIG_FILE, pBuffer, nChars);
1278 free(pBuffer);
1279#else
1280 msg.SetVariable(VID_CONFIG_FILE, (BYTE *)pszConfig, (DWORD)strlen(pszConfig));
1281#endif
1282
1283 if (SendMessage(&msg))
1284 {
1285 dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
1286 }
1287 else
1288 {
1289 dwResult = ERR_CONNECTION_BROKEN;
1290 }
1291
1292 return dwResult;
1293}
1294
1295
1296//
1297// Get routing table from agent
1298//
1299
1300ROUTING_TABLE *AgentConnection::GetRoutingTable(void)
1301{
1302 ROUTING_TABLE *pRT = NULL;
1303 DWORD i, dwBits;
1304 TCHAR *pChar, *pBuf;
1305
1306 if (GetList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS)
1307 {
1308 pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
1309 pRT->iNumEntries = m_dwNumDataLines;
1310 pRT->pRoutes = (ROUTE *)malloc(sizeof(ROUTE) * m_dwNumDataLines);
1311 memset(pRT->pRoutes, 0, sizeof(ROUTE) * m_dwNumDataLines);
1312 for(i = 0; i < m_dwNumDataLines; i++)
1313 {
1314 pBuf = m_ppDataLines[i];
1315
1316 // Destination address and mask
1317 pChar = _tcschr(pBuf, _T(' '));
1318 if (pChar != NULL)
1319 {
1320 TCHAR *pSlash;
1321 static TCHAR defaultMask[] = _T("24");
1322
1323 *pChar = 0;
1324 pSlash = _tcschr(pBuf, _T('/'));
1325 if (pSlash != NULL)
1326 {
1327 *pSlash = 0;
1328 pSlash++;
1329 }
1330 else // Just a paranoia protection, should'n happen if agent working correctly
1331 {
1332 pSlash = defaultMask;
1333 }
1334 pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
1335 dwBits = _tcstoul(pSlash, NULL, 10);
1336 pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
1337 pBuf = pChar + 1;
1338 }
1339
1340 // Next hop address
1341 pChar = _tcschr(pBuf, _T(' '));
1342 if (pChar != NULL)
1343 {
1344 *pChar = 0;
1345 pRT->pRoutes[i].dwNextHop = ntohl(_t_inet_addr(pBuf));
1346 pBuf = pChar + 1;
1347 }
1348
1349 // Interface index
1350 pChar = _tcschr(pBuf, ' ');
1351 if (pChar != NULL)
1352 {
1353 *pChar = 0;
1354 pRT->pRoutes[i].dwIfIndex = _tcstoul(pBuf, NULL, 10);
1355 pBuf = pChar + 1;
1356 }
1357
1358 // Route type
1359 pRT->pRoutes[i].dwRouteType = _tcstoul(pBuf, NULL, 10);
1360 }
1361
1362 Lock();
1363 DestroyResultData();
1364 Unlock();
1365 }
1366
1367 return pRT;
1368}
1369
1370
1371//
1372// Set proxy information
1373//
1374
1375void AgentConnection::SetProxy(DWORD dwAddr, WORD wPort, int iAuthMethod, const TCHAR *pszSecret)
1376{
1377 m_dwProxyAddr = dwAddr;
1378 m_wProxyPort = wPort;
1379 m_iProxyAuth = iAuthMethod;
1380 if (pszSecret != NULL)
1381 {
1382#ifdef UNICODE
1383 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1384 pszSecret, -1, m_szProxySecret, MAX_SECRET_LENGTH, NULL, NULL);
1385#else
1386 nx_strncpy(m_szProxySecret, pszSecret, MAX_SECRET_LENGTH);
1387#endif
1388 }
1389 else
1390 {
1391 m_szProxySecret[0] = 0;
1392 }
1393 m_bUseProxy = TRUE;
1394}
1395
1396
1397//
1398// Setup proxy connection
1399//
1400
1401DWORD AgentConnection::SetupProxyConnection(void)
1402{
1403 CSCPMessage msg(m_nProtocolVersion);
1404 DWORD dwRqId;
1405
1406 dwRqId = m_dwRequestId++;
1407 msg.SetCode(CMD_SETUP_PROXY_CONNECTION);
1408 msg.SetId(dwRqId);
1409 msg.SetVariable(VID_IP_ADDRESS, (DWORD)ntohl(m_dwAddr));
1410 msg.SetVariable(VID_AGENT_PORT, m_wPort);
1411 if (SendMessage(&msg))
1412 return WaitForRCC(dwRqId, 60000); // Wait 60 seconds for remote connect
1413 else
1414 return ERR_CONNECTION_BROKEN;
1415}
1416
1417
1418//
1419// Enable trap receiving on connection
1420//
1421
1422DWORD AgentConnection::EnableTraps(void)
1423{
1424 CSCPMessage msg(m_nProtocolVersion);
1425 DWORD dwRqId;
1426
1427 dwRqId = m_dwRequestId++;
1428 msg.SetCode(CMD_ENABLE_AGENT_TRAPS);
1429 msg.SetId(dwRqId);
1430 if (SendMessage(&msg))
1431 return WaitForRCC(dwRqId, m_dwCommandTimeout);
1432 else
1433 return ERR_CONNECTION_BROKEN;
1434}
1435
1436
1437//
1438// Send custom request to agent
1439//
1440
1441CSCPMessage *AgentConnection::CustomRequest(CSCPMessage *pRequest, const TCHAR *recvFile)
1442{
1443 DWORD dwRqId, rcc;
1444 CSCPMessage *msg = NULL;
1445
1446 dwRqId = m_dwRequestId++;
1447 pRequest->SetId(dwRqId);
1448 if (recvFile != NULL)
1449 {
1450 rcc = PrepareFileUpload(recvFile, dwRqId);
1451 if (rcc != ERR_SUCCESS)
1452 {
1453 // Create fake response message
1454 msg = new CSCPMessage;
1455 msg->SetCode(CMD_REQUEST_COMPLETED);
1456 msg->SetId(dwRqId);
1457 msg->SetVariable(VID_RCC, rcc);
1458 }
1459 }
1460
1461 if (msg == NULL)
1462 {
1463 if (SendMessage(pRequest))
1464 {
1465 msg = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1466 if ((msg != NULL) && (recvFile != NULL))
1467 {
1468 if (msg->GetVariableLong(VID_RCC) == ERR_SUCCESS)
1469 {
1470 if (ConditionWait(m_condFileUpload, 1800000)) // 30 min timeout
1471 {
1472 if (!m_fileUploadSucceeded)
1473 {
1474 msg->SetVariable(VID_RCC, ERR_IO_FAILURE);
1475 remove(recvFile);
1476 }
1477 }
1478 else
1479 {
1480 msg->SetVariable(VID_RCC, ERR_REQUEST_TIMEOUT);
1481 }
1482 }
1483 else
1484 {
1485 close(m_hCurrFile);
1486 m_hCurrFile = -1;
1487 remove(recvFile);
1488 }
1489 }
1490 }
1491 }
1492
1493 return msg;
1494}
1495
1496
1497//
1498// Prepare for file upload
1499//
1500
1501DWORD AgentConnection::PrepareFileUpload(const TCHAR *fileName, DWORD rqId)
1502{
1503 if (m_hCurrFile != -1)
1504 return ERR_RESOURCE_BUSY;
1505
1506 ConditionReset(m_condFileUpload);
1507 m_hCurrFile = open(fileName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, O_RDWR);
1508 m_dwUploadRequestId = rqId;
1509 return (m_hCurrFile != -1) ? ERR_SUCCESS : ERR_FILE_OPEN_ERROR;
1510}
1511
1512
1513//
1514// File upload completion handler
1515//
1516
1517void AgentConnection::OnFileUpload(BOOL success)
1518{
1519 m_fileUploadSucceeded = success;
1520 ConditionSet(m_condFileUpload);
1521}