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, :timeout ]
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 71
71:         def initialize( host, options={} )
72:           @saved_message = nil
73:           @session_id = nil
74: 
75:           yield self
76: 
77:           invalid_options = options.keys - VALID_OPTIONS
78: 
79:           unless invalid_options.empty?
80:             raise ArgumentError,
81:               "invalid option(s) to #{self.class}: #{invalid_options.inspect}"
82:           end
83: 
84:           @port = options[ :port ] || @default_port
85:           @socket = timeout( options[:timeout] || 0 ) do
86:             ( options[:proxy] || @socket_factory ).open( host, @port )
87:           end
88: 
89:           @packet_sender.socket = @socket
90:           @packet_receiver.socket = @socket
91: 
92:           @kex_info = {
93:             :client_version_string => self.class.version,
94:             :server_version_string =>
95:               @version_negotiator.negotiate( @socket, self.class.version ) }
96: 
97:           @options = options
98:           kexinit
99:         end
version()

Returns the version string of this client.

    # File lib/net/ssh/transport/session.rb, line 59
59:         def self.version
60:           "#{PROTOCOL}-#{NAME}_#{Net::SSH::Version::STRING}"
61:         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 102
102:         def client_name
103:           return @hostname if defined? @hostname
104: 
105:           sockaddr = @socket.getsockname
106:           begin
107:             @hostname =
108:               Socket.getnameinfo( sockaddr, Socket::NI_NAMEREQD ).first
109:           rescue
110:             begin
111:               @hostname = Socket.getnameinfo( sockaddr ).first
112:             rescue
113:               begin
114:                 @hostname = Socket.gethostbyname( Socket.gethostname ).first
115:               rescue
116:                 @logger.error "the client ipaddr/name could not be determined"
117:               end
118:             end
119:           end
120: 
121:           return @hostname
122:         end
close()

Closes the connection.

     # File lib/net/ssh/transport/session.rb, line 137
137:         def close
138:           # TODO: send a DISCONNECT message to the server to close gracefully
139:           @socket.close
140:         end
ping!()

Sends an IGNORE packet to the server, as a way to ping the connection and make sure the server knows the client is still active.

     # File lib/net/ssh/transport/session.rb, line 315
315:         def ping!
316:           send_message [IGNORE, 4, "ping"].pack("cNA4")
317:         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 309
309:         def reader_ready?
310:           IO.select([@socket],nil,nil,0) != nil
311:         end
send_message( message )

Sends the given payload, using the currently configured OutgoingPacketStream.

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