Loading...
Searching...
No Matches
XrdTlsSocket Class Reference

Socket wrapper for TLS I/O. More...

`#include <XrdTlsSocket.hh>`

Collaboration diagram for XrdTlsSocket:

## Public Types

enum | HS_Mode { TLS_HS_BLOCK = true , TLS_HS_NOBLK = false }
enum | RW_Mode { TLS_RNB_WNB , TLS_RNB_WBL , TLS_RBL_WNB , TLS_RBL_WBL }
enum | SDType { sdForce = 1 , sdImmed = 2 , sdWait = 3 }

## Public Member Functions

| XrdTlsSocket ()
| XrdTlsSocket (XrdTlsContext &ctx, int sfd, RW_Mode rwm, HS_Mode hsm, bool isClient, bool serial=true)
| ~XrdTlsSocket ()
| Destructor.
XrdTls::RC | Accept (std::string *eMsg=0)
XrdTls::RC | Connect (const char *thehost=0, std::string *eWhy=0)
XrdTlsContext * | Context ()
XrdTlsPeerCerts * | getCerts (bool ver=true)
const char * | Init (XrdTlsContext &ctx, int sfd, RW_Mode rwm, HS_Mode hsm, bool isClient, bool serial=true, const char *tid="")
bool | NeedHandShake ()
XrdTls::RC | Peek (char *buffer, size_t size, int &bytesPeek)
int | Pending (bool any=true)
XrdTls::RC | Read (char *buffer, size_t size, int &bytesRead)
| Read from the TLS connection. If necessary, a handshake will be done.
void | SetTraceID (const char *tid)
void | Shutdown (SDType=sdImmed)
const char * | Version ()
XrdTls::RC | Write (const char *buffer, size_t size, int &bytesOut)

## Detailed Description

Socket wrapper for TLS I/O.

Definition at line 39 of file XrdTlsSocket.hh.

## Member Enumeration Documentation

## HS_Mode

enum XrdTlsSocket::HS_Mode

Enumerator
TLS_HS_BLOCK | Always block during handshake.
TLS_HS_NOBLK | Do not block during handshake.

Definition at line 51 of file XrdTlsSocket.hh.

{
TLS_HS_BLOCK = true,
TLS_HS_NOBLK = false,
};
XrdTlsSocket::TLS_HS_BLOCK
@ TLS_HS_BLOCK
Always block during handshake.
Definition XrdTlsSocket.hh:53
XrdTlsSocket::TLS_HS_NOBLK
@ TLS_HS_NOBLK
Do not block during handshake.
Definition XrdTlsSocket.hh:54

## RW_Mode

enum XrdTlsSocket::RW_Mode

Enumerator
TLS_RNB_WNB | Non-blocking read non-blocking write.
TLS_RNB_WBL | Non-blocking read blocking write.
TLS_RBL_WNB | blocking read non-blocking write
TLS_RBL_WBL | blocking read blocking write

Definition at line 43 of file XrdTlsSocket.hh.

{
TLS_RNB_WNB,
TLS_RNB_WBL,
TLS_RBL_WNB,
TLS_RBL_WBL
};
XrdTlsSocket::TLS_RNB_WBL
@ TLS_RNB_WBL
Non-blocking read blocking write.
Definition XrdTlsSocket.hh:46
XrdTlsSocket::TLS_RBL_WNB
@ TLS_RBL_WNB
blocking read non-blocking write
Definition XrdTlsSocket.hh:47
XrdTlsSocket::TLS_RBL_WBL
@ TLS_RBL_WBL
blocking read blocking write
Definition XrdTlsSocket.hh:48
XrdTlsSocket::TLS_RNB_WNB
@ TLS_RNB_WNB
Non-blocking read non-blocking write.
Definition XrdTlsSocket.hh:45

## SDType

enum XrdTlsSocket::SDType

Tear down a TLS connection

