XRootD
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)
 
XrdTlsContextContext ()
 
XrdTlsPeerCertsgetCerts (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

Enumerator
TLS_HS_BLOCK 

Always block during handshake.

TLS_HS_NOBLK 

Do not block during handshake.

Definition at line 51 of file XrdTlsSocket.hh.

52{
53 TLS_HS_BLOCK = true,
54 TLS_HS_NOBLK = false,
55};
@ TLS_HS_BLOCK
Always block during handshake.
@ TLS_HS_NOBLK
Do not block during handshake.

◆ 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.

44{
49};
@ TLS_RNB_WBL
Non-blocking read blocking write.
@ TLS_RBL_WNB
blocking read non-blocking write
@ TLS_RBL_WBL
blocking read blocking write
@ TLS_RNB_WNB
Non-blocking read non-blocking write.

◆ SDType

Tear down a TLS connection

Parameters
Oneof 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.

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.

134 : pImpl( new XrdTlsSocketImpl() )
135{
136
137// Simply initialize this object and throw an exception if it fails
138//
139 const char *eMsg = Init(ctx, sfd, rwm, hsm, isClient, serial);
140 if (eMsg) throw std::invalid_argument( eMsg );
141}
#define eMsg(x)
const char * Init(XrdTlsContext &ctx, int sfd, RW_Mode rwm, HS_Mode hsm, bool isClient, bool serial=true, const char *tid="")

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.

121 : pImpl( new XrdTlsSocketImpl() )
122{
123
124}

◆ ~XrdTlsSocket()

XrdTlsSocket::~XrdTlsSocket ( )

Destructor.

Definition at line 147 of file XrdTlsSocket.cc.

148{
149 if (pImpl->ssl) Shutdown(sdForce);
150 delete pImpl;
151}
void Shutdown(SDType=sdImmed)

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.

158{
159 EPNAME("Accept");
160 int rc, ssler;
161 bool wOK, aOK = true;
162
163// Make sure there is a context here
164//
165 if (pImpl->ssl == 0)
166 {AcceptEMsg(eWhy, "TLS socket has no context");
168 }
169 undoImpl ImplTracker(pImpl);
170
171// Do some tracing
172//
173 DBG_SOK("Accepting a TLS connection...");
174
175// An accept may require several tries, so we do that here.
176//
177do{if ((rc = SSL_accept( pImpl->ssl )) > 0)
178 {if (pImpl->cOpts & xVerify)
179 {X509 *theCert = SSL_get_peer_certificate(pImpl->ssl);
180 if (!theCert)
181 {AcceptEMsg(eWhy, "x509 certificate is missing");
183 }
184 X509_free(theCert);
185 rc = SSL_get_verify_result(pImpl->ssl);
186 if (rc != X509_V_OK)
187 {AcceptEMsg(eWhy, "x509 certificate verification failed");
189 }
190 }
191 ImplTracker.KeepImpl();
192
193// Reset the socket to blocking mode if we need to. Note that we have to brute
194// force this on the socket as setting a BIO after accept has no effect. We
195// also tell ssl that we want to block on a handshake from now on.
196//
197 if (pImpl->cAttr & acc2Block)
198// BIO_set_nbio(SSL_get_rbio(pImpl->ssl), 0); *Does not work after accept*
199 {int eNO = errno;
200 int flags = fcntl(pImpl->sFD, F_GETFL, 0);
201 flags &= ~O_NONBLOCK;
202 fcntl(pImpl->sFD, F_SETFL, flags);
203 SSL_set_mode(pImpl->ssl, SSL_MODE_AUTO_RETRY);
204 errno = eNO;
205 }
206 return XrdTls::TLS_AOK;
207 }
208
209 // Get the actual SSL error code.
210 //
211 ssler = Diagnose("TLS_Accept", rc, XrdTls::dbgSOK);
212
213 // Check why we did not succeed. We may be able to recover.
214 //
215 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE) {
216 if(ssler == SSL_ERROR_SSL){
217 //In the case the accept does have an error related to OpenSSL,
218 //shutdown the TLSSocket in case the link associated to that connection
219 //is re-used
220 Shutdown();
221 }
222 aOK = false; break;
223 }
224
225 if (pImpl->hsNoBlock) return XrdTls::ssl2RC(ssler);
226
227 } while((wOK = Wait4OK(ssler == SSL_ERROR_WANT_READ)));
228
229// If we are here then we got an error
230//
231 AcceptEMsg(eWhy, (!aOK ? Err2Text(ssler).c_str() : XrdSysE2T(errno)));
232 errno = ECONNABORTED;
234}
#define EPNAME(x)
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
#define DBG_SOK(y)
static RC ssl2RC(int sslrc)
Definition XrdTls.cc:205
static const int dbgSOK
Turn debugging in for socket operations.
Definition XrdTls.hh:101
@ TLS_AOK
All went well, will always be zero.
Definition XrdTls.hh:40
@ TLS_VER_Error
Certificate verification failed.
Definition XrdTls.hh:48
@ TLS_CRT_Missing
The x509 certificate missing.
Definition XrdTls.hh:42
@ TLS_SYS_Error
A system call error occurred.
Definition XrdTls.hh:46
@ 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.

