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:           @host = host
 75: 
 76:           yield self
 77: 
 78:           invalid_options = options.keys - VALID_OPTIONS
 79: 
 80:           unless invalid_options.empty?
 81:             raise ArgumentError,
 82:               "invalid option(s) to #{self.class}: #{invalid_options.inspect}"
 83:           end
 84: 
 85:           @logger.debug "connecting" if @logger.debug?
 86: 
 87:           @port = options[ :port ] || @default_port
 88:           @socket = timeout( options[:timeout] || 0 ) do
 89:             ( options[:proxy] || @socket_factory ).open( host, @port )
 90:           end
 91: 
 92:           @packet_sender.socket = @socket
 93:           @packet_receiver.socket = @socket
 94: 
 95:           @kex_info = {
 96:             :client_version_string => self.class.version,
 97:             :server_version_string =>
 98:               @version_negotiator.negotiate( @socket, self.class.version ) }
 99: 
100:           @options = options
101:           kexinit
102:         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 114
114:         def client_name
115:           return @hostname if defined? @hostname
116: 
117:           sockaddr = @socket.getsockname
118:           begin
119:             @hostname =
120:               Socket.getnameinfo( sockaddr, Socket::NI_NAMEREQD ).first
121:           rescue
122:             begin
123:               @hostname = Socket.getnameinfo( sockaddr ).first
124:             rescue
125:               begin
126:                 @hostname = Socket.gethostbyname( Socket.gethostname ).first
127:               rescue
128:                 @logger.error "the client ipaddr/name could not be determined"
129:               end
130:             end
131:           end
132: 
133:           return @hostname
134:         end
close()

Closes the connection.

     # File lib/net/ssh/transport/session.rb, line 149
149:         def close
150:           # TODO: send a DISCONNECT message to the server to close gracefully
151:           @socket.close
152:         end
peer()

Returns info about the remote peer

     # File lib/net/ssh/transport/session.rb, line 105
105:         def peer
106:           @peer ||= begin
107:             addr = @socket.getpeername
108:             ip_address = Socket.getnameinfo(addr, Socket::NI_NUMERICHOST | Socket::NI_NUMERICSERV).first
109:             { :ip => ip_address, :port => @port.to_i, :host => @host }
110:           end
111:         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 327
327:         def ping!
328:           send_message [IGNORE, 4, "ping"].pack("cNA4")
329:         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 321
321:         def reader_ready?
322:           IO.select([@socket],nil,nil,0) != nil
323:         end
send_message( message )

Sends the given payload, using the currently configured OutgoingPacketStream.

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