Author: remm
Date: Mon Apr 13 17:22:05 2015
New Revision: 1673242

URL: http://svn.apache.org/r1673242
Log:
- Cleanup and simplify NIO2 SSL code.
- Use the scatter/gather variants of SSL engine.
- Remove the loop for the gather write (since the non SSL code will not always 
write everything, this doesn't have to either).

Modified:
    tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java?rev=1673242&r1=1673241&r2=1673242&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java 
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java Mon Apr 
13 17:22:05 2015
@@ -552,7 +552,7 @@ public class SecureNio2Channel extends N
     private class FutureRead implements Future<Integer> {
         private final ByteBuffer dst;
         private final Future<Integer> integer;
-        public FutureRead(ByteBuffer dst) {
+        private FutureRead(ByteBuffer dst) {
             this.dst = dst;
             this.integer = sc.read(netInBuffer);
         }
@@ -656,17 +656,17 @@ public class SecureNio2Channel extends N
     }
 
     private class FutureWrite implements Future<Integer> {
-        private ByteBuffer src;
+        private final ByteBuffer src;
         private Future<Integer> integer = null;
         private int written = 0;
         private Throwable t = null;
-        protected FutureWrite(ByteBuffer src) {
+        private FutureWrite(ByteBuffer src) {
+            this.src = src;
             //are we closing or closed?
             if (closing || closed) {
                 t = new IOException(sm.getString("channel.nio.ssl.closing"));
                 return;
             }
-            this.src = src;
             wrap();
         }
         @Override
@@ -755,71 +755,10 @@ public class SecureNio2Channel extends N
         return new FutureWrite(src);
     }
 
-    private class ReadCompletionHandler<A> implements 
CompletionHandler<Integer, A> {
-        protected ByteBuffer dst;
-        protected CompletionHandler<Integer, ? super A> handler;
-        protected ReadCompletionHandler(ByteBuffer dst, 
CompletionHandler<Integer, ? super A> handler) {
-            this.dst = dst;
-            this.handler = handler;
-        }
-
-        @Override
-        public void completed(Integer nBytes, A attach) {
-            if (nBytes.intValue() < 0) {
-                failed(new EOFException(), attach);
-            } else {
-                try {
-                    //the data read
-                    int read = 0;
-                    //the SSL engine result
-                    SSLEngineResult unwrap;
-                    do {
-                        //prepare the buffer
-                        netInBuffer.flip();
-                        //unwrap the data
-                        unwrap = sslEngine.unwrap(netInBuffer, dst);
-                        //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();
-                            //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 && read > 0) {
-                            //buffer overflow can happen, if we have read 
data, then
-                            //empty out the dst buffer before we do another 
read
-                            break;
-                        } else {
-                            //here we should trap BUFFER_OVERFLOW and call 
expand on the buffer
-                            //for now, throw an exception, as we initialized 
the buffers
-                            //in the constructor
-                            throw new 
IOException(sm.getString("channel.nio.ssl.unwrapFail", unwrap.getStatus()));
-                        }
-                    } while ((netInBuffer.position() != 0)); //continue to 
unwrapping as long as the input buffer has stuff
-                    // If everything is OK, so complete
-                    readPending = false;
-                    handler.completed(Integer.valueOf(read), attach);
-                } catch (Exception e) {
-                    failed(e, attach);
-                }
-            }
-        }
-        @Override
-        public void failed(Throwable exc, A attach) {
-            readPending = false;
-            handler.failed(exc, attach);
-        }
-    }
-
     @Override
     public <A> void read(final ByteBuffer dst,
             long timeout, TimeUnit unit, final A attachment,
-            final CompletionHandler<Integer, ? super A> handler) {
+            CompletionHandler<Integer, ? super A> handler) {
         // Check state
         if (closing || closed) {
             handler.completed(Integer.valueOf(-1), attachment);
@@ -833,14 +772,65 @@ public class SecureNio2Channel extends N
         } else {
             readPending = true;
         }
-        sc.read(netInBuffer, timeout, unit, attachment, new 
ReadCompletionHandler<>(dst, handler));
+        sc.read(netInBuffer, timeout, unit, attachment, new 
CompletionHandler<Integer, A>() {
+            @Override
+            public void completed(Integer nBytes, A attach) {
+                if (nBytes.intValue() < 0) {
+                    failed(new EOFException(), attach);
+                } else {
+                    try {
+                        //the data read
+                        int read = 0;
+                        //the SSL engine result
+                        SSLEngineResult unwrap;
+                        do {
+                            //prepare the buffer
+                            netInBuffer.flip();
+                            //unwrap the data
+                            unwrap = sslEngine.unwrap(netInBuffer, dst);
+                            //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();
+                                //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 && read > 0) {
+                                //buffer overflow can happen, if we have read 
data, then
+                                //empty out the dst buffer before we do 
another read
+                                break;
+                            } else {
+                                //here we should trap BUFFER_OVERFLOW and call 
expand on the buffer
+                                //for now, throw an exception, as we 
initialized the buffers
+                                //in the constructor
+                                throw new 
IOException(sm.getString("channel.nio.ssl.unwrapFail", unwrap.getStatus()));
+                            }
+                        } while ((netInBuffer.position() != 0)); //continue to 
unwrapping as long as the input buffer has stuff
+                        // If everything is OK, so complete
+                        readPending = false;
+                        handler.completed(Integer.valueOf(read), attach);
+                    } catch (Exception e) {
+                        failed(e, attach);
+                    }
+                }
+            }
+            @Override
+            public void failed(Throwable exc, A attach) {
+                readPending = false;
+                handler.failed(exc, attach);
+            }
+        });
     }
 
-    // TODO: Possible optimization for scatter
     @Override
     public <A> void read(ByteBuffer[] dsts, int offset, int length,
             long timeout, TimeUnit unit, A attachment,
-            final CompletionHandler<Long, ? super A> handler) {
+            CompletionHandler<Long, ? super A> handler) {
         if (offset < 0 || dsts == null || (offset + length) > dsts.length) {
             throw new IllegalArgumentException();
         }
@@ -855,22 +845,65 @@ public class SecureNio2Channel extends N
         if (dst == null) {
             throw new IllegalArgumentException();
         }
-        CompletionHandler<Integer, ? super A> handlerWrapper = new 
CompletionHandler<Integer, A>() {
+        sc.read(netInBuffer, timeout, unit, attachment, new 
CompletionHandler<Integer, A>() {
             @Override
-            public void completed(Integer result, A attachment) {
-                handler.completed(Long.valueOf(result.longValue()), 
attachment);
+            public void completed(Integer nBytes, A attach) {
+                if (nBytes.intValue() < 0) {
+                    failed(new EOFException(), attach);
+                } else {
+                    try {
+                        //the data read
+                        long read = 0;
+                        //the SSL engine result
+                        SSLEngineResult unwrap;
+                        do {
+                            //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();
+                                //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 && read > 0) {
+                                //buffer overflow can happen, if we have read 
data, then
+                                //empty out the dst buffer before we do 
another read
+                                break;
+                            } else {
+                                //here we should trap BUFFER_OVERFLOW and call 
expand on the buffer
+                                //for now, throw an exception, as we 
initialized the buffers
+                                //in the constructor
+                                throw new 
IOException(sm.getString("channel.nio.ssl.unwrapFail", unwrap.getStatus()));
+                            }
+                        } while ((netInBuffer.position() != 0)); //continue to 
unwrapping as long as the input buffer has stuff
+                        // If everything is OK, so complete
+                        readPending = false;
+                        handler.completed(Long.valueOf(read), attach);
+                    } catch (Exception e) {
+                        failed(e, attach);
+                    }
+                }
             }
             @Override
-            public void failed(Throwable exc, A attachment) {
-                handler.failed(exc, attachment);
+            public void failed(Throwable exc, A attach) {
+                readPending = false;
+                handler.failed(exc, attach);
             }
-        };
-        read(dst, timeout, unit, attachment, handlerWrapper);
+        });
+
     }
 
     @Override
-    public <A> void write(final ByteBuffer src, final long timeout, final 
TimeUnit unit,
-            final A attachment, final CompletionHandler<Integer, ? super A> 
handler) {
+    public <A> void write(ByteBuffer src, long timeout, TimeUnit unit,
+            A attachment, CompletionHandler<Integer, ? super A> handler) {
         // Check state
         if (closing || closed) {
             handler.failed(new 
IOException(sm.getString("channel.nio.ssl.closing")), attachment);
@@ -928,80 +961,6 @@ public class SecureNio2Channel extends N
         }
     }
 
-    private class GatherState<A> {
-        public ByteBuffer[] srcs;
-        public int offset;
-        public int length;
-        public A attachment;
-        public long timeout;
-        public TimeUnit unit;
-        public CompletionHandler<Long, ? super A> handler;
-        protected GatherState(ByteBuffer[] srcs, int offset, int length,
-                long timeout, TimeUnit unit, A attachment,
-                CompletionHandler<Long, ? super A> handler) {
-            this.srcs = srcs;
-            this.offset = offset;
-            this.length = length;
-            this.timeout = timeout;
-            this.unit = unit;
-            this.attachment = attachment;
-            this.handler = handler;
-            this.pos = offset;
-        }
-        public long writeCount = 0;
-        public int pos;
-    }
-
-    private class GatherCompletionHandler<A> implements 
CompletionHandler<Integer, GatherState<A>> {
-        protected GatherState<A> state;
-        protected GatherCompletionHandler(GatherState<A> state) {
-            this.state = state;
-        }
-        @Override
-        public void completed(Integer nBytes, GatherState<A> attachment) {
-            if (nBytes.intValue() < 0) {
-                failed(new EOFException(), attachment);
-            } else {
-                if (state.pos == state.offset + state.length) {
-                    writePending = false;
-                    state.handler.completed(Long.valueOf(state.writeCount), 
state.attachment);
-                } else if (netOutBuffer.hasRemaining()) {
-                    sc.write(netOutBuffer, state.timeout, state.unit, state, 
this);
-                } else {
-                    try {
-                        // Prepare the output buffer
-                        netOutBuffer.clear();
-                        // Wrap the source data into the internal buffer
-                        SSLEngineResult result = 
sslEngine.wrap(state.srcs[state.pos], netOutBuffer);
-                        int written = result.bytesConsumed();
-                        state.writeCount += written;
-                        netOutBuffer.flip();
-                        if (result.getStatus() == Status.OK) {
-                            if (result.getHandshakeStatus() == 
HandshakeStatus.NEED_TASK) {
-                                tasks();
-                            }
-                            if (!state.srcs[state.pos].hasRemaining()) {
-                                state.pos++;
-                            }
-                            // Write data to the channel
-                            sc.write(netOutBuffer, state.timeout, state.unit, 
state, this);
-                        } else {
-                            throw new 
IOException(sm.getString("channel.nio.ssl.wrapFail", result.getStatus()));
-                        }
-                    } catch (Exception e) {
-                        failed(e, attachment);
-                    }
-                }
-            }
-        }
-        @Override
-        public void failed(Throwable exc, GatherState<A> attachment) {
-            writePending = false;
-            state.handler.failed(exc, state.attachment);
-        }
-    }
-
-    // TODO: Possible optimization for gather
     @Override
     public <A> void write(ByteBuffer[] srcs, int offset, int length,
             long timeout, TimeUnit unit, A attachment,
@@ -1020,23 +979,41 @@ public class SecureNio2Channel extends N
             writePending = true;
         }
         try {
-            GatherState<A> state = new GatherState<>(srcs, offset, length,
-                    timeout, unit, attachment, handler);
-            // Prepare the output buffer
+             // Prepare the output buffer
             netOutBuffer.clear();
             // Wrap the source data into the internal buffer
-            SSLEngineResult result = sslEngine.wrap(srcs[offset], 
netOutBuffer);
-            state.writeCount += result.bytesConsumed();
+            SSLEngineResult result = sslEngine.wrap(srcs, offset, length, 
netOutBuffer);
+            final int written = result.bytesConsumed();
             netOutBuffer.flip();
             if (result.getStatus() == Status.OK) {
                 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
                     tasks();
                 }
-                if (!srcs[offset].hasRemaining()) {
-                    state.pos++;
-                }
                 // Write data to the channel
-                sc.write(netOutBuffer, timeout, unit, state, new 
GatherCompletionHandler<>(state));
+                sc.write(netOutBuffer, timeout, unit, attachment, new 
CompletionHandler<Integer, A>() {
+                    @Override
+                    public void completed(Integer nBytes, A attach) {
+                        if (nBytes.intValue() < 0) {
+                            failed(new EOFException(), attach);
+                        } else if (netOutBuffer.hasRemaining()) {
+                            sc.write(netOutBuffer, timeout, unit, attachment, 
this);
+                        } else if (written == 0) {
+                            // Special case, start over to avoid code 
duplication
+                            writePending = false;
+                            write(srcs, offset, length, timeout, unit, 
attachment, handler);
+                        } else {
+                            // Call the handler completed method with the
+                            // consumed bytes number
+                            writePending = false;
+                            handler.completed(Long.valueOf(written), attach);
+                        }
+                    }
+                    @Override
+                    public void failed(Throwable exc, A attach) {
+                        writePending = false;
+                        handler.failed(exc, attach);
+                    }
+                });
             } else {
                 throw new IOException(sm.getString("channel.nio.ssl.wrapFail", 
result.getStatus()));
             }



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

Reply via email to