Class | Net::SSH::Transport::Session |
In: |
lib/net/ssh/transport/session.rb
|
Parent: | Object |
algorithm_negotiator | [W] | |
algorithms | [R] | the collection of algorithms currently being used |
ciphers | [W] | |
compressors | [W] | |
decompressors | [W] | |
default_port | [W] | |
hmacs | [W] | |
kexs | [W] | |
logger | [W] | |
packet_receiver | [W] | |
packet_sender | [W] | |
session_id | [R] | the unique session identifier |
socket_factory | [W] | |
version_negotiator | [W] |
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: @logger.debug "connecting" if @logger.debug? 85: 86: @port = options[ :port ] || @default_port 87: @socket = timeout( options[:timeout] || 0 ) do 88: ( options[:proxy] || @socket_factory ).open( host, @port ) 89: end 90: 91: @packet_sender.socket = @socket 92: @packet_receiver.socket = @socket 93: 94: @kex_info = { 95: :client_version_string => self.class.version, 96: :server_version_string => 97: @version_negotiator.negotiate( @socket, self.class.version ) } 98: 99: @options = options 100: kexinit 101: end
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
Returns the name of the client’s host, as reported by the socket.
# File lib/net/ssh/transport/session.rb, line 104 104: def client_name 105: return @hostname if defined? @hostname 106: 107: sockaddr = @socket.getsockname 108: begin 109: @hostname = 110: Socket.getnameinfo( sockaddr, Socket::NI_NAMEREQD ).first 111: rescue 112: begin 113: @hostname = Socket.getnameinfo( sockaddr ).first 114: rescue 115: begin 116: @hostname = Socket.gethostbyname( Socket.gethostname ).first 117: rescue 118: @logger.error "the client ipaddr/name could not be determined" 119: end 120: end 121: end 122: 123: return @hostname 124: end
Closes the connection.
# File lib/net/ssh/transport/session.rb, line 139 139: def close 140: # TODO: send a DISCONNECT message to the server to close gracefully 141: @socket.close 142: end
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 317 317: def ping! 318: send_message [IGNORE, 4, "ping"].pack("cNA4") 319: end
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 311 311: def reader_ready? 312: IO.select([@socket],nil,nil,0) != nil 313: end
Sends the given payload, using the currently configured OutgoingPacketStream.
# File lib/net/ssh/transport/session.rb, line 300 300: def send_message( message ) 301: if @logger.debug? 302: @logger.debug "sending message >>#{message.to_s.inspect}<<" 303: end 304: 305: @packet_sender.send message 306: end
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 234 234: def wait_for_message 235: buffer = type = nil 236: 237: if @saved_message 238: type, buffer = @saved_message 239: @logger.debug "returning saved message: #{type}" if @logger.debug? 240: @saved_message = nil 241: else 242: loop do 243: if @logger.debug? 244: @logger.debug "waiting for packet from server..." 245: end 246: 247: buffer = @packet_receiver.get 248: next unless buffer 249: 250: type = buffer.read_byte 251: @logger.debug "got packet of type #{type}" if @logger.debug? 252: 253: case type 254: when DISCONNECT 255: reason_code = buffer.read_long 256: description = buffer.read_string 257: language = buffer.read_string 258: raise Net::SSH::Transport::Disconnect, 259: "disconnected: #{description} (#{reason_code})" 260: 261: when IGNORE 262: # do nothing 263: @logger.info "received IGNORE message " + 264: "(#{buffer.read_string.inspect})" if @logger.debug? 265: 266: when DEBUG 267: # do nothing 268: @logger.info "received DEBUG message" if @logger.debug? 269: always_display = buffer.read_bool 270: message = buffer.read_string 271: language = buffer.read_string 272: if always_display 273: @logger.warn "#{message} (#{language})" if @logger.warn? 274: else 275: @logger.debug "#{message} (#{language})" if @logger.debug? 276: end 277: 278: when KEXINIT 279: # unless we're already doing a key-exchange, do key 280: # re-exchange 281: if !@doing_kexinit 282: @logger.info "re-key requested" if @logger.info? 283: @saved_message = [ type, buffer ] 284: kexinit 285: else 286: break 287: end 288: 289: else 290: break 291: end 292: end 293: end 294: 295: return type, buffer 296: end