starting to move shared classes into rex
git-svn-id: file:///home/svn/incoming/trunk@2559 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
d369ef3737
commit
675dbe37b0
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# Log severities
|
||||
#
|
||||
LOG_ERROR = 'error'
|
||||
LOG_DEBUG = 'debug'
|
||||
LOG_INFO = 'info'
|
||||
LOG_WARN = 'warn'
|
||||
LOG_RAW = 'raw'
|
||||
|
||||
#
|
||||
# Log levels
|
||||
#
|
||||
# LEV_0 errors and warnings may be displayed to the user by default.
|
||||
#
|
||||
LEV_0 = 0
|
||||
LEV_1 = 1
|
||||
LEV_2 = 2
|
||||
LEV_3 = 3
|
|
@ -0,0 +1,126 @@
|
|||
require 'Rex'
|
||||
|
||||
module Rex
|
||||
module Logging
|
||||
|
||||
###
|
||||
#
|
||||
# LogDispatcher
|
||||
# -------------
|
||||
#
|
||||
# The log dispatcher associates log sources with log sinks. A log source
|
||||
# is a unique identity that is associated with one and only one log sink.
|
||||
# For instance, the framework-core registers the 'core'
|
||||
#
|
||||
###
|
||||
class LogDispatcher
|
||||
|
||||
def initialize()
|
||||
self.log_sinks = {}
|
||||
self.log_sinks_rwlock = ReadWriteLock.new
|
||||
end
|
||||
|
||||
# Returns the sink that is associated with the supplied source
|
||||
def [](src)
|
||||
sink = nil
|
||||
|
||||
log_sinks_rwlock.synchronize_read {
|
||||
sink = log_sinks[src]
|
||||
}
|
||||
|
||||
return sink
|
||||
end
|
||||
|
||||
# Calls the source association routnie
|
||||
def []=(src, sink)
|
||||
store(src, sink)
|
||||
end
|
||||
|
||||
# Associates the supplied source with the supplied sink
|
||||
def store(src, sink)
|
||||
log_sinks_rwlock.synchronize_write {
|
||||
if (log_sinks[src] == nil)
|
||||
log_sinks[src] = sink
|
||||
else
|
||||
raise(
|
||||
RuntimeError,
|
||||
"The supplied log source #{src} is already registered.",
|
||||
caller)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# Removes a source association if one exists
|
||||
def delete(src)
|
||||
sink = nil
|
||||
|
||||
log_sinks_rwlock.synchronize_write {
|
||||
sink = log_sinks[src]
|
||||
|
||||
log_sinks.delete(src)
|
||||
}
|
||||
|
||||
if (sink)
|
||||
sink.cleanup
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
# Performs the actual log operation against the supplied source
|
||||
def log(sev, src, level, msg, from)
|
||||
log_sinks_rwlock.synchronize_read {
|
||||
if ((sink = log_sinks[src]))
|
||||
sink.log(sev, src, level, msg, from)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
attr_accessor :log_sinks, :log_sinks_rwlock
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
#
|
||||
# An instance of the log dispatcher exists in the global namespace, along
|
||||
# with stubs for many of the common logging methods. Various sources can
|
||||
# register themselves as a log sink such that logs can be directed at
|
||||
# various targets depending on where they're sourced from. By doing it
|
||||
# this way, things like sessions can use the global logging stubs and
|
||||
# still be directed at the correct log file.
|
||||
#
|
||||
###
|
||||
def dlog(msg, src = 'core', level = 0, from = caller)
|
||||
$dispatcher.log(LOG_DEBUG, src, level, msg, from)
|
||||
end
|
||||
|
||||
def elog(msg, src = 'core', level = 0, from = caller)
|
||||
$dispatcher.log(LOG_ERROR, src, level, msg, from)
|
||||
end
|
||||
|
||||
def wlog(msg, src = 'core', level = 0, from = caller)
|
||||
$dispatcher.log(LOG_WARN, src, level, msg, from)
|
||||
end
|
||||
|
||||
def ilog(msg, src = 'core', level = 0, from = caller)
|
||||
$dispatcher.log(LOG_INFO, src, level, msg, from)
|
||||
end
|
||||
|
||||
def rlog(msg, src = 'core', level = 0, from = caller)
|
||||
$dispatcher.log(LOG_RAW, src, level, msg, from)
|
||||
end
|
||||
|
||||
def register_log_source(src, sink)
|
||||
$dispatcher[src] = sink
|
||||
end
|
||||
|
||||
def deregister_log_source(src, sink)
|
||||
$dispatcher.delete(src)
|
||||
end
|
||||
|
||||
# Creates the global log dispatcher
|
||||
$dispatcher = Rex::Logging::LogDispatcher.new
|
|
@ -0,0 +1,36 @@
|
|||
require 'Rex/Constants'
|
||||
|
||||
module Rex
|
||||
module Logging
|
||||
|
||||
###
|
||||
#
|
||||
# LogSink
|
||||
# -------
|
||||
#
|
||||
# This abstract interface is what must be implemented by any class
|
||||
# that would like to register as a log sink on a given LogDispatcher
|
||||
# instance, such as the Framework object.
|
||||
#
|
||||
###
|
||||
module LogSink
|
||||
|
||||
def cleanup
|
||||
end
|
||||
|
||||
def log(sev, src, level, msg, from)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def get_current_timestamp
|
||||
return Time.now.strftime("%m/%d/%Y %H:%M:%S")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
require 'Rex/Logging/Sinks/Flatfile'
|
|
@ -0,0 +1,50 @@
|
|||
module Rex
|
||||
module Logging
|
||||
module Sinks
|
||||
|
||||
###
|
||||
#
|
||||
# Flatfile
|
||||
# --------
|
||||
#
|
||||
# This class implements the LogSink interface and backs it against a
|
||||
# file on disk.
|
||||
#
|
||||
###
|
||||
class Flatfile
|
||||
|
||||
include Rex::Logging::LogSink
|
||||
|
||||
def initialize(file)
|
||||
self.fd = File.new(file, "a")
|
||||
end
|
||||
|
||||
def cleanup
|
||||
fd.close
|
||||
end
|
||||
|
||||
def log(sev, src, level, msg, from)
|
||||
if (sev == LOG_RAW)
|
||||
fd.write(msg)
|
||||
else
|
||||
code = 'i'
|
||||
|
||||
case sev
|
||||
when LOG_DEBUG
|
||||
code = 'd'
|
||||
when LOG_ERROR
|
||||
code = 'e'
|
||||
when LOG_INFO
|
||||
code = 'i'
|
||||
end
|
||||
fd.write("[#{get_current_timestamp}] [#{code}(#{level})] #{src}: #{msg}\n")
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :fd
|
||||
|
||||
end
|
||||
|
||||
end end end
|
|
@ -0,0 +1,163 @@
|
|||
require 'thread'
|
||||
|
||||
module Rex
|
||||
|
||||
###
|
||||
#
|
||||
# ReadWriteLock
|
||||
# -------------
|
||||
#
|
||||
# This class implements a read/write lock synchronization
|
||||
# primitive. It is meant to allow for more efficient access to
|
||||
# resources that are more often read from than written to and many
|
||||
# times can have concurrent reader threads. By allowing the reader
|
||||
# threads to lock the resource concurrently rather than serially,
|
||||
# a large performance boost can be seen. Acquiring a write lock
|
||||
# results in exclusive access to the resource and thereby prevents
|
||||
# any read operations during the time that a write lock is acquired.
|
||||
# Only one write lock may be acquired at a time.
|
||||
#
|
||||
###
|
||||
class ReadWriteLock
|
||||
|
||||
def initialize
|
||||
@read_sync_mutex = Mutex.new
|
||||
@write_sync_mutex = Mutex.new
|
||||
@exclusive_mutex = Mutex.new
|
||||
@readers = 0
|
||||
@writer = false
|
||||
end
|
||||
|
||||
# Acquires the read lock for the calling thread
|
||||
def lock_read
|
||||
read_sync_mutex.lock
|
||||
|
||||
begin
|
||||
# If there are a non-zero number of readers and a
|
||||
# writer is waiting to acquire the exclusive lock,
|
||||
# free up the sync mutex temporarily and lock/unlock
|
||||
# the exclusive lock. This is to give the writer
|
||||
# thread a chance to acquire the lock and prevents
|
||||
# it from being constantly starved.
|
||||
if ((@readers > 0) and
|
||||
(@writer))
|
||||
read_sync_mutex.unlock
|
||||
exclusive_mutex.lock
|
||||
exclusive_mutex.unlock
|
||||
read_sync_mutex.lock
|
||||
end
|
||||
|
||||
# Increment the active reader count
|
||||
@readers += 1
|
||||
|
||||
# If we now have just one reader, acquire the exclusive
|
||||
# lock. Track the thread owner so that we release the
|
||||
# lock from within the same thread context later on.
|
||||
if (@readers == 1)
|
||||
exclusive_mutex.lock
|
||||
|
||||
@owner = Thread.current
|
||||
end
|
||||
ensure
|
||||
read_sync_mutex.unlock
|
||||
end
|
||||
end
|
||||
|
||||
# Releases the read lock for the calling thread
|
||||
def unlock_read
|
||||
read_sync_mutex.lock
|
||||
|
||||
begin
|
||||
unlocked = false
|
||||
|
||||
# Keep looping until we've lost this thread's reader
|
||||
# lock
|
||||
while (!unlocked)
|
||||
# If there are no more readers left after this one
|
||||
if (@readers - 1 == 0)
|
||||
# If the calling thread is the owner of the exclusive
|
||||
# reader lock, then let's release that shit!
|
||||
if (Thread.current == @owner)
|
||||
@owner = nil
|
||||
|
||||
exclusive_mutex.unlock
|
||||
end
|
||||
# If there is more than one reader left and this thread is
|
||||
# the owner of the exclusive lock, then keep looping so that
|
||||
# we can eventually unlock the exclusive mutex in this thread's
|
||||
# context
|
||||
elsif (Thread.current == @owner)
|
||||
read_sync_mutex.unlock
|
||||
|
||||
next
|
||||
end
|
||||
|
||||
# Unlocked!
|
||||
unlocked = true
|
||||
|
||||
# Decrement the active reader count
|
||||
@readers -= 1
|
||||
end
|
||||
ensure
|
||||
read_sync_mutex.unlock
|
||||
end
|
||||
end
|
||||
|
||||
# Acquire the exclusive write lock
|
||||
def lock_write
|
||||
write_sync_mutex.lock
|
||||
|
||||
begin
|
||||
@writer = true
|
||||
|
||||
exclusive_mutex.lock
|
||||
|
||||
@owner = Thread.current
|
||||
ensure
|
||||
write_sync_mutex.unlock
|
||||
end
|
||||
end
|
||||
|
||||
# Release the exclusive write lock
|
||||
def unlock_write
|
||||
# If the caller is not the owner of the write lock, then someone is
|
||||
# doing something broken, let's let them know.
|
||||
if (Thread.current != @owner)
|
||||
raise RuntimeError, "Non-owner calling thread attempted to release write lock", caller
|
||||
end
|
||||
|
||||
# Otherwise, release the exclusive write lock
|
||||
@writer = false
|
||||
|
||||
exclusive_mutex.unlock
|
||||
end
|
||||
|
||||
# Synchronize a block for read access
|
||||
def synchronize_read
|
||||
lock_read
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
unlock_read
|
||||
end
|
||||
end
|
||||
|
||||
# Synchronize a block for write access
|
||||
def synchronize_write
|
||||
lock_write
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
unlock_write
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :read_sync_mutex
|
||||
attr_accessor :write_sync_mutex
|
||||
attr_accessor :exclusive_mutex
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,87 @@
|
|||
module Rex
|
||||
|
||||
###
|
||||
#
|
||||
# Transformer - more than meets the eye!
|
||||
# -----------
|
||||
#
|
||||
# This class, aside from having a kickass name, is responsible for translating
|
||||
# object instances of one or more types into a single list instance of one or
|
||||
# more types. This is useful for translating object instances that be can
|
||||
# either strings or an array of strings into an array of strings, for
|
||||
# instance. It lets you make things take a uniform structure in an abstract
|
||||
# manner.
|
||||
#
|
||||
###
|
||||
class Transformer
|
||||
|
||||
# Translates the object instance supplied in src_instance to an instance of
|
||||
# dst_class. The dst_class parameter's instance must support the <<
|
||||
# operator. An example call to this method looks something like:
|
||||
#
|
||||
# Transformer.transform(string, Array, [ String ], target)
|
||||
def Transformer.transform(src_instance, dst_class, supported_classes,
|
||||
target = nil)
|
||||
dst_instance = dst_class.new
|
||||
|
||||
if (src_instance.kind_of?(Array))
|
||||
src_instance.each { |src_inst|
|
||||
Transformer.transform_single(src_inst, dst_instance,
|
||||
supported_classes, target)
|
||||
}
|
||||
elsif (!src_instance.kind_of?(NilClass))
|
||||
Transformer.transform_single(src_instance, dst_instance,
|
||||
supported_classes, target)
|
||||
end
|
||||
|
||||
return dst_instance
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Transform a single source instance.
|
||||
def Transformer.transform_single(src_instance, dst_instance,
|
||||
supported_classes, target)
|
||||
# If the src instance's class is supported, just add it to the dst
|
||||
# instance
|
||||
if (supported_classes.include?(src_instance.class))
|
||||
dst_instance << src_instance
|
||||
# If the source instance is a string, query each of the supported
|
||||
# classes to see if they can serialize it to their particular data
|
||||
# type.
|
||||
elsif (src_instance.kind_of?(String))
|
||||
new_src_instance = nil
|
||||
|
||||
# Walk each supported class calling from_s if exported
|
||||
supported_classes.each { |sup_class|
|
||||
new_src_instance = sup_class.from_s(src_instance)
|
||||
|
||||
if (new_src_instance != nil)
|
||||
dst_instance << new_src_instance
|
||||
break
|
||||
end
|
||||
}
|
||||
|
||||
# If we don't have a valid new src instance, then we suck
|
||||
if (new_src_instance == nil)
|
||||
bomb_translation(src_instance, target)
|
||||
end
|
||||
# Otherwise, bomb translation
|
||||
else
|
||||
bomb_translation(src_instance, target)
|
||||
end
|
||||
end
|
||||
|
||||
def Transformer.bomb_translation(src_instance, target)
|
||||
error = "Invalid source class (#{src_instance.class})"
|
||||
|
||||
if (target != nil)
|
||||
error += " for #{target}"
|
||||
end
|
||||
|
||||
raise ArgumentError, error, caller
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue