"S. Robert James" <srobertjames / gmail.com> writes:

> (Here is a stack trace:
> #<EOFError: end of file reached>
> "/ruby/lib/ruby/1.8/net/ftp.rb:211:in `readline'"
>  "/ruby/lib/ruby/1.8/net/ftp.rb:211:in `getline'"
>  "/ruby/lib/ruby/1.8/net/ftp.rb:221:in `getmultiline'"
>  "/ruby/lib/ruby/1.8/net/ftp.rb:235:in `getresp'"
>  "/ruby/lib/ruby/1.8/net/ftp.rb:251:in `voidresp'"
>  "/ruby/lib/ruby/1.8/net/ftp.rb:176:in `connect'"
>  "/ruby/lib/ruby/1.8/monitor.rb:229:in `synchronize'"
>  "/ruby/lib/ruby/1.8/net/ftp.rb:174:in `connect'"
>  "/ruby/lib/ruby/1.8/net/ftp.rb:136:in `initialize'"
>  "/ruby/lib/ruby/1.8/net/ftp.rb:120:in `open'"
>   "my_code/connection.rb:27:in `ftp'" # Net::FTP.open(ftp_host,
> username, password)

Looking at that, and at other messages in this thread, I tried this
experiment.  First, I set up a service locally that listened to port
8989 and simply echoed ten lines with a five second delay between each
echo.  (with a simple shell script + inetd)

Then, in irb:

require "socket"
(1..1300).map{|s|puts s;a=TCPSocket.open("localhost",8989);a.readline;a}

This fails with the same EOFError reported in ftp.rb, after opening
the 256th socket.  (I use "map" instead of "each" to keep from closing
sockets in garbage collection)

It would seem that somehow when the underlying operating system has
too many descriptors open, the effect is that TCPSocket.open succeeds,
but it manages to succeed in such a manner that .readline on the
resulting socket will immediately trigger EOFError.

Looking at ext/socket.c, I don't see how that's possible.  The
socket() call should be returning -1 (with errno set to ENFILE) which
should cause init_inetsock_internal to invoke
rb_sys_fail("socket(2)"), but clearly that isn't happening.

So:

ftp.rb gives this error message when there are too many connections
open in this process.  The fault seems to be that TCPSocket.open
claims to succeed when it didn't really.  It is a mystery why that
happens.

-- 
s=%q(  Daniel Martin -- martin / snowplow.org
       puts "s=%q(#{s})",s.map{|i|i}[1]       )
       puts "s=%q(#{s})",s.map{|i|i}[1]