implemented message compression in Java API; fixed protocol version issues in agent...
authorVictor Kirhenshtein <victor@netxms.org>
Mon, 13 Feb 2017 14:59:49 +0000 (16:59 +0200)
committerVictor Kirhenshtein <victor@netxms.org>
Mon, 13 Feb 2017 14:59:49 +0000 (16:59 +0200)
37 files changed:
include/nxcpapi.h
src/java/client/netxms-base/jzlib-license.txt [moved from src/java/client/netxms-client/jzlib-license.txt with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/Adler32.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/Adler32.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/CRC32.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/CRC32.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/Checksum.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/Checksum.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/Deflate.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/Deflate.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/Deflater.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/Deflater.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/DeflaterOutputStream.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/DeflaterOutputStream.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/GZIPException.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/GZIPException.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/GZIPHeader.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/GZIPHeader.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/GZIPInputStream.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/GZIPInputStream.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/GZIPOutputStream.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/GZIPOutputStream.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/InfBlocks.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/InfBlocks.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/InfCodes.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/InfCodes.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/InfTree.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/InfTree.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/Inflate.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/Inflate.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/Inflater.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/Inflater.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/InflaterInputStream.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/InflaterInputStream.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/JZlib.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/JZlib.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/StaticTree.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/StaticTree.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/Tree.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/Tree.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/ZInputStream.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/ZInputStream.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/ZOutputStream.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/ZOutputStream.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/ZStream.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/ZStream.java with 100% similarity]
src/java/client/netxms-base/src/main/java/com/jcraft/jzlib/ZStreamException.java [moved from src/java/client/netxms-client/src/main/java/com/jcraft/jzlib/ZStreamException.java with 100% similarity]
src/java/client/netxms-base/src/main/java/org/netxms/base/EncryptionContext.java
src/java/client/netxms-base/src/main/java/org/netxms/base/NXCPMessage.java
src/java/client/netxms-base/src/test/java/org/netxms/base/NXCPMessageTest.java
src/java/client/netxms-base/src/test/java/org/netxms/base/ZlibTest.java [new file with mode: 0644]
src/java/client/netxms-client/src/main/java/org/netxms/client/NXCSession.java
src/java/netxms-eclipse/FileManager/src/org/netxms/ui/eclipse/filemanager/Activator.java
src/java/netxms-eclipse/FileManager/src/org/netxms/ui/eclipse/filemanager/views/AgentFileManager.java
src/server/core/agent.cpp
src/server/core/download_job.cpp
src/server/core/node.cpp
src/server/core/session.cpp
src/server/include/nms_core.h

index d6b5a5a..81f7202 100644 (file)
@@ -80,6 +80,9 @@ public:
    UINT32 getId() const { return m_id; }
    void setId(UINT32 id) { m_id = id; }
 
+   int getProtocolVersion() const { return m_version; }
+   void setProtocolVersion(int version) { m_version = version; }
+
    bool isEndOfFile() const { return (m_flags & MF_END_OF_FILE) ? true : false; }
    bool isEndOfSequence() const { return (m_flags & MF_END_OF_SEQUENCE) ? true : false; }
    bool isReverseOrder() const { return (m_flags & MF_REVERSE_ORDER) ? true : false; }
index e466bef..5dd5e8e 100644 (file)
@@ -260,14 +260,15 @@ public final class EncryptionContext
         * Encrypt NXCP message.
         * 
         * @param msg message to encrypt
+        * @param allowCompression true if payload compression is allowed
         * @return encrypted message as sequence of bytes, ready to send over the network
         * @throws IOException 
         * @throws GeneralSecurityException 
         * @throws InvalidKeyException 
         */
