use share_ptr to store peers

This commit is contained in:
orignal 2024-04-27 08:18:49 -04:00
parent bb6212ccc1
commit 8fe989050e
2 changed files with 82 additions and 72 deletions

View File

@ -457,6 +457,7 @@ namespace transport
return; return;
} }
if(RoutesRestricted() && !IsRestrictedPeer(ident)) return; if(RoutesRestricted() && !IsRestrictedPeer(ident)) return;
std::shared_ptr<Peer> peer;
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
if (it == m_Peers.end ()) if (it == m_Peers.end ())
{ {
@ -470,10 +471,12 @@ namespace transport
if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable
{ {
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
peer = std::make_shared<Peer>(r, ts);
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, {r, ts})).first; peer = m_Peers.emplace (ident, peer).first->second;
} }
connected = ConnectToPeer (ident, it->second); if (peer)
connected = ConnectToPeer (ident, peer);
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
@ -481,11 +484,15 @@ namespace transport
} }
if (!connected) return; if (!connected) return;
} }
if (it->second.IsConnected ()) else
it->second.sessions.front ()->SendI2NPMessages (msgs); peer = it->second;
if (!peer) return;
if (peer->IsConnected ())
peer->sessions.front ()->SendI2NPMessages (msgs);
else else
{ {
auto sz = it->second.delayedMessages.size (); auto sz = peer->delayedMessages.size ();
if (sz < MAX_NUM_DELAYED_MESSAGES) if (sz < MAX_NUM_DELAYED_MESSAGES)
{ {
if (sz < CHECK_PROFILE_NUM_DELAYED_MESSAGES && sz + msgs.size () >= CHECK_PROFILE_NUM_DELAYED_MESSAGES) if (sz < CHECK_PROFILE_NUM_DELAYED_MESSAGES && sz + msgs.size () >= CHECK_PROFILE_NUM_DELAYED_MESSAGES)
@ -494,7 +501,7 @@ namespace transport
{ {
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped"); LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it); m_Peers.erase (ident);
return; return;
} }
} }
@ -502,30 +509,30 @@ namespace transport
if (sz > MAX_NUM_DELAYED_MESSAGES/2 && it1->onDrop) if (sz > MAX_NUM_DELAYED_MESSAGES/2 && it1->onDrop)
it1->Drop (); // drop earlier because we can handle it it1->Drop (); // drop earlier because we can handle it
else else
it->second.delayedMessages.push_back (it1); peer->delayedMessages.push_back (it1);
} }
else else
{ {
LogPrint (eLogWarning, "Transports: Delayed messages queue size to ", LogPrint (eLogWarning, "Transports: Delayed messages queue size to ",
ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES); ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES);
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it); m_Peers.erase (ident);
} }
} }
} }
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer) bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr<Peer> peer)
{ {
if (!peer.router) // reconnect if (!peer->router) // reconnect
peer.SetRouter (netdb.FindRouter (ident)); // try to get new one from netdb peer->SetRouter (netdb.FindRouter (ident)); // try to get new one from netdb
if (peer.router) // we have RI already if (peer->router) // we have RI already
{ {
if (peer.priority.empty ()) if (peer->priority.empty ())
SetPriority (peer); SetPriority (peer);
while (peer.numAttempts < (int)peer.priority.size ()) while (peer->numAttempts < (int)peer->priority.size ())
{ {
auto tr = peer.priority[peer.numAttempts]; auto tr = peer->priority[peer->numAttempts];
peer.numAttempts++; peer->numAttempts++;
switch (tr) switch (tr)
{ {
case i2p::data::RouterInfo::eNTCP2V4: case i2p::data::RouterInfo::eNTCP2V4:
@ -533,12 +540,12 @@ namespace transport
{ {
if (!m_NTCP2Server) continue; if (!m_NTCP2Server) continue;
std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eNTCP2V6) ? std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eNTCP2V6) ?
peer.router->GetPublishedNTCP2V6Address () : peer.router->GetPublishedNTCP2V4Address (); peer->router->GetPublishedNTCP2V6Address () : peer->router->GetPublishedNTCP2V4Address ();
if (address && IsInReservedRange(address->host)) if (address && IsInReservedRange(address->host))
address = nullptr; address = nullptr;
if (address) if (address)
{ {
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address); auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer->router, address);
if( m_NTCP2Server->UsingProxy()) if( m_NTCP2Server->UsingProxy())
m_NTCP2Server->ConnectWithProxy(s); m_NTCP2Server->ConnectWithProxy(s);
else else
@ -552,12 +559,12 @@ namespace transport
{ {
if (!m_SSU2Server) continue; if (!m_SSU2Server) continue;
std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eSSU2V6) ? std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eSSU2V6) ?
peer.router->GetSSU2V6Address () : peer.router->GetSSU2V4Address (); peer->router->GetSSU2V6Address () : peer->router->GetSSU2V4Address ();
if (address && IsInReservedRange(address->host)) if (address && IsInReservedRange(address->host))
address = nullptr; address = nullptr;
if (address && address->IsReachableSSU ()) if (address && address->IsReachableSSU ())
{ {
if (m_SSU2Server->CreateSession (peer.router, address)) if (m_SSU2Server->CreateSession (peer->router, address))
return true; return true;
} }
break; break;
@ -565,10 +572,10 @@ namespace transport
case i2p::data::RouterInfo::eNTCP2V6Mesh: case i2p::data::RouterInfo::eNTCP2V6Mesh:
{ {
if (!m_NTCP2Server) continue; if (!m_NTCP2Server) continue;
auto address = peer.router->GetYggdrasilAddress (); auto address = peer->router->GetYggdrasilAddress ();
if (address) if (address)
{ {
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address); auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer->router, address);
m_NTCP2Server->Connect (s); m_NTCP2Server->Connect (s);
return true; return true;
} }
@ -580,9 +587,9 @@ namespace transport
} }
LogPrint (eLogInfo, "Transports: No compatible addresses available"); LogPrint (eLogInfo, "Transports: No compatible addresses available");
if (peer.router->IsReachableFrom (i2p::context.GetRouterInfo ())) if (peer->router->IsReachableFrom (i2p::context.GetRouterInfo ()))
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them
peer.Done (); peer->Done ();
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident); m_Peers.erase (ident);
return false; return false;
@ -590,7 +597,7 @@ namespace transport
else if (i2p::data::IsRouterBanned (ident)) else if (i2p::data::IsRouterBanned (ident))
{ {
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped"); LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
peer.Done (); peer->Done ();
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident); m_Peers.erase (ident);
return false; return false;
@ -604,7 +611,7 @@ namespace transport
return true; return true;
} }
void Transports::SetPriority (Peer& peer) const void Transports::SetPriority (std::shared_ptr<Peer> peer) const
{ {
static const std::vector<i2p::data::RouterInfo::SupportedTransports> static const std::vector<i2p::data::RouterInfo::SupportedTransports>
ntcp2Priority = ntcp2Priority =
@ -623,13 +630,13 @@ namespace transport
i2p::data::RouterInfo::eNTCP2V4, i2p::data::RouterInfo::eNTCP2V4,
i2p::data::RouterInfo::eNTCP2V6Mesh i2p::data::RouterInfo::eNTCP2V6Mesh
}; };
if (!peer.router) return; if (!peer || !peer->router) return;
auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) & auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) &
peer.router->GetCompatibleTransports (true); peer->router->GetCompatibleTransports (true);
auto directTransports = compatibleTransports & peer.router->GetPublishedTransports (); auto directTransports = compatibleTransports & peer->router->GetPublishedTransports ();
peer.numAttempts = 0; peer->numAttempts = 0;
peer.priority.clear (); peer->priority.clear ();
bool isReal = peer.router->GetProfile ()->IsReal (); bool isReal = peer->router->GetProfile ()->IsReal ();
bool ssu2 = isReal ? (rand () & 1) : false; // try NTCP2 if router is not confirmed real bool ssu2 = isReal ? (rand () & 1) : false; // try NTCP2 if router is not confirmed real
const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority; const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority;
if (directTransports) if (directTransports)
@ -643,7 +650,7 @@ namespace transport
} }
for (auto transport: priority) for (auto transport: priority)
if (transport & directTransports) if (transport & directTransports)
peer.priority.push_back (transport); peer->priority.push_back (transport);
compatibleTransports &= ~directTransports; compatibleTransports &= ~directTransports;
} }
if (compatibleTransports) if (compatibleTransports)
@ -651,7 +658,7 @@ namespace transport
// then remaining // then remaining
for (auto transport: priority) for (auto transport: priority)
if (transport & compatibleTransports) if (transport & compatibleTransports)
peer.priority.push_back (transport); peer->priority.push_back (transport);
} }
} }
@ -668,8 +675,8 @@ namespace transport
if (r) if (r)
{ {
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect"); LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
it->second.SetRouter (r); it->second->SetRouter (r);
if (!it->second.IsConnected ()) if (!it->second->IsConnected ())
ConnectToPeer (ident, it->second); ConnectToPeer (ident, it->second);
} }
else else
@ -796,31 +803,32 @@ namespace transport
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
if (it != m_Peers.end ()) if (it != m_Peers.end ())
{ {
if (it->second.numAttempts > 1) auto peer = it->second;
if (peer->numAttempts > 1)
{ {
// exclude failed transports // exclude failed transports
i2p::data::RouterInfo::CompatibleTransports transports = 0; i2p::data::RouterInfo::CompatibleTransports transports = 0;
int numExcluded = it->second.numAttempts - 1; int numExcluded = peer->numAttempts - 1;
if (numExcluded > (int)it->second.priority.size ()) numExcluded = it->second.priority.size (); if (numExcluded > (int)peer->priority.size ()) numExcluded = peer->priority.size ();
for (int i = 0; i < numExcluded; i++) for (int i = 0; i < numExcluded; i++)
transports |= it->second.priority[i]; transports |= peer->priority[i];
i2p::data::netdb.ExcludeReachableTransports (ident, transports); i2p::data::netdb.ExcludeReachableTransports (ident, transports);
} }
if (it->second.router && it->second.numAttempts) if (peer->router && peer->numAttempts)
{ {
auto transport = it->second.priority[it->second.numAttempts-1]; auto transport = peer->priority[peer->numAttempts-1];
if (transport == i2p::data::RouterInfo::eNTCP2V4 || if (transport == i2p::data::RouterInfo::eNTCP2V4 ||
transport == i2p::data::RouterInfo::eNTCP2V6 || transport == i2p::data::RouterInfo::eNTCP2V6Mesh) transport == i2p::data::RouterInfo::eNTCP2V6 || transport == i2p::data::RouterInfo::eNTCP2V6Mesh)
it->second.router->GetProfile ()->Connected (); // outgoing NTCP2 connection if always real peer->router->GetProfile ()->Connected (); // outgoing NTCP2 connection if always real
i2p::data::netdb.SetUnreachable (ident, false); // clear unreachable i2p::data::netdb.SetUnreachable (ident, false); // clear unreachable
} }
it->second.numAttempts = 0; peer->numAttempts = 0;
it->second.router = nullptr; // we don't need RouterInfo after successive connect peer->router = nullptr; // we don't need RouterInfo after successive connect
bool sendDatabaseStore = true; bool sendDatabaseStore = true;
if (it->second.delayedMessages.size () > 0) if (it->second->delayedMessages.size () > 0)
{ {
// check if first message is our DatabaseStore (publishing) // check if first message is our DatabaseStore (publishing)
auto firstMsg = it->second.delayedMessages[0]; auto firstMsg = peer->delayedMessages[0];
if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore && if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore &&
i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ()) i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ())
sendDatabaseStore = false; // we have it in the list already sendDatabaseStore = false; // we have it in the list already
@ -829,9 +837,9 @@ namespace transport
session->SendLocalRouterInfo (); session->SendLocalRouterInfo ();
else else
session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds
it->second.sessions.push_back (session); peer->sessions.push_back (session);
session->SendI2NPMessages (it->second.delayedMessages); session->SendI2NPMessages (peer->delayedMessages);
it->second.delayedMessages.clear (); peer->delayedMessages.clear ();
} }
else // incoming connection or peer test else // incoming connection or peer test
{ {
@ -846,10 +854,11 @@ namespace transport
auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed
if (r) r->GetProfile ()->Connected (); if (r) r->GetProfile ()->Connected ();
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
auto peer = std::make_shared<Peer>(r, ts);
peer->sessions.push_back (session);
peer->router = nullptr;
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
auto it = m_Peers.insert (std::make_pair (ident, Peer{ r, ts })).first; m_Peers.emplace (ident, peer);
it->second.sessions.push_back (session);
it->second.router = nullptr;
} }
}); });
} }
@ -864,15 +873,16 @@ namespace transport
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
if (it != m_Peers.end ()) if (it != m_Peers.end ())
{ {
bool wasConnected = it->second.IsConnected (); auto peer = it->second;
it->second.sessions.remove (session); bool wasConnected = peer->IsConnected ();
if (!it->second.IsConnected ()) peer->sessions.remove (session);
if (!peer->IsConnected ())
{ {
if (it->second.delayedMessages.size () > 0) if (peer->delayedMessages.size () > 0)
{ {
if (wasConnected) // we had an active session before if (wasConnected) // we had an active session before
it->second.numAttempts = 0; // start over peer->numAttempts = 0; // start over
ConnectToPeer (ident, it->second); ConnectToPeer (ident, peer);
} }
else else
{ {
@ -898,12 +908,12 @@ namespace transport
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_Peers.begin (); it != m_Peers.end (); ) for (auto it = m_Peers.begin (); it != m_Peers.end (); )
{ {
it->second.sessions.remove_if ( it->second->sessions.remove_if (
[](std::shared_ptr<TransportSession> session)->bool [](std::shared_ptr<TransportSession> session)->bool
{ {
return !session || !session->IsEstablished (); return !session || !session->IsEstablished ();
}); });
if (!it->second.IsConnected () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) if (!it->second->IsConnected () && ts > it->second->creationTime + SESSION_CREATION_TIMEOUT)
{ {
LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds"); LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
/* if (!it->second.router) /* if (!it->second.router)
@ -917,12 +927,12 @@ namespace transport
} }
else else
{ {
if (ts > it->second.nextRouterInfoUpdateTime) if (ts > it->second->nextRouterInfoUpdateTime)
{ {
auto session = it->second.sessions.front (); auto session = it->second->sessions.front ();
if (session) if (session)
session->SendLocalRouterInfo (true); session->SendLocalRouterInfo (true);
it->second.nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL + it->second->nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL +
rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE; rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE;
} }
++it; ++it;
@ -1042,13 +1052,13 @@ namespace transport
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (bool isHighBandwidth) const std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (bool isHighBandwidth) const
{ {
return GetRandomPeer ( return GetRandomPeer (
[isHighBandwidth](const Peer& peer)->bool [isHighBandwidth](std::shared_ptr<const Peer> peer)->bool
{ {
// connected, not overloaded and not slow // connected, not overloaded and not slow
return !peer.router && peer.IsConnected () && peer.isReachable && return !peer->router && peer->IsConnected () && peer->isReachable &&
peer.sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE && peer->sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE &&
!peer.sessions.front ()->IsSlow () && !peer.sessions.front ()->IsBandwidthExceeded (peer.isHighBandwidth) && !peer->sessions.front ()->IsSlow () && !peer->sessions.front ()->IsBandwidthExceeded (peer->isHighBandwidth) &&
(!isHighBandwidth || peer.isHighBandwidth); (!isHighBandwidth || peer->isHighBandwidth);
}); });
} }

View File

@ -191,8 +191,8 @@ namespace transport
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident); void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident); void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs); void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer); bool ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr<Peer> peer);
void SetPriority (Peer& peer) const; void SetPriority (std::shared_ptr<Peer> peer) const;
void HandlePeerCleanupTimer (const boost::system::error_code& ecode); void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
void HandlePeerTestTimer (const boost::system::error_code& ecode); void HandlePeerTestTimer (const boost::system::error_code& ecode);
void HandleUpdateBandwidthTimer (const boost::system::error_code& ecode); void HandleUpdateBandwidthTimer (const boost::system::error_code& ecode);
@ -215,7 +215,7 @@ namespace transport
SSU2Server * m_SSU2Server; SSU2Server * m_SSU2Server;
NTCP2Server * m_NTCP2Server; NTCP2Server * m_NTCP2Server;
mutable std::mutex m_PeersMutex; mutable std::mutex m_PeersMutex;
std::unordered_map<i2p::data::IdentHash, Peer> m_Peers; std::unordered_map<i2p::data::IdentHash, std::shared_ptr<Peer> > m_Peers;
X25519KeysPairSupplier m_X25519KeysPairSupplier; X25519KeysPairSupplier m_X25519KeysPairSupplier;