package org.merapi.internal; import java.io.BufferedReader; import java.io.EOFException; import java.io.IOException; import java.io.InputStreamReader; import java.io.InterruptedIOException; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.logging.Level; import java.util.logging.Logger; /** * Class PolicyServer * Starts a PolicyServer on the specified port. * Can be started as main class, passing the port number as the first command line argument * @author Thomas Meyer, Less Rain (thomas@lessrain.com) * */ public class PolicyServer extends Thread { /** * If no argument is passed the server will listen on this port for connections */ public static final int DEFAULT_PORT = 12344; public static final String[] DEFAULT_POLICY = new String[]{"*"}; /** * The character sequence sent by the Flash Player to request a _policy file */ public static final String POLICY_REQUEST = "<policy-file-request/>"; public static final boolean DEBUG = true; /** * @param args Use the first command line argument to set the port the server will listen on for connections */ public static void main(String[] args) { int port = DEFAULT_PORT; try { if (args.length > 0) { port = Integer.parseInt(args[0]); } } catch (NumberFormatException e) { } // Start the PolicyServer (new PolicyServer(port, new String[]{"*:80"})).start(); } /* * PolicyServer class variables */ private int _port; private boolean _listening; public ServerSocket _socketServer; private String _policy; /** * PolicyServer constructor * @param port_ Sets the port that the PolicyServer listens on */ public PolicyServer( int port_, String[] allowedHosts_ ) { _port = port_; _listening=true; if (allowedHosts_==null) allowedHosts_ = DEFAULT_POLICY; _policy = buildPolicy(allowedHosts_); } private String buildPolicy( String[] allowedHosts_ ) { StringBuffer policyBuffer = new StringBuffer(); policyBuffer.append("<?xml version=\"1.0\"?><cross-domain-policy>"); for (int i = 0; i < allowedHosts_.length; i++) { String[] hostInfo = allowedHosts_[i].split(":"); String hostname = hostInfo[0]; // String ports = null; // if (hostInfo.length>1) ports = hostInfo[1]; // else ports = "*"; policyBuffer.append("<allow-access-from domain=\""+hostname+"\" to-ports=\"12345\" />"); } policyBuffer.append("</cross-domain-policy>"); return policyBuffer.toString(); } // /** // * PolicyServer constructor // * @param port_ Sets the port that the PolicyServer listens on // */ // public PolicyServer(int port_, String[] allowedHosts_) { // _port = port_; // _listening = true; // if (allowedHosts_ == null) { // allowedHosts_ = DEFAULT_POLICY; // } // _policy = buildPolicy(allowedHosts_); // } // public static String hostname = null; // public static int Port = 0; // // private String buildPolicy(String[] allowedHosts_) { // StringBuffer policyBuffer = new StringBuffer(); // // policyBuffer.append("<?xml version=\"1.0\"?><cross-domain-policy>"); // for (int i = 0; i < allowedHosts_.length; i++) { // String[] hostInfo = allowedHosts_[i].split(":"); //// if (hostname == null) { //// hostname = hostInfo[0]; //// } // String hostname = hostInfo[0]; //// String ports = null; //// if (hostInfo.length>1) ports = hostInfo[1]; //// else ports = "*"; // //// policyBuffer.append("<allow-access-from domain=\""+hostname+"\" to-ports=\"12345\" />"); // policyBuffer.append("<allow-access-from domain=\"" + hostname + "\" to-ports=\"12345\" />");// secure=\"false\" />"); // // } // policyBuffer.append("</cross-domain-policy>"); // // return policyBuffer.toString(); // } /** * Thread run method, accepts incoming connections and creates SocketConnection objects to handle requests */ public void run() { try { _listening = true; // Start listening for connections _socketServer = new ServerSocket(_port, 1); if (DEBUG) { System.out.println("PolicyServer listening on port " + _port); } while (_listening) { // _listening = false; // Wait for a connection and accept it Socket socket = _socketServer.accept(); System.out.println("RemoteSocketAddress (Pol): " + socket.getRemoteSocketAddress().toString()); System.out.println("LockalSocketAddress (Pol): " + socket.getRemoteSocketAddress().toString()); System.out.println("InetAddress (Pol): " + socket.getInetAddress().getHostAddress()); // PolicyServer.hostname = socket.getInetAddress().getHostAddress(); try { // if (DEBUG) { System.out.println("PolicyServer got a connection on port " + _port); // } // Start a new connection thread (new SocketConnection(socket)).start(); } catch (Exception e) { // if (DEBUG) { System.out.println("Exception: " + e.getMessage()); // } } try { // Wait for a sec until a new connection is accepted to avoid flooding sleep(1000); } catch (InterruptedException e) {} } } catch (IOException e) { // if (DEBUG) { System.out.println("IO Exception: " + e.getMessage()); // } } try { _socketServer.close(); // while (!_socketServer.isClosed()) { // try { // _socketServer.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } //// if (DEBUG) { // System.out.println("PolicyServer closing"); //// } //// Bridge.open(); } catch (IOException ex) { Logger.getLogger(PolicyServer.class.getName()).log(Level.SEVERE, null, ex); } // while (!_socketServer.isClosed()) { // try { // _socketServer.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } //// if (DEBUG) { // System.out.println("PolicyServer closing"); //// } //// Bridge.open(); } /** * Local class SocketConnection * For every accepted connection one SocketConnection is created. * It waits for the _policy file request, returns the _policy file and closes the connection immediately * @author Thomas Meyer, Less Rain (thomas@lessrain.com) * */ class SocketConnection extends Thread { private Socket _socket; private BufferedReader _socketIn; private PrintWriter _socketOut; /** * Constructor takes the Socket object for this connection * @param socket_ Socket connection to a client created by the PolicyServer main thread */ public SocketConnection(Socket socket_) { _socket = socket_; } /** * Thread run method waits for the _policy request, returns the poilcy file and closes the connection */ public void run() { try { // initialize socket and readers/writers _socket.setSoTimeout(10000); _socketIn = new BufferedReader(new InputStreamReader(_socket.getInputStream())); _socketOut = new PrintWriter(_socket.getOutputStream(), true); } catch (IOException e) { if (DEBUG) { System.out.println("IO Exception " + e.getMessage()); } return; } readPolicyRequest(); } /** * Wait for and read the _policy request sent by the Flash Player * Return the _policy file and close the Socket connection */ private void readPolicyRequest() { try { // Read the request and compare it to the request string defined in the constants. // If the proper _policy request has been sent write out the _policy file if (POLICY_REQUEST.equals(read())) { write(_policy); } } catch (Exception e) { if (DEBUG) { System.out.println("Exception " + e.getMessage()); } } close(); } /** * Read until a zero character is sent or a maximum of 100 character * @return The character sequence read * @throws IOException * @throws EOFException * @throws InterruptedIOException */ private String read() throws IOException, EOFException, InterruptedIOException { StringBuffer buffer = new StringBuffer(); int codePoint; boolean zeroByteRead = false; if (DEBUG) { System.out.println("Reading..."); } do { codePoint = _socketIn.read(); if (codePoint == 0) { zeroByteRead = true; } else { buffer.appendCodePoint(codePoint); } } while (!zeroByteRead && buffer.length() < 100); if (DEBUG) { System.out.println("Read: " + buffer.toString()); } return buffer.toString(); } /** * Writes a String to the client * @param msg Text to be sent to the client (_policy file) */ public void write(String msg) { _socketOut.println(msg + "\u0000"); _socketOut.flush(); if (DEBUG) { System.out.println("Wrote: " + msg); } } /** * Close the Socket connection an set everything to null. Prepared for garbage collection */ public void close() { try { if (_socket != null) { _socket.close(); } if (_socketOut != null) { _socketOut.close(); } if (_socketIn != null) { _socketIn.close(); } } catch (IOException e) { } _socketIn = null; _socketOut = null; _socket = null; } } }