This is an automated email from the ASF dual-hosted git repository.

remm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/master by this push:
     new d58aa08  Add vectoring for NIO
d58aa08 is described below

commit d58aa0849f6eda19720af61082f8b12254e841bb
Author: remm <r...@apache.org>
AuthorDate: Wed Apr 10 16:28:13 2019 +0200

    Add vectoring for NIO
    
    This is done by adding the ScatteringByteChannel and
    GatheringByteChannel in the main NioChannel. The read SSL code is the
    most complex portion and is based on the latest version of the NIO2
    channel.
---
 java/org/apache/tomcat/util/net/NioChannel.java    |  28 +++-
 .../apache/tomcat/util/net/SecureNioChannel.java   | 146 ++++++++++++++++++++-
 webapps/docs/changelog.xml                         |   7 +
 3 files changed, 176 insertions(+), 5 deletions(-)

diff --git a/java/org/apache/tomcat/util/net/NioChannel.java 
b/java/org/apache/tomcat/util/net/NioChannel.java
index 34a70f5..4bc865c 100644
--- a/java/org/apache/tomcat/util/net/NioChannel.java
+++ b/java/org/apache/tomcat/util/net/NioChannel.java
@@ -19,6 +19,8 @@ package org.apache.tomcat.util.net;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.ByteChannel;
+import java.nio.channels.GatheringByteChannel;
+import java.nio.channels.ScatteringByteChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.SocketChannel;
@@ -33,7 +35,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @version 1.0
  */