-       public byte[] encryptMessage(NXCPMessage msg) throws IOException, GeneralSecurityException
+       public byte[] encryptMessage(NXCPMessage msg, boolean allowCompression) throws IOException, GeneralSecurityException
        {
-               final byte[] msgBytes = msg.createNXCPMessage();
+               final byte[] msgBytes = msg.createNXCPMessage(allowCompression);
                
                ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
                DataOutputStream outputStream = new DataOutputStream(byteStream);
index f0e56bf..cf1bc17 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * NetXMS - open source network management system
- * Copyright (C) 2003-2013 Victor Kirhenshtein
+ * Copyright (C) 2003-2017 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
@@ -24,12 +24,20 @@ import java.io.DataOutputStream;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.security.GeneralSecurityException;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 import java.util.zip.CRC32;
+import com.jcraft.jzlib.Deflater;
+import com.jcraft.jzlib.DeflaterOutputStream;
+import com.jcraft.jzlib.InflaterInputStream;
+import com.jcraft.jzlib.JZlib;
 
+/**
+ * NXCP (NetXMS Communication Protocol) message
+ */
 public class NXCPMessage
 {
        public static final int HEADER_SIZE = 16;
@@ -42,6 +50,7 @@ public class NXCPMessage
        public static final int MF_END_OF_SEQUENCE = 0x0008;
        public static final int MF_REVERSE_ORDER = 0x0010;
        public static final int MF_CONTROL = 0x0020;
+   public static final int MF_COMPRESSED = 0x0040;
        
        private int messageCode;
        private int messageFlags;
@@ -74,10 +83,11 @@ public class NXCPMessage
 
        /**
         * Create NXCPMessage from binary NXCP message
-        * @param nxcpMessage
-        * @param ectx
-        * @throws IOException
-        * @throws NXCPException
+        * 
+        * @param nxcpMessage NXCP message
+        * @param ectx encryption context
+        * @throws IOException if internal byte stream error occurs (normally should not happen)
+        * @throws NXCPException if message cannot be parsed
         */
        public NXCPMessage(final byte[] nxcpMessage, EncryptionContext ectx) throws IOException, NXCPException
        {
@@ -119,11 +129,11 @@ public class NXCPMessage
                        
                        payloadInputStream.skip(4);
                        messageCode = payloadInputStream.readUnsignedShort();
-                       createFromStream(payloadInputStream, payloadByteArrayInputStream);
+                       createFromStream(payloadInputStream);
                }
                else
                {
-                       createFromStream(inputStream, byteArrayInputStream);
+                       createFromStream(inputStream);
                }
        }
 
@@ -133,7 +143,7 @@ public class NXCPMessage
         * @param byteArrayInputStream
         * @throws IOException
         */
-       private void createFromStream(NXCPDataInputStream inputStream, ByteArrayInputStream byteArrayInputStream) throws IOException
+       private void createFromStream(NXCPDataInputStream inputStream) throws IOException
        {
                messageFlags = inputStream.readUnsignedShort();
                inputStream.skipBytes(4);       // Message size
@@ -151,12 +161,16 @@ public class NXCPMessage
                }
                else
                {
-                       final int numVars = inputStream.readInt();
-       
+         final int numVars = inputStream.readInt();
+                  if ((messageFlags & MF_COMPRESSED) == MF_COMPRESSED)
+                  {
+                     // Compressed message
+                     inputStream.skip(4);  // skip original message length
+                     inputStream = new NXCPDataInputStream(new InflaterInputStream(inputStream));
+                  }
+                  
                        for(int i = 0; i < numVars; i++)
                        {
-                               byteArrayInputStream.mark(byteArrayInputStream.available());
-                               
                                // Read first 8 bytes - any DF (data field) is at least 8 bytes long
                                byte[] df = new byte[32];
                                inputStream.readFully(df, 0, 8);
@@ -173,10 +187,10 @@ public class NXCPMessage
                                        case NXCPMessageField.TYPE_STRING:              // all these types has 4-byte length field followed by actual content
                                        case NXCPMessageField.TYPE_BINARY:
                                                int size = inputStream.readInt();
-                                               byteArrayInputStream.reset();
-                                               df = new byte[size + 12];
-                                               inputStream.readFully(df);
-                                               
+                                               df = Arrays.copyOf(df, size + 12);
+                                               intToBytes(size, df, 8);
+                                               inputStream.readFully(df, 12, size);
+
                                                // Each df aligned to 8-bytes boundary
                                                final int rem = (size + 12) % 8;
                                                if (rem != 0)
@@ -194,6 +208,22 @@ public class NXCPMessage
                        }
                }
        }
