001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io.remotecontrol;
003
004import static org.openstreetmap.josm.tools.I18n.marktr;
005
006import java.io.IOException;
007import java.net.BindException;
008import java.net.InetAddress;
009import java.net.ServerSocket;
010import java.net.Socket;
011import java.net.SocketException;
012
013import org.openstreetmap.josm.Main;
014
015/**
016 * Simple HTTP server that spawns a {@link RequestProcessor} for every
017 * connection.
018 *
019 * Taken from YWMS plugin by frsantos.
020 */
021public class RemoteControlHttpServer extends Thread {
022
023    /** The server socket */
024    private ServerSocket server;
025
026    private static RemoteControlHttpServer instance;
027
028    /**
029     * Starts or restarts the HTTP server
030     */
031    public static void restartRemoteControlHttpServer() {
032        int port = Main.pref.getInteger("remote.control.port", 8111);
033        try {
034            stopRemoteControlHttpServer();
035
036            instance = new RemoteControlHttpServer(port);
037            instance.start();
038        } catch (BindException ex) {
039            Main.warn(marktr("Cannot start remotecontrol server on port {0}: {1}"),
040                    Integer.toString(port), ex.getLocalizedMessage());
041        } catch (IOException ioe) {
042            Main.error(ioe);
043        }
044    }
045
046    /**
047     * Stops the HTTP server
048     * @since 5861
049     */
050    public static void stopRemoteControlHttpServer() {
051        if (instance != null) {
052            try {
053                instance.stopServer();
054                instance = null;
055            } catch (IOException ioe) {
056                Main.error(ioe);
057            }
058        }
059    }
060
061    /**
062     * Constructor
063     * @param port The port this server will listen on
064     * @throws IOException when connection errors
065     */
066    public RemoteControlHttpServer(int port) throws IOException {
067        super("RemoteControl HTTP Server");
068        this.setDaemon(true);
069        // Start the server socket with only 1 connection.
070        // Also make sure we only listen
071        // on the local interface so nobody from the outside can connect!
072        // NOTE: On a dual stack machine with old Windows OS this may not listen on both interfaces!
073        this.server = new ServerSocket(port, 1,
074            InetAddress.getByName(Main.pref.get("remote.control.host", "localhost")));
075    }
076
077    /**
078     * The main loop, spawns a {@link RequestProcessor} for each connection
079     */
080    @Override
081    public void run() {
082        Main.info(marktr("RemoteControl::Accepting connections on port {0}"),
083             Integer.toString(server.getLocalPort()));
084        while (true) {
085            try {
086                @SuppressWarnings("resource")
087                Socket request = server.accept();
088                RequestProcessor.processRequest(request);
089            } catch (SocketException se) {
090                if (!server.isClosed())
091                    Main.error(se);
092            } catch (IOException ioe) {
093                Main.error(ioe);
094            }
095        }
096    }
097
098    /**
099     * Stops the HTTP server
100     *
101     * @throws IOException
102     */
103    public void stopServer() throws IOException {
104        server.close();
105        Main.info(marktr("RemoteControl::Server stopped."));
106    }
107}