diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index cb6e5dd2..17b0e80e 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -417,8 +417,7 @@ namespace transport { auto ts = i2p::util::GetSecondsSinceEpoch (); std::unique_lock l(m_PeersMutex); - it = m_Peers.insert (std::pair(ident, { 0, r, {}, - ts, ts + PEER_ROUTER_INFO_UPDATE_INTERVAL, {} })).first; + it = m_Peers.insert (std::pair(ident, {r, ts})).first; } connected = ConnectToPeer (ident, it->second); } @@ -453,127 +452,81 @@ namespace transport peer.router = netdb.FindRouter (ident); // try to get new one from netdb if (peer.router) // we have RI already { - if (peer.numAttempts < 2) // NTCP2, 0 - ipv6, 1 - ipv4 + if (peer.priority.empty ()) + SetPriority (peer); + while (peer.numAttempts < (int)peer.priority.size ()) { - if (m_NTCP2Server) // we support NTCP2 + auto tr = peer.priority[peer.numAttempts]; + peer.numAttempts++; + switch (tr) { - std::shared_ptr address; - if (!peer.numAttempts) // NTCP2 ipv6 - { - if (context.GetRouterInfo ().IsNTCP2V6 () && peer.router->IsReachableBy (RouterInfo::eNTCP2V6)) + case i2p::data::RouterInfo::eNTCP2V4: + case i2p::data::RouterInfo::eNTCP2V6: + { + if (!m_NTCP2Server) continue; + std::shared_ptr address = (tr == i2p::data::RouterInfo::eNTCP2V6) ? + peer.router->GetPublishedNTCP2V6Address () : peer.router->GetPublishedNTCP2V4Address (); + if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + address = nullptr; + if (address) { - address = peer.router->GetPublishedNTCP2V6Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; + auto s = std::make_shared (*m_NTCP2Server, peer.router, address); + if( m_NTCP2Server->UsingProxy()) + m_NTCP2Server->ConnectWithProxy(s); + else + m_NTCP2Server->Connect (s); + return true; } - peer.numAttempts++; + break; } - if (!address && peer.numAttempts == 1) // NTCP2 ipv4 + case i2p::data::RouterInfo::eSSU2V4: + case i2p::data::RouterInfo::eSSU2V6: { - if (context.GetRouterInfo ().IsNTCP2 (true) && peer.router->IsReachableBy (RouterInfo::eNTCP2V4)) + if (!m_SSU2Server) continue; + std::shared_ptr address = (tr == i2p::data::RouterInfo::eSSU2V6) ? + peer.router->GetSSU2V6Address () : peer.router->GetSSU2V4Address (); + if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + address = nullptr; + if (address && address->IsReachableSSU ()) { - address = peer.router->GetPublishedNTCP2V4Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; + if (m_SSU2Server->CreateSession (peer.router, address)) + return true; } - peer.numAttempts++; - } - if (address) + break; + } + case i2p::data::RouterInfo::eSSUV4: + case i2p::data::RouterInfo::eSSUV6: { - auto s = std::make_shared (*m_NTCP2Server, peer.router, address); - if( m_NTCP2Server->UsingProxy()) - m_NTCP2Server->ConnectWithProxy(s); - else - m_NTCP2Server->Connect (s); - return true; - } - } - else - peer.numAttempts = 2; // switch to SSU - } - if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU2, 2 - ipv6, 3 - ipv4 - { - if (m_SSU2Server) - { - std::shared_ptr address; - if (peer.numAttempts == 2) // SSU2 ipv6 - { - if (context.GetRouterInfo ().IsSSU2V6 () && peer.router->IsReachableBy (RouterInfo::eSSU2V6)) + if (!m_SSUServer) continue; + std::shared_ptr address = (tr == i2p::data::RouterInfo::eSSUV6) ? + peer.router->GetSSUV6Address () : peer.router->GetSSUAddress (true); + if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + address = nullptr; + if (address && address->IsReachableSSU ()) { - address = peer.router->GetSSU2V6Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; + if (m_SSUServer->CreateSession (peer.router, address)) + return true; } - peer.numAttempts++; - } - if (!address && peer.numAttempts == 3) // SSU2 ipv4 + break; + } + case i2p::data::RouterInfo::eNTCP2V6Mesh: { - if (context.GetRouterInfo ().IsSSU2V4 () && peer.router->IsReachableBy (RouterInfo::eSSU2V4)) + if (!m_NTCP2Server) continue; + auto address = peer.router->GetYggdrasilAddress (); + if (address) { - address = peer.router->GetSSU2V4Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (address && address->IsReachableSSU ()) - { - if (m_SSU2Server->CreateSession (peer.router, address)) - return true; - } - } - else - peer.numAttempts += 2; // switch to mesh - } - if (peer.numAttempts == 4) // Mesh - { - peer.numAttempts++; - if (m_NTCP2Server && context.GetRouterInfo ().IsMesh () && peer.router->IsMesh ()) - { - auto address = peer.router->GetYggdrasilAddress (); - if (address) - { - auto s = std::make_shared (*m_NTCP2Server, peer.router, address); - m_NTCP2Server->Connect (s); - return true; - } - } - } - if (peer.numAttempts == 5 || peer.numAttempts == 6) // SSU, 5 - ipv6, 6 - ipv4 - { - if (m_SSUServer) - { - std::shared_ptr address; - if (peer.numAttempts == 5) // SSU ipv6 - { - if (context.GetRouterInfo ().IsSSUV6 () && peer.router->IsReachableBy (RouterInfo::eSSUV6)) - { - address = peer.router->GetSSUV6Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (!address && peer.numAttempts == 6) // SSU ipv4 - { - if (context.GetRouterInfo ().IsSSU (true) && peer.router->IsReachableBy (RouterInfo::eSSUV4)) - { - address = peer.router->GetSSUAddress (true); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (address && address->IsReachableSSU ()) - { - if (m_SSUServer->CreateSession (peer.router, address)) + auto s = std::make_shared (*m_NTCP2Server, peer.router, address); + m_NTCP2Server->Connect (s); return true; - } - } - else - peer.numAttempts += 2; - } - LogPrint (eLogInfo, "Transports: No compatble NTCP2 or SSU addresses available"); + } + break; + } + default: + LogPrint (eLogError, "Transports: Unknown transport ", (int)tr); + } + } + + LogPrint (eLogInfo, "Transports: No compatible addresses available"); i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed peer.Done (); std::unique_lock l(m_PeersMutex); @@ -585,10 +538,32 @@ namespace transport LogPrint (eLogInfo, "Transports: RouterInfo for ", ident.ToBase64 (), " not found, requested"); i2p::data::netdb.RequestDestination (ident, std::bind ( &Transports::RequestComplete, this, std::placeholders::_1, ident)); - } + } return true; - } - + } + + void Transports::SetPriority (Peer& peer) const + { + static const std::vector ntcp2Priority = + { + i2p::data::RouterInfo::eNTCP2V6, + i2p::data::RouterInfo::eNTCP2V4, + i2p::data::RouterInfo::eSSU2V6, + i2p::data::RouterInfo::eSSU2V4, + i2p::data::RouterInfo::eNTCP2V6Mesh, + i2p::data::RouterInfo::eSSUV6, + i2p::data::RouterInfo::eSSUV4 + }; + if (!peer.router) return; + auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) & + peer.router->GetCompatibleTransports (true); + peer.numAttempts = 0; + peer.priority.clear (); + for (auto transport: ntcp2Priority) + if (transport & compatibleTransports) + peer.priority.push_back (transport); + } + void Transports::RequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident) { m_Service->post (std::bind (&Transports::HandleRequestComplete, this, r, ident)); @@ -779,8 +754,7 @@ namespace transport session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore auto ts = i2p::util::GetSecondsSinceEpoch (); std::unique_lock l(m_PeersMutex); - m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, - ts, ts + PEER_ROUTER_INFO_UPDATE_INTERVAL, {} })); + m_Peers.insert (std::make_pair (ident, Peer{ nullptr, ts })); } }); } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 4f33b317..362c5ead 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -71,7 +71,14 @@ namespace transport std::list > sessions; uint64_t creationTime, nextRouterInfoUpdateTime; std::vector > delayedMessages; + std::vector priority; + Peer (std::shared_ptr r, uint64_t ts): + numAttempts (0), router (r), creationTime (ts), + nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL) + { + } + void Done () { for (auto& it: sessions) @@ -147,6 +154,7 @@ namespace transport void HandleRequestComplete (std::shared_ptr r, i2p::data::IdentHash ident); void PostMessages (i2p::data::IdentHash ident, std::vector > msgs); bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer); + void SetPriority (Peer& peer) const; void HandlePeerCleanupTimer (const boost::system::error_code& ecode); void HandlePeerTestTimer (const boost::system::error_code& ecode);