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.ServerSocket;
008import java.net.Socket;
009import java.net.SocketException;
010
011import org.openstreetmap.josm.spi.preferences.Config;
012import org.openstreetmap.josm.tools.Logging;
013
014/**
015 * Simple HTTP server that spawns a {@link RequestProcessor} for every
016 * connection.
017 *
018 * Taken from YWMS plugin by frsantos.
019 */
020public class RemoteControlHttpServer extends Thread {
021
022    /** The server socket */
023    private final ServerSocket server;
024
025    /** The server instance for IPv4 */
026    private static volatile RemoteControlHttpServer instance4;
027    /** The server instance for IPv6 */
028    private static volatile RemoteControlHttpServer instance6;
029
030    /**
031     * Starts or restarts the HTTP server
032     */
033    public static void restartRemoteControlHttpServer() {
034        stopRemoteControlHttpServer();
035        int port = Config.getPref().getInt("remote.control.port", 8111);
036        try {
037            instance4 = new RemoteControlHttpServer(port, false);
038            instance4.start();
039        } catch (IOException ex) {
040            Logging.debug(ex);
041            Logging.warn(marktr("Cannot start IPv4 remotecontrol server on port {0}: {1}"),
042                    Integer.toString(port), ex.getLocalizedMessage());
043        }
044        try {
045            instance6 = new RemoteControlHttpServer(port, true);
046            instance6.start();
047        } catch (IOException ex) {
048            /* only show error when we also have no IPv4 */
049            if (instance4 == null) {
050                Logging.debug(ex);
051                Logging.warn(marktr("Cannot start IPv6 remotecontrol server on port {0}: {1}"),
052                    Integer.toString(port), ex.getLocalizedMessage());
053            }
054        }
055    }
056
057    /**
058     * Stops the HTTP server
059     * @since 5861
060     */
061    public static void stopRemoteControlHttpServer() {
062        if (instance4 != null) {
063            try {
064                instance4.stopServer();
065            } catch (IOException ioe) {
066                Logging.error(ioe);
067            }
068            instance4 = null;
069        }
070        if (instance6 != null) {
071            try {
072                instance6.stopServer();
073            } catch (IOException ioe) {
074                Logging.error(ioe);
075            }
076            instance6 = null;
077        }
078    }
079
080    /**
081     * Constructor
082     * @param port The port this server will listen on
083     * @param ipv6 Whether IPv6 or IPv4 server should be started
084     * @throws IOException when connection errors
085     * @since 8339
086     */
087    public RemoteControlHttpServer(int port, boolean ipv6) throws IOException {
088        super("RemoteControl HTTP Server");
089        this.setDaemon(true);
090        this.server = new ServerSocket(port, 1, ipv6 ?
091            RemoteControl.getInet6Address() : RemoteControl.getInet4Address());
092    }
093
094    /**
095     * The main loop, spawns a {@link RequestProcessor} for each connection
096     */
097    @Override
098    public void run() {
099        Logging.info(marktr("RemoteControl::Accepting remote connections on {0}:{1}"),
100                server.getInetAddress(), Integer.toString(server.getLocalPort()));
101        while (true) {
102            try {
103                @SuppressWarnings("resource")
104                Socket request = server.accept();
105                RequestProcessor.processRequest(request);
106            } catch (SocketException e) {
107                if (!server.isClosed()) {
108                    Logging.error(e);
109                } else {
110                    // stop the thread automatically if server is stopped
111                    return;
112                }
113            } catch (IOException ioe) {
114                Logging.error(ioe);
115            }
116        }
117    }
118
119    /**
120     * Stops the HTTP server
121     *
122     * @throws IOException if any I/O error occurs
123     */
124    public void stopServer() throws IOException {
125        Logging.info(marktr("RemoteControl::Server {0}:{1} stopped."),
126        server.getInetAddress(), Integer.toString(server.getLocalPort()));
127        server.close();
128    }
129}