Merge pull request #598 from majestrate/master

recent work
This commit is contained in:
Jeff 2019-05-08 13:28:00 -04:00 committed by GitHub
commit e93c7559f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 454 additions and 203 deletions

View File

@ -154,8 +154,8 @@ extern "C"
// For utp_writev, to writes data from multiple buffers
struct utp_iovec
{
void *iov_base;
size_t iov_len;
void *iov_base = nullptr;
size_t iov_len = 0;
};
// Public Functions

View File

@ -348,8 +348,16 @@ __ ___ ____ _ _ ___ _ _ ____
llarp::LogInfo("SIGHUP");
if(router)
{
router->hiddenServiceContext().ForEachService(
[](const std::string &name,
const llarp::service::Endpoint_ptr &ep) -> bool {
ep->ResetInternalState();
llarp::LogInfo("Reset internal state for ", name);
return true;
});
router->PumpLL();
Config newconfig;
if(newconfig.Load(configfile.c_str()))
if(!newconfig.Load(configfile.c_str()))
{
llarp::LogError("failed to load config file ", configfile);
return;

View File

@ -138,8 +138,10 @@ namespace llarp
src = pkt.src();
pkt.UpdateIPv4PacketOnDst(src, m_IP);
const llarp_buffer_t& pktbuf = pkt.Buffer(); // life time extension
uint8_t queue_idx = pktbuf.sz / llarp::routing::ExitPadSize;
auto& queue = m_DownstreamQueues[queue_idx];
const uint8_t queue_idx = pktbuf.sz / llarp::routing::ExitPadSize;
if(m_DownstreamQueues.find(queue_idx) == m_DownstreamQueues.end())
m_DownstreamQueues.emplace(queue_idx, InboundTrafficQueue_t{});
auto& queue = m_DownstreamQueues.at(queue_idx);
if(queue.size() == 0)
{
queue.emplace_back();

View File

@ -58,10 +58,12 @@ namespace llarp
}
bool
BaseSession::SelectHop(llarp_nodedb* db, const RouterContact& prev,
BaseSession::SelectHop(llarp_nodedb* db, const std::set< RouterID >& prev,
RouterContact& cur, size_t hop,
llarp::path::PathRole roles)
{
std::set< RouterID > exclude = prev;
exclude.insert(m_ExitRouter);
if(hop == numHops - 1)
{
if(db->Get(m_ExitRouter, cur))
@ -69,13 +71,8 @@ namespace llarp
router->LookupRouter(m_ExitRouter, nullptr);
return false;
}
else if(hop == numHops - 2)
{
return db->select_random_hop_excluding(cur,
{prev.pubkey, m_ExitRouter});
}
else
return path::Builder::SelectHop(db, prev, cur, hop, roles);
return path::Builder::SelectHop(db, exclude, cur, hop, roles);
}
bool
@ -151,6 +148,29 @@ namespace llarp
m_PendingCallbacks.clear();
}
void
BaseSession::ResetInternalState()
{
auto sendExitClose = [&](const llarp::path::Path_ptr p) {
const static auto roles =
llarp::path::ePathRoleExit | llarp::path::ePathRoleSVC;
if(p->SupportsAnyRoles(roles))
{
llarp::LogInfo(p->Name(), " closing exit path");
llarp::routing::CloseExitMessage msg;
if(msg.Sign(router->crypto(), m_ExitIdentity)
&& p->SendExitClose(msg, router))
{
p->ClearRoles(roles);
}
else
llarp::LogWarn(p->Name(), " failed to send exit close message");
}
};
ForEachPath(sendExitClose);
path::Builder::ResetInternalState();
}
bool
BaseSession::Stop()
{
@ -234,6 +254,14 @@ namespace llarp
return m_LastUse && now > m_LastUse && now - m_LastUse > LifeSpan;
}
bool
BaseSession::UrgentBuild(llarp_time_t now) const
{
if(!IsReady())
return NumInStatus(path::ePathBuilding) < m_NumPaths;
return path::Builder::UrgentBuild(now);
}
bool
BaseSession::FlushUpstream()
{
@ -248,9 +276,11 @@ namespace llarp
{
auto& msg = queue.front();
msg.S = path->NextSeqNo();
if(path->SendRoutingMessage(msg, router))
if(path && path->SendRoutingMessage(msg, router))
m_LastUse = now;
queue.pop_front();
// spread across all paths
path = PickRandomEstablishedPath(llarp::path::ePathRoleExit);
}
}
}
@ -275,6 +305,8 @@ namespace llarp
r->TryConnectAsync(results[0], 5);
});
}
else if(UrgentBuild(now))
BuildOneAlignedTo(m_ExitRouter);
}
return true;
}