+
+       /**
+        * Encode 32 bit integer into byte array (in network byte order)
+        * 
+        * @param value integer value
+        * @param data byte array
+        * @param offset offset within byte array
+        * @throws ArrayIndexOutOfBoundsException if given offset is invalid or there is not enough space for placing integer
+        */
+       private static void intToBytes(int value, byte[] data, int offset) throws ArrayIndexOutOfBoundsException
+       {
+          data[offset] = (byte)(value >> 24);
+      data[offset + 1] = (byte)((value >> 16) & 0xFF);
+      data[offset + 2] = (byte)((value >> 8) & 0xFF);
+      data[offset + 3] = (byte)(value & 0xFF);
+       }
        
        /**
         * @return the msgCode
@@ -578,7 +608,7 @@ public class NXCPMessage
         * 
         * @return byte stream ready to send
         */
-       public byte[] createNXCPMessage() throws IOException
+       public byte[] createNXCPMessage(boolean allowCompression) throws IOException
        {
                ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
                DataOutputStream outputStream = new DataOutputStream(byteStream);
@@ -613,18 +643,41 @@ public class NXCPMessage
                                final byte[] field = nxcpVariable.createNXCPDataField();
                                outputStream.write(field);
                        }
-                       final byte[] payload = byteStream.toByteArray();
+                       byte[] payload = byteStream.toByteArray();
+                       
+                       boolean compressed = false;
+         if (allowCompression && (payload.length > 128))
+         {
+            byteStream = new ByteArrayOutputStream();
+            byte[] length = new byte[4];
+            intToBytes(payload.length, length, 0);
+            byteStream.write(length);
+            DeflaterOutputStream deflaterStream = new DeflaterOutputStream(byteStream, new Deflater(JZlib.Z_BEST_COMPRESSION));
+            deflaterStream.write(payload);
+            deflaterStream.close();
+
+            final int padding = (8 - (byteStream.size() % 8)) & 7;
+            for (int i = 0; i < padding; i++)
+               byteStream.write(0);
+            
+            byte[] compPayload = byteStream.toByteArray();
+            if (compPayload.length < payload.length)
+            {
+               payload = compPayload;
+               compressed = true;
+            }
+         }
 
                        // Create message header in new byte stream and add payload
                        byteStream = new ByteArrayOutputStream();
                        //noinspection IOResourceOpenedButNotSafelyClosed
                        outputStream = new DataOutputStream(byteStream);
                        outputStream.writeShort(messageCode);
-                       outputStream.writeShort(messageFlags);
+                       outputStream.writeShort(messageFlags | (compressed ? MF_COMPRESSED : 0));
                        outputStream.writeInt(payload.length + HEADER_SIZE);       // Size
                        outputStream.writeInt((int)messageId);
                        outputStream.writeInt(fields.size());
-                       outputStream.write(payload);
+                  outputStream.write(payload);
                }
 
                return byteStream.toByteArray();
@@ -779,6 +832,9 @@ public class NXCPMessage
                this.controlData = controlData;
        }
 
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
        @Override
        public String toString()
        {
index ec4a381..7c03ca8 100644 (file)
@@ -57,7 +57,7 @@ public class NXCPMessageTest extends TestCase
                msg1.setFieldInt64(4, 123456789L);
                msg1.setField(5, byteTest);
        
-               final byte[] bytes = msg1.createNXCPMessage();
+               final byte[] bytes = msg1.createNXCPMessage(false);
                assertEquals(120, bytes.length);
                
                final NXCPMessage msg2 = new NXCPMessage(bytes, null);
@@ -71,6 +71,31 @@ public class NXCPMessageTest extends TestCase
                assertEquals(true, Arrays.equals(byteTest, msg2.findField(5).getAsBinary()));
        }
        
