FileDocCategorySizeDatePackage
SSLReadTask.javaAPI DocGlassfish v2 API18503Fri May 04 22:37:10 BST 2007com.sun.enterprise.web.connector.grizzly.ssl

SSLReadTask

public class SSLReadTask extends com.sun.enterprise.web.connector.grizzly.DefaultReadTask
SSL support over NIO. This Task handles the SSL requests using a non blocking socket. The SSL handshake is done using this class. Once the handshake is successful, the SSLProcessorTask is executed.
author
Jean-Francois Arcand

Fields Summary
protected SSLEngine
sslEngine
The SSLEngine required to encrypt/decrypt SSL request bytes.
protected int
appBBSize
Decrypted ByteBuffer default size.
protected int
inputBBSize
Encrypted ByteBuffer default size.
protected ByteBuffer
inputBB
The encrypted input ByteBuffer.
protected ByteBuffer
outputBB
The encrupted output ByteBuffer
protected boolean
handshake
Is the handshake completed.
protected org.apache.tomcat.util.net.SSLImplementation
sslImplementation
The Coyote SSLImplementation used to retrive the SSLContext
Constructors Summary
public SSLReadTask()


    
    // -------------------------------------------------------------------- //
    
      
        ;//
    
Methods Summary
public voidallocateBuffers()
Allocate themandatory ByteBuffers. Since the ByteBuffer are maintaned on the SSLWorkerThread lazily, this method makes sure the ByteBuffers are properly allocated and configured.

        final SSLWorkerThread workerThread = 
                (SSLWorkerThread)Thread.currentThread();
        
        int expectedSize = sslEngine.getSession().getPacketBufferSize();
        if (inputBBSize < expectedSize){
            inputBBSize = expectedSize;
        }

        if (inputBB != null && inputBB.capacity() < inputBBSize) {
            ByteBuffer newBB = ByteBuffer.allocate(inputBBSize);
            inputBB.flip();
            newBB.put(inputBB);
            inputBB = newBB;                                
        } else if (inputBB == null && workerThread.getInputBB() != null ){
            inputBB = workerThread.getInputBB();
        } else if (inputBB == null){
            inputBB = ByteBuffer.allocate(inputBBSize);
        }      
        
        if (workerThread.getOutputBB() == null) {
            outputBB = ByteBuffer.allocate(inputBBSize);
        } else {
            outputBB = workerThread.getOutputBB();
        }
        
        if (byteBuffer == null && workerThread.getByteBuffer() == null){
            byteBuffer = ByteBuffer.allocate(inputBBSize * 2);
        } else if (byteBuffer == null){
            byteBuffer = workerThread.getByteBuffer();
        }

        expectedSize = sslEngine.getSession().getApplicationBufferSize();
        if ( expectedSize > byteBuffer.capacity() ) {
            ByteBuffer newBB = ByteBuffer.allocate(expectedSize);
            byteBuffer.flip();
            newBB.put(byteBuffer);
            byteBuffer = newBB;
        }   
         
        // Make sure the same ByteBuffer is used.
        workerThread.setInputBB(inputBB);
        workerThread.setOutputBB(outputBB);  
        workerThread.setByteBuffer(byteBuffer);
   
        outputBB.position(0);
        outputBB.limit(0); 
        workerThread.setSSLEngine(sslEngine);
    
protected voidconfigureProcessorTask()
Configure the SSLProcessorTask.

        super.configureProcessorTask();
        SSLSupport sslSupport = sslImplementation.getSSLSupport(sslEngine);
        ((SSLProcessorTask)processorTask).setSSLSupport(sslSupport);
        ((SSLProcessorTask)processorTask).setSslReadTask(this);
    
public voiddetachProcessor()
Return the ProcessorTask to the pool.

        if ( processorTask != null ){
            ((SSLProcessorTask)processorTask).setSSLSupport(null);
            ((SSLProcessorTask)processorTask).setSslReadTask(null);
        }
        super.detachProcessor();
    
protected booleandoHandshake(int timeout)
Execute a non blocking SSL handshake.

        HandshakeStatus handshakeStatus = HandshakeStatus.NEED_UNWRAP;
        boolean OK = true;    
        final SSLWorkerThread workerThread = 
                (SSLWorkerThread)Thread.currentThread();
        try{ 
            if ( handshake ) {
                byteBuffer = SSLUtils.doHandshake
                             (key,byteBuffer,inputBB,outputBB,sslEngine,
                              handshakeStatus,timeout);

                if (doRead(inputBB) == -1){
                    throw new EOFException();
                }
            }  
        } catch (EOFException ex) {
            Logger logger = SSLSelectorThread.logger();
            if ( logger.isLoggable(Level.FINE) ){
                logger.log(Level.FINE,"doHandshake",ex);
            }            
            OK = false;
        } finally {
            workerThread.setOutputBB(outputBB);
        }
        return OK;
    
