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

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

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/ObjectID.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/ObjectID.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/ObjectID.java
new file mode 100755
index 0000000..c112cd0
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/ObjectID.java
@@ -0,0 +1,67 @@
+// 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 common.asn1;
+
+import streamer.ByteBuffer;
+
+public class ObjectID extends Tag {
+
+    /**
+     * Raw bytes of encoded OID.
+     */
+    public ByteBuffer value;
+
+    public ObjectID(String name) {
+        super(name);
+        tagType = OBJECT_ID;
+    }
+
+    @Override
+    public boolean isValueSet() {
+        return value != null;
+    }
+
+    @Override
+    public long calculateLengthOfValuePayload() {
+        return value.length;
+    }
+
+    @Override
+    public void writeTagValuePayload(ByteBuffer buf) {
+        buf.writeBytes(value);
+    }
+
+    @Override
+    public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
+        long length = buf.readBerLength();
+
+        value = buf.readBytes((int)length);
+    }
+
+    @Override
+    public Tag deepCopy(String suffix) {
+        return new ObjectID(name + suffix).copyFrom(this);
+    }
+
+    @Override
+    public Tag copyFrom(Tag tag) {
+        super.copyFrom(tag);
+        value = new ByteBuffer(((ObjectID)tag).value.toByteArray());
+        return this;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/OctetString.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/OctetString.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/OctetString.java
new file mode 100755
index 0000000..3da9c84
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/OctetString.java
@@ -0,0 +1,80 @@
+// 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 common.asn1;
+
+import streamer.ByteBuffer;
+
+public class OctetString extends Tag {
+
+    public ByteBuffer value = null;
+
+    public OctetString(String name) {
+        super(name);
+        tagType = OCTET_STRING;
+    }
+
+    @Override
+    public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
+        // Type is already read by parent parser
+
+        long length = buf.readBerLength();
+
+        if (length > buf.length)
+            throw new RuntimeException("BER octet string is too long: " + length + " bytes. Data: " + buf + ".");
+
+        value = buf.readBytes((int)length);
+    }
+
+    @Override
+    public Tag deepCopy(String suffix) {
+        return new OctetString(name + suffix).copyFrom(this);
+    }
+
+    @Override
+    public Tag copyFrom(Tag tag) {
+        super.copyFrom(tag);
+        value = ((OctetString)tag).value;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + "= " + value;
+    }
+
+    @Override
+    public long calculateLengthOfValuePayload() {
+        if (value != null)
+            return value.length;
+        else
+            return 0;
+    }
+
+    @Override
+    public void writeTagValuePayload(ByteBuffer buf) {
+        if (value != null)
+            buf.writeBytes(value);
+        else
+            return;
+    }
+
+    @Override
+    public boolean isValueSet() {
+        return value != null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Sequence.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Sequence.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Sequence.java
new file mode 100755
index 0000000..6fa23f8
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Sequence.java
@@ -0,0 +1,143 @@
+// 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 common.asn1;
+
+import java.util.Arrays;
+
+import streamer.ByteBuffer;
+
+/**
+ * One or more elements of different types.
+ *
+ * Only prefixed tags are supported.
+ */
+public class Sequence extends Tag {
+
+    public Tag[] tags;
+
+    public Sequence(String name) {
+        super(name);
+        tagType = SEQUENCE;
+        // Sequence and SequenceOf are always encoded as constructed
+        constructed = true;
+    }
+
+    @Override
+    public long calculateLengthOfValuePayload() {
+        long sum = 0;
+
+        for (Tag tag : tags) {
+            long tagLength = tag.calculateFullLength();
+            sum += tagLength;
+        }
+
+        return sum;
+    }
+
+    @Override
+    public void writeTagValuePayload(ByteBuffer buf) {
+        // Write tags
+        for (Tag tag : tags) {
+            tag.writeTag(buf);
+        }
+    }
+
+    @Override
+    public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
+        // Type is already read by parent parser
+
+        long length = buf.readBerLength();
+        if (length > buf.remainderLength())
+            throw new RuntimeException("BER sequence is too long: " + length + " bytes, while buffer remainder length is " + buf.remainderLength() + ". Data: " + buf
+                    + ".");
+
+        ByteBuffer value = buf.readBytes((int)length);
+        parseContent(value);
+
+        value.unref();
+    }
+
+    protected void parseContent(ByteBuffer buf) {
+        for (int i = 0; buf.remainderLength() > 0 && i < tags.length; i++) {
+            BerType typeAndFlags = readBerType(buf);
+
+            // If current tag does not match data in buffer
+            if (!tags[i].isTypeValid(typeAndFlags)) {
+
+                // If tag is required, then throw exception
+                if (!tags[i].optional) {
+                    throw new RuntimeException("[" + this + "] ERROR: Required tag is missed: " + tags[i] + ". Unexected tag type: " + typeAndFlags + ". Data: " + buf
+                            + ".");
+                } else {
+                    // One or more tags are omitted, so skip them
+                    for (; i < tags.length; i++) {
+                        if (tags[i].isTypeValid(typeAndFlags)) {
+                            break;
+                        }
+                    }
+
+                    if (i >= tags.length || !tags[i].isTypeValid(typeAndFlags)) {
+                        throw new RuntimeException("[" + this + "] ERROR: No more tags to read or skip, but some data still left in buffer. Unexected tag type: "
+                                + typeAndFlags + ". Data: " + buf + ".");
+                    }
+                }
+            }
+
+            tags[i].readTag(buf, typeAndFlags);
+        }
+
+    }
+
+    @Override
+    public boolean isTypeValid(BerType typeAndFlags, boolean explicit) {
+        if (explicit)
+            return typeAndFlags.tagClass == tagClass && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagNumber;
+        else
+            // Sequences are always encoded as "constructed" in BER.
+            return typeAndFlags.tagClass == UNIVERSAL_CLASS && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == SEQUENCE;
+    }
+
+    @Override
+    public Tag deepCopy(String suffix) {
+        return new Sequence(name + suffix).copyFrom(this);
+    }
+
+    @Override
+    public Tag copyFrom(Tag tag) {
+        super.copyFrom(tag);
+
+        if (tags.length != ((Sequence)tag).tags.length)
+            throw new RuntimeException("Incompatible sequences. This: " + this + ", another: " + tag + ".");
+
+        for (int i = 0; i < tags.length; i++) {
+            tags[i].copyFrom(((Sequence)tag).tags[i]);
+        }
+
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + "{" + Arrays.toString(tags) + " }";
+    }
+
+    @Override
+    public boolean isValueSet() {
+        return tags != null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/SequenceOf.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/SequenceOf.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/SequenceOf.java
new file mode 100755
index 0000000..f288991
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/SequenceOf.java
@@ -0,0 +1,82 @@
+// 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 common.asn1;
+
+import java.util.ArrayList;
+
+import streamer.ByteBuffer;
+
+/**
+ * Zero or more elements of same type (array).
+ */
+public class SequenceOf extends Sequence {
+
+    /**
+     * Type of this array.
+     */
+    public Tag type;
+
+    /* Values are stored in tags[] variable inherited from Sequence. */
+
+    public SequenceOf(String name) {
+        super(name);
+    }
+
+    @Override
+    protected void parseContent(ByteBuffer buf) {
+        ArrayList<Tag> tagList = new ArrayList<Tag>();
+
+        for (int index = 0; buf.remainderLength() > 0; index++) {
+            // End of array is marked with two zero bytes (0x00 0x00)
+            if (buf.peekUnsignedByte(0) == 0x00 && buf.peekUnsignedByte(1) == 0x00) {
+                break;
+            }
+
+            Tag tag = type.deepCopy(index);
+
+            tag.readTag(buf);
+            tagList.add(tag);
+        }
+
+        tags = tagList.toArray(new Tag[tagList.size()]);
+    }
+
+    @Override
+    public Tag deepCopy(String suffix) {
+        return new SequenceOf(name + suffix).copyFrom(this);
+    }
+
+    @Override
+    public Tag copyFrom(Tag tag) {
+        super.copyFrom(tag);
+        // We can create shallow copy of type, because it will not be modified
+        type = ((SequenceOf)tag).type;
+
+        tags = new Tag[((Sequence)tag).tags.length];
+        for (int i = 0; i < tags.length; i++) {
+            tags[i] = ((Sequence)tag).tags[i].deepCopy("");
+        }
+
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + ": " + type;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Tag.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Tag.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Tag.java
new file mode 100755
index 0000000..80ece43
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Tag.java
@@ -0,0 +1,462 @@
+// 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 common.asn1;
+
+import streamer.ByteBuffer;
+
+public abstract class Tag implements Asn1Constants {
+
+    /**
+     * Name of this tag, for debugging purposes.
+     */
+    public String name = "";
+
+    /**
+     * Is this tag required or optional, for explicit tags only.
+     */
+    public boolean optional = false;
+
+    /**
+     * Tag primitive (e.g. implicit boolean), or constructed (e.g. sequence, or
+     * explicit boolean).
+     */
+    public boolean constructed = false;
+
+    /**
+     * Class of tag, when it is explicit.
+     */
+    public int tagClass = UNIVERSAL_CLASS;
+
+    /**
+     * Tag number (e.g. index in sequence), when tag is explicit.
+     */
+    public int tagNumber = -1;
+
+    /**
+     * Tag type (e.g. INDER), when tag is implicit.
+     */
+    public int tagType = -1;
+
+    /**
+     * If tag is explicit, then it is prefixed with tag number, so it can be
+     * optional or used in unordered set.
+     */
+    public boolean explicit = false;
+
+    public Tag(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Write tag value, with or without prefix.
+     */
+    public void writeTag(ByteBuffer buf) {
+
+        if (!isMustBeWritten())
+            return;
+
+        // Write prefix, when necessary
+        if (explicit) {
+
+            // Write tag prefix, always constructed
+            BerType berTagPrefix = new BerType(tagClass, true, tagNumber);
+            writeBerType(buf, berTagPrefix);
+
+            // Write tag prefix length
+            buf.writeBerLength(calculateLength());
+
+            // Write tag value
+            writeTagValue(buf);
+        } else {
+            // If implicit, just write tag value
+            writeTagValue(buf);
+        }
+    }
+
+    /**
+     * Must return true when value of this tag is set or tag is required, so it
+     * can be written, false otherwise.
+     */
+    public boolean isMustBeWritten() {
+        return !optional || isValueSet();
+    }
+
+    /**
+     * Must return true when value of this tag is set or tag is required, so it
+     * can be written, false otherwise.
+     */
+    public abstract boolean isValueSet();
+
+    /**
+     * Calculate full length of tag, including type (or prefix, when explicit).
+     */
+    public long calculateFullLength() {
+        if (!isMustBeWritten())
+            return 0;
+
+        // Length of value, including type
+        long length = calculateLength();
+
+        if (!explicit) {
+            // Length of tag type and it length
+            length += calculateLengthOfTagTypeOrTagNumber(tagType) + calculateLengthOfLength(length);
+        } else {
+            // Length of tag prefix and it length
+            length += calculateLengthOfTagTypeOrTagNumber(tagNumber) + calculateLengthOfLength(length);
+        }
+
+        return length;
+    }
+
+    /**
+     * Calculate length of tag, including type when explicit, but without length
+     * of prefix (or type, when implicit).
+     */
+    public long calculateLength() {
+        if (!isMustBeWritten())
+            return 0;
+
+        // Length of value
+        long length = calculateLengthOfValuePayload();
+
+        if (explicit) {
+            // Length of tag type and it length
+            length += calculateLengthOfTagTypeOrTagNumber(tagType) + calculateLengthOfLength(length);
+        }
+
+        return length;
+    }
+
+    /**
+     * Calculate length of BER length.
+     */
+    public int calculateLengthOfLength(long length) {
+        if (length < 0)
+            throw new RuntimeException("[" + this + "] ERROR: Length of tag cannot be less than zero: " + length + ".");
+
+        if (length <= 0x7f)
+            return 1;
+        if (length <= 0xff)
+            return 2;
+        if (length <= 0xffFF)
+            return 3;
+        if (length <= 0xffFFff)
+            return 4;
+        if (length <= 0xffFFffFFL)
+            return 5;
+        if (length <= 0xffFFffFFffL)
+            return 6;
+        if (length <= 0xffFFffFFffFFL)
+            return 7;
+        if (length <= 0xffFFffFFffFFffL)
+            return 8;
+
+        return 9;
+    }
+
+    /**
+     * Calculate length of type to tag number. Values less than 31 are encoded
+     * using lower 5 bits of first byte of tag. Values larger than 31 are
+     * indicated by lower 5 bits set to 1 (0x1F, 31), and next bytes are contain
+     * value in network order, where topmost bit of byte (0x80) indicates is value
+     * contains more bytes, i.e. last byte of sequence has this bit set to 0.
+     */
+    public int calculateLengthOfTagTypeOrTagNumber(int tagType) {
+        if (tagType >= EXTENDED_TYPE)
+            throw new RuntimeException("Multibyte tag types are not supported yet.");
+
+        return 1;
+    }
+
+    /**
+     * Calculate length of payload only, without tag prefix, tag type, and
+     * lengths.
+     *
+     * @return
+     */
+    public abstract long calculateLengthOfValuePayload();
+
+    /**
+     * Write tag value only, without prefix.
+     */
+    public void writeTagValue(ByteBuffer buf) {
+
+        // Write type
+        BerType valueType = new BerType(UNIVERSAL_CLASS, constructed, tagType);
+        writeBerType(buf, valueType);
+
+        // Write length
+        long lengthOfPayload = calculateLengthOfValuePayload();
+        buf.writeBerLength(lengthOfPayload);
+
+        // Store cursor to check is calculated length matches length of actual bytes
+        // written
+        int storedCursor = buf.cursor;
+
+        // Write value
+        writeTagValuePayload(buf);
+
+        // Check is calculated length matches length of actual bytes written, to catch errors early
+        int actualLength = buf.cursor - storedCursor;
+        if (actualLength != lengthOfPayload)
+            throw new RuntimeException("[" + this + "] ERROR: Unexpected length of data in buffer. Expected " + lengthOfPayload + " of bytes of payload, but "
+                    + actualLength + " bytes are written instead. Data: " + buf + ".");
+    }
+
+    /**
+     * Write tag value only, without prefix, tag type, and length.
+     */
+    public abstract void writeTagValuePayload(ByteBuffer buf);
+
+    /**
+     * Read required tag, i.e. we are 100% sure that byte buffer will contain this
+     * tag, or exception will be thrown otherwise.
+     *
+     * @param buf
+     *          buffer with tag data
+     */
+    public void readTag(ByteBuffer buf) {
+        BerType typeAndFlags = readBerType(buf);
+
+        // * DEBUG */System.out.println("Tag, read " + typeAndFlags);
+
+        if (!isTypeValid(typeAndFlags))
+            throw new RuntimeException("[" + this + "] Unexpected type: " + typeAndFlags + ".");
+
+        readTag(buf, typeAndFlags);
+    }
+
+    /**
+     * Read tag when it type is already read.
+     */
+    public void readTag(ByteBuffer buf, BerType typeAndFlags) {
+
+        if (explicit) {
+            long length = buf.readBerLength();
+
+            if (length > buf.length)
+                throw new RuntimeException("BER value is too long: " + length + " bytes. Data: " + buf + ".");
+
+            ByteBuffer value = buf.readBytes((int)length);
+
+            readTagValue(value);
+
+            value.unref();
+        } else {
+
+            readTagValue(buf, typeAndFlags);
+        }
+    }
+
+    /**
+     * Read tag value only, i.e. it prefix is already read.
+     */
+    public void readTagValue(ByteBuffer value) {
+        BerType typeAndFlags = readBerType(value);
+
+        // * DEBUG */System.out.println("Tag, read value " + typeAndFlags);
+
+        if (!isTypeValid(typeAndFlags, false))
+            throw new RuntimeException("[" + this + "] Unexpected type: " + typeAndFlags + ".");
+
+        readTagValue(value, typeAndFlags);
+    }
+
+    /**
+     * Check are tag type and flags valid for this tag.
+     */
+    public final boolean isTypeValid(BerType typeAndFlags) {
+        return isTypeValid(typeAndFlags, explicit);
+    }
+
+    /**
+     * Check are tag type and flags valid for this tag with or without tag prefix.
+     *
+     * @param explicit
+     *          if true, then value is wrapped in tag prefix
+     */
+    public boolean isTypeValid(BerType typeAndFlags, boolean explicit) {
+        if (explicit)
+            return typeAndFlags.tagClass == tagClass && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagNumber;
+        else
+            return typeAndFlags.tagClass == UNIVERSAL_CLASS && !typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagType;
+    }
+
+    @Override
+    public String toString() {
+        return "  \nTag [name="
+                + name
+
+                + ((constructed) ? ", constructed=" + constructed : "")
+
+                + (", tagType=" + tagTypeOrNumberToString(UNIVERSAL_CLASS, tagType))
+
+                + ((explicit) ? ", explicit=" + explicit + ", optional=" + optional + ", tagClass=" + tagClassToString(tagClass) + ", tagNumber="
+                        + tagTypeOrNumberToString(tagClass, tagNumber) : "") + "]";
+    }
+
+    public static final String tagTypeOrNumberToString(int tagClass, int tagTypeOrNumber) {
+        switch (tagClass) {
+        case UNIVERSAL_CLASS:
+            switch (tagTypeOrNumber) {
+            case EOF:
+                return "EOF";
+            case BOOLEAN:
+                return "BOOLEAN";
+            case INTEGER:
+                return "INTEGER";
+            case BIT_STRING:
+                return "BIT_STRING";
+            case OCTET_STRING:
+                return "OCTET_STRING";
+            case NULL:
+                return "NULL";
+            case OBJECT_ID:
+                return "OBJECT_ID";
+            case REAL:
+                return "REAL";
+            case ENUMERATED:
+                return "ENUMERATED";
+            case SEQUENCE:
+                return "SEQUENCE";
+            case SET:
+                return "SET";
+            case NUMERIC_STRING:
+                return "NUMERIC_STRING";
+            case PRINTABLE_STRING:
+                return "PRINTABLE_STRING";
+            case TELETEX_STRING:
+                return "TELETEX_STRING";
+            case VIDEOTEXT_STRING:
+                return "VIDEOTEXT_STRING";
+            case IA5_STRING:
+                return "IA5_STRING";
+            case UTCTIME:
+                return "UTCTIME";
+            case GENERAL_TIME:
+                return "GENERAL_TIME";
+            case GRAPHIC_STRING:
+                return "GRAPHIC_STRING";
+            case VISIBLE_STRING:
+                return "VISIBLE_STRING";
+            case GENERAL_STRING:
+                return "GENERAL_STRING";
+            case EXTENDED_TYPE:
+                return "EXTENDED_TYPE (multibyte)";
+            default:
+                return "UNKNOWN(" + tagTypeOrNumber + ")";
+
+            }
+
+        default:
+            return "[" + tagTypeOrNumber + "]";
+        }
+    }
+
+    public static final String tagClassToString(int tagClass) {
+        switch (tagClass) {
+        case UNIVERSAL_CLASS:
+            return "UNIVERSAL";
+        case CONTEXT_CLASS:
+            return "CONTEXT";
+        case APPLICATION_CLASS:
+            return "APPLICATION";
+        case PRIVATE_CLASS:
+            return "PRIVATE";
+        default:
+            return "UNKNOWN";
+        }
+    }
+
+    /**
+     * Read BER tag type.
+     */
+    public BerType readBerType(ByteBuffer buf) {
+        int typeAndFlags = buf.readUnsignedByte();
+
+        int tagClass = typeAndFlags & CLASS_MASK;
+
+        boolean constructed = (typeAndFlags & CONSTRUCTED) != 0;
+
+        int type = typeAndFlags & TYPE_MASK;
+        if (type == EXTENDED_TYPE)
+            throw new RuntimeException("Extended tag types/numbers (31+) are not supported yet.");
+
+        return new BerType(tagClass, constructed, type);
+    }
+
+    /**
+     * Write BER tag type.
+     */
+    public void writeBerType(ByteBuffer buf, BerType berType) {
+
+        if (berType.typeOrTagNumber >= EXTENDED_TYPE || berType.typeOrTagNumber < 0)
+            throw new RuntimeException("Extended tag types/numbers (31+) are not supported yet: " + berType + ".");
+
+        if ((berType.tagClass & CLASS_MASK) != berType.tagClass)
+            throw new RuntimeException("Value of BER tag class is out of range: " + berType.tagClass + ". Expected values: " + UNIVERSAL_CLASS + ", " + CONTEXT_CLASS
+                    + ", " + APPLICATION_CLASS + ", " + PRIVATE_CLASS + ".");
+
+        int typeAndFlags = berType.tagClass | ((berType.constructed) ? CONSTRUCTED : 0) | berType.typeOrTagNumber;
+
+        buf.writeByte(typeAndFlags);
+    }
+
+    /**
+     * Read tag value only, i.e. it prefix is already read, when value type is
+     * already read.
+     *
+     * @param buf
+     *          buffer with tag data
+     */
+    public abstract void readTagValue(ByteBuffer buf, BerType typeAndFlags);
+
+    /**
+     * Create deep copy of this tag with given suffix appended to name.
+     *
+     * @param suffix
+     *          suffix to add to tag name, or empty string
+     * @return deep copy of this tag
+     */
+    public abstract Tag deepCopy(String suffix);
+
+    /**
+     * Create deep copy of this tag for array or set.
+     *
+     * @param index
+     *          index of element in array or set
+     * @return deep copy of this tag
+     */
+    public Tag deepCopy(int index) {
+        return deepCopy("[" + index + "]");
+    }
+
+    /**
+     * Copy tag values from an other tag, except name.
+     *
+     * @return this
+     */
+    public Tag copyFrom(Tag tag) {
+        constructed = tag.constructed;
+        explicit = tag.explicit;
+        optional = tag.optional;
+        tagClass = tag.tagClass;
+        tagNumber = tag.tagNumber;
+        return this;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IncrementalOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IncrementalOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IncrementalOption.java
new file mode 100755
index 0000000..eb24d11
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IncrementalOption.java
@@ -0,0 +1,28 @@
+// 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 common.opt;
+
+public class IncrementalOption extends Option {
+    int value = 0;
+
+    @Override
+    public int parse(int position, String[] args) {
+        value++;
+        return super.parse(position, args);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IntOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IntOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IntOption.java
new file mode 100755
index 0000000..87e732a
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IntOption.java
@@ -0,0 +1,41 @@
+// 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 common.opt;
+
+public class IntOption extends Option {
+    public int value = 0;
+
+    @Override
+    public int parse(int position, String[] args) {
+        if (position + 1 >= args.length)
+            throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
+
+        value = Integer.parseInt(args[position + 1]);
+        return super.parse(position, args) + 1;
+    }
+
+    @Override
+    public String help() {
+        StringBuilder help = new StringBuilder();
+        help.append(join("|", name, alias, aliases)).append(" VALUE\t").append(description);
+        if (required)
+            help.append(" Required.");
+        else if (value != 0)
+            help.append(" Default value is \"").append("" + value).append("\".");
+        return help.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/NoArgumentForOptionException.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/NoArgumentForOptionException.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/NoArgumentForOptionException.java
new file mode 100755
index 0000000..a074672
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/NoArgumentForOptionException.java
@@ -0,0 +1,26 @@
+// 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 common.opt;
+
+public class NoArgumentForOptionException extends RuntimeException {
+    public NoArgumentForOptionException(String message) {
+        super(message);
+    }
+
+    private static final long serialVersionUID = 1L;
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/Option.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/Option.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/Option.java
new file mode 100755
index 0000000..e69d3f3
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/Option.java
@@ -0,0 +1,102 @@
+// 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 common.opt;
+
+public class Option {
+
+    public String name = "";
+    public String alias = null;
+    public String aliases[] = null;
+
+    public String description = "";
+    public boolean used = false;
+    public boolean required = false;
+
+    /**
+     * Parse option value, if any.
+     *
+     * @param position
+     *          position of this option in list of arguments
+     * @param args
+     *          command line arguments
+     * @return how many arguments are consumed, at least 1
+     */
+    public int parse(int position, String args[]) {
+        used = true;
+        return 1;
+    }
+
+    @Override
+    public String toString() {
+        return help();
+    }
+
+    /**
+     * Return help string for this option. Example:
+     *
+     * <pre>
+     *   --foo|-f    Foo option.
+     * </pre>
+     */
+    public String help() {
+        return join("|", name, alias, aliases) + "\t" + description + ((required) ? " Required." : "");
+    }
+
+    /**
+     * Return string like "--foo|-f|--another-foo-alias".
+     */
+    protected String join(String delim, String name, String alias, String aliases[]) {
+
+        // Option name is mandatory
+        StringBuilder sb = new StringBuilder(name.length());
+        sb.append(name);
+
+        // Alias is optional
+        if (alias != null && alias.length() > 0) {
+            sb.append(delim).append(alias);
+        }
+
+        // Other aliases are optional too
+        if (aliases != null) {
+            for (String s : aliases) {
+                if (s != null && s.length() > 0) {
+                    sb.append(delim).append(s);
+                }
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Return description of options in format suitable for help and usage text.
+     *
+     * @param header
+     *          header string to print before list of options
+     * @param options
+     *          list of options to print
+     */
+    public static String toHelp(String header, Option[] options) {
+        StringBuffer sb = new StringBuffer();
+        sb.append(header).append(":\n");
+        for (Option option : options) {
+            sb.append("  ").append(option.help()).append('\n');
+        }
+        return sb.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionParser.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionParser.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionParser.java
new file mode 100755
index 0000000..11c42fe
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionParser.java
@@ -0,0 +1,147 @@
+// 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 common.opt;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Simple parser of GNU-like options.
+ */
+public class OptionParser {
+
+    public static Option helpOption() {
+        return new Option() {
+            {
+                name = "--help";
+                alias = "-h";
+            }
+        };
+    }
+
+    /**
+     * Parse options, capture values and return rest of arguments.
+     *
+     * @param args
+     *          command line arguments to parse
+     * @param startFrom
+     *          number of first argument to start parsing from
+     * @param options
+     *          options to fill with values
+     * @return rest of command line after first non-option or "--" separator
+     */
+    public static String[] parseOptions(String args[], int startFrom, Option options[]) {
+        // Convert array of options into map, where key is option name or alias
+        Map<String, Option> optionMap = new HashMap<String, Option>(options.length);
+        for (Option option : options) {
+            optionMap.put(option.name, option);
+
+            if (option.alias != null)
+                optionMap.put(option.alias, option);
+
+            if (option.aliases != null) {
+                for (String alias : option.aliases)
+                    optionMap.put(alias, option);
+            }
+        }
+
+        // Parse arguments
+        int position = startFrom;
+        while (position < args.length) {
+            // Double dash means end of options
+            String optionName = args[position];
+            if (optionName.equals("--")) {
+                position++;
+                break;
+            }
+
+            Option option = optionMap.get(optionName);
+
+            // If option is not found, then this is argument, unless is starts with
+            // dash
+            if (option == null)
+                if (!optionName.startsWith("-"))
+                    break;
+                else
+                    throw new UnknownOptionException("Option \"" + optionName
+                            + "\" is unknown. If this is not an option, then use \"--\" to separate options and arguments. Known options: " + optionMap.keySet().toString());
+
+            position += option.parse(position, args);
+        }
+
+        // Check is required options are used on command line
+        for (Option option : options) {
+            if (option.required && !option.used)
+                throw new OptionRequiredException("Option \"" + option.name + "\" is required.");
+        }
+
+        // Return rest of arguments, which are left after options
+        return (position < args.length) ? Arrays.copyOfRange(args, position, args.length) : new String[] {};
+    }
+
+    /* Example. */
+    public static void main(String args[]) {
+        if (args.length == 0)
+            args = new String[] {"--help", "--foo", "fooval", "--bar", "123", "-v", "--verbose", "-v", "-a", "a1", "-aa", "a2", "-aaa", "a3", "rest", "of",
+        "arguments"};
+
+        StringOption foo = new StringOption() {
+            {
+                name = "--foo";
+                alias = "-f";
+                value = "fooDefault";
+            }
+        };
+
+        IntOption bar = new IntOption() {
+            {
+                name = "--bar";
+                alias = "-b";
+                value = 123;
+            }
+        };
+
+        IncrementalOption verbose = new IncrementalOption() {
+            {
+                name = "--verbose";
+                alias = "-v";
+            }
+        };
+
+        StringArrayOption array = new StringArrayOption() {
+            {
+                name = "--array";
+                alias = "-a";
+                aliases = new String[] {"-aa", "-aaa"};
+            }
+        };
+
+        String arguments[] = OptionParser.parseOptions(args, 0, new Option[] {helpOption(), foo, bar, verbose, array});
+
+        assertTrue(foo.value.equals("fooval"));
+        assertTrue(bar.value == 123);
+        assertTrue(verbose.value == 3);
+        assertTrue(Arrays.equals(array.value, new String[] {"a1", "a2", "a3"}));
+        assertTrue(Arrays.equals(arguments, new String[] {"rest", "of", "arguments"}));
+    }
+
+    public static void assertTrue(boolean result) {
+        if (!result)
+            throw new AssertionError();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionRequiredException.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionRequiredException.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionRequiredException.java
new file mode 100755
index 0000000..b397627
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionRequiredException.java
@@ -0,0 +1,26 @@
+// 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 common.opt;
+
+public class OptionRequiredException extends RuntimeException {
+    public OptionRequiredException(String message) {
+        super(message);
+    }
+
+    private static final long serialVersionUID = 1L;
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringArrayOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringArrayOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringArrayOption.java
new file mode 100755
index 0000000..b2f3c30
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringArrayOption.java
@@ -0,0 +1,38 @@
+// 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 common.opt;
+
+import java.util.Arrays;
+
+public class StringArrayOption extends Option {
+    public String value[] = null;
+
+    @Override
+    public int parse(int position, String[] args) {
+        if (position + 1 >= args.length)
+            throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
+
+        // Append value to end of array of values
+        if (value == null) {
+            value = new String[] {args[position + 1]};
+        } else {
+            value = Arrays.copyOf(value, value.length + 1);
+            value[value.length - 1] = args[position + 1];
+        }
+        return super.parse(position, args) + 1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringEnumerationOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringEnumerationOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringEnumerationOption.java
new file mode 100755
index 0000000..f59952e
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringEnumerationOption.java
@@ -0,0 +1,72 @@
+// 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 common.opt;
+
+public class StringEnumerationOption extends Option {
+    public String value = "";
+    public String choices[] = new String[] {};
+
+    @Override
+    public int parse(int position, String[] args) {
+        if (position + 1 >= args.length)
+            throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
+
+        value = args[position + 1];
+
+        for (String s : choices) {
+            if (value.equals(s))
+                return super.parse(position, args) + 1;
+        }
+
+        throw new NoArgumentForOptionException("Unexpected argument for option \"" + args[position] + "\": \"" + value + "\". Expected argument: "
+                + join("|", choices) + ".");
+    }
+
+    @Override
+    public String help() {
+        StringBuilder help = new StringBuilder();
+        help.append(join("|", name, alias, aliases)).append(" ").append(join("|", choices)).append("\t").append(description);
+        if (required)
+            help.append(" Required.");
+        else if (value != null && value.length() > 0)
+            help.append(" Default value is \"").append(value).append("\".");
+        return help.toString();
+    }
+
+    /**
+     * Join strings in array into one large string.
+     */
+    protected String join(String delim, String values[]) {
+        StringBuilder sb = new StringBuilder();
+        if (values != null) {
+            boolean first = true;
+            for (String s : values) {
+                if (s != null && s.length() > 0) {
+                    if (first)
+                        first = false;
+                    else
+                        sb.append(delim);
+
+                    sb.append(s);
+                }
+            }
+        }
+
+        return sb.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringOption.java
new file mode 100755
index 0000000..ec9c82c
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringOption.java
@@ -0,0 +1,41 @@
+// 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 common.opt;
+
+public class StringOption extends Option {
+    public String value = "";
+
+    @Override
+    public int parse(int position, String[] args) {
+        if (position + 1 >= args.length)
+            throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
+
+        value = args[position + 1];
+        return super.parse(position, args) + 1;
+    }
+
+    @Override
+    public String help() {
+        StringBuilder help = new StringBuilder();
+        help.append(join("|", name, alias, aliases)).append(" VALUE\t").append(description);
+        if (required)
+            help.append(" Required.");
+        else if (value != null && value.length() > 0)
+            help.append(" Default value is \"").append(value).append("\".");
+        return help.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/UnknownOptionException.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/UnknownOptionException.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/UnknownOptionException.java
new file mode 100755
index 0000000..58cce73
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/UnknownOptionException.java
@@ -0,0 +1,27 @@
+// 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 common.opt;
+
+public class UnknownOptionException extends RuntimeException {
+
+    public UnknownOptionException(String message) {
+        super(message);
+    }
+
+    private static final long serialVersionUID = 1L;
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java
deleted file mode 100644
index 06449f6..0000000
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java
+++ /dev/null
@@ -1,350 +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 rdpclient;
-
-import java.awt.event.KeyEvent;
-
-import streamer.BaseElement;
-import streamer.ByteBuffer;
-import streamer.Link;
-import common.KeyOrder;
-
-public class AwtRdpKeyboardAdapter extends BaseElement {
-
-    /**
-     * Absence of this flag indicates a key-down event, while its presence
-     * indicates a key-release event.
-     */
-    public static final int FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01;
-
-    /**
-     * Keystroke message contains an extended scancode. For enhanced 101-key and
-     * 102-key keyboards, extended keys include the right ALT and right CTRL keys
-     * on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE
-     * DOWN and ARROW keys in the clusters to the left of the numeric keypad; and
-     * the Divide ("/") and ENTER keys in the numeric keypad.
-     */
-    public static final int FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02;
-
-    public static final int FASTPATH_INPUT_EVENT_SCANCODE = 0;
-
-    public AwtRdpKeyboardAdapter(String id) {
-        super(id);
-    }
-
-    @Override
-    public void handleData(ByteBuffer buf, Link link) {
-        if (verbose)
-            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
-
-        KeyOrder order = (KeyOrder)buf.getOrder();
-        buf.unref();
-
-        ByteBuffer outBuf = new ByteBuffer(2, true);
-
-        int scanCode = map_en_us(order.event);
-
-        // eventHeader (1 byte): An 8-bit, unsigned integer. The format of this
-        // field is the same as the eventHeader byte field described in section
-        // 2.2.8.1.2.2. The eventCode bitfield (3 bits in size) MUST be set to
-        // FASTPATH_INPUT_EVENT_SCANCODE (0). The eventFlags bitfield (5 bits in
-        // size) contains flags describing the keyboard event.
-        outBuf.writeByte((scanCode >> 8) | (FASTPATH_INPUT_EVENT_SCANCODE << 5) | ((order.pressed) ? 0 : FASTPATH_INPUT_KBDFLAGS_RELEASE));
-
-        // keyCode (1 byte): An 8-bit, unsigned integer. The scancode of the key
-        // which triggered the event.
-        outBuf.writeByte(scanCode);
-
-        // Push buffer to one pad only, so it can be modified without copying of
-        // data
-        pushDataToPad(STDOUT, outBuf);
-    }
-
-    /**
-     * Return key scan code (in lower byte) and extended flags (in second byte).
-     */
-    private int map_en_us(KeyEvent event) {
-        // Also set extended key flag when necessary.
-        // For enhanced 101-key and 102-key keyboards, extended keys include the
-        // right ALT and right CTRL keys on the main section of the keyboard; the
-        // INS, DEL, HOME, END, PAGE UP, PAGE DOWN and ARROW keys in the clusters to
-        // the left of the numeric keypad; and the Divide ("/") and ENTER keys in
-        // the numeric keypad.
-
-        switch (event.getKeyCode()) {
-        // Functional keys
-            case KeyEvent.VK_ESCAPE:
-                return 1;
-            case KeyEvent.VK_F1:
-                return 59;
-            case KeyEvent.VK_F2:
-                return 60;
-            case KeyEvent.VK_F3:
-                return 61;
-            case KeyEvent.VK_F4:
-                return 62;
-            case KeyEvent.VK_F5:
-                return 63;
-            case KeyEvent.VK_F6:
-                return 64;
-            case KeyEvent.VK_F7:
-                return 65;
-            case KeyEvent.VK_F8:
-                return 66;
-            case KeyEvent.VK_F9:
-                return 67;
-            case KeyEvent.VK_F10:
-                return 68;
-            case KeyEvent.VK_F11:
-                return 87;
-            case KeyEvent.VK_F12:
-                return 88;
-
-                // Row #1
-            case KeyEvent.VK_BACK_QUOTE:
-                return 41;
-            case KeyEvent.VK_1:
-                return 2;
-            case KeyEvent.VK_2:
-                return 3;
-            case KeyEvent.VK_3:
-                return 4;
-            case KeyEvent.VK_4:
-                return 5;
-            case KeyEvent.VK_5:
-                return 6;
-            case KeyEvent.VK_6:
-                return 7;
-            case KeyEvent.VK_7:
-                return 8;
-            case KeyEvent.VK_8:
-                return 9;
-            case KeyEvent.VK_9:
-                return 10;
-            case KeyEvent.VK_0:
-                return 11;
-            case KeyEvent.VK_MINUS:
-                return 12;
-            case KeyEvent.VK_EQUALS:
-                return 13;
-            case KeyEvent.VK_BACK_SPACE:
-                return 14;
-
-                // Row #2
-            case KeyEvent.VK_TAB:
-                return 15;
-            case KeyEvent.VK_Q:
-                return 16;
-            case KeyEvent.VK_W:
-                return 17;
-            case KeyEvent.VK_E:
-                return 18;
-            case KeyEvent.VK_R:
-                return 19;
-            case KeyEvent.VK_T:
-                return 20;
-            case KeyEvent.VK_Y:
-                return 21;
-            case KeyEvent.VK_U:
-                return 22;
-            case KeyEvent.VK_I:
-                return 23;
-            case KeyEvent.VK_O:
-                return 24;
-            case KeyEvent.VK_P:
-                return 25;
-            case KeyEvent.VK_OPEN_BRACKET:
-                return 26;
-            case KeyEvent.VK_CLOSE_BRACKET:
-                return 27;
-            case KeyEvent.VK_ENTER:
-                switch (event.getKeyLocation()) {
-                    default:
-                    case KeyEvent.KEY_LOCATION_STANDARD:
-                        return 28;
-                    case KeyEvent.KEY_LOCATION_NUMPAD:
-                        return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 28;
-                }
-
-                // Row #3
-            case KeyEvent.VK_CAPS_LOCK:
-                return 58;
-            case KeyEvent.VK_A:
-                return 30;
-            case KeyEvent.VK_S:
-                return 31;
-            case KeyEvent.VK_D:
-                return 32;
-            case KeyEvent.VK_F:
-                return 33;
-            case KeyEvent.VK_G:
-                return 34;
-            case KeyEvent.VK_H:
-                return 35;
-            case KeyEvent.VK_J:
-                return 36;
-            case KeyEvent.VK_K:
-                return 37;
-            case KeyEvent.VK_L:
-                return 38;
-            case KeyEvent.VK_SEMICOLON:
-                return 39;
-            case KeyEvent.VK_QUOTE:
-                return 40;
-
-                // Row #4
-            case KeyEvent.VK_SHIFT:
-                switch (event.getKeyLocation()) {
-                    default:
-                    case KeyEvent.KEY_LOCATION_LEFT:
-                        return 42;
-                    case KeyEvent.KEY_LOCATION_RIGHT:
-                        return 54;
-                }
-            case KeyEvent.VK_BACK_SLASH:
-                return 43;
-            case KeyEvent.VK_Z:
-                return 44;
-            case KeyEvent.VK_X:
-                return 45;
-            case KeyEvent.VK_C:
-                return 46;
-            case KeyEvent.VK_V:
-                return 47;
-            case KeyEvent.VK_B:
-                return 48;
-            case KeyEvent.VK_N:
-                return 49;
-            case KeyEvent.VK_M:
-                return 50;
-            case KeyEvent.VK_COMMA:
-                return 51;
-            case KeyEvent.VK_PERIOD:
-                return 52;
-            case KeyEvent.VK_SLASH:
-                return 53;
-
-                //
-                // Bottom row
-            case KeyEvent.VK_CONTROL:
-                switch (event.getKeyLocation()) {
-                    default:
-                    case KeyEvent.KEY_LOCATION_LEFT:
-                        return 29;
-                    case KeyEvent.KEY_LOCATION_RIGHT:
-                        return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 29;
-                }
-            case KeyEvent.VK_WINDOWS:
-                switch (event.getKeyLocation()) {
-                    default:
-                    case KeyEvent.KEY_LOCATION_LEFT:
-                        return 91;
-                    case KeyEvent.KEY_LOCATION_RIGHT:
-                        return 92;
-                }
-            case KeyEvent.VK_ALT:
-                switch (event.getKeyLocation()) {
-                    default:
-                    case KeyEvent.KEY_LOCATION_LEFT:
-                        return 56;
-                    case KeyEvent.KEY_LOCATION_RIGHT:
-                        return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
-                }
-            case KeyEvent.VK_ALT_GRAPH:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
-
-            case KeyEvent.VK_SPACE:
-                return 57;
-
-            case KeyEvent.VK_CONTEXT_MENU:
-                return 93;
-
-                //
-                // Special keys
-            case KeyEvent.VK_PRINTSCREEN:
-                return 55;
-            case KeyEvent.VK_SCROLL_LOCK:
-                return 70;
-            case KeyEvent.VK_PAUSE:
-                return 29;
-
-                // Text navigation keys
-            case KeyEvent.VK_INSERT:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 82;
-            case KeyEvent.VK_HOME:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 71;
-            case KeyEvent.VK_PAGE_UP:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 73;
-            case KeyEvent.VK_DELETE:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 83;
-            case KeyEvent.VK_END:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 79;
-            case KeyEvent.VK_PAGE_DOWN:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 81;
-
-                // Cursor keys
-            case KeyEvent.VK_UP:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 72;
-            case KeyEvent.VK_LEFT:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 75;
-            case KeyEvent.VK_DOWN:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 80;
-            case KeyEvent.VK_RIGHT:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 77;
-
-                // Keypad
-            case KeyEvent.VK_NUM_LOCK:
-                return 69;
-            case KeyEvent.VK_DIVIDE:
-                return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 53;
-            case KeyEvent.VK_MULTIPLY:
-                return 55;
-            case KeyEvent.VK_SUBTRACT:
-                return 74;
-            case KeyEvent.VK_ADD:
-                return 78;
-
-            case KeyEvent.VK_NUMPAD7:
-                return 71;
-            case KeyEvent.VK_NUMPAD8:
-                return 72;
-            case KeyEvent.VK_NUMPAD9:
-                return 73;
-            case KeyEvent.VK_NUMPAD4:
-                return 75;
-            case KeyEvent.VK_NUMPAD5:
-                return 76;
-            case KeyEvent.VK_NUMPAD6:
-                return 77;
-            case KeyEvent.VK_NUMPAD1:
-                return 79;
-            case KeyEvent.VK_NUMPAD2:
-                return 80;
-            case KeyEvent.VK_NUMPAD3:
-                return 81;
-            case KeyEvent.VK_NUMPAD0:
-                return 82;
-            case KeyEvent.VK_DECIMAL:
-                return 83;
-
-            default:
-                System.err.println("Key is not mapped: " + event + ".");
-                return 57; // Space
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java
deleted file mode 100644
index f533906..0000000
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java
+++ /dev/null
@@ -1,179 +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 rdpclient;
-
-import java.awt.event.InputEvent;
-
-import streamer.BaseElement;
-import streamer.ByteBuffer;
-import streamer.Link;
-import common.MouseOrder;
-
-/**
- * @see http://msdn.microsoft.com/en-us/library/cc240594.aspx
- */
-public class AwtRdpMouseAdapter extends BaseElement {
-    public static final int FASTPATH_INPUT_EVENT_MOUSE = 0x01;
-
-    /**
-     * Event is a mouse wheel rotation. The only valid flags in a wheel rotation
-     * event are PTRFLAGS_WHEEL_NEGATIVE and the WheelRotationMask; all other
-     * pointer flags are ignored.
-     */
-    public static final int PTRFLAGS_WHEEL = 0x0200;
-
-    /**
-     * Wheel rotation value (contained in the WheelRotationMask bit field) is
-     * negative and MUST be sign-extended before injection at the server.
-     */
-    public static final int PTRFLAGS_WHEEL_NEGATIVE = 0x0100;
-
-    /**
-     * Bit field describing the number of rotation units the mouse wheel was
-     * rotated. The value is negative if the PTRFLAGS_WHEEL_NEGATIVE flag is set.
-     */
-    public static final int WHEEL_ROTATION_MASK = 0x01FF;
-
-    /**
-     * Indicates that the mouse position MUST be updated to the location specified
-     * by the xPos and yPos fields.
-     */
-    public static final int PTRFLAGS_MOVE = 0x0800;
-
-    /**
-     * Indicates that a click event has occurred at the position specified by the
-     * xPos and yPos fields. The button flags indicate which button has been
-     * clicked and at least one of these flags MUST be set.
-     */
-    public static final int PTRFLAGS_DOWN = 0x8000;
-
-    /**
-     * Mouse button 1 (left button) was clicked or released. If the PTRFLAGS_DOWN
-     * flag is set, then the button was clicked, otherwise it was released.
-     */
-    public static final int PTRFLAGS_BUTTON1 = 0x1000;
-
-    /**
-     * Mouse button 2 (right button) was clicked or released. If the PTRFLAGS_DOWN
-     * flag is set, then the button was clicked, otherwise it was released.
-     */
-    public static final int PTRFLAGS_BUTTON2 = 0x2000;
-
-    /**
-     * Mouse button 3 (middle button or wheel) was clicked or released. If the
-     * PTRFLAGS_DOWN flag is set, then the button was clicked, otherwise it was
-     * released.
-     */
-    public static final int PTRFLAGS_BUTTON3 = 0x4000;
-
-    public AwtRdpMouseAdapter(String id) {
-        super(id);
-    }
-
-    @Override
-    public void handleData(ByteBuffer buf, Link link) {
-        if (verbose)
-            System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
-
-        // Get mouse event
-        MouseOrder order = (MouseOrder)buf.getOrder();
-
-        ByteBuffer outBuf = new ByteBuffer(7, true);
-
-        // eventHeader (1 byte): An 8-bit, unsigned integer. EventCode bitfield (top
-        // 3 bits) MUST be set to FASTPATH_INPUT_EVENT_MOUSE (1). The
-        // eventFlags bitfield (low 5 bits) MUST be zeroed out.
-        outBuf.writeByte(FASTPATH_INPUT_EVENT_MOUSE << 5);
-
-        // pointerFlags (2 bytes): A 16-bit, unsigned integer.
-        outBuf.writeShortLE(getPointerFlags(order));
-
-        // xPos (2 bytes): A 16-bit, unsigned integer. The x-coordinate of the
-        // pointer.
-        outBuf.writeShortLE(order.event.getX());
-
-        // yPos (2 bytes): A 16-bit, unsigned integer. The y-coordinate of the
-        // pointer.
-        outBuf.writeShortLE(order.event.getY());
-
-        // Push buffer to one pad only, so it can be modified without copying of
-        // data
-        pushDataToPad(STDOUT, outBuf);
-    }
-
-    // Remember mouse buttons
-    protected boolean button1, button2, button3;
-
-    protected int getPointerFlags(MouseOrder order) {
-        int flags = 0;
-
-        int modifiers = order.event.getModifiersEx();
-
-        if (order.pressed) {
-            // Mouse pressed
-            flags |= PTRFLAGS_DOWN;
-
-            // Check, which one of buttons is released
-            boolean b1 = ((modifiers & InputEvent.BUTTON1_DOWN_MASK) > 0) && !button1;
-            boolean b2 = ((modifiers & InputEvent.BUTTON2_DOWN_MASK) > 0) && !button2;
-            boolean b3 = ((modifiers & InputEvent.BUTTON3_DOWN_MASK) > 0) && !button3;
-
-            if (b1) {
-                flags |= PTRFLAGS_BUTTON1;
-                button1 = true;
-            }
-
-            if (b2) {
-                flags |= PTRFLAGS_BUTTON3;
-                button2 = true;
-            }
-
-            if (b3) {
-                flags |= PTRFLAGS_BUTTON2;
-                button3 = true;
-            }
-        } else if (order.released) {
-            // Mouse released
-
-            // Check, which one of buttons is released
-            boolean b1 = !((modifiers & InputEvent.BUTTON1_DOWN_MASK) > 0) && button1;
-            boolean b2 = !((modifiers & InputEvent.BUTTON2_DOWN_MASK) > 0) && button2;
-            boolean b3 = !((modifiers & InputEvent.BUTTON3_DOWN_MASK) > 0) && button3;
-
-            if (b1) {
-                flags |= PTRFLAGS_BUTTON1;
-                button1 = false;
-            }
-
-            if (b2) {
-                flags |= PTRFLAGS_BUTTON3;
-                button2 = false;
-            }
-
-            if (b3) {
-                flags |= PTRFLAGS_BUTTON2;
-                button3 = false;
-            }
-        } else {
-            // Mouse moved
-            flags |= PTRFLAGS_MOVE;
-        }
-
-        return flags;
-    }
-
-}