improve windows select loop

add generic svr4 poll(2) event loop
pull/452/head
Rick V 5 years ago
parent 65434a4e62
commit bbba2c0eea
No known key found for this signature in database
GPG Key ID: C0EDC8723FDC3465

@ -311,7 +311,7 @@ if(UNIX)
if (SOLARIS_HAVE_EPOLL)
get_filename_component(EV_SRC "llarp/ev/ev_epoll.cpp" ABSOLUTE)
else()
get_filename_component(EV_SRC "llarp/ev/ev_poll.cpp" ABSOLUTE)
get_filename_component(EV_SRC "llarp/ev/ev_sun.cpp" ABSOLUTE)
endif()
else()
message(FATAL_ERROR "Your operating system is not supported yet")

@ -78,6 +78,13 @@ win32/win32_upoll.c
)
endif(WIN32)
if (SOLARIS)
set(LIB_PLATFORM_SRC
${LIB_PLATFORM_SRC}
ev/upoll_sun.c
)
endif(SOLARIS)
add_library(${PLATFORM_LIB} STATIC ${LIB_PLATFORM_SRC})
target_link_libraries(${PLATFORM_LIB} PUBLIC ${CRYPTOGRAPHY_LIB} ${UTIL_LIB} libutp Threads::Threads)

@ -14,6 +14,8 @@
#elif defined(_WIN32) || defined(_WIN64) || defined(__NT__)
#define SHUT_RDWR SD_BOTH
#include <ev/ev_win32.hpp>
#elif defined(__sun) && !defined(SOLARIS_HAVE_EPOLL)
#include <ev/ev_sun.hpp>
#else
#error No async event loop for your platform, subclass llarp_ev_loop
#endif
@ -22,13 +24,15 @@
void
llarp_ev_loop_alloc(struct llarp_ev_loop **ev)
{
#if __linux__ || __sun__
#if __linux__ || SOLARIS_HAVE_EPOLL
*ev = new llarp_epoll_loop;
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| (__APPLE__ && __MACH__)
*ev = new llarp_kqueue_loop;
#elif defined(_WIN32) || defined(_WIN64) || defined(__NT__)
*ev = new llarp_win32_loop;
#elif defined(__sun) && !defined(SOLARIS_HAVE_EPOLL)
*ev = new llarp_poll_loop;
#else
// TODO: fall back to a generic select-based event loop
#error no event loop subclass
@ -40,15 +44,16 @@ llarp_ev_loop_alloc(struct llarp_ev_loop **ev)
std::unique_ptr< llarp_ev_loop >
llarp_make_ev_loop()
{
#if __linux__ || __sun__
#if __linux__ || SOLARIS_HAVE_EPOLL
std::unique_ptr< llarp_ev_loop > r = std::make_unique< llarp_epoll_loop >();
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| (__APPLE__ && __MACH__)
std::unique_ptr< llarp_ev_loop > r = std::make_unique< llarp_kqueue_loop >();
#elif defined(_WIN32) || defined(_WIN64) || defined(__NT__)
std::unique_ptr< llarp_ev_loop > r = std::make_unique< llarp_win32_loop >();
#elif defined(__sun) && !defined(SOLARIS_HAVE_EPOLL)
std::unique_ptr< llarp_ev_loop > r = std::make_unique< llarp_poll_loop >();
#else
// TODO: fall back to a generic select-based event loop
#error no event loop subclass
#endif
r->init();

@ -55,7 +55,11 @@ static ssize_t
IO(std::function< ssize_t(void) > iofunc)
{
ssize_t ret = iofunc();
errno = 0;
#ifndef _WIN32
errno = 0;
#else
WSASetLastError(0);
#endif
return ret;
}

@ -0,0 +1,526 @@
#include <ev/ev_sun.hpp>
namespace llarp
{
int
tcp_conn::read(byte_t* buf, size_t sz)
{
if(_shouldClose)
return -1;
ssize_t amount = ::read(fd, buf, sz);
if(amount > 0)
{
if(tcp.read)
tcp.read(&tcp, llarp_buffer_t(buf, amount));
}
else if(amount < 0)
{
// error
_shouldClose = true;
errno = 0;
return -1;
}
return 0;
}
void
tcp_conn::flush_write()
{
connected();
ev_io::flush_write();
}
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
}
void
tcp_conn::connect()
{
socklen_t slen = sizeof(sockaddr_in);
if(_addr.ss_family == AF_UNIX)
slen = sizeof(sockaddr_un);
else if(_addr.ss_family == AF_INET6)
slen = sizeof(sockaddr_in6);
int result = ::connect(fd, (const sockaddr*)&_addr, slen);
if(result == 0)
{
llarp::LogDebug("connected immedidately");
connected();
}
else if(errno == EINPROGRESS)
{
// in progress
llarp::LogDebug("connect in progress");
errno = 0;
return;
}
else if(_conn->error)
{
// wtf?
llarp::LogError("error connecting ", strerror(errno));
_conn->error(_conn);
errno = 0;
}
}
int
tcp_serv::read(byte_t*, size_t)
{
int new_fd = ::accept(fd, nullptr, nullptr);
if(new_fd == -1)
{
llarp::LogError("failed to accept on ", fd, ":", strerror(errno));
return -1;
}
// build handler
llarp::tcp_conn* connimpl = new tcp_conn(loop, new_fd);
if(loop->add_ev(connimpl, true))
{
// call callback
if(tcp->accepted)
tcp->accepted(tcp, &connimpl->tcp);
return 0;
}
// cleanup error
delete connimpl;
return -1;
}
bool
udp_listener::tick()
{
if(udp->tick)
udp->tick(udp);
return true;
}
int
udp_listener::read(byte_t* buf, size_t sz)
{
llarp_buffer_t b;
b.base = buf;
b.cur = b.base;
sockaddr_in6 src;
socklen_t slen = sizeof(sockaddr_in6);
sockaddr* addr = (sockaddr*)&src;
ssize_t ret = ::recvfrom(fd, b.base, sz, 0, addr, &slen);
if(ret < 0)
{
errno = 0;
return -1;
}
if(static_cast< size_t >(ret) > sz)
return -1;
b.sz = ret;
udp->recvfrom(udp, addr, ManagedBuffer{b});
return ret;
}
int
udp_listener::sendto(const sockaddr* to, const void* data, size_t sz)
{
socklen_t slen;
switch(to->sa_family)
{
case AF_INET:
slen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
slen = sizeof(struct sockaddr_in6);
break;
default:
return -1;
}
ssize_t sent = ::sendto(fd, data, sz, SOCK_NONBLOCK, to, slen);
if(sent == -1)
{
llarp::LogWarn(strerror(errno));
}
return sent;
}
int
tun::sendto(__attribute__((unused)) const sockaddr* to,
__attribute__((unused)) const void* data,
__attribute__((unused)) size_t sz)
{
return -1;
}
bool
tun::tick()
{
if(t->tick)
t->tick(t);
flush_write();
return true;
}
void
tun::flush_write()
{
if(t->before_write)
t->before_write(t);
ev_io::flush_write();
}
int
tun::read(byte_t* buf, size_t sz)
{
ssize_t ret = tuntap_read(tunif, buf, sz);
if(ret > 0 && t->recvpkt)
{
// does not have pktinfo
t->recvpkt(t, llarp_buffer_t(buf, ret));
}
return ret;
}
bool
tun::setup()
{
llarp::LogDebug("set ifname to ", t->ifname);
strncpy(tunif->if_name, t->ifname, sizeof(tunif->if_name));
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1)
{
llarp::LogWarn("failed to start interface");
return false;
}
if(tuntap_up(tunif) == -1)
{
llarp::LogWarn("failed to put interface up: ", strerror(errno));
return false;
}
if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1)
{
llarp::LogWarn("failed to set ip");
return false;
}
fd = tunif->tun_fd;
if(fd == -1)
return false;
// set non blocking
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
return false;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1;
}
}; // namespace llarp
bool
llarp_poll_loop::tcp_connect(struct llarp_tcp_connecter* tcp,
const sockaddr* remoteaddr)
{
// create socket
int fd = ::socket(remoteaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return false;
// set non blocking
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
{
::close(fd);
return false;
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
::close(fd);
return false;
}
llarp::tcp_conn* conn = new llarp::tcp_conn(this, fd, remoteaddr, tcp);
add_ev(conn, true);
conn->connect();
return true;
}
llarp::ev_io*
llarp_poll_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;
}
return new llarp::tcp_serv(this, fd, tcp);
}
bool
llarp_poll_loop::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
llarp_poll_loop::running() const
{
return upollfd != nullptr;
}
bool
llarp_poll_loop::init()
{
if(!upollfd)
upollfd = upoll_create(1); // why do we return false? (see ev_poll.cpp)
return false;
}
int
llarp_poll_loop::tick(int ms)
{
upoll_event_t events[1024];
int result;
result = upoll_wait(upollfd, events, 1024, ms);
bool didIO = false;
if(result > 0)
{
int idx = 0;
while(idx < result)
{
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev)
{
llarp::LogDebug(idx, " of ", result, " on ", ev->fd,
" events=", std::to_string(events[idx].events));
if(events[idx].events & UPOLLERR && errno)
{
IO([&]() -> ssize_t {
llarp::LogDebug("upoll error");
ev->error();
return 0;
});
}
else
{
// write THEN READ don't revert me
if(events[idx].events & UPOLLOUT)
{
IO([&]() -> ssize_t {
llarp::LogDebug("upoll out");
ev->flush_write();
return 0;
});
}
if(events[idx].events & UPOLLIN)
{
ssize_t amount = IO([&]() -> ssize_t {
llarp::LogDebug("upoll in");
return ev->read(readbuf, sizeof(readbuf));
});
if(amount > 0)
didIO = true;
}
}
}
++idx;
}
}
if(result != -1)
tick_listeners();
/// if we didn't get an io events we sleep to avoid 100% cpu use
if(!didIO)
std::this_thread::sleep_for(std::chrono::milliseconds(5));
return result;
}
int
llarp_poll_loop::run()
{
upoll_event_t events[1024];
int result;
do
{
result = upoll_wait(upollfd, events, 1024, EV_TICK_INTERVAL);
if(result > 0)
{
int idx = 0;
while(idx < result)
{
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev)
{
if(events[idx].events & UPOLLERR)
{
ev->error();
}
else
{
if(events[idx].events & UPOLLIN)
{
ev->read(readbuf, sizeof(readbuf));
}
if(events[idx].events & UPOLLOUT)
{
ev->flush_write();
}
}
}
++idx;
}
}
if(result != -1)
tick_listeners();
} while(upollfd);
return result;
}
int
llarp_poll_loop::udp_bind(const sockaddr* addr)
{
socklen_t slen;
switch(addr->sa_family)
{
case AF_INET:
slen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
slen = sizeof(struct sockaddr_in6);
break;
default:
return -1;
}
int fd = socket(addr->sa_family, SOCK_DGRAM, 0);
if(fd == -1)
{
perror("socket()");
return -1;
}
if(addr->sa_family == AF_INET6)
{
// enable dual stack explicitly
int dual = 1;
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &dual, sizeof(dual)) == -1)
{
// failed
perror("setsockopt()");
close(fd);
return -1;
}
}
llarp::Addr a(*addr);
llarp::LogDebug("bind to ", a);
if(bind(fd, addr, slen) == -1)
{
perror("bind()");
close(fd);
return -1;
}
return fd;
}
bool
llarp_poll_loop::close_ev(llarp::ev_io* ev)
{
return upoll_ctl(upollfd, UPOLL_CTL_DEL, ev->fd, nullptr) != -1;
}
llarp::ev_io*
llarp_poll_loop::create_tun(llarp_tun_io* tun)
{
llarp::tun* t = new llarp::tun(tun, this);
if(t->setup())
{
return t;
}
delete t;
return nullptr;
}
llarp::ev_io*
llarp_poll_loop::create_udp(llarp_udp_io* l, const sockaddr* src)
{
int fd = udp_bind(src);
if(fd == -1)
return nullptr;
llarp::ev_io* listener = new llarp::udp_listener(fd, l);
l->impl = listener;
return listener;
}
bool
llarp_poll_loop::add_ev(llarp::ev_io* e, bool write)
{
upoll_event_t ev;
ev.data.ptr = e;
ev.events = UPOLLIN | UPOLLERR;
if(write)
ev.events |= UPOLLOUT;
if(upoll_ctl(upollfd, UPOLL_CTL_ADD, e->fd, &ev) == -1)
{
delete e;
return false;
}
handlers.emplace_back(e);
return true;
}
bool
llarp_poll_loop::udp_close(llarp_udp_io* l)
{
bool ret = false;
llarp::udp_listener* listener = static_cast< llarp::udp_listener* >(l->impl);
if(listener)
{
close_ev(listener);
// remove handler
auto itr = handlers.begin();
while(itr != handlers.end())
{
if(itr->get() == listener)
itr = handlers.erase(itr);
else
++itr;
}
l->impl = nullptr;
ret = true;
}
return ret;
}
void
llarp_poll_loop::stop()
{
// close all handlers before closing the upoll fd
auto itr = handlers.begin();
while(itr != handlers.end())
{
close_ev(itr->get());
itr = handlers.erase(itr);
}
if(upollfd)
upoll_destroy(upollfd);
upollfd = nullptr;
}