View File

@ -48,6 +48,11 @@ namespace llarp
return m_BundleRC;
}
virtual void
ResetInternalState() override;
bool UrgentBuild(llarp_time_t) const override;
void
HandlePathDied(llarp::path::Path_ptr p) override;
@ -55,8 +60,9 @@ namespace llarp
CheckPathDead(path::Path_ptr p, llarp_time_t dlt);
bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop, llarp::path::PathRole roles) override;
SelectHop(llarp_nodedb* db, const std::set< RouterID >& prev,
RouterContact& cur, size_t hop,
llarp::path::PathRole roles) override;
bool
ShouldBuildMore(llarp_time_t now) const override;

View File

@ -185,6 +185,22 @@ namespace llarp
return m_Router->Now();
}
bool
ExitEndpoint::VisitEndpointsFor(
const PubKey &pk, std::function< bool(exit::Endpoint *const) > visit)
{
auto range = m_ActiveExits.equal_range(pk);
auto itr = range.first;
while(itr != range.second)
{
if(visit(itr->second.get()))
++itr;
else
return true;
}
return false;
}
void
ExitEndpoint::Flush()
{
@ -213,21 +229,22 @@ namespace llarp
return;
}
}
exit::Endpoint *ep = m_ChosenExits[pk];
if(ep == nullptr)
{
// we may have all dead sessions, wtf now?
LogWarn(Name(), " dropped inbound traffic for session ", pk,
" as we have no working endpoints");
}
else
{
auto tryFlushingTraffic = [&](exit::Endpoint *const ep) -> bool {
if(!ep->QueueInboundTraffic(ManagedBuffer{pkt.Buffer()}))
{
LogWarn(Name(), " dropped inbound traffic for session ", pk,
" as we are overloaded (probably)");
// continue iteration
return true;
}
// break iteration
return false;
};
if(!VisitEndpointsFor(pk, tryFlushingTraffic))
{
// we may have all dead sessions, wtf now?
LogWarn(Name(), " dropped inbound traffic for session ", pk,
" as we have no working endpoints");
}
});
{

View File

@ -25,6 +25,10 @@ namespace llarp
std::string
Name() const;
bool
VisitEndpointsFor(const PubKey& pk,
std::function< bool(exit::Endpoint* const) > visit);
util::StatusObject
ExtractStatus() const;

View File

@ -433,6 +433,14 @@ namespace llarp
return true;
}
void
TunEndpoint::ResetInternalState()
{
service::Endpoint::ResetInternalState();
if(m_Exit)
m_Exit->ResetInternalState();
}
// FIXME: pass in which question it should be addressing
bool
TunEndpoint::ShouldHookDNSMessage(const dns::Message &msg) const

View File

@ -153,6 +153,9 @@ namespace llarp
void
Flush();
virtual void
ResetInternalState() override;
protected:
using PacketQueue_t = llarp::util::CoDelQueue<
net::IPv4Packet, net::IPv4Packet::GetTime, net::IPv4Packet::PutTime,

View File

