1
1
Fork 0
mirror of https://github.com/oxen-io/lokinet synced 2023-12-14 06:53:00 +01:00
This commit is contained in:
Jeff Becker 2018-01-31 14:59:26 -05:00
parent 773eb21a71
commit 4718281202
No known key found for this signature in database
GPG key ID: F357B3B42F6F9B05
13 changed files with 410 additions and 60 deletions

5
.gitignore vendored
View file

@ -5,4 +5,7 @@
*.o
*.plist
llarpd
llarpd
*.test
*.bin

View file

@ -11,8 +11,18 @@ STATIC_OBJ = $(STATIC_SRC_CPP:.cpp=.cpp.o) $(STATIC_SRC_C:.c=.c.o)
DAEMON_SRC = $(wildcard $(REPO)/daemon/*.c)
DAEMON_OBJ = $(DAEMON_SRC:.c=.c.o)
TEST_SRC_C = $(wildcard $(REPO)/test/*.c)
TEST_SRC_CPP = $(wildcard $(REPO)/test/*.cpp)
TEST_OBJ_C = $(TEST_SRC_C:.c=.c.bin)
TEST_OBJ_CPP = $(TEST_SRC_CPP:.cpp=.cpp.bin)
TEST_SRC = $(TEST_SRC_C) $(TEST_SRC_CPP)
TEST_OBJ = $(TEST_OBJ_C) $(TEST_OBJ_CPP)
HDRS = $(wildcard $(REPO)/llarp/*.hpp) $(wildcard $(REPO)/include/*/*.h)
SRCS = $(DAEMON_SRC) $(STATIC_SRC_CPP) $(STATIC_SRC_C)
SRCS = $(DAEMON_SRC) $(STATIC_SRC_CPP) $(STATIC_SRC_C) $(TEST_SRC_C) $(TEST_SRC_CPP)
FORMAT = clang-format
SODIUM_FLAGS = $(shell pkg-config --cflags libsodium)
@ -31,7 +41,7 @@ endif
REQUIRED_CFLAGS = $(LIBUV_FLAGS) $(SODIUM_FLAGS) -I$(REPO)/include -std=c99 $(CFLAGS) $(DEBUG_FLAGS) $(VER_FLAGS)
REQUIRED_CXXFLAGS = $(LIBUV_FLAGS) $(SODIUM_FLAGS) -I$(REPO)/include -std=c++17 $(CXXFLAGS) $(DEBUG_FLAGS) $(VER_FLAGS)
REQUIRED_LDFLAGS = $(LDFLAGS) -ljemalloc $(SODIUM_LIBS) $(LIBUV_LIBS)
REQUIRED_LDFLAGS = $(LDFLAGS) -ljemalloc $(SODIUM_LIBS) $(LIBUV_LIBS) -lm -lstdc++
all: build
@ -40,6 +50,21 @@ format: $(HDRS) $(SRCS)
build: $(EXE)
test: $(TEST_OBJ_CPP) $(TEST_OBJ_C)
$(TEST_SRC): $(STATIC_LIB)
$(TEST_OBJ_CPP): $(TEST_SRC_CPP)
$(CXX) $(REQUIRED_CXXFLAGS) $< -o $<.bin $(STATIC_LIB) $(REQUIRED_LDFLAGS)
mv $<.bin $<.test
$<.test
$(TEST_OBJ_C): $(TEST_SRC_C)
$(CC) $(REQUIRED_CFLAGS) $< -o $<.bin $(STATIC_LIB) $(REQUIRED_LDFLAGS)
mv $<.bin $<.test
$<.test
$(EXE): $(DAEMON_OBJ) $(STATIC_LIB)
$(CXX) $(DAEMON_OBJ) $(STATIC_LIB) $(REQUIRED_LDFLAGS) -o $(EXE)
@ -53,4 +78,4 @@ $(STATIC_LIB): $(STATIC_OBJ)
$(AR) -r $(STATIC_LIB) $(STATIC_OBJ)
clean:
$(RM) $(DAEMON_OBJ) $(EXE) $(STATIC_OBJ) $(STATIC_LIB)
$(RM) $(DAEMON_OBJ) $(EXE) $(STATIC_OBJ) $(STATIC_LIB) $(TEST_OBJ)

