Merge pull request #616 from michael-loki/reader_removal

Replace dict_reader/list_reader with version which doesn't involve indirection
pull/619/head
Jeff 5 years ago committed by GitHub
commit 3bd1aa50ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,6 @@
#include <dht/context.hpp>
#include <util/bencode.hpp>
#include <dht/messages/findintro.hpp>
#include <dht/messages/findrouter.hpp>
#include <dht/messages/gotintro.hpp>
@ -17,57 +18,57 @@ namespace llarp
bool firstKey = true;
bool relayed = false;
MessageDecoder(const Key_t &from) : From(from)
MessageDecoder(const Key_t &from, bool wasRelayed)
: From(from), relayed(wasRelayed)
{
}
static bool
on_key(dict_reader *r, llarp_buffer_t *key)
bool
operator()(llarp_buffer_t *buffer, llarp_buffer_t *key)
{
llarp_buffer_t strbuf;
MessageDecoder *dec = static_cast< MessageDecoder * >(r->user);
// check for empty dict
if(!key)
return !dec->firstKey;
return !firstKey;
// first key
if(dec->firstKey)
if(firstKey)
{
if(!(*key == "A"))
return false;
if(!bencode_read_string(r->buffer, &strbuf))
if(!bencode_read_string(buffer, &strbuf))
return false;
// bad msg size?
if(strbuf.sz != 1)
return false;
llarp::LogInfo("Handle DHT message ", *strbuf.base,
" relayed=", dec->relayed);
" relayed=", relayed);
switch(*strbuf.base)
{
case 'F':
dec->msg.reset(new FindIntroMessage(dec->From, dec->relayed));
msg.reset(new FindIntroMessage(From, relayed));
break;
case 'R':
if(dec->relayed)
dec->msg.reset(new RelayedFindRouterMessage(dec->From));
if(relayed)
msg.reset(new RelayedFindRouterMessage(From));
else
dec->msg.reset(new FindRouterMessage(dec->From));
msg.reset(new FindRouterMessage(From));
break;
case 'S':
dec->msg.reset(new GotRouterMessage(dec->From, dec->relayed));
msg.reset(new GotRouterMessage(From, relayed));
break;
case 'I':
dec->msg.reset(new PublishIntroMessage());
msg.reset(new PublishIntroMessage());
break;
case 'G':
if(dec->relayed)
if(relayed)
{
dec->msg.reset(new RelayedGotIntroMessage());
msg.reset(new RelayedGotIntroMessage());
break;
}
else
{
dec->msg.reset(new GotIntroMessage(dec->From));
msg.reset(new GotIntroMessage(From));
break;
}
default:
@ -75,23 +76,19 @@ namespace llarp
// bad msg type
return false;
}
dec->firstKey = false;
return dec->msg != nullptr;
firstKey = false;
return msg != nullptr;
}
else
return dec->msg->DecodeKey(*key, r->buffer);
return msg->DecodeKey(*key, buffer);
}
};
IMessage::Ptr_t
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))
MessageDecoder dec(from, relayed);
if(!bencode_read_dict(dec, buf))
return nullptr;
return std::move(dec.msg);
@ -99,25 +96,25 @@ namespace llarp
struct ListDecoder
{
ListDecoder(const Key_t &from, std::vector< IMessage::Ptr_t > &list)
: From(from), l(list)
ListDecoder(bool hasRelayed, const Key_t &from,
std::vector< IMessage::Ptr_t > &list)
: relayed(hasRelayed), From(from), l(list)
{
}
bool relayed = false;
bool relayed;
const Key_t &From;
std::vector< IMessage::Ptr_t > &l;
static bool
on_item(list_reader *r, bool has)
bool
operator()(llarp_buffer_t *buffer, bool has)
{
ListDecoder *dec = static_cast< ListDecoder * >(r->user);
if(!has)
return true;
auto msg = DecodeMesssage(dec->From, r->buffer, dec->relayed);
auto msg = DecodeMesssage(From, buffer, relayed);
if(msg)
{
dec->l.emplace_back(std::move(msg));
l.emplace_back(std::move(msg));
return true;
}
else
@ -129,12 +126,8 @@ namespace llarp
DecodeMesssageList(Key_t from, llarp_buffer_t *buf,
std::vector< IMessage::Ptr_t > &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);
ListDecoder dec(relayed, from, list);
return bencode_read_list(dec, buf);
}
} // namespace dht
} // namespace llarp

