cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From devd...@apache.org
Subject [5/9] Remote Desktop Protocol(RDP) client that is suitable for including in the console VM. The client renders RDP to a window created by Java. It is important for Hyper-V support, because Hyper-V provides access to the consoles of VMs that it is running
Date Fri, 08 Nov 2013 08:16:08 GMT
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/RdpState.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/RdpState.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/RdpState.java
new file mode 100644
index 0000000..c85972d
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/RdpState.java
@@ -0,0 +1,33 @@
+// 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;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class RdpState {
+  
+  public long serverShareId;
+  public int serverUserChannelId;
+
+  public Set<Integer> channels=new HashSet<Integer>();
+  
+  public void channelJoined(int actualChannel) {
+    channels.add(actualChannel);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerBitmapUpdate.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerBitmapUpdate.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerBitmapUpdate.java
new file mode 100644
index 0000000..0e5b79a
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerBitmapUpdate.java
@@ -0,0 +1,201 @@
+// 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;
+
+import common.BitmapOrder;
+import common.BitmapRectangle;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.FakeSink;
+import streamer.Link;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+
+/**
+ * @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(0);
+    data.setOrder(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/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerChannel1003Router.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerChannel1003Router.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerChannel1003Router.java
new file mode 100644
index 0000000..fdad522
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerChannel1003Router.java
@@ -0,0 +1,530 @@
+// 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;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.MockSink;
+import streamer.MockSource;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+
+public class ServerChannel1003Router 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 ServerChannel1003Router(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 data2 = data.readBytes(data.length - data.cursor);
+      data.unref();
+
+      switch (updateType) {
+      case UPDATETYPE_ORDERS:
+        pushDataToPad("orders", data2);
+        break;
+      case UPDATETYPE_BITMAP:
+        pushDataToPad("bitmap", data2);
+        break;
+      case UPDATETYPE_PALETTE:
+        pushDataToPad("palette", data2);
+        break;
+      case UPDATETYPE_SYNCHRONIZE:
+        // Ignore
+        data2.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 ServerChannel1003Router("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/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerControlPDUCooperate.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerControlPDUCooperate.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerControlPDUCooperate.java
new file mode 100644
index 0000000..f2d3d36
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/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;
+
+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/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerControlPDUGrantedControl.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerControlPDUGrantedControl.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerControlPDUGrantedControl.java
new file mode 100644
index 0000000..e050e8a
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/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;
+
+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/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerDemandActivePDU.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerDemandActivePDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerDemandActivePDU.java
new file mode 100644
index 0000000..9ce87d3
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerDemandActivePDU.java
@@ -0,0 +1,661 @@
+// 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;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.FakeSink;
+import streamer.Link;
+import streamer.MockSource;
+import streamer.Order;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+
+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/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerFastPath.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerFastPath.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerFastPath.java
new file mode 100644
index 0000000..fbec1ce
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerFastPath.java
@@ -0,0 +1,259 @@
+// 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;
+
+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 = 3;
+  
+  /**
+   * Fast path protocol version (first two bits of first byte).
+   */
+  public static final int PROTOCOL_FASTPATH = 0;
+  
+  
+  /**
+   * TPKT packets will be pushed to that pad.
+   */
+  public static final String TPKT_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();
+
+    if (typeAndFlags == PROTOCOL_TPKT) {
+      //
+      // TPKT
+      //
+
+      // 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;
+
+      pushDataToPad(TPKT_PAD, buf);
+
+      // TPKT is handled
+      return;
+    }
+
+    //
+    // FastPath
+    //
+    // Number of bytes in updateData field (including header (1+1 or 2
+    // bytes))
+    int length = buf.readVariableUnsignedShort();
+
+    // Length is the size of payload, so we need to calculate from cursor
+    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/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerLicenseErrorPDUValidClient.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerLicenseErrorPDUValidClient.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerLicenseErrorPDUValidClient.java
new file mode 100644
index 0000000..194ffe6
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/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;
+
+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)
+//
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerMCSAttachUserConfirmPDU.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerMCSAttachUserConfirmPDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerMCSAttachUserConfirmPDU.java
new file mode 100644
index 0000000..8373b83
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/ServerMCSAttachUserConfirmPDU.java
@@ -0,0 +1,133 @@
+// 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;
+
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.MockSink;
+import streamer.MockSource;
+import streamer.OneTimeSwitch;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+
+/**
+ * Server response to MCS Attach User request.
+ * 
+ * Once the User Channel ID has been extracted, the client MUST send an MCS
+ * Channel Join Request PDU for the user channel.
+ * 
+ * @see http://msdn.microsoft.com/en-us/library/cc240685.aspx
+ */
+public class ServerMCSAttachUserConfirmPDU extends OneTimeSwitch {
+
+  public static final int MCS_ATTACH_USER_CONFIRM_PDU = 0xb;
+
+  public static final int INITIATOR_PRESENT = 0x2;
+
+  protected RdpState state;
+
+  public ServerMCSAttachUserConfirmPDU(String id, RdpState state) {
+    super(id);
+    this.state = state;
+  }
+
+  @Override
+  protected void handleOneTimeData(ByteBuffer buf, Link link) {
+    if (verbose)
+      System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+    int typeAndFlags = buf.readUnsignedByte();
+    int type = typeAndFlags >> 2;
+    int flags = typeAndFlags & 0x3;
+    
+    if (type != MCS_ATTACH_USER_CONFIRM_PDU)
+      throw new RuntimeException("["+this+"] ERROR: Incorrect type of MCS AttachUserConfirm PDU. Expected value: 11, actual value: " + type + ", data: " + buf + ".");
+
+    if (flags != INITIATOR_PRESENT)
+      throw new RuntimeException("Initator field is not present in MCS AttachUserConfirm PDU. Data: " + buf + ".");
+
+    int rtSuccess = buf.readUnsignedByte() >> 4;
+    if (rtSuccess != 0)
+      throw new RuntimeException("["+this+"] ERROR: Cannot attach user: request failed. Error code: " + rtSuccess + ", data: " + buf + ".");
+
+    // If the initiator field is present, the client stores the value of the
+    // initiator in the User Channel ID store , because the initiator specifies
+    // the User Channel ID.
+    state.serverUserChannelId = buf.readUnsignedShort() + 1001;
+
+    buf.unref();
+
+    // Next: client MCS Channel Join Request PDU (s)
+    switchOff();
+  }
+
+  /**
+   * Example.
+   */
+  /**
+   * Example.
+   * 
+   * @see http://msdn.microsoft.com/en-us/library/cc240842.aspx
+   * @see http://msdn.microsoft.com/en-us/library/cc240500.aspx
+   */
+  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[] { (byte) 0x2E, // MCS user confirm (001011..,
+                                              // 0xb), InitiatorPresent: 1
+                                              // (......01, 0x1)
+        (byte) 0x00, // RT successfull (0000...., 0x0)
+        // Initiator: 1001+3 = 1004
+        (byte) 0x00, (byte) 0x03, };
+
+    RdpState rdpState = new RdpState();
+    MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet, new byte[] { 1, 2, 3 }));
+    Element atachUserConfirm = new ServerMCSAttachUserConfirmPDU("attach_user_confirm", rdpState);
+    Element sink = new MockSink("sink");
+    Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] { 1, 2, 3 }));
+
+    Pipeline pipeline = new PipelineImpl("test");
+    pipeline.add(source, atachUserConfirm, sink, mainSink);
+    pipeline.link("source", "attach_user_confirm", "mainSink");
+    pipeline.link("attach_user_confirm >" + OTOUT, "sink");
+    pipeline.runMainLoop("source", STDOUT, false, false);
+
+    if (rdpState.serverUserChannelId != 1004)
+      System.err.println("Incorrect user channel ID. Expected value: 1004, actual value: " + rdpState.serverUserChannelId + ".");
+  }
+
+}
+
+/*
+ * 03 00 00 0B 02 F0 80 2E 00 00 03.
+ * 
+ * Frame: Number = 18, Captured Frame Length = 68, 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: 11 version: 3 (0x3) Reserved: 0 (0x0) PacketLength: 11 (0xB) - X224:
+ * Data Length: 2 (0x2) Type: Data EOT: 128 (0x80) - T125: Attach User Confirm,
+ * Result = rt-successful, Indicator = 0x3ec - MCSHeader: Type=Attach User
+ * Confirm - Type: Attach User Confirm - RootIndex: 11 Value: (001011..) 0xb -
+ * MCSAttachUserConfirm: Result = rt-successful, Indicator = 0x3ec
+ * InitiatorPresent: 1 (0x1) - Result: rt-successful - Result: rt-successful -
+ * RootIndex: 0 Value: (0000....) 0x0 - Initiator: 0x3ec - UserID: 0x3ec -
+ * ChannelId: 1004 - Align: No Padding Padding5: (00000...) 0x0 Value: 3 (0x3)
+ */


Mime
View raw message