blob: eb345a2230d6301f58fa19f6e0074f9150395821 [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 common;
import java.awt.Frame;
import java.awt.ScrollPane;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.net.InetSocketAddress;
import java.util.Arrays;
import rdpclient.RdpClient;
import streamer.Element;
import streamer.Pipeline;
import streamer.PipelineImpl;
import streamer.SocketWrapper;
import streamer.SocketWrapperImpl;
import streamer.apr.AprSocketWrapperImpl;
import streamer.bco.BcoSocketWrapperImpl;
import streamer.ssl.SSLState;
import vncclient.VncClient;
import common.opt.IntOption;
import common.opt.Option;
import common.opt.OptionParser;
import common.opt.StringEnumerationOption;
import common.opt.StringOption;
public class Client {
enum Protocol {
NONE, VNC, RDP, HYPERV
}
// Common options
private final Option help = new Option() {
{
name = "--help";
alias = "-h";
description = "Show this help text.";
}
};
private final Option debugLink = new Option() {
{
name = "--debug-link";
alias = "-DL";
description = "Print debugging messages when packets are trasnferred via links.";
}
};
private final Option debugElement = new Option() {
{
name = "--debug-element";
alias = "-DE";
description = "Print debugging messages when packets are received or sent by elements.";
}
};
private final Option debugPipeline = new Option() {
{
name = "--debug-pipeline";
alias = "-DP";
description = "Print debugging messages in pipelines.";
}
};
private final StringOption hostName = new StringOption() {
{
name = "--host";
alias = "-n";
aliases = new String[] {"--host-name"};
required = true;
description = "Name or IP address of host to connect to.";
}
};
private final IntOption canvasWidth = new IntOption() {
{
name = "--width";
alias = "-W";
value = 1024;
description = "Width of canvas.";
}
};
private final IntOption canvasHeight = new IntOption() {
{
name = "--height";
alias = "-H";
value = 768;
description = "Height of canvas.";
}
};
// Protocol specific options
private final IntOption vncPort = new IntOption() {
{
name = "--port";
alias = "-p";
value = 5901;
description = "Port of VNC display server to connect to. Calculate as 5900 + display number, e.g. 5900 for display #0, 5901 for display #1, and so on.";
}
};
private final IntOption rdpPort = new IntOption() {
{
name = "--port";
alias = "-p";
value = 3389;
description = "Port of RDP server to connect to.";
}
};
private final IntOption hyperVPort = new IntOption() {
{
name = "--port";
alias = "-p";
value = 2179;
description = "Port of HyperV server to connect to.";
}
};
private final StringOption password = new StringOption() {
{
name = "--password";
alias = "-P";
required = true;
description = "Password to use.";
}
};
private final StringOption rdpPassword = new StringOption() {
{
name = "--password";
alias = "-P";
required = false;
description = "Password to use. If omitted, then login screen will be shown.";
}
};
private final StringOption userName = new StringOption() {
{
name = "--user";
alias = "-U";
value = "Administrator";
description = "User name to use.";
}
};
private final StringOption domain = new StringOption() {
{
name = "--domain";
alias = "-D";
value = "Workgroup";
description = "NTLM domain to login into.";
}
};
private final StringOption hyperVInstanceId = new StringOption() {
{
name = "--instance";
alias = "-i";
required = true;
description = "HyperV instance ID to use.";
}
};
private final StringEnumerationOption sslImplementation = new StringEnumerationOption() {
{
name = "--ssl-implementation";
alias = "-j";
value = "apr";
choices = new String[] {"jre", "apr", "bco"};
description = "Select SSL engine to use: JRE standard implementation, Apache Portable Runtime native library, BonuncyCastle.org implementation.";
}
};
private final Option[] commonOptions = new Option[] {help, debugLink, debugElement, debugPipeline, hostName, canvasWidth, canvasHeight};
private final Option[] vncOptions = new Option[] {vncPort, password};
private final Option[] rdpOptions = new Option[] {sslImplementation, rdpPort, domain, userName, rdpPassword};
private final Option[] hyperVOptions = new Option[] {sslImplementation, hyperVPort, hyperVInstanceId, domain, userName, password};
private static Frame frame;
private static SocketWrapper socket;
private static ScrollPane scroller;
private static ScreenDescription screen;
private static BufferedImageCanvas canvas;
private InetSocketAddress address;
private void help() {
System.out.println("Usage: \n java common.Client vnc|rdp|hyperv OPTIONS\n");
System.out.println(Option.toHelp("Common options", commonOptions));
System.out.println(Option.toHelp("VNC options", vncOptions));
System.out.println(Option.toHelp("RDP options", rdpOptions));
System.out.println(Option.toHelp("HyperV options", hyperVOptions));
}
public void runClient(String[] args) {
try {
Protocol protocol = parseOptions(args);
if (protocol == Protocol.NONE)
return;
System.setProperty("streamer.Link.debug", "" + debugLink.used);
System.setProperty("streamer.Element.debug", "" + debugElement.used);
System.setProperty("streamer.Pipeline.debug", "" + debugPipeline.used);
SSLState sslState = new SSLState();
// Create socket wrapper
if ("jre".equals(sslImplementation.value)) {
socket = new SocketWrapperImpl("socket", sslState);
} else if ("apr".equals(sslImplementation.value)) {
socket = new AprSocketWrapperImpl("socket", sslState);
} else if ("bco".equals(sslImplementation.value)) {
socket = new BcoSocketWrapperImpl("socket", sslState);
} else {
throw new RuntimeException("Unexpected option value: \"" + sslImplementation.value + "\". " + sslImplementation.help());
}
screen = new ScreenDescription();
canvas = new BufferedImageCanvas(canvasWidth.value, canvasHeight.value);
screen.addSizeChangeListener(new SizeChangeListener() {
@Override
public void sizeChanged(int width, int height) {
if (canvas != null) {
canvas.setCanvasSize(width, height);
if (scroller != null)
scroller.setSize(canvas.getWidth(), canvas.getHeight());
}
}
});
assemblePipeline(setMainElementAndAddressBasedOnProtocol(protocol, sslState));
frame = createVncClientMainWindow(canvas, protocol.toString() + " " + hostName.value, new WindowAdapter() {
@Override
public void windowClosing(WindowEvent evt) {
shutdown();
}
});
try {
// Connect socket to remote server and run main loop(s)
socket.connect(address);
} finally {
shutdown();
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
protected static void assemblePipeline(Element main) {
Pipeline pipeline = new PipelineImpl("Client");
pipeline.add(socket, main);
pipeline.link("socket", main.getId(), "socket");
pipeline.validate();
}
private Element setMainElementAndAddressBasedOnProtocol(Protocol protocol, SSLState sslState) {
Element main;
switch (protocol) {
case VNC:
address = new InetSocketAddress(hostName.value, vncPort.value);
main = new VncClient("client", password.value, screen, canvas);
break;
case RDP:
address = new InetSocketAddress(hostName.value, rdpPort.value);
main = new RdpClient("client", hostName.value, domain.value, userName.value, rdpPassword.value, null, screen, canvas, sslState);
break;
case HYPERV:
address = new InetSocketAddress(hostName.value, hyperVPort.value);
main = new RdpClient("client", hostName.value, domain.value, userName.value, password.value, hyperVInstanceId.value, screen, canvas, sslState);
break;
default:
address = null;
main = null;
}
return main;
}
private Protocol parseOptions(String[] args) {
String protocolName = (args.length > 0) ? args[0] : "";
Protocol protocol = Protocol.NONE;
Option[] options;
if (protocolName.equals("vnc")) {
protocol = Protocol.VNC;
options = join(commonOptions, vncOptions);
} else if (protocolName.equals("rdp")) {
protocol = Protocol.RDP;
options = join(commonOptions, rdpOptions);
} else if (protocolName.equals("hyperv")) {
protocol = Protocol.HYPERV;
options = join(commonOptions, hyperVOptions);
} else {
help();
return Protocol.NONE;
}
// Parse all options for given protocol
String[] arguments = OptionParser.parseOptions(args, 1, options);
if (arguments.length > 0) {
System.err.println("[Client] ERROR: Arguments are not allowed here. Check command syntax. Extra arguments: \"" + Arrays.toString(arguments) + "\".");
help();
return Protocol.NONE;
}
if (help.used) {
help();
return Protocol.NONE;
}
return protocol;
}
protected static void shutdown() {
if (frame != null) {
frame.setVisible(false);
frame.dispose();
}
if (socket != null)
socket.shutdown();
}
protected static Frame createVncClientMainWindow(BufferedImageCanvas canvas, String title, WindowListener windowListener) {
// Create AWT windows
Frame frame = new Frame(title + " - RDP");
// Use scrolling pane to support screens, which are larger than ours
scroller = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
scroller.add(canvas);
scroller.setSize(canvas.getWidth(), canvas.getHeight());
frame.add(scroller);
frame.pack();
frame.setVisible(true);
frame.addWindowListener(windowListener);
return frame;
}
/**
* Join two arrays with options and return new array.
*/
private Option[] join(Option[] a1, Option[] a2) {
// Extend first array
Option[] result = Arrays.copyOf(a1, a1.length + a2.length);
// Append second array to first
for (int i = 0, p = a1.length; i < a2.length; i++, p++)
result[p] = a2[i];
return result;
}
public static void main(String args[]) {
// *DEBUG*/System.setProperty("javax.net.debug", "ssl");
// * DEBUG */System.setProperty("javax.net.debug", "ssl:record:packet");
new Client().runClient(args);
}
}