net-ssh 6.1.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/FUNDING.yml +1 -0
  5. data/.github/config/rubocop_linter_action.yml +4 -0
  6. data/.github/workflows/ci-with-docker.yml +44 -0
  7. data/.github/workflows/ci.yml +94 -0
  8. data/.github/workflows/rubocop.yml +16 -0
  9. data/.gitignore +4 -0
  10. data/.rubocop.yml +12 -1
  11. data/.rubocop_todo.yml +475 -376
  12. data/CHANGES.txt +64 -3
  13. data/DEVELOPMENT.md +23 -0
  14. data/Dockerfile +29 -0
  15. data/Dockerfile.openssl3 +17 -0
  16. data/Gemfile +2 -0
  17. data/Gemfile.noed25519 +2 -0
  18. data/Gemfile.norbnacl +12 -0
  19. data/README.md +38 -22
  20. data/Rakefile +92 -0
  21. data/SECURITY.md +4 -0
  22. data/docker-compose.yml +25 -0
  23. data/lib/net/ssh/authentication/agent.rb +29 -13
  24. data/lib/net/ssh/authentication/certificate.rb +14 -11
  25. data/lib/net/ssh/authentication/constants.rb +0 -1
  26. data/lib/net/ssh/authentication/ed25519.rb +14 -11
  27. data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
  28. data/lib/net/ssh/authentication/key_manager.rb +65 -36
  29. data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
  30. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
  31. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -2
  32. data/lib/net/ssh/authentication/methods/none.rb +6 -9
  33. data/lib/net/ssh/authentication/methods/password.rb +2 -3
  34. data/lib/net/ssh/authentication/methods/publickey.rb +57 -17
  35. data/lib/net/ssh/authentication/pageant.rb +97 -97
  36. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +3 -3
  37. data/lib/net/ssh/authentication/session.rb +25 -17
  38. data/lib/net/ssh/buffer.rb +71 -51
  39. data/lib/net/ssh/buffered_io.rb +25 -26
  40. data/lib/net/ssh/config.rb +33 -20
  41. data/lib/net/ssh/connection/channel.rb +84 -82
  42. data/lib/net/ssh/connection/constants.rb +0 -4
  43. data/lib/net/ssh/connection/event_loop.rb +30 -24
  44. data/lib/net/ssh/connection/keepalive.rb +12 -12
  45. data/lib/net/ssh/connection/session.rb +109 -108
  46. data/lib/net/ssh/connection/term.rb +56 -58
  47. data/lib/net/ssh/errors.rb +12 -12
  48. data/lib/net/ssh/key_factory.rb +7 -8
  49. data/lib/net/ssh/known_hosts.rb +86 -18
  50. data/lib/net/ssh/loggable.rb +8 -9
  51. data/lib/net/ssh/packet.rb +1 -1
  52. data/lib/net/ssh/prompt.rb +9 -11
  53. data/lib/net/ssh/proxy/command.rb +1 -1
  54. data/lib/net/ssh/proxy/errors.rb +2 -4
  55. data/lib/net/ssh/proxy/http.rb +18 -20
  56. data/lib/net/ssh/proxy/https.rb +8 -10
  57. data/lib/net/ssh/proxy/jump.rb +8 -10
  58. data/lib/net/ssh/proxy/socks4.rb +2 -4
  59. data/lib/net/ssh/proxy/socks5.rb +3 -5
  60. data/lib/net/ssh/service/forward.rb +7 -7
  61. data/lib/net/ssh/test/channel.rb +24 -26
  62. data/lib/net/ssh/test/extensions.rb +35 -35
  63. data/lib/net/ssh/test/kex.rb +6 -8
  64. data/lib/net/ssh/test/local_packet.rb +0 -2
  65. data/lib/net/ssh/test/packet.rb +3 -3
  66. data/lib/net/ssh/test/remote_packet.rb +6 -8
  67. data/lib/net/ssh/test/script.rb +25 -27
  68. data/lib/net/ssh/test/socket.rb +12 -15
  69. data/lib/net/ssh/test.rb +4 -5
  70. data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
  71. data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
  72. data/lib/net/ssh/transport/algorithms.rb +51 -19
  73. data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  74. data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  75. data/lib/net/ssh/transport/cipher_factory.rb +56 -29
  76. data/lib/net/ssh/transport/constants.rb +3 -3
  77. data/lib/net/ssh/transport/ctr.rb +7 -7
  78. data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
  79. data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
  80. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  81. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  82. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  83. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  84. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  85. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  86. data/lib/net/ssh/transport/hmac.rb +12 -12
  87. data/lib/net/ssh/transport/identity_cipher.rb +19 -13
  88. data/lib/net/ssh/transport/kex/abstract.rb +12 -5
  89. data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
  90. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +2 -1
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
  92. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +21 -21
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -2
  95. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
  96. data/lib/net/ssh/transport/kex.rb +8 -6
  97. data/lib/net/ssh/transport/key_expander.rb +7 -8
  98. data/lib/net/ssh/transport/openssl.rb +51 -26
  99. data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  100. data/lib/net/ssh/transport/packet_stream.rb +46 -26
  101. data/lib/net/ssh/transport/server_version.rb +17 -16
  102. data/lib/net/ssh/transport/session.rb +9 -7
  103. data/lib/net/ssh/transport/state.rb +44 -44
  104. data/lib/net/ssh/verifiers/accept_new.rb +0 -2
  105. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  106. data/lib/net/ssh/verifiers/always.rb +6 -4
  107. data/lib/net/ssh/verifiers/never.rb +0 -2
  108. data/lib/net/ssh/version.rb +2 -2
  109. data/lib/net/ssh.rb +15 -8
  110. data/net-ssh-public_cert.pem +19 -18
  111. data/net-ssh.gemspec +7 -4
  112. data/support/ssh_tunnel_bug.rb +3 -3
  113. data.tar.gz.sig +0 -0
  114. metadata +76 -29
  115. metadata.gz.sig +0 -0
  116. data/.travis.yml +0 -52
