reading from TUN using native async io:

writing: 
pull/91/head
despair 6 years ago
parent c17e30b587
commit 65ff1ba991

@ -15,6 +15,13 @@
#ifdef _WIN32
#include <win32_up.h>
#include <win32_upoll.h>
// io packet for TUN read/write
struct asio_evt_pkt
{
OVERLAPPED pkt = {0, 0, 0, 0, nullptr}; // must be first, since this is part of the IO call
bool write = false; // true, or false if read pkt
size_t sz; // if this doesn't match what is in the packet, note the error
};
#endif
#ifndef MAX_WRITE_QUEUE_SIZE
@ -160,11 +167,21 @@ namespace llarp
virtual ssize_t
do_write(void* data, size_t sz)
{
DWORD x;
if(this->is_tun)
{
WriteFile(fd.tun, data, sz, &x, nullptr);
return x;
DWORD x;
bool r;
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->sz = sz;
pkt->write = true;
_doserrno = 0;
r = WriteFile(fd.tun, data, sz, &x, &pkt->pkt);
if(r) // we returned immediately
return x;
else if(_doserrno == ERROR_IO_PENDING)
return sz;
else
return -1;
}
return uwrite(fd.socket, (char*)data, sz);
}

@ -265,7 +265,9 @@ namespace llarp
struct llarp_win32_loop : public llarp_ev_loop
{
upoll_t* upollfd;
llarp_win32_loop() : upollfd(nullptr)
HANDLE tun_event_queue;
llarp_win32_loop() : upollfd(nullptr), tun_event_queue(INVALID_HANDLE_VALUE)
{
}
@ -327,12 +329,14 @@ struct llarp_win32_loop : public llarp_ev_loop
{
if(upollfd)
upoll_destroy(upollfd);
if(tun_event_queue != INVALID_HANDLE_VALUE)
CloseHandle(tun_event_queue);
}
bool
running() const
{
return upollfd != nullptr;
return (upollfd != nullptr) && (tun_event_queue != INVALID_HANDLE_VALUE);
}
bool
@ -340,7 +344,10 @@ struct llarp_win32_loop : public llarp_ev_loop
{
if(!upollfd)
upollfd = upoll_create(1);
return false;
if(tun_event_queue == INVALID_HANDLE_VALUE)
tun_event_queue =
CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1024);
return upollfd && (tun_event_queue != INVALID_HANDLE_VALUE);
}
int
@ -376,6 +383,27 @@ struct llarp_win32_loop : public llarp_ev_loop
++idx;
}
}
DWORD size = 0;
OVERLAPPED* ovl = nullptr;
ULONG_PTR listener = 0;
asio_evt_pkt* pkt;
while(
GetQueuedCompletionStatus(tun_event_queue, &size, &listener, &ovl, ms))
{
pkt = (asio_evt_pkt*)ovl;
llarp::ev_io* ev = reinterpret_cast< llarp::ev_io* >(listener);
/*if(size != pkt->sz)
llarp::LogWarn("incomplete async io operation: got ", size,
" bytes, expected ", pkt->sz, " bytes");*/
if(!pkt->write)
ev->read(readbuf, sizeof(readbuf));
else
ev->flush_write();
++result;
delete pkt;
}
if(result != -1)
tick_listeners();
return result;
@ -472,6 +500,12 @@ struct llarp_win32_loop : public llarp_ev_loop
bool
close_ev(llarp::ev_io* ev)
{
if(ev->is_tun)
{
CancelIo(ev->fd.tun);
CloseHandle(ev->fd.tun);
return true;
}
return upoll_ctl(upollfd, UPOLL_CTL_DEL, ev->fd.socket, nullptr) != -1;
}
@ -501,13 +535,16 @@ struct llarp_win32_loop : public llarp_ev_loop
bool
add_ev(llarp::ev_io* e, bool write)
{
// if tun, add to vector without adding to
// the epollfd - epollfds on windows only take
// real sockets
if(write)
e->flags = 1;
if(e->is_tun)
{
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->write = false;
pkt->sz = sizeof(readbuf);
CreateIoCompletionPort(e->fd.tun, tun_event_queue, (ULONG_PTR)e, 1024);
// queue an initial read
ReadFile(e->fd.tun, readbuf, sizeof(readbuf), nullptr, &pkt->pkt);
goto add;
}
upoll_event_t ev;
ev.data.ptr = e;
ev.events = UPOLLIN | UPOLLERR;
@ -553,7 +590,18 @@ struct llarp_win32_loop : public llarp_ev_loop
if(upollfd)
upoll_destroy(upollfd);
upollfd = nullptr;
if(tun_event_queue != INVALID_HANDLE_VALUE)
{
CloseHandle(tun_event_queue);
tun_event_queue = INVALID_HANDLE_VALUE;
}
}
};
extern "C" asio_evt_pkt*
getTunEventPkt()
{
return new asio_evt_pkt;
}
#endif

@ -244,7 +244,7 @@ namespace llarp
struct addrinfo hint, *res = NULL;
int ret;
memset(&hint, '\0', sizeof hint);
memset(&hint, 0, sizeof hint);
hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;

@ -24,6 +24,20 @@
/*#include <strsafe.h>*/
#include "tuntap.h"
// io packet for TUN read/write
// this _should_ be the same size as
// the corresponding C++ struct
struct asio_evt_pkt
{
OVERLAPPED pkt; // must be first, since this is part of the IO call
_Bool write; // true, or false if read pkt
size_t sz; // if this doesn't match what is in the packet, note the error
};
// function from c++
struct asio_evt_pkt *
getTunEventPkt();
// DDK macros
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
@ -416,22 +430,27 @@ int
tuntap_read(struct device *dev, void *buf, size_t size)
{
DWORD x;
BOOL r;
_doserrno = 0;
struct asio_evt_pkt *pkt = getTunEventPkt();
pkt->write = FALSE;
pkt->sz = size;
if(size)
{
ReadFile(dev->tun_fd, buf, (DWORD)size, &x, NULL);
r = ReadFile(dev->tun_fd, buf, (DWORD)size, &x, &pkt->pkt);
if(r)
return x;
int errcode = GetLastError();
if(errcode)
if(_doserrno && _doserrno != 997)
{
tuntap_log(TUNTAP_LOG_ERR,
(const char *)formated_error(L"%1%0", errcode));
(const char *)formated_error(L"%1%0", _doserrno));
return -1;
}
}
else
return -1;
return x;
}
else
return size;
return -1; // unreachable
}
int
@ -449,8 +468,8 @@ tuntap_write(struct device *dev, void *buf, size_t size)
(const char *)formated_error(L"%1%0", errcode));
return -1;
}
}
else
}
else
return -1;
return x;
}

Loading…
Cancel
Save