- add_channel_open_handler
- allocate_channel_id
- channels
- do_channel_close
- do_channel_data
- do_channel_eof
- do_channel_extended_data
- do_channel_failure
- do_channel_open
- do_channel_open_confirmation
- do_channel_open_failure
- do_channel_request
- do_channel_success
- do_channel_window_adjust
- do_request_failure
- do_request_success
- global_request
- loop
- new
- open_channel
- process
- reader_ready?
- register_data_request
- remove_channel
- remove_channel_open_handler
- send_message
Request | = | Struct.new( :type, :data, :callback ) |
A structure for representing global requests, as registered by the global_request method. | ||
DataRequest | = | Struct.new( :channel, :data, :type ) |
A structure for representing a data buffer that must be sent across a channel. | ||
MESSAGES | = | {} |
Create a new connection driver that communicates over the given transport session. log is the logger instance to write log messages to, buffers is a buffer factory, and channels is a factory that can return new channel instances.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 46 46: def initialize( session, log, buffers, factories ) 47: @session = session 48: @log = log 49: @buffers = buffers 50: @factories = factories 51: 52: @channel_id_mutex = Mutex.new 53: @next_channel_id = 0 54: 55: @channel_map = Hash.new 56: @request_queue = Array.new 57: @channel_open_handlers = Hash.new 58: @data_requests = Array.new 59: end
Add a callback to be invoked when a channel-open request is recieved for a channel of the given type. The handler-id is returned.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 88 88: def add_channel_open_handler( type, &block ) 89: ( @channel_open_handlers[ type ] ||= Array.new ).push block 90: @channel_open_handlers.length 91: end
Return the next available channel id for this connection. This method is thread-safe.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 101 101: def allocate_channel_id 102: @channel_id_mutex.synchronize do 103: @next_channel_id += 1 104: return @next_channel_id 105: end 106: end
Returns an array of active channels.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 82 82: def channels 83: @channel_map.values 84: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 307 307: def do_channel_close( response ) 308: local_id = response.read_long 309: @log.debug "CHANNEL_CLOSE recieved (#{local_id})" if @log.debug? 310: @channel_map[ local_id ].close false 311: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 277 277: def do_channel_data( response ) 278: local_id = response.read_long 279: data = response.read_string 280: 281: if @log.debug? 282: @log.debug "CHANNEL_DATA recieved (#{local_id}:#{data.inspect})" 283: end 284: 285: @channel_map[ local_id ].do_data data 286: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 301 301: def do_channel_eof( response ) 302: local_id = response.read_long 303: @log.debug "CHANNEL_EOF recieved (#{local_id})" if @log.debug? 304: @channel_map[ local_id ].do_eof 305: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 288 288: def do_channel_extended_data( response ) 289: local_id = response.read_long 290: data_type = response.read_long 291: data = response.read_string 292: 293: if @log.debug? 294: @log.debug "CHANNEL_EXTENDED_DATA recieved " + 295: "(#{local_id}:#{data_type}:#{data.inspect})" 296: end 297: 298: @channel_map[ local_id ].do_extended_data data_type, data 299: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 332 332: def do_channel_failure( response ) 333: local_id = response.read_long 334: @log.debug "CHANNEL_FAILURE recieved (#{local_id})" if @log.debug? 335: @channel_map[ local_id ].do_failure 336: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 204 204: def do_channel_open( response ) 205: ch_type = response.read_string 206: @log.debug "CHANNEL_OPEN recieved (#{ch_type})" if @log.debug? 207: handled = false 208: 209: sender_channel = response.read_long 210: window_size = response.read_long 211: packet_size = response.read_long 212: 213: channel = @factories[:create].call( ch_type, sender_channel, 214: window_size, packet_size ) 215: 216: ( @channel_open_handlers[ ch_type ] || [] ).each do |handler| 217: next unless handler 218: handled = true 219: handler.call( self, channel, response ) 220: end 221: 222: unless handled 223: raise Net::SSH::Exception, 224: "cannot handle request to open a channel of type '#{ch_type}'" 225: end 226: 227: @channel_map[channel.local_id] = channel 228: 229: writer = @buffers.writer 230: writer.write_byte CHANNEL_OPEN_CONFIRMATION 231: writer.write_long channel.remote_id 232: writer.write_long channel.local_id 233: writer.write_long 0x7FFFFFFF 234: writer.write_long 0x7FFFFFFF 235: @session.send_message writer 236: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 251 251: def do_channel_open_confirmation( response ) 252: local_id = response.read_long 253: remote_id = response.read_long 254: window_size = response.read_long 255: packet_size = response.read_long 256: 257: if @log.debug? 258: @log.debug "CHANNEL_OPEN_CONFIRMATION recieved (#{local_id})" 259: end 260: 261: channel = @channel_map[ local_id ] 262: channel.do_confirm_open remote_id, window_size, packet_size 263: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 238 238: def do_channel_open_failure( response ) 239: local_id = response.read_long 240: reason_code = response.read_long 241: reason = response.read_string 242: language = response.read_string 243: 244: @log.debug "CHANNEL_OPEN_FAILURE recieved (#{reason})" if @log.debug? 245: 246: channel = @channel_map[ local_id ] 247: @channel_map.delete local_id 248: channel.do_confirm_failed reason_code, reason, language 249: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 313 313: def do_channel_request( response ) 314: local_id = response.read_long 315: request = response.read_string 316: want_reply = response.read_bool 317: request_data = response.remainder_as_buffer 318: 319: if @log.debug? 320: @log.debug "CHANNEL_REQUEST recieved (#{local_id}:#{request})" 321: end 322: 323: @channel_map[ local_id ].do_request request, want_reply, request_data 324: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 326 326: def do_channel_success( response ) 327: local_id = response.read_long 328: @log.debug "CHANNEL_SUCCESS recieved (#{local_id})" if @log.debug? 329: @channel_map[ local_id ].do_success 330: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 265 265: def do_channel_window_adjust( response ) 266: local_id = response.read_long 267: bytes_to_add = response.read_long 268: 269: if @log.debug? 270: @log.debug "CHANNEL_WINDOW_ADJUST recieved " + 271: "(#{local_id}:#{bytes_to_add})" 272: end 273: 274: @channel_map[ local_id ].do_window_adjust( bytes_to_add ) 275: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 199 199: def do_request_failure( response ) 200: @log.debug "REQUEST_FAILURE received" if @log.debug? 201: process_request response, false 202: end
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 194 194: def do_request_success( response ) 195: @log.debug "REQUEST_SUCCESS received" if @log.debug? 196: process_request response, true 197: end
Send a global request packet to the server. This returns immediately. The given block will be invoked when the server responds.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 165 165: def global_request( type, data=nil, &block ) 166: writer = @buffers.writer 167: writer.write_byte GLOBAL_REQUEST 168: writer.write_string type.to_s 169: writer.write_bool true 170: writer.write data.to_s if data 171: @session.send_message writer 172: 173: @request_queue.push Request.new( type, data, block ) 174: self 175: end
Repeated call process for as long as the given block returns true. If no block is given, then the loop continues until there are no more open channels on this connection.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 132 132: def loop( &block ) 133: block ||= proc { not @channel_map.empty? } 134: process while block.call 135: end
Open and return a new channel. This returns immediately, before the server confirms that the channel was opened. When the server sends the confirmation, the on_confirm callback will be invoked.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 70 70: def open_channel( type, extra_data=nil, &on_confirm ) 71: channel = @factories[:open].call( type, extra_data ) 72: channel.on_confirm_open &on_confirm 73: @channel_map[ channel.local_id ] = channel 74: end
Wait for and dispatch a single event. If nonblock is false (the default) this will block until a message has been received. Otherwise, it will return immediately.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 140 140: def process( nonblock=false ) 141: process_data_requests 142: 143: if !nonblock || reader_ready? 144: type, response = @session.wait_for_message 145: 146: unless ( dispatcher = MESSAGES[ type ] ) 147: raise Net::SSH::Exception, 148: "Unexpected response type '#{type}', (#{response.inspect})" 149: end 150: 151: dispatcher[:method].bind( self ).call( response ) 152: end 153: 154: self 155: end
Delegates the the reader_ready method of the transport session.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 184 184: def reader_ready? 185: @session.reader_ready? 186: end
Register a data buffer (of an optional type) to be sent across the given channel at the next available opportunity.
This is used internally by channels to hide the window size and maximum packet size from the client. Clients should not call this method directly.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 114 114: def register_data_request( channel, data, type=nil ) 115: @data_requests << DataRequest.new( channel, data, type ) 116: 117: # make sure the new data request has a chance to be sent to the 118: # server... Otherwise, it cannot be sent until the next time #process 119: # is invoked, which can be unexpected in synchronous situations. 120: process_data_requests 121: end
Remove the given channel from the connection.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 77 77: def remove_channel( channel ) 78: @channel_map.delete channel.local_id 79: end
Remove a callback with the given id for channel-open requests of the given type.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 95 95: def remove_channel_open_handler( type, id ) 96: @channel_open_handlers[ type ][ id-1 ] = nil 97: end
A convenience method for sending messages.
[ show source ]
# File lib/net/ssh/connection/driver.rb, line 178 178: def send_message( msg ) 179: @session.send_message msg 180: self 181: end