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