You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2012/03/29 06:40:44 UTC

svn commit: r1306715 - in /tomcat/trunk/java/org/apache: coyote/ajp/ coyote/http11/ coyote/spdy/ tomcat/jni/socket/ tomcat/spdy/ tomcat/util/net/

Author: costin
Date: Thu Mar 29 04:40:43 2012
New Revision: 1306715

URL: http://svn.apache.org/viewvc?rev=1306715&view=rev
Log:
Add a hook for JIO, NIO, APR that allows SSL connections to negotiate an alternative protocol, if the SSL layer supports it.
Updates/fixes/cleanups to the spdy implementation.


Added:
    tomcat/trunk/java/org/apache/coyote/http11/NpnHandler.java
    tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportOpenSSL.java
    tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportSocket.java
Removed:
    tomcat/trunk/java/org/apache/tomcat/spdy/SpdyContextJni.java
    tomcat/trunk/java/org/apache/tomcat/spdy/SpdyContextProxy.java
Modified:
    tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java
    tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java
    tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java
    tomcat/trunk/java/org/apache/coyote/spdy/SpdyAprNpnHandler.java
    tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java
    tomcat/trunk/java/org/apache/coyote/spdy/SpdyProxyProtocol.java
    tomcat/trunk/java/org/apache/tomcat/jni/socket/AprSocketContext.java
    tomcat/trunk/java/org/apache/tomcat/spdy/CompressDeflater6.java
    tomcat/trunk/java/org/apache/tomcat/spdy/SpdyConnection.java
    tomcat/trunk/java/org/apache/tomcat/spdy/SpdyContext.java
    tomcat/trunk/java/org/apache/tomcat/spdy/SpdyFrame.java
    tomcat/trunk/java/org/apache/tomcat/spdy/SpdyStream.java
    tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java
    tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java

Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProtocol.java Thu Mar 29 04:40:43 2012
@@ -19,6 +19,8 @@ package org.apache.coyote.ajp;
 import java.nio.channels.SocketChannel;
 import java.util.Iterator;
 
+import javax.net.ssl.SSLEngine;
+
 import org.apache.coyote.AbstractProtocol;
 import org.apache.coyote.Processor;
 import org.apache.juli.logging.Log;
@@ -176,5 +178,9 @@ public class AjpNioProtocol extends Abst
             register(processor);
             return processor;
         }
+
+        @Override
+        public void onCreateSSLEngine(SSLEngine engine) {
+        }
     }
 }

Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpProtocol.java Thu Mar 29 04:40:43 2012
@@ -140,5 +140,9 @@ public class AjpProtocol extends Abstrac
             register(processor);
             return processor;
         }
+
+        @Override
+        public void beforeHandshake(SocketWrapper<Socket> socket) {
+        }
     }
 }

Modified: tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java Thu Mar 29 04:40:43 2012
@@ -183,4 +183,15 @@ public abstract class AbstractHttp11Prot
     public void setMaxKeepAliveRequests(int mkar) {
         endpoint.setMaxKeepAliveRequests(mkar);
     }
+    
+    protected NpnHandler npnHandler;
+    public void setNpnHandler(String impl) {
+        try {
+            Class<?> c = Class.forName(impl);
+            npnHandler = (NpnHandler) c.newInstance();
+        } catch (Exception ex) {
+            getLog().warn("Failed to init light protocol " + impl, ex);
+        }
+    }
+
 }

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java Thu Mar 29 04:40:43 2012
@@ -45,16 +45,6 @@ public class Http11AprProtocol extends A
 
     private static final Log log = LogFactory.getLog(Http11AprProtocol.class);
 
-    /**
-     * Interface specific for protocols that negotiate at NPN level, like
-     * SPDY. This is only available for APR, will replace the HTTP framing.
-     */
-    public static interface NpnHandler {
-        SocketState process(SocketWrapper<Long> socket, SocketStatus status,
-                Http11AprProtocol proto, AbstractEndpoint endpoint);
-        public void init(final AbstractEndpoint ep, long sslContext, Adapter adapter);
-    }
-
     @Override
     protected Log getLog() { return log; }
 
@@ -75,7 +65,6 @@ public class Http11AprProtocol extends A
     }
 
     private final Http11ConnectionHandler cHandler;
-    private NpnHandler npnHandler;
 
     public boolean getUseSendfile() { return ((AprEndpoint)endpoint).getUseSendfile(); }
     public void setUseSendfile(boolean useSendfile) { ((AprEndpoint)endpoint).setUseSendfile(useSendfile); }
@@ -184,16 +173,6 @@ public class Http11AprProtocol extends A
     public int getSSLVerifyDepth() { return ((AprEndpoint)endpoint).getSSLVerifyDepth(); }
     public void setSSLVerifyDepth(int SSLVerifyDepth) { ((AprEndpoint)endpoint).setSSLVerifyDepth(SSLVerifyDepth); }
 
-    // TODO: map of protocols
-    public void setNpnHandler(String impl) {
-        try {
-            Class<?> c = Class.forName(impl);
-            npnHandler = (NpnHandler) c.newInstance();
-        } catch (Exception ex) {
-            getLog().warn("Failed to init light protocol " + impl, ex);
-        }
-    }
-
     // ----------------------------------------------------- JMX related methods
 
     @Override
@@ -269,8 +248,7 @@ public class Http11AprProtocol extends A
                 }
                 if (processor == null) {
                     // if not null - this is a former comet request, handled by http11
-                    SocketState socketState = proto.npnHandler.process(socket, status,
-                            proto, proto.endpoint);
+                    SocketState socketState = proto.npnHandler.process(socket, status);
                     // handled by npn protocol.
                     if (socketState == SocketState.CLOSED ||
                             socketState == SocketState.LONG) {
@@ -296,7 +274,6 @@ public class Http11AprProtocol extends A
                 // Async
                 socket.setAsync(true);
             } else if (processor.isComet() && proto.endpoint.isRunning()) {
-                // Comet
                 ((AprEndpoint) proto.endpoint).getCometPoller().add(
                         socket.getSocket().longValue(), false);
             } else {

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProtocol.java Thu Mar 29 04:40:43 2012
@@ -20,6 +20,8 @@ import java.io.IOException;
 import java.nio.channels.SocketChannel;
 import java.util.Iterator;
 
+import javax.net.ssl.SSLEngine;
+
 import org.apache.coyote.AbstractProtocol;
 import org.apache.coyote.Processor;
 import org.apache.coyote.http11.upgrade.UpgradeInbound;
@@ -27,11 +29,13 @@ import org.apache.coyote.http11.upgrade.
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.net.AbstractEndpoint;
+import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
 import org.apache.tomcat.util.net.NioChannel;
 import org.apache.tomcat.util.net.NioEndpoint;
 import org.apache.tomcat.util.net.NioEndpoint.Handler;
 import org.apache.tomcat.util.net.SSLImplementation;
 import org.apache.tomcat.util.net.SecureNioChannel;
+import org.apache.tomcat.util.net.SocketStatus;
 import org.apache.tomcat.util.net.SocketWrapper;
 
 
@@ -73,7 +77,14 @@ public class Http11NioProtocol extends A
         return ((NioEndpoint)endpoint);
     }
 
-
+    @Override
+    public void start() throws Exception {
+        super.start();
+        if (npnHandler != null) {
+            npnHandler.init(getEndpoint(), 0, adapter);
+        }
+    }
+    
     // -------------------- Properties--------------------
 
     private Http11ConnectionHandler cHandler;
@@ -201,6 +212,17 @@ public class Http11NioProtocol extends A
             }
         }
 
