- libnxcscp merged into libnetxms
authorVictor Kirhenshtein <victor@netxms.org>
Fri, 20 Oct 2006 10:16:04 +0000 (10:16 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Fri, 20 Oct 2006 10:16:04 +0000 (10:16 +0000)
- Fixed NetWare compilation issues

28 files changed:
.gitattributes
Makefile.nw
include/config-netware.h
netware/nlmconv.inc
src/agent/core/Makefile.am
src/agent/core/nxagentd.def
src/agent/subagents/logscan/Makefile.am
src/agent/subagents/portCheck/Makefile.am
src/libnetxms/Makefile.am
src/libnetxms/Makefile.nw
src/libnetxms/crypto.cpp [new file with mode: 0644]
src/libnetxms/dload.cpp
src/libnetxms/message.cpp [new file with mode: 0644]
src/libnetxms/msgwq.cpp [new file with mode: 0644]
src/libnetxms/nxcp.cpp [new file with mode: 0644]
src/libnetxms/serial.cpp
src/libnxcl/Makefile.am
src/libnxmap/Makefile.am
src/libnxsl/Makefile.am
src/nxevent/Makefile.am
src/nxscript/Makefile.am
src/server/core/Makefile.am
src/server/libnxsrv/Makefile.am
src/server/netxmsd/Makefile.am
src/server/tools/nxaction/Makefile.am
src/server/tools/nxadm/Makefile.am
src/server/tools/nxget/Makefile.am
src/server/tools/nxupload/Makefile.am

index 2cb3851..0e4c981 100644 (file)
@@ -947,6 +947,7 @@ src/libnetxms/Makefile.am -text
 src/libnetxms/Makefile.nw -text
 src/libnetxms/c_lgcc3.cpp -text
 src/libnetxms/config.cpp -text
+src/libnetxms/crypto.cpp -text
 src/libnetxms/dir.c -text
 src/libnetxms/dload.cpp -text
 src/libnetxms/gen_uuid.c -text
@@ -962,7 +963,10 @@ src/libnetxms/libnetxms.vcw -text
 src/libnetxms/main.cpp -text
 src/libnetxms/md5.cpp -text
 src/libnetxms/md5.h -text
+src/libnetxms/message.cpp -text
+src/libnetxms/msgwq.cpp -text
 src/libnetxms/netxms.def -text
+src/libnetxms/nxcp.cpp -text
 src/libnetxms/queue.cpp -text
 src/libnetxms/regex.c -text
 src/libnetxms/rwlock.cpp -text
index 119f6ea..39ba895 100644 (file)
@@ -3,7 +3,7 @@
 # Copyright (c) 2006 Victor Kirhenshtein
 #
 
-SUBDIRS = src/libnetxms src/libnxcscp src/agent/core \
+SUBDIRS = src/libnetxms src/agent/core \
           src/agent/subagents/netware src/agent/subagents/ping
 COMMAND = for dir in $(SUBDIRS); do \
           if ! make -C $$dir -f Makefile.nw $@; then exit $$?; fi; done
index 019ad5c..bcd2787 100644 (file)
@@ -12,8 +12,8 @@
 /* Define to 1 if you have the `sys/utsname.h' header file. */
 #define HAVE_SYS_UTSNAME_H 1
 
-/* Define to 1 if you have the <termio.h> header file. */
-#define HAVE_TERMIO_H 1
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
 
 /* The size of a `long', as computed by sizeof. */
 #define SIZEOF_LONG 4
index 9a0d910..2da0fed 100644 (file)
@@ -3,5 +3,5 @@ INPUT c:/nwsdk/libc/imports/libcpre.gcc.o   # clib startup code
 IMPORT @c:/nwsdk/libc/imports/libc.imp
 IMPORT @c:/nwsdk/libc/imports/netware.imp
 
-VERSION 0,2,13
+VERSION 0,2,14
 COPYRIGHT "Copyright (c) 2004, 2005, 2006 NetXMS Team"
index d4b8e59..54d1817 100644 (file)
@@ -11,7 +11,7 @@ INCLUDES=-I@top_srcdir@/include
 
 bin_PROGRAMS = nxagentd
 nxagentd_SOURCES = messages.c actions.cpp comm.cpp config.cpp exec.cpp getparam.cpp log.cpp lpp.cpp nxagentd.cpp session.cpp static_subagents.cpp subagent.cpp sysinfo.cpp tools.cpp trap.cpp upgrade.cpp
-nxagentd_LDADD = @ALL_STATIC_FLAG@ @PTHREAD_LIBS@ ../../libnetxms/libnetxms.la ../../libnxcscp/libnxcscp.la @SUBAGENT_LIBS@
+nxagentd_LDADD = @ALL_STATIC_FLAG@ @PTHREAD_LIBS@ ../../libnetxms/libnetxms.la @SUBAGENT_LIBS@
 AM_CPPFLAGS = $(all_includes) -DPREFIX=\"@prefix@\"
 CLEANFILES = messages.c messages.h static_subagents.cpp
 
index 54993cd..88f88d7 100644 (file)
@@ -11,7 +11,6 @@ INPUT nxagentd_r.o
 
 # Import/Export
 IMPORT @../../libnetxms/netxms.imp
-IMPORT @../../libnxcscp/nxcscp.imp
 
 # Entry points
 START _LibCPrelude
@@ -23,4 +22,4 @@ TYPE 0
 DESCRIPTION "NetXMS Core Agent"
 SCREENNAME "NetXMS Agent"
 
-MODULE LIBC, NETXMS, NXCSCP
+MODULE LIBC, NETXMS
index e63bd76..4719b95 100644 (file)
@@ -1,10 +1,10 @@
-# $Id: Makefile.am,v 1.2 2006-03-09 12:25:26 victor Exp $
+# $Id: Makefile.am,v 1.3 2006-10-20 10:15:54 victor Exp $
 
 INCLUDES=-I@top_srcdir@/include
 
 lib_LTLIBRARIES = libnsm_logscan.la
 libnsm_logscan_la_SOURCES = logscan.cpp
-libnsm_logscan_la_LDFLAGS = ../../../libnetxms/libnetxms.la ../../../libnxcscp/libnxcscp.la
+libnsm_logscan_la_LDFLAGS = ../../../libnetxms/libnetxms.la
 
 EXTRA_DIST = logscan.dsw logscan.dsp logscan.h
 
index 7308320..e0d9d7b 100644 (file)
@@ -1,11 +1,11 @@
-# $Id: Makefile.am,v 1.11 2006-09-27 19:09:18 victor Exp $
+# $Id: Makefile.am,v 1.12 2006-10-20 10:15:55 victor Exp $
 
 INCLUDES=-I@top_srcdir@/include
 
 lib_LTLIBRARIES = libnsm_portCheck.la
 libnsm_portCheck_la_SOURCES = main.cpp net.cpp pop3.cpp ssh.cpp smtp.cpp \
        http.cpp custom.cpp telnet.cpp
-libnsm_portCheck_la_LDFLAGS = ../../../libnetxms/libnetxms.la ../../../libnxcscp/libnxcscp.la
+libnsm_portCheck_la_LDFLAGS = ../../../libnetxms/libnetxms.la
 
 EXTRA_DIST = net.h main.h
 
index 0fa1721..e3e471c 100644 (file)
@@ -1,7 +1,7 @@
 INCLUDES=-I@top_srcdir@/include
 
 lib_LTLIBRARIES = libnetxms.la
-libnetxms_la_SOURCES = config.cpp gen_uuid.c dload.cpp hash.cpp icmp.cpp inline.cpp main.cpp md5.cpp queue.cpp rwlock.cpp scandir.c serial.cpp sha1.cpp strtoll.c strtoull.c threads.cpp tools.cpp unicode.cpp uuid.c
+libnetxms_la_SOURCES = config.cpp crypto.cpp gen_uuid.c dload.cpp hash.cpp icmp.cpp inline.cpp main.cpp md5.cpp message.cpp msgwq.cpp nxcp.cpp queue.cpp rwlock.cpp scandir.c serial.cpp sha1.cpp strtoll.c strtoull.c threads.cpp tools.cpp unicode.cpp uuid.c
 libnetxms_la_LDFLAGS = -version-info $(LIBNETXMS_LIBRARY_VERSION) $(PTHREAD_LIBS)
 
 EXTRA_DIST = \
index 6f10115..7947cfc 100644 (file)
@@ -5,9 +5,9 @@
 
 include ../../netware/Makefile.inc
 
-OBJECTS  = c_lgcc3.o config.o gen_uuid.o dload.o hash.o icmp.o inline.o \
-          main.o md5.o queue.o sha1.o strtoll.o strtoull.o tools.o \
-          unicode.o uuid.o
+OBJECTS  = c_lgcc3.o config.o crypto.o gen_uuid.o dload.o hash.o icmp.o \
+          inline.o main.o md5.o message.o msgwq.o nxcp.o queue.o serial.o \
+          sha1.o strtoll.o strtoull.o tools.o unicode.o uuid.o
 EXEC     = netxms.nlm
 DEF      = netxms.def
 OBJTMP   = netxms_r.o
diff --git a/src/libnetxms/crypto.cpp b/src/libnetxms/crypto.cpp
new file mode 100644 (file)
index 0000000..6c1fea4
--- /dev/null
@@ -0,0 +1,498 @@
+/* 
+** NetXMS - Network Management System
+** NetXMS Foundation Library
+** Copyright (C) 2003, 2004, 2005, 2006 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: crypto.cpp
+**
+**/
+
+#include "libnetxms.h"
+
+
+//
+// Constants
+//
+
+#define KEY_BUFFER_SIZE       4096
+
+
+//
+// Supported ciphers. By default, we support all ciphers compiled
+// into OpenSSL library.
+//
+
+static DWORD m_dwSupportedCiphers = 
+#ifdef _WITH_ENCRYPTION
+#ifndef OPENSSL_NO_AES
+   CSCP_SUPPORT_AES_256 |
+#endif
+#ifndef OPENSSL_NO_BF
+   CSCP_SUPPORT_BLOWFISH |
+#endif
+#ifndef OPENSSL_NO_IDEA
+   CSCP_SUPPORT_IDEA |
+#endif
+#ifndef OPENSSL_NO_DES
+   CSCP_SUPPORT_3DES |
+#endif
+#endif   /* _WITH_ENCRYPTION */
+   0;
+
+
+//
+// Static data
+//
+
+#ifdef _WITH_ENCRYPTION
+
+typedef OPENSSL_CONST EVP_CIPHER * (*CIPHER_FUNC)(void);
+static CIPHER_FUNC m_pfCipherList[NETXMS_MAX_CIPHERS] =
+{
+#ifndef OPENSSL_NO_AES
+   EVP_aes_256_cbc,
+#else
+   NULL,
+#endif
+#ifndef OPENSSL_NO_BF
+   EVP_bf_cbc,
+#else
+   NULL,
+#endif
+#ifndef OPENSSL_NO_IDEA
+   EVP_idea_cbc,
+#else
+   NULL,
+#endif
+#ifndef OPENSSL_NO_DES
+   EVP_des_ede3_cbc
+#else
+   NULL
+#endif
+};
+static WORD m_wNoEncryptionFlag = 0;
+static MUTEX *m_pCryptoMutexList = NULL;
+
+
+//
+// Locking callback for CRYPTO library
+//
+
+static void CryptoLockingCallback(int nMode, int nLock, const char *pszFile, int nLine)
+{
+   if (nMode & CRYPTO_LOCK)
+      MutexLock(m_pCryptoMutexList[nLock], INFINITE);
+   else
+      MutexUnlock(m_pCryptoMutexList[nLock]);
+}
+
+
+//
+// ID callback for CRYPTO library
+//
+
+#ifndef _WIN32
+
+static unsigned long CryptoIdCallback(void)
+{
+   return (unsigned long)GetCurrentThreadId();
+}
+
+#endif
+
+#endif   /* _WITH_ENCRYPTION */
+
+
+//
+// Initialize OpenSSL library
+//
+
+BOOL LIBNETXMS_EXPORTABLE InitCryptoLib(DWORD dwEnabledCiphers)
+{
+#ifdef _WITH_ENCRYPTION
+   BYTE random[8192];
+   int i;
+
+   CRYPTO_malloc_init();
+   ERR_load_CRYPTO_strings();
+   OpenSSL_add_all_algorithms();
+   RAND_seed(random, 8192);
+   m_dwSupportedCiphers &= dwEnabledCiphers;
+   m_wNoEncryptionFlag = htons(MF_DONT_ENCRYPT);
+   m_pCryptoMutexList = (MUTEX *)malloc(sizeof(MUTEX) * CRYPTO_num_locks());
+   for(i = 0; i < CRYPTO_num_locks(); i++)
+      m_pCryptoMutexList[i] = MutexCreate();
+   CRYPTO_set_locking_callback(CryptoLockingCallback);
+#ifndef _WIN32
+   CRYPTO_set_id_callback(CryptoIdCallback);
+#endif   /* _WIN32 */
+#endif   /* _WITH_ENCRYPTION */
+   return TRUE;
+}
+
+
+//
+// Get supported ciphers
+//
+
+DWORD LIBNETXMS_EXPORTABLE CSCPGetSupportedCiphers(void)
+{
+   return m_dwSupportedCiphers;
+}
+
+
+//
+// Encrypt message
+//
+
+CSCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE 
+   *CSCPEncryptMessage(CSCP_ENCRYPTION_CONTEXT *pCtx, CSCP_MESSAGE *pMsg)
+{
+#ifdef _WITH_ENCRYPTION
+   CSCP_ENCRYPTED_MESSAGE *pEnMsg;
+   CSCP_ENCRYPTED_PAYLOAD_HEADER header;
+   int nSize;
+   EVP_CIPHER_CTX cipher;
+   DWORD dwMsgSize;
+
+   if (pMsg->wFlags & m_wNoEncryptionFlag)
+      return (CSCP_ENCRYPTED_MESSAGE *)nx_memdup(pMsg, ntohl(pMsg->dwSize));
+
+   if (m_pfCipherList[pCtx->nCipher] == NULL)
+      return NULL;   // Unsupported cipher
+
+   EVP_EncryptInit(&cipher, m_pfCipherList[pCtx->nCipher](), pCtx->pSessionKey, pCtx->iv);
+   EVP_CIPHER_CTX_set_key_length(&cipher, pCtx->nKeyLen);
+
+   dwMsgSize = ntohl(pMsg->dwSize);
+   pEnMsg = (CSCP_ENCRYPTED_MESSAGE *)malloc(dwMsgSize + CSCP_ENCRYPTION_HEADER_SIZE + 
+                     EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(&cipher)) + 8);
+   pEnMsg->wCode = htons(CMD_ENCRYPTED_MESSAGE);
+
+   header.dwChecksum = htonl(CalculateCRC32((BYTE *)pMsg, dwMsgSize, 0));
+   EVP_EncryptUpdate(&cipher, pEnMsg->data, &nSize, (BYTE *)&header, CSCP_EH_ENCRYPTED_BYTES);
+   dwMsgSize = nSize;
+   EVP_EncryptUpdate(&cipher, pEnMsg->data + dwMsgSize, &nSize, (BYTE *)pMsg, ntohl(pMsg->dwSize));
+   dwMsgSize += nSize;
+   EVP_EncryptFinal(&cipher, pEnMsg->data + dwMsgSize, &nSize);
+   dwMsgSize += nSize + CSCP_EH_UNENCRYPTED_BYTES;
+   EVP_CIPHER_CTX_cleanup(&cipher);
+
+   if (dwMsgSize % 8 != 0)
+   {
+      pEnMsg->nPadding = (BYTE)(8 - (dwMsgSize % 8));
+      dwMsgSize += pEnMsg->nPadding;
+   }
+   else
+   {
+      pEnMsg->nPadding = 0;
+   }
+   pEnMsg->dwSize = htonl(dwMsgSize);
+
+   return pEnMsg;
+#else    /* _WITH_ENCRYPTION */
+   return NULL;
+#endif
+}
+
+
+//
+// Decrypt message
+//
+
+BOOL LIBNETXMS_EXPORTABLE CSCPDecryptMessage(CSCP_ENCRYPTION_CONTEXT *pCtx,
+                                             CSCP_ENCRYPTED_MESSAGE *pMsg,
+                                             BYTE *pDecryptionBuffer)
+{
+#ifdef _WITH_ENCRYPTION
+   int nSize;
+   EVP_CIPHER_CTX cipher;
+   DWORD dwChecksum, dwMsgSize;
+   CSCP_MESSAGE *pClearMsg;
+
+   if (m_pfCipherList[pCtx->nCipher] == NULL)
+      return FALSE;   // Unsupported cipher
+
+   pMsg->dwSize = ntohl(pMsg->dwSize);
+   EVP_DecryptInit(&cipher, m_pfCipherList[pCtx->nCipher](), pCtx->pSessionKey, pCtx->iv);
+   EVP_CIPHER_CTX_set_key_length(&cipher, pCtx->nKeyLen);
+   EVP_DecryptUpdate(&cipher, pDecryptionBuffer, &nSize, pMsg->data,
+                     pMsg->dwSize - CSCP_EH_UNENCRYPTED_BYTES - pMsg->nPadding);
+   EVP_DecryptFinal(&cipher, pDecryptionBuffer + nSize, &nSize);
+   EVP_CIPHER_CTX_cleanup(&cipher);
+
+   pClearMsg = (CSCP_MESSAGE *)(pDecryptionBuffer + CSCP_EH_ENCRYPTED_BYTES);
+   dwMsgSize = ntohl(pClearMsg->dwSize);
+   if (dwMsgSize > pMsg->dwSize)
+      return FALSE;  // Message decrypted incorrectly, because it can't be larger than encrypted
+   dwChecksum = CalculateCRC32((BYTE *)pClearMsg, dwMsgSize, 0);
+   if (dwChecksum != ntohl(((CSCP_ENCRYPTED_PAYLOAD_HEADER *)pDecryptionBuffer)->dwChecksum))
+      return FALSE;  // Bad checksum
+
+   memcpy(pMsg, pClearMsg, dwMsgSize);
+   return TRUE;
+#else    /* _WITH_ENCRYPTION */
+   return FALSE;
+#endif
+}
+
+
+//
+// Destroy encryption context
+//
+
+void LIBNETXMS_EXPORTABLE DestroyEncryptionContext(CSCP_ENCRYPTION_CONTEXT *pCtx)
+{
+   if ((pCtx != NULL) && (pCtx != PROXY_ENCRYPTION_CTX))
+   {
+      safe_free(pCtx->pSessionKey);
+      free(pCtx);
+   }
+}
+
+
+//
+// Setup encryption context
+// Function will determine is it called on initiator or responder side
+// by message code. Initiator should provide it's private key,
+// and responder should provide pointer to response message.
+//
+
+DWORD LIBNETXMS_EXPORTABLE SetupEncryptionContext(CSCPMessage *pMsg, 
+                                                  CSCP_ENCRYPTION_CONTEXT **ppCtx,
+                                                  CSCPMessage **ppResponse,
+                                                  RSA *pPrivateKey, int nNXCPVersion)
+{
+   DWORD dwResult = RCC_NOT_IMPLEMENTED;
+
+#ifdef _WITH_ENCRYPTION
+   if (pMsg->GetCode() == CMD_REQUEST_SESSION_KEY)
+   {
+      DWORD dwCiphers;
+
+      *ppResponse = new CSCPMessage(nNXCPVersion);
+      (*ppResponse)->SetCode(CMD_SESSION_KEY);
+      (*ppResponse)->SetId(pMsg->GetId());
+      (*ppResponse)->DisableEncryption();
+
+      dwCiphers = pMsg->GetVariableLong(VID_SUPPORTED_ENCRYPTION) & m_dwSupportedCiphers;
+      if (dwCiphers == 0)
+      {
+         (*ppResponse)->SetVariable(VID_RCC, RCC_NO_CIPHERS);
+         dwResult = RCC_NO_CIPHERS;
+      }
+      else
+      {
+         BYTE *pBufPos, ucKeyBuffer[KEY_BUFFER_SIZE];
+         RSA *pServerKey;
+         DWORD dwKeySize;
+
+         // Create new context
+         *ppCtx = (CSCP_ENCRYPTION_CONTEXT *)malloc(sizeof(CSCP_ENCRYPTION_CONTEXT));
+
+         // Select cipher
+         if (dwCiphers & CSCP_SUPPORT_AES_256)
+         {
+            (*ppCtx)->nCipher = CSCP_CIPHER_AES_256;
+            (*ppCtx)->nKeyLen = 32;
+         }
+         else if (dwCiphers & CSCP_SUPPORT_BLOWFISH)
+         {
+            (*ppCtx)->nCipher = CSCP_CIPHER_BLOWFISH;
+            (*ppCtx)->nKeyLen = 32;
+         }
+         else if (dwCiphers & CSCP_SUPPORT_IDEA)
+         {
+            (*ppCtx)->nCipher = CSCP_CIPHER_IDEA;
+            (*ppCtx)->nKeyLen = 16;
+         }
+         else if (dwCiphers & CSCP_SUPPORT_3DES)
+         {
+            (*ppCtx)->nCipher = CSCP_CIPHER_3DES;
+            (*ppCtx)->nKeyLen = 24;
+         }
+
+         // Generate key
+         (*ppCtx)->pSessionKey = (BYTE *)malloc((*ppCtx)->nKeyLen);
+         RAND_bytes((*ppCtx)->pSessionKey, (*ppCtx)->nKeyLen);
+         RAND_bytes((*ppCtx)->iv, EVP_MAX_IV_LENGTH);
+
+         // Encrypt key
+         dwKeySize = pMsg->GetVariableBinary(VID_PUBLIC_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
+         pBufPos = ucKeyBuffer;
+         pServerKey = d2i_RSAPublicKey(NULL, (OPENSSL_CONST BYTE **)&pBufPos, dwKeySize);
+         if (pServerKey != NULL)
+         {
+            (*ppResponse)->SetVariable(VID_RCC, RCC_SUCCESS);
+            dwKeySize = RSA_public_encrypt((*ppCtx)->nKeyLen, (*ppCtx)->pSessionKey,
+                                           ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
+            (*ppResponse)->SetVariable(VID_SESSION_KEY, ucKeyBuffer, dwKeySize);
+            dwKeySize = RSA_public_encrypt(EVP_MAX_IV_LENGTH, (*ppCtx)->iv,
+                                           ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
+            (*ppResponse)->SetVariable(VID_SESSION_IV, ucKeyBuffer, dwKeySize);
+            (*ppResponse)->SetVariable(VID_CIPHER, (WORD)(*ppCtx)->nCipher);
+            (*ppResponse)->SetVariable(VID_KEY_LENGTH, (WORD)(*ppCtx)->nKeyLen);
+            (*ppResponse)->SetVariable(VID_IV_LENGTH, (WORD)EVP_MAX_IV_LENGTH);
+            RSA_free(pServerKey);
+            dwResult = RCC_SUCCESS;
+         }
+         else
+         {
+            (*ppResponse)->SetVariable(VID_RCC, RCC_INVALID_PUBLIC_KEY);
+            dwResult = RCC_INVALID_PUBLIC_KEY;
+         }
+      }
+   }
+   else if (pMsg->GetCode() == CMD_SESSION_KEY)
+   {
+      dwResult = pMsg->GetVariableLong(VID_RCC);
+      if (dwResult == RCC_SUCCESS)
+      {
+         BYTE ucKeyBuffer[KEY_BUFFER_SIZE], ucSessionKey[KEY_BUFFER_SIZE];
+         DWORD dwKeySize;
+         int nSize, nIVLen;
+
+         // Create new context
+         *ppCtx = (CSCP_ENCRYPTION_CONTEXT *)malloc(sizeof(CSCP_ENCRYPTION_CONTEXT));
+         (*ppCtx)->nCipher = pMsg->GetVariableShort(VID_CIPHER);
+         (*ppCtx)->nKeyLen = pMsg->GetVariableShort(VID_KEY_LENGTH);
+         (*ppCtx)->pSessionKey = (BYTE *)malloc((*ppCtx)->nKeyLen);
+
+         // Decrypt session key
+         dwKeySize = pMsg->GetVariableBinary(VID_SESSION_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
+         nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey,
+                                     pPrivateKey, RSA_PKCS1_OAEP_PADDING);
+         if (nSize == (*ppCtx)->nKeyLen)
+         {
+            memcpy((*ppCtx)->pSessionKey, ucSessionKey, nSize);
+
+            // Decrypt session IV
+            nIVLen = pMsg->GetVariableShort(VID_IV_LENGTH);
+            if (nIVLen == 0)  // Versions prior to 0.2.13 don't send IV length, assume 16
+               nIVLen = 16;
+            dwKeySize = pMsg->GetVariableBinary(VID_SESSION_IV, ucKeyBuffer, KEY_BUFFER_SIZE);
+            nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey,
+                                        pPrivateKey, RSA_PKCS1_OAEP_PADDING);
+            if ((nSize == nIVLen) &&
+                (nIVLen <= EVP_CIPHER_iv_length(m_pfCipherList[(*ppCtx)->nCipher]())))
+            {
+               memcpy((*ppCtx)->iv, ucSessionKey, min(EVP_MAX_IV_LENGTH, nIVLen));
+            }
+            else
+            {
+               dwResult = RCC_INVALID_SESSION_KEY;
+            }
+         }
+         else
+         {
+            dwResult = RCC_INVALID_SESSION_KEY;
+         }
+      }
+   }
+
+   if ((dwResult != RCC_SUCCESS) && (*ppCtx != NULL))
+   {
+      DestroyEncryptionContext(*ppCtx);
+      *ppCtx = NULL;
+   }
+#else
+   if (pMsg->GetCode() == CMD_REQUEST_SESSION_KEY)
+   {
+      *ppResponse = new CSCPMessage(nNXCPVersion);
+      (*ppResponse)->SetCode(CMD_SESSION_KEY);
+      (*ppResponse)->SetId(pMsg->GetId());
+      (*ppResponse)->DisableEncryption();
+      (*ppResponse)->SetVariable(VID_RCC, dwResult);
+   }
+#endif
+
+   return dwResult;
+}
+
+
+//
+// Prepare session key request message
+//
+
+void LIBNETXMS_EXPORTABLE PrepareKeyRequestMsg(CSCPMessage *pMsg, RSA *pServerKey)
+{
+#ifdef _WITH_ENCRYPTION
+   int iLen;
+   BYTE *pKeyBuffer, *pBufPos;
+
+   pMsg->SetCode(CMD_REQUEST_SESSION_KEY);
+   pMsg->SetVariable(VID_SUPPORTED_ENCRYPTION, m_dwSupportedCiphers);
+
+   iLen = i2d_RSAPublicKey(pServerKey, NULL);
+   pKeyBuffer = (BYTE *)malloc(iLen);
+   pBufPos = pKeyBuffer;
+   i2d_RSAPublicKey(pServerKey, &pBufPos);
+   pMsg->SetVariable(VID_PUBLIC_KEY, pKeyBuffer, iLen);
+   free(pKeyBuffer);
+#endif
+}
+
+
+//
+// Load RSA key(s) from file
+//
+
+RSA LIBNETXMS_EXPORTABLE *LoadRSAKeys(TCHAR *pszKeyFile)
+{
+#ifdef _WITH_ENCRYPTION
+   FILE *fp;
+   BYTE *pKeyBuffer, *pBufPos, hash[SHA1_DIGEST_SIZE];
+   DWORD dwLen;
+   RSA *pKey = NULL;
+
+   fp = _tfopen(pszKeyFile, _T("rb"));
+   if (fp != NULL)
+   {
+      if (fread(&dwLen, 1, sizeof(DWORD), fp) == sizeof(DWORD))
+      {
+         pKeyBuffer = (BYTE *)malloc(dwLen);
+         pBufPos = pKeyBuffer;
+         if (fread(pKeyBuffer, 1, dwLen, fp) == dwLen)
+         {
+            BYTE hash2[SHA1_DIGEST_SIZE];
+
+            fread(hash, 1, SHA1_DIGEST_SIZE, fp);
+            CalculateSHA1Hash(pKeyBuffer, dwLen, hash2);
+            if (!memcmp(hash, hash2, SHA1_DIGEST_SIZE))
+            {
+               pKey = d2i_RSAPublicKey(NULL, (OPENSSL_CONST BYTE **)&pBufPos, dwLen);
+               if (pKey != NULL)
+               {
+                  if (d2i_RSAPrivateKey(&pKey, (OPENSSL_CONST BYTE **)&pBufPos,
+                                        dwLen - CAST_FROM_POINTER((pBufPos - pKeyBuffer), DWORD)) == NULL)
+                  {
+                     RSA_free(pKey);
+                     pKey = NULL;
+                  }
+               }
+            }
+         }
+         free(pKeyBuffer);
+      }
+      fclose(fp);
+   }
+
+   return pKey;
+#else
+   return NULL;
+#endif
+}
index dc255b9..eb5661b 100644 (file)
@@ -24,6 +24,7 @@
 #include "libnetxms.h"
 
 #if defined(_NETWARE)
+#undef SEVERITY_CRITICAL
 #include <netware.h>
 #elif !defined(_WIN32)
 #include <dlfcn.h>
diff --git a/src/libnetxms/message.cpp b/src/libnetxms/message.cpp
new file mode 100644 (file)
index 0000000..ba759b5
--- /dev/null
@@ -0,0 +1,593 @@
+/* 
+** NetXMS - Network Management System
+** NetXMS Foundation Library
+** Copyright (C) 2003, 2004, 2005, 2006 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: message.cpp
+**
+**/
+
+#include "libnetxms.h"
+
+
+//
+// Calculate variable size
+//
+
+static int VariableSize(CSCP_DF *pVar, BOOL bNetworkByteOrder)
+{
+   int nSize;
+
+   switch(pVar->bType)
+   {
+      case CSCP_DT_INTEGER:
+         nSize = 12;
+         break;
+      case CSCP_DT_INT64:
+      case CSCP_DT_FLOAT:
+         nSize = 16;
+         break;
+      case CSCP_DT_INT16:
+         nSize = 8;
+         break;
+      case CSCP_DT_STRING:
+      case CSCP_DT_BINARY:
+         if (bNetworkByteOrder)
+            nSize = ntohl(pVar->df_string.dwLen) + 12;
+         else
+            nSize = pVar->df_string.dwLen + 12;
+         break;
+      default:
+         nSize = 8;
+         break;
+   }
+   return nSize;
+}
+
+
+//
+// Default constructor for CSCPMessage class
+//
+
+CSCPMessage::CSCPMessage(int nVersion)
+{
+   m_wCode = 0;
+   m_dwId = 0;
+   m_dwNumVar = 0;
+   m_ppVarList = NULL;
+   m_wFlags = 0;
+   m_nVersion = nVersion;
+}
+
+
+//
+// Create a copy of prepared CSCP message
+//
+
+CSCPMessage::CSCPMessage(CSCPMessage *pMsg)
+{
+   DWORD i;
+
+   m_wCode = pMsg->m_wCode;
+   m_dwId = pMsg->m_dwId;
+   m_wFlags = pMsg->m_wFlags;
+   m_nVersion = pMsg->m_nVersion;
+   m_dwNumVar = pMsg->m_dwNumVar;
+   m_ppVarList = (CSCP_DF **)malloc(sizeof(CSCP_DF *) * m_dwNumVar);
+   for(i = 0; i < m_dwNumVar; i++)
+   {
+      m_ppVarList[i] = (CSCP_DF *)nx_memdup(pMsg->m_ppVarList[i],
+                                            VariableSize(pMsg->m_ppVarList[i], FALSE));
+   }
+}
+
+
+//
+// Create CSCPMessage object from received message
+//
+
+CSCPMessage::CSCPMessage(CSCP_MESSAGE *pMsg, int nVersion)
+{
+   DWORD i, dwPos, dwSize, dwVar;
+   CSCP_DF *pVar;
+   int iVarSize;
+
+   m_wFlags = ntohs(pMsg->wFlags);
+   m_wCode = ntohs(pMsg->wCode);
+   m_dwId = ntohl(pMsg->dwId);
+   dwSize = ntohl(pMsg->dwSize);
+   m_dwNumVar = ntohl(pMsg->dwNumVars);
+   m_ppVarList = (CSCP_DF **)malloc(sizeof(CSCP_DF *) * m_dwNumVar);
+   m_nVersion = nVersion;
+   
+   // Parse data fields
+   for(dwPos = CSCP_HEADER_SIZE, dwVar = 0; dwVar < m_dwNumVar; dwVar++)
+   {
+      pVar = (CSCP_DF *)(((BYTE *)pMsg) + dwPos);
+
+      // Calculate variable size
+      iVarSize = VariableSize(pVar, TRUE);
+
+      // Create new entry
+      m_ppVarList[dwVar] = (CSCP_DF *)malloc(iVarSize);
+      memcpy(m_ppVarList[dwVar], pVar, iVarSize);
+
+      // Convert numeric values to host format
+      m_ppVarList[dwVar]->dwVarId = ntohl(m_ppVarList[dwVar]->dwVarId);
+      switch(pVar->bType)
+      {
+         case CSCP_DT_INTEGER:
+            m_ppVarList[dwVar]->df_int32 = ntohl(m_ppVarList[dwVar]->df_int32);
+            break;
+         case CSCP_DT_INT64:
+            m_ppVarList[dwVar]->df_int64 = ntohq(m_ppVarList[dwVar]->df_int64);
+            break;
+         case CSCP_DT_INT16:
+            m_ppVarList[dwVar]->df_int16 = ntohs(m_ppVarList[dwVar]->df_int16);
+            break;
+         case CSCP_DT_FLOAT:
+            m_ppVarList[dwVar]->df_real = ntohd(m_ppVarList[dwVar]->df_real);
+            break;
+         case CSCP_DT_STRING:
+#if !(WORDS_BIGENDIAN)
+            m_ppVarList[dwVar]->df_string.dwLen = ntohl(m_ppVarList[dwVar]->df_string.dwLen);
+            for(i = 0; i < m_ppVarList[dwVar]->df_string.dwLen / 2; i++)
+               m_ppVarList[dwVar]->df_string.szValue[i] = ntohs(m_ppVarList[dwVar]->df_string.szValue[i]);
+#endif
+            break;
+         case CSCP_DT_BINARY:
+            m_ppVarList[dwVar]->df_string.dwLen = ntohl(m_ppVarList[dwVar]->df_string.dwLen);
+            break;
+      }
+
+      // Starting from version 2, all variables should be 8-byte aligned
+      if (m_nVersion >= 2)
+         dwPos += iVarSize + ((8 - (iVarSize % 8)) & 7);
+      else
+         dwPos += iVarSize;
+   }
+}
+
+
+//
+// Destructor for CSCPMessage
+//
+
+CSCPMessage::~CSCPMessage()
+{
+   DeleteAllVariables();
+}
+
+
+//
+// Find variable by name
+//
+
+DWORD CSCPMessage::FindVariable(DWORD dwVarId)
+{
+   DWORD i;
+
+   for(i = 0; i < m_dwNumVar; i++)
+      if (m_ppVarList[i]->dwVarId == dwVarId)
+         return i;
+   return INVALID_INDEX;
+}
+
+
+//
+// Set variable
+// Argument dwSize (data size) is used only for DT_BINARY type
+//
+
+void *CSCPMessage::Set(DWORD dwVarId, BYTE bType, void *pValue, DWORD dwSize)
+{
+   DWORD dwIndex, dwLength;
+   CSCP_DF *pVar;
+#ifndef UNICODE
+   WCHAR *pBuffer;
+#endif
+
+   // Create CSCP_DF structure
+   switch(bType)
+   {
+      case CSCP_DT_INTEGER:
+         pVar = (CSCP_DF *)malloc(12);
+         pVar->df_int32 = *((DWORD *)pValue);
+         break;
+      case CSCP_DT_INT16:
+         pVar = (CSCP_DF *)malloc(8);
+         pVar->df_int16 = *((WORD *)pValue);
+         break;
+      case CSCP_DT_INT64:
+         pVar = (CSCP_DF *)malloc(16);
+         pVar->df_int64 = *((QWORD *)pValue);
+         break;
+      case CSCP_DT_FLOAT:
+         pVar = (CSCP_DF *)malloc(16);
+         pVar->df_real = *((double *)pValue);
+         break;
+      case CSCP_DT_STRING:
+         dwLength = (DWORD)_tcslen((TCHAR *)pValue);
+         pVar = (CSCP_DF *)malloc(12 + dwLength * 2);
+         pVar->df_string.dwLen = dwLength * 2;
+#ifdef UNICODE
+         memcpy(pVar->df_string.szValue, pValue, pVar->df_string.dwLen);
+#else
+         pBuffer = (WCHAR *)malloc(dwLength * 2 + 2);
+         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char *)pValue, dwLength, pBuffer, dwLength + 1);
+         memcpy(pVar->df_string.szValue, pBuffer, pVar->df_string.dwLen);
+         free(pBuffer);
+#endif
+         break;
+      case CSCP_DT_BINARY:
+         pVar = (CSCP_DF *)malloc(12 + dwSize);
+         pVar->df_string.dwLen = dwSize;
+         if ((pVar->df_string.dwLen > 0) && (pValue != NULL))
+            memcpy(pVar->df_string.szValue, pValue, pVar->df_string.dwLen);
+         break;
+      default:
+         return NULL;  // Invalid data type, unable to handle
+   }
+   pVar->dwVarId = dwVarId;
+   pVar->bType = bType;
+
+   // Check if variable exists
+   dwIndex = FindVariable(pVar->dwVarId);
+   if (dwIndex == INVALID_INDEX) // Add new variable to list
+   {
+      m_ppVarList = (CSCP_DF **)realloc(m_ppVarList, sizeof(CSCP_DF *) * (m_dwNumVar + 1));
+      m_ppVarList[m_dwNumVar] = pVar;
+      m_dwNumVar++;
+   }
+   else  // Replace existing variable
+   {
+      free(m_ppVarList[dwIndex]);
+      m_ppVarList[dwIndex] = pVar;
+   }
+
+   return (bType == CSCP_DT_INT16) ? ((void *)((BYTE *)pVar + 6)) : ((void *)((BYTE *)pVar + 8));
+}
+
+
+//
+// Get variable value
+//
+
+void *CSCPMessage::Get(DWORD dwVarId, BYTE bType)
+{
+   DWORD dwIndex;
+
+   // Find variable
+   dwIndex = FindVariable(dwVarId);
+   if (dwIndex == INVALID_INDEX)
+      return NULL;      // No such variable
+
+   // Check data type
+   if (m_ppVarList[dwIndex]->bType != bType)
+      return NULL;
+
+   return (bType == CSCP_DT_INT16) ?
+             ((void *)((BYTE *)m_ppVarList[dwIndex] + 6)) : 
+             ((void *)((BYTE *)m_ppVarList[dwIndex] + 8));
+}
+
+
+//
+// Get integer variable
+//
+
+DWORD CSCPMessage::GetVariableLong(DWORD dwVarId)
+{
+   char *pValue;
+
+   pValue = (char *)Get(dwVarId, CSCP_DT_INTEGER);
+   return pValue ? *((DWORD *)pValue) : 0;
+}
+
+
+//
+// Get 16-bit integer variable
+//
+
+WORD CSCPMessage::GetVariableShort(DWORD dwVarId)
+{
+   void *pValue;
+
+   pValue = Get(dwVarId, CSCP_DT_INT16);
+   return pValue ? *((WORD *)pValue) : 0;
+}
+
+
+//
+// Get 16-bit integer variable as signel 32-bit integer
+//
+
+LONG CSCPMessage::GetVariableShortAsInt32(DWORD dwVarId)
+{
+   void *pValue;
+
+   pValue = Get(dwVarId, CSCP_DT_INT16);
+   return pValue ? *((short *)pValue) : 0;
+}
+
+
+//
+// Get 64-bit integer variable
+//
+
+QWORD CSCPMessage::GetVariableInt64(DWORD dwVarId)
+{
+   char *pValue;
+
+   pValue = (char *)Get(dwVarId, CSCP_DT_INT64);
+   return pValue ? *((QWORD *)pValue) : 0;
+}
+
+
+//
+// Get 64-bit floating point variable
+//
+
+double CSCPMessage::GetVariableDouble(DWORD dwVarId)
+{
+   char *pValue;
+
+   pValue = (char *)Get(dwVarId, CSCP_DT_FLOAT);
+   return pValue ? *((double *)pValue) : 0;
+}
+
+
+//
+// Get string variable
+// If szBuffer is NULL, memory block of required size will be allocated
+// for result; if szBuffer is not NULL, entire result or part of it will
+// be placed to szBuffer and pointer to szBuffer will be returned.
+// Note: dwBufSize is buffer size in characters, not bytes!
+//
+
+TCHAR *CSCPMessage::GetVariableStr(DWORD dwVarId, TCHAR *pszBuffer, DWORD dwBufSize)
+{
+   void *pValue;
+   TCHAR *pStr = NULL;
+   DWORD dwLen;
+
+   if ((pszBuffer != NULL) && (dwBufSize == 0))
+      return NULL;   // non-sense combination
+
+   pValue = Get(dwVarId, CSCP_DT_STRING);
+   if (pValue != NULL)
+   {
+      if (pszBuffer == NULL)
+      {
+#ifdef UNICODE
+         pStr = (TCHAR *)malloc(*((DWORD *)pValue) + 2);
+#else
+         pStr = (TCHAR *)malloc(*((DWORD *)pValue) / 2 + 1);
+#endif
+      }
+      else
+      {
+         pStr = pszBuffer;
+      }
+
+      dwLen = (pszBuffer == NULL) ? (*((DWORD *)pValue) / 2) : min(*((DWORD *)pValue) / 2, dwBufSize - 1);
+#ifdef UNICODE
+      memcpy(pStr, (BYTE *)pValue + 4, dwLen * 2);
+#else
+      WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, 
+                          (WCHAR *)((BYTE *)pValue + 4), dwLen, pStr, dwLen + 1, NULL, NULL);
+#endif
+      pStr[dwLen] = 0;
+   }
+   else
+   {
+      if (pszBuffer != NULL)
+      {
+         pStr = pszBuffer;
+         pStr[0] = 0;
+      }
+   }
+   return pStr;
+}
+
+
+//
+// Get binary (byte array) variable
+// Result will be placed to the buffer provided (no more than dwBufSize bytes,
+// and actual size of data will be returned
+// If pBuffer is NULL, just actual data length is returned
+//
+
+DWORD CSCPMessage::GetVariableBinary(DWORD dwVarId, BYTE *pBuffer, DWORD dwBufSize)
+{
+   void *pValue;
+   DWORD dwSize;
+
+   pValue = Get(dwVarId, CSCP_DT_BINARY);
+   if (pValue != NULL)
+   {
+      dwSize = *((DWORD *)pValue);
+      if (pBuffer != NULL)
+         memcpy(pBuffer, (BYTE *)pValue + 4, min(dwBufSize, dwSize));
+   }
+   else
+   {
+      dwSize = 0;
+   }
+   return dwSize;
+}
+
+
+//
+// Build protocol message ready to be send over the wire
+//
+
+CSCP_MESSAGE *CSCPMessage::CreateMessage(void)
+{
+   DWORD dwSize;
+   int iVarSize;
+   DWORD i, j;
+   CSCP_MESSAGE *pMsg;
+   CSCP_DF *pVar;
+
+   // Calculate message size
+   for(i = 0, dwSize = CSCP_HEADER_SIZE; i < m_dwNumVar; i++)
+   {
+      iVarSize = VariableSize(m_ppVarList[i], FALSE);
+      if (m_nVersion >= 2)
+         dwSize += iVarSize + ((8 - (iVarSize % 8)) & 7);
+      else
+         dwSize += iVarSize;
+   }
+
+   // Message should be aligned to 8 bytes boundary
+   // This is always the case starting from version 2 because
+   // all variables padded to be _kratnimi_ 8 bytes
+   if (m_nVersion < 2)
+      dwSize += (8 - (dwSize % 8)) & 7;
+
+   // Create message
+   pMsg = (CSCP_MESSAGE *)malloc(dwSize);
+   pMsg->wCode = htons(m_wCode);
+   pMsg->wFlags = htons(m_wFlags);
+   pMsg->dwSize = htonl(dwSize);
+   pMsg->dwId = htonl(m_dwId);
+   pMsg->dwNumVars = htonl(m_dwNumVar);
+
+   // Fill data fields
+   for(i = 0, pVar = (CSCP_DF *)((char *)pMsg + CSCP_HEADER_SIZE); i < m_dwNumVar; i++)
+   {
+      iVarSize = VariableSize(m_ppVarList[i], FALSE);
+      memcpy(pVar, m_ppVarList[i], iVarSize);
+
+      // Convert numeric values to network format
+      pVar->dwVarId = htonl(pVar->dwVarId);
+      switch(pVar->bType)
+      {
+         case CSCP_DT_INTEGER:
+            pVar->df_int32 = htonl(pVar->df_int32);
+            break;
+         case CSCP_DT_INT64:
+            pVar->df_int64 = htonq(pVar->df_int64);
+            break;
+         case CSCP_DT_INT16:
+            pVar->df_int16 = htons(pVar->df_int16);
+            break;
+         case CSCP_DT_FLOAT:
+            pVar->df_real = htond(pVar->df_real);
+            break;
+         case CSCP_DT_STRING:
+#if !(WORDS_BIGENDIAN)
+            for(j = 0; j < pVar->df_string.dwLen / 2; j++)
+               pVar->df_string.szValue[j] = htons(pVar->df_string.szValue[j]);
+            pVar->df_string.dwLen = htonl(pVar->df_string.dwLen);
+#endif
+            break;
+         case CSCP_DT_BINARY:
+            pVar->df_string.dwLen = htonl(pVar->df_string.dwLen);
+            break;
+      }
+
+      if (m_nVersion >= 2)
+         pVar = (CSCP_DF *)((char *)pVar + iVarSize + ((8 - (iVarSize % 8)) & 7));
+      else
+         pVar = (CSCP_DF *)((char *)pVar + iVarSize);
+   }
+
+   return pMsg;
+}
+
+
+//
+// Delete all variables
+//
+
+void CSCPMessage::DeleteAllVariables(void)
+{
+   if (m_ppVarList != NULL)
+   {
+      DWORD i;
+
+      for(i = 0; i < m_dwNumVar; i++)
+         free(m_ppVarList[i]);
+      free(m_ppVarList);
+
+      m_ppVarList = NULL;
+      m_dwNumVar = 0;
+   }
+}
+
+
+//
+// Set binary variable to an array of DWORDs
+//
+
+void CSCPMessage::SetVariableToInt32Array(DWORD dwVarId, DWORD dwNumElements, DWORD *pdwData)
+{
+   DWORD i, *pdwBuffer;
+
+   pdwBuffer = (DWORD *)Set(dwVarId, CSCP_DT_BINARY, pdwData, dwNumElements * sizeof(DWORD));
+   if (pdwBuffer != NULL)
+   {
+      pdwBuffer++;   // First DWORD is a length field
+      for(i = 0; i < dwNumElements; i++)  // Convert DWORDs to network byte order
+         pdwBuffer[i] = htonl(pdwBuffer[i]);
+   }
+}
+
+
+//
+// Get binary variable as an array of DWORDs
+//
+
+DWORD CSCPMessage::GetVariableInt32Array(DWORD dwVarId, DWORD dwNumElements, DWORD *pdwBuffer)
+{
+   DWORD i, dwSize;
+
+   dwSize = GetVariableBinary(dwVarId, (BYTE *)pdwBuffer, dwNumElements * sizeof(DWORD));
+   dwSize /= sizeof(DWORD);   // Convert bytes to elements
+   for(i = 0; i < dwSize; i++)
+      pdwBuffer[i] = ntohl(pdwBuffer[i]);
+   return dwSize;
+}
+
+
+//
+// Set binary variable from file
+//
+
+BOOL CSCPMessage::SetVariableFromFile(DWORD dwVarId, TCHAR *pszFileName)
+{
+   FILE *pFile;
+   BYTE *pBuffer;
+   DWORD dwSize;
+   BOOL bResult = FALSE;
+
+   dwSize = (DWORD)FileSize(pszFileName);
+   pFile = _tfopen(pszFileName, _T("rb"));
+   if (pFile != NULL)
+   {
+      pBuffer = (BYTE *)Set(dwVarId, CSCP_DT_BINARY, NULL, dwSize);
+      if (pBuffer != NULL)
+      {
+         if (fread(pBuffer + sizeof(DWORD), 1, dwSize, pFile) == dwSize)
+            bResult = TRUE;
+      }
+      fclose(pFile);
+   }
+   return bResult;
+}
diff --git a/src/libnetxms/msgwq.cpp b/src/libnetxms/msgwq.cpp
new file mode 100644 (file)
index 0000000..9d3f8c0
--- /dev/null
@@ -0,0 +1,231 @@
+/* 
+** NetXMS - Network Management System
+** NetXMS Foundation Library
+** Copyright (C) 2004 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: msgwq.cpp
+**
+**/
+
+#include "libnetxms.h"
+
+
+//
+// Constants
+//
+
+#define TTL_CHECK_INTERVAL    200
+
+
+//
+// Constructor
+//
+
+MsgWaitQueue::MsgWaitQueue()
+{
+   m_dwMsgHoldTime = 30000;      // Default message TTL is 30 seconds
+   m_dwNumElements = 0;
+   m_pElements = NULL;
+   m_mutexDataAccess = MutexCreate();
+   m_condStop = ConditionCreate(FALSE);
+   m_condNewMsg = ConditionCreate(TRUE);
+   m_hHkThread = ThreadCreateEx(MWQThreadStarter, 0, this);
+}
+
+
+//
+// Destructor
+//
+
+MsgWaitQueue::~MsgWaitQueue()
+{
+   ConditionSet(m_condStop);
+
+   // Wait for housekeeper thread to terminate
+   ThreadJoin(m_hHkThread);
+
+   // Housekeeper thread stopped, proceed with object destruction
+   Clear();
+   safe_free(m_pElements);
+   MutexDestroy(m_mutexDataAccess);
+   ConditionDestroy(m_condStop);
+   ConditionDestroy(m_condNewMsg);
+}
+
+
+//
+// Clear queue
+//
+
+void MsgWaitQueue::Clear(void)
+{
+   DWORD i;
+
+   Lock();
+
+   for(i = 0; i < m_dwNumElements; i++)
+      if (m_pElements[i].wIsBinary)
+      {
+         safe_free(m_pElements[i].pMsg);
+      }
+      else
+      {
+         delete (CSCPMessage *)(m_pElements[i].pMsg);
+      }
+   m_dwNumElements = 0;
+   Unlock();
+}
+
+
+//
+// Put message into queue
+//
+
+void MsgWaitQueue::Put(CSCPMessage *pMsg)
+{
+   Lock();
+
+       // FIXME possible memory leak/fault
+   m_pElements = (WAIT_QUEUE_ELEMENT *)realloc(m_pElements,
+                       sizeof(WAIT_QUEUE_ELEMENT) * (m_dwNumElements + 1));
+       
+   m_pElements[m_dwNumElements].wCode = pMsg->GetCode();
+   m_pElements[m_dwNumElements].wIsBinary = 0;
+   m_pElements[m_dwNumElements].dwId = pMsg->GetId();
+   m_pElements[m_dwNumElements].dwTTL = m_dwMsgHoldTime;
+   m_pElements[m_dwNumElements].pMsg = pMsg;
+   m_dwNumElements++;
+
+   Unlock();
+
+   ConditionPulse(m_condNewMsg);
+}
+
+
+//
+// Put raw message into queue
+//
+
+void MsgWaitQueue::Put(CSCP_MESSAGE *pMsg)
+{
+   Lock();
+
+   m_pElements = (WAIT_QUEUE_ELEMENT *)realloc(m_pElements, 
+                              sizeof(WAIT_QUEUE_ELEMENT) * (m_dwNumElements + 1));
+   m_pElements[m_dwNumElements].wCode = pMsg->wCode;
+   m_pElements[m_dwNumElements].wIsBinary = 1;
+   m_pElements[m_dwNumElements].dwId = pMsg->dwId;
+   m_pElements[m_dwNumElements].dwTTL = m_dwMsgHoldTime;
+   m_pElements[m_dwNumElements].pMsg = pMsg;
+   m_dwNumElements++;
+   Unlock();
+
+   ConditionPulse(m_condNewMsg);
+}
+
+
+//
+// Wait for message with specific code and ID
+// Function return pointer to the message on success or
+// NULL on timeout or error
+//
+
+void *MsgWaitQueue::WaitForMessageInternal(WORD wIsBinary, WORD wCode, DWORD dwId, DWORD dwTimeOut)
+{
+   DWORD i, dwSleepTime;
+   QWORD qwStartTime;
+
+   do
+   {
+      Lock();
+      for(i = 0; i < m_dwNumElements; i++)
+               {
+         if ((m_pElements[i].dwId == dwId) &&
+             (m_pElements[i].wCode == wCode) &&
+             (m_pElements[i].wIsBinary == wIsBinary))
+         {
+            void *pMsg;
+
+            pMsg = m_pElements[i].pMsg;
+            m_dwNumElements--;
+            memmove(&m_pElements[i], &m_pElements[i + 1],
+                                               sizeof(WAIT_QUEUE_ELEMENT) * (m_dwNumElements - i));
+            Unlock();
+            return pMsg;
+         }
+               }
+      Unlock();
+
+      qwStartTime = GetCurrentTimeMs();
+      ConditionWait(m_condNewMsg, min(dwTimeOut, 100));
+      dwSleepTime = (DWORD)(GetCurrentTimeMs() - qwStartTime);
+      dwTimeOut -= min(dwSleepTime, dwTimeOut);
+   } while(dwTimeOut > 0);
+
+   return NULL;
+}
+
+
+//
+// Housekeeping thread
+//
+
+void MsgWaitQueue::HousekeeperThread(void)
+{
+   DWORD i;
+
+   while(1)
+   {
+      if (ConditionWait(m_condStop, TTL_CHECK_INTERVAL))
+         break;
+
+      Lock();
+      for(i = 0; i < m_dwNumElements; i++)
+               {
+         if (m_pElements[i].dwTTL <= TTL_CHECK_INTERVAL)
+         {
+            if (m_pElements[i].wIsBinary)
+            {
+               safe_free(m_pElements[i].pMsg);
+            }
+            else
+            {
+               delete (CSCPMessage *)(m_pElements[i].pMsg);
+            }
+            m_dwNumElements--;
+            memmove(&m_pElements[i], &m_pElements[i + 1], sizeof(WAIT_QUEUE_ELEMENT) * (m_dwNumElements - i));
+            i--;
+         }
+         else
+         {
+            m_pElements[i].dwTTL -= TTL_CHECK_INTERVAL;
+         }
+               }
+      Unlock();
+   }
+}
+
+
+//
+// Housekeeper thread starter
+//
+
+THREAD_RESULT THREAD_CALL MsgWaitQueue::MWQThreadStarter(void *pArg)
+{
+   ((MsgWaitQueue *)pArg)->HousekeeperThread();
+   return THREAD_OK;
+}
diff --git a/src/libnetxms/nxcp.cpp b/src/libnetxms/nxcp.cpp
new file mode 100644 (file)
index 0000000..0a30875
--- /dev/null
@@ -0,0 +1,545 @@
+/* $Id: nxcp.cpp,v 1.1 2006-10-20 10:15:56 victor Exp $ */
+/* 
+** NetXMS - Network Management System
+** NetXMS Foundation Library
+** Copyright (C) 2003, 2004, 2005, 2006 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: nxcp.cpp
+**
+**/
+
+#include "libnetxms.h"
+
+
+//
+// Constants
+//
+
+#define FILE_BUFFER_SIZE      32768
+
+
+//
+// Get symbolic name for message code
+//
+
+TCHAR LIBNETXMS_EXPORTABLE *NXCPMessageCodeName(WORD wCode, TCHAR *pszBuffer)
+{
+   static TCHAR *pszMsgNames[] =
+   {
+      _T("CMD_LOGIN"),
+      _T("CMD_LOGIN_RESP"),
+      _T("CMD_KEEPALIVE"),
+      _T("CMD_EVENT"),
+      _T("CMD_GET_OBJECTS"),
+      _T("CMD_OBJECT"),
+      _T("CMD_DELETE_OBJECT"),
+      _T("CMD_MODIFY_OBJECT"),
+      _T("CMD_OBJECT_LIST_END"),
+      _T("CMD_OBJECT_UPDATE"),
+      _T("CMD_GET_EVENTS"),
+      _T("CMD_EVENT_LIST_END"),
+      _T("CMD_GET_CONFIG_VARLIST"),
+      _T("CMD_SET_CONFIG_VARIABLE"),
+      _T("CMD_GET_OBJECT_TOOLS"),
+      _T("CMD_EXECUTE_ACTION"),
+      _T("CMD_DELETE_CONFIG_VARIABLE"),
+      _T("CMD_NOTIFY"),
+      _T("CMD_TRAP"),
+      _T("CMD_OPEN_EPP"),
+      _T("CMD_CLOSE_EPP"),
+      _T("CMD_SAVE_EPP"),
+      _T("CMD_EPP_RECORD"),
+      _T("CMD_LOCK_EVENT_DB"),
+      _T("CMD_UNLOCK_EVENT_DB"),
+      _T("CMD_SET_EVENT_INFO"),
+      _T("CMD_EVENT_DB_RECORD"),
+      _T("CMD_LOAD_EVENT_DB"),
+      _T("CMD_REQUEST_COMPLETED"),
+      _T("CMD_LOAD_USER_DB"),
+      _T("CMD_USER_DATA"),
+      _T("CMD_GROUP_DATA"),
+      _T("CMD_USER_DB_EOF"),
+      _T("CMD_UPDATE_USER"),
+      _T("CMD_DELETE_USER"),
+      _T("CMD_CREATE_USER"),
+      _T("CMD_LOCK_USER_DB"),
+      _T("CMD_UNLOCK_USER_DB"),
+      _T("CMD_USER_DB_UPDATE"),
+      _T("CMD_SET_PASSWORD"),
+      _T("CMD_GET_NODE_DCI_LIST"),
+      _T("CMD_NODE_DCI"),
+      _T("CMD_NODE_DCI_LIST_END"),
+      _T("CMD_DELETE_NODE_DCI"),
+      _T("CMD_MODIFY_NODE_DCI"),
+      _T("CMD_UNLOCK_NODE_DCI_LIST"),
+      _T("CMD_SET_OBJECT_MGMT_STATUS"),
+      _T("CMD_CREATE_NEW_DCI"),
+      _T("CMD_GET_DCI_DATA"),
+      _T("CMD_DCI_DATA"),
+      _T("CMD_GET_MIB_TIMESTAMP"),
+      _T("CMD_GET_MIB"),
+      _T("CMD_REQUEST_NEW_LPP_ID"),
+      _T("CMD_OPEN_LPP"),
+      _T("CMD_CREATE_OBJECT"),
+      _T("CMD_GET_EVENT_NAMES"),
+      _T("CMD_EVENT_NAME_LIST"),
+      _T("CMD_BIND_OBJECT"),
+      _T("CMD_UNBIND_OBJECT"),
+      _T("CMD_GET_IMAGE_LIST"),
+      _T("CMD_LOAD_IMAGE_FILE"),
+      _T("CMD_IMAGE_LIST"),
+      _T("CMD_IMAGE_FILE"),
+      _T("CMD_AUTHENTICATE"),
+      _T("CMD_GET_PARAMETER"),
+      _T("CMD_GET_LIST"),
+      _T("CMD_ACTION"),
+      _T("CMD_GET_DEFAULT_IMAGE_LIST"),
+      _T("CMD_DEFAULT_IMAGE_LIST"),
+      _T("CMD_GET_ALL_ALARMS"),
+      _T("CMD_GET_ALARM"),
+      _T("CMD_ACK_ALARM"),
+      _T("CMD_ALARM_UPDATE"),
+      _T("CMD_ALARM_DATA"),
+      _T("CMD_DELETE_ALARM"),
+      _T("CMD_LOCK_ACTION_DB"),
+      _T("CMD_UNLOCK_ACTION_DB"),
+      _T("CMD_LOAD_ACTIONS"),
+      _T("CMD_ACTION_DB_UPDATE"),
+      _T("CMD_MODIFY_ACTION"),
+      _T("CMD_CREATE_ACTION"),
+      _T("CMD_DELETE_ACTION"),
+      _T("CMD_ACTION_DATA"),
+      _T("CMD_GET_CONTAINER_CAT_LIST"),
+      _T("CMD_CONTAINER_CAT_DATA"),
+      _T("CMD_DELETE_CONTAINER_CAT"),
+      _T("CMD_CREATE_CONTAINER_CAT"),
+      _T("CMD_MODIFY_CONTAINER_CAT"),
+      _T("CMD_POLL_NODE"),
+      _T("CMD_POLLING_INFO"),
+      _T("CMD_COPY_DCI"),
+      _T("CMD_WAKEUP_NODE"),
+      _T("CMD_DELETE_EVENT_TEMPLATE"),
+      _T("CMD_GENERATE_EVENT_CODE"),
+      _T("CMD_LOCK_TRAP_CFG"),
+      _T("CMD_UNLOCK_TRAP_CFG"),
+      _T("CMD_CREATE_TRAP"),
+      _T("CMD_MODIFY_TRAP"),
+      _T("CMD_DELETE_TRAP"),
+      _T("CMD_LOAD_TRAP_CFG"),
+      _T("CMD_TRAP_CFG_RECORD"),
+      _T("CMD_QUERY_PARAMETER"),
+      _T("CMD_GET_SERVER_INFO"),
+      _T("CMD_SET_DCI_STATUS"),
+      _T("CMD_FILE_DATA"),
+      _T("CMD_TRANSFER_FILE"),
+      _T("CMD_UPGRADE_AGENT"),
+      _T("CMD_GET_PACKAGE_LIST"),
+      _T("CMD_PACKAGE_INFO"),
+      _T("CMD_REMOVE_PACKAGE"),
+      _T("CMD_INSTALL_PACKAGE"),
+      _T("CMD_LOCK_PACKAGE_DB"),
+      _T("CMD_UNLOCK_PACKAGE_DB"),
+      _T("CMD_ABORT_FILE_TRANSFER"),
+      _T("CMD_CHECK_NETWORK_SERVICE"),
+      _T("CMD_GET_AGENT_CONFIG"),
+      _T("CMD_UPDATE_AGENT_CONFIG"),
+      _T("CMD_GET_PARAMETER_LIST"),
+      _T("CMD_DEPLOY_PACKAGE"),
+      _T("CMD_INSTALLER_INFO"),
+      _T("CMD_GET_LAST_VALUES"),
+      _T("CMD_APPLY_TEMPLATE"),
+      _T("CMD_SET_USER_VARIABLE"),
+      _T("CMD_GET_USER_VARIABLE"),
+      _T("CMD_ENUM_USER_VARIABLES"),
+      _T("CMD_DELETE_USER_VARIABLE"),
+      _T("CMD_ADM_MESSAGE"),
+      _T("CMD_ADM_REQUEST"),
+      _T("CMD_CHANGE_IP_ADDR"),
+      _T("CMD_REQUEST_SESSION_KEY"),
+      _T("CMD_ENCRYPTED_MESSAGE"),
+      _T("CMD_SESSION_KEY"),
+      _T("CMD_REQUEST_ENCRYPTION"),
+      _T("CMD_GET_ROUTING_TABLE"),
+      _T("CMD_EXEC_TABLE_TOOL"),
+      _T("CMD_TABLE_DATA"),
+      _T("CMD_APPLY_LOG_POLICY"),
+      _T("CMD_CHANGE_SUBSCRIPTION"),
+      _T("CMD_GET_SYSLOG"),
+      _T("CMD_SYSLOG_RECORDS"),
+      _T("CMD_GET_LPP_LIST"),
+      _T("CMD_OPEN_LOG_POLICY"),
+      _T("CMD_CLOSE_LOG_POLICY"),
+      _T("CMD_GET_OBJECT_TOOL_DETAILS"),
+      _T("CMD_LOCK_OBJECT_TOOLS"),
+      _T("CMD_UNLOCK_OBJECT_TOOLS"),
+      _T("CMD_UPDATE_OBJECT_TOOL"),
+      _T("CMD_DELETE_OBJECT_TOOL"),
+      _T("CMD_SETUP_PROXY_CONNECTION"),
+      _T("CMD_GENERATE_OBJECT_TOOL_ID"),
+      _T("CMD_GET_SERVER_STATS"),
+      _T("CMD_GET_SCRIPT_LIST"),
+      _T("CMD_GET_SCRIPT"),
+      _T("CMD_UPDATE_SCRIPT"),
+      _T("CMD_DELETE_SCRIPT"),
+      _T("CMD_RENAME_SCRIPT"),
+      _T("CMD_GET_SESSION_LIST"),
+      _T("CMD_KILL_SESSION"),
+      _T("CMD_GET_TRAP_LOG"),
+      _T("CMD_TRAP_LOG_RECORDS"),
+      _T("CMD_START_SNMP_WALK"),
+      _T("CMD_SNMP_WALK_DATA"),
+      _T("CMD_GET_MAP_LIST"),
+      _T("CMD_LOAD_MAP"),
+      _T("CMD_SAVE_MAP"),
+      _T("CMD_DELETE_MAP"),
+      _T("CMD_RESOLVE_MAP_NAME"),
+      _T("CMD_SUBMAP_DATA"),
+      _T("CMD_UPLOAD_SUBMAP_BK_IMAGE"),
+      _T("CMD_GET_SUBMAP_BK_IMAGE"),
+      _T("CMD_GET_MODULE_LIST"),
+      _T("CMD_UPDATE_MODULE_INFO"),
+      _T("CMD_COPY_USER_VARIABLE"),
+      _T("CMD_RESOLVE_DCI_NAMES"),
+      _T("CMD_GET_MY_CONFIG"),
+      _T("CMD_GET_AGENT_CFG_LIST"),
+      _T("CMD_OPEN_AGENT_CONFIG"),
+      _T("CMD_SAVE_AGENT_CONFIG"),
+      _T("CMD_DELETE_AGENT_CONFIG"),
+      _T("CMD_SWAP_AGENT_CONFIGS"),
+      _T("CMD_TERMINATE_ALARM"),
+      _T("CMD_GET_NXCP_CAPS"),
+      _T("CMD_NXCP_CAPS"),
+      _T("CMD_GET_OBJECT_COMMENTS"),
+      _T("CMD_UPDATE_OBJECT_COMMENTS"),
+      _T("CMD_ENABLE_AGENT_TRAPS")
+   };
+
+   if ((wCode >= CMD_LOGIN) && (wCode <= CMD_ENABLE_AGENT_TRAPS))
+      _tcscpy(pszBuffer, pszMsgNames[wCode - CMD_LOGIN]);
+   else
+      _stprintf(pszBuffer, _T("CMD_UNKNOWN(%d)"), wCode);
+   return pszBuffer;
+}
+
+
+//
+// Receive raw CSCP message from network
+// If pMsg is NULL, temporary buffer will be re-initialized
+// Returns message size on success or:
+//   0 if connection is closed
+//  <0 on socket errors
+//   1 if message is too large to fit in buffer (normal messages is at least 16
+//     bytes long, so we never get length of 1 for valid message)
+//     In this case, only message header will be copied into buffer
+//   2 Message decryption failed
+//   3 Receive timeout
+//
+
+int LIBNETXMS_EXPORTABLE RecvNXCPMessage(SOCKET hSocket, CSCP_MESSAGE *pMsg,
+                                         CSCP_BUFFER *pBuffer, DWORD dwMaxMsgSize,
+                                         CSCP_ENCRYPTION_CONTEXT **ppCtx, 
+                                         BYTE *pDecryptionBuffer, DWORD dwTimeout)
+{
+   DWORD dwMsgSize = 0, dwBytesRead = 0, dwBytesToCopy;
+   int iErr;
+   BOOL bSkipMsg = FALSE;
+
+   // Initialize buffer if requested
+   if (pMsg == NULL)
+   {
+      pBuffer->dwBufSize = 0;
+      pBuffer->dwBufPos = 0;
+      return 0;
+   }
+
+   // Check if we have something in buffer
+   if (pBuffer->dwBufSize > 0)
+   {
+      // Handle the case when entire message header have not been read into the buffer
+      if (pBuffer->dwBufSize < CSCP_HEADER_SIZE)
+      {
+         // Most likely we are at the buffer end, so move content
+         // to the beginning
+         memmove(pBuffer->szBuffer, &pBuffer->szBuffer[pBuffer->dwBufPos], pBuffer->dwBufSize);
+         pBuffer->dwBufPos = 0;
+
+         // Receive new portion of data from the network 
+         // and append it to existing data in buffer
+                       iErr = RecvEx(hSocket, &pBuffer->szBuffer[pBuffer->dwBufSize],
+                       CSCP_TEMP_BUF_SIZE - pBuffer->dwBufSize, 0, dwTimeout);
+         if (iErr <= 0)
+            return (iErr == -2) ? 3 : iErr;
+         pBuffer->dwBufSize += (DWORD)iErr;
+      }
+
+      // Get message size from message header and copy available 
+      // message bytes from buffer
+      dwMsgSize = ntohl(((CSCP_MESSAGE *)(&pBuffer->szBuffer[pBuffer->dwBufPos]))->dwSize);
+      if (dwMsgSize > dwMaxMsgSize)
+      {
+         bSkipMsg = TRUE;  // Message is too large, will skip it
+         memcpy(pMsg, &pBuffer->szBuffer[pBuffer->dwBufPos], CSCP_HEADER_SIZE);
+      }
+      dwBytesRead = min(dwMsgSize, pBuffer->dwBufSize);
+      if (!bSkipMsg)
+         memcpy(pMsg, &pBuffer->szBuffer[pBuffer->dwBufPos], dwBytesRead);
+      pBuffer->dwBufSize -= dwBytesRead;
+      pBuffer->dwBufPos = (pBuffer->dwBufSize > 0) ? (pBuffer->dwBufPos + dwBytesRead) : 0;
+      if (dwBytesRead == dwMsgSize)
+         goto decrypt_message;
+   }
+
+   // Receive rest of message from the network
+   do
+   {
+      iErr = RecvEx(hSocket, pBuffer->szBuffer, CSCP_TEMP_BUF_SIZE, 0, dwTimeout);
+      if (iErr <= 0)
+         return (iErr == -2) ? 3 : iErr;
+
+      if (dwBytesRead == 0 &&
+                 iErr >= (sizeof(((CSCP_MESSAGE *)(pBuffer->szBuffer))->dwSize))) // New message?
+      {
+         dwMsgSize = ntohl(((CSCP_MESSAGE *)(pBuffer->szBuffer))->dwSize);
+         if (dwMsgSize > dwMaxMsgSize)
+         {
+            bSkipMsg = TRUE;  // Message is too large, just skip it
+            memcpy(pMsg, pBuffer->szBuffer, CSCP_HEADER_SIZE);
+         }
+      }
+      dwBytesToCopy = min((DWORD)iErr, dwMsgSize - dwBytesRead);
+      if (!bSkipMsg)
+         memcpy(((char *)pMsg) + dwBytesRead, pBuffer->szBuffer, dwBytesToCopy);
+      dwBytesRead += dwBytesToCopy;
+   }
+   while(dwBytesRead < dwMsgSize);
+   
+   // Check if we have something left in buffer
+   if (dwBytesToCopy < (DWORD)iErr)
+   {
+      pBuffer->dwBufPos = dwBytesToCopy;
+      pBuffer->dwBufSize = (DWORD)iErr - dwBytesToCopy;
+   }
+
+   // Check for encrypted message
+decrypt_message:
+   if ((!bSkipMsg) && (ntohs(pMsg->wCode) == CMD_ENCRYPTED_MESSAGE))
+   {
+      if ((*ppCtx != NULL) && (*ppCtx != PROXY_ENCRYPTION_CTX))
+      {
+         if (CSCPDecryptMessage(*ppCtx, (CSCP_ENCRYPTED_MESSAGE *)pMsg, pDecryptionBuffer))
+         {
+            dwMsgSize = ntohl(pMsg->dwSize);
+         }
+         else
+         {
+            dwMsgSize = 2;    // Decryption failed
+         }
+      }
+      else
+      {
+         if (*ppCtx != PROXY_ENCRYPTION_CTX)
+            dwMsgSize = 2;
+      }
+   }
+
+   return bSkipMsg ? 1 : (int)dwMsgSize;
+}
+
+
+//
+// Create CSCP message with raw data (MF_BINARY flag)
+// If pBuffer is NULL, new buffer is allocated with malloc()
+// Buffer should be of dwDataSize + CSCP_HEADER_SIZE + 8 bytes.
+//
+
+CSCP_MESSAGE LIBNETXMS_EXPORTABLE *CreateRawNXCPMessage(WORD wCode, DWORD dwId, WORD wFlags,
+                                                        DWORD dwDataSize, void *pData, 
+                                                        CSCP_MESSAGE *pBuffer)
+{
+   CSCP_MESSAGE *pMsg;
+   DWORD dwPadding;
+
+   if (pBuffer == NULL)
+      pMsg = (CSCP_MESSAGE *)malloc(dwDataSize + CSCP_HEADER_SIZE + 8);
+   else
+      pMsg = pBuffer;
+
+   // Message should be aligned to 8 bytes boundary
+   dwPadding = (8 - ((dwDataSize + CSCP_HEADER_SIZE) % 8)) & 7;
+
+   pMsg->wCode = htons(wCode);
+   pMsg->wFlags = htons(MF_BINARY | wFlags);
+   pMsg->dwId = htonl(dwId);
+   pMsg->dwSize = htonl(dwDataSize + CSCP_HEADER_SIZE + dwPadding);
+   pMsg->dwNumVars = htonl(dwDataSize);   // dwNumVars contains actual data size for binary message
+   memcpy(pMsg->df, pData, dwDataSize);
+
+   return pMsg;
+}
+
+
+//
+// Send file over CSCP
+//
+
+BOOL LIBNETXMS_EXPORTABLE SendFileOverNXCP(SOCKET hSocket, DWORD dwId, TCHAR *pszFile,
+                                           CSCP_ENCRYPTION_CONTEXT *pCtx)
+{
+#ifndef UNDER_CE
+   int hFile, iBytes;
+#else
+   FILE *hFile;
+   int iBytes;
+#endif
+   DWORD dwPadding;
+   BOOL bResult = FALSE;
+   CSCP_MESSAGE *pMsg;
+   CSCP_ENCRYPTED_MESSAGE *pEnMsg;
+
+#ifndef UNDER_CE
+   hFile = _topen(pszFile, O_RDONLY | O_BINARY);
+   if (hFile != -1)
+#else
+   hFile = _tfopen(pszFile, _T("rb"));
+   if (hFile != NULL)
+#endif
+   {
+      // Allocate message and prepare it's header
+      pMsg = (CSCP_MESSAGE *)malloc(FILE_BUFFER_SIZE + CSCP_HEADER_SIZE + 8);
+      pMsg->dwId = htonl(dwId);
+      pMsg->wCode = htons(CMD_FILE_DATA);
+      pMsg->wFlags = htons(MF_BINARY);
+      
+      while(1)
+      {
+#ifndef UNDER_CE
+         iBytes = read(hFile, pMsg->df, FILE_BUFFER_SIZE);
+         if (iBytes < 0)
+            break;
+#else
+         iBytes = fread(pMsg->df, 1, FILE_BUFFER_SIZE, hFile);
+         if (ferror(hFile))
+            break;
+#endif
+
+         // Message should be aligned to 8 bytes boundary
+         dwPadding = (8 - (((DWORD)iBytes + CSCP_HEADER_SIZE) % 8)) & 7;
+         pMsg->dwSize = htonl((DWORD)iBytes + CSCP_HEADER_SIZE + dwPadding);
+         pMsg->dwNumVars = htonl((DWORD)iBytes);   // dwNumVars contains actual data size for binary message
+         if (iBytes < FILE_BUFFER_SIZE)
+            pMsg->wFlags |= htons(MF_END_OF_FILE);
+
+         if (pCtx != NULL)
+         {
+            pEnMsg = CSCPEncryptMessage(pCtx, pMsg);
+            if (pEnMsg != NULL)
+            {
+               SendEx(hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0);
+               free(pEnMsg);
+            }
+         }
+         else
+         {
+            SendEx(hSocket, (char *)pMsg, (DWORD)iBytes + CSCP_HEADER_SIZE + dwPadding, 0);
+         }
+
+         if (iBytes < FILE_BUFFER_SIZE)
+         {
+            // End of file
+            bResult = TRUE;
+            break;
+         }
+      }
+
+      free(pMsg);
+#ifndef UNDER_CE
+      close(hFile);
+#else
+      fclose(hFile);
+#endif
+   }
+
+   // If file upload failed, send CMD_ABORT_FILE_TRANSFER
+   if (!bResult)
+   {
+      CSCP_MESSAGE msg;
+
+      msg.dwId = htonl(dwId);
+      msg.wCode = htons(CMD_ABORT_FILE_TRANSFER);
+      msg.wFlags = htons(MF_BINARY);
+      msg.dwNumVars = 0;
+      msg.dwSize = htonl(CSCP_HEADER_SIZE);
+      if (pCtx != NULL)
+      {
+         pEnMsg = CSCPEncryptMessage(pCtx, &msg);
+         if (pEnMsg != NULL)
+         {
+            SendEx(hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0);
+            free(pEnMsg);
+         }
+      }
+      else
+      {
+         SendEx(hSocket, (char *)&msg, CSCP_HEADER_SIZE, 0);
+      }
+   }
+
+   return bResult;
+}
+
+
+//
+// Get version of NXCP used by peer
+//
+
+BOOL LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(SOCKET hSocket, int *pnVersion)
+{
+   CSCP_MESSAGE msg;
+   CSCP_ENCRYPTION_CONTEXT *pDummyCtx = NULL;
+   CSCP_BUFFER *pBuffer;
+   BOOL bRet = FALSE;
+   int nSize;
+
+   msg.dwId = 0;
+   msg.dwNumVars = 0;
+   msg.dwSize = htonl(CSCP_HEADER_SIZE);
+   msg.wCode = htons(CMD_GET_NXCP_CAPS);
+   msg.wFlags = htons(MF_CONTROL);
+   if (SendEx(hSocket, &msg, CSCP_HEADER_SIZE, 0) == CSCP_HEADER_SIZE)
+   {
+      pBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
+      RecvNXCPMessage(0, NULL, pBuffer, 0, NULL, NULL, 0);
+      nSize = RecvNXCPMessage(hSocket, &msg, pBuffer, CSCP_HEADER_SIZE, &pDummyCtx, NULL, 30000);
+      if ((nSize == CSCP_HEADER_SIZE) &&
+          (ntohs(msg.wCode) == CMD_NXCP_CAPS) &&
+          (ntohs(msg.wFlags) & MF_CONTROL))
+      {
+         bRet = TRUE;
+         *pnVersion = ntohl(msg.dwNumVars) >> 24;
+      }
+      else if ((nSize == 1) || (nSize == 3) || (nSize >= CSCP_HEADER_SIZE))
+      {
+         // We don't receive any answr or receive invalid answer - 
+         // assume that peer doesn't understand CMD_GET_NXCP_CAPS message
+         // and set version number to 1
+         bRet = TRUE;
+         *pnVersion = 1;
+      }
+      free(pBuffer);
+   }
+   return bRet;
+}
index 926529b..b519dd8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: serial.cpp,v 1.14 2006-09-10 06:59:37 victor Exp $ */
+/* $Id: serial.cpp,v 1.15 2006-10-20 10:15:56 victor Exp $ */
 
 /* 
 ** NetXMS - Network Management System
 # endif
 #endif
 
+#ifdef _NETWARE
+#ifndef ECHOKE
+#define ECHOKE   0
+#endif
+#ifndef ECHOCTL
+#define ECHOCTL  0
+#endif
+#ifndef OPOST
+#define OPOST    0
+#endif
+#ifndef ONLCR
+#define ONLCR    0
+#endif
+#endif
+
 
 //
 // Constructor
@@ -169,8 +184,13 @@ bool Serial::Set(int nSpeed, int nDataBits, int nParity, int nStopBits, int nFlo
                case 38400:  baud = B38400;  break;
                default:     baud = B38400;  break;
        }
+#ifdef _NETWARE
+       cfsetispeed(&newTio, (speed_t)baud);
+       cfsetospeed(&newTio, (speed_t)baud);
+#else
        cfsetispeed(&newTio, baud);
        cfsetospeed(&newTio, baud);
+#endif
 
        newTio.c_cflag &= ~(CSIZE);
        switch(nDataBits)
@@ -416,6 +436,9 @@ void Serial::Flush(void)
 /*
 
 $Log: not supported by cvs2svn $
+Revision 1.14  2006/09/10 06:59:37  victor
+Fixed problmes with Win32 build
+
 Revision 1.13  2006/09/07 22:02:06  alk
 UNIX version of Serial rewritten
 termio removed from configure (depricated in favour of termio_s_?)
index 5ff6c85..12b2e4b 100644 (file)
@@ -7,7 +7,7 @@ libnxcl_la_SOURCES = actions.cpp agentcfg.cpp alarms.cpp comm.cpp datacoll.cpp \
                     script.cpp server.cpp session.cpp snmptrap.cpp snmp.cpp \
                     users.cpp
 libnxcl_la_LDFLAGS = -version-info $(LIBNXCL_LIBRARY_VERSION) $(PTHREAD_LIBS)
-libnxcl_la_LIBADD = ../libnetxms/libnetxms.la ../libnxcscp/libnxcscp.la ../libnxmap/libnxmap.la
+libnxcl_la_LIBADD = ../libnetxms/libnetxms.la ../libnxmap/libnxmap.la
 
 EXTRA_DIST = \
        libnxcl.dsp libnxcl.dsw \
index f145186..b2d6651 100644 (file)
@@ -3,7 +3,7 @@ INCLUDES=-I@top_srcdir@/include
 lib_LTLIBRARIES = libnxmap.la
 libnxmap_la_SOURCES = main.cpp map.cpp submap.cpp
 libnxmap_la_LDFLAGS = -version-info $(LIBNXMAP_LIBRARY_VERSION) $(PTHREAD_LIBS)
-libnxmap_la_LIBADD = ../libnetxms/libnetxms.la ../libnxcscp/libnxcscp.la
+libnxmap_la_LIBADD = ../libnetxms/libnetxms.la
 
 EXTRA_DIST = \
        libnxmap.dsp libnxmap.dsw \
index f0e176e..8b7f279 100644 (file)
@@ -6,7 +6,7 @@ libnxsl_la_SOURCES = lex.yy.cpp parser.tab.cpp class.cpp compiler.cpp \
                                                        library.cpp main.cpp program.cpp stack.cpp value.cpp \
                                                        variable.cpp
 libnxsl_la_LDFLAGS = -version-info $(LIBNXSL_LIBRARY_VERSION) $(PTHREAD_LIBS)
-libnxsl_la_LIBADD = ../libnetxms/libnetxms.la ../libnxcscp/libnxcscp.la
+libnxsl_la_LIBADD = ../libnetxms/libnetxms.la
 
 EXTRA_DIST = libnxsl.dsp libnxsl.dsw libnxsl.h parser.l parser.y parser.tab.hpp
 
index 94f18fe..7a62edf 100644 (file)
@@ -12,6 +12,6 @@ INCLUDES=-I@top_srcdir@/include
 
 bin_PROGRAMS = nxevent
 nxevent_SOURCES = nxevent.cpp
-nxevent_LDADD = @PTHREAD_LIBS@ ../libnetxms/libnetxms.la ../libnxcscp/libnxcscp.la ../libnxmap/libnxmap.la ../libnxcl/libnxcl.la
+nxevent_LDADD = @PTHREAD_LIBS@ ../libnetxms/libnetxms.la ../libnxmap/libnxmap.la ../libnxcl/libnxcl.la
 
 EXTRA_DIST = nxevent.dsp nxevent.dsw nxevent.h
index 8fd4fda..732e3ca 100644 (file)
@@ -12,6 +12,6 @@ INCLUDES=-I@top_srcdir@/include
 
 bin_PROGRAMS = nxscript
 nxscript_SOURCES = class.cpp nxscript.cpp
-nxscript_LDADD = @PTHREAD_LIBS@ ../libnetxms/libnetxms.la ../libnxcscp/libnxcscp.la ../libnxsl/libnxsl.la
+nxscript_LDADD = @PTHREAD_LIBS@ ../libnetxms/libnetxms.la ../libnxsl/libnxsl.la
 
 EXTRA_DIST = nxscript.dsp nxscript.dsw nxscript.h
index e038d4f..7a41aed 100644 (file)
@@ -17,8 +17,9 @@ libnxcore_la_SOURCES = acl.cpp agent.cpp actions.cpp admin.cpp alarm.cpp \
                        syslogd.cpp template.cpp tools.cpp tracert.cpp \
                        uniroot.cpp users.cpp vpnconn.cpp watchdog.cpp zone.cpp
 libnxcore_la_LDFLAGS = -version-info $(LIBNXCORE_LIBRARY_VERSION) $(PTHREAD_LIBS)
-libnxcore_la_LIBADD = ../../libnetxms/libnetxms.la ../../libnxcscp/libnxcscp.la \
-                     ../../libnxsnmp/libnxsnmp.la ../../libnxmap/libnxmap.la \
+libnxcore_la_LIBADD = ../../libnetxms/libnetxms.la \
+                     ../../libnxsnmp/libnxsnmp.la \
+                     ../../libnxmap/libnxmap.la \
                      ../libnxsrv/libnxsrv.la ../../libnxsl/libnxsl.la
 
 EXTRA_DIST = \
index 1501bcc..b266c8b 100644 (file)
@@ -3,7 +3,7 @@ INCLUDES=-I@top_srcdir@/include -I@top_srcdir@/src/server/include
 lib_LTLIBRARIES = libnxsrv.la
 libnxsrv_la_SOURCES = messages.c agent.cpp db.cpp log.cpp main.cpp
 libnxsrv_la_LDFLAGS = -version-info $(LIBNXSRV_LIBRARY_VERSION) $(PTHREAD_LIBS)
-libnxsrv_la_LIBADD = ../../libnetxms/libnetxms.la ../../libnxcscp/libnxcscp.la
+libnxsrv_la_LIBADD = ../../libnetxms/libnetxms.la
 
 messages.c: ../include/messages.h
 
index 923e9c9..230eb3b 100644 (file)
@@ -2,7 +2,7 @@ INCLUDES=-I@top_srcdir@/include -I@top_srcdir@/src/server/include
 
 bin_PROGRAMS = netxmsd
 netxmsd_SOURCES = netxmsd.cpp
-netxmsd_LDADD = @PTHREAD_LIBS@ ../../libnetxms/libnetxms.la ../../libnxcscp/libnxcscp.la ../../libnxsnmp/libnxsnmp.la ../../libnxsl/libnxsl.la ../../libnxmap/libnxmap.la ../libnxsrv/libnxsrv.la ../core/libnxcore.la
+netxmsd_LDADD = @PTHREAD_LIBS@ ../../libnetxms/libnetxms.la ../../libnxsnmp/libnxsnmp.la ../../libnxsl/libnxsl.la ../../libnxmap/libnxmap.la ../libnxsrv/libnxsrv.la ../core/libnxcore.la
 
 EXTRA_DIST = \
        netxmsd.dsp netxmsd.dsw \
index 04146ca..95ca6a0 100644 (file)
@@ -2,7 +2,7 @@ INCLUDES=-I@top_srcdir@/include -I@top_srcdir@/src/server/include
 
 bin_PROGRAMS = nxaction
 nxaction_SOURCES = nxaction.cpp
-nxaction_LDADD = @PTHREAD_LIBS@ ../../../libnetxms/libnetxms.la ../../../libnxcscp/libnxcscp.la ../../libnxsrv/libnxsrv.la
+nxaction_LDADD = @PTHREAD_LIBS@ ../../../libnetxms/libnetxms.la ../../libnxsrv/libnxsrv.la
 
 EXTRA_DIST = \
        nxaction.dsp nxaction.dsw
index 6cca6d7..a7da0ae 100644 (file)
@@ -2,7 +2,7 @@ INCLUDES=-I@top_srcdir@/include -I@top_srcdir@/src/server/include
 
 bin_PROGRAMS = nxadm
 nxadm_SOURCES = comm.cpp nxadm.cpp
-nxadm_LDADD = @PTHREAD_LIBS@ ../../../libnetxms/libnetxms.la ../../../libnxcscp/libnxcscp.la ../../libnxsrv/libnxsrv.la
+nxadm_LDADD = @PTHREAD_LIBS@ ../../../libnetxms/libnetxms.la ../../libnxsrv/libnxsrv.la
 
 EXTRA_DIST = \
        nxadm.dsp nxadm.dsw \
index 2cd2079..ddf4b77 100644 (file)
@@ -2,7 +2,7 @@ INCLUDES=-I@top_srcdir@/include -I@top_srcdir@/src/server/include
 
 bin_PROGRAMS = nxget
 nxget_SOURCES = nxget.cpp
-nxget_LDADD = @PTHREAD_LIBS@ ../../../libnetxms/libnetxms.la ../../../libnxcscp/libnxcscp.la ../../libnxsrv/libnxsrv.la
+nxget_LDADD = @PTHREAD_LIBS@ ../../../libnetxms/libnetxms.la ../../libnxsrv/libnxsrv.la
 
 EXTRA_DIST = \
        nxget.dsp nxget.dsw
index 3f94dab..329ce48 100644 (file)
@@ -2,7 +2,7 @@ INCLUDES=-I@top_srcdir@/include -I@top_srcdir@/src/server/include
 
 bin_PROGRAMS = nxupload
 nxupload_SOURCES = nxupload.cpp
-nxupload_LDADD = @PTHREAD_LIBS@ ../../../libnetxms/libnetxms.la ../../../libnxcscp/libnxcscp.la ../../libnxsrv/libnxsrv.la
+nxupload_LDADD = @PTHREAD_LIBS@ ../../../libnetxms/libnetxms.la ../../libnxsrv/libnxsrv.la
 
 EXTRA_DIST = \
        nxupload.dsp nxupload.dsw