From 3f10f6651d7b966a23c68621d63389ea35e55839 Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Tue, 29 Oct 2024 12:46:14 -0400
Subject: [PATCH 1/3] use splice if queue is not semi-full

---
 libi2pd/SSU2Session.cpp | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp
index 5d5d5249..aba8195e 100644
--- a/libi2pd/SSU2Session.cpp
+++ b/libi2pd/SSU2Session.cpp
@@ -412,16 +412,24 @@ namespace transport
 					" is semi-full (size = ", m_SendQueue.size (), ", lag = ", queueLag / 1000, ", rtt = ", (int)m_RTT, ")");
 			}
 		}
-		for (auto it: msgs)
-		{
-			if (isSemiFull && it->onDrop)
-				it->Drop (); // drop earlier because we can handle it
-			else
+		if (isSemiFull)
+		{	
+			for (auto it: msgs)
 			{
-				it->SetEnqueueTime (mts);
-				m_SendQueue.push_back (std::move (it));
+				if (it->onDrop)
+					it->Drop (); // drop earlier because we can handle it
+				else
+				{
+					it->SetEnqueueTime (mts);
+					m_SendQueue.push_back (std::move (it));
+				}
 			}
-		}
+		}	
+		else
+		{
+			for (auto& it: msgs) it->SetEnqueueTime (mts);
+			m_SendQueue.splice (m_SendQueue.end (), msgs);
+		}	
 		if (IsEstablished ())
 		{	
 			SendQueue ();

From 8a8277edda0392a3fd99278409b811fc44f9e739 Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Tue, 29 Oct 2024 13:59:21 -0400
Subject: [PATCH 2/3] check for empty URL string

---
 libi2pd/HTTP.cpp               | 1 +
 libi2pd_client/AddressBook.cpp | 9 ++++-----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp
index 990781bc..258d3ada 100644
--- a/libi2pd/HTTP.cpp
+++ b/libi2pd/HTTP.cpp
@@ -103,6 +103,7 @@ namespace http
 
 	bool URL::parse(std::string_view url) 
 	{
+		if (url.empty ()) return false;
 		std::size_t pos_p = 0; /* < current parse position */
 		std::size_t pos_c = 0; /* < work position */
 		if(url.at(0) != '/' || pos_p > 0) 
diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp
index 14599cf7..802b7996 100644
--- a/libi2pd_client/AddressBook.cpp
+++ b/libi2pd_client/AddressBook.cpp
@@ -582,16 +582,15 @@ namespace client
 			}
 			else
 			{
-				LogPrint (eLogInfo, "Addressbook: Loading subscriptions from config file");
+				LogPrint (eLogInfo, "Addressbook: Loading subscriptions from config");
 				// using config file items
 				std::string subscriptionURLs; i2p::config::GetOption("addressbook.subscriptions", subscriptionURLs);
 				std::vector<std::string> subsList;
 				boost::split(subsList, subscriptionURLs, boost::is_any_of(","), boost::token_compress_on);
 
 				for (const auto& s: subsList)
-				{
-					m_Subscriptions.push_back (std::make_shared<AddressBookSubscription> (*this, s));
-				}
+					if (!s.empty ())
+						m_Subscriptions.push_back (std::make_shared<AddressBookSubscription> (*this, s));
 				LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded");
 			}
 		}
@@ -823,7 +822,7 @@ namespace client
 		}
 	}
 
-	AddressBookSubscription::AddressBookSubscription (AddressBook& book, const std::string& link):
+	AddressBookSubscription::AddressBookSubscription (AddressBook& book, std::string_view link):
 		m_Book (book), m_Link (link)
 	{
 	}

From 0086f8e27ad0f4fd702838c4782bb057df74ca77 Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Tue, 29 Oct 2024 15:32:06 -0400
Subject: [PATCH 3/3] use std::async for address book download

---
 libi2pd_client/AddressBook.cpp | 51 +++++++++++++++++++++-------------
 libi2pd_client/AddressBook.h   |  7 +++--
 2 files changed, 36 insertions(+), 22 deletions(-)

diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp
index 802b7996..c9452cc6 100644
--- a/libi2pd_client/AddressBook.cpp
+++ b/libi2pd_client/AddressBook.cpp
@@ -305,7 +305,7 @@ namespace client
 		identHash = hash;
 	}
 
-	AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false),
+	AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false),
 		m_NumRetries (0), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr),
 		m_IsEnabled (true)
 	{
@@ -344,20 +344,28 @@ namespace client
 			delete m_SubscriptionsUpdateTimer;
 			m_SubscriptionsUpdateTimer = nullptr;
 		}