@ -0,0 +1,136 @@
#ifndef EV_POLL_HPP
#define EV_POLL_HPP
#include <ev/ev.hpp>
#include <net/net.h>
#include <net/net.hpp>
#include <util/buffer.hpp>
#include <util/buffer.hpp>
#include <util/logger.hpp>
#include <util/mem.hpp>
#include <cassert>
#include <cstdio>
#include <fcntl.h>
#include <signal.h>
#include "upoll_sun.h"
#include <sys/un.h>
#include <tuntap.h>
#include <unistd.h>
namespace llarp
{
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
udp_listener(int fd, llarp_udp_io* u) : ev_io(fd), udp(u){};
~udp_listener()
{
}
bool
tick();
int
read(byte_t* buf, size_t sz);
int
sendto(const sockaddr* to, const void* data, size_t sz);
};
struct tun : public ev_io
{
llarp_tun_io* t;
device* tunif;
tun(llarp_tun_io* tio, llarp_ev_loop* l)
: ev_io(-1, new LossyWriteQueue_t("tun_write_queue", l, l))
, t(tio)
, tunif(tuntap_init())
{
};
int
sendto(const sockaddr* to, const void* data, size_t sz);
bool
tick();
void
flush_write();
int
read(byte_t* buf, size_t sz);
bool
setup();
~tun()
{
if(tunif)
tuntap_destroy(tunif);
}
};
}; // namespace llarp
struct llarp_poll_loop : public llarp_ev_loop
{
upoll_t* upollfd;
llarp_poll_loop() : upollfd(nullptr)
{
}
~llarp_poll_loop()
{
if(upollfd)
upoll_destroy(upollfd);
}
bool
tcp_connect(struct llarp_tcp_connecter* tcp, const sockaddr* remoteaddr);
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr);
virtual bool
udp_listen(llarp_udp_io* l, const sockaddr* src);
bool
running() const;
bool
init();
int
tick(int ms);
int
run();
int
udp_bind(const sockaddr* addr);
bool
close_ev(llarp::ev_io* ev);
llarp::ev_io*
create_tun(llarp_tun_io* tun);
llarp::ev_io*
create_udp(llarp_udp_io* l, const sockaddr* src);
bool
add_ev(llarp::ev_io* e, bool write);
bool
udp_close(llarp_udp_io* l);
void
stop();
};
#endif

