i2pd/libi2pd/Tunnel.h

336 lines
13 KiB
C
Raw Normal View History

/*
2024-02-04 23:45:22 +03:00
* Copyright (c) 2013-2024, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
2013-12-07 04:02:49 +04:00
#ifndef TUNNEL_H__
#define TUNNEL_H__
#include <inttypes.h>
#include <map>
2016-03-02 04:48:56 +03:00
#include <unordered_map>
2013-12-07 04:02:49 +04:00
#include <list>
2014-01-21 03:37:51 +04:00
#include <vector>
2013-12-07 04:02:49 +04:00
#include <string>
#include <thread>
2014-04-03 20:19:12 +04:00
#include <mutex>
2015-01-20 06:28:13 +03:00
#include <memory>
2021-10-21 04:05:22 +03:00
#include "util.h"
2013-12-07 04:02:49 +04:00
#include "Queue.h"
2015-11-03 17:15:49 +03:00
#include "Crypto.h"
2013-12-07 04:02:49 +04:00
#include "TunnelConfig.h"
2014-03-14 20:35:02 +04:00
#include "TunnelPool.h"
2013-12-07 04:02:49 +04:00
#include "TransitTunnel.h"
#include "TunnelEndpoint.h"
#include "TunnelGateway.h"
#include "TunnelBase.h"
#include "I2NPProtocol.h"
namespace i2p
{
namespace tunnel
2016-10-20 19:14:32 +03:00
{
2018-01-06 06:48:51 +03:00
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
2014-09-26 18:15:34 +04:00
const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds
const int STANDARD_NUM_RECORDS = 4; // in VariableTunnelBuild message
2021-01-14 19:24:03 +03:00
const int MAX_NUM_RECORDS = 8;
2024-02-25 23:57:57 +03:00
const int UNKNOWN_LATENCY = -1;
2024-03-04 14:41:50 +03:00
const int HIGH_LATENCY_PER_HOP = 250000; // in microseconds
const int MAX_TUNNEL_MSGS_BATCH_SIZE = 100; // handle messages without interrupt
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 5000;
const int TUNNEL_MANAGE_INTERVAL = 15; // in seconds
const int TUNNEL_POOLS_MANAGE_INTERVAL = 5; // in seconds
const int TUNNEL_MEMORY_POOL_MANAGE_INTERVAL = 120; // in seconds
const size_t I2NP_TUNNEL_MESSAGE_SIZE = TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34; // reserved for alignment and NTCP 16 + 6 + 12
const size_t I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE = 2*TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + 28; // reserved for alignment and NTCP 16 + 6 + 6
const double TCSR_SMOOTHING_CONSTANT = 0.0005; // smoothing constant in exponentially weighted moving average
const double TCSR_START_VALUE = 0.1; // start value of tunnel creation success rate
2014-07-27 04:56:42 +04:00
enum TunnelState
{
eTunnelStatePending,
2014-09-26 18:15:34 +04:00
eTunnelStateBuildReplyReceived,
eTunnelStateBuildFailed,
2014-07-27 04:56:42 +04:00
eTunnelStateEstablished,
eTunnelStateTestFailed,
2014-08-26 18:31:32 +04:00
eTunnelStateFailed,
eTunnelStateExpiring
2018-01-06 06:48:51 +03:00
};
2013-12-07 04:02:49 +04:00
class OutboundTunnel;
class InboundTunnel;
2024-02-04 23:45:22 +03:00
class Tunnel: public TunnelBase,
public std::enable_shared_from_this<Tunnel>
2013-12-07 04:02:49 +04:00
{
2015-11-03 17:15:49 +03:00
struct TunnelHop
{
std::shared_ptr<const i2p::data::IdentityEx> ident;
i2p::crypto::TunnelDecryption decryption;
2018-01-06 06:48:51 +03:00
};
2013-12-07 04:02:49 +04:00
public:
/** function for visiting a hops stored in a tunnel */
typedef std::function<void(std::shared_ptr<const i2p::data::IdentityEx>)> TunnelHopVisitor;
2015-05-06 23:17:48 +03:00
Tunnel (std::shared_ptr<const TunnelConfig> config);
~Tunnel ();
2013-12-07 04:02:49 +04:00
2015-01-27 22:55:46 +03:00
void Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
2018-01-06 06:48:51 +03:00
2015-05-06 23:17:48 +03:00
std::shared_ptr<const TunnelConfig> GetTunnelConfig () const { return m_Config; }
2018-01-06 06:48:51 +03:00
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const;
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const;
bool IsShortBuildMessage () const { return m_IsShortBuildMessage; };
i2p::data::RouterInfo::CompatibleTransports GetFarEndTransports () const { return m_FarEndTransports; };
2014-07-27 04:56:42 +04:00
TunnelState GetState () const { return m_State; };
2016-11-01 17:26:40 +03:00
void SetState (TunnelState state);
bool IsEstablished () const { return m_State == eTunnelStateEstablished || m_State == eTunnelStateTestFailed; };
2014-07-27 04:56:42 +04:00
bool IsFailed () const { return m_State == eTunnelStateFailed; };
2015-04-17 18:36:42 +03:00
bool IsRecreated () const { return m_IsRecreated; };
void SetRecreated (bool recreated) { m_IsRecreated = recreated; };
2018-02-27 03:41:24 +03:00
int GetNumHops () const { return m_Hops.size (); };
2016-11-01 17:46:07 +03:00
virtual bool IsInbound() const = 0;
2018-01-06 06:48:51 +03:00
2015-01-20 06:28:13 +03:00
std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; };
2018-01-06 06:48:51 +03:00
void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; };
2013-12-07 04:02:49 +04:00
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
2016-03-03 06:41:53 +03:00
2013-12-07 04:02:49 +04:00
// implements TunnelBase
2023-04-04 04:35:10 +03:00
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) override;
2015-12-10 03:07:12 +03:00
/** @brief add latency sample */
2024-02-27 11:15:15 +03:00
void AddLatencySample(const int us) { m_Latency = LatencyIsKnown() ? (m_Latency + us) >> 1 : us; }
/** @brief get this tunnel's estimated latency */
2024-02-27 11:15:15 +03:00
int GetMeanLatency() const { return (m_Latency + 500) / 1000; }
2017-07-08 16:53:33 +03:00
/** @brief return true if this tunnel's latency fits in range [lowerbound, upperbound] */
2024-02-25 23:57:57 +03:00
bool LatencyFitsRange(int lowerbound, int upperbound) const;
2018-01-06 06:48:51 +03:00
2024-02-25 23:57:57 +03:00
bool LatencyIsKnown() const { return m_Latency != UNKNOWN_LATENCY; }
bool IsSlow () const { return LatencyIsKnown() && m_Latency > HIGH_LATENCY_PER_HOP*GetNumHops (); }
/** visit all hops we currently store */
void VisitTunnelHops(TunnelHopVisitor v);
2018-01-06 06:48:51 +03:00
2013-12-07 04:02:49 +04:00
private:
2015-05-06 23:17:48 +03:00
std::shared_ptr<const TunnelConfig> m_Config;
std::vector<TunnelHop> m_Hops;
bool m_IsShortBuildMessage;
2015-01-20 06:28:13 +03:00
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
2014-07-27 04:56:42 +04:00
TunnelState m_State;
i2p::data::RouterInfo::CompatibleTransports m_FarEndTransports;
bool m_IsRecreated; // if tunnel is replaced by new, or new tunnel requested to replace
2024-02-27 11:15:15 +03:00
int m_Latency; // in microseconds
2018-01-06 06:48:51 +03:00
};
2013-12-07 04:02:49 +04:00
2018-01-06 06:48:51 +03:00
class OutboundTunnel: public Tunnel
2013-12-07 04:02:49 +04:00
{
public:
2018-01-06 06:48:51 +03:00
OutboundTunnel (std::shared_ptr<const TunnelConfig> config):
2015-11-03 17:15:49 +03:00
Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {};
2013-12-07 04:02:49 +04:00
void SendTunnelDataMsgTo (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
virtual void SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
2018-01-06 06:48:51 +03:00
const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; };
2016-03-04 00:24:13 +03:00
virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
2018-01-06 06:48:51 +03:00
2014-01-04 07:56:28 +04:00
// implements TunnelBase
2023-04-04 04:35:10 +03:00
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
2016-11-01 17:46:07 +03:00
2023-04-04 04:35:10 +03:00
bool IsInbound() const override { return false; }
2018-01-06 06:48:51 +03:00
2013-12-07 04:02:49 +04:00
private:
2014-04-03 20:19:12 +04:00
std::mutex m_SendMutex;
2018-01-06 06:48:51 +03:00
TunnelGateway m_Gateway;
2015-11-03 17:15:49 +03:00
i2p::data::IdentHash m_EndpointIdentHash;
2013-12-07 04:02:49 +04:00
};
2016-03-03 06:41:53 +03:00
2024-02-04 23:45:22 +03:00
class InboundTunnel: public Tunnel
2013-12-07 04:02:49 +04:00
{
public:
2015-05-06 23:17:48 +03:00
InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {};
2023-04-04 04:35:10 +03:00
void HandleTunnelDataMsg (std::shared_ptr<I2NPMessage>&& msg) override;
virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
2023-04-04 04:35:10 +03:00
bool IsInbound() const override { return true; }
// override TunnelBase
2023-04-04 05:50:31 +03:00
void Cleanup () override { m_Endpoint.Cleanup (); };
2024-02-04 23:45:22 +03:00
protected:
std::shared_ptr<InboundTunnel> GetSharedFromThis ()
{
return std::static_pointer_cast<InboundTunnel>(shared_from_this ());
}
private:
2013-12-07 04:02:49 +04:00
2018-01-06 06:48:51 +03:00
TunnelEndpoint m_Endpoint;
};
2016-03-03 06:41:53 +03:00
class ZeroHopsInboundTunnel: public InboundTunnel
{
public:
2013-12-07 04:02:49 +04:00
2016-03-03 06:41:53 +03:00
ZeroHopsInboundTunnel ();
2023-04-04 04:35:10 +03:00
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
size_t GetNumReceivedBytes () const override { return m_NumReceivedBytes; };
2018-01-06 06:48:51 +03:00
private:
size_t m_NumReceivedBytes;
2018-01-06 06:48:51 +03:00
};
2016-03-04 00:24:13 +03:00
class ZeroHopsOutboundTunnel: public OutboundTunnel
{
public:
ZeroHopsOutboundTunnel ();
void SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs) override;
2023-04-04 04:35:10 +03:00
size_t GetNumSentBytes () const override { return m_NumSentBytes; };
2018-01-06 06:48:51 +03:00
2016-03-04 00:24:13 +03:00
private:
size_t m_NumSentBytes;
2018-01-06 06:48:51 +03:00
};
2016-03-04 00:24:13 +03:00
2013-12-07 04:02:49 +04:00
class Tunnels
2018-01-06 06:48:51 +03:00
{
2013-12-07 04:02:49 +04:00
public:
Tunnels ();
~Tunnels ();
void Start ();
2018-01-06 06:48:51 +03:00
void Stop ();
std::shared_ptr<InboundTunnel> GetPendingInboundTunnel (uint32_t replyMsgID);
std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID);
2015-01-27 22:55:46 +03:00
std::shared_ptr<InboundTunnel> GetNextInboundTunnel ();
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel ();
2015-01-20 06:28:13 +03:00
std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; };
2016-03-02 04:48:56 +03:00
std::shared_ptr<TunnelBase> GetTunnel (uint32_t tunnelID);
int GetTransitTunnelsExpirationTimeout ();
2023-01-05 19:59:47 +03:00
bool AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel);
2015-01-27 22:55:46 +03:00
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel);
2021-07-21 20:08:12 +03:00
std::shared_ptr<InboundTunnel> CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel);
std::shared_ptr<OutboundTunnel> CreateOutboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<TunnelPool> pool);
void PostTunnelData (std::shared_ptr<I2NPMessage> msg);
void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
2015-01-27 22:55:46 +03:00
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel);
std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops, int numOuboundHops,
int numInboundTunnels, int numOutboundTunnels, int inboundVariance, int outboundVariance);
2015-01-20 06:28:13 +03:00
void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool);
void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
2018-01-06 06:48:51 +03:00
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
void SetMaxNumTransitTunnels (uint32_t maxNumTransitTunnels);
uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; };
int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; }
2013-12-07 04:02:49 +04:00
private:
2018-01-06 06:48:51 +03:00
template<class TTunnel>
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config,
std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
template<class TTunnel>
2018-01-06 06:48:51 +03:00
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
2016-03-01 23:22:36 +03:00
void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg);
2018-01-06 06:48:51 +03:00
void Run ();
2023-02-10 02:32:18 +03:00
void ManageTunnels (uint64_t ts);
void ManageOutboundTunnels (uint64_t ts);
void ManageInboundTunnels (uint64_t ts);
void ManageTransitTunnels (uint64_t ts);
void ManagePendingTunnels (uint64_t ts);
template<class PendingTunnels>
2023-02-10 02:32:18 +03:00
void ManagePendingTunnels (PendingTunnels& pendingTunnels, uint64_t ts);
void ManageTunnelPools (uint64_t ts);
2018-01-06 06:48:51 +03:00
2021-07-30 21:12:50 +03:00
std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel (std::shared_ptr<TunnelPool> pool);
std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel (std::shared_ptr<TunnelPool> pool);
2016-03-04 00:24:13 +03:00
2023-02-02 05:28:05 +03:00
// Calculating of tunnel creation success rate
void SuccesiveTunnelCreation()
2023-02-02 05:28:05 +03:00
{
// total TCSR
m_TotalNumSuccesiveTunnelCreations++;
// A modified version of the EWMA algorithm, where alpha is increased at the beginning to accelerate similarity
double alpha = TCSR_SMOOTHING_CONSTANT + (1 - TCSR_SMOOTHING_CONSTANT)/++m_TunnelCreationAttemptsNum;
m_TunnelCreationSuccessRate = alpha * 1 + (1 - alpha) * m_TunnelCreationSuccessRate;
}
void FailedTunnelCreation()
2023-02-02 05:28:05 +03:00
{
m_TotalNumFailedTunnelCreations++;
2023-02-02 05:28:05 +03:00
double alpha = TCSR_SMOOTHING_CONSTANT + (1 - TCSR_SMOOTHING_CONSTANT)/++m_TunnelCreationAttemptsNum;
m_TunnelCreationSuccessRate = alpha * 0 + (1 - alpha) * m_TunnelCreationSuccessRate;
}
2013-12-07 04:02:49 +04:00
private:
bool m_IsRunning;
2018-01-06 06:48:51 +03:00
std::thread * m_Thread;
2015-01-27 22:55:46 +03:00
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID
std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels;
2015-01-27 22:55:46 +03:00
std::list<std::shared_ptr<OutboundTunnel> > m_OutboundTunnels;
2016-03-02 04:48:56 +03:00
std::list<std::shared_ptr<TransitTunnel> > m_TransitTunnels;
std::unordered_map<uint32_t, std::shared_ptr<TunnelBase> > m_Tunnels; // tunnelID->tunnel known by this id
std::mutex m_PoolsMutex;
2015-01-20 06:28:13 +03:00
std::list<std::shared_ptr<TunnelPool>> m_Pools;
std::shared_ptr<TunnelPool> m_ExploratoryPool;
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool;
uint32_t m_MaxNumTransitTunnels;
2023-02-01 19:14:56 +03:00
// count of tunnels for total TCSR algorithm
int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations;
double m_TunnelCreationSuccessRate;
int m_TunnelCreationAttemptsNum;
2015-02-28 15:59:34 +03:00
2013-12-07 04:02:49 +04:00
public:
// for HTTP only
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
2013-12-10 17:10:49 +04:00
const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; };
size_t CountTransitTunnels() const;
size_t CountInboundTunnels() const;
size_t CountOutboundTunnels() const;
2018-01-06 06:48:51 +03:00
2015-02-04 00:45:19 +03:00
int GetQueueSize () { return m_Queue.GetSize (); };
int GetTunnelCreationSuccessRate () const { return std::round(m_TunnelCreationSuccessRate * 100); } // in percents
double GetPreciseTunnelCreationSuccessRate () const { return m_TunnelCreationSuccessRate * 100; } // in percents
2023-02-01 19:14:56 +03:00
int GetTotalTunnelCreationSuccessRate () const // in percents
{
2023-02-01 19:14:56 +03:00
int totalNum = m_TotalNumSuccesiveTunnelCreations + m_TotalNumFailedTunnelCreations;
return totalNum ? m_TotalNumSuccesiveTunnelCreations*100/totalNum : 0;
}
2018-01-06 06:48:51 +03:00
};
2013-12-07 04:02:49 +04:00
extern Tunnels tunnels;
2018-01-06 06:48:51 +03:00
}
2013-12-07 04:02:49 +04:00
}
#endif