Represents a low-level SSH session, at the transport protocol level. This handles the algorithm negotiation and key exchange for any SSH connection.

Methods
Included Modules
Constants
NAME = "Ruby/Net::SSH"
  The name that Net::SSH reports for itself
PROTOCOL = "SSH-2.0"
  The SSH protocol supported by Net::SSH.
VALID_OPTIONS = [ :port, :host_key, :kex, :encryption, :hmac, :compression, :languages, :compression_level, :proxy ]
Attributes
[W] algorithm_negotiator
[R] algorithms the collection of algorithms currently being used
[W] ciphers
[W] compressors
[W] decompressors
[W] default_port
[W] hmacs
[W] kexs
[W] logger
[W] packet_receiver
[W] packet_sender
[R] session_id the unique session identifier
[W] socket_factory
[W] version_negotiator
Public Class methods
new( host, options={} ) {|self| ...}

Create a new connection to the given host. This will negotiate the algorithms to use and exchange the keys. A block must be given. The uninitialized self will be passed to the block, so that dependencies may be injected.

    # File lib/net/ssh/transport/session.rb, line 69
69:         def initialize( host, options={} )
70:           @saved_message = nil
71:           @session_id = nil
72: 
73:           yield self
74: 
75:           invalid_options = options.keys - VALID_OPTIONS
76: 
77:           unless invalid_options.empty?
78:             raise ArgumentError,
79:               "invalid option(s) to #{self.class}: #{invalid_options.inspect}"
80:           end
81: 
82:           @port = options[ :port ] || @default_port
83:           @socket = ( options[:proxy] || @socket_factory ).open( host, @port )
84: 
85:           @packet_sender.socket = @socket
86:           @packet_receiver.socket = @socket
87: 
88:           @kex_info = {
89:             :client_version_string => self.class.version,
90:             :server_version_string =>
91:               @version_negotiator.negotiate( @socket, self.class.version ) }
92: 
93:           @options = options
94:           kexinit
95:         end
version()

Returns the version string of this client.

    # File lib/net/ssh/transport/session.rb, line 58
58:         def self.version
59:           "#{PROTOCOL}-#{NAME}_#{Net::SSH::Version::STRING}"
60:         end
Public Instance methods
client_name()

Returns the name of the client’s host, as reported by the socket.

     # File lib/net/ssh/transport/session.rb, line 98
 98:         def client_name
 99:           return @hostname if defined? @hostname
100: 
101:           sockaddr = @socket.getsockname
102:           begin
103:             @hostname =
104:               Socket.getnameinfo( sockaddr, Socket::NI_NAMEREQD ).first
105:           rescue
106:             begin
107:               @hostname = Socket.getnameinfo( sockaddr ).first
108:             rescue
109:               begin
110:                 @hostname = Socket.gethostbyname( Socket.gethostname ).first
111:               rescue
112:                 @logger.error "the client ipaddr/name could not be determined"
113:               end
114:             end
115:           end
116: 
117:           return @hostname
118:         end
close()

Closes the connection.

     # File lib/net/ssh/transport/session.rb, line 133
133:         def close
134:           # TODO: send a DISCONNECT message to the server to close gracefully
135:           @socket.close
136:         end
reader_ready?()

Returns true if there are bytes to be read on the socket. Note that this only means there is an encrypted packet ready to be read, not that there is data available to any particular SSH channel.

     # File lib/net/ssh/transport/session.rb, line 305
305:         def reader_ready?
306:           IO.select([@socket],nil,nil,0) != nil
307:         end
send_message( message )

Sends the given payload, using the currently configured OutgoingPacketStream.

     # File lib/net/ssh/transport/session.rb, line 294
294:         def send_message( message )
295:           if @logger.debug?
296:             @logger.debug "sending message >>#{message.to_s.inspect}<<"
297:           end
298: 
299:           @packet_sender.send message
300:         end
wait_for_message()

Waits for the next message from the server, handling common requests like DISCONNECT, IGNORE, DEBUG, and KEXINIT in the background. The next message is returned as a [ type, buffer ] tuple, where the buffer is a Net::SSH::Util::ReaderBuffer.

     # File lib/net/ssh/transport/session.rb, line 228
228:         def wait_for_message
229:           buffer = type = nil
230: 
231:           if @saved_message
232:             type, buffer = @saved_message
233:             @logger.debug "returning saved message: #{type}" if @logger.debug?
234:             @saved_message = nil
235:           else
236:             loop do
237:               if @logger.debug?
238:                 @logger.debug "waiting for packet from server..."
239:               end
240: 
241:               buffer = @packet_receiver.get
242:               next unless buffer
243: 
244:               type = buffer.read_byte
245:               @logger.debug "got packet of type #{type}" if @logger.debug?
246: 
247:               case type
248:                 when DISCONNECT
249:                   reason_code = buffer.read_long
250:                   description = buffer.read_string
251:                   language = buffer.read_string
252:                   raise Net::SSH::Transport::Disconnect,
253:                     "disconnected: #{description} (#{reason_code})"
254: 
255:                 when IGNORE
256:                   # do nothing
257:                   @logger.info "received IGNORE message " +
258:                     "(#{buffer.read_string.inspect})" if @logger.debug?
259: 
260:                 when DEBUG
261:                   # do nothing
262:                   @logger.info "received DEBUG message" if @logger.debug?
263:                   always_display = buffer.read_bool
264:                   message = buffer.read_string
265:                   language = buffer.read_string
266:                   if always_display
267:                     @logger.warn "#{message} (#{language})" if @logger.warn?
268:                   else
269:                     @logger.debug "#{message} (#{language})" if @logger.debug?
270:                   end
271: 
272:                 when KEXINIT
273:                   # unless we're already doing a key-exchange, do key
274:                   # re-exchange
275:                   if !@doing_kexinit
276:                     @logger.info "re-key requested" if @logger.info?
277:                     @saved_message = [ type, buffer ]
278:                     kexinit
279:                   else
280:                     break
281:                   end
282: 
283:                 else
284:                   break
285:               end
286:             end
287:           end
288: 
289:           return type, buffer
290:         end

[Validate]