diff options
author | Adam <Adam@anope.org> | 2014-05-08 18:00:31 -0400 |
---|---|---|
committer | Attila Molnar <attilamolnar@hush.com> | 2014-05-10 12:09:01 +0200 |
commit | caec2724849c7f92126168b8724157836e6cffe7 (patch) | |
tree | 32a4e5c228daf5b79f8d4eb9c55a271b0f400dc9 | |
parent | 3e3ede8c30981da03fc46bd81c8e948bc3a761f0 (diff) |
m_ldap: time out LDAP queries
Set LDAP_OPT_NETWORK_TIMEOUT to 0 in m_ldap to prevent the asynchronous
library calls from blocking
Fix memory leak of pending queries when m_ldap is unloaded
-rw-r--r-- | src/modules/extra/m_ldap.cpp | 80 |
1 files changed, 68 insertions, 12 deletions
diff --git a/src/modules/extra/m_ldap.cpp b/src/modules/extra/m_ldap.cpp index 63c29ed3a..d480a88f6 100644 --- a/src/modules/extra/m_ldap.cpp +++ b/src/modules/extra/m_ldap.cpp @@ -1,8 +1,8 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2013 Adam <Adam@anope.org> - * Copyright (C) 2003-2013 Anope Team <team@anope.org> + * Copyright (C) 2013-2014 Adam <Adam@anope.org> + * Copyright (C) 2003-2014 Anope Team <team@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -35,6 +35,8 @@ class LDAPService : public LDAPProvider, public SocketThread reference<ConfigTag> config; time_t last_connect; int searchscope; + time_t timeout; + time_t last_timeout_check; LDAPMod** BuildMods(const LDAPMods& attributes) { @@ -100,20 +102,47 @@ class LDAPService : public LDAPProvider, public SocketThread if (i != NULL) { this->LockQueue(); - this->queries[msgid] = i; + this->queries[msgid] = std::make_pair(ServerInstance->Time(), i); this->UnlockQueueWakeup(); } } + void Timeout() + { + if (last_timeout_check == ServerInstance->Time()) + return; + last_timeout_check = ServerInstance->Time(); + + for (query_queue::iterator it = this->queries.begin(); it != this->queries.end(); ) + { + LDAPQuery msgid = it->first; + time_t created = it->second.first; + LDAPInterface* i = it->second.second; + ++it; + + if (ServerInstance->Time() > created + timeout) + { + LDAPResult* ldap_result = new LDAPResult(); + ldap_result->id = msgid; + ldap_result->error = "Query timed out"; + + this->queries.erase(msgid); + this->results.push_back(std::make_pair(i, ldap_result)); + + this->NotifyParent(); + } + } + } + public: - typedef std::map<int, LDAPInterface*> query_queue; + typedef std::map<LDAPQuery, std::pair<time_t, LDAPInterface*> > query_queue; typedef std::vector<std::pair<LDAPInterface*, LDAPResult*> > result_queue; query_queue queries; result_queue results; LDAPService(Module* c, ConfigTag* tag) : LDAPProvider(c, "LDAP/" + tag->getString("id")) - , con(NULL), config(tag), last_connect(0) + , con(NULL), config(tag), last_connect(0), last_timeout_check(0) { std::string scope = config->getString("searchscope"); if (scope == "base") @@ -122,6 +151,7 @@ class LDAPService : public LDAPProvider, public SocketThread searchscope = LDAP_SCOPE_ONELEVEL; else searchscope = LDAP_SCOPE_SUBTREE; + timeout = config->getInt("timeout", 5); Connect(); } @@ -131,13 +161,29 @@ class LDAPService : public LDAPProvider, public SocketThread this->LockQueue(); for (query_queue::iterator i = this->queries.begin(); i != this->queries.end(); ++i) - ldap_abandon_ext(this->con, i->first, NULL, NULL); + { + LDAPQuery msgid = i->first; + LDAPInterface* inter = i->second.second; + + ldap_abandon_ext(this->con, msgid, NULL, NULL); + + if (inter) + { + LDAPResult r; + r.error = "LDAP Interface is going away"; + inter->OnError(r); + } + } this->queries.clear(); for (result_queue::iterator i = this->results.begin(); i != this->results.end(); ++i) { - i->second->error = "LDAP Interface is going away"; - i->first->OnError(*i->second); + LDAPInterface* inter = i->first; + LDAPResult* r = i->second; + + r->error = "LDAP Interface is going away"; + if (inter) + inter->OnError(*r); } this->results.clear(); @@ -152,6 +198,7 @@ class LDAPService : public LDAPProvider, public SocketThread int i = ldap_initialize(&this->con, server.c_str()); if (i != LDAP_SUCCESS) throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i)); + const int version = LDAP_VERSION3; i = ldap_set_option(this->con, LDAP_OPT_PROTOCOL_VERSION, &version); if (i != LDAP_OPT_SUCCESS) @@ -160,6 +207,15 @@ class LDAPService : public LDAPProvider, public SocketThread this->con = NULL; throw LDAPException("Unable to set protocol version for " + this->name + ": " + ldap_err2string(i)); } + + const struct timeval tv = { 0, 0 }; + i = ldap_set_option(this->con, LDAP_OPT_NETWORK_TIMEOUT, &tv); + if (i != LDAP_OPT_SUCCESS) + { + ldap_unbind_ext(this->con, NULL, NULL); + this->con = NULL; + throw LDAPException("Unable to set timeout for " + this->name + ": " + ldap_err2string(i)); + } } LDAPQuery BindAsManager(LDAPInterface* i) CXX11_OVERRIDE @@ -315,8 +371,8 @@ class LDAPService : public LDAPProvider, public SocketThread this->UnlockQueue(); continue; } - else - this->UnlockQueue(); + this->Timeout(); + this->UnlockQueue(); struct timeval tv = { 1, 0 }; LDAPMessage* result; @@ -335,7 +391,7 @@ class LDAPService : public LDAPProvider, public SocketThread ldap_msgfree(result); continue; } - LDAPInterface* i = it->second; + LDAPInterface* i = it->second.second; this->queries.erase(it); this->UnlockQueue(); @@ -531,7 +587,7 @@ class ModuleLDAP : public Module for (LDAPService::query_queue::iterator it2 = s->queries.begin(); it2 != s->queries.end();) { int msgid = it2->first; - LDAPInterface* i = it2->second; + LDAPInterface* i = it2->second.second; ++it2; if (i->creator == m) |