+        public SocketState process(SocketWrapper<NioChannel> socket,
+                SocketStatus status) {
+            if (proto.npnHandler != null) {
+                SocketState ss = proto.npnHandler.process(socket, status);
+                if (ss != SocketState.OPEN) {
+                    return ss;
+                }
+            }
+            return super.process(socket, status);
+        }
+        
 
         /**
          * Expected to be used by the handler once the processor is no longer
@@ -286,5 +308,12 @@ public class Http11NioProtocol extends A
             return new UpgradeNioProcessor(socket, inbound,
                     ((Http11NioProtocol) getProtocol()).getEndpoint().getSelectorPool());
         }
+
+        @Override
+        public void onCreateSSLEngine(SSLEngine engine) {
+            if (proto.npnHandler != null) {
+                proto.npnHandler.onCreateEngine(engine);
+            }
+        }
     }
 }

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Protocol.java Thu Mar 29 04:40:43 2012
@@ -25,9 +25,11 @@ import org.apache.coyote.http11.upgrade.
 import org.apache.coyote.http11.upgrade.UpgradeInbound;
 import org.apache.juli.logging.Log;
 import org.apache.tomcat.util.net.AbstractEndpoint;
+import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
 import org.apache.tomcat.util.net.JIoEndpoint;
 import org.apache.tomcat.util.net.JIoEndpoint.Handler;
 import org.apache.tomcat.util.net.SSLImplementation;
+import org.apache.tomcat.util.net.SocketStatus;
 import org.apache.tomcat.util.net.SocketWrapper;
 
 
@@ -89,6 +91,14 @@ public class Http11Protocol extends Abst
             this.disableKeepAlivePercentage = disableKeepAlivePercentage;
         }
     }
+    
+    @Override
+    public void start() throws Exception {
+        super.start();
+        if (npnHandler != null) {
+            npnHandler.init(endpoint, 0, adapter);
+        }
+    }
 
     // ----------------------------------------------------- JMX related methods
 
@@ -124,6 +134,17 @@ public class Http11Protocol extends Abst
             return proto.sslImplementation;
         }
 
+        public SocketState process(SocketWrapper<Socket> socket,
+                SocketStatus status) {
+            if (proto.npnHandler != null) {
+                SocketState ss = proto.npnHandler.process(socket, status);
+                if (ss != SocketState.OPEN) {
+                    return ss;
+                }
+            }
+            return super.process(socket, status);
+        }
+        
         /**
          * Expected to be used by the handler once the processor is no longer
          * required.
@@ -191,5 +212,9 @@ public class Http11Protocol extends Abst
                 throws IOException {
             return new UpgradeBioProcessor(socket, inbound);
         }
+
+        @Override
+        public void beforeHandshake(SocketWrapper<Socket> socket) {
+        }
     }
 }

Added: tomcat/trunk/java/org/apache/coyote/http11/NpnHandler.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/NpnHandler.java?rev=1306715&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/NpnHandler.java (added)
+++ tomcat/trunk/java/org/apache/coyote/http11/NpnHandler.java Thu Mar 29 04:40:43 2012
@@ -0,0 +1,43 @@
+/*
+ */
+package org.apache.coyote.http11;
+
+import org.apache.coyote.Adapter;
+import org.apache.tomcat.util.net.AbstractEndpoint;
+import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
+import org.apache.tomcat.util.net.SocketStatus;
+import org.apache.tomcat.util.net.SocketWrapper;
+
+/**
+ * Interface specific for protocols that negotiate at NPN level, like
+ * SPDY. This is only available for APR, will replace the HTTP framing.
+ */
+public interface NpnHandler {
+    
+    /** 
+     * Check if the socket has negotiated the right NPN and process it.
+     *  
+     * @param socket
+     * @param status
+     * @return OPEN if the socket doesn't have the right npn.
+     *    CLOSE if processing is done. LONG to request read polling.
+     */
+    SocketState process(SocketWrapper<?> socket, SocketStatus status);
+    
+    /**
+     * Initialize the npn handler.
+     * 
+     * @param ep
+     * @param sslContext
+     * @param adapter
+     */
+    public void init(final AbstractEndpoint ep, long sslContext, Adapter adapter);
+
+    /** 
+     * Called when a SSLSocket or SSLEngine are first used, to initialize 
+     * NPN extension.
+     * 
+     * @param socket SSLEngine or SSLSocket
+     */
+    void onCreateEngine(Object socket);
+}
\ No newline at end of file

Modified: tomcat/trunk/java/org/apache/coyote/spdy/SpdyAprNpnHandler.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/spdy/SpdyAprNpnHandler.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/spdy/SpdyAprNpnHandler.java (original)
+++ tomcat/trunk/java/org/apache/coyote/spdy/SpdyAprNpnHandler.java Thu Mar 29 04:40:43 2012
@@ -20,12 +20,14 @@ import java.io.IOException;
 
 import org.apache.coyote.Adapter;
 import org.apache.coyote.http11.Http11AprProtocol;
+import org.apache.coyote.http11.NpnHandler;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.jni.SSLExt;
+import org.apache.tomcat.spdy.NetSupportOpenSSL;
 import org.apache.tomcat.spdy.SpdyConnection;
 import org.apache.tomcat.spdy.SpdyContext;
-import org.apache.tomcat.spdy.SpdyContextJni;
+import org.apache.tomcat.spdy.SpdyContext.SpdyHandler;
 import org.apache.tomcat.spdy.SpdyStream;
 import org.apache.tomcat.util.net.AbstractEndpoint;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
