From b9e25fa4e43a7ac403b12d72b3e4ae0d495cf3cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com> Date: Tue, 1 Nov 2016 17:45:40 -0400 Subject: [PATCH] namedirectory: add cache, parse URI for nameserver * Use .cache/ring/namecache to cache found sameservice mappings * Parse URIs, use hostname as the nameserver (if any) or the default Change-Id: Id7b16369359fa798d91c89a82917509d5990eae1 --- src/client/configurationmanager.cpp | 8 ++- src/ringdht/namedirectory.cpp | 87 +++++++++++++++++++++++++++-- src/ringdht/namedirectory.h | 16 ++++-- src/ringdht/ringaccount.cpp | 22 +++++--- src/ringdht/ringaccount.h | 1 + 5 files changed, 113 insertions(+), 21 deletions(-) diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp index 97132fec0a..eb7b0e04d7 100644 --- a/src/client/configurationmanager.cpp +++ b/src/client/configurationmanager.cpp @@ -838,9 +838,13 @@ bool lookupName(const std::string& account, const std::string& nameserver, const { #if HAVE_RINGNS if (account.empty()) { - ring::NameDirectory::instance(nameserver).lookupName(name, [name](const std::string& result, ring::NameDirectory::Response response) { + auto cb = [name](const std::string& result, ring::NameDirectory::Response response) { ring::emitSignal<DRing::ConfigurationSignal::RegisteredNameFound>("", (int)response, result, name); - }); + }; + if (nameserver.empty()) + ring::NameDirectory::lookupUri(name, "", cb); + else + ring::NameDirectory::instance(nameserver).lookupName(name, cb); return true; } else if (auto acc = ring::Manager::instance().getAccount<RingAccount>(account)) { acc->lookupName(name); diff --git a/src/ringdht/namedirectory.cpp b/src/ringdht/namedirectory.cpp index 3a65863db4..55afa13647 100644 --- a/src/ringdht/namedirectory.cpp +++ b/src/ringdht/namedirectory.cpp @@ -20,7 +20,9 @@ #include "logger.h" #include "string_utils.h" #include "thread_pool.h" +#include "fileutils.h" +#include <msgpack.hpp> #include <json/json.h> #include <restbed> @@ -28,13 +30,16 @@ #include <ciso646> #include <sstream> #include <regex> +#include <fstream> namespace ring { constexpr const char* const QUERY_NAME {"/name/"}; constexpr const char* const QUERY_ADDR {"/addr/"}; + +/** Parser for Ring URIs. ( protocol ) ( username ) ( hostname ) */ +const std::regex URI_VALIDATOR {"^([a-zA-Z]+:(?://)?)?(?:([a-z0-9-_]{1,64})@)?([a-zA-Z0-9\\-._~%!$&'()*+,;=:\\[\\]]+)"}; const std::regex NAME_VALIDATOR {"^[a-z0-9-_]{3,32}$"}; -const std::regex URI_VALIDATOR {"^(:?[a-zA-Z]+://)?([a-zA-Z0-9\\-._~%!$&'()*+,;=:\\[\\]]+)"}; constexpr size_t MAX_RESPONSE_SIZE {1024 * 1024}; @@ -42,20 +47,50 @@ std::string hostFromUri(const std::string& uri) { std::smatch pieces_match; if (std::regex_search(uri, pieces_match, URI_VALIDATOR)) - if (pieces_match.size() == 3) - return pieces_match[2].str(); + if (pieces_match.size() == 4) + return pieces_match[3].str(); return uri; } -NameDirectory::NameDirectory(const std::string& s) : serverUri_(s), serverHost_(hostFromUri(s)) +void +NameDirectory::lookupUri(const std::string& uri, const std::string& default_server, LookupCallback cb) +{ + RING_WARN("lookupUri: %s", uri.c_str()); + std::smatch pieces_match; + if (std::regex_search(uri, pieces_match, URI_VALIDATOR)) { + if (pieces_match.size() == 4) { + if (pieces_match[2].length() == 0) + instance(default_server).lookupName(pieces_match[3], cb); + else + instance("http://"+pieces_match[3].str()).lookupName(pieces_match[2], cb); + return; + } + } + RING_ERR("Can't parse URI: %s", uri.c_str()); + cb("", Response::error); +} + +NameDirectory::NameDirectory(const std::string& s) + : serverUri_(s), + serverHost_(hostFromUri(s)), + cachePath_(fileutils::get_cache_dir()+DIR_SEPARATOR_STR+"namecache"+DIR_SEPARATOR_STR+serverHost_) {} +void +NameDirectory::load() +{ + loadCache(); +} + NameDirectory& NameDirectory::instance(const std::string& server) { const std::string& s = server.empty() ? DEFAULT_SERVER_URI : server; static std::map<std::string, NameDirectory> instances {}; - auto it = instances.emplace(s, NameDirectory{s}); - return it.first->second; + auto r = instances.emplace(s, NameDirectory{s}); + RING_WARN("NameDirectory: %s %p", s.c_str(), &r.first->second); + if (r.second) + r.first->second.load(); + return r.first->second; } size_t getContentLength(restbed::Response& reply) @@ -108,6 +143,7 @@ void NameDirectory::lookupAddress(const std::string& addr, LookupCallback cb) addrCache_.emplace(name, addr); nameCache_.emplace(addr, name); cb(name, Response::found); + saveCache(); } else { cb("", Response::notFound); } @@ -172,6 +208,7 @@ void NameDirectory::lookupName(const std::string& name, LookupCallback cb) addrCache_.emplace(name, addr); nameCache_.emplace(addr, name); cb(addr, Response::found); + saveCache(); } else { cb("", Response::notFound); } @@ -265,4 +302,42 @@ void NameDirectory::registerName(const std::string& addr, const std::string& nam ThreadPool::instance().run([ret](){ ret.get(); }); } +void +NameDirectory::saveCache() +{ + fileutils::recursive_mkdir(fileutils::get_cache_dir()+DIR_SEPARATOR_STR+"namecache"); + std::ofstream file(cachePath_, std::ios::trunc); + msgpack::pack(file, nameCache_); + RING_DBG("Saved %lu name-address mappings", (long unsigned)nameCache_.size()); +} + +void +NameDirectory::loadCache() +{ + msgpack::unpacker pac; + + // read file + { + std::ifstream file(cachePath_); + if (!file.is_open()) { + RING_DBG("Could not load %s", cachePath_.c_str()); + return; + } + std::string line; + while (std::getline(file, line)) { + pac.reserve_buffer(line.size()); + memcpy(pac.buffer(), line.data(), line.size()); + pac.buffer_consumed(line.size()); + } + } + + // load values + msgpack::object_handle oh; + if (pac.next(oh)) + oh.get().convert(nameCache_); + for (const auto& m : nameCache_) + addrCache_.emplace(m.second, m.first); + RING_DBG("Loaded %lu name-address mappings", (long unsigned)nameCache_.size()); +} + } diff --git a/src/ringdht/namedirectory.h b/src/ringdht/namedirectory.h index e8acc6f2a4..fe6b923bed 100644 --- a/src/ringdht/namedirectory.h +++ b/src/ringdht/namedirectory.h @@ -26,20 +26,24 @@ namespace ring { class NameDirectory { public: + enum class Response : int { found = 0, invalidName, notFound, error }; + enum class RegistrationResponse : int { success = 0, invalidName, alreadyTaken, error }; + + using LookupCallback = std::function<void(const std::string& result, Response response)>; + using RegistrationCallback = std::function<void(RegistrationResponse response)>; + NameDirectory() {} NameDirectory(const std::string& s); + void load(); static NameDirectory& instance(const std::string& server); static NameDirectory& instance() { return instance(DEFAULT_SERVER_URI); } - enum class Response : int { found = 0, invalidName, notFound, error }; - enum class RegistrationResponse : int { success = 0, invalidName, alreadyTaken, error }; + static void lookupUri(const std::string& uri, const std::string& default_server, LookupCallback cb); - using LookupCallback = std::function<void(const std::string& result, Response response)>; void lookupAddress(const std::string& addr, LookupCallback cb); void lookupName(const std::string& name, LookupCallback cb); - using RegistrationCallback = std::function<void(RegistrationResponse response)>; void registerName(const std::string& addr, const std::string& name, const std::string& owner, RegistrationCallback cb); const std::string& getServer() const { @@ -54,8 +58,12 @@ private: std::map<std::string, std::string> nameCache_; std::map<std::string, std::string> addrCache_; + const std::string cachePath_; + bool validateName(const std::string& name) const; + void saveCache(); + void loadCache(); }; } diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index a72a5d0faa..808ce79cc5 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -235,7 +235,7 @@ RingAccount::newOutgoingCall(const std::string& toUrl) } catch (...) { #if HAVE_RINGNS std::weak_ptr<RingAccount> wthis_ = std::static_pointer_cast<RingAccount>(shared_from_this()); - nameDir_.get().lookupName(sufix, [wthis_,call](const std::string& result, NameDirectory::Response response) mutable { + NameDirectory::lookupUri(sufix, nameServer_, [wthis_,call](const std::string& result, NameDirectory::Response response) mutable { runOnMainThread([=]() mutable { if (auto sthis = wthis_.lock()) { try { @@ -571,9 +571,13 @@ void RingAccount::unserialize(const YAML::Node &node) dhtPortUsed_ = dhtPort_; #if HAVE_RINGNS - std::string ringns_server; - parseValue(node, DRing::Account::ConfProperties::RingNS::URI, ringns_server); - nameDir_ = NameDirectory::instance(ringns_server); + try { + //std::string ringns_server; + parseValue(node, DRing::Account::ConfProperties::RingNS::URI, nameServer_); + nameDir_ = NameDirectory::instance(nameServer_); + } catch (const std::exception& e) { + RING_WARN("can't read name server: %s", e.what()); + } #endif parseValue(node, Conf::DHT_PUBLIC_IN_CALLS, dhtPublicInCalls_); @@ -1169,9 +1173,9 @@ RingAccount::setAccountDetails(const std::map<std::string, std::string> &details parseString(details, DRing::Account::ConfProperties::ARCHIVE_PATH, archivePath_); #if HAVE_RINGNS - std::string ringns_server; - parseString(details, DRing::Account::ConfProperties::RingNS::URI, ringns_server); - nameDir_ = NameDirectory::instance(ringns_server); + //std::string ringns_server; + parseString(details, DRing::Account::ConfProperties::RingNS::URI, nameServer_); + nameDir_ = NameDirectory::instance(nameServer_); #endif loadAccount(archive_password, archive_pin); @@ -1206,7 +1210,7 @@ RingAccount::getAccountDetails() const //a.emplace(DRing::Account::ConfProperties::ETH::KEY_FILE, ethPath_); a.emplace(DRing::Account::ConfProperties::RingNS::ACCOUNT, ethAccount_); #if HAVE_RINGNS - a.emplace(DRing::Account::ConfProperties::RingNS::URI, nameDir_.get().getServer()); + a.emplace(DRing::Account::ConfProperties::RingNS::URI, nameServer_); #endif return a; @@ -1229,7 +1233,7 @@ void RingAccount::lookupName(const std::string& name) { auto acc = getAccountID(); - nameDir_.get().lookupName(name, [acc,name](const std::string& result, NameDirectory::Response response) { + NameDirectory::lookupUri(name, nameServer_, [acc,name](const std::string& result, NameDirectory::Response response) { emitSignal<DRing::ConfigurationSignal::RegisteredNameFound>(acc, (int)response, result, name); }); } diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index 82dc120c66..3c5ad43bc7 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -353,6 +353,7 @@ class RingAccount : public SIPAccountBase { #if HAVE_RINGNS std::reference_wrapper<NameDirectory> nameDir_; + std::string nameServer_; std::string registeredName_; #endif -- GitLab