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}