2 ** NetXMS - Network Management System
4 ** Copyright (C) 2003-2016 Victor Kirhenshtein
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.
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.
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.
32 #define _tell(f) lseek(f,0,SEEK_CUR)
38 #define MAX_MSG_SIZE 268435456
41 * Agent connection thread pool
43 ThreadPool LIBNXSRV_EXPORTABLE
*g_agentConnectionThreadPool
= NULL
;
48 #ifdef _WITH_ENCRYPTION
49 static int m_iDefaultEncryptionPolicy
= ENCRYPTION_ALLOWED
;
51 static int m_iDefaultEncryptionPolicy
= ENCRYPTION_DISABLED
;
55 * Set default encryption policy for agent communication
57 void LIBNXSRV_EXPORTABLE
SetAgentDEP(int iPolicy
)
59 #ifdef _WITH_ENCRYPTION
60 m_iDefaultEncryptionPolicy
= iPolicy
;
65 * Receiver thread starter
67 THREAD_RESULT THREAD_CALL
AgentConnection::receiverThreadStarter(void *pArg
)
69 ((AgentConnection
*)pArg
)->receiverThread();
70 ((AgentConnection
*)pArg
)->decInternalRefCount();
75 * Constructor for AgentConnection
77 AgentConnection::AgentConnection(InetAddress addr
, WORD port
, int authMethod
, const TCHAR
*secret
)
79 m_internalRefCount
= 1;
83 m_iAuthMethod
= authMethod
;
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;
90 nx_strncpy(m_szSecret
, secret
, MAX_SECRET_LENGTH
);
98 m_tLastCommandTime
= 0;
100 m_ppDataLines
= NULL
;
101 m_pMsgWaitQueue
= new MsgWaitQueue
;
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
;
110 m_iEncryptionPolicy
= m_iDefaultEncryptionPolicy
;
112 m_iProxyAuth
= AUTH_NONE
;
114 m_dwRecvTimeout
= 420000; // 7 minutes
115 m_nProtocolVersion
= NXCP_VERSION
;
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
;
130 AgentConnection::~AgentConnection()
132 DbgPrintf(7, _T("AgentConnection destructor called (this=%p, thread=%p)"), this, (void *)m_hReceiverThread
);
134 ThreadDetach(m_hReceiverThread
);
140 delete m_pMsgWaitQueue
;
142 m_pCtx
->decRefCount();
144 if (m_hCurrFile
!= -1)
147 onFileDownload(false);
150 MutexDestroy(m_mutexDataLock
);
151 MutexDestroy(m_mutexSocketWrite
);
152 ConditionDestroy(m_condFileDownload
);
156 * Print message. This method is virtual and can be overrided in
157 * derived classes. Default implementation will print message to stdout.
159 void AgentConnection::printMsg(const TCHAR
*format
, ...)
163 va_start(args
, format
);
164 _vtprintf(format
, args
);
172 void AgentConnection::receiverThread()
174 UINT32 msgBufferSize
= 1024;
176 NXCP_MESSAGE
*pRawMsg
;
177 NXCP_BUFFER
*pMsgBuffer
;
178 BYTE
*pDecryptionBuffer
= NULL
;
183 // Initialize raw message receiving function
184 pMsgBuffer
= (NXCP_BUFFER
*)malloc(sizeof(NXCP_BUFFER
));
185 RecvNXCPMessage(0, NULL
, pMsgBuffer
, 0, NULL
, NULL
, 0);
187 // Allocate space for raw message
188 pRawMsg
= (NXCP_MESSAGE
*)malloc(msgBufferSize
);
189 #ifdef _WITH_ENCRYPTION
190 pDecryptionBuffer
= (BYTE
*)malloc(msgBufferSize
);
193 // Message receiving loop
196 // Shrink buffer after receiving large message
197 if (msgBufferSize
> 131072)
199 msgBufferSize
= 131072;
200 pRawMsg
= (NXCP_MESSAGE
*)realloc(pRawMsg
, msgBufferSize
);
201 if (pDecryptionBuffer
!= NULL
)
202 pDecryptionBuffer
= (BYTE
*)realloc(pDecryptionBuffer
, msgBufferSize
);
205 // Receive raw message
209 if ((error
= RecvNXCPMessageEx(nSocket
, &pRawMsg
, pMsgBuffer
, &msgBufferSize
,
210 &m_pCtx
, (pDecryptionBuffer
!= NULL
) ? &pDecryptionBuffer
: NULL
,
211 m_dwRecvTimeout
, MAX_MSG_SIZE
)) <= 0)
213 if ((error
!= 0) && (WSAGetLastError() != WSAESHUTDOWN
))
214 DbgPrintf(6, _T("AgentConnection::ReceiverThread(): RecvNXCPMessage() failed: error=%d, socket_error=%d"), error
, WSAGetLastError());
218 // Check if we get too large message
221 printMsg(_T("Received too large message %s (%d bytes)"),
222 NXCPMessageCodeName(ntohs(pRawMsg
->code
), szBuffer
),
223 ntohl(pRawMsg
->size
));
227 // Check if we are unable to decrypt message
230 printMsg(_T("Unable to decrypt received message"));
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"));
243 // Check that actual received packet size is equal to encoded in packet
244 if ((int)ntohl(pRawMsg
->size
) != error
)
246 printMsg(_T("RecvMsg: Bad packet length [size=%d ActualSize=%d]"), ntohl(pRawMsg
->size
), error
);
247 continue; // Bad packet, wait for next
250 if (ntohs(pRawMsg
->flags
) & MF_BINARY
)
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());
259 if ((pRawMsg
->code
== CMD_FILE_DATA
) && (pRawMsg
->id
== m_dwDownloadRequestId
))
261 if (m_sendToClientMessageCallback
!= NULL
)
263 pRawMsg
->code
= ntohs(pRawMsg
->code
);
264 pRawMsg
->numFields
= ntohl(pRawMsg
->numFields
);
265 m_sendToClientMessageCallback(pRawMsg
, m_downloadProgressCallbackArg
);
267 if (ntohs(pRawMsg
->flags
) & MF_END_OF_FILE
)
269 onFileDownload(true);
273 if (m_downloadProgressCallback
!= NULL
)
275 m_downloadProgressCallback(pRawMsg
->size
- (NXCP_HEADER_SIZE
+ 8), m_downloadProgressCallbackArg
);
281 if (m_hCurrFile
!= -1)
283 if (write(m_hCurrFile
, pRawMsg
->fields
, pRawMsg
->numFields
) == (int)pRawMsg
->numFields
)
285 if (ntohs(pRawMsg
->flags
) & MF_END_OF_FILE
)
290 onFileDownload(true);
294 if (m_downloadProgressCallback
!= NULL
)
296 m_downloadProgressCallback(_tell(m_hCurrFile
), m_downloadProgressCallbackArg
);
307 onFileDownload(false);
312 if((pRawMsg
->code
== CMD_ABORT_FILE_TRANSFER
) && (pRawMsg
->id
== m_dwDownloadRequestId
))
314 if (m_sendToClientMessageCallback
!= NULL
)
316 pRawMsg
->code
= ntohs(pRawMsg
->code
);
317 pRawMsg
->numFields
= ntohl(pRawMsg
->numFields
);
318 m_sendToClientMessageCallback(pRawMsg
, m_downloadProgressCallbackArg
);
320 onFileDownload(false);
324 //error on agent side
328 onFileDownload(false);
334 // Create message object from raw message
335 pMsg
= new NXCPMessage(pRawMsg
, m_nProtocolVersion
);
336 switch(pMsg
->getCode())
338 case CMD_REQUEST_COMPLETED
:
339 case CMD_SESSION_KEY
:
340 m_pMsgWaitQueue
->put(pMsg
);
343 if (g_agentConnectionThreadPool
!= NULL
)
345 incInternalRefCount();
346 ThreadPoolExecute(g_agentConnectionThreadPool
, this, &AgentConnection::onTrapCallback
, pMsg
);
353 case CMD_PUSH_DCI_DATA
:
354 if (g_agentConnectionThreadPool
!= NULL
)
356 incInternalRefCount();
357 ThreadPoolExecute(g_agentConnectionThreadPool
, this, &AgentConnection::onDataPushCallback
, pMsg
);
365 if (g_agentConnectionThreadPool
!= NULL
)
367 incInternalRefCount();
368 ThreadPoolExecute(g_agentConnectionThreadPool
, this, &AgentConnection::processCollectedDataCallback
, pMsg
);
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
);
380 case CMD_FILE_MONITORING
:
381 onFileMonitoringData(pMsg
);
385 if (g_agentConnectionThreadPool
!= NULL
)
387 incInternalRefCount();
388 ThreadPoolExecute(g_agentConnectionThreadPool
, this, &AgentConnection::onSnmpTrapCallback
, pMsg
);
396 if (processCustomMessage(pMsg
))
399 m_pMsgWaitQueue
->put(pMsg
);
405 // Close socket and mark connection as disconnected
407 if (m_hCurrFile
!= -1)
411 onFileDownload(false);
415 shutdown(m_hSocket
, SHUT_RDWR
);
416 closesocket(m_hSocket
);
420 m_pCtx
->decRefCount();
423 m_isConnected
= false;
428 #ifdef _WITH_ENCRYPTION
429 free(pDecryptionBuffer
);
436 bool AgentConnection::connect(RSA
*pServerKey
, BOOL bVerbose
, UINT32
*pdwError
, UINT32
*pdwSocketError
, UINT64 serverId
)
439 bool success
= false;
440 bool forceEncryption
= false;
441 bool secondPass
= false;
444 if (pdwError
!= NULL
)
445 *pdwError
= ERR_INTERNAL_ERROR
;
447 if (pdwSocketError
!= NULL
)
450 // Check if already connected
454 // Wait for receiver thread from previous connection, if any
455 ThreadJoin(m_hReceiverThread
);
456 m_hReceiverThread
= INVALID_THREAD_HANDLE
;
458 // Check if we need to close existing socket
460 closesocket(m_hSocket
);
465 m_hSocket
= socket(m_bUseProxy
? m_proxyAddr
.getFamily() : m_addr
.getFamily(), SOCK_STREAM
, 0);
466 if (m_hSocket
== INVALID_SOCKET
)
468 printMsg(_T("Call to socket() failed"));
469 goto connect_cleanup
;
472 // Fill in address structure
474 sa
= m_bUseProxy
? m_proxyAddr
.fillSockAddr(&sb
, m_wProxyPort
) : m_addr
.fillSockAddr(&sb
, m_wPort
);
477 if ((sa
== NULL
) || (ConnectEx(m_hSocket
, sa
, SA_LEN(sa
), m_connectionTimeout
) == -1))
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
;
487 if (!NXCPGetPeerProtocolVersion(m_hSocket
, &m_nProtocolVersion
, m_mutexSocketWrite
))
489 dwError
= ERR_INTERNAL_ERROR
;
490 goto connect_cleanup
;
493 // Start receiver thread
494 incInternalRefCount();
495 m_hReceiverThread
= ThreadCreateEx(receiverThreadStarter
, 0, this);
499 if ((m_iEncryptionPolicy
== ENCRYPTION_PREFERRED
) ||
500 (m_iEncryptionPolicy
== ENCRYPTION_REQUIRED
) ||
501 forceEncryption
) // Agent require encryption
503 if (pServerKey
!= NULL
)
505 dwError
= setupEncryption(pServerKey
);
506 if ((dwError
!= ERR_SUCCESS
) &&
507 ((m_iEncryptionPolicy
== ENCRYPTION_REQUIRED
) || forceEncryption
))
508 goto connect_cleanup
;
512 if ((m_iEncryptionPolicy
== ENCRYPTION_REQUIRED
) || forceEncryption
)
514 dwError
= ERR_ENCRYPTION_REQUIRED
;
515 goto connect_cleanup
;
520 // Authenticate itself to agent
521 if ((dwError
= authenticate(m_bUseProxy
&& !secondPass
)) != ERR_SUCCESS
)
523 if ((dwError
== ERR_ENCRYPTION_REQUIRED
) &&
524 (m_iEncryptionPolicy
!= ENCRYPTION_DISABLED
))
526 forceEncryption
= true;
527 goto setup_encryption
;
529 printMsg(_T("Authentication to agent %s failed (%s)"), m_addr
.toString(szBuffer
),
530 AgentErrorCodeToText(dwError
));
531 goto connect_cleanup
;
534 // Test connectivity and inform agent about server capabilities
535 if ((dwError
= setServerCapabilities()) != ERR_SUCCESS
)
537 if ((dwError
== ERR_ENCRYPTION_REQUIRED
) &&
538 (m_iEncryptionPolicy
!= ENCRYPTION_DISABLED
))
540 forceEncryption
= true;
541 goto setup_encryption
;
543 if (dwError
!= ERR_UNKNOWN_COMMAND
) // Older agents may not support enable IPv6 command
545 printMsg(_T("Communication with agent %s failed (%s)"), m_addr
.toString(szBuffer
), AgentErrorCodeToText(dwError
));
546 goto connect_cleanup
;
550 if (m_bUseProxy
&& !secondPass
)
552 dwError
= setupProxyConnection();
553 if (dwError
!= ERR_SUCCESS
)
554 goto connect_cleanup
;
558 m_pCtx
->decRefCount();
563 forceEncryption
= false;
564 goto setup_encryption
;
568 setServerId(serverId
);
571 dwError
= ERR_SUCCESS
;
576 if (pdwSocketError
!= NULL
)
577 *pdwSocketError
= (UINT32
)WSAGetLastError();
581 shutdown(m_hSocket
, SHUT_RDWR
);
583 ThreadJoin(m_hReceiverThread
);
584 m_hReceiverThread
= INVALID_THREAD_HANDLE
;
589 closesocket(m_hSocket
);
595 m_pCtx
->decRefCount();
601 m_isConnected
= success
;
602 if (pdwError
!= NULL
)
608 * Disconnect from agent
610 void AgentConnection::disconnect()
613 if (m_hCurrFile
!= -1)
617 onFileDownload(false);
622 shutdown(m_hSocket
, SHUT_RDWR
);
625 m_isConnected
= false;
630 * Set authentication data
632 void AgentConnection::setAuthData(int method
, const TCHAR
*secret
)
634 m_iAuthMethod
= method
;
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;
639 nx_strncpy(m_szSecret
, secret
, MAX_SECRET_LENGTH
);
644 * Destroy command execuion results data
646 void AgentConnection::destroyResultData()
650 if (m_ppDataLines
!= NULL
)
652 for(i
= 0; i
< m_dwNumDataLines
; i
++)
653 if (m_ppDataLines
[i
] != NULL
)
654 free(m_ppDataLines
[i
]);
656 m_ppDataLines
= NULL
;
658 m_dwNumDataLines
= 0;
662 * Get interface list from agent
664 InterfaceList
*AgentConnection::getInterfaceList()
666 InterfaceList
*pIfList
= NULL
;
669 if (getList(_T("Net.InterfaceList")) == ERR_SUCCESS
)
671 pIfList
= new InterfaceList(m_dwNumDataLines
);
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
++)
677 pBuf
= m_ppDataLines
[i
];
681 pChar
= _tcschr(pBuf
, ' ');
685 ifIndex
= _tcstoul(pBuf
, NULL
, 10);
689 bool newInterface
= false;
690 InterfaceInfo
*iface
= pIfList
->findByIfIndex(ifIndex
);
693 iface
= new InterfaceInfo(ifIndex
);
698 pChar
= _tcschr(pBuf
, _T(' '));
702 static TCHAR defaultMask
[] = _T("24");
705 pSlash
= _tcschr(pBuf
, _T('/'));
711 else // Just a paranoia protection, should'n happen if agent working correctly
713 pSlash
= defaultMask
;
715 InetAddress addr
= InetAddress::parse(pBuf
);
716 addr
.setMaskBits(_tcstol(pSlash
, NULL
, 10));
717 iface
->ipAddrList
.add(addr
);
724 pChar
= _tcschr(pBuf
, ' ');
730 iface
->type
= _tcstoul(pBuf
, &eptr
, 10);
732 // newer agents can return if_type(mtu)
733 if (*eptr
== _T('('))
736 eptr
= _tcschr(pBuf
, _T(')'));
740 iface
->mtu
= _tcstol(pBuf
, NULL
, 10);
748 pChar
= _tcschr(pBuf
, ' ');
752 StrToBin(pBuf
, iface
->macAddr
, MAC_ADDR_LENGTH
);
756 // Name (set description to name)
757 nx_strncpy(iface
->name
, pBuf
, MAX_DB_STRING
);
758 nx_strncpy(iface
->description
, pBuf
, MAX_DB_STRING
);
773 * Get parameter value
775 UINT32
AgentConnection::getParameter(const TCHAR
*pszParam
, UINT32 dwBufSize
, TCHAR
*pszBuffer
)
778 return ERR_NOT_CONNECTED
;
780 NXCPMessage
msg(m_nProtocolVersion
);
781 UINT32 dwRqId
= generateRequestId();
782 msg
.setCode(CMD_GET_PARAMETER
);
784 msg
.setField(VID_PARAMETER
, pszParam
);
787 if (sendMessage(&msg
))
789 NXCPMessage
*pResponse
= waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, m_dwCommandTimeout
);
790 if (pResponse
!= NULL
)
792 dwRetCode
= pResponse
->getFieldAsUInt32(VID_RCC
);
793 if (dwRetCode
== ERR_SUCCESS
)
794 pResponse
->getFieldAsString(VID_VALUE
, pszBuffer
, dwBufSize
);
799 dwRetCode
= ERR_REQUEST_TIMEOUT
;
804 dwRetCode
= ERR_CONNECTION_BROKEN
;
812 ARP_CACHE
*AgentConnection::getArpCache()
814 ARP_CACHE
*pArpCache
= NULL
;
815 TCHAR szByte
[4], *pBuf
, *pChar
;
818 if (getList(_T("Net.ArpCache")) == ERR_SUCCESS
)
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
);
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
++)
835 pBuf
= m_ppDataLines
[i
];
836 if (_tcslen(pBuf
) < 20) // Invalid line
840 for(j
= 0; j
< 6; j
++)
842 memcpy(szByte
, pBuf
, sizeof(TCHAR
) * 2);
843 pArpCache
->pEntries
[i
].bMacAddr
[j
] = (BYTE
)_tcstol(szByte
, NULL
, 16);
850 pChar
= _tcschr(pBuf
, _T(' '));
853 pArpCache
->pEntries
[i
].ipAddr
= ntohl(_t_inet_addr(pBuf
));
857 pArpCache
->pEntries
[i
].dwIndex
= _tcstoul(pChar
+ 1, NULL
, 10);
868 * Send dummy command to agent (can be used for keepalive)
870 UINT32
AgentConnection::nop()
873 return ERR_CONNECTION_BROKEN
;
875 NXCPMessage
msg(m_nProtocolVersion
);
878 dwRqId
= generateRequestId();
879 msg
.setCode(CMD_KEEPALIVE
);
881 if (sendMessage(&msg
))
882 return waitForRCC(dwRqId
, m_dwCommandTimeout
);
884 return ERR_CONNECTION_BROKEN
;
888 * inform agent about server capabilities
890 UINT32
AgentConnection::setServerCapabilities()
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);
899 if (sendMessage(&msg
))
900 return waitForRCC(dwRqId
, m_dwCommandTimeout
);
902 return ERR_CONNECTION_BROKEN
;
908 UINT32
AgentConnection::setServerId(UINT64 serverId
)
910 NXCPMessage
msg(m_nProtocolVersion
);
911 UINT32 dwRqId
= generateRequestId();
912 msg
.setCode(CMD_SET_SERVER_ID
);
913 msg
.setField(VID_SERVER_ID
, serverId
);
915 if (sendMessage(&msg
))
916 return waitForRCC(dwRqId
, m_dwCommandTimeout
);
918 return ERR_CONNECTION_BROKEN
;
922 * Wait for request completion code
924 UINT32
AgentConnection::waitForRCC(UINT32 dwRqId
, UINT32 dwTimeOut
)
929 pMsg
= m_pMsgWaitQueue
->waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, dwTimeOut
);
932 dwRetCode
= pMsg
->getFieldAsUInt32(VID_RCC
);
937 dwRetCode
= ERR_REQUEST_TIMEOUT
;
943 * Send message to agent
945 bool AgentConnection::sendMessage(NXCPMessage
*pMsg
)
948 NXCP_MESSAGE
*pRawMsg
= pMsg
->createMessage();
949 NXCPEncryptionContext
*pCtx
= acquireEncryptionContext();
952 NXCP_ENCRYPTED_MESSAGE
*pEnMsg
= pCtx
->encryptMessage(pRawMsg
);
955 success
= (SendEx(m_hSocket
, (char *)pEnMsg
, ntohl(pEnMsg
->size
), 0, m_mutexSocketWrite
) == (int)ntohl(pEnMsg
->size
));
966 success
= (SendEx(m_hSocket
, (char *)pRawMsg
, ntohl(pRawMsg
->size
), 0, m_mutexSocketWrite
) == (int)ntohl(pRawMsg
->size
));
973 * Send raw message to agent
975 bool AgentConnection::sendRawMessage(NXCP_MESSAGE
*pMsg
)
978 NXCP_MESSAGE
*pRawMsg
= pMsg
;
979 NXCPEncryptionContext
*pCtx
= acquireEncryptionContext();
982 NXCP_ENCRYPTED_MESSAGE
*pEnMsg
= pCtx
->encryptMessage(pRawMsg
);
985 success
= (SendEx(m_hSocket
, (char *)pEnMsg
, ntohl(pEnMsg
->size
), 0, m_mutexSocketWrite
) == (int)ntohl(pEnMsg
->size
));
996 success
= (SendEx(m_hSocket
, (char *)pRawMsg
, ntohl(pRawMsg
->size
), 0, m_mutexSocketWrite
) == (int)ntohl(pRawMsg
->size
));
1002 * Callback for processing data push on separate thread
1004 void AgentConnection::onTrapCallback(NXCPMessage
*msg
)
1008 decInternalRefCount();
1012 * Trap handler. Should be overriden in derived classes to implement
1013 * actual trap processing. Default implementation do nothing.
1015 void AgentConnection::onTrap(NXCPMessage
*pMsg
)
1020 * Callback for processing data push on separate thread
1022 void AgentConnection::onDataPushCallback(NXCPMessage
*msg
)
1026 decInternalRefCount();
1030 * Data push handler. Should be overriden in derived classes to implement
1031 * actual data push processing. Default implementation do nothing.
1033 void AgentConnection::onDataPush(NXCPMessage
*pMsg
)
1038 * Monitoring data handler. Should be overriden in derived classes to implement
1039 * actual monitoring data processing. Default implementation do nothing.
1041 void AgentConnection::onFileMonitoringData(NXCPMessage
*pMsg
)
1046 * Callback for processing data push on separate thread
1048 void AgentConnection::onSnmpTrapCallback(NXCPMessage
*msg
)
1052 decInternalRefCount();
1056 * SNMP trap handler. Should be overriden in derived classes to implement
1057 * actual SNMP trap processing. Default implementation do nothing.
1059 void AgentConnection::onSnmpTrap(NXCPMessage
*pMsg
)
1064 * Custom message handler
1065 * If returns true, message considered as processed and will not be placed in wait queue
1067 bool AgentConnection::processCustomMessage(NXCPMessage
*pMsg
)
1073 * Get list of values
1075 UINT32
AgentConnection::getList(const TCHAR
*pszParam
)
1077 NXCPMessage
msg(m_nProtocolVersion
), *pResponse
;
1078 UINT32 i
, dwRqId
, dwRetCode
;
1082 destroyResultData();
1083 dwRqId
= generateRequestId();
1084 msg
.setCode(CMD_GET_LIST
);
1086 msg
.setField(VID_PARAMETER
, pszParam
);
1087 if (sendMessage(&msg
))
1089 pResponse
= waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, m_dwCommandTimeout
);
1090 if (pResponse
!= NULL
)
1092 dwRetCode
= pResponse
->getFieldAsUInt32(VID_RCC
);
1093 if (dwRetCode
== ERR_SUCCESS
)
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
);
1104 dwRetCode
= ERR_REQUEST_TIMEOUT
;
1109 dwRetCode
= ERR_CONNECTION_BROKEN
;
1114 dwRetCode
= ERR_NOT_CONNECTED
;
1123 UINT32
AgentConnection::getTable(const TCHAR
*pszParam
, Table
**table
)
1125 NXCPMessage
msg(m_nProtocolVersion
), *pResponse
;
1126 UINT32 dwRqId
, dwRetCode
;
1131 dwRqId
= generateRequestId();
1132 msg
.setCode(CMD_GET_TABLE
);
1134 msg
.setField(VID_PARAMETER
, pszParam
);
1135 if (sendMessage(&msg
))
1137 pResponse
= waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, m_dwCommandTimeout
);
1138 if (pResponse
!= NULL
)
1140 dwRetCode
= pResponse
->getFieldAsUInt32(VID_RCC
);
1141 if (dwRetCode
== ERR_SUCCESS
)
1143 *table
= new Table(pResponse
);
1149 dwRetCode
= ERR_REQUEST_TIMEOUT
;
1154 dwRetCode
= ERR_CONNECTION_BROKEN
;
1159 dwRetCode
= ERR_NOT_CONNECTED
;
1166 * Authenticate to agent
1168 UINT32
AgentConnection::authenticate(BOOL bProxyData
)
1170 NXCPMessage
msg(m_nProtocolVersion
);
1173 int iAuthMethod
= bProxyData
? m_iProxyAuth
: m_iAuthMethod
;
1174 const char *pszSecret
= bProxyData
? m_szProxySecret
: m_szSecret
;
1176 WCHAR szBuffer
[MAX_SECRET_LENGTH
];
1179 if (iAuthMethod
== AUTH_NONE
)
1180 return ERR_SUCCESS
; // No authentication required
1182 dwRqId
= generateRequestId();
1183 msg
.setCode(CMD_AUTHENTICATE
);
1185 msg
.setField(VID_AUTH_METHOD
, (WORD
)iAuthMethod
);
1188 case AUTH_PLAINTEXT
:
1190 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, pszSecret
, -1, szBuffer
, MAX_SECRET_LENGTH
);
1191 msg
.setField(VID_SHARED_SECRET
, szBuffer
);
1193 msg
.setField(VID_SHARED_SECRET
, pszSecret
);
1197 CalculateMD5Hash((BYTE
*)pszSecret
, (int)strlen(pszSecret
), hash
);
1198 msg
.setField(VID_SHARED_SECRET
, hash
, MD5_DIGEST_SIZE
);
1200 case AUTH_SHA1_HASH
:
1201 CalculateSHA1Hash((BYTE
*)pszSecret
, (int)strlen(pszSecret
), hash
);
1202 msg
.setField(VID_SHARED_SECRET
, hash
, SHA1_DIGEST_SIZE
);
1207 if (sendMessage(&msg
))
1208 return waitForRCC(dwRqId
, m_dwCommandTimeout
);
1210 return ERR_CONNECTION_BROKEN
;
1214 * Execute action on agent
1216 UINT32
AgentConnection::execAction(const TCHAR
*pszAction
, int argc
, TCHAR
**argv
,
1217 bool withOutput
, void (* outputCallback
)(ActionCallbackEvent
, const TCHAR
*, void *), void *cbData
)
1219 NXCPMessage
msg(m_nProtocolVersion
);
1224 return ERR_NOT_CONNECTED
;
1226 dwRqId
= generateRequestId();
1227 msg
.setCode(CMD_ACTION
);
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
]);
1235 if (sendMessage(&msg
))
1239 UINT32 rcc
= waitForRCC(dwRqId
, m_dwCommandTimeout
);
1240 if (rcc
== ERR_SUCCESS
)
1242 outputCallback(ACE_CONNECTED
, NULL
, cbData
); // Indicate successful start
1246 NXCPMessage
*response
= waitForMessage(CMD_COMMAND_OUTPUT
, dwRqId
, m_dwCommandTimeout
);
1247 if (response
!= NULL
)
1249 eos
= response
->isEndOfSequence();
1250 if (response
->isFieldExist(VID_MESSAGE
))
1253 response
->getFieldAsString(VID_MESSAGE
, line
, 4096);
1254 outputCallback(ACE_DATA
, line
, cbData
);
1260 return ERR_REQUEST_TIMEOUT
;
1263 outputCallback(ACE_DISCONNECTED
, NULL
, cbData
);
1273 return waitForRCC(dwRqId
, m_dwCommandTimeout
);
1278 return ERR_CONNECTION_BROKEN
;
1283 * Upload file to agent
1285 UINT32
AgentConnection::uploadFile(const TCHAR
*localFile
, const TCHAR
*destinationFile
, void (* progressCallback
)(INT64
, void *), void *cbArg
, NXCPCompressionMethod compMethod
)
1287 UINT32 dwRqId
, dwResult
;
1288 NXCPMessage
msg(m_nProtocolVersion
);
1291 return ERR_NOT_CONNECTED
;
1293 dwRqId
= generateRequestId();
1296 // Use core agent if destination file name is not set and file manager subagent otherwise
1297 if ((destinationFile
== NULL
) || (*destinationFile
== 0))
1299 msg
.setCode(CMD_TRANSFER_FILE
);
1301 for(i
= (int)_tcslen(localFile
) - 1;
1302 (i
>= 0) && (localFile
[i
] != '\\') && (localFile
[i
] != '/'); i
--);
1303 msg
.setField(VID_FILE_NAME
, &localFile
[i
+ 1]);
1307 msg
.setCode(CMD_FILEMGR_UPLOAD
);
1308 msg
.setField(VID_FILE_NAME
, destinationFile
);
1311 if (sendMessage(&msg
))
1313 dwResult
= waitForRCC(dwRqId
, m_dwCommandTimeout
);
1317 dwResult
= ERR_CONNECTION_BROKEN
;
1320 if (dwResult
== ERR_SUCCESS
)
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
);
1327 dwResult
= ERR_IO_FAILURE
;
1328 m_fileUploadInProgress
= false;
1335 * Send upgrade command
1337 UINT32
AgentConnection::startUpgrade(const TCHAR
*pszPkgName
)
1339 UINT32 dwRqId
, dwResult
;
1340 NXCPMessage
msg(m_nProtocolVersion
);
1344 return ERR_NOT_CONNECTED
;
1346 dwRqId
= generateRequestId();
1348 msg
.setCode(CMD_UPGRADE_AGENT
);
1350 for(i
= (int)_tcslen(pszPkgName
) - 1;
1351 (i
>= 0) && (pszPkgName
[i
] != '\\') && (pszPkgName
[i
] != '/'); i
--);
1352 msg
.setField(VID_FILE_NAME
, &pszPkgName
[i
+ 1]);
1354 if (sendMessage(&msg
))
1356 dwResult
= waitForRCC(dwRqId
, m_dwCommandTimeout
);
1360 dwResult
= ERR_CONNECTION_BROKEN
;
1367 * Check status of network service via agent
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
)
1373 UINT32 dwRqId
, dwResult
;
1374 NXCPMessage
msg(m_nProtocolVersion
), *pResponse
;
1375 static WORD m_wDefaultPort
[] = { 7, 22, 110, 25, 21, 80, 443, 23 };
1378 return ERR_NOT_CONNECTED
;
1380 dwRqId
= generateRequestId();
1382 msg
.setCode(CMD_CHECK_NETWORK_SERVICE
);
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
);
1394 if (sendMessage(&msg
))
1396 // Wait up to 90 seconds for results
1397 pResponse
= waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, 90000);
1398 if (pResponse
!= NULL
)
1400 dwResult
= pResponse
->getFieldAsUInt32(VID_RCC
);
1401 if (dwResult
== ERR_SUCCESS
)
1403 *pdwStatus
= pResponse
->getFieldAsUInt32(VID_SERVICE_STATUS
);
1404 if (responseTime
!= NULL
)
1406 *responseTime
= pResponse
->getFieldAsUInt32(VID_RESPONSE_TIME
);
1413 dwResult
= ERR_REQUEST_TIMEOUT
;
1418 dwResult
= ERR_CONNECTION_BROKEN
;
1425 * Get list of supported parameters from agent
1427 UINT32
AgentConnection::getSupportedParameters(ObjectArray
<AgentParameterDefinition
> **paramList
, ObjectArray
<AgentTableDefinition
> **tableList
)
1429 UINT32 dwRqId
, dwResult
;
1430 NXCPMessage
msg(m_nProtocolVersion
), *pResponse
;
1436 return ERR_NOT_CONNECTED
;
1438 dwRqId
= generateRequestId();
1440 msg
.setCode(CMD_GET_PARAMETER_LIST
);
1443 if (sendMessage(&msg
))
1445 pResponse
= waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, m_dwCommandTimeout
);
1446 if (pResponse
!= NULL
)
1448 dwResult
= pResponse
->getFieldAsUInt32(VID_RCC
);
1449 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): RCC=%d"), dwResult
);
1450 if (dwResult
== ERR_SUCCESS
)
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
++)
1456 plist
->add(new AgentParameterDefinition(pResponse
, id
));
1460 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d parameters received from agent"), count
);
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
++)
1466 tlist
->add(new AgentTableDefinition(pResponse
, id
));
1470 DbgPrintf(6, _T("AgentConnection::getSupportedParameters(): %d tables received from agent"), count
);
1476 dwResult
= ERR_REQUEST_TIMEOUT
;
1481 dwResult
= ERR_CONNECTION_BROKEN
;
1490 UINT32
AgentConnection::setupEncryption(RSA
*pServerKey
)
1492 #ifdef _WITH_ENCRYPTION
1493 NXCPMessage
msg(m_nProtocolVersion
), *pResp
;
1494 UINT32 dwRqId
, dwError
, dwResult
;
1496 dwRqId
= generateRequestId();
1498 PrepareKeyRequestMsg(&msg
, pServerKey
, false);
1500 if (sendMessage(&msg
))
1502 pResp
= waitForMessage(CMD_SESSION_KEY
, dwRqId
, m_dwCommandTimeout
);
1505 dwResult
= SetupEncryptionContext(pResp
, &m_pCtx
, NULL
, pServerKey
, m_nProtocolVersion
);
1509 dwError
= ERR_SUCCESS
;
1511 case RCC_NO_CIPHERS
:
1512 dwError
= ERR_NO_CIPHERS
;
1514 case RCC_INVALID_PUBLIC_KEY
:
1515 dwError
= ERR_INVALID_PUBLIC_KEY
;
1517 case RCC_INVALID_SESSION_KEY
:
1518 dwError
= ERR_INVALID_SESSION_KEY
;
1521 dwError
= ERR_INTERNAL_ERROR
;
1528 dwError
= ERR_REQUEST_TIMEOUT
;
1533 dwError
= ERR_CONNECTION_BROKEN
;
1538 return ERR_NOT_IMPLEMENTED
;
1543 * Get configuration file from agent
1545 UINT32
AgentConnection::getConfigFile(TCHAR
**ppszConfig
, UINT32
*pdwSize
)
1547 UINT32 i
, dwRqId
, dwResult
;
1548 NXCPMessage
msg(m_nProtocolVersion
), *pResponse
;
1554 return ERR_NOT_CONNECTED
;
1556 dwRqId
= generateRequestId();
1558 msg
.setCode(CMD_GET_AGENT_CONFIG
);
1561 if (sendMessage(&msg
))
1563 pResponse
= waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, m_dwCommandTimeout
);
1564 if (pResponse
!= NULL
)
1566 dwResult
= pResponse
->getFieldAsUInt32(VID_RCC
);
1567 if (dwResult
== ERR_SUCCESS
)
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
);
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'))
1583 *ppszConfig
= WideStringFromUTF8String((char *)utf8Text
);
1585 *ppszConfig
= MBStringFromUTF8String((char *)utf8Text
);
1588 *pdwSize
= (UINT32
)_tcslen(*ppszConfig
);
1594 dwResult
= ERR_REQUEST_TIMEOUT
;
1599 dwResult
= ERR_CONNECTION_BROKEN
;
1606 * Update configuration file on agent
1608 UINT32
AgentConnection::updateConfigFile(const TCHAR
*pszConfig
)
1610 UINT32 dwRqId
, dwResult
;
1611 NXCPMessage
msg(m_nProtocolVersion
);
1618 return ERR_NOT_CONNECTED
;
1620 dwRqId
= generateRequestId();
1622 msg
.setCode(CMD_UPDATE_AGENT_CONFIG
);
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
);
1632 msg
.setField(VID_CONFIG_FILE
, (BYTE
*)pszConfig
, (UINT32
)strlen(pszConfig
));
1635 if (sendMessage(&msg
))
1637 dwResult
= waitForRCC(dwRqId
, m_dwCommandTimeout
);
1641 dwResult
= ERR_CONNECTION_BROKEN
;
1648 * Get routing table from agent
1650 ROUTING_TABLE
*AgentConnection::getRoutingTable()
1652 ROUTING_TABLE
*pRT
= NULL
;
1654 TCHAR
*pChar
, *pBuf
;
1656 if (getList(_T("Net.IP.RoutingTable")) == ERR_SUCCESS
)
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
++)
1664 pBuf
= m_ppDataLines
[i
];
1666 // Destination address and mask
1667 pChar
= _tcschr(pBuf
, _T(' '));
1671 static TCHAR defaultMask
[] = _T("24");
1674 pSlash
= _tcschr(pBuf
, _T('/'));
1680 else // Just a paranoia protection, should'n happen if agent working correctly
1682 pSlash
= defaultMask
;
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
));
1691 pChar
= _tcschr(pBuf
, _T(' '));
1695 pRT
->pRoutes
[i
].dwNextHop
= ntohl(_t_inet_addr(pBuf
));
1700 pChar
= _tcschr(pBuf
, ' ');
1704 pRT
->pRoutes
[i
].dwIfIndex
= _tcstoul(pBuf
, NULL
, 10);
1709 pRT
->pRoutes
[i
].dwRouteType
= _tcstoul(pBuf
, NULL
, 10);
1713 destroyResultData();
1721 * Set proxy information
1723 void AgentConnection::setProxy(InetAddress addr
, WORD wPort
, int iAuthMethod
, const TCHAR
*pszSecret
)
1726 m_wProxyPort
= wPort
;
1727 m_iProxyAuth
= iAuthMethod
;
1728 if (pszSecret
!= NULL
)
1731 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
,
1732 pszSecret
, -1, m_szProxySecret
, MAX_SECRET_LENGTH
, NULL
, NULL
);
1734 nx_strncpy(m_szProxySecret
, pszSecret
, MAX_SECRET_LENGTH
);
1739 m_szProxySecret
[0] = 0;
1745 * Setup proxy connection
1747 UINT32
AgentConnection::setupProxyConnection()
1749 NXCPMessage
msg(m_nProtocolVersion
);
1752 dwRqId
= generateRequestId();
1753 msg
.setCode(CMD_SETUP_PROXY_CONNECTION
);
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
1760 return ERR_CONNECTION_BROKEN
;
1764 * Enable trap receiving on connection
1766 UINT32
AgentConnection::enableTraps()
1768 NXCPMessage
msg(m_nProtocolVersion
);
1771 dwRqId
= generateRequestId();
1772 msg
.setCode(CMD_ENABLE_AGENT_TRAPS
);
1774 if (sendMessage(&msg
))
1775 return waitForRCC(dwRqId
, m_dwCommandTimeout
);
1777 return ERR_CONNECTION_BROKEN
;
1781 * Enable trap receiving on connection
1783 UINT32
AgentConnection::enableFileUpdates()
1785 NXCPMessage
msg(m_nProtocolVersion
);
1788 dwRqId
= generateRequestId();
1789 msg
.setCode(CMD_ENABLE_FILE_UPDATES
);
1791 if (sendMessage(&msg
))
1793 return waitForRCC(dwRqId
, m_dwCommandTimeout
);
1796 return ERR_CONNECTION_BROKEN
;
1800 * Take screenshot from remote system
1802 UINT32
AgentConnection::takeScreenshot(const TCHAR
*sessionName
, BYTE
**data
, size_t *size
)
1804 NXCPMessage
msg(m_nProtocolVersion
);
1807 dwRqId
= generateRequestId();
1808 msg
.setCode(CMD_TAKE_SCREENSHOT
);
1810 msg
.setField(VID_NAME
, sessionName
);
1811 if (sendMessage(&msg
))
1813 NXCPMessage
*response
= waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, m_dwCommandTimeout
);
1814 if (response
!= NULL
)
1816 UINT32 rcc
= response
->getFieldAsUInt32(VID_RCC
);
1817 if (rcc
== ERR_SUCCESS
)
1819 const BYTE
*p
= response
->getBinaryFieldPtr(VID_FILE_DATA
, size
);
1822 *data
= (BYTE
*)malloc(*size
);
1823 memcpy(*data
, p
, *size
);
1835 return ERR_REQUEST_TIMEOUT
;
1840 return ERR_CONNECTION_BROKEN
;
1845 * Send custom request to agent
1847 NXCPMessage
*AgentConnection::customRequest(NXCPMessage
*pRequest
, const TCHAR
*recvFile
, bool append
, void (*downloadProgressCallback
)(size_t, void *),
1848 void (*fileResendCallback
)(NXCP_MESSAGE
*, void *), void *cbArg
)
1851 NXCPMessage
*msg
= NULL
;
1853 dwRqId
= generateRequestId();
1854 pRequest
->setId(dwRqId
);
1855 if (recvFile
!= NULL
)
1857 rcc
= prepareFileDownload(recvFile
, dwRqId
, append
, downloadProgressCallback
, fileResendCallback
,cbArg
);
1858 if (rcc
!= ERR_SUCCESS
)
1860 // Create fake response message
1861 msg
= new NXCPMessage
;
1862 msg
->setCode(CMD_REQUEST_COMPLETED
);
1864 msg
->setField(VID_RCC
, rcc
);
1870 if (sendMessage(pRequest
))
1872 msg
= waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, m_dwCommandTimeout
);
1873 if ((msg
!= NULL
) && (recvFile
!= NULL
))
1875 if (msg
->getFieldAsUInt32(VID_RCC
) == ERR_SUCCESS
)
1877 if (ConditionWait(m_condFileDownload
, 1800000)) // 30 min timeout
1879 if (!m_fileDownloadSucceeded
)
1881 msg
->setField(VID_RCC
, ERR_IO_FAILURE
);
1882 if (m_deleteFileOnDownloadFailure
)
1888 msg
->setField(VID_RCC
, ERR_REQUEST_TIMEOUT
);
1893 if (fileResendCallback
!= NULL
)
1909 * Prepare for file download
1911 UINT32
AgentConnection::prepareFileDownload(const TCHAR
*fileName
, UINT32 rqId
, bool append
, void (*downloadProgressCallback
)(size_t, void *),
1912 void (*fileResendCallback
)(NXCP_MESSAGE
*, void *), void *cbArg
)
1914 if (fileResendCallback
== NULL
)
1916 if (m_hCurrFile
!= -1)
1917 return ERR_RESOURCE_BUSY
;
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)
1924 DbgPrintf(4, _T("AgentConnection::PrepareFileDownload(): cannot open file %s (%s); append=%d rqId=%d"),
1925 fileName
, _tcserror(errno
), append
, rqId
);
1930 lseek(m_hCurrFile
, 0, SEEK_END
);
1933 m_dwDownloadRequestId
= rqId
;
1934 m_downloadProgressCallback
= downloadProgressCallback
;
1935 m_downloadProgressCallbackArg
= cbArg
;
1937 m_sendToClientMessageCallback
= NULL
;
1939 return (m_hCurrFile
!= -1) ? ERR_SUCCESS
: ERR_FILE_OPEN_ERROR
;
1943 ConditionReset(m_condFileDownload
);
1945 m_dwDownloadRequestId
= rqId
;
1946 m_downloadProgressCallback
= downloadProgressCallback
;
1947 m_downloadProgressCallbackArg
= cbArg
;
1949 m_sendToClientMessageCallback
= fileResendCallback
;
1956 * File upload completion handler
1958 void AgentConnection::onFileDownload(bool success
)
1960 if (!success
&& m_deleteFileOnDownloadFailure
)
1961 _tremove(m_currentFileName
);
1962 m_fileDownloadSucceeded
= success
;
1963 ConditionSet(m_condFileDownload
);
1967 * Enable trap receiving on connection
1969 UINT32
AgentConnection::getPolicyInventory(AgentPolicyInfo
**info
)
1971 NXCPMessage
msg(m_nProtocolVersion
);
1975 dwRqId
= generateRequestId();
1976 msg
.setCode(CMD_GET_POLICY_INVENTORY
);
1978 if (sendMessage(&msg
))
1980 NXCPMessage
*response
= waitForMessage(CMD_REQUEST_COMPLETED
, dwRqId
, m_dwCommandTimeout
);
1981 if (response
!= NULL
)
1983 rcc
= response
->getFieldAsUInt32(VID_RCC
);
1984 if (rcc
== ERR_SUCCESS
)
1985 *info
= new AgentPolicyInfo(response
);
1990 rcc
= ERR_REQUEST_TIMEOUT
;
1995 rcc
= ERR_CONNECTION_BROKEN
;
2001 * Uninstall policy by GUID
2003 UINT32
AgentConnection::uninstallPolicy(const uuid
& guid
)
2006 NXCPMessage
msg(m_nProtocolVersion
);
2008 rqId
= generateRequestId();
2010 msg
.setCode(CMD_UNINSTALL_AGENT_POLICY
);
2011 msg
.setField(VID_GUID
, guid
);
2012 if (sendMessage(&msg
))
2014 rcc
= waitForRCC(rqId
, m_dwCommandTimeout
);
2018 rcc
= ERR_CONNECTION_BROKEN
;
2024 * Acquire encryption context
2026 NXCPEncryptionContext
*AgentConnection::acquireEncryptionContext()
2029 NXCPEncryptionContext
*ctx
= m_pCtx
;
2037 * Callback for processing collected data on separate thread
2039 void AgentConnection::processCollectedDataCallback(NXCPMessage
*msg
)
2041 NXCPMessage response
;
2042 response
.setCode(CMD_REQUEST_COMPLETED
);
2043 response
.setId(msg
->getId());
2045 if (msg
->getFieldAsBoolean(VID_BULK_RECONCILIATION
))
2047 UINT32 rcc
= processBulkCollectedData(msg
, &response
);
2048 response
.setField(VID_RCC
, rcc
);
2052 UINT32 rcc
= processCollectedData(msg
);
2053 response
.setField(VID_RCC
, rcc
);
2056 sendMessage(&response
);
2058 decInternalRefCount();
2062 * Process collected data information (for DCI with agent-side cache)
2064 UINT32
AgentConnection::processCollectedData(NXCPMessage
*msg
)
2066 return ERR_NOT_IMPLEMENTED
;
2070 * Process collected data information in bulk mode (for DCI with agent-side cache)
2072 UINT32
AgentConnection::processBulkCollectedData(NXCPMessage
*request
, NXCPMessage
*response
)
2074 return ERR_NOT_IMPLEMENTED
;
2078 * Create new agent parameter definition from NXCP message
2080 AgentParameterDefinition::AgentParameterDefinition(NXCPMessage
*msg
, UINT32 baseId
)
2082 m_name
= msg
->getFieldAsString(baseId
);
2083 m_description
= msg
->getFieldAsString(baseId
+ 1);
2084 m_dataType
= (int)msg
->getFieldAsUInt16(baseId
+ 2);
2088 * Create new agent parameter definition from another definition object
2090 AgentParameterDefinition::AgentParameterDefinition(AgentParameterDefinition
*src
)
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
;
2098 * Destructor for agent parameter definition
2100 AgentParameterDefinition::~AgentParameterDefinition()
2103 safe_free(m_description
);
2109 UINT32
AgentParameterDefinition::fillMessage(NXCPMessage
*msg
, UINT32 baseId
)
2111 msg
->setField(baseId
, m_name
);
2112 msg
->setField(baseId
+ 1, m_description
);
2113 msg
->setField(baseId
+ 2, (WORD
)m_dataType
);
2118 * Create new agent table definition from NXCP message
2120 AgentTableDefinition::AgentTableDefinition(NXCPMessage
*msg
, UINT32 baseId
)
2122 m_name
= msg
->getFieldAsString(baseId
);
2123 m_description
= msg
->getFieldAsString(baseId
+ 2);
2125 TCHAR
*instanceColumns
= msg
->getFieldAsString(baseId
+ 1);
2126 if (instanceColumns
!= NULL
)
2128 m_instanceColumns
= new StringList(instanceColumns
, _T("|"));
2129 free(instanceColumns
);
2133 m_instanceColumns
= new StringList
;
2136 m_columns
= new ObjectArray
<AgentTableColumnDefinition
>(16, 16, true);
2140 * Create new agent table definition from another definition object
2142 AgentTableDefinition::AgentTableDefinition(AgentTableDefinition
*src
)
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
++)
2150 m_columns
->add(new AgentTableColumnDefinition(src
->m_columns
->get(i
)));
2154 * Destructor for agent table definition
2156 AgentTableDefinition::~AgentTableDefinition()
2159 safe_free(m_description
);
2160 delete m_instanceColumns
;
2167 UINT32
AgentTableDefinition::fillMessage(NXCPMessage
*msg
, UINT32 baseId
)
2169 msg
->setField(baseId
+ 1, m_name
);
2170 msg
->setField(baseId
+ 2, m_description
);
2172 TCHAR
*instanceColumns
= m_instanceColumns
->join(_T("|"));
2173 msg
->setField(baseId
+ 3, instanceColumns
);
2174 free(instanceColumns
);
2176 UINT32 varId
= baseId
+ 4;
2177 for(int i
= 0; i
< m_columns
->size(); i
++)
2179 msg
->setField(varId
++, m_columns
->get(i
)->m_name
);
2180 msg
->setField(varId
++, (WORD
)m_columns
->get(i
)->m_dataType
);
2183 msg
->setField(baseId
, varId
- baseId
);
2184 return varId
- baseId
;