tun code refactor (#1495)

* partial tun code refactor

* take out the trash

* move vpn platform code into llarp/vpn/platform.cpp

* fix hive build

* fix win32

* fix memory leak on win32

* reduce cpu use

* make macos compile

* win32 patches:

* use wepoll for zmq
* use all cores on windows iocp read loop

* fix zmq patch for windows

* clean up cmake for win32

* add uninstall before reinstall option to win32 installer

* more ipv6 stuff

* make it compile

* fix up route poker

* remove an unneeded code block in macos wtf

* always use call to system

* fix route poker behavior on macos

* disable ipv6 on windows for now

* cpu perf improvement:

* colease calls to Router::PumpLL to 1 per event loop wakeup

* set up THEN add addresses

* emulate proactor event loop on win32

* remove excessively verbose error message

* fix issue #1499

* exclude uv_poll from win32 so that it can start up

* update logtag to include directory

* create minidump on windows if there was a crash

* make windows happy

* use dmp suffix on minidump files

* typo fix

* address feedback from jason
* use PROJECT_SOURCE_DIR instead of CMAKE_SOURCE_DIR
* quote $@ in apply-patches in case path has spaces in it

* address feedback from tom

* remove llarp/ev/pipe
* add comments for clairification
* make event loop queue size constant named
stable
Jeff 2021-01-11 18:13:22 -05:00 committed by GitHub
parent 029b6db364
commit 49b9ad7197
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
124 changed files with 1416 additions and 8657 deletions

View File

@ -23,7 +23,7 @@ set(RELEASE_MOTTO "Proof of soon" CACHE STRING "Release motto")
add_definitions(-DLLARP_VERSION_MAJOR=${lokinet_VERSION_MAJOR})
add_definitions(-DLLARP_VERSION_MINOR=${lokinet_VERSION_MINOR})
add_definitions(-DLLARP_VERSION_PATCH=${lokinet_VERSION_PATCH})
if(RELEASE_MOTTO)
if(RELEASE_MOTTO AND CMAKE_BUILD_TYPE MATCHES "[Rr][Ee][Ll][Ee][Aa][Ss][Ee]")
add_definitions(-DLLARP_RELEASE_MOTTO="${RELEASE_MOTTO}")
endif()
@ -329,8 +329,6 @@ add_subdirectory(external/date EXCLUDE_FROM_ALL)
include_directories(SYSTEM external/sqlite_orm/include)
add_subdirectory(vendor)
if(ANDROID)
target_link_libraries(base_libs INTERFACE log)
target_compile_definitions(base_libs INTERFACE ANDROID)

View File

@ -259,9 +259,16 @@ build_external(sqlite3)
add_static_target(sqlite3 sqlite3_external libsqlite3.a)
if(ZMQ_VERSION VERSION_LESS 4.3.4 AND CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
if(ARCH_TRIPLET MATCHES mingw)
set(zmq_extra --with-poller=wepoll)
endif()
if(CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
set(zmq_patch
PATCH_COMMAND patch -p1 -i ${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-closesocket.patch)
PATCH_COMMAND ${PROJECT_SOURCE_DIR}/contrib/apply-patches.sh ${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-wepoll.patch)
if(ZMQ_VERSION VERSION_LESS 4.3.4)
set(zmq_patch ${zmq_patch} ${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-closesocket.patch)
endif()
endif()
build_external(zmq
@ -269,7 +276,7 @@ build_external(zmq
${zmq_patch}
CONFIGURE_COMMAND ./configure ${cross_host} --prefix=${DEPS_DESTDIR} --enable-static --disable-shared
--disable-curve-keygen --enable-curve --disable-drafts --disable-libunwind --with-libsodium
--without-pgm --without-norm --without-vmci --without-docs --with-pic --disable-Werror
--without-pgm --without-norm --without-vmci --without-docs --with-pic --disable-Werror ${zmq_extra}
"CC=${deps_cc}" "CXX=${deps_cxx}" "CFLAGS=${deps_CFLAGS} -fstack-protector" "CXXFLAGS=${deps_CXXFLAGS} -fstack-protector"
"sodium_CFLAGS=-I${DEPS_DESTDIR}/include" "sodium_LIBS=-L${DEPS_DESTDIR}/lib -lsodium"
)

View File

@ -1,6 +1,8 @@
function(add_log_tag target)
get_target_property(TARGET_SRCS ${target} SOURCES)
foreach(F ${TARGET_SRCS})
set_property(SOURCE ${F} APPEND PROPERTY COMPILE_DEFINITIONS LOG_TAG=\"${F}\")
get_filename_component(fpath "${F}" ABSOLUTE)
string(REPLACE "${PROJECT_SOURCE_DIR}/" "" logtag "${fpath}")
set_property(SOURCE ${F} APPEND PROPERTY COMPILE_DEFINITIONS LOG_TAG=\"${logtag}\")
endforeach()
endfunction()

View File

@ -1,5 +1,8 @@
set(GUI_ZIP_URL "https://oxen.rocks/loki-project/loki-network-control-panel/master/lokinet-gui-windows-32bit-v0.3.5.zip")
set(GUI_ZIP_HASH SHA256=fcb1d78f7d6eecb440d05a034dd7e60ae506275af5b0f600b416bb1a896f32aa)
if(NOT GUI_ZIP_URL)
set(GUI_ZIP_URL "https://oxen.rocks/loki-project/loki-network-control-panel/master/lokinet-gui-windows-32bit-v0.3.5.zip")
set(GUI_ZIP_HASH_OPTS EXPECTED_HASH SHA256=fcb1d78f7d6eecb440d05a034dd7e60ae506275af5b0f600b416bb1a896f32aa)
endif()
set(TUNTAP_URL "https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe")
set(TUNTAP_EXE "${CMAKE_BINARY_DIR}/tuntap-install.exe")
set(BOOTSTRAP_URL "https://seed.lokinet.org/lokinet.signed")
@ -16,7 +19,7 @@ file(DOWNLOAD
file(DOWNLOAD
${GUI_ZIP_URL}
${CMAKE_BINARY_DIR}/lokinet-gui.zip
EXPECTED_HASH ${GUI_ZIP_HASH})
${GUI_ZIP_HASH_OPTS})
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf ${CMAKE_BINARY_DIR}/lokinet-gui.zip
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
@ -28,6 +31,7 @@ install(FILES ${BOOTSTRAP_FILE} DESTINATION share)
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Lokinet")
set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/win32-setup/lokinet.ico")
set(CPACK_NSIS_DEFINES "RequestExecutionLevel admin")
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '$INSTDIR\\\\bin\\\\tuntap-install.exe /S'\\nExecWait '$INSTDIR\\\\bin\\\\lokinet.exe --install'\\nExecWait '$INSTDIR\\\\bin\\\\lokinet.exe -g C:\\\\ProgramData\\\\lokinet\\\\lokinet.ini'\\nCopyFiles '$INSTDIR\\\\share\\\\bootstrap.signed' C:\\\\ProgramData\\\\lokinet\\\\bootstrap.signed")
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "ExecWait 'net stop lokinet'\\nExecWait 'taskkill /f /t /im lokinet-gui.exe'\\nExecWait '$INSTDIR\\\\bin\\\\lokinet.exe --remove'\\nRMDir /r /REBOOTOK C:\\\\ProgramData\\\\lokinet")
set(CPACK_NSIS_CREATE_ICONS_EXTRA

4
contrib/apply-patches.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
for f in "$@" ; do
patch -p1 -i "$f"
done

View File

@ -0,0 +1,16 @@
diff --git a/external/wepoll/wepoll.c b/external/wepoll/wepoll.c
--- a/external/wepoll/wepoll.c
+++ b/external/wepoll/wepoll.c
@@ -140,9 +140,9 @@
#pragma warning(push, 1)
#endif
-#include <WS2tcpip.h>
-#include <WinSock2.h>
-#include <Windows.h>
+#include <ws2tcpip.h>
+#include <winsock2.h>
+#include <windows.h>
#ifndef __GNUC__
#pragma warning(pop)

View File

@ -1,5 +1,5 @@
#!/bin/bash
mkdir -p build-windows
cd build-windows
cmake -G Ninja -DCMAKE_CROSSCOMPILE=ON -DCMAKE_EXE_LINKER_FLAGS=-fstack-protector -DLIBUV_ROOT=$PWD/../external/libuv -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always -DCMAKE_TOOLCHAIN_FILE=../contrib/cross/mingw64.cmake -DBUILD_STATIC_DEPS=ON -DBUILD_PACKAGE=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DWITH_TESTS=OFF -DNATIVE_BUILD=OFF -DSTATIC_LINK=ON -DWITH_SYSTEMD=OFF -DFORCE_LOKIMQ_SUBMODULE=ON -DSUBMODULE_CHECK=OFF -DWITH_LTO=OFF ..
cmake -G Ninja -DCMAKE_CROSSCOMPILE=ON -DCMAKE_EXE_LINKER_FLAGS=-fstack-protector -DLIBUV_ROOT=$PWD/../external/libuv -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always -DCMAKE_TOOLCHAIN_FILE=../contrib/cross/mingw64.cmake -DBUILD_STATIC_DEPS=ON -DBUILD_PACKAGE=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DWITH_TESTS=OFF -DNATIVE_BUILD=OFF -DSTATIC_LINK=ON -DWITH_SYSTEMD=OFF -DFORCE_LOKIMQ_SUBMODULE=ON -DSUBMODULE_CHECK=OFF -DWITH_LTO=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_CROSSCOMPLING=ON ..
ninja package

View File

@ -8,6 +8,10 @@
#include <util/str.hpp>
#include <util/thread/logic.hpp>
#ifdef _WIN32
#include <dbghelp.h>
#endif
#include <csignal>
#include <cxxopts.hpp>
@ -329,6 +333,45 @@ class WindowsServiceStopped
TellWindowsServiceStopped();
}
};
/// minidump generation for windows jizz
/// will make a coredump when there is an unhandled exception
LONG
GenerateDump(EXCEPTION_POINTERS* pExceptionPointers)
{
std::stringstream ss;
ss << "C:\\ProgramData\\lokinet\\crash-" << llarp::time_now_ms().count() << ".dmp";
const std::string fname = ss.str();
HANDLE hDumpFile;
SYSTEMTIME stLocalTime;
GetLocalTime(&stLocalTime);
MINIDUMP_EXCEPTION_INFORMATION ExpParam;
hDumpFile = CreateFile(
fname.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
0,
CREATE_ALWAYS,
0,
0);
ExpParam.ThreadId = GetCurrentThreadId();
ExpParam.ExceptionPointers = pExceptionPointers;
ExpParam.ClientPointers = TRUE;
MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hDumpFile,
MiniDumpWithDataSegs,
&ExpParam,
NULL,
NULL);
return 1;
}
#endif
int
@ -521,6 +564,10 @@ lokinet_main(int argc, char* argv[])
return 0;
}
#ifdef _WIN32
SetUnhandledExceptionFilter(&GenerateDump);
#endif
std::thread main_thread{std::bind(&run_main_context, configFile, opts)};
auto ftr = exit_code.get_future();

View File

@ -4,6 +4,7 @@
#include <util/fs.hpp>
#include <util/types.hpp>
#include <ev/ev.hpp>
#include <ev/vpn.hpp>
#include <nodedb.hpp>
#include <crypto/crypto.hpp>
#include <router/abstractrouter.hpp>
@ -95,6 +96,10 @@ namespace llarp
virtual std::unique_ptr<AbstractRouter>
makeRouter(llarp_ev_loop_ptr __netloop, std::shared_ptr<Logic> logic);
/// create the vpn platform for use in creating network interfaces
virtual std::unique_ptr<llarp::vpn::Platform>
makeVPNPlatform();
protected:
std::shared_ptr<Config> config = nullptr;

View File

@ -1,267 +0,0 @@
/*
* Copyright (c) 2012 Tristan Le Guern <leguern AT medu DOT se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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 SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#if defined Windows
#else /* Unix */
#include <sys/socket.h>
#endif
#if !defined Windows /* Unix :) */
#if !defined Linux
#include <netinet/in.h>
#endif
#if defined(Linux)
// Once we drop xenial support we can just include net/if.h on linux
#include <linux/if.h>
#else
#include <net/if.h>
#endif
#if defined Linux
#include <netinet/in.h>
#elif defined(iOS)
#include <net/ethernet.h>
#else
#include <netinet/if_ether.h>
#endif
#endif
#include <stdint.h>
#ifndef LIBTUNTAP_H_
#define LIBTUNTAP_H_
#if defined IFNAMSIZ && !defined IF_NAMESIZE
#define IF_NAMESIZE IFNAMSIZ /* Historical BSD name */
#elif !defined IF_NAMESIZE
#define IF_NAMESIZE 16
#endif
#define IF_DESCRSIZE 50 /* XXX: Tests needed on NetBSD and OpenBSD */
#if defined TUNSETDEBUG
#define TUNSDEBUG TUNSETDEBUG
#endif
#if defined Windows
#define TUNFD_INVALID_VALUE INVALID_HANDLE_VALUE
#else /* Unix */
#define TUNFD_INVALID_VALUE -1
#endif
/*
* Uniformize types
* - t_tun: tun device file descriptor
* - t_tun_in_addr: struct in_addr/IN_ADDR
* - t_tun_in6_addr: struct in6_addr/IN6_ADDR
*/
#if defined Windows
#include <windows.h>
#include <in6addr.h>
#include <winsock2.h>
typedef HANDLE t_tun;
typedef IN_ADDR t_tun_in_addr;
typedef IN6_ADDR t_tun_in6_addr;
#else /* Unix */
typedef int t_tun;
typedef struct in_addr t_tun_in_addr;
typedef struct in6_addr t_tun_in6_addr;
#endif
/*
* Windows helpers
*/
#if defined Windows
//#define strncat(x, y, z) strncat_s((x), _countof(x), (y), (z));
#define strdup(x) _strdup(x)
#endif
#define TUNTAP_ID_MAX 256
#define TUNTAP_ID_ANY 257
#define TUNTAP_MODE_ETHERNET 0x0001
#define TUNTAP_MODE_TUNNEL 0x0002
#define TUNTAP_MODE_PERSIST 0x0004
#define TUNTAP_LOG_NONE 0x0000
#define TUNTAP_LOG_DEBUG 0x0001
#define TUNTAP_LOG_INFO 0x0002
#define TUNTAP_LOG_NOTICE 0x0004
#define TUNTAP_LOG_WARN 0x0008
#define TUNTAP_LOG_ERR 0x0016
/* Versioning: 0xMMmm, with 'M' for major and 'm' for minor */
#define TUNTAP_VERSION_MAJOR 0
#define TUNTAP_VERSION_MINOR 3
#define TUNTAP_VERSION ((TUNTAP_VERSION_MAJOR << 8) | TUNTAP_VERSION_MINOR)
#define TUNTAP_GET_FD(x) (x)->tun_fd
/* Handle Windows symbols export */
#if defined Windows
#if defined(tuntap_EXPORTS) && defined(_USRDLL) /* CMake generated goo */
#define TUNTAP_EXPORT __declspec(dllexport)
#elif defined(tuntap_EXPORTS)
#define TUNTAP_EXPORT __declspec(dllimport)
#else
#define TUNTAP_EXPORT extern
#endif
#else /* Unix */
#define TUNTAP_EXPORT extern
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct device
{
/** set me on ios and android to block on a promise for the fd */
int (*obtain_fd)(struct device*);
/** user data */
void* user;
t_tun tun_fd;
int ctrl_sock;
int flags; /* ifr.ifr_flags on Unix */
char if_name[IF_NAMESIZE];
#if defined(Windows)
int idx; /* needed to set ipv6 address */
DWORD bindaddr; /* set DNS client address */
#endif
#if defined(FreeBSD)
int mode;
#endif
#if defined(__sun)
int ip_fd;
int reserved;
char internal_name[IF_NAMESIZE];
#endif
};
/* User definable log callback */
typedef void (*t_tuntap_log)(int, int, const char*, const char*);
TUNTAP_EXPORT t_tuntap_log __tuntap_log;
#ifndef LOG_TAG
#define LOG_TAG "tuntap"
#endif
#define tuntap_log(lvl, msg) __tuntap_log(lvl, __LINE__, LOG_TAG, msg)
/* Portable "public" functions */
TUNTAP_EXPORT struct device*
tuntap_init(void);
TUNTAP_EXPORT int
tuntap_version(void);
TUNTAP_EXPORT void
tuntap_destroy(struct device*);
TUNTAP_EXPORT void
tuntap_release(struct device*);
TUNTAP_EXPORT int
tuntap_start(struct device*, int, int);
TUNTAP_EXPORT char*
tuntap_get_ifname(struct device*);
TUNTAP_EXPORT int
tuntap_set_ifname(struct device*, const char*);
TUNTAP_EXPORT int
tuntap_set_descr(struct device*, const char*);
TUNTAP_EXPORT int
tuntap_up(struct device*);
TUNTAP_EXPORT int
tuntap_down(struct device*);
TUNTAP_EXPORT int
tuntap_get_mtu(struct device*);
TUNTAP_EXPORT int
tuntap_set_mtu(struct device*, int);
/** set ip address and netmask
*/
TUNTAP_EXPORT int
tuntap_set_ip(struct device*, const char* srcaddr, const char* dstaddr, int netmask);
// TUNTAP_EXPORT int tuntap_set_ip_old(struct device *, const char
// *, int);
/*TUNTAP_EXPORT int tuntap_set_ip_old(struct device *, const char
* *, int);*/
TUNTAP_EXPORT int
tuntap_read(struct device*, void*, size_t);
TUNTAP_EXPORT int
tuntap_write(struct device*, void*, size_t);
TUNTAP_EXPORT int
tuntap_get_readable(struct device*);
TUNTAP_EXPORT int
tuntap_set_nonblocking(struct device* dev, int);
TUNTAP_EXPORT int
tuntap_set_debug(struct device* dev, int);
/* Logging functions */
TUNTAP_EXPORT void
tuntap_log_set_cb(t_tuntap_log cb);
void
tuntap_log_default(int, int, const char*, const char*);
void
tuntap_log_hexdump(void*, size_t);
void
tuntap_log_chksum(void*, int);
/* OS specific functions */
int
tuntap_sys_start(struct device*, int, int);
void
tuntap_sys_destroy(struct device*);
int
tuntap_sys_set_ipv4(struct device*, t_tun_in_addr*, uint32_t);
#if defined(Windows)
int
tuntap_sys_set_dns(struct device* dev, t_tun_in_addr* s, uint32_t mask);
#endif
#if defined(FreeBSD)
int
tuntap_sys_set_ipv4_tap(struct device*, t_tun_in_addr*, uint32_t);
int
tuntap_sys_set_ipv4_tun(
struct device* dev, t_tun_in_addr* s4, t_tun_in_addr* s4dest, uint32_t bits, int netmask);
#endif
int
tuntap_sys_set_ipv6(struct device*, t_tun_in6_addr*, uint32_t);
int
tuntap_sys_set_ifname(struct device*, const char*, size_t);
int
tuntap_sys_set_descr(struct device*, const char*, size_t);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -52,7 +52,6 @@ add_library(lokinet-platform
ev/ev.cpp
ev/pipe.cpp
ev/ev_libuv.cpp
net/ip.cpp
net/ip_address.cpp
net/ip_packet.cpp
@ -61,7 +60,7 @@ add_library(lokinet-platform
net/net_int.cpp
net/route.cpp
net/sock_addr.cpp
$<TARGET_OBJECTS:tuntap>
vpn/platform.cpp
)
target_link_libraries(lokinet-platform PUBLIC lokinet-cryptography lokinet-util Threads::Threads base_libs libuv)
@ -83,7 +82,6 @@ endif()
if (WIN32)
target_sources(lokinet-platform PRIVATE
ev/ev_libuv.cpp
ev/ev_win32.cpp
win32/win32_inet.c
win32/win32_intrnl.c)

View File

@ -98,7 +98,16 @@ namespace llarp
std::unique_ptr<AbstractRouter>
Context::makeRouter(llarp_ev_loop_ptr netloop, std::shared_ptr<Logic> logic)
{
return std::make_unique<Router>(netloop, logic);
return std::make_unique<Router>(netloop, logic, makeVPNPlatform());
}
std::unique_ptr<vpn::Platform>
Context::makeVPNPlatform()
{
auto plat = vpn::MakeNativePlatform(this);
if (plat == nullptr)
throw std::runtime_error("vpn platform not supported");
return plat;
}
int
@ -123,9 +132,9 @@ namespace llarp
llarp_ev_loop_run_single_process(mainloop, logic);
if (closeWaiter)
{
// inform promise if called by CloseAsync
closeWaiter->set_value();
}
Close();
return 0;
}
@ -177,13 +186,6 @@ namespace llarp
/// async stop router on sigint
router->Stop();
}
else
{
if (logic)
logic->stop();
llarp_ev_loop_stop(mainloop);
Close();
}
}
void

View File

@ -47,14 +47,7 @@ namespace llarp
return false;
}
}
const IpAddress any("0.0.0.0", 0);
auto self = shared_from_this();
LogicCall(m_ClientLogic, [=]() {
llarp_ev_add_udp(self->m_ClientLoop.get(), &self->m_Client, any.createSockAddr());
});
return (
llarp_ev_add_udp(self->m_ServerLoop.get(), &self->m_Server, addr.createSockAddr()) == 0);
return (llarp_ev_add_udp(m_ServerLoop, &m_Server, addr.createSockAddr()) == 0);
}
static Proxy::Buffer_t