255{
256 EPNAME("Connect");
257 int ssler, rc;
258 bool wOK = true, aOK = true;
259
260// Setup host verification of a host has been specified. This is a to-do
261// when we move to new versions of SSL. For now, we use the notary object.
262//
263
264// Do some tracing
265//
266 DBG_SOK("Connecting to " <<(thehost ? thehost : "unverified host")
267 <<(thehost && pImpl->cOpts & DNSok ? " dnsok" : "" ));
268
269// Do the connect.
270//
271do{int rc = SSL_connect( pImpl->ssl );
272 if (rc == 1) break;
273
274 ssler = Diagnose("TLS_Connect", rc, XrdTls::dbgSOK);
275
276 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
277 {aOK = false; break;}
278
279 if (pImpl->hsNoBlock) return XrdTls::ssl2RC(ssler);
280
281 } while((wOK = Wait4OK(ssler == SSL_ERROR_WANT_READ)));
282
283// Check if everything went well. Note that we need to save the errno as
284// we may be calling external methods that may generate other errors. We
285//
286 if (!aOK || !wOK)
287 {rc = errno;
288 DBG_SOK("Handshake failed; "<<(!aOK ? Err2Text(ssler) : XrdSysE2T(rc)));
289 if (eWhy)
290 {const char *hName = (thehost ? thehost : "host");
291 *eWhy = "Unable to connect to ";
292 *eWhy += hName;
293 *eWhy += "; ";
294 if (!aOK) *eWhy += Err2Text(ssler);
295 else *eWhy += XrdSysE2T(rc);
296 }
297 if (!aOK) return XrdTls::ssl2RC(ssler);
298 errno = rc;
300 }
301
302// Set the hsDone flag!
303//
304 pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
305
306// Validate the host name if so desired. Note that cert verification is
307// checked by the notary since hostname validation requires it. We currently
308// do not support dnsOK but doing so just means we need to check the option
309// and if on, also pass a XrdNetAddrInfo object generated from the hostname.
310//
311 if (thehost)
312 {const char *eTxt = XrdTlsNotary::Validate(pImpl->ssl, thehost, 0);
313 if (eTxt)
314 {DBG_SOK(thehost << " verification failed; " <<eTxt);
315 if (eWhy)
316 {
317 *eWhy = "Unable to validate "; *eWhy += thehost;
318 *eWhy += "; "; *eWhy += eTxt;
319 }
321 }
322 }
323
324 DBG_SOK("Connect completed without error.");
325 return XrdTls::TLS_AOK;
326}
static const char * Validate(const SSL *ssl, const char *hName, XrdNetAddrInfo *netInfo=0)
@ 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.

333{
334 return pImpl->tlsctx;
335}

◆ 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.

399{
400 XrdSysMutexHelper mHelper;
401
402// Serialize call if need be
403//
404 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
405
406// If verified certs need to be returned, make sure the certs are verified
407//
408 if (ver && SSL_get_verify_result(pImpl->ssl) != X509_V_OK) return 0;
409
410// Get the certs and return
411//
412 X509 *pcert = SSL_get_peer_certificate(pImpl->ssl);
413 if (pcert == 0) return 0;
414 return new XrdTlsPeerCerts(pcert, SSL_get_peer_cert_chain(pImpl->ssl));
415}
void Lock(XrdSysMutex *Mutex)

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.

