Class: Net::SSH::Connection::Session

### Home Classes Methods

### In Files

- lib/net/ssh/connection/session.rb

### Parent

Object

### Namespace

- CLASS Net::SSH::Connection::Session::NilChannel

### Methods

- ::new
- #[]
- #[]=
- #busy?
- #close
- #closed?
- #exec
- #exec!
- #forward
- #host
- #listen_to
- #loop
- #loop_forever
- #on_global_request
- #on_open_channel
- #open_channel
- #postprocess
- #preprocess
- #process
- #send_global_request
- #send_message
- #shutdown!
- #stop_listening_to

### Included Modules

- Net::SSH::Connection::Constants
- Net::SSH::Loggable

### Files

- README.rdoc

### Class/Module Index

Quicksearch

- Net
- Net::SSH
- Net::SSH::Authentication
- Net::SSH::Authentication::Agent
- Net::SSH::Authentication::Agent::Comment
- Net::SSH::Authentication::AgentError
- Net::SSH::Authentication::AgentNotAvailable
- Net::SSH::Authentication::Constants
- Net::SSH::Authentication::DisallowedMethod
- Net::SSH::Authentication::KeyManager
- Net::SSH::Authentication::KeyManagerError
- Net::SSH::Authentication::Methods
- Net::SSH::Authentication::Methods::Abstract
- Net::SSH::Authentication::Methods::Hostbased
- Net::SSH::Authentication::Methods::KeyboardInteractive
- Net::SSH::Authentication::Methods::None
- Net::SSH::Authentication::Methods::Password
- Net::SSH::Authentication::Methods::Publickey
- Net::SSH::Authentication::Session
- Net::SSH::AuthenticationFailed
- Net::SSH::Buffer
- Net::SSH::ChannelOpenFailed
- Net::SSH::ChannelRequestFailed
- Net::SSH::Compat
- Net::SSH::Config
- Net::SSH::Connection
- Net::SSH::Connection::Channel
- Net::SSH::Connection::Constants
- Net::SSH::Connection::Session
- Net::SSH::Connection::Session::NilChannel
- Net::SSH::Connection::Term
- Net::SSH::ConnectionTimeout
- Net::SSH::Disconnect
- Net::SSH::Exception
- Net::SSH::HostKeyError
- Net::SSH::HostKeyMismatch
- Net::SSH::HostKeyUnknown
- Net::SSH::KeyFactory
- Net::SSH::KnownHosts
- Net::SSH::Loggable
- Net::SSH::Packet
- Net::SSH::PromptMethods
- Net::SSH::PromptMethods::Clear
- Net::SSH::PromptMethods::Highline
- Net::SSH::PromptMethods::Termios
- Net::SSH::Proxy
- Net::SSH::Proxy::Command
- Net::SSH::Proxy::ConnectError
- Net::SSH::Proxy::Error
- Net::SSH::Proxy::HTTP
- Net::SSH::Proxy::SOCKS4
- Net::SSH::Proxy::SOCKS5
- Net::SSH::Proxy::UnauthorizedError
- Net::SSH::Test
- Net::SSH::Test::Channel
- Net::SSH::Test::Extensions
- Net::SSH::Test::Extensions::BufferedIo
- Net::SSH::Test::Extensions::Channel
- Net::SSH::Test::Extensions::IO
- Net::SSH::Test::Extensions::IO::ClassMethods
- Net::SSH::Test::Extensions::PacketStream
- Net::SSH::Test::Kex
- Net::SSH::Test::LocalPacket
- Net::SSH::Test::Packet
- Net::SSH::Test::RemotePacket
- Net::SSH::Test::Script
- Net::SSH::Test::Socket
- Net::SSH::Transport
- Net::SSH::Transport::Algorithms
- Net::SSH::Transport::CTR
- Net::SSH::Transport::CipherFactory
- Net::SSH::Transport::Constants
- Net::SSH::Transport::HMAC
- Net::SSH::Transport::HMAC::Abstract
- Net::SSH::Transport::HMAC::MD5
- Net::SSH::Transport::HMAC::MD5_96
- Net::SSH::Transport::HMAC::None
- Net::SSH::Transport::HMAC::RIPEMD160
- Net::SSH::Transport::HMAC::SHA1
- Net::SSH::Transport::HMAC::SHA1_96
- Net::SSH::Transport::HMAC::SHA2_256
- Net::SSH::Transport::HMAC::SHA2_256_96
- Net::SSH::Transport::HMAC::SHA2_512
- Net::SSH::Transport::HMAC::SHA2_512_96
- Net::SSH::Transport::IdentityCipher
- Net::SSH::Transport::Kex
- Net::SSH::Transport::Kex::DiffieHellmanGroup14SHA1
- Net::SSH::Transport::Kex::DiffieHellmanGroup1SHA1
- Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA1
- Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA256
- Net::SSH::Transport::Kex::EcdhSHA2NistP256
- Net::SSH::Transport::Kex::EcdhSHA2NistP384
- Net::SSH::Transport::Kex::EcdhSHA2NistP521
- Net::SSH::Transport::KeyExpander
- Net::SSH::Transport::PacketStream
- Net::SSH::Transport::ServerVersion
- Net::SSH::Transport::Session
- Net::SSH::Transport::State
- Net::SSH::Verifiers
- Net::SSH::Verifiers::Lenient
- Net::SSH::Verifiers::Null
- Net::SSH::Verifiers::Secure
- Net::SSH::Verifiers::Strict
- Net::SSH::Version
- OpenSSL
- OpenSSL::BN
- OpenSSL::PKey
- OpenSSL::PKey::DH
- OpenSSL::PKey::DSA
- OpenSSL::PKey::EC
- OpenSSL::PKey::OpenSSL
- OpenSSL::PKey::OpenSSL::PKey
- OpenSSL::PKey::OpenSSL::PKey::OpenSSL
- OpenSSL::PKey::OpenSSL::PKey::OpenSSL::PKey
- OpenSSL::PKey::OpenSSL::PKey::OpenSSL::PKey::ECError
- OpenSSL::PKey::PKey
- OpenSSL::PKey::RSA
- String