Parameters

  One | of the following enums: sdForce - Forced shutdown (violates TLS standard). sdImmed - Immediate shutdown (don't wait for ack); the default. sdWait - Wait for peer acknowledgement (may be slow).

Enumerator
sdForce |
sdImmed |
sdWait |

Definition at line 225 of file XrdTlsSocket.hh.

{sdForce = 1, sdImmed = 2, sdWait = 3};
XrdTlsSocket::sdImmed
@ sdImmed
Definition XrdTlsSocket.hh:225
XrdTlsSocket::sdWait
@ sdWait
Definition XrdTlsSocket.hh:225
XrdTlsSocket::sdForce
@ sdForce
Definition XrdTlsSocket.hh:225

## Constructor & Destructor Documentation

## XrdTlsSocket() [1/2]

XrdTlsSocket::XrdTlsSocket | ( | XrdTlsContext & | ctx,
|  | int | sfd,
|  | XrdTlsSocket::RW_Mode | rwm,
|  | XrdTlsSocket::HS_Mode | hsm,
|  | bool | isClient,
|  | bool | serial = true )

Constructor - creates specified mode TLS I/O wrapper for given socket file descriptor. Note this constructor throws an exception should any error be encountered. Use the parameterless constructor if you wish to avoid handling exceptions. When an exception is thrown, you should print all associated errors by calling GetErrs() or PrintErrs().

Parameters

  ctx | - the context for the connection. Be aware that a context can be associated wity multiple connections.
  sfd | - the file descriptor associated with the connection.
  rwm | - One of the above enums describing how connection I/O should be handled.
  hsm | - One of the above enums describing how handshakes during read/write calls should be handled.
  isClient | - When true initialize for client use. Otherwise, initialize for server use.
  serial | - When true, only allows one thread to use the socket at a time to prevent SSL errors (default). When false does not add this protection, assuming caller does so.

Definition at line 130 of file XrdTlsSocket.cc.

: pImpl( new XrdTlsSocketImpl() )
{
// Simply initialize this object and throw an exception if it fails
//
const char *eMsg = Init(ctx, sfd, rwm, hsm, isClient, serial);
if (eMsg) throw std::invalid_argument( eMsg );
}
eMsg
#define eMsg(x)
Definition XrdSecsssAdmin.cc:53
XrdTlsSocket::Init
const char * Init(XrdTlsContext &ctx, int sfd, RW_Mode rwm, HS_Mode hsm, bool isClient, bool serial=true, const char *tid="")
Definition XrdTlsSocket.cc:421

References eMsg, and Init().

Here is the call graph for this function:

## XrdTlsSocket() [2/2]

XrdTlsSocket::XrdTlsSocket | ( |  | ) |

Constructor - reserves space for a TLS I/O wrapper. Use the Init() method to fully initialize this object.

Definition at line 121 of file XrdTlsSocket.cc.

: pImpl( new XrdTlsSocketImpl() )
{
}

## ~XrdTlsSocket()

XrdTlsSocket::~XrdTlsSocket | ( |  | ) |

Destructor.

Definition at line 147 of file XrdTlsSocket.cc.

{
if (pImpl->ssl) Shutdown(sdForce);
delete pImpl;
}
XrdTlsSocket::Shutdown
void Shutdown(SDType=sdImmed)
Definition XrdTlsSocket.cc:710

References sdForce, and Shutdown().

Here is the call graph for this function:

## Member Function Documentation

## Accept()

XrdTls::RC XrdTlsSocket::Accept | ( | std::string * | eMsg = 0 | ) |

Accept an incoming TLS connection

Parameters

  eMsg | - If not nil, receives the associated error message.

Returns
  The appropriate TLS return code.

Definition at line 157 of file XrdTlsSocket.cc.

{
EPNAME("Accept");
int rc, ssler;
bool wOK, aOK = true;
// Make sure there is a context here
//
if (pImpl->ssl == 0)
{AcceptEMsg(eWhy, "TLS socket has no context");
return XrdTls::TLS_CTX_Missing;
}
undoImpl ImplTracker(pImpl);
// Do some tracing
//
DBG_SOK("Accepting a TLS connection...");
// An accept may require several tries, so we do that here.
//
do{if ((rc = SSL_accept( pImpl->ssl )) > 0)
{if (pImpl->cOpts & xVerify)
{X509 *theCert = SSL_get_peer_certificate(pImpl->ssl);
if (!theCert)
{AcceptEMsg(eWhy, "x509 certificate is missing");
return XrdTls::TLS_CRT_Missing;
}
X509_free(theCert);
rc = SSL_get_verify_result(pImpl->ssl);
if (rc != X509_V_OK)
{AcceptEMsg(eWhy, "x509 certificate verification failed");
return XrdTls::TLS_VER_Error;
}
}
ImplTracker.KeepImpl();
// Reset the socket to blocking mode if we need to. Note that we have to brute
// force this on the socket as setting a BIO after accept has no effect. We
// also tell ssl that we want to block on a handshake from now on.
//
if (pImpl->cAttr & acc2Block)
// BIO_set_nbio(SSL_get_rbio(pImpl->ssl), 0); *Does not work after accept*
{int eNO = errno;
int flags = fcntl(pImpl->sFD, F_GETFL, 0);
flags &= ~O_NONBLOCK;
fcntl(pImpl->sFD, F_SETFL, flags);
SSL_set_mode(pImpl->ssl, SSL_MODE_AUTO_RETRY);
errno = eNO;
}
return XrdTls::TLS_AOK;
}
// Get the actual SSL error code.
//
ssler = Diagnose("TLS_Accept", rc, XrdTls::dbgSOK);
// Check why we did not succeed. We may be able to recover.
//
if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE) {
if(ssler == SSL_ERROR_SSL){
//In the case the accept does have an error related to OpenSSL,
//shutdown the TLSSocket in case the link associated to that connection
//is re-used
Shutdown();
}
aOK = false; break;
}
if (pImpl->hsNoBlock) return XrdTls::ssl2RC(ssler);
} while((wOK = Wait4OK(ssler == SSL_ERROR_WANT_READ)));
// If we are here then we got an error
//
AcceptEMsg(eWhy, (!aOK ? Err2Text(ssler).c_str() : XrdSysE2T(errno)));
errno = ECONNABORTED;
return XrdTls::TLS_SYS_Error;
}
EPNAME
#define EPNAME(x)
Definition XrdBwmTrace.hh:56
XrdSysE2T
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
DBG_SOK
#define DBG_SOK(y)
Definition XrdTlsTrace.hh:43
XrdTls::ssl2RC
static RC ssl2RC(int sslrc)
Definition XrdTls.cc:205
XrdTls::dbgSOK
static const int dbgSOK
Turn debugging in for socket operations.
Definition XrdTls.hh:101
XrdTls::TLS_AOK
@ TLS_AOK
All went well, will always be zero.
Definition XrdTls.hh:40
XrdTls::TLS_VER_Error
@ TLS_VER_Error
Certificate verification failed.
Definition XrdTls.hh:48
XrdTls::TLS_CRT_Missing
@ TLS_CRT_Missing
The x509 certificate missing.
Definition XrdTls.hh:42
XrdTls::TLS_SYS_Error
@ TLS_SYS_Error
A system call error occurred.
Definition XrdTls.hh:46
XrdTls::TLS_CTX_Missing
@ TLS_CTX_Missing
The TLS context is missing.
Definition XrdTls.hh:43

