Merge pull request #843 from majestrate/obep-ibgw

Allow point to point client tunnels to use OB tunnels that share OBEP and IBGW of remote destination
pull/844/head
orignal 7 years ago committed by GitHub
commit 36ea6c13df

@ -10,20 +10,21 @@
#include "ClientContext.h" #include "ClientContext.h"
#include "SOCKS.h" #include "SOCKS.h"
#include "WebSocks.h" #include "WebSocks.h"
#include "MatchedDestination.h"
namespace i2p namespace i2p
{ {
namespace client namespace client
{ {
ClientContext context; ClientContext context;
ClientContext::ClientContext (): m_SharedLocalDestination (nullptr), ClientContext::ClientContext (): m_SharedLocalDestination (nullptr),
m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr), m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr),
m_BOBCommandChannel (nullptr), m_I2CPServer (nullptr) m_BOBCommandChannel (nullptr), m_I2CPServer (nullptr)
{ {
} }
ClientContext::~ClientContext () ClientContext::~ClientContext ()
{ {
delete m_HttpProxy; delete m_HttpProxy;
delete m_SocksProxy; delete m_SocksProxy;
@ -31,20 +32,20 @@ namespace client
delete m_BOBCommandChannel; delete m_BOBCommandChannel;
delete m_I2CPServer; delete m_I2CPServer;
} }
void ClientContext::Start () void ClientContext::Start ()
{ {
if (!m_SharedLocalDestination) if (!m_SharedLocalDestination)
{ {
m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination; m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination;
m_SharedLocalDestination->Start (); m_SharedLocalDestination->Start ();
} }
m_AddressBook.Start (); m_AddressBook.Start ();
std::shared_ptr<ClientDestination> localDestination; std::shared_ptr<ClientDestination> localDestination;
bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy); bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy);
if (httproxy) { if (httproxy) {
std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys); std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys);
@ -60,7 +61,7 @@ namespace client
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
ReadI2CPOptionsFromConfig ("httpproxy.", params); ReadI2CPOptionsFromConfig ("httpproxy.", params);
localDestination = CreateNewLocalDestination (keys, false, &params); localDestination = CreateNewLocalDestination (keys, false, &params);
} }
else else
LogPrint(eLogError, "Clients: failed to load HTTP Proxy key"); LogPrint(eLogError, "Clients: failed to load HTTP Proxy key");
} }
@ -71,10 +72,10 @@ namespace client
LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what()); LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what());
} }
} }
localDestination = nullptr; localDestination = nullptr;
bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy); bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy);
if (socksproxy) if (socksproxy)
{ {
std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys); std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys);
std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr); std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr);
@ -104,8 +105,8 @@ namespace client
} }
// I2P tunnels // I2P tunnels
ReadTunnels (); ReadTunnels ();
// SAM // SAM
bool sam; i2p::config::GetOption("sam.enabled", sam); bool sam; i2p::config::GetOption("sam.enabled", sam);
if (sam) { if (sam) {
@ -118,7 +119,7 @@ namespace client
} catch (std::exception& e) { } catch (std::exception& e) {
LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what()); LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what());
} }
} }
// BOB // BOB
bool bob; i2p::config::GetOption("bob.enabled", bob); bool bob; i2p::config::GetOption("bob.enabled", bob);
@ -132,27 +133,27 @@ namespace client
} catch (std::exception& e) { } catch (std::exception& e) {
LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what()); LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what());
} }
} }
// I2CP // I2CP
bool i2cp; i2p::config::GetOption("i2cp.enabled", i2cp); bool i2cp; i2p::config::GetOption("i2cp.enabled", i2cp);
if (i2cp) if (i2cp)
{ {
std::string i2cpAddr; i2p::config::GetOption("i2cp.address", i2cpAddr); std::string i2cpAddr; i2p::config::GetOption("i2cp.address", i2cpAddr);
uint16_t i2cpPort; i2p::config::GetOption("i2cp.port", i2cpPort); uint16_t i2cpPort; i2p::config::GetOption("i2cp.port", i2cpPort);
LogPrint(eLogInfo, "Clients: starting I2CP at ", i2cpAddr, ":", i2cpPort); LogPrint(eLogInfo, "Clients: starting I2CP at ", i2cpAddr, ":", i2cpPort);
try try
{ {
m_I2CPServer = new I2CPServer (i2cpAddr, i2cpPort); m_I2CPServer = new I2CPServer (i2cpAddr, i2cpPort);
m_I2CPServer->Start (); m_I2CPServer->Start ();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in I2CP: ", e.what()); LogPrint(eLogError, "Clients: Exception in I2CP: ", e.what());
} }
} }
m_AddressBook.StartResolvers (); m_AddressBook.StartResolvers ();
// start UDP cleanup // start UDP cleanup
if (!m_ServerForwards.empty ()) if (!m_ServerForwards.empty ())
@ -161,7 +162,7 @@ namespace client
ScheduleCleanupUDP(); ScheduleCleanupUDP();
} }
} }
void ClientContext::Stop () void ClientContext::Stop ()
{ {
if (m_HttpProxy) if (m_HttpProxy)
@ -185,28 +186,28 @@ namespace client
LogPrint(eLogInfo, "Clients: stopping I2P client tunnel on port ", it.first); LogPrint(eLogInfo, "Clients: stopping I2P client tunnel on port ", it.first);
it.second->Stop (); it.second->Stop ();
} }
m_ClientTunnels.clear (); m_ClientTunnels.clear ();
for (auto& it: m_ServerTunnels) for (auto& it: m_ServerTunnels)
{ {
LogPrint(eLogInfo, "Clients: stopping I2P server tunnel"); LogPrint(eLogInfo, "Clients: stopping I2P server tunnel");
it.second->Stop (); it.second->Stop ();
} }
m_ServerTunnels.clear (); m_ServerTunnels.clear ();
if (m_SamBridge) if (m_SamBridge)
{ {
LogPrint(eLogInfo, "Clients: stopping SAM bridge"); LogPrint(eLogInfo, "Clients: stopping SAM bridge");
m_SamBridge->Stop (); m_SamBridge->Stop ();
delete m_SamBridge; delete m_SamBridge;
m_SamBridge = nullptr; m_SamBridge = nullptr;
} }
if (m_BOBCommandChannel) if (m_BOBCommandChannel)
{ {
LogPrint(eLogInfo, "Clients: stopping BOB command channel"); LogPrint(eLogInfo, "Clients: stopping BOB command channel");
m_BOBCommandChannel->Stop (); m_BOBCommandChannel->Stop ();
delete m_BOBCommandChannel; delete m_BOBCommandChannel;
m_BOBCommandChannel = nullptr; m_BOBCommandChannel = nullptr;
} }
@ -214,7 +215,7 @@ namespace client
{ {
LogPrint(eLogInfo, "Clients: stopping I2CP"); LogPrint(eLogInfo, "Clients: stopping I2CP");
m_I2CPServer->Stop (); m_I2CPServer->Stop ();
delete m_I2CPServer; delete m_I2CPServer;
m_I2CPServer = nullptr; m_I2CPServer = nullptr;
} }
@ -226,18 +227,18 @@ namespace client
m_ServerForwards.clear(); m_ServerForwards.clear();
m_ClientForwards.clear(); m_ClientForwards.clear();
} }
if (m_CleanupUDPTimer) if (m_CleanupUDPTimer)
{ {
m_CleanupUDPTimer->cancel (); m_CleanupUDPTimer->cancel ();
m_CleanupUDPTimer = nullptr; m_CleanupUDPTimer = nullptr;
} }
for (auto& it: m_Destinations) for (auto& it: m_Destinations)
it.second->Stop (); it.second->Stop ();
m_Destinations.clear (); m_Destinations.clear ();
m_SharedLocalDestination = nullptr; m_SharedLocalDestination = nullptr;
} }
void ClientContext::ReloadConfig () void ClientContext::ReloadConfig ()
{ {
@ -246,14 +247,14 @@ namespace client
Stop(); Stop();
Start(); Start();
} }
bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType) bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType)
{ {
bool success = true; bool success = true;
std::string fullPath = i2p::fs::DataDirPath (filename); std::string fullPath = i2p::fs::DataDirPath (filename);
std::ifstream s(fullPath, std::ifstream::binary); std::ifstream s(fullPath, std::ifstream::binary);
if (s.is_open ()) if (s.is_open ())
{ {
s.seekg (0, std::ios::end); s.seekg (0, std::ios::end);
size_t len = s.tellg(); size_t len = s.tellg();
s.seekg (0, std::ios::beg); s.seekg (0, std::ios::beg);
@ -267,18 +268,18 @@ namespace client
else else
LogPrint (eLogInfo, "Clients: Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded"); LogPrint (eLogInfo, "Clients: Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded");
delete[] buf; delete[] buf;
} }
else else
{ {
LogPrint (eLogError, "Clients: can't open file ", fullPath, " Creating new one with signature type ", sigType); LogPrint (eLogError, "Clients: can't open file ", fullPath, " Creating new one with signature type ", sigType);
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType); keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
size_t len = keys.GetFullLen (); size_t len = keys.GetFullLen ();
uint8_t * buf = new uint8_t[len]; uint8_t * buf = new uint8_t[len];
len = keys.ToBuffer (buf, len); len = keys.ToBuffer (buf, len);
f.write ((char *)buf, len); f.write ((char *)buf, len);
delete[] buf; delete[] buf;
LogPrint (eLogInfo, "Clients: New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created"); LogPrint (eLogInfo, "Clients: New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
} }
return success; return success;
@ -306,9 +307,9 @@ namespace client
} }
return infos; return infos;
} }
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType, std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
const std::map<std::string, std::string> * params) const std::map<std::string, std::string> * params)
{ {
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType); i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params); auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
@ -318,6 +319,16 @@ namespace client
return localDestination; return localDestination;
} }
std::shared_ptr<ClientDestination> ClientContext::CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params)
{
MatchedTunnelDestination * cl = new MatchedTunnelDestination(keys, name, params);
auto localDestination = std::shared_ptr<ClientDestination>(cl);
std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
localDestination->Start ();
return localDestination;
}
void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination) void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination)
{ {
if (!destination) return; if (!destination) return;
@ -328,7 +339,7 @@ namespace client
{ {
std::unique_lock<std::mutex> l(m_DestinationsMutex); std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations.erase (it); m_Destinations.erase (it);
} }
d->Stop (); d->Stop ();
} }
} }
@ -341,32 +352,32 @@ namespace client
{ {
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists"); LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
if (!it->second->IsRunning ()) if (!it->second->IsRunning ())
{ {
it->second->Start (); it->second->Start ();
return it->second; return it->second;
} }
return nullptr; return nullptr;
} }
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params); auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
std::unique_lock<std::mutex> l(m_DestinationsMutex); std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[keys.GetPublic ()->GetIdentHash ()] = localDestination; m_Destinations[keys.GetPublic ()->GetIdentHash ()] = localDestination;
localDestination->Start (); localDestination->Start ();
return localDestination; return localDestination;
} }
std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
{ {
auto it = m_Destinations.find (destination); auto it = m_Destinations.find (destination);
if (it != m_Destinations.end ()) if (it != m_Destinations.end ())
return it->second; return it->second;
return nullptr; return nullptr;
} }
template<typename Section, typename Type> template<typename Section, typename Type>
std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
{ {
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value)); return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value));
} }
template<typename Section> template<typename Section>
void ClientContext::ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const void ClientContext::ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const
@ -378,24 +389,24 @@ namespace client
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_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); 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
{ {
std::string value; std::string value;
if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNEL_LENGTH, value)) if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNEL_LENGTH, value))
options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = value; options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = value;
if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, value)) if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, value))
options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = value; options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = value;
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)) if (i2p::config::GetOption(prefix + I2CP_PARAM_MIN_TUNNEL_LATENCY, value))
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value; options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value;
if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value)) if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value))
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value; options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value;
} }
void ClientContext::ReadTunnels () void ClientContext::ReadTunnels ()
{ {
@ -411,20 +422,20 @@ namespace client
} }
} }
LogPrint(eLogDebug, "FS: tunnels config file: ", tunConf); LogPrint(eLogDebug, "FS: tunnels config file: ", tunConf);
try try
{ {
boost::property_tree::read_ini (tunConf, pt); boost::property_tree::read_ini (tunConf, pt);
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ()); LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ());
return; return;
} }
int numClientTunnels = 0, numServerTunnels = 0; int numClientTunnels = 0, numServerTunnels = 0;
for (auto& section: pt) for (auto& section: pt)
{ {
std::string name = section.first; std::string name = section.first;
try try
{ {
std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE); std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE);
@ -440,13 +451,14 @@ namespace client
dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION); dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION);
int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT); int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
// optional params // optional params
bool matchTunnels = section.second.get(I2P_CLIENT_TUNNEL_MATCH_TUNNELS, false);
std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, ""); std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "");
std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1"); std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
// I2CP // I2CP
std::map<std::string, std::string> options; std::map<std::string, std::string> options;
ReadI2CPOptions (section, options); ReadI2CPOptions (section, options);
std::shared_ptr<ClientDestination> localDestination = nullptr; std::shared_ptr<ClientDestination> localDestination = nullptr;
if (keys.length () > 0) if (keys.length () > 0)
@ -456,9 +468,15 @@ namespace client
{ {
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
if (!localDestination) if (!localDestination)
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options); {
if(matchTunnels)
localDestination = CreateNewMatchedTunnelDestination(k, dest, &options);
else
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options);
}
} }
} }
if (type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) { if (type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) {
// udp client // udp client
// TODO: hostnames // TODO: hostnames
@ -515,7 +533,7 @@ namespace client
|| type == I2P_TUNNELS_SECTION_TYPE_HTTP || type == I2P_TUNNELS_SECTION_TYPE_HTTP
|| type == I2P_TUNNELS_SECTION_TYPE_IRC || type == I2P_TUNNELS_SECTION_TYPE_IRC
|| type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) || type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER)
{ {
// mandatory params // mandatory params
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST); std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
int port = section.second.get<int> (I2P_SERVER_TUNNEL_PORT); int port = section.second.get<int> (I2P_SERVER_TUNNEL_PORT);
@ -532,15 +550,15 @@ namespace client
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
// I2CP // I2CP
std::map<std::string, std::string> options; std::map<std::string, std::string> options;
ReadI2CPOptions (section, options); ReadI2CPOptions (section, options);
std::shared_ptr<ClientDestination> localDestination = nullptr; std::shared_ptr<ClientDestination> localDestination = nullptr;
i2p::data::PrivateKeys k; i2p::data::PrivateKeys k;
if(!LoadPrivateKeys (k, keys, sigType)) if(!LoadPrivateKeys (k, keys, sigType))
continue; continue;
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
if (!localDestination) if (!localDestination)
localDestination = CreateNewLocalDestination (k, true, &options); localDestination = CreateNewLocalDestination (k, true, &options);
if (type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) if (type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER)
{ {
@ -549,7 +567,7 @@ namespace client
auto localAddress = boost::asio::ip::address::from_string(address); auto localAddress = boost::asio::ip::address::from_string(address);
boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port); boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
I2PUDPServerTunnel * serverTunnel = new I2PUDPServerTunnel(name, localDestination, localAddress, endpoint, port); I2PUDPServerTunnel * serverTunnel = new I2PUDPServerTunnel(name, localDestination, localAddress, endpoint, port);
if(!isUniqueLocal) if(!isUniqueLocal)
{ {
LogPrint(eLogInfo, "Clients: disabling loopback address mapping"); LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
serverTunnel->SetUniqueLocal(isUniqueLocal); serverTunnel->SetUniqueLocal(isUniqueLocal);
@ -566,10 +584,10 @@ namespace client
} }
else else
LogPrint(eLogError, "Clients: I2P Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, "already exists"); LogPrint(eLogError, "Clients: I2P Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, "already exists");
continue; continue;
} }
I2PServerTunnel * serverTunnel; I2PServerTunnel * serverTunnel;
if (type == I2P_TUNNELS_SECTION_TYPE_HTTP) if (type == I2P_TUNNELS_SECTION_TYPE_HTTP)
serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip); serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip);
@ -594,7 +612,7 @@ namespace client
{ {
comma = accessList.find (',', pos); comma = accessList.find (',', pos);
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos)); ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
idents.insert (ident); idents.insert (ident);
pos = comma + 1; pos = comma + 1;
} }
@ -602,7 +620,7 @@ namespace client
serverTunnel->SetAccessList (idents); serverTunnel->SetAccessList (idents);
} }
if (m_ServerTunnels.insert (std::make_pair ( if (m_ServerTunnels.insert (std::make_pair (
std::make_pair (localDestination->GetIdentHash (), inPort), std::make_pair (localDestination->GetIdentHash (), inPort),
std::unique_ptr<I2PServerTunnel>(serverTunnel))).second) std::unique_ptr<I2PServerTunnel>(serverTunnel))).second)
{ {
serverTunnel->Start (); serverTunnel->Start ();
@ -610,21 +628,21 @@ namespace client
} }
else else
LogPrint (eLogError, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists"); LogPrint (eLogError, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists");
} }
else else
LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", tunConf); LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", tunConf);
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ()); LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ());
} }
} }
LogPrint (eLogInfo, "Clients: ", numClientTunnels, " I2P client tunnels created"); LogPrint (eLogInfo, "Clients: ", numClientTunnels, " I2P client tunnels created");
LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created"); LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created");
} }
void ClientContext::ScheduleCleanupUDP() void ClientContext::ScheduleCleanupUDP()
{ {
if (m_CleanupUDPTimer) if (m_CleanupUDPTimer)
@ -644,5 +662,5 @@ namespace client
ScheduleCleanupUDP(); ScheduleCleanupUDP();
} }
} }
} }
} }

