/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.command.net;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import org.jnode.shell.AbstractCommand;
import org.jnode.shell.syntax.Argument;
import org.jnode.shell.syntax.HostNameArgument;
import org.jnode.shell.syntax.PortNumberArgument;
/**
* This command establishes a TCP connection to a remote machine, either by
* connecting to it or accepting a remote connection. Once the connection has
* been set up, it sends the command's standard input to the remote connection and
* sends the output from the connection to the command's standard output.
*
* @author quades
* @author crawley@jnode.org
*/
public class TcpInoutCommand extends AbstractCommand {
// FIXME this command is only useful for testing. What we Really need is
// implementations of TELNET, RSH and SSH protocols (client and
// server-side).
private static final String help_host = "the hostname of the server to contact";
private static final String help_port = "the port the server is listening to";
private static final String help_lport = "the local port we should listen to";
private static final String help_super = "Set up an interactive TCP connection to a remote machine";
private final HostNameArgument argHost;
private final PortNumberArgument argPort;
private final PortNumberArgument argLocalPort;
private Socket socket;
private CopyThread toThread;
private CopyThread fromThread;
public TcpInoutCommand() {
super(help_super);
argHost = new HostNameArgument("host", Argument.OPTIONAL, help_host);
argPort = new PortNumberArgument("port", Argument.OPTIONAL, help_port);
argLocalPort = new PortNumberArgument("localPort", Argument.OPTIONAL, help_lport);
registerArguments(argHost, argLocalPort, argPort);
}
/**
* @param args
*/
public static void main(String[] args) throws Exception {
new TcpInoutCommand().execute(args);
}
public void execute() throws IOException {
Socket socket;
if (argLocalPort.isSet()) {
int port = argLocalPort.getValue();
ServerSocket ss = ServerSocketFactory.getDefault().createServerSocket(port);
socket = ss.accept();
} else {
InetAddress host = argHost.getAsInetAddress();
int port = argPort.getValue();
socket = SocketFactory.getDefault().createSocket(host, port);
}
InputStream in = getInput().getInputStream();
OutputStream out = getOutput().getOutputStream();
PrintWriter err = getError().getPrintWriter();
toThread = new CopyThread(in, socket.getOutputStream(), err);
fromThread = new CopyThread(socket.getInputStream(), out, err);
synchronized (this) {
toThread.start();
fromThread.start();
try {
wait();
} catch (InterruptedException e) {
close(null);
}
}
}
private synchronized void close(CopyThread source) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// We don't care ...
}
socket = null;
notifyAll();
}
if (source != toThread) {
toThread.terminate();
}
if (source != fromThread) {
fromThread.terminate();
}
}
private class CopyThread extends Thread {
private final InputStream in;
private final OutputStream out;
private final PrintWriter err;
private boolean terminated;
CopyThread(InputStream in, OutputStream out, PrintWriter err) {
this.in = in;
this.out = out;
this.err = err;
}
synchronized void terminate() {
if (!this.terminated) {
interrupt();
this.terminated = true;
}
}
public void run() {
try {
while (socket != null) {
int b = in.read();
if (b == -1) {
break;
}
out.write(b);
}
} catch (IOException ex) {
synchronized (this) {
if (!terminated) {
err.println(ex.getLocalizedMessage());
}
}
} finally {
close(this);
}
}
}
}