References DBG_SOK, XrdTls::dbgSOK, EPNAME, Shutdown(), XrdTls::ssl2RC(), XrdTls::TLS_AOK, XrdTls::TLS_CRT_Missing, XrdTls::TLS_CTX_Missing, XrdTls::TLS_SYS_Error, XrdTls::TLS_VER_Error, and XrdSysE2T().

Here is the call graph for this function:

## Connect()

XrdTls::RC XrdTlsSocket::Connect | ( | const char * | thehost = 0,
|  | std::string * | eWhy = 0 )

Establish a TLS connection

Parameters

  thehost | - The expected hostname. If nil the peername is not verified.
  eWhy | - If not nil, receives the associated error message.

Returns
  TLS_AOK if the operation was successful; otherwise the appropraite return code indicating the problem with eWhy, not nil, containing a description of the error.

Definition at line 254 of file XrdTlsSocket.cc.

{
EPNAME("Connect");
int ssler, rc;
bool wOK = true, aOK = true;
// Setup host verification of a host has been specified. This is a to-do
// when we move to new versions of SSL. For now, we use the notary object.
//
// Do some tracing
//
DBG_SOK("Connecting to " <<(thehost ? thehost : "unverified host")
<<(thehost && pImpl->cOpts & DNSok ? " dnsok" : "" ));
// Do the connect.
//
do{int rc = SSL_connect( pImpl->ssl );
if (rc == 1) break;
ssler = Diagnose("TLS_Connect", rc, XrdTls::dbgSOK);
if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
{aOK = false; break;}
if (pImpl->hsNoBlock) return XrdTls::ssl2RC(ssler);
} while((wOK = Wait4OK(ssler == SSL_ERROR_WANT_READ)));
// Check if everything went well. Note that we need to save the errno as
// we may be calling external methods that may generate other errors. We
//
if (!aOK || !wOK)
{rc = errno;
DBG_SOK("Handshake failed; "<<(!aOK ? Err2Text(ssler) : XrdSysE2T(rc)));
if (eWhy)
{const char *hName = (thehost ? thehost : "host");
*eWhy = "Unable to connect to ";
*eWhy += hName;
*eWhy += "; ";
if (!aOK) *eWhy += Err2Text(ssler);
else *eWhy += XrdSysE2T(rc);
}
if (!aOK) return XrdTls::ssl2RC(ssler);
errno = rc;
return XrdTls::TLS_SYS_Error;
}
// Set the hsDone flag!
//
pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
// Validate the host name if so desired. Note that cert verification is
// checked by the notary since hostname validation requires it. We currently
// do not support dnsOK but doing so just means we need to check the option
// and if on, also pass a XrdNetAddrInfo object generated from the hostname.
//
if (thehost)
{const char *eTxt = XrdTlsNotary::Validate(pImpl->ssl, thehost, 0);
if (eTxt)
{DBG_SOK(thehost << " verification failed; " <<eTxt);
if (eWhy)
{
*eWhy = "Unable to validate "; *eWhy += thehost;
*eWhy += "; "; *eWhy += eTxt;
}
return XrdTls::TLS_HNV_Error;
}
}
DBG_SOK("Connect completed without error.");
return XrdTls::TLS_AOK;
}
XrdTlsNotary::Validate
static const char * Validate(const SSL *ssl, const char *hName, XrdNetAddrInfo *netInfo=0)
Definition XrdTlsNotary.cc:56
XrdTls::TLS_HNV_Error
@ TLS_HNV_Error
A hostname validation error occuured.
Definition XrdTls.hh:44