@ -464,7 +464,8 @@ llarp_win32_loop::tick(int ms)
{
upoll_event_t events[1024];
int result;
result = upoll_wait(upollfd, events, 1024, ms);
result = upoll_wait(upollfd, events, 1024, ms);
bool didIO = false;
if(result > 0)
{
int idx = 0;
@ -473,28 +474,46 @@ llarp_win32_loop::tick(int ms)
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev)
{
if(events[idx].events & UPOLLERR)
llarp::LogDebug(idx, " of ", result, " on ", ev->fd,
" events=", std::to_string(events[idx].events));
if(events[idx].events & UPOLLERR && WSAGetLastError())
{
ev->error();
IO([&]() -> ssize_t {
llarp::LogDebug("upoll error");
ev->error();
return 0;
});
}
else
{
if(events[idx].events & UPOLLIN)
// write THEN READ don't revert me
if(events[idx].events & UPOLLOUT)
{
ev->read(readbuf, sizeof(readbuf));
IO([&]() -> ssize_t {
llarp::LogDebug("upoll out");
ev->flush_write();
return 0;
});
}
if(events[idx].events & UPOLLOUT)
if(events[idx].events & UPOLLIN)
{
ev->flush_write();
ssize_t amount = IO([&]() -> ssize_t {
llarp::LogDebug("upoll in");
return ev->read(readbuf, sizeof(readbuf));
});
if(amount > 0)
didIO = true;
}
}
}
++idx;
}
}
if(result != -1)
tick_listeners();
/// if we didn't get an io events we sleep to avoid 100% cpu use
if(!didIO)
std::this_thread::sleep_for(std::chrono::milliseconds(5));
return result;
}

