celluloid-io 0.17.2 → 0.17.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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