refactoring of AgentConnection::getList
[public/netxms.git] / src / server / libnxsrv / agent.cpp
CommitLineData
cc022855 1/*
5039dede
AK
2** NetXMS - Network Management System
3** Server Library
d3a20572 4** Copyright (C) 2003-2017 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>
feaad9f8 26#include <nxstat.h>
5039dede 27
feaad9f8 28#ifndef _WIN32
ff198273 29#define _tell(f) lseek(f,0,SEEK_CUR)
f00612ba
VK
30#endif
31
aff47b6a
VK
32#define DEBUG_TAG _T("agent.conn")
33
a3050773
VK
34/**
35 * Constants
36 */
de69178d 37#define MAX_MSG_SIZE 268435456
5039dede 38
a3050773 39/**
1693f955
VK
40 * Agent connection thread pool
41 */
42ThreadPool LIBNXSRV_EXPORTABLE *g_agentConnectionThreadPool = NULL;
43
44/**
aa93afcf
VK
45 * Unique connection ID
46 */
47static VolatileCounter s_connectionId = 0;
48
49/**
a3050773
VK
50 * Static data
51 */
5039dede
AK
52#ifdef _WITH_ENCRYPTION
53static int m_iDefaultEncryptionPolicy = ENCRYPTION_ALLOWED;
54#else
55static int m_iDefaultEncryptionPolicy = ENCRYPTION_DISABLED;
56#endif
57
a3050773
VK
58/**
59 * Set default encryption policy for agent communication
60 */
5039dede
AK
61void LIBNXSRV_EXPORTABLE SetAgentDEP(int iPolicy)
62{
63#ifdef _WITH_ENCRYPTION
64 m_iDefaultEncryptionPolicy = iPolicy;
65#endif
66}
67
a3050773
VK
68/**
69 * Receiver thread starter
70 */
71THREAD_RESULT THREAD_CALL AgentConnection::receiverThreadStarter(void *pArg)
5039dede 72{
930a2a62 73 ThreadSetName("AgentReceiver");
a3050773 74 ((AgentConnection *)pArg)->receiverThread();
a87ef571 75 ((AgentConnection *)pArg)->decInternalRefCount();
5039dede
AK
76 return THREAD_OK;
77}
78
a3050773
VK
79/**
80 * Constructor for AgentConnection
81 */
2f6c6597 82AgentConnection::AgentConnection(const InetAddress& addr, WORD port, int authMethod, const TCHAR *secret, bool allowCompression)
5039dede 83{
a87ef571
VK
84 m_internalRefCount = 1;
85 m_userRefCount = 1;
aff47b6a 86 m_debugId = InterlockedIncrement(&s_connectionId);
c11eee9b 87 m_addr = addr;
69c6604d
VK
88 m_wPort = port;
89 m_iAuthMethod = authMethod;
90 if (secret != NULL)
5039dede
AK
91 {
92#ifdef UNICODE
69c6604d 93 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, secret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
08b214c6 94 m_szSecret[MAX_SECRET_LENGTH - 1] = 0;
5039dede 95#else
69c6604d 96 nx_strncpy(m_szSecret, secret, MAX_SECRET_LENGTH);
5039dede
AK
97#endif
98 }
99 else
100 {
101 m_szSecret[0] = 0;
102 }
9674aefa 103 m_allowCompression = allowCompression;
e3ff8ad1 104 m_channel = NULL;
5039dede 105 m_tLastCommandTime = 0;
5039dede 106 m_pMsgWaitQueue = new MsgWaitQueue;
e9902466 107 m_requestId = 0;
a01c2a20
VK
108 m_connectionTimeout = 5000; // 5 seconds
109 m_dwCommandTimeout = 5000; // Default timeout 5 seconds
9fd816cc 110 m_isConnected = false;
5039dede 111 m_mutexDataLock = MutexCreate();
d3a7cf4c 112 m_mutexSocketWrite = MutexCreate();
5039dede
AK
113 m_hReceiverThread = INVALID_THREAD_HANDLE;
114 m_pCtx = NULL;
115 m_iEncryptionPolicy = m_iDefaultEncryptionPolicy;
ed83ffcd 116 m_useProxy = false;
ec13a467 117 m_iProxyAuth = AUTH_NONE;
1693f955 118 m_wProxyPort = 4700;
5039dede
AK
119 m_dwRecvTimeout = 420000; // 7 minutes
120 m_nProtocolVersion = NXCP_VERSION;
121 m_hCurrFile = -1;
76b4edb5 122 m_deleteFileOnDownloadFailure = true;
bb85e341 123 m_condFileDownload = ConditionCreate(TRUE);
1693f955 124 m_fileDownloadSucceeded = false;
4685a2ad 125 m_fileUploadInProgress = false;
9630fcd1 126 m_sendToClientMessageCallback = NULL;
1693f955
VK
127 m_dwDownloadRequestId = 0;
128 m_downloadProgressCallback = NULL;
129 m_downloadProgressCallbackArg = NULL;
5039dede
AK
130}
131
a3050773
VK
132/**
133 * Destructor
134 */
5039dede
AK
135AgentConnection::~AgentConnection()
136{
aa93afcf 137 debugPrintf(7, _T("AgentConnection destructor called (this=%p, thread=%p)"), this, (void *)m_hReceiverThread);
1693f955 138
a87ef571 139 ThreadDetach(m_hReceiverThread);
5039dede 140
5039dede 141 delete m_pMsgWaitQueue;
98abc9f1
VK
142 if (m_pCtx != NULL)
143 m_pCtx->decRefCount();
5039dede
AK
144
145 if (m_hCurrFile != -1)
9f6d453a 146 {
feaad9f8 147 _close(m_hCurrFile);
1693f955 148 onFileDownload(false);
9f6d453a 149 }
62432449
VK
150 else if (m_sendToClientMessageCallback != NULL)
151 {
152 onFileDownload(false);
153 }
5039dede 154
ddfd039e
VK
155 if (m_channel != NULL)
156 m_channel->decRefCount();
157
5039dede 158 MutexDestroy(m_mutexDataLock);
d3a7cf4c 159 MutexDestroy(m_mutexSocketWrite);
bb85e341 160 ConditionDestroy(m_condFileDownload);
5039dede
AK
161}
162
a3050773 163/**
aa93afcf 164 * Write debug output
a3050773 165 */
aa93afcf 166void AgentConnection::debugPrintf(int level, const TCHAR *format, ...)
5039dede 167{
aa93afcf 168 va_list args;
af21affe 169 va_start(args, format);
aff47b6a 170 nxlog_debug_tag_object2(DEBUG_TAG, m_debugId, level, format, args);
5039dede 171 va_end(args);
5039dede
AK
172}
173
a3050773
VK
174/**
175 * Receiver thread
176 */
177void AgentConnection::receiverThread()
5039dede 178{
ddfd039e 179 AbstractCommChannel *channel = m_channel;
e3ff8ad1 180 UINT32 msgBufferSize = 1024;
5039dede
AK
181
182 // Initialize raw message receiving function
e3ff8ad1 183 NXCP_BUFFER *msgBuffer = (NXCP_BUFFER *)malloc(sizeof(NXCP_BUFFER));
efe30b82 184 NXCPInitBuffer(msgBuffer);
5039dede
AK
185
186 // Allocate space for raw message
e3ff8ad1 187 NXCP_MESSAGE *rawMsg = (NXCP_MESSAGE *)malloc(msgBufferSize);
5039dede 188#ifdef _WITH_ENCRYPTION
e3ff8ad1
VK
189 BYTE *decryptionBuffer = (BYTE *)malloc(msgBufferSize);
190#else
191 BYTE *decryptionBuffer = NULL;
5039dede
AK
192#endif
193
e3ff8ad1 194 while(true)
5039dede 195 {
e3ff8ad1
VK
196 // Shrink buffer after receiving large message
197 if (msgBufferSize > 131072)
198 {
199 msgBufferSize = 131072;
200 rawMsg = (NXCP_MESSAGE *)realloc(rawMsg, msgBufferSize);
201 if (decryptionBuffer != NULL)
202 decryptionBuffer = (BYTE *)realloc(decryptionBuffer, msgBufferSize);
203 }
8f4f648d 204
5039dede 205 // Receive raw message
ddfd039e 206 int rc = RecvNXCPMessageEx(channel, &rawMsg, msgBuffer, &msgBufferSize,
e3ff8ad1
VK
207 &m_pCtx, (decryptionBuffer != NULL) ? &decryptionBuffer : NULL,
208 m_dwRecvTimeout, MAX_MSG_SIZE);
209 if (rc <= 0)
210 {
211 if ((rc != 0) && (WSAGetLastError() != WSAESHUTDOWN))
aa93afcf 212 debugPrintf(6, _T("AgentConnection::ReceiverThread(): RecvNXCPMessage() failed: error=%d, socket_error=%d"), rc, WSAGetLastError());
35a9f4a3
VK
213 else
214 debugPrintf(6, _T("AgentConnection::ReceiverThread(): communication channel shutdown"));
5039dede 215 break;
e3ff8ad1 216 }
5039dede
AK
217
218 // Check if we get too large message
e3ff8ad1 219 if (rc == 1)
5039dede 220 {
e3ff8ad1 221 TCHAR buffer[64];
aa93afcf 222 debugPrintf(6, _T("Received too large message %s (%d bytes)"), NXCPMessageCodeName(ntohs(rawMsg->code), buffer), ntohl(rawMsg->size));
5039dede
AK
223 continue;
224 }
225
226 // Check if we are unable to decrypt message
e3ff8ad1 227 if (rc == 2)
5039dede 228 {
aa93afcf 229 debugPrintf(6, _T("Unable to decrypt received message"));
5039dede
AK
230 continue;
231 }
232
233 // Check for timeout
e3ff8ad1 234 if (rc == 3)
5039dede 235 {
e3ff8ad1
VK
236 if (m_fileUploadInProgress)
237 continue; // Receive timeout may occur when uploading large files via slow links
aa93afcf 238 debugPrintf(6, _T("Timed out waiting for message"));
5039dede
AK
239 break;
240 }
241
242 // Check that actual received packet size is equal to encoded in packet
e3ff8ad1 243 if ((int)ntohl(rawMsg->size) != rc)
5039dede 244 {
aa93afcf 245 debugPrintf(6, _T("RecvMsg: Bad packet length [size=%d ActualSize=%d]"), ntohl(rawMsg->size), rc);
5039dede
AK
246 continue; // Bad packet, wait for next
247 }
248
e3ff8ad1
VK
249 if (ntohs(rawMsg->flags) & MF_BINARY)
250 {
5039dede 251 // Convert message header to host format
e3ff8ad1
VK
252 rawMsg->id = ntohl(rawMsg->id);
253 rawMsg->code = ntohs(rawMsg->code);
254 rawMsg->numFields = ntohl(rawMsg->numFields);
aff47b6a 255 if (nxlog_get_debug_level_tag_object(DEBUG_TAG, m_debugId) >= 6)
e3ff8ad1
VK
256 {
257 TCHAR buffer[64];
35a9f4a3
VK
258 debugPrintf(6, _T("Received raw message %s (%d) from agent at %s"),
259 NXCPMessageCodeName(rawMsg->code, buffer), rawMsg->id, (const TCHAR *)m_addr.toString());
e3ff8ad1 260 }
5039dede 261
e3ff8ad1
VK
262 if ((rawMsg->code == CMD_FILE_DATA) && (rawMsg->id == m_dwDownloadRequestId))
263 {
76b4edb5 264 if (m_sendToClientMessageCallback != NULL)
5039dede 265 {
e3ff8ad1
VK
266 rawMsg->code = ntohs(rawMsg->code);
267 rawMsg->numFields = ntohl(rawMsg->numFields);
268 m_sendToClientMessageCallback(rawMsg, m_downloadProgressCallbackArg);
76b4edb5 269
e3ff8ad1 270 if (ntohs(rawMsg->flags) & MF_END_OF_FILE)
5039dede 271 {
62432449 272 m_sendToClientMessageCallback = NULL;
1693f955 273 onFileDownload(true);
5039dede 274 }
76b4edb5 275 else
276 {
277 if (m_downloadProgressCallback != NULL)
278 {
e3ff8ad1 279 m_downloadProgressCallback(rawMsg->size - (NXCP_HEADER_SIZE + 8), m_downloadProgressCallbackArg);
76b4edb5 280 }
281 }
5039dede
AK
282 }
283 else
284 {
76b4edb5 285 if (m_hCurrFile != -1)
286 {
e3ff8ad1 287 if (_write(m_hCurrFile, rawMsg->fields, rawMsg->numFields) == (int)rawMsg->numFields)
76b4edb5 288 {
e3ff8ad1 289 if (ntohs(rawMsg->flags) & MF_END_OF_FILE)
76b4edb5 290 {
feaad9f8 291 _close(m_hCurrFile);
76b4edb5 292 m_hCurrFile = -1;
293
1693f955 294 onFileDownload(true);
76b4edb5 295 }
296 else
297 {
298 if (m_downloadProgressCallback != NULL)
299 {
300 m_downloadProgressCallback(_tell(m_hCurrFile), m_downloadProgressCallbackArg);
301 }
302 }
303 }
304 }
305 else
306 {
307 // I/O error
feaad9f8 308 _close(m_hCurrFile);
76b4edb5 309 m_hCurrFile = -1;
cc022855 310
1693f955 311 onFileDownload(false);
76b4edb5 312 }
5039dede 313 }
e3ff8ad1 314 }
9a895fd6 315
e3ff8ad1
VK
316 if ((rawMsg->code == CMD_ABORT_FILE_TRANSFER) && (rawMsg->id == m_dwDownloadRequestId))
317 {
9a895fd6 318 if (m_sendToClientMessageCallback != NULL)
319 {
e3ff8ad1
VK
320 rawMsg->code = ntohs(rawMsg->code);
321 rawMsg->numFields = ntohl(rawMsg->numFields);
322 m_sendToClientMessageCallback(rawMsg, m_downloadProgressCallbackArg);
62432449 323 m_sendToClientMessageCallback = NULL;
9a895fd6 324
1693f955 325 onFileDownload(false);
9a895fd6 326 }
327 else
328 {
329 //error on agent side
feaad9f8 330 _close(m_hCurrFile);
9a895fd6 331 m_hCurrFile = -1;
332
1693f955 333 onFileDownload(false);
9a895fd6 334 }
e3ff8ad1
VK
335 }
336 }
aa93afcf
VK
337 else if (ntohs(rawMsg->flags) & MF_CONTROL)
338 {
339 // Convert message header to host format
340 rawMsg->id = ntohl(rawMsg->id);
341 rawMsg->code = ntohs(rawMsg->code);
342 rawMsg->flags = ntohs(rawMsg->flags);
343 rawMsg->numFields = ntohl(rawMsg->numFields);
aff47b6a 344 if (nxlog_get_debug_level_tag_object(DEBUG_TAG, m_debugId) >= 6)
aa93afcf
VK
345 {
346 TCHAR buffer[64];
347 debugPrintf(6, _T("Received control message %s from agent at %s"),
348 NXCPMessageCodeName(rawMsg->code, buffer), (const TCHAR *)m_addr.toString());
349 }
f8a3b35a 350 m_pMsgWaitQueue->put((NXCP_MESSAGE *)nx_memdup(rawMsg, ntohl(rawMsg->size)));
aa93afcf 351 }
e3ff8ad1
VK
352 else
353 {
354 // Create message object from raw message
198745dd
VK
355 NXCPMessage *msg = NXCPMessage::deserialize(rawMsg, m_nProtocolVersion);
356 if (msg != NULL)
35a9f4a3 357 {
aff47b6a 358 if (nxlog_get_debug_level_tag_object(DEBUG_TAG, m_debugId) >= 6)
198745dd
VK
359 {
360 TCHAR buffer[64];
361 debugPrintf(6, _T("Received message %s (%d) from agent at %s"),
362 NXCPMessageCodeName(msg->getCode(), buffer), msg->getId(), (const TCHAR *)m_addr.toString());
363 }
364 switch(msg->getCode())
365 {
366 case CMD_REQUEST_COMPLETED:
367 case CMD_SESSION_KEY:
368 m_pMsgWaitQueue->put(msg);
369 break;
370 case CMD_TRAP:
371 if (g_agentConnectionThreadPool != NULL)
372 {
373 incInternalRefCount();
374 ThreadPoolExecute(g_agentConnectionThreadPool, this, &AgentConnection::onTrapCallback, msg);
375 }
376 else
377 {
378 delete msg;
379 }
380 break;
381 case CMD_SYSLOG_RECORDS:
382 if (g_agentConnectionThreadPool != NULL)
383 {
384 incInternalRefCount();
385 ThreadPoolExecute(g_agentConnectionThreadPool, this, &AgentConnection::onSyslogMessageCallback, msg);
386 }
387 else
388 {
389 delete msg;
390 }
391 break;
392 case CMD_PUSH_DCI_DATA:
393 if (g_agentConnectionThreadPool != NULL)
394 {
395 incInternalRefCount();
396 ThreadPoolExecute(g_agentConnectionThreadPool, this, &AgentConnection::onDataPushCallback, msg);
397 }
398 else
399 {
400 delete msg;
401 }
402 break;
403 case CMD_DCI_DATA:
404 if (g_agentConnectionThreadPool != NULL)
405 {
406 incInternalRefCount();
407 ThreadPoolExecute(g_agentConnectionThreadPool, this, &AgentConnection::processCollectedDataCallback, msg);
408 }
409 else
410 {
411 NXCPMessage response;
412 response.setCode(CMD_REQUEST_COMPLETED);
413 response.setId(msg->getId());
414 response.setField(VID_RCC, ERR_INTERNAL_ERROR);
415 sendMessage(&response);
416 delete msg;
417 }
418 break;
419 case CMD_FILE_MONITORING:
420 onFileMonitoringData(msg);
421 delete msg;
422 break;
423 case CMD_SNMP_TRAP:
424 if (g_agentConnectionThreadPool != NULL)
425 {
426 incInternalRefCount();
427 ThreadPoolExecute(g_agentConnectionThreadPool, this, &AgentConnection::onSnmpTrapCallback, msg);
428 }
429 else
430 {
431 delete msg;
432 }
433 break;
434 default:
435 if (processCustomMessage(msg))
436 delete msg;
437 else
438 m_pMsgWaitQueue->put(msg);
439 break;
440 }
35a9f4a3 441 }
198745dd 442 else
e3ff8ad1 443 {
198745dd 444 debugPrintf(6, _T("RecvMsg: message deserialization error"));
e3ff8ad1
VK
445 }
446 }
5039dede 447 }
35a9f4a3 448 debugPrintf(6, _T("Receiver loop terminated"));
5039dede
AK
449
450 // Close socket and mark connection as disconnected
a3050773 451 lock();
f2665675
VK
452 if (m_hCurrFile != -1)
453 {
feaad9f8 454 _close(m_hCurrFile);
f2665675 455 m_hCurrFile = -1;
1693f955 456 onFileDownload(false);
f2665675 457 }
62432449
VK
458 else if (m_sendToClientMessageCallback != NULL)
459 {
460 m_sendToClientMessageCallback = NULL;
461 onFileDownload(false);
462 }
cc022855 463
35a9f4a3 464 debugPrintf(6, _T("Closing communication channel"));
ddfd039e
VK
465 channel->close();
466 channel->decRefCount();
98abc9f1
VK
467 if (m_pCtx != NULL)
468 {
469 m_pCtx->decRefCount();
470 m_pCtx = NULL;
471 }
9fd816cc 472 m_isConnected = false;
a3050773 473 unlock();
f8a3b35a
VK
474
475 free(rawMsg);
476 free(msgBuffer);
477#ifdef _WITH_ENCRYPTION
478 free(decryptionBuffer);
479#endif
480
481 debugPrintf(6, _T("Receiver thread stopped"));
e3ff8ad1 482}
5039dede 483
e3ff8ad1
VK
484/**
485 * Create channel. Default implementation creates socket channel.
486 */
487AbstractCommChannel *AgentConnection::createChannel()
488{
489 // Create socket
ed83ffcd 490 SOCKET s = socket(m_useProxy ? m_proxyAddr.getFamily() : m_addr.getFamily(), SOCK_STREAM, 0);
e3ff8ad1
VK
491 if (s == INVALID_SOCKET)
492 {
aa93afcf 493 debugPrintf(6, _T("Call to socket() failed"));
e3ff8ad1
VK
494 return NULL;
495 }
496
497 // Fill in address structure
498 SockAddrBuffer sb;
ed83ffcd 499 struct sockaddr *sa = m_useProxy ? m_proxyAddr.fillSockAddr(&sb, m_wProxyPort) : m_addr.fillSockAddr(&sb, m_wPort);
e3ff8ad1
VK
500
501 // Connect to server
502 if ((sa == NULL) || (ConnectEx(s, sa, SA_LEN(sa), m_connectionTimeout) == -1))
503 {
504 TCHAR buffer[64];
aa93afcf 505 debugPrintf(5, _T("Cannot establish connection with agent at %s:%d"),
ed83ffcd
VK
506 m_useProxy ? m_proxyAddr.toString(buffer) : m_addr.toString(buffer),
507 (int)(m_useProxy ? m_wProxyPort : m_wPort));
e3ff8ad1
VK
508 closesocket(s);
509 return NULL;
510 }
511
512 return new SocketCommChannel(s);
5039dede
AK
513}
514
a3050773 515/**
98f0ac42
VK
516 * Acquire communication channel. Caller must call decRefCount to release channel.
517 */
518AbstractCommChannel *AgentConnection::acquireChannel()
519{
520 lock();
521 AbstractCommChannel *channel = m_channel;
522 if (channel != NULL)
523 channel->incRefCount();
524 unlock();
525 return channel;
526}
527
528/**
a3050773
VK
529 * Connect to agent
530 */
e3ff8ad1 531bool AgentConnection::connect(RSA *pServerKey, UINT32 *pdwError, UINT32 *pdwSocketError, UINT64 serverId)
5039dede 532{
5039dede 533 TCHAR szBuffer[256];
9fd816cc
VK
534 bool success = false;
535 bool forceEncryption = false;
536 bool secondPass = false;
967893bb 537 UINT32 dwError = 0;
5039dede
AK
538
539 if (pdwError != NULL)
540 *pdwError = ERR_INTERNAL_ERROR;
541
c3acd0f6
VK
542 if (pdwSocketError != NULL)
543 *pdwSocketError = 0;
544
5039dede 545 // Check if already connected
9fd816cc
VK
546 if (m_isConnected)
547 return false;
5039dede
AK
548
549 // Wait for receiver thread from previous connection, if any
550 ThreadJoin(m_hReceiverThread);
551 m_hReceiverThread = INVALID_THREAD_HANDLE;
552
e3ff8ad1
VK
553 // Check if we need to close existing channel
554 if (m_channel != NULL)
5039dede 555 {
e3ff8ad1
VK
556 m_channel->decRefCount();
557 m_channel = NULL;
5039dede
AK
558 }
559
e3ff8ad1
VK
560 m_channel = createChannel();
561 if (m_channel == NULL)
5039dede 562 {
aa93afcf 563 debugPrintf(6, _T("Cannot create communication channel"));
5039dede
AK
564 dwError = ERR_CONNECT_FAILED;
565 goto connect_cleanup;
566 }
567
e3ff8ad1 568 if (!NXCPGetPeerProtocolVersion(m_channel, &m_nProtocolVersion, m_mutexSocketWrite))
5039dede 569 {
aa93afcf 570 debugPrintf(6, _T("Protocol version negotiation failed"));
5039dede
AK
571 dwError = ERR_INTERNAL_ERROR;
572 goto connect_cleanup;
573 }
aa93afcf 574 debugPrintf(6, _T("Using NXCP version %d"), m_nProtocolVersion);
5039dede
AK
575
576 // Start receiver thread
a87ef571 577 incInternalRefCount();
ddfd039e 578 m_channel->incRefCount(); // for receiver thread
a3050773 579 m_hReceiverThread = ThreadCreateEx(receiverThreadStarter, 0, this);
5039dede
AK
580
581 // Setup encryption
582setup_encryption:
583 if ((m_iEncryptionPolicy == ENCRYPTION_PREFERRED) ||
584 (m_iEncryptionPolicy == ENCRYPTION_REQUIRED) ||
9fd816cc 585 forceEncryption) // Agent require encryption
5039dede
AK
586 {
587 if (pServerKey != NULL)
588 {
7c521895 589 dwError = setupEncryption(pServerKey);
5039dede 590 if ((dwError != ERR_SUCCESS) &&
9fd816cc 591 ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || forceEncryption))
5039dede
AK
592 goto connect_cleanup;
593 }
594 else
595 {
9fd816cc 596 if ((m_iEncryptionPolicy == ENCRYPTION_REQUIRED) || forceEncryption)
5039dede
AK
597 {
598 dwError = ERR_ENCRYPTION_REQUIRED;
599 goto connect_cleanup;
600 }
601 }
602 }
603
604 // Authenticate itself to agent
ed83ffcd 605 if ((dwError = authenticate(m_useProxy && !secondPass)) != ERR_SUCCESS)
5039dede
AK
606 {
607 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
608 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
609 {
9fd816cc 610 forceEncryption = true;
5039dede
AK
611 goto setup_encryption;
612 }
aa93afcf 613 debugPrintf(5, _T("Authentication to agent %s failed (%s)"), m_addr.toString(szBuffer),
5039dede
AK
614 AgentErrorCodeToText(dwError));
615 goto connect_cleanup;
616 }
617
1a5ddd2a
VK
618 // Test connectivity and inform agent about server capabilities
619 if ((dwError = setServerCapabilities()) != ERR_SUCCESS)
5039dede
AK
620 {
621 if ((dwError == ERR_ENCRYPTION_REQUIRED) &&
622 (m_iEncryptionPolicy != ENCRYPTION_DISABLED))
623 {
9fd816cc 624 forceEncryption = true;
5039dede
AK
625 goto setup_encryption;
626 }
6de2ec52
VK
627 if (dwError != ERR_UNKNOWN_COMMAND) // Older agents may not support enable IPv6 command
628 {
aa93afcf 629 debugPrintf(5, _T("Communication with agent %s failed (%s)"), m_addr.toString(szBuffer), AgentErrorCodeToText(dwError));
6de2ec52
VK
630 goto connect_cleanup;
631 }
5039dede
AK
632 }
633
ed83ffcd 634 if (m_useProxy && !secondPass)
5039dede 635 {
7c521895 636 dwError = setupProxyConnection();
5039dede
AK
637 if (dwError != ERR_SUCCESS)
638 goto connect_cleanup;
a3050773 639 lock();
98abc9f1
VK
640 if (m_pCtx != NULL)
641 {
642 m_pCtx->decRefCount();
643 m_pCtx = NULL;
644 }
a3050773 645 unlock();
217f041b 646
aa93afcf
VK
647 debugPrintf(6, _T("Proxy connection established"));
648
217f041b 649 // Renegotiate NXCP version with actual target agent
aa93afcf 650 NXCP_MESSAGE msg;
aa93afcf
VK
651 msg.id = 0;
652 msg.numFields = 0;
653 msg.size = htonl(NXCP_HEADER_SIZE);
654 msg.code = htons(CMD_GET_NXCP_CAPS);
655 msg.flags = htons(MF_CONTROL);
656 if (m_channel->send(&msg, NXCP_HEADER_SIZE, m_mutexSocketWrite) == NXCP_HEADER_SIZE)
217f041b 657 {
aa93afcf
VK
658 NXCP_MESSAGE *rsp = m_pMsgWaitQueue->waitForRawMessage(CMD_NXCP_CAPS, 0, m_dwCommandTimeout);
659 if (rsp != NULL)
660 {
661 m_nProtocolVersion = rsp->numFields >> 24;
f8a3b35a 662 free(rsp);
aa93afcf
VK
663 }
664 else
665 {
666 // assume that peer doesn't understand CMD_GET_NXCP_CAPS message
667 // and set version number to 1
aa93afcf
VK
668 m_nProtocolVersion = 1;
669 }
670 debugPrintf(6, _T("Using NXCP version %d after re-negotioation"), m_nProtocolVersion);
671 }
672 else
673 {
674 debugPrintf(6, _T("Protocol version re-negotiation failed - cannot send CMD_GET_NXCP_CAPS message"));
675 dwError = ERR_CONNECTION_BROKEN;
676 goto connect_cleanup;
217f041b
VK
677 }
678
9fd816cc
VK
679 secondPass = true;
680 forceEncryption = false;
5039dede
AK
681 goto setup_encryption;
682 }
683
9674aefa 684 if (serverId != 0)
7f6ecb6d
TD
685 setServerId(serverId);
686
9fd816cc 687 success = true;
5039dede
AK
688 dwError = ERR_SUCCESS;
689
690connect_cleanup:
9fd816cc 691 if (!success)
5039dede 692 {
c3acd0f6 693 if (pdwSocketError != NULL)
967893bb 694 *pdwSocketError = (UINT32)WSAGetLastError();
c3acd0f6 695
a3050773 696 lock();
e3ff8ad1
VK
697 if (m_channel != NULL)
698 m_channel->shutdown();
a3050773 699 unlock();
5039dede
AK
700 ThreadJoin(m_hReceiverThread);
701 m_hReceiverThread = INVALID_THREAD_HANDLE;
702
a3050773 703 lock();
e3ff8ad1 704 if (m_channel != NULL)
5039dede 705 {
e3ff8ad1 706 m_channel->close();
ddfd039e 707 m_channel->decRefCount();
e3ff8ad1 708 m_channel = NULL;
5039dede
AK
709 }
710
98abc9f1
VK
711 if (m_pCtx != NULL)
712 {
713 m_pCtx->decRefCount();
714 m_pCtx = NULL;
715 }
5039dede 716
a3050773 717 unlock();
5039dede 718 }
9fd816cc 719 m_isConnected = success;
5039dede
AK
720 if (pdwError != NULL)
721 *pdwError = dwError;
9fd816cc 722 return success;
5039dede
AK
723}
724
af21affe
VK
725/**
726 * Disconnect from agent
727 */
7c521895 728void AgentConnection::disconnect()
5039dede 729{
f8a3b35a 730 debugPrintf(6, _T("disconnect() called"));
a3050773 731 lock();
f2665675
VK
732 if (m_hCurrFile != -1)
733 {
feaad9f8 734 _close(m_hCurrFile);
f2665675 735 m_hCurrFile = -1;
1693f955 736 onFileDownload(false);
f2665675 737 }
62432449
VK
738 else if (m_sendToClientMessageCallback != NULL)
739 {
740 m_sendToClientMessageCallback = NULL;
741 onFileDownload(false);
742 }
9fa031cd 743
e3ff8ad1 744 if (m_channel != NULL)
5039dede 745 {
e3ff8ad1 746 m_channel->shutdown();
ddfd039e
VK
747 m_channel->decRefCount();
748 m_channel = NULL;
5039dede 749 }
9fd816cc 750 m_isConnected = false;
a3050773 751 unlock();
f8a3b35a 752 debugPrintf(6, _T("Disconnect completed"));
5039dede
AK
753}
754
af21affe
VK
755/**
756 * Set authentication data
757 */
758void AgentConnection::setAuthData(int method, const TCHAR *secret)
cc022855 759{
af21affe
VK
760 m_iAuthMethod = method;
761#ifdef UNICODE
762 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, secret, -1, m_szSecret, MAX_SECRET_LENGTH, NULL, NULL);
763 m_szSecret[MAX_SECRET_LENGTH - 1] = 0;
764#else
765 nx_strncpy(m_szSecret, secret, MAX_SECRET_LENGTH);
766#endif
767}
5039dede 768
af21affe 769/**
d51f2182
VK
770 * Get interface list from agent
771 */
98762401 772InterfaceList *AgentConnection::getInterfaceList()
5039dede 773{
6a777a32
VK
774 StringList *data;
775 if (getList(_T("Net.InterfaceList"), &data) != ERR_SUCCESS)
776 return NULL;
5039dede 777
6a777a32
VK
778 InterfaceList *pIfList = new InterfaceList(data->size());
779
780 // Parse result set. Each line should have the following format:
781 // index ip_address/mask_bits iftype mac_address name
782 for(int i = 0; i < data->size(); i++)
5039dede 783 {
6a777a32
VK
784 TCHAR *line = _tcsdup(data->get(i));
785 TCHAR *pBuf = line;
786 UINT32 ifIndex = 0;
5039dede 787
6a777a32
VK
788 // Index
789 TCHAR *pChar = _tcschr(pBuf, ' ');
790 if (pChar != NULL)
5039dede 791 {
6a777a32
VK
792 *pChar = 0;
793 ifIndex = _tcstoul(pBuf, NULL, 10);
794 pBuf = pChar + 1;
795 }
5039dede 796
6a777a32
VK
797 bool newInterface = false;
798 InterfaceInfo *iface = pIfList->findByIfIndex(ifIndex);
799 if (iface == NULL)
800 {
801 iface = new InterfaceInfo(ifIndex);
802 newInterface = true;
803 }
804
805 // Address and mask
806 pChar = _tcschr(pBuf, _T(' '));
807 if (pChar != NULL)
808 {
809 TCHAR *pSlash;
810 static TCHAR defaultMask[] = _T("24");
811
812 *pChar = 0;
813 pSlash = _tcschr(pBuf, _T('/'));
814 if (pSlash != NULL)
5039dede 815 {
6a777a32
VK
816 *pSlash = 0;
817 pSlash++;
5039dede 818 }
6a777a32 819 else // Just a paranoia protection, should'n happen if agent working correctly
2ffad7c2 820 {
6a777a32 821 pSlash = defaultMask;
2ffad7c2 822 }
6a777a32
VK
823 InetAddress addr = InetAddress::parse(pBuf);
824 if (addr.isValid())
5039dede 825 {
6a777a32
VK
826 addr.setMaskBits(_tcstol(pSlash, NULL, 10));
827 // Agent may return 0.0.0.0/0 for interfaces without IP address
828 if ((addr.getFamily() != AF_INET) || (addr.getAddressV4() != 0))
829 iface->ipAddrList.add(addr);
5039dede 830 }
6a777a32
VK
831 pBuf = pChar + 1;
832 }
5039dede 833
6a777a32
VK
834 if (newInterface)
835 {
836 // Interface type
837 pChar = _tcschr(pBuf, ' ');
838 if (pChar != NULL)
5039dede 839 {
6a777a32 840 *pChar = 0;
33560996 841
6a777a32
VK
842 TCHAR *eptr;
843 iface->type = _tcstoul(pBuf, &eptr, 10);
e13420c1 844
6a777a32
VK
845 // newer agents can return if_type(mtu)
846 if (*eptr == _T('('))
847 {
848 pBuf = eptr + 1;
849 eptr = _tcschr(pBuf, _T(')'));
850 if (eptr != NULL)
33560996 851 {
6a777a32
VK
852 *eptr = 0;
853 iface->mtu = _tcstol(pBuf, NULL, 10);
33560996 854 }
2ffad7c2 855 }
5039dede 856
6a777a32
VK
857 pBuf = pChar + 1;
858 }
98762401 859
6a777a32
VK
860 // MAC address
861 pChar = _tcschr(pBuf, ' ');
862 if (pChar != NULL)
863 {
864 *pChar = 0;
865 StrToBin(pBuf, iface->macAddr, MAC_ADDR_LENGTH);
866 pBuf = pChar + 1;
2ffad7c2 867 }
5039dede 868
6a777a32
VK
869 // Name (set description to name)
870 _tcslcpy(iface->name, pBuf, MAX_DB_STRING);
871 _tcslcpy(iface->description, pBuf, MAX_DB_STRING);
872
873 pIfList->add(iface);
874 }
875 free(line);
5039dede
AK
876 }
877
6a777a32 878 delete data;
5039dede
AK
879 return pIfList;
880}
881
489b117b 882/**
883 * Get parameter value
884 */
967893bb 885UINT32 AgentConnection::getParameter(const TCHAR *pszParam, UINT32 dwBufSize, TCHAR *pszBuffer)
5039dede 886{
9fd816cc 887 if (!m_isConnected)
e9902466 888 return ERR_NOT_CONNECTED;
5039dede 889
e9902466
VK
890 NXCPMessage msg(m_nProtocolVersion);
891 UINT32 dwRqId = generateRequestId();
892 msg.setCode(CMD_GET_PARAMETER);
893 msg.setId(dwRqId);
894 msg.setField(VID_PARAMETER, pszParam);
895
896 UINT32 dwRetCode;
897 if (sendMessage(&msg))
5039dede 898 {
60c0ce89
VK
899 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
900 if (response != NULL)
5039dede 901 {
60c0ce89 902 dwRetCode = response->getFieldAsUInt32(VID_RCC);
e9902466 903 if (dwRetCode == ERR_SUCCESS)
c2b7d357
VK
904 {
905 if (response->isFieldExist(VID_VALUE))
906 {
907 response->getFieldAsString(VID_VALUE, pszBuffer, dwBufSize);
908 }
909 else
910 {
911 dwRetCode = ERR_MALFORMED_RESPONSE;
912 debugPrintf(3, _T("Malformed response to CMD_GET_PARAMETER"));
913 }
914 }
60c0ce89 915 delete response;
5039dede
AK
916 }
917 else
918 {
e9902466 919 dwRetCode = ERR_REQUEST_TIMEOUT;
5039dede
AK
920 }
921 }
922 else
923 {
e9902466 924 dwRetCode = ERR_CONNECTION_BROKEN;
5039dede 925 }
5039dede
AK
926 return dwRetCode;
927}
928
489b117b 929/**
930 * Get ARP cache
931 */
4687826e 932ARP_CACHE *AgentConnection::getArpCache()
5039dede 933{
6a777a32
VK
934 StringList *data;
935 if (getList(_T("Net.ArpCache"), &data) != ERR_SUCCESS)
936 return NULL;
5039dede 937
6a777a32
VK
938 // Create empty structure
939 ARP_CACHE *pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
940 pArpCache->dwNumEntries = data->size();
941 pArpCache->pEntries = (ARP_ENTRY *)calloc(data->size(), sizeof(ARP_ENTRY));
942
943 TCHAR szByte[4], *pBuf, *pChar;
944 szByte[2] = 0;
945
946 // Parse data lines
947 // Each line has form of XXXXXXXXXXXX a.b.c.d n
948 // where XXXXXXXXXXXX is a MAC address (12 hexadecimal digits)
949 // a.b.c.d is an IP address in decimal dotted notation
950 // n is an interface index
951 for(int i = 0; i < data->size(); i++)
5039dede 952 {
6a777a32
VK
953 TCHAR *line = _tcsdup(data->get(i));
954 pBuf = line;
955 if (_tcslen(pBuf) < 20) // Invalid line
956 continue;
5039dede 957
6a777a32
VK
958 // MAC address
959 for(int j = 0; j < 6; j++)
960 {
961 memcpy(szByte, pBuf, sizeof(TCHAR) * 2);
962 pArpCache->pEntries[i].bMacAddr[j] = (BYTE)_tcstol(szByte, NULL, 16);
963 pBuf += 2;
964 }
5039dede 965
6a777a32
VK
966 // IP address
967 while(*pBuf == ' ')
968 pBuf++;
969 pChar = _tcschr(pBuf, _T(' '));
970 if (pChar != NULL)
971 *pChar = 0;
972 pArpCache->pEntries[i].ipAddr = ntohl(_t_inet_addr(pBuf));
5039dede 973
6a777a32
VK
974 // Interface index
975 if (pChar != NULL)
976 pArpCache->pEntries[i].dwIndex = _tcstoul(pChar + 1, NULL, 10);
5039dede 977
6a777a32 978 free(line);
5039dede 979 }
6a777a32
VK
980
981 delete data;
5039dede
AK
982 return pArpCache;
983}
984
489b117b 985/**
986 * Send dummy command to agent (can be used for keepalive)
987 */
967893bb 988UINT32 AgentConnection::nop()
5039dede 989{
83191808
VK
990 if (!m_isConnected)
991 return ERR_CONNECTION_BROKEN;
992
b368969c 993 NXCPMessage msg(m_nProtocolVersion);
967893bb 994 UINT32 dwRqId;
5039dede 995
e9902466 996 dwRqId = generateRequestId();
b368969c
VK
997 msg.setCode(CMD_KEEPALIVE);
998 msg.setId(dwRqId);
7c521895
VK
999 if (sendMessage(&msg))
1000 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1001 else
1002 return ERR_CONNECTION_BROKEN;
1003}
1004
489b117b 1005/**
1a5ddd2a 1006 * inform agent about server capabilities
ea3993c8 1007 */
1a5ddd2a 1008UINT32 AgentConnection::setServerCapabilities()
ea3993c8
VK
1009{
1010 NXCPMessage msg(m_nProtocolVersion);
e9902466 1011 UINT32 dwRqId = generateRequestId();
1a5ddd2a
VK
1012 msg.setCode(CMD_SET_SERVER_CAPABILITIES);
1013 msg.setField(VID_ENABLED, (INT16)1); // Enables IPv6 on pre-2.0 agents
1014 msg.setField(VID_IPV6_SUPPORT, (INT16)1);
1015 msg.setField(VID_BULK_RECONCILIATION, (INT16)1);
9674aefa 1016 msg.setField(VID_ENABLE_COMPRESSION, (INT16)(m_allowCompression ? 1 : 0));
ea3993c8
VK
1017 msg.setId(dwRqId);
1018 if (sendMessage(&msg))
1019 return waitForRCC(dwRqId, m_dwCommandTimeout);
1020 else
1021 return ERR_CONNECTION_BROKEN;
1022}
1023
1024/**
e9902466
VK
1025 * Set server ID
1026 */
1027UINT32 AgentConnection::setServerId(UINT64 serverId)
1028{
1029 NXCPMessage msg(m_nProtocolVersion);
1030 UINT32 dwRqId = generateRequestId();
1031 msg.setCode(CMD_SET_SERVER_ID);
1032 msg.setField(VID_SERVER_ID, serverId);
1033 msg.setId(dwRqId);
1034 if (sendMessage(&msg))
1035 return waitForRCC(dwRqId, m_dwCommandTimeout);
1036 else
1037 return ERR_CONNECTION_BROKEN;
1038}
1039
1040/**
489b117b 1041 * Wait for request completion code
1042 */
967893bb 1043UINT32 AgentConnection::waitForRCC(UINT32 dwRqId, UINT32 dwTimeOut)
5039dede 1044{
1af3bfac
VK
1045 UINT32 rcc;
1046 NXCPMessage *response = m_pMsgWaitQueue->waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
1047 if (response != NULL)
5039dede 1048 {
1af3bfac
VK
1049 rcc = response->getFieldAsUInt32(VID_RCC);
1050 delete response;
5039dede
AK
1051 }
1052 else
1053 {
1af3bfac 1054 rcc = ERR_REQUEST_TIMEOUT;
5039dede 1055 }
1af3bfac 1056 return rcc;
5039dede
AK
1057}
1058
5c44534b
VK
1059/**
1060 * Send message to agent
1061 */
1693f955 1062bool AgentConnection::sendMessage(NXCPMessage *pMsg)
5039dede 1063{
98f0ac42
VK
1064 AbstractCommChannel *channel = acquireChannel();
1065 if (channel == NULL)
1066 return false;
1067
aff47b6a 1068 if (nxlog_get_debug_level_tag_object(DEBUG_TAG, m_debugId) >= 6)
35a9f4a3
VK
1069 {
1070 TCHAR buffer[64];
1071 debugPrintf(6, _T("Sending message %s (%d) to agent at %s"),
1072 NXCPMessageCodeName(pMsg->getCode(), buffer), pMsg->getId(), (const TCHAR *)m_addr.toString());
1073 }
1074
1693f955 1075 bool success;
198745dd 1076 NXCP_MESSAGE *rawMsg = pMsg->serialize(m_allowCompression);
98abc9f1
VK
1077 NXCPEncryptionContext *pCtx = acquireEncryptionContext();
1078 if (pCtx != NULL)
5039dede 1079 {
e3ff8ad1 1080 NXCP_ENCRYPTED_MESSAGE *pEnMsg = pCtx->encryptMessage(rawMsg);
5039dede
AK
1081 if (pEnMsg != NULL)
1082 {
98f0ac42 1083 success = (channel->send(pEnMsg, ntohl(pEnMsg->size), m_mutexSocketWrite) == (int)ntohl(pEnMsg->size));
5039dede
AK
1084 free(pEnMsg);
1085 }
1086 else
1087 {
1693f955 1088 success = false;
5039dede 1089 }
98abc9f1 1090 pCtx->decRefCount();
5039dede
AK
1091 }
1092 else
1093 {
98f0ac42 1094 success = (channel->send(rawMsg, ntohl(rawMsg->size), m_mutexSocketWrite) == (int)ntohl(rawMsg->size));
5039dede 1095 }
e3ff8ad1 1096 free(rawMsg);
98f0ac42 1097 channel->decRefCount();
1693f955 1098 return success;
5039dede
AK
1099}
1100
d51f2182 1101/**
7cf549ad 1102 * Send raw message to agent
1103 */
1693f955 1104bool AgentConnection::sendRawMessage(NXCP_MESSAGE *pMsg)
7cf549ad 1105{
98f0ac42
VK
1106 AbstractCommChannel *channel = acquireChannel();
1107 if (channel == NULL)
1108 return false;
1109
1693f955 1110 bool success;
e3ff8ad1 1111 NXCP_MESSAGE *rawMsg = pMsg;
7cf549ad 1112 NXCPEncryptionContext *pCtx = acquireEncryptionContext();
1113 if (pCtx != NULL)
1114 {
e3ff8ad1 1115 NXCP_ENCRYPTED_MESSAGE *pEnMsg = pCtx->encryptMessage(rawMsg);
7cf549ad 1116 if (pEnMsg != NULL)
1117 {
98f0ac42 1118 success = (channel->send(pEnMsg, ntohl(pEnMsg->size), m_mutexSocketWrite) == (int)ntohl(pEnMsg->size));
7cf549ad 1119 free(pEnMsg);
1120 }
1121 else
1122 {
1693f955 1123 success = false;
7cf549ad 1124 }
1125 pCtx->decRefCount();
1126 }
1127 else
1128 {
98f0ac42 1129 success = (channel->send(rawMsg, ntohl(rawMsg->size), m_mutexSocketWrite) == (int)ntohl(rawMsg->size));
7cf549ad 1130 }
98f0ac42 1131 channel->decRefCount();
1693f955 1132 return success;
7cf549ad 1133}
1134
1135/**
685508a7 1136 * Callback for processing incoming event on separate thread
cce2f2ef
VK
1137 */
1138void AgentConnection::onTrapCallback(NXCPMessage *msg)
1139{
1140 onTrap(msg);
1141 delete msg;
a87ef571 1142 decInternalRefCount();
cce2f2ef
VK
1143}
1144
1145/**
d51f2182
VK
1146 * Trap handler. Should be overriden in derived classes to implement
1147 * actual trap processing. Default implementation do nothing.
1148 */
b368969c 1149void AgentConnection::onTrap(NXCPMessage *pMsg)
f480bdd4
VK
1150{
1151}
1152
d51f2182 1153/**
685508a7
VK
1154 * Callback for processing incoming syslog message on separate thread
1155 */
1156void AgentConnection::onSyslogMessageCallback(NXCPMessage *msg)
1157{
1158 onSyslogMessage(msg);
1159 delete msg;
1160 decInternalRefCount();
1161}
1162
1163/**
1164 * Syslog message handler. Should be overriden in derived classes to implement
1165 * actual message processing. Default implementation do nothing.
1166 */
1167void AgentConnection::onSyslogMessage(NXCPMessage *pMsg)
1168{
1169}
1170
1171/**
1693f955
VK
1172 * Callback for processing data push on separate thread
1173 */
1174void AgentConnection::onDataPushCallback(NXCPMessage *msg)
1175{
1176 onDataPush(msg);
1177 delete msg;
a87ef571 1178 decInternalRefCount();
1693f955
VK
1179}
1180
1181/**
d51f2182
VK
1182 * Data push handler. Should be overriden in derived classes to implement
1183 * actual data push processing. Default implementation do nothing.
1184 */
b368969c 1185void AgentConnection::onDataPush(NXCPMessage *pMsg)
5039dede
AK
1186{
1187}
1188
d51f2182 1189/**
9fa031cd 1190 * Monitoring data handler. Should be overriden in derived classes to implement
1191 * actual monitoring data processing. Default implementation do nothing.
1192 */
b368969c 1193void AgentConnection::onFileMonitoringData(NXCPMessage *pMsg)
9fa031cd 1194{
1195}
1196
1197/**
cce2f2ef
VK
1198 * Callback for processing data push on separate thread
1199 */
1200void AgentConnection::onSnmpTrapCallback(NXCPMessage *msg)
1201{
1202 onSnmpTrap(msg);
1203 delete msg;
a87ef571 1204 decInternalRefCount();
cce2f2ef
VK
1205}
1206
1207/**
489b117b 1208 * SNMP trap handler. Should be overriden in derived classes to implement
1209 * actual SNMP trap processing. Default implementation do nothing.
1210 */
b368969c 1211void AgentConnection::onSnmpTrap(NXCPMessage *pMsg)
489b117b 1212{
1213}
1214
1215/**
d51f2182
VK
1216 * Custom message handler
1217 * If returns true, message considered as processed and will not be placed in wait queue
1218 */
b368969c 1219bool AgentConnection::processCustomMessage(NXCPMessage *pMsg)
90284364
VK
1220{
1221 return false;
1222}
1223
d51f2182
VK
1224/**
1225 * Get list of values
1226 */
6a777a32 1227UINT32 AgentConnection::getList(const TCHAR *param, StringList **list)
5039dede 1228{
6a777a32
VK
1229 UINT32 rcc;
1230 *list = NULL;
9fd816cc 1231 if (m_isConnected)
5039dede 1232 {
6a777a32
VK
1233 NXCPMessage msg(CMD_GET_LIST, generateRequestId(), m_nProtocolVersion);
1234 msg.setField(VID_PARAMETER, param);
7c521895 1235 if (sendMessage(&msg))
5039dede 1236 {
6a777a32
VK
1237 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, msg.getId(), m_dwCommandTimeout);
1238 if (response != NULL)
5039dede 1239 {
6a777a32
VK
1240 rcc = response->getFieldAsUInt32(VID_RCC);
1241 if (rcc == ERR_SUCCESS)
5039dede 1242 {
6a777a32
VK
1243 *list = new StringList();
1244 int count = response->getFieldAsInt32(VID_NUM_STRINGS);
1245 for(int i = 0; i < count; i++)
1246 (*list)->addPreallocated(response->getFieldAsString(VID_ENUM_VALUE_BASE + i));
5039dede 1247 }
6a777a32 1248 delete response;
5039dede
AK
1249 }
1250 else
1251 {
6a777a32 1252 rcc = ERR_REQUEST_TIMEOUT;
5039dede
AK
1253 }
1254 }
1255 else
1256 {
6a777a32 1257 rcc = ERR_CONNECTION_BROKEN;
5039dede
AK
1258 }
1259 }
1260 else
1261 {
6a777a32 1262 rcc = ERR_NOT_CONNECTED;
5039dede
AK
1263 }
1264
6a777a32 1265 return rcc;
5039dede
AK
1266}
1267
d51f2182
VK
1268/**
1269 * Get table
1270 */
967893bb 1271UINT32 AgentConnection::getTable(const TCHAR *pszParam, Table **table)
4687826e 1272{
b368969c 1273 NXCPMessage msg(m_nProtocolVersion), *pResponse;
967893bb 1274 UINT32 dwRqId, dwRetCode;
4687826e
VK
1275
1276 *table = NULL;
9fd816cc 1277 if (m_isConnected)
4687826e 1278 {
e9902466 1279 dwRqId = generateRequestId();
b368969c
VK
1280 msg.setCode(CMD_GET_TABLE);
1281 msg.setId(dwRqId);
1282 msg.setField(VID_PARAMETER, pszParam);
4687826e
VK
1283 if (sendMessage(&msg))
1284 {
1285 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1286 if (pResponse != NULL)
1287 {
b368969c 1288 dwRetCode = pResponse->getFieldAsUInt32(VID_RCC);
4687826e
VK
1289 if (dwRetCode == ERR_SUCCESS)
1290 {
1291 *table = new Table(pResponse);
1292 }
1293 delete pResponse;
1294 }
1295 else
1296 {
1297 dwRetCode = ERR_REQUEST_TIMEOUT;
1298 }
1299 }
1300 else
1301 {
1302 dwRetCode = ERR_CONNECTION_BROKEN;
1303 }
1304 }
1305 else
1306 {
1307 dwRetCode = ERR_NOT_CONNECTED;
1308 }
1309
1310 return dwRetCode;
1311}
1312
975f38fc
VK
1313/**
1314 * Authenticate to agent
1315 */
967893bb 1316UINT32 AgentConnection::authenticate(BOOL bProxyData)
5039dede 1317{
b368969c 1318 NXCPMessage msg(m_nProtocolVersion);
967893bb 1319 UINT32 dwRqId;
5039dede
AK
1320 BYTE hash[32];
1321 int iAuthMethod = bProxyData ? m_iProxyAuth : m_iAuthMethod;
08b214c6 1322 const char *pszSecret = bProxyData ? m_szProxySecret : m_szSecret;
5039dede
AK
1323#ifdef UNICODE
1324 WCHAR szBuffer[MAX_SECRET_LENGTH];
1325#endif
1326
1327 if (iAuthMethod == AUTH_NONE)
1328 return ERR_SUCCESS; // No authentication required
1329
e9902466 1330 dwRqId = generateRequestId();
b368969c
VK
1331 msg.setCode(CMD_AUTHENTICATE);
1332 msg.setId(dwRqId);
1333 msg.setField(VID_AUTH_METHOD, (WORD)iAuthMethod);
5039dede
AK
1334 switch(iAuthMethod)
1335 {
1336 case AUTH_PLAINTEXT:
1337#ifdef UNICODE
1338 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszSecret, -1, szBuffer, MAX_SECRET_LENGTH);
b368969c 1339 msg.setField(VID_SHARED_SECRET, szBuffer);
5039dede 1340#else
b368969c 1341 msg.setField(VID_SHARED_SECRET, pszSecret);
5039dede
AK
1342#endif
1343 break;
1344 case AUTH_MD5_HASH:
1345 CalculateMD5Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
b368969c 1346 msg.setField(VID_SHARED_SECRET, hash, MD5_DIGEST_SIZE);
5039dede
AK
1347 break;
1348 case AUTH_SHA1_HASH:
1349 CalculateSHA1Hash((BYTE *)pszSecret, (int)strlen(pszSecret), hash);
b368969c 1350 msg.setField(VID_SHARED_SECRET, hash, SHA1_DIGEST_SIZE);
5039dede
AK
1351 break;
1352 default:
1353 break;
1354 }
7c521895
VK
1355 if (sendMessage(&msg))
1356 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1357 else
1358 return ERR_CONNECTION_BROKEN;
1359}
1360
908d71bd
VK
1361/**
1362 * Execute action on agent
1363 */
2649d20b 1364UINT32 AgentConnection::execAction(const TCHAR *action, const StringList &list,
908d71bd 1365 bool withOutput, void (* outputCallback)(ActionCallbackEvent, const TCHAR *, void *), void *cbData)
5039dede 1366{
b368969c 1367 NXCPMessage msg(m_nProtocolVersion);
967893bb 1368 UINT32 dwRqId;
5039dede
AK
1369 int i;
1370
9fd816cc 1371 if (!m_isConnected)
5039dede
AK
1372 return ERR_NOT_CONNECTED;
1373
e9902466 1374 dwRqId = generateRequestId();
b368969c
VK
1375 msg.setCode(CMD_ACTION);
1376 msg.setId(dwRqId);
1e84fc1d 1377 msg.setField(VID_ACTION_NAME, action);
b368969c 1378 msg.setField(VID_RECEIVE_OUTPUT, (UINT16)(withOutput ? 1 : 0));
2649d20b 1379 msg.setField(VID_NUM_ARGS, (UINT32)list.size());
1380 for(i = 0; i < list.size(); i++)
1381 msg.setField(VID_ACTION_ARG_BASE + i, list.get(i));
5039dede 1382
7c521895 1383 if (sendMessage(&msg))
908d71bd
VK
1384 {
1385 if (withOutput)
1386 {
1387 UINT32 rcc = waitForRCC(dwRqId, m_dwCommandTimeout);
1388 if (rcc == ERR_SUCCESS)
1389 {
1390 outputCallback(ACE_CONNECTED, NULL, cbData); // Indicate successful start
1391 bool eos = false;
1392 while(!eos)
1393 {
cd737544 1394 NXCPMessage *response = waitForMessage(CMD_COMMAND_OUTPUT, dwRqId, m_dwCommandTimeout * 10);
908d71bd
VK
1395 if (response != NULL)
1396 {
1397 eos = response->isEndOfSequence();
1398 if (response->isFieldExist(VID_MESSAGE))
1399 {
1400 TCHAR line[4096];
b368969c 1401 response->getFieldAsString(VID_MESSAGE, line, 4096);
908d71bd
VK
1402 outputCallback(ACE_DATA, line, cbData);
1403 }
1404 delete response;
1405 }
1406 else
1407 {
1408 return ERR_REQUEST_TIMEOUT;
1409 }
1410 }
1411 outputCallback(ACE_DISCONNECTED, NULL, cbData);
1412 return ERR_SUCCESS;
1413 }
1414 else
1415 {
1416 return rcc;
1417 }
1418 }
1419 else
1420 {
1421 return waitForRCC(dwRqId, m_dwCommandTimeout);
1422 }
1423 }
5039dede 1424 else
908d71bd 1425 {
5039dede 1426 return ERR_CONNECTION_BROKEN;
908d71bd 1427 }
5039dede
AK
1428}
1429
74d2f1ea 1430/**
1431 * Upload file to agent
1432 */
d3a20572 1433UINT32 AgentConnection::uploadFile(const TCHAR *localFile, const TCHAR *destinationFile, void (* progressCallback)(INT64, void *), void *cbArg, NXCPStreamCompressionMethod compMethod)
5039dede 1434{
967893bb 1435 UINT32 dwRqId, dwResult;
b368969c 1436 NXCPMessage msg(m_nProtocolVersion);
5039dede 1437
fb239ffc
VK
1438 // Disable compression if it is disabled on connection level or if agent do not support it
1439 if (!m_allowCompression || (m_nProtocolVersion < 4))
1440 compMethod = NXCP_STREAM_COMPRESSION_NONE;
1441
9fd816cc 1442 if (!m_isConnected)
5039dede
AK
1443 return ERR_NOT_CONNECTED;
1444
e9902466 1445 dwRqId = generateRequestId();
b368969c 1446 msg.setId(dwRqId);
5039dede 1447
c8f93990
VK
1448 time_t lastModTime = 0;
1449 NX_STAT_STRUCT st;
1450 if (CALL_STAT(localFile, &st) == 0)
1451 {
1452 lastModTime = st.st_mtime;
1453 }
1454
8581943e
VK
1455 // Use core agent if destination file name is not set and file manager subagent otherwise
1456 if ((destinationFile == NULL) || (*destinationFile == 0))
74d2f1ea 1457 {
b368969c 1458 msg.setCode(CMD_TRANSFER_FILE);
8581943e
VK
1459 int i;
1460 for(i = (int)_tcslen(localFile) - 1;
1461 (i >= 0) && (localFile[i] != '\\') && (localFile[i] != '/'); i--);
b368969c 1462 msg.setField(VID_FILE_NAME, &localFile[i + 1]);
74d2f1ea 1463 }
1464 else
1465 {
b368969c 1466 msg.setCode(CMD_FILEMGR_UPLOAD);
74b9e2aa 1467 msg.setField(VID_OVERVRITE, true);
b368969c 1468 msg.setField(VID_FILE_NAME, destinationFile);
f0c1d2a4 1469 }
c8f93990 1470 msg.setFieldFromTime(VID_MODIFICATION_TIME, lastModTime);
5039dede 1471
7c521895 1472 if (sendMessage(&msg))
5039dede 1473 {
7c521895 1474 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1475 }
1476 else
1477 {
1478 dwResult = ERR_CONNECTION_BROKEN;
1479 }
1480
1481 if (dwResult == ERR_SUCCESS)
1482 {
98f0ac42
VK
1483 AbstractCommChannel *channel = acquireChannel();
1484 if (channel != NULL)
1485 {
aff47b6a 1486 debugPrintf(5, _T("Sending file \"%s\" to agent %s compression"),
98f0ac42
VK
1487 localFile, (compMethod == NXCP_STREAM_COMPRESSION_NONE) ? _T("without") : _T("with"));
1488 m_fileUploadInProgress = true;
1489 NXCPEncryptionContext *ctx = acquireEncryptionContext();
1490 if (SendFileOverNXCP(channel, dwRqId, localFile, ctx, 0, progressCallback, cbArg, m_mutexSocketWrite, compMethod))
1491 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
1492 else
1493 dwResult = ERR_IO_FAILURE;
1494 m_fileUploadInProgress = false;
9b7ff3f5
VK
1495 if (ctx != NULL)
1496 ctx->decRefCount();
98f0ac42
VK
1497 channel->decRefCount();
1498 }
5039dede 1499 else
98f0ac42
VK
1500 {
1501 dwResult = ERR_CONNECTION_BROKEN;
1502 }
5039dede
AK
1503 }
1504
1505 return dwResult;
1506}
1507
8581943e
VK
1508/**
1509 * Send upgrade command
1510 */
967893bb 1511UINT32 AgentConnection::startUpgrade(const TCHAR *pszPkgName)
5039dede 1512{
967893bb 1513 UINT32 dwRqId, dwResult;
b368969c 1514 NXCPMessage msg(m_nProtocolVersion);
5039dede
AK
1515 int i;
1516
9fd816cc 1517 if (!m_isConnected)
5039dede
AK
1518 return ERR_NOT_CONNECTED;
1519
e9902466 1520 dwRqId = generateRequestId();
5039dede 1521
b368969c
VK
1522 msg.setCode(CMD_UPGRADE_AGENT);
1523 msg.setId(dwRqId);
cc022855 1524 for(i = (int)_tcslen(pszPkgName) - 1;
5039dede 1525 (i >= 0) && (pszPkgName[i] != '\\') && (pszPkgName[i] != '/'); i--);
b368969c 1526 msg.setField(VID_FILE_NAME, &pszPkgName[i + 1]);
5039dede 1527
7c521895 1528 if (sendMessage(&msg))
5039dede 1529 {
7c521895 1530 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1531 }
1532 else
1533 {
1534 dwResult = ERR_CONNECTION_BROKEN;
1535 }
1536
1537 return dwResult;
1538}
1539
a0e181dc
VK
1540/**
1541 * Check status of network service via agent
1542 */
c75e9ee4 1543UINT32 AgentConnection::checkNetworkService(UINT32 *pdwStatus, const InetAddress& addr, int iServiceType,
e13420c1 1544 WORD wPort, WORD wProto, const TCHAR *pszRequest,
b8014eee 1545 const TCHAR *pszResponse, UINT32 *responseTime)
5039dede 1546{
967893bb 1547 UINT32 dwRqId, dwResult;
b368969c 1548 NXCPMessage msg(m_nProtocolVersion), *pResponse;
a0e181dc 1549 static WORD m_wDefaultPort[] = { 7, 22, 110, 25, 21, 80, 443, 23 };
5039dede 1550
9fd816cc 1551 if (!m_isConnected)
5039dede
AK
1552 return ERR_NOT_CONNECTED;
1553
e9902466 1554 dwRqId = generateRequestId();
5039dede 1555
b368969c
VK
1556 msg.setCode(CMD_CHECK_NETWORK_SERVICE);
1557 msg.setId(dwRqId);
c75e9ee4 1558 msg.setField(VID_IP_ADDRESS, addr);
b368969c
VK
1559 msg.setField(VID_SERVICE_TYPE, (WORD)iServiceType);
1560 msg.setField(VID_IP_PORT,
cc022855 1561 (wPort != 0) ? wPort :
1562 m_wDefaultPort[((iServiceType >= NETSRV_CUSTOM) &&
a0e181dc 1563 (iServiceType <= NETSRV_TELNET)) ? iServiceType : 0]);
b368969c
VK
1564 msg.setField(VID_IP_PROTO, (wProto != 0) ? wProto : (WORD)IPPROTO_TCP);
1565 msg.setField(VID_SERVICE_REQUEST, pszRequest);
1566 msg.setField(VID_SERVICE_RESPONSE, pszResponse);
5039dede 1567
7c521895 1568 if (sendMessage(&msg))
5039dede
AK
1569 {
1570 // Wait up to 90 seconds for results
7c521895 1571 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, 90000);
5039dede
AK
1572 if (pResponse != NULL)
1573 {
b368969c 1574 dwResult = pResponse->getFieldAsUInt32(VID_RCC);
5039dede
AK
1575 if (dwResult == ERR_SUCCESS)
1576 {
b368969c 1577 *pdwStatus = pResponse->getFieldAsUInt32(VID_SERVICE_STATUS);
b8014eee
VK
1578 if (responseTime != NULL)
1579 {
b368969c 1580 *responseTime = pResponse->getFieldAsUInt32(VID_RESPONSE_TIME);
b8014eee 1581 }
5039dede
AK
1582 }
1583 delete pResponse;
1584 }
1585 else
1586 {
1587 dwResult = ERR_REQUEST_TIMEOUT;
1588 }
1589 }
1590 else
1591 {
1592 dwResult = ERR_CONNECTION_BROKEN;
1593 }
1594
1595 return dwResult;
1596}
1597
074498ac 1598/**
86c126f5 1599 * Get list of supported parameters from agent
074498ac 1600 */
967893bb 1601UINT32 AgentConnection::getSupportedParameters(ObjectArray<AgentParameterDefinition> **paramList, ObjectArray<AgentTableDefinition> **tableList)
5039dede 1602{
967893bb 1603 UINT32 dwRqId, dwResult;
b368969c 1604 NXCPMessage msg(m_nProtocolVersion), *pResponse;
5039dede 1605
cc8ce218
VK
1606 *paramList = NULL;
1607 *tableList = NULL;
5039dede 1608
9fd816cc 1609 if (!m_isConnected)
5039dede
AK
1610 return ERR_NOT_CONNECTED;
1611
e9902466 1612 dwRqId = generateRequestId();
5039dede 1613
b368969c
VK
1614 msg.setCode(CMD_GET_PARAMETER_LIST);
1615 msg.setId(dwRqId);
5039dede 1616
7c521895 1617 if (sendMessage(&msg))
5039dede 1618 {
7c521895 1619 pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1620 if (pResponse != NULL)
1621 {
b368969c 1622 dwResult = pResponse->getFieldAsUInt32(VID_RCC);
cc8ce218 1623 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): RCC=%d"), dwResult);
5039dede
AK
1624 if (dwResult == ERR_SUCCESS)
1625 {
b368969c 1626 UINT32 count = pResponse->getFieldAsUInt32(VID_NUM_PARAMETERS);
86c126f5 1627 ObjectArray<AgentParameterDefinition> *plist = new ObjectArray<AgentParameterDefinition>(count, 16, true);
b368969c 1628 for(UINT32 i = 0, id = VID_PARAM_LIST_BASE; i < count; i++)
5039dede 1629 {
b368969c
VK
1630 plist->add(new AgentParameterDefinition(pResponse, id));
1631 id += 3;
5039dede 1632 }
86c126f5 1633 *paramList = plist;
cc8ce218
VK
1634 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d parameters received from agent"), count);
1635
b368969c 1636 count = pResponse->getFieldAsUInt32(VID_NUM_TABLES);
86c126f5 1637 ObjectArray<AgentTableDefinition> *tlist = new ObjectArray<AgentTableDefinition>(count, 16, true);
b368969c 1638 for(UINT32 i = 0, id = VID_TABLE_LIST_BASE; i < count; i++)
cc8ce218 1639 {
b368969c
VK
1640 tlist->add(new AgentTableDefinition(pResponse, id));
1641 id += 3;
cc8ce218 1642 }
86c126f5 1643 *tableList = tlist;
cc8ce218
VK
1644 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d tables received from agent"), count);
1645 }
5039dede
AK
1646 delete pResponse;
1647 }
1648 else
1649 {
1650 dwResult = ERR_REQUEST_TIMEOUT;
1651 }
1652 }
1653 else
1654 {
1655 dwResult = ERR_CONNECTION_BROKEN;
1656 }
1657
1658 return dwResult;
1659}
1660
074498ac
VK
1661/**
1662 * Setup encryption
1663 */
967893bb 1664UINT32 AgentConnection::setupEncryption(RSA *pServerKey)
5039dede
AK
1665{
1666#ifdef _WITH_ENCRYPTION
b368969c 1667 NXCPMessage msg(m_nProtocolVersion), *pResp;
967893bb 1668 UINT32 dwRqId, dwError, dwResult;
5039dede 1669
e9902466 1670 dwRqId = generateRequestId();
5039dede 1671
9e9d631e 1672 PrepareKeyRequestMsg(&msg, pServerKey, false);
b368969c 1673 msg.setId(dwRqId);
7c521895 1674 if (sendMessage(&msg))
5039dede 1675 {
7c521895 1676 pResp = waitForMessage(CMD_SESSION_KEY, dwRqId, m_dwCommandTimeout);
5039dede
AK
1677 if (pResp != NULL)
1678 {
1679 dwResult = SetupEncryptionContext(pResp, &m_pCtx, NULL, pServerKey, m_nProtocolVersion);
1680 switch(dwResult)
1681 {
1682 case RCC_SUCCESS:
1683 dwError = ERR_SUCCESS;
1684 break;
1685 case RCC_NO_CIPHERS:
1686 dwError = ERR_NO_CIPHERS;
1687 break;
1688 case RCC_INVALID_PUBLIC_KEY:
1689 dwError = ERR_INVALID_PUBLIC_KEY;
1690 break;
1691 case RCC_INVALID_SESSION_KEY:
1692 dwError = ERR_INVALID_SESSION_KEY;
1693 break;
1694 default:
1695 dwError = ERR_INTERNAL_ERROR;
1696 break;
1697 }
1698 delete pResp;
1699 }
1700 else
1701 {
1702 dwError = ERR_REQUEST_TIMEOUT;
1703 }
1704 }
1705 else
1706 {
1707 dwError = ERR_CONNECTION_BROKEN;
1708 }
1709
1710 return dwError;
1711#else
1712 return ERR_NOT_IMPLEMENTED;
1713#endif
1714}
1715
5944946e
VK
1716/**
1717 * Get configuration file from agent
1718 */
967893bb 1719UINT32 AgentConnection::getConfigFile(TCHAR **ppszConfig, UINT32 *pdwSize)
5039dede 1720{
5039dede
AK
1721 *ppszConfig = NULL;
1722 *pdwSize = 0;
1723
9fd816cc 1724 if (!m_isConnected)
5039dede
AK
1725 return ERR_NOT_CONNECTED;
1726
f1c7358a
VK
1727 UINT32 dwResult;
1728 UINT32 dwRqId = generateRequestId();
5039dede 1729
f1c7358a 1730 NXCPMessage msg(m_nProtocolVersion);
b368969c
VK
1731 msg.setCode(CMD_GET_AGENT_CONFIG);
1732 msg.setId(dwRqId);
5039dede 1733
7c521895 1734 if (sendMessage(&msg))
5039dede 1735 {
f1c7358a 1736 NXCPMessage *pResponse = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
1737 if (pResponse != NULL)
1738 {
b368969c 1739 dwResult = pResponse->getFieldAsUInt32(VID_RCC);
5039dede
AK
1740 if (dwResult == ERR_SUCCESS)
1741 {
f1c7358a 1742 size_t size = pResponse->getFieldAsBinary(VID_CONFIG_FILE, NULL, 0);
4c5f5165 1743 BYTE *utf8Text = (BYTE *)malloc(size + 1);
1744 pResponse->getFieldAsBinary(VID_CONFIG_FILE, (BYTE *)utf8Text, size);
1745
1746 // We expect text file, so replace all non-printable characters with spaces
f1c7358a 1747 for(size_t i = 0; i < size; i++)
4c5f5165 1748 if ((utf8Text[i] < ' ') &&
1749 (utf8Text[i] != '\t') &&
1750 (utf8Text[i] != '\r') &&
1751 (utf8Text[i] != '\n'))
1752 utf8Text[i] = ' ';
1753 utf8Text[size] = 0;
1754
5039dede 1755#ifdef UNICODE
4c5f5165 1756 *ppszConfig = WideStringFromUTF8String((char *)utf8Text);
5039dede 1757#else
4c5f5165 1758 *ppszConfig = MBStringFromUTF8String((char *)utf8Text);
5039dede 1759#endif
4c5f5165 1760 free(utf8Text);
1761 *pdwSize = (UINT32)_tcslen(*ppszConfig);
5039dede
AK
1762 }
1763 delete pResponse;
1764 }
1765 else
1766 {
1767 dwResult = ERR_REQUEST_TIMEOUT;
1768 }
1769 }
1770 else
1771 {
1772 dwResult = ERR_CONNECTION_BROKEN;
1773 }
1774
1775 return dwResult;
1776}
1777
5944946e
VK
1778/**
1779 * Update configuration file on agent
1780 */
967893bb 1781UINT32 AgentConnection::updateConfigFile(const TCHAR *pszConfig)
5039dede 1782{
967893bb 1783 UINT32 dwRqId, dwResult;
b368969c 1784 NXCPMessage msg(m_nProtocolVersion);
5039dede
AK
1785#ifdef UNICODE
1786 int nChars;
1787 BYTE *pBuffer;
1788#endif
1789
9fd816cc 1790 if (!m_isConnected)
5039dede
AK
1791 return ERR_NOT_CONNECTED;
1792
e9902466 1793 dwRqId = generateRequestId();
5039dede 1794
b368969c
VK
1795 msg.setCode(CMD_UPDATE_AGENT_CONFIG);
1796 msg.setId(dwRqId);
5039dede 1797#ifdef UNICODE
465b3f2d 1798 nChars = (int)_tcslen(pszConfig);
5039dede
AK
1799 pBuffer = (BYTE *)malloc(nChars + 1);
1800 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
08b214c6 1801 pszConfig, nChars, (char *)pBuffer, nChars + 1, NULL, NULL);
b368969c 1802 msg.setField(VID_CONFIG_FILE, pBuffer, nChars);
5039dede
AK
1803 free(pBuffer);
1804#else
b368969c 1805 msg.setField(VID_CONFIG_FILE, (BYTE *)pszConfig, (UINT32)strlen(pszConfig));
5039dede
AK
1806#endif
1807
7c521895 1808 if (sendMessage(&msg))
5039dede 1809 {
7c521895 1810 dwResult = waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1811 }
1812 else
1813 {
1814 dwResult = ERR_CONNECTION_BROKEN;
1815 }
1816
1817 return dwResult;
1818}
1819
5944946e
VK
1820/**
1821 * Get routing table from agent
1822 */
4687826e 1823ROUTING_TABLE *AgentConnection::getRoutingTable()
5039dede 1824{
6a777a32
VK
1825 StringList *data;
1826 if (getList(_T("Net.IP.RoutingTable"), &data) != ERR_SUCCESS)
1827 return NULL;
5039dede 1828
6a777a32
VK
1829 ROUTING_TABLE *pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
1830 pRT->iNumEntries = data->size();
1831 pRT->pRoutes = (ROUTE *)calloc(data->size(), sizeof(ROUTE));
1832 for(int i = 0; i < data->size(); i++)
5039dede 1833 {
6a777a32
VK
1834 TCHAR *line = _tcsdup(data->get(i));
1835 TCHAR *pBuf = line;
1836
1837 // Destination address and mask
1838 TCHAR *pChar = _tcschr(pBuf, _T(' '));
1839 if (pChar != NULL)
5039dede 1840 {
6a777a32
VK
1841 TCHAR *pSlash;
1842 static TCHAR defaultMask[] = _T("24");
5039dede 1843
6a777a32
VK
1844 *pChar = 0;
1845 pSlash = _tcschr(pBuf, _T('/'));
1846 if (pSlash != NULL)
5039dede 1847 {
6a777a32
VK
1848 *pSlash = 0;
1849 pSlash++;
5039dede 1850 }
6a777a32 1851 else // Just a paranoia protection, should'n happen if agent working correctly
5039dede 1852 {
6a777a32 1853 pSlash = defaultMask;
5039dede 1854 }
6a777a32
VK
1855 pRT->pRoutes[i].dwDestAddr = ntohl(_t_inet_addr(pBuf));
1856 UINT32 dwBits = _tcstoul(pSlash, NULL, 10);
1857 pRT->pRoutes[i].dwDestMask = (dwBits == 32) ? 0xFFFFFFFF : (~(0xFFFFFFFF >> dwBits));
1858 pBuf = pChar + 1;
1859 }
5039dede 1860
6a777a32
VK
1861 // Next hop address
1862 pChar = _tcschr(pBuf, _T(' '));
1863 if (pChar != NULL)
1864 {
1865 *pChar = 0;
1866 pRT->pRoutes[i].dwNextHop = ntohl(_t_inet_addr(pBuf));
1867 pBuf = pChar + 1;
1868 }
5039dede 1869
6a777a32
VK
1870 // Interface index
1871 pChar = _tcschr(pBuf, ' ');
1872 if (pChar != NULL)
1873 {
1874 *pChar = 0;
1875 pRT->pRoutes[i].dwIfIndex = _tcstoul(pBuf, NULL, 10);
1876 pBuf = pChar + 1;
5039dede
AK
1877 }
1878
6a777a32
VK
1879 // Route type
1880 pRT->pRoutes[i].dwRouteType = _tcstoul(pBuf, NULL, 10);
1881
1882 free(line);
5039dede
AK
1883 }
1884
6a777a32 1885 delete data;
5039dede
AK
1886 return pRT;
1887}
1888
5944946e
VK
1889/**
1890 * Set proxy information
1891 */
c11eee9b 1892void AgentConnection::setProxy(InetAddress addr, WORD wPort, int iAuthMethod, const TCHAR *pszSecret)
5039dede 1893{
c11eee9b 1894 m_proxyAddr = addr;
5039dede
AK
1895 m_wProxyPort = wPort;
1896 m_iProxyAuth = iAuthMethod;
1897 if (pszSecret != NULL)
1898 {
1899#ifdef UNICODE
cc022855 1900 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
5039dede
AK
1901 pszSecret, -1, m_szProxySecret, MAX_SECRET_LENGTH, NULL, NULL);
1902#else
1903 nx_strncpy(m_szProxySecret, pszSecret, MAX_SECRET_LENGTH);
1904#endif
1905 }
1906 else
1907 {
1908 m_szProxySecret[0] = 0;
1909 }
b76ba8c2 1910 m_useProxy = true;
5039dede
AK
1911}
1912
5944946e
VK
1913/**
1914 * Setup proxy connection
1915 */
967893bb 1916UINT32 AgentConnection::setupProxyConnection()
5039dede 1917{
b368969c 1918 NXCPMessage msg(m_nProtocolVersion);
967893bb 1919 UINT32 dwRqId;
5039dede 1920
e9902466 1921 dwRqId = generateRequestId();
b368969c
VK
1922 msg.setCode(CMD_SETUP_PROXY_CONNECTION);
1923 msg.setId(dwRqId);
c11eee9b 1924 msg.setField(VID_IP_ADDRESS, m_addr.getAddressV4()); // FIXME: V6 support in proxy
b368969c 1925 msg.setField(VID_AGENT_PORT, m_wPort);
7c521895
VK
1926 if (sendMessage(&msg))
1927 return waitForRCC(dwRqId, 60000); // Wait 60 seconds for remote connect
5039dede
AK
1928 else
1929 return ERR_CONNECTION_BROKEN;
1930}
1931
ef8278f0
VK
1932/**
1933 * Enable trap receiving on connection
1934 */
967893bb 1935UINT32 AgentConnection::enableTraps()
5039dede 1936{
b368969c 1937 NXCPMessage msg(m_nProtocolVersion);
967893bb 1938 UINT32 dwRqId;
5039dede 1939
e9902466 1940 dwRqId = generateRequestId();
b368969c
VK
1941 msg.setCode(CMD_ENABLE_AGENT_TRAPS);
1942 msg.setId(dwRqId);
7c521895
VK
1943 if (sendMessage(&msg))
1944 return waitForRCC(dwRqId, m_dwCommandTimeout);
5039dede
AK
1945 else
1946 return ERR_CONNECTION_BROKEN;
1947}
1948
cc022855 1949/**
e13420c1 1950 * Enable trap receiving on connection
1951 */
1952UINT32 AgentConnection::enableFileUpdates()
1953{
1954 NXCPMessage msg(m_nProtocolVersion);
1955 UINT32 dwRqId;
1956
1957 dwRqId = generateRequestId();
1958 msg.setCode(CMD_ENABLE_FILE_UPDATES);
1959 msg.setId(dwRqId);
1960 if (sendMessage(&msg))
1961 {
1962 return waitForRCC(dwRqId, m_dwCommandTimeout);
1963 }
1964 else
1965 return ERR_CONNECTION_BROKEN;
1966}
1967
1968/**
5944946e
VK
1969 * Take screenshot from remote system
1970 */
9c786c0f 1971UINT32 AgentConnection::takeScreenshot(const TCHAR *sessionName, BYTE **data, size_t *size)
5944946e 1972{
b368969c 1973 NXCPMessage msg(m_nProtocolVersion);
5944946e
VK
1974 UINT32 dwRqId;
1975
e9902466 1976 dwRqId = generateRequestId();
b368969c
VK
1977 msg.setCode(CMD_TAKE_SCREENSHOT);
1978 msg.setId(dwRqId);
1979 msg.setField(VID_NAME, sessionName);
5944946e
VK
1980 if (sendMessage(&msg))
1981 {
b368969c 1982 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5944946e
VK
1983 if (response != NULL)
1984 {
b368969c 1985 UINT32 rcc = response->getFieldAsUInt32(VID_RCC);
5944946e
VK
1986 if (rcc == ERR_SUCCESS)
1987 {
ca0a165b 1988 const BYTE *p = response->getBinaryFieldPtr(VID_FILE_DATA, size);
5944946e
VK
1989 if (p != NULL)
1990 {
1991 *data = (BYTE *)malloc(*size);
1992 memcpy(*data, p, *size);
1993 }
1994 else
1995 {
1996 *data = NULL;
1997 }
1998 }
1999 delete response;
2000 return rcc;
2001 }
2002 else
2003 {
2004 return ERR_REQUEST_TIMEOUT;
2005 }
2006 }
2007 else
2008 {
2009 return ERR_CONNECTION_BROKEN;
2010 }
2011}
2012
2013/**
a5722427 2014 * Resolve hostname by IP address in local network
2015 */
2016TCHAR *AgentConnection::getHostByAddr(const InetAddress& ipAddr, TCHAR *buf, size_t bufLen)
2017{
2018 NXCPMessage msg(m_nProtocolVersion);
2019 UINT32 dwRqId;
2020
2021 dwRqId = generateRequestId();
2022 msg.setCode(CMD_HOST_BY_IP);
2023 msg.setId(dwRqId);
2024 msg.setField(VID_IP_ADDRESS, ipAddr);
2025 TCHAR *result = NULL;
2026 if (sendMessage(&msg))
2027 {
2028 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
2029 if (response != NULL)
2030 {
2031 UINT32 rcc = response->getFieldAsUInt32(VID_RCC);
2032 if (rcc == ERR_SUCCESS)
2033 {
2034 result = response->getFieldAsString(VID_NAME, buf, bufLen);
2035 }
2036 delete response;
2037 return result;
2038 }
2039 else
2040 {
2041 return result;
2042 }
2043 }
2044 else
2045 {
2046 return result;
2047 }
2048}
2049
2050/**
cc022855 2051 * Send custom request to agent
2052 */
e3ff8ad1
VK
2053NXCPMessage *AgentConnection::customRequest(NXCPMessage *pRequest, const TCHAR *recvFile, bool append,
2054 void (*downloadProgressCallback)(size_t, void *), void (*fileResendCallback)(NXCP_MESSAGE *, void *), void *cbArg)
5039dede 2055{
967893bb 2056 UINT32 dwRqId, rcc;
b368969c 2057 NXCPMessage *msg = NULL;
5039dede 2058
e9902466 2059 dwRqId = generateRequestId();
b368969c 2060 pRequest->setId(dwRqId);
5039dede
AK
2061 if (recvFile != NULL)
2062 {
76b4edb5 2063 rcc = prepareFileDownload(recvFile, dwRqId, append, downloadProgressCallback, fileResendCallback,cbArg);
5039dede
AK
2064 if (rcc != ERR_SUCCESS)
2065 {
2066 // Create fake response message
b368969c
VK
2067 msg = new NXCPMessage;
2068 msg->setCode(CMD_REQUEST_COMPLETED);
2069 msg->setId(dwRqId);
2070 msg->setField(VID_RCC, rcc);
5039dede
AK
2071 }
2072 }
2073
2074 if (msg == NULL)
2075 {
7c521895 2076 if (sendMessage(pRequest))
5039dede 2077 {
7c521895 2078 msg = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
5039dede
AK
2079 if ((msg != NULL) && (recvFile != NULL))
2080 {
b368969c 2081 if (msg->getFieldAsUInt32(VID_RCC) == ERR_SUCCESS)
5039dede 2082 {
bb85e341 2083 if (ConditionWait(m_condFileDownload, 1800000)) // 30 min timeout
5039dede 2084 {
bb85e341 2085 if (!m_fileDownloadSucceeded)
5039dede 2086 {
b368969c 2087 msg->setField(VID_RCC, ERR_IO_FAILURE);
901a5a9b 2088 if (m_deleteFileOnDownloadFailure)
08b214c6 2089 _tremove(recvFile);
5039dede
AK
2090 }
2091 }
2092 else
2093 {
b368969c 2094 msg->setField(VID_RCC, ERR_REQUEST_TIMEOUT);
5039dede
AK
2095 }
2096 }
2097 else
2098 {
ef8278f0 2099 if (fileResendCallback != NULL)
76b4edb5 2100 {
feaad9f8 2101 _close(m_hCurrFile);
76b4edb5 2102 m_hCurrFile = -1;
2103 _tremove(recvFile);
2104 }
5039dede
AK
2105 }
2106 }
76b4edb5 2107
5039dede
AK
2108 }
2109 }
2110
2111 return msg;
2112}
2113
76b4edb5 2114/**
ef8278f0 2115 * Prepare for file download
76b4edb5 2116 */
76b4edb5 2117UINT32 AgentConnection::prepareFileDownload(const TCHAR *fileName, UINT32 rqId, bool append, void (*downloadProgressCallback)(size_t, void *),
e3ff8ad1 2118 void (* fileResendCallback)(NXCP_MESSAGE *, void *), void *cbArg)
5039dede 2119{
ef8278f0 2120 if (fileResendCallback == NULL)
76b4edb5 2121 {
2122 if (m_hCurrFile != -1)
2123 return ERR_RESOURCE_BUSY;
5039dede 2124
76b4edb5 2125 nx_strncpy(m_currentFileName, fileName, MAX_PATH);
2126 ConditionReset(m_condFileDownload);
2127 m_hCurrFile = _topen(fileName, (append ? 0 : (O_CREAT | O_TRUNC)) | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
2128 if (m_hCurrFile == -1)
2129 {
2130 DbgPrintf(4, _T("AgentConnection::PrepareFileDownload(): cannot open file %s (%s); append=%d rqId=%d"),
2131 fileName, _tcserror(errno), append, rqId);
2132 }
2133 else
2134 {
2135 if (append)
2136 lseek(m_hCurrFile, 0, SEEK_END);
2137 }
2138
2139 m_dwDownloadRequestId = rqId;
2140 m_downloadProgressCallback = downloadProgressCallback;
2141 m_downloadProgressCallbackArg = cbArg;
2142
9630fcd1
AK
2143 m_sendToClientMessageCallback = NULL;
2144
76b4edb5 2145 return (m_hCurrFile != -1) ? ERR_SUCCESS : ERR_FILE_OPEN_ERROR;
2146 }
2147 else
2148 {
2149 ConditionReset(m_condFileDownload);
76b4edb5 2150
2151 m_dwDownloadRequestId = rqId;
2152 m_downloadProgressCallback = downloadProgressCallback;
2153 m_downloadProgressCallbackArg = cbArg;
2154
9630fcd1
AK
2155 m_sendToClientMessageCallback = fileResendCallback;
2156
76b4edb5 2157 return ERR_SUCCESS;
2158 }
5039dede
AK
2159}
2160
76b4edb5 2161/**
2162 * File upload completion handler
2163 */
1693f955 2164void AgentConnection::onFileDownload(bool success)
5039dede 2165{
76b4edb5 2166 if (!success && m_deleteFileOnDownloadFailure)
901a5a9b 2167 _tremove(m_currentFileName);
bb85e341
VK
2168 m_fileDownloadSucceeded = success;
2169 ConditionSet(m_condFileDownload);
5039dede 2170}
1f385e47 2171
ef8278f0
VK
2172/**
2173 * Enable trap receiving on connection
2174 */
967893bb 2175UINT32 AgentConnection::getPolicyInventory(AgentPolicyInfo **info)
1f385e47 2176{
b368969c 2177 NXCPMessage msg(m_nProtocolVersion);
967893bb 2178 UINT32 dwRqId, rcc;
1f385e47
VK
2179
2180 *info = NULL;
e9902466 2181 dwRqId = generateRequestId();
b368969c
VK
2182 msg.setCode(CMD_GET_POLICY_INVENTORY);
2183 msg.setId(dwRqId);
1f385e47
VK
2184 if (sendMessage(&msg))
2185 {
b368969c 2186 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
1f385e47
VK
2187 if (response != NULL)
2188 {
b368969c 2189 rcc = response->getFieldAsUInt32(VID_RCC);
1f385e47
VK
2190 if (rcc == ERR_SUCCESS)
2191 *info = new AgentPolicyInfo(response);
2192 delete response;
2193 }
2194 else
2195 {
2196 rcc = ERR_REQUEST_TIMEOUT;
2197 }
2198 }
2199 else
2200 {
2201 rcc = ERR_CONNECTION_BROKEN;
2202 }
2203 return rcc;
2204}
2205
ef8278f0
VK
2206/**
2207 * Uninstall policy by GUID
2208 */
7dd6369a 2209UINT32 AgentConnection::uninstallPolicy(const uuid& guid)
1f385e47 2210{
967893bb 2211 UINT32 rqId, rcc;
b368969c 2212 NXCPMessage msg(m_nProtocolVersion);
1f385e47
VK
2213
2214 rqId = generateRequestId();
b368969c
VK
2215 msg.setId(rqId);
2216 msg.setCode(CMD_UNINSTALL_AGENT_POLICY);
7dd6369a 2217 msg.setField(VID_GUID, guid);
1f385e47
VK
2218 if (sendMessage(&msg))
2219 {
2220 rcc = waitForRCC(rqId, m_dwCommandTimeout);
2221 }
2222 else
2223 {
2224 rcc = ERR_CONNECTION_BROKEN;
2225 }
2226 return rcc;
2227}
98abc9f1 2228
86c126f5
VK
2229/**
2230 * Acquire encryption context
2231 */
98abc9f1
VK
2232NXCPEncryptionContext *AgentConnection::acquireEncryptionContext()
2233{
a3050773 2234 lock();
98abc9f1
VK
2235 NXCPEncryptionContext *ctx = m_pCtx;
2236 if (ctx != NULL)
2237 ctx->incRefCount();
a3050773 2238 unlock();
98abc9f1
VK
2239 return ctx;
2240}
86c126f5
VK
2241
2242/**
1693f955
VK
2243 * Callback for processing collected data on separate thread
2244 */
2245void AgentConnection::processCollectedDataCallback(NXCPMessage *msg)
2246{
1693f955
VK
2247 NXCPMessage response;
2248 response.setCode(CMD_REQUEST_COMPLETED);
2249 response.setId(msg->getId());
a1273b42
VK
2250
2251 if (msg->getFieldAsBoolean(VID_BULK_RECONCILIATION))
2252 {
2253 UINT32 rcc = processBulkCollectedData(msg, &response);
2254 response.setField(VID_RCC, rcc);
2255 }
2256 else
2257 {
2258 UINT32 rcc = processCollectedData(msg);
2259 response.setField(VID_RCC, rcc);
2260 }
2261
1693f955
VK
2262 sendMessage(&response);
2263 delete msg;
a87ef571 2264 decInternalRefCount();
1693f955
VK
2265}
2266
2267/**
6fbaa926
VK
2268 * Process collected data information (for DCI with agent-side cache)
2269 */
02d936bd 2270UINT32 AgentConnection::processCollectedData(NXCPMessage *msg)
6fbaa926 2271{
02d936bd 2272 return ERR_NOT_IMPLEMENTED;
a1273b42
VK
2273}
2274
2275/**
2276 * Process collected data information in bulk mode (for DCI with agent-side cache)
2277 */
2278UINT32 AgentConnection::processBulkCollectedData(NXCPMessage *request, NXCPMessage *response)
2279{
2280 return ERR_NOT_IMPLEMENTED;
6fbaa926
VK
2281}
2282
2283/**
86c126f5
VK
2284 * Create new agent parameter definition from NXCP message
2285 */
b368969c 2286AgentParameterDefinition::AgentParameterDefinition(NXCPMessage *msg, UINT32 baseId)
86c126f5 2287{
b368969c
VK
2288 m_name = msg->getFieldAsString(baseId);
2289 m_description = msg->getFieldAsString(baseId + 1);
2290 m_dataType = (int)msg->getFieldAsUInt16(baseId + 2);
86c126f5
VK
2291}
2292
2293/**
2294 * Create new agent parameter definition from another definition object
2295 */
2296AgentParameterDefinition::AgentParameterDefinition(AgentParameterDefinition *src)
2297{
2298 m_name = (src->m_name != NULL) ? _tcsdup(src->m_name) : NULL;
2299 m_description = (src->m_description != NULL) ? _tcsdup(src->m_description) : NULL;
2300 m_dataType = src->m_dataType;
2301}
2302
2303/**
2304 * Destructor for agent parameter definition
2305 */
2306AgentParameterDefinition::~AgentParameterDefinition()
2307{
2308 safe_free(m_name);
2309 safe_free(m_description);
2310}
2311
2312/**
2313 * Fill NXCP message
2314 */
b368969c 2315UINT32 AgentParameterDefinition::fillMessage(NXCPMessage *msg, UINT32 baseId)
86c126f5 2316{
b368969c
VK
2317 msg->setField(baseId, m_name);
2318 msg->setField(baseId + 1, m_description);
2319 msg->setField(baseId + 2, (WORD)m_dataType);
86c126f5
VK
2320 return 3;
2321}
2322
2323/**
2324 * Create new agent table definition from NXCP message
2325 */
b368969c 2326AgentTableDefinition::AgentTableDefinition(NXCPMessage *msg, UINT32 baseId)
86c126f5 2327{
b368969c
VK
2328 m_name = msg->getFieldAsString(baseId);
2329 m_description = msg->getFieldAsString(baseId + 2);
86c126f5 2330
b368969c 2331 TCHAR *instanceColumns = msg->getFieldAsString(baseId + 1);
86c126f5
VK
2332 if (instanceColumns != NULL)
2333 {
2334 m_instanceColumns = new StringList(instanceColumns, _T("|"));
2335 free(instanceColumns);
2336 }
2337 else
2338 {
2339 m_instanceColumns = new StringList;
2340 }
2341
2342 m_columns = new ObjectArray<AgentTableColumnDefinition>(16, 16, true);
2343}
2344
2345/**
2346 * Create new agent table definition from another definition object
2347 */
2348AgentTableDefinition::AgentTableDefinition(AgentTableDefinition *src)
2349{
2350 m_name = (src->m_name != NULL) ? _tcsdup(src->m_name) : NULL;
2351 m_description = (src->m_description != NULL) ? _tcsdup(src->m_description) : NULL;
2352 m_instanceColumns = new StringList(src->m_instanceColumns);
2353 m_columns = new ObjectArray<AgentTableColumnDefinition>(16, 16, true);
2354 for(int i = 0; i < src->m_columns->size(); i++)
2355 {
2356 m_columns->add(new AgentTableColumnDefinition(src->m_columns->get(i)));
2357 }
2358}
2359/**
2360 * Destructor for agent table definition
2361 */
2362AgentTableDefinition::~AgentTableDefinition()
2363{
2364 safe_free(m_name);
2365 safe_free(m_description);
2366 delete m_instanceColumns;
2367 delete m_columns;
2368}
2369
2370/**
2371 * Fill NXCP message
2372 */
b368969c 2373UINT32 AgentTableDefinition::fillMessage(NXCPMessage *msg, UINT32 baseId)
86c126f5 2374{
b368969c
VK
2375 msg->setField(baseId + 1, m_name);
2376 msg->setField(baseId + 2, m_description);
86c126f5
VK
2377
2378 TCHAR *instanceColumns = m_instanceColumns->join(_T("|"));
b368969c 2379 msg->setField(baseId + 3, instanceColumns);
86c126f5
VK
2380 free(instanceColumns);
2381
967893bb 2382 UINT32 varId = baseId + 4;
86c126f5
VK
2383 for(int i = 0; i < m_columns->size(); i++)
2384 {
b368969c
VK
2385 msg->setField(varId++, m_columns->get(i)->m_name);
2386 msg->setField(varId++, (WORD)m_columns->get(i)->m_dataType);
86c126f5
VK
2387 }
2388
b368969c 2389 msg->setField(baseId, varId - baseId);
86c126f5
VK
2390 return varId - baseId;
2391}