@ -0,0 +1,433 @@
#include "upoll_sun.h"
#define uhash_slot(K, S) (((K) ^ (K >> 8)) & (S - 1))
static uhash_t*
uhash_create(uint32_t size)
{
int i;
size--;
size |= size >> 1;
size |= size >> 2;
size |= size >> 4;
size |= size >> 8;
size |= size >> 16;
size++;
uhash_t* hash = (uhash_t*)calloc(1, sizeof(uhash_t) + size * sizeof(ulist_t));
hash->count = 0;
hash->size = size;
hash->items = (ulist_t*)(((char*)hash) + sizeof(uhash_t));
for(i = 0; i < size; i++)
{
ulist_init(&hash->items[i]);
}
return hash;
}
static void*
uhash_lookup(uhash_t* hash, intptr_t key)
{
uint32_t slot = uhash_slot(key, hash->size);
ulist_t* q;
ulist_scan(q, &hash->items[slot])
{
uitem_t* i = ulist_data(q, uitem_t, list);
if(i->key == key)
return i->val;
}
return NULL;
}
static void
uhash_insert(uhash_t* hash, intptr_t key, void* val)
{
uint32_t slot = uhash_slot(key, hash->size);
uitem_t* item = (uitem_t*)calloc(1, sizeof(uitem_t));
ulist_init(&item->list);
item->key = key;
item->val = val;
ulist_append(&hash->items[slot], &item->list);
}
static int
uhash_delete(uhash_t* hash, intptr_t key)
{
uint32_t slot = uhash_slot(key, hash->size);
ulist_t* q;
ulist_scan(q, &hash->items[slot])
{
uitem_t* i = ulist_data(q, uitem_t, list);
if(i->key == key)
{
ulist_remove(q);
free(q);
return 1;
}
}
return 0;
}
static int
uhash_destroy(uhash_t* hash)
{
int i;
for(i = 0; i < hash->size; i++)
{
while(!ulist_empty(&hash->items[i]))
{
ulist_t* q = ulist_next(&hash->items[i]);
uitem_t* n = ulist_data(q, uitem_t, list);
ulist_remove(q);
free(n);
}
}
return 0;
}
upoll_t*
upoll_create(uint32_t size)
{
assert(size > 0);
upoll_t* upq = (upoll_t*)calloc(1, sizeof(upoll_t));
ulist_init(&upq->alive);
upq->table = uhash_create(size);
return upq;
}
void
upoll_destroy(upoll_t* upq)
{
assert(upq != NULL);
uhash_destroy(upq->table);
ulist_t* q;
unote_t* n;
while(!ulist_empty(&upq->alive))
{
q = ulist_next(&upq->alive);
n = ulist_data(n, unote_t, queue);
ulist_remove(q);
free(n);
}
free(upq);
}
int
upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t* event)
{
if(fd < 0)
return -EBADF;
unote_t* note = NULL;
switch(op)
{
case UPOLL_CTL_ADD:
{
note = (unote_t*)uhash_lookup(upq->table, fd);
if(!note)
{
note = (unote_t*)calloc(1, sizeof(unote_t));
note->upoll = upq;
ulist_init(&note->queue);
note->event = *event;
note->fd = fd;
ulist_append(&upq->alive, &note->queue);
uhash_insert(upq->table, fd, (void*)note);
}
break;
}
case UPOLL_CTL_DEL:
{
note = (unote_t*)uhash_lookup(upq->table, fd);
if(!note)
return -ENOENT;
event = &note->event;
ulist_remove(&note->queue);
uhash_delete(upq->table, fd);
free(note);
break;
}
case UPOLL_CTL_MOD:
{
note = (unote_t*)uhash_lookup(upq->table, fd);
if(!note)
return -ENOENT;
note->event = *event;
break;
}
default:
{
return -EINVAL;
}
}
return 0;
}
int
upoll_wait_poll(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
{
/* FD_SETSIZE should be smaller than OPEN_MAX, but OPEN_MAX isn't portable */
if(nev > FD_SETSIZE)
nev = FD_SETSIZE;
unote_t* nvec[nev];
int r, i, nfds = 0;
uint32_t hint;
struct pollfd pfds[nev];
unote_t* n = NULL;
ulist_t* s = ulist_mark(&upq->alive);
ulist_t* q = ulist_next(&upq->alive);
while(q != s && nfds < nev)
{
n = ulist_data(q, unote_t, queue);
q = ulist_next(q);
ulist_remove(&n->queue);
ulist_insert(&upq->alive, &n->queue);
nvec[nfds] = n;
pfds[nfds].events = 0;
pfds[nfds].fd = n->fd;
if(n->event.events & UPOLLIN)
{
pfds[nfds].events |= POLLIN;
}
if(n->event.events & UPOLLOUT)
{
pfds[nfds].events |= POLLOUT;
}
nfds++;
}
r = poll(pfds, nfds, timeout);
if(r < 0)
return -errno;
int e = 0;
for(i = 0; i < nfds && e < nev; i++)
{
hint = 0;
if(pfds[i].revents)
{
n = nvec[i];
if(pfds[i].revents & POLLIN)
hint |= UPOLLIN;
if(pfds[i].revents & POLLOUT)
hint |= UPOLLOUT;
if(pfds[i].revents & (POLLERR | POLLNVAL | POLLHUP))
hint |= (UPOLLERR | UPOLLIN);
if(hint & UPOLLERR)
hint &= ~UPOLLOUT;
evs[e].data = n->event.data;
evs[e].events = hint;
++e;
}
}
return e;
}
int
upoll_wait(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
{
int r = 0;
r = upoll_wait_poll(upq, evs, nev, timeout);
return r;
}
intptr_t
usocket(int domain, int type, int proto)
{
intptr_t fd = (intptr_t)socket(domain, type, proto);
if(fd < 0)
return -errno;
int rc = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
if(rc < 0)
return -errno;
return fd;
}
int
ubind(intptr_t fd, const char* host, const char* serv)
{
struct addrinfo* info;
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
int optval = 0;
unsigned int optlen = sizeof(optval);
int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
hint.ai_family = AF_INET;
hint.ai_socktype = optval;
rc = getaddrinfo(host, serv, &hint, &info);
optval = 1;
if(!rc)
{
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if(!rc)
rc = bind(fd, info->ai_addr, info->ai_addrlen);
}
freeaddrinfo(info);
if(rc)
{
return errno;
}
return 0;
}
int
uconnect(intptr_t fd, const char* host, const char* serv)
{
struct addrinfo* info;
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
int optval = 0;
unsigned int optlen;
int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
hint.ai_family = AF_INET;
hint.ai_socktype = optval;
rc = getaddrinfo(host, serv, &hint, &info);
if(!rc)
{
rc = connect(fd, info->ai_addr, info->ai_addrlen);
}
freeaddrinfo(info);
if(rc)
{
if(errno != EINPROGRESS)
return errno;
}
return 0;
}
int
ulisten(intptr_t sock, int backlog)
{
return listen(sock, backlog);
}
intptr_t
uaccept(intptr_t sock)
{
struct sockaddr addr;
addr.sa_family = AF_INET;
socklen_t addr_len;
intptr_t fd = accept(sock, &addr, &addr_len);
if(fd < 0)
return errno;
return fd;
}
int
uclose(intptr_t sock)
{
return close(sock);
}
int
uread(intptr_t fd, char* buf, size_t len)
{
return recv(fd, buf, len, 0);
}
int
uwrite(intptr_t fd, const char* buf, size_t len)
{
return send(fd, buf, len, 0);
}
/* adapted from (renamed make_overlapped to async for allergy reasons): */
/* socketpair.c
Copyright 2007, 2010 by Nathan C. Myers <ncm@cantrip.org>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
The name of the author must not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Changes:
* 2014-02-12: merge David Woodhouse, Ger Hobbelt improvements
* git.infradead.org/users/dwmw2/openconnect.git/commitdiff/bdeefa54
* github.com/GerHobbelt/selectable-socketpair
* always init the socks[] to -1/INVALID_SOCKET on error, both on Win32/64
* and UNIX/other platforms
* 2013-07-18: Change to BSD 3-clause license
* 2010-03-31:
* set addr to 127.0.0.1 because win32 getsockname does not always set it.
* 2010-02-25:
* set SO_REUSEADDR option to avoid leaking some windows resource.
* Windows System Error 10049, "Event ID 4226 TCP/IP has reached
* the security limit imposed on the number of concurrent TCP connect
* attempts." Bleah.
* 2007-04-25:
* preserve value of WSAGetLastError() on all error returns.
* 2007-04-22: (Thanks to Matthew Gregan <kinetik@flim.org>)
* s/EINVAL/WSAEINVAL/ fix trivial compile failure
* s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout
* of a child process.
* add argument make_overlapped
*/
int
usocketpair(intptr_t socks[2], int dummy)
{
int sovec[2];
if(socks == 0)
{
errno = EINVAL;
return -1;
}
dummy = socketpair(AF_LOCAL, SOCK_STREAM, 0, sovec);
if(dummy)
{
socks[0] = socks[1] = -1;
}
else
{
socks[0] = sovec[0];
socks[1] = sovec[1];
}
return dummy;
}

@ -0,0 +1,178 @@
#ifndef _UPOLL_H_
#define _UPOLL_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#define UPOLL_CTL_ADD 1
#define UPOLL_CTL_DEL 2
#define UPOLL_CTL_MOD 3
#define UPOLLIN 0x01
#define UPOLLOUT 0x02
#define UPOLLERR 0x04
#define UPOLLET 0x08
typedef struct upoll upoll_t;
typedef union upoll_data {
void* ptr;
intptr_t fd;
uint32_t u32;
uint64_t u64;
} upoll_data_t;
typedef struct upoll_event
{
uint32_t events;
upoll_data_t data;
} upoll_event_t;
upoll_t*
upoll_create(uint32_t size);
int
upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t* event);
int
upoll_wait(upoll_t* upq, upoll_event_t* events, int maxevents, int timeout);
void
upoll_destroy(upoll_t* upq);
intptr_t
usocket(int domain, int type, int proto);
intptr_t
uaccept(intptr_t sock);
int
ubind(intptr_t sock, const char* name, const char* serv);
int
ulisten(intptr_t sock, int backlog);
int
uconnect(intptr_t sock, const char* name, const char* serv);
int
uclose(intptr_t sock);
int
uread(intptr_t fd, char* buf, size_t len);
int
uwrite(intptr_t fd, const char* buf, size_t len);
int
usocketpair(intptr_t socks[2], int async);
#if(defined(__64BIT__) || defined(__x86_64__))
#define __IS_64BIT__
#else
#define __IS_32BIT__
#endif
#include <sys/types.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <poll.h>
typedef struct unote unote_t;
typedef struct ulist ulist_t;
typedef struct uitem uitem_t;
typedef struct uhash uhash_t;
struct ulist
{
ulist_t* next;
ulist_t* prev;
};
struct uitem
{
ulist_t list;
intptr_t key;
void* val;
};
struct uhash
{
uint16_t count;
uint16_t size;
ulist_t* items;
};
struct upoll
{
int fd; /* backend fd (epoll, kqueue) */
ulist_t alive; /* all notes this queue knows about */
uhash_t* table;
};
struct unote
{
upoll_event_t event;
intptr_t fd;
ulist_t queue; /* handle for the queue's notes */
upoll_t* upoll;
};
#define container_of(ptr, type, member) \
((type*)((char*)(ptr)-offsetof(type, member)))
#define ulist_init(q) \
(q)->prev = q; \
(q)->next = q
#define ulist_head(h) (h)->next
#define ulist_next(q) (q)->next
#define ulist_tail(h) (h)->prev
#define ulist_prev(q) (q)->prev
#define ulist_empty(h) (h == (h)->prev)
#define ulist_append(h, x) \
(x)->prev = (h)->prev; \
(x)->prev->next = x; \
(x)->next = h; \
(h)->prev = x
#define ulist_insert(h, x) \
(x)->next = (h)->next; \
(x)->next->prev = x; \
(x)->prev = h; \
(h)->next = x
#define ulist_remove(x) \
(x)->next->prev = (x)->prev; \
(x)->prev->next = (x)->next; \
(x)->prev = x; \
(x)->next = x
#define ulist_mark(h) (h)
#define ulist_scan(q, h) \
for((q) = ulist_head(h); (q) != ulist_mark(h); (q) = ulist_next(q))
#define ulist_data(q, type, link) container_of(q, type, link)
#ifdef __cplusplus
}
#endif
#endif /* _UPOLL_H_ */

@ -2,7 +2,6 @@
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
namespace network.loki.lokinet.win32.ui

Loading…
Cancel
Save