Included Modules
Constants
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 = {}
 
Public Class methods
new( session, log, buffers, factories )

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.

    # 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
Public Instance methods
add_channel_open_handler( type, &block )

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.

    # 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
allocate_channel_id()

Return the next available channel id for this connection. This method is thread-safe.

     # 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
channels()

Returns an array of active channels.

    # File lib/net/ssh/connection/driver.rb, line 82
82:         def channels
83:           @channel_map.values
84:         end
do_channel_close( response )
     # 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
do_channel_data( response )
     # 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
do_channel_eof( response )
     # 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
do_channel_extended_data( response )
     # 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
do_channel_failure( response )
     # 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
do_channel_open( response )
     # 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
do_channel_open_confirmation( response )
     # 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
do_channel_open_failure( response )
     # 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
do_channel_request( response )
     # 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
do_channel_success( response )
     # 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
do_channel_window_adjust( response )
     # 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
do_request_failure( response )
     # 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
do_request_success( response )
     # 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
global_request( type, data=nil, &block )

Send a global request packet to the server. This returns immediately. The given block will be invoked when the server responds.

     # 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
loop( &block )

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.

     # 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_channel( type, extra_data=nil, &on_confirm )

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.

    # 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
process( nonblock=false )

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.

     # 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
reader_ready?()

Delegates the the reader_ready method of the transport session.

     # File lib/net/ssh/connection/driver.rb, line 184
184:         def reader_ready?
185:           @session.reader_ready?
186:         end
register_data_request( channel, data, type=nil )

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.

     # 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_channel( channel )

Remove the given channel from the connection.

    # File lib/net/ssh/connection/driver.rb, line 77
77:         def remove_channel( channel )
78:           @channel_map.delete channel.local_id
79:         end
remove_channel_open_handler( type, id )

Remove a callback with the given id for channel-open requests of the given type.

    # 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
send_message( msg )

A convenience method for sending messages.

     # File lib/net/ssh/connection/driver.rb, line 178
178:         def send_message( msg )
179:           @session.send_message msg
180:           self
181:         end

[Validate]