drb 2.0.4

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 DRb
3
+ class DRbObject # :nodoc:
4
+ def ==(other)
5
+ return false unless DRbObject === other
6
+ (@ref == other.__drbref) && (@uri == other.__drburi)
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_relative 'drb'
8
+ require 'monitor'
9
+
10
+ module DRb
11
+ class ExtServ
12
+ include MonitorMixin
13
+ include DRbUndumped
14
+
15
+ def initialize(there, name, server=nil)
16
+ super()
17
+ @server = server || DRb::primary_server
18
+ @name = name
19
+ ro = DRbObject.new(nil, there)
20
+ synchronize do
21
+ @invoker = ro.regist(name, DRbObject.new(self, @server.uri))
22
+ end
23
+ end
24
+ attr_reader :server
25
+
26
+ def front
27
+ DRbObject.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,92 @@
1
+ # frozen_string_literal: false
2
+ =begin
3
+ external service manager
4
+ Copyright (c) 2000 Masatoshi SEKI
5
+ =end
6
+
7
+ require_relative 'drb'
8
+ require 'monitor'
9
+
10
+ module DRb
11
+ class ExtServManager
12
+ include DRbUndumped
13
+ include MonitorMixin
14
+
15
+ @@command = {}
16
+
17
+ def self.command
18
+ @@command
19
+ end
20
+
21
+ def self.command=(cmd)
22
+ @@command = cmd
23
+ end
24
+
25
+ def initialize
26
+ super()
27
+ @cond = new_cond
28
+ @servers = {}
29
+ @waiting = []
30
+ @queue = Thread::Queue.new
31
+ @thread = invoke_thread
32
+ @uri = nil
33
+ end
34
+ attr_accessor :uri
35
+
36
+ def service(name)
37
+ synchronize do
38
+ while true
39
+ server = @servers[name]
40
+ return server if server && server.alive? # server may be `false'
41
+ invoke_service(name)
42
+ @cond.wait
43
+ end
44
+ end
45
+ end
46
+
47
+ def regist(name, ro)
48
+ synchronize do
49
+ @servers[name] = ro
50
+ @cond.signal
51
+ end
52
+ self
53
+ end
54
+
55
+ def unregist(name)
56
+ synchronize do
57
+ @servers.delete(name)
58
+ end
59
+ end
60
+
61
+ private
62
+ def invoke_thread
63
+ Thread.new do
64
+ while name = @queue.pop
65
+ invoke_service_command(name, @@command[name])
66
+ end
67
+ end
68
+ end
69
+
70
+ def invoke_service(name)
71
+ @queue.push(name)
72
+ end
73
+
74
+ def invoke_service_command(name, command)
75
+ raise "invalid command. name: #{name}" unless command
76
+ synchronize do
77
+ return if @servers.include?(name)
78
+ @servers[name] = false
79
+ end
80
+ uri = @uri || DRb.uri
81
+ if command.respond_to? :to_ary
82
+ command = command.to_ary + [uri, name]
83
+ pid = spawn(*command)
84
+ else
85
+ pid = spawn("#{command} #{uri} #{name}")
86
+ end
87
+ th = Process.detach(pid)
88
+ th[:drb_service] = name
89
+ th
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: false
2
+ require_relative 'drb'
3
+ require 'monitor'
4
+
5
+ module DRb
6
+
7
+ # Gateway id conversion forms a gateway between different DRb 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 'drb/drb'
16
+ # require 'drb/unix'
17
+ # require 'drb/gw'
18
+ #
19
+ # DRb.install_id_conv DRb::GWIdConv.new
20
+ # gw = DRb::GW.new
21
+ # s1 = DRb::DRbServer.new 'drbunix:/path/to/gateway', gw
22
+ # s2 = DRb::DRbServer.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
+ # DRb.start_service 'drbunix:', nil # an anonymous server
30
+ # gw = DRbObject.new nil, 'drbunix:/path/to/gateway'
31
+ # gw[:unix] = some_service
32
+ # DRb.thread.join
33
+
34
+ class GWIdConv < DRbIdConv
35
+ def to_obj(ref) # :nodoc:
36
+ if Array === ref && ref[0] == :DRbObject
37
+ return DRbObject.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 DRbObject # :nodoc:
74
+ def self._load(s)
75
+ uri, ref = Marshal.load(s)
76
+ if DRb.uri == uri
77
+ return ref ? DRb.to_obj(ref) : DRb.front
78
+ end
79
+
80
+ self.new_with(DRb.uri, [:DRbObject, uri, ref])
81
+ end
82
+
83
+ def _dump(lv)
84
+ if DRb.uri == @uri
85
+ if Array === @ref && @ref[0] == :DRbObject
86
+ Marshal.dump([@ref[1], @ref[2]])
87
+ else
88
+ Marshal.dump([@uri, @ref]) # ??
89
+ end
90
+ else
91
+ Marshal.dump([DRb.uri, [:DRbObject, @uri, @ref]])
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ =begin
98
+ DRb.install_id_conv(DRb::GWIdConv.new)
99
+
100
+ front = DRb::GW.new
101
+
102
+ s1 = DRb::DRbServer.new('drbunix:/tmp/gw_b_a', front)
103
+ s2 = DRb::DRbServer.new('drbunix:/tmp/gw_b_c', front)
104
+
105
+ s1.thread.join
106
+ s2.thread.join
107
+ =end
108
+
109
+ =begin
110
+ # foo.rb
111
+
112
+ require 'drb/drb'
113
+
114
+ class Foo
115
+ include DRbUndumped
116
+ def initialize(name, peer=nil)
117
+ @name = name
118
+ @peer = peer
119
+ end
120
+
121
+ def ping(obj)
122
+ puts "#{@name}: ping: #{obj.inspect}"
123
+ @peer.ping(self) if @peer
124
+ end
125
+ end
126
+ =end
127
+
128
+ =begin
129
+ # gw_a.rb
130
+ require 'drb/unix'
131
+ require 'foo'
132
+
133
+ obj = Foo.new('a')
134
+ DRb.start_service("drbunix:/tmp/gw_a", obj)
135
+
136
+ robj = DRbObject.new_with_uri('drbunix:/tmp/gw_b_a')
137
+ robj[:a] = obj
138
+
139
+ DRb.thread.join
140
+ =end
141
+
142
+ =begin
143
+ # gw_c.rb
144
+ require 'drb/unix'
145
+ require 'foo'
146
+
147
+ foo = Foo.new('c', nil)
148
+
149
+ DRb.start_service("drbunix:/tmp/gw_c", nil)
150
+
151
+ robj = DRbObject.new_with_uri("drbunix:/tmp/gw_b_c")
152
+
153
+ puts "c->b"
154
+ a = robj[:a]
155
+ sleep 2
156
+
157
+ a.ping(foo)
158
+
159
+ DRb.thread.join
160
+ =end
161
+
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: false
2
+ # for ruby-1.8.0
3
+
4
+ module DRb # :nodoc: all
5
+ class DRbServer
6
+ module InvokeMethod18Mixin
7
+ def block_yield(x)
8
+ if x.size == 1 && x[0].class == Array
9
+ x[0] = DRbArray.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 DRb
5
+ # The Observable module extended to DRb. See Observable for details.
6
+ module DRbObservable
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,344 @@
1
+ # frozen_string_literal: false
2
+ require 'socket'
3
+ require 'openssl'
4
+ require_relative 'drb'
5
+ require 'singleton'
6
+
7
+ module DRb
8
+
9
+ # The protocol for DRb over an SSL socket
10
+ #
11
+ # The URI for a DRb socket over SSL is:
12
+ # <code>drbssl://<host>:<port>?<option></code>. The option is optional
13
+ class DRbSSLSocket < DRbTCPSocket
14
+
15
+ # SSLConfig handles the needed SSL information for establishing a
16
+ # DRbSSLSocket connection, including generating the X509 / RSA pair.
17
+ #
18
+ # An instance of this config can be passed to DRbSSLSocket.new,
19
+ # DRbSSLSocket.open and DRbSSLSocket.open_server
20
+ #
21
+ # See DRb::DRbSSLSocket::SSLConfig.new for more details
22
+ class SSLConfig
23
+
24
+ # Default values for a SSLConfig instance.
25
+ #
26
+ # See DRb::DRbSSLSocket::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 DRb::DRbSSLSocket::SSLConfig instance
44
+ #
45
+ # The DRb::DRbSSLSocket 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 'drb/ssl'
111
+ # c = DRb::DRbSSLSocket::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 'drb/ssl'
122
+ # c = DRb::DRbSSLSocket::SSLConfig.new({
123
+ # :SSLCertName => [["CN" => DRb::DRbSSLSocket.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(2048){|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, "SHA256")
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 drbssl://...
226
+ #
227
+ # Raises DRbBadScheme or DRbBadURI if +uri+ is not matching or malformed
228
+ def self.parse_uri(uri) # :nodoc:
229
+ if /\Adrbssl:\/\/(.*?):(\d+)(\?(.*))?\z/ =~ uri
230
+ host = $1
231
+ port = $2.to_i
232
+ option = $4
233
+ [host, port, option]
234
+ else
235
+ raise(DRbBadScheme, uri) unless uri.start_with?('drbssl:')
236
+ raise(DRbBadURI, 'can\'t parse uri:' + uri)
237
+ end
238
+ end
239
+
240
+ # Return an DRb::DRbSSLSocket instance as a client-side connection,
241
+ # with the SSL connected. This is called from DRb::start_service or while
242
+ # connecting to a remote object:
243
+ #
244
+ # DRb.start_service 'drbssl://localhost:0', front, config
245
+ #
246
+ # +uri+ is the URI we are connected to,
247
+ # <code>'drbssl://localhost:0'</code> above, +config+ is our
248
+ # configuration. Either a Hash or DRb::DRbSSLSocket::SSLConfig
249
+ def self.open(uri, config)
250
+ host, port, = parse_uri(uri)
251
+ soc = TCPSocket.open(host, port)
252
+ ssl_conf = SSLConfig::new(config)
253
+ ssl_conf.setup_ssl_context
254
+ ssl = ssl_conf.connect(soc)
255
+ self.new(uri, ssl, ssl_conf, true)
256
+ end
257
+
258
+ # Returns a DRb::DRbSSLSocket instance as a server-side connection, with
259
+ # the SSL connected. This is called from DRb::start_service or while
260
+ # connecting to a remote object:
261
+ #
262
+ # DRb.start_service 'drbssl://localhost:0', front, config
263
+ #
264
+ # +uri+ is the URI we are connected to,
265
+ # <code>'drbssl://localhost:0'</code> above, +config+ is our
266
+ # configuration. Either a Hash or DRb::DRbSSLSocket::SSLConfig
267
+ def self.open_server(uri, config)
268
+ uri = 'drbssl://:0' unless uri
269
+ host, port, = parse_uri(uri)
270
+ if host.size == 0
271
+ host = getservername
272
+ soc = open_server_inaddr_any(host, port)
273
+ else
274
+ soc = TCPServer.open(host, port)
275
+ end
276
+ port = soc.addr[1] if port == 0
277
+ @uri = "drbssl://#{host}:#{port}"
278
+
279
+ ssl_conf = SSLConfig.new(config)
280
+ ssl_conf.setup_certificate
281
+ ssl_conf.setup_ssl_context
282
+ self.new(@uri, soc, ssl_conf, false)
283
+ end
284
+
285
+ # This is a convenience method to parse +uri+ and separate out any
286
+ # additional options appended in the +uri+.
287
+ #
288
+ # Returns an option-less uri and the option => [uri,option]
289
+ #
290
+ # The +config+ is completely unused, so passing nil is sufficient.
291
+ def self.uri_option(uri, config) # :nodoc:
292
+ host, port, option = parse_uri(uri)
293
+ return "drbssl://#{host}:#{port}", option
294
+ end
295
+
296
+ # Create a DRb::DRbSSLSocket instance.
297
+ #
298
+ # +uri+ is the URI we are connected to.
299
+ # +soc+ is the tcp socket we are bound to.
300
+ # +config+ is our configuration. Either a Hash or SSLConfig
301
+ # +is_established+ is a boolean of whether +soc+ is currently established
302
+ #
303
+ # This is called automatically based on the DRb protocol.
304
+ def initialize(uri, soc, config, is_established)
305
+ @ssl = is_established ? soc : nil
306
+ super(uri, soc.to_io, config)
307
+ end
308
+
309
+ # Returns the SSL stream
310
+ def stream; @ssl; end # :nodoc:
311
+
312
+ # Closes the SSL stream before closing the dRuby connection.
313
+ def close # :nodoc:
314
+ if @ssl
315
+ @ssl.close
316
+ @ssl = nil
317
+ end
318
+ super
319
+ end
320
+
321
+ def accept # :nodoc:
322
+ begin
323
+ while true
324
+ soc = accept_or_shutdown
325
+ return nil unless soc
326
+ break if (@acl ? @acl.allow_socket?(soc) : true)
327
+ soc.close
328
+ end
329
+ begin
330
+ ssl = @config.accept(soc)
331
+ rescue Exception
332
+ soc.close
333
+ raise
334
+ end
335
+ self.class.new(uri, ssl, @config, true)
336
+ rescue OpenSSL::SSL::SSLError
337
+ warn("#{$!.message} (#{$!.class})", uplevel: 0) if @config[:verbose]
338
+ retry
339
+ end
340
+ end
341
+ end
342
+
343
+ DRbProtocol.add_protocol(DRbSSLSocket)
344
+ end