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)
+//
+
+}