Skip to content

Commit

Permalink
[XrdCl] Make tls handshake async.
Browse files Browse the repository at this point in the history
  • Loading branch information
simonmichal committed Jun 21, 2019
1 parent 4557c8b commit a4ce2d2
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 46 deletions.
172 changes: 134 additions & 38 deletions src/XrdCl/XrdClAsyncTlsSocketHandler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace XrdCl
pXrdHandler( 0 ),
pCorked( false ),
pWrtHdrDone( false ),
pTlsHSRevert( None ),
pWrtBody( 0 )
{

Expand All @@ -56,6 +57,29 @@ namespace XrdCl

}

//----------------------------------------------------------------------------
// Handler a socket event
//----------------------------------------------------------------------------
void AsyncTlsSocketHandler::Event( uint8_t type, XrdCl::Socket *socket )
{
if( pTlsHSRevert == ReadOnWrite )
{
//------------------------------------------------------------------------
// In this case we would like to call the OnRead routine on the Write event
//------------------------------------------------------------------------
if( type & ReadyToWrite ) type = ReadyToRead;
}
else if( pTlsHSRevert == WriteOnRead )
{
//------------------------------------------------------------------------
// In this case we would like to call the OnWrite routine on the Read event
//------------------------------------------------------------------------
if( type & ReadyToRead ) type = ReadyToWrite;
}

AsyncSocketHandler::Event( type, socket );
}

//----------------------------------------------------------------------------
// Connect returned
//----------------------------------------------------------------------------
Expand All @@ -71,7 +95,7 @@ namespace XrdCl
//------------------------------------------------------------------------
// Initialize the TLS layer
//------------------------------------------------------------------------
//try???? This should be under a try-catch!
//try???? This should be under a try-catch! TODO
pTls.reset( new Tls( tlsContext, pSocket->GetFD() ) );

//------------------------------------------------------------------------
Expand All @@ -86,7 +110,6 @@ namespace XrdCl
//----------------------------------------------------------------------------
// Got a write readiness event
//----------------------------------------------------------------------------

void AsyncTlsSocketHandler::OnWrite()
{
//--------------------------------------------------------------------------
Expand All @@ -110,18 +133,15 @@ namespace XrdCl
if( !pWrtHdrDone )
{
Status st = WriteCurrentMessage( pOutgoing );
OnTlsWrite( st );

if( !st.IsOK() )
{
OnFault( st );
return;
}

if( st.code == suRetry )
{
OnTlsRetry();
return;
}
if( st.code == suRetry ) return;

pWrtHdrDone = true;
}
Expand All @@ -148,18 +168,15 @@ namespace XrdCl
while( pCurrentChunk != pWrtBody->end() )
{
Status st = WriteCurrentChunk( *pCurrentChunk );
OnTlsWrite( st );

if( !st.IsOK() )
{
OnFault( st );
return;
}

if( st.code == suRetry )
{
OnTlsRetry();
return;
}
if( st.code == suRetry ) return;

++pCurrentChunk;
}
Expand Down Expand Up @@ -203,14 +220,16 @@ namespace XrdCl
return;
}

if( !(st = WriteCurrentMessage( pHSOutgoing )).IsOK() )
st = WriteCurrentMessage( pHSOutgoing );
OnTlsWrite( st );

if( !st.IsOK() )
{
OnFaultWhileHandshaking( st );
return;
}

if( st.code == suRetry )
return;
if( st.code == suRetry ) return;

