From 6ba60093d204b9fff3b9a295eb9365f8ae4225da Mon Sep 17 00:00:00 2001 From: despair86 Date: Thu, 4 Oct 2018 06:20:08 -0500 Subject: [PATCH] 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 --- llarp/dnsd.cpp | 2 +- llarp/ev.hpp | 27 ++++++++++++------ llarp/ev_win32.hpp | 70 ++++++++++++++++++++++++++-------------------- 3 files changed, 59 insertions(+), 40 deletions(-) diff --git a/llarp/dnsd.cpp b/llarp/dnsd.cpp index 1e476b673..341210acc 100644 --- a/llarp/dnsd.cpp +++ b/llarp/dnsd.cpp @@ -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; diff --git a/llarp/ev.hpp b/llarp/ev.hpp index f60853113..3fb4e3153 100644 --- a/llarp/ev.hpp +++ b/llarp/ev.hpp @@ -5,14 +5,16 @@ #ifndef _WIN32 #include #endif - -#ifndef _MSC_VER #include -#endif #include #include #include #include + +#ifdef _WIN32 +#include +#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); } diff --git a/llarp/ev_win32.hpp b/llarp/ev_win32.hpp index 1391778c1..c9651736f 100644 --- a/llarp/ev_win32.hpp +++ b/llarp/ev_win32.hpp @@ -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; }