nio4r 2.3.1 → 2.5.3

Sign up to get free protection for your applications and to get access to all the features.
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 +18 -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