diff options
-rw-r--r-- | include/base.h | 4 | ||||
-rw-r--r-- | include/caller.h | 24 | ||||
-rw-r--r-- | include/cull_list.h | 15 | ||||
-rw-r--r-- | include/inspircd.h | 5 | ||||
-rw-r--r-- | include/modules.h | 27 | ||||
-rw-r--r-- | src/commands/cmd_reloadmodule.cpp | 39 | ||||
-rw-r--r-- | src/commands/cmd_unloadmodule.cpp | 6 | ||||
-rw-r--r-- | src/configreader.cpp | 3 | ||||
-rw-r--r-- | src/cull_list.cpp | 8 | ||||
-rw-r--r-- | src/dynamic.cpp | 2 | ||||
-rw-r--r-- | src/inspircd.cpp | 21 | ||||
-rw-r--r-- | src/modules.cpp | 180 | ||||
-rw-r--r-- | src/modules/extra/m_pgsql.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_filter.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_globalload.cpp | 34 | ||||
-rw-r--r-- | src/modules/m_password_hash.cpp | 3 | ||||
-rw-r--r-- | src/modules/m_rline.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_spanningtree/main.cpp | 12 | ||||
-rw-r--r-- | src/modules/m_spanningtree/main.h | 6 | ||||
-rw-r--r-- | src/modules/m_sqllog.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_sqloper.cpp | 5 | ||||
-rw-r--r-- | src/testsuite.cpp | 6 |
22 files changed, 258 insertions, 154 deletions
diff --git a/include/base.h b/include/base.h index 0464f68e2..ed03eeac5 100644 --- a/include/base.h +++ b/include/base.h @@ -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> diff --git a/include/caller.h b/include/caller.h index 666035752..420f17afb 100644 --- a/include/caller.h +++ b/include/caller.h @@ -47,63 +47,63 @@ * 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> > diff --git a/include/cull_list.h b/include/cull_list.h index 2b3ed1391..33e9a7ea6 100644 --- a/include/cull_list.h +++ b/include/cull_list.h @@ -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 diff --git a/include/inspircd.h b/include/inspircd.h index df80ba4bf..4fb28e2d7 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -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 ****/ diff --git a/include/modules.h b/include/modules.h index 9207a2bd9..151c3fef8 100644 --- a/include/modules.h +++ b/include/modules.h @@ -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 diff --git a/src/commands/cmd_reloadmodule.cpp b/src/commands/cmd_reloadmodule.cpp index 37693b501..ca972fd18 100644 --- a/src/commands/cmd_reloadmodule.cpp +++ b/src/commands/cmd_reloadmodule.cpp @@ -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) diff --git a/src/commands/cmd_unloadmodule.cpp b/src/commands/cmd_unloadmodule.cpp index 5aecd22dd..c3ae49d1c 100644 --- a/src/commands/cmd_unloadmodule.cpp +++ b/src/commands/cmd_unloadmodule.cpp @@ -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; } diff --git a/src/configreader.cpp b/src/configreader.cpp index 70c99e8ae..4877cab5a 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -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()); diff --git a/src/cull_list.cpp b/src/cull_list.cpp index f87095126..6033ec695 100644 --- a/src/cull_list.cpp +++ b/src/cull_list.cpp @@ -48,3 +48,11 @@ void CullList::Apply() } } +void ActionList::Run() +{ + for(unsigned int i=0; i < list.size(); i++) + { + list[i]->Call(); + } + list.clear(); +} diff --git a/src/dynamic.cpp b/src/dynamic.cpp index 637a57db4..70d5e7cae 100644 --- a/src/dynamic.cpp +++ b/src/dynamic.cpp @@ -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(); diff --git a/src/inspircd.cpp b/src/inspircd.cpp index a1273d651..c59109724 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -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) { diff --git a/src/modules.cpp b/src/modules.cpp index 8c0fccba6..f1e53deba 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -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()) diff --git a/src/modules/extra/m_pgsql.cpp b/src/modules/extra/m_pgsql.cpp index df0ca7f42..8e37e0dea 100644 --- a/src/modules/extra/m_pgsql.cpp +++ b/src/modules/extra/m_pgsql.cpp @@ -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 diff --git a/src/modules/m_filter.cpp b/src/modules/m_filter.cpp index 5beb46fc4..3f95f02c9 100644 --- a/src/modules/m_filter.cpp +++ b/src/modules/m_filter.cpp @@ -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> ¶meters, 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")) { diff --git a/src/modules/m_globalload.cpp b/src/modules/m_globalload.cpp index 636b9f4e4..50032919a 100644 --- a/src/modules/m_globalload.cpp +++ b/src/modules/m_globalload.cpp @@ -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> ¶meters, 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); } }; diff --git a/src/modules/m_password_hash.cpp b/src/modules/m_password_hash.cpp index afc6cdd79..af6256a1c 100644 --- a/src/modules/m_password_hash.cpp +++ b/src/modules/m_password_hash.cpp @@ -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); diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp index a1a57199a..df5fca504 100644 --- a/src/modules/m_rline.cpp +++ b/src/modules/m_rline.cpp @@ -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")) { diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 9c0997d7c..afd40e0c9 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -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); } diff --git a/src/modules/m_spanningtree/main.h b/src/modules/m_spanningtree/main.h index 66b396171..be9c460d9 100644 --- a/src/modules/m_spanningtree/main.h +++ b/src/modules/m_spanningtree/main.h @@ -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(); diff --git a/src/modules/m_sqllog.cpp b/src/modules/m_sqllog.cpp index f1174b0ce..9b019f931 100644 --- a/src/modules/m_sqllog.cpp +++ b/src/modules/m_sqllog.cpp @@ -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() diff --git a/src/modules/m_sqloper.cpp b/src/modules/m_sqloper.cpp index cf5bb3da5..c4eaa6911 100644 --- a/src/modules/m_sqloper.cpp +++ b/src/modules/m_sqloper.cpp @@ -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); } }; diff --git a/src/testsuite.cpp b/src/testsuite.cpp index bc68cb5f1..48ba4845c 100644 --- a/src/testsuite.cpp +++ b/src/testsuite.cpp @@ -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"); |