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