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



238
239
240
241
# File 'lib/rex/proto/ssh/connection.rb', line 238

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)


243
244
245
# File 'lib/rex/proto/ssh/connection.rb', line 243

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)


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/rex/proto/ssh/connection.rb', line 215

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



159
160
161
# File 'lib/rex/proto/ssh/connection.rb', line 159

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.



197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/rex/proto/ssh/connection.rb', line 197

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



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/rex/proto/ssh/connection.rb', line 163

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