Project

General

Profile

Actions

Bug #3515

closed

FreeBSD wrongly raises ECONNRESET on close(2)

Added by naruse (Yui NARUSE) almost 14 years ago. Updated almost 13 years ago.

Status:
Closed
Target version:
ruby -v:
ruby 1.9.3dev (2010-07-02 trunk 28520) [x86_64-freebsd8.1]
Backport:
[ruby-dev:41778]

Description

=begin
FreeBSD 8 では現在以下のようなテストに失敗しています。

  1. Error:
    test_idle(IMAPTest):
    Errno::ECONNRESET: Connection reset by peer
    /home/naruse/ruby/test/net/imap/test_imap.rb:189:in `test_idle'

  2. Failure:
    test_03(TestDRbSSLCore) [/home/naruse/ruby/test/drb/drbtest.rb:138]:
    [DRb::DRbConnError] exception expected, not
    Class: Errno::ECONNRESET
    Message: <"Connection reset by peer">
    ---Backtrace---
    /home/naruse/ruby/test/drb/drbtest.rb:139:in block in test_03' /home/naruse/ruby/test/drb/drbtest.rb:138:in test_03'


  1. Failure:
    test_07_public_private_protected_missing(TestDRbSSLCore) [/home/naruse/ruby/test/drb/drbtest.rb:182]:
    Exception raised:
    <#<Errno::ECONNRESET: Connection reset by peer>>.

これらに共通するのは「Errno::ECONNRESET: Connection reset by peer」という例外が発生している点です。
この例外は socket の close(2) を呼んだ際に errno に ECONNRESET がセットされたときに発生します。
しかし、この挙動は POSIX 仕様外であり、FreeBSD 独自のものです。

http://www.freebsd.org/cgi/man.cgi?query=close&apropos=0&sektion=0&manpath=FreeBSD+8.0-RELEASE&format=html
http://www.opengroup.org/onlinepubs/9699919799/functions/close.html
http://netbsd.gw.com/cgi-bin/man-cgi?close++NetBSD-current
http://www.openbsd.org/cgi-bin/man.cgi?query=close&apropos=0&sektion=0&manpath=OpenBSD+Current&arch=i386&format=html
http://leaf.dragonflybsd.org/cgi/web-man?command=close&section=ANY
http://www.kernel.org/doc/man-pages/online/pages/man2/close.2.html
http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man2/close.2.html

これが結果的に、他の OS では例外が投げられない状況で例外が発生するという現象を生み出しています。
以下は関連する議論です。
http://old.nabble.com/close()-failing-with-ECONNRESET-td28817716.html
http://old.nabble.com/Re:-kern-146845:--libc--close(2)-returns-error-54-(connection-reset-by-peer)-wrongly-td28649525.html

で、Ruby における対策ですが、close(2) で errno に ECONNRESET がセットされた場合、
それを無視するべきだと思います。
いかがそのパッチなのですがいかがでしょうか。

diff --git a/io.c b/io.c
index 05b2d45..a1b49d2 100644
--- a/io.c
+++ b/io.c
@@ -3436,7 +3436,7 @@ fptr_finalize(rb_io_t fptr, int noraise)
/
fptr->fd may be closed even if close fails.
* POSIX doesn't specify it.
* We assumes it is closed. */

  •    if (close(fptr->fd) < 0 && NIL_P(err))
    
  •    if (close(fptr->fd) < 0 && NIL_P(err) && errno != ECONNRESET)
           err = noraise ? Qtrue : INT2NUM(errno);
    
    }
    skip_fd_close:
    =end

Related issues 1 (0 open1 closed)

Related to Ruby master - Bug #2632: Windows での未読のあるソケットのクローズ後の読み取りRejectedwanabe (_ wanabe)01/23/2010Actions
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0