diff options
| author | Remko Tronçon <git@el-tramo.be> | 2011-10-08 07:40:01 (GMT) |
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2011-10-08 07:40:01 (GMT) |
| commit | 2c6f1075474f6b8086cc6abf7978aee9421761c8 (patch) | |
| tree | 33dede68126fa3f9355406de7067d63499bd7775 | |
| parent | 3fafb8bb9387d859bc187c23db6efac90c8683d4 (diff) | |
| download | swift-contrib-2c6f1075474f6b8086cc6abf7978aee9421761c8.zip swift-contrib-2c6f1075474f6b8086cc6abf7978aee9421761c8.tar.bz2 | |
Protect JID cache access with mutex.
The overhead appears to be neglectible.
Using TSS had a similar overhead, with the disadvantages that it uses
more storage (one cache per thread vs one cache), has less cache reuse,
and that Windows/MSVC doesn't support automatic TSS cleanup, so it
requires manual cleanup work (which is non-trivial).
Note that the mutex approach may yield more overhead in multi-threaded
applications (in case of contention). Currently, the mutex also locks
during the whole nameprep sequence, which is not strictly necessary.
| -rw-r--r-- | Swiften/JID/JID.cpp | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp index 66d6ff6..9b47ef7 100644 --- a/Swiften/JID/JID.cpp +++ b/Swiften/JID/JID.cpp @@ -1,66 +1,68 @@ /* * Copyright (c) 2010 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #define SWIFTEN_CACHE_JID_PREP #include <vector> #include <list> #include <iostream> #include <string> #ifdef SWIFTEN_CACHE_JID_PREP +#include <boost/thread/mutex.hpp> #include <boost/unordered_map.hpp> #endif #include <boost/assign/list_of.hpp> #include <boost/algorithm/string/find_format.hpp> #include <boost/algorithm/string/finder.hpp> #include <sstream> #include <stringprep.h> #include <Swiften/Base/String.h> #include <Swiften/JID/JID.h> #include <Swiften/IDN/StringPrep.h> using namespace Swift; #ifdef SWIFTEN_CACHE_JID_PREP typedef boost::unordered_map<std::string, std::string> PrepCache; +static boost::mutex namePrepCacheMutex; static PrepCache nodePrepCache; static PrepCache domainPrepCache; static PrepCache resourcePrepCache; #endif static const std::list<char> escapedChars = boost::assign::list_of(' ')('"')('&')('\'')('/')('<')('>')('@')(':'); static std::string getEscaped(char c) { return makeString() << '\\' << std::hex << static_cast<int>(c); } static bool getEscapeSequenceValue(const std::string& sequence, unsigned char& value) { std::stringstream s; unsigned int v; s << std::hex << sequence; s >> v; value = static_cast<unsigned char>(v); return (!s.fail() && !s.bad() && (value == 0x5C || std::find(escapedChars.begin(), escapedChars.end(), value) != escapedChars.end())); } // Disabling this code for now, since GCC4.5+boost1.42 (on ubuntu) seems to // result in a bug. Replacing it with naive code. #if 0 struct UnescapedCharacterFinder { template<typename Iterator> boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) { for (; begin != end; ++begin) { if (std::find(escapedChars.begin(), escapedChars.end(), *begin) != escapedChars.end()) { return boost::iterator_range<Iterator>(begin, begin + 1); } else if (*begin == '\\') { // Check if we have an escaped dissalowed character sequence Iterator innerBegin = begin + 1; if (innerBegin != end && innerBegin + 1 != end) { Iterator innerEnd = innerBegin + 2; unsigned char value; @@ -122,76 +124,82 @@ JID::JID(const std::string& node, const std::string& domain) : valid_(true), has nameprepAndSetComponents(node, domain, ""); } JID::JID(const std::string& node, const std::string& domain, const std::string& resource) : valid_(true), hasResource_(true) { nameprepAndSetComponents(node, domain, resource); } void JID::initializeFromString(const std::string& jid) { if (String::beginsWith(jid, '@')) { valid_ = false; return; } std::string bare, resource; size_t slashIndex = jid.find('/'); if (slashIndex != jid.npos) { hasResource_ = true; bare = jid.substr(0, slashIndex); resource = jid.substr(slashIndex + 1, jid.npos); } else { hasResource_ = false; bare = jid; } std::pair<std::string,std::string> nodeAndDomain = String::getSplittedAtFirst(bare, '@'); if (nodeAndDomain.second.empty()) { nameprepAndSetComponents("", nodeAndDomain.first, resource); } else { nameprepAndSetComponents(nodeAndDomain.first, nodeAndDomain.second, resource); } } void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) { + if (domain.empty()) { + valid_ = false; + return; + } try { #ifndef SWIFTEN_CACHE_JID_PREP node_ = StringPrep::getPrepared(node, StringPrep::NamePrep); domain_ = StringPrep::getPrepared(domain, StringPrep::XMPPNodePrep); resource_ = StringPrep::getPrepared(resource, StringPrep::XMPPResourcePrep); #else + boost::mutex::scoped_lock lock(namePrepCacheMutex); + std::pair<PrepCache::iterator, bool> r; r = nodePrepCache.insert(std::make_pair(node, std::string())); if (r.second) { r.first->second = StringPrep::getPrepared(node, StringPrep::NamePrep); } node_ = r.first->second; r = domainPrepCache.insert(std::make_pair(domain, std::string())); if (r.second) { r.first->second = StringPrep::getPrepared(domain, StringPrep::XMPPNodePrep); } domain_ = r.first->second; r = resourcePrepCache.insert(std::make_pair(resource, std::string())); if (r.second) { r.first->second = StringPrep::getPrepared(resource, StringPrep::XMPPResourcePrep); } resource_ = r.first->second; #endif if (domain_.empty()) { valid_ = false; return; } } catch (const std::exception&) { valid_ = false; } } std::string JID::toString() const { std::string string; if (!node_.empty()) { string += node_ + "@"; |
Swift