References DBG_SOK, XrdTls::dbgSOK, EPNAME, XrdTls::ssl2RC(), XrdTls::TLS_AOK, XrdTls::TLS_HNV_Error, XrdTls::TLS_SYS_Error, XrdTlsNotary::Validate(), and XrdSysE2T().

Here is the call graph for this function:

## Context()

XrdTlsContext * XrdTlsSocket::Context | ( |  | ) |

Obtain context associated with this connection.

Returns
  : Tls connection object

Definition at line 332 of file XrdTlsSocket.cc.

{
return pImpl->tlsctx;
}

## getCerts()

XrdTlsPeerCerts * XrdTlsSocket::getCerts | ( | bool | ver = true | ) |

Get peer certificates associated with the socket.

Parameters

  ver | - When true, only return verified certificates.

Returns
  A pointer to the object holding the peer certificate and the associated chain. Nill is returned if there are no certificates of if verification did not occur but ver was true. The caller is responsible for deleting the returned object.

Definition at line 398 of file XrdTlsSocket.cc.

{
XrdSysMutexHelper mHelper;
// Serialize call if need be
//
if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
// If verified certs need to be returned, make sure the certs are verified
//
if (ver && SSL_get_verify_result(pImpl->ssl) != X509_V_OK) return 0;
// Get the certs and return
//
X509 *pcert = SSL_get_peer_certificate(pImpl->ssl);
if (pcert == 0) return 0;
return new XrdTlsPeerCerts(pcert, SSL_get_peer_cert_chain(pImpl->ssl));
}
XrdSysMutexHelper::Lock
void Lock(XrdSysMutex *Mutex)
Definition XrdSysPthread.hh:266

References XrdSysMutexHelper::Lock().

Here is the call graph for this function:

## Init()

const char * XrdTlsSocket::Init | ( | XrdTlsContext & | ctx,
|  | int | sfd,
|  | XrdTlsSocket::RW_Mode | rwm,
|  | XrdTlsSocket::HS_Mode | hsm,
|  | bool | isClient,
|  | bool | serial = true,
|  | const char * | tid = "" )

Initialize this object to handle the specified TLS I/O mode for the given file descriptor. Should an error occur, messages are automatically routed to the context message callback before returning.

Parameters

  ctx | - the context for the connection. Be aware that a context can be associated wity multiple connections.
  sfd | - the file descriptor associated with the connection.
  rwm | - One of the above enums describing how connection I/O should be handled.
  hsm | - One of the above enums describing how handshakes during read/write calls should be handled.
  isClient | - When true initialize for client use. Otherwise, initialize for server use.
  serial | - When true, only allows one thread to use the socket at a time to prevent SSL errors (default). When false does not add this protection, assuming caller does so.
  tid | - Trace identifier to appear in messages. The value must have the same lifetime as this object.

