# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: C:\Projects\Grizzly\trunk\modules # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: grizzly/src/main/java/com/sun/grizzly/async/AsyncQueueReaderContextTask.java --- grizzly/src/main/java/com/sun/grizzly/async/AsyncQueueReaderContextTask.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/async/AsyncQueueReaderContextTask.java Locally Modified (Based On LOCAL) @@ -23,7 +23,7 @@ package com.sun.grizzly.async; -import com.sun.grizzly.ContextTask; +import com.sun.grizzly.SelectionKeyContextTask; import java.nio.channels.SelectionKey; @@ -35,11 +35,11 @@ * * @author Alexey Stashok */ -public class AsyncQueueReaderContextTask extends ContextTask { +public class AsyncQueueReaderContextTask extends SelectionKeyContextTask { private static final TaskPool taskPool = new TaskPool() { @Override - public AsyncQueueReaderContextTask newTask() { + public AsyncQueueReaderContextTask newInstance() { return new AsyncQueueReaderContextTask(); } }; @@ -55,7 +55,7 @@ taskPool.offer(contextTask); } - public Object call() throws Exception { + public Object doCall() throws Exception { try { SelectionKey selectionKey = context.getSelectionKey(); if (selectionKey == null) { Index: grizzly/src/main/java/com/sun/grizzly/async/AsyncQueueWriterContextTask.java --- grizzly/src/main/java/com/sun/grizzly/async/AsyncQueueWriterContextTask.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/async/AsyncQueueWriterContextTask.java Locally Modified (Based On LOCAL) @@ -23,7 +23,7 @@ package com.sun.grizzly.async; -import com.sun.grizzly.ContextTask; +import com.sun.grizzly.SelectionKeyContextTask; import java.nio.channels.SelectionKey; @@ -35,11 +35,11 @@ * * @author Alexey Stashok */ -public class AsyncQueueWriterContextTask extends ContextTask { +public class AsyncQueueWriterContextTask extends SelectionKeyContextTask { private static final TaskPool taskPool = new TaskPool() { @Override - public AsyncQueueWriterContextTask newTask() { + public AsyncQueueWriterContextTask newInstance() { return new AsyncQueueWriterContextTask(); } }; @@ -55,7 +55,7 @@ taskPool.offer(contextTask); } - public Object call() throws Exception { + protected Object doCall() throws Exception { try { SelectionKey selectionKey = context.getSelectionKey(); if (selectionKey == null) { Index: grizzly/src/main/java/com/sun/grizzly/CallbackHandlerContextTask.java --- grizzly/src/main/java/com/sun/grizzly/CallbackHandlerContextTask.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/CallbackHandlerContextTask.java Locally Modified (Based On LOCAL) @@ -33,11 +33,11 @@ * * @author Alexey Stashok */ -public class CallbackHandlerContextTask extends ContextTask { +public class CallbackHandlerContextTask extends SelectionKeyContextTask { private static final TaskPool taskPool = new TaskPool() { @Override - public CallbackHandlerContextTask newTask() { + public CallbackHandlerContextTask newInstance() { return new CallbackHandlerContextTask(); } }; @@ -53,7 +53,7 @@ taskPool.offer(contextTask); } - public Object call() throws Exception { + protected Object doCall() throws Exception { IOEvent ioEvent = context.getIOEvent(); OpType currentOpType = context.getCurrentOpType(); @@ -93,6 +93,4 @@ callBackHandler = null; super.recycle(); } - - } Index: grizzly/src/main/java/com/sun/grizzly/Context.java --- grizzly/src/main/java/com/sun/grizzly/Context.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/Context.java Locally Modified (Based On LOCAL) @@ -32,6 +32,7 @@ import com.sun.grizzly.async.AsyncReadCondition; import com.sun.grizzly.async.AsyncWriteCallbackHandler; import com.sun.grizzly.util.AttributeHolder; +import com.sun.grizzly.util.SelectionKeyAttachment; import java.io.IOException; import java.net.SocketAddress; import java.nio.ByteBuffer; @@ -373,7 +374,7 @@ // If a IOEvent has been defined, invoke it first and // let its associated CallbackHandler decide if the ProtocolChain // be invoked or not. - Object attachment = key.attachment(); + Object attachment = SelectionKeyAttachment.getAttachment(key); if (ioEvent != null && (attachment instanceof CallbackHandler)) { CallbackHandlerContextTask task = CallbackHandlerContextTask.poll(); task.setCallBackHandler((CallbackHandler) attachment); Index: grizzly/src/main/java/com/sun/grizzly/ContextTask.java --- grizzly/src/main/java/com/sun/grizzly/ContextTask.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/ContextTask.java Locally Modified (Based On LOCAL) @@ -23,6 +23,7 @@ package com.sun.grizzly; +import com.sun.grizzly.util.ConcurrentLinkedQueuePool; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; @@ -47,24 +48,13 @@ context = null; } - protected abstract static class TaskPool { - private ConcurrentLinkedQueue pool = - new ConcurrentLinkedQueue(); + protected abstract static class TaskPool + extends ConcurrentLinkedQueuePool { - public abstract E newTask(); - - public E poll() { - E task = pool.poll(); - if (task == null) { - task = newTask(); - } - - return task; - } - + @Override public void offer(E task) { task.recycle(); - pool.offer(task); + super.offer(task); } } } Index: grizzly/src/main/java/com/sun/grizzly/Controller.java --- grizzly/src/main/java/com/sun/grizzly/Controller.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/Controller.java Locally Modified (Based On LOCAL) @@ -25,6 +25,7 @@ import com.sun.grizzly.util.AttributeHolder; import com.sun.grizzly.util.Cloner; +import com.sun.grizzly.util.ConcurrentLinkedQueuePool; import com.sun.grizzly.util.Copyable; import com.sun.grizzly.util.State; import com.sun.grizzly.util.StateHolder; @@ -135,7 +136,7 @@ /** * A cached list of Context. Context are by default stateless. */ - private ConcurrentLinkedQueue contexts; + private ConcurrentLinkedQueuePool contexts; /** @@ -239,7 +240,13 @@ * Controller constructor */ public Controller() { - contexts = new ConcurrentLinkedQueue(); + contexts = new ConcurrentLinkedQueuePool() { + @Override + public Context newInstance() { + return new Context(); + } + }; + stateHolder = new StateHolder(true); } @@ -262,10 +269,8 @@ ProtocolChainInstanceHandler pciHandler = null; ProtocolChain protocolChain = null; Context serverCtx = contexts.poll(); - if (serverCtx == null){ - serverCtx = new Context(); serverCtx.setController(this); - } + serverCtx.setSelectorHandler(selectorHandler); try { @@ -474,9 +479,6 @@ */ public Context pollContext(SelectionKey key){ Context ctx = contexts.poll(); - if (ctx == null){ - ctx = new Context(); - } ctx.setController(this); ctx.setSelectionKey(key); return ctx; Index: grizzly/src/main/java/com/sun/grizzly/DefaultSelectionKeyHandler.java --- grizzly/src/main/java/com/sun/grizzly/DefaultSelectionKeyHandler.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/DefaultSelectionKeyHandler.java Locally Modified (Based On LOCAL) @@ -23,8 +23,9 @@ package com.sun.grizzly; +import com.sun.grizzly.util.SelectionKeyAttachment; +import com.sun.grizzly.util.SelectionKeyActionAttachment; import com.sun.grizzly.util.Copyable; -import com.sun.grizzly.util.ThreadAttachment; import java.io.IOException; import java.net.Socket; import java.nio.channels.ClosedChannelException; @@ -34,11 +35,7 @@ import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSession; -import static com.sun.grizzly.filter.SSLReadFilter.EXPIRE_TIME; -import com.sun.grizzly.util.WorkerThread; import java.nio.channels.Selector; /** @@ -103,6 +100,12 @@ * {@inheritDoc} */ public void process(SelectionKey key) { + Object attachment = key.attachment(); + + if (attachment instanceof SelectionKeyActionAttachment) { + ((SelectionKeyActionAttachment) attachment).process(key); + } + removeExpirationStamp(key); } @@ -238,7 +241,11 @@ closeChannel(key.channel()); } - key.attach(null); + Object attachment = key.attach(null); + if (attachment instanceof SelectionKeyAttachment) { + ((SelectionKeyAttachment) attachment).release(key); + } + key.cancel(); key = null; } @@ -309,13 +316,8 @@ if (attachment != null) { if (attachment instanceof Long) { key.attach(null); - } else if (attachment instanceof ThreadAttachment) { - ((WorkerThread) Thread.currentThread()).attach( - (ThreadAttachment) attachment); - key.attach(null); - } else if (attachment instanceof SSLEngine) { - SSLEngine sslEngine = (SSLEngine) attachment; - sslEngine.getSession().removeValue(EXPIRE_TIME); + } else if (attachment instanceof SelectionKeyAttachment) { + ((SelectionKeyAttachment) attachment).setTimeout(null); } } } @@ -331,11 +333,8 @@ Object attachment = key.attachment(); if (attachment == null) { key.attach(currentTime); - } else if (attachment instanceof ThreadAttachment) { - ((ThreadAttachment) attachment).setTimeout(currentTime); - } else if (attachment instanceof SSLEngine) { - SSLEngine sslEngine = (SSLEngine) attachment; - sslEngine.getSession().putValue(EXPIRE_TIME,currentTime); + } else if (attachment instanceof SelectionKeyAttachment) { + ((SelectionKeyAttachment) attachment).setTimeout(currentTime); } } @@ -356,17 +355,9 @@ // can't predict the type of the attached object. if (attachment instanceof Long) { return (Long) attachment; - } else if (attachment instanceof SSLEngine) { - SSLSession sslSession = ((SSLEngine) attachment).getSession(); - if (sslSession != null && - sslSession.getValue(EXPIRE_TIME) != null) { - return (Long) sslSession.getValue(EXPIRE_TIME); + } else if (attachment instanceof SelectionKeyAttachment) { + return ((SelectionKeyAttachment) attachment).getTimeout(); } - - return null; - } else if (attachment instanceof ThreadAttachment) { - return ((ThreadAttachment) attachment).getTimeout(); - } } catch (ClassCastException ex) { if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, Index: grizzly/src/main/java/com/sun/grizzly/filter/SSLReadFilter.java --- grizzly/src/main/java/com/sun/grizzly/filter/SSLReadFilter.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/filter/SSLReadFilter.java Locally Modified (Based On LOCAL) @@ -27,7 +27,9 @@ import com.sun.grizzly.Controller; import com.sun.grizzly.ProtocolFilter; import com.sun.grizzly.SSLConfig; +import com.sun.grizzly.util.SSLSelectionKeyAttachment; import com.sun.grizzly.util.SSLUtils; +import com.sun.grizzly.util.SelectionKeyAttachment; import com.sun.grizzly.util.WorkerThreadImpl; import java.io.EOFException; import java.io.IOException; @@ -49,14 +51,6 @@ * @author Jeanfrancois Arcand */ public class SSLReadFilter implements ProtocolFilter{ - - public final static String HANDSHAKE = "handshake"; - public final static String DATA_DECODED = "dataDecoded"; - public final static String INPUT_BB_REMAINDER = "inputBBRemainder"; - public final static String OUTPUT_BB_REMAINDER = "outputBBRemainder"; - - - /** * The SSLContext associated with the SSL implementation * we are running on. @@ -95,12 +89,6 @@ /** - * Session keep-alive flag. - */ - public final static String EXPIRE_TIME = "expireTime"; - - - /** * Has the enabled protocol configured. */ private boolean isProtocolConfigured = false; @@ -125,7 +113,6 @@ public boolean execute(Context ctx) throws IOException { boolean result = true; int count = 0; - boolean isCopied = false; Throwable exception = null; SelectionKey key = ctx.getSelectionKey(); WorkerThreadImpl workerThread; @@ -137,22 +124,18 @@ SSLEngine sslEngine = newSSLEngine(key); workerThread.setSSLEngine(sslEngine); - key.attach(sslEngine); + if (key.attachment() == null) { + key.attach(SSLSelectionKeyAttachment.create(key, sslEngine)); + } - boolean hasHandshake = Boolean.TRUE.equals( - sslEngine.getSession().getValue(HANDSHAKE)); - - restoreSecuredBufferRemainders(sslEngine); + boolean hasHandshake = sslEngine.getSession().isValid(); try { allocateBuffers(); - isCopied = copyByteBufferToInputBB(sslEngine, - workerThread.getByteBuffer(), workerThread.getInputBB()); if (hasHandshake) { count = doRead(key); } else if (doHandshake(key, SSLUtils.getReadTimeout())) { hasHandshake = true; - sslEngine.getSession().putValue(HANDSHAKE, Boolean.TRUE); // set "no available data" for secured output buffer ByteBuffer outputBB = workerThread.getOutputBB(); @@ -168,12 +151,6 @@ log("SSLReadFilter.execute",ex); } finally { if (exception != null || count == -1){ - if (isCopied) { - /* if some data was copied from ByteBuffer, - * but connection got closed - clean inputBB */ - workerThread.getInputBB().clear(); - } - ctx.setAttribute(Context.THROWABLE,exception); ctx.setKeyRegistrationState( Context.KeyRegistrationState.CANCEL); @@ -199,8 +176,7 @@ cancel(ctx.getSelectionKey()); } else if (ctx.getKeyRegistrationState() == Context.KeyRegistrationState.REGISTER){ - SSLEngine sslEngine = (SSLEngine) ctx.getSelectionKey().attachment(); - saveSecuredBufferRemainders(sslEngine); + saveSecuredBufferRemainders(ctx.getSelectionKey()); ctx.getSelectorHandler().register(ctx.getSelectionKey(), SelectionKey.OP_READ); ctx.setKeyRegistrationState(Context.KeyRegistrationState.NONE); @@ -295,20 +271,20 @@ } - private static int doRead(SelectionKey key){ + private static int doRead(SelectionKey key) { final WorkerThreadImpl workerThread = - (WorkerThreadImpl)Thread.currentThread(); + (WorkerThreadImpl) Thread.currentThread(); ByteBuffer byteBuffer = workerThread.getByteBuffer(); ByteBuffer outputBB = workerThread.getOutputBB(); ByteBuffer inputBB = workerThread.getInputBB(); SSLEngine sslEngine = workerThread.getSSLEngine(); int count = -1; - try{ + try { // Read first bytes to avoid continuing if the client // closed the connection. - count = ((SocketChannel)key.channel()).read(inputBB); - if (count != -1){ + count = ((SocketChannel) key.channel()).read(inputBB); + if (count != -1) { // Decrypt the bytes we just read. if (Controller.logger().isLoggable(Level.FINE)) { Controller.logger().log(Level.FINE, @@ -318,21 +294,20 @@ } byteBuffer = - SSLUtils.unwrapAll(byteBuffer,inputBB,sslEngine); + SSLUtils.unwrapAll(byteBuffer, inputBB, sslEngine); workerThread.setInputBB(inputBB); workerThread.setOutputBB(outputBB); workerThread.setByteBuffer(byteBuffer); } return count; - } catch(IOException ex){ + } catch (IOException ex) { log("Exception during SSL read.", ex); return -1; } finally { - if (count == -1){ - try{ + if (count == -1) { + try { sslEngine.closeInbound(); - } catch (SSLException ex){ - ; + } catch (SSLException ex) { } } } @@ -399,13 +374,12 @@ SSLEngine sslEngine = null; if (key.attachment() == null){ sslEngine = newSSLEngine(); - } else if (key.attachment() instanceof SSLEngine){ - sslEngine = (SSLEngine)key.attachment(); + } else if (key.attachment() instanceof SSLSelectionKeyAttachment){ + sslEngine = ((SSLSelectionKeyAttachment) SelectionKeyAttachment.getAttachment(key)).getSslEngine(); } else { sslEngine = newSSLEngine(); } sslEngine.setWantClientAuth(wantClientAuth); - sslEngine.getSession().removeValue(EXPIRE_TIME); sslEngine.setNeedClientAuth(needClientAuth); return sslEngine; } @@ -613,78 +587,28 @@ return ciphers; } - /** - * If bytebuffer is not empty it means that previous - * ProtocolFilters has read some data already. This data - * should be copied to the inputBB. - */ - private static boolean copyByteBufferToInputBB(SSLEngine sslEngine, - ByteBuffer byteBuffer, ByteBuffer inputBB) { - if (byteBuffer.position() > 0) { - Boolean isDataDecoded = - (Boolean) sslEngine.getSession().getValue(DATA_DECODED); + private void saveSecuredBufferRemainders(SelectionKey selectionKey) { + SSLSelectionKeyAttachment attachment = + (SSLSelectionKeyAttachment) selectionKey.attachment(); - if (!Boolean.TRUE.equals(isDataDecoded)) { - byteBuffer.flip(); - inputBB.put(byteBuffer); - byteBuffer.clear(); - return true; - } else if (isDataDecoded != null) { - sslEngine.getSession().removeValue(DATA_DECODED); - } - } - - return false; - } - - /** - * Restores (if required) secure buffers, associated with SSLEngine, - * which were saved during previous SSLReadFilter execution. - * It makes possible data, which wasn't processed on previous cycle to be processed now - */ - private void restoreSecuredBufferRemainders(SSLEngine sslEngine) { - WorkerThreadImpl workerThread = (WorkerThreadImpl) Thread.currentThread(); - - ByteBuffer inputBBRemainder = (ByteBuffer) sslEngine.getSession(). - getValue(INPUT_BB_REMAINDER); - if (inputBBRemainder != null) { - sslEngine.getSession().removeValue(INPUT_BB_REMAINDER); - workerThread.setInputBB(inputBBRemainder); - } - - ByteBuffer outputBBRemainder = (ByteBuffer) sslEngine.getSession(). - getValue(OUTPUT_BB_REMAINDER); - if (outputBBRemainder != null) { - sslEngine.getSession().removeValue(OUTPUT_BB_REMAINDER); - workerThread.setOutputBB(outputBBRemainder); - } - } - - /** - * Saves (if required) secure buffers, associated with SSLEngine - * If secured data, associated with SSLEngine, is not completely - * processed now (may be additional data is required) - then it could be processed - * on next SSLReadFilter execution. - */ - private void saveSecuredBufferRemainders(SSLEngine sslEngine) { - WorkerThreadImpl workerThread = (WorkerThreadImpl) Thread.currentThread(); - - if (sslEngine == null) { + if (attachment == null) { Controller.logger().log(Level.FINE, - "SSLEngine is NULL, when saving buffers"); + "SelectionKey attachment is NULL, when saving buffers"); return; } + WorkerThreadImpl workerThread = (WorkerThreadImpl) Thread.currentThread(); + ByteBuffer inputBB = workerThread.getInputBB(); if (inputBB != null && inputBB.hasRemaining()) { - sslEngine.getSession().putValue(INPUT_BB_REMAINDER, inputBB); workerThread.setInputBB(null); + attachment.setInputBB(inputBB); } ByteBuffer outputBB = workerThread.getOutputBB(); if (outputBB != null && outputBB.hasRemaining()) { - sslEngine.getSession().putValue(OUTPUT_BB_REMAINDER, outputBB); workerThread.setOutputBB(null); + attachment.setOutputBB(outputBB); } } Index: grizzly/src/main/java/com/sun/grizzly/ProtocolChainContextTask.java --- grizzly/src/main/java/com/sun/grizzly/ProtocolChainContextTask.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/ProtocolChainContextTask.java Locally Modified (Based On LOCAL) @@ -24,8 +24,6 @@ package com.sun.grizzly; -import java.nio.channels.SelectionKey; - /** * ProtocolChain task, which will be executed by * Context, when Context.execute(ContextTask) @@ -33,11 +31,11 @@ * * @author Alexey Stashok */ -public class ProtocolChainContextTask extends ContextTask { +public class ProtocolChainContextTask extends SelectionKeyContextTask { private static final TaskPool taskPool = new TaskPool() { @Override - public ProtocolChainContextTask newTask() { + public ProtocolChainContextTask newInstance() { return new ProtocolChainContextTask(); } }; @@ -51,16 +49,10 @@ taskPool.offer(contextTask); } - public Object call() throws Exception { - SelectionKey currentKey = context.getSelectionKey(); - SelectionKeyHandler selectionKeyHandler = context. - getSelectorHandler().getSelectionKeyHandler(); - - selectionKeyHandler.process(currentKey); + protected Object doCall() throws Exception { try { context.getProtocolChain().execute(context); } finally { - selectionKeyHandler.postProcess(currentKey); offer(this); } Index: grizzly/src/main/java/com/sun/grizzly/SelectionKeyContextTask.java --- grizzly/src/main/java/com/sun/grizzly/SelectionKeyContextTask.java Locally New +++ grizzly/src/main/java/com/sun/grizzly/SelectionKeyContextTask.java Locally New @@ -0,0 +1,66 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can obtain + * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package com.sun.grizzly; + +import java.nio.channels.SelectionKey; + +/** + * Basic class for all ContextTasks, which are dealing with + * SelectionKeys + * + * @author Alexey Stashok + */ +public abstract class SelectionKeyContextTask extends ContextTask { + + public final Object call() throws Exception { + Object result = null; + SelectionKey currentKey = context.getSelectionKey(); + SelectionKeyHandler selectionKeyHandler = context. + getSelectorHandler().getSelectionKeyHandler(); + + selectionKeyHandler.process(currentKey); + try { + result = doCall(); + } finally { + selectionKeyHandler.postProcess(currentKey); + } + + return result; + } + + protected abstract Object doCall() throws Exception; +} Index: grizzly/src/main/java/com/sun/grizzly/SSLConnectorHandler.java --- grizzly/src/main/java/com/sun/grizzly/SSLConnectorHandler.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/SSLConnectorHandler.java Locally Modified (Based On LOCAL) @@ -1102,7 +1102,6 @@ */ private void registerSelectionKeyFor(int ops) { SelectionKey key = getSelectionKey(); - key.attach(this); selectorHandler.register(key, ops); } @@ -1119,7 +1118,6 @@ if (securedOutputBuffer.hasRemaining()) { SelectionKey key = socketChannel.keyFor(selectorHandler.getSelector()); - key.attach(callbackHandler); selectorHandler.register(key, SelectionKey.OP_WRITE); return false; Index: grizzly/src/main/java/com/sun/grizzly/TCPConnectorHandler.java --- grizzly/src/main/java/com/sun/grizzly/TCPConnectorHandler.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/TCPConnectorHandler.java Locally Modified (Based On LOCAL) @@ -366,7 +366,6 @@ int nRead = socketChannel.read(byteBuffer); if (nRead == 0){ - key.attach(callbackHandler); selectorHandler.register(key,SelectionKey.OP_READ); } return nRead; @@ -406,7 +405,6 @@ } if (totalWriteBytes == 0 && byteBuffer.hasRemaining()){ - key.attach(callbackHandler); selectorHandler.register(key,SelectionKey.OP_WRITE); } return totalWriteBytes; @@ -537,10 +535,7 @@ if (key == null) return; - key.cancel(); - key.attach(null); - - selectorHandler.closeChannel(socketChannel); + selectorHandler.getSelectionKeyHandler().cancel(key); } else { socketChannel.close(); } Index: grizzly/src/main/java/com/sun/grizzly/TCPSelectorHandler.java --- grizzly/src/main/java/com/sun/grizzly/TCPSelectorHandler.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/TCPSelectorHandler.java Locally Modified (Based On LOCAL) @@ -29,8 +29,10 @@ import com.sun.grizzly.async.TCPAsyncQueueWriter; import com.sun.grizzly.async.AsyncQueueWriterContextTask; import com.sun.grizzly.async.TCPAsyncQueueReader; +import com.sun.grizzly.util.CallbackHandlerSelectionKeyAttachment; import com.sun.grizzly.util.Cloner; import com.sun.grizzly.util.Copyable; +import com.sun.grizzly.util.SelectionKeyAttachment; import com.sun.grizzly.util.SelectionKeyOP; import com.sun.grizzly.util.SelectionKeyOP.ConnectSelectionKeyOP; import com.sun.grizzly.util.State; @@ -401,11 +403,22 @@ } socketChannel.configureBlocking(false); - boolean isConnected = socketChannel.connect(remoteAddress); SelectionKey key = socketChannel.register(selector, - SelectionKey.OP_CONNECT, callbackHandler); + SelectionKey.OP_CONNECT); + key.attach(CallbackHandlerSelectionKeyAttachment.create(key, callbackHandler)); - // if channel was connected immediately + boolean isConnected = false; + try { + isConnected = socketChannel.connect(remoteAddress); + } catch(IOException e) { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "IOException occured when tried to connect socket", e); + } + + isConnected = true; + } + + // if channel was connected immediately or exception occured if (isConnected) { onConnectInterest(key, ctx); } @@ -610,7 +623,7 @@ throws IOException{ // disable OP_READ on key before doing anything else key.interestOps(key.interestOps() & (~SelectionKey.OP_READ)); - Object attach = key.attachment(); + Object attach = SelectionKeyAttachment.getAttachment(key); if (asyncQueueReader.isAsyncQueueReaderEnabledFor(key)) { final Context context = pollContext(ctx, key); @@ -646,7 +659,8 @@ context.setCurrentOpType(Context.OpType.OP_WRITE); invokeAsyncQueueWriter(context); return false; - } else if ((attach = key.attachment()) instanceof CallbackHandler){ + } else if ((attach = SelectionKeyAttachment.getAttachment(key)) + instanceof CallbackHandler){ final Context context = pollContext(ctx, key); context.setCurrentOpType(Context.OpType.OP_WRITE); invokeCallbackHandler((CallbackHandler) attach, context); @@ -671,7 +685,7 @@ key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE)); key.interestOps(key.interestOps() & (~SelectionKey.OP_READ)); - Object attach = key.attachment(); + Object attach = SelectionKeyAttachment.getAttachment(key); if (attach instanceof CallbackHandler){ final Context context = pollContext(ctx, key); context.setCurrentOpType(Context.OpType.OP_CONNECT); Index: grizzly/src/main/java/com/sun/grizzly/UDPConnectorHandler.java --- grizzly/src/main/java/com/sun/grizzly/UDPConnectorHandler.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/UDPConnectorHandler.java Locally Modified (Based On LOCAL) @@ -60,38 +60,38 @@ /** * The underlying UDPSelectorHandler used to mange SelectionKeys. */ - private UDPSelectorHandler selectorHandler; + protected UDPSelectorHandler selectorHandler; /** * A CallbackHandler handler invoked by the UDPSelectorHandler * when a non blocking operation is ready to be processed. */ - private CallbackHandler callbackHandler; + protected CallbackHandler callbackHandler; /** * The connection's DatagramChannel. */ - private DatagramChannel datagramChannel; + protected DatagramChannel datagramChannel; /** * Is the connection established. */ - private volatile boolean isConnected; + protected volatile boolean isConnected; /** * The internal Controller used (in case not specified). */ - private Controller controller; + protected Controller controller; /** * IsConnected Latch related */ - private CountDownLatch isConnectedLatch; + protected CountDownLatch isConnectedLatch; /** @@ -104,7 +104,7 @@ * A blocking InputStream that use a pool of Selector * to execute a blocking read operation. */ - private ByteBufferInputStream inputStream; + protected ByteBufferInputStream inputStream; /** @@ -192,7 +192,6 @@ isConnectedLatch = new CountDownLatch(1); selectorHandler.connect(remoteAddress,localAddress,callbackHandler); - inputStream = new ByteBufferInputStream(); try { isConnectedLatch.await(30, TimeUnit.SECONDS); @@ -294,6 +293,9 @@ SelectionKey key = datagramChannel.keyFor(selectorHandler.getSelector()); if (blocking){ + if (inputStream == null) { + inputStream = new ByteBufferInputStream(); + } inputStream.setSelectionKey(key); inputStream.setChannelType( ByteBufferInputStream.ChannelType.DatagramChannel); @@ -307,7 +309,6 @@ int nRead = datagramChannel.read(byteBuffer); if (nRead == 0){ - key.attach(callbackHandler); selectorHandler.register(key, SelectionKey.OP_READ); } return nRead; @@ -338,7 +339,6 @@ int nWrite = datagramChannel.write(byteBuffer); if (nWrite == 0){ - key.attach(callbackHandler); selectorHandler.register(key, SelectionKey.OP_WRITE); } return nWrite; @@ -513,10 +513,7 @@ if (key == null) return; - key.cancel(); - key.attach(null); - - selectorHandler.closeChannel(datagramChannel); + selectorHandler.getSelectionKeyHandler().cancel(key); } else { datagramChannel.close(); } @@ -542,8 +539,10 @@ datagramChannel = (DatagramChannel)key.channel(); isConnected = datagramChannel.isConnected(); + if (isConnectedLatch != null) { isConnectedLatch.countDown(); } + } /** Index: grizzly/src/main/java/com/sun/grizzly/UDPSelectorHandler.java --- grizzly/src/main/java/com/sun/grizzly/UDPSelectorHandler.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/UDPSelectorHandler.java Locally Modified (Based On LOCAL) @@ -25,6 +25,7 @@ import com.sun.grizzly.async.UDPAsyncQueueReader; import com.sun.grizzly.async.UDPAsyncQueueWriter; +import com.sun.grizzly.util.CallbackHandlerSelectionKeyAttachment; import com.sun.grizzly.util.Copyable; import com.sun.grizzly.util.SelectionKeyOP; import com.sun.grizzly.util.State; @@ -154,7 +155,8 @@ datagramChannel.configureBlocking(false); datagramChannel.connect(remoteAddress); SelectionKey key = datagramChannel.register(selector, - SelectionKey.OP_READ | SelectionKey.OP_WRITE, callbackHandler); + SelectionKey.OP_READ | SelectionKey.OP_WRITE); + key.attach(CallbackHandlerSelectionKeyAttachment.create(key, callbackHandler)); onConnectInterest(key, ctx); } Index: grizzly/src/main/java/com/sun/grizzly/util/CallbackHandlerSelectionKeyAttachment.java --- grizzly/src/main/java/com/sun/grizzly/util/CallbackHandlerSelectionKeyAttachment.java Locally New +++ grizzly/src/main/java/com/sun/grizzly/util/CallbackHandlerSelectionKeyAttachment.java Locally New @@ -0,0 +1,86 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can obtain + * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package com.sun.grizzly.util; + +import com.sun.grizzly.CallbackHandler; +import java.nio.channels.SelectionKey; +import java.util.concurrent.atomic.AtomicReference; + +/** + * SelectionKey attachment, which wraps CallbackHandler + * + * @author Alexey Stashok + */ +public class CallbackHandlerSelectionKeyAttachment extends SelectionKeyAttachmentWrapper { + private static ConcurrentLinkedQueuePool pool = + new ConcurrentLinkedQueuePool() { + + @Override + public CallbackHandlerSelectionKeyAttachment newInstance() { + return new CallbackHandlerSelectionKeyAttachment(); + } + }; + + // Is used for key pooling + private AtomicReference associatedKey = new AtomicReference(); + + + /** + * Creates the CallbackHandler to the SelectionKey + * CallbackHandler will not be attached directly, but wrapped with + * CallbackHandlerSelectionKeyAttachment + */ + public static CallbackHandlerSelectionKeyAttachment create(SelectionKey key, + CallbackHandler callbackHandler) { + CallbackHandlerSelectionKeyAttachment attachment = pool.poll(); + + attachment.associatedKey.set(key); + attachment.setAttachment(callbackHandler); + return attachment; + } + + private CallbackHandlerSelectionKeyAttachment() { + } + + @Override + public void release(SelectionKey selectionKey) { + if (associatedKey.getAndSet(null) == selectionKey) { + super.release(selectionKey); + pool.offer(this); + } + } +} Index: grizzly/src/main/java/com/sun/grizzly/util/ConcurrentLinkedQueuePool.java --- grizzly/src/main/java/com/sun/grizzly/util/ConcurrentLinkedQueuePool.java Locally New +++ grizzly/src/main/java/com/sun/grizzly/util/ConcurrentLinkedQueuePool.java Locally New @@ -0,0 +1,60 @@ +/* + * The contents of this file are subject to the terms + * of the Common Development and Distribution License + * (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the license at + * https://glassfish.dev.java.net/public/CDDLv1.0.html or + * glassfish/bootstrap/legal/CDDLv1.0.txt. + * See the License for the specific language governing + * permissions and limitations under the License. + * + * When distributing Covered Code, include this CDDL + * Header Notice in each file and include the License file + * at glassfish/bootstrap/legal/CDDLv1.0.txt. + * If applicable, add the following below the CDDL Header, + * with the fields enclosed by brackets [] replaced by + * you own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + */ + +package com.sun.grizzly.util; + +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * ObjectPool implementation based on ConcurrentLinkedQueue + * + * @author Alexey Stashok + */ +public abstract class ConcurrentLinkedQueuePool implements ObjectPool { + private volatile ConcurrentLinkedQueue pool; + + public abstract E newInstance(); + + public E poll() { + if (pool == null) { + synchronized(this) { + if (pool == null) { + pool = new ConcurrentLinkedQueue(); + } + } + } + + E object = pool.poll(); + if (object == null) { + object = newInstance(); + } + + return object; + } + + public void offer(E object) { + if (pool != null) { + pool.offer(object); + } + } +} Index: grizzly/src/main/java/com/sun/grizzly/util/ObjectPool.java --- grizzly/src/main/java/com/sun/grizzly/util/ObjectPool.java Locally New +++ grizzly/src/main/java/com/sun/grizzly/util/ObjectPool.java Locally New @@ -0,0 +1,35 @@ +/* + * The contents of this file are subject to the terms + * of the Common Development and Distribution License + * (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the license at + * https://glassfish.dev.java.net/public/CDDLv1.0.html or + * glassfish/bootstrap/legal/CDDLv1.0.txt. + * See the License for the specific language governing + * permissions and limitations under the License. + * + * When distributing Covered Code, include this CDDL + * Header Notice in each file and include the License file + * at glassfish/bootstrap/legal/CDDLv1.0.txt. + * If applicable, add the following below the CDDL Header, + * with the fields enclosed by brackets [] replaced by + * you own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + */ + +package com.sun.grizzly.util; + +/** + * Basic interface for object pool implementations + * + * @author Alexey Stashok + */ +public interface ObjectPool { + public E poll(); + + public void offer(E object); +} Index: grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyActionAttachment.java --- grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyActionAttachment.java Locally New +++ grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyActionAttachment.java Locally New @@ -0,0 +1,50 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can obtain + * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package com.sun.grizzly.util; + +import java.nio.channels.SelectionKey; + +/** + * Class represents extended version of SelectionKeyAttachment, + * and introduces process method, which will be called by framework once + * SelectionKey has some ready event, before actual event processing. + * + * @author Alexey Stashok + */ +public abstract class SelectionKeyActionAttachment extends SelectionKeyAttachment { + public abstract void process(SelectionKey selectionKey); +} Index: grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyAttachment.java --- grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyAttachment.java Locally New +++ grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyAttachment.java Locally New @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can obtain + * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package com.sun.grizzly.util; + +import java.nio.channels.SelectionKey; + +/** + * Basic class for all SelectionKey attachments. + * Custom attachments should be inherited from it. + * + * @author Alexey Stashok + */ +public abstract class SelectionKeyAttachment { + private Long timeout; + + public static Object getAttachment(SelectionKey key) { + Object attachment = key.attachment(); + if (attachment instanceof SelectionKeyAttachmentWrapper) { + return ((SelectionKeyAttachmentWrapper) attachment).getAttachment(); + } + + return attachment; + } + + public Long getTimeout() { + return timeout; + } + + public void setTimeout(Long timeout) { + this.timeout = timeout; + } + + public void release(SelectionKey selectionKey) { + timeout = null; + } +} Index: grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyAttachmentWrapper.java --- grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyAttachmentWrapper.java Locally New +++ grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyAttachmentWrapper.java Locally New @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can obtain + * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package com.sun.grizzly.util; + +import java.nio.channels.SelectionKey; + +/** + * SelectionKey attachment utility class. + * This class could be used as wrapper for custom SelectionKey + * attachments, which are not subclasses of SelectionKeyAttachment + * class. + * + * @author Alexey Stashok + */ +public class SelectionKeyAttachmentWrapper extends SelectionKeyActionAttachment { + private E attachment; + + public E getAttachment() { + return attachment; + } + + public void setAttachment(E attachment) { + this.attachment = attachment; + } + + @Override + public void process(SelectionKey selectionKey) { + // Do nothing by default + } + + @Override + public void release(SelectionKey selectionKey) { + attachment = null; + super.release(selectionKey); + } +} Index: grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyOP.java --- grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyOP.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/util/SelectionKeyOP.java Locally Modified (Based On LOCAL) @@ -27,7 +27,6 @@ import java.net.SocketAddress; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; -import java.util.concurrent.ConcurrentLinkedQueue; /** * @@ -38,27 +37,29 @@ private SelectionKey key; private SelectableChannel channel; - private static ConcurrentLinkedQueue readWritePool = - new ConcurrentLinkedQueue(); + private static ConcurrentLinkedQueuePool readWritePool = + new ConcurrentLinkedQueuePool() { + @Override + public SelectionKeyOP newInstance() { + return new SelectionKeyOP(); + } + }; - private static ConcurrentLinkedQueue connectPool = - new ConcurrentLinkedQueue(); + private static ConcurrentLinkedQueuePool connectPool = + new ConcurrentLinkedQueuePool() { + @Override + public SelectionKeyOP newInstance() { + return new ConnectSelectionKeyOP(); + } + }; public static SelectionKeyOP aquireSelectionKeyOP(int op) { if (op == SelectionKey.OP_READ || op == SelectionKey.OP_WRITE || op == (SelectionKey.OP_WRITE | SelectionKey.OP_READ)) { SelectionKeyOP operation = readWritePool.poll(); - if (operation == null) { - operation = new SelectionKeyOP(); - } - return operation; } else if (op == SelectionKey.OP_CONNECT) { SelectionKeyOP operation = connectPool.poll(); - if (operation == null) { - operation = new ConnectSelectionKeyOP(); - } - \ No newline at end of file return operation; } Index: grizzly/src/main/java/com/sun/grizzly/util/SSLSelectionKeyAttachment.java --- grizzly/src/main/java/com/sun/grizzly/util/SSLSelectionKeyAttachment.java Locally New +++ grizzly/src/main/java/com/sun/grizzly/util/SSLSelectionKeyAttachment.java Locally New @@ -0,0 +1,150 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can obtain + * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package com.sun.grizzly.util; + +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.util.concurrent.atomic.AtomicReference; +import javax.net.ssl.SSLEngine; + +/** + * SelectionKeyAttachment implementation, which is targeted for SSL + * support. + * + * @author Alexey Stashok + */ +public class SSLSelectionKeyAttachment extends SelectionKeyActionAttachment { + + private static ConcurrentLinkedQueuePool pool = + new ConcurrentLinkedQueuePool() { + + @Override + public SSLSelectionKeyAttachment newInstance() { + return new SSLSelectionKeyAttachment(); + } + }; + + private SSLEngine sslEngine; + private ByteBuffer inputBB; + private ByteBuffer outputBB; + + // Is used for key pooling + private AtomicReference associatedKey = new AtomicReference(); + + + /** + * Saves (if required) secure buffers, associated with SSLEngine + * If secured data, associated with SSLEngine, is not completely + * processed now (may be additional data is required) - then it could be processed + * on next SSLReadFilter execution. + */ + public static SSLSelectionKeyAttachment create(SelectionKey key, + SSLEngine sslEngine) { + SSLSelectionKeyAttachment attachment = pool.poll(); + + attachment.associatedKey.set(key); + attachment.setInputBB(null); + attachment.setOutputBB(null); + + attachment.setSslEngine(sslEngine); + return attachment; + } + + private SSLSelectionKeyAttachment() { + } + + public ByteBuffer getInputBB() { + return inputBB; + } + + public void setInputBB(ByteBuffer inputBB) { + this.inputBB = inputBB; + } + + public ByteBuffer getOutputBB() { + return outputBB; + } + + public void setOutputBB(ByteBuffer outputBB) { + this.outputBB = outputBB; + } + + public SSLEngine getSslEngine() { + return sslEngine; + } + + public void setSslEngine(SSLEngine sslEngine) { + this.sslEngine = sslEngine; + } + + /** + * Restores (if required) secure buffers, associated with SSLEngine, + * which were saved during previous SSLReadFilter execution. + * It makes possible data, which wasn't processed on previous cycle to be processed now + */ + @Override + public void process(SelectionKey selectionKey) { + WorkerThreadImpl workerThread; + try { + workerThread = (WorkerThreadImpl) Thread.currentThread(); + } catch (ClassCastException ex) { + throw new IllegalStateException(ex.getMessage()); + } + + if (inputBB != null) { + workerThread.setInputBB(inputBB); + inputBB = null; + } + + if (outputBB != null) { + workerThread.setOutputBB(outputBB); + outputBB = null; + } + + workerThread.setSSLEngine(sslEngine); + } + + @Override + public void release(SelectionKey selectionKey) { + if (associatedKey.getAndSet(null) == selectionKey) { + sslEngine = null; + inputBB = null; + outputBB = null; + super.release(selectionKey); + pool.offer(this); + } + } +} \ No newline at end of file Index: grizzly/src/main/java/com/sun/grizzly/util/ThreadAttachment.java --- grizzly/src/main/java/com/sun/grizzly/util/ThreadAttachment.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/util/ThreadAttachment.java Locally Modified (Based On LOCAL) @@ -23,6 +23,7 @@ package com.sun.grizzly.util; import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; import java.util.WeakHashMap; import javax.net.ssl.SSLEngine; @@ -32,12 +33,9 @@ * * @author Jeanfrancois Arcand */ -public class ThreadAttachment { +public class ThreadAttachment extends SelectionKeyActionAttachment { - private long timeout; - - private String threadId; @@ -169,22 +167,13 @@ this.threadId = threadId; } - /** - * Set the timeout used by the SelectionKeyHandler to times out an idle - * connection. + * SelectionKey attachment processing + * @param selectionKey */ - public void setTimeout(long timeout){ - this.timeout = timeout; + public void process(SelectionKey selectionKey) { + ((WorkerThread) Thread.currentThread()).attach( + (ThreadAttachment) this); + selectionKey.attach(null); } - - - /** - * Return the timeout used by the SelectionKeyHandler to times out an idle - * connection. - */ - public long getTimeout(){ - return timeout; } - -} Index: grizzly/src/main/java/com/sun/grizzly/util/WorkerThreadImpl.java --- grizzly/src/main/java/com/sun/grizzly/util/WorkerThreadImpl.java Base (BASE) +++ grizzly/src/main/java/com/sun/grizzly/util/WorkerThreadImpl.java Locally Modified (Based On LOCAL) @@ -294,11 +294,11 @@ * @return a new ThreadAttachment */ public ThreadAttachment detach(boolean copyState) { - if (threadAttachment == null){ + if (threadAttachment == null) { threadAttachment = new ThreadAttachment(); } - try{ + try { threadAttachment.setByteBuffer(byteBuffer); threadAttachment.setSSLEngine(sslEngine); threadAttachment.setInputBB(inputBB); @@ -308,7 +308,7 @@ } finally { // We cannot cache/re-use this object as it might be referenced // by more than one thread. - if (copyState){ + if (copyState) { // Re-create a new ByteBuffer byteBuffer = ByteBufferFactory.allocate(byteBufferType, initialByteBufferSize); Index: grizzly/src/test/java/com/sun/grizzly/ClientCacheTest.java --- grizzly/src/test/java/com/sun/grizzly/ClientCacheTest.java Base (BASE) +++ grizzly/src/test/java/com/sun/grizzly/ClientCacheTest.java Locally Modified (Based On LOCAL) @@ -131,6 +131,7 @@ controller.setProtocolChainInstanceHandler( new DefaultProtocolChainInstanceHandler(){ + @Override public ProtocolChain poll() { ProtocolChain protocolChain = protocolChains.poll(); if (protocolChain == null){ @@ -175,10 +176,8 @@ try { int nRead = socketChannel.read(readBB); if (nRead == 0 && readTry++ < 2){ - key.attach(callbackHandler); - controller.registerKey(key, - SelectionKey.OP_READ, - Controller.Protocol.TCP); + ioEvent.attachment().getSelectorHandler().register(key, + SelectionKey.OP_READ); } else { responseArrivedLatchHolder[0].countDown(); } @@ -196,10 +195,8 @@ int nWrite = socketChannel.write(writeBB); if (nWrite == 0){ - key.attach(callbackHandler); - controller.registerKey(key, - SelectionKey.OP_WRITE, - Controller.Protocol.TCP); + ioEvent.attachment().getSelectorHandler().register(key, + SelectionKey.OP_WRITE); return; } } Index: grizzly/src/test/java/com/sun/grizzly/TCPAsyncQueueWriterTest.java --- grizzly/src/test/java/com/sun/grizzly/TCPAsyncQueueWriterTest.java Base (BASE) +++ grizzly/src/test/java/com/sun/grizzly/TCPAsyncQueueWriterTest.java Locally Modified (Based On LOCAL) @@ -214,7 +214,6 @@ try { int nRead = socketChannel.read(readBB); if (readBB.hasRemaining()){ - key.attach(callbackHandler); selectorHandler.register(key, SelectionKey.OP_READ); } else { responseArrivedLatchHolder[0].countDown(); Index: grizzly/src/test/java/com/sun/grizzly/TCPConnectorHandlerTest.java --- grizzly/src/test/java/com/sun/grizzly/TCPConnectorHandlerTest.java Base (BASE) +++ grizzly/src/test/java/com/sun/grizzly/TCPConnectorHandlerTest.java Locally Modified (Based On LOCAL) @@ -278,7 +278,6 @@ try { int nRead = socketChannel.read(readBB); if (nRead == 0 && readTry++ < 2){ - key.attach(callbackHandler); selectorHandler.register(key, SelectionKey.OP_READ); } else { responseArrivedLatchHolder[0].countDown(); @@ -299,7 +298,6 @@ int nWrite = socketChannel.write(writeBB); if (nWrite == 0){ - key.attach(callbackHandler); selectorHandler.register(key, SelectionKey.OP_WRITE); return; } Index: grizzly/src/test/java/com/sun/grizzly/UDPAsyncQueueWriterTest.java --- grizzly/src/test/java/com/sun/grizzly/UDPAsyncQueueWriterTest.java Base (BASE) +++ grizzly/src/test/java/com/sun/grizzly/UDPAsyncQueueWriterTest.java Locally Modified (Based On LOCAL) @@ -214,7 +214,6 @@ try { int nRead = socketChannel.read(readBB); if (readBB.hasRemaining()){ - key.attach(callbackHandler); selectorHandler.register(key, SelectionKey.OP_READ); } else { responseArrivedLatchHolder[0].countDown(); Index: portunif/src/main/java/com/sun/grizzly/portunif/TLSPUPreProcessor.java --- portunif/src/main/java/com/sun/grizzly/portunif/TLSPUPreProcessor.java Base (BASE) +++ portunif/src/main/java/com/sun/grizzly/portunif/TLSPUPreProcessor.java Locally Modified (Based On LOCAL) @@ -26,8 +26,9 @@ import com.sun.grizzly.Context; import com.sun.grizzly.Controller; import com.sun.grizzly.SSLConfig; -import com.sun.grizzly.filter.SSLReadFilter; +import com.sun.grizzly.util.SSLSelectionKeyAttachment; import com.sun.grizzly.util.SSLUtils; +import com.sun.grizzly.util.SelectionKeyAttachment; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; @@ -50,12 +51,7 @@ private static final String TMP_DECODED_BUFFER ="TMP_DECODED_BUFFER"; - /** - * Decrypted ByteBuffer default size. - */ - private final static int appBBSize = 5 * 4096; - /** * The SSLContext associated with the SSL implementation * we are running on. @@ -108,14 +104,14 @@ SSLEngine sslEngine = null; - Object attachment = key.attachment(); - if (attachment == null || !(attachment instanceof SSLEngine)) { + Object attachment = SelectionKeyAttachment.getAttachment(key); + if (attachment == null || !(attachment instanceof SSLSelectionKeyAttachment)) { sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(false); sslEngine.setNeedClientAuth(needClientAuth); sslEngine.setWantClientAuth(wantClientAuth); } else { - sslEngine = (SSLEngine) attachment; + sslEngine = ((SSLSelectionKeyAttachment) attachment).getSslEngine(); } ByteBuffer inputBB = protocolRequest.getSecuredInputByteBuffer(); @@ -146,8 +142,7 @@ inputBB.put((ByteBuffer) byteBuffer.flip()); byteBuffer.clear(); - boolean OK = Boolean.TRUE.equals( - sslEngine.getSession().getValue(SSLReadFilter.HANDSHAKE)); + boolean OK = sslEngine.getSession().isValid(); if (!OK) { // Handshake wasn't completed on prev step HandshakeStatus handshakeStatus = HandshakeStatus.NEED_UNWRAP; @@ -156,8 +151,7 @@ byteBuffer = SSLUtils.doHandshake(channel, byteBuffer, inputBB, outputBB, sslEngine, handshakeStatus, SSLUtils.getReadTimeout(), inputBB.position() > 0); - sslEngine.getSession().putValue(SSLReadFilter.HANDSHAKE, true); - key.attach(sslEngine); + key.attach(SSLSelectionKeyAttachment.create(key, sslEngine)); protocolRequest.setSSLEngine(sslEngine); // set "no available data" for secured output buffer outputBB.limit(outputBB.position()); @@ -196,8 +190,6 @@ if (byteRead > -1) { byteBuffer = SSLUtils.unwrapAll(byteBuffer, inputBB, sslEngine); protocolRequest.setByteBuffer(byteBuffer); - sslEngine.getSession().putValue(SSLReadFilter.DATA_DECODED, - Boolean.TRUE); } else { throw new EOFException(); } Index: portunif/src/test/java/com/sun/grizzly/portunif/SimpleProtocolHandler.java --- portunif/src/test/java/com/sun/grizzly/portunif/SimpleProtocolHandler.java Base (BASE) +++ portunif/src/test/java/com/sun/grizzly/portunif/SimpleProtocolHandler.java Locally Modified (Based On LOCAL) @@ -25,13 +25,14 @@ import com.sun.grizzly.Context; import com.sun.grizzly.Controller; +import com.sun.grizzly.util.SSLSelectionKeyAttachment; import com.sun.grizzly.util.OutputWriter; import com.sun.grizzly.util.SSLOutputWriter; +import com.sun.grizzly.util.SelectionKeyAttachment; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.util.logging.Level; -import javax.net.ssl.SSLEngine; /** * @author Alexey Stashok @@ -78,9 +79,9 @@ buffer.position(pos); } - Object attachment = protocolRequest.getSelectionKey().attachment(); - if (attachment instanceof SSLEngine) { - protocolRequest.setSSLEngine((SSLEngine) attachment); + Object attachment = SelectionKeyAttachment.getAttachment(protocolRequest.getSelectionKey()); + if (attachment instanceof SSLSelectionKeyAttachment) { + protocolRequest.setSSLEngine(((SSLSelectionKeyAttachment) attachment).getSslEngine()); allocateBuffers(protocolRequest); } else { protocolRequest.setSSLEngine(null);