Issue #10915 has been reported by Naohisa Goto. ---------------------------------------- Bug #10915: Error in FTPTest#test_abort and test_status on Solaris https://bugs.ruby-lang.org/issues/10915 * 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/