refactored event loop base classes

use the base class impl for llarp::tcp_conn::sendto

can't seem to escape quotes ;-;

yeah this need to stay out of the unix build

turn on gnu extensions

apple stuff

remove duplicate code

clean up

fix vtable

clang-format

parameter checks
pull/36/head
despair 6 years ago
parent 9afe63d738
commit 186e2ea989

@ -94,8 +94,6 @@ endif()
add_compile_options(-Wall -Wno-deprecated-declarations -march=native)
add_compile_options(${OPTIMIZE_FLAGS})
add_compile_options($ENV{CFLAGS})
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:$ENV{CXXFLAGS}>)
if(SHADOW)
add_compile_options(-fPIC)

@ -1,6 +1,6 @@
#ifndef LLARP_EV_H
#define LLARP_EV_H
#if defined(__MINGW32__) || defined(_WIN32)
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
@ -8,7 +8,6 @@
#define ssize_t long
#endif
#else
#include <netinet/in.h>
#include <sys/socket.h>
#endif
@ -17,6 +16,7 @@
#include <stdlib.h>
#include <tuntap.h>
#include <llarp/time.h>
/**
* ev.h
*

@ -108,7 +108,7 @@ answer_request_alloc(struct dnsc_context *dnsc, void *sock, const char *url,
request->context = dnsc;
char *sUrl = strdup(url);
request->question.name = (char *)sUrl; // since it's a std::String
request->question.name = (char *)sUrl; // since it's a std::String
// we can nuke sUrl now
free(sUrl);
@ -324,7 +324,8 @@ generic_handle_dnsc_recvfrom(dnsc_answer_request *request,
if(answer == nullptr)
{
llarp::LogWarn("nameserver ", upstreamAddr,
" didnt return any answers for ", question?question->name:"null question");
" didnt return any answers for ",
question ? question->name : "null question");
request->resolved(request);
return;
}

@ -7,13 +7,13 @@
// apparently current Solaris will emulate epoll.
#if __linux__ || __sun__
#include "ev_epoll.hpp"
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| (__APPLE__ && __MACH__)
#include "ev_kqueue.hpp"
#endif
#if defined(_WIN32) || defined(_WIN64) || defined(__NT__)
#elif defined(_WIN32) || defined(_WIN64) || defined(__NT__)
#include "ev_win32.hpp"
#else
#error No async event loop for your platform, subclass llarp_ev_loop
#endif
void
@ -21,13 +21,13 @@ llarp_ev_loop_alloc(struct llarp_ev_loop **ev)
{
#if __linux__ || __sun__
*ev = new llarp_epoll_loop;
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| (__APPLE__ && __MACH__)
*ev = new llarp_kqueue_loop;
#endif
#if defined(_WIN32) || defined(_WIN64) || defined(__NT__)
#elif defined(_WIN32) || defined(_WIN64) || defined(__NT__)
*ev = new llarp_win32_loop;
#else
#error no event loop subclass
#endif
(*ev)->init();
(*ev)->_now = llarp_time_now_ms();
@ -202,117 +202,4 @@ namespace llarp
return true;
}
int
tcp_serv::read(void *, size_t)
{
#ifndef _WIN32
int new_fd = ::accept(fd, nullptr, nullptr);
if(new_fd == -1)
{
llarp::LogError("failed to accept on ", fd, ":", strerror(errno));
return -1;
}
#else
SOCKET new_fd = ::accept(std::get< SOCKET >(fd), nullptr, nullptr);
if(new_fd == INVALID_SOCKET)
{
llarp::LogError("failed to accept on ", std::get< SOCKET >(fd), ":",
strerror(errno));
return -1;
}
#endif
llarp_tcp_conn *conn = new llarp_tcp_conn;
// zero out callbacks
conn->tick = nullptr;
conn->closed = nullptr;
conn->read = nullptr;
// build handler
llarp::tcp_conn *connimpl = new tcp_conn(new_fd, conn);
conn->impl = connimpl;
conn->loop = loop;
if(loop->add_ev(connimpl, true))
{
// call callback
if(tcp->accepted)
tcp->accepted(tcp, conn);
return 0;
}
// cleanup error
delete conn;
delete connimpl;
return -1;
}
} // namespace llarp
// they're effectively alike, save for the fact that we must not
// get file descriptors below zero
#ifndef _WIN32
llarp::ev_io *
llarp_ev_loop::bind_tcp(llarp_tcp_acceptor *tcp, const sockaddr *bindaddr)
{
int fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
{
sz = sizeof(sockaddr_in6);
}
else if(bindaddr->sa_family == AF_UNIX)
{
sz = sizeof(sockaddr_un);
}
if(::bind(fd, bindaddr, sz) == -1)
{
::close(fd);
return nullptr;
}
if(::listen(fd, 5) == -1)
{
::close(fd);
return nullptr;
}
llarp::ev_io *serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
return serv;
}
#else
llarp::ev_io *
llarp_ev_loop::bind_tcp(llarp_tcp_acceptor *tcp, const sockaddr *bindaddr)
{
DWORD on = 1;
SOCKET fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == INVALID_SOCKET)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
{
sz = sizeof(sockaddr_in6);
}
// keep. inexplicably, windows now has unix domain sockets
// for now, use the ID numbers directly until this comes out of
// beta
else if(bindaddr->sa_family == AF_UNIX)
{
sz = 110; // current size in 10.0.17763, verify each time the beta PSDK
// is updated
}
if(::bind(fd, bindaddr, sz) == SOCKET_ERROR)
{
::closesocket(fd);
return nullptr;
}
if(::listen(fd, 5) == SOCKET_ERROR)
{
::closesocket(fd);
return nullptr;
}
llarp::ev_io *serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
// We're non-blocking now, but can't really make use of it
// until we cut over to WSA* functions
ioctlsocket(fd, FIONBIO, &on);
return serv;
}
#endif
} // namespace llarp

@ -28,7 +28,8 @@
namespace llarp
{
struct ev_io
#ifdef _WIN32
struct win32_ev_io
{
struct WriteBuffer
{
@ -51,7 +52,8 @@ namespace llarp
struct GetTime
{
llarp_time_t operator()(const WriteBuffer & buf) const
llarp_time_t
operator()(const WriteBuffer& buf) const
{
return buf.timestamp;
}
@ -59,9 +61,12 @@ namespace llarp
struct PutTime
{
llarp_ev_loop * loop;
PutTime(llarp_ev_loop * l ) : loop(l) {}
void operator()(WriteBuffer & buf)
llarp_ev_loop* loop;
PutTime(llarp_ev_loop* l) : loop(l)
{
}
void
operator()(WriteBuffer& buf)
{
buf.timestamp = llarp_ev_loop_time_now_ms(loop);
}
@ -85,52 +90,33 @@ namespace llarp
typedef std::deque< WriteBuffer > LosslessWriteQueue_t;
#ifndef _WIN32
int fd;
int flags = 0;
ev_io(int f) : fd(f)
{
}
/// for tun
ev_io(int f, LossyWriteQueue_t* q) : fd(f), m_LossyWriteQueue(q)
{
}
/// for tcp
ev_io(int f, LosslessWriteQueue_t* q) : fd(f), m_BlockingWriteQueue(q)
{
}
#else
// on windows, tcp/udp event loops are socket fds
// and TUN device is a plain old fd
std::variant< SOCKET, HANDLE > fd;
// These....shouldn't be here, but because of the distinction,
// coupled with the async events api, we have to add our file
// descriptors to the event queue at object construction,
// unlike UNIX where these can be separated
ULONG_PTR listener_id = 0;
bool isTCP = false;
bool write = false;
WSAOVERLAPPED portfd[2];
// for udp?
ev_io(SOCKET f) : fd(f)
// constructors
// for udp
win32_ev_io(SOCKET f) : fd(f)
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
};
// for tun
ev_io(HANDLE t, LossyWriteQueue_t* q) : fd(t), m_LossyWriteQueue(q)
win32_ev_io(HANDLE t, LossyWriteQueue_t* q) : fd(t), m_LossyWriteQueue(q)
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
}
// for tcp
ev_io(SOCKET f, LosslessWriteQueue_t* q) : fd(f), m_BlockingWriteQueue(q)
win32_ev_io(SOCKET f, LosslessWriteQueue_t* q)
: fd(f), m_BlockingWriteQueue(q)
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
isTCP = true;
}
#endif
virtual int
read(void* buf, size_t sz) = 0;
@ -151,14 +137,20 @@ namespace llarp
virtual ssize_t
do_write(void* data, size_t sz)
{
#ifndef _WIN32
return write(fd, data, sz);
#else
DWORD w;
WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, &portfd[1]);
GetOverlappedResult(std::get< HANDLE >(fd), &portfd[1], &w, TRUE);
if(std::holds_alternative< HANDLE >(fd))
{
WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, &portfd[1]);
GetOverlappedResult(std::get< HANDLE >(fd), &portfd[1], &w, TRUE);
}
else
{
WriteFile((HANDLE)std::get< SOCKET >(fd), data, sz, nullptr,
&portfd[1]);
GetOverlappedResult((HANDLE)std::get< SOCKET >(fd), &portfd[1], &w,
TRUE);
}
return w;
#endif
}
bool
@ -219,89 +211,222 @@ namespace llarp
}
/// reset errno
errno = 0;
#if _WIN32
SetLastError(0);
#endif
}
std::unique_ptr< LossyWriteQueue_t > m_LossyWriteQueue;
std::unique_ptr< LosslessWriteQueue_t > m_BlockingWriteQueue;
virtual ~ev_io()
virtual ~win32_ev_io()
{
#ifndef _WIN32
::close(fd);
#else
closesocket(std::get< SOCKET >(fd));
#endif
};
};
#endif
struct tcp_conn : public ev_io
struct posix_ev_io
{
bool _shouldClose = false;
llarp_tcp_conn* tcp;
tcp_conn(int fd, llarp_tcp_conn* conn)
: ev_io(fd, new LosslessWriteQueue_t{}), tcp(conn)
struct WriteBuffer
{
llarp_time_t timestamp = 0;
size_t bufsz;
byte_t buf[EV_WRITE_BUF_SZ];
WriteBuffer() = default;
WriteBuffer(const byte_t* ptr, size_t sz)
{
if(sz <= sizeof(buf))
{
bufsz = sz;
memcpy(buf, ptr, bufsz);
}
else
bufsz = 0;
}
struct GetTime
{
llarp_time_t
operator()(const WriteBuffer& buf) const
{
return buf.timestamp;
}
};
struct PutTime
{
llarp_ev_loop* loop;
PutTime(llarp_ev_loop* l) : loop(l)
{
}
void
operator()(WriteBuffer& buf)
{
buf.timestamp = llarp_ev_loop_time_now_ms(loop);
}
};
struct Compare
{
bool
operator()(const WriteBuffer& left, const WriteBuffer& right) const
{
return left.timestamp < right.timestamp;
}
};
};
typedef llarp::util::CoDelQueue< WriteBuffer, WriteBuffer::GetTime,
WriteBuffer::PutTime, WriteBuffer::Compare,
llarp::util::NullMutex,
llarp::util::NullLock, 5, 100, 128 >
LossyWriteQueue_t;
typedef std::deque< WriteBuffer > LosslessWriteQueue_t;
int fd;
int flags = 0;
posix_ev_io(int f) : fd(f)
{
}
virtual ~tcp_conn()
/// for tun
posix_ev_io(int f, LossyWriteQueue_t* q) : fd(f), m_LossyWriteQueue(q)
{
delete tcp;
}
/// for tcp
posix_ev_io(int f, LosslessWriteQueue_t* q) : fd(f), m_BlockingWriteQueue(q)
{
}
virtual int
read(void* buf, size_t sz) = 0;
virtual int
sendto(const sockaddr* dst, const void* data, size_t sz)
{
return -1;
};
/// return false if we want to deregister and remove ourselves
virtual bool
tick()
{
return true;
};
/// used for tun interface and tcp conn
virtual ssize_t
do_write(void* buf, size_t sz)
do_write(void* data, size_t sz)
{
if(_shouldClose)
return -1;
#if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__FreeBSD__) || defined(__sun)
// pretty much every UNIX system still extant, plus linux _and_ solaris
// (on both sides of the fork) can ignore SIGPIPE....except Macintosh,
// and the other vendored systems... -rick
return ::send(fd, buf, sz, MSG_NOSIGNAL); // ignore sigpipe
#elif defined(_WIN32)
// TODO: make async
return ::send(std::get< SOCKET >(fd), (char*)buf, sz, 0);
#else
return ::send(fd, buf, sz, 0);
#endif
return write(fd, data, sz);
}
int
read(void* buf, size_t sz)
bool
queue_write(const byte_t* buf, size_t sz)
{
if(_shouldClose)
return -1;
#ifndef _WIN32
ssize_t amount = ::read(fd, buf, sz);
#else
// TODO: make async
ssize_t amount = ::recv(std::get< SOCKET >(fd), (char*)buf, sz, 0);
#endif
if(amount > 0)
if(m_LossyWriteQueue)
{
m_LossyWriteQueue->Emplace(buf, sz);
return true;
}
else if(m_BlockingWriteQueue)
{
if(tcp->read)
tcp->read(tcp, buf, amount);
m_BlockingWriteQueue->emplace_back(buf, sz);
return true;
}
else
return false;
}
/// called in event loop when fd is ready for writing
/// requeues anything not written
/// this assumes fd is set to non blocking
virtual void
flush_write()
{
if(m_LossyWriteQueue)
m_LossyWriteQueue->Process([&](WriteBuffer& buffer) {
do_write(buffer.buf, buffer.bufsz);
// if we would block we save the entries for later
// discard entry
});
else if(m_BlockingWriteQueue)
{
// error
_shouldClose = true;
return -1;
// write buffers
while(m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, itr.bufsz);
if(result == -1)
return;
ssize_t dlt = itr.bufsz - result;
if(dlt > 0)
{
// queue remaining to front of queue
WriteBuffer buff(itr.buf + dlt, itr.bufsz - dlt);
m_BlockingWriteQueue->pop_front();
m_BlockingWriteQueue->push_front(buff);
// TODO: errno?
return;
}
m_BlockingWriteQueue->pop_front();
if(errno == EAGAIN || errno == EWOULDBLOCK)
{
errno = 0;
return;
}
}
}
return 0;
/// reset errno
errno = 0;
}
bool
tick();
std::unique_ptr< LossyWriteQueue_t > m_LossyWriteQueue;
std::unique_ptr< LosslessWriteQueue_t > m_BlockingWriteQueue;
int
sendto(const sockaddr*, const void*, size_t)
virtual ~posix_ev_io()
{
return -1;
close(fd);
};
};
// finally create aliases by platform
#ifdef _WIN32
using ev_io = win32_ev_io;
#else
using ev_io = posix_ev_io;
#endif
// wew, managed to get away with using
// 'int fd' across all platforms
// since we're operating entirely
// on sockets
struct tcp_conn : public ev_io
{
bool _shouldClose = false;
llarp_tcp_conn* tcp;
tcp_conn(int fd, llarp_tcp_conn* conn)
: ev_io(fd, new LosslessWriteQueue_t{}), tcp(conn)
{
}
virtual ~tcp_conn()
{
delete tcp;
}
virtual ssize_t
do_write(void* buf, size_t sz);
virtual int
read(void* buf, size_t sz);
bool
tick();
};
struct tcp_serv : public ev_io
@ -328,6 +453,8 @@ namespace llarp
}; // namespace llarp
// this (nearly!) abstract base class
// is overriden for each platform
struct llarp_ev_loop
{
byte_t readbuf[EV_READ_BUF_SZ];
@ -343,20 +470,8 @@ struct llarp_ev_loop
virtual void
stop() = 0;
bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
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);
}
virtual bool
udp_listen(llarp_udp_io* l, const sockaddr* src) = 0;
virtual llarp::ev_io*
create_udp(llarp_udp_io* l, const sockaddr* src) = 0;
@ -370,8 +485,8 @@ struct llarp_ev_loop
virtual llarp::ev_io*
create_tun(llarp_tun_io* tun) = 0;
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* addr);
virtual llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* addr) = 0;
/// register event listener
virtual bool

@ -18,6 +18,70 @@
namespace llarp
{
int
tcp_conn::read(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
ssize_t amount = ::read(fd, buf, sz);
if(amount > 0)
{
if(tcp->read)
tcp->read(tcp, buf, amount);
}
else
{
// error
_shouldClose = true;
return -1;
}
return 0;
}
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
// pretty much every UNIX system still extant, _including_ solaris
// (on both sides of the fork) can ignore SIGPIPE....except
// the other vendored systems... -rick
return ::send(fd, buf, sz, MSG_NOSIGNAL); // ignore sigpipe
}
int
tcp_serv::read(void*, size_t)
{
int new_fd = ::accept(fd, nullptr, nullptr);
if(new_fd == -1)
{
llarp::LogError("failed to accept on ", fd, ":", strerror(errno));
return -1;
}
llarp_tcp_conn* conn = new llarp_tcp_conn;
// zero out callbacks
conn->tick = nullptr;
conn->closed = nullptr;
conn->read = nullptr;
// build handler
llarp::tcp_conn* connimpl = new tcp_conn(new_fd, conn);
conn->impl = connimpl;
conn->loop = loop;
if(loop->add_ev(connimpl, true))
{
// call callback
if(tcp->accepted)
tcp->accepted(tcp, conn);
return 0;
}
// cleanup error
delete conn;
delete connimpl;
return -1;
}
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
@ -169,6 +233,45 @@ struct llarp_epoll_loop : public llarp_ev_loop
{
}
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
int fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
{
sz = sizeof(sockaddr_in6);
}
else if(bindaddr->sa_family == AF_UNIX)
{
sz = sizeof(sockaddr_un);
}
if(::bind(fd, bindaddr, sz) == -1)
{
::close(fd);
return nullptr;
}
if(::listen(fd, 5) == -1)
{
::close(fd);
return nullptr;
}
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
return serv;
}
virtual bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = ev->fd;
return ev && add_ev(ev, false);
}
~llarp_epoll_loop()
{
if(epollfd != -1)

@ -26,6 +26,73 @@
namespace llarp
{
int
tcp_conn::read(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
ssize_t amount = ::read(fd, buf, sz);
if(amount > 0)
{
if(tcp->read)
tcp->read(tcp, buf, amount);
}
else
{
// error
_shouldClose = true;
return -1;
}
return 0;
}
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
// macintosh uses a weird sockopt
return ::send(fd, buf, sz, MSG_NOSIGNAL); // ignore sigpipe
#else
return ::send(fd, buf, sz, 0);
#endif
}
int
tcp_serv::read(void*, size_t)
{
int new_fd = ::accept(fd, nullptr, nullptr);
if(new_fd == -1)
{
llarp::LogError("failed to accept on ", fd, ":", strerror(errno));
return -1;
}
llarp_tcp_conn* conn = new llarp_tcp_conn;
// zero out callbacks
conn->tick = nullptr;
conn->closed = nullptr;
conn->read = nullptr;
// build handler
llarp::tcp_conn* connimpl = new tcp_conn(new_fd, conn);
conn->impl = connimpl;
conn->loop = loop;
if(loop->add_ev(connimpl, true))
{
// call callback
if(tcp->accepted)
tcp->accepted(tcp, conn);
return 0;
}
// cleanup error
delete conn;
delete connimpl;
return -1;
}
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
@ -187,6 +254,36 @@ struct llarp_kqueue_loop : public llarp_ev_loop
{
}
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
int fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
{
sz = sizeof(sockaddr_in6);
}
else if(bindaddr->sa_family == AF_UNIX)
{
sz = sizeof(sockaddr_un);
}
if(::bind(fd, bindaddr, sz) == -1)
{
::close(fd);
return nullptr;
}
if(::listen(fd, 5) == -1)
{
::close(fd);
return nullptr;
}
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
return serv;
}
~llarp_kqueue_loop()
{
}
@ -344,6 +441,15 @@ struct llarp_kqueue_loop : public llarp_ev_loop
return fd;
}
virtual bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = ev->fd;
return ev && add_ev(ev, false);
}
bool
close_ev(llarp::ev_io* ev)
{

@ -10,6 +10,68 @@
namespace llarp
{
int
tcp_conn::read(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
// TODO: make async
ssize_t amount = ::recv(std::get< SOCKET >(fd), (char*)buf, sz, 0);
if(amount > 0)
{
if(tcp->read)
tcp->read(tcp, buf, amount);
}
else
{
// error
_shouldClose = true;
return -1;
}
return 0;
}
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
// TODO: make async
return ::send(std::get< SOCKET >(fd), (char*)buf, sz, 0);
}
int
tcp_serv::read(void*, size_t)
{
SOCKET new_fd = ::accept(std::get< SOCKET >(fd), nullptr, nullptr);
if(new_fd == INVALID_SOCKET)
{
llarp::LogError("failed to accept on ", std::get< SOCKET >(fd), ":",
strerror(errno));
return -1;
}
llarp_tcp_conn* conn = new llarp_tcp_conn;
// zero out callbacks
conn->tick = nullptr;
conn->closed = nullptr;
conn->read = nullptr;
// build handler
llarp::tcp_conn* connimpl = new tcp_conn(new_fd, conn);
conn->impl = connimpl;
conn->loop = loop;
if(loop->add_ev(connimpl, true))
{
// call callback
if(tcp->accepted)
tcp->accepted(tcp, conn);
return 0;
}
// cleanup error
delete conn;
delete connimpl;
return -1;
}
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
@ -87,14 +149,11 @@ namespace llarp
llarp_tun_io* t;
device* tunif;
OVERLAPPED* tun_async[2];
tun(llarp_tun_io* tio)
: ev_io(INVALID_HANDLE_VALUE, new LossyWriteQueue_t("tun_write_queue"))
tun(llarp_tun_io* tio, llarp_ev_loop* l)
: ev_io(INVALID_HANDLE_VALUE,
new LossyWriteQueue_t("win32_tun_write", l))
, t(tio)
, tunif(tuntap_init())
{
};
, tunif(tuntap_init()){};
int
sendto(const sockaddr* to, const void* data, size_t sz)
@ -174,6 +233,7 @@ namespace llarp
{
}
};
}; // namespace llarp
struct llarp_win32_loop : public llarp_ev_loop
@ -191,6 +251,44 @@ struct llarp_win32_loop : public llarp_ev_loop
iocpfd = INVALID_HANDLE_VALUE;
}
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
DWORD on = 1;
SOCKET fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == INVALID_SOCKET)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
{
sz = sizeof(sockaddr_in6);
}
// keep. inexplicably, windows now has unix domain sockets
// for now, use the ID numbers directly until this comes out of
// beta
else if(bindaddr->sa_family == AF_UNIX)
{
sz = 110; // current size in 10.0.17763, verify each time the beta PSDK
// is updated
}
if(::bind(fd, bindaddr, sz) == SOCKET_ERROR)
{
::closesocket(fd);
return nullptr;
}
if(::listen(fd, 5) == SOCKET_ERROR)
{
::closesocket(fd);
return nullptr;
}
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
// We're non-blocking now, but can't really make use of it
// until we cut over to WSA* functions
ioctlsocket(fd, FIONBIO, &on);
return serv;
}
bool
init()
{
@ -227,13 +325,9 @@ struct llarp_win32_loop : public llarp_ev_loop
llarp::LogDebug("size: ", iolen, "\tev_id: ", ev_id,
"\tqdata: ", qdata);
if(ev->write)
{
ev->flush_write();
}
else
{
ev->read(readbuf, iolen);
}
}
++idx;
}
@ -346,23 +440,21 @@ struct llarp_win32_loop : public llarp_ev_loop
// and stop any pending I/O
BOOL stopped;
int close_fd;
switch(ev->fd.index())
if(std::holds_alternative< SOCKET >(ev->fd))
{
case 0:
stopped =
::CancelIo(reinterpret_cast< HANDLE >(std::get< SOCKET >(ev->fd)));
close_fd = closesocket(std::get< SOCKET >(ev->fd));
break;
case 1:
stopped = ::CancelIo(std::get< HANDLE >(ev->fd));
close_fd = CloseHandle(std::get< HANDLE >(ev->fd));
if(close_fd)
close_fd = 0; // must be zero
else
close_fd = 1;
break;
default:
return false;
stopped =
::CancelIo(reinterpret_cast< HANDLE >(std::get< SOCKET >(ev->fd)));
close_fd = closesocket(std::get< SOCKET >(ev->fd));
}
else
{
stopped = ::CancelIo(std::get< HANDLE >(ev->fd));
close_fd = CloseHandle(std::get< HANDLE >(ev->fd));
if(close_fd)
close_fd = 0; // must be zero
else
close_fd = 1;
}
return close_fd == 0 && stopped == TRUE;
}
@ -382,7 +474,7 @@ struct llarp_win32_loop : public llarp_ev_loop
llarp::ev_io*
create_tun(llarp_tun_io* tun)
{
llarp::tun* t = new llarp::tun(tun);
llarp::tun* t = new llarp::tun(tun, this);
if(t->setup())
return t;
delete t;
@ -397,6 +489,11 @@ struct llarp_win32_loop : public llarp_ev_loop
ev->listener_id = reinterpret_cast< ULONG_PTR >(ev);
memset(&buf, 0, 1024);
// if the write flag was set earlier,
// clear it on demand
if(ev->write && !write)
ev->write = false;
if(ev->isTCP)
{
if(!::CreateIoCompletionPort((HANDLE)std::get< SOCKET >(ev->fd), iocpfd,
@ -412,58 +509,49 @@ struct llarp_win32_loop : public llarp_ev_loop
ev->write = true;
}
else
{
::ReadFile((HANDLE)std::get< SOCKET >(ev->fd), &buf, 1024, nullptr,
&ev->portfd[0]);
}
handlers.emplace_back(ev);
return true;
}
switch(ev->fd.index())
{
case 0:
if(!::CreateIoCompletionPort((HANDLE)std::get< 0 >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
if(write)
{
::WriteFile((HANDLE)std::get< 0 >(ev->fd), &buf, 1024, nullptr,
&ev->portfd[1]);
ev->write = true;
}
else
{
::ReadFile((HANDLE)std::get< 0 >(ev->fd), &buf, 1024, nullptr,
&ev->portfd[0]);
}
break;
case 1:
t = dynamic_cast< llarp::tun* >(ev);
if(!::CreateIoCompletionPort(std::get< 1 >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
if(write)
{
::WriteFile(std::get< 1 >(ev->fd), &buf, 1024, nullptr,
t->tun_async[1]);
ev->write = true;
}
else
{
::ReadFile(std::get< 1 >(ev->fd), &buf, 1024, nullptr,
t->tun_async[0]);
}
break;
default:
if(std::holds_alternative< SOCKET >(ev->fd))
{
if(!::CreateIoCompletionPort((HANDLE)std::get< 0 >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
if(write)
{
::WriteFile((HANDLE)std::get< 0 >(ev->fd), &buf, 1024, nullptr,
&ev->portfd[1]);
ev->write = true;
}
else
::ReadFile((HANDLE)std::get< 0 >(ev->fd), &buf, 1024, nullptr,
&ev->portfd[0]);
}
else
{
t = dynamic_cast< llarp::tun* >(ev);
if(!::CreateIoCompletionPort(std::get< 1 >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
if(write)
{
::WriteFile(std::get< 1 >(ev->fd), &buf, 1024, nullptr,
t->tun_async[1]);
ev->write = true;
}
else
::ReadFile(std::get< 1 >(ev->fd), &buf, 1024, nullptr, t->tun_async[0]);
}
handlers.emplace_back(ev);
return true;
}
@ -498,6 +586,15 @@ struct llarp_win32_loop : public llarp_ev_loop
return iocpfd != INVALID_HANDLE_VALUE;
}
bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = std::get< SOCKET >(ev->fd);
return ev && add_ev(ev, false);
}
void
stop()
{

@ -269,7 +269,8 @@ namespace llarp
}
bool
Identity::SignIntroSet(IntroSet& i, llarp_crypto* crypto, llarp_time_t now) const
Identity::SignIntroSet(IntroSet& i, llarp_crypto* crypto,
llarp_time_t now) const
{
if(i.I.size() == 0)
return false;

Loading…
Cancel
Save