Returns
  =0 - object has been initialized.
  !0 - an error occurred, the return value is a pointer to a message summarizing the error. This message is the same as would be thrown by the parameterized constructor.

Definition at line 421 of file XrdTlsSocket.cc.

{
BIO *rbio, *wbio = 0;
// Make sure this connection is not in use if this is a client. Servers are
// allowed to throw away the previous setup as they reuse sockets.
//
if ( pImpl->ssl )
{if (isClient) return "TLS I/O: connection is still in use.";
else {SSL_free( pImpl->ssl );
pImpl->ssl = 0;
}
}
// Obtain the ssl object at this point.
//
pImpl->ssl = static_cast<SSL *>(ctx.Session());
if (pImpl->ssl == 0) return "TLS I/O: failed to get ssl object.";
// Initialze values from the context.
//
pImpl->tlsctx = &ctx;
const XrdTlsContext::CTX_Params *parms = ctx.GetParams();
pImpl->hsWait = (parms->opts & XrdTlsContext::hsto) * 1000; // Poll timeout
if (ctx.x509Verify()) pImpl->cOpts = xVerify;
else pImpl->cOpts = 0;
if (parms->opts & XrdTlsContext::dnsok) pImpl->cOpts |= DNSok;
pImpl->traceID = tid;
pImpl->isClient= isClient;
pImpl->isSerial= serial;
// Set the ssl object state to correspond to client or server type
//
if (isClient)
{SSL_set_connect_state( pImpl->ssl );
pImpl->cAttr = 0;
} else {
SSL_set_accept_state( pImpl->ssl );
pImpl->cAttr = isServer;
}
// Allocate right number of bio's and initialize them as requested. Note
// that when the read and write bios have the same attribue, we use only one.
//
switch( rwm )
{
case TLS_RNB_WNB:
rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
BIO_set_nbio( rbio, 1 );
break;
case TLS_RNB_WBL:
rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
BIO_set_nbio( rbio, 1 );
wbio = BIO_new_socket( sfd, BIO_NOCLOSE );
pImpl->cAttr |= wBlocking;
break;
case TLS_RBL_WNB:
rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
wbio = BIO_new_socket( sfd, BIO_NOCLOSE );
BIO_set_nbio( wbio, 1 );
pImpl->cAttr |= rBlocking;
break;
case TLS_RBL_WBL:
rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
pImpl->cAttr |= (rBlocking | wBlocking);
break;
default:
return "TLS I/O: invalid TLS rw mode."; break;
}
// Set correct handshake mode
//
if (hsm) pImpl->hsNoBlock = false;
else pImpl->hsNoBlock = true;
// Reset the handshake and fatal error indicators
//
pImpl->hsDone = false;
pImpl->fatal = 0;
// The glories of OpenSSL require that we do some fancy footwork with the
// handshake timeout. If there is one and this is a server and the server
// wants blocking reads, we initially set the socket as non-blocking as the
// bio's can handle it. Then after the accept we set it back to blocking mode.
// Note: doing this via the bio causes the socket to remain nonblocking. yech!
//
if (pImpl->hsWait && !hsm && pImpl->cAttr & rBlocking)
{int flags = fcntl(sfd, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(sfd, F_SETFL, flags);
pImpl->cAttr |= acc2Block;
}
// Finally attach the bios to the ssl object. When the ssl object is freed
// the bios will be freed as well.
//
pImpl->sFD = sfd;
if (wbio == 0) wbio = rbio;
SSL_set_bio( pImpl->ssl, rbio, wbio );
// All done. The caller will do an Accept() or Connect() afterwards.
//
return 0;
}
XrdTlsContext::hsto
static const uint64_t hsto
Mask to isolate the hsto.
Definition XrdTlsContext.hh:244
XrdTlsContext::x509Verify
bool x509Verify()
Definition XrdTlsContext.cc:1122
XrdTlsContext::Session
void * Session()
Definition XrdTlsContext.cc:896
XrdTlsContext::GetParams
const CTX_Params * GetParams()
Definition XrdTlsContext.cc:853
XrdTlsContext::dnsok
static const uint64_t dnsok
Trust DNS for host name.
Definition XrdTlsContext.hh:249
XrdTlsContext::CTX_Params::opts
uint64_t opts
Options as passed to the constructor.
Definition XrdTlsContext.hh:79

References XrdTlsContext::dnsok, XrdTlsContext::GetParams(), XrdTlsContext::hsto, XrdTlsContext::CTX_Params::opts, XrdTlsContext::Session(), TLS_RBL_WBL, TLS_RBL_WNB, TLS_RNB_WBL, TLS_RNB_WNB, and XrdTlsContext::x509Verify().

Referenced by XrdTlsSocket().

Here is the call graph for this function:
Here is the caller graph for this function:

## NeedHandShake()

bool XrdTlsSocket::NeedHandShake | ( |  | ) |

Returns
  : true if the TLS/SSL session is not established yet, false otherwise

Definition at line 849 of file XrdTlsSocket.cc.

{
XrdSysMutexHelper mHelper;
//------------------------------------------------------------------------
// Return an error if this socket received a fatal error as OpenSSL will
// SEGV when called after such an error. So, return something reasonable.
// Technically, we don't need to serialize this because nothing get
// modified. We do so anyway out of abundance of caution.
//------------------------------------------------------------------------
if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
if (pImpl->fatal) return false;
pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
return !pImpl->hsDone;
}

References XrdSysMutexHelper::Lock().

Here is the call graph for this function:

## Peek()

XrdTls::RC XrdTlsSocket::Peek | ( | char * | buffer,
|  | size_t | size,
|  | int & | bytesPeek )

Peek at the TLS connection data. If necessary, a handshake will be done.

Parameters

  buffer | - Pointer to buffer to hold the data.
  size | - The size of the buffer in bytes.
  bytesPeek | - Number of bytes placed in the buffer, if successful.

Returns
  TLS_AOK if the operation was successful; otherwise the appropraite return code indicating the problem.

Definition at line 538 of file XrdTlsSocket.cc.

{
EPNAME("Peek");
XrdSysMutexHelper mHelper;
int ssler;
//------------------------------------------------------------------------
// Serialize call if need be
//------------------------------------------------------------------------
if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
//------------------------------------------------------------------------
// Return an error if this socket received a fatal error as OpenSSL will
// SEGV when called after such an error.
//------------------------------------------------------------------------
if (pImpl->fatal)
{DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
return (XrdTls::RC)pImpl->fatal;
}
//------------------------------------------------------------------------
// If necessary, SSL_read() will negotiate a TLS/SSL session, so we don't
// have to explicitly call SSL_connect or SSL_do_handshake.
//------------------------------------------------------------------------
do{int rc = SSL_peek( pImpl->ssl, buffer, size );
// Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
// returned to the caller. So, we short-circuit all the error handling.
//
if( rc > 0 )
{bytesPeek = rc;
return XrdTls::TLS_AOK;
}
// We have a potential error. Get the SSL error code and whether or
// not the handshake actually is finished (semi-accurate)
//
pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
ssler = Diagnose("TLS_Peek", rc, XrdTls::dbgSIO);
// If the error isn't due to blocking issues, we are done.
//
if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
return XrdTls::ssl2RC(ssler);
// If the caller is non-blocking, the return the issue. Otherwise, block.
//
if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & rBlocking))
return XrdTls::ssl2RC(ssler);
} while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
// Return failure as the Wait failed.
//
return XrdTls::TLS_SYS_Error;
}
DBG_SIO
#define DBG_SIO(y)
Definition XrdTlsTrace.hh:47
XrdTls::dbgSIO
static const int dbgSIO
Turn debugging in for socket I/O.
Definition XrdTls.hh:102
XrdTls::RC
RC
Definition XrdTls.hh:40