@ -38,13 +38,10 @@ namespace llarp
}
bool
InboundMessageParser::OnKey(dict_reader* r, llarp_buffer_t* key)
InboundMessageParser::operator()(llarp_buffer_t* buffer, llarp_buffer_t* key)
{
InboundMessageParser* handler =
static_cast< InboundMessageParser* >(r->user);
// we are reading the first key
if(handler->firstkey)
if(firstkey)
{
llarp_buffer_t strbuf;
// check for empty dict
@ -57,7 +54,7 @@ namespace llarp
return false;
}
if(!bencode_read_string(r->buffer, &strbuf))
if(!bencode_read_string(buffer, &strbuf))
{
llarp::LogWarn("could not read value of message type");
return false;
@ -74,23 +71,23 @@ namespace llarp
switch(*strbuf.cur)
{
case 'i':
handler->msg = &handler->holder->i;
isLIM = true;
msg = &holder->i;
isLIM = true;
break;
case 'd':
handler->msg = &handler->holder->d;
msg = &holder->d;
break;
case 'u':
handler->msg = &handler->holder->u;
msg = &holder->u;
break;
case 'm':
handler->msg = &handler->holder->m;
msg = &holder->m;
break;
case 'c':
handler->msg = &handler->holder->c;
msg = &holder->c;
break;
case 'x':
handler->msg = &handler->holder->x;
msg = &holder->x;
break;
default:
return false;
@ -98,20 +95,19 @@ namespace llarp
if(!isLIM)
{
const std::string host =
"RX_" + RouterID(handler->from->GetPubKey()).ToString();
METRICS_DYNAMIC_INCREMENT(handler->msg->Name(), host.c_str());
const std::string host = "RX_" + RouterID(from->GetPubKey()).ToString();
METRICS_DYNAMIC_INCREMENT(msg->Name(), host.c_str());
}
handler->msg->session = handler->from;
handler->firstkey = false;
msg->session = from;
firstkey = false;
return true;
}
// check for last element
if(!key)
return handler->MessageDone();
return MessageDone();
return handler->msg->DecodeKey(*key, r->buffer);
return msg->DecodeKey(*key, buffer);
}
bool
@ -135,12 +131,11 @@ namespace llarp
llarp::LogWarn("no link session");
return false;
}
reader.user = this;
reader.on_key = &OnKey;
from = src;
firstkey = true;
from = src;
firstkey = true;
ManagedBuffer copy(buf);
return bencode_read_dict(&copy.underlying, &reader);
return bencode_read_dict(*this, &copy.underlying);
}
void

