Skip to content

Commit

Permalink
Write to TUN device asynchronously
Browse files Browse the repository at this point in the history
  • Loading branch information
dechamps committed Jan 7, 2018
1 parent 32ccdd8 commit 001cd46
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ chacha_poly1305_SOURCES = \

tincd_SOURCES = \
address_cache.c address_cache.h \
async_device.c async_device.h \
async_send.c async_send.h \
autoconnect.c autoconnect.h \
buffer.c buffer.h \
Expand Down
123 changes: 123 additions & 0 deletions src/async_device.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
async_device.c -- asynchronous send() functions
Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.org>,
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "system.h"
#include "net.h"

#include "async_device.h"

#include <assert.h>

#include "logger.h"
#include "tinycthread.h"
#include "utils.h"
#include "xalloc.h"
#include "netutl.h"
#include "device.h"

bool async_device_enabled = false;
static thrd_t async_device_thrd;
static mtx_t async_device_mtx;
static cnd_t async_device_cnd;

#define ASYNC_DEVICE_QUEUE_LENGTH 128
vpn_packet_t async_device_queue[ASYNC_DEVICE_QUEUE_LENGTH];
size_t async_device_queue_index = 0;
size_t async_device_queue_length = 0;

static int async_device_thread(void* data) {
assert(mtx_lock(&async_device_mtx) == thrd_success);
while (true) {
while (async_device_enabled && async_device_queue_length == 0) {
assert(cnd_wait(&async_device_cnd, &async_device_mtx) == thrd_success);
}

if (async_device_queue_length > 0) {
vpn_packet_t* request = &async_device_queue[async_device_queue_index];
assert(mtx_unlock(&async_device_mtx) == thrd_success);

devops.write(request);

assert(mtx_lock(&async_device_mtx) == thrd_success);
async_device_queue_index++;
async_device_queue_index %= ASYNC_DEVICE_QUEUE_LENGTH;
async_device_queue_length--;

continue;
}

if (!async_device_enabled) break;
}
assert(mtx_unlock(&async_device_mtx) == thrd_success);
return 0;
}

void async_device_write(vpn_packet_t *packet) {
assert(async_device_enabled);

assert(mtx_lock(&async_device_mtx) == thrd_success);

if (async_device_queue_length < ASYNC_DEVICE_QUEUE_LENGTH) {
vpn_packet_t* request = &async_device_queue[(async_device_queue_index + async_device_queue_length) % ASYNC_DEVICE_QUEUE_LENGTH];
memcpy(request, packet, sizeof(*packet));

if (async_device_queue_length == 0) {
assert(cnd_signal(&async_device_cnd) == thrd_success);
}

async_device_queue_length++;
}

assert(mtx_unlock(&async_device_mtx) == thrd_success);
}

void async_device_init() {
if (mtx_init(&async_device_mtx, mtx_plain) != thrd_success) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Unable to initialize async send mutex, falling back to synchronous mode");
return;
}
if (cnd_init(&async_device_cnd) != thrd_success) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Unable to initialize async send condition variable, falling back to synchronous mode");
mtx_destroy(&async_device_mtx);
return;
}

async_device_enabled = true;

if (thrd_create(&async_device_thrd, async_device_thread, NULL) != thrd_success) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Unable to initialize async send thread, falling back to synchronous mode");
async_device_enabled = 0;
cnd_destroy(&async_device_cnd);
mtx_destroy(&async_device_mtx);
return;
}
}

void async_device_exit() {
assert(mtx_lock(&async_device_mtx) == thrd_success);
async_device_enabled = false;
assert(cnd_broadcast(&async_device_cnd) == thrd_success);
assert(mtx_unlock(&async_device_mtx) == thrd_success);

int result = -1;
assert(thrd_join(async_device_thrd, &result));
assert(result == 0);

mtx_destroy(&async_device_mtx);
}
27 changes: 27 additions & 0 deletions src/async_device.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef TINC_ASYNC_DEVICE_H
#define TINC_ASYNC_DEVICE_H

/*
async_send.h -- asynchronous send() functions
Copyright (C) 2018 Etienne Dechamps <etienne@edechamps.fr>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

extern void async_device_init();
extern void async_device_exit();
extern void async_device_write(struct vpn_packet_t *);

#endif
3 changes: 2 additions & 1 deletion src/net_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "route.h"
#include "utils.h"
#include "xalloc.h"
#include "async_device.h"
#include "async_send.h"

#ifndef MAX
Expand Down Expand Up @@ -1396,7 +1397,7 @@ void send_packet(node_t *n, vpn_packet_t *packet) {

n->out_packets++;
n->out_bytes += packet->len;
devops.write(packet);
async_device_write(packet);
return;
}

Expand Down
3 changes: 3 additions & 0 deletions src/net_setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "subnet.h"
#include "utils.h"
#include "xalloc.h"
#include "async_device.h"
#include "async_send.h"

#ifdef HAVE_MINIUPNPC
Expand Down Expand Up @@ -1202,6 +1203,7 @@ static bool setup_myself(void) {
initialize network
*/
bool setup_network(void) {
async_device_init();
async_send_init();
init_connections();
init_subnets();
Expand Down Expand Up @@ -1287,6 +1289,7 @@ void close_network_connections(void) {
exit_nodes();
exit_connections();
async_send_exit();
async_device_exit();

if(!device_standby) {
device_disable();
Expand Down

0 comments on commit 001cd46

Please sign in to comment.