diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000000000000000000000000000000000000..26374afe107fe3fadfc0ff1d3ec6454f7a675a96
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1 @@
+Checks: '-*,clang-diagnostic-*,performance-*,bugprone-*,llvm-*,clang-analyzer-*,misc-*,-llvm-namespace-comment,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-llvm-header-guard,-llvm-include-order,-bugprone-suspicious-string-compare'
diff --git a/include/opendht/callbacks.h b/include/opendht/callbacks.h
index 21288556260f7f6af21da34762526dac001a542b..6738c3079efcc476679e7cb64b55257ccbccd0a7 100644
--- a/include/opendht/callbacks.h
+++ b/include/opendht/callbacks.h
@@ -131,8 +131,8 @@ using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::
 
 typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data);
 
-OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
-OPENDHT_PUBLIC GetCallback bindGetCb(GetCallbackSimple cb);
+OPENDHT_PUBLIC GetCallbackSimple bindGetCb(const GetCallbackRaw& raw_cb, void* user_data);
+OPENDHT_PUBLIC GetCallback bindGetCb(const GetCallbackSimple& cb);
 
 using DoneCallback = std::function<void(bool success, const std::vector<std::shared_ptr<Node>>& nodes)>;
 typedef void (*DoneCallbackRaw)(bool, std::vector<std::shared_ptr<Node>>*, void *user_data);
@@ -142,10 +142,10 @@ typedef bool (*FilterRaw)(const Value&, void *user_data);
 
 using DoneCallbackSimple = std::function<void(bool success)>;
 
-OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data);
+OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data);
 OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackSimple donecb);
-OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data);
-OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data);
-OPENDHT_PUBLIC Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data);
+OPENDHT_PUBLIC DoneCallback bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data);
+OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data);
+OPENDHT_PUBLIC Value::Filter bindFilterRaw(const FilterRaw& raw_filter, void* user_data);
 
 }
diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h
index 96c492a205d2e5082d8c4b96dc3eb5aced05adb8..badb0c757144336247094b4534a1863cdcc20474 100644
--- a/include/opendht/crypto.h
+++ b/include/opendht/crypto.h
@@ -431,7 +431,7 @@ struct OPENDHT_PUBLIC Certificate {
     void addRevocationList(RevocationList&&);
     void addRevocationList(std::shared_ptr<RevocationList>);
 
-    static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false);
+    static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false);
 
     gnutls_x509_crt_t getCopy() const {
         if (not cert)
@@ -503,7 +503,7 @@ struct OPENDHT_PUBLIC TrustList
     TrustList(TrustList&& o) noexcept : trust(std::move(o.trust)) {
         o.trust = nullptr;
     }
-    TrustList& operator=(TrustList&& o);
+    TrustList& operator=(TrustList&& o) noexcept;
     ~TrustList();
     void add(const Certificate& crt);
     void add(const RevocationList& crl);
@@ -611,11 +611,11 @@ using SecureBlob = secure_vector<uint8_t>;
  *           If not set, the generated certificate will be a self-signed CA.
  * @param key_length stength of the generated private key (bits).
  */
-OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
-OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
+OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca);
+OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", const Identity& ca = {}, unsigned key_length = 4096);
 
-OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, Identity ca, bool is_ca);
-OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", Identity ca = {});
+OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca);
+OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", const Identity& ca = {});
 
 
 /**
diff --git a/include/opendht/default_types.h b/include/opendht/default_types.h
index 48f0b9b6f96e5f6c2d3cac7f8943975a984302c0..47932755747e4f7028fa9e0b25eecce9143da753 100644
--- a/include/opendht/default_types.h
+++ b/include/opendht/default_types.h
@@ -38,7 +38,7 @@ class OPENDHT_PUBLIC DhtMessage : public Value::Serializable<DhtMessage>
 public:
     static const ValueType TYPE;
 
-    DhtMessage(std::string s = {}, Blob msg = {}) : service(s), data(msg) {}
+    DhtMessage(const std::string& s = {}, const Blob& msg = {}) : service(s), data(msg) {}
 
     std::string getService() const {
         return service;
@@ -48,7 +48,7 @@ public:
 
     static bool storePolicy(InfoHash key, std::shared_ptr<Value>& value, const InfoHash& from, const SockAddr&);
 
-    static Value::Filter ServiceFilter(std::string s);
+    static Value::Filter ServiceFilter(const std::string& s);
 
     /** print value for debugging */
     friend std::ostream& operator<< (std::ostream&, const DhtMessage&);
diff --git a/include/opendht/dht.h b/include/opendht/dht.h
index e0f6795c87fc7568fcaaa7c2eb595dfdb071d955..d8b6b7e8d473537f9e9ec8969505e1418929a16c 100644
--- a/include/opendht/dht.h
+++ b/include/opendht/dht.h
@@ -68,7 +68,7 @@ public:
      * Initialise the Dht with two open sockets (for IPv4 and IP6)
      * and an ID for the node.
      */
-    Dht(const int& s, const int& s6, Config config);
+    Dht(const int& s, const int& s6, const Config& config);
     virtual ~Dht();
 
     /**
@@ -430,7 +430,7 @@ private:
      * nodes.
      */
     void dataPersistence(InfoHash id);
-    size_t maintainStorage(decltype(store)::value_type&, bool force=false, DoneCallback donecb=nullptr);
+    size_t maintainStorage(decltype(store)::value_type&, bool force=false, const DoneCallback& donecb={});
 
     // Buckets
     RoutingTable& buckets(sa_family_t af) { return af == AF_INET ? buckets4 : buckets6; }
diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h
index 32ba4431398c02ceceaed50245a5f277387ab860..73774c76c1bd9ff2c035784f9f9f515a7d32649a 100644
--- a/include/opendht/dhtrunner.h
+++ b/include/opendht/dhtrunner.h
@@ -364,7 +364,7 @@ public:
             /*.push_node_id = */""
         });
     }
-    void run(in_port_t port, Config config);
+    void run(in_port_t port, const Config& config);
 
     /**
      * @param local4: Local IPv4 address and port to bind. Can be null.
@@ -374,12 +374,12 @@ public:
      * @param threaded: If false, loop() must be called periodically. Otherwise a thread is launched.
      * @param cb: Optional callback to receive general state information.
      */
-    void run(const SockAddr& local4, const SockAddr& local6, Config config);
+    void run(const SockAddr& local4, const SockAddr& local6, const Config& config);
 
     /**
      * Same as @run(sockaddr_in, sockaddr_in6, Identity, bool, StatusCallback), but with string IP addresses and service (port).
      */
-    void run(const char* ip4, const char* ip6, const char* service, Config config);
+    void run(const char* ip4, const char* ip6, const char* service, const Config& config);
 
     void setOnStatusChanged(StatusCallback&& cb) {
         statusCb = std::move(cb);
diff --git a/include/opendht/network_engine.h b/include/opendht/network_engine.h
index 032f49c53a94c9a33c4ef83114b190a65305d268..6fb1611fc153e1c6b79ac4477223f2a3d63e7ac4 100644
--- a/include/opendht/network_engine.h
+++ b/include/opendht/network_engine.h
@@ -206,15 +206,15 @@ public:
 
     NetworkEngine(Logger& log, Scheduler& scheduler, const int& s = -1, const int& s6 = -1);
     NetworkEngine(InfoHash& myid, NetId net, const int& s, const int& s6, Logger& log, Scheduler& scheduler,
-            decltype(NetworkEngine::onError) onError,
-            decltype(NetworkEngine::onNewNode) onNewNode,
-            decltype(NetworkEngine::onReportedAddr) onReportedAddr,
-            decltype(NetworkEngine::onPing) onPing,
-            decltype(NetworkEngine::onFindNode) onFindNode,
-            decltype(NetworkEngine::onGetValues) onGetValues,
-            decltype(NetworkEngine::onListen) onListen,
-            decltype(NetworkEngine::onAnnounce) onAnnounce,
-            decltype(NetworkEngine::onRefresh) onRefresh);
+            decltype(NetworkEngine::onError)&& onError,
+            decltype(NetworkEngine::onNewNode)&& onNewNode,
+            decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
+            decltype(NetworkEngine::onPing)&& onPing,
+            decltype(NetworkEngine::onFindNode)&& onFindNode,
+            decltype(NetworkEngine::onGetValues)&& onGetValues,
+            decltype(NetworkEngine::onListen)&& onListen,
+            decltype(NetworkEngine::onAnnounce)&& onAnnounce,
+            decltype(NetworkEngine::onRefresh)&& onRefresh);
 
     virtual ~NetworkEngine();
 
diff --git a/include/opendht/securedht.h b/include/opendht/securedht.h
index 6e2339af558dddcf68355ddce4c969a406921467..5c6eb0b3b8e636f6655aaf89d03aef469bb58ed2 100644
--- a/include/opendht/securedht.h
+++ b/include/opendht/securedht.h
@@ -37,9 +37,9 @@ public:
 
     using Config = SecureDhtConfig;
 