426{
427 BIO *rbio, *wbio = 0;
428
429// Make sure this connection is not in use if this is a client. Servers are
430// allowed to throw away the previous setup as they reuse sockets.
431//
432 if ( pImpl->ssl )
433 {if (isClient) return "TLS I/O: connection is still in use.";
434 else {SSL_free( pImpl->ssl );
435 pImpl->ssl = 0;
436 }
437 }
438
439// Obtain the ssl object at this point.
440//
441 pImpl->ssl = static_cast<SSL *>(ctx.Session());
442 if (pImpl->ssl == 0) return "TLS I/O: failed to get ssl object.";
443
444// Initialze values from the context.
445//
446 pImpl->tlsctx = &ctx;
447 const XrdTlsContext::CTX_Params *parms = ctx.GetParams();
448 pImpl->hsWait = (parms->opts & XrdTlsContext::hsto) * 1000; // Poll timeout
449 if (ctx.x509Verify()) pImpl->cOpts = xVerify;
450 else pImpl->cOpts = 0;
451 if (parms->opts & XrdTlsContext::dnsok) pImpl->cOpts |= DNSok;
452 pImpl->traceID = tid;
453 pImpl->isClient= isClient;
454 pImpl->isSerial= serial;
455
456// Set the ssl object state to correspond to client or server type
457//
458 if (isClient)
459 {SSL_set_connect_state( pImpl->ssl );
460 pImpl->cAttr = 0;
461 } else {
462 SSL_set_accept_state( pImpl->ssl );
463 pImpl->cAttr = isServer;
464 }
465
466// Allocate right number of bio's and initialize them as requested. Note
467// that when the read and write bios have the same attribue, we use only one.
468//
469 switch( rwm )
470 {
471 case TLS_RNB_WNB:
472 rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
473 BIO_set_nbio( rbio, 1 );
474 break;
475
476 case TLS_RNB_WBL:
477 rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
478 BIO_set_nbio( rbio, 1 );
479 wbio = BIO_new_socket( sfd, BIO_NOCLOSE );
480 pImpl->cAttr |= wBlocking;
481 break;
482
483 case TLS_RBL_WNB:
484 rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
485 wbio = BIO_new_socket( sfd, BIO_NOCLOSE );
486 BIO_set_nbio( wbio, 1 );
487 pImpl->cAttr |= rBlocking;
488 break;
489
490 case TLS_RBL_WBL:
491 rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
492 pImpl->cAttr |= (rBlocking | wBlocking);
493 break;
494
495 default:
496 return "TLS I/O: invalid TLS rw mode."; break;
497 }
498
499// Set correct handshake mode
500//
501 if (hsm) pImpl->hsNoBlock = false;
502 else pImpl->hsNoBlock = true;
503
504// Reset the handshake and fatal error indicators
505//
506 pImpl->hsDone = false;
507 pImpl->fatal = 0;
508
509// The glories of OpenSSL require that we do some fancy footwork with the
510// handshake timeout. If there is one and this is a server and the server
511// wants blocking reads, we initially set the socket as non-blocking as the
512// bio's can handle it. Then after the accept we set it back to blocking mode.
513// Note: doing this via the bio causes the socket to remain nonblocking. yech!
514//
515 if (pImpl->hsWait && !hsm && pImpl->cAttr & rBlocking)
516 {int flags = fcntl(sfd, F_GETFL, 0);
517 flags |= O_NONBLOCK;
518 fcntl(sfd, F_SETFL, flags);
519 pImpl->cAttr |= acc2Block;
520 }
521
522// Finally attach the bios to the ssl object. When the ssl object is freed
523// the bios will be freed as well.
524//
525 pImpl->sFD = sfd;
526 if (wbio == 0) wbio = rbio;
527 SSL_set_bio( pImpl->ssl, rbio, wbio );
528
529// All done. The caller will do an Accept() or Connect() afterwards.
530//
531 return 0;
532}
static const uint64_t hsto
Mask to isolate the hsto.
const CTX_Params * GetParams()
static const uint64_t dnsok
Trust DNS for host name.
uint64_t opts
Options as passed to the constructor.

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.

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

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.