+   public void testCompressedMessageEncodingAndDecoding() throws Exception
+   {
+      final byte[] byteTest = Arrays.copyOf(new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50 }, 500);
+      
+      final NXCPMessage msg1 = new NXCPMessage(1, 2);
+      msg1.setField(1, "string value 01234567890");
+      msg1.setFieldInt16(2, 10);
+      msg1.setFieldInt32(3, 20);
+      msg1.setFieldInt64(4, 123456789L);
+      msg1.setField(5, byteTest);
+   
+      final byte[] bytes = msg1.createNXCPMessage(true);
+      assertEquals(120, bytes.length);
+      
+      final NXCPMessage msg2 = new NXCPMessage(bytes, null);
+      
+      assertEquals(1, msg2.getMessageCode());
+      assertEquals(2L, msg2.getMessageId());
+      assertEquals("string value 01234567890", msg2.findField(1).getAsString());
+      assertEquals(10, msg2.findField(2).getAsInteger().intValue());
+      assertEquals(20, msg2.findField(3).getAsInteger().intValue());
+      assertEquals(123456789L, msg2.findField(4).getAsInteger().longValue());
+      assertEquals(true, Arrays.equals(byteTest, msg2.findField(5).getAsBinary()));
+   }
+   
        /**
         * Do encryption test for given cipher ID
         * 
@@ -86,11 +111,11 @@ public class NXCPMessageTest extends TestCase
           
       final NXCPMessage msg1 = new NXCPMessage(NXCPCodes.CMD_REQUEST_COMPLETED, 2);
       msg1.setFieldInt32(NXCPCodes.VID_RCC, 0);
-      final byte[] bytes = msg1.createNXCPMessage();
+      final byte[] bytes = msg1.createNXCPMessage(true);
       System.out.println("   Message encoded into " + bytes.length + " bytes");
       
           EncryptionContext ctx = new EncryptionContext(cipher);
-          byte[] encryptedBytes = ctx.encryptMessage(msg1);
+          byte[] encryptedBytes = ctx.encryptMessage(msg1, true);
       System.out.println("   Message encrypted into " + encryptedBytes.length + " bytes");
       
       final NXCPMessage msg2 = new NXCPMessage(encryptedBytes, ctx);
diff --git a/src/java/client/netxms-base/src/test/java/org/netxms/base/ZlibTest.java b/src/java/client/netxms-base/src/test/java/org/netxms/base/ZlibTest.java
new file mode 100644 (file)
index 0000000..dc52d46
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * 
+ */
+package org.netxms.base;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.util.Arrays;
+import com.jcraft.jzlib.Deflater;
+import com.jcraft.jzlib.DeflaterOutputStream;
+import com.jcraft.jzlib.InflaterInputStream;
+import com.jcraft.jzlib.JZlib;
+import junit.framework.TestCase;
+
+/**
+ * Tests for bundled ZLib implementation
+ *
+ */
+public class ZlibTest extends TestCase
+{
+   private static final String TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+   
+   public void testCompression() throws Exception
+   {
+      ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+      bytesOut.write(new byte[] { 0x01, 0x02, 0x03, 0x04 });
+      DeflaterOutputStream zout = new DeflaterOutputStream(bytesOut, new Deflater(JZlib.Z_BEST_COMPRESSION));
+      byte[] bytes = TEXT.getBytes();
+      zout.write(bytes);
+      zout.close();
+      byte[] zbytes = bytesOut.toByteArray();
+      ByteArrayInputStream bytesIn = new ByteArrayInputStream(zbytes);
+      bytesIn.skip(4);
+      InflaterInputStream zin = new InflaterInputStream(bytesIn);
+      byte[] dbytes = new byte[bytes.length];
+      DataInputStream din = new DataInputStream(zin);
+      din.readFully(dbytes);
+      assertTrue(Arrays.equals(bytes, dbytes));
+      zin.close();
+      System.out.println(String.format("Size: clear text %d, compressed %d", bytes.length, zbytes.length));
+   }
+}
index f492b3d..b7b3b64 100644 (file)
@@ -254,9 +254,10 @@ public class NXCSession
    private ReceiverThread recvThread = null;
    private HousekeeperThread housekeeperThread = null;
    private AtomicLong requestId = new AtomicLong(1);
