raktr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE.md +29 -0
  4. data/README.md +77 -0
  5. data/Rakefile +53 -0
  6. data/lib/raktr/connection/callbacks.rb +71 -0
  7. data/lib/raktr/connection/error.rb +120 -0
  8. data/lib/raktr/connection/peer_info.rb +90 -0
  9. data/lib/raktr/connection/tls.rb +164 -0
  10. data/lib/raktr/connection.rb +339 -0
  11. data/lib/raktr/global.rb +24 -0
  12. data/lib/raktr/iterator.rb +249 -0
  13. data/lib/raktr/queue.rb +89 -0
  14. data/lib/raktr/tasks/base.rb +57 -0
  15. data/lib/raktr/tasks/delayed.rb +33 -0
  16. data/lib/raktr/tasks/one_off.rb +30 -0
  17. data/lib/raktr/tasks/periodic.rb +58 -0
  18. data/lib/raktr/tasks/persistent.rb +29 -0
  19. data/lib/raktr/tasks.rb +105 -0
  20. data/lib/raktr/version.rb +13 -0
  21. data/lib/raktr.rb +707 -0
  22. data/spec/raktr/connection/tls_spec.rb +348 -0
  23. data/spec/raktr/connection_spec.rb +74 -0
  24. data/spec/raktr/iterator_spec.rb +203 -0
  25. data/spec/raktr/queue_spec.rb +91 -0
  26. data/spec/raktr/tasks/base.rb +8 -0
  27. data/spec/raktr/tasks/delayed_spec.rb +71 -0
  28. data/spec/raktr/tasks/one_off_spec.rb +66 -0
  29. data/spec/raktr/tasks/periodic_spec.rb +57 -0
  30. data/spec/raktr/tasks/persistent_spec.rb +54 -0
  31. data/spec/raktr/tasks_spec.rb +155 -0
  32. data/spec/raktr_spec.rb +20 -0
  33. data/spec/raktr_tls_spec.rb +20 -0
  34. data/spec/spec_helper.rb +17 -0
  35. data/spec/support/fixtures/handlers/echo_client.rb +34 -0
  36. data/spec/support/fixtures/handlers/echo_client_tls.rb +10 -0
  37. data/spec/support/fixtures/handlers/echo_server.rb +12 -0
  38. data/spec/support/fixtures/handlers/echo_server_tls.rb +8 -0
  39. data/spec/support/fixtures/pems/cacert.pem +37 -0
  40. data/spec/support/fixtures/pems/client/cert.pem +37 -0
  41. data/spec/support/fixtures/pems/client/foo-cert.pem +39 -0
  42. data/spec/support/fixtures/pems/client/foo-key.pem +51 -0
  43. data/spec/support/fixtures/pems/client/key.pem +51 -0
  44. data/spec/support/fixtures/pems/server/cert.pem +37 -0
  45. data/spec/support/fixtures/pems/server/key.pem +51 -0
  46. data/spec/support/helpers/paths.rb +23 -0
  47. data/spec/support/helpers/utilities.rb +135 -0
  48. data/spec/support/lib/server_option_parser.rb +29 -0
  49. data/spec/support/lib/servers/runner.rb +13 -0
  50. data/spec/support/lib/servers.rb +133 -0
  51. data/spec/support/servers/echo.rb +14 -0
  52. data/spec/support/servers/echo_tls.rb +22 -0
  53. data/spec/support/servers/echo_unix.rb +14 -0
  54. data/spec/support/servers/echo_unix_tls.rb +22 -0
  55. data/spec/support/shared/connection.rb +696 -0
  56. data/spec/support/shared/raktr.rb +834 -0
  57. data/spec/support/shared/task.rb +21 -0
  58. metadata +140 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2aa060f18df13540e73b42a5e9c68bdf86eaf03ae21104da0e827e57252dffe3
