diff --git a/llarp/tooling/router_hive.cpp b/llarp/tooling/router_hive.cpp index 769f0a77b..502e2c903 100644 --- a/llarp/tooling/router_hive.cpp +++ b/llarp/tooling/router_hive.cpp @@ -160,6 +160,17 @@ namespace tooling LogicCall(ctx->logic, [visit, ctx]() { visit(ctx); }); } + llarp::AbstractRouter* + RouterHive::GetRelay(const llarp::RouterID& id) + { + auto itr = relays.find(id); + if (itr == relays.end()) + return nullptr; + + auto ctx = llarp::Context::Get(itr->second); + return ctx->router.get(); + } + std::vector RouterHive::RelayConnectedRelays() { @@ -213,4 +224,55 @@ namespace tooling return results; } + void + RouterHive::ForEachRelayRouter(std::function visit) + { + for (auto [routerId, ctx] : relays) + { + visit(GetRelay(routerId)); + } + } + + void + RouterHive::ForEachClientRouter(std::function visit) + { + for (auto [routerId, ctx] : clients) + { + visit(GetRelay(routerId)); + } + } + + void + RouterHive::ForEachRouterRouter(std::function visit) + { + ForEachRelayRouter(visit); + ForEachClientRouter(visit); + } + + void + RouterHive::ForEachRelayContext(std::function visit) + { + for (auto [routerId, ctx] : relays) + { + VisitRouter(ctx, visit); + } + } + + void + RouterHive::ForEachClientContext(std::function visit) + { + for (auto [routerId, ctx] : clients) + { + VisitRouter(ctx, visit); + } + } + + /// safely visit every router context + void + RouterHive::ForEachRouterContext(std::function visit) + { + ForEachRelayContext(visit); + ForEachClientContext(visit); + } + } // namespace tooling diff --git a/llarp/tooling/router_hive.hpp b/llarp/tooling/router_hive.hpp index 7c547eeea..d88186da3 100644 --- a/llarp/tooling/router_hive.hpp +++ b/llarp/tooling/router_hive.hpp @@ -16,6 +16,7 @@ struct llarp_main; namespace llarp { struct Context; + struct AbstractRouter; } namespace tooling @@ -64,31 +65,23 @@ namespace tooling std::deque GetAllEvents(); + // functions to safely visit each relay and/or client's AbstractRouter or Context void - ForEachRelay(std::function visit) - { - for (auto [routerId, ctx] : relays) - { - VisitRouter(ctx, visit); - } - } + ForEachRelayRouter(std::function visit); + void + ForEachClientRouter(std::function visit); + void + ForEachRouterRouter(std::function visit); void - ForEachClient(std::function visit) - { - for (auto [routerId, ctx] : clients) - { - VisitRouter(ctx, visit); - } - } - - /// safely visit every router context + ForEachRelayContext(std::function visit); void - ForEachRouter(std::function visit) - { - ForEachRelay(visit); - ForEachClient(visit); - } + ForEachClientContext(std::function visit); + void + ForEachRouterContext(std::function visit); + + llarp::AbstractRouter* + GetRelay(const llarp::RouterID& id); std::vector RelayConnectedRelays(); diff --git a/pybind/CMakeLists.txt b/pybind/CMakeLists.txt index e307f67cd..a8706ff50 100644 --- a/pybind/CMakeLists.txt +++ b/pybind/CMakeLists.txt @@ -1,11 +1,13 @@ pybind11_add_module(pyllarp MODULE module.cpp llarp/context.cpp + llarp/router.cpp llarp/router_id.cpp llarp/router_contact.cpp llarp/crypto/types.cpp llarp/config.cpp llarp/logger.cpp + llarp/peerstats.cpp llarp/dht/dht_types.cpp llarp/path/path_types.cpp llarp/path/path_hop_config.cpp diff --git a/pybind/common.hpp b/pybind/common.hpp index 93faecd6e..125944016 100644 --- a/pybind/common.hpp +++ b/pybind/common.hpp @@ -20,6 +20,9 @@ namespace llarp void CryptoTypes_Init(py::module& mod); + void + AbstractRouter_Init(py::module& mod); + void RouterID_Init(py::module& mod); @@ -32,6 +35,12 @@ namespace llarp void PathTypes_Init(py::module& mod); + void + PeerDb_Init(py::module& mod); + + void + PeerStats_Init(py::module& mod); + namespace dht { void diff --git a/pybind/llarp/peerstats.cpp b/pybind/llarp/peerstats.cpp new file mode 100644 index 000000000..eebca2059 --- /dev/null +++ b/pybind/llarp/peerstats.cpp @@ -0,0 +1,40 @@ +#include "common.hpp" +#include "config/config.hpp" +#include "peerstats/peer_db.hpp" +#include "peerstats/types.hpp" + +#include + +namespace llarp +{ + void + PeerDb_Init(py::module& mod) + { + using PeerDb_ptr = std::shared_ptr; + py::class_(mod, "PeerDb") + .def("getCurrentPeerStats", &PeerDb::getCurrentPeerStats); + } + + void + PeerStats_Init(py::module& mod) + { + py::class_(mod, "PeerStats") + .def_readwrite("routerId", &PeerStats::routerId) + .def_readwrite("numConnectionAttempts", &PeerStats::numConnectionAttempts) + .def_readwrite("numConnectionSuccesses", &PeerStats::numConnectionSuccesses) + .def_readwrite("numConnectionRejections", &PeerStats::numConnectionRejections) + .def_readwrite("numConnectionTimeouts", &PeerStats::numConnectionTimeouts) + .def_readwrite("numPathBuilds", &PeerStats::numPathBuilds) + .def_readwrite("numPacketsAttempted", &PeerStats::numPacketsAttempted) + .def_readwrite("numPacketsSent", &PeerStats::numPacketsSent) + .def_readwrite("numPacketsDropped", &PeerStats::numPacketsDropped) + .def_readwrite("numPacketsResent", &PeerStats::numPacketsResent) + .def_readwrite("numDistinctRCsReceived", &PeerStats::numDistinctRCsReceived) + .def_readwrite("numLateRCs", &PeerStats::numLateRCs) + .def_readwrite("peakBandwidthBytesPerSec", &PeerStats::peakBandwidthBytesPerSec) + .def_readwrite("longestRCReceiveInterval", &PeerStats::longestRCReceiveInterval) + .def_readwrite("leastRCRemainingLifetime", &PeerStats::leastRCRemainingLifetime) + .def_readwrite("lastRCUpdated", &PeerStats::lastRCUpdated) + .def_readwrite("stale", &PeerStats::stale); + } +} // namespace llarp diff --git a/pybind/llarp/router.cpp b/pybind/llarp/router.cpp new file mode 100644 index 000000000..7531c27c5 --- /dev/null +++ b/pybind/llarp/router.cpp @@ -0,0 +1,15 @@ +#include "common.hpp" + +#include "router/abstractrouter.hpp" + +namespace llarp +{ + void + AbstractRouter_Init(py::module& mod) + { + py::class_(mod, "AbstractRouter") + .def("rc", &AbstractRouter::rc) + .def("Stop", &AbstractRouter::Stop) + .def("peerDb", &AbstractRouter::peerDb); + } +} // namespace llarp diff --git a/pybind/llarp/router_id.cpp b/pybind/llarp/router_id.cpp index 6c15f8814..a04784d52 100644 --- a/pybind/llarp/router_id.cpp +++ b/pybind/llarp/router_id.cpp @@ -18,8 +18,6 @@ namespace llarp .def("__repr__", &RouterID::ToString) .def("__str__", &RouterID::ToString) .def("ShortString", &RouterID::ShortString) - .def("__eq__", [](const RouterID* const lhs, const RouterID* const rhs) { - return *lhs == *rhs; - }); + .def("__eq__", [](const RouterID& lhs, const RouterID& rhs) { return lhs == rhs; }); } } // namespace llarp diff --git a/pybind/llarp/tooling/router_hive.cpp b/pybind/llarp/tooling/router_hive.cpp index 63f7e6c44..098d46e9b 100644 --- a/pybind/llarp/tooling/router_hive.cpp +++ b/pybind/llarp/tooling/router_hive.cpp @@ -3,7 +3,9 @@ #include "pybind11/iostream.h" #include +#include "router/abstractrouter.hpp" #include "llarp.hpp" + namespace tooling { void @@ -17,12 +19,16 @@ namespace tooling .def("StartRelays", &RouterHive::StartRelays) .def("StartClients", &RouterHive::StartClients) .def("StopAll", &RouterHive::StopRouters) - .def("ForEachRelay", &RouterHive::ForEachRelay) - .def("ForEachClient", &RouterHive::ForEachClient) - .def("ForEachRouter", &RouterHive::ForEachRouter) + .def("ForEachRelayContext", &RouterHive::ForEachRelayContext) + .def("ForEachClientContext", &RouterHive::ForEachClientContext) + .def("ForEachRouterContext", &RouterHive::ForEachRouterContext) + .def("ForEachRelayRouter", &RouterHive::ForEachRelayRouter) + .def("ForEachClientRouter", &RouterHive::ForEachClientRouter) + .def("ForEachRouterRouter", &RouterHive::ForEachRouterRouter) .def("GetNextEvent", &RouterHive::GetNextEvent) .def("GetAllEvents", &RouterHive::GetAllEvents) .def("RelayConnectedRelays", &RouterHive::RelayConnectedRelays) - .def("GetRelayRCs", &RouterHive::GetRelayRCs); + .def("GetRelayRCs", &RouterHive::GetRelayRCs) + .def("GetRelay", &RouterHive::GetRelay); } } // namespace tooling diff --git a/pybind/module.cpp b/pybind/module.cpp index e53894179..aa57fa25a 100644 --- a/pybind/module.cpp +++ b/pybind/module.cpp @@ -5,6 +5,9 @@ PYBIND11_MODULE(pyllarp, m) { tooling::RouterHive_Init(m); tooling::RouterEvent_Init(m); + llarp::AbstractRouter_Init(m); + llarp::PeerDb_Init(m); + llarp::PeerStats_Init(m); llarp::RouterID_Init(m); llarp::RouterContact_Init(m); llarp::CryptoTypes_Init(m); diff --git a/test/hive/test_peer_stats.py b/test/hive/test_peer_stats.py index d618279c0..fd47b656f 100644 --- a/test/hive/test_peer_stats.py +++ b/test/hive/test_peer_stats.py @@ -2,20 +2,23 @@ import pyllarp from time import time def test_peer_stats(HiveForPeerStats): - hive = HiveForPeerStats(n_relays=12, n_clients=0, netid="hive") + + numRelays = 12 + + hive = HiveForPeerStats(n_relays=numRelays, n_clients=0, netid="hive") start_time = time() cur_time = start_time test_duration = 30 #seconds - paths = [] - - print("looking for events...") - + # we track the number of attempted sessions and inbound/outbound established sessions numInbound = 0 numOutbound = 0 numAttempts = 0 + # we pick an arbitrary router out of our routers + someRouterId = None + while cur_time < start_time + test_duration: hive.CollectAllEvents() @@ -32,13 +35,40 @@ def test_peer_stats(HiveForPeerStats): if event_name == "ConnectionAttemptEvent": numAttempts += 1 + if someRouterId is None: + someRouterId = event.remoteId; + hive.events = [] cur_time = time() + # these should be strictly equal, although there is variation because of + # the time we sample print("test duration exceeded") print("in: {} out: {} attempts: {}", numInbound, numOutbound, numAttempts); - assert(numInbound == numOutbound) - assert(numOutbound == numAttempts) + totalReceived = tally_rc_received_for_peer(hive.hive, someRouterId) + + # every router should have received this relay's RC exactly once + print("total times RC received: {} numRelays: {}", totalReceived, numRelays) + assert(totalReceived == numRelays) + +def tally_rc_received_for_peer(hive, routerId): + + numFound = 0 + + def visit(relay): + nonlocal numFound + + peerDb = relay.peerDb() + stats = peerDb.getCurrentPeerStats(routerId); + + assert(stats.routerId == routerId) + + numFound += stats.numDistinctRCsReceived + + hive.ForEachRelayRouter(visit) + + return numFound; + if __name__ == "__main__": main()