Module: Rex::Proto::Ssh::IOMergeAbstraction

Included in:
ChannelFD
Defined in:
lib/rex/proto/ssh/connection.rb

Overview

A modified Rex::IO::Stream for separate file descriptors consumers are responsible for relevant initialization and fd_rd+fd_wr methods to expose selectable R/W IOs.

Instance Method Summary collapse

Instance Method Details

#closeObject


254
255
256
257
# File 'lib/rex/proto/ssh/connection.rb', line 254

def close
  fd_rd.close if (fd_rd and !fd_rd.closed?)
  fd_wr.close if (fd_wr and !fd_wr.closed?)
end

#closed?Boolean

Returns:

  • (Boolean)

259
260
261
# File 'lib/rex/proto/ssh/connection.rb', line 259

def closed?
  (fd_rd.nil? or fd_rd.closed?) and (fd_wr.nil? or fd_wr.closed?)
end

#has_read_data?(timeout = nil) ⇒ Boolean

Polls the stream to see if there is any read data available. Returns true if data is available for reading, otherwise false is returned.

Returns:

  • (Boolean)

231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/rex/proto/ssh/connection.rb', line 231

def has_read_data?(timeout = nil)

  # Allow a timeout of "0" that waits almost indefinitely for input, this
  # mimics the behavior of Rex::ThreadSafe.select() and fixes some corner
  # cases of unintentional no-wait timeouts.
  timeout = 3600 if (timeout and timeout == 0)

  begin
    if ((rv = ::IO.select([ fd_rd ], nil, nil, timeout)) and
        (rv[0]) and
        (rv[0][0] == fd_rd))
      true
    else
      false
    end
  rescue ::Errno::EBADF, ::Errno::ENOTSOCK
    raise ::EOFError
  rescue StreamClosedError, ::IOError, ::EOFError, ::Errno::EPIPE
    #  Return false if the socket is dead
    return false
  end
end

#inspectObject


175
176
177
# File 'lib/rex/proto/ssh/connection.rb', line 175

def inspect
  "#{self.class}(#{fd_rd.inspect}|#{fd_wr.inspect})"
end

#read(length = nil, opts = {}) ⇒ Object

This method reads data of the supplied length from the stream.


213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/rex/proto/ssh/connection.rb', line 213

def read(length = nil, opts = {})

  begin
    return fd_rd.read_nonblock( length )
  rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
    # Sleep for a half a second, or until we can read again
    Rex::ThreadSafe.select( [ fd_rd ], nil, nil, 0.5 )
    # Decrement the block size to handle full sendQs better
    retry
  rescue ::IOError, ::Errno::EPIPE
    return nil
  end
end

#write(buf, opts = {}) ⇒ Object


179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/rex/proto/ssh/connection.rb', line 179

def write(buf, opts = {})
  total_sent   = 0
  total_length = buf.length
  block_size   = 32768

  begin
    while( total_sent < total_length )
      s = Rex::ThreadSafe.select( nil, [ fd_wr ], nil, 0.2 )
      if( s == nil || s[0] == nil )
        next
      end
      data = buf[total_sent, block_size]
      sent = fd_wr.write_nonblock( data )
      if sent > 0
        total_sent += sent
      end
    end
  rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
    # Sleep for a half a second, or until we can write again
    Rex::ThreadSafe.select( nil, [ fd_wr ], nil, 0.5 )
    # Decrement the block size to handle full sendQs better
    block_size = 1024
    # Try to write the data again
    retry
  rescue ::IOError, ::Errno::EPIPE
    return nil
  end

  total_sent
end