Parent

Class/Module Index [+]

Quicksearch

Rex::IO::RingBuffer

Public Class Methods

new(socket, opts={}) click to toggle source

Create a new ring buffer

# File lib/rex/io/ring_buffer.rb, line 31
def initialize(socket, opts={})
        self.size  = opts[:size] || (1024 * 4)
        self.fd    = socket
        self.seq   = 0
        self.beg   = 0
        self.cur   = 0
        self.queue = Array.new( self.size )
        self.mutex = Mutex.new
end

Public Instance Methods

base_sequence() click to toggle source

The base_sequence method returns the earliest sequence number in the queue. This is zero until all slots are filled and the ring rotates.

# File lib/rex/io/ring_buffer.rb, line 179
def base_sequence
        self.mutex.synchronize do
                return 0 if not self.queue[self.beg]
                return self.queue[self.beg][0]
        end
end
clear_data() click to toggle source

The clear_data method wipes the ring buffer

# File lib/rex/io/ring_buffer.rb, line 88
def clear_data
        self.mutex.synchronize do
                self.seq   = 0
                self.beg   = 0
                self.cur   = 0
                self.queue = Array.new( self.size )
        end
end
create_stream() click to toggle source

The create_steam method assigns a IO::Socket compatible object to the ringer buffer

# File lib/rex/io/ring_buffer.rb, line 197
def create_stream
        Stream.new(self)
end
inspect() click to toggle source
# File lib/rex/io/ring_buffer.rb, line 41
def inspect
        "#<Rex::IO::RingBuffer @size=#{size} @fd=#{fd} @seq=#{seq} @beg=#{beg} @cur=#{cur}>"
end
last_sequence() click to toggle source

The last_sequence method returns the "next" sequence number where new data will be available.

# File lib/rex/io/ring_buffer.rb, line 190
def last_sequence
        self.seq
end
monitor_thread() click to toggle source

The built-in monitor thread (normally unused with Metasploit)

# File lib/rex/io/ring_buffer.rb, line 63
def monitor_thread
        Thread.new do
                begin
                while self.fd
                        buff = self.fd.get_once(-1, 1.0)
                        next if not buff
                        store_data(buff)
                end
                rescue ::Exception => e
                        self.monitor_thread_error = e
                end
        end
end
put(data, opts={}) click to toggle source

Push data back into the associated stream socket. Logging must occur elsewhere, this function is simply a passthrough.

# File lib/rex/io/ring_buffer.rb, line 81
def put(data, opts={})
        self.fd.put(data, opts={})
end
read_data(ptr=nil) click to toggle source

The read_data method returns a two element array with the new reader cursor (a sequence number) and the returned data buffer (if any). A result of nil/nil indicates that no data is available

# File lib/rex/io/ring_buffer.rb, line 126
def read_data(ptr=nil)
        self.mutex.synchronize do

        # Verify that there is data in the queue
        return [nil,nil] if not self.queue[self.beg]

        # Configure the beginning read pointer (sequence number, not index)
        ptr ||= self.queue[self.beg][0]
        return [nil,nil] if not ptr

        # If the pointer is below our baseline, we lost some data, so jump forward
        if ptr < self.queue[self.beg][0]
                ptr = self.queue[self.beg][0]
        end

        # Calculate how many blocks exist between the current sequence number
        # and the requested pointer, this becomes the number of blocks we will
        # need to read to satisfy the result. Due to the mutex block, we do
        # not need to scan to find the sequence of the starting block or
        # check the sequence of the ending block.
        dis = self.seq - ptr

        # If the requested sequnce number is less than our base pointer, it means
        # that no new data is available and we should return empty.
        return [nil,nil] if dis < 0

        # Calculate the beginning block index and number of blocks to read
        off = ptr - self.queue[self.beg][0]
        set = (self.beg + off) % self.size


        # Build the buffer by reading forward by the number of blocks needed
        # and return the last read sequence number, plus one, as the new read
        # pointer.
        buff = ""
        cnt  = 0
        lst  = ptr
        ptr.upto(self.seq) do |i|
                block = self.queue[ (set + cnt) % self.size ]
                lst,data = block[0],block[1]
                buff += data
                cnt += 1
        end

        return [lst + 1, buff]

        end
end
select() click to toggle source

The select method returns when there is a chance of new data XXX: This is mostly useless and requires a rewrite to use a

real select or notify mechanism
# File lib/rex/io/ring_buffer.rb, line 206
def select
        ::IO.select([ self.fd ], nil, [ self.fd ], 0.10)
end
start_monitor() click to toggle source

Start the built-in monitor, not called when used in a larger framework

# File lib/rex/io/ring_buffer.rb, line 48
def start_monitor
        self.monitor = monitor_thread if not self.monitor
end
stop_monitor() click to toggle source

Stop the built-in monitor

# File lib/rex/io/ring_buffer.rb, line 55
def stop_monitor
        self.monitor.kill if self.monitor
        self.monitor = nil
end
store_data(data) click to toggle source

The store_data method is used to insert data into the ring buffer.

# File lib/rex/io/ring_buffer.rb, line 100
def store_data(data)
        self.mutex.synchronize do
                # self.cur points to the array index of queue containing the last item
                # adding data will result in cur + 1 being used to store said data
                # if cur is larger than size - 1, it will wrap back around. If cur
                # is *smaller* beg, beg is increemnted to cur + 1 (and wrapped if
                # necessary

                loc = 0
                if self.seq > 0
                        loc = ( self.cur + 1 ) % self.size

                        if loc <= self.beg
                                self.beg = (self.beg + 1) % self.size
                        end
                end

                self.queue[loc] = [self.seq += 1, data]
                self.cur = loc
        end
end
wait(seq) click to toggle source

The wait method blocks until new data is available

# File lib/rex/io/ring_buffer.rb, line 213
def wait(seq)
        nseq = nil
        while not nseq
                nseq,data = read_data(seq)
                select
        end
end
wait_for(seq,timeout=1) click to toggle source

The wait_for method blocks until new data is available or the timeout is reached

# File lib/rex/io/ring_buffer.rb, line 224
def wait_for(seq,timeout=1)
        begin
                ::Timeout.timeout(timeout) do
                        wait(seq)
                end
        rescue ::Timeout::Error
        end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.