diff options
-rw-r--r-- | include/inspircd.h | 25 | ||||
-rw-r--r-- | include/modules.h | 2 | ||||
-rw-r--r-- | src/inspircd.cpp | 11 | ||||
-rw-r--r-- | src/modules.cpp | 42 | ||||
-rw-r--r-- | src/modules/m_cloaking.cpp | 5 | ||||
-rw-r--r-- | src/modules/m_oper_hash.cpp | 3 | ||||
-rw-r--r-- | src/modules/m_spanningtree.cpp | 4 |
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() |