Class: Celluloid::IO::TCPSocket

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

Overview

TCPSocket with combined blocking and evented support

Constant Summary

Constants inherited from Stream

Stream::BLOCK_SIZE

Instance Attribute Summary

Attributes inherited from Stream

#sync

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Stream

#<<, #close, #each, #each_byte, #eof?, #flush, #getc, #gets, #print, #printf, #puts, #read, #readchar, #readline, #readlines, #readpartial, #sysread, #syswrite, #ungetc, #wait_readable, #wait_writable, #write

Constructor Details

#initialize(remote_host, remote_port = nil, 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.



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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/celluloid/io/tcp_socket.rb', line 38

def initialize(remote_host, remote_port = nil, local_host = nil, local_port = nil)
  super()

  # Allow users to pass in a Ruby TCPSocket directly
  if remote_host.is_a? ::TCPSocket
    @addr = nil
    @socket = remote_host
    return
  elsif remote_port.nil?
    raise ArgumentError, "wrong number of arguments (1 for 2)"
  end

  # 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
    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

    # HAX: for some reason we need to finish_connect ourselves on JRuby
    # This logic is unnecessary but JRuby still throws Errno::EINPROGRESS
    # if we retry the non-blocking connect instead of just finishing it
    retry unless defined?(JRUBY_VERSION) && @socket.to_channel.finish_connect
  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 DEPRECATED: to be removed in a future release



31
32
33
# File 'lib/celluloid/io/tcp_socket.rb', line 31

def self.from_ruby_socket(ruby_socket)
  new(ruby_socket)
end

.open(*args, &block) ⇒ Object

Open a TCP socket, yielding it to the given block and closing it automatically when done (if a block is given)



15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/celluloid/io/tcp_socket.rb', line 15

def self.open(*args, &block)
  sock = new(*args)

  if block_given?
    begin
      yield sock
    ensure
      sock.close
    end
  end

  sock
end

Instance Method Details

#recv(maxlen, flags = nil) ⇒ Object

Receives a message

Raises:

  • (NotImplementedError)


104
105
106
107
# File 'lib/celluloid/io/tcp_socket.rb', line 104

def recv(maxlen, flags = nil)
  raise NotImplementedError, "flags not supported" if flags && !flags.zero?
  readpartial(maxlen)
end

#send(msg, flags, dest_sockaddr = nil) ⇒ Object

Send a message

Raises:

  • (NotImplementedError)


110
111
112
113
114
# File 'lib/celluloid/io/tcp_socket.rb', line 110

def send(msg, flags, dest_sockaddr = nil)
  raise NotImplementedError, "dest_sockaddr not supported" if dest_sockaddr
  raise NotImplementedError, "flags not supported" unless flags.zero?
  write(msg)
end

#to_ioObject



99
100
101
# File 'lib/celluloid/io/tcp_socket.rb', line 99

def to_io
  @socket
end