Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=49095
authormarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 25 May 2010 13:53:14 +0000 (13:53 +0000)
committermarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 25 May 2010 13:53:14 +0000 (13:53 +0000)
AprEndpoint does not wakeup accepts with deferred accept or BSD filters
Based on a patch provided by Ruediger Pluem

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@948043 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/tomcat/util/net/AprEndpoint.java

index 0e2a92c..511b46a 100644 (file)
@@ -17,6 +17,8 @@
 
 package org.apache.tomcat.util.net;
 
+import java.io.PrintWriter;
+import java.net.InetSocketAddress;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -578,6 +580,59 @@ public class AprEndpoint extends AbstractEndpoint {
 
 
     /**
+     * Unlock the server socket accept using a bogus connection.
+     */
+    @Override
+    protected void unlockAccept() {
+        java.net.Socket s = null;
+        InetSocketAddress saddr = null;
+        try {
+            // Need to create a connection to unlock the accept();
+            if (getAddress() == null) {
+                saddr = new InetSocketAddress("localhost", getPort());
+            } else {
+                saddr = new InetSocketAddress(getAddress(),getPort());
+            }
+            s = new java.net.Socket();
+            s.setSoTimeout(getSocketProperties().getSoTimeout());
+            // TODO Consider hard-coding to s.setSoLinger(true,0)
+            s.setSoLinger(getSocketProperties().getSoLingerOn(),getSocketProperties().getSoLingerTime());
+            if (log.isDebugEnabled()) {
+                log.debug("About to unlock socket for:"+saddr);
+            }
+            s.connect(saddr,getSocketProperties().getUnlockTimeout());
+            /*
+             * In the case of a deferred accept / accept filters we need to
+             * send data to wake up the accept. Send OPTIONS * to bypass even
+             * BSD accept filters. The Acceptor will discard it.
+             */
+            if (deferAccept) {
+                PrintWriter pw;
+
+                pw = new PrintWriter(s.getOutputStream());
+                pw.print("OPTIONS * HTTP/1.0\r\n" +
+                         "User-Agent: Tomcat wakeup connection\r\n\r\n");
+                pw.flush();
+            }
+            if (log.isDebugEnabled()) {
+                log.debug("Socket unlock completed for:"+saddr);
+            }
+        } catch(Exception e) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("endpoint.debug.unlock", "" + getPort()), e);
+            }
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+        }
+    }    
+
+    /**
      * Pause the endpoint, which will make it stop accepting new sockets.
      */
     @Override
@@ -823,6 +878,15 @@ public class AprEndpoint extends AbstractEndpoint {
                 try {
                     // Accept the next incoming connection from the server socket
                     long socket = Socket.accept(serverSock);
+                    /*
+                     * In the case of a deferred accept unlockAccept needs to
+                     * send data. This data will be rubbish, so destroy the
+                     * socket and don't process it.
+                     */
+                    if (deferAccept && (paused || !running)) {
+                        Socket.destroy(socket);
+                        continue;
+                    }
                     // Hand this socket off to an appropriate processor
                     if (!processSocketWithOptions(socket)) {
                         // Close socket and pool right away