protected java.lang.Object[]doPeerCertificateChain(boolean needClientAuth)
Get the peer certificate list by enatiating a new handshake.

return
Object[] An array of X509Certificate.

        Logger logger = SSLSelectorThread.logger();
        final SSLWorkerThread workerThread = 
                (SSLWorkerThread)Thread.currentThread();
     
        Certificate[] certs=null;
        try {
            certs = sslEngine.getSession().getPeerCertificates();
        } catch( Throwable t ) {
            if ( logger.isLoggable(Level.FINE))
                logger.log(Level.FINE,"Error getting client certs",t);
        }
 
        if (certs == null && needClientAuth){
            sslEngine.getSession().invalidate();
            sslEngine.setNeedClientAuth(true);
            sslEngine.beginHandshake();         
                      
            ByteBuffer origBB = workerThread.getByteBuffer();
            outputBB = workerThread.getOutputBB();

            // In case the application hasn't read all the body bytes.
            if ( origBB.position() != origBB.limit() ){
                byteBuffer = ByteBuffer.allocate(origBB.capacity());
            } else {
                byteBuffer = origBB;
            }
            byteBuffer.clear();
            outputBB.position(0);
            outputBB.limit(0); 
            
            handshake= true;
            try{
                doHandshake(0);
            } catch (Throwable ex){
                if ( logger.isLoggable(Level.FINE))
                    logger.log(Level.FINE,"Error during handshake",ex);   
                return null;
            } finally {
                byteBuffer = origBB;
                handshake= false;
                workerThread.setByteBuffer(byteBuffer);   
                inputStream.setByteBuffer(byteBuffer);
                byteBuffer.clear();
            }            

            try {
                certs = sslEngine.getSession().getPeerCertificates();
            } catch( Throwable t ) {
                if ( logger.isLoggable(Level.FINE))
                    logger.log(Level.FINE,"Error getting client certs",t);
            }
        }
        
        if( certs==null ) return null;
        
        X509Certificate[] x509Certs = new X509Certificate[certs.length];
        for(int i=0; i < certs.length; i++) {
            if( certs[i] instanceof X509Certificate ) {
                x509Certs[i] = (X509Certificate)certs[i];
            } else {
                try {
                    byte [] buffer = certs[i].getEncoded();
                    CertificateFactory cf =
                    CertificateFactory.getInstance("X.509");
                    ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
                    x509Certs[i] = (X509Certificate)
                    cf.generateCertificate(stream);
                } catch(Exception ex) { 
                    logger.log(Level.INFO,"Error translating cert " + certs[i],
                                     ex);
                    return null;
                }
            }
            
            if(logger.isLoggable(Level.FINE))
                logger.log(Level.FINE,"Cert #" + i + " = " + x509Certs[i]);
        }
        
        if(x509Certs.length < 1)
            return null;
            
        return x509Certs;
    
private intdoRead(java.nio.ByteBuffer inputBB)

 
        int count = -1;
        try{
            // Read first bytes to avoid continuing if the client
            // closed the connection.
            count = ((SocketChannel)key.channel()).read(inputBB);
            if (count != -1){
                // Decrypt the bytes we just read.
                byteBuffer =
                        SSLUtils.unwrapAll(byteBuffer,inputBB,sslEngine);
                final SSLWorkerThread workerThread =
                        (SSLWorkerThread)Thread.currentThread();
                workerThread.setByteBuffer(byteBuffer);
                workerThread.setInputBB(inputBB);
            }
            return count;
        } catch(IOException ex){
            return -1;
        } finally {
            if (count == -1){
                try{
                    sslEngine.closeInbound();
                } catch (SSLException ex){
                    ;
                }
            } 
        }
    