References DBG_SIO, XrdTls::dbgSIO, EPNAME, XrdSysMutexHelper::Lock(), XrdTls::ssl2RC(), XrdTls::TLS_AOK, and XrdTls::TLS_SYS_Error.

Here is the call graph for this function:

## Pending()

int XrdTlsSocket::Pending | ( | bool | any = true | ) |

Check if data is pending or readable.

Parameters

  any | True to return in any data is in the queue. False to return the number of processed bytes.

Returns
  any = true: 1 is returned if there is data in the queue (processed or not). 0 is returned o/w. any = false: the number of processed bytes that are available. These are not necesarily data bytes. A subsequent read may still return 0.

Definition at line 602 of file XrdTlsSocket.cc.

{
XrdSysMutexHelper mHelper;
//------------------------------------------------------------------------
// Return an error if this socket received a fatal error as OpenSSL will
// SEGV when called after such an error. So, return something reasonable.
//------------------------------------------------------------------------
if (pImpl->fatal) return 0;
//------------------------------------------------------------------------
// Serialize call if need be
//------------------------------------------------------------------------
if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
if (!any) return SSL_pending(pImpl->ssl);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
return SSL_pending(pImpl->ssl) != 0;
#else
return SSL_has_pending(pImpl->ssl);
#endif
}

