2021-03-09 22:24:35 +00:00
|
|
|
#include "sendcontext.hpp"
|
2019-04-19 16:02:32 +00:00
|
|
|
|
2021-03-09 22:24:35 +00:00
|
|
|
#include <llarp/router/abstractrouter.hpp>
|
|
|
|
#include <llarp/routing/path_transfer_message.hpp>
|
|
|
|
#include "endpoint.hpp"
|
2019-07-30 23:42:13 +00:00
|
|
|
#include <utility>
|
2019-09-19 14:41:31 +00:00
|
|
|
#include <unordered_set>
|
2022-07-28 16:07:38 +00:00
|
|
|
#include <llarp/crypto/crypto.hpp>
|
2019-04-19 16:02:32 +00:00
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
{
|
|
|
|
namespace service
|
|
|
|
{
|
2020-01-06 21:08:31 +00:00
|
|
|
static constexpr size_t SendContextQueueSize = 512;
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
SendContext::SendContext(
|
|
|
|
ServiceInfo ident, const Introduction& intro, path::PathSet* send, Endpoint* ep)
|
2019-07-30 23:42:13 +00:00
|
|
|
: remoteIdent(std::move(ident))
|
2019-04-19 16:02:32 +00:00
|
|
|
, remoteIntro(intro)
|
|
|
|
, m_PathSet(send)
|
|
|
|
, m_DataHandler(ep)
|
|
|
|
, m_Endpoint(ep)
|
2020-02-24 19:40:45 +00:00
|
|
|
, createdAt(ep->Now())
|
2020-01-06 21:08:31 +00:00
|
|
|
, m_SendQueue(SendContextQueueSize)
|
2021-11-15 14:20:57 +00:00
|
|
|
{}
|
2019-04-19 16:02:32 +00:00
|
|
|
|
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
SendContext::Send(std::shared_ptr<ProtocolFrame> msg, path::Path_ptr path)
|
2019-04-19 16:02:32 +00:00
|
|
|
{
|
2021-11-15 14:20:57 +00:00
|
|
|
if (path->IsReady()
|
|
|
|
and m_SendQueue.tryPushBack(std::make_pair(
|
|
|
|
std::make_shared<routing::PathTransferMessage>(*msg, remoteIntro.pathID), path))
|
|
|
|
== thread::QueueReturn::Success)
|
|
|
|
{
|
|
|
|
m_Endpoint->Router()->TriggerPump();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2019-04-25 17:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-30 15:09:42 +00:00
|
|
|
SendContext::FlushUpstream()
|
2019-04-25 17:15:56 +00:00
|
|
|
{
|
|
|
|
auto r = m_Endpoint->Router();
|
2020-04-07 18:38:56 +00:00
|
|
|
std::unordered_set<path::Path_ptr, path::Path::Ptr_Hash> flushpaths;
|
2021-03-31 16:06:50 +00:00
|
|
|
auto rttRMS = 0ms;
|
2021-11-15 14:20:57 +00:00
|
|
|
while (auto maybe = m_SendQueue.tryPopFront())
|
2019-04-25 17:15:56 +00:00
|
|
|
{
|
2021-11-15 14:20:57 +00:00
|
|
|
auto& [msg, path] = *maybe;
|
|
|
|
msg->S = path->NextSeqNo();
|
|
|
|
if (path->SendRoutingMessage(*msg, r))
|
2019-04-19 16:02:32 +00:00
|
|
|
{
|
2021-11-15 14:20:57 +00:00
|
|
|
lastGoodSend = r->Now();
|
|
|
|
flushpaths.emplace(path);
|
|
|
|
m_Endpoint->ConvoTagTX(msg->T.T);
|
|
|
|
const auto rtt = (path->intro.latency + remoteIntro.latency) * 2;
|
|
|
|
rttRMS += rtt * rtt.count();
|
2021-11-14 15:51:44 +00:00
|
|
|
}
|
2019-09-19 14:41:31 +00:00
|
|
|
}
|
|
|
|
// flush the select path's upstream
|
2020-04-07 18:38:56 +00:00
|
|
|
for (const auto& path : flushpaths)
|
2019-09-19 14:41:31 +00:00
|
|
|
{
|
|
|
|
path->FlushUpstream(r);
|
2019-04-25 17:15:56 +00:00
|
|
|
}
|
2021-03-31 16:06:50 +00:00
|
|
|
if (flushpaths.empty())
|
|
|
|
return;
|
|
|
|
estimatedRTT = std::chrono::milliseconds{
|
|
|
|
static_cast<int64_t>(std::sqrt(rttRMS.count() / flushpaths.size()))};
|
2019-04-19 16:02:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// send on an established convo tag
|
|
|
|
void
|
|
|
|
SendContext::EncryptAndSendTo(const llarp_buffer_t& payload, ProtocolType t)
|
|
|
|
{
|
|
|
|
SharedSecret shared;
|
2020-04-07 18:38:56 +00:00
|
|
|
auto f = std::make_shared<ProtocolFrame>();
|
2020-08-22 17:53:30 +00:00
|
|
|
f->R = 0;
|
2019-09-19 14:41:31 +00:00
|
|
|
f->N.Randomize();
|
|
|
|
f->T = currentConvoTag;
|
|
|
|
f->S = ++sequenceNo;
|
2019-04-19 16:02:32 +00:00
|
|
|
|
2021-03-03 23:42:10 +00:00
|
|
|
auto path = m_PathSet->GetPathByRouter(remoteIntro.router);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (!path)
|
2019-04-19 16:02:32 +00:00
|
|
|
{
|
2021-06-02 19:52:13 +00:00
|
|
|
ShiftIntroRouter(remoteIntro.router);
|
|
|
|
LogWarn(m_PathSet->Name(), " cannot encrypt and send: no path for intro ", remoteIntro);
|
2019-04-19 16:02:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
if (!m_DataHandler->GetCachedSessionKeyFor(f->T, shared))
|
2019-04-19 16:02:32 +00:00
|
|
|
{
|
2021-06-02 19:52:13 +00:00
|
|
|
LogWarn(
|
|
|
|
m_PathSet->Name(), " could not send, has no cached session key on session T=", f->T);
|
2019-04-19 16:02:32 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-05-22 16:20:50 +00:00
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
auto m = std::make_shared<ProtocolMessage>();
|
2019-09-19 14:41:31 +00:00
|
|
|
m_DataHandler->PutIntroFor(f->T, remoteIntro);
|
|
|
|
m_DataHandler->PutReplyIntroFor(f->T, path->intro);
|
2020-04-07 18:38:56 +00:00
|
|
|
m->proto = t;
|
2021-04-02 15:10:37 +00:00
|
|
|
if (auto maybe = m_Endpoint->GetSeqNoForConvo(f->T))
|
|
|
|
{
|
|
|
|
m->seqno = *maybe;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-06-02 19:52:13 +00:00
|
|
|
LogWarn(m_PathSet->Name(), " could not get sequence number for session T=", f->T);
|
2021-04-02 15:10:37 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-09-19 14:41:31 +00:00
|
|
|
m->introReply = path->intro;
|
2020-04-07 18:38:56 +00:00
|
|
|
f->F = m->introReply.pathID;
|
|
|
|
m->sender = m_Endpoint->GetIdentity().pub;
|
|
|
|
m->tag = f->T;
|
2019-09-19 14:41:31 +00:00
|
|
|
m->PutBuffer(payload);
|
2021-03-02 02:06:20 +00:00
|
|
|
m_Endpoint->Router()->QueueWork([f, m, shared, path, this] {
|
|
|
|
if (not f->EncryptAndSign(*m, shared, m_Endpoint->GetIdentity()))
|
2019-09-19 14:41:31 +00:00
|
|
|
{
|
2021-06-02 19:52:13 +00:00
|
|
|
LogError(m_PathSet->Name(), " failed to sign message");
|
2019-09-19 14:41:31 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-03-02 02:06:20 +00:00
|
|
|
Send(f, path);
|
2019-09-19 14:41:31 +00:00
|
|
|
});
|
2019-04-19 16:02:32 +00:00
|
|
|
}
|
|
|
|
|
2021-01-01 18:55:31 +00:00
|
|
|
void
|
|
|
|
SendContext::AsyncSendAuth(std::function<void(AuthResult)> resultHandler)
|
|
|
|
{
|
|
|
|
const auto maybe = m_Endpoint->MaybeGetAuthInfoForEndpoint(remoteIdent.Addr());
|
|
|
|
if (maybe.has_value())
|
|
|
|
{
|
|
|
|
// send auth message
|
2021-02-24 12:14:15 +00:00
|
|
|
const llarp_buffer_t authdata{maybe->token};
|
2021-03-08 20:48:11 +00:00
|
|
|
AsyncGenIntro(authdata, ProtocolType::Auth);
|
2021-01-01 18:55:31 +00:00
|
|
|
authResultListener = resultHandler;
|
|
|
|
}
|
|
|
|
else
|
2021-02-24 12:14:15 +00:00
|
|
|
resultHandler({AuthResultCode::eAuthFailed, "no auth for given endpoint"});
|
2021-01-01 18:55:31 +00:00
|
|
|
}
|
|
|
|
|
2019-04-19 16:02:32 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
SendContext::AsyncEncryptAndSendTo(const llarp_buffer_t& data, ProtocolType protocol)
|
2019-04-19 16:02:32 +00:00
|
|
|
{
|
2021-06-02 19:52:13 +00:00
|
|
|
if (IntroSent())
|
2019-04-19 16:02:32 +00:00
|
|
|
{
|
|
|
|
EncryptAndSendTo(data, protocol);
|
2020-06-24 13:24:07 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-06-02 19:52:13 +00:00
|
|
|
// have we generated the initial intro but not sent it yet? bail here so we don't cause
|
|
|
|
// bullshittery
|
|
|
|
if (IntroGenerated() and not IntroSent())
|
2021-06-03 12:56:35 +00:00
|
|
|
{
|
|
|
|
LogWarn(
|
|
|
|
m_PathSet->Name(),
|
|
|
|
" we have generated an intial handshake but have not sent it yet so we drop a packet "
|
|
|
|
"to prevent bullshittery");
|
2021-06-02 19:52:13 +00:00
|
|
|
return;
|
2021-06-03 12:56:35 +00:00
|
|
|
}
|
2020-06-24 13:24:07 +00:00
|
|
|
const auto maybe = m_Endpoint->MaybeGetAuthInfoForEndpoint(remoteIdent.Addr());
|
|
|
|
if (maybe.has_value())
|
|
|
|
{
|
|
|
|
// send auth message
|
|
|
|
const llarp_buffer_t authdata(maybe->token);
|
2021-03-08 20:48:11 +00:00
|
|
|
AsyncGenIntro(authdata, ProtocolType::Auth);
|
2019-04-19 16:02:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
AsyncGenIntro(data, protocol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace service
|
|
|
|
|
|
|
|
} // namespace llarp
|