uringmachine 0.5 → 0.5.1

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.
data/ext/um/um_ssl.h ADDED
@@ -0,0 +1,22 @@
1
+ #ifndef UM_SSL_H
2
+ #define UM_SSL_H
3
+
4
+ #include <ruby.h>
5
+ // #include <openssl/bio.h>
6
+ #include <openssl/ssl.h>
7
+ // #include <openssl/dh.h>
8
+ // #include <openssl/err.h>
9
+ // #include <openssl/x509.h>
10
+
11
+ enum ssl_role {
12
+ ROLE_SERVER,
13
+ ROLE_CLIENT
14
+ };
15
+
16
+ struct um_ssl_connection {
17
+ VALUE self;
18
+
19
+ enum ssl_role role;
20
+ };
21
+
22
+ #endif // UM_SSL_H
@@ -0,0 +1,138 @@
1
+ /*
2
+ Adopted from:
3
+ https://github.com/puma/puma/blob/master/ext/puma_http11/mini_ssl.c
4
+
5
+ License (BSD-3):
6
+ https://github.com/puma/puma/blob/master/LICENSE
7
+ */
8
+
9
+ #include "um.h"
10
+ #include "um_ssl.h"
11
+ // #include <openssl/bio.h>
12
+ #include <openssl/ssl.h>
13
+ // #include <openssl/dh.h>
14
+ // #include <openssl/err.h>
15
+ // #include <openssl/x509.h>
16
+
17
+ VALUE eSSLError;
18
+ VALUE cSSLConnection;
19
+
20
+ static void UM_SSL_Connection_mark(void *ptr) {
21
+ // struct um_ssl_connection *connection = ptr;
22
+ // rb_gc_mark_movable(connection->self);
23
+
24
+ // um_op_list_mark(machine, machine->transient_head);
25
+ // um_op_list_mark(machine, machine->runqueue_head);
26
+ }
27
+
28
+ static void UM_SSL_Connection_compact(void *ptr) {
29
+ // struct um_ssl_connection *connection = ptr;
30
+ // machine->self = rb_gc_location(machine->self);
31
+ // machine->poll_fiber = rb_gc_location(machine->poll_fiber);
32
+
33
+ // um_op_list_compact(machine, machine->transient_head);
34
+ // um_op_list_compact(machine, machine->runqueue_head);
35
+ }
36
+
37
+ static void UM_SSL_Connection_free(void *ptr) {
38
+ // um_ssl_connection_teardown((struct um_ssl_connection *)ptr);
39
+ free(ptr);
40
+ }
41
+
42
+ static size_t UM_SSL_Connection_size(const void *ptr) {
43
+ return sizeof(struct um_ssl_connection);
44
+ }
45
+
46
+ static const rb_data_type_t UM_SSL_Connection_type = {
47
+ "UringMachine::SSL::Connection",
48
+ {UM_SSL_Connection_mark, UM_SSL_Connection_free, UM_SSL_Connection_size, UM_SSL_Connection_compact},
49
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
50
+ };
51
+
52
+ static VALUE UM_SSL_Connection_allocate(VALUE klass) {
53
+ struct um_ssl_connection *connection = ALLOC(struct um_ssl_connection);
54
+ return TypedData_Wrap_Struct(klass, &UM_SSL_Connection_type, connection);
55
+ }
56
+
57
+ VALUE UM_SSL_Connection_initialize(VALUE self, VALUE machine, VALUE fd, VALUE ctx) {
58
+ // struct um_ssl_connection *connection = RTYPEDDATA_DATA(self);
59
+
60
+ return self;
61
+ }
62
+
63
+ VALUE UM_SSL_check(VALUE self) {
64
+ return Qnil;
65
+ }
66
+
67
+ void Init_SSL(void) {
68
+ VALUE cUM = rb_define_class("UringMachine", rb_cObject);
69
+ VALUE cSSL = rb_define_module_under(cUM, "SSL");
70
+
71
+ cSSLConnection = rb_define_class_under(cSSL, "Connection", rb_cObject);
72
+ rb_define_alloc_func(cUM, UM_SSL_Connection_allocate);
73
+
74
+ rb_define_method(cSSLConnection, "initialize", UM_SSL_Connection_initialize, 3);
75
+
76
+ // cCtx = rb_define_class_under(cSSL, "SSLContext", rb_cObject);
77
+ // rb_define_alloc_func(cCtx, sslctx_alloc);
78
+ // rb_define_method(cCtx, "initialize", sslctx_initialize, 1);
79
+ // rb_undef_method(cCtx, "initialize_copy");
80
+
81
+ // OpenSSL Build / Runtime/Load versions
82
+
83
+ /* Version of OpenSSL that UringMachine was compiled with */
84
+ rb_define_const(cSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
85
+
86
+ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
87
+ /* Version of OpenSSL that UringMachine loaded with */
88
+ rb_define_const(cSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
89
+ #else
90
+ rb_define_const(cSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
91
+ #endif
92
+
93
+ #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
94
+ /* True if SSL3 is not available */
95
+ rb_define_const(cSSL, "OPENSSL_NO_SSL3", Qtrue);
96
+ #else
97
+ rb_define_const(cSSL, "OPENSSL_NO_SSL3", Qfalse);
98
+ #endif
99
+
100
+ #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
101
+ /* True if TLS1 is not available */
102
+ rb_define_const(cSSL, "OPENSSL_NO_TLS1", Qtrue);
103
+ #else
104
+ rb_define_const(cSSL, "OPENSSL_NO_TLS1", Qfalse);
105
+ #endif
106
+
107
+ #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
108
+ /* True if TLS1_1 is not available */
109
+ rb_define_const(cSSL, "OPENSSL_NO_TLS1_1", Qtrue);
110
+ #else
111
+ rb_define_const(cSSL, "OPENSSL_NO_TLS1_1", Qfalse);
112
+ #endif
113
+
114
+ rb_define_singleton_method(cSSL, "check", UM_SSL_check, 0);
115
+
116
+ eSSLError = rb_define_class_under(cSSL, "SSLError", rb_eStandardError);
117
+
118
+ // rb_define_singleton_method(cSSLConnection, "server", engine_init_server, 1);
119
+ // rb_define_singleton_method(cSSLConnection, "client", engine_init_client, 0);
120
+
121
+ // rb_define_method(cSSLConnection, "inject", engine_inject, 1);
122
+ // rb_define_method(cSSLConnection, "read", engine_read, 0);
123
+
124
+ // rb_define_method(cSSLConnection, "write", engine_write, 1);
125
+ // rb_define_method(cSSLConnection, "extract", engine_extract, 0);
126
+
127
+ // rb_define_method(cSSLConnection, "shutdown", engine_shutdown, 0);
128
+
129
+ // rb_define_method(cSSLConnection, "init?", engine_init, 0);
130
+
131
+ /* @!attribute [r] peercert
132
+ * Returns `nil` when `MiniSSL::Context#verify_mode` is set to `VERIFY_NONE`.
133
+ * @return [String, nil] DER encoded cert
134
+ */
135
+ // rb_define_method(cSSLConnection, "peercert", engine_peercert, 0);
136
+
137
+ // rb_define_method(cSSLConnection, "ssl_vers_st", engine_ssl_vers_st, 0);
138
+ }
@@ -0,0 +1,96 @@
1
+ module UringMachine
2
+ module SSL
3
+ class ContextBuilder
4
+ def initialize(params, log_writer)
5
+ @params = params
6
+ @log_writer = log_writer
7
+ end
8
+
9
+ def context
10
+ ctx = SSL::Context.new
11
+
12
+ if defined?(JRUBY_VERSION)
13
+ unless params['keystore']
14
+ log_writer.error "Please specify the Java keystore via 'keystore='"
15
+ end
16
+
17
+ ctx.keystore = params['keystore']
18
+
19
+ unless params['keystore-pass']
20
+ log_writer.error "Please specify the Java keystore password via 'keystore-pass='"
21
+ end
22
+
23
+ ctx.keystore_pass = params['keystore-pass']
24
+ ctx.keystore_type = params['keystore-type']
25
+
26
+ if truststore = params['truststore']
27
+ ctx.truststore = truststore.eql?('default') ? :default : truststore
28
+ ctx.truststore_pass = params['truststore-pass']
29
+ ctx.truststore_type = params['truststore-type']
30
+ end
31
+
32
+ ctx.cipher_suites = params['cipher_suites'] || params['ssl_cipher_list']
33
+ ctx.protocols = params['protocols'] if params['protocols']
34
+ else
35
+ if params['key'].nil? && params['key_pem'].nil?
36
+ log_writer.error "Please specify the SSL key via 'key=' or 'key_pem='"
37
+ end
38
+
39
+ ctx.key = params['key'] if params['key']
40
+ ctx.key_pem = params['key_pem'] if params['key_pem']
41
+ ctx.key_password_command = params['key_password_command'] if params['key_password_command']
42
+
43
+ if params['cert'].nil? && params['cert_pem'].nil?
44
+ log_writer.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
45
+ end
46
+
47
+ ctx.cert = params['cert'] if params['cert']
48
+ ctx.cert_pem = params['cert_pem'] if params['cert_pem']
49
+
50
+ if ['peer', 'force_peer'].include?(params['verify_mode'])
51
+ unless params['ca']
52
+ log_writer.error "Please specify the SSL ca via 'ca='"
53
+ end
54
+ # needed for UM::SSL::Socket#peercert, env['puma.peercert']
55
+ require 'openssl'
56
+ end
57
+
58
+ ctx.ca = params['ca'] if params['ca']
59
+ ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
60
+ ctx.ssl_ciphersuites = params['ssl_ciphersuites'] if params['ssl_ciphersuites'] && HAS_TLS1_3
61
+
62
+ ctx.reuse = params['reuse'] if params['reuse']
63
+ end
64
+
65
+ ctx.no_tlsv1 = params['no_tlsv1'] == 'true'
66
+ ctx.no_tlsv1_1 = params['no_tlsv1_1'] == 'true'
67
+
68
+ if params['verify_mode']
69
+ ctx.verify_mode = case params['verify_mode']
70
+ when "peer"
71
+ SSL::VERIFY_PEER
72
+ when "force_peer"
73
+ SSL::VERIFY_PEER | SSL::VERIFY_FAIL_IF_NO_PEER_CERT
74
+ when "none"
75
+ SSL::VERIFY_NONE
76
+ else
77
+ log_writer.error "Please specify a valid verify_mode="
78
+ SSL::VERIFY_NONE
79
+ end
80
+ end
81
+
82
+ if params['verification_flags']
83
+ ctx.verification_flags = params['verification_flags'].split(',').
84
+ map { |flag| SSL::VERIFICATION_FLAGS.fetch(flag) }.
85
+ inject { |sum, flag| sum ? sum | flag : flag }
86
+ end
87
+
88
+ ctx
89
+ end
90
+
91
+ private
92
+
93
+ attr_reader :params, :log_writer
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,394 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ # need for Puma::MiniSSL::OPENSSL constants used in `HAS_TLS1_3`
5
+ # use require, see https://github.com/puma/puma/pull/2381
6
+ # require 'puma/puma_http11'
7
+
8
+ require_relative '../uringmachine'
9
+
10
+ class UringMachine
11
+ module SSL
12
+ # Define constant at runtime, as it's easy to determine at built time,
13
+ # but Puma could (it shouldn't) be loaded with an older OpenSSL version
14
+ # @version 5.0.0
15
+ HAS_TLS1_3 =
16
+ ((OPENSSL_VERSION[/ \d+\.\d+\.\d+/].split('.').map(&:to_i) <=> [1,1,1]) != -1 &&
17
+ (OPENSSL_LIBRARY_VERSION[/ \d+\.\d+\.\d+/].split('.').map(&:to_i) <=> [1,1,1]) !=-1)
18
+
19
+ class Socket
20
+ def initialize(socket, engine)
21
+ @socket = socket
22
+ @engine = engine
23
+ @peercert = nil
24
+ @reuse = nil
25
+ end
26
+
27
+ # @!attribute [r] to_io
28
+ def to_io
29
+ @socket
30
+ end
31
+
32
+ def closed?
33
+ @socket.closed?
34
+ end
35
+
36
+ # Returns a two element array,
37
+ # first is protocol version (SSL_get_version),
38
+ # second is 'handshake' state (SSL_state_string)
39
+ #
40
+ # Used for dropping tcp connections to ssl.
41
+ # See OpenSSL ssl/ssl_stat.c SSL_state_string for info
42
+ # @!attribute [r] ssl_version_state
43
+ # @version 5.0.0
44
+ #
45
+ def ssl_version_state
46
+ @engine.ssl_vers_st
47
+ end
48
+
49
+ # Used to check the handshake status, in particular when a TCP connection
50
+ # is made with TLSv1.3 as an available protocol
51
+ # @version 5.0.0
52
+ def bad_tlsv1_3?
53
+ HAS_TLS1_3 && ssl_version_state == ['TLSv1.3', 'SSLERR']
54
+ end
55
+ private :bad_tlsv1_3?
56
+
57
+ def readpartial(size)
58
+ while true
59
+ output = @engine.read
60
+ return output if output
61
+
62
+ data = @socket.readpartial(size)
63
+ @engine.inject(data)
64
+ output = @engine.read
65
+
66
+ return output if output
67
+
68
+ while neg_data = @engine.extract
69
+ @socket.write neg_data
70
+ end
71
+ end
72
+ end
73
+
74
+ def engine_read_all
75
+ output = @engine.read
76
+ while output and additional_output = @engine.read
77
+ output << additional_output
78
+ end
79
+ output
80
+ end
81
+
82
+ def read_nonblock(size, *_)
83
+ # *_ is to deal with keyword args that were added
84
+ # at some point (and being used in the wild)
85
+ while true
86
+ output = engine_read_all
87
+ return output if output
88
+
89
+ data = @socket.read_nonblock(size, exception: false)
90
+ if data == :wait_readable || data == :wait_writable
91
+ # It would make more sense to let @socket.read_nonblock raise
92
+ # EAGAIN if necessary but it seems like it'll misbehave on Windows.
93
+ # I don't have a Windows machine to debug this so I can't explain
94
+ # exactly whats happening in that OS. Please let me know if you
95
+ # find out!
96
+ #
97
+ # In the meantime, we can emulate the correct behavior by
98
+ # capturing :wait_readable & :wait_writable and raising EAGAIN
99
+ # ourselves.
100
+ raise IO::EAGAINWaitReadable
101
+ elsif data.nil?
102
+ raise SSLError.exception "HTTP connection?" if bad_tlsv1_3?
103
+ return nil
104
+ end
105
+
106
+ @engine.inject(data)
107
+ output = engine_read_all
108
+
109
+ return output if output
110
+
111
+ while neg_data = @engine.extract
112
+ @socket.write neg_data
113
+ end
114
+ end
115
+ end
116
+
117
+ def write(data)
118
+ return 0 if data.empty?
119
+
120
+ data_size = data.bytesize
121
+ need = data_size
122
+
123
+ while true
124
+ wrote = @engine.write data
125
+
126
+ enc_wr = +''
127
+ while (enc = @engine.extract)
128
+ enc_wr << enc
129
+ end
130
+ @socket.write enc_wr unless enc_wr.empty?
131
+
132
+ need -= wrote
133
+
134
+ return data_size if need == 0
135
+
136
+ data = data.byteslice(wrote..-1)
137
+ end
138
+ end
139
+
140
+ alias_method :syswrite, :write
141
+ alias_method :<<, :write
142
+
143
+ # This is a temporary fix to deal with websockets code using
144
+ # write_nonblock.
145
+
146
+ # The problem with implementing it properly
147
+ # is that it means we'd have to have the ability to rewind
148
+ # an engine because after we write+extract, the socket
149
+ # write_nonblock call might raise an exception and later
150
+ # code would pass the same data in, but the engine would think
151
+ # it had already written the data in.
152
+ #
153
+ # So for the time being (and since write blocking is quite rare),
154
+ # go ahead and actually block in write_nonblock.
155
+ #
156
+ def write_nonblock(data, *_)
157
+ write data
158
+ end
159
+
160
+ def flush
161
+ @socket.flush
162
+ end
163
+
164
+ def close
165
+ begin
166
+ unless @engine.shutdown
167
+ while alert_data = @engine.extract
168
+ @socket.write alert_data
169
+ end
170
+ end
171
+ rescue IOError, SystemCallError
172
+ Puma::Util.purge_interrupt_queue
173
+ # nothing
174
+ ensure
175
+ @socket.close
176
+ end
177
+ end
178
+
179
+ # @!attribute [r] peeraddr
180
+ def peeraddr
181
+ @socket.peeraddr
182
+ end
183
+
184
+ # OpenSSL is loaded in `MicroSSL::ContextBuilder` when
185
+ # `MicroSSL::Context#verify_mode` is not `VERIFY_NONE`.
186
+ # When `VERIFY_NONE`, `MicroSSL::Engine#peercert` is nil, regardless of
187
+ # whether the client sends a cert.
188
+ # @return [OpenSSL::X509::Certificate, nil]
189
+ # @!attribute [r] peercert
190
+ def peercert
191
+ return @peercert if @peercert
192
+
193
+ raw = @engine.peercert
194
+ return nil unless raw
195
+
196
+ @peercert = OpenSSL::X509::Certificate.new raw
197
+ end
198
+ end
199
+
200
+ class Context
201
+ attr_accessor :verify_mode
202
+ attr_reader :no_tlsv1, :no_tlsv1_1
203
+
204
+ def initialize
205
+ @no_tlsv1 = false
206
+ @no_tlsv1_1 = false
207
+ @key = nil
208
+ @cert = nil
209
+ @key_pem = nil
210
+ @cert_pem = nil
211
+ @reuse = nil
212
+ @reuse_cache_size = nil
213
+ @reuse_timeout = nil
214
+ end
215
+
216
+ def check_file(file, desc)
217
+ raise ArgumentError, "#{desc} file '#{file}' does not exist" unless File.exist? file
218
+ raise ArgumentError, "#{desc} file '#{file}' is not readable" unless File.readable? file
219
+ end
220
+
221
+ # non-jruby Context properties
222
+ attr_reader :key
223
+ attr_reader :key_password_command
224
+ attr_reader :cert
225
+ attr_reader :ca
226
+ attr_reader :cert_pem
227
+ attr_reader :key_pem
228
+ attr_accessor :ssl_cipher_filter
229
+ attr_accessor :ssl_ciphersuites
230
+ attr_accessor :verification_flags
231
+
232
+ attr_reader :reuse, :reuse_cache_size, :reuse_timeout
233
+
234
+ def key=(key)
235
+ check_file key, 'Key'
236
+ @key = key
237
+ end
238
+
239
+ def key_password_command=(key_password_command)
240
+ @key_password_command = key_password_command
241
+ end
242
+
243
+ def cert=(cert)
244
+ check_file cert, 'Cert'
245
+ @cert = cert
246
+ end
247
+
248
+ def ca=(ca)
249
+ check_file ca, 'ca'
250
+ @ca = ca
251
+ end
252
+
253
+ def cert_pem=(cert_pem)
254
+ raise ArgumentError, "'cert_pem' is not a String" unless cert_pem.is_a? String
255
+ @cert_pem = cert_pem
256
+ end
257
+
258
+ def key_pem=(key_pem)
259
+ raise ArgumentError, "'key_pem' is not a String" unless key_pem.is_a? String
260
+ @key_pem = key_pem
261
+ end
262
+
263
+ def check
264
+ raise "Key not configured" if @key.nil? && @key_pem.nil?
265
+ raise "Cert not configured" if @cert.nil? && @cert_pem.nil?
266
+ end
267
+
268
+ # Executes the command to return the password needed to decrypt the key.
269
+ def key_password
270
+ raise "Key password command not configured" if @key_password_command.nil?
271
+
272
+ stdout_str, stderr_str, status = Open3.capture3(@key_password_command)
273
+
274
+ return stdout_str.chomp if status.success?
275
+
276
+ raise "Key password failed with code #{status.exitstatus}: #{stderr_str}"
277
+ end
278
+
279
+ # Controls session reuse. Allowed values are as follows:
280
+ # * 'off' - matches the behavior of Puma 5.6 and earlier. This is included
281
+ # in case reuse 'on' is made the default in future Puma versions.
282
+ # * 'dflt' - sets session reuse on, with OpenSSL default cache size of
283
+ # 20k and default timeout of 300 seconds.
284
+ # * 's,t' - where s and t are integer strings, for size and timeout.
285
+ # * 's' - where s is an integer strings for size.
286
+ # * ',t' - where t is an integer strings for timeout.
287
+ #
288
+ def reuse=(reuse_str)
289
+ case reuse_str
290
+ when 'off'
291
+ @reuse = nil
292
+ when 'dflt'
293
+ @reuse = true
294
+ when /\A\d+\z/
295
+ @reuse = true
296
+ @reuse_cache_size = reuse_str.to_i
297
+ when /\A\d+,\d+\z/
298
+ @reuse = true
299
+ size, time = reuse_str.split ','
300
+ @reuse_cache_size = size.to_i
301
+ @reuse_timeout = time.to_i
302
+ when /\A,\d+\z/
303
+ @reuse = true
304
+ @reuse_timeout = reuse_str.delete(',').to_i
305
+ end
306
+ end
307
+ end
308
+
309
+ # disables TLSv1
310
+ # @!attribute [w] no_tlsv1=
311
+ def no_tlsv1=(tlsv1)
312
+ raise ArgumentError, "Invalid value of no_tlsv1=" unless ['true', 'false', true, false].include?(tlsv1)
313
+ @no_tlsv1 = tlsv1
314
+ end
315
+
316
+ # disables TLSv1 and TLSv1.1. Overrides `#no_tlsv1=`
317
+ # @!attribute [w] no_tlsv1_1=
318
+ def no_tlsv1_1=(tlsv1_1)
319
+ raise ArgumentError, "Invalid value of no_tlsv1_1=" unless ['true', 'false', true, false].include?(tlsv1_1)
320
+ @no_tlsv1_1 = tlsv1_1
321
+ end
322
+
323
+ VERIFY_NONE = 0
324
+ VERIFY_PEER = 1
325
+ VERIFY_FAIL_IF_NO_PEER_CERT = 2
326
+
327
+ # https://github.com/openssl/openssl/blob/master/include/openssl/x509_vfy.h.in
328
+ # /* Certificate verify flags */
329
+ VERIFICATION_FLAGS = {
330
+ "USE_CHECK_TIME" => 0x2,
331
+ "CRL_CHECK" => 0x4,
332
+ "CRL_CHECK_ALL" => 0x8,
333
+ "IGNORE_CRITICAL" => 0x10,
334
+ "X509_STRICT" => 0x20,
335
+ "ALLOW_PROXY_CERTS" => 0x40,
336
+ "POLICY_CHECK" => 0x80,
337
+ "EXPLICIT_POLICY" => 0x100,
338
+ "INHIBIT_ANY" => 0x200,
339
+ "INHIBIT_MAP" => 0x400,
340
+ "NOTIFY_POLICY" => 0x800,
341
+ "EXTENDED_CRL_SUPPORT" => 0x1000,
342
+ "USE_DELTAS" => 0x2000,
343
+ "CHECK_SS_SIGNATURE" => 0x4000,
344
+ "TRUSTED_FIRST" => 0x8000,
345
+ "SUITEB_128_LOS_ONLY" => 0x10000,
346
+ "SUITEB_192_LOS" => 0x20000,
347
+ "SUITEB_128_LOS" => 0x30000,
348
+ "PARTIAL_CHAIN" => 0x80000,
349
+ "NO_ALT_CHAINS" => 0x100000,
350
+ "NO_CHECK_TIME" => 0x200000
351
+ }.freeze
352
+
353
+ class Server
354
+ def initialize(socket, ctx)
355
+ @socket = socket
356
+ @ctx = ctx
357
+ @eng_ctx = IS_JRUBY ? @ctx : SSLContext.new(ctx)
358
+ end
359
+
360
+ def accept
361
+ @ctx.check
362
+ io = @socket.accept
363
+ engine = Engine.server @eng_ctx
364
+ Socket.new io, engine
365
+ end
366
+
367
+ def accept_nonblock
368
+ @ctx.check
369
+ io = @socket.accept_nonblock
370
+ engine = Engine.server @eng_ctx
371
+ Socket.new io, engine
372
+ end
373
+
374
+ # @!attribute [r] to_io
375
+ def to_io
376
+ @socket
377
+ end
378
+
379
+ # @!attribute [r] addr
380
+ # @version 5.0.0
381
+ def addr
382
+ @socket.addr
383
+ end
384
+
385
+ def close
386
+ @socket.close unless @socket.closed? # closed? call is for Windows
387
+ end
388
+
389
+ def closed?
390
+ @socket.closed?
391
+ end
392
+ end
393
+ end
394
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UringMachine
4
- VERSION = '0.5'
4
+ VERSION = '0.5.1'
5
5
  end
data/lib/uringmachine.rb CHANGED
@@ -8,6 +8,10 @@ UM = UringMachine
8
8
  class UringMachine
9
9
  @@fiber_map = {}
10
10
 
11
+ def fiber_map
12
+ @@fiber_map
13
+ end
14
+
11
15
  def spin(value = nil, &block)
12
16
  f = Fiber.new do |resume_value|
13
17
  block.(resume_value)
@@ -30,4 +34,8 @@ class UringMachine
30
34
  @resolver ||= DNSResolver.new(self)
31
35
  @resolver.resolve(hostname, type)
32
36
  end
37
+
38
+ def ssl_accept(fd, ssl_ctx)
39
+ SSL::Connection.new(self, fd, ssl_ctx)
40
+ end
33
41
  end
data/test/helper.rb CHANGED
@@ -51,6 +51,12 @@ module Minitest::Assertions
51
51
  end
52
52
 
53
53
  class UMBaseTest < Minitest::Test
54
+ # pull in UM constants
55
+ UM.constants.each do |c|
56
+ v = UM.const_get(c)
57
+ const_set(c, v) if v.is_a?(Integer)
58
+ end
59
+
54
60
  attr_accessor :machine
55
61
 
56
62
  def setup