class DRb::DRbTCPSocket

def self.getservername

Returns the hostname of this server
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

def self.open(uri, config)

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

+config+.
Open a client connection to +uri+ (DRb URI string) using configuration
def self.open(uri, config)
  host, port, = parse_uri(uri)
  soc = TCPSocket.open(host, port)
  self.new(uri, soc, config)
end

def self.open_server(uri, config)

configuration +config+.
Open a server listening for connections at +uri+ using
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

def self.open_server_inaddr_any(host, port)

preferred over IPv6 servers.
If +port+ is 0 the first available port is used. IPv4 servers are
For the families available for +host+, returns a TCPServer on +port+.
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

def self.parse_uri(uri)

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

def self.uri_option(uri, config)

Parse +uri+ into a [uri, option] pair.
def self.uri_option(uri, config)
  host, port, option = parse_uri(uri)
  return "druby://#{host}:#{port}", option
end

def accept

the server's side of this client-server session.
accept a client connection and return a new instance to handle
On the server side, for an instance returned by #open_server,
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

def accept_or_shutdown

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

def alive?

Check to see if this connection is alive.
def alive?
  return false unless @socket
  if @socket.to_io.wait_readable(0)
    close
    return false
  end
  true
end

def close

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

Close the connection.
def close
  shutdown
  if @socket
    @socket.close
    @socket = nil
  end
  close_shutdown_pipe
end

def close_shutdown_pipe

def close_shutdown_pipe
  @shutdown_pipe_w.close
  @shutdown_pipe_r.close
end

def initialize(uri, soc, config={})

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

Create a new DRbTCPSocket instance.
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

def peeraddr

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

def recv_reply

On the client side, receive a reply from the server.
def recv_reply
  @msg.recv_reply(stream)
end

def recv_request

On the server side, receive a request from the client.
def recv_request
  @msg.recv_request(stream)
end

def send_reply(succ, result)

On the server side, send a reply to the client.
def send_reply(succ, result)
  @msg.send_reply(stream, succ, result)
end

def send_request(ref, msg_id, arg, b)

On the client side, send a request to the server.
def send_request(ref, msg_id, arg, b)
  @msg.send_request(stream, ref, msg_id, arg, b)
end

def set_sockopt(soc) # :nodoc:

:nodoc:
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

def shutdown

Graceful shutdown
def shutdown
  @shutdown_pipe_w.close
end

def stream; @socket; end

Get the socket.
def stream; @socket; end