celluloid-io 0.17.2 → 0.17.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f22ca0d4783bd9c3d65491e35c23cb265f9f5921
4
- data.tar.gz: 19eb07a8af91273aa9d02d0a13d8b8d7cc7fd42e
3
+ metadata.gz: 868ae36a7ec2c6a1f488023e9a2358af5e66cdfd
4
+ data.tar.gz: 90e7851f8bfbe6dc3c47b3d450bb674b2db407c5
5
5
  SHA512:
6
- metadata.gz: 7461a398eda2e60590099d4794bb6bd7bc6d1854b1e69acfea49ef9ff898ba537d25025a89add4582aecb15b276b34bbdf0d84c2d4ba0100a3eefa23f3724476
7
- data.tar.gz: 55426f5b1593876194494c4f193b824daddeaa3679493c84b36d5d8887e4c4f715aa710e4239fdb757065a0af0ebcf48585986af6d50cb06a1d612e5f76e5c7e
6
+ metadata.gz: 1346986683c4491cfbda904e9f399bd1e6c5c6f4b0ac416003f61b7b9c55b8f26c4f07237ed8088e68030acc60a2f117c2b1523d2a46fa44d050eb5a0fec5077
7
+ data.tar.gz: c5d8b43d6a89f49a5751c3c43dbee6bc0cb6b3c21a205350170163182ebda93542eca67076cdc725387358d0ae91a125bf162bb866df99547e9631082e723f0b
@@ -3,6 +3,7 @@ language: ruby
3
3
  rvm:
4
4
  - rbx-2
5
5
  - jruby
6
+ - 2.3.0
6
7
  - 2.2.2
7
8
  - 2.2.0
8
9
  - 2.1.4
