nio4r 2.3.1-java → 2.5.3-java
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
- data/.github/workflows/workflow.yml +43 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +37 -11
- data/CHANGES.md +40 -0
- data/Gemfile +5 -6
- data/README.md +53 -7
- data/Rakefile +0 -2
- data/examples/echo_server.rb +2 -2
- data/ext/libev/Changes +35 -0
- data/ext/libev/README +2 -1
- data/ext/libev/ev.c +213 -151
- data/ext/libev/ev.h +95 -88
- data/ext/libev/ev_epoll.c +26 -15
- data/ext/libev/ev_kqueue.c +11 -5
- data/ext/libev/ev_linuxaio.c +642 -0
- data/ext/libev/ev_poll.c +13 -8
- data/ext/libev/ev_port.c +5 -2
- data/ext/libev/ev_vars.h +14 -3
- data/ext/libev/ev_wrap.h +16 -0
- data/ext/nio4r/extconf.rb +2 -0
- data/ext/nio4r/monitor.c +1 -0
- data/ext/nio4r/nio4r.h +1 -1
- data/ext/nio4r/org/nio4r/Selector.java +5 -1
- data/ext/nio4r/selector.c +5 -5
- data/lib/nio.rb +3 -3
- data/lib/nio/bytebuffer.rb +4 -0
- data/lib/nio/monitor.rb +10 -8
- data/lib/nio/selector.rb +3 -1
- data/lib/nio/version.rb +1 -1
- data/nio4r.gemspec +10 -2
- data/{tasks → rakelib}/extension.rake +2 -0
- data/{tasks → rakelib}/rspec.rake +0 -0
- data/{tasks → rakelib}/rubocop.rake +0 -0
- data/spec/nio/acceptables_spec.rb +3 -5
- data/spec/nio/bytebuffer_spec.rb +2 -4
- data/spec/nio/monitor_spec.rb +2 -2
- data/spec/nio/selectables/ssl_socket_spec.rb +50 -20
- data/spec/nio/selectables/tcp_socket_spec.rb +23 -17
- data/spec/nio/selectables/udp_socket_spec.rb +13 -8
- data/spec/nio/selector_spec.rb +34 -16
- data/spec/spec_helper.rb +4 -16
- data/spec/support/selectable_examples.rb +37 -17
- metadata +28 -17
- data/.travis.yml +0 -36
- data/LICENSE.txt +0 -20
- data/appveyor.yml +0 -27
- data/ext/libev/README.embed +0 -3
- data/ext/libev/test_libev_win32.c +0 -123
data/ext/libev/ev_poll.c
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
2
|
* libev poll fd activity backend
|
3
3
|
*
|
4
|
-
* Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
|
4
|
+
* Copyright (c) 2007,2008,2009,2010,2011,2016,2019 Marc Alexander Lehmann <libev@schmorp.de>
|
5
5
|
* All rights reserved.
|
6
6
|
*
|
7
7
|
* Redistribution and use in source and binary forms, with or without modifica-
|
@@ -41,10 +41,12 @@
|
|
41
41
|
|
42
42
|
inline_size
|
43
43
|
void
|
44
|
-
|
44
|
+
array_needsize_pollidx (int *base, int offset, int count)
|
45
45
|
{
|
46
|
-
/*
|
47
|
-
* to
|
46
|
+
/* using memset (.., -1, ...) is tempting, we we try
|
47
|
+
* to be ultraportable
|
48
|
+
*/
|
49
|
+
base += offset;
|
48
50
|
while (count--)
|
49
51
|
*base++ = -1;
|
50
52
|
}
|
@@ -57,14 +59,14 @@ poll_modify (EV_P_ int fd, int oev, int nev)
|
|
57
59
|
if (oev == nev)
|
58
60
|
return;
|
59
61
|
|
60
|
-
array_needsize (int, pollidxs, pollidxmax, fd + 1,
|
62
|
+
array_needsize (int, pollidxs, pollidxmax, fd + 1, array_needsize_pollidx);
|
61
63
|
|
62
64
|
idx = pollidxs [fd];
|
63
65
|
|
64
66
|
if (idx < 0) /* need to allocate a new pollfd */
|
65
67
|
{
|
66
68
|
pollidxs [fd] = idx = pollcnt++;
|
67
|
-
array_needsize (struct pollfd, polls, pollmax, pollcnt,
|
69
|
+
array_needsize (struct pollfd, polls, pollmax, pollcnt, array_needsize_noinit);
|
68
70
|
polls [idx].fd = fd;
|
69
71
|
}
|
70
72
|
|
@@ -108,14 +110,17 @@ poll_poll (EV_P_ ev_tstamp timeout)
|
|
108
110
|
else
|
109
111
|
for (p = polls; res; ++p)
|
110
112
|
{
|
111
|
-
assert (("libev: poll
|
113
|
+
assert (("libev: poll returned illegal result, broken BSD kernel?", p < polls + pollcnt));
|
112
114
|
|
113
115
|
if (expect_false (p->revents)) /* this expect is debatable */
|
114
116
|
{
|
115
117
|
--res;
|
116
118
|
|
117
119
|
if (expect_false (p->revents & POLLNVAL))
|
118
|
-
|
120
|
+
{
|
121
|
+
assert (("libev: poll found invalid fd in poll set", 0));
|
122
|
+
fd_kill (EV_A_ p->fd);
|
123
|
+
}
|
119
124
|
else
|
120
125
|
fd_event (
|
121
126
|
EV_A_
|
data/ext/libev/ev_port.c
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
2
|
* libev solaris event port backend
|
3
3
|
*
|
4
|
-
* Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
|
4
|
+
* Copyright (c) 2007,2008,2009,2010,2011,2019 Marc Alexander Lehmann <libev@schmorp.de>
|
5
5
|
* All rights reserved.
|
6
6
|
*
|
7
7
|
* Redistribution and use in source and binary forms, with or without modifica-
|
@@ -69,7 +69,10 @@ port_associate_and_check (EV_P_ int fd, int ev)
|
|
69
69
|
)
|
70
70
|
{
|
71
71
|
if (errno == EBADFD)
|
72
|
-
|
72
|
+
{
|
73
|
+
assert (("libev: port_associate found invalid fd", errno != EBADFD));
|
74
|
+
fd_kill (EV_A_ fd);
|
75
|
+
}
|
73
76
|
else
|
74
77
|
ev_syserr ("(libev) port_associate");
|
75
78
|
}
|
data/ext/libev/ev_vars.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
2
|
* loop member variable declarations
|
3
3
|
*
|
4
|
-
* Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libev@schmorp.de>
|
4
|
+
* Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2019 Marc Alexander Lehmann <libev@schmorp.de>
|
5
5
|
* All rights reserved.
|
6
6
|
*
|
7
7
|
* Redistribution and use in source and binary forms, with or without modifica-
|
@@ -107,6 +107,17 @@ VARx(int, epoll_epermcnt)
|
|
107
107
|
VARx(int, epoll_epermmax)
|
108
108
|
#endif
|
109
109
|
|
110
|
+
#if EV_USE_LINUXAIO || EV_GENWRAP
|
111
|
+
VARx(aio_context_t, linuxaio_ctx)
|
112
|
+
VARx(int, linuxaio_iteration)
|
113
|
+
VARx(struct aniocb **, linuxaio_iocbps)
|
114
|
+
VARx(int, linuxaio_iocbpmax)
|
115
|
+
VARx(struct iocb **, linuxaio_submits)
|
116
|
+
VARx(int, linuxaio_submitcnt)
|
117
|
+
VARx(int, linuxaio_submitmax)
|
118
|
+
VARx(ev_io, linuxaio_epoll_w)
|
119
|
+
#endif
|
120
|
+
|
110
121
|
#if EV_USE_KQUEUE || EV_GENWRAP
|
111
122
|
VARx(pid_t, kqueue_fd_pid)
|
112
123
|
VARx(struct kevent *, kqueue_changes)
|
@@ -195,8 +206,8 @@ VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */
|
|
195
206
|
|
196
207
|
VARx(void *, userdata)
|
197
208
|
/* C++ doesn't support the ev_loop_callback typedef here. stinks. */
|
198
|
-
VAR (release_cb, void (*release_cb)(EV_P)
|
199
|
-
VAR (acquire_cb, void (*acquire_cb)(EV_P)
|
209
|
+
VAR (release_cb, void (*release_cb)(EV_P) EV_NOEXCEPT)
|
210
|
+
VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_NOEXCEPT)
|
200
211
|
VAR (invoke_cb , ev_loop_callback invoke_cb)
|
201
212
|
#endif
|
202
213
|
|
data/ext/libev/ev_wrap.h
CHANGED
@@ -50,6 +50,14 @@
|
|
50
50
|
#define kqueue_eventmax ((loop)->kqueue_eventmax)
|
51
51
|
#define kqueue_events ((loop)->kqueue_events)
|
52
52
|
#define kqueue_fd_pid ((loop)->kqueue_fd_pid)
|
53
|
+
#define linuxaio_ctx ((loop)->linuxaio_ctx)
|
54
|
+
#define linuxaio_epoll_w ((loop)->linuxaio_epoll_w)
|
55
|
+
#define linuxaio_iocbpmax ((loop)->linuxaio_iocbpmax)
|
56
|
+
#define linuxaio_iocbps ((loop)->linuxaio_iocbps)
|
57
|
+
#define linuxaio_iteration ((loop)->linuxaio_iteration)
|
58
|
+
#define linuxaio_submitcnt ((loop)->linuxaio_submitcnt)
|
59
|
+
#define linuxaio_submitmax ((loop)->linuxaio_submitmax)
|
60
|
+
#define linuxaio_submits ((loop)->linuxaio_submits)
|
53
61
|
#define loop_count ((loop)->loop_count)
|
54
62
|
#define loop_depth ((loop)->loop_depth)
|
55
63
|
#define loop_done ((loop)->loop_done)
|
@@ -149,6 +157,14 @@
|
|
149
157
|
#undef kqueue_eventmax
|
150
158
|
#undef kqueue_events
|
151
159
|
#undef kqueue_fd_pid
|
160
|
+
#undef linuxaio_ctx
|
161
|
+
#undef linuxaio_epoll_w
|
162
|
+
#undef linuxaio_iocbpmax
|
163
|
+
#undef linuxaio_iocbps
|
164
|
+
#undef linuxaio_iteration
|
165
|
+
#undef linuxaio_submitcnt
|
166
|
+
#undef linuxaio_submitmax
|
167
|
+
#undef linuxaio_submits
|
152
168
|
#undef loop_count
|
153
169
|
#undef loop_depth
|
154
170
|
#undef loop_done
|
data/ext/nio4r/extconf.rb
CHANGED
@@ -4,6 +4,7 @@ require "rubygems"
|
|
4
4
|
|
5
5
|
# Write a dummy Makefile on Windows because we use the pure Ruby implementation there
|
6
6
|
if Gem.win_platform?
|
7
|
+
require "devkit" if RUBY_PLATFORM.include?("mingw")
|
7
8
|
File.write("Makefile", "all install::\n")
|
8
9
|
File.write("nio4r_ext.so", "")
|
9
10
|
exit
|
@@ -13,6 +14,7 @@ require "mkmf"
|
|
13
14
|
|
14
15
|
have_header("unistd.h")
|
15
16
|
|
17
|
+
$defs << "-DEV_USE_LINUXAIO" if have_header("linux/aio_abi.h")
|
16
18
|
$defs << "-DEV_USE_SELECT" if have_header("sys/select.h")
|
17
19
|
$defs << "-DEV_USE_POLL" if have_type("port_event_t", "poll.h")
|
18
20
|
$defs << "-DEV_USE_EPOLL" if have_header("sys/epoll.h")
|
data/ext/nio4r/monitor.c
CHANGED
data/ext/nio4r/nio4r.h
CHANGED
@@ -19,6 +19,7 @@ import org.jruby.anno.JRubyMethod;
|
|
19
19
|
import org.jruby.runtime.Block;
|
20
20
|
import org.jruby.runtime.ThreadContext;
|
21
21
|
import org.jruby.runtime.builtin.IRubyObject;
|
22
|
+
import org.jruby.util.io.OpenFile;
|
22
23
|
|
23
24
|
import org.nio4r.Monitor;
|
24
25
|
|
@@ -136,7 +137,10 @@ public class Selector extends RubyObject {
|
|
136
137
|
@JRubyMethod
|
137
138
|
public IRubyObject deregister(ThreadContext context, IRubyObject io) {
|
138
139
|
Ruby runtime = context.getRuntime();
|
139
|
-
|
140
|
+
OpenFile file = RubyIO.convertToIO(context, io).getOpenFileInitialized();
|
141
|
+
if (file.fd() == null)
|
142
|
+
return context.nil;
|
143
|
+
Channel rawChannel = file.channel();
|
140
144
|
|
141
145
|
if(!(rawChannel instanceof SelectableChannel)) {
|
142
146
|
throw runtime.newArgumentError("not a selectable IO object");
|
data/ext/nio4r/selector.c
CHANGED
@@ -52,8 +52,8 @@ static VALUE NIO_Selector_close_synchronized(VALUE *args);
|
|
52
52
|
static VALUE NIO_Selector_closed_synchronized(VALUE *args);
|
53
53
|
|
54
54
|
static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout);
|
55
|
-
static void NIO_Selector_timeout_callback(ev_loop *ev_loop, struct ev_timer *timer, int revents);
|
56
|
-
static void NIO_Selector_wakeup_callback(ev_loop *ev_loop, struct ev_io *io, int revents);
|
55
|
+
static void NIO_Selector_timeout_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents);
|
56
|
+
static void NIO_Selector_wakeup_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents);
|
57
57
|
|
58
58
|
/* Default number of slots in the buffer for selected monitors */
|
59
59
|
#define INITIAL_READY_BUFFER 32
|
@@ -530,12 +530,12 @@ static VALUE NIO_Selector_is_empty(VALUE self)
|
|
530
530
|
|
531
531
|
|
532
532
|
/* Called whenever a timeout fires on the event loop */
|
533
|
-
static void NIO_Selector_timeout_callback(ev_loop *ev_loop, struct ev_timer *timer, int revents)
|
533
|
+
static void NIO_Selector_timeout_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents)
|
534
534
|
{
|
535
535
|
}
|
536
536
|
|
537
537
|
/* Called whenever a wakeup request is sent to a selector */
|
538
|
-
static void NIO_Selector_wakeup_callback(ev_loop *ev_loop, struct ev_io *io, int revents)
|
538
|
+
static void NIO_Selector_wakeup_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents)
|
539
539
|
{
|
540
540
|
char buffer[128];
|
541
541
|
struct NIO_Selector *selector = (struct NIO_Selector *)io->data;
|
@@ -546,7 +546,7 @@ static void NIO_Selector_wakeup_callback(ev_loop *ev_loop, struct ev_io *io, int
|
|
546
546
|
}
|
547
547
|
|
548
548
|
/* libev callback fired whenever a monitor gets an event */
|
549
|
-
void NIO_Selector_monitor_callback(ev_loop *ev_loop, struct ev_io *io, int revents)
|
549
|
+
void NIO_Selector_monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents)
|
550
550
|
{
|
551
551
|
struct NIO_Monitor *monitor_data = (struct NIO_Monitor *)io->data;
|
552
552
|
struct NIO_Selector *selector = monitor_data->selector;
|
data/lib/nio.rb
CHANGED
@@ -18,7 +18,7 @@ if ENV["NIO4R_PURE"] == "true" || (Gem.win_platform? && !defined?(JRUBY_VERSION)
|
|
18
18
|
require "nio/monitor"
|
19
19
|
require "nio/selector"
|
20
20
|
require "nio/bytebuffer"
|
21
|
-
NIO::ENGINE = "ruby"
|
21
|
+
NIO::ENGINE = "ruby"
|
22
22
|
else
|
23
23
|
require "nio4r_ext"
|
24
24
|
|
@@ -26,8 +26,8 @@ else
|
|
26
26
|
require "java"
|
27
27
|
require "jruby"
|
28
28
|
org.nio4r.Nio4r.new.load(JRuby.runtime, false)
|
29
|
-
NIO::ENGINE = "java"
|
29
|
+
NIO::ENGINE = "java"
|
30
30
|
else
|
31
|
-
NIO::ENGINE = "libev"
|
31
|
+
NIO::ENGINE = "libev"
|
32
32
|
end
|
33
33
|
end
|
data/lib/nio/bytebuffer.rb
CHANGED
@@ -24,6 +24,7 @@ module NIO
|
|
24
24
|
# @return [NIO::ByteBuffer]
|
25
25
|
def initialize(capacity)
|
26
26
|
raise TypeError, "no implicit conversion of #{capacity.class} to Integer" unless capacity.is_a?(Integer)
|
27
|
+
|
27
28
|
@capacity = capacity
|
28
29
|
clear
|
29
30
|
end
|
@@ -119,9 +120,11 @@ module NIO
|
|
119
120
|
# @return [self]
|
120
121
|
def put(str)
|
121
122
|
raise TypeError, "expected String, got #{str.class}" unless str.respond_to?(:to_str)
|
123
|
+
|
122
124
|
str = str.to_str
|
123
125
|
|
124
126
|
raise OverflowError, "buffer is full" if str.length > @limit - @position
|
127
|
+
|
125
128
|
@buffer[@position...str.length] = str
|
126
129
|
@position += str.length
|
127
130
|
self
|
@@ -188,6 +191,7 @@ module NIO
|
|
188
191
|
# @raise [NIO::ByteBuffer::MarkUnsetError] mark has not been set (call `#mark` first)
|
189
192
|
def reset
|
190
193
|
raise MarkUnsetError, "mark has not been set" unless @mark
|
194
|
+
|
191
195
|
@position = @mark
|
192
196
|
self
|
193
197
|
end
|
data/lib/nio/monitor.rb
CHANGED
@@ -6,16 +6,18 @@ module NIO
|
|
6
6
|
attr_reader :io, :interests, :selector
|
7
7
|
attr_accessor :value, :readiness
|
8
8
|
|
9
|
-
# :nodoc
|
9
|
+
# :nodoc:
|
10
10
|
def initialize(io, interests, selector)
|
11
|
-
unless io.is_a?(
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
unless defined?(::OpenSSL) && io.is_a?(::OpenSSL::SSL::SSLSocket)
|
12
|
+
unless io.is_a?(IO)
|
13
|
+
if IO.respond_to? :try_convert
|
14
|
+
io = IO.try_convert(io)
|
15
|
+
elsif io.respond_to? :to_io
|
16
|
+
io = io.to_io
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
+
raise TypeError, "can't convert #{io.class} into IO" unless io.is_a? IO
|
20
|
+
end
|
19
21
|
end
|
20
22
|
|
21
23
|
@io = io
|
data/lib/nio/selector.rb
CHANGED
@@ -44,7 +44,9 @@ module NIO
|
|
44
44
|
# * :w - is the IO writeable?
|
45
45
|
# * :rw - is the IO either readable or writeable?
|
46
46
|
def register(io, interest)
|
47
|
-
|
47
|
+
unless defined?(::OpenSSL) && io.is_a?(::OpenSSL::SSL::SSLSocket)
|
48
|
+
io = IO.try_convert(io)
|
49
|
+
end
|
48
50
|
|
49
51
|
@lock.synchronize do
|
50
52
|
raise IOError, "selector is closed" if closed?
|
data/lib/nio/version.rb
CHANGED
data/nio4r.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require File.expand_path("
|
3
|
+
require File.expand_path("lib/nio/version", __dir__)
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.authors = ["Tony Arcieri"]
|
@@ -20,7 +20,15 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
spec.version = NIO::VERSION
|
22
22
|
|
23
|
-
spec.
|
23
|
+
spec.metadata = {
|
24
|
+
"bug_tracker_uri" => "https://github.com/socketry/nio4r/issues",
|
25
|
+
"changelog_uri" => "https://github.com/socketry/nio4r/blob/master/CHANGES.md",
|
26
|
+
"documentation_uri" => "https://www.rubydoc.info/gems/nio4r/#{spec.version}",
|
27
|
+
"source_code_uri" => "https://github.com/socketry/nio4r/tree/v#{spec.version}",
|
28
|
+
"wiki_uri" => "https://github.com/socketry/nio4r/wiki"
|
29
|
+
}
|
30
|
+
|
31
|
+
spec.required_ruby_version = ">= 2.4"
|
24
32
|
|
25
33
|
if defined? JRUBY_VERSION
|
26
34
|
spec.files << "lib/nio4r_ext.jar"
|
File without changes
|
File without changes
|
@@ -17,16 +17,14 @@ RSpec.describe "NIO acceptables" do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
describe TCPServer do
|
20
|
-
let(:port) { next_available_tcp_port }
|
21
|
-
|
22
20
|
let :acceptable_subject do
|
23
|
-
server = TCPServer.new("127.0.0.1",
|
24
|
-
TCPSocket.open("127.0.0.1",
|
21
|
+
server = TCPServer.new("127.0.0.1", 0)
|
22
|
+
TCPSocket.open("127.0.0.1", server.local_address.ip_port)
|
25
23
|
server
|
26
24
|
end
|
27
25
|
|
28
26
|
let :unacceptable_subject do
|
29
|
-
TCPServer.new("127.0.0.1",
|
27
|
+
TCPServer.new("127.0.0.1", 0)
|
30
28
|
end
|
31
29
|
|
32
30
|
it_behaves_like "an NIO acceptable"
|
data/spec/nio/bytebuffer_spec.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
-
# rubocop:disable Metrics/BlockLength
|
6
5
|
RSpec.describe NIO::ByteBuffer do
|
7
6
|
let(:capacity) { 256 }
|
8
7
|
let(:example_string) { "Testing 1 2 3..." }
|
@@ -288,8 +287,8 @@ RSpec.describe NIO::ByteBuffer do
|
|
288
287
|
|
289
288
|
context "I/O" do
|
290
289
|
let(:addr) { "127.0.0.1" }
|
291
|
-
let(:
|
292
|
-
let(:
|
290
|
+
let(:server) { TCPServer.new(addr, 0) }
|
291
|
+
let(:port) { server.local_address.ip_port }
|
293
292
|
let(:client) { TCPSocket.new(addr, port) }
|
294
293
|
let(:peer) { server_thread.value }
|
295
294
|
|
@@ -353,4 +352,3 @@ RSpec.describe NIO::ByteBuffer do
|
|
353
352
|
end
|
354
353
|
end
|
355
354
|
end
|
356
|
-
# rubocop:enable Metrics/BlockLength
|
data/spec/nio/monitor_spec.rb
CHANGED
@@ -5,9 +5,9 @@ require "socket"
|
|
5
5
|
|
6
6
|
RSpec.describe NIO::Monitor do
|
7
7
|
let(:addr) { "127.0.0.1" }
|
8
|
-
let(:port) { next_available_tcp_port }
|
9
8
|
|
10
|
-
let(:reader) { TCPServer.new(addr,
|
9
|
+
let(:reader) { TCPServer.new(addr, 0) }
|
10
|
+
let(:port) { reader.local_address.ip_port }
|
11
11
|
let(:writer) { TCPSocket.new(addr, port) }
|
12
12
|
|
13
13
|
let(:selector) { NIO::Selector.new }
|
@@ -1,13 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
|
-
require "openssl"
|
5
4
|
|
6
5
|
RSpec.describe OpenSSL::SSL::SSLSocket do
|
6
|
+
|
7
|
+
require "openssl"
|
8
|
+
|
9
|
+
before(:all) do
|
10
|
+
@tls = []
|
11
|
+
end
|
12
|
+
|
7
13
|
let(:addr) { "127.0.0.1" }
|
8
|
-
let(:port) { next_available_tcp_port }
|
9
14
|
|
10
|
-
let(:ssl_key) { OpenSSL::PKey::RSA.new(
|
15
|
+
let(:ssl_key) { OpenSSL::PKey::RSA.new(2048) }
|
11
16
|
|
12
17
|
let(:ssl_cert) do
|
13
18
|
name = OpenSSL::X509::Name.new([%w[CN 127.0.0.1]])
|
@@ -28,12 +33,19 @@ RSpec.describe OpenSSL::SSL::SSLSocket do
|
|
28
33
|
OpenSSL::SSL::SSLContext.new.tap do |ctx|
|
29
34
|
ctx.cert = ssl_cert
|
30
35
|
ctx.key = ssl_key
|
36
|
+
unless @tls.empty?
|
37
|
+
if ctx.respond_to? :set_minmax_proto_version, true
|
38
|
+
ctx.max_version = @tls[0]
|
39
|
+
else
|
40
|
+
ctx.ssl_version = @tls[1]
|
41
|
+
end
|
42
|
+
end
|
31
43
|
end
|
32
44
|
end
|
33
45
|
|
34
46
|
let :readable_subject do
|
35
|
-
server = TCPServer.new(addr,
|
36
|
-
client = TCPSocket.open(addr,
|
47
|
+
server = TCPServer.new(addr, 0)
|
48
|
+
client = TCPSocket.open(addr, server.local_address.ip_port)
|
37
49
|
peer = server.accept
|
38
50
|
|
39
51
|
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
|
@@ -47,16 +59,17 @@ RSpec.describe OpenSSL::SSL::SSLSocket do
|
|
47
59
|
|
48
60
|
ssl_peer.accept
|
49
61
|
ssl_peer << "data"
|
62
|
+
ssl_peer.flush
|
50
63
|
|
51
64
|
thread.join
|
52
|
-
pending "Failed to produce a readable SSL socket" unless select([ssl_client], [], [], 0)
|
53
65
|
|
66
|
+
pending "Failed to produce a readable socket" unless select([ssl_client], [], [], 10)
|
54
67
|
ssl_client
|
55
68
|
end
|
56
69
|
|
57
70
|
let :unreadable_subject do
|
58
|
-
server = TCPServer.new(addr,
|
59
|
-
client = TCPSocket.new(addr,
|
71
|
+
server = TCPServer.new(addr, 0)
|
72
|
+
client = TCPSocket.new(addr, server.local_address.ip_port)
|
60
73
|
peer = server.accept
|
61
74
|
|
62
75
|
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
|
@@ -70,13 +83,17 @@ RSpec.describe OpenSSL::SSL::SSLSocket do
|
|
70
83
|
ssl_peer.accept
|
71
84
|
thread.join
|
72
85
|
|
86
|
+
if ssl_client.ssl_version == "TLSv1.3"
|
87
|
+
expect(ssl_client.read_nonblock(1, exception: false)).to eq(:wait_readable)
|
88
|
+
end
|
89
|
+
|
73
90
|
pending "Failed to produce an unreadable socket" if select([ssl_client], [], [], 0)
|
74
91
|
ssl_client
|
75
92
|
end
|
76
93
|
|
77
94
|
let :writable_subject do
|
78
|
-
server = TCPServer.new(addr,
|
79
|
-
client = TCPSocket.new(addr,
|
95
|
+
server = TCPServer.new(addr, 0)
|
96
|
+
client = TCPSocket.new(addr, server.local_address.ip_port)
|
80
97
|
peer = server.accept
|
81
98
|
|
82
99
|
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
|
@@ -95,8 +112,8 @@ RSpec.describe OpenSSL::SSL::SSLSocket do
|
|
95
112
|
end
|
96
113
|
|
97
114
|
let :unwritable_subject do
|
98
|
-
server = TCPServer.new(addr,
|
99
|
-
client = TCPSocket.new(addr,
|
115
|
+
server = TCPServer.new(addr, 0)
|
116
|
+
client = TCPSocket.new(addr, server.local_address.ip_port)
|
100
117
|
peer = server.accept
|
101
118
|
|
102
119
|
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
|
@@ -128,22 +145,22 @@ RSpec.describe OpenSSL::SSL::SSLSocket do
|
|
128
145
|
|
129
146
|
# Once more for good measure!
|
130
147
|
begin
|
131
|
-
#
|
148
|
+
# ssl_client.write_nonblock "X" * 1024
|
132
149
|
loop { ssl_client.write_nonblock "X" * 1024 }
|
133
150
|
rescue OpenSSL::SSL::SSLError
|
134
151
|
end
|
135
152
|
|
136
153
|
# Sanity check to make sure we actually produced an unwritable socket
|
137
|
-
|
138
|
-
|
139
|
-
|
154
|
+
if select([], [ssl_client], [], 0)
|
155
|
+
pending "Failed to produce an unwritable socket"
|
156
|
+
end
|
140
157
|
|
141
158
|
ssl_client
|
142
159
|
end
|
143
160
|
|
144
161
|
let :pair do
|
145
|
-
server = TCPServer.new(addr,
|
146
|
-
client = TCPSocket.new(addr,
|
162
|
+
server = TCPServer.new(addr, 0)
|
163
|
+
client = TCPSocket.new(addr, server.local_address.ip_port)
|
147
164
|
peer = server.accept
|
148
165
|
|
149
166
|
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
|
@@ -159,6 +176,19 @@ RSpec.describe OpenSSL::SSL::SSLSocket do
|
|
159
176
|
[thread.value, ssl_peer]
|
160
177
|
end
|
161
178
|
|
162
|
-
|
163
|
-
|
179
|
+
describe "using TLS 1.2" do
|
180
|
+
before(:all) do
|
181
|
+
@tls = %i[TLS1_2 TLSv1_2]
|
182
|
+
end
|
183
|
+
it_behaves_like "an NIO selectable"
|
184
|
+
it_behaves_like "an NIO selectable stream"
|
185
|
+
end
|
186
|
+
|
187
|
+
describe "using TLS 1.3", if: OpenSSL::SSL.const_defined?(:TLS1_3_VERSION) do
|
188
|
+
before(:all) do
|
189
|
+
@tls = %i[TLS1_3 TLSv1_3]
|
190
|
+
end
|
191
|
+
it_behaves_like "an NIO selectable"
|
192
|
+
it_behaves_like "an NIO selectable stream", true
|
193
|
+
end
|
164
194
|
end
|