@ -34,19 +34,21 @@ namespace client
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination"; const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
const char I2P_CLIENT_TUNNEL_KEYS[] = "keys"; const char I2P_CLIENT_TUNNEL_KEYS[] = "keys";
const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype"; const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport"; const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
const char I2P_SERVER_TUNNEL_HOST[] = "host"; const char I2P_CLIENT_TUNNEL_MATCH_TUNNELS[] = "matchtunnels";
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride"; const char I2P_SERVER_TUNNEL_HOST[] = "host";
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride";
const char I2P_SERVER_TUNNEL_PORT[] = "port"; const char I2P_SERVER_TUNNEL_PORT[] = "port";
const char I2P_SERVER_TUNNEL_KEYS[] = "keys"; const char I2P_SERVER_TUNNEL_KEYS[] = "keys";
const char I2P_SERVER_TUNNEL_SIGNATURE_TYPE[] = "signaturetype"; const char I2P_SERVER_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
const char I2P_SERVER_TUNNEL_INPORT[] = "inport"; const char I2P_SERVER_TUNNEL_INPORT[] = "inport";
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist"; const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
const char I2P_SERVER_TUNNEL_GZIP[] = "gzip"; const char I2P_SERVER_TUNNEL_GZIP[] = "gzip";
const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword"; const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword";
const char I2P_SERVER_TUNNEL_ADDRESS[] = "address"; const char I2P_SERVER_TUNNEL_ADDRESS[] = "address";
const char I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL[] = "enableuniquelocal"; const char I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL[] = "enableuniquelocal";
class ClientContext class ClientContext
{ {
public: public:
@ -62,10 +64,11 @@ namespace client
std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; }; std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; };
std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1, std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1,
const std::map<std::string, std::string> * params = nullptr); // transient const std::map<std::string, std::string> * params = nullptr); // transient
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true, std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
const std::map<std::string, std::string> * params = nullptr); const std::map<std::string, std::string> * params = nullptr);
std::shared_ptr<ClientDestination> CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params = nullptr);
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination); void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const; std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
AddressBook& GetAddressBook () { return m_AddressBook; }; AddressBook& GetAddressBook () { return m_AddressBook; };
@ -81,16 +84,16 @@ namespace client
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const; std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const;
template<typename Section> template<typename Section>
void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const; void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const;
void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const; void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const;
void CleanupUDP(const boost::system::error_code & ecode); void CleanupUDP(const boost::system::error_code & ecode);
void ScheduleCleanupUDP(); void ScheduleCleanupUDP();
private: private:
std::mutex m_DestinationsMutex; std::mutex m_DestinationsMutex;
std::map<i2p::data::IdentHash, std::shared_ptr<ClientDestination> > m_Destinations; std::map<i2p::data::IdentHash, std::shared_ptr<ClientDestination> > m_Destinations;
std::shared_ptr<ClientDestination> m_SharedLocalDestination; std::shared_ptr<ClientDestination> m_SharedLocalDestination;
AddressBook m_AddressBook; AddressBook m_AddressBook;
@ -99,16 +102,16 @@ namespace client
std::map<boost::asio::ip::tcp::endpoint, std::unique_ptr<I2PService> > m_ClientTunnels; // local endpoint->tunnel std::map<boost::asio::ip::tcp::endpoint, std::unique_ptr<I2PService> > m_ClientTunnels; // local endpoint->tunnel
std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
std::mutex m_ForwardsMutex; std::mutex m_ForwardsMutex;
std::map<boost::asio::ip::udp::endpoint, std::unique_ptr<I2PUDPClientTunnel> > m_ClientForwards; // local endpoint -> udp tunnel std::map<boost::asio::ip::udp::endpoint, std::unique_ptr<I2PUDPClientTunnel> > m_ClientForwards; // local endpoint -> udp tunnel
std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PUDPServerTunnel> > m_ServerForwards; // <destination,port> -> udp tunnel std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PUDPServerTunnel> > m_ServerForwards; // <destination,port> -> udp tunnel
SAMBridge * m_SamBridge; SAMBridge * m_SamBridge;
BOBCommandChannel * m_BOBCommandChannel; BOBCommandChannel * m_BOBCommandChannel;
I2CPServer * m_I2CPServer; I2CPServer * m_I2CPServer;
std::unique_ptr<boost::asio::deadline_timer> m_CleanupUDPTimer; std::unique_ptr<boost::asio::deadline_timer> m_CleanupUDPTimer;
public: public:
// for HTTP // for HTTP
const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; }; const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; };
@ -119,9 +122,9 @@ namespace client
const i2p::proxy::HTTPProxy * GetHttpProxy () const { return m_HttpProxy; } const i2p::proxy::HTTPProxy * GetHttpProxy () const { return m_HttpProxy; }
const i2p::proxy::SOCKSProxy * GetSocksProxy () const { return m_SocksProxy; } const i2p::proxy::SOCKSProxy * GetSocksProxy () const { return m_SocksProxy; }
}; };
extern ClientContext context; extern ClientContext context;
} }
} }
#endif #endif

