mirror of https://github.com/oxen-io/lokinet
Adds Link-Relay Status Messages
Success case: - the path endpoint creates and sends a LR_StatusMessage upon successful path creation Failure case: - an intermediate hop creates and sends a LR_StatusMessage upon failure to forward the path to the next hop for any reason Both cases: - transit hops receive LR_StatusMessages and add a frame to them reflecting their "status" with respect to that path - the path creator receives LR_StatusMessages and decrypts/parses the LR_StatusRecord frames from the path hops. If all is good, the Path does as it would when receiving a PathConfirmMessage. If not, the Path marks the new path as failed. LR_StatusMessage is now used/sent in place of PathConfirmMessagepull/732/head
parent
011abde5ec
commit
38fd0552d3
@ -0,0 +1,285 @@
|
||||
#include <messages/relay_status.hpp>
|
||||
|
||||
#include <crypto/crypto.hpp>
|
||||
#include <path/path_context.hpp>
|
||||
#include <path/ihophandler.hpp>
|
||||
#include <router/abstractrouter.hpp>
|
||||
#include <routing/path_confirm_message.hpp>
|
||||
#include <util/bencode.hpp>
|
||||
#include <util/buffer.hpp>
|
||||
#include <util/logger.hpp>
|
||||
#include <util/logic.hpp>
|
||||
#include <util/memfn.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct LRSM_AsyncHandler
|
||||
: public std::enable_shared_from_this< LRSM_AsyncHandler >
|
||||
{
|
||||
using HopHandler_ptr = std::shared_ptr< llarp::path::IHopHandler >;
|
||||
|
||||
std::array< EncryptedFrame, 8 > frames;
|
||||
PathID_t pathid;
|
||||
uint64_t status = 0;
|
||||
HopHandler_ptr path;
|
||||
AbstractRouter* router;
|
||||
|
||||
LRSM_AsyncHandler(const std::array< EncryptedFrame, 8 >& _frames,
|
||||
const PathID_t& _pathid, uint64_t _status,
|
||||
HopHandler_ptr _path, AbstractRouter* _router)
|
||||
: frames(_frames)
|
||||
, pathid(_pathid)
|
||||
, status(_status)
|
||||
, path(_path)
|
||||
, router(_router)
|
||||
{
|
||||
}
|
||||
|
||||
~LRSM_AsyncHandler() = default;
|
||||
|
||||
void
|
||||
handle()
|
||||
{
|
||||
path->HandleLRSM(status, frames, router);
|
||||
}
|
||||
|
||||
void
|
||||
queue_handle()
|
||||
{
|
||||
auto func =
|
||||
std::bind(&llarp::LRSM_AsyncHandler::handle, shared_from_this());
|
||||
router->threadpool()->addJob(func);
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
LR_StatusMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
|
||||
{
|
||||
bool read = false;
|
||||
if(key == "c")
|
||||
{
|
||||
return BEncodeReadArray(frames, buf);
|
||||
}
|
||||
else if(key == "p")
|
||||
{
|
||||
if(!BEncodeMaybeReadDictEntry("p", pathid, read, key, buf))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(key == "s")
|
||||
{
|
||||
if(!BEncodeMaybeReadDictInt("s", status, read, key, buf))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(key == "v")
|
||||
{
|
||||
if(!BEncodeMaybeReadVersion("v", version, LLARP_PROTO_VERSION, read, key,
|
||||
buf))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
void
|
||||
LR_StatusMessage::Clear()
|
||||
{
|
||||
std::for_each(frames.begin(), frames.end(), [](auto& f) { f.Clear(); });
|
||||
}
|
||||
|
||||
bool
|
||||
LR_StatusMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
// msg type
|
||||
if(!BEncodeWriteDictMsgType(buf, "a", "s"))
|
||||
return false;
|
||||
// frames
|
||||
if(!BEncodeWriteDictArray("c", frames, buf))
|
||||
return false;
|
||||
// path id
|
||||
if(!BEncodeWriteDictEntry("p", pathid, buf))
|
||||
return false;
|
||||
// status (for now, only success bit is relevant)
|
||||
if(!BEncodeWriteDictInt("s", status, buf))
|
||||
return false;
|
||||
// version
|
||||
if(!bencode_write_version_entry(buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
LR_StatusMessage::HandleMessage(AbstractRouter* router) const
|
||||
{
|
||||
llarp::LogDebug("Received LR_Status message from (", session->GetPubKey(),
|
||||
")");
|
||||
if(frames.size() != path::max_len)
|
||||
{
|
||||
llarp::LogError("LRSM invalid number of records, ", frames.size(),
|
||||
"!=", path::max_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto path =
|
||||
router->pathContext().GetByUpstream(session->GetPubKey(), pathid);
|
||||
if(!path)
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"unhandled LR_Status message: no associated IHopHandler found");
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint64_t ourStatus = LR_StatusRecord::SUCCESS;
|
||||
auto handler = std::make_shared< LRSM_AsyncHandler >(
|
||||
frames, pathid, ourStatus, path, router);
|
||||
|
||||
handler->queue_handle();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
LR_StatusMessage::SetDummyFrames()
|
||||
{
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
|
||||
// call this from a worker thread
|
||||
bool
|
||||
LR_StatusMessage::CreateAndSend(AbstractRouter* router, const PathID_t pathid,
|
||||
const RouterID nextHop,
|
||||
const SharedSecret pathKey, uint64_t status)
|
||||
{
|
||||
auto message = std::make_shared< LR_StatusMessage >();
|
||||
|
||||
message->status = status & LR_StatusRecord::SUCCESS;
|
||||
message->pathid = pathid;
|
||||
|
||||
message->SetDummyFrames();
|
||||
|
||||
if(!message->AddFrame(pathKey, status))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QueueSendMessage(router, nextHop, message);
|
||||
return true; // can't guarantee delivery here, as far as we know it's fine
|
||||
}
|
||||
|
||||
bool
|
||||
LR_StatusMessage::AddFrame(const SharedSecret& pathKey, uint64_t status)
|
||||
{
|
||||
frames[7] = frames[6];
|
||||
frames[6] = frames[5];
|
||||
frames[5] = frames[4];
|
||||
frames[4] = frames[3];
|
||||
frames[3] = frames[2];
|
||||
frames[2] = frames[1];
|
||||
frames[1] = frames[0];
|
||||
|
||||
auto& frame = frames[0];
|
||||
|
||||
frame.Randomize();
|
||||
|
||||
LR_StatusRecord record;
|
||||
|
||||
record.status = status;
|
||||
record.version = LLARP_PROTO_VERSION;
|
||||
|
||||
llarp_buffer_t buf(frame.data(), frame.size());
|
||||
buf.cur = buf.base + EncryptedFrameOverheadSize;
|
||||
// encode record
|
||||
if(!record.BEncode(&buf))
|
||||
{
|
||||
// failed to encode?
|
||||
LogError(Name(), " Failed to generate Status Record");
|
||||
DumpBuffer(buf);
|
||||
return false;
|
||||
}
|
||||
// use ephemeral keypair for frame
|
||||
if(!frame.DoEncrypt(pathKey, true))
|
||||
{
|
||||
LogError(Name(), " Failed to encrypt LRSR");
|
||||
DumpBuffer(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
LR_StatusMessage::QueueSendMessage(AbstractRouter* router,
|
||||
const RouterID nextHop,
|
||||
std::shared_ptr< LR_StatusMessage > msg)
|
||||
{
|
||||
auto func = std::bind(&LR_StatusMessage::SendMessage, router, nextHop, msg);
|
||||
router->pathContext().logic()->queue_func(func);
|
||||
}
|
||||
|
||||
void
|
||||
LR_StatusMessage::SendMessage(AbstractRouter* router, const RouterID nextHop,
|
||||
std::shared_ptr< LR_StatusMessage > msg)
|
||||
{
|
||||
llarp::LogDebug("Attempting to send LR_Status message to (", nextHop, ")");
|
||||
if(not router->HasSessionTo(nextHop))
|
||||
{
|
||||
llarp::LogError(
|
||||
"Sending LR_Status message, but no connection to previous hop (",
|
||||
nextHop, ")");
|
||||
return;
|
||||
}
|
||||
if(not router->SendToOrQueue(nextHop, msg.get()))
|
||||
{
|
||||
llarp::LogError("Sending LR_Status message, SendToOrQueue to ", nextHop,
|
||||
" failed");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LR_StatusRecord::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
return bencode_start_dict(buf) && BEncodeWriteDictInt("s", status, buf)
|
||||
&& bencode_write_version_entry(buf) && bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
LR_StatusRecord::OnKey(llarp_buffer_t* buffer, llarp_buffer_t* key)
|
||||
{
|
||||
if(!key)
|
||||
return true;
|
||||
|
||||
bool read = false;
|
||||
|
||||
if(!BEncodeMaybeReadDictInt("s", status, read, *key, buffer))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadVersion("v", version, LLARP_PROTO_VERSION, read, *key,
|
||||
buffer))
|
||||
return false;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
LR_StatusRecord::BDecode(llarp_buffer_t* buf)
|
||||
{
|
||||
return bencode_read_dict(util::memFn(&LR_StatusRecord::OnKey, this), buf);
|
||||
}
|
||||
|
||||
bool
|
||||
LR_StatusRecord::operator==(const LR_StatusRecord& other) const
|
||||
{
|
||||
return status == other.status;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
@ -0,0 +1,107 @@
|
||||
#ifndef LLARP_RELAY_STATUS_HPP
|
||||
#define LLARP_RELAY_STATUS_HPP
|
||||
|
||||
#include <crypto/encrypted_frame.hpp>
|
||||
#include <crypto/types.hpp>
|
||||
#include <messages/link_message.hpp>
|
||||
#include <path/path_types.hpp>
|
||||
#include <pow.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
// forward declare
|
||||
struct AbstractRouter;
|
||||
namespace path
|
||||
{
|
||||
struct PathContext;
|
||||
struct IHopHandler;
|
||||
} // namespace path
|
||||
|
||||
struct LR_StatusRecord
|
||||
{
|
||||
static constexpr uint64_t SUCCESS = 1;
|
||||
static constexpr uint64_t FAIL_TIMEOUT = 1 << 1;
|
||||
static constexpr uint64_t FAIL_CONGESTION = 1 << 2;
|
||||
static constexpr uint64_t FAIL_DEST_UNKNOWN = 1 << 3;
|
||||
static constexpr uint64_t FAIL_DECRYPT_ERROR = 1 << 4;
|
||||
static constexpr uint64_t FAIL_MALFORMED_RECORD = 1 << 5;
|
||||
static constexpr uint64_t FAIL_DEST_INVALID = 1 << 6;
|
||||
static constexpr uint64_t FAIL_CANNOT_CONNECT = 1 << 7;
|
||||
|
||||
uint64_t status = 0;
|
||||
uint64_t version = 0;
|
||||
|
||||
bool
|
||||
BDecode(llarp_buffer_t *buf);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t *buf) const;
|
||||
|
||||
bool
|
||||
operator==(const LR_StatusRecord &other) const;
|
||||
|
||||
private:
|
||||
bool
|
||||
OnKey(llarp_buffer_t *buffer, llarp_buffer_t *key);
|
||||
};
|
||||
|
||||
struct LR_StatusMessage : public ILinkMessage
|
||||
{
|
||||
std::array< EncryptedFrame, 8 > frames;
|
||||
|
||||
PathID_t pathid;
|
||||
|
||||
uint64_t status = 0;
|
||||
|
||||
LR_StatusMessage(const std::array< EncryptedFrame, 8 > &_frames)
|
||||
: ILinkMessage(), frames(_frames)
|
||||
{
|
||||
}
|
||||
|
||||
LR_StatusMessage() = default;
|
||||
|
||||
~LR_StatusMessage() = default;
|
||||
|
||||
void
|
||||
Clear() override;
|
||||
|
||||
bool
|
||||
DecodeKey(const llarp_buffer_t &key, llarp_buffer_t *buf) override;
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t *buf) const override;
|
||||
|
||||
bool
|
||||
HandleMessage(AbstractRouter *router) const override;
|
||||
|
||||
void
|
||||
SetDummyFrames();
|
||||
|
||||
static bool
|
||||
CreateAndSend(AbstractRouter *router, const PathID_t pathid,
|
||||
const RouterID nextHop, const SharedSecret pathKey,
|
||||
uint64_t status);
|
||||
|
||||
bool
|
||||
AddFrame(const SharedSecret &pathKey, uint64_t status);
|
||||
|
||||
static void
|
||||
QueueSendMessage(AbstractRouter *router, const RouterID nextHop,
|
||||
std::shared_ptr< LR_StatusMessage > msg);
|
||||
|
||||
static void
|
||||
SendMessage(AbstractRouter *router, const RouterID nextHop,
|
||||
std::shared_ptr< LR_StatusMessage > msg);
|
||||
|
||||
const char *
|
||||
Name() const override
|
||||
{
|
||||
return "RelayStatus";
|
||||
}
|
||||
};
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue