Socket functions like send
and receive
can be interrupted by signals. Because of this some extra code is needed, e.g. to check for errno == EINTR
. This is described on corresponding man pages.
I wonder how this works when OpenSSL functions are used, e.g. SSL_write
, SSL_read
. Their man pages do not say anything about signals. I also tried to google for this, but without luck. Do you know if OpenSSL handles signals internally, or some extra code is needed? If yes, how to check if function call was interrupted by signal?
Update:
Looks that OpenSSL does not handle retries. It only sets the "should retry" flag on BIO object. So I need to use something like this to detect if call was interrupted and retry is needed:
int result = SSL_write(ssl, buff, length);
if ((result < 0) && BIO_should_retry(SSL_get_wbio(ssl)))
// need to retry
int result = SSL_read(ssl, buff, length);
if ((result < 0) && BIO_should_retry(SSL_get_rbio(ssl)))
// need to retry
As being a libray OpenSSL cannot make any assumptions on how signals are handled by the particular program using it. So it needs to handle the case of a system call being interupted on the reception of a signal.
A check whether it made sense to retry a failed read()
is implemented inside OpenSSL.
Use BIO_should_retry()
if BIO_read()
(or BIO_write()
) failed.
For an example read here: http://cvs.openssl.org/rlog?f=openssl/demos/bio/sconnect.c
The implementation's relevant code follows:
static int sock_read(BIO *b, char *out, int outl)
{
int ret=0;
if (out != NULL)
{
clear_socket_error();
ret=readsocket(b->num,out,outl);
BIO_clear_retry_flags(b);
if (ret <= 0)
{
if (BIO_sock_should_retry(ret))
BIO_set_retry_read(b);
}
}
return(ret);
}
The relevant referred functions are here:
(get_last_socket_error()
returns errno
on most IXish platforms)
int BIO_sock_should_retry(int i)
{
int err;
if ((i == 0) || (i == -1))
{
err=get_last_socket_error();
#if defined(OPENSSL_SYS_WINDOWS) && 0 /* more microsoft stupidity? perhaps not? Ben 4/1/99 */
if ((i == -1) && (err == 0))
return(1);
#endif
return(BIO_sock_non_fatal_error(err));
}
return(0);
}
int BIO_sock_non_fatal_error(int err)
{
switch (err)
{
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_NETWARE)
# if defined(WSAEWOULDBLOCK)
case WSAEWOULDBLOCK:
# endif
# if 0 /* This appears to always be an error */
# if defined(WSAENOTCONN)
case WSAENOTCONN:
# endif
# endif
#endif
#ifdef EWOULDBLOCK
# ifdef WSAEWOULDBLOCK
# if WSAEWOULDBLOCK != EWOULDBLOCK
case EWOULDBLOCK:
# endif
# else
case EWOULDBLOCK:
# endif
#endif
#if defined(ENOTCONN)
case ENOTCONN:
#endif
#ifdef EINTR
case EINTR:
#endif
#ifdef EAGAIN
# if EWOULDBLOCK != EAGAIN
case EAGAIN:
# endif
#endif
#ifdef EPROTO
case EPROTO:
#endif
#ifdef EINPROGRESS
case EINPROGRESS:
#endif
#ifdef EALREADY
case EALREADY:
#endif
return(1);
/* break; */
default:
break;
}
return(0);
}
For details see sock_read()
to be inspected here: http://cvs.openssl.org/rlog?f=openssl/crypto/bio/bss_sock.c
(The sources quoted along with the indention used is from version 1.0.1e.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With