@ -19,7 +19,7 @@ namespace client
} }
namespace datagram namespace datagram
{ {
// milliseconds for max session idle time // milliseconds for max session idle time
const uint64_t DATAGRAM_SESSION_MAX_IDLE = 10 * 60 * 1000; const uint64_t DATAGRAM_SESSION_MAX_IDLE = 10 * 60 * 1000;
// milliseconds for how long we try sticking to a dead routing path before trying to switch // milliseconds for how long we try sticking to a dead routing path before trying to switch
const uint64_t DATAGRAM_SESSION_PATH_TIMEOUT = 10 * 1000; const uint64_t DATAGRAM_SESSION_PATH_TIMEOUT = 10 * 1000;
@ -33,14 +33,14 @@ namespace datagram
const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000; const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000;
// max 64 messages buffered in send queue for each datagram session // max 64 messages buffered in send queue for each datagram session
const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64; const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64;
class DatagramSession : public std::enable_shared_from_this<DatagramSession> class DatagramSession : public std::enable_shared_from_this<DatagramSession>
{ {
public: public:
DatagramSession(i2p::client::ClientDestination * localDestination, const i2p::data::IdentHash & remoteIdent); DatagramSession(i2p::client::ClientDestination * localDestination, const i2p::data::IdentHash & remoteIdent);
void Start (); void Start ();
void Stop (); void Stop ();
/** @brief ack the garlic routing path */ /** @brief ack the garlic routing path */
@ -56,7 +56,7 @@ namespace datagram
std::shared_ptr<const i2p::data::IdentHash> IBGW; std::shared_ptr<const i2p::data::IdentHash> IBGW;
std::shared_ptr<const i2p::data::IdentHash> OBEP; std::shared_ptr<const i2p::data::IdentHash> OBEP;
const uint64_t activity; const uint64_t activity;
Info() : IBGW(nullptr), OBEP(nullptr), activity(0) {} Info() : IBGW(nullptr), OBEP(nullptr), activity(0) {}
Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a) : Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a) :
activity(a) { activity(a) {
@ -77,7 +77,7 @@ namespace datagram
void HandleSend(std::shared_ptr<I2NPMessage> msg); void HandleSend(std::shared_ptr<I2NPMessage> msg);
std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath(); std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath();
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls); void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
private: private:
@ -95,16 +95,16 @@ namespace datagram
typedef std::shared_ptr<DatagramSession> DatagramSession_ptr; typedef std::shared_ptr<DatagramSession> DatagramSession_ptr;
const size_t MAX_DATAGRAM_SIZE = 32768; const size_t MAX_DATAGRAM_SIZE = 32768;
class DatagramDestination class DatagramDestination
{ {
typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver; typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver;
public: public:
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner); DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
~DatagramDestination (); ~DatagramDestination ();
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
@ -116,21 +116,21 @@ namespace datagram
void ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); }; void ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); };
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote); std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote);
// clean up stale sessions // clean up stale sessions
void CleanUp (); void CleanUp ();
private: private:
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident); std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
/** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */ /** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */
Receiver FindReceiver(uint16_t port); Receiver FindReceiver(uint16_t port);
private: private:
i2p::client::ClientDestination * m_Owner; i2p::client::ClientDestination * m_Owner;
i2p::data::IdentityEx m_Identity; i2p::data::IdentityEx m_Identity;
@ -142,9 +142,8 @@ namespace datagram
i2p::data::GzipInflator m_Inflator; i2p::data::GzipInflator m_Inflator;
i2p::data::GzipDeflator m_Deflator; i2p::data::GzipDeflator m_Deflator;
}; };
} }
} }
#endif #endif

