From b6dca5ccd6e1ca537a5ad664bb21de938c91cb1b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Tue, 10 Jan 2017 23:05:34 -0500
Subject: [PATCH] dht: use new NodeStats structure to provide stats

---
 include/opendht/callbacks.h | 10 ++++++++++
 include/opendht/dht.h       |  4 ++--
 include/opendht/dhtrunner.h |  3 ++-
 src/callbacks.cpp           | 15 ++++++++++++++-
 src/dht.cpp                 | 37 +++++++++++++++----------------------
 src/dhtrunner.cpp           | 20 ++++++++++++++++++--
 src/network_engine.cpp      |  2 +-
 src/routing_table.cpp       |  2 ++
 tools/dhtnode.cpp           | 10 ++++------
 9 files changed, 68 insertions(+), 35 deletions(-)

diff --git a/include/opendht/callbacks.h b/include/opendht/callbacks.h
index 3a400725..12d9f023 100644
--- a/include/opendht/callbacks.h
+++ b/include/opendht/callbacks.h
@@ -39,6 +39,16 @@ enum class NodeStatus {
     Connected     // 1+ good nodes
 };
 
+struct OPENDHT_PUBLIC NodeStats {
+    unsigned good_nodes,
+             dubious_nodes,
+             cached_nodes,
+             incoming_nodes;
+    unsigned table_depth;
+    unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
+    std::string toString() const;
+};
+
 /**
  * Dht configuration.
  */
diff --git a/include/opendht/dht.h b/include/opendht/dht.h
index 82e7136d..00ec6b83 100644
--- a/include/opendht/dht.h
+++ b/include/opendht/dht.h
@@ -270,8 +270,8 @@ public:
     std::vector<ValuesExport> exportValues() const;
     void importValues(const std::vector<ValuesExport>&);
 
-    unsigned getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return,
-            unsigned *incoming_return) const;
+    NodeStats getNodesStats(sa_family_t af) const;
+
     std::string getStorageLog() const;
     std::string getStorageLog(const InfoHash&) const;
 
diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h
index 1a7eecfe..86042c40 100644
--- a/include/opendht/dhtrunner.h
+++ b/include/opendht/dhtrunner.h
@@ -276,7 +276,8 @@ public:
         return running;
     }
 
-    int getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
+    NodeStats getNodesStats(sa_family_t af) const;
+    unsigned getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
 
     std::vector<unsigned> getNodeMessageStats(bool in = false) const;
     std::string getStorageLog() const;
diff --git a/src/callbacks.cpp b/src/callbacks.cpp
index bcdaf6fb..8908a2df 100644
--- a/src/callbacks.cpp
+++ b/src/callbacks.cpp
@@ -55,4 +55,17 @@ bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) {
     };
 }
 
-}
\ No newline at end of file
+std::string
+NodeStats::toString() const
+{
+    std::stringstream ss;
+    ss << "Known nodes: " << good_nodes << " good, " << dubious_nodes << " dubious, " << incoming_nodes << " incoming." << std::endl;
+    if (table_depth > 1) {
+        ss << "Routing table depth: " << table_depth << std::endl;
+        unsigned long tot_nodes = 8 * std::exp2(table_depth);
+        ss << "Network size estimation: " << tot_nodes << " nodes" << std::endl;
+    }
+    return ss.str();
+}
+
+}
diff --git a/src/dht.cpp b/src/dht.cpp
index 72a29ffd..d357c115 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -728,12 +728,11 @@ Dht::setLoggers(LogMethod error, LogMethod warn, LogMethod debug)
 NodeStatus
 Dht::getStatus(sa_family_t af) const
 {
-    unsigned good = 0, dubious = 0, cached = 0, incoming = 0;
-    unsigned tot = getNodesStats(af, &good, &dubious, &cached, &incoming);
+    const auto& stats = getNodesStats(af);
     auto& ping = af == AF_INET ? pending_pings4 : pending_pings6;
-    if (good)
+    if (stats.good_nodes)
         return NodeStatus::Connected;
-    if (ping or tot)
+    if (ping or stats.getKnownNodes())
         return NodeStatus::Connecting;
     return NodeStatus::Disconnected;
 }
@@ -2479,32 +2478,26 @@ Dht::tokenMatch(const Blob& token, const sockaddr *sa) const
     return false;
 }
 
