Bug #963: /opt/local/lib/ruby/1.8/drb/drb.rb:852:in `initialize': getaddrinfo: nodename nor servname provided, or not known (SocketError)
http://redmine.ruby-lang.org/issues/show/963

Author: Charl Matthee
Status: Open, Priority: Normal

There are two issues here:

1) The DRb code in drb.rb does not correctly deal with multiple network families if they're present.
2) TCPServer.open(port) where port == 0 fails on OS X but not Linux.


When you run the following DRb client code you get the error in the Summary:

#!/usr/bin/env ruby -KU

require 'rubygems'
require 'thread'
require 'drb'

Thread.abort_on_exception = true
DRb.start_service
q = DRbObject.new_with_uri('druby://127.0.0.1:3491')
loop do
  q.push("Hello from #{Process.pid} at #{Time.now}", rand(10))
  sleep 1
end
exit


The source in question is (/opt/local/lib/ruby/1.8/drb/drb.rb:852):

    def self.open_server_inaddr_any(host, port)
      infos = Socket::getaddrinfo(host, nil,
                                  Socket::AF_UNSPEC,
                                  Socket::SOCK_STREAM,                                  0,
                                  Socket::AI_PASSIVE)
      family = infos.collect { |af, *_| af }.uniq
      case family
      when ['AF_INET']
        return TCPServer.open('0.0.0.0', port)
      when ['AF_INET6']
        return TCPServer.open('::', port)
      else
        return TCPServer.open(port)
      end
    end


On my MacBook Pro the Socket::getaddrinfo() above returns the following (where hostname == 'localhost'):

[["AF_INET6", 0, "localhost", "::1", 30, 1, 6], ["AF_INET6",
0, "localhost", "fe80::1%lo0", 30, 1, 6], ["AF_INET", 0, "localhost",
"127.0.0.1", 2, 1, 6]]


The family assignment and case block are written to assume that you'll generally have only one network family in the
family variable. Deviations to this fall through to call the following code (where port == 0) from that block which
is where the error occurs:

return TCPServer.open(port)


TCPServer.open(port) where port == 0 seems to fail on OS X:

$ irb
irb(main):001:0> require "socket"
=> true
irb(main):002:0> port = 0
=> 0
irb(main):003:0> TCPServer.open(port)
SocketError: getaddrinfo: nodename nor servname provided, or not known
        from (irb):3:in `initialize'
        from (irb):3:in `open'
        from (irb):3
        from :0
irb(main):004:0>


But the same works on Linux:

$ irb
irb(main):001:0> require "socket"
=> true
irb(main):002:0> port = 0
=> 0
irb(main):003:0> TCPServer.open(port)
=> #<TCPServer:0xb7c37f78>
irb(main):004:0>


The patch below simply fixes /opt/local/lib/ruby/1.8/drb/drb.rb (issue #1 above) by treating the network families as
a list and trying 'AF_INET' and 'AF_INET6' in succession and then falling through to TCPServer.open(port) if no families
matched:

$ diff /opt/local/lib/ruby/1.8/drb/drb.rb ~/Desktop/drb.rb-new 
845,853c845,848
<       family = infos.collect { |af, *_| af }.uniq
<       case family
<       when ['AF_INET']
<         return TCPServer.open('0.0.0.0', port)
<       when ['AF_INET6']
<         return TCPServer.open('::', port)
<       else
<         return TCPServer.open(port)
<       end
---
>       families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
>       return TCPServer.open('0.0.0.0', port) if families.has_key?('AF_INET')
>       return TCPServer.open('::', port) if families.has_key?('AF_INET6')
>       return TCPServer.open(port)
866c861
<       soc = TCPServer.open(host, port)
---
>       soc = TCPServer.open(host,  port)


A further patch may be required to deal with the different way in which OS X responds to TCPServer.open(0) (issue #2
above).


----------------------------------------
http://redmine.ruby-lang.org