@ -16,10 +16,9 @@ namespace llarp
{
InboundMessageParser(AbstractRouter* router);
~InboundMessageParser();
dict_reader reader;
static bool
OnKey(dict_reader* r, llarp_buffer_t* buf);
bool
operator()(llarp_buffer_t* buffer, llarp_buffer_t* key);
/// start processig message from a link session
bool

@ -9,6 +9,8 @@
#include <util/logic.hpp>
#include <nodedb.hpp>
#include <functional>
namespace llarp
{
LR_CommitMessage::~LR_CommitMessage()
@ -113,47 +115,44 @@ namespace llarp
}
bool
LR_CommitRecord::OnKey(dict_reader* r, llarp_buffer_t* key)
LR_CommitRecord::OnKey(llarp_buffer_t* buffer, llarp_buffer_t* key)
{
if(!key)
return true;
LR_CommitRecord* self = static_cast< LR_CommitRecord* >(r->user);
bool read = false;
if(!BEncodeMaybeReadDictEntry("c", self->commkey, read, *key, r->buffer))
if(!BEncodeMaybeReadDictEntry("c", commkey, read, *key, buffer))
return false;
if(!BEncodeMaybeReadDictEntry("i", self->nextHop, read, *key, r->buffer))
if(!BEncodeMaybeReadDictEntry("i", nextHop, read, *key, buffer))
return false;
if(!BEncodeMaybeReadDictInt("l", self->lifetime, read, *key, r->buffer))
if(!BEncodeMaybeReadDictInt("l", lifetime, read, *key, buffer))
return false;
if(!BEncodeMaybeReadDictEntry("n", self->tunnelNonce, read, *key,
r->buffer))
if(!BEncodeMaybeReadDictEntry("n", tunnelNonce, read, *key, buffer))
return false;
if(!BEncodeMaybeReadDictEntry("r", self->rxid, read, *key, r->buffer))
if(!BEncodeMaybeReadDictEntry("r", rxid, read, *key, buffer))
return false;
if(!BEncodeMaybeReadDictEntry("t", self->txid, read, *key, r->buffer))
if(!BEncodeMaybeReadDictEntry("t", txid, read, *key, buffer))
return false;
if(*key == "u")
{
self->nextRC = std::make_unique< RouterContact >();
return self->nextRC->BDecode(r->buffer);
nextRC = std::make_unique< RouterContact >();
return nextRC->BDecode(buffer);
}
if(!BEncodeMaybeReadVersion("v", self->version, LLARP_PROTO_VERSION, read,
*key, r->buffer))
if(!BEncodeMaybeReadVersion("v", version, LLARP_PROTO_VERSION, read, *key,
buffer))
return false;
if(*key == "w")
{
// check for duplicate
if(self->work)
if(work)
{
llarp::LogWarn("duplicate POW in LRCR");
return false;
}
self->work = std::make_unique< PoW >();
return self->work->BDecode(r->buffer);
work = std::make_unique< PoW >();
return work->BDecode(buffer);
}
return read;
}
@ -161,10 +160,9 @@ namespace llarp
bool
LR_CommitRecord::BDecode(llarp_buffer_t* buf)
{
dict_reader r;
r.user = this;
r.on_key = &OnKey;
return bencode_read_dict(buf, &r);
using namespace std::placeholders;
return bencode_read_dict(std::bind(&LR_CommitRecord::OnKey, this, _1, _2),
buf);
}
bool

@ -41,8 +41,8 @@ namespace llarp
operator==(const LR_CommitRecord &other) const;
private:
static bool
OnKey(dict_reader *r, llarp_buffer_t *buf);
bool
OnKey(llarp_buffer_t *buffer, llarp_buffer_t *key);
};
struct LR_CommitMessage : public ILinkMessage

