From aa202b2cd8769d3b86d21d237828d5eaf4fd9985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= Date: Tue, 5 Jun 2018 19:43:38 -0400 Subject: [PATCH] dhtrunner: add getNodeInfo() Allow to retrieve all dht stats in a single API call using the new method getNodeInfo() and the JSON-serializable new structure NodeInfo. --- CMakeLists.txt | 19 ++++-- configure.ac | 105 +++++++++++++++-------------- include/opendht/callbacks.h | 29 ++++++-- include/opendht/dht_proxy_server.h | 3 +- include/opendht/dhtrunner.h | 1 + include/opendht/value.h | 14 ++-- src/Makefile.am | 4 +- src/callbacks.cpp | 30 ++++++++- src/dht_proxy_server.cpp | 19 ++---- src/dhtrunner.cpp | 11 +++ src/value.cpp | 8 +-- 11 files changed, 152 insertions(+), 91 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c3dd1fd..35e22ab4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,9 +47,21 @@ if (NOT OPENDHT_ARGON2) set(OPENDHT_ARGON2 ON) endif() endif () + +pkg_search_module(Jsoncpp jsoncpp) +if (Jsoncpp_FOUND) + add_definitions(-DOPENDHT_JSONCPP) + list (APPEND opendht_SOURCES + src/base64.h + src/base64.cpp + ) +endif() + if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT) find_package(Restbed REQUIRED) - pkg_search_module(Jsoncpp jsoncpp) + if (!Jsoncpp_FOUND) + message(SEND_ERROR "Jsoncpp is required for DHT proxy support") + endif() endif() # Build flags @@ -207,13 +219,8 @@ if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT) list (APPEND opendht_HEADERS include/opendht/proxy.h ) - list (APPEND opendht_SOURCES - src/base64.h - src/base64.cpp - ) endif () - if(OPENDHT_ARGON2) # make sure argon2 submodule is up to date and initialized message("Initializing Argon2 submodule") diff --git a/configure.ac b/configure.ac index 59936934..93105f53 100644 --- a/configure.ac +++ b/configure.ac @@ -101,9 +101,51 @@ LT_LANG(C++) AX_CXX_COMPILE_STDCXX(11,[noext],[mandatory]) PKG_PROG_PKG_CONFIG() + +AC_ARG_ENABLE([proxy_server], AS_HELP_STRING([--enable-proxy-server], [Enable proxy server ability]), proxy_server=yes, proxy_server=no) +AM_CONDITIONAL(ENABLE_PROXY_SERVER, test x$proxy_server == xyes) + +AC_ARG_ENABLE([push_notifications], AS_HELP_STRING([--enable-push-notifications], [Enable push notifications support]), push_notifications=yes, push_notifications=no) +AM_CONDITIONAL(ENABLE_PUSH_NOTIFICATIONS, test x$push_notifications == xyes) + +AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity], + [Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no) +AM_CONDITIONAL(ENABLE_PROXY_SERVER_IDENTITY, test x$proxy_server_identity == xyes -a x$proxy_server == xyes) +AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity], + [Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no) + +AC_ARG_ENABLE([proxy_client], AS_HELP_STRING([--enable-proxy-client], [Enable proxy client ability]), proxy_client=yes, proxy_client=no) +AM_CONDITIONAL(ENABLE_PROXY_CLIENT, test x$proxy_client == xyes) + +AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests], [Enable tests]), build_tests=yes, build_tests=no) +AM_CONDITIONAL(ENABLE_TESTS, test x$build_tests == xyes) +AM_COND_IF([ENABLE_TESTS], [ + PKG_CHECK_MODULES([CppUnit], [cppunit >= 1.12]) +]) + +AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes | test x$proxy_server == xyes) + PKG_CHECK_MODULES([Nettle], [nettle >= 2.4]) PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3]) PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2]) + +AC_ARG_WITH([jsoncpp], AS_HELP_STRING([--without-jsoncpp], [Build without JsonCpp support])) +AS_IF([test "x$with_jsoncpp" != "xno"], + [PKG_CHECK_MODULES([JsonCpp], [jsoncpp >= 1.7.2], [have_jsoncpp=yes], [have_jsoncpp=no])], + [have_jsoncpp=no]) +AS_IF([test "x$have_jsoncpp" = "xyes"], [ + AC_MSG_NOTICE([Using JsonCpp]) + CPPFLAGS+=" -DOPENDHT_JSONCPP=1" +], [ + AC_MSG_NOTICE([Not using JsonCpp]) + AM_COND_IF(PROXY_CLIENT_OR_SERVER, AC_MSG_ERROR(["JsonCpp is required for proxy/push notification support"])) +]) + +AM_COND_IF([PROXY_CLIENT_OR_SERVER], [ + AC_CHECK_LIB(restbed, exit,, AC_MSG_ERROR([Missing restbed files])) + LDFLAGS="${LDFLAGS} -lrestbed" +]) + CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT" dnl Check for Argon2 @@ -135,58 +177,21 @@ AM_COND_IF([ENABLE_TOOLS], [ ]) ]) -AC_ARG_ENABLE([proxy_server], AS_HELP_STRING([--enable-proxy-server], [Enable proxy server ability]), proxy_server=yes, proxy_server=no) -AM_CONDITIONAL(ENABLE_PROXY_SERVER, test x$proxy_server == xyes) -AC_ARG_ENABLE([push_notifications], AS_HELP_STRING([--enable-push-notifications], [Enable push notifications support]), push_notifications=yes, push_notifications=no) -AM_CONDITIONAL(ENABLE_PUSH_NOTIFICATIONS, test x$push_notifications == xyes) -AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity], - [Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no) -AM_CONDITIONAL(ENABLE_PROXY_SERVER_IDENTITY, test x$proxy_server_identity == xyes) -AC_ARG_ENABLE([proxy_client], AS_HELP_STRING([--enable-proxy-client], [Enable proxy client ability]), proxy_client=yes, proxy_client=no) -AM_CONDITIONAL(ENABLE_PROXY_CLIENT, test x$proxy_client == xyes) +AM_COND_IF(ENABLE_PROXY_SERVER, + [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=true"], + [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=false"]) -AM_COND_IF([ENABLE_PROXY_SERVER], [ - AC_CHECK_LIB(restbed, exit,, AC_MSG_ERROR([Missing restbed files])) - PKG_CHECK_MODULES([Jsoncpp], [jsoncpp >= 1.7.2]) - CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=true -ljsoncpp -lrestbed" -], [ - CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=false" -]) +AM_COND_IF(ENABLE_PROXY_CLIENT, + [CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=true"], + [CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=false"]) -AM_COND_IF([ENABLE_PUSH_NOTIFICATIONS], [ - CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=true" -], [ - CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=false" -]) +AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS, + [CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=true"], + [CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=false"]) -AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity], - [Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no) -AM_CONDITIONAL(ENABLE_PROXY_SERVER_IDENTITY, test x$proxy_server_identity == xyes -a x$proxy_server == xyes) -AM_COND_IF([ENABLE_PROXY_SERVER_IDENTITY], [ - CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=true" -], [ - CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=false" -]) - -AM_COND_IF([ENABLE_PROXY_CLIENT], [ - CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=true" -], [ - CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=false" -]) - -AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes | test x$proxy_server == xyes) -AM_COND_IF([PROXY_CLIENT_OR_SERVER], [ - AC_CHECK_LIB(restbed, exit,, AC_MSG_ERROR([Missing restbed files])) - PKG_CHECK_MODULES([Jsoncpp], [jsoncpp >= 1.7.4]) - CPPFLAGS="${CPPFLAGS} ${Jsoncpp_CFLAGS}" - LDFLAGS="${LDFLAGS} ${Jsoncpp_LIBS} -lrestbed" -], []) - -AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests], [Enable tests]), build_tests=yes, build_tests=no) -AM_CONDITIONAL(ENABLE_TESTS, test x$build_tests == xyes) -AM_COND_IF([ENABLE_TESTS], [ - PKG_CHECK_MODULES([CppUnit], [cppunit >= 1.12]) -]) +AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY, + [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=true"], + [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=false"]) AC_CONFIG_FILES([doc/Doxyfile doc/Makefile]) @@ -202,6 +207,6 @@ AM_COND_IF([USE_CYTHON], [ AC_CONFIG_FILES([Makefile src/Makefile tools/Makefile - tests/Makefile + tests/Makefile opendht.pc]) AC_OUTPUT diff --git a/include/opendht/callbacks.h b/include/opendht/callbacks.h index 8507a77e..91ebd84d 100644 --- a/include/opendht/callbacks.h +++ b/include/opendht/callbacks.h @@ -27,9 +27,9 @@ #include #include -#if OPENDHT_PROXY_SERVER +#ifdef OPENDHT_JSONCPP #include -#endif //OPENDHT_PROXY_SERVER +#endif namespace dht { @@ -52,14 +52,35 @@ struct OPENDHT_PUBLIC NodeStats { unsigned table_depth {0}; unsigned getKnownNodes() const { return good_nodes + dubious_nodes; } std::string toString() const; -#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT + +#ifdef OPENDHT_JSONCPP /** * Build a json object from a NodeStats */ Json::Value toJson() const; NodeStats() {}; explicit NodeStats(const Json::Value& v); -#endif //OPENDHT_PROXY_SERVER +#endif + + MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth) +}; + +struct OPENDHT_PUBLIC NodeInfo { + InfoHash id; + InfoHash node_id; + NodeStats ipv4; + NodeStats ipv6; + +#ifdef OPENDHT_JSONCPP + /** + * Build a json object from a NodeStats + */ + Json::Value toJson() const; + NodeInfo() {}; + explicit NodeInfo(const Json::Value& v); +#endif + + MSGPACK_DEFINE_MAP(id, node_id, ipv4, ipv6) }; /** diff --git a/include/opendht/dht_proxy_server.h b/include/opendht/dht_proxy_server.h index ecf8fbb4..e240aa4e 100644 --- a/include/opendht/dht_proxy_server.h +++ b/include/opendht/dht_proxy_server.h @@ -239,8 +239,7 @@ private: Sp printStatsJob_; mutable std::mutex statsMutex_; - mutable NodeStats ipv4Stats_ {}; - mutable NodeStats ipv6Stats_ {}; + mutable NodeInfo nodeInfo_ {}; // Handle client quit for listen. // NOTE: can be simplified when we will supports restbed 5.0 diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h index 8eb08f2b..dec7bbff 100644 --- a/include/opendht/dhtrunner.h +++ b/include/opendht/dhtrunner.h @@ -293,6 +293,7 @@ public: 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; + NodeInfo getNodeInfo() const; std::vector getNodeMessageStats(bool in = false) const; std::string getStorageLog() const; diff --git a/include/opendht/value.h b/include/opendht/value.h index 4a950cda..63795caf 100644 --- a/include/opendht/value.h +++ b/include/opendht/value.h @@ -37,9 +37,9 @@ #include #include -#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT +#ifdef OPENDHT_JSONCPP #include -#endif //OPENDHT_PROXY_SERVER +#endif namespace dht { @@ -372,13 +372,13 @@ struct OPENDHT_PUBLIC Value Value(ValueType::Id t, const uint8_t* dat_ptr, size_t dat_len, Id id = INVALID_ID) : id(id), type(t), data(dat_ptr, dat_ptr+dat_len) {} -#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT +#ifdef OPENDHT_JSONCPP /** * Build a value from a json object * @param json */ Value(Json::Value& json); -#endif //OPENDHT_PROXY_SERVER +#endif template Value(ValueType::Id t, const Type& d, Id id = INVALID_ID) @@ -451,7 +451,7 @@ struct OPENDHT_PUBLIC Value return ss.str(); } -#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT +#ifdef OPENDHT_JSONCPP /** * Build a json object from a value * Example: @@ -461,7 +461,7 @@ struct OPENDHT_PUBLIC Value * } */ Json::Value toJson() const; -#endif //OPENDHT_PROXY_SERVER +#endif /** Return the size in bytes used by this value in memory (minimum). */ size_t size() const; @@ -996,7 +996,7 @@ unpackVector(const std::vector>& vals) { return ret; } -#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT +#ifdef OPENDHT_JSONCPP uint64_t unpackId(const Json::Value& json, const std::string& key); #endif diff --git a/src/Makefile.am b/src/Makefile.am index 67e4e833..c84722e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ lib_LTLIBRARIES = libopendht.la -libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ -libopendht_la_LIBADD = @Argon2_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@ +libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ +libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@ libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ libopendht_la_SOURCES = \ dht.cpp \ diff --git a/src/callbacks.cpp b/src/callbacks.cpp index 2cac5e68..ec57d2b1 100644 --- a/src/callbacks.cpp +++ b/src/callbacks.cpp @@ -68,7 +68,7 @@ NodeStats::toString() const return ss.str(); } -#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT +#ifdef OPENDHT_JSONCPP /** * Build a json object from a NodeStats */ @@ -98,6 +98,32 @@ NodeStats::NodeStats(const Json::Value& val) if (val.isMember("table_depth")) table_depth = static_cast(val["table_depth"].asLargestUInt()); } -#endif //OPENDHT_PROXY_SERVER + +/** + * Build a json object from a NodeStats + */ +Json::Value +NodeInfo::toJson() const +{ + Json::Value val; + if (id) + val["id"] = id.toString(); + val["node_id"] = node_id.toString(); + val["ipv4"] = ipv4.toJson(); + val["ipv6"] = ipv6.toJson(); + return val; +} + +NodeInfo::NodeInfo(const Json::Value& v) +{ + if (v.isMember("id")) + id = InfoHash(v["id"].asString()); + node_id = InfoHash(v["node_id"].asString()); + ipv4 = NodeStats(v["ipv4"]); + ipv6 = NodeStats(v["ipv6"]); +} + +#endif + } diff --git a/src/dht_proxy_server.cpp b/src/dht_proxy_server.cpp index 86eb6ab7..0cc49a91 100644 --- a/src/dht_proxy_server.cpp +++ b/src/dht_proxy_server.cpp @@ -29,7 +29,6 @@ #include #include #include - #include using namespace std::placeholders; @@ -132,12 +131,10 @@ DhtProxyServer::DhtProxyServer(std::shared_ptr dht, in_port_t port , } if (not stopListeners) { // Refresh stats cache - auto newIpv4Stats = dht_->getNodesStats(AF_INET); - auto newIpv6Stats = dht_->getNodesStats(AF_INET6); + auto newInfo = dht_->getNodeInfo(); { std::lock_guard lck(statsMutex_); - ipv4Stats_ = std::move(newIpv4Stats); - ipv6Stats_ = std::move(newIpv6Stats); + nodeInfo_ = std::move(newInfo); } } }); @@ -213,22 +210,16 @@ DhtProxyServer::getNodeInfo(const std::shared_ptr& session) co try { if (dht_) { Json::Value result; - auto id = dht_->getId(); - if (id) - result["id"] = id.toString(); - result["node_id"] = dht_->getNodeId().toString(); { std::lock_guard lck(statsMutex_); - if (ipv4Stats_.good_nodes == 0 && ipv6Stats_.good_nodes == 0) { + if (nodeInfo_.ipv4.good_nodes == 0 && nodeInfo_.ipv6.good_nodes == 0) { // NOTE: we want to avoid the disconnected state as much as possible // So, if the node is disconnected, we should force the update of the cache // and reconnect as soon as possible // This should not happen much - ipv4Stats_ = dht_->getNodesStats(AF_INET); - ipv6Stats_ = dht_->getNodesStats(AF_INET); + nodeInfo_ = dht_->getNodeInfo(); } - result["ipv4"] = ipv4Stats_.toJson(); - result["ipv6"] = ipv6Stats_.toJson(); + result = nodeInfo_.toJson(); } result["public_ip"] = s->get_origin(); // [ipv6:ipv4]:port or ipv4:port Json::StreamWriterBuilder wbuilder; diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp index 04381464..104ee3d6 100644 --- a/src/dhtrunner.cpp +++ b/src/dhtrunner.cpp @@ -301,6 +301,17 @@ DhtRunner::getNodesStats(sa_family_t af) const return activeDht()->getNodesStats(af); } +NodeInfo +DhtRunner::getNodeInfo() const { + std::lock_guard lck(dht_mtx); + NodeInfo info; + info.id = getId(); + info.node_id = getNodeId(); + info.ipv4 = dht_->getNodesStats(AF_INET); + info.ipv6 = dht_->getNodesStats(AF_INET6); + return info; +} + std::vector DhtRunner::getNodeMessageStats(bool in) const { diff --git a/src/value.cpp b/src/value.cpp index aea02953..ed17f090 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -22,9 +22,9 @@ #include "default_types.h" #include "securedht.h" // print certificate ID -#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT +#ifdef OPENDHT_JSONCPP #include "base64.h" -#endif //OPENDHT_PROXY_SERVER +#endif namespace dht { @@ -172,7 +172,7 @@ Value::msgpack_unpack_body(const msgpack::object& o) } } -#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT +#ifdef OPENDHT_JSONCPP Value::Value(Json::Value& json) { id = Value::Id(unpackId(json, "id")); @@ -248,7 +248,7 @@ unpackId(const Json::Value& json, const std::string& key) { } catch (...) {} return ret; } -#endif //OPENDHT_PROXY_SERVER +#endif bool FieldValue::operator==(const FieldValue& vfd) const