From: om Date: Tue, 28 Aug 2007 18:47:55 +0000 (+0000) Subject: First step on the road of module loader rewriting. So far this only really removes... X-Git-Tag: v2.0.23~4612 X-Git-Url: https://git.netwichtig.de/gitweb/?a=commitdiff_plain;h=b37ec974ee20b943a9129ae054390a565c49bd3c;p=user%2Fhenk%2Fcode%2Finspircd.git First step on the road of module loader rewriting. So far this only really removes module factories. Any modules not updated to use MODULE_INIT() yet will now fail to compile \o/ git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@7971 e03df62e-2008-0410-955e-edbf42e46eb7 --- diff --git a/include/base.h b/include/base.h index e769e93b1..faea391a3 100644 --- a/include/base.h +++ b/include/base.h @@ -223,6 +223,66 @@ class CoreExport BoolSet : public classbase bool operator=(BoolSet other); }; +/** This class can be used on its own to represent an exception, or derived to represent a module-specific exception. + * When a module whishes to abort, e.g. within a constructor, it should throw an exception using ModuleException or + * a class derived from ModuleException. If a module throws an exception during its constructor, the module will not + * be loaded. If this happens, the error message returned by ModuleException::GetReason will be displayed to the user + * attempting to load the module, or dumped to the console if the ircd is currently loading for the first time. + */ +class CoreExport CoreException : public std::exception +{ + protected: + /** Holds the error message to be displayed + */ + const std::string err; + /** Source of the exception + */ + const std::string source; + public: + /** Default constructor, just uses the error mesage 'Core threw an exception'. + */ + CoreException() : err("Core threw an exception"), source("The core") {} + /** This constructor can be used to specify an error message before throwing. + */ + CoreException(const std::string &message) : err(message), source("The core") {} + /** This constructor can be used to specify an error message before throwing, + * and to specify the source of the exception. + */ + CoreException(const std::string &message, const std::string &src) : err(message), source(src) {} + /** This destructor solves world hunger, cancels the world debt, and causes the world to end. + * Actually no, it does nothing. Never mind. + * @throws Nothing! + */ + virtual ~CoreException() throw() {}; + /** Returns the reason for the exception. + * The module should probably put something informative here as the user will see this upon failure. + */ + virtual const char* GetReason() + { + return err.c_str(); + } -#endif + virtual const char* GetSource() + { + return source.c_str(); + } +}; + +class CoreExport ModuleException : public CoreException +{ + public: + /** Default constructor, just uses the error mesage 'Module threw an exception'. + */ + ModuleException() : CoreException("Module threw an exception", "A Module") {} + + /** This constructor can be used to specify an error message before throwing. + */ + ModuleException(const std::string &message) : CoreException(message, "A Module") {} + /** This destructor solves world hunger, cancels the world debt, and causes the world to end. + * Actually no, it does nothing. Never mind. + * @throws Nothing! + */ + virtual ~ModuleException() throw() {}; +}; +#endif diff --git a/include/dynamic.h b/include/dynamic.h index db46291c4..6de566117 100644 --- a/include/dynamic.h +++ b/include/dynamic.h @@ -14,21 +14,19 @@ #ifndef __DLL_H #define __DLL_H -/** This typedef represents the init_module function within each module. - * The init_module function is the only exported extern "C" declaration - * in any module file. - */ -typedef void * (initfunc) (void); - #include "inspircd_config.h" -class InspIRCd; - /** The DLLManager class is able to load a module file by filename, * and locate its init_module symbol. */ class CoreExport DLLManager { + protected: + + /** The last error string, or NULL + */ + char *err; + public: /** This constructor loads the module using dlopen() * @param ServerInstance The creator class of this object @@ -58,43 +56,64 @@ class CoreExport DLLManager * pointer (yes, really!) and on windows it is a library handle. */ void *h; - - protected: - - /** The last error string, or NULL - */ - char *err; }; -/** This class is a specialized form of DLLManager designed to load InspIRCd modules. - * It's job is to call the init_module function and receive a factory pointer. - */ -class CoreExport DLLFactoryBase : public DLLManager +class CoreExport LoadModuleException : public CoreException { public: - /** Default constructor. - * This constructor loads a module file by calling its DLLManager subclass constructor, - * then finds the symbol using DLLManager::GetSymbol(), and calls the symbol, - * obtaining a valid pointer to the init_module function + /** This constructor can be used to specify an error message before throwing. */ - DLLFactoryBase(InspIRCd* Instance, const char *fname, const char *func_name = 0); - - /** Default destructor. + LoadModuleException(const std::string &message) + : CoreException(message, "the core") + { + } + + /** This destructor solves world hunger, cancels the world debt, and causes the world to end. + * Actually no, it does nothing. Never mind. + * @throws Nothing! */ - virtual ~DLLFactoryBase(); + virtual ~LoadModuleException() throw() {}; +}; - /** A function pointer to the factory function. +class CoreExport FindSymbolException : public CoreException +{ + public: + /** This constructor can be used to specify an error message before throwing. + */ + FindSymbolException(const std::string &message) + : CoreException(message, "the core") + { + } + + /** This destructor solves world hunger, cancels the world debt, and causes the world to end. + * Actually no, it does nothing. Never mind. + * @throws Nothing! */ - void * (*factory_func)(void); + virtual ~FindSymbolException() throw() {}; }; -/** This is the highest-level class of the DLLFactory system used to load InspIRCd modules. - * Its job is to finally call the init_module function and obtain a pointer to a ModuleFactory. - * This template is a container for ModuleFactory itself, so that it may 'plug' into ModuleFactory - * and provide module loading capabilities transparently. +/** This is the highest-level class of the DLLFactory system used to load InspIRCd modules and commands. + * All the dirty mucking around with dl*() is done by DLLManager, all this does it put a pretty shell on + * it and make it nice to use to load modules and core commands. This class is quite specialised for these + * two uses and it may not be useful more generally -- use DLLManager directly for that. */ -template class CoreExport DLLFactory : public DLLFactoryBase +template class CoreExport DLLFactory : public DLLManager { + protected: + /** This typedef represents the init_* function within each module or command. + * The init_module function is the only exported extern "C" declaration + * in any module file. In a cmd_*.cpp file the equivilant is init_command + */ + typedef ReturnType * (initfunctype) (InspIRCd*); + + /** Pointer to the init function. + */ + initfunctype* init_func; + + /** Instance pointer to be passed to init_*() when it is called. + */ + InspIRCd* ServerInstance; + public: /** Default constructor. * This constructor passes its paramerers down through DLLFactoryBase and then DLLManager @@ -102,26 +121,41 @@ template class CoreExport DLLFactory : public DLLFactoryBase * class. It is then down to the core to call the ModuleFactory::CreateModule() method and * receive a Module* which it can insert into its module lists. */ - DLLFactory(InspIRCd* Instance, const char *fname, const char *func_name=0) : DLLFactoryBase(Instance, fname, func_name) + DLLFactory(InspIRCd* Instance, const char *fname, const char *func_name) + : DLLManager(Instance, fname), init_func(NULL), ServerInstance(Instance) + { + const char* error = LastError(); + + if(!error) + { + if(!GetSymbol((void **)&init_func, func_name)) + { + throw FindSymbolException("Missing " + std::string(func_name) + "() entrypoint!"); + } + } + else + { + throw LoadModuleException(error); + } + } + + ReturnType* CallInit() { - if (factory_func) - factory = reinterpret_cast(factory_func()); + if(init_func) + { + return init_func(ServerInstance); + } else - factory = reinterpret_cast(-1); + { + return NULL; + } } /** The destructor deletes the ModuleFactory pointer. */ ~DLLFactory() { - if (factory) - delete factory; } - - /** The ModuleFactory pointer. - */ - T *factory; }; #endif - diff --git a/include/globals.h b/include/globals.h index 4a01e454e..bf832be59 100644 --- a/include/globals.h +++ b/include/globals.h @@ -36,4 +36,3 @@ typedef std::vector< KeyVal > KeyValList; typedef std::multimap< std::string, KeyValList > ConfigDataHash; #endif - diff --git a/include/modules.h b/include/modules.h index df857d506..e5596430f 100644 --- a/include/modules.h +++ b/include/modules.h @@ -93,6 +93,7 @@ class ServerConfig; /* Forward-delacare module for ModuleMessage etc */ class Module; +class InspIRCd; /** Low level definition of a FileReader classes file cache area - * a text file seperated into lines. @@ -361,68 +362,6 @@ class CoreExport Event : public ModuleMessage char* Send(InspIRCd* ServerInstance); }; -/** This class can be used on its own to represent an exception, or derived to represent a module-specific exception. - * When a module whishes to abort, e.g. within a constructor, it should throw an exception using ModuleException or - * a class derived from ModuleException. If a module throws an exception during its constructor, the module will not - * be loaded. If this happens, the error message returned by ModuleException::GetReason will be displayed to the user - * attempting to load the module, or dumped to the console if the ircd is currently loading for the first time. - */ -class CoreExport CoreException : public std::exception -{ - protected: - /** Holds the error message to be displayed - */ - const std::string err; - /** Source of the exception - */ - const std::string source; - public: - /** Default constructor, just uses the error mesage 'Core threw an exception'. - */ - CoreException() : err("Core threw an exception"), source("The core") {} - /** This constructor can be used to specify an error message before throwing. - */ - CoreException(const std::string &message) : err(message), source("The core") {} - /** This constructor can be used to specify an error message before throwing, - * and to specify the source of the exception. - */ - CoreException(const std::string &message, const std::string &src) : err(message), source(src) {} - /** This destructor solves world hunger, cancels the world debt, and causes the world to end. - * Actually no, it does nothing. Never mind. - * @throws Nothing! - */ - virtual ~CoreException() throw() {}; - /** Returns the reason for the exception. - * The module should probably put something informative here as the user will see this upon failure. - */ - virtual const char* GetReason() - { - return err.c_str(); - } - - virtual const char* GetSource() - { - return source.c_str(); - } -}; - -class CoreExport ModuleException : public CoreException -{ - public: - /** Default constructor, just uses the error mesage 'Module threw an exception'. - */ - ModuleException() : CoreException("Module threw an exception", "A Module") {} - - /** This constructor can be used to specify an error message before throwing. - */ - ModuleException(const std::string &message) : CoreException(message, "A Module") {} - /** This destructor solves world hunger, cancels the world debt, and causes the world to end. - * Actually no, it does nothing. Never mind. - * @throws Nothing! - */ - virtual ~ModuleException() throw() {}; -}; - /** Priority types which can be returned from Module::Prioritize() */ enum Priority { PRIORITY_FIRST, PRIORITY_DONTCARE, PRIORITY_LAST, PRIORITY_BEFORE, PRIORITY_AFTER }; @@ -1639,32 +1578,10 @@ class CoreExport FileReader : public classbase int FileSize(); }; - -/** Instantiates classes inherited from Module. - * This class creates a class inherited from type Module, using new. This is to allow for modules - * to create many different variants of Module, dependent on architecture, configuration, etc. - * In most cases, the simple class shown in the example module m_foobar.so will suffice for most - * modules. - */ -class CoreExport ModuleFactory : public classbase -{ - public: - /** The default constructor does nothing. - */ - ModuleFactory() { } - /** The default destructor does nothing - */ - virtual ~ModuleFactory() { } - /** Creates a new module. - * Your inherited class of ModuleFactory must return a pointer to your Module class - * using this method. - */ - virtual Module * CreateModule(InspIRCd* Me) = 0; -}; - -/** A DLLFactory (designed to load shared objects) containing a ModuleFactory. +/** A DLLFactory (designed to load shared objects) containing a + * handle to a module's init_module() function. */ -typedef DLLFactory ircd_module; +typedef DLLFactory ircd_module; /** A list of loaded Modules */ @@ -1679,18 +1596,9 @@ typedef std::vector FactoryList; * It defines the class factory and external init_module function. */ #define MODULE_INIT(y) \ - class Factory : public ModuleFactory \ + extern "C" DllExport Module * init_module(InspIRCd* Me) \ { \ - public: \ - virtual Module * CreateModule(InspIRCd* Me) \ - { \ - return new y(Me); \ - } \ - }; \ - extern "C" DllExport void * init_module(void) \ - { \ - return new Factory; \ + return new y(Me); \ } #endif - diff --git a/src/dynamic.cpp b/src/dynamic.cpp index 80035ef70..9a0ae34d3 100644 --- a/src/dynamic.cpp +++ b/src/dynamic.cpp @@ -11,6 +11,7 @@ * --------------------------------------------------- */ +#include "globals.h" #include "inspircd.h" #include "dynamic.h" #ifndef WIN32 @@ -63,22 +64,3 @@ bool DLLManager::GetSymbol(void** v, const char* sym_name) /* succeeded :) */ return true; } - -DLLFactoryBase::DLLFactoryBase(InspIRCd* Instance, const char* fname, const char* symbol) : DLLManager(Instance, fname) -{ - /* try get the factory function if there is no error yet */ - factory_func = 0; - - if (!LastError()) - { - if (!GetSymbol( (void **)&factory_func, symbol ? symbol : "init_module")) - { - throw ModuleException("Missing init_module() entrypoint!"); - } - } -} - -DLLFactoryBase::~DLLFactoryBase() -{ -} - diff --git a/src/modules.cpp b/src/modules.cpp index 906efd862..08bbcd513 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -427,38 +427,39 @@ bool InspIRCd::LoadModule(const char* filename) if (!ServerConfig::DirValid(modfile)) { - this->Log(DEFAULT,"Module %s is not within the modules directory.",modfile); - snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile); + snprintf(MODERR, MAXBUF,"Module %s is not within the modules directory.", modfile); + this->Log(DEFAULT, MODERR); return false; } + if (ServerConfig::FileExists(modfile)) { - for (unsigned int j = 0; j < Config->module_names.size(); j++) { if (Config->module_names[j] == filename_str) { this->Log(DEFAULT,"Module %s is already loaded, cannot load a module twice!",modfile); - snprintf(MODERR,MAXBUF,"Module already loaded"); + snprintf(MODERR, MAXBUF, "Module already loaded"); return false; } } + Module* m = NULL; ircd_module* a = NULL; + try { - a = new ircd_module(this, modfile); + /* This will throw a CoreException if there's a problem loading + * the module file or getting a pointer to the init_module symbol. + */ + a = new ircd_module(this, modfile, "init_module"); + factory[this->ModCount+1] = a; - if (factory[this->ModCount+1]->LastError()) - { - this->Log(DEFAULT,"Unable to load %s: %s",modfile,factory[this->ModCount+1]->LastError()); - snprintf(MODERR,MAXBUF,"Loader/Linker error: %s",factory[this->ModCount+1]->LastError()); - return false; - } - if ((long)factory[this->ModCount+1]->factory != -1) - { - m = factory[this->ModCount+1]->factory->CreateModule(this); + + m = factory[this->ModCount+1]->CallInit(); + if(m) + { Version v = m->GetVersion(); if (v.API != API_VERSION) @@ -474,6 +475,7 @@ bool InspIRCd::LoadModule(const char* filename) } modules[this->ModCount+1] = m; + /* save the module and the module's classfactory, if * this isnt done, random crashes can occur :/ */ Config->module_names.push_back(filename); @@ -489,11 +491,23 @@ bool InspIRCd::LoadModule(const char* filename) } else { - this->Log(DEFAULT,"Unable to load %s",modfile); - snprintf(MODERR,MAXBUF,"Factory function failed: Probably missing init_module() entrypoint."); + this->Log(DEFAULT, "Unable to load %s",modfile); + snprintf(MODERR,MAXBUF, "Probably missing init_module() entrypoint, but dlsym() didn't notice a problem"); return false; } } + catch (LoadModuleException& modexcept) + { + this->Log(DEFAULT,"Unable to load %s: %s", modfile, modexcept.GetReason()); + snprintf(MODERR,MAXBUF,"Loader/Linker error: %s", modexcept.GetReason()); + return false; + } + catch (FindSymbolException& modexcept) + { + this->Log(DEFAULT,"Unable to load %s: %s", modfile, modexcept.GetReason()); + snprintf(MODERR,MAXBUF,"Loader/Linker error: %s", modexcept.GetReason()); + return false; + } catch (CoreException& modexcept) { this->Log(DEFAULT,"Unable to load %s: %s",modfile,modexcept.GetReason()); @@ -507,6 +521,7 @@ bool InspIRCd::LoadModule(const char* filename) snprintf(MODERR,MAXBUF,"Module file could not be found"); return false; } + this->ModCount++; FOREACH_MOD_I(this,I_OnLoadModule,OnLoadModule(modules[this->ModCount],filename_str)); // now work out which modules, if any, want to move to the back of the queue, @@ -1066,5 +1081,3 @@ int FileReader::FileSize() { return fc.size(); } - -