No matching classes.

# Net::SSH::Connection::Session

A session class representing the connection service running on top of the SSH transport layer. It manages the creation of channels (see open_channel), and the dispatching of messages to the various channels. It also encapsulates the SSH event loop (via loop and process), and serves as a central point-of-reference for all SSH-related services (e.g. port forwarding, SFTP, SCP, etc.).

You will rarely (if ever) need to instantiate this class directly; rather, you'll almost always use Net::SSH.start to initialize a new network connection, authenticate a user, and return a new connection session, all in one call.

    Net::SSH.start("localhost", "user") do |ssh|
      # 'ssh' is an instance of Net::SSH::Connection::Session
      ssh.exec! "/etc/init.d/some_process start"
    end

### Constants

DEFAULT_IO_SELECT_TIMEOUT

  Default IO.select timeout threshold

MAP

### Attributes

options[R]

The map of options that were used to initialize this instance.

properties[R]

The collection of custom properties for this instance. (See #[] and #[]=).

transport[R]

The underlying transport layer abstraction (see Net::SSH::Transport::Session).

### Public Class Methods

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

Create a new connection service instance atop the given transport layer. Initializes the listeners to be only the underlying socket object.

    # File lib/net/ssh/connection/session.rb, line 65
    def initialize(transport, options={})
      self.logger = transport.logger

      @transport = transport
      @options = options

      @channel_id_counter = -1
      @channels = Hash.new(NilChannel.new(self))
      @listeners = { transport.socket => nil }
      @pending_requests = []
      @channel_open_handlers = {}
      @on_global_request = {}
      @properties = (options[:properties] || {}).dup

      @max_pkt_size = (options.has_key?(:max_pkt_size) ? options[:max_pkt_size] : 0x8000)
      @max_win_size = (options.has_key?(:max_win_size) ? options[:max_win_size] : 0x20000)

      @last_keepalive_sent_at = nil
    end

### Public Instance Methods

[](key) click to toggle source

Retrieves a custom property from this instance. This can be used to store additional state in applications that must manage multiple SSH connections.

    # File lib/net/ssh/connection/session.rb, line 88
    def [](key)
      @properties[key]
    end

[]=(key, value) click to toggle source

Sets a custom property for this instance.

    # File lib/net/ssh/connection/session.rb, line 93
    def []=(key, value)
      @properties[key] = value
    end

busy?(include_invisible=false) click to toggle source

Returns `true` if there are any channels currently active on this session. By default, this will not include "invisible" channels (such as those created by forwarding ports and such), but if you pass a `true` value for `include_invisible`, then those will be counted.

This can be useful for determining whether the event loop should continue to be run.

    ssh.loop { ssh.busy? }

    # File lib/net/ssh/connection/session.rb, line 142
    def busy?(include_invisible=false)
      if include_invisible
        channels.any?
      else
        channels.any? { |id, ch| !ch[:invisible] }
      end
    end

close() click to toggle source

Closes the session gracefully, blocking until all channels have successfully closed, and then closes the underlying transport layer connection.

    # File lib/net/ssh/connection/session.rb, line 115
    def close
      info { "closing remaining channels (#{channels.length} open)" }
      channels.each { |id, channel| channel.close }
      loop(0.1) { channels.any? }
      transport.close
    end

closed?() click to toggle source

Returns true if the underlying transport has been closed. Note that this can be a little misleading, since if the remote server has closed the connection, the local end will still think it is open until the next operation on the socket. Nevertheless, this method can be useful if you just want to know if you have closed the connection.

    # File lib/net/ssh/connection/session.rb, line 108
    def closed?
      transport.closed?
    end

exec(command, &block) click to toggle source

A convenience method for executing a command and interacting with it. If no block is given, all output is printed via $stdout and $stderr. Otherwise, the block is called for each data and extended data packet, with three arguments: the channel object, a symbol indicating the data type (:stdout or :stderr), and the data (as a string).

Note that this method returns immediately, and requires an event loop (see Session#loop) in order for the command to actually execute.

This is effectively identical to calling open_channel, and then Net::SSH::Connection::Channel#exec, and then setting up the channel callbacks. However, for most uses, this will be sufficient.

    ssh.exec "grep something /some/files" do |ch, stream, data|
      if stream == :stderr
        puts "ERROR: #{data}"
      else
        puts data
      end
    end

    # File lib/net/ssh/connection/session.rb, line 328
    def exec(command, &block)
      open_channel do |channel|
        channel.exec(command) do |ch, success|
          raise "could not execute command: #{command.inspect}" unless success

          channel.on_data do |ch2, data|
            if block
              block.call(ch2, :stdout, data)
            else
              $stdout.print(data)
            end
          end

          channel.on_extended_data do |ch2, type, data|
            if block
              block.call(ch2, :stderr, data)
            else
              $stderr.print(data)
            end
          end
        end
      end
    end

exec!(command, &block) click to toggle source

Same as exec, except this will block until the command finishes. Also, if a block is not given, this will return all output (stdout and stderr) as a single string.

    matches = ssh.exec!("grep something /some/files")

    # File lib/net/ssh/connection/session.rb, line 357
    def exec!(command, &block)
      block ||= Proc.new do |ch, type, data|
        ch[:result] ||= ""
        ch[:result] << data
      end

      channel = exec(command, &block)
      channel.wait

      return channel[:result]
    end

forward() click to toggle source

Returns a reference to the Net::SSH::Service::Forward service, which can be used for forwarding ports over SSH.

    # File lib/net/ssh/connection/session.rb, line 426
    def forward
      @forward ||= Service::Forward.new(self)
    end

host() click to toggle source

Returns the name of the host that was given to the transport layer to connect to.

    # File lib/net/ssh/connection/session.rb, line 99
    def host
      transport.host
    end

listen_to(io, &callback) click to toggle source

Adds an IO object for the event loop to listen to. If a callback is given, it will be invoked when the io is ready to be read, otherwise, the io will merely have its fill method invoked.

Any `io` value passed to this method must have mixed into it the Net::SSH::BufferedIo functionality, typically by calling extend on the object.

The following example executes a process on the remote server, opens a socket to somewhere, and then pipes data from that socket to the remote process' stdin stream:

    channel = ssh.open_channel do |ch|
      ch.exec "/some/process/that/wants/input" do |ch, success|
        abort "can't execute!" unless success

        io = TCPSocket.new(somewhere, port)
        io.extend(Net::SSH::BufferedIo)
        ssh.listen_to(io)

        ch.on_process do
          if io.available > 0
            ch.send_data(io.read_available)
          end
        end

        ch.on_close do
          ssh.stop_listening_to(io)
          io.close
        end
      end
    end

    channel.wait

    # File lib/net/ssh/connection/session.rb, line 414
    def listen_to(io, &callback)
      listeners[io] = callback
    end

loop(wait=nil, &block) click to toggle source

The main event loop. Calls process until process returns false. If a block is given, it is passed to process, otherwise a default proc is used that just returns true if there are any channels active (see busy?). The # `wait` parameter is also passed through to process (where it is interpreted as the maximum number of seconds to wait for IO.select to return).

    # loop for as long as there are any channels active
    ssh.loop

    # loop for as long as there are any channels active, but make sure
    # the event loop runs at least once per 0.1 second
    ssh.loop(0.1)

    # loop until ctrl-C is pressed
    int_pressed = false
    trap("INT") { int_pressed = true }
    ssh.loop(0.1) { not int_pressed }

    # File lib/net/ssh/connection/session.rb, line 167
    def loop(wait=nil, &block)
      running = block || Proc.new { busy? }
      loop_forever { break unless process(wait, &running) }
    end

Also aliased as: loop_forever
loop_forever(wait=nil, &block) click to toggle source

preserve a reference to Kernel#loop

Alias for: loop
on_global_request(type, &block) click to toggle source

Registers a handler to be invoked when the server sends a global request of the given type. The callback receives the request data as the first parameter, and true/false as the second (indicating whether a response is required). If the callback sends the response, it should return :sent. Otherwise, if it returns true, REQUEST_SUCCESS will be sent, and if it returns false, REQUEST_FAILURE will be sent.

    # File lib/net/ssh/connection/session.rb, line 450
    def on_global_request(type, &block)
      old, @on_global_request[type] = @on_global_request[type], block
      old
    end

on_open_channel(type, &block) click to toggle source

Registers a handler to be invoked when the server wants to open a channel on the client. The callback receives the connection object, the new channel object, and the packet itself as arguments, and should raise ChannelOpenFailed if it is unable to open the channel for some reason. Otherwise, the channel will be opened and a confirmation message sent to the server.

This is used by the Net::SSH::Service::Forward service to open a channel when a remote forwarded port receives a connection. However, you are welcome to register handlers for other channel types, as needed.

    # File lib/net/ssh/connection/session.rb, line 440
    def on_open_channel(type, &block)
      channel_open_handlers[type] = block
    end

open_channel(type="session", *extra, &on_confirm) click to toggle source

Requests that a new channel be opened. By default, the channel will be of type "session", but if you know what you're doing you can select any of the channel types supported by the SSH protocol. The `extra` parameters must be even in number and conform to the same format as described for Net::SSH::Buffer.from. If a callback is given, it will be invoked when the server confirms that the channel opened successfully. The sole parameter for the callback is the channel object itself.

In general, you'll use open_channel without any arguments; the only time you'd want to set the channel type or pass additional initialization data is if you were implementing an SSH extension.

    channel = ssh.open_channel do |ch|
      ch.exec "grep something /some/files" do |ch, success|
        ...
      end
    end

    channel.wait

    # File lib/net/ssh/connection/session.rb, line 296
    def open_channel(type="session", *extra, &on_confirm)
      local_id = get_next_channel_id

      channel = Channel.new(self, type, local_id, @max_pkt_size, @max_win_size, &on_confirm)
      msg = Buffer.from(:byte, CHANNEL_OPEN, :string, type, :long, local_id,
        :long, channel.local_maximum_window_size,
        :long, channel.local_maximum_packet_size, *extra)
      send_message(msg)

      channels[local_id] = channel
    end

postprocess(readers, writers) click to toggle source

This is called internally as part of process. It loops over the given arrays of reader IO's and writer IO's, processing them as needed, and then calls Net::SSH::Transport::Session#rekey_as_needed to allow the transport layer to rekey. Then returns true.

    # File lib/net/ssh/connection/session.rb, line 231
    def postprocess(readers, writers)
      Array(readers).each do |reader|
        if listeners[reader]
          listeners[reader].call(reader)
        else
          if reader.fill.zero?
            reader.close
            stop_listening_to(reader)
          end
        end
      end

      Array(writers).each do |writer|
        writer.send_pending
      end

      send_keepalive_as_needed(readers, writers)
      transport.rekey_as_needed

      return true
    end

preprocess() click to toggle source

This is called internally as part of process. It dispatches any available incoming packets, and then runs Net::SSH::Connection::Channel#process for any active channels. If a block is given, it is invoked at the start of the method and again at the end, and if the block ever returns false, this method returns false. Otherwise, it returns true.

    # File lib/net/ssh/connection/session.rb, line 219
    def preprocess
      return false if block_given? && !yield(self)
      dispatch_incoming_packets
      channels.each { |id, channel| channel.process unless channel.closing? }
      return false if block_given? && !yield(self)
      return true
    end

process(wait=nil, &block) click to toggle source

The core of the event loop. It processes a single iteration of the event loop. If a block is given, it should return false when the processing should abort, which causes process to return false. Otherwise, process returns true. The session itself is yielded to the block as its only argument.

If `wait` is nil (the default), this method will block until any of the monitored IO objects are ready to be read from or written to. If you want it to not block, you can pass 0, or you can pass any other numeric value to indicate that it should block for no more than that many seconds. Passing 0 is a good way to poll the connection, but if you do it too frequently it can make your CPU quite busy!

This will also cause all active channels to be processed once each (see Net::SSH::Connection::Channel#on_process).

    # process multiple Net::SSH connections in parallel
    connections = [
      Net::SSH.start("host1", ...),
      Net::SSH.start("host2", ...)
    ]

    connections.each do |ssh|
      ssh.exec "grep something /in/some/files"
    end

    condition = Proc.new { |s| s.busy? }

    loop do
      connections.delete_if { |ssh| !ssh.process(0.1, &condition) }
      break if connections.empty?
    end

    # File lib/net/ssh/connection/session.rb, line 204
    def process(wait=nil, &block)
      return false unless preprocess(&block)

      r = listeners.keys
      w = r.select { |w2| w2.respond_to?(:pending_write?) && w2.pending_write? }
      readers, writers, = Net::SSH::Compat.io_select(r, w, nil, io_select_wait(wait))

      postprocess(readers, writers)
    end

send_global_request(type, *extra, &callback) click to toggle source

Send a global request of the given type. The `extra` parameters must be even in number, and conform to the same format as described for Net::SSH::Buffer.from. If a callback is not specified, the request will not require a response from the server, otherwise the server is required to respond and indicate whether the request was successful or not. This success or failure is indicated by the callback being invoked, with the first parameter being true or false (success, or failure), and the second being the packet itself.

Generally, Net::SSH will manage global requests that need to be sent (e.g. port forward requests and such are handled in the Net::SSH::Service::Forward class, for instance). However, there may be times when you need to send a global request that isn't explicitly handled by Net::SSH, and so this method is available to you.

    ssh.send_global_request("keep-alive@openssh.com")

    # File lib/net/ssh/connection/session.rb, line 269
    def send_global_request(type, *extra, &callback)
      info { "sending global request #{type}" }
      msg = Buffer.from(:byte, GLOBAL_REQUEST, :string, type.to_s, :bool, !callback.nil?, *extra)
      send_message(msg)
      pending_requests << callback if callback
      self
    end

send_message(message) click to toggle source

Enqueues a message to be sent to the server as soon as the socket is available for writing. Most programs will never need to call this, but if you are implementing an extension to the SSH protocol, or if you need to send a packet that Net::SSH does not directly support, you can use this to send it.

    ssh.send_message(Buffer.from(:byte, REQUEST_SUCCESS).to_s)

    # File lib/net/ssh/connection/session.rb, line 376
    def send_message(message)
      transport.enqueue_message(message)
    end

shutdown!() click to toggle source

Performs a "hard" shutdown of the connection. In general, this should never be done, but it might be necessary (in a rescue clause, for instance, when the connection needs to close but you don't know the status of the underlying protocol's state).

    # File lib/net/ssh/connection/session.rb, line 126
    def shutdown!
      transport.shutdown!
    end

stop_listening_to(io) click to toggle source

Removes the given io object from the listeners collection, so that the event loop will no longer monitor it.

    # File lib/net/ssh/connection/session.rb, line 420
    def stop_listening_to(io)
      listeners.delete(io)
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.