-    static dht::Config& getConfig(SecureDht::Config& conf)
+    static dht::Config getConfig(const SecureDht::Config& conf)
     {
-        auto& c = conf.node_config;
+        auto c = conf.node_config;
         if (not c.node_id and conf.id.second)
             c.node_id = InfoHash::get("node:"+conf.id.second->getId().toString());
         return c;
@@ -127,8 +127,8 @@ public:
 
     Value decrypt(const Value& v);
 
-    void findCertificate(const InfoHash& node, std::function<void(const Sp<crypto::Certificate>)> cb);
-    void findPublicKey(const InfoHash& node, std::function<void(const Sp<const crypto::PublicKey>)> cb);
+    void findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb);
+    void findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb);
 
     const Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
     void registerCertificate(Sp<crypto::Certificate>& cert);
@@ -332,8 +332,8 @@ private:
     SecureDht& operator=(const SecureDht&) = delete;
 
     Sp<Value> checkValue(const Sp<Value>& v);
-    ValueCallback getCallbackFilter(ValueCallback, Value::Filter&&);
-    GetCallback getCallbackFilter(GetCallback, Value::Filter&&);
+    ValueCallback getCallbackFilter(const ValueCallback&, Value::Filter&&);
+    GetCallback getCallbackFilter(const GetCallback&, Value::Filter&&);
 
     Sp<crypto::PrivateKey> key_ {};
     Sp<crypto::Certificate> certificate_ {};
diff --git a/include/opendht/value.h b/include/opendht/value.h
index 9867745fc6726b738b9d4aa9e0f59698faa1e4a0..0d5d620738892b9a79197fa0843078b458794012 100644
--- a/include/opendht/value.h
+++ b/include/opendht/value.h
@@ -79,7 +79,7 @@ static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
 struct OPENDHT_PUBLIC ValueType {
     typedef uint16_t Id;
 
-    static bool DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
+    static bool DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
     static bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&) {
         return false;
     }
@@ -947,7 +947,7 @@ struct OPENDHT_PUBLIC Query
  */
 struct OPENDHT_PUBLIC FieldValueIndex {
     FieldValueIndex() {}
-    FieldValueIndex(const Value& v, Select s = {});
+    FieldValueIndex(const Value& v, const Select& s = {});
     /**
      * Tells if all the fields of this are contained in the other
      * FieldValueIndex with the same value.
diff --git a/src/base64.cpp b/src/base64.cpp
index 9a8d329feef6ebf98176d11225fb909ba0d00b40..04d7aba8aa4b06cf0bfa4b272eae7c360476188f 100644
--- a/src/base64.cpp
+++ b/src/base64.cpp
@@ -17,8 +17,8 @@
 
 #include "base64.h"
 
-#include <stdint.h>
-#include <stdlib.h>
+#include <cstdint>
+#include <cstdlib>
 
 /* Mainly based on the following stackoverflow question:
  * http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
diff --git a/src/callbacks.cpp b/src/callbacks.cpp
index be6bec9a3dd39c0739be486c54f1b499052e28c5..7dd963613d7b7dcba8e758a5d07e142bb11be031 100644
--- a/src/callbacks.cpp
+++ b/src/callbacks.cpp
@@ -4,7 +4,7 @@ namespace dht {
 
 
 GetCallbackSimple
-bindGetCb(GetCallbackRaw raw_cb, void* user_data)
+bindGetCb(const GetCallbackRaw& raw_cb, void* user_data)
 {
     if (not raw_cb) return {};
     return [=](const std::shared_ptr<Value>& value) {
@@ -13,7 +13,7 @@ bindGetCb(GetCallbackRaw raw_cb, void* user_data)
 }
 
 GetCallback
-bindGetCb(GetCallbackSimple cb)
+bindGetCb(const GetCallbackSimple& cb)
 {
     if (not cb) return {};
     return [=](const std::vector<std::shared_ptr<Value>>& values) {
@@ -25,7 +25,7 @@ bindGetCb(GetCallbackSimple cb)
 }
 
 ShutdownCallback
-bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data)
+bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data)
 {
     return [=]() { shutdown_cb_raw(user_data); };
 }
@@ -39,7 +39,7 @@ bindDoneCb(DoneCallbackSimple donecb)
 }
 
 DoneCallback
-bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
+bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data)
 {
     if (not raw_cb) return {};
     return [=](bool success, const std::vector<std::shared_ptr<Node>>& nodes) {
@@ -48,7 +48,7 @@ bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
 }
 
 DoneCallbackSimple
-bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) {
+bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data) {
     if (not raw_cb) return {};
     return [=](bool success) {
         raw_cb(success, user_data);
diff --git a/src/crypto.cpp b/src/crypto.cpp
index 0f667054eed3930674e646c5e1e065344b4a7d2f..7f82889cda76f15584aa3cda589791820f728b59 100644
--- a/src/crypto.cpp
+++ b/src/crypto.cpp
@@ -385,7 +385,7 @@ PrivateKey::getPublicKey() const
     return pk_ret;
 }
 
-PublicKey::PublicKey(const Blob& dat) : pk(nullptr)
+PublicKey::PublicKey(const Blob& dat)
 {
     unpack(dat.data(), dat.size());
 }
@@ -572,7 +572,7 @@ PublicKey::getLongId() const
 #endif
 }
 
-Certificate::Certificate(const Blob& certData) : cert(nullptr)
+Certificate::Certificate(const Blob& certData)
 {
     unpack(certData.data(), certData.size());
 }
@@ -896,7 +896,7 @@ PrivateKey::generateEC()
 }
 
 Identity
-generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_length, bool is_ca)
+generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca)
 {
     auto key = std::make_shared<PrivateKey>(PrivateKey::generate(key_length));
     auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
@@ -905,12 +905,12 @@ generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_leng
 
 
 Identity
-generateIdentity(const std::string& name, Identity ca, unsigned key_length) {
+generateIdentity(const std::string& name, const Identity& ca, unsigned key_length) {
     return generateIdentity(name, ca, key_length, !ca.first || !ca.second);
 }
 
 Identity
-generateEcIdentity(const std::string& name, crypto::Identity ca, bool is_ca)
+generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca)
 {
     auto key = std::make_shared<PrivateKey>(PrivateKey::generateEC());
     auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
@@ -918,19 +918,19 @@ generateEcIdentity(const std::string& name, crypto::Identity ca, bool is_ca)
 }
 
 Identity
-generateEcIdentity(const std::string& name, Identity ca) {
+generateEcIdentity(const std::string& name, const Identity& ca) {
     return generateEcIdentity(name, ca, !ca.first || !ca.second);
 }
 
 Certificate
-Certificate::generate(const PrivateKey& key, const std::string& name, Identity ca, bool is_ca)
+Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca)
 {
     gnutls_x509_crt_t cert;
     if (not key.x509_key or gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS)
         return {};
     Certificate ret {cert};
 
-    int64_t now = time(NULL);
+    int64_t now = time(nullptr);
     /* 2038 bug: don't allow time wrap */
     auto boundTime = [](int64_t t) -> time_t {
         return std::min<int64_t>(t, std::numeric_limits<time_t>::max());
@@ -1228,11 +1228,11 @@ TrustList::~TrustList() {
 }
 
 TrustList&
-TrustList::operator=(TrustList&& o)
+TrustList::operator=(TrustList&& o) noexcept
 {
     if (trust)
         gnutls_x509_trust_list_deinit(trust, true);
-    trust = std::move(o.trust);
+    trust = o.trust;
     o.trust = nullptr;
     return *this;
 }
diff --git a/src/default_types.cpp b/src/default_types.cpp
index 8b4bcc7a903d4f035be128247315c93b5e23a0bc..6bf39f3d537b6ecdfc7d3ec43882c8aaedc6829b 100644
--- a/src/default_types.cpp
+++ b/src/default_types.cpp
@@ -38,7 +38,7 @@ DhtMessage::storePolicy(InfoHash h, std::shared_ptr<Value>& v, const InfoHash& f
 }
 
 Value::Filter
-DhtMessage::ServiceFilter(std::string s)
+DhtMessage::ServiceFilter(const std::string& s)
 {
     return Value::Filter::chain(
         Value::TypeFilter(TYPE),
diff --git a/src/dht.cpp b/src/dht.cpp
index 5400828cf3074918d0f2f6a24b518ae1cabc80b5..4862a067aaf82c6b8229e0e837305a21ef9f6b8c 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -537,7 +537,7 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
                     if (auto sr = ws.lock()) {
                         auto l = sr->listeners.find(list_token);
                         if (l != sr->listeners.end()) {
-                            l->second.get_cb(l->second.filter.filter(values), expired);
+                            l->second.get_cb(values, expired);
                         }
                     }
                 }, [ws,list_token] (ListenSyncStatus status) {
@@ -1714,7 +1714,7 @@ Dht::~Dht()
 
 Dht::Dht() : store(), network_engine(DHT_LOG, scheduler) {}
 
-Dht::Dht(const int& s, const int& s6, Config config)
+Dht::Dht(const int& s, const int& s6, const Config& config)
     : myid(config.node_id ? config.node_id : InfoHash::getRandom()), store(), store_quota(),
     network_engine(myid, config.network, s, s6, DHT_LOG, scheduler,
             std::bind(&Dht::onError, this, _1, _2),
@@ -1846,8 +1846,8 @@ Dht::bucketMaintenance(RoutingTable& list)
                 }
 
                 DHT_LOG.d(id, n->id, "[node %s] sending find %s for bucket maintenance", n->toString().c_str(), id.toString().c_str());
-                auto start = scheduler.time();
-                network_engine.sendFindNode(n, id, want, nullptr, [this,start,n](const net::Request&, bool over) {
+                //auto start = scheduler.time();
+                network_engine.sendFindNode(n, id, want, nullptr, [this,n](const net::Request&, bool over) {
                     if (over) {
                         const auto& end = scheduler.time();
                         // using namespace std::chrono;
@@ -1877,7 +1877,7 @@ Dht::dataPersistence(InfoHash id)
 }
 
 size_t
-Dht::maintainStorage(decltype(store)::value_type& storage, bool force, DoneCallback donecb)
+Dht::maintainStorage(decltype(store)::value_type& storage, bool force, const DoneCallback& donecb)
 {
     const auto& now = scheduler.time();
     size_t announce_per_af = 0;
diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp
index 92de36d5fe98d787e5a35c392e6c9be0a675d309..659cb9f9bc5ed567195bfe101b8619a4d838e5fe 100644
--- a/src/dhtrunner.cpp
+++ b/src/dhtrunner.cpp
@@ -75,7 +75,7 @@ DhtRunner::~DhtRunner()
 }
 
 void
-DhtRunner::run(in_port_t port, DhtRunner::Config config)
+DhtRunner::run(in_port_t port, const DhtRunner::Config& config)
 {
     SockAddr sin4;
     sin4.setFamily(AF_INET);
@@ -87,7 +87,7 @@ DhtRunner::run(in_port_t port, DhtRunner::Config config)
 }
 
 void
-DhtRunner::run(const char* ip4, const char* ip6, const char* service, DhtRunner::Config config)
+DhtRunner::run(const char* ip4, const char* ip6, const char* service, const DhtRunner::Config& config)
 {
     auto res4 = SockAddr::resolve(ip4, service);
     auto res6 = SockAddr::resolve(ip6, service);
@@ -96,7 +96,7 @@ DhtRunner::run(const char* ip4, const char* ip6, const char* service, DhtRunner:
 }
 
 void
-DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config config)
+DhtRunner::run(const SockAddr& local4, const SockAddr& local6, const DhtRunner::Config& config)
 {
     if (running)
         return;
@@ -629,7 +629,7 @@ DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f
     {
         std::lock_guard<std::mutex> lck(storage_mtx);
         pending_ops.emplace([=](SecureDht& dht) mutable {
-            dht.get(hash, vcb, dcb, std::move(f), std::move(w));
+            dht.get(hash, std::move(vcb), std::move(dcb), std::move(f), std::move(w));
         });
     }
     cv.notify_all();
@@ -638,14 +638,14 @@ DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f
 void
 DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, Value::Filter f, Where w)
 {
-    get(InfoHash::get(key), vcb, dcb, f, w);
+    get(InfoHash::get(key), std::move(vcb), std::move(dcb), std::move(f), std::move(w));
 }
 void
 DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) {
     {
         std::lock_guard<std::mutex> lck(storage_mtx);
         pending_ops.emplace([=](SecureDht& dht) mutable {
-            dht.query(hash, cb, done_cb, std::move(q));
+            dht.query(hash, std::move(cb), std::move(done_cb), std::move(q));
         });
     }
     cv.notify_all();
@@ -678,7 +678,7 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
             listeners_.emplace(tokenbGlobal, std::move(listener));
             ret_token->set_value(tokenbGlobal);
 #else
-            ret_token->set_value(dht.listen(hash, vcb, f, w));
+            ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
 #endif
         });
     }
@@ -689,7 +689,7 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
 std::future<size_t>
 DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Where w)
 {
-    return listen(InfoHash::get(key), vcb, f, w);
+    return listen(InfoHash::get(key), std::move(vcb), std::move(f), std::move(w));
 }
 
 void
@@ -768,7 +768,7 @@ DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, tim
 void
 DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, time_point created, bool permanent)
 {
-    put(InfoHash::get(key), std::forward<Value>(value), cb, created, permanent);
+    put(InfoHash::get(key), std::forward<Value>(value), std::move(cb), created, permanent);
 }
 
 void
@@ -798,13 +798,13 @@ DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback c
 void
 DhtRunner::putSigned(InfoHash hash, Value&& value, DoneCallback cb)
 {
-    putSigned(hash, std::make_shared<Value>(std::move(value)), cb);
+    putSigned(hash, std::make_shared<Value>(std::move(value)), std::move(cb));
 }
 
 void
 DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb)
 {
-    putSigned(InfoHash::get(key), std::forward<Value>(value), cb);
+    putSigned(InfoHash::get(key), std::forward<Value>(value), std::move(cb));
 }
 
 void
@@ -822,13 +822,13 @@ DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value
 void
 DhtRunner::putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb)
 {
-    putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), cb);
+    putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb));
 }
 
 void
 DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb)
 {
-    putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), cb);
+    putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb));
 }
 
 void
