ruby-changes:11400
From: akr <ko1@a...>
Date: Sat, 21 Mar 2009 02:39:58 +0900 (JST)
Subject: [ruby-changes:11400] Ruby:r23020 (trunk): * ext/openssl/lib/openssl/buffering.rb
akr 2009-03-21 02:39:44 +0900 (Sat, 21 Mar 2009) New Revision: 23020 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=23020 Log: * 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. Modified files: trunk/ChangeLog trunk/NEWS trunk/ext/openssl/lib/openssl/buffering.rb trunk/ext/openssl/ossl_ssl.c trunk/test/openssl/test_pair.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 23019) +++ ChangeLog (revision 23020) @@ -1,3 +1,12 @@ +Sat Mar 21 02:37:07 2009 Tanaka Akira <akr@f...> + + * 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@r...> * win32/win32.c (errmap): added ERROR_MOD_NOT_FOUND. Index: ext/openssl/ossl_ssl.c =================================================================== --- ext/openssl/ossl_ssl.c (revision 23019) +++ ext/openssl/ossl_ssl.c (revision 23020) @@ -1180,13 +1180,8 @@ return ossl_ssl_read_internal(argc, argv, self, 1); } - -/* - * call-seq: - * ssl.syswrite(string) => integer - */ static VALUE -ossl_ssl_write(VALUE self, VALUE str) +ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock) { SSL *ssl; int nwrite = 0; @@ -1203,9 +1198,19 @@ case SSL_ERROR_NONE: goto end; 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)); continue; 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)); continue; case SSL_ERROR_SYSCALL: @@ -1227,6 +1232,26 @@ /* * 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: * ssl.sysclose => nil */ static VALUE @@ -1545,6 +1570,7 @@ rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1); rb_define_private_method(cSSLSocket, "sysread_nonblock", ossl_ssl_read_nonblock, -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, "cert", ossl_ssl_get_cert, 0); rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0); Index: ext/openssl/lib/openssl/buffering.rb =================================================================== --- ext/openssl/lib/openssl/buffering.rb (revision 23019) +++ ext/openssl/lib/openssl/buffering.rb (revision 23020) @@ -116,6 +116,7 @@ # # So OpenSSL::Buffering#read_nonblock needs two rescue clause as follows. # + # # emulates blocking read (readpartial). # begin # result = ssl.read_nonblock(maxlen) # rescue IO::WaitReadable @@ -249,6 +250,48 @@ s.length 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) do_write(s) self Index: NEWS =================================================================== --- NEWS (revision 23019) +++ NEWS (revision 23020) @@ -92,7 +92,8 @@ * openssl * new method: - * Buffering#read_nonblock + * OpenSSL::Buffering#read_nonblock + * OpenSSL::Buffering#write_nonblock * socket Index: test/openssl/test_pair.rb =================================================================== --- test/openssl/test_pair.rb (revision 23019) +++ test/openssl/test_pair.rb (revision 23020) @@ -165,6 +165,33 @@ } 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/