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

ruby-changes:8958

From: matz <ko1@a...>
Date: Thu, 4 Dec 2008 16:26:43 +0900 (JST)
Subject: [ruby-changes:8958] Ruby:r20494 (ruby_1_8): * ext/openssl/ossl_ssl.c (ossl_ssl_read_nonblock):

matz	2008-12-04 16:26:28 +0900 (Thu, 04 Dec 2008)

  New Revision: 20494

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=20494

  Log:
    * ext/openssl/ossl_ssl.c (ossl_ssl_read_nonblock):
      OpenSSL::SSL::SSLSocket should implement read_nonblock.  a patch
      from Aaron Patterson in [ruby-core:20277].  fix: #814 [ruby-core:20241]
    * ext/tk/lib/tk/menu.rb: TkOptionMenubutton.new fails to treat

  Modified files:
    branches/ruby_1_8/ChangeLog
    branches/ruby_1_8/ext/openssl/ossl_ssl.c
    branches/ruby_1_8/test/openssl/test_ssl.rb

Index: ruby_1_8/ext/openssl/ossl_ssl.c
===================================================================
--- ruby_1_8/ext/openssl/ossl_ssl.c	(revision 20493)
+++ ruby_1_8/ext/openssl/ossl_ssl.c	(revision 20494)
@@ -14,6 +14,12 @@
 #include <rubysig.h>
 #include <rubyio.h>
 
+#if defined(HAVE_FCNTL_H) || defined(_WIN32)
+#include <fcntl.h>
+#elif defined(HAVE_SYS_FCNTL_H)
+#include <sys/fcntl.h>
+#endif
+
 #if defined(HAVE_UNISTD_H)
 #  include <unistd.h> /* for read(), and write() */
 #endif
