]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Fix module unmapping with culled Module objects
authordanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>
Wed, 14 Oct 2009 22:12:55 +0000 (22:12 +0000)
committerdanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>
Wed, 14 Oct 2009 22:12:55 +0000 (22:12 +0000)
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@11875 e03df62e-2008-0410-955e-edbf42e46eb7

22 files changed:
include/base.h
include/caller.h
include/cull_list.h
include/inspircd.h
include/modules.h
src/commands/cmd_reloadmodule.cpp
src/commands/cmd_unloadmodule.cpp
src/configreader.cpp
src/cull_list.cpp
src/dynamic.cpp
src/inspircd.cpp
src/modules.cpp
src/modules/extra/m_pgsql.cpp
src/modules/m_filter.cpp
src/modules/m_globalload.cpp
src/modules/m_password_hash.cpp
src/modules/m_rline.cpp
src/modules/m_spanningtree/main.cpp
src/modules/m_spanningtree/main.h
src/modules/m_sqllog.cpp
src/modules/m_sqloper.cpp
src/testsuite.cpp

index 0464f68e205bc609a312b5c1076ef5100e58ced1..ed03eeac5313c45e15d975005ffc8b8e72e3e9df 100644 (file)
@@ -55,8 +55,8 @@ class CoreExport refcountbase : public classbase
 class CoreExport reference_base
 {
  protected:
-       static inline unsigned int inc(refcountbase* v) { return ++(v->refcount); }
-       static inline unsigned int dec(refcountbase* v) { return --(v->refcount); }
+       template<typename T> static inline unsigned int inc(T* v) { return ++(v->refcount); }
+       template<typename T> static inline unsigned int dec(T* v) { return --(v->refcount); }
 };
 
 template <typename T>
index 66603575221e794e395b315606738b522c81d2d1..420f17afb1ecd6a081a65178b3a0188c8bc41843 100644 (file)
  * this until you do, as if you get this wrong, this can generate some pretty long
  * winded and confusing error messages at compile time.
  */
-template <typename ReturnType> class CoreExport HandlerBase0
+template <typename ReturnType> class CoreExport HandlerBase0 : public classbase
 {
  public:
        virtual ReturnType Call() = 0;
        virtual ~HandlerBase0() { }
 };
 
-template <typename ReturnType, typename Param1> class CoreExport HandlerBase1
+template <typename ReturnType, typename Param1> class CoreExport HandlerBase1 : public classbase
 {
  public:
        virtual ReturnType Call(Param1) = 0;
        virtual ~HandlerBase1() { }
 };
 
-template <typename ReturnType, typename Param1, typename Param2> class CoreExport HandlerBase2
+template <typename ReturnType, typename Param1, typename Param2> class CoreExport HandlerBase2 : public classbase
 {
  public:
        virtual ReturnType Call(Param1, Param2) = 0;
        virtual ~HandlerBase2() { }
 };
 
-template <typename ReturnType, typename Param1, typename Param2, typename Param3> class CoreExport HandlerBase3
+template <typename ReturnType, typename Param1, typename Param2, typename Param3> class CoreExport HandlerBase3 : public classbase
 {
  public:
        virtual ReturnType Call(Param1, Param2, Param3) = 0;
        virtual ~HandlerBase3() { }
 };
 
-template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4> class CoreExport HandlerBase4
+template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4> class CoreExport HandlerBase4 : public classbase
 {
  public:
        virtual ReturnType Call(Param1, Param2, Param3, Param4) = 0;
        virtual ~HandlerBase4() { }
 };
 
-template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5> class CoreExport HandlerBase5
+template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5> class CoreExport HandlerBase5 : public classbase
 {
  public:
        virtual ReturnType Call(Param1, Param2, Param3, Param4, Param5) = 0;
        virtual ~HandlerBase5() { }
 };
 
-template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6> class CoreExport HandlerBase6
+template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6> class CoreExport HandlerBase6 : public classbase
 {
  public:
        virtual ReturnType Call(Param1, Param2, Param3, Param4, Param5, Param6) = 0;
        virtual ~HandlerBase6() { }
 };
 
-template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7> class CoreExport HandlerBase7
+template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7> class CoreExport HandlerBase7 : public classbase
 {
  public:
        virtual ReturnType Call(Param1, Param2, Param3, Param4, Param5, Param6, Param7) = 0;
        virtual ~HandlerBase7() { }
 };
 
