Merge branch 'staging' of ssh://github.com/loki-project/loki-network into staging

pull/244/head
Jeff Becker 5 years ago
commit ed0294ddcf
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

3
.gitignore vendored

@ -48,4 +48,7 @@ rapidjson/
.vscode
build64/
build2/
/contrib/lokinet-bootstrap-winnt/cacert.pem
/contrib/lokinet-bootstrap-winnt/data.enc
/contrib/lokinet-bootstrap-winnt/out.bine
default.profraw

@ -6,7 +6,7 @@ project(${PROJECT_NAME} C CXX ASM)
option(USE_LIBABYSS "enable libabyss" )
option(USE_AVX2 "enable avx2 code" )
option(USE_NETNS "enable networking namespace support" )
option(USE_NETNS "enable networking namespace support. Linux only" )
option(AMD_RYZEN_HACK "hack for AMD Ryzen FPU bug (support FMA3 and FMA4 in FPU, but does not show in CPUID)" )
option(STATIC_LINK "emit fully linked binaries" )
option(NON_PC_TARGET "non-pc target build: iphone, andriod, embedded non-i386 SBC, etc" )
@ -29,13 +29,18 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND SHADOW)
message( FATAL_ERROR "Shared library target is Linux only" )
message( FATAL_ERROR "shadow-framework is Linux only" )
endif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND SHADOW)
if (STATIC_LINK AND SHADOW)
message(FATAL_ERROR "the shadow-framework build cannot be linked statically!")
endif(STATIC_LINK AND SHADOW)
if (WIN32 AND NOT STATIC_LINK)
message("Shared object builds are not yet supported for Windows, linking statically")
set(STATIC_LINK ON)
endif(WIN32 AND NOT STATIC_LINK)
# turns off those annoying warnings for
# target-specific crypto code paths not
# applicable to the host's FPU -rick
@ -85,7 +90,7 @@ else()
if(NOT ANDROID)
if(NOT NON_PC_TARGET)
if (NOT USE_AVX2)
set(CRYPTO_FLAGS -march=core2 -msse4.1 -mtune=native -mfpmath=sse)
set(CRYPTO_FLAGS -march=nocona -mtune=native -mfpmath=sse)
else()
set(CRYPTO_FLAGS -march=haswell -mtune=native -mfpmath=sse)
endif(NOT USE_AVX2)
@ -180,6 +185,9 @@ endif(NOT GIT_VERSION)
if(RELEASE_MOTTO)
add_definitions(-DLLARP_RELEASE_MOTTO="${RELEASE_MOTTO}")
if(WIN32)
add_definitions(-DRELEASE_MOTTO=${RELEASE_MOTTO})
endif(WIN32)
endif(RELEASE_MOTTO)
set(EXE lokinet)
@ -695,13 +703,13 @@ else()
#add_executable(${CLIENT_EXE} ${CLIENT_SRC})
#add_executable(${DNS_EXE} ${DNS_SRC})
add_subdirectory(${GTEST_DIR})
if(NOT WIN32)
add_executable(${TEST_EXE} ${TEST_SRC})
add_executable(${EXE} ${EXE_SRC})
else()
add_executable(${TEST_EXE} ${TEST_SRC} llarp/version.rc)
add_executable(${EXE} ${EXE_SRC} llarp/version.rc)
endif(NOT WIN32)
if(NOT WIN32)
add_executable(${TEST_EXE} ${TEST_SRC})
add_executable(${EXE} ${EXE_SRC})
else()
add_executable(${TEST_EXE} ${TEST_SRC} llarp/constants/version.rc)
add_executable(${EXE} ${EXE_SRC} llarp/constants/version.rc)
endif(NOT WIN32)
target_include_directories(${TEST_EXE} PRIVATE test)
target_include_directories(${TEST_EXE} PRIVATE ${GTEST_DIR}/include ${GTEST_DIR})
@ -712,6 +720,7 @@ endif(NOT WIN32)
else()
install(PROGRAMS ${CMAKE_SOURCE_DIR}/lokinet-bootstrap DESTINATION bin)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(CODE "execute_process(COMMAND setcap cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)")
endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
@ -719,11 +728,13 @@ endif(NOT WIN32)
add_library(${STATIC_LIB} STATIC ${LIB_SRC})
add_library(${UTIL_LIB} STATIC ${LIB_UTIL_SRC})
add_library(${PLATFORM_LIB} STATIC ${LIB_PLATFORM_SRC})
if(USE_LIBABYSS)
target_link_libraries(${PLATFORM_LIB} ${UTIL_LIB} Threads::Threads ${ABYSS_LIB})
else()
target_link_libraries(${PLATFORM_LIB} ${UTIL_LIB} Threads::Threads)
endif(USE_LIBABYSS)
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if(NON_PC_TARGET)
target_link_libraries(${PLATFORM_LIB} -lrt)
@ -731,9 +742,11 @@ endif(NOT WIN32)
target_link_libraries(${PLATFORM_LIB} -lcap)
endif(NON_PC_TARGET)
endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
target_link_libraries(${STATIC_LIB} ${CRYPTOGRAPHY_LIB} ${LIBS} ${UTIL_LIB} ${PLATFORM_LIB})
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${UTIL_LIB} ${PLATFORM_LIB})
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${UTIL_LIB} ${PLATFORM_LIB})
if (WIN32)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${UTIL_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${UTIL_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
@ -750,4 +763,4 @@ endif(NOT WIN32)
target_link_libraries(${SHARED_LIB} ${CRYPTOGRAPHY_LIB} ${LIBS} ${UTIL_LIB} ${PLATFORM_LIB} Threads::Threads)
install(TARGETS ${SHARED_LIB} LIBRARY DESTINATION lib)
endif(WITH_SHARED)
endif(SHADOW)
endif(SHADOW)

@ -56,8 +56,6 @@ NON_PC_TARGET ?= OFF
STATIC_LINK ?= OFF
# enable network namespace isolation
NETNS ?= OFF
# using clang
CLANG ?= OFF
# cross compile?
CROSS ?= OFF
# build liblokinet-shared.so
@ -72,11 +70,11 @@ BUILD_ROOT = $(REPO)/build
SCAN_BUILD ?= scan-build
CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DUSING_CLANG=$(CLANG) -DSTATIC_LINK=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DUSE_LIBABYSS=$(JSONRPC) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) '$(REPO)'")
CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DUSE_LIBABYSS=$(JSONRPC) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) '$(REPO)'")
ANALYZE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "$(SCAN_BUILD) cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DUSING_CLANG=$(CLANG) -DSTATIC_LINK=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DUSE_LIBABYSS=$(JSONRPC) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) '$(REPO)'")
ANALYZE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "$(SCAN_BUILD) cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DUSE_LIBABYSS=$(JSONRPC) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) '$(REPO)'")
COVERAGE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DUSING_CLANG=$(CLANG) -DSTATIC_LINK=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DUSE_LIBABYSS=$(JSONRPC) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DWITH_COVERAGE=yes '$(REPO)'")
COVERAGE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DUSE_LIBABYSS=$(JSONRPC) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DWITH_COVERAGE=yes '$(REPO)'")
TARGETS = $(REPO)/lokinet
SIGS = $(TARGETS:=.sig)

