mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 21:37:17 +01:00
add latency requirement option
This commit is contained in:
parent
8a545b98ec
commit
fc94e846a6
|
@ -372,6 +372,8 @@ namespace client
|
||||||
options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY);
|
options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY);
|
||||||
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY);
|
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY);
|
||||||
options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND);
|
options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND);
|
||||||
|
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY);
|
||||||
|
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const
|
void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const
|
||||||
|
@ -384,7 +386,11 @@ namespace client
|
||||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, value))
|
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, value))
|
||||||
options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = value;
|
options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = value;
|
||||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, value))
|
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, value))
|
||||||
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = value;
|
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = value;
|
||||||
|
if (i2p::config::GetOption(prefix + I2CP_PARAM_MIN_TUNNEL_LATENCY, value))
|
||||||
|
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value;
|
||||||
|
if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value))
|
||||||
|
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientContext::ReadTunnels ()
|
void ClientContext::ReadTunnels ()
|
||||||
|
|
|
@ -86,7 +86,9 @@ namespace config {
|
||||||
("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length")
|
("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length")
|
||||||
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
|
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
|
||||||
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
|
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
|
||||||
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity")
|
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity")
|
||||||
|
("httpproxy.latency.min", value<int>()->default_value(0), "HTTP proxy min latency for tunnels")
|
||||||
|
("httpproxy.latency.max", value<int>()->default_value(0), "HTTP proxy max latency for tunnels")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description socksproxy("SOCKS Proxy options");
|
options_description socksproxy("SOCKS Proxy options");
|
||||||
|
@ -98,7 +100,9 @@ namespace config {
|
||||||
("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length")
|
("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length")
|
||||||
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length")
|
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length")
|
||||||
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity")
|
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity")
|
||||||
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity")
|
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity")
|
||||||
|
("socksproxy.latency.min", value<int>()->default_value(0), "SOCKS proxy min latency for tunnels")
|
||||||
|
("socksproxy.latency.max", value<int>()->default_value(0), "SOCKS proxy max latency for tunnels")
|
||||||
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy")
|
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy")
|
||||||
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy")
|
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy")
|
||||||
;
|
;
|
||||||
|
|
|
@ -63,6 +63,22 @@ namespace client
|
||||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty);
|
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty);
|
||||||
if (explicitPeers)
|
if (explicitPeers)
|
||||||
m_Pool->SetExplicitPeers (explicitPeers);
|
m_Pool->SetExplicitPeers (explicitPeers);
|
||||||
|
if(params)
|
||||||
|
{
|
||||||
|
auto itr = params->find(I2CP_PARAM_MAX_TUNNEL_LATENCY);
|
||||||
|
if (itr != params->end()) {
|
||||||
|
auto maxlatency = std::stoi(itr->second);
|
||||||
|
itr = params->find(I2CP_PARAM_MIN_TUNNEL_LATENCY);
|
||||||
|
if (itr != params->end()) {
|
||||||
|
auto minlatency = std::stoi(itr->second);
|
||||||
|
if ( minlatency > 0 && maxlatency > 0 ) {
|
||||||
|
// set tunnel pool latency
|
||||||
|
LogPrint(eLogInfo, "Destination: requiring tunnel latency [", minlatency, "ms, ", maxlatency, "ms]");
|
||||||
|
m_Pool->RequireLatency(minlatency, maxlatency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaseSetDestination::~LeaseSetDestination ()
|
LeaseSetDestination::~LeaseSetDestination ()
|
||||||
|
|
|
@ -50,6 +50,12 @@ namespace client
|
||||||
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
|
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
|
||||||
const int DEFAULT_TAGS_TO_SEND = 40;
|
const int DEFAULT_TAGS_TO_SEND = 40;
|
||||||
|
|
||||||
|
// latency
|
||||||
|
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
|
||||||
|
const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
|
||||||
|
const char I2CP_PARAM_MAX_TUNNEL_LATENCY[] = "latency.max";
|
||||||
|
const int DEFAULT_MAX_TUNNEL_LATENCY = 0;
|
||||||
|
|
||||||
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
||||||
|
|
||||||
class LeaseSetDestination: public i2p::garlic::GarlicDestination,
|
class LeaseSetDestination: public i2p::garlic::GarlicDestination,
|
||||||
|
|
23
Tunnel.cpp
23
Tunnel.cpp
|
@ -21,6 +21,23 @@ namespace i2p
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
void TunnelLatency::AddSample(Sample s)
|
||||||
|
{
|
||||||
|
m_samples ++;
|
||||||
|
m_latency += s / m_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TunnelLatency::HasSamples() const
|
||||||
|
{
|
||||||
|
return m_samples > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TunnelLatency::Latency TunnelLatency::GetMeanLatency() const
|
||||||
|
{
|
||||||
|
return m_latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config):
|
Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config):
|
||||||
TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()),
|
TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()),
|
||||||
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false)
|
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false)
|
||||||
|
@ -162,6 +179,12 @@ namespace tunnel
|
||||||
return established;
|
return established;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Tunnel::LatencyFitsRange(uint64_t lower, uint64_t upper) const
|
||||||
|
{
|
||||||
|
auto latency = GetMeanLatency();
|
||||||
|
return latency >= lower && latency <= upper;
|
||||||
|
}
|
||||||
|
|
||||||
void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
|
void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
|
||||||
{
|
{
|
||||||
const uint8_t * inPayload = in->GetPayload () + 4;
|
const uint8_t * inPayload = in->GetPayload () + 4;
|
||||||
|
|
25
Tunnel.h
25
Tunnel.h
|
@ -79,6 +79,22 @@ namespace tunnel
|
||||||
eTunnelStateExpiring
|
eTunnelStateExpiring
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief for storing latency history */
|
||||||
|
struct TunnelLatency
|
||||||
|
{
|
||||||
|
typedef uint64_t Sample;
|
||||||
|
typedef uint64_t Latency;
|
||||||
|
|
||||||
|
|
||||||
|
void AddSample(Sample s);
|
||||||
|
bool HasSamples() const;
|
||||||
|
Latency GetMeanLatency() const;
|
||||||
|
|
||||||
|
Latency m_latency = 0;
|
||||||
|
std::size_t m_samples = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class OutboundTunnel;
|
class OutboundTunnel;
|
||||||
class InboundTunnel;
|
class InboundTunnel;
|
||||||
class Tunnel: public TunnelBase
|
class Tunnel: public TunnelBase
|
||||||
|
@ -118,6 +134,14 @@ namespace tunnel
|
||||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
||||||
|
|
||||||
|
/** @brief add latency sample */
|
||||||
|
void AddLatencySample(const uint64_t ms) { m_Latency.AddSample(ms); }
|
||||||
|
/** @brief get this tunnel's estimated latency */
|
||||||
|
uint64_t GetMeanLatency() const { return m_Latency.GetMeanLatency(); }
|
||||||
|
/** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */
|
||||||
|
bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const;
|
||||||
|
|
||||||
|
bool LatencyIsKnown() const { return m_Latency.HasSamples(); }
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void PrintHops (std::stringstream& s) const;
|
void PrintHops (std::stringstream& s) const;
|
||||||
|
@ -129,6 +153,7 @@ namespace tunnel
|
||||||
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
|
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
|
||||||
TunnelState m_State;
|
TunnelState m_State;
|
||||||
bool m_IsRecreated;
|
bool m_IsRecreated;
|
||||||
|
TunnelLatency m_Latency;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OutboundTunnel: public Tunnel
|
class OutboundTunnel: public Tunnel
|
||||||
|
|
|
@ -147,12 +147,16 @@ namespace tunnel
|
||||||
|
|
||||||
std::shared_ptr<OutboundTunnel> TunnelPool::GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded) const
|
std::shared_ptr<OutboundTunnel> TunnelPool::GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded) const
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
if (HasLatencyRequriement())
|
||||||
|
return GetLowestLatencyOutboundTunnel(excluded);
|
||||||
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
return GetNextTunnel (m_OutboundTunnels, excluded);
|
return GetNextTunnel (m_OutboundTunnels, excluded);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<InboundTunnel> TunnelPool::GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded) const
|
std::shared_ptr<InboundTunnel> TunnelPool::GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded) const
|
||||||
{
|
{
|
||||||
|
if (HasLatencyRequriement())
|
||||||
|
return GetLowestLatencyInboundTunnel(excluded);
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
return GetNextTunnel (m_InboundTunnels, excluded);
|
return GetNextTunnel (m_InboundTunnels, excluded);
|
||||||
}
|
}
|
||||||
|
@ -322,7 +326,12 @@ namespace tunnel
|
||||||
test.first->SetState (eTunnelStateEstablished);
|
test.first->SetState (eTunnelStateEstablished);
|
||||||
if (test.second->GetState () == eTunnelStateTestFailed)
|
if (test.second->GetState () == eTunnelStateTestFailed)
|
||||||
test.second->SetState (eTunnelStateEstablished);
|
test.second->SetState (eTunnelStateEstablished);
|
||||||
LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
|
uint64_t dlt = i2p::util::GetMillisecondsSinceEpoch () - timestamp;
|
||||||
|
LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", dlt, " milliseconds");
|
||||||
|
// update latency
|
||||||
|
uint64_t latency = dlt / 2;
|
||||||
|
test.first->AddLatencySample(latency);
|
||||||
|
test.second->AddLatencySample(latency);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -523,5 +532,37 @@ namespace tunnel
|
||||||
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
|
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
|
||||||
return m_CustomPeerSelector != nullptr;
|
return m_CustomPeerSelector != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<InboundTunnel> TunnelPool::GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude) const
|
||||||
|
{
|
||||||
|
std::shared_ptr<InboundTunnel> tun = nullptr;
|
||||||
|
std::unique_lock<std::mutex> lock(m_InboundTunnelsMutex);
|
||||||
|
uint64_t min = 1000000;
|
||||||
|
for (const auto & itr : m_InboundTunnels) {
|
||||||
|
if(!itr->LatencyIsKnown()) continue;
|
||||||
|
auto l = itr->GetMeanLatency();
|
||||||
|
if (l >= min) continue;
|
||||||
|
tun = itr;
|
||||||
|
if(tun == exclude) continue;
|
||||||
|
min = l;
|
||||||
|
}
|
||||||
|
return tun;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<OutboundTunnel> TunnelPool::GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude) const
|
||||||
|
{
|
||||||
|
std::shared_ptr<OutboundTunnel> tun = nullptr;
|
||||||
|
std::unique_lock<std::mutex> lock(m_OutboundTunnelsMutex);
|
||||||
|
uint64_t min = 1000000;
|
||||||
|
for (const auto & itr : m_OutboundTunnels) {
|
||||||
|
if(!itr->LatencyIsKnown()) continue;
|
||||||
|
auto l = itr->GetMeanLatency();
|
||||||
|
if (l >= min) continue;
|
||||||
|
tun = itr;
|
||||||
|
if(tun == exclude) continue;
|
||||||
|
min = l;
|
||||||
|
}
|
||||||
|
return tun;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
TunnelPool.h
15
TunnelPool.h
|
@ -69,6 +69,17 @@ namespace tunnel
|
||||||
void SetCustomPeerSelector(TunnelPeerSelector selector);
|
void SetCustomPeerSelector(TunnelPeerSelector selector);
|
||||||
void UnsetCustomPeerSelector();
|
void UnsetCustomPeerSelector();
|
||||||
bool HasCustomPeerSelector();
|
bool HasCustomPeerSelector();
|
||||||
|
|
||||||
|
/** @brief make this tunnel pool yield tunnels that fit latency range [min, max] */
|
||||||
|
void RequireLatency(uint64_t min, uint64_t max) { m_MinLatency = min; m_MaxLatency = max; }
|
||||||
|
|
||||||
|
/** @brief return true if this tunnel pool has a latency requirement */
|
||||||
|
bool HasLatencyRequriement() const { return m_MinLatency > 0 && m_MaxLatency > 0; }
|
||||||
|
|
||||||
|
/** @brief get the lowest latency tunnel in this tunnel pool regardless of latency requirements */
|
||||||
|
std::shared_ptr<InboundTunnel> GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude=nullptr) const;
|
||||||
|
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude=nullptr) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateInboundTunnel ();
|
void CreateInboundTunnel ();
|
||||||
|
@ -94,6 +105,10 @@ namespace tunnel
|
||||||
bool m_IsActive;
|
bool m_IsActive;
|
||||||
std::mutex m_CustomPeerSelectorMutex;
|
std::mutex m_CustomPeerSelectorMutex;
|
||||||
TunnelPeerSelector m_CustomPeerSelector;
|
TunnelPeerSelector m_CustomPeerSelector;
|
||||||
|
|
||||||
|
uint64_t m_MinLatency=0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms
|
||||||
|
uint64_t m_MaxLatency=0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
|
|
Loading…
Reference in a new issue