diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index bffbe73d..f4e4bfca 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -90,6 +90,7 @@ namespace client m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler; m_MethodHandlers["NetworkSetting"] = &I2PControlHandlers::NetworkSettingHandler; m_MethodHandlers["ClientServicesInfo"] = &I2PControlHandlers::ClientServicesInfoHandler; + m_MethodHandlers["LocalDestinationInfo"] = &I2PControlHandlers::LocalDestinationInfoHandler; // I2PControl m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler; diff --git a/daemon/I2PControlHandlers.cpp b/daemon/I2PControlHandlers.cpp index a04fb930..9430b3ec 100644 --- a/daemon/I2PControlHandlers.cpp +++ b/daemon/I2PControlHandlers.cpp @@ -100,6 +100,53 @@ namespace client ss << "\"" << name << "\":" << buf.str(); } +// LocalDestinationInfo + + void I2PControlHandlers::LocalDestinationInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) + { + auto& addressBook = i2p::client::context.GetAddressBook (); + auto addr = addressBook.GetAddress (params.get ("destination", "")); + auto dest = addr && addr->IsIdentHash () ? + i2p::client::context.FindLocalDestination (addr->identHash) : nullptr; + if (!dest) + { + InsertParam (results, "error", std::string ("destination not found")); + return; + } + InsertParam (results, "destination", addressBook.ToAddress (dest->GetIdentHash ())); + + // arrays are written by hand: write_json makes an array only below the root + results << ",\"leasesets\":["; + bool first = true; + for (const auto& it: dest->GetLeaseSetsList ()) + { + if (!it) continue; + boost::property_tree::ptree ls; + ls.put ("address", addressBook.ToAddress (it->GetIdentHash ())); + ls.put ("type", (int)it->GetStoreType ()); + ls.put ("encType", (int)it->GetEncryptionType ()); + if (!first) results << ","; + first = false; + boost::property_tree::write_json (results, ls, false); + } + results << "],\"streams\":["; + first = true; + for (const auto& it: dest->GetAllStreams ()) + { + if (!it) continue; + auto identity = it->GetRemoteIdentity (); + boost::property_tree::ptree st; + st.put ("id", it->GetRecvStreamID ()); + st.put ("destination", identity ? addressBook.ToAddress (identity->GetIdentHash ()) : ""); + st.put ("sent", it->GetNumSentBytes ()); + st.put ("received", it->GetNumReceivedBytes ()); + if (!first) results << ","; + first = false; + boost::property_tree::write_json (results, st, false); + } + results << "]"; + } + // RouterInfo void I2PControlHandlers::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) diff --git a/daemon/I2PControlHandlers.h b/daemon/I2PControlHandlers.h index ceaae738..ab3341b5 100644 --- a/daemon/I2PControlHandlers.h +++ b/daemon/I2PControlHandlers.h @@ -29,6 +29,7 @@ namespace client void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); + void LocalDestinationInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); protected: diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 742265f4..96d2d094 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1447,13 +1447,9 @@ namespace client { std::vector > ret; if (m_StreamingDestination) - { - for (auto& it: m_StreamingDestination->GetStreams ()) - ret.push_back (it.second); - } + m_StreamingDestination->GetStreamsList (ret); for (auto& it: m_StreamingDestinationsByPorts) - for (auto& it1: it.second->GetStreams ()) - ret.push_back (it1.second); + it.second->GetStreamsList (ret); return ret; } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index ac23f220..986254b5 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -235,6 +236,16 @@ namespace client // for HTTP only int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); }; const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; }; + // copy for other threads, unlike GetLeaseSets which hands out the container itself + std::vector > GetLeaseSetsList () const + { + std::lock_guard lock(m_RemoteLeaseSetsMutex); + std::vector > leaseSets; + leaseSets.reserve (m_RemoteLeaseSets.size ()); + for (const auto& it: m_RemoteLeaseSets) + leaseSets.push_back (it.second); + return leaseSets; + } bool IsEncryptedLeaseSet () const { return m_LeaseSetType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; }; bool IsPerClientAuth () const { return m_AuthType > 0; }; }; diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 47b8431e..4b4e8fea 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -391,6 +392,14 @@ namespace stream // for HTTP only const decltype(m_Streams)& GetStreams () const { return m_Streams; }; + + // copy for other threads, unlike GetStreams which hands out the map itself + void GetStreamsList (std::vector >& streams) + { + std::unique_lock l(m_StreamsMutex); + for (const auto& it: m_Streams) + streams.push_back (it.second); + } }; //-------------------------------------------------