* ext/openssl/lib/openssl/buffering.rb
(OpenSSL::Buffering#write_nonblock): new method. * ext/openssl/ossl_ssl.c (ossl_ssl_write_nonblock): new method. (ossl_ssl_write_internal): defined. (ossl_ssl_write): use ossl_ssl_write_internal. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23020 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
88db4af385
commit
17a085ea8c
@ -1,3 +1,12 @@
|
|||||||
|
Sat Mar 21 02:37:07 2009 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* ext/openssl/lib/openssl/buffering.rb
|
||||||
|
(OpenSSL::Buffering#write_nonblock): new method.
|
||||||
|
|
||||||
|
* ext/openssl/ossl_ssl.c (ossl_ssl_write_nonblock): new method.
|
||||||
|
(ossl_ssl_write_internal): defined.
|
||||||
|
(ossl_ssl_write): use ossl_ssl_write_internal.
|
||||||
|
|
||||||
Fri Mar 20 18:25:25 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Fri Mar 20 18:25:25 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* win32/win32.c (errmap): added ERROR_MOD_NOT_FOUND.
|
* win32/win32.c (errmap): added ERROR_MOD_NOT_FOUND.
|
||||||
|
3
NEWS
3
NEWS
@ -92,7 +92,8 @@ with all sufficient information, see the ChangeLog file.
|
|||||||
|
|
||||||
* openssl
|
* openssl
|
||||||
* new method:
|
* new method:
|
||||||
* Buffering#read_nonblock
|
* OpenSSL::Buffering#read_nonblock
|
||||||
|
* OpenSSL::Buffering#write_nonblock
|
||||||
|
|
||||||
* socket
|
* socket
|
||||||
|
|
||||||
|
@ -116,6 +116,7 @@ module Buffering
|
|||||||
#
|
#
|
||||||
# So OpenSSL::Buffering#read_nonblock needs two rescue clause as follows.
|
# So OpenSSL::Buffering#read_nonblock needs two rescue clause as follows.
|
||||||
#
|
#
|
||||||
|
# # emulates blocking read (readpartial).
|
||||||
# begin
|
# begin
|
||||||
# result = ssl.read_nonblock(maxlen)
|
# result = ssl.read_nonblock(maxlen)
|
||||||
# rescue IO::WaitReadable
|
# rescue IO::WaitReadable
|
||||||
@ -249,6 +250,48 @@ module Buffering
|
|||||||
s.length
|
s.length
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Writes _str_ in the non-blocking manner.
|
||||||
|
#
|
||||||
|
# If there are buffered data, it is flushed at first.
|
||||||
|
# This may block.
|
||||||
|
#
|
||||||
|
# write_nonblock returns number of bytes written to the SSL connection.
|
||||||
|
#
|
||||||
|
# When no data can be written without blocking,
|
||||||
|
# It raises OpenSSL::SSL::SSLError extended by
|
||||||
|
# IO::WaitReadable or IO::WaitWritable.
|
||||||
|
#
|
||||||
|
# IO::WaitReadable means SSL needs to read internally.
|
||||||
|
# So write_nonblock should be called again after
|
||||||
|
# underlying IO is readable.
|
||||||
|
#
|
||||||
|
# IO::WaitWritable means SSL needs to write internally.
|
||||||
|
# So write_nonblock should be called again after
|
||||||
|
# underlying IO is writable.
|
||||||
|
#
|
||||||
|
# So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows.
|
||||||
|
#
|
||||||
|
# # emulates blocking write.
|
||||||
|
# begin
|
||||||
|
# result = ssl.write_nonblock(str)
|
||||||
|
# rescue IO::WaitReadable
|
||||||
|
# IO.select([io])
|
||||||
|
# retry
|
||||||
|
# rescue IO::WaitWritable
|
||||||
|
# IO.select(nil, [io])
|
||||||
|
# retry
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Note that one reason that write_nonblock read from a underlying IO
|
||||||
|
# is the peer requests a new TLS/SSL handshake.
|
||||||
|
# See openssl FAQ for more details.
|
||||||
|
# http://www.openssl.org/support/faq.html
|
||||||
|
#
|
||||||
|
def write_nonblock(s)
|
||||||
|
flush
|
||||||
|
syswrite_nonblock(s)
|
||||||
|
end
|
||||||
|
|
||||||
def << (s)
|
def << (s)
|
||||||
do_write(s)
|
do_write(s)
|
||||||
self
|
self
|
||||||
|
@ -1180,13 +1180,8 @@ ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self)
|
|||||||
return ossl_ssl_read_internal(argc, argv, self, 1);
|
return ossl_ssl_read_internal(argc, argv, self, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* ssl.syswrite(string) => integer
|
|
||||||
*/
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ossl_ssl_write(VALUE self, VALUE str)
|
ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock)
|
||||||
{
|
{
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
int nwrite = 0;
|
int nwrite = 0;
|
||||||
@ -1203,9 +1198,19 @@ ossl_ssl_write(VALUE self, VALUE str)
|
|||||||
case SSL_ERROR_NONE:
|
case SSL_ERROR_NONE:
|
||||||
goto end;
|
goto end;
|
||||||
case SSL_ERROR_WANT_WRITE:
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
if (nonblock) {
|
||||||
|
VALUE exc = ossl_exc_new(eSSLError, "write would block");
|
||||||
|
rb_extend_object(exc, rb_mWaitWritable);
|
||||||
|
rb_exc_raise(exc);
|
||||||
|
}
|
||||||
rb_io_wait_writable(FPTR_TO_FD(fptr));
|
rb_io_wait_writable(FPTR_TO_FD(fptr));
|
||||||
continue;
|
continue;
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
|
if (nonblock) {
|
||||||
|
VALUE exc = ossl_exc_new(eSSLError, "read would block");
|
||||||
|
rb_extend_object(exc, rb_mWaitReadable);
|
||||||
|
rb_exc_raise(exc);
|
||||||
|
}
|
||||||
rb_io_wait_readable(FPTR_TO_FD(fptr));
|
rb_io_wait_readable(FPTR_TO_FD(fptr));
|
||||||
continue;
|
continue;
|
||||||
case SSL_ERROR_SYSCALL:
|
case SSL_ERROR_SYSCALL:
|
||||||
@ -1225,6 +1230,26 @@ ossl_ssl_write(VALUE self, VALUE str)
|
|||||||
return INT2NUM(nwrite);
|
return INT2NUM(nwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* ssl.syswrite(string) => integer
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
ossl_ssl_write(VALUE self, VALUE str)
|
||||||
|
{
|
||||||
|
return ossl_ssl_write_internal(self, str, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* ssl.syswrite_nonblock(string) => integer
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
ossl_ssl_write_nonblock(VALUE self, VALUE str)
|
||||||
|
{
|
||||||
|
return ossl_ssl_write_internal(self, str, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* ssl.sysclose => nil
|
* ssl.sysclose => nil
|
||||||
@ -1545,6 +1570,7 @@ Init_ossl_ssl()
|
|||||||
rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1);
|
rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1);
|
||||||
rb_define_private_method(cSSLSocket, "sysread_nonblock", ossl_ssl_read_nonblock, -1);
|
rb_define_private_method(cSSLSocket, "sysread_nonblock", ossl_ssl_read_nonblock, -1);
|
||||||
rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1);
|
rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1);
|
||||||
|
rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, 1);
|
||||||
rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0);
|
rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0);
|
||||||
rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0);
|
rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0);
|
||||||
rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0);
|
rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0);
|
||||||
|
@ -165,6 +165,33 @@ class OpenSSL::TestPair < Test::Unit::TestCase
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_write_nonblock
|
||||||
|
ssl_pair {|s1, s2|
|
||||||
|
n = 0
|
||||||
|
begin
|
||||||
|
n += s1.write_nonblock("a" * 100000)
|
||||||
|
n += s1.write_nonblock("b" * 100000)
|
||||||
|
n += s1.write_nonblock("c" * 100000)
|
||||||
|
n += s1.write_nonblock("d" * 100000)
|
||||||
|
n += s1.write_nonblock("e" * 100000)
|
||||||
|
n += s1.write_nonblock("f" * 100000)
|
||||||
|
rescue IO::WaitWritable
|
||||||
|
end
|
||||||
|
s1.close
|
||||||
|
assert_equal(n, s2.read.length)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_write_nonblock_with_buffered_data
|
||||||
|
ssl_pair {|s1, s2|
|
||||||
|
s1.write "foo"
|
||||||
|
s1.write_nonblock("bar")
|
||||||
|
s1.write "baz"
|
||||||
|
s1.close
|
||||||
|
assert_equal("foobarbaz", s2.read)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user