Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 032CD10BD0 for ; Mon, 23 Dec 2013 09:16:04 +0000 (UTC) Received: (qmail 47216 invoked by uid 500); 23 Dec 2013 09:14:05 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 46744 invoked by uid 500); 23 Dec 2013 09:13:19 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 46527 invoked by uid 99); 23 Dec 2013 09:12:57 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 23 Dec 2013 09:12:57 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 34F1D82BC64; Mon, 23 Dec 2013 09:12:56 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: devdeep@apache.org To: commits@cloudstack.apache.org Date: Mon, 23 Dec 2013 09:13:05 -0000 Message-Id: <706b0cb5a7dd47c79e46c67ffbffeda7@git.apache.org> In-Reply-To: <33588344be7742c7825dfb633d396983@git.apache.org> References: <33588344be7742c7825dfb633d396983@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [11/22] CLOUDSTACK-5344: Update to allow rdp console to access hyper-v vm virtual framebuffer. http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientConfirmActivePDU.java ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientConfirmActivePDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientConfirmActivePDU.java new file mode 100755 index 0000000..9c0c52e --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientConfirmActivePDU.java @@ -0,0 +1,1132 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package rdpclient.rdp; + +import streamer.BaseElement; +import streamer.ByteBuffer; +import streamer.Element; +import streamer.Link; +import streamer.Pipeline; +import streamer.PipelineImpl; +import streamer.debug.MockSink; +import streamer.debug.MockSource; + +import common.ScreenDescription; + +/** + * @see http://msdn.microsoft.com/en-us/library/cc240488.aspx + */ +public class ClientConfirmActivePDU extends BaseElement { + + public static final String SOURCE_DESC = "MSTSC"; + + public static final int CAPSTYPE_BITMAP = 0x2; + + protected int numberCapabilities; + + protected RdpState state; + protected ScreenDescription screen; + + protected boolean desktopResize = false; + protected int prefferedBitsPerPixel = 16; + + public ClientConfirmActivePDU(String id, ScreenDescription screen, RdpState state) { + super(id); + this.state = state; + this.screen = screen; + } + + @Override + public void handleData(ByteBuffer aBuf, Link link) { + + // Body + ByteBuffer buf = new ByteBuffer(1024, true); + numberCapabilities = 0; + writeCapabilities(buf); + buf.trimAtCursor(); + + // Header + ByteBuffer header = createMCSHeader(buf); + + // Length of source descriptor, including NULL character (LE) + header.writeShortLE(SOURCE_DESC.length() + 1); + + // Length of combined capabilities + 4 bytes (number of capabilities and + // padding) (LE) + header.writeShortLE(buf.length + 4); + + header.writeString(SOURCE_DESC, RdpConstants.CHARSET_8); + header.writeByte(0); + + // Number of capabilities + header.writeShortLE(numberCapabilities); + + // Padding 2 bytes + header.writeShortLE(0); + + header.trimAtCursor(); + + // Prepend header to capabilities + buf.prepend(header); + + // Trim buffer to actual length of data written + buf.trimAtCursor(); + + pushDataToPad(STDOUT, buf); + + sendOtherRequredPackets(); + + } + + private ByteBuffer createMCSHeader(ByteBuffer buf) { + ByteBuffer header = new ByteBuffer(100); + // MCS Send Data Request + header.writeByte(0x64); + + // Initiator: 1004 (1001+3) + header.writeShort(3); + + // Channel ID: 1003 (I/O channel) + header.writeShort(RdpConstants.CHANNEL_IO); + + // Data priority: high (0x40), segmentation: begin (0x20) | end (0x10) + header.writeByte(0x70); + + int length = buf.length + 26; + + // User data length: (variable length field, LE) + header.writeVariableShort(length); + + // Total length: (LE) + header.writeShortLE(length); + + // PDU type: Confirm Active PDU (0x3), TS_PROTOCOL_VERSION (0x10) (LE) + header.writeShortLE(0x13); + + // PDU source: 1004 (LE) + header.writeShortLE(1004); + + // Share ID, e.g. 0x000103ea (LE) + header.writeIntLE((int)state.serverShareId); + + // Originator ID: 1002 (LE) + header.writeShortLE(1002); + return header; + } + + private void sendOtherRequredPackets() { + // Send sequence in bulk + + sendSynchronizePDU(); + sendControlPDUActionCooperate(); + sendControlPDUActionRequestControl(); + // sendBitmapCachePersistentListPDU(); + sendFontListPDU(); + } + + private void sendFontListPDU() { + { + int length = 1024; // Large enough + ByteBuffer buf = new ByteBuffer(length, true); + + /* @formatter:off */ + buf.writeBytes(new byte[] { + // MCS Send Data Request + (byte)0x64, + // Initiator: 1004 (1001+3) + (byte)0x00, (byte)0x03, + // Channel ID: 1003 (I/O channel) + (byte)0x03, (byte)0xeb, + // Data priority: high (0x40), segmentation: begin (0x20) | end (0x10) + (byte)0x70, + // User data length: 26 bytes (0x1a, variable length field) + (byte)0x80, (byte)0x1a, + + // Total length: 26 bytes (0x1a, LE) + (byte)0x1a, (byte)0x00, + // PDU type: PDUTYPE_DATAPDU (0x7), PDU version: 1 (0x0010) (LE) + (byte)0x17, (byte)0x00, + // PDU source: 1004 (LE) + (byte)0xec, (byte)0x03, + }); + // Share ID, 4 bytes (LE) + buf.writeIntLE((int)state.serverShareId); + + buf.writeBytes(new byte[] { + // Padding 1 byte + (byte)0x00, + // Stream ID: STREAM_LOW (1) + (byte)0x01, + // uncompressedLength : 12 bytes (LE) + (byte)0x0c, (byte)0x00, + + // pduType2: PDUTYPE2_FONTLIST (39) + (byte)0x27, + // generalCompressedType: 0 + (byte)0x00, + // generalCompressedLength: 0 (LE) + (byte)0x00, (byte)0x00, + + // numberEntries (should be set to zero): 0 (LE) + (byte)0x00, (byte)0x00, + // totalNumEntries (should be set to zero): 0 (LE) + (byte)0x00, (byte)0x00, + // listFlags (should be set to 0x3): 0x0003 (LE), FONTLIST_LAST(0x2) | FONTLIST_FIRST(0x1) + (byte)0x03, (byte)0x00, + // entrySize: 50 bytes (0x0032, LE) + (byte)0x32, (byte)0x00, + }); + /* @formatter:on */ + + // Trim buffer to actual length of data written + buf.trimAtCursor(); + + pushDataToPad(STDOUT, buf); + } + } + + private void sendControlPDUActionRequestControl() { + int length = 1024; // Large enough + ByteBuffer buf = new ByteBuffer(length, true); + + /* @formatter:off */ + buf.writeBytes(new byte[] { + // MCS Send Data Request + (byte)0x64, + // Initiator: 1004 (1001+3) + (byte)0x00, (byte)0x03, + // Channel ID: 1003 (I/O channel) + (byte)0x03, (byte)0xeb, + // Data priority: high (0x40), segmentation: begin (0x20) | end (0x10) + (byte)0x70, + // User data length: 26 bytes (0x1a, variable length field) + (byte)0x80, (byte)0x1a, + + // Total length: 26 bytes (0x1a, LE) + (byte)0x1a, (byte)0x00, + // PDU type: PDUTYPE_DATAPDU (0x7), PDU version: 1 (0x0010) (LE) + (byte)0x17, (byte)0x00, + // PDU source: 1004 (LE) + (byte)0xec, (byte)0x03, + }); + // Share ID, 4 bytes (LE) + buf.writeIntLE((int)state.serverShareId); + + buf.writeBytes(new byte[] { + // Padding 1 byte + (byte)0x00, + // Stream ID: STREAM_LOW (1) + (byte)0x01, + // uncompressedLength : 12 bytes (LE) + (byte)0x0c, (byte)0x00, + // pduType2: PDUTYPE2_CONTROL (20) + (byte)0x14, + // generalCompressedType: 0 + (byte)0x00, + // generalCompressedLength: 0 (LE) + (byte)0x00, (byte)0x00, + + // action: CTRLACTION_REQUEST_CONTROL (1) (LE) + (byte)0x01, (byte)0x00, + // grantId: 0 (LE) + (byte)0x00, (byte)0x00, + // controlId: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + }); + /* @formatter:on */ + + // Trim buffer to actual length of data written + buf.trimAtCursor(); + + pushDataToPad(STDOUT, buf); + } + + private void sendControlPDUActionCooperate() { + int length = 1024; // Large enough + ByteBuffer buf = new ByteBuffer(length, true); + + /* @formatter:off */ + buf.writeBytes(new byte[] { + // MCS Send Data Request + (byte)0x64, + // Initiator: 1004 (1001+3) + (byte)0x00, (byte)0x03, + // Channel ID: 1003 (I/O channel) + (byte)0x03, (byte)0xeb, + // Data priority: high (0x40), segmentation: begin (0x20) | end (0x10) + (byte)0x70, + // User data length: 26 bytes (0x1a, variable length field) + (byte)0x80, (byte)0x1a, + + // Total length: 26 bytes (0x1a, LE) + (byte)0x1a,(byte)0x00, + // PDU type: PDUTYPE_DATAPDU (0x7), PDU version: 1 (0x0010) (LE) + (byte)0x17, (byte)0x00, + // PDU source: 1004 (LE) + (byte)0xec, (byte)0x03, + }); + // Share ID, 4 bytes (LE) + buf.writeIntLE((int)state.serverShareId); + + buf.writeBytes(new byte[] { + // Padding 1 byte + (byte)0x00, + // Stream ID: STREAM_LOW (1) + (byte)0x01, + // uncompressedLength : 12 bytes (LE) + (byte)0x0c, (byte)0x00, + // pduType2: PDUTYPE2_CONTROL (20) + (byte)0x14, + // generalCompressedType: 0 + (byte)0x00, + // generalCompressedLength: 0 (LE?) + (byte)0x00, (byte)0x00, + // action: CTRLACTION_COOPERATE (4) (LE) + (byte)0x04, (byte)0x00, + // grantId: 0 (LE) + (byte)0x00, (byte)0x00, + // controlId: 0 + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + }); + /* @formatter:on */ + + buf.trimAtCursor(); + + pushDataToPad(STDOUT, buf); + } + + private void sendSynchronizePDU() { + + ByteBuffer buf = new ByteBuffer(1024, true); + /* @formatter:off */ + buf.writeBytes(new byte[] { + // MCS send data request + (byte)0x64, + // Initiator: 1004 (1001+3) + (byte)0x00, (byte)0x03, + // Channel ID: 1003 (I/O Channel) + (byte)0x03, (byte)0xeb, + // Data priority: high (0x40), segmentation: begin (0x20) | end (0x10) + (byte)0x70, + // Data length: 22 bytes (0x16, variable length field) + (byte)0x80, (byte)0x16, + + // RDP: total length: 22 bytes (LE) + (byte)0x16, (byte)0x00, + + // PDU type: PDUTYPE_DATAPDU (0x7), TS_PROTOCOL_VERSION (0x10) (LE) + (byte)0x17, (byte)0x00, + + // PDU source: 1007 (LE) + (byte)0xec, (byte)0x03, + }); + // Share ID, 4 bytes (LE) + buf.writeIntLE((int)state.serverShareId); + + buf.writeBytes(new byte[] { + // Padding: 1 byte + (byte)0x00, + // Stream ID: STREAM_LOW (1) + (byte)0x01, + // uncompressedLength : 8 bytes (LE) + (byte)0x08, (byte)0x00, + // pduType2 = PDUTYPE2_SYNCHRONIZE (31) + (byte)0x1f, + // generalCompressedType: 0 + (byte)0x00, + // generalCompressedLength: 0 (LE?) + (byte)0x00, (byte)0x00, + // messageType: SYNCMSGTYPE_SYNC (1) (LE) + (byte)0x01, (byte)0x00, + // targetUser: 0x03ea + (byte)0xea, (byte)0x03, + }); + /* @formatter:on */ + buf.trimAtCursor(); + pushDataToPad(STDOUT, buf); + } + + private void writeCapabilities(ByteBuffer buf) { + writeGeneralCS(buf); + + writeBitmapCS(buf); + + writeOrderCS(buf); + + writeBitmapCache2CS(buf); + + writeColorTableCacheCS(buf); + + writeWindowActivationCS(buf); + + writeControlCS(buf); + + writePointerCS(buf); + + writeShareCS(buf); + + writeInputCS(buf); + + writeBrushCS(buf); + + writeSoundCS(buf); + + writeFontCS(buf); + + writeOffscreenBitmapCS(buf); + + writeGlyphCacheCS(buf); + } + + private void writeBrushCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Brush Capability Set (8 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240564.aspx + (byte)0x0f, (byte)0x00, // capability set type: CAPSTYPE_BRUSH (15, + // LE) + (byte)0x08, (byte)0x00, // length of capability set: 8 bytes (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // brushSupportLevel: + // BRUSH_DEFAULT + // (0x0, LE) + + }); + } + + private void writeInputCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Input Capability Set (88 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240563.aspx + (byte)0x0d, + (byte)0x00, // capability set type: CAPSTYPE_INPUT (13, LE) + (byte)0x58, + (byte)0x00, // length of capability set: 88 bytes (LE) + (byte)0x35, + (byte)0x00, // inputFlags: 0x0035 (LE), INPUT_FLAG_FASTPATH_INPUT2 + // (0x20), INPUT_FLAG_VKPACKET (0x10), INPUT_FLAG_MOUSEX + // (0x4), INPUT_FLAG_SCANCODES (0x1) + (byte)0x00, + (byte)0x00, // Padding 2 bytes + (byte)0x09, + (byte)0x04, + (byte)0x00, + (byte)0x00, // keyboardLayout: "US" keyboard layout (0x000409, LE) + (byte)0x00, + (byte)0x00, + (byte)0x00, + (byte)0x00, // keyboardType: unknown (LE) + (byte)0x00, + (byte)0x00, + (byte)0x00, + (byte)0x00, // keyboardSubType: unknown (LE) + (byte)0x00, + (byte)0x00, + (byte)0x00, + (byte)0x00, // keyboardFunctionKey: unknown (LE) + // imeFileName: "", (64 bytes, including trailing NULL characters, UCS2) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + + }); + } + + private void writeShareCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Share Capability Set (8 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240570.aspx + (byte)0x09, (byte)0x00, // capability set type: CAPSTYPE_SHARE (9, LE) + (byte)0x08, (byte)0x00, // length of capability set: 8 bytes (LE) + (byte)0x00, (byte)0x00, // nodeID (must be set to 0 by client): 0 (LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes (LE) + + }); + } + + private void writePointerCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Pointer Capability Set (10 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240562.aspx + (byte)0x08, (byte)0x00, // capability set type: CAPSTYPE_POINTER (8, + // LE) + (byte)0x0a, (byte)0x00, // length of capability set: 10 bytes (LE) + (byte)0x00, (byte)0x00, // colorPointerFlag: FALSE (LE) + (byte)0x00, (byte)0x00, // colorPointerCacheSize: 0 (LE) + (byte)0x14, (byte)0x00, // pointerCacheSize: 20 (LE) + + }); + } + + private void writeControlCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Control Capability Set (12 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240568.aspx + (byte)0x05, (byte)0x00, // capability set type: CAPSTYPE_ACTIVATION + // (7) + (byte)0x0c, (byte)0x00, // length of capability set: 12 bytes (LE) + (byte)0x00, (byte)0x00, // controlFlags (should be set to 0): 0 (LE) + (byte)0x00, (byte)0x00, // remoteDetachFlag (should be set to 0): 0 + // (LE) + (byte)0x02, (byte)0x00, // controlInterest (should be set to + // CONTROLPRIORITY_NEVER): + // CONTROLPRIORITY_NEVER (2) (LE) + (byte)0x02, (byte)0x00, // detachInterest (should be set to + // CONTROLPRIORITY_NEVER): + // CONTROLPRIORITY_NEVER (2) (LE) + + }); + } + + private void writeWindowActivationCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Window Activation Capability Set (12 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240569.aspx + (byte)0x07, (byte)0x00, // capability set type: CAPSTYPE_ACTIVATION + // (7) (LE) + (byte)0x0c, (byte)0x00, // length of capability set: 12 bytes (LE) + (byte)0x00, (byte)0x00, // helpKeyFlag (should be set to FALSE (0)): + // FALSE (0, LE) + (byte)0x00, (byte)0x00, // helpKeyIndexFlag (should be set to FALSE + // (0)): FALSE (0, LE) + (byte)0x00, (byte)0x00, // helpExtendedKeyFlag (should be set to FALSE + // (0)): FALSE (0, LE) + (byte)0x00, (byte)0x00, // windowManagerKeyFlag (should be set to + // FALSE (0)): FALSE (0, LE) + + }); + } + + private void writeColorTableCacheCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + + // + // Color Table Cache Capability Set (8 bytes), see + // http://msdn.microsoft.com/en-us/library/cc241564.aspx + (byte)0x0a, (byte)0x00, // capability set type: CAPSTYPE_COLORCACHE + // (10) (LE) + (byte)0x08, (byte)0x00, // length of capability set: 8 bytes (LE) + (byte)0x06, (byte)0x00, // Color table cache size (must be ignored + // during capability exchange and is assumed + // to be 0x0006): 6 (LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + + }); + } + + private void writeBitmapCache2CS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Bitmap Cache Rev. 2 Capability Set (40 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240560.aspx + (byte)0x13, (byte)0x00, // capability set type: + // CAPSTYPE_BITMAPCACHE_REV2 (19) (LE) + (byte)0x28, (byte)0x00, // length of capability set: 40 bytes (LE) + (byte)0x00, (byte)0x00, // Cache flags: 0 (LE) + (byte)0x00, // Padding 1 byte + (byte)0x00, // Number of cell caches: 0 + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache0 + // cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache1 + // cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache2 + // cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache3 + // cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache4 + // cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Padding 12 bytes + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Padding + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Padding + }); + } + + private void writeGeneralCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // Capabilities, see + // http://msdn.microsoft.com/en-us/library/cc240486.aspx + + // + // General capability set (24 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240549.aspx + (byte)0x01, (byte)0x00, // capability set type: CAPSTYPE_GENERAL (1) + // (LE) + (byte)0x18, (byte)0x00, // length of capability set: 24 bytes (LE) + (byte)0x01, (byte)0x00, // TS_OSMAJORTYPE_WINDOWS (1) (LE) + (byte)0x03, (byte)0x00, // TS_OSMINORTYPE_WINDOWS_NT (3) (LE) + (byte)0x00, (byte)0x02, // TS_CAPS_PROTOCOLVERSION (0x0200) (LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + (byte)0x00, (byte)0x00, // generalCompressionTypes: 0 (LE) + + // Extra flags: 0x040d (LE) + // FastPathOutput: (...............1) Advertiser supports fast-path + // output + // ShadowCompression: (..............0.) Advertiser NOT supports shadow + // compression + // LongLengthCredentials: (.............1..) Advertiser supports + // long-length credentials for the user name, password, or domain name + // SessionAutoreconnection: (............1...) Advertiser supports + // session auto-reconnection + // ImprovedEncryptionChecksum: (...........0....) Client and server NOT + // support improved encryption checksum + // Reserved1: (......00000.....) + // CompressedBitMapDataFlag: (.....1..........) No 8-UINT8 header is + // present for compressed bitmap data + // Reserved2: (00000...........) + (byte)0x0d, (byte)0x04, + + (byte)0x00, (byte)0x00, // updateCapabilityFlag: 0 (LE) + (byte)0x00, (byte)0x00, // remoteUnshareFlag: 0 (LE) + (byte)0x00, (byte)0x00, // generalCompressionLevel: 0 (LE) + (byte)0x00, // refreshRectSupport: FALSE (0) + (byte)0x00, // suppressOutputSupport: FALSE (0) + + }); + } + + private void writeBitmapCS(ByteBuffer buf) { + // Bitmap capability set (28 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240554.aspx + + numberCapabilities++; + + // Capability set type: CAPSTYPE_BITMAP (2) (LE) + buf.writeShortLE(CAPSTYPE_BITMAP); + + // Length of capability set: 28 bytes (LE) + buf.writeShortLE(28); + + // preferredBitsPerPixel: 16 bpp (LE) + buf.writeShortLE(prefferedBitsPerPixel); + + // receive1BitPerPixel (ignored and SHOULD be set to TRUE (0x1)): TRUE (0x1) (LE) + buf.writeShortLE(1); + + // receive4BitsPerPixel (ignored and SHOULD be set to TRUE (0x1)): TRUE (0x1) (LE) + buf.writeShortLE(1); + + // receive8BitsPerPixel (ignored and SHOULD be set to TRUE (0x1)): TRUE (0x1) (LE) + buf.writeShortLE(1); + + // Desktop width and height (LE) + buf.writeShortLE(screen.getFramebufferWidth()); + buf.writeShortLE(screen.getFramebufferHeight()); + + // Padding 2 bytes + buf.writeShortLE(0); + + // desktopResizeFlag (LE) + buf.writeShortLE((desktopResize) ? 1 : 0); + + buf.writeBytes(new byte[] { + (byte)0x01, (byte)0x00, // bitmapCompressionFlag (must be set to TRUE + // (0x1)): TRUE (0x1) (LE) + (byte)0x00, // highColorFlags (field is ignored and SHOULD be set to + // zero): 0 + (byte)0x01, // drawingFlags: 0x1 TODO: padding, why 0x1 ??? + (byte)0x01, (byte)0x00, // multipleRectangleSupport: TRUE (LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + + }); + } + + private void writeOrderCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Order Capability Set (88 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240556.aspx + (byte)0x03, + (byte)0x00, // capability set type: CAPSTYPE_ORDER (3) (LE) + (byte)0x58, + (byte)0x00, // length of capability set: 88 bytes (LE) + // terminalDescriptor = "" (16 bytes, UCS2) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // pad4octetsA + (byte)0x01, (byte)0x00, // desktopSaveXGranularity (ignored): 1 (LE) + (byte)0x14, (byte)0x00, // desktopSaveYGranularity (ignored): 20 (LE) + (byte)0x00, (byte)0x00, // pad2octetsA (ignored) + (byte)0x01, (byte)0x00, // maximumOrderLevel: ORD_LEVEL_1_ORDERS (1) + (byte)0x00, (byte)0x00, // number of fonts (ignored): 0 + (byte)0x4a, (byte)0x00, // orderFlags = 0x004a (LE), + // SOLIDPATTERNBRUSHONLY (0x40), + // ZEROBOUNDSDELTASSUPPORT (0x8, MUST), + // NEGOTIATEORDERSUPPORT (0x2, MUST) + // Order support: 32 bytes (no primary drawing orders are supported, so + // this array MUST be initialized to all zeros, use 0x01 for TRUE). + (byte)0x00, // TS_NEG_DSTBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_PATBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_SCRBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MEMBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MEM3BLT_INDEX: FALSE + (byte)0x00, // TS_NEG_ATEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_AEXTTEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_DRAWNINEGRID_INDEX: FALSE + (byte)0x00, // TS_NEG_LINETO_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTI_DRAWNINEGRID_INDEX: FALSE + (byte)0x00, // TS_NEG_OPAQUERECT_INDEX: FALSE + (byte)0x00, // TS_NEG_SAVEBITMAP_INDEX: FALSE + (byte)0x00, // TS_NEG_WTEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_MEMBLT_R2_INDEX: FALSE + (byte)0x00, // TS_NEG_MEM3BLT_R2_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTIDSTBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTIPATBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTISCRBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTIOPAQUERECT_INDEX: FALSE + (byte)0x00, // TS_NEG_FAST_INDEX_INDEX: FALSE + (byte)0x00, // TS_NEG_POLYGON_SC_INDEX: FALSE + (byte)0x00, // TS_NEG_POLYGON_CB_INDEX: FALSE + (byte)0x00, // TS_NEG_POLYLINE_INDEX: TRUE + (byte)0x00, // Unused: 0 + (byte)0x00, // TS_NEG_FAST_GLYPH_INDEX: FALSE + (byte)0x00, // TS_NEG_ELLIPSE_SC_INDEX: FALSE + (byte)0x00, // TS_NEG_ELLIPSE_CB_INDEX: FALSE + (byte)0x00, // TS_NEG_INDEX_INDEX: FALSE + (byte)0x00, // TS_NEG_WEXTTEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_WLONGTEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_WLONGEXTTEXTOUT_INDEX: FALSE + (byte)0x00, // Unused: 0 + (byte)0x00, (byte)0x00, // Text flags (ignored): 0 (LE) + (byte)0x00, (byte)0x00, // Order support extra flags: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Padding 4 bytes + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Desktop save size + // (ignored): 0 + // (assumed to be + // 230400 bytes + // (480*480, + // 0x38400, LE)) + (byte)0x00, (byte)0x00, // Padding 2 bytes + (byte)0x00, (byte)0x00, // Padding 2 bytes + (byte)0xe4, (byte)0x04, // Text ANSI Code Page: 1252, ANSI - Latin I + // (0x04e4, LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + + }); + } + + private void writeSoundCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Sound Capability Set (8 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240552.aspx + (byte)0x0c, (byte)0x00, // capability set type: CAPSTYPE_SOUND (12, + // LE) + (byte)0x08, (byte)0x00, // length of capability set: 8 bytes (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // soundFlags: + // 0x0000 (LE) // + // SOUND_FLAG_BEEPS + // (0x1) + + }); + } + + private void writeFontCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Font Capability Set (8 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240571.aspx + (byte)0x0e, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, + + }); + } + + private void writeOffscreenBitmapCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Offscreen Bitmap Cache Capability Set (12 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240550.aspx + (byte)0x11, (byte)0x00, // capability set type: + // CAPSTYPE_OFFSCREENCACHE (17, LE) + (byte)0x0c, (byte)0x00, // length of capability set: 12 bytes (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // offscreenSupportLevel: + // FALSE (LE) + (byte)0x00, (byte)0x00, // offscreenCacheSize: 0 (LE) + (byte)0x00, (byte)0x00, // offscreenCacheEntries: 0 (LE) + + }); + } + + private void writeGlyphCacheCS(ByteBuffer buf) { + numberCapabilities++; + buf.writeBytes(new byte[] { + // + // Glyph Cache Capability Set (52 bytes), see + // http://msdn.microsoft.com/en-us/library/cc240565.aspx + (byte)0x10, (byte)0x00, // capability set type: + // CAPSTYPE_OFFSCREENCACHE (16, LE) + (byte)0x34, (byte)0x00, // length of capability set: 52 bytes (LE) + // Glyph Cache (40 bytes) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x04, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x04, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x08, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x08, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x10, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x20, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x40, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x80, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x00, (byte)0x01, // CacheMaximumCellSize: 4 (LE) + (byte)0x40, (byte)0x00, // CacheEntries: 64 (LE) + (byte)0x00, (byte)0x08, // CacheMaximumCellSize: 2048 (LE) + // FragCache + (byte)0x00, (byte)0x01, // CacheEntries: 256 (LE) + (byte)0x00, (byte)0x01, // CacheMaximumCellSize: 256 (LE) + // + (byte)0x00, (byte)0x00, // GlyphSupportLevel: GLYPH_SUPPORT_NONE (0x0, + // LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + }); + } + + /** + * Example. + */ + public static void main(String args[]) { + // System.setProperty("streamer.Link.debug", "true"); + System.setProperty("streamer.Element.debug", "true"); + // System.setProperty("streamer.Pipeline.debug", "true"); + + /* @formatter:off */ + byte[] packet = new byte[] { + // MCS Send Data Request + (byte)0x64, + + // Initiator: 1004 (1001+3) + (byte)0x00, (byte)0x03, + + // Channel ID: 1003 (I/O channel) + (byte)0x03, (byte)0xeb, + + // Data priority: high (0x40), segmentation: begin (0x20) | end (0x10) + (byte)0x70, + + // User data length: 432 bytes (0x1b0, variable length field) + (byte)0x81, (byte)0xb0, + + // Total length: 432 bytes (0x1b0, LE) + (byte)0xb0, (byte)0x01, + + // PDU type: Confirm Active PDU (0x3), TS_PROTOCOL_VERSION (0x10) (LE) + (byte)0x13, (byte)0x00, + + // PDU source: 1004 (LE) + (byte)0xec, (byte)0x03, + + // Share ID: 0x000103ea (LE) + (byte)0xea, (byte)0x03, (byte)0x01, (byte)0x00, + + // Originator ID: 1002 (LE) + (byte)0xea, (byte)0x03, + + // Length of source descriptor: 6 bytes (including NULL character) (LE) + (byte)0x06, (byte)0x00, + + // Length of combined capabilities: 410 bytes (LE) + (byte)0x9a, (byte)0x01, + + // Source descriptor: "MSTSC" ??? + (byte)0x4d, (byte)0x53, (byte)0x54, (byte)0x53, (byte)0x43, (byte)0x00, + + // Number of capabilities: 15 (LE) + (byte)0x0f, (byte)0x00, + + // Padding 2 bytes + (byte)0x00, (byte)0x00, + + // Capabilities, see http://msdn.microsoft.com/en-us/library/cc240486.aspx + + // + // General capability set (24 bytes), see http://msdn.microsoft.com/en-us/library/cc240549.aspx + (byte)0x01, (byte)0x00, // capability set type: CAPSTYPE_GENERAL (1) (LE) + (byte)0x18, (byte)0x00, // length of capability set: 24 bytes (LE) + (byte)0x01, (byte)0x00, // TS_OSMAJORTYPE_WINDOWS (1) (LE) + (byte)0x03, (byte)0x00, // TS_OSMINORTYPE_WINDOWS_NT (3) (LE) + (byte)0x00, (byte)0x02, // TS_CAPS_PROTOCOLVERSION (0x0200) (LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + (byte)0x00, (byte)0x00, // generalCompressionTypes: 0 (LE) + + // Extra flags: 0x040d (LE) +// FastPathOutput: (...............1) Advertiser supports fast-path output +// ShadowCompression: (..............0.) Advertiser NOT supports shadow compression +// LongLengthCredentials: (.............1..) Advertiser supports long-length credentials for the user name, password, or domain name +// SessionAutoreconnection: (............1...) Advertiser supports session auto-reconnection +// ImprovedEncryptionChecksum: (...........0....) Client and server NOT support improved encryption checksum +// Reserved1: (......00000.....) +// CompressedBitMapDataFlag: (.....1..........) No 8-UINT8 header is present for compressed bitmap data +// Reserved2: (00000...........) + (byte)0x0d, (byte)0x04, + + (byte)0x00, (byte)0x00, // updateCapabilityFlag: 0 (LE) + (byte)0x00, (byte)0x00, // remoteUnshareFlag: 0 (LE) + (byte)0x00, (byte)0x00, // generalCompressionLevel: 0 (LE) + (byte)0x00, // refreshRectSupport: FALSE (0) + (byte)0x00, // suppressOutputSupport: FALSE (0) + + // + // Bitmap capability set (28 bytes), see http://msdn.microsoft.com/en-us/library/cc240554.aspx + (byte)0x02, (byte)0x00, // capability set type: CAPSTYPE_BITMAP (2) (LE) + (byte)0x1c, (byte)0x00, // length of capability set: 28 bytes (LE) + (byte)0x10, (byte)0x00, // preferredBitsPerPixel: 16 bpp (LE) + (byte)0x01, (byte)0x00, // receive1BitPerPixel (ignored and SHOULD be set to TRUE (0x1)): TRUE (0x1) (LE) + (byte)0x01, (byte)0x00, // receive4BitsPerPixel (ignored and SHOULD be set to TRUE (0x1)): TRUE (0x1) (LE) + (byte)0x01, (byte)0x00, // receive8BitsPerPixel (ignored and SHOULD be set to TRUE (0x1)): TRUE (0x1) (LE) + (byte)0x00, (byte)0x04, // desktopWidth = 1024 pixels (LE) + (byte)0x00, (byte)0x03, // desktopHeight = 768 pixels (LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + (byte)0x00, (byte)0x00, // desktopResizeFlag: FALSE (0x0) (LE) + (byte)0x01, (byte)0x00, // bitmapCompressionFlag (must be set to TRUE (0x1)): TRUE (0x1) (LE) + (byte)0x00, // highColorFlags (field is ignored and SHOULD be set to zero): 0 + (byte)0x01, // drawingFlags: 0x1 TODO: padding, why 0x1 ??? + (byte)0x01, (byte)0x00, // multipleRectangleSupport: TRUE (LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + + // + // Order Capability Set (88 bytes), see http://msdn.microsoft.com/en-us/library/cc240556.aspx + (byte)0x03, (byte)0x00, // capability set type: CAPSTYPE_ORDER (3) (LE) + (byte)0x58, (byte)0x00, // length of capability set: 88 bytes (LE) + // terminalDescriptor = "" (16 bytes, UCS2) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // pad4octetsA + (byte)0x01, (byte)0x00, // desktopSaveXGranularity (ignored): 1 (LE) + (byte)0x14, (byte)0x00, // desktopSaveYGranularity (ignored): 20 (LE) + (byte)0x00, (byte)0x00, // pad2octetsA (ignored) + (byte)0x01, (byte)0x00, // maximumOrderLevel: ORD_LEVEL_1_ORDERS (1) + (byte)0x00, (byte)0x00, // number of fonts (ignored): 0 + (byte)0x4a, (byte)0x00, // orderFlags = 0x004a (LE), SOLIDPATTERNBRUSHONLY (0x40), ZEROBOUNDSDELTASSUPPORT (0x8, MUST), NEGOTIATEORDERSUPPORT (0x2, MUST) + // Order support: 32 bytes (no primary drawing orders are supported, so this array MUST be initialized to all zeros, use 0x01 for TRUE). + (byte)0x00, // TS_NEG_DSTBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_PATBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_SCRBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MEMBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MEM3BLT_INDEX: FALSE + (byte)0x00, // TS_NEG_ATEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_AEXTTEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_DRAWNINEGRID_INDEX: FALSE + (byte)0x00, // TS_NEG_LINETO_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTI_DRAWNINEGRID_INDEX: FALSE + (byte)0x00, // TS_NEG_OPAQUERECT_INDEX: FALSE + (byte)0x00, // TS_NEG_SAVEBITMAP_INDEX: FALSE + (byte)0x00, // TS_NEG_WTEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_MEMBLT_R2_INDEX: FALSE + (byte)0x00, // TS_NEG_MEM3BLT_R2_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTIDSTBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTIPATBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTISCRBLT_INDEX: FALSE + (byte)0x00, // TS_NEG_MULTIOPAQUERECT_INDEX: FALSE + (byte)0x00, // TS_NEG_FAST_INDEX_INDEX: FALSE + (byte)0x00, // TS_NEG_POLYGON_SC_INDEX: FALSE + (byte)0x00, // TS_NEG_POLYGON_CB_INDEX: FALSE + (byte)0x00, // TS_NEG_POLYLINE_INDEX: TRUE + (byte)0x00, // Unused: 0 + (byte)0x00, // TS_NEG_FAST_GLYPH_INDEX: FALSE + (byte)0x00, // TS_NEG_ELLIPSE_SC_INDEX: FALSE + (byte)0x00, // TS_NEG_ELLIPSE_CB_INDEX: FALSE + (byte)0x00, // TS_NEG_INDEX_INDEX: FALSE + (byte)0x00, // TS_NEG_WEXTTEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_WLONGTEXTOUT_INDEX: FALSE + (byte)0x00, // TS_NEG_WLONGEXTTEXTOUT_INDEX: FALSE + (byte)0x00, // Unused: 0 + (byte)0x00, (byte)0x00, // Text flags (ignored): 0 (LE) + (byte)0x00, (byte)0x00, // Order support extra flags: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Padding 4 bytes + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Desktop save size (ignored): 0 (assumed to be 230400 bytes (480*480, 0x38400, LE)) + (byte)0x00, (byte)0x00, // Padding 2 bytes + (byte)0x00, (byte)0x00, // Padding 2 bytes + (byte)0xe4, (byte)0x04, // Text ANSI Code Page: 1252, ANSI - Latin I (0x04e4, LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + + // + // Bitmap Cache Rev. 2 Capability Set (40 bytes), see http://msdn.microsoft.com/en-us/library/cc240560.aspx + (byte)0x13, (byte)0x00, // capability set type: CAPSTYPE_BITMAPCACHE_REV2 (19) (LE) + (byte)0x28, (byte)0x00, // length of capability set: 40 bytes (LE) + (byte)0x00, (byte)0x00, // Cache flags: 0 (LE) + (byte)0x00, // Padding 1 byte + (byte)0x00, // Number of cell caches: 0 + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache0 cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache1 cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache2 cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache3 cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Bitmap cache4 cell info: 0 (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Padding 12 bytes + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Padding + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // Padding + + // + // Color Table Cache Capability Set (8 bytes), see http://msdn.microsoft.com/en-us/library/cc241564.aspx + (byte)0x0a, (byte)0x00, // capability set type: CAPSTYPE_COLORCACHE (10) (LE) + (byte)0x08, (byte)0x00, // length of capability set: 8 bytes (LE) + (byte)0x06, (byte)0x00, // Color table cache size (must be ignored during capability exchange and is assumed to be 0x0006): 6 (LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + + // + // Window Activation Capability Set (12 bytes), see http://msdn.microsoft.com/en-us/library/cc240569.aspx + (byte)0x07, (byte)0x00, // capability set type: CAPSTYPE_ACTIVATION (7) (LE) + (byte)0x0c, (byte)0x00, // length of capability set: 12 bytes (LE) + (byte)0x00, (byte)0x00, // helpKeyFlag (should be set to FALSE (0)): FALSE (0, LE) + (byte)0x00, (byte)0x00, // helpKeyIndexFlag (should be set to FALSE (0)): FALSE (0, LE) + (byte)0x00, (byte)0x00, // helpExtendedKeyFlag (should be set to FALSE (0)): FALSE (0, LE) + (byte)0x00, (byte)0x00, // windowManagerKeyFlag (should be set to FALSE (0)): FALSE (0, LE) + + // + // Control Capability Set (12 bytes), see http://msdn.microsoft.com/en-us/library/cc240568.aspx + (byte)0x05, (byte)0x00, // capability set type: CAPSTYPE_ACTIVATION (7) + (byte)0x0c, (byte)0x00, // length of capability set: 12 bytes (LE) + (byte)0x00, (byte)0x00, // controlFlags (should be set to 0): 0 (LE) + (byte)0x00, (byte)0x00, // remoteDetachFlag (should be set to 0): 0 (LE) + (byte)0x02, (byte)0x00, // controlInterest (should be set to CONTROLPRIORITY_NEVER): CONTROLPRIORITY_NEVER (2) (LE) + (byte)0x02, (byte)0x00, // detachInterest (should be set to CONTROLPRIORITY_NEVER): CONTROLPRIORITY_NEVER (2) (LE) + + // + // Pointer Capability Set (10 bytes), see http://msdn.microsoft.com/en-us/library/cc240562.aspx + (byte)0x08, (byte)0x00, // capability set type: CAPSTYPE_POINTER (8, LE) + (byte)0x0a, (byte)0x00, // length of capability set: 10 bytes (LE) + (byte)0x00, (byte)0x00, // colorPointerFlag: FALSE (LE) + (byte)0x00, (byte)0x00, // colorPointerCacheSize: 0 (LE) + (byte)0x14, (byte)0x00, // pointerCacheSize: 20 (LE) + + // + // Share Capability Set (8 bytes), see http://msdn.microsoft.com/en-us/library/cc240570.aspx + (byte)0x09, (byte)0x00, // capability set type: CAPSTYPE_SHARE (9, LE) + (byte)0x08, (byte)0x00, // length of capability set: 8 bytes (LE) + (byte)0x00, (byte)0x00, // nodeID (must be set to 0 by client): 0 (LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes (LE) + + // + // Input Capability Set (88 bytes), see http://msdn.microsoft.com/en-us/library/cc240563.aspx + (byte)0x0d, (byte)0x00, // capability set type: CAPSTYPE_INPUT (13, LE) + (byte)0x58, (byte)0x00, // length of capability set: 88 bytes (LE) + (byte)0x35, (byte)0x00, // inputFlags: 0x0035 (LE), INPUT_FLAG_FASTPATH_INPUT2 (0x20), INPUT_FLAG_VKPACKET (0x10), INPUT_FLAG_MOUSEX (0x4), INPUT_FLAG_SCANCODES (0x1) + (byte)0x00, (byte)0x00, // Padding 2 bytes + (byte)0x09, (byte)0x04, (byte)0x00, (byte)0x00, // keyboardLayout: "US" keyboard layout (0x000409, LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // keyboardType: unknown (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // keyboardSubType: unknown (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // keyboardFunctionKey: unknown (LE) + // imeFileName: "", (64 bytes, including trailing NULL characters, UCS2) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + + // + // Brush Capability Set (8 bytes), see http://msdn.microsoft.com/en-us/library/cc240564.aspx + (byte)0x0f, (byte)0x00, // capability set type: CAPSTYPE_BRUSH (15, LE) + (byte)0x08, (byte)0x00, // length of capability set: 8 bytes (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // brushSupportLevel: BRUSH_DEFAULT (0x0, LE) + + // + // Sound Capability Set (8 bytes), see http://msdn.microsoft.com/en-us/library/cc240552.aspx + (byte)0x0c, (byte)0x00, // capability set type: CAPSTYPE_SOUND (12, LE) + (byte)0x08, (byte)0x00, // length of capability set: 8 bytes (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // soundFlags: 0x0000 (LE) // SOUND_FLAG_BEEPS (0x1) + + // + // Font Capability Set (8 bytes), see http://msdn.microsoft.com/en-us/library/cc240571.aspx + (byte)0x0e, (byte)0x00, + (byte)0x08, (byte)0x00, + (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, + + // + // Offscreen Bitmap Cache Capability Set (12 bytes), see http://msdn.microsoft.com/en-us/library/cc240550.aspx + (byte)0x11, (byte)0x00, // capability set type: CAPSTYPE_OFFSCREENCACHE (17, LE) + (byte)0x0c, (byte)0x00, // length of capability set: 12 bytes (LE) + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // offscreenSupportLevel: FALSE (LE) + (byte)0x00, (byte)0x00, // offscreenCacheSize: 0 (LE) + (byte)0x00, (byte)0x00, // offscreenCacheEntries: 0 (LE) + + // + // Glyph Cache Capability Set (52 bytes), see http://msdn.microsoft.com/en-us/library/cc240565.aspx + (byte)0x10, (byte)0x00, // capability set type: CAPSTYPE_OFFSCREENCACHE (16, LE) + (byte)0x34, (byte)0x00, // length of capability set: 52 bytes (LE) + // Glyph Cache (40 bytes) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x04, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x04, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x08, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x08, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x10, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x20, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x40, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x80, (byte)0x00, // CacheMaximumCellSize: 4 (LE) + (byte)0xfe, (byte)0x00, // CacheEntries: 254 (LE) + (byte)0x00, (byte)0x01, // CacheMaximumCellSize: 4 (LE) + (byte)0x40, (byte)0x00, // CacheEntries: 64 (LE) + (byte)0x00, (byte)0x08, // CacheMaximumCellSize: 2048 (LE) + // FragCache + (byte)0x00, (byte)0x01, // CacheEntries: 256 (LE) + (byte)0x00, (byte)0x01, // CacheMaximumCellSize: 256 (LE) + // + (byte)0x00, (byte)0x00, // GlyphSupportLevel: GLYPH_SUPPORT_NONE (0x0, LE) + (byte)0x00, (byte)0x00, // Padding 2 bytes + }; + /* @formatter:on */ + + RdpState rdpState = new RdpState(); + ScreenDescription screenDescription = new ScreenDescription(); + screenDescription.setFramebufferSize(1024, 768); + + rdpState.serverShareId = 0x000103ea; + + MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {})); + Element confirm_active = new ClientConfirmActivePDU("confirm_active", screenDescription, rdpState); + Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet)); + + Pipeline pipeline = new PipelineImpl("test"); + pipeline.add(source, confirm_active, sink); + pipeline.link("source", "confirm_active", "sink"); + pipeline.runMainLoop("source", STDOUT, false, false); + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientFastPathPDU.java ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientFastPathPDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientFastPathPDU.java new file mode 100755 index 0000000..108429c --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientFastPathPDU.java @@ -0,0 +1,55 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package rdpclient.rdp; + +import streamer.BaseElement; +import streamer.ByteBuffer; +import streamer.Link; + +/** + * @see http://msdn.microsoft.com/en-us/library/cc240589.aspx + */ +public class ClientFastPathPDU extends BaseElement { + + public ClientFastPathPDU(String id) { + super(id); + } + + @Override + public void handleData(ByteBuffer buf, Link link) { + if (verbose) + System.out.println("[" + this + "] INFO: Data received: " + buf + "."); + + if (buf.length > 32767 - 3) + throw new RuntimeException("Packet is too long: " + buf + "."); + + ByteBuffer data = new ByteBuffer(6); + + // FastPath, 1 event, no checksum, not encrypted + data.writeByte(0x4); + + // Length of full packet, including length field, in network order. + // Topmost bit of first byte indicates that field has 2 bytes + data.writeShort((1 + 2 + buf.length) | 0x8000); + data.trimAtCursor(); + + buf.prepend(data); + + pushDataToAllOuts(buf); + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientInfoPDU.java ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientInfoPDU.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientInfoPDU.java new file mode 100755 index 0000000..7334d7f --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientInfoPDU.java @@ -0,0 +1,456 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package rdpclient.rdp; + +import streamer.ByteBuffer; +import streamer.Element; +import streamer.Link; +import streamer.OneTimeSwitch; +import streamer.Pipeline; +import streamer.PipelineImpl; +import streamer.debug.MockSink; +import streamer.debug.MockSource; + +/** + * @see http://msdn.microsoft.com/en-us/library/cc240475.aspx + */ +public class ClientInfoPDU extends OneTimeSwitch { + + public static final int INFO_MOUSE = 0x1; + public static final int INFO_DISABLECTRLALTDEL = 0x2; + public static final int INFO_UNICODE = 0x10; + + public static final int INFO_MAXIMIZESHELL = 0x20; + public static final int INFO_LOGONNOTIFY = 0x40; + public static final int INFO_ENABLEWINDOWSKEY = 0x100; + public static final int INFO_MOUSE_HAS_WHEEL = 0x00020000; + public static final int INFO_NOAUDIOPLAYBACK = 0x00080000; + + public static final int PERF_DISABLE_WALLPAPER = 0x1; + public static final int PERF_DISABLE_FULLWINDOWDRAG = 0x2; + public static final int PERF_DISABLE_MENUANIMATIONS = 0x4; + + protected byte[] userName = "".getBytes(RdpConstants.CHARSET_16); + protected byte[] password = "".getBytes(RdpConstants.CHARSET_16); // No effect + protected byte[] alternateShell = "".getBytes(RdpConstants.CHARSET_16); + protected byte[] domain = "".getBytes(RdpConstants.CHARSET_16); + protected byte[] workingDir = "".getBytes(RdpConstants.CHARSET_16); + protected byte[] clientAddress = "192.168.0.100".getBytes(RdpConstants.CHARSET_16); + protected byte[] clientDir = "C:\\Windows\\System32\\mstscax.dll".getBytes(RdpConstants.CHARSET_16); + + protected String standardTimeZoneName = "EET, Standard Time"; + protected String daylightTimeZoneName = "EET, Summer Time"; + protected int standardTimeZoneBias = 0; /* in minutes */ + protected int daylightTimeZoneBias = 60; /* in minutes */ + + public ClientInfoPDU(String id, String userName) { + super(id); + this.userName = userName.getBytes(RdpConstants.CHARSET_16); + } + + @Override + protected void handleOneTimeData(ByteBuffer buf, Link link) { + if (buf == null) + return; + + throw new RuntimeException("Unexpected packet: " + buf + "."); + } + + @Override + protected void onStart() { + super.onStart(); + + // Length of packet + ByteBuffer buf = new ByteBuffer(1024, true); + + // MCS Send Data Request PDU + buf.writeByte(0x64); + + // Initiator: 0x03 + 1001 = 1004 + buf.writeShort(3); + + // Channel ID: 1003 + buf.writeShort(1003); + + // Data priority: high, segmentation: begin | end (0x40 | 0x20 | 0x10 = 0x70) + buf.writeByte(0x70); + + // User data length: (variable length field) + int length = 224 + userName.length + password.length + alternateShell.length + domain.length + workingDir.length + clientAddress.length + clientDir.length; + buf.writeShort(length | 0x8000); + + // Flags: SEC_INFO_PKT (0x4000) + buf.writeShort(0x4000); + + // TS_SECURITY_HEADER::flagsHi - ignored + buf.writeShort(0x0000); + + // Codepage: 0 (UNKNOWN, LE) (use 0x04090409 (1033,1033) for EN_US) + buf.writeIntLE(0x0000); + + // Flags + buf.writeIntLE(INFO_MOUSE | INFO_DISABLECTRLALTDEL | INFO_UNICODE | + INFO_MAXIMIZESHELL | INFO_LOGONNOTIFY | INFO_ENABLEWINDOWSKEY | + INFO_MOUSE_HAS_WHEEL | INFO_NOAUDIOPLAYBACK); + + // + // Lengths + // + + // cbDomain length: 0 bytes (LE) (NOT including size of mandatory NULL terminator) + buf.writeShortLE(domain.length); + + // cbUserName length: 16 bytes (0x10, LE) (NOT including size of mandatory NULL terminator) + buf.writeShortLE(userName.length); + + // cbPassword length: (LE) (NOT including size of mandatory NULL terminator) + buf.writeShortLE(password.length); + + // cbAlternateShell: (LE) (NOT including size of mandatory NULL terminator) + buf.writeShortLE(alternateShell.length); + + // cbWorkingDir: (LE) (NOT including size of mandatory NULL terminator) + buf.writeShortLE(workingDir.length); + + // + // Values + // + + // Domain: (UCS2), see cbDomain + buf.writeBytes(domain); + buf.writeShort(0); + + // User name: (UCS2), see cbUserName + buf.writeBytes(userName); + buf.writeShort(0); + + // Password: (UCS2), see cbPassword + buf.writeBytes(password); + buf.writeShort(0); + + // Alternate shell: (UCS2), see cbAlternateShell + buf.writeBytes(alternateShell); + buf.writeShort(0); + + // Working directory: (UCS2), see cbWorkingDir + buf.writeBytes(workingDir); + buf.writeShort(0); + + // Client address family: 2 (AF_INET, LE) + buf.writeShortLE(2); + + // cbClientAddress: ( LE) (including the size of the mandatory NULL terminator) + buf.writeShortLE(clientAddress.length + 2); + + // Client address: (UCS2) + buf.writeBytes(clientAddress); + buf.writeShort(0); + + // cbClientDir: 64 bytes (0x40, LE) (including the size of the mandatory NULL terminator) + buf.writeShortLE(clientDir.length + 2); + + // Client directory: (UCS2) + buf.writeBytes(clientDir); + buf.writeShort(0); + + // + // Client time zone: + // + + // Bias: 0 minutes (LE) + buf.writeIntLE(0); + + // Standard name: "EET, Standard Time" (fixed string: 64 bytes, UCS2) + buf.writeFixedString(62, standardTimeZoneName, RdpConstants.CHARSET_16); + buf.writeShort(0); + + // Standard date + buf.writeBytes(new byte[] { + // wYear: 0 (LE) + (byte)0x00, (byte)0x00, + // wMonth: unknown (LE) + (byte)0x00, (byte)0x00, + // wDayOfWeek: Sunday (LE) + (byte)0x00, (byte)0x00, + // wDay: unknown (LE) + (byte)0x00, (byte)0x00, + // wHour: 0 (LE) + (byte)0x00, (byte)0x00, + // wMinute: 0 (LE) + (byte)0x00, (byte)0x00, + // wSecond: 0 (LE) + (byte)0x00, (byte)0x00, + // wMilliseconds: 0 + (byte)0x00, (byte)0x00, + + }); + + // StandardBias: 0 minutes (LE) + buf.writeIntLE(standardTimeZoneBias); + + // Daylight name: "EET, Summer Time" (fixed string: 64 bytes, UCS2) + buf.writeFixedString(62, daylightTimeZoneName, RdpConstants.CHARSET_16); + buf.writeShort(0); + + // Daylight date + buf.writeBytes(new byte[] { + // wYear: 0 (LE) + (byte)0x00, (byte)0x00, + // wMonth: unknown (LE) + (byte)0x00, (byte)0x00, + // wDayOfWeek: Sunday (LE) + (byte)0x00, (byte)0x00, + // wDay: unknown (LE) + (byte)0x00, (byte)0x00, + // wHour: 0 (LE) + (byte)0x00, (byte)0x00, + // wMinute: 0 (LE) + (byte)0x00, (byte)0x00, + // wSecond: 0 (LE) + (byte)0x00, (byte)0x00, + // wMilliseconds: 0 + (byte)0x00, (byte)0x00, + + }); + + // Daylight bias: 60 minutes (LE) + buf.writeIntLE(daylightTimeZoneBias); + + // Client session ID: 0x00000000 (LE) + buf.writeIntLE(0); + + // Performance flags: 0x7 (LE) = PERF_DISABLE_WALLPAPER (0x1), PERF_DISABLE_FULLWINDOWDRAG (0x2), PERF_DISABLE_MENUANIMATIONS (0x4) + buf.writeIntLE(PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS); + + // cbAutoReconnectCookie: 0 bytes (LE) + buf.writeShortLE(0); + + // Trim buffer to actual length of data written + buf.trimAtCursor(); + + pushDataToOTOut(buf); + + switchOff(); + } + + /** + * Example. + */ + public static void main(String args[]) { + // System.setProperty("streamer.Link.debug", "true"); + System.setProperty("streamer.Element.debug", "true"); + // System.setProperty("streamer.Pipeline.debug", "true"); + + /* @formatter:off */ + byte[] packet = new byte[] { + + // TPKT + (byte) 0x03, (byte) 0x00, + + // TPKT length: 343 bytes + (byte) 0x01, (byte) 0x57, + + // X224 Data PDU + (byte) 0x02, (byte) 0xf0, (byte) 0x80, + + + // MCS Send Data Request PDU + (byte) 0x64, + + // Initiator: 0x03 + 1001 = 1004 + (byte) 0x00, (byte) 0x03, + + // Channel ID: 1003 (IO Channel) + (byte) 0x03, (byte) 0xeb, + + // Data priority: high, segmentation: begin | end (0x40 | 0x20 | 0x10 = 0x70) + (byte) 0x70, + + // User data length: 328 (0x148) bytes, variable length field + (byte) 0x81, (byte) 0x48, + + // Flags: SEC_INFO_PKT (0x4000) + (byte) 0x40, (byte) 0x00, + + // TS_SECURITY_HEADER::flagsHi - ignored + (byte) 0x00, (byte) 0x00, + + // Codepage: 0 (UNKNOWN, LE) (use 0x04090409 (1033,1033) for EN_US) + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // Flags: 0xa0173 (LE), INFO_MOUSE (0x1), INFO_DISABLECTRLALTDEL (0x2), INFO_UNICODE (0x10), + // INFO_MAXIMIZESHELL (0x20), INFO_LOGONNOTIFY (0x40), INFO_ENABLEWINDOWSKEY (0x100), + // INFO_MOUSE_HAS_WHEEL (0x00020000), INFO_NOAUDIOPLAYBACK (0x00080000), + (byte) 0x73, (byte) 0x01, (byte) 0x0a, (byte) 0x00, + + // Lengths + + // cbDomain length: 0 bytes (LE) (NOT including size of mandatory NULL terminator) + (byte) 0x00, (byte) 0x00, + + // cbUserName length: 16 bytes (0x10, LE) (NOT including size of mandatory NULL terminator) + (byte) 0x10, (byte) 0x00, + + // cbPassword length: 0 bytes (LE) (NOT including size of mandatory NULL terminator) + (byte) 0x00, (byte) 0x00, + + // cbAlternateShell: 0 bytes (LE) (NOT including size of mandatory NULL terminator) + (byte) 0x00, (byte) 0x00, + + // cbWorkingDir: 0 bytes (LE) (NOT including size of mandatory NULL terminator) + (byte) 0x00, (byte) 0x00, + + // Values + + // Domain: "" (UCS2), see cbDomain + (byte) 0x00, (byte) 0x00, + + // User name: "vlisivka" (UCS2), see cbUserName + (byte) 0x76, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x73, (byte) 0x00, + (byte) 0x69, (byte) 0x00, (byte) 0x76, (byte) 0x00, (byte) 0x6b, (byte) 0x00, (byte) 0x61, (byte) 0x00, + (byte) 0x00, (byte) 0x00, + + // Password: "" (UCS2), see cbPassword + (byte) 0x00, (byte) 0x00, + + // Alternate shell: "" (UCS2), see cbAlternateShell + (byte) 0x00, (byte) 0x00, + + // Working directory: "" (UCS2), see cbWorkingDir + (byte) 0x00, (byte) 0x00, + + // Client address family: 2 (AF_INET, LE) + (byte) 0x02, (byte) 0x00, + + // cbClientAddress = 28 bytes (0x1c, LE) (including the size of the mandatory NULL terminator) + (byte) 0x1c, (byte) 0x00, + + // Client address: "192.168.0.100" (UCS2) + (byte) 0x31, (byte) 0x00, (byte) 0x39, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x2e, (byte) 0x00, + (byte) 0x31, (byte) 0x00, (byte) 0x36, (byte) 0x00, (byte) 0x38, (byte) 0x00, (byte) 0x2e, (byte) 0x00, + (byte) 0x30, (byte) 0x00, (byte) 0x2e, (byte) 0x00, (byte) 0x31, (byte) 0x00, (byte) 0x30, (byte) 0x00, + (byte) 0x30, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // cbClientDir: 64 bytes (0x40, LE) (including the size of the mandatory NULL terminator) + (byte) 0x40, (byte) 0x00, + + // Client directory: "C:\Windows\System32\mstscax.dll" (UCS2) + (byte) 0x43, (byte) 0x00, (byte) 0x3a, (byte) 0x00, (byte) 0x5c, (byte) 0x00, (byte) 0x57, (byte) 0x00, + (byte) 0x69, (byte) 0x00, (byte) 0x6e, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x6f, (byte) 0x00, + (byte) 0x77, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x5c, (byte) 0x00, (byte) 0x53, (byte) 0x00, + (byte) 0x79, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x65, (byte) 0x00, + (byte) 0x6d, (byte) 0x00, (byte) 0x33, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x5c, (byte) 0x00, + (byte) 0x6d, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x73, (byte) 0x00, + (byte) 0x63, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x78, (byte) 0x00, (byte) 0x2e, (byte) 0x00, + (byte) 0x64, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // + // Client time zone: + + // Bias: 0 minutes (LE) + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // Standard name: "EET, Standard Time" (fixed string: 64 bytes, UCS2) + (byte) 0x45, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x2c, (byte) 0x00, + (byte) 0x20, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x61, (byte) 0x00, + (byte) 0x6e, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x72, (byte) 0x00, + (byte) 0x64, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x69, (byte) 0x00, + (byte) 0x6d, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // + // Standard date + // wYear: 0 (LE) + (byte) 0x00, (byte) 0x00, + // wMonth: unknown (LE) + (byte) 0x00, (byte) 0x00, + // wDayOfWeek: Sunday (LE) + (byte) 0x00, (byte) 0x00, + // wDay: unknown (LE) + (byte) 0x00, (byte) 0x00, + // wHour: 0 (LE) + (byte) 0x00, (byte) 0x00, + // wMinute: 0 (LE) + (byte) 0x00, (byte) 0x00, + // wSecond: 0 (LE) + (byte) 0x00, (byte) 0x00, + // wMilliseconds: 0 + (byte) 0x00, (byte) 0x00, + + // StandardBias: 0 minutes (LE) + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // Daylight name: "EET, Summer Time" (fixed string: 64 bytes, UCS2) + (byte) 0x45, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x2c, (byte) 0x00, + (byte) 0x20, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x75, (byte) 0x00, (byte) 0x6d, (byte) 0x00, + (byte) 0x6d, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x20, (byte) 0x00, + (byte) 0x54, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x6d, (byte) 0x00, (byte) 0x65, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // Daylight date + // wYear: 0 (LE) + (byte) 0x00, (byte) 0x00, + // wMonth: unknown (LE) + (byte) 0x00, (byte) 0x00, + // wDayOfWeek: Sunday (LE) + (byte) 0x00, (byte) 0x00, + // wDay: unknown (LE) + (byte) 0x00, (byte) 0x00, + // wHour: 0 (LE) + (byte) 0x00, (byte) 0x00, + // wMinute: 0 (LE) + (byte) 0x00, (byte) 0x00, + // wSecond: 0 (LE) + (byte) 0x00, (byte) 0x00, + // wMilliseconds: 0 + (byte) 0x00, (byte) 0x00, + + // Daylight bias: 60 minutes (LE) + (byte) 0x3c, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + + // Client session ID: 0x00000000 (LE) + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // Performance flags: 0x7 (LE) = PERF_DISABLE_WALLPAPER (0x1), PERF_DISABLE_FULLWINDOWDRAG (0x2), PERF_DISABLE_MENUANIMATIONS (0x4) + (byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + // cbAutoReconnectCookie: 0 bytes (LE) + (byte) 0x00, (byte) 0x00, + }; + /* @formatter:on */ + + MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3})); + Element client_info = new ClientInfoPDU("client_info", "vlisivka"); + Element x224 = new ClientX224DataPDU("x224"); + Element tpkt = new ClientTpkt("tpkt"); + Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet)); + Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3})); + + Pipeline pipeline = new PipelineImpl("test"); + pipeline.add(source, client_info, x224, tpkt, sink, mainSink); + pipeline.link("source", "client_info", "mainSink"); + pipeline.link("client_info >" + OTOUT, "x224", "tpkt", "sink"); + pipeline.runMainLoop("source", STDOUT, false, false); + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSAttachUserRequest.java ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSAttachUserRequest.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSAttachUserRequest.java new file mode 100755 index 0000000..dbe8bd1 --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSAttachUserRequest.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package rdpclient.rdp; + +import streamer.ByteBuffer; +import streamer.Element; +import streamer.Link; +import streamer.OneTimeSwitch; +import streamer.Pipeline; +import streamer.PipelineImpl; +import streamer.debug.MockSink; +import streamer.debug.MockSource; + +/** + * @see http://msdn.microsoft.com/en-us/library/cc240684.aspx + */ +public class ClientMCSAttachUserRequest extends OneTimeSwitch { + + public ClientMCSAttachUserRequest(String id) { + super(id); + } + + @Override + protected void handleOneTimeData(ByteBuffer buf, Link link) { + if (buf == null) + return; + + throw new RuntimeException("Unexpected packet: " + buf + "."); + } + + @Override + protected void onStart() { + super.onStart(); + + int length = 1; + ByteBuffer buf = new ByteBuffer(length, true); + + buf.writeByte(0x28); // AttachUserRequest + + pushDataToOTOut(buf); + + switchOff(); + } + + /** + * Example. + */ + public static void main(String args[]) { + // System.setProperty("streamer.Link.debug", "true"); + System.setProperty("streamer.Element.debug", "true"); + // System.setProperty("streamer.Pipeline.debug", "true"); + + /* @formatter:off */ + byte[] packet = new byte[] { + + 0x03, 0x00, 0x00, 0x08, // TPKT Header (length = 8 bytes) + 0x02, (byte) 0xf0, (byte) 0x80, // X.224 Data TPDU + + // PER encoded (ALIGNED variant of BASIC-PER) PDU contents: + 0x28, + + // 0x28: + // 0 - --\ + // 0 - | + // 1 - | CHOICE: From DomainMCSPDU select attachUserRequest (10) + // 0 - | of type AttachUserRequest + // 1 - | + // 0 - --/ + // 0 - padding + // 0 - padding + + }; + /* @formatter:on */ + + MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3})); + Element todo = new ClientMCSAttachUserRequest("TODO"); + Element x224 = new ClientX224DataPDU("x224"); + Element tpkt = new ClientTpkt("tpkt"); + Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet)); + Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3})); + + Pipeline pipeline = new PipelineImpl("test"); + pipeline.add(source, todo, x224, tpkt, sink, mainSink); + pipeline.link("source", "TODO", "mainSink"); + pipeline.link("TODO >" + OTOUT, "x224", "tpkt", "sink"); + pipeline.runMainLoop("source", STDOUT, false, false); + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSChannelJoinRequest_ServerMCSChannelConfirmPDUs.java ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSChannelJoinRequest_ServerMCSChannelConfirmPDUs.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSChannelJoinRequest_ServerMCSChannelConfirmPDUs.java new file mode 100755 index 0000000..59dd233 --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/rdp/ClientMCSChannelJoinRequest_ServerMCSChannelConfirmPDUs.java @@ -0,0 +1,223 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package rdpclient.rdp; + +import streamer.ByteBuffer; +import streamer.Element; +import streamer.Link; +import streamer.OneTimeSwitch; +import streamer.Pipeline; +import streamer.PipelineImpl; +import streamer.debug.MockSink; +import streamer.debug.MockSource; + +/** + * The MCS Channel Join Request PDUs are sent sequentially. The first PDU is + * sent after receiving the MCS Attach User Confirm PDU and subsequent PDUs are + * sent after receiving the MCS Channel Join Confirm PDU for the previous + * request. Sending of the MCS Channel Join Request PDUs MUST continue until all + * channels have been successfully joined. + * + * @see http://msdn.microsoft.com/en-us/library/cc240686.aspx + */ +public class ClientMCSChannelJoinRequest_ServerMCSChannelConfirmPDUs extends OneTimeSwitch { + + private static final int MCS_CHANNEL_CONFIRM_PDU = 15; + + protected int[] channels; + protected int channelRequestsSent = 0; + + protected RdpState state; + + public ClientMCSChannelJoinRequest_ServerMCSChannelConfirmPDUs(String id, int[] channels, RdpState state) { + super(id); + this.channels = channels; + this.state = state; + } + + @Override + protected void handleOneTimeData(ByteBuffer buf, Link link) { + if (buf == null) + return; + + // Parse channel confirm response + int typeAndFlags = buf.readUnsignedByte(); + int type = typeAndFlags >> 2; + // int flags = typeAndFlags & 0x3; + + if (type != MCS_CHANNEL_CONFIRM_PDU) + throw new RuntimeException("[" + this + "] ERROR: Incorrect type of MCS AttachUserConfirm PDU. Expected value: 15, actual value: " + type + ", data: " + buf + "."); + + int rtSuccess = buf.readUnsignedByte() >> 4; + if (rtSuccess != 0) + throw new RuntimeException("[" + this + "] ERROR: Cannot connect to channel: request failed. Error code: " + rtSuccess + ", channel ID: " + + channels[channelRequestsSent - 1] + + ", data: " + buf + "."); + + // Initiator and requested fields MAY be ignored, however, the channelId + // field MUST be examined. If the value of the channelId field does not + // correspond with the value of the channelId field sent in the previous MCS + // Channel Join Request PDU the connection SHOULD be dropped. + + // Initiator: 1007 (6+1001) + // int initator=buf.readUnsignedShort(); + buf.skipBytes(2); + + // Requested channel + // int requestedChannel=buf.readUnsignedShort(); + buf.skipBytes(2); + + // Actual channel + int actualChannel = buf.readUnsignedShort(); + if (actualChannel != channels[channelRequestsSent - 1]) + throw new RuntimeException("Unexpeceted channeld ID returned. Expected channeld ID: " + channels[channelRequestsSent - 1] + ", actual channel ID: " + + actualChannel + ", data: " + buf + "."); + + state.channelJoined(actualChannel); + + buf.unref(); + + if (channelRequestsSent < channels.length) + sendChannelRequest(channels[channelRequestsSent++]); + else + switchOff(); + } + + @Override + protected void onStart() { + super.onStart(); + + sendChannelRequest(channels[channelRequestsSent++]); + + // Switch off after receiving response(s) + } + + private void sendChannelRequest(int channel) { + ByteBuffer buf = new ByteBuffer(5, true); + + buf.writeByte(0x38); // Channel Join request + + buf.writeShort(state.serverUserChannelId - 1001); // ChannelJoinRequest::initiator: 1004 + buf.writeShort(channel); + + pushDataToOTOut(buf); + } + + /** + * Example. + * + * @see http://msdn.microsoft.com/en-us/library/cc240834.aspx + */ + public static void main(String args[]) { + // System.setProperty("streamer.Link.debug", "true"); + System.setProperty("streamer.Element.debug", "true"); + // System.setProperty("streamer.Pipeline.debug", "true"); + + /* @formatter:off */ + byte[] clientRequestPacket = new byte[] { + 0x03, 0x00, 0x00, 0x0c, // TPKT Header (length = 12 bytes) + 0x02, (byte) 0xf0, (byte) 0x80, // X.224 Data TPDU + + // PER encoded (ALIGNED variant of BASIC-PER) PDU contents: + 0x38, 0x00, 0x03, 0x03, (byte) 0xef, + + // 0x38: + // 0 - --\ + // 0 - | + // 1 - | CHOICE: From DomainMCSPDU select channelJoinRequest (14) + // 1 - | of type ChannelJoinRequest + // 1 - | + // 0 - --/ + // 0 - padding + // 0 - padding + + // 0x00: + // 0 - --\ + // 0 - | + // 0 - | + // 0 - | + // 0 - | + // 0 - | + // 0 - | + // 0 - | + // | ChannelJoinRequest::initiator = 0x03 + 1001 = 1004 + // 0x03: | + // 0 - | + // 0 - | + // 0 - | + // 0 - | + // 0 - | + // 1 - | + // 1 - | + // 0 - --/ + + // 0x03: + // 0 - --\ + // 0 - | + // 0 - | + // 0 - | + // 0 - | + // 0 - | + // 1 - | + // 1 - | + // | ChannelJoinRequest::channelId = 0x03ef = 1007 + // 0xef: | + // 1 - | + // 1 - | + // 1 - | + // 0 - | + // 1 - | + // 1 - | + // 1 - | + // 1 - --/ + }; + + byte[] serverResponsePacket = new byte[] { + // MCS Channel Confirm + (byte)0x3e, + + // result: rt-successful (0) + (byte)0x00, + + // Initiator: 1007 (6+1001) + (byte)0x00, (byte)0x06, + + // Requested channel + (byte)0x03, (byte)0xef, + + // Actual channel + (byte)0x03, (byte)0xef, + }; + /* @formatter:on */ + + RdpState rdpState = new RdpState(); + rdpState.serverUserChannelId = 1004; + MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(serverResponsePacket, new byte[] {1, 2, 3})); + Element todo = new ClientMCSChannelJoinRequest_ServerMCSChannelConfirmPDUs("channels", new int[] {1007}, rdpState); + Element x224 = new ClientX224DataPDU("x224"); + Element tpkt = new ClientTpkt("tpkt"); + Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(clientRequestPacket)); + Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3})); + + Pipeline pipeline = new PipelineImpl("test"); + pipeline.add(source, todo, x224, tpkt, sink, mainSink); + pipeline.link("source", "channels", "mainSink"); + pipeline.link("channels >" + OTOUT, "x224", "tpkt", "sink"); + pipeline.runMainLoop("source", STDOUT, false, false); + } + +}