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