// Server.java
package net.sf.gogui.tools.server;
import net.sf.gogui.util.Options;
import net.sf.gogui.util.ProcessUtil;
import net.sf.gogui.util.StreamCopy;
import net.sf.gogui.util.StringUtil;
import net.sf.gogui.version.Version;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
/** Connects a Go program supporting GTP to a socket. */
public final class Server
{
/** Constructor.
@param verbose Log everything sent and received to stderr
@param loop Restart program and wait for new connection after
connection is closed (only for incoming connections)
@param program Command line for Go program
@param remoteHost If null then the server waits for incoming
connections, otherwise it connects to a remote computer with this
name.
@param port Port number at remote host
@param userFile file containing login information that is sent to the
@param timeout Timeout in seconds, zero for no timeout.
remote host. Only used if remoteHost is set. */
public Server(boolean verbose, boolean loop, String program,
String remoteHost, int port, String userFile,
int timeout)
throws Exception
{
Runtime runtime = Runtime.getRuntime();
ServerSocket serverSocket = null;
if (remoteHost == null)
serverSocket = new ServerSocket(port, 1);
while (true)
{
Process process
= runtime.exec(StringUtil.splitArguments(program));
Thread stdErrThread = new ProcessUtil.StdErrThread(process);
stdErrThread.start();
Socket socket;
if (serverSocket == null)
socket = connectToRemote(remoteHost, port, userFile);
else
{
if (verbose)
System.err.println("Waiting for connection...");
socket = serverSocket.accept();
}
if (verbose)
System.err.println("gogui-server: Connected with "
+ socket.getInetAddress());
if (timeout >= 0)
socket.setSoTimeout(timeout * 1000);
Thread fromNet =
new Thread(new StreamCopy(verbose, socket.getInputStream(),
process.getOutputStream(), true));
Thread toNet =
new Thread(new StreamCopy(verbose, process.getInputStream(),
socket.getOutputStream(), false));
fromNet.start();
toNet.start();
toNet.join();
socket.shutdownOutput();
fromNet.join();
socket.close();
process.waitFor();
if (remoteHost != null || ! loop)
break;
}
if (serverSocket != null)
serverSocket.close();
}
public static void main(String[] args)
{
try
{
String options[] = {
"config:",
"help",
"loop",
"port:",
"remote:",
"timeout:",
"user:",
"verbose",
"version",
};
Options opt = Options.parse(args, options);
boolean verbose = opt.contains("verbose");
boolean loop = opt.contains("loop");
if (loop && opt.contains("remote"))
{
System.err.println("Option -loop can't be used with -remote");
System.exit(1);
}
if (opt.contains("help"))
{
printUsage(System.out);
return;
}
if (opt.contains("version"))
{
System.out.println("gogui-server " + Version.get());
return;
}
if (! opt.contains("port"))
{
System.err.println("Please specify port with option -port");
System.exit(1);
}
int port = opt.getInteger("port");
String remoteHost = opt.get("remote", null);
String userFile = opt.get("user", null);
int timeout = opt.getInteger("timeout", 0, 0);
if (userFile != null && remoteHost == null)
{
System.err.println("Option -user only valid with -remote");
System.exit(1);
}
ArrayList<String> arguments = opt.getArguments();
if (arguments.size() != 1)
{
printUsage(System.err);
System.exit(1);
}
String program = arguments.get(0);
new Server(verbose, loop, program, remoteHost, port, userFile,
timeout);
}
catch (Throwable t)
{
StringUtil.printException(t);
System.exit(1);
}
}
private static Socket connectToRemote(String remoteHost, int port,
String userFile) throws Exception
{
System.err.println("Connecting to " + remoteHost + " " + port);
Socket socket = new Socket(remoteHost, port);
if (userFile != null)
{
System.err.println("Sending login information from file "
+ userFile);
InputStream inputStream = new FileInputStream(new File(userFile));
try
{
OutputStream outputStream = socket.getOutputStream();
byte buffer[] = new byte[1024];
while (true)
{
int n = inputStream.read(buffer);
if (n < 0)
break;
outputStream.write(buffer, 0, n);
}
}
finally
{
inputStream.close();
}
}
System.err.println("Connected");
return socket;
}
private static void printUsage(PrintStream out)
{
out.print("Usage: gogui-server [options] program\n" +
"\n" +
"-config config file\n" +
"-help display this help and exit\n" +
"-loop restart after connection finished\n" +
"-port port of network connection\n" +
"-remote connect to remote host\n" +
"-timeout timeout seconds for closing idle connections\n" +
"-user login information for remote host\n" +
"-verbose print debugging messages\n" +
"-version print version and exit\n");
}
}