@ -5,6 +5,8 @@
namespace llarp
{
static constexpr size_t MaxSessionsPerKey = 16;
ILinkLayer::ILinkLayer(const SecretKey& routerEncSecret, GetRCFunc getrc,
LinkMessageHandler handler, SignBufferFunc signbuf,
SessionEstablishedHandler establishedSession,
@ -152,7 +154,6 @@ namespace llarp
bool
ILinkLayer::MapAddr(const RouterID& pk, ILinkSession* s)
{
static constexpr size_t MaxSessionsPerKey = 16;
Lock l_authed(&m_AuthedLinksMutex);
Lock l_pending(&m_PendingMutex);
llarp::Addr addr = s->GetRemoteEndpoint();
@ -220,10 +221,20 @@ namespace llarp
bool
ILinkLayer::TryEstablishTo(RouterContact rc)
{
{
Lock l(&m_AuthedLinksMutex);
if(m_AuthedLinks.count(rc.pubkey) >= MaxSessionsPerKey)
return false;
}
llarp::AddressInfo to;
if(!PickAddress(rc, to))
return false;
llarp::Addr addr(to);
{
Lock l(&m_PendingMutex);
if(m_Pending.count(addr) >= MaxSessionsPerKey)
return false;
}
std::shared_ptr< ILinkSession > s = NewOutboundSession(rc, to);
if(PutSession(s))
{

View File

@ -202,6 +202,13 @@ namespace llarp
SessionClosedHandler SessionClosed;
SessionRenegotiateHandler SessionRenegotiate;
bool
operator<(const ILinkLayer& other) const
{
return Rank() < other.Rank() || Name() < other.Name()
|| m_ourAddr < other.m_ourAddr;
}
/// called by link session to remove a pending session who is timed out
// void
// RemovePending(ILinkSession* s) LOCKS_EXCLUDED(m_PendingMutex);

View File

@ -47,7 +47,7 @@ namespace llarp
/// return true if we are established
virtual bool
IsEstablished() = 0;
IsEstablished() const = 0;
/// return true if this session has timed out
virtual bool

View File

@ -37,7 +37,7 @@ operator==(const sockaddr& a, const sockaddr& b)
bool
operator<(const sockaddr_in6& a, const sockaddr_in6& b)
{
return memcmp(&a, &b, sizeof(sockaddr_in6)) < 0;
return a.sin6_addr < b.sin6_addr || a.sin6_port < b.sin6_port;
}
bool

View File

@ -82,6 +82,19 @@ namespace llarp
k.begin());
}
PathContext::EndpointPathPtrSet
PathContext::FindOwnedPathsWithEndpoint(const RouterID& r)
{
EndpointPathPtrSet found;
m_OurPaths.ForEach([&](const PathSet_ptr& set) {
set->ForEachPath([&](const Path_ptr& p) {
if(p->Endpoint() == r && p->IsReady())
found.insert(p);
});
});
return found;
}
bool
PathContext::ForwardLRCM(const RouterID& nextHop,
const std::array< EncryptedFrame, 8 >& frames)

View File

@ -12,6 +12,7 @@
#include <routing/message.hpp>
#include <service/intro.hpp>
#include <util/aligned.hpp>
#include <util/compare_ptr.hpp>
#include <util/threading.hpp>
#include <util/time.hpp>
@ -271,6 +272,8 @@ namespace llarp
AbstractRouter* r) override;
};
using TransitHop_ptr = std::shared_ptr< TransitHop >;
inline std::ostream&
operator<<(std::ostream& out, const TransitHop& h)
{
@ -302,6 +305,14 @@ namespace llarp
util::StatusObject
ExtractStatus() const;
bool
operator<(const PathHopConfig& other) const
{
return std::tie(txID, rxID, rc, upstream, lifetime)
< std::tie(other.txID, other.rxID, other.rc, other.upstream,
other.lifetime);
}
};
/// A path we made
@ -343,6 +354,12 @@ namespace llarp
return _role;
}
bool
operator<(const Path& other) const
{
return hops < other.hops;
}
void
MarkActive(llarp_time_t now)
{
@ -360,7 +377,14 @@ namespace llarp
bool
SupportsAnyRoles(PathRole roles) const
{
return roles == ePathRoleAny || (_role & roles) != 0;
return roles == ePathRoleAny || (_role | roles) != 0;
}
/// clear role bits
void
ClearRoles(PathRole roles)
{
_role &= ~roles;
}
PathStatus
@ -624,6 +648,11 @@ namespace llarp
routing::MessageHandler_ptr
GetHandler(const PathID_t& id);
using EndpointPathPtrSet = std::set< Path_ptr, ComparePtr< Path_ptr > >;
/// get a set of all paths that we own who's endpoint is r
EndpointPathPtrSet
FindOwnedPathsWithEndpoint(const RouterID& r);
bool
ForwardLRCM(const RouterID& nextHop,
const std::array< EncryptedFrame, 8 >& frames);
@ -643,13 +672,20 @@ namespace llarp
void
RemovePathSet(PathSet_ptr set);
using TransitHopsMap_t =
std::multimap< PathID_t, std::shared_ptr< TransitHop > >;
using TransitHopsMap_t = std::multimap< PathID_t, TransitHop_ptr >;
struct SyncTransitMap_t
{
util::Mutex first; // protects second
TransitHopsMap_t second GUARDED_BY(first);
void
ForEach(std::function< void(const TransitHop_ptr&) > visit)
{
util::Lock lock(&first);
for(const auto& item : second)
visit(item.second);
}
};
// maps path id -> pathset owner of path
@ -659,6 +695,14 @@ namespace llarp
{
util::Mutex first; // protects second
OwnedPathsMap_t second GUARDED_BY(first);
void
ForEach(std::function< void(const PathSet_ptr&) > visit)
{
util::Lock lock(&first);
for(const auto& item : second)
visit(item.second);
}
};
llarp_threadpool*

View File

@ -181,6 +181,13 @@ namespace llarp
{
}
void
Builder::ResetInternalState()
{
buildIntervalLimit = MIN_PATH_BUILD_INTERVAL;
lastBuild = 0;
}
void
Builder::Tick(llarp_time_t now)
{
@ -206,7 +213,7 @@ namespace llarp
}
bool
Builder::SelectHop(llarp_nodedb* db, const RouterContact& prev,
Builder::SelectHop(llarp_nodedb* db, const std::set< RouterID >& exclude,
RouterContact& cur, size_t hop, PathRole roles)
{
(void)roles;
@ -214,29 +221,37 @@ namespace llarp
if(hop == 0)
{
if(router->NumberOfConnectedRouters() == 0)
{
// persist connection
router->ConnectToRandomRouters(1);
return false;
}
bool got = false;
router->ForEachPeer(
[&](const ILinkSession* s, bool) {
const PubKey k(s->GetPubKey());
if(got || router->IsBootstrapNode(k))
return;
cur = s->GetRemoteRC();
got = true;
[&](const ILinkSession* s, bool isOutbound) {
if(s && s->IsEstablished() && isOutbound && !got)
{
const RouterContact rc = s->GetRemoteRC();
if(got || router->IsBootstrapNode(rc.pubkey)
|| exclude.count(rc.pubkey))
return;
cur = rc;
got = true;
}
},
true);
return got;
}
std::set< RouterID > exclude = {prev.pubkey};
do
{
cur.Clear();
--tries;
if(db->select_random_hop_excluding(cur, exclude))
std::set< RouterID > excluding = exclude;
if(db->select_random_hop_excluding(cur, excluding))
{
excluding.insert(cur.pubkey);
if(!router->routerProfiling().IsBadForPath(cur.pubkey))
return true;
exclude.insert(cur.pubkey);
}
} while(tries > 0);
return tries > 0;
@ -284,36 +299,98 @@ namespace llarp
void
Builder::BuildOne(PathRole roles)
{
std::vector< RouterContact > hops;
std::vector< RouterContact > hops(numHops);
if(SelectHops(router->nodedb(), hops, roles))
Build(hops, roles);
}
bool Builder::UrgentBuild(llarp_time_t) const
{
return buildIntervalLimit > MIN_PATH_BUILD_INTERVAL * 4;
}
bool
Builder::BuildOneAlignedTo(const RouterID remote)
{
std::vector< RouterContact > hops(0);
std::set< RouterID > routers = {remote};
/// if we really need this path build it "dangerously"
if(UrgentBuild(router->Now()))
{
const auto aligned =
router->pathContext().FindOwnedPathsWithEndpoint(remote);
/// pick the lowest latency path that aligns to remote
/// note: peer exuastion is made worse happen here
Path_ptr p;
llarp_time_t min = std::numeric_limits< llarp_time_t >::max();
for(const auto& path : aligned)
{
if(path->intro.latency < min && path->hops.size() == numHops)
{
p = path;
min = path->intro.latency;
}
}
if(p)
{
for(const auto& hop : p->hops)
{
if(hop.rc.pubkey.IsZero())
return false;
hops.emplace_back(hop.rc);
}
}
}
if(hops.size() == 0)
{
hops.resize(numHops);
auto nodedb = router->nodedb();
for(size_t idx = 0; idx < hops.size(); idx++)
{
hops[idx].Clear();
if(idx == numHops - 1)
{
// last hop
if(!nodedb->Get(remote, hops[idx]))
{
router->LookupRouter(remote, nullptr);
return false;
}
}
else
{
if(!SelectHop(nodedb, routers, hops[idx], idx, path::ePathRoleAny))
return false;
}
if(hops[idx].pubkey.IsZero())
return false;
routers.insert(hops[idx].pubkey);
}
}
LogInfo(Name(), " building path to ", remote);
Build(hops);
return true;
}
bool
Builder::SelectHops(llarp_nodedb* nodedb,
std::vector< RouterContact >& hops, PathRole roles)
{
hops.resize(numHops);
size_t idx = 0;
while(idx < numHops)
std::set< RouterID > exclude;
while(idx < hops.size())
{
hops[idx].Clear();
size_t tries = 4;
if(idx == 0)
{
while(tries > 0 && !SelectHop(nodedb, hops[0], hops[0], 0, roles))
--tries;
}
else
{
while(tries > 0
&& !SelectHop(nodedb, hops[idx - 1], hops[idx], idx, roles))
--tries;
}
if(tries == 0)
while(tries > 0 && !SelectHop(nodedb, exclude, hops[idx], idx, roles))
--tries;
if(tries == 0 || hops[idx].pubkey.IsZero())
{
LogWarn(Name(), " failed to select hop ", idx);
return false;
}
exclude.insert(hops[idx].pubkey);
++idx;
}
return true;
@ -337,6 +414,7 @@ namespace llarp
ctx->router = router;
ctx->pathset = GetSelf();
auto path = std::make_shared< path::Path >(hops, this, roles);
LogInfo(Name(), " build ", path->HopsString());
path->SetBuildResultHook(
[this](Path_ptr p) { this->HandlePathBuilt(p); });
ctx->AsyncGenerateKeys(path, router->logic(), router->threadpool(), this,
@ -356,8 +434,8 @@ namespace llarp
{
// linear backoff
static constexpr llarp_time_t MaxBuildInterval = 30 * 1000;
buildIntervalLimit =
std::min(MIN_PATH_BUILD_INTERVAL + buildIntervalLimit, MaxBuildInterval);
buildIntervalLimit = std::min(
MIN_PATH_BUILD_INTERVAL + buildIntervalLimit, MaxBuildInterval);
router->routerProfiling().MarkPathFail(p.get());
PathSet::HandlePathBuildTimeout(p);
LogWarn(Name(), " build interval is now ", buildIntervalLimit);

View File

@ -21,6 +21,9 @@ namespace llarp
/// flag for PathSet::Stop()
std::atomic< bool > _run;
virtual bool
UrgentBuild(llarp_time_t now) const;
public:
AbstractRouter* router;
llarp_dht_context* dht;
@ -39,8 +42,8 @@ namespace llarp
ExtractStatus() const;
virtual bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop, PathRole roles) override;
SelectHop(llarp_nodedb* db, const std::set< RouterID >& prev,
RouterContact& cur, size_t hop, PathRole roles) override;
virtual bool
ShouldBuildMore(llarp_time_t now) const override;
@ -49,6 +52,9 @@ namespace llarp
virtual bool
ShouldBundleRC() const = 0;
virtual void
ResetInternalState() override;
/// return true if we hit our soft limit for building paths too fast
bool
BuildCooldownHit(llarp_time_t now) const;
@ -78,6 +84,9 @@ namespace llarp
void
BuildOne(PathRole roles = ePathRoleAny) override;
bool
BuildOneAlignedTo(const RouterID endpoint) override;
void
Build(const std::vector< RouterContact >& hops,
PathRole roles = ePathRoleAny) override;

View File

@ -216,15 +216,16 @@ namespace llarp
return false;
}
/// reset all cooldown timers
virtual void
ResetInternalState() = 0;
virtual bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop, PathRole roles) = 0;
SelectHop(llarp_nodedb* db, const std::set< RouterID >& prev,
RouterContact& cur, size_t hop, PathRole roles) = 0;
protected:
size_t m_NumPaths;
void
TickPaths(llarp_time_t now, AbstractRouter* r);
virtual bool
BuildOneAlignedTo(const RouterID endpoint) = 0;
void
ForEachPath(std::function< void(const Path_ptr&) > visit) const
@ -238,6 +239,12 @@ namespace llarp
}
}
protected:
size_t m_NumPaths;
void
TickPaths(llarp_time_t now, AbstractRouter* r);
using PathInfo_t = std::pair< RouterID, PathID_t >;
struct PathInfoHash

View File

@ -193,16 +193,22 @@ namespace llarp
TransitHop::HandleCloseExitMessage(
const llarp::routing::CloseExitMessage& msg, AbstractRouter* r)
{
llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
const llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
auto ep = r->exitContext().FindEndpointForPath(info.rxID);
if(ep && msg.Verify(r->crypto(), ep->PubKey()))
{
ep->Close();
// ep is now gone af
llarp::routing::CloseExitMessage reply;
reply.Y = msg.Y;
reply.S = NextSeqNo();
if(reply.Sign(r->crypto(), r->identity()))
return SendRoutingMessage(reply, r);
{
if(SendRoutingMessage(reply, r))
{
r->PumpLL();
ep->Close();
return true;
}
}
}
return SendRoutingMessage(discard, r);
}

View File

@ -188,11 +188,16 @@ namespace llarp
Profiling::MarkPathFail(path::Path* p)
{
lock_t lock(&m_ProfilesMutex);
size_t idx = 0;
for(const auto& hop : p->hops)
{
// TODO: also mark bad?
m_Profiles[hop.rc.pubkey].pathFailCount += 1;
m_Profiles[hop.rc.pubkey].lastUpdated = llarp::time_now_ms();
// don't mark first hop as failure because we are connected to it directly
if(idx)
{
m_Profiles[hop.rc.pubkey].pathFailCount += 1;
m_Profiles[hop.rc.pubkey].lastUpdated = llarp::time_now_ms();
}
++idx;
}
}

View File

@ -358,8 +358,7 @@ namespace llarp
if(nodedb()->Get(remote, remoteRC))
{
// try connecting directly as the rc is loaded from disk
TryConnectAsync(remoteRC, 10);
return true;
return TryConnectAsync(remoteRC, 10);
}
// we don't have the RC locally so do a dht lookup
@ -1796,9 +1795,8 @@ namespace llarp
}
return want > 0;
});
if(wanted != want)
LogInfo("connecting to ", abs(want - wanted), " out of ", wanted,
" random routers");
LogInfo("connecting to ", abs(want - wanted), " out of ", wanted,
" random routers");
}
bool