-template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8> class CoreExport HandlerBase8
+template <typename ReturnType, typename Param1, typename Param2, typename Param3, typename Param4, typename Param5, typename Param6, typename Param7, typename Param8> class CoreExport HandlerBase8 : public classbase
 {
  public:
        virtual ReturnType Call(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8) = 0;
@@ -120,12 +120,6 @@ template <typename HandlerType> class CoreExport caller
        { }
 
        virtual ~caller() { }
-
-       caller& operator=(HandlerType* newtarget)
-       {
-               target = newtarget;
-               return *this;
-       }
 };
 
 template <typename ReturnType> class CoreExport caller0 : public caller< HandlerBase0<ReturnType> >
index 2b3ed13915435fa25d9f18a0c44c4760906827b7..33e9a7ea6039aa026598230ac49fdefa50a7814b 100644 (file)
@@ -33,5 +33,20 @@ class CoreExport CullList
        void Apply();
 };
 
+class CoreExport ActionList
+{
+       std::vector<HandlerBase0<void>*> list;
+
+ public:
+       /** Adds an item to the list
+        */
+       void AddAction(HandlerBase0<void>* item) { list.push_back(item); }
+
+       /** Runs the items
+        */
+       void Run();
+
+};
+
 #endif
 
index df80ba4bfc425d0eb39e29f3ca21fa0522b40e5e..4fb28e2d7f66ea251c6d409b6b6eebf48c7fc62f 100644 (file)
@@ -78,6 +78,8 @@ CoreExport extern InspIRCd* ServerInstance;
 
 #include "inspircd_config.h"
 #include "inspircd_version.h"
+#include "caller.h"
+#include "cull_list.h"
 #include "extensible.h"
 #include "numerics.h"
 #include "uid.h"
@@ -94,7 +96,6 @@ CoreExport extern InspIRCd* ServerInstance;
 #include "mode.h"
 #include "socketengine.h"
 #include "snomasks.h"
-#include "cull_list.h"
 #include "filelogger.h"
 #include "caller.h"
 #include "modules.h"
@@ -381,6 +382,8 @@ class CoreExport InspIRCd : public classbase
        /** Global cull list, will be processed on next iteration
         */
        CullList GlobalCulls;
+       /** Actions that must happen outside of the current call stack */
+       ActionList AtomicActions;
 
        /**** Functors ****/
 