539 {
540 EPNAME("Peek");
541 XrdSysMutexHelper mHelper;
542 int ssler;
543
544 //------------------------------------------------------------------------
545 // Serialize call if need be
546 //------------------------------------------------------------------------
547
548 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
549
550 //------------------------------------------------------------------------
551 // Return an error if this socket received a fatal error as OpenSSL will
552 // SEGV when called after such an error.
553 //------------------------------------------------------------------------
554
555 if (pImpl->fatal)
556 {DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
557 return (XrdTls::RC)pImpl->fatal;
558 }
559
560 //------------------------------------------------------------------------
561 // If necessary, SSL_read() will negotiate a TLS/SSL session, so we don't
562 // have to explicitly call SSL_connect or SSL_do_handshake.
563 //------------------------------------------------------------------------
564
565 do{int rc = SSL_peek( pImpl->ssl, buffer, size );
566
567 // Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
568 // returned to the caller. So, we short-circuit all the error handling.
569 //
570 if( rc > 0 )
571 {bytesPeek = rc;
572 return XrdTls::TLS_AOK;
573 }
574
575 // We have a potential error. Get the SSL error code and whether or
576 // not the handshake actually is finished (semi-accurate)
577 //
578 pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
579 ssler = Diagnose("TLS_Peek", rc, XrdTls::dbgSIO);
580
581 // If the error isn't due to blocking issues, we are done.
582 //
583 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
584 return XrdTls::ssl2RC(ssler);
585
586 // If the caller is non-blocking, the return the issue. Otherwise, block.
587 //
588 if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & rBlocking))
589 return XrdTls::ssl2RC(ssler);
590
591 } while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
592
593 // Return failure as the Wait failed.
594 //
596 }
#define DBG_SIO(y)
static const int dbgSIO
Turn debugging in for socket I/O.
Definition XrdTls.hh:102

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
anyTrue 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.

603{
604 XrdSysMutexHelper mHelper;
605
606 //------------------------------------------------------------------------
607 // Return an error if this socket received a fatal error as OpenSSL will
608 // SEGV when called after such an error. So, return something reasonable.
609 //------------------------------------------------------------------------
610
611 if (pImpl->fatal) return 0;
612
613 //------------------------------------------------------------------------
614 // Serialize call if need be
615 //------------------------------------------------------------------------
616
617 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
618
619 if (!any) return SSL_pending(pImpl->ssl);
620#if OPENSSL_VERSION_NUMBER < 0x10100000L
621 return SSL_pending(pImpl->ssl) != 0;
622#else
623 return SSL_has_pending(pImpl->ssl);
624#endif
625}

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.

632{
633 EPNAME("Read");
634 XrdSysMutexHelper mHelper;
635 int ssler;
636
637 //------------------------------------------------------------------------
638 // Serialize call if need be
639 //------------------------------------------------------------------------
640
641 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
642
643 //------------------------------------------------------------------------
644 // Return an error if this socket received a fatal error as OpenSSL will
645 // SEGV when called after such an error.
646 //------------------------------------------------------------------------
647
648 if (pImpl->fatal)
649 {DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
650 return (XrdTls::RC)pImpl->fatal;
651 }
652
653 //------------------------------------------------------------------------
654 // If necessary, SSL_read() will negotiate a TLS/SSL session, so we don't
655 // have to explicitly call SSL_connect or SSL_do_handshake.
656 //------------------------------------------------------------------------
657
658 do{int rc = SSL_read( pImpl->ssl, buffer, size );
659
660 // Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
661 // returned to the caller. So, we short-circuit all the error handling.
662 //
663 if( rc > 0 )
664 {bytesRead = rc;
665 DBG_SIO(rc <<" out of " <<size <<" bytes.");
666 return XrdTls::TLS_AOK;
667 }
668
669 // We have a potential error. Get the SSL error code and whether or
670 // not the handshake actually is finished (semi-accurate)
671 //
672 ssler = Diagnose("TLS_Read", rc, XrdTls::dbgSIO);
673 if (ssler == SSL_ERROR_NONE)
674 {bytesRead = 0;
675 DBG_SIO("0 out of " <<size <<" bytes.");
676 return XrdTls::TLS_AOK;
677 }
678
679 // If the error isn't due to blocking issues, we are done.
680 //
681 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
682 return XrdTls::ssl2RC(ssler);
683
684 // If the caller is non-blocking for reads, return the issue. Otherwise,
685 // block for the caller.
686 //
687 if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & rBlocking))
688 return XrdTls::ssl2RC(ssler);
689
690 // Wait until we can read again.
691
692 } while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
693
695 }

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.

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

◆ Shutdown()

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