delete pHSOutgoing;
pHSOutgoing = 0;
Expand Down Expand Up @@ -338,17 +357,15 @@ namespace XrdCl
if( !pHeaderDone )
{
st = pXrdTransport->GetHeader( pIncoming, pTls.get() );
OnTlsRead( st );

if( !st.IsOK() )
{
OnFault( st );
return;
}

if( st.code == suRetry )
{
OnTlsRetry();
return;
}
if( st.code == suRetry ) return;

log->Dump( AsyncSockMsg, "[%s] Received message header for 0x%x size: %d",
pStreamName.c_str(), pIncoming, pIncoming->GetCursor() );
Expand Down Expand Up @@ -380,36 +397,32 @@ namespace XrdCl

uint32_t bytesRead = 0;
st = pXrdHandler->ReadMessageBody( pIncoming, pTls.get(), bytesRead );
OnTlsRead( st );

if( !st.IsOK() )
{
OnFault( st );
return;
}
pIncMsgSize += bytesRead;

if( st.code == suRetry )
{
OnTlsRetry();
return;
}
if( st.code == suRetry ) return;
}
//--------------------------------------------------------------------------
// No raw handler, so we read the message to the buffer
//--------------------------------------------------------------------------
else
{
st = pXrdTransport->GetBody( pIncoming, pTls.get() );
OnTlsRead( st );

if( !st.IsOK() )
{
OnFault( st );
return;
}

if( st.code == suRetry )
{
OnTlsRetry();
return;
}
if( st.code == suRetry ) return;

pIncMsgSize = pIncoming->GetSize();
}
Expand All @@ -434,14 +447,15 @@ namespace XrdCl
// reading has finished
//--------------------------------------------------------------------------
Status st = ReadMessage( pHSIncoming );
OnTlsRead( st );

if( !st.IsOK() )
{
OnFaultWhileHandshaking( st );
return;
}

if( st.code != suDone )
return;
if( st.code == suRetry ) return;

AsyncSocketHandler::HandleHandShake();

Expand Down Expand Up @@ -550,17 +564,99 @@ namespace XrdCl
}

//------------------------------------------------------------------------
// TLS/SSL layer asked to retry an I/O operation
// Process the status of an operation that issues a TLS write
//------------------------------------------------------------------------
void AsyncTlsSocketHandler::OnTlsRetry()
void AsyncTlsSocketHandler::OnTlsWrite( Status& status )
{
//----------------------------------------------------------------------
// Make sure the socket is uncorked before we do the TLS/SSL hand shake
// There's nothing to be done if the write simply failed
//----------------------------------------------------------------------
if( pCorked && pTls->NeedHandShake() )
if( !status.IsOK() ) return;

if( pTls->NeedHandShake() )
{
Status st = Uncork();
if( !st.IsOK() ) OnFault( st );
//--------------------------------------------------------------------
// Make sure the socket is uncorked before we do the TLS/SSL
// hand shake
//--------------------------------------------------------------------
if( pCorked )
{
Status st = Uncork();
if( !st.IsOK() ) status = st;
}

//--------------------------------------------------------------------
// Check if we need to switch on a revert state
//--------------------------------------------------------------------
if( status.IsOK() && status.code == suRetry && status.errNo == SSL_ERROR_WANT_READ )
{
pTlsHSRevert = WriteOnRead;
Status st = DisableUplink();
if( !st.IsOK() ) status = st;
//------------------------------------------------------------------
// Return early so the revert state wont get cleared
//------------------------------------------------------------------
return;
}
}

//----------------------------------------------------------------------
// If we got up until here we need to clear the revert state
//----------------------------------------------------------------------
if( pTlsHSRevert == WriteOnRead )
{
Status st = EnableUplink();
if( !st.IsOK() ) status = st;
}
pTlsHSRevert = None;
}