-		if (m_IsDownloading)
+		bool isDownloading = m_Downloading.valid ();
+		if (isDownloading)
 		{
-			LogPrint (eLogInfo, "Addressbook: Subscriptions are downloading, abort");
-			for (int i = 0; i < 30; i++)
-			{
-				if (!m_IsDownloading)
+			if (m_Downloading.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
+				isDownloading = false;
+			else	
+			{	
+				LogPrint (eLogInfo, "Addressbook: Subscriptions are downloading, abort");
+				for (int i = 0; i < 30; i++)
 				{
-					LogPrint (eLogInfo, "Addressbook: Subscriptions download complete");
-					break;
+					if (m_Downloading.wait_for(std::chrono::seconds(1)) == std::future_status::ready) // wait for 1 seconds
+					{
+						isDownloading = false;
+						LogPrint (eLogInfo, "Addressbook: Subscriptions download complete");
+						break;
+					}
 				}
-				std::this_thread::sleep_for (std::chrono::seconds (1)); // wait for 1 seconds
-			}
-			LogPrint (eLogError, "Addressbook: Subscription download timeout");
-			m_IsDownloading = false;
+			}	
+			if (!isDownloading)
+				m_Downloading.get ();
+			else
+				LogPrint (eLogError, "Addressbook: Subscription download timeout");
 		}
 		if (m_Storage)
 		{
@@ -644,7 +652,6 @@ namespace client
 
 	void AddressBook::DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified)
 	{
-		m_IsDownloading = false;
 		m_NumRetries++;
 		int nextUpdateTimeout = m_NumRetries*CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT;
 		if (m_NumRetries > CONTINIOUS_SUBSCRIPTION_MAX_NUM_RETRIES || nextUpdateTimeout > CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT)
@@ -699,7 +706,13 @@ namespace client
 				LogPrint(eLogWarning, "Addressbook: Missing local destination, skip subscription update");
 				return;
 			}
-			if (!m_IsDownloading && dest->IsReady ())
+			bool isDownloading = m_Downloading.valid ();
+			if (isDownloading && m_Downloading.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active?
+			{
+				m_Downloading.get ();
+				isDownloading = false;
+			}	
+			if (!isDownloading && dest->IsReady ())
 			{
 				if (!m_IsLoaded)
 				{
@@ -708,17 +721,15 @@ namespace client
 					std::string defaultSubURL; i2p::config::GetOption("addressbook.defaulturl", defaultSubURL);
 					if (!m_DefaultSubscription)
 						m_DefaultSubscription = std::make_shared<AddressBookSubscription>(*this, defaultSubURL);
-					m_IsDownloading = true;
-					std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription));
-					load_hosts.detach(); // TODO: use join
+					m_Downloading = std::async (std::launch::async,
+						std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription));
 				}
 				else if (!m_Subscriptions.empty ())
 				{
 					// pick random subscription
 					auto ind = rand () % m_Subscriptions.size();
-					m_IsDownloading = true;
-					std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind]));
-					load_hosts.detach(); // TODO: use join
+					m_Downloading = std::async (std::launch::async,
+						std::bind (&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind]));
 				}
 			}
 			else
diff --git a/libi2pd_client/AddressBook.h b/libi2pd_client/AddressBook.h
index fc4f19a7..553ae51b 100644
--- a/libi2pd_client/AddressBook.h
+++ b/libi2pd_client/AddressBook.h
@@ -11,10 +11,12 @@
 
 #include <string.h>
 #include <string>
+#include <string_view>
 #include <map>
 #include <vector>
 #include <iostream>
 #include <mutex>
+#include <future>
 #include <memory>
 #include <boost/asio.hpp>
 #include "Base.h"
@@ -124,7 +126,8 @@ namespace client
 			std::mutex m_LookupsMutex;
 			std::map<uint32_t, std::string> m_Lookups; // nonce -> address
 			AddressBookStorage * m_Storage;
-			volatile bool m_IsLoaded, m_IsDownloading;
+			volatile bool m_IsLoaded;
+			std::future<void> m_Downloading;
 			int m_NumRetries;
 			std::vector<std::shared_ptr<AddressBookSubscription> > m_Subscriptions;
 			std::shared_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet
@@ -136,7 +139,7 @@ namespace client
 	{
 		public:
 
-			AddressBookSubscription (AddressBook& book, const std::string& link);
+			AddressBookSubscription (AddressBook& book, std::string_view link);
 			void CheckUpdates ();
 
 		private: