sonixlabs-net-ssh 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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