File diff suppressed because it is too large Load Diff

@ -234,7 +234,6 @@ llarp_ensure_router_config(std::ofstream &f, std::string basepath)
bool
llarp_ensure_client_config(std::ofstream &f, std::string basepath)
{
#ifndef _WIN32
const std::string snappExample_fpath = basepath + "snapp-example.ini";
// done with fname.ini
// start client.ini
@ -268,7 +267,6 @@ llarp_ensure_client_config(std::ofstream &f, std::string basepath)
f << "# uncomment next line to enable persistant snapp" << std::endl;
f << "#example-snapp=" << snappExample_fpath << std::endl;
f << std::endl << std::endl;
#endif
f << "# network settings " << std::endl;
f << "[network]" << std::endl;

@ -1,9 +1,25 @@
// WARNING: for the love of all that is good and holy
// please DO NOT convert this file to UTF-8, much less
// UTF-16 - the UNIX cross-rc does not understand UTF-16,
// and UTF-8 chews up the copyright symbols.
// -rick
//
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#include <winresrc.h>
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
// English (United States) resources
#define STRINGIZER(version) #version
#ifdef LLARP_RELEASE_MOTTO
#define VERSION_STRING(version, codename, revision) \
STRINGIZER(version) "-release [" STRINGIZER(codename) "] (rev-" STRINGIZER(revision) ")"
#else
#define VERSION_STRING(version, revision) \
STRINGIZER(version) STRINGIZER(revision)
#endif
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
@ -42,8 +58,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,3,1,0
PRODUCTVERSION 0,3,1,0
FILEVERSION 0,4,0,0
PRODUCTVERSION 0,4,0,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x3L
@ -58,15 +74,23 @@ BEGIN
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "includes relay/exit functionality, such code is highly experimental on non UNIX/Linux/Macintosh targets!"
VALUE "Comments", "includes relay/exit functionality, such code is highly experimental on non-Linux targets"
VALUE "CompanyName", "Loki Foundation"
VALUE "FileDescription", "LokiNET daemon for Microsoft® Windows® NT™"
VALUE "FileVersion", "0.3.1-dev"
#ifdef LLARP_RELEASE_MOTTO
VALUE "FileVersion", VERSION_STRING(0.4.0, RELEASE_MOTTO, GIT_REV)
#else
VALUE "FileVersion", VERSION_STRING(0.4.0-dev-, GIT_REV)
#endif
VALUE "InternalName", "llarpd"
VALUE "LegalCopyright", "Copyright ©2018 Loki Foundation, Jeff Becker, Rick V. All rights reserved. This software is provided under the terms of the zlib-libpng licence; see the file LICENSE for details."
VALUE "LegalCopyright", "Copyright ©2018 Jeff Becker, Rick V for the Loki Foundation. All rights reserved. This software is provided under the terms of the zlib-libpng licence; see the file LICENSE for details."
VALUE "OriginalFilename", "llarpd.exe"
VALUE "ProductName", "LokiNET for Windows"
VALUE "ProductVersion", "0.3.1-dev"
#ifdef LLARP_RELEASE_MOTTO
VALUE "ProductVersion", VERSION_STRING(0.4.0, RELEASE_MOTTO, GIT_REV)
#else
VALUE "ProductVersion", VERSION_STRING(0.4.0-dev-, GIT_REV)
#endif
END
END
BLOCK "VarFileInfo"
@ -82,7 +106,8 @@ END
//
1 RT_MANIFEST "app.xml"
#endif // English (U.S.) resources
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////

@ -1 +1,583 @@
#include <ev/ev_kqueue.hpp>
namespace llarp
{
inline int
tcp_conn::read(byte_t* buf, size_t sz)
{
if(sz == 0)
{
if(tcp.read)
tcp.read(&tcp, llarp::InitBuffer(nullptr, 0));
return 0;
}
if(_shouldClose)
return -1;
ssize_t amount = ::read(fd, buf, sz);
if(amount >= 0)
{
if(tcp.read)
tcp.read(&tcp, llarp::InitBuffer(buf, amount));
}
else
{
if(errno == EAGAIN || errno == EWOULDBLOCK)
{
errno = 0;
return 0;
}
_shouldClose = true;
return -1;
}
return 0;
}
inline void
tcp_conn::flush_write()
{
connected();
ev_io::flush_write();
}
inline 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
}
inline 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");
connected();
}
else if(errno == EINPROGRESS)
{
llarp::LogDebug("connect in progress");
errno = 0;
return;
}
else if(_conn)
{
_conn->error(_conn);
}
}
inline 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;
}
// get flags
int flags = fcntl(new_fd, F_GETFL, 0);
if(flags == -1)
{
::close(new_fd);
return -1;
}
// set flags
if(fcntl(new_fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
llarp::LogError("Failed to set non block on ", fd, ": ", strerror(errno));
::close(new_fd);
return -1;
}
// build handler
llarp::tcp_conn* connimpl = new llarp::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)
{
sockaddr_in6 src;
socklen_t slen = sizeof(sockaddr_in6);
sockaddr* addr = (sockaddr*)&src;
ssize_t ret = ::recvfrom(fd, buf, sz, 0, addr, &slen);
if(ret < 0)
{
llarp::LogWarn("recvfrom failed");
return -1;
}
if(static_cast< size_t >(ret) > sz)
{
llarp::LogWarn("ret > sz");
return -1;
}
if(!addr)
{
llarp::LogWarn("no source addr");
}
// Addr is the source
udp->recvfrom(udp, addr, llarp::InitBuffer(buf, ret));
return 0;
}
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;
}
if(!fd)
{
printf("kqueue sendto fd empty\n");
return -1;
}
ssize_t sent = ::sendto(fd, data, sz, 0, to, slen);
if(sent == -1 || errno)
{
llarp::LogError("failed to send udp: ", strerror(errno));
errno = 0;
}
return sent;
}
int
tun::sendto(__attribute__((unused)) const sockaddr* to,
__attribute__((unused)) const void* data,
__attribute__((unused)) size_t sz)
{
return -1;
}
#ifdef __APPLE__
ssize_t
tun::do_write(void* buf, size_t sz)
{
iovec vecs[2];
// TODO: IPV6
uint32_t t = htonl(AF_INET);
vecs[0].iov_base = &t;
vecs[0].iov_len = sizeof(t);
vecs[1].iov_base = buf;
vecs[1].iov_len = sz;
return writev(fd, vecs, 2);
}
#endif
void
tun::before_flush_write()
{
if(t->before_write)
{
t->before_write(t);
}
}
bool
tun::tick()
{
if(t->tick)
t->tick(t);
flush_write();
return true;
}
int
tun::read(byte_t* buf, size_t)
{
// all BSDs have packet info except freebsd
#ifdef __FreeBSD__
const ssize_t offset = 0;
#else
const ssize_t offset = 4;
#endif
ssize_t ret = ::read(fd, buf, 1500);
if(ret > offset && t->recvpkt)
{
buf += offset;
ret -= offset;
auto pkt = llarp::InitBuffer(buf, ret);
t->recvpkt(t, pkt);
}
return ret;
}
bool
tun::setup()
{
llarp::LogDebug("set up tunif");
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1)
return false;
if(tuntap_up(tunif) == -1)
return false;
if(tuntap_set_ifname(tunif, t->ifname) == -1)
return false;
llarp::LogInfo("set ", tunif->if_name, " to use address ", t->ifaddr);
if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1)
return false;
fd = tunif->tun_fd;
return fd != -1;
}
}; // namespace llarp
llarp::ev_io*
llarp_kqueue_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;
}
// set non blocking
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
{
::close(fd);
return nullptr;
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
::close(fd);
return nullptr;
}
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
return serv;
}
llarp::ev_io*
llarp_kqueue_loop::create_tun(llarp_tun_io* tun)
{
llarp::tun* t = new llarp::tun(tun, this);
if(t->setup())
return t;
delete t;
return nullptr;
}
bool
llarp_kqueue_loop::init()
{
if(kqueuefd == -1)
{
kqueuefd = kqueue();
}
return kqueuefd != -1;
}
bool
llarp_kqueue_loop::running() const
{
return kqueuefd != -1;
}
bool
llarp_kqueue_loop::tcp_connect(llarp_tcp_connecter* tcp, const sockaddr* addr)
{
int fd = ::socket(addr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return false;
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, addr, tcp);
add_ev(conn, true);
conn->connect();
return true;
}
int
llarp_kqueue_loop::tick(int ms)
{
std::array< struct kevent, 1024 > events;
int result;
timespec t;
t.tv_sec = 0;
t.tv_nsec = ms * 1000000UL;
result = kevent(kqueuefd, nullptr, 0, events.data(), events.size(), &t);
// result: 0 is a timeout
if(result > 0)
{
int idx = 0;
while(idx < result)
{
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].udata);
if(ev)
{
if(events[idx].filter & EVFILT_READ)
ev->read(readbuf,
std::min(sizeof(readbuf), size_t(events[idx].data)));
if(events[idx].filter & EVFILT_WRITE)
{
ev->flush_write_buffers(events[idx].data);
}
}
++idx;
}
}
if(result != -1)
tick_listeners();
return result;
}
int
llarp_kqueue_loop::run()
{
timespec t;
t.tv_sec = 0;
t.tv_nsec = 1000000UL * EV_TICK_INTERVAL;
struct kevent events[1024];
int result;
do
{
result = kevent(kqueuefd, nullptr, 0, events, 1024, &t);
// result: 0 is a timeout
if(result > 0)
{
int idx = 0;
while(idx < result)
{
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].udata);
if(ev)
{
if(events[idx].filter & EVFILT_READ)
ev->read(readbuf,
std::min(sizeof(readbuf), size_t(events[idx].data)));
if(events[idx].filter & EVFILT_WRITE)
ev->flush_write_buffers(events[idx].data);
}
else
{
llarp::LogWarn("kqueue event ", idx, " udata wasnt an ev_io");
}
++idx;
}
}
if(result != -1)
tick_listeners();
} while(result != -1);
return result;
}
int
llarp_kqueue_loop::udp_bind(const sockaddr* addr)
{
socklen_t slen;
llarp::LogDebug("kqueue bind affam", addr->sa_family);
switch(addr->sa_family)
{
case AF_INET:
slen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
slen = sizeof(struct sockaddr_in6);
break;
#ifdef AF_LINK
#endif
#ifdef AF_PACKET
case AF_PACKET:
slen = sizeof(struct sockaddr_ll);
break;
#endif
default:
llarp::LogError("unsupported address family");
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);
// FreeBSD handbook said to do this
if(addr->sa_family == AF_INET && INADDR_ANY)
a._addr4.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(fd, addr, slen) == -1)
{
perror("bind()");
close(fd);
return -1;
}
return fd;
}
bool
llarp_kqueue_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_kqueue_loop::close_ev(llarp::ev_io* ev)
{
EV_SET(&ev->change, ev->fd, ev->flags, EV_DELETE, 0, 0, nullptr);
return kevent(kqueuefd, &ev->change, 1, nullptr, 0, nullptr) != -1;
}
llarp::ev_io*
llarp_kqueue_loop::create_udp(llarp_udp_io* l, const sockaddr* src)
{
int fd = udp_bind(src);
if(fd == -1)
return nullptr;
llarp::udp_listener* listener = new llarp::udp_listener(fd, l);
l->impl = listener;
return listener;
}
bool
llarp_kqueue_loop::add_ev(llarp::ev_io* ev, bool w)
{
ev->flags = EVFILT_READ;
EV_SET(&ev->change, ev->fd, EVFILT_READ, EV_ADD, 0, 0, ev);
if(kevent(kqueuefd, &ev->change, 1, nullptr, 0, nullptr) == -1)
{
llarp::LogError("Failed to add event: ", strerror(errno));
delete ev;
return false;
}
if(w)
{
ev->flags |= EVFILT_WRITE;
EV_SET(&ev->change, ev->fd, EVFILT_WRITE, EV_ADD, 0, 0, ev);
if(kevent(kqueuefd, &ev->change, 1, nullptr, 0, nullptr) == -1)
{
llarp::LogError("Failed to add event: ", strerror(errno));
delete ev;
return false;
}
}
handlers.emplace_back(ev);
return true;
}
bool
llarp_kqueue_loop::udp_close(llarp_udp_io* l)
{
bool ret = false;
auto listener = static_cast< llarp::udp_listener* >(l->impl);
if(listener)
{
// printf("Calling close_ev for [%x] fd[%d]\n", listener, listener->fd);
ret = close_ev(listener);
// remove handler
auto itr = handlers.begin();
while(itr != handlers.end())
{
if(itr->get() == listener)
{
itr = handlers.erase(itr);
ret = true;
}
else
++itr;
}
l->impl = nullptr;
}
return ret;
}
void
llarp_kqueue_loop::stop()
{
auto itr = handlers.begin();
while(itr != handlers.end())
{
close_ev(itr->get());
itr = handlers.erase(itr);
}
if(kqueuefd != -1)
::close(kqueuefd);
kqueuefd = -1;
}

