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 CA81610E9F for ; Fri, 8 Nov 2013 08:16:27 +0000 (UTC) Received: (qmail 85303 invoked by uid 500); 8 Nov 2013 08:16:07 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 85211 invoked by uid 500); 8 Nov 2013 08:16:05 -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 85186 invoked by uid 99); 8 Nov 2013 08:16:05 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 08 Nov 2013 08:16:05 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 05561815411; Fri, 8 Nov 2013 08:16:04 +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: Fri, 08 Nov 2013 08:16:04 -0000 Message-Id: <55bcc409d79f44b5b89e0a77af68f2b3@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [1/9] Remote Desktop Protocol(RDP) client that is suitable for including in the console VM. The client renders RDP to a window created by Java. It is important for Hyper-V support, because Hyper-V provides access to the consoles of VMs that it is running Updated Branches: refs/heads/master 57ba367f3 -> a98c473dc http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/Vnc_3_3_Hello.java ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/Vnc_3_3_Hello.java b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/Vnc_3_3_Hello.java new file mode 100644 index 0000000..323380b --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/main/java/vncclient/Vnc_3_3_Hello.java @@ -0,0 +1,115 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package vncclient; + +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 Vnc_3_3_Hello extends OneTimeSwitch { + + public Vnc_3_3_Hello(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(); + + } + + 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); + + Vnc_3_3_Hello hello = new Vnc_3_3_Hello("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/a98c473d/services/console-proxy-rdp/rdpconsole/src/test/doc/README.txt ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/test/doc/README.txt b/services/console-proxy-rdp/rdpconsole/src/test/doc/README.txt new file mode 100644 index 0000000..dd41683 --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/test/doc/README.txt @@ -0,0 +1,32 @@ +// 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. + +To debug RDP sessions with Network Monitor or Wireshark, you need to +configure RDP server with custom private key. For Network Monitor +Decrypt Expert, you also will need to downgrade RDP server TLS protocol +to version 1.0. + +File dev-rdp-config.bat contains instructions to configure RDP to use custom +key, open firewall, disable NLA, downgrade TLS, and start RDP service. + +File rdp.pfx contains custom private key (password: test) for use with +rdp-config.bat and Network Monitor Decrypt Expert. If you will generate +your own key, you will need to alter rpd-file.bat to use it +fingerprints. + +File rdp-key.pem contains private key in PEM format for use with +Wireshark. http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/test/doc/dev-rdp-config.bat ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/test/doc/dev-rdp-config.bat b/services/console-proxy-rdp/rdpconsole/src/test/doc/dev-rdp-config.bat new file mode 100644 index 0000000..14a7bbd --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/test/doc/dev-rdp-config.bat @@ -0,0 +1,126 @@ +rem Licensed to the Apache Software Foundation (ASF) under one +rem or more contributor license agreements. See the NOTICE file +rem distributed with this work for additional information +rem regarding copyright ownership. The ASF licenses this file +rem to you under the Apache License, Version 2.0 (the +rem "License"); you may not use this file except in compliance +rem with the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, +rem software distributed under the License is distributed on an +rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +rem KIND, either express or implied. See the License for the +rem specific language governing permissions and limitations +rem under the License. + +rem +rem Configure and start RDP service. +rem Configure RPD service to use custom key instead of autogenerated for Wireshark and Network Monitor Decrypt Expert. +rem rdp.pfx is necessary because it fingerprints are hardcoded in this script. +rem + +rem Turn off firewall + +netsh advfirewall firewall set rule group="Remote Desktop" new enable=yes + +rem Enable TS connections +rem +rem Windows Registry Editor Version 5.00 +rem +rem [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server] +rem "AllowTSConnections"=dword:00000001 +rem "fDenyTSConnections"=dword:00000000 + +reg add "HKLM\System\CurrentControlSet\Control\Terminal Server" /v "AllowTSConnections" /t REG_DWORD /d 1 /f +reg add "HKLM\System\CurrentControlSet\Control\Terminal Server" /v "fDenyTSConnections" /t REG_DWORD /d 0 /f + +rem Disable RDP NLA + +reg add "HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f + +rem Enable TS service + +sc config TermService start=auto + +rem Certificate Generation + +rem Make self-signed certificate + +rem makecert -r -pe -n "CN=%COMPUTERNAME%" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr LocalMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 + +rem Import certificate + +certutil -p test -importPFX "Remote Desktop" rdp.pfx + +rem Configure RDP server to use certificate: + +rem Windows Registry Editor Version 5.00 +rem +rem [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp] +rem "SSLCertificateSHA1Hash"=hex:c1,70,84,70,bc,56,42,0a,bb,f4,35,35,ba,a6,09,b0,4e,98,4a,47 +reg add "HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v "SSLCertificateSHA1Hash" /t REG_HEX /d "" /f + +rem Grant permissions on certificate for everyone + +rem certutil -repairstore My "bcb40fb84ac891bd41068fe686864559" D:PAI(A;;GA;;;BA)(A;;GA;;;SY)(A;;GR;;;NS) +certutil -repairstore "Remote Desktop" "bcb40fb84ac891bd41068fe686864559" D:PAI(A;;GA;;;BA)(A;;GA;;;SY)(A;;GR;;;NS) + +rem confirm with + +rem certutil -store -v My +certutil -store -v "Remote Desktop" + +rem Disable TLS 1.1 (for Network Monitor Decrypt Expert) +rem +rem Windows Registry Editor Version 5.00 +rem +rem [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client] +rem "Enabled"=dword:00000000 +rem "DisabledByDefault"=dword:00000001 +rem +rem [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server] +rem "Enabled"=dword:00000000 +rem "DisabledByDefault"=dword:00000001 + +reg add "HKLM\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client" /v "Enabled" /t REG_DWORD /d 0 /f +reg add "HKLM\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client" /v "DisabledByDefault" /t REG_DWORD /d 1 /f +reg add "HKLM\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server" /v "Enabled" /t REG_DWORD /d 0 /f +reg add "HKLM\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server" /v "DisabledByDefault" /t REG_DWORD /d 1 /f + + +rem Disable TLS 1.2 (for Network Monitor Decrypt Expert) +rem +rem Windows Registry Editor Version 5.00 +rem +rem [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client] +rem "Enabled"=dword:00000000 +rem "DisabledByDefault"=dword:00000001 +rem +rem [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server] +rem "Enabled"=dword:00000000 +rem "DisabledByDefault"=dword:00000001 + +reg add "HKLM\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client" /v "Enabled" /t REG_DWORD /d 0 /f +reg add "HKLM\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client" /v "DisabledByDefault" /t REG_DWORD /d 1 /f +reg add "HKLM\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server" /v "Enabled" /t REG_DWORD /d 0 /f +reg add "HKLM\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server" /v "DisabledByDefault" /t REG_DWORD /d 1 /f + +rem Start TS service + +net start Termservice + + +rem For Network Monitor Decrypt Expert. + +rem Install .Net 3.5 + +rem dism /online /enable-feature /featurename:NetFx3ServerFeatures +rem dism /online /enable-feature /featurename:NetFx3 + +rem PS. +rem Don't forget to set Windows profile as active in Network Monitor, so SSL traffic branch will appear under +rem svnchost.exe, so you will be able to decrypt it (don't forget to save and reopen captured traffic to file first). +rem + http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/test/doc/rdp-key.pem ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/test/doc/rdp-key.pem b/services/console-proxy-rdp/rdpconsole/src/test/doc/rdp-key.pem new file mode 100644 index 0000000..cd050cd --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/test/doc/rdp-key.pem @@ -0,0 +1,23 @@ +Bag Attributes + Microsoft Local Key set: + localKeyID: 01 00 00 00 + friendlyName: 8fcf718d-921f-4bfc-9ae4-f63e9c66b6c7 + Microsoft CSP Name: Microsoft RSA SChannel Cryptographic Provider +Key Attributes + X509v3 Key Usage: 10 +-----BEGIN PRIVATE KEY----- +MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKrmMXjeoXRn6UFf +Hmw2HOnT/mEeSWQANzquJnKDBORIjD2rxL3h5FQ/DQUF4gm5JvBll8uWpDX11mVm +LlAZ2kA8KuJ2JuYEvu/GwuDyrP4D1sOiCwIjJnvmg5DjLB9sll5ohMbjMtiSFm5L +/YJNXop/pGJucvVzL4t0ZJ1zT2lZAgMBAAECgYAN/OJeuyyQeD+iXweaVTS5OzJ7 +PrBEgM03pQpp9zXx/P6LJUe1c2UUM8bvVGoJ+eW2HNkES/oSN2MLEKAVl7aCLWTe +7Ejc3JIRB7ZRdNt89w9XvxuRSn87pO082ciMsLvEqqDYahy3BxgI0J/GKbo28Zme +Z9f9QNCZ8TzbXJbDmwJBANVpBSfi09n5fUy3nGurGxE3chBnyik+Rft63fZp9eiD +lU5Q4l22+ZUTBChJUtLHztihcb4a4RQX6B4nH5Y1RtMCQQDNAVBKe2VfnFeEoIX7 +ooRnIKIVMxW08GENuJz64otshfH6jRaLL4E/QJLIpoNRFqafyuMkP5x8oZ3uvV1+ +nsujAkAd0Xez9ACP00lLn9gOPzEf/bRFUIsxqg7TLX64AGQoocIJ2ElYuMk0qByL +mHsnEl33bM9ctZq/WPvIwsSqEzWbAkAcb/k2S8W1LJfLUwUi8dlSAOna7Pou3kVo +RNqpxrE2faIicl3VMuLH5mo2ITsIDY9RjTBS/+vyMe0Zh/UnMlnnAkAAppLiJ15o +L3JlVbGRN+4kCP2HVtVRVIl3OlBoVSJZ5qe+s7HowTGurU/iYr1kmWd/C5sU0KPB +evwz8pdL08vr +-----END PRIVATE KEY----- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java ---------------------------------------------------------------------- diff --git a/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java b/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java new file mode 100644 index 0000000..cba01fd --- /dev/null +++ b/services/console-proxy-rdp/rdpconsole/src/test/java/rdpclient/MockServerTest.java @@ -0,0 +1,189 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package rdpclient; + +import static rdpclient.MockServer.Packet.PacketType.CLIENT; +import static rdpclient.MockServer.Packet.PacketType.SERVER; +import static rdpclient.MockServer.Packet.PacketType.UPGRADE_TO_SSL; + +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +import junit.framework.TestCase; +import rdpclient.MockServer.Packet; + +public class MockServerTest extends TestCase { + + public void testIsMockServerCanRespond() throws Exception { + + final byte[] mockClientData = new byte[] { 0x01, 0x02, 0x03 }; + final byte[] mockServerData = new byte[] { 0x03, 0x02, 0x01 }; + + MockServer server = new MockServer(new Packet[] { new Packet("Client hello") { + { + type = CLIENT; + data = mockClientData; + } + }, new Packet("Server hello") { + { + type = SERVER; + data = mockServerData; + } + } }); + + server.start(); + + // Connect to server and send and receive mock data + + Socket socket = SocketFactory.getDefault().createSocket(); + try { + socket.connect(server.getAddress()); + + InputStream is = socket.getInputStream(); + OutputStream os = socket.getOutputStream(); + + // Write mock data to server + os.write(mockClientData); + + // Read data from server + byte actualData[] = new byte[mockServerData.length]; + int actualDataLength = is.read(actualData); + + // Compare mock data with actual data + assertEquals("Unexpected length of actual data read from server.", mockServerData.length, actualDataLength); + + for (int i = 0; i < actualDataLength; i++) { + assertEquals("Unexpected byte #" + i + " in response", mockServerData[i], actualData[i]); + } + + server.waitUntilShutdowned(1 * 1000 /* up to 1 second */); + + assertNull("Unexpected exception at mock server side.", server.getException()); + assertTrue("Server is not shutdowned at after conversation.", server.isShutdowned()); + + } finally { + socket.close(); + } + } + + public void testIsMockServerCanUpgradeConnectionToSsl() throws Exception { + + final byte[] mockClientData1 = new byte[] { 0x01, 0x02, 0x03 }; + final byte[] mockServerData1 = new byte[] { 0x03, 0x02, 0x01 }; + + final byte[] mockClientData2 = new byte[] { 0x02, 0x04, 0x02, 0x03 }; + final byte[] mockServerData2 = new byte[] { 0x02, 0x02, 0x01, 0x04 }; + + MockServer server = new MockServer(new Packet[] { new Packet("Client hello") { + { + type = CLIENT; + data = mockClientData1; + } + }, new Packet("Server hello") { + { + type = SERVER; + data = mockServerData1; + } + }, new Packet("Upgrade connection to SSL") { + { + type = UPGRADE_TO_SSL; + } + }, new Packet("Client data over SSL") { + { + type = CLIENT; + data = mockClientData2; + } + }, new Packet("Server data over SSL") { + { + type = SERVER; + data = mockServerData2; + } + } }); + + server.start(); + + // Connect to server and send and receive mock data + + Socket socket = SocketFactory.getDefault().createSocket(); + try { + InetSocketAddress address = server.getAddress(); + socket.connect(address); + + // Send hello data over plain connection + { + InputStream is = socket.getInputStream(); + OutputStream os = socket.getOutputStream(); + + // Write mock data to server + os.write(mockClientData1); + + // Read data from server + byte actualData[] = new byte[mockServerData1.length]; + int actualDataLength = is.read(actualData); + + // Compare mock data with actual data + assertEquals("Unexpected length of actual data read from server.", mockServerData1.length, actualDataLength); + + for (int i = 0; i < actualDataLength; i++) { + assertEquals("Unexpected byte #" + i + " in response", mockServerData1[i], actualData[i]); + } + } + + // Upgrade connection to SSL and send mock data + { + //System.setProperty("javax.net.debug", "ssl"); + + final SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); + SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket, address.getHostString(), address.getPort(), true); + sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); + sslSocket.startHandshake(); + + InputStream is = sslSocket.getInputStream(); + OutputStream os = sslSocket.getOutputStream(); + + // Write mock data to server + os.write(mockClientData2); + + // Read data from server + byte actualData[] = new byte[mockServerData2.length]; + int actualDataLength = is.read(actualData); + + // Compare mock data with actual data + assertEquals("Unexpected length of actual data read from server.", mockServerData2.length, actualDataLength); + + for (int i = 0; i < actualDataLength; i++) { + assertEquals("Unexpected byte #" + i + " in response", mockServerData2[i], actualData[i]); + } + + } + + server.waitUntilShutdowned(1 * 1000 /* up to 1 second */); + + assertNull("Unexpected exception at mock server side.", server.getException()); + assertTrue("Server is not shutdowned at after conversation.", server.isShutdowned()); + } finally { + socket.close(); + } + + } +}