Definition at line 710 of file XrdTlsSocket.cc.

711{
712 EPNAME("Shutdown");
713 XrdSysMutexHelper mHelper;
714 const char *how;
715 int sdMode, rc;
716
717// Make sure we have an ssl object.
718//
719 if (pImpl->ssl == 0) return;
720
721// While we do not need to technically serialize here, we're being conservative
722//
723 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
724
725// Perform shutdown as needed. This is required before freeing the ssl object.
726// If we previously encountered a SYSCALL or SSL error, shutdown is prohibited!
727// The following code is patterned after code in the public TomCat server.
728//
729 if (!pImpl->fatal)
730 {switch(sdType)
731 {case sdForce: // Forced shutdown which violate TLS standard!
732 sdMode = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN;
733 how = "forced";
734 break;
735 case sdWait: // Wait for client acknowledgement
736 sdMode = 0;
737 how = "clean";
738 break;
739 default: // Fast shutdown, don't wait for ack (compliant)
740 sdMode = SSL_RECEIVED_SHUTDOWN;
741 how = "fast";
742 break;
743 }
744
745 DBG_SOK("Doing " <<how <<" shutdown.");
746 SSL_set_shutdown(pImpl->ssl, sdMode);
747
748 for (int i = 0; i < 4; i++)
749 {rc = SSL_shutdown( pImpl->ssl );
750 if (rc > 0) break;
751 if (rc < 0)
752 {rc = SSL_get_error( pImpl->ssl, rc );
753 if (rc == SSL_ERROR_WANT_READ || rc == SSL_ERROR_WANT_WRITE)
754 {if (Wait4OK(rc == SSL_ERROR_WANT_READ)) continue;
755 rc = SSL_ERROR_SYSCALL;
756 }
757 char msgBuff[512];
758 std::string eMsg = Err2Text(rc);
759 snprintf(msgBuff, sizeof(msgBuff),
760 "FD %d TLS shutdown failed; %s.\n",pImpl->sFD,eMsg.c_str());
761 XrdTls::Emsg(pImpl->traceID, msgBuff, true);
762 break;
763 }
764 }
765 }
766
767// Now free the ssl object which will free all the BIO's associated with it
768//
769 SSL_free( pImpl->ssl );
770 pImpl->ssl = 0;
771 pImpl->fatal = 0;
772}
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.

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

◆ 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.

780{
781 EPNAME("Write");
782 XrdSysMutexHelper mHelper;
783 int ssler;
784
785 //------------------------------------------------------------------------
786 // Serialize call if need be
787 //------------------------------------------------------------------------
788
789 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
790
791 //------------------------------------------------------------------------
792 // Return an error if this socket received a fatal error as OpenSSL will
793 // SEGV when called after such an error.
794 //------------------------------------------------------------------------
795
796 if (pImpl->fatal)
797 {DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
798 return (XrdTls::RC)pImpl->fatal;
799 }
800
801 //------------------------------------------------------------------------
802 // If necessary, SSL_write() will negotiate a TLS/SSL session, so we don't
803 // have to explicitly call SSL_connect or SSL_do_handshake.
804 //------------------------------------------------------------------------
805
806 do{int rc = SSL_write( pImpl->ssl, buffer, size );
807
808 // Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
809 // returned to the caller. So, we short-circuit all the error handling.
810 //
811 if (rc > 0)
812 {bytesWritten = rc;
813 DBG_SIO(rc <<" out of " <<size <<" bytes.");
814 return XrdTls::TLS_AOK;
815 }
816
817 // We have a potential error. Get the SSL error code and whether or
818 // not the handshake actually is finished (semi-accurate)
819 //
820 ssler = Diagnose("TLS_Write", rc, XrdTls::dbgSIO);
821 if (ssler == SSL_ERROR_NONE)
822 {bytesWritten = 0;
823 DBG_SIO(rc <<" out of " <<size <<" bytes.");
824 return XrdTls::TLS_AOK;
825 }
826
827 // If the error isn't due to blocking issues, we are done.
828 //
829 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
830 return XrdTls::ssl2RC(ssler);
831
832 // If the caller is non-blocking for reads, return the issue. Otherwise,
833 // block for the caller.
834 //
835 if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & wBlocking))
836 return XrdTls::ssl2RC(ssler);
837
838 // Wait unil the write can get restarted
839
840 } while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
841
843}

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: