diff --git a/CMakeLists.txt b/CMakeLists.txt index ddae8b93e..a9aa9190e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -332,6 +332,7 @@ set(LIB_UTIL_SRC llarp/util/mem.cpp llarp/util/queue_manager.cpp llarp/util/queue.cpp + llarp/util/status.cpp llarp/util/str.cpp llarp/util/string_view.cpp llarp/util/thread_pool.cpp diff --git a/libabyss/include/abyss/json.hpp b/libabyss/include/abyss/json.hpp index 045374624..243b3d2d3 100644 --- a/libabyss/include/abyss/json.hpp +++ b/libabyss/include/abyss/json.hpp @@ -2,18 +2,6 @@ #define __ABYSS_JSON_JSON_HPP #include -//#if __cplusplus >= 201703L -#if 0 -#include -#include -namespace abyss -{ - namespace json - { - using Object = std::unordered_map< std::string, std::any >; - } -} // namespace abyss -#else #include namespace abyss { @@ -22,10 +10,7 @@ namespace abyss using Document = rapidjson::Document; using Value = rapidjson::Value; } // namespace json -} // namespace abyss -#endif -namespace abyss -{ + #if __cplusplus >= 201703L using string_view = std::string_view; #else diff --git a/llarp/dht/bucket.hpp b/llarp/dht/bucket.hpp index ad09e79cf..344d0032a 100644 --- a/llarp/dht/bucket.hpp +++ b/llarp/dht/bucket.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -13,13 +14,25 @@ namespace llarp namespace dht { template < typename Val_t > - struct Bucket + struct Bucket : public util::IStateful { using BucketStorage_t = std::map< Key_t, Val_t, XorMetric >; using Random_t = std::function< uint64_t() >; Bucket(const Key_t& us, Random_t r) : nodes(XorMetric(us)), random(r){}; + void + ExtractStatus(util::StatusObject& obj) const override + { + for(const auto& item : nodes) + { + std::string keyname = item.first.ToHex(); + util::StatusObject itemObj; + item.second.ExtractStatus(itemObj); + obj.PutObject(keyname.c_str(), itemObj); + } + } + size_t size() const { diff --git a/llarp/dht/context.cpp b/llarp/dht/context.cpp index 6d9203507..4087ca533 100644 --- a/llarp/dht/context.cpp +++ b/llarp/dht/context.cpp @@ -222,6 +222,28 @@ namespace llarp pendingExploreLookups.Expire(now); } + void + Context::ExtractStatus(util::StatusObject &obj) const + { + util::StatusObject pendingRouterObj, pendingIntrosetObj, pendingTagObj, + pendingExploreObj, routerBucketObj, serviceBucketObj; + + pendingRouterLookups.ExtractStatus(pendingRouterObj); + pendingIntrosetLookups.ExtractStatus(pendingIntrosetObj); + pendingTagLookups.ExtractStatus(pendingTagObj); + pendingExploreLookups.ExtractStatus(pendingExploreObj); + nodes->ExtractStatus(routerBucketObj); + services->ExtractStatus(serviceBucketObj); + + obj.PutObject("pendingRouterLookups", pendingRouterObj); + obj.PutObject("pendingIntrosetLookups", pendingIntrosetObj); + obj.PutObject("pendingTagLookups", pendingTagObj); + obj.PutObject("pendingExploreLookups", pendingExploreObj); + obj.PutObject("nodes", routerBucketObj); + obj.PutObject("services", serviceBucketObj); + obj.PutString("ourKey", ourKey.ToHex()); + } + void Context::Init(const Key_t &us, llarp::Router *r, llarp_time_t exploreInterval) diff --git a/llarp/dht/context.hpp b/llarp/dht/context.hpp index 80908659c..649c0186a 100644 --- a/llarp/dht/context.hpp +++ b/llarp/dht/context.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -68,7 +69,7 @@ namespace llarp Nodes() const = 0; }; - struct Context final : public AbstractContext + struct Context final : public AbstractContext, public util::IStateful { Context(); @@ -76,6 +77,9 @@ namespace llarp { } + void + ExtractStatus(util::StatusObject& obj) const override; + llarp::Crypto* Crypto() const override; diff --git a/llarp/dht/explorenetworkjob.hpp b/llarp/dht/explorenetworkjob.hpp index d88b6b9cc..275b5121a 100644 --- a/llarp/dht/explorenetworkjob.hpp +++ b/llarp/dht/explorenetworkjob.hpp @@ -31,6 +31,29 @@ namespace llarp return false; } + void + ExtractStatus(util::StatusObject &obj) const override + { + std::vector< std::string > foundObjs; + for(const auto &found : valuesFound) + { + foundObjs.emplace_back(found.ToHex()); + } + obj.PutStringArray("found", foundObjs); + + util::StatusObject txownerObj; + txownerObj.PutInt("txid", whoasked.txid); + txownerObj.PutString("node", whoasked.node.ToHex()); + obj.PutObject("whoasked", txownerObj); + + std::vector< std::string > asked; + for(const auto &peer : peersAsked) + asked.emplace_back(peer.ToHex()); + obj.PutStringArray("asked", asked); + + obj.PutString("target", target.ToHex()); + } + void DoNextRequest(const Key_t &) override { diff --git a/llarp/dht/localrouterlookup.cpp b/llarp/dht/localrouterlookup.cpp index 494a0f08e..fe5bcd2dc 100644 --- a/llarp/dht/localrouterlookup.cpp +++ b/llarp/dht/localrouterlookup.cpp @@ -32,6 +32,17 @@ namespace llarp localPath); return; } + if(valuesFound.size()) + { + RouterContact found; + for(const auto &rc : valuesFound) + { + if(rc.OtherIsNewer(found)) + found = rc; + } + valuesFound.clear(); + valuesFound.emplace_back(found); + } routing::DHTMessage msg; msg.M.emplace_back(new GotRouterMessage(parent->OurKey(), whoasked.txid, valuesFound, true)); diff --git a/llarp/dht/node.hpp b/llarp/dht/node.hpp index 3ae1ee0a7..bd5f02937 100644 --- a/llarp/dht/node.hpp +++ b/llarp/dht/node.hpp @@ -9,7 +9,7 @@ namespace llarp { namespace dht { - struct RCNode + struct RCNode : public util::IStateful { RouterContact rc; Key_t ID; @@ -23,6 +23,12 @@ namespace llarp { } + void + ExtractStatus(util::StatusObject& obj) const override + { + obj.PutInt("lastUpdated", rc.last_updated); + } + bool operator<(const RCNode& other) const { @@ -30,7 +36,7 @@ namespace llarp } }; - struct ISNode + struct ISNode : public util::IStateful { service::IntroSet introset; @@ -46,6 +52,24 @@ namespace llarp introset.A.CalculateAddress(ID.as_array()); } + void + ExtractStatus(util::StatusObject& obj) const override + { + obj.PutInt("timestamp", introset.T); + + std::vector< util::StatusObject > introsObjs; + for(const auto intro : introset.I) + { + util::StatusObject introObj; + introObj.PutString("router", intro.router.ToHex()); + introObj.PutInt("expiresAt", intro.expiresAt); + introObj.PutInt("latency", intro.latency); + introObj.PutInt("version", intro.version); + introsObjs.emplace_back(introObj); + } + obj.PutObjectArray("intros", introsObjs); + } + bool operator<(const ISNode& other) const { diff --git a/llarp/dht/publishservicejob.cpp b/llarp/dht/publishservicejob.cpp index 12a9a7752..df86b6f9a 100644 --- a/llarp/dht/publishservicejob.cpp +++ b/llarp/dht/publishservicejob.cpp @@ -31,6 +31,26 @@ namespace llarp return true; } + void + PublishServiceJob::ExtractStatus(util::StatusObject &obj) const + { + obj.PutString("target", I.A.Name()); + obj.PutInt("S", S); + util::StatusObject introsetObj; + I.ExtractStatus(introsetObj); + obj.PutObject("introset", introsetObj); + std::vector< std::string > dontTellObj; + for(const auto &key : dontTell) + dontTellObj.emplace_back(key.ToHex()); + obj.PutStringArray("exclude", dontTellObj); + + util::StatusObject whoaskedTx; + whoaskedTx.PutInt("txid", whoasked.txid); + whoaskedTx.PutString("node", whoasked.node.ToHex()); + + obj.PutObject("whoasked", whoaskedTx); + } + void PublishServiceJob::Start(const TXOwner &peer) { diff --git a/llarp/dht/publishservicejob.hpp b/llarp/dht/publishservicejob.hpp index b69877cbc..cf351fd7c 100644 --- a/llarp/dht/publishservicejob.hpp +++ b/llarp/dht/publishservicejob.hpp @@ -34,6 +34,9 @@ namespace llarp return false; } + void + ExtractStatus(util::StatusObject &obj) const override; + void DoNextRequest(const Key_t &) override { diff --git a/llarp/dht/recursiverouterlookup.hpp b/llarp/dht/recursiverouterlookup.hpp index 5acbbdc06..e143adbb1 100644 --- a/llarp/dht/recursiverouterlookup.hpp +++ b/llarp/dht/recursiverouterlookup.hpp @@ -25,6 +25,31 @@ namespace llarp return false; } + void + ExtractStatus(util::StatusObject &obj) const override + { + std::vector< util::StatusObject > foundObjs; + for(const auto &found : valuesFound) + { + util::StatusObject foundObj; + found.ExtractStatus(foundObj); + foundObjs.emplace_back(foundObj); + } + obj.PutObjectArray("found", foundObjs); + + util::StatusObject txownerObj; + txownerObj.PutInt("txid", whoasked.txid); + txownerObj.PutString("node", whoasked.node.ToHex()); + obj.PutObject("whoasked", txownerObj); + + std::vector< std::string > asked; + for(const auto &peer : peersAsked) + asked.emplace_back(peer.ToHex()); + obj.PutStringArray("asked", asked); + + obj.PutString("target", target.ToHex()); + } + void DoNextRequest(const Key_t &) override { diff --git a/llarp/dht/serviceaddresslookup.cpp b/llarp/dht/serviceaddresslookup.cpp index fa2fa02f9..16308d92d 100644 --- a/llarp/dht/serviceaddresslookup.cpp +++ b/llarp/dht/serviceaddresslookup.cpp @@ -72,24 +72,50 @@ namespace llarp ask); } } - void - ServiceAddressLookup::SendReply() + ServiceAddressLookup::ExtractStatus(util::StatusObject &obj) const { - if(handleResult) + std::vector< util::StatusObject > foundObjs; + for(const auto &found : valuesFound) { - handleResult(valuesFound); + util::StatusObject introsetObj; + found.ExtractStatus(introsetObj); + foundObjs.emplace_back(introsetObj); } + obj.PutObjectArray("found", foundObjs); + + util::StatusObject txownerObj; + txownerObj.PutInt("txid", whoasked.txid); + txownerObj.PutString("node", whoasked.node.ToHex()); + obj.PutObject("whoasked", txownerObj); + + std::vector< std::string > asked; + for(const auto &peer : peersAsked) + asked.emplace_back(peer.ToHex()); + obj.PutStringArray("asked", asked); + + obj.PutString("target", target.ToHex()); + } + + void + ServiceAddressLookup::SendReply() + { // get newest introset if(valuesFound.size()) { llarp::service::IntroSet found; for(const auto &introset : valuesFound) + { if(found.OtherIsNewer(introset)) found = introset; + } valuesFound.clear(); valuesFound.emplace_back(found); } + if(handleResult) + { + handleResult(valuesFound); + } parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage(valuesFound, whoasked.txid)); } diff --git a/llarp/dht/serviceaddresslookup.hpp b/llarp/dht/serviceaddresslookup.hpp index 708eac5d0..062a51cef 100644 --- a/llarp/dht/serviceaddresslookup.hpp +++ b/llarp/dht/serviceaddresslookup.hpp @@ -34,6 +34,9 @@ namespace llarp void DoNextRequest(const Key_t &ask) override; + void + ExtractStatus(util::StatusObject &obj) const override; + virtual void SendReply() override; }; diff --git a/llarp/dht/taglookup.cpp b/llarp/dht/taglookup.cpp index af7760081..63dc9c85e 100644 --- a/llarp/dht/taglookup.cpp +++ b/llarp/dht/taglookup.cpp @@ -30,6 +30,30 @@ namespace llarp new FindIntroMessage(target, peer.txid, R)); } + void + TagLookup::ExtractStatus(util::StatusObject &obj) const + { + std::vector< util::StatusObject > foundObjs; + for(const auto &found : valuesFound) + { + util::StatusObject introsetObj; + found.ExtractStatus(introsetObj); + foundObjs.emplace_back(introsetObj); + } + obj.PutObjectArray("found", foundObjs); + + util::StatusObject txownerObj; + txownerObj.PutInt("txid", whoasked.txid); + txownerObj.PutString("node", whoasked.node.ToHex()); + obj.PutObject("whoasked", txownerObj); + + std::vector< std::string > asked; + for(const auto &peer : peersAsked) + asked.emplace_back(peer.ToHex()); + obj.PutStringArray("asked", asked); + obj.PutString("target", target.ToString()); + } + void TagLookup::SendReply() { diff --git a/llarp/dht/taglookup.hpp b/llarp/dht/taglookup.hpp index e028af7e5..12ae5e2bb 100644 --- a/llarp/dht/taglookup.hpp +++ b/llarp/dht/taglookup.hpp @@ -30,6 +30,9 @@ namespace llarp return false; } + void + ExtractStatus(util::StatusObject &obj) const override; + void DoNextRequest(const Key_t &) override { diff --git a/llarp/dht/tx.hpp b/llarp/dht/tx.hpp index 15c966dfb..598903bea 100644 --- a/llarp/dht/tx.hpp +++ b/llarp/dht/tx.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -15,7 +16,7 @@ namespace llarp struct AbstractContext; template < typename K, typename V > - struct TX + struct TX : public util::IStateful { K target; AbstractContext* parent; @@ -37,6 +38,11 @@ namespace llarp bool AskNextPeer(const Key_t& prevPeer, const std::unique_ptr< Key_t >& next); + virtual void + ExtractStatus(util::StatusObject&) const override + { + } + virtual bool Validate(const V& value) const = 0; diff --git a/llarp/dht/txholder.hpp b/llarp/dht/txholder.hpp index 41107748f..902bdecea 100644 --- a/llarp/dht/txholder.hpp +++ b/llarp/dht/txholder.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -15,7 +16,7 @@ namespace llarp { template < typename K, typename V, typename K_Hash, llarp_time_t requestTimeoutMS = 5000UL > - struct TXHolder + struct TXHolder : public util::IStateful { using TXPtr = std::unique_ptr< TX< K, V > >; // tx who are waiting for a reply for each key @@ -28,6 +29,54 @@ namespace llarp const TX< K, V >* GetPendingLookupFrom(const TXOwner& owner) const; + void + ExtractStatus(util::StatusObject& obj) const override + { + std::vector< util::StatusObject > txObjs, timeoutsObjs, waitingObjs; + { + auto itr = tx.begin(); + while(itr != tx.end()) + { + util::StatusObject txObj, txOwnerObj, txSuperObj; + itr->second->ExtractStatus(txObj); + txOwnerObj.PutInt("txid", itr->first.txid); + txOwnerObj.PutString("node", itr->first.node.ToHex()); + + txSuperObj.PutObject("tx", txObj); + txSuperObj.PutObject("owner", txOwnerObj); + txObjs.emplace_back(txSuperObj); + ++itr; + } + } + obj.PutObjectArray("tx", txObjs); + { + auto itr = timeouts.begin(); + while(itr != timeouts.end()) + { + util::StatusObject timeoutObj; + timeoutObj.PutInt("time", itr->second); + timeoutObj.PutString("target", itr->first.ToHex()); + timeoutsObjs.emplace_back(timeoutObj); + ++itr; + } + } + obj.PutObjectArray("timeouts", timeoutsObjs); + { + auto itr = waiting.begin(); + while(itr != waiting.end()) + { + util::StatusObject waitingObj, txOwnerObj; + txOwnerObj.PutInt("txid", itr->second.txid); + txOwnerObj.PutString("node", itr->second.node.ToHex()); + waitingObj.PutObject("whoasked", txOwnerObj); + waitingObj.PutString("target", itr->first.ToHex()); + waitingObjs.emplace_back(waitingObj); + ++itr; + } + } + obj.PutObjectArray("waiting", waitingObjs); + } + bool HasLookupFor(const K& target) const { diff --git a/llarp/exit/context.cpp b/llarp/exit/context.cpp index 58c331fc0..ee301fd95 100644 --- a/llarp/exit/context.cpp +++ b/llarp/exit/context.cpp @@ -46,6 +46,19 @@ namespace llarp } } + void + Context::ExtractStatus(util::StatusObject& obj) const + { + auto itr = m_Exits.begin(); + while(itr != m_Exits.end()) + { + util::StatusObject sobj; + itr->second->ExtractStatus(sobj); + obj.PutObject(itr->first.c_str(), sobj); + ++itr; + } + } + void Context::CalculateExitTraffic(TrafficStats& stats) { diff --git a/llarp/exit/context.hpp b/llarp/exit/context.hpp index 57d527280..934bc53b5 100644 --- a/llarp/exit/context.hpp +++ b/llarp/exit/context.hpp @@ -11,7 +11,7 @@ namespace llarp namespace exit { /// owner of all the exit endpoints - struct Context + struct Context : public util::IStateful { using Config_t = std::unordered_multimap< std::string, std::string >; @@ -24,6 +24,9 @@ namespace llarp void ClearAllEndpoints(); + void + ExtractStatus(util::StatusObject &obj) const; + /// send close to all exit sessions and remove all sessions void Stop(); diff --git a/llarp/exit/endpoint.cpp b/llarp/exit/endpoint.cpp index 492dac40f..1ac8ff3e9 100644 --- a/llarp/exit/endpoint.cpp +++ b/llarp/exit/endpoint.cpp @@ -31,6 +31,21 @@ namespace llarp m_Parent->RemoveExit(this); } + void + Endpoint::ExtractStatus(util::StatusObject& obj) const + { + obj.PutString("identity", m_remoteSignKey.ToHex()); + obj.PutString("ip", m_IP.ToString()); + obj.PutInt("txRate", m_TxRate); + obj.PutInt("rxRate", m_RxRate); + obj.PutInt("createdAt", createdAt); + auto now = m_Parent->Now(); + obj.PutBool("exiting", !m_RewriteSource); + obj.PutBool("looksDead", LooksDead(now)); + obj.PutBool("expiresSoon", ExpiresSoon(now)); + obj.PutBool("expired", IsExpired(now)); + } + bool Endpoint::UpdateLocalPath(const llarp::PathID_t& nextPath) { diff --git a/llarp/exit/endpoint.hpp b/llarp/exit/endpoint.hpp index 69819b524..691c2bb09 100644 --- a/llarp/exit/endpoint.hpp +++ b/llarp/exit/endpoint.hpp @@ -17,7 +17,7 @@ namespace llarp namespace exit { /// persistant exit state for 1 identity on the exit node - struct Endpoint + struct Endpoint : public util::IStateful { static constexpr size_t MaxUpstreamQueueSize = 256; @@ -31,6 +31,10 @@ namespace llarp void Close(); + /// implement istateful + void + ExtractStatus(util::StatusObject& obj) const override; + /// return true if we are expired right now bool IsExpired(llarp_time_t now) const; diff --git a/llarp/exit/session.cpp b/llarp/exit/session.cpp index e0857830d..863d697cb 100644 --- a/llarp/exit/session.cpp +++ b/llarp/exit/session.cpp @@ -24,6 +24,15 @@ namespace llarp { } + void + BaseSession::ExtractStatus(util::StatusObject& obj) const + { + path::Builder::ExtractStatus(obj); + obj.PutInt("lastExitUse", m_LastUse); + auto pub = m_ExitIdentity.toPublic(); + obj.PutString("exitIdentity", pub.ToString()); + } + bool BaseSession::LoadIdentityFromFile(const char* fname) { diff --git a/llarp/exit/session.hpp b/llarp/exit/session.hpp index d72e78dd4..914983886 100644 --- a/llarp/exit/session.hpp +++ b/llarp/exit/session.hpp @@ -25,6 +25,9 @@ namespace llarp virtual ~BaseSession(); + void + ExtractStatus(util::StatusObject& obj) const override; + bool SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur, size_t hop, llarp::path::PathRole roles) override; diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 5d59908ee..d8d3e4f22 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -42,6 +42,25 @@ namespace llarp { } + void + ExitEndpoint::ExtractStatus(util::StatusObject &obj) const + { + obj.PutBool("permitExit", m_PermitExit); + std::vector< util::StatusObject > activeObjs; + { + auto itr = m_ActiveExits.begin(); + while(itr != m_ActiveExits.end()) + { + util::StatusObject sessionObj; + itr->second->ExtractStatus(sessionObj); + activeObjs.emplace_back(sessionObj); + ++itr; + } + } + obj.PutString("ip", m_IfAddr.ToString()); + obj.PutObjectArray("exitSessions", activeObjs); + } + bool ExitEndpoint::ShouldHookDNSMessage(const dns::Message &msg) const { diff --git a/llarp/handlers/exit.hpp b/llarp/handlers/exit.hpp index ef9cc72af..a202d3828 100644 --- a/llarp/handlers/exit.hpp +++ b/llarp/handlers/exit.hpp @@ -11,7 +11,7 @@ namespace llarp struct Router; namespace handlers { - struct ExitEndpoint : public dns::IQueryHandler + struct ExitEndpoint : public dns::IQueryHandler, public util::IStateful { ExitEndpoint(const std::string& name, Router* r); ~ExitEndpoint(); @@ -25,6 +25,9 @@ namespace llarp std::string Name() const; + void + ExtractStatus(util::StatusObject& obj) const override; + bool ShouldHookDNSMessage(const dns::Message& msg) const override; diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 88110dba9..abb5c16e0 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -53,6 +53,38 @@ namespace llarp tunif.recvpkt = &tunifRecvPkt; } + void + TunEndpoint::ExtractStatus(util::StatusObject &obj) const + { + service::Endpoint::ExtractStatus(obj); + obj.PutString("ifaddr", m_OurRange.ToString()); + + std::vector< std::string > resolvers; + for(const auto &addr : m_UpstreamResolvers) + resolvers.emplace_back(addr.ToString()); + obj.PutStringArray("ustreamResolvers", resolvers); + obj.PutString("localResolver", m_LocalResolverAddr.ToString()); + util::StatusObject ips; + for(const auto &item : m_IPActivity) + { + util::StatusObject ipObj; + ipObj.PutInt("lastActive", item.second); + std::string remoteStr; + AlignedBuffer< 32 > addr = m_IPToAddr.at(item.first); + if(m_SNodes.at(addr)) + remoteStr = RouterID(addr.as_array()).ToString(); + else + remoteStr = service::Address(addr.as_array()).ToString(); + ipObj.PutString("remote", remoteStr); + std::string ipaddr = item.first.ToString(); + ips.PutObject(ipaddr.c_str(), ipObj); + } + obj.PutObject("addrs", ips); + obj.PutString("ourIP", m_OurIP.ToString()); + obj.PutString("nextIP", m_NextIP.ToString()); + obj.PutString("maxIP", m_MaxIP.ToString()); + } + bool TunEndpoint::SetOption(const std::string &k, const std::string &v) { diff --git a/llarp/handlers/tun.hpp b/llarp/handlers/tun.hpp index 500360994..1ac9a3501 100644 --- a/llarp/handlers/tun.hpp +++ b/llarp/handlers/tun.hpp @@ -30,6 +30,9 @@ namespace llarp virtual void Tick(llarp_time_t now) override; + void + ExtractStatus(util::StatusObject& obj) const override; + bool ShouldHookDNSMessage(const dns::Message& msg) const override; diff --git a/llarp/net/net.hpp b/llarp/net/net.hpp index 0d8c6e2f0..20185dae5 100644 --- a/llarp/net/net.hpp +++ b/llarp/net/net.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include // for itoa @@ -71,7 +72,14 @@ namespace llarp friend std::ostream& operator<<(std::ostream& out, const IPRange& a) { - return out << a.addr << "/" << a.netmask_bits; + return out << a.ToString(); + } + + std::string + ToString() const + { + return addr.ToString() + "/" + + std::to_string(llarp::bits::count_bits(netmask_bits.h)); } }; diff --git a/llarp/net/net_int.hpp b/llarp/net/net_int.hpp index c1f81bc98..342df07c8 100644 --- a/llarp/net/net_int.hpp +++ b/llarp/net/net_int.hpp @@ -53,6 +53,15 @@ namespace llarp return out; } + std::string ToString() const + { + uint32_t n = htonl(h); + char tmp[INET_ADDRSTRLEN] = {0}; + if(!inet_ntop(AF_INET, (void*)&n, tmp, sizeof(tmp))) + return ""; + return tmp; + } + struct Hash { inline size_t diff --git a/llarp/path/path.cpp b/llarp/path/path.cpp index 82cc29357..68533d71e 100644 --- a/llarp/path/path.cpp +++ b/llarp/path/path.cpp @@ -155,26 +155,24 @@ namespace llarp IHopHandler* PathContext::GetByUpstream(const RouterID& remote, const PathID_t& id) { - auto own = MapGet( - m_OurPaths, id, - [](__attribute__((unused)) const PathSet* s) -> bool { - // TODO: is this right? - return true; - }, - [remote, id](PathSet* p) -> IHopHandler* { - return p->GetByUpstream(remote, id); - }); + auto own = MapGet(m_OurPaths, id, + [](__attribute__((unused)) const PathSet* s) -> bool { + // TODO: is this right? + return true; + }, + [remote, id](PathSet* p) -> IHopHandler* { + return p->GetByUpstream(remote, id); + }); if(own) return own; - return MapGet( - m_TransitPaths, id, - [remote](const std::shared_ptr< TransitHop >& hop) -> bool { - return hop->info.upstream == remote; - }, - [](const std::shared_ptr< TransitHop >& h) -> IHopHandler* { - return h.get(); - }); + return MapGet(m_TransitPaths, id, + [remote](const std::shared_ptr< TransitHop >& hop) -> bool { + return hop->info.upstream == remote; + }, + [](const std::shared_ptr< TransitHop >& h) -> IHopHandler* { + return h.get(); + }); } bool @@ -191,14 +189,13 @@ namespace llarp IHopHandler* PathContext::GetByDownstream(const RouterID& remote, const PathID_t& id) { - return MapGet( - m_TransitPaths, id, - [remote](const std::shared_ptr< TransitHop >& hop) -> bool { - return hop->info.downstream == remote; - }, - [](const std::shared_ptr< TransitHop >& h) -> IHopHandler* { - return h.get(); - }); + return MapGet(m_TransitPaths, id, + [remote](const std::shared_ptr< TransitHop >& hop) -> bool { + return hop->info.downstream == remote; + }, + [](const std::shared_ptr< TransitHop >& h) -> IHopHandler* { + return h.get(); + }); } PathSet* @@ -438,6 +435,55 @@ namespace llarp _status = st; } + void + Path::ExtractStatus(util::StatusObject& obj) const + { + std::vector< util::StatusObject > subobj; + for(const auto& hop : hops) + { + util::StatusObject hopobj; + hopobj.PutString("txid", hop.txID.ToHex()); + hopobj.PutString("rxid", hop.rxID.ToHex()); + hopobj.PutString("router", hop.rc.pubkey.ToString()); + hopobj.PutInt("lifetime", hop.lifetime); + subobj.emplace_back(hopobj); + } + obj.PutObjectArray("hops", subobj); + + util::StatusObject introObj; + intro.ExtractStatus(introObj); + obj.PutObject("intro", introObj); + + switch(_status) + { + case ePathBuilding: + obj.PutString("status", "building"); + break; + case ePathEstablished: + obj.PutString("status", "established"); + break; + case ePathTimeout: + obj.PutString("status", "timeout"); + break; + case ePathExpired: + obj.PutString("status", "expired"); + break; + default: + obj.PutString("status", "unknown"); + break; + } + obj.PutInt("lastRecvMsg", m_LastRecvMessage); + obj.PutInt("lastLatencyTest", m_LastLatencyTestTime); + obj.PutInt("buildStarted", buildStarted); + obj.PutBool("ready", IsReady()); + obj.PutBool("hasExit", SupportsAnyRoles(ePathRoleExit)); + + auto now = llarp::time_now_ms(); + obj.PutBool("expired", Expired(now)); + obj.PutBool("expiresSoon", ExpiresSoon(now)); + obj.PutInt("expiresAt", ExpireTime()); + } + void Path::Tick(llarp_time_t now, llarp::Router* r) { diff --git a/llarp/path/path.hpp b/llarp/path/path.hpp index 5ab9f0ee1..afc3b0bf7 100644 --- a/llarp/path/path.hpp +++ b/llarp/path/path.hpp @@ -291,7 +291,9 @@ namespace llarp }; /// A path we made - struct Path : public IHopHandler, public llarp::routing::IMessageHandler + struct Path : public IHopHandler, + public llarp::routing::IMessageHandler, + public util::IStateful { using BuildResultHookFunc = std::function< void(Path*) >; using CheckForDeadFunc = std::function< bool(Path*, llarp_time_t) >; @@ -318,6 +320,9 @@ namespace llarp Path(const std::vector< RouterContact >& routers, PathSet* parent, PathRole startingRoles); + void + ExtractStatus(util::StatusObject& obj) const override; + PathRole Role() const { diff --git a/llarp/path/pathbuilder.cpp b/llarp/path/pathbuilder.cpp index daf57aedb..3aca16924 100644 --- a/llarp/path/pathbuilder.cpp +++ b/llarp/path/pathbuilder.cpp @@ -184,6 +184,21 @@ namespace llarp router->paths.RemovePathBuilder(this); } + void + Builder::ExtractStatus(util::StatusObject& obj) const + { + obj.PutInt("keygens", keygens.load()); + obj.PutInt("numHops", numHops); + obj.PutInt("numPaths", m_NumPaths); + std::vector< util::StatusObject > pathObjs; + ForEachPath([&pathObjs](const Path* p) { + util::StatusObject pobj; + p->ExtractStatus(pobj); + pathObjs.emplace_back(pobj); + }); + obj.PutObjectArray("paths", pathObjs); + } + bool Builder::SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur, size_t hop, PathRole roles) diff --git a/llarp/path/pathbuilder.hpp b/llarp/path/pathbuilder.hpp index e8b2c6171..b62aeef68 100644 --- a/llarp/path/pathbuilder.hpp +++ b/llarp/path/pathbuilder.hpp @@ -2,6 +2,8 @@ #define LLARP_PATHBUILDER_HPP_ #include +#include + #include struct llarp_dht_context; @@ -13,7 +15,7 @@ namespace llarp // milliseconds waiting between builds on a path constexpr llarp_time_t MIN_PATH_BUILD_INTERVAL = 5 * 1000; - struct Builder : public PathSet + struct Builder : public PathSet, public util::IStateful { protected: /// flag for PathSet::Stop() @@ -36,6 +38,9 @@ namespace llarp virtual ~Builder(); + virtual void + ExtractStatus(util::StatusObject& obj) const override; + virtual bool SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur, size_t hop, PathRole roles) override; diff --git a/llarp/path/pathset.hpp b/llarp/path/pathset.hpp index 0061d3dbc..50fc644ec 100644 --- a/llarp/path/pathset.hpp +++ b/llarp/path/pathset.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -209,6 +210,18 @@ namespace llarp } } + void + ForEachPath(std::function< void(const Path*) > visit) const + { + Lock_t lock(m_PathsMutex); + auto itr = m_Paths.begin(); + while(itr != m_Paths.end()) + { + visit(itr->second); + ++itr; + } + } + private: using PathInfo_t = std::pair< RouterID, PathID_t >; diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 58afb3b1d..1a840b1e2 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -237,6 +237,18 @@ namespace llarp llarp_dht_context_free(_dht); } + void + Router::ExtractStatus(util::StatusObject &obj) const + { + util::StatusObject dhtObj, exitObj, hsObj; + _dht->impl.ExtractStatus(dhtObj); + obj.PutObject("dht", dhtObj); + hiddenServiceContext.ExtractStatus(hsObj); + obj.PutObject("services", hsObj); + exitContext.ExtractStatus(exitObj); + obj.PutObject("exit", exitObj); + } + bool Router::HandleRecvLinkMessageBuffer(llarp::ILinkSession *session, const llarp_buffer_t &buf) diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 17b96ca44..bc55793d5 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -113,7 +114,7 @@ namespace llarp const std::vector< llarp::RouterContact > &results) = 0; }; - struct Router final : public AbstractRouter + struct Router final : public AbstractRouter, public util::IStateful { bool ready; // transient iwp encryption key @@ -152,6 +153,9 @@ namespace llarp return _dht; } + void + ExtractStatus(util::StatusObject &obj) const override; + Crypto * crypto() const override { diff --git a/llarp/router_contact.cpp b/llarp/router_contact.cpp index c17635136..d22ad37c8 100644 --- a/llarp/router_contact.cpp +++ b/llarp/router_contact.cpp @@ -151,6 +151,16 @@ namespace llarp last_updated = 0; } + void + RouterContact::ExtractStatus(util::StatusObject &obj) const + { + obj.PutInt("lastUpdated", last_updated); + obj.PutBool("exit", IsExit()); + obj.PutBool("publicRouter", IsPublicRouter()); + if(HasNick()) + obj.PutString("nickname", Nick()); + } + bool RouterContact::DecodeKey(const llarp_buffer_t &key, llarp_buffer_t *buf) { diff --git a/llarp/router_contact.hpp b/llarp/router_contact.hpp index e813acc14..2e47fcdf5 100644 --- a/llarp/router_contact.hpp +++ b/llarp/router_contact.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -56,7 +57,7 @@ namespace llarp }; /// RouterContact - struct RouterContact final : public IBEncodeMessage + struct RouterContact final : public IBEncodeMessage, public util::IStateful { /// for unit tests static bool IgnoreBogons; @@ -98,6 +99,9 @@ namespace llarp uint64_t last_updated = 0; + void + ExtractStatus(util::StatusObject &obj) const override; + bool BEncode(llarp_buffer_t *buf) const override; diff --git a/llarp/rpc/rpc.cpp b/llarp/rpc/rpc.cpp index 56254b5f4..8deeef496 100644 --- a/llarp/rpc/rpc.cpp +++ b/llarp/rpc/rpc.cpp @@ -217,6 +217,15 @@ namespace llarp { } + bool + DumpState(Response& resp) const + { + util::StatusObject dump; + router->ExtractStatus(dump); + resp.AddMember("result", dump.Impl, resp.GetAllocator()); + return true; + } + bool ListExitLevels(Response& resp) const { @@ -280,6 +289,10 @@ namespace llarp { return ListExitLevels(response); } + else if(method == "llarp.admin.dumpstate") + { + return DumpState(response); + } return false; } }; diff --git a/llarp/service/Intro.cpp b/llarp/service/Intro.cpp index ab23da307..7c89c87e1 100644 --- a/llarp/service/Intro.cpp +++ b/llarp/service/Intro.cpp @@ -8,6 +8,15 @@ namespace llarp { } + void + Introduction::ExtractStatus(util::StatusObject& obj) const + { + obj.PutString("router", router.ToHex()); + obj.PutInt("expiresAt", expiresAt); + obj.PutInt("latency", latency); + obj.PutInt("version", version); + } + bool Introduction::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) { diff --git a/llarp/service/Intro.hpp b/llarp/service/Intro.hpp index 23c7f91cf..f7973099e 100644 --- a/llarp/service/Intro.hpp +++ b/llarp/service/Intro.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -11,7 +12,8 @@ namespace llarp { namespace service { - struct Introduction final : public llarp::IBEncodeMessage + struct Introduction final : public llarp::IBEncodeMessage, + public util::IStateful { llarp::PubKey router; llarp::PathID_t pathID; @@ -29,6 +31,9 @@ namespace llarp expiresAt = other.expiresAt; } + void + ExtractStatus(util::StatusObject& obj) const override; + bool IsExpired(llarp_time_t now) const { diff --git a/llarp/service/IntroSet.cpp b/llarp/service/IntroSet.cpp index 70964fa68..83b96556f 100644 --- a/llarp/service/IntroSet.cpp +++ b/llarp/service/IntroSet.cpp @@ -12,6 +12,22 @@ namespace llarp delete W; } + void + IntroSet::ExtractStatus(util::StatusObject& obj) const + { + std::vector< util::StatusObject > introsObjs; + for(const auto& intro : I) + { + util::StatusObject introObj; + intro.ExtractStatus(introObj); + introsObjs.emplace_back(introObj); + } + obj.PutObjectArray("intros", introsObjs); + if(!topic.IsZero()) + obj.PutString("topic", topic.ToString()); + obj.PutInt("published", T); + } + bool IntroSet::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) { diff --git a/llarp/service/IntroSet.hpp b/llarp/service/IntroSet.hpp index f781d38a7..4e8584716 100644 --- a/llarp/service/IntroSet.hpp +++ b/llarp/service/IntroSet.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -23,8 +24,12 @@ namespace llarp constexpr std::size_t MAX_INTROSET_SIZE = 4096; // 10 seconds clock skew permitted for introset expiration constexpr llarp_time_t MAX_INTROSET_TIME_DELTA = (10 * 1000); - struct IntroSet final : public llarp::IBEncodeMessage + struct IntroSet final : public llarp::IBEncodeMessage, + public util::IStateful { + void + ExtractStatus(util::StatusObject& obj) const override; + ServiceInfo A; std::vector< Introduction > I; PQPubKey K; diff --git a/llarp/service/context.cpp b/llarp/service/context.cpp index c966431da..ff6b13db8 100644 --- a/llarp/service/context.cpp +++ b/llarp/service/context.cpp @@ -30,6 +30,19 @@ namespace llarp return true; } + void + Context::ExtractStatus(util::StatusObject &obj) const + { + auto itr = m_Endpoints.begin(); + while(itr != m_Endpoints.end()) + { + util::StatusObject sobj; + itr->second->ExtractStatus(sobj); + obj.PutObject(itr->first.c_str(), sobj); + ++itr; + } + } + void Context::ForEachService( std::function< bool(const std::string &, diff --git a/llarp/service/context.hpp b/llarp/service/context.hpp index de002223f..d17ec3d24 100644 --- a/llarp/service/context.hpp +++ b/llarp/service/context.hpp @@ -13,7 +13,7 @@ namespace llarp namespace service { /// holds all the hidden service endpoints we own - struct Context + struct Context : public util::IStateful { Context(llarp::Router *r); ~Context(); @@ -25,6 +25,9 @@ namespace llarp bool StopAll(); + void + ExtractStatus(util::StatusObject &obj) const override; + bool hasEndpoints(); diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 89a8705d0..39cae8233 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -144,6 +144,84 @@ namespace llarp } } + void + Endpoint::ExtractStatus(util::StatusObject& obj) const + { + path::Builder::ExtractStatus(obj); + obj.PutString("identity", m_Identity.pub.Addr().ToString()); + + obj.PutInt("lastPublished", m_LastPublish); + obj.PutInt("lastPublishAttempt", m_LastPublishAttempt); + util::StatusObject introsetObj; + m_IntroSet.ExtractStatus(introsetObj); + obj.PutObject("introset", introsetObj); + + if(!m_Tag.IsZero()) + obj.PutString("tag", m_Tag.ToString()); + + std::vector< util::StatusObject > remoteSessions, deadSessions, + snodeSessions, lookups; + + { + auto itr = m_RemoteSessions.begin(); + while(itr != m_RemoteSessions.end()) + { + util::StatusObject sobj; + itr->second->ExtractStatus(sobj); + remoteSessions.emplace_back(sobj); + ++itr; + } + } + obj.PutObjectArray("remoteSessions", remoteSessions); + { + auto itr = m_DeadSessions.begin(); + while(itr != m_DeadSessions.end()) + { + util::StatusObject sobj; + itr->second->ExtractStatus(sobj); + deadSessions.emplace_back(sobj); + ++itr; + } + } + obj.PutObjectArray("deadSessions", deadSessions); + { + auto itr = m_SNodeSessions.begin(); + while(itr != m_SNodeSessions.end()) + { + util::StatusObject sobj; + itr->second->ExtractStatus(sobj); + snodeSessions.emplace_back(sobj); + ++itr; + } + } + obj.PutObjectArray("snodeSessions", snodeSessions); + { + auto itr = m_PendingLookups.begin(); + while(itr != m_PendingLookups.end()) + { + util::StatusObject sobj; + itr->second->ExtractStatus(sobj); + lookups.emplace_back(sobj); + ++itr; + } + } + obj.PutObjectArray("lookups", lookups); + + util::StatusObject sessionObj; + { + auto itr = m_Sessions.begin(); + while(itr != m_Sessions.end()) + { + util::StatusObject sobj; + itr->second.ExtractStatus(sobj); + std::string k = itr->first.ToHex(); + sessionObj.PutObject(k.c_str(), sobj); + ++itr; + } + } + obj.PutObject("converstations", sessionObj); + } + void Endpoint::Tick(llarp_time_t now) { @@ -233,12 +311,13 @@ namespace llarp continue; std::array< byte_t, 1024 > tmp = {0}; llarp_buffer_t buf(tmp); - if(!SendToServiceOrQueue(introset.A.Addr().data(), buf, - eProtocolText)) - { + if(SendToServiceOrQueue(introset.A.Addr().data(), buf, eProtocolText)) + llarp::LogInfo(Name(), " send message to ", introset.A.Addr(), + " for tag ", tag.ToString()); + else + llarp::LogWarn(Name(), " failed to send/queue data to ", introset.A.Addr(), " for tag ", tag.ToString()); - } } itr->second.Expire(now); if(itr->second.ShouldRefresh(now)) diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index ef2a10051..c2eb74594 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -40,6 +40,9 @@ namespace llarp Endpoint(const std::string& nickname, llarp::Router* r, Context* parent); ~Endpoint(); + virtual void + ExtractStatus(util::StatusObject& obj) const override; + void SetHandler(IDataHandler* h); @@ -532,13 +535,24 @@ namespace llarp /// on initialize functions std::list< std::function< bool(void) > > m_OnInit; - struct Session + struct Session : public util::IStateful { SharedSecret sharedKey; ServiceInfo remote; Introduction intro; llarp_time_t lastUsed = 0; uint64_t seqno = 0; + + void + ExtractStatus(util::StatusObject& obj) const override + { + obj.PutInt("lastUsed", lastUsed); + obj.PutString("remote", remote.Addr().ToString()); + obj.PutInt("seqno", seqno); + util::StatusObject introObj; + intro.ExtractStatus(introObj); + obj.PutObject("intro", introObj); + }; }; /// sessions diff --git a/llarp/service/lookup.hpp b/llarp/service/lookup.hpp index 85497c9aa..e1dadafff 100644 --- a/llarp/service/lookup.hpp +++ b/llarp/service/lookup.hpp @@ -20,7 +20,7 @@ namespace llarp constexpr size_t MaxConcurrentLookups = size_t(4); - struct IServiceLookup + struct IServiceLookup : public util::IStateful { IServiceLookup() = delete; virtual ~IServiceLookup(){}; @@ -55,6 +55,17 @@ namespace llarp const std::string name; RouterID endpoint; + void + ExtractStatus(util::StatusObject& obj) const override + { + auto now = llarp::time_now_ms(); + obj.PutInt("txid", txid); + obj.PutString("endpoint", endpoint.ToHex()); + obj.PutString("name", name); + obj.PutBool("timedOut", IsTimedOut(now)); + obj.PutInt("createdAt", m_created); + } + protected: IServiceLookup(ILookupHolder* parent, uint64_t tx, const std::string& name); diff --git a/llarp/util/status.cpp b/llarp/util/status.cpp new file mode 100644 index 000000000..e472e3780 --- /dev/null +++ b/llarp/util/status.cpp @@ -0,0 +1,128 @@ +#include + +namespace llarp +{ + namespace util + { + StatusObject::StatusObject() + { +#ifdef USE_ABYSS + Impl.SetObject(); +#endif + } + + StatusObject::StatusObject(const StatusObject& other) + { +#ifdef USE_ABYSS + Impl.SetObject(); + Impl.CopyFrom(other.Impl, Impl.GetAllocator()); +#else + (void)other; +#endif + } + + StatusObject::~StatusObject() + { + } + + void + StatusObject::PutBool(const char* name, bool val) + { +#ifdef USE_ABYSS + Value_t v; + v.SetBool(val); + Value_t k(name, Impl.GetAllocator()); + Impl.AddMember(k, v, Impl.GetAllocator()); +#else + (void)name; + (void)val; +#endif + } + + void + StatusObject::PutInt(const char* name, uint64_t val) + { +#ifdef USE_ABYSS + Value_t v; + v.SetInt(val); + Value_t k(name, Impl.GetAllocator()); + Impl.AddMember(k, v, Impl.GetAllocator()); +#else + (void)name; + (void)val; +#endif + } + + void + StatusObject::PutObject(const char* name, const StatusObject& val) + { +#ifdef USE_ABYSS + Value_t v; + v.SetObject(); + v.CopyFrom(val.Impl, Impl.GetAllocator()); + Value_t k(name, Impl.GetAllocator()); + Impl.AddMember(k, v, Impl.GetAllocator()); +#else + (void)name; + (void)val; +#endif + } + + void + StatusObject::PutObjectArray(const char* name, + const std::vector< StatusObject >& arr) + { +#ifdef USE_ABYSS + Value_t v; + v.SetArray(); + for(const auto& obj : arr) + { + Value_t i; + i.SetObject(); + i.CopyFrom(obj.Impl, Impl.GetAllocator()); + v.PushBack(i, Impl.GetAllocator()); + } + Value_t k(name, Impl.GetAllocator()); + Impl.AddMember(k, v, Impl.GetAllocator()); +#else + (void)name; + (void)val; +#endif + } + + void + StatusObject::PutStringArray(const char* name, + const std::vector< std::string >& arr) + { +#ifdef USE_ABYSS + Value_t v; + v.SetArray(); + for(const auto& str : arr) + { + Value_t i; + i.SetString(str.c_str(), Impl.GetAllocator()); + v.PushBack(i, Impl.GetAllocator()); + } + Value_t k(name, Impl.GetAllocator()); + Impl.AddMember(k, v, Impl.GetAllocator()); +#else + (void)name; + (void)val; +#endif + } + + void + StatusObject::PutString(const char* name, const std::string& val) + { +#ifdef USE_ABYSS + Value_t v; + v.SetString(val.c_str(), Impl.GetAllocator()); + Value_t k(name, Impl.GetAllocator()); + Impl.AddMember(k, v, Impl.GetAllocator()); +#else + (void)name; + (void)val; +#endif + } + } // namespace util +} // namespace llarp diff --git a/llarp/util/status.hpp b/llarp/util/status.hpp new file mode 100644 index 000000000..6dd49e9cd --- /dev/null +++ b/llarp/util/status.hpp @@ -0,0 +1,62 @@ +#ifndef LLARP_UTIL_STATUS_HPP +#define LLARP_UTIL_STATUS_HPP +#ifdef USE_ABYSS +#include +#endif +#include + +namespace llarp +{ + namespace util + { +#ifdef USE_ABYSS + using StatusObject_Impl = ::abyss::json::Document; + using Value_t = ::abyss::json::Value; +#else + struct StatusObject_Impl + { + }; +#endif + + struct StatusObject + { + StatusObject(); + ~StatusObject(); + + StatusObject(StatusObject&&) = delete; + StatusObject(const StatusObject& other); + + void + PutInt(const char* name, uint64_t val); + + void + PutString(const char* name, const std::string& val); + + void + PutBool(const char* name, bool val); + + void + PutObject(const char* name, const StatusObject& obj); + + void + PutStringArray(const char* name, const std::vector< std::string >& arr); + + void + PutObjectArray(const char* name, const std::vector< StatusObject >& arr); + + StatusObject_Impl Impl; + }; + + /// an entity that has a status that can be extracted + struct IStateful + { + virtual ~IStateful(){}; + + virtual void + ExtractStatus(StatusObject& state) const = 0; + }; + + } // namespace util +} // namespace llarp + +#endif