GNUTLS: Improve rb_ssl_read_or_write()

* Set errno to 0 before attempting any read/write operations as it may
  affect our tests otherwise.

* Properly check whether the gnutls_record_recv()/gnutls_record_send()
  call failed and distinguish between kernel and library errors.
This commit is contained in:
Aaron Jones 2016-09-16 22:26:52 +00:00
parent d4e71871c0
commit 0071c423d5
No known key found for this signature in database
GPG key ID: EC6F86EE9CD840B5

View file

@ -304,32 +304,30 @@ rb_ssl_read_or_write(const int r_or_w, rb_fde_t *const F, void *const rbuf, cons
{ {
ssize_t ret; ssize_t ret;
errno = 0;
if(r_or_w == 0) if(r_or_w == 0)
ret = gnutls_record_recv(SSL_P(F), rbuf, count); ret = gnutls_record_recv(SSL_P(F), rbuf, count);
else else
ret = gnutls_record_send(SSL_P(F), wbuf, count); ret = gnutls_record_send(SSL_P(F), wbuf, count);
if(ret < 0) if(ret >= 0)
return ret;
if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (errno == 0 || rb_ignore_errno(errno))))
{ {
switch (ret) if(gnutls_record_get_direction(SSL_P(F)) == 0)
{ return RB_RW_SSL_NEED_READ;
case GNUTLS_E_AGAIN: else
case GNUTLS_E_INTERRUPTED: return RB_RW_SSL_NEED_WRITE;
if(rb_ignore_errno(errno))
{
if(gnutls_record_get_direction(*ssl) == 0)
return RB_RW_SSL_NEED_READ;
else
return RB_RW_SSL_NEED_WRITE;
break;
}
default:
F->ssl_errno = (unsigned long) -ret;
errno = EIO;
return RB_RW_IO_ERROR;
}
} }
return ret;
if(ret == GNUTLS_E_INTERRUPTED && errno != 0)
return RB_RW_IO_ERROR;
errno = EIO;
F->ssl_errno = (unsigned long) -ret;
return RB_RW_SSL_ERROR;
} }
ssize_t ssize_t