@ -9,134 +9,15 @@
#include <sys/un.h>
#if __FreeBSD__ || __OpenBSD__ || __NetBSD__ || (__APPLE__ && __MACH__)
// kqueue / kevent
// why did we need a macro here, kqueue(7) _only_ exists
// on BSD and Macintosh
#include <sys/event.h>
#include <fcntl.h>
#endif
// original upstream
#include <unistd.h>
#include <cstdio>
namespace llarp
{
inline int
tcp_conn::read(byte_t* buf, size_t sz)
{
if(sz == 0)
{
if(tcp.read)
tcp.read(&tcp, llarp::InitBuffer(nullptr, 0));
return 0;
}
if(_shouldClose)
return -1;
ssize_t amount = ::read(fd, buf, sz);
if(amount >= 0)
{
if(tcp.read)
tcp.read(&tcp, llarp::InitBuffer(buf, amount));
}
else
{
if(errno == EAGAIN || errno == EWOULDBLOCK)
{
errno = 0;
return 0;
}
_shouldClose = true;
return -1;
}
return 0;
}
inline void
tcp_conn::flush_write()
{
connected();
ev_io::flush_write();
}
inline 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
}
inline 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");
connected();
}
else if(errno == EINPROGRESS)
{
llarp::LogDebug("connect in progress");
errno = 0;
return;
}
else if(_conn)
{
_conn->error(_conn);
}
}
inline 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;
}
// get flags
int flags = fcntl(new_fd, F_GETFL, 0);
if(flags == -1)
{
::close(new_fd);
return -1;
}
// set flags
if(fcntl(new_fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
llarp::LogError("Failed to set non block on ", fd, ": ", strerror(errno));
::close(new_fd);
return -1;
}
// build handler
llarp::tcp_conn* connimpl = new llarp::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;
}
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
@ -148,67 +29,13 @@ namespace llarp
}
bool
tick()
{
if(udp->tick)
udp->tick(udp);
return true;
}
tick();
virtual int
read(byte_t* buf, size_t sz)
{
sockaddr_in6 src;
socklen_t slen = sizeof(sockaddr_in6);
sockaddr* addr = (sockaddr*)&src;
ssize_t ret = ::recvfrom(fd, buf, sz, 0, addr, &slen);
if(ret < 0)
{
llarp::LogWarn("recvfrom failed");
return -1;
}
if(static_cast< size_t >(ret) > sz)
{
llarp::LogWarn("ret > sz");
return -1;
}
if(!addr)
{
llarp::LogWarn("no source addr");
}
// Addr is the source
udp->recvfrom(udp, addr, llarp::InitBuffer(buf, ret));
return 0;
}
read(byte_t* buf, size_t sz);
virtual int
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;
}
if(!fd)
{
printf("kqueue sendto fd empty\n");
return -1;
}
ssize_t sent = ::sendto(fd, data, sz, 0, to, slen);
if(sent == -1 || errno)
{
llarp::LogError("failed to send udp: ", strerror(errno));
errno = 0;
}
return sent;
}
sendto(const sockaddr* to, const void* data, size_t sz);
};
struct tun : public ev_io
@ -223,99 +50,23 @@ namespace llarp
int
sendto(__attribute__((unused)) const sockaddr* to,
__attribute__((unused)) const void* data,
__attribute__((unused)) size_t sz) override
{
return -1;
}
__attribute__((unused)) size_t sz) override;
#ifdef __APPLE__
ssize_t
do_write(void* buf, size_t sz) override
{
iovec vecs[2];
// TODO: IPV6
uint32_t t = htonl(AF_INET);
vecs[0].iov_base = &t;
vecs[0].iov_len = sizeof(t);
vecs[1].iov_base = buf;
vecs[1].iov_len = sz;
return writev(fd, vecs, 2);
}
do_write(void* buf, size_t sz) override;
#endif
void
before_flush_write() override
{
if(t->before_write)
{
t->before_write(t);
}
}
before_flush_write() override;
bool
tick() override
{
if(t->tick)
t->tick(t);
flush_write();
return true;
}
tick() override;
int
read(byte_t* buf, size_t) override
{
// all BSDs have packet info except freebsd
#ifdef __FreeBSD__
const ssize_t offset = 0;
#else
const ssize_t offset = 4;
#endif
ssize_t ret = ::read(fd, buf, 1500);
if(ret > offset && t->recvpkt)
{
buf += offset;
ret -= offset;
auto pkt = llarp::InitBuffer(buf, ret);
t->recvpkt(t, pkt);
}
return ret;
}
read(byte_t* buf, size_t) override;
bool
setup()
{
llarp::LogDebug("set up tunif");
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1)
{
llarp::LogWarn("Can't set tuntap to tunnel mode");
return false;
}
if(tuntap_up(tunif) == -1)
{
llarp::LogWarn("Can't bring up tuntap");
return false;
}
if(tuntap_set_ifname(tunif, t->ifname) == -1)
{
llarp::LogInfo("Can't set tun interface name to ", tunif->if_name);
return false;
}
// currently trying to set
llarp::LogInfo("setting ", tunif->if_name, " to use address ", t->ifaddr);
if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1)
{
llarp::LogWarn("Can't set tuntap ip on ", tunif->if_name, " to ",
t->ifaddr, " netmask ", t->netmask);
return false;
}
fd = tunif->tun_fd;
return fd != -1;
}
setup();
~tun()
{
@ -324,7 +75,7 @@ namespace llarp
}
};
}; // namespace llarp
} // namespace llarp
struct llarp_kqueue_loop : public llarp_ev_loop
{
@ -335,325 +86,50 @@ 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;
}
// set non blocking
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
{
::close(fd);
return nullptr;
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
::close(fd);
return nullptr;
}
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
return serv;
}
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr);
~llarp_kqueue_loop()
{
}
llarp::ev_io*
create_tun(llarp_tun_io* tun)
{
llarp::tun* t = new llarp::tun(tun, this);
if(t->setup())
return t;
llarp::LogWarn("Could not set up tun");
delete t;
return nullptr;
}
create_tun(llarp_tun_io* tun);
bool
init()
{
if(kqueuefd == -1)
{
kqueuefd = kqueue();
}
return kqueuefd != -1;
}
init();
bool
running() const
{
return kqueuefd != -1;
}
running() const;
bool
tcp_connect(llarp_tcp_connecter* tcp, const sockaddr* addr)
{
int fd = ::socket(addr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return false;
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, addr, tcp);
add_ev(conn, true);
conn->connect();
return true;
}
tcp_connect(llarp_tcp_connecter* tcp, const sockaddr* addr);
int
tick(int ms)
{
std::array< struct kevent, 1024 > events;
int result;
timespec t;
t.tv_sec = 0;
t.tv_nsec = ms * 1000000UL;
result = kevent(kqueuefd, nullptr, 0, events.data(), events.size(), &t);
// result: 0 is a timeout
if(result > 0)
{
int idx = 0;
while(idx < result)
{
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].udata);
if(ev)
{
if(events[idx].filter & EVFILT_WRITE)
ev->flush_write_buffers(events[idx].data);
if(events[idx].filter & EVFILT_READ)
ev->read(readbuf,
std::min(sizeof(readbuf), size_t(events[idx].data)));
}
++idx;
}
}
if(result != -1)
tick_listeners();
return result;
}
tick(int ms);
int
run()
{
timespec t;
t.tv_sec = 0;
t.tv_nsec = 1000000UL * EV_TICK_INTERVAL;
struct kevent events[1024];
int result;
do
{
result = kevent(kqueuefd, nullptr, 0, events, 1024, &t);
// result: 0 is a timeout
if(result > 0)
{
int idx = 0;
while(idx < result)
{
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].udata);
if(ev)
{
if(events[idx].filter & EVFILT_READ)
ev->read(readbuf,
std::min(sizeof(readbuf), size_t(events[idx].data)));
if(events[idx].filter & EVFILT_WRITE)
ev->flush_write_buffers(events[idx].data);
}
else
{
llarp::LogWarn("kqueue event ", idx, " udata wasnt an ev_io");
}
++idx;
}
}
if(result != -1)
tick_listeners();
} while(result != -1);
return result;
}
run();
int
udp_bind(const sockaddr* addr)
{
socklen_t slen;
llarp::LogDebug("kqueue bind affam", addr->sa_family);
switch(addr->sa_family)
{
case AF_INET:
slen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
slen = sizeof(struct sockaddr_in6);
break;
#ifdef AF_LINK
#endif
#ifdef AF_PACKET
case AF_PACKET:
slen = sizeof(struct sockaddr_ll);
break;
#endif
default:
llarp::LogError("unsupported address family");
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);
// FreeBSD handbook said to do this
if(addr->sa_family == AF_INET && INADDR_ANY)
a._addr4.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(fd, addr, slen) == -1)
{
perror("bind()");
close(fd);
return -1;
}
return fd;
}
udp_bind(const sockaddr* addr);
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);
}
udp_listen(llarp_udp_io* l, const sockaddr* src);
bool
close_ev(llarp::ev_io* ev)
{
EV_SET(&ev->change, ev->fd, ev->flags, EV_DELETE, 0, 0, nullptr);
return kevent(kqueuefd, &ev->change, 1, nullptr, 0, nullptr) != -1;
}
close_ev(llarp::ev_io* ev);
llarp::ev_io*
create_udp(llarp_udp_io* l, const sockaddr* src)
{
int fd = udp_bind(src);
if(fd == -1)
return nullptr;
llarp::udp_listener* listener = new llarp::udp_listener(fd, l);
l->impl = listener;
return listener;
}
create_udp(llarp_udp_io* l, const sockaddr* src);
bool
add_ev(llarp::ev_io* ev, bool w)
{
ev->flags = EVFILT_READ;
EV_SET(&ev->change, ev->fd, EVFILT_READ, EV_ADD, 0, 0, ev);
if(kevent(kqueuefd, &ev->change, 1, nullptr, 0, nullptr) == -1)
{
llarp::LogError("Failed to add event: ", strerror(errno));
delete ev;
return false;
}
if(w)
{
ev->flags |= EVFILT_WRITE;
EV_SET(&ev->change, ev->fd, EVFILT_WRITE, EV_ADD, 0, 0, ev);
if(kevent(kqueuefd, &ev->change, 1, nullptr, 0, nullptr) == -1)
{
llarp::LogError("Failed to add event: ", strerror(errno));
delete ev;
return false;
}
}
handlers.emplace_back(ev);
return true;
}
add_ev(llarp::ev_io* ev, bool w);
bool
udp_close(llarp_udp_io* l)
{
bool ret = false;
auto listener = static_cast< llarp::udp_listener* >(l->impl);
if(listener)
{
// printf("Calling close_ev for [%x] fd[%d]\n", listener, listener->fd);
ret = close_ev(listener);
// remove handler
auto itr = handlers.begin();
while(itr != handlers.end())
{
if(itr->get() == listener)
{
itr = handlers.erase(itr);
ret = true;
}
else
++itr;
}
l->impl = nullptr;
}
return ret;
}
udp_close(llarp_udp_io* l);
void
stop()
{
auto itr = handlers.begin();
while(itr != handlers.end())
{
close_ev(itr->get());
itr = handlers.erase(itr);
}
if(kqueuefd != -1)
::close(kqueuefd);
kqueuefd = -1;
}
stop();
};
#endif