index 9207a2bd98dc925f708b9d1a8a57f4259493a51f..151c3fef836928659225da7f304b900743c905ce 100644 (file)
@@ -107,7 +107,7 @@ struct ModResult {
 /** If you change the module API in any way, increment this value.
  * This MUST be a pure integer, with no parenthesis
  */
-#define API_VERSION 133
+#define API_VERSION 134
 
 class ServerConfig;
 
@@ -917,9 +917,8 @@ class CoreExport Module : public Extensible
         * absolutely neccessary (e.g. a module that extends the features of another
         * module).
         * @param mod A pointer to the new module
-        * @param name The new module's filename
         */
-       virtual void OnLoadModule(Module* mod,const std::string &name);
+       virtual void OnLoadModule(Module* mod);
 
        /** Called whenever a module is unloaded.
         * mod will contain a pointer to the module, and string will contain its name,
@@ -933,7 +932,7 @@ class CoreExport Module : public Extensible
         * @param mod Pointer to the module being unloaded (still valid)
         * @param name The filename of the module being unloaded
         */
-       virtual void OnUnloadModule(Module* mod,const std::string &name);
+       virtual void OnUnloadModule(Module* mod);
 
        /** Called once every five seconds for background processing.
         * This timer can be used to control timed features. Its period is not accurate
@@ -1502,6 +1501,9 @@ class CoreExport ModuleManager : public classbase
                PRIO_STATE_AGAIN,
                PRIO_STATE_LAST
        } prioritizationState;
+
+       /** Internal unload module hook */
+       bool CanUnload(Module*);
  public:
 
        /** Event handler hooks.
@@ -1590,15 +1592,24 @@ class CoreExport ModuleManager : public classbase
         */
        bool Load(const char* filename);
 
-       /** Unload a given module file
-        * @param filename The file to unload
-        * @return True if the module was unloaded
+       /** Unload a given module file. Note that the module will not be
+        * completely gone until the cull list has finished processing.
+        *
+        * @return true on success; if false, LastError will give a reason
+        */
+       bool Unload(Module* module);
+
+       /** Run an asynchronous reload of the given module. When the reload is
+        * complete, the callback will be run with true if the reload succeeded
+        * and false if it did not.
         */
-       bool Unload(const char* filename);
+       void Reload(Module* module, HandlerBase1<void, bool>* callback);
 
        /** Called by the InspIRCd constructor to load all modules from the config file.
         */
        void LoadAll();
+       void UnloadAll();
+       void DoSafeUnload(Module*);
 
        /** Get the total number of currently loaded modules
         * @return The number of loaded modules
index 37693b501cdd6b0ec437fce5989d6a5ad4c84ef8..ca972fd18875bab4f93d112fcead4982ce974ddd 100644 (file)
@@ -28,6 +28,24 @@ class CommandReloadmodule : public Command
        CmdResult Handle(const std::vector<std::string>& parameters, User *user);
 };
 
+class ReloadModuleWorker : public HandlerBase1<void, bool>
+{
+ public:
+       const std::string name;
+       const std::string uid;
+       ReloadModuleWorker(const std::string& uuid, const std::string& modn)
+               : name(modn), uid(uuid) {}
+       void Call(bool result)
+       {
+               ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s %ssuccessfully reloaded",
+                       name.c_str(), result ? "" : "un");
+               User* user = ServerInstance->FindNick(uid);
+               if (user)
+                       user->WriteNumeric(975, "%s %s :Module %ssuccessfully reloaded.",
+                               user->nick.c_str(), name.c_str(), result ? "" : "un");
+       }
+};
+
 CmdResult CommandReloadmodule::Handle (const std::vector<std::string>& parameters, User *user)
 {
        if (parameters[0] == "cmd_reloadmodule.so")
@@ -37,20 +55,17 @@ CmdResult CommandReloadmodule::Handle (const std::vector<std::string>& parameter
                return CMD_FAILURE;
        }
 
-       if (ServerInstance->Modules->Unload(parameters[0].c_str()))
+       Module* m = ServerInstance->Modules->Find(parameters[0]);
+       if (m)
        {
-               ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s unloaded %s",user->nick.c_str(), parameters[0].c_str());
-               if (ServerInstance->Modules->Load(parameters[0].c_str()))
-               {
-                       ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s reloaded %s",user->nick.c_str(), parameters[0].c_str());
-                       user->WriteNumeric(975, "%s %s :Module successfully reloaded.",user->nick.c_str(), parameters[0].c_str());
-                       return CMD_SUCCESS;
-               }
+               ServerInstance->Modules->Reload(m, new ReloadModuleWorker(parameters[0], user->uuid));
+               return CMD_SUCCESS;
+       }
+       else
+       {
+               user->WriteNumeric(975, "%s %s :Could not find module by that name", user->nick.c_str(), parameters[0].c_str());
+               return CMD_FAILURE;
        }
-
-       ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s unsuccessfully reloaded %s",user->nick.c_str(), parameters[0].c_str());
-       user->WriteNumeric(975, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
-       return CMD_FAILURE;
 }
 
 COMMAND_INIT(CommandReloadmodule)
index 5aecd22ddef0d1f924d642a7c227846bcd618fd3..c3ae49d1ce5c1669bd54941399d6bd159059fa3e 100644 (file)
@@ -41,14 +41,16 @@ CmdResult CommandUnloadmodule::Handle (const std::vector<std::string>& parameter
                return CMD_FAILURE;
        }
                
-       if (ServerInstance->Modules->Unload(parameters[0].c_str()))
+       Module* m = ServerInstance->Modules->Find(parameters[0]);
+       if (m && ServerInstance->Modules->Unload(m))
        {
                ServerInstance->SNO->WriteGlobalSno('a', "MODULE UNLOADED: %s unloaded %s", user->nick.c_str(), parameters[0].c_str());
                user->WriteNumeric(973, "%s %s :Module successfully unloaded.",user->nick.c_str(), parameters[0].c_str());
        }
        else
        {
-               user->WriteNumeric(972, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
+               user->WriteNumeric(972, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(),
+                       m ? ServerInstance->Modules->LastError().c_str() : "No such module");
                return CMD_FAILURE;
        }
 
index 70c99e8ae4f7257a7a28a6b315b336d91bc43dfb..4877cab5a518422cf1c594b2c098223cef87563a 100644 (file)
@@ -1219,7 +1219,8 @@ void ServerConfig::ApplyModules(User* user)
                // Don't remove cmd_*.so, just remove m_*.so
                if (removing->c_str()[0] == 'c')
                        continue;
-               if (ServerInstance->Modules->Unload(removing->c_str()))
+               Module* m = ServerInstance->Modules->Find(*removing);
+               if (m && ServerInstance->Modules->Unload(m))
                {
                        ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH UNLOADED MODULE: %s",removing->c_str());
 
index f87095126c1dcf42d744adb49847dd61a3481f61..6033ec695a126de15698520cfbbc838f0438833e 100644 (file)
@@ -48,3 +48,11 @@ void CullList::Apply()
        }
 }
 
+void ActionList::Run()
+{
+       for(unsigned int i=0; i < list.size(); i++)
+       {
+               list[i]->Call();
+       }
+       list.clear();
+}
index 637a57db4552c7d6c415ee5e44a1aca24335e590..70d5e7cae8b5a47d278c0199ba381f284889d693 100644 (file)
@@ -26,7 +26,7 @@ DLLManager::DLLManager(const char *fname)
                return;
        }
 
-       h = dlopen(fname, RTLD_NOW|RTLD_LOCAL|RTLD_NODELETE);
+       h = dlopen(fname, RTLD_NOW|RTLD_LOCAL);
        if (!h)
        {
                err = dlerror();
index a1273d651638a1821ca464da833881099b7db7ef..c591097245aeeaa0a075c6d7f586c5552af6f752 100644 (file)
@@ -111,22 +111,8 @@ void InspIRCd::Cleanup()
                Users->QuitUser(u, "Server shutdown");
        }
 
-       /* We do this more than once, so that any service providers get a
-        * chance to be unhooked by the modules using them, but then get
-        * a chance to be removed themsleves.
-        *
-        * XXX there may be a better way to do this
-        */
-       for (int tries = 0; tries < 4; tries++)
-       {
-               std::vector<std::string> module_names = Modules->GetAllModuleNames(0);
-               for (std::vector<std::string>::iterator k = module_names.begin(); k != module_names.end(); ++k)
-               {
-                       /* Unload all modules, so they get a chance to clean up their listeners */
-                       this->Modules->Unload(k->c_str());
-               }
-               GlobalCulls.Apply();
-       }
+       GlobalCulls.Apply();
+       Modules->UnloadAll();
 
        /* Delete objects dynamically allocated in constructor (destructor would be more appropriate, but we're likely exiting) */
        /* Must be deleted before modes as it decrements modelines */
@@ -788,7 +774,8 @@ int InspIRCd::Run()
                this->SE->DispatchEvents();
 
                /* if any users were quit, take them out */
-               this->GlobalCulls.Apply();
+               GlobalCulls.Apply();
+               AtomicActions.Run();
 
                if (this->s_signal)
                {
index 8c0fccba6d91fd7239d6cc33121a07da6e94e588..f1e53deba59056c952f5bb1b594eb19c8a36e469 100644 (file)
@@ -11,8 +11,6 @@
  * ---------------------------------------------------
  */
 
-/* $Core */
-
 #include "inspircd.h"
 #include "xline.h"
 #include "socket.h"
@@ -56,7 +54,6 @@ void Event::Send()
 Module::Module() { }
 bool Module::cull()
 {
-       ServerInstance->GlobalCulls.AddItem(ModuleDLLManager);
        return true;
 }
 Module::~Module() { }
@@ -85,8 +82,8 @@ void          Module::OnUserPostNick(User*, const std::string&) { }
 ModResult      Module::OnPreMode(User*, User*, Channel*, const std::vector<std::string>&) { return MOD_RES_PASSTHRU; }
 void           Module::On005Numeric(std::string&) { }
 ModResult      Module::OnKill(User*, User*, const std::string&) { return MOD_RES_PASSTHRU; }
-void           Module::OnLoadModule(Module*, const std::string&) { }
-void           Module::OnUnloadModule(Module*, const std::string&) { }
+void           Module::OnLoadModule(Module*) { }
+void           Module::OnUnloadModule(Module*) { }
 void           Module::OnBackgroundTimer(time_t) { }
 ModResult      Module::OnPreCommand(std::string&, std::vector<std::string>&, User *, bool, const std::string&) { return MOD_RES_PASSTHRU; }
 void           Module::OnPostCommand(const std::string&, const std::vector<std::string>&, User *, CmdResult, const std::string&) { }
@@ -408,7 +405,7 @@ bool ModuleManager::Load(const char* filename)
        }
 
        this->ModCount++;
-       FOREACH_MOD(I_OnLoadModule,OnLoadModule(newmod, filename_str));
+       FOREACH_MOD(I_OnLoadModule,OnLoadModule(newmod));
 
        /* We give every module a chance to re-prioritize when we introduce a new one,
         * not just the one thats loading, as the new module could affect the preference
@@ -430,63 +427,117 @@ bool ModuleManager::Load(const char* filename)
        return true;
 }
 
-bool ModuleManager::Unload(const char* filename)
+bool ModuleManager::CanUnload(Module* mod)
 {
-       std::string filename_str(filename);
-       std::map<std::string, Module*>::iterator modfind = Modules.find(filename);
+       std::map<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile);
 
-       if (modfind != Modules.end())
+       if (modfind == Modules.end() || modfind->second != mod)
        {
-               if (modfind->second->GetVersion().Flags & VF_STATIC)
-               {
-                       LastModuleError = "Module " + filename_str + " not unloadable (marked static)";
-                       ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
-                       return false;
-               }
-               std::pair<int,std::string> intercount = GetInterfaceInstanceCount(modfind->second);
-               if (intercount.first > 0)
-               {
-                       LastModuleError = "Failed to unload module " + filename_str + ", being used by " + ConvToStr(intercount.first) + " other(s) via interface '" + intercount.second + "'";
-                       ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
-                       return false;
-               }
+               LastModuleError = "Module " + mod->ModuleSourceFile + " is not loaded, cannot unload it!";
+               ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
+               return false;
+       }
+       if (mod->GetVersion().Flags & VF_STATIC)
+       {
+               LastModuleError = "Module " + mod->ModuleSourceFile + " not unloadable (marked static)";
+               ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
+               return false;
+       }
+       std::pair<int,std::string> intercount = GetInterfaceInstanceCount(mod);
+       if (intercount.first > 0)
+       {
+               LastModuleError = "Failed to unload module " + mod->ModuleSourceFile + ", being used by " + ConvToStr(intercount.first) + " other(s) via interface '" + intercount.second + "'";
+               ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
+               return false;
+       }
+       return true;
+}
 
-               std::vector<ExtensionItem*> items;
-               ServerInstance->Extensions.BeginUnregister(modfind->second, items);
-               /* Give the module a chance to tidy out all its metadata */
-               for (chan_hash::iterator c = ServerInstance->chanlist->begin(); c != ServerInstance->chanlist->end(); c++)
-               {
-                       modfind->second->OnCleanup(TYPE_CHANNEL,c->second);
-                       c->second->doUnhookExtensions(items);
-                       const UserMembList* users = c->second->GetUsers();
-                       for(UserMembCIter mi = users->begin(); mi != users->end(); mi++)
-                               mi->second->doUnhookExtensions(items);
-               }
-               for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++)
-               {
-                       modfind->second->OnCleanup(TYPE_USER,u->second);
-                       u->second->doUnhookExtensions(items);
-               }
+void ModuleManager::DoSafeUnload(Module* mod)
+{
+       std::map<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile);
 