@ -32,12 +32,10 @@ namespace llarp
InboundMessageParser::InboundMessageParser()
: firstKey(false)
, key('\0')
, ourKey('\0')
, msg(nullptr)
, m_Holder(std::make_unique< MessageHolder >())
{
reader.user = this;
reader.on_key = &OnKey;
}
InboundMessageParser::~InboundMessageParser()
@ -45,76 +43,74 @@ namespace llarp
}
bool
InboundMessageParser::OnKey(dict_reader* r, llarp_buffer_t* key)
InboundMessageParser::operator()(llarp_buffer_t* buffer,
llarp_buffer_t* key)
{
InboundMessageParser* self =
static_cast< InboundMessageParser* >(r->user);
if(key == nullptr && self->firstKey)
if(key == nullptr && firstKey)
{
// empty dict
return false;
}
if(!key)
return true;
if(self->firstKey)
if(firstKey)
{
llarp_buffer_t strbuf;
if(!(*key == "A"))
return false;
if(!bencode_read_string(r->buffer, &strbuf))
if(!bencode_read_string(buffer, &strbuf))
return false;
if(strbuf.sz != 1)
return false;
self->key = *strbuf.cur;
LogDebug("routing message '", self->key, "'");
switch(self->key)
ourKey = *strbuf.cur;
LogDebug("routing message '", key, "'");
switch(ourKey)
{
case 'D':
self->msg = &self->m_Holder->D;
msg = &m_Holder->D;
break;
case 'L':
self->msg = &self->m_Holder->L;
msg = &m_Holder->L;
break;
case 'M':
self->msg = &self->m_Holder->M;
msg = &m_Holder->M;
break;
case 'P':
self->msg = &self->m_Holder->P;
msg = &m_Holder->P;
break;
case 'T':
self->msg = &self->m_Holder->T;
msg = &m_Holder->T;
break;
case 'H':
self->msg = &self->m_Holder->H;
msg = &m_Holder->H;
break;
case 'I':
self->msg = &self->m_Holder->I;
msg = &m_Holder->I;
break;
case 'G':
self->msg = &self->m_Holder->G;
msg = &m_Holder->G;
break;
case 'J':
self->msg = &self->m_Holder->J;
msg = &m_Holder->J;
break;
case 'O':
self->msg = &self->m_Holder->O;
msg = &m_Holder->O;
break;
case 'U':
self->msg = &self->m_Holder->U;
msg = &m_Holder->U;
break;
case 'C':
self->msg = &self->m_Holder->C;
msg = &m_Holder->C;
break;
default:
llarp::LogError("invalid routing message id: ", *strbuf.cur);
}
self->firstKey = false;
return self->msg != nullptr;
firstKey = false;
return msg != nullptr;
}
else
{
return self->msg->DecodeKey(*key, r->buffer);
return msg->DecodeKey(*key, buffer);
}
}
@ -129,13 +125,13 @@ namespace llarp
firstKey = true;
ManagedBuffer copiedBuf(buf);
auto& copy = copiedBuf.underlying;
if(bencode_read_dict(&copy, &reader))
if(bencode_read_dict(*this, &copy))
{
msg->from = from;
result = msg->HandleMessage(h, r);
if(!result)
{
llarp::LogWarn("Failed to handle inbound routing message ", key);
llarp::LogWarn("Failed to handle inbound routing message ", ourKey);
}
}
else

@ -25,13 +25,12 @@ namespace llarp
ParseMessageBuffer(const llarp_buffer_t& buf, IMessageHandler* handler,
const PathID_t& from, AbstractRouter* r);
private:
static bool
OnKey(dict_reader* r, llarp_buffer_t* key);
bool
operator()(llarp_buffer_t* buffer, llarp_buffer_t* key);
private:
bool firstKey;
char key;
dict_reader reader;
char ourKey;
struct MessageHolder;

@ -121,59 +121,3 @@ bencode_end(llarp_buffer_t* buff)
assert(std::distance(std::begin(letter), std::end(letter)) == 1);
return buff->write(std::begin(letter), std::end(letter));
}
bool
bencode_read_dict(llarp_buffer_t* buff, struct dict_reader* r)
{
if(buff->size_left() < 2) // minimum case is 'de'
return false;
llarp_buffer_t strbuf; // temporary buffer for current element
r->buffer = buff; // set up dict_reader
if(*r->buffer->cur != 'd') // ensure is a dictionary
return false;
r->buffer->cur++;
while(r->buffer->size_left() && *r->buffer->cur != 'e')
{
if(bencode_read_string(r->buffer, &strbuf))
{
if(!r->on_key(r, &strbuf)) // check for early abort
return false;
}
else
return false;
}
if(*r->buffer->cur != 'e')
{
llarp::LogWarn("reading dict not ending on 'e'");
// make sure we're at dictionary end
return false;
}
r->buffer->cur++;
return r->on_key(r, nullptr);
}
bool
bencode_read_list(llarp_buffer_t* buff, struct list_reader* r)
{
if(buff->size_left() < 2) // minimum case is 'le'
return false;
r->buffer = buff;
if(*r->buffer->cur != 'l') // ensure is a list
{
llarp::LogWarn("bencode::bencode_read_list - expecting list got ",
*r->buffer->cur);
return false;
}
r->buffer->cur++;
while(r->buffer->size_left() && *r->buffer->cur != 'e')
{
if(!r->on_item(r, true)) // check for early abort
return false;
}
if(*r->buffer->cur != 'e') // make sure we're at a list end
return false;
r->buffer->cur++;
return r->on_item(r, false);
}