@ -1 +1,629 @@
#include <ev/ev_win32.hpp>
// a single event queue for the TUN interface
HANDLE tun_event_queue = INVALID_HANDLE_VALUE;
// we hand the kernel our thread handles to process completion events
HANDLE* kThreadPool;
// list of TUN listeners (useful for exits or other nodes with multiple TUNs)
std::list< win32_tun_io* > tun_listeners;
void
begin_tun_loop(int nThreads)
{
kThreadPool = new HANDLE[nThreads];
for(int i = 0; i < nThreads; ++i)
{
kThreadPool[i] =
CreateThread(nullptr, 0, &tun_ev_loop, nullptr, 0, nullptr);
}
llarp::LogInfo("created ", nThreads, " threads for TUN event queue");
}
// this one is called from the TUN handler
bool
win32_tun_io::queue_write(const byte_t* buf, size_t sz)
{
do_write((void*)buf, sz);
return true;
}
bool
win32_tun_io::setup()
{
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1)
{
llarp::LogWarn("failed to start interface");
return false;
}
if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1)
{
llarp::LogWarn("failed to set ip");
return false;
}
if(tuntap_up(tunif) == -1)
{
char ebuf[1024];
int err = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL, ebuf,
1024, nullptr);
llarp::LogWarn("failed to put interface up: ", ebuf);
return false;
}
if(tunif->tun_fd == INVALID_HANDLE_VALUE)
return false;
return true;
}
// first TUN device gets to set up the event port
bool
win32_tun_io::add_ev()
{
if(tun_event_queue == INVALID_HANDLE_VALUE)
{
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
unsigned long numCPU = sys_info.dwNumberOfProcessors;
// let the system handle 2x the number of CPUs or hardware
// threads
tun_event_queue = CreateIoCompletionPort(tunif->tun_fd, nullptr,
(ULONG_PTR)this, numCPU * 2);
begin_tun_loop(numCPU * 2);
}
else
CreateIoCompletionPort(tunif->tun_fd, tun_event_queue, (ULONG_PTR)this, 0);
// we're already non-blocking
// add to list
tun_listeners.push_back(this);
read(readbuf, 4096);
return true;
}
// places data in event queue for kernel to process
void
win32_tun_io::do_write(void* data, size_t sz)
{
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->buf = data;
pkt->sz = sz;
pkt->write = true;
memset(&pkt->pkt, '\0', sizeof(pkt->pkt));
WriteFile(tunif->tun_fd, data, sz, nullptr, &pkt->pkt);
}
// while this one is called from the event loop
// eventually comes back and calls queue_write()
void
win32_tun_io::flush_write()
{
if(t->before_write)
t->before_write(t);
}
void
win32_tun_io::read(byte_t* buf, size_t sz)
{
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->buf = buf;
memset(&pkt->pkt, '\0', sizeof(OVERLAPPED));
pkt->sz = sz;
pkt->write = false;
ReadFile(tunif->tun_fd, buf, sz, nullptr, &pkt->pkt);
}
// and now the event loop itself
extern "C" DWORD FAR PASCAL
tun_ev_loop(void* unused)
{
UNREFERENCED_PARAMETER(unused);
DWORD size = 0;
OVERLAPPED* ovl = nullptr;
ULONG_PTR listener = 0;
asio_evt_pkt* pkt = nullptr;
BOOL alert;
while(true)
{
alert =
GetQueuedCompletionStatus(tun_event_queue, &size, &listener, &ovl, 100);
if(!alert)
{
// tick listeners on io timeout, this is required to be done every tick
// cycle regardless of any io being done, this manages the internal state
// of the tun logic
for(const auto& tun : tun_listeners)
{
if(tun->t->tick)
tun->t->tick(tun->t);
tun->flush_write();
}
continue; // let's go at it once more
}
if(listener == (ULONG_PTR)~0)
break;
// if we're here, then we got something interesting :>
pkt = (asio_evt_pkt*)ovl;
win32_tun_io* ev = reinterpret_cast< win32_tun_io* >(listener);
if(!pkt->write)
{
// llarp::LogInfo("read tun ", size, " bytes, pass to handler");
// skip if our buffer remains empty
// (if our buffer is empty, we don't even have a valid IP frame.
// just throw it out)
if(*(byte_t*)pkt->buf == '\0')
{
delete pkt;
continue;
}
if(ev->t->recvpkt)
ev->t->recvpkt(ev->t, llarp::InitBuffer(pkt->buf, size));
ev->read(ev->readbuf, sizeof(ev->readbuf));
}
else
{
// ok let's queue another read!
ev->read(ev->readbuf, sizeof(ev->readbuf));
}
if(ev->t->tick)
ev->t->tick(ev->t);
ev->flush_write();
delete pkt; // don't leak
}
llarp::LogInfo("exit TUN event loop thread from system managed thread pool");
return 0;
}
void
exit_tun_loop()
{
// if we get all-ones in the queue, thread exits, and we clean up
PostQueuedCompletionStatus(tun_event_queue, 0, ~0, nullptr);
// kill the kernel's thread pool
int i = (&kThreadPool)[1] - kThreadPool; // get the size of our thread pool
llarp::LogInfo("closing ", i, " threads");
WaitForMultipleObjects(i, kThreadPool, TRUE, INFINITE);
for(int j = 0; j < i; ++j)
CloseHandle(kThreadPool[j]);
delete[] kThreadPool;
// the IOCP refcount is decreased each time an associated fd
// is closed
// the fds are closed in their destructors
// once we get to zero, we can safely close the event port
auto itr = tun_listeners.begin();
while(itr != tun_listeners.end())
{
delete(*itr);
itr = tun_listeners.erase(itr);
}
CloseHandle(tun_event_queue);
}
namespace llarp
{
int
tcp_conn::read(byte_t* buf, size_t sz)
{
if(_shouldClose)
return -1;
ssize_t amount = uread(fd, (char*)buf, sz);
if(amount > 0)
{
if(tcp.read)
tcp.read(&tcp, llarp::InitBuffer(buf, amount));
}
else
{
// error
_shouldClose = true;
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;
return uwrite(fd, (char*)buf, sz);
}
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(WSAGetLastError() == WSAEINPROGRESS)
{
// in progress
llarp::LogDebug("connect in progress");
WSASetLastError(0);
return;
}
else if(_conn->error)
{
// wtf?
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogError("error connecting: ", ebuf);
_conn->error(_conn);
}
}
int
tcp_serv::read(byte_t*, size_t)
{
int new_fd = ::accept(fd, nullptr, nullptr);
if(new_fd == -1)
{
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogError("failed to accept on ", fd, ":", ebuf);
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, (char*)b.base, sz, 0, addr, &slen);
if(ret < 0)
return -1;
if(static_cast< size_t >(ret) > sz)
return -1;
b.sz = ret;
udp->recvfrom(udp, addr, b);
return 0;
}
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, (char*)data, sz, 0, to, slen);
if(sent == -1)
{
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogWarn(ebuf);
}
return sent;
}
}; // namespace llarp
bool
llarp_win32_loop::tcp_connect(struct llarp_tcp_connecter* tcp,
const sockaddr* remoteaddr)
{
// create socket
int fd = usocket(remoteaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
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_win32_loop::bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
int fd = usocket(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);
}
// 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 = sizeof(sockaddr_un);
if(::bind(fd, bindaddr, sz) == -1)
{
uclose(fd);
return nullptr;
}
if(ulisten(fd, 5) == -1)
{
uclose(fd);
return nullptr;
}
return new llarp::tcp_serv(this, fd, tcp);
}
bool
llarp_win32_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_win32_loop::running() const
{
return (upollfd != nullptr);
}
bool
llarp_win32_loop::init()
{
if(!upollfd)
upollfd = upoll_create(1);
return upollfd != nullptr;
}
// OK, the event loop, as it exists now, will _only_
// work on sockets (and not very efficiently at that).
int
llarp_win32_loop::tick(int ms)
{
upoll_event_t events[1024];
int result;
result = upoll_wait(upollfd, events, 1024, ms);
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();
return result;
}
int
llarp_win32_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_win32_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 = usocket(addr->sa_family, SOCK_DGRAM, 0);
if(fd == -1)
{
perror("usocket()");
return -1;
}
if(addr->sa_family == AF_INET6)
{
// enable dual stack explicitly
int dual = 1;
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&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_win32_loop::close_ev(llarp::ev_io* ev)
{
return upoll_ctl(upollfd, UPOLL_CTL_DEL, ev->fd, nullptr) != -1;
}
// no tunnels here
llarp::ev_io*
llarp_win32_loop::create_tun(llarp_tun_io* tun)
{
UNREFERENCED_PARAMETER(tun);
return nullptr;
}
llarp::ev_io*
llarp_win32_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_win32_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_win32_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_win32_loop::stop()
{
// do nothing
}

@ -1,8 +1,6 @@
#ifndef EV_WIN32_HPP
#define EV_WIN32_HPP
#ifndef EV_WIN32_H
#define EV_WIN32_H
#include <ev/ev.hpp>
#include <net/net.h>
#include <net/net.hpp>
#include <util/buffer.h>
@ -24,31 +22,37 @@ struct asio_evt_pkt
// to be zero-copy
};
struct win32_tun_io;
extern "C" DWORD FAR PASCAL
tun_ev_loop(void* unused);
// list of TUN listeners (useful for exits or other nodes with multiple TUNs)
std::list< win32_tun_io* > tun_listeners;
// a single event queue for the TUN interface
HANDLE tun_event_queue =
INVALID_HANDLE_VALUE; // we pass this to the event loop thread procedure
// upon setup
// we hand the kernel our thread handles to process completion events
HANDLE* kThreadPool;
void
exit_tun_loop();
void
begin_tun_loop(int nThreads)
begin_tun_loop(int nThreads);
namespace llarp
{
kThreadPool = new HANDLE[nThreads];
for(int i = 0; i < nThreads; ++i)
struct udp_listener : public ev_io
{
kThreadPool[i] =
CreateThread(nullptr, 0, &tun_ev_loop, nullptr, 0, nullptr);
}
llarp::LogInfo("created ", nThreads, " threads for TUN event queue");
}
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);
};
} // namespace llarp
// A different kind of event loop,
// more suited for the native Windows NT
@ -59,192 +63,29 @@ struct win32_tun_io
device* tunif;
byte_t readbuf[EV_READ_BUF_SZ] = {0};
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 GetNow
{
void* loop;
GetNow(void* l) : loop(l)
{
}
llarp_time_t
operator()() const
{
return llarp::time_now_ms();
}
};
struct PutTime
{
void* loop;
PutTime(void* l) : loop(l)
{
}
void
operator()(WriteBuffer& buf)
{
buf.timestamp = llarp::time_now_ms();
}
};
struct Compare
{
bool
operator()(const WriteBuffer& left, const WriteBuffer& right) const
{
return left.timestamp < right.timestamp;
}
};
};
using LossyWriteQueue_t =
llarp::util::CoDelQueue< WriteBuffer, WriteBuffer::GetTime,
WriteBuffer::PutTime, WriteBuffer::Compare,
WriteBuffer::GetNow, llarp::util::NullMutex,
llarp::util::NullLock, 5, 100, 128 >;
std::unique_ptr< LossyWriteQueue_t > m_LossyWriteQueue;
win32_tun_io(llarp_tun_io* tio) : t(tio), tunif(tuntap_init())
{
// This is not your normal everyday event loop, this is _advanced_ event
// handling :>
m_LossyWriteQueue = std::make_unique< LossyWriteQueue_t >("win32_tun_queue",
nullptr, nullptr);
};
win32_tun_io(llarp_tun_io* tio) : t(tio), tunif(tuntap_init()){};
bool
queue_write(const byte_t* buf, size_t sz)
{
if(m_LossyWriteQueue)
{
m_LossyWriteQueue->Emplace(buf, sz);
flush_write();
return true;
}
else
return false;
}
queue_write(const byte_t* buf, size_t sz);
bool
setup()
{
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1)
{
llarp::LogWarn("failed to start interface");
return false;
}
if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1)
{
llarp::LogWarn("failed to set ip");
return false;
}
if(tuntap_up(tunif) == -1)
{
char ebuf[1024];
int err = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogWarn("failed to put interface up: ", ebuf);
return false;
}
if(tunif->tun_fd == INVALID_HANDLE_VALUE)
return false;
return true;
}
setup();
// first TUN device gets to set up the event port
bool
add_ev()
{
if(tun_event_queue == INVALID_HANDLE_VALUE)
{
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
unsigned long numCPU = sys_info.dwNumberOfProcessors;
// let the system handle 2x the number of CPUs or hardware
// threads
tun_event_queue = CreateIoCompletionPort(tunif->tun_fd, nullptr,
(ULONG_PTR)this, numCPU * 2);
begin_tun_loop(numCPU * 2);
}
else
CreateIoCompletionPort(tunif->tun_fd, tun_event_queue, (ULONG_PTR)this,
0);
// we're already non-blocking
// add to list
tun_listeners.push_back(this);
read(readbuf, 4096);
return true;
}
add_ev();
// places data in event queue for kernel to process
void
do_write(void* data, size_t sz)
{
llarp::LogInfo("writing some data");
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->buf = data;
pkt->sz = sz;
pkt->write = true;
memset(&pkt->pkt, '\0', sizeof(pkt->pkt));
WriteFile(tunif->tun_fd, data, sz, nullptr, &pkt->pkt);
}
do_write(void* data, size_t sz);
// we call this one when we get a packet in the event port
// which then kicks off another write
void
flush_write()
{
if(t->before_write)
t->before_write(t);
m_LossyWriteQueue->Process([&](WriteBuffer& buffer) {
do_write(buffer.buf, buffer.bufsz);
// we are NEVER going to block
// because Windows NT implements true async io
});
}
flush_write();
void
read(byte_t* buf, size_t sz)
{
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->buf = buf;
memset(&pkt->pkt, '\0', sizeof(OVERLAPPED));
pkt->sz = sz;
pkt->write = false;
ReadFile(tunif->tun_fd, buf, sz, nullptr, &pkt->pkt);
}
read(byte_t* buf, size_t sz);
~win32_tun_io()
{
@ -254,243 +95,7 @@ struct win32_tun_io
}
};
// and now the event loop itself
extern "C" DWORD FAR PASCAL
tun_ev_loop(void* unused)
{
UNREFERENCED_PARAMETER(unused);
DWORD size = 0;
OVERLAPPED* ovl = nullptr;
ULONG_PTR listener = 0;
asio_evt_pkt* pkt = nullptr;
BOOL alert;
while(true)
{
alert =
GetQueuedCompletionStatus(tun_event_queue, &size, &listener, &ovl, 100);
if(!alert)
continue; // let's go at it once more
if(listener == (ULONG_PTR)~0)
break;
// if we're here, then we got something interesting :>
pkt = (asio_evt_pkt*)ovl;
win32_tun_io* ev = reinterpret_cast< win32_tun_io* >(listener);
if(!pkt->write)
{
// llarp::LogInfo("read tun ", size, " bytes, pass to handler");
if(ev->t->recvpkt)
ev->t->recvpkt(ev->t, llarp::InitBuffer(pkt->buf, size));
ev->flush_write();
ev->read(ev->readbuf, sizeof(ev->readbuf));
}
else
{
llarp::LogInfo("write ", size, " bytes to tunnel interface");
// ok let's queue another read!
ev->read(ev->readbuf, sizeof(ev->readbuf));
}
delete pkt; // don't leak
}
llarp::LogInfo("exit TUN event loop thread from system managed thread pool");
return 0;
}
void
exit_tun_loop()
{
// if we get all-ones in the queue, thread exits, and we clean up
PostQueuedCompletionStatus(tun_event_queue, 0, ~0, nullptr);
// kill the kernel's thread pool
int i = (&kThreadPool)[1] - kThreadPool; // get the size of our thread pool
llarp::LogInfo("closing ", i, " threads");
WaitForMultipleObjects(i, kThreadPool, TRUE, INFINITE);
for(int j = 0; j < i; ++j)
CloseHandle(kThreadPool[j]);
delete[] kThreadPool;
// the IOCP refcount is decreased each time an associated fd
// is closed
// the fds are closed in their destructors
// once we get to zero, we can safely close the event port
auto itr = tun_listeners.begin();
while(itr != tun_listeners.end())
{
delete(*itr);
itr = tun_listeners.erase(itr);
}
CloseHandle(tun_event_queue);
}
namespace llarp
{
int
tcp_conn::read(byte_t* buf, size_t sz)
{
if(_shouldClose)
return -1;
ssize_t amount = uread(fd, (char*)buf, sz);
if(amount > 0)
{
if(tcp.read)
tcp.read(&tcp, llarp::InitBuffer(buf, amount));
}
else
{
// error
_shouldClose = true;
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;
return uwrite(fd, (char*)buf, sz);
}
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(WSAGetLastError() == WSAEINPROGRESS)
{
// in progress
llarp::LogDebug("connect in progress");
WSASetLastError(0);
return;
}
else if(_conn->error)
{
// wtf?
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogError("error connecting: ", ebuf);
_conn->error(_conn);
}
}
int
tcp_serv::read(byte_t*, size_t)
{
int new_fd = ::accept(fd, nullptr, nullptr);
if(new_fd == -1)
{
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogError("failed to accept on ", fd, ":", ebuf);
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;
}
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()
{
if(udp->tick)
udp->tick(udp);
return true;
}
int
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, (char*)b.base, sz, 0, addr, &slen);
if(ret < 0)
return -1;
if(static_cast< size_t >(ret) > sz)
return -1;
b.sz = ret;
udp->recvfrom(udp, addr, b);
return 0;
}
int
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, (char*)data, sz, 0, to, slen);
if(sent == -1)
{
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogWarn(ebuf);
}
return sent;
}
};
}; // namespace llarp
// UDP event loop (we use select(3SOCKET) because linux)
struct llarp_win32_loop : public llarp_ev_loop
{
upoll_t* upollfd;
@ -500,56 +105,13 @@ struct llarp_win32_loop : public llarp_ev_loop
}
bool
tcp_connect(struct llarp_tcp_connecter* tcp, const sockaddr* remoteaddr)
{
// create socket
int fd = usocket(remoteaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return false;
llarp::tcp_conn* conn = new llarp::tcp_conn(this, fd, remoteaddr, tcp);
add_ev(conn, true);
conn->connect();
return true;
}
tcp_connect(struct llarp_tcp_connecter* tcp, const sockaddr* remoteaddr);
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
int fd = usocket(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);
}
// 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 = sizeof(sockaddr_un);
if(::bind(fd, bindaddr, sz) == -1)
{
uclose(fd);
return nullptr;
}
if(ulisten(fd, 5) == -1)
{
uclose(fd);
return nullptr;
}
return new llarp::tcp_serv(this, fd, tcp);
}
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr);
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);
}
udp_listen(llarp_udp_io* l, const sockaddr* src);
~llarp_win32_loop()
{
@ -558,219 +120,38 @@ struct llarp_win32_loop : public llarp_ev_loop
}
bool
running() const
{
return (upollfd != nullptr);
}
running() const;
bool
init()
{
if(!upollfd)
upollfd = upoll_create(1);
return upollfd != nullptr;
}
init();
// OK, the event loop, as it exists now, will _only_
// work on sockets (and not very efficiently at that).
int
tick(int ms)
{
upoll_event_t events[1024];
int result;
result = upoll_wait(upollfd, events, 1024, ms);
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();
return result;
}
tick(int ms);
int
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;
}
run();
int
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 = usocket(addr->sa_family, SOCK_DGRAM, 0);
if(fd == -1)
{
perror("usocket()");
return -1;
}
if(addr->sa_family == AF_INET6)
{
// enable dual stack explicitly
int dual = 1;
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&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;
}
udp_bind(const sockaddr* addr);
bool
close_ev(llarp::ev_io* ev)
{
return upoll_ctl(upollfd, UPOLL_CTL_DEL, ev->fd, nullptr) != -1;
}
close_ev(llarp::ev_io* ev);
// no tunnels here
llarp::ev_io*
create_tun(llarp_tun_io* tun)
{
UNREFERENCED_PARAMETER(tun);
return nullptr;
}
create_tun(llarp_tun_io* tun);
llarp::ev_io*
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;
}
create_udp(llarp_udp_io* l, const sockaddr* src);
bool
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;
}
add_ev(llarp::ev_io* e, bool write);
bool
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;
}
udp_close(llarp_udp_io* l);
void
stop()
{
// do nothing
}
stop();
};
#endif
#endif

