Class: Celluloid::IO::TCPSocket

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
CommonMethods
Defined in:
lib/celluloid/io/tcp_socket.rb

Overview

TCPSocket with combined blocking and evented support

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CommonMethods

#acquire_ownership, #evented?, #read, #readpartial, #release_ownership, #wait_readable, #wait_writable, #write

Constructor Details

#initialize(remote_host, remote_port, local_host = nil, local_port = nil) ⇒ TCPSocket

Opens a TCP connection to remote_host on remote_port. If local_host and local_port are specified, then those parameters are used on the local end to establish the connection.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/celluloid/io/tcp_socket.rb', line 25

def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
  # Is it an IPv4 address?
  begin
    @addr = Resolv::IPv4.create(remote_host)
  rescue ArgumentError
  end

  # Guess it's not IPv4! Is it IPv6?
  unless @addr
    begin
      @addr = Resolv::IPv6.create(remote_host)
    rescue ArgumentError
    end
  end

  # Guess it's not an IP address, so let's try DNS
  unless @addr
    # TODO: suppport asynchronous DNS
    # Even EventMachine doesn't do async DNS by default o_O
    addrs = Array(DNSResolver.new.resolve(remote_host))
    raise Resolv::ResolvError, "DNS result has no information for #{remote_host}" if addrs.empty?
    
    # Pseudorandom round-robin DNS support :/
    @addr = addrs[rand(addrs.size)]
  end

  case @addr
  when Resolv::IPv4
    family = Socket::AF_INET
  when Resolv::IPv6
    family = Socket::AF_INET6
  else raise ArgumentError, "unsupported address class: #{@addr.class}"
  end

  @socket = Socket.new(family, Socket::SOCK_STREAM, 0)
  @socket.bind Addrinfo.tcp(local_host, local_port) if local_host

  begin
    @socket.connect_nonblock Socket.sockaddr_in(remote_port, @addr.to_s)
  rescue Errno::EINPROGRESS
    wait_writable
    retry
  rescue Errno::EISCONN
    # We're now connected! Yay exceptions for flow control
    # NOTE: This is the approach the Ruby stdlib docs suggest ;_;
  end
end

Class Method Details

.from_ruby_socket(ruby_socket) ⇒ Object

Convert a Ruby TCPSocket into a Celluloid::IO::TCPSocket



15
16
17
18
19
20
# File 'lib/celluloid/io/tcp_socket.rb', line 15

def self.from_ruby_socket(ruby_socket)
  # Some hax here, but whatever ;)
  socket = allocate
  socket.instance_variable_set(:@socket, ruby_socket)
  socket
end

Instance Method Details

#to_ioObject



73
74
75
# File 'lib/celluloid/io/tcp_socket.rb', line 73

def to_io
  @socket
end