Filemng: Fixed recognition of directory if it is a symlinkc to dir. Bug #606
[public/netxms.git] / src / server / libnxsrv / agent.cpp
CommitLineData
cc022855 1/*
5039dede
AK
2** NetXMS - Network Management System
3** Server Library
0f506caa 4** Copyright (C) 2003-2013 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
a3050773
VK
35/**
36 * Constants
37 */
8f4f648d 38#define MAX_MSG_SIZE 8388608
5039dede 39
a3050773
VK
40/**
41 * Static data
42 */
5039dede
AK
43#ifdef _WITH_ENCRYPTION
44static int m_iDefaultEncryptionPolicy = ENCRYPTION_ALLOWED;
45#else
46static int m_iDefaultEncryptionPolicy = ENCRYPTION_DISABLED;
47#endif
48
a3050773
VK
49/**
50 * Set default encryption policy for agent communication
51 */
5039dede
AK
52void LIBNXSRV_EXPORTABLE SetAgentDEP(int iPolicy)
53{
54#ifdef _WITH_ENCRYPTION
55 m_iDefaultEncryptionPolicy = iPolicy;
56#endif
57}
58
a3050773
VK
59/**
60 * Receiver thread starter
61 */
62THREAD_RESULT THREAD_CALL AgentConnection::receiverThreadStarter(void *pArg)
5039dede 63{
a3050773 64 ((AgentConnection *)pArg)->receiverThread();
5039dede
AK
65 return THREAD_OK;
66}
67
a3050773
VK
68/**
69 * Constructor for AgentConnection
70 */
69c6604d 71AgentConnection::AgentConnection(UINT32 ipAddr, WORD port, int authMethod, const TCHAR *secret)
5039dede 72{
69c6604d
VK
73 m_dwAddr = ipAddr;
74 m_wPort = port;
75 m_iAuthMethod = authMethod;
76 if (secret != NULL)
5039dede
AK
77 {
78#ifdef UNICODE
69c6604d 79 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, secret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
08b214c6 80 m_szSecret[MAX_SECRET_LENGTH - 1] = 0;
5039dede 81#else
69c6604d 82 nx_strncpy(m_szSecret, secret, MAX_SECRET_LENGTH);
5039dede
AK
83#endif
84 }
85 else
86 {
87 m_szSecret[0] = 0;
88 }
89 m_hSocket = -1;
90 m_tLastCommandTime = 0;
91 m_dwNumDataLines = 0;
92 m_ppDataLines = NULL;
93 m_pMsgWaitQueue = new MsgWaitQueue;
94 m_dwRequestId = 1;
7c521895 95 m_connectionTimeout = 30000; // 30 seconds
5039dede
AK
96 m_dwCommandTimeout = 10000; // Default timeout 10 seconds
97 m_bIsConnected = FALSE;
98 m_mutexDataLock = MutexCreate();
d3a7cf4c 99 m_mutexSocketWrite = MutexCreate();
5039dede
AK
100 m_hReceiverThread = INVALID_THREAD_HANDLE;
101 m_pCtx = NULL;
102 m_iEncryptionPolicy = m_iDefaultEncryptionPolicy;
103 m_bUseProxy = FALSE;
104 m_dwRecvTimeout = 420000; // 7 minutes
105 m_nProtocolVersion = NXCP_VERSION;
106 m_hCurrFile = -1;
76b4edb5 107 m_deleteFileOnDownloadFailure = true;
bb85e341 108 m_condFileDownload = ConditionCreate(TRUE);
4685a2ad 109 m_fileUploadInProgress = false;
9630fcd1 110 m_sendToClientMessageCallback = NULL;
5039dede
AK
111}
112
a3050773
VK
113/**
114 * Destructor
115 */
5039dede
AK
116AgentConnection::~AgentConnection()
117{
118 // Disconnect from peer
7c521895 119 disconnect();
5039dede
AK
120
121 // Wait for receiver thread termination
122 ThreadJoin(m_hReceiverThread);
cc022855 123
5039dede 124 // Close socket if active
a3050773 125 lock();
5039dede
AK
126 if (m_hSocket != -1)
127 {
128 closesocket(m_hSocket);
129 m_hSocket = -1;
130 }
a3050773 131 unlock();
5039dede 132
a3050773 133 lock();
7c521895 134 destroyResultData();
a3050773 135 unlock();
5039dede
AK
136
137 delete m_pMsgWaitQueue;
98abc9f1
VK
138 if (m_pCtx != NULL)
139 m_pCtx->decRefCount();
5039dede
AK
140
141 if (m_hCurrFile != -1)
9f6d453a 142 {
5039dede 143 close(m_hCurrFile);
f480bdd4 144 onFileDownload(FALSE);
9f6d453a 145 }
5039dede
AK
146
147 MutexDestroy(m_mutexDataLock);
d3a7cf4c 148 MutexDestroy(m_mutexSocketWrite);
bb85e341 149 ConditionDestroy(m_condFileDownload);
5039dede
AK
150}
151
a3050773
VK
152/**
153 * Print message. This method is virtual and can be overrided in
154 * derived classes. Default implementation will print message to stdout.
155 */
af21affe 156void AgentConnection::printMsg(const TCHAR *format, ...)
5039dede
AK
157{
158 va_list args;
159
af21affe
VK
160 va_start(args, format);
161 _vtprintf(format, args);
5039dede
AK
162 va_end(args);
163 _tprintf(_T("\n"));
164}
165
a3050773
VK
166/**
167 * Receiver thread
168 */
169void AgentConnection::receiverThread()
5039dede 170{
967893bb 171 UINT32 msgBufferSize = 1024;
5039dede
AK
172 CSCPMessage *pMsg;
173 CSCP_MESSAGE *pRawMsg;
174 CSCP_BUFFER *pMsgBuffer;
175 BYTE *pDecryptionBuffer = NULL;
4685a2ad 176 int error;
5039dede
AK
177 TCHAR szBuffer[128], szIpAddr[16];
178 SOCKET nSocket;
179
180 // Initialize raw message receiving function
181 pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
182 RecvNXCPMessage(0, NULL, pMsgBuffer, 0, NULL, NULL, 0);
183
184 // Allocate space for raw message
8f4f648d 185 pRawMsg = (CSCP_MESSAGE *)malloc(msgBufferSize);
5039dede 186#ifdef _WITH_ENCRYPTION
8f4f648d 187 pDecryptionBuffer = (BYTE *)malloc(msgBufferSize);
5039dede
AK
188#endif
189
190 // Message receiving loop
191 while(1)
192 {
8f4f648d
VK
193 // Shrink buffer after receiving large message
194 if (msgBufferSize > 131072)
195 {
196 msgBufferSize = 131072;
197 pRawMsg = (CSCP_MESSAGE *)realloc(pRawMsg, msgBufferSize);
198 if (pDecryptionBuffer != NULL)
199 pDecryptionBuffer = (BYTE *)realloc(pDecryptionBuffer, msgBufferSize);
200 }
201
5039dede 202 // Receive raw message
a3050773 203 lock();
5039dede 204 nSocket = m_hSocket;
a3050773 205 unlock();
8f4f648d
VK
206 if ((error = RecvNXCPMessageEx(nSocket, &pRawMsg, pMsgBuffer, &msgBufferSize,
207 &m_pCtx, (pDecryptionBuffer != NULL) ? &pDecryptionBuffer : NULL,
208 m_dwRecvTimeout, MAX_MSG_SIZE)) <= 0)
5039dede 209 {
a2069340
VK
210 if (WSAGetLastError() != WSAESHUTDOWN)
211 DbgPrintf(6, _T("AgentConnection::ReceiverThread(): RecvNXCPMessage() failed: error=%d, socket_error=%d"), error, WSAGetLastError());
5039dede
AK
212 break;
213 }
214
215 // Check if we get too large message
4685a2ad 216 if (error == 1)
5039dede 217 {
cc022855 218 printMsg(_T("Received too large message %s (%d bytes)"),
5039dede
AK
219 NXCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
220 ntohl(pRawMsg->dwSize));
221 continue;
222 }
223
224 // Check if we are unable to decrypt message
4685a2ad 225 if (error == 2)
5039dede 226 {
a3050773 227 printMsg(_T("Unable to decrypt received message"));
5039dede
AK
228 continue;
229 }
230
231 // Check for timeout
4685a2ad 232 if (error == 3)
5039dede 233 {
4685a2ad
VK
234 if (m_fileUploadInProgress)
235 continue; // Receive timeout may occur when uploading large files via slow links
a3050773 236 printMsg(_T("Timed out waiting for message"));
5039dede
AK
237 break;
238 }
239
240 // Check that actual received packet size is equal to encoded in packet
4685a2ad 241 if ((int)ntohl(pRawMsg->dwSize) != error)
5039dede 242 {
a3050773 243 printMsg(_T("RecvMsg: Bad packet length [dwSize=%d ActualSize=%d]"), ntohl(pRawMsg->dwSize), error);
5039dede
AK
244 continue; // Bad packet, wait for next
245 }
246
247 if (ntohs(pRawMsg->wFlags) & MF_BINARY)
248 {
249 // Convert message header to host format
250 pRawMsg->dwId = ntohl(pRawMsg->dwId);
251 pRawMsg->wCode = ntohs(pRawMsg->wCode);
252 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
08b214c6 253 DbgPrintf(6, _T("Received raw message %s from agent at %s"),
7c521895 254 NXCPMessageCodeName(pRawMsg->wCode, szBuffer), IpToStr(getIpAddr(), szIpAddr));
5039dede 255
76b4edb5 256 if ((pRawMsg->wCode == CMD_FILE_DATA) && (pRawMsg->dwId == m_dwDownloadRequestId))
5039dede 257 {
76b4edb5 258 if (m_sendToClientMessageCallback != NULL)
5039dede 259 {
76b4edb5 260 pRawMsg->wCode = ntohs(pRawMsg->wCode);
261 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
262 m_sendToClientMessageCallback(pRawMsg, m_downloadProgressCallbackArg);
263
5039dede
AK
264 if (ntohs(pRawMsg->wFlags) & MF_END_OF_FILE)
265 {
f480bdd4 266 onFileDownload(TRUE);
5039dede 267 }
76b4edb5 268 else
269 {
270 if (m_downloadProgressCallback != NULL)
271 {
272 m_downloadProgressCallback(pRawMsg->dwSize - (CSCP_HEADER_SIZE + 8), m_downloadProgressCallbackArg);
273 }
274 }
5039dede
AK
275 }
276 else
277 {
76b4edb5 278 if (m_hCurrFile != -1)
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 onFileDownload(TRUE);
288 }
289 else
290 {
291 if (m_downloadProgressCallback != NULL)
292 {
293 m_downloadProgressCallback(_tell(m_hCurrFile), m_downloadProgressCallbackArg);
294 }
295 }
296 }
297 }
298 else
299 {
300 // I/O error
301 close(m_hCurrFile);
302 m_hCurrFile = -1;
cc022855 303
76b4edb5 304 onFileDownload(FALSE);
305 }
5039dede
AK
306 }
307 }
308 }
309 else
310 {
311 // Create message object from raw message
312 pMsg = new CSCPMessage(pRawMsg, m_nProtocolVersion);
f480bdd4 313 switch(pMsg->GetCode())
5039dede 314 {
f480bdd4
VK
315 case CMD_TRAP:
316 onTrap(pMsg);
317 delete pMsg;
318 break;
319 case CMD_PUSH_DCI_DATA:
320 onDataPush(pMsg);
321 delete pMsg;
322 break;
90284364 323 case CMD_REQUEST_COMPLETED:
c17f6cbc 324 m_pMsgWaitQueue->put(pMsg);
f480bdd4 325 break;
9fa031cd 326 case CMD_FILE_MONITORING:
327 onFileMonitoringData(pMsg);
328 delete pMsg;
329 break;
90284364
VK
330 default:
331 if (processCustomMessage(pMsg))
332 delete pMsg;
333 else
c17f6cbc 334 m_pMsgWaitQueue->put(pMsg);
90284364 335 break;
5039dede
AK
336 }
337 }
338 }
339
340 // Close socket and mark connection as disconnected
a3050773 341 lock();
f2665675
VK
342 if (m_hCurrFile != -1)
343 {
344 close(m_hCurrFile);
345 m_hCurrFile = -1;
f480bdd4 346 onFileDownload(FALSE);
f2665675 347 }
cc022855 348
4685a2ad 349 if (error == 0)
5039dede
AK
350 shutdown(m_hSocket, SHUT_RDWR);
351 closesocket(m_hSocket);
352 m_hSocket = -1;
98abc9f1
VK
353 if (m_pCtx != NULL)
354 {
355 m_pCtx->decRefCount();
356 m_pCtx = NULL;
357 }
5039dede 358 m_bIsConnected = FALSE;
a3050773 359 unlock();
5039dede
AK
360
361 free(pRawMsg);
362 free(pMsgBuffer);
363#ifdef _WITH_ENCRYPTION
364 free(pDecryptionBuffer);
365#endif
366}
367
a3050773
VK
368/**
369 * Connect to agent
370 */
967893bb 371BOOL AgentConnection::connect(RSA *pServerKey, BOOL bVerbose, UINT32 *pdwError, UINT32 *pdwSocketError)
5039dede
AK
372{
373 struct sockaddr_in sa;
374 TCHAR szBuffer[256];
375 BOOL bSuccess = FALSE, bForceEncryption = FALSE, bSecondPass = FALSE;
967893bb 376 UINT32 dwError = 0;
5039dede
AK
377
378 if (pdwError != NULL)
379 *pdwError = ERR_INTERNAL_ERROR;
380
c3acd0f6
VK
381 if (pdwSocketError != NULL)
382 *pdwSocketError = 0;
383
5039dede
AK
384 // Check if already connected
385 if (m_bIsConnected)
386 return FALSE;
387
388 // Wait for receiver thread from previous connection, if any
389 ThreadJoin(m_hReceiverThread);
390 m_hReceiverThread = INVALID_THREAD_HANDLE;
391
392 // Check if we need to close existing socket
393 if (m_hSocket != -1)
394 closesocket(m_hSocket);
395
396 // Create socket
397 m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
4c0c75c7 398 if (m_hSocket == INVALID_SOCKET)
5039dede 399 {
a3050773 400 printMsg(_T("Call to socket() failed"));
5039dede
AK
401 goto connect_cleanup;
402 }
403
404 // Fill in address structure
405 memset(&sa, 0, sizeof(sa));
406 sa.sin_family = AF_INET;
407 if (m_bUseProxy)
408 {
409 sa.sin_addr.s_addr = m_dwProxyAddr;
410 sa.sin_port = htons(m_wProxyPort);
411 }
412 else
413 {
414 sa.sin_addr.s_addr = m_dwAddr;
415 sa.sin_port = htons(m_wPort);
416 }
417
418 // Connect to server
7c521895 419 if (ConnectEx(m_hSocket, (struct sockaddr *)&sa, sizeof(sa), m_connectionTimeout) == -1)
5039dede
AK
420 {
421 if (bVerbose)
a3050773 422 printMsg(_T("Cannot establish connection with agent %s"),
5039dede
AK
423 IpToStr(ntohl(m_bUseProxy ? m_dwProxyAddr : m_dwAddr), szBuffer));
424 dwError = ERR_CONNECT_FAILED;
425 goto connect_cleanup;
426 }
427
d3a7cf4c 428 if (!NXCPGetPeerProtocolVersion(m_hSocket, &m_nProtocolVersion, m_mutexSocketWrite))
5039dede
AK
429 {
430 dwError = ERR_INTERNAL_ERROR;
431 goto connect_cleanup;
432 }
433
434 // Start receiver thread
a3050773 435 m_hReceiverThread = ThreadCreateEx(receiverThreadStarter, 0, this);
5039dede
AK
436
437 // Setup encryption
438setup_encryption:
439 if ((m_iEncryptionPolicy == ENCRYPTION_PREFERRED) ||
440 (m_iEncryptionPolicy == ENCRYPTION_REQUIRED) ||
441 (bForceEncryption)) // Agent require encryption
442 {
443 if (pServerKey != NULL)
444 {
7c521895 445 dwError = setupEncryption(pServerKey);
5039dede
AK
446 if ((dwError != ERR_SUCCESS) &&
447 ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption))
448 goto connect_cleanup;
449 }
450 else
451 {
452 if ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || bForceEncryption)
453 {
454 dwError = ERR_ENCRYPTION_REQUIRED;
455 goto connect_cleanup;
456 }
457 }
458 }
459
460 // Authenticate itself to agent
7c521895 461 if ((dwError = authenticate(m_bUseProxy && !bSecondPass)) != ERR_SUCCESS)
5039dede
AK
462 {
463 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
464 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
465 {
466 bForceEncryption = TRUE;
467 goto setup_encryption;
468 }
a3050773 469 printMsg(_T("Authentication to agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
5039dede
AK
470 AgentErrorCodeToText(dwError));
471 goto connect_cleanup;
472 }
473
474 // Test connectivity
45d84f8a 475 if ((dwError = nop()) != ERR_SUCCESS)
5039dede
AK
476 {
477 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
478 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
479 {
480 bForceEncryption = TRUE;
481 goto setup_encryption;
482 }
a3050773 483 printMsg(_T("Communication with agent %s failed (%s)"), IpToStr(ntohl(m_dwAddr), szBuffer),
5039dede
AK
484 AgentErrorCodeToText(dwError));
485 goto connect_cleanup;
486 }
487
488 if (m_bUseProxy && !bSecondPass)
489 {
7c521895 490 dwError = setupProxyConnection();
5039dede
AK
491 if (dwError != ERR_SUCCESS)
492 goto connect_cleanup;
a3050773 493 lock();
98abc9f1
VK
494 if (m_pCtx != NULL)
495 {
496 m_pCtx->decRefCount();
497 m_pCtx = NULL;
498 }
a3050773 499 unlock();
5039dede
AK
500 bSecondPass = TRUE;
501 bForceEncryption = FALSE;
502 goto setup_encryption;
503 }
504
505 bSuccess = TRUE;
506 dwError = ERR_SUCCESS;
507
508connect_cleanup:
509 if (!bSuccess)
510 {
c3acd0f6 511 if (pdwSocketError != NULL)
967893bb 512 *pdwSocketError = (UINT32)WSAGetLastError();
c3acd0f6 513
a3050773 514 lock();
5039dede
AK
515 if (m_hSocket != -1)
516 shutdown(m_hSocket, SHUT_RDWR);
a3050773 517 unlock();
5039dede
AK
518 ThreadJoin(m_hReceiverThread);
519 m_hReceiverThread = INVALID_THREAD_HANDLE;
520
a3050773 521 lock();
5039dede
AK
522 if (m_hSocket != -1)
523 {
524 closesocket(m_hSocket);
525 m_hSocket = -1;
526 }
527
98abc9f1
VK
528 if (m_pCtx != NULL)
529 {
530 m_pCtx->decRefCount();
531 m_pCtx = NULL;
532 }
5039dede 533
a3050773 534 unlock();
5039dede
AK
535 }
536 m_bIsConnected = bSuccess;
537 if (pdwError != NULL)
538 *pdwError = dwError;
539 return bSuccess;
540}
541
af21affe
VK
542/**
543 * Disconnect from agent
544 */
7c521895 545void AgentConnection::disconnect()
5039dede 546{
a3050773 547 lock();
f2665675
VK
548 if (m_hCurrFile != -1)
549 {
550 close(m_hCurrFile);
551 m_hCurrFile = -1;
f480bdd4 552 onFileDownload(FALSE);
f2665675 553 }
9fa031cd 554
5039dede
AK
555 if (m_hSocket != -1)
556 {
557 shutdown(m_hSocket, SHUT_RDWR);
558 }
7c521895 559 destroyResultData();
5039dede 560 m_bIsConnected = FALSE;
a3050773 561 unlock();
5039dede
AK
562}
563
af21affe
VK
564/**
565 * Set authentication data
566 */
567void AgentConnection::setAuthData(int method, const TCHAR *secret)
cc022855 568{
af21affe
VK
569 m_iAuthMethod = method;
570#ifdef UNICODE
571 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, secret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
572 m_szSecret[MAX_SECRET_LENGTH - 1] = 0;
573#else
574 nx_strncpy(m_szSecret, secret, MAX_SECRET_LENGTH);
575#endif
576}
5039dede 577
af21affe
VK
578/**
579 * Destroy command execuion results data
580 */
7c521895 581void AgentConnection::destroyResultData()
5039dede 582{
967893bb 583 UINT32 i;
5039dede
AK
584
585 if (m_ppDataLines != NULL)
586 {
587 for(i = 0; i < m_dwNumDataLines; i++)
588 if (m_ppDataLines[i] != NULL)
589 free(m_ppDataLines[i]);
590 free(m_ppDataLines);
591 m_ppDataLines = NULL;
592 }
593 m_dwNumDataLines = 0;
594}
595
d51f2182
VK
596/**
597 * Get interface list from agent
598 */
98762401 599InterfaceList *AgentConnection::getInterfaceList()
5039dede 600{
98762401 601 InterfaceList *pIfList = NULL;
36e44abe 602 NX_INTERFACE_INFO iface;
967893bb 603 UINT32 i, dwBits;
5039dede
AK
604 TCHAR *pChar, *pBuf;
605
4687826e 606 if (getList(_T("Net.InterfaceList")) == ERR_SUCCESS)
5039dede 607 {
98762401 608 pIfList = new InterfaceList(m_dwNumDataLines);
5039dede
AK
609
610 // Parse result set. Each line should have the following format:
611 // index ip_address/mask_bits iftype mac_address name
612 for(i = 0; i < m_dwNumDataLines; i++)
613 {
614 pBuf = m_ppDataLines[i];
36e44abe 615 memset(&iface, 0, sizeof(NX_INTERFACE_INFO));
5039dede
AK
616
617 // Index
618 pChar = _tcschr(pBuf, ' ');
619 if (pChar != NULL)
620 {
621 *pChar = 0;
98762401 622 iface.dwIndex = _tcstoul(pBuf, NULL, 10);
5039dede
AK
623 pBuf = pChar + 1;
624 }
625
626 // Address and mask
627 pChar = _tcschr(pBuf, _T(' '));
628 if (pChar != NULL)
629 {
630 TCHAR *pSlash;
631 static TCHAR defaultMask[] = _T("24");
632
633 *pChar = 0;
634 pSlash = _tcschr(pBuf, _T('/'));
635 if (pSlash != NULL)
636 {
637 *pSlash = 0;
638 pSlash++;
639 }
640 else // Just a paranoia protection, should'n happen if agent working correctly
641 {
642 pSlash = defaultMask;
643 }
98762401 644 iface.dwIpAddr = ntohl(_t_inet_addr(pBuf));
5039dede 645 dwBits = _tcstoul(pSlash, NULL, 10);
98762401 646 iface.dwIpNetMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
5039dede
AK
647 pBuf = pChar + 1;
648 }
649
650 // Interface type
651 pChar = _tcschr(pBuf, ' ');
652 if (pChar != NULL)
653 {
654 *pChar = 0;
98762401 655 iface.dwType = _tcstoul(pBuf, NULL, 10);
5039dede
AK
656 pBuf = pChar + 1;
657 }
658
659 // MAC address
660 pChar = _tcschr(pBuf, ' ');
661 if (pChar != NULL)
662 {
663 *pChar = 0;
98762401 664 StrToBin(pBuf, iface.bMacAddr, MAC_ADDR_LENGTH);
5039dede
AK
665 pBuf = pChar + 1;
666 }
667
478d4ff4
VK
668 // Name (set description to name)
669 nx_strncpy(iface.szName, pBuf, MAX_DB_STRING);
670 nx_strncpy(iface.szDescription, pBuf, MAX_DB_STRING);
98762401
VK
671
672 pIfList->add(&iface);
5039dede
AK
673 }
674
a3050773 675 lock();
7c521895 676 destroyResultData();
a3050773 677 unlock();
5039dede
AK
678 }
679
680 return pIfList;
681}
682
683
684//
685// Get parameter value
686//
687
967893bb 688UINT32 AgentConnection::getParameter(const TCHAR *pszParam, UINT32 dwBufSize, TCHAR *pszBuffer)
5039dede
AK
689{
690 CSCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 691 UINT32 dwRqId, dwRetCode;
5039dede
AK
692
693 if (m_bIsConnected)
694 {
695 dwRqId = m_dwRequestId++;
696 msg.SetCode(CMD_GET_PARAMETER);
697 msg.SetId(dwRqId);
698 msg.SetVariable(VID_PARAMETER, pszParam);
7c521895 699 if (sendMessage(&msg))
5039dede 700 {
7c521895 701 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
702 if (pResponse != NULL)
703 {
704 dwRetCode = pResponse->GetVariableLong(VID_RCC);
705 if (dwRetCode == ERR_SUCCESS)
706 pResponse->GetVariableStr(VID_VALUE, pszBuffer, dwBufSize);
707 delete pResponse;
708 }
709 else
710 {
711 dwRetCode = ERR_REQUEST_TIMEOUT;
712 }
713 }
714 else
715 {
716 dwRetCode = ERR_CONNECTION_BROKEN;
717 }
718 }
719 else
720 {
721 dwRetCode = ERR_NOT_CONNECTED;
722 }
723
724 return dwRetCode;
725}
726
727
728//
729// Get ARP cache
730//
731
4687826e 732ARP_CACHE *AgentConnection::getArpCache()
5039dede
AK
733{
734 ARP_CACHE *pArpCache = NULL;
735 TCHAR szByte[4], *pBuf, *pChar;
967893bb 736 UINT32 i, j;
5039dede 737
4687826e 738 if (getList(_T("Net.ArpCache")) == ERR_SUCCESS)
5039dede
AK
739 {
740 // Create empty structure
741 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
742 pArpCache->dwNumEntries = m_dwNumDataLines;
743 pArpCache->pEntries = (ARP_ENTRY *)malloc(sizeof(ARP_ENTRY) * m_dwNumDataLines);
744 memset(pArpCache->pEntries, 0, sizeof(ARP_ENTRY) * m_dwNumDataLines);
745
746 szByte[2] = 0;
747
748 // Parse data lines
749 // Each line has form of XXXXXXXXXXXX a.b.c.d n
750 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
751 // a.b.c.d is an IP address in decimal dotted notation
752 // n is an interface index
753 for(i = 0; i < m_dwNumDataLines; i++)
754 {
755 pBuf = m_ppDataLines[i];
756 if (_tcslen(pBuf) < 20) // Invalid line
757 continue;
758
759 // MAC address
760 for(j = 0; j < 6; j++)
761 {
762 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
763 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
764 pBuf+=2;
765 }
766
767 // IP address
768 while(*pBuf == ' ')
769 pBuf++;
770 pChar = _tcschr(pBuf, _T(' '));
771 if (pChar != NULL)
772 *pChar = 0;
773 pArpCache->pEntries[i].dwIpAddr = ntohl(_t_inet_addr(pBuf));
774
775 // Interface index
776 if (pChar != NULL)
777 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
778 }
779
a3050773 780 lock();
7c521895 781 destroyResultData();
a3050773 782 unlock();
5039dede
AK
783 }
784 return pArpCache;
785}
786
787
788//
789// Send dummy command to agent (can be used for keepalive)
790//
791
967893bb 792UINT32 AgentConnection::nop()
5039dede
AK
793{
794 CSCPMessage msg(m_nProtocolVersion);
967893bb 795 UINT32 dwRqId;
5039dede
AK
796
797 dwRqId = m_dwRequestId++;
798 msg.SetCode(CMD_KEEPALIVE);
799 msg.SetId(dwRqId);
7c521895
VK
800 if (sendMessage(&msg))
801 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
802 else
803 return ERR_CONNECTION_BROKEN;
804}
805
806
807//
808// Wait for request completion code
809//
810
967893bb 811UINT32 AgentConnection::waitForRCC(UINT32 dwRqId, UINT32 dwTimeOut)
5039dede
AK
812{
813 CSCPMessage *pMsg;
967893bb 814 UINT32 dwRetCode;
5039dede 815
c17f6cbc 816 pMsg = m_pMsgWaitQueue->waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
5039dede
AK
817 if (pMsg != NULL)
818 {
819 dwRetCode = pMsg->GetVariableLong(VID_RCC);
820 delete pMsg;
821 }
822 else
823 {
824 dwRetCode = ERR_REQUEST_TIMEOUT;
825 }
826 return dwRetCode;
827}
828
5c44534b
VK
829/**
830 * Send message to agent
831 */
7c521895 832BOOL AgentConnection::sendMessage(CSCPMessage *pMsg)
5039dede 833{
5039dede
AK
834 BOOL bResult;
835
5c44534b 836 CSCP_MESSAGE *pRawMsg = pMsg->createMessage();
98abc9f1
VK
837 NXCPEncryptionContext *pCtx = acquireEncryptionContext();
838 if (pCtx != NULL)
5039dede 839 {
98abc9f1 840 CSCP_ENCRYPTED_MESSAGE *pEnMsg = CSCPEncryptMessage(pCtx, pRawMsg);
5039dede
AK
841 if (pEnMsg != NULL)
842 {
d3a7cf4c 843 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->dwSize));
5039dede
AK
844 free(pEnMsg);
845 }
846 else
847 {
848 bResult = FALSE;
849 }
98abc9f1 850 pCtx->decRefCount();
5039dede
AK
851 }
852 else
853 {
d3a7cf4c 854 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->dwSize));
5039dede
AK
855 }
856 free(pRawMsg);
857 return bResult;
858}
859
7cf549ad 860/**
861 * Send raw message to agent
862 */
863BOOL AgentConnection::sendRawMessage(CSCP_MESSAGE *pMsg)
864{
865 BOOL bResult;
866
867 CSCP_MESSAGE *pRawMsg = pMsg;
868 NXCPEncryptionContext *pCtx = acquireEncryptionContext();
869 if (pCtx != NULL)
870 {
871 CSCP_ENCRYPTED_MESSAGE *pEnMsg = CSCPEncryptMessage(pCtx, pRawMsg);
872 if (pEnMsg != NULL)
873 {
874 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->dwSize));
875 free(pEnMsg);
876 }
877 else
878 {
879 bResult = FALSE;
880 }
881 pCtx->decRefCount();
882 }
883 else
884 {
885 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->dwSize));
886 }
887 return bResult;
888}
889
d51f2182
VK
890/**
891 * Trap handler. Should be overriden in derived classes to implement
892 * actual trap processing. Default implementation do nothing.
893 */
f480bdd4
VK
894void AgentConnection::onTrap(CSCPMessage *pMsg)
895{
896}
897
d51f2182
VK
898/**
899 * Data push handler. Should be overriden in derived classes to implement
900 * actual data push processing. Default implementation do nothing.
901 */
f480bdd4 902void AgentConnection::onDataPush(CSCPMessage *pMsg)
5039dede
AK
903{
904}
905
9fa031cd 906/**
907 * Monitoring data handler. Should be overriden in derived classes to implement
908 * actual monitoring data processing. Default implementation do nothing.
909 */
910void AgentConnection::onFileMonitoringData(CSCPMessage *pMsg)
911{
912}
913
d51f2182
VK
914/**
915 * Custom message handler
916 * If returns true, message considered as processed and will not be placed in wait queue
917 */
90284364
VK
918bool AgentConnection::processCustomMessage(CSCPMessage *pMsg)
919{
920 return false;
921}
922
d51f2182
VK
923/**
924 * Get list of values
925 */
967893bb 926UINT32 AgentConnection::getList(const TCHAR *pszParam)
5039dede
AK
927{
928 CSCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 929 UINT32 i, dwRqId, dwRetCode;
5039dede
AK
930
931 if (m_bIsConnected)
932 {
7c521895 933 destroyResultData();
5039dede
AK
934 dwRqId = m_dwRequestId++;
935 msg.SetCode(CMD_GET_LIST);
936 msg.SetId(dwRqId);
937 msg.SetVariable(VID_PARAMETER, pszParam);
7c521895 938 if (sendMessage(&msg))
5039dede 939 {
7c521895 940 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
941 if (pResponse != NULL)
942 {
943 dwRetCode = pResponse->GetVariableLong(VID_RCC);
944 if (dwRetCode == ERR_SUCCESS)
945 {
946 m_dwNumDataLines = pResponse->GetVariableLong(VID_NUM_STRINGS);
947 m_ppDataLines = (TCHAR **)malloc(sizeof(TCHAR *) * m_dwNumDataLines);
948 for(i = 0; i < m_dwNumDataLines; i++)
949 m_ppDataLines[i] = pResponse->GetVariableStr(VID_ENUM_VALUE_BASE + i);
950 }
951 delete pResponse;
952 }
953 else
954 {
955 dwRetCode = ERR_REQUEST_TIMEOUT;
956 }
957 }
958 else
959 {
960 dwRetCode = ERR_CONNECTION_BROKEN;
961 }
962 }
963 else
964 {
965 dwRetCode = ERR_NOT_CONNECTED;
966 }
967
968 return dwRetCode;
969}
970
d51f2182
VK
971/**
972 * Get table
973 */
967893bb 974UINT32 AgentConnection::getTable(const TCHAR *pszParam, Table **table)
4687826e
VK
975{
976 CSCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 977 UINT32 dwRqId, dwRetCode;
4687826e
VK
978
979 *table = NULL;
980 if (m_bIsConnected)
981 {
982 dwRqId = m_dwRequestId++;
983 msg.SetCode(CMD_GET_TABLE);
984 msg.SetId(dwRqId);
985 msg.SetVariable(VID_PARAMETER, pszParam);
986 if (sendMessage(&msg))
987 {
988 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
989 if (pResponse != NULL)
990 {
991 dwRetCode = pResponse->GetVariableLong(VID_RCC);
992 if (dwRetCode == ERR_SUCCESS)
993 {
994 *table = new Table(pResponse);
995 }
996 delete pResponse;
997 }
998 else
999 {
1000 dwRetCode = ERR_REQUEST_TIMEOUT;
1001 }
1002 }
1003 else
1004 {
1005 dwRetCode = ERR_CONNECTION_BROKEN;
1006 }
1007 }
1008 else
1009 {
1010 dwRetCode = ERR_NOT_CONNECTED;
1011 }
1012
1013 return dwRetCode;
1014}
1015
975f38fc
VK
1016/**
1017 * Authenticate to agent
1018 */
967893bb 1019UINT32 AgentConnection::authenticate(BOOL bProxyData)
5039dede
AK
1020{
1021 CSCPMessage msg(m_nProtocolVersion);
967893bb 1022 UINT32 dwRqId;
5039dede
AK
1023 BYTE hash[32];
1024 int iAuthMethod = bProxyData ? m_iProxyAuth : m_iAuthMethod;
08b214c6 1025 const char *pszSecret = bProxyData ? m_szProxySecret : m_szSecret;
5039dede
AK
1026#ifdef UNICODE
1027 WCHAR szBuffer[MAX_SECRET_LENGTH];
1028#endif
1029
1030 if (iAuthMethod == AUTH_NONE)
1031 return ERR_SUCCESS; // No authentication required
1032
1033 dwRqId = m_dwRequestId++;
1034 msg.SetCode(CMD_AUTHENTICATE);
1035 msg.SetId(dwRqId);
1036 msg.SetVariable(VID_AUTH_METHOD, (WORD)iAuthMethod);
1037 switch(iAuthMethod)
1038 {
1039 case AUTH_PLAINTEXT:
1040#ifdef UNICODE
1041 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszSecret, -1, szBuffer, MAX_SECRET_LENGTH);
1042 msg.SetVariable(VID_SHARED_SECRET, szBuffer);
1043#else
1044 msg.SetVariable(VID_SHARED_SECRET, pszSecret);
1045#endif
1046 break;
1047 case AUTH_MD5_HASH:
1048 CalculateMD5Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
1049 msg.SetVariable(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
1050 break;
1051 case AUTH_SHA1_HASH:
1052 CalculateSHA1Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
1053 msg.SetVariable(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
1054 break;
1055 default:
1056 break;
1057 }
7c521895
VK
1058 if (sendMessage(&msg))
1059 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1060 else
1061 return ERR_CONNECTION_BROKEN;
1062}
1063
1064
1065//
1066// Execute action on agent
1067//
1068
967893bb 1069UINT32 AgentConnection::execAction(const TCHAR *pszAction, int argc, TCHAR **argv)
5039dede
AK
1070{
1071 CSCPMessage msg(m_nProtocolVersion);
967893bb 1072 UINT32 dwRqId;
5039dede
AK
1073 int i;
1074
1075 if (!m_bIsConnected)
1076 return ERR_NOT_CONNECTED;
1077
1078 dwRqId = m_dwRequestId++;
1079 msg.SetCode(CMD_ACTION);
1080 msg.SetId(dwRqId);
1081 msg.SetVariable(VID_ACTION_NAME, pszAction);
967893bb 1082 msg.SetVariable(VID_NUM_ARGS, (UINT32)argc);
5039dede
AK
1083 for(i = 0; i < argc; i++)
1084 msg.SetVariable(VID_ACTION_ARG_BASE + i, argv[i]);
1085
7c521895
VK
1086 if (sendMessage(&msg))
1087 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1088 else
1089 return ERR_CONNECTION_BROKEN;
1090}
1091
1092
1093//
1094// Upload file to agent
1095//
1096
967893bb 1097UINT32 AgentConnection::uploadFile(const TCHAR *localFile, const TCHAR *destinationFile, void (* progressCallback)(INT64, void *), void *cbArg)
5039dede 1098{
967893bb 1099 UINT32 dwRqId, dwResult;
5039dede
AK
1100 CSCPMessage msg(m_nProtocolVersion);
1101 int i;
1102
1103 if (!m_bIsConnected)
1104 return ERR_NOT_CONNECTED;
1105
1106 dwRqId = m_dwRequestId++;
1107
1108 msg.SetCode(CMD_TRANSFER_FILE);
1109 msg.SetId(dwRqId);
cc022855 1110 for(i = (int)_tcslen(localFile) - 1;
619e5c9b
VK
1111 (i >= 0) && (localFile[i] != '\\') && (localFile[i] != '/'); i--);
1112 msg.SetVariable(VID_FILE_NAME, &localFile[i + 1]);
1113 if (destinationFile != NULL)
f0c1d2a4 1114 {
619e5c9b 1115 msg.SetVariable(VID_DESTINATION_FILE_NAME, destinationFile);
f0c1d2a4 1116 }
5039dede 1117
7c521895 1118 if (sendMessage(&msg))
5039dede 1119 {
7c521895 1120 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1121 }
1122 else
1123 {
1124 dwResult = ERR_CONNECTION_BROKEN;
1125 }
1126
1127 if (dwResult == ERR_SUCCESS)
1128 {
4685a2ad 1129 m_fileUploadInProgress = true;
98abc9f1 1130 NXCPEncryptionContext *ctx = acquireEncryptionContext();
cc022855 1131 if (SendFileOverNXCP(m_hSocket, dwRqId, localFile, ctx, 0, progressCallback, cbArg, m_mutexSocketWrite))
7c521895 1132 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1133 else
1134 dwResult = ERR_IO_FAILURE;
4685a2ad 1135 m_fileUploadInProgress = false;
5039dede
AK
1136 }
1137
1138 return dwResult;
1139}
1140
1141
1142//
1143// Send upgrade command
1144//
1145
967893bb 1146UINT32 AgentConnection::startUpgrade(const TCHAR *pszPkgName)
5039dede 1147{
967893bb 1148 UINT32 dwRqId, dwResult;
5039dede
AK
1149 CSCPMessage msg(m_nProtocolVersion);
1150 int i;
1151
1152 if (!m_bIsConnected)
1153 return ERR_NOT_CONNECTED;
1154
1155 dwRqId = m_dwRequestId++;
1156
1157 msg.SetCode(CMD_UPGRADE_AGENT);
1158 msg.SetId(dwRqId);
cc022855 1159 for(i = (int)_tcslen(pszPkgName) - 1;
5039dede
AK
1160 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
1161 msg.SetVariable(VID_FILE_NAME, &pszPkgName[i + 1]);
1162
7c521895 1163 if (sendMessage(&msg))
5039dede 1164 {
7c521895 1165 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1166 }
1167 else
1168 {
1169 dwResult = ERR_CONNECTION_BROKEN;
1170 }
1171
1172 return dwResult;
1173}
1174
a0e181dc
VK
1175/**
1176 * Check status of network service via agent
1177 */
cc022855 1178UINT32 AgentConnection::checkNetworkService(UINT32 *pdwStatus, UINT32 dwIpAddr, int iServiceType,
1179 WORD wPort, WORD wProto,
5039dede
AK
1180 const TCHAR *pszRequest, const TCHAR *pszResponse)
1181{
967893bb 1182 UINT32 dwRqId, dwResult;
5039dede 1183 CSCPMessage msg(m_nProtocolVersion), *pResponse;
a0e181dc 1184 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80, 443, 23 };
5039dede
AK
1185
1186 if (!m_bIsConnected)
1187 return ERR_NOT_CONNECTED;
1188
1189 dwRqId = m_dwRequestId++;
1190
1191 msg.SetCode(CMD_CHECK_NETWORK_SERVICE);
1192 msg.SetId(dwRqId);
1193 msg.SetVariable(VID_IP_ADDRESS, dwIpAddr);
1194 msg.SetVariable(VID_SERVICE_TYPE, (WORD)iServiceType);
cc022855 1195 msg.SetVariable(VID_IP_PORT,
1196 (wPort != 0) ? wPort :
1197 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
a0e181dc 1198 (iServiceType <= NETSRV_TELNET)) ? iServiceType : 0]);
5039dede
AK
1199 msg.SetVariable(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
1200 msg.SetVariable(VID_SERVICE_REQUEST, pszRequest);
1201 msg.SetVariable(VID_SERVICE_RESPONSE, pszResponse);
1202
7c521895 1203 if (sendMessage(&msg))
5039dede
AK
1204 {
1205 // Wait up to 90 seconds for results
7c521895 1206 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
5039dede
AK
1207 if (pResponse != NULL)
1208 {
1209 dwResult = pResponse->GetVariableLong(VID_RCC);
1210 if (dwResult == ERR_SUCCESS)
1211 {
1212 *pdwStatus = pResponse->GetVariableLong(VID_SERVICE_STATUS);
1213 }
1214 delete pResponse;
1215 }
1216 else
1217 {
1218 dwResult = ERR_REQUEST_TIMEOUT;
1219 }
1220 }
1221 else
1222 {
1223 dwResult = ERR_CONNECTION_BROKEN;
1224 }
1225
1226 return dwResult;
1227}
1228
074498ac 1229/**
86c126f5 1230 * Get list of supported parameters from agent
074498ac 1231 */
967893bb 1232UINT32 AgentConnection::getSupportedParameters(ObjectArray<AgentParameterDefinition> **paramList, ObjectArray<AgentTableDefinition> **tableList)
5039dede 1233{
967893bb 1234 UINT32 dwRqId, dwResult;
5039dede
AK
1235 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1236
cc8ce218
VK
1237 *paramList = NULL;
1238 *tableList = NULL;
5039dede
AK
1239
1240 if (!m_bIsConnected)
1241 return ERR_NOT_CONNECTED;
1242
1243 dwRqId = m_dwRequestId++;
1244
1245 msg.SetCode(CMD_GET_PARAMETER_LIST);
1246 msg.SetId(dwRqId);
1247
7c521895 1248 if (sendMessage(&msg))
5039dede 1249 {
7c521895 1250 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1251 if (pResponse != NULL)
1252 {
1253 dwResult = pResponse->GetVariableLong(VID_RCC);
cc8ce218 1254 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): RCC=%d"), dwResult);
5039dede
AK
1255 if (dwResult == ERR_SUCCESS)
1256 {
967893bb 1257 UINT32 count = pResponse->GetVariableLong(VID_NUM_PARAMETERS);
86c126f5 1258 ObjectArray<AgentParameterDefinition> *plist = new ObjectArray<AgentParameterDefinition>(count, 16, true);
967893bb 1259 for(UINT32 i = 0, dwId = VID_PARAM_LIST_BASE; i < count; i++)
5039dede 1260 {
86c126f5
VK
1261 plist->add(new AgentParameterDefinition(pResponse, dwId));
1262 dwId += 3;
5039dede 1263 }
86c126f5 1264 *paramList = plist;
cc8ce218
VK
1265 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d parameters received from agent"), count);
1266
1267 count = pResponse->GetVariableLong(VID_NUM_TABLES);
86c126f5 1268 ObjectArray<AgentTableDefinition> *tlist = new ObjectArray<AgentTableDefinition>(count, 16, true);
967893bb 1269 for(UINT32 i = 0, dwId = VID_TABLE_LIST_BASE; i < count; i++)
cc8ce218 1270 {
86c126f5
VK
1271 tlist->add(new AgentTableDefinition(pResponse, dwId));
1272 dwId += 3;
cc8ce218 1273 }
86c126f5 1274 *tableList = tlist;
cc8ce218
VK
1275 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d tables received from agent"), count);
1276 }
5039dede
AK
1277 delete pResponse;
1278 }
1279 else
1280 {
1281 dwResult = ERR_REQUEST_TIMEOUT;
1282 }
1283 }
1284 else
1285 {
1286 dwResult = ERR_CONNECTION_BROKEN;
1287 }
1288
1289 return dwResult;
1290}
1291
074498ac
VK
1292/**
1293 * Setup encryption
1294 */
967893bb 1295UINT32 AgentConnection::setupEncryption(RSA *pServerKey)
5039dede
AK
1296{
1297#ifdef _WITH_ENCRYPTION
1298 CSCPMessage msg(m_nProtocolVersion), *pResp;
967893bb 1299 UINT32 dwRqId, dwError, dwResult;
5039dede
AK
1300
1301 dwRqId = m_dwRequestId++;
1302
9e9d631e 1303 PrepareKeyRequestMsg(&msg, pServerKey, false);
5039dede 1304 msg.SetId(dwRqId);
7c521895 1305 if (sendMessage(&msg))
5039dede 1306 {
7c521895 1307 pResp = waitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
5039dede
AK
1308 if (pResp != NULL)
1309 {
1310 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey, m_nProtocolVersion);
1311 switch(dwResult)
1312 {
1313 case RCC_SUCCESS:
1314 dwError = ERR_SUCCESS;
1315 break;
1316 case RCC_NO_CIPHERS:
1317 dwError = ERR_NO_CIPHERS;
1318 break;
1319 case RCC_INVALID_PUBLIC_KEY:
1320 dwError = ERR_INVALID_PUBLIC_KEY;
1321 break;
1322 case RCC_INVALID_SESSION_KEY:
1323 dwError = ERR_INVALID_SESSION_KEY;
1324 break;
1325 default:
1326 dwError = ERR_INTERNAL_ERROR;
1327 break;
1328 }
1329 delete pResp;
1330 }
1331 else
1332 {
1333 dwError = ERR_REQUEST_TIMEOUT;
1334 }
1335 }
1336 else
1337 {
1338 dwError = ERR_CONNECTION_BROKEN;
1339 }
1340
1341 return dwError;
1342#else
1343 return ERR_NOT_IMPLEMENTED;
1344#endif
1345}
1346
1347
1348//
1349// Get configuration file from agent
1350//
1351
967893bb 1352UINT32 AgentConnection::getConfigFile(TCHAR **ppszConfig, UINT32 *pdwSize)
5039dede 1353{
967893bb 1354 UINT32 i, dwRqId, dwResult;
5039dede
AK
1355 CSCPMessage msg(m_nProtocolVersion), *pResponse;
1356#ifdef UNICODE
1357 BYTE *pBuffer;
1358#endif
1359
1360 *ppszConfig = NULL;
1361 *pdwSize = 0;
1362
1363 if (!m_bIsConnected)
1364 return ERR_NOT_CONNECTED;
1365
1366 dwRqId = m_dwRequestId++;
1367
1368 msg.SetCode(CMD_GET_AGENT_CONFIG);
1369 msg.SetId(dwRqId);
1370
7c521895 1371 if (sendMessage(&msg))
5039dede 1372 {
7c521895 1373 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1374 if (pResponse != NULL)
1375 {
1376 dwResult = pResponse->GetVariableLong(VID_RCC);
1377 if (dwResult == ERR_SUCCESS)
1378 {
1379 *pdwSize = pResponse->GetVariableBinary(VID_CONFIG_FILE, NULL, 0);
1380 *ppszConfig = (TCHAR *)malloc((*pdwSize + 1) * sizeof(TCHAR));
1381#ifdef UNICODE
1382 pBuffer = (BYTE *)malloc(*pdwSize + 1);
1383 pResponse->GetVariableBinary(VID_CONFIG_FILE, pBuffer, *pdwSize);
08b214c6 1384 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char *)pBuffer, *pdwSize, *ppszConfig, *pdwSize);
5039dede
AK
1385 free(pBuffer);
1386#else
1387 pResponse->GetVariableBinary(VID_CONFIG_FILE, (BYTE *)(*ppszConfig), *pdwSize);
1388#endif
1389 (*ppszConfig)[*pdwSize] = 0;
1390
1391 // We expect text file, so replace all non-printable characters with spaces
1392 for(i = 0; i < *pdwSize; i++)
cc022855 1393 if (((*ppszConfig)[i] < _T(' ')) &&
5039dede
AK
1394 ((*ppszConfig)[i] != _T('\t')) &&
1395 ((*ppszConfig)[i] != _T('\r')) &&
1396 ((*ppszConfig)[i] != _T('\n')))
1397 (*ppszConfig)[i] = _T(' ');
1398 }
1399 delete pResponse;
1400 }
1401 else
1402 {
1403 dwResult = ERR_REQUEST_TIMEOUT;
1404 }
1405 }
1406 else
1407 {
1408 dwResult = ERR_CONNECTION_BROKEN;
1409 }
1410
1411 return dwResult;
1412}
1413
1414
1415//
1416// Get configuration file from agent
1417//
1418
967893bb 1419UINT32 AgentConnection::updateConfigFile(const TCHAR *pszConfig)
5039dede 1420{
967893bb 1421 UINT32 dwRqId, dwResult;
5039dede
AK
1422 CSCPMessage msg(m_nProtocolVersion);
1423#ifdef UNICODE
1424 int nChars;
1425 BYTE *pBuffer;
1426#endif
1427
1428 if (!m_bIsConnected)
1429 return ERR_NOT_CONNECTED;
1430
1431 dwRqId = m_dwRequestId++;
1432
1433 msg.SetCode(CMD_UPDATE_AGENT_CONFIG);
1434 msg.SetId(dwRqId);
1435#ifdef UNICODE
465b3f2d 1436 nChars = (int)_tcslen(pszConfig);
5039dede
AK
1437 pBuffer = (BYTE *)malloc(nChars + 1);
1438 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
08b214c6 1439 pszConfig, nChars, (char *)pBuffer, nChars + 1, NULL, NULL);
5039dede
AK
1440 msg.SetVariable(VID_CONFIG_FILE, pBuffer, nChars);
1441 free(pBuffer);
1442#else
967893bb 1443 msg.SetVariable(VID_CONFIG_FILE, (BYTE *)pszConfig, (UINT32)strlen(pszConfig));
5039dede
AK
1444#endif
1445
7c521895 1446 if (sendMessage(&msg))
5039dede 1447 {
7c521895 1448 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1449 }
1450 else
1451 {
1452 dwResult = ERR_CONNECTION_BROKEN;
1453 }
1454
1455 return dwResult;
1456}
1457
1458
1459//
1460// Get routing table from agent
1461//
1462
4687826e 1463ROUTING_TABLE *AgentConnection::getRoutingTable()
5039dede
AK
1464{
1465 ROUTING_TABLE *pRT = NULL;
967893bb 1466 UINT32 i, dwBits;
5039dede
AK
1467 TCHAR *pChar, *pBuf;
1468
4687826e 1469 if (getList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS)
5039dede
AK
1470 {
1471 pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
1472 pRT->iNumEntries = m_dwNumDataLines;
1473 pRT->pRoutes = (ROUTE *)malloc(sizeof(ROUTE) * m_dwNumDataLines);
1474 memset(pRT->pRoutes, 0, sizeof(ROUTE) * m_dwNumDataLines);
1475 for(i = 0; i < m_dwNumDataLines; i++)
1476 {
1477 pBuf = m_ppDataLines[i];
1478
1479 // Destination address and mask
1480 pChar = _tcschr(pBuf, _T(' '));
1481 if (pChar != NULL)
1482 {
1483 TCHAR *pSlash;
1484 static TCHAR defaultMask[] = _T("24");
1485
1486 *pChar = 0;
1487 pSlash = _tcschr(pBuf, _T('/'));
1488 if (pSlash != NULL)
1489 {
1490 *pSlash = 0;
1491 pSlash++;
1492 }
1493 else // Just a paranoia protection, should'n happen if agent working correctly
1494 {
1495 pSlash = defaultMask;
1496 }
1497 pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
1498 dwBits = _tcstoul(pSlash, NULL, 10);
1499 pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
1500 pBuf = pChar + 1;
1501 }
1502
1503 // Next hop address
1504 pChar = _tcschr(pBuf, _T(' '));
1505 if (pChar != NULL)
1506 {
1507 *pChar = 0;
1508 pRT->pRoutes[i].dwNextHop = ntohl(_t_inet_addr(pBuf));
1509 pBuf = pChar + 1;
1510 }
1511
1512 // Interface index
1513 pChar = _tcschr(pBuf, ' ');
1514 if (pChar != NULL)
1515 {
1516 *pChar = 0;
1517 pRT->pRoutes[i].dwIfIndex = _tcstoul(pBuf, NULL, 10);
1518 pBuf = pChar + 1;
1519 }
1520
1521 // Route type
1522 pRT->pRoutes[i].dwRouteType = _tcstoul(pBuf, NULL, 10);
1523 }
1524
a3050773 1525 lock();
7c521895 1526 destroyResultData();
a3050773 1527 unlock();
5039dede
AK
1528 }
1529
1530 return pRT;
1531}
1532
1533
1534//
1535// Set proxy information
1536//
1537
967893bb 1538void AgentConnection::setProxy(UINT32 dwAddr, WORD wPort, int iAuthMethod, const TCHAR *pszSecret)
5039dede
AK
1539{
1540 m_dwProxyAddr = dwAddr;
1541 m_wProxyPort = wPort;
1542 m_iProxyAuth = iAuthMethod;
1543 if (pszSecret != NULL)
1544 {
1545#ifdef UNICODE
cc022855 1546 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
5039dede
AK
1547 pszSecret, -1, m_szProxySecret, MAX_SECRET_LENGTH, NULL, NULL);
1548#else
1549 nx_strncpy(m_szProxySecret, pszSecret, MAX_SECRET_LENGTH);
1550#endif
1551 }
1552 else
1553 {
1554 m_szProxySecret[0] = 0;
1555 }
1556 m_bUseProxy = TRUE;
1557}
1558
1559
1560//
1561// Setup proxy connection
1562//
1563
967893bb 1564UINT32 AgentConnection::setupProxyConnection()
5039dede
AK
1565{
1566 CSCPMessage msg(m_nProtocolVersion);
967893bb 1567 UINT32 dwRqId;
5039dede
AK
1568
1569 dwRqId = m_dwRequestId++;
1570 msg.SetCode(CMD_SETUP_PROXY_CONNECTION);
1571 msg.SetId(dwRqId);
967893bb 1572 msg.SetVariable(VID_IP_ADDRESS, (UINT32)ntohl(m_dwAddr));
5039dede 1573 msg.SetVariable(VID_AGENT_PORT, m_wPort);
7c521895
VK
1574 if (sendMessage(&msg))
1575 return waitForRCC(dwRqId, 60000); // Wait 60 seconds for remote connect
5039dede
AK
1576 else
1577 return ERR_CONNECTION_BROKEN;
1578}
1579
ef8278f0
VK
1580/**
1581 * Enable trap receiving on connection
1582 */
967893bb 1583UINT32 AgentConnection::enableTraps()
5039dede
AK
1584{
1585 CSCPMessage msg(m_nProtocolVersion);
967893bb 1586 UINT32 dwRqId;
5039dede
AK
1587
1588 dwRqId = m_dwRequestId++;
1589 msg.SetCode(CMD_ENABLE_AGENT_TRAPS);
1590 msg.SetId(dwRqId);
7c521895
VK
1591 if (sendMessage(&msg))
1592 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1593 else
1594 return ERR_CONNECTION_BROKEN;
1595}
1596
cc022855 1597/**
1598 * Send custom request to agent
1599 */
76b4edb5 1600CSCPMessage *AgentConnection::customRequest(CSCPMessage *pRequest, const TCHAR *recvFile, bool append, void (*downloadProgressCallback)(size_t, void *),
1601 void (*fileResendCallback)(CSCP_MESSAGE*, void *), void *cbArg)
5039dede 1602{
967893bb 1603 UINT32 dwRqId, rcc;
5039dede
AK
1604 CSCPMessage *msg = NULL;
1605
1606 dwRqId = m_dwRequestId++;
1607 pRequest->SetId(dwRqId);
1608 if (recvFile != NULL)
1609 {
76b4edb5 1610 rcc = prepareFileDownload(recvFile, dwRqId, append, downloadProgressCallback, fileResendCallback,cbArg);
5039dede
AK
1611 if (rcc != ERR_SUCCESS)
1612 {
1613 // Create fake response message
1614 msg = new CSCPMessage;
1615 msg->SetCode(CMD_REQUEST_COMPLETED);
1616 msg->SetId(dwRqId);
1617 msg->SetVariable(VID_RCC, rcc);
1618 }
1619 }
1620
1621 if (msg == NULL)
1622 {
7c521895 1623 if (sendMessage(pRequest))
5039dede 1624 {
7c521895 1625 msg = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1626 if ((msg != NULL) && (recvFile != NULL))
1627 {
1628 if (msg->GetVariableLong(VID_RCC) == ERR_SUCCESS)
1629 {
bb85e341 1630 if (ConditionWait(m_condFileDownload, 1800000)) // 30 min timeout
5039dede 1631 {
bb85e341 1632 if (!m_fileDownloadSucceeded)
5039dede
AK
1633 {
1634 msg->SetVariable(VID_RCC, ERR_IO_FAILURE);
901a5a9b 1635 if (m_deleteFileOnDownloadFailure)
08b214c6 1636 _tremove(recvFile);
5039dede
AK
1637 }
1638 }
1639 else
1640 {
1641 msg->SetVariable(VID_RCC, ERR_REQUEST_TIMEOUT);
1642 }
1643 }
1644 else
1645 {
ef8278f0 1646 if (fileResendCallback != NULL)
76b4edb5 1647 {
1648 close(m_hCurrFile);
1649 m_hCurrFile = -1;
1650 _tremove(recvFile);
1651 }
5039dede
AK
1652 }
1653 }
76b4edb5 1654
5039dede
AK
1655 }
1656 }
1657
1658 return msg;
1659}
1660
76b4edb5 1661/**
ef8278f0 1662 * Prepare for file download
76b4edb5 1663 */
76b4edb5 1664UINT32 AgentConnection::prepareFileDownload(const TCHAR *fileName, UINT32 rqId, bool append, void (*downloadProgressCallback)(size_t, void *),
ef8278f0 1665 void (*fileResendCallback)(CSCP_MESSAGE *, void *), void *cbArg)
5039dede 1666{
ef8278f0 1667 if (fileResendCallback == NULL)
76b4edb5 1668 {
1669 if (m_hCurrFile != -1)
1670 return ERR_RESOURCE_BUSY;
5039dede 1671
76b4edb5 1672 nx_strncpy(m_currentFileName, fileName, MAX_PATH);
1673 ConditionReset(m_condFileDownload);
1674 m_hCurrFile = _topen(fileName, (append ? 0 : (O_CREAT | O_TRUNC)) | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
1675 if (m_hCurrFile == -1)
1676 {
1677 DbgPrintf(4, _T("AgentConnection::PrepareFileDownload(): cannot open file %s (%s); append=%d rqId=%d"),
1678 fileName, _tcserror(errno), append, rqId);
1679 }
1680 else
1681 {
1682 if (append)
1683 lseek(m_hCurrFile, 0, SEEK_END);
1684 }
1685
1686 m_dwDownloadRequestId = rqId;
1687 m_downloadProgressCallback = downloadProgressCallback;
1688 m_downloadProgressCallbackArg = cbArg;
1689
9630fcd1
AK
1690 m_sendToClientMessageCallback = NULL;
1691
76b4edb5 1692 return (m_hCurrFile != -1) ? ERR_SUCCESS : ERR_FILE_OPEN_ERROR;
1693 }
1694 else
1695 {
1696 ConditionReset(m_condFileDownload);
76b4edb5 1697
1698 m_dwDownloadRequestId = rqId;
1699 m_downloadProgressCallback = downloadProgressCallback;
1700 m_downloadProgressCallbackArg = cbArg;
1701
9630fcd1
AK
1702 m_sendToClientMessageCallback = fileResendCallback;
1703
76b4edb5 1704 return ERR_SUCCESS;
1705 }
5039dede
AK
1706}
1707
76b4edb5 1708/**
1709 * File upload completion handler
1710 */
f480bdd4 1711void AgentConnection::onFileDownload(BOOL success)
5039dede 1712{
76b4edb5 1713 if (!success && m_deleteFileOnDownloadFailure)
901a5a9b 1714 _tremove(m_currentFileName);
bb85e341
VK
1715 m_fileDownloadSucceeded = success;
1716 ConditionSet(m_condFileDownload);
5039dede 1717}
1f385e47 1718
ef8278f0
VK
1719/**
1720 * Enable trap receiving on connection
1721 */
967893bb 1722UINT32 AgentConnection::getPolicyInventory(AgentPolicyInfo **info)
1f385e47
VK
1723{
1724 CSCPMessage msg(m_nProtocolVersion);
967893bb 1725 UINT32 dwRqId, rcc;
1f385e47
VK
1726
1727 *info = NULL;
1728 dwRqId = m_dwRequestId++;
1729 msg.SetCode(CMD_GET_POLICY_INVENTORY);
1730 msg.SetId(dwRqId);
1731 if (sendMessage(&msg))
1732 {
1733 CSCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1734 if (response != NULL)
1735 {
1736 rcc = response->GetVariableLong(VID_RCC);
1737 if (rcc == ERR_SUCCESS)
1738 *info = new AgentPolicyInfo(response);
1739 delete response;
1740 }
1741 else
1742 {
1743 rcc = ERR_REQUEST_TIMEOUT;
1744 }
1745 }
1746 else
1747 {
1748 rcc = ERR_CONNECTION_BROKEN;
1749 }
1750 return rcc;
1751}
1752
ef8278f0
VK
1753/**
1754 * Uninstall policy by GUID
1755 */
967893bb 1756UINT32 AgentConnection::uninstallPolicy(uuid_t guid)
1f385e47 1757{
967893bb 1758 UINT32 rqId, rcc;
1f385e47
VK
1759 CSCPMessage msg(m_nProtocolVersion);
1760
1761 rqId = generateRequestId();
1762 msg.SetId(rqId);
1763 msg.SetCode(CMD_UNINSTALL_AGENT_POLICY);
1764 msg.SetVariable(VID_GUID, guid, UUID_LENGTH);
1765 if (sendMessage(&msg))
1766 {
1767 rcc = waitForRCC(rqId, m_dwCommandTimeout);
1768 }
1769 else
1770 {
1771 rcc = ERR_CONNECTION_BROKEN;
1772 }
1773 return rcc;
1774}
98abc9f1 1775
86c126f5
VK
1776/**
1777 * Acquire encryption context
1778 */
98abc9f1
VK
1779NXCPEncryptionContext *AgentConnection::acquireEncryptionContext()
1780{
a3050773 1781 lock();
98abc9f1
VK
1782 NXCPEncryptionContext *ctx = m_pCtx;
1783 if (ctx != NULL)
1784 ctx->incRefCount();
a3050773 1785 unlock();
98abc9f1
VK
1786 return ctx;
1787}
86c126f5
VK
1788
1789/**
1790 * Create new agent parameter definition from NXCP message
1791 */
967893bb 1792AgentParameterDefinition::AgentParameterDefinition(CSCPMessage *msg, UINT32 baseId)
86c126f5
VK
1793{
1794 m_name = msg->GetVariableStr(baseId);
1795 m_description = msg->GetVariableStr(baseId + 1);
1796 m_dataType = (int)msg->GetVariableShort(baseId + 2);
1797}
1798
1799/**
1800 * Create new agent parameter definition from another definition object
1801 */
1802AgentParameterDefinition::AgentParameterDefinition(AgentParameterDefinition *src)
1803{
1804 m_name = (src->m_name != NULL) ? _tcsdup(src->m_name) : NULL;
1805 m_description = (src->m_description != NULL) ? _tcsdup(src->m_description) : NULL;
1806 m_dataType = src->m_dataType;
1807}
1808
1809/**
1810 * Destructor for agent parameter definition
1811 */
1812AgentParameterDefinition::~AgentParameterDefinition()
1813{
1814 safe_free(m_name);
1815 safe_free(m_description);
1816}
1817
1818/**
1819 * Fill NXCP message
1820 */
967893bb 1821UINT32 AgentParameterDefinition::fillMessage(CSCPMessage *msg, UINT32 baseId)
86c126f5
VK
1822{
1823 msg->SetVariable(baseId, m_name);
1824 msg->SetVariable(baseId + 1, m_description);
1825 msg->SetVariable(baseId + 2, (WORD)m_dataType);
1826 return 3;
1827}
1828
1829/**
1830 * Create new agent table definition from NXCP message
1831 */
967893bb 1832AgentTableDefinition::AgentTableDefinition(CSCPMessage *msg, UINT32 baseId)
86c126f5
VK
1833{
1834 m_name = msg->GetVariableStr(baseId);
1835 m_description = msg->GetVariableStr(baseId + 2);
1836
1837 TCHAR *instanceColumns = msg->GetVariableStr(baseId + 1);
1838 if (instanceColumns != NULL)
1839 {
1840 m_instanceColumns = new StringList(instanceColumns, _T("|"));
1841 free(instanceColumns);
1842 }
1843 else
1844 {
1845 m_instanceColumns = new StringList;
1846 }
1847
1848 m_columns = new ObjectArray<AgentTableColumnDefinition>(16, 16, true);
1849}
1850
1851/**
1852 * Create new agent table definition from another definition object
1853 */
1854AgentTableDefinition::AgentTableDefinition(AgentTableDefinition *src)
1855{
1856 m_name = (src->m_name != NULL) ? _tcsdup(src->m_name) : NULL;
1857 m_description = (src->m_description != NULL) ? _tcsdup(src->m_description) : NULL;
1858 m_instanceColumns = new StringList(src->m_instanceColumns);
1859 m_columns = new ObjectArray<AgentTableColumnDefinition>(16, 16, true);
1860 for(int i = 0; i < src->m_columns->size(); i++)
1861 {
1862 m_columns->add(new AgentTableColumnDefinition(src->m_columns->get(i)));
1863 }
1864}
1865/**
1866 * Destructor for agent table definition
1867 */
1868AgentTableDefinition::~AgentTableDefinition()
1869{
1870 safe_free(m_name);
1871 safe_free(m_description);
1872 delete m_instanceColumns;
1873 delete m_columns;
1874}
1875
1876/**
1877 * Fill NXCP message
1878 */
967893bb 1879UINT32 AgentTableDefinition::fillMessage(CSCPMessage *msg, UINT32 baseId)
86c126f5
VK
1880{
1881 msg->SetVariable(baseId + 1, m_name);
1882 msg->SetVariable(baseId + 2, m_description);
1883
1884 TCHAR *instanceColumns = m_instanceColumns->join(_T("|"));
1885 msg->SetVariable(baseId + 3, instanceColumns);
1886 free(instanceColumns);
1887
967893bb 1888 UINT32 varId = baseId + 4;
86c126f5
VK
1889 for(int i = 0; i < m_columns->size(); i++)
1890 {
1891 msg->SetVariable(varId++, m_columns->get(i)->m_name);
1892 msg->SetVariable(varId++, (WORD)m_columns->get(i)->m_dataType);
1893 }
1894
1895 msg->SetVariable(baseId, varId - baseId);
1896 return varId - baseId;
1897}