-public class NioChannel implements ByteChannel {
+public class NioChannel implements ByteChannel, ScatteringByteChannel, 
GatheringByteChannel {
 
     protected static final StringManager sm = 
StringManager.getManager(NioChannel.class);
 
@@ -134,6 +136,18 @@ public class NioChannel implements ByteChannel {
         return sc.write(src);
     }
 
+    @Override
+    public long write(ByteBuffer[] srcs) throws IOException {
+        return write(srcs, 0, srcs.length);
+    }
+
+    @Override
+    public long write(ByteBuffer[] srcs, int offset, int length)
+            throws IOException {
+        checkInterruptStatus();
+        return sc.write(srcs, offset, length);
+    }
+
     /**
      * Reads a sequence of bytes from this channel into the given buffer.
      *
@@ -147,6 +161,17 @@ public class NioChannel implements ByteChannel {
         return sc.read(dst);
     }
 
+    @Override
+    public long read(ByteBuffer[] dsts) throws IOException {
+        return read(dsts, 0, dsts.length);
+    }
+
+    @Override
+    public long read(ByteBuffer[] dsts, int offset, int length)
+            throws IOException {
+        return sc.read(dsts, offset, length);
+    }
+
     public Object getAttachment() {
         Poller pol = getPoller();
         Selector sel = pol!=null?pol.getSelector():null;
@@ -241,4 +266,5 @@ public class NioChannel implements ByteChannel {
     protected ApplicationBufferHandler getAppReadBufHandler() {
         return appReadBufHandler;
     }
+
 }
diff --git a/java/org/apache/tomcat/util/net/SecureNioChannel.java 
b/java/org/apache/tomcat/util/net/SecureNioChannel.java
index 33bd110..37bcc1f 100644
--- a/java/org/apache/tomcat/util/net/SecureNioChannel.java
+++ b/java/org/apache/tomcat/util/net/SecureNioChannel.java
@@ -43,7 +43,7 @@ import org.apache.tomcat.util.res.StringManager;
 /**
  * Implementation of a secure socket channel
  */
-public class SecureNioChannel extends NioChannel  {
+public class SecureNioChannel extends NioChannel {
 
     private static final Log log = LogFactory.getLog(SecureNioChannel.class);
     private static final StringManager sm = 
StringManager.getManager(SecureNioChannel.class);
@@ -611,9 +611,8 @@ public class SecureNioChannel extends NioChannel  {
                         // This is the normal case for this code
                         
getBufHandler().expand(sslEngine.getSession().getApplicationBufferSize());
                         dst = getBufHandler().getReadBuffer();
-                    } else if (dst == getAppReadBufHandler().getByteBuffer()) {
-                        getAppReadBufHandler()
-                                
.expand(sslEngine.getSession().getApplicationBufferSize());
+                    } else if (getAppReadBufHandler() != null && dst == 
getAppReadBufHandler().getByteBuffer()) {
+                        
getAppReadBufHandler().expand(sslEngine.getSession().getApplicationBufferSize());
                         dst = getAppReadBufHandler().getByteBuffer();
                     } else {
                         // Can't expand the buffer as there is no way to signal
@@ -630,6 +629,111 @@ public class SecureNioChannel extends NioChannel  {
         return read;
     }
 
+    @Override
+    public long read(ByteBuffer[] dsts, int offset, int length)
+            throws IOException {
+        //are we in the middle of closing or closed?
+        if ( closing || closed) return -1;
+        //did we finish our handshake?
+        if (!handshakeComplete) throw new 
IllegalStateException(sm.getString("channel.nio.ssl.incompleteHandshake"));
+
+        //read from the network
+        int netread = sc.read(netInBuffer);
+        //did we reach EOF? if so send EOF up one layer.
+        if (netread == -1) return -1;
+
+        //the data read
+        int read = 0;
+        //the SSL engine result
+        SSLEngineResult unwrap;
+        boolean processOverflow = false;
+        do {
+            boolean useOverflow = false;
+            if (processOverflow) {
+                useOverflow = true;
+            }
+            processOverflow = false;
+            //prepare the buffer
+            netInBuffer.flip();
+            //unwrap the data
+            unwrap = sslEngine.unwrap(netInBuffer, dsts, offset, length);
+            //compact the buffer
+            netInBuffer.compact();
+
+            if (unwrap.getStatus() == Status.OK || unwrap.getStatus() == 
Status.BUFFER_UNDERFLOW) {
+                //we did receive some data, add it to our total
+                read += unwrap.bytesProduced();
+                if (useOverflow) {
+                    // Remove the data read into the overflow buffer
+                    read -= getBufHandler().getReadBuffer().position();
+                }
+                //perform any tasks if needed
+                if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                    tasks();
+                }
+                //if we need more network data, then bail out for now.
+                if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
+                    break;
+                }
+            } else if (unwrap.getStatus() == Status.BUFFER_OVERFLOW) {
+                if (read > 0) {
+                    // Buffer overflow can happen if we have read data. Return
+                    // so the destination buffer can be emptied before another
+                    // read is attempted
+                    break;
+                } else {
+                    ByteBuffer readBuffer = getBufHandler().getReadBuffer();
+                    boolean found = false;
+                    boolean resized = true;
+                    for (int i = 0; i < length; i++) {
+                        // The SSL session has increased the required buffer 
size
+                        // since the buffer was created.
+                        if (dsts[offset + i] == 
getBufHandler().getReadBuffer()) {
+                            
getBufHandler().expand(sslEngine.getSession().getApplicationBufferSize());
+                            if (dsts[offset + i] == 
getBufHandler().getReadBuffer()) {
+                                resized = false;
+                            }
+                            dsts[offset + i] = getBufHandler().getReadBuffer();
+                            found = true;
+                        } else if (getAppReadBufHandler() != null && 
dsts[offset + i] == getAppReadBufHandler().getByteBuffer()) {
+                            
getAppReadBufHandler().expand(sslEngine.getSession().getApplicationBufferSize());
+                            if (dsts[offset + i] == 
getAppReadBufHandler().getByteBuffer()) {
+                                resized = false;
+                            }
+                            dsts[offset + i] = 
getAppReadBufHandler().getByteBuffer();
+                            found = true;
+                        }
+                    }
+                    if (found) {
+                        if (!resized) {
+                            throw new 
IOException(sm.getString("channel.nio.ssl.unwrapFail", unwrap.getStatus()));
+                        }
+                    } else {
+                        // Add the main read buffer in the destinations and 
try again
+                        ByteBuffer[] dsts2 = new ByteBuffer[dsts.length + 1];
+                        int dstOffset = 0;
+                        for (int i = 0; i < dsts.length + 1; i++) {
+                            if (i == offset + length) {
+                                dsts2[i] = readBuffer;
+                                dstOffset = -1;
+                            } else {
+                                dsts2[i] = dsts[i + dstOffset];
+                            }
+                        }
+                        dsts = dsts2;
+                        length++;
+                        getBufHandler().configureReadBufferForWrite();
+                        processOverflow = true;
+                    }
+                }
+            } else {
+                // Something else went wrong
+                throw new 
IOException(sm.getString("channel.nio.ssl.unwrapFail", unwrap.getStatus()));
+            }
+        } while (netInBuffer.position() != 0 || processOverflow); //continue 
to unwrapping as long as the input buffer has stuff
+        return read;
+    }
+
     /**
      * Writes a sequence of bytes to this channel from the given buffer.
      *
@@ -678,6 +782,40 @@ public class SecureNioChannel extends NioChannel  {
     }
 
     @Override
+    public long write(ByteBuffer[] srcs, int offset, int length)
+            throws IOException {
+        checkInterruptStatus();
+        // Are we closing or closed?
+        if (closing || closed) {
+            throw new IOException(sm.getString("channel.nio.ssl.closing"));
+        }
+
+        if (!flush(netOutBuffer)) {
+            // We haven't emptied out the buffer yet
+            return 0;
+        }
+
+        // The data buffer is empty, we can reuse the entire buffer.
+        netOutBuffer.clear();
+
+        SSLEngineResult result = sslEngine.wrap(srcs, offset, length, 
netOutBuffer);
+        // The number of bytes written
+        int written = result.bytesConsumed();
+        netOutBuffer.flip();
+
+        if (result.getStatus() == Status.OK) {
+            if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) 
tasks();
+        } else {
+            throw new IOException(sm.getString("channel.nio.ssl.wrapFail", 
result.getStatus()));
+        }
+
+        // Force a flush
+        flush(netOutBuffer);
+
+        return written;
+    }
+
+    @Override
     public int getOutboundRemaining() {
         return netOutBuffer.remaining();
     }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 40c4f86..7fef23d 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -45,6 +45,13 @@
   issues do not "pop up" wrt. others).
 -->
 <section name="Tomcat 9.0.19 (markt)" rtext="in development">
+  <subsection name="Coyote">
+    <changelog>
+      <update>
+        Add vectoring for NIO in the base and SSL channels. (remm)
+      </update>
+    </changelog>
+  </subsection>
 </section>
 <section name="Tomcat 9.0.18 (markt)" rtext="release in progress">
   <subsection name="Catalina">


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

Reply via email to