123456789_123456789_123456789_123456789_123456789_

Class: DRb::DRbTCPSocket

Do not use. This class is for internal use only.
Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Inherits: Object
Defined in: lib/drb/drb.rb

Overview

The default drb protocol which communicates over a TCP socket.

The DRb TCP protocol URI looks like: druby://<host>:<port>?<option>. The option is optional.

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(uri, soc, config = {}) ⇒ DRbTCPSocket

Create a new DRbTCPSocket instance.

#uri is the URI we are connected to. soc is the tcp socket we are bound to. DRb.config is our configuration.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 903

def initialize(uri, soc, config={})
  @uri = uri
  @socket = soc
  @config = config
  @acl = config[:tcp_acl]
  @msg = DRbMessage.new(config)
  set_sockopt(@socket)
  @shutdown_pipe_r, @shutdown_pipe_w = IO.pipe
end

Class Method Details

.getservername

Returns the hostname of this server

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 845

def self.getservername
  host = Socket::gethostname
  begin
    Socket::getaddrinfo(host, nil,
                              Socket::AF_UNSPEC,
                              Socket::SOCK_STREAM,
                              0,
                              Socket::AI_PASSIVE)[0][3]
  rescue
    'localhost'
  end
end

.open(uri, config)

Open a client connection to #uri (DRb URI string) using configuration DRb.config.

This can raise DRbBadScheme or DRbBadURI if #uri is not for a recognized protocol. See DRbServer.new for information on built-in URI protocols.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 838

def self.open(uri, config)
  host, port, = parse_uri(uri)
  soc = TCPSocket.open(host, port)
  self.new(uri, soc, config)
end

.open_server(uri, config)

Open a server listening for connections at #uri using configuration DRb.config.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 876

def self.open_server(uri, config)
  uri = 'druby://:0' unless uri
  host, port, _ = parse_uri(uri)
  config = {:tcp_original_host => host}.update(config)
  if host.size == 0
    host = getservername
    soc = open_server_inaddr_any(host, port)
  else
    soc = TCPServer.open(host, port)
  end
  port = soc.addr[1] if port == 0
  config[:tcp_port] = port
  uri = "druby://#{host}:#{port}"
  self.new(uri, soc, config)
end

.open_server_inaddr_any(host, port)

For the families available for host, returns a TCPServer on port. If port is 0 the first available port is used. IPv4 servers are preferred over IPv6 servers.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 861

def self.open_server_inaddr_any(host, port)
  infos = Socket::getaddrinfo(host, nil,
                              Socket::AF_UNSPEC,
                              Socket::SOCK_STREAM,
                              0,
                              Socket::AI_PASSIVE)
  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)
  # :stopdoc:
end

.parse_uri(uri) (private)

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 818

def self.parse_uri(uri)
  if /\Adruby:\/\/(.*?):(\d+)(\?(.*))?\z/ =~ uri
    host = $1
    port = $2.to_i
    option = $4
    [host, port, option]
  else
    raise(DRbBadScheme, uri) unless uri.start_with?('druby:')
    raise(DRbBadURI, 'can\'t parse uri:' + uri)
  end
end

.uri_option(uri, config)

Parse #uri into a [uri, option] pair.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 893

def self.uri_option(uri, config)
  host, port, option = parse_uri(uri)
  return "druby://#{host}:#{port}", option
end

Instance Attribute Details

#alive?Boolean (readonly)

Check to see if this connection is alive.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 1001

def alive?
  return false unless @socket
  if @socket.to_io.wait_readable(0)
    close
    return false
  end
  true
end

#uri (readonly)

Get the URI that we are connected to.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 914

attr_reader :uri

Instance Method Details

#accept

On the server side, for an instance returned by #open_server, accept a client connection and return a new instance to handle the server’s side of this client-server session.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 971

def accept
  while true
    s = accept_or_shutdown
    return nil unless s
    break if (@acl ? @acl.allow_socket?(s) : true)
    s.close
  end
  if @config[:tcp_original_host].to_s.size == 0
    uri = "druby://#{s.addr[3]}:#{@config[:tcp_port]}"
  else
    uri = @uri
  end
  self.class.new(uri, s, @config)
end

#accept_or_shutdown (private)

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 986

def accept_or_shutdown
  readables, = IO.select([@socket, @shutdown_pipe_r])
  if readables.include? @shutdown_pipe_r
    return nil
  end
  @socket.accept
end

#close

Close the connection.

If this is an instance returned by #open_server, then this stops listening for new connections altogether. If this is an instance returned by #open or by #accept, then it closes this particular client-server session.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 953

def close
  shutdown
  if @socket
    @socket.close
    @socket = nil
  end
  close_shutdown_pipe
end

#close_shutdown_pipe (private)

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 962

def close_shutdown_pipe
  @shutdown_pipe_w.close
  @shutdown_pipe_r.close
end

#peeraddr

Get the address of our TCP peer (the other end of the socket we are bound to.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 918

def peeraddr
  @socket.peeraddr
end

#recv_reply

On the client side, receive a reply from the server.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 941

def recv_reply
  @msg.recv_reply(stream)
end

#recv_request

On the server side, receive a request from the client.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 931

def recv_request
  @msg.recv_request(stream)
end

#send_reply(succ, result)

On the server side, send a reply to the client.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 936

def send_reply(succ, result)
  @msg.send_reply(stream, succ, result)
end

#send_request(ref, msg_id, arg, b)

On the client side, send a request to the server.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 926

def send_request(ref, msg_id, arg, b)
  @msg.send_request(stream, ref, msg_id, arg, b)
end

#set_sockopt(soc)

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 1010

def set_sockopt(soc) # :nodoc:
  soc.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
rescue IOError, Errno::ECONNRESET, Errno::EINVAL
  # closed/shutdown socket, ignore error
end

#shutdown

Graceful shutdown

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 996

def shutdown
  @shutdown_pipe_w.close
end

#stream

Get the socket.

[ GitHub ]

  
# File 'lib/drb/drb.rb', line 923

def stream; @socket; end