@@ -5,10 +5,9 @@ require 'net/ssh/service/forward'
5
5
  require 'net/ssh/connection/keepalive'
6
6
  require 'net/ssh/connection/event_loop'
7
7
 
8
- module Net
9
- module SSH
8
+ module Net
9
+ module SSH
10
10
  module Connection
11
-
12
11
  # A session class representing the connection service running on top of
13
12
  # the SSH transport layer. It manages the creation of channels (see
14
13
  # #open_channel), and the dispatching of messages to the various channels.
@@ -28,50 +27,50 @@ module Net
28
27
  class Session
29
28
  include Loggable
30
29
  include Constants
31
-
30
+
32
31
  # Default IO.select timeout threshold
33
32
  DEFAULT_IO_SELECT_TIMEOUT = 300
34
-
33
+
35
34
  # The underlying transport layer abstraction (see Net::SSH::Transport::Session).
36
35
  attr_reader :transport
37
-
36
+
38
37
  # The map of options that were used to initialize this instance.
39
38
  attr_reader :options
40
-
39
+
41
40
  # The collection of custom properties for this instance. (See #[] and #[]=).
42
41
  attr_reader :properties
43
-
42
+
44
43
  # The map of channels, each key being the local-id for the channel.
45
- attr_reader :channels #:nodoc:
46
-
44
+ attr_reader :channels # :nodoc:
45
+
47
46
  # The map of listeners that the event loop knows about. See #listen_to.
48
- attr_reader :listeners #:nodoc:
49
-
47
+ attr_reader :listeners # :nodoc:
48
+
50
49
  # The map of specialized handlers for opening specific channel types. See
51
50
  # #on_open_channel.
52
- attr_reader :channel_open_handlers #:nodoc:
53
-
51
+ attr_reader :channel_open_handlers # :nodoc:
52
+
54
53
  # The list of callbacks for pending requests. See #send_global_request.
55
- attr_reader :pending_requests #:nodoc:
56
-
54
+ attr_reader :pending_requests # :nodoc:
55
+
57
56
  class NilChannel
58
57
  def initialize(session)
59
58
  @session = session
60
59
  end
61
-
60
+
62
61
  def method_missing(sym, *args)
63
62
  @session.lwarn { "ignoring request #{sym.inspect} for non-existent (closed?) channel; probably ssh server bug" }
64
63
  end
65
64
  end
66
-
65
+
67
66
  # Create a new connection service instance atop the given transport
68
67
  # layer. Initializes the listeners to be only the underlying socket object.
