bunny 0.10.8 → 1.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -4
- data/ChangeLog.md +1 -152
- data/Gemfile +1 -1
- data/README.md +5 -5
- data/bunny.gemspec +1 -1
- data/lib/bunny.rb +14 -2
- data/lib/bunny/channel.rb +94 -158
- data/lib/bunny/channel_id_allocator.rb +1 -2
- data/lib/bunny/concurrent/condition.rb +1 -2
- data/lib/bunny/concurrent/continuation_queue.rb +1 -1
- data/lib/bunny/consumer.rb +0 -13
- data/lib/bunny/consumer_work_pool.rb +2 -5
- data/lib/bunny/delivery_info.rb +1 -3
- data/lib/bunny/exceptions.rb +1 -4
- data/lib/bunny/heartbeat_sender.rb +1 -1
- data/lib/bunny/reader_loop.rb +3 -23
- data/lib/bunny/session.rb +19 -103
- data/lib/bunny/socket.rb +1 -1
- data/lib/bunny/transport.rb +7 -31
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/basic_ack_spec.rb +19 -34
- data/spec/higher_level_api/integration/basic_cancel_spec.rb +1 -1
- data/spec/higher_level_api/integration/basic_consume_spec.rb +2 -63
- data/spec/higher_level_api/integration/basic_get_spec.rb +1 -1
- data/spec/higher_level_api/integration/basic_nack_spec.rb +1 -1
- data/spec/higher_level_api/integration/basic_publish_spec.rb +1 -1
- data/spec/higher_level_api/integration/basic_qos_spec.rb +8 -5
- data/spec/higher_level_api/integration/basic_reject_spec.rb +17 -16
- data/spec/higher_level_api/integration/basic_return_spec.rb +1 -1
- data/spec/higher_level_api/integration/channel_close_spec.rb +10 -6
- data/spec/higher_level_api/integration/channel_flow_spec.rb +9 -6
- data/spec/higher_level_api/integration/channel_open_spec.rb +20 -11
- data/spec/higher_level_api/integration/confirm_select_spec.rb +1 -1
- data/spec/higher_level_api/integration/connection_spec.rb +1 -1
- data/spec/higher_level_api/integration/consistent_hash_exchange_spec.rb +1 -1
- data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +1 -46
- data/spec/higher_level_api/integration/dead_lettering_spec.rb +1 -1
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +1 -1
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +1 -1
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +1 -1
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +1 -1
- data/spec/higher_level_api/integration/merry_go_round_spec.rb +1 -1
- data/spec/higher_level_api/integration/message_properties_access_spec.rb +1 -1
- data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +1 -1
- data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +1 -1
- data/spec/higher_level_api/integration/queue_declare_spec.rb +1 -1
- data/spec/higher_level_api/integration/queue_delete_spec.rb +2 -2
- data/spec/higher_level_api/integration/queue_purge_spec.rb +1 -1
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +2 -2
- data/spec/higher_level_api/integration/read_only_consumer_spec.rb +1 -1
- data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +2 -2
- data/spec/higher_level_api/integration/tls_connection_spec.rb +2 -86
- data/spec/higher_level_api/integration/tx_commit_spec.rb +1 -1
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +1 -1
- data/spec/unit/concurrent/condition_spec.rb +46 -53
- metadata +5 -25
- data/benchmarks/mutex_and_monitor.rb +0 -42
- data/benchmarks/synchronized_sorted_set.rb +0 -53
- data/lib/amq/protocol/extensions.rb +0 -16
- data/lib/bunny/concurrent/atomic_fixnum.rb +0 -74
- data/lib/bunny/concurrent/synchronized_sorted_set.rb +0 -56
- data/lib/bunny/timeout.rb +0 -18
- data/lib/bunny/versioned_delivery_tag.rb +0 -28
- data/spec/higher_level_api/integration/connection_stop_spec.rb +0 -26
- data/spec/higher_level_api/integration/exclusive_queue_spec.rb +0 -28
- data/spec/issues/issue141_spec.rb +0 -44
- data/spec/stress/connection_open_close_spec.rb +0 -40
- data/spec/unit/concurrent/atomic_fixnum_spec.rb +0 -35
- data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +0 -73
@@ -1,5 +1,4 @@
|
|
1
1
|
require "thread"
|
2
|
-
require "monitor"
|
3
2
|
require "amq/int_allocator"
|
4
3
|
|
5
4
|
module Bunny
|
@@ -19,7 +18,7 @@ module Bunny
|
|
19
18
|
# @param [Integer] max_channel Max allowed channel id
|
20
19
|
def initialize(max_channel = ((1 << 16) - 1))
|
21
20
|
@allocator = AMQ::IntAllocator.new(1, max_channel)
|
22
|
-
@mutex =
|
21
|
+
@mutex = Mutex.new
|
23
22
|
end
|
24
23
|
|
25
24
|
|
data/lib/bunny/consumer.rb
CHANGED
@@ -37,7 +37,6 @@ module Bunny
|
|
37
37
|
@consumer_tag = consumer_tag
|
38
38
|
@exclusive = exclusive
|
39
39
|
@arguments = arguments
|
40
|
-
# no_ack set to true = no manual ack = automatic ack. MK.
|
41
40
|
@no_ack = no_ack
|
42
41
|
end
|
43
42
|
|
@@ -90,18 +89,6 @@ module Bunny
|
|
90
89
|
"#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name}> @consumer_tag=#{@consumer_tag}>"
|
91
90
|
end
|
92
91
|
|
93
|
-
# @return [Boolean] true if this consumer uses automatic acknowledgement mode
|
94
|
-
# @api public
|
95
|
-
def automatic_acknowledgement?
|
96
|
-
@no_ack == false
|
97
|
-
end
|
98
|
-
|
99
|
-
# @return [Boolean] true if this consumer uses manual (explicit) acknowledgement mode
|
100
|
-
# @api public
|
101
|
-
def manual_acknowledgement?
|
102
|
-
@no_ack == true
|
103
|
-
end
|
104
|
-
|
105
92
|
#
|
106
93
|
# Recovery
|
107
94
|
#
|
@@ -4,8 +4,6 @@ module Bunny
|
|
4
4
|
# Thread pool that dispatches consumer deliveries. Not supposed to be shared between channels
|
5
5
|
# or threads.
|
6
6
|
#
|
7
|
-
# Every channel its own consumer pool.
|
8
|
-
#
|
9
7
|
# @private
|
10
8
|
class ConsumerWorkPool
|
11
9
|
|
@@ -13,7 +11,6 @@ module Bunny
|
|
13
11
|
# API
|
14
12
|
#
|
15
13
|
|
16
|
-
attr_reader :threads
|
17
14
|
attr_reader :size
|
18
15
|
|
19
16
|
def initialize(size = 1)
|
@@ -51,8 +48,8 @@ module Bunny
|
|
51
48
|
end
|
52
49
|
end
|
53
50
|
|
54
|
-
def join
|
55
|
-
@threads.each { |t| t.join
|
51
|
+
def join
|
52
|
+
@threads.each { |t| t.join }
|
56
53
|
end
|
57
54
|
|
58
55
|
def pause
|
data/lib/bunny/delivery_info.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "bunny/versioned_delivery_tag"
|
2
|
-
|
3
1
|
module Bunny
|
4
2
|
# Wraps {AMQ::Protocol::Basic::Deliver} to
|
5
3
|
# provide access to the delivery properties as immutable hash as
|
@@ -26,7 +24,7 @@ module Bunny
|
|
26
24
|
@basic_deliver = basic_deliver
|
27
25
|
@hash = {
|
28
26
|
:consumer_tag => basic_deliver.consumer_tag,
|
29
|
-
:delivery_tag =>
|
27
|
+
:delivery_tag => basic_deliver.delivery_tag,
|
30
28
|
:redelivered => basic_deliver.redelivered,
|
31
29
|
:exchange => basic_deliver.exchange,
|
32
30
|
:routing_key => basic_deliver.routing_key,
|
data/lib/bunny/exceptions.rb
CHANGED
@@ -55,7 +55,7 @@ module Bunny
|
|
55
55
|
when Exception then
|
56
56
|
e.message
|
57
57
|
end
|
58
|
-
super("Could not
|
58
|
+
super("Could not estabilish TCP connection to #{hostname}:#{port}: #{m}")
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -70,9 +70,6 @@ module Bunny
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
class ShutdownSignal < Exception
|
74
|
-
end
|
75
|
-
|
76
73
|
# Raised when RabbitMQ closes TCP connection before finishing connection
|
77
74
|
# sequence properly. This typically indicates an authentication issue.
|
78
75
|
class PossibleAuthenticationFailureError < Exception
|
data/lib/bunny/reader_loop.rb
CHANGED
@@ -19,6 +19,7 @@ module Bunny
|
|
19
19
|
|
20
20
|
def start
|
21
21
|
@thread = Thread.new(&method(:run_loop))
|
22
|
+
@thread.abort_on_exception = true
|
22
23
|
end
|
23
24
|
|
24
25
|
def resume
|
@@ -32,10 +33,8 @@ module Bunny
|
|
32
33
|
break if @stopping || @network_is_down
|
33
34
|
run_once
|
34
35
|
rescue Errno::EBADF => ebadf
|
35
|
-
break if @stopping
|
36
36
|
# ignored, happens when we loop after the transport has already been closed
|
37
37
|
rescue AMQ::Protocol::EmptyResponseError, IOError, SystemCallError => e
|
38
|
-
break if @stopping
|
39
38
|
log_exception(e)
|
40
39
|
|
41
40
|
@network_is_down = true
|
@@ -45,18 +44,13 @@ module Bunny
|
|
45
44
|
else
|
46
45
|
@session_thread.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
47
46
|
end
|
48
|
-
rescue ShutdownSignal => _
|
49
|
-
break
|
50
47
|
rescue Exception => e
|
51
|
-
break if @stopping
|
52
48
|
log_exception(e)
|
53
49
|
|
54
50
|
@network_is_down = true
|
55
51
|
@session_thread.raise(Bunny::NetworkFailure.new("caught an unexpected exception in the network loop: #{e.message}", e))
|
56
52
|
end
|
57
53
|
end
|
58
|
-
|
59
|
-
@stopped = true
|
60
54
|
end
|
61
55
|
|
62
56
|
def run_once
|
@@ -86,23 +80,9 @@ module Bunny
|
|
86
80
|
@stopping = true
|
87
81
|
end
|
88
82
|
|
89
|
-
def stopped?
|
90
|
-
@stopped
|
91
|
-
end
|
92
|
-
|
93
|
-
def raise(e)
|
94
|
-
@thread.raise(e) if @thread
|
95
|
-
end
|
96
|
-
|
97
|
-
def join
|
98
|
-
@thread.join if @thread
|
99
|
-
end
|
100
|
-
|
101
83
|
def kill
|
102
|
-
|
103
|
-
|
104
|
-
@thread.join
|
105
|
-
end
|
84
|
+
@thread.kill
|
85
|
+
@thread.join
|
106
86
|
end
|
107
87
|
|
108
88
|
def log_exception(e)
|
data/lib/bunny/session.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "socket"
|
2
2
|
require "thread"
|
3
|
-
require "monitor"
|
4
3
|
|
5
4
|
require "bunny/transport"
|
6
5
|
require "bunny/channel_id_allocator"
|
@@ -97,23 +96,18 @@ module Bunny
|
|
97
96
|
# @option connection_string_or_opts [String] :password ("guest") Password
|
98
97
|
# @option connection_string_or_opts [String] :vhost ("/") Virtual host to use
|
99
98
|
# @option connection_string_or_opts [Integer] :heartbeat (600) Heartbeat interval. 0 means no heartbeat.
|
100
|
-
# @option connection_string_or_opts [Boolean] :tls (false) Should TLS/SSL be used?
|
101
|
-
# @option connection_string_or_opts [String] :tls_cert (nil) Path to client TLS/SSL certificate file (.pem)
|
102
|
-
# @option connection_string_or_opts [String] :tls_key (nil) Path to client TLS/SSL private key file (.pem)
|
103
|
-
# @option connection_string_or_opts [Array<String>] :tls_ca_certificates Array of paths to TLS/SSL CA files (.pem), by default detected from OpenSSL configuration
|
104
99
|
#
|
105
100
|
# @option optz [String] :auth_mechanism ("PLAIN") Authentication mechanism, PLAIN or EXTERNAL
|
106
101
|
# @option optz [String] :locale ("PLAIN") Locale RabbitMQ should use
|
107
102
|
#
|
108
103
|
# @see http://rubybunny.info/articles/connecting.html Connecting to RabbitMQ guide
|
109
|
-
# @see http://rubybunny.info/articles/tls.html TLS/SSL guide
|
110
104
|
# @api public
|
111
105
|
def initialize(connection_string_or_opts = Hash.new, optz = Hash.new)
|
112
106
|
opts = case (ENV["RABBITMQ_URL"] || connection_string_or_opts)
|
113
107
|
when nil then
|
114
108
|
Hash.new
|
115
109
|
when String then
|
116
|
-
|
110
|
+
AMQ::Settings.parse_amqp_url(connection_string_or_opts)
|
117
111
|
when Hash then
|
118
112
|
connection_string_or_opts
|
119
113
|
end.merge(optz)
|
@@ -150,14 +144,11 @@ module Bunny
|
|
150
144
|
@mechanism = opts.fetch(:auth_mechanism, "PLAIN")
|
151
145
|
@credentials_encoder = credentials_encoder_for(@mechanism)
|
152
146
|
@locale = @opts.fetch(:locale, DEFAULT_LOCALE)
|
153
|
-
|
154
|
-
@mutex_impl = @opts.fetch(:mutex_impl, Monitor)
|
155
|
-
|
156
147
|
# mutex for the channel id => channel hash
|
157
|
-
@channel_mutex =
|
148
|
+
@channel_mutex = Mutex.new
|
158
149
|
# transport operations/continuations mutex. A workaround for
|
159
150
|
# the non-reentrant Ruby mutexes. MK.
|
160
|
-
@transport_mutex =
|
151
|
+
@transport_mutex = Mutex.new
|
161
152
|
@channels = Hash.new
|
162
153
|
|
163
154
|
@origin_thread = Thread.current
|
@@ -195,11 +186,6 @@ module Bunny
|
|
195
186
|
@threaded
|
196
187
|
end
|
197
188
|
|
198
|
-
# @private
|
199
|
-
attr_reader :mutex_impl
|
200
|
-
|
201
|
-
# Provides a way to fine tune the socket used by connection.
|
202
|
-
# Accepts a block that the socket will be yielded to.
|
203
189
|
def configure_socket(&block)
|
204
190
|
raise ArgumentError, "No block provided!" if block.nil?
|
205
191
|
|
@@ -233,7 +219,7 @@ module Bunny
|
|
233
219
|
self.open_connection
|
234
220
|
|
235
221
|
@reader_loop = nil
|
236
|
-
self.start_reader_loop if threaded
|
222
|
+
self.start_reader_loop if @threaded
|
237
223
|
|
238
224
|
@default_channel = self.create_channel
|
239
225
|
rescue Exception => e
|
@@ -272,14 +258,9 @@ module Bunny
|
|
272
258
|
if @transport.open?
|
273
259
|
close_all_channels
|
274
260
|
|
275
|
-
Bunny::
|
276
|
-
self.close_connection(
|
261
|
+
Bunny::Timer.timeout(@transport.disconnect_timeout, ClientTimeout) do
|
262
|
+
self.close_connection(false)
|
277
263
|
end
|
278
|
-
|
279
|
-
maybe_shutdown_reader_loop
|
280
|
-
close_transport
|
281
|
-
|
282
|
-
@status = :closed
|
283
264
|
end
|
284
265
|
end
|
285
266
|
alias stop close
|
@@ -349,41 +330,6 @@ module Bunny
|
|
349
330
|
@default_channel.exchange(*args)
|
350
331
|
end
|
351
332
|
|
352
|
-
# Defines a callback that will be executed when RabbitMQ blocks the connection
|
353
|
-
# because it is running low on memory or disk space (as configured via config file
|
354
|
-
# and/or rabbitmqctl).
|
355
|
-
#
|
356
|
-
# @yield [AMQ::Protocol::Connection::Blocked] connection.blocked method which provides a reason for blocking
|
357
|
-
#
|
358
|
-
# @api public
|
359
|
-
def on_blocked(&block)
|
360
|
-
@block_callback = block
|
361
|
-
end
|
362
|
-
|
363
|
-
# Defines a callback that will be executed when RabbitMQ unblocks the connection
|
364
|
-
# that was previously blocked, e.g. because the memory or disk space alarm has cleared.
|
365
|
-
#
|
366
|
-
# @see #on_blocked
|
367
|
-
# @api public
|
368
|
-
def on_unblocked(&block)
|
369
|
-
@unblock_callback = block
|
370
|
-
end
|
371
|
-
|
372
|
-
# @return [Boolean] true if the connection is currently blocked by RabbitMQ because it's running low on
|
373
|
-
# RAM, disk space, or other resource; false otherwise
|
374
|
-
# @see #on_blocked
|
375
|
-
# @see #on_unblocked
|
376
|
-
def blocked?
|
377
|
-
@blocked
|
378
|
-
end
|
379
|
-
|
380
|
-
# Parses an amqp[s] URI into a hash that {Bunny::Session#initialize} accepts.
|
381
|
-
#
|
382
|
-
# @param [String] uri amqp or amqps URI to parse
|
383
|
-
# @return [Hash] Parsed URI as a hash
|
384
|
-
def self.parse_uri(uri)
|
385
|
-
AMQ::Settings.parse_amqp_url(uri)
|
386
|
-
end
|
387
333
|
|
388
334
|
#
|
389
335
|
# Implementation
|
@@ -418,21 +364,19 @@ module Bunny
|
|
418
364
|
# @private
|
419
365
|
def close_all_channels
|
420
366
|
@channels.reject {|n, ch| n == 0 || !ch.open? }.each do |_, ch|
|
421
|
-
Bunny::
|
367
|
+
Bunny::Timer.timeout(@transport.disconnect_timeout, ClientTimeout) { ch.close }
|
422
368
|
end
|
423
369
|
end
|
424
370
|
|
425
371
|
# @private
|
426
372
|
def close_connection(sync = true)
|
427
|
-
|
428
|
-
@transport.send_frame(AMQ::Protocol::Connection::Close.encode(200, "Goodbye", 0, 0))
|
373
|
+
@transport.send_frame(AMQ::Protocol::Connection::Close.encode(200, "Goodbye", 0, 0))
|
429
374
|
|
430
|
-
|
431
|
-
|
375
|
+
maybe_shutdown_heartbeat_sender
|
376
|
+
@status = :not_connected
|
432
377
|
|
433
|
-
|
434
|
-
|
435
|
-
end
|
378
|
+
if sync
|
379
|
+
@last_connection_close_ok = wait_on_continuations
|
436
380
|
end
|
437
381
|
end
|
438
382
|
|
@@ -448,11 +392,16 @@ module Bunny
|
|
448
392
|
@last_connection_error = instantiate_connection_level_exception(method)
|
449
393
|
@continuations.push(method)
|
450
394
|
|
451
|
-
|
395
|
+
raise @last_connection_error
|
452
396
|
when AMQ::Protocol::Connection::CloseOk then
|
453
397
|
@last_connection_close_ok = method
|
454
398
|
begin
|
455
399
|
@continuations.clear
|
400
|
+
|
401
|
+
reader_loop.stop
|
402
|
+
@reader_loop = nil
|
403
|
+
|
404
|
+
@transport.close
|
456
405
|
rescue StandardError => e
|
457
406
|
@logger.error e.class.name
|
458
407
|
@logger.error e.message
|
@@ -666,40 +615,7 @@ module Bunny
|
|
666
615
|
|
667
616
|
# @private
|
668
617
|
def maybe_shutdown_reader_loop
|
669
|
-
if @reader_loop
|
670
|
-
@reader_loop.stop
|
671
|
-
if threaded?
|
672
|
-
# this is the easiest way to wait until the loop
|
673
|
-
# is guaranteed to have terminated
|
674
|
-
@reader_loop.raise(ShutdownSignal)
|
675
|
-
# joining the thread here may take forever
|
676
|
-
# on JRuby because sun.nio.ch.KQueueArrayWrapper#kevent0 is
|
677
|
-
# a native method that cannot be (easily) interrupted.
|
678
|
-
# So we use this ugly hack or else our test suite takes forever
|
679
|
-
# to run on JRuby (a new connection is opened/closed per example). MK.
|
680
|
-
if defined?(JRUBY_VERSION)
|
681
|
-
sleep 0.075
|
682
|
-
else
|
683
|
-
@reader_loop.join
|
684
|
-
end
|
685
|
-
else
|
686
|
-
# single threaded mode, nothing to do. MK.
|
687
|
-
end
|
688
|
-
end
|
689
|
-
|
690
|
-
@reader_loop = nil
|
691
|
-
end
|
692
|
-
|
693
|
-
# @private
|
694
|
-
def close_transport
|
695
|
-
begin
|
696
|
-
@transport.close
|
697
|
-
rescue StandardError => e
|
698
|
-
@logger.error "Exception when closing transport:"
|
699
|
-
@logger.error e.class.name
|
700
|
-
@logger.error e.message
|
701
|
-
@logger.error e.backtrace
|
702
|
-
end
|
618
|
+
@reader_loop.stop if @reader_loop
|
703
619
|
end
|
704
620
|
|
705
621
|
# @private
|
data/lib/bunny/socket.rb
CHANGED
@@ -14,7 +14,7 @@ module Bunny
|
|
14
14
|
READ_RETRY_EXCEPTION_CLASSES << IO::WaitReadable if IO.const_defined?(:WaitReadable)
|
15
15
|
|
16
16
|
def self.open(host, port, options = {})
|
17
|
-
Timeout.timeout(options[:socket_timeout]
|
17
|
+
Timeout.timeout(options[:socket_timeout]) do
|
18
18
|
sock = new(host, port)
|
19
19
|
if Socket.constants.include?('TCP_NODELAY') || Socket.constants.include?(:TCP_NODELAY)
|
20
20
|
sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
|
data/lib/bunny/transport.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "socket"
|
2
2
|
require "thread"
|
3
|
-
require "monitor"
|
4
3
|
|
5
4
|
begin
|
6
5
|
require "openssl"
|
@@ -41,15 +40,7 @@ module Bunny
|
|
41
40
|
@tls_certificate = opts[:tls_certificate] || opts[:ssl_cert_string]
|
42
41
|
@tls_key = opts[:tls_key] || opts[:ssl_key_string]
|
43
42
|
@tls_certificate_store = opts[:tls_certificate_store]
|
44
|
-
|
45
|
-
default_ca_file = ENV[OpenSSL::X509::DEFAULT_CERT_FILE_ENV] || OpenSSL::X509::DEFAULT_CERT_FILE
|
46
|
-
default_ca_path = ENV[OpenSSL::X509::DEFAULT_CERT_DIR_ENV] || OpenSSL::X509::DEFAULT_CERT_DIR
|
47
|
-
@tls_ca_certificates = opts.fetch(:tls_ca_certificates, [
|
48
|
-
default_ca_file,
|
49
|
-
File.join(default_ca_path, 'ca-certificates.crt'), # Ubuntu/Debian
|
50
|
-
File.join(default_ca_path, 'ca-bundle.crt'), # Amazon Linux & Fedora/RHEL
|
51
|
-
File.join(default_ca_path, 'ca-bundle.pem') # OpenSUSE
|
52
|
-
])
|
43
|
+
@tls_ca_certificates = opts.fetch(:tls_ca_certificates, [])
|
53
44
|
@verify_peer = opts[:verify_ssl] || opts[:verify_peer]
|
54
45
|
|
55
46
|
@read_write_timeout = opts[:socket_timeout] || 3
|
@@ -58,7 +49,7 @@ module Bunny
|
|
58
49
|
@connect_timeout = nil if @connect_timeout == 0
|
59
50
|
@disconnect_timeout = @read_write_timeout || @connect_timeout
|
60
51
|
|
61
|
-
@writes_mutex =
|
52
|
+
@writes_mutex = Mutex.new
|
62
53
|
|
63
54
|
maybe_initialize_socket
|
64
55
|
prepare_tls_context if @tls_enabled
|
@@ -112,7 +103,7 @@ module Bunny
|
|
112
103
|
def write(data)
|
113
104
|
begin
|
114
105
|
if @read_write_timeout
|
115
|
-
Bunny::
|
106
|
+
Bunny::Timer.timeout(@read_write_timeout, Bunny::ClientTimeout) do
|
116
107
|
if open?
|
117
108
|
@writes_mutex.synchronize { @socket.write(data) }
|
118
109
|
@socket.flush
|
@@ -250,12 +241,12 @@ module Bunny
|
|
250
241
|
|
251
242
|
def initialize_socket
|
252
243
|
begin
|
253
|
-
@socket = Bunny::
|
244
|
+
@socket = Bunny::Timer.timeout(@connect_timeout, ConnectionTimeout) do
|
254
245
|
Bunny::Socket.open(@host, @port,
|
255
246
|
:keepalive => @opts[:keepalive],
|
256
247
|
:socket_timeout => @connect_timeout)
|
257
248
|
end
|
258
|
-
rescue StandardError,
|
249
|
+
rescue StandardError, ConnectionTimeout => e
|
259
250
|
@status = :not_connected
|
260
251
|
raise Bunny::TCPConnectionFailed.new(e, self.hostname, self.port)
|
261
252
|
end
|
@@ -320,24 +311,14 @@ module Bunny
|
|
320
311
|
end
|
321
312
|
|
322
313
|
def initialize_tls_context(ctx)
|
323
|
-
ctx.cert = OpenSSL::X509::Certificate.new(@tls_certificate)
|
324
|
-
ctx.key = OpenSSL::PKey::RSA.new(@tls_key)
|
314
|
+
ctx.cert = OpenSSL::X509::Certificate.new(@tls_certificate)
|
315
|
+
ctx.key = OpenSSL::PKey::RSA.new(@tls_key)
|
325
316
|
ctx.cert_store = if @tls_certificate_store
|
326
317
|
@tls_certificate_store
|
327
318
|
else
|
328
319
|
initialize_tls_certificate_store(@tls_ca_certificates)
|
329
320
|
end
|
330
321
|
|
331
|
-
if !@tls_certificate
|
332
|
-
@logger.warn <<-MSG
|
333
|
-
Using TLS but no client certificate is provided! If RabbitMQ is configured to verify peer
|
334
|
-
certificate, connection upgrade will fail!
|
335
|
-
MSG
|
336
|
-
end
|
337
|
-
if @tls_certificate && !@tls_key
|
338
|
-
@logger.warn "Using TLS but no client private key is provided!"
|
339
|
-
end
|
340
|
-
|
341
322
|
# setting TLS/SSL version only works correctly when done
|
342
323
|
# vis set_params. MK.
|
343
324
|
ctx.set_params(:ssl_version => @opts.fetch(:tls_protocol, DEFAULT_TLS_PROTOCOL))
|
@@ -347,11 +328,6 @@ module Bunny
|
|
347
328
|
end
|
348
329
|
|
349
330
|
def initialize_tls_certificate_store(certs)
|
350
|
-
certs = certs.select { |path| File.readable? path }
|
351
|
-
@logger.debug "Using CA certificates at #{certs.join(', ')}"
|
352
|
-
if certs.empty?
|
353
|
-
@logger.error "No CA certificates found, add one with :tls_ca_certificates"
|
354
|
-
end
|
355
331
|
OpenSSL::X509::Store.new.tap do |store|
|
356
332
|
certs.each { |path| store.add_file(path) }
|
357
333
|
end
|