View file

@ -25,16 +25,24 @@ typedef uint8_t llarp_hmacsec_t[HMACSECSIZE];
typedef uint8_t llarp_sig_t[SIGSIZE];
typedef uint8_t llarp_tunnel_nounce_t[TUNNOUNCESIZE];
struct llarp_keypair
{
llarp_pubkey_t pub;
llarp_seckey_t sec;
};
typedef bool (*llarp_dh_func)(llarp_sharedkey_t *, llarp_pubkey_t, llarp_tunnel_nounce_t, llarp_seckey_t);
struct llarp_crypto {
bool (*xchacha20)(llarp_buffer_t, llarp_sharedkey_t, llarp_nounce_t);
bool (*dh_client)(llarp_sharedkey_t *, llarp_pubkey_t, llarp_tunnel_nounce_t,
llarp_seckey_t);
bool (*dh_server)(llarp_sharedkey_t *, llarp_pubkey_t, llarp_tunnel_nounce_t,
llarp_seckey_t);
llarp_dh_func dh_client;
llarp_dh_func dh_server;
bool (*hash)(llarp_hash_t *, llarp_buffer_t);
bool (*hmac)(llarp_hash_t *, llarp_buffer_t, llarp_hmacsec_t);
bool (*sign)(llarp_sig_t *, llarp_seckey_t, llarp_buffer_t);
bool (*verify)(llarp_pubkey_t, llarp_buffer_t, llarp_sig_t);
void (*randomize)(llarp_buffer_t);
void (*keygen)(struct llarp_keypair *);
};
void llarp_crypto_libsodium_init(struct llarp_crypto *c);

View file