public voiddoTask()
Perform an SSL handshake using an SSLEngine. If the handshake is successfull, process the connection.

        
        int count = 0;
        Exception exception = null;
        boolean keepAlive = false;
        SSLEngineResult result;  
        final SSLWorkerThread workerThread = 
                (SSLWorkerThread)Thread.currentThread();
        
        SocketChannel socketChannel = (SocketChannel)key.channel();
        try {
            allocateBuffers();          
            if (!doHandshake(SSLUtils.getReadTimeout())) {
                keepAlive = false;
                count = -1;
            } else {   
                if (!handshake){
                    count = doRead(inputBB);
                    if (count == -1){
                        keepAlive = false;
                        return;
                    }
                } else {
                    handshake = false;
                }
                               
                try{
                    inputStream.setByteBuffer(byteBuffer);
                    keepAlive = process();                            
                } catch (IOException ex) {
                    keepAlive = false; 
                }
            }     
        } catch (IOException ex) {         
            exception = ex;
            keepAlive = false;
        } catch (Throwable ex) {
            Logger logger = SSLSelectorThread.logger();
            if ( logger.isLoggable(Level.FINE) ){
                logger.log(Level.FINE,"doRead",ex);
            }            
            count = -1;
            keepAlive = false;
        } finally { 
            manageKeepAlive(keepAlive,count,exception);
        }            
    
public booleangetHandshake()
Return the handshake status.

        return handshake;
    
public java.nio.ByteBuffergetInputBB()
Return the encrypted ByteBuffer used to handle request.

        return inputBB;
    
public java.nio.ByteBuffergetOutputBB()

        return outputBB;
    
public javax.net.ssl.SSLEnginegetSSLEngine()
Return the SSLEngine used by this instance.

        return sslEngine;
    
public voidinitialize(com.sun.enterprise.web.connector.grizzly.StreamAlgorithm algorithm, boolean useDirectByteBuffer, boolean useByteBufferView)
Initialize this object.

        type = READ_TASK;    
        this.algorithm = algorithm;       
        inputStream = new SSLByteBufferInputStream();
        
        this.useDirectByteBuffer = useDirectByteBuffer;
        this.useByteBufferView = useByteBufferView; 
    
protected booleanprocess()
Process the request using the decrypted ByteBuffer. The SSLProcessorTask

        boolean keepAlive = false;     
        SocketChannel socketChannel = (SocketChannel)key.channel();
        Socket socket = socketChannel.socket();
        algorithm.setSocketChannel(socketChannel);    
        inputStream.setSelectionKey(key);
                
        if (processorTask == null){
            attachProcessor(selectorThread.getProcessorTask());
        }
        
        // Always true with the NoParsingAlgorithm
        if ( algorithm.parse(byteBuffer) ){ 
           return executeProcessorTask();
        } else {
           // Never happens with the default StreamAlgorithm
           return true;
        }
    
public voidrecycle()
Recycle this object so it can be re-used. Make sure all ByteBuffers are properly recycled.

        if (byteBuffer != null){ 
            try{
                WorkerThread workerThread = (WorkerThread)Thread.currentThread();    
                workerThread.setByteBuffer(byteBuffer);
            } catch (ClassCastException ex){
                // Avoid failling if the Grizzly extension doesn't support
                // the WorkerThread interface.               
                Logger logger = SSLSelectorThread.logger();
                if (logger.isLoggable(Level.FINEST))
                    logger.log(Level.FINEST,"recycle",ex);                
            } finally {
                byteBuffer = algorithm.postParse(byteBuffer);   
                byteBuffer.clear();
            }
        }    
        handshake = true;
        
        inputStream.recycle();
        algorithm.recycle();
        key = null;
        inputStream.setSelectionKey(null);       

        if ( inputBB != null ) {
            inputBB.clear();
        }
        
        if ( outputBB != null ){
            outputBB.clear();
            outputBB.position(0);
            outputBB.limit(0);
        }
             
        inputBB = null;
        outputBB = null;
        byteBuffer = null;                
        sslEngine = null;
    
public voidregisterKey()
Register the SelectionKey with the Selector. The SSLEngine is attached because it is impossible to keep-alive an ssl connection without re-using the same SSLEngine.

        key.attach(sslEngine);
        super.registerKey();
    
public voidsetHandshake(boolean handshake)
Set true if the handshake already occured.

        this.handshake = handshake;
    
public voidsetInputBB(java.nio.ByteBuffer inputBB)
Set the encrypted ByteBuffer used to handle request.

        this.inputBB = inputBB;
    
public voidsetOutputBB(java.nio.ByteBuffer outputBB)

        this.outputBB = outputBB;
    
public voidsetSSLEngine(javax.net.ssl.SSLEngine sslEngine)
Set the SSLEngine.

        this.sslEngine = sslEngine;     
    
public voidsetSSLImplementation(org.apache.tomcat.util.net.SSLImplementation sslImplementation)
Set the Coyote SSLImplemenation

        this.sslImplementation = sslImplementation;