69
- def initialize(transport, options={})
68
+ def initialize(transport, options = {})
70
69
  self.logger = transport.logger
71
-
70
+
72
71
  @transport = transport
73
72
  @options = options
74
-
73
+
75
74
  @channel_id_counter = -1
76
75
  @channels = Hash.new(NilChannel.new(self))
77
76
  @listeners = { transport.socket => nil }
@@ -79,34 +78,34 @@ module Net
79
78
  @channel_open_handlers = {}
80
79
  @on_global_request = {}
81
80
  @properties = (options[:properties] || {}).dup
82
-
81
+
83
82
  @max_pkt_size = (options.key?(:max_pkt_size) ? options[:max_pkt_size] : 0x8000)
84
83
  @max_win_size = (options.key?(:max_win_size) ? options[:max_win_size] : 0x20000)
85
-
84
+
86
85
  @keepalive = Keepalive.new(self)
87
-
86
+
88
87
  @event_loop = options[:event_loop] || SingleSessionEventLoop.new
89
88
  @event_loop.register(self)
90
89
  end
91
-
90
+
92
91
  # Retrieves a custom property from this instance. This can be used to
93
92
  # store additional state in applications that must manage multiple
94
93
  # SSH connections.
95
94
  def [](key)
96
95
  @properties[key]
97
96
  end
98
-
97
+
99
98
  # Sets a custom property for this instance.
100
99
  def []=(key, value)
101
100
  @properties[key] = value
102
101
  end
103
-
102
+
104
103
  # Returns the name of the host that was given to the transport layer to
105
104
  # connect to.
106
105
  def host
107
106
  transport.host
108
107
  end
109
-
108
+
110
109
  # Returns true if the underlying transport has been closed. Note that
111
110
  # this can be a little misleading, since if the remote server has
112
111
  # closed the connection, the local end will still think it is open
@@ -115,7 +114,7 @@ module Net
115
114
  def closed?
116
115
  transport.closed?
117
116
  end
118
-
117
+
119
118
  # Closes the session gracefully, blocking until all channels have
120
119
  # successfully closed, and then closes the underlying transport layer
121
120
  # connection.
@@ -129,7 +128,7 @@ module Net
129
128
  end
130
129
  transport.close
131
130
  end
132
-
131
+
133
132
  # Performs a "hard" shutdown of the connection. In general, this should
134
133
  # never be done, but it might be necessary (in a rescue clause, for instance,
135
134
  # when the connection needs to close but you don't know the status of the
@@ -137,10 +136,10 @@ module Net
137
136
  def shutdown!
138
137
  transport.shutdown!
139
138
  end
140
-
139
+
141
140
  # preserve a reference to Kernel#loop
142
141
  alias :loop_forever :loop
143
-
142
+
144
143
  # Returns +true+ if there are any channels currently active on this
145
144
  # session. By default, this will not include "invisible" channels
146
145
  # (such as those created by forwarding ports and such), but if you pass
@@ -150,14 +149,14 @@ module Net
150
149
  # to be run.
151
150
  #
152
151
  # ssh.loop { ssh.busy? }
153
- def busy?(include_invisible=false)
152
+ def busy?(include_invisible = false)
154
153
  if include_invisible
155
154
  channels.any?
156
155
  else
157
156
  channels.any? { |id, ch| !ch[:invisible] }
158
157
  end
159
158
  end
160
-
159
+
161
160
  # The main event loop. Calls #process until #process returns false. If a
162
161
  # block is given, it is passed to #process, otherwise a default proc is
163
162
  # used that just returns true if there are any channels active (see #busy?).
@@ -175,7 +174,7 @@ module Net
175
174
  # int_pressed = false
176
175
  # trap("INT") { int_pressed = true }
177
176
  # ssh.loop(0.1) { not int_pressed }
178
- def loop(wait=nil, &block)
177
+ def loop(wait = nil, &block)
179
178
  running = block || Proc.new { busy? }
180
179
  loop_forever { break unless process(wait, &running) }
181
180
  begin
@@ -188,7 +187,7 @@ module Net
188
187
  end
189
188
  end
190
189
  end
191
-
190
+
192
191
  # The core of the event loop. It processes a single iteration of the event
193
192
  # loop. If a block is given, it should return false when the processing
