From 9cd62d8873ef441eea2b9d6b6c6aea25a1e7003a Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 26 Sep 2014 10:15:34 -0400 Subject: [PATCH] fixed tunnel build race condition --- I2NPProtocol.cpp | 6 ++++++ Tunnel.cpp | 39 +++++++++++++++++++++++++++------------ Tunnel.h | 4 +++- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 427aa79a..d5bb0265 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -330,7 +330,10 @@ namespace i2p i2p::tunnel::tunnels.AddInboundTunnel (static_cast(tunnel)); } else + { LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been declined"); + tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed); + } } else { @@ -386,7 +389,10 @@ namespace i2p i2p::tunnel::tunnels.AddOutboundTunnel (static_cast(tunnel)); } else + { LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been declined"); + tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed); + } } else LogPrint ("Pending tunnel for message ", replyMsgID, " not found"); diff --git a/Tunnel.cpp b/Tunnel.cpp index 59eccc94..57c16184 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -246,7 +246,10 @@ namespace tunnel { auto it = m_PendingTunnels.find(replyMsgID); if (it != m_PendingTunnels.end ()) + { + it->second->SetState (eTunnelStateBuildReplyReceived); return it->second; + } return nullptr; } @@ -369,23 +372,35 @@ namespace tunnel void Tunnels::ManageTunnels () { - // check pending tunnel. delete non-successive + // check pending tunnel. delete failed or timeout uint64_t ts = i2p::util::GetSecondsSinceEpoch (); for (auto it = m_PendingTunnels.begin (); it != m_PendingTunnels.end ();) { - if (it->second->GetState () == eTunnelStatePending) + auto tunnel = it->second; + switch (tunnel->GetState ()) { - if (ts > it->second->GetCreationTime () + TUNNEL_CREATION_TIMEOUT) - { - LogPrint ("Pending tunnel build request ", it->first, " was not successive. Deleted"); - delete it->second; + case eTunnelStatePending: + if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT) + { + LogPrint ("Pending tunnel build request ", it->first, " timeout. Deleted"); + delete tunnel; + it = m_PendingTunnels.erase (it); + } + else + it++; + break; + case eTunnelStateBuildFailed: + LogPrint ("Pending tunnel build request ", it->first, " failed. Deleted"); + delete tunnel; it = m_PendingTunnels.erase (it); - } - else + break; + case eTunnelStateBuildReplyReceived: + // intermidiate state, will be either established of build failed it++; - } - else - it = m_PendingTunnels.erase (it); + break; + default: + it = m_PendingTunnels.erase (it); + } } ManageInboundTunnels (); @@ -405,7 +420,7 @@ namespace tunnel if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) { LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired"); - auto pool = (*it)->GetTunnelPool (); + auto pool = tunnel->GetTunnelPool (); if (pool) pool->TunnelExpired (tunnel); it = m_OutboundTunnels.erase (it); diff --git a/Tunnel.h b/Tunnel.h index a848e6b7..73a0e0c6 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -23,12 +23,14 @@ namespace tunnel { const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute - const int TUNNEL_CREATION_TIMEOUT = 20; // 20 seconds + const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds const int STANDARD_NUM_RECORDS = 5; // in VariableTunnelBuild message enum TunnelState { eTunnelStatePending, + eTunnelStateBuildReplyReceived, + eTunnelStateBuildFailed, eTunnelStateEstablished, eTunnelStateTestFailed, eTunnelStateFailed,