From 80a55c5b75dd2a7d4891e331394bc92432474e19 Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Mon, 6 Feb 2023 13:19:41 -0500
Subject: [PATCH] store unrechable in profile

---
 libi2pd/NetDb.cpp     | 14 ++++++++++++--
 libi2pd/Profiling.cpp | 23 ++++++++++++++++++++---
 libi2pd/Profiling.h   | 11 ++++++++---
 3 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp
index c46adff1..02e1c058 100644
--- a/libi2pd/NetDb.cpp
+++ b/libi2pd/NetDb.cpp
@@ -427,7 +427,15 @@ namespace data
 	{
 		auto it = m_RouterInfos.find (ident);
 		if (it != m_RouterInfos.end ())
-			return it->second->SetUnreachable (unreachable);
+		{	
+			it->second->SetUnreachable (unreachable);
+			if (unreachable)
+			{	
+				auto profile = it->second->GetProfile ();
+				if (profile)
+					profile->Unreachable ();
+			}	
+		}	
 	}
 
 	void NetDb::Reseed ()
@@ -626,6 +634,8 @@ namespace data
 				updatedCount++;
 				continue;
 			}
+			if (it.second->GetProfile ()->IsUnreachable ())
+				it.second->SetUnreachable (true);
 			// make router reachable back if too few routers or floodfills
 			if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate ||
 				(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
@@ -1334,7 +1344,7 @@ namespace data
 		std::unique_lock<std::mutex> l(m_FloodfillsMutex);
 		for (const auto& it: m_Floodfills)
 		{
-			if (!it->IsUnreachable ())
+			if (!it->IsUnreachable () && !it->GetProfile ()->IsUnreachable ())
 			{
 				XORMetric m = destKey ^ it->GetIdentHash ();
 				if (m < minMetric && !excluded.count (it->GetIdentHash ()))
diff --git a/libi2pd/Profiling.cpp b/libi2pd/Profiling.cpp
index f826bf43..6f805193 100644
--- a/libi2pd/Profiling.cpp
+++ b/libi2pd/Profiling.cpp
@@ -23,7 +23,7 @@ namespace data
 
 	RouterProfile::RouterProfile ():
 		m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
-		m_LastDeclineTime (0),
+		m_LastDeclineTime (0), m_LastUnreachableTime (0),
 		m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
 		m_NumTimesTaken (0), m_NumTimesRejected (0)
 	{
@@ -52,6 +52,8 @@ namespace data
 		// fill property tree
 		boost::property_tree::ptree pt;
 		pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
+		if (m_LastUnreachableTime)
+			pt.put (PEER_PROFILE_LAST_UNREACHABLE_TIME, m_LastUnreachableTime);
 		pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
 		pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
 
@@ -96,6 +98,7 @@ namespace data
 				m_LastUpdateTime = boost::posix_time::time_from_string (t);
 			if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
 			{
+				m_LastUnreachableTime = pt.get (PEER_PROFILE_LAST_UNREACHABLE_TIME, 0);
 				try
 				{
 					// read participations
@@ -152,6 +155,11 @@ namespace data
 			m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch ();
 	}
 
+	void RouterProfile::Unreachable ()
+	{
+		m_LastUnreachableTime = i2p::util::GetSecondsSinceEpoch ();
+	}	
+		
 	bool RouterProfile::IsLowPartcipationRate () const
 	{
 		return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
@@ -169,12 +177,12 @@ namespace data
 		auto ts = i2p::util::GetSecondsSinceEpoch ();
 		if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL)
 			m_LastDeclineTime = 0;
-		return m_LastDeclineTime;
+		return (bool)m_LastDeclineTime;
 	}	
 		
 	bool RouterProfile::IsBad ()
 	{
-		if (IsDeclinedRecently ()) return true;
+		if (IsDeclinedRecently () || IsUnreachable ()) return true;
 		auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
 		if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
 		{
@@ -188,6 +196,15 @@ namespace data
 		return isBad;
 	}
 
+	bool RouterProfile::IsUnreachable ()
+	{
+		if (!m_LastUnreachableTime) return false;
+		auto ts = i2p::util::GetSecondsSinceEpoch ();
+		if (ts > m_LastUnreachableTime + PEER_PROFILE_UNREACHABLE_INTERVAL)
+			m_LastUnreachableTime = 0;
+		return (bool)m_LastUnreachableTime;
+	}	
+		
 	std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
 	{
 		auto profile = std::make_shared<RouterProfile> ();
diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h
index 1c523a22..58b5e2ea 100644
--- a/libi2pd/Profiling.h
+++ b/libi2pd/Profiling.h
@@ -22,6 +22,7 @@ namespace data
 	const char PEER_PROFILE_SECTION_USAGE[] = "usage";
 	// params
 	const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
+	const char PEER_PROFILE_LAST_UNREACHABLE_TIME[] = "lastunreachabletime";
 	const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
 	const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
 	const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
@@ -32,7 +33,8 @@ namespace data
 	const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 24 * 3600; // in seconds (1 day)
 	const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3 * 3600; // in seconds (3 hours)
 	const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes)
-
+	const int PEER_PROFILE_UNREACHABLE_INTERVAL = 2*3600; // on seconds (2 hours) 
+	
 	class RouterProfile
 	{
 		public:
@@ -44,10 +46,13 @@ namespace data
 			void Load (const IdentHash& identHash);
 
 			bool IsBad ();
-
+			bool IsUnreachable ();
+			
 			void TunnelBuildResponse (uint8_t ret);
 			void TunnelNonReplied ();
 
+			void Unreachable ();
+			
 		private:
 
 			boost::posix_time::ptime GetTime () const;
@@ -61,7 +66,7 @@ namespace data
 		private:
 
 			boost::posix_time::ptime m_LastUpdateTime; // TODO: use std::chrono
-			uint64_t m_LastDeclineTime; // in seconds
+			uint64_t m_LastDeclineTime, m_LastUnreachableTime; // in seconds
 			// participation
 			uint32_t m_NumTunnelsAgreed;
 			uint32_t m_NumTunnelsDeclined;