@ -27,16 +27,16 @@ namespace client
{ {
const uint8_t PROTOCOL_TYPE_STREAMING = 6; const uint8_t PROTOCOL_TYPE_STREAMING = 6;
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17; const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
const uint8_t PROTOCOL_TYPE_RAW = 18; const uint8_t PROTOCOL_TYPE_RAW = 18;
const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successfull publish const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successfull publish
const int PUBLISH_MIN_INTERVAL = 20; // in seconds const int PUBLISH_MIN_INTERVAL = 20; // in seconds
const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
const int DESTINATION_CLEANUP_TIMEOUT = 3; // in minutes const int DESTINATION_CLEANUP_TIMEOUT = 3; // in minutes
const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7; const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
// I2CP // I2CP
const char I2CP_PARAM_INBOUND_TUNNEL_LENGTH[] = "inbound.length"; const char I2CP_PARAM_INBOUND_TUNNEL_LENGTH[] = "inbound.length";
const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3; const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3;
@ -56,7 +56,7 @@ namespace client
const int DEFAULT_MIN_TUNNEL_LATENCY = 0; const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
const char I2CP_PARAM_MAX_TUNNEL_LATENCY[] = "latency.max"; const char I2CP_PARAM_MAX_TUNNEL_LATENCY[] = "latency.max";
const int DEFAULT_MAX_TUNNEL_LATENCY = 0; 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,
@ -78,24 +78,24 @@ namespace client
{ {
for (auto& it: requestComplete) it (ls); for (auto& it: requestComplete) it (ls);
requestComplete.clear (); requestComplete.clear ();
} }
}; };
public: public:
LeaseSetDestination (bool isPublic, const std::map<std::string, std::string> * params = nullptr); LeaseSetDestination (bool isPublic, const std::map<std::string, std::string> * params = nullptr);
~LeaseSetDestination (); ~LeaseSetDestination ();
virtual bool Start (); virtual bool Start ();
virtual bool Stop (); virtual bool Stop ();
bool IsRunning () const { return m_IsRunning; }; bool IsRunning () const { return m_IsRunning; };
boost::asio::io_service& GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; }; std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; }; bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; };
std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident); std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr); bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true); void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true);
// implements GarlicDestination // implements GarlicDestination
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet (); std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
@ -105,7 +105,7 @@ namespace client
// override GarlicDestination // override GarlicDestination
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void SetLeaseSetUpdated (); void SetLeaseSetUpdated ();
protected: protected:
@ -115,10 +115,10 @@ namespace client
// I2CP // I2CP
virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0; virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0;
virtual void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels) = 0; virtual void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels) = 0;
private: private:
void Run (); void Run ();
void UpdateLeaseSet (); void UpdateLeaseSet ();
void Publish (); void Publish ();
void HandlePublishConfirmationTimer (const boost::system::error_code& ecode); void HandlePublishConfirmationTimer (const boost::system::error_code& ecode);
@ -126,18 +126,18 @@ namespace client
void HandlePublishDelayTimer (const boost::system::error_code& ecode); void HandlePublishDelayTimer (const boost::system::error_code& ecode);
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len); void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete); void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete);
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request); bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest); void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
void HandleCleanupTimer (const boost::system::error_code& ecode); void HandleCleanupTimer (const boost::system::error_code& ecode);
void CleanupRemoteLeaseSets (); void CleanupRemoteLeaseSets ();
private: private:
volatile bool m_IsRunning; volatile bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
mutable std::mutex m_RemoteLeaseSetsMutex; mutable std::mutex m_RemoteLeaseSetsMutex;
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets; std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
@ -150,16 +150,16 @@ namespace client
uint32_t m_PublishReplyToken; uint32_t m_PublishReplyToken;
uint64_t m_LastSubmissionTime; // in seconds uint64_t m_LastSubmissionTime; // in seconds
std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer, boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer,
m_PublishDelayTimer, m_CleanupTimer; m_PublishDelayTimer, m_CleanupTimer;
public: public:
// for HTTP only // for HTTP only
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); }; int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; }; const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; };
}; };
class ClientDestination: public LeaseSetDestination class ClientDestination: public LeaseSetDestination
{ {
@ -171,16 +171,16 @@ namespace client
// if cancelled before ready, informs promise with nullptr // if cancelled before ready, informs promise with nullptr
void Ready(ReadyPromise & p); void Ready(ReadyPromise & p);
#endif #endif
ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr); ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
~ClientDestination (); ~ClientDestination ();
bool Start (); virtual bool Start ();
bool Stop (); virtual bool Stop ();
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
// streaming // streaming
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const; std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
@ -191,31 +191,31 @@ namespace client
void StopAcceptingStreams (); void StopAcceptingStreams ();
bool IsAcceptingStreams () const; bool IsAcceptingStreams () const;
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor); void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
// datagram // datagram
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
i2p::datagram::DatagramDestination * CreateDatagramDestination (); i2p::datagram::DatagramDestination * CreateDatagramDestination ();
// implements LocalDestination // implements LocalDestination
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); }; std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
protected: protected:
void CleanupDestination (); void CleanupDestination ();
// I2CP // I2CP
void HandleDataMessage (const uint8_t * buf, size_t len); void HandleDataMessage (const uint8_t * buf, size_t len);
void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels); void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
private: private:
std::shared_ptr<ClientDestination> GetSharedFromThis () std::shared_ptr<ClientDestination> GetSharedFromThis ()
{ return std::static_pointer_cast<ClientDestination>(shared_from_this ()); } { return std::static_pointer_cast<ClientDestination>(shared_from_this ()); }
void PersistTemporaryKeys (); void PersistTemporaryKeys ();
#ifdef I2LUA #ifdef I2LUA
void ScheduleCheckForReady(ReadyPromise * p); void ScheduleCheckForReady(ReadyPromise * p);
void HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p); void HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p);
#endif #endif
private: private:
i2p::data::PrivateKeys m_Keys; i2p::data::PrivateKeys m_Keys;
@ -226,13 +226,13 @@ namespace client
i2p::datagram::DatagramDestination * m_DatagramDestination; i2p::datagram::DatagramDestination * m_DatagramDestination;
boost::asio::deadline_timer m_ReadyChecker; boost::asio::deadline_timer m_ReadyChecker;
public: public:
// for HTTP only // for HTTP only
std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams () const; std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams () const;
}; };
} }
} }
#endif #endif

@ -19,9 +19,9 @@ namespace i2p
namespace client namespace client
{ {
const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 65536; const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 65536;
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
// for HTTP tunnels // for HTTP tunnels
const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64 const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64
const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64 const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64
const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address
@ -33,21 +33,21 @@ namespace client
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket, I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket, I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API
I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, std::shared_ptr<boost::asio::ip::tcp::socket> socket, I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P
~I2PTunnelConnection (); ~I2PTunnelConnection ();
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0); void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
void Connect (bool isUniqueLocal = true); void Connect (bool isUniqueLocal = true);
protected: protected:
void Terminate (); void Terminate ();
void Receive (); void Receive ();
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
virtual void Write (const uint8_t * buf, size_t len); // can be overloaded virtual void Write (const uint8_t * buf, size_t len); // can be overloaded
void HandleWrite (const boost::system::error_code& ecode); void HandleWrite (const boost::system::error_code& ecode);
void StreamReceive (); void StreamReceive ();
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@ -75,28 +75,28 @@ namespace client
protected: protected:
void Write (const uint8_t * buf, size_t len); void Write (const uint8_t * buf, size_t len);
private: private:
std::stringstream m_InHeader, m_OutHeader; std::stringstream m_InHeader, m_OutHeader;
bool m_HeaderSent, m_ConnectionSent, m_ProxyConnectionSent; bool m_HeaderSent, m_ConnectionSent, m_ProxyConnectionSent;
}; };
class I2PServerTunnelConnectionHTTP: public I2PTunnelConnection class I2PServerTunnelConnectionHTTP: public I2PTunnelConnection
{ {
public: public:
I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& host); const boost::asio::ip::tcp::endpoint& target, const std::string& host);
protected: protected:
void Write (const uint8_t * buf, size_t len); void Write (const uint8_t * buf, size_t len);
private: private:
std::string m_Host; std::string m_Host;
std::stringstream m_InHeader, m_OutHeader; std::stringstream m_InHeader, m_OutHeader;
bool m_HeaderSent; bool m_HeaderSent;
@ -106,21 +106,21 @@ namespace client
class I2PTunnelConnectionIRC: public I2PTunnelConnection class I2PTunnelConnectionIRC: public I2PTunnelConnection
{ {
public: public:
I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass); const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass);
protected: protected:
void Write (const uint8_t * buf, size_t len); void Write (const uint8_t * buf, size_t len);
private: private:
std::shared_ptr<const i2p::data::IdentityEx> m_From; std::shared_ptr<const i2p::data::IdentityEx> m_From;
std::stringstream m_OutPacket, m_InPacket; std::stringstream m_OutPacket, m_InPacket;
bool m_NeedsWebIrc; bool m_NeedsWebIrc;
std::string m_WebircPass; std::string m_WebircPass;
}; };
@ -133,24 +133,24 @@ namespace client
public: public:
I2PClientTunnel (const std::string& name, const std::string& destination, I2PClientTunnel (const std::string& name, const std::string& destination,
const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0); const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
~I2PClientTunnel () {} ~I2PClientTunnel () {}
void Start (); void Start ();
void Stop (); void Stop ();
const char* GetName() { return m_Name.c_str (); } const char* GetName() { return m_Name.c_str (); }
private: private:
const i2p::data::IdentHash * GetIdentHash (); const i2p::data::IdentHash * GetIdentHash ();
private: private:
std::string m_Name, m_Destination; std::string m_Name, m_Destination;
const i2p::data::IdentHash * m_DestinationIdentHash; const i2p::data::IdentHash * m_DestinationIdentHash;
int m_DestinationPort; int m_DestinationPort;
}; };
@ -173,7 +173,7 @@ namespace client
uint16_t RemotePort; uint16_t RemotePort;
uint8_t m_Buffer[I2P_UDP_MAX_MTU]; uint8_t m_Buffer[I2P_UDP_MAX_MTU];
UDPSession(boost::asio::ip::udp::endpoint localEndpoint, UDPSession(boost::asio::ip::udp::endpoint localEndpoint,
const std::shared_ptr<i2p::client::ClientDestination> & localDestination, const std::shared_ptr<i2p::client::ClientDestination> & localDestination,
boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash * ident, boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash * ident,
@ -182,7 +182,7 @@ namespace client
void Receive(); void Receive();
}; };
/** read only info about a datagram session */ /** read only info about a datagram session */
struct DatagramSessionInfo struct DatagramSessionInfo
{ {
@ -205,7 +205,7 @@ namespace client
}; };
typedef std::shared_ptr<UDPSession> UDPSessionPtr; typedef std::shared_ptr<UDPSession> UDPSessionPtr;
/** server side udp tunnel, many i2p inbound to 1 ip outbound */ /** server side udp tunnel, many i2p inbound to 1 ip outbound */
class I2PUDPServerTunnel class I2PUDPServerTunnel
{ {
@ -239,7 +239,7 @@ namespace client
std::shared_ptr<i2p::client::ClientDestination> m_LocalDest; std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
}; };
class I2PUDPClientTunnel class I2PUDPClientTunnel
{ {
public: public:
I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest, I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest,
@ -249,7 +249,7 @@ namespace client
void Start(); void Start();
const char * GetName() const { return m_Name.c_str(); } const char * GetName() const { return m_Name.c_str(); }
std::vector<std::shared_ptr<DatagramSessionInfo> > GetSessions(); std::vector<std::shared_ptr<DatagramSessionInfo> > GetSessions();
bool IsLocalDestination(const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); } bool IsLocalDestination(const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); }
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDest; } std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDest; }
@ -275,18 +275,18 @@ namespace client
uint16_t RemotePort; uint16_t RemotePort;
bool m_cancel_resolve; bool m_cancel_resolve;
}; };
class I2PServerTunnel: public I2PService class I2PServerTunnel: public I2PService
{ {
public: public:
I2PServerTunnel (const std::string& name, const std::string& address, int port, I2PServerTunnel (const std::string& name, const std::string& address, int port,
std::shared_ptr<ClientDestination> localDestination, int inport = 0, bool gzip = true); std::shared_ptr<ClientDestination> localDestination, int inport = 0, bool gzip = true);
void Start (); void Start ();
void Stop (); void Stop ();
void SetAccessList (const std::set<i2p::data::IdentHash>& accessList); void SetAccessList (const std::set<i2p::data::IdentHash>& accessList);
void SetUniqueLocal (bool isUniqueLocal) { m_IsUniqueLocal = isUniqueLocal; } void SetUniqueLocal (bool isUniqueLocal) { m_IsUniqueLocal = isUniqueLocal; }
bool IsUniqueLocal () const { return m_IsUniqueLocal; } bool IsUniqueLocal () const { return m_IsUniqueLocal; }
@ -296,13 +296,13 @@ namespace client
uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); }; uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); };
const boost::asio::ip::tcp::endpoint& GetEndpoint () const { return m_Endpoint; } const boost::asio::ip::tcp::endpoint& GetEndpoint () const { return m_Endpoint; }
const char* GetName() { return m_Name.c_str (); } const char* GetName() { return m_Name.c_str (); }
void SetMaxConnsPerMinute(const uint32_t conns) { m_PortDestination->SetMaxConnsPerMinute(conns); } void SetMaxConnsPerMinute(const uint32_t conns) { m_PortDestination->SetMaxConnsPerMinute(conns); }
private: private:
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver); std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
void Accept (); void Accept ();
@ -310,11 +310,11 @@ namespace client
virtual std::shared_ptr<I2PTunnelConnection> CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream); virtual std::shared_ptr<I2PTunnelConnection> CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
private: private:
bool m_IsUniqueLocal; bool m_IsUniqueLocal;
std::string m_Name, m_Address; std::string m_Name, m_Address;
int m_Port; int m_Port;
boost::asio::ip::tcp::endpoint m_Endpoint; boost::asio::ip::tcp::endpoint m_Endpoint;
std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination; std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination;
std::set<i2p::data::IdentHash> m_AccessList; std::set<i2p::data::IdentHash> m_AccessList;
bool m_IsAccessList; bool m_IsAccessList;
@ -324,9 +324,9 @@ namespace client
{ {
public: public:
I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port, I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port,
std::shared_ptr<ClientDestination> localDestination, const std::string& host, std::shared_ptr<ClientDestination> localDestination, const std::string& host,
int inport = 0, bool gzip = true); int inport = 0, bool gzip = true);
private: private:
@ -336,14 +336,14 @@ namespace client
std::string m_Host; std::string m_Host;
}; };
class I2PServerTunnelIRC: public I2PServerTunnel class I2PServerTunnelIRC: public I2PServerTunnel
{ {
public: public:
I2PServerTunnelIRC (const std::string& name, const std::string& address, int port, I2PServerTunnelIRC (const std::string& name, const std::string& address, int port,
std::shared_ptr<ClientDestination> localDestination, const std::string& webircpass, std::shared_ptr<ClientDestination> localDestination, const std::string& webircpass,
int inport = 0, bool gzip = true); int inport = 0, bool gzip = true);
private: private:
@ -355,6 +355,6 @@ namespace client
}; };
} }
} }
#endif #endif

