summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/base.h4
-rw-r--r--include/caller.h24
-rw-r--r--include/cull_list.h15
-rw-r--r--include/inspircd.h5
-rw-r--r--include/modules.h27
-rw-r--r--src/commands/cmd_reloadmodule.cpp39
-rw-r--r--src/commands/cmd_unloadmodule.cpp6
-rw-r--r--src/configreader.cpp3
-rw-r--r--src/cull_list.cpp8
-rw-r--r--src/dynamic.cpp2
-rw-r--r--src/inspircd.cpp21
-rw-r--r--src/modules.cpp180
-rw-r--r--src/modules/extra/m_pgsql.cpp2
-rw-r--r--src/modules/m_filter.cpp4
-rw-r--r--src/modules/m_globalload.cpp34
-rw-r--r--src/modules/m_password_hash.cpp3
-rw-r--r--src/modules/m_rline.cpp2
-rw-r--r--src/modules/m_spanningtree/main.cpp12
-rw-r--r--src/modules/m_spanningtree/main.h6
-rw-r--r--src/modules/m_sqllog.cpp4
-rw-r--r--src/modules/m_sqloper.cpp5
-rw-r--r--src/testsuite.cpp6
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> &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"))
{
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> &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);
}
};
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");