@ -0,0 +1,37 @@
#ifndef LLARP_CRYPTO_ASYNC_H_
#define LLARP_CRYPTO_ASYNC_H_
#include <llarp/crypto.h>
#include <llarp/ev.h>
#include <llarp/threadpool.h>
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_async_dh;
struct llarp_async_dh * llarp_async_dh_new(struct llarp_crypto * crypto, struct llarp_ev_loop * ev, struct llarp_threadpool * tp);
void llarp_async_dh_free(struct llarp_async_dh ** dh);
struct llarp_dh_result;
typedef void (*llarp_dh_complete_hook)(struct llarp_dh_result *);
struct llarp_dh_internal;
struct llarp_dh_result
{
struct llarp_dh_internal * impl;
llarp_sharedkey_t result;
void * user;
llarp_dh_complete_hook hook;
};
void llarp_async_client_dh(struct llarp_async_dh * dh, llarp_seckey_t ourkey, llarp_pubkey_t theirkey, llarp_tunnel_nounce_t nounce, llarp_dh_complete_hook result, void * user);
void llarp_async_server_dh(struct llarp_async_dh * dh, llarp_seckey_t ourkey, llarp_pubkey_t theirkey, llarp_tunnel_nounce_t nounce, llarp_dh_complete_hook result, void * user);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -34,21 +34,33 @@ int llarp_ev_add_udp_listener(struct llarp_ev_loop *ev,
int llarp_ev_close_udp_listener(struct llarp_udp_listener *listener);
struct llarp_ev_job {
struct llarp_ev_async_call;
typedef void (*llarp_ev_work_func)(struct llarp_ev_async_call *);
struct llarp_ev_caller;
struct llarp_ev_async_call {
/** the loop this job belongs to */
struct llarp_ev_loop *loop;
const struct llarp_ev_loop *loop;
/** private implementation */
const struct llarp_ev_caller * parent;
/** user data */
void *user;
/** work is called async when ready in the event loop thread */
void (*work)(struct llarp_ev_job *);
const void *user;
/**
work is called async when ready in the event loop thread
must not free from inside this call as it is done elsewhere
*/
const llarp_ev_work_func work;
};
/**
call work async in event loop thread (thread safe)
return true if we queued the job otherwise return false
*/
bool llarp_ev_async(struct llarp_ev_loop *ev, struct llarp_ev_job job);
struct llarp_ev_caller * llarp_ev_prepare_async(struct llarp_ev_loop *ev, llarp_ev_work_func func);
bool llarp_ev_call_async(struct llarp_ev_caller * c, void * user);
void llarp_ev_caller_stop(struct llarp_ev_caller * c);
#ifdef __cplusplus
}
#endif

View file

@ -10,16 +10,21 @@ struct llarp_threadpool;
struct llarp_threadpool *llarp_init_threadpool(int workers);
void llarp_free_threadpool(struct llarp_threadpool **tp);
typedef void (*llarp_thread_work_func)(void*);
/** job to be done in worker thread */
struct llarp_thread_job {
/**
called async after work is executed
*/
struct llarp_ev_job *result;
struct llarp_ev_caller * caller;
void * data;
/** user data to pass to work function */
void *user;
/** called in threadpool worker thread */
void (*work)(void *);
llarp_thread_work_func work;
};
void llarp_threadpool_queue_job(struct llarp_threadpool *tp,

85
llarp/crypto_async.c Normal file
View file

@ -0,0 +1,85 @@
#include <llarp/crypto_async.h>
#include <llarp/mem.h>
#include <string.h>
struct llarp_async_dh
{
llarp_dh_func client;
llarp_dh_func server;
struct llarp_threadpool * tp;
struct llarp_ev_caller * caller;
};
struct llarp_dh_internal
{
llarp_dh_func func;
llarp_pubkey_t theirkey;
llarp_seckey_t ourkey;
llarp_tunnel_nounce_t nounce;
struct llarp_dh_result result;
};
static void llarp_crypto_dh_work(void * user)
{
struct llarp_dh_internal * impl = (struct llarp_dh_internal *)user;
impl->func(&impl->result.result, impl->theirkey, impl->nounce, impl->ourkey);
}
static void llarp_crypto_dh_result(struct llarp_ev_async_call * call)
{
struct llarp_dh_internal * impl = (struct llarp_dh_internal *) call->user;
impl->result.hook(&impl->result);
llarp_g_mem.free(impl);
}
static void llarp_async_dh_exec(struct llarp_async_dh * dh, llarp_dh_func func, llarp_seckey_t ourkey, llarp_pubkey_t theirkey, llarp_tunnel_nounce_t nounce, llarp_dh_complete_hook result, void * user)
{
struct llarp_dh_internal * impl = llarp_g_mem.alloc(sizeof(struct llarp_dh_internal), 16);
memcpy(impl->theirkey, theirkey, sizeof(llarp_pubkey_t));
memcpy(impl->ourkey, ourkey, sizeof(llarp_seckey_t));
memcpy(impl->nounce, nounce, sizeof(llarp_tunnel_nounce_t));
impl->result.impl = impl;
impl->result.user = user;
impl->result.hook = result;
impl->func = func;
struct llarp_thread_job job = {
.caller = dh->caller,
.data = impl,
.user = impl,
.work = &llarp_crypto_dh_work
};
llarp_threadpool_queue_job(dh->tp, job);
}
void llarp_async_client_dh(struct llarp_async_dh * dh, llarp_seckey_t ourkey, llarp_pubkey_t theirkey, llarp_tunnel_nounce_t nounce, llarp_dh_complete_hook result, void * user)
{
llarp_async_dh_exec(dh, dh->client, ourkey, theirkey, nounce, result, user);
}
void llarp_async_server_dh(struct llarp_async_dh * dh, llarp_seckey_t ourkey, llarp_pubkey_t theirkey, llarp_tunnel_nounce_t nounce, llarp_dh_complete_hook result, void * user)
{
llarp_async_dh_exec(dh, dh->server, ourkey, theirkey, nounce, result, user);
}
struct llarp_async_dh * llarp_async_dh_new(struct llarp_crypto * crypto, struct llarp_ev_loop * ev, struct llarp_threadpool * tp)
{
struct llarp_async_dh * dh = llarp_g_mem.alloc(sizeof(struct llarp_async_dh), 16);
dh->client = crypto->dh_client;
dh->server = crypto->dh_server;
dh->tp = tp;
dh->caller = llarp_ev_prepare_async(ev, &llarp_crypto_dh_result);
return dh;
}
void llarp_async_dh_free(struct llarp_async_dh ** dh)
{
if(*dh)
{
llarp_ev_caller_stop((*dh)->caller);
llarp_g_mem.free(*dh);
*dh = NULL;
}
}

View file

@ -1,17 +1,15 @@
#include <llarp/crypto.h>
#include <sodium/crypto_generichash.h>
#include <sodium/crypto_scalarmult.h>
#include <sodium/crypto_sign.h>
#include <sodium/crypto_stream_xchacha20.h>
#include <sodium.h>
#include <assert.h>
namespace llarp {
namespace sodium {
bool xchacha20(llarp_buffer_t buff, llarp_sharedkey_t k, llarp_nounce_t n) {
static bool xchacha20(llarp_buffer_t buff, llarp_sharedkey_t k, llarp_nounce_t n) {
uint8_t *base = (uint8_t *)buff.base;
return crypto_stream_xchacha20_xor(base, base, buff.sz, n, k) == 0;
}
bool dh(llarp_sharedkey_t *shared, uint8_t *client_pk, uint8_t *server_pk,
static bool dh(llarp_sharedkey_t *shared, uint8_t *client_pk, uint8_t *server_pk,
uint8_t *remote_key, uint8_t *local_key) {
uint8_t *out = *shared;
const size_t outsz = SHAREDKEYSIZE;
@ -26,7 +24,7 @@ bool dh(llarp_sharedkey_t *shared, uint8_t *client_pk, uint8_t *server_pk,
return true;
}
bool dh_client(llarp_sharedkey_t *shared, llarp_pubkey_t pk,
static bool dh_client(llarp_sharedkey_t *shared, llarp_pubkey_t pk,
llarp_tunnel_nounce_t n, llarp_seckey_t sk) {
llarp_pubkey_t local_pk;
crypto_scalarmult_base(local_pk, sk);
@ -37,7 +35,7 @@ bool dh_client(llarp_sharedkey_t *shared, llarp_pubkey_t pk,
return false;
}
bool dh_server(llarp_sharedkey_t *shared, llarp_pubkey_t pk,
static bool dh_server(llarp_sharedkey_t *shared, llarp_pubkey_t pk,
llarp_tunnel_nounce_t n, llarp_seckey_t sk) {
llarp_pubkey_t local_pk;
crypto_scalarmult_base(local_pk, sk);
@ -48,31 +46,44 @@ bool dh_server(llarp_sharedkey_t *shared, llarp_pubkey_t pk,
return false;
}
bool hash(llarp_hash_t *result, llarp_buffer_t buff) {
static bool hash(llarp_hash_t *result, llarp_buffer_t buff) {
const uint8_t *base = (const uint8_t *)buff.base;
return crypto_generichash(*result, HASHSIZE, base, buff.sz, nullptr, 0) != -1;
}
bool hmac(llarp_hash_t *result, llarp_buffer_t buff, llarp_seckey_t secret) {
static bool hmac(llarp_hash_t *result, llarp_buffer_t buff, llarp_seckey_t secret) {
const uint8_t *base = (const uint8_t *)buff.base;
return crypto_generichash(*result, sizeof(llarp_hash_t), base, buff.sz,
secret, HMACSECSIZE) != -1;
}
bool sign(llarp_sig_t *result, llarp_seckey_t secret, llarp_buffer_t buff) {
static bool sign(llarp_sig_t *result, llarp_seckey_t secret, llarp_buffer_t buff) {
const uint8_t *base = (const uint8_t *)buff.base;
return crypto_sign_detached(*result, nullptr, base, buff.sz, secret) != -1;
}
bool verify(llarp_pubkey_t pub, llarp_buffer_t buff, llarp_sig_t sig) {
static bool verify(llarp_pubkey_t pub, llarp_buffer_t buff, llarp_sig_t sig) {
const uint8_t *base = (const uint8_t *)buff.base;
return crypto_sign_verify_detached(sig, base, buff.sz, pub) != -1;
}
static void randomize(llarp_buffer_t buff)
{
randombytes((unsigned char *)buff.base, buff.sz);
}
static void keygen(struct llarp_keypair * keys)
{
randombytes(keys->sec, sizeof(llarp_seckey_t));
unsigned char sk[64];
crypto_sign_seed_keypair(keys->pub, sk, keys->sec);
}
} // namespace sodium
} // namespace llarp
extern "C" {
void llarp_crypto_libsodium_init(struct llarp_crypto *c) {
assert(sodium_init() != -1);
c->xchacha20 = llarp::sodium::xchacha20;
c->dh_client = llarp::sodium::dh_client;
c->dh_server = llarp::sodium::dh_server;
@ -80,5 +91,7 @@ void llarp_crypto_libsodium_init(struct llarp_crypto *c) {
c->hmac = llarp::sodium::hmac;
c->sign = llarp::sodium::sign;
c->verify = llarp::sodium::verify;
c->randomize = llarp::sodium::randomize;
c->keygen = llarp::sodium::keygen;
}
}

View file

@ -2,6 +2,65 @@
#include <llarp/ev.h>
#include <uv.h>
#include <mutex>
#include <queue>
struct llarp_ev_caller
{
static void * operator new(size_t sz)
{
return llarp::Alloc<llarp_ev_caller>();
}
static void operator delete(void * ptr)
{
llarp_g_mem.free(ptr);
}
llarp_ev_caller(llarp_ev_loop * ev, llarp_ev_work_func func) :
loop(ev),
work(func)
{
async.data = this;
}
~llarp_ev_caller()
{
}
bool appendCall(void * user)
{
std::unique_lock<std::mutex> lock(access);
bool should = pending.size() == 0;
llarp_ev_async_call * call = new llarp_ev_async_call{
loop,
this,
user,
this->work};
pending.push(call);
return should;
}
void Call()
{
std::unique_lock<std::mutex> lock(access);
while(pending.size() > 0)
{
auto & front = pending.front();
front->work(front);
pending.pop();
}
}
std::mutex access;
struct llarp_ev_loop * loop;
uv_async_t async;
std::queue<llarp_ev_async_call *> pending;
llarp_ev_work_func work;
};
struct llarp_ev_loop {
uv_loop_t _loop;
@ -61,16 +120,14 @@ static void udp_close_cb(uv_handle_t *handle) {
namespace llarp {
static void ev_handle_async_closed(uv_handle_t *handle) {
struct llarp_ev_job *ev = static_cast<llarp_ev_job *>(handle->data);
llarp_g_mem.free(ev);
llarp_g_mem.free(handle);
static void ev_caller_async_closed(uv_handle_t *handle) {
llarp_ev_caller *caller = static_cast<llarp_ev_caller *>(handle->data);
delete caller;
}
static void ev_handle_async(uv_async_t *handle) {
struct llarp_ev_job *ev = static_cast<llarp_ev_job *>(handle->data);
ev->work(ev);
uv_close((uv_handle_t *)handle, ev_handle_async_closed);
static void ev_handle_async_call(uv_async_t *handle) {
llarp_ev_caller * caller = static_cast<llarp_ev_caller *>(handle->data);
caller->Call();
}
} // namespace llarp
@ -132,23 +189,29 @@ int llarp_ev_close_udp_listener(struct llarp_udp_listener *listener) {
void llarp_ev_loop_stop(struct llarp_ev_loop *loop) { uv_stop(loop->loop()); }
bool llarp_ev_async(struct llarp_ev_loop *loop, struct llarp_ev_job job) {
struct llarp_ev_job *job_copy =
static_cast<struct llarp_ev_job *>(llarp_g_mem.alloc(
sizeof(struct llarp_ev_job), llarp::alignment<llarp_ev_job>()));
job_copy->work = job.work;
job_copy->loop = loop;
job_copy->user = job.user;
uv_async_t *async = static_cast<uv_async_t *>(
llarp_g_mem.alloc(sizeof(uv_async_t), llarp::alignment<uv_async_t>()));
async->data = job_copy;
if (uv_async_init(loop->loop(), async, llarp::ev_handle_async) == 0 &&
uv_async_send(async))
return true;
else {
llarp_g_mem.free(job_copy);
llarp_g_mem.free(async);
return false;
struct llarp_ev_caller * llarp_ev_prepare_async(struct llarp_ev_loop * loop, llarp_ev_work_func work)
{
llarp_ev_caller * caller = new llarp_ev_caller(loop, work);
if(uv_async_init(loop->loop(), &caller->async, llarp::ev_handle_async_call) == 0)
return caller;
else
{
delete caller;
return nullptr;
}
}
bool llarp_ev_call_async(struct llarp_ev_caller * caller, void * user)
{
if(caller->appendCall(user))
return uv_async_send(&caller->async) == 0;
else
return true;
}
void llarp_ev_caller_stop(struct llarp_ev_caller * caller)
{
uv_close((uv_handle_t*)&caller->async, llarp::ev_caller_async_closed);
}
}

View file

@ -6,6 +6,13 @@ namespace llarp {
template <typename T> static constexpr size_t alignment() {
return std::exp2(1 + std::floor(std::log2(sizeof(T))));
}
template<typename T>
static T * Alloc(llarp_alloc * mem=&llarp_g_mem)
{
return static_cast<T *>(
mem->alloc(sizeof(T), alignment<T>()));
}
} // namespace llarp
#endif

View file

@ -4,7 +4,7 @@
namespace llarp {
namespace thread {
Pool::Pool(size_t workers) {
stop.store(true);
stop.store(false);
while (workers--) {
threads.emplace_back([this] {
for (;;) {
@ -21,10 +21,12 @@ Pool::Pool(size_t workers) {
// do work
job.work(job.user);
// inform result if needed
if (job.result && job.result->loop)
if (!llarp_ev_async(job.result->loop, *job.result)) {
if (job.caller)
{
if (!llarp_ev_call_async(job.caller, job.data)) {
std::cerr << "failed to queue result in thread worker" << std::endl;
}
}
}
});
}
@ -73,6 +75,16 @@ struct llarp_threadpool *llarp_init_threadpool(int workers) {
void llarp_threadpool_join(struct llarp_threadpool *pool) { pool->impl.Join(); }
void llarp_threadpool_start(struct llarp_threadpool * pool)
{
/** no op */
}
void llarp_threadpool_queue_job(struct llarp_threadpool * pool, struct llarp_thread_job job)
{
pool->impl.QueueJob(job);
}
void llarp_free_threadpool(struct llarp_threadpool **pool) {
delete *pool;
*pool = nullptr;

74
test/test_async_dh.c Normal file
View file

@ -0,0 +1,74 @@
#include <llarp/crypto_async.h>
#include <llarp/mem.h>
#include <stdio.h>
struct dh_bench_main
{
size_t completed;
size_t num;
struct llarp_ev_loop * ev;
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 % 1000 == 0)
printf("completed %ld\n", m->completed);
if(m->completed == m->num)
{
printf("we done\n");
llarp_ev_loop_stop(m->ev);
}
}
int main(int argc, char * argv[])
{
struct dh_bench_main dh_main;
struct llarp_crypto crypto;
struct llarp_threadpool * tp;
llarp_mem_jemalloc();
llarp_crypto_libsodium_init(&crypto);
llarp_ev_loop_alloc(&dh_main.ev);
tp = llarp_init_threadpool(8);
dh_main.dh = llarp_async_dh_new(&crypto, dh_main.ev, tp);
llarp_threadpool_start(tp);
/* do work here */
dh_main.num = 100000;
dh_main.completed = 0;
struct llarp_keypair ourkey;
struct llarp_keypair theirkey;
crypto.keygen(&ourkey);
crypto.keygen(&theirkey);
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);
size_t sz = dh_main.num;
printf("starting %ld dh jobs\n", sz);
while(sz--)
{
crypto.randomize(n_buff);
llarp_async_client_dh(dh_main.dh, ourkey.sec, theirkey.pub, nounce, handle_dh_complete, &dh_main);
}
printf("started %ld dh jobs\n", dh_main.num);
llarp_ev_loop_run(dh_main.ev);
llarp_threadpool_join(tp);
llarp_async_dh_free(&dh_main.dh);
llarp_ev_loop_free(&dh_main.ev);
llarp_free_threadpool(&tp);
printf("did %ld of %ld work\n", dh_main.completed, dh_main.num);
return 0;
}

6
test/test_cpp.cpp Normal file
View file

@ -0,0 +1,6 @@
int main(int argc, char * argv[])
{
return 0;
}