lokinet/llarp/service/sendcontext.cpp

173 lines
5.1 KiB
C++
Raw Normal View History

#include "sendcontext.hpp"
2019-04-19 16:02:32 +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>
#include <unordered_set>
#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;
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)
{}
2019-04-19 16:02:32 +00:00
bool
SendContext::Send(std::shared_ptr<ProtocolFrame> msg, path::Path_ptr path)
2019-04-19 16:02:32 +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
SendContext::FlushUpstream()
2019-04-25 17:15:56 +00:00
{
auto r = m_Endpoint->Router();
std::unordered_set<path::Path_ptr, path::Path::Ptr_Hash> flushpaths;
auto rttRMS = 0ms;
while (auto maybe = m_SendQueue.tryPopFront())
2019-04-25 17:15:56 +00:00
{
auto& [msg, path] = *maybe;
msg->S = path->NextSeqNo();
if (path->SendRoutingMessage(*msg, r))
2019-04-19 16:02:32 +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
}
}
// flush the select path's upstream
for (const auto& path : flushpaths)
{
path->FlushUpstream(r);
2019-04-25 17:15:56 +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;
auto f = std::make_shared<ProtocolFrame>();
f->R = 0;
f->N.Randomize();
f->T = currentConvoTag;
f->S = ++sequenceNo;
2019-04-19 16:02:32 +00:00
auto path = m_PathSet->GetPathByRouter(remoteIntro.router);
if (!path)
2019-04-19 16:02:32 +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;
}
if (!m_DataHandler->GetCachedSessionKeyFor(f->T, shared))
2019-04-19 16:02:32 +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
auto m = std::make_shared<ProtocolMessage>();
m_DataHandler->PutIntroFor(f->T, remoteIntro);
m_DataHandler->PutReplyIntroFor(f->T, path->intro);
m->proto = t;
if (auto maybe = m_Endpoint->GetSeqNoForConvo(f->T))
{
m->seqno = *maybe;
}
else
{
LogWarn(m_PathSet->Name(), " could not get sequence number for session T=", f->T);
return;
}
m->introReply = path->intro;
f->F = m->introReply.pathID;
m->sender = m_Endpoint->GetIdentity().pub;
m->tag = f->T;
m->PutBuffer(payload);
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
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()))
{
LogError(m_PathSet->Name(), " failed to sign message");
return;
}
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
2021-03-02 02:06:20 +00:00
Send(f, path);
});
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
SendContext::AsyncEncryptAndSendTo(const llarp_buffer_t& data, ProtocolType protocol)
2019-04-19 16:02:32 +00:00
{
if (IntroSent())
2019-04-19 16:02:32 +00:00
{
EncryptAndSendTo(data, protocol);
return;
}
// 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");
return;
2021-06-03 12:56:35 +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