194
193
  # should abort, which causes #process to return false. Otherwise,
@@ -223,13 +222,13 @@ module Net
223
222
  # connections.delete_if { |ssh| !ssh.process(0.1, &condition) }
224
223
  # break if connections.empty?
225
224
  # end
226
- def process(wait=nil, &block)
225
+ def process(wait = nil, &block)
227
226
  @event_loop.process(wait, &block)
228
227
  rescue StandardError
229
228
  force_channel_cleanup_on_close if closed?
230
229
  raise
231
230
  end
232
-
231
+
233
232
  # This is called internally as part of #process. It dispatches any
234
233
  # available incoming packets, and then runs Net::SSH::Connection::Channel#process
235
234
  # for any active channels. If a block is given, it is invoked at the
@@ -237,31 +236,33 @@ module Net
237
236
  # false, this method returns false. Otherwise, it returns true.
238
237
  def preprocess(&block)
239
238
  return false if block_given? && !yield(self)
239
+
240
240
  ev_preprocess(&block)
241
241
  return false if block_given? && !yield(self)
242
+
242
243
  return true
243
244
  end
244
-
245
+
245
246
  # Called by event loop to process available data before going to
246
247
  # event multiplexing
247
248
  def ev_preprocess(&block)
248
249
  dispatch_incoming_packets(raise_disconnect_errors: false)
249
250
  each_channel { |id, channel| channel.process unless channel.local_closed? }
250
251
  end
251
-
252
+
252
253
  # Returns the file descriptors the event loop should wait for read/write events,
253
254
  # we also return the max wait
254
255
  def ev_do_calculate_rw_wait(wait)
255
256
  r = listeners.keys
256
257
  w = r.select { |w2| w2.respond_to?(:pending_write?) && w2.pending_write? }
257
- [r,w,io_select_wait(wait)]
258
+ [r, w, io_select_wait(wait)]
258
259
  end
259
-
260
+
260
261
  # This is called internally as part of #process.
261
262
  def postprocess(readers, writers)
262
263
  ev_do_handle_events(readers, writers)
263
264
  end
264
-
265
+
265
266
  # It loops over the given arrays of reader IO's and writer IO's,
266
267
  # processing them as needed, and
267
268
  # then calls Net::SSH::Transport::Session#rekey_as_needed to allow the
@@ -277,12 +278,12 @@ module Net
277
278
  end
278
279
  end
279
280
  end
280
-
281
+
281
282
  Array(writers).each do |writer|
282
283
  writer.send_pending
283
284
  end
284
285
  end
285
-
286
+
286
287
  # calls Net::SSH::Transport::Session#rekey_as_needed to allow the
287
288
  # transport layer to rekey
288
289
  def ev_do_postprocess(was_events)
@@ -290,7 +291,7 @@ module Net
290
291
  transport.rekey_as_needed
291
292
  true
292
293
  end
293
-
294
+
294
295
  # Send a global request of the given type. The +extra+ parameters must
295
296
  # be even in number, and conform to the same format as described for
296
297
  # Net::SSH::Buffer.from. If a callback is not specified, the request will
@@ -314,7 +315,7 @@ module Net
314
315
  pending_requests << callback if callback
315
316
  self
316
317
  end
317
-
318
+
318
319
  # Requests that a new channel be opened. By default, the channel will be
319
320
  # of type "session", but if you know what you're doing you can select any
320
321
  # of the channel types supported by the SSH protocol. The +extra+ parameters
@@ -334,27 +335,27 @@ module Net
334
335
  # end
335
336
  #
336
337
  # channel.wait
337
- def open_channel(type="session", *extra, &on_confirm)
338
+ def open_channel(type = "session", *extra, &on_confirm)
338
339
  local_id = get_next_channel_id
339
-
340
+
340
341
  channel = Channel.new(self, type, local_id, @max_pkt_size, @max_win_size, &on_confirm)
341
342
  msg = Buffer.from(:byte, CHANNEL_OPEN, :string, type, :long, local_id,
342
- :long, channel.local_maximum_window_size,
343
- :long, channel.local_maximum_packet_size, *extra)
343
+ :long, channel.local_maximum_window_size,
344
+ :long, channel.local_maximum_packet_size, *extra)
344
345
  send_message(msg)
345
-
346
+
346
347
  channels[local_id] = channel
