sonixlabs-net-ssh 2.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 (123) hide show
  1. data/CHANGELOG.rdoc +262 -0
  2. data/Manifest +121 -0
  3. data/README.rdoc +184 -0
  4. data/Rakefile +86 -0
  5. data/Rudyfile +96 -0
  6. data/THANKS.rdoc +19 -0
  7. data/lib/net/ssh.rb +223 -0
  8. data/lib/net/ssh/authentication/agent.rb +179 -0
  9. data/lib/net/ssh/authentication/constants.rb +18 -0
  10. data/lib/net/ssh/authentication/key_manager.rb +253 -0
  11. data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  12. data/lib/net/ssh/authentication/methods/hostbased.rb +75 -0
  13. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +70 -0
  14. data/lib/net/ssh/authentication/methods/password.rb +43 -0
  15. data/lib/net/ssh/authentication/methods/publickey.rb +96 -0
  16. data/lib/net/ssh/authentication/pageant.rb +264 -0
  17. data/lib/net/ssh/authentication/session.rb +146 -0
  18. data/lib/net/ssh/buffer.rb +340 -0
  19. data/lib/net/ssh/buffered_io.rb +198 -0
  20. data/lib/net/ssh/config.rb +207 -0
  21. data/lib/net/ssh/connection/channel.rb +630 -0
  22. data/lib/net/ssh/connection/constants.rb +33 -0
  23. data/lib/net/ssh/connection/session.rb +597 -0
  24. data/lib/net/ssh/connection/term.rb +178 -0
  25. data/lib/net/ssh/errors.rb +88 -0
  26. data/lib/net/ssh/key_factory.rb +102 -0
  27. data/lib/net/ssh/known_hosts.rb +129 -0
  28. data/lib/net/ssh/loggable.rb +61 -0
  29. data/lib/net/ssh/packet.rb +102 -0
  30. data/lib/net/ssh/prompt.rb +93 -0
  31. data/lib/net/ssh/proxy/command.rb +75 -0
  32. data/lib/net/ssh/proxy/errors.rb +14 -0
  33. data/lib/net/ssh/proxy/http.rb +94 -0
  34. data/lib/net/ssh/proxy/socks4.rb +70 -0
  35. data/lib/net/ssh/proxy/socks5.rb +142 -0
  36. data/lib/net/ssh/ruby_compat.rb +43 -0
  37. data/lib/net/ssh/service/forward.rb +298 -0
  38. data/lib/net/ssh/test.rb +89 -0
  39. data/lib/net/ssh/test/channel.rb +129 -0
  40. data/lib/net/ssh/test/extensions.rb +152 -0
  41. data/lib/net/ssh/test/kex.rb +44 -0
  42. data/lib/net/ssh/test/local_packet.rb +51 -0
  43. data/lib/net/ssh/test/packet.rb +81 -0
  44. data/lib/net/ssh/test/remote_packet.rb +38 -0
  45. data/lib/net/ssh/test/script.rb +157 -0
  46. data/lib/net/ssh/test/socket.rb +64 -0
  47. data/lib/net/ssh/transport/algorithms.rb +386 -0
  48. data/lib/net/ssh/transport/cipher_factory.rb +79 -0
  49. data/lib/net/ssh/transport/constants.rb +30 -0
  50. data/lib/net/ssh/transport/hmac.rb +42 -0
  51. data/lib/net/ssh/transport/hmac/abstract.rb +79 -0
  52. data/lib/net/ssh/transport/hmac/md5.rb +12 -0
  53. data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  54. data/lib/net/ssh/transport/hmac/none.rb +15 -0
  55. data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  56. data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  57. data/lib/net/ssh/transport/hmac/sha2_256.rb +15 -0
  58. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +13 -0
  59. data/lib/net/ssh/transport/hmac/sha2_512.rb +14 -0
  60. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +13 -0
  61. data/lib/net/ssh/transport/identity_cipher.rb +55 -0
  62. data/lib/net/ssh/transport/kex.rb +17 -0
  63. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  64. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +80 -0
  65. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +15 -0
  66. data/lib/net/ssh/transport/key_expander.rb +26 -0
  67. data/lib/net/ssh/transport/openssl.rb +127 -0
  68. data/lib/net/ssh/transport/packet_stream.rb +235 -0
  69. data/lib/net/ssh/transport/server_version.rb +71 -0
  70. data/lib/net/ssh/transport/session.rb +278 -0
  71. data/lib/net/ssh/transport/state.rb +206 -0
  72. data/lib/net/ssh/verifiers/lenient.rb +30 -0
  73. data/lib/net/ssh/verifiers/null.rb +12 -0
  74. data/lib/net/ssh/verifiers/strict.rb +53 -0
  75. data/lib/net/ssh/version.rb +62 -0
  76. data/lib/sonixlabs-net-ssh.rb +1 -0
  77. data/net-ssh.gemspec +145 -0
  78. data/setup.rb +1585 -0
  79. data/support/arcfour_check.rb +20 -0
  80. data/support/ssh_tunnel_bug.rb +65 -0
  81. data/test/authentication/methods/common.rb +28 -0
  82. data/test/authentication/methods/test_abstract.rb +51 -0
  83. data/test/authentication/methods/test_hostbased.rb +114 -0
  84. data/test/authentication/methods/test_keyboard_interactive.rb +100 -0
  85. data/test/authentication/methods/test_password.rb +52 -0
  86. data/test/authentication/methods/test_publickey.rb +148 -0
  87. data/test/authentication/test_agent.rb +205 -0
  88. data/test/authentication/test_key_manager.rb +171 -0
  89. data/test/authentication/test_session.rb +106 -0
  90. data/test/common.rb +107 -0
  91. data/test/configs/eqsign +3 -0
  92. data/test/configs/exact_match +8 -0
  93. data/test/configs/host_plus +10 -0
  94. data/test/configs/multihost +4 -0
  95. data/test/configs/wild_cards +14 -0
  96. data/test/connection/test_channel.rb +467 -0
  97. data/test/connection/test_session.rb +488 -0
  98. data/test/test_all.rb +9 -0
  99. data/test/test_buffer.rb +336 -0
  100. data/test/test_buffered_io.rb +63 -0
  101. data/test/test_config.rb +120 -0
  102. data/test/test_key_factory.rb +79 -0
  103. data/test/transport/hmac/test_md5.rb +39 -0
  104. data/test/transport/hmac/test_md5_96.rb +25 -0
  105. data/test/transport/hmac/test_none.rb +34 -0
  106. data/test/transport/hmac/test_sha1.rb +34 -0
  107. data/test/transport/hmac/test_sha1_96.rb +25 -0
  108. data/test/transport/hmac/test_sha2_256.rb +35 -0
  109. data/test/transport/hmac/test_sha2_256_96.rb +25 -0
  110. data/test/transport/hmac/test_sha2_512.rb +35 -0
  111. data/test/transport/hmac/test_sha2_512_96.rb +25 -0
  112. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
  113. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
  114. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +33 -0
  115. data/test/transport/test_algorithms.rb +308 -0
  116. data/test/transport/test_cipher_factory.rb +213 -0
  117. data/test/transport/test_hmac.rb +34 -0
  118. data/test/transport/test_identity_cipher.rb +40 -0
  119. data/test/transport/test_packet_stream.rb +736 -0
  120. data/test/transport/test_server_version.rb +78 -0
  121. data/test/transport/test_session.rb +315 -0
  122. data/test/transport/test_state.rb +179 -0
  123. metadata +178 -0