-               /* Tidy up any dangling resolvers */
-               ServerInstance->Res->CleanResolvers(modfind->second);
+       std::vector<ExtensionItem*> items;
+       ServerInstance->Extensions.BeginUnregister(modfind->second, items);
+       /* Give the module a chance to tidy out all its metadata */
+       for (chan_hash::iterator c = ServerInstance->chanlist->begin(); c != ServerInstance->chanlist->end(); c++)
+       {
+               mod->OnCleanup(TYPE_CHANNEL,c->second);
+               c->second->doUnhookExtensions(items);
+               const UserMembList* users = c->second->GetUsers();
+               for(UserMembCIter mi = users->begin(); mi != users->end(); mi++)
+                       mi->second->doUnhookExtensions(items);
+       }
+       for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++)
+       {
+               mod->OnCleanup(TYPE_USER,u->second);
+               u->second->doUnhookExtensions(items);
+       }
 
-               FOREACH_MOD(I_OnUnloadModule,OnUnloadModule(modfind->second, modfind->first));
+       /* Tidy up any dangling resolvers */
+       ServerInstance->Res->CleanResolvers(mod);
 
-               this->DetachAll(modfind->second);
+       FOREACH_MOD(I_OnUnloadModule,OnUnloadModule(mod));
 
-               ServerInstance->GlobalCulls.AddItem(modfind->second);
-               Modules.erase(modfind);
+       DetachAll(mod);
 
