metasploit-framework/lib/rex/service_manager.rb

155 lines
3.2 KiB
Ruby

# -*- coding: binary -*-
require 'singleton'
require 'rex'
require 'rex/service'
module Rex
###
#
# This class manages service allocation and interaction. This class can be
# used to start HTTP servers and manage them and all that stuff. Yup.
#
###
class ServiceManager < Hash
#
# This class is a singleton.
#
include Singleton
#
# Calls the instance method to start a service.
#
def self.start(klass, *args)
self.instance.start(klass, *args)
end
#
# Calls the instance method to stop a service.
#
def self.stop(klass, *args)
self.instance.stop(klass, *args)
end
#
# Stop a service using the alias that's associated with it.
#
def self.stop_by_alias(als)
self.instance.stop_by_alias(als)
end
#
# Stop the supplied service instance.
#
def self.stop_service(service)
self.instance.stop_service(service)
end
#
# Starts a service and assigns it a unique name in the service hash.
#
def start(klass, *args)
# Get the hardcore alias.
hals = "#{klass}" + klass.hardcore_alias(*args)
# Has a service already been constructed for this guy? If so, increment
# its reference count like it aint no thang.
if (inst = self[hals])
inst.ref
return inst
end
inst = klass.new(*args)
als = inst.alias
# Find an alias that isn't taken.
if (self[als])
cnt = 1
cnt += 1 while (self[als + " #{cnt}"])
als = inst.alias + " #{cnt}"
end
# Extend the instance as a service.
inst.extend(Rex::Service)
# Re-aliases the instance.
inst.alias = als
# Fire up the engines. If an error occurs an exception will be
# raised.
inst.start
# Alias associate and initialize reference counting
self[als] = self[hals] = inst.refinit
# Pass the caller a reference
inst.ref
inst
end
#
# Stop a service using a given klass and arguments. These should mirror
# what was originally passed to start exactly. If the reference count of
# the service drops to zero the service will be destroyed.
#
def stop(klass, *args)
stop_service(hals[hardcore_alias(klass, *args)])
end
#
# Stops a service using the provided alias.
#
def stop_by_alias(als)
stop_service(self[als])
end
#
# Stops a service instance.
#
def stop_service(inst)
# Stop the service and be done wif it, but only if the number of
# references has dropped to zero
if (inst)
# Since the instance may have multiple aliases, scan through
# all the pairs for matching stuff.
self.each_pair { |cals, cinst|
self.delete(cals) if (inst == cinst)
}
# Lose the list-held reference to the instance
inst.deref
return true
end
# Return false if the service isn't there
return false
end
#
# Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+
# "can't add a new key into hash during iteration"
#
def each(&block)
list = []
self.keys.sort.each do |sidx|
list << [sidx, self[sidx]]
end
list.each(&block)
end
protected
#
# Returns the alias for a given service instance.
#
def hardcore_alias(klass, *args)
"__#{klass.name}#{args}"
end
end
end