View File

@ -9,10 +9,6 @@
// We libuv now
#include <ev/ev_libuv.hpp>
#if defined(_WIN32) || defined(_WIN64) || defined(__NT__)
#define SHUT_RDWR SD_BOTH
#include <ev/ev_win32.hpp>
#endif
llarp_ev_loop_ptr
llarp_make_ev_loop(size_t queueLength)
@ -34,14 +30,14 @@ llarp_ev_loop_run_single_process(llarp_ev_loop_ptr ev, std::shared_ptr<llarp::Lo
}
int
llarp_ev_add_udp(struct llarp_ev_loop* ev, struct llarp_udp_io* udp, const llarp::SockAddr& src)
llarp_ev_add_udp(const llarp_ev_loop_ptr& ev, struct llarp_udp_io* udp, const llarp::SockAddr& src)
{
if (ev == nullptr or udp == nullptr)
{
llarp::LogError("Attempting llarp_ev_add_udp() with null event loop or udp io struct.");
return -1;
}
udp->parent = ev;
udp->parent = ev.get();
if (ev->udp_listen(udp, src))
return 0;
llarp::LogError("llarp_ev_add_udp() call to udp_listen failed.");
@ -75,129 +71,3 @@ llarp_ev_udp_sendto(struct llarp_udp_io* udp, const llarp::SockAddr& to, const l
{
return udp->sendto(udp, to, buf.base, buf.sz);
}
bool
llarp_ev_add_tun(struct llarp_ev_loop* loop, struct llarp_tun_io* tun)
{
if (tun->ifaddr[0] == 0 || strcmp(tun->ifaddr, "auto") == 0)
{
LogError("invalid ifaddr on tun: ", tun->ifaddr);
return false;
}
if (tun->ifname[0] == 0 || strcmp(tun->ifname, "auto") == 0)
{
LogError("invalid ifname on tun: ", tun->ifname);
return false;
}
#if !defined(_WIN32)
return loop->tun_listen(tun);
#else
UNREFERENCED_PARAMETER(loop);
auto dev = new win32_tun_io(tun);
tun->impl = dev;
// We're not even going to add this to the socket event loop
if (dev)
{
dev->setup();
return dev->add_ev(loop); // start up tun and add to event queue
}
llarp::LogWarn("Loop could not create tun");
return false;
#endif
}
bool
llarp_ev_tun_async_write(struct llarp_tun_io* tun, const llarp_buffer_t& buf)
{
if (buf.sz > EV_WRITE_BUF_SZ)
{
llarp::LogWarn("packet too big, ", buf.sz, " > ", EV_WRITE_BUF_SZ);
return false;
}
#ifndef _WIN32
return tun->writepkt(tun, buf.base, buf.sz);
#else
return static_cast<win32_tun_io*>(tun->impl)->queue_write(buf.base, buf.sz);
#endif
}
bool
llarp_tcp_conn_async_write(struct llarp_tcp_conn* conn, const llarp_buffer_t& b)
{
ManagedBuffer buf{b};
size_t sz = buf.underlying.sz;
buf.underlying.cur = buf.underlying.base;
while (sz > EV_WRITE_BUF_SZ)
{
ssize_t amount = conn->write(conn, buf.underlying.cur, EV_WRITE_BUF_SZ);
if (amount <= 0)
{
llarp::LogError("write underrun");
llarp_tcp_conn_close(conn);
return false;
}
buf.underlying.cur += amount;
sz -= amount;
}
return conn->write(conn, buf.underlying.cur, sz) > 0;
}
void
llarp_tcp_async_try_connect(struct llarp_ev_loop* loop, struct llarp_tcp_connecter* tcp)
{
tcp->loop = loop;
llarp::IpAddress address(tcp->remote);
if (not address.getPort())
throw std::runtime_error(llarp::stringify("Address with no port: ", address));
llarp::SockAddr addr = address.createSockAddr();
if (!loop->tcp_connect(tcp, addr))
{
llarp::LogError("async connect failed");
if (tcp->error)
tcp->error(tcp);
}
}
bool
llarp_tcp_serve(
struct llarp_ev_loop* loop, struct llarp_tcp_acceptor* tcp, const llarp::SockAddr& bindaddr)
{
tcp->loop = loop;
return loop->tcp_listen(tcp, bindaddr);
}
void
llarp_tcp_acceptor_close(struct llarp_tcp_acceptor* tcp)
{
tcp->close(tcp);
}
void
llarp_tcp_conn_close(struct llarp_tcp_conn* conn)
{
conn->close(conn);
}
namespace llarp
{
bool
tcp_conn::tick()
{
if (_shouldClose)
{
if (tcp.closed)
tcp.closed(&tcp);
::shutdown(fd, SHUT_RDWR);
return false;
}
if (tcp.tick)
tcp.tick(&tcp);
return true;
}
} // namespace llarp

View File

@ -4,7 +4,6 @@
#include <net/ip_address.hpp>
#include <util/buffer.hpp>
#include <util/time.hpp>
#include <tuntap.h>
#ifdef _WIN32
#include <winsock2.h>
@ -31,17 +30,13 @@
#define EV_TICK_INTERVAL 10
// forward declare
struct llarp_threadpool;
struct llarp_ev_loop;
namespace llarp
{
class Logic;
}
struct EventLoop;
} // namespace llarp
using llarp_ev_loop_ptr = std::shared_ptr<llarp_ev_loop>;
using llarp_ev_loop_ptr = std::shared_ptr<llarp::EventLoop>;
/// make an event loop using our baked in event loop on Windows
/// make an event loop using libuv otherwise.
@ -68,7 +63,7 @@ struct llarp_udp_io
int fd;
void* user;
void* impl;
struct llarp_ev_loop* parent;
llarp::EventLoop* parent;
/// called every event loop tick after reads
void (*tick)(struct llarp_udp_io*);
@ -80,7 +75,7 @@ struct llarp_udp_io
/// add UDP handler
int
llarp_ev_add_udp(struct llarp_ev_loop* ev, struct llarp_udp_io* udp, const llarp::SockAddr& src);
llarp_ev_add_udp(const llarp_ev_loop_ptr& ev, struct llarp_udp_io* udp, const llarp::SockAddr& src);
/// send a UDP packet
int
@ -90,139 +85,4 @@ llarp_ev_udp_sendto(struct llarp_udp_io* udp, const llarp::SockAddr& to, const l
int
llarp_ev_close_udp(struct llarp_udp_io* udp);
// forward declare
struct llarp_tcp_acceptor;
/// a single tcp connection
struct llarp_tcp_conn
{
/// user data
void* user;
/// private implementation
void* impl;
/// parent loop (dont set me)
struct llarp_ev_loop* loop;
/// handle read event
void (*read)(struct llarp_tcp_conn*, const llarp_buffer_t&);
//// set by parent
ssize_t (*write)(struct llarp_tcp_conn*, const byte_t*, size_t sz);
/// set by parent
bool (*is_open)(struct llarp_tcp_conn*);
/// handle close event (free-ing is handled by event loop)
void (*closed)(struct llarp_tcp_conn*);
/// explict close by user (set by parent)
void (*close)(struct llarp_tcp_conn*);
/// handle event loop tick
void (*tick)(struct llarp_tcp_conn*);
};
/// queue async write a buffer in full
/// return if we queued it or not
bool
llarp_tcp_conn_async_write(struct llarp_tcp_conn*, const llarp_buffer_t&);
/// close a tcp connection
void
llarp_tcp_conn_close(struct llarp_tcp_conn*);
/// handles outbound connections to 1 endpoint
struct llarp_tcp_connecter
{
/// remote address family
int af;
/// remote address string
llarp::IpAddress remote;
/// userdata pointer
void* user;
/// private implementation (dont set me)
void* impl;
/// parent event loop (dont set me)
struct llarp_ev_loop* loop;
/// handle outbound connection made
void (*connected)(struct llarp_tcp_connecter*, struct llarp_tcp_conn*);
/// handle outbound connection error
void (*error)(struct llarp_tcp_connecter*);
};
/// async try connecting to a remote connection 1 time
void
llarp_tcp_async_try_connect(struct llarp_ev_loop* l, struct llarp_tcp_connecter* tcp);
/// handles inbound connections
struct llarp_tcp_acceptor
{
/// userdata pointer
void* user;
/// internal implementation
void* impl;
/// parent event loop (dont set me)
struct llarp_ev_loop* loop;
/// handle event loop tick
void (*tick)(struct llarp_tcp_acceptor*);
/// handle inbound connection
void (*accepted)(struct llarp_tcp_acceptor*, struct llarp_tcp_conn*);
/// handle after server socket closed (free-ing is handled by event loop)
void (*closed)(struct llarp_tcp_acceptor*);
/// set by impl
void (*close)(struct llarp_tcp_acceptor*);
};
/// bind to an address and start serving async
/// return false if failed to bind
/// return true on success
bool
llarp_tcp_serve(
struct llarp_ev_loop* loop, struct llarp_tcp_acceptor* t, const llarp::SockAddr& bindaddr);
/// close and stop accepting connections
void
llarp_tcp_acceptor_close(struct llarp_tcp_acceptor*);
#ifdef _WIN32
#define IFNAMSIZ (16)
#endif
struct llarp_fd_promise;
/// wait until the fd promise is set
int
llarp_fd_promise_wait_for_value(struct llarp_fd_promise* promise);
struct llarp_tun_io
{
// TODO: more info?
char ifaddr[128];
// windows only
uint32_t dnsaddr;
int netmask;
char ifname[IFNAMSIZ + 1];
void* user;
void* impl;
/// functor for getting a promise that returns the vpn fd
/// dont set me if you don't know how to use this
struct llarp_fd_promise* (*get_fd_promise)(struct llarp_tun_io*);
struct llarp_ev_loop* parent;
/// called when we are able to write right before we write
/// this happens after reading packets
void (*before_write)(struct llarp_tun_io*);
/// called every event loop tick after reads
void (*tick)(struct llarp_tun_io*);
void (*recvpkt)(struct llarp_tun_io*, const llarp_buffer_t&);
/// set by parent
bool (*writepkt)(struct llarp_tun_io*, const byte_t*, size_t);
};
/// create tun interface with network interface name ifname
/// returns true on success otherwise returns false
bool
llarp_ev_add_tun(struct llarp_ev_loop* ev, struct llarp_tun_io* tun);
/// async write a packet on tun interface
/// returns true if queued, returns false on drop
bool
llarp_ev_tun_async_write(struct llarp_tun_io* tun, const llarp_buffer_t&);
#endif

View File

@ -2,6 +2,7 @@
#define LLARP_EV_HPP
#include <net/ip_address.hpp>
#include <net/ip_packet.hpp>
#include <ev/ev.h>
#include <util/buffer.hpp>
#include <util/codel.hpp>
@ -51,759 +52,81 @@ struct llarp_ev_pkt_pipe;
#define EV_WRITE_BUF_SZ (4 * 1024UL)
#endif
/// do io and reset errno after
static ssize_t
IO(std::function<ssize_t(void)> iofunc)
{
ssize_t ret = iofunc();
#ifndef _WIN32
errno = 0;
#else
WSASetLastError(0);
#endif
return ret;
}
namespace llarp
{
#ifdef _WIN32
struct win32_ev_io
namespace vpn
{
struct WriteBuffer
{
llarp_time_t timestamp = 0s;
size_t bufsz;
byte_t buf[EV_WRITE_BUF_SZ] = {0};
class NetworkInterface;
}
WriteBuffer() = default;
// this (nearly!) abstract base class
// is overriden for each platform
struct EventLoop
{
byte_t readbuf[EV_READ_BUF_SZ] = {0};
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
{
llarp_ev_loop_ptr loop;
GetNow(llarp_ev_loop_ptr l) : loop(l)
{}
llarp_time_t
operator()() const
{
return llarp_ev_loop_time_now_ms(loop);
}
};
struct PutTime
{
llarp_ev_loop_ptr loop;
PutTime(llarp_ev_loop_ptr 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;
}
};
};
using LosslessWriteQueue_t = std::deque<WriteBuffer>;
intptr_t fd; // Sockets only, fuck UNIX-style reactive IO with a rusty knife
int flags = 0;
win32_ev_io(intptr_t f) : fd(f){};
/// for tcp
win32_ev_io(intptr_t f, LosslessWriteQueue_t* q) : fd(f), m_BlockingWriteQueue(q)
{}
virtual void
error()
{
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL, ebuf, 1024, nullptr);
llarp::LogError(ebuf);
}
virtual int
read(byte_t* buf, size_t sz) = 0;
virtual int
sendto(const SockAddr& dst, const void* data, size_t sz)
{
UNREFERENCED_PARAMETER(dst);
UNREFERENCED_PARAMETER(data);
UNREFERENCED_PARAMETER(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* data, size_t sz)
{
return send(fd, (char*)data, sz, 0);
}
bool
queue_write(const byte_t* buf, size_t sz)
{
if (m_BlockingWriteQueue)
{
m_BlockingWriteQueue->emplace_back(buf, sz);
return true;
}
else
return false;
}
virtual void
flush_write()
{
flush_write_buffers(0);
}
/// 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_buffers(size_t amount)
{
if (m_BlockingWriteQueue)
{
if (amount)
{
while (amount && m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, std::min(amount, 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();
amount -= result;
}
}
else
{
// 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();
int wsaerr = WSAGetLastError();
if (wsaerr == WSA_IO_PENDING || wsaerr == WSAEWOULDBLOCK)
{
WSASetLastError(0);
return;
}
}
}
}
/// reset errno
WSASetLastError(0);
}
std::unique_ptr<LosslessWriteQueue_t> m_BlockingWriteQueue;
virtual ~win32_ev_io()
{
closesocket(fd);
};
};
#else
struct posix_ev_io
{
struct WriteBuffer
{
llarp_time_t timestamp = 0s;
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& writebuf) const
{
return writebuf.timestamp;
}
};
struct GetNow
{
llarp_ev_loop_ptr loop;
GetNow(llarp_ev_loop_ptr l) : loop(std::move(l))
{}
llarp_time_t
operator()() const
{
return llarp_ev_loop_time_now_ms(loop);
}
};
struct PutTime
{
llarp_ev_loop_ptr loop;
PutTime(llarp_ev_loop_ptr l) : loop(std::move(l))
{}
void
operator()(WriteBuffer& writebuf)
{
writebuf.timestamp = llarp_ev_loop_time_now_ms(loop);
}
};
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>;
using LosslessWriteQueue_t = std::deque<WriteBuffer>;
int fd;
int flags = 0;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || (__APPLE__ && __MACH__)
struct kevent change;
#endif
posix_ev_io(int f) : fd(f)
{}
/// for tun
posix_ev_io(int f, LossyWriteQueue_t* q) : fd(f), m_LossyWriteQueue(q)
{}
/// for tcp
posix_ev_io(int f, LosslessWriteQueue_t* q) : fd(f), m_BlockingWriteQueue(q)
{}
virtual void
error()
{
llarp::LogError(strerror(errno));
}
init() = 0;
virtual int
read(byte_t* buf, size_t sz) = 0;
run() = 0;
virtual int
sendto(
__attribute__((unused)) const SockAddr& dst,
__attribute__((unused)) const void* data,
__attribute__((unused)) 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* data, size_t sz)
{
return write(fd, data, sz);
}
bool
queue_write(const byte_t* buf, size_t sz)
{
if (m_LossyWriteQueue)
{
m_LossyWriteQueue->Emplace(buf, sz);
return true;
}
if (m_BlockingWriteQueue)
{
m_BlockingWriteQueue->emplace_back(buf, sz);
return true;
}
return false;
}
running() const = 0;
virtual void
flush_write()
{
flush_write_buffers(0);
}
virtual void
before_flush_write()
update_time()
{}
/// called in event loop when fd is ready for writing
/// requeues anything not written
/// this assumes fd is set to non blocking
virtual llarp_time_t
time_now() const
{
return llarp::time_now_ms();
}
virtual void
flush_write_buffers(size_t amount)
{
before_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)
{
if (amount)
{
while (amount && m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, std::min(amount, itr.bufsz));
if (result <= 0)
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();
amount -= result;
}
}
else
{
// write buffers
while (m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, itr.bufsz);
if (result <= 0)
{
errno = 0;
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;
}
}
}
}
/// reset errno
errno = 0;
}
stopped(){};
std::unique_ptr<LossyWriteQueue_t> m_LossyWriteQueue;
std::unique_ptr<LosslessWriteQueue_t> m_BlockingWriteQueue;
virtual uint32_t
call_after_delay(llarp_time_t delay_ms, std::function<void(void)> callback) = 0;
virtual ~posix_ev_io()
{
close(fd);
}
virtual void
cancel_delayed_call(uint32_t call_id) = 0;
virtual bool
add_network_interface(
std::shared_ptr<vpn::NetworkInterface> netif,
std::function<void(net::IPPacket)> packetHandler) = 0;