-   private boolean isConnected = false;
-   private boolean isDisconnected = false;
+   private boolean connected = false;
+   private boolean disconnected = false;
    private boolean serverConsoleConnected = false;
+   private boolean allowCompression = false;
    private EncryptionContext encryptionContext = null;
 
    // Communication parameters
@@ -1393,7 +1394,7 @@ public class NXCSession
       {
          try
          {
-            message = encryptionContext.encryptMessage(msg);
+            message = encryptionContext.encryptMessage(msg, allowCompression);
          }
          catch(GeneralSecurityException e)
          {
@@ -1402,7 +1403,7 @@ public class NXCSession
       }
       else
       {
-         message = msg.createNXCPMessage();
+         message = msg.createNXCPMessage(allowCompression);
       }
       outputStream.write(message);
    }
@@ -1732,10 +1733,10 @@ public class NXCSession
     */
    public void connect(int[] componentVersions) throws IOException, UnknownHostException, NXCException, IllegalStateException
    {
-      if (isConnected)
+      if (connected)
          throw new IllegalStateException("Session already connected");
 
-      if (isDisconnected)
+      if (disconnected)
          throw new IllegalStateException("Session already disconnected and cannot be reused");
       
       encryptionContext = null;
@@ -1814,11 +1815,11 @@ public class NXCSession
          }
 
          Logger.debug("NXCSession.connect", "Connected to server version " + serverVersion);
-         isConnected = true;
+         connected = true;
       }
       finally
       {
-         if (!isConnected) 
+         if (!connected) 
             disconnect(SessionNotification.USER_DISCONNECT);
       }
    }
@@ -1866,10 +1867,10 @@ public class NXCSession
     */
    public void login(AuthenticationType authType, String login, String password, Certificate certificate, Signature signature) throws NXCException, IOException, IllegalStateException
    {
-      if (!isConnected)
+      if (!connected)
          throw new IllegalStateException("Session not connected");
 
-      if (isDisconnected)
+      if (disconnected)
          throw new IllegalStateException("Session already disconnected and cannot be reused");
       
       authenticationMethod = authType;
@@ -1909,6 +1910,7 @@ public class NXCSession
          request.setField(NXCPCodes.VID_CLIENT_ADDRESS, clientAddress);
       if (clientLanguage != null)
          request.setField(NXCPCodes.VID_LANGUAGE, clientLanguage);
+      request.setFieldInt16(NXCPCodes.VID_ENABLE_COMPRESSION, 1);
       sendMessage(request);
       
       final NXCPMessage response = waitForMessage(NXCPCodes.CMD_LOGIN_RESP, request.getMessageId());
@@ -1951,6 +1953,8 @@ public class NXCSession
       Logger.info("NXCSession.connect", "alarmListDisplayLimit = " + alarmListDisplayLimit);
 
       messageOfTheDay = response.getFieldAsString(NXCPCodes.VID_MESSAGE_OF_THE_DAY);
+
+      allowCompression = response.getFieldAsBoolean(NXCPCodes.VID_ENABLE_COMPRESSION);
       
       Logger.info("NXCSession.connect", "succesfully logged in, userId=" + userId);
    }
@@ -1980,7 +1984,7 @@ public class NXCSession
     */
    synchronized private void disconnect(int reason)
    {
-      if (isDisconnected)
+      if (disconnected)
          return;
       
       if (socket != null)
@@ -2047,8 +2051,8 @@ public class NXCSession
          msgWaitQueue = null;
       }
 
-      isConnected = false;
-      isDisconnected = true;
+      connected = false;
+      disconnected = true;
       
       listeners.clear();
       consoleListeners.clear();
@@ -2075,7 +2079,7 @@ public class NXCSession
     */
    public boolean isConnected()
    {
-      return isConnected;
+      return connected;
    }
 
    /**
@@ -7275,7 +7279,7 @@ public class NXCSession
     */
    public boolean checkConnection()
    {
-      if (!isConnected)
+      if (!connected)
          return false;
       
       final NXCPMessage msg = newMessage(NXCPCodes.CMD_KEEPALIVE);
@@ -7782,7 +7786,10 @@ public class NXCSession
          }
       }
       