@ -41,38 +41,4 @@ bencode_start_dict(llarp_buffer_t* buff);
bool
bencode_end(llarp_buffer_t* buff);
struct dict_reader
{
/// makes passing data into on_key easier
llarp_buffer_t* buffer;
/// not currently used, maybe used in the future to pass additional
/// information to on_key
void* user;
/**
* called when we got a key string, return true to continue iteration
* called with null key on done iterating
*/
std::function< bool(dict_reader*, llarp_buffer_t*) > on_key;
};
bool
bencode_read_dict(llarp_buffer_t* buff, struct dict_reader* r);
struct list_reader
{
/// makes passing data into on_item easier
llarp_buffer_t* buffer;
/// not currently used, maybe used in the future to pass additional
/// information to on_item
void* user;
/**
* called with true when we got an element, return true to continue iteration
* called with false on iteration completion
*/
std::function< bool(list_reader*, bool) > on_item;
};
bool
bencode_read_list(llarp_buffer_t* buff, struct list_reader* r);
#endif

@ -140,28 +140,6 @@ namespace llarp
return bencode_end(buf);
}
template < typename Array >
bool
BEncodeReadArray(Array& array, llarp_buffer_t* buf)
{
if(*buf->cur != 'l') // ensure is a list
return false;
buf->cur++;
size_t idx = 0;
while(buf->size_left() && *buf->cur != 'e')
{
if(idx >= array.size())
return false;
if(!array[idx++].BDecode(buf))
return false;
}
if(*buf->cur != 'e') // make sure we're at a list end
return false;
buf->cur++;
return true;
}
template < typename Iter >
bool
BEncodeWriteList(Iter itr, Iter end, llarp_buffer_t* buf)
@ -176,44 +154,97 @@ namespace llarp
return bencode_end(buf);
}
template < typename List_t >
template < typename Sink >
bool
BEncodeReadList(List_t& result, llarp_buffer_t* buf)
bencode_read_dict(Sink&& sink, llarp_buffer_t* buffer)
{
if(*buf->cur != 'l') // ensure is a list
if(buffer->size_left() < 2) // minimum case is 'de'
return false;
buf->cur++;
while(buf->size_left() && *buf->cur != 'e')
if(*buffer->cur != 'd') // ensure is a dictionary
return false;
buffer->cur++;
while(buffer->size_left() && *buffer->cur != 'e')
{
if(!result.emplace(result.end())->BDecode(buf))
llarp_buffer_t strbuf; // temporary buffer for current element
if(bencode_read_string(buffer, &strbuf))
{
if(!sink(buffer, &strbuf)) // check for early abort
return false;
}
else
return false;
}
if(*buf->cur != 'e') // make sure we're at a list end
if(*buffer->cur != 'e')
{
llarp::LogWarn("reading dict not ending on 'e'");
// make sure we're at dictionary end
return false;
buf->cur++;
return true;
}
buffer->cur++;
return sink(buffer, nullptr);
}
template < typename T >
template < typename Sink >
bool
BEncodeReadSet(std::set< T >& result, llarp_buffer_t* buf)
bencode_read_list(Sink&& sink, llarp_buffer_t* buffer)
{
if(*buf->cur != 'l') // ensure is a list
if(buffer->size_left() < 2) // minimum case is 'le'
return false;
if(*buffer->cur != 'l') // ensure is a list
{
llarp::LogWarn("bencode::bencode_read_list - expecting list got ",
*buffer->cur);
return false;
}
buf->cur++;
while(buf->size_left() && *buf->cur != 'e')
buffer->cur++;
while(buffer->size_left() && *buffer->cur != 'e')
{
T item;
if(!item.BDecode(buf))
if(!sink(buffer, true)) // check for early abort
return false;
return result.insert(item).second;
}
if(*buf->cur != 'e') // make sure we're at a list end
if(*buffer->cur != 'e') // make sure we're at a list end
return false;
buf->cur++;
return true;
buffer->cur++;
return sink(buffer, false);
}
template < typename Array >
bool
BEncodeReadArray(Array& array, llarp_buffer_t* buf)
{
size_t idx = 0;
return bencode_read_list(
[&array, &idx](llarp_buffer_t* buffer, bool has) {
if(has)
{
if(idx >= array.size())
return false;
if(!array[idx++].BDecode(buffer))
return false;
}
return true;
},
buf);
}
template < typename List_t >
bool
BEncodeReadList(List_t& result, llarp_buffer_t* buf)
{
return bencode_read_list(
[&result](llarp_buffer_t* buffer, bool has) {
if(has)
{
if(!result.emplace(result.end())->BDecode(buffer))
{
return false;
}
}
return true;
},
buf);
}
template < typename List_t >
@ -245,19 +276,16 @@ namespace llarp
virtual bool
BDecode(llarp_buffer_t* buf)
{
dict_reader r;
r.user = this;
r.on_key = &OnKey;
return bencode_read_dict(buf, &r);
return bencode_read_dict(*this, buf);
}
// TODO: check for shadowed values elsewhere
uint64_t version = 0;
static bool
OnKey(dict_reader* r, llarp_buffer_t* k)
bool
operator()(llarp_buffer_t* buffer, llarp_buffer_t* key)
{
return static_cast< IBEncodeMessage* >(r->user)->HandleKey(k, r->buffer);
return HandleKey(key, buffer);
}
bool

