blob: d4e48c6ee29d3306e1f4e2f4d3a5e2bc398ba28a [file] [log] [blame]
// 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 length: " + 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 timeToWaitMilliseconds) throws InterruptedException {
long deadline = System.currentTimeMillis() + timeToWaitMilliseconds;
while (!shutdowned && System.currentTimeMillis() < deadline) {
Thread.sleep(10);
}
}
}