@ -12,7 +12,7 @@ INCFLAGS ?=
# detect proper flag for c++11 support by compilers # detect proper flag for c++11 support by compilers
CXXVER := $(shell $(CXX) -dumpversion) CXXVER := $(shell $(CXX) -dumpversion)
ifeq ($(shell expr match $(CXX) 'clang'),5) ifeq ($(shell expr match $(CXX) 'clang'),5)
NEEDED_CXXFLAGS += -std=c++11 NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10 else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
NEEDED_CXXFLAGS += -std=c++11 NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7 else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7

@ -0,0 +1,113 @@
#include "MatchedDestination.h"
#include "Log.h"
#include "ClientContext.h"
namespace i2p
{
namespace client
{
MatchedTunnelDestination::MatchedTunnelDestination(const i2p::data::PrivateKeys & keys, const std::string & remoteName, const std::map<std::string, std::string> * params)
: ClientDestination(keys, false, params),
m_RemoteName(remoteName) {}
void MatchedTunnelDestination::ResolveCurrentLeaseSet()
{
if(i2p::client::context.GetAddressBook().GetIdentHash(m_RemoteName, m_RemoteIdent))
{
auto ls = FindLeaseSet(m_RemoteIdent);
if(ls)
{
HandleFoundCurrentLeaseSet(ls);
}
else
RequestDestination(m_RemoteIdent, std::bind(&MatchedTunnelDestination::HandleFoundCurrentLeaseSet, this, std::placeholders::_1));
}
else
LogPrint(eLogWarning, "Destination: failed to resolve ", m_RemoteName);
}
void MatchedTunnelDestination::HandleFoundCurrentLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> ls)
{
if(ls)
{
LogPrint(eLogDebug, "Destination: resolved remote lease set for ", m_RemoteName);
m_RemoteLeaseSet = ls;
}
else
{
m_ResolveTimer->expires_from_now(boost::posix_time::seconds(1));
m_ResolveTimer->async_wait([&](const boost::system::error_code & ec) {
if(!ec) ResolveCurrentLeaseSet();
});
}
}
bool MatchedTunnelDestination::Start()
{
if(ClientDestination::Start())
{
m_ResolveTimer = std::make_shared<boost::asio::deadline_timer>(GetService());
GetTunnelPool()->SetCustomPeerSelector(this);
ResolveCurrentLeaseSet();
return true;
}
else
return false;
}
bool MatchedTunnelDestination::Stop()
{
if(ClientDestination::Stop())
{
if(m_ResolveTimer)
m_ResolveTimer->cancel();
return true;
}
else
return false;
}
bool MatchedTunnelDestination::SelectPeers(i2p::tunnel::Path & path, int hops, bool inbound)
{
auto pool = GetTunnelPool();
if(!i2p::tunnel::StandardSelectPeers(path, hops, inbound, std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1)))
return false;
// more here for outbound tunnels
if(!inbound && m_RemoteLeaseSet)
{
if(m_RemoteLeaseSet->IsExpired())
{
ResolveCurrentLeaseSet();
}
if(m_RemoteLeaseSet && !m_RemoteLeaseSet->IsExpired())
{
// remote lease set is good
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases();
// pick lease
std::shared_ptr<i2p::data::RouterInfo> obep;
while(!obep && leases.size() > 0) {
auto idx = rand() % leases.size();
auto lease = leases[idx];
obep = i2p::data::netdb.FindRouter(lease->tunnelGateway);
leases.erase(leases.begin()+idx);
}
if(obep) {
path.push_back(obep->GetRouterIdentity());
LogPrint(eLogDebug, "Destination: found OBEP matching IBGW");
} else
LogPrint(eLogWarning, "Destination: could not find proper IBGW for matched outbound tunnel");
}
}
return true;
}
bool MatchedTunnelDestination::OnBuildResult(const i2p::tunnel::Path & path, bool inbound, i2p::tunnel::TunnelBuildResult result)
{
return true;
}
}
}

@ -0,0 +1,36 @@
#ifndef MATCHED_DESTINATION_H_
#define MATCHED_DESTINATION_H_
#include "Destination.h"
#include <string>
namespace i2p
{
namespace client
{
/**
client tunnel that uses same OBEP as IBGW of each remote lease for a remote destination
*/
class MatchedTunnelDestination : public ClientDestination, public i2p::tunnel::ITunnelPeerSelector
{
public:
MatchedTunnelDestination(const i2p::data::PrivateKeys& keys, const std::string & remoteName, const std::map<std::string, std::string> * params = nullptr);
bool Start();
bool Stop();
bool SelectPeers(i2p::tunnel::Path & peers, int hops, bool inbound);
bool OnBuildResult(const i2p::tunnel::Path & peers, bool inbound, i2p::tunnel::TunnelBuildResult result);
private:
void ResolveCurrentLeaseSet();
void HandleFoundCurrentLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> ls);
private:
std::string m_RemoteName;
i2p::data::IdentHash m_RemoteIdent;
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
std::shared_ptr<boost::asio::deadline_timer> m_ResolveTimer;
};
}
}
#endif

