class Mongo::Server::Connection

This class models the socket connections for servers and their behavior.

@since 2.0.0

Constants

PING

The ping command.

@since 2.1.0

@deprecated No longer necessary with Server Selection specification.

PING_BYTES

The ping message as raw bytes.

@since 2.1.0

@deprecated No longer necessary with Server Selection specification.

PING_MESSAGE

Ping message.

@since 2.1.0

@deprecated No longer necessary with Server Selection specification.

PING_OP_MSG

The ping command for an OP_MSG (server versions >= 3.6).

@since 2.5.0

@deprecated No longer necessary with Server Selection specification.

PING_OP_MSG_BYTES

The ping OP_MSG message as raw bytes (server versions >= 3.6).

@since 2.5.0

@deprecated No longer necessary with Server Selection specification.

PING_OP_MSG_MESSAGE

Ping message as an OP_MSG (server versions >= 3.6).

@since 2.5.0

@deprecated No longer necessary with Server Selection specification.

Attributes

last_checkin[R]

The last time the connection was checked back into a pool.

@since 2.5.0

Public Class Methods

new(server, options = {}) click to toggle source

Creates a new connection object to the specified target address with the specified options.

The constructor does not perform any I/O (and thus does not create sockets, handshakes nor authenticates); call connect! method on the connection object to create the network connection.

@api private

@example Create the connection.

Connection.new(server)

@note Connection must never be directly instantiated outside of a

Server.

@param [ Mongo::Server ] server The server the connection is for. @param [ Hash ] options The connection options.

@option options [ Integer ] :generation Connection pool's generation

for this connection.

@since 2.0.0

# File lib/mongo/server/connection.rb, line 91
def initialize(server, options = {})
  @monitoring = server.monitoring
  @options = options.freeze
  @server = server
  @ssl_options = options.select { |k, v| k.to_s.start_with?(SSL) }.freeze
  @socket = nil
  @last_checkin = nil
  @auth_mechanism = nil
  @pid = Process.pid
end

Public Instance Methods

connect!() click to toggle source

Establishes a network connection to the target address.

If the connection is already established, this method does nothing.

@example Connect to the host.

connection.connect!

@note This method mutates the connection class by setting a socket if

one previously did not exist.

@return [ true ] If the connection succeeded.

@since 2.0.0

# File lib/mongo/server/connection.rb, line 129
def connect!
  unless @socket
    socket = address.socket(socket_timeout, ssl_options,
      connect_timeout: address.connect_timeout)
    handshake!(socket)
    pending_connection = PendingConnection.new(socket, @server, monitoring, options)
    authenticate!(pending_connection)
    # When @socket is assigned, the socket should have handshaken and
    # authenticated and be usable.
    @socket = socket
  end
  true
end
disconnect!() click to toggle source

Disconnect the connection.

@example Disconnect from the host.

connection.disconnect!

@note This method mutates the connection by setting the socket to nil

if the closing succeeded.

@return [ true ] If the disconnect succeeded.

@since 2.0.0

# File lib/mongo/server/connection.rb, line 154
def disconnect!
  @auth_mechanism = nil
  @last_checkin = nil
  if socket
    socket.close
    @socket = nil
  end
  true
end
generation() click to toggle source

Connection pool generation from which this connection was created. May be nil.

@since 2.7.0 @api private

# File lib/mongo/server/connection.rb, line 112
def generation
  options[:generation]
end
ping() click to toggle source

Ping the connection to see if the server is responding to commands. This is non-blocking on the server side.

@example Ping the connection.

connection.ping

@note This uses a pre-serialized ping message for optimization.

@return [ true, false ] If the server is accepting connections.

@since 2.1.0

@deprecated No longer necessary with Server Selection specification.

# File lib/mongo/server/connection.rb, line 177
def ping
  bytes = features.op_msg_enabled? ? PING_OP_MSG_BYTES : PING_BYTES
  ensure_connected do |socket|
    socket.write(bytes)
    reply = Protocol::Message.deserialize(socket, max_message_size)
    reply.documents[0][Operation::Result::OK] == 1
  end
