mirror of https://github.com/oxen-io/lokinet
Merge branch 'master' of https://github.com/majestrate/llarp
commit
3f6a5c4ca5
@ -0,0 +1,129 @@
|
||||
#ifndef LLARP_ALIGNED_HPP
|
||||
#define LLARP_ALIGNED_HPP
|
||||
|
||||
#include <llarp/crypto.h>
|
||||
#include <sodium.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <llarp/logger.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
/// aligned buffer, sz must be multiple of 8 bytes
|
||||
template < size_t sz >
|
||||
struct AlignedBuffer
|
||||
{
|
||||
AlignedBuffer()
|
||||
{
|
||||
Zero();
|
||||
}
|
||||
|
||||
AlignedBuffer(const AlignedBuffer& other) : AlignedBuffer(other.data())
|
||||
{
|
||||
}
|
||||
|
||||
AlignedBuffer(const byte_t* data)
|
||||
{
|
||||
for(size_t idx = 0; idx < sz; ++idx)
|
||||
buf.b[idx] = data[idx];
|
||||
}
|
||||
|
||||
AlignedBuffer&
|
||||
operator=(const byte_t* data)
|
||||
{
|
||||
for(size_t idx = 0; idx < sz; ++idx)
|
||||
buf.b[idx] = data[idx];
|
||||
return *this;
|
||||
}
|
||||
|
||||
byte_t& operator[](size_t idx)
|
||||
{
|
||||
return buf.b[idx];
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const AlignedBuffer& self)
|
||||
{
|
||||
size_t idx = 0;
|
||||
out << std::hex << std::setw(2) << std::setfill('0');
|
||||
while(idx < sz)
|
||||
{
|
||||
out << (int)self.buf.b[idx++];
|
||||
}
|
||||
return out << std::dec << std::setw(0) << std::setfill(' ');
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const AlignedBuffer& other) const
|
||||
{
|
||||
return memcmp(data(), other.data(), sz) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const AlignedBuffer& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
size_t
|
||||
size() const
|
||||
{
|
||||
return sz;
|
||||
}
|
||||
|
||||
void
|
||||
Zero()
|
||||
{
|
||||
for(size_t idx = 0; sz < idx / 8; ++idx)
|
||||
buf.l[idx] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Randomize()
|
||||
{
|
||||
randombytes(buf.b, sz);
|
||||
}
|
||||
|
||||
byte_t*
|
||||
data()
|
||||
{
|
||||
return &buf.b[0];
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
data() const
|
||||
{
|
||||
return &buf.b[0];
|
||||
}
|
||||
|
||||
uint64_t*
|
||||
data_l()
|
||||
{
|
||||
return &buf.l[0];
|
||||
}
|
||||
|
||||
const uint64_t*
|
||||
data_l() const
|
||||
{
|
||||
return &buf.l[0];
|
||||
}
|
||||
|
||||
operator const byte_t*() const
|
||||
{
|
||||
return &buf.b[0];
|
||||
}
|
||||
|
||||
operator byte_t*()
|
||||
{
|
||||
return &buf.b[0];
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
byte_t b[sz];
|
||||
uint64_t l[sz / 8];
|
||||
} buf;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,296 @@
|
||||
#ifndef LLARP_DHT_HPP_
|
||||
#define LLARP_DHT_HPP_
|
||||
#include <llarp/buffer.h>
|
||||
#include <llarp/dht.h>
|
||||
#include <llarp/router.h>
|
||||
#include <llarp/router_contact.h>
|
||||
#include <llarp/time.h>
|
||||
#include <llarp/aligned.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
const size_t MAX_MSG_SIZE = 2048;
|
||||
|
||||
struct Key_t : public llarp::AlignedBuffer< 32 >
|
||||
{
|
||||
Key_t(const byte_t* val) : llarp::AlignedBuffer< 32 >(val)
|
||||
{
|
||||
}
|
||||
|
||||
Key_t() : llarp::AlignedBuffer< 32 >()
|
||||
{
|
||||
}
|
||||
|
||||
Key_t
|
||||
operator^(const Key_t& other) const
|
||||
{
|
||||
Key_t dist;
|
||||
for(size_t idx = 0; idx < 32; ++idx)
|
||||
dist[idx] = (*this)[idx] ^ other[idx];
|
||||
return dist;
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const Key_t& other) const
|
||||
{
|
||||
return memcmp(data_l(), other.data_l(), 32) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
llarp_rc* rc;
|
||||
|
||||
Key_t ID;
|
||||
|
||||
Node() : rc(nullptr)
|
||||
{
|
||||
ID.Zero();
|
||||
}
|
||||
|
||||
Node(llarp_rc* other) : rc(other)
|
||||
{
|
||||
ID = other->pubkey;
|
||||
}
|
||||
};
|
||||
|
||||
struct SearchJob
|
||||
{
|
||||
const static uint64_t JobTimeout = 30000;
|
||||
|
||||
SearchJob();
|
||||
|
||||
SearchJob(const Key_t& requestor, const Key_t& target,
|
||||
llarp_router_lookup_job* job);
|
||||
|
||||
void
|
||||
Completed(const llarp_rc* router, bool timeout = false) const;
|
||||
|
||||
bool
|
||||
IsExpired(llarp_time_t now) const;
|
||||
|
||||
private:
|
||||
llarp_time_t started;
|
||||
Key_t requestor;
|
||||
Key_t target;
|
||||
llarp_router_lookup_job* job;
|
||||
};
|
||||
|
||||
struct XorMetric
|
||||
{
|
||||
const Key_t& us;
|
||||
|
||||
XorMetric(const Key_t& ourKey) : us(ourKey){};
|
||||
|
||||
bool
|
||||
operator()(const Key_t& left, const Key_t& right) const
|
||||
{
|
||||
return (us ^ left) < right;
|
||||
};
|
||||
};
|
||||
|
||||
struct IMessage
|
||||
{
|
||||
virtual ~IMessage(){};
|
||||
|
||||
IMessage(const Key_t& from) : From(from)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool
|
||||
BEncode(llarp_buffer_t* buf) const = 0;
|
||||
|
||||
virtual bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val) = 0;
|
||||
|
||||
virtual bool
|
||||
HandleMessage(llarp_router* router,
|
||||
std::vector< IMessage* >& replies) const = 0;
|
||||
|
||||
Key_t From;
|
||||
};
|
||||
|
||||
IMessage*
|
||||
DecodeMessage(const Key_t& from, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
DecodeMesssageList(const Key_t& from, llarp_buffer_t* buf,
|
||||
std::vector< IMessage* >& dst);
|
||||
|
||||
struct Bucket
|
||||
{
|
||||
typedef std::map< Key_t, Node, XorMetric > BucketStorage_t;
|
||||
|
||||
Bucket(const Key_t& us) : nodes(XorMetric(us)){};
|
||||
|
||||
bool
|
||||
FindClosest(const Key_t& target, Key_t& result) const;
|
||||
|
||||
bool
|
||||
FindCloseExcluding(const Key_t& target, Key_t& result,
|
||||
const Key_t& exclude) const;
|
||||
|
||||
BucketStorage_t nodes;
|
||||
};
|
||||
|
||||
struct Context
|
||||
{
|
||||
Context();
|
||||
~Context();
|
||||
|
||||
llarp_dht_msg_handler custom_handler = nullptr;
|
||||
|
||||
SearchJob*
|
||||
FindPendingTX(const Key_t& owner, uint64_t txid);
|
||||
|
||||
void
|
||||
RemovePendingLookup(const Key_t& owner, uint64_t txid);
|
||||
|
||||
void
|
||||
LookupRouter(const Key_t& target, const Key_t& whoasked,
|
||||
const Key_t& askpeer,
|
||||
llarp_router_lookup_job* job = nullptr);
|
||||
|
||||
void
|
||||
LookupRouterViaJob(llarp_router_lookup_job* job);
|
||||
|
||||
void
|
||||
LookupRouterRelayed(const Key_t& requester, uint64_t txid,
|
||||
const Key_t& target,
|
||||
std::vector< IMessage* >& replies);
|
||||
|
||||
void
|
||||
Init(const Key_t& us, llarp_router* router);
|
||||
|
||||
void
|
||||
QueueRouterLookup(llarp_router_lookup_job* job);
|
||||
|
||||
static void
|
||||
handle_cleaner_timer(void* user, uint64_t orig, uint64_t left);
|
||||
|
||||
static void
|
||||
queue_router_lookup(void* user);
|
||||
|
||||
llarp_router* router = nullptr;
|
||||
Bucket* nodes = nullptr;
|
||||
|
||||
private:
|
||||
void
|
||||
ScheduleCleanupTimer();
|
||||
|
||||
void
|
||||
CleanupTX();
|
||||
|
||||
uint64_t ids;
|
||||
|
||||
struct TXOwner
|
||||
{
|
||||
Key_t requester = {0};
|
||||
uint64_t txid = 0;
|
||||
|
||||
bool
|
||||
operator==(const TXOwner& other) const
|
||||
{
|
||||
return txid == other.txid && requester == other.requester;
|
||||
}
|
||||
bool
|
||||
operator<(const TXOwner& other) const
|
||||
{
|
||||
return txid < other.txid && requester < other.requester;
|
||||
}
|
||||
};
|
||||
|
||||
struct TXOwnerHash
|
||||
{
|
||||
std::size_t
|
||||
operator()(TXOwner const& o) const noexcept
|
||||
{
|
||||
std::size_t sz2;
|
||||
memcpy(&sz2, &o.requester[0], sizeof(std::size_t));
|
||||
return o.txid ^ (sz2 << 1);
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map< TXOwner, SearchJob, TXOwnerHash > pendingTX;
|
||||
Key_t ourKey;
|
||||
};
|
||||
|
||||
struct GotRouterMessage : public IMessage
|
||||
{
|
||||
GotRouterMessage(const Key_t& from) : IMessage(from)
|
||||
{
|
||||
}
|
||||
GotRouterMessage(const Key_t& from, uint64_t id, const llarp_rc* result)
|
||||
: IMessage(from), txid(id)
|
||||
{
|
||||
if(result)
|
||||
{
|
||||
R.emplace_back();
|
||||
llarp_rc_clear(&R.back());
|
||||
llarp_rc_copy(&R.back(), result);
|
||||
}
|
||||
}
|
||||
|
||||
~GotRouterMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
bool
|
||||
HandleMessage(llarp_router* router,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
|
||||
std::vector< llarp_rc > R;
|
||||
uint64_t txid = 0;
|
||||
uint64_t version = 0;
|
||||
};
|
||||
|
||||
struct FindRouterMessage : public IMessage
|
||||
{
|
||||
FindRouterMessage(const Key_t& from) : IMessage(from)
|
||||
{
|
||||
}
|
||||
|
||||
FindRouterMessage(const Key_t& from, const Key_t& target, uint64_t id)
|
||||
: IMessage(from), K(target), txid(id)
|
||||
{
|
||||
}
|
||||
|
||||
~FindRouterMessage();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
||||
bool
|
||||
HandleMessage(llarp_router* router,
|
||||
std::vector< IMessage* >& replies) const;
|
||||
|
||||
Key_t K;
|
||||
uint64_t txid = 0;
|
||||
uint64_t version = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
struct llarp_dht_context
|
||||
{
|
||||
llarp::dht::Context impl;
|
||||
llarp_router* parent;
|
||||
llarp_dht_context(llarp_router* router);
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,30 @@
|
||||
#ifndef LLARP_MESSAGES_DHT_IMMEDIATE_HPP
|
||||
#define LLARP_MESSAGES_DHT_IMMEDIATE_HPP
|
||||
#include <llarp/dht.hpp>
|
||||
#include <llarp/link_message.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct DHTImmeidateMessage : public ILinkMessage
|
||||
{
|
||||
DHTImmeidateMessage(const RouterID& from) : ILinkMessage(from)
|
||||
{
|
||||
}
|
||||
|
||||
~DHTImmeidateMessage();
|
||||
|
||||
std::vector< llarp::dht::IMessage* > msgs;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
HandleMessage(llarp_router* router) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,27 @@
|
||||
#ifndef LLARP_MESSAGES_LINK_INTRO_HPP
|
||||
#define LLARP_MESSAGES_LINK_INTRO_HPP
|
||||
#include <llarp/link_message.hpp>
|
||||
namespace llarp
|
||||
{
|
||||
struct LinkIntroMessage : public ILinkMessage
|
||||
{
|
||||
LinkIntroMessage(llarp_rc* rc) : ILinkMessage({}), RC(rc)
|
||||
{
|
||||
}
|
||||
|
||||
~LinkIntroMessage();
|
||||
|
||||
llarp_rc* RC;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
HandleMessage(llarp_router* router) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,160 @@
|
||||
#include <llarp/bencode.h>
|
||||
|
||||
bool
|
||||
bencode_write_bytestring(llarp_buffer_t* buff, const void* data, size_t sz)
|
||||
{
|
||||
if(!llarp_buffer_writef(buff, "%ld:", sz))
|
||||
return false;
|
||||
return llarp_buffer_write(buff, data, sz);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_write_int(llarp_buffer_t* buff, int i)
|
||||
{
|
||||
return llarp_buffer_writef(buff, "i%de", i);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_write_uint16(llarp_buffer_t* buff, uint16_t i)
|
||||
{
|
||||
return llarp_buffer_writef(buff, "i%de", i);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_write_int64(llarp_buffer_t* buff, int64_t i)
|
||||
{
|
||||
return llarp_buffer_writef(buff, "i%lde", i);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_write_uint64(llarp_buffer_t* buff, uint64_t i)
|
||||
{
|
||||
return llarp_buffer_writef(buff, "i%lde", i);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_write_sizeint(llarp_buffer_t* buff, size_t i)
|
||||
{
|
||||
return llarp_buffer_writef(buff, "i%lde", i);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_start_list(llarp_buffer_t* buff)
|
||||
{
|
||||
return llarp_buffer_write(buff, "l", 1);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_start_dict(llarp_buffer_t* buff)
|
||||
{
|
||||
return llarp_buffer_write(buff, "d", 1);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_end(llarp_buffer_t* buff)
|
||||
{
|
||||
return llarp_buffer_write(buff, "e", 1);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_write_version_entry(llarp_buffer_t* buff)
|
||||
{
|
||||
return llarp_buffer_writef(buff, "1:vi%de", LLARP_PROTO_VERSION);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_read_integer(struct llarp_buffer_t* buffer, uint64_t* result)
|
||||
{
|
||||
size_t len;
|
||||
if(*buffer->cur != 'i')
|
||||
return false;
|
||||
|
||||
char numbuf[32];
|
||||
|
||||
buffer->cur++;
|
||||
|
||||
len =
|
||||
llarp_buffer_read_until(buffer, 'e', (byte_t*)numbuf, sizeof(numbuf) - 1);
|
||||
if(!len)
|
||||
return false;
|
||||
|
||||
buffer->cur++;
|
||||
|
||||
numbuf[len] = 0;
|
||||
*result = atol(numbuf);
|
||||
return *result != -1;
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_read_string(llarp_buffer_t* buffer, llarp_buffer_t* result)
|
||||
{
|
||||
size_t len, slen;
|
||||
int num;
|
||||
char numbuf[10];
|
||||
|
||||
len =
|
||||
llarp_buffer_read_until(buffer, ':', (byte_t*)numbuf, sizeof(numbuf) - 1);
|
||||
if(!len)
|
||||
return false;
|
||||
|
||||
numbuf[len] = 0;
|
||||
num = atoi(numbuf);
|
||||
if(num < 0)
|
||||
return false;
|
||||
|
||||
slen = num;
|
||||
|
||||
buffer->cur++;
|
||||
|
||||
len = llarp_buffer_size_left(*buffer);
|
||||
if(len < slen)
|
||||
return false;
|
||||
|
||||
result->base = buffer->cur;
|
||||
result->cur = buffer->cur;
|
||||
result->sz = slen;
|
||||
buffer->cur += slen;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_read_dict(llarp_buffer_t* buff, struct dict_reader* r)
|
||||
{
|
||||
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(llarp_buffer_size_left(*r->buffer) && *r->buffer->cur != 'e')
|
||||
{
|
||||
if(bencode_read_string(r->buffer, &strbuf))
|
||||
{
|
||||
if(!r->on_key(r, &strbuf)) // check for early abort
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(*r->buffer->cur != 'e') // make sure we're at dictionary end
|
||||
return false;
|
||||
r->buffer->cur++;
|
||||
return r->on_key(r, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
bencode_read_list(llarp_buffer_t* buff, struct list_reader* r)
|
||||
{
|
||||
r->buffer = buff;
|
||||
if(*r->buffer->cur != 'l') // ensure is a list
|
||||
return false;
|
||||
|
||||
r->buffer->cur++;
|
||||
while(llarp_buffer_size_left(*r->buffer) && *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);
|
||||
}
|
@ -0,0 +1,572 @@
|
||||
#include <llarp/bencode.h>
|
||||
#include <llarp/dht.hpp>
|
||||
#include <llarp/messages/dht_immediate.hpp>
|
||||
#include "router.hpp"
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
DHTImmeidateMessage::~DHTImmeidateMessage()
|
||||
{
|
||||
for(auto &msg : msgs)
|
||||
delete msg;
|
||||
msgs.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "m"))
|
||||
return llarp::dht::DecodeMesssageList(remote.data(), buf, msgs);
|
||||
if(llarp_buffer_eq(key, "v"))
|
||||
{
|
||||
if(!bencode_read_integer(buf, &version))
|
||||
return false;
|
||||
return version == LLARP_PROTO_VERSION;
|
||||
}
|
||||
// bad key
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message type
|
||||
if(!bencode_write_bytestring(buf, "a", 1))
|
||||
return false;
|
||||
if(!bencode_write_bytestring(buf, "m", 1))
|
||||
return false;
|
||||
|
||||
// dht messages
|
||||
if(!bencode_write_bytestring(buf, "m", 1))
|
||||
return false;
|
||||
// begin list
|
||||
if(!bencode_start_list(buf))
|
||||
return false;
|
||||
for(const auto &msg : msgs)
|
||||
{
|
||||
if(!msg->BEncode(buf))
|
||||
return false;
|
||||
}
|
||||
// end list
|
||||
if(!bencode_end(buf))
|
||||
return false;
|
||||
|
||||
// protocol version
|
||||
if(!bencode_write_version_entry(buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
DHTImmeidateMessage::HandleMessage(llarp_router *router) const
|
||||
{
|
||||
DHTImmeidateMessage *reply = new DHTImmeidateMessage(remote);
|
||||
bool result = true;
|
||||
for(auto &msg : msgs)
|
||||
{
|
||||
result &= msg->HandleMessage(router, reply->msgs);
|
||||
}
|
||||
return result && router->SendToOrQueue(remote.data(), {reply});
|
||||
}
|
||||
|
||||
namespace dht
|
||||
{
|
||||
GotRouterMessage::~GotRouterMessage()
|
||||
{
|
||||
for(auto &rc : R)
|
||||
llarp_rc_free(&rc);
|
||||
R.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::HandleMessage(llarp_router *router,
|
||||
std::vector< IMessage * > &replies) const
|
||||
{
|
||||
auto &dht = router->dht->impl;
|
||||
auto pending = dht.FindPendingTX(From, txid);
|
||||
if(pending)
|
||||
{
|
||||
if(R.size())
|
||||
pending->Completed(&R[0]);
|
||||
else
|
||||
pending->Completed(nullptr);
|
||||
|
||||
dht.RemovePendingLookup(From, txid);
|
||||
return true;
|
||||
}
|
||||
llarp::Warn("Got response for DHT transaction we are not tracking, txid=",
|
||||
txid);
|
||||
return false;
|
||||
}
|
||||
|
||||
FindRouterMessage::~FindRouterMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
FindRouterMessage::BEncode(llarp_buffer_t *buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message type
|
||||
if(!bencode_write_bytestring(buf, "A", 1))
|
||||
return false;
|
||||
if(!bencode_write_bytestring(buf, "R", 1))
|
||||
return false;
|
||||
|
||||
// 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, "K"))
|
||||
{
|
||||
if(!bencode_read_string(val, &strbuf))
|
||||
return false;
|
||||
if(strbuf.sz != K.size())
|
||||
return false;
|
||||
|
||||
memcpy(K.data(), strbuf.base, K.size());
|
||||
return true;
|
||||
}
|
||||
if(llarp_buffer_eq(key, "T"))
|
||||
{
|
||||
return bencode_read_integer(val, &txid);
|
||||
}
|
||||
if(llarp_buffer_eq(key, "V"))
|
||||
{
|
||||
return bencode_read_integer(val, &version);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
FindRouterMessage::HandleMessage(llarp_router *router,
|
||||
std::vector< IMessage * > &replies) const
|
||||
{
|
||||
auto &dht = router->dht->impl;
|
||||
auto pending = dht.FindPendingTX(From, txid);
|
||||
if(pending)
|
||||
{
|
||||
llarp::Warn("Got duplicate DHT lookup from ", From, " txid=", txid);
|
||||
return false;
|
||||
}
|
||||
dht.LookupRouterRelayed(From, txid, K, replies);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct MessageDecoder
|
||||
{
|
||||
const Key_t &From;
|
||||
bool firstKey = true;
|
||||
IMessage *msg = nullptr;
|
||||
|
||||
MessageDecoder(const Key_t &from) : From(from)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
on_key(dict_reader *r, llarp_buffer_t *key)
|
||||
{
|
||||
llarp_buffer_t strbuf;
|
||||
MessageDecoder *dec = static_cast< MessageDecoder * >(r->user);
|
||||
// check for empty dict
|
||||
if(!key)
|
||||
return !dec->firstKey;
|
||||
|
||||
// first key
|
||||
if(dec->firstKey)
|
||||
{
|
||||
if(!llarp_buffer_eq(*key, "A"))
|
||||
return false;
|
||||
if(!bencode_read_string(r->buffer, &strbuf))
|
||||
return false;
|
||||
// bad msg size?
|
||||
if(strbuf.sz != 1)
|
||||
return false;
|
||||
switch(*strbuf.base)
|
||||
{
|
||||
case 'R':
|
||||
dec->msg = new FindRouterMessage(dec->From);
|
||||
break;
|
||||
case 'S':
|
||||
dec->msg = new GotRouterMessage(dec->From);
|
||||
break;
|
||||
default:
|
||||
llarp::Warn("unknown dht message type: ", (char)*strbuf.base);
|
||||
// bad msg type
|
||||
return false;
|
||||
}
|
||||
dec->firstKey = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return dec->msg->DecodeKey(*key, r->buffer);
|
||||
}
|
||||
};
|
||||
|
||||
IMessage *
|
||||
DecodeMesssage(const Key_t &from, llarp_buffer_t *buf)
|
||||
{
|
||||
MessageDecoder dec(from);
|
||||
dict_reader r;
|
||||
r.user = &dec;
|
||||
r.on_key = &MessageDecoder::on_key;
|
||||
if(bencode_read_dict(buf, &r))
|
||||
return dec.msg;
|
||||
else
|
||||
{
|
||||
if(dec.msg)
|
||||
delete dec.msg;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
struct ListDecoder
|
||||
{
|
||||
ListDecoder(const Key_t &from, std::vector< IMessage * > &list)
|
||||
: From(from), l(list){};
|
||||
|
||||
const Key_t &From;
|
||||
std::vector< IMessage * > &l;
|
||||
|
||||
static bool
|
||||
on_item(list_reader *r, bool has)
|
||||
{
|
||||
ListDecoder *dec = static_cast< ListDecoder * >(r->user);
|
||||
if(!has)
|
||||
return true;
|
||||
auto msg = DecodeMesssage(dec->From, r->buffer);
|
||||
if(msg)
|
||||
{
|
||||
dec->l.push_back(msg);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
DecodeMesssageList(const Key_t &from, llarp_buffer_t *buf,
|
||||
std::vector< IMessage * > &list)
|
||||
{
|
||||
ListDecoder dec(from, list);
|
||||
|
||||
list_reader r;
|
||||
r.user = &dec;
|
||||
r.on_item = &ListDecoder::on_item;
|
||||
return bencode_read_list(buf, &r);
|
||||
}
|
||||
|
||||
SearchJob::SearchJob()
|
||||
{
|
||||
started = 0;
|
||||
requestor.Zero();
|
||||
target.Zero();
|
||||
}
|
||||
|
||||
SearchJob::SearchJob(const Key_t &asker, const Key_t &key,
|
||||
llarp_router_lookup_job *j)
|
||||
: started(llarp_time_now_ms()), requestor(asker), target(key), job(j)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SearchJob::Completed(const llarp_rc *router, bool timeout) const
|
||||
{
|
||||
if(job && job->hook)
|
||||
{
|
||||
if(router)
|
||||
{
|
||||
job->found = true;
|
||||
llarp_rc_copy(&job->result, router);
|
||||
}
|
||||
job->hook(job);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SearchJob::IsExpired(llarp_time_t now) const
|
||||
{
|
||||
return now - started >= JobTimeout;
|
||||
}
|
||||
|
||||
bool
|
||||
Bucket::FindClosest(const Key_t &target, Key_t &result) const
|
||||
{
|
||||
auto itr = nodes.lower_bound(target);
|
||||
if(itr == nodes.end())
|
||||
return false;
|
||||
|
||||
result = itr->second.ID;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Bucket::FindCloseExcluding(const Key_t &target, Key_t &result,
|
||||
const Key_t &exclude) const
|
||||
{
|
||||
auto itr = nodes.lower_bound(target);
|
||||
if(itr == nodes.end())
|
||||
return false;
|
||||
if(itr->second.ID == exclude)
|
||||
++itr;
|
||||
if(itr == nodes.end())
|
||||
return false;
|
||||
result = itr->second.ID;
|
||||
return true;
|
||||
}
|
||||
|
||||
Context::Context()
|
||||
{
|
||||
randombytes((byte_t *)&ids, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
if(nodes)
|
||||
delete nodes;
|
||||
}
|
||||
|
||||
void
|
||||
Context::handle_cleaner_timer(void *u, uint64_t orig, uint64_t left)
|
||||
{
|
||||
if(left)
|
||||
return;
|
||||
Context *ctx = static_cast< Context * >(u);
|
||||
|
||||
ctx->CleanupTX();
|
||||
}
|
||||
|
||||
void
|
||||
Context::LookupRouterRelayed(const Key_t &requester, uint64_t txid,
|
||||
const Key_t &target,
|
||||
std::vector< IMessage * > &replies)
|
||||
{
|
||||
if(target == ourKey)
|
||||
{
|
||||
// we are the target, give them our RC
|
||||
replies.push_back(new GotRouterMessage(requester, txid, &router->rc));
|
||||
return;
|
||||
}
|
||||
Key_t next = ourKey;
|
||||
nodes->FindClosest(target, next);
|
||||
if(next == ourKey)
|
||||
{
|
||||
// we are closest and don't have a match
|
||||
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
|
||||
return;
|
||||
}
|
||||
if(next == target)
|
||||
{
|
||||
// we know it
|
||||
replies.push_back(
|
||||
new GotRouterMessage(requester, txid, nodes->nodes[target].rc));
|
||||
return;
|
||||
}
|
||||
|
||||
// ask neighbor
|
||||
LookupRouter(target, requester, next);
|
||||
}
|
||||
|
||||
void
|
||||
Context::RemovePendingLookup(const Key_t &owner, uint64_t id)
|
||||
{
|
||||
auto itr = pendingTX.find({owner, id});
|
||||
if(itr == pendingTX.end())
|
||||
return;
|
||||
pendingTX.erase(itr);
|
||||
}
|
||||
|
||||
SearchJob *
|
||||
Context::FindPendingTX(const Key_t &owner, uint64_t id)
|
||||
{
|
||||
auto itr = pendingTX.find({owner, id});
|
||||
if(itr == pendingTX.end())
|
||||
return nullptr;
|
||||
else
|
||||
return &itr->second;
|
||||
}
|
||||
|
||||
void
|
||||
Context::CleanupTX()
|
||||
{
|
||||
auto now = llarp_time_now_ms();
|
||||
std::set< TXOwner > expired;
|
||||
|
||||
for(auto &item : pendingTX)
|
||||
if(item.second.IsExpired(now))
|
||||
expired.insert(item.first);
|
||||
|
||||
for(const auto &e : expired)
|
||||
{
|
||||
pendingTX[e].Completed(nullptr, true);
|
||||
RemovePendingLookup(e.requester, e.txid);
|
||||
if(e.requester != ourKey)
|
||||
{
|
||||
// inform not found
|
||||
auto msg = new llarp::DHTImmeidateMessage(e.requester);
|
||||
msg->msgs.push_back(
|
||||
new GotRouterMessage(e.requester, e.txid, nullptr));
|
||||
router->SendToOrQueue(e.requester, {msg});
|
||||
}
|
||||
}
|
||||
|
||||
ScheduleCleanupTimer();
|
||||
}
|
||||
|
||||
void
|
||||
Context::Init(const Key_t &us, llarp_router *r)
|
||||
{
|
||||
router = r;
|
||||
ourKey = us;
|
||||
nodes = new Bucket(ourKey);
|
||||
llarp::Debug("intialize dht with key ", ourKey);
|
||||
}
|
||||
|
||||
void
|
||||
Context::ScheduleCleanupTimer()
|
||||
{
|
||||
llarp_logic_call_later(router->logic,
|
||||
{1000, this, &handle_cleaner_timer});
|
||||
}
|
||||
|
||||
void
|
||||
Context::LookupRouter(const Key_t &target, const Key_t &whoasked,
|
||||
const Key_t &askpeer, llarp_router_lookup_job *job)
|
||||
{
|
||||
auto id = ++ids;
|
||||
pendingTX[{whoasked, id}] = SearchJob(whoasked, target, job);
|
||||
|
||||
llarp::Info("Asking ", askpeer, " for router ", target, " for ",
|
||||
whoasked);
|
||||
auto msg = new llarp::DHTImmeidateMessage(askpeer);
|
||||
msg->msgs.push_back(new FindRouterMessage(askpeer, target, id));
|
||||
router->SendToOrQueue(askpeer, {msg});
|
||||
}
|
||||
|
||||
void
|
||||
Context::LookupRouterViaJob(llarp_router_lookup_job *job)
|
||||
{
|
||||
Key_t peer;
|
||||
if(nodes->FindCloseExcluding(job->target, peer, ourKey))
|
||||
LookupRouter(job->target, ourKey, peer, job);
|
||||
else if(job->hook)
|
||||
{
|
||||
job->found = false;
|
||||
job->hook(job);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Context::queue_router_lookup(void *user)
|
||||
{
|
||||
llarp_router_lookup_job *job =
|
||||
static_cast< llarp_router_lookup_job * >(user);
|
||||
job->dht->impl.LookupRouterViaJob(job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llarp_dht_context::llarp_dht_context(llarp_router *router)
|
||||
{
|
||||
parent = router;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct llarp_dht_context *
|
||||
llarp_dht_context_new(struct llarp_router *router)
|
||||
{
|
||||
return new llarp_dht_context(router);
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_context_free(struct llarp_dht_context *ctx)
|
||||
{
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_put_local_router(struct llarp_dht_context *ctx, struct llarp_rc *rc)
|
||||
|
||||
{
|
||||
llarp::dht::Key_t k = rc->pubkey;
|
||||
llarp::Debug("put router at ", k);
|
||||
ctx->impl.nodes->nodes[k] = rc;
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_remove_local_router(struct llarp_dht_context *ctx, const byte_t *id)
|
||||
{
|
||||
auto &nodes = ctx->impl.nodes->nodes;
|
||||
auto itr = nodes.find(id);
|
||||
if(itr == nodes.end())
|
||||
return;
|
||||
nodes.erase(itr);
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_set_msg_handler(struct llarp_dht_context *ctx,
|
||||
llarp_dht_msg_handler handler)
|
||||
{
|
||||
ctx->impl.custom_handler = handler;
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_context_start(struct llarp_dht_context *ctx, const byte_t *key)
|
||||
{
|
||||
ctx->impl.Init(key, ctx->parent);
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dh_lookup_router(struct llarp_dht_context *ctx,
|
||||
struct llarp_router_lookup_job *job)
|
||||
{
|
||||
job->dht = ctx;
|
||||
llarp_logic_queue_job(ctx->parent->logic,
|
||||
{job, &llarp::dht::Context::queue_router_lookup});
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
#include <llarp/bencode.h>
|
||||
#include <llarp/router_contact.h>
|
||||
#include <llarp/messages/link_intro.hpp>
|
||||
#include "logger.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
LinkIntroMessage::~LinkIntroMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
LinkIntroMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf)
|
||||
{
|
||||
if(llarp_buffer_eq(key, "r"))
|
||||
{
|
||||
if(!llarp_rc_bdecode(RC, buf))
|
||||
{
|
||||
llarp::Warn("failed to decode RC");
|
||||
return false;
|
||||
}
|
||||
remote = (byte_t*)RC->pubkey;
|
||||
llarp::Debug("decoded RC from ", remote);
|
||||
return true;
|
||||
}
|
||||
else if(llarp_buffer_eq(key, "v"))
|
||||
{
|
||||
if(!bencode_read_integer(buf, &version))
|
||||
return false;
|
||||
if(version != LLARP_PROTO_VERSION)
|
||||
{
|
||||
llarp::Warn("llarp protocol version missmatch ", version,
|
||||
" != ", LLARP_PROTO_VERSION);
|
||||
return false;
|
||||
}
|
||||
llarp::Debug("LIM version ", version);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::Warn("invalid LIM key: ", *key.cur);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LinkIntroMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
if(!bencode_write_bytestring(buf, "a", 1))
|
||||
return false;
|
||||
if(!bencode_write_bytestring(buf, "i", 1))
|
||||
return false;
|
||||
|
||||
if(RC)
|
||||
{
|
||||
if(!bencode_write_bytestring(buf, "r", 1))
|
||||
return false;
|
||||
if(!llarp_rc_bencode(RC, buf))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!bencode_write_version_entry(buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
LinkIntroMessage::HandleMessage(llarp_router* router) const
|
||||
{
|
||||
llarp::Info("got LIM from ", remote);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#include <llarp/messages/relay_commit.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
LR_CommitMessage::~LR_CommitMessage()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
LR_CommitMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf)
|
||||
{
|
||||
// TODO: implement
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
LR_CommitMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
// TODO: implement
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
LR_CommitMessage::HandleMessage(llarp_router* router) const
|
||||
{
|
||||
// TODO: implement
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
#include <llarp/crypto_async.h>
|
||||
#include <llarp/mem.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct bench_main {
|
||||
size_t completed;
|
||||
size_t num;
|
||||
size_t jobs;
|
||||
struct llarp_threadpool *pool;
|
||||
struct llarp_async_cipher *cipher;
|
||||
struct llarp_crypto crypto;
|
||||
};
|
||||
|
||||
static void handle_cipher_complete(struct llarp_cipher_result *res) {
|
||||
struct bench_main *m = (struct bench_main *)res->user;
|
||||
size_t sz = m->jobs;
|
||||
m->completed++;
|
||||
size_t left = m->num - m->completed;
|
||||
if (m->completed % 10000 == 0)
|
||||
printf("completed %ld and %ld left\n", m->completed, left);
|
||||
if (m->completed == m->num) {
|
||||
llarp_threadpool_stop(m->pool);
|
||||
printf("done\n");
|
||||
} else if (m->completed % sz == 0) {
|
||||
llarp_nounce_t nounce;
|
||||
while (sz--) {
|
||||
m->crypto.randbytes(nounce, sizeof(llarp_nounce_t));
|
||||
llarp_async_cipher_queue_op(m->cipher, &res->buff, nounce,
|
||||
handle_cipher_complete, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct bench_main b_main;
|
||||
struct llarp_threadpool *tp;
|
||||
|
||||
llarp_mem_stdlib();
|
||||
llarp_crypto_libsodium_init(&b_main.crypto);
|
||||
b_main.pool = llarp_init_threadpool(1);
|
||||
llarp_threadpool_start(b_main.pool);
|
||||
tp = llarp_init_threadpool(8);
|
||||
|
||||
b_main.num = 5000000;
|
||||
b_main.jobs = 5000;
|
||||
b_main.completed = 0;
|
||||
llarp_sharedkey_t key;
|
||||
b_main.crypto.randbytes(key, sizeof(llarp_sharedkey_t));
|
||||
|
||||
b_main.cipher = llarp_async_cipher_new(key, &b_main.crypto, b_main.pool, tp);
|
||||
llarp_threadpool_start(tp);
|
||||
|
||||
llarp_nounce_t nounce;
|
||||
llarp_buffer_t n_buff;
|
||||
n_buff.base = nounce;
|
||||
n_buff.cur = n_buff.base;
|
||||
n_buff.sz = sizeof(llarp_nounce_t);
|
||||
size_t sz = b_main.jobs;
|
||||
printf("starting %ld jobs\n", sz);
|
||||
/* do work here */
|
||||
while (sz--) {
|
||||
llarp_buffer_t *msg = llarp_g_mem.alloc(sizeof(llarp_buffer_t), 8);
|
||||
msg->base = llarp_g_mem.alloc(1024, 1024);
|
||||
msg->sz = 1024;
|
||||
msg->cur = msg->base;
|
||||
b_main.crypto.randomize(*msg);
|
||||
b_main.crypto.randbytes(nounce, sizeof(llarp_nounce_t));
|
||||
llarp_async_cipher_queue_op(b_main.cipher, msg, nounce,
|
||||
handle_cipher_complete, &b_main);
|
||||
}
|
||||
printf("started %ld jobs\n", b_main.jobs);
|
||||
llarp_threadpool_wait(b_main.pool);
|
||||
llarp_threadpool_join(b_main.pool);
|
||||
llarp_threadpool_stop(tp);
|
||||
llarp_threadpool_join(tp);
|
||||
llarp_free_threadpool(&tp);
|
||||
llarp_free_threadpool(&b_main.pool);
|
||||
llarp_async_cipher_free(&b_main.cipher);
|
||||
printf("did %ld of %ld work\n", b_main.completed, b_main.num);
|
||||
return 0;
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
#include <llarp/crypto_async.h>
|
||||
#include <llarp/mem.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct dh_bench_main {
|
||||
size_t completed;
|
||||
size_t num;
|
||||
struct llarp_threadpool *result;
|
||||
struct llarp_async_dh *dh;
|
||||
};
|
||||
|
||||
static void handle_dh_complete(struct llarp_dh_result *res) {
|
||||
struct dh_bench_main *m = (struct dh_bench_main *)res->user;
|
||||
|
||||
m->completed++;
|
||||
if (m->completed % 10000 == 0) printf("completed %ld\n", m->completed);
|
||||
if (m->completed == m->num) {
|
||||
printf("done\n");
|
||||
llarp_threadpool_stop(m->result);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct dh_bench_main dh_main;
|
||||
struct llarp_crypto crypto;
|
||||
struct llarp_threadpool *tp;
|
||||
|
||||
llarp_mem_stdlib();
|
||||
llarp_crypto_libsodium_init(&crypto);
|
||||
|
||||
tp = llarp_init_threadpool(8);
|
||||
dh_main.result = llarp_init_threadpool(1);
|
||||
llarp_threadpool_start(dh_main.result);
|
||||
|
||||
dh_main.num = 500000;
|
||||
dh_main.completed = 0;
|
||||
llarp_seckey_t ourkey;
|
||||
llarp_seckey_t theirkey;
|
||||
|
||||
crypto.keygen(&ourkey);
|
||||
crypto.keygen(&theirkey);
|
||||
|
||||
dh_main.dh = llarp_async_dh_new(ourkey, &crypto, dh_main.result, tp);
|
||||
llarp_threadpool_start(tp);
|
||||
|
||||
llarp_tunnel_nounce_t nounce;
|
||||
llarp_buffer_t n_buff;
|
||||
n_buff.base = nounce;
|
||||
n_buff.cur = n_buff.base;
|
||||
n_buff.sz = sizeof(llarp_tunnel_nounce_t);
|
||||
|
||||
uint8_t *theirpubkey = llarp_seckey_topublic(theirkey);
|
||||
|
||||
size_t sz = dh_main.num;
|
||||
printf("starting %ld dh jobs\n", sz);
|
||||
/* do work here */
|
||||
while (sz--) {
|
||||
crypto.randomize(n_buff);
|
||||
llarp_async_client_dh(dh_main.dh, theirpubkey, nounce, handle_dh_complete,
|
||||
&dh_main);
|
||||
}
|
||||
printf("started %ld dh jobs\n", dh_main.num);
|
||||
llarp_threadpool_wait(dh_main.result);
|
||||
llarp_threadpool_join(dh_main.result);
|
||||
llarp_threadpool_stop(tp);
|
||||
llarp_threadpool_join(tp);
|
||||
|
||||
llarp_free_threadpool(&tp);
|
||||
llarp_free_threadpool(&dh_main.result);
|
||||
|
||||
llarp_async_dh_free(&dh_main.dh);
|
||||
printf("did %ld of %ld work\n", dh_main.completed, dh_main.num);
|
||||
return 0;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) { return 0; }
|
Loading…
Reference in New Issue