View File

@ -55,19 +55,6 @@ struct TryConnectJob;
namespace llarp
{
template < typename T >
struct CompareLinks
{
bool
operator()(const std::unique_ptr< T > &left,
const std::unique_ptr< T > &right) const
{
const std::string leftName = left->Name();
const std::string rightName = right->Name();
return left->Rank() < right->Rank() || leftName < rightName;
}
};
struct Router final : public AbstractRouter
{
bool ready;
@ -292,10 +279,11 @@ namespace llarp
std::string lokidRPCUser = "";
std::string lokidRPCPassword = "";
std::set< std::unique_ptr< ILinkLayer >, CompareLinks< ILinkLayer > >
outboundLinks;
std::set< std::unique_ptr< ILinkLayer >, CompareLinks< ILinkLayer > >
inboundLinks;
using LinkLayer_ptr = std::unique_ptr< ILinkLayer >;
using LinkSet = std::set< LinkLayer_ptr, ComparePtr< LinkLayer_ptr > >;
LinkSet outboundLinks;
LinkSet inboundLinks;
Profiling _routerProfiling;
std::string routerProfilesFile = "profiles.dat";

View File

@ -596,6 +596,18 @@ namespace llarp
return false;
}
void
Endpoint::ResetInternalState()
{
path::Builder::ResetInternalState();
static auto resetState = [](auto& container) {
std::for_each(container.begin(), container.end(),
[](auto& item) { item.second->ResetInternalState(); });
};
resetState(m_RemoteSessions);
resetState(m_SNodeSessions);
}
bool
Endpoint::ShouldPublishDescriptors(llarp_time_t now) const
{

View File

@ -82,6 +82,9 @@ namespace llarp
return huint32_t{0};
}
virtual void
ResetInternalState() override;
/// router's logic
/// use when sending any data on a path
Logic*

View File

@ -47,6 +47,9 @@ namespace llarp
llarp_time_t
GetNewestIntroExpiration() const;
bool
GetNewestIntro(Introduction& intro) const;
bool
HasExpiredIntros(llarp_time_t now) const;

View File

@ -38,7 +38,7 @@ namespace llarp
/// determine if this request has timed out
bool
IsTimedOut(llarp_time_t now, llarp_time_t timeout = 15000) const
IsTimedOut(llarp_time_t now, llarp_time_t timeout = 60000) const
{
if(now <= m_created)
return false;

View File

@ -104,10 +104,9 @@ namespace llarp
{
LogWarn("failed to pick new intro during introset update");
}
if(GetPathByRouter(m_NextIntro.router) == nullptr)
if(GetPathByRouter(m_NextIntro.router) == nullptr
&& !BuildCooldownHit(Now()))
BuildOneAlignedTo(m_NextIntro.router);
else
SwapIntros();
}
else
++m_LookupFails;
@ -134,52 +133,18 @@ namespace llarp
p->SetDropHandler(std::bind(&OutboundContext::HandleDataDrop, this,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3));
}
bool
OutboundContext::BuildOneAlignedTo(const RouterID& remote)
{
LogInfo(Name(), " building path to ", remote);
auto nodedb = m_Endpoint->Router()->nodedb();
std::vector< RouterContact > hops;
hops.resize(numHops);
for(size_t hop = 0; hop < numHops; ++hop)
{
if(hop == 0)
{
if(!SelectHop(nodedb, hops[0], hops[0], 0, path::ePathRoleAny))
return false;
}
else if(hop == numHops - 1)
{
// last hop
if(!nodedb->Get(remote, hops[hop]))
return false;
}
// middle hop
else
{
size_t tries = 5;
do
{
nodedb->select_random_hop_excluding(hops[hop],
{hops[hop - 1].pubkey, remote});
--tries;
} while(m_Endpoint->Router()->routerProfiling().IsBadForPath(
hops[hop].pubkey)
&& tries > 0);
return tries > 0;
}
return false;
}
Build(hops);
return true;
// we now have a path to the next intro, swap intros
if(p->Endpoint() == m_NextIntro.router && remoteIntro != m_NextIntro)
SwapIntros();
}
void
OutboundContext::AsyncGenIntro(const llarp_buffer_t& payload,
ProtocolType t)
{
if(remoteIntro.router.IsZero())
SwapIntros();
auto path = m_PathSet->GetNewestPathByRouter(remoteIntro.router);
if(path == nullptr)
{
@ -187,7 +152,8 @@ namespace llarp
path = m_Endpoint->GetPathByRouter(remoteIntro.router);
if(path == nullptr)
{
BuildOneAlignedTo(remoteIntro.router);
if(!BuildCooldownHit(Now()))
BuildOneAlignedTo(remoteIntro.router);
LogWarn(Name(), " dropping intro frame, no path to ",
remoteIntro.router);
return;
@ -287,16 +253,6 @@ namespace llarp
// shift intro if it expires "soon"
ShiftIntroduction();
}
// swap if we can
if(remoteIntro != m_NextIntro)
{
if(GetPathByRouter(m_NextIntro.router) != nullptr)
{
// we can safely set remoteIntro to the next one
SwapIntros();
LogInfo(Name(), " swapped intro");
}
}
// lookup router in intro if set and unknown
m_Endpoint->EnsureRouterIsKnown(remoteIntro.router);
// expire bad intros
@ -315,15 +271,19 @@ namespace llarp
{
if(!GetNewestPathByRouter(remoteIntro.router))
{
BuildOneAlignedTo(remoteIntro.router);
if(!BuildCooldownHit(now))
BuildOneAlignedTo(remoteIntro.router);
}
else
{
Encrypted< 64 > tmp;
tmp.Randomize();
llarp_buffer_t buf(tmp.data(), tmp.size());
AsyncEncryptAndSendTo(buf, eProtocolControl);
if(currentConvoTag.IsZero())
return false;
return !m_DataHandler->HasConvoTag(currentConvoTag);
}
Encrypted< 64 > tmp;
tmp.Randomize();
llarp_buffer_t buf(tmp.data(), tmp.size());
AsyncEncryptAndSendTo(buf, eProtocolControl);
if(currentConvoTag.IsZero())
return false;
return !m_DataHandler->HasConvoTag(currentConvoTag);
}
}
// if we are dead return true so we are removed
@ -333,28 +293,27 @@ namespace llarp
}
bool
OutboundContext::SelectHop(llarp_nodedb* db, const RouterContact& prev,
OutboundContext::SelectHop(llarp_nodedb* db,
const std::set< RouterID >& prev,
RouterContact& cur, size_t hop,
path::PathRole roles)
{
if(remoteIntro.router.IsZero())
if(m_NextIntro.router.IsZero() || prev.count(m_NextIntro.router))
{
SwapIntros();
if(!ShiftIntroduction(false))
return false;
}
std::set< RouterID > exclude = prev;
exclude.insert(m_NextIntro.router);
if(hop == numHops - 1)
{
m_Endpoint->EnsureRouterIsKnown(remoteIntro.router);
if(db->Get(remoteIntro.router, cur))
m_Endpoint->EnsureRouterIsKnown(m_NextIntro.router);
if(db->Get(m_NextIntro.router, cur))
return true;
++m_BuildFails;
return false;
}
else if(hop == numHops - 2)
{
return db->select_random_hop_excluding(
cur, {prev.pubkey, remoteIntro.router});
}
return path::Builder::SelectHop(db, prev, cur, hop, roles);
return path::Builder::SelectHop(db, exclude, cur, hop, roles);
}
bool
@ -411,13 +370,10 @@ namespace llarp
if(shiftedRouter)
{
lastShift = now;
BuildOneAlignedTo(m_NextIntro.router);
if(!BuildCooldownHit(now))
BuildOneAlignedTo(m_NextIntro.router);
}
else if(shiftedIntro)
{
SwapIntros();
}
else
else if(!shiftedIntro)
{
LogInfo(Name(), " updating introset");
UpdateIntroSet(true);
@ -433,7 +389,7 @@ namespace llarp
if(now - lastShift < MIN_SHIFT_INTERVAL)
return false;
bool shifted = false;
// to find a intro on the same router as before
// to find a intro on the same router as before that is newer
for(const auto& intro : currentIntroSet.I)
{
if(intro.ExpiresSoon(now))
@ -441,10 +397,14 @@ namespace llarp
if(m_BadIntros.find(intro) == m_BadIntros.end()
&& remoteIntro.router == intro.router)
{
m_NextIntro = intro;
return true;
if(intro.expiresAt > m_NextIntro.expiresAt)
{
m_NextIntro = intro;
return true;
}
}
}
/// pick newer intro not on same router
for(const auto& intro : currentIntroSet.I)
{
m_Endpoint->EnsureRouterIsKnown(intro.router);
@ -452,19 +412,21 @@ namespace llarp
continue;
if(m_BadIntros.find(intro) == m_BadIntros.end() && m_NextIntro != intro)
{
shifted = intro.router != m_NextIntro.router
|| (now < intro.expiresAt
&& intro.expiresAt - now
> 10 * 1000); // TODO: hardcoded value
m_NextIntro = intro;
success = true;
break;
shifted = intro.router != m_NextIntro.router;
if(intro.expiresAt > m_NextIntro.expiresAt)
{
m_NextIntro = intro;
success = true;
}
}
}
if(shifted && rebuild)
if(m_NextIntro.router.IsZero())
return false;
if(shifted)
{
lastShift = now;
BuildOneAlignedTo(m_NextIntro.router);
if(rebuild && !BuildCooldownHit(Now()))
BuildOneAlignedTo(m_NextIntro.router);
}
return success;
}
@ -526,9 +488,7 @@ namespace llarp
++num;
});
// build a path if one isn't already pending build or established
if(num == 0)
BuildOneAlignedTo(m_NextIntro.router);
SwapIntros();
BuildOneAlignedTo(m_NextIntro.router);
}
}
}