@ -18,7 +18,7 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels): TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true), m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true),
@ -37,25 +37,25 @@ namespace tunnel
if (m_ExplicitPeers) if (m_ExplicitPeers)
{ {
int size = m_ExplicitPeers->size (); int size = m_ExplicitPeers->size ();
if (m_NumInboundHops > size) if (m_NumInboundHops > size)
{ {
m_NumInboundHops = size; m_NumInboundHops = size;
LogPrint (eLogInfo, "Tunnels: Inbound tunnel length has beed adjusted to ", size, " for explicit peers"); LogPrint (eLogInfo, "Tunnels: Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
} }
if (m_NumOutboundHops > size) if (m_NumOutboundHops > size)
{ {
m_NumOutboundHops = size; m_NumOutboundHops = size;
LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has beed adjusted to ", size, " for explicit peers"); LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
} }
m_NumInboundTunnels = 1; m_NumInboundTunnels = 1;
m_NumOutboundTunnels = 1; m_NumOutboundTunnels = 1;
} }
} }
void TunnelPool::DetachTunnels () void TunnelPool::DetachTunnels ()
{ {
{ {
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
for (auto& it: m_InboundTunnels) for (auto& it: m_InboundTunnels)
it->SetTunnelPool (nullptr); it->SetTunnelPool (nullptr);
m_InboundTunnels.clear (); m_InboundTunnels.clear ();
@ -67,21 +67,21 @@ namespace tunnel
m_OutboundTunnels.clear (); m_OutboundTunnels.clear ();
} }
m_Tests.clear (); m_Tests.clear ();
} }
void TunnelPool::TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel) void TunnelPool::TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel)
{ {
if (!m_IsActive) return; if (!m_IsActive) return;
{ {
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
EmitTunnelEvent("tunnels.created", createdTunnel); EmitTunnelEvent("tunnels.created", createdTunnel);
#endif #endif
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
m_InboundTunnels.insert (createdTunnel); m_InboundTunnels.insert (createdTunnel);
} }
if (m_LocalDestination) if (m_LocalDestination)
m_LocalDestination->SetLeaseSetUpdated (); m_LocalDestination->SetLeaseSetUpdated ();
OnTunnelBuildResult(createdTunnel, eBuildResultOkay); OnTunnelBuildResult(createdTunnel, eBuildResultOkay);
} }
@ -89,25 +89,25 @@ namespace tunnel
{ {
if (expiredTunnel) if (expiredTunnel)
{ {
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
EmitTunnelEvent("tunnels.expired", expiredTunnel); EmitTunnelEvent("tunnels.expired", expiredTunnel);
#endif #endif
expiredTunnel->SetTunnelPool (nullptr); expiredTunnel->SetTunnelPool (nullptr);
for (auto& it: m_Tests) for (auto& it: m_Tests)
if (it.second.second == expiredTunnel) it.second.second = nullptr; if (it.second.second == expiredTunnel) it.second.second = nullptr;
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
m_InboundTunnels.erase (expiredTunnel); m_InboundTunnels.erase (expiredTunnel);
} }
} }
void TunnelPool::TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel) void TunnelPool::TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel)
{ {
if (!m_IsActive) return; if (!m_IsActive) return;
{ {
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
EmitTunnelEvent("tunnels.created", createdTunnel); EmitTunnelEvent("tunnels.created", createdTunnel);
#endif #endif
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
m_OutboundTunnels.insert (createdTunnel); m_OutboundTunnels.insert (createdTunnel);
} }
@ -120,9 +120,9 @@ namespace tunnel
{ {
if (expiredTunnel) if (expiredTunnel)
{ {
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
EmitTunnelEvent("tunnels.expired", expiredTunnel); EmitTunnelEvent("tunnels.expired", expiredTunnel);
#endif #endif
expiredTunnel->SetTunnelPool (nullptr); expiredTunnel->SetTunnelPool (nullptr);
for (auto& it: m_Tests) for (auto& it: m_Tests)
if (it.second.first == expiredTunnel) it.second.first = nullptr; if (it.second.first == expiredTunnel) it.second.first = nullptr;
@ -131,7 +131,7 @@ namespace tunnel
m_OutboundTunnels.erase (expiredTunnel); m_OutboundTunnels.erase (expiredTunnel);
} }
} }
std::vector<std::shared_ptr<InboundTunnel> > TunnelPool::GetInboundTunnels (int num) const std::vector<std::shared_ptr<InboundTunnel> > TunnelPool::GetInboundTunnels (int num) const
{ {
std::vector<std::shared_ptr<InboundTunnel> > v; std::vector<std::shared_ptr<InboundTunnel> > v;
@ -144,8 +144,8 @@ namespace tunnel
{ {
v.push_back (it); v.push_back (it);
i++; i++;
} }
} }
return v; return v;
} }
@ -153,7 +153,7 @@ namespace tunnel
{ {
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); 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
{ {
@ -164,11 +164,11 @@ namespace tunnel
template<class TTunnels> template<class TTunnels>
typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const
{ {
if (tunnels.empty ()) return nullptr; if (tunnels.empty ()) return nullptr;
uint32_t ind = rand () % (tunnels.size ()/2 + 1), i = 0; uint32_t ind = rand () % (tunnels.size ()/2 + 1), i = 0;
typename TTunnels::value_type tunnel = nullptr; typename TTunnels::value_type tunnel = nullptr;
for (const auto& it: tunnels) for (const auto& it: tunnels)
{ {
if (it->IsEstablished () && it != excluded) if (it->IsEstablished () && it != excluded)
{ {
if(HasLatencyRequirement() && it->LatencyIsKnown() && !it->LatencyFitsRange(m_MinLatency, m_MaxLatency)) { if(HasLatencyRequirement() && it->LatencyIsKnown() && !it->LatencyFitsRange(m_MinLatency, m_MaxLatency)) {
@ -183,7 +183,7 @@ namespace tunnel
if(HasLatencyRequirement() && !tunnel) { if(HasLatencyRequirement() && !tunnel) {
ind = rand () % (tunnels.size ()/2 + 1), i = 0; ind = rand () % (tunnels.size ()/2 + 1), i = 0;
for (const auto& it: tunnels) for (const auto& it: tunnels)
{ {
if (it->IsEstablished () && it != excluded) if (it->IsEstablished () && it != excluded)
{ {
tunnel = it; tunnel = it;
@ -199,10 +199,10 @@ namespace tunnel
std::shared_ptr<OutboundTunnel> TunnelPool::GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const std::shared_ptr<OutboundTunnel> TunnelPool::GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const
{ {
if (old && old->IsEstablished ()) return old; if (old && old->IsEstablished ()) return old;
std::shared_ptr<OutboundTunnel> tunnel; std::shared_ptr<OutboundTunnel> tunnel;
if (old) if (old)
{ {
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
for (const auto& it: m_OutboundTunnels) for (const auto& it: m_OutboundTunnels)
if (it->IsEstablished () && old->GetEndpointIdentHash () == it->GetEndpointIdentHash ()) if (it->IsEstablished () && old->GetEndpointIdentHash () == it->GetEndpointIdentHash ())
{ {
@ -210,9 +210,9 @@ namespace tunnel
break; break;
} }
} }
if (!tunnel) if (!tunnel)
tunnel = GetNextOutboundTunnel (); tunnel = GetNextOutboundTunnel ();
return tunnel; return tunnel;
} }
@ -220,12 +220,12 @@ namespace tunnel
{ {
int num = 0; int num = 0;
{ {
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
for (const auto& it : m_OutboundTunnels) for (const auto& it : m_OutboundTunnels)
if (it->IsEstablished ()) num++; if (it->IsEstablished ()) num++;
} }
for (int i = num; i < m_NumOutboundTunnels; i++) for (int i = num; i < m_NumOutboundTunnels; i++)
CreateOutboundTunnel (); CreateOutboundTunnel ();
num = 0; num = 0;
{ {
@ -253,20 +253,20 @@ namespace tunnel
LogPrint (eLogWarning, "Tunnels: test of tunnel ", it.first, " failed"); LogPrint (eLogWarning, "Tunnels: test of tunnel ", it.first, " failed");
// if test failed again with another tunnel we consider it failed // if test failed again with another tunnel we consider it failed
if (it.second.first) if (it.second.first)
{ {
if (it.second.first->GetState () == eTunnelStateTestFailed) if (it.second.first->GetState () == eTunnelStateTestFailed)
{ {
it.second.first->SetState (eTunnelStateFailed); it.second.first->SetState (eTunnelStateFailed);
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
m_OutboundTunnels.erase (it.second.first); m_OutboundTunnels.erase (it.second.first);
} }
else else
it.second.first->SetState (eTunnelStateTestFailed); it.second.first->SetState (eTunnelStateTestFailed);
} }
if (it.second.second) if (it.second.second)
{ {
if (it.second.second->GetState () == eTunnelStateTestFailed) if (it.second.second->GetState () == eTunnelStateTestFailed)
{ {
it.second.second->SetState (eTunnelStateFailed); it.second.second->SetState (eTunnelStateFailed);
{ {
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
@ -274,25 +274,25 @@ namespace tunnel
} }
if (m_LocalDestination) if (m_LocalDestination)
m_LocalDestination->SetLeaseSetUpdated (); m_LocalDestination->SetLeaseSetUpdated ();
} }
else else
it.second.second->SetState (eTunnelStateTestFailed); it.second.second->SetState (eTunnelStateTestFailed);
} }
} }
// new tests // new tests
auto it1 = m_OutboundTunnels.begin (); auto it1 = m_OutboundTunnels.begin ();
auto it2 = m_InboundTunnels.begin (); auto it2 = m_InboundTunnels.begin ();
while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ()) while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ())
{ {
bool failed = false; bool failed = false;
if ((*it1)->IsFailed ()) if ((*it1)->IsFailed ())
{ {
failed = true; failed = true;
++it1; ++it1;
} }
if ((*it2)->IsFailed ()) if ((*it2)->IsFailed ())
{ {
failed = true; failed = true;
++it2; ++it2;
} }
@ -307,7 +307,7 @@ namespace tunnel
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (), (*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
CreateDeliveryStatusMsg (msgID)); CreateDeliveryStatusMsg (msgID));
++it1; ++it2; ++it1; ++it2;
} }
} }
} }
@ -317,24 +317,24 @@ namespace tunnel
m_LocalDestination->ProcessGarlicMessage (msg); m_LocalDestination->ProcessGarlicMessage (msg);
else else
LogPrint (eLogWarning, "Tunnels: local destination doesn't exist, dropped"); LogPrint (eLogWarning, "Tunnels: local destination doesn't exist, dropped");
} }
void TunnelPool::ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg) void TunnelPool::ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg)
{ {
const uint8_t * buf = msg->GetPayload (); const uint8_t * buf = msg->GetPayload ();
uint32_t msgID = bufbe32toh (buf); uint32_t msgID = bufbe32toh (buf);
buf += 4; buf += 4;
uint64_t timestamp = bufbe64toh (buf); uint64_t timestamp = bufbe64toh (buf);
decltype(m_Tests)::mapped_type test; decltype(m_Tests)::mapped_type test;
bool found = false; bool found = false;
{ {
std::unique_lock<std::mutex> l(m_TestsMutex); std::unique_lock<std::mutex> l(m_TestsMutex);
auto it = m_Tests.find (msgID); auto it = m_Tests.find (msgID);
if (it != m_Tests.end ()) if (it != m_Tests.end ())
{ {
found = true; found = true;
test = it->second; test = it->second;
m_Tests.erase (it); m_Tests.erase (it);
} }
} }
@ -358,35 +358,23 @@ namespace tunnel
m_LocalDestination->ProcessDeliveryStatusMessage (msg); m_LocalDestination->ProcessDeliveryStatusMessage (msg);
else else
LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped"); LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped");
} }
} }
std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const
{ {
bool isExploratory = (i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ()); bool isExploratory = (i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ());
auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop): auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop):
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop); i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
if (!hop || hop->GetProfile ()->IsBad ()) if (!hop || hop->GetProfile ()->IsBad ())
hop = i2p::data::netdb.GetRandomRouter (prevHop); hop = i2p::data::netdb.GetRandomRouter (prevHop);
return hop; return hop;
} }
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound) bool StandardSelectPeers(Path & peers, int numHops, bool inbound, SelectHopFunc nextHop)
{ {
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; auto prevHop = i2p::context.GetSharedRouterInfo ();
// peers is empty
if (numHops <= 0) return true;
// custom peer selector in use ?
{
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
if (m_CustomPeerSelector)
return m_CustomPeerSelector->SelectPeers(peers, numHops, isInbound);
}
// explicit peers in use
if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound);
auto prevHop = i2p::context.GetSharedRouterInfo ();
if(i2p::transport::transports.RoutesRestricted()) if(i2p::transport::transports.RoutesRestricted())
{ {
/** if routes are restricted prepend trusted first hop */ /** if routes are restricted prepend trusted first hop */
@ -405,30 +393,46 @@ namespace tunnel
numHops--; numHops--;
} }
} }
for(int i = 0; i < numHops; i++ ) for(int i = 0; i < numHops; i++ )
{ {
auto hop = SelectNextHop (prevHop); auto hop = nextHop (prevHop);
if (!hop) if (!hop)
{ {
LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ()); LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ());
return false; return false;
} }
prevHop = hop; prevHop = hop;
peers.push_back (hop->GetRouterIdentity ()); peers.push_back (hop->GetRouterIdentity ());
} }
return true; return true;
} }
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound)
{
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
// peers is empty
if (numHops <= 0) return true;
// custom peer selector in use ?
{
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
if (m_CustomPeerSelector)
return m_CustomPeerSelector->SelectPeers(peers, numHops, isInbound);
}
// explicit peers in use
if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound);
return StandardSelectPeers(peers, numHops, isInbound, std::bind(&TunnelPool::SelectNextHop, this, std::placeholders::_1));
}
bool TunnelPool::SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound) bool TunnelPool::SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound)
{ {
int size = m_ExplicitPeers->size (); int size = m_ExplicitPeers->size ();
std::vector<int> peerIndicies; std::vector<int> peerIndicies;
for (int i = 0; i < size; i++) peerIndicies.push_back(i); for (int i = 0; i < size; i++) peerIndicies.push_back(i);
std::random_shuffle (peerIndicies.begin(), peerIndicies.end()); std::random_shuffle (peerIndicies.begin(), peerIndicies.end());
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
for (int i = 0; i < numHops; i++) for (int i = 0; i < numHops; i++)
{ {
auto& ident = (*m_ExplicitPeers)[peerIndicies[i]]; auto& ident = (*m_ExplicitPeers)[peerIndicies[i]];
auto r = i2p::data::netdb.FindRouter (ident); auto r = i2p::data::netdb.FindRouter (ident);
@ -443,7 +447,7 @@ namespace tunnel
} }
return true; return true;
} }
void TunnelPool::CreateInboundTunnel () void TunnelPool::CreateInboundTunnel ()
{ {
auto outboundTunnel = GetNextOutboundTunnel (); auto outboundTunnel = GetNextOutboundTunnel ();
@ -455,15 +459,15 @@ namespace tunnel
{ {
std::shared_ptr<TunnelConfig> config; std::shared_ptr<TunnelConfig> config;
if (m_NumInboundHops > 0) if (m_NumInboundHops > 0)
{ {
std::reverse (peers.begin (), peers.end ()); std::reverse (peers.begin (), peers.end ());
config = std::make_shared<TunnelConfig> (peers); config = std::make_shared<TunnelConfig> (peers);
} }
auto tunnel = tunnels.CreateInboundTunnel (config, outboundTunnel); auto tunnel = tunnels.CreateInboundTunnel (config, outboundTunnel);
tunnel->SetTunnelPool (shared_from_this ()); tunnel->SetTunnelPool (shared_from_this ());
if (tunnel->IsEstablished ()) // zero hops if (tunnel->IsEstablished ()) // zero hops
TunnelCreated (tunnel); TunnelCreated (tunnel);
} }
else else
LogPrint (eLogError, "Tunnels: Can't create inbound tunnel, no peers available"); LogPrint (eLogError, "Tunnels: Can't create inbound tunnel, no peers available");
} }
@ -480,41 +484,41 @@ namespace tunnel
newTunnel->SetTunnelPool (shared_from_this()); newTunnel->SetTunnelPool (shared_from_this());
if (newTunnel->IsEstablished ()) // zero hops if (newTunnel->IsEstablished ()) // zero hops
TunnelCreated (newTunnel); TunnelCreated (newTunnel);
} }
void TunnelPool::CreateOutboundTunnel () void TunnelPool::CreateOutboundTunnel ()
{ {
auto inboundTunnel = GetNextInboundTunnel (); auto inboundTunnel = GetNextInboundTunnel ();
if (!inboundTunnel) if (!inboundTunnel)
inboundTunnel = tunnels.GetNextInboundTunnel (); inboundTunnel = tunnels.GetNextInboundTunnel ();
if (inboundTunnel) if (inboundTunnel)
{ {
LogPrint (eLogDebug, "Tunnels: Creating destination outbound tunnel..."); LogPrint (eLogDebug, "Tunnels: Creating destination outbound tunnel...");
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers; std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
if (SelectPeers (peers, false)) if (SelectPeers (peers, false))
{ {
std::shared_ptr<TunnelConfig> config; std::shared_ptr<TunnelConfig> config;
if (m_NumOutboundHops > 0) if (m_NumOutboundHops > 0)
config = std::make_shared<TunnelConfig>(peers, inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ()); config = std::make_shared<TunnelConfig>(peers, inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ());
auto tunnel = tunnels.CreateOutboundTunnel (config); auto tunnel = tunnels.CreateOutboundTunnel (config);
tunnel->SetTunnelPool (shared_from_this ()); tunnel->SetTunnelPool (shared_from_this ());
if (tunnel->IsEstablished ()) // zero hops if (tunnel->IsEstablished ()) // zero hops
TunnelCreated (tunnel); TunnelCreated (tunnel);
} }
else else
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no peers available"); LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no peers available");
} }
else else
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no inbound tunnels found"); LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no inbound tunnels found");
} }
void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel) void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel)
{ {
auto inboundTunnel = GetNextInboundTunnel (); auto inboundTunnel = GetNextInboundTunnel ();
if (!inboundTunnel) if (!inboundTunnel)
inboundTunnel = tunnels.GetNextInboundTunnel (); inboundTunnel = tunnels.GetNextInboundTunnel ();
if (inboundTunnel) if (inboundTunnel)
{ {
LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel..."); LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel...");
std::shared_ptr<TunnelConfig> config; std::shared_ptr<TunnelConfig> config;
if (m_NumOutboundHops > 0) if (m_NumOutboundHops > 0)
@ -523,10 +527,10 @@ namespace tunnel
newTunnel->SetTunnelPool (shared_from_this ()); newTunnel->SetTunnelPool (shared_from_this ());
if (newTunnel->IsEstablished ()) // zero hops if (newTunnel->IsEstablished ()) // zero hops
TunnelCreated (newTunnel); TunnelCreated (newTunnel);
} }
else else
LogPrint (eLogDebug, "Tunnels: Can't re-create outbound tunnel, no inbound tunnels found"); LogPrint (eLogDebug, "Tunnels: Can't re-create outbound tunnel, no inbound tunnels found");
} }
void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel) void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel)
{ {
@ -535,7 +539,7 @@ namespace tunnel
tunnel->SetTunnelPool (shared_from_this ()); tunnel->SetTunnelPool (shared_from_this ());
} }
void TunnelPool::SetCustomPeerSelector(TunnelPeerSelector selector) void TunnelPool::SetCustomPeerSelector(ITunnelPeerSelector * selector)
{ {
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex); std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
m_CustomPeerSelector = selector; m_CustomPeerSelector = selector;
@ -567,7 +571,7 @@ namespace tunnel
} }
return tun; return tun;
} }
std::shared_ptr<OutboundTunnel> TunnelPool::GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude) const std::shared_ptr<OutboundTunnel> TunnelPool::GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude) const
{ {
std::shared_ptr<OutboundTunnel> tun = nullptr; std::shared_ptr<OutboundTunnel> tun = nullptr;

@ -30,25 +30,29 @@ namespace tunnel
eBuildResultTimeout // tunnel build timed out eBuildResultTimeout // tunnel build timed out
}; };
typedef std::shared_ptr<const i2p::data::IdentityEx> Peer;
typedef std::vector<Peer> Path;
/** interface for custom tunnel peer selection algorithm */ /** interface for custom tunnel peer selection algorithm */
struct ITunnelPeerSelector struct ITunnelPeerSelector
{ {
typedef std::shared_ptr<const i2p::data::IdentityEx> Peer; virtual ~ITunnelPeerSelector() {};
typedef std::vector<Peer> TunnelPath; virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0;
virtual bool OnBuildResult(const Path & peers, bool isInbound, TunnelBuildResult result) = 0;
virtual bool SelectPeers(TunnelPath & peers, int hops, bool isInbound) = 0;
virtual bool OnBuildResult(TunnelPath & peers, bool isInbound, TunnelBuildResult result) = 0;
}; };
typedef std::shared_ptr<ITunnelPeerSelector> TunnelPeerSelector;
typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>)> SelectHopFunc;
// standard peer selection algorithm
bool StandardSelectPeers(Path & path, int hops, bool inbound, SelectHopFunc nextHop);
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
{ {
public: public:
TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels); TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
~TunnelPool (); ~TunnelPool ();
std::shared_ptr<i2p::garlic::GarlicDestination> GetLocalDestination () const { return m_LocalDestination; }; std::shared_ptr<i2p::garlic::GarlicDestination> GetLocalDestination () const { return m_LocalDestination; };
void SetLocalDestination (std::shared_ptr<i2p::garlic::GarlicDestination> destination) { m_LocalDestination = destination; }; void SetLocalDestination (std::shared_ptr<i2p::garlic::GarlicDestination> destination) { m_LocalDestination = destination; };
void SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers); void SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers);
@ -62,7 +66,7 @@ namespace tunnel
void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel); void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel);
std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const; std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const;
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr) const; std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr) const;
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const; std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const;
std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const; std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const;
void TestTunnels (); void TestTunnels ();
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
@ -75,7 +79,7 @@ namespace tunnel
int GetNumInboundTunnels () const { return m_NumInboundTunnels; }; int GetNumInboundTunnels () const { return m_NumInboundTunnels; };
int GetNumOutboundTunnels () const { return m_NumOutboundTunnels; }; int GetNumOutboundTunnels () const { return m_NumOutboundTunnels; };
void SetCustomPeerSelector(TunnelPeerSelector selector); void SetCustomPeerSelector(ITunnelPeerSelector * selector);
void UnsetCustomPeerSelector(); void UnsetCustomPeerSelector();
bool HasCustomPeerSelector(); bool HasCustomPeerSelector();
@ -90,23 +94,25 @@ namespace tunnel
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude=nullptr) const; std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude=nullptr) const;
void OnTunnelBuildResult(std::shared_ptr<Tunnel> tunnel, TunnelBuildResult result); void OnTunnelBuildResult(std::shared_ptr<Tunnel> tunnel, TunnelBuildResult result);
// for overriding tunnel peer selection
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
private: private:
void CreateInboundTunnel (); void CreateInboundTunnel ();
void CreateOutboundTunnel (); void CreateOutboundTunnel ();
void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel); void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
template<class TTunnels> template<class TTunnels>
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const; typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const;
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
bool SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound); bool SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound);
bool SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound); bool SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound);
private: private:
std::shared_ptr<i2p::garlic::GarlicDestination> m_LocalDestination; std::shared_ptr<i2p::garlic::GarlicDestination> m_LocalDestination;
int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels; int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels;
std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers; std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers;
mutable std::mutex m_InboundTunnelsMutex; mutable std::mutex m_InboundTunnelsMutex;
std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
mutable std::mutex m_OutboundTunnelsMutex; mutable std::mutex m_OutboundTunnelsMutex;
@ -115,20 +121,19 @@ namespace tunnel
std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests; std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests;
bool m_IsActive; bool m_IsActive;
std::mutex m_CustomPeerSelectorMutex; std::mutex m_CustomPeerSelectorMutex;
TunnelPeerSelector m_CustomPeerSelector; ITunnelPeerSelector * m_CustomPeerSelector;
uint64_t m_MinLatency=0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms 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 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
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; }; const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; }; const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
}; };
} }
} }
#endif #endif

