summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/inspircd.h25
-rw-r--r--include/modules.h2
-rw-r--r--src/inspircd.cpp11
-rw-r--r--src/modules.cpp42
-rw-r--r--src/modules/m_cloaking.cpp5
-rw-r--r--src/modules/m_oper_hash.cpp3
-rw-r--r--src/modules/m_spanningtree.cpp4
7 files changed, 84 insertions, 8 deletions
diff --git a/include/inspircd.h b/include/inspircd.h
index 74678b206..8cce5513a 100644
--- a/include/inspircd.h
+++ b/include/inspircd.h
@@ -727,6 +727,31 @@ class InspIRCd : public classbase
*/
bool PublishInterface(const std::string &InterfaceName, Module* Mod);
+ /** Return a pair saying how many other modules are currently using the
+ * interfaces provided by module m.
+ * @param m The module to count usage for
+ * @return A pair, where the first value is the number of uses of the interface,
+ * and the second value is the interface name being used.
+ */
+ std::pair<int,std::string> GetInterfaceInstanceCount(Module* m);
+
+ /** Mark your module as using an interface.
+ * If you mark your module as using an interface, then that interface
+ * module may not unload until your module has unloaded first.
+ * This can be used to prevent crashes by ensuring code you depend on
+ * is always in memory while your module is active.
+ * @param InterfaceName The interface to use
+ */
+ void UseInterface(const std::string &InterfaceName);
+
+ /** Mark your module as finished with an interface.
+ * If you used UseInterface() above, you should use this method when
+ * your module is finished with the interface (usually in its destructor)
+ * to allow the modules which implement the given interface to be unloaded.
+ * @param InterfaceName The interface you are finished with using.
+ */
+ void DoneWithInterface(const std::string &InterfaceName);
+
/** Unpublish a 'feature'.
* When your module exits, it must call this method for every feature it
* is providing so that the feature table is cleaned up.
diff --git a/include/modules.h b/include/modules.h
index 9ace806b7..df8c03e3b 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -107,7 +107,7 @@ typedef std::deque<Module*> modulelist;
/** Holds a list of all modules which implement interfaces, by interface name
*/
-typedef std::map<std::string, modulelist> interfacelist;
+typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
/**
* This #define allows us to call a method in all
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index 12134f3f6..e7801f1d5 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -505,6 +505,17 @@ bool InspIRCd::UnloadModule(const char* filename)
snprintf(MODERR,MAXBUF,"Module not unloadable (marked static)");
return false;
}
+ std::pair<int,std::string> intercount = GetInterfaceInstanceCount(modules[j]);
+ if (intercount.first > 0)
+ {
+ this->Log(DEFAULT,"Failed to unload module %s, being used by %d other(s) via interface '%s'",filename, intercount.first, intercount.second.c_str());
+ snprintf(MODERR,MAXBUF,"Module not unloadable (Still in use by %d other module%s which %s using its interface '%s') -- unload dependent modules first!",
+ intercount.first,
+ intercount.first > 1 ? "s" : "",
+ intercount.first > 1 ? "are" : "is",
+ intercount.second.c_str());
+ return false;
+ }
/* Give the module a chance to tidy out all its metadata */
for (chan_hash::iterator c = this->chanlist.begin(); c != this->chanlist.end(); c++)
{
diff --git a/src/modules.cpp b/src/modules.cpp
index 4ae033c8b..b670291ec 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -258,12 +258,12 @@ bool InspIRCd::PublishInterface(const std::string &InterfaceName, Module* Mod)
{
modulelist ml;
ml.push_back(Mod);
- Interfaces[InterfaceName] = ml;
+ Interfaces[InterfaceName] = std::make_pair(0, ml);
return true;
}
else
{
- iter->second.push_back(Mod);
+ iter->second.second.push_back(Mod);
return true;
}
return false;
@@ -276,12 +276,12 @@ bool InspIRCd::UnpublishInterface(const std::string &InterfaceName, Module* Mod)
if (iter == Interfaces.end())
return false;
- for (modulelist::iterator x = iter->second.begin(); x != iter->second.end(); x++)
+ for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
{
if (*x == Mod)
{
- iter->second.erase(x);
- if (iter->second.empty())
+ iter->second.second.erase(x);
+ if (iter->second.second.empty())
Interfaces.erase(InterfaceName);
return true;
}
@@ -295,7 +295,37 @@ modulelist* InspIRCd::FindInterface(const std::string &InterfaceName)
if (iter == Interfaces.end())
return NULL;
else
- return &(iter->second);
+ return &(iter->second.second);
+}
+
+void InspIRCd::UseInterface(const std::string &InterfaceName)
+{
+ interfacelist::iterator iter = Interfaces.find(InterfaceName);
+ if (iter != Interfaces.end())
+ iter->second.first++;
+
+}
+
+void InspIRCd::DoneWithInterface(const std::string &InterfaceName)
+{
+ interfacelist::iterator iter = Interfaces.find(InterfaceName);
+ if (iter != Interfaces.end())
+ iter->second.first--;
+}
+
+std::pair<int,std::string> InspIRCd::GetInterfaceInstanceCount(Module* m)
+{
+ for (interfacelist::iterator iter = Interfaces.begin(); iter != Interfaces.end(); iter++)
+ {
+ for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
+ {
+ if (*x == m)
+ {
+ return std::make_pair(iter->second.first, iter->first);
+ }
+ }
+ }
+ return std::make_pair(0, "");
}
const std::string& InspIRCd::GetModuleName(Module* m)
diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp
index ffa189007..a32f7348d 100644
--- a/src/modules/m_cloaking.cpp
+++ b/src/modules/m_cloaking.cpp
@@ -230,7 +230,9 @@ class ModuleCloaking : public Module
ModuleCloaking(InspIRCd* Me)
: Module::Module(Me)
{
- /* Attempt to locate the Hash service provider, bail if we can't find it */
+ ServerInstance->UseInterface("HashRequest");
+
+ /* Attempt to locate the md5 service provider, bail if we can't find it */
HashModule = ServerInstance->FindModule("m_md5.so");
if (!HashModule)
throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");
@@ -248,6 +250,7 @@ class ModuleCloaking : public Module
{
ServerInstance->Modes->DelMode(cu);
DELETE(cu);
+ ServerInstance->DoneWithInterface("HashRequest");
}
virtual Version GetVersion()
diff --git a/src/modules/m_oper_hash.cpp b/src/modules/m_oper_hash.cpp
index b9e246c2b..61a43b1e1 100644
--- a/src/modules/m_oper_hash.cpp
+++ b/src/modules/m_oper_hash.cpp
@@ -91,6 +91,8 @@ class ModuleOperHash : public Module
Conf = NULL;
OnRehash("");
+ ServerInstance->UseInterface("HashRequest");
+
/* Find all modules which implement the interface 'HashRequest' */
modulelist* ml = ServerInstance->FindInterface("HashRequest");
@@ -121,6 +123,7 @@ class ModuleOperHash : public Module
virtual ~ModuleOperHash()
{
+ ServerInstance->DoneWithInterface("HashRequest");
}
void Implements(char* List)
diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp
index c0d2d7428..ef7e17820 100644
--- a/src/modules/m_spanningtree.cpp
+++ b/src/modules/m_spanningtree.cpp
@@ -4188,6 +4188,8 @@ class ModuleSpanningTree : public Module
ModuleSpanningTree(InspIRCd* Me)
: Module::Module(Me), max_local(0), max_global(0)
{
+ ServerInstance->UseInterface("InspSocketHook");
+
Utils = new SpanningTreeUtilities(Me, this);
command_rconnect = new cmd_rconnect(ServerInstance, this, Utils);
@@ -5402,6 +5404,8 @@ class ModuleSpanningTree : public Module
delete Utils;
if (SyncTimer)
ServerInstance->Timers->DelTimer(SyncTimer);
+
+ ServerInstance->DoneWithInterface("InspSocketHook");
}
virtual Version GetVersion()