//------------------------------------------------------------------------
// Process the status of an operation that issues a TLS read
//------------------------------------------------------------------------
void AsyncTlsSocketHandler::OnTlsRead( Status& status )
{
//----------------------------------------------------------------------
// There's nothing to be done if the write simply failed
//----------------------------------------------------------------------
if( !status.IsOK() ) return;

if( pTls->NeedHandShake() )
{
//--------------------------------------------------------------------
// Make sure the socket is uncorked before we do the TLS/SSL
// hand shake
//--------------------------------------------------------------------
if( pCorked )
{
Status st = Uncork();
if( !st.IsOK() ) status = st;
}

//--------------------------------------------------------------------
// Check if we need to switch on a revert state
//--------------------------------------------------------------------
if( status.code == suRetry && status.errNo == SSL_ERROR_WANT_WRITE )
{
pTlsHSRevert = ReadOnWrite;
Status st = EnableUplink();
if( !st.IsOK() ) status = st;
//------------------------------------------------------------------
// Return early so the revert state wont get cleared
//------------------------------------------------------------------
return;
}
}

//----------------------------------------------------------------------
// If we got up until here we need to clear the revert state
//----------------------------------------------------------------------
if( pTlsHSRevert == ReadOnWrite )
{
Status st = DisableUplink();
if( !st.IsOK() ) status = st;
}
pTlsHSRevert = None;
}
}

56 changes: 51 additions & 5 deletions src/XrdCl/XrdClAsyncTlsSocketHandler.hh
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ namespace XrdCl

private:

//------------------------------------------------------------------------
//! Flags to indicate what is the TLS hand-shake revert state
//!
//! - None : there is no revert state
//! - ReadOnWrite : OnRead routines will be called on write event due to
//! TLS handshake
//! - WriteOnRead : OnWrite routines will be called on read event due to
//! TLS handshake
//------------------------------------------------------------------------
enum TlsHSRevert{ None, ReadOnWrite, WriteOnRead };

//------------------------------------------------------------------------
//! Handle a socket event
//------------------------------------------------------------------------
virtual void Event( uint8_t type, XrdCl::Socket *socket );

//------------------------------------------------------------------------
// Connect returned
//------------------------------------------------------------------------
Expand Down Expand Up @@ -111,13 +127,34 @@ namespace XrdCl
Status Flash();

//------------------------------------------------------------------------
// TLS/SSL layer asked to retry an I/O operation
// Process the status of an operation that issues a TLS write
//
// - If the operation failed there is nothing to be done.
//
// - If the operation succeeded with suRetry it might be that TLS layer
// asked to reissue the operation but on a read event (SSL_ERROR_WANT_READ)
// due to hand-shake re-negotiations, in this case we need to set a
// respective TLS revert state (pTlsHSRevert=WriteOnRead).
//
// - Otherwise we need to clear the revert state (pTlsHSRevert=None)
//
// It could be due to the socket layer or due to TLS/SSL session
// re-negotiation (in this case we have to make sure the socket is not
// corked).
//------------------------------------------------------------------------
inline void OnTlsRetry();
inline void OnTlsWrite( Status& st );

//------------------------------------------------------------------------
// Process the status of an operation that issues a TLS read
//
// - If the operation failed there is nothing to be done.
//
// - If the operation succeeded with suRetry it might be that TLS layer
// asked to reissue the operation but on a write event (SSL_ERROR_WANT_WRITE)
// due to hand-shake re-negotiations, in this case we need to set a
// respective TLS revert state (pTlsHSRevert=ReadOnWrite).
//
// - Otherwise we need to clear the revert state (pTlsHSRevert=None)
//
//------------------------------------------------------------------------
inline void OnTlsRead( Status& st );

//------------------------------------------------------------------------
// Data members
Expand All @@ -127,6 +164,15 @@ namespace XrdCl
std::unique_ptr<Tls> pTls;
bool pCorked;
bool pWrtHdrDone;
//------------------------------------------------------------------------
// In case during TLS hand-shake WantRead has been returned on write or
// WantWrite has been returned on read we need to flip the following events.
//
// None : all events should be processed normally
// ReadOnWrite : on write event the OnRead routines should be called
// WriteOnRead : on read event the OnWrite routines should be called
//------------------------------------------------------------------------
TlsHSRevert pTlsHSRevert;
ChunkList::iterator pCurrentChunk;
ChunkList *pWrtBody;
};
Expand Down

0 comments on commit a4ce2d2

Please sign in to comment.