References XrdSysMutexHelper::Lock().

Here is the call graph for this function:

## Read()

XrdTls::RC XrdTlsSocket::Read | ( | char * | buffer,
|  | size_t | size,
|  | int & | bytesRead )

Read from the TLS connection. If necessary, a handshake will be done.

Parameters

  buffer | - Pointer to buffer to hold the data.
  size | - The size of the buffer in bytes.
  bytesRead | - Number of bytes placed in the buffer, if successful.

Returns
  TLS_AOK if the operation was successful; otherwise the appropraite return code indicating the problem.

Definition at line 631 of file XrdTlsSocket.cc.

{
EPNAME("Read");
XrdSysMutexHelper mHelper;
int ssler;
//------------------------------------------------------------------------
// Serialize call if need be
//------------------------------------------------------------------------
if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
//------------------------------------------------------------------------
// Return an error if this socket received a fatal error as OpenSSL will
// SEGV when called after such an error.
//------------------------------------------------------------------------
if (pImpl->fatal)
{DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
return (XrdTls::RC)pImpl->fatal;
}
//------------------------------------------------------------------------
// If necessary, SSL_read() will negotiate a TLS/SSL session, so we don't
// have to explicitly call SSL_connect or SSL_do_handshake.
//------------------------------------------------------------------------
do{int rc = SSL_read( pImpl->ssl, buffer, size );
// Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
// returned to the caller. So, we short-circuit all the error handling.
//
if( rc > 0 )
{bytesRead = rc;
DBG_SIO(rc <<" out of " <<size <<" bytes.");
return XrdTls::TLS_AOK;
}
// We have a potential error. Get the SSL error code and whether or
// not the handshake actually is finished (semi-accurate)
//
ssler = Diagnose("TLS_Read", rc, XrdTls::dbgSIO);
if (ssler == SSL_ERROR_NONE)
{bytesRead = 0;
DBG_SIO("0 out of " <<size <<" bytes.");
return XrdTls::TLS_AOK;
}
// If the error isn't due to blocking issues, we are done.
//
if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
return XrdTls::ssl2RC(ssler);
// If the caller is non-blocking for reads, return the issue. Otherwise,
// block for the caller.
//
if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & rBlocking))
return XrdTls::ssl2RC(ssler);
// Wait until we can read again.
} while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
return XrdTls::TLS_SYS_Error;
}

References DBG_SIO, XrdTls::dbgSIO, EPNAME, XrdSysMutexHelper::Lock(), XrdTls::ssl2RC(), XrdTls::TLS_AOK, and XrdTls::TLS_SYS_Error.

Here is the call graph for this function:

## SetTraceID()

void XrdTlsSocket::SetTraceID | ( | const char * | tid | ) |

