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