1 /*
2 * Copyright (c) 2013-2021, 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 #ifndef TUNNEL_POOL__
10 #define TUNNEL_POOL__
11 
12 #include <inttypes.h>
13 #include <set>
14 #include <vector>
15 #include <utility>
16 #include <mutex>
17 #include <memory>
18 #include "Identity.h"
19 #include "LeaseSet.h"
20 #include "RouterInfo.h"
21 #include "I2NPProtocol.h"
22 #include "TunnelBase.h"
23 #include "RouterContext.h"
24 #include "Garlic.h"
25 
26 namespace i2p
27 {
28 namespace tunnel
29 {
30 	const int TUNNEL_POOL_MANAGE_INTERVAL = 10; // in seconds
31 	const int TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY = 16;
32 	const int TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY = 16;
33 
34 	class Tunnel;
35 	class InboundTunnel;
36 	class OutboundTunnel;
37 
38 	typedef std::shared_ptr<const i2p::data::IdentityEx> Peer;
39 	struct Path
40 	{
41 		std::vector<Peer> peers;
42 		bool isShort = true;
43 		i2p::data::RouterInfo::CompatibleTransports farEndTransports = i2p::data::RouterInfo::eAllTransports;
44 
45 		void Add (std::shared_ptr<const i2p::data::RouterInfo> r);
46 		void Reverse ();
47 	};
48 
49 	/** interface for custom tunnel peer selection algorithm */
50 	struct ITunnelPeerSelector
51 	{
~ITunnelPeerSelectorITunnelPeerSelector52 		virtual ~ITunnelPeerSelector() {};
53 		virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0;
54 	};
55 
56 
57 	typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>, bool)> SelectHopFunc;
58 	bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop);
59 
60 	class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
61 	{
62 		public:
63 
64 			TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
65 			~TunnelPool ();
66 
GetLocalDestination()67 			std::shared_ptr<i2p::garlic::GarlicDestination> GetLocalDestination () const { return m_LocalDestination; };
SetLocalDestination(std::shared_ptr<i2p::garlic::GarlicDestination> destination)68 			void SetLocalDestination (std::shared_ptr<i2p::garlic::GarlicDestination> destination) { m_LocalDestination = destination; };
69 			void SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers);
70 
71 			void CreateTunnels ();
72 			void TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel);
73 			void TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel);
74 			void TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel);
75 			void TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel);
76 			void RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel);
77 			void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel);
78 			std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const;
79 			std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr,
80 				i2p::data::RouterInfo::CompatibleTransports compatible = i2p::data::RouterInfo::eAllTransports) const;
81 			std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr,
82 				i2p::data::RouterInfo::CompatibleTransports compatible = i2p::data::RouterInfo::eAllTransports) const;
83 			std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const;
84 			void TestTunnels ();
85 			void ManageTunnels (uint64_t ts);
86 			void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
87 			void ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg);
88 
89 			bool IsExploratory () const;
IsActive()90 			bool IsActive () const { return m_IsActive; };
SetActive(bool isActive)91 			void SetActive (bool isActive) { m_IsActive = isActive; };
92 			void DetachTunnels ();
93 
GetNumInboundTunnels()94 			int GetNumInboundTunnels () const { return m_NumInboundTunnels; };
GetNumOutboundTunnels()95 			int GetNumOutboundTunnels () const { return m_NumOutboundTunnels; };
GetNumInboundHops()96 			int GetNumInboundHops() const { return m_NumInboundHops; };
GetNumOutboundHops()97 			int GetNumOutboundHops() const { return m_NumOutboundHops; };
98 
99 			/** i2cp reconfigure */
100 			bool Reconfigure(int inboundHops, int outboundHops, int inboundQuant, int outboundQuant);
101 
102 			void SetCustomPeerSelector(ITunnelPeerSelector * selector);
103 			void UnsetCustomPeerSelector();
104 			bool HasCustomPeerSelector();
105 
106 			/** @brief make this tunnel pool yield tunnels that fit latency range [min, max] */
RequireLatency(uint64_t min,uint64_t max)107 			void RequireLatency(uint64_t min, uint64_t max) { m_MinLatency = min; m_MaxLatency = max; }
108 
109 			/** @brief return true if this tunnel pool has a latency requirement */
HasLatencyRequirement()110 			bool HasLatencyRequirement() const { return m_MinLatency > 0 && m_MaxLatency > 0; }
111 
112 			/** @brief get the lowest latency tunnel in this tunnel pool regardless of latency requirements */
113 			std::shared_ptr<InboundTunnel> GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude = nullptr) const;
114 			std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude = nullptr) const;
115 
116 			// for overriding tunnel peer selection
117 			std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse) const;
118 
119 		private:
120 
121 			void CreateInboundTunnel ();
122 			void CreateOutboundTunnel ();
123 			void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
124 			template<class TTunnels>
125 			typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels,
126 				typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible) const;
127 			bool SelectPeers (Path& path, bool isInbound);
128 			bool SelectExplicitPeers (Path& path, bool isInbound);
129 
130 		private:
131 
132 			std::shared_ptr<i2p::garlic::GarlicDestination> m_LocalDestination;
133 			int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels;
134 			std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers;
135 			mutable std::mutex m_InboundTunnelsMutex;
136 			std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
137 			mutable std::mutex m_OutboundTunnelsMutex;
138 			std::set<std::shared_ptr<OutboundTunnel>, TunnelCreationTimeCmp> m_OutboundTunnels;
139 			mutable std::mutex m_TestsMutex;
140 			std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests;
141 			bool m_IsActive;
142 			uint64_t m_NextManageTime; // in seconds
143 			std::mutex m_CustomPeerSelectorMutex;
144 			ITunnelPeerSelector * m_CustomPeerSelector;
145 
146 			uint64_t m_MinLatency = 0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms
147 			uint64_t m_MaxLatency = 0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms
148 
149 		public:
150 
151 			// for HTTP only
decltype(m_OutboundTunnels)152 			const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
decltype(m_InboundTunnels)153 			const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
154 
155 	};
156 }
157 }
158 
159 #endif
160