Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 36 additions & 29 deletions ext/openssl/ossl_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1590,26 +1590,24 @@ ossl_ssl_s_alloc(VALUE klass)
}

static VALUE
peer_ip_address(VALUE self)
peer_ip_address(VALUE io)
{
VALUE remote_address = rb_funcall(rb_attr_get(self, id_i_io), rb_intern("remote_address"), 0);
VALUE remote_address = rb_funcall(io, rb_intern("remote_address"), 0);

return rb_funcall(remote_address, rb_intern("inspect_sockaddr"), 0);
}

static VALUE
fallback_peer_ip_address(VALUE self, VALUE args)
fallback_peer_ip_address(VALUE self, VALUE exc)
{
return rb_str_new_cstr("(null)");
}

static VALUE
peeraddr_ip_str(VALUE self)
peeraddr_ip_str(VALUE io)
{
VALUE rb_mErrno = rb_const_get(rb_cObject, rb_intern("Errno"));
VALUE rb_eSystemCallError = rb_const_get(rb_mErrno, rb_intern("SystemCallError"));

return rb_rescue2(peer_ip_address, self, fallback_peer_ip_address, (VALUE)0, rb_eSystemCallError, NULL);
return rb_rescue2(peer_ip_address, io, fallback_peer_ip_address, Qnil,
rb_eSystemCallError, (VALUE)0);
}

/*
Expand Down Expand Up @@ -1696,11 +1694,15 @@ ossl_ssl_setup(VALUE self)
return Qtrue;
}

static int
errno_mapped(void)
{
#ifdef _WIN32
#define ssl_get_error(ssl, ret) (errno = rb_w32_map_errno(WSAGetLastError()), SSL_get_error((ssl), (ret)))
return rb_w32_map_errno(WSAGetLastError());
#else
#define ssl_get_error(ssl, ret) SSL_get_error((ssl), (ret))
return errno;
#endif
}

static void
write_would_block(int nonblock)
Expand Down Expand Up @@ -1741,35 +1743,34 @@ static void
io_wait_writable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
if (!rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
if (!rb_io_wait(io, INT2NUM(RUBY_IO_WRITABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become writable!");
}
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_wait_writable(fptr->fd);
rb_thread_fd_writable(fptr->fd);
#endif
}

static void
io_wait_readable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
if (!rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
if (!rb_io_wait(io, INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become readable!");
}
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_wait_readable(fptr->fd);
rb_thread_wait_fd(fptr->fd);
#endif
}

static VALUE
ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
{
SSL *ssl;
int ret, ret2;
VALUE cb_state;
int nonblock = opts != Qfalse;

Expand All @@ -1779,7 +1780,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)

VALUE io = rb_attr_get(self, id_i_io);
for (;;) {
ret = func(ssl);
int ret = func(ssl);
int saved_errno = errno_mapped();

cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
Expand All @@ -1791,7 +1793,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
if (ret > 0)
break;

switch ((ret2 = ssl_get_error(ssl, ret))) {
int code = SSL_get_error(ssl, ret);
switch (code) {
case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
Expand All @@ -1805,10 +1808,11 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
case SSL_ERROR_SYSCALL:
#ifdef __APPLE__
/* See ossl_ssl_write_internal() */
if (errno == EPROTOTYPE)
if (saved_errno == EPROTOTYPE)
continue;
#endif
if (errno) rb_sys_fail(funcname);
if (saved_errno)
rb_exc_raise(rb_syserr_new(saved_errno, funcname));
/* fallthrough */
default: {
VALUE error_append = Qnil;
Expand All @@ -1829,10 +1833,10 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
ossl_raise(eSSLError,
"%s%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s%"PRIsVALUE,
funcname,
ret2 == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
ret2,
errno,
peeraddr_ip_str(self),
code == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
code,
saved_errno,
peeraddr_ip_str(io),
SSL_state_string_long(ssl),
error_append);
}
Expand Down Expand Up @@ -1974,6 +1978,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
for (;;) {
rb_str_locktmp(str);
int nread = SSL_read(ssl, RSTRING_PTR(str), ilen);
int saved_errno = errno_mapped();
rb_str_unlocktmp(str);

cb_state = rb_attr_get(self, ID_callback_state);
Expand All @@ -1983,7 +1988,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
rb_jump_tag(NUM2INT(cb_state));
}

switch (ssl_get_error(ssl, nread)) {
switch (SSL_get_error(ssl, nread)) {
case SSL_ERROR_NONE:
rb_str_set_len(str, nread);
return str;
Expand All @@ -2006,8 +2011,8 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
break;
case SSL_ERROR_SYSCALL:
if (!ERR_peek_error()) {
if (errno)
rb_sys_fail(0);
if (saved_errno)
rb_exc_raise(rb_syserr_new(saved_errno, "SSL_read"));
else {
/*
* The underlying BIO returned 0. This is actually a
Expand Down Expand Up @@ -2092,6 +2097,7 @@ ossl_ssl_write_internal_safe(VALUE _args)

for (;;) {
int nwritten = SSL_write(ssl, RSTRING_PTR(str), num);
int saved_errno = errno_mapped();

cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
Expand All @@ -2100,7 +2106,7 @@ ossl_ssl_write_internal_safe(VALUE _args)
rb_jump_tag(NUM2INT(cb_state));
}

switch (ssl_get_error(ssl, nwritten)) {
switch (SSL_get_error(ssl, nwritten)) {
case SSL_ERROR_NONE:
return INT2NUM(nwritten);
case SSL_ERROR_WANT_WRITE:
Expand All @@ -2121,10 +2127,11 @@ ossl_ssl_write_internal_safe(VALUE _args)
* make the error handling in line with the socket library.
* [Bug #14713] https://bugs.ruby-lang.org/issues/14713
*/
if (errno == EPROTOTYPE)
if (saved_errno == EPROTOTYPE)
continue;
#endif
if (errno) rb_sys_fail(0);
if (saved_errno)
rb_exc_raise(rb_syserr_new(saved_errno, "SSL_write"));
/* fallthrough */
default:
ossl_raise(eSSLError, "SSL_write");
Expand Down
Loading