diff --git a/include/opendht/dht.h b/include/opendht/dht.h index 263ee1511d6c0565a8bf0d0592d38c7a1a255475..c7bf07b0595ede07c94d10fd28e6b4944eac3dab 100644 --- a/include/opendht/dht.h +++ b/include/opendht/dht.h @@ -188,6 +188,10 @@ public: void importValues(const std::vector<ValuesExport>&); int getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const; + std::string getStorageLog() const; + std::string getRoutingTablesLog(sa_family_t af) const; + std::string getSearchesLog(sa_family_t af) const; + void dumpTables() const; /* This must be provided by the user. */ diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h index afc11a5114db91838cb6e640af68510fcf99a4ed..82b4eeb0919da32b0821624ede5445a96107c411 100644 --- a/include/opendht/dhtrunner.h +++ b/include/opendht/dhtrunner.h @@ -89,6 +89,12 @@ public: return dht->getId(); } + InfoHash getRoutingId() const { + if (!dht) + return {}; + return dht->getRoutingId(); + } + std::vector<Dht::NodeExport> exportNodes() const { std::unique_lock<std::mutex> lck(dht_mtx); if (!dht) @@ -122,6 +128,28 @@ public: return running; } + int getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const + { + std::unique_lock<std::mutex> lck(dht_mtx); + return dht->getNodesStats(af, good_return, dubious_return, cached_return, incoming_return); + } + + std::string getStorageLog() const + { + std::unique_lock<std::mutex> lck(dht_mtx); + return dht->getStorageLog(); + } + std::string getRoutingTablesLog(sa_family_t af) const + { + std::unique_lock<std::mutex> lck(dht_mtx); + return dht->getRoutingTablesLog(af); + } + std::string getSearchesLog(sa_family_t af) const + { + std::unique_lock<std::mutex> lck(dht_mtx); + return dht->getSearchesLog(af); + } + /** * If threaded is false, loop() must be called periodically. */ diff --git a/src/dht.cpp b/src/dht.cpp index e0ab1bc7cde8cd297e6ae4246cdacc544bf0a0c5..d0cd1e5dfd23a947461f5b4e1a350a6fbee37b15 100644 --- a/src/dht.cpp +++ b/src/dht.cpp @@ -1663,6 +1663,38 @@ Dht::dumpTables() const DHT_DEBUG("%s", out.str().c_str()); } +std::string +Dht::getStorageLog() const +{ + std::stringstream out; + for (const auto& st : store) { + out << "Storage " << st.id << " " << st.listeners.size() << " list., " << st.values.size() << " values:" << std::endl; + for (const auto& v : st.values) + out << " " << *v.data << " (" << (now.tv_sec - v.time) << "s)" << std::endl; + } + return out.str(); +} + + +std::string +Dht::getRoutingTablesLog(sa_family_t af) const +{ + auto& list = (af == AF_INET) ? buckets : buckets6; + std::stringstream out; + for (const auto& b : list) + dumpBucket(b, out); + return out.str(); +} + +std::string +Dht::getSearchesLog(sa_family_t af) const +{ + auto& list = (af == AF_INET) ? buckets : buckets6; + std::stringstream out; + for (const auto& sr : searches) + dumpSearch(sr, out); + return out.str(); +} Dht::Dht(int s, int s6, const InfoHash& id) : dht_socket(s), dht_socket6(s6), myid(id) diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp index e87fd88eb7bcbc8d2d3897abdf4c67e74c7abc5a..21cb4ac0392e84c3a216e1e6430fb8b759198a89 100644 --- a/tools/dhtnode.cpp +++ b/tools/dhtnode.cpp @@ -86,13 +86,18 @@ void printLog(std::ostream& s, char const* m, va_list args) { int main(int argc, char **argv) { - if (argc < 2) - throw std::invalid_argument("Entrez un port"); - int i = 1; - int p = atoi(argv[i++]); - if (p <= 0 || p >= 0x10000) - throw std::invalid_argument("Port invalide: " + std::to_string(p)); + int p = 0; + if (argc >= 2) { + int a = atoi(argv[i]); + if (a > 0 && a < 0x10000) { + p = a; + i++; + } + } + if (!p) + p = 4222; + in_port_t port = p; std::vector<sockaddr_storage> bootstrap_nodes {}; @@ -128,28 +133,68 @@ main(int argc, char **argv) auto crt_tmp = dht::crypto::generateIdentity("DHT Node", ca_tmp); DhtRunner dht; - dht.run(port, crt_tmp, true, [](dht::Dht::Status ipv4, dht::Dht::Status ipv6) { - std::cout << (int)ipv4 << (int)ipv6 << std::endl; + dht.run(port, crt_tmp, true, [](dht::Dht::Status /* ipv4 */, dht::Dht::Status /* ipv6 */) { }); - dht.setLoggers( - [](char const* m, va_list args){ std::cerr << red; printLog(std::cerr, m, args); std::cerr << def; }, - [](char const* m, va_list args){ std::cout << yellow; printLog(std::cout, m, args); std::cout << def; }, - [](char const* m, va_list args){ printLog(std::cout, m, args); } - ); - dht.bootstrap(bootstrap_nodes); + std::cout << "OpenDht node " << dht.getRoutingId() << " running on port " << port<< std::endl; + std::cout << "Public key ID " << dht.getId() << std::endl; + while (true) { + std::cout << ">> "; std::string line; std::getline(std::cin, line); std::istringstream iss(line); std::string op, idstr, value; iss >> op >> idstr; - if (op == "x" || op == "q" || op == "exit" || op == "quit") { + if (std::cin.eof() || op == "x" || op == "q" || op == "exit" || op == "quit") { break; + } else if (op == "h" || op == "help") { + std::cout << "OpenDht command line interface (CLI)" << std::endl; + std::cout << "Possible commands:" << std::endl; + std::cout << " h, help Print this help message." << std::endl; + std::cout << " q, quit Quit the program." << std::endl; + + std::cout << std::endl << "Node information:" << std::endl; + std::cout << " ll Print basic information and stats about the current node." << std::endl; + std::cout << " ls Print basic information about current searches." << std::endl; + std::cout << " ld Print basic information about currenty stored values on this node." << std::endl; + std::cout << " lr Print the full current routing table of this node" << std::endl; + + std::cout << std::endl << "Operations on the DHT:" << std::endl; + std::cout << " g [key] Get values at [key]." << std::endl; + std::cout << " l [key] Listen for value changes at [key]." << std::endl; + std::cout << " p [key] [str] Put string value at [key]." << std::endl; + std::cout << " s [key] [str] Put string value at [key], signed with our generated private key." << std::endl; + std::cout << " e [key] [dest] [str] Put string value at [key], encrypted for [dest] with its public key (if found)." << std::endl; + std::cout << std::endl; + continue; + } else if (op == "ll") { + 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 << "OpenDht node " << dht.getRoutingId() << std::endl; + std::cout << "Public key ID " << dht.getId() << std::endl; + std::cout << "IPv4 nodes : " << good4 << " good, " << dubious4 << " dubious, " << incoming4 << " incoming." << std::endl; + std::cout << "IPv6 nodes : " << good6 << " good, " << dubious6 << " dubious, " << incoming6 << " incoming." << std::endl; + continue; + } else if (op == "lr") { + std::cout << "IPv4 routing table:" << std::endl; + std::cout << dht.getRoutingTablesLog(AF_INET) << std::endl; + std::cout << "IPv6 routing table:" << std::endl; + std::cout << dht.getRoutingTablesLog(AF_INET6) << std::endl; + continue; + } else if (op == "ld") { + std::cout << dht.getStorageLog() << std::endl; + continue; + } else if (op == "ls") { + std::cout << "Searches:" << std::endl; + std::cout << dht.getSearchesLog(AF_INET) << std::endl; + continue; } dht::InfoHash id {idstr}; @@ -211,10 +256,13 @@ main(int argc, char **argv) dht.put(id, dht::Value {dht::ServiceAnnouncement::TYPE.id, dht::ServiceAnnouncement(port)}, [](bool ok) { std::cout << "Announce done !" << ok << std::endl; }); + } else { + std::cout << "Unknown command: " << op << std::endl; + std::cout << " (type 'h' or 'help' for help)" << std::endl; } } - std::cout << "Stopping node..." << std::endl; + std::cout << std::endl << "Stopping node..." << std::endl; dht.join(); gnutls_global_deinit();