@ -190,7 +190,7 @@ namespace llarp
{
for(auto& item : m_Upstream)
{
auto& queue = item.second;
auto& queue = item.second; // XXX: uninitialised memory here!
while(queue.size())
{
auto& msg = queue.front();

@ -700,8 +700,10 @@ namespace llarp
return pkt.Load(buf) && pkt.Header()->version == 4;
}))
{
#if defined(DEBUG) || !defined(RELEASE_MOTTO)
llarp::LogInfo("invalid pkt");
llarp::DumpBuffer(buf);
#endif
}
}

@ -587,6 +587,10 @@ namespace llarp
{
byte_t tmp[MAX_LINK_MSG_SIZE / 2];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
// should help prevent bad paths with uninitialised members
// FIXME: Why would we get uninitialised IMessages?
if(msg->version != LLARP_PROTO_VERSION)
return false;
if(!msg->BEncode(&buf))
{
llarp::LogError("Bencode failed");

@ -17,6 +17,7 @@
#include <fstream>
#include <cstdlib>
#include <iterator>
#if defined(RPI) || defined(ANDROID)
#include <unistd.h>
#endif

@ -317,13 +317,11 @@ namespace llarp
return false;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
{
std::ofstream f;
f.open(fname, std::ios::binary);
if(!f.is_open())
return false;
f.write((char *)buf.base, buf.sz);
}
std::ofstream f; // why was this in its own scope?
f.open(fname, std::ios::binary);
if(!f.is_open())
return false;
f.write((char *)buf.base, buf.sz);
return true;
}
@ -331,19 +329,17 @@ namespace llarp
RouterContact::Read(const char *fname)
{
byte_t tmp[MAX_RC_SIZE] = {0};
std::ifstream f;
f.open(fname, std::ios::binary);
if(!f.is_open())
{
std::ifstream f;
f.open(fname, std::ios::binary);
if(!f.is_open())
{
llarp::LogError("Failed to open ", fname);
return false;
}
f.seekg(0, std::ios::end);
auto l = f.tellg();
f.seekg(0, std::ios::beg);
f.read((char *)tmp, l);
llarp::LogError("Failed to open ", fname);
return false;
}
f.seekg(0, std::ios::end);
auto l = f.tellg();
f.seekg(0, std::ios::beg);
f.read((char *)tmp, l);
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
return BDecode(&buf);
}

@ -28,8 +28,11 @@ namespace llarp
{
// evidently, does nothing on LP64 systems (where size_t is *already*
// unsigned long but zero-extends this on LLP64 systems
std::copy(str.begin(), str.begin() + std::min(16UL, str.size()),
begin());
// 2Jan19: reeee someone undid the patch
std::copy(
str.begin(),
str.begin() + std::min(std::string::size_type(16), str.size()),
begin());
}
Tag&
@ -42,8 +45,10 @@ namespace llarp
Tag&
operator=(const std::string& str)
{
std::copy(str.begin(), str.begin() + std::min(16UL, str.size()),
begin());
std::copy(
str.begin(),
str.begin() + std::min(std::string::size_type(16), str.size()),
begin());
return *this;
}

@ -10,7 +10,7 @@
// these need to be in a specific order
#include <assert.h>
#include <net.h>
#include <net/net.h>
#include <windows.h>
#include <iphlpapi.h>
#if WINNT_CROSS_COMPILE && !NTSTATUS

@ -176,9 +176,6 @@ upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t* event)
int
upoll_wait_select(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
{
/* ok we need to test each file descriptor to see whether it is a real file
* or a socket. select any file handles (they are always ready)
*/
if(nev > FD_SETSIZE)
nev = FD_SETSIZE;

@ -29,10 +29,12 @@
#include <sys/stat.h>
// this is probably big enough to get
// the lesser of 4096 sockets or whatever
// the lesser of 96 sockets or whatever
// the system allows
// this used to be 4096, but i think
// that took ages to process
#ifndef FD_SETSIZE
#define FD_SETSIZE 4096
#define FD_SETSIZE 96
#endif
#include <io.h>

Binary file not shown.
Loading…
Cancel
Save