Set the trace identifier (used when it's updated).

Parameters

  tid | - Pointer to trace identifier.

Definition at line 701 of file XrdTlsSocket.cc.

{
if (pImpl) pImpl->traceID = tid;
}

## Shutdown()

void XrdTlsSocket::Shutdown | ( | XrdTlsSocket::SDType | sdType = sdImmed | ) |

Definition at line 710 of file XrdTlsSocket.cc.

{
EPNAME("Shutdown");
XrdSysMutexHelper mHelper;
const char *how;
int sdMode, rc;
// Make sure we have an ssl object.
//
if (pImpl->ssl == 0) return;
// While we do not need to technically serialize here, we're being conservative
//
if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
// Perform shutdown as needed. This is required before freeing the ssl object.
// If we previously encountered a SYSCALL or SSL error, shutdown is prohibited!
// The following code is patterned after code in the public TomCat server.
//
if (!pImpl->fatal)
{switch(sdType)
{case sdForce: // Forced shutdown which violate TLS standard!
sdMode = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN;
how = "forced";
break;
case sdWait: // Wait for client acknowledgement
sdMode = 0;
how = "clean";
break;
default: // Fast shutdown, don't wait for ack (compliant)
sdMode = SSL_RECEIVED_SHUTDOWN;
how = "fast";
break;
}
DBG_SOK("Doing " <<how <<" shutdown.");
SSL_set_shutdown(pImpl->ssl, sdMode);
for (int i = 0; i < 4; i++)
{rc = SSL_shutdown( pImpl->ssl );
if (rc > 0) break;
if (rc < 0)
{rc = SSL_get_error( pImpl->ssl, rc );
if (rc == SSL_ERROR_WANT_READ || rc == SSL_ERROR_WANT_WRITE)
{if (Wait4OK(rc == SSL_ERROR_WANT_READ)) continue;
rc = SSL_ERROR_SYSCALL;
}
char msgBuff[512];
std::string eMsg = Err2Text(rc);
snprintf(msgBuff, sizeof(msgBuff),
"FD %d TLS shutdown failed; %s.\n",pImpl->sFD,eMsg.c_str());
XrdTls::Emsg(pImpl->traceID, msgBuff, true);
break;
}
}
}
// Now free the ssl object which will free all the BIO's associated with it
//
SSL_free( pImpl->ssl );
pImpl->ssl = 0;
pImpl->fatal = 0;
}
XrdTls::Emsg
static void Emsg(const char *tid, const char *msg=0, bool flush=true)
Definition XrdTls.cc:104

References DBG_SOK, XrdTls::Emsg(), eMsg, EPNAME, XrdSysMutexHelper::Lock(), sdForce, and sdWait.

Referenced by ~XrdTlsSocket(), and Accept().

Here is the call graph for this function:
Here is the caller graph for this function:

## Version()

const char * XrdTlsSocket::Version | ( |  | ) |

Returns
  The TLS version number being used.

Definition at line 888 of file XrdTlsSocket.cc.

{
// This call modifies nothing nor does it depend on modified data once the
// connection is esablished and doesn't need serialization.
//
return SSL_get_version(pImpl->ssl);
}

## Write()

XrdTls::RC XrdTlsSocket::Write | ( | const char * | buffer,
|  | size_t | size,
|  | int & | bytesOut )

Write to the TLS connection. If necessary, a handshake will be done.

Parameters

  buffer | - Pointer to buffer holding the data.
  size | - The size of the data to write.
  bytesOut | - Number of bytes actually written, if successful.

Returns
  TLS_AOK if the operation was successful; otherwise the appropraite return code indicating the problem.

Definition at line 778 of file XrdTlsSocket.cc.

{
EPNAME("Write");
XrdSysMutexHelper mHelper;
int ssler;
//------------------------------------------------------------------------
// Serialize call if need be
//------------------------------------------------------------------------
if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
//------------------------------------------------------------------------
// Return an error if this socket received a fatal error as OpenSSL will
// SEGV when called after such an error.
//------------------------------------------------------------------------
if (pImpl->fatal)
{DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
return (XrdTls::RC)pImpl->fatal;
}
//------------------------------------------------------------------------
// If necessary, SSL_write() will negotiate a TLS/SSL session, so we don't
// have to explicitly call SSL_connect or SSL_do_handshake.
//------------------------------------------------------------------------
do{int rc = SSL_write( pImpl->ssl, buffer, size );
// Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
// returned to the caller. So, we short-circuit all the error handling.
//
if (rc > 0)
{bytesWritten = rc;
DBG_SIO(rc <<" out of " <<size <<" bytes.");
return XrdTls::TLS_AOK;
}
// We have a potential error. Get the SSL error code and whether or
// not the handshake actually is finished (semi-accurate)
//
ssler = Diagnose("TLS_Write", rc, XrdTls::dbgSIO);
if (ssler == SSL_ERROR_NONE)
{bytesWritten = 0;
DBG_SIO(rc <<" out of " <<size <<" bytes.");
return XrdTls::TLS_AOK;
}
// If the error isn't due to blocking issues, we are done.
//
if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
return XrdTls::ssl2RC(ssler);
// If the caller is non-blocking for reads, return the issue. Otherwise,
// block for the caller.
//
if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & wBlocking))
return XrdTls::ssl2RC(ssler);
// Wait unil the write can get restarted
} while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
return XrdTls::TLS_SYS_Error;
}

References DBG_SIO, XrdTls::dbgSIO, EPNAME, XrdSysMutexHelper::Lock(), XrdTls::ssl2RC(), XrdTls::TLS_AOK, and XrdTls::TLS_SYS_Error.

Here is the call graph for this function:

The documentation for this class was generated from the following files:

- XrdTlsSocket.hh
- XrdTlsSocket.cc