i2pd/Tunnel.cpp

800 lines
22 KiB
C++
Raw Normal View History

2014-12-31 14:14:53 +00:00
#include <string.h>
#include "I2PEndian.h"
2014-01-09 22:55:53 +00:00
#include <thread>
#include <algorithm>
#include <vector>
2015-11-03 14:15:49 +00:00
#include <openssl/rand.h>
2013-12-07 00:02:49 +00:00
#include "RouterContext.h"
#include "Log.h"
#include "Timestamp.h"
#include "I2NPProtocol.h"
#include "Transports.h"
#include "NetDb.h"
#include "Tunnel.h"
namespace i2p
{
namespace tunnel
{
2015-05-06 20:17:48 +00:00
Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config):
2015-11-03 14:15:49 +00:00
TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()),
2015-04-17 15:36:42 +00:00
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false)
2013-12-07 00:02:49 +00:00
{
}
Tunnel::~Tunnel ()
{
}
2015-01-27 19:55:46 +00:00
void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel)
2013-12-07 00:02:49 +00:00
{
auto numHops = m_Config->GetNumHops ();
int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops;
auto msg = NewI2NPShortMessage ();
2013-12-07 00:02:49 +00:00
*msg->GetPayload () = numRecords;
msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1;
// shuffle records
std::vector<int> recordIndicies;
for (int i = 0; i < numRecords; i++) recordIndicies.push_back(i);
std::random_shuffle (recordIndicies.begin(), recordIndicies.end());
2013-12-07 00:02:49 +00:00
// create real records
uint8_t * records = msg->GetPayload () + 1;
2013-12-07 00:02:49 +00:00
TunnelHopConfig * hop = m_Config->GetFirstHop ();
int i = 0;
while (hop)
{
2015-11-03 14:15:49 +00:00
uint32_t msgID;
if (hop->next) // we set replyMsgID for last hop only
RAND_bytes ((uint8_t *)&msgID, 4);
else
msgID = replyMsgID;
int idx = recordIndicies[i];
2015-11-03 14:15:49 +00:00
hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID);
hop->recordIndex = idx;
2013-12-07 00:02:49 +00:00
i++;
hop = hop->next;
}
2014-06-19 01:24:24 +00:00
// fill up fake records with random data
for (int i = numHops; i < numRecords; i++)
2014-06-19 01:24:24 +00:00
{
int idx = recordIndicies[i];
2015-11-03 14:15:49 +00:00
RAND_bytes (records + idx*TUNNEL_BUILD_RECORD_SIZE, TUNNEL_BUILD_RECORD_SIZE);
2014-06-19 01:24:24 +00:00
}
// decrypt real records
2014-05-15 22:58:26 +00:00
i2p::crypto::CBCDecryption decryption;
2013-12-07 00:02:49 +00:00
hop = m_Config->GetLastHop ()->prev;
while (hop)
{
2014-05-15 22:58:26 +00:00
decryption.SetKey (hop->replyKey);
// decrypt records after current hop
TunnelHopConfig * hop1 = hop->next;
while (hop1)
{
2014-06-24 23:33:30 +00:00
decryption.SetIV (hop->replyIV);
uint8_t * record = records + hop1->recordIndex*TUNNEL_BUILD_RECORD_SIZE;
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
hop1 = hop1->next;
}
2013-12-07 00:02:49 +00:00
hop = hop->prev;
}
msg->FillI2NPMessageHeader (eI2NPVariableTunnelBuild);
// send message
2013-12-07 00:02:49 +00:00
if (outboundTunnel)
2015-11-24 18:09:12 +00:00
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
2013-12-07 00:02:49 +00:00
else
2015-11-24 18:09:12 +00:00
i2p::transport::transports.SendMessage (GetNextIdentHash (), msg);
2013-12-07 00:02:49 +00:00
}
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
{
2015-12-18 06:20:06 +00:00
LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records.");
2014-05-15 22:58:26 +00:00
i2p::crypto::CBCDecryption decryption;
2013-12-07 00:02:49 +00:00
TunnelHopConfig * hop = m_Config->GetLastHop ();
while (hop)
{
2014-05-15 22:58:26 +00:00
decryption.SetKey (hop->replyKey);
// decrypt records before and including current hop
TunnelHopConfig * hop1 = hop;
while (hop1)
{
2014-06-19 01:24:24 +00:00
auto idx = hop1->recordIndex;
if (idx >= 0 && idx < msg[0])
{
uint8_t * record = msg + 1 + idx*TUNNEL_BUILD_RECORD_SIZE;
2014-06-24 23:33:30 +00:00
decryption.SetIV (hop->replyIV);
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
2014-06-19 01:24:24 +00:00
}
else
2015-12-18 06:20:06 +00:00
LogPrint (eLogWarning, "Tunnel: hop index ", idx, " is out of range");
hop1 = hop1->prev;
}
2013-12-07 00:02:49 +00:00
hop = hop->prev;
}
2014-07-27 00:56:42 +00:00
bool established = true;
2014-06-19 01:24:24 +00:00
hop = m_Config->GetFirstHop ();
while (hop)
2013-12-07 00:02:49 +00:00
{
const uint8_t * record = msg + 1 + hop->recordIndex*TUNNEL_BUILD_RECORD_SIZE;
uint8_t ret = record[BUILD_RESPONSE_RECORD_RET_OFFSET];
2015-12-18 06:20:06 +00:00
LogPrint (eLogDebug, "Tunnel: Build response ret code=", (int)ret);
2015-11-03 14:15:49 +00:00
auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ());
if (profile)
profile->TunnelBuildResponse (ret);
if (ret)
2013-12-07 00:02:49 +00:00
// if any of participants declined the tunnel is not established
2014-07-27 00:56:42 +00:00
established = false;
2014-06-19 01:24:24 +00:00
hop = hop->next;
2013-12-07 00:02:49 +00:00
}
2014-07-27 00:56:42 +00:00
if (established)
2014-05-09 23:34:12 +00:00
{
2015-11-03 14:15:49 +00:00
// create tunnel decryptions from layer and iv keys in reverse order
hop = m_Config->GetLastHop ();
2014-05-09 23:34:12 +00:00
while (hop)
{
2015-11-06 14:01:02 +00:00
auto tunnelHop = new TunnelHop;
tunnelHop->ident = hop->ident;
2015-11-03 14:15:49 +00:00
tunnelHop->decryption.SetKeys (hop->layerKey, hop->ivKey);
m_Hops.push_back (std::unique_ptr<TunnelHop>(tunnelHop));
hop = hop->prev;
2014-05-09 23:34:12 +00:00
}
2015-11-03 14:15:49 +00:00
m_Config = nullptr;
2014-05-09 23:34:12 +00:00
}
2014-07-27 00:56:42 +00:00
if (established) m_State = eTunnelStateEstablished;
return established;
2013-12-07 00:02:49 +00:00
}
void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
2013-12-07 00:02:49 +00:00
{
const uint8_t * inPayload = in->GetPayload () + 4;
uint8_t * outPayload = out->GetPayload () + 4;
2015-11-03 14:15:49 +00:00
for (auto& it: m_Hops)
{
it->decryption.Decrypt (inPayload, outPayload);
inPayload = outPayload;
2015-11-03 14:15:49 +00:00
}
2013-12-07 00:02:49 +00:00
}
void Tunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{
2016-01-18 00:00:00 +00:00
LogPrint (eLogWarning, "Tunnel: Can't send I2NP messages without delivery instructions");
}
2015-11-03 14:15:49 +00:00
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > Tunnel::GetPeers () const
{
auto peers = GetInvertedPeers ();
std::reverse (peers.begin (), peers.end ());
return peers;
}
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > Tunnel::GetInvertedPeers () const
{
// hops are in inverted order
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > ret;
for (auto& it: m_Hops)
ret.push_back (it->ident);
return ret;
}
2015-12-10 00:07:12 +00:00
void Tunnel::PrintHops (std::stringstream& s) const
{
for (auto& it: m_Hops)
{
2016-01-17 16:10:56 +00:00
s << "";
2015-12-10 00:07:12 +00:00
s << i2p::data::GetIdentHashAbbreviation (it->ident->GetIdentHash ());
}
}
2015-11-03 14:15:49 +00:00
void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg)
2013-12-07 00:02:49 +00:00
{
if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive
auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (msg, newMsg);
newMsg->from = shared_from_this ();
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
2013-12-07 00:02:49 +00:00
}
2015-12-09 23:01:42 +00:00
void InboundTunnel::Print (std::stringstream& s) const
{
2015-12-10 00:07:12 +00:00
PrintHops (s);
2016-01-17 16:10:56 +00:00
s << "" << GetTunnelID () << ":me";
2015-12-09 23:01:42 +00:00
}
2015-11-03 14:15:49 +00:00
2015-06-22 02:29:50 +00:00
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
2013-12-07 00:02:49 +00:00
{
TunnelMessageBlock block;
if (gwHash)
{
block.hash = gwHash;
if (gwTunnel)
{
block.deliveryType = eDeliveryTypeTunnel;
block.tunnelID = gwTunnel;
}
else
block.deliveryType = eDeliveryTypeRouter;
}
else
block.deliveryType = eDeliveryTypeLocal;
2015-06-22 02:29:50 +00:00
block.data = msg;
2014-04-03 16:19:12 +00:00
std::unique_lock<std::mutex> l(m_SendMutex);
m_Gateway.SendTunnelDataMsg (block);
2013-12-07 00:02:49 +00:00
}
2014-01-20 23:37:51 +00:00
void OutboundTunnel::SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs)
2013-12-07 00:02:49 +00:00
{
2014-04-03 16:19:12 +00:00
std::unique_lock<std::mutex> l(m_SendMutex);
2014-01-20 23:37:51 +00:00
for (auto& it : msgs)
m_Gateway.PutTunnelDataMsg (it);
2014-01-20 23:37:51 +00:00
m_Gateway.SendBuffer ();
2013-12-07 00:02:49 +00:00
}
2014-01-20 23:37:51 +00:00
void OutboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{
2016-01-18 00:00:00 +00:00
LogPrint (eLogError, "Tunnel: incoming message for outbound tunnel ", GetTunnelID ());
}
2015-12-09 23:01:42 +00:00
void OutboundTunnel::Print (std::stringstream& s) const
{
2015-12-10 00:07:12 +00:00
s << GetTunnelID () << ":me";
PrintHops (s);
2016-01-17 16:10:56 +00:00
s << "";
2015-12-09 23:01:42 +00:00
}
2015-11-03 14:15:49 +00:00
2013-12-07 00:02:49 +00:00
Tunnels tunnels;
2015-02-28 12:59:34 +00:00
Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr),
m_NumSuccesiveTunnelCreations (0), m_NumFailedTunnelCreations (0)
2013-12-07 00:02:49 +00:00
{
}
Tunnels::~Tunnels ()
{
for (auto& it : m_TransitTunnels)
delete it.second;
m_TransitTunnels.clear ();
}
2015-01-27 19:55:46 +00:00
std::shared_ptr<InboundTunnel> Tunnels::GetInboundTunnel (uint32_t tunnelID)
2013-12-07 00:02:49 +00:00
{
auto it = m_InboundTunnels.find(tunnelID);
if (it != m_InboundTunnels.end ())
return it->second;
return nullptr;
}
TransitTunnel * Tunnels::GetTransitTunnel (uint32_t tunnelID)
{
auto it = m_TransitTunnels.find(tunnelID);
if (it != m_TransitTunnels.end ())
return it->second;
return nullptr;
}
2015-01-27 19:55:46 +00:00
std::shared_ptr<InboundTunnel> Tunnels::GetPendingInboundTunnel (uint32_t replyMsgID)
2013-12-07 00:02:49 +00:00
{
return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels);
}
2015-01-27 19:55:46 +00:00
std::shared_ptr<OutboundTunnel> Tunnels::GetPendingOutboundTunnel (uint32_t replyMsgID)
{
return GetPendingTunnel (replyMsgID, m_PendingOutboundTunnels);
}
template<class TTunnel>
2015-01-27 19:55:46 +00:00
std::shared_ptr<TTunnel> Tunnels::GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels)
{
auto it = pendingTunnels.find(replyMsgID);
if (it != pendingTunnels.end () && it->second->GetState () == eTunnelStatePending)
2014-09-26 14:15:34 +00:00
{
it->second->SetState (eTunnelStateBuildReplyReceived);
return it->second;
2014-09-26 14:15:34 +00:00
}
2013-12-07 00:02:49 +00:00
return nullptr;
}
2015-01-27 19:55:46 +00:00
std::shared_ptr<InboundTunnel> Tunnels::GetNextInboundTunnel ()
2013-12-07 00:02:49 +00:00
{
2015-01-27 19:55:46 +00:00
std::shared_ptr<InboundTunnel> tunnel;
2013-12-07 00:02:49 +00:00
size_t minReceived = 0;
for (auto it : m_InboundTunnels)
2014-03-21 19:54:55 +00:00
{
2014-08-26 14:31:32 +00:00
if (!it.second->IsEstablished ()) continue;
2013-12-07 00:02:49 +00:00
if (!tunnel || it.second->GetNumReceivedBytes () < minReceived)
{
tunnel = it.second;
minReceived = it.second->GetNumReceivedBytes ();
2014-03-21 19:54:55 +00:00
}
}
2013-12-07 00:02:49 +00:00
return tunnel;
}
2015-01-27 19:55:46 +00:00
std::shared_ptr<OutboundTunnel> Tunnels::GetNextOutboundTunnel ()
2013-12-07 00:02:49 +00:00
{
2015-11-03 14:15:49 +00:00
if (!m_OutboundTunnels.size ()) return nullptr;
uint32_t ind = rand () % m_OutboundTunnels.size (), i = 0;
2015-01-27 19:55:46 +00:00
std::shared_ptr<OutboundTunnel> tunnel;
2013-12-29 15:48:57 +00:00
for (auto it: m_OutboundTunnels)
{
2014-08-26 14:31:32 +00:00
if (it->IsEstablished ())
2013-12-07 00:02:49 +00:00
{
tunnel = it;
2014-03-21 19:54:55 +00:00
i++;
}
2014-08-29 11:44:12 +00:00
if (i > ind && tunnel) break;
2014-03-21 19:54:55 +00:00
}
return tunnel;
2013-12-07 00:02:49 +00:00
}
2014-03-15 00:24:12 +00:00
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (int numInboundHops,
int numOutboundHops, int numInboundTunnels, int numOutboundTunnels)
2014-03-15 00:24:12 +00:00
{
auto pool = std::make_shared<TunnelPool> (numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels);
2014-10-05 15:01:12 +00:00
std::unique_lock<std::mutex> l(m_PoolsMutex);
2014-12-10 02:07:54 +00:00
m_Pools.push_back (pool);
2014-03-15 00:51:51 +00:00
return pool;
}
2015-01-20 03:28:13 +00:00
void Tunnels::DeleteTunnelPool (std::shared_ptr<TunnelPool> pool)
2014-03-15 00:51:51 +00:00
{
2014-10-11 13:47:24 +00:00
if (pool)
{
StopTunnelPool (pool);
2014-12-10 02:07:54 +00:00
{
std::unique_lock<std::mutex> l(m_PoolsMutex);
m_Pools.remove (pool);
}
}
}
2015-01-20 03:28:13 +00:00
void Tunnels::StopTunnelPool (std::shared_ptr<TunnelPool> pool)
{
if (pool)
{
pool->SetActive (false);
2014-10-11 13:47:24 +00:00
pool->DetachTunnels ();
}
2014-03-15 00:24:12 +00:00
}
2013-12-07 00:02:49 +00:00
void Tunnels::AddTransitTunnel (TransitTunnel * tunnel)
{
2014-09-14 11:50:01 +00:00
std::unique_lock<std::mutex> l(m_TransitTunnelsMutex);
2015-02-10 14:39:49 +00:00
if (!m_TransitTunnels.insert (std::make_pair (tunnel->GetTunnelID (), tunnel)).second)
{
2016-01-18 00:00:00 +00:00
LogPrint (eLogError, "Tunnel: transit tunnel with id ", tunnel->GetTunnelID (), " already exists");
2015-02-10 14:39:49 +00:00
delete tunnel;
}
2013-12-07 00:02:49 +00:00
}
void Tunnels::Start ()
{
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Tunnels::Run, this));
}
void Tunnels::Stop ()
{
m_IsRunning = false;
m_Queue.WakeUp ();
if (m_Thread)
{
m_Thread->join ();
delete m_Thread;
m_Thread = 0;
}
}
void Tunnels::Run ()
{
2014-01-09 22:55:53 +00:00
std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready
2013-12-07 00:02:49 +00:00
uint64_t lastTs = 0;
2013-12-07 00:02:49 +00:00
while (m_IsRunning)
{
try
{
auto msg = m_Queue.GetNextWithTimeout (1000); // 1 sec
2015-01-22 02:50:46 +00:00
if (msg)
{
uint32_t prevTunnelID = 0, tunnelID = 0;
2015-01-31 15:39:29 +00:00
TunnelBase * prevTunnel = nullptr;
2015-01-22 02:50:46 +00:00
do
{
2015-01-31 15:39:29 +00:00
TunnelBase * tunnel = nullptr;
uint8_t typeID = msg->GetTypeID ();
switch (typeID)
{
case eI2NPTunnelData:
case eI2NPTunnelGateway:
{
tunnelID = bufbe32toh (msg->GetPayload ());
if (tunnelID == prevTunnelID)
tunnel = prevTunnel;
else if (prevTunnel)
prevTunnel->FlushTunnelDataMsgs ();
2015-01-22 02:50:46 +00:00
if (!tunnel && typeID == eI2NPTunnelData)
2015-01-27 19:55:46 +00:00
tunnel = GetInboundTunnel (tunnelID).get ();
if (!tunnel)
tunnel = GetTransitTunnel (tunnelID);
if (tunnel)
{
if (typeID == eI2NPTunnelData)
tunnel->HandleTunnelDataMsg (msg);
else // tunnel gateway assumed
HandleTunnelGatewayMsg (tunnel, msg);
}
else
2016-01-18 00:00:00 +00:00
LogPrint (eLogWarning, "Tunnel: tunnel with id ", tunnelID, " not found");
break;
}
case eI2NPVariableTunnelBuild:
case eI2NPVariableTunnelBuildReply:
case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply:
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
break;
default:
2016-01-28 02:54:42 +00:00
LogPrint (eLogWarning, "Tunnel: unexpected messsage type ", (int) typeID);
}
2015-01-22 02:50:46 +00:00
msg = m_Queue.Get ();
if (msg)
{
prevTunnelID = tunnelID;
prevTunnel = tunnel;
}
else if (tunnel)
tunnel->FlushTunnelDataMsgs ();
}
2015-01-22 02:50:46 +00:00
while (msg);
2013-12-07 00:02:49 +00:00
}
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
2013-12-07 00:02:49 +00:00
if (ts - lastTs >= 15) // manage tunnels every 15 seconds
{
ManageTunnels ();
lastTs = ts;
}
}
catch (std::exception& ex)
{
2015-12-18 06:20:06 +00:00
LogPrint (eLogError, "Tunnel: runtime exception: ", ex.what ());
2013-12-07 00:02:49 +00:00
}
}
}
void Tunnels::HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr<I2NPMessage> msg)
{
if (!tunnel)
{
2016-01-18 00:00:00 +00:00
LogPrint (eLogError, "Tunnel: missing tunnel for gateway");
return;
}
const uint8_t * payload = msg->GetPayload ();
uint16_t len = bufbe16toh(payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET);
// we make payload as new I2NP message to send
msg->offset += I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE;
2016-01-25 19:31:51 +00:00
if (msg->offset + len > msg->len)
{
LogPrint (eLogError, "Tunnel: gateway payload ", (int)len, " exceeds message length ", (int)msg->len);
return;
}
msg->len = msg->offset + len;
auto typeID = msg->GetTypeID ();
2016-01-18 00:00:00 +00:00
LogPrint (eLogDebug, "Tunnel: gateway of ", (int) len, " bytes for tunnel ", tunnel->GetTunnelID (), ", msg type ", (int)typeID);
if (IsRouterInfoMsg (msg) || typeID == eI2NPDatabaseSearchReply)
// transit DatabaseStore my contain new/updated RI
// or DatabaseSearchReply with new routers
2016-01-31 23:27:47 +00:00
i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg));
tunnel->SendTunnelDataMsg (msg);
}
2013-12-07 00:02:49 +00:00
void Tunnels::ManageTunnels ()
2014-10-06 16:50:36 +00:00
{
ManagePendingTunnels ();
ManageInboundTunnels ();
ManageOutboundTunnels ();
ManageTransitTunnels ();
ManageTunnelPools ();
}
void Tunnels::ManagePendingTunnels ()
{
ManagePendingTunnels (m_PendingInboundTunnels);
ManagePendingTunnels (m_PendingOutboundTunnels);
}
template<class PendingTunnels>
void Tunnels::ManagePendingTunnels (PendingTunnels& pendingTunnels)
2013-12-07 00:02:49 +00:00
{
2014-09-26 14:15:34 +00:00
// check pending tunnel. delete failed or timeout
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = pendingTunnels.begin (); it != pendingTunnels.end ();)
2013-12-07 00:02:49 +00:00
{
2014-09-26 14:15:34 +00:00
auto tunnel = it->second;
switch (tunnel->GetState ())
{
2014-09-26 14:15:34 +00:00
case eTunnelStatePending:
if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT)
{
2016-01-18 00:00:00 +00:00
LogPrint (eLogWarning, "Tunnel: pending build request ", it->first, " timeout, deleted");
// update stats
auto config = tunnel->GetTunnelConfig ();
if (config)
{
auto hop = config->GetFirstHop ();
while (hop)
{
2015-11-03 14:15:49 +00:00
if (hop->ident)
{
auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ());
if (profile)
profile->TunnelNonReplied ();
}
hop = hop->next;
}
}
// delete
it = pendingTunnels.erase (it);
2015-02-28 12:59:34 +00:00
m_NumFailedTunnelCreations++;
2014-09-26 14:15:34 +00:00
}
else
it++;
break;
case eTunnelStateBuildFailed:
2016-01-28 02:54:42 +00:00
LogPrint (eLogWarning, "Tunnel: pending build request ", it->first, " failed, deleted");
it = pendingTunnels.erase (it);
2015-02-28 12:59:34 +00:00
m_NumFailedTunnelCreations++;
2014-09-26 14:15:34 +00:00
break;
case eTunnelStateBuildReplyReceived:
2015-01-27 19:55:46 +00:00
// intermediate state, will be either established of build failed
it++;
2014-09-26 14:15:34 +00:00
break;
default:
2015-02-28 12:59:34 +00:00
// success
it = pendingTunnels.erase (it);
2015-02-28 12:59:34 +00:00
m_NumSuccesiveTunnelCreations++;
2014-09-26 14:15:34 +00:00
}
2013-12-07 00:02:49 +00:00
}
2014-10-06 16:50:36 +00:00
}
2013-12-07 00:02:49 +00:00
void Tunnels::ManageOutboundTunnels ()
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
2013-12-07 00:02:49 +00:00
{
2014-08-31 12:56:03 +00:00
for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();)
2013-12-07 00:02:49 +00:00
{
2014-09-13 23:43:25 +00:00
auto tunnel = *it;
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
2014-08-31 12:56:03 +00:00
{
2016-01-18 00:00:00 +00:00
LogPrint (eLogDebug, "Tunnel: tunnel with id ", tunnel->GetTunnelID (), " expired");
2015-04-15 01:37:21 +00:00
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->TunnelExpired (tunnel);
it = m_OutboundTunnels.erase (it);
2014-08-31 12:56:03 +00:00
}
else
{
2015-04-17 15:36:42 +00:00
if (tunnel->IsEstablished ())
2015-04-15 01:37:21 +00:00
{
2015-04-17 15:36:42 +00:00
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
tunnel->SetIsRecreated ();
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->RecreateOutboundTunnel (tunnel);
}
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring);
2015-04-15 01:37:21 +00:00
}
2014-08-31 12:56:03 +00:00
it++;
}
2014-08-26 14:31:32 +00:00
}
2014-08-31 12:56:03 +00:00
}
2013-12-07 00:02:49 +00:00
if (m_OutboundTunnels.size () < 5)
2013-12-07 00:02:49 +00:00
{
// trying to create one more oubound tunnel
2015-01-27 19:55:46 +00:00
auto inboundTunnel = GetNextInboundTunnel ();
2015-04-03 14:02:45 +00:00
auto router = i2p::data::netdb.GetRandomRouter ();
if (!inboundTunnel || !router) return;
2016-01-18 00:00:00 +00:00
LogPrint (eLogDebug, "Tunnel: creating one hop outbound tunnel");
CreateTunnel<OutboundTunnel> (
2015-11-03 14:15:49 +00:00
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () },
inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ())
2015-04-03 14:02:45 +00:00
);
2013-12-07 00:02:49 +00:00
}
}
void Tunnels::ManageInboundTunnels ()
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
2013-12-07 00:02:49 +00:00
{
2014-08-31 12:56:03 +00:00
for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();)
2013-12-07 00:02:49 +00:00
{
2014-09-13 23:43:25 +00:00
auto tunnel = it->second;
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
2014-08-31 12:56:03 +00:00
{
2016-01-18 00:00:00 +00:00
LogPrint (eLogDebug, "Tunnel: tunnel with id ", tunnel->GetTunnelID (), " expired");
2015-04-15 01:37:21 +00:00
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->TunnelExpired (tunnel);
it = m_InboundTunnels.erase (it);
2014-08-31 12:56:03 +00:00
}
else
{
2015-04-17 15:36:42 +00:00
if (tunnel->IsEstablished ())
2015-04-15 01:37:21 +00:00
{
2015-04-17 15:36:42 +00:00
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
tunnel->SetIsRecreated ();
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->RecreateInboundTunnel (tunnel);
}
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring);
2015-04-15 01:37:21 +00:00
}
2014-08-31 12:56:03 +00:00
it++;
}
2014-08-26 14:31:32 +00:00
}
2014-08-31 12:56:03 +00:00
}
2013-12-10 13:10:49 +00:00
if (m_InboundTunnels.empty ())
{
2016-01-18 00:00:00 +00:00
LogPrint (eLogDebug, "Tunnel: Creating zero hops inbound tunnel");
2013-12-10 13:10:49 +00:00
CreateZeroHopsInboundTunnel ();
if (!m_ExploratoryPool)
{
m_ExploratoryPool = CreateTunnelPool (2, 2, 5, 5); // 2-hop exploratory, 5 tunnels
m_ExploratoryPool->SetLocalDestination (i2p::context.GetSharedDestination ());
}
2013-12-10 13:10:49 +00:00
return;
}
2013-12-07 00:02:49 +00:00
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5)
2013-12-07 00:02:49 +00:00
{
2015-04-03 14:02:45 +00:00
// trying to create one more inbound tunnel
auto router = i2p::data::netdb.GetRandomRouter ();
2016-02-10 00:00:00 +00:00
if (!router) {
LogPrint (eLogWarning, "Tunnel: can't find any router, skip creating tunnel");
return;
}
2016-01-18 00:00:00 +00:00
LogPrint (eLogDebug, "Tunnel: creating one hop inbound tunnel");
CreateTunnel<InboundTunnel> (
2015-11-03 14:15:49 +00:00
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () })
2015-04-03 14:02:45 +00:00
);
2013-12-07 00:02:49 +00:00
}
}
2014-01-04 03:56:28 +00:00
void Tunnels::ManageTransitTunnels ()
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();)
{
if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
2014-07-03 23:53:11 +00:00
auto tmp = it->second;
2016-01-18 00:00:00 +00:00
LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tmp->GetTunnelID (), " expired");
2014-09-14 11:50:01 +00:00
{
std::unique_lock<std::mutex> l(m_TransitTunnelsMutex);
it = m_TransitTunnels.erase (it);
}
2014-07-03 23:53:11 +00:00
delete tmp;
2014-01-04 03:56:28 +00:00
}
else
it++;
}
}
2014-03-15 00:24:12 +00:00
void Tunnels::ManageTunnelPools ()
{
2014-10-05 15:01:12 +00:00
std::unique_lock<std::mutex> l(m_PoolsMutex);
for (auto it: m_Pools)
2014-03-17 20:50:03 +00:00
{
2015-01-20 03:28:13 +00:00
auto pool = it;
if (pool && pool->IsActive ())
2014-10-11 13:01:08 +00:00
{
pool->CreateTunnels ();
pool->TestTunnels ();
}
2014-03-17 20:50:03 +00:00
}
2014-03-15 00:24:12 +00:00
}
2013-12-07 00:02:49 +00:00
void Tunnels::PostTunnelData (std::shared_ptr<I2NPMessage> msg)
2013-12-07 00:02:49 +00:00
{
if (msg) m_Queue.Put (msg);
}
void Tunnels::PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
2015-01-23 03:00:41 +00:00
{
m_Queue.Put (msgs);
}
2013-12-07 00:02:49 +00:00
template<class TTunnel>
2015-05-06 20:17:48 +00:00
std::shared_ptr<TTunnel> Tunnels::CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel)
2013-12-07 00:02:49 +00:00
{
2015-01-27 19:55:46 +00:00
auto newTunnel = std::make_shared<TTunnel> (config);
2015-11-03 14:15:49 +00:00
uint32_t replyMsgID;
RAND_bytes ((uint8_t *)&replyMsgID, 4);
AddPendingTunnel (replyMsgID, newTunnel);
2014-09-27 21:51:55 +00:00
newTunnel->Build (replyMsgID, outboundTunnel);
2013-12-07 00:02:49 +00:00
return newTunnel;
}
2015-01-27 19:55:46 +00:00
void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel)
{
m_PendingInboundTunnels[replyMsgID] = tunnel;
}
2015-01-27 19:55:46 +00:00
void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel)
{
m_PendingOutboundTunnels[replyMsgID] = tunnel;
}
2015-01-27 19:55:46 +00:00
void Tunnels::AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel)
2013-12-07 00:02:49 +00:00
{
2013-12-10 13:10:49 +00:00
m_OutboundTunnels.push_back (newTunnel);
2014-03-16 20:03:20 +00:00
auto pool = newTunnel->GetTunnelPool ();
if (pool && pool->IsActive ())
2014-03-16 20:03:20 +00:00
pool->TunnelCreated (newTunnel);
else
newTunnel->SetTunnelPool (nullptr);
2013-12-07 00:02:49 +00:00
}
2015-01-27 19:55:46 +00:00
void Tunnels::AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel)
2013-12-07 00:02:49 +00:00
{
2014-03-15 00:51:51 +00:00
m_InboundTunnels[newTunnel->GetTunnelID ()] = newTunnel;
auto pool = newTunnel->GetTunnelPool ();
2014-03-15 00:24:12 +00:00
if (!pool)
2014-03-15 00:51:51 +00:00
{
// build symmetric outbound tunnel
2015-11-03 14:15:49 +00:00
CreateTunnel<OutboundTunnel> (std::make_shared<TunnelConfig>(newTunnel->GetInvertedPeers (),
newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()),
GetNextOutboundTunnel ());
}
2014-03-15 00:24:12 +00:00
else
{
if (pool->IsActive ())
pool->TunnelCreated (newTunnel);
else
newTunnel->SetTunnelPool (nullptr);
}
2013-12-07 00:02:49 +00:00
}
void Tunnels::CreateZeroHopsInboundTunnel ()
{
2013-12-10 13:10:49 +00:00
CreateTunnel<InboundTunnel> (
2015-11-03 14:15:49 +00:00
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >
2014-01-09 00:30:47 +00:00
{
2015-11-03 14:15:49 +00:00
i2p::context.GetIdentity ()
2014-01-09 00:30:47 +00:00
}));
2013-12-07 00:02:49 +00:00
}
int Tunnels::GetTransitTunnelsExpirationTimeout ()
{
int timeout = 0;
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(m_TransitTunnelsMutex);
for (auto it: m_TransitTunnels)
{
int t = it.second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts;
if (t > timeout) timeout = t;
}
return timeout;
}
2013-12-07 00:02:49 +00:00
}
}
2016-01-17 16:10:56 +00:00