Bug #963
Updated by jeremyevans0 (Jeremy Evans) over 5 years ago
=begin 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). =end