Coverage Report - com.sun.grizzly.SSLConnectorHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
SSLConnectorHandler
76 %
228/299
67 %
95/142
0
SSLConnectorHandler$1
43 %
3/7
0 %
0/2
0
SSLConnectorHandler$2
100 %
2/2
N/A
0
SSLConnectorHandler$SSLInternalCallbackHandler
54 %
13/24
38 %
6/16
0
SSLConnectorHandler$SSLReadPostProcessor
100 %
6/6
N/A
0
SSLConnectorHandler$SSLWritePreProcessor
100 %
8/8
75 %
3/4
0
 
 1  
 /*
 2  
  * 
 3  
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 4  
  * 
 5  
  * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
 6  
  * 
 7  
  * The contents of this file are subject to the terms of either the GNU
 8  
  * General Public License Version 2 only ("GPL") or the Common Development
 9  
  * and Distribution License("CDDL") (collectively, the "License").  You
 10  
  * may not use this file except in compliance with the License. You can obtain
 11  
  * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 12  
  * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 13  
  * language governing permissions and limitations under the License.
 14  
  * 
 15  
  * When distributing the software, include this License Header Notice in each
 16  
  * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 17  
  * Sun designates this particular file as subject to the "Classpath" exception
 18  
  * as provided by Sun in the GPL Version 2 section of the License file that
 19  
  * accompanied this code.  If applicable, add the following below the License
 20  
  * Header, with the fields enclosed by brackets [] replaced by your own
 21  
  * identifying information: "Portions Copyrighted [year]
 22  
  * [name of copyright owner]"
 23  
  * 
 24  
  * Contributor(s):
 25  
  * 
 26  
  * If you wish your version of this file to be governed by only the CDDL or
 27  
  * only the GPL Version 2, indicate your decision by adding "[Contributor]
 28  
  * elects to include this software in this distribution under the [CDDL or GPL
 29  
  * Version 2] license."  If you don't indicate a single choice of license, a
 30  
  * recipient has the option to distribute your version of this file under
 31  
  * either the CDDL, the GPL Version 2 or to extend the choice of license to
 32  
  * its licensees as provided above.  However, if you add GPL Version 2 code
 33  
  * and therefore, elected the GPL Version 2 license, then the option applies
 34  
  * only if the new code is made subject to such option by the copyright
 35  
  * holder.
 36  
  *
 37  
  */
 38  
 package com.sun.grizzly;
 39  
 
 40  
 import com.sun.grizzly.async.AsyncQueueDataProcessor;
 41  
 import com.sun.grizzly.async.AsyncQueueReadable;
 42  
 import com.sun.grizzly.async.AsyncQueueWritable;
 43  
 import com.sun.grizzly.async.AsyncReadCallbackHandler;
 44  
 import com.sun.grizzly.async.AsyncReadCondition;
 45  
 import com.sun.grizzly.async.AsyncWriteCallbackHandler;
 46  
 import com.sun.grizzly.util.OutputWriter;
 47  
 import com.sun.grizzly.util.SSLOutputWriter;
 48  
 import com.sun.grizzly.util.SSLUtils;
 49  
 import java.io.EOFException;
 50  
 import java.io.IOException;
 51  
 import java.net.SocketAddress;
 52  
 import java.nio.BufferOverflowException;
 53  
 import java.nio.ByteBuffer;
 54  
 import java.nio.channels.AlreadyConnectedException;
 55  
 import java.nio.channels.NotYetConnectedException;
 56  
 import java.nio.channels.SelectableChannel;
 57  
 import java.nio.channels.SelectionKey;
 58  
 import java.nio.channels.SocketChannel;
 59  
 import java.util.concurrent.CountDownLatch;
 60  
 import java.util.concurrent.TimeUnit;
 61  
 import java.util.logging.Level;
 62  
 import java.util.logging.Logger;
 63  
 import javax.net.ssl.SSLContext;
 64  
 import javax.net.ssl.SSLEngine;
 65  
 import javax.net.ssl.SSLEngineResult;
 66  
 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
 67  
 import javax.net.ssl.SSLException;
 68  
 
 69  
 /**
 70  
  * <p>
 71  
  * Non blocking SSL Connector Handler. The recommended way to use this class
 72  
  * is by creating an external Controller and share the same SelectorHandler
 73  
  * instance.
 74  
  * </p><p>
 75  
  * Recommended
 76  
  * -----------
 77  
  * </p><p><pre><code>
 78  
  * Controller controller = new Controller();
 79  
  * // new SSLSelectorHandler(true) means the Selector will be used only
 80  
  * // for client operation (OP_READ, OP_WRITE, OP_CONNECT).
 81  
  * SSLSelectorHandler sslSelectorHandler = new SSLSelectorHandler(true);
 82  
  * controller.setSelectorHandler(sslSelectorHandler);
 83  
  * SSLConnectorHandler sslConnectorHandler = new SSLConnectorHandler();
 84  
  * sslConnectorHandler.connect(localhost,port, new SSLCallbackHandler(){...},
 85  
  *                             sslSelectorHandler);
 86  
  * SSLConnectorHandler sslConnectorHandler2 = new SSLConnectorHandler();
 87  
  * sslConnectorHandler2.connect(localhost,port, new SSLCallbackHandler(){...},
 88  
  *                             sslSelectorHandler);
 89  
  * </code></pre></p><p>
 90  
  * Not recommended (but still works)
 91  
  * ---------------------------------
 92  
  * </p><p><pre><code>
 93  
  * SSLConnectorHandler sslConnectorHandler = new SSLConnectorHandler();
 94  
  * sslConnectorHandler.connect(localhost,port);
 95  
  *
 96  
  * Internally, an new Controller will be created everytime connect(localhost,port)
 97  
  * is invoked, which has an impact on performance.
 98  
  *
 99  
  * As common comment: developer should be very careful if dealing directly with
 100  
  * <code>SSLConnectorHandler</code>'s underlying socket channel! In most cases
 101  
  * there is no need to do this, but use read, write methods provided
 102  
  * by <code>SSLConnectorHandler</code>
 103  
  * </code></pre></p>
 104  
  *
 105  
  * @author Alexey Stashok
 106  
  * @author Jeanfrancois Arcand
 107  
  */
 108  4355816
 public class SSLConnectorHandler implements ConnectorHandler<SSLSelectorHandler, 
 109  
         SSLCallbackHandler>, AsyncQueueWritable, AsyncQueueReadable {
 110  
     
 111  
     /**
 112  
      * Default Logger.
 113  
      */
 114  1
     private static Logger logger = Logger.getLogger("grizzly");
 115  
     
 116  
     /**
 117  
      * The underlying SSLSelectorHandler used to mange SelectionKeys.
 118  
      */
 119  
     private SSLSelectorHandler selectorHandler;
 120  
     
 121  
     /**
 122  
      * A {@link SSLCallbackHandler} handler invoked by the SSLSelectorHandler
 123  
      * when a non blocking operation is ready to be processed.
 124  
      */
 125  
     private SSLCallbackHandler callbackHandler;
 126  
     
 127  
     /*
 128  
      * An empty ByteBuffer used for handshaking
 129  
      */
 130  1
     private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
 131  
     
 132  
     /**
 133  
      * Input buffer for reading encrypted data from channel
 134  
      */
 135  
     private ByteBuffer securedInputBuffer;
 136  
     
 137  
     /**
 138  
      * Output buffer, which contains encrypted data ready for writing to channel
 139  
      */
 140  
     private ByteBuffer securedOutputBuffer;
 141  
     
 142  
     /**
 143  
      * Buffer, where application data could be written during a asynchronous handshaking.
 144  
      * It is set when user application calls: SSLConnectorHandler.handshake(appDataBuffer)
 145  
      * and references appDataBuffer.
 146  
      */
 147  
     private ByteBuffer asyncHandshakeBuffer;
 148  
     
 149  
     /**
 150  
      * The connection's SocketChannel.
 151  
      */
 152  
     private SocketChannel socketChannel;
 153  
     
 154  
     /**
 155  
      * Default {@link SSLContext}, created on
 156  
      * top of default <code>SSLConfiguration</code>
 157  
      */
 158  
     private static volatile SSLContext defaultSSLContext;
 159  
     
 160  
     /**
 161  
      * Is the connection established.
 162  
      */
 163  
     private volatile boolean isConnected;
 164  
     
 165  
     /**
 166  
      * Is the handshake phase completed
 167  
      */
 168  
     private volatile boolean isHandshakeDone;
 169  
     
 170  
     /**
 171  
      * The internal Controller used (in case not specified).
 172  
      */
 173  
     private Controller controller;
 174  
     
 175  
     /**
 176  
      * IsConnected Latch related
 177  
      */
 178  
     private CountDownLatch isConnectedLatch;
 179  
     
 180  
     /**
 181  
      * Are we creating a controller every run.
 182  
      */
 183  14
     private boolean isStandalone = false;
 184  
     
 185  
     /**
 186  
      * Is async handshake in progress
 187  
      */
 188  
     private boolean isProcessingAsyncHandshake;
 189  
     
 190  
     /**
 191  
      * Result of last{@link SSLEngine} operation
 192  
      */
 193  
     private SSLEngineResult sslLastOperationResult;
 194  
     
 195  
     /**
 196  
      * Current handshake status
 197  
      */
 198  
     private SSLEngineResult.HandshakeStatus handshakeStatus;
 199  
     
 200  
     /**
 201  
      * Current{@link SSLEngine} status
 202  
      */
 203  14
     private SSLEngineResult.Status sslEngineStatus = null;
 204  
     
 205  
     
 206  
     /**
 207  
      * Are we creating a controller every run.
 208  
      */
 209  
     private boolean delegateSSLTasks;
 210  
     
 211  
     /**
 212  
      * Connector's{@link SSLEngine}
 213  
      */
 214  
     private SSLEngine sslEngine;
 215  
     
 216  
     /**
 217  
      * Connector's {@link SSLContext}
 218  
      */
 219  
     private SSLContext sslContext;
 220  
     
 221  
     /**
 222  
      * SSL read postprocessor for <code>AsyncQueueReadable</code>
 223  
      */
 224  
     private volatile AsyncQueueDataProcessor sslReadPostProcessor;
 225  
 
 226  
     /**
 227  
      * SSL write preprocessor for <code>AsyncQueueWritable</code>
 228  
      */
 229  
     private volatile AsyncQueueDataProcessor sslWritePreProcessor;
 230  
     
 231  
     /**
 232  
      * Connector's write mode
 233  
      */
 234  
     private boolean isAsyncWriteQueueMode;
 235  
     
 236  
     /**
 237  
      * Connector's read mode
 238  
      */
 239  
     private boolean isAsyncReadQueueMode;
 240  
 
 241  
     public SSLConnectorHandler() {
 242  14
         this(defaultSSLContext);
 243  14
     }
 244  
     
 245  
     public SSLConnectorHandler(SSLConfig sslConfig) {
 246  0
         this(sslConfig.createSSLContext());
 247  0
     }
 248  
     
 249  14
     public SSLConnectorHandler(SSLContext sslContext) {
 250  14
         if (sslContext == null) {
 251  1
             if (defaultSSLContext == null) {
 252  1
                 synchronized (SSLConnectorHandler.class) {
 253  1
                     if (defaultSSLContext == null) {
 254  1
                         defaultSSLContext = SSLConfig.DEFAULT_CONFIG.createSSLContext();
 255  
                     }
 256  1
                 }
 257  
             }
 258  
             
 259  1
             sslContext = defaultSSLContext;
 260  
         }
 261  
         
 262  14
         this.sslContext = sslContext;
 263  14
     }
 264  
     
 265  
     public boolean getDelegateSSLTasks() {
 266  0
         return delegateSSLTasks;
 267  
     }
 268  
     
 269  
     public void setDelegateSSLTasks(boolean delegateSSLTasks) {
 270  0
         this.delegateSSLTasks = delegateSSLTasks;
 271  0
     }
 272  
     
 273  
     /**
 274  
      * Connect to hostname:port. When an aysnchronous event happens (e.g
 275  
      * OP_READ or OP_WRITE), the {@link Controller} will invoke
 276  
      * the {@link CallbackHandler}.
 277  
      * @param remoteAddress remote address to connect
 278  
      * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when
 279  
      *        a non blocking operation is ready to be handled. When null, all 
 280  
      *        read and write operation will be delegated to the default
 281  
      *        {@link ProtocolChain} and its list of {@link ProtocolFilter} 
 282  
      *        . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}.
 283  
      * @throws java.io.IOException
 284  
      */
 285  
     public void connect(SocketAddress remoteAddress, SSLCallbackHandler callbackHandler) throws IOException {
 286  104
         connect(remoteAddress, null, callbackHandler);
 287  104
     }
 288  
     
 289  
     /**
 290  
      * Connect to hostname:port. When an aysnchronous event happens (e.g
 291  
      * OP_READ or OP_WRITE), the {@link Controller} will invoke
 292  
      * the {@link CallbackHandler}.
 293  
      * @param remoteAddress remote address to connect
 294  
      * @param localAddress local address to bind
 295  
      * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when
 296  
      *        a non blocking operation is ready to be handled. When null, all 
 297  
      *        read and write operation will be delegated to the default
 298  
      *        {@link ProtocolChain} and its list of {@link ProtocolFilter} 
 299  
      *        . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}.
 300  
      * @throws java.io.IOException
 301  
      */
 302  
     public void connect(SocketAddress remoteAddress, SocketAddress localAddress, SSLCallbackHandler callbackHandler) throws IOException {
 303  104
         if (controller == null) {
 304  0
             throw new IllegalStateException("Controller cannot be null");
 305  
         }
 306  
         
 307  104
         connect(remoteAddress, localAddress, callbackHandler, (SSLSelectorHandler) controller.getSelectorHandler(protocol()));
 308  104
     }
 309  
     
 310  
     /**
 311  
      * Connect to hostname:port. When an aysnchronous event happens (e.g
 312  
      * OP_READ or OP_WRITE), the {@link Controller} will invoke
 313  
      * the {@link CallbackHandler}.
 314  
      * @param remoteAddress remote address to connect
 315  
      * @param callbackHandler the handler invoked by the Controller when
 316  
      *        an non blocking operation is ready to be handled.
 317  
      * @param selectorHandler an instance of SelectorHandler.
 318  
      * @throws java.io.IOException
 319  
      */
 320  
     public void connect(SocketAddress remoteAddress, SSLCallbackHandler callbackHandler, SSLSelectorHandler selectorHandler) throws IOException {
 321  0
         connect(remoteAddress, null, callbackHandler, selectorHandler);
 322  0
     }
 323  
     
 324  
     /**
 325  
      * Connect to hostname:port. When an aysnchronous event happens (e.g
 326  
      * OP_READ or OP_WRITE), the {@link Controller} will invoke
 327  
      * the {@link CallbackHandler}.
 328  
      * @param remoteAddress remote address to connect
 329  
      * @param localAddress local address to bin
 330  
      * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when
 331  
      *        a non blocking operation is ready to be handled. When null, all 
 332  
      *        read and write operation will be delegated to the default
 333  
      *        {@link ProtocolChain} and its list of {@link ProtocolFilter} 
 334  
      *        . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}.
 335  
      * @param selectorHandler an instance of SelectorHandler.
 336  
      * @throws java.io.IOException
 337  
      */
 338  
     public void connect(SocketAddress remoteAddress, SocketAddress localAddress,
 339  
             SSLCallbackHandler callbackHandler,
 340  
             SSLSelectorHandler selectorHandler) throws IOException {
 341  114
         if (isConnected) {
 342  0
             throw new AlreadyConnectedException();
 343  
         }
 344  
         
 345  114
         if (controller == null) {
 346  0
             throw new IllegalStateException("Controller cannot be null");
 347  
         }
 348  
         
 349  114
         if (selectorHandler == null) {
 350  0
             throw new IllegalStateException("SelectorHandler cannot be null");
 351  
         }
 352  
         
 353  114
         this.selectorHandler = selectorHandler;
 354  114
         if (callbackHandler == null){
 355  0
             callbackHandler = new DefaultCallbackHandler(this);
 356  
         } else {
 357  114
             this.callbackHandler = callbackHandler;
 358  
         }
 359  
         
 360  
         // Wait for the onConnect to be invoked.
 361  114
         isConnectedLatch = new CountDownLatch(1);
 362  
         
 363  114
         selectorHandler.connect(remoteAddress, localAddress, 
 364  
                 new SSLInternalCallbackHandler());
 365  
         
 366  
         try {
 367  114
             isConnectedLatch.await(30, TimeUnit.SECONDS);
 368  0
         } catch (InterruptedException ex) {
 369  0
             throw new IOException(ex.getMessage());
 370  114
         }
 371  114
     }
 372  
     
 373  
     /**
 374  
      * Connect to hostname:port. Internally an instance of Controller and
 375  
      * its default SelectorHandler will be created everytime this method is
 376  
      * called. This method should be used only and only if no external
 377  
      * Controller has been initialized.
 378  
      * @param remoteAddress remote address to connect
 379  
      * @throws java.io.IOException
 380  
      */
 381  
     public void connect(SocketAddress remoteAddress) throws IOException {
 382  10
         connect(remoteAddress, (SocketAddress) null);
 383  10
     }
 384  
     
 385  
     /**
 386  
      * Connect to hostname:port. Internally an instance of Controller and
 387  
      * its default SelectorHandler will be created everytime this method is
 388  
      * called. This method should be used only and only if no external
 389  
      * Controller has been initialized.
 390  
      * @param remoteAddress remote address to connect
 391  
      * @throws java.io.IOException
 392  
      * @param localAddress local address to bin
 393  
      */
 394  
     public void connect(SocketAddress remoteAddress, SocketAddress localAddress) throws IOException {
 395  10
         if (isConnected) {
 396  0
             throw new AlreadyConnectedException();
 397  
         }
 398  
         
 399  10
         if (controller == null) {
 400  10
             isStandalone = true;
 401  10
             controller = new Controller();
 402  10
             controller.setSelectorHandler(new SSLSelectorHandler(true));
 403  10
             DefaultPipeline pipeline = new DefaultPipeline();
 404  10
             pipeline.initPipeline();
 405  10
             pipeline.startPipeline();
 406  10
             controller.setPipeline(pipeline);
 407  
             
 408  10
             final CountDownLatch latch = new CountDownLatch(1);
 409  10
             controller.addStateListener(new ControllerStateListenerAdapter() {
 410  
                 @Override
 411  
                 public void onReady() {
 412  10
                     latch.countDown();
 413  10
                 }
 414  
                 
 415  
                 @Override
 416  
                 public void onException(Throwable e) {
 417  0
                     if (latch.getCount() > 0) {
 418  0
                         logger.log(Level.SEVERE, "Error occured on Controller startup: ", e);
 419  
                     }
 420  
                     
 421  0
                     latch.countDown();
 422  0
                 }
 423  
             });
 424  10
             callbackHandler = new DefaultCallbackHandler(this,false);        
 425  10
             new Thread(controller, "GrizzlySSLConnectorHandler-Controller").start();
 426  
             
 427  
             try {
 428  10
                 latch.await();
 429  0
             } catch (InterruptedException ex) {
 430  10
             }
 431  
         }
 432  
         
 433  10
         connect(remoteAddress, localAddress, callbackHandler, (SSLSelectorHandler)
 434  
                 controller.getSelectorHandler(protocol()));
 435  10
     }
 436  
     
 437  
     /**
 438  
      * Initiate SSL handshake phase.
 439  
      * Handshake is required to be done after connection established.
 440  
      *
 441  
      * @param byteBuffer Application {@link ByteBuffer}, where application data
 442  
      * will be stored
 443  
      * @param blocking true, if handshake should be done in blocking mode, for non-blocking false
 444  
      * @return If blocking parameter is true - method should always return true if handshake is done,
 445  
      * or throw IOException otherwise. For non-blocking mode method returns true if handshake is done, or false
 446  
      * if handshake will be completed in non-blocking manner.
 447  
      * If False returned - <code>SSLConnectorHandler</code> will call callbackHandler.onHandshake() to notify
 448  
      * about finishing handshake phase.
 449  
      * @throws java.io.IOException if some error occurs during processing I/O operations/
 450  
      */
 451  
     public boolean handshake(ByteBuffer byteBuffer, boolean blocking) throws IOException {
 452  114
         sslEngine.beginHandshake();
 453  114
         handshakeStatus = sslEngine.getHandshakeStatus();
 454  
         
 455  114
         if (blocking) {
 456  103
             SSLUtils.doHandshake(socketChannel, byteBuffer, securedInputBuffer, 
 457  
                     securedOutputBuffer, sslEngine, handshakeStatus);
 458  103
             securedOutputBuffer.limit(securedOutputBuffer.position());
 459  103
             finishHandshake();
 460  
             
 461  
             // Sync should be always done
 462  103
             return true;
 463  
         } else {
 464  11
             return doAsyncHandshake(byteBuffer);
 465  
         }
 466  
     }
 467  
     
 468  
     /**
 469  
      * Read bytes. If blocking is set to <tt>true</tt>, a pool of temporary
 470  
      * {@link Selector} will be used to read bytes.
 471  
      * @param byteBuffer The byteBuffer to store bytes.
 472  
      * @param blocking <tt>true</tt> if a a pool of temporary Selector
 473  
      *        is required to handle a blocking read.
 474  
      * @return number of bytes read from a channel.
 475  
      * Be careful, because return value represents the length of encrypted data,
 476  
      * which was read from a channel. Don't use return value to determine the
 477  
      * availability of a decrypted data to process, but use byteBuffer.remaining().
 478  
      * @throws java.io.IOException
 479  
      */
 480  
     public long read(ByteBuffer byteBuffer, boolean blocking) throws IOException {
 481  80971
         if (!isConnected) {
 482  0
             throw new NotYetConnectedException();
 483  
         }
 484  
         
 485  80971
         if (blocking) {
 486  91
             return SSLUtils.doSecureRead(socketChannel, sslEngine,
 487  
                     byteBuffer, securedInputBuffer);
 488  
         } else {
 489  80880
             isAsyncReadQueueMode = false;
 490  80880
             int nRead = doReadAsync(byteBuffer);
 491  
             
 492  80879
             if (nRead == 0) {
 493  39604
                 registerSelectionKeyFor(SelectionKey.OP_READ);
 494  
             }
 495  
             
 496  80879
             return nRead;
 497  
         }
 498  
     }
 499  
     
 500  
     
 501  
     /**
 502  
      * Writes bytes. If blocking is set to <tt>true</tt>, a pool of temporary
 503  
      * {@link Selector} will be used to writes bytes.
 504  
      * @param byteBuffer The byteBuffer to write.
 505  
      * @param blocking <tt>true</tt> if a a pool of temporary Selector
 506  
      *        is required to handle a blocking write.
 507  
      * @return number of bytes written on a channel.
 508  
      * Be careful, as non-crypted data is passed, but crypted data is written
 509  
      * on channel. Don't use return value to determine the
 510  
      * number of bytes from original buffer, which were written.
 511  
      * @throws java.io.IOException
 512  
      */
 513  
     public long write(ByteBuffer byteBuffer, boolean blocking) throws IOException {
 514  192
         if (!isConnected) {
 515  0
             throw new NotYetConnectedException();
 516  
         }
 517  
         
 518  192
         if (blocking) {
 519  91
             long nWrite = SSLOutputWriter.flushChannel(socketChannel,
 520  
                     byteBuffer, securedOutputBuffer, sslEngine);
 521  
             // Mark securedOutputBuffer as empty
 522  91
             securedOutputBuffer.position(securedOutputBuffer.limit());
 523  91
             return nWrite;
 524  
         } else {
 525  101
             if (callbackHandler == null) {
 526  0
                 throw new IllegalStateException("Non blocking write needs a CallbackHandler");
 527  
             }
 528  
             
 529  101
             isAsyncWriteQueueMode = false;
 530  101
             int nWrite = 1;
 531  101
             int totalWrite = 0;
 532  
             
 533  202
             while (nWrite > 0 &&
 534  
                     (byteBuffer.hasRemaining() || securedOutputBuffer.hasRemaining())) {
 535  101
                 nWrite = doWriteAsync(byteBuffer);
 536  101
                 totalWrite += nWrite;
 537  
             }
 538  
             
 539  101
             if (byteBuffer.hasRemaining() || securedOutputBuffer.hasRemaining()) {
 540  0
                 registerSelectionKeyFor(SelectionKey.OP_WRITE);
 541  
             }
 542  
             
 543  101
             return totalWrite;
 544  
         }
 545  
     }
 546  
     
 547  
     
 548  
     /**
 549  
      * {@inheritDoc}
 550  
      */
 551  
     public void writeToAsyncQueue(ByteBuffer buffer) throws IOException {
 552  511000
         writeToAsyncQueue(buffer, null);
 553  510984
     }
 554  
 
 555  
 
 556  
     /**
 557  
      * {@inheritDoc}
 558  
      */
 559  
     public void writeToAsyncQueue(ByteBuffer buffer, 
 560  
             AsyncWriteCallbackHandler callbackHandler) throws IOException {
 561  510834
         writeToAsyncQueue(buffer, callbackHandler, obtainSSLWritePreProcessor());
 562  510985
     }
 563  
 
 564  
 
 565  
     /**
 566  
      * {@inheritDoc}
 567  
      */
 568  
     public void writeToAsyncQueue(ByteBuffer buffer, 
 569  
             AsyncWriteCallbackHandler callbackHandler,
 570  
             AsyncQueueDataProcessor writePreProcessor) throws IOException {
 571  511000
         writeToAsyncQueue(buffer, callbackHandler, writePreProcessor, false);
 572  510985
     }
 573  
 
 574  
     
 575  
     /**
 576  
      * {@inheritDoc}
 577  
      */
 578  
     public void writeToAsyncQueue(ByteBuffer buffer, 
 579  
             AsyncWriteCallbackHandler callbackHandler,
 580  
             AsyncQueueDataProcessor writePreProcessor,
 581  
             boolean isCloneByteBuffer) throws IOException {
 582  511000
         isAsyncWriteQueueMode = true;
 583  511000
         selectorHandler.getAsyncQueueWriter().write(
 584  
                 socketChannel.keyFor(selectorHandler.getSelector()), buffer,
 585  
                 callbackHandler, writePreProcessor, isCloneByteBuffer);
 586  510985
     }
 587  
 
 588  
     
 589  
     /**
 590  
      * {@inheritDoc}
 591  
      */
 592  
     public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer)
 593  
             throws IOException {
 594  0
         writeToAsyncQueue(dstAddress, buffer);
 595  0
     }
 596  
 
 597  
 
 598  
     /**
 599  
      * {@inheritDoc}
 600  
      */
 601  
     public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer, 
 602  
             AsyncWriteCallbackHandler callbackHandler) throws IOException {
 603  0
         writeToAsyncQueue(dstAddress, buffer, callbackHandler, obtainSSLWritePreProcessor());
 604  0
     }
 605  
 
 606  
 
 607  
     /**
 608  
      * {@inheritDoc}
 609  
      */
 610  
     public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer, 
 611  
             AsyncWriteCallbackHandler callbackHandler, 
 612  
             AsyncQueueDataProcessor writePreProcessor) throws IOException {
 613  0
         writeToAsyncQueue(dstAddress, buffer, callbackHandler, writePreProcessor);
 614  0
     }
 615  
 
 616  
     
 617  
     /**
 618  
      * {@inheritDoc}
 619  
      */
 620  
     public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer, 
 621  
             AsyncWriteCallbackHandler callbackHandler, 
 622  
             AsyncQueueDataProcessor writePreProcessor, boolean isCloneByteBuffer)
 623  
             throws IOException {
 624  0
         isAsyncWriteQueueMode = true;
 625  0
         selectorHandler.getAsyncQueueWriter().write(
 626  
                 socketChannel.keyFor(selectorHandler.getSelector()), dstAddress,
 627  
                 buffer, callbackHandler, writePreProcessor, isCloneByteBuffer);
 628  0
     }
 629  
 
 630  
     
 631  
     /**
 632  
      * {@inheritDoc}
 633  
      */
 634  
     public void readFromAsyncQueue(ByteBuffer buffer, 
 635  
             AsyncReadCallbackHandler callbackHandler) throws IOException {
 636  0
         readFromAsyncQueue(buffer, callbackHandler, null);
 637  0
     }
 638  
 
 639  
 
 640  
     /**
 641  
      * {@inheritDoc}
 642  
      */
 643  
     public void readFromAsyncQueue(ByteBuffer buffer, 
 644  
             AsyncReadCallbackHandler callbackHandler, 
 645  
             AsyncReadCondition condition) throws IOException {
 646  100
         readFromAsyncQueue(buffer, callbackHandler, condition, 
 647  
                 obtainSSLReadPostProcessor());
 648  100
     }
 649  
 
 650  
 
 651  
     /**
 652  
      * {@inheritDoc}
 653  
      */
 654  
     public void readFromAsyncQueue(ByteBuffer buffer, 
 655  
             AsyncReadCallbackHandler callbackHandler, 
 656  
             AsyncReadCondition condition, 
 657  
             AsyncQueueDataProcessor readPostProcessor) throws IOException {
 658  100
         isAsyncReadQueueMode = true;
 659  100
         selectorHandler.getAsyncQueueReader().read(
 660  
                 socketChannel.keyFor(selectorHandler.getSelector()), buffer,
 661  
                 callbackHandler, condition, readPostProcessor);
 662  100
     }
 663  
 
 664  
     
 665  
     /**
 666  
      * Close the underlying connection.
 667  
      */
 668  
     public void close() throws IOException {
 669  114
         if (socketChannel != null) {
 670  114
             if (isConnected) {
 671  
                 try {
 672  114
                     if (securedOutputBuffer.hasRemaining()) {
 673  
                         // if there is something is securedOutputBuffer - flush it
 674  1
                         OutputWriter.flushChannel(socketChannel, securedOutputBuffer);
 675  
                     }
 676  
                     
 677  
                     // Close secure outbound channel and flush data
 678  113
                     sslEngine.closeOutbound();
 679  113
                     SSLUtils.wrap(EMPTY_BUFFER, securedOutputBuffer, sslEngine);
 680  113
                     OutputWriter.flushChannel(socketChannel, securedOutputBuffer);
 681  1
                 } catch (IOException e) {
 682  1
                     logger.log(Level.FINE, "IOException during closing the connector.", e);
 683  113
                 }
 684  
             }
 685  
             
 686  114
             if (selectorHandler != null) {
 687  114
                 SelectionKey key = socketChannel.keyFor(selectorHandler.getSelector());
 688  
                 
 689  114
                 if (key == null) {
 690  0
                     return;
 691  
                 }
 692  114
                 selectorHandler.getSelectionKeyHandler().close(key);
 693  
             }
 694  
             
 695  114
             socketChannel.close();
 696  
         }
 697  
         
 698  114
         if (controller != null && isStandalone) {
 699  10
             controller.stop();
 700  10
             controller = null;
 701  
         }
 702  
         
 703  114
         sslEngine = null;
 704  114
         asyncHandshakeBuffer = null;
 705  114
         isStandalone = false;
 706  114
         isConnected = false;
 707  114
         isHandshakeDone = false;
 708  114
     }
 709  
     
 710  
     
 711  
     /**
 712  
      * Finish handling the OP_CONNECT interest ops.
 713  
      * @param key - a {@link SelectionKey}
 714  
      */
 715  
     public void finishConnect(SelectionKey key) throws IOException{
 716  
         try {
 717  114
             if (logger.isLoggable(Level.FINE)) {
 718  0
                 logger.log(Level.FINE, "Finish connect");
 719  
             }
 720  
 
 721  114
             socketChannel = (SocketChannel) key.channel();
 722  114
             socketChannel.finishConnect();
 723  114
             isConnected = socketChannel.isConnected();
 724  114
             if (isConnected) {
 725  114
                 initSSLEngineIfRequired();
 726  
             }
 727  0
         } catch (IOException e) {
 728  0
             throw e;
 729  
         } finally {
 730  114
             isConnectedLatch.countDown();
 731  114
         }
 732  114
     }
 733  
     
 734  
     /**
 735  
      * Changes SSLConnectorHandler state, after handshake operation is done.
 736  
      * Normally should not be called by outside Grizzly, just in case when custom
 737  
      * handshake code was used.
 738  
      */
 739  
     public void finishHandshake() {
 740  114
         isProcessingAsyncHandshake = false;
 741  114
         isHandshakeDone = true;
 742  114
     }
 743  
     
 744  
     /**
 745  
      * A token decribing the protocol supported by an implementation of this
 746  
      * interface
 747  
      * @return this {@link ConnectorHandler}'s protocol
 748  
      */
 749  
     public Controller.Protocol protocol() {
 750  218
         return Controller.Protocol.TLS;
 751  
     }
 752  
     
 753  
     
 754  
     /**
 755  
      * Is the underlying SocketChannel connected.
 756  
      * @return <tt>true</tt> if connected, otherwise <tt>false</tt>
 757  
      */
 758  
     public boolean isConnected() {
 759  124
         return isConnected && socketChannel.isOpen();
 760  
     }
 761  
     
 762  
     /**
 763  
      * Is the underlying SocketChannel connected.
 764  
      * @return <tt>true</tt> if connected, otherwise <tt>false</tt>
 765  
      */
 766  
     public boolean isHandshakeDone() {
 767  104
         return isHandshakeDone && !isProcessingAsyncHandshake;
 768  
     }
 769  
 
 770  
     
 771  
     /**
 772  
      * Get SSLConnector's {@link SSLContext}
 773  
      */
 774  
     public SSLContext getSSLContext() {
 775  0
         return sslContext;
 776  
     }
 777  
     
 778  
     
 779  
     /**
 780  
      * Set {@link SSLContext}.
 781  
      * Use this method to change SSLConnectorHandler configuration.
 782  
      * New configuration will become active only after SSLConnector
 783  
      * will be closed and connected again.
 784  
      */
 785  
     public void setSSLContext(SSLContext sslContext) {
 786  0
         this.sslContext = sslContext;
 787  0
     }
 788  
     
 789  
     
 790  
     /**
 791  
      * Configure SSLConnectorHandler's SSL settings.
 792  
      *
 793  
      * Use this method to change SSLConnectorHandler configuration.
 794  
      * New configuration will become active only after SSLConnector
 795  
      * will be closed and connected again.
 796  
      */
 797  
     public void configure(SSLConfig sslConfig) {
 798  0
         this.sslContext = sslConfig.createSSLContext();
 799  0
     }
 800  
     
 801  
     /**
 802  
      * Returns SSLConnector's{@link SSLEngine}
 803  
      * @return{@link SSLEngine}
 804  
      */
 805  
     public SSLEngine getSSLEngine() {
 806  0
         return sslEngine;
 807  
     }
 808  
     
 809  
     /**
 810  
      * Set{@link SSLEngine}
 811  
      * @param sslEngine{@link SSLEngine}
 812  
      */
 813  
     public void setSSLEngine(SSLEngine sslEngine) {
 814  0
         this.sslEngine = sslEngine;
 815  0
     }
 816  
     
 817  
     /**
 818  
      * Returns <code>SSLConnectorHandler</code>'s secured input buffer, it
 819  
      * uses for reading data from a socket channel.
 820  
      * @return secured input {@link ByteBuffer}
 821  
      */
 822  
     public ByteBuffer getSecuredInputBuffer() {
 823  0
         return securedInputBuffer;
 824  
     }
 825  
     
 826  
     /**
 827  
      * Returns <code>SSLConnectorHandler</code>'s secured output buffer, it
 828  
      * uses for writing data to a socket channel.
 829  
      * @return secured output {@link ByteBuffer}
 830  
      */
 831  
     public ByteBuffer getSecuredOutputBuffer() {
 832  0
         return securedOutputBuffer;
 833  
     }
 834  
     
 835  
     /**
 836  
      * Return the  {@link Controller}
 837  
      * @return the  {@link Controller}
 838  
      */
 839  
     public Controller getController() {
 840  0
         return controller;
 841  
     }
 842  
     
 843  
     
 844  
     /**
 845  
      * Set the {@link Controller} to use with this instance.
 846  
      * @param controller the {@link Controller} to use with this instance.
 847  
      */
 848  
     public void setController(Controller controller) {
 849  311
         this.controller = controller;
 850  311
     }
 851  
     
 852  
     
 853  
     /**
 854  
      * Return the current {@link SocketChannel} used.
 855  
      * @return the current {@link SocketChannel} used.
 856  
      */
 857  
     public SelectableChannel getUnderlyingChannel() {
 858  0
         return socketChannel;
 859  
     }
 860  
     
 861  
     
 862  
     /**
 863  
      * Set the {@link SocketChannel}.
 864  
      * @param the {@link SocketChannel} to use.
 865  
      */  
 866  
     protected void setUnderlyingChannel(SocketChannel socketChannel){
 867  10
         this.socketChannel = socketChannel;
 868  10
     }
 869  
     
 870  
     
 871  
     /**
 872  
      * Return the {@link CallbackHandler}. 
 873  
      * @return the {@link CallbackHandler}. 
 874  
      */
 875  
     public SSLCallbackHandler getCallbackHandler() {
 876  0
         return callbackHandler;
 877  
     }
 878  
     
 879  
 
 880  
     /**
 881  
      * Set the {@link CallbackHandler}. 
 882  
      * @param callbackHandler the {@link CallbackHandler}. 
 883  
      */   
 884  
     public void setCallbackHandler(SSLCallbackHandler callbackHandler) {
 885  0
         this.callbackHandler = callbackHandler;
 886  0
     }
 887  
     
 888  
     
 889  
     /**
 890  
      * Return the associated {@link SelectorHandler}.
 891  
      * @return the associated {@link SelectorHandler}.
 892  
      */
 893  
     public SSLSelectorHandler getSelectorHandler() {
 894  0
         return selectorHandler;
 895  
     }
 896  
     
 897  
     /**
 898  
      * Gets the size of the largest application buffer that may occur when
 899  
      * using this session.
 900  
      * SSLEngine application data buffers must be large enough to hold the
 901  
      * application data from any inbound network application data packet
 902  
      * received. Typically, outbound application data buffers can be of any size.
 903  
      *
 904  
      * (javadoc is taken from SSLSession.getApplicationBufferSize())
 905  
      * @return largets application buffer size, which may occur
 906  
      */
 907  
     public int getApplicationBufferSize() {
 908  197
         initSSLEngineIfRequired();
 909  197
         return sslEngine.getSession().getApplicationBufferSize();
 910  
     }
 911  
         
 912  
     /**
 913  
      * Read a data from channel in async mode and decrypt
 914  
      * @param byteBuffer buffer for decrypted data
 915  
      * @return number of bytes read from a channel
 916  
      * @throws java.io.IOException
 917  
      */
 918  
     private int doReadAsync(ByteBuffer byteBuffer) throws IOException {
 919  
         // Clear or compact secured input buffer
 920  80925
         clearOrCompactBuffer(securedInputBuffer);
 921  
         
 922  
         // Read data to secured buffer
 923  80925
         int bytesRead = socketChannel.read(securedInputBuffer);
 924  
         
 925  80924
         if (bytesRead == -1) {
 926  
             try {
 927  0
                 sslEngine.closeInbound();
 928  
                 // check if there is some secured data still available
 929  0
                 if (securedInputBuffer.position() == 0 ||
 930  
                         sslEngineStatus == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
 931  0
                     return -1;
 932  
                 }
 933  0
             } catch (SSLException e) {
 934  0
                 return -1;
 935  0
             }
 936  
         }
 937  
         
 938  80924
         securedInputBuffer.flip();
 939  
         
 940  80924
         if (bytesRead == 0 && !securedInputBuffer.hasRemaining()) {
 941  39616
             return 0;
 942  
         }
 943  
         
 944  41308
         int bytesProduced = unwrapAll(byteBuffer);
 945  
         
 946  41308
         if (bytesProduced == 0) {
 947  45
             if (sslEngineStatus == SSLEngineResult.Status.CLOSED) {
 948  0
                 return -1;
 949  45
             } else if (sslEngineStatus == SSLEngineResult.Status.BUFFER_OVERFLOW) {
 950  0
                 throw new BufferOverflowException();
 951  
             }
 952  
         }
 953  
         
 954  41308
         return bytesRead;
 955  
     }
 956  
     
 957  
     private int unwrapAll(ByteBuffer byteBuffer) throws SSLException {
 958  49651
         SSLEngineResult result = null;
 959  49651
         int bytesProduced = 0;
 960  
         
 961  
         do {
 962  103231
             result = sslEngine.unwrap(securedInputBuffer, byteBuffer);
 963  103231
             bytesProduced += result.bytesProduced();
 964  
             // During handshake phase several unwrap actions could be executed on read data
 965  103231
         } while (result.getStatus() == SSLEngineResult.Status.OK && 
 966  
                 (isHandshakeDone || (result.getHandshakeStatus() == 
 967  
                 SSLEngineResult.HandshakeStatus.NEED_UNWRAP && 
 968  
                 result.bytesProduced() == 0)));
 969  
         
 970  49651
         updateSSLEngineStatus(result);
 971  49651
         return bytesProduced;
 972  
     }
 973  
     
 974  
     /**
 975  
      * Write secured data to channel in async mode
 976  
      *
 977  
      * @param byteBuffer non-crypted data buffer
 978  
      * @return number of bytes written on a channel.
 979  
      * Be careful, as non-crypted data is passed, but crypted data is written
 980  
      * on channel. Don't use return value to determine,
 981  
      * number of bytes from original buffer, which were written.
 982  
      * @throws java.io.IOException
 983  
      */
 984  
     private int doWriteAsync(ByteBuffer byteBuffer) throws IOException {
 985  101
         if (securedOutputBuffer.hasRemaining() && !flushSecuredOutputBuffer()) {
 986  0
             return 0;
 987  
         }
 988  
         
 989  101
         securedOutputBuffer.clear();
 990  101
         SSLEngineResult result = SSLUtils.wrap(byteBuffer, securedOutputBuffer, sslEngine);
 991  
         
 992  101
         updateSSLEngineStatus(result);
 993  
         
 994  101
         return socketChannel.write(securedOutputBuffer);
 995  
         
 996  
     }
 997  
     
 998  
     /**
 999  
      * Perform an SSL handshake in async mode.
 1000  
      * @param byteBuffer The application {@link ByteBuffer}
 1001  
      *
 1002  
      * @throws IOException if the handshake fail.
 1003  
      */
 1004  
     private boolean doAsyncHandshake(ByteBuffer byteBuffer) throws IOException {
 1005  
         SSLEngineResult result;
 1006  33
         isProcessingAsyncHandshake = true;
 1007  33
         asyncHandshakeBuffer = byteBuffer;
 1008  78
         while (handshakeStatus != HandshakeStatus.FINISHED) {
 1009  1
             switch (handshakeStatus) {
 1010  
                 case NEED_WRAP:
 1011  44
                     result = SSLUtils.wrap(EMPTY_BUFFER, securedOutputBuffer, sslEngine);
 1012  44
                     updateSSLEngineStatus(result);
 1013  1
                     switch (result.getStatus()) {
 1014  
                         case OK:
 1015  44
                             if (!flushSecuredOutputBuffer()) {
 1016  0
                                 return false;
 1017  
                             }
 1018  
                             break;
 1019  
                         default:
 1020  0
                             throw new IOException("Handshaking error: " + result.getStatus());
 1021  
                     }
 1022  
                     
 1023  44
                     if (handshakeStatus != HandshakeStatus.NEED_UNWRAP) {
 1024  22
                         break;
 1025  
                     }
 1026  
                 case NEED_UNWRAP:
 1027  45
                     int bytesRead = doReadAsync(byteBuffer);
 1028  45
                     if (bytesRead == -1) {
 1029  
                         try {
 1030  0
                             sslEngine.closeInbound();
 1031  0
                         } catch (IOException e) {
 1032  0
                             logger.log(Level.FINE, "Exception occured when closing sslEngine inbound.", e);
 1033  0
                         }
 1034  
                         
 1035  0
                         throw new EOFException("Connection closed");
 1036  45
                     } else if (bytesRead == 0 && sslLastOperationResult.bytesConsumed() == 0) {
 1037  22
                         registerSelectionKeyFor(SelectionKey.OP_READ);
 1038  22
                         return false;
 1039  
                     }
 1040  
                     
 1041  23
                     if (handshakeStatus != HandshakeStatus.NEED_TASK) {
 1042  12
                         break;
 1043  
                     }
 1044  
                 case NEED_TASK:
 1045  11
                     handshakeStatus = executeDelegatedTask();
 1046  11
                     break;
 1047  
                 default:
 1048  0
                     throw new RuntimeException("Invalid Handshaking State" + handshakeStatus);
 1049  
             }
 1050  
         }
 1051  
         
 1052  11
         if (isProcessingAsyncHandshake) {
 1053  11
             finishHandshake();
 1054  
         }
 1055  
         
 1056  11
         asyncHandshakeBuffer = null;
 1057  11
         return true;
 1058  
     }
 1059  
     
 1060  
     /**
 1061  
      * Complete hanshakes operations.
 1062  
      * @return SSLEngineResult.HandshakeStatus
 1063  
      */
 1064  
     private SSLEngineResult.HandshakeStatus executeDelegatedTask() {
 1065  
         Runnable runnable;
 1066  22
         while ((runnable = sslEngine.getDelegatedTask()) != null) {
 1067  11
             runnable.run();
 1068  
         }
 1069  
         
 1070  11
         return sslEngine.getHandshakeStatus();
 1071  
     }
 1072  
 
 1073  
     /**
 1074  
      * Update <code>SSLConnectorHandler</code> internal status with
 1075  
      * last{@link SSLEngine} operation result.
 1076  
      *
 1077  
      * @param result last{@link SSLEngine} operation result
 1078  
      */
 1079  
     private void updateSSLEngineStatus(SSLEngineResult result) {
 1080  559798
         sslLastOperationResult = result;
 1081  559801
         sslEngineStatus = result.getStatus();
 1082  559800
         handshakeStatus = result.getHandshakeStatus();
 1083  559801
     }
 1084  
     
 1085  
     /**
 1086  
      * Clears buffer if there is no info available, or compact buffer otherwise.
 1087  
      * @param buffer byte byffer
 1088  
      */
 1089  
     private static void clearOrCompactBuffer(ByteBuffer buffer) {
 1090  89268
         if (!buffer.hasRemaining()) {
 1091  89151
             buffer.clear();
 1092  117
         } else if (buffer.remaining() < buffer.capacity()) {
 1093  23
             buffer.compact();
 1094  
         }
 1095  89268
     }
 1096  
     
 1097  
     /**
 1098  
      * Gets <code>SSLConnectorHandler</code> {@link SelectionKey}
 1099  
      * @return {@link SelectionKey}
 1100  
      */
 1101  
     private SelectionKey getSelectionKey() {
 1102  39626
         return socketChannel.keyFor(selectorHandler.getSelector());
 1103  
     }
 1104  
     
 1105  
     /**
 1106  
      * Registers <code>SSLConnectorHandler<code>'s {@link SelectionKey}
 1107  
      * to listen channel operations.
 1108  
      * @param ops interested channel operations
 1109  
      */
 1110  
     private void registerSelectionKeyFor(int ops) {
 1111  39626
         SelectionKey key = getSelectionKey();
 1112  39626
         selectorHandler.register(key, ops);
 1113  39626
     }
 1114  
     
 1115  
     /**
 1116  
      * Flushes as much as possible bytes from the secured output buffer
 1117  
      * @return true if secured buffer was completely flushed, false otherwise
 1118  
      */
 1119  
     private boolean flushSecuredOutputBuffer() throws IOException {
 1120  44
         int nWrite = 1;
 1121  
         
 1122  88
         while (nWrite > 0 && securedOutputBuffer.hasRemaining()) {
 1123  44
             nWrite = socketChannel.write(securedOutputBuffer);
 1124  
         }
 1125  
         
 1126  44
         if (securedOutputBuffer.hasRemaining()) {
 1127  0
             SelectionKey key = socketChannel.keyFor(selectorHandler.getSelector());
 1128  0
             selectorHandler.register(key, SelectionKey.OP_WRITE);
 1129  
             
 1130  0
             return false;
 1131  
         }
 1132  
         
 1133  44
         return true;
 1134  
     }
 1135  
     
 1136  
     /**
 1137  
      * Initiate{@link SSLEngine} and related secure buffers
 1138  
      */
 1139  
     private void initSSLEngineIfRequired() {
 1140  311
         if (sslEngine == null) {
 1141  114
             sslEngine = sslContext.createSSLEngine();
 1142  114
             sslEngine.setUseClientMode(true);
 1143  
         }
 1144  
             
 1145  311
         int bbSize = sslEngine.getSession().getPacketBufferSize();
 1146  311
         securedInputBuffer = ByteBuffer.allocate(bbSize * 2);
 1147  311
         securedOutputBuffer = ByteBuffer.allocate(bbSize * 2);
 1148  311
         securedOutputBuffer.limit(0);
 1149  311
     }
 1150  
     
 1151  
     private AsyncQueueDataProcessor obtainSSLReadPostProcessor() {
 1152  100
         if (sslReadPostProcessor == null) {
 1153  1
             synchronized(this) {
 1154  1
                 if (sslReadPostProcessor == null) {
 1155  1
                     sslReadPostProcessor = new SSLReadPostProcessor();
 1156  
                 }
 1157  1
             }
 1158  
         }
 1159  
         
 1160  100
         return sslReadPostProcessor;
 1161  
     }
 1162  
 
 1163  
     private AsyncQueueDataProcessor obtainSSLWritePreProcessor() {
 1164  510840
         if (sslWritePreProcessor == null) {
 1165  5
             synchronized(this) {
 1166  5
                 if (sslWritePreProcessor == null) {
 1167  2
                     sslWritePreProcessor = new SSLWritePreProcessor();
 1168  
                 }
 1169  5
             }
 1170  
         }
 1171  
         
 1172  511000
         return sslWritePreProcessor;
 1173  
     }
 1174  
     
 1175  
     /**
 1176  
      * Internal SSL CallbackHandler, which is able to process properly SSL handshake
 1177  
      * phase and translate its calls to the custom SSLCallbackHandler.
 1178  
      */
 1179  228
     private class SSLInternalCallbackHandler implements CallbackHandler {
 1180  
         public void onConnect(IOEvent ioEvent) {
 1181  114
             callbackHandler.onConnect(ioEvent);
 1182  114
         }
 1183  
 
 1184  
         public void onRead(IOEvent ioEvent) {
 1185  39626
             if (!isAsyncReadQueueMode) {
 1186  
                 try {
 1187  
                     // if processing handshake - pass the data to handshake related code
 1188  39626
                     if (isProcessingAsyncHandshake) {
 1189  22
                         if (doAsyncHandshake(asyncHandshakeBuffer)) {
 1190  11
                             callbackHandler.onHandshake(ioEvent);
 1191  
                         }
 1192  
 
 1193  22
                         return;
 1194  
                     }
 1195  
 
 1196  39604
                     callbackHandler.onRead(ioEvent);
 1197  0
                 } catch (IOException e) {
 1198  0
                     logger.log(Level.SEVERE, "Exception occured when reading from SSL channel.", e);
 1199  39604
                 }
 1200  
             }
 1201  39604
         }
 1202  
 
 1203  
         public void onWrite(IOEvent ioEvent) {
 1204  43
             if (!isAsyncWriteQueueMode) {
 1205  
                 try {
 1206  
                     // check if all the secured data was written, if not -
 1207  
                     // flush as much as possible.
 1208  0
                     if (!securedOutputBuffer.hasRemaining() || flushSecuredOutputBuffer()) {
 1209  
                         // if no encrypted data left in buffer - continue processing
 1210  0
                         if (isProcessingAsyncHandshake) {
 1211  0
                             if (doAsyncHandshake(asyncHandshakeBuffer)) {
 1212  0
                                 callbackHandler.onHandshake(ioEvent);
 1213  
                             }
 1214  
 
 1215  0
                             return;
 1216  
                         }
 1217  
 
 1218  0
                         callbackHandler.onWrite(ioEvent);
 1219  
                     }
 1220  0
                 } catch (IOException e) {
 1221  0
                     logger.log(Level.SEVERE, "Exception occured when writing to SSL channel.", e);
 1222  0
                 }
 1223  
             }
 1224  43
         }
 1225  
     }
 1226  
     
 1227  
     /**
 1228  
      * SSL <code>AsyncQueueDataProcessor</code> for a 
 1229  
      * <code>TCPAsyncQueueReader</code>
 1230  
      */
 1231  2
     private class SSLReadPostProcessor implements AsyncQueueDataProcessor {
 1232  
         public ByteBuffer getInternalByteBuffer() {
 1233  123460
             return securedInputBuffer;
 1234  
         }
 1235  
 
 1236  
         public void process(ByteBuffer byteBuffer) throws SSLException {
 1237  8343
             securedInputBuffer.flip();
 1238  8343
             unwrapAll(byteBuffer);
 1239  8343
             clearOrCompactBuffer(securedInputBuffer);
 1240  8343
         }
 1241  
     }
 1242  
     
 1243  
     /**
 1244  
      * SSL <code>AsyncQueueDataProcessor</code> for a 
 1245  
      * <code>TCPAsyncQueueWriter</code>
 1246  
      */
 1247  4
     private class SSLWritePreProcessor implements AsyncQueueDataProcessor {
 1248  
         public ByteBuffer getInternalByteBuffer() {
 1249  1020023
             return securedOutputBuffer;
 1250  
         }
 1251  
 
 1252  
         public void process(ByteBuffer byteBuffer) throws SSLException {
 1253  510019
             if (!byteBuffer.hasRemaining() || securedOutputBuffer.hasRemaining()) return;
 1254  
             
 1255  510005
             securedOutputBuffer.clear();
 1256  510005
             SSLEngineResult result = sslEngine.wrap(byteBuffer, securedOutputBuffer);
 1257  510005
             updateSSLEngineStatus(result);
 1258  510005
             securedOutputBuffer.flip();
 1259  510005
         }
 1260  
     }
 1261  
 }