You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by de...@apache.org on 2013/12/23 10:13:01 UTC

[07/22] CLOUDSTACK-5344: Update to allow rdp console to access hyper-v vm virtual framebuffer.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSAttachUserConfirmPDU.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSAttachUserConfirmPDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSAttachUserConfirmPDU.java
new file mode 100755
index 0000000..09b4129
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSAttachUserConfirmPDU.java
@@ -0,0 +1,116 @@
+// 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.Element;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.MockSink;
+import streamer.debug.MockSource;
+
+/**
+ * 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 + ".");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSChannelJoinConfirmPDU.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSChannelJoinConfirmPDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSChannelJoinConfirmPDU.java
new file mode 100755
index 0000000..1aa4a86
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSChannelJoinConfirmPDU.java
@@ -0,0 +1,89 @@
+// 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 ServerMCSChannelJoinConfirmPDU extends OneTimeSwitch {
+
+    protected int channel;
+
+    public ServerMCSChannelJoinConfirmPDU(String id, int channel) {
+        super(id);
+        this.channel = channel;
+    }
+
+    @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();
+    }
+
+}
+
+/*
+ * 03 00 00 0F 02 F0 80 3E 00 00 03 03 EC 03 EC 
+
+  Frame: Number = 22, Captured Frame Length = 72, 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: 15
+    version: 3 (0x3)
+    Reserved: 0 (0x0)
+    PacketLength: 15 (0xF)
+- X224: Data
+    Length: 2 (0x2)
+    Type: Data
+    EOT: 128 (0x80)
+- T125: Channel Join Confirm, ChannelId = 1004, Result = rt-successful
+  - MCSHeader: Type=Channel Join Confirm
+   - Type: Channel Join Confirm
+    - RootIndex: 15
+       Value: (001111..) 0xf
+  - MCSChannelJoinConfirm: ChannelId = 1004, Result = rt-successful
+     ChannelIdPresent: 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)
+   - Requested: 0x3ec
+    - ChannelId: 1004
+       Align: No Padding
+       Value: 1004 (0x3EC)
+   - ChannelId: 0x3ec
+    - ChannelId: 1004
+       Align: No Padding
+       Value: 1004 (0x3EC)
+ 
+ */

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSConnectResponse.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSConnectResponse.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSConnectResponse.java
new file mode 100755
index 0000000..686c939
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSConnectResponse.java
@@ -0,0 +1,283 @@
+// 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;
+
+/**
+ * Once the basic server settings data blocks have been processed successfully, the client MUST send the MCS Attach User Request PDU to the server.
+ * 
+ * @see http://msdn.microsoft.com/en-us/library/cc240682.aspx
+ */
+public class ServerMCSConnectResponse extends OneTimeSwitch {
+
+    public ServerMCSConnectResponse(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 64 02 F0 80 7F 66 5A 0A 01 00 02 01 00 30 1A 02 01 22 02 01 03 02 01 00 02 01 01 02 01 00 02 01 01 02 03 00 FF F8 02 01 02 04 36 00 05 00 14 7C 00 01 2A 14 76 0A 01 01 00 01 C0 00 4D 63 44 6E 20 01 0C 0C 00 04 00 08 00 01 00 00 00 03 0C 08 00 EB 03 00 00 02 0C 0C 00 00 00 00 00 00 00 00 00 
+
+  Frame: Number = 12, Captured Frame Length = 157, 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: 100
+    version: 3 (0x3)
+    Reserved: 0 (0x0)
+    PacketLength: 100 (0x64)
+- X224: Data
+    Length: 2 (0x2)
+    Type: Data
+    EOT: 128 (0x80)
+- T125: MCSConnect Response
+  - MCSConnectResponse: Result = rt-successful
+   - ConnectResponseHeader: 
+    - AsnId: Application Constructed Tag (102)
+     - HighTag: 
+        Class:     (01......) Application (1)
+        Type:      (..1.....) Constructed
+        TagNumber: (...11111)
+        TagValueEnd: 102 (0x66)
+    - AsnLen: Length = 90, LengthOfLength = 0
+       Length: 90 bytes, LengthOfLength = 0
+   - Result: rt-successful
+    - Value: 0
+     - AsnIntegerHeader: 
+      - AsnId: Enumerated type (Universal 10)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...01010) 10
+      - AsnLen: Length = 1, LengthOfLength = 0
+         Length: 1 bytes, LengthOfLength = 0
+       AsnInt: 0 (0x0)
+   - CalledConnectId: 0
+    - AsnIntegerHeader: 
+     - AsnId: Integer type (Universal 2)
+      - LowTag: 
+         Class:    (00......) Universal (0)
+         Type:     (..0.....) Primitive
+         TagValue: (...00010) 2
+     - AsnLen: Length = 1, LengthOfLength = 0
+        Length: 1 bytes, LengthOfLength = 0
+      AsnInt: 0 (0x0)
+   - DomainParameters: Length = 26, LengthOfLength = 0
+    - DomainParametersHeader: 0x1
+     - AsnId: Sequence and SequenceOf types (Universal 16)
+      - LowTag: 
+         Class:    (00......) Universal (0)
+         Type:     (..1.....) Constructed
+         TagValue: (...10000) 16
+     - AsnLen: Length = 26, LengthOfLength = 0
+        Length: 26 bytes, LengthOfLength = 0
+    - ChannelIds: 34
+     - AsnIntegerHeader: 
+      - AsnId: Integer type (Universal 2)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...00010) 2
+      - AsnLen: Length = 1, LengthOfLength = 0
+         Length: 1 bytes, LengthOfLength = 0
+       AsnInt: 34 (0x22)
+    - UserIDs: 3
+     - AsnIntegerHeader: 
+      - AsnId: Integer type (Universal 2)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...00010) 2
+      - AsnLen: Length = 1, LengthOfLength = 0
+         Length: 1 bytes, LengthOfLength = 0
+       AsnInt: 3 (0x3)
+    - TokenIds: 0
+     - AsnIntegerHeader: 
+      - AsnId: Integer type (Universal 2)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...00010) 2
+      - AsnLen: Length = 1, LengthOfLength = 0
+         Length: 1 bytes, LengthOfLength = 0
+       AsnInt: 0 (0x0)
+    - NumPriorities: 1
+     - AsnIntegerHeader: 
+      - AsnId: Integer type (Universal 2)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...00010) 2
+      - AsnLen: Length = 1, LengthOfLength = 0
+         Length: 1 bytes, LengthOfLength = 0
+       AsnInt: 1 (0x1)
+    - MinThroughput: 0
+     - AsnIntegerHeader: 
+      - AsnId: Integer type (Universal 2)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...00010) 2
+      - AsnLen: Length = 1, LengthOfLength = 0
+         Length: 1 bytes, LengthOfLength = 0
+       AsnInt: 0 (0x0)
+    - Height: 1
+     - AsnIntegerHeader: 
+      - AsnId: Integer type (Universal 2)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...00010) 2
+      - AsnLen: Length = 1, LengthOfLength = 0
+         Length: 1 bytes, LengthOfLength = 0
+       AsnInt: 1 (0x1)
+    - MCSPDUsize: 65528
+     - AsnIntegerHeader: 
+      - AsnId: Integer type (Universal 2)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...00010) 2
+      - AsnLen: Length = 3, LengthOfLength = 0
+         Length: 3 bytes, LengthOfLength = 0
+       AsnInt: 65528 (0xFFF8)
+    - protocolVersion: 2
+     - AsnIntegerHeader: 
+      - AsnId: Integer type (Universal 2)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...00010) 2
+      - AsnLen: Length = 1, LengthOfLength = 0
+         Length: 1 bytes, LengthOfLength = 0
+       AsnInt: 2 (0x2)
+   - UserData: Identifier = Generic Conference Contro (0.0.20.124.0.1)
+    - UserDataHeader: 
+     - AsnId: OctetString type (Universal 4)
+      - LowTag: 
+         Class:    (00......) Universal (0)
+         Type:     (..0.....) Primitive
+         TagValue: (...00100) 4
+     - AsnLen: Length = 54, LengthOfLength = 0
+        Length: 54 bytes, LengthOfLength = 0
+    - AsnBerObjectIdentifier: Generic Conference Control (0.0.20.124.0.1)
+     - AsnObjectIdentifierHeader: 
+      - AsnId: Reserved for use by the encoding rules (Universal 0)
+       - LowTag: 
+          Class:    (00......) Universal (0)
+          Type:     (..0.....) Primitive
+          TagValue: (...00000) 0
+      - AsnLen: Length = 5, LengthOfLength = 0
+         Length: 5 bytes, LengthOfLength = 0
+       First: 0 (0x0)
+       Final: 20 (0x14)
+       Final: 124 (0x7C)
+       Final: 0 (0x0)
+       Final: 1 (0x1)
+    - ConnectPDULength: 42
+       Align: No Padding
+       Length: 42
+    - ConnectGCCPDU: conferenceCreateResponse
+       ExtensionBit: 0 (0x0)
+     - ChoiceValue: conferenceCreateResponse
+        Value: (001.....) 0x1
+     - conferenceCreateResponse: 
+        ExtensionBit: 0 (0x0)
+        userDataPresent: 1 (0x1)
+      - nodeID: 0x79f3
+       - UserID: 31219
+        - Align: No Padding
+           Padding2: (00......) 0x0
+          Value: 30218 (0x760A)
+      - tag: 1 (0x1)
+       - Length: 1
+          Align: No Padding
+          Length: 1
+         Value: 1 (0x1)
+      - result: success
+         ExtensionBit: 0 (0x0)
+       - RootIndex: 0
+          Value: (000.....) 0x0
+      - userData: 
+       - Size: 1
+        - Align: No Padding
+           Padding4: (0000....) 0x0
+          Length: 1
+       - UserData: 0x4d63446e
+          valuePresent: 1 (0x1)
+        - key: h221NonStandard
+         - ChoiceValue: h221NonStandard
+            Value: (1.......) 0x1
+         - h221NonStandard: 
+          - H221NonStandardIdentifier: length: 4
+           - ConstrainedLength: 4
+              Value: (00000000) 0x0
+           - Align: No Padding
+              Padding6: (000000..) 0x0
+             Value: Binary Large Object (4 Bytes)
+        - ServerMcsConnectResponsePdu: 
+         - RDPGCCUserDataResponseLength: 32
+            Align: No Padding
+            Length: 32
+         - TsUd: SC_CORE
+          - TsUdHeader: Type = SC_CORE, Length = 12
+             Type: SC_CORE
+             Length: 12 (0xC)
+          - TsUdScCore: 
+             Version: RDP 5.0, 5.1, 5.2, 6.0, 6.1, and 7.0 
+             ClientRequestedProtocols: TLS 1.0
+         - TsUd: SC_NET
+          - TsUdHeader: Type = SC_NET, Length = 8
+             Type: SC_NET
+             Length: 8 (0x8)
+          - TsUdScNet: 
+             MCSChannelID: 1003 (0x3EB)
+             ChannelCount: 0 (0x0)
+             Pad: 0 Bytes
+         - TsUd: SC_SECURITY
+          - TsUdHeader: Type = SC_SECURITY, Length = 12
+             Type: SC_SECURITY
+             Length: 12 (0xC)
+          - TsUdSCSec1: 
+           - EncryptionMethod: 
+              Support40Bit:  (...............................0) Not Support 
+              Support128Bit: (..............................0.) Not Support 128-bit
+              Reserved1:     (.............................0..)
+              Support56Bit:  (............................0...) Not Support 56-bit
+              SupportFIPS:   (...........................0....) Not Support FIPS Compliant
+              Reserved2:     (000000000000000000000000000.....)
+             EncryptionLevel: TS_ENCRYPTION_NONE
+ */

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSPDU.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSPDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSPDU.java
new file mode 100755
index 0000000..badea27
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerMCSPDU.java
@@ -0,0 +1,149 @@
+// 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 ServerMCSPDU extends BaseElement {
+
+    public ServerMCSPDU(String id) {
+        super(id);
+    }
+
+    @Override
+    public void handleData(ByteBuffer buf, Link link) {
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        byte headerByte = buf.readSignedByte();
+        int type = headerByte >> 2;
+
+        switch (type) {
+        // Expected type: send data indication: 26 (0x1a, top 6 bits, or 0x68)
+        case 0x1a: {
+            // int userId = buf.readUnsignedShort() + 1001; // User ID: 1002 (1001+1)
+            buf.skipBytes(2); // Ignore user ID
+
+            int channelId = buf.readUnsignedShort(); // Channel ID: 1003
+
+            int flags = buf.readSignedByte();
+            if ((flags & 0x30) != 0x30)
+                throw new RuntimeException("Fragmented MCS packets are not supported.");
+
+            int payloadLength = buf.readVariableUnsignedShort();
+
+            ByteBuffer data = buf.readBytes(payloadLength);
+
+            buf.unref();
+
+            pushDataToPad("channel_" + channelId, data);
+            break;
+        }
+
+        case 0x8: {
+            // Disconnection sequence.
+            buf.unref();
+            break;
+        }
+
+        default:
+            throw new RuntimeException("Unsupported MCS packet type: " + type + "(" + headerByte + "), 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: 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
+        };
+
+        MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
+        Element mcs = new ServerMCSPDU("mcs") {
+            {
+                verbose = true;
+            }
+        };
+        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, sink);
+        pipeline.link("source", "tpkt", "x224", "mcs >channel_1003", "sink");
+        pipeline.runMainLoop("source", STDOUT, false, false);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerPaletteUpdate.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerPaletteUpdate.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerPaletteUpdate.java
new file mode 100755
index 0000000..0beca2f
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerPaletteUpdate.java
@@ -0,0 +1,78 @@
+// 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 java.awt.image.IndexColorModel;
+
+import common.ScreenDescription;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc240623.aspx
+ */
+public class ServerPaletteUpdate extends BaseElement {
+
+    public static final int UPDATETYPE_PALETTE = 0x0002;
+    protected ScreenDescription screen;
+
+    public ServerPaletteUpdate(String id, ScreenDescription screen) {
+        super(id);
+        this.screen = screen;
+    }
+
+    @Override
+    public void handleData(ByteBuffer buf, Link link) {
+
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        // (2 bytes): A 16-bit, unsigned integer. The update type. This field MUST
+        // be set to UPDATETYPE_PALETTE (0x0002).
+        int updateType = buf.readUnsignedShortLE();
+        if (updateType != UPDATETYPE_PALETTE)
+            throw new RuntimeException("Unexpected update type. Expected type: UPDATETYPE_PALETTE (0x0002), actual value: " + updateType + ", data: " + buf + ".");
+
+        // pad2Octets (2 bytes): A 16-bit, unsigned integer. Padding. Values in this
+        // field MUST be ignored.
+        buf.skipBytes(2);
+
+        // (4 bytes): A 32-bit, unsigned integer. The number of RGB triplets in the
+        // paletteData field. This field MUST be set to 256 (the number of entries
+        // in an 8 bpp palette).
+        int numberColors = (int)buf.readUnsignedIntLE();
+        if (numberColors != 256)
+            throw new RuntimeException("Unexpected value for number of color field in server Palette Update packet. Expected value: 256 colors, actual value: "
+                    + numberColors + ", data: " + buf + ".");
+
+        // (variable): An array of palette entries in RGB triplet format packed on
+        // byte boundaries. The number of triplet entries is given by the
+        // numberColors field.
+        ByteBuffer paletteEntries = buf.readBytes(numberColors * 3);
+
+        // In the case of a Palette Update, the client MUST update the global
+        // palette on all drawing surfaces
+        screen.colorMap = new IndexColorModel(8, numberColors, paletteEntries.data, paletteEntries.offset, false);
+
+        /* DEBUG */buf.assertThatBufferIsFullyRead();
+
+        buf.unref();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerSynchronizePDU.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerSynchronizePDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerSynchronizePDU.java
new file mode 100755
index 0000000..b83f474
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerSynchronizePDU.java
@@ -0,0 +1,115 @@
+// 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 ServerSynchronizePDU extends OneTimeSwitch {
+
+    public ServerSynchronizePDU(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 24 02 F0 80 68 00 01 03 EB 70 16 16 00 17 00 EA 03 EA 03 01 00 08 00 16 00 1F 00 00 00 01 00 86 A4 
+
+  Frame: Number = 36, Captured Frame Length = 93, 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: 36
+    version: 3 (0x3)
+    Reserved: 0 (0x0)
+    PacketLength: 36 (0x24)
+- 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: 22
+    - Align: No Padding
+       Padding4: (0000....) 0x0
+      Length: 22
+    RDP: RDPBCGR
+- RDPBCGR: SynchronizePDU
+  - SlowPathPacket: SynchronizePDU 
+   - SlowPath: Type = TS_PDUTYPE_DATAPDU
+    - TsShareControlHeader: Type = TS_PDUTYPE_DATAPDU
+       TotalLength: 22 (0x16)
+     - PDUType: 23 (0x17)
+        Type:            (............0111) TS_PDUTYPE_DATAPDU
+        ProtocolVersion: (000000000001....) 1
+       PDUSource: 1002 (0x3EA)
+    - SlowPathIoPacket: 0x0
+     - ShareDataHeader: TS_PDUTYPE2_SYNCHRONIZE
+        ShareID: 66538 (0x103EA)
+        Pad1: 8 (0x8)
+        StreamID: STREAM_UNDEFINED
+        UncompressedLength: 22 (0x16)
+        PDUType2: TS_PDUTYPE2_SYNCHRONIZE
+      - 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)
+     - TsSynchronizePDU: 0x1
+        MessageType: 0x1, MUST be set to SYNCMSGTYPE_SYNC (1)
+        TargetUser: 42118 (0xA486)
+ */

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerTpkt.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerTpkt.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerTpkt.java
new file mode 100755
index 0000000..d9662d2
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerTpkt.java
@@ -0,0 +1,70 @@
+// 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;
+
+public class ServerTpkt extends BaseElement {
+
+    /**
+     * TPKT protocol version (first byte).
+     */
+    public static final int PROTOCOL_TPKT = 3;
+
+    public ServerTpkt(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 + ".");
+
+        // We need at least 4 bytes to get packet length
+        if (!cap(buf, 4, UNLIMITED, link, false))
+            return;
+
+        int version = buf.readUnsignedByte();
+        if (version != PROTOCOL_TPKT)
+            throw new RuntimeException("Unexpected data in TPKT header. Expected TPKT version: 0x03,  actual value: " + buf + ".");
+
+        buf.skipBytes(1); // Reserved byte
+
+        // Length of whole packet, including header
+        int length = buf.readUnsignedShort();
+        if (!cap(buf, length, length, link, false))
+            return;
+
+        int payloadLength = length - buf.cursor;
+
+        // Extract payload
+        ByteBuffer outBuf = buf.slice(buf.cursor, payloadLength, true);
+        buf.unref();
+
+        if (verbose) {
+            outBuf.putMetadata("source", this);
+        }
+
+        pushDataToAllOuts(outBuf);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerX224ConnectionConfirmPDU.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerX224ConnectionConfirmPDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerX224ConnectionConfirmPDU.java
new file mode 100755
index 0000000..d024063
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerX224ConnectionConfirmPDU.java
@@ -0,0 +1,234 @@
+// 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.Element;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.MockSink;
+import streamer.debug.MockSource;
+
+/**
+ * Once the External Security Protocol handshake has run to completion, the
+ * client MUST continue with the connection sequence by sending the MCS Connect
+ * Initial PDU to the server over the newly established secure channel.
+ * 
+ * 
+ * @see http://msdn.microsoft.com/en-us/library/cc240663.aspx
+ */
+public class ServerX224ConnectionConfirmPDU extends OneTimeSwitch {
+
+    public static final int X224_TPDU_CONNECTION_REQUEST = 0xe0;
+    public static final int X224_TPDU_CONNECTION_CONFIRM = 0xd0;
+    public static final int X224_TPDU_DISCONNECTION_REQUEST = 0x80;
+    public static final int X224_TPDU_DISCONNECTION_CONFIRM = 0xc0;
+    public static final int X224_TPDU_EXPEDITED_DATA = 0x10;
+    public static final int X224_TPDU_DATA_ACKNOWLEDGE = 0x61;
+    public static final int X224_TPDU_EXPEDITET_ACKNOWLEDGE = 0x40;
+    public static final int X224_TPDU_REJECT = 0x51;
+    public static final int X224_TPDU_ERROR = 0x70;
+    public static final int X224_TPDU_PROTOCOL_IDENTIFIER = 0x01;
+
+    /**
+     * The server requires that the client support Enhanced RDP Security with
+     * either TLS 1.0, 1.1 or 1.2 or CredSSP. If only CredSSP was requested then
+     * the server only supports TLS.
+     */
+    public static final int SSL_REQUIRED_BY_SERVER = 0x00000001;
+
+    /**
+     * The server is configured to only use Standard RDP Security mechanisms and
+     * does not support any External Security Protocols.
+     */
+    public static final int SSL_NOT_ALLOWED_BY_SERVER = 0x00000002;
+
+    /**
+     * The server does not possess a valid authentication certificate and cannot
+     * initialize the External Security Protocol Provider.
+     */
+    public static final int SSL_CERT_NOT_ON_SERVER = 0x00000003;
+
+    /**
+     * The list of requested security protocols is not consistent with the current
+     * security protocol in effect. This error is only possible when the Direct
+     * Approach is used and an External Security Protocolis already being used.
+     */
+    public static final int INCONSISTENT_FLAGS = 0x00000004;
+
+    /**
+     * The server requires that the client support Enhanced RDP Security with
+     * CredSSP.
+     */
+    public static final int HYBRID_REQUIRED_BY_SERVER = 0x00000005;
+
+    /**
+     * The server requires that the client support Enhanced RDP Security with TLS
+     * 1.0, 1.1 or 1.2 and certificate-based client authentication.
+     */
+    public static final int SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006;
+
+    public ServerX224ConnectionConfirmPDU(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 + ".");
+
+        int x224Length = buf.readVariableSignedIntLE();
+
+        int x224Type = buf.readUnsignedByte();
+        if (x224Type != X224_TPDU_CONNECTION_CONFIRM)
+            throw new RuntimeException("Unexpected type of packet. Expected type: " + X224_TPDU_CONNECTION_CONFIRM + " (CONNECTION CONFIRM), actual type: "
+                    + x224Type + ", length: " + x224Length + ", buf: " + buf + ".");
+
+        // Ignore destination reference, because client side has only one node
+        buf.skipBytes(2);
+
+        // Source reference
+        // int srcRef = buf.readUnsignedShort();
+        buf.skipBytes(2);
+
+        // Ignore class and options
+        buf.skipBytes(1);
+
+        // RDP_NEG_RSP::type (TYPE_RDP_NEG_RSP)
+        int negType = buf.readUnsignedByte();
+
+        // RDP_NEG_RSP::flags (0)
+        buf.skipBytes(1); // Ignore: always 0
+
+        // RDP_NEG_RSP::length (always 8 bytes)
+        int length = buf.readUnsignedShortLE();
+
+        if (length != 8)
+            throw new RuntimeException("Unexpected length of buffer. Expected value: 8, actual value: " + length + ", RDP NEG buf: " + buf + ".");
+
+        // RDP_NEG_RSP: Selected protocols (PROTOCOL_SSL)
+        int protocol = buf.readSignedIntLE();
+
+        if (negType != RdpConstants.RDP_NEG_REQ_TYPE_NEG_RSP) {
+            // Parse error code, see
+            // http://msdn.microsoft.com/en-us/library/cc240507.aspx
+            int errorCode = protocol;
+            String message = "Unknown error.";
+            switch (errorCode) {
+            case SSL_REQUIRED_BY_SERVER:
+                message = "The server requires that the client support Enhanced RDP Security with either TLS 1.0, 1.1 or 1.2 or CredSSP. If only CredSSP was requested then the server only supports TLS.";
+                break;
+
+            case SSL_NOT_ALLOWED_BY_SERVER:
+                message = "The server is configured to only use Standard RDP Security mechanisms and does not support any External Security Protocols.";
+                break;
+
+            case SSL_CERT_NOT_ON_SERVER:
+                message = "The server does not possess a valid authentication certificate and cannot initialize the External Security Protocol Provider.";
+                break;
+
+            case INCONSISTENT_FLAGS:
+                message = "The list of requested security protocols is not consistent with the current security protocol in effect. This error is only possible when the Direct Approach is used and an External Security Protocolis already being used.";
+                break;
+
+            case HYBRID_REQUIRED_BY_SERVER:
+                message = "The server requires that the client support Enhanced RDP Security with CredSSP.";
+                break;
+
+            case SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER:
+                message = "The server requires that the client support Enhanced RDP Security  with TLS 1.0, 1.1 or 1.2 and certificate-based client authentication.";
+                break;
+
+            }
+            throw new RuntimeException("Connection failure: " + message);
+        }
+
+        if (protocol != RdpConstants.RDP_NEG_REQ_PROTOCOL_SSL && protocol != RdpConstants.RDP_NEG_REQ_PROTOCOL_HYBRID)
+            throw new RuntimeException("Unexpected protocol type (nor SSL, nor HYBRID (SSL+CredSSP)): " + protocol + ", RDP NEG buf: " + buf + ".");
+
+        if (verbose)
+            System.out.println("[" + this + "] INFO: RDP Negotiation response. Type: " + negType + ", protocol: " + protocol + ".");
+
+        // Next: upgrade socket to SSL, send ConnectInitial packet
+        switchOff();
+    }
+
+    /**
+     * 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[] { 
+//    
+//        0x03, // -> TPKT Header: TPKT version = 3
+//        0x00, // TPKT Header: Reserved = 0
+//        0x00, 0x13, // TPKT Header: Packet length - (total = 19 bytes)
+//        0x0e, // X.224: Length indicator (14 bytes)
+//        (byte) 0xd0, // X.224: Type (high nibble) = 0xd = CC TPDU; credit
+//                     // (low nibble) = 0
+//        0x00, 0x00, // X.224: Destination reference = 0
+//        0x12, 0x34, // X.224: Source reference = 0x1234 (bogus value)
+//        0x00, // X.224: Class and options = 0
+//
+//        0x02, // RDP_NEG_RSP::type (TYPE_RDP_NEG_RSP)
+//        0x00, // RDP_NEG_RSP::flags (0)
+//        0x08, 0x00, // RDP_NEG_RSP::length (8 bytes)
+//        0x01, 0x00, 0x00, 0x00 // RDP_NEG_RSP: Selected protocols (PROTOCOL_SSL)
+//    };
+
+        // Connection failure
+        // 03 00 00 13 0e d0 00 00 12 34 00 03 00 08 00 05 00 00 00
+        byte[] packet = new byte[] {
+
+                0x03, // -> TPKT Header: TPKT version = 3
+                0x00, // TPKT Header: Reserved = 0
+                0x00, 0x13, // TPKT Header: Packet length - (total = 19 bytes)
+                0x0e, // X.224: Length indicator (14 bytes)
+                (byte)0xd0, // X.224: Type (high nibble) = 0xd = CC TPDU; credit
+                            // (low nibble) = 0
+                0x00, 0x00, // X.224: Destination reference = 0
+                0x12, 0x34, // X.224: Source reference = 0x1234 (bogus value)
+                0x00, // X.224: Class and options = 0
+                (byte)0x03, // Failure 
+                (byte)0x00, // RDP_NEG_RSP::flags (0)
+                (byte)0x08, (byte)0x00, // RDP_NEG_RSP::length (8 bytes) 
+                (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x00, // Code:  HYBRID_REQUIRED_BY_SERVER
+
+        };
+
+        MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(packet));
+        Element cc = new ServerX224ConnectionConfirmPDU("cc");
+        Element tpkt = new ServerTpkt("tpkt");
+        Element sink = new MockSink("sink", new ByteBuffer[] {});
+        Element mainSink = new MockSink("mainSink", new ByteBuffer[] {});
+
+        Pipeline pipeline = new PipelineImpl("test");
+        pipeline.add(source, tpkt, cc, sink, mainSink);
+        pipeline.link("source", "tpkt", "cc", "mainSink");
+        pipeline.link("cc >" + OTOUT, "sink");
+        pipeline.runMainLoop("source", STDOUT, false, false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerX224DataPdu.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerX224DataPdu.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerX224DataPdu.java
new file mode 100755
index 0000000..2c0087e
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ServerX224DataPdu.java
@@ -0,0 +1,64 @@
+// 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;
+
+public class ServerX224DataPdu extends BaseElement {
+
+    public static final int X224_TPDU_LAST_DATA_UNIT = 0x80;
+    public static final int X224_TPDU_DATA = 0xF0;
+
+    public ServerX224DataPdu(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 + ".");
+
+        int headerLength = buf.readVariableSignedIntLE();
+
+        if (headerLength != 2)
+            throw new RuntimeException("Unexpected X224 Data PDU header length. Expected header length: 2 , actual header length: " + headerLength + ".");
+
+        // Read X224 type and options
+        int type = buf.readUnsignedByte(); // High nibble: type, low nibble:
+
+        if ((type & 0xf0) != X224_TPDU_DATA)
+            throw new RuntimeException("[" + this + "] ERROR: Unexepcted X224 packet type. Expected packet type: " + X224_TPDU_DATA
+                    + " (X224_TPDU_DATA), actual packet type: " + type + ", buf: " + buf + ".");
+
+        int options = buf.readUnsignedByte();
+
+        if ((options & X224_TPDU_LAST_DATA_UNIT) != X224_TPDU_LAST_DATA_UNIT)
+            throw new RuntimeException("Unexepcted X224 packet options. Expected options: " + X224_TPDU_LAST_DATA_UNIT
+                    + " (X224_TPDU_LAST_DATA_UNIT), actual packet options: " + options + ", buf: " + buf + ".");
+
+        ByteBuffer payload = buf.readBytes(buf.length - buf.cursor);
+
+        buf.unref();
+
+        pushDataToAllOuts(payload);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/AssertingByteBuffer.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/AssertingByteBuffer.java b/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/AssertingByteBuffer.java
deleted file mode 100644
index 1958475..0000000
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/AssertingByteBuffer.java
+++ /dev/null
@@ -1,107 +0,0 @@
-// 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 streamer;
-
-import java.nio.charset.Charset;
-
-/**
- * Assert that writes to this buffer are matching expected data.
- */
-public class AssertingByteBuffer extends ByteBuffer {
-
-  public AssertingByteBuffer(byte[] expectedData) {
-    super(expectedData);
-  }
-
-  private void assertEquals(int expected, int actual) {
-    if (expected != actual)
-      throw new RuntimeException("Expected value does not match actual value. Expected value: " + expected + ", actual value: " + actual + ", buf: "+this+".");
-  }
-
-  @Override
-  public void writeByte(int b) {
-    if(b<0)
-      throw new RuntimeException();
-    //*DEBUG*/System.out.println("WriteByte: "+b+", cursor:"+cursor+".");
-    assertEquals(readUnsignedByte(), b&0xff);
-  }
-
-  @Override
-  public void writeShort(int x) {
-    //*DEBUG*/System.out.println("WriteShort: "+x+", cursor:"+cursor+".");
-    assertEquals(readUnsignedShort(), x&0xFFff);
-  }
-
-  @Override
-  public void writeShortLE(int x) {
-    //*DEBUG*/System.out.println("WriteShortLE: "+x+", cursor:"+cursor+".");
-    assertEquals(readUnsignedShortLE(), x&0xFFff);
-  }
-
-  @Override
-  public void writeInt(int i) {
-    //*DEBUG*/System.out.println("WriteInt: "+i+", cursor:"+cursor+".");
-    assertEquals(readSignedInt(), i);
-  }
-
-  @Override
-  public void writeIntLE(int i) {
-    //*DEBUG*/System.out.println("WriteIntLE: "+i+", cursor:"+cursor+".");
-    assertEquals(readSignedIntLE(), i);
-  }
-
-  @Override
-  public void writeVariableIntLE(int i) {
-    //*DEBUG*/System.out.println("WriteVariableIntLE: "+i+", cursor:"+cursor+".");
-    assertEquals(readVariableSignedIntLE(), i);
-  }
-
-  @Override
-  public void writeString(String actual, Charset charset) {
-    //*DEBUG*/System.out.println("WriteString: "+actual+", cursor:"+cursor+".");
-    String expected = readString(actual.length(), charset);
-    if (!actual.equals(expected))
-      throw new RuntimeException("Expected value does not match actual value. Expected value: " + expected + ", actual value: " + actual + ".");
-  }
-
-  @Override
-  public void writeBytes(ByteBuffer actual) {
-    //*DEBUG*/System.out.println("WriteString: "+actual+", cursor:"+cursor+".");
-    ByteBuffer expected = readBytes(actual.length);
-    if (!actual.equals(expected))
-      throw new RuntimeException("Expected value does not match actual value. Expected value: " + expected + ", actual value: " + actual + ".");
-  }
-
-  @Override
-  public void writeBytes(byte[] actualData) {
-    ByteBuffer actual = new ByteBuffer(actualData);
-    //*DEBUG*/System.out.println("WriteString: "+actual+", cursor:"+cursor+".");
-    ByteBuffer expected = readBytes(actual.length);
-    if (!actual.equals(expected))
-      throw new RuntimeException("Expected value does not match actual value. Expected value: " + expected + ", actual value: " + actual + ".");
-  }
-
-  @Override
-  public void writeBytes(byte[] actualData, int offset, int length) {
-    ByteBuffer actual = new ByteBuffer(actualData, offset, length);
-    //*DEBUG*/System.out.println("WriteString: "+actual+", cursor:"+cursor+".");
-    ByteBuffer expected = readBytes(actual.length);
-    if (!actual.equals(expected))
-      throw new RuntimeException("Expected value does not match actual value. Expected value: " + expected + ", actual value: " + actual + ".");
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BaseElement.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BaseElement.java b/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BaseElement.java
old mode 100644
new mode 100755
index 86f9be3..10c7c70
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BaseElement.java
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BaseElement.java
@@ -21,397 +21,401 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import streamer.debug.FakeSink;
+import streamer.debug.FakeSource;
+
 public class BaseElement implements Element {
 
-  protected String id;
-
-  /**
-   * Constant for @see cap() method to indicate that length is not restricted.
-   */
-  public static final int UNLIMITED = -1;
-
-  /**
-   * Set to true to enable debugging messages.
-   */
-  protected boolean verbose = false;
-
-  /**
-   * Limit on number of packets sent to sink from this element. Can be handy for
-   * fake elements and handshake-related elements.
-   */
-  protected int numBuffers = 0;
-
-  /**
-   * Number of packets sent to sink.
-   */
-  protected int packetNumber = 0;
-
-  /**
-   * Recommended size for incoming buffer in pull mode.
-   */
-  protected int incommingBufLength = -1;
-
-  protected Map<String, DataSource> inputPads = new HashMap<String, DataSource>();
-  protected Map<String, DataSink> outputPads = new HashMap<String, DataSink>();
-
-  public BaseElement(String id) {
-    this.id = id;
-
-    verbose = System.getProperty("streamer.Element.debug", "false").equals("true") || System.getProperty("streamer.Element.debug", "").contains(id);
-  }
-
-  @Override
-  public String toString() {
-    return "Element(" + id + ")";
-  }
-
-  @Override
-  public Link getLink(String padName) {
-    if (inputPads.containsKey(padName))
-      return (Link) inputPads.get(padName);
-    else if (outputPads.containsKey(padName))
-      return (Link) outputPads.get(padName);
-    else
-      return null;
-  }
-
-  @Override
-  public Set<String> getPads(Direction direction) {
-    switch (direction) {
-    case IN:
-      return inputPads.keySet();
-
-    case OUT:
-      return outputPads.keySet();
+    protected String id;
+
+    /**
+     * Constant for @see cap() method to indicate that length is not restricted.
+     */
+    public static final int UNLIMITED = -1;
+
+    /**
+     * Set to true to enable debugging messages.
+     */
+    protected boolean verbose = false;
+
+    /**
+     * Limit on number of packets sent to sink from this element. Can be handy for
+     * fake elements and handshake-related elements.
+     */
+    protected int numBuffers = 0;
+
+    /**
+     * Number of packets sent to sink.
+     */
+    protected int packetNumber = 0;
+
+    /**
+     * Recommended size for incoming buffer in pull mode.
+     */
+    protected int incommingBufLength = -1;
+
+    protected Map<String, DataSource> inputPads = new HashMap<String, DataSource>();
+    protected Map<String, DataSink> outputPads = new HashMap<String, DataSink>();
+
+    public BaseElement(String id) {
+        this.id = id;
+
+        verbose = System.getProperty("streamer.Element.debug", "false").equals("true") || System.getProperty("streamer.Element.debug", "").contains(id);
+    }
+
+    @Override
+    public String toString() {
+        return "Element(" + id + ")";
+    }
+
+    @Override
+    public Link getLink(String padName) {
+        if (inputPads.containsKey(padName))
+            return (Link)inputPads.get(padName);
+        else if (outputPads.containsKey(padName))
+            return (Link)outputPads.get(padName);
+        else
+            return null;
     }
-    return null;
-  }
-
-  @Override
-  public void validate() {
-    for (String padName : inputPads.keySet()) {
-      if (inputPads.get(padName) == null)
-        throw new RuntimeException("[ " + this + "] Required input pad is not connected. Pad name: " + padName + ".");
+
+    @Override
+    public Set<String> getPads(Direction direction) {
+        switch (direction) {
+        case IN:
+            return inputPads.keySet();
+
+        case OUT:
+            return outputPads.keySet();
+        }
+        return null;
     }
 
-    for (String padName : outputPads.keySet()) {
-      if (outputPads.get(padName) == null)
-        throw new RuntimeException("[ " + this + "] Required output pad is not connected. Pad name: " + padName + ".");
+    @Override
+    public void validate() {
+        for (String padName : inputPads.keySet()) {
+            if (inputPads.get(padName) == null)
+                throw new RuntimeException("[ " + this + "] Required input pad is not connected. Pad name: " + padName + ".");
+        }
+
+        for (String padName : outputPads.keySet()) {
+            if (outputPads.get(padName) == null)
+                throw new RuntimeException("[ " + this + "] Required output pad is not connected. Pad name: " + padName + ".");
+        }
     }
-  }
 
-  @Override
-  public void setLink(String padName, Link link, Direction direction) {
-    switch (direction) {
-    case IN:
-      if (inputPads.get(padName) != null)
-        throw new RuntimeException("Cannot link more than one wire to same pad. Element: " + this + ", pad: " + padName + ":" + direction + ", new link: "
-            + link + ", existing link: " + inputPads.get(padName) + ".");
-      inputPads.put(padName, link);
-      link.setSink(this);
+    @Override
+    public void setLink(String padName, Link link, Direction direction) {
+        switch (direction) {
+        case IN:
+            if (inputPads.get(padName) != null)
+                throw new RuntimeException("Cannot link more than one wire to same pad. Element: " + this + ", pad: " + padName + ":" + direction + ", new link: "
+                        + link + ", existing link: " + inputPads.get(padName) + ".");
+            inputPads.put(padName, link);
+            link.setSink(this);
 
-      break;
+            break;
 
-    case OUT:
-      if (outputPads.get(padName) != null)
-        throw new RuntimeException("Cannot link more than one wire to same pad. Element: " + this + ", pad: " + padName + ":" + direction + ", new link: "
-            + link + ", existing link: " + outputPads.get(padName) + ".");
+        case OUT:
+            if (outputPads.get(padName) != null)
+                throw new RuntimeException("Cannot link more than one wire to same pad. Element: " + this + ", pad: " + padName + ":" + direction + ", new link: "
+                        + link + ", existing link: " + outputPads.get(padName) + ".");
 
-      outputPads.put(padName, link);
-      link.setSource(this);
+            outputPads.put(padName, link);
+            link.setSource(this);
 
-      break;
+            break;
+        }
     }
-  }
-
-  @Override
-  public void dropLink(String padName) {
-    if (inputPads.containsKey(padName)) {
-      Link link = (Link) inputPads.remove(padName);
-      if (link != null)
-        link.setSink(null);
+
+    @Override
+    public void dropLink(String padName) {
+        if (inputPads.containsKey(padName)) {
+            Link link = (Link)inputPads.remove(padName);
+            if (link != null)
+                link.setSink(null);
+        }
+
+        if (outputPads.containsKey(padName)) {
+            Link link = (Link)outputPads.remove(padName);
+            if (link != null)
+                link.setSource(null);
+        }
     }
 
-    if (outputPads.containsKey(padName)) {
-      Link link = (Link) outputPads.remove(padName);
-      if (link != null)
-        link.setSource(null);
+    /**
+     * By default, try to pull data from input links.
+     * 
+     * Override this method in data source elements.
+     */
+    @Override
+    public void poll(boolean block) {
+        for (DataSource source : inputPads.values()) {
+            Link link = (Link)source;
+            ByteBuffer buf = link.pull(block);
+
+            if (buf != null) {
+                handleData(buf, link);
+            }
+        }
     }
-  }
-
-  /**
-   * By default, try to pull data from input links.
-   * 
-   * Override this method in data source elements.
-   */
-  @Override
-  public void poll(boolean block) {
-    for (DataSource source : inputPads.values()) {
-      Link link = (Link) source;
-      ByteBuffer buf = link.pull(block);
-
-      if (buf != null) {
-        handleData(buf, link);
-      }
+
+    /**
+     * By default, do nothing with incoming data and retransmit data to all output
+     * pads.
+     */
+    @Override
+    public void handleData(ByteBuffer buf, Link link) {
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+        pushDataToAllOuts(buf);
     }
-  }
-
-  /**
-   * By default, do nothing with incoming data and retransmit data to all output
-   * pads.
-   */
-  @Override
-  public void handleData(ByteBuffer buf, Link link) {
-    if (buf == null)
-      return;
-
-    if (verbose)
-      System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
-
-    pushDataToAllOuts(buf);
-  }
-
-  /**
-   * Send data to all output pads.
-   */
-  protected final void pushDataToAllOuts(ByteBuffer buf) {
-
-    if (buf == null)
-      return;
-
-    if (outputPads.size() == 0)
-      throw new RuntimeException("Number of outgoing connection is zero. Cannot send data to output. Data: " + buf + ".");
-
-    // Send data to all pads with OUT direction
-    for (DataSink out : outputPads.values()) {
-      if (verbose)
-        System.out.println("[" + this + "] INFO: Sending buf " + buf + " to " + out + ".");
-
-      buf.rewindCursor();
-      buf.ref();
-      out.sendData(buf);
+
+    /**
+     * Send data to all output pads.
+     */
+    protected final void pushDataToAllOuts(ByteBuffer buf) {
+
+        if (buf == null) {
+            throw new NullPointerException();
+        }
+
+        if (outputPads.size() == 0)
+            throw new RuntimeException("Number of outgoing connection is zero. Cannot send data to output. Data: " + buf + ".");
+
+        // Send data to all pads with OUT direction
+        for (DataSink out : outputPads.values()) {
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Sending buf " + buf + " to " + out + ".");
+
+            buf.rewindCursor();
+            buf.ref();
+            out.sendData(buf);
+        }
+
+        buf.unref();
+        packetNumber++;
     }
 
-    buf.unref();
-    packetNumber++;
-  }
-
-  /**
-   * Send data to given pad only.
-   */
-  protected void pushDataToPad(String padName, ByteBuffer buf) {
-    if (buf == null)
-      return;
-
-    if (verbose)
-      System.out.println("[" + this + "] INFO: Sending buf " + buf + " to " + padName + ".");
-
-    DataSink link = outputPads.get(padName);
-    if (link == null)
-      throw new RuntimeException("Output pad of " + this + " element is not connected to a link. Pad name: " + padName + ".");
-
-    buf.rewindCursor();
-    link.sendData(buf);
-  }
-
-  /**
-   * By default, do nothing with incoming event and retransmit event to all
-   * pads.
-   */
-  @Override
-  public void handleEvent(Event event, Direction direction) {
-    if (verbose)
-      System.out.println("[" + this + "] INFO: Event " + event + ":" + direction + " is received.");
-
-    switch (event) {
-    case STREAM_CLOSE:
-      onClose();
-      break;
-    case STREAM_START:
-      onStart();
-      break;
+    /**
+     * Send data to given pad only.
+     */
+    protected void pushDataToPad(String padName, ByteBuffer buf) {
+        if (buf == null)
+            return;
+
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Sending buf " + buf + " to " + padName + ".");
+
+        DataSink link = outputPads.get(padName);
+        if (link == null)
+            throw new RuntimeException("Output pad of " + this + " element is not connected to a link. Pad name: " + padName + ".");
+
+        buf.rewindCursor();
+        link.sendData(buf);
     }
 
-    sendEventToAllPads(event, direction);
-  }
-
-  /**
-   * Override this method to do something when STREAM_CLOSE event arrives.
-   */
-  protected void onClose() {
-  }
-
-  /**
-   * Override this method to do something when STREAM_START event arrives.
-   */
-  protected void onStart() {
-  }
-
-  /**
-   * Send event to all outputs.
-   * 
-   * @param event
-   *          a event
-   * @param direction
-   *          IN to send event to input pads, OUT to send event to all output
-   *          pads
-   */
-  protected final void sendEventToAllPads(Event event, Direction direction) {
-    if (verbose)
-      System.out.println("[" + this + "] INFO: Sending event " + event + ":" + direction + ".");
-
-    switch (direction) {
-    case IN:
-      // Send event to all pads with IN direction
-      for (DataSource in : inputPads.values()) {
-        in.sendEvent(event, direction);
-      }
-      break;
-    case OUT:
-      // Send event to all pads with OUT direction
-      for (DataSink out : outputPads.values()) {
-        out.sendEvent(event, direction);
-      }
-      break;
+    /**
+     * By default, do nothing with incoming event and retransmit event to all
+     * pads.
+     */
+    @SuppressWarnings("incomplete-switch")
+    @Override
+    public void handleEvent(Event event, Direction direction) {
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Event " + event + ":" + direction + " is received.");
+
+        switch (event) {
+        case STREAM_CLOSE:
+            onClose();
+            break;
+        case STREAM_START:
+            onStart();
+            break;
+        }
+
+        sendEventToAllPads(event, direction);
     }
-  }
-
-  /**
-   * Ensure that packet has required minimum and maximum length, cuts tail when
-   * necessary.
-   * 
-   * @param buf
-   *          a buffer
-   * @param minLength
-   *          minimum length of packet or -1
-   * @param maxLength
-   *          maximum length of packet or -1
-   * @param link
-   *          source link, to push unnecessary data back
-   * @param fromCursor
-   *          if true, then position will be included into calculation
-   * @return true,
-   */
-  public boolean cap(ByteBuffer buf, int minLength, int maxLength, Link link, boolean fromCursor) {
-
-    if (buf == null)
-      return false;
-
-    int length = buf.length;
-
-    int cursor;
-    if (fromCursor)
-      cursor = buf.cursor;
-    else
-      cursor = 0;
-
-    length -= cursor;
-
-    if ((minLength < 0 || length >= minLength) && (maxLength < 0 || length <= maxLength))
-      // Buffer is already in bounds
-      return true;
-
-    // Buffer is too small, wait for the rest of buffer
-    if (minLength >= 0 && length < minLength) {
-
-      if (verbose)
-        System.out.println("[" + this + "] INFO: Buffer is too small. Min length: " + minLength + ", data length (after cursor): " + length + ".");
-
-      link.pushBack(buf.slice(0, length + cursor, true), minLength + cursor);
-      return false;
-    } else if (maxLength >= 0 && length > maxLength) {
-
-      if (verbose)
-        System.out.println("[" + this + "] INFO: Buffer is too big. Max length: " + maxLength + ", data length (after cursor): " + length + ".");
-
-      // Buffer is too big, cut unnecessary tail
-      link.pushBack(buf.slice(maxLength + cursor, length - maxLength, true));
-      buf.length = maxLength + cursor;
 
+    /**
+     * Override this method to do something when STREAM_CLOSE event arrives.
+     */
+    protected void onClose() {
     }
 
-    return true;
-  }
+    /**
+     * Override this method to do something when STREAM_START event arrives.
+     */
+    protected void onStart() {
+    }
 
-  @Override
-  public void dropLink(Link link) {
-    if (inputPads.containsValue(link)) {
-      for (Entry<String, DataSource> entry : inputPads.entrySet())
-        if (link.equals(entry.getValue())) {
-          inputPads.remove(entry.getKey());
-          break;
+    /**
+     * Send event to all outputs.
+     * 
+     * @param event
+     *          a event
+     * @param direction
+     *          IN to send event to input pads, OUT to send event to all output
+     *          pads
+     */
+    protected final void sendEventToAllPads(Event event, Direction direction) {
+        if (verbose)
+            System.out.println("[" + this + "] INFO: Sending event " + event + ":" + direction + ".");
+
+        switch (direction) {
+        case IN:
+            // Send event to all pads with IN direction
+            for (DataSource in : inputPads.values()) {
+                in.sendEvent(event, direction);
+            }
+            break;
+        case OUT:
+            // Send event to all pads with OUT direction
+            for (DataSink out : outputPads.values()) {
+                out.sendEvent(event, direction);
+            }
+            break;
         }
     }
 
-    if (outputPads.containsValue(link)) {
-      for (Entry<String, DataSink> entry : outputPads.entrySet())
-        if (link.equals(entry.getValue())) {
-          outputPads.remove(entry.getKey());
-          break;
+    /**
+     * Ensure that packet has required minimum and maximum length, cuts tail when
+     * necessary.
+     * 
+     * @param buf
+     *          a buffer
+     * @param minLength
+     *          minimum length of packet or -1
+     * @param maxLength
+     *          maximum length of packet or -1
+     * @param link
+     *          source link, to push unnecessary data back
+     * @param fromCursor
+     *          if true, then position will be included into calculation
+     * @return true, if buffer is long enough, false otherwise
+     */
+    public boolean cap(ByteBuffer buf, int minLength, int maxLength, Link link, boolean fromCursor) {
+
+        if (buf == null)
+            return false;
+
+        int length = buf.length;
+
+        int cursor;
+        if (fromCursor)
+            cursor = buf.cursor;
+        else
+            cursor = 0;
+
+        length -= cursor;
+
+        if ((minLength < 0 || length >= minLength) && (maxLength < 0 || length <= maxLength))
+            // Buffer is already in bounds
+            return true;
+
+        // Buffer is too small, wait for the rest of buffer
+        if (minLength >= 0 && length < minLength) {
+
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Buffer is too small. Min length: " + minLength + ", data length (after cursor): " + length + ".");
+
+            link.pushBack(buf.slice(0, length + cursor, true), minLength + cursor);
+            return false;
+        } else if (maxLength >= 0 && length > maxLength) {
+
+            if (verbose)
+                System.out.println("[" + this + "] INFO: Buffer is too big. Max length: " + maxLength + ", data length (after cursor): " + length + ".");
+
+            // Buffer is too big, cut unnecessary tail
+            link.pushBack(buf.slice(maxLength + cursor, length - maxLength, true));
+            buf.length = maxLength + cursor;
+
         }
+
+        return true;
     }
-  }
-
-  @Override
-  public void replaceLink(Link existingLink, Link newLink) {
-    if (inputPads.containsValue(existingLink)) {
-      for (Entry<String, DataSource> entry : inputPads.entrySet())
-        if (existingLink.equals(entry.getValue())) {
-          inputPads.put(entry.getKey(), newLink);
-          newLink.setSink(this);
-          break;
+
+    @Override
+    public void dropLink(Link link) {
+        if (inputPads.containsValue(link)) {
+            for (Entry<String, DataSource> entry : inputPads.entrySet())
+                if (link.equals(entry.getValue())) {
+                    inputPads.remove(entry.getKey());
+                    break;
+                }
+        }
+
+        if (outputPads.containsValue(link)) {
+            for (Entry<String, DataSink> entry : outputPads.entrySet())
+                if (link.equals(entry.getValue())) {
+                    outputPads.remove(entry.getKey());
+                    break;
+                }
         }
     }
 
-    if (outputPads.containsValue(existingLink)) {
-      for (Entry<String, DataSink> entry : outputPads.entrySet())
-        if (existingLink.equals(entry.getValue())) {
-          outputPads.put(entry.getKey(), newLink);
-          newLink.setSource(this);
-          break;
+    @Override
+    public void replaceLink(Link existingLink, Link newLink) {
+        if (inputPads.containsValue(existingLink)) {
+            for (Entry<String, DataSource> entry : inputPads.entrySet())
+                if (existingLink.equals(entry.getValue())) {
+                    inputPads.put(entry.getKey(), newLink);
+                    newLink.setSink(this);
+                    break;
+                }
         }
+
+        if (outputPads.containsValue(existingLink)) {
+            for (Entry<String, DataSink> entry : outputPads.entrySet())
+                if (existingLink.equals(entry.getValue())) {
+                    outputPads.put(entry.getKey(), newLink);
+                    newLink.setSource(this);
+                    break;
+                }
+        }
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Example.
+     */
+    public static void main(String args[]) {
+        Element source = new FakeSource("source") {
+            {
+                this.verbose = true;
+                this.numBuffers = 10;
+                this.incommingBufLength = 3;
+                this.delay = 100;
+            }
+        };
+
+        Element sink = new FakeSink("sink") {
+            {
+                this.verbose = true;
+            }
+        };
+
+        Pipeline pipeline = new PipelineImpl("test");
+        pipeline.add(source);
+        pipeline.add(new BaseElement("t1"));
+        pipeline.add(new BaseElement("t2"));
+        pipeline.add(new BaseElement("t3"));
+        pipeline.add(new BaseElement("t4"));
+        pipeline.add(sink);
+
+        pipeline.link("source", "t1", "t2", "t3", "t4", "sink");
+
+        // Links between source-t1-t2 will operate in pull mode.
+        // Links between t3-t4-sink will operate in push mode.
+        // Link between t2-t3 will run main loop (pull from source and push to
+        // sink).
+        Link link = pipeline.getLink("t3", STDOUT);
+        link.sendEvent(Event.STREAM_START, Direction.IN);
+        link.run();
     }
-  }
-
-  @Override
-  public String getId() {
-    return id;
-  }
-
-  /**
-   * Example.
-   */
-  public static void main(String args[]) {
-    Element source = new FakeSource("source") {
-      {
-        this.verbose = true;
-        this.numBuffers = 10;
-        this.incommingBufLength = 3;
-        this.delay = 100;
-      }
-    };
-
-    Element sink = new FakeSink("sink") {
-      {
-        this.verbose = true;
-      }
-    };
-
-    Pipeline pipeline = new PipelineImpl("test");
-    pipeline.add(source);
-    pipeline.add(new BaseElement("t1"));
-    pipeline.add(new BaseElement("t2"));
-    pipeline.add(new BaseElement("t3"));
-    pipeline.add(new BaseElement("t4"));
-    pipeline.add(sink);
-
-    pipeline.link("source", "t1", "t2", "t3", "t4", "sink");
-
-    // Links between source-t1-t2 will operate in pull mode.
-    // Links between t3-t4-sink will operate in push mode.
-    // Link between t2-t3 will run main loop (pull from source and push to
-    // sink).
-    pipeline.getLink("t3", STDOUT).run();
-  }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BufferPool.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BufferPool.java b/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BufferPool.java
old mode 100644
new mode 100755
index 47f1435..d8e9139
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BufferPool.java
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/streamer/BufferPool.java
@@ -17,20 +17,20 @@
 package streamer;
 
 public class BufferPool {
-  public static byte[] allocateNewBuffer(int minSize) {
-    // TODO: search for free buffer in pool
-    if (minSize >= 0)
-      return new byte[minSize];
-    else
-      // Return large buffer by default, too minimize number of round trips
-      // between to read full packet when packet is large, but it is important
-      // to return buffer to pool to reuse it (or null-ify links to it for
-      // faster GC)
-      // TODO: get free buffer from pool
-      return new byte[128 * 1024];
-  }
+    public static byte[] allocateNewBuffer(int minSize) {
+        // TODO: search for free buffer in pool
+        if (minSize >= 0)
+            return new byte[minSize];
+        else
+            // Return large buffer by default, too minimize number of round trips
+            // between to read full packet when packet is large, but it is important
+            // to return buffer to pool to reuse it (or null-ify links to it for
+            // faster GC)
+            // TODO: get free buffer from pool
+            return new byte[128 * 1024];
+    }
 
-  public static void recycleBuffer(byte[] buf) {
-    // TODO: return buffer to pool
-  }
+    public static void recycleBuffer(byte[] buf) {
+        // TODO: return buffer to pool
+    }
 }