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