347
348
  end
348
-
349
+
349
350
  class StringWithExitstatus < String
350
351
  def initialize(str, exitstatus)
351
352
  super(str)
352
353
  @exitstatus = exitstatus
353
354
  end
354
-
355
+
355
356
  attr_reader :exitstatus
356
357
  end
357
-
358
+
358
359
  # A convenience method for executing a command and interacting with it. If
359
360
  # no block is given, all output is printed via $stdout and $stderr. Otherwise,
360
361
  # the block is called for each data and extended data packet, with three
@@ -379,17 +380,17 @@ module Net
379
380
  open_channel do |channel|
380
381
  channel.exec(command) do |ch, success|
381
382
  raise "could not execute command: #{command.inspect}" unless success
382
-
383
+
383
384
  if status
384
- channel.on_request("exit-status") do |ch2,data|
385
+ channel.on_request("exit-status") do |ch2, data|
385
386
  status[:exit_code] = data.read_long
386
387
  end
387
-
388
+
388
389
  channel.on_request("exit-signal") do |ch2, data|
389
390
  status[:exit_signal] = data.read_long
390
391
  end
391
392
  end
392
-
393
+
393
394
  channel.on_data do |ch2, data|
394
395
  if block
395
396
  block.call(ch2, :stdout, data)
@@ -397,7 +398,7 @@ module Net
397
398
  $stdout.print(data)
398
399
  end
399
400
  end
400
-
401
+
401
402
  channel.on_extended_data do |ch2, type, data|
402
403
  if block
403
404
  block.call(ch2, :stderr, data)
@@ -408,30 +409,30 @@ module Net
408
409
  end
409
410
  end
410
411
  end
411
-
412
+
412
413
  # Same as #exec, except this will block until the command finishes. Also,
413
414
  # if no block is given, this will return all output (stdout and stderr)
414
415
  # as a single string.
415
416
  #
416
417
  # matches = ssh.exec!("grep something /some/files")
417
418
  #
418
- # the returned string has an exitstatus method to query it's exit satus
419
+ # the returned string has an exitstatus method to query its exit status
419
420
  def exec!(command, status: nil, &block)
420
421
  block_or_concat = block || Proc.new do |ch, type, data|
421
- ch[:result] ||= ""
422
+ ch[:result] ||= String.new
422
423
  ch[:result] << data
423
424
  end
424
-
425
+
425
426
  status ||= {}
426
427
  channel = exec(command, status: status, &block_or_concat)
427
428
  channel.wait
428
-
429
- channel[:result] ||= "" unless block
429
+
430
+ channel[:result] ||= String.new unless block
430
431
  channel[:result] &&= channel[:result].force_encoding("UTF-8") unless block
431
-
432
+
432
433
  StringWithExitstatus.new(channel[:result], status[:exit_code]) if channel[:result]
433
434
  end
434
-
435
+
435
436
  # Enqueues a message to be sent to the server as soon as the socket is
436
437
  # available for writing. Most programs will never need to call this, but
437
438
  # if you are implementing an extension to the SSH protocol, or if you
@@ -442,7 +443,7 @@ module Net
442
443
  def send_message(message)
443
444
  transport.enqueue_message(message)
444
445
  end
445
-
446
+
446
447
  # Adds an IO object for the event loop to listen to. If a callback
447
448
  # is given, it will be invoked when the io is ready to be read, otherwise,
448
449
  # the io will merely have its #fill method invoked.
@@ -480,19 +481,19 @@ module Net
480
481
  def listen_to(io, &callback)
481
482
  listeners[io] = callback
482
483
  end
483
-
484
+
484
485
  # Removes the given io object from the listeners collection, so that the
485
486
  # event loop will no longer monitor it.
486
487
  def stop_listening_to(io)
487
488
  listeners.delete(io)
488
489
  end
489
-
490
+
490
491
  # Returns a reference to the Net::SSH::Service::Forward service, which can
491
492
  # be used for forwarding ports over SSH.
492
493
  def forward
493
494
  @forward ||= Service::Forward.new(self)
494
495
  end
495
-
496
+
496
497
  # Registers a handler to be invoked when the server wants to open a
497
498
  # channel on the client. The callback receives the connection object,
498
499
  # the new channel object, and the packet itself as arguments, and should
