| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| package streamer.debug; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.InetSocketAddress; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.util.Arrays; |
| |
| import javax.net.ssl.SSLSocket; |
| import javax.net.ssl.SSLSocketFactory; |
| |
| import org.apache.log4j.Logger; |
| |
| public class MockServer implements Runnable { |
| private static final Logger s_logger = Logger.getLogger(MockServer.class); |
| |
| private boolean shutdown = false; |
| private ServerSocket serverSocket; |
| private final Packet[] packets; |
| private Throwable exception; |
| private boolean shutdowned; |
| |
| /** |
| * Set to true to enable debugging messages. |
| */ |
| protected boolean verbose = System.getProperty("rdpclient.MockServer.debug", "false").equals("true"); |
| |
| public MockServer(Packet packets[]) { |
| this.packets = packets; |
| } |
| |
| public void start() throws IOException { |
| serverSocket = new ServerSocket(0); |
| |
| shutdown = false; |
| exception = null; |
| shutdowned = false; |
| |
| Thread thread = new Thread(this); |
| thread.setDaemon(true); |
| thread.start(); |
| } |
| |
| @Override |
| public void run() { |
| |
| try (Socket socket = serverSocket.accept();) { |
| |
| if (verbose) |
| System.out.println("[" + this + "] INFO: Client connected: " + socket.getRemoteSocketAddress() + "."); |
| |
| InputStream is = socket.getInputStream(); |
| OutputStream os = socket.getOutputStream(); |
| |
| try { |
| for (int i = 0; i < packets.length && !shutdown; i++) { |
| |
| Packet packet = packets[i]; |
| switch (packet.type) { |
| case CLIENT: { |
| // Read client data and compare it with mock data |
| // (unless "ignore" option is set) |
| byte actualData[] = new byte[packet.data.length]; |
| int actualDataLength = is.read(actualData); |
| |
| if (verbose) |
| System.out.println("[" + this + "] INFO: Data is read: {" + Arrays.toString(Arrays.copyOf(actualData, actualDataLength)) + "}."); |
| |
| if (!packet.ignore) { |
| // Compare actual data with expected data |
| if (actualDataLength != packet.data.length) { |
| throw new AssertionError("Actual length of client request for packet #" + (i + 1) + " (\"" + packet.id + "\")" |
| + " does not match length of expected client request. Actual length: " + actualDataLength + ", expected legnth: " + packet.data.length |
| + "."); |
| } |
| |
| for (int j = 0; j < packet.data.length; j++) { |
| |
| if (packet.data[j] != actualData[j]) { |
| throw new AssertionError("Actual byte #" + (j + 1) + " of client request for packet #" + (i + 1) + " (\"" + packet.id + "\")" |
| + " does not match corresponding byte of expected client request. Actual byte: " + actualData[j] + ", expected byte: " + packet.data[j] |
| + "."); |
| } |
| } |
| } |
| break; |
| } |
| case SERVER: { |
| // Send mock data to client |
| os.write(packet.data); |
| |
| if (verbose) |
| System.out.println("[" + this + "] INFO: Data is written: {" + Arrays.toString(packet.data) + "}."); |
| |
| break; |
| } |
| case UPGRADE_TO_SSL: { |
| // Attach SSL context to socket |
| |
| final SSLSocketFactory sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault(); |
| SSLSocket sslSocket = (SSLSocket)sslSocketFactory.createSocket(socket, null, serverSocket.getLocalPort(), true); |
| sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); |
| sslSocket.setUseClientMode(false); |
| sslSocket.startHandshake(); |
| is = sslSocket.getInputStream(); |
| os = sslSocket.getOutputStream(); |
| |
| break; |
| } |
| default: |
| throw new RuntimeException("Unknown packet type: " + packet.type); |
| } |
| |
| } |
| } finally { |
| try { |
| is.close(); |
| } catch (Throwable e) { |
| s_logger.info("[ignored]" |
| + "in stream close failed: " + e.getLocalizedMessage()); |
| } |
| try { |
| os.close(); |
| } catch (Throwable e) { |
| s_logger.info("[ignored]" |
| + "out stream close failed: " + e.getLocalizedMessage()); |
| } |
| try { |
| serverSocket.close(); |
| } catch (Throwable e) { |
| s_logger.info("[ignored]" |
| + "server socket close failed: " + e.getLocalizedMessage()); |
| } |
| } |
| } catch (Throwable e) { |
| System.err.println("Error in mock server: " + e.getMessage()); |
| e.printStackTrace(System.err); |
| exception = e; |
| } |
| shutdowned = true; |
| if (verbose) |
| System.out.println("[" + this + "] INFO: Mock server shutdowned."); |
| |
| } |
| |
| public void shutdown() { |
| shutdown = true; |
| } |
| |
| public InetSocketAddress getAddress() { |
| return (InetSocketAddress)serverSocket.getLocalSocketAddress(); |
| } |
| |
| public Throwable getException() { |
| return exception; |
| } |
| |
| public static class Packet { |
| public static enum PacketType { |
| SERVER, CLIENT, UPGRADE_TO_SSL; |
| } |
| |
| public String id = ""; |
| |
| public Packet() { |
| } |
| |
| public Packet(String id) { |
| this.id = id; |
| } |
| |
| public PacketType type; |
| |
| public boolean ignore = false; |
| |
| public byte data[]; |
| } |
| |
| public boolean isShutdowned() { |
| return shutdowned; |
| } |
| |
| public void waitUntilShutdowned(long timeToWaitMiliseconds) throws InterruptedException { |
| long deadline = System.currentTimeMillis() + timeToWaitMiliseconds; |
| while (!shutdowned && System.currentTimeMillis() < deadline) { |
| Thread.sleep(10); |
| } |
| } |
| } |