aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@oriontransfer.co.nz>2024-01-18 06:08:59 +1300
committerGitHub <noreply@github.com>2024-01-18 02:08:59 +0900
commit3bbf5178a90efb036e7124a8fe7a9f4c3fc5ccc6 (patch)
treea18462346a058f17e6b1340c074942702052dc67
parent559b8ed1d16da11b2ccec556fc945be2b7afc139 (diff)
downloadruby-openssl-3bbf5178a90efb036e7124a8fe7a9f4c3fc5ccc6.tar.gz
Add support for IO#timeout. (#714)
* Add support for IO#timeout.
-rw-r--r--ext/openssl/extconf.rb1
-rw-r--r--ext/openssl/ossl_ssl.c15
-rw-r--r--lib/openssl/ssl.rb10
-rw-r--r--test/openssl/test_ssl.rb18
4 files changed, 42 insertions, 2 deletions
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 56f4a1c3..4119c72c 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -49,6 +49,7 @@ $defs.push("-D""OPENSSL_SUPPRESS_DEPRECATED")
have_func("rb_io_descriptor")
have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h") # Ruby 3.1
+have_func("rb_io_timeout", "ruby/io.h")
Logging::message "=== Checking for system dependent stuff... ===\n"
have_library("nsl", "t_open")
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 236d455f..9f374b65 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -1725,11 +1725,20 @@ no_exception_p(VALUE opts)
#define RUBY_IO_TIMEOUT_DEFAULT Qnil
#endif
+#ifdef HAVE_RB_IO_TIMEOUT
+#define IO_TIMEOUT_ERROR rb_eIOTimeoutError
+#else
+#define IO_TIMEOUT_ERROR rb_eIOError
+#endif
+
+
static void
io_wait_writable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT);
+ if (!rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
+ rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become writable!");
+ }
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
@@ -1741,7 +1750,9 @@ static void
io_wait_readable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT);
+ if (!rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
+ rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become readable!");
+ }
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
diff --git a/lib/openssl/ssl.rb b/lib/openssl/ssl.rb
index 7e59400c..75a74a3f 100644
--- a/lib/openssl/ssl.rb
+++ b/lib/openssl/ssl.rb
@@ -299,6 +299,16 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
def wait_writable(*args)
to_io.wait_writable(*args)
end
+
+ if IO.method_defined?(:timeout)
+ def timeout
+ to_io.timeout
+ end
+
+ def timeout=(value)
+ to_io.timeout=(value)
+ end
+ end
end
def verify_certificate_identity(cert, hostname)
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 07dc9a34..dcb7757a 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -193,6 +193,24 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
}
end
+ def test_read_with_timeout
+ omit "does not support timeout" unless IO.method_defined?(:timeout)
+
+ start_server do |port|
+ server_connect(port) do |ssl|
+ str = +("x" * 100 + "\n")
+ ssl.syswrite(str)
+ assert_equal(str, ssl.sysread(str.bytesize))
+
+ ssl.timeout = 1
+ assert_raise(IO::TimeoutError) {ssl.read(1)}
+
+ ssl.syswrite(str)
+ assert_equal(str, ssl.sysread(str.bytesize))
+ end
+ end
+ end
+
def test_getbyte
start_server { |port|
server_connect(port) { |ssl|