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.warn(marktr("Cannot start IPv4 remotecontrol server on port {0}: {1}"), 040 Integer.toString(port), ex.getLocalizedMessage()); 041 } 042 try { 043 instance6 = new RemoteControlHttpServer(port, true); 044 instance6.start(); 045 } catch (IOException ex) { 046 /* only show error when we also have no IPv4 */ 047 if (instance4 == null) { 048 Main.warn(marktr("Cannot start IPv6 remotecontrol server on port {0}: {1}"), 049 Integer.toString(port), ex.getLocalizedMessage()); 050 } 051 } 052 } 053 054 /** 055 * Stops the HTTP server 056 * @since 5861 057 */ 058 public static void stopRemoteControlHttpServer() { 059 if (instance4 != null) { 060 try { 061 instance4.stopServer(); 062 } catch (IOException ioe) { 063 Main.error(ioe); 064 } 065 instance4 = null; 066 } 067 if (instance6 != null) { 068 try { 069 instance6.stopServer(); 070 } catch (IOException ioe) { 071 Main.error(ioe); 072 } 073 instance6 = null; 074 } 075 } 076 077 /** 078 * Constructor 079 * @param port The port this server will listen on 080 * @param ipv6 Whether IPv6 or IPv4 server should be started 081 * @throws IOException when connection errors 082 * @since 8339 083 */ 084 public RemoteControlHttpServer(int port, boolean ipv6) throws IOException { 085 super("RemoteControl HTTP Server"); 086 this.setDaemon(true); 087 this.server = new ServerSocket(port, 1, ipv6 ? 088 RemoteControl.getInet6Address() : RemoteControl.getInet4Address()); 089 } 090 091 /** 092 * The main loop, spawns a {@link RequestProcessor} for each connection 093 */ 094 @Override 095 public void run() { 096 Main.info(marktr("RemoteControl::Accepting remote connections on {0}:{1}"), 097 server.getInetAddress(), Integer.toString(server.getLocalPort())); 098 while (true) { 099 try { 100 @SuppressWarnings("resource") 101 Socket request = server.accept(); 102 RequestProcessor.processRequest(request); 103 } catch (SocketException se) { 104 if (!server.isClosed()) { 105 Main.error(se); 106 } else { 107 // stop the thread automatically if server is stopped 108 return; 109 } 110 } catch (IOException ioe) { 111 Main.error(ioe); 112 } 113 } 114 } 115 116 /** 117 * Stops the HTTP server 118 * 119 * @throws IOException if any I/O error occurs 120 */ 121 public void stopServer() throws IOException { 122 Main.info(marktr("RemoteControl::Server {0}:{1} stopped."), 123 server.getInetAddress(), Integer.toString(server.getLocalPort())); 124 server.close(); 125 } 126}