-               ServerInstance->Logs->Log("MODULE", DEFAULT,"Module %s unloaded",filename);
-               this->ModCount--;
-               ServerInstance->BuildISupport();
-               return true;
-       }
+       Modules.erase(modfind);
+       ServerInstance->GlobalCulls.AddItem(mod);
 
-       LastModuleError = "Module " + filename_str + " is not loaded, cannot unload it!";
-       ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
-       return false;
+       ServerInstance->Logs->Log("MODULE", DEFAULT,"Module %s unloaded",mod->ModuleSourceFile.c_str());
+       this->ModCount--;
+       ServerInstance->BuildISupport();
+}
+
+namespace {
+       struct UnloadAction : public HandlerBase0<void>
+       {
+               Module* const mod;
+               UnloadAction(Module* m) : mod(m) {}
+               void Call()
+               {
+                       DLLManager* dll = mod->ModuleDLLManager;
+                       ServerInstance->Modules->DoSafeUnload(mod);
+                       ServerInstance->GlobalCulls.Apply();
+                       delete dll;
+                       ServerInstance->GlobalCulls.AddItem(this);
+               }
+       };
+
+       struct ReloadAction : public HandlerBase0<void>
+       {
+               Module* const mod;
+               HandlerBase1<void, bool>* const callback;
+               ReloadAction(Module* m, HandlerBase1<void, bool>* c)
+                       : mod(m), callback(c) {}
+               void Call()
+               {
+                       DLLManager* dll = mod->ModuleDLLManager;
+                       std::string name = mod->ModuleSourceFile;
+                       ServerInstance->Modules->DoSafeUnload(mod);
+                       ServerInstance->GlobalCulls.Apply();
+                       delete dll;
+                       bool rv = ServerInstance->Modules->Load(name.c_str());
+                       callback->Call(rv);
+                       ServerInstance->GlobalCulls.AddItem(this);
+               }
+       };
+}
+
+bool ModuleManager::Unload(Module* mod)
+{
+       if (!CanUnload(mod))
+               return false;
+       ServerInstance->AtomicActions.AddAction(new UnloadAction(mod));
+       return true;
+}
+
+void ModuleManager::Reload(Module* mod, HandlerBase1<void, bool>* callback)
+{
+       if (CanUnload(mod))
+               ServerInstance->AtomicActions.AddAction(new ReloadAction(mod, callback));
+       else
+               callback->Call(false);
 }
 
 /* We must load the modules AFTER initializing the socket engine, now */
