Issue #10915 has been updated by Usaku NAKAMURA.


Naohisa Goto wrote:
> Solaris, Linux にて動作を確認しました。
> Windowsなどその他のOSでは未確認です。

そこはまあ、入れてみればわかるのでいいんじゃないかと。
(ちなみにこの変更自体はWindowsでもたぶん問題はありません。)

----------------------------------------
Bug #10915: Error in FTPTest#test_abort and test_status on Solaris
https://bugs.ruby-lang.org/issues/10915#change-51686

* Author: Naohisa Goto
* Status: Open
* Priority: Normal
* Assignee: 
* ruby -v: ruby 2.3.0dev (2015-02-26) [sparc64-solaris2.10]
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
Solaris 10 にて、make test-all で以下のエラーが出ます。
(r49732にて確認)

~~~
  1) Error:
FTPTest#test_abort:
Net::ReadTimeout: Net::ReadTimeout
    /XXXXXXXXXX/lib/net/protocol.rb:158:in `rescue in rbuf_fill'
    /XXXXXXXXXX/lib/net/protocol.rb:152:in `rbuf_fill'
    /XXXXXXXXXX/lib/net/protocol.rb:134:in `readuntil'
    /XXXXXXXXXX/lib/net/ftp.rb:1108:in `gets'
    /XXXXXXXXXX/lib/net/ftp.rb:1113:in `readline'
    /XXXXXXXXXX/lib/net/ftp.rb:290:in `getline'
    /XXXXXXXXXX/lib/net/ftp.rb:301:in `getmultiline'
    /XXXXXXXXXX/lib/net/ftp.rb:886:in `abort'
    /XXXXXXXXXX/test/net/ftp/test_ftp.rb:726:in `test_abort'

  2) Error:
FTPTest#test_status:
Net::ReadTimeout: Net::ReadTimeout
    /XXXXXXXXXX/lib/net/protocol.rb:158:in `rescue in rbuf_fill'
    /XXXXXXXXXX/lib/net/protocol.rb:152:in `rbuf_fill'
    /XXXXXXXXXX/lib/net/protocol.rb:134:in `readuntil'
    /XXXXXXXXXX/lib/net/ftp.rb:1108:in `gets'
    /XXXXXXXXXX/lib/net/ftp.rb:1113:in `readline'
    /XXXXXXXXXX/lib/net/ftp.rb:290:in `getline'
    /XXXXXXXXXX/lib/net/ftp.rb:301:in `getmultiline'
    /XXXXXXXXXX/lib/net/ftp.rb:319:in `getresp'
    /XXXXXXXXXX/lib/net/ftp.rb:900:in `status'
    /XXXXXXXXXX/test/net/ftp/test_ftp.rb:759:in `test_status'
~~~

net/ftp の abort と status は、以下のように MSG_OOB オプションを付けて、
帯域外データとして送信しています。

~~~
 @sock.send(line, Socket::MSG_OOB)
~~~

これを test_ftp.rb 内の sock.recv(1024) にて受けています。
Linux などでは、これで受信できているようですが、
Solaris では、ioctl() SIOCATMARK 要求をする必要があるような感じです。
しかし、この ioctl は Rubyレベルでは、少なくともポータブルには、出す方法がありません。

かわりに、OOBデータも通常データとみなして受信するソケット・オプション
SO_OOBINLINE を受信側のソケット・オプションに指定すると、
タイムアウトすることはなくなりましたが、以下のFailureが出ました。

~~~
  2) Failure:
FTPTest#test_abort [/user3/gen-info/ngoto/testruby/daily/src/sparc64-cc12-trunk-49756/test/net/ftp/test_ftp.rb:727]:
<"ABOR\r"> expected but was
<"ABOR\r\n">.

  3) Failure:
FTPTest#test_status [/user3/gen-info/ngoto/testruby/daily/src/sparc64-cc12-trunk-49756/test/net/ftp/test_ftp.rb:760]:
<"STAT\r"> expected but was
<"STAT\r\n">.
~~~

これは、受信側で BasicSocket#recv システムコールをそのまま使っているが、
バッファリングはOSや環境に依存するのが原因と思われます。
Linuxでは最後の"\n"だけ別の塊として受信しますが、Solarisでは全部を同時に受信するようです。

SO_OOBINLINE を指定したのだから、recv システムコールを直接使わなくても、gets を使えば十分と考えられます。

まとめると、以下のパッチにより、ErrorおよびFailureは出なくなりました。

~~~
Index: test/net/ftp/test_ftp.rb
===================================================================
--- test/net/ftp/test_ftp.rb    (revision 49774)
+++ test/net/ftp/test_ftp.rb    (working copy)
@@ -711,7 +711,7 @@
       sock.print("230 Login successful.\r\n")
       commands.push(sock.gets)
       sock.print("200 Switching to Binary mode.\r\n")
-      commands.push(sock.recv(1024))
+      commands.push(sock.gets)
       sock.print("225 No transfer to ABOR.\r\n")
     }
     begin
@@ -724,7 +724,7 @@
         assert_match(/\APASS /, commands.shift)
         assert_equal("TYPE I\r\n", commands.shift)
         ftp.abort
-        assert_equal("ABOR\r", commands.shift)
+        assert_equal("ABOR\r\n", commands.shift)
         assert_equal(nil, commands.shift)
       ensure
         ftp.close if ftp
@@ -744,7 +744,7 @@
       sock.print("230 Login successful.\r\n")
       commands.push(sock.gets)
       sock.print("200 Switching to Binary mode.\r\n")
-      commands.push(sock.recv(1024))
+      commands.push(sock.gets)
       sock.print("211 End of status\r\n")
     }
     begin
@@ -757,7 +757,7 @@
         assert_match(/\APASS /, commands.shift)
         assert_equal("TYPE I\r\n", commands.shift)
         ftp.status
-        assert_equal("STAT\r", commands.shift)
+        assert_equal("STAT\r\n", commands.shift)
         assert_equal(nil, commands.shift)
       ensure
         ftp.close if ftp
@@ -856,6 +856,7 @@
       end
       sock = server.accept
       begin
+        sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, 1)
         yield(sock)
         sock.shutdown(Socket::SHUT_WR)
         sock.read unless sock.eof?
~~~

Solaris, Linux にて動作を確認しました。
Windowsなどその他のOSでは未確認です。


---Files--------------------------------
20150227-test-ftp.patch (1.61 KB)


-- 
https://bugs.ruby-lang.org/