Coverage Report - com.sun.grizzly.filter.SSLReadFilter
 
Classes in this File Line Coverage Branch Coverage Complexity
SSLReadFilter
59 %
130/222
51 %
45/88
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  
 
 39  
 package com.sun.grizzly.filter;
 40  
 
 41  
 import com.sun.grizzly.Context;
 42  
 import com.sun.grizzly.Controller;
 43  
 import com.sun.grizzly.ProtocolFilter;
 44  
 import com.sun.grizzly.SSLConfig;
 45  
 import com.sun.grizzly.util.InputReader;
 46  
 import com.sun.grizzly.util.SSLUtils;
 47  
 import com.sun.grizzly.util.ThreadAttachment;
 48  
 import com.sun.grizzly.util.ThreadAttachment.Mode;
 49  
 import com.sun.grizzly.util.WorkerThread;
 50  
 import java.io.EOFException;
 51  
 import java.io.IOException;
 52  
 import java.nio.ByteBuffer;
 53  
 import java.nio.channels.SelectionKey;
 54  
 import java.nio.channels.SocketChannel;
 55  
 import java.util.ArrayList;
 56  
 import java.util.logging.Level;
 57  
 import javax.net.ssl.SSLContext;
 58  
 import javax.net.ssl.SSLEngine;
 59  
 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
 60  
 import javax.net.ssl.SSLException;
 61  
 
 62  
 /**
 63  
  * Simple ProtocolFilter implementation which execute an SSL handshake and
 64  
  * decrypt the bytes, the pass the control to the next filter.
 65  
  *
 66  
  * @author Jeanfrancois Arcand
 67  
  */
 68  
 public class SSLReadFilter implements ProtocolFilter{
 69  
     /**
 70  
      * The {@link SSLContext} associated with the SSL implementation
 71  
      * we are running on.
 72  
      */
 73  
     protected SSLContext sslContext;
 74  
     
 75  
     
 76  
     /**
 77  
      * The list of cipher suite
 78  
      */
 79  5
     private String[] enabledCipherSuites = null;
 80  
     
 81  
     
 82  
     /**
 83  
      * the list of protocols
 84  
      */
 85  5
     private String[] enabledProtocols = null;
 86  
     
 87  
     
 88  
     /**
 89  
      * Client mode when handshaking.
 90  
      */
 91  5
     private boolean clientMode = false;
 92  
     
 93  
     
 94  
     /**
 95  
      * Require client Authentication.
 96  
      */
 97  5
     private boolean needClientAuth = false;
 98  
     
 99  
     
 100  
     /**
 101  
      * True when requesting authentication.
 102  
      */
 103  5
     private boolean wantClientAuth = false;
 104  
     
 105  
     
 106  
     /**
 107  
      * Has the enabled protocol configured.
 108  
      */
 109  5
     private boolean isProtocolConfigured = false;
 110  
     
 111  
     
 112  
     /**
 113  
      * Has the enabled Cipher configured.
 114  
      */
 115  5
     private boolean isCipherConfigured = false;
 116  
     
 117  
     
 118  
     /**
 119  
      * Encrypted ByteBuffer default size.
 120  
      */
 121  5
     protected int inputBBSize = 5 * 4096;
 122  
     
 123  
     
 124  5
     public SSLReadFilter() {
 125  5
     }
 126  
 
 127  
     
 128  
     public boolean execute(Context ctx) throws IOException {
 129  53994
         boolean result = true;
 130  53994
         int count = 0;
 131  53994
         Throwable exception = null;
 132  53994
         SelectionKey key = ctx.getSelectionKey();
 133  
         WorkerThread workerThread;
 134  
         try{
 135  53994
             workerThread = (WorkerThread)Thread.currentThread();   
 136  0
         } catch (ClassCastException ex){
 137  0
             throw new IllegalStateException(ex.getMessage());
 138  53994
         }
 139  
 
 140  53994
         SSLEngine sslEngine = workerThread.getSSLEngine();
 141  53994
         if (sslEngine == null) {
 142  116
             sslEngine = newSSLEngine(key);
 143  116
             workerThread.setSSLEngine(sslEngine);
 144  116
             ThreadAttachment attachment = workerThread.updateAttachment(Mode.SSL_ENGINE);
 145  116
             key.attach(attachment);
 146  
         }
 147  
 
 148  53994
         boolean hasHandshake = sslEngine.getSession().isValid();
 149  
         try {
 150  53994
             allocateBuffers();
 151  
             
 152  53994
             if (hasHandshake) {
 153  53878
                 count = doRead(key);
 154  116
             } else if (doHandshake(key, SSLUtils.getReadTimeout())) {
 155  114
                 hasHandshake = true;
 156  
                 // set "no available data" for secured output buffer
 157  114
                 ByteBuffer outputBB = workerThread.getOutputBB();
 158  114
                 outputBB.limit(outputBB.position());
 159  114
             } else {
 160  2
                 count = -1;
 161  
             }
 162  0
         } catch (IOException ex) {
 163  0
             exception = ex;
 164  0
             log("SSLReadFilter.execute",ex);
 165  0
         } catch (Throwable ex) {
 166  0
             exception = ex;    
 167  0
             log("SSLReadFilter.execute",ex);
 168  
         } finally {
 169  53994
             if (exception != null || count == -1){
 170  111
                 ctx.setAttribute(Context.THROWABLE,exception);
 171  111
                 ctx.setKeyRegistrationState(
 172  
                         Context.KeyRegistrationState.CANCEL);
 173  111
                 result = false;
 174  
             }
 175  
         }     
 176  53994
         return result;
 177  
     }
 178  
 
 179  
     
 180  
     /**
 181  
      * If no bytes were available, close the connection by cancelling the
 182  
      * SelectionKey. If bytes were available, register the SelectionKey
 183  
      * for new bytes.
 184  
      *
 185  
      * @return <tt>true</tt> if the previous ProtocolFilter postExecute method
 186  
      *         needs to be invoked.
 187  
      */
 188  
     public boolean postExecute(Context ctx) throws IOException {
 189  53994
         if (ctx.getKeyRegistrationState()
 190  
                 == Context.KeyRegistrationState.CANCEL){
 191  111
             ctx.getSelectorHandler().getSelectionKeyHandler().
 192  
                     cancel(ctx.getSelectionKey());
 193  53883
         } else if (ctx.getKeyRegistrationState()
 194  
                 == Context.KeyRegistrationState.REGISTER){            
 195  53883
             saveSecuredBufferRemainders(ctx.getSelectionKey());
 196  53883
             ctx.getSelectorHandler().register(ctx.getSelectionKey(),
 197  
                     SelectionKey.OP_READ);
 198  53883
             ctx.setKeyRegistrationState(Context.KeyRegistrationState.NONE);
 199  
         }
 200  53994
         return true;
 201  
     }
 202  
     
 203  
     
 204  
     /**
 205  
      * Allocate themandatory {@link ByteBuffer}s. Since the ByteBuffer
 206  
      * are maintaned on the {@link WorkerThread} lazily, this method
 207  
      * makes sure the ByteBuffers are properly allocated and configured.
 208  
      */    
 209  
     protected void allocateBuffers(){
 210  53994
         final WorkerThread workerThread = 
 211  
                 (WorkerThread)Thread.currentThread();
 212  53994
         ByteBuffer byteBuffer = workerThread.getByteBuffer();
 213  53994
         ByteBuffer outputBB = workerThread.getOutputBB();
 214  53994
         ByteBuffer inputBB = workerThread.getInputBB();
 215  
             
 216  53994
         int expectedSize = workerThread.getSSLEngine().getSession()
 217  
             .getPacketBufferSize();
 218  53994
         if (inputBBSize < expectedSize){
 219  0
             inputBBSize = expectedSize;
 220  
         }
 221  
 
 222  53994
         if (inputBB != null && inputBB.capacity() < inputBBSize) {
 223  0
             ByteBuffer newBB = ByteBuffer.allocate(inputBBSize);
 224  0
             inputBB.flip();
 225  0
             newBB.put(inputBB);
 226  0
             inputBB = newBB;                                
 227  0
         } else if (inputBB == null){
 228  116
             inputBB = ByteBuffer.allocate(inputBBSize);
 229  
         }      
 230  
         
 231  53994
         if (outputBB == null) {
 232  155
             outputBB = ByteBuffer.allocate(inputBBSize);
 233  
         } 
 234  
         
 235  53994
         if (byteBuffer == null){
 236  0
             byteBuffer = ByteBuffer.allocate(inputBBSize * 2);
 237  
         } 
 238  
 
 239  53994
         expectedSize = workerThread.getSSLEngine().getSession()
 240  
             .getApplicationBufferSize();
 241  53994
         if ( expectedSize > byteBuffer.capacity() ) {
 242  24
             ByteBuffer newBB = ByteBuffer.allocate(expectedSize);
 243  24
             byteBuffer.flip();
 244  24
             newBB.put(byteBuffer);
 245  24
             byteBuffer = newBB;
 246  
         }   
 247  
 
 248  53994
         workerThread.setInputBB(inputBB);
 249  53994
         workerThread.setOutputBB(outputBB);  
 250  53994
         workerThread.setByteBuffer(byteBuffer);
 251  
    
 252  53994
         outputBB.position(0);
 253  53994
         outputBB.limit(0);
 254  53994
     }
 255  
     
 256  
     
 257  
     /**
 258  
      * Execute a non blocking SSL handshake.
 259  
      * @param key {@link SelectionKey}
 260  
      * @param timeout 
 261  
      * @return 
 262  
      * @throws java.io.IOException 
 263  
      */    
 264  
     private static boolean doHandshake(SelectionKey key,int timeout) throws IOException{
 265  116
         final WorkerThread workerThread = 
 266  
                 (WorkerThread)Thread.currentThread();
 267  116
         ByteBuffer byteBuffer = workerThread.getByteBuffer();
 268  116
         ByteBuffer outputBB = workerThread.getOutputBB();
 269  116
         ByteBuffer inputBB = workerThread.getInputBB();
 270  116
         SSLEngine sslEngine = workerThread.getSSLEngine();
 271  
         
 272  116
         HandshakeStatus handshakeStatus = HandshakeStatus.NEED_UNWRAP;
 273  
         
 274  116
         boolean OK = true;    
 275  
         try{ 
 276  116
             byteBuffer = SSLUtils.doHandshake
 277  
                          ((SocketChannel) key.channel(), byteBuffer, inputBB,
 278  
                     outputBB, sslEngine, handshakeStatus, timeout);
 279  114
             if (doRead(key) == -1){
 280  0
                 throw new EOFException();
 281  
             }
 282  2
         } catch (IOException ex) {
 283  2
             log("doHandshake", ex);
 284  2
             OK = false;
 285  114
         }
 286  116
         return OK;
 287  
     }    
 288  
     
 289  
     
 290  
     private static int doRead(SelectionKey key) {
 291  53992
         final WorkerThread workerThread =
 292  
                 (WorkerThread) Thread.currentThread();
 293  53992
         ByteBuffer byteBuffer = workerThread.getByteBuffer();
 294  53992
         ByteBuffer outputBB = workerThread.getOutputBB();
 295  53992
         ByteBuffer inputBB = workerThread.getInputBB();
 296  53992
         SSLEngine sslEngine = workerThread.getSSLEngine();
 297  
 
 298  53992
         int count = -1;
 299  
         try {
 300  
             // Read first bytes to avoid continuing if the client
 301  
             // closed the connection.
 302  53992
             int initialBufferPosition = byteBuffer.position();
 303  
 
 304  
             try {
 305  53992
                 count = ((SocketChannel) key.channel()).read(inputBB);
 306  0
             } catch(IOException e) {
 307  0
                 log("Exception during SSL read.", e);
 308  0
                 count = -1;
 309  53992
             }
 310  
             
 311  53992
             if (count > -1 || inputBB.position() > 0) {
 312  
                 // Decrypt the bytes we just read.
 313  53883
                 if (Controller.logger().isLoggable(Level.FINE)) {
 314  0
                     Controller.logger().log(Level.FINE,
 315  
                             "SSLReadFilter. Read: " + count +
 316  
                             " Calling unwrapAll. InputBB: " +
 317  
                             inputBB + " byteBuffer: " + byteBuffer);
 318  
                 }
 319  
 
 320  53883
                 int initialInputBBPosition = inputBB.position();
 321  53883
                 byteBuffer =
 322  
                         SSLUtils.unwrapAll(byteBuffer, inputBB, sslEngine);
 323  53883
                 workerThread.setInputBB(inputBB);
 324  53883
                 workerThread.setOutputBB(outputBB);
 325  53883
                 workerThread.setByteBuffer(byteBuffer);
 326  
                 
 327  53883
                 if (count == -1 && byteBuffer.position() != initialBufferPosition) {
 328  0
                     return initialInputBBPosition;
 329  
                 }
 330  
             }
 331  53992
             return count;
 332  0
         } catch (IOException ex) {
 333  0
             log("Exception during SSL read.", ex);
 334  0
             return -1;
 335  
         } finally {
 336  53992
             if (count == -1) {
 337  
                 try {
 338  109
                     sslEngine.closeInbound();
 339  0
                 } catch (SSLException ex) {
 340  54101
                 }
 341  
             }
 342  
         }
 343  
     }
 344  
     
 345  
     
 346  
     /**
 347  
      * Get the peer certificate list by initiating a new handshake.
 348  
      * @param key {@link SelectionKey}
 349  
      * @param needClientAuth 
 350  
      * @return Object[] An array of X509Certificate.
 351  
      * @throws java.io.IOException 
 352  
      */
 353  
     public static Object[] doPeerCertificateChain(SelectionKey key,
 354  
             boolean needClientAuth) throws IOException {
 355  
         
 356  0
         final WorkerThread workerThread = 
 357  
                 (WorkerThread)Thread.currentThread();
 358  0
         ByteBuffer byteBuffer = workerThread.getByteBuffer();
 359  0
         ByteBuffer inputBB = workerThread.getInputBB();
 360  0
         ByteBuffer outputBB = workerThread.getOutputBB();
 361  0
         SSLEngine sslEngine = workerThread.getSSLEngine();
 362  
         
 363  0
         return SSLUtils.doPeerCertificateChain((SocketChannel) key.channel(), 
 364  
                 byteBuffer, inputBB, outputBB, sslEngine, needClientAuth, 
 365  
                 InputReader.getDefaultReadTimeout());
 366  
     }
 367  
     
 368  
     
 369  
     /**
 370  
      * Return a new configured{@link SSLEngine}
 371  
      * @return a new configured{@link SSLEngine}
 372  
      */
 373  
     protected SSLEngine newSSLEngine(){
 374  116
         SSLEngine sslEngine = sslContext.createSSLEngine();
 375  116
         if (enabledCipherSuites != null){            
 376  0
             if (!isCipherConfigured){
 377  0
                 enabledCipherSuites = configureEnabledCiphers(sslEngine,
 378  
                                                         enabledCipherSuites);
 379  0
                 isCipherConfigured = true;
 380  
             }
 381  0
             sslEngine.setEnabledCipherSuites(enabledCipherSuites);
 382  
         }
 383  
         
 384  116
         if (enabledProtocols != null){
 385  0
             if (!isProtocolConfigured) {
 386  0
                 enabledProtocols = configureEnabledProtocols(sslEngine,
 387  
                                                     enabledProtocols);
 388  0
                 isProtocolConfigured = true;
 389  
             }
 390  0
             sslEngine.setEnabledProtocols(enabledProtocols);
 391  
         }
 392  116
         sslEngine.setUseClientMode(clientMode);
 393  116
         return sslEngine;
 394  
     }
 395  
     
 396  
     
 397  
     /**
 398  
      * Configure and return an instance of SSLEngine
 399  
      * @param key  a {@link SelectionKey}
 400  
      * @return  a configured instance of{@link SSLEngine}
 401  
      */
 402  
     protected SSLEngine newSSLEngine(SelectionKey key){
 403  116
         SSLEngine sslEngine = null;
 404  116
         if (key.attachment() instanceof ThreadAttachment) {
 405  2
             sslEngine = ((WorkerThread) Thread.currentThread()).getSSLEngine();
 406  
         }
 407  
         
 408  116
         if (sslEngine == null) {
 409  116
            sslEngine = newSSLEngine();
 410  
         }
 411  
         
 412  116
         sslEngine.setWantClientAuth(wantClientAuth);
 413  116
         sslEngine.setNeedClientAuth(needClientAuth);
 414  116
         return sslEngine;
 415  
     }
 416  
            
 417  
     /**
 418  
      * Configures SSL settings. <code>SSLConfig</code> contains all the parameters
 419  
      * required to build{@link SSLEngine}. There will be no need to call
 420  
      * four methods: setSSLContext, setClientMode, setWantClientAuth, 
 421  
      * setNeedClientAuth.
 422  
      * @param sslConfig <code>SSLConfig</code> configuration
 423  
      */
 424  
     public void configure(SSLConfig sslConfig) {
 425  0
         sslContext = sslConfig.createSSLContext();
 426  0
         wantClientAuth = sslConfig.isWantClientAuth();
 427  0
         needClientAuth = sslConfig.isNeedClientAuth();
 428  0
         clientMode = sslConfig.isClientMode();
 429  0
     }
 430  
     
 431  
     /**
 432  
      * Set the SSLContext required to support SSL over NIO.
 433  
      * @param sslContext {@link SSLContext}
 434  
      */
 435  
     public void setSSLContext(SSLContext sslContext){
 436  5
         this.sslContext = sslContext;
 437  5
     }
 438  
     
 439  
     
 440  
     /**
 441  
      * Return the SSLContext required to support SSL over NIO.
 442  
      * @return {@link SSLContext}
 443  
      */    
 444  
     public SSLContext getSSLContext(){
 445  0
         return sslContext;
 446  
     }
 447  
     
 448  
     
 449  
     /**
 450  
      * Returns the list of cipher suites to be enabled when {@link SSLEngine}
 451  
      * is initialized.
 452  
      *
 453  
      * @return <tt>null</tt> means 'use {@link SSLEngine}'s default.'
 454  
      */
 455  
     public String[] getEnabledCipherSuites() {
 456  0
         return enabledCipherSuites;
 457  
     }
 458  
     
 459  
     
 460  
     /**
 461  
      * Sets the list of cipher suites to be enabled when {@link SSLEngine}
 462  
      * is initialized.
 463  
      * @param enabledCipherSuites 
 464  
      */
 465  
     public void setEnabledCipherSuites(String[] enabledCipherSuites) {
 466  0
         this.enabledCipherSuites = enabledCipherSuites;
 467  0
     }
 468  
     
 469  
     
 470  
     /**
 471  
      * Returns the list of protocols to be enabled when {@link SSLEngine}
 472  
      * is initialized.
 473  
      *
 474  
      * @return <tt>null</tt> means 'use {@link SSLEngine}'s default.'
 475  
      */
 476  
     public String[] getEnabledProtocols() {
 477  0
         return enabledProtocols;
 478  
     }
 479  
     
 480  
     
 481  
     /**
 482  
      * Sets the list of protocols to be enabled when {@link SSLEngine}
 483  
      * is initialized.
 484  
      *
 485  
      * @param enabledProtocols <tt>null</tt> means 'use {@link SSLEngine}'s default.'
 486  
      */
 487  
     public void setEnabledProtocols(String[] enabledProtocols) {
 488  0
         this.enabledProtocols = enabledProtocols;
 489  0
     }
 490  
     
 491  
     
 492  
     /**
 493  
      * Returns <tt>true</tt> if the SSlEngine is set to use client mode
 494  
      * when handshaking.
 495  
      * @return true / false
 496  
      */
 497  
     public boolean isClientMode() {
 498  0
         return clientMode;
 499  
     }
 500  
     
 501  
     
 502  
     /**
 503  
      * Configures the engine to use client (or server) mode when handshaking.
 504  
      * @param clientMode 
 505  
      */    
 506  
     public void setClientMode(boolean clientMode) {
 507  0
         this.clientMode = clientMode;
 508  0
     }
 509  
     
 510  
     
 511  
     /**
 512  
      * Returns <tt>true</tt> if the SSLEngine will <em>require</em>
 513  
      * client authentication.
 514  
      * @return 
 515  
      */   
 516  
     public boolean isNeedClientAuth() {
 517  0
         return needClientAuth;
 518  
     }
 519  
     
 520  
     
 521  
     /**
 522  
      * Configures the engine to <em>require</em> client authentication.
 523  
      * @param needClientAuth 
 524  
      */    
 525  
     public void setNeedClientAuth(boolean needClientAuth) {
 526  0
         this.needClientAuth = needClientAuth;
 527  0
     }
 528  
     
 529  
     
 530  
     /**
 531  
      * Returns <tt>true</tt> if the engine will <em>request</em> client
 532  
      * authentication.
 533  
      * @return 
 534  
      */   
 535  
     public boolean isWantClientAuth() {
 536  0
         return wantClientAuth;
 537  
     }
 538  
     
 539  
     
 540  
     /**
 541  
      * Configures the engine to <em>request</em> client authentication.
 542  
      * @param wantClientAuth 
 543  
      */    
 544  
     public void setWantClientAuth(boolean wantClientAuth) {
 545  0
         this.wantClientAuth = wantClientAuth;
 546  0
     }
 547  
     
 548  
     
 549  
     /**
 550  
      * Return the list of allowed protocol.
 551  
      * @return String[] an array of supported protocols.
 552  
      */
 553  
     private final static String[] configureEnabledProtocols(
 554  
             SSLEngine sslEngine, String[] requestedProtocols){
 555  
         
 556  0
         String[] supportedProtocols = sslEngine.getSupportedProtocols();
 557  0
         String[] protocols = null;
 558  0
         ArrayList<String> list = null;
 559  0
         for(String supportedProtocol: supportedProtocols){        
 560  
             /*
 561  
              * Check to see if the requested protocol is among the
 562  
              * supported protocols, i.e., may be enabled
 563  
              */
 564  0
             for(String protocol: requestedProtocols) {
 565  0
                 protocol = protocol.trim();
 566  0
                 if (supportedProtocol.equals(protocol)) {
 567  0
                     if (list == null) {
 568  0
                         list = new ArrayList<String>();
 569  
                     }
 570  0
                     list.add(protocol);
 571  0
                     break;
 572  
                 }
 573  
             }
 574  
         } 
 575  
 
 576  0
         if (list != null) {
 577  0
             protocols = list.toArray(new String[list.size()]);                
 578  
         }
 579  
  
 580  0
         return protocols;
 581  
     }
 582  
     
 583  
     
 584  
     /**
 585  
      * Determines the SSL cipher suites to be enabled.
 586  
      *
 587  
      * @return Array of SSL cipher suites to be enabled, or null if none of the
 588  
      * requested ciphers are supported
 589  
      */
 590  
     private final static String[] configureEnabledCiphers(SSLEngine sslEngine,
 591  
             String[] requestedCiphers) {
 592  
 
 593  0
         String[] supportedCiphers = sslEngine.getSupportedCipherSuites();
 594  0
         String[] ciphers = null;
 595  0
         ArrayList<String> list = null;
 596  0
         for(String supportedCipher: supportedCiphers){        
 597  
             /*
 598  
              * Check to see if the requested protocol is among the
 599  
              * supported protocols, i.e., may be enabled
 600  
              */
 601  0
             for(String cipher: requestedCiphers) {
 602  0
                 cipher = cipher.trim();
 603  0
                 if (supportedCipher.equals(cipher)) {
 604  0
                     if (list == null) {
 605  0
                         list = new ArrayList<String>();
 606  
                     }
 607  0
                     list.add(cipher);
 608  0
                     break;
 609  
                 }
 610  
             }
 611  
         } 
 612  
 
 613  0
         if (list != null) {
 614  0
             ciphers = list.toArray(new String[list.size()]);                
 615  
         }
 616  
  
 617  0
         return ciphers;
 618  
     }
 619  
 
 620  
     private void saveSecuredBufferRemainders(SelectionKey selectionKey) {
 621  53883
         ThreadAttachment attachment = 
 622  
                 (ThreadAttachment) selectionKey.attachment();
 623  
         
 624  53883
         WorkerThread workerThread = (WorkerThread) Thread.currentThread();   
 625  
 
 626  53883
         if (attachment == null || workerThread.getAttachment() != attachment) {
 627  0
             Controller.logger().log(Level.FINE, 
 628  
                     "SelectionKey ThreadAttachment is NULL or doesn't " +
 629  
                     "correspond to the current thread, when saving buffers");
 630  0
             return;
 631  
         }
 632  
         
 633  53883
         ByteBuffer inputBB = workerThread.getInputBB();
 634  53883
         if (inputBB != null && inputBB.hasRemaining()) {
 635  53883
             workerThread.updateAttachment(attachment.getMode() | Mode.INPUT_BB);
 636  
         } else {
 637  0
             workerThread.updateAttachment(attachment.getMode() & 
 638  
                     (Integer.MAX_VALUE ^ Mode.INPUT_BB));
 639  
         }
 640  
 
 641  53883
         ByteBuffer outputBB = workerThread.getOutputBB();
 642  53883
         if (outputBB != null && outputBB.hasRemaining()) {
 643  191
             workerThread.updateAttachment(attachment.getMode() | Mode.OUTPUT_BB);
 644  
         } else {
 645  53692
             workerThread.updateAttachment(attachment.getMode() & 
 646  
                     (Integer.MAX_VALUE ^ Mode.OUTPUT_BB));
 647  
         }
 648  53883
     }
 649  
     
 650  
     /**
 651  
      * Log a message/exception.
 652  
      * @param msg <code>String</code>
 653  
      * @param t <code>Throwable</code>
 654  
      */
 655  
     protected static void log(String msg, Throwable t) {
 656  2
         if (Controller.logger().isLoggable(Level.FINE)) {
 657  0
             Controller.logger().log(Level.FINE, msg, t);
 658  
         }
 659  2
     }   
 660  
 }