@@ -506,7 +507,7 @@ module Net
506
507
  def on_open_channel(type, &block)
507
508
  channel_open_handlers[type] = block
508
509
  end
509
-
510
+
510
511
  # Registers a handler to be invoked when the server sends a global request
511
512
  # of the given type. The callback receives the request data as the first
512
513
  # parameter, and true/false as the second (indicating whether a response
@@ -517,61 +518,61 @@ module Net
517
518
  old, @on_global_request[type] = @on_global_request[type], block
518
519
  old
519
520
  end
520
-
521
+
521
522
  def cleanup_channel(channel)
522
523
  if channel.local_closed? and channel.remote_closed?
523
524
  info { "#{host} delete channel #{channel.local_id} which closed locally and remotely" }
524
525
  channels.delete(channel.local_id)
525
526
  end
526
527
  end
527
-
528
+
528
529
  # If the #preprocess and #postprocess callbacks for this session need to run
529
530
  # periodically, this method returns the maximum number of seconds which may
530
531
  # pass between callbacks.
531
532
  def max_select_wait_time
532
533
  @keepalive.interval if @keepalive.enabled?
533
534
  end
534
-
535
+
535
536
  private
536
-
537
+
537
538
  # iterate channels with the posibility of callbacks opening new channels during the iteration
538
539
  def each_channel(&block)
539
540
  channels.dup.each(&block)
540
541
  end
541
-
542
+
542
543
  # Read all pending packets from the connection and dispatch them as
543
544
  # appropriate. Returns as soon as there are no more pending packets.
544
545
  def dispatch_incoming_packets(raise_disconnect_errors: true)
545
546
  while packet = transport.poll_message
546
547
  raise Net::SSH::Exception, "unexpected response #{packet.type} (#{packet.inspect})" unless MAP.key?(packet.type)
547
-
548
+
548
549
  send(MAP[packet.type], packet)
549
550
  end
550
551
  rescue StandardError
551
552
  force_channel_cleanup_on_close if closed?
552
553
  raise if raise_disconnect_errors || !$!.is_a?(Net::SSH::Disconnect)
553
554
  end
554
-
555
+
555
556
  # Returns the next available channel id to be assigned, and increments
556
557
  # the counter.
557
558
  def get_next_channel_id
558
559
  @channel_id_counter += 1
559
560
  end
560
-
561
+
561
562
  def force_channel_cleanup_on_close
562
563
  channels.each do |id, channel|
563
564
  channel_closed(channel)
564
565
  end
565
566
  end
566
-
567
+
567
568
  def channel_closed(channel)
568
569
  channel.remote_closed!
569
570
  channel.close
570
-
571
+
571
572
  cleanup_channel(channel)
572
573
  channel.do_close
573
574
  end
574
-
575
+
575
576
  # Invoked when a global request is received. The registered global
576
577
  # request callback will be invoked, if one exists, and the necessary
577
578
  # reply returned.
@@ -583,41 +584,41 @@ module Net
583
584
  if result != :sent && result != true && result != false
584
585
  raise "expected global request handler for `#{packet[:request_type]}' to return true, false, or :sent, but got #{result.inspect}"
585
586
  end
586
-
587
+
587
588
  if packet[:want_reply] && result != :sent
588
589
  msg = Buffer.from(:byte, result ? REQUEST_SUCCESS : REQUEST_FAILURE)
589
590
  send_message(msg)
590
591
  end
591
592
  end
592
-
593
+
593
594
  # Invokes the next pending request callback with +true+.
594
595
  def request_success(packet)
595
596
  info { "global request success" }
596
597
  callback = pending_requests.shift
597
598
  callback.call(true, packet) if callback
598
599
  end
599
-
600
+
600
601
  # Invokes the next pending request callback with +false+.
601
602
  def request_failure(packet)
602
603
  info { "global request failure" }
603
604
  callback = pending_requests.shift
604
605
  callback.call(false, packet) if callback
605
606
  end
606
-
607
+
607
608
  # Called when the server wants to open a channel. If no registered
608
609
  # channel handler exists for the given channel type, CHANNEL_OPEN_FAILURE
609
610
  # is returned, otherwise the callback is invoked and everything proceeds
610
611
  # accordingly.
611
612
  def channel_open(packet)
612
613
  info { "channel open #{packet[:channel_type]}" }