-unsigned
-Dht::getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const
+NodeStats
+Dht::getNodesStats(sa_family_t af) const
 {
+    NodeStats stats {};
     const auto& now = scheduler.time();
-    unsigned good = 0, dubious = 0, cached = 0, incoming = 0;
-    for (const auto& b : buckets(af)) {
+    const auto& bcks = buckets(af);
+    for (const auto& b : bcks) {
         for (auto& n : b.nodes) {
             if (n->isGood(now)) {
-                good++;
+                stats.good_nodes++;
                 if (n->time > n->reply_time)
-                    incoming++;
+                    stats.incoming_nodes++;
             } else if (not n->isExpired())
-                dubious++;
+                stats.dubious_nodes++;
         }
         if (b.cached)
-            cached++;
-    }
-    if (good_return)
-        *good_return = good;
-    if (dubious_return)
-        *dubious_return = dubious;
-    if (cached_return)
-        *cached_return = cached;
-    if (incoming_return)
-        *incoming_return = incoming;
-    return good + dubious;
+            stats.cached_nodes++;
+    }
+    stats.table_depth = bcks.depth(bcks.findBucket(myid));
+    return stats;
 }
 
 void
diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp
index bd8a5b23..21f670a2 100644
--- a/src/dhtrunner.cpp
+++ b/src/dhtrunner.cpp
@@ -233,11 +233,27 @@ DhtRunner::importValues(const std::vector<ValuesExport>& values) {
     dht_->importValues(values);
 }
 
-int
+unsigned
 DhtRunner::getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const
 {
     std::lock_guard<std::mutex> lck(dht_mtx);
-    return dht_->getNodesStats(af, good_return, dubious_return, cached_return, incoming_return);
+    const auto stats = dht_->getNodesStats(af);
+    if (good_return)
+        *good_return = stats.good_nodes;
+    if (dubious_return)
+        *dubious_return = stats.dubious_nodes;
+    if (cached_return)
+        *cached_return = stats.cached_nodes;
+    if (incoming_return)
+        *incoming_return = stats.incoming_nodes;
+    return stats.good_nodes + stats.dubious_nodes;
+}
+
+NodeStats
+DhtRunner::getNodesStats(sa_family_t af) const
+{
+    std::lock_guard<std::mutex> lck(dht_mtx);
+    return dht_->getNodesStats(af);
 }
 
 std::vector<unsigned>
diff --git a/src/network_engine.cpp b/src/network_engine.cpp
index ba157a16..761b3289 100644
--- a/src/network_engine.cpp
+++ b/src/network_engine.cpp
@@ -594,7 +594,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
 }
 
 void
-packToken(msgpack::packer<msgpack::sbuffer>& pk, Blob token)
+packToken(msgpack::packer<msgpack::sbuffer>& pk, const Blob& token)
 {
     pk.pack_bin(token.size());
     pk.pack_bin_body((char*)token.data(), token.size());
diff --git a/src/routing_table.cpp b/src/routing_table.cpp
index 576b3d14..54b08897 100644
--- a/src/routing_table.cpp
+++ b/src/routing_table.cpp
@@ -70,6 +70,8 @@ RoutingTable::middle(const RoutingTable::const_iterator& it) const
 unsigned
 RoutingTable::depth(const RoutingTable::const_iterator& it) const
 {
+    if (it == end())
+        return 0;
     int bit1 = it->first.lowbit();
     int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
     return std::max(bit1, bit2)+1;
diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp
index 4d61b126..24955c04 100644
--- a/tools/dhtnode.cpp
+++ b/tools/dhtnode.cpp
@@ -101,12 +101,10 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params)
             continue;
         } else if (op == "ll") {
             print_node_info(dht, params);
-            unsigned good4, dubious4, cached4, incoming4;
-            unsigned good6, dubious6, cached6, incoming6;
-            dht->getNodesStats(AF_INET, &good4, &dubious4, &cached4, &incoming4);
-            dht->getNodesStats(AF_INET6, &good6, &dubious6, &cached6, &incoming6);
-            std::cout << "IPv4 nodes : " << good4 << " good, " << dubious4 << " dubious, " << incoming4 << " incoming." << std::endl;
-            std::cout << "IPv6 nodes : " << good6 << " good, " << dubious6 << " dubious, " << incoming6 << " incoming." << std::endl;
+            std::cout << "IPv4 stats:" << std::endl;
+            std::cout << dht->getNodesStats(AF_INET).toString() << std::endl;
+            std::cout << "IPv6 stats:" << std::endl;
+            std::cout << dht->getNodesStats(AF_INET6).toString() << std::endl;
             continue;
         } else if (op == "lr") {
             std::cout << "IPv4 routing table:" << std::endl;
-- 
GitLab