public
Description: Pure Ruby implementation of an SSH (protocol 2) client
Homepage: http://rubyforge.org/projects/net-ssh
Clone URL: git://github.com/jamis/net-ssh.git
Search Repo:
Make channel open failures work via a callback to parallel how channel 
open successes work
jamis (author)
Sat Apr 05 14:43:24 -0700 2008
commit  a5d884130d8fbe8180f59cce47cac5f8a9cca931
tree    b5c77871e3d9c55892608c9780adb663dfc2c819
parent  b9be5284a789923dfe239d533c1f64d5a0a686b7
...
 
 
 
 
 
1
2
3
...
1
2
3
4
5
6
7
8
0
@@ -1,3 +1,8 @@
0
+=== *unreleased*
0
+
0
+* Make channel open failure work with a callback so that failures can be handled similarly to successes [Jamis Buck]
0
+
0
+
0
 === 2.0 Preview Release 2 (1.99.1) / 22 Mar 2008
0
 
0
 * Partial support for ~/.ssh/config (and related) SSH configuration files [Daniel J. Berger, Jamis Buck]
...
124
125
126
127
 
128
129
130
...
392
393
394
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
396
397
...
493
494
495
 
 
 
 
 
 
 
 
 
 
 
 
496
497
498
...
124
125
126
 
127
128
129
130
...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
...
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
0
@@ -124,7 +124,7 @@ module Net; module SSH; module Connection
0
       @properties = {}
0
 
0
       @pending_requests = []
0
- @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil
0
+ @on_open_failed = @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil
0
       @on_request = {}
0
       @closing = @eof = false
0
     end
0
@@ -392,6 +392,21 @@ module Net; module SSH; module Connection
0
       old
0
     end
0
 
0
+ # Registers a callback to be invoked when the server was unable to open
0
+ # the requested channel. The channel itself will be passed to the block,
0
+ # along with the integer "reason code" for the failure, and a textual
0
+ # description of the failure from the server.
0
+ #
0
+ # channel = session.open_channel do |ch|
0
+ # # ..
0
+ # end
0
+ #
0
+ # channel.on_open_failed { |ch, code, desc| ... }
0
+ def on_open_failed(&block)
0
+ old, @on_open_failed = @on_open_failed, block
0
+ old
0
+ end
0
+
0
     # Registers a callback to be invoked when a channel request of the given
0
     # type is received. The callback will receive the channel as the first
0
     # argument, and the associated (unparsed) data as the second. The data
0
@@ -493,6 +508,18 @@ module Net; module SSH; module Connection
0
         @on_confirm_open.call(self) if @on_confirm_open
0
       end
0
 
0
+ # Invoked when the server failed to open the channel. If an #on_open_failed
0
+ # callback was specified, it will be invoked with the channel, reason code,
0
+ # and description as arguments. Otherwise, a ChannelOpenFailed exception
0
+ # will be raised.
0
+ def do_open_failed(reason_code, description)
0
+ if @on_open_failed
0
+ @on_open_failed.call(self, reason_code, description)
0
+ else
0
+ raise ChannelOpenFailed.new(reason_code, description)
0
+ end
0
+ end
0
+
0
       # Invoked when the server sends a CHANNEL_WINDOW_ADJUST packet, and
0
       # causes the remote window size to be adjusted upwards by the given
0
       # number of bytes. This has the effect of allowing more data to be sent
...
509
510
511
512
513
 
 
514
515
516
...
509
510
511
 
 
512
513
514
515
516
0
@@ -509,8 +509,8 @@ module Net; module SSH; module Connection
0
 
0
       def channel_open_failure(packet)
0
         error { "channel_open_failed: #{packet[:local_id]} #{packet[:reason_code]} #{packet[:description]}" }
0
- channels.delete(packet[:local_id])
0
- raise ChannelOpenFailed.new(packet[:reason_code], packet[:description])
0
+ channel = channels.delete(packet[:local_id])
0
+ channel.do_open_failed(packet[:reason_code], packet[:description])
0
       end
0
 
0
       def channel_window_adjust(packet)
...
68
69
70
71
 
72
73
74
 
 
 
 
 
75
76
77
...
68
69
70
 
71
72
73
74
75
76
77
78
79
80
81
82
0
@@ -68,10 +68,15 @@ module Net; module SSH; module Service
0
         client = socket.accept
0
         debug { "received connection on #{bind_address}:#{local_port}" }
0
 
0
- session.open_channel("direct-tcpip", :string, remote_host, :long, remote_port, :string, bind_address, :long, local_port) do |channel|
0
+ channel = session.open_channel("direct-tcpip", :string, remote_host, :long, remote_port, :string, bind_address, :long, local_port) do |channel|
0
           channel.info { "direct channel established" }
0
           prepare_client(client, channel, :local)
0
         end
0
+
0
+ channel.on_open_failed do |ch, code, description|
0
+ channel.error { "could not establish direct channel: #{description} (#{code})" }
0
+ client.close
0
+ end
0
       end
0
     end
0
 
...
237
238
239
240
 
241
 
242
243
 
244
245
246
...
237
238
239
 
240
241
242
243
 
244
245
246
247
0
@@ -237,10 +237,11 @@ module Connection
0
       assert_equal "auth-agent", ch.type
0
     end
0
 
0
- def test_channel_open_failure_should_remove_channel_raise_exception
0
+ def test_channel_open_failure_should_remove_channel_and_tell_channel_that_open_failed
0
       session.channels[1] = stub("channel")
0
+ session.channels[1].expects(:do_open_failed).with(1234, "some reason")
0
       transport.return(CHANNEL_OPEN_FAILURE, :long, 1, :long, 1234, :string, "some reason", :string, "lang tag")
0
- assert_raises(Net::SSH::ChannelOpenFailed) { process_times(2) }
0
+ process_times(2)
0
       assert session.channels.empty?
0
     end
0
 

Comments

    No one has commented yet.