diff --git a/src/network_engine.cpp b/src/network_engine.cpp
index db4bc1fd1d478cc890e4f8650708ffa2aa00492e..6eed6584d71754e1bb360f675bb580d2d00ceb4a 100644
--- a/src/network_engine.cpp
+++ b/src/network_engine.cpp
@@ -142,19 +142,27 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
 NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, const int& s, const int& s6)
     : myid(zeroes), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
 {}
+
 NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, const int& s, const int& s6, Logger& log, Scheduler& scheduler,
-        decltype(NetworkEngine::onError) onError,
-        decltype(NetworkEngine::onNewNode) onNewNode,
-        decltype(NetworkEngine::onReportedAddr) onReportedAddr,
-        decltype(NetworkEngine::onPing) onPing,
-        decltype(NetworkEngine::onFindNode) onFindNode,
-        decltype(NetworkEngine::onGetValues) onGetValues,
-        decltype(NetworkEngine::onListen) onListen,
-        decltype(NetworkEngine::onAnnounce) onAnnounce,
-        decltype(NetworkEngine::onRefresh) onRefresh) :
-    onError(onError), onNewNode(onNewNode), onReportedAddr(onReportedAddr), onPing(onPing), onFindNode(onFindNode),
-    onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), onRefresh(onRefresh), myid(myid),
-    network(net), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
+        decltype(NetworkEngine::onError)&& onError,
+        decltype(NetworkEngine::onNewNode)&& onNewNode,
+        decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
+        decltype(NetworkEngine::onPing)&& onPing,
+        decltype(NetworkEngine::onFindNode)&& onFindNode,
+        decltype(NetworkEngine::onGetValues)&& onGetValues,
+        decltype(NetworkEngine::onListen)&& onListen,
+        decltype(NetworkEngine::onAnnounce)&& onAnnounce,
+        decltype(NetworkEngine::onRefresh)&& onRefresh) :
+    onError(std::move(onError)),
+    onNewNode(std::move(onNewNode)),
+    onReportedAddr(std::move(onReportedAddr)),
+    onPing(std::move(onPing)),
+    onFindNode(std::move(onFindNode)),
+    onGetValues(std::move(onGetValues)),
+    onListen(std::move(onListen)),
+    onAnnounce(std::move(onAnnounce)),
+    onRefresh(std::move(onRefresh)),
+    myid(myid), network(net), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
 {
     if (dht_socket >= 0) {
         if (!set_nonblocking(dht_socket, 1))
@@ -191,23 +199,23 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(4+(network?1:0));
 
-    pk.pack(std::string("u"));
+    pk.pack(KEY_U);
     pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
-    pk.pack(std::string("id")); pk.pack(myid);
+    pk.pack(KEY_REQ_ID); pk.pack(myid);
     if (not token.empty()) {
-        pk.pack(std::string("token")); packToken(pk, token);
+        pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
     }
     if (not values.empty()) {
-        pk.pack(std::string("re"));
+        pk.pack(KEY_REQ_REFRESHED);
         pk.pack(values);
         DHT_LOG.d(n->id, "[node %s] sending %zu refreshed values", n->toString().c_str(), values.size());
     }
 
-    pk.pack(std::string("t")); pk.pack(socket_id);
-    pk.pack(std::string("y")); pk.pack(std::string("r"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_TID); pk.pack(socket_id);
+    pk.pack(KEY_Y); pk.pack(KEY_R);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     // send response
@@ -221,23 +229,23 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(4+(network?1:0));
 
-    pk.pack(std::string("u"));
+    pk.pack(KEY_U);
     pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
-    pk.pack(std::string("id")); pk.pack(myid);
+    pk.pack(KEY_REQ_ID); pk.pack(myid);
     if (not token.empty()) {
-        pk.pack(std::string("token")); packToken(pk, token);
+        pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
     }
     if (not values.empty()) {
-        pk.pack(std::string("exp"));
+        pk.pack(KEY_REQ_EXPIRED);
         pk.pack(values);
         DHT_LOG.d(n->id, "[node %s] sending %zu expired values", n->toString().c_str(), values.size());
     }
 
-    pk.pack(std::string("t")); pk.pack(socket_id);
-    pk.pack(std::string("y")); pk.pack(std::string("r"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_TID); pk.pack(socket_id);
+    pk.pack(KEY_Y); pk.pack(KEY_R);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     // send response
@@ -687,16 +695,16 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(5+(network?1:0));
 
-    pk.pack(std::string("a")); pk.pack_map(1);
-     pk.pack(std::string("id")); pk.pack(myid);
+    pk.pack(KEY_A); pk.pack_map(1);
+     pk.pack(KEY_REQ_ID); pk.pack(myid);
 
-    pk.pack(std::string("q")); pk.pack(std::string("ping"));
-    pk.pack(std::string("t")); pk.pack_bin(tid.size());
+    pk.pack(KEY_Q); pk.pack(QUERY_PING);
+    pk.pack(KEY_TID); pk.pack_bin(tid.size());
                               pk.pack_bin_body((const char*)tid.data(), tid.size());
-    pk.pack(std::string("y")); pk.pack(std::string("q"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Y); pk.pack(KEY_Q);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     auto req = std::make_shared<Request>(MessageType::Ping, tid.toInt(), node,
@@ -724,17 +732,17 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(4+(network?1:0));
 
-    pk.pack(std::string("r")); pk.pack_map(2);
-      pk.pack(std::string("id")); pk.pack(myid);
+    pk.pack(KEY_R); pk.pack_map(2);
+      pk.pack(KEY_REQ_ID); pk.pack(myid);
       insertAddr(pk, addr);
 
     TransId t (tid);
-    pk.pack(std::string("t")); pk.pack_bin(t.size());
+    pk.pack(KEY_TID); pk.pack_bin(t.size());
                                pk.pack_bin_body((const char*)t.data(), t.size());
-    pk.pack(std::string("y")); pk.pack(std::string("r"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Y); pk.pack(KEY_R);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     send(buffer.data(), buffer.size(), 0, addr);
@@ -748,23 +756,23 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(5+(network?1:0));
 
-    pk.pack(std::string("a")); pk.pack_map(2 + (want>0?1:0));
-      pk.pack(std::string("id"));     pk.pack(myid);
-      pk.pack(std::string("target")); pk.pack(target);
+    pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
+      pk.pack(KEY_REQ_ID);     pk.pack(myid);
+      pk.pack(KEY_REQ_TARGET); pk.pack(target);
     if (want > 0) {
-      pk.pack(std::string("w"));
+      pk.pack(KEY_REQ_WANT);
       pk.pack_array(((want & WANT4)?1:0) + ((want & WANT6)?1:0));
       if (want & WANT4) pk.pack(AF_INET);
       if (want & WANT6) pk.pack(AF_INET6);
     }
 
-    pk.pack(std::string("q")); pk.pack(std::string("find"));
-    pk.pack(std::string("t")); pk.pack_bin(tid.size());
+    pk.pack(KEY_Q); pk.pack(QUERY_FIND);
+    pk.pack(KEY_TID); pk.pack_bin(tid.size());
                                pk.pack_bin_body((const char*)tid.data(), tid.size());
-    pk.pack(std::string("y")); pk.pack(std::string("q"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Y); pk.pack(KEY_Q);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     auto req = std::make_shared<Request>(MessageType::FindNode, tid.toInt(), n,
@@ -794,26 +802,26 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query&
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(5+(network?1:0));
 
-    pk.pack(std::string("a"));  pk.pack_map(2 +
+    pk.pack(KEY_A);  pk.pack_map(2 +
                                 (query.where.getFilter() or not query.select.getSelection().empty() ? 1:0) +
                                 (want>0?1:0));
-      pk.pack(std::string("id")); pk.pack(myid);
-      pk.pack(std::string("h"));  pk.pack(info_hash);
-      pk.pack(std::string("q")); pk.pack(query);
+      pk.pack(KEY_REQ_ID); pk.pack(myid);
+      pk.pack(KEY_REQ_H);  pk.pack(info_hash);
+      pk.pack(KEY_Q); pk.pack(query);
     if (want > 0) {
-      pk.pack(std::string("w"));
+      pk.pack(KEY_REQ_WANT);
       pk.pack_array(((want & WANT4)?1:0) + ((want & WANT6)?1:0));
       if (want & WANT4) pk.pack(AF_INET);
       if (want & WANT6) pk.pack(AF_INET6);
     }
 
-    pk.pack(std::string("q")); pk.pack(std::string("get"));
-    pk.pack(std::string("t")); pk.pack_bin(tid.size());
+    pk.pack(KEY_Q); pk.pack(QUERY_GET);
+    pk.pack(KEY_TID); pk.pack_bin(tid.size());
                                pk.pack_bin_body((const char*)tid.data(), tid.size());
-    pk.pack(std::string("y")); pk.pack(std::string("q"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Y); pk.pack(KEY_Q);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     auto req = std::make_shared<Request>(MessageType::GetValues, tid.toInt(), n,
@@ -901,7 +909,7 @@ NetworkEngine::packValueHeader(msgpack::sbuffer& buffer, const std::vector<Sp<Va
         total_size += v.size();
 
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
-    pk.pack(std::string("values"));
+    pk.pack(KEY_REQ_VALUES);
     pk.pack_array(svals.size());
     // try to put everything in a single UDP packet
     if (svals.size() < 50 && total_size < MAX_PACKET_VALUE_SIZE) {
@@ -929,12 +937,12 @@ NetworkEngine::sendValueParts(const TransId& tid, const std::vector<Blob>& svals
             msgpack::packer<msgpack::sbuffer> pk(&buffer);
             pk.pack_map(3+(network?1:0));
             if (network) {
-                pk.pack(std::string("n")); pk.pack(network);
+                pk.pack(KEY_NETID); pk.pack(network);
             }
-            pk.pack(std::string("y")); pk.pack(std::string("v"));
-            pk.pack(std::string("t")); pk.pack_bin(tid.size());
+            pk.pack(KEY_Y); pk.pack(KEY_V);
+            pk.pack(KEY_TID); pk.pack_bin(tid.size());
                                        pk.pack_bin_body((const char*)tid.data(), tid.size());
-            pk.pack(std::string("p")); pk.pack_map(1);
+            pk.pack(KEY_V); pk.pack_map(1);
                 pk.pack(i); pk.pack_map(2);
                     pk.pack(std::string("o")); pk.pack(start);
                     pk.pack(std::string("d")); pk.pack_bin(end-start);
@@ -954,22 +962,22 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(4+(network?1:0));
 
-    pk.pack(std::string("r"));
+    pk.pack(KEY_R);
     pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0));
-    pk.pack(std::string("id")); pk.pack(myid);
+    pk.pack(KEY_REQ_ID); pk.pack(myid);
     insertAddr(pk, addr);
     if (nodes.size() > 0) {
-        pk.pack(std::string("n4"));
+        pk.pack(KEY_REQ_NODES4);
         pk.pack_bin(nodes.size());
         pk.pack_bin_body((const char*)nodes.data(), nodes.size());
     }
     if (nodes6.size() > 0) {
-        pk.pack(std::string("n6"));
+        pk.pack(KEY_REQ_NODES6);
         pk.pack_bin(nodes6.size());
         pk.pack_bin_body((const char*)nodes6.data(), nodes6.size());
     }
     if (not token.empty()) {
-        pk.pack(std::string("token")); packToken(pk, token);
+        pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
     }
     std::vector<Blob> svals {};
     if (not st.empty()) { /* pack complete values */
@@ -977,7 +985,7 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
         if (fields.empty()) {
             svals = packValueHeader(buffer, st);
         } else { /* pack fields */
-            pk.pack(std::string("fields"));
+            pk.pack(KEY_REQ_FIELDS);
             pk.pack_map(2);
             pk.pack(std::string("f")); pk.pack(fields);
             pk.pack(std::string("v")); pk.pack_array(st.size()*fields.size());
@@ -989,12 +997,12 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
     }
 
     TransId t (tid);
-    pk.pack(std::string("t")); pk.pack_bin(t.size());
-                               pk.pack_bin_body((const char*)t.data(), t.size());
-    pk.pack(std::string("y")); pk.pack(std::string("r"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_TID); pk.pack_bin(t.size());
+                      pk.pack_bin_body((const char*)t.data(), t.size());
+    pk.pack(KEY_Y); pk.pack(KEY_R);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     // send response
@@ -1086,23 +1094,23 @@ NetworkEngine::sendListen(Sp<Node> n,
     pk.pack_map(5+(network?1:0));
 
     auto has_query = query.where.getFilter() or not query.select.getSelection().empty();
-    pk.pack(std::string("a")); pk.pack_map(4 + has_query);
-      pk.pack(std::string("id"));    pk.pack(myid);
-      pk.pack(std::string("h"));     pk.pack(hash);
-      pk.pack(std::string("token")); packToken(pk, token);
-      pk.pack(std::string("sid"));  pk.pack_bin(sid.size());
-                                     pk.pack_bin_body((const char*)sid.data(), sid.size());
+    pk.pack(KEY_A); pk.pack_map(4 + has_query);
+      pk.pack(KEY_REQ_ID);    pk.pack(myid);
+      pk.pack(KEY_REQ_H);     pk.pack(hash);
+      pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
+      pk.pack(KEY_REQ_SID);   pk.pack_bin(sid.size());
+                              pk.pack_bin_body((const char*)sid.data(), sid.size());
       if (has_query) {
-          pk.pack(std::string("q")); pk.pack(query);
+          pk.pack(KEY_REQ_QUERY); pk.pack(query);
       }
 
-    pk.pack(std::string("q")); pk.pack(std::string("listen"));
-    pk.pack(std::string("t")); pk.pack_bin(tid.size());
+    pk.pack(KEY_Q); pk.pack(QUERY_LISTEN);
+    pk.pack(KEY_TID); pk.pack_bin(tid.size());
                                pk.pack_bin_body((const char*)tid.data(), tid.size());
-    pk.pack(std::string("y")); pk.pack(std::string("q"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Y); pk.pack(KEY_Q);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     auto req = std::make_shared<Request>(MessageType::Listen, tid.toInt(), n,
@@ -1128,17 +1136,17 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(4+(network?1:0));
 
-    pk.pack(std::string("r")); pk.pack_map(2);
-      pk.pack(std::string("id")); pk.pack(myid);
+    pk.pack(KEY_R); pk.pack_map(2);
+      pk.pack(KEY_REQ_ID); pk.pack(myid);
       insertAddr(pk, addr);
 
     TransId t (tid);
-    pk.pack(std::string("t")); pk.pack_bin(t.size());
+    pk.pack(KEY_TID); pk.pack_bin(t.size());
                                pk.pack_bin_body((const char*)t.data(), t.size());
-    pk.pack(std::string("y")); pk.pack(std::string("r"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Y); pk.pack(KEY_R);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     send(buffer.data(), buffer.size(), 0, addr);
@@ -1158,23 +1166,23 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(5+(network?1:0));
 
-    pk.pack(std::string("a")); pk.pack_map((created < scheduler.time() ? 5 : 4));
-      pk.pack(std::string("id"));     pk.pack(myid);
-      pk.pack(std::string("h"));      pk.pack(infohash);
+    pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4));
+      pk.pack(KEY_REQ_ID);     pk.pack(myid);
+      pk.pack(KEY_REQ_H);      pk.pack(infohash);
       auto v = packValueHeader(buffer, {value});
       if (created < scheduler.time()) {
-          pk.pack(std::string("c"));
+          pk.pack(KEY_REQ_CREATION);
           pk.pack(to_time_t(created));
       }
-      pk.pack(std::string("token"));  pk.pack(token);
+      pk.pack(KEY_REQ_TOKEN);  pk.pack(token);
 
-    pk.pack(std::string("q")); pk.pack(std::string("put"));
-    pk.pack(std::string("t")); pk.pack_bin(tid.size());
-                               pk.pack_bin_body((const char*)tid.data(), tid.size());
-    pk.pack(std::string("y")); pk.pack(std::string("q"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Q);   pk.pack(QUERY_PUT);
+    pk.pack(KEY_TID); pk.pack_bin(tid.size());
+                      pk.pack_bin_body((const char*)tid.data(), tid.size());
+    pk.pack(KEY_Y);   pk.pack(KEY_Q);
+    pk.pack(KEY_UA);  pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid.toInt(), n,
@@ -1216,19 +1224,19 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(5+(network?1:0));
 
-    pk.pack(std::string("a")); pk.pack_map(4);
-      pk.pack(std::string("id"));  pk.pack(myid);
-      pk.pack(std::string("h"));  pk.pack(infohash);
-      pk.pack(std::string("vid")); pk.pack(vid);
-      pk.pack(std::string("token"));  pk.pack(token);
+    pk.pack(KEY_A); pk.pack_map(4);
+      pk.pack(KEY_REQ_ID);       pk.pack(myid);
+      pk.pack(KEY_REQ_H);        pk.pack(infohash);
+      pk.pack(KEY_REQ_VALUE_ID); pk.pack(vid);
+      pk.pack(KEY_REQ_TOKEN);    pk.pack(token);
 
-    pk.pack(std::string("q")); pk.pack(std::string("refresh"));
-    pk.pack(std::string("t")); pk.pack_bin(tid.size());
+    pk.pack(KEY_Q); pk.pack(QUERY_REFRESH);
+    pk.pack(KEY_TID); pk.pack_bin(tid.size());
                                pk.pack_bin_body((const char*)tid.data(), tid.size());
-    pk.pack(std::string("y")); pk.pack(std::string("q"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Y); pk.pack(KEY_Q);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     auto req = std::make_shared<Request>(MessageType::Refresh, tid.toInt(), n,
@@ -1261,18 +1269,18 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(4+(network?1:0));
 
-    pk.pack(std::string("r")); pk.pack_map(3);
-      pk.pack(std::string("id"));  pk.pack(myid);
-      pk.pack(std::string("vid")); pk.pack(vid);
+    pk.pack(KEY_R); pk.pack_map(3);
+      pk.pack(KEY_REQ_ID);  pk.pack(myid);
+      pk.pack(KEY_REQ_VALUE_ID); pk.pack(vid);
       insertAddr(pk, addr);
 
     TransId t(tid);
-    pk.pack(std::string("t")); pk.pack_bin(t.size());
+    pk.pack(KEY_TID); pk.pack_bin(t.size());
                                pk.pack_bin_body((const char*)t.data(), t.size());
-    pk.pack(std::string("y")); pk.pack(std::string("r"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Y); pk.pack(KEY_R);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     send(buffer.data(), buffer.size(), 0, addr);
@@ -1289,22 +1297,22 @@ NetworkEngine::sendError(const SockAddr& addr,
     msgpack::packer<msgpack::sbuffer> pk(&buffer);
     pk.pack_map(4 + (include_id?1:0));
 
-    pk.pack(std::string("e")); pk.pack_array(2);
+    pk.pack(KEY_E); pk.pack_array(2);
       pk.pack(code);
       pk.pack(message);
 
     if (include_id) {
-        pk.pack(std::string("r")); pk.pack_map(1);
-          pk.pack(std::string("id")); pk.pack(myid);
+        pk.pack(KEY_R); pk.pack_map(1);
+          pk.pack(KEY_REQ_ID); pk.pack(myid);
     }
 
     TransId t(tid);
-    pk.pack(std::string("t")); pk.pack_bin(t.size());
+    pk.pack(KEY_TID); pk.pack_bin(t.size());
                                pk.pack_bin_body((const char*)t.data(), t.size());
-    pk.pack(std::string("y")); pk.pack(std::string("e"));
-    pk.pack(std::string("v")); pk.pack(my_v);
+    pk.pack(KEY_Y); pk.pack(KEY_E);
+    pk.pack(KEY_UA); pk.pack(my_v);
     if (network) {
-        pk.pack(std::string("n")); pk.pack(network);
+        pk.pack(KEY_NETID); pk.pack(network);
     }
 
     send(buffer.data(), buffer.size(), 0, addr);
diff --git a/src/node.cpp b/src/node.cpp
index 2f4c3044f5eb18a4bcc08cc656a1a3ab864154cf..f1217da84d9ab573db6a2da60675f26eb5da2503 100644
--- a/src/node.cpp
+++ b/src/node.cpp
@@ -49,7 +49,7 @@ Node::isGood(time_point now) const
 bool
 Node::isPendingMessage() const
 {
-    for (auto r : requests_) {
+    for (const auto& r : requests_) {
         if (r.second->pending())
             return true;
     }
@@ -60,7 +60,7 @@ size_t
 Node::getPendingMessageCount() const
 {
     size_t count {0};
-    for (auto r : requests_) {
+    for (const auto& r : requests_) {
         if (r.second->pending())
             count++;
     }
diff --git a/src/op_cache.cpp b/src/op_cache.cpp
index b6091274481ddbebd43a7a20c64759e08fa30e36..d995e46523a4974d0d129c82d89fb7edeb7d7992 100644
--- a/src/op_cache.cpp
+++ b/src/op_cache.cpp
@@ -160,7 +160,7 @@ SearchCache::getOp(const Sp<Query>& q) const
 }
 
 size_t
-SearchCache::listen(ValueCallback get_cb, Sp<Query> q, Value::Filter filter, OnListen onListen)
+SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen)
 {
     // find exact match
     auto op = getOp(q);
@@ -192,7 +192,7 @@ SearchCache::cancelListen(size_t gtoken, const time_point& now) {
 }
 
 void
-SearchCache::cancelAll(std::function<void(size_t)> onCancel) {
+SearchCache::cancelAll(const std::function<void(size_t)>& onCancel) {
     for (auto& op : ops) {
         auto cache = std::move(op.second);
         cache->removeAll();
@@ -202,7 +202,7 @@ SearchCache::cancelAll(std::function<void(size_t)> onCancel) {
 }
 
 time_point
-SearchCache::expire(const time_point& now, std::function<void(size_t)> onCancel) {
+SearchCache::expire(const time_point& now, const std::function<void(size_t)>& onCancel) {
     nextExpiration_ = time_point::max();
     auto ret = nextExpiration_;
     for (auto it = ops.begin(); it != ops.end();) {
diff --git a/src/op_cache.h b/src/op_cache.h
index 6caa337644be2299c9111d13adb66dda30361e0e..ac64a4beee7fe93d6e87b9d13c6f2244896462c5 100644
--- a/src/op_cache.h
+++ b/src/op_cache.h
@@ -104,7 +104,7 @@ public:
     void onValuesAdded(const std::vector<Sp<Value>>& vals);
     void onValuesExpired(const std::vector<Sp<Value>>& vals);
 
-    bool addListener(size_t token, ValueCallback cb, Sp<Query> q, Value::Filter filter) {
+    bool addListener(size_t token, const ValueCallback& cb, const Sp<Query>& q, const Value::Filter& filter) {
         listeners.emplace(token, LocalListener{q, filter, cb});
         auto cached = cache.get(filter);
         if (not cached.empty()) {
@@ -163,12 +163,12 @@ public:
     SearchCache(SearchCache&&) = default;
 
     using OnListen = std::function<size_t(Sp<Query>, ValueCallback, SyncCallback)>;
-    size_t listen(ValueCallback get_cb, Sp<Query> q, Value::Filter filter, OnListen onListen);
+    size_t listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen);
 
     bool cancelListen(size_t gtoken, const time_point& now);
-    void cancelAll(std::function<void(size_t)> onCancel);
+    void cancelAll(const std::function<void(size_t)>& onCancel);
 
-    time_point expire(const time_point& now, std::function<void(size_t)> onCancel);
+    time_point expire(const time_point& now, const std::function<void(size_t)>& onCancel);
     time_point getExpiration() const {
         return nextExpiration_;
     }
diff --git a/src/parsed_message.h b/src/parsed_message.h
index 206e826cd30fed250d0ac25280f778eee3b0e684..6b568f5579b2a25514f68fef0468420a813567a5 100644
--- a/src/parsed_message.h
+++ b/src/parsed_message.h
@@ -26,6 +26,42 @@
 namespace dht {
 namespace net {
 
+static const std::string KEY_Y {"y"};
+static const std::string KEY_R {"r"};
+static const std::string KEY_U {"u"};
+static const std::string KEY_E {"e"};
+static const std::string KEY_V {"p"};
+static const std::string KEY_TID {"t"};
+static const std::string KEY_UA {"v"};
+static const std::string KEY_NETID {"n"};
+static const std::string KEY_ISCLIENT {"s"};
+static const std::string KEY_Q {"q"};
+static const std::string KEY_A {"a"};
+
+static const std::string KEY_REQ_SID {"sid"};
+static const std::string KEY_REQ_ID {"id"};
+static const std::string KEY_REQ_H {"h"};
+static const std::string KEY_REQ_TARGET {"target"};
+static const std::string KEY_REQ_QUERY {"q"};
+static const std::string KEY_REQ_TOKEN {"token"};
+static const std::string KEY_REQ_VALUE_ID {"vid"};
+static const std::string KEY_REQ_NODES4 {"n4"};
+static const std::string KEY_REQ_NODES6 {"n6"};
+static const std::string KEY_REQ_CREATION {"c"};
+static const std::string KEY_REQ_ADDRESS {"sa"};
+static const std::string KEY_REQ_VALUES {"values"};
+static const std::string KEY_REQ_EXPIRED {"exp"};
+static const std::string KEY_REQ_REFRESHED {"re"};
+static const std::string KEY_REQ_FIELDS {"fileds"};
+static const std::string KEY_REQ_WANT {"w"};
+
+static const std::string QUERY_PING {"ping"};
+static const std::string QUERY_FIND {"find"};
+static const std::string QUERY_GET {"get"};
+static const std::string QUERY_PUT {"put"};
+static const std::string QUERY_LISTEN {"listen"};
+static const std::string QUERY_REFRESH {"refresh"};
+
 Tid unpackTid(const msgpack::object& o) {
     switch (o.type) {
     case msgpack::type::POSITIVE_INTEGER:
@@ -78,7 +114,7 @@ struct ParsedMessage {
     /* reported address by the distant node */
     std::string ua;
     SockAddr addr;
-    void msgpack_unpack(msgpack::object o);
+    void msgpack_unpack(const msgpack::object& o);
 
     bool append(const ParsedMessage& block);
     bool complete();
@@ -123,63 +159,79 @@ ParsedMessage::complete()
 }
 
 void
-ParsedMessage::msgpack_unpack(msgpack::object msg)
+ParsedMessage::msgpack_unpack(const msgpack::object& msg)
 {
-    auto y = findMapValue(msg, "y");
-    auto r = findMapValue(msg, "r");
-    auto u = findMapValue(msg, "u");
-    auto e = findMapValue(msg, "e");
-    auto v = findMapValue(msg, "p");
-
-    if (auto t = findMapValue(msg, "t"))
-        tid = unpackTid(*t);
-
-    if (auto rv = findMapValue(msg, "v"))
-        ua = rv->as<std::string>();
-
-    if (auto netid = findMapValue(msg, "n"))
-        network = netid->as<NetId>();
-
-    if (auto is_client_v = findMapValue(msg, "s"))
-        is_client = is_client_v->as<bool>();
-
-    std::string q;
-    if (auto rq = findMapValue(msg, "q")) {
-        if (rq->type != msgpack::type::STR)
-            throw msgpack::type_error();
-        q = rq->as<std::string>();
+    if (msg.type != msgpack::type::MAP) throw msgpack::type_error();
+
+    struct ParsedMsg {
+        msgpack::object* y;
+        msgpack::object* r;
+        msgpack::object* u;
+        msgpack::object* e;
+        msgpack::object* v;
+        msgpack::object* a;
+        std::string q;
+    } parsed {};
+
+    for (unsigned i = 0; i < msg.via.map.size; i++) {
+        auto& o = msg.via.map.ptr[i];
+        if (o.key.type != msgpack::type::STR)
+            continue;
+        auto key = o.key.as<std::string>();
+        if (key == KEY_Y)
+            parsed.y = &o.val;
+        else if (key == KEY_R)
+            parsed.r = &o.val;
+        else if (key == KEY_U)
+            parsed.u = &o.val;
+        else if (key == KEY_E)
+            parsed.e = &o.val;
+        else if (key == KEY_V)
+            parsed.v = &o.val;
+        else if (key == KEY_TID)
+            tid = unpackTid(o.val);
+        else if (key == KEY_UA)
+            ua = o.val.as<std::string>();
+        else if (key == KEY_NETID)
+            network = o.val.as<NetId>();
+        else if (key == KEY_ISCLIENT)
+            is_client = o.val.as<bool>();
+        else if (key == KEY_Q)
+            parsed.q = o.val.as<std::string>();
+        else if (key == KEY_A)
+            parsed.a = &o.val;
     }
 
-    if (e)
+    if (parsed.e)
         type = MessageType::Error;
-    else if (r)
+    else if (parsed.r)
         type = MessageType::Reply;
-    else if (v)
+    else if (parsed.v)
         type = MessageType::ValueData;
-    else if (u)
+    else if (parsed.u)
         type = MessageType::ValueUpdate;
-    else if (y and y->as<std::string>() != "q")
+    else if (parsed.y and parsed.y->as<std::string>() != "q")
         throw msgpack::type_error();
-    else if (q == "ping")
+    else if (parsed.q == QUERY_PING)
         type = MessageType::Ping;
-    else if (q == "find")
+    else if (parsed.q == QUERY_FIND)
         type = MessageType::FindNode;
-    else if (q == "get")
+    else if (parsed.q == QUERY_GET)
         type = MessageType::GetValues;
-    else if (q == "listen")
+    else if (parsed.q == QUERY_LISTEN)
         type = MessageType::Listen;
-    else if (q == "put")
+    else if (parsed.q == QUERY_PUT)
         type = MessageType::AnnounceValue;
-    else if (q == "refresh")
+    else if (parsed.q == QUERY_REFRESH)
         type = MessageType::Refresh;
     else
         throw msgpack::type_error();
 
     if (type == MessageType::ValueData) {
-        if (v->type != msgpack::type::MAP)
+        if (parsed.v->type != msgpack::type::MAP)
             throw msgpack::type_error();
-        for (size_t i = 0; i < v->via.map.size; ++i) {
-            auto& vdat = v->via.map.ptr[i];
+        for (size_t i = 0; i < parsed.v->via.map.size; ++i) {
+            auto& vdat = parsed.v->via.map.ptr[i];
             auto o = findMapValue(vdat.val, "o");
             auto d = findMapValue(vdat.val, "d");
             if (not o or not d)
@@ -189,70 +241,85 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
         return;
     }
 
-    auto a = findMapValue(msg, "a");
-    if (!a && !r && !e && !u)
+    if (!parsed.a && !parsed.r && !parsed.e && !parsed.u)
         throw msgpack::type_error();
-    auto& req = a ? *a : (r ? *r : (u ? *u : *e));
+    auto& req = parsed.a ? *parsed.a : (parsed.r ? *parsed.r : (parsed.u ? *parsed.u : *parsed.e));
 
-    if (e) {
-        if (e->type != msgpack::type::ARRAY)
+    if (parsed.e) {
+        if (parsed.e->type != msgpack::type::ARRAY)
             throw msgpack::type_error();
-        error_code = e->via.array.ptr[0].as<uint16_t>();
+        error_code = parsed.e->via.array.ptr[0].as<uint16_t>();
     }
 
-    if (auto t = findMapValue(req, "sid"))
-        socket_id = unpackTid(*t);
-
-    if (auto rid = findMapValue(req, "id"))
-        id = {*rid};
+    struct ParsedReq {
+        msgpack::object* values;
+        msgpack::object* fields;
+        msgpack::object* sa;
+        msgpack::object* want;
+    } parsedReq {};
 
-    if (auto rh = findMapValue(req, "h"))
-        info_hash = {*rh};
-
-    if (auto rtarget = findMapValue(req, "target"))
-        target = {*rtarget};
-
-    if (auto rquery = findMapValue(req, "q"))
-        query.msgpack_unpack(*rquery);
-
-    if (auto otoken = findMapValue(req, "token"))
-        token = unpackBlob(*otoken);
-
-    if (auto vid = findMapValue(req, "vid"))
-        value_id = vid->as<Value::Id>();
-
-    if (auto rnodes4 = findMapValue(req, "n4"))
-        nodes4_raw = unpackBlob(*rnodes4);
-
-    if (auto rnodes6 = findMapValue(req, "n6"))
-        nodes6_raw = unpackBlob(*rnodes6);
+    for (unsigned i = 0; i < req.via.map.size; i++) {
+        auto& o = req.via.map.ptr[i];
+        if (o.key.type != msgpack::type::STR)
+            continue;
+        auto key = o.key.as<std::string>();
+        if (key == KEY_REQ_SID)
+            socket_id = unpackTid(o.val);
+        else if (key == KEY_REQ_ID)
+            id = {o.val};
+        else if (key == KEY_REQ_H)
+            info_hash = {o.val};
+        else if (key == KEY_REQ_TARGET)
+            target = {o.val};
+        else if (key == KEY_REQ_QUERY)
+            query.msgpack_unpack(o.val);
+        else if (key == KEY_REQ_TOKEN)
+            token = unpackBlob(o.val);
+        else if (key == KEY_REQ_VALUE_ID)
+            value_id = o.val.as<Value::Id>();
+        else if (key == KEY_REQ_NODES4)
+            nodes4_raw = unpackBlob(o.val);
+        else if (key == KEY_REQ_NODES6)
+            nodes6_raw = unpackBlob(o.val);
+        else if (key == KEY_REQ_ADDRESS)
+            parsedReq.sa = &o.val;
+        else if (key == KEY_REQ_CREATION)
+            created = from_time_t(o.val.as<std::time_t>());
+        else if (key == KEY_REQ_VALUES)
+            parsedReq.values = &o.val;
+        else if (key == KEY_REQ_EXPIRED)
+            expired_values = o.val.as<decltype(expired_values)>();
+        else if (key == KEY_REQ_REFRESHED)
+            refreshed_values = o.val.as<decltype(refreshed_values)>();
+        else if (key == KEY_REQ_FIELDS)
+            parsedReq.fields = &o.val;
+        else if (key == KEY_REQ_WANT)
+            parsedReq.want = &o.val;
+    }
 
-    if (auto sa = findMapValue(req, "sa")) {
-        if (sa->type != msgpack::type::BIN)
+    if (parsedReq.sa) {
+        if (parsedReq.sa->type != msgpack::type::BIN)
             throw msgpack::type_error();
-        auto l = sa->via.bin.size;
+        auto l = parsedReq.sa->via.bin.size;
         if (l == sizeof(in_addr)) {
             addr.setFamily(AF_INET);
             auto& a = addr.getIPv4();
             a.sin_port = 0;
-            std::copy_n(sa->via.bin.ptr, l, (char*)&a.sin_addr);
+            std::copy_n(parsedReq.sa->via.bin.ptr, l, (char*)&a.sin_addr);
         } else if (l == sizeof(in6_addr)) {
             addr.setFamily(AF_INET6);
             auto& a = addr.getIPv6();
             a.sin6_port = 0;
-            std::copy_n(sa->via.bin.ptr, l, (char*)&a.sin6_addr);
+            std::copy_n(parsedReq.sa->via.bin.ptr, l, (char*)&a.sin6_addr);
         }
     } else
         addr = {};
 
-    if (auto rcreated = findMapValue(req, "c"))
-        created = from_time_t(rcreated->as<std::time_t>());
-
-    if (auto rvalues = findMapValue(req, "values")) {
-        if (rvalues->type != msgpack::type::ARRAY)
+    if (parsedReq.values) {
+        if (parsedReq.values->type != msgpack::type::ARRAY)
             throw msgpack::type_error();
-        for (size_t i = 0; i < rvalues->via.array.size; i++) {
-            auto& packed_v = rvalues->via.array.ptr[i];
+        for (size_t i = 0; i < parsedReq.values->via.array.size; i++) {
+            auto& packed_v = parsedReq.values->via.array.ptr[i];
             if (packed_v.type == msgpack::type::POSITIVE_INTEGER) {
                 // Skip oversize values with a small margin for header overhead
                 if (packed_v.via.u64 > MAX_VALUE_SIZE + 32)
@@ -260,16 +327,16 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
                 value_parts.emplace(i, std::make_pair(packed_v.via.u64, Blob{}));
             } else {
                 try {
-                    values.emplace_back(std::make_shared<Value>(rvalues->via.array.ptr[i]));
+                    values.emplace_back(std::make_shared<Value>(parsedReq.values->via.array.ptr[i]));
                 } catch (const std::exception& e) {
                      //DHT_LOG_WARN("Error reading value: %s", e.what());
                 }
             }
         }
-    } else if (auto raw_fields = findMapValue(req, "fields")) {
-        if (auto rfields = findMapValue(*raw_fields, "f")) {
+    } else if (parsedReq.fields) {
+        if (auto rfields = findMapValue(*parsedReq.fields, "f")) {
             auto vfields = rfields->as<std::set<Value::Field>>();
-            if (auto rvalues = findMapValue(*raw_fields, "v")) {
+            if (auto rvalues = findMapValue(*parsedReq.fields, "v")) {
                 if (rvalues->type != msgpack::type::ARRAY)
                     throw msgpack::type_error();
                 size_t val_num = rvalues->via.array.size / vfields.size();
@@ -284,18 +351,14 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
         } else {
             throw msgpack::type_error();
         }
-    } else if (auto raw_fields = findMapValue(req, "exp")) {
-        expired_values = raw_fields->as<decltype(expired_values)>();
-    } else if (auto raw_fields = findMapValue(req, "re")) {
-        refreshed_values = raw_fields->as<decltype(refreshed_values)>();
     }
 
-    if (auto w = findMapValue(req, "w")) {
-        if (w->type != msgpack::type::ARRAY)
+    if (parsedReq.want) {
+        if (parsedReq.want->type != msgpack::type::ARRAY)
             throw msgpack::type_error();
         want = 0;
-        for (unsigned i=0; i<w->via.array.size; i++) {
-            auto& val = w->via.array.ptr[i];
+        for (unsigned i=0; i<parsedReq.want->via.array.size; i++) {
+            auto& val = parsedReq.want->via.array.ptr[i];
             try {
                 auto w = val.as<sa_family_t>();
                 if (w == AF_INET)
diff --git a/src/routing_table.cpp b/src/routing_table.cpp
index 87f341d827c26d95d3b1ba6749d0b6a513cdc568..82525afef50b0ac454164c47f8d966fdb9546953 100644
--- a/src/routing_table.cpp
+++ b/src/routing_table.cpp
@@ -92,7 +92,7 @@ RoutingTable::middle(const RoutingTable::const_iterator& it) const
         throw std::out_of_range("End of table");
 
     InfoHash id = it->first;
-    id.setBit(bit, 1);
+    id.setBit(bit, true);
     return id;
 }
 
diff --git a/src/search.h b/src/search.h
index 80dca94aad8778f2241bef92ff076b6059e490f7..da80f1af722373c10364e6ac7dd971b9aa8179b2 100644
--- a/src/search.h
+++ b/src/search.h
@@ -387,7 +387,6 @@ struct Dht::Search {
     /* listeners */
     struct SearchListener {
         Sp<Query> query;
-        Value::Filter filter;
         ValueCallback get_cb;
         SyncCallback sync_cb;
     };
@@ -489,7 +488,7 @@ struct Dht::Search {
     bool isAnnounced(Value::Id id) const;
     bool isListening(time_point now) const;
 
-    void get(Value::Filter f, const Sp<Query>& q, const QueryCallback& qcb, const GetCallback& gcb, const DoneCallback& dcb, Scheduler& scheduler) {
+    void get(const Value::Filter& f, const Sp<Query>& q, const QueryCallback& qcb, const GetCallback& gcb, const DoneCallback& dcb, Scheduler& scheduler) {
         if (gcb or qcb) {
             if (not cache.get(f, q, gcb, dcb)) {
                 const auto& now = scheduler.time();
@@ -499,12 +498,12 @@ struct Dht::Search {
         }
     }
 
-    size_t listen(ValueCallback cb, Value::Filter f, const Sp<Query>& q, Scheduler& scheduler) {
+    size_t listen(const ValueCallback& cb, const Value::Filter& f, const Sp<Query>& q, Scheduler& scheduler) {
         //DHT_LOG.e(id, "[search %s IPv%c] listen", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
         return cache.listen(cb, q, f, [&](const Sp<Query>& q, ValueCallback vcb, SyncCallback scb){
             done = false;
             auto token = ++listener_token;
-            listeners.emplace(token, SearchListener{q, f, vcb, scb});
+            listeners.emplace(token, SearchListener{q, vcb, scb});
             scheduler.edit(nextSearchStep, scheduler.time());
             return token;
         });
diff --git a/src/securedht.cpp b/src/securedht.cpp
index 382a54b4ed40375bb4eb1e934262753a58cc6453..251960be243ca67ec866c355acf0c154bb644a51 100644
--- a/src/securedht.cpp
+++ b/src/securedht.cpp
@@ -61,8 +61,7 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
     }
 }
 
-SecureDht::~SecureDht()
-{}
+SecureDht::~SecureDht() = default;
 
 ValueType
 SecureDht::secureType(ValueType&& type)
@@ -166,7 +165,7 @@ SecureDht::registerCertificate(Sp<crypto::Certificate>& cert)
 }
 
 void
-SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<crypto::Certificate>)> cb)
+SecureDht::findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb)
 {
     Sp<crypto::Certificate> b = getCertificate(node);
     if (b && *b) {
@@ -207,7 +206,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<cry
 }
 
 void
-SecureDht::findPublicKey(const InfoHash& node, std::function<void(const Sp<const crypto::PublicKey>)> cb)
+SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb)
 {
     auto pk = getPublicKey(node);
     if (pk && *pk) {
@@ -280,7 +279,7 @@ SecureDht::checkValue(const Sp<Value>& v)
 }
 
 ValueCallback
-SecureDht::getCallbackFilter(ValueCallback cb, Value::Filter&& filter)
+SecureDht::getCallbackFilter(const ValueCallback& cb, Value::Filter&& filter)
 {
     return [=](const std::vector<Sp<Value>>& values, bool expired) {
         std::vector<Sp<Value>> tmpvals {};
@@ -299,7 +298,7 @@ SecureDht::getCallbackFilter(ValueCallback cb, Value::Filter&& filter)
 
 
 GetCallback
-SecureDht::getCallbackFilter(GetCallback cb, Value::Filter&& filter)
+SecureDht::getCallbackFilter(const GetCallback& cb, Value::Filter&& filter)
 {
     return [=](const std::vector<Sp<Value>>& values) {
         std::vector<Sp<Value>> tmpvals {};
diff --git a/src/value.cpp b/src/value.cpp
index 34e6ba1332f6bc5098a7e81e94bf055ac4ffdf66..5a77f70c561eff0e1785b5389923735fbb894eb2 100644
--- a/src/value.cpp
+++ b/src/value.cpp
@@ -65,8 +65,8 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
         } else {
             s << "Data (type: " << v.type << " ): ";
             s << std::hex;
-            for (size_t i=0; i<v.data.size(); i++)
-                s << std::setfill('0') << std::setw(2) << (unsigned)v.data[i];
+            for (auto i : v.data)
+                s << std::setfill('0') << std::setw(2) << (unsigned)i;
             s << std::dec;
         }
     }
@@ -78,7 +78,7 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
 const ValueType ValueType::USER_DATA = {0, "User Data"};
 
 bool
-ValueType::DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&)
+ValueType::DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&)
 {
     return v->size() <= MAX_VALUE_SIZE;
 }
@@ -292,7 +292,7 @@ FieldValue::getLocalFilter() const
     }
 }
 
-FieldValueIndex::FieldValueIndex(const Value& v, Select s)
+FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
 {
     auto selection = s.getSelection();
     if (not selection.empty()) {
@@ -399,8 +399,8 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
 }
 
 void trim_str(std::string& str) {
-    auto first = std::min(str.size(), str.find_first_not_of(" "));
-    auto last = std::min(str.size(), str.find_last_not_of(" "));
+    auto first = std::min(str.size(), str.find_first_not_of(' '));
+    auto last = std::min(str.size(), str.find_last_not_of(' '));
     str = str.substr(first, last - first + 1);
 }
 
diff --git a/tests/tests_runner.cpp b/tests/tests_runner.cpp
index 87803bc37eb99824c79e84b19b80b240d09079c0..a380bee1a4ecd49c94a4084f0b0bcb0e9b1a87ff 100644
--- a/tests/tests_runner.cpp
+++ b/tests/tests_runner.cpp
@@ -21,7 +21,7 @@
 #include <cppunit/CompilerOutputter.h>
 #include <iostream>
 
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
     CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
     CppUnit::Test *suite = registry.makeTest();
     if (suite->countTestCases() == 0) {
diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp
index f14c1f9b43aa324f748744433bb8b2aa48007966..189fb6375c849075063dfa03a64c292ec1402434 100644
--- a/tools/dhtnode.cpp
+++ b/tools/dhtnode.cpp
@@ -307,7 +307,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
             }, [start](bool ok) {
                 auto end = std::chrono::high_resolution_clock::now();
                 std::cout << "Get: " << (ok ? "completed" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
-            }, {}, dht::Where {std::move(rem)});
+            }, {}, dht::Where {rem});
         }
         else if (op == "q") {
             std::string rem;
@@ -322,7 +322,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
             }, [start](bool ok) {
                 auto end = std::chrono::high_resolution_clock::now();
                 std::cout << "Query: " << (ok ? "completed" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
-            }, dht::Query {std::move(rem)});
+            }, dht::Query {rem});
         }
         else if (op == "l") {
             std::string rem;
@@ -332,7 +332,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
                 for (const auto& value : values)
                     std::cout << "\t" << *value << std::endl;
                 return true;
-            }, {}, dht::Where {std::move(rem)});
+            }, {}, dht::Where {rem});
             auto t = token.get();
             std::cout << "Listening, token: " << t << std::endl;
         }
@@ -431,7 +431,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
                                   << p.toString() << std::endl
                                   << "   hash: " << p.hash() << std::endl;
                         std::cout << "   entries:" << std::endl;
-                        for (auto v : vals)
+                        for (const auto& v : vals)
                              std::cout << "      " << v->first.toString() << "[vid: " << v->second << "]" << std::endl;
                     },
                     [start](bool ok) {