Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial non-blocking connect support

  • Loading branch information...
commit b9f9ffab2cb53a0ecdc040ebefd5c32e47a54d44 1 parent c2a5a5e
@tarcieri tarcieri authored
Showing with 49 additions and 3 deletions.
  1. +3 −1 .travis.yml
  2. +4 −0 CHANGES.md
  3. +42 −2 lib/celluloid/io/tcp_socket.rb
View
4 .travis.yml
@@ -3,7 +3,9 @@ rvm:
- 1.9.3
- ruby-head
- jruby-19mode
- - jruby-head
+
+# Non-blocking connect is causing deadlocks on jruby-head
+# - jruby-head
# See https://github.com/rubinius/rubinius/issues/1611
# - rbx-19mode
View
4 CHANGES.md
@@ -1,3 +1,7 @@
+HEAD
+----
+* True non-blocking connect support (async DNS support still pending)
+
0.9.0
-----
* TCPServer, TCPSocket, and UDPSocket classes in Celluloid::IO namespace
View
44 lib/celluloid/io/tcp_socket.rb
@@ -1,4 +1,5 @@
require 'socket'
+require 'resolv'
module Celluloid
module IO
@@ -22,8 +23,47 @@ def self.from_ruby_socket(ruby_socket)
# and local_port are specified, then those parameters are used on the
# local end to establish the connection.
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
- # FIXME: not using non-blocking connect
- @socket = ::TCPSocket.new(remote_host, remote_port, local_host, local_port)
+ # 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
+ @addr = Resolv::DNS.new.getaddress(remote_host)
+ 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
def to_io

1 comment on commit b9f9ffa

Please sign in to comment.
Something went wrong with that request. Please try again.