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            ioe.printStackTrace();
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                ioe.printStackTrace();
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)
067        throws IOException
068    {
069        super("RemoteControl HTTP Server");
070        this.setDaemon(true);
071        // Start the server socket with only 1 connection.
072        // Also make sure we only listen
073        // on the local interface so nobody from the outside can connect!
074        // NOTE: On a dual stack machine with old Windows OS this may not listen on both interfaces!
075        this.server = new ServerSocket(port, 1,
076            InetAddress.getByName(Main.pref.get("remote.control.host", "localhost")));
077    }
078
079    /**
080     * The main loop, spawns a {@link RequestProcessor} for each connection
081     */
082    @Override
083    public void run()
084    {
085        Main.info(marktr("RemoteControl::Accepting connections on port {0}"),
086             Integer.toString(server.getLocalPort()));
087        while (true)
088        {
089            try
090            {
091                Socket request = server.accept();
092                RequestProcessor.processRequest(request);
093            }
094            catch( SocketException se)
095            {
096                if( !server.isClosed() )
097                    se.printStackTrace();
098                }
099            catch (IOException ioe)
100            {
101                ioe.printStackTrace();
102            }
103        }
104    }
105
106    /**
107     * Stops the HTTP server
108     *
109     * @throws IOException
110     */
111    public void stopServer() throws IOException
112    {
113        server.close();
114        Main.info(marktr("RemoteControl::Server stopped."));
115    }
116}