io-endpoint 0.4.0 → 0.5.0
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/io/endpoint/bound_endpoint.rb +86 -0
- data/lib/io/endpoint/composite_endpoint.rb +1 -0
- data/lib/io/endpoint/connected_endpoint.rb +69 -0
- data/lib/io/endpoint/generic.rb +28 -10
- data/lib/io/endpoint/shared_endpoint.rb +3 -132
- data/lib/io/endpoint/ssl_endpoint.rb +46 -28
- data/lib/io/endpoint/version.rb +1 -1
- data/lib/io/endpoint/wrapper.rb +76 -53
- data/lib/io/endpoint.rb +1 -0
- data.tar.gz.sig +0 -0
- metadata +5 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 204ed5172990d0df3a5d02e63b8e75d8caaf161808fea4e99b67f0d422241cc6
|
4
|
+
data.tar.gz: 7ba7e7052949565c4cb327076c493db15d6f3057493f93d4210ec5ac5bc7808b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12aa8f963bc0787de988e9efcf80fbff38a857e8130e663ed8c329402048ab9e1940dcc2637f17de2f77f43d9222914808b5ec89e91420ed0d07475dbabc9d0e
|
7
|
+
data.tar.gz: ce830974878205da1f7e91378af0bdb05f1a4017cc60715c2dca5607573992f38d97712e6b879d99ab31db95a5b12c40ab3df959da12cc56f4b2189dd37b314e
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'generic'
|
7
|
+
require_relative 'composite_endpoint'
|
8
|
+
require_relative 'address_endpoint'
|
9
|
+
|
10
|
+
module IO::Endpoint
|
11
|
+
class BoundEndpoint < Generic
|
12
|
+
def self.bound(endpoint, backlog: Socket::SOMAXCONN, close_on_exec: false)
|
13
|
+
sockets = endpoint.bind
|
14
|
+
|
15
|
+
sockets.each do |server|
|
16
|
+
# This is somewhat optional. We want to have a generic interface as much as possible so that users of this interface can just call it without knowing a lot of internal details. Therefore, we ignore errors here if it's because the underlying socket does not support the operation.
|
17
|
+
begin
|
18
|
+
server.listen(backlog)
|
19
|
+
rescue Errno::EOPNOTSUPP
|
20
|
+
# Ignore.
|
21
|
+
end
|
22
|
+
|
23
|
+
server.close_on_exec = close_on_exec
|
24
|
+
end
|
25
|
+
|
26
|
+
return self.new(endpoint, sockets, **endpoint.options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(endpoint, sockets, **options)
|
30
|
+
super(**options)
|
31
|
+
|
32
|
+
@endpoint = endpoint
|
33
|
+
@sockets = sockets
|
34
|
+
end
|
35
|
+
|
36
|
+
attr :endpoint
|
37
|
+
attr :sockets
|
38
|
+
|
39
|
+
# A endpoint for the local end of the bound socket.
|
40
|
+
# @returns [CompositeEndpoint] A composite endpoint for the local end of the bound socket.
|
41
|
+
def local_address_endpoint(**options)
|
42
|
+
endpoints = @sockets.map do |socket|
|
43
|
+
AddressEndpoint.new(socket.to_io.local_address, **options)
|
44
|
+
end
|
45
|
+
|
46
|
+
return CompositeEndpoint.new(endpoints)
|
47
|
+
end
|
48
|
+
|
49
|
+
# A endpoint for the remote end of the bound socket.
|
50
|
+
# @returns [CompositeEndpoint] A composite endpoint for the remote end of the bound socket.
|
51
|
+
def remote_address_endpoint(**options)
|
52
|
+
endpoints = @sockets.map do |wrapper|
|
53
|
+
AddressEndpoint.new(socket.to_io.remote_address, **options)
|
54
|
+
end
|
55
|
+
|
56
|
+
return CompositeEndpoint.new(endpoints)
|
57
|
+
end
|
58
|
+
|
59
|
+
def close
|
60
|
+
@sockets.each(&:close)
|
61
|
+
@sockets.clear
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
"\#<#{self.class} #{@sockets.size} bound sockets for #{@endpoint}>"
|
66
|
+
end
|
67
|
+
|
68
|
+
def bind(wrapper = Wrapper.default, &block)
|
69
|
+
@sockets.map do |server|
|
70
|
+
if block_given?
|
71
|
+
wrapper.async do
|
72
|
+
yield server
|
73
|
+
end
|
74
|
+
else
|
75
|
+
server.dup
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Generic
|
82
|
+
def bound(**options)
|
83
|
+
BoundEndpoint.bound(self, **options)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'generic'
|
7
|
+
require_relative 'composite_endpoint'
|
8
|
+
require_relative 'socket_endpoint'
|
9
|
+
|
10
|
+
require 'openssl'
|
11
|
+
|
12
|
+
module IO::Endpoint
|
13
|
+
class ConnectedEndpoint < Generic
|
14
|
+
def self.connected(endpoint, close_on_exec: false)
|
15
|
+
socket = endpoint.connect
|
16
|
+
|
17
|
+
socket.close_on_exec = close_on_exec
|
18
|
+
|
19
|
+
return self.new(endpoint, socket, **endpoint.options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(endpoint, socket, **options)
|
23
|
+
super(**options)
|
24
|
+
|
25
|
+
@endpoint = endpoint
|
26
|
+
@socket = socket
|
27
|
+
end
|
28
|
+
|
29
|
+
attr :endpoint
|
30
|
+
attr :socket
|
31
|
+
|
32
|
+
# A endpoint for the local end of the bound socket.
|
33
|
+
# @returns [AddressEndpoint] A endpoint for the local end of the connected socket.
|
34
|
+
def local_address_endpoint(**options)
|
35
|
+
AddressEndpoint.new(socket.to_io.local_address, **options)
|
36
|
+
end
|
37
|
+
|
38
|
+
# A endpoint for the remote end of the bound socket.
|
39
|
+
# @returns [AddressEndpoint] A endpoint for the remote end of the connected socket.
|
40
|
+
def remote_address_endpoint(**options)
|
41
|
+
AddressEndpoint.new(socket.to_io.remote_address, **options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def connect(wrapper = Wrapper.default, &block)
|
45
|
+
if block_given?
|
46
|
+
yield @socket
|
47
|
+
else
|
48
|
+
return @socket.dup
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def close
|
53
|
+
if @socket
|
54
|
+
@socket.close
|
55
|
+
@socket = nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"\#<#{self.class} #{@socket} connected for #{@endpoint}>"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Generic
|
65
|
+
def connected(**options)
|
66
|
+
ConnectedEndpoint.connected(self, **options)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/io/endpoint/generic.rb
CHANGED
@@ -59,22 +59,40 @@ module IO::Endpoint
|
|
59
59
|
@options[:local_address]
|
60
60
|
end
|
61
61
|
|
62
|
-
#
|
63
|
-
# @
|
62
|
+
# Bind a socket to the given address. If a block is given, the socket will be automatically closed when the block exits.
|
63
|
+
# @parameter wrapper [Wrapper] The wrapper to use for binding.
|
64
|
+
# @yields {|socket| ...} An optional block which will be passed the socket.
|
65
|
+
# @parameter socket [Socket] The socket which has been bound.
|
66
|
+
# @returns [Array(Socket)] the bound socket
|
67
|
+
def bind(wrapper = Wrapper.default, &block)
|
68
|
+
raise NotImplementedError
|
69
|
+
end
|
70
|
+
|
71
|
+
# Connects a socket to the given address. If a block is given, the socket will be automatically closed when the block exits.
|
72
|
+
# @parameter wrapper [Wrapper] The wrapper to use for connecting.
|
73
|
+
# @return [Socket] the connected socket
|
74
|
+
def connect(wrapper = Wrapper.default, &block)
|
75
|
+
raise NotImplementedError
|
76
|
+
end
|
77
|
+
|
78
|
+
# Bind and accept connections on the given address.
|
79
|
+
# @parameter wrapper [Wrapper] The wrapper to use for accepting connections.
|
80
|
+
# @yields [Socket] The accepted socket.
|
81
|
+
def accept(wrapper = Wrapper.default, &block)
|
82
|
+
bind(wrapper) do |server|
|
83
|
+
wrapper.accept(server, **@options, &block)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Enumerate all discrete paths as endpoints.
|
88
|
+
# @yields {|endpoint| ...} A block which will be passed each endpoint.
|
89
|
+
# @parameter endpoint [Endpoint] The endpoint.
|
64
90
|
def each
|
65
91
|
return to_enum unless block_given?
|
66
92
|
|
67
93
|
yield self
|
68
94
|
end
|
69
95
|
|
70
|
-
# Accept connections from the specified endpoint.
|
71
|
-
# @param backlog [Integer] the number of connections to listen for.
|
72
|
-
def accept(wrapper = Wrapper.default, *arguments, **options, &block)
|
73
|
-
bind(wrapper, *arguments, **options) do |server|
|
74
|
-
wrapper.accept(server, &block)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
96
|
# Create an Endpoint instance by URI scheme. The host and port of the URI will be passed to the Endpoint factory method, along with any options.
|
79
97
|
#
|
80
98
|
# You should not use untrusted input as it may execute arbitrary code.
|
@@ -1,136 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright,
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative 'socket_endpoint'
|
9
|
-
|
10
|
-
require 'openssl'
|
11
|
-
|
12
|
-
module IO::Endpoint
|
13
|
-
# Pre-connect and pre-bind sockets so that it can be used between processes.
|
14
|
-
class SharedEndpoint < Generic
|
15
|
-
# Create a new `SharedEndpoint` by binding to the given endpoint.
|
16
|
-
def self.bound(endpoint, backlog: Socket::SOMAXCONN, close_on_exec: false, **options)
|
17
|
-
sockets = endpoint.bind(**options)
|
18
|
-
|
19
|
-
sockets.each do |server|
|
20
|
-
# This is somewhat optional. We want to have a generic interface as much as possible so that users of this interface can just call it without knowing a lot of internal details. Therefore, we ignore errors here if it's because the underlying socket does not support the operation.
|
21
|
-
begin
|
22
|
-
server.listen(backlog)
|
23
|
-
rescue Errno::EOPNOTSUPP
|
24
|
-
# Ignore.
|
25
|
-
end
|
26
|
-
|
27
|
-
server.close_on_exec = close_on_exec
|
28
|
-
end
|
29
|
-
|
30
|
-
return self.new(endpoint, sockets)
|
31
|
-
end
|
32
|
-
|
33
|
-
# Create a new `SharedEndpoint` by connecting to the given endpoint.
|
34
|
-
def self.connected(endpoint, close_on_exec: false)
|
35
|
-
socket = endpoint.connect
|
36
|
-
|
37
|
-
socket.close_on_exec = close_on_exec
|
38
|
-
|
39
|
-
return self.new(endpoint, [socket])
|
40
|
-
end
|
41
|
-
|
42
|
-
def initialize(endpoint, sockets, **options)
|
43
|
-
super(**options)
|
44
|
-
|
45
|
-
raise TypeError, "sockets must be an Array" unless sockets.is_a?(Array)
|
46
|
-
|
47
|
-
@endpoint = endpoint
|
48
|
-
@sockets = sockets
|
49
|
-
end
|
50
|
-
|
51
|
-
attr :endpoint
|
52
|
-
attr :sockets
|
53
|
-
|
54
|
-
def local_address_endpoint(**options)
|
55
|
-
endpoints = @sockets.map do |wrapper|
|
56
|
-
AddressEndpoint.new(wrapper.to_io.local_address, **options)
|
57
|
-
end
|
58
|
-
|
59
|
-
return CompositeEndpoint.new(endpoints)
|
60
|
-
end
|
61
|
-
|
62
|
-
def remote_address_endpoint(**options)
|
63
|
-
endpoints = @sockets.map do |wrapper|
|
64
|
-
AddressEndpoint.new(wrapper.to_io.remote_address, **options)
|
65
|
-
end
|
66
|
-
|
67
|
-
return CompositeEndpoint.new(endpoints)
|
68
|
-
end
|
69
|
-
|
70
|
-
# Close all the internal sockets.
|
71
|
-
def close
|
72
|
-
@sockets.each(&:close)
|
73
|
-
@sockets.clear
|
74
|
-
end
|
75
|
-
|
76
|
-
def each(&block)
|
77
|
-
return to_enum unless block_given?
|
78
|
-
|
79
|
-
@sockets.each do |socket|
|
80
|
-
yield SocketEndpoint.new(socket.dup)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def bind(wrapper = Wrapper.default, &block)
|
85
|
-
@sockets.each.map do |server|
|
86
|
-
server = server.dup
|
87
|
-
|
88
|
-
if block_given?
|
89
|
-
wrapper.async do
|
90
|
-
begin
|
91
|
-
yield server
|
92
|
-
ensure
|
93
|
-
server.close
|
94
|
-
end
|
95
|
-
end
|
96
|
-
else
|
97
|
-
server
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def connect(wrapper = Wrapper.default, &block)
|
103
|
-
@sockets.each do |socket|
|
104
|
-
socket = socket.dup
|
105
|
-
|
106
|
-
return socket unless block_given?
|
107
|
-
|
108
|
-
begin
|
109
|
-
return yield(socket)
|
110
|
-
ensure
|
111
|
-
socket.close
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def accept(wrapper = Wrapper.default, &block)
|
117
|
-
bind(wrapper) do |server|
|
118
|
-
wrapper.accept(server, &block)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def to_s
|
123
|
-
"\#<#{self.class} #{@sockets.size} descriptors for #{@endpoint}>"
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
class Generic
|
128
|
-
def bound(**options)
|
129
|
-
SharedEndpoint.bound(self, **options)
|
130
|
-
end
|
131
|
-
|
132
|
-
def connected(**options)
|
133
|
-
SharedEndpoint.connected(self, **options)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
6
|
+
require_relative 'bound_endpoint'
|
7
|
+
require_relative 'connected_endpoint'
|
@@ -8,34 +8,52 @@ require_relative 'generic'
|
|
8
8
|
|
9
9
|
require 'openssl'
|
10
10
|
|
11
|
-
module OpenSSL
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
11
|
+
module OpenSSL
|
12
|
+
module SSL
|
13
|
+
module SocketForwarder
|
14
|
+
unless method_defined?(:close_on_exec=)
|
15
|
+
def close_on_exec=(value)
|
16
|
+
to_io.close_on_exec = value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
unless method_defined?(:close_on_exec)
|
21
|
+
def local_address
|
22
|
+
to_io.local_address
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
unless method_defined?(:wait)
|
27
|
+
def wait(*arguments)
|
28
|
+
to_io.wait(*arguments)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
unless method_defined?(:wait_readable)
|
33
|
+
def wait_readable(*arguments)
|
34
|
+
to_io.wait_readable(*arguments)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
unless method_defined?(:wait_writable)
|
39
|
+
def wait_writable(*arguments)
|
40
|
+
to_io.wait_writable(*arguments)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if IO.method_defined?(:timeout)
|
45
|
+
unless method_defined?(:timeout)
|
46
|
+
def timeout
|
47
|
+
to_io.timeout
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
unless method_defined?(:timeout=)
|
52
|
+
def timeout=(value)
|
53
|
+
to_io.timeout = value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
39
57
|
end
|
40
58
|
end
|
41
59
|
end
|
data/lib/io/endpoint/version.rb
CHANGED
data/lib/io/endpoint/wrapper.rb
CHANGED
@@ -38,50 +38,30 @@ module IO::Endpoint
|
|
38
38
|
raise NotImplementedError
|
39
39
|
end
|
40
40
|
|
41
|
-
# Build and wrap the underlying io.
|
42
|
-
# @option reuse_port [Boolean] Allow this port to be bound in multiple processes.
|
43
|
-
# @option reuse_address [Boolean] Allow this port to be bound in multiple processes.
|
44
|
-
# @option linger [Boolean] Wait for data to be sent before closing the socket.
|
45
|
-
# @option buffered [Boolean] Enable or disable Nagle's algorithm for TCP sockets.
|
46
|
-
def build(*arguments, timeout: nil, reuse_address: true, reuse_port: nil, linger: nil, buffered: false)
|
47
|
-
socket = ::Socket.new(*arguments)
|
48
|
-
|
49
|
-
# Set the timeout:
|
50
|
-
if timeout
|
51
|
-
set_timeout(socket, timeout)
|
52
|
-
end
|
53
|
-
|
54
|
-
if reuse_address
|
55
|
-
socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
56
|
-
end
|
57
|
-
|
58
|
-
if reuse_port
|
59
|
-
socket.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
|
60
|
-
end
|
61
|
-
|
62
|
-
if linger
|
63
|
-
socket.setsockopt(SOL_SOCKET, SO_LINGER, 1)
|
64
|
-
end
|
65
|
-
|
66
|
-
if buffered == false
|
67
|
-
set_buffered(socket, buffered)
|
68
|
-
end
|
69
|
-
|
70
|
-
yield socket if block_given?
|
71
|
-
|
72
|
-
return socket
|
73
|
-
rescue
|
74
|
-
socket&.close
|
75
|
-
raise
|
76
|
-
end
|
77
|
-
|
78
41
|
# Establish a connection to a given `remote_address`.
|
79
42
|
# @example
|
80
43
|
# socket = Async::IO::Socket.connect(Async::IO::Address.tcp("8.8.8.8", 53))
|
81
|
-
# @
|
82
|
-
# @
|
83
|
-
|
84
|
-
|
44
|
+
# @parameter remote_address [Address] The remote address to connect to.
|
45
|
+
# @parameter linger [Boolean] Wait for data to be sent before closing the socket.
|
46
|
+
# @parameter local_address [Address] The local address to bind to before connecting.
|
47
|
+
def connect(remote_address, local_address: nil, linger: nil, timeout: nil, buffered: false, **options)
|
48
|
+
socket = nil
|
49
|
+
|
50
|
+
begin
|
51
|
+
socket = ::Socket.new(remote_address.afamily, remote_address.socktype, remote_address.protocol)
|
52
|
+
|
53
|
+
if linger
|
54
|
+
socket.setsockopt(SOL_SOCKET, SO_LINGER, 1)
|
55
|
+
end
|
56
|
+
|
57
|
+
if buffered == false
|
58
|
+
set_buffered(socket, buffered)
|
59
|
+
end
|
60
|
+
|
61
|
+
if timeout
|
62
|
+
set_timeout(socket, timeout)
|
63
|
+
end
|
64
|
+
|
85
65
|
if local_address
|
86
66
|
if defined?(IP_BIND_ADDRESS_NO_PORT)
|
87
67
|
# Inform the kernel (Linux 4.2+) to not reserve an ephemeral port when using bind(2) with a port number of 0. The port will later be automatically chosen at connect(2) time, in a way that allows sharing a source port as long as the 4-tuple is unique.
|
@@ -90,6 +70,9 @@ module IO::Endpoint
|
|
90
70
|
|
91
71
|
socket.bind(local_address.to_sockaddr)
|
92
72
|
end
|
73
|
+
rescue
|
74
|
+
socket&.close
|
75
|
+
raise
|
93
76
|
end
|
94
77
|
|
95
78
|
begin
|
@@ -108,14 +91,48 @@ module IO::Endpoint
|
|
108
91
|
end
|
109
92
|
end
|
110
93
|
|
94
|
+
# JRuby requires ServerSocket
|
95
|
+
if defined?(::ServerSocket)
|
96
|
+
ServerSocket = ::ServerSocket
|
97
|
+
else
|
98
|
+
ServerSocket = ::Socket
|
99
|
+
end
|
100
|
+
|
111
101
|
# Bind to a local address.
|
112
102
|
# @example
|
113
103
|
# socket = Async::IO::Socket.bind(Async::IO::Address.tcp("0.0.0.0", 9090))
|
114
|
-
# @
|
115
|
-
# @
|
116
|
-
|
117
|
-
|
104
|
+
# @parameter local_address [Address] The local address to bind to.
|
105
|
+
# @parameter reuse_port [Boolean] Allow this port to be bound in multiple processes.
|
106
|
+
# @parameter reuse_address [Boolean] Allow this port to be bound in multiple processes.
|
107
|
+
# @parameter linger [Boolean] Wait for data to be sent before closing the socket.
|
108
|
+
# @parameter protocol [Integer] The socket protocol to use.
|
109
|
+
def bind(local_address, protocol: 0, reuse_address: true, reuse_port: nil, linger: nil, bound_timeout: nil, **options, &block)
|
110
|
+
socket = nil
|
111
|
+
|
112
|
+
begin
|
113
|
+
socket = ServerSocket.new(local_address.afamily, local_address.socktype, protocol)
|
114
|
+
|
115
|
+
if reuse_address
|
116
|
+
socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
117
|
+
end
|
118
|
+
|
119
|
+
if reuse_port
|
120
|
+
socket.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
|
121
|
+
end
|
122
|
+
|
123
|
+
if linger
|
124
|
+
socket.setsockopt(SOL_SOCKET, SO_LINGER, 1)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Set the timeout:
|
128
|
+
if bound_timeout
|
129
|
+
set_timeout(socket, bound_timeout)
|
130
|
+
end
|
131
|
+
|
118
132
|
socket.bind(local_address.to_sockaddr)
|
133
|
+
rescue
|
134
|
+
socket&.close
|
135
|
+
raise
|
119
136
|
end
|
120
137
|
|
121
138
|
return socket unless block_given?
|
@@ -130,11 +147,11 @@ module IO::Endpoint
|
|
130
147
|
end
|
131
148
|
|
132
149
|
# Bind to a local address and accept connections in a loop.
|
133
|
-
def accept(server, timeout:
|
150
|
+
def accept(server, timeout: nil, &block)
|
134
151
|
while true
|
135
152
|
socket, address = server.accept
|
136
153
|
|
137
|
-
socket
|
154
|
+
set_timeout(socket, timeout) if timeout != false
|
138
155
|
|
139
156
|
async do
|
140
157
|
yield socket, address
|
@@ -145,20 +162,26 @@ module IO::Endpoint
|
|
145
162
|
|
146
163
|
class ThreadWrapper < Wrapper
|
147
164
|
def async(&block)
|
148
|
-
Thread.new(&block)
|
165
|
+
::Thread.new(&block)
|
149
166
|
end
|
150
167
|
end
|
151
168
|
|
152
169
|
class FiberWrapper < Wrapper
|
153
170
|
def async(&block)
|
154
|
-
Fiber.schedule(&block)
|
171
|
+
::Fiber.schedule(&block)
|
155
172
|
end
|
156
173
|
end
|
157
174
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
175
|
+
if Fiber.respond_to?(:scheduler)
|
176
|
+
def Wrapper.default
|
177
|
+
if Fiber.scheduler
|
178
|
+
FiberWrapper.new
|
179
|
+
else
|
180
|
+
ThreadWrapper.new
|
181
|
+
end
|
182
|
+
end
|
183
|
+
else
|
184
|
+
def Wrapper.default
|
162
185
|
ThreadWrapper.new
|
163
186
|
end
|
164
187
|
end
|
data/lib/io/endpoint.rb
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-endpoint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -37,7 +37,7 @@ cert_chain:
|
|
37
37
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
38
38
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
39
39
|
-----END CERTIFICATE-----
|
40
|
-
date: 2024-01-
|
40
|
+
date: 2024-01-25 00:00:00.000000000 Z
|
41
41
|
dependencies: []
|
42
42
|
description:
|
43
43
|
email:
|
@@ -48,7 +48,9 @@ files:
|
|
48
48
|
- lib/io/connected.rb
|
49
49
|
- lib/io/endpoint.rb
|
50
50
|
- lib/io/endpoint/address_endpoint.rb
|
51
|
+
- lib/io/endpoint/bound_endpoint.rb
|
51
52
|
- lib/io/endpoint/composite_endpoint.rb
|
53
|
+
- lib/io/endpoint/connected_endpoint.rb
|
52
54
|
- lib/io/endpoint/generic.rb
|
53
55
|
- lib/io/endpoint/host_endpoint.rb
|
54
56
|
- lib/io/endpoint/shared_endpoint.rb
|
@@ -79,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
81
|
- !ruby/object:Gem::Version
|
80
82
|
version: '0'
|
81
83
|
requirements: []
|
82
|
-
rubygems_version: 3.
|
84
|
+
rubygems_version: 3.5.3
|
83
85
|
signing_key:
|
84
86
|
specification_version: 4
|
85
87
|
summary: Provides a separation of concerns interface for IO endpoints.
|
metadata.gz.sig
CHANGED
Binary file
|