switch to std::variant for win32 ev_io

- sockets are a distinct (non-negative) file descriptor
- plain old file descriptors are opaque handles

this makes the specialisations of llarp::ev_io on win32 type-safe as
- TAP-Windows v9 adapter is a plain old device file (same as on UNIX and Linux)
- UDP listeners are sockets, so the type must change (from signed to unsigned int) to accomodate Winsock2
pull/20/head
despair86 6 years ago
parent f17727d50a
commit 6ba60093d2

@ -82,7 +82,7 @@ writecname_dnss_response(std::string cname, const struct sockaddr *from,
dnsd_question_request *request)
{
const size_t BUFFER_SIZE = 1024 + (request->question.name.size() * 2);
char buf[BUFFER_SIZE];
char buf[BUFFER_SIZE]; // heh, another UNIX compiler extension: VLAs in C++
memset(buf, 0, BUFFER_SIZE);
char *write_buffer = buf;
char *bufferBegin = buf;

@ -5,14 +5,16 @@
#ifndef _WIN32
#include <sys/uio.h>
#endif
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <llarp/buffer.h>
#include <list>
#include <llarp/codel.hpp>
#include <vector>
#ifdef _WIN32
#include <variant>
#endif
#ifndef MAX_WRITE_QUEUE_SIZE
#define MAX_WRITE_QUEUE_SIZE 1024
#endif
@ -29,13 +31,18 @@ namespace llarp
int fd;
ev_io(int f) : fd(f), m_writeq("writequeue"){};
#else
SOCKET fd;
// on windows, udp event loops are socket fds
// and TUN device is a plain old fd
std::variant< SOCKET, HANDLE > fd;
// the unique completion key that helps us to
// identify the object instance for which we receive data
// Here, we'll use the address of the udp_listener instance, converted to
// its literal int/int64 representation.
// Here, we'll use the address of the udp_listener instance, converted
// to its literal int/int64 representation.
ULONG_PTR listener_id = 0;
ev_io(SOCKET f) : fd(f), m_writeq("writequeue"){};
ev_io(HANDLE t)
: fd(t), m_writeq("writequeue"){}; // overload for TUN device, which
// _is_ a regular file descriptor
#endif
virtual int
read(void* buf, size_t sz) = 0;
@ -50,7 +57,7 @@ namespace llarp
#ifndef _WIN32
return write(fd, data, sz) != -1;
#else
return WriteFile((void*)fd, data, sz, nullptr, nullptr);
return WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, nullptr);
#endif
}
@ -129,7 +136,7 @@ namespace llarp
#ifndef _WIN32
::close(fd);
#else
closesocket(fd);
closesocket(std::get< SOCKET >(fd));
#endif
};
};
@ -156,7 +163,11 @@ struct llarp_ev_loop
auto ev = create_udp(l, src);
if(ev)
{
#ifdef _WIN32
l->fd = std::get< SOCKET >(ev->fd);
#else
l->fd = ev->fd;
#endif
}
return ev && add_ev(ev, false);
}

@ -43,8 +43,8 @@ namespace llarp
unsigned long flags = 0;
WSABUF wbuf = {sz, static_cast< char* >(buf)};
// WSARecvFrom
int ret = ::WSARecvFrom(fd, &wbuf, 1, nullptr, &flags, addr, &slen,
&portfds[0], nullptr);
int ret = ::WSARecvFrom(std::get< SOCKET >(fd), &wbuf, 1, nullptr, &flags,
addr, &slen, &portfds[0], nullptr);
// 997 is the error code for queued ops
int s_errno = ::WSAGetLastError();
if(ret && s_errno != 997)
@ -74,9 +74,9 @@ namespace llarp
return -1;
}
// WSASendTo
ssize_t sent =
::WSASendTo(fd, &wbuf, 1, nullptr, 0, to, slen, &portfds[1], nullptr);
int s_errno = ::WSAGetLastError();
ssize_t sent = ::WSASendTo(std::get< SOCKET >(fd), &wbuf, 1, nullptr, 0,
to, slen, &portfds[1], nullptr);
int s_errno = ::WSAGetLastError();
if(sent && s_errno != 997)
{
llarp::LogWarn("send socket error ", s_errno);
@ -91,7 +91,7 @@ namespace llarp
llarp_tun_io* t;
device* tunif;
tun(llarp_tun_io* tio)
: ev_io(INVALID_SOCKET)
: ev_io(INVALID_HANDLE_VALUE)
, t(tio)
, tunif(tuntap_init())
@ -147,12 +147,12 @@ namespace llarp
return false;
}
fd = (SOCKET)tunif->tun_fd;
if(fd == -1)
fd = tunif->tun_fd;
if(std::get< HANDLE >(fd) == INVALID_HANDLE_VALUE)
return false;
// we're already non-blocking
return true;
return true;
}
~tun()
@ -208,7 +208,7 @@ struct llarp_win32_loop : public llarp_ev_loop
{
llarp::udp_listener* ev =
reinterpret_cast< llarp::udp_listener* >(ev_id);
if(ev && ev->fd)
if(ev && !ev->fd.valueless_by_exception())
{
ev->getData(readbuf, sizeof(readbuf), iolen);
}
@ -216,18 +216,13 @@ struct llarp_win32_loop : public llarp_ev_loop
++idx;
} while(::GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, ms));
// tick_listeners inlined since win32 does not
// implement ev_tun
for(auto& l : udp_listeners)
{
if(l->tick)
l->tick(l);
}
if(!idx)
return -1;
else
{
tick_listeners();
result = idx;
}
return result;
}
@ -255,7 +250,7 @@ struct llarp_win32_loop : public llarp_ev_loop
{
llarp::udp_listener* ev =
reinterpret_cast< llarp::udp_listener* >(ev_id);
if(ev && ev->fd)
if(ev && !ev->fd.valueless_by_exception())
{
ev->getData(readbuf, sizeof(readbuf), iolen);
}
@ -263,16 +258,13 @@ struct llarp_win32_loop : public llarp_ev_loop
++idx;
} while(::GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, 10));
for(auto& l : udp_listeners)
{
if(l->tick)
l->tick(l);
}
if(!idx)
return -1;
else
{
tick_listeners();
result = idx;
}
return result;
}
@ -331,8 +323,9 @@ struct llarp_win32_loop : public llarp_ev_loop
{
// On Windows, just close the socket to decrease the iocp refcount
// and stop any pending I/O
BOOL stopped = ::CancelIo(reinterpret_cast< HANDLE >(ev->fd));
return closesocket(ev->fd) == 0 && stopped == TRUE;
BOOL stopped =
::CancelIo(reinterpret_cast< HANDLE >(std::get< SOCKET >(ev->fd)));
return closesocket(std::get< SOCKET >(ev->fd)) == 0 && stopped == TRUE;
}
llarp::ev_io*
@ -362,11 +355,26 @@ struct llarp_win32_loop : public llarp_ev_loop
add_ev(llarp::ev_io* ev, bool write)
{
ev->listener_id = reinterpret_cast< ULONG_PTR >(ev);
if(!::CreateIoCompletionPort(reinterpret_cast< HANDLE >(ev->fd), iocpfd,
ev->listener_id, 0))
switch(ev->fd.index())
{
delete ev;
return false;
case 0:
if(!::CreateIoCompletionPort((HANDLE)std::get< 0 >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
break;
case 1:
if(!::CreateIoCompletionPort(std::get< 1 >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
break;
default:
return false;
}
return true;
}

Loading…
Cancel
Save