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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/workflow.yml +43 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +37 -11
  5. data/CHANGES.md +40 -0
  6. data/Gemfile +5 -6
  7. data/README.md +53 -7
  8. data/Rakefile +0 -2
  9. data/examples/echo_server.rb +2 -2
  10. data/ext/libev/Changes +35 -0
  11. data/ext/libev/README +2 -1
  12. data/ext/libev/ev.c +213 -151
  13. data/ext/libev/ev.h +95 -88
  14. data/ext/libev/ev_epoll.c +26 -15
  15. data/ext/libev/ev_kqueue.c +11 -5
  16. data/ext/libev/ev_linuxaio.c +642 -0
  17. data/ext/libev/ev_poll.c +13 -8
  18. data/ext/libev/ev_port.c +5 -2
  19. data/ext/libev/ev_vars.h +14 -3
  20. data/ext/libev/ev_wrap.h +16 -0
  21. data/ext/nio4r/extconf.rb +2 -0
  22. data/ext/nio4r/monitor.c +1 -0
  23. data/ext/nio4r/nio4r.h +1 -1
  24. data/ext/nio4r/org/nio4r/Selector.java +5 -1
  25. data/ext/nio4r/selector.c +5 -5
  26. data/lib/nio.rb +3 -3
  27. data/lib/nio/bytebuffer.rb +4 -0
  28. data/lib/nio/monitor.rb +10 -8
  29. data/lib/nio/selector.rb +3 -1
  30. data/lib/nio/version.rb +1 -1
  31. data/nio4r.gemspec +10 -2
  32. data/{tasks → rakelib}/extension.rake +2 -0
  33. data/{tasks → rakelib}/rspec.rake +0 -0
  34. data/{tasks → rakelib}/rubocop.rake +0 -0
  35. data/spec/nio/acceptables_spec.rb +3 -5
  36. data/spec/nio/bytebuffer_spec.rb +2 -4
  37. data/spec/nio/monitor_spec.rb +2 -2
  38. data/spec/nio/selectables/ssl_socket_spec.rb +50 -20
  39. data/spec/nio/selectables/tcp_socket_spec.rb +23 -17
  40. data/spec/nio/selectables/udp_socket_spec.rb +13 -8
  41. data/spec/nio/selector_spec.rb +34 -16
  42. data/spec/spec_helper.rb +4 -16
  43. data/spec/support/selectable_examples.rb +37 -17
  44. metadata +28 -17
  45. data/.travis.yml +0 -36
  46. data/LICENSE.txt +0 -20
  47. data/appveyor.yml +0 -27
  48. data/ext/libev/README.embed +0 -3
  49. data/ext/libev/test_libev_win32.c +0 -123
@@ -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
- pollidx_init (int *base, int count)
44
+ array_needsize_pollidx (int *base, int offset, int count)
45
45
  {
46
- /* consider using memset (.., -1, ...), which is practically guaranteed
47
- * to work on all systems implementing poll */
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, pollidx_init);
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, EMPTY2);
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() returned illegal result, broken BSD kernel?", p < polls + pollcnt));
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
- fd_kill (EV_A_ p->fd);
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_
@@ -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
- fd_kill (EV_A_ fd);
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
  }
@@ -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) EV_THROW)
199
- VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_THROW)
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
 
@@ -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
@@ -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")
@@ -66,6 +66,7 @@ static VALUE NIO_Monitor_allocate(VALUE klass)
66
66
 
67
67
  static void NIO_Monitor_mark(struct NIO_Monitor *monitor)
68
68
  {
69
+ return rb_gc_mark(monitor->self);
69
70
  }
70
71
 
71
72
  static void NIO_Monitor_free(struct NIO_Monitor *monitor)
@@ -12,7 +12,7 @@
12
12
 
13
13
  struct NIO_Selector
14
14
  {
15
- ev_loop *ev_loop;
15
+ struct ev_loop *ev_loop;
16
16
  struct ev_timer timer; /* for timeouts */
17
17
  struct ev_io wakeup;
18
18
 
@@ -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
- Channel rawChannel = RubyIO.convertToIO(context, io).getChannel();
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");
@@ -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".freeze
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".freeze
29
+ NIO::ENGINE = "java"
30
30
  else
31
- NIO::ENGINE = "libev".freeze
31
+ NIO::ENGINE = "libev"
32
32
  end
33
33
  end
@@ -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
@@ -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?(IO)
12
- if IO.respond_to? :try_convert
13
- io = IO.try_convert(io)
14
- elsif io.respond_to? :to_io
15
- io = io.to_io
16
- end
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
- raise TypeError, "can't convert #{io.class} into IO" unless io.is_a? IO
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
@@ -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
- io = IO.try_convert(io)
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?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NIO
4
- VERSION = "2.3.1".freeze
4
+ VERSION = "2.5.3"
5
5
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path("../lib/nio/version", __FILE__)
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.required_ruby_version = ">= 2.2.2"
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"
@@ -4,6 +4,8 @@ if defined? JRUBY_VERSION
4
4
  require "rake/javaextensiontask"
5
5
  Rake::JavaExtensionTask.new("nio4r_ext") do |ext|
6
6
  ext.ext_dir = "ext/nio4r"
7
+ ext.source_version = "1.8"
8
+ ext.target_version = "1.8"
7
9
  end
8
10
  else
9
11
  require "rake/extensiontask"
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", port)
24
- TCPSocket.open("127.0.0.1", port)
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", port + 1)
27
+ TCPServer.new("127.0.0.1", 0)
30
28
  end
31
29
 
32
30
  it_behaves_like "an NIO acceptable"
@@ -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(:port) { next_available_tcp_port }
292
- let(:server) { TCPServer.new(addr, port) }
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
@@ -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, port) }
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(1024) }
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, port)
36
- client = TCPSocket.open(addr, port)
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, port)
59
- client = TCPSocket.new(addr, port)
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, port)
79
- client = TCPSocket.new(addr, port)
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, port)
99
- client = TCPSocket.new(addr, port)
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
- # ssl_client.write_nonblock "X" * 1024
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
- # if select([], [ssl_client], [], 0)
138
- # pending "Failed to produce an unwritable socket"
139
- # end
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, port)
146
- client = TCPSocket.new(addr, port)
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
- it_behaves_like "an NIO selectable"
163
- it_behaves_like "an NIO selectable stream"
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