net-ssh 5.2.0 → 7.0.1

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