@@ -0,0 +1,340 @@
1
+ require 'net/ssh/ruby_compat'
2
+ require 'net/ssh/transport/openssl'
3
+
4
+ module Net; module SSH
5
+
6
+ # Net::SSH::Buffer is a flexible class for building and parsing binary
7
+ # data packets. It provides a stream-like interface for sequentially
8
+ # reading data items from the buffer, as well as a useful helper method
9
+ # for building binary packets given a signature.
10
+ #
11
+ # Writing to a buffer always appends to the end, regardless of where the
12
+ # read cursor is. Reading, on the other hand, always begins at the first
13
+ # byte of the buffer and increments the read cursor, with subsequent reads
14
+ # taking up where the last left off.
15
+ #
16
+ # As a consumer of the Net::SSH library, you will rarely come into contact
17
+ # with these buffer objects directly, but it could happen. Also, if you
18
+ # are ever implementing a protocol on top of SSH (e.g. SFTP), this buffer
19
+ # class can be quite handy.
20
+ class Buffer
21
+ # This is a convenience method for creating and populating a new buffer
22
+ # from a single command. The arguments must be even in length, with the
23
+ # first of each pair of arguments being a symbol naming the type of the
24
+ # data that follows. If the type is :raw, the value is written directly
25
+ # to the hash.
26
+ #
27
+ # b = Buffer.from(:byte, 1, :string, "hello", :raw, "\1\2\3\4")
28
+ # #-> "\1\0\0\0\5hello\1\2\3\4"
29
+ #
30
+ # The supported data types are:
31
+ #
32
+ # * :raw => write the next value verbatim (#write)
33
+ # * :int64 => write an 8-byte integer (#write_int64)
34
+ # * :long => write a 4-byte integer (#write_long)
35
+ # * :byte => write a single byte (#write_byte)
36
+ # * :string => write a 4-byte length followed by character data (#write_string)
37
+ # * :bool => write a single byte, interpreted as a boolean (#write_bool)
38
+ # * :bignum => write an SSH-encoded bignum (#write_bignum)
39
+ # * :key => write an SSH-encoded key value (#write_key)
40
+ #
41
+ # Any of these, except for :raw, accepts an Array argument, to make it
42
+ # easier to write multiple values of the same type in a briefer manner.
43
+ def self.from(*args)
44
+ raise ArgumentError, "odd number of arguments given" unless args.length % 2 == 0
45
+
46
+ buffer = new
47
+ 0.step(args.length-1, 2) do |index|
48
+ type = args[index]
49
+ value = args[index+1]
50
+ if type == :raw
51
+ buffer.append(value.to_s)
52
+ elsif Array === value
53
+ buffer.__send__("write_#{type}", *value)
54
+ else
55
+ buffer.__send__("write_#{type}", value)
56
+ end
57
+ end
58
+
59
+ buffer
60
+ end
61
+
62
+ # exposes the raw content of the buffer
63
+ attr_reader :content
64
+
65
+ # the current position of the pointer in the buffer
66
+ attr_accessor :position
67
+
68
+ # Creates a new buffer, initialized to the given content. The position
69
+ # is initialized to the beginning of the buffer.
70
+ def initialize(content="")
71
+ @content = content.to_s
72
+ @position = 0
73
+ end
74
+
75
+ # Returns the length of the buffer's content.
76
+ def length
77
+ @content.length
78
+ end
79
+
80
+ # Returns the number of bytes available to be read (e.g., how many bytes
81
+ # remain between the current position and the end of the buffer).
82
+ def available
83
+ length - position
84
+ end
85
+
86
+ # Returns a copy of the buffer's content.
87
+ def to_s
88
+ (@content || "").dup
89
+ end
90
+
91
+ # Compares the contents of the two buffers, returning +true+ only if they
92
+ # are identical in size and content.
93
+ def ==(buffer)
94
+ to_s == buffer.to_s
95
+ end
96
+
97
+ # Returns +true+ if the buffer contains no data (e.g., it is of zero length).
98
+ def empty?
99
+ @content.empty?
100
+ end
101
+
102
+ # Resets the pointer to the start of the buffer. Subsequent reads will
103
+ # begin at position 0.
104
+ def reset!
105
+ @position = 0
106
+ end
107
+
108
+ # Returns true if the pointer is at the end of the buffer. Subsequent
109
+ # reads will return nil, in this case.
110
+ def eof?
111
+ @position >= length
112
+ end
113
+
114
+ # Resets the buffer, making it empty. Also, resets the read position to
115
+ # 0.
116
+ def clear!
117
+ @content = ""
118
+ @position = 0
119
+ end
120
+
121
+ # Consumes n bytes from the buffer, where n is the current position
122
+ # unless otherwise specified. This is useful for removing data from the
123
+ # buffer that has previously been read, when you are expecting more data
124
+ # to be appended. It helps to keep the size of buffers down when they
125
+ # would otherwise tend to grow without bound.
126
+ #
127
+ # Returns the buffer object itself.
128
+ def consume!(n=position)
129
+ if n >= length
130
+ # optimize for a fairly common case
131
+ clear!
132
+ elsif n > 0
133
+ @content = @content[n..-1] || ""
134
+ @position -= n
135
+ @position = 0 if @position < 0
136
+ end
137
+ self
138
+ end
139
+
140
+ # Appends the given text to the end of the buffer. Does not alter the
141
+ # read position. Returns the buffer object itself.
142
+ def append(text)
143
+ @content << text
144
+ self
145
+ end
146
+
147
+ # Returns all text from the current pointer to the end of the buffer as
148
+ # a new Net::SSH::Buffer object.
149
+ def remainder_as_buffer
150
+ Buffer.new(@content[@position..-1])
151
+ end
152
+
153
+ # Reads all data up to and including the given pattern, which may be a
154
+ # String, Fixnum, or Regexp and is interpreted exactly as String#index
155
+ # does. Returns nil if nothing matches. Increments the position to point
156
+ # immediately after the pattern, if it does match. Returns all data up to
157
+ # and including the text that matched the pattern.
158
+ def read_to(pattern)
159
+ index = @content.index(pattern, @position) or return nil
160
+ length = case pattern
161
+ when String then pattern.length
162
+ when Fixnum then 1
163
+ when Regexp then $&.length
164
+ end
165
+ index && read(index+length)
166
+ end
167
+
168
+ # Reads and returns the next +count+ bytes from the buffer, starting from
169
+ # the read position. If +count+ is +nil+, this will return all remaining
170
+ # text in the buffer. This method will increment the pointer.
171
+ def read(count=nil)
172
+ count ||= length
173
+ count = length - @position if @position + count > length
174
+ @position += count
175
+ @content[@position-count, count]
176
+ end
177
+
178
+ # Reads (as #read) and returns the given number of bytes from the buffer,
179
+ # and then consumes (as #consume!) all data up to the new read position.
180
+ def read!(count=nil)
181
+ data = read(count)
182
+ consume!
183
+ data
184
+ end
185
+
186
+ # Return the next 8 bytes as a 64-bit integer (in network byte order).
187
+ # Returns nil if there are less than 8 bytes remaining to be read in the
188
+ # buffer.
189
+ def read_int64
190
+ hi = read_long or return nil
191
+ lo = read_long or return nil
192
+ return (hi << 32) + lo
193
+ end
194
+
195
+ # Return the next four bytes as a long integer (in network byte order).
196
+ # Returns nil if there are less than 4 bytes remaining to be read in the
197
+ # buffer.
198
+ def read_long
199
+ b = read(4) or return nil
200
+ b.unpack("N").first
201
+ end
202
+
203
+ # Read and return the next byte in the buffer. Returns nil if called at
204
+ # the end of the buffer.
205
+ def read_byte
206
+ b = read(1) or return nil
207
+ b.getbyte(0)
208
+ end
209
+
210
+ # Read and return an SSH2-encoded string. The string starts with a long
211
+ # integer that describes the number of bytes remaining in the string.
212
+ # Returns nil if there are not enough bytes to satisfy the request.
213
+ def read_string
214
+ length = read_long or return nil
215
+ read(length)
216
+ end
217
+
218
+ # Read a single byte and convert it into a boolean, using 'C' rules
219
+ # (i.e., zero is false, non-zero is true).
220
+ def read_bool
221
+ b = read_byte or return nil
222
+ b != 0
223
+ end
224
+
225
+ # Read a bignum (OpenSSL::BN) from the buffer, in SSH2 format. It is
226
+ # essentially just a string, which is reinterpreted to be a bignum in
227
+ # binary format.
228
+ def read_bignum
229
+ data = read_string
230
+ return unless data
231
+ OpenSSL::BN.new(data, 2)
232
+ end
233
+
234
+ # Read a key from the buffer. The key will start with a string
235
+ # describing its type. The remainder of the key is defined by the
236
+ # type that was read.
237
+ def read_key
238
+ type = read_string
239
+ return (type ? read_keyblob(type) : nil)
240
+ end
241
+
242
+ # Read a keyblob of the given type from the buffer, and return it as
243
+ # a key. Only RSA and DSA keys are supported.
244
+ def read_keyblob(type)
245
+ case type
246
+ when "ssh-dss"
247
+ key = OpenSSL::PKey::DSA.new
248
+ key.p = read_bignum
249
+ key.q = read_bignum
250
+ key.g = read_bignum
251
+ key.pub_key = read_bignum
252
+
253
+ when "ssh-rsa"
254
+ key = OpenSSL::PKey::RSA.new
255
+ key.e = read_bignum
256
+ key.n = read_bignum
257
+
258
+ else
259
+ raise NotImplementedError, "unsupported key type `#{type}'"
260
+ end
261
+
262
+ return key
263
+ end
264
+
265
+ # Reads the next string from the buffer, and returns a new Buffer
266
+ # object that wraps it.
267
+ def read_buffer
268
+ Buffer.new(read_string)
269
+ end
270
+
271
+ # Writes the given data literally into the string. Does not alter the
272
+ # read position. Returns the buffer object.
273
+ def write(*data)
274
+ data.each { |datum| @content << datum }
275
+ self
276
+ end
277
+
278
+ # Writes each argument to the buffer as a network-byte-order-encoded
279
+ # 64-bit integer (8 bytes). Does not alter the read position. Returns the
280
+ # buffer object.
281
+ def write_int64(*n)
282
+ n.each do |i|
283
+ hi = (i >> 32) & 0xFFFFFFFF
284
+ lo = i & 0xFFFFFFFF
285
+ @content << [hi, lo].pack("N2")
286
+ end
287
+ self
288
+ end
289
+
290
+ # Writes each argument to the buffer as a network-byte-order-encoded
291
+ # long (4-byte) integer. Does not alter the read position. Returns the
292
+ # buffer object.
293
+ def write_long(*n)
294
+ @content << n.pack("N*")
295
+ self
296
+ end
297
+
298
+ # Writes each argument to the buffer as a byte. Does not alter the read
299
+ # position. Returns the buffer object.
300
+ def write_byte(*n)
301
+ n.each { |b| @content << b.chr }
302
+ self
303
+ end
304
+
305
+ # Writes each argument to the buffer as an SSH2-encoded string. Each
306
+ # string is prefixed by its length, encoded as a 4-byte long integer.
307
+ # Does not alter the read position. Returns the buffer object.
308
+ def write_string(*text)
309
+ text.each do |string|
310
+ s = string.to_s
311
+ write_long(s.length)
312
+ write(s)
313
+ end
314
+ self
315
+ end
316
+
317
+ # Writes each argument to the buffer as a (C-style) boolean, with 1
318
+ # meaning true, and 0 meaning false. Does not alter the read position.
319
+ # Returns the buffer object.
320
+ def write_bool(*b)
321
+ b.each { |v| @content << (v ? "\1" : "\0") }
322
+ self
323
+ end
324
+
325
+ # Writes each argument to the buffer as a bignum (SSH2-style). No
326
+ # checking is done to ensure that the arguments are, in fact, bignums.
327
+ # Does not alter the read position. Returns the buffer object.
328
+ def write_bignum(*n)
329
+ @content << n.map { |b| b.to_ssh }.join
330
+ self
331
+ end
332
+
333
+ # Writes the given arguments to the buffer as SSH2-encoded keys. Does not
334
+ # alter the read position. Returns the buffer object.
335
+ def write_key(*key)
336
+ key.each { |k| append(k.to_blob) }
337
+ self
338
+ end
339
+ end
340
+ end; end;
@@ -0,0 +1,198 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/loggable'
3
+ require 'net/ssh/ruby_compat'
4
+
5
+ module Net; module SSH
6
+
7
+ # This module is used to extend sockets and other IO objects, to allow
8
+ # them to be buffered for both read and write. This abstraction makes it
9
+ # quite easy to write a select-based event loop
10
+ # (see Net::SSH::Connection::Session#listen_to).
11
+ #
12
+ # The general idea is that instead of calling #read directly on an IO that
13
+ # has been extended with this module, you call #fill (to add pending input
14
+ # to the internal read buffer), and then #read_available (to read from that
15
+ # buffer). Likewise, you don't call #write directly, you call #enqueue to
16
+ # add data to the write buffer, and then #send_pending or #wait_for_pending_sends
17
+ # to actually send the data across the wire.
18
+ #
19
+ # In this way you can easily use the object as an argument to IO.select,
20
+ # calling #fill when it is available for read, or #send_pending when it is
21
+ # available for write, and then call #enqueue and #read_available during
22
+ # the idle times.
23
+ #
24
+ # socket = TCPSocket.new(address, port)
25
+ # socket.extend(Net::SSH::BufferedIo)
26
+ #
27
+ # ssh.listen_to(socket)
28
+ #
29
+ # ssh.loop do
30
+ # if socket.available > 0
31
+ # puts socket.read_available
32
+ # socket.enqueue("response\n")
33
+ # end
34
+ # end
35
+ #
36
+ # Note that this module must be used to extend an instance, and should not
37
+ # be included in a class. If you do want to use it via an include, then you
38
+ # must make sure to invoke the private #initialize_buffered_io method in
39
+ # your class' #initialize method:
40
+ #
41
+ # class Foo < IO
42
+ # include Net::SSH::BufferedIo
43
+ #
44
+ # def initialize
45
+ # initialize_buffered_io
46
+ # # ...
47
+ # end
48
+ # end
49
+ module BufferedIo
50
+ include Loggable
51
+
52
+ # Called when the #extend is called on an object, with this module as the
53
+ # argument. It ensures that the modules instance variables are all properly
54
+ # initialized.
55
+ def self.extended(object) #:nodoc:
56
+ # need to use __send__ because #send is overridden in Socket
57
+ object.__send__(:initialize_buffered_io)
58
+ end
59
+
60
+ # Tries to read up to +n+ bytes of data from the remote end, and appends
61
+ # the data to the input buffer. It returns the number of bytes read, or 0
62
+ # if no data was available to be read.
63
+ def fill(n=8192)
64
+ input.consume!
65
+ data = recv(n)
66
+ debug { "read #{data.length} bytes" }
67
+ input.append(data)
68
+ return data.length
69
+ end
70
+
71
+ # Read up to +length+ bytes from the input buffer. If +length+ is nil,
72
+ # all available data is read from the buffer. (See #available.)
73
+ def read_available(length=nil)
74
+ input.read(length || available)
75
+ end
76
+
77
+ # Returns the number of bytes available to be read from the input buffer.
78
+ # (See #read_available.)
79
+ def available
80
+ input.available
81
+ end
82
+
83
+ # Enqueues data in the output buffer, to be written when #send_pending
84
+ # is called. Note that the data is _not_ sent immediately by this method!
85
+ def enqueue(data)
86
+ output.append(data)
87
+ end
88
+
89
+ # Returns +true+ if there is data waiting in the output buffer, and
90
+ # +false+ otherwise.
91
+ def pending_write?
92
+ output.length > 0
93
+ end
94
+
95
+ # Sends as much of the pending output as possible. Returns +true+ if any
96
+ # data was sent, and +false+ otherwise.
97
+ def send_pending
98
+ if output.length > 0
99
+ sent = send(output.to_s, 0)
100
+ debug { "sent #{sent} bytes" }
101
+ output.consume!(sent)
102
+ return sent > 0
103
+ else
104
+ return false
105
+ end
106
+ end
107
+
108
+ # Calls #send_pending repeatedly, if necessary, blocking until the output
109
+ # buffer is empty.
110
+ def wait_for_pending_sends
111
+ send_pending
112
+ while output.length > 0
113
+ result = Net::SSH::Compat.io_select(nil, [self]) or next
114
+ next unless result[1].any?
115
+ send_pending
116
+ end
117
+ end
118
+
119
+ public # these methods are primarily for use in tests
120
+
121
+ def write_buffer #:nodoc:
122
+ output.to_s
123
+ end
124
+
125
+ def read_buffer #:nodoc:
126
+ input.to_s
127
+ end
128
+
129
+ private
130
+
131
+ #--
132
+ # Can't use attr_reader here (after +private+) without incurring the
133
+ # wrath of "ruby -w". We hates it.
134
+ #++
135
+
136
+ def input; @input; end
137
+ def output; @output; end
138
+
139
+ # Initializes the intput and output buffers for this object. This method
140
+ # is called automatically when the module is mixed into an object via
141
+ # Object#extend (see Net::SSH::BufferedIo.extended), but must be called
142
+ # explicitly in the +initialize+ method of any class that uses
143
+ # Module#include to add this module.
144
+ def initialize_buffered_io
145
+ @input = Net::SSH::Buffer.new
146
+ @output = Net::SSH::Buffer.new
147
+ end
148
+ end
149
+
150
+
151
+
152
+ # Fixes for two issues by Miklós Fazekas:
153
+ #
154
+ # * if client closes a forwarded connection, but the server is
155
+ # reading, net-ssh terminates with IOError socket closed.
156
+ # * if client force closes (RST) a forwarded connection, but
157
+ # server is reading, net-ssh terminates with [an exception]
158
+ #
159
+ # See:
160
+ #
161
+ # http://net-ssh.lighthouseapp.com/projects/36253/tickets/7
162
+ # http://github.com/net-ssh/net-ssh/tree/portfwfix
163
+ #
164
+ module ForwardedBufferedIo
165
+ def fill(n=8192)
166
+ begin
167
+ super(n)
168
+ rescue Errno::ECONNRESET => e
169
+ debug { "connection was reset => shallowing exception:#{e}" }
170
+ return 0
171
+ rescue IOError => e
172
+ if e.message =~ /closed/ then
173
+ debug { "connection was reset => shallowing exception:#{e}" }
174
+ return 0
175
+ else
176
+ raise
177
+ end
178
+ end
179
+ end
180
+
181
+ def send_pending
182
+ begin
183
+ super
184
+ rescue Errno::ECONNRESET => e
185
+ debug { "connection was reset => shallowing exception:#{e}" }
186
+ return 0
187
+ rescue IOError => e
188
+ if e.message =~ /closed/ then
189
+ debug { "connection was reset => shallowing exception:#{e}" }
190
+ return 0
191
+ else
192
+ raise
193
+ end
194
+ end
195
+ end
196
+ end
197
+
198
+ end; end