/ libi2pd / Transports.cpp
Transports.cpp
   1  /*
   2  * Copyright (c) 2013-2026, The PurpleI2P Project
   3  *
   4  * This file is part of Purple i2pd project and licensed under BSD3
   5  *
   6  * See full license text in LICENSE file at top of project tree
   7  */
   8  
   9  #include <boost/algorithm/string.hpp> // for boost::to_lower
  10  #include "Log.h"
  11  #include "Crypto.h"
  12  #include "RouterContext.h"
  13  #include "I2NPProtocol.h"
  14  #include "NetDb.hpp"
  15  #include "Transports.h"
  16  #include "Config.h"
  17  #include "HTTP.h"
  18  #include "util.h"
  19  
  20  using namespace i2p::data;
  21  
  22  namespace i2p
  23  {
  24  namespace transport
  25  {
  26  	template<typename Keys>
  27  	EphemeralKeysSupplier<Keys>::EphemeralKeysSupplier (int size):
  28  		m_QueueSize (size), m_IsRunning (false)
  29  	{
  30  	}
  31  
  32  	template<typename Keys>
  33  	EphemeralKeysSupplier<Keys>::~EphemeralKeysSupplier ()
  34  	{
  35  		Stop ();
  36  	}
  37  
  38  	template<typename Keys>
  39  	void EphemeralKeysSupplier<Keys>::Start ()
  40  	{
  41  		m_IsRunning = true;
  42  		m_Thread.reset (new std::thread (std::bind (&EphemeralKeysSupplier<Keys>::Run, this)));
  43  	}
  44  
  45  	template<typename Keys>
  46  	void EphemeralKeysSupplier<Keys>::Stop ()
  47  	{
  48  		{
  49  			std::unique_lock<std::mutex> l(m_AcquiredMutex);
  50  			m_IsRunning = false;
  51  			m_Acquired.notify_one ();
  52  		}
  53  		if (m_Thread)
  54  		{
  55  			m_Thread->join ();
  56  			m_Thread = nullptr;
  57  		}
  58  		if (!m_Queue.empty ())
  59  		{
  60  			// clean up queue
  61  			std::queue<std::shared_ptr<Keys> > tmp;
  62  	   		std::swap (m_Queue, tmp);
  63  		}
  64  		m_KeysPool.CleanUpMt ();
  65  	}
  66  
  67  	template<typename Keys>
  68  	void EphemeralKeysSupplier<Keys>::Run ()
  69  	{
  70  		i2p::util::SetThreadName("Ephemerals");
  71  
  72  		while (m_IsRunning)
  73  		{
  74  			int num, total = 0;
  75  			while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < m_QueueSize)
  76  			{
  77  				CreateEphemeralKeys (num);
  78  				total += num;
  79  			}
  80  			if (total > m_QueueSize)
  81  			{
  82  				LogPrint (eLogWarning, "Transports: ", total, " ephemeral keys generated at the time");
  83  				std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break
  84  			}
  85  			else
  86  			{
  87  				m_KeysPool.CleanUpMt ();
  88  				std::unique_lock<std::mutex> l(m_AcquiredMutex);
  89  				if (!m_IsRunning) break;
  90  				m_Acquired.wait (l); // wait for element gets acquired
  91  			}
  92  		}
  93  	}
  94  
  95  	template<typename Keys>
  96  	void EphemeralKeysSupplier<Keys>::CreateEphemeralKeys (int num)
  97  	{
  98  		if (num > 0)
  99  		{
 100  			for (int i = 0; i < num; i++)
 101  			{
 102  				auto pair = m_KeysPool.AcquireSharedMt ();
 103  				pair->GenerateKeys ();
 104  				std::unique_lock<std::mutex> l(m_AcquiredMutex);
 105  				m_Queue.push (pair);
 106  			}
 107  		}
 108  	}
 109  
 110  	template<typename Keys>
 111  	std::shared_ptr<Keys> EphemeralKeysSupplier<Keys>::Acquire ()
 112  	{
 113  		{
 114  			std::unique_lock<std::mutex> l(m_AcquiredMutex);
 115  			if (!m_Queue.empty ())
 116  			{
 117  				auto pair = m_Queue.front ();
 118  				m_Queue.pop ();
 119  				m_Acquired.notify_one ();
 120  				return pair;
 121  			}
 122  		}
 123  		// queue is empty, create new
 124  		auto pair = m_KeysPool.AcquireSharedMt ();
 125  		pair->GenerateKeys ();
 126  		return pair;
 127  	}
 128  
 129  	template<typename Keys>
 130  	void EphemeralKeysSupplier<Keys>::Return (std::shared_ptr<Keys> pair)
 131  	{
 132  		if (pair)
 133  		{
 134  			std::unique_lock<std::mutex> l(m_AcquiredMutex);
 135  			if ((int)m_Queue.size () < 2*m_QueueSize)
 136  				m_Queue.push (pair);
 137  		}
 138  		else
 139  			LogPrint(eLogError, "Transports: Return null keys");
 140  	}
 141  
 142  	void Peer::UpdateParams (std::shared_ptr<const i2p::data::RouterInfo> router)
 143  	{
 144  		if (router)
 145  		{
 146  			isHighBandwidth = router->IsHighBandwidth ();
 147  			isEligible =(bool)router->GetCompatibleTransports (true) && // reachable
 148  				router->GetCongestion () < i2p::data::RouterInfo::eHighCongestion && // accepts tunnel and not overloaded
 149  				router->IsECIES () && router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION; // not too old
 150  		}
 151  	}
 152  
 153  	Transports transports;
 154  
 155  	Transports::Transports ():
 156  		m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr),
 157  		m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
 158  		m_UpdateBandwidthTimer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr),
 159  		m_X25519KeysPairSupplier (NUM_X25519_PRE_GENERATED_KEYS),
 160  		m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0),
 161  		m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0),
 162  		m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0),
 163  		m_InBandwidth5m (0), m_OutBandwidth5m (0), m_TransitBandwidth5m (0),
 164  		m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL)
 165  	{
 166  	}
 167  
 168  	Transports::~Transports ()
 169  	{
 170  		Stop ();
 171  		if (m_Service)
 172  		{
 173  			delete m_PeerCleanupTimer; m_PeerCleanupTimer = nullptr;
 174  			delete m_PeerTestTimer; m_PeerTestTimer = nullptr;
 175  			delete m_UpdateBandwidthTimer; m_UpdateBandwidthTimer = nullptr;
 176  			delete m_Work; m_Work = nullptr;
 177  			delete m_Service; m_Service = nullptr;
 178  		}
 179  	}
 180  
 181  	void Transports::Start (bool enableNTCP2, bool enableSSU2)
 182  	{
 183  		if (!m_Service)
 184  		{
 185  			m_Service = new boost::asio::io_context ();
 186  			m_Work = new boost::asio::executor_work_guard<boost::asio::io_context::executor_type> (m_Service->get_executor ());
 187  			m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service);
 188  			m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
 189  			m_UpdateBandwidthTimer = new boost::asio::deadline_timer (*m_Service);
 190  			m_BanListCleanupTimer = std::make_unique<boost::asio::steady_timer>(*m_Service);
 191  		}
 192  
 193  		bool ipv4; i2p::config::GetOption("ipv4", ipv4);
 194  		bool ipv6; i2p::config::GetOption("ipv6", ipv6);
 195  		i2p::config::GetOption("nat", m_IsNAT);
 196  		m_X25519KeysPairSupplier.Start ();
 197  		m_IsRunning = true;
 198  		m_Thread = new std::thread (std::bind (&Transports::Run, this));
 199  		std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
 200          int ntcp2version = 2;
 201  #if OPENSSL_PQ
 202          i2p::config::GetOption("ntcp2.version", ntcp2version);
 203  #endif
 204  		i2p::http::URL proxyurl;
 205  		// create NTCP2. TODO: move to acceptor
 206  		if (enableNTCP2 || i2p::context.SupportsMesh ())
 207  		{
 208  			if(!ntcp2proxy.empty() && enableNTCP2)
 209  			{
 210  				if(proxyurl.parse(ntcp2proxy))
 211  				{
 212  					if(proxyurl.schema == "socks" || proxyurl.schema == "http")
 213  					{
 214  						m_NTCP2Server = new NTCP2Server ();
 215  						NTCP2Server::ProxyType proxytype = NTCP2Server::eSocksProxy;
 216  
 217  						if (proxyurl.schema == "http")
 218  							proxytype = NTCP2Server::eHTTPProxy;
 219  
 220  						m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port, proxyurl.user, proxyurl.pass);
 221  						i2p::context.SetStatus (eRouterStatusProxy);
 222  						if (ipv6)
 223  							i2p::context.SetStatusV6 (eRouterStatusProxy);
 224  					}
 225  					else
 226  						LogPrint(eLogCritical, "Transports: Unsupported NTCP2 proxy URL ", ntcp2proxy);
 227  				}
 228  				else
 229  					LogPrint(eLogCritical, "Transports: Invalid NTCP2 proxy URL ", ntcp2proxy);
 230  			}
 231  			else
 232  				m_NTCP2Server = new NTCP2Server ();
 233  			m_NTCP2Server->SetVersion (ntcp2version);
 234  		}
 235  
 236  		// create SSU2 server
 237  		if (enableSSU2)
 238  		{
 239  			m_SSU2Server = new SSU2Server ();
 240  			std::string ssu2proxy; i2p::config::GetOption("ssu2.proxy", ssu2proxy);
 241  			if (!ssu2proxy.empty())
 242  			{
 243  				if (proxyurl.parse (ssu2proxy) && proxyurl.schema == "socks")
 244  				{
 245  					if (m_SSU2Server->SetProxy (proxyurl.host, proxyurl.port))
 246  					{
 247  						i2p::context.SetStatus (eRouterStatusProxy);
 248  						if (ipv6)
 249  							i2p::context.SetStatusV6 (eRouterStatusProxy);
 250  					}
 251  					else
 252  						LogPrint(eLogCritical, "Transports: Can't set SSU2 proxy ", ssu2proxy);
 253  				}
 254  				else
 255  					LogPrint(eLogCritical, "Transports: Invalid SSU2 proxy URL ", ssu2proxy);
 256  			}
 257  		}
 258  
 259  		// bind to interfaces
 260  		if (ipv4)
 261  		{
 262  			std::string address; i2p::config::GetOption("address4", address);
 263  			if (!address.empty ())
 264  			{
 265  				boost::system::error_code ec;
 266  				auto addr = boost::asio::ip::make_address (address, ec);
 267  				if (!ec)
 268  				{
 269  					if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
 270  					if (m_SSU2Server) m_SSU2Server->SetLocalAddress (addr);
 271  				}
 272  			}
 273  
 274  			if (enableSSU2)
 275  			{
 276  				uint16_t mtu; i2p::config::GetOption ("ssu2.mtu4", mtu);
 277  				if (mtu)
 278  				{
 279  					if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
 280  					if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE;
 281  					i2p::context.SetMTU (mtu, true);
 282  				}
 283  			}
 284  		}
 285  
 286  		if (ipv6)
 287  		{
 288  			std::string address; i2p::config::GetOption("address6", address);
 289  			if (!address.empty ())
 290  			{
 291  				boost::system::error_code ec;
 292  				auto addr = boost::asio::ip::make_address (address, ec);
 293  				if (!ec)
 294  				{
 295  					if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
 296  					if (m_SSU2Server) m_SSU2Server->SetLocalAddress (addr);
 297  				}
 298  			}
 299  
 300  			if (enableSSU2)
 301  			{
 302  				uint16_t mtu; i2p::config::GetOption ("ssu2.mtu6", mtu);
 303  				if (mtu)
 304  				{
 305  					if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
 306  					if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE;
 307  					i2p::context.SetMTU (mtu, false);
 308  				}
 309  			}
 310  		}
 311  
 312  		bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
 313  		if (ygg)
 314  		{
 315  			std::string address; i2p::config::GetOption("meshnets.yggaddress", address);
 316  			if (!address.empty ())
 317  			{
 318  				boost::system::error_code ec;
 319  				auto addr = boost::asio::ip::make_address (address, ec);
 320  				if (!ec && m_NTCP2Server && i2p::util::net::IsYggdrasilAddress (addr))
 321  					m_NTCP2Server->SetLocalAddress (addr);
 322  			}
 323  		}
 324  
 325  		// start servers
 326  		if (m_NTCP2Server) m_NTCP2Server->Start ();
 327  		if (m_SSU2Server) m_SSU2Server->Start ();
 328  		if (m_SSU2Server) DetectExternalIP ();
 329  
 330  		m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5 * SESSION_CREATION_TIMEOUT));
 331  		m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
 332  
 333  		uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
 334  		for (int i = 0; i < TRAFFIC_SAMPLE_COUNT; i++)
 335  		{
 336  			m_TrafficSamples[i].Timestamp = ts - (TRAFFIC_SAMPLE_COUNT - i - 1) * 1000;
 337  			m_TrafficSamples[i].TotalReceivedBytes = 0;
 338  			m_TrafficSamples[i].TotalSentBytes = 0;
 339  			m_TrafficSamples[i].TotalTransitTransmittedBytes = 0;
 340  		}
 341  		m_TrafficSamplePtr = TRAFFIC_SAMPLE_COUNT - 1;
 342  
 343  		m_UpdateBandwidthTimer->expires_from_now (boost::posix_time::seconds(1));
 344  		m_UpdateBandwidthTimer->async_wait (std::bind (&Transports::HandleUpdateBandwidthTimer, this, std::placeholders::_1));
 345  
 346  		if (m_IsNAT)
 347  		{
 348  			m_PeerTestTimer->expires_from_now (boost::posix_time::seconds(PEER_TEST_INTERVAL + m_Rng() % PEER_TEST_INTERVAL_VARIANCE));
 349  			m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
 350  		}
 351  		m_BanListCleanupTimer->expires_after (std::chrono::seconds(BAN_LIST_CLEANUP_INTERVAL + m_Rng () % BAN_LIST_CLEANUP_INTERVAL_VARIANCE));
 352  		m_BanListCleanupTimer->async_wait (std::bind (&Transports::HandleBanListCleanupTimer, this, std::placeholders::_1));
 353  	}
 354  
 355  	void Transports::Stop ()
 356  	{
 357  		if (m_PeerCleanupTimer) m_PeerCleanupTimer->cancel ();
 358  		if (m_PeerTestTimer) m_PeerTestTimer->cancel ();
 359  		if (m_BanListCleanupTimer) m_BanListCleanupTimer->cancel ();
 360  
 361  		if (m_SSU2Server)
 362  		{
 363  			m_SSU2Server->Stop ();
 364  			delete m_SSU2Server;
 365  			m_SSU2Server = nullptr;
 366  		}
 367  
 368  		if (m_NTCP2Server)
 369  		{
 370  			m_NTCP2Server->Stop ();
 371  			delete m_NTCP2Server;
 372  			m_NTCP2Server = nullptr;
 373  		}
 374  
 375  		m_X25519KeysPairSupplier.Stop ();
 376  		m_IsRunning = false;
 377  		if (m_Service) m_Service->stop ();
 378  		if (m_Thread)
 379  		{
 380  			m_Thread->join ();
 381  			delete m_Thread;
 382  			m_Thread = nullptr;
 383  		}
 384  		m_Peers.clear ();
 385  	}
 386  
 387  	void Transports::Run ()
 388  	{
 389  		i2p::util::SetThreadName("Transports");
 390  
 391  		while (m_IsRunning && m_Service)
 392  		{
 393  			try
 394  			{
 395  				m_Service->run ();
 396  			}
 397  			catch (std::exception& ex)
 398  			{
 399  				LogPrint (eLogError, "Transports: Runtime exception: ", ex.what ());
 400  			}
 401  		}
 402  	}
 403  
 404  	void Transports::UpdateBandwidthValues(int interval, uint32_t& in, uint32_t& out, uint32_t& transit)
 405  	{
 406  		TrafficSample& sample1 = m_TrafficSamples[m_TrafficSamplePtr];
 407  		TrafficSample& sample2 = m_TrafficSamples[(TRAFFIC_SAMPLE_COUNT + m_TrafficSamplePtr - interval) % TRAFFIC_SAMPLE_COUNT];
 408  		auto delta = (int64_t)sample1.Timestamp - (int64_t)sample2.Timestamp;
 409  		if (delta <= 0)
 410  		{
 411  			LogPrint (eLogError, "Transports: Backward clock jump detected, got ", delta, " instead of ", interval * 1000);
 412  			return;
 413  		}
 414  		in = (sample1.TotalReceivedBytes - sample2.TotalReceivedBytes) * 1000 / delta;
 415  		out = (sample1.TotalSentBytes - sample2.TotalSentBytes) * 1000 / delta;
 416  		transit = (sample1.TotalTransitTransmittedBytes - sample2.TotalTransitTransmittedBytes) * 1000 / delta;
 417  	}
 418  
 419  	void Transports::HandleUpdateBandwidthTimer (const boost::system::error_code& ecode)
 420  	{
 421  		if (ecode != boost::asio::error::operation_aborted)
 422  		{
 423  			m_TrafficSamplePtr++;
 424  			if (m_TrafficSamplePtr == TRAFFIC_SAMPLE_COUNT)
 425  				m_TrafficSamplePtr = 0;
 426  
 427  			TrafficSample& sample = m_TrafficSamples[m_TrafficSamplePtr];
 428  			sample.Timestamp = i2p::util::GetMillisecondsSinceEpoch();
 429  			sample.TotalReceivedBytes = m_TotalReceivedBytes;
 430  			sample.TotalSentBytes = m_TotalSentBytes;
 431  			sample.TotalTransitTransmittedBytes = m_TotalTransitTransmittedBytes;
 432  
 433  			UpdateBandwidthValues (1, m_InBandwidth, m_OutBandwidth, m_TransitBandwidth);
 434  			UpdateBandwidthValues (15, m_InBandwidth15s, m_OutBandwidth15s, m_TransitBandwidth15s);
 435  			UpdateBandwidthValues (300, m_InBandwidth5m, m_OutBandwidth5m, m_TransitBandwidth5m);
 436  
 437  			m_UpdateBandwidthTimer->expires_from_now (boost::posix_time::seconds(1));
 438  			m_UpdateBandwidthTimer->async_wait (std::bind (&Transports::HandleUpdateBandwidthTimer, this, std::placeholders::_1));
 439  		}
 440  	}
 441  
 442  	int Transports::GetCongestionLevel (bool longTerm) const
 443  	{
 444  		auto bwLimit = i2p::context.GetBandwidthLimit () * 1024; // convert to bytes
 445  		auto tbwLimit = i2p::context.GetTransitBandwidthLimit () * 1024; // convert to bytes
 446  
 447  		if (tbwLimit == 0 || bwLimit == 0)
 448  			return CONGESTION_LEVEL_FULL;
 449  
 450  		uint32_t bw;
 451  		uint32_t tbw;
 452  		if (longTerm)
 453  		{
 454  			bw = std::max (m_InBandwidth5m, m_OutBandwidth5m);
 455  			tbw = m_TransitBandwidth5m;
 456  		}
 457  		else
 458  		{
 459  			bw = std::max (m_InBandwidth15s, m_OutBandwidth15s);
 460  			tbw = m_TransitBandwidth;
 461  		}
 462  		auto bwCongestionLevel = CONGESTION_LEVEL_FULL * bw / bwLimit;
 463  		auto tbwCongestionLevel = CONGESTION_LEVEL_FULL * tbw / tbwLimit;
 464  		return std::max (bwCongestionLevel, tbwCongestionLevel);
 465  	}
 466  
 467  	std::future<std::shared_ptr<TransportSession> > Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
 468  	{
 469  		if (m_IsOnline)
 470  			return SendMessages (ident, { msg });
 471  		return {}; // invalid future
 472  	}
 473  
 474  	std::future<std::shared_ptr<TransportSession> > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs)
 475  	{
 476  		return boost::asio::post (*m_Service, boost::asio::use_future ([this, ident, msgs = std::move(msgs)] () mutable
 477  			{
 478  				return PostMessages (ident, msgs);
 479  			}));
 480  	}
 481  
 482  	std::shared_ptr<TransportSession> Transports::PostMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
 483  	{
 484  		if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
 485  		{
 486  			// we send it to ourself
 487  			for (auto& it: msgs)
 488  				m_LoopbackHandler.PutNextMessage (std::move (it));
 489  			m_LoopbackHandler.Flush ();
 490  			return nullptr;
 491  		}
 492  		if(RoutesRestricted() && !IsRestrictedPeer(ident)) return nullptr;
 493  		std::shared_ptr<Peer> peer;
 494  		{
 495  			std::lock_guard<std::mutex> l(m_PeersMutex);
 496  			auto it = m_Peers.find (ident);
 497  			if (it != m_Peers.end ())
 498  				peer = it->second;
 499  		}
 500  		if (!peer)
 501  		{
 502  			// check if not banned
 503  			if (i2p::data::IsRouterBanned (ident)) return nullptr; // don't create peer to unreachable router
 504  			// try to connect
 505  			bool connected = false;
 506  			try
 507  			{
 508  				auto r = netdb.FindRouter (ident);
 509  				if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()) ||
 510  					(r->GetVersion () < i2p::data::NETDB_MIN_ALLOWED_VERSION && !r->IsHighBandwidth ())))
 511  					return nullptr; // router found but non-reachable or too old
 512  
 513  				peer = std::make_shared<Peer>(r, i2p::util::GetSecondsSinceEpoch ());
 514  				{
 515  					std::lock_guard<std::mutex> l(m_PeersMutex);
 516  					peer = m_Peers.emplace (ident, peer).first->second;
 517  				}
 518  				if (peer)
 519  					connected = ConnectToPeer (ident, peer);
 520  			}
 521  			catch (std::exception& ex)
 522  			{
 523  				LogPrint (eLogError, "Transports: PostMessages exception:", ex.what ());
 524  			}
 525  			if (!connected) return nullptr;
 526  		}
 527  
 528  		if (!peer) return nullptr;
 529  		if (peer->IsConnected ())
 530  		{
 531  			auto session = peer->sessions.front ();
 532  			if (session) session->SendI2NPMessages (msgs);
 533  			return session;
 534  		}
 535  		else
 536  		{
 537  			auto sz = peer->delayedMessages.size ();
 538  			if (sz < MAX_NUM_DELAYED_MESSAGES)
 539  			{
 540  				if (sz < CHECK_PROFILE_NUM_DELAYED_MESSAGES && sz + msgs.size () >= CHECK_PROFILE_NUM_DELAYED_MESSAGES)
 541  				{
 542  					if (i2p::data::IsRouterBanned (ident))
 543  					{
 544  						LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
 545  						std::lock_guard<std::mutex> l(m_PeersMutex);
 546  						m_Peers.erase (ident);
 547  						return nullptr;
 548  					}
 549  				}
 550  				if (sz > MAX_NUM_DELAYED_MESSAGES/2)
 551  				{
 552  					for (auto& it1: msgs)
 553  						if (it1->onDrop)
 554  							it1->Drop (); // drop earlier because we can handle it
 555  						else
 556  							peer->delayedMessages.push_back (it1);
 557  				}
 558  				else
 559  					peer->delayedMessages.splice (peer->delayedMessages.end (), msgs);
 560  			}
 561  			else
 562  			{
 563  				LogPrint (eLogWarning, "Transports: Delayed messages queue size to ",
 564  					ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES);
 565  				std::lock_guard<std::mutex> l(m_PeersMutex);
 566  				m_Peers.erase (ident);
 567  			}
 568  		}
 569  		return nullptr;
 570  	}
 571  
 572  	bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr<Peer> peer)
 573  	{
 574  		if (!peer->router) // reconnect
 575  		{
 576  			auto r = netdb.FindRouter (ident); // try to get new one from netdb
 577  			if (r)
 578  			{
 579  				peer->SetRouter (r);
 580  				r->CancelBufferToDelete ();
 581  			}
 582  		}
 583  		if (peer->router) // we have RI already
 584  		{
 585  			if (peer->priority.empty ())
 586  				SetPriority (peer);
 587  			while (peer->numAttempts < (int)peer->priority.size ())
 588  			{
 589  				auto tr = peer->priority[peer->numAttempts];
 590  				peer->numAttempts++;
 591  				switch (tr)
 592  				{
 593  					case i2p::data::RouterInfo::eNTCP2V4:
 594  					case i2p::data::RouterInfo::eNTCP2V6:
 595  					{
 596  						if (!m_NTCP2Server) continue;
 597  						std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eNTCP2V6) ?
 598  							peer->router->GetPublishedNTCP2V6Address () : peer->router->GetPublishedNTCP2V4Address ();
 599  						if (address && IsInReservedRange(address->host))
 600  							address = nullptr;
 601  						if (address)
 602  						{
 603  							auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer->router, address);
 604  							if( m_NTCP2Server->UsingProxy())
 605  								m_NTCP2Server->ConnectWithProxy(s);
 606  							else
 607  								m_NTCP2Server->Connect (s);
 608  							return true;
 609  						}
 610  						break;
 611  					}
 612  					case i2p::data::RouterInfo::eSSU2V4:
 613  					case i2p::data::RouterInfo::eSSU2V6:
 614  					{
 615  						if (!m_SSU2Server) continue;
 616  						std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eSSU2V6) ?
 617  							peer->router->GetSSU2V6Address () : peer->router->GetSSU2V4Address ();
 618  						if (address && IsInReservedRange(address->host))
 619  							address = nullptr;
 620  						if (address && address->IsReachableSSU ())
 621  						{
 622  							if (m_SSU2Server->CreateSession (peer->router, address))
 623  								return true;
 624  						}
 625  						break;
 626  					}
 627  					case i2p::data::RouterInfo::eNTCP2V6Mesh:
 628  					{
 629  						if (!m_NTCP2Server) continue;
 630  						auto address = peer->router->GetYggdrasilAddress ();
 631  						if (address)
 632  						{
 633  							auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer->router, address);
 634  							m_NTCP2Server->Connect (s);
 635  							return true;
 636  						}
 637  						break;
 638  					}
 639  					default:
 640  						LogPrint (eLogError, "Transports: Unknown transport ", (int)tr);
 641  				}
 642  			}
 643  
 644  			LogPrint (eLogInfo, "Transports: No compatible addresses available");
 645  			if (!i2p::context.IsLimitedConnectivity () && peer->router->IsReachableFrom (i2p::context.GetRouterInfo ()))
 646  				i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them
 647  			peer->Done ();
 648  			std::lock_guard<std::mutex> l(m_PeersMutex);
 649  			m_Peers.erase (ident);
 650  			return false;
 651  		}
 652  		else if (i2p::data::IsRouterBanned (ident))
 653  		{
 654  			LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
 655  			peer->Done ();
 656  			std::lock_guard<std::mutex> l(m_PeersMutex);
 657  			m_Peers.erase (ident);
 658  			return false;
 659  		}
 660  		else // otherwise request RI
 661  		{
 662  			LogPrint (eLogInfo, "Transports: RouterInfo for ", ident.ToBase64 (), " not found, requested");
 663  			i2p::data::netdb.RequestDestination (ident, std::bind (
 664  				&Transports::RequestComplete, this, std::placeholders::_1, ident));
 665  		}
 666  		return true;
 667  	}
 668  
 669  	void Transports::SetPriority (std::shared_ptr<Peer> peer)
 670  	{
 671  		static constexpr std::array
 672  			ntcp2Priority =
 673  		{
 674  			i2p::data::RouterInfo::eNTCP2V6,
 675  			i2p::data::RouterInfo::eNTCP2V4,
 676  			i2p::data::RouterInfo::eSSU2V6,
 677  			i2p::data::RouterInfo::eSSU2V4,
 678  			i2p::data::RouterInfo::eNTCP2V6Mesh
 679  		},
 680  			ssu2Priority =
 681  		{
 682  			i2p::data::RouterInfo::eSSU2V6,
 683  			i2p::data::RouterInfo::eSSU2V4,
 684  			i2p::data::RouterInfo::eNTCP2V6,
 685  			i2p::data::RouterInfo::eNTCP2V4,
 686  			i2p::data::RouterInfo::eNTCP2V6Mesh
 687  		};
 688  		if (!peer || !peer->router) return;
 689  		auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) &
 690  			peer->router->GetCompatibleTransports (true);
 691  		auto directTransports = compatibleTransports & peer->router->GetPublishedTransports ();
 692  		peer->numAttempts = 0;
 693  		peer->priority.clear ();
 694  
 695  		std::shared_ptr<RouterProfile> profile;
 696  		if (peer->router->HasProfile ()) profile = peer->router->GetProfile (); // only if in memory
 697  		bool ssu2 = false; // NTCP2 by default
 698  		bool isReal = profile ? profile->IsReal () : true;
 699  		if (isReal)
 700  		{
 701  			ssu2 = m_Rng () & 1; // 1/2
 702  			if (ssu2 && !profile)
 703  			{
 704  				profile = peer->router->GetProfile (); // load profile if necessary
 705  				isReal = profile->IsReal ();
 706  				if (!isReal) ssu2 = false; // try NTCP2 if router is not confirmed real
 707  			}
 708  		}
 709  		const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority;
 710  		if (directTransports)
 711  		{
 712  			// direct connections have higher priority
 713  			if (!isReal && (directTransports & (i2p::data::RouterInfo::eNTCP2V4 | i2p::data::RouterInfo::eNTCP2V6)))
 714  			{
 715  				// Non-confirmed router and a NTCP2 direct connection is presented
 716  				compatibleTransports &= ~directTransports; // exclude SSU2 direct connections
 717  				directTransports &= ~(i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6);
 718  			}
 719  			for (auto transport: priority)
 720  				if (transport & directTransports)
 721  					peer->priority.push_back (transport);
 722  			compatibleTransports &= ~directTransports;
 723  		}
 724  		if (compatibleTransports)
 725  		{
 726  			// then remaining
 727  			for (auto transport: priority)
 728  				if (transport & compatibleTransports)
 729  					peer->priority.push_back (transport);
 730  		}
 731  		if (peer->priority.empty ())
 732  		{
 733  			// try recently connected SSU2 if any
 734  			auto supportedTransports = context.GetRouterInfo ().GetCompatibleTransports (false) &
 735  				peer->router->GetCompatibleTransports (false);
 736  			if ((supportedTransports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)) &&
 737  			    peer->router->HasProfile ())
 738  			{
 739  				auto ep = peer->router->GetProfile ()->GetLastEndpoint ();
 740  				if (!ep.address ().is_unspecified () && ep.port ())
 741  				{
 742  					if (ep.address ().is_v4 ())
 743  					{
 744  						if ((supportedTransports & i2p::data::RouterInfo::eSSU2V4) &&
 745  							m_SSU2Server->IsConnectedRecently (ep, false))
 746  							peer->priority.push_back (i2p::data::RouterInfo::eSSU2V4);
 747  					}
 748  					else if (ep.address ().is_v6 ())
 749  					{
 750  						if ((supportedTransports & i2p::data::RouterInfo::eSSU2V6) &&
 751  							m_SSU2Server->IsConnectedRecently (ep))
 752  							peer->priority.push_back (i2p::data::RouterInfo::eSSU2V6);
 753  					}
 754  				}
 755  			}
 756  		}
 757  	}
 758  
 759  	void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
 760  	{
 761  		boost::asio::post (*m_Service, std::bind (&Transports::HandleRequestComplete, this, r, ident));
 762  	}
 763  
 764  	void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident)
 765  	{
 766  		std::shared_ptr<Peer> peer;
 767  		{
 768  			std::lock_guard<std::mutex> l(m_PeersMutex);
 769  			auto it = m_Peers.find (ident);
 770  			if (it != m_Peers.end ())
 771  			{
 772  				if (r)
 773  					peer = it->second;
 774  				else
 775  					m_Peers.erase (it);
 776  			}
 777  		}
 778  
 779  		if (peer && !peer->router && r)
 780  		{
 781  			LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
 782  			peer->SetRouter (r);
 783  			if (!peer->IsConnected ())
 784  				ConnectToPeer (ident, peer);
 785  		}
 786  		else if (!r)
 787  			LogPrint (eLogInfo, "Transports: RouterInfo not found, failed to send messages");
 788  
 789  	}
 790  
 791  	void Transports::DetectExternalIP ()
 792  	{
 793  		if (RoutesRestricted())
 794  		{
 795  			LogPrint(eLogInfo, "Transports: Restricted routes enabled, not detecting IP");
 796  			i2p::context.SetStatus (eRouterStatusOK);
 797  			return;
 798  		}
 799  		if (m_SSU2Server)
 800  			PeerTest ();
 801  		else
 802  			LogPrint (eLogWarning, "Transports: Can't detect external IP. SSU or SSU2 is not available");
 803  	}
 804  
 805  	void Transports::PeerTest (bool ipv4, bool ipv6)
 806  	{
 807  		if (RoutesRestricted() || i2p::context.IsLimitedConnectivity () ||
 808  		    !m_SSU2Server || m_SSU2Server->UsesProxy ()) return;
 809  		if (ipv4 && i2p::context.SupportsV4 ())
 810  		{
 811  			LogPrint (eLogInfo, "Transports: Started peer test IPv4");
 812  			std::unordered_set<i2p::data::IdentHash> excluded;
 813  			excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
 814  			int testDelay = 0;
 815  			for (int i = 0; i < 5; i++)
 816  			{
 817  				auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4
 818  				if (router)
 819  				{
 820  					if (!i2p::context.GetTesting ())
 821  					{
 822  						i2p::context.SetTesting (true);
 823  						// send first peer test immediately
 824  						m_SSU2Server->StartPeerTest (router, true);
 825  					}
 826  					else
 827  					{
 828  						testDelay += PEER_TEST_DELAY_INTERVAL + m_Rng() % PEER_TEST_DELAY_INTERVAL_VARIANCE;
 829  						if (m_Service)
 830  						{
 831  							auto delayTimer = std::make_shared<boost::asio::deadline_timer>(*m_Service);
 832  							delayTimer->expires_from_now (boost::posix_time::milliseconds (testDelay));
 833  							delayTimer->async_wait (
 834  								[this, router, delayTimer](const boost::system::error_code& ecode)
 835  								{
 836  									if (ecode != boost::asio::error::operation_aborted)
 837  										m_SSU2Server->StartPeerTest (router, true);
 838  								});
 839  						}
 840  					}
 841  					excluded.insert (router->GetIdentHash ());
 842  				}
 843  			}
 844  			if (excluded.size () <= 1)
 845  				LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4");
 846  		}
 847  		if (ipv6 && i2p::context.SupportsV6 ())
 848  		{
 849  			LogPrint (eLogInfo, "Transports: Started peer test IPv6");
 850  			std::unordered_set<i2p::data::IdentHash> excluded;
 851  			excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
 852  			int testDelay = 0;
 853  			for (int i = 0; i < 5; i++)
 854  			{
 855  				auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6
 856  				if (router)
 857  				{
 858  					if (!i2p::context.GetTestingV6 ())
 859  					{
 860  						i2p::context.SetTestingV6 (true);
 861  						// send first peer test immediately
 862  						m_SSU2Server->StartPeerTest (router, false);
 863  					}
 864  					else
 865  					{
 866  						testDelay += PEER_TEST_DELAY_INTERVAL + m_Rng() % PEER_TEST_DELAY_INTERVAL_VARIANCE;
 867  						if (m_Service)
 868  						{
 869  							auto delayTimer = std::make_shared<boost::asio::deadline_timer>(*m_Service);
 870  							delayTimer->expires_from_now (boost::posix_time::milliseconds (testDelay));
 871  							delayTimer->async_wait (
 872  								[this, router, delayTimer](const boost::system::error_code& ecode)
 873  								{
 874  									if (ecode != boost::asio::error::operation_aborted)
 875  										m_SSU2Server->StartPeerTest (router, false);
 876  								});
 877  						}
 878  					}
 879  					excluded.insert (router->GetIdentHash ());
 880  				}
 881  			}
 882  			if (excluded.size () <= 1)
 883  				LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6");
 884  		}
 885  	}
 886  
 887  	std::shared_ptr<i2p::crypto::X25519Keys> Transports::GetNextX25519KeysPair ()
 888  	{
 889  		return m_X25519KeysPairSupplier.Acquire ();
 890  	}
 891  
 892  	void Transports::ReuseX25519KeysPair (std::shared_ptr<i2p::crypto::X25519Keys> pair)
 893  	{
 894  		m_X25519KeysPairSupplier.Return (pair);
 895  	}
 896  
 897  	void Transports::PeerConnected (std::shared_ptr<TransportSession> session)
 898  	{
 899  		boost::asio::post (*m_Service, [session, this]()
 900  		{
 901  			auto remoteIdentity = session->GetRemoteIdentity ();
 902  			if (!remoteIdentity) return;
 903  			auto ident = remoteIdentity->GetIdentHash ();
 904  			auto it = m_Peers.find (ident);
 905  			if (it != m_Peers.end ())
 906  			{
 907  				auto peer = it->second;
 908  				if (peer->numAttempts > 1)
 909  				{
 910  					// exclude failed transports
 911  					i2p::data::RouterInfo::CompatibleTransports transports = 0;
 912  					int numExcluded = peer->numAttempts - 1;
 913  					if (numExcluded > (int)peer->priority.size ()) numExcluded = peer->priority.size ();
 914  					for (int i = 0; i < numExcluded; i++)
 915  						transports |= peer->priority[i];
 916  					i2p::data::netdb.ExcludeReachableTransports (ident, transports);
 917  				}
 918  				if (peer->router && peer->numAttempts)
 919  				{
 920  					auto transport = peer->priority[peer->numAttempts-1];
 921  					if (transport == i2p::data::RouterInfo::eNTCP2V4 ||
 922  						transport == i2p::data::RouterInfo::eNTCP2V6 || transport == i2p::data::RouterInfo::eNTCP2V6Mesh)
 923  							i2p::data::UpdateRouterProfile (ident,
 924  								[](std::shared_ptr<i2p::data::RouterProfile> profile)
 925  								{
 926  									if (profile) profile->Connected (); // outgoing NTCP2 connection if always real
 927  								});
 928  					i2p::data::netdb.SetUnreachable (ident, false); // clear unreachable
 929  				}
 930  				peer->numAttempts = 0;
 931  				peer->router = nullptr; // we don't need RouterInfo after successive connect
 932  				bool sendDatabaseStore = true;
 933  				if (it->second->delayedMessages.size () > 0)
 934  				{
 935  					// check if first message is our DatabaseStore (publishing)
 936  					auto firstMsg = peer->delayedMessages.front ();
 937  					if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore &&
 938  							i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ())
 939  						sendDatabaseStore = false; // we have it in the list already
 940  				}
 941  				if (sendDatabaseStore)
 942  					session->SendLocalRouterInfo ();
 943  				else
 944  					session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds
 945  				peer->sessions.push_back (session);
 946  				session->SendI2NPMessages (peer->delayedMessages); // send and clear
 947  			}
 948  			else // incoming connection or peer test
 949  			{
 950  				if(RoutesRestricted() && ! IsRestrictedPeer(ident)) {
 951  					// not trusted
 952  					LogPrint(eLogWarning, "Transports: Closing untrusted inbound connection from ", ident.ToBase64());
 953  					session->Done();
 954  					return;
 955  				}
 956  				if (!session->IsOutgoing ()) // incoming
 957  				{
 958  					std::list<std::shared_ptr<I2NPMessage> > msgs{ CreateDatabaseStoreMsg () };
 959  					session->SendI2NPMessages (msgs); // send DatabaseStore
 960  				}
 961  				auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed
 962  				i2p::data::UpdateRouterProfile (ident,
 963  					[](std::shared_ptr<i2p::data::RouterProfile> profile)
 964  					{
 965  						if (profile) profile->Connected ();
 966  					});
 967  				auto ts = i2p::util::GetSecondsSinceEpoch ();
 968  				auto peer = std::make_shared<Peer>(r, ts);
 969  				peer->sessions.push_back (session);
 970  				peer->router = nullptr;
 971  				std::lock_guard<std::mutex> l(m_PeersMutex);
 972  				m_Peers.emplace (ident, peer);
 973  			}
 974  		});
 975  	}
 976  
 977  	void Transports::PeerDisconnected (std::shared_ptr<TransportSession> session)
 978  	{
 979  		boost::asio::post (*m_Service, [session, this]()
 980  		{
 981  			auto remoteIdentity = session->GetRemoteIdentity ();
 982  			if (!remoteIdentity) return;
 983  			auto ident = remoteIdentity->GetIdentHash ();
 984  			auto it = m_Peers.find (ident);
 985  			if (it != m_Peers.end ())
 986  			{
 987  				auto peer = it->second;
 988  				bool wasConnected = peer->IsConnected ();
 989  				peer->sessions.remove (session);
 990  				if (!peer->IsConnected ())
 991  				{
 992  					if (peer->delayedMessages.size () > 0)
 993  					{
 994  						if (wasConnected) // we had an active session before
 995  							peer->numAttempts = 0; // start over
 996  						ConnectToPeer (ident, peer);
 997  					}
 998  					else
 999  					{
1000  						{
1001  							std::lock_guard<std::mutex> l(m_PeersMutex);
1002  							m_Peers.erase (it);
1003  						}
1004  						// delete buffer of just disconnected router
1005  						auto r = i2p::data::netdb.FindRouter (ident);
1006  						if (r && !r->IsUpdated ()) r->ScheduleBufferToDelete ();
1007  					}
1008  				}
1009  			}
1010  		});
1011  	}
1012  
1013  	bool Transports::IsConnected (const i2p::data::IdentHash& ident) const
1014  	{
1015  		std::lock_guard<std::mutex> l(m_PeersMutex);
1016  #if __cplusplus >= 202002L // C++20
1017  		return m_Peers.contains (ident);
1018  #else
1019  		auto it = m_Peers.find (ident);
1020  		return it != m_Peers.end ();
1021  #endif
1022  	}
1023  
1024  	void Transports::UpdatePeerParams (std::shared_ptr<const i2p::data::RouterInfo> r)
1025  	{
1026  		if (!r) return;
1027  		std::shared_ptr<Peer> peer;
1028  		{
1029  			std::lock_guard<std::mutex> l(m_PeersMutex);
1030  			auto it = m_Peers.find (r->GetIdentHash ());
1031  			if (it != m_Peers.end ())
1032  				peer = it->second;
1033  		}
1034  		if (peer)
1035  			peer->UpdateParams (r);
1036  	}
1037  
1038  	void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode)
1039  	{
1040  		if (ecode != boost::asio::error::operation_aborted)
1041  		{
1042  			auto ts = i2p::util::GetSecondsSinceEpoch ();
1043  			for (auto it = m_Peers.begin (); it != m_Peers.end (); )
1044  			{
1045  				it->second->sessions.remove_if (
1046  					[](std::shared_ptr<TransportSession> session)->bool
1047  					{
1048  						return !session || !session->IsEstablished ();
1049  					});
1050   				if (!it->second->IsConnected () && ts > it->second->creationTime + SESSION_CREATION_TIMEOUT)
1051  				{
1052  					LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
1053  				/*	if (!it->second.router)
1054  					{
1055  						// if router for ident not found mark it unreachable
1056  						auto profile = i2p::data::GetRouterProfile (it->first);
1057  						if (profile) profile->Unreachable ();
1058  					}	*/
1059  					std::lock_guard<std::mutex> l(m_PeersMutex);
1060  					it = m_Peers.erase (it);
1061  				}
1062  				else
1063  				{
1064  					if (ts > it->second->nextRouterInfoUpdateTime)
1065  					{
1066  						auto session = it->second->sessions.front ();
1067  						if (session)
1068  							session->SendLocalRouterInfo (true);
1069  						it->second->nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL +
1070  							m_Rng() % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE;
1071  					}
1072  					++it;
1073  				}
1074  			}
1075  			bool ipv4Testing = i2p::context.GetTesting ();
1076  			if (!ipv4Testing)
1077  				ipv4Testing = i2p::context.GetRouterInfo ().IsSSU2V4 () && (i2p::context.GetStatus() == eRouterStatusUnknown);
1078  			bool ipv6Testing = i2p::context.GetTestingV6 ();
1079  			if (!ipv6Testing)
1080  				ipv6Testing = i2p::context.GetRouterInfo ().IsSSU2V6 () && (i2p::context.GetStatusV6() == eRouterStatusUnknown);
1081  			// if still testing or unknown, repeat peer test
1082  			if (ipv4Testing || ipv6Testing)
1083  				PeerTest (ipv4Testing, ipv6Testing);
1084  			m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(2 * SESSION_CREATION_TIMEOUT + m_Rng() % SESSION_CREATION_TIMEOUT));
1085  			m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
1086  		}
1087  	}
1088  
1089  	void Transports::HandlePeerTestTimer (const boost::system::error_code& ecode)
1090  	{
1091  		if (ecode != boost::asio::error::operation_aborted)
1092  		{
1093  			PeerTest ();
1094  			m_PeerTestTimer->expires_from_now (boost::posix_time::seconds(PEER_TEST_INTERVAL + m_Rng() % PEER_TEST_INTERVAL_VARIANCE));
1095  			m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
1096  		}
1097  	}
1098  
1099  	void Transports::HandleBanListCleanupTimer (const boost::system::error_code& ecode)
1100  	{
1101  		if (ecode != boost::asio::error::operation_aborted)
1102  		{
1103  			if (!m_BanList.empty ())
1104  			{
1105  				auto ts = i2p::util::GetMonotonicSeconds ();
1106  				{
1107  					std::lock_guard<std::mutex> l(m_BanListMutex);
1108  					for (auto it = m_BanList.begin (); it != m_BanList.end (); )
1109  					{
1110  						if (ts < it->second)
1111  							it++;
1112  						else
1113  							it = m_BanList.erase (it);
1114  					}
1115  				}
1116  			}
1117  			m_BanListCleanupTimer->expires_after (std::chrono::seconds(BAN_LIST_CLEANUP_INTERVAL + m_Rng () % BAN_LIST_CLEANUP_INTERVAL_VARIANCE));
1118  			m_BanListCleanupTimer->async_wait (std::bind (&Transports::HandleBanListCleanupTimer, this, std::placeholders::_1));
1119  		}
1120  	}
1121  
1122  	template<typename Filter>
1123  	std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (Filter filter) const
1124  	{
1125  		if (m_Peers.empty()) return nullptr;
1126  		auto ts = i2p::util::GetSecondsSinceEpoch ();
1127  		bool found = false;
1128  		i2p::data::IdentHash ident;
1129  		{
1130  			uint16_t inds[3];
1131  			RAND_bytes ((uint8_t *)inds, sizeof (inds));
1132  			std::lock_guard<std::mutex> l(m_PeersMutex);
1133  			auto count = m_Peers.size ();
1134  			if(count == 0) return nullptr;
1135  			inds[0] %= count;
1136  			auto it = m_Peers.begin ();
1137  			std::advance (it, inds[0]);
1138  			// try random peer
1139  			if (it != m_Peers.end () && filter (it->second))
1140  			{
1141  				ident = it->first;
1142  				found = true;
1143  			}
1144  			else
1145  			{
1146  				// try some peers around
1147  				auto it1 = m_Peers.begin ();
1148  				if (inds[0])
1149  				{
1150  					// before
1151  					inds[1] %= inds[0];
1152  					std::advance (it1, (inds[1] + inds[0])/2);
1153  				}
1154  				else
1155  					it1 = it;
1156  				auto it2 = it;
1157  				if (inds[0] < m_Peers.size () - 1)
1158  				{
1159  					// after
1160  					inds[2] %= (m_Peers.size () - 1 - inds[0]); inds[2] /= 2;
1161  					std::advance (it2, inds[2]);
1162  				}
1163  				// it1 - from, it2 - to
1164  				it = it1;
1165  				while (it != it2 && it != m_Peers.end ())
1166  				{
1167  					if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL &&
1168  					    filter (it->second))
1169  					{
1170  						ident = it->first;
1171  						it->second->lastSelectionTime = ts;
1172  						found = true;
1173  						break;
1174  					}
1175  					it++;
1176  				}
1177  				if (!found)
1178  				{
1179  					// still not found, try from the beginning
1180  					it = m_Peers.begin ();
1181  					while (it != it1 && it != m_Peers.end ())
1182  					{
1183  						if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL &&
1184  						    filter (it->second))
1185  						{
1186  							ident = it->first;
1187  							it->second->lastSelectionTime = ts;
1188  							found = true;
1189  							break;
1190  						}
1191  						it++;
1192  					}
1193  					if (!found)
1194  					{
1195  						// still not found, try to the beginning
1196  						it = it2;
1197  						while (it != m_Peers.end ())
1198  						{
1199  							if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL &&
1200  							    filter (it->second))
1201  							{
1202  								ident = it->first;
1203  								it->second->lastSelectionTime = ts;
1204  								found = true;
1205  								break;
1206  							}
1207  							it++;
1208  						}
1209  					}
1210  				}
1211  			}
1212  		}
1213  		return found ? i2p::data::netdb.FindRouter (ident) : nullptr;
1214  	}
1215  
1216  	std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (bool isHighBandwidth) const
1217  	{
1218  		return GetRandomPeer (
1219  			[isHighBandwidth](std::shared_ptr<const Peer> peer)->bool
1220  			{
1221  				// connected, not overloaded and not slow
1222  				return !peer->router && peer->IsConnected () && peer->isEligible &&
1223  					peer->sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE &&
1224  					!peer->sessions.front ()->IsSlow () && !peer->sessions.front ()->IsBandwidthExceeded (peer->isHighBandwidth) &&
1225  					(!isHighBandwidth || peer->isHighBandwidth);
1226  			});
1227  	}
1228  
1229  	void Transports::RestrictRoutesToFamilies(const std::vector<std::string_view>& families)
1230  	{
1231  		std::lock_guard<std::mutex> lock(m_FamilyMutex);
1232  		m_TrustedFamilies.clear();
1233  		for (auto f: families)
1234  		{
1235              std::string fam(f); boost::to_lower (fam);
1236  			auto id = i2p::data::netdb.GetFamilies ().GetFamilyID (fam);
1237  			if (id)
1238  				m_TrustedFamilies.push_back (id);
1239  		}
1240  	}
1241  
1242  	void Transports::RestrictRoutesToRouters(const std::vector<i2p::data::IdentHash>& routers)
1243  	{
1244  		std::lock_guard<std::mutex> lock(m_TrustedRoutersMutex);
1245  		m_TrustedRouters.clear();
1246  		for (const auto & ri : routers )
1247  			m_TrustedRouters.insert(ri);
1248  	}
1249  
1250  	bool Transports::RoutesRestricted() const
1251  	{
1252  		{
1253  			std::lock_guard<std::mutex> routerslock(m_TrustedRoutersMutex);
1254  			if (!m_TrustedRouters.empty ()) return true;
1255  		}
1256  		{
1257  			std::lock_guard<std::mutex> famlock(m_FamilyMutex);
1258  			if (!m_TrustedFamilies.empty ()) return true;
1259  		}
1260  		return false;
1261  	}
1262  
1263  	/** XXX: if routes are not restricted this dies */
1264  	std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRestrictedPeer()
1265  	{
1266  		{
1267  			std::lock_guard<std::mutex> l(m_FamilyMutex);
1268  			i2p::data::FamilyID fam = 0;
1269  			auto sz = m_TrustedFamilies.size();
1270  			if(sz > 1)
1271  			{
1272  				auto it = m_TrustedFamilies.begin ();
1273  				std::advance(it, m_Rng() % sz);
1274  				fam = *it;
1275  			}
1276  			else if (sz == 1)
1277  			{
1278  				fam = m_TrustedFamilies[0];
1279  			}
1280  			if (fam)
1281  				return i2p::data::netdb.GetRandomRouterInFamily(fam);
1282  		}
1283  		{
1284  			std::lock_guard<std::mutex> l(m_TrustedRoutersMutex);
1285  			auto sz = m_TrustedRouters.size();
1286  			if (sz)
1287  			{
1288  				auto it = m_TrustedRouters.begin();
1289  				if(sz > 1)
1290  					std::advance(it, m_Rng() % sz);
1291  				return i2p::data::netdb.FindRouter(*it);
1292  			}
1293  		}
1294  		return nullptr;
1295  	}
1296  
1297  	bool Transports::IsTrustedRouter (const i2p::data::IdentHash& ih) const
1298  	{
1299  		if (m_TrustedRouters.empty ()) return false;
1300  		std::lock_guard<std::mutex> l(m_TrustedRoutersMutex);
1301  #if __cplusplus >= 202002L // C++20
1302  		if (m_TrustedRouters.contains (ih))
1303  #else
1304  		if (m_TrustedRouters.count (ih) > 0)
1305  #endif
1306  			return true;
1307  		return false;
1308  	}
1309  
1310  	bool Transports::IsRestrictedPeer(const i2p::data::IdentHash& ih) const
1311  	{
1312  		if (IsTrustedRouter (ih)) return true;
1313  
1314  		{
1315  			std::lock_guard<std::mutex> l(m_FamilyMutex);
1316  			auto ri = i2p::data::netdb.FindRouter(ih);
1317  			for (const auto & fam : m_TrustedFamilies)
1318  				if(ri->IsFamily(fam)) return true;
1319  		}
1320  		return false;
1321  	}
1322  
1323  	void Transports::SetOnline (bool online)
1324  	{
1325  		if (m_IsOnline != online)
1326  		{
1327  			m_IsOnline = online;
1328  			if (online)
1329  				PeerTest ();
1330  			else
1331  				i2p::context.SetError (eRouterErrorOffline);
1332  		}
1333  	}
1334  
1335  	int Transports::GetLocalDelay () const
1336  	{
1337  		return (i2p::context.GetStatus () == eRouterStatusProxy) ? 1000 : 0; // 1 sec for proxy. TODO: implement param
1338  	}
1339  
1340  	bool Transports::IsInReservedRange (const boost::asio::ip::address& host) const
1341  	{
1342  		return IsCheckReserved () && i2p::util::net::IsInReservedRange (host);
1343  	}
1344  
1345  	bool Transports::IsBanned (const boost::asio::ip::address& addr)
1346  	{
1347  		std::lock_guard<std::mutex> l(m_BanListMutex);
1348  		auto it = m_BanList.find (addr);
1349  		if (it != m_BanList.end ())
1350  		{
1351  			if (it->second > i2p::util::GetMonotonicSeconds ())
1352  				return true;
1353  			else
1354  				m_BanList.erase (it);
1355  		}
1356  		return false;
1357  	}
1358  
1359  	bool Transports::AddBan (const boost::asio::ip::address& addr)
1360  	{
1361  		auto ts = i2p::util::GetMonotonicSeconds () + IP_BAN_TIME + m_Rng () % IP_BAN_TIME_VARIANCE;
1362  		std::lock_guard<std::mutex> l(m_BanListMutex);
1363  		return m_BanList.emplace (addr, ts).second;
1364  	}
1365  
1366  	void InitAddressFromIface ()
1367  	{
1368  		bool ipv6; i2p::config::GetOption("ipv6", ipv6);
1369  		bool ipv4; i2p::config::GetOption("ipv4", ipv4);
1370  
1371  		// ifname -> address
1372  		std::string ifname; i2p::config::GetOption("ifname", ifname);
1373  		if (ipv4 && i2p::config::IsDefault ("address4"))
1374  		{
1375  			std::string ifname4; i2p::config::GetOption("ifname4", ifname4);
1376  			if (!ifname4.empty ())
1377  				i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname4, false).to_string ()); // v4
1378  			else if (!ifname.empty ())
1379  				i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname, false).to_string ()); // v4
1380  		}
1381  		if (ipv6 && i2p::config::IsDefault ("address6"))
1382  		{
1383  			std::string ifname6; i2p::config::GetOption("ifname6", ifname6);
1384  			if (!ifname6.empty ())
1385  				i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname6, true).to_string ()); // v6
1386  			else if (!ifname.empty ())
1387  				i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname, true).to_string ()); // v6
1388  		}
1389  	}
1390  
1391  	void InitTransports ()
1392  	{
1393  		bool ipv6;     i2p::config::GetOption("ipv6", ipv6);
1394  		bool ipv4;     i2p::config::GetOption("ipv4", ipv4);
1395  		bool ygg;      i2p::config::GetOption("meshnets.yggdrasil", ygg);
1396  		uint16_t port; i2p::config::GetOption("port", port);
1397  		bool stan;	   i2p::config::GetOption("stan", stan);
1398  
1399  		boost::asio::ip::address_v6 yggaddr;
1400  		if (ygg)
1401  		{
1402  			std::string yggaddress; i2p::config::GetOption ("meshnets.yggaddress", yggaddress);
1403  			if (!yggaddress.empty ())
1404  			{
1405  				yggaddr = boost::asio::ip::make_address (yggaddress).to_v6 ();
1406  				if (yggaddr.is_unspecified () || !i2p::util::net::IsYggdrasilAddress (yggaddr) ||
1407  					!i2p::util::net::IsLocalAddress (yggaddr))
1408  				{
1409  					LogPrint(eLogWarning, "Transports: Can't find Yggdrasil address ", yggaddress);
1410  					ygg = false;
1411  				}
1412  			}
1413  			else
1414  			{
1415  				yggaddr = i2p::util::net::GetYggdrasilAddress ();
1416  				if (yggaddr.is_unspecified ())
1417  				{
1418  					LogPrint(eLogWarning, "Transports: Yggdrasil is not running. Disabled");
1419  					ygg = false;
1420  				}
1421  			}
1422  		}
1423  
1424  		if (ipv6 &&	i2p::util::net::GetClearnetIPV6Address ().is_unspecified ())
1425  		{
1426  			std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
1427  			std::string ssu2proxy; i2p::config::GetOption("ssu2.proxy", ssu2proxy);
1428  			if (ntcp2proxy.empty () && ssu2proxy.empty ())
1429  			{
1430  				LogPrint(eLogWarning, "Transports: Clearnet ipv6 not found. Disabled");
1431  				ipv6 = false;
1432  			}
1433  		}
1434  
1435  		if (!i2p::config::IsDefault("port"))
1436  		{
1437  			LogPrint(eLogInfo, "Transports: Accepting incoming connections at port ", port);
1438  			i2p::context.UpdatePort (port);
1439  		}
1440  		i2p::context.SetSupportsV6 (ipv6);
1441  		i2p::context.SetSupportsV4 (ipv4);
1442  		i2p::context.SetSupportsMesh (ygg, yggaddr);
1443  
1444  		bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
1445  		if (ntcp2)
1446  		{
1447  			bool published = false;
1448  			if (!stan) i2p::config::GetOption("ntcp2.published", published);
1449  			if (published)
1450  			{
1451  				std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
1452  				if (!ntcp2proxy.empty ()) published = false;
1453  			}
1454  			int ntcp2version = 2;
1455  #if OPENSSL_PQ
1456  			i2p::config::GetOption("ntcp2.version", ntcp2version);
1457  #endif
1458  			if (published)
1459  			{
1460  				uint16_t ntcp2port; i2p::config::GetOption("ntcp2.port", ntcp2port);
1461  				if (!ntcp2port) ntcp2port = port; // use standard port
1462  				i2p::context.PublishNTCP2Address (ntcp2port, true, ipv4, ipv6, false, ntcp2version); // publish
1463  				if (ipv6)
1464  				{
1465  					std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr);
1466  					auto addr = boost::asio::ip::make_address (ipv6Addr).to_v6 ();
1467  					if (!addr.is_unspecified () && addr != boost::asio::ip::address_v6::any ())
1468  						i2p::context.UpdateNTCP2V6Address (addr); // set ipv6 address if configured
1469  				}
1470  			}
1471  			else
1472  				i2p::context.PublishNTCP2Address (port, false, ipv4, ipv6, false, ntcp2version); // unpublish
1473  		}
1474  		if (ygg)
1475  		{
1476  			i2p::context.PublishNTCP2Address (port, true, false, false, true, 2);
1477  			i2p::context.UpdateNTCP2V6Address (yggaddr);
1478  			if (!ipv4 && !ipv6)
1479  				i2p::context.SetStatus (eRouterStatusMesh);
1480  		}
1481  		bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
1482  		if (ssu2 && i2p::config::IsDefault ("ssu2.enabled") && !ipv4 && !ipv6)
1483  			ssu2 = false; // don't enable ssu2 for yggdrasil only router
1484  		if (ssu2)
1485  		{
1486  			uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
1487  			if (!ssu2port && port) ssu2port = port;
1488  			bool published = false;
1489  			if (!stan) i2p::config::GetOption("ssu2.published", published);
1490  			if (published)
1491  				i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish
1492  			else
1493  				i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish
1494  		}
1495  		if (stan)
1496  			i2p::context.SetStatus (eRouterStatusStan);
1497  	}
1498  }
1499  }