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