613
-
614
+
614
615
  local_id = get_next_channel_id
615
-
616
+
616
617
  channel = Channel.new(self, packet[:channel_type], local_id, @max_pkt_size, @max_win_size)
617
618
  channel.do_open_confirmation(packet[:remote_id], packet[:window_size], packet[:packet_size])
618
-
619
+
619
620
  callback = channel_open_handlers[packet[:channel_type]]
620
-
621
+
621
622
  if callback
622
623
  begin
623
624
  callback[self, channel, packet]
@@ -632,80 +633,80 @@ module Net
632
633
  else
633
634
  failure = [3, "unknown channel type #{channel.type}"]
634
635
  end
635
-
636
+
636
637
  if failure
637
638
  error { failure.inspect }
638
639
  msg = Buffer.from(:byte, CHANNEL_OPEN_FAILURE, :long, channel.remote_id, :long, failure[0], :string, failure[1], :string, "")
639
640
  end
640
-
641
+
641
642
  send_message(msg)
642
643
  end
643
-
644
+
644
645
  def channel_open_confirmation(packet)
645
646
  info { "channel_open_confirmation: #{packet[:local_id]} #{packet[:remote_id]} #{packet[:window_size]} #{packet[:packet_size]}" }
646
647
  channel = channels[packet[:local_id]]
647
648
  channel.do_open_confirmation(packet[:remote_id], packet[:window_size], packet[:packet_size])
648
649
  end
649
-
650
+
650
651
  def channel_open_failure(packet)
651
652
  error { "channel_open_failed: #{packet[:local_id]} #{packet[:reason_code]} #{packet[:description]}" }
652
653
  channel = channels.delete(packet[:local_id])
653
654
  channel.do_open_failed(packet[:reason_code], packet[:description])
654
655
  end
655
-
656
+
656
657
  def channel_window_adjust(packet)
657
658
  info { "channel_window_adjust: #{packet[:local_id]} +#{packet[:extra_bytes]}" }
658
659
  channels[packet[:local_id]].do_window_adjust(packet[:extra_bytes])
659
660
  end
660
-
661
+
661
662
  def channel_request(packet)
662
663
  info { "channel_request: #{packet[:local_id]} #{packet[:request]} #{packet[:want_reply]}" }
663
664
  channels[packet[:local_id]].do_request(packet[:request], packet[:want_reply], packet[:request_data])
664
665
  end
665
-
666
+
666
667
  def channel_data(packet)
667
668
  info { "channel_data: #{packet[:local_id]} #{packet[:data].length}b" }
668
669
  channels[packet[:local_id]].do_data(packet[:data])
669
670
  end
670
-
671
+
671
672
  def channel_extended_data(packet)
672
673
  info { "channel_extended_data: #{packet[:local_id]} #{packet[:data_type]} #{packet[:data].length}b" }
673
674
  channels[packet[:local_id]].do_extended_data(packet[:data_type], packet[:data])
674
675
  end
675
-
676
+
676
677
  def channel_eof(packet)
677
678
  info { "channel_eof: #{packet[:local_id]}" }
678
679
  channels[packet[:local_id]].do_eof
679
680
  end
680
-
681
+
681
682
  def channel_close(packet)
682
683
  info { "channel_close: #{packet[:local_id]}" }
683
-
684
+
684
685
  channel = channels[packet[:local_id]]
685
686
  channel_closed(channel)
686
687
  end
687
-
688
+
688
689
  def channel_success(packet)
689
690
  info { "channel_success: #{packet[:local_id]}" }
690
691
  channels[packet[:local_id]].do_success
691
692
  end
692
-
693
+
693
694
  def channel_failure(packet)
694
695
  info { "channel_failure: #{packet[:local_id]}" }
695
696
  channels[packet[:local_id]].do_failure
696
697
  end
697
-
698
+
698
699
  def io_select_wait(wait)
699
700
  [wait, max_select_wait_time].compact.min
700
701
  end
701
-
702
+
702
703
  MAP = Constants.constants.each_with_object({}) do |name, memo|
703
704
  value = const_get(name)
704
705
  next unless Integer === value
706
+
705
707
  memo[value] = name.downcase.to_sym
706
708
  end
707
709
  end
708
-
709
710
  end
710
711
  end
711
712
  end