You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by hu...@apache.org on 2014/01/03 11:17:45 UTC
[12/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/vncclient/VncInitializer.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/VncInitializer.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/VncInitializer.java
deleted file mode 100644
index 25631c2..0000000
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/VncInitializer.java
+++ /dev/null
@@ -1,245 +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 vncclient;
-
-import streamer.ByteBuffer;
-import streamer.Element;
-import streamer.Link;
-import streamer.MockSink;
-import streamer.MockSource;
-import streamer.OneTimeSwitch;
-import streamer.Pipeline;
-import streamer.PipelineImpl;
-import common.ScreenDescription;
-
-public class VncInitializer extends OneTimeSwitch {
-
- // Pad names
- public static final String CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD = "encodings";
- public static final String CLIENT_PIXEL_FORMAT_ADAPTER_PAD = "pixel_format";
-
- protected byte sharedFlag = RfbConstants.EXCLUSIVE_ACCESS;
-
- /**
- * Properties of remote screen .
- */
- protected ScreenDescription screen;
-
- public VncInitializer(String id, boolean shared, ScreenDescription screen) {
- super(id);
-
- setSharedFlag(shared);
- this.screen = screen;
-
- declarePads();
- }
-
- @Override
- protected void declarePads() {
- super.declarePads();
- outputPads.put(CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD, null);
- outputPads.put(CLIENT_PIXEL_FORMAT_ADAPTER_PAD, null);
- }
-
- public ScreenDescription getScreen() {
- return screen;
- }
-
- public void setScreen(ScreenDescription screen) {
- this.screen = screen;
- }
-
- public void setSharedFlag(boolean shared) {
- if (shared)
- sharedFlag = RfbConstants.SHARED_ACCESS;
- else
- sharedFlag = RfbConstants.EXCLUSIVE_ACCESS;
- }
-
- @Override
- protected void handleOneTimeData(ByteBuffer buf, Link link) {
- if (verbose)
- System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
-
- // Server initialization message is at least 24 bytes long + length of
- // desktop name
- if (!cap(buf, 24, UNLIMITED, link, false))
- return;
-
- // Read server initialization message
- // Read frame buffer size
- int framebufferWidth = buf.readUnsignedShort();
- int framebufferHeight = buf.readUnsignedShort();
-
- // Read pixel format
- int bitsPerPixel = buf.readUnsignedByte();
- int depth = buf.readUnsignedByte();
-
- int bigEndianFlag = buf.readUnsignedByte();
- int trueColorFlag = buf.readUnsignedByte();
-
- int redMax = buf.readUnsignedShort();
- int greenMax = buf.readUnsignedShort();
- int blueMax = buf.readUnsignedShort();
-
- int redShift = buf.readUnsignedByte();
- int greenShift = buf.readUnsignedByte();
- int blueShift = buf.readUnsignedByte();
-
- // Skip padding
- buf.skipBytes(3);
-
- // Read desktop name
- int length = buf.readSignedInt();
-
- // Consume exactly $length bytes, push back any extra bytes
- if (!cap(buf, length, length, link, true))
- return;
-
- String desktopName = buf.readString(length, RfbConstants.US_ASCII_CHARSET);
- buf.unref();
- if (verbose)
- System.out.println("[" + this + "] INFO: Desktop name: \"" + desktopName + "\", bpp: " + bitsPerPixel + ", depth: " + depth + ", screen size: " +
- framebufferWidth + "x" + framebufferHeight + ".");
-
- // Set screen properties
- screen.setFramebufferSize(framebufferWidth, framebufferHeight);
- screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag != RfbConstants.LITTLE_ENDIAN, trueColorFlag == RfbConstants.TRUE_COLOR, redMax, greenMax, blueMax,
- redShift, greenShift, blueShift);
- screen.setDesktopName(desktopName);
-
- // If sever screen has different parameters than ours, then change it
- if (!screen.isRGB888_32_LE()) {
- // Send client pixel format
- sendClientPixelFormat();
- }
-
- // Send encodings supported by client
- sendSupportedEncodings();
-
- switchOff();
-
- }
-
- @Override
- protected void onStart() {
- ByteBuffer buf = new ByteBuffer(new byte[] {sharedFlag});
- pushDataToOTOut(buf);
- }
-
- private void sendClientPixelFormat() {
- pushDataToPad(CLIENT_PIXEL_FORMAT_ADAPTER_PAD, new ByteBuffer(0));
- }
-
- private void sendSupportedEncodings() {
- pushDataToPad(CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD, new ByteBuffer(0));
- }
-
- @Override
- public String toString() {
- return "VncInit(" + id + ")";
- }
-
- /**
- * 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");
-
- final String desktopName = "test";
-
- Element source = new MockSource("source") {
- {
- bufs = ByteBuffer.convertByteArraysToByteBuffers(
- // Send screen description
- new byte[] {
- // Framebuffer width (short)
- 0, (byte)200,
- // Framebuffer height (short)
- 0, 100,
- // Bits per pixel
- 32,
- // Depth,
- 24,
- // Endianness flag
- RfbConstants.LITTLE_ENDIAN,
- // Truecolor flag
- RfbConstants.TRUE_COLOR,
- // Red max (short)
- 0, (byte)255,
- // Green max (short)
- 0, (byte)255,
- // Blue max (short)
- 0, (byte)255,
- // Red shift
- 16,
- // Green shift
- 8,
- // Blue shift
- 0,
- // Padding
- 0, 0, 0,
- // Desktop name length (int)
- 0, 0, 0, 4,
- // Desktop name ("test", 4 bytes)
- 't', 'e', 's', 't',
-
- // Tail
- 1, 2, 3
-
- },
- // Tail packet
- new byte[] {4, 5, 6});
- }
- };
-
- ScreenDescription screen = new ScreenDescription();
- final VncInitializer init = new VncInitializer("init", true, screen);
- Element initSink = new MockSink("initSink") {
- {
- // Expect shared flag
- bufs = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {RfbConstants.SHARED_ACCESS});
- }
- };
- Element mainSink = new MockSink("mainSink") {
- {
- // Expect two tail packets
- bufs = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}, new byte[] {4, 5, 6});
- }
- };
- ByteBuffer[] emptyBuf = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {});
- Element encodingsSink = new MockSink("encodings", emptyBuf);
- Element pixelFormatSink = new MockSink("pixel_format", emptyBuf);
-
- Pipeline pipeline = new PipelineImpl("test");
- pipeline.addAndLink(source, init, mainSink);
- pipeline.add(encodingsSink, pixelFormatSink, initSink);
- pipeline.link("init >otout", "initSink");
- pipeline.link("init >" + CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD, "encodings");
- pipeline.link("init >" + CLIENT_PIXEL_FORMAT_ADAPTER_PAD, "pixel_format");
-
- pipeline.runMainLoop("source", STDOUT, false, false);
-
- if (!screen.isRGB888_32_LE())
- System.err.println("Screen description was read incorrectly: " + screen + ".");
- if (!desktopName.equals(screen.getDesktopName()))
- System.err.println("Screen desktop name was read incorrectly: \"" + screen.getDesktopName() + "\".");
-
- }
-}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/VncMessageHandler.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/VncMessageHandler.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/VncMessageHandler.java
deleted file mode 100644
index 6421fb2..0000000
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/VncMessageHandler.java
+++ /dev/null
@@ -1,420 +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 vncclient;
-
-import streamer.BaseElement;
-import streamer.ByteBuffer;
-import streamer.Element;
-import streamer.Link;
-import streamer.MockSink;
-import streamer.MockSource;
-import streamer.Pipeline;
-import streamer.PipelineImpl;
-import common.BitmapOrder;
-import common.BitmapRectangle;
-import common.CopyRectOrder;
-import common.ScreenDescription;
-
-public class VncMessageHandler extends BaseElement {
- protected ScreenDescription screen = null;
-
- // Pad names
- public static final String SERVER_BELL_ADAPTER_PAD = "bell";
- public static final String SERVER_CLIPBOARD_ADAPTER_PAD = "clipboard";
- public static final String PIXEL_ADAPTER_PAD = "pixels";
- public static final String FRAME_BUFFER_UPDATE_REQUEST_ADAPTER_PAD = "fbur";
-
- // Keys for metadata
- public static final String CLIPBOARD_CONTENT = "content";
- public static final String TARGET_X = "x";
- public static final String TARGET_Y = "y";
- public static final String WIDTH = "width";
- public static final String HEIGHT = "height";
- public static final String SOURCE_X = "srcX";
- public static final String SOURCE_Y = "srcY";
- public static final String PIXEL_FORMAT = "pixel_format";
-
- private static final String NUM_OF_PROCESSED_RECTANGLES = "rects";
- private static final String SAVED_CURSOR_POSITION = "cursor";
-
- // Pixel format: RGB888 LE 32
- public static final String RGB888LE32 = "RGB888LE32";
-
- public VncMessageHandler(String id, ScreenDescription screen) {
- super(id);
- this.screen = screen;
- declarePads();
- }
-
- private void declarePads() {
- outputPads.put(SERVER_BELL_ADAPTER_PAD, null);
- outputPads.put(SERVER_BELL_ADAPTER_PAD, null);
- outputPads.put(SERVER_CLIPBOARD_ADAPTER_PAD, null);
- outputPads.put(PIXEL_ADAPTER_PAD, null);
- outputPads.put(FRAME_BUFFER_UPDATE_REQUEST_ADAPTER_PAD, null);
-
- inputPads.put("stdin", null);
- }
-
- @Override
- public void handleData(ByteBuffer buf, Link link) {
- if (buf == null)
- return;
-
- try {
- if (verbose)
- System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
-
- if (!cap(buf, 1, UNLIMITED, link, false))
- return;
-
- // Read server message type
- int messageType = buf.readUnsignedByte();
-
- // Invoke packet handler by packet type.
- switch (messageType) {
-
- case RfbConstants.SERVER_FRAMEBUFFER_UPDATE: {
- // Handle frame buffer update
- if (!handleFBU(buf, link))
- return;
-
- // Frame buffer update is received and fully processed, send request for
- // another frame buffer update to server.
- sendFBUR();
-
- break;
- }
-
- case RfbConstants.SERVER_BELL: {
- if (!handleBell(buf, link))
- return;
- break;
- }
-
- case RfbConstants.SERVER_CUT_TEXT: {
- if (!handleClipboard(buf, link))
- return;
- break;
- }
-
- default:
- // TODO: allow to extend functionality
- throw new RuntimeException("Unknown server packet type: " + messageType + ".");
- }
-
- // Cut tail, if any
- cap(buf, 0, 0, link, true);
- } finally {
-
- // Return processed buffer back to pool
- buf.unref();
- }
- }
-
- private boolean handleClipboard(ByteBuffer buf, Link link) {
- if (!cap(buf, 3 + 4, UNLIMITED, link, true))
- return false;
-
- // Skip padding
- buf.skipBytes(3);
-
- // Read text length
- int length = buf.readSignedInt();
-
- // We need full string to parse it
- if (!cap(buf, length, UNLIMITED, link, true))
- return false;
-
- String content = buf.readString(length, RfbConstants.US_ASCII_CHARSET);
-
- // Send content in metadata
- ByteBuffer outBuf = new ByteBuffer(0);
- outBuf.putMetadata(CLIPBOARD_CONTENT, content);
-
- pushDataToPad(SERVER_CLIPBOARD_ADAPTER_PAD, outBuf);
-
- return true;
- }
-
- private boolean handleBell(ByteBuffer buf, Link link) {
- // Send empty packet to bell adapter to produce bell
- pushDataToPad(SERVER_BELL_ADAPTER_PAD, new ByteBuffer(0));
-
- return true;
- }
-
- // FIXME: this method is too complex
- private boolean handleFBU(ByteBuffer buf, Link link) {
-
- // We need at least 3 bytes here, 1 - padding, 2 - number of rectangles
- if (!cap(buf, 3, UNLIMITED, link, true))
- return false;
-
- buf.skipBytes(1);// Skip padding
-
- // Read number of rectangles
- int numberOfRectangles = buf.readUnsignedShort();
-
- if (verbose)
- System.out.println("[" + this + "] INFO: Frame buffer update. Number of rectangles: " + numberOfRectangles + ".");
-
- // Each rectangle must have header at least, header length is 12 bytes.
- if (!cap(buf, 12 * numberOfRectangles, UNLIMITED, link, true))
- return false;
-
- // For all rectangles
-
- // Restore saved point, to avoid flickering and performance problems when
- // frame buffer update is split between few incoming packets.
- int numberOfProcessedRectangles = (buf.getMetadata(NUM_OF_PROCESSED_RECTANGLES) != null) ? (Integer)buf.getMetadata(NUM_OF_PROCESSED_RECTANGLES) : 0;
- if (buf.getMetadata(SAVED_CURSOR_POSITION) != null)
- buf.cursor = (Integer)buf.getMetadata(SAVED_CURSOR_POSITION);
-
- if (verbose && numberOfProcessedRectangles > 0)
- System.out.println("[" + this + "] INFO: Restarting from saved point. Number of already processed rectangles: " + numberOfRectangles + ", cursor: " +
- buf.cursor + ".");
-
- // For all new rectangles
- for (int i = numberOfProcessedRectangles; i < numberOfRectangles; i++) {
-
- // We need coordinates of rectangle (2x4 bytes) and encoding type (4
- // bytes)
- if (!cap(buf, 12, UNLIMITED, link, true))
- return false;
-
- // Read coordinates of rectangle
- int x = buf.readUnsignedShort();
- int y = buf.readUnsignedShort();
- int width = buf.readUnsignedShort();
- int height = buf.readUnsignedShort();
-
- // Read rectangle encoding
- int encodingType = buf.readSignedInt();
-
- // Process rectangle
- switch (encodingType) {
-
- case RfbConstants.ENCODING_RAW: {
- if (!handleRawRectangle(buf, link, x, y, width, height))
- return false;
- break;
- }
-
- case RfbConstants.ENCODING_COPY_RECT: {
- if (!handleCopyRect(buf, link, x, y, width, height))
- return false;
- break;
- }
-
- case RfbConstants.ENCODING_DESKTOP_SIZE: {
- if (!handleScreenSizeChangeRect(buf, link, x, y, width, height))
- return false;
- break;
- }
-
- default:
- // TODO: allow to extend functionality
- throw new RuntimeException("Unsupported ecnoding: " + encodingType + ".");
- }
-
- // Update information about processed rectangles to avoid handling of same
- // rectangle multiple times.
- // TODO: push back partial rectangle only instead
- buf.putMetadata(NUM_OF_PROCESSED_RECTANGLES, ++numberOfProcessedRectangles);
- buf.putMetadata(SAVED_CURSOR_POSITION, buf.cursor);
- }
-
- return true;
- }
-
- private boolean handleScreenSizeChangeRect(ByteBuffer buf, Link link, int x, int y, int width, int height) {
- // Remote screen size is changed
- if (verbose)
- System.out.println("[" + this + "] INFO: Screen size rect. Width: " + width + ", height: " + height + ".");
-
- screen.setFramebufferSize(width, height);
-
- return true;
- }
-
- private boolean handleCopyRect(ByteBuffer buf, Link link, int x, int y, int width, int height) {
- // Copy rectangle from one part of screen to another.
- // Areas may overlap. Antialiasing may cause visible artifacts.
-
- // We need 4 bytes with coordinates of source rectangle
- if (!cap(buf, 4, UNLIMITED, link, true))
- return false;
-
- CopyRectOrder order = new CopyRectOrder();
-
- order.srcX = buf.readUnsignedShort();
- order.srcY = buf.readUnsignedShort();
- order.x = x;
- order.y = y;
- order.width = width;
- order.height = height;
-
- if (verbose)
- System.out.println("[" + this + "] INFO: Copy rect. X: " + x + ", y: " + y + ", width: " + width + ", height: " + height + ", srcX: " + order.srcX +
- ", srcY: " + order.srcY + ".");
-
- pushDataToPad(PIXEL_ADAPTER_PAD, new ByteBuffer(order));
-
- return true;
- }
-
- private boolean handleRawRectangle(ByteBuffer buf, Link link, int x, int y, int width, int height) {
- // Raw rectangle is just array of pixels to draw on screen.
- int rectDataLength = width * height * screen.getBytesPerPixel();
-
- // We need at least rectDataLength bytes. Extra bytes may contain other
- // rectangles.
- if (!cap(buf, rectDataLength, UNLIMITED, link, true))
- return false;
-
- if (verbose)
- System.out.println("[" + this + "] INFO: Raw rect. X: " + x + ", y: " + y + ", width: " + width + ", height: " + height + ", data length: " + rectDataLength +
- ".");
-
- BitmapRectangle rectangle = new BitmapRectangle();
- rectangle.x = x;
- rectangle.y = y;
- rectangle.width = width;
- rectangle.height = height;
- rectangle.bufferWidth = width;
- rectangle.bufferHeight = height;
- rectangle.bitmapDataStream = buf.readBytes(rectDataLength);
- rectangle.colorDepth = screen.getColorDeph();
-
- BitmapOrder order = new BitmapOrder();
- order.rectangles = new BitmapRectangle[] {rectangle};
-
- pushDataToPad(PIXEL_ADAPTER_PAD, new ByteBuffer(order));
- return true;
- }
-
- @Override
- public void onStart() {
- // Send Frame Buffer Update request
- sendFBUR();
- }
-
- private void sendFBUR() {
- ByteBuffer buf = new ByteBuffer(0);
- buf.putMetadata("incremental", true);
- pushDataToPad(FRAME_BUFFER_UPDATE_REQUEST_ADAPTER_PAD, buf);
- }
-
- @Override
- public String toString() {
- return "VNCMessageHandler(" + id + ")";
- }
-
- /**
- * 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");
-
- Element source = new MockSource("source") {
- {
- // Split messages at random boundaries to check "pushback" logic
- bufs =
- ByteBuffer.convertByteArraysToByteBuffers(new byte[] {
- // Message type: server bell
- RfbConstants.SERVER_BELL,
-
- // Message type: clipboard text
- RfbConstants.SERVER_CUT_TEXT,
- // Padding
- 0, 0, 0,
- // Length (test)
- 0, 0, 0, 4,
-
- }, new byte[] {
- // Clipboard text
- 't', 'e', 's', 't',
-
- // Message type: frame buffer update
- RfbConstants.SERVER_FRAMEBUFFER_UPDATE,
- // Padding
- 0,
- // Number of rectangles
- 0, 3,},
-
- new byte[] {
-
- // x, y, width, height: 0x0@4x4
- 0, 0, 0, 0, 0, 4, 0, 4,
- // Encoding: desktop size
- (byte)((RfbConstants.ENCODING_DESKTOP_SIZE >> 24) & 0xff), (byte)((RfbConstants.ENCODING_DESKTOP_SIZE >> 16) & 0xff),
- (byte)((RfbConstants.ENCODING_DESKTOP_SIZE >> 8) & 0xff), (byte)((RfbConstants.ENCODING_DESKTOP_SIZE >> 0) & 0xff),},
-
- new byte[] {
-
- // x, y, width, height: 0x0@4x4
- 0, 0, 0, 0, 0, 4, 0, 4,
- // Encoding: raw rect
- (byte)((RfbConstants.ENCODING_RAW >> 24) & 0xff), (byte)((RfbConstants.ENCODING_RAW >> 16) & 0xff),
- (byte)((RfbConstants.ENCODING_RAW >> 8) & 0xff), (byte)((RfbConstants.ENCODING_RAW >> 0) & 0xff),
- // Raw pixel data 4x4x1 bpp
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,}, new byte[] {11, 12, 13, 14, 15, 16,
-
- // x, y, width, height: 0x0@2x2
- 0, 0, 0, 0, 0, 2, 0, 2,
- // Encoding: copy rect
- (byte)((RfbConstants.ENCODING_COPY_RECT >> 24) & 0xff), (byte)((RfbConstants.ENCODING_COPY_RECT >> 16) & 0xff),
- (byte)((RfbConstants.ENCODING_COPY_RECT >> 8) & 0xff), (byte)((RfbConstants.ENCODING_COPY_RECT >> 0) & 0xff),
- // srcX, srcY: 2x2
- 0, 2, 0, 2,});
- }
- };
-
- ScreenDescription screen = new ScreenDescription() {
- {
- this.bytesPerPixel = 1;
- }
- };
-
- final Element handler = new VncMessageHandler("handler", screen);
-
- ByteBuffer[] emptyBuf = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {});
- Element fburSink = new MockSink("fbur", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {}, new byte[] {}));
- Element bellSink = new MockSink("bell", emptyBuf);
- Element clipboardSink = new MockSink("clipboard", emptyBuf);
- Element desktopSizeChangeSink = new MockSink("desktop_size", emptyBuf);
- Element pixelsSink = new MockSink("pixels", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,}));
- Element copyRectSink = new MockSink("copy_rect", emptyBuf);
-
- Pipeline pipeline = new PipelineImpl("test");
- pipeline.addAndLink(source, handler);
- pipeline.add(fburSink, bellSink, clipboardSink, desktopSizeChangeSink, pixelsSink, copyRectSink);
-
- pipeline.link("handler >" + FRAME_BUFFER_UPDATE_REQUEST_ADAPTER_PAD, "fbur");
- pipeline.link("handler >" + SERVER_BELL_ADAPTER_PAD, "bell");
- pipeline.link("handler >" + SERVER_CLIPBOARD_ADAPTER_PAD, "clipboard");
- pipeline.link("handler >" + PIXEL_ADAPTER_PAD, "pixels");
-
- pipeline.runMainLoop("source", STDOUT, false, false);
-
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/adapter/AwtVncKeyboardAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/adapter/AwtVncKeyboardAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/adapter/AwtVncKeyboardAdapter.java
new file mode 100755
index 0000000..6b50e35
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/adapter/AwtVncKeyboardAdapter.java
@@ -0,0 +1,369 @@
+// 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 vncclient.adapter;
+
+import java.awt.event.KeyEvent;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+import vncclient.vnc.RfbConstants;
+import common.KeyOrder;
+
+public class AwtVncKeyboardAdapter extends BaseElement {
+
+ protected boolean sh = false;
+ protected boolean caps = false;
+ protected boolean num = false;
+
+ public AwtVncKeyboardAdapter(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(8);
+ outBuf.writeByte(RfbConstants.CLIENT_KEYBOARD_EVENT);
+
+ outBuf.writeByte((order.pressed) ? RfbConstants.KEY_DOWN : RfbConstants.KEY_UP);
+ outBuf.writeShort(0); // padding
+ outBuf.writeInt(map_en_us(order));
+
+ pushDataToAllOuts(outBuf);
+ }
+
+ /**
+ * Return key scan code (in lower byte) and extended flags (in second byte).
+ */
+ private int map_en_us(KeyOrder order) {
+
+ switch (order.event.getKeyCode()) {
+ // Functional keys
+ case KeyEvent.VK_ESCAPE:
+ return 0xff1b;
+ case KeyEvent.VK_F1:
+ return 0xffbe;
+ case KeyEvent.VK_F2:
+ return 0xffbf;
+ case KeyEvent.VK_F3:
+ return 0xffc0;
+ case KeyEvent.VK_F4:
+ return 0xffc1;
+ case KeyEvent.VK_F5:
+ return 0xffc2;
+ case KeyEvent.VK_F6:
+ return 0xffc3;
+ case KeyEvent.VK_F7:
+ return 0xffc4;
+ case KeyEvent.VK_F8:
+ return 0xffc5;
+ case KeyEvent.VK_F9:
+ return 0xffc6;
+ case KeyEvent.VK_F10:
+ return 0xffc7;
+ case KeyEvent.VK_F11:
+ return 0xffc8;
+ case KeyEvent.VK_F12:
+ return 0xffc9;
+
+ // Row #1
+ case KeyEvent.VK_BACK_QUOTE:
+ return (sh) ? '~' : '`';
+ case KeyEvent.VK_1:
+ return (sh) ? '!' : '1';
+ case KeyEvent.VK_2:
+ return (sh) ? '@' : '2';
+ case KeyEvent.VK_3:
+ return (sh) ? '#' : '3';
+ case KeyEvent.VK_4:
+ return (sh) ? '$' : '4';
+ case KeyEvent.VK_5:
+ return (sh) ? '%' : '5';
+ case KeyEvent.VK_6:
+ return (sh) ? '^' : '6';
+ case KeyEvent.VK_7:
+ return (sh) ? '&' : '7';
+ case KeyEvent.VK_8:
+ return (sh) ? '*' : '8';
+ case KeyEvent.VK_9:
+ return (sh) ? '(' : '9';
+ case KeyEvent.VK_0:
+ return (sh) ? ')' : '0';
+ case KeyEvent.VK_MINUS:
+ return (sh) ? '_' : '-';
+ case KeyEvent.VK_EQUALS:
+ return (sh) ? '+' : '=';
+ case KeyEvent.VK_BACK_SPACE:
+ return 0xff08;
+
+ // Row #2
+ case KeyEvent.VK_TAB:
+ return 0xff09;
+ case KeyEvent.VK_Q:
+ return (sh ^ caps) ? 'Q' : 'q';
+ case KeyEvent.VK_W:
+ return (sh ^ caps) ? 'W' : 'w';
+ case KeyEvent.VK_E:
+ return (sh ^ caps) ? 'E' : 'e';
+ case KeyEvent.VK_R:
+ return (sh ^ caps) ? 'R' : 'r';
+ case KeyEvent.VK_T:
+ return (sh ^ caps) ? 'T' : 't';
+ case KeyEvent.VK_Y:
+ return (sh ^ caps) ? 'Y' : 'y';
+ case KeyEvent.VK_U:
+ return (sh ^ caps) ? 'U' : 'u';
+ case KeyEvent.VK_I:
+ return (sh ^ caps) ? 'I' : 'i';
+ case KeyEvent.VK_O:
+ return (sh ^ caps) ? 'O' : 'o';
+ case KeyEvent.VK_P:
+ return (sh ^ caps) ? 'P' : 'p';
+ case KeyEvent.VK_OPEN_BRACKET:
+ return (sh) ? '{' : '[';
+ case KeyEvent.VK_CLOSE_BRACKET:
+ return (sh) ? '{' : ']';
+ case KeyEvent.VK_ENTER:
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_STANDARD:
+ return 0xff0d;
+ case KeyEvent.KEY_LOCATION_NUMPAD:
+ return 0xff8d;
+ }
+
+ // Row #3
+ case KeyEvent.VK_CAPS_LOCK:
+ if (order.pressed)
+ caps = !caps;
+ return 0xFFE5;
+ case KeyEvent.VK_A:
+ return (sh ^ caps) ? 'A' : 'a';
+ case KeyEvent.VK_S:
+ return (sh ^ caps) ? 'S' : 's';
+ case KeyEvent.VK_D:
+ return (sh ^ caps) ? 'D' : 'd';
+ case KeyEvent.VK_F:
+ return (sh ^ caps) ? 'F' : 'f';
+ case KeyEvent.VK_G:
+ return (sh ^ caps) ? 'G' : 'g';
+ case KeyEvent.VK_H:
+ return (sh ^ caps) ? 'H' : 'h';
+ case KeyEvent.VK_J:
+ return (sh ^ caps) ? 'J' : 'j';
+ case KeyEvent.VK_K:
+ return (sh ^ caps) ? 'K' : 'k';
+ case KeyEvent.VK_L:
+ return (sh ^ caps) ? 'L' : 'l';
+ case KeyEvent.VK_SEMICOLON:
+ return (sh) ? ':' : ';';
+ case KeyEvent.VK_QUOTE:
+ return (sh) ? '"' : '\'';
+
+ // Row #4
+ case KeyEvent.VK_SHIFT:
+ sh = !sh;
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 0xffe1;
+ case KeyEvent.KEY_LOCATION_RIGHT:
+ return 0xffe2;
+ }
+ case KeyEvent.VK_BACK_SLASH:
+ return (sh) ? '|' : '\\';
+ case KeyEvent.VK_Z:
+ return (sh ^ caps) ? 'Z' : 'z';
+ case KeyEvent.VK_X:
+ return (sh ^ caps) ? 'X' : 'x';
+ case KeyEvent.VK_C:
+ return (sh ^ caps) ? 'C' : 'c';
+ case KeyEvent.VK_V:
+ return (sh ^ caps) ? 'V' : 'v';
+ case KeyEvent.VK_B:
+ return (sh ^ caps) ? 'B' : 'b';
+ case KeyEvent.VK_N:
+ return (sh ^ caps) ? 'N' : 'n';
+ case KeyEvent.VK_M:
+ return (sh ^ caps) ? 'M' : 'M';
+ case KeyEvent.VK_COMMA:
+ return (sh) ? '<' : ',';
+ case KeyEvent.VK_PERIOD:
+ return (sh) ? '>' : '.';
+ case KeyEvent.VK_SLASH:
+ return (sh) ? '?' : '/';
+
+ //
+ // Bottom row
+ case KeyEvent.VK_CONTROL:
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 0xFFE3;
+ case KeyEvent.KEY_LOCATION_RIGHT:
+ return 0xFFE4;
+ }
+ case KeyEvent.VK_WINDOWS:
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 0xFFED; // HyperL
+ case KeyEvent.KEY_LOCATION_RIGHT:
+ return 0xFFEE; // HyperR
+ }
+ case KeyEvent.VK_META:
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 0xFFE7; // MetaL
+ case KeyEvent.KEY_LOCATION_RIGHT:
+ return 0xFFE8; // MetaR
+ }
+
+ case KeyEvent.VK_ALT:
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 0xFFE9;
+ case KeyEvent.KEY_LOCATION_RIGHT:
+ return 0xFFEA;
+ }
+ case KeyEvent.VK_ALT_GRAPH:
+ return 0xfe03;
+
+ case KeyEvent.VK_SPACE:
+ return ' ';
+
+ case KeyEvent.VK_CONTEXT_MENU:
+ return 0xff67;
+
+ //
+ // Special keys
+ case KeyEvent.VK_PRINTSCREEN:
+ return (sh) ? 0xFF15/* SysRq */: 0xFF61 /* Print */;
+ case KeyEvent.VK_SCROLL_LOCK:
+ return 0xFF14;
+ case KeyEvent.VK_PAUSE:
+ return (sh) ? 0xFF6B/* Break */: 0xFF13/* Pause */;
+
+ // Text navigation keys
+ case KeyEvent.VK_INSERT:
+ return 0xff63;
+ case KeyEvent.VK_DELETE:
+ return 0xffff;
+ case KeyEvent.VK_HOME:
+ return 0xff50;
+ case KeyEvent.VK_END:
+ return 0xff57;
+ case KeyEvent.VK_PAGE_UP:
+ return 0xff55;
+ case KeyEvent.VK_PAGE_DOWN:
+ return 0xff56;
+
+ // Cursor keys
+ case KeyEvent.VK_LEFT:
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 0xff51;
+ case KeyEvent.KEY_LOCATION_NUMPAD:
+ return 0xFF96;
+ }
+ case KeyEvent.VK_UP:
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 0xff52;
+ case KeyEvent.KEY_LOCATION_NUMPAD:
+ return 0xFF97;
+ }
+ case KeyEvent.VK_RIGHT:
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 0xff53;
+ case KeyEvent.KEY_LOCATION_NUMPAD:
+ return 0xFF98;
+ }
+ case KeyEvent.VK_DOWN:
+ switch (order.event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 0xff54;
+ case KeyEvent.KEY_LOCATION_NUMPAD:
+ return 0xFF99;
+ }
+
+ // Keypad
+ case KeyEvent.VK_NUM_LOCK:
+ if (order.pressed)
+ num = !num;
+ return 0xFF6F;
+ case KeyEvent.VK_DIVIDE:
+ return 0xFFAF;
+ case KeyEvent.VK_MULTIPLY:
+ return 0xFFAA;
+ case KeyEvent.VK_SUBTRACT:
+ return 0xFFAD;
+ case KeyEvent.VK_ADD:
+ return 0xFFAB;
+
+ case KeyEvent.VK_KP_LEFT:
+ return 0xFF96;
+ case KeyEvent.VK_KP_UP:
+ return 0xFF97;
+ case KeyEvent.VK_KP_RIGHT:
+ return 0xFF98;
+ case KeyEvent.VK_KP_DOWN:
+ return 0xFF99;
+
+ case KeyEvent.VK_NUMPAD0:
+ return 0xFFB0;
+ case KeyEvent.VK_NUMPAD1:
+ return 0xFFB1;
+ case KeyEvent.VK_NUMPAD2:
+ return 0xFFB2;
+ case KeyEvent.VK_NUMPAD3:
+ return 0xFFB3;
+ case KeyEvent.VK_NUMPAD4:
+ return 0xFFB4;
+ case KeyEvent.VK_NUMPAD5:
+ return 0xFFB5;
+ case KeyEvent.VK_NUMPAD6:
+ return 0xFFB6;
+ case KeyEvent.VK_NUMPAD7:
+ return 0xFFB7;
+ case KeyEvent.VK_NUMPAD8:
+ return 0xFFB8;
+ case KeyEvent.VK_NUMPAD9:
+ return 0xFFB9;
+ case KeyEvent.VK_DECIMAL:
+ return 0xFFAE;
+
+ default:
+ System.err.println("Key is not mapped: " + order + ".");
+ return ' '; // Space
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/adapter/AwtVncMouseAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/adapter/AwtVncMouseAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/adapter/AwtVncMouseAdapter.java
new file mode 100755
index 0000000..59216d3
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/adapter/AwtVncMouseAdapter.java
@@ -0,0 +1,71 @@
+// 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 vncclient.adapter;
+
+import java.awt.event.InputEvent;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+import vncclient.vnc.RfbConstants;
+import common.MouseOrder;
+
+public class AwtVncMouseAdapter extends BaseElement {
+
+ public AwtVncMouseAdapter(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(6);
+
+ outBuf.writeByte(RfbConstants.CLIENT_POINTER_EVENT);
+
+ int buttonMask = mapAwtModifiersToVncButtonMask(order.event.getModifiersEx());
+ outBuf.writeByte(buttonMask);
+ outBuf.writeShort(order.event.getX());
+ outBuf.writeShort(order.event.getY());
+
+ pushDataToAllOuts(outBuf);
+ }
+
+ /**
+ * Current state of buttons 1 to 8 are represented by bits 0 to 7 of
+ * button-mask respectively, 0 meaning up, 1 meaning down (pressed). On a
+ * conventional mouse, buttons 1, 2 and 3 correspond to the left, middle and
+ * right buttons on the mouse. On a wheel mouse, each step of the wheel
+ * upwards is represented by a press and release of button 4, and each step
+ * downwards is represented by a press and release of button 5.
+ *
+ * @param modifiers
+ * extended modifiers from AWT mouse event
+ * @return VNC mouse button mask
+ */
+ public static int mapAwtModifiersToVncButtonMask(int modifiers) {
+ int mask = (((modifiers & InputEvent.BUTTON1_DOWN_MASK) != 0) ? 0x1 : 0) | (((modifiers & InputEvent.BUTTON2_DOWN_MASK) != 0) ? 0x2 : 0)
+ | (((modifiers & InputEvent.BUTTON3_DOWN_MASK) != 0) ? 0x4 : 0);
+ return mask;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/EncodingsMessage.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/EncodingsMessage.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/EncodingsMessage.java
new file mode 100755
index 0000000..5dfa831
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/EncodingsMessage.java
@@ -0,0 +1,63 @@
+// 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 vncclient.vnc;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+
+public class EncodingsMessage extends BaseElement {
+
+ protected final int[] encodings;
+
+ public EncodingsMessage(String id, int[] encodings) {
+ super(id);
+ this.encodings = encodings;
+ declarePads();
+ }
+
+ protected void declarePads() {
+ inputPads.put(STDIN, null);
+ outputPads.put(STDOUT, null);
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (buf == null)
+ return;
+
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+ buf.unref();
+
+ ByteBuffer outBuf = new ByteBuffer(4 + encodings.length * 4);
+
+ outBuf.writeByte(RfbConstants.CLIENT_SET_ENCODINGS);
+
+ outBuf.writeByte(0);// padding
+
+ outBuf.writeShort(encodings.length);
+
+ for (int i = 0; i < encodings.length; i++) {
+ outBuf.writeInt(encodings[i]);
+ }
+
+ pushDataToAllOuts(outBuf);
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/FrameBufferUpdateRequest.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/FrameBufferUpdateRequest.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/FrameBufferUpdateRequest.java
new file mode 100755
index 0000000..ee94c60
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/FrameBufferUpdateRequest.java
@@ -0,0 +1,126 @@
+// 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 vncclient.vnc;
+
+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;
+import common.ScreenDescription;
+
+public class FrameBufferUpdateRequest extends BaseElement {
+ // TODO: use object with fields instead of raw values in map
+ public static final String INCREMENTAL_UPDATE = "incremental";
+ public static final String TARGET_X = "x";
+ public static final String TARGET_Y = "y";
+ public static final String WIDTH = "width";
+ public static final String HEIGHT = "height";
+
+ protected ScreenDescription screen;
+
+ public FrameBufferUpdateRequest(String id, ScreenDescription screen) {
+ super(id);
+ this.screen = screen;
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (buf == null)
+ return;
+
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ Boolean incremental = (Boolean)buf.getMetadata(INCREMENTAL_UPDATE);
+ Integer x = (Integer)buf.getMetadata(TARGET_X);
+ Integer y = (Integer)buf.getMetadata(TARGET_Y);
+ Integer width = (Integer)buf.getMetadata(WIDTH);
+ Integer height = (Integer)buf.getMetadata(HEIGHT);
+ buf.unref();
+
+ // Set default values when parameters are not set
+ if (incremental == null)
+ incremental = false;
+
+ if (x == null)
+ x = 0;
+ if (y == null)
+ y = 0;
+
+ if (width == null)
+ width = screen.getFramebufferWidth();
+ if (height == null)
+ height = screen.getFramebufferHeight();
+
+ ByteBuffer outBuf = new ByteBuffer(10);
+
+ outBuf.writeByte(RfbConstants.CLIENT_FRAMEBUFFER_UPDATE_REQUEST);
+ outBuf.writeByte((incremental) ? RfbConstants.FRAMEBUFFER_INCREMENTAL_UPDATE_REQUEST : RfbConstants.FRAMEBUFFER_FULL_UPDATE_REQUEST);
+ outBuf.writeShort(x);
+ outBuf.writeShort(y);
+ outBuf.writeShort(width);
+ outBuf.writeShort(height);
+
+ if (verbose) {
+ outBuf.putMetadata("sender", this);
+ outBuf.putMetadata("dimensions", width + "x" + height + "@" + x + "x" + y);
+ }
+
+ pushDataToAllOuts(outBuf);
+ }
+
+ public static void main(String args[]) {
+ System.setProperty("streamer.Element.debug", "true");
+
+ ScreenDescription screen = new ScreenDescription();
+ screen.setFramebufferSize(120, 80);
+ Element adapter = new FrameBufferUpdateRequest("renderer", screen);
+
+ Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {
+ // Request
+ RfbConstants.CLIENT_FRAMEBUFFER_UPDATE_REQUEST,
+ // Full update (redraw area)
+ RfbConstants.FRAMEBUFFER_FULL_UPDATE_REQUEST,
+ // X
+ 0, 1,
+ // Y
+ 0, 2,
+ // Width
+ 0, 3,
+ // Height
+ 0, 4}));
+
+ ByteBuffer buf = new ByteBuffer(new byte[0]);
+ buf.putMetadata(TARGET_X, 1);
+ buf.putMetadata(TARGET_Y, 2);
+ buf.putMetadata(WIDTH, 3);
+ buf.putMetadata(HEIGHT, 4);
+
+ Element source = new MockSource("source", new ByteBuffer[] {buf});
+
+ Pipeline pipeline = new PipelineImpl("test");
+
+ pipeline.addAndLink(source, adapter, sink);
+ pipeline.runMainLoop("source", STDOUT, false, false);
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/RGB888LE32PixelFormatRequest.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/RGB888LE32PixelFormatRequest.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/RGB888LE32PixelFormatRequest.java
new file mode 100755
index 0000000..2350f14
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/RGB888LE32PixelFormatRequest.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 vncclient.vnc;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+import common.ScreenDescription;
+
+public class RGB888LE32PixelFormatRequest extends BaseElement {
+ protected int bitsPerPixel = 32;
+ protected int depth = 24;
+ protected int bigEndianFlag = RfbConstants.LITTLE_ENDIAN;
+ protected int trueColourFlag = RfbConstants.TRUE_COLOR;
+ protected int redMax = 255;
+ protected int greenMax = 255;
+ protected int blueMax = 255;
+ protected int redShift = 0;
+ protected int greenShift = 8;
+ protected int blueShift = 16;
+
+ protected ScreenDescription screen;
+
+ public RGB888LE32PixelFormatRequest(String id, ScreenDescription screen) {
+ super(id);
+ this.screen = screen;
+ }
+
+ protected void declarePads() {
+ inputPads.put(STDIN, null);
+ outputPads.put(STDOUT, null);
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (buf == null)
+ return;
+
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+ buf.unref();
+
+ ByteBuffer outBuf = new ByteBuffer(20);
+
+ outBuf.writeByte(RfbConstants.CLIENT_SET_PIXEL_FORMAT);
+
+ // Padding
+ outBuf.writeByte(0);
+ outBuf.writeByte(0);
+ outBuf.writeByte(0);
+
+ // Send pixel format
+ outBuf.writeByte(bitsPerPixel);
+ outBuf.writeByte(depth);
+ outBuf.writeByte(bigEndianFlag);
+ outBuf.writeByte(trueColourFlag);
+ outBuf.writeShort(redMax);
+ outBuf.writeShort(greenMax);
+ outBuf.writeShort(blueMax);
+ outBuf.writeByte(redShift);
+ outBuf.writeByte(greenShift);
+ outBuf.writeByte(blueShift);
+
+ // Padding
+ outBuf.writeByte(0);
+ outBuf.writeByte(0);
+ outBuf.writeByte(0);
+
+ screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag != RfbConstants.LITTLE_ENDIAN, trueColourFlag == RfbConstants.TRUE_COLOR, redMax, greenMax,
+ blueMax, redShift, greenShift, blueShift);
+
+ pushDataToAllOuts(outBuf);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/RfbConstants.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/RfbConstants.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/RfbConstants.java
new file mode 100755
index 0000000..a3895d4
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/RfbConstants.java
@@ -0,0 +1,85 @@
+// 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 vncclient.vnc;
+
+import java.nio.charset.Charset;
+
+public interface RfbConstants {
+
+ public static final String RFB_PROTOCOL_VERSION_MAJOR = "RFB 003.";
+ public static final String VNC_PROTOCOL_VERSION_MINOR = "003";
+ public static final String RFB_PROTOCOL_VERSION = RFB_PROTOCOL_VERSION_MAJOR + VNC_PROTOCOL_VERSION_MINOR;
+
+ /**
+ * Server message types.
+ */
+ final static int SERVER_FRAMEBUFFER_UPDATE = 0, SERVER_SET_COLOURMAP_ENTRIES = 1, SERVER_BELL = 2, SERVER_CUT_TEXT = 3;
+
+ /**
+ * Client message types.
+ */
+ public static final int CLIENT_SET_PIXEL_FORMAT = 0, CLIENT_FIX_COLOURMAP_ENTRIES = 1, CLIENT_SET_ENCODINGS = 2, CLIENT_FRAMEBUFFER_UPDATE_REQUEST = 3,
+ CLIENT_KEYBOARD_EVENT = 4, CLIENT_POINTER_EVENT = 5, CLIENT_CUT_TEXT = 6;
+
+ /**
+ * Server authorization type
+ */
+ public final static int CONNECTION_FAILED = 0, NO_AUTH = 1, VNC_AUTH = 2;
+
+ /**
+ * Server authorization reply.
+ */
+ public final static int VNC_AUTH_OK = 0, VNC_AUTH_FAILED = 1, VNC_AUTH_TOO_MANY = 2;
+
+ /**
+ * Encodings.
+ */
+ public final static int ENCODING_RAW = 0, ENCODING_COPY_RECT = 1, ENCODING_RRE = 2, ENCODING_CO_RRE = 4, ENCODING_HEXTILE = 5, ENCODING_ZRLE = 16;
+
+ /**
+ * Pseudo-encodings.
+ */
+ public final static int ENCODING_CURSOR = -239 /*0xFFFFFF11*/, ENCODING_DESKTOP_SIZE = -223 /*0xFFFFFF21*/;
+
+ /**
+ * Encodings, which we support.
+ */
+ public final static int[] SUPPORTED_ENCODINGS_ARRAY = {ENCODING_RAW, ENCODING_COPY_RECT, ENCODING_DESKTOP_SIZE};
+
+ /**
+ * Frame buffer update request type: update of whole screen or partial update.
+ */
+ public static final int FRAMEBUFFER_FULL_UPDATE_REQUEST = 0, FRAMEBUFFER_INCREMENTAL_UPDATE_REQUEST = 1;
+
+ public static final int KEY_UP = 0, KEY_DOWN = 1;
+
+ public static final int LITTLE_ENDIAN = 0, BIG_ENDIAN = 1;
+
+ public static final int EXCLUSIVE_ACCESS = 0, SHARED_ACCESS = 1;
+
+ public static final int PALETTE = 0, TRUE_COLOR = 1;
+
+ /**
+ * Default 8 bit charset to use when communicating with server.
+ */
+ public static final Charset US_ASCII_CHARSET = Charset.availableCharsets().get("US-ASCII");
+
+ /**
+ * Default 16 bit charset to use when communicating with server.
+ */
+ public static final Charset UCS2_CHARSET = Charset.availableCharsets().get("UTF-16LE");
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/Vnc33Authentication.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/Vnc33Authentication.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/Vnc33Authentication.java
new file mode 100755
index 0000000..6fdb3b1
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/Vnc33Authentication.java
@@ -0,0 +1,292 @@
+// 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 vncclient.vnc;
+
+import java.security.spec.KeySpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESKeySpec;
+
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.FakeSink;
+import streamer.debug.MockSink;
+import streamer.debug.MockSource;
+
+public class Vnc33Authentication extends OneTimeSwitch {
+
+ /**
+ * Password to use when authentication is required.
+ */
+ protected String password = null;
+
+ /**
+ * Authentication stage:
+ * <ul>
+ * <li>0 - challenge received, response must be sent
+ * <li>1 - authentication result received.
+ * </ul>
+ */
+ protected int stage = 0;
+
+ public Vnc33Authentication(String id) {
+ super(id);
+ }
+
+ public Vnc33Authentication(String id, String password) {
+ super(id);
+ this.password = password;
+ }
+
+ @Override
+ protected void handleOneTimeData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ switch (stage) {
+ case 0: // Read security with optional challenge and response
+ stage0(buf, link);
+
+ break;
+ case 1: // Read authentication response
+ stage1(buf, link);
+ break;
+ }
+
+ }
+
+ /**
+ * Read security type. If connection type is @see
+ * RfbConstants.CONNECTION_FAILED, then throw exception. If connection type is @see
+ * RfbConstants.NO_AUTH, then switch off this element. If connection type is @see
+ * RfbConstants.VNC_AUTH, then read challenge, send encoded password, and read
+ * authentication response.
+ */
+ private void stage0(ByteBuffer buf, Link link) {
+ // At least 4 bytes are necessary
+ if (!cap(buf, 4, UNLIMITED, link, true))
+ return;
+
+ // Read security type
+ int authType = buf.readSignedInt();
+
+ switch (authType) {
+ case RfbConstants.CONNECTION_FAILED: {
+ // Server forbids to connect. Read reason and throw exception
+
+ int length = buf.readSignedInt();
+ String reason = new String(buf.data, buf.offset, length, RfbConstants.US_ASCII_CHARSET);
+
+ throw new RuntimeException("Authentication to VNC server is failed. Reason: " + reason);
+ }
+
+ case RfbConstants.NO_AUTH: {
+ // Client can connect without authorization. Nothing to do.
+ // Switch off this element from circuit
+ switchOff();
+ break;
+ }
+
+ case RfbConstants.VNC_AUTH: {
+ // Read challenge and generate response
+ responseToChallenge(buf, link);
+ break;
+ }
+
+ default:
+ throw new RuntimeException("Unsupported VNC protocol authorization scheme, scheme code: " + authType + ".");
+ }
+
+ }
+
+ private void responseToChallenge(ByteBuffer buf, Link link) {
+ // Challenge is exactly 16 bytes long
+ if (!cap(buf, 16, 16, link, true))
+ return;
+
+ ByteBuffer challenge = buf.slice(buf.cursor, 16, true);
+ buf.unref();
+
+ // Encode challenge with password
+ ByteBuffer response;
+ try {
+ response = encodePassword(challenge, password);
+ challenge.unref();
+ } catch (Exception e) {
+ throw new RuntimeException("Cannot encrypt client password to send to server: " + e.getMessage());
+ }
+
+ if (verbose) {
+ response.putMetadata("sender", this);
+ }
+
+ // Send encoded challenge
+ nextStage();
+ pushDataToOTOut(response);
+
+ }
+
+ private void nextStage() {
+ stage++;
+
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Next stage: " + stage + ".");
+ }
+
+ /**
+ * Encode password using DES encryption with given challenge.
+ *
+ * @param challenge
+ * a random set of bytes.
+ * @param password
+ * a password
+ * @return DES hash of password and challenge
+ */
+ public ByteBuffer encodePassword(ByteBuffer challenge, String password) {
+ if (challenge.length != 16)
+ throw new RuntimeException("Challenge must be exactly 16 bytes long.");
+
+ // VNC password consist of up to eight ASCII characters.
+ byte[] key = {0, 0, 0, 0, 0, 0, 0, 0}; // Padding
+ byte[] passwordAsciiBytes = password.getBytes(RfbConstants.US_ASCII_CHARSET);
+ System.arraycopy(passwordAsciiBytes, 0, key, 0, Math.min(password.length(), 8));
+
+ // Flip bytes (reverse bits) in key
+ for (int i = 0; i < key.length; i++) {
+ key[i] = flipByte(key[i]);
+ }
+
+ try {
+ KeySpec desKeySpec = new DESKeySpec(key);
+ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
+ SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
+ Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+
+ ByteBuffer buf = new ByteBuffer(cipher.doFinal(challenge.data, challenge.offset, challenge.length));
+
+ return buf;
+ } catch (Exception e) {
+ throw new RuntimeException("Cannot encode password.", e);
+ }
+ }
+
+ /**
+ * Reverse bits in byte, so least significant bit will be most significant
+ * bit. E.g. 01001100 will become 00110010.
+ *
+ * See also: http://www.vidarholen.net/contents/junk/vnc.html ,
+ * http://bytecrafter .blogspot.com/2010/09/des-encryption-as-used-in-vnc.html
+ *
+ * @param b
+ * a byte
+ * @return byte in reverse order
+ */
+ private static byte flipByte(byte b) {
+ int b1_8 = (b & 0x1) << 7;
+ int b2_7 = (b & 0x2) << 5;
+ int b3_6 = (b & 0x4) << 3;
+ int b4_5 = (b & 0x8) << 1;
+ int b5_4 = (b & 0x10) >>> 1;
+ int b6_3 = (b & 0x20) >>> 3;
+ int b7_2 = (b & 0x40) >>> 5;
+ int b8_1 = (b & 0x80) >>> 7;
+ byte c = (byte)(b1_8 | b2_7 | b3_6 | b4_5 | b5_4 | b6_3 | b7_2 | b8_1);
+ return c;
+ }
+
+ /**
+ * Read authentication result, send nothing.
+ */
+ private void stage1(ByteBuffer buf, Link link) {
+ // Read authentication response
+ if (!cap(buf, 4, 4, link, false))
+ return;
+
+ int authResult = buf.readSignedInt();
+
+ switch (authResult) {
+ case RfbConstants.VNC_AUTH_OK: {
+ // Nothing to do
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Authentication successfull.");
+ break;
+ }
+
+ case RfbConstants.VNC_AUTH_TOO_MANY:
+ throw new RuntimeException("Connection to VNC server failed: too many wrong attempts.");
+
+ case RfbConstants.VNC_AUTH_FAILED:
+ throw new RuntimeException("Connection to VNC server failed: wrong password.");
+
+ default:
+ throw new RuntimeException("Connection to VNC server failed, reason code: " + authResult);
+ }
+
+ switchOff();
+
+ }
+
+ @Override
+ public String toString() {
+ return "VNC3.3 Authentication(" + id + ")";
+ }
+
+ /**
+ * 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");
+
+ final String password = "test";
+
+ Element source = new MockSource("source") {
+ {
+ bufs = ByteBuffer.convertByteArraysToByteBuffers(
+ // Request authentication and send 16 byte challenge
+ new byte[] {0, 0, 0, RfbConstants.VNC_AUTH, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
+ // Respond to challenge with AUTH_OK
+ new byte[] {0, 0, 0, RfbConstants.VNC_AUTH_OK});
+ }
+ };
+
+ Element mainSink = new FakeSink("mainSink");
+ final Vnc33Authentication auth = new Vnc33Authentication("auth", password);
+ Element initSink = new MockSink("initSink") {
+ {
+ // Expect encoded password
+ bufs = new ByteBuffer[] {auth.encodePassword(new ByteBuffer(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), password)};
+ }
+ };
+
+ Pipeline pipeline = new PipelineImpl("test");
+ pipeline.addAndLink(source, auth, mainSink);
+ pipeline.add(initSink);
+ pipeline.link("auth >otout", "initSink");
+
+ pipeline.runMainLoop("source", STDOUT, false, false);
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/Vnc33Hello.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/Vnc33Hello.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/Vnc33Hello.java
new file mode 100755
index 0000000..812c6a8
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/Vnc33Hello.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 vncclient.vnc;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import streamer.ByteBuffer;
+import streamer.InputStreamSource;
+import streamer.Link;
+import streamer.OneTimeSwitch;
+import streamer.OutputStreamSink;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+
+/**
+ * VNC server sends hello packet with RFB protocol version, e.g.
+ * "RFB 003.007\n". We need to send response packet with supported protocol
+ * version, e.g. "RFB 003.003\n".
+ */
+public class Vnc33Hello extends OneTimeSwitch {
+
+ public Vnc33Hello(String id) {
+ super(id);
+ }
+
+ @Override
+ protected void handleOneTimeData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ // Initial packet is exactly 12 bytes long
+ if (!cap(buf, 12, 12, link, false))
+ return;
+
+ // Read protocol version
+ String rfbProtocol = new String(buf.data, buf.offset, buf.length, RfbConstants.US_ASCII_CHARSET);
+ buf.unref();
+
+ // Server should use RFB protocol 3.x
+ if (!rfbProtocol.contains(RfbConstants.RFB_PROTOCOL_VERSION_MAJOR))
+ throw new RuntimeException("Cannot handshake with VNC server. Unsupported protocol version: \"" + rfbProtocol + "\".");
+
+ // Send response: we support RFB 3.3 only
+ String ourProtocolString = RfbConstants.RFB_PROTOCOL_VERSION + "\n";
+
+ ByteBuffer outBuf = new ByteBuffer(ourProtocolString.getBytes(RfbConstants.US_ASCII_CHARSET));
+
+ if (verbose) {
+ outBuf.putMetadata("sender", this);
+ outBuf.putMetadata("version", RfbConstants.RFB_PROTOCOL_VERSION);
+ }
+
+ pushDataToOTOut(outBuf);
+
+ // Switch off this element from circuit
+ switchOff();
+
+ }
+
+ @Override
+ public String toString() {
+ return "Vnc3.3 Hello(" + id + ")";
+ }
+
+ /**
+ * 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");
+
+ InputStream is = new ByteArrayInputStream("RFB 003.007\ntest".getBytes(RfbConstants.US_ASCII_CHARSET));
+ ByteArrayOutputStream initOS = new ByteArrayOutputStream();
+ ByteArrayOutputStream mainOS = new ByteArrayOutputStream();
+ InputStreamSource inputStreamSource = new InputStreamSource("source", is);
+ OutputStreamSink outputStreamSink = new OutputStreamSink("mainSink", mainOS);
+
+ Vnc33Hello hello = new Vnc33Hello("hello");
+
+ Pipeline pipeline = new PipelineImpl("test");
+
+ pipeline.addAndLink(inputStreamSource, hello, outputStreamSink);
+ pipeline.add(new OutputStreamSink("initSink", initOS));
+
+ pipeline.link("hello >" + OneTimeSwitch.OTOUT, "initSink");
+
+ pipeline.runMainLoop("source", STDOUT, false, false);
+
+ String initOut = new String(initOS.toByteArray(), RfbConstants.US_ASCII_CHARSET);
+ String mainOut = new String(mainOS.toByteArray(), RfbConstants.US_ASCII_CHARSET);
+
+ if (!"RFB 003.003\n".equals(initOut))
+ System.err.println("Unexpected value for hello response: \"" + initOut + "\".");
+
+ if (!"test".equals(mainOut))
+ System.err.println("Unexpected value for main data: \"" + mainOut + "\".");
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/48c47101/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/VncInitializer.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/VncInitializer.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/VncInitializer.java
new file mode 100755
index 0000000..0b96c73
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/vnc/VncInitializer.java
@@ -0,0 +1,245 @@
+// 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 vncclient.vnc;
+
+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;
+import common.ScreenDescription;
+
+public class VncInitializer extends OneTimeSwitch {
+
+ // Pad names
+ public static final String CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD = "encodings";
+ public static final String CLIENT_PIXEL_FORMAT_ADAPTER_PAD = "pixel_format";
+
+ protected byte sharedFlag = RfbConstants.EXCLUSIVE_ACCESS;
+
+ /**
+ * Properties of remote screen .
+ */
+ protected ScreenDescription screen;
+
+ public VncInitializer(String id, boolean shared, ScreenDescription screen) {
+ super(id);
+
+ setSharedFlag(shared);
+ this.screen = screen;
+
+ declarePads();
+ }
+
+ @Override
+ protected void declarePads() {
+ super.declarePads();
+ outputPads.put(CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD, null);
+ outputPads.put(CLIENT_PIXEL_FORMAT_ADAPTER_PAD, null);
+ }
+
+ public ScreenDescription getScreen() {
+ return screen;
+ }
+
+ public void setScreen(ScreenDescription screen) {
+ this.screen = screen;
+ }
+
+ public void setSharedFlag(boolean shared) {
+ if (shared)
+ sharedFlag = RfbConstants.SHARED_ACCESS;
+ else
+ sharedFlag = RfbConstants.EXCLUSIVE_ACCESS;
+ }
+
+ @Override
+ protected void handleOneTimeData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ // Server initialization message is at least 24 bytes long + length of
+ // desktop name
+ if (!cap(buf, 24, UNLIMITED, link, false))
+ return;
+
+ // Read server initialization message
+ // Read frame buffer size
+ int framebufferWidth = buf.readUnsignedShort();
+ int framebufferHeight = buf.readUnsignedShort();
+
+ // Read pixel format
+ int bitsPerPixel = buf.readUnsignedByte();
+ int depth = buf.readUnsignedByte();
+
+ int bigEndianFlag = buf.readUnsignedByte();
+ int trueColorFlag = buf.readUnsignedByte();
+
+ int redMax = buf.readUnsignedShort();
+ int greenMax = buf.readUnsignedShort();
+ int blueMax = buf.readUnsignedShort();
+
+ int redShift = buf.readUnsignedByte();
+ int greenShift = buf.readUnsignedByte();
+ int blueShift = buf.readUnsignedByte();
+
+ // Skip padding
+ buf.skipBytes(3);
+
+ // Read desktop name
+ int length = buf.readSignedInt();
+
+ // Consume exactly $length bytes, push back any extra bytes
+ if (!cap(buf, length, length, link, true))
+ return;
+
+ String desktopName = buf.readString(length, RfbConstants.US_ASCII_CHARSET);
+ buf.unref();
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Desktop name: \"" + desktopName + "\", bpp: " + bitsPerPixel + ", depth: " + depth + ", screen size: "
+ + framebufferWidth + "x" + framebufferHeight + ".");
+
+ // Set screen properties
+ screen.setFramebufferSize(framebufferWidth, framebufferHeight);
+ screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag != RfbConstants.LITTLE_ENDIAN, trueColorFlag == RfbConstants.TRUE_COLOR, redMax, greenMax, blueMax, redShift,
+ greenShift, blueShift);
+ screen.setDesktopName(desktopName);
+
+ // If sever screen has different parameters than ours, then change it
+ if (!screen.isRGB888_32_LE()) {
+ // Send client pixel format
+ sendClientPixelFormat();
+ }
+
+ // Send encodings supported by client
+ sendSupportedEncodings();
+
+ switchOff();
+
+ }
+
+ @Override
+ protected void onStart() {
+ ByteBuffer buf = new ByteBuffer(new byte[] {sharedFlag});
+ pushDataToOTOut(buf);
+ }
+
+ private void sendClientPixelFormat() {
+ pushDataToPad(CLIENT_PIXEL_FORMAT_ADAPTER_PAD, new ByteBuffer(0));
+ }
+
+ private void sendSupportedEncodings() {
+ pushDataToPad(CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD, new ByteBuffer(0));
+ }
+
+ @Override
+ public String toString() {
+ return "VncInit(" + id + ")";
+ }
+
+ /**
+ * 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");
+
+ final String desktopName = "test";
+
+ Element source = new MockSource("source") {
+ {
+ bufs = ByteBuffer.convertByteArraysToByteBuffers(
+ // Send screen description
+ new byte[] {
+ // Framebuffer width (short)
+ 0, (byte)200,
+ // Framebuffer height (short)
+ 0, 100,
+ // Bits per pixel
+ 32,
+ // Depth,
+ 24,
+ // Endianness flag
+ RfbConstants.LITTLE_ENDIAN,
+ // Truecolor flag
+ RfbConstants.TRUE_COLOR,
+ // Red max (short)
+ 0, (byte)255,
+ // Green max (short)
+ 0, (byte)255,
+ // Blue max (short)
+ 0, (byte)255,
+ // Red shift
+ 16,
+ // Green shift
+ 8,
+ // Blue shift
+ 0,
+ // Padding
+ 0, 0, 0,
+ // Desktop name length (int)
+ 0, 0, 0, 4,
+ // Desktop name ("test", 4 bytes)
+ 't', 'e', 's', 't',
+
+ // Tail
+ 1, 2, 3
+
+ },
+ // Tail packet
+ new byte[] {4, 5, 6});
+ }
+ };
+
+ ScreenDescription screen = new ScreenDescription();
+ final VncInitializer init = new VncInitializer("init", true, screen);
+ Element initSink = new MockSink("initSink") {
+ {
+ // Expect shared flag
+ bufs = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {RfbConstants.SHARED_ACCESS});
+ }
+ };
+ Element mainSink = new MockSink("mainSink") {
+ {
+ // Expect two tail packets
+ bufs = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}, new byte[] {4, 5, 6});
+ }
+ };
+ ByteBuffer[] emptyBuf = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {});
+ Element encodingsSink = new MockSink("encodings", emptyBuf);
+ Element pixelFormatSink = new MockSink("pixel_format", emptyBuf);
+
+ Pipeline pipeline = new PipelineImpl("test");
+ pipeline.addAndLink(source, init, mainSink);
+ pipeline.add(encodingsSink, pixelFormatSink, initSink);
+ pipeline.link("init >otout", "initSink");
+ pipeline.link("init >" + CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD, "encodings");
+ pipeline.link("init >" + CLIENT_PIXEL_FORMAT_ADAPTER_PAD, "pixel_format");
+
+ pipeline.runMainLoop("source", STDOUT, false, false);
+
+ if (!screen.isRGB888_32_LE())
+ System.err.println("Screen description was read incorrectly: " + screen + ".");
+ if (!desktopName.equals(screen.getDesktopName()))
+ System.err.println("Screen desktop name was read incorrectly: \"" + screen.getDesktopName() + "\".");
+
+ }
+}