[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]