package edu.colostate.vchill.proxy; import edu.colostate.vchill.ChillDefines; import edu.colostate.vchill.ChillDefines.Channel; import edu.colostate.vchill.cache.CacheMainLRU; import edu.colostate.vchill.chill.ChillFieldInfo; import edu.colostate.vchill.gui.GUIUtil; import edu.colostate.vchill.socket.SocketArchCtl.Command; import java.io.DataInputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; /** * Driver class for an archive proxy server. Listens to socket requests and * creates new threads to handle them. * * @author Alexander Deyke * @author Jochen Deyke * @author jpont * @version 2010-08-30 */ public final class ArchiveProxy extends Proxy { /** * list of ProxyControlThreads */ private ArrayList<ProxyControlThread> controlThreads = new ArrayList<ProxyControlThread>(); /** * private constructor prevents instantiation */ private ArchiveProxy() { } public static void main(final String[] args) throws IOException { new ArchiveProxy().parseCommandLineArguments(args).run(); System.exit(0); } public void run() throws IOException { if (guiflag) GUIUtil.startGUI("Java VCHILL Archive Proxy Server"); //gui requested // instantiate cache cache = new CacheMainLRU(cacheSize); ServerSocket clientsocket = null; try { clientsocket = new ServerSocket(listenPort); System.out.println("Proxy: Listening on port " + listenPort); } catch (IOException ioe) { System.err.println("Proxy: Could not listen on port " + listenPort); throw new Error(ioe); } while (true) { // repeat forever Socket socket = clientsocket.accept(); DataInputStream in = new DataInputStream(socket.getInputStream()); int fromSocket = in.readInt(); //hello if (fromSocket == Command.HALT_COMMAND.ordinal()) { String pwd = in.readUTF(); if (password.equals(pwd)) { System.out.println("Proxy server shutting down"); return; } else { System.out.println("Shutdown attempt with bad password: " + pwd); System.out.println("Proxy server NOT shutting down"); } } else if (fromSocket == ChillDefines.HELLO) { fromSocket = in.readInt(); //channel if (fromSocket == Channel.ARCH_CTL.ordinal()) { System.out.println("Proxy: Control socket request identified from " + socket.getInetAddress().getHostName()); ProxyControlThread controlThread = new ProxyControlThread(socket, this); controlThreads.add(controlThread); controlThread.start(); } else if ((fromSocket & 0xffff) == Channel.GEN_MOM_DAT.ordinal()) { int sessionID = (fromSocket >> 16) & 0xffff; System.out.println("Proxy: Data socket request identified from " + socket.getInetAddress().getHostName()); removeDead(); // get rid of dead control threads first for (ProxyControlThread controlThread : controlThreads) { if (sessionID == controlThread.getSessionID()) { ProxyDataThread dataThread = new ProxyDataThread(socket, controlThread, cache); controlThread.addDataThread(dataThread); dataThread.start(); break; } } } else { System.out.println("Bad request from " + socket.getInetAddress().getHostName() + ": unknown channel type"); } } else { System.out.println("Bad request from " + socket.getInetAddress().getHostName() + ": outdated version?"); } Proxy.sleep(100); } } /** * Sets the global setting variables according to the arguments * passed in. If an error is encountered, the application is * terminated. * * @param args The command line arguments as passed to main * @return this object; useful for chaining this method into creation */ private ArchiveProxy parseCommandLineArguments(final String[] args) { //parse commandline arguments if (args.length % 2 != 0) die(); for (int i = 0; i < args.length; i += 2) { if (args[i].equals("-server") || args[i].equals("-s")) { serverName = args[i + 1]; } else if (args[i].equals("-serverport") || args[i].equals("-sp")) { try { serverPort = Integer.parseInt(args[i + 1]); } catch (NumberFormatException e) { die(); } if (serverPort < 1 || serverPort > 65535) die(); } else if (args[i].equals("-listenport") || args[i].equals("-lp")) { try { listenPort = Integer.parseInt(args[i + 1]); } catch (NumberFormatException e) { die(); } if (listenPort < 1 || listenPort > 65535) die(); } else if (args[i].equals("-timeout") || args[i].equals("-t") || args[i].equals("-to")) { try { timeout = 60000l * Integer.parseInt(args[i + 1]); } catch (NumberFormatException e) { die(); } if (timeout < 0) die(); } else if (args[i].equals("-cachesize") || args[i].equals("-cs")) { try { cacheSize = ChillFieldInfo.types.length * Integer.parseInt(args[i + 1]); } catch (NumberFormatException e) { die(); } if (cacheSize < 0) die(); } else if (args[i].equals("-calculation") || args[i].equals("-c")) { if (args[i + 1].equals("on")) { calcflag = true; } else if (args[i + 1].equals("off")) { calcflag = false; } else { die(); } } else if (args[i].equals("-password") || args[i].equals("-p")) { password = args[i + 1]; } else if (args[i].equals("-gui") || args[i].equals("-g")) { if (args[i + 1].equals("on")) { guiflag = true; } else if (args[i + 1].equals("off")) { guiflag = false; } else { die(); } } else { die(); } } addCalculatedTypeScales(); return this; } /** * Looks at list of control threads and removes inactive ones from the list. */ private void removeDead() { for (int i = controlThreads.size() - 1; i > 0; i--) { if (!(controlThreads.get(i)).isAlive()) { System.out.println("Proxy: Removing dead thread"); controlThreads.remove(i); } } } /** * Prints usage message and exits. */ private static void die() { System.err.println("Usage: java Proxy [-server name] [-serverport port] [-listenport port]"); System.err.println(" [-timeout minutes] [-cachesize numsweeps] [-calculation on|off]"); System.err.println(" [-password pwd] [-gui on|off]"); System.err.println("Defaults: radar.chill.colostate.edu 2510 2510 60 20 on secret"); System.err.println("server: what server the proxy should connect to"); System.err.println("serverport: what port the proxy should connect to"); System.err.println("listenport: what port the proxy should listen on"); System.err.println("timeout: how long the control socket can idle before being terminated"); System.err.println(" 0 means forever"); System.err.println("cachesize: size is in number of sweeps, each with " + ChillFieldInfo.types.length + " types"); System.err.println("calculation: if the proxy should calculate hybrid data types"); System.err.println(" Turn this off if you're connecting to another proxy"); System.err.println("password: a password which must be matched to shut down the proxy"); System.exit(1); } }