-      AgentFileData file =  new AgentFileData(id, remoteFileName, waitForFile(msg.getMessageId(), 36000000));
+      File remoteFile = waitForFile(msg.getMessageId(), 36000000);
+      if (remoteFile == null)
+         throw new NXCException(RCC.INTERNAL_ERROR);
+      AgentFileData file =  new AgentFileData(id, remoteFileName, remoteFile);
       
       try
       {
index ae6a2f4..e4f03a4 100644 (file)
@@ -18,6 +18,7 @@
  */
 package org.netxms.ui.eclipse.filemanager;
 
+import org.eclipse.core.runtime.Status;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.osgi.framework.BundleContext;
@@ -27,7 +28,6 @@ import org.osgi.framework.BundleContext;
  */
 public class Activator extends AbstractUIPlugin
 {
-
        // The plug-in ID
        public static final String PLUGIN_ID = "org.netxms.ui.eclipse.filemanager"; //$NON-NLS-1$
 
@@ -88,4 +88,35 @@ public class Activator extends AbstractUIPlugin
        {
                return imageDescriptorFromPlugin(PLUGIN_ID, path);
        }
+
+   /**
+    * Log via platform logging facilities
+    * 
+    * @param msg
+    */
+   public static void logInfo(String msg)
+   {
+      log(Status.INFO, msg, null);
+   }
+
+   /**
+    * Log via platform logging facilities
+    * 
+    * @param msg
+    */
+   public static void logError(String msg, Exception e)
+   {
+      log(Status.ERROR, msg, e);
+   }
+
+   /**
+    * Log via platform logging facilities
+    * 
+    * @param msg
+    * @param e
+    */
+   public static void log(int status, String msg, Exception e)
+   {
+      getDefault().getLog().log(new Status(status, PLUGIN_ID, Status.OK, msg, e));
+   }
 }
index 9bb8a0b..6d053f4 100644 (file)
@@ -1018,6 +1018,7 @@ public class AgentFileManager extends ViewPart
                      final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
                      MessageDialogHelper.openError(window.getShell(), Messages.get().AgentFileManager_Error,
                            String.format(Messages.get().AgentFileManager_OpenViewError, e.getLocalizedMessage()));
+                     Activator.logError("Exception in AgentFileManager.tailFile", e);
                   }
                }
             });