@@ -1005,6 +1011,71 @@
 static VALUE
 ossl_ssl_read(int argc, VALUE *argv, VALUE self)
 {
+  SSL *ssl;
+  int ilen, nread = 0;
+  VALUE len, str;
+  rb_io_t *fptr;
+
+  rb_scan_args(argc, argv, "11", &len, &str);
+  ilen = NUM2INT(len);
+  if(NIL_P(str)) str = rb_str_new(0, ilen);
+  else{
+    StringValue(str);
+    rb_str_modify(str);
+    rb_str_resize(str, ilen);
+  }
+  if(ilen == 0) return str;
+
+  Data_Get_Struct(self, SSL, ssl);
+  GetOpenFile(ossl_ssl_get_io(self), fptr);
+  if (ssl) {
+    if(SSL_pending(ssl) <= 0)
+      rb_thread_wait_fd(FPTR_TO_FD(fptr));
+    for (;;){
+      nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
+      switch(ssl_get_error(ssl, nread)){
+        case SSL_ERROR_NONE:
+          goto end;
+        case SSL_ERROR_ZERO_RETURN:
+          rb_eof_error();
+        case SSL_ERROR_WANT_WRITE:
+          rb_io_wait_writable(FPTR_TO_FD(fptr));
+          continue;
+        case SSL_ERROR_WANT_READ:
+          rb_io_wait_readable(FPTR_TO_FD(fptr));
+          continue;
+        case SSL_ERROR_SYSCALL:
+          if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
+          rb_sys_fail(0);
+        default:
+          ossl_raise(eSSLError, "SSL_read:");
+      }
+    }
+  }
+  else {
+    rb_warning("SSL session is not started yet.");
+    return rb_funcall(ossl_ssl_get_io(self), rb_intern("read_nonblock"), 2, len, str);
+  }
+
+end:
+  rb_str_set_len(str, nread);
+  OBJ_TAINT(str);
+
+  return str;
+}
+
+/*
+ * call-seq:
+ *    ssl.read_nonblock(length) => string
+ *    ssl.read_nonblock(length, buffer) => buffer
+ *
+ * === Parameters
+ * * +length+ is a positive integer.
+ * * +buffer+ is a string used to store the result.
+ */
+static VALUE
+ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self)
+{
     SSL *ssl;
     int ilen, nread = 0;
     VALUE len, str;
@@ -1022,12 +1093,11 @@
 
     Data_Get_Struct(self, SSL, ssl);
     GetOpenFile(ossl_ssl_get_io(self), fptr);
+    rb_io_set_nonblock(fptr);
     if (ssl) {
-	if(SSL_pending(ssl) <= 0)
-	    rb_thread_wait_fd(FPTR_TO_FD(fptr));
 	for (;;){
 	    nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
-	    switch(ssl_get_error(ssl, nread)){
+	    switch(SSL_get_error(ssl, nread)){
 	    case SSL_ERROR_NONE:
 		goto end;
 	    case SSL_ERROR_ZERO_RETURN:
@@ -1036,7 +1106,7 @@
                 rb_io_wait_writable(FPTR_TO_FD(fptr));
                 continue;
 	    case SSL_ERROR_WANT_READ:
-                rb_io_wait_readable(FPTR_TO_FD(fptr));
+	        rb_sys_fail(fptr->path);
 		continue;
 	    case SSL_ERROR_SYSCALL:
 		if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
@@ -1047,9 +1117,8 @@
         }
     }
     else {
-        ID id_sysread = rb_intern("sysread");
         rb_warning("SSL session is not started yet.");
-        return rb_funcall(ossl_ssl_get_io(self), id_sysread, 2, len, str);
+        return rb_funcall(ossl_ssl_get_io(self), rb_intern("sysread"), 2, len, str);
     }
 
   end:
@@ -1423,6 +1492,7 @@
     rb_define_method(cSSLSocket, "sysread",    ossl_ssl_read, -1);
     rb_define_method(cSSLSocket, "syswrite",   ossl_ssl_write, 1);
     rb_define_method(cSSLSocket, "sysclose",   ossl_ssl_close, 0);
+    rb_define_method(cSSLSocket, "read_nonblock",    ossl_ssl_read_nonblock, -1);
     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_chain", ossl_ssl_get_peer_cert_chain, 0);
Index: ruby_1_8/ChangeLog
===================================================================
--- ruby_1_8/ChangeLog	(revision 20493)
+++ ruby_1_8/ChangeLog	(revision 20494)
@@ -1,6 +1,12 @@
+Thu Dec  4 16:19:18 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* ext/openssl/ossl_ssl.c (ossl_ssl_read_nonblock):
+	  OpenSSL::SSL::SSLSocket should implement read_nonblock.  a patch
+	  from Aaron Patterson in [ruby-core:20277].  fix: #814 [ruby-core:20241]
+
 Thu Dec  4 06:04:16 2008  Hidetoshi NAGAI  <nagai@a...>
 
-	* ext/tk/lib/tk/menu.rb: TkOptionMenubutton.new fails to treat 
+	* ext/tk/lib/tk/menu.rb: TkOptionMenubutton.new fails to treat
 	  'parent' and 'variable' options on a Hash argument.
 
 Wed Dec  3 16:38:11 2008  Akinori MUSHA  <knu@i...>
Index: ruby_1_8/test/openssl/test_ssl.rb
===================================================================
--- ruby_1_8/test/openssl/test_ssl.rb	(revision 20493)
+++ ruby_1_8/test/openssl/test_ssl.rb	(revision 20494)
@@ -155,6 +155,21 @@
     assert_equal(ctx.setup, nil)
   end
 
+  def test_ssl_read_nonblock
+    start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) { |server, port|
+      sock = TCPSocket.new("127.0.0.1", port)
+      ssl = OpenSSL::SSL::SSLSocket.new(sock)
+      ssl.sync_close = true
+      ssl.connect
+      assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { ssl.read_nonblock(100) }
+      ssl.write("abc\n")
+      IO.select [ssl]
+      assert_equal('a', ssl.read_nonblock(1))
+      assert_equal("bc\n", ssl.read_nonblock(100))
+      assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { ssl.read_nonblock(100) }
+    }
+  end
+
   def test_connect_and_close
     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
       sock = TCPSocket.new("127.0.0.1", port)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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