drab 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: false
2
+ module DRab
3
+ class DRabObject # :nodoc:
4
+ def ==(other)
5
+ return false unless DRabObject === other
6
+ (@ref == other.__drabref) && (@uri == other.__draburi)
7
+ end
8
+
9
+ def hash
10
+ [@uri, @ref].hash
11
+ end
12
+
13
+ alias eql? ==
14
+ end
15
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: false
2
+ =begin
3
+ external service
4
+ Copyright (c) 2000,2002 Masatoshi SEKI
5
+ =end
6
+
7
+ require 'drab/drab'
8
+ require 'monitor'
9
+
10
+ module DRab
11
+ class ExtServ
12
+ include MonitorMixin
13
+ include DRabUndumped
14
+
15
+ def initialize(there, name, server=nil)
16
+ super()
17
+ @server = server || DRab::primary_server
18
+ @name = name
19
+ ro = DRabObject.new(nil, there)
20
+ synchronize do
21
+ @invoker = ro.regist(name, DRabObject.new(self, @server.uri))
22
+ end
23
+ end
24
+ attr_reader :server
25
+
26
+ def front
27
+ DRabObject.new(nil, @server.uri)
28
+ end
29
+
30
+ def stop_service
31
+ synchronize do
32
+ @invoker.unregist(@name)
33
+ server = @server
34
+ @server = nil
35
+ server.stop_service
36
+ true
37
+ end
38
+ end
39
+
40
+ def alive?
41
+ @server ? @server.alive? : false
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: false
2
+ =begin
3
+ external service manager
4
+ Copyright (c) 2000 Masatoshi SEKI
5
+ =end
6
+
7
+ require 'drab/drab'
8
+ require 'thread'
9
+ require 'monitor'
10
+
11
+ module DRab
12
+ class ExtServManager
13
+ include DRabUndumped
14
+ include MonitorMixin
15
+
16
+ @@command = {}
17
+
18
+ def self.command
19
+ @@command
20
+ end
21
+
22
+ def self.command=(cmd)
23
+ @@command = cmd
24
+ end
25
+
26
+ def initialize
27
+ super()
28
+ @cond = new_cond
29
+ @servers = {}
30
+ @waiting = []
31
+ @queue = Thread::Queue.new
32
+ @thread = invoke_thread
33
+ @uri = nil
34
+ end
35
+ attr_accessor :uri
36
+
37
+ def service(name)
38
+ synchronize do
39
+ while true
40
+ server = @servers[name]
41
+ return server if server&.alive?
42
+ invoke_service(name)
43
+ @cond.wait
44
+ end
45
+ end
46
+ end
47
+
48
+ def regist(name, ro)
49
+ synchronize do
50
+ @servers[name] = ro
51
+ @cond.signal
52
+ end
53
+ self
54
+ end
55
+
56
+ def unregist(name)
57
+ synchronize do
58
+ @servers.delete(name)
59
+ end
60
+ end
61
+
62
+ private
63
+ def invoke_thread
64
+ Thread.new do
65
+ while true
66
+ name = @queue.pop
67
+ invoke_service_command(name, @@command[name])
68
+ end
69
+ end
70
+ end
71
+
72
+ def invoke_service(name)
73
+ @queue.push(name)
74
+ end
75
+
76
+ def invoke_service_command(name, command)
77
+ raise "invalid command. name: #{name}" unless command
78
+ synchronize do
79
+ return if @servers.include?(name)
80
+ @servers[name] = false
81
+ end
82
+ uri = @uri || DRab.uri
83
+ if command.respond_to? :to_ary
84
+ command = command.to_ary + [uri, name]
85
+ pid = spawn(*command)
86
+ else
87
+ pid = spawn("#{command} #{uri} #{name}")
88
+ end
89
+ th = Process.detach(pid)
90
+ th[:drab_service] = name
91
+ th
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: false
2
+ require 'drab/drab'
3
+ require 'monitor'
4
+
5
+ module DRab
6
+
7
+ # Gateway id conversion forms a gateway between different DRab protocols or
8
+ # networks.
9
+ #
10
+ # The gateway needs to install this id conversion and create servers for
11
+ # each of the protocols or networks it will be a gateway between. It then
12
+ # needs to create a server that attaches to each of these networks. For
13
+ # example:
14
+ #
15
+ # require 'drab'
16
+ # require 'unix'
17
+ # require 'drab/gw'
18
+ #
19
+ # DRab.install_id_conv DRab::GWIdConv.new
20
+ # gw = DRab::GW.new
21
+ # s1 = DRab::DRabServer.new 'drabunix:/path/to/gateway', gw
22
+ # s2 = DRab::DRabServer.new 'druby://example:10000', gw
23
+ #
24
+ # s1.thread.join
25
+ # s2.thread.join
26
+ #
27
+ # Each client must register services with the gateway, for example:
28
+ #
29
+ # DRab.start_service 'drabunix:', nil # an anonymous server
30
+ # gw = DRabObject.new nil, 'drabunix:/path/to/gateway'
31
+ # gw[:unix] = some_service
32
+ # DRab.thread.join
33
+
34
+ class GWIdConv < DRabIdConv
35
+ def to_obj(ref) # :nodoc:
36
+ if Array === ref && ref[0] == :DRabObject
37
+ return DRabObject.new_with(ref[1], ref[2])
38
+ end
39
+ super(ref)
40
+ end
41
+ end
42
+
43
+ # The GW provides a synchronized store for participants in the gateway to
44
+ # communicate.
45
+
46
+ class GW
47
+ include MonitorMixin
48
+
49
+ # Creates a new GW
50
+
51
+ def initialize
52
+ super()
53
+ @hash = {}
54
+ end
55
+
56
+ # Retrieves +key+ from the GW
57
+
58
+ def [](key)
59
+ synchronize do
60
+ @hash[key]
61
+ end
62
+ end
63
+
64
+ # Stores value +v+ at +key+ in the GW
65
+
66
+ def []=(key, v)
67
+ synchronize do
68
+ @hash[key] = v
69
+ end
70
+ end
71
+ end
72
+
73
+ class DRabObject # :nodoc:
74
+ def self._load(s)
75
+ #uri, ref = Marshal::load(s)
76
+ uri, ref = JSON::load(s)
77
+ if DRab.uri == uri
78
+ return ref ? DRab.to_obj(ref) : DRab.front
79
+ end
80
+
81
+ self.new_with(DRab.uri, [:DRabObject, uri, ref])
82
+ end
83
+
84
+ def _dump(lv)
85
+ if DRab.uri == @uri
86
+ if Array === @ref && @ref[0] == :DRabObject
87
+ #Marshal::dump([@ref[1], @ref[2]])
88
+ JSON::dump([@ref[1], @ref[2]])
89
+ else
90
+ #Marshal::dump([@uri, @ref]) # ??
91
+ JSON::dump([@uri, @ref]) # ??
92
+ end
93
+ else
94
+ #Marshal::dump([DRab.uri, [:DRabObject, @uri, @ref]])
95
+ JSON::dump([DRab.uri, [:DRabObject, @uri, @ref]])
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ =begin
102
+ DRab.install_id_conv(DRab::GWIdConv.new)
103
+
104
+ front = DRab::GW.new
105
+
106
+ s1 = DRab::DRabServer.new('drabunix:/tmp/gw_b_a', front)
107
+ s2 = DRab::DRabServer.new('drabunix:/tmp/gw_b_c', front)
108
+
109
+ s1.thread.join
110
+ s2.thread.join
111
+ =end
112
+
113
+ =begin
114
+ # foo.rb
115
+
116
+ require 'drab/drab'
117
+
118
+ class Foo
119
+ include DRabUndumped
120
+ def initialize(name, peer=nil)
121
+ @name = name
122
+ @peer = peer
123
+ end
124
+
125
+ def ping(obj)
126
+ puts "#{@name}: ping: #{obj.inspect}"
127
+ @peer.ping(self) if @peer
128
+ end
129
+ end
130
+ =end
131
+
132
+ =begin
133
+ # gw_a.rb
134
+ require 'drab/unix'
135
+ require 'foo'
136
+
137
+ obj = Foo.new('a')
138
+ DRab.start_service("drabunix:/tmp/gw_a", obj)
139
+
140
+ robj = DRabObject.new_with_uri('drabunix:/tmp/gw_b_a')
141
+ robj[:a] = obj
142
+
143
+ DRab.thread.join
144
+ =end
145
+
146
+ =begin
147
+ # gw_c.rb
148
+ require 'drab/unix'
149
+ require 'foo'
150
+
151
+ foo = Foo.new('c', nil)
152
+
153
+ DRab.start_service("drabunix:/tmp/gw_c", nil)
154
+
155
+ robj = DRabObject.new_with_uri("drabunix:/tmp/gw_b_c")
156
+
157
+ puts "c->b"
158
+ a = robj[:a]
159
+ sleep 2
160
+
161
+ a.ping(foo)
162
+
163
+ DRab.thread.join
164
+ =end
165
+
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: false
2
+ # for ruby-1.8.0
3
+
4
+ module DRab # :nodoc: all
5
+ class DRabServer
6
+ module InvokeMethod18Mixin
7
+ def block_yield(x)
8
+ if x.size == 1 && x[0].class == Array
9
+ x[0] = DRabArray.new(x[0])
10
+ end
11
+ @block.call(*x)
12
+ end
13
+
14
+ def perform_with_block
15
+ @obj.__send__(@msg_id, *@argv) do |*x|
16
+ jump_error = nil
17
+ begin
18
+ block_value = block_yield(x)
19
+ rescue LocalJumpError
20
+ jump_error = $!
21
+ end
22
+ if jump_error
23
+ case jump_error.reason
24
+ when :break
25
+ break(jump_error.exit_value)
26
+ else
27
+ raise jump_error
28
+ end
29
+ end
30
+ block_value
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: false
2
+ require 'observer'
3
+
4
+ module DRab
5
+ # The Observable module extended to DRab. See Observable for details.
6
+ module DRabObservable
7
+ include Observable
8
+
9
+ # Notifies observers of a change in state. See also
10
+ # Observable#notify_observers
11
+ def notify_observers(*arg)
12
+ if defined? @observer_state and @observer_state
13
+ if defined? @observer_peers
14
+ @observer_peers.each do |observer, method|
15
+ begin
16
+ observer.send(method, *arg)
17
+ rescue
18
+ delete_observer(observer)
19
+ end
20
+ end
21
+ end
22
+ @observer_state = false
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,346 @@
1
+ # frozen_string_literal: false
2
+ require 'socket'
3
+ require 'openssl'
4
+ require 'drab/drab'
5
+ require 'singleton'
6
+
7
+ module DRab
8
+
9
+ # The protocol for DRab over an SSL socket
10
+ #
11
+ # The URI for a DRab socket over SSL is:
12
+ # <code>drabssl://<host>:<port>?<option></code>. The option is optional
13
+ class DRabSSLSocket < DRabTCPSocket
14
+
15
+ # SSLConfig handles the needed SSL information for establishing a
16
+ # DRabSSLSocket connection, including generating the X509 / RSA pair.
17
+ #
18
+ # An instance of this config can be passed to DRabSSLSocket.new,
19
+ # DRabSSLSocket.open and DRabSSLSocket.open_server
20
+ #
21
+ # See DRab::DRabSSLSocket::SSLConfig.new for more details
22
+ class SSLConfig
23
+
24
+ # Default values for a SSLConfig instance.
25
+ #
26
+ # See DRab::DRabSSLSocket::SSLConfig.new for more details
27
+ DEFAULT = {
28
+ :SSLCertificate => nil,
29
+ :SSLPrivateKey => nil,
30
+ :SSLClientCA => nil,
31
+ :SSLCACertificatePath => nil,
32
+ :SSLCACertificateFile => nil,
33
+ :SSLTmpDhCallback => nil,
34
+ :SSLVerifyMode => ::OpenSSL::SSL::VERIFY_NONE,
35
+ :SSLVerifyDepth => nil,
36
+ :SSLVerifyCallback => nil, # custom verification
37
+ :SSLCertificateStore => nil,
38
+ # Must specify if you use auto generated certificate.
39
+ :SSLCertName => nil, # e.g. [["CN","fqdn.example.com"]]
40
+ :SSLCertComment => "Generated by Ruby/OpenSSL"
41
+ }
42
+
43
+ # Create a new DRab::DRabSSLSocket::SSLConfig instance
44
+ #
45
+ # The DRab::DRabSSLSocket will take either a +config+ Hash or an instance
46
+ # of SSLConfig, and will setup the certificate for its session for the
47
+ # configuration. If want it to generate a generic certificate, the bare
48
+ # minimum is to provide the :SSLCertName
49
+ #
50
+ # === Config options
51
+ #
52
+ # From +config+ Hash:
53
+ #
54
+ # :SSLCertificate ::
55
+ # An instance of OpenSSL::X509::Certificate. If this is not provided,
56
+ # then a generic X509 is generated, with a correspond :SSLPrivateKey
57
+ #
58
+ # :SSLPrivateKey ::
59
+ # A private key instance, like OpenSSL::PKey::RSA. This key must be
60
+ # the key that signed the :SSLCertificate
61
+ #
62
+ # :SSLClientCA ::
63
+ # An OpenSSL::X509::Certificate, or Array of certificates that will
64
+ # used as ClientCAs in the SSL Context
65
+ #
66
+ # :SSLCACertificatePath ::
67
+ # A path to the directory of CA certificates. The certificates must
68
+ # be in PEM format.
69
+ #
70
+ # :SSLCACertificateFile ::
71
+ # A path to a CA certificate file, in PEM format.
72
+ #
73
+ # :SSLTmpDhCallback ::
74
+ # A DH callback. See OpenSSL::SSL::SSLContext.tmp_dh_callback
75
+ #
76
+ # :SSLVerifyMode ::
77
+ # This is the SSL verification mode. See OpenSSL::SSL::VERIFY_* for
78
+ # available modes. The default is OpenSSL::SSL::VERIFY_NONE
79
+ #
80
+ # :SSLVerifyDepth ::
81
+ # Number of CA certificates to walk, when verifying a certificate
82
+ # chain.
83
+ #
84
+ # :SSLVerifyCallback ::
85
+ # A callback to be used for additional verification. See
86
+ # OpenSSL::SSL::SSLContext.verify_callback
87
+ #
88
+ # :SSLCertificateStore ::
89
+ # A OpenSSL::X509::Store used for verification of certificates
90
+ #
91
+ # :SSLCertName ::
92
+ # Issuer name for the certificate. This is required when generating
93
+ # the certificate (if :SSLCertificate and :SSLPrivateKey were not
94
+ # given). The value of this is to be an Array of pairs:
95
+ #
96
+ # [["C", "Raleigh"], ["ST","North Carolina"],
97
+ # ["CN","fqdn.example.com"]]
98
+ #
99
+ # See also OpenSSL::X509::Name
100
+ #
101
+ # :SSLCertComment ::
102
+ # A comment to be used for generating the certificate. The default is
103
+ # "Generated by Ruby/OpenSSL"
104
+ #
105
+ #
106
+ # === Example
107
+ #
108
+ # These values can be added after the fact, like a Hash.
109
+ #
110
+ # require 'ssl'
111
+ # c = DRab::DRabSSLSocket::SSLConfig.new {}
112
+ # c[:SSLCertificate] =
113
+ # OpenSSL::X509::Certificate.new(File.read('mycert.crt'))
114
+ # c[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(File.read('mycert.key'))
115
+ # c[:SSLVerifyMode] = OpenSSL::SSL::VERIFY_PEER
116
+ # c[:SSLCACertificatePath] = "/etc/ssl/certs/"
117
+ # c.setup_certificate
118
+ #
119
+ # or
120
+ #
121
+ # require 'ssl'
122
+ # c = DRab::DRabSSLSocket::SSLConfig.new({
123
+ # :SSLCertName => [["CN" => DRab::DRabSSLSocket.getservername]]
124
+ # })
125
+ # c.setup_certificate
126
+ #
127
+ def initialize(config)
128
+ @config = config
129
+ @cert = config[:SSLCertificate]
130
+ @pkey = config[:SSLPrivateKey]
131
+ @ssl_ctx = nil
132
+ end
133
+
134
+ # A convenience method to access the values like a Hash
135
+ def [](key);
136
+ @config[key] || DEFAULT[key]
137
+ end
138
+
139
+ # Connect to IO +tcp+, with context of the current certificate
140
+ # configuration
141
+ def connect(tcp)
142
+ ssl = ::OpenSSL::SSL::SSLSocket.new(tcp, @ssl_ctx)
143
+ ssl.sync = true
144
+ ssl.connect
145
+ ssl
146
+ end
147
+
148
+ # Accept connection to IO +tcp+, with context of the current certificate
149
+ # configuration
150
+ def accept(tcp)
151
+ ssl = OpenSSL::SSL::SSLSocket.new(tcp, @ssl_ctx)
152
+ ssl.sync = true
153
+ ssl.accept
154
+ ssl
155
+ end
156
+
157
+ # Ensures that :SSLCertificate and :SSLPrivateKey have been provided
158
+ # or that a new certificate is generated with the other parameters
159
+ # provided.
160
+ def setup_certificate
161
+ if @cert && @pkey
162
+ return
163
+ end
164
+
165
+ rsa = OpenSSL::PKey::RSA.new(1024){|p, n|
166
+ next unless self[:verbose]
167
+ case p
168
+ when 0; $stderr.putc "." # BN_generate_prime
169
+ when 1; $stderr.putc "+" # BN_generate_prime
170
+ when 2; $stderr.putc "*" # searching good prime,
171
+ # n = #of try,
172
+ # but also data from BN_generate_prime
173
+ when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
174
+ # but also data from BN_generate_prime
175
+ else; $stderr.putc "*" # BN_generate_prime
176
+ end
177
+ }
178
+
179
+ cert = OpenSSL::X509::Certificate.new
180
+ cert.version = 3
181
+ cert.serial = 0
182
+ name = OpenSSL::X509::Name.new(self[:SSLCertName])
183
+ cert.subject = name
184
+ cert.issuer = name
185
+ cert.not_before = Time.now
186
+ cert.not_after = Time.now + (365*24*60*60)
187
+ cert.public_key = rsa.public_key
188
+
189
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
190
+ cert.extensions = [
191
+ ef.create_extension("basicConstraints","CA:FALSE"),
192
+ ef.create_extension("subjectKeyIdentifier", "hash") ]
193
+ ef.issuer_certificate = cert
194
+ cert.add_extension(ef.create_extension("authorityKeyIdentifier",
195
+ "keyid:always,issuer:always"))
196
+ if comment = self[:SSLCertComment]
197
+ cert.add_extension(ef.create_extension("nsComment", comment))
198
+ end
199
+ cert.sign(rsa, OpenSSL::Digest::SHA1.new)
200
+
201
+ @cert = cert
202
+ @pkey = rsa
203
+ end
204
+
205
+ # Establish the OpenSSL::SSL::SSLContext with the configuration
206
+ # parameters provided.
207
+ def setup_ssl_context
208
+ ctx = ::OpenSSL::SSL::SSLContext.new
209
+ ctx.cert = @cert
210
+ ctx.key = @pkey
211
+ ctx.client_ca = self[:SSLClientCA]
212
+ ctx.ca_path = self[:SSLCACertificatePath]
213
+ ctx.ca_file = self[:SSLCACertificateFile]
214
+ ctx.tmp_dh_callback = self[:SSLTmpDhCallback]
215
+ ctx.verify_mode = self[:SSLVerifyMode]
216
+ ctx.verify_depth = self[:SSLVerifyDepth]
217
+ ctx.verify_callback = self[:SSLVerifyCallback]
218
+ ctx.cert_store = self[:SSLCertificateStore]
219
+ @ssl_ctx = ctx
220
+ end
221
+ end
222
+
223
+ # Parse the dRuby +uri+ for an SSL connection.
224
+ #
225
+ # Expects drabssl://...
226
+ #
227
+ # Raises DRabBadScheme or DRabBadURI if +uri+ is not matching or malformed
228
+ def self.parse_uri(uri) # :nodoc:
229
+ if uri =~ /^drabssl:\/\/(.*?):(\d+)(\?(.*))?$/
230
+ host = $1
231
+ port = $2.to_i
232
+ option = $4
233
+ [host, port, option]
234
+ else
235
+ raise(DRabBadScheme, uri) unless uri =~ /^drabssl:/
236
+ raise(DRabBadURI, 'can\'t parse uri:' + uri)
237
+ end
238
+ end
239
+
240
+ # Return an DRab::DRabSSLSocket instance as a client-side connection,
241
+ # with the SSL connected. This is called from DRab::start_service or while
242
+ # connecting to a remote object:
243
+ #
244
+ # DRab.start_service 'drabssl://localhost:0', front, config
245
+ #
246
+ # +uri+ is the URI we are connected to,
247
+ # <code>'drabssl://localhost:0'</code> above, +config+ is our
248
+ # configuration. Either a Hash or DRab::DRabSSLSocket::SSLConfig
249
+ def self.open(uri, config)
250
+ host, port, = parse_uri(uri)
251
+ host.untaint
252
+ port.untaint
253
+ soc = TCPSocket.open(host, port)
254
+ ssl_conf = SSLConfig::new(config)
255
+ ssl_conf.setup_ssl_context
256
+ ssl = ssl_conf.connect(soc)
257
+ self.new(uri, ssl, ssl_conf, true)
258
+ end
259
+
260
+ # Returns a DRab::DRabSSLSocket instance as a server-side connection, with
261
+ # the SSL connected. This is called from DRab::start_service or while
262
+ # connecting to a remote object:
263
+ #
264
+ # DRab.start_service 'drabssl://localhost:0', front, config
265
+ #
266
+ # +uri+ is the URI we are connected to,
267
+ # <code>'drabssl://localhost:0'</code> above, +config+ is our
268
+ # configuration. Either a Hash or DRab::DRabSSLSocket::SSLConfig
269
+ def self.open_server(uri, config)
270
+ uri = 'drabssl://:0' unless uri
271
+ host, port, = parse_uri(uri)
272
+ if host.size == 0
273
+ host = getservername
274
+ soc = open_server_inaddr_any(host, port)
275
+ else
276
+ soc = TCPServer.open(host, port)
277
+ end
278
+ port = soc.addr[1] if port == 0
279
+ @uri = "drabssl://#{host}:#{port}"
280
+
281
+ ssl_conf = SSLConfig.new(config)
282
+ ssl_conf.setup_certificate
283
+ ssl_conf.setup_ssl_context
284
+ self.new(@uri, soc, ssl_conf, false)
285
+ end
286
+
287
+ # This is a convenience method to parse +uri+ and separate out any
288
+ # additional options appended in the +uri+.
289
+ #
290
+ # Returns an option-less uri and the option => [uri,option]
291
+ #
292
+ # The +config+ is completely unused, so passing nil is sufficient.
293
+ def self.uri_option(uri, config) # :nodoc:
294
+ host, port, option = parse_uri(uri)
295
+ return "drabssl://#{host}:#{port}", option
296
+ end
297
+
298
+ # Create a DRab::DRabSSLSocket instance.
299
+ #
300
+ # +uri+ is the URI we are connected to.
301
+ # +soc+ is the tcp socket we are bound to.
302
+ # +config+ is our configuration. Either a Hash or SSLConfig
303
+ # +is_established+ is a boolean of whether +soc+ is currently established
304
+ #
305
+ # This is called automatically based on the DRab protocol.
306
+ def initialize(uri, soc, config, is_established)
307
+ @ssl = is_established ? soc : nil
308
+ super(uri, soc.to_io, config)
309
+ end
310
+
311
+ # Returns the SSL stream
312
+ def stream; @ssl; end # :nodoc:
313
+
314
+ # Closes the SSL stream before closing the dRuby connection.
315
+ def close # :nodoc:
316
+ if @ssl
317
+ @ssl.close
318
+ @ssl = nil
319
+ end
320
+ super
321
+ end
322
+
323
+ def accept # :nodoc:
324
+ begin
325
+ while true
326
+ soc = accept_or_shutdown
327
+ return nil unless soc
328
+ break if (@acl ? @acl.allow_socket?(soc) : true)
329
+ soc.close
330
+ end
331
+ begin
332
+ ssl = @config.accept(soc)
333
+ rescue Exception
334
+ soc.close
335
+ raise
336
+ end
337
+ self.class.new(uri, ssl, @config, true)
338
+ rescue OpenSSL::SSL::SSLError
339
+ warn("#{__FILE__}:#{__LINE__}: warning: #{$!.message} (#{$!.class})") if @config[:verbose]
340
+ retry
341
+ end
342
+ end
343
+ end
344
+
345
+ DRabProtocol.add_protocol(DRabSSLSocket)
346
+ end