mirror of https://github.com/oxen-io/lokinet
Merge branch 'staging' of ssh://github.com/loki-project/loki-network into staging
commit
cbfbdc506d
@ -1,135 +0,0 @@
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/all.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct MessageDecoder
|
||||
{
|
||||
const Key_t &From;
|
||||
std::unique_ptr< IMessage > msg;
|
||||
bool firstKey = true;
|
||||
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;
|
||||
llarp::LogInfo("Handle DHT message ", *strbuf.base,
|
||||
" relayed=", dec->relayed);
|
||||
switch(*strbuf.base)
|
||||
{
|
||||
case 'F':
|
||||
dec->msg.reset(new FindIntroMessage(dec->From, dec->relayed));
|
||||
break;
|
||||
case 'R':
|
||||
if(dec->relayed)
|
||||
dec->msg.reset(new RelayedFindRouterMessage(dec->From));
|
||||
else
|
||||
dec->msg.reset(new FindRouterMessage(dec->From));
|
||||
break;
|
||||
case 'S':
|
||||
dec->msg.reset(new GotRouterMessage(dec->From, dec->relayed));
|
||||
break;
|
||||
case 'I':
|
||||
dec->msg.reset(new PublishIntroMessage());
|
||||
break;
|
||||
case 'G':
|
||||
if(dec->relayed)
|
||||
{
|
||||
dec->msg.reset(new RelayedGotIntroMessage());
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
dec->msg.reset(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);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr< 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 nullptr;
|
||||
|
||||
return std::unique_ptr< IMessage >(std::move(dec.msg));
|
||||
}
|
||||
|
||||
struct ListDecoder
|
||||
{
|
||||
ListDecoder(const Key_t &from,
|
||||
std::vector< std::unique_ptr< IMessage > > &list)
|
||||
: From(from), l(list){};
|
||||
|
||||
bool relayed = false;
|
||||
const Key_t &From;
|
||||
std::vector< std::unique_ptr< 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.emplace_back(std::move(msg));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
DecodeMesssageList(Key_t from, llarp_buffer_t *buf,
|
||||
std::vector< std::unique_ptr< 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
|
@ -1,86 +0,0 @@
|
||||
#include <messages/dht_immediate.hpp>
|
||||
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
DHTImmeidateMessage::~DHTImmeidateMessage()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DHTImmeidateMessage::Clear()
|
||||
{
|
||||
msgs.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "m"))
|
||||
return llarp::dht::DecodeMesssageList(dht::Key_t(session->GetPubKey()),
|
||||
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;
|
||||
reply.session = session;
|
||||
bool result = true;
|
||||
for(auto &msg : msgs)
|
||||
{
|
||||
result &= msg->HandleMessage(router->dht, reply.msgs);
|
||||
}
|
||||
if(reply.msgs.size())
|
||||
{
|
||||
if(result)
|
||||
{
|
||||
result = router->SendToOrQueue(session->GetPubKey(), &reply);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace llarp
|
@ -1,217 +0,0 @@
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/findintro.hpp>
|
||||
#include <dht/messages/gotintro.hpp>
|
||||
#include <routing/message.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
/*
|
||||
struct IntroSetLookupInformer
|
||||
{
|
||||
llarp::Router* router;
|
||||
service::Address target;
|
||||
|
||||
void
|
||||
SendReply(const llarp::routing::IMessage* msg)
|
||||
{
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
FindIntroMessage::~FindIntroMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
FindIntroMessage::DecodeKey(llarp_buffer_t k, llarp_buffer_t* val)
|
||||
{
|
||||
bool read = false;
|
||||
|
||||
if(!BEncodeMaybeReadDictEntry("N", N, read, k, val))
|
||||
return false;
|
||||
|
||||
if(!BEncodeMaybeReadDictInt("R", R, read, k, val))
|
||||
return false;
|
||||
|
||||
if(!BEncodeMaybeReadDictEntry("S", S, read, k, val))
|
||||
return false;
|
||||
|
||||
if(!BEncodeMaybeReadDictInt("T", T, read, k, val))
|
||||
return false;
|
||||
|
||||
if(!BEncodeMaybeReadVersion("V", version, LLARP_PROTO_VERSION, read, k,
|
||||
val))
|
||||
return false;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
FindIntroMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message id
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "F"))
|
||||
return false;
|
||||
if(N.Empty())
|
||||
{
|
||||
// recursion
|
||||
if(!BEncodeWriteDictInt("R", R, buf))
|
||||
return false;
|
||||
// service address
|
||||
if(!BEncodeWriteDictEntry("S", S, buf))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!BEncodeWriteDictEntry("N", N, buf))
|
||||
return false;
|
||||
// recursion
|
||||
if(!BEncodeWriteDictInt("R", R, buf))
|
||||
return false;
|
||||
}
|
||||
// txid
|
||||
if(!BEncodeWriteDictInt("T", T, buf))
|
||||
return false;
|
||||
// protocol version
|
||||
if(!BEncodeWriteDictInt("V", LLARP_PROTO_VERSION, buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
FindIntroMessage::HandleMessage(
|
||||
llarp_dht_context* ctx,
|
||||
std::vector< std::unique_ptr< IMessage > >& replies) const
|
||||
{
|
||||
if(R > 5)
|
||||
{
|
||||
llarp::LogError("R value too big, ", R, "> 5");
|
||||
return false;
|
||||
}
|
||||
auto& dht = ctx->impl;
|
||||
if(dht.pendingIntrosetLookups.HasPendingLookupFrom(TXOwner{From, T}))
|
||||
{
|
||||
llarp::LogWarn("duplicate FIM from ", From, " txid=", T);
|
||||
return false;
|
||||
}
|
||||
Key_t peer;
|
||||
std::set< Key_t > exclude = {dht.OurKey(), From};
|
||||
if(N.Empty())
|
||||
{
|
||||
llarp::LogInfo("lookup ", S.ToString());
|
||||
const auto introset = dht.GetIntroSetByServiceAddress(S);
|
||||
if(introset)
|
||||
{
|
||||
service::IntroSet i = *introset;
|
||||
replies.emplace_back(new GotIntroMessage({i}, T));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(R == 0)
|
||||
{
|
||||
// we don't have it
|
||||
Key_t target = S.ToKey();
|
||||
Key_t closer;
|
||||
// find closer peer
|
||||
if(!dht.nodes->FindClosest(target, closer))
|
||||
return false;
|
||||
if(relayed)
|
||||
dht.LookupIntroSetForPath(S, T, pathID, closer);
|
||||
else
|
||||
replies.emplace_back(new GotIntroMessage(From, closer, T));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_t us = dht.OurKey();
|
||||
Key_t target = S.ToKey();
|
||||
// we are recursive
|
||||
if(dht.nodes->FindCloseExcluding(target, peer, exclude))
|
||||
{
|
||||
if(relayed)
|
||||
dht.LookupIntroSetForPath(S, T, pathID, peer);
|
||||
else
|
||||
{
|
||||
if((us ^ target) < (peer ^ target))
|
||||
{
|
||||
// we are not closer than our peer to the target so don't
|
||||
// recurse farther
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
return true;
|
||||
}
|
||||
else if(R > 0)
|
||||
dht.LookupIntroSetRecursive(S, From, T, peer, R - 1);
|
||||
else
|
||||
dht.LookupIntroSetIterative(S, From, T, peer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no more closer peers
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(relayed)
|
||||
{
|
||||
// tag lookup
|
||||
if(dht.nodes->GetRandomNodeExcluding(peer, exclude))
|
||||
{
|
||||
dht.LookupTagForPath(N, T, pathID, peer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no more closer peers
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(R == 0)
|
||||
{
|
||||
// base case
|
||||
auto introsets = dht.FindRandomIntroSetsWithTagExcluding(N, 2, {});
|
||||
std::vector< service::IntroSet > reply;
|
||||
for(const auto& introset : introsets)
|
||||
{
|
||||
reply.push_back(introset);
|
||||
}
|
||||
replies.emplace_back(new GotIntroMessage(reply, T));
|
||||
return true;
|
||||
}
|
||||
else if(R < 5)
|
||||
{
|
||||
// tag lookup
|
||||
if(dht.nodes->GetRandomNodeExcluding(peer, exclude))
|
||||
{
|
||||
dht.LookupTagRecursive(N, From, T, peer, R - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// too big R value
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,172 +0,0 @@
|
||||
#include <dht/messages/findrouter.hpp>
|
||||
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/gotrouter.hpp>
|
||||
#include <messages/dht.hpp>
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
bool
|
||||
RelayedFindRouterMessage::HandleMessage(
|
||||
llarp_dht_context *ctx,
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
/// lookup for us, send an immeidate reply
|
||||
Key_t us = dht.OurKey();
|
||||
Key_t k{K};
|
||||
if(K == us)
|
||||
{
|
||||
auto path = dht.router->paths.GetByUpstream(K, pathID);
|
||||
if(path)
|
||||
{
|
||||
replies.emplace_back(
|
||||
new GotRouterMessage(k, txid, {dht.router->rc()}, false));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Key_t peer;
|
||||
// check if we know this in our nodedb first
|
||||
RouterContact found;
|
||||
if(dht.router->nodedb->Get(K, found))
|
||||
{
|
||||
replies.emplace_back(new GotRouterMessage(k, txid, {found}, false));
|
||||
return true;
|
||||
}
|
||||
// lookup if we don't have it in our nodedb
|
||||
if(dht.nodes->FindClosest(k, peer))
|
||||
dht.LookupRouterForPath(K, txid, pathID, peer);
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// exploritory or not?
|
||||
if(!bencode_write_bytestring(buf, "E", 1))
|
||||
return false;
|
||||
if(!bencode_write_uint64(buf, exploritory ? 1 : 0))
|
||||
return false;
|
||||
|
||||
// iterative or not?
|
||||
if(!bencode_write_bytestring(buf, "I", 1))
|
||||
return false;
|
||||
if(!bencode_write_uint64(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, "E"))
|
||||
{
|
||||
uint64_t result;
|
||||
if(!bencode_read_integer(val, &result))
|
||||
return false;
|
||||
|
||||
exploritory = result != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
std::copy(strbuf.base, strbuf.base + K.SIZE, K.begin());
|
||||
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< std::unique_ptr< 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;
|
||||
}
|
||||
if(dht.pendingRouterLookups.HasPendingLookupFrom({From, txid}))
|
||||
{
|
||||
llarp::LogWarn("Duplicate FRM from ", From, " txid=", txid);
|
||||
return false;
|
||||
}
|
||||
RouterContact found;
|
||||
Key_t k{K};
|
||||
if(exploritory)
|
||||
return dht.HandleExploritoryRouterLookup(From, txid, K, replies);
|
||||
else if(dht.router->nodedb->Get(K, found))
|
||||
{
|
||||
replies.emplace_back(new GotRouterMessage(k, txid, {found}, false));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
dht.LookupRouterRelayed(From, txid, k, !iterative, replies);
|
||||
return true;
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,124 +0,0 @@
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/gotintro.hpp>
|
||||
#include <messages/dht.hpp>
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
GotIntroMessage::GotIntroMessage(
|
||||
const std::vector< llarp::service::IntroSet > &results, uint64_t tx)
|
||||
: IMessage({}), I(results), T(tx)
|
||||
{
|
||||
}
|
||||
|
||||
GotIntroMessage::~GotIntroMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
GotIntroMessage::HandleMessage(
|
||||
llarp_dht_context *ctx,
|
||||
__attribute__((unused))
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
auto crypto = &dht.router->crypto;
|
||||
|
||||
for(const auto &introset : I)
|
||||
{
|
||||
if(!introset.Verify(crypto, dht.Now()))
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"Invalid introset while handling direct GotIntro "
|
||||
"from ",
|
||||
From);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TXOwner owner(From, T);
|
||||
auto tagLookup = dht.pendingTagLookups.GetPendingLookupFrom(owner);
|
||||
if(tagLookup)
|
||||
{
|
||||
dht.pendingTagLookups.Found(owner, tagLookup->target, I);
|
||||
return true;
|
||||
}
|
||||
auto serviceLookup =
|
||||
dht.pendingIntrosetLookups.GetPendingLookupFrom(owner);
|
||||
if(serviceLookup)
|
||||
{
|
||||
if(I.size())
|
||||
{
|
||||
dht.pendingIntrosetLookups.Found(owner, serviceLookup->target, I);
|
||||
}
|
||||
else
|
||||
{
|
||||
dht.pendingIntrosetLookups.NotFound(owner, K);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
llarp::LogError("no pending TX for GIM from ", From, " txid=", T);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RelayedGotIntroMessage::HandleMessage(
|
||||
llarp_dht_context *ctx,
|
||||
__attribute__((unused))
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
// TODO: implement me better?
|
||||
auto pathset = ctx->impl.router->paths.GetLocalPathSet(pathID);
|
||||
if(pathset)
|
||||
{
|
||||
return pathset->HandleGotIntroMessage(this);
|
||||
}
|
||||
llarp::LogWarn("No path for got intro message pathid=", pathID);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GotIntroMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "I"))
|
||||
{
|
||||
return BEncodeReadList(I, buf);
|
||||
}
|
||||
if(llarp_buffer_eq(key, "K"))
|
||||
{
|
||||
if(K) // duplicate key?
|
||||
return false;
|
||||
K.reset(new dht::Key_t());
|
||||
return K->BDecode(buf);
|
||||
}
|
||||
bool read = false;
|
||||
if(!BEncodeMaybeReadDictInt("T", T, read, key, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("V", version, read, key, buf))
|
||||
return false;
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
GotIntroMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "G"))
|
||||
return false;
|
||||
if(!BEncodeWriteDictList("I", I, buf))
|
||||
return false;
|
||||
if(K)
|
||||
{
|
||||
if(!BEncodeWriteDictEntry("K", *K.get(), buf))
|
||||
return false;
|
||||
}
|
||||
if(!BEncodeWriteDictInt("T", T, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("V", version, buf))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,123 +0,0 @@
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/gotrouter.hpp>
|
||||
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
GotRouterMessage::~GotRouterMessage()
|
||||
{
|
||||
}
|
||||
|
||||
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(K)
|
||||
{
|
||||
if(!BEncodeWriteDictEntry("K", *K.get(), buf))
|
||||
return false;
|
||||
}
|
||||
|
||||
// near
|
||||
if(N.size())
|
||||
{
|
||||
if(!BEncodeWriteDictList("N", N, buf))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!BEncodeWriteDictList("R", R, buf))
|
||||
return false;
|
||||
|
||||
// txid
|
||||
if(!BEncodeWriteDictInt("T", txid, buf))
|
||||
return false;
|
||||
|
||||
// version
|
||||
if(!BEncodeWriteDictInt("V", version, buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "K"))
|
||||
{
|
||||
if(K) // duplicate key?
|
||||
return false;
|
||||
K.reset(new dht::Key_t());
|
||||
return K->BDecode(val);
|
||||
}
|
||||
if(llarp_buffer_eq(key, "N"))
|
||||
{
|
||||
return BEncodeReadList(N, 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,
|
||||
__attribute__((unused))
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
if(relayed)
|
||||
{
|
||||
auto pathset = ctx->impl.router->paths.GetLocalPathSet(pathID);
|
||||
return pathset && pathset->HandleGotRouterMessage(this);
|
||||
}
|
||||
// not relayed
|
||||
TXOwner owner(From, txid);
|
||||
|
||||
if(dht.pendingExploreLookups.HasPendingLookupFrom(owner))
|
||||
{
|
||||
if(N.size() == 0)
|
||||
dht.pendingExploreLookups.NotFound(owner, K);
|
||||
else
|
||||
{
|
||||
dht.pendingExploreLookups.Found(owner, From.as_array(), N);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// not explore lookup
|
||||
|
||||
if(!dht.pendingRouterLookups.HasPendingLookupFrom(owner))
|
||||
{
|
||||
llarp::LogWarn("Unwarrented GRM from ", From, " txid=", txid);
|
||||
return false;
|
||||
}
|
||||
// no pending lookup
|
||||
|
||||
llarp::LogInfo("DHT no pending lookup");
|
||||
if(R.size() == 1)
|
||||
dht.pendingRouterLookups.Found(owner, R[0].pubkey, {R[0]});
|
||||
else
|
||||
dht.pendingRouterLookups.NotFound(owner, K);
|
||||
return true;
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1 +1,140 @@
|
||||
#include <dht/message.hpp>
|
||||
#include <dht/context.hpp>
|
||||
|
||||
#include <dht/messages/findintro.hpp>
|
||||
#include <dht/messages/findrouter.hpp>
|
||||
#include <dht/messages/gotintro.hpp>
|
||||
#include <dht/messages/gotrouter.hpp>
|
||||
#include <dht/messages/pubintro.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct MessageDecoder
|
||||
{
|
||||
const Key_t &From;
|
||||
std::unique_ptr< IMessage > msg;
|
||||
bool firstKey = true;
|
||||
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;
|
||||
llarp::LogInfo("Handle DHT message ", *strbuf.base,
|
||||
" relayed=", dec->relayed);
|
||||
switch(*strbuf.base)
|
||||
{
|
||||
case 'F':
|
||||
dec->msg.reset(new FindIntroMessage(dec->From, dec->relayed));
|
||||
break;
|
||||
case 'R':
|
||||
if(dec->relayed)
|
||||
dec->msg.reset(new RelayedFindRouterMessage(dec->From));
|
||||
else
|
||||
dec->msg.reset(new FindRouterMessage(dec->From));
|
||||
break;
|
||||
case 'S':
|
||||
dec->msg.reset(new GotRouterMessage(dec->From, dec->relayed));
|
||||
break;
|
||||
case 'I':
|
||||
dec->msg.reset(new PublishIntroMessage());
|
||||
break;
|
||||
case 'G':
|
||||
if(dec->relayed)
|
||||
{
|
||||
dec->msg.reset(new RelayedGotIntroMessage());
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
dec->msg.reset(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);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr< 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 nullptr;
|
||||
|
||||
return std::unique_ptr< IMessage >(std::move(dec.msg));
|
||||
}
|
||||
|
||||
struct ListDecoder
|
||||
{
|
||||
ListDecoder(const Key_t &from,
|
||||
std::vector< std::unique_ptr< IMessage > > &list)
|
||||
: From(from), l(list){};
|
||||
|
||||
bool relayed = false;
|
||||
const Key_t &From;
|
||||
std::vector< std::unique_ptr< 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.emplace_back(std::move(msg));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
DecodeMesssageList(Key_t from, llarp_buffer_t *buf,
|
||||
std::vector< std::unique_ptr< 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
|
||||
|
@ -1 +0,0 @@
|
||||
#include <dht/messages/all.hpp>
|
@ -1,8 +0,0 @@
|
||||
#ifndef LLARP_DHT_MESSAGES_ALL_HPP
|
||||
#define LLARP_DHT_MESSAGES_ALL_HPP
|
||||
#include <dht/messages/findintro.hpp>
|
||||
#include <dht/messages/findrouter.hpp>
|
||||
#include <dht/messages/gotintro.hpp>
|
||||
#include <dht/messages/gotrouter.hpp>
|
||||
#include <dht/messages/pubintro.hpp>
|
||||
#endif
|
@ -1 +1,204 @@
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/findintro.hpp>
|
||||
#include <dht/messages/gotintro.hpp>
|
||||
#include <routing/message.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
FindIntroMessage::~FindIntroMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
FindIntroMessage::DecodeKey(llarp_buffer_t k, llarp_buffer_t* val)
|
||||
{
|
||||
bool read = false;
|
||||
|
||||
if(!BEncodeMaybeReadDictEntry("N", N, read, k, val))
|
||||
return false;
|
||||
|
||||
if(!BEncodeMaybeReadDictInt("R", R, read, k, val))
|
||||
return false;
|
||||
|
||||
if(!BEncodeMaybeReadDictEntry("S", S, read, k, val))
|
||||
return false;
|
||||
|
||||
if(!BEncodeMaybeReadDictInt("T", T, read, k, val))
|
||||
return false;
|
||||
|
||||
if(!BEncodeMaybeReadVersion("V", version, LLARP_PROTO_VERSION, read, k,
|
||||
val))
|
||||
return false;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
FindIntroMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message id
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "F"))
|
||||
return false;
|
||||
if(N.Empty())
|
||||
{
|
||||
// recursion
|
||||
if(!BEncodeWriteDictInt("R", R, buf))
|
||||
return false;
|
||||
// service address
|
||||
if(!BEncodeWriteDictEntry("S", S, buf))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!BEncodeWriteDictEntry("N", N, buf))
|
||||
return false;
|
||||
// recursion
|
||||
if(!BEncodeWriteDictInt("R", R, buf))
|
||||
return false;
|
||||
}
|
||||
// txid
|
||||
if(!BEncodeWriteDictInt("T", T, buf))
|
||||
return false;
|
||||
// protocol version
|
||||
if(!BEncodeWriteDictInt("V", LLARP_PROTO_VERSION, buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
FindIntroMessage::HandleMessage(
|
||||
llarp_dht_context* ctx,
|
||||
std::vector< std::unique_ptr< IMessage > >& replies) const
|
||||
{
|
||||
if(R > 5)
|
||||
{
|
||||
llarp::LogError("R value too big, ", R, "> 5");
|
||||
return false;
|
||||
}
|
||||
auto& dht = ctx->impl;
|
||||
if(dht.pendingIntrosetLookups.HasPendingLookupFrom(TXOwner{From, T}))
|
||||
{
|
||||
llarp::LogWarn("duplicate FIM from ", From, " txid=", T);
|
||||
return false;
|
||||
}
|
||||
Key_t peer;
|
||||
std::set< Key_t > exclude = {dht.OurKey(), From};
|
||||
if(N.Empty())
|
||||
{
|
||||
llarp::LogInfo("lookup ", S.ToString());
|
||||
const auto introset = dht.GetIntroSetByServiceAddress(S);
|
||||
if(introset)
|
||||
{
|
||||
service::IntroSet i = *introset;
|
||||
replies.emplace_back(new GotIntroMessage({i}, T));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(R == 0)
|
||||
{
|
||||
// we don't have it
|
||||
Key_t target = S.ToKey();
|
||||
Key_t closer;
|
||||
// find closer peer
|
||||
if(!dht.nodes->FindClosest(target, closer))
|
||||
return false;
|
||||
if(relayed)
|
||||
dht.LookupIntroSetForPath(S, T, pathID, closer);
|
||||
else
|
||||
replies.emplace_back(new GotIntroMessage(From, closer, T));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_t us = dht.OurKey();
|
||||
Key_t target = S.ToKey();
|
||||
// we are recursive
|
||||
if(dht.nodes->FindCloseExcluding(target, peer, exclude))
|
||||
{
|
||||
if(relayed)
|
||||
dht.LookupIntroSetForPath(S, T, pathID, peer);
|
||||
else
|
||||
{
|
||||
if((us ^ target) < (peer ^ target))
|
||||
{
|
||||
// we are not closer than our peer to the target so don't
|
||||
// recurse farther
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
return true;
|
||||
}
|
||||
else if(R > 0)
|
||||
dht.LookupIntroSetRecursive(S, From, T, peer, R - 1);
|
||||
else
|
||||
dht.LookupIntroSetIterative(S, From, T, peer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no more closer peers
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(relayed)
|
||||
{
|
||||
// tag lookup
|
||||
if(dht.nodes->GetRandomNodeExcluding(peer, exclude))
|
||||
{
|
||||
dht.LookupTagForPath(N, T, pathID, peer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no more closer peers
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(R == 0)
|
||||
{
|
||||
// base case
|
||||
auto introsets = dht.FindRandomIntroSetsWithTagExcluding(N, 2, {});
|
||||
std::vector< service::IntroSet > reply;
|
||||
for(const auto& introset : introsets)
|
||||
{
|
||||
reply.push_back(introset);
|
||||
}
|
||||
replies.emplace_back(new GotIntroMessage(reply, T));
|
||||
return true;
|
||||
}
|
||||
else if(R < 5)
|
||||
{
|
||||
// tag lookup
|
||||
if(dht.nodes->GetRandomNodeExcluding(peer, exclude))
|
||||
{
|
||||
dht.LookupTagRecursive(N, From, T, peer, R - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// too big R value
|
||||
replies.emplace_back(new GotIntroMessage({}, T));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
@ -1 +1,172 @@
|
||||
#include <dht/messages/findrouter.hpp>
|
||||
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/gotrouter.hpp>
|
||||
#include <messages/dht.hpp>
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
bool
|
||||
RelayedFindRouterMessage::HandleMessage(
|
||||
llarp_dht_context *ctx,
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
/// lookup for us, send an immeidate reply
|
||||
Key_t us = dht.OurKey();
|
||||
Key_t k{K};
|
||||
if(K == us)
|
||||
{
|
||||
auto path = dht.router->paths.GetByUpstream(K, pathID);
|
||||
if(path)
|
||||
{
|
||||
replies.emplace_back(
|
||||
new GotRouterMessage(k, txid, {dht.router->rc()}, false));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Key_t peer;
|
||||
// check if we know this in our nodedb first
|
||||
RouterContact found;
|
||||
if(dht.router->nodedb->Get(K, found))
|
||||
{
|
||||
replies.emplace_back(new GotRouterMessage(k, txid, {found}, false));
|
||||
return true;
|
||||
}
|
||||
// lookup if we don't have it in our nodedb
|
||||
if(dht.nodes->FindClosest(k, peer))
|
||||
dht.LookupRouterForPath(K, txid, pathID, peer);
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// exploritory or not?
|
||||
if(!bencode_write_bytestring(buf, "E", 1))
|
||||
return false;
|
||||
if(!bencode_write_uint64(buf, exploritory ? 1 : 0))
|
||||
return false;
|
||||
|
||||
// iterative or not?
|
||||
if(!bencode_write_bytestring(buf, "I", 1))
|
||||
return false;
|
||||
if(!bencode_write_uint64(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, "E"))
|
||||
{
|
||||
uint64_t result;
|
||||
if(!bencode_read_integer(val, &result))
|
||||
return false;
|
||||
|
||||
exploritory = result != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
std::copy(strbuf.base, strbuf.base + K.SIZE, K.begin());
|
||||
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< std::unique_ptr< 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;
|
||||
}
|
||||
if(dht.pendingRouterLookups.HasPendingLookupFrom({From, txid}))
|
||||
{
|
||||
llarp::LogWarn("Duplicate FRM from ", From, " txid=", txid);
|
||||
return false;
|
||||
}
|
||||
RouterContact found;
|
||||
Key_t k{K};
|
||||
if(exploritory)
|
||||
return dht.HandleExploritoryRouterLookup(From, txid, K, replies);
|
||||
else if(dht.router->nodedb->Get(K, found))
|
||||
{
|
||||
replies.emplace_back(new GotRouterMessage(k, txid, {found}, false));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
dht.LookupRouterRelayed(From, txid, k, !iterative, replies);
|
||||
return true;
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
@ -1 +1,125 @@
|
||||
#include <dht/messages/gotintro.hpp>
|
||||
|
||||
#include <dht/context.hpp>
|
||||
#include <messages/dht.hpp>
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
GotIntroMessage::GotIntroMessage(
|
||||
const std::vector< llarp::service::IntroSet > &results, uint64_t tx)
|
||||
: IMessage({}), I(results), T(tx)
|
||||
{
|
||||
}
|
||||
|
||||
GotIntroMessage::~GotIntroMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
GotIntroMessage::HandleMessage(
|
||||
llarp_dht_context *ctx,
|
||||
__attribute__((unused))
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
auto crypto = &dht.router->crypto;
|
||||
|
||||
for(const auto &introset : I)
|
||||
{
|
||||
if(!introset.Verify(crypto, dht.Now()))
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"Invalid introset while handling direct GotIntro "
|
||||
"from ",
|
||||
From);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TXOwner owner(From, T);
|
||||
auto tagLookup = dht.pendingTagLookups.GetPendingLookupFrom(owner);
|
||||
if(tagLookup)
|
||||
{
|
||||
dht.pendingTagLookups.Found(owner, tagLookup->target, I);
|
||||
return true;
|
||||
}
|
||||
auto serviceLookup =
|
||||
dht.pendingIntrosetLookups.GetPendingLookupFrom(owner);
|
||||
if(serviceLookup)
|
||||
{
|
||||
if(I.size())
|
||||
{
|
||||
dht.pendingIntrosetLookups.Found(owner, serviceLookup->target, I);
|
||||
}
|
||||
else
|
||||
{
|
||||
dht.pendingIntrosetLookups.NotFound(owner, K);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
llarp::LogError("no pending TX for GIM from ", From, " txid=", T);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RelayedGotIntroMessage::HandleMessage(
|
||||
llarp_dht_context *ctx,
|
||||
__attribute__((unused))
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
// TODO: implement me better?
|
||||
auto pathset = ctx->impl.router->paths.GetLocalPathSet(pathID);
|
||||
if(pathset)
|
||||
{
|
||||
return pathset->HandleGotIntroMessage(this);
|
||||
}
|
||||
llarp::LogWarn("No path for got intro message pathid=", pathID);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GotIntroMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "I"))
|
||||
{
|
||||
return BEncodeReadList(I, buf);
|
||||
}
|
||||
if(llarp_buffer_eq(key, "K"))
|
||||
{
|
||||
if(K) // duplicate key?
|
||||
return false;
|
||||
K.reset(new dht::Key_t());
|
||||
return K->BDecode(buf);
|
||||
}
|
||||
bool read = false;
|
||||
if(!BEncodeMaybeReadDictInt("T", T, read, key, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("V", version, read, key, buf))
|
||||
return false;
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
GotIntroMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "G"))
|
||||
return false;
|
||||
if(!BEncodeWriteDictList("I", I, buf))
|
||||
return false;
|
||||
if(K)
|
||||
{
|
||||
if(!BEncodeWriteDictEntry("K", *K.get(), buf))
|
||||
return false;
|
||||
}
|
||||
if(!BEncodeWriteDictInt("T", T, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("V", version, buf))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
@ -1 +1,123 @@
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/gotrouter.hpp>
|
||||
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
GotRouterMessage::~GotRouterMessage()
|
||||
{
|
||||
}
|
||||
|
||||
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(K)
|
||||
{
|
||||
if(!BEncodeWriteDictEntry("K", *K.get(), buf))
|
||||
return false;
|
||||
}
|
||||
|
||||
// near
|
||||
if(N.size())
|
||||
{
|
||||
if(!BEncodeWriteDictList("N", N, buf))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!BEncodeWriteDictList("R", R, buf))
|
||||
return false;
|
||||
|
||||
// txid
|
||||
if(!BEncodeWriteDictInt("T", txid, buf))
|
||||
return false;
|
||||
|
||||
// version
|
||||
if(!BEncodeWriteDictInt("V", version, buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "K"))
|
||||
{
|
||||
if(K) // duplicate key?
|
||||
return false;
|
||||
K.reset(new dht::Key_t());
|
||||
return K->BDecode(val);
|
||||
}
|
||||
if(llarp_buffer_eq(key, "N"))
|
||||
{
|
||||
return BEncodeReadList(N, 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,
|
||||
__attribute__((unused))
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
auto &dht = ctx->impl;
|
||||
if(relayed)
|
||||
{
|
||||
auto pathset = ctx->impl.router->paths.GetLocalPathSet(pathID);
|
||||
return pathset && pathset->HandleGotRouterMessage(this);
|
||||
}
|
||||
// not relayed
|
||||
TXOwner owner(From, txid);
|
||||
|
||||
if(dht.pendingExploreLookups.HasPendingLookupFrom(owner))
|
||||
{
|
||||
if(N.size() == 0)
|
||||
dht.pendingExploreLookups.NotFound(owner, K);
|
||||
else
|
||||
{
|
||||
dht.pendingExploreLookups.Found(owner, From.as_array(), N);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// not explore lookup
|
||||
|
||||
if(!dht.pendingRouterLookups.HasPendingLookupFrom(owner))
|
||||
{
|
||||
llarp::LogWarn("Unwarrented GRM from ", From, " txid=", txid);
|
||||
return false;
|
||||
}
|
||||
// no pending lookup
|
||||
|
||||
llarp::LogInfo("DHT no pending lookup");
|
||||
if(R.size() == 1)
|
||||
dht.pendingRouterLookups.Found(owner, R[0].pubkey, {R[0]});
|
||||
else
|
||||
dht.pendingRouterLookups.NotFound(owner, K);
|
||||
return true;
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
@ -1 +1,121 @@
|
||||
#include <dht/messages/pubintro.hpp>
|
||||
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/gotintro.hpp>
|
||||
#include <messages/dht.hpp>
|
||||
#include <messages/dht_immediate.hpp>
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
PublishIntroMessage::~PublishIntroMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
|
||||
{
|
||||
bool read = false;
|
||||
if(llarp_buffer_eq(key, "E"))
|
||||
{
|
||||
return BEncodeReadList(E, val);
|
||||
}
|
||||
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("T", txID, read, key, val))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("V", version, read, key, val))
|
||||
return false;
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::HandleMessage(
|
||||
llarp_dht_context *ctx,
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
auto now = ctx->impl.Now();
|
||||
if(S > 5)
|
||||
{
|
||||
llarp::LogWarn("invalid S value ", S, " > 5");
|
||||
return false;
|
||||
}
|
||||
auto &dht = ctx->impl;
|
||||
if(!I.Verify(&dht.router->crypto, now))
|
||||
{
|
||||
llarp::LogWarn("invalid introset: ", I);
|
||||
// don't propogate or store
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
if(I.W && !I.W->IsValid(dht.router->crypto.shorthash, now))
|
||||
{
|
||||
llarp::LogWarn("proof of work not good enough for IntroSet");
|
||||
// don't propogate or store
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
llarp::dht::Key_t addr;
|
||||
if(!I.A.CalculateAddress(addr.as_array()))
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"failed to calculate hidden service address for PubIntro message");
|
||||
return false;
|
||||
}
|
||||
|
||||
now += llarp::service::MAX_INTROSET_TIME_DELTA;
|
||||
if(I.IsExpired(now))
|
||||
{
|
||||
// don't propogate or store
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
dht.services->PutNode(I);
|
||||
replies.emplace_back(new GotIntroMessage({I}, txID));
|
||||
Key_t peer;
|
||||
std::set< Key_t > exclude;
|
||||
for(const auto &e : E)
|
||||
exclude.insert(e);
|
||||
exclude.insert(From);
|
||||
exclude.insert(dht.OurKey());
|
||||
if(S && dht.nodes->FindCloseExcluding(addr, peer, exclude))
|
||||
{
|
||||
dht.PropagateIntroSetTo(From, txID, I, peer, S - 1, exclude);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "I"))
|
||||
return false;
|
||||
if(!BEncodeWriteDictList("E", E, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictEntry("I", I, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("R", R, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("S", S, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("T", txID, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("V", LLARP_PROTO_VERSION, buf))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
@ -1,119 +0,0 @@
|
||||
#include <dht/context.hpp>
|
||||
#include <dht/messages/pubintro.hpp>
|
||||
#include <messages/dht.hpp>
|
||||
#include <messages/dht_immediate.hpp>
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
PublishIntroMessage::~PublishIntroMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
|
||||
{
|
||||
bool read = false;
|
||||
if(llarp_buffer_eq(key, "E"))
|
||||
{
|
||||
return BEncodeReadList(E, val);
|
||||
}
|
||||
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("T", txID, read, key, val))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("V", version, read, key, val))
|
||||
return false;
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::HandleMessage(
|
||||
llarp_dht_context *ctx,
|
||||
std::vector< std::unique_ptr< IMessage > > &replies) const
|
||||
{
|
||||
auto now = ctx->impl.Now();
|
||||
if(S > 5)
|
||||
{
|
||||
llarp::LogWarn("invalid S value ", S, " > 5");
|
||||
return false;
|
||||
}
|
||||
auto &dht = ctx->impl;
|
||||
if(!I.Verify(&dht.router->crypto, now))
|
||||
{
|
||||
llarp::LogWarn("invalid introset: ", I);
|
||||
// don't propogate or store
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
if(I.W && !I.W->IsValid(dht.router->crypto.shorthash, now))
|
||||
{
|
||||
llarp::LogWarn("proof of work not good enough for IntroSet");
|
||||
// don't propogate or store
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
llarp::dht::Key_t addr;
|
||||
if(!I.A.CalculateAddress(addr.as_array()))
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"failed to calculate hidden service address for PubIntro message");
|
||||
return false;
|
||||
}
|
||||
|
||||
now += llarp::service::MAX_INTROSET_TIME_DELTA;
|
||||
if(I.IsExpired(now))
|
||||
{
|
||||
// don't propogate or store
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
dht.services->PutNode(I);
|
||||
replies.emplace_back(new GotIntroMessage({I}, txID));
|
||||
Key_t peer;
|
||||
std::set< Key_t > exclude;
|
||||
for(const auto &e : E)
|
||||
exclude.insert(e);
|
||||
exclude.insert(From);
|
||||
exclude.insert(dht.OurKey());
|
||||
if(S && dht.nodes->FindCloseExcluding(addr, peer, exclude))
|
||||
{
|
||||
dht.PropagateIntroSetTo(From, txID, I, peer, S - 1, exclude);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "I"))
|
||||
return false;
|
||||
if(!BEncodeWriteDictList("E", E, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictEntry("I", I, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("R", R, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("S", S, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("T", txID, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("V", LLARP_PROTO_VERSION, buf))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -0,0 +1 @@
|
||||
#include <dht/txowner.hpp>
|
@ -0,0 +1,54 @@
|
||||
#ifndef LLARP_DHT_TXOWNER_HPP
|
||||
#define LLARP_DHT_TXOWNER_HPP
|
||||
|
||||
#include <dht/key.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct TXOwner
|
||||
{
|
||||
Key_t node;
|
||||
uint64_t txid = 0;
|
||||
|
||||
TXOwner() = default;
|
||||
TXOwner(const TXOwner&) = default;
|
||||
TXOwner(TXOwner&&) = default;
|
||||
|
||||
TXOwner&
|
||||
operator=(const TXOwner&) = default;
|
||||
|
||||
TXOwner(const Key_t& k, uint64_t id) : node(k), txid(id)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const TXOwner& other) const
|
||||
{
|
||||
return std::tie(txid, node) == std::tie(other.txid, other.node);
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const TXOwner& other) const
|
||||
{
|
||||
return std::tie(txid, node) < std::tie(other.txid, other.node);
|
||||
}
|
||||
|
||||
struct Hash
|
||||
{
|
||||
std::size_t
|
||||
operator()(const TXOwner& o) const noexcept
|
||||
{
|
||||
std::size_t sz2;
|
||||
memcpy(&sz2, &o.node[0], sizeof(std::size_t));
|
||||
return o.txid ^ (sz2 << 1);
|
||||
}
|
||||
};
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -1 +1,86 @@
|
||||
#include <messages/dht_immediate.hpp>
|
||||
|
||||
#include <router/router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
DHTImmediateMessage::~DHTImmediateMessage()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DHTImmediateMessage::Clear()
|
||||
{
|
||||
msgs.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmediateMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "m"))
|
||||
return llarp::dht::DecodeMesssageList(dht::Key_t(session->GetPubKey()),
|
||||
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
|
||||
DHTImmediateMessage::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
|
||||
DHTImmediateMessage::HandleMessage(llarp::Router *router) const
|
||||
{
|
||||
DHTImmediateMessage reply;
|
||||
reply.session = session;
|
||||
bool result = true;
|
||||
for(auto &msg : msgs)
|
||||
{
|
||||
result &= msg->HandleMessage(router->dht, reply.msgs);
|
||||
}
|
||||
if(reply.msgs.size())
|
||||
{
|
||||
if(result)
|
||||
{
|
||||
result = router->SendToOrQueue(session->GetPubKey(), &reply);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace llarp
|
||||
|
@ -1,123 +0,0 @@
|
||||
#include <dht/bucket.hpp>
|
||||
#include <dht/key.hpp>
|
||||
#include <dht/node.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using Key_t = llarp::dht::Key_t;
|
||||
|
||||
class KademliaDHTTest : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
KademliaDHTTest()
|
||||
{
|
||||
}
|
||||
~KademliaDHTTest()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SetUp()
|
||||
{
|
||||
us.Fill(16);
|
||||
nodes = new llarp::dht::Bucket< llarp::dht::RCNode >(us);
|
||||
size_t numNodes = 10;
|
||||
byte_t fill = 1;
|
||||
while(numNodes)
|
||||
{
|
||||
llarp::dht::RCNode n;
|
||||
n.ID.Fill(fill);
|
||||
nodes->PutNode(n);
|
||||
--numNodes;
|
||||
++fill;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TearDown()
|
||||
{
|
||||
delete nodes;
|
||||
}
|
||||
|
||||
llarp::dht::Bucket< llarp::dht::RCNode >* nodes = nullptr;
|
||||
llarp::dht::Key_t us;
|
||||
};
|
||||
|
||||
TEST_F(KademliaDHTTest, TestBucketFindClosest)
|
||||
{
|
||||
llarp::dht::Key_t result;
|
||||
llarp::dht::Key_t target;
|
||||
llarp::dht::Key_t oldResult;
|
||||
target.Fill(5);
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
ASSERT_TRUE(target == result);
|
||||
oldResult = result;
|
||||
target.Fill(0xf5);
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
ASSERT_TRUE(oldResult == result);
|
||||
};
|
||||
|
||||
TEST_F(KademliaDHTTest, TestBucketOperators)
|
||||
{
|
||||
llarp::dht::Key_t zero;
|
||||
llarp::dht::Key_t one;
|
||||
llarp::dht::Key_t three;
|
||||
|
||||
zero.Zero();
|
||||
one.Fill(1);
|
||||
three.Fill(3);
|
||||
ASSERT_TRUE(zero < one);
|
||||
ASSERT_TRUE(zero < three);
|
||||
ASSERT_FALSE(zero > one);
|
||||
ASSERT_FALSE(zero > three);
|
||||
ASSERT_TRUE(zero != three);
|
||||
ASSERT_FALSE(zero == three);
|
||||
ASSERT_TRUE((zero ^ one) == one);
|
||||
ASSERT_TRUE(one < three);
|
||||
ASSERT_TRUE(three > one);
|
||||
ASSERT_TRUE(one != three);
|
||||
ASSERT_FALSE(one == three);
|
||||
ASSERT_TRUE((one ^ three) == (three ^ one));
|
||||
};
|
||||
|
||||
TEST_F(KademliaDHTTest, TestBucketRandomized_1000)
|
||||
{
|
||||
size_t moreNodes = 100;
|
||||
while(moreNodes--)
|
||||
{
|
||||
llarp::dht::RCNode n;
|
||||
n.ID.Randomize();
|
||||
nodes->PutNode(n);
|
||||
}
|
||||
const size_t count = 1000;
|
||||
size_t left = count;
|
||||
while(left--)
|
||||
{
|
||||
llarp::dht::Key_t result;
|
||||
llarp::dht::Key_t target;
|
||||
llarp::dht::Key_t expect;
|
||||
target.Randomize();
|
||||
expect = target;
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
if(target == result)
|
||||
{
|
||||
ASSERT_FALSE((result ^ target) < (expect ^ target));
|
||||
ASSERT_FALSE((result ^ target) != (expect ^ target));
|
||||
ASSERT_TRUE((result ^ target) == (expect ^ target));
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_t dist = result ^ target;
|
||||
Key_t oldDist = expect ^ target;
|
||||
ASSERT_TRUE((result ^ target) != (expect ^ target));
|
||||
if((result ^ target) < (expect ^ target))
|
||||
{
|
||||
std::cout << "result=" << result << "expect=" << expect << std::endl;
|
||||
std::cout << dist << ">=" << oldDist << "iteration=" << (count - left)
|
||||
<< std::endl;
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
ASSERT_FALSE((result ^ target) == (expect ^ target));
|
||||
}
|
||||
}
|
||||
};
|
@ -0,0 +1,370 @@
|
||||
#include <dht/bucket.hpp>
|
||||
#include <dht/key.hpp>
|
||||
#include <dht/node.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using Key_t = llarp::dht::Key_t;
|
||||
using Value_t = llarp::dht::RCNode;
|
||||
using Bucket_t = llarp::dht::Bucket< Value_t >;
|
||||
|
||||
class TestDhtBucket : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestDhtBucket() : randInt(0)
|
||||
{
|
||||
us.Fill(16);
|
||||
nodes = std::make_unique< Bucket_t >(us, [&]() { return randInt++; });
|
||||
size_t numNodes = 10;
|
||||
byte_t fill = 1;
|
||||
while(numNodes)
|
||||
{
|
||||
Value_t n;
|
||||
n.ID.Fill(fill);
|
||||
nodes->PutNode(n);
|
||||
--numNodes;
|
||||
++fill;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t randInt;
|
||||
|
||||
llarp::dht::Key_t us;
|
||||
std::unique_ptr< Bucket_t > nodes;
|
||||
};
|
||||
|
||||
TEST_F(TestDhtBucket, simple_cycle)
|
||||
{
|
||||
// Empty the current bucket.
|
||||
nodes->Clear();
|
||||
|
||||
// Create a simple value, and add it to the bucket.
|
||||
Value_t val;
|
||||
val.ID.Fill(1);
|
||||
|
||||
nodes->PutNode(val);
|
||||
|
||||
// Verify the value is in the bucket
|
||||
ASSERT_TRUE(nodes->HasNode(val.ID));
|
||||
ASSERT_EQ(1u, nodes->size());
|
||||
|
||||
// Verify after deletion, the value is no longer in the bucket
|
||||
nodes->DelNode(val.ID);
|
||||
ASSERT_FALSE(nodes->HasNode(val.ID));
|
||||
|
||||
// Verify deleting again succeeds;
|
||||
nodes->DelNode(val.ID);
|
||||
ASSERT_FALSE(nodes->HasNode(val.ID));
|
||||
}
|
||||
|
||||
TEST_F(TestDhtBucket, get_random_node_excluding)
|
||||
{
|
||||
// Empty the current bucket.
|
||||
nodes->Clear();
|
||||
|
||||
// We expect not to find anything
|
||||
Key_t result;
|
||||
std::set< Key_t > excludeSet;
|
||||
ASSERT_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||
|
||||
// Create a simple value.
|
||||
Value_t val;
|
||||
val.ID.Fill(1);
|
||||
|
||||
// Add the simple value to the exclude set
|
||||
excludeSet.insert(val.ID);
|
||||
ASSERT_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||
|
||||
// Add the simple value to the bucket
|
||||
nodes->PutNode(val);
|
||||
ASSERT_FALSE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||
|
||||
excludeSet.clear();
|
||||
|
||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||
ASSERT_EQ(val.ID, result);
|
||||
|
||||
// Add an element to the exclude set which isn't the bucket.
|
||||
Key_t other;
|
||||
other.Fill(0xff);
|
||||
excludeSet.insert(other);
|
||||
|
||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||
ASSERT_EQ(val.ID, result);
|
||||
|
||||
// Add a node which is in both bucket and excludeSet
|
||||
Value_t nextVal;
|
||||
nextVal.ID.Fill(0xAA);
|
||||
excludeSet.insert(nextVal.ID);
|
||||
nodes->PutNode(nextVal);
|
||||
|
||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||
ASSERT_EQ(val.ID, result);
|
||||
|
||||
// Clear the excludeSet - we should still have 2 nodes in the bucket
|
||||
excludeSet.clear();
|
||||
|
||||
randInt = 0;
|
||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||
ASSERT_EQ(val.ID, result);
|
||||
|
||||
// Set the random value to be 1, we should get the other node.
|
||||
randInt = 1;
|
||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||
ASSERT_EQ(nextVal.ID, result);
|
||||
|
||||
// Set the random value to be 100, we should get the first node.
|
||||
randInt = 100;
|
||||
ASSERT_TRUE(nodes->GetRandomNodeExcluding(result, excludeSet));
|
||||
ASSERT_EQ(val.ID, result);
|
||||
}
|
||||
|
||||
TEST_F(TestDhtBucket, find_closest)
|
||||
{
|
||||
// Empty the current bucket.
|
||||
nodes->Clear();
|
||||
|
||||
// We expect not to find anything
|
||||
Key_t target;
|
||||
target.Fill(0xF0);
|
||||
|
||||
Key_t result;
|
||||
ASSERT_FALSE(nodes->FindClosest(target, result));
|
||||
|
||||
// Add a node to the bucket
|
||||
Value_t first;
|
||||
first.ID.Zero();
|
||||
nodes->PutNode(first);
|
||||
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
ASSERT_EQ(result, first.ID);
|
||||
|
||||
// Add another node to the bucket, closer to the target
|
||||
Value_t second;
|
||||
second.ID.Fill(0x10);
|
||||
nodes->PutNode(second);
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
ASSERT_EQ(result, second.ID);
|
||||
|
||||
// Add a third node to the bucket, closer to the target
|
||||
Value_t third;
|
||||
third.ID.Fill(0x20);
|
||||
nodes->PutNode(third);
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
ASSERT_EQ(result, third.ID);
|
||||
|
||||
// Add a fourth node to the bucket, greater than the target
|
||||
Value_t fourth;
|
||||
fourth.ID.Fill(0xF1);
|
||||
nodes->PutNode(fourth);
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
ASSERT_EQ(result, fourth.ID);
|
||||
|
||||
// Add a fifth node to the bucket, equal to the target
|
||||
Value_t fifth;
|
||||
fifth.ID.Fill(0xF0);
|
||||
nodes->PutNode(fifth);
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
ASSERT_EQ(result, fifth.ID);
|
||||
}
|
||||
|
||||
TEST_F(TestDhtBucket, get_many_random)
|
||||
{
|
||||
// Empty the current bucket.
|
||||
nodes->Clear();
|
||||
|
||||
// Verify behaviour with empty node set
|
||||
std::set< Key_t > result;
|
||||
ASSERT_FALSE(nodes->GetManyRandom(result, 0));
|
||||
ASSERT_FALSE(nodes->GetManyRandom(result, 1));
|
||||
|
||||
// Add 5 nodes to the bucket
|
||||
std::set< Value_t > curValues;
|
||||
std::set< Key_t > curKeys;
|
||||
for(byte_t i = 0x00; i < 0x05; ++i)
|
||||
{
|
||||
Value_t v;
|
||||
v.ID.Fill(i);
|
||||
ASSERT_TRUE(curKeys.insert(v.ID).second);
|
||||
nodes->PutNode(v);
|
||||
}
|
||||
|
||||
// Fetching more than the current size fails
|
||||
ASSERT_EQ(5u, nodes->size());
|
||||
ASSERT_FALSE(nodes->GetManyRandom(result, nodes->size() + 1));
|
||||
|
||||
// Fetching the current size succeeds
|
||||
ASSERT_TRUE(nodes->GetManyRandom(result, nodes->size()));
|
||||
ASSERT_EQ(curKeys, result);
|
||||
|
||||
// Fetching a subset succeeds.
|
||||
// Note we hack this by "fixing" the random number generator
|
||||
result.clear();
|
||||
|
||||
ASSERT_TRUE(nodes->GetManyRandom(result, 1u));
|
||||
ASSERT_EQ(1u, result.size());
|
||||
ASSERT_EQ(*curKeys.begin(), *result.begin());
|
||||
|
||||
randInt = 0;
|
||||
result.clear();
|
||||
|
||||
ASSERT_TRUE(nodes->GetManyRandom(result, nodes->size() - 1));
|
||||
ASSERT_EQ(nodes->size() - 1, result.size());
|
||||
ASSERT_EQ(std::set< Key_t >(++curKeys.rbegin(), curKeys.rend()), result);
|
||||
}
|
||||
|
||||
TEST_F(TestDhtBucket, find_close_excluding)
|
||||
{
|
||||
// Empty the current bucket.
|
||||
nodes->Clear();
|
||||
|
||||
Key_t target;
|
||||
target.Zero();
|
||||
std::set< Key_t > exclude;
|
||||
Key_t result;
|
||||
|
||||
// Empty node + exclude set fails
|
||||
ASSERT_FALSE(nodes->FindCloseExcluding(target, result, exclude));
|
||||
|
||||
Value_t first;
|
||||
first.ID.Fill(0xF0);
|
||||
exclude.insert(first.ID);
|
||||
|
||||
// Empty nodes fails
|
||||
ASSERT_FALSE(nodes->FindCloseExcluding(target, result, exclude));
|
||||
|
||||
// Nodes and exclude set match
|
||||
nodes->PutNode(first);
|
||||
ASSERT_FALSE(nodes->FindCloseExcluding(target, result, exclude));
|
||||
|
||||
// Exclude set empty
|
||||
exclude.clear();
|
||||
ASSERT_TRUE(nodes->FindCloseExcluding(target, result, exclude));
|
||||
result = first.ID;
|
||||
|
||||
Value_t second;
|
||||
second.ID.Fill(0x01);
|
||||
nodes->PutNode(second);
|
||||
|
||||
ASSERT_TRUE(nodes->FindCloseExcluding(target, result, exclude));
|
||||
result = second.ID;
|
||||
|
||||
exclude.insert(second.ID);
|
||||
ASSERT_TRUE(nodes->FindCloseExcluding(target, result, exclude));
|
||||
result = first.ID;
|
||||
}
|
||||
|
||||
TEST_F(TestDhtBucket, find_many_near_excluding)
|
||||
{
|
||||
// Empty the current bucket.
|
||||
nodes->Clear();
|
||||
|
||||
Key_t target;
|
||||
target.Zero();
|
||||
std::set< Key_t > exclude;
|
||||
std::set< Key_t > result;
|
||||
|
||||
// Empty node + exclude set, with size 0 succeeds
|
||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 0, exclude));
|
||||
ASSERT_EQ(0u, result.size());
|
||||
// Empty node + exclude set fails
|
||||
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||
|
||||
Value_t first;
|
||||
first.ID.Fill(0xF0);
|
||||
exclude.insert(first.ID);
|
||||
|
||||
// Empty nodes fails
|
||||
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||
|
||||
// Nodes and exclude set match
|
||||
nodes->PutNode(first);
|
||||
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||
|
||||
// Single node succeeds
|
||||
exclude.clear();
|
||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||
ASSERT_EQ(result, std::set< Key_t >({first.ID}));
|
||||
|
||||
// Trying to grab 2 nodes from a 1 node set fails
|
||||
result.clear();
|
||||
ASSERT_FALSE(nodes->GetManyNearExcluding(target, result, 2, exclude));
|
||||
|
||||
// two nodes finds closest
|
||||
Value_t second;
|
||||
second.ID.Fill(0x01);
|
||||
nodes->PutNode(second);
|
||||
result.clear();
|
||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 1, exclude));
|
||||
ASSERT_EQ(result, std::set< Key_t >({second.ID}));
|
||||
|
||||
// 3 nodes finds 2 closest
|
||||
Value_t third;
|
||||
third.ID.Fill(0x02);
|
||||
nodes->PutNode(third);
|
||||
result.clear();
|
||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 2, exclude));
|
||||
ASSERT_EQ(result, std::set< Key_t >({second.ID, third.ID}));
|
||||
|
||||
// 4 nodes, one in exclude set finds 2 closest
|
||||
Value_t fourth;
|
||||
fourth.ID.Fill(0x03);
|
||||
nodes->PutNode(fourth);
|
||||
exclude.insert(third.ID);
|
||||
result.clear();
|
||||
ASSERT_TRUE(nodes->GetManyNearExcluding(target, result, 2, exclude));
|
||||
ASSERT_EQ(result, std::set< Key_t >({second.ID, fourth.ID}));
|
||||
}
|
||||
|
||||
TEST_F(TestDhtBucket, TestBucketFindClosest)
|
||||
{
|
||||
llarp::dht::Key_t result;
|
||||
llarp::dht::Key_t target;
|
||||
target.Fill(5);
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
ASSERT_EQ(target, result);
|
||||
const llarp::dht::Key_t oldResult = result;
|
||||
target.Fill(0xf5);
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
ASSERT_EQ(oldResult, result);
|
||||
};
|
||||
|
||||
TEST_F(TestDhtBucket, TestBucketRandomized_1000)
|
||||
{
|
||||
size_t moreNodes = 100;
|
||||
while(moreNodes--)
|
||||
{
|
||||
llarp::dht::RCNode n;
|
||||
n.ID.Fill(randInt);
|
||||
randInt++;
|
||||
nodes->PutNode(n);
|
||||
}
|
||||
const size_t count = 1000;
|
||||
size_t left = count;
|
||||
while(left--)
|
||||
{
|
||||
llarp::dht::Key_t result;
|
||||
llarp::dht::Key_t target;
|
||||
target.Randomize();
|
||||
const llarp::dht::Key_t expect = target;
|
||||
ASSERT_TRUE(nodes->FindClosest(target, result));
|
||||
if(target == result)
|
||||
{
|
||||
ASSERT_GE(result ^ target, expect ^ target);
|
||||
ASSERT_EQ(result ^ target, expect ^ target);
|
||||
ASSERT_EQ(result ^ target, expect ^ target);
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_t dist = result ^ target;
|
||||
Key_t oldDist = expect ^ target;
|
||||
ASSERT_NE(result ^ target, expect ^ target);
|
||||
|
||||
ASSERT_GE(result ^ target, expect ^ target)
|
||||
<< "result=" << result << "expect=" << expect << std::endl
|
||||
<< dist << ">=" << oldDist << "iteration=" << (count - left);
|
||||
|
||||
ASSERT_NE(result ^ target, expect ^ target);
|
||||
}
|
||||
}
|
||||
};
|
@ -0,0 +1,88 @@
|
||||
#include <dht/kademlia.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using llarp::dht::Key_t;
|
||||
|
||||
using Array = std::array< byte_t, Key_t::SIZE >;
|
||||
|
||||
struct XorMetricData
|
||||
{
|
||||
Array us;
|
||||
Array left;
|
||||
Array right;
|
||||
bool result;
|
||||
|
||||
XorMetricData(const Array& u, const Array& l, const Array& r, bool res)
|
||||
: us(u), left(l), right(r), result(res)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& stream, const XorMetricData& x)
|
||||
{
|
||||
stream << int(x.us[0]) << " " << int(x.left[0]) << " " << int(x.right[0])
|
||||
<< " " << std::boolalpha << x.result;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
struct XorMetric : public ::testing::TestWithParam< XorMetricData >
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(XorMetric, test)
|
||||
{
|
||||
auto d = GetParam();
|
||||
ASSERT_EQ(llarp::dht::XorMetric{Key_t{d.us}}(Key_t{d.left}, Key_t{d.right}),
|
||||
d.result);
|
||||
}
|
||||
|
||||
std::vector< XorMetricData >
|
||||
makeData()
|
||||
{
|
||||
std::vector< XorMetricData > result;
|
||||
|
||||
Array zero;
|
||||
zero.fill(0);
|
||||
Array one;
|
||||
one.fill(1);
|
||||
Array two;
|
||||
two.fill(2);
|
||||
Array three;
|
||||
three.fill(3);
|
||||
|
||||
result.emplace_back(zero, zero, zero, false);
|
||||
result.emplace_back(zero, zero, one, true);
|
||||
result.emplace_back(zero, zero, two, true);
|
||||
result.emplace_back(zero, one, zero, false);
|
||||
result.emplace_back(zero, one, one, false);
|
||||
result.emplace_back(zero, one, two, true);
|
||||
result.emplace_back(zero, two, zero, false);
|
||||
result.emplace_back(zero, two, one, false);
|
||||
result.emplace_back(zero, two, two, false);
|
||||
result.emplace_back(one, zero, zero, false);
|
||||
result.emplace_back(one, zero, one, false);
|
||||
result.emplace_back(one, zero, two, true);
|
||||
result.emplace_back(one, one, zero, true);
|
||||
result.emplace_back(one, one, one, false);
|
||||
result.emplace_back(one, one, two, true);
|
||||
result.emplace_back(one, two, zero, false);
|
||||
result.emplace_back(one, two, one, false);
|
||||
result.emplace_back(one, two, two, false);
|
||||
result.emplace_back(two, zero, zero, false);
|
||||
result.emplace_back(two, zero, one, true);
|
||||
result.emplace_back(two, zero, two, false);
|
||||
result.emplace_back(two, one, zero, false);
|
||||
result.emplace_back(two, one, one, false);
|
||||
result.emplace_back(two, one, two, false);
|
||||
result.emplace_back(two, two, zero, true);
|
||||
result.emplace_back(two, two, one, true);
|
||||
result.emplace_back(two, two, two, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(TestDhtXorMetric, XorMetric,
|
||||
::testing::ValuesIn(makeData()));
|
@ -0,0 +1,123 @@
|
||||
#include <dht/txowner.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using llarp::dht::Key_t;
|
||||
using llarp::dht::TXOwner;
|
||||
|
||||
struct TxOwnerData
|
||||
{
|
||||
Key_t node;
|
||||
uint64_t id;
|
||||
size_t expectedHash;
|
||||
|
||||
TxOwnerData(const Key_t& k, uint64_t i, size_t h)
|
||||
: node(k), id(i), expectedHash(h)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct TxOwner : public ::testing::TestWithParam< TxOwnerData >
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(TxOwner, default_construct)
|
||||
{
|
||||
TXOwner dc;
|
||||
ASSERT_TRUE(dc.node.IsZero());
|
||||
ASSERT_EQ(0u, dc.txid);
|
||||
ASSERT_EQ(0u, TXOwner::Hash()(dc));
|
||||
}
|
||||
|
||||
TEST_P(TxOwner, hash)
|
||||
{
|
||||
// test single interactions (constructor and hash)
|
||||
auto d = GetParam();
|
||||
TXOwner constructor(d.node, d.id);
|
||||
|
||||
ASSERT_EQ(d.expectedHash, TXOwner::Hash()(constructor));
|
||||
}
|
||||
|
||||
std::vector< TxOwnerData >
|
||||
makeData()
|
||||
{
|
||||
std::vector< TxOwnerData > result;
|
||||
|
||||
Key_t zero;
|
||||
zero.Zero();
|
||||
Key_t one;
|
||||
one.Fill(0x01);
|
||||
Key_t two;
|
||||
two.Fill(0x02);
|
||||
|
||||
uint64_t max = std::numeric_limits< uint64_t >::max();
|
||||
|
||||
result.emplace_back(zero, 0, 0ull);
|
||||
result.emplace_back(zero, 1, 1ull);
|
||||
result.emplace_back(one, 0, 144680345676153346ull);
|
||||
result.emplace_back(one, 1, 144680345676153347ull);
|
||||
result.emplace_back(two, 0, 289360691352306692ull);
|
||||
result.emplace_back(two, 2, 289360691352306694ull);
|
||||
result.emplace_back(zero, max, 18446744073709551615ull);
|
||||
result.emplace_back(one, max, 18302063728033398269ull);
|
||||
result.emplace_back(two, max, 18157383382357244923ull);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct TxOwnerCmpData
|
||||
{
|
||||
TXOwner lhs;
|
||||
TXOwner rhs;
|
||||
bool equal;
|
||||
bool less;
|
||||
|
||||
TxOwnerCmpData(const TXOwner& l, const TXOwner& r, bool e, bool ls)
|
||||
: lhs(l), rhs(r), equal(e), less(ls)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct TxOwnerOps : public ::testing::TestWithParam< TxOwnerCmpData >
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(TxOwnerOps, operators)
|
||||
{
|
||||
// test single interactions (constructor and hash)
|
||||
auto d = GetParam();
|
||||
|
||||
ASSERT_EQ(d.lhs == d.rhs, d.equal);
|
||||
ASSERT_EQ(d.lhs < d.rhs, d.less);
|
||||
}
|
||||
|
||||
std::vector< TxOwnerCmpData >
|
||||
makeCmpData()
|
||||
{
|
||||
std::vector< TxOwnerCmpData > result;
|
||||
|
||||
Key_t zero;
|
||||
zero.Fill(0x00);
|
||||
Key_t one;
|
||||
one.Fill(0x01);
|
||||
Key_t two;
|
||||
two.Fill(0x02);
|
||||
|
||||
result.emplace_back(TXOwner(zero, 0), TXOwner(zero, 0), true, false);
|
||||
result.emplace_back(TXOwner(one, 0), TXOwner(one, 0), true, false);
|
||||
result.emplace_back(TXOwner(two, 0), TXOwner(two, 0), true, false);
|
||||
|
||||
result.emplace_back(TXOwner(zero, 0), TXOwner(one, 0), false, true);
|
||||
result.emplace_back(TXOwner(two, 0), TXOwner(one, 0), false, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(TestDhtTxOwner, TxOwner,
|
||||
::testing::ValuesIn(makeData()));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(TestDhtTxOwner, TxOwnerOps,
|
||||
::testing::ValuesIn(makeCmpData()));
|
Loading…
Reference in New Issue