Author: markt Date: Thu Jan 15 09:21:17 2015 New Revision: 1652003 URL: http://svn.apache.org/r1652003 Log: InputBuffer refactoring. All compiles but not yet tested.
Added: tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java (with props) Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java?rev=1652003&r1=1652002&r2=1652003&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java (original) +++ tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java Thu Jan 15 09:21:17 2015 @@ -80,7 +80,8 @@ public class InternalNioInputBuffer exte wrapper = socketWrapper; - int bufLength = headerBufferSize + wrapper.getSocket().getBufHandler().getReadBuffer().capacity(); + int bufLength = headerBufferSize + + wrapper.getSocket().getBufHandler().getReadBuffer().capacity(); if (buf == null || buf.length < bufLength) { buf = new byte[bufLength]; } Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1652003&r1=1652002&r2=1652003&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Thu Jan 15 09:21:17 2015 @@ -2387,7 +2387,13 @@ public class AprEndpoint extends Abstrac sslOutputBuffer = null; } - socketWriteBuffer = ByteBuffer.allocateDirect(6 * 1500); + socketBufferHandler = new SocketBufferHandler(6 * 1500, 6 * 1500, true); + } + + + @Override + protected void resetSocketBufferHandler(Long socket) { + socketBufferHandler.reset(); } @@ -2571,19 +2577,16 @@ public class AprEndpoint extends Abstrac private void doWriteInternal() throws IOException { - if (!writeBufferFlipped) { - socketWriteBuffer.flip(); - writeBufferFlipped = true; - } - int thisTime; + ByteBuffer socketWriteBuffer = socketBufferHandler.getWriteBuffer(); do { thisTime = 0; if (getEndpoint().isSSLEnabled()) { if (sslOutputBuffer.remaining() == 0) { // Buffer was fully written last time around sslOutputBuffer.clear(); + socketBufferHandler.configureWriteBufferForRead(); transfer(socketWriteBuffer, sslOutputBuffer); sslOutputBuffer.flip(); } else { @@ -2598,9 +2601,9 @@ public class AprEndpoint extends Abstrac sslOutputBuffer.position() + sslWritten); } } else { - thisTime = Socket.sendb(getSocket().longValue(), - socketWriteBuffer, socketWriteBuffer.position(), - socketWriteBuffer.limit() - socketWriteBuffer.position()); + socketBufferHandler.configureWriteBufferForRead(); + thisTime = Socket.sendb(getSocket().longValue(), socketWriteBuffer, + socketWriteBuffer.position(), socketWriteBuffer.remaining()); } if (Status.APR_STATUS_IS_EAGAIN(-thisTime)) { thisTime = 0; @@ -2617,10 +2620,6 @@ public class AprEndpoint extends Abstrac socketWriteBuffer.position(socketWriteBuffer.position() + thisTime); } while ((thisTime > 0 || getBlockingStatus()) && socketWriteBuffer.hasRemaining()); - if (socketWriteBuffer.remaining() == 0) { - socketWriteBuffer.clear(); - writeBufferFlipped = false; - } // If there is data left in the buffer the socket will be registered for // write further up the stack. This is to ensure the socket is only // registered for write once as both container and user code can trigger Modified: tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java?rev=1652003&r1=1652002&r2=1652003&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Channel.java Thu Jan 15 09:21:17 2015 @@ -26,8 +26,6 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.apache.tomcat.util.net.SecureNio2Channel.ApplicationBufferHandler; - /** * Base class for a SocketChannel wrapper used by the endpoint. * This way, logic for a SSL socket channel remains the same as for @@ -39,9 +37,9 @@ public class Nio2Channel implements Asyn protected AsynchronousSocketChannel sc = null; protected SocketWrapperBase<Nio2Channel> socket = null; - protected ApplicationBufferHandler bufHandler; + protected final SocketBufferHandler bufHandler; - public Nio2Channel(ApplicationBufferHandler bufHandler) { + public Nio2Channel(SocketBufferHandler bufHandler) { this.bufHandler = bufHandler; } @@ -96,7 +94,7 @@ public class Nio2Channel implements Asyn return sc.isOpen(); } - public ApplicationBufferHandler getBufHandler() { + public SocketBufferHandler getBufHandler() { return bufHandler; } Modified: tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java?rev=1652003&r1=1652002&r2=1652003&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java Thu Jan 15 09:21:17 2015 @@ -54,7 +54,6 @@ import org.apache.tomcat.util.ExceptionU import org.apache.tomcat.util.buf.ByteBufferHolder; import org.apache.tomcat.util.collections.SynchronizedStack; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; -import org.apache.tomcat.util.net.SecureNio2Channel.ApplicationBufferHandler; import org.apache.tomcat.util.net.jsse.NioX509KeyManager; /** @@ -477,13 +476,13 @@ public class Nio2Endpoint extends Abstra if (sslContext != null) { SSLEngine engine = createSSLEngine(); int appBufferSize = engine.getSession().getApplicationBufferSize(); - NioBufferHandler bufhandler = new NioBufferHandler( + SocketBufferHandler bufhandler = new SocketBufferHandler( Math.max(appBufferSize, socketProperties.getAppReadBufSize()), Math.max(appBufferSize, socketProperties.getAppWriteBufSize()), socketProperties.getDirectBuffer()); channel = new SecureNio2Channel(engine, bufhandler, this); } else { - NioBufferHandler bufhandler = new NioBufferHandler( + SocketBufferHandler bufhandler = new SocketBufferHandler( socketProperties.getAppReadBufSize(), socketProperties.getAppWriteBufSize(), socketProperties.getDirectBuffer()); @@ -818,8 +817,6 @@ public class Nio2Endpoint extends Abstra writeNotify = true; } writePending.release(); - socketWriteBuffer.clear(); - writeBufferFlipped = false; } } if (writeNotify && nestedWriteCompletionCount.get().get() == 0) { @@ -874,8 +871,6 @@ public class Nio2Endpoint extends Abstra writeNotify = true; } writePending.release(); - socketWriteBuffer.clear(); - writeBufferFlipped = false; } } if (writeNotify && nestedWriteCompletionCount.get().get() == 0) { @@ -913,8 +908,16 @@ public class Nio2Endpoint extends Abstra super.reset(channel, soTimeout); upgradeInit = false; sendfileData = null; - // Channel will be null when socket is being closed. - socketWriteBuffer = (channel == null) ? null : channel.getBufHandler().getWriteBuffer(); + } + + + @Override + protected void resetSocketBufferHandler(Nio2Channel socket) { + if (socket == null) { + socketBufferHandler = null; + } else { + socketBufferHandler = socket.getBufHandler(); + } } @Override @@ -1136,7 +1139,8 @@ public class Nio2Endpoint extends Abstra if (writePending.tryAcquire()) { // No pending completion handler, so writing to the main buffer // is possible - int thisTime = transfer(buf, off, len, socketWriteBuffer); + socketBufferHandler.configureWriteBufferForWrite(); + int thisTime = transfer(buf, off, len, socketBufferHandler.getWriteBuffer()); len = len - thisTime; off = off + thisTime; if (len > 0) { @@ -1158,13 +1162,13 @@ public class Nio2Endpoint extends Abstra @Override protected void doWrite(boolean block) throws IOException { try { - socketWriteBuffer.flip(); - while (socketWriteBuffer.hasRemaining()) { - if (getSocket().write(socketWriteBuffer).get(getTimeout(), TimeUnit.MILLISECONDS).intValue() < 0) { + socketBufferHandler.configureWriteBufferForRead(); + while (socketBufferHandler.getWriteBuffer().hasRemaining()) { + if (getSocket().write(socketBufferHandler.getWriteBuffer()).get(getTimeout(), + TimeUnit.MILLISECONDS).intValue() < 0) { throw new EOFException(sm.getString("iob.failedwrite")); } } - socketWriteBuffer.clear(); } catch (ExecutionException e) { if (e.getCause() instanceof IOException) { throw (IOException) e.getCause(); @@ -1204,15 +1208,12 @@ public class Nio2Endpoint extends Abstra private boolean flushNonBlocking(boolean hasPermit) { synchronized (writeCompletionHandler) { if (hasPermit || writePending.tryAcquire()) { - if (!writeBufferFlipped) { - socketWriteBuffer.flip(); - writeBufferFlipped = true; - } + socketBufferHandler.configureWriteBufferForRead(); if (bufferedWrites.size() > 0) { // Gathering write of the main buffer plus all leftovers ArrayList<ByteBuffer> arrayList = new ArrayList<>(); - if (socketWriteBuffer.hasRemaining()) { - arrayList.add(socketWriteBuffer); + if (socketBufferHandler.getWriteBuffer().hasRemaining()) { + arrayList.add(socketBufferHandler.getWriteBuffer()); } for (ByteBufferHolder buffer : bufferedWrites) { buffer.flip(); @@ -1222,15 +1223,14 @@ public class Nio2Endpoint extends Abstra ByteBuffer[] array = arrayList.toArray(new ByteBuffer[arrayList.size()]); getSocket().write(array, 0, array.length, getTimeout(), TimeUnit.MILLISECONDS, array, gatheringWriteCompletionHandler); - } else if (socketWriteBuffer.hasRemaining()) { + } else if (socketBufferHandler.getWriteBuffer().hasRemaining()) { // Regular write - getSocket().write(socketWriteBuffer, getTimeout(), - TimeUnit.MILLISECONDS, socketWriteBuffer, writeCompletionHandler); + getSocket().write(socketBufferHandler.getWriteBuffer(), getTimeout(), + TimeUnit.MILLISECONDS, socketBufferHandler.getWriteBuffer(), + writeCompletionHandler); } else { // Nothing was written writePending.release(); - socketWriteBuffer.clear(); - writeBufferFlipped = false; } } return hasDataToWrite(); @@ -1241,7 +1241,8 @@ public class Nio2Endpoint extends Abstra @Override public boolean hasDataToWrite() { synchronized (writeCompletionHandler) { - return hasMoreDataToFlush() || bufferedWrites.size() > 0 || getError() != null; + return !socketBufferHandler.isWriteBufferEmpty() || + bufferedWrites.size() > 0 || getError() != null; } } @@ -1287,31 +1288,8 @@ public class Nio2Endpoint extends Abstra } - // ------------------------------------------------ Application Buffer Handler - public static class NioBufferHandler implements ApplicationBufferHandler { - private ByteBuffer readbuf = null; - private ByteBuffer writebuf = null; - - public NioBufferHandler(int readsize, int writesize, boolean direct) { - if ( direct ) { - readbuf = ByteBuffer.allocateDirect(readsize); - writebuf = ByteBuffer.allocateDirect(writesize); - }else { - readbuf = ByteBuffer.allocate(readsize); - writebuf = ByteBuffer.allocate(writesize); - } - } - - @Override - public ByteBuffer getReadBuffer() {return readbuf;} - @Override - public ByteBuffer getWriteBuffer() {return writebuf;} - - } - // ------------------------------------------------ Handler Inner Interface - /** * Bare bones interface used for socket processing. Per thread data is to be * stored in the ThreadWithAttributes extra folders, or alternately in Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java?rev=1652003&r1=1652002&r2=1652003&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java Thu Jan 15 09:21:17 2015 @@ -24,7 +24,6 @@ import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import org.apache.tomcat.util.net.NioEndpoint.Poller; -import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler; import org.apache.tomcat.util.res.StringManager; /** @@ -44,13 +43,13 @@ public class NioChannel implements ByteC protected SocketChannel sc = null; - protected ApplicationBufferHandler bufHandler; + protected final SocketBufferHandler bufHandler; protected Poller poller; protected boolean sendFile = false; - public NioChannel(SocketChannel channel, ApplicationBufferHandler bufHandler) { + public NioChannel(SocketChannel channel, SocketBufferHandler bufHandler) { this.sc = channel; this.bufHandler = bufHandler; } @@ -61,19 +60,15 @@ public class NioChannel implements ByteC * @throws IOException If a problem was encountered resetting the channel */ public void reset() throws IOException { - bufHandler.getReadBuffer().clear(); - // TODO AJP and HTTPS have different expectations for the state of - // the buffer at the start of a read. These need to be reconciled. - bufHandler.getReadBuffer().limit(0); - bufHandler.getWriteBuffer().clear(); + bufHandler.reset(); this.sendFile = false; } public int getBufferSize() { if ( bufHandler == null ) return 0; int size = 0; - size += bufHandler.getReadBuffer()!=null?bufHandler.getReadBuffer().capacity():0; - size += bufHandler.getWriteBuffer()!=null?bufHandler.getWriteBuffer().capacity():0; + size += bufHandler.getReadBuffer().capacity(); + size += bufHandler.getWriteBuffer().capacity(); return size; } @@ -151,7 +146,7 @@ public class NioChannel implements ByteC return att; } - public ApplicationBufferHandler getBufHandler() { + public SocketBufferHandler getBufHandler() { return bufHandler; } 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=1652003&r1=1652002&r2=1652003&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Thu Jan 15 09:21:17 2015 @@ -54,7 +54,6 @@ import org.apache.tomcat.util.Introspect import org.apache.tomcat.util.collections.SynchronizedQueue; import org.apache.tomcat.util.collections.SynchronizedStack; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; -import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler; import org.apache.tomcat.util.net.jsse.NioX509KeyManager; /** @@ -512,16 +511,17 @@ public class NioEndpoint extends Abstrac if (sslContext != null) { SSLEngine engine = createSSLEngine(); int appbufsize = engine.getSession().getApplicationBufferSize(); - NioBufferHandler bufhandler = new NioBufferHandler(Math.max(appbufsize,socketProperties.getAppReadBufSize()), - Math.max(appbufsize,socketProperties.getAppWriteBufSize()), - socketProperties.getDirectBuffer()); + SocketBufferHandler bufhandler = new SocketBufferHandler( + Math.max(appbufsize,socketProperties.getAppReadBufSize()), + Math.max(appbufsize,socketProperties.getAppWriteBufSize()), + socketProperties.getDirectBuffer()); channel = new SecureNioChannel(socket, engine, bufhandler, selectorPool); } else { // normal tcp setup - NioBufferHandler bufhandler = new NioBufferHandler(socketProperties.getAppReadBufSize(), - socketProperties.getAppWriteBufSize(), - socketProperties.getDirectBuffer()); - + SocketBufferHandler bufhandler = new SocketBufferHandler( + socketProperties.getAppReadBufSize(), + socketProperties.getAppWriteBufSize(), + socketProperties.getDirectBuffer()); channel = new NioChannel(socket, bufhandler); } } else { @@ -1339,10 +1339,19 @@ public class NioEndpoint extends Abstrac } writeLatch = null; setWriteTimeout(soTimeout); - // Channel will be null when socket is being closed. - socketWriteBuffer = (channel == null) ? null : channel.getBufHandler().getWriteBuffer(); } + + @Override + protected void resetSocketBufferHandler(NioChannel socket) { + if (socket == null) { + socketBufferHandler = null; + } else { + socketBufferHandler = socket.getBufHandler(); + } + } + + public void reset() { reset(null,null,-1); } @@ -1392,17 +1401,16 @@ public class NioEndpoint extends Abstrac @Override public boolean isReady() throws IOException { - ByteBuffer readBuffer = getSocket().getBufHandler().getReadBuffer(); + socketBufferHandler.configureReadBufferForRead(); - if (readBuffer.remaining() > 0) { + if (socketBufferHandler.getReadBuffer().remaining() > 0) { return true; } - readBuffer.clear(); fillReadBuffer(false); - boolean isReady = readBuffer.position() > 0; - readBuffer.flip(); + + boolean isReady = socketBufferHandler.getReadBuffer().position() > 0; return isReady; } @@ -1411,7 +1419,8 @@ public class NioEndpoint extends Abstrac public int read(boolean block, byte[] b, int off, int len) throws IOException { - ByteBuffer readBuffer = getSocket().getBufHandler().getReadBuffer(); + socketBufferHandler.configureReadBufferForRead(); + ByteBuffer readBuffer = socketBufferHandler.getReadBuffer(); int remaining = readBuffer.remaining(); // Is there enough data in the read buffer to satisfy this request? @@ -1430,13 +1439,12 @@ public class NioEndpoint extends Abstrac } // Fill the read buffer as best we can - readBuffer.clear(); int nRead = fillReadBuffer(block); - // Full as much of the remaining byte array as possible with the data - // that was just read + // Full as much of the remaining byte array as possible with the + // data that was just read if (nRead > 0) { - readBuffer.flip(); + socketBufferHandler.configureReadBufferForRead(); if (nRead > leftToWrite) { readBuffer.get(b, newOffset, leftToWrite); leftToWrite = 0; @@ -1444,8 +1452,6 @@ public class NioEndpoint extends Abstrac readBuffer.get(b, newOffset, nRead); leftToWrite -= nRead; } - } else if (nRead == 0) { - readBuffer.flip(); } else if (nRead == -1) { // TODO i18n throw new EOFException(); @@ -1458,14 +1464,8 @@ public class NioEndpoint extends Abstrac @Override public void unRead(ByteBuffer returnedInput) { if (returnedInput != null) { - ByteBuffer readBuffer = getSocket().getBufHandler().getReadBuffer(); - if (readBuffer.remaining() > 0) { - readBuffer.flip(); - } else { - readBuffer.clear(); - } - readBuffer.put(returnedInput); - readBuffer.flip(); + socketBufferHandler.configureReadBufferForWrite(); + socketBufferHandler.getReadBuffer().put(returnedInput); } } @@ -1482,6 +1482,7 @@ public class NioEndpoint extends Abstrac private int fillReadBuffer(boolean block) throws IOException { int nRead; NioChannel channel = getSocket(); + socketBufferHandler.configureReadBufferForWrite(); if (block) { Selector selector = null; try { @@ -1495,7 +1496,7 @@ public class NioEndpoint extends Abstrac if (att == null) { throw new IOException("Key must be cancelled."); } - nRead = pool.read(channel.getBufHandler().getReadBuffer(), + nRead = pool.read(socketBufferHandler.getReadBuffer(), channel, selector, att.getTimeout()); } catch (EOFException eof) { nRead = -1; @@ -1505,7 +1506,7 @@ public class NioEndpoint extends Abstrac } } } else { - nRead = channel.read(channel.getBufHandler().getReadBuffer()); + nRead = channel.read(socketBufferHandler.getReadBuffer()); } return nRead; } @@ -1513,10 +1514,7 @@ public class NioEndpoint extends Abstrac @Override protected synchronized void doWrite(boolean block) throws IOException { - if (!writeBufferFlipped) { - socketWriteBuffer.flip(); - writeBufferFlipped = true; - } + socketBufferHandler.configureWriteBufferForRead(); long writeTimeout = getWriteTimeout(); Selector selector = null; @@ -1526,7 +1524,8 @@ public class NioEndpoint extends Abstrac // Ignore } try { - pool.write(socketWriteBuffer, getSocket(), selector, writeTimeout, block); + pool.write(socketBufferHandler.getWriteBuffer(), getSocket(), + selector, writeTimeout, block); // Make sure we are flushed do { if (getSocket().flush(true, selector, writeTimeout)) break; @@ -1536,10 +1535,6 @@ public class NioEndpoint extends Abstrac pool.put(selector); } } - if (socketWriteBuffer.remaining() == 0) { - socketWriteBuffer.clear(); - writeBufferFlipped = false; - } // If there is data left in the buffer the socket will be registered for // write further up the stack. This is to ensure the socket is only // registered for write once as both container and user code can trigger @@ -1581,33 +1576,8 @@ public class NioEndpoint extends Abstrac } - // ------------------------------------------------ Application Buffer Handler - public static class NioBufferHandler implements ApplicationBufferHandler { - private ByteBuffer readbuf = null; - private ByteBuffer writebuf = null; - - public NioBufferHandler(int readsize, int writesize, boolean direct) { - if (direct) { - readbuf = ByteBuffer.allocateDirect(readsize); - writebuf = ByteBuffer.allocateDirect(writesize); - } else { - readbuf = ByteBuffer.allocate(readsize); - writebuf = ByteBuffer.allocate(writesize); - } - // TODO AJP and HTTPS have different expectations for the state of - // the buffer at the start of a read. These need to be reconciled. - readbuf.limit(0); - } - - @Override - public ByteBuffer getReadBuffer() {return readbuf;} - @Override - public ByteBuffer getWriteBuffer() {return writebuf;} - } - // ------------------------------------------------ Handler Inner Interface - /** * Bare bones interface used for socket processing. Per thread data is to be * stored in the ThreadWithAttributes extra folders, or alternately in 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=1652003&r1=1652002&r2=1652003&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java Thu Jan 15 09:21:17 2015 @@ -61,7 +61,7 @@ public class SecureNio2Channel extends N private CompletionHandler<Integer, SocketWrapperBase<Nio2Channel>> handshakeReadCompletionHandler; private CompletionHandler<Integer, SocketWrapperBase<Nio2Channel>> handshakeWriteCompletionHandler; - public SecureNio2Channel(SSLEngine engine, ApplicationBufferHandler bufHandler, + public SecureNio2Channel(SSLEngine engine, SocketBufferHandler bufHandler, Nio2Endpoint endpoint0) { super(bufHandler); sslEngine = engine; @@ -979,20 +979,6 @@ public class SecureNio2Channel extends N } } - /** - * Callback interface to be able to expand buffers - * when buffer overflow exceptions happen - */ - public static interface ApplicationBufferHandler { - public ByteBuffer getReadBuffer(); - public ByteBuffer getWriteBuffer(); - } - - @Override - public ApplicationBufferHandler getBufHandler() { - return bufHandler; - } - @Override public boolean isHandshakeComplete() { return handshakeComplete; @@ -1011,10 +997,6 @@ public class SecureNio2Channel extends N return emptyBuf; } - public void setBufHandler(ApplicationBufferHandler bufHandler) { - this.bufHandler = bufHandler; - } - @Override public AsynchronousSocketChannel getIOChannel() { return sc; Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java?rev=1652003&r1=1652002&r2=1652003&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Thu Jan 15 09:21:17 2015 @@ -50,8 +50,8 @@ public class SecureNioChannel extends Ni protected NioSelectorPool pool; - public SecureNioChannel(SocketChannel channel, SSLEngine engine, - ApplicationBufferHandler bufHandler, NioSelectorPool pool) throws IOException { + public SecureNioChannel(SocketChannel channel, SSLEngine engine, SocketBufferHandler bufHandler, + NioSelectorPool pool) throws IOException { super(channel,bufHandler); this.sslEngine = engine; int netBufSize = sslEngine.getSession().getPacketBufferSize(); @@ -192,9 +192,7 @@ public class SecureNioChannel extends Ni //read more data, reregister for OP_READ return SelectionKey.OP_READ; } else if (handshake.getStatus() == Status.BUFFER_OVERFLOW) { - // TODO AJP and HTTPS have different expectations for the state of - // the buffer at the start of a read. These need to be reconciled. - bufHandler.getReadBuffer().compact(); + bufHandler.configureReadBufferForWrite(); } else { throw new IOException(sm.getString("channel.nio.ssl.unexpectedStatusDuringWrap", handshakeStatus)); }//switch @@ -225,8 +223,8 @@ public class SecureNioChannel extends Ni //validate the network buffers are empty if (netInBuffer.position() > 0 && netInBuffer.position()<netInBuffer.limit()) throw new IOException(sm.getString("channel.nio.ssl.netInputNotEmpty")); if (netOutBuffer.position() > 0 && netOutBuffer.position()<netOutBuffer.limit()) throw new IOException(sm.getString("channel.nio.ssl.netOutputNotEmpty")); - if (getBufHandler().getReadBuffer().position()>0 && getBufHandler().getReadBuffer().position()<getBufHandler().getReadBuffer().limit()) throw new IOException(sm.getString("channel.nio.ssl.appInputNotEmpty")); - if (getBufHandler().getWriteBuffer().position()>0 && getBufHandler().getWriteBuffer().position()<getBufHandler().getWriteBuffer().limit()) throw new IOException(sm.getString("channel.nio.ssl.appOutputNotEmpty")); + if (!getBufHandler().isReadBufferEmpty()) throw new IOException(sm.getString("channel.nio.ssl.appInputNotEmpty")); + if (!getBufHandler().isWriteBufferEmpty()) throw new IOException(sm.getString("channel.nio.ssl.appOutputNotEmpty")); reset(); boolean isReadable = true; boolean isWriteable = true; @@ -292,6 +290,7 @@ public class SecureNioChannel extends Ni //so we can clear it here. netOutBuffer.clear(); //perform the wrap + bufHandler.configureWriteBufferForWrite(); SSLEngineResult result = sslEngine.wrap(bufHandler.getWriteBuffer(), netOutBuffer); //prepare the results to be written netOutBuffer.flip(); @@ -326,6 +325,7 @@ public class SecureNioChannel extends Ni //prepare the buffer with the incoming data netInBuffer.flip(); //call unwrap + bufHandler.configureReadBufferForWrite(); result = sslEngine.unwrap(netInBuffer, bufHandler.getReadBuffer()); //compact the buffer, this is an optional method, wonder what would happen if we didn't netInBuffer.compact(); @@ -410,8 +410,10 @@ public class SecureNioChannel extends Ni */ @Override public int read(ByteBuffer dst) throws IOException { - //if we want to take advantage of the expand function, make sure we only use the ApplicationBufferHandler's buffers - if ( dst != bufHandler.getReadBuffer() ) throw new IllegalArgumentException(sm.getString("channel.nio.ssl.invalidBuffer")); + // Make sure we only use the ApplicationBufferHandler's buffers + if (dst != bufHandler.getReadBuffer()) { + throw new IllegalArgumentException(sm.getString("channel.nio.ssl.invalidBuffer")); + } //are we in the middle of closing or closed? if ( closing || closed) return -1; //did we finish our handshake? @@ -473,7 +475,9 @@ public class SecureNioChannel extends Ni return written; } else { //make sure we can handle expand, and that we only use one buffer - if ( (!this.isSendFile()) && (src != bufHandler.getWriteBuffer()) ) throw new IllegalArgumentException(sm.getString("channel.nio.ssl.invalidBuffer")); + if (!this.isSendFile() && src != bufHandler.getWriteBuffer()) { + throw new IllegalArgumentException(sm.getString("channel.nio.ssl.invalidBuffer")); + } //are we closing or closed? if ( closing || closed) throw new IOException(sm.getString("channel.nio.ssl.closing")); @@ -531,7 +535,7 @@ public class SecureNioChannel extends Ni } @Override - public ApplicationBufferHandler getBufHandler() { + public SocketBufferHandler getBufHandler() { return bufHandler; } @@ -553,10 +557,6 @@ public class SecureNioChannel extends Ni return emptyBuf; } - public void setBufHandler(ApplicationBufferHandler bufHandler) { - this.bufHandler = bufHandler; - } - @Override public SocketChannel getIOChannel() { return sc; Added: tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java?rev=1652003&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java (added) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java Thu Jan 15 09:21:17 2015 @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.net; + +import java.nio.ByteBuffer; + +public class SocketBufferHandler { + + private volatile boolean readBufferConfiguredForWrite = true; + private final ByteBuffer readBuffer; + + private volatile boolean writeBufferConfiguredForWrite = true; + private final ByteBuffer writeBuffer; + + + public SocketBufferHandler(int readBufferSize, int writeBufferSize, + boolean direct) { + if (direct) { + readBuffer = ByteBuffer.allocateDirect(readBufferSize); + writeBuffer = ByteBuffer.allocateDirect(writeBufferSize); + } else { + readBuffer = ByteBuffer.allocate(readBufferSize); + writeBuffer = ByteBuffer.allocate(writeBufferSize); + } + } + + + public void configureReadBufferForWrite() { + setReadBufferConFiguredForWrite(true); + } + + + public void configureReadBufferForRead() { + setReadBufferConFiguredForWrite(false); + } + + + private void setReadBufferConFiguredForWrite(boolean readBufferConFiguredForWrite) { + // NO-OP if buffer is already in correct state + if (this.readBufferConfiguredForWrite != readBufferConFiguredForWrite) { + if (readBufferConFiguredForWrite) { + // Switching to write + int remaining = readBuffer.remaining(); + if (remaining == 0) { + readBuffer.clear(); + } else { + readBuffer.compact(); + readBuffer.position(remaining); + readBuffer.limit(readBuffer.capacity()); + } + } else { + // Switching to read + readBuffer.flip(); + } + this.readBufferConfiguredForWrite = readBufferConFiguredForWrite; + } + } + + + public ByteBuffer getReadBuffer() { + return readBuffer; + } + + + public boolean isReadBufferEmpty() { + if (readBufferConfiguredForWrite) { + return readBuffer.position() > 0; + } else { + return readBuffer.remaining() > 0; + } + } + + + public void configureWriteBufferForWrite() { + setWriteBufferConfiguredForWrite(true); + } + + + public void configureWriteBufferForRead() { + setWriteBufferConfiguredForWrite(false); + } + + + private void setWriteBufferConfiguredForWrite(boolean writeBufferConfiguredForWrite) { + // NO-OP if buffer is already in correct state + if (this.writeBufferConfiguredForWrite != writeBufferConfiguredForWrite) { + if (writeBufferConfiguredForWrite) { + // Switching to write + int remaining = writeBuffer.remaining(); + if (remaining == 0) { + writeBuffer.clear(); + } else { + writeBuffer.compact(); + writeBuffer.position(remaining); + writeBuffer.limit(writeBuffer.capacity()); + } + } else { + // Switching to read + writeBuffer.flip(); + } + this.writeBufferConfiguredForWrite = writeBufferConfiguredForWrite; + } + } + + + public boolean isWriteBufferWritable() { + if (writeBufferConfiguredForWrite) { + return writeBuffer.hasRemaining(); + } else { + return writeBuffer.remaining() == 0; + } + } + + + public ByteBuffer getWriteBuffer() { + return writeBuffer; + } + + + public boolean isWriteBufferEmpty() { + if (writeBufferConfiguredForWrite) { + return writeBuffer.position() == 0; + } else { + return writeBuffer.remaining() == 0; + } + } + + + public void reset() { + readBuffer.clear(); + readBufferConfiguredForWrite = true; + writeBuffer.clear(); + writeBufferConfiguredForWrite = true; + } +} Propchange: tomcat/trunk/java/org/apache/tomcat/util/net/SocketBufferHandler.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java?rev=1652003&r1=1652002&r2=1652003&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SocketWrapperBase.java Thu Jan 15 09:21:17 2015 @@ -70,8 +70,10 @@ public abstract class SocketWrapperBase< */ private final Object writeThreadLock = new Object(); - protected volatile ByteBuffer socketWriteBuffer; - protected volatile boolean writeBufferFlipped; + /** + * The buffers used for communicating with the socket. + */ + protected volatile SocketBufferHandler socketBufferHandler = null; /** * For "non-blocking" writes use an external set of buffers. Although the @@ -180,13 +182,8 @@ public abstract class SocketWrapperBase< public abstract boolean isReadPending(); - protected boolean hasMoreDataToFlush() { - return (writeBufferFlipped && socketWriteBuffer.remaining() > 0) || - (!writeBufferFlipped && socketWriteBuffer.position() > 0); - } - public boolean hasDataToWrite() { - return hasMoreDataToFlush() || bufferedWrites.size() > 0; + return !socketBufferHandler.isWriteBufferEmpty() || bufferedWrites.size() > 0; } /** @@ -213,8 +210,7 @@ public abstract class SocketWrapperBase< public boolean canWrite() { - return !writeBufferFlipped && socketWriteBuffer.hasRemaining() && - bufferedWrites.size() == 0; + return socketBufferHandler.isWriteBufferWritable() && bufferedWrites.size() == 0; } public void addDispatch(DispatchType dispatchType) { @@ -263,8 +259,11 @@ public abstract class SocketWrapperBase< this.socket = socket; this.timeout = timeout; upgraded = false; + resetSocketBufferHandler(socket); } + protected abstract void resetSocketBufferHandler(E socket); + /** * Overridden for debug purposes. No guarantees are made about the format of * this message which may vary significantly between point releases. @@ -346,12 +345,14 @@ public abstract class SocketWrapperBase< // Keep writing until all the data has been transferred to the socket // write buffer and space remains in that buffer - int thisTime = transfer(buf, off, len, socketWriteBuffer); - while (socketWriteBuffer.remaining() == 0) { + socketBufferHandler.configureWriteBufferForWrite(); + int thisTime = transfer(buf, off, len, socketBufferHandler.getWriteBuffer()); + while (socketBufferHandler.getWriteBuffer().remaining() == 0) { len = len - thisTime; off = off + thisTime; doWrite(true); - thisTime = transfer(buf, off, len, socketWriteBuffer); + socketBufferHandler.configureWriteBufferForWrite(); + thisTime = transfer(buf, off, len, socketBufferHandler.getWriteBuffer()); } } @@ -369,16 +370,18 @@ public abstract class SocketWrapperBase< * @throws IOException If an IO error occurs during the write */ protected void writeNonBlocking(byte[] buf, int off, int len) throws IOException { - if (!writeBufferFlipped) { - int thisTime = transfer(buf, off, len, socketWriteBuffer); + if (bufferedWrites.size() == 0 && socketBufferHandler.isWriteBufferWritable()) { + socketBufferHandler.configureWriteBufferForWrite(); + int thisTime = transfer(buf, off, len, socketBufferHandler.getWriteBuffer()); len = len - thisTime; - while (socketWriteBuffer.remaining() == 0) { + while (!socketBufferHandler.isWriteBufferWritable()) { off = off + thisTime; doWrite(false); - if (writeBufferFlipped) { - thisTime = 0; + if (len > 0 && socketBufferHandler.isWriteBufferWritable()) { + socketBufferHandler.configureWriteBufferForWrite(); + thisTime = transfer(buf, off, len, socketBufferHandler.getWriteBuffer()); } else { - thisTime = transfer(buf, off, len, socketWriteBuffer); + thisTime = 0; } len = len - thisTime; } @@ -432,11 +435,12 @@ public abstract class SocketWrapperBase< if (bufferedWrites.size() > 0) { Iterator<ByteBufferHolder> bufIter = bufferedWrites.iterator(); - while (!hasMoreDataToFlush() && bufIter.hasNext()) { + while (socketBufferHandler.isWriteBufferEmpty() && bufIter.hasNext()) { ByteBufferHolder buffer = bufIter.next(); buffer.flip(); - while (!hasMoreDataToFlush() && buffer.getBuf().remaining()>0) { - transfer(buffer.getBuf(), socketWriteBuffer); + while (socketBufferHandler.isWriteBufferEmpty() && buffer.getBuf().remaining()>0) { + socketBufferHandler.configureWriteBufferForWrite(); + transfer(buffer.getBuf(), socketBufferHandler.getWriteBuffer()); if (buffer.getBuf().remaining() == 0) { bufIter.remove(); } @@ -449,22 +453,23 @@ public abstract class SocketWrapperBase< protected boolean flushNonBlocking() throws IOException { - boolean dataLeft = hasMoreDataToFlush(); + boolean dataLeft = !socketBufferHandler.isWriteBufferEmpty(); // Write to the socket, if there is anything to write if (dataLeft) { doWrite(false); } - dataLeft = hasMoreDataToFlush(); + dataLeft = !socketBufferHandler.isWriteBufferEmpty(); if (!dataLeft && bufferedWrites.size() > 0) { Iterator<ByteBufferHolder> bufIter = bufferedWrites.iterator(); - while (!hasMoreDataToFlush() && bufIter.hasNext()) { + while (socketBufferHandler.isWriteBufferEmpty() && bufIter.hasNext()) { ByteBufferHolder buffer = bufIter.next(); buffer.flip(); - while (!hasMoreDataToFlush() && buffer.getBuf().remaining() > 0) { - transfer(buffer.getBuf(), socketWriteBuffer); + while (socketBufferHandler.isWriteBufferEmpty() && buffer.getBuf().remaining() > 0) { + socketBufferHandler.configureWriteBufferForWrite(); + transfer(buffer.getBuf(), socketBufferHandler.getWriteBuffer()); if (buffer.getBuf().remaining() == 0) { bufIter.remove(); } @@ -473,7 +478,7 @@ public abstract class SocketWrapperBase< } } - return hasMoreDataToFlush(); + return !socketBufferHandler.isWriteBufferEmpty(); } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org