@@ -535,6 +586,29 @@ void ModuleManager::LoadAll()
        }
 }
 
+void ModuleManager::UnloadAll()
+{
+       /* We do this more than once, so that any service providers get a
+        * chance to be unhooked by the modules using them, but then get
+        * a chance to be removed themsleves.
+        *
+        * Note: this deliberately does NOT delete the DLLManager objects
+        */
+       for (int tries = 0; tries < 4; tries++)
+       {
+               std::map<std::string, Module*>::iterator i = Modules.begin();
+               while (i != Modules.end())
+               {
+                       std::map<std::string, Module*>::iterator me = i++;
+                       if (CanUnload(me->second))
+                       {
+                               ServerInstance->GlobalCulls.AddItem(me->second);
+                       }
+               }
+               ServerInstance->GlobalCulls.Apply();
+       }
+}
+
 bool ModuleManager::PublishFeature(const std::string &FeatureName, Module* Mod)
 {
        if (Features.find(FeatureName) == Features.end())
index df0ca7f4266bb88430a3aa9b9d894822bef4b9d9..8e37e0deae8dea3657eb1a1255596df9e5ddb38c 100644 (file)
@@ -930,7 +930,7 @@ class ModulePgSQL : public Module
                }
        }
 
-       virtual void OnUnloadModule(Module* mod, const std::string&     name)
+       virtual void OnUnloadModule(Module* mod)
        {
                /* When a module unloads we have to check all the pending queries for all our connections
                 * and set the Module* specifying where the query came from to NULL. If the query has already
index 5beb46fc44c96d34f634af155149444f4906a13a..3f95f02c994914a572f223977d7ec9cade7d0533 100644 (file)
@@ -145,7 +145,7 @@ protected:
        virtual ModResult OnStats(char symbol, User* user, string_list &results) = 0;
        virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, User *user, bool validated, const std::string &original_line);
        bool AppliesToMe(User* user, FilterResult* filter, int flags);
-       void OnLoadModule(Module* mod, const std::string& name);
+       void OnLoadModule(Module* mod);
        virtual void ReadFilters(ConfigReader &MyConf) = 0;
 };
 
@@ -456,7 +456,7 @@ void FilterBase::OnRehash(User* user)
        }
 }
 
-void FilterBase::OnLoadModule(Module* mod, const std::string& name)
+void FilterBase::OnLoadModule(Module* mod)
 {
        if (ServerInstance->Modules->ModuleHasInterface(mod, "RegularExpression"))
        {
index 636b9f4e4ab10cb404db4f61c27598de8ff39af2..50032919a0dac9bbea03d4b244d2f89e4c9b36f0 100644 (file)
@@ -22,7 +22,8 @@ class CommandGloadmodule : public Command
  public:
        CommandGloadmodule(Module* Creator) : Command(Creator,"GLOADMODULE", 1)
        {
-               flags_needed = 'o'; syntax = "<modulename> [servermask]";
+               flags_needed = 'o';
+               syntax = "<modulename> [servermask]";
                TRANSLATE3(TR_TEXT, TR_TEXT, TR_END);
        }
 
@@ -61,7 +62,8 @@ class CommandGunloadmodule : public Command
  public:
        CommandGunloadmodule(Module* Creator) : Command(Creator,"GUNLOADMODULE", 1)
        {
-               flags_needed = 'o'; syntax = "<modulename> [servermask]";
+               flags_needed = 'o';
+               syntax = "<modulename> [servermask]";
        }
 
        CmdResult Handle (const std::vector<std::string> &parameters, User *user)
@@ -70,10 +72,12 @@ class CommandGunloadmodule : public Command
 
                if (InspIRCd::Match(ServerInstance->Config->ServerName.c_str(), servername))
                {
-                       if (ServerInstance->Modules->Unload(parameters[0].c_str()))
+                       Module* m = ServerInstance->Modules->Find(parameters[0]);
+                       if (m && ServerInstance->Modules->Unload(m))
                        {
                                ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBALLY UNLOADED BY '%s'",parameters[0].c_str(), user->nick.c_str());
-                               user->WriteNumeric(973, "%s %s :Module successfully unloaded.",user->nick.c_str(), parameters[0].c_str());
+                               ServerInstance->DumpText(user, ":%s 973 %s %s :Module successfully unloaded.",
+                                       ServerInstance->Config->ServerName.c_str(), user->nick.c_str(), parameters[0].c_str());
                        }
                        else
                        {
@@ -108,20 +112,8 @@ class CommandGreloadmodule : public Command
 
                if (InspIRCd::Match(ServerInstance->Config->ServerName.c_str(), servername))
                {
-                       bool ok = true;
-                       if (!ServerInstance->Modules->Unload(parameters[0].c_str()))
-                       {
-                               ok = false;
-                               user->WriteNumeric(972, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
-                       }
-                       if (!ServerInstance->Modules->Load(parameters[0].c_str()))
-                       {
-                               ok = false;
-                               user->WriteNumeric(974, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str());
-                       }
-                       ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBALLY RELOADED BY '%s'",parameters[0].c_str(), user->nick.c_str());
-                       if (ok)
-                               user->WriteNumeric(975, "%s %s :Module successfully loaded.",user->nick.c_str(), parameters[0].c_str());
+                       Module* m = ServerInstance->Modules->Find(parameters[0]);
+                       ServerInstance->Modules->Reload(m, NULL);
                }
                else
                        ServerInstance->SNO->WriteToSnoMask('a', "MODULE '%s' GLOBAL RELOAD BY '%s' (not reloaded here)",parameters[0].c_str(), user->nick.c_str());
@@ -150,13 +142,13 @@ class ModuleGlobalLoad : public Module
                ServerInstance->AddCommand(&cmd3);
        }
 
-       virtual ~ModuleGlobalLoad()
+       ~ModuleGlobalLoad()
        {
        }
 
-       virtual Version GetVersion()
+       Version GetVersion()
        {
-               return Version("Allows global loading of a module.", VF_COMMON | VF_VENDOR, API_VERSION);
+               return Version("Allows global loading of a module.", VF_COMMON | VF_VENDOR);
        }
 };
 
index afc6cdd7946213ee468b8acbba71ceafbe20e21b..af6256a1c9bf453a0f5e74aadc295ef1047b82a9 100644 (file)
@@ -114,11 +114,10 @@ class ModuleOperHash : public Module
        }
 
 
-       virtual void OnLoadModule(Module* mod, const std::string& name)
+       virtual void OnLoadModule(Module* mod)
        {
                if (ServerInstance->Modules->ModuleHasInterface(mod, "HashRequest"))
                {
-                       ServerInstance->Logs->Log("m_password-hash",DEBUG, "Post-load registering hasher: %s", name.c_str());
                        std::string sname = HashNameRequest(this, mod).response;
                        hashers[sname.c_str()] = mod;
                        names.push_back(sname);
index a1a57199a328fc87a3792c6e133623f2cfbe8c41..df5fca50490d43897049421a82f1513a49dc0f7f 100644 (file)
@@ -290,7 +290,7 @@ class ModuleRLine : public Module
                return MOD_RES_DENY;
        }
 
-       virtual void OnLoadModule(Module* mod, const std::string& name)
+       virtual void OnLoadModule(Module* mod)
        {
                if (ServerInstance->Modules->ModuleHasInterface(mod, "RegularExpression"))
                {
index 9c0997d7cc31f9993069d298246fabfbba8d998c..afd40e0c9dda48fee653bc0c0ae055239ff0d8fe 100644 (file)
@@ -772,17 +772,17 @@ void ModuleSpanningTree::OnRehash(User* user)
        Utils->ReadConfiguration(true);
 }
 
-void ModuleSpanningTree::OnLoadModule(Module* mod, const std::string &name)
+void ModuleSpanningTree::OnLoadModule(Module* mod)
 {
-       this->RedoConfig(mod, name);
+       this->RedoConfig(mod);
 }
 
-void ModuleSpanningTree::OnUnloadModule(Module* mod, const std::string &name)
+void ModuleSpanningTree::OnUnloadModule(Module* mod)
 {
-       this->RedoConfig(mod, name);
+       this->RedoConfig(mod);
 }
 
-void ModuleSpanningTree::RedoConfig(Module* mod, const std::string &name)
+void ModuleSpanningTree::RedoConfig(Module* mod)
 {
        /* If m_sha256.so is loaded (we use this for HMAC) or any module implementing a BufferedSocket interface is loaded,
         * then we need to re-read our config again taking this into account.
@@ -794,7 +794,7 @@ void ModuleSpanningTree::RedoConfig(Module* mod, const std::string &name)
        if (ml && std::find(ml->begin(), ml->end(), mod) != ml->end())
                IsBufferSocketModule = true;
 
-       if (name == "m_sha256.so" || IsBufferSocketModule)
+       if (mod->ModuleSourceFile == "m_sha256.so" || IsBufferSocketModule)
        {
                Utils->ReadConfiguration(true);
        }
index 66b396171160e8c793ec9576a92791e05a4f1ac0..be9c460d9166fc9ba7c48c7eac6ef12ee636546c 100644 (file)
@@ -49,7 +49,7 @@ class ModuleSpanningTree : public Module
        CommandRSQuit* command_rsquit;
        SpanningTreeUtilities* Utils;
 
-       void RedoConfig(Module* mod, const std::string &name);
+       void RedoConfig(Module* mod);
 
  public:
        CacheRefreshTimer *RefreshTimer;
@@ -188,8 +188,8 @@ class ModuleSpanningTree : public Module
        ModResult OnSetAway(User* user, const std::string &awaymsg);
        void ProtoSendMode(void* opaque, TargetTypeFlags target_type, void* target, const std::vector<std::string> &modeline, const std::vector<TranslateType> &translate);
        void ProtoSendMetaData(void* opaque, Extensible* target, const std::string &extname, const std::string &extdata);
-       void OnLoadModule(Module* mod,const std::string &name);
-       void OnUnloadModule(Module* mod,const std::string &name);
+       void OnLoadModule(Module* mod);
+       void OnUnloadModule(Module* mod);
        bool cull();
        ~ModuleSpanningTree();
        Version GetVersion();
index f1174b0ce778bc402f6ca9ad6d8a5055f15d93a5..9b019f931fbf1a2c6872b46174e3430922a08ce3 100644 (file)
@@ -258,9 +258,9 @@ class ModuleSQLLog : public Module
                AddLogEntry(LT_DISCONNECT,user->nick,user->host,user->server);
        }
 
-       virtual void OnLoadModule(Module* mod, const std::string &name)
+       virtual void OnLoadModule(Module* mod)
        {
-               AddLogEntry(LT_LOADMODULE,name,ServerInstance->Config->ServerName.c_str(), ServerInstance->Config->ServerName.c_str());
+               AddLogEntry(LT_LOADMODULE,mod->ModuleSourceFile,ServerInstance->Config->ServerName.c_str(), ServerInstance->Config->ServerName.c_str());
        }
 
        virtual Version GetVersion()
index cf5bb3da53dff2d8ea68bfb11fe8b53e56d36185..c4eaa6911000cc14187b490b2e2d3caa6a514e32 100644 (file)
@@ -87,11 +87,10 @@ public:
                return false;
        }
 
-       virtual void OnLoadModule(Module* mod, const std::string& name)
+       virtual void OnLoadModule(Module* mod)
        {
                if (ServerInstance->Modules->ModuleHasInterface(mod, "HashRequest"))
                {
-                       ServerInstance->Logs->Log("m_sqloper",DEBUG, "Post-load registering hasher: %s", name.c_str());
                        std::string sname = HashNameRequest(this, mod).response;
                        hashers[sname.c_str()] = mod;
                        names.push_back(sname);
@@ -303,7 +302,7 @@ public:
 
        Version GetVersion()
        {
-               return Version("Allows storage of oper credentials in an SQL table", VF_VENDOR, API_VERSION);
+               return Version("Allows storage of oper credentials in an SQL table", VF_VENDOR);
        }
 
 };
index bc68cb5f108c360ee95eb025bddcf076547e6d67..48ba4845cbbca4eb317ffeee8c92633c63eb72bb 100644 (file)
@@ -79,7 +79,11 @@ TestSuite::TestSuite()
                        case '3':
                                cout << "Enter module filename to unload: ";
                                cin >> modname;
-                               cout << (ServerInstance->Modules->Unload(modname.c_str()) ? "\nSUCCESS!\n" : "\nFAILURE\n");
+                               {
+                                       Module* m = ServerInstance->Modules->Find(modname);
+                                       cout << (ServerInstance->Modules->Unload(m) ? "\nSUCCESS!\n" : "\nFAILURE\n");
+                                       ServerInstance->AtomicActions.Run();
+                               }
                                break;
                        case '4':
                                cout << (DoThreadTests() ? "\nSUCCESS!\n" : "\nFAILURE\n");