@ -37,7 +37,7 @@ set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/FS.cpp" "${CMAKE_SOURCE_DIR}/FS.cpp"
"${CMAKE_SOURCE_DIR}/Log.cpp" "${CMAKE_SOURCE_DIR}/Log.cpp"
"${CMAKE_SOURCE_DIR}/NTCPSession.cpp" "${CMAKE_SOURCE_DIR}/NTCPSession.cpp"
"${CMAKE_SOURCE_DIR}/NetDbRequests.cpp" "${CMAKE_SOURCE_DIR}/NetDbRequests.cpp"
"${CMAKE_SOURCE_DIR}/NetDb.cpp" "${CMAKE_SOURCE_DIR}/NetDb.cpp"
"${CMAKE_SOURCE_DIR}/Profiling.cpp" "${CMAKE_SOURCE_DIR}/Profiling.cpp"
"${CMAKE_SOURCE_DIR}/Reseed.cpp" "${CMAKE_SOURCE_DIR}/Reseed.cpp"
@ -47,7 +47,7 @@ set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/SSUData.cpp" "${CMAKE_SOURCE_DIR}/SSUData.cpp"
"${CMAKE_SOURCE_DIR}/SSUSession.cpp" "${CMAKE_SOURCE_DIR}/SSUSession.cpp"
"${CMAKE_SOURCE_DIR}/Streaming.cpp" "${CMAKE_SOURCE_DIR}/Streaming.cpp"
"${CMAKE_SOURCE_DIR}/Destination.cpp" "${CMAKE_SOURCE_DIR}/Destination.cpp"
"${CMAKE_SOURCE_DIR}/TransitTunnel.cpp" "${CMAKE_SOURCE_DIR}/TransitTunnel.cpp"
"${CMAKE_SOURCE_DIR}/Tunnel.cpp" "${CMAKE_SOURCE_DIR}/Tunnel.cpp"
"${CMAKE_SOURCE_DIR}/TunnelGateway.cpp" "${CMAKE_SOURCE_DIR}/TunnelGateway.cpp"
@ -59,16 +59,16 @@ set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/Datagram.cpp" "${CMAKE_SOURCE_DIR}/Datagram.cpp"
"${CMAKE_SOURCE_DIR}/Family.cpp" "${CMAKE_SOURCE_DIR}/Family.cpp"
"${CMAKE_SOURCE_DIR}/Signature.cpp" "${CMAKE_SOURCE_DIR}/Signature.cpp"
"${CMAKE_SOURCE_DIR}/Timestamp.cpp" "${CMAKE_SOURCE_DIR}/Timestamp.cpp"
"${CMAKE_SOURCE_DIR}/api.cpp" "${CMAKE_SOURCE_DIR}/api.cpp"
"${CMAKE_SOURCE_DIR}/Event.cpp" "${CMAKE_SOURCE_DIR}/Event.cpp"
"${CMAKE_SOURCE_DIR}/Gost.cpp" "${CMAKE_SOURCE_DIR}/Gost.cpp"
) )
if (WITH_WEBSOCKETS) if (WITH_WEBSOCKETS)
add_definitions(-DWITH_EVENTS) add_definitions(-DWITH_EVENTS)
find_package(websocketpp REQUIRED) find_package(websocketpp REQUIRED)
endif () endif ()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS) if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS)
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp") list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
@ -90,8 +90,9 @@ install(TARGETS libi2pd
set (CLIENT_SRC set (CLIENT_SRC
"${CMAKE_SOURCE_DIR}/AddressBook.cpp" "${CMAKE_SOURCE_DIR}/AddressBook.cpp"
"${CMAKE_SOURCE_DIR}/BOB.cpp" "${CMAKE_SOURCE_DIR}/BOB.cpp"
"${CMAKE_SOURCE_DIR}/ClientContext.cpp" "${CMAKE_SOURCE_DIR}/ClientContext.cpp"
"${CMAKE_SOURCE_DIR}/MatchedDestination.cpp"
"${CMAKE_SOURCE_DIR}/I2PTunnel.cpp" "${CMAKE_SOURCE_DIR}/I2PTunnel.cpp"
"${CMAKE_SOURCE_DIR}/I2PService.cpp" "${CMAKE_SOURCE_DIR}/I2PService.cpp"
"${CMAKE_SOURCE_DIR}/SAM.cpp" "${CMAKE_SOURCE_DIR}/SAM.cpp"
@ -357,7 +358,7 @@ include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_
# warn if for meshnet # warn if for meshnet
if (WITH_MESHNET) if (WITH_MESHNET)
message(STATUS "Building for testnet") message(STATUS "Building for testnet")
message(WARNING "This build will NOT work on mainline i2p") message(WARNING "This build will NOT work on mainline i2p")
endif() endif()

@ -8,10 +8,9 @@ LIB_SRC = \
Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Event.cpp Gost.cpp Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Event.cpp Gost.cpp
LIB_CLIENT_SRC = \ LIB_CLIENT_SRC = \
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \ AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp MatchedDestination.cpp \
SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp WebSocks.cpp SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp WebSocks.cpp
# also: Daemon{Linux,Win32}.cpp will be added later # also: Daemon{Linux,Win32}.cpp will be added later
DAEMON_SRC = \ DAEMON_SRC = \
HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp

Loading…
Cancel
Save