View File

@ -82,15 +82,12 @@ namespace llarp
void
UpdateIntroSet(bool randomizePath) override;
bool
BuildOneAlignedTo(const RouterID& remote);
void
HandlePathBuilt(path::Path_ptr path) override;
bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop, path::PathRole roles) override;
SelectHop(llarp_nodedb* db, const std::set< RouterID >& prev,
RouterContact& cur, size_t hop, path::PathRole roles) override;
bool
HandleHiddenServiceFrame(path::Path_ptr p, const ProtocolFrame& frame);

View File

@ -0,0 +1,22 @@
#ifndef LLARP_UTIL_COMPARE_PTR_HPP
#define LLARP_UTIL_COMPARE_PTR_HPP
#include <functional>
namespace llarp
{
/// type for comparing smart pointer's managed values
template < typename Ptr_t, typename Compare = std::less<> >
struct ComparePtr
{
bool
operator()(const Ptr_t& left, const Ptr_t& right) const
{
if(left && right)
return Compare()(*left, *right);
else
return Compare()(left, right);
}
};
} // namespace llarp
#endif

View File

@ -32,15 +32,15 @@ namespace llarp
if(!sock)
return;
ssize_t expect = 0;
std::vector< utp_iovec > vecs;
std::vector< utp_iovec > send;
for(const auto& vec : vecq)
{
expect += vec.iov_len;
vecs.push_back(vec);
send.emplace_back(vec);
}
if(expect)
{
ssize_t s = utp_writev(sock, vecs.data(), vecs.size());
ssize_t s = utp_writev(sock, send.data(), send.size());
if(s < 0)
return;
if(s > 0)
@ -189,7 +189,7 @@ namespace llarp
bool
Session::TimedOut(llarp_time_t now) const
{
if(state == eInitial)
if(state == eInitial || state == eLinkEstablished)
return false;
if(sendq.size() >= MaxSendQueueSize)
{
@ -254,7 +254,16 @@ namespace llarp
Session::SendMessageBuffer(const llarp_buffer_t& buf)
{
if(sendq.size() >= MaxSendQueueSize)
{
// pump write queue if we seem to be full
PumpWrite();
}
if(sendq.size() >= MaxSendQueueSize)
{
// we didn't pump anything wtf
// this means we're stalled
return false;
}
size_t sz = buf.sz;
byte_t* ptr = buf.base;
uint32_t msgid = m_NextTXMsgID++;
@ -270,7 +279,6 @@ namespace llarp
ptr += s;
sz -= s;
}
PumpWrite();
return true;
}

View File

@ -120,9 +120,9 @@ namespace llarp
SendKeepAlive() override;
bool
IsEstablished() override
IsEstablished() const override
{
return state == eSessionReady || state == eLinkEstablished;
return state == eSessionReady;
}
bool