bunny 0.10.8 → 1.0.0.pre1
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.
- 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
|