@ -387,15 +387,15 @@ TEST_P(DictReadTest, readtest)
std::vector< std::string > result;
dict_reader reader{nullptr, nullptr, [&](dict_reader*, llarp_buffer_t* buf) {
if(buf)
{
result.emplace_back(buf->base, buf->base + buf->sz);
}
return true;
}};
ASSERT_TRUE(bencode_read_dict(&buffer, &reader));
ASSERT_TRUE(llarp::bencode_read_dict(
[&](llarp_buffer_t*, llarp_buffer_t* key) {
if(key)
{
result.emplace_back(key->base, key->base + key->sz);
}
return true;
},
&buffer));
ASSERT_EQ(result, d.output);
}
@ -422,18 +422,17 @@ TEST_P(ListReadTest, readtest)
std::vector< std::string > result;
list_reader reader{nullptr, nullptr, [&](list_reader* r, bool cont) {
if(cont)
{
auto b = r->buffer;
llarp_buffer_t tmp;
bencode_read_string(b, &tmp);
result.emplace_back(tmp.base, tmp.base + tmp.sz);
}
return true;
}};
ASSERT_TRUE(bencode_read_list(&buffer, &reader));
ASSERT_TRUE(llarp::bencode_read_list(
[&](llarp_buffer_t* b, bool cont) {
if(cont)
{
llarp_buffer_t tmp;
bencode_read_string(b, &tmp);
result.emplace_back(tmp.base, tmp.base + tmp.sz);
}
return true;
},
&buffer));
ASSERT_EQ(result, d.output);
}
@ -446,8 +445,6 @@ INSTANTIATE_TEST_CASE_P(TestBencode, ListReadTest,
TEST(TestBencode, ReadDictEmptyBuffer)
{
llarp_buffer_t buf((byte_t*)nullptr, 0);
dict_reader reader;
reader.on_key = [](dict_reader*, llarp_buffer_t*) -> bool { return true; };
reader.user = nullptr;
ASSERT_FALSE(bencode_read_dict(&buf, &reader));
ASSERT_FALSE(llarp::bencode_read_dict(
[](llarp_buffer_t*, llarp_buffer_t*) { return true; }, &buf));
}

Loading…
Cancel
Save