Skip to content

Commit 3bbf517

Browse files
authored
Add support for IO#timeout. (#714)
* Add support for IO#timeout.
1 parent 559b8ed commit 3bbf517

File tree

4 files changed

+42
-2
lines changed

4 files changed

+42
-2
lines changed

ext/openssl/extconf.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949

5050
have_func("rb_io_descriptor")
5151
have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h") # Ruby 3.1
52+
have_func("rb_io_timeout", "ruby/io.h")
5253

5354
Logging::message "=== Checking for system dependent stuff... ===\n"
5455
have_library("nsl", "t_open")

ext/openssl/ossl_ssl.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,11 +1725,20 @@ no_exception_p(VALUE opts)
17251725
#define RUBY_IO_TIMEOUT_DEFAULT Qnil
17261726
#endif
17271727

1728+
#ifdef HAVE_RB_IO_TIMEOUT
1729+
#define IO_TIMEOUT_ERROR rb_eIOTimeoutError
1730+
#else
1731+
#define IO_TIMEOUT_ERROR rb_eIOError
1732+
#endif
1733+
1734+
17281735
static void
17291736
io_wait_writable(VALUE io)
17301737
{
17311738
#ifdef HAVE_RB_IO_MAYBE_WAIT
1732-
rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT);
1739+
if (!rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
1740+
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become writable!");
1741+
}
17331742
#else
17341743
rb_io_t *fptr;
17351744
GetOpenFile(io, fptr);
@@ -1741,7 +1750,9 @@ static void
17411750
io_wait_readable(VALUE io)
17421751
{
17431752
#ifdef HAVE_RB_IO_MAYBE_WAIT
1744-
rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT);
1753+
if (!rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
1754+
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become readable!");
1755+
}
17451756
#else
17461757
rb_io_t *fptr;
17471758
GetOpenFile(io, fptr);

lib/openssl/ssl.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,16 @@ def wait_readable(*args)
299299
def wait_writable(*args)
300300
to_io.wait_writable(*args)
301301
end
302+
303+
if IO.method_defined?(:timeout)
304+
def timeout
305+
to_io.timeout
306+
end
307+
308+
def timeout=(value)
309+
to_io.timeout=(value)
310+
end
311+
end
302312
end
303313

304314
def verify_certificate_identity(cert, hostname)

test/openssl/test_ssl.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,24 @@ def test_sysread_and_syswrite
193193
}
194194
end
195195

196+
def test_read_with_timeout
197+
omit "does not support timeout" unless IO.method_defined?(:timeout)
198+
199+
start_server do |port|
200+
server_connect(port) do |ssl|
201+
str = +("x" * 100 + "\n")
202+
ssl.syswrite(str)
203+
assert_equal(str, ssl.sysread(str.bytesize))
204+
205+
ssl.timeout = 1
206+
assert_raise(IO::TimeoutError) {ssl.read(1)}
207+
208+
ssl.syswrite(str)
209+
assert_equal(str, ssl.sysread(str.bytesize))
210+
end
211+
end
212+
end
213+
196214
def test_getbyte
197215
start_server { |port|
198216
server_connect(port) { |ssl|

0 commit comments

Comments
 (0)