From 1e10e28fd7aa8edf5423a1212a3c207c89d9aad3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Sun, 17 Mar 2019 13:04:58 -0400
Subject: [PATCH] network: improve message parsing performance

---
 src/network_engine.cpp | 234 +++++++++++++++++++-------------------
 src/parsed_message.h   | 251 ++++++++++++++++++++++++++---------------
 2 files changed, 274 insertions(+), 211 deletions(-)

diff --git a/src/network_engine.cpp b/src/network_engine.cpp
index db4bc1fd..d3ea1293 100644
--- a/src/network_engine.cpp
+++ b/src/network_engine.cpp
@@ -191,23 +191,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 +221,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 +687,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 +724,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 +748,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 +794,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 +901,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 +929,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 +954,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 +977,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 +989,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 +1086,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 +1128,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 +1158,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 +1216,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 +1261,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 +1289,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/parsed_message.h b/src/parsed_message.h
index 206e826c..6b568f55 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)
-- 
GitLab