end
record_checkin!() click to toggle source

Record the last checkin time.

@example Record the checkin time on this connection.

connection.record_checkin!

@return [ self ]

@since 2.5.0

# File lib/mongo/server/connection.rb, line 208
def record_checkin!
  @last_checkin = Time.now
  self
end
socket_timeout() click to toggle source

Get the timeout to execute an operation on a socket.

@example Get the timeout to execute an operation on a socket.

connection.timeout

@return [ Float ] The operation timeout in seconds.

@since 2.0.0

# File lib/mongo/server/connection.rb, line 194
def socket_timeout
  @timeout ||= options[:socket_timeout]
end
Also aliased as: timeout
timeout()

@deprecated Please use :socket_timeout instead. Will be removed in 3.0.0

Alias for: socket_timeout

Private Instance Methods

authenticate!(pending_connection) click to toggle source
# File lib/mongo/server/connection.rb, line 279
def authenticate!(pending_connection)
  if options[:user] || options[:auth_mech]
    user = Auth::User.new(Options::Redacted.new(:auth_mech => default_mechanism).merge(options))
    @server.handle_auth_failure! do
      begin
        Auth.get(user).login(pending_connection)
      rescue => e
        log_warn("Failed to handshake with #{address}: #{e.class}: #{e}")
        raise
      end
    end
  end
end
default_mechanism() click to toggle source
# File lib/mongo/server/connection.rb, line 293
def default_mechanism
  @auth_mechanism || (@server.features.scram_sha_1_enabled? ? :scram : :mongodb_cr)
end
deliver(message) click to toggle source
Calls superclass method
# File lib/mongo/server/connection.rb, line 297
def deliver(message)
  begin
    super
  # Important: timeout errors are not handled here
  rescue Error::SocketError
    @server.unknown!
    @server.pool.disconnect!
    raise
  end
end
handshake!(socket) click to toggle source
# File lib/mongo/server/connection.rb, line 215
def handshake!(socket)
  unless socket
    raise Error::HandshakeError, "Cannot handshake because there is no usable socket"
  end

  response = average_rtt = nil
  @server.handle_handshake_failure! do
    begin
      response, exc, rtt, average_rtt =
        @server.monitor.round_trip_time_averager.measure do
          socket.write(app_metadata.ismaster_bytes)
          Protocol::Message.deserialize(socket, max_message_size).documents[0]
        end

      if exc
        raise exc
      end
    rescue => e
      log_warn("Failed to handshake with #{address}: #{e.class}: #{e}")
      raise
    end
  end

  post_handshake(response, average_rtt)
end
post_handshake(response, average_rtt) click to toggle source

This is a separate method to keep the nesting level down.

# File lib/mongo/server/connection.rb, line 242
def post_handshake(response, average_rtt)
  if response["ok"] == 1
    # Auth mechanism is entirely dependent on the contents of
    # ismaster response *for this connection*.
    # Ismaster received by the monitoring connection should advertise
    # the same wire protocol, but if it doesn't, we use whatever
    # the monitoring connection advertised for filling out the
    # server description and whatever the non-monitoring connection
    # (that's this one) advertised for performing auth on that
    # connection.
    @auth_mechanism = if response['saslSupportedMechs']
      if response['saslSupportedMechs'].include?(Mongo::Auth::SCRAM::SCRAM_SHA_256_MECHANISM)
        :scram256
      else
        :scram
      end
    else
      # MongoDB servers < 2.6 are no longer suported.
      # Wire versions should always be returned in ismaster.
      # See also https://jira.mongodb.org/browse/RUBY-1584.
      min_wire_version = response[Description::MIN_WIRE_VERSION]
      max_wire_version = response[Description::MAX_WIRE_VERSION]
      features = Description::Features.new(min_wire_version..max_wire_version)
      if features.scram_sha_1_enabled?
        :scram
      else
        :mongodb_cr
      end
    end
  else
    @auth_mechanism = nil
  end

  new_description = Description.new(address, response, average_rtt)
  @server.monitor.publish(Event::DESCRIPTION_CHANGED, @server.description, new_description)
end