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) dnsd_question_request *request)
{ {
const size_t BUFFER_SIZE = 1024 + (request->question.name.size() * 2); 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); memset(buf, 0, BUFFER_SIZE);
char *write_buffer = buf; char *write_buffer = buf;
char *bufferBegin = buf; char *bufferBegin = buf;

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

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

Loading…
Cancel
Save