index 35e53e4..a243169 100644 (file)
@@ -265,7 +265,7 @@ static void CancelUnknownFileMonitoring(Node *object,TCHAR *remoteFile)
    AgentConnection *conn = object->createAgentConnection();
    if(conn != NULL)
    {
-      NXCPMessage request;
+      NXCPMessage request(conn->getProtocolVersion());
       request.setId(conn->generateRequestId());
       request.setCode(CMD_CANCEL_FILE_MONITORING);
       request.setField(VID_FILE_NAME, remoteFile);
index 6170fc3..17a1a95 100644 (file)
@@ -120,7 +120,7 @@ ServerJobResult FileDownloadJob::run()
    AgentConnection *conn = m_node->createAgentConnection();
        if (conn != NULL)
        {
-               NXCPMessage msg, *response;
+               NXCPMessage msg(conn->getProtocolVersion()), *response;
 
                m_socket = conn->getSocket();
                conn->setDeleteFileOnDownloadFailure(false);
index 645cd86..7509a3d 100644 (file)
@@ -7499,7 +7499,7 @@ AccessPointState Node::getAccessPointState(AccessPoint *ap, SNMP_Transport *snmp
  */
 void Node::syncDataCollectionWithAgent(AgentConnectionEx *conn)
 {
-   NXCPMessage msg;
+   NXCPMessage msg(conn->getProtocolVersion());
    msg.setCode(CMD_DATA_COLLECTION_CONFIG);
    msg.setId(conn->generateRequestId());
 
@@ -7573,7 +7573,7 @@ void Node::syncDataCollectionWithAgent(AgentConnectionEx *conn)
  */
 void Node::clearDataCollectionConfigFromAgent(AgentConnectionEx *conn)
 {
-   NXCPMessage msg;
+   NXCPMessage msg(conn->getProtocolVersion());
    msg.setCode(CMD_CLEAN_AGENT_DCI_CONF);
    msg.setId(conn->generateRequestId());
    NXCPMessage *response = conn->customRequest(&msg);
index 00a6ed5..fd7378f 100644 (file)
@@ -629,7 +629,7 @@ void ClientSession::updateThread()
    UPDATE_INFO *pUpdate;
    NXCPMessage msg;
 
-   while(1)
+   while(true)
    {
       pUpdate = (UPDATE_INFO *)m_pUpdateQueue->getOrBlock();
       if (pUpdate == INVALID_POINTER_VALUE)    // Session termination indicator
@@ -741,7 +741,7 @@ void ClientSession::processingThread()
    UINT32 i;
        int status;
 
-   while(1)
+   while(true)
    {
       pMsg = (NXCPMessage *)m_pMessageQueue->getOrBlock();
       if (pMsg == INVALID_POINTER_VALUE)    // Session termination indicator
@@ -1550,17 +1550,18 @@ bool ClientSession::sendMessage(NXCPMessage *msg)
    if (isTerminated())
       return false;
 
-       if (msg->getCode() != CMD_ADM_MESSAGE)
-   {
-      TCHAR buffer[128];
-               debugPrintf(6, _T("Sending message %s"), NXCPMessageCodeName(msg->getCode(), buffer));
-   }
+       NXCP_MESSAGE *rawMsg = msg->createMessage((m_dwFlags & CSF_COMPRESSION_ENABLED) != 0);
 
-       NXCP_MESSAGE *rawMsg = msg->createMessage();
-   if ((nxlog_get_debug_level() >= 8) && (msg->getCode() != CMD_ADM_MESSAGE))
+   if ((nxlog_get_debug_level() >= 6) && (msg->getCode() != CMD_ADM_MESSAGE))
    {
-      String msgDump = NXCPMessage::dump(rawMsg, NXCP_VERSION);
-      debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
+      TCHAR buffer[128];
+      debugPrintf(6, _T("Sending%s message %s (%d bytes)"),
+               (ntohs(rawMsg->flags) & MF_COMPRESSED) ? _T(" compressed") : _T(""), NXCPMessageCodeName(msg->getCode(), buffer), ntohl(rawMsg->size));
+      if (nxlog_get_debug_level() >= 8)
+      {
+         String msgDump = NXCPMessage::dump(rawMsg, NXCP_VERSION);
+         debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
+      }
    }
 
    bool result;
@@ -1600,16 +1601,16 @@ void ClientSession::sendRawMessage(NXCP_MESSAGE *msg)
       return;
 
    UINT16 code = htons(msg->code);
-   if (code != CMD_ADM_MESSAGE)
+   if ((code != CMD_ADM_MESSAGE) && (nxlog_get_debug_level() >= 6))
    {
       TCHAR buffer[128];
-          debugPrintf(6, _T("Sending message %s"), NXCPMessageCodeName(ntohs(msg->code), buffer));
-   }
-
-   if ((code != CMD_ADM_MESSAGE) && (nxlog_get_debug_level() >= 8))
-   {
-      String msgDump = NXCPMessage::dump(msg, NXCP_VERSION);
-      debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
+          debugPrintf(6, _T("Sending%s message %s (%d bytes)"),
+                   (ntohs(msg->flags) & MF_COMPRESSED) ? _T(" compressed") : _T(""), NXCPMessageCodeName(ntohs(msg->code), buffer), ntohl(msg->size));
+      if (nxlog_get_debug_level() >= 8)
+      {
+         String msgDump = NXCPMessage::dump(msg, NXCP_VERSION);
+         debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
+      }
    }
 
    bool result;
@@ -1943,6 +1944,17 @@ void ClientSession::login(NXCPMessage *pRequest)
                        msg.setField(VID_ALARM_LIST_DISP_LIMIT, ConfigReadULong(_T("AlarmListDisplayLimit"), 4096));
          msg.setField(VID_SERVER_COMMAND_TIMEOUT, ConfigReadULong(_T("ServerCommandOutputTimeout"), 60));
 
+         if (pRequest->getFieldAsBoolean(VID_ENABLE_COMPRESSION))
+         {
+            debugPrintf(3, _T("Protocol level compression is supported by client"));
+            m_dwFlags |= CSF_COMPRESSION_ENABLED;
+            msg.setField(VID_ENABLE_COMPRESSION, true);
+         }
+         else
+         {
+            debugPrintf(3, _T("Protocol level compression is not supported by client"));
+         }
+
          TCHAR buffer[MAX_DB_STRING];
          ConfigReadStr(_T("ServerName"), buffer, MAX_DB_STRING, _T(""));
          msg.setField(VID_SERVER_NAME, buffer);
@@ -10971,6 +10983,7 @@ void ClientSession::cancelFileMonitoring(NXCPMessage *request)
          debugPrintf(6, _T("Cancel file monitoring %s"), remoteFile);
          if (conn != NULL)
          {
+            request->setProtocolVersion(conn->getProtocolVersion());
             request->setId(conn->generateRequestId());
             response = conn->customRequest(request);
             if (response != NULL)
@@ -10986,12 +10999,12 @@ void ClientSession::cancelFileMonitoring(NXCPMessage *request)
                   msg.setField(VID_RCC, AgentErrorToRCC(rcc));
                   debugPrintf(6, _T("Error on agent: %d (%s)"), rcc, AgentErrorCodeToText(rcc));
                }
+               delete response;
             }
             else
             {
                msg.setField(VID_RCC, RCC_INTERNAL_ERROR);
             }
-            delete response;
             conn->decRefCount();
          }
          else
@@ -13622,6 +13635,7 @@ void ClientSession::fileManagerControl(NXCPMessage *request)
             if (conn != NULL)
             {
                request->setId(conn->generateRequestId());
+               request->setProtocolVersion(conn->getProtocolVersion());
                if ((request->getCode() == CMD_GET_FOLDER_CONTENT) && request->getFieldAsBoolean(VID_ALLOW_MULTIPART))
                {
                   debugPrintf(5, _T("Processing multipart agent folder content request"));
@@ -13639,6 +13653,7 @@ void ClientSession::fileManagerControl(NXCPMessage *request)
                            break;
                         }
                         response->setId(msg.getId());
+                        response->setProtocolVersion(NXCP_VERSION);
                         sendMessage(response);
                         if (response->isEndOfSequence())
                         {
@@ -13667,6 +13682,7 @@ void ClientSession::fileManagerControl(NXCPMessage *request)
                   {
                      response->setId(msg.getId());
                      response->setCode(CMD_REQUEST_COMPLETED);
+                     response->setProtocolVersion(NXCP_VERSION);
                      responseMessage = response;
 
                      // Add line in audit log
index 02ec3b7..76a0f15 100644 (file)
@@ -186,6 +186,7 @@ typedef void * HSNMPSESSION;
 #define CSF_EPP_UPLOAD           ((UINT32)0x00000010)
 #define CSF_CONSOLE_OPEN         ((UINT32)0x00000020)
 #define CSF_AUTHENTICATED        ((UINT32)0x00000080)
+#define CSF_COMPRESSION_ENABLED  ((UINT32)0x00000100)
 #define CSF_RECEIVING_MAP_DATA   ((UINT32)0x00000200)
 #define CSF_SYNC_OBJECT_COMMENTS ((UINT32)0x00000400)
 #define CSF_CUSTOM_LOCK_1        ((UINT32)0x01000000)
@@ -772,7 +773,7 @@ public:
 
    void run();
 
-   void postMessage(NXCPMessage *pMsg) { m_pSendQueue->put(pMsg->createMessage()); }
+   void postMessage(NXCPMessage *pMsg) { m_pSendQueue->put(pMsg->createMessage((m_dwFlags & CSF_COMPRESSION_ENABLED) != 0)); }
    bool sendMessage(NXCPMessage *pMsg);
    void sendRawMessage(NXCP_MESSAGE *pMsg);
    void sendPollerMsg(UINT32 dwRqId, const TCHAR *pszMsg);