summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2011-10-08 07:40:01 (GMT)
committerRemko Tronçon <git@el-tramo.be>2011-10-08 07:40:01 (GMT)
commit2c6f1075474f6b8086cc6abf7978aee9421761c8 (patch)
tree33dede68126fa3f9355406de7067d63499bd7775 /Swiften/JID/JID.cpp
parent3fafb8bb9387d859bc187c23db6efac90c8683d4 (diff)
downloadswift-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.
Diffstat (limited to 'Swiften/JID/JID.cpp')
-rw-r--r--Swiften/JID/JID.cpp8
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_ + "@";