[#25808] break & retry in block — Shin-ichiro HARA <sinara@...>

原です。

15 messages 2005/03/04

[#25812] Re: [ruby-cvs] ruby/test/ruby, ruby/test/logger, ruby/sample, ruby/misc, ruby/lib/xmlrpc, ruby/lib/wsdl/soap, ruby/lib/rexml, ruby/lib/rdoc/parsers, ruby/lib/rdoc/generators, ruby/lib/irb, ruby/lib, ruby/ext/zlib, ruby/ext/win32ole, ruby/ext/tk, ruby/ext/strscan, ruby/ext/socket, ruby/ext/readline, ruby/ext/pty, ruby/ext/openssl, ruby/ext/iconv, ruby/ext/etc, ruby/ext/dl, ruby/ext/curses, ruby/ext/bigdecimal, ruby/ext/Win32API, ruby: * array.c: replace rb_protect_inspect() and rb_inspecting_p() by — Tanaka Akira <akr@...17n.org>

In article <20050304064753.53859C671F@lithium.ruby-lang.org>,

3 messages 2005/03/06

[#25853] conflict method and local variable — Hidetoshi NAGAI <nagai@...>

永井@知能.九工大です.

56 messages 2005/03/10
[#25854] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/10

まつもと ゆきひろです

[#25855] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/10

永井@知能.九工大です.

[#25856] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/10

まつもと ゆきひろです

[#25857] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/11

永井@知能.九工大です.

[#25858] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/11

まつもと ゆきひろです

[#25861] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/11

永井@知能.九工大です.

[#25863] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/11

まつもと ゆきひろです

[#25864] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/11

永井@知能.九工大です.

[#25865] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/11

まつもと ゆきひろです

[#25866] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/11

永井@知能.九工大です.

[#25869] Re: conflict method and local variable — Shugo Maeda <shugo@...> 2005/03/13

前田です。

[#25875] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/13

まつもと ゆきひろです

[#25878] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/13

永井@知能.九工大です.

[#25882] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/13

まつもと ゆきひろです

[#25884] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/14

永井@知能.九工大です.

[#25885] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/14

まつもと ゆきひろです

[#25888] Re: conflict method and local variable — Shugo Maeda <shugo@...> 2005/03/14

前田です。

[#25946] ext/tk/sample/**/*.gif are broken — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp>

山本です。

16 messages 2005/03/27

[#25959] some trouble on ext/tk/sample — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp>

山本です。

20 messages 2005/03/29
[#25969] Re: some trouble on ext/tk/sample — Hidetoshi NAGAI <nagai@...> 2005/03/30

永井@知能.九工大です.

[#25970] Re: some trouble on ext/tk/sample — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp> 2005/03/30

山本です。

[#25973] Re: some trouble on ext/tk/sample — Hidetoshi NAGAI <nagai@...> 2005/03/31

永井@知能.九工大です.

[ruby-dev:25794] OpenSSL::SSL::SSLSocket and IO

From: Tanaka Akira <akr@...17n.org>
Date: 2005-03-02 13:24:21 UTC
List: ruby-dev #25794
OpenSSL::SSL::SSLSocket と IO との一貫性を調べようと思ってちょっと調べ
たところ、いろいろ気がつきました。

* SSL_ERROR_WANT_WRITE:, SSL_ERROR_WANT_READ になったときに busy loop
  になることがあります

  少なくとも、ossl_ssl_read, ossl_ssl_write では次のようにすると busy
  loop になります。
  ossl_start_ssl のは確認していません。

  % cat sslpair.rb 
  require 'openssl'
  require 'socket'

  module SSLPair
    def server
      host = "127.0.0.1"
      port = 0
      key = OpenSSL::PKey::RSA.new(512)
      cert = OpenSSL::X509::Certificate.new
      cert.version = 2
      cert.serial = 0
      name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
      cert.subject = name
      cert.issuer = name
      cert.not_before = Time.now
      cert.not_after = Time.now + 3600
      cert.public_key = key.public_key
      ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
      cert.extensions = [
        ef.create_extension("basicConstraints","CA:FALSE"),
        ef.create_extension("subjectKeyIdentifier","hash"),
        ef.create_extension("extendedKeyUsage","serverAuth"),
        ef.create_extension("keyUsage",
                            "keyEncipherment,dataEncipherment,digitalSignature")
      ]
      ef.issuer_certificate = cert
      cert.add_extension ef.create_extension("authorityKeyIdentifier",
                                             "keyid:always,issuer:always")
      cert.sign(key, OpenSSL::Digest::SHA1.new)
      ctx = OpenSSL::SSL::SSLContext.new()
      ctx.key = key
      ctx.cert = cert
      tcps = TCPServer.new(host, port)
      ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
      return ssls
    end

    def client(port)
      host = "127.0.0.1"
      ctx = OpenSSL::SSL::SSLContext.new()
      s = TCPSocket.new(host, port)
      ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
      ssl.connect
      ssl.sync_close = true
      ssl
    end

    def ssl_pair
      ssls = server
      th = Thread.new {
        ns = ssls.accept
        ssls.close
        ns
      }
      port = ssls.to_io.addr[1]
      c = client(port)
      s = th.value
      return c, s
    end
  end

  include SSLPair
  % strace ./ruby -I. -r sslpair.rb -e 'p $$; s1, s2 = ssl_pair; s1.sysread(10)'
  ...
  read(7, 0x81f9b60, 5)                   = -1 EAGAIN (Resource temporarily unavailable)
  getpid()                                = 2508
  read(7, 0x81f9b60, 5)                   = -1 EAGAIN (Resource temporarily unavailable)
  getpid()                                = 2508
  read(7, 0x81f9b60, 5)                   = -1 EAGAIN (Resource temporarily unavailable)
  getpid()                                = 2508
  ...

  % strace ./ruby -Iext/openssl/lib -I.ext -I.ext/i686-linux -I. -r sslpair.rb -e 'p $$; s1, s2 = ssl_pair; s1.write "a" * 200000'
  ...
  write(7, "\f\342\274\4Z\230\206]>h\344\212{\342r\227P\2111\376\0"..., 370) = -1 EAGAIN (Resource temporarily unavailable)
  getpid()                                = 6050
  write(7, "\f\342\274\4Z\230\206]>h\344\212{\342r\227P\2111\376\0"..., 370) = -1 EAGAIN (Resource temporarily unavailable)
  getpid()                                = 6050
  write(7, "\f\342\274\4Z\230\206]>h\344\212{\342r\227P\2111\376\0"..., 370) = -1 EAGAIN (Resource temporarily unavailable)
  getpid()                                = 6050
  write(7, "\f\342\274\4Z\230\206]>h\344\212{\342r\227P\2111\376\0"..., 370) = -1 EAGAIN (Resource temporarily unavailable)
  ...

* fill_rbuff で、Errno::EAGAIN は Ruby レベルには出ないようなので、
  rescue するのは不要ではないでしょうか

* consume_rbuff で、@eof を nil に設定し直すのは変だと思うのですが、いっ
  たん EOF になってからさらに通信が行われることがあるのでしょうか?

* read で、(今では) read(0) は "" を返さないと、IO と一貫しません

* readline, readchar で、EOFErorr という typo があります

* getc で to_i ではバイトの値を得られません

* eof? で、バッファが空のときは実際に読んで確認する必要があります

* puts で、出力レコードセパレータとして $/ を使っています

* readpartial を実装してみました

Index: ext/openssl/ossl_ssl.c
===================================================================
RCS file: /src/ruby/ext/openssl/ossl_ssl.c,v
retrieving revision 1.19
diff -u -p -r1.19 ossl_ssl.c
--- ext/openssl/ossl_ssl.c	15 Feb 2005 17:50:46 -0000	1.19
+++ ext/openssl/ossl_ssl.c	2 Mar 2005 12:44:03 -0000
@@ -434,7 +434,7 @@ ossl_ssl_setup(VALUE self)
 }
 
 static void
-ossl_start_ssl(SSL *ssl, int (*func)())
+ossl_start_ssl(SSL *ssl, int fd, int (*func)())
 {
     int ret;
 
@@ -442,9 +442,11 @@ ossl_start_ssl(SSL *ssl, int (*func)())
 	if((ret = func(ssl)) > 0) break;
 	switch(SSL_get_error(ssl, ret)){
 	case SSL_ERROR_WANT_WRITE:
+            rb_io_wait_writable(fd);
+            continue;
 	case SSL_ERROR_WANT_READ:
-	    rb_thread_schedule();
-	    continue;
+            rb_io_wait_readable(fd);
+            continue;
 	default:
 	    ossl_raise(eSSLError, NULL);
 	}
@@ -456,12 +458,14 @@ ossl_ssl_connect(VALUE self)
 {
     SSL *ssl;
     VALUE cb;
+    OpenFile *fptr;
 
     ossl_ssl_setup(self);
     Data_Get_Struct(self, SSL, ssl);
+    GetOpenFile(ossl_ssl_get_io(self), fptr);
     cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self));
     SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb);
-    ossl_start_ssl(ssl, SSL_connect);
+    ossl_start_ssl(ssl, fptr->fd, SSL_connect);
 
     return self;
 }
@@ -471,12 +475,14 @@ ossl_ssl_accept(VALUE self)
 {
     SSL *ssl;
     VALUE cb;
+    OpenFile *fptr;
 
     ossl_ssl_setup(self);
     Data_Get_Struct(self, SSL, ssl);
+    GetOpenFile(ossl_ssl_get_io(self), fptr);
     cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self));
     SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb);
-    ossl_start_ssl(ssl, SSL_accept);
+    ossl_start_ssl(ssl, fptr->fd, SSL_accept);
 
     return self;
 }
@@ -512,8 +518,10 @@ ossl_ssl_read(int argc, VALUE *argv, VAL
 	    case SSL_ERROR_ZERO_RETURN:
 		rb_eof_error();
 	    case SSL_ERROR_WANT_WRITE:
+                rb_io_wait_writable(fptr->fd);
+                continue;
 	    case SSL_ERROR_WANT_READ:
-		rb_thread_schedule();
+                rb_io_wait_readable(fptr->fd);
 		continue;
 	    case SSL_ERROR_SYSCALL:
 		if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
@@ -542,9 +550,11 @@ ossl_ssl_write(VALUE self, VALUE str)
 {
     SSL *ssl;
     int nwrite = 0;
+    OpenFile *fptr;
 
     StringValue(str);
     Data_Get_Struct(self, SSL, ssl);
+    GetOpenFile(ossl_ssl_get_io(self), fptr);
 
     if (ssl) {
 	for (;;){
@@ -553,9 +563,11 @@ ossl_ssl_write(VALUE self, VALUE str)
 	    case SSL_ERROR_NONE:
 		goto end;
 	    case SSL_ERROR_WANT_WRITE:
+                rb_io_wait_writable(fptr->fd);
+                continue;
 	    case SSL_ERROR_WANT_READ:
-		rb_thread_schedule();
-		continue;
+                rb_io_wait_readable(fptr->fd);
+                continue;
 	    case SSL_ERROR_SYSCALL:
 		rb_eof_error();
 	    default:
Index: ext/openssl/lib/openssl/buffering.rb
===================================================================
RCS file: /src/ruby/ext/openssl/lib/openssl/buffering.rb,v
retrieving revision 1.8
diff -u -p -r1.8 buffering.rb
--- ext/openssl/lib/openssl/buffering.rb	15 Feb 2005 17:50:47 -0000	1.8
+++ ext/openssl/lib/openssl/buffering.rb	2 Mar 2005 12:44:04 -0000
@@ -32,8 +32,6 @@ module Buffering
     @rbuffer = "" unless defined? @rbuffer
     begin
       @rbuffer << self.sysread(BLOCK_SIZE)
-    rescue Errno::EAGAIN
-      retry
     rescue EOFError
       @eof = true
     end
@@ -41,7 +39,6 @@ module Buffering
 
   def consume_rbuff(size=nil)
     if @rbuffer.size == 0
-      @eof = nil
       nil
     else
       size = @rbuffer.size unless size
@@ -54,6 +51,14 @@ module Buffering
   public
 
   def read(size=nil, buf=nil)
+    if size == 0
+      if buf
+        buf.clear
+        return buf
+      else
+        return ""
+      end
+    end
     fill_rbuff unless defined? @rbuffer
     @eof ||= nil
     until @eof
@@ -68,6 +73,27 @@ module Buffering
     (size && ret.empty?) ? nil : ret
   end
 
+  def readpartial(maxlen, buf=nil)
+    if maxlen == 0
+      if buf
+        buf.clear
+        return buf
+      else
+        return ""
+      end
+    end
+    if !defined?(@rbuffer) || @rbuffer.size == 0
+      return sysread(maxlen, buf)
+    end
+    ret = consume_rbuff(maxlen)
+    if buf
+      buf.replace(ret)
+      ret = buf
+    end
+    raise EOFError if ret.empty?
+    ret
+  end
+
   def gets(eol=$/)
     fill_rbuff unless defined? @rbuffer
     idx = @rbuffer.index(eol)
@@ -101,13 +127,13 @@ module Buffering
   end
 
   def readline(eol=$/)
-    raise EOFErorr if eof?
+    raise EOFError if eof?
     gets(eol)
   end
 
   def getc
     c = read(1)
-    c ? c.to_i : nil
+    c ? c[0] : nil
   end
 
   def each_byte
@@ -117,7 +143,7 @@ module Buffering
   end
 
   def readchar
-    raise EOFErorr if eof?
+    raise EOFError if eof?
     getc
   end
 
@@ -127,6 +153,7 @@ module Buffering
 
   def eof?
     @eof ||= nil
+    fill_rbuff if !@eof && (!defined?(@rbuffer) || @rbuffer.size == 0)
     @eof && @rbuffer.size == 0
   end
   alias eof eof?
@@ -168,8 +195,8 @@ module Buffering
     s = ""
     args.each{|arg|
       s << arg.to_s
-      unless /#{$/}\z/o =~ s
-        s << $/
+      unless /#{Regexp.quote $\}\z/o =~ s
+        s << $\
       end
     }
     do_write(s)
Index: test/openssl/test_pair.rb
===================================================================
RCS file: test/openssl/test_pair.rb
diff -N test/openssl/test_pair.rb
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ test/openssl/test_pair.rb	2 Mar 2005 12:44:12 -0000
@@ -0,0 +1,157 @@
+begin
+  require "openssl"
+rescue LoadError
+end
+require 'test/unit'
+
+if defined?(OpenSSL)
+
+require 'socket'
+dir = File.expand_path(__FILE__)
+2.times {dir = File.dirname(dir)}
+$:.replace([File.join(dir, "ruby")] | $:)
+require 'ut_eof'
+
+module SSLPair
+  def server
+    host = "127.0.0.1"
+    port = 0
+    key = OpenSSL::PKey::RSA.new(512)
+    cert = OpenSSL::X509::Certificate.new
+    cert.version = 2
+    cert.serial = 0
+    name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
+    cert.subject = name
+    cert.issuer = name
+    cert.not_before = Time.now
+    cert.not_after = Time.now + 3600
+    cert.public_key = key.public_key
+    ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
+    cert.extensions = [
+      ef.create_extension("basicConstraints","CA:FALSE"),
+      ef.create_extension("subjectKeyIdentifier","hash"),
+      ef.create_extension("extendedKeyUsage","serverAuth"),
+      ef.create_extension("keyUsage",
+                          "keyEncipherment,dataEncipherment,digitalSignature")
+    ]
+    ef.issuer_certificate = cert
+    cert.add_extension ef.create_extension("authorityKeyIdentifier",
+                                           "keyid:always,issuer:always")
+    cert.sign(key, OpenSSL::Digest::SHA1.new)
+    ctx = OpenSSL::SSL::SSLContext.new()
+    ctx.key = key
+    ctx.cert = cert
+    tcps = TCPServer.new(host, port)
+    ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
+    return ssls
+  end
+
+  def client(port)
+    host = "127.0.0.1"
+    ctx = OpenSSL::SSL::SSLContext.new()
+    s = TCPSocket.new(host, port)
+    ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
+    ssl.connect
+    ssl.sync_close = true
+    ssl
+  end
+
+  def ssl_pair
+    ssls = server
+    th = Thread.new {
+      ns = ssls.accept
+      ssls.close
+      ns
+    }
+    port = ssls.to_io.addr[1]
+    c = client(port)
+    s = th.value
+    if block_given?
+      begin
+        yield c, s
+      ensure
+        c.close unless c.closed?
+        s.close unless s.closed?
+      end
+    else
+      return c, s
+    end
+  end
+end
+
+class OpenSSL::TestEOF1 < Test::Unit::TestCase
+  include TestEOF
+  include SSLPair
+
+  def open_file(content)
+    s1, s2 = ssl_pair
+    Thread.new { s2 << content; s2.close }
+    yield s1
+  end
+end
+
+class OpenSSL::TestEOF2 < Test::Unit::TestCase
+  include TestEOF
+  include SSLPair
+
+  def open_file(content)
+    s1, s2 = ssl_pair
+    Thread.new { s1 << content; s1.close }
+    yield s2
+  end
+end
+
+class OpenSSL::TestPair < Test::Unit::TestCase
+  include SSLPair
+
+  def test_getc
+    ssl_pair {|s1, s2|
+      s1 << "a"
+      assert_equal(?a, s2.getc)
+    }
+  end
+
+  def test_readpartial
+    ssl_pair {|s1, s2|
+      s2.write "a\nbcd"
+      assert_equal("a\n", s1.gets)
+      assert_equal("bcd", s1.readpartial(10))
+      s2.write "efg"
+      assert_equal("efg", s1.readpartial(10))
+      s2.close
+      assert_raise(EOFError) { s1.readpartial(10) }
+      assert_raise(EOFError) { s1.readpartial(10) }
+      assert_equal("", s1.readpartial(0))
+    }
+  end
+
+  def test_readall
+    ssl_pair {|s1, s2|
+      s2.close
+      assert_equal("", s1.read)
+    }
+  end
+
+  def test_readline
+    ssl_pair {|s1, s2|
+      s2.close
+      assert_raise(EOFError) { s1.readline }
+    }
+  end
+
+  def test_puts_meta
+    ssl_pair {|s1, s2|
+      begin
+        $\ = '*'
+        s1.puts 'a'
+        s1.close
+        assert_equal("a*", s2.read)
+      ensure
+        $\ = "\n"
+      end
+    }
+  end
+
+end
+
+end
Index: test/ruby/ut_eof.rb
===================================================================
RCS file: /src/ruby/test/ruby/ut_eof.rb,v
retrieving revision 1.8
diff -u -p -r1.8 ut_eof.rb
--- test/ruby/ut_eof.rb	6 Dec 2004 08:40:30 -0000	1.8
+++ test/ruby/ut_eof.rb	2 Mar 2005 12:44:13 -0000
@@ -83,6 +83,19 @@ module TestEOF
     }
   end
 
+  def test_eof_2
+    open_file("") {|f|
+      assert_equal("", f.read)
+      assert(f.eof?)
+    }
+  end
+
+  def test_eof_3
+    open_file("") {|f|
+      assert(f.eof?)
+    }
+  end
+
   module Seek
     def open_file_seek(content, pos)
       open_file(content) do |f|

どんなもんでしょう?
-- 
[田中 哲][たなか あきら][Tanaka Akira]

In This Thread

Prev Next