When we first started trying to use distributed DeepTest, we quickly ran into an issue with DRb servers not binding to the correct addresses. DRb does provide a way to bind to 0.0.0.0 to listen to all addresses, but there’s a downside to the way it does it. The url you provide to DRb to accomplish this must omit the hostname (e.g. druby://:0/). DRb then determines what hostname to report to clients by calling getaddrinfo with the empty hostname. Unfortunately for us getaddrinfo didn’t provide a hostname that could be used by our developer machines to connect to the DeepTest servers. For a brief moment we thought we were stuck.

When we looked into how DRb handles protocols, however, we realized we could simply add a protocol that would accept a hostname as part of the url and use it to report the DRb url to clients when needed. For listening on the network, however, the protocol always binds to 0.0.0.0. By registering this protocol (which we called drubyall since it listens on all interfaces) you can use it in any DRb url, which is pretty handy. Although it wasn’t nice that we ran into the problem, it was very nice that DRb gave us an easy out to extending its communications layer.


  module DeepTest
    class DRbBindAllTCPSocket < DRb::DRbTCPSocket
      def self.parse_uri(uri)
        if uri =~ /^drubyall:\/\/(.*?):(\d+)(\?(.*))?$/
          host = $1
          port = $2.to_i
          option = $4
          [host, port, option]
        else
          raise(DRb::DRbBadScheme, uri) unless uri =~ /^drubyall:/
          raise(DRb::DRbBadURI, 'can\'t parse uri:' + uri)
        end
      end

      # Open a server listening for connections at +uri+ using 
      # configuration +config+.
      def self.open_server(uri, config)
        uri = 'drubyall://:0' unless uri
        host, port, opt = parse_uri(uri)

        if host.size == 0
          host = getservername
        end

        DeepTest.logger.debug("Listening on port #{port}, all addresses.")
        soc = TCPServer.open('0.0.0.0', port)          
        port = soc.addr[1] if port == 0
        uri = "druby://#{host}:#{port}" 
        self.new(uri, soc, config)
      end
    end
  end

  DRb::DRbProtocol.add_protocol DeepTest::DRbBindAllTCPSocket

Sorry, comments are closed for this article.