mirror of https://github.com/oxen-io/lokinet
Merge branch 'hidden-service-dht' of https://github.com/majestrate/llarp
commit
e1a4c2f32c
@ -1,408 +1,5 @@
|
||||
#ifndef LLARP_DHT_HPP_
|
||||
#define LLARP_DHT_HPP_
|
||||
#include <llarp/buffer.h>
|
||||
#include <llarp/dht.h>
|
||||
#include <llarp/router.h>
|
||||
#include <llarp/router_contact.h>
|
||||
#include <llarp/time.h>
|
||||
#include <llarp/aligned.hpp>
|
||||
#include <llarp/path_types.hpp>
|
||||
#include <llarp/service.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
const size_t MAX_MSG_SIZE = 2048;
|
||||
|
||||
struct Key_t : public llarp::AlignedBuffer< 32 >
|
||||
{
|
||||
Key_t(const byte_t* val) : llarp::AlignedBuffer< 32 >(val)
|
||||
{
|
||||
}
|
||||
|
||||
Key_t() : llarp::AlignedBuffer< 32 >()
|
||||
{
|
||||
}
|
||||
|
||||
Key_t
|
||||
operator^(const Key_t& other) const
|
||||
{
|
||||
Key_t dist;
|
||||
for(size_t idx = 0; idx < 4; ++idx)
|
||||
dist.l[idx] = l[idx] ^ other.l[idx];
|
||||
return dist;
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const Key_t& other) const
|
||||
{
|
||||
return memcmp(data_l(), other.data_l(), 32) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct RCNode
|
||||
{
|
||||
llarp_rc* rc;
|
||||
|
||||
Key_t ID;
|
||||
|
||||
RCNode() : rc(nullptr)
|
||||
{
|
||||
ID.Zero();
|
||||
}
|
||||
|
||||
RCNode(llarp_rc* other) : rc(other)
|
||||
{
|
||||
ID = other->pubkey;
|
||||
}
|
||||
};
|
||||
|
||||
struct ISNode
|
||||
{
|
||||
llarp::service::IntroSet* introset;
|
||||
|
||||
Key_t ID;
|
||||
|
||||
ISNode() : introset(nullptr)
|
||||
{
|
||||
ID.Zero();
|
||||
}
|
||||
|
||||
ISNode(llarp::service::IntroSet* other) : introset(other)
|
||||
{
|
||||
other->A.CalculateAddress(ID);
|
||||
}
|
||||
};
|
||||
|
||||
struct SearchJob
|
||||
{
|
||||
const static uint64_t JobTimeout = 30000;
|
||||
|
||||
SearchJob();
|
||||
|
||||
SearchJob(const Key_t& requester, uint64_t requesterTX,
|
||||
const Key_t& target, llarp_router_lookup_job* job,
|
||||
const std::set< Key_t >& excludes);
|
||||
|
||||
void
|
||||
Completed(const llarp_rc* router, bool timeout = false) const;
|
||||
|
||||
bool
|
||||
IsExpired(llarp_time_t now) const;
|
||||
|
||||
llarp_router_lookup_job* job = nullptr;
|
||||
llarp_time_t started;
|
||||
Key_t requester;
|
||||
uint64_t requesterTX;
|
||||
Key_t target;
|
||||
std::set< Key_t > exclude;
|
||||
};
|
||||
|
||||
struct XorMetric
|
||||
{
|
||||
const Key_t& us;
|
||||
|
||||
XorMetric(const Key_t& ourKey) : us(ourKey){};
|
||||
|
||||
bool
|
||||
operator()(const Key_t& left, const Key_t& right) const
|
||||
{
|
||||
return (us ^ left) < (us ^ right);
|
||||
};
|
||||
};
|
||||
|
||||
struct IMessage
|
||||
{
|
||||
virtual ~IMessage(){};
|
||||
|
||||
/// construct
|
||||
IMessage(const Key_t& from) : From(from)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool
|
||||
BEncode(llarp_buffer_t* buf) const = 0;
|
||||
|
||||
virtual bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val) = 0;
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* dht,
|
||||
std::vector< IMessage* >& replies) const = 0;
|
||||
|
||||
Key_t From;
|
||||
PathID_t pathID;
|
||||
};
|
||||
|
||||
IMessage*
|
||||
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed = false);
|
||||
|
||||
bool
|
||||
DecodeMesssageList(const Key_t& from, llarp_buffer_t* buf,
|
||||
std::vector< IMessage* >& dst, bool relayed = false);
|
||||
|
||||
template < typename Val_t >
|
||||
struct Bucket
|
||||
{
|
||||
typedef std::map< Key_t, Val_t, XorMetric > BucketStorage_t;
|
||||
|
||||
Bucket(const Key_t& us) : nodes(XorMetric(us)){};
|
||||
|
||||
bool
|
||||
FindClosest(const Key_t& target, Key_t& result) const
|
||||
{
|
||||
Key_t mindist;
|
||||
mindist.Fill(0xff);
|
||||
for(const auto& item : nodes)
|
||||
{
|
||||
auto curDist = item.first ^ target;
|
||||
if(curDist < mindist)
|
||||
{
|
||||
mindist = curDist;
|
||||
result = item.first;
|
||||
}
|
||||
}
|
||||
return nodes.size() > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
FindCloseExcluding(const Key_t& target, Key_t& result,
|
||||
const std::set< Key_t >& exclude) const
|
||||
{
|
||||
Key_t maxdist;
|
||||
maxdist.Fill(0xff);
|
||||
Key_t mindist;
|
||||
mindist.Fill(0xff);
|
||||
for(const auto& item : nodes)
|
||||
{
|
||||
if(exclude.find(item.first) != exclude.end())
|
||||
continue;
|
||||
auto curDist = item.first ^ target;
|
||||
if(curDist < mindist)
|
||||
{
|
||||
mindist = curDist;
|
||||
result = item.first;
|
||||
}
|
||||
}
|
||||
return mindist < maxdist;
|
||||
}
|
||||
|
||||
void
|
||||
PutNode(const Val_t& val)
|
||||
{
|
||||
nodes[val.ID] = val;
|
||||
}
|
||||
|
||||
void
|
||||
DelNode(const Key_t& key)
|
||||
{
|
||||
auto itr = nodes.find(key);
|
||||
if(itr != nodes.end())
|
||||
nodes.erase(itr);
|
||||
}
|
||||
|
||||
BucketStorage_t nodes;
|
||||
};
|
||||
|
||||
struct Context
|
||||
{
|
||||
Context();
|
||||
~Context();
|
||||
|
||||
llarp_dht_msg_handler custom_handler = nullptr;
|
||||
|
||||
SearchJob*
|
||||
FindPendingTX(const Key_t& owner, uint64_t txid);
|
||||
|
||||
void
|
||||
RemovePendingLookup(const Key_t& owner, uint64_t txid);
|
||||
|
||||
void
|
||||
LookupRouter(const Key_t& target, const Key_t& whoasked,
|
||||
uint64_t whoaskedTX, const Key_t& askpeer,
|
||||
llarp_router_lookup_job* job = nullptr,
|
||||
bool iterative = false, std::set< Key_t > excludes = {});
|
||||
|
||||
void
|
||||
LookupRouterViaJob(llarp_router_lookup_job* job);
|
||||
|
||||
void
|
||||
LookupRouterRelayed(const Key_t& requester, uint64_t txid,
|
||||
const Key_t& target, bool recursive,
|
||||
std::vector< IMessage* >& replies);
|
||||
|
||||
bool
|
||||
RelayRequestForPath(const llarp::PathID_t& localPath,
|
||||
const IMessage* msg);
|
||||
|
||||
void
|
||||
Init(const Key_t& us, llarp_router* router);
|
||||
|
||||
void
|
||||
QueueRouterLookup(llarp_router_lookup_job* job);
|
||||
|
||||
static void
|
||||
handle_cleaner_timer(void* user, uint64_t orig, uint64_t left);
|
||||
|
||||
static void
|
||||
queue_router_lookup(void* user);
|
||||
|
||||
llarp_router* router = nullptr;
|
||||
// for router contacts
|
||||
Bucket< RCNode >* nodes = nullptr;
|
||||
|
||||
// for introduction sets
|
||||
Bucket< ISNode >* services = nullptr;
|
||||
bool allowTransit = false;
|
||||
|
||||
const Key_t&
|
||||
OurKey() const
|
||||
{
|
||||
return ourKey;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
ScheduleCleanupTimer();
|
||||
|
||||
void
|
||||
CleanupTX();
|
||||
|
||||
uint64_t ids;
|
||||
|
||||
struct TXOwner
|
||||
{
|
||||
Key_t node;
|
||||
uint64_t txid = 0;
|
||||
|
||||
bool
|
||||
operator==(const TXOwner& other) const
|
||||
{
|
||||
return txid == other.txid && node == other.node;
|
||||
}
|
||||
bool
|
||||
operator<(const TXOwner& other) const
|
||||
{
|
||||
return txid < other.txid || node < other.node;
|
||||
}
|
||||
};
|
||||
|
||||
struct TXOwnerHash
|
||||
{
|
||||
std::size_t
|
||||
operator()(TXOwner const& o) const noexcept
|
||||
{
|
||||
std::size_t sz2;
|
||||
memcpy(&sz2, &o.node[0], sizeof(std::size_t));
|
||||
return o.txid ^ (sz2 << 1);
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map< TXOwner, SearchJob, TXOwnerHash > pendingTX;
|
||||
Key_t ourKey;
|
||||
};
|
||||
|
||||
struct PublishIntroMessage : public IMessage
|
||||
{
|
||||
llarp::service::IntroSet I;
|
||||
uint64_t R;
|
||||
uint64_t S;
|
||||
bool hasS = false;
|
||||
uint64_t V;
|
||||
PublishIntroMessage() : IMessage({})
|
||||
{
|
||||
}
|
||||
|
||||
~PublishIntroMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
};
|
||||
|
||||
struct GotRouterMessage : public IMessage
|
||||
{
|
||||
GotRouterMessage(const Key_t& from) : IMessage(from)
|
||||
{
|
||||
}
|
||||
GotRouterMessage(const Key_t& from, uint64_t id, const llarp_rc* result)
|
||||
: IMessage(from), txid(id)
|
||||
{
|
||||
if(result)
|
||||
{
|
||||
R.emplace_back();
|
||||
llarp_rc_clear(&R.back());
|
||||
llarp_rc_copy(&R.back(), result);
|
||||
}
|
||||
}
|
||||
|
||||
~GotRouterMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
|
||||
std::vector< llarp_rc > R;
|
||||
uint64_t txid = 0;
|
||||
uint64_t version = 0;
|
||||
};
|
||||
|
||||
struct FindRouterMessage : public IMessage
|
||||
{
|
||||
FindRouterMessage(const Key_t& from) : IMessage(from)
|
||||
{
|
||||
}
|
||||
|
||||
FindRouterMessage(const Key_t& from, const Key_t& target, uint64_t id)
|
||||
: IMessage(from), K(target), txid(id)
|
||||
{
|
||||
}
|
||||
|
||||
~FindRouterMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
|
||||
Key_t K;
|
||||
bool iterative = false;
|
||||
uint64_t txid = 0;
|
||||
uint64_t version = 0;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
||||
struct llarp_dht_context
|
||||
{
|
||||
llarp::dht::Context impl;
|
||||
llarp_router* parent;
|
||||
llarp_dht_context(llarp_router* router);
|
||||
};
|
||||
|
||||
#endif
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include <llarp/dht/key.hpp>
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/dht/messages/all.hpp>
|
||||
#include <llarp/dht/node.hpp>
|
@ -0,0 +1,77 @@
|
||||
#ifndef LLARP_DHT_BUCKET_HPP
|
||||
#define LLARP_DHT_BUCKET_HPP
|
||||
|
||||
#include <llarp/dht/kademlia.hpp>
|
||||
#include <llarp/dht/key.hpp>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
template < typename Val_t >
|
||||
struct Bucket
|
||||
{
|
||||
typedef std::map< Key_t, Val_t, XorMetric > BucketStorage_t;
|
||||
|
||||
Bucket(const Key_t& us) : nodes(XorMetric(us)){};
|
||||
|
||||
bool
|
||||
FindClosest(const Key_t& target, Key_t& result) const
|
||||
{
|
||||
Key_t mindist;
|
||||
mindist.Fill(0xff);
|
||||
for(const auto& item : nodes)
|
||||
{
|
||||
auto curDist = item.first ^ target;
|
||||
if(curDist < mindist)
|
||||
{
|
||||
mindist = curDist;
|
||||
result = item.first;
|
||||
}
|
||||
}
|
||||
return nodes.size() > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
FindCloseExcluding(const Key_t& target, Key_t& result,
|
||||
const std::set< Key_t >& exclude) const
|
||||
{
|
||||
Key_t maxdist;
|
||||
maxdist.Fill(0xff);
|
||||
Key_t mindist;
|
||||
mindist.Fill(0xff);
|
||||
for(const auto& item : nodes)
|
||||
{
|
||||
if(exclude.find(item.first) != exclude.end())
|
||||
continue;
|
||||
auto curDist = item.first ^ target;
|
||||
if(curDist < mindist)
|
||||
{
|
||||
mindist = curDist;
|
||||
result = item.first;
|
||||
}
|
||||
}
|
||||
return mindist < maxdist;
|
||||
}
|
||||
|
||||
void
|
||||
PutNode(const Val_t& val)
|
||||
{
|
||||
nodes[val.ID] = val;
|
||||
}
|
||||
|
||||
void
|
||||
DelNode(const Key_t& key)
|
||||
{
|
||||
auto itr = nodes.find(key);
|
||||
if(itr != nodes.end())
|
||||
nodes.erase(itr);
|
||||
}
|
||||
|
||||
BucketStorage_t nodes;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,130 @@
|
||||
#ifndef LLARP_DHT_CONTEXT_HPP
|
||||
#define LLARP_DHT_CONTEXT_HPP
|
||||
|
||||
#include <llarp/dht.h>
|
||||
#include <llarp/router.h>
|
||||
#include <llarp/dht/bucket.hpp>
|
||||
#include <llarp/dht/key.hpp>
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/dht/node.hpp>
|
||||
#include <llarp/dht/search_job.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct Context
|
||||
{
|
||||
Context();
|
||||
~Context();
|
||||
|
||||
SearchJob*
|
||||
FindPendingTX(const Key_t& owner, uint64_t txid);
|
||||
|
||||
void
|
||||
RemovePendingLookup(const Key_t& owner, uint64_t txid);
|
||||
|
||||
void
|
||||
LookupServiceDirect(const Key_t& target, const Key_t& whoasked,
|
||||
uint64_t whoaskedTX, const Key_t& askpeer,
|
||||
SearchJob::IntroSetHookFunc handler,
|
||||
bool iterateive = false,
|
||||
std::set< Key_t > excludes = {});
|
||||
|
||||
void
|
||||
LookupRouter(const Key_t& target, const Key_t& whoasked,
|
||||
uint64_t whoaskedTX, const Key_t& askpeer,
|
||||
llarp_router_lookup_job* job = nullptr,
|
||||
bool iterative = false, std::set< Key_t > excludes = {});
|
||||
|
||||
void
|
||||
LookupRouterViaJob(llarp_router_lookup_job* job);
|
||||
|
||||
void
|
||||
LookupRouterRelayed(const Key_t& requester, uint64_t txid,
|
||||
const Key_t& target, bool recursive,
|
||||
std::vector< IMessage* >& replies);
|
||||
|
||||
bool
|
||||
RelayRequestForPath(const llarp::PathID_t& localPath,
|
||||
const IMessage* msg);
|
||||
|
||||
void
|
||||
Init(const Key_t& us, llarp_router* router);
|
||||
|
||||
void
|
||||
QueueRouterLookup(llarp_router_lookup_job* job);
|
||||
|
||||
static void
|
||||
handle_cleaner_timer(void* user, uint64_t orig, uint64_t left);
|
||||
|
||||
static void
|
||||
queue_router_lookup(void* user);
|
||||
|
||||
llarp_router* router = nullptr;
|
||||
// for router contacts
|
||||
Bucket< RCNode >* nodes = nullptr;
|
||||
|
||||
// for introduction sets
|
||||
Bucket< ISNode >* services = nullptr;
|
||||
bool allowTransit = false;
|
||||
|
||||
const Key_t&
|
||||
OurKey() const
|
||||
{
|
||||
return ourKey;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
ScheduleCleanupTimer();
|
||||
|
||||
void
|
||||
CleanupTX();
|
||||
|
||||
uint64_t ids;
|
||||
|
||||
struct TXOwner
|
||||
{
|
||||
Key_t node;
|
||||
uint64_t txid = 0;
|
||||
|
||||
bool
|
||||
operator==(const TXOwner& other) const
|
||||
{
|
||||
return txid == other.txid && node == other.node;
|
||||
}
|
||||
bool
|
||||
operator<(const TXOwner& other) const
|
||||
{
|
||||
return txid < other.txid || node < other.node;
|
||||
}
|
||||
};
|
||||
|
||||
struct TXOwnerHash
|
||||
{
|
||||
std::size_t
|
||||
operator()(TXOwner const& o) const noexcept
|
||||
{
|
||||
std::size_t sz2;
|
||||
memcpy(&sz2, &o.node[0], sizeof(std::size_t));
|
||||
return o.txid ^ (sz2 << 1);
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map< TXOwner, SearchJob, TXOwnerHash > pendingTX;
|
||||
Key_t ourKey;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
||||
struct llarp_dht_context
|
||||
{
|
||||
llarp::dht::Context impl;
|
||||
llarp_router* parent;
|
||||
llarp_dht_context(llarp_router* router);
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,24 @@
|
||||
#ifndef LLARP_DHT_KADEMLIA_HPP
|
||||
#define LLARP_DHT_KADEMLIA_HPP
|
||||
|
||||
#include <llarp/dht/key.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct XorMetric
|
||||
{
|
||||
const Key_t& us;
|
||||
|
||||
XorMetric(const Key_t& ourKey) : us(ourKey){};
|
||||
|
||||
bool
|
||||
operator()(const Key_t& left, const Key_t& right) const
|
||||
{
|
||||
return (us ^ left) < (us ^ right);
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,37 @@
|
||||
#ifndef LLARP_DHT_KEY_HPP
|
||||
#define LLARP_DHT_KEY_HPP
|
||||
#include <llarp/aligned.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct Key_t : public llarp::AlignedBuffer< 32 >
|
||||
{
|
||||
Key_t(const byte_t* val) : llarp::AlignedBuffer< 32 >(val)
|
||||
{
|
||||
}
|
||||
|
||||
Key_t() : llarp::AlignedBuffer< 32 >()
|
||||
{
|
||||
}
|
||||
|
||||
Key_t
|
||||
operator^(const Key_t& other) const
|
||||
{
|
||||
Key_t dist;
|
||||
for(size_t idx = 0; idx < 4; ++idx)
|
||||
dist.l[idx] = l[idx] ^ other.l[idx];
|
||||
return dist;
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const Key_t& other) const
|
||||
{
|
||||
return memcmp(data_l(), other.data_l(), 32) < 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,41 @@
|
||||
#ifndef LLARP_DHT_MESSAGE_HPP
|
||||
#define LLARP_DHT_MESSAGE_HPP
|
||||
#include <llarp/dht.h>
|
||||
#include <llarp/bencode.hpp>
|
||||
#include <llarp/dht/key.hpp>
|
||||
#include <llarp/path_types.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
constexpr size_t MAX_MSG_SIZE = 2048;
|
||||
|
||||
struct IMessage : public llarp::IBEncodeMessage
|
||||
{
|
||||
virtual ~IMessage(){};
|
||||
|
||||
/// construct
|
||||
IMessage(const Key_t& from) : From(from)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* dht,
|
||||
std::vector< IMessage* >& replies) const = 0;
|
||||
|
||||
Key_t From;
|
||||
PathID_t pathID;
|
||||
};
|
||||
|
||||
IMessage*
|
||||
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed = false);
|
||||
|
||||
bool
|
||||
DecodeMesssageList(const Key_t& from, llarp_buffer_t* buf,
|
||||
std::vector< IMessage* >& dst, bool relayed = false);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,8 @@
|
||||
#ifndef LLARP_DHT_MESSAGES_ALL_HPP
|
||||
#define LLARP_DHT_MESSAGES_ALL_HPP
|
||||
#include <llarp/dht/messages/findintro.hpp>
|
||||
#include <llarp/dht/messages/findrouter.hpp>
|
||||
#include <llarp/dht/messages/gotintro.hpp>
|
||||
#include <llarp/dht/messages/gotrouter.hpp>
|
||||
#include <llarp/dht/messages/pubintro.hpp>
|
||||
#endif
|
@ -0,0 +1,31 @@
|
||||
#ifndef LLARP_DHT_MESSAGES_FIND_INTRO_HPP
|
||||
#define LLARP_DHT_MESSAGES_FIND_INTRO_HPP
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/service/address.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct FindIntroMessage : public IMessage
|
||||
{
|
||||
uint64_t R = 0;
|
||||
bool iterative = false;
|
||||
llarp::service::Address S;
|
||||
uint64_t T = 0;
|
||||
|
||||
~FindIntroMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
#endif
|
@ -0,0 +1,54 @@
|
||||
#ifndef LLARP_DHT_MESSAGES_FIND_ROUTER_HPP
|
||||
#define LLARP_DHT_MESSAGES_FIND_ROUTER_HPP
|
||||
#include <llarp/dht/message.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct FindRouterMessage : public IMessage
|
||||
{
|
||||
FindRouterMessage(const Key_t& from) : IMessage(from)
|
||||
{
|
||||
}
|
||||
|
||||
FindRouterMessage(const Key_t& from, const Key_t& target, uint64_t id)
|
||||
: IMessage(from), K(target), txid(id)
|
||||
{
|
||||
}
|
||||
|
||||
~FindRouterMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
|
||||
Key_t K;
|
||||
bool iterative = false;
|
||||
uint64_t txid = 0;
|
||||
uint64_t version = 0;
|
||||
};
|
||||
|
||||
/// variant of FindRouterMessage relayed via path
|
||||
struct RelayedFindRouterMessage : public FindRouterMessage
|
||||
{
|
||||
RelayedFindRouterMessage(const Key_t& from) : FindRouterMessage(from)
|
||||
{
|
||||
}
|
||||
|
||||
/// handle a relayed FindRouterMessage, do a lookup on the dht and inform
|
||||
/// the path of the result
|
||||
/// TODO: smart path expiration logic needs to be implemented
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,47 @@
|
||||
#ifndef LLARP_DHT_MESSAGES_GOT_INTRO_HPP
|
||||
#define LLARP_DHT_MESSAGES_GOT_INTRO_HPP
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/service/IntroSet.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
/// acknologement to PublishIntroMessage or reply to FinIntroMessage
|
||||
struct GotIntroMessage : public IMessage
|
||||
{
|
||||
std::list< llarp::service::IntroSet > I;
|
||||
uint64_t T = 0;
|
||||
|
||||
GotIntroMessage(const Key_t& from) : IMessage(from)
|
||||
{
|
||||
}
|
||||
|
||||
GotIntroMessage(uint64_t tx, const llarp::service::IntroSet* i = nullptr);
|
||||
|
||||
~GotIntroMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
};
|
||||
|
||||
struct RelayedGotIntroMessage : public GotIntroMessage
|
||||
{
|
||||
RelayedGotIntroMessage() : GotIntroMessage({})
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
#endif
|
@ -0,0 +1,43 @@
|
||||
#ifndef LLARP_DHT_MESSAGES_GOT_ROUTER_HPP
|
||||
#define LLARP_DHT_MESSAGES_GOT_ROUTER_HPP
|
||||
#include <llarp/dht/message.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct GotRouterMessage : public IMessage
|
||||
{
|
||||
GotRouterMessage(const Key_t& from) : IMessage(from)
|
||||
{
|
||||
}
|
||||
GotRouterMessage(const Key_t& from, uint64_t id, const llarp_rc* result)
|
||||
: IMessage(from), txid(id)
|
||||
{
|
||||
if(result)
|
||||
{
|
||||
R.emplace_back();
|
||||
llarp_rc_clear(&R.back());
|
||||
llarp_rc_copy(&R.back(), result);
|
||||
}
|
||||
}
|
||||
|
||||
~GotRouterMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
|
||||
std::vector< llarp_rc > R;
|
||||
uint64_t txid = 0;
|
||||
uint64_t version = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,40 @@
|
||||
#ifndef LLARP_DHT_MESSAGES_PUB_INTRO_HPP
|
||||
#define LLARP_DHT_MESSAGES_PUB_INTRO_HPP
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/service/IntroSet.hpp>
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct PublishIntroMessage : public IMessage
|
||||
{
|
||||
llarp::service::IntroSet I;
|
||||
uint64_t R = 0;
|
||||
uint64_t S = 0;
|
||||
uint64_t txID = 0;
|
||||
bool hasS = false;
|
||||
PublishIntroMessage() : IMessage({})
|
||||
{
|
||||
}
|
||||
|
||||
PublishIntroMessage(const llarp::service::IntroSet& i, uint64_t tx)
|
||||
: IMessage({}), txID(tx)
|
||||
{
|
||||
I = i;
|
||||
}
|
||||
|
||||
~PublishIntroMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context* ctx,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,49 @@
|
||||
#ifndef LLARP_DHT_NODE_HPP
|
||||
#define LLARP_DHT_NODE_HPP
|
||||
|
||||
#include <llarp/router_contact.h>
|
||||
#include <llarp/dht/key.hpp>
|
||||
#include <llarp/service/IntroSet.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct RCNode
|
||||
{
|
||||
llarp_rc* rc;
|
||||
|
||||
Key_t ID;
|
||||
|
||||
RCNode() : rc(nullptr)
|
||||
{
|
||||
ID.Zero();
|
||||
}
|
||||
|
||||
RCNode(llarp_rc* other) : rc(other)
|
||||
{
|
||||
ID = other->pubkey;
|
||||
}
|
||||
};
|
||||
|
||||
struct ISNode
|
||||
{
|
||||
llarp::service::IntroSet introset;
|
||||
|
||||
Key_t ID;
|
||||
|
||||
ISNode()
|
||||
{
|
||||
ID.Zero();
|
||||
}
|
||||
|
||||
ISNode(const llarp::service::IntroSet& other)
|
||||
{
|
||||
introset = other;
|
||||
other.A.CalculateAddress(ID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,53 @@
|
||||
|
||||
#ifndef LLARP_DHT_SEARCH_JOB_HPP
|
||||
#define LLARP_DHT_SEARCH_JOB_HPP
|
||||
#include <llarp/dht.h>
|
||||
#include <llarp/time.h>
|
||||
#include <functional>
|
||||
#include <llarp/dht/key.hpp>
|
||||
#include <llarp/service/IntroSet.hpp>
|
||||
#include <set>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct SearchJob
|
||||
{
|
||||
const static uint64_t JobTimeout = 30000;
|
||||
typedef std::function< void(const llarp::service::IntroSet*) >
|
||||
IntroSetHookFunc;
|
||||
SearchJob();
|
||||
/// for routers
|
||||
SearchJob(const Key_t& requester, uint64_t requesterTX,
|
||||
const Key_t& target, const std::set< Key_t >& excludes,
|
||||
llarp_router_lookup_job* job);
|
||||
/// for introsets
|
||||
SearchJob(const Key_t& requester, uint64_t requesterTX,
|
||||
const Key_t& target, const std::set< Key_t >& excludes,
|
||||
IntroSetHookFunc found);
|
||||
|
||||
void
|
||||
FoundRouter(const llarp_rc* router) const;
|
||||
|
||||
void
|
||||
FoundIntro(const llarp::service::IntroSet* introset) const;
|
||||
|
||||
void
|
||||
Timeout() const;
|
||||
|
||||
bool
|
||||
IsExpired(llarp_time_t now) const;
|
||||
|
||||
// only set if looking up router
|
||||
llarp_router_lookup_job* job = nullptr;
|
||||
IntroSetHookFunc foundIntroHook;
|
||||
llarp_time_t started;
|
||||
Key_t requester;
|
||||
uint64_t requesterTX;
|
||||
Key_t target;
|
||||
std::set< Key_t > exclude;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
#endif
|
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "llarp/address_info.h"
|
||||
|
||||
struct llarp_link;
|
||||
struct llarp_link_session;
|
||||
|
||||
struct llarp_link_establish_job
|
||||
{
|
||||
void *user;
|
||||
void (*result)(struct llarp_link_establish_job *);
|
||||
struct llarp_ai ai;
|
||||
uint64_t timeout;
|
||||
uint16_t retries;
|
||||
|
||||
byte_t pubkey[PUBKEYSIZE];
|
||||
/** set on success by try_establish */
|
||||
struct llarp_link *link;
|
||||
/** set on success by try_establish */
|
||||
struct llarp_link_session *session;
|
||||
};
|
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "llarp/buffer.h"
|
||||
|
||||
enum header_flag
|
||||
{
|
||||
eSessionInvalidated = (1 << 0),
|
||||
eHighPacketDrop = (1 << 1),
|
||||
eHighMTUDetected = (1 << 2),
|
||||
eProtoUpgrade = (1 << 3)
|
||||
};
|
||||
|
||||
struct frame_header
|
||||
{
|
||||
byte_t *ptr;
|
||||
|
||||
frame_header(byte_t *buf);
|
||||
|
||||
byte_t *
|
||||
data();
|
||||
|
||||
uint8_t &
|
||||
version();
|
||||
|
||||
uint8_t &
|
||||
msgtype();
|
||||
|
||||
uint16_t
|
||||
size() const;
|
||||
|
||||
void
|
||||
setsize(uint16_t sz);
|
||||
|
||||
uint8_t &
|
||||
flags();
|
||||
|
||||
void
|
||||
setflag(header_flag f);
|
||||
};
|
@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
#include "codel.hpp"
|
||||
#include "frame_header.hpp"
|
||||
#include "inbound_message.hpp"
|
||||
#include "llarp/logger.hpp"
|
||||
#include "llarp/time.h"
|
||||
#include "llarp/types.h"
|
||||
#include "sendbuf.hpp"
|
||||
#include "transit_message.hpp"
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
|
||||
enum msgtype
|
||||
{
|
||||
eALIV = 0x00,
|
||||
eXMIT = 0x01,
|
||||
eACKS = 0x02,
|
||||
eFRAG = 0x03
|
||||
};
|
||||
|
||||
static inline byte_t *
|
||||
init_sendbuf(sendbuf_t *buf, msgtype t, uint16_t sz, uint8_t flags)
|
||||
{
|
||||
frame_header hdr(buf->data());
|
||||
hdr.version() = 0;
|
||||
hdr.msgtype() = t;
|
||||
hdr.setsize(sz);
|
||||
buf->data()[4] = 0;
|
||||
buf->data()[5] = flags;
|
||||
return hdr.data();
|
||||
}
|
||||
|
||||
struct llarp_router;
|
||||
struct llarp_link_session;
|
||||
|
||||
struct frame_state
|
||||
{
|
||||
byte_t rxflags = 0;
|
||||
byte_t txflags = 0;
|
||||
uint64_t rxids = 0;
|
||||
uint64_t txids = 0;
|
||||
llarp_time_t lastEvent = 0;
|
||||
std::unordered_map< uint64_t, transit_message * > rx;
|
||||
std::unordered_map< uint64_t, transit_message * > tx;
|
||||
|
||||
typedef std::queue< sendbuf_t * > sendqueue_t;
|
||||
typedef llarp::util::CoDelQueue<
|
||||
InboundMessage *, InboundMessage::GetTime, InboundMessage::PutTime,
|
||||
llarp::util::DummyMutex, llarp::util::DummyLock >
|
||||
recvqueue_t;
|
||||
|
||||
llarp_link_session *parent = nullptr;
|
||||
|
||||
sendqueue_t sendqueue;
|
||||
recvqueue_t recvqueue;
|
||||
uint64_t nextMsgID = 0;
|
||||
|
||||
frame_state(llarp_link_session *session)
|
||||
: parent(session), recvqueue("iwp_inbound_message")
|
||||
{
|
||||
}
|
||||
|
||||
/// return true if both sides have the same state flags
|
||||
bool
|
||||
flags_agree(byte_t flags) const;
|
||||
|
||||
bool
|
||||
process_inbound_queue();
|
||||
|
||||
llarp_router *
|
||||
Router();
|
||||
|
||||
void
|
||||
clear();
|
||||
|
||||
bool
|
||||
inbound_frame_complete(uint64_t id);
|
||||
|
||||
void
|
||||
push_ackfor(uint64_t id, uint32_t bitmask);
|
||||
|
||||
bool
|
||||
got_xmit(frame_header hdr, size_t sz);
|
||||
|
||||
void
|
||||
alive();
|
||||
|
||||
bool
|
||||
got_frag(frame_header hdr, size_t sz);
|
||||
|
||||
bool
|
||||
got_acks(frame_header hdr, size_t sz);
|
||||
|
||||
// queue new outbound message
|
||||
void
|
||||
queue_tx(uint64_t id, transit_message *msg);
|
||||
|
||||
void
|
||||
retransmit(llarp_time_t now);
|
||||
|
||||
// get next frame to encrypt and transmit
|
||||
bool
|
||||
next_frame(llarp_buffer_t *buf);
|
||||
|
||||
void
|
||||
pop_next_frame();
|
||||
|
||||
bool
|
||||
process(byte_t *buf, size_t sz);
|
||||
};
|
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "buffer.hpp"
|
||||
#include "llarp/time.h"
|
||||
#include "llarp/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct InboundMessage
|
||||
{
|
||||
uint64_t msgid;
|
||||
std::vector< byte_t > msg;
|
||||
llarp_time_t queued = 0;
|
||||
|
||||
InboundMessage(uint64_t id, const std::vector< byte_t > &m)
|
||||
: msgid(id), msg(m)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
operator>(const InboundMessage &other) const
|
||||
{
|
||||
// order in ascending order for codel queue
|
||||
return msgid > other.msgid;
|
||||
}
|
||||
|
||||
llarp_buffer_t
|
||||
Buffer()
|
||||
{
|
||||
return llarp::Buffer< decltype(msg) >(msg);
|
||||
}
|
||||
|
||||
struct GetTime
|
||||
{
|
||||
llarp_time_t
|
||||
operator()(const InboundMessage *msg)
|
||||
{
|
||||
return msg->queued;
|
||||
}
|
||||
};
|
||||
|
||||
struct OrderCompare
|
||||
{
|
||||
bool
|
||||
operator()(const InboundMessage *left, const InboundMessage *right)
|
||||
{
|
||||
return left->msgid < right->msgid;
|
||||
}
|
||||
};
|
||||
|
||||
struct PutTime
|
||||
{
|
||||
void
|
||||
operator()(InboundMessage *msg)
|
||||
{
|
||||
msg->queued = llarp_time_now_ms();
|
||||
}
|
||||
};
|
||||
};
|
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "llarp/buffer.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
struct sendbuf_t
|
||||
{
|
||||
sendbuf_t(size_t s) : sz(s)
|
||||
{
|
||||
_buf = new byte_t[s];
|
||||
}
|
||||
|
||||
~sendbuf_t()
|
||||
{
|
||||
if(_buf)
|
||||
delete[] _buf;
|
||||
}
|
||||
|
||||
size_t sz;
|
||||
|
||||
size_t
|
||||
size() const
|
||||
{
|
||||
return sz;
|
||||
}
|
||||
|
||||
byte_t *
|
||||
data()
|
||||
{
|
||||
return _buf;
|
||||
}
|
||||
|
||||
private:
|
||||
byte_t *_buf = nullptr;
|
||||
};
|
||||
|
||||
typedef std::queue< sendbuf_t * > sendqueue_t;
|
@ -0,0 +1,480 @@
|
||||
#pragma once
|
||||
|
||||
#include "llarp/iwp.h"
|
||||
#include "llarp/iwp/establish_job.hpp"
|
||||
#include "router.hpp"
|
||||
#include "session.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
|
||||
struct llarp_link
|
||||
{
|
||||
typedef std::mutex mtx_t;
|
||||
typedef std::lock_guard< mtx_t > lock_t;
|
||||
|
||||
llarp_router *router;
|
||||
llarp_crypto *crypto;
|
||||
llarp_logic *logic;
|
||||
llarp_ev_loop *netloop;
|
||||
llarp_async_iwp *iwp;
|
||||
llarp_threadpool *worker;
|
||||
llarp_link *parent = nullptr;
|
||||
llarp_udp_io udp;
|
||||
llarp::Addr addr;
|
||||
char keyfile[255];
|
||||
uint32_t timeout_job_id;
|
||||
|
||||
const char *
|
||||
name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
const char *m_name;
|
||||
|
||||
typedef std::unordered_map< llarp::Addr, llarp_link_session *,
|
||||
llarp::addrhash >
|
||||
LinkMap_t;
|
||||
|
||||
LinkMap_t m_sessions;
|
||||
mtx_t m_sessions_Mutex;
|
||||
|
||||
typedef std::unordered_map< llarp::PubKey, llarp::Addr, llarp::PubKeyHash >
|
||||
SessionMap_t;
|
||||
|
||||
SessionMap_t m_Connected;
|
||||
mtx_t m_Connected_Mutex;
|
||||
|
||||
typedef std::unordered_map< llarp::Addr, llarp_link_session *,
|
||||
llarp::addrhash >
|
||||
PendingSessionMap_t;
|
||||
PendingSessionMap_t m_PendingSessions;
|
||||
mtx_t m_PendingSessions_Mutex;
|
||||
|
||||
llarp::SecretKey seckey;
|
||||
|
||||
llarp_link(const llarp_iwp_args &args)
|
||||
: router(args.router)
|
||||
, crypto(args.crypto)
|
||||
, logic(args.logic)
|
||||
, worker(args.cryptoworker)
|
||||
, m_name("IWP")
|
||||
{
|
||||
strncpy(keyfile, args.keyfile, sizeof(keyfile));
|
||||
iwp = llarp_async_iwp_new(crypto, logic, worker);
|
||||
}
|
||||
|
||||
~llarp_link()
|
||||
{
|
||||
llarp_async_iwp_free(iwp);
|
||||
}
|
||||
|
||||
bool
|
||||
has_intro_from(const llarp::Addr &from)
|
||||
{
|
||||
std::unique_lock< std::mutex > lock(m_PendingSessions_Mutex);
|
||||
return m_PendingSessions.find(from) != m_PendingSessions.end();
|
||||
}
|
||||
|
||||
void
|
||||
put_intro_from(llarp_link_session *s)
|
||||
{
|
||||
std::unique_lock< std::mutex > lock(m_PendingSessions_Mutex);
|
||||
m_PendingSessions[s->addr] = s;
|
||||
}
|
||||
|
||||
void
|
||||
remove_intro_from(const llarp::Addr &from)
|
||||
{
|
||||
std::unique_lock< std::mutex > lock(m_PendingSessions_Mutex);
|
||||
m_PendingSessions.erase(from);
|
||||
}
|
||||
|
||||
// set that src address has identity pubkey
|
||||
void
|
||||
MapAddr(const llarp::Addr &src, const llarp::PubKey &identity)
|
||||
{
|
||||
lock_t lock(m_Connected_Mutex);
|
||||
m_Connected[identity] = src;
|
||||
}
|
||||
|
||||
static bool
|
||||
has_session_to(llarp_link *serv, const byte_t *pubkey)
|
||||
{
|
||||
llarp::PubKey pk(pubkey);
|
||||
lock_t lock(serv->m_Connected_Mutex);
|
||||
return serv->m_Connected.find(pk) != serv->m_Connected.end();
|
||||
}
|
||||
|
||||
void
|
||||
TickSessions()
|
||||
{
|
||||
auto now = llarp_time_now_ms();
|
||||
{
|
||||
lock_t lock(m_sessions_Mutex);
|
||||
std::set< llarp::Addr > remove;
|
||||
for(auto &itr : m_sessions)
|
||||
{
|
||||
llarp_link_session *s = itr.second;
|
||||
if(s && s->Tick(now))
|
||||
remove.insert(itr.first);
|
||||
}
|
||||
|
||||
for(const auto &addr : remove)
|
||||
RemoveSessionByAddr(addr);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
sendto(llarp_link *serv, const byte_t *pubkey, llarp_buffer_t buf)
|
||||
{
|
||||
// lock_t lock(serv->m_Connected_Mutex);
|
||||
auto itr = serv->m_Connected.find(pubkey);
|
||||
if(itr != serv->m_Connected.end())
|
||||
{
|
||||
// lock_t innerlock(serv->m_sessions_Mutex);
|
||||
auto inner_itr = serv->m_sessions.find(itr->second);
|
||||
if(inner_itr != serv->m_sessions.end())
|
||||
{
|
||||
llarp_link_session *link = inner_itr->second;
|
||||
return link->sendto(buf);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
UnmapAddr(const llarp::Addr &src)
|
||||
{
|
||||
lock_t lock(m_Connected_Mutex);
|
||||
// std::unordered_map< llarp::pubkey, llarp::Addr, llarp::pubkeyhash >
|
||||
auto itr = std::find_if(
|
||||
m_Connected.begin(), m_Connected.end(),
|
||||
[src](const std::pair< llarp::PubKey, llarp::Addr > &item) -> bool {
|
||||
return src == item.second;
|
||||
});
|
||||
if(itr == std::end(m_Connected))
|
||||
return;
|
||||
|
||||
// tell router we are done with this session
|
||||
router->SessionClosed(itr->first);
|
||||
|
||||
m_Connected.erase(itr);
|
||||
}
|
||||
|
||||
llarp_link_session *
|
||||
create_session(llarp::Addr src)
|
||||
{
|
||||
return new llarp_link_session(this, seckey, src);
|
||||
}
|
||||
|
||||
bool
|
||||
has_session_to(const llarp::Addr &dst)
|
||||
{
|
||||
lock_t lock(m_sessions_Mutex);
|
||||
return m_sessions.find(dst) != m_sessions.end();
|
||||
}
|
||||
|
||||
llarp_link_session *
|
||||
find_session(const llarp::Addr &addr)
|
||||
{
|
||||
lock_t lock(m_sessions_Mutex);
|
||||
auto itr = m_sessions.find(addr);
|
||||
if(itr == m_sessions.end())
|
||||
return nullptr;
|
||||
else
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
void
|
||||
put_session(const llarp::Addr &src, llarp_link_session *impl)
|
||||
{
|
||||
lock_t lock(m_sessions_Mutex);
|
||||
m_sessions.emplace(src, impl);
|
||||
impl->our_router = &router->rc;
|
||||
}
|
||||
|
||||
void
|
||||
clear_sessions()
|
||||
{
|
||||
lock_t lock(m_sessions_Mutex);
|
||||
auto itr = m_sessions.begin();
|
||||
while(itr != m_sessions.end())
|
||||
{
|
||||
delete itr->second;
|
||||
itr = m_sessions.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_logic_pump(void *user)
|
||||
{
|
||||
llarp_link *self = static_cast< llarp_link * >(user);
|
||||
lock_t lock(self->m_sessions_Mutex);
|
||||
auto itr = self->m_sessions.begin();
|
||||
while(itr != self->m_sessions.end())
|
||||
{
|
||||
itr->second->TickLogic();
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PumpLogic()
|
||||
{
|
||||
llarp_logic_queue_job(logic, {this, &handle_logic_pump});
|
||||
}
|
||||
|
||||
void
|
||||
RemoveSessionByAddr(const llarp::Addr &addr)
|
||||
{
|
||||
auto itr = m_sessions.find(addr);
|
||||
if(itr != m_sessions.end())
|
||||
{
|
||||
llarp::LogDebug("removing session ", addr);
|
||||
UnmapAddr(addr);
|
||||
llarp_link_session *s = itr->second;
|
||||
s->done();
|
||||
m_sessions.erase(itr);
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
pubkey()
|
||||
{
|
||||
return llarp::seckey_topublic(seckey);
|
||||
}
|
||||
|
||||
bool
|
||||
ensure_privkey()
|
||||
{
|
||||
llarp::LogDebug("ensure transport private key at ", keyfile);
|
||||
std::error_code ec;
|
||||
if(!fs::exists(keyfile, ec))
|
||||
{
|
||||
if(!keygen(keyfile))
|
||||
return false;
|
||||
}
|
||||
std::ifstream f(keyfile);
|
||||
if(f.is_open())
|
||||
{
|
||||
f.read((char *)seckey.data(), seckey.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
keygen(const char *fname)
|
||||
{
|
||||
crypto->encryption_keygen(seckey);
|
||||
llarp::LogInfo("new transport key generated");
|
||||
std::ofstream f(fname);
|
||||
if(f.is_open())
|
||||
{
|
||||
f.write((char *)seckey.data(), seckey.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_cleanup_timer(void *l, uint64_t orig, uint64_t left)
|
||||
{
|
||||
if(left)
|
||||
return;
|
||||
llarp_link *link = static_cast< llarp_link * >(l);
|
||||
link->timeout_job_id = 0;
|
||||
link->TickSessions();
|
||||
link->issue_cleanup_timer(orig);
|
||||
}
|
||||
|
||||
// this is called in net threadpool
|
||||
static void
|
||||
handle_recvfrom(struct llarp_udp_io *udp, const struct sockaddr *saddr,
|
||||
const void *buf, ssize_t sz)
|
||||
{
|
||||
llarp_link *link = static_cast< llarp_link * >(udp->user);
|
||||
|
||||
llarp_link_session *s = link->find_session(*saddr);
|
||||
if(s == nullptr)
|
||||
{
|
||||
// new inbound session
|
||||
s = link->create_session(*saddr);
|
||||
}
|
||||
s->recv(buf, sz);
|
||||
}
|
||||
|
||||
void
|
||||
cancel_timer()
|
||||
{
|
||||
if(timeout_job_id)
|
||||
{
|
||||
llarp_logic_cancel_call(logic, timeout_job_id);
|
||||
}
|
||||
timeout_job_id = 0;
|
||||
}
|
||||
|
||||
void
|
||||
issue_cleanup_timer(uint64_t timeout)
|
||||
{
|
||||
timeout_job_id = llarp_logic_call_later(
|
||||
logic, {timeout, this, &llarp_link::handle_cleanup_timer});
|
||||
}
|
||||
|
||||
void
|
||||
get_our_address(struct llarp_ai *addr)
|
||||
{
|
||||
addr->rank = 1;
|
||||
strncpy(addr->dialect, "IWP", sizeof(addr->dialect));
|
||||
memcpy(addr->enc_key, pubkey(), 32);
|
||||
memcpy(addr->ip.s6_addr, this->addr.addr6(), 16);
|
||||
addr->port = this->addr.port();
|
||||
}
|
||||
|
||||
static void
|
||||
after_recv(llarp_udp_io *udp)
|
||||
{
|
||||
llarp_link *self = static_cast< llarp_link * >(udp->user);
|
||||
self->PumpLogic();
|
||||
}
|
||||
|
||||
bool
|
||||
configure(struct llarp_ev_loop *netloop, const char *ifname, int af,
|
||||
uint16_t port)
|
||||
{
|
||||
if(!ensure_privkey())
|
||||
{
|
||||
llarp::LogError("failed to ensure private key");
|
||||
return false;
|
||||
}
|
||||
|
||||
llarp::LogDebug("configure link ifname=", ifname, " af=", af,
|
||||
" port=", port);
|
||||
// bind
|
||||
sockaddr_in ip4addr;
|
||||
sockaddr_in6 ip6addr;
|
||||
sockaddr *addr = nullptr;
|
||||
switch(af)
|
||||
{
|
||||
case AF_INET:
|
||||
addr = (sockaddr *)&ip4addr;
|
||||
llarp::Zero(addr, sizeof(ip4addr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
addr = (sockaddr *)&ip6addr;
|
||||
llarp::Zero(addr, sizeof(ip6addr));
|
||||
break;
|
||||
// TODO: AF_PACKET
|
||||
default:
|
||||
llarp::LogError(__FILE__, "unsupported address family", af);
|
||||
return false;
|
||||
}
|
||||
|
||||
addr->sa_family = af;
|
||||
|
||||
if(!llarp::StrEq(ifname, "*"))
|
||||
{
|
||||
if(!llarp_getifaddr(ifname, af, addr))
|
||||
{
|
||||
llarp::LogError("failed to get address of network interface ", ifname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_name = "OWP"; // outboundLink_name;
|
||||
|
||||
switch(af)
|
||||
{
|
||||
case AF_INET:
|
||||
ip4addr.sin_port = htons(port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
ip6addr.sin6_port = htons(port);
|
||||
break;
|
||||
// TODO: AF_PACKET
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
this->addr = *addr;
|
||||
this->netloop = netloop;
|
||||
udp.recvfrom = &llarp_link::handle_recvfrom;
|
||||
udp.user = this;
|
||||
udp.tick = &llarp_link::after_recv;
|
||||
llarp::LogDebug("bind IWP link to ", addr);
|
||||
if(llarp_ev_add_udp(netloop, &udp, addr) == -1)
|
||||
{
|
||||
llarp::LogError("failed to bind to ", addr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
start_link(struct llarp_logic *logic)
|
||||
{
|
||||
// give link implementations
|
||||
// link->parent = l;
|
||||
timeout_job_id = 0;
|
||||
logic = logic;
|
||||
// start cleanup timer
|
||||
issue_cleanup_timer(500);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
stop_link()
|
||||
{
|
||||
cancel_timer();
|
||||
llarp_ev_close_udp(&udp);
|
||||
clear_sessions();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
iter_sessions(llarp_link_session_iter iter)
|
||||
{
|
||||
auto sz = m_sessions.size();
|
||||
if(sz)
|
||||
{
|
||||
llarp::LogDebug("we have ", sz, "sessions");
|
||||
iter.link = this;
|
||||
// TODO: race condition with cleanup timer
|
||||
for(auto &item : m_sessions)
|
||||
if(item.second)
|
||||
if(!iter.visit(&iter, item.second))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
try_establish(struct llarp_link_establish_job *job)
|
||||
{
|
||||
llarp::Addr dst(job->ai);
|
||||
llarp::LogDebug("establish session to ", dst);
|
||||
llarp_link_session *s = find_session(dst);
|
||||
if(s == nullptr)
|
||||
{
|
||||
s = create_session(dst);
|
||||
put_session(dst, s);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
s->establish_job = job;
|
||||
s->frame.alive(); // mark it alive
|
||||
s->introduce(job->ai.enc_key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
mark_session_active(llarp_link_session *s)
|
||||
{
|
||||
s->frame.alive();
|
||||
}
|
||||
};
|
@ -0,0 +1,178 @@
|
||||
#pragma once
|
||||
|
||||
#include "codel.hpp"
|
||||
#include "frame_state.hpp"
|
||||
#include "llarp/buffer.h"
|
||||
#include "llarp/crypto.hpp"
|
||||
#include "llarp/crypto_async.h"
|
||||
#include "llarp/router_contact.h"
|
||||
#include "llarp/time.h"
|
||||
#include "llarp/types.h"
|
||||
#include "net.hpp"
|
||||
|
||||
struct llarp_udp_io;
|
||||
struct llarp_async_iwp;
|
||||
struct llarp_logic;
|
||||
struct llarp_link;
|
||||
struct transit_message;
|
||||
struct llarp_link_establish_job;
|
||||
|
||||
struct llarp_link_session
|
||||
{
|
||||
static constexpr llarp_time_t SESSION_TIMEOUT = 10000;
|
||||
static constexpr llarp_time_t KEEP_ALIVE_INTERVAL = SESSION_TIMEOUT / 4;
|
||||
static constexpr size_t MAX_PAD = 128;
|
||||
|
||||
llarp_link_session(llarp_link *l, const byte_t *seckey, const llarp::Addr &a);
|
||||
|
||||
~llarp_link_session();
|
||||
|
||||
void
|
||||
session_start();
|
||||
|
||||
bool sendto(llarp_buffer_t);
|
||||
|
||||
bool
|
||||
has_timed_out();
|
||||
bool
|
||||
timedout(llarp_time_t now, llarp_time_t timeout = SESSION_TIMEOUT);
|
||||
|
||||
void
|
||||
close();
|
||||
|
||||
void
|
||||
session_established();
|
||||
|
||||
llarp_link *
|
||||
get_parent();
|
||||
llarp_rc *
|
||||
get_remote_router();
|
||||
|
||||
bool
|
||||
CheckRCValid();
|
||||
bool
|
||||
IsEstablished();
|
||||
void
|
||||
send_LIM();
|
||||
bool
|
||||
is_invalidated() const;
|
||||
|
||||
void
|
||||
done();
|
||||
void
|
||||
pump();
|
||||
void
|
||||
introduce(uint8_t *pub);
|
||||
|
||||
void
|
||||
intro_ack();
|
||||
void
|
||||
on_intro_ack(const void *buf, size_t sz);
|
||||
void
|
||||
on_intro(const void *buf, size_t sz);
|
||||
void
|
||||
on_session_start(const void *buf, size_t sz);
|
||||
void
|
||||
encrypt_frame_async_send(const void *buf, size_t sz);
|
||||
|
||||
// void send_keepalive(void *user);
|
||||
bool
|
||||
Tick(llarp_time_t now);
|
||||
|
||||
void
|
||||
PumpCryptoOutbound();
|
||||
|
||||
// process inbound and outbound queues (logic thread)
|
||||
void
|
||||
TickLogic();
|
||||
|
||||
// this is called from net thread
|
||||
void
|
||||
recv(const void *buf, size_t sz);
|
||||
|
||||
llarp_router *
|
||||
Router();
|
||||
|
||||
llarp_udp_io *udp;
|
||||
llarp_crypto *crypto;
|
||||
llarp_async_iwp *iwp;
|
||||
llarp_logic *logic;
|
||||
|
||||
llarp_link *serv = nullptr;
|
||||
|
||||
llarp_rc *our_router = nullptr;
|
||||
llarp_rc remote_router;
|
||||
|
||||
llarp::SecretKey eph_seckey;
|
||||
llarp::PubKey remote;
|
||||
llarp::SharedSecret sessionkey;
|
||||
|
||||
llarp_link_establish_job *establish_job = nullptr;
|
||||
|
||||
/// cached timestamp for frame creation
|
||||
llarp_time_t now;
|
||||
llarp_time_t lastKeepalive = 0;
|
||||
uint32_t establish_job_id = 0;
|
||||
uint32_t frames = 0;
|
||||
bool working = false;
|
||||
|
||||
llarp::util::CoDelQueue< iwp_async_frame *, FrameGetTime, FramePutTime >
|
||||
outboundFrames;
|
||||
/*
|
||||
std::mutex m_EncryptedFramesMutex;
|
||||
std::queue< iwp_async_frame > encryptedFrames;
|
||||
*/
|
||||
llarp::util::CoDelQueue< iwp_async_frame *, FrameGetTime, FramePutTime >
|
||||
decryptedFrames;
|
||||
|
||||
uint32_t pump_send_timer_id = 0;
|
||||
uint32_t pump_recv_timer_id = 0;
|
||||
|
||||
llarp::Addr addr;
|
||||
iwp_async_intro intro;
|
||||
iwp_async_introack introack;
|
||||
iwp_async_session_start start;
|
||||
// frame_state frame;
|
||||
bool started_inbound_codel = false;
|
||||
|
||||
byte_t token[32];
|
||||
byte_t workbuf[MAX_PAD + 128];
|
||||
|
||||
enum State
|
||||
{
|
||||
eInitial,
|
||||
eIntroRecv,
|
||||
eIntroSent,
|
||||
eIntroAckSent,
|
||||
eIntroAckRecv,
|
||||
eSessionStartSent,
|
||||
eLIMSent,
|
||||
eEstablished,
|
||||
eTimeout
|
||||
};
|
||||
|
||||
State state;
|
||||
void
|
||||
EnterState(State st);
|
||||
|
||||
void
|
||||
add_outbound_message(uint64_t id, transit_message *msg);
|
||||
void
|
||||
EncryptOutboundFrames();
|
||||
iwp_async_frame *
|
||||
alloc_frame(const void *buf, size_t sz);
|
||||
void
|
||||
decrypt_frame(const void *buf, size_t sz);
|
||||
|
||||
static void
|
||||
handle_frame_decrypt(iwp_async_frame *f);
|
||||
|
||||
frame_state frame;
|
||||
};
|
||||
|
||||
struct llarp_link_session_iter
|
||||
{
|
||||
void *user;
|
||||
struct llarp_link *link;
|
||||
bool (*visit)(struct llarp_link_session_iter *, struct llarp_link_session *);
|
||||
};
|
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "llarp/types.h"
|
||||
#include "sendbuf.hpp"
|
||||
#include "xmit.hpp"
|
||||
|
||||
#include <bitset>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct transit_message
|
||||
{
|
||||
xmit msginfo;
|
||||
std::bitset< 32 > status = {};
|
||||
|
||||
typedef std::vector< byte_t > fragment_t;
|
||||
|
||||
std::unordered_map< byte_t, fragment_t > frags;
|
||||
fragment_t lastfrag;
|
||||
llarp_time_t lastAck = 0;
|
||||
llarp_time_t started;
|
||||
|
||||
void
|
||||
clear();
|
||||
|
||||
// calculate acked bitmask
|
||||
uint32_t
|
||||
get_bitmask() const;
|
||||
|
||||
// outbound
|
||||
transit_message(llarp_buffer_t buf, const byte_t *hash, uint64_t id,
|
||||
uint16_t mtu = 1024);
|
||||
|
||||
// inbound
|
||||
transit_message(const xmit &x);
|
||||
|
||||
/// ack packets based off a bitmask
|
||||
void
|
||||
ack(uint32_t bitmask);
|
||||
|
||||
bool
|
||||
should_send_ack(llarp_time_t now) const;
|
||||
|
||||
bool
|
||||
should_resend_frags(llarp_time_t now) const;
|
||||
|
||||
bool
|
||||
should_resend_xmit(llarp_time_t now) const;
|
||||
bool
|
||||
completed() const;
|
||||
|
||||
// template < typename T >
|
||||
void
|
||||
generate_xmit(sendqueue_t &queue, byte_t flags = 0);
|
||||
|
||||
// template < typename T >
|
||||
void
|
||||
retransmit_frags(sendqueue_t &queue, byte_t flags = 0);
|
||||
|
||||
bool
|
||||
reassemble(std::vector< byte_t > &buffer);
|
||||
|
||||
void
|
||||
put_message(llarp_buffer_t buf, const byte_t *hash, uint64_t id,
|
||||
uint16_t mtu = 1024);
|
||||
|
||||
void
|
||||
put_lastfrag(byte_t *buf, size_t sz);
|
||||
|
||||
bool
|
||||
put_frag(byte_t fragno, byte_t *buf);
|
||||
};
|
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "llarp/buffer.h"
|
||||
|
||||
struct xmit
|
||||
{
|
||||
byte_t buffer[48];
|
||||
|
||||
xmit() = default;
|
||||
|
||||
xmit(byte_t *ptr);
|
||||
|
||||
xmit(const xmit &other);
|
||||
|
||||
void
|
||||
set_info(const byte_t *hash, uint64_t id, uint16_t fragsz, uint16_t lastsz,
|
||||
uint8_t numfrags, uint8_t flags = 0x01);
|
||||
|
||||
const byte_t *
|
||||
hash() const;
|
||||
|
||||
uint64_t
|
||||
msgid() const;
|
||||
|
||||
// size of each full fragment
|
||||
uint16_t
|
||||
fragsize() const;
|
||||
|
||||
// number of full fragments
|
||||
uint8_t
|
||||
numfrags() const;
|
||||
|
||||
// size of the entire message
|
||||
size_t
|
||||
totalsize() const;
|
||||
|
||||
// size of the last fragment
|
||||
uint16_t
|
||||
lastfrag() const;
|
||||
|
||||
uint8_t
|
||||
flags();
|
||||
};
|
@ -1,127 +0,0 @@
|
||||
#ifndef LLARP_LINK_H_
|
||||
#define LLARP_LINK_H_
|
||||
#include <llarp/address_info.h>
|
||||
#include <llarp/crypto.h>
|
||||
#include <llarp/ev.h>
|
||||
#include <llarp/logic.h>
|
||||
#include <llarp/mem.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** 2^15 bytes */
|
||||
#define MAX_LINK_MSG_SIZE (32768)
|
||||
|
||||
/**
|
||||
* wire layer transport interface
|
||||
*/
|
||||
struct llarp_link;
|
||||
|
||||
/**
|
||||
* wire layer transport session for point to point communication between us
|
||||
* and another
|
||||
*/
|
||||
struct llarp_link_session;
|
||||
|
||||
/** outbound session establish job */
|
||||
struct llarp_link_establish_job
|
||||
{
|
||||
void *user;
|
||||
void (*result)(struct llarp_link_establish_job *);
|
||||
struct llarp_ai ai;
|
||||
uint64_t timeout;
|
||||
uint16_t retries;
|
||||
|
||||
byte_t pubkey[PUBKEYSIZE];
|
||||
/** set on success by try_establish */
|
||||
struct llarp_link *link;
|
||||
/** set on success by try_establish */
|
||||
struct llarp_link_session *session;
|
||||
};
|
||||
|
||||
struct llarp_link_session_iter
|
||||
{
|
||||
void *user;
|
||||
struct llarp_link *link;
|
||||
bool (*visit)(struct llarp_link_session_iter *, struct llarp_link_session *);
|
||||
};
|
||||
|
||||
struct llarp_link_ev_listener
|
||||
{
|
||||
void *user;
|
||||
void (*established)(struct llarp_link_ev_listener *,
|
||||
struct llarp_link_session *, bool);
|
||||
void (*timeout)(struct llarp_link_ev_listener *, struct llarp_link_session *,
|
||||
bool);
|
||||
void (*tx)(struct llarp_link_ev_listener *, struct llarp_link_session *,
|
||||
size_t);
|
||||
void (*rx)(struct llarp_link_ev_listener *, struct llarp_link_session *,
|
||||
size_t);
|
||||
void (*error)(struct llarp_link_ev_listener *, struct llarp_link_session *,
|
||||
const char *);
|
||||
};
|
||||
|
||||
// forward declare
|
||||
struct llarp_router;
|
||||
|
||||
struct llarp_link
|
||||
{
|
||||
void *impl;
|
||||
struct llarp_router *router;
|
||||
const char *(*name)(void);
|
||||
void (*get_our_address)(struct llarp_link *, struct llarp_ai *);
|
||||
/*
|
||||
int (*register_listener)(struct llarp_link *, struct
|
||||
llarp_link_ev_listener); void (*deregister_listener)(struct llarp_link *,
|
||||
int);
|
||||
*/
|
||||
bool (*configure)(struct llarp_link *, struct llarp_ev_loop *, const char *,
|
||||
int, uint16_t);
|
||||
bool (*start_link)(struct llarp_link *, struct llarp_logic *);
|
||||
bool (*stop_link)(struct llarp_link *);
|
||||
void (*iter_sessions)(struct llarp_link *, struct llarp_link_session_iter);
|
||||
bool (*try_establish)(struct llarp_link *, struct llarp_link_establish_job *);
|
||||
/// send to already established session given its public identity key
|
||||
/// returns false if we don't have this session
|
||||
/// returns true if the messages were queued
|
||||
bool (*sendto)(struct llarp_link *, const byte_t *, llarp_buffer_t);
|
||||
/// return true if we have a session to router given public identity key
|
||||
bool (*has_session_to)(struct llarp_link *, const byte_t *);
|
||||
void (*mark_session_active)(struct llarp_link *, struct llarp_link_session *);
|
||||
void (*free_impl)(struct llarp_link *);
|
||||
};
|
||||
|
||||
/** checks if all members are initialized */
|
||||
bool
|
||||
llarp_link_initialized(struct llarp_link *link);
|
||||
|
||||
struct llarp_link_session
|
||||
{
|
||||
void *impl;
|
||||
/** send an entire message, splits up into smaller pieces and does
|
||||
* encryption
|
||||
*/
|
||||
bool (*sendto)(struct llarp_link_session *, llarp_buffer_t);
|
||||
/** return true if this session is timed out */
|
||||
bool (*timeout)(struct llarp_link_session *);
|
||||
/** explicit close session */
|
||||
void (*close)(struct llarp_link_session *);
|
||||
/** set session established */
|
||||
void (*established)(struct llarp_link_session *);
|
||||
/** get parent link */
|
||||
struct llarp_link *(*get_parent)(struct llarp_link_session *);
|
||||
/** get router contact of remote router */
|
||||
struct llarp_rc *(*get_remote_router)(struct llarp_link_session *);
|
||||
};
|
||||
|
||||
bool
|
||||
llarp_link_session_initialized(struct llarp_link_session *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,16 @@
|
||||
#ifndef LLARP_MESSAGES_HIDDEN_SERIVCE_HPP
|
||||
#define LLARP_MESSAGES_HIDDEN_SERIVCE_HPP
|
||||
|
||||
#include <llarp/routing/message.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace routing
|
||||
{
|
||||
struct HiddenServiceFrame : public IMessage
|
||||
{
|
||||
};
|
||||
} // namespace routing
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -1,21 +0,0 @@
|
||||
#ifndef LLARP_QUIC_H_
|
||||
#define LLARP_QUIC_H_
|
||||
|
||||
#include <llarp/link.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct llarp_quic_args
|
||||
{
|
||||
};
|
||||
|
||||
bool
|
||||
quic_link_init(struct llarp_link* link, struct llarp_quic_args args,
|
||||
struct llarp_msg_muxer* muxer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -1,179 +1,12 @@
|
||||
#ifndef LLARP_SERVICE_HPP
|
||||
#define LLARP_SERVICE_HPP
|
||||
#include <llarp/aligned.hpp>
|
||||
#include <llarp/bencode.hpp>
|
||||
#include <llarp/crypto.hpp>
|
||||
#include <llarp/path_types.hpp>
|
||||
#include <llarp/pow.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
constexpr std::size_t MAX_INTROSET_SIZE = 1024;
|
||||
|
||||
// forward declare
|
||||
struct IntroSet;
|
||||
|
||||
/// hidden service address
|
||||
typedef llarp::AlignedBuffer< 32 > Address;
|
||||
|
||||
std::string
|
||||
AddressToString(const Address& addr);
|
||||
|
||||
typedef llarp::AlignedBuffer< 16 > VanityNonce;
|
||||
|
||||
struct ServiceInfo : public llarp::IBEncodeMessage
|
||||
{
|
||||
llarp::PubKey enckey;
|
||||
llarp::PubKey signkey;
|
||||
uint64_t version = 0;
|
||||
VanityNonce vanity;
|
||||
|
||||
ServiceInfo();
|
||||
|
||||
~ServiceInfo();
|
||||
|
||||
ServiceInfo&
|
||||
operator=(const ServiceInfo& other)
|
||||
{
|
||||
enckey = other.enckey;
|
||||
signkey = other.signkey;
|
||||
version = other.version;
|
||||
vanity = other.vanity;
|
||||
return *this;
|
||||
};
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const ServiceInfo& i)
|
||||
{
|
||||
return out << "[e=" << i.enckey << " s=" << i.signkey
|
||||
<< " v=" << i.version << " x=" << i.vanity << "]";
|
||||
}
|
||||
|
||||
/// calculate our address
|
||||
bool
|
||||
CalculateAddress(Address& addr) const;
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
};
|
||||
|
||||
// private keys
|
||||
struct Identity : public llarp::IBEncodeMessage
|
||||
{
|
||||
llarp::SecretKey enckey;
|
||||
llarp::SecretKey signkey;
|
||||
uint64_t version = 0;
|
||||
VanityNonce vanity;
|
||||
|
||||
// public service info
|
||||
ServiceInfo pub;
|
||||
|
||||
~Identity();
|
||||
|
||||
// regenerate secret keys
|
||||
void
|
||||
RegenerateKeys(llarp_crypto* c);
|
||||
|
||||
// load from file
|
||||
bool
|
||||
LoadFromFile(const std::string& fpath);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
SignIntroSet(IntroSet& i, llarp_crypto* c) const;
|
||||
};
|
||||
|
||||
struct Introduction : public llarp::IBEncodeMessage
|
||||
{
|
||||
llarp::PubKey router;
|
||||
llarp::PathID_t pathID;
|
||||
uint64_t version = 0;
|
||||
uint64_t expiresAt;
|
||||
|
||||
~Introduction();
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const Introduction& i)
|
||||
{
|
||||
return out << "k=" << i.router << " p=" << i.pathID
|
||||
<< " v=" << i.version << " x=" << i.expiresAt;
|
||||
}
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
operator<(const Introduction& other) const
|
||||
{
|
||||
return expiresAt < other.expiresAt || pathID < other.pathID;
|
||||
}
|
||||
};
|
||||
|
||||
struct IntroSet : public llarp::IBEncodeMessage
|
||||
{
|
||||
ServiceInfo A;
|
||||
std::set< Introduction > I;
|
||||
uint64_t V = 0;
|
||||
llarp::PoW* W = nullptr;
|
||||
llarp::Signature Z;
|
||||
|
||||
~IntroSet();
|
||||
|
||||
IntroSet&
|
||||
operator=(const IntroSet& other)
|
||||
{
|
||||
A = other.A;
|
||||
I = other.I;
|
||||
V = other.V;
|
||||
if(W)
|
||||
delete W;
|
||||
W = other.W;
|
||||
Z = other.Z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const IntroSet& i)
|
||||
{
|
||||
out << "A=[" << i.A << "] I=[";
|
||||
for(const auto& intro : i.I)
|
||||
{
|
||||
out << intro << ",";
|
||||
}
|
||||
return out << "] V=" << i.V << " Z=" << i.Z;
|
||||
}
|
||||
|
||||
bool
|
||||
BDecode(llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
VerifySignature(llarp_crypto* crypto) const;
|
||||
};
|
||||
|
||||
}; // namespace service
|
||||
} // namespace llarp
|
||||
#include <llarp/service/Identity.hpp>
|
||||
#include <llarp/service/Intro.hpp>
|
||||
#include <llarp/service/IntroSet.hpp>
|
||||
#include <llarp/service/config.hpp>
|
||||
#include <llarp/service/context.hpp>
|
||||
#include <llarp/service/endpoint.hpp>
|
||||
#include <llarp/service/types.hpp>
|
||||
|
||||
#endif
|
@ -0,0 +1,49 @@
|
||||
#ifndef LLARP_SERVICE_IDENTITY_HPP
|
||||
#define LLARP_SERVICE_IDENTITY_HPP
|
||||
#include <llarp/bencode.hpp>
|
||||
#include <llarp/crypto.hpp>
|
||||
#include <llarp/service/Info.hpp>
|
||||
#include <llarp/service/IntroSet.hpp>
|
||||
#include <llarp/service/types.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
// private keys
|
||||
struct Identity : public llarp::IBEncodeMessage
|
||||
{
|
||||
llarp::SecretKey enckey;
|
||||
llarp::SecretKey signkey;
|
||||
uint64_t version = 0;
|
||||
VanityNonce vanity;
|
||||
|
||||
// public service info
|
||||
ServiceInfo pub;
|
||||
|
||||
~Identity();
|
||||
|
||||
// regenerate secret keys
|
||||
void
|
||||
RegenerateKeys(llarp_crypto* c);
|
||||
|
||||
// load from file
|
||||
bool
|
||||
LoadFromFile(const std::string& fpath);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
EnsureKeys(const std::string& fpath, llarp_crypto* c);
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
SignIntroSet(IntroSet& i, llarp_crypto* c) const;
|
||||
};
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,59 @@
|
||||
#ifndef LLARP_SERVICE_INFO_HPP
|
||||
#define LLARP_SERVICE_INFO_HPP
|
||||
#include <llarp/bencode.hpp>
|
||||
#include <llarp/crypto.hpp>
|
||||
#include <llarp/service/types.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
struct ServiceInfo : public llarp::IBEncodeMessage
|
||||
{
|
||||
llarp::PubKey enckey;
|
||||
llarp::PubKey signkey;
|
||||
uint64_t version = 0;
|
||||
VanityNonce vanity;
|
||||
|
||||
ServiceInfo();
|
||||
|
||||
~ServiceInfo();
|
||||
|
||||
bool
|
||||
operator==(const ServiceInfo& other) const
|
||||
{
|
||||
return enckey == other.enckey && signkey == other.signkey
|
||||
&& version == other.version && vanity == other.vanity;
|
||||
}
|
||||
|
||||
ServiceInfo&
|
||||
operator=(const ServiceInfo& other)
|
||||
{
|
||||
enckey = other.enckey;
|
||||
signkey = other.signkey;
|
||||
version = other.version;
|
||||
vanity = other.vanity;
|
||||
return *this;
|
||||
};
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const ServiceInfo& i)
|
||||
{
|
||||
return out << "[e=" << i.enckey << " s=" << i.signkey
|
||||
<< " v=" << i.version << " x=" << i.vanity << "]";
|
||||
}
|
||||
|
||||
/// calculate our address
|
||||
bool
|
||||
CalculateAddress(byte_t* buf) const;
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
};
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,55 @@
|
||||
#ifndef LLARP_SERVICE_INTRO_HPP
|
||||
#define LLARP_SERVICE_INTRO_HPP
|
||||
#include <llarp/bencode.hpp>
|
||||
#include <llarp/crypto.hpp>
|
||||
#include <llarp/path_types.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
struct Introduction : public llarp::IBEncodeMessage
|
||||
{
|
||||
llarp::PubKey router;
|
||||
llarp::PathID_t pathID;
|
||||
uint64_t latency = 0;
|
||||
uint64_t version = 0;
|
||||
uint64_t expiresAt = 0;
|
||||
|
||||
Introduction() = default;
|
||||
Introduction(const Introduction& other)
|
||||
{
|
||||
router = other.router;
|
||||
pathID = other.pathID;
|
||||
latency = other.latency;
|
||||
version = other.version;
|
||||
expiresAt = other.expiresAt;
|
||||
}
|
||||
|
||||
~Introduction();
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const Introduction& i)
|
||||
{
|
||||
return out << "k=" << i.router << " p=" << i.pathID
|
||||
<< " v=" << i.version << " x=" << i.expiresAt;
|
||||
}
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
operator<(const Introduction& other) const
|
||||
{
|
||||
return expiresAt < other.expiresAt || pathID < other.pathID;
|
||||
}
|
||||
};
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,63 @@
|
||||
#ifndef LLARP_SERVICE_INTROSET_HPP
|
||||
#define LLARP_SERVICE_INTROSET_HPP
|
||||
#include <iostream>
|
||||
#include <llarp/bencode.hpp>
|
||||
#include <llarp/crypto.hpp>
|
||||
#include <llarp/pow.hpp>
|
||||
#include <llarp/service/Info.hpp>
|
||||
#include <llarp/service/Intro.hpp>
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
constexpr std::size_t MAX_INTROSET_SIZE = 1024;
|
||||
|
||||
struct IntroSet : public llarp::IBEncodeMessage
|
||||
{
|
||||
ServiceInfo A;
|
||||
std::list< Introduction > I;
|
||||
llarp::PoW* W = nullptr;
|
||||
llarp::Signature Z;
|
||||
|
||||
~IntroSet();
|
||||
|
||||
IntroSet&
|
||||
operator=(const IntroSet& other)
|
||||
{
|
||||
A = other.A;
|
||||
I = other.I;
|
||||
version = other.version;
|
||||
if(W)
|
||||
delete W;
|
||||
W = other.W;
|
||||
Z = other.Z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const IntroSet& i)
|
||||
{
|
||||
out << "A=[" << i.A << "] I=[";
|
||||
for(const auto& intro : i.I)
|
||||
{
|
||||
out << intro << ",";
|
||||
}
|
||||
return out << "] V=" << i.version << " Z=" << i.Z;
|
||||
}
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
VerifySignature(llarp_crypto* crypto) const;
|
||||
};
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,38 @@
|
||||
#ifndef LLARP_SERVICE_ADDRESS_HPP
|
||||
#define LLARP_SERVICE_ADDRESS_HPP
|
||||
#include <llarp/aligned.hpp>
|
||||
#include <llarp/dht/key.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
struct Address : public llarp::AlignedBuffer< 32 >
|
||||
{
|
||||
std::string
|
||||
ToString() const;
|
||||
|
||||
Address() : llarp::AlignedBuffer< 32 >()
|
||||
{
|
||||
}
|
||||
|
||||
Address(const byte_t* data) : llarp::AlignedBuffer< 32 >(data)
|
||||
{
|
||||
}
|
||||
struct Hash
|
||||
{
|
||||
size_t
|
||||
operator()(const Address& addr) const
|
||||
{
|
||||
size_t idx = 0;
|
||||
memcpy(&idx, addr, sizeof(idx));
|
||||
return idx;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
#ifndef LLARP_SERVICE_CONFIG_HPP
|
||||
#define LLARP_SERVICE_CONFIG_HPP
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
struct Config
|
||||
{
|
||||
typedef std::list< std::pair< std::string, std::string > >
|
||||
section_values_t;
|
||||
typedef std::pair< std::string, section_values_t > section_t;
|
||||
|
||||
std::list< section_t > services;
|
||||
|
||||
bool
|
||||
Load(const std::string& fname);
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,30 @@
|
||||
#ifndef LLARP_SERVICE_CONTEXT_HPP
|
||||
#define LLARP_SERVICE_CONTEXT_HPP
|
||||
#include <llarp/router.h>
|
||||
#include <llarp/service/config.hpp>
|
||||
#include <llarp/service/endpoint.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
/// holds all the hidden service endpoints we own
|
||||
struct Context
|
||||
{
|
||||
Context(llarp_router *r);
|
||||
~Context();
|
||||
|
||||
void
|
||||
Tick();
|
||||
|
||||
bool
|
||||
AddEndpoint(const Config::section_t &conf);
|
||||
|
||||
private:
|
||||
llarp_router *m_Router;
|
||||
std::unordered_map< std::string, Endpoint * > m_Endpoints;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,96 @@
|
||||
#ifndef LLARP_SERVICE_ENDPOINT_HPP
|
||||
#define LLARP_SERVICE_ENDPOINT_HPP
|
||||
#include <llarp/messages/hidden_service.hpp>
|
||||
#include <llarp/pathbuilder.hpp>
|
||||
#include <llarp/service/Identity.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
struct Endpoint : public llarp_pathbuilder_context
|
||||
{
|
||||
Endpoint(const std::string& nickname, llarp_router* r);
|
||||
~Endpoint();
|
||||
|
||||
bool
|
||||
SetOption(const std::string& k, const std::string& v);
|
||||
|
||||
void
|
||||
Tick();
|
||||
|
||||
bool
|
||||
Start();
|
||||
|
||||
bool
|
||||
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg);
|
||||
|
||||
bool
|
||||
HandleHiddenServiceFrame(const llarp::routing::HiddenServiceFrame* msg);
|
||||
|
||||
/// return true if we have an established path to a hidden service
|
||||
bool
|
||||
HasPathToService(const Address& remote) const;
|
||||
|
||||
/// return false if we don't have a path to the service
|
||||
/// return true if we did and we removed it
|
||||
bool
|
||||
ForgetPathToService(const Address& remote);
|
||||
|
||||
/// context needed to initiate an outbound hidden service session
|
||||
struct OutboundContext : public llarp_pathbuilder_context
|
||||
{
|
||||
OutboundContext(Endpoint* parent);
|
||||
~OutboundContext();
|
||||
|
||||
/// the remote hidden service's curren intro set
|
||||
IntroSet currentIntroSet;
|
||||
|
||||
uint64_t sequenceNo = 0;
|
||||
|
||||
/// encrypt asynchronously and send to remote endpoint from us
|
||||
/// returns false if we cannot send yet otherwise returns true
|
||||
bool
|
||||
AsyncEncryptAndSendTo(llarp_buffer_t D);
|
||||
|
||||
/// issues a lookup to find the current intro set of the remote service
|
||||
void
|
||||
UpdateIntroSet();
|
||||
|
||||
bool
|
||||
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg);
|
||||
|
||||
private:
|
||||
llarp::SharedSecret sharedKey;
|
||||
Endpoint* m_Parent;
|
||||
};
|
||||
|
||||
// passed a sendto context when we have a path established otherwise
|
||||
// nullptr if the path was not made before the timeout
|
||||
typedef std::function< void(OutboundContext*) > PathEnsureHook;
|
||||
|
||||
/// return false if we have already called this function before for this
|
||||
/// address
|
||||
bool
|
||||
EnsurePathToService(const Address& remote, PathEnsureHook h,
|
||||
uint64_t timeoutMS);
|
||||
|
||||
virtual bool
|
||||
HandleAuthenticatedDataFrom(const Address& remote, llarp_buffer_t data)
|
||||
{
|
||||
/// TODO: imlement me
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
llarp_router* m_Router;
|
||||
std::string m_Keyfile;
|
||||
std::string m_Name;
|
||||
Identity m_Identity;
|
||||
std::unordered_map< Address, OutboundContext*, Address::Hash >
|
||||
m_RemoteSessions;
|
||||
};
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,6 @@
|
||||
#ifndef LLARP_SERVICE_TYPES_HPP
|
||||
#define LLARP_SERVICE_TYPES_HPP
|
||||
#include <llarp/service/address.hpp>
|
||||
#include <llarp/service/vanity.hpp>
|
||||
|
||||
#endif
|
@ -0,0 +1,14 @@
|
||||
|
||||
#ifndef LLARP_SERVICE_VANITY_HPP
|
||||
#define LLARP_SERVICE_VANITY_HPP
|
||||
#include <llarp/aligned.hpp>
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
/// hidden service address
|
||||
|
||||
typedef llarp::AlignedBuffer< 16 > VanityNonce;
|
||||
}
|
||||
}
|
||||
#endif
|
@ -1,16 +1,10 @@
|
||||
#ifndef LLARP_TIME_H
|
||||
#define LLARP_TIME_H
|
||||
#include <llarp/types.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
llarp_time_t
|
||||
llarp_time_now_ms();
|
||||
llarp_seconds_t
|
||||
llarp_time_now_sec();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,865 +1,57 @@
|
||||
#include <llarp/bencode.hpp>
|
||||
#include <llarp/dht.hpp>
|
||||
#include <llarp/messages/dht.hpp>
|
||||
#include <llarp/messages/dht_immediate.hpp>
|
||||
#include <llarp/dht.h>
|
||||
#include "router.hpp"
|
||||
#include "router_contact.hpp"
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
#include <algorithm> // std::find
|
||||
#include <set>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
DHTImmeidateMessage::~DHTImmeidateMessage()
|
||||
{
|
||||
for(auto &msg : msgs)
|
||||
delete msg;
|
||||
msgs.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "m"))
|
||||
return llarp::dht::DecodeMesssageList(remote.data(), buf, msgs);
|
||||
if(llarp_buffer_eq(key, "v"))
|
||||
{
|
||||
if(!bencode_read_integer(buf, &version))
|
||||
return false;
|
||||
return version == LLARP_PROTO_VERSION;
|
||||
}
|
||||
// bad key
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message type
|
||||
if(!bencode_write_bytestring(buf, "a", 1))
|
||||
return false;
|
||||
if(!bencode_write_bytestring(buf, "m", 1))
|
||||
return false;
|
||||
|
||||
// dht messages
|
||||
if(!bencode_write_bytestring(buf, "m", 1))
|
||||
return false;
|
||||
// begin list
|
||||
if(!bencode_start_list(buf))
|
||||
return false;
|
||||
for(const auto &msg : msgs)
|
||||
{
|
||||
if(!msg->BEncode(buf))
|
||||
return false;
|
||||
}
|
||||
// end list
|
||||
if(!bencode_end(buf))
|
||||
return false;
|
||||
|
||||
// protocol version
|
||||
if(!bencode_write_version_entry(buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::HandleMessage(llarp_router *router) const
|
||||
{
|
||||
DHTImmeidateMessage *reply = new DHTImmeidateMessage(remote);
|
||||
bool result = true;
|
||||
for(auto &msg : msgs)
|
||||
{
|
||||
result &= msg->HandleMessage(router->dht, reply->msgs);
|
||||
}
|
||||
return result && router->SendToOrQueue(remote.data(), reply);
|
||||
}
|
||||
|
||||
namespace dht
|
||||
{
|
||||
struct PathLookupInformer
|
||||
{
|
||||
llarp_router *router;
|
||||
PathID_t pathID;
|
||||
uint64_t txid;
|
||||
|
||||
PathLookupInformer(llarp_router *r, const PathID_t &id, uint64_t tx)
|
||||
: router(r), pathID(id), txid(tx)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SendReply(const llarp::routing::IMessage *msg)
|
||||
{
|
||||
auto path = router->paths.GetByUpstream(router->pubkey(), pathID);
|
||||
if(path == nullptr)
|
||||
{
|
||||
llarp::LogWarn("Path not found for relayed DHT message txid=", txid,
|
||||
" pathid=", pathID);
|
||||
return;
|
||||
}
|
||||
if(!path->SendRoutingMessage(msg, router))
|
||||
llarp::LogWarn("Failed to send reply for relayed DHT message txid=",
|
||||
txid, "pathid=", pathID);
|
||||
}
|
||||
|
||||
static void
|
||||
InformReply(llarp_router_lookup_job *job)
|
||||
{
|
||||
PathLookupInformer *self =
|
||||
static_cast< PathLookupInformer * >(job->user);
|
||||
llarp::routing::DHTMessage reply;
|
||||
if(job->found)
|
||||
{
|
||||
if(llarp_rc_verify_sig(&self->router->crypto, &job->result))
|
||||
{
|
||||
reply.M.push_back(
|
||||
new GotRouterMessage(job->target, self->txid, &job->result));
|
||||
}
|
||||
llarp_rc_free(&job->result);
|
||||
llarp_rc_clear(&job->result);
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.M.push_back(
|
||||
new GotRouterMessage(job->target, self->txid, nullptr));
|
||||
}
|
||||
self->SendReply(&reply);
|
||||
// TODO: is this okay?
|
||||
delete self;
|
||||
delete job;
|
||||
}
|
||||
};
|
||||
|
||||
/// variant of FindRouterMessage relayed via path
|
||||
struct RelayedFindRouterMessage : public FindRouterMessage
|
||||
{
|
||||
RelayedFindRouterMessage(const Key_t &from) : FindRouterMessage(from)
|
||||
{
|
||||
}
|
||||
|
||||
/// handle a relayed FindRouterMessage, do a lookup on the dht and inform
|
||||
/// the path of the result
|
||||
/// TODO: smart path expiration logic needs to be implemented
|
||||
virtual bool
|
||||
HandleMessage(llarp_dht_context *ctx, std::vector< IMessage * > &replies)
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
/// lookup for us, send an immeidate reply
|
||||
if(K == dht.OurKey())
|
||||
{
|
||||
auto path = dht.router->paths.GetByUpstream(K, pathID);
|
||||
if(path)
|
||||
{
|
||||
llarp::routing::DHTMessage reply;
|
||||
reply.M.push_back(new GotRouterMessage(K, txid, &dht.router->rc));
|
||||
return path->SendRoutingMessage(&reply, dht.router);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
llarp_router_lookup_job *job = new llarp_router_lookup_job;
|
||||
PathLookupInformer *informer =
|
||||
new PathLookupInformer(dht.router, pathID, txid);
|
||||
job->user = informer;
|
||||
job->hook = &PathLookupInformer::InformReply;
|
||||
job->found = false;
|
||||
job->dht = ctx;
|
||||
memcpy(job->target, K, sizeof(job->target));
|
||||
Key_t peer;
|
||||
if(dht.nodes->FindClosest(K, peer))
|
||||
dht.LookupRouter(K, dht.OurKey(), txid, peer, job);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
PublishIntroMessage::~PublishIntroMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
|
||||
{
|
||||
bool read = false;
|
||||
if(!BEncodeMaybeReadDictEntry("I", I, read, key, val))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("R", R, read, key, val))
|
||||
return false;
|
||||
if(llarp_buffer_eq(key, "S"))
|
||||
{
|
||||
read = true;
|
||||
hasS = true;
|
||||
if(!bencode_read_integer(val, &S))
|
||||
return false;
|
||||
}
|
||||
if(!BEncodeMaybeReadDictInt("V", V, read, key, val))
|
||||
return false;
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::HandleMessage(llarp_dht_context *ctx,
|
||||
std::vector< IMessage * > &replies) const
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
if(!I.VerifySignature(&dht.router->crypto))
|
||||
{
|
||||
llarp::LogWarn("invalid introset signature");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "I"))
|
||||
return false;
|
||||
if(!BEncodeWriteDictEntry("I", I, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt(buf, "R", R))
|
||||
return false;
|
||||
if(hasS)
|
||||
{
|
||||
if(!BEncodeWriteDictInt(buf, "S", S))
|
||||
return false;
|
||||
}
|
||||
if(!BEncodeWriteDictInt(buf, "V", LLARP_PROTO_VERSION))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
GotRouterMessage::~GotRouterMessage()
|
||||
{
|
||||
for(auto &rc : R)
|
||||
llarp_rc_free(&rc);
|
||||
R.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message type
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "S"))
|
||||
return false;
|
||||
|
||||
if(!BEncodeWriteDictList("R", R, buf))
|
||||
return false;
|
||||
|
||||
// txid
|
||||
if(!BEncodeWriteDictInt(buf, "T", txid))
|
||||
return false;
|
||||
|
||||
// version
|
||||
if(!BEncodeWriteDictInt(buf, "V", version))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "R"))
|
||||
{
|
||||
return BEncodeReadList(R, val);
|
||||
}
|
||||
if(llarp_buffer_eq(key, "T"))
|
||||
{
|
||||
return bencode_read_integer(val, &txid);
|
||||
}
|
||||
bool read = false;
|
||||
if(!BEncodeMaybeReadVersion("V", version, LLARP_PROTO_VERSION, read, key,
|
||||
val))
|
||||
return false;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::HandleMessage(llarp_dht_context *ctx,
|
||||
std::vector< IMessage * > &replies) const
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
auto pending = dht.FindPendingTX(From, txid);
|
||||
if(pending)
|
||||
{
|
||||
if(R.size())
|
||||
{
|
||||
pending->Completed(&R[0]);
|
||||
if(pending->requester != dht.OurKey())
|
||||
{
|
||||
replies.push_back(new GotRouterMessage(
|
||||
pending->target, pending->requesterTX, &R[0]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate to next closest peer
|
||||
Key_t nextPeer;
|
||||
pending->exclude.insert(From);
|
||||
if(pending->exclude.size() < 3
|
||||
&& dht.nodes->FindCloseExcluding(pending->target, nextPeer,
|
||||
pending->exclude))
|
||||
{
|
||||
llarp::LogInfo(pending->target, " was not found via ", From,
|
||||
" iterating to next peer ", nextPeer,
|
||||
" already asked ", pending->exclude.size(),
|
||||
" other peers");
|
||||
dht.LookupRouter(pending->target, pending->requester,
|
||||
pending->requesterTX, nextPeer, nullptr, true,
|
||||
pending->exclude);
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogInfo(pending->target, " was not found via ", From,
|
||||
" and we won't look it up");
|
||||
pending->Completed(nullptr);
|
||||
if(pending->requester != dht.OurKey())
|
||||
{
|
||||
replies.push_back(new GotRouterMessage(
|
||||
pending->target, pending->requesterTX, nullptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
dht.RemovePendingLookup(From, txid);
|
||||
return true;
|
||||
}
|
||||
llarp::LogWarn(
|
||||
"Got response for DHT transaction we are not tracking, txid=", txid);
|
||||
return false;
|
||||
}
|
||||
|
||||
FindRouterMessage::~FindRouterMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
FindRouterMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message type
|
||||
if(!bencode_write_bytestring(buf, "A", 1))
|
||||
return false;
|
||||
if(!bencode_write_bytestring(buf, "R", 1))
|
||||
return false;
|
||||
|
||||
// iterative or not?
|
||||
if(!bencode_write_bytestring(buf, "I", 1))
|
||||
return false;
|
||||
if(!bencode_write_int(buf, iterative ? 1 : 0))
|
||||
return false;
|
||||
|
||||
// key
|
||||
if(!bencode_write_bytestring(buf, "K", 1))
|
||||
return false;
|
||||
if(!bencode_write_bytestring(buf, K.data(), K.size()))
|
||||
return false;
|
||||
|
||||
// txid
|
||||
if(!bencode_write_bytestring(buf, "T", 1))
|
||||
return false;
|
||||
if(!bencode_write_uint64(buf, txid))
|
||||
return false;
|
||||
|
||||
// version
|
||||
if(!bencode_write_bytestring(buf, "V", 1))
|
||||
return false;
|
||||
if(!bencode_write_uint64(buf, version))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
FindRouterMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
|
||||
{
|
||||
llarp_buffer_t strbuf;
|
||||
|
||||
if(llarp_buffer_eq(key, "I"))
|
||||
{
|
||||
uint64_t result;
|
||||
if(!bencode_read_integer(val, &result))
|
||||
return false;
|
||||
|
||||
iterative = result != 0;
|
||||
return true;
|
||||
}
|
||||
if(llarp_buffer_eq(key, "K"))
|
||||
{
|
||||
if(!bencode_read_string(val, &strbuf))
|
||||
return false;
|
||||
if(strbuf.sz != K.size())
|
||||
return false;
|
||||
|
||||
memcpy(K.data(), strbuf.base, K.size());
|
||||
return true;
|
||||
}
|
||||
if(llarp_buffer_eq(key, "T"))
|
||||
{
|
||||
return bencode_read_integer(val, &txid);
|
||||
}
|
||||
if(llarp_buffer_eq(key, "V"))
|
||||
{
|
||||
return bencode_read_integer(val, &version);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
FindRouterMessage::HandleMessage(llarp_dht_context *ctx,
|
||||
std::vector< IMessage * > &replies) const
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
if(!dht.allowTransit)
|
||||
{
|
||||
llarp::LogWarn("Got DHT lookup from ", From,
|
||||
" when we are not allowing dht transit");
|
||||
return false;
|
||||
}
|
||||
auto pending = dht.FindPendingTX(From, txid);
|
||||
if(pending)
|
||||
{
|
||||
llarp::LogWarn("Got duplicate DHT lookup from ", From, " txid=", txid);
|
||||
return false;
|
||||
}
|
||||
dht.LookupRouterRelayed(From, txid, K, !iterative, replies);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct MessageDecoder
|
||||
{
|
||||
const Key_t &From;
|
||||
bool firstKey = true;
|
||||
IMessage *msg = nullptr;
|
||||
bool relayed = false;
|
||||
|
||||
MessageDecoder(const Key_t &from) : From(from)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
on_key(dict_reader *r, llarp_buffer_t *key)
|
||||
{
|
||||
llarp_buffer_t strbuf;
|
||||
MessageDecoder *dec = static_cast< MessageDecoder * >(r->user);
|
||||
// check for empty dict
|
||||
if(!key)
|
||||
return !dec->firstKey;
|
||||
|
||||
// first key
|
||||
if(dec->firstKey)
|
||||
{
|
||||
if(!llarp_buffer_eq(*key, "A"))
|
||||
return false;
|
||||
if(!bencode_read_string(r->buffer, &strbuf))
|
||||
return false;
|
||||
// bad msg size?
|
||||
if(strbuf.sz != 1)
|
||||
return false;
|
||||
switch(*strbuf.base)
|
||||
{
|
||||
case 'R':
|
||||
if(dec->relayed)
|
||||
dec->msg = new RelayedFindRouterMessage(dec->From);
|
||||
else
|
||||
dec->msg = new FindRouterMessage(dec->From);
|
||||
break;
|
||||
case 'S':
|
||||
if(dec->relayed)
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"GotRouterMessage found when parsing relayed DHT "
|
||||
"message");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
dec->msg = new GotRouterMessage(dec->From);
|
||||
break;
|
||||
case 'I':
|
||||
dec->msg = new PublishIntroMessage();
|
||||
break;
|
||||
default:
|
||||
llarp::LogWarn("unknown dht message type: ", (char)*strbuf.base);
|
||||
// bad msg type
|
||||
return false;
|
||||
}
|
||||
dec->firstKey = false;
|
||||
return dec->msg != nullptr;
|
||||
}
|
||||
else
|
||||
return dec->msg->DecodeKey(*key, r->buffer);
|
||||
}
|
||||
};
|
||||
|
||||
IMessage *
|
||||
DecodeMesssage(const Key_t &from, llarp_buffer_t *buf, bool relayed)
|
||||
{
|
||||
MessageDecoder dec(from);
|
||||
dec.relayed = relayed;
|
||||
dict_reader r;
|
||||
r.user = &dec;
|
||||
r.on_key = &MessageDecoder::on_key;
|
||||
if(bencode_read_dict(buf, &r))
|
||||
return dec.msg;
|
||||
else
|
||||
{
|
||||
if(dec.msg)
|
||||
delete dec.msg;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
struct ListDecoder
|
||||
{
|
||||
ListDecoder(const Key_t &from, std::vector< IMessage * > &list)
|
||||
: From(from), l(list){};
|
||||
|
||||
bool relayed = false;
|
||||
const Key_t &From;
|
||||
std::vector< IMessage * > &l;
|
||||
|
||||
static bool
|
||||
on_item(list_reader *r, bool has)
|
||||
{
|
||||
ListDecoder *dec = static_cast< ListDecoder * >(r->user);
|
||||
if(!has)
|
||||
return true;
|
||||
auto msg = DecodeMesssage(dec->From, r->buffer, dec->relayed);
|
||||
if(msg)
|
||||
{
|
||||
dec->l.push_back(msg);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
DecodeMesssageList(const Key_t &from, llarp_buffer_t *buf,
|
||||
std::vector< IMessage * > &list, bool relayed)
|
||||
{
|
||||
ListDecoder dec(from, list);
|
||||
dec.relayed = relayed;
|
||||
list_reader r;
|
||||
r.user = &dec;
|
||||
r.on_item = &ListDecoder::on_item;
|
||||
return bencode_read_list(buf, &r);
|
||||
}
|
||||
|
||||
SearchJob::SearchJob()
|
||||
{
|
||||
started = 0;
|
||||
requester.Zero();
|
||||
target.Zero();
|
||||
}
|
||||
|
||||
SearchJob::SearchJob(const Key_t &asker, uint64_t tx, const Key_t &key,
|
||||
llarp_router_lookup_job *j,
|
||||
const std::set< Key_t > &excludes)
|
||||
: job(j)
|
||||
, started(llarp_time_now_ms())
|
||||
, requester(asker)
|
||||
, requesterTX(tx)
|
||||
, target(key)
|
||||
, exclude(excludes)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SearchJob::Completed(const llarp_rc *router, bool timeout) const
|
||||
{
|
||||
if(job && job->hook)
|
||||
{
|
||||
if(router)
|
||||
{
|
||||
job->found = true;
|
||||
llarp_rc_copy(&job->result, router);
|
||||
}
|
||||
job->hook(job);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SearchJob::IsExpired(llarp_time_t now) const
|
||||
{
|
||||
return now - started >= JobTimeout;
|
||||
}
|
||||
|
||||
Context::Context()
|
||||
{
|
||||
randombytes((byte_t *)&ids, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
if(nodes)
|
||||
delete nodes;
|
||||
if(services)
|
||||
delete services;
|
||||
}
|
||||
|
||||
void
|
||||
Context::handle_cleaner_timer(void *u, uint64_t orig, uint64_t left)
|
||||
{
|
||||
if(left)
|
||||
return;
|
||||
Context *ctx = static_cast< Context * >(u);
|
||||
|
||||
ctx->CleanupTX();
|
||||
ctx->ScheduleCleanupTimer();
|
||||
}
|
||||
|
||||
void
|
||||
Context::LookupRouterRelayed(const Key_t &requester, uint64_t txid,
|
||||
const Key_t &target, bool recursive,
|
||||
std::vector< IMessage * > &replies)
|
||||
{
|
||||
if(target == ourKey)
|
||||
{
|
||||
// we are the target, give them our RC
|
||||
replies.push_back(new GotRouterMessage(requester, txid, &router->rc));
|
||||
return;
|
||||
}
|
||||
Key_t next;
|
||||
std::set< Key_t > excluding = {requester, ourKey};
|
||||
if(nodes->FindCloseExcluding(target, next, excluding))
|
||||
{
|
||||
if(next == target)
|
||||
{
|
||||
// we know it
|
||||
replies.push_back(
|
||||
new GotRouterMessage(requester, txid, nodes->nodes[target].rc));
|
||||
}
|
||||
else if(recursive) // are we doing a recursive lookup?
|
||||
{
|
||||
if((requester ^ target) < (ourKey ^ target))
|
||||
{
|
||||
// we aren't closer to the target than next hop
|
||||
// so we won't ask neighboor recursively, tell them we don't have it
|
||||
llarp::LogInfo("we aren't closer to ", target, " than ", next,
|
||||
" so we end it here");
|
||||
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// yeah, ask neighboor recursively
|
||||
LookupRouter(target, requester, txid, next);
|
||||
}
|
||||
}
|
||||
else // otherwise tell them we don't have it
|
||||
{
|
||||
llarp::LogInfo("we don't have ", target,
|
||||
" and this was an iterative request so telling ",
|
||||
requester, " that we don't have it");
|
||||
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't know it and have no closer peers
|
||||
llarp::LogInfo("we don't have ", target,
|
||||
" and have no closer peers so telling ", requester,
|
||||
" that we don't have it");
|
||||
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Context::RemovePendingLookup(const Key_t &owner, uint64_t id)
|
||||
{
|
||||
TXOwner search;
|
||||
search.node = owner;
|
||||
search.txid = id;
|
||||
auto itr = pendingTX.find(search);
|
||||
if(itr == pendingTX.end())
|
||||
return;
|
||||
pendingTX.erase(itr);
|
||||
}
|
||||
|
||||
SearchJob *
|
||||
Context::FindPendingTX(const Key_t &owner, uint64_t id)
|
||||
{
|
||||
TXOwner search;
|
||||
search.node = owner;
|
||||
search.txid = id;
|
||||
auto itr = pendingTX.find(search);
|
||||
if(itr == pendingTX.end())
|
||||
return nullptr;
|
||||
else
|
||||
return &itr->second;
|
||||
}
|
||||
|
||||
void
|
||||
Context::CleanupTX()
|
||||
{
|
||||
auto now = llarp_time_now_ms();
|
||||
llarp::LogDebug("DHT tick");
|
||||
|
||||
auto itr = pendingTX.begin();
|
||||
while(itr != pendingTX.end())
|
||||
{
|
||||
if(itr->second.IsExpired(now))
|
||||
{
|
||||
itr->second.Completed(nullptr, true);
|
||||
itr = pendingTX.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Context::Init(const Key_t &us, llarp_router *r)
|
||||
{
|
||||
router = r;
|
||||
ourKey = us;
|
||||
nodes = new Bucket< RCNode >(ourKey);
|
||||
services = new Bucket< ISNode >(ourKey);
|
||||
llarp::LogDebug("intialize dht with key ", ourKey);
|
||||
}
|
||||
|
||||
void
|
||||
Context::ScheduleCleanupTimer()
|
||||
{
|
||||
llarp_logic_call_later(router->logic,
|
||||
{1000, this, &handle_cleaner_timer});
|
||||
}
|
||||
|
||||
bool
|
||||
Context::RelayRequestForPath(const llarp::PathID_t &id, const IMessage *msg)
|
||||
{
|
||||
llarp::routing::DHTMessage reply;
|
||||
if(!msg->HandleMessage(router->dht, reply.M))
|
||||
return false;
|
||||
auto path = router->paths.GetByUpstream(router->pubkey(), id);
|
||||
return path && path->SendRoutingMessage(&reply, router);
|
||||
}
|
||||
|
||||
void
|
||||
Context::LookupRouter(const Key_t &target, const Key_t &whoasked,
|
||||
uint64_t txid, const Key_t &askpeer,
|
||||
llarp_router_lookup_job *job, bool iterative,
|
||||
std::set< Key_t > excludes)
|
||||
{
|
||||
if(target.IsZero() || whoasked.IsZero() || askpeer.IsZero())
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto id = ++ids;
|
||||
TXOwner ownerKey;
|
||||
ownerKey.node = askpeer;
|
||||
ownerKey.txid = id;
|
||||
if(txid == 0)
|
||||
txid = id;
|
||||
|
||||
pendingTX[ownerKey] = SearchJob(whoasked, txid, target, job, excludes);
|
||||
|
||||
llarp::LogInfo("Asking ", askpeer, " for router ", target, " for ",
|
||||
whoasked);
|
||||
auto msg = new llarp::DHTImmeidateMessage(askpeer);
|
||||
auto dhtmsg = new FindRouterMessage(askpeer, target, id);
|
||||
dhtmsg->iterative = iterative;
|
||||
msg->msgs.push_back(dhtmsg);
|
||||
router->SendToOrQueue(askpeer, msg);
|
||||
}
|
||||
|
||||
void
|
||||
Context::LookupRouterViaJob(llarp_router_lookup_job *job)
|
||||
{
|
||||
Key_t peer;
|
||||
if(nodes->FindClosest(job->target, peer))
|
||||
LookupRouter(job->target, ourKey, 0, peer, job);
|
||||
else if(job->hook)
|
||||
{
|
||||
job->found = false;
|
||||
job->hook(job);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Context::queue_router_lookup(void *user)
|
||||
{
|
||||
llarp_router_lookup_job *job =
|
||||
static_cast< llarp_router_lookup_job * >(user);
|
||||
job->dht->impl.LookupRouterViaJob(job);
|
||||
}
|
||||
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
||||
llarp_dht_context::llarp_dht_context(llarp_router *router)
|
||||
{
|
||||
parent = router;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
struct llarp_dht_context *
|
||||
llarp_dht_context_new(struct llarp_router *router)
|
||||
{
|
||||
struct llarp_dht_context *
|
||||
llarp_dht_context_new(struct llarp_router *router)
|
||||
{
|
||||
return new llarp_dht_context(router);
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_context_free(struct llarp_dht_context *ctx)
|
||||
{
|
||||
delete ctx;
|
||||
}
|
||||
return new llarp_dht_context(router);
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_put_peer(struct llarp_dht_context *ctx, struct llarp_rc *rc)
|
||||
void
|
||||
llarp_dht_context_free(struct llarp_dht_context *ctx)
|
||||
{
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
{
|
||||
llarp::dht::RCNode n(rc);
|
||||
ctx->impl.nodes->PutNode(n);
|
||||
}
|
||||
void
|
||||
llarp_dht_put_peer(struct llarp_dht_context *ctx, struct llarp_rc *rc)
|
||||
|
||||
void
|
||||
llarp_dht_remove_peer(struct llarp_dht_context *ctx, const byte_t *id)
|
||||
{
|
||||
llarp::dht::Key_t k = id;
|
||||
ctx->impl.nodes->DelNode(k);
|
||||
}
|
||||
{
|
||||
llarp::dht::RCNode n(rc);
|
||||
ctx->impl.nodes->PutNode(n);
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_set_msg_handler(struct llarp_dht_context *ctx,
|
||||
llarp_dht_msg_handler handler)
|
||||
{
|
||||
ctx->impl.custom_handler = handler;
|
||||
}
|
||||
void
|
||||
llarp_dht_remove_peer(struct llarp_dht_context *ctx, const byte_t *id)
|
||||
{
|
||||
llarp::dht::Key_t k = id;
|
||||
ctx->impl.nodes->DelNode(k);
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_allow_transit(llarp_dht_context *ctx)
|
||||
{
|
||||
ctx->impl.allowTransit = true;
|
||||
}
|
||||
void
|
||||
llarp_dht_allow_transit(llarp_dht_context *ctx)
|
||||
{
|
||||
ctx->impl.allowTransit = true;
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_context_start(struct llarp_dht_context *ctx, const byte_t *key)
|
||||
{
|
||||
ctx->impl.Init(key, ctx->parent);
|
||||
}
|
||||
void
|
||||
llarp_dht_context_start(struct llarp_dht_context *ctx, const byte_t *key)
|
||||
{
|
||||
ctx->impl.Init(key, ctx->parent);
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_lookup_router(struct llarp_dht_context *ctx,
|
||||
struct llarp_router_lookup_job *job)
|
||||
{
|
||||
job->dht = ctx;
|
||||
job->found = false;
|
||||
llarp_logic_queue_job(ctx->parent->logic,
|
||||
{job, &llarp::dht::Context::queue_router_lookup});
|
||||
}
|
||||
void
|
||||
llarp_dht_lookup_router(struct llarp_dht_context *ctx,
|
||||
struct llarp_router_lookup_job *job)
|
||||
{
|
||||
job->dht = ctx;
|
||||
job->found = false;
|
||||
llarp_logic_queue_job(ctx->parent->logic,
|
||||
{job, &llarp::dht::Context::queue_router_lookup});
|
||||
}
|
||||
|
@ -0,0 +1,210 @@
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include <llarp/dht/messages/gotrouter.hpp>
|
||||
#include <llarp/messages/dht.hpp>
|
||||
#include <llarp/messages/dht_immediate.hpp>
|
||||
#include "router.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
Context::Context()
|
||||
{
|
||||
randombytes((byte_t *)&ids, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
if(nodes)
|
||||
delete nodes;
|
||||
if(services)
|
||||
delete services;
|
||||
}
|
||||
|
||||
void
|
||||
Context::handle_cleaner_timer(void *u, uint64_t orig, uint64_t left)
|
||||
{
|
||||
if(left)
|
||||
return;
|
||||
Context *ctx = static_cast< Context * >(u);
|
||||
|
||||
ctx->CleanupTX();
|
||||
ctx->ScheduleCleanupTimer();
|
||||
}
|
||||
|
||||
void
|
||||
Context::LookupRouterRelayed(const Key_t &requester, uint64_t txid,
|
||||
const Key_t &target, bool recursive,
|
||||
std::vector< IMessage * > &replies)
|
||||
{
|
||||
if(target == ourKey)
|
||||
{
|
||||
// we are the target, give them our RC
|
||||
replies.push_back(new GotRouterMessage(requester, txid, &router->rc));
|
||||
return;
|
||||
}
|
||||
Key_t next;
|
||||
std::set< Key_t > excluding = {requester, ourKey};
|
||||
if(nodes->FindCloseExcluding(target, next, excluding))
|
||||
{
|
||||
if(next == target)
|
||||
{
|
||||
// we know it
|
||||
replies.push_back(
|
||||
new GotRouterMessage(requester, txid, nodes->nodes[target].rc));
|
||||
}
|
||||
else if(recursive) // are we doing a recursive lookup?
|
||||
{
|
||||
if((requester ^ target) < (ourKey ^ target))
|
||||
{
|
||||
// we aren't closer to the target than next hop
|
||||
// so we won't ask neighboor recursively, tell them we don't have it
|
||||
llarp::LogInfo("we aren't closer to ", target, " than ", next,
|
||||
" so we end it here");
|
||||
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// yeah, ask neighboor recursively
|
||||
LookupRouter(target, requester, txid, next);
|
||||
}
|
||||
}
|
||||
else // otherwise tell them we don't have it
|
||||
{
|
||||
llarp::LogInfo("we don't have ", target,
|
||||
" and this was an iterative request so telling ",
|
||||
requester, " that we don't have it");
|
||||
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't know it and have no closer peers
|
||||
llarp::LogInfo("we don't have ", target,
|
||||
" and have no closer peers so telling ", requester,
|
||||
" that we don't have it");
|
||||
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Context::RemovePendingLookup(const Key_t &owner, uint64_t id)
|
||||
{
|
||||
TXOwner search;
|
||||
search.node = owner;
|
||||
search.txid = id;
|
||||
auto itr = pendingTX.find(search);
|
||||
if(itr == pendingTX.end())
|
||||
return;
|
||||
pendingTX.erase(itr);
|
||||
}
|
||||
|
||||
SearchJob *
|
||||
Context::FindPendingTX(const Key_t &owner, uint64_t id)
|
||||
{
|
||||
TXOwner search;
|
||||
search.node = owner;
|
||||
search.txid = id;
|
||||
auto itr = pendingTX.find(search);
|
||||
if(itr == pendingTX.end())
|
||||
return nullptr;
|
||||
else
|
||||
return &itr->second;
|
||||
}
|
||||
|
||||
void
|
||||
Context::CleanupTX()
|
||||
{
|
||||
auto now = llarp_time_now_ms();
|
||||
llarp::LogDebug("DHT tick");
|
||||
|
||||
auto itr = pendingTX.begin();
|
||||
while(itr != pendingTX.end())
|
||||
{
|
||||
if(itr->second.IsExpired(now))
|
||||
{
|
||||
itr->second.Timeout();
|
||||
itr = pendingTX.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Context::Init(const Key_t &us, llarp_router *r)
|
||||
{
|
||||
router = r;
|
||||
ourKey = us;
|
||||
nodes = new Bucket< RCNode >(ourKey);
|
||||
services = new Bucket< ISNode >(ourKey);
|
||||
llarp::LogDebug("intialize dht with key ", ourKey);
|
||||
}
|
||||
|
||||
void
|
||||
Context::ScheduleCleanupTimer()
|
||||
{
|
||||
llarp_logic_call_later(router->logic,
|
||||
{1000, this, &handle_cleaner_timer});
|
||||
}
|
||||
|
||||
bool
|
||||
Context::RelayRequestForPath(const llarp::PathID_t &id, const IMessage *msg)
|
||||
{
|
||||
llarp::routing::DHTMessage reply;
|
||||
if(!msg->HandleMessage(router->dht, reply.M))
|
||||
return false;
|
||||
auto path = router->paths.GetByUpstream(router->pubkey(), id);
|
||||
return path && path->SendRoutingMessage(&reply, router);
|
||||
}
|
||||
|
||||
void
|
||||
Context::LookupRouter(const Key_t &target, const Key_t &whoasked,
|
||||
uint64_t txid, const Key_t &askpeer,
|
||||
llarp_router_lookup_job *job, bool iterative,
|
||||
std::set< Key_t > excludes)
|
||||
{
|
||||
if(target.IsZero() || whoasked.IsZero() || askpeer.IsZero())
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto id = ++ids;
|
||||
TXOwner ownerKey;
|
||||
ownerKey.node = askpeer;
|
||||
ownerKey.txid = id;
|
||||
if(txid == 0)
|
||||
txid = id;
|
||||
SearchJob j(whoasked, txid, target, excludes, job);
|
||||
pendingTX[ownerKey] = j;
|
||||
llarp::LogInfo("Asking ", askpeer, " for router ", target, " for ",
|
||||
whoasked);
|
||||
auto msg = new llarp::DHTImmeidateMessage(askpeer);
|
||||
auto dhtmsg = new FindRouterMessage(askpeer, target, id);
|
||||
dhtmsg->iterative = iterative;
|
||||
msg->msgs.push_back(dhtmsg);
|
||||
router->SendToOrQueue(askpeer, msg);
|
||||
}
|
||||
|
||||
void
|
||||
Context::LookupRouterViaJob(llarp_router_lookup_job *job)
|
||||
{
|
||||
Key_t peer;
|
||||
if(nodes->FindClosest(job->target, peer))
|
||||
LookupRouter(job->target, ourKey, 0, peer, job);
|
||||
else if(job->hook)
|
||||
{
|
||||
job->found = false;
|
||||
job->hook(job);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Context::queue_router_lookup(void *user)
|
||||
{
|
||||
llarp_router_lookup_job *job =
|
||||
static_cast< llarp_router_lookup_job * >(user);
|
||||
job->dht->impl.LookupRouterViaJob(job);
|
||||
}
|
||||
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -0,0 +1,142 @@
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include <llarp/dht/messages/all.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct MessageDecoder
|
||||
{
|
||||
const Key_t &From;
|
||||
bool firstKey = true;
|
||||
IMessage *msg = nullptr;
|
||||
bool relayed = false;
|
||||
|
||||
MessageDecoder(const Key_t &from) : From(from)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
on_key(dict_reader *r, llarp_buffer_t *key)
|
||||
{
|
||||
llarp_buffer_t strbuf;
|
||||
MessageDecoder *dec = static_cast< MessageDecoder * >(r->user);
|
||||
// check for empty dict
|
||||
if(!key)
|
||||
return !dec->firstKey;
|
||||
|
||||
// first key
|
||||
if(dec->firstKey)
|
||||
{
|
||||
if(!llarp_buffer_eq(*key, "A"))
|
||||
return false;
|
||||
if(!bencode_read_string(r->buffer, &strbuf))
|
||||
return false;
|
||||
// bad msg size?
|
||||
if(strbuf.sz != 1)
|
||||
return false;
|
||||
switch(*strbuf.base)
|
||||
{
|
||||
case 'R':
|
||||
if(dec->relayed)
|
||||
dec->msg = new RelayedFindRouterMessage(dec->From);
|
||||
else
|
||||
dec->msg = new FindRouterMessage(dec->From);
|
||||
break;
|
||||
case 'S':
|
||||
if(dec->relayed)
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"GotRouterMessage found when parsing relayed DHT "
|
||||
"message");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
dec->msg = new GotRouterMessage(dec->From);
|
||||
break;
|
||||
case 'I':
|
||||
dec->msg = new PublishIntroMessage();
|
||||
break;
|
||||
case 'G':
|
||||
if(dec->relayed)
|
||||
{
|
||||
dec->msg = new RelayedGotIntroMessage();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
dec->msg = new GotIntroMessage(dec->From);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llarp::LogWarn("unknown dht message type: ", (char)*strbuf.base);
|
||||
// bad msg type
|
||||
return false;
|
||||
}
|
||||
dec->firstKey = false;
|
||||
return dec->msg != nullptr;
|
||||
}
|
||||
else
|
||||
return dec->msg->DecodeKey(*key, r->buffer);
|
||||
}
|
||||
};
|
||||
|
||||
IMessage *
|
||||
DecodeMesssage(const Key_t &from, llarp_buffer_t *buf, bool relayed)
|
||||
{
|
||||
MessageDecoder dec(from);
|
||||
dec.relayed = relayed;
|
||||
dict_reader r;
|
||||
r.user = &dec;
|
||||
r.on_key = &MessageDecoder::on_key;
|
||||
if(bencode_read_dict(buf, &r))
|
||||
{
|
||||
return dec.msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dec.msg)
|
||||
delete dec.msg;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
struct ListDecoder
|
||||
{
|
||||
ListDecoder(const Key_t &from, std::vector< IMessage * > &list)
|
||||
: From(from), l(list){};
|
||||
|
||||
bool relayed = false;
|
||||
const Key_t &From;
|
||||
std::vector< IMessage * > &l;
|
||||
|
||||
static bool
|
||||
on_item(list_reader *r, bool has)
|
||||
{
|
||||
ListDecoder *dec = static_cast< ListDecoder * >(r->user);
|
||||
if(!has)
|
||||
return true;
|
||||
auto msg = DecodeMesssage(dec->From, r->buffer, dec->relayed);
|
||||
if(msg)
|
||||
{
|
||||
dec->l.push_back(msg);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
DecodeMesssageList(const Key_t &from, llarp_buffer_t *buf,
|
||||
std::vector< IMessage * > &list, bool relayed)
|
||||
{
|
||||
ListDecoder dec(from, list);
|
||||
dec.relayed = relayed;
|
||||
list_reader r;
|
||||
r.user = &dec;
|
||||
r.on_item = &ListDecoder::on_item;
|
||||
return bencode_read_list(buf, &r);
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -0,0 +1,81 @@
|
||||
#include <llarp/messages/dht_immediate.hpp>
|
||||
#include "router.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
DHTImmeidateMessage::~DHTImmeidateMessage()
|
||||
{
|
||||
for(auto &msg : msgs)
|
||||
delete msg;
|
||||
msgs.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "m"))
|
||||
return llarp::dht::DecodeMesssageList(remote.data(), buf, msgs);
|
||||
if(llarp_buffer_eq(key, "v"))
|
||||
{
|
||||
if(!bencode_read_integer(buf, &version))
|
||||
return false;
|
||||
return version == LLARP_PROTO_VERSION;
|
||||
}
|
||||
// bad key
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message type
|
||||
if(!bencode_write_bytestring(buf, "a", 1))
|
||||
return false;
|
||||
if(!bencode_write_bytestring(buf, "m", 1))
|
||||
return false;
|
||||
|
||||
// dht messages
|
||||
if(!bencode_write_bytestring(buf, "m", 1))
|
||||
return false;
|
||||
// begin list
|
||||
if(!bencode_start_list(buf))
|
||||
return false;
|
||||
for(const auto &msg : msgs)
|
||||
{
|
||||
if(!msg->BEncode(buf))
|
||||
return false;
|
||||
}
|
||||
// end list
|
||||
if(!bencode_end(buf))
|
||||
return false;
|
||||
|
||||
// protocol version
|
||||
if(!bencode_write_version_entry(buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::HandleMessage(llarp_router *router) const
|
||||
{
|
||||
DHTImmeidateMessage *reply = new DHTImmeidateMessage(remote);
|
||||
bool result = true;
|
||||
for(auto &msg : msgs)
|
||||
{
|
||||
result &= msg->HandleMessage(router->dht, reply->msgs);
|
||||
}
|
||||
if(reply->msgs.size())
|
||||
{
|
||||
return result && router->SendToOrQueue(remote.data(), reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete reply;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
#include <llarp/dht/messages/findintro.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
FindIntroMessage::~FindIntroMessage()
|
||||
{
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue