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