Class: Bunny::Transport
- Inherits:
-
Object
- Object
- Bunny::Transport
- Defined in:
- lib/bunny/transport.rb
Constant Summary collapse
- DEFAULT_CONNECTION_TIMEOUT =
Default TCP connection timeout
30.0- DEFAULT_READ_TIMEOUT =
30.0- DEFAULT_WRITE_TIMEOUT =
30.0- TLS_VERSION_ALIASES =
mimics METHODS_MAP in ssl.rb but also lists TLS 1.3 and string constants
{ TLSv1: OpenSSL::SSL::TLS1_VERSION, TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION, TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION, "1.0": OpenSSL::SSL::TLS1_VERSION, "1.1": OpenSSL::SSL::TLS1_1_VERSION, "1.2": OpenSSL::SSL::TLS1_2_VERSION, OpenSSL::SSL::TLS1_VERSION => OpenSSL::SSL::TLS1_VERSION, OpenSSL::SSL::TLS1_1_VERSION => OpenSSL::SSL::TLS1_1_VERSION, OpenSSL::SSL::TLS1_2_VERSION => OpenSSL::SSL::TLS1_2_VERSION }
Instance Attribute Summary collapse
-
#connect_timeout ⇒ Object
readonly
Returns the value of attribute connect_timeout.
-
#disconnect_timeout ⇒ Object
readonly
Returns the value of attribute disconnect_timeout.
-
#host ⇒ Object
readonly
Returns the value of attribute host.
-
#port ⇒ Object
readonly
Returns the value of attribute port.
-
#read_timeout ⇒ Object
Returns the value of attribute read_timeout.
-
#session ⇒ Object
readonly
Returns the value of attribute session.
-
#socket ⇒ Object
readonly
Returns the value of attribute socket.
-
#tls_ca_certificates ⇒ Object
readonly
Returns the value of attribute tls_ca_certificates.
-
#tls_certificate_path ⇒ Object
readonly
Returns the value of attribute tls_certificate_path.
-
#tls_context ⇒ Object
readonly
Returns the value of attribute tls_context.
-
#tls_key_path ⇒ Object
readonly
Returns the value of attribute tls_key_path.
-
#verify_peer ⇒ Object
readonly
Returns the value of attribute verify_peer.
-
#write_timeout ⇒ Object
readonly
Returns the value of attribute write_timeout.
Class Method Summary collapse
- .ping!(host, port, timeout) ⇒ Object
- .reachable?(host, port, timeout) ⇒ Boolean (also: reacheable?)
Instance Method Summary collapse
- #close(reason = nil) ⇒ Object
- #closed? ⇒ Boolean
- #configure_socket(&block) ⇒ Object
- #configure_tls_context(&block) ⇒ Object
- #connect ⇒ Object
- #connected? ⇒ Boolean
- #flush ⇒ Object
- #hostname ⇒ Object
-
#initialize(session, host, port, opts) ⇒ Transport
constructor
A new instance of Transport.
- #initialize_socket ⇒ Object
- #local_address ⇒ Object
- #maybe_initialize_socket ⇒ Object
- #open? ⇒ Boolean
- #post_initialize_socket ⇒ Object
- #read_fully(count) ⇒ Object
- #read_fully_into(buffer, count) ⇒ Object
-
#read_next_frame(opts = {}) ⇒ Object
Exposed primarily for Bunny::Channel.
- #read_ready?(timeout = nil) ⇒ Boolean
-
#send_frame(frame) ⇒ Object
Sends frame to the peer.
-
#send_frame_without_timeout(frame) ⇒ Object
Sends frame to the peer without timeout control.
- #uses_ssl? ⇒ Boolean (also: #ssl?)
- #uses_tls? ⇒ Boolean (also: #tls?)
-
#write(data) ⇒ Object
Writes data to the socket.
-
#write_without_timeout(data, raise_exceptions = false) ⇒ Object
Writes data to the socket without timeout checks.
Constructor Details
#initialize(session, host, port, opts) ⇒ Transport
Returns a new instance of Transport.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/bunny/transport.rb', line 60 def initialize(session, host, port, opts) @session = session @session_error_handler = opts[:session_error_handler] @host = host @port = port @opts = opts @logger = session.logger @tls_enabled = tls_enabled?(opts) @read_timeout = opts[:read_timeout] || DEFAULT_READ_TIMEOUT @read_timeout = nil if @read_timeout == 0 @write_timeout = opts[:socket_timeout] # Backwards compatibility @write_timeout ||= opts[:write_timeout] || DEFAULT_WRITE_TIMEOUT @write_timeout = nil if @write_timeout == 0 @connect_timeout = self.timeout_from(opts) @connect_timeout = nil if @connect_timeout == 0 @disconnect_timeout = @write_timeout || @read_timeout || @connect_timeout @writes_mutex = @session.mutex_impl.new @socket = nil prepare_tls_context(opts) if @tls_enabled end |
Instance Attribute Details
#connect_timeout ⇒ Object (readonly)
Returns the value of attribute connect_timeout.
52 53 54 |
# File 'lib/bunny/transport.rb', line 52 def connect_timeout @connect_timeout end |
#disconnect_timeout ⇒ Object (readonly)
Returns the value of attribute disconnect_timeout.
52 53 54 |
# File 'lib/bunny/transport.rb', line 52 def disconnect_timeout @disconnect_timeout end |
#host ⇒ Object (readonly)
Returns the value of attribute host.
52 53 54 |
# File 'lib/bunny/transport.rb', line 52 def host @host end |
#port ⇒ Object (readonly)
Returns the value of attribute port.
52 53 54 |
# File 'lib/bunny/transport.rb', line 52 def port @port end |
#read_timeout ⇒ Object
Returns the value of attribute read_timeout.
52 53 54 |
# File 'lib/bunny/transport.rb', line 52 def read_timeout @read_timeout end |
#session ⇒ Object (readonly)
Returns the value of attribute session.
52 53 54 |
# File 'lib/bunny/transport.rb', line 52 def session @session end |
#socket ⇒ Object (readonly)
Returns the value of attribute socket.
52 53 54 |
# File 'lib/bunny/transport.rb', line 52 def socket @socket end |
#tls_ca_certificates ⇒ Object (readonly)
Returns the value of attribute tls_ca_certificates.
53 54 55 |
# File 'lib/bunny/transport.rb', line 53 def tls_ca_certificates @tls_ca_certificates end |
#tls_certificate_path ⇒ Object (readonly)
Returns the value of attribute tls_certificate_path.
53 54 55 |
# File 'lib/bunny/transport.rb', line 53 def tls_certificate_path @tls_certificate_path end |
#tls_context ⇒ Object (readonly)
Returns the value of attribute tls_context.
53 54 55 |
# File 'lib/bunny/transport.rb', line 53 def tls_context @tls_context end |
#tls_key_path ⇒ Object (readonly)
Returns the value of attribute tls_key_path.
53 54 55 |
# File 'lib/bunny/transport.rb', line 53 def tls_key_path @tls_key_path end |
#verify_peer ⇒ Object (readonly)
Returns the value of attribute verify_peer.
53 54 55 |
# File 'lib/bunny/transport.rb', line 53 def verify_peer @verify_peer end |
#write_timeout ⇒ Object (readonly)
Returns the value of attribute write_timeout.
52 53 54 |
# File 'lib/bunny/transport.rb', line 52 def write_timeout @write_timeout end |
Class Method Details
.ping!(host, port, timeout) ⇒ Object
320 321 322 |
# File 'lib/bunny/transport.rb', line 320 def self.ping!(host, port, timeout) raise ConnectionTimeout.new("#{host}:#{port} is unreachable") if !reachable?(host, port, timeout) end |
.reachable?(host, port, timeout) ⇒ Boolean Also known as: reacheable?
303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/bunny/transport.rb', line 303 def self.reachable?(host, port, timeout) begin s = Bunny::SocketImpl.open(host, port, connect_timeout: timeout) true rescue SocketError, Timeout::Error => _e false ensure s.close if s end end |
Instance Method Details
#close(reason = nil) ⇒ Object
222 223 224 |
# File 'lib/bunny/transport.rb', line 222 def close(reason = nil) @socket.close if open? end |
#closed? ⇒ Boolean
230 231 232 |
# File 'lib/bunny/transport.rb', line 230 def closed? !open? end |
#configure_socket(&block) ⇒ Object
146 147 148 |
# File 'lib/bunny/transport.rb', line 146 def configure_socket(&block) block.call(@socket) if @socket end |
#configure_tls_context(&block) ⇒ Object
150 151 152 |
# File 'lib/bunny/transport.rb', line 150 def configure_tls_context(&block) block.call(@tls_context) if @tls_context end |
#connect ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/bunny/transport.rb', line 108 def connect if uses_tls? begin @socket.connect rescue OpenSSL::SSL::SSLError => e @logger.error { "TLS connection failed: #{e.}" } raise e end log_peer_certificate_info(Logger::DEBUG, @socket.peer_cert) log_peer_certificate_chain_info(Logger::DEBUG, @socket.peer_cert_chain) begin @socket.post_connection_check(host) if @verify_peer rescue OpenSSL::SSL::SSLError => e @logger.error do msg = "Peer verification of target server failed: #{e.}. " msg += "Target hostname: #{hostname}, see peer certificate chain details below." msg end log_peer_certificate_info(Logger::ERROR, @socket.peer_cert) log_peer_certificate_chain_info(Logger::ERROR, @socket.peer_cert_chain) raise e end @status = :connected @socket else # no-op end end |
#connected? ⇒ Boolean
142 143 144 |
# File 'lib/bunny/transport.rb', line 142 def connected? :connected == @status && open? end |
#flush ⇒ Object
234 235 236 |
# File 'lib/bunny/transport.rb', line 234 def flush @socket.flush if @socket end |
#hostname ⇒ Object
89 90 91 |
# File 'lib/bunny/transport.rb', line 89 def hostname @host end |
#initialize_socket ⇒ Object
324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/bunny/transport.rb', line 324 def initialize_socket @logger.debug("Using connection timeout of #{@connect_timeout} when connecting to #{@host}:#{@port}") begin @socket = Bunny::SocketImpl.open(@host, @port, keepalive: @opts[:keepalive], connect_timeout: @connect_timeout) rescue StandardError, ClientTimeout => e @status = :not_connected raise Bunny::TCPConnectionFailed.new(e, self.hostname, self.port) end @socket end |
#local_address ⇒ Object
93 94 95 |
# File 'lib/bunny/transport.rb', line 93 def local_address @socket.local_address end |
#maybe_initialize_socket ⇒ Object
338 339 340 |
# File 'lib/bunny/transport.rb', line 338 def maybe_initialize_socket initialize_socket if !@socket || closed? end |
#open? ⇒ Boolean
226 227 228 |
# File 'lib/bunny/transport.rb', line 226 def open? @socket && !@socket.closed? end |
#post_initialize_socket ⇒ Object
342 343 344 345 346 347 348 |
# File 'lib/bunny/transport.rb', line 342 def post_initialize_socket @socket = if uses_tls? and !@socket.is_a?(Bunny::SSLSocketImpl) wrap_in_tls_socket(@socket) else @socket end end |
#read_fully(count) ⇒ Object
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/bunny/transport.rb', line 238 def read_fully(count) begin @socket.read_fully(count, @read_timeout) rescue SystemCallError, Timeout::Error, Bunny::ConnectionError, IOError => e @logger.error "Got an exception when receiving data: #{e.} (#{e.class.name})" close @status = :not_connected if @session.automatically_recover? raise else @session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.}", e)) end end end |
#read_fully_into(buffer, count) ⇒ Object
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/bunny/transport.rb', line 285 def read_fully_into(buffer, count) begin @socket.read_fully_into(buffer, count, @read_timeout) rescue SystemCallError, Timeout::Error, Bunny::ConnectionError, IOError => e @logger.error "Got an exception when receiving data: #{e.} (#{e.class.name})" close @status = :not_connected if @session.automatically_recover? raise else @session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.}", e)) end end buffer end |
#read_next_frame(opts = {}) ⇒ Object
Exposed primarily for Bunny::Channel
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/bunny/transport.rb', line 261 def read_next_frame(opts = {}) @frame_header_buffer ||= String.new(capacity: 7) @frame_header_buffer.clear header = read_fully_into(@frame_header_buffer, 7) type, channel, size = AMQ::Protocol::Frame.decode_header(header) payload = if size > 0 read_fully(size) else '' end frame_end = read_fully(1) # 1) the size is miscalculated if payload.bytesize != size raise BadLengthError.new(size, payload.bytesize) end # 2) the size is OK, but the string doesn't end with FINAL_OCTET raise NoFinalOctetError.new if frame_end != AMQ::Protocol::Frame::FINAL_OCTET AMQ::Protocol::Frame.new(type, payload, channel) end |
#read_ready?(timeout = nil) ⇒ Boolean
254 255 256 257 |
# File 'lib/bunny/transport.rb', line 254 def read_ready?(timeout = nil) io = IO.select([@socket].compact, nil, nil, timeout) io && io[0].include?(@socket) end |
#send_frame(frame) ⇒ Object
Sends frame to the peer.
201 202 203 204 205 206 207 |
# File 'lib/bunny/transport.rb', line 201 def send_frame(frame) if closed? @session.handle_network_failure(ConnectionClosedError.new(frame)) if @session.automatically_recover? else write(frame.encode) end end |
#send_frame_without_timeout(frame) ⇒ Object
Sends frame to the peer without timeout control.
213 214 215 216 217 218 219 |
# File 'lib/bunny/transport.rb', line 213 def send_frame_without_timeout(frame) if closed? @session.handle_network_failure(ConnectionClosedError.new(frame)) if @session.automatically_recover? else write_without_timeout(frame.encode) end end |
#uses_ssl? ⇒ Boolean Also known as: ssl?
102 103 104 |
# File 'lib/bunny/transport.rb', line 102 def uses_ssl? @tls_enabled end |
#uses_tls? ⇒ Boolean Also known as: tls?
97 98 99 |
# File 'lib/bunny/transport.rb', line 97 def uses_tls? @tls_enabled end |
#write(data) ⇒ Object
Writes data to the socket. If read/write timeout was specified the operation will return after that amount of time has elapsed waiting for the socket.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/bunny/transport.rb', line 156 def write(data) return write_without_timeout(data) unless @write_timeout begin if open? @writes_mutex.synchronize do @socket.write_nonblock_fully(data, @write_timeout) end end rescue SystemCallError, Timeout::Error, Bunny::ConnectionError, IOError => e @logger.error "Got an exception when sending data: #{e.} (#{e.class.name})" close @status = :not_connected if @session.automatically_recover? @session.handle_network_failure(e) else @session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.}", e)) end end end |
#write_without_timeout(data, raise_exceptions = false) ⇒ Object
Writes data to the socket without timeout checks
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/bunny/transport.rb', line 179 def write_without_timeout(data, raise_exceptions = false) begin @writes_mutex.synchronize do @socket.write(data) @socket.flush end rescue SystemCallError, Bunny::ConnectionError, IOError => e close raise e if raise_exceptions if @session.automatically_recover? @session.handle_network_failure(e) else @session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.}", e)) end end end |