Project

General

Profile

Bug #963

Updated by jeremyevans0 (Jeremy Evans) over 4 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 
 

Back