@@ -57,66 +59,57 @@ import org.apache.tomcat.util.net.Socket
  * negotiated by TLS.
  *
  */
-public class SpdyAprNpnHandler implements Http11AprProtocol.NpnHandler {
+public class SpdyAprNpnHandler implements NpnHandler {
 
     private static final Log log = LogFactory.getLog(AprEndpoint.class);
 
-    private SpdyContextApr spdyContext;
-
-    boolean ssl = true;
+    private SpdyContext spdyContext;
 
     @Override
     public void init(final AbstractEndpoint ep, long sslContext,
             final Adapter adapter) {
+        spdyContext = new SpdyContext();
         if (sslContext == 0) {
-            // Apr endpoint without SSL.
-            ssl = false;
-            spdyContext = new SpdyContextApr(ep, adapter);
-            spdyContext.setExecutor(ep.getExecutor());
+            // Apr endpoint without SSL - proxy mode.
+            spdyContext.setTlsComprression(false, false);
             return;
         }
-        if (0 == SSLExt.setNPN(sslContext, SpdyContext.SPDY_NPN_OUT)) {
-            spdyContext = new SpdyContextApr(ep, adapter);
-            spdyContext.setExecutor(ep.getExecutor());
-        } else {
+        if (0 != SSLExt.setNPN(sslContext, SpdyContext.SPDY_NPN_OUT)) {
             log.warn("SPDY/NPN not supported");
         }
-    }
-
-
-    private final class SpdyContextApr extends SpdyContextJni {
-        private final AbstractEndpoint ep;
-
-        private final Adapter adapter;
-
-        private SpdyContextApr(AbstractEndpoint ep, Adapter adapter) {
-            this.ep = ep;
-            this.adapter = adapter;
-        }
-
-        @Override
-        protected void onSynStream(SpdyConnection con, SpdyStream ch) throws IOException {
-            SpdyProcessor sp = new SpdyProcessor(con, ep);
-            sp.setAdapter(adapter);
-            sp.onSynStream(ch);
-        }
+        spdyContext.setNetSupport(new NetSupportOpenSSL());
+        spdyContext.setExecutor(ep.getExecutor());
+        spdyContext.setHandler(new SpdyHandler() {
+            @Override
+            public void onStream(SpdyConnection con, SpdyStream ch)
+                    throws IOException {
+                SpdyProcessor sp = new SpdyProcessor(con, ep);
+                sp.setAdapter(adapter);
+                sp.onSynStream(ch);
+            }
+        });
     }
 
     @Override
-    public SocketState process(SocketWrapper<Long> socketO, SocketStatus status,
-            Http11AprProtocol proto, AbstractEndpoint endpoint) {
+    public SocketState process(SocketWrapper<?> socketO, SocketStatus status) {
 
-        SocketWrapper<Long> socketW = socketO;
+        SocketWrapper<Long> socketW = (SocketWrapper<Long>) socketO;
         long socket = socketW.getSocket().longValue();
+        
+        if (! spdyContext.getNetSupport().isSpdy(socketW.getSocket())) {
+            return SocketState.OPEN;            
+        }
 
         try {
-            spdyContext.onAccept(socket);
+            ((NetSupportOpenSSL) spdyContext.getNetSupport()).onAcceptLong(socket);
         } catch (IOException e) {
         }
         // No need to keep tomcat thread busy - but socket will be handled by apr socket context.
         return SocketState.LONG;
     }
 
-    public void onClose(SocketWrapper<Long> socketWrapper) {
+
+    @Override
+    public void onCreateEngine(Object socket) {
     }
 }

Modified: tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java Thu Mar 29 04:40:43 2012
@@ -97,15 +97,21 @@ public class SpdyProcessor extends Abstr
                 inFrame = spdyStream.getDataFrame(endpoint.getSoTimeout());
             }
             if (inFrame == null) {
+                return -1; // timeout
+            }
+            if (inFrame.remaining() == 0 && inFrame.isHalfClose()) {
                 return -1;
             }
-
-            int rd = Math.min(inFrame.endData, bchunk.getBytes().length);
+            
+            int rd = Math.min(inFrame.remaining(), bchunk.getBytes().length);
             System.arraycopy(inFrame.data, inFrame.off, bchunk.getBytes(),
                     bchunk.getStart(), rd);
             inFrame.advance(rd);
-            if (inFrame.off == inFrame.endData) {
+            if (inFrame.remaining() == 0) {
                 spdy.getSpdyContext().releaseFrame(inFrame);
+                if (!inFrame.isHalfClose()) {
+                    inFrame = null;
+                }
             }
             bchunk.setEnd(bchunk.getEnd() + rd);
             return rd;

Modified: tomcat/trunk/java/org/apache/coyote/spdy/SpdyProxyProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/spdy/SpdyProxyProtocol.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/spdy/SpdyProxyProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/spdy/SpdyProxyProtocol.java Thu Mar 29 04:40:43 2012
@@ -23,8 +23,10 @@ import org.apache.coyote.AbstractProtoco
 import org.apache.coyote.ajp.Constants;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.spdy.NetSupportSocket;
 import org.apache.tomcat.spdy.SpdyConnection;
-import org.apache.tomcat.spdy.SpdyContextProxy;
+import org.apache.tomcat.spdy.SpdyContext;
+import org.apache.tomcat.spdy.SpdyContext.SpdyHandler;
 import org.apache.tomcat.spdy.SpdyStream;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler;
 import org.apache.tomcat.util.net.JIoEndpoint;
@@ -51,7 +53,7 @@ public class SpdyProxyProtocol extends A
     private static final Log log = LogFactory.getLog(SpdyProxyProtocol.class);
 
     JIoEndpoint.Handler cHandler = new TomcatJioHandler();
-    SpdyContextProxy spdyContext;
+    SpdyContext spdyContext;
 
     public SpdyProxyProtocol() {
         endpoint = new JIoEndpoint();
@@ -84,14 +86,17 @@ public class SpdyProxyProtocol extends A
     @Override
     public void start() throws Exception {
         super.start();
-        spdyContext = new SpdyContextProxy() {
+        spdyContext = new SpdyContext();
+        spdyContext.setTlsComprression(false, false);
+        spdyContext.setHandler(new SpdyHandler() {
             @Override
-            protected void onSynStream(SpdyConnection con, SpdyStream ch) throws IOException {
+            public void onStream(SpdyConnection con, SpdyStream ch) throws IOException {
                 SpdyProcessor sp = new SpdyProcessor(con, endpoint);
                 sp.setAdapter(adapter);
                 sp.onSynStream(ch);
             }
-        };
+        });
+        spdyContext.setNetSupport(new NetSupportSocket());
         spdyContext.setExecutor(endpoint.getExecutor());
     }
 
@@ -109,8 +114,11 @@ public class SpdyProxyProtocol extends A
         @Override
         public SocketState process(SocketWrapper<Socket> socket,
                 SocketStatus status) {
-            SpdyConnection ch = spdyContext.getConnection(socket.getSocket());
-            ch.onBlockingSocket();
+            try {
+                spdyContext.getNetSupport().onAccept(socket.getSocket());
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
             return SocketState.CLOSED;
         }
 
@@ -119,5 +127,9 @@ public class SpdyProxyProtocol extends A
             return null;
         }
 
+        @Override
+        public void beforeHandshake(SocketWrapper<Socket> socket) {
+        }
+
     }
 }

Modified: tomcat/trunk/java/org/apache/tomcat/jni/socket/AprSocketContext.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jni/socket/AprSocketContext.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jni/socket/AprSocketContext.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/jni/socket/AprSocketContext.java Thu Mar 29 04:40:43 2012
@@ -417,6 +417,9 @@ public class AprSocketContext {
 
     public AprSocket socket(long socket) throws IOException {
         AprSocket sock = newSocket(this);
+        // Tomcat doesn't set this
+        SSLExt.sslSetMode(socket, SSLExt.SSL_MODE_ENABLE_PARTIAL_WRITE |
+                SSLExt.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
         sock.setStatus(AprSocket.ACCEPTED);
         sock.socket = socket;
         return sock;
@@ -429,7 +432,7 @@ public class AprSocketContext {
             if (socket.socket != 0) {
                 long s = socket.socket;
                 socket.socket = 0;
-                System.err.println("DESTROY: " + Long.toHexString(s));
+                log.info("DESTROY: " + Long.toHexString(s));
                 Socket.destroy(s);
             }
         }
@@ -583,7 +586,7 @@ public class AprSocketContext {
             if (rootPool == 0) {
                 return;
             }
-            System.err.println("DESTROY " + rootPool);
+            log.info("Destroy root pool " + rootPool);
             //Pool.destroy(rootPool);
             //rootPool = 0;
         }
@@ -1226,7 +1229,9 @@ public class AprSocketContext {
                 updateIOThread(ch);
             } else {
                 synchronized (this) {
-                    updates.add(ch);
+                    if (!updates.contains(ch)) {
+                        updates.add(ch);
+                    }
                     interruptPoll();
                 }
                 if (debugPoll) {
@@ -1276,6 +1281,9 @@ public class AprSocketContext {
             boolean failed = false;
             int rv;
             synchronized (channels) {
+                if (up.isClosed()) {
+                    return;
+                }
                 rv = Poll.add(serverPollset, up.socket, req);
                 if (rv != Status.APR_SUCCESS) {
                     up.poller = null;

Modified: tomcat/trunk/java/org/apache/tomcat/spdy/CompressDeflater6.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/spdy/CompressDeflater6.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/spdy/CompressDeflater6.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/spdy/CompressDeflater6.java Thu Mar 29 04:40:43 2012
@@ -26,11 +26,11 @@ import org.apache.tomcat.spdy.SpdyConnec
 /**
  * Java6 Deflater with the workaround from tomcat http filters.
  */
-public class CompressDeflater6 implements CompressSupport {
+class CompressDeflater6 implements CompressSupport {
     public static long DICT_ID = 3751956914L;
 
     // Make sure to use the latest from net/spdy/spdy_framer.cc, not from spec
-    private static String SPDY_DICT_S = "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
+    static String SPDY_DICT_S = "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
             + "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
             + "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
             + "-agent10010120020120220320420520630030130230330430530630740040140240340440"
@@ -67,6 +67,11 @@ public class CompressDeflater6 implement
     public CompressDeflater6() {
     }
 
+    public static CompressDeflater6 get() {
+        // TODO: code to plug in v7-specific. It is marginally faster.
+        return new CompressDeflater6();
+    }
+    
     public void recycle() {
         // TODO
     }
@@ -143,7 +148,6 @@ public class CompressDeflater6 implement
         decOff = start;
 
         int off = start;
-        int max = frame.data.length;
 
         zipIn.setInput(frame.data, start, decMax - start);
 

Added: tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportOpenSSL.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportOpenSSL.java?rev=1306715&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportOpenSSL.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportOpenSSL.java Thu Mar 29 04:40:43 2012
@@ -0,0 +1,203 @@
+/*
+ */
+package org.apache.tomcat.spdy;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.nio.channels.ByteChannel;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.net.ssl.SSLEngine;
+
+import org.apache.tomcat.jni.SSLExt;
+import org.apache.tomcat.jni.Status;
+import org.apache.tomcat.jni.socket.AprSocket;
+import org.apache.tomcat.jni.socket.AprSocketContext;
+import org.apache.tomcat.jni.socket.AprSocketContext.NonBlockingPollHandler;
+import org.apache.tomcat.jni.socket.AprSocketContext.TlsCertVerifier;
+
+
+public class NetSupportOpenSSL extends SpdyContext.NetSupport {
+
+    List<String> protos = Arrays.asList(new String[] {"spdy/2", "http/1.1"});
+    AprSocketContext con;
+
+    public NetSupportOpenSSL() {
+        con = new AprSocketContext();
+        //if (insecureCerts) {
+        con.customVerification(new TlsCertVerifier() {
+            @Override
+            public void handshakeDone(AprSocket ch) {
+            }
+        });
+        //}
+        con.setNpn("spdy/2");        
+    }
+    
+    @Override
+    public boolean isSpdy(Object socketW) {
+        byte[] proto = new byte[32];
+        int len = SSLExt.getNPN((Long) socketW, proto);
+        return len == 6; // todo: check spdy/2
+    }
+    
+    @Override
+    public SpdyConnection getConnection(String host, int port) throws IOException {
+        SpdyConnectionAprSocket spdy = new SpdyConnectionAprSocket(ctx);
+
+        AprSocket ch = con.socket(host, port, ctx.tls);
+
+        spdy.setSocket(ch);
+
+        ch.connect();
+
+        ch.setHandler(new SpdySocketHandler(spdy));
+
+        // need to consume the input to receive more read events
+        int rc = spdy.processInput();
+        if (rc == SpdyConnection.CLOSE) {
+            ch.close();
+            throw new IOException("Error connecting");
+        }
+
+        return spdy;
+    }
+
+    @Override
+    public void onAccept(Object socket) throws IOException {
+        onAcceptLong((Long) socket);
+    }
+    
+    public void onAcceptLong(long socket) throws IOException {
+        SpdyConnectionAprSocket spdy = new SpdyConnectionAprSocket(ctx);
+        AprSocket s = con.socket(socket);
+        spdy.setSocket(s);
+
+        SpdySocketHandler handler = new SpdySocketHandler(spdy);
+        s.setHandler(handler);
+        handler.process(s, true, true, false);
+    }
+
+    public AprSocketContext getAprContext() {
+        return con;
+    }
+
+
+    @Override
+    public void listen(final int port, String cert, String key) throws IOException {
+        con = new AprSocketContext() {
+            @Override
+            protected void onSocket(AprSocket s) throws IOException {
+                SpdyConnectionAprSocket spdy = new SpdyConnectionAprSocket(ctx);
+                spdy.setSocket(s);
+
+                SpdySocketHandler handler = new SpdySocketHandler(spdy);
+                s.setHandler(handler);
+            }
+        };
+
+        con.setNpn(SpdyContext.SPDY_NPN_OUT);
+        con.setKeys(cert, key);
+
+        con.listen(port);
+    }
+
+    @Override
+    public void stop() throws IOException {
+        con.stop();
+    }
+
+    // NB
+    static class SpdySocketHandler implements NonBlockingPollHandler {
+        SpdyConnection con;
+
+        SpdySocketHandler(SpdyConnection con) {
+            this.con = con;
+        }
+
+        @Override
+        public void closed(AprSocket ch) {
+            // not used ( polling not implemented yet )
+        }
+
+        @Override
+        public void process(AprSocket ch, boolean in, boolean out, boolean close) {
+            try {
+                int rc = con.processInput();
+                if (rc == SpdyConnection.CLOSE) {
+                    ch.close();
+                }
+                con.drain();
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+                ch.reset();
+            }
+        }
+
+        @Override
+        public void connected(AprSocket ch) {
+        }
+
+        @Override
+        public void error(AprSocket ch, Throwable t) {
+        }
+
+    }
+
+    public static class SpdyConnectionAprSocket extends SpdyConnection {
+        AprSocket socket;
+
+        public SpdyConnectionAprSocket(SpdyContext spdyContext) {
+            super(spdyContext);
+        }
+
+        public void setSocket(AprSocket ch) {
+            this.socket = ch;
+        }
+
+        @Override
+        public void close() throws IOException {
+            socket.close();
+        }
+
+        @Override
+        public int write(byte[] data, int off, int len) throws IOException {
+            if (socket == null) {
+                return -1;
+            }
+            int sent = socket.write(data, off, len);
+            if (sent < 0) {
+                return -1;
+            }
+            return sent;
+        }
+
+        /**
+         * @throws IOException
+         */
+        @Override
+        public int read(byte[] data, int off, int len) throws IOException {
+            if (socket == null) {
+                return -1;
+            }
+            int rd = socket.read(data, off, len);
+            // org.apache.tomcat.jni.Socket.recv(socket, data, off, len);
+            if (rd == -Status.APR_EOF) {
+                return -1;
+            }
+            if (rd == -Status.TIMEUP || rd == -Status.EINTR || rd == -Status.EAGAIN) {
+                rd = 0;
+            }
+            if (rd < 0) {
+                return -1;
+            }
+            off += rd;
+            len -= rd;
+            return rd;
+        }
+    }
+
+    
+}

Added: tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportSocket.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportSocket.java?rev=1306715&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportSocket.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/spdy/NetSupportSocket.java Thu Mar 29 04:40:43 2012
@@ -0,0 +1,158 @@
+/*
+ */
+package org.apache.tomcat.spdy;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+
+
+public class NetSupportSocket extends SpdyContext.NetSupport {
+
+    public void onCreateEngine(Object engine) {
+    }
+    
+    public boolean isSpdy(Object socketW) {
+        return false;
+    }
+
+    public SpdyConnection getConnection(String host, int port) throws IOException {
+        try {
+            Socket sock = getSocket(host, port);
+
+            sock.getInputStream();
+            SpdyConnectionSocket con = new SpdyConnectionSocket(ctx, sock);
+
+            ctx.getExecutor().execute(con.inputThread);
+            return con;
+        } catch (IOException ex) {
+            ex.printStackTrace();
+            throw ex;
+        }
+        
+    }
+    
+
+    protected Socket getSocket(String host, int port) throws IOException {
+        try {
+            if (ctx.tls) {
+                SSLContext sslCtx = SSLContext.getDefault();
+                SSLSocket socket = (SSLSocket) sslCtx.getSocketFactory().createSocket(host, port);
+                //socket.setEnabledProtocols(new String[] {"TLS1"});
+                socket.startHandshake();
+                return socket;
+            } else {
+                return new Socket(host, port);            
+            }
+        } catch (NoSuchAlgorithmException e) {
+            throw new IOException(e);
+        }
+        
+    }
+
+    boolean running = true;
+    ServerSocket serverSocket;
+
+    @Override
+    public void stop() throws IOException {
+        running = false;
+        serverSocket.close();
+    }
+
+    public void onAccept(Object socket) {
+        SpdyConnectionSocket ch = new SpdyConnectionSocket(ctx, (Socket) socket);
+        ctx.getExecutor().execute(ch.inputThread);
+        ch.onBlockingSocket();
+    }
+
+    
+    @Override
+    public void listen(final int port, String cert, String key) throws IOException {
+        ctx.getExecutor().execute(new Runnable() {
+            @Override
+            public void run() {
+                accept(port);
+            }
+        });
+    }
+
+    private void accept(int port) {
+        try {
+            serverSocket = new ServerSocket(port);
+            while (running) {
+                final Socket socket = serverSocket.accept();
+                ctx.getExecutor().execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        onAccept(socket);
+                        try {
+                            socket.close();
+                        } catch (IOException e) {
+                            e.printStackTrace();
+                        }
+                    }
+                });
+            }
+        } catch (IOException ex) {
+            if (running) {
+                ex.printStackTrace();
+            }
+            running = false;
+        }
+    }
+
+
+    public static class SpdyConnectionSocket extends SpdyConnection {
+        Socket socket;
+
+
+        Runnable inputThread = new Runnable() {
+            @Override
+            public void run() {
+                onBlockingSocket();
+                try {
+                    inClosed = true;
+                    socket.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        };
+
+        public SpdyConnectionSocket(SpdyContext spdyContext) {
+            super(spdyContext);
+        }
+
+        public SpdyConnectionSocket(SpdyContext spdyContext, Socket socket) {
+            super(spdyContext);
+            this.socket = socket;
+        }
+
+        @Override
+        public void close() throws IOException {
+            socket.close();
+        }
+
+        @Override
+        public synchronized int write(byte[] data, int off, int len) throws IOException {
+            socket.getOutputStream().write(data, off, len);
+            return len;
+        }
+
+        @Override
+        public int read(byte[] data, int off, int len) throws IOException {
+            try {
+                return socket.getInputStream().read(data, off, len);
+            } catch (SocketTimeoutException ex) {
+                return 0;
+            }
+        }
+    }
+    
+}
+

Modified: tomcat/trunk/java/org/apache/tomcat/spdy/SpdyConnection.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/spdy/SpdyConnection.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/spdy/SpdyConnection.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/spdy/SpdyConnection.java Thu Mar 29 04:40:43 2012
@@ -23,12 +23,13 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import org.apache.tomcat.util.net.NioSelectorPool;
+
 /**
  * Main class implementing SPDY protocol. Works with both blocking and
  * non-blocking sockets. To simplify integration in various endpoints there is
@@ -119,14 +120,10 @@ public abstract class SpdyConnection { /
 
     LinkedList<SpdyFrame> outQueue = new LinkedList<SpdyFrame>();
 
-    Lock framerLock = new ReentrantLock();
-
     // --------------
 
     public static byte[] NPN = "spdy/2".getBytes();
 
-    private Condition outCondition;
-
     public static final int LONG = 1;
 
     public static final int CLOSE = -1;
@@ -142,9 +139,8 @@ public abstract class SpdyConnection { /
 
     public SpdyConnection(SpdyContext spdyContext) {
         this.spdyContext = spdyContext;
-        outCondition = framerLock.newCondition();
         if (spdyContext.compression) {
-            setCompressSupport(new CompressDeflater6());
+            setCompressSupport(CompressDeflater6.get());
         }
     }
 
@@ -215,9 +211,7 @@ public abstract class SpdyConnection { /
      */
     private boolean _drain() {
         while (true) {
-            framerLock.lock();
-
-            try {
+            synchronized (outQueue) {
                 if (out == null) {
                     out = prioriyQueue.poll();
                     if (out == null) {
@@ -227,49 +221,46 @@ public abstract class SpdyConnection { /
                         return false;
                     }
                     if (goAway < out.streamId) {
-
+                        // TODO
                     }
-                    SpdyFrame oframe = out;
                     try {
-                        if (!oframe.c) {
+                        if (!out.c) {
                             // late: IDs are assigned as we send ( priorities may affect
                             // the transmission order )
-                            if (oframe.stream != null) {
-                                oframe.streamId = oframe.stream.getRequest().streamId;
+                            if (out.stream != null) {
+                                out.streamId = out.stream.getRequest().streamId;
                             }
-                        } else if (oframe.type == TYPE_SYN_STREAM) {
-                            oframe.fixNV(18);
+                        } else if (out.type == TYPE_SYN_STREAM) {
+                            out.fixNV(18);
                             if (compressSupport != null) {
-                                compressSupport.compress(oframe, 18);
+                                compressSupport.compress(out, 18);
                             }
-                        } else if (oframe.type == TYPE_SYN_REPLY
-                                || oframe.type == TYPE_HEADERS) {
-                            oframe.fixNV(14);
+                        } else if (out.type == TYPE_SYN_REPLY
+                                || out.type == TYPE_HEADERS) {
+                            out.fixNV(14);
                             if (compressSupport != null) {
-                                compressSupport.compress(oframe, 14);
+                                compressSupport.compress(out, 14);
                             }
                         }
                     } catch (IOException ex) {
                         abort("Compress error");
                         return false;
                     }
-                    if (oframe.type == TYPE_SYN_STREAM) {
-                        oframe.streamId = outStreamId;
+                    if (out.type == TYPE_SYN_STREAM) {
+                        out.streamId = outStreamId;
                         outStreamId += 2;
                         synchronized(channels) {
-                            channels.put(oframe.streamId, oframe.stream);
+                            channels.put(out.streamId, out.stream);
                         }
                     }
 
-                    oframe.serializeHead();
+                    out.serializeHead();
 
                 }
                 if (out.endData == out.off) {
                     out = null;
                     continue;
                 }
-            } finally {
-                framerLock.unlock();
             }
 
             if (SpdyContext.debug) {
@@ -292,13 +283,6 @@ public abstract class SpdyConnection { /
                         toWrite -= wr;
                     }
                 }
-                // Frame was sent
-                framerLock.lock();
-                try {
-                    outCondition.signalAll();
-                } finally {
-                    framerLock.unlock();
-                }
 
                 synchronized (channels) {
                     if (out.stream != null) {
@@ -325,8 +309,9 @@ public abstract class SpdyConnection { /
      *
      * With a nb transport it should call drain directly.
      */
-    public void nonBlockingDrain() {
-        // TODO: if (nonBlocking()) { drain() }
+    public void nonBlockingSend(SpdyFrame oframe, SpdyStream proc) 
+            throws IOException {
+        queueFrame(oframe, proc, oframe.pri == 0 ? outQueue : prioriyQueue);
         getSpdyContext().getExecutor().execute(nbDrain);
     }
 
@@ -339,6 +324,10 @@ public abstract class SpdyConnection { /
         }
     };
 
+    /**
+     * Add the frame to the queue and send until the queue is empty.
+     * 
+     */
     public void send(SpdyFrame oframe, SpdyStream proc)
             throws IOException {
         queueFrame(oframe, proc, oframe.pri == 0 ? outQueue : prioriyQueue);
@@ -346,7 +335,7 @@ public abstract class SpdyConnection { /
     }
 
     private void queueFrame(SpdyFrame oframe, SpdyStream proc,
-            LinkedList<SpdyFrame> outQueue) throws IOException {
+            LinkedList<SpdyFrame> queue) throws IOException {
 
         oframe.endData = oframe.off;
         oframe.off = 0;
@@ -354,12 +343,9 @@ public abstract class SpdyConnection { /
         // we can't compress either - it's stateful.
         oframe.stream = proc;
 
-        framerLock.lock();
-        try {
-            outQueue.add(oframe);
-            outCondition.signalAll();
-        } finally {
-            framerLock.unlock();
+        // all sync for adding/removing is on outQueue
+        synchronized (outQueue) {
+            queue.add(oframe);            
         }
     }
 
@@ -555,8 +541,10 @@ public abstract class SpdyConnection { /
     }
 
     /**
-     * Process a SPDY connection. Called in a separate thread.
+     * Process a SPDY connection. Called in the input thread, should not 
+     * block.
      *
+     * @return
      * @throws IOException
      */
     protected int handleFrame() throws IOException {
@@ -569,8 +557,8 @@ public abstract class SpdyConnection { /
                     int id = inFrame.read24();
                     int value = inFrame.readInt();
                 }
+                // TODO: save/interpret settings
                 break;
-                // receivedHello = currentInFrame;
             }
             case TYPE_GOAWAY: {
                 int lastStream = inFrame.readInt();
@@ -585,24 +573,22 @@ public abstract class SpdyConnection { /
             case TYPE_RST_STREAM: {
                 inFrame.streamId = inFrame.read32();
                 int errCode = inFrame.read32();
-                trace("> RST "
-                        + inFrame.streamId
-                        + " "
-                        + ((errCode < RST_ERRORS.length) ? RST_ERRORS[errCode]
-                                : errCode));
+                if (SpdyContext.debug) {
+                    trace("> RST "
+                            + inFrame.streamId
+                            + " "
+                            + ((errCode < RST_ERRORS.length) ? RST_ERRORS[errCode]
+                                    : errCode));
+                }
                 SpdyStream sch;
                 synchronized(channels) {
-                        sch = channels.get(inFrame.streamId);
+                        sch = channels.remove(inFrame.streamId);
                 }
-                if (sch == null) {
-                    abort("Missing channel " + inFrame.streamId);
-                    return CLOSE;
+                // if RST stream is for a closed channel - we can ignore.
+                if (sch != null) {
+                    sch.onReset();
                 }
-                sch.onCtlFrame(inFrame);
 
-                synchronized(channels) {
-                    channels.remove(inFrame.streamId);
-                }
                 inFrame = null;
                 break;
             }
@@ -622,7 +608,7 @@ public abstract class SpdyConnection { /
                     abort("Error reading headers " + t);
                     return CLOSE;
                 }
-                spdyContext.onSynStream(this, ch);
+                spdyContext.onStream(this, ch);
                 break;
             }
             case TYPE_SYN_REPLY: {
@@ -697,7 +683,7 @@ public abstract class SpdyConnection { /
      * balancer and tomcat) there is no need for the compression overhead. There
      * are also multiple possible implementations.
      */
-    public static interface CompressSupport {
+    static interface CompressSupport {
         public void compress(SpdyFrame frame, int start) throws IOException;
 
         public void decompress(SpdyFrame frame, int start) throws IOException;

Modified: tomcat/trunk/java/org/apache/tomcat/spdy/SpdyContext.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/spdy/SpdyContext.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/spdy/SpdyContext.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/spdy/SpdyContext.java Thu Mar 29 04:40:43 2012
@@ -33,7 +33,7 @@ import java.util.concurrent.Executors;
  * handles SSL and compression. Test with: --user-data-dir=/tmp/test
  * --use-spdy=no-compress,no-ssl
  */
-public class SpdyContext {
+public final class SpdyContext {
 
     public static final byte[] SPDY_NPN;
 
@@ -52,7 +52,45 @@ public class SpdyContext {
     public static boolean debug = false;
 
     protected boolean tls = true;
-    protected boolean compression = false;
+    protected boolean compression = true;
+
+    private NetSupport netSupport;
+
+
+    public static abstract class NetSupport {
+        protected SpdyContext ctx;
+        
+        public void setSpdyContext(SpdyContext ctx) {
+            this.ctx = ctx;
+        }
+        
+        public abstract SpdyConnection getConnection(String host, int port) throws IOException;
+
+        public void onCreateEngine(Object engine) {
+        }
+
+        public boolean isSpdy(Object socketW) {
+            return false;
+        }
+
+        public void onAccept(Object socket) throws IOException {
+        }
+
+        public void listen(int port, String cert, String key)
+                throws IOException {
+        }
+
+        public void stop() throws IOException {
+        }
+    }
+    
+    public SpdyContext() {
+    }
+    
+    public void setTlsComprression(boolean tls, boolean compress) {
+        this.tls = tls;
+        this.compression = compress;
+    }
 
     /**
      * Get a frame - frames are heavy buffers, may be reused.
@@ -89,6 +127,37 @@ public class SpdyContext {
         this.executor = executor;
     }
 
+    public void setNetSupport(NetSupport netSupport) {
+        this.netSupport = netSupport;
+        netSupport.setSpdyContext(this);
+    }
+
+    public NetSupport getNetSupport() {
+        if (netSupport == null) {
+            try {
+                Class<?> c0 = Class.forName("org.apache.tomcat.spdy.NetSupportOpenSSL");
+                netSupport = (NetSupport) c0.newInstance();
+                netSupport.setSpdyContext(this);
+                return netSupport;
+            } catch (Throwable t) {
+                // ignore, openssl not supported
+            }
+            try {
+                Class<?> c1 = Class.forName("org.apache.tomcat.spdy.NetSupportJava7");
+                netSupport = (NetSupport) c1.newInstance();
+                netSupport.setSpdyContext(this);
+                return netSupport;
+            } catch (Throwable t) {
+                // ignore, npn not supported
+            }
+            // non-ssl mode must be set explicitly
+            throw new RuntimeException("SSL NextProtoclNegotiation no supported.");
+        }
+        
+        return netSupport;
+    }
+    
+    
     /**
      * SPDY is a multiplexed protocol - the SpdyProcessors will be executed on
      * this executor.
@@ -103,31 +172,58 @@ public class SpdyContext {
         return executor;
     }
 
+    SpdyHandler handler;
+    
+    public SpdyHandler getHandler() {
+        return handler;
+    }
+
+    public void setHandler(SpdyHandler handler) {
+        this.handler = handler;
+    }
+
+    public static interface SpdyHandler {
+        public void onStream(SpdyConnection spdyCon, SpdyStream ch) throws IOException;
+        
+    }
+
     /**
-     * Override for servers.
-     * @throws IOException
+     * A handler implementing this interface will be called in the 'io' thread - the
+     * thread reading the multiplexed stream, and in the case of non-blocking 
+     * transports also handling polling the socket.
+     *  
      */
-    protected void onSynStream(SpdyConnection spdyCon, SpdyStream ch) throws IOException {
+    public static interface NonBlockingSpdyHandler extends SpdyHandler {
     }
+    
 
     /**
      * Client mode: return a connection for host/port.
      * @throws IOException
      */
     public SpdyConnection getConnection(String host, int port) throws IOException {
-        return null;
+        return netSupport.getConnection(host, port);
     }
 
     public void releaseConnection(SpdyConnection con) {
     }
 
-    public void listen(final int port, String cert, String key) throws IOException {
-        throw new IOException("Not implemented");
+    public final void listen(final int port, String cert, String key) throws IOException {
+        netSupport.listen(port, cert, key);
     }
 
     /**
      * Close all pending connections and free resources.
      */
-    public void stop() throws IOException {
+    public final void stop() throws IOException {
+        netSupport.stop();
+    }
+
+    public void onStream(SpdyConnection spdyConnection, SpdyStream ch) throws IOException {
+        if (handler instanceof NonBlockingSpdyHandler) {
+            handler.onStream(spdyConnection, ch);
+        } else if (handler instanceof SpdyHandler) {
+            getExecutor().execute(ch);
+        }
     }
 }

Modified: tomcat/trunk/java/org/apache/tomcat/spdy/SpdyFrame.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/spdy/SpdyFrame.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/spdy/SpdyFrame.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/spdy/SpdyFrame.java Thu Mar 29 04:40:43 2012
@@ -350,4 +350,5 @@ public class SpdyFrame {
     public boolean isData() {
         return !c;
     }
+    
 }

Modified: tomcat/trunk/java/org/apache/tomcat/spdy/SpdyStream.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/spdy/SpdyStream.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/spdy/SpdyStream.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/spdy/SpdyStream.java Thu Mar 29 04:40:43 2012
@@ -17,6 +17,7 @@
 package org.apache.tomcat.spdy;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.nio.charset.Charset;
 import java.util.Map;
@@ -37,7 +38,7 @@ import java.util.concurrent.TimeUnit;
  * The frame must be either consumed or popInFrame must be called, after the
  * call is done the frame will be reused.
  */
-public class SpdyStream {
+public class SpdyStream implements Runnable {
     public static final Charset UTF8 = Charset.forName("UTF-8");
 
     protected SpdyConnection spdy;
@@ -84,9 +85,6 @@ public class SpdyStream {
 
     /**
      * Non-blocking, called when a data frame is received.
-     *
-     * The processor must consume the data, or set frame.data to null or a fresh
-     * buffer ( to avoid a copy ).
      */
     public void onDataFrame(SpdyFrame inFrame) {
         synchronized(this) {
@@ -110,8 +108,6 @@ public class SpdyStream {
             reqFrame = frame;
         } else if (frame.type == SpdyConnection.TYPE_SYN_REPLY) {
             resFrame = frame;
-        } else if (frame.type == SpdyConnection.TYPE_RST_STREAM) {
-            onReset();
         }
         synchronized (this) {
             inData.add(frame);
@@ -142,7 +138,7 @@ public class SpdyStream {
     }
 
     /**
-     * Waits and return the next data frame.
+     * Waits and return the next data frame, null on timeout.
      */
     public SpdyFrame getDataFrame(long to) throws IOException {
         while (true) {
@@ -150,27 +146,29 @@ public class SpdyStream {
             if (res == null || res.isData()) {
                 return res;
             }
+            if (res.type == SpdyConnection.TYPE_RST_STREAM) {
+                throw new IOException("Reset");
+            }
         }
     }
 
     /**
-     * Waits and return the next frame. First frame will be the control frame
+     * Waits and return the next frame. 
+     * 
+     * First frame will be the control frame
      */
     public SpdyFrame getFrame(long to) throws IOException {
         SpdyFrame in;
         try {
             synchronized (this) {
                 if (inData.size() == 0 && finRcvd) {
-                    return null;
+                    return END_FRAME;
                 }
             }
             in = inData.poll(to, TimeUnit.MILLISECONDS);
-            if (in == END_FRAME) {
-                return null;
-            }
             return in;
         } catch (InterruptedException e) {
-            throw new IOException(e);
+            return null;
         }
     }
 
@@ -250,5 +248,64 @@ public class SpdyStream {
         spdy.send(reqFrame, this);
     }
 
+    @Override
+    public void run() {
+        try {
+            spdy.spdyContext.handler.onStream(spdy, this);
+        } catch (IOException e) {
+            e.printStackTrace();
+            // TODO: send rst, error processing the stream.
+        }
+    }
+
+
+    public InputStream getInputStream() {
+        return new SpdyInputStream();
+    }
+    
+    class SpdyInputStream extends InputStream {
+        SpdyFrame current = null;
+        long to = 10000; // TODO
+        int pos = 0;
 
+        private void fill() throws IOException {
+            if (current == null || current.off == current.endData) {
+                if (current != null) {
+                    spdy.spdyContext.releaseFrame(current);
+                }
+                current = getFrame(to);
+            }
+        }
+        
+        @Override
+        public int read() throws IOException {
+            fill();
+            if (current == null) {
+                return -1;
+            }
+            return current.readByte();
+        }
+        
+        public int read(byte b[], int off, int len) throws IOException {
+            fill();
+            if (current == null) {
+                return -1;
+            }
+            // don't wait for next frame
+            int rd = Math.min(len, current.endData - current.off);
+            System.arraycopy(current.data, current.off, b, off, rd);
+            current.off += rd;
+            return rd;
+        }
+     
+        public int available() throws IOException {
+            return 0;
+        }
+        public void close() throws IOException {
+            // send RST if not closed
+        }
+        
+        
+        
+    }
 }

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java Thu Mar 29 04:40:43 2012
@@ -128,6 +128,7 @@ public class JIoEndpoint extends Abstrac
         public SocketState process(SocketWrapper<Socket> socket,
                 SocketStatus status);
         public SSLImplementation getSslImplementation();
+        public void beforeHandshake(SocketWrapper<Socket> socket);        
     }
 
 
@@ -289,7 +290,7 @@ public class JIoEndpoint extends Abstrac
             synchronized (socket) {
                 try {
                     SocketState state = SocketState.OPEN;
-
+                    handler.beforeHandshake(socket);
                     try {
                         // SSL handshake
                         serverSocketFactory.handshake(socket.getSocket());

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=1306715&r1=1306714&r2=1306715&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Thu Mar 29 04:40:43 2012
@@ -703,6 +703,7 @@ public class NioEndpoint extends Abstrac
         if ( getCiphersArray().length > 0 ) engine.setEnabledCipherSuites(getCiphersArray());
         if ( getSslEnabledProtocolsArray().length > 0 ) engine.setEnabledProtocols(getSslEnabledProtocolsArray());
 
+        handler.onCreateSSLEngine(engine);
         return engine;
     }
 
@@ -1573,6 +1574,7 @@ public class NioEndpoint extends Abstrac
         public void release(SocketWrapper<NioChannel> socket);
         public void release(SocketChannel socket);
         public SSLImplementation getSslImplementation();
+        public void onCreateSSLEngine(SSLEngine engine);
     }
 
 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org