Module: Rex::IO::Stream
- Included in:
- Socket::Tcp
- Defined in:
- lib/rex/io/stream.rb
Overview
This mixin is an abstract representation of a streaming connection. Streams extend classes that must implement the following methods:
syswrite(buffer)
sysread(length)
shutdown(how)
close
peerinfo
localinfo
Instance Method Summary collapse
-
#<<(buf) ⇒ Object
This method writes the supplied buffer to the stream by calling the write routine.
-
#>> ⇒ Object
This method calls get_once() to read pending data from the socket.
-
#def_block_size ⇒ Object
The default block size to read in chunks from the wire.
-
#def_max_loops ⇒ Object
The maximum number of read loops to perform before returning to the caller.
-
#def_read_loop_timeout ⇒ Object
The default number of seconds to wait while in a read loop after read data has been found.
-
#def_read_timeout ⇒ Object
The default number of seconds to wait for a read operation to timeout.
-
#def_write_timeout ⇒ Object
The default number of seconds to wait for a write operation to timeout.
-
#fd ⇒ Object
This method returns the selectable file descriptor, or self by default.
-
#get(timeout = nil, ltimeout = def_read_loop_timeout, opts = {}) ⇒ Object
This method reads as much data as it can from the wire given a maximum timeout.
-
#get_once(length = -1,, timeout = def_read_timeout) ⇒ Object
This method emulates the behavior of Pex::Socket::Recv in MSF2.
-
#has_read_data?(timeout = nil) ⇒ Boolean
Polls the stream to see if there is any read data available.
-
#put(buf, opts = {}) ⇒ Object
This method writes the full contents of the supplied buffer, optionally with a timeout.
-
#read(length = nil, opts = {}) ⇒ Object
This method reads data of the supplied length from the stream.
-
#timed_read(length = nil, wait = def_read_timeout, opts = {}) ⇒ Object
This method reads from the stream, optionally timing out after a period of time.
-
#timed_write(buf, wait = def_write_timeout, opts = {}) ⇒ Object
This method writes to the stream, optionally timing out after a period of time.
-
#write(buf, opts = {}) ⇒ Object
This method writes the supplied buffer to the stream.
Instance Method Details
#<<(buf) ⇒ Object
This method writes the supplied buffer to the stream by calling the write routine.
127 128 129 |
# File 'lib/rex/io/stream.rb', line 127 def <<(buf) return write(buf.to_s) end |
#>> ⇒ Object
This method calls get_once() to read pending data from the socket
134 135 136 |
# File 'lib/rex/io/stream.rb', line 134 def >> get_once end |
#def_block_size ⇒ Object
The default block size to read in chunks from the wire.
303 304 305 |
# File 'lib/rex/io/stream.rb', line 303 def def_block_size 16384 end |
#def_max_loops ⇒ Object
The maximum number of read loops to perform before returning to the caller.
296 297 298 |
# File 'lib/rex/io/stream.rb', line 296 def def_max_loops 1024 end |
#def_read_loop_timeout ⇒ Object
The default number of seconds to wait while in a read loop after read data has been found.
288 289 290 |
# File 'lib/rex/io/stream.rb', line 288 def def_read_loop_timeout 0.1 end |
#def_read_timeout ⇒ Object
The default number of seconds to wait for a read operation to timeout.
280 281 282 |
# File 'lib/rex/io/stream.rb', line 280 def def_read_timeout 10 end |
#def_write_timeout ⇒ Object
The default number of seconds to wait for a write operation to timeout.
273 274 275 |
# File 'lib/rex/io/stream.rb', line 273 def def_write_timeout 10 end |
#fd ⇒ Object
This method returns the selectable file descriptor, or self by default.
113 114 115 |
# File 'lib/rex/io/stream.rb', line 113 def fd self end |
#get(timeout = nil, ltimeout = def_read_loop_timeout, opts = {}) ⇒ Object
This method reads as much data as it can from the wire given a maximum timeout.
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/rex/io/stream.rb', line 211 def get(timeout = nil, ltimeout = def_read_loop_timeout, opts = {}) # For those people who are used to being able to use a negative timeout! if (timeout and timeout.to_i < 0) timeout = nil end # No data in the first place? bust. if (has_read_data?(timeout) == false) return nil end buf = "" lps = 0 eof = false # Keep looping until there is no more data to be gotten.. while (has_read_data?(ltimeout) == true) # Catch EOF errors so that we can handle them properly. begin temp = read(def_block_size) rescue EOFError eof = true end # If we read zero bytes and we had data, then we've hit EOF if (temp and temp.length == 0) eof = true end # If we reached EOF and there are no bytes in the buffer we've been # reading into, then throw an EOF error. if (eof) # If we've already read at least some data, then it's time to # break out and let it be processed before throwing an EOFError. if (buf.length > 0) break else raise EOFError end end break if (temp == nil or temp.empty? == true) buf += temp lps += 1 break if (lps >= def_max_loops) end # Return the entire buffer we read in return buf end |
#get_once(length = -1,, timeout = def_read_timeout) ⇒ Object
This method emulates the behavior of Pex::Socket::Recv in MSF2
195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/rex/io/stream.rb', line 195 def get_once(length = -1, timeout = def_read_timeout) if (has_read_data?(timeout) == false) return nil end bsize = (length == -1) ? def_block_size : length data = read(bsize) raise EOFError if data.nil? data 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.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/rex/io/stream.rb', line 87 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 ], nil, nil, timeout)) and (rv[0]) and (rv[0][0] == fd)) 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 |
#put(buf, opts = {}) ⇒ Object
This method writes the full contents of the supplied buffer, optionally with a timeout.
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/rex/io/stream.rb', line 170 def put(buf, opts = {}) return 0 if (buf == nil or buf.length == 0) send_len = buf.length send_idx = 0 wait = opts['Timeout'] || 0 # Keep writing until our send length drops to zero while (send_idx < send_len) curr_len = timed_write(buf[send_idx, buf.length-send_idx], wait, opts) # If the write operation failed due to an IOError, then we fail. return buf.length - send_len if (curr_len == nil) send_len -= curr_len send_idx += curr_len end return buf.length - send_len end |
#read(length = nil, opts = {}) ⇒ Object
This method reads data of the supplied length from the stream.
69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/rex/io/stream.rb', line 69 def read(length = nil, opts = {}) begin return fd.read_nonblock( length ) rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK # Sleep for a half a second, or until we can read again Rex::ThreadSafe.select( [ fd ], nil, nil, 0.5 ) # Decrement the block size to handle full sendQs better retry rescue ::IOError, ::Errno::EPIPE return nil end end |
#timed_read(length = nil, wait = def_read_timeout, opts = {}) ⇒ Object
This method reads from the stream, optionally timing out after a period of time.
156 157 158 159 160 161 162 163 164 |
# File 'lib/rex/io/stream.rb', line 156 def timed_read(length = nil, wait = def_read_timeout, opts = {}) if (wait and wait > 0) Timeout.timeout(wait) { return read(length, opts) } else return read(length, opts) end end |
#timed_write(buf, wait = def_write_timeout, opts = {}) ⇒ Object
This method writes to the stream, optionally timing out after a period of time.
142 143 144 145 146 147 148 149 150 |
# File 'lib/rex/io/stream.rb', line 142 def timed_write(buf, wait = def_write_timeout, opts = {}) if (wait and wait > 0) Timeout.timeout(wait) { return write(buf, opts) } else return write(buf, opts) end end |
#write(buf, opts = {}) ⇒ Object
This method writes the supplied buffer to the stream. This method intelligent reduces the size of supplied buffers so that ruby doesn’t get into a potential global thread blocking state when used on blocking sockets. That is, this method will send the supplied buffer in chunks of, at most, 32768 bytes.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/rex/io/stream.rb', line 35 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 ], nil, 0.2 ) if( s == nil || s[0] == nil ) next end data = buf[total_sent, block_size] sent = fd.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 ], 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 |