Index: java/org/apache/catalina/core/StandardServer.java =================================================================== --- java/org/apache/catalina/core/StandardServer.java (revision 1066318) +++ java/org/apache/catalina/core/StandardServer.java (working copy) @@ -181,8 +181,18 @@ */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); - private boolean stopAwait = false; + private volatile boolean stopAwait = false; + /** + * Thread that currently is inside our await() method. + */ + private volatile Thread awaitThread = null; + + /** + * Server socket that is used to wait for the shutdown command. + */ + private volatile ServerSocket awaitSocket = null; + // ------------------------------------------------------------- Properties @@ -344,6 +354,24 @@ public void stopAwait() { stopAwait=true; + Thread t = awaitThread; + if (t != null) { + ServerSocket s = awaitSocket; + if (s != null) { + awaitSocket = null; + try { + s.close(); + } catch (IOException e) { + // Ignored + } + } + t.interrupt(); + try { + t.join(1000); + } catch (InterruptedException e) { + // Ignored + } + } } /** @@ -358,92 +386,117 @@ return; } if( port==-1 ) { - while( true ) { - try { - Thread.sleep( 10000 ); - } catch( InterruptedException ex ) { + try { + awaitThread = Thread.currentThread(); + while(!stopAwait) { + try { + Thread.sleep( 10000 ); + } catch( InterruptedException ex ) { + // continue and check the flag + } } - if( stopAwait ) return; + } finally { + awaitThread = null; } + return; } - + // Set up a server socket to wait on - ServerSocket serverSocket = null; try { - serverSocket = + awaitSocket = new ServerSocket(port, 1, InetAddress.getByName("localhost")); } catch (IOException e) { log.error("StandardServer.await: create[" + port + "]: ", e); - System.exit(1); + return; } - // Loop waiting for a connection and a valid command - while (true) { + try { + awaitThread = Thread.currentThread(); - // Wait for the next connection - Socket socket = null; - InputStream stream = null; - try { - socket = serverSocket.accept(); - socket.setSoTimeout(10 * 1000); // Ten seconds - stream = socket.getInputStream(); - } catch (AccessControlException ace) { - log.warn("StandardServer.accept security exception: " - + ace.getMessage(), ace); - continue; - } catch (IOException e) { - log.error("StandardServer.await: accept: ", e); - System.exit(1); + // Loop waiting for a connection and a valid command + while (!stopAwait) { + ServerSocket serverSocket = awaitSocket; + if (serverSocket == null) { + break; + } + + // Wait for the next connection + Socket socket = null; + StringBuilder command = new StringBuilder(); + try { + InputStream stream = null; + try { + socket = serverSocket.accept(); + socket.setSoTimeout(10 * 1000); // Ten seconds + stream = socket.getInputStream(); + } catch (AccessControlException ace) { + log.warn("StandardServer.accept security exception: " + + ace.getMessage(), ace); + continue; + } catch (IOException e) { + if (stopAwait) { + // Wait was aborted with socket.close() + break; + } + log.error("StandardServer.await: accept: ", e); + break; + } + + // Read a set of characters from the socket + int expected = 1024; // Cut off to avoid DoS attack + while (expected < shutdown.length()) { + if (random == null) + random = new Random(); + expected += (random.nextInt() % 1024); + } + while (expected > 0) { + int ch = -1; + try { + ch = stream.read(); + } catch (IOException e) { + log.warn("StandardServer.await: read: ", e); + ch = -1; + } + if (ch < 32) // Control character or EOF terminates loop + break; + command.append((char) ch); + expected--; + } + } finally { + // Close the socket now that we are done with it + try { + if (socket != null) { + socket.close(); + } + } catch (IOException e) { + // Ignore + } + } + + // Match against our command string + boolean match = command.toString().equals(shutdown); + if (match) { + break; + } else + log.warn("StandardServer.await: Invalid command '" + + command.toString() + "' received"); } + } finally { + ServerSocket serverSocket = awaitSocket; + awaitThread = null; + awaitSocket = null; - // Read a set of characters from the socket - StringBuffer command = new StringBuffer(); - int expected = 1024; // Cut off to avoid DoS attack - while (expected < shutdown.length()) { - if (random == null) - random = new Random(); - expected += (random.nextInt() % 1024); - } - while (expected > 0) { - int ch = -1; + // Close the server socket and return + if (serverSocket != null) { try { - ch = stream.read(); + serverSocket.close(); } catch (IOException e) { - log.warn("StandardServer.await: read: ", e); - ch = -1; + // Ignore } - if (ch < 32) // Control character or EOF terminates loop - break; - command.append((char) ch); - expected--; } - - // Close the socket now that we are done with it - try { - socket.close(); - } catch (IOException e) { - ; - } - - // Match against our command string - boolean match = command.toString().equals(shutdown); - if (match) { - break; - } else - log.warn("StandardServer.await: Invalid command '" + - command.toString() + "' received"); - } - - // Close the server socket and return - try { - serverSocket.close(); - } catch (IOException e) { - ; - } - } @@ -738,8 +791,7 @@ // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); - if (port == -1) - stopAwait(); + stopAwait(); } Index: java/org/apache/catalina/startup/Catalina.java =================================================================== --- java/org/apache/catalina/startup/Catalina.java (revision 1066318) +++ java/org/apache/catalina/startup/Catalina.java (working copy) @@ -34,6 +34,7 @@ import org.apache.catalina.Container; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; +import org.apache.catalina.Server; import org.apache.catalina.core.StandardServer; import org.apache.juli.ClassLoaderLogManager; import org.apache.tomcat.util.digester.Digester; @@ -382,7 +383,8 @@ arguments(arguments); } - if( getServer() == null ) { + Server s = getServer(); + if( s == null ) { // Create and execute our Digester Digester digester = createStopDigester(); digester.setClassLoader(Thread.currentThread().getContextClassLoader()); @@ -401,17 +403,25 @@ } } else { // Server object already present. Must be running as a service - // Shutdown hook will take care of clean-up - System.exit(0); + if (s instanceof Lifecycle) { + try { + ((Lifecycle) s).stop(); + } catch (LifecycleException e) { + log.error("Catalina.stop: ", e); + } + return; + } + // else fall down } // Stop the existing server + s = getServer(); try { - if (getServer().getPort()>0) { + if (s.getPort()>0) { String hostAddress = InetAddress.getByName("localhost").getHostAddress(); Socket socket = new Socket(hostAddress, getServer().getPort()); OutputStream stream = socket.getOutputStream(); - String shutdown = getServer().getShutdown(); + String shutdown = s.getShutdown(); for (int i = 0; i < shutdown.length(); i++) stream.write(shutdown.charAt(i)); stream.flush();