private long doWrap ( ByteBuffer [ ] userBuffers , int off , int len ) throws IOException { if ( anyAreSet ( state , FLAG_CLOSED ) ) { throw new ClosedChannelException ( ) ; } if ( outstandingTasks > 0 ) { return 0 ; } if ( anyAreSet ( state , FLAG_WRITE_REQUIRES_READ ) ) { doUnwrap ( null , 0 , 0 ) ; if ( allAreClear ( state , FLAG_READ_REQUIRES_WRITE ) ) { //unless a wrap is immediatly required we just return return 0 ; } } if ( wrappedData != null ) { int res = sink . write ( wrappedData . getBuffer ( ) ) ; if ( res == 0 || wrappedData . getBuffer ( ) . hasRemaining ( ) ) { return 0 ; } wrappedData . getBuffer ( ) . clear ( ) ; } else { wrappedData = bufferPool . allocate ( ) ; } try { SSLEngineResult result = null ; while ( result == null || ( result . getHandshakeStatus ( ) == SSLEngineResult . HandshakeStatus . NEED_WRAP && result . getStatus ( ) != SSLEngineResult . Status . BUFFER_OVERFLOW ) ) { if ( userBuffers == null ) { result = engine . wrap ( EMPTY_BUFFER , wrappedData . getBuffer ( ) ) ; } else { result = engine . wrap ( userBuffers , off , len , wrappedData . getBuffer ( ) ) ; } } wrappedData . getBuffer ( ) . flip ( ) ; if ( result . getStatus ( ) == SSLEngineResult . Status . BUFFER_UNDERFLOW ) { throw new IOException ( "underflow" ) ; //todo: can this happen? } else if ( result . getStatus ( ) == SSLEngineResult . Status . BUFFER_OVERFLOW ) { if ( ! wrappedData . getBuffer ( ) . hasRemaining ( ) ) { //if an earlier wrap suceeded we ignore this throw new IOException ( "overflow" ) ; //todo: handle properly } } //attempt to write it out, if we fail we just return //we ignore the handshake status, as wrap will get called again if ( wrappedData . getBuffer ( ) . hasRemaining ( ) ) { sink . write ( wrappedData . getBuffer ( ) ) ; } //if it was not a complete write we just return if ( wrappedData . getBuffer ( ) . hasRemaining ( ) ) { return result . bytesConsumed ( ) ; } if ( ! handleHandshakeResult ( result ) ) { return 0 ; } if ( result . getStatus ( ) == SSLEngineResult . Status . CLOSED && userBuffers != null ) { notifyWriteClosed ( ) ; throw new ClosedChannelException ( ) ; } return result . bytesConsumed ( ) ; } catch ( RuntimeException | IOException | Error e ) { try { close ( ) ; } catch ( Throwable ex ) { UndertowLogger . REQUEST_LOGGER . debug ( "Exception closing SSLConduit after exception in doWrap()" , ex ) ; } throw e ; } finally { //this can be cleared if the channel is fully closed if ( wrappedData != null ) { if ( ! wrappedData . getBuffer ( ) . hasRemaining ( ) ) { wrappedData . close ( ) ; wrappedData = null ; } } } }
Wraps the user data and attempts to send it to the remote client . If data has already been buffered then this is attempted to be sent first .