You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by hu...@apache.org on 2014/01/03 11:17:49 UTC

[16/50] [abbrv] CLOUDSTACK-5344: Updated to allow rdp console to access hyper-v vm virtual framebuffer.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerBitmapUpdate.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerBitmapUpdate.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerBitmapUpdate.java
new file mode 100755
index 0000000..6accc16
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerBitmapUpdate.java
@@ -0,0 +1,199 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package rdpclient.rdp;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.FakeSink;
+import common.BitmapOrder;
+import common.BitmapRectangle;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc240624.aspx
+ */
+public class ServerBitmapUpdate extends BaseElement {
+    public static final int UPDATETYPE_BITMAP = 0x0001;
+
+    /**
+     * Indicates that the bitmap data is compressed. The bitmapComprHdr field MUST
+     * be present if the NO_BITMAP_COMPRESSION_HDR (0x0400) flag is not set.
+     */
+    public static final int BITMAP_COMPRESSION = 0x0001;
+
+    /**
+     * Indicates that the bitmapComprHdr field is not present (removed for
+     * bandwidth efficiency to save 8 bytes).
+     */
+    private static final int NO_BITMAP_COMPRESSION_HDR = 0x0400;
+
+    public ServerBitmapUpdate(String id) {
+        super(id);
+    }
+
+    @Override
+    public void handleData(ByteBuffer buf, Link link) {
+
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        // * DEBUG */System.out.println(buf.toHexString(buf.length));
+
+        BitmapOrder order = new BitmapOrder();
+
+        // (2 bytes): A 16-bit, unsigned integer. The update type. This field MUST
+        // be set to UPDATETYPE_BITMAP (0x0001).
+        int updateType = buf.readSignedShortLE();
+        if (updateType != UPDATETYPE_BITMAP)
+            throw new RuntimeException("Unknown update type. Expected update type: UPDATETYPE_BITMAP (0x1). Actual update type: " + updateType + ", buf: " + buf
+                    + ".");
+
+        // (2 bytes): A 16-bit, unsigned integer. The number of screen rectangles
+        // present in the rectangles field.
+        int numberRectangles = buf.readSignedShortLE();
+
+        // (variable): Variable-length array of TS_BITMAP_DATA structures, each of
+        // which contains a rectangular clipping taken from the server-side screen
+        // frame buffer. The number of screen clippings in the array is specified by
+        // the numberRectangles field.
+        BitmapRectangle[] rectangles = new BitmapRectangle[numberRectangles];
+        for (int i = 0; i < numberRectangles; i++) {
+            rectangles[i] = readRectangle(buf);
+        }
+        order.rectangles = rectangles;
+
+        buf.assertThatBufferIsFullyRead();
+
+        ByteBuffer data = new ByteBuffer(order);
+        pushDataToAllOuts(data);
+
+        buf.unref();
+    }
+
+    public BitmapRectangle readRectangle(ByteBuffer buf) {
+
+        BitmapRectangle rectangle = new BitmapRectangle();
+
+        // (2 bytes): A 16-bit, unsigned integer. Left bound of the rectangle.
+        rectangle.x = buf.readSignedShortLE();
+
+        // (2 bytes): A 16-bit, unsigned integer. Top bound of the rectangle.
+        rectangle.y = buf.readSignedShortLE();
+
+        // (2 bytes): A 16-bit, unsigned integer. Inclusive right bound of the
+        // rectangle.
+        int destRight = buf.readSignedShortLE();
+        rectangle.width = destRight - rectangle.x + 1;
+
+        // (2 bytes): A 16-bit, unsigned integer. Inclusive bottom bound of the
+        // rectangle.
+        int destBottom = buf.readSignedShortLE();
+        rectangle.height = destBottom - rectangle.y + 1;
+
+        // (2 bytes): A 16-bit, unsigned integer. The width of the rectangle.
+        rectangle.bufferWidth = buf.readSignedShortLE();
+
+        // (2 bytes): A 16-bit, unsigned integer. The height of the rectangle.
+        rectangle.bufferHeight = buf.readSignedShortLE();
+
+        // (2 bytes): A 16-bit, unsigned integer. The color depth of the rectangle
+        // data in bits-per-pixel.
+        rectangle.colorDepth = buf.readSignedShortLE();
+
+        // (2 bytes): A 16-bit, unsigned integer. The flags describing the format of
+        // the bitmap data in the bitmapDataStream field.
+        int flags = buf.readSignedShortLE();
+
+        // BITMAP_COMPRESSION 0x0001
+        // Indicates that the bitmap data is compressed. The bitmapComprHdr field
+        // MUST be present if the NO_BITMAP_COMPRESSION_HDR (0x0400) flag is not
+        // set.
+        boolean compressed = ((flags & BITMAP_COMPRESSION) > 0);
+
+        // (2 bytes): A 16-bit, unsigned integer. The size in bytes of the data in
+        // the bitmapComprHdr and bitmapDataStream fields.
+        int bitmapLength = buf.readSignedShortLE();
+
+        // NO_BITMAP_COMPRESSION_HDR 0x0400
+        // Indicates that the bitmapComprHdr field is not present (removed for
+        // bandwidth efficiency to save 8 bytes).
+        if (compressed && (flags & NO_BITMAP_COMPRESSION_HDR) == 0) {
+            // (8 bytes): Optional Compressed Data Header structure specifying the
+            // bitmap data in the bitmapDataStream.
+            // This field MUST be present if the BITMAP_COMPRESSION (0x0001) flag is
+            // present in the Flags field, but the NO_BITMAP_COMPRESSION_HDR (0x0400)
+            // flag is not.
+
+            // Note: Even when compression header is enabled, server sends nothing.
+            // rectangle.compressedBitmapHeader = buf.readBytes(8);
+        }
+
+        // (variable): A variable-length array of bytes describing a bitmap image.
+        // Bitmap data is either compressed or uncompressed, depending on whether
+        // the BITMAP_COMPRESSION flag is present in the Flags field. Uncompressed
+        // bitmap data is formatted as a bottom-up, left-to-right series of pixels.
+        // Each pixel is a whole number of bytes. Each row contains a multiple of
+        // four bytes (including up to three bytes of padding, as necessary).
+        // Compressed bitmaps not in 32 bpp format are compressed using Interleaved
+        // RLE and encapsulated in an RLE Compressed Bitmap Stream structure,
+        // while compressed bitmaps at a color depth of 32 bpp are compressed
+        // using RDP 6.0 Bitmap Compression and stored inside
+        // an RDP 6.0 Bitmap Compressed Stream structure.
+        if (!compressed) {
+            rectangle.bitmapDataStream = buf.readBytes(bitmapLength);
+        } else {
+            ByteBuffer compressedImage = buf.readBytes(bitmapLength);
+            //* DEBUG */System.out.println("Compressed image: " + compressedImage + ", depth: " + rectangle.bitsPerPixel + ".");
+            rectangle.bitmapDataStream = RLEBitmapDecompression.rleDecompress(compressedImage, rectangle.bufferWidth, rectangle.bufferHeight, rectangle.colorDepth);
+            compressedImage.unref();
+        }
+
+        return rectangle;
+    }
+
+    /**
+     * Example.
+     */
+    public static void main(String args[]) {
+        ByteBuffer packet = new ByteBuffer(new byte[] {0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x10, 0x00,
+                0x01, 0x04, 0x0a, 0x00, 0x0c, (byte)0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
+
+        Element bitmap = new ServerBitmapUpdate("bitmap") {
+            {
+                verbose = true;
+            }
+        };
+        FakeSink fakeSink = new FakeSink("sink") {
+            {
+                verbose = true;
+            }
+        };
+        Pipeline pipeline = new PipelineImpl("test");
+
+        // BufferedImageCanvas canvas = new BufferedImageCanvas(1024, 768);
+        // Element adapter = new AwtRdpAdapter("test",canvas );
+        // pipeline.addAndLink(bitmap, adapter);
+        pipeline.addAndLink(bitmap, fakeSink);
+
+        bitmap.handleData(packet, null);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerControlPDUCooperate.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerControlPDUCooperate.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerControlPDUCooperate.java
new file mode 100755
index 0000000..2a9d49d
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerControlPDUCooperate.java
@@ -0,0 +1,117 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package rdpclient.rdp;
+
+import streamer.ByteBuffer;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+
+public class ServerControlPDUCooperate extends OneTimeSwitch {
+
+    public ServerControlPDUCooperate(String id) {
+        super(id);
+    }
+
+    @Override
+    protected void handleOneTimeData(ByteBuffer buf, Link link) {
+        if (buf == null)
+            return;
+
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        // Ignore packet
+        buf.unref();
+        switchOff();
+    }
+
+}
+
+/* @formatter:off */
+/*
+03 00 00 28 02 F0 80 68 00 01 03 EB 70 1A 1A 00 17 00 EA 03 EA 03 01 00 9A 02 1A 00 14 00 00 00 04 00 00 00 00 00 00 00
+
+
+  Frame: Number = 38, Captured Frame Length = 97, MediaType = DecryptedPayloadHeader
++ DecryptedPayloadHeader: FrameCount = 1, ErrorStatus = SUCCESS
+  TLSSSLData: Transport Layer Security (TLS) Payload Data
++ TLS: TLS Rec Layer-1 SSL Application Data
+  ISOTS: TPKTCount = 1
+- TPKT: version: 3, Length: 40
+    version: 3 (0x3)
+    Reserved: 0 (0x0)
+    PacketLength: 40 (0x28)
+- X224: Data
+    Length: 2 (0x2)
+    Type: Data
+    EOT: 128 (0x80)
+- T125: Data Packet
+  - MCSHeader: Type=Send Data Indication, UserID=1002, ChannelID=1003
+   - Type: Send Data Indication
+    - RootIndex: 26
+       Value: (011010..) 0x1a
+   - UserID: 0x3ea
+    - UserID: 0x3ea
+     - ChannelId: 1002
+      - Align: No Padding
+         Padding2: (00......) 0x0
+        Value: 1 (0x1)
+   - Channel: 0x3eb
+    - ChannelId: 1003
+       Align: No Padding
+       Value: 1003 (0x3EB)
+   - DataPriority: high
+    - DataPriority: high
+     - RootIndex: 1
+        Value: (01......) 0x1
+   - Segmentation: Begin End
+      Begin: (1.......) Begin
+      End:   (.1......) End
+   - Length: 26
+    - Align: No Padding
+       Padding4: (0000....) 0x0
+      Length: 26
+    RDP: RDPBCGR
+- RDPBCGR: TsControlPDU
+  - SlowPathPacket: TsControlPDU
+   - SlowPath: Type = TS_PDUTYPE_DATAPDU
+    - TsShareControlHeader: Type = TS_PDUTYPE_DATAPDU
+       TotalLength: 26 (0x1A)
+     - PDUType: 23 (0x17)
+        Type:            (............0111) TS_PDUTYPE_DATAPDU
+        ProtocolVersion: (000000000001....) 1
+       PDUSource: 1002 (0x3EA)
+    - SlowPathIoPacket: 0x0
+     - ShareDataHeader: TS_PDUTYPE2_CONTROL
+        ShareID: 66538 (0x103EA)
+        Pad1: 154 (0x9A)
+        StreamID: TS_STREAM_MED
+        UncompressedLength: 26 (0x1A)
+        PDUType2: TS_PDUTYPE2_CONTROL
+      - CompressedType: Not Compressed
+         MPPC:       (....0000) MPPC 8K
+         Reserved:   (...0....)
+         Compressed: (..0.....) Not Compressed
+         Front:      (.0......) Not At Front
+         Flush:      (0.......) Not Flushed
+        CompressedLength: 0 (0x0)
+     - TsControlPDU: Action = Cooperate
+        Action: Cooperate
+        GrantID: 0 (0x0)
+        ControlID: 0 (0x0)
+
+ */

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerControlPDUGrantedControl.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerControlPDUGrantedControl.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerControlPDUGrantedControl.java
new file mode 100755
index 0000000..974d622
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerControlPDUGrantedControl.java
@@ -0,0 +1,114 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package rdpclient.rdp;
+
+import streamer.ByteBuffer;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+
+public class ServerControlPDUGrantedControl extends OneTimeSwitch {
+
+    public ServerControlPDUGrantedControl(String id) {
+        super(id);
+    }
+
+    @Override
+    protected void handleOneTimeData(ByteBuffer buf, Link link) {
+        if (buf == null)
+            return;
+
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        // Ignore packet
+        buf.unref();
+        switchOff();
+    }
+
+}
+/* @formatter:off */
+/*
+03 00 00 28 02 F0 80 68 00 01 03 EB 70 1A 1A 00 17 00 EA 03 EA 03 01 00 50 02 1A 00 14 00 00 00 02 00 EC 03 EA 03 00 00
+
+  Frame: Number = 45, Captured Frame Length = 97, MediaType = DecryptedPayloadHeader
++ DecryptedPayloadHeader: FrameCount = 1, ErrorStatus = SUCCESS
+  TLSSSLData: Transport Layer Security (TLS) Payload Data
++ TLS: TLS Rec Layer-1 SSL Application Data
+  ISOTS: TPKTCount = 1
+- TPKT: version: 3, Length: 40
+    version: 3 (0x3)
+    Reserved: 0 (0x0)
+    PacketLength: 40 (0x28)
+- X224: Data
+    Length: 2 (0x2)
+    Type: Data
+    EOT: 128 (0x80)
+- T125: Data Packet
+  - MCSHeader: Type=Send Data Indication, UserID=1002, ChannelID=1003
+   - Type: Send Data Indication
+    - RootIndex: 26
+       Value: (011010..) 0x1a
+   - UserID: 0x3ea
+    - UserID: 0x3ea
+     - ChannelId: 1002
+      - Align: No Padding
+         Padding2: (00......) 0x0
+        Value: 1 (0x1)
+   - Channel: 0x3eb
+    - ChannelId: 1003
+       Align: No Padding
+       Value: 1003 (0x3EB)
+   - DataPriority: high
+    - DataPriority: high
+     - RootIndex: 1
+        Value: (01......) 0x1
+   - Segmentation: Begin End
+      Begin: (1.......) Begin
+      End:   (.1......) End
+   - Length: 26
+    - Align: No Padding
+       Padding4: (0000....) 0x0
+      Length: 26
+    RDP: RDPBCGR
+- RDPBCGR: TsControlPDU
+  - SlowPathPacket: TsControlPDU
+   - SlowPath: Type = TS_PDUTYPE_DATAPDU
+    - TsShareControlHeader: Type = TS_PDUTYPE_DATAPDU
+       TotalLength: 26 (0x1A)
+     - PDUType: 23 (0x17)
+        Type:            (............0111) TS_PDUTYPE_DATAPDU
+        ProtocolVersion: (000000000001....) 1
+       PDUSource: 1002 (0x3EA)
+    - SlowPathIoPacket: 0x0
+     - ShareDataHeader: TS_PDUTYPE2_CONTROL
+        ShareID: 66538 (0x103EA)
+        Pad1: 80 (0x50)
+        StreamID: TS_STREAM_MED
+        UncompressedLength: 26 (0x1A)
+        PDUType2: TS_PDUTYPE2_CONTROL
+      - CompressedType: Not Compressed
+         MPPC:       (....0000) MPPC 8K
+         Reserved:   (...0....)
+         Compressed: (..0.....) Not Compressed
+         Front:      (.0......) Not At Front
+         Flush:      (0.......) Not Flushed
+        CompressedLength: 0 (0x0)
+     - TsControlPDU: Action = Granted Control
+        Action: Granted Control
+        GrantID: 1004 (0x3EC)
+        ControlID: 1002 (0x3EA)
+ */

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerDemandActivePDU.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerDemandActivePDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerDemandActivePDU.java
new file mode 100755
index 0000000..88ede17a
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerDemandActivePDU.java
@@ -0,0 +1,660 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package rdpclient.rdp;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.Order;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.FakeSink;
+import streamer.debug.MockSource;
+import common.ScreenDescription;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc240669.aspx
+ * @see http://msdn.microsoft.com/en-us/library/cc240484.aspx
+ */
+public class ServerDemandActivePDU extends BaseElement {
+
+    /**
+     * Demand Active PDU.
+     */
+    public static final int PDUTYPE_DEMANDACTIVEPDU = 0x1;
+
+    protected RdpState state;
+    protected ScreenDescription screen;
+
+    public ServerDemandActivePDU(String id, ScreenDescription screen, RdpState state) {
+        super(id);
+        this.state = state;
+        this.screen = screen;
+    }
+
+    @Override
+    public void handleData(ByteBuffer buf, Link link) {
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        // Total length of packet
+        int length = buf.readSignedShortLE(); // Ignore
+        if (buf.length != length)
+            throw new RuntimeException("Incorrect length of packet. Length: " + length + ", data: " + buf + ".");
+
+        int type = buf.readSignedShortLE() & 0xf;
+        if (type != PDUTYPE_DEMANDACTIVEPDU)
+            throw new RuntimeException("Unknown PDU type. Expected type: Demand Active PDU (0x1), actual tyoe: " + type + ", data: " + buf + ".");
+
+        // TS_SHARECONTROLHEADER::pduSource = 0x03ea (1002)
+        int pduSource = buf.readSignedShortLE();
+        if (pduSource != 1002)
+            throw new RuntimeException("Unexepcted source of demand active PDU. Expected source: 1002, actual source: " + pduSource + ".");
+
+        // (4 bytes): A 32-bit, unsigned integer. The share identifier for the
+        // packet (see [T128] section 8.4.2 for more information regarding share
+        // IDs).
+        long shareId = buf.readUnsignedIntLE();
+        state.serverShareId = shareId;
+
+        // Ignore rest of server data because it is not used by this client.
+        // (2 bytes): A 16-bit, unsigned integer. The size in bytes of the
+        // sourceDescriptor field.
+        int lengthSourceDescriptor = buf.readUnsignedShortLE();
+
+        // (2 bytes): A 16-bit, unsigned integer. The combined size in bytes of the
+        // numberCapabilities, pad2Octets, and capabilitySets fields.
+        int lengthCombinedCapabilities = buf.readUnsignedShortLE();
+
+        // (variable): A variable-length array of bytes containing a source
+        // descriptor,
+        // ByteBuffer sourceDescriptor = buf.readBytes(lengthSourceDescriptor);
+        buf.skipBytes(lengthSourceDescriptor);
+
+        // (variable): An array of Capability Set (section 2.2.1.13.1.1.1)
+        // structures. The number of capability sets is specified by the
+        // numberCapabilities field.
+        handleCapabiltySets(buf.readBytes(lengthCombinedCapabilities));
+
+        // (4 bytes): A 32-bit, unsigned integer. The session identifier. This field
+        // is ignored by the client.
+        buf.skipBytes(4);
+
+        /* DEBUG */buf.assertThatBufferIsFullyRead();
+
+        buf.unref();
+
+        sendHandshakePackets();
+    }
+
+    /**
+     * General Capability Set
+     */
+    public static final int CAPSTYPE_GENERAL = 0x0001;
+    /**
+     * Bitmap Capability Set
+     */
+    public static final int CAPSTYPE_BITMAP = 0x0002;
+    /**
+     * Order Capability Set
+     */
+    public static final int CAPSTYPE_ORDER = 0x0003;
+    /**
+     * Revision 1 Bitmap Cache Capability Set
+     */
+    public static final int CAPSTYPE_BITMAPCACHE = 0x0004;
+    /**
+     * Control Capability Set
+     */
+    public static final int CAPSTYPE_CONTROL = 0x0005;
+    /**
+     * Window Activation Capability Set
+     */
+    public static final int CAPSTYPE_ACTIVATION = 0x0007;
+    /**
+     * Pointer Capability Set
+     */
+    public static final int CAPSTYPE_POINTER = 0x0008;
+    /**
+     * Share Capability Set
+     */
+    public static final int CAPSTYPE_SHARE = 0x0009;
+    /**
+     * Color Table Cache Capability Set
+     */
+    public static final int CAPSTYPE_COLORCACHE = 0x000A;
+    /**
+     * Sound Capability Set
+     */
+    public static final int CAPSTYPE_SOUND = 0x000C;
+    /**
+     * Input Capability Set
+     */
+    public static final int CAPSTYPE_INPUT = 0x000D;
+    /**
+     * Font Capability Set
+     */
+    public static final int CAPSTYPE_FONT = 0x000E;
+    /**
+     * Brush Capability Set
+     */
+    public static final int CAPSTYPE_BRUSH = 0x000F;
+    /**
+     * Glyph Cache Capability Set
+     */
+    public static final int CAPSTYPE_GLYPHCACHE = 0x0010;
+    /**
+     * Offscreen Bitmap Cache Capability Set
+     */
+    public static final int CAPSTYPE_OFFSCREENCACHE = 0x0011;
+    /**
+     * Bitmap Cache Host Support Capability Set
+     */
+    public static final int CAPSTYPE_BITMAPCACHE_HOSTSUPPORT = 0x0012;
+    /**
+     * Revision 2 Bitmap Cache Capability Set
+     */
+    public static final int CAPSTYPE_BITMAPCACHE_REV2 = 0x0013;
+    /**
+     * Virtual Channel Capability Set
+     */
+    public static final int CAPSTYPE_VIRTUALCHANNEL = 0x0014;
+    /**
+     * DrawNineGrid Cache Capability Set
+     */
+    public static final int CAPSTYPE_DRAWNINEGRIDCACHE = 0x0015;
+    /**
+     * Draw GDI+ Cache Capability Set
+     */
+    public static final int CAPSTYPE_DRAWGDIPLUS = 0x0016;
+    /**
+     * Remote Programs Capability Set
+     */
+    public static final int CAPSTYPE_RAIL = 0x0017;
+    /**
+     * Window List Capability Set
+     */
+    public static final int CAPSTYPE_WINDOW = 0x0018;
+    /**
+     * Desktop Composition Extension Capability Set
+     */
+    public static final int CAPSETTYPE_COMPDESK = 0x0019;
+    /**
+     * Multifragment Update Capability Set
+     */
+    public static final int CAPSETTYPE_MULTIFRAGMENTUPDATE = 0x001A;
+    /**
+     * Large Pointer Capability Set
+     */
+    public static final int CAPSETTYPE_LARGE_POINTER = 0x001B;
+    /**
+     * Surface Commands Capability Set
+     */
+    public static final int CAPSETTYPE_SURFACE_COMMANDS = 0x001C;
+    /**
+     * Bitmap Codecs Capability Set
+     */
+    public static final int CAPSETTYPE_BITMAP_CODECS = 0x001D;
+    /**
+     * Frame Acknowledge Capability Set
+     */
+    public static final int CAPSSETTYPE_FRAME_ACKNOWLEDGE = 0x001E;
+
+    /**
+     * @see http://msdn.microsoft.com/en-us/library/cc240486.aspx
+     */
+    protected void handleCapabiltySets(ByteBuffer buf) {
+        // (2 bytes): A 16-bit, unsigned integer. The number of capability sets
+        // included in the Demand Active PDU.
+        int numberCapabilities = buf.readSignedShortLE();
+
+        // (2 bytes): Padding.
+        buf.skipBytes(2);
+
+        for (int i = 0; i < numberCapabilities; i++) {
+            // (2 bytes): A 16-bit, unsigned integer. The type identifier of the
+            // capability set.
+            int capabilitySetType = buf.readUnsignedShortLE();
+
+            // (2 bytes): A 16-bit, unsigned integer. The length in bytes of the
+            // capability data, including the size of the capabilitySetType and
+            // lengthCapability fields.
+            int lengthCapability = buf.readUnsignedShortLE();
+
+            // (variable): Capability set data which conforms to the structure of the
+            // type given by the capabilitySetType field.
+            ByteBuffer capabilityData = buf.readBytes(lengthCapability - 4);
+
+            switch (capabilitySetType) {
+            case CAPSTYPE_GENERAL:
+                break;
+            case CAPSTYPE_BITMAP:
+                handleBitmapCapabilities(capabilityData);
+                break;
+            case CAPSTYPE_ORDER:
+                break;
+            case CAPSTYPE_BITMAPCACHE:
+                break;
+            case CAPSTYPE_CONTROL:
+                break;
+            case CAPSTYPE_ACTIVATION:
+                break;
+            case CAPSTYPE_POINTER:
+                break;
+            case CAPSTYPE_SHARE:
+                break;
+            case CAPSTYPE_COLORCACHE:
+                break;
+            case CAPSTYPE_SOUND:
+                break;
+            case CAPSTYPE_INPUT:
+                break;
+            case CAPSTYPE_FONT:
+                break;
+            case CAPSTYPE_BRUSH:
+                break;
+            case CAPSTYPE_GLYPHCACHE:
+                break;
+            case CAPSTYPE_OFFSCREENCACHE:
+                break;
+            case CAPSTYPE_BITMAPCACHE_HOSTSUPPORT:
+                break;
+            case CAPSTYPE_BITMAPCACHE_REV2:
+                break;
+            case CAPSTYPE_VIRTUALCHANNEL:
+                break;
+            case CAPSTYPE_DRAWNINEGRIDCACHE:
+                break;
+            case CAPSTYPE_DRAWGDIPLUS:
+                break;
+            case CAPSTYPE_RAIL:
+                break;
+            case CAPSTYPE_WINDOW:
+                break;
+            case CAPSETTYPE_COMPDESK:
+                break;
+            case CAPSETTYPE_MULTIFRAGMENTUPDATE:
+                break;
+            case CAPSETTYPE_LARGE_POINTER:
+                break;
+            case CAPSETTYPE_SURFACE_COMMANDS:
+                break;
+            case CAPSETTYPE_BITMAP_CODECS:
+                break;
+            case CAPSSETTYPE_FRAME_ACKNOWLEDGE:
+                break;
+            default:
+                // Ignore
+                break;
+            }
+
+            capabilityData.unref();
+        }
+
+        // TODO
+
+        buf.unref();
+    }
+
+    /**
+     * @see http://msdn.microsoft.com/en-us/library/cc240554.aspx
+     */
+    protected void handleBitmapCapabilities(ByteBuffer buf) {
+
+        // (2 bytes): A 16-bit, unsigned integer. The server MUST set this field to
+        // the color depth of the session, while the client SHOULD set this field to
+        // the color depth requested in the Client Core Data (section 2.2.1.3.2).
+        int preferredBitsPerPixel = buf.readUnsignedShortLE();
+        screen.setPixelFormatRGBTrueColor(preferredBitsPerPixel);
+
+        // receive1BitPerPixel (2 bytes): A 16-bit, unsigned integer. Indicates
+        // whether the client can receive 1 bpp. This field is ignored and SHOULD be
+        // set to TRUE (0x0001).
+        buf.skipBytes(2);
+
+        // receive4BitsPerPixel(2 bytes): A 16-bit, unsigned integer. Indicates
+        // whether the client can receive 4 bpp. This field is ignored and SHOULD be
+        // set to TRUE (0x0001).
+        buf.skipBytes(2);
+
+        // receive8BitsPerPixel (2 bytes): A 16-bit, unsigned integer. Indicates
+        // whether the client can receive 8 bpp. This field is ignored and SHOULD be
+        // set to TRUE (0x0001).
+        buf.skipBytes(2);
+
+        // (2 bytes): A 16-bit, unsigned integer. The width of the desktop in the
+        // session.
+        int desktopWidth = buf.readUnsignedShortLE();
+
+        // (2 bytes): A 16-bit, unsigned integer. The height of the desktop in the
+        // session.
+        int desktopHeight = buf.readUnsignedShortLE();
+
+        screen.setFramebufferSize(desktopWidth, desktopHeight);
+
+        // pad2octets (2 bytes): A 16-bit, unsigned integer. Padding. Values in this
+        // field MUST be ignored.
+
+        // desktopResizeFlag (2 bytes): A 16-bit, unsigned integer. Indicates
+        // whether resizing the desktop by using a Deactivation-Reactivation
+        // Sequence is supported.
+
+        // bitmapCompressionFlag (2 bytes): A 16-bit, unsigned integer. Indicates
+        // whether bitmap compression is supported. This field MUST be set to TRUE
+        // (0x0001) because support for compressed bitmaps is required for a
+        // connection to proceed.
+
+        // highColorFlags (1 byte): An 8-bit, unsigned integer. Client support for
+        // 16 bpp color modes. This field is ignored and SHOULD be set to zero.
+
+        // drawingFlags (1 byte): An 8-bit, unsigned integer. Flags describing
+        // support for 32 bpp bitmaps.
+
+        // multipleRectangleSupport (2 bytes): A 16-bit, unsigned integer. Indicates
+        // whether the use of multiple bitmap rectangles is supported in the Bitmap
+        // Update (section 2.2.9.1.1.3.1.2). This field MUST be set to TRUE (0x0001)
+        // because multiple rectangle support is required for a connection to
+        // proceed.
+
+        // pad2octetsB (2 bytes): A 16-bit, unsigned integer. Padding. Values in
+        // this field MUST be ignored.
+    }
+
+    /**
+     * Send all client requests in one hop, to simplify logic.
+     */
+    protected void sendHandshakePackets() {
+        // Send reactivation sequence in bulk
+        pushDataToPad("confirm_active", new ByteBuffer((Order)null));
+    }
+
+    /**
+     * Example.
+     *
+     */
+    public static void main(String args[]) {
+        // System.setProperty("streamer.Link.debug", "true");
+        System.setProperty("streamer.Element.debug", "true");
+        // System.setProperty("streamer.Pipeline.debug", "true");
+
+        /* @formatter:off */
+        byte[] packet = new byte[] {
+                0x67, 0x01,  //  TS_SHARECONTROLHEADER::totalLength = 0x0167 = 359 bytes
+                0x11, 0x00,  //  TS_SHARECONTROLHEADER::pduType = 0x0011 0x0011 = 0x0010 | 0x0001  = TS_PROTOCOL_VERSION | PDUTYPE_DEMANDACTIVEPDU
+
+                (byte) 0xea, 0x03,  //  TS_SHARECONTROLHEADER::pduSource = 0x03ea (1002)
+
+                (byte) 0xea, 0x03, 0x01, 0x00,  //  TS_DEMAND_ACTIVE_PDU::shareId
+                0x04, 0x00,  //  TS_DEMAND_ACTIVE_PDU::lengthSourceDescriptor = 4 bytes
+                0x51, 0x01,  //  TS_DEMAND_ACTIVE_PDU::lengthCombinedCapabilities = 0x151 = 337 bytes
+
+                0x52, 0x44, 0x50, 0x00,  //  TS_DEMAND_ACTIVE_PDU::sourceDescriptor = "RDP"
+
+                0x0d, 0x00,  //  TS_DEMAND_ACTIVE_PDU::numberCapabilities = 13
+                0x00, 0x00,  //  TS_DEMAND_ACTIVE_PDU::pad2octets
+
+                //  Share Capability Set (8 bytes)
+                // 0x09, 0x00, 0x08, 0x00, (byte) 0xea, 0x03, (byte) 0xdc, (byte) 0xe2,
+                //
+                0x09, 0x00,  //  TS_SHARE_CAPABILITYSET::capabilitySetType = CAPSTYPE_SHARE (9)
+                0x08, 0x00,  //  TS_SHARE_CAPABILITYSET::lengthCapability = 8 bytes
+                (byte) 0xea, 0x03,  //  TS_SHARE_CAPABILITYSET::nodeID = 0x03ea (1002)
+                (byte) 0xdc, (byte) 0xe2,  //  TS_SHARE_CAPABILITYSET::pad2octets
+
+                //  General Capability Set (24 bytes)
+                // 0x01, 0x00, 0x18, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x04,
+                // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+                //
+                0x01, 0x00,  //  TS_GENERAL_CAPABILITYSET::capabilitySetType = CAPSTYPE_GENERAL (1)
+                0x18, 0x00,  //  TS_GENERAL_CAPABILITYSET::lengthCapability = 24 bytes
+
+                0x01, 0x00,  //  TS_GENERAL_CAPABILITYSET::osMajorType = TS_OSMAJORTYPE_WINDOWS (1)
+                0x03, 0x00,  //  TS_GENERAL_CAPABILITYSET::osMinorType = TS_OSMINORTYPE_WINDOWS_NT (3)
+                0x00, 0x02,  //  TS_GENERAL_CAPABILITYSET::protocolVersion = TS_CAPS_PROTOCOLVERSION (0x0200)
+                0x00, 0x00,  //  TS_GENERAL_CAPABILITYSET::pad2octetsA
+                0x00, 0x00,  //  TS_GENERAL_CAPABILITYSET::generalCompressionTypes = 0
+                0x1d, 0x04,  //  TS_GENERAL_CAPABILITYSET::extraFlags = 0x041d = 0x0400 | 0x0010 | 0x0008 | 0x0004 | 0x0001 = NO_BITMAP_COMPRESSION_HDR | ENC_SALTED_CHECKSUM | AUTORECONNECT_SUPPORTED | LONG_CREDENTIALS_SUPPORTED | FASTPATH_OUTPUT_SUPPORTED
+
+                0x00, 0x00,  //  TS_GENERAL_CAPABILITYSET::updateCapabilityFlag = 0
+                0x00, 0x00,  //  TS_GENERAL_CAPABILITYSET::remoteUnshareFlag = 0
+                0x00, 0x00,  //  TS_GENERAL_CAPABILITYSET::generalCompressionLevel = 0
+                0x01,  //  TS_GENERAL_CAPABILITYSET::refreshRectSupport = TRUE
+                0x01,  //  TS_GENERAL_CAPABILITYSET::suppressOutputSupport = TRUE
+
+                // Virtual Channel Capability Set (8 bytes)
+                // 0x14, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00,
+                //
+                0x14, 0x00,  //  TS_VIRTUALCHANNEL_CAPABILITYSET::capabilitySetType = CAPSTYPE_VIRTUALCHANNEL (20)
+                0x08, 0x00,  //  TS_VIRTUALCHANNEL_CAPABILITYSET::lengthCapability = 8 bytes
+
+                0x02, 0x00, 0x00, 0x00,  //  TS_VIRTUALCHANNEL_CAPABILITYSET::vccaps1 = 0x00000002 = VCCAPS_COMPR_CS_8K
+
+                //  DrawGdiPlus Capability Set (40 bytes)
+                // 0x16, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, (byte) 0xf6, 0x13, (byte) 0xf3, 0x01, 0x00, 0x00, 0x00,
+                // 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, (byte) 0x9c, (byte) 0xf6, 0x13, (byte) 0xf3, 0x61, (byte) 0xa6, (byte) 0x82, (byte) 0x80,
+                // 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, (byte) 0x91, (byte) 0xbf,
+                //
+                0x16, 0x00,  //  TS_DRAW_GDIPLUS_CAPABILITYSET::capabilitySetType = CAPSTYPE_DRAWGDIPLUS (22)
+                0x28, 0x00,  //  TS_DRAW_GDIPLUS_CAPABILITYSET::lengthCapability = 40 bytes
+
+                0x00, 0x00, 0x00, 0x00,  //  TS_DRAW_GDIPLUS_CAPABILITYSET::drawGdiplusSupportLevel = TS_DRAW_GDIPLUS_DEFAULT (0)
+                0x70, (byte) 0xf6, 0x13, (byte) 0xf3,  //  TS_DRAW_GDIPLUS_CAPABILITYSET::GdipVersion (not initialized by server)
+                0x01, 0x00, 0x00, 0x00,  //  TS_DRAW_GDIPLUS_CAPABILITYSET::drawGdiplusCacheLevel  = TS_DRAW_GDIPLUS_CACHE_LEVEL_ONE (1)
+
+                0x01, 0x00,  //  TS_GDIPLUS_CACHE_ENTRIES::GdipGraphicsCacheEntries  (not initialized by server)
+                0x00, 0x00,  //  TS_GDIPLUS_CACHE_ENTRIES::GdipObjectBrushCacheEntries (not initialized by server)
+                0x18, 0x00,  //  TS_GDIPLUS_CACHE_ENTRIES::GdipObjectPenCacheEntries (not initialized by server)
+                0x00, 0x00,  //  TS_GDIPLUS_CACHE_ENTRIES::GdipObjectImageCacheEntries (not initialized by server)
+                (byte) 0x9c, (byte) 0xf6,  //  TS_GDIPLUS_CACHE_ENTRIES::GdipObjectImageAttributesCacheEntries (not initialized by server)
+
+                0x13, (byte) 0xf3,  //  TS_GDIPLUS_CACHE_CHUNK_SIZE::GdipGraphicsCacheChunkSize  (not initialized by server)
+                0x61, (byte) 0xa6,  //  TS_GDIPLUS_CACHE_CHUNK_SIZE::GdipObjectBrushCacheChunkSize (not initialized by server)
+                (byte) 0x82, (byte) 0x80,  //  TS_GDIPLUS_CACHE_CHUNK_SIZE::GdipObjectPenCacheChunkSize (not initialized by server)
+                0x00, 0x00,  //   TS_GDIPLUS_CACHE_CHUNK_SIZE::GdipObjectImageAttributesCacheChunkSize (not initialized by server)
+
+                0x00, 0x00,  //  TS_GDIPLUS_IMAGE_CACHE_PROPERTIES::GdipObjectImageCacheChunkSize  (not initialized by server)
+                0x00, 0x50,  //  TS_GDIPLUS_IMAGE_CACHE_PROPERTIES::GdipObjectImageCacheTotalSize  (not initialized by server)
+                (byte) 0x91, (byte) 0xbf,  //  TS_GDIPLUS_IMAGE_CACHE_PROPERTIES::GdipObjectImageCacheMaxSize (not initialized by server)
+
+                //  Font Capability Set (4 bytes)
+                // 0x0e, 0x00, 0x04, 0x00,
+                //
+                // Due to a bug, the TS_FONT_CAPABILITYSET capability set size is incorrectly set to 4 bytes (it must be 8 bytes). As a result of this bug, the fontSupportFlags and pad2octets fields are missing.
+                0x0e, 0x00,  //  TS_FONT_CAPABILITYSET::capabilitySetType = CAPSTYPE_FONT (14)
+                0x04, 0x00,  //  TS_FONT_CAPABILITYSET::lengthCapability = 4 bytes
+
+
+                //  Bitmap Capability Set (28 bytes)
+                // 0x02, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04,
+                // 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+                //
+                0x02, 0x00,  //  TS_BITMAP_CAPABILITYSET::capabilitySetType = CAPSTYPE_BITMAP (2)
+                0x1c, 0x00,  //  TS_BITMAP_CAPABILITYSET::lengthCapability = 28 bytes
+
+                0x18, 0x00,  //  TS_BITMAP_CAPABILITYSET::preferredBitsPerPixel = 24 bpp
+                0x01, 0x00,  //  TS_BITMAP_CAPABILITYSET::receive1BitPerPixel = TRUE
+                0x01, 0x00,  //  TS_BITMAP_CAPABILITYSET::receive4BitsPerPixel = TRUE
+                0x01, 0x00,  //  TS_BITMAP_CAPABILITYSET::receive8BitsPerPixel = TRUE
+                0x00, 0x05,  //  TS_BITMAP_CAPABILITYSET::desktopWidth = 1280 pixels
+                0x00, 0x04,  //  TS_BITMAP_CAPABILITYSET::desktopHeight = 1024 pixels
+                0x00, 0x00,  //  TS_BITMAP_CAPABILITYSET::pad2octets
+                0x01, 0x00,  //  TS_BITMAP_CAPABILITYSET::desktopResizeFlag = TRUE
+                0x01, 0x00,  //  TS_BITMAP_CAPABILITYSET::bitmapCompressionFlag = TRUE
+                0x00,  //  TS_BITMAP_CAPABILITYSET::highColorFlags = 0
+                0x00,  //  TS_BITMAP_CAPABILITYSET::pad1octet
+                0x01, 0x00,  //  TS_BITMAP_CAPABILITYSET::multipleRectangleSupport = TRUE
+                0x00, 0x00,  //  TS_BITMAP_CAPABILITYSET::pad2octetsB
+
+                //  Order Capability Set (88 bytes)
+                // 0x03, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                // 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00,
+                // 0x00, 0x00, 0x22, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
+                // 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
+                // 0x00, 0x00, 0x00, 0x00, (byte) 0xa1, 0x06, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x40, 0x42, 0x0f, 0x00,
+                // 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                //
+                0x03, 0x00,  //  TS_ORDER_CAPABILITYSET::capabilitySetType = CAPSTYPE_ORDER (3)
+                0x58, 0x00,  //  TS_ORDER_CAPABILITYSET::lengthCapability = 88 bytes
+
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // TS_ORDER_CAPABILITYSET::terminalDescriptor = ""
+                0x40, 0x42, 0x0f, 0x00,  //  TS_ORDER_CAPABILITYSET::pad4octetsA
+
+                0x01, 0x00,  //  TS_ORDER_CAPABILITYSET::desktopSaveXGranularity = 1
+                0x14, 0x00,  //  TS_ORDER_CAPABILITYSET::desktopSaveYGranularity = 20
+                0x00, 0x00,  //  TS_ORDER_CAPABILITYSET::pad2octetsA
+                0x01, 0x00,  //  TS_ORDER_CAPABILITYSET::maximumOrderLevel = ORD_LEVEL_1_ORDERS (1)
+                0x00, 0x00,  //  TS_ORDER_CAPABILITYSET::numberFonts = 0
+
+                0x22, 0x00,  //  TS_ORDER_CAPABILITYSET::orderFlags = 0x0022 = 0x0020 | 0x0002 = COLORINDEXSUPPORT | NEGOTIATEORDERSUPPORT
+
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_DSTBLT_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_PATBLT_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_SCRBLT_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MEMBLT_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MEM3BLT_INDEX] = TRUE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_ATEXTOUT_INDEX] = FALSE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_AEXTTEXTOUT_INDEX] = FALSE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_DRAWNINEGRID_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_LINETO_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTI_DRAWNINEGRID_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_OPAQUERECT_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_SAVEBITMAP_INDEX] = TRUE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_WTEXTOUT_INDEX] = FALSE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MEMBLT_R2_INDEX] = FALSE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MEM3BLT_R2_INDEX] = FALSE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTIDSTBLT_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTIPATBLT_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTISCRBLT_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_MULTIOPAQUERECT_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_FAST_INDEX_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_POLYGON_SC_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_POLYGON_CB_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_POLYLINE_INDEX] = TRUE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[23] = 0
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_FAST_GLYPH_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_ELLIPSE_SC_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_ELLIPSE_CB_INDEX] = TRUE
+                0x01,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_INDEX_INDEX] = TRUE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_WEXTTEXTOUT_INDEX] = FALSE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_WLONGTEXTOUT_INDEX] = FALSE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[TS_NEG_WLONGEXTTEXTOUT_INDEX] = FALSE
+                0x00,  //  TS_ORDER_CAPABILITYSET::orderSupport[24] = 0
+
+                (byte) 0xa1, 0x06,  //  TS_ORDER_CAPABILITYSET::textFlags = 0x06a1
+
+                0x00, 0x00,  //  TS_ORDER_CAPABILITYSET::pad2octetsB
+                0x40, 0x42, 0x0f, 0x00,  //  TS_ORDER_CAPABILITYSET::pad4octetsB
+
+                0x40, 0x42, 0x0f, 0x00,  //  TS_ORDER_CAPABILITYSET::desktopSaveSize = 0xf4240 = 1000000
+                0x01, 0x00,  //  TS_ORDER_CAPABILITYSET::pad2octetsC
+                0x00, 0x00,  //  TS_ORDER_CAPABILITYSET::pad2octetsD
+                0x00, 0x00,  //  TS_ORDER_CAPABILITYSET::textANSICodePage
+                0x00, 0x00,  //  TS_ORDER_CAPABILITYSET::pad2octetsE
+
+                // Color Table Cache Capability Set (8 bytes)
+                // 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00,
+                //
+                0x0a, 0x00,  //  TS_COLORTABLECACHE_CAPABILITYSET::capabilitySetType = CAPSTYPE_COLORCACHE (10)
+                0x08, 0x00,  //  TS_COLORTABLECACHE_CAPABILITYSET::lengthCapability = 8 bytes
+
+                0x06, 0x00,  //  TS_COLORTABLECACHE_CAPABILITYSET::colorTableCacheSize = 6
+                0x00, 0x00,  //  TS_COLORTABLECACHE_CAPABILITYSET::pad2octets
+
+                // Bitmap Cache Host Support Capability Set (8 bytes)
+                // 0x12, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
+                //
+                0x12, 0x00,  //  TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::capabilitySetType  = CAPSTYPE_BITMAPCACHE_HOSTSUPPORT (18)
+                0x08, 0x00,  //  TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::lengthCapability  = 8 bytes
+
+                0x01,  //  TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::CacheVersion = 1  (corresponds to rev. 2 capabilities)
+                0x00,  //  TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::Pad1
+                0x00, 0x00,  //  TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT::Pad2
+
+                // Pointer Capability Set (10 bytes)
+                // 0x08, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x19, 0x00, 0x19, 0x00,
+                //
+                0x08, 0x00,  //  TS_POINTER_CAPABILITYSET::capabilitySetType = CAPSTYPE_POINTER (8)
+                0x0a, 0x00,  //  TS_POINTER_CAPABILITYSET::lengthCapability = 10 bytes
+
+                0x01, 0x00,  //  TS_POINTER_CAPABILITYSET::colorPointerFlag = TRUE
+                0x19, 0x00,  //  TS_POINTER_CAPABILITYSET::colorPointerCacheSize = 25
+                0x19, 0x00,  //  TS_POINTER_CAPABILITYSET::pointerCacheSize = 25
+
+                //  Input Capability Set (88 bytes)
+                // 0x0d, 0x00, 0x58, 0x00, 0x35, 0x00, 0x00, 0x00, (byte) 0xa1, 0x06, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00,
+                // 0x0c, (byte) 0xf6, 0x13, (byte) 0xf3, (byte) 0x93, 0x5a, 0x37, (byte) 0xf3, 0x00, (byte) 0x90, 0x30, (byte) 0xe1, 0x34, 0x1c, 0x38, (byte) 0xf3,
+                // 0x40, (byte) 0xf6, 0x13, (byte) 0xf3, 0x04, 0x00, 0x00, 0x00, 0x4c, 0x54, (byte) 0xdc, (byte) 0xe2, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2,
+                // 0x01, 0x00, 0x00, 0x00, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2, 0x00, 0x00, 0x00, 0x00, 0x38, (byte) 0xf6, 0x13, (byte) 0xf3,
+                // 0x2e, 0x05, 0x38, (byte) 0xf3, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2, 0x2c, (byte) 0xf6, 0x13, (byte) 0xf3, 0x00, 0x00, 0x00, 0x00,
+                // 0x08, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x19, 0x00,
+                //
+                0x0d, 0x00,  //  TS_INPUT_CAPABILITYSET::capabilitySetType = CAPSTYPE_INPUT (13)
+                0x58, 0x00,  //  TS_INPUT_CAPABILITYSET::lengthCapability = 88 bytes
+
+                0x35, 0x00,  //  TS_INPUT_CAPABILITYSET::inputFlags = 0x0035 = 0x0020 | 0x0010 | 0x0004 | 0x0001 = INPUT_FLAG_FASTPATH_INPUT2 | INPUT_FLAG_VKPACKET | INPUT_FLAG_MOUSEX | INPUT_FLAG_SCANCODES
+
+                0x00, 0x00,  //  TS_INPUT_CAPABILITYSET::pad2octetsA
+                (byte) 0xa1, 0x06, 0x00, 0x00,  //  TS_INPUT_CAPABILITYSET::keyboardLayout (not initialized by server)
+                0x40, 0x42, 0x0f, 0x00,  //  TS_INPUT_CAPABILITYSET::keyboardType (not initialized by server)
+                0x0c, (byte) 0xf6, 0x13, (byte) 0xf3,  //  TS_INPUT_CAPABILITYSET::keyboardSubType  (not initialized by server)
+                (byte) 0x93, 0x5a, 0x37, (byte) 0xf3,  //  TS_INPUT_CAPABILITYSET::keyboardFunctionKey (not initialized by server)
+
+                // TS_INPUT_CAPABILITYSET::imeFileName (not initialized by server)
+                0x00, (byte) 0x90, 0x30, (byte) 0xe1, 0x34, 0x1c, 0x38, (byte) 0xf3, 0x40, (byte) 0xf6, 0x13, (byte) 0xf3, 0x04, 0x00, 0x00, 0x00,
+                0x4c, 0x54, (byte) 0xdc, (byte) 0xe2, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2, 0x01, 0x00, 0x00, 0x00, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2,
+                0x00, 0x00, 0x00, 0x00, 0x38, (byte) 0xf6, 0x13, (byte) 0xf3, 0x2e, 0x05, 0x38, (byte) 0xf3, 0x08, 0x50, (byte) 0xdc, (byte) 0xe2,
+                0x2c, (byte) 0xf6, 0x13, (byte) 0xf3, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x19, 0x00,
+
+                //  RAIL Capability Set (8 bytes)
+                // 0x17, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+                //
+                0x17, 0x00,  //  TS_RAIL_CAPABILITYSET::capabilitySetType = CAPSTYPE_RAIL (23)
+                0x08, 0x00,  //  TS_RAIL_CAPABILITYSET::lengthCapability = 8 bytes
+
+                0x00, 0x00, 0x00, 0x00,  //  TS_RAIL_CAPABILITYSET::railSupportLevel = TS_RAIL_LEVEL_DEFAULT (0)
+
+                //  Windowing Capability Set (11 bytes)
+                // 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                //
+                0x18, 0x00,  //  TS_WINDOW_CAPABILITYSET::capabilitySetType =  CAPSTYPE_WINDOW (24)
+                0x0b, 0x00,  //  TS_WINDOW_CAPABILITYSET::lengthCapability = 11 bytes
+
+                0x00, 0x00, 0x00, 0x00,  //  TS_WINDOW_CAPABILITYSET::wndSupportLevel = TS_WINDOW_LEVEL_DEFAULT (0)
+                0x00,  //  TS_WINDOW_CAPABILITYSET::nIconCaches = 0
+                0x00, 0x00,  //  TS_WINDOW_CAPABILITYSET::nIconCacheEntries = 0
+
+                // Remainder of Demand Active PDU:
+
+                0x00, 0x00, 0x00, 0x00,  //  TS_DEMAND_ACTIVE_PDU::sessionId = 0
+        };
+        /* @formatter:on */
+
+        RdpState rdpState = new RdpState();
+        ScreenDescription screenDescription = new ScreenDescription();
+
+        MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
+        Element demandActive = new ServerDemandActivePDU("demand_active", screenDescription, rdpState);
+        Element sink = new FakeSink("sink");
+
+        Pipeline pipeline = new PipelineImpl("test");
+        pipeline.add(source, demandActive, sink);
+        pipeline.link("source", "demand_active", "sink");
+        pipeline.runMainLoop("source", STDOUT, false, false);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerFastPath.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerFastPath.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerFastPath.java
new file mode 100755
index 0000000..f88f492
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerFastPath.java
@@ -0,0 +1,315 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package rdpclient.rdp;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc240621.aspx
+ */
+public class ServerFastPath extends BaseElement {
+
+    /**
+     * TPKT protocol version (first byte).
+     */
+    public static final int PROTOCOL_TPKT = 0x03;
+
+    /**
+     * Fast path protocol version (first two bits of first byte).
+     */
+    public static final int PROTOCOL_FASTPATH = 0x00;
+
+    /**
+     * CredSSP packets.
+     */
+    public static final int PROTOCOL_CREDSSP = 0x30;
+
+    /**
+     * TPKT packets will be pushed to that pad.
+     */
+    public static final String TPKT_PAD = "tpkt";
+
+    /**
+     * CredSSP packets will be pushed to same pad as TPKT, because they are part
+     * of slow-path initialization sequence.
+     */
+    public static final String CREDSSP_PAD = "tpkt";
+
+    private static final String ORDERS_PAD = "orders";
+    private static final String BITMAP_PAD = "bitmap";
+    private static final String PALETTE_PAD = "palette";
+
+    /**
+     * Indicates that packet contains 8 byte secure checksum at top of packet. Top
+     * two bits of first byte.
+     */
+    public static final int FASTPATH_OUTPUT_SECURE_CHECKSUM = 1;
+
+    /**
+     * Indicates that packet contains 8 byte secure checksum at top of packet and
+     * packet content is encrypted. Top two bits of first byte.
+     */
+    public static final int FASTPATH_OUTPUT_ENCRYPTED = 2;
+
+    public static final int FASTPATH_UPDATETYPE_ORDERS = 0;
+    public static final int FASTPATH_UPDATETYPE_BITMAP = 1;
+    public static final int FASTPATH_UPDATETYPE_PALETTE = 2;
+    public static final int FASTPATH_UPDATETYPE_SYNCHRONIZE = 3;
+    public static final int FASTPATH_UPDATETYPE_SURFCMDS = 4;
+    public static final int FASTPATH_UPDATETYPE_PTR_NULL = 5;
+    public static final int FASTPATH_UPDATETYPE_PTR_DEFAULT = 6;
+    public static final int FASTPATH_UPDATETYPE_PTR_POSITION = 8;
+    public static final int FASTPATH_UPDATETYPE_COLOR = 9;
+    public static final int FASTPATH_UPDATETYPE_CACHED = 0xa;
+    public static final int FASTPATH_UPDATETYPE_POINTER = 0xb;
+
+    public static final int FASTPATH_FRAGMENT_SINGLE = 0;
+    public static final int FASTPATH_FRAGMENT_LAST = 1;
+    public static final int FASTPATH_FRAGMENT_FIRST = 2;
+    public static final int FASTPATH_FRAGMENT_NEXT = 3;
+
+    public static final int FASTPATH_OUTPUT_COMPRESSION_USED = 2;
+
+    public ServerFastPath(String id) {
+        super(id);
+    }
+
+    @Override
+    public void handleData(ByteBuffer buf, Link link) {
+        if (buf == null)
+            return;
+
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        // * DEBUG */System.out.println(buf.toHexString(buf.length));
+
+        // We need at 4 bytes to read packet type (TPKT or FastPath) and packet
+        // length
+        if (!cap(buf, 4, UNLIMITED, link, false))
+            return;
+
+        int typeAndFlags = buf.readUnsignedByte();
+
+        switch (typeAndFlags) {
+        case PROTOCOL_TPKT: // 0x03
+            handleTpkt(buf, link);
+            break;
+
+        case PROTOCOL_CREDSSP: // 0x30, potential clash with FastPath
+            handleCredSSP(buf, link);
+            break;
+
+        default: // (value & 0x03) == 0x00
+        case PROTOCOL_FASTPATH:
+            handleFastPath(buf, link, typeAndFlags);
+            break;
+        }
+
+    }
+
+    private void handleTpkt(ByteBuffer buf, Link link) {
+        // Reserved
+        buf.skipBytes(1);
+
+        // Read TPKT length
+        int length = buf.readUnsignedShort();
+
+        if (!cap(buf, length, length, link, false))
+            // Wait for full packet to arrive
+            return;
+
+        int payloadLength = length - buf.cursor;
+
+        // Extract payload
+        ByteBuffer outBuf = buf.slice(buf.cursor, payloadLength, true);
+        buf.unref();
+
+        if (verbose) {
+            outBuf.putMetadata("source", this);
+        }
+
+        pushDataToPad(TPKT_PAD, outBuf);
+    }
+
+    private void handleCredSSP(ByteBuffer buf, Link link) {
+
+        if (verbose)
+            System.out.println("[" + this + "] INFO: CredSSP data received: " + buf + ".");
+
+        // Store header position: will parse whole header later in BER format parser
+        int headerPosition = buf.cursor - 1;
+
+        long payloadLength = buf.readBerLength();
+        if (payloadLength > 10 * 1024)
+            throw new RuntimeException("[" + this + "] ERROR: CredSSP packets seems to be too long: " + payloadLength + "bytes. Data: " + buf + ".");
+
+        // Length is the size of payload, so we need to append size of header
+        int headerLength = buf.cursor - headerPosition;
+        int packetLength = (int)payloadLength + headerLength;
+        if (!cap(buf, packetLength, packetLength, link, false))
+            // Wait for full packet to arrive
+            return;
+
+        // Extract payload (with header)
+        ByteBuffer outBuf = buf.slice(headerPosition, packetLength, true);
+        buf.unref();
+
+        if (verbose) {
+            outBuf.putMetadata("source", this);
+        }
+
+        pushDataToPad(CREDSSP_PAD, outBuf);
+    }
+
+    private void handleFastPath(ByteBuffer buf, Link link, int typeAndFlags) {
+        // Number of bytes in updateData field (including header (1+1 or 2
+        // bytes))
+        int length = buf.readVariableUnsignedShort();
+
+        if (!cap(buf, length, length, link, false))
+            // Wait for full packet to arrive
+            return;
+
+        int type = typeAndFlags & 0x3;
+        int securityFlags = (typeAndFlags >> 6) & 0x3;
+
+        // Assertions
+        {
+            if (type != PROTOCOL_FASTPATH)
+                throw new RuntimeException("Unknown protocol. Expected protocol: 0 (FastPath). Actual protocol: " + type + ", data: " + buf + ".");
+
+            switch (securityFlags) {
+            case FASTPATH_OUTPUT_SECURE_CHECKSUM:
+                // TODO
+                throw new RuntimeException("Secure checksum is not supported in FastPath packets.");
+            case FASTPATH_OUTPUT_ENCRYPTED:
+                // TODO
+                throw new RuntimeException("Encryption is not supported in FastPath packets.");
+            }
+        }
+
+        // TODO: optional FIPS information, when FIPS is selected
+        // TODO: optional data signature (checksum), when checksum or FIPS is
+        // selected
+
+        // Array of FastPath update fields
+        while (buf.cursor < buf.length) {
+
+            int updateHeader = buf.readUnsignedByte();
+
+            int size = buf.readUnsignedShortLE();
+
+            int updateCode = updateHeader & 0xf;
+            int fragmentation = (updateHeader >> 4) & 0x3;
+            int compression = (updateHeader >> 6) & 0x3;
+
+            if (verbose)
+                System.out.println("[" + this + "] INFO: FastPath update received. UpdateCode: " + updateCode + ", fragmentation: " + fragmentation + ", compression: "
+                        + compression + ", size: " + size + ".");
+
+            ByteBuffer data = buf.readBytes(size);
+            buf.putMetadata("fragmentation", fragmentation);
+            buf.putMetadata("compression", compression);
+
+            switch (updateCode) {
+
+            case FASTPATH_UPDATETYPE_ORDERS:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_ORDERS.");
+                pushDataToPad(ORDERS_PAD, data);
+                break;
+
+            case FASTPATH_UPDATETYPE_BITMAP:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_BITMAP.");
+                pushDataToPad(BITMAP_PAD, data);
+                break;
+
+            case FASTPATH_UPDATETYPE_PALETTE:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PALETTE.");
+                pushDataToPad(PALETTE_PAD, data);
+                break;
+
+            case FASTPATH_UPDATETYPE_SYNCHRONIZE:
+                // @see http://msdn.microsoft.com/en-us/library/cc240625.aspx
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_SYNCHRONIZE.");
+
+                data.unref();
+
+                if (size != 0)
+                    throw new RuntimeException("Size of FastPath synchronize packet must be 0. UpdateCode: " + updateCode + ", fragmentation: " + fragmentation
+                            + ", compression: " + compression + ", size: " + size + ", data: " + data + ".");
+                break;
+
+            case FASTPATH_UPDATETYPE_SURFCMDS:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_SURFCMDS.");
+
+                break;
+
+            case FASTPATH_UPDATETYPE_PTR_NULL:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PTR_NULL.");
+
+                break;
+
+            case FASTPATH_UPDATETYPE_PTR_DEFAULT:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PTR_DEFAULT.");
+
+                break;
+
+            case FASTPATH_UPDATETYPE_PTR_POSITION:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PTR_POSITION.");
+
+                break;
+
+            case FASTPATH_UPDATETYPE_COLOR:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_COLOR.");
+
+                break;
+
+            case FASTPATH_UPDATETYPE_CACHED:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_CACHED.");
+
+                break;
+
+            case FASTPATH_UPDATETYPE_POINTER:
+                if (verbose)
+                    System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_POINTER.");
+
+                break;
+
+            default:
+                throw new RuntimeException("Unknown FastPath update. UpdateCode: " + updateCode + ", fragmentation: " + fragmentation + ", compression: " + compression
+                        + ", size: " + size + ", data: " + data + ".");
+
+            }
+            buf.unref();
+
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerIOChannelRouter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerIOChannelRouter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerIOChannelRouter.java
new file mode 100755
index 0000000..dad3548
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerIOChannelRouter.java
@@ -0,0 +1,534 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package rdpclient.rdp;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.MockSink;
+import streamer.debug.MockSource;
+
+public class ServerIOChannelRouter extends BaseElement {
+
+    /**
+     * Demand Active PDU.
+     */
+    public static final int PDUTYPE_DEMANDACTIVEPDU = 0x1;
+
+    /**
+     * Confirm Active PDU.
+     */
+    public static final int PDUTYPE_CONFIRMACTIVEPDU = 0x3;
+
+    /**
+     * Deactivate All PDU.
+     */
+    public static final int PDUTYPE_DEACTIVATEALLPDU = 0x6;
+
+    /**
+     * Data PDU (actual type is revealed by the pduType2 field in the Share Data
+     * Header).
+     */
+    public static final int PDUTYPE_DATAPDU = 0x7;
+
+    /**
+     * Enhanced Security Server Redirection PDU.
+     */
+    public static final int PDUTYPE_SERVER_REDIR_PKT = 0xA;
+
+    protected RdpState state;
+
+    public ServerIOChannelRouter(String id, RdpState state) {
+        super(id);
+        this.state = state;
+    }
+
+    /**
+     * @see http://msdn.microsoft.com/en-us/library/cc240576.aspx
+     */
+    @Override
+    public void handleData(ByteBuffer buf, Link link) {
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        int length = buf.readUnsignedShortLE();
+        if (buf.length != length)
+        {
+            // It is ServerErrorAlert-ValidClient
+            // Ignore it
+            //throw new RuntimeException("[" + this + "] ERROR: Incorrect PDU length: " + length + ", data: " + buf + ".");
+        }
+
+        int type = buf.readUnsignedShortLE() & 0xf;
+
+        // int sourceId = buf.readUnsignedShortLE();
+        buf.skipBytes(2);
+
+        switch (type) {
+        case PDUTYPE_DEMANDACTIVEPDU:
+            pushDataToPad("demand_active", buf);
+            break;
+        case PDUTYPE_CONFIRMACTIVEPDU:
+            throw new RuntimeException("Unexpected client CONFIRM ACTIVE PDU. Data: " + buf + ".");
+        case PDUTYPE_DEACTIVATEALLPDU:
+            // pushDataToPad("deactivate_all", buf);
+            /* ignore */buf.unref();
+            break;
+        case PDUTYPE_DATAPDU:
+            handleDataPdu(buf);
+            break;
+        case PDUTYPE_SERVER_REDIR_PKT:
+            // pushDataToPad("server_redir", buf);
+            /* ignore */buf.unref();
+            break;
+        default:
+            throw new RuntimeException("[" + this + "] ERROR: Unknown PDU type: " + type + ", data: " + buf + ".");
+        }
+
+    }
+
+    /**
+     * Graphics Update PDU.
+     */
+    public static final int PDUTYPE2_UPDATE = 0x02;
+
+    /**
+     * Control PDU.
+     */
+    public static final int PDUTYPE2_CONTROL = 0x14;
+
+    /**
+     * Pointer Update PDU.
+     */
+    public static final int PDUTYPE2_POINTER = 0x1B;
+
+    /**
+     * Input Event PDU.
+     */
+    public static final int PDUTYPE2_INPUT = 0x1C;
+
+    /**
+     * Synchronize PDU.
+     */
+    public static final int PDUTYPE2_SYNCHRONIZE = 0x1F;
+
+    /**
+     * Refresh Rect PDU.
+     */
+    public static final int PDUTYPE2_REFRESH_RECT = 0x21;
+
+    /**
+     * Play Sound PDU.
+     */
+    public static final int PDUTYPE2_PLAY_SOUND = 0x22;
+
+    /**
+     * Suppress Output PDU.
+     */
+    public static final int PDUTYPE2_SUPPRESS_OUTPUT = 0x23;
+
+    /**
+     * Shutdown Request PDU.
+     */
+    public static final int PDUTYPE2_SHUTDOWN_REQUEST = 0x24;
+
+    /**
+     * Shutdown Request Denied PDU.
+     */
+    public static final int PDUTYPE2_SHUTDOWN_DENIED = 0x25;
+
+    /**
+     * Save Session Info PDU.
+     */
+    public static final int PDUTYPE2_SAVE_SESSION_INFO = 0x26;
+
+    /**
+     * Font List PDU.
+     */
+    public static final int PDUTYPE2_FONTLIST = 0x27;
+
+    /**
+     * Font Map PDU.
+     */
+    public static final int PDUTYPE2_FONTMAP = 0x28;
+
+    /**
+     * Set Keyboard Indicators PDU.
+     */
+    public static final int PDUTYPE2_SET_KEYBOARD_INDICATORS = 0x29;
+
+    /**
+     * Persistent Key List PDU.
+     */
+    public static final int PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST = 0x2B;
+
+    /**
+     * Bitmap Cache Error PDU.
+     */
+    public static final int PDUTYPE2_BITMAPCACHE_ERROR_PDU = 0x2C;
+
+    /**
+     * Set Keyboard IME Status PDU.
+     */
+    public static final int PDUTYPE2_SET_KEYBOARD_IME_STATUS = 0x2D;
+
+    /**
+     * Offscreen Bitmap Cache Error PDU.
+     */
+    public static final int PDUTYPE2_OFFSCRCACHE_ERROR_PDU = 0x2E;
+
+    /**
+     * Set Error Info PDU.
+     */
+    public static final int PDUTYPE2_SET_ERROR_INFO_PDU = 0x2F;
+
+    /**
+     * DrawNineGrid Cache Error PDU.
+     */
+    public static final int PDUTYPE2_DRAWNINEGRID_ERROR_PDU = 0x30;
+
+    /**
+     * GDI+ Error PDU.
+     */
+    public static final int PDUTYPE2_DRAWGDIPLUS_ERROR_PDU = 0x31;
+
+    /**
+     * Auto-Reconnect Status PDU.
+     */
+    public static final int PDUTYPE2_ARC_STATUS_PDU = 0x32;
+
+    /**
+     * Status Info PDU.
+     */
+    public static final int PDUTYPE2_STATUS_INFO_PDU = 0x36;
+
+    /**
+     * Monitor Layout PDU.
+     */
+    public static final int PDUTYPE2_MONITOR_LAYOUT_PDU = 0x37;
+
+    /**
+     * Indicates an Orders Update.
+     */
+    public static final int UPDATETYPE_ORDERS = 0x0000;
+
+    /**
+     * Indicates a Bitmap Graphics Update.
+     */
+    public static final int UPDATETYPE_BITMAP = 0x0001;
+
+    /**
+     * Indicates a Palette Update.
+     */
+    public static final int UPDATETYPE_PALETTE = 0x0002;
+
+    /**
+     * Indicates a Synchronize Update.
+     */
+    public static final int UPDATETYPE_SYNCHRONIZE = 0x0003;
+
+    /**
+     * @see http://msdn.microsoft.com/en-us/library/cc240577.aspx
+     */
+    protected void handleDataPdu(ByteBuffer buf) {
+
+        // (4 bytes): A 32-bit, unsigned integer. Share identifier for the packet.
+        long shareId = buf.readUnsignedIntLE();
+        if (shareId != state.serverShareId)
+            throw new RuntimeException("Unexpected share ID: " + shareId + ".");
+//    buf.skipBytes(4);
+
+        // Padding.
+        buf.skipBytes(1);
+
+        // (1 byte): An 8-bit, unsigned integer. The stream identifier for the
+        // packet.
+        // int streamId = buf.readUnsignedByte();
+        buf.skipBytes(1);
+
+        // (2 bytes): A 16-bit, unsigned integer. The uncompressed length of the
+        // packet in bytes.
+        int uncompressedLength = buf.readUnsignedShortLE();
+
+        // (1 byte): An 8-bit, unsigned integer. The type of Data PDU.
+        int type2 = buf.readUnsignedByte();
+
+        // (1 byte): An 8-bit, unsigned integer. The compression type and flags
+        // specifying the data following the Share Data Header
+        int compressedType = buf.readUnsignedByte();
+        if (compressedType != 0)
+            throw new RuntimeException("Compression of protocol packets is not supported. Data: " + buf + ".");
+
+        // (2 bytes): A 16-bit, unsigned integer. The compressed length of the
+        // packet in bytes.
+        int compressedLength = buf.readUnsignedShortLE();
+        if (compressedLength != 0)
+            throw new RuntimeException("Compression of protocol packets is not supported. Data: " + buf + ".");
+
+        ByteBuffer data = buf.readBytes(uncompressedLength - 18);
+        buf.unref();
+
+        switch (type2) {
+
+        case PDUTYPE2_UPDATE: {
+
+            // (2 bytes): A 16-bit, unsigned integer. Type of the graphics update.
+            int updateType = data.readUnsignedShortLE();
+            ByteBuffer payload = data.readBytes(data.length - data.cursor);
+            data.unref();
+
+            switch (updateType) {
+            case UPDATETYPE_ORDERS:
+                pushDataToPad("orders", payload);
+                break;
+            case UPDATETYPE_BITMAP:
+                pushDataToPad("bitmap", payload);
+                break;
+            case UPDATETYPE_PALETTE:
+                pushDataToPad("palette", payload);
+                break;
+            case UPDATETYPE_SYNCHRONIZE:
+                // Ignore
+                payload.unref();
+                break;
+            }
+
+            break;
+        }
+        case PDUTYPE2_CONTROL:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_CONTROL ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_POINTER:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_POINTER ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_INPUT:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_INPUT ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_SYNCHRONIZE:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SYNCHRONIZE ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_REFRESH_RECT:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_REFRESH_RECT ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_PLAY_SOUND:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_PLAY_SOUND ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_SUPPRESS_OUTPUT:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SUPPRESS_OUTPUT ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_SHUTDOWN_REQUEST:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SHUTDOWN_REQUEST ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_SHUTDOWN_DENIED:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SHUTDOWN_DENIED ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_SAVE_SESSION_INFO:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SAVE_SESSION_INFO ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_FONTLIST:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_FONTLIST ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_FONTMAP:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_FONTMAP ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_SET_KEYBOARD_INDICATORS:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SET_KEYBOARD_INDICATORS ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_BITMAPCACHE_ERROR_PDU:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_BITMAPCACHE_ERROR_PDU ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_SET_KEYBOARD_IME_STATUS:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SET_KEYBOARD_IME_STATUS ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_OFFSCRCACHE_ERROR_PDU:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_OFFSCRCACHE_ERROR_PDU ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_SET_ERROR_INFO_PDU:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_SET_ERROR_INFO_PDU ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_DRAWNINEGRID_ERROR_PDU:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_DRAWNINEGRID_ERROR_PDU ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_DRAWGDIPLUS_ERROR_PDU:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_DRAWGDIPLUS_ERROR_PDU ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_ARC_STATUS_PDU:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_ARC_STATUS_PDU ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_STATUS_INFO_PDU:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_STATUS_INFO_PDU ignored.");
+            // Ignore
+            data.unref();
+            break;
+        case PDUTYPE2_MONITOR_LAYOUT_PDU:
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Packet PDUTYPE2_MONITOR_LAYOUT_PDU ignored.");
+            // Ignore
+            data.unref();
+            break;
+
+        default:
+            throw new RuntimeException("Unknow data PDU type: " + type2 + ", data: " + buf + ".");
+        }
+    }
+
+    /**
+     * Example.
+     *
+     */
+    public static void main(String args[]) {
+        // System.setProperty("streamer.Link.debug", "true");
+        System.setProperty("streamer.Element.debug", "true");
+        // System.setProperty("streamer.Pipeline.debug", "true");
+
+        byte[] packet = new byte[] {
+                // TPKT
+                (byte)0x03, (byte)0x00, // TPKT Header: TPKT version = 3
+                (byte)0x00, (byte)0x1B, // TPKT length: 27 bytes
+
+                // X224
+                (byte)0x02, // X224 Length: 2 bytes
+                (byte)0xF0, // X224 Type: Data
+                (byte)0x80, // X224 EOT
+
+                // MCS
+                // Type: send data indication: 26 (0x1a, top 6 bits)
+                (byte)0x68, // ??
+
+                (byte)0x00, (byte)0x01, // User ID: 1002 (1001+1)
+                (byte)0x03, (byte)0xEB, // Channel ID: 1003
+                (byte)0x70, // Data priority: high, segmentation: begin|end
+                (byte)0x0D, // Payload length: 13 bytes
+
+                // Deactivate all PDU
+                (byte)0x0D, (byte)0x00, // Length: 13 bytes (LE)
+
+                // - PDUType: (0x16, LE)
+                // Type: (............0110) TS_PDUTYPE_DEACTIVATEALLPDU
+                // ProtocolVersion: (000000000001....) 1
+                (byte)0x16, (byte)0x00,
+
+                (byte)0xEA, (byte)0x03, // PDU source: 1002 (LE)
+                (byte)0xEA, (byte)0x03, (byte)0x01, (byte)0x00, // ShareID = 66538
+
+                (byte)0x01, (byte)0x00, // Length if source descriptor: 1 (LE)
+                (byte)0x00, // Source descriptor (should be set to 0): 0
+        };
+
+        MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
+        RdpState rdpState = new RdpState() {
+            {
+                serverShareId = 66538;
+            }
+        };
+        Element channel1003 = new ServerIOChannelRouter("channel_1003", rdpState);
+        Element mcs = new ServerMCSPDU("mcs");
+        Element tpkt = new ServerTpkt("tpkt");
+        Element x224 = new ServerX224DataPdu("x224");
+        Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {
+                // Deactivate all PDU
+                (byte)0x0D, (byte)0x00, // Length: 13 bytes (LE)
+
+                // - PDUType: 22 (0x16, LE)
+                // Type: (............0110) TS_PDUTYPE_DEACTIVATEALLPDU
+                // ProtocolVersion: (000000000001....) 1
+                (byte)0x16, (byte)0x00,
+
+                (byte)0xEA, (byte)0x03, // PDU source: 1002 (LE)
+                (byte)0xEA, (byte)0x03, (byte)0x01, (byte)0x00, // ShareID = 66538
+
+                (byte)0x01, (byte)0x00, // Length if source descriptor: 1 (LE)
+                (byte)0x00, // Source descriptor (should be set to 0): 0
+        }));
+
+        Pipeline pipeline = new PipelineImpl("test");
+        pipeline.add(source, tpkt, x224, mcs, channel1003, sink);
+        pipeline.link("source", "tpkt", "x224", "mcs >channel_1003", "channel_1003 >deactivate_all", "sink");
+        pipeline.runMainLoop("source", STDOUT, false, false);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerLicenseErrorPDUValidClient.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerLicenseErrorPDUValidClient.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerLicenseErrorPDUValidClient.java
new file mode 100755
index 0000000..22e8094
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerLicenseErrorPDUValidClient.java
@@ -0,0 +1,121 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package rdpclient.rdp;
+
+import streamer.ByteBuffer;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+
+public class ServerLicenseErrorPDUValidClient extends OneTimeSwitch {
+
+    public ServerLicenseErrorPDUValidClient(String id) {
+        super(id);
+    }
+
+    @Override
+    protected void handleOneTimeData(ByteBuffer buf, Link link) {
+        if (buf == null)
+            return;
+
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        // Ignore packet
+        buf.unref();
+        switchOff();
+    }
+
+    /* @formatter:off */
+//   * Server Error alert
+//
+//03 00 00 22 02 F0 80 68 00 01 03 EB 70 14 80 00 F1 BC FF 03 10 00 07 00 00 00 02 00 00 00 04 00 00 00
+//
+//
+// Frame: Number = 30, Captured Frame Length = 91, MediaType = DecryptedPayloadHeader
+//+ DecryptedPayloadHeader: FrameCount = 1, ErrorStatus = SUCCESS
+// TLSSSLData: Transport Layer Security (TLS) Payload Data
+//+ TLS: TLS Rec Layer-1 SSL Application Data
+// ISOTS: TPKTCount = 1
+//- TPKT: version: 3, Length: 34
+//    version: 3 (0x3)
+//    Reserved: 0 (0x0)
+//    PacketLength: 34 (0x22)
+//- X224: Data
+//    Length: 2 (0x2)
+//    Type: Data
+//    EOT: 128 (0x80)
+//- T125: Data Packet
+// - MCSHeader: Type=Send Data Indication, UserID=1002, ChannelID=1003
+//  - Type: Send Data Indication
+//    - RootIndex: 26
+//      Value: (011010..) 0x1a
+//  - UserID: 0x3ea
+//    - UserID: 0x3ea
+//    - ChannelId: 1002
+//     - Align: No Padding
+//        Padding2: (00......) 0x0
+//       Value: 1 (0x1)
+//  - Channel: 0x3eb
+//    - ChannelId: 1003
+//      Align: No Padding
+//      Value: 1003 (0x3EB)
+//  - DataPriority: high
+//    - DataPriority: high
+//    - RootIndex: 1
+//       Value: (01......) 0x1
+//  - Segmentation: Begin End
+//     Begin: (1.......) Begin
+//     End:   (.1......) End
+//  - Length: 20
+//    - Align: No Padding
+//      Padding4: (0000....) 0x0
+//     Length: 20
+//    RDP: RDPBCGR
+//- RDPBCGR: RDPELE
+// - SecurityHeader: License Packet
+//  - Flags: 128 (0x80)
+//     SecurityExchange:        (...............0) Not Security Exchange PDU
+//     Reserved1:               (.............00.) Reserved
+//     Encrypted:               (............0...) Not Encrypted packet
+//     ResetSeqNumber:          (...........0....) MUST be ignored.
+//     IgnoreSeqNumber:         (..........0.....) MUST be ignored.
+//     InfoPacket:              (.........0......) Not Client Info PDU
+//     LicensePacket:           (........1.......) License Packet
+//     Reserved2:               (.......0........) Reserved
+//     LicensePacketEncryption: (......0.........) Not License Packet Encryption
+//     ServerRedirectionPacket: (.....0..........) Not Standard Security Server Redirection PDU
+//     ImprovedChecksumForMACG: (....0...........) Not Improved Checksum for MAC Generation
+//     Reserved3:               (.000............) Reserved
+//     FlagsHiValid:            (0...............) FlagsHi should be ignored
+//    FlagsHi: Should be ignored
+//- RDPELE: GM_ERROR_ALERT
+// - TsPreambleHeader: Type = GM_ERROR_ALERT
+//    MsgType: GM_ERROR_ALERT
+//  - Flags: 3 (0x3)
+//     LicenseProtocolVersionMask: (....0011) RDP 5.0, 5.1, 5.2, 6.0, 6.1, and 7.0
+//     Unused:                     (.000....)
+//     ExtendedErrorMSGsupported:  (0.......) that extended error information using the License Error Message is NOT supported.
+//    MsgSize: 16 (0x10)
+// - TsLicenseErrorMessage: ErrorCode = STATUS_VALID_CLIENT
+//    ErrorCode: STATUS_VALID_CLIENT
+//    StateTransition: ST_NO_TRANSITION
+//  - LiceseBinaryBlob: Type = Not Available
+//     RandomData: This value should be ignored
+//     BlobLen: 0 (0x0)
+//
+
+}