data/CHANGES.md CHANGED
@@ -1,3 +1,35 @@
1
+ 0.17.3 (2016-01-18)
2
+ -----
3
+ * [#163](https://github.com/celluloid/celluloid-io/pull/163)
4
+ Support Ruby 2.3.0.
5
+
6
+ * [#162](https://github.com/celluloid/celluloid-io/pull/162)
7
+ Fix broken specs.
8
+
9
+ * [#160](https://github.com/celluloid/celluloid-io/pull/160)
10
+ Use a common super class for all socket wrappers.
11
+ ([@hannesg])
12
+
13
+ * [#159](https://github.com/celluloid/celluloid-io/pull/159)
14
+ UNIXSocket: don't delegate #readline and #puts.
15
+ ([@hannesg])
16
+
17
+ * [#158](https://github.com/celluloid/celluloid-io/pull/158)
18
+ Use unix sockets in unix spec instead of tcp sockets.
19
+ ([@hannesg])
20
+
21
+ * [#157](https://github.com/celluloid/celluloid-io/pull/157)
22
+ Stream#close is not called in subclasses.
23
+ ([@hannesg])
24
+
25
+ * [#155](https://github.com/celluloid/celluloid-io/pull/155)
26
+ Only close Selector it not already closed.
27
+
28
+ * [#98](https://github.com/celluloid/celluloid-io/pull/98)
29
+ Added spec for writing later to a socket within a request/response cycle
30
+ using the timer primitives.
31
+ ([@TiagoCardoso1983])
32
+
1
33
  0.17.2 (2015-09-30)
2
34
  -----
3
35
  * Revamped test suite, using shared RSpec configuration layer provided by Celluloid itself.
@@ -84,3 +116,6 @@
84
116
  0.7.0
85
117
  -----
86
118
  * Initial release forked from Celluloid
119
+
120
+ [@TiagoCardoso1983]: https://github.com/TiagoCardoso1983
121
+ [@hannesg]: https://github.com/hannesg
@@ -4,6 +4,7 @@ require "celluloid"
4
4
  require "celluloid/io/dns_resolver"
5
5
  require "celluloid/io/mailbox"
6
6
  require "celluloid/io/reactor"
7
+ require "celluloid/io/socket"
7
8
  require "celluloid/io/stream"
8
9
 
9
10
  require "celluloid/io/tcp_server"
@@ -49,7 +49,7 @@ module Celluloid
49
49
  # have woken up. However, in some cases, the monitor is already
50
50
  # invalid, e.g. in the case that we are terminating. We catch this
51
51
  # case explicitly.
52
- monitor.close
52
+ monitor.close unless monitor.closed?
53
53
  end
54
54
  end
55
55
 
@@ -0,0 +1,80 @@
1
+ module Celluloid
2
+ module IO
3
+ # Base class for all classes that wrap a ruby socket.
4
+ # @abstract
5
+ class Socket
6
+ extend Forwardable
7
+
8
+ def_delegators :@socket, :close, :close_read, :close_write, :closed?
9
+ def_delegators :@socket, :read_nonblock, :write_nonblock
10
+ def_delegators :@socket, :addr, :getsockopt, :setsockopt, :getsockname, :fcntl
11
+
12
+ # @param socket [BasicSocket, OpenSSL::SSL::SSLSocket]
13
+ def initialize(socket)
14
+ case socket
15
+ when ::BasicSocket, OpenSSL::SSL::SSLSocket
16
+ @socket = socket
17
+ else
18
+ raise ArgumentError, "expected a socket, got #{socket.inspect}"
19
+ end
20
+ end
21
+
22
+ # Returns the wrapped socket.
23
+ # @return [BasicSocket, OpenSSL::SSL::SSLSocket]
24
+ def to_io
25
+ @socket
26
+ end
27
+
28
+ # Compatibility
29
+ Constants = ::Socket::Constants
30
+ include Constants
31
+
32
+ # Celluloid::IO:Socket.new behaves like Socket.new for compatibility.
33
+ # This is is not problematic since Celluloid::IO::Socket is abstract.
34
+ # To instantiate a socket use one of its subclasses.
35
+ def self.new(*args)
36
+ if self == Celluloid::IO::Socket
37
+ return ::Socket.new(*args)
38
+ else
39
+ super
40
+ end
41
+ end
42
+
43
+ # Tries to convert the given ruby socket into a subclass of GenericSocket.
44
+ # @param socket
45
+ # @return [SSLSocket, TCPServer, TCPSocket, UDPSocket, UNIXServer, UNIXSocket]
46
+ # @return [nil] if the socket can't be converted
47
+ def self.try_convert(socket, convert_io = true)
48
+ case socket
49
+ when Celluloid::IO::Socket, Celluloid::IO::SSLServer
50
+ socket
51
+ when ::TCPServer
52
+ TCPServer.new(socket)
53
+ when ::TCPSocket
54
+ TCPSocket.new(socket)
55
+ when ::UDPSocket
56
+ UDPSocket.new(socket)
57
+ when ::UNIXServer
58
+ UNIXServer.new(socket)
59
+ when ::UNIXSocket
60
+ UNIXSocket.new(socket)
61
+ when OpenSSL::SSL::SSLServer
62
+ SSLServer.new(socket.to_io, socket.instance_variable_get(:@ctx))
63
+ when OpenSSL::SSL::SSLSocket
64
+ SSLSocket.new(socket)
65
+ else
66
+ if convert_io
67
+ return try_convert(IO.try_convert(socket), false)
68
+ end
69
+ nil
70
+ end
71
+ end
72
+
73
+ class << self
74
+ extend Forwardable
75
+ def_delegators '::Socket', *(::Socket.methods - self.methods - [:try_convert])
76
+ end
77
+
78
+ end
79
+ end
80
+ end
@@ -11,10 +11,7 @@ module Celluloid
11
11
  attr_reader :tcp_server
12
12
 
13
13
  def initialize(server, ctx)
14
- if server.is_a?(::TCPServer)
15
- server = Celluloid::IO::TCPServer.from_ruby_server(server)
16
- end
17
- @tcp_server = server
14
+ @tcp_server = Socket.try_convert(server)
18
15
  @ctx = ctx
19
16
  @start_immediately = true
20
17
  end
@@ -6,11 +6,7 @@ module Celluloid
6
6
  class SSLSocket < Stream
7
7
  extend Forwardable
8
8
 
9
- def_delegators :@socket,
10
- :read_nonblock,
11
- :write_nonblock,
12
- :close,
13
- :closed?,
9
+ def_delegators :to_io,
14
10
  :cert,
15
11
  :cipher,
16
12
  :client_ca,
@@ -22,14 +18,14 @@ module Celluloid
22
18
  :sync_close=
23
19
 
24
20
  def initialize(io, ctx = OpenSSL::SSL::SSLContext.new)
25
- super()
26
21
  @context = ctx
27
- @socket = OpenSSL::SSL::SSLSocket.new(::IO.try_convert(io), @context)
28
- @socket.sync_close = true if @socket.respond_to?(:sync_close=)
22
+ socket = OpenSSL::SSL::SSLSocket.new(::IO.try_convert(io), @context)
23
+ socket.sync_close = true if socket.respond_to?(:sync_close=)
24
+ super(socket)
29
25
  end
30
26
 
31
27
  def connect
32
- @socket.connect_nonblock
28
+ to_io.connect_nonblock
33
29
  self
34
30
  rescue ::IO::WaitReadable
35
31
  wait_readable
@@ -37,7 +33,7 @@ module Celluloid
37
33
  end
38
34
 
39
35
  def accept
40
- @socket.accept_nonblock
36
+ to_io.accept_nonblock
41
37
  self
42
38
  rescue ::IO::WaitReadable
43
39
  wait_readable
@@ -47,9 +43,6 @@ module Celluloid
47
43
  retry
48
44
  end
49
45
 
50
- def to_io
51
- @socket
52
- end
53
46
  end
54
47
  end
55
48
  end
@@ -8,7 +8,7 @@
8
8
  module Celluloid
9
9
  module IO
10
10
  # Base class of all streams in Celluloid::IO
11
- class Stream
11
+ class Stream < Socket
12
12
  include Enumerable
13
13
 
14
14
  # The "sync mode" of the stream
@@ -16,7 +16,8 @@ module Celluloid
16
16
  # See IO#sync for full details.
17
17
  attr_accessor :sync
18
18
 
19
- def initialize
19
+ def initialize(socket)
20
+ super
20
21
  @eof = false
21
22
  @sync = true
22
23
  @read_buffer = ''.force_encoding(Encoding::ASCII_8BIT)
@@ -309,7 +310,7 @@ module Celluloid
309
310
  # Closes the stream and flushes any unwritten data.
310
311
  def close
311
312
  flush rescue nil
312
- sysclose
313
+ super
313
314
  end
314
315
 
315
316
  #######
@@ -3,36 +3,51 @@ require 'socket'
3
3
  module Celluloid
4
4
  module IO
5
5
  # TCPServer with combined blocking and evented support
6
- class TCPServer
6
+ class TCPServer < Socket
7
7
  extend Forwardable
8
- def_delegators :@server, :listen, :sysaccept, :close, :closed?, :addr, :setsockopt
8
+ def_delegators :to_io, :listen, :sysaccept, :addr
9
9
 
10
- def initialize(hostname_or_port, port = nil)
11
- if port.nil?
12
- @server = ::TCPServer.new(hostname_or_port)
10
+ # @overload initialize(port)
11
+ # Opens a tcp server on the given port.
12
+ # @param port [Numeric]
13
+ #
14
+ # @overload initialize(hostname, port)
15
+ # Opens a tcp server on the given port and interface.
16
+ # @param hostname [String]
17
+ # @param port [Numeric]
18
+ #
19
+ # @overload initialize(socket)
20
+ # Wraps an already existing tcp server instance.
21
+ # @param socket [::TCPServer]
22
+ def initialize(*args)
23
+ if args.first.kind_of? ::BasicSocket
24
+ # socket
25
+ socket = args.first
26
+ fail ArgumentError, "wrong number of arguments (#{args.size} for 1)" if args.size != 1
27
+ fail ArgumentError, "wrong kind of socket (#{socket.class} for TCPServer)" unless socket.kind_of? ::TCPServer
28
+ super(socket)
13
29
  else
14
- @server = ::TCPServer.new(hostname_or_port, port)
30
+ super(::TCPServer.new(*args))
15
31
  end
16
32
  end
17
33
 
34
+ # @return [TCPSocket]
18
35
  def accept
19
- Celluloid::IO.wait_readable(@server)
36
+ Celluloid::IO.wait_readable(to_io)
20
37
  accept_nonblock
21
38
  end
22
39
 
40
+ # @return [TCPSocket]
23
41
  def accept_nonblock
24
- Celluloid::IO::TCPSocket.new(@server.accept_nonblock)
25
- end
26
-
27
- def to_io
28
- @server
42
+ Celluloid::IO::TCPSocket.new(to_io.accept_nonblock)
29
43
  end
30
44
 
31
45
  # Convert a Ruby TCPServer into a Celluloid::IO::TCPServer
46
+ # @deprecated Use .new instead.
32
47
  def self.from_ruby_server(ruby_server)
33
- server = allocate
34
- server.instance_variable_set(:@server, ruby_server)
35
- server
48
+ warn "#from_ruby_server is deprecated please use .new instead"
49
+
50
+ self.new(ruby_server)
36
51
  end
37
52
  end
38
53
  end
@@ -7,8 +7,7 @@ module Celluloid
7
7
  class TCPSocket < Stream
8
8
  extend Forwardable
9
9
 
10
- def_delegators :@socket, :read_nonblock, :write_nonblock, :close, :close_read, :close_write, :closed?
11
- def_delegators :@socket, :addr, :peeraddr, :setsockopt, :getsockname
10
+ def_delegators :to_io, :peeraddr
12
11
 
13
12
  # Open a TCP socket, yielding it to the given block and closing it
14
13
  # automatically when done (if a block is given)
@@ -25,91 +24,114 @@ module Celluloid
25
24
 
26
25
  # Convert a Ruby TCPSocket into a Celluloid::IO::TCPSocket
27
26
  # DEPRECATED: to be removed in a future release
27
+ # @deprecated Use {Celluloid::IO::TCPSocket#new} instead.
28
28
  def self.from_ruby_socket(ruby_socket)
29
29
  new(ruby_socket)
30
30
  end
31
31
 
32
- # Opens a TCP connection to remote_host on remote_port. If local_host
33
- # and local_port are specified, then those parameters are used on the
34
- # local end to establish the connection.
35
- def initialize(remote_host, remote_port = nil, local_host = nil, local_port = nil)
36
- super()
37
-
38
- # Allow users to pass in a Ruby TCPSocket directly
39
- if remote_host.is_a? ::TCPSocket
40
- @addr = nil
41
- @socket = remote_host
42
- return
43
- elsif remote_port.nil?
44
- fail ArgumentError, "wrong number of arguments (1 for 2)"
32
+ # @overload initialize(remote_host, remote_port = nil, local_host = nil, local_port = nil)
33
+ # Opens a TCP connection to remote_host on remote_port. If local_host
34
+ # and local_port are specified, then those parameters are used on the
35
+ # local end to establish the connection.
36
+ # @param remote_host [String, Resolv::IPv4, Resolv::IPv6]
37
+ # @param remote_port [Numeric]
38
+ # @param local_host [String]
39
+ # @param local_port [Numeric]
40
+ #
41
+ # @overload initialize(socket)
42
+ # Wraps an already existing tcp socket.
43
+ # @param socket [::TCPSocket]
44
+ #
45
+ def initialize(*args)
46
+ if args.first.kind_of? ::BasicSocket
47
+ # socket
48
+ socket = args.first
49
+ fail ArgumentError, "wrong number of arguments (#{args.size} for 1)" if args.size != 1
50
+ fail ArgumentError, "wrong kind of socket (#{socket.class} for TCPSocket)" unless socket.kind_of? ::TCPSocket
51
+ super(socket)
52
+ else
53
+ super(create_socket(*args))
45
54
  end
55
+ end
56
+
57
+ # Receives a message
58
+ def recv(maxlen, flags = nil)
59
+ fail NotImplementedError, "flags not supported" if flags && !flags.zero?
60
+ readpartial(maxlen)
61
+ end
62
+
63
+ # Send a message
64
+ def send(msg, flags, dest_sockaddr = nil)
65
+ fail NotImplementedError, "dest_sockaddr not supported" if dest_sockaddr
66
+ fail NotImplementedError, "flags not supported" unless flags.zero?
67
+ write(msg)
68
+ end
69
+
70
+ # @return [Resolv::IPv4, Resolv::IPv6]
71
+ def addr
72
+ socket = to_io
73
+ ra = socket.remote_address
74
+ if ra.ipv4?
75
+ return Resolv::IPv4.create(ra.ip_address)
76
+ elsif ra.ipv6?
77
+ return Resolv::IPv6.create(ra.ip_address)
78
+ else
79
+ raise ArgumentError, "not an ip socket: #{socket.inspect}"
80
+ end
81
+ end
82
+ private
46
83
 
84
+ def create_socket(remote_host, remote_port = nil, local_host = nil, local_port = nil)
47
85
  # Is it an IPv4 address?
48
86
  begin
49
- @addr = Resolv::IPv4.create(remote_host)
87
+ addr = Resolv::IPv4.create(remote_host)
50
88
  rescue ArgumentError
51
89
  end
52
90
 
53
91
  # Guess it's not IPv4! Is it IPv6?
54
- unless @addr
92
+ unless addr
55
93
  begin
56
- @addr = Resolv::IPv6.create(remote_host)
94
+ addr = Resolv::IPv6.create(remote_host)
57
95
  rescue ArgumentError
58
96
  end
59
97
  end
60
98
 
61
99
  # Guess it's not an IP address, so let's try DNS
62
- unless @addr
100
+ unless addr
63
101
  addrs = Array(DNSResolver.new.resolve(remote_host))
64
102
  fail Resolv::ResolvError, "DNS result has no information for #{remote_host}" if addrs.empty?
65
103
 
66
104
  # Pseudorandom round-robin DNS support :/
67
- @addr = addrs[rand(addrs.size)]
105
+ addr = addrs[rand(addrs.size)]
68
106
  end
69
107
 
70
- case @addr
108
+ case addr
71
109
  when Resolv::IPv4
72
110
  family = Socket::AF_INET
73
111
  when Resolv::IPv6
74
112
  family = Socket::AF_INET6
75
- else fail ArgumentError, "unsupported address class: #{@addr.class}"
113
+ else fail ArgumentError, "unsupported address class: #{addr.class}"
76
114
  end
77
115
 
78
- @socket = Socket.new(family, Socket::SOCK_STREAM, 0)
79
- @socket.bind Addrinfo.tcp(local_host, local_port) if local_host
116
+ socket = Socket.new(family, Socket::SOCK_STREAM, 0)
117
+ socket.bind Addrinfo.tcp(local_host, local_port) if local_host
80
118
 
81
119
  begin
82
- @socket.connect_nonblock Socket.sockaddr_in(remote_port, @addr.to_s)
120
+ socket.connect_nonblock Socket.sockaddr_in(remote_port, addr.to_s)
83
121
  rescue Errno::EINPROGRESS, Errno::EALREADY
84
122
  # JRuby raises EINPROGRESS, MRI raises EALREADY
85
-
86
- wait_writable
123
+ Celluloid::IO.wait_writable(socket)
87
124
 
88
125
  # HAX: for some reason we need to finish_connect ourselves on JRuby
89
126
  # This logic is unnecessary but JRuby still throws Errno::EINPROGRESS
90
127
  # if we retry the non-blocking connect instead of just finishing it
91
- retry unless RUBY_PLATFORM == "java" && @socket.to_channel.finish_connect
128
+ retry unless RUBY_PLATFORM == "java" && socket.to_channel.finish_connect
92
129
  rescue Errno::EISCONN
93
130
  # We're now connected! Yay exceptions for flow control
94
131
  # NOTE: This is the approach the Ruby stdlib docs suggest ;_;
95
132
  end
96
- end
97
-
98
- def to_io
99
- @socket
100
- end
101
-
102
- # Receives a message
103
- def recv(maxlen, flags = nil)
104
- fail NotImplementedError, "flags not supported" if flags && !flags.zero?
105
- readpartial(maxlen)
106
- end
107
133
 
108
- # Send a message
109
- def send(msg, flags, dest_sockaddr = nil)
110
- fail NotImplementedError, "dest_sockaddr not supported" if dest_sockaddr
111
- fail NotImplementedError, "flags not supported" unless flags.zero?
112
- write(msg)
134
+ return socket
113
135
  end
114
136
  end
115
137
  end