4
+ data.tar.gz: 5f1dd3fa7626e764f5212424c8e25b26a16bb52d4d00a2d2e6e4e5684575123a
5
+ SHA512:
6
+ metadata.gz: 8889f36f41d78a38dbd5afb95af6f4c2836e2056bb00451dabb10141c19d34c1ce02a7809c54e3c807713ab0b3bb94e6d969eb423878ab2c8514db703c868f85
7
+ data.tar.gz: fa3426f952f1980e9916aeaa1af050da734fec2c8de94a8e352c5223271e4309f66abd9fba46399d5470394ad9b4d65801620c4b060e9b4db1c0775d23a8859e
data/CHANGELOG.md ADDED
@@ -0,0 +1 @@
1
+ # ChangeLog
data/LICENSE.md ADDED
@@ -0,0 +1,29 @@
1
+ # License
2
+
3
+ Copyright (C) 2022, Ecsypno <https://ecsypno.com/>
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without modification,
7
+ are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice,
10
+ this list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its contributors
17
+ may be used to endorse or promote products derived from this software
18
+ without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
24
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # Raktr
2
+
3
+ <table>
4
+ <tr>
5
+ <th>Version</th>
6
+ <td>0.0.1</td>
7
+ </tr>
8
+ <tr>
9
+ <th>Github page</th>
10
+ <td><a href="http://github.com/qadron/raktr">http://github.com/qadron/raktr</a></td>
11
+ <tr/>
12
+ <tr>
13
+ <th>Code Documentation</th>
14
+ <td><a href="http://rubydoc.info/github/qadron/raktr/">http://rubydoc.info/github/qadron/raktr/</a></td>
15
+ </tr>
16
+ <tr>
17
+ <th>Author</th>
18
+ <td><a href="http://twitter.com/Zap0tek">Tasos Laskos</a></td>
19
+ </tr>
20
+ <tr>
21
+ <th>Copyright</th>
22
+ <td>2022 <a href="https://ecsypno.com">Ecsypno</a></td>
23
+ </tr>
24
+ <tr>
25
+ <th>License</th>
26
+ <td><a href="file.LICENSE.html">3-clause BSD</a></td>
27
+ </tr>
28
+ </table>
29
+
30
+ ## Synopsis
31
+
32
+ Raktr is a simple, lightweight, pure-Ruby implementation of the
33
+ [Reactor](http://en.wikipedia.org/wiki/Reactor_pattern) pattern, mainly focused
34
+ on network connections -- and less so on generic tasks.
35
+
36
+ ## Features
37
+
38
+ - Extremely lightweight.
39
+ - Very simple design.
40
+ - Support for TCP/IP and UNIX-domain sockets.
41
+ - TLS encryption.
42
+ - Pure-Ruby.
43
+ - Multi-platform.
44
+
45
+ ## Supported platforms
46
+
47
+ - Rubies:
48
+ - MRI >= 1.9
49
+ - Rubinius
50
+ - JRuby
51
+ - Operating Systems:
52
+ - Linux
53
+ - OSX
54
+ - Windows
55
+
56
+ ## Examples
57
+
58
+ For examples please see the `examples/` directory.
59
+
60
+ ## Installation
61
+
62
+ gem install raktr
63
+
64
+ ## Running the Specs
65
+
66
+ rake spec
67
+
68
+ ## Bug reports/Feature requests
69
+
70
+ Please send your feedback using GitHub's issue system at
71
+ [http://github.com/qadron/raktr/issues](http://github.com/qadron/raktr/issues).
72
+
73
+
74
+ ## License
75
+
76
+ Raktr is provided under the 3-clause BSD license.
77
+ See the [LICENSE](https://github.com/qadron/raktr/blob/master/LICENSE.md) file for more information.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ =begin
2
+
3
+ This file is part of the Raktr project and may be subject to
4
+ redistribution and commercial restrictions. Please see the Raktr
5
+ web site for more information on licensing and terms of use.
6
+
7
+ =end
8
+
9
+ require 'rubygems'
10
+ require File.expand_path( File.dirname( __FILE__ ) ) + '/lib/raktr/version'
11
+
12
+ begin
13
+ require 'rspec'
14
+ require 'rspec/core/rake_task'
15
+
16
+ RSpec::Core::RakeTask.new
17
+ rescue
18
+ end
19
+
20
+ task default: [ :build, :spec ]
21
+
22
+ desc 'Generate docs'
23
+ task :docs do
24
+ outdir = '../raktr-docs'
25
+ sh "rm -rf #{outdir}"
26
+ sh "mkdir -p #{outdir}"
27
+
28
+ sh "yardoc -o #{outdir}"
29
+
30
+ sh 'rm -rf .yardoc'
31
+ end
32
+
33
+ desc 'Clean up'
34
+ task :clean do
35
+ sh 'rm *.gem || true'
36
+ end
37
+
38
+ desc 'Build the gem.'
39
+ task build: [ :clean ] do
40
+ sh "gem build raktr.gemspec"
41
+ end
42
+
43
+ desc 'Build and install the gem.'
44
+ task install: [ :build ] do
45
+ sh "gem install raktr-#{Raktr::VERSION}.gem"
46
+ end
47
+
48
+ desc 'Push a new version to Rubygems'
49
+ task publish: [ :build ] do
50
+ sh "git tag -a v#{Raktr::VERSION} -m 'Version #{Raktr::VERSION}'"
51
+ sh "gem push raktr-#{Raktr::VERSION}.gem"
52
+ end
53
+ task release: [ :publish ]
@@ -0,0 +1,71 @@
1
+ =begin
2
+
3
+ This file is part of the Raktr project and may be subject to
4
+ redistribution and commercial restrictions. Please see the Raktr
5
+ web site for more information on licensing and terms of use.
6
+
7
+ =end
8
+
9
+ class Raktr
10
+ class Connection
11
+
12
+ # Callbacks to be invoked per event.
13
+ #
14
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
15
+ module Callbacks
16
+
17
+ # Called after the connection has been established.
18
+ #
19
+ # @abstract
20
+ def on_connect
21
+ end
22
+
23
+ # Called after the connection has been attached to a {#raktr}.
24
+ #
25
+ # @abstract
26
+ def on_attach
27
+ end
28
+
29
+ # Called right the connection is detached from the {#raktr}.
30
+ #
31
+ # @abstract
32
+ def on_detach
33
+ end
34
+
35
+ # @note If a connection could not be established no {#socket} may be
36
+ # available.
37
+ #
38
+ # Called when the connection gets closed.
39
+ #
40
+ # @param [Exception] reason
41
+ # Reason for the close.
42
+ #
43
+ # @abstract
44
+ def on_close( reason )
45
+ end
46
+
47
+ # Called when data are available.
48
+ #
49
+ # @param [String] data
50
+ # Incoming data.
51
+ #
52
+ # @abstract
53
+ def on_read( data )
54
+ end
55
+
56
+ # Called after each {#write} call.
57
+ #
58
+ # @abstract
59
+ def on_write
60
+ end
61
+
62
+ # Called after the {#write buffered data} have all been sent to the peer.
63
+ #
64
+ # @abstract
65
+ def on_flush
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,120 @@
1
+ =begin
2
+
3
+ This file is part of the Raktr project and may be subject to
4
+ redistribution and commercial restrictions. Please see the Raktr
5
+ web site for more information on licensing and terms of use.
6
+
7
+ =end
8
+
9
+ class Raktr
10
+ class Connection
11
+
12
+ # {Connection} error namespace.
13
+ #
14
+ # All {Connection} errors inherit from and live under it.
15
+ #
16
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
17
+ class Error < Raktr::Error
18
+
19
+ class << self
20
+ # Captures Ruby exceptions and converts them to an appropriate
21
+ # subclass of {Error}.
22
+ #
23
+ # @param [Block] block Block to run.
24
+ def translate( &block )
25
+ block.call
26
+ rescue IOError, Errno::ENOTCONN, Errno::ENOTSOCK => e
27
+ raise_with_proper_backtrace( e, Closed )
28
+ rescue SocketError, Errno::ENOENT => e
29
+ raise_with_proper_backtrace( e, HostNotFound )
30
+ rescue Errno::EPIPE => e
31
+ raise_with_proper_backtrace( e, BrokenPipe )
32
+ rescue Errno::ECONNREFUSED,
33
+ # JRuby throws Errno::EADDRINUSE when trying to connect to a
34
+ # non-existent server.
35
+ Errno::EADDRINUSE => e
36
+ raise_with_proper_backtrace( e, Refused )
37
+ rescue Errno::ECONNRESET, Errno::ECONNABORTED => e
38
+ raise_with_proper_backtrace( e, Reset )
39
+ rescue Errno::EACCES => e
40
+ raise_with_proper_backtrace( e, Permission )
41
+ rescue Errno::EBADF => e
42
+ raise_with_proper_backtrace( e, BadSocket )
43
+
44
+ # Catch and forward these before handling OpenSSL::OpenSSLError because
45
+ # all SSL errors inherit from it, including OpenSSL::SSL::SSLErrorWaitReadable
46
+ # and OpenSSL::SSL::SSLErrorWaitWritable which also inherit from
47
+ # IO::WaitReadable and IO::WaitWritable and need special treatment.
48
+ rescue IO::WaitReadable, IO::WaitWritable, Errno::EINPROGRESS
49
+ raise
50
+
51
+ # We're mainly interested in translating SSL handshake errors but there
52
+ # aren't any specific exceptions for these.
53
+ #
54
+ # Why make things easy and clean, right?
55
+ rescue OpenSSL::SSL::SSLError, OpenSSL::OpenSSLError => e
56
+ raise_with_proper_backtrace( e, SSL )
57
+ end
58
+
59
+ def raise_with_proper_backtrace( ruby, raktr )
60
+ e = raktr.new( ruby.to_s )
61
+ e.set_backtrace ruby.backtrace
62
+ raise e
63
+ end
64
+ end
65
+
66
+ # Like a `SocketError.getaddrinfo` exception.
67
+ #
68
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
69
+ class HostNotFound < Error
70
+ end
71
+
72
+ # Like a `Errno::EACCES` exception.
73
+ #
74
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
75
+ class Permission < Error
76
+ end
77
+
78
+ # Like a `Errno::ECONNREFUSED` exception.
79
+ #
80
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
81
+ class Refused < Error
82
+ end
83
+
84
+ # Like a `Errno::ECONNRESET` exception.
85
+ #
86
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
87
+ class Reset < Error
88
+ end
89
+
90
+ # Like a `Errno::EPIPE` exception.
91
+ #
92
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
93
+ class BrokenPipe < Error
94
+ end
95
+
96
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
97
+ class Timeout < Error
98
+ end
99
+
100
+ # Like a `IOError` exception.
101
+ #
102
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
103
+ class Closed < Error
104
+ end
105
+
106
+ # Like a `Errno::EBADF` exception.
107
+ #
108
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
109
+ class BadSocket < Error
110
+ end
111
+
112
+ # Like a `OpenSSL::OpenSSLError` exception.
113
+ #
114
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
115
+ class SSL < Error
116
+ end
117
+
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,90 @@
1
+ =begin
2
+
3
+ This file is part of the Raktr project and may be subject to
4
+ redistribution and commercial restrictions. Please see the Raktr
5
+ web site for more information on licensing and terms of use.
6
+
7
+ =end
8
+
9
+ class Raktr
10
+ class Connection
11
+
12
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
13
+ module PeerInfo
14
+
15
+ # @param [Bool] resolve
16
+ # Resolve IP address to hostname.
17
+ # @return [Hash]
18
+ # Peer address information:
19
+ #
20
+ # * IP socket:
21
+ # * Without `resolve`:
22
+ #
23
+ # {
24
+ # protocol: 'AF_INET',
25
+ # port: 10314,
26
+ # hostname: '127.0.0.1',
27
+ # ip_address: '127.0.0.1'
28
+ # }
29
+ #
30
+ # * With `resolve`:
31
+ #
32
+ # {
33
+ # protocol: 'AF_INET',
34
+ # port: 10314,
35
+ # hostname: 'localhost',
36
+ # ip_address: '127.0.0.1'
37
+ # }
38
+ #
39
+ # * UNIX-domain socket:
40
+ #
41
+ # {
42
+ # protocol: 'AF_UNIX',
43
+ # path: '/tmp/my-socket'
44
+ # }
45
+ def peer_address_info( resolve = false )
46
+ if Raktr.supports_unix_sockets? && to_io.is_a?( UNIXSocket )
47
+ {
48
+ protocol: to_io.peeraddr.first,
49
+ path: to_io.path
50
+ }
51
+ else
52
+ protocol, port, hostname, ip_address = to_io.peeraddr( resolve )
53
+
54
+ {
55
+ protocol: protocol,
56
+ port: port,
57
+ hostname: hostname,
58
+ ip_address: ip_address
59
+ }
60
+ end
61
+ end
62
+
63
+ # @return [String]
64
+ # Peer's IP address or socket path.
65
+ def peer_address
66
+ peer_ip_address || peer_address_info[:path]
67
+ end
68
+
69
+ # @return [String]
70
+ # Peer's IP address.
71
+ def peer_ip_address
72
+ peer_address_info[:ip_address]
73
+ end
74
+
75
+ # @return [String]
76
+ # Peer's hostname.
77
+ def peer_hostname
78
+ peer_address_info(true)[:hostname]
79
+ end
80
+
81
+ # @return [String]
82
+ # Peer's port.
83
+ def peer_port
84
+ peer_address_info[:port]
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,164 @@
1
+ =begin
2
+
3
+ This file is part of the Raktr project and may be subject to
4
+ redistribution and commercial restrictions. Please see the Raktr
5
+ web site for more information on licensing and terms of use.
6
+
7
+ =end
8
+
9
+ class Raktr
10
+ class Connection
11
+
12
+ # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
13
+ module TLS
14
+
15
+ # Converts the {#socket} to an SSL one.
16
+ #
17
+ # @param [Hash] options
18
+ # @option [String] :certificate
19
+ # Path to a PEM certificate.
20
+ # @option [String] :private_key
21
+ # Path to a PEM private key.
22
+ # @option [String] :ca
23
+ # Path to a PEM CA.
24
+ def start_tls( options = {} )
25
+ if @socket.is_a? OpenSSL::SSL::SSLSocket
26
+ @ssl_context = @socket.context
27
+ return
28
+ end
29
+
30
+ @ssl_context = OpenSSL::SSL::SSLContext.new
31
+ @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
32
+
33
+ if options[:certificate] && options[:private_key]
34
+
35
+ @ssl_context.cert =
36
+ OpenSSL::X509::Certificate.new( File.open( options[:certificate] ) )
37
+ @ssl_context.key =
38
+ OpenSSL::PKey::RSA.new( File.open( options[:private_key] ) )
39
+
40
+ @ssl_context.ca_file = options[:ca]
41
+ @ssl_context.verify_mode =
42
+ OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
43
+
44
+ elsif @role == :server
45
+ @ssl_context.key = OpenSSL::PKey::RSA.new( 2048 )
46
+ @ssl_context.cert = OpenSSL::X509::Certificate.new
47
+ @ssl_context.cert.subject = OpenSSL::X509::Name.new( [['CN', 'localhost']] )
48
+ @ssl_context.cert.issuer = @ssl_context.cert.subject
49
+ @ssl_context.cert.public_key = @ssl_context.key
50
+ @ssl_context.cert.not_before = Time.now
51
+ @ssl_context.cert.not_after = Time.now + 60 * 60 * 24
52
+ @ssl_context.cert.version = 2
53
+ @ssl_context.cert.serial = 1
54
+
55
+ @ssl_context.cert.sign( @ssl_context.key, OpenSSL::Digest::SHA1.new )
56
+ end
57
+
58
+ if @role == :server
59
+ @socket = OpenSSL::SSL::SSLServer.new( @socket, @ssl_context )
60
+ else
61
+ @socket = OpenSSL::SSL::SSLSocket.new( @socket, @ssl_context )
62
+ @socket.sync_close = true
63
+
64
+ # We've switched to SSL, a connection needs to be re-established
65
+ # via the SSL handshake.
66
+ @connected = false
67
+
68
+ _connect if unix?
69
+ end
70
+
71
+ @socket
72
+ end
73
+
74
+ # Performs an SSL handshake in addition to a plaintext connect operation.
75
+ #
76
+ # @private
77
+ def _connect
78
+ return if @ssl_connected
79
+
80
+ Error.translate do
81
+ @plaintext_connected ||= super
82
+ return if !@plaintext_connected
83
+
84
+ # Mark the connection as not connected due to the pending SSL handshake.
85
+ @connected = false
86
+
87
+ @socket.connect_nonblock
88
+ @ssl_connected = @connected = true
89
+ end
90
+ rescue IO::WaitReadable, IO::WaitWritable, Errno::EINPROGRESS
91
+ rescue Error => e
92
+ close e
93
+ end
94
+
95
+ # First checks if there's a pending SSL #accept operation when this
96
+ # connection is a server handler which has been passed an accepted
97
+ # plaintext connection.
98
+ #
99
+ # @private
100
+ def _write( *args )
101
+ return ssl_accept if accept?
102
+
103
+ super( *args )
104
+ end
105
+
106
+ # First checks if there's a pending SSL #accept operation when this
107
+ # connection is a server handler which has been passed an accepted
108
+ # plaintext connection.
109
+ #
110
+ # @private
111
+ def _read
112
+ return ssl_accept if accept?
113
+
114
+ super
115
+ rescue OpenSSL::SSL::SSLErrorWaitReadable
116
+ end
117
+
118
+ private
119
+
120
+ def ssl_accept
121
+ Error.translate do
122
+ @accepted = !!@socket.accept_nonblock
123
+ end
124
+ rescue IO::WaitReadable, IO::WaitWritable
125
+ rescue Error => e
126
+ close e
127
+ false
128
+ end
129
+
130
+ def accept?
131
+ return false if @accepted
132
+ return false if role != :server || !@socket.is_a?( OpenSSL::SSL::SSLSocket )
133
+
134
+ true
135
+ end
136
+
137
+ # Accepts a new SSL client connection.
138
+ #
139
+ # @return [OpenSSL::SSL::SSLSocket, nil]
140
+ # New connection or `nil` if the socket isn't ready to accept new
141
+ # connections yet.
142
+ #
143
+ # @private
144
+ def socket_accept
145
+ Error.translate do
146
+ socket = to_io.accept_nonblock
147
+
148
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(
149
+ socket,
150
+ @ssl_context
151
+ )
152
+ ssl_socket.sync_close = true
153
+ ssl.accept if @start_immediately
154
+ ssl_socket
155
+ end
156
+ rescue IO::WaitReadable, IO::WaitWritable
157
+ rescue Error => e
158
+ close e
159
+ end
160
+
161
+ end
162
+
163
+ end
164
+ end