mirror of
https://github.com/oxen-io/lokinet
synced 2023-12-14 06:53:00 +01:00
Merge a2889174e1
into e11f5018c2
This commit is contained in:
commit
775c471efd
|
@ -315,6 +315,34 @@ local mac_builder(name,
|
|||
],
|
||||
};
|
||||
|
||||
// iphone builder
|
||||
local iphone_builder(name,
|
||||
build_type='Release',
|
||||
werror=true,
|
||||
cmake_extra='',
|
||||
local_mirror=true,
|
||||
extra_cmds=[],
|
||||
jobs=6,
|
||||
allow_fail=false) = {
|
||||
kind: 'pipeline',
|
||||
type: 'exec',
|
||||
name: name,
|
||||
platform: { os: 'darwin', arch: 'amd64' },
|
||||
steps: [
|
||||
{ name: 'submodules', commands: submodule_commands },
|
||||
{
|
||||
name: 'build',
|
||||
environment: { SSH_KEY: { from_secret: 'SSH_KEY' } },
|
||||
commands: [
|
||||
'echo "Building on ${DRONE_STAGE_MACHINE}"',
|
||||
'export CMAKE_BUILD_PARALLEL_LEVEL=6',
|
||||
'ulimit -n 1024', // because macos sets ulimit to 256 for some reason yeah idk
|
||||
'./contrib/ios.sh ' + ci_dep_mirror(local_mirror),
|
||||
] + extra_cmds,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = {
|
||||
kind: 'pipeline',
|
||||
type: 'docker',
|
||||
|
@ -438,6 +466,11 @@ local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = {
|
|||
deb_builder(docker_base + 'ubuntu-jammy-builder', 'jammy', 'ubuntu/jammy'),
|
||||
deb_builder(docker_base + 'debian-sid-builder', 'sid', 'debian/sid', arch='arm64'),
|
||||
|
||||
// iphone builds:
|
||||
iphone_builder('iOS (embedded lokinet)', build_type='Debug', extra_cmds=[
|
||||
'UPLOAD_OS=iphone ./contrib/ci/drone-static-upload.sh',
|
||||
]),
|
||||
|
||||
// Macos builds:
|
||||
mac_builder('macOS (Release)', extra_cmds=[
|
||||
'./contrib/ci/drone-check-static-libs.sh',
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,6 +4,7 @@
|
|||
*.a
|
||||
*.o
|
||||
*.so
|
||||
*.DS_Store
|
||||
|
||||
/build*/
|
||||
**/__pycache__/**
|
||||
|
|
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -39,3 +39,9 @@
|
|||
[submodule "external/CLI11"]
|
||||
path = external/CLI11
|
||||
url = https://github.com/CLIUtils/CLI11.git
|
||||
[submodule "external/ios-cmake"]
|
||||
path = external/ios-cmake
|
||||
url = https://github.com/leetal/ios-cmake.git
|
||||
[submodule "external/libuv"]
|
||||
path = external/libuv
|
||||
url = https://github.com/libuv/libuv.git
|
||||
|
|
|
@ -50,6 +50,7 @@ option(USE_AVX2 "enable avx2 code" OFF)
|
|||
option(USE_NETNS "enable networking namespace support. Linux only" OFF)
|
||||
option(NATIVE_BUILD "optimise for host system and FPU" ON)
|
||||
option(WITH_EMBEDDED_LOKINET "build liblokinet.so for embedded lokinet" OFF)
|
||||
option(LIBLOKINET_TEST_UTILS "build test utils in contrib/liblokinet" OFF)
|
||||
option(XSAN "use sanitiser, if your system has it (requires -DCMAKE_BUILD_TYPE=Debug)" OFF)
|
||||
option(USE_JEMALLOC "Link to jemalloc for memory allocations, if found" ON)
|
||||
option(TESTNET "testnet build" OFF)
|
||||
|
@ -75,6 +76,11 @@ option(STATIC_LINK "link statically against dependencies" ${BUILD_STATIC_DEPS})
|
|||
if(BUILD_STATIC_DEPS AND NOT STATIC_LINK)
|
||||
message(FATAL_ERROR "Option BUILD_STATIC_DEPS requires STATIC_LINK to be enabled as well")
|
||||
endif()
|
||||
|
||||
if (BUILD_STATIC_DEPS OR WITH_EMBEDDED_LOKINET)
|
||||
include(cmake/combine_archives.cmake)
|
||||
endif()
|
||||
|
||||
if(BUILD_STATIC_DEPS)
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
|
||||
include(StaticBuild)
|
||||
|
@ -119,7 +125,11 @@ include(cmake/gui-option.cmake)
|
|||
|
||||
include(cmake/solaris.cmake)
|
||||
include(cmake/win32.cmake)
|
||||
include(cmake/macos.cmake)
|
||||
|
||||
option(APPLE_IOS "Set if building for iOS" OFF)
|
||||
if (APPLE AND (NOT APPLE_IOS))
|
||||
include(cmake/macos.cmake)
|
||||
endif()
|
||||
|
||||
# No in-source building
|
||||
include(MacroEnsureOutOfSourceBuild)
|
||||
|
@ -213,20 +223,28 @@ if (WOW64_CROSS_COMPILE OR WIN64_CROSS_COMPILE)
|
|||
include(cmake/cross_compile.cmake)
|
||||
endif()
|
||||
|
||||
if(NOT APPLE)
|
||||
if(NATIVE_BUILD)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le)
|
||||
add_compile_options(-mcpu=native -mtune=native)
|
||||
else()
|
||||
add_compile_options(-march=native -mtune=native)
|
||||
endif()
|
||||
elseif(NOT NON_PC_TARGET)
|
||||
if (USE_AVX2)
|
||||
add_compile_options(-march=haswell -mtune=haswell -mfpmath=sse)
|
||||
else()
|
||||
# Public binary releases
|
||||
add_compile_options(-march=nocona -mtune=haswell -mfpmath=sse)
|
||||
endif()
|
||||
if(APPLE)
|
||||
if(IOS AND ARCH STREQUAL "arm64")
|
||||
message(STATUS "IOS: Changing arch from arm64 to armv8")
|
||||
add_compile_options(-march=armv8)
|
||||
elseif(IOS AND ARCH STREQUAL "x86_64")
|
||||
message(STATUS "IOS: Changing arch from x86_64 to x86-64")
|
||||
add_compile_options(-march=x86-64)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NATIVE_BUILD)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le)
|
||||
add_compile_options(-mcpu=native -mtune=native)
|
||||
else()
|
||||
add_compile_options(-march=native -mtune=native)
|
||||
endif()
|
||||
elseif(NOT NON_PC_TARGET)
|
||||
if (USE_AVX2)
|
||||
add_compile_options(-march=haswell -mtune=haswell -mfpmath=sse)
|
||||
else()
|
||||
# Public binary releases
|
||||
add_compile_options(-march=nocona -mtune=haswell -mfpmath=sse)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -313,11 +331,15 @@ if(ANDROID)
|
|||
add_subdirectory(jni)
|
||||
endif()
|
||||
|
||||
if(WITH_EMBEDDED_LOKINET AND LIBLOKINET_TEST_UTILS)
|
||||
add_subdirectory(contrib/liblokinet)
|
||||
endif()
|
||||
|
||||
add_subdirectory(docs)
|
||||
|
||||
include(cmake/gui.cmake)
|
||||
|
||||
if(APPLE)
|
||||
if(APPLE AND (NOT APPLE_IOS))
|
||||
macos_target_setup()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -48,13 +48,6 @@ set(ZMQ_SOURCE zeromq-${ZMQ_VERSION}.tar.gz)
|
|||
set(ZMQ_HASH SHA512=e198ef9f82d392754caadd547537666d4fba0afd7d027749b3adae450516bcf284d241d4616cad3cb4ad9af8c10373d456de92dc6d115b037941659f141e7c0e
|
||||
CACHE STRING "libzmq source hash")
|
||||
|
||||
set(LIBUV_VERSION 1.44.2 CACHE STRING "libuv version")
|
||||
set(LIBUV_MIRROR ${LOCAL_MIRROR} https://dist.libuv.org/dist/v${LIBUV_VERSION}
|
||||
CACHE STRING "libuv mirror(s)")
|
||||
set(LIBUV_SOURCE libuv-v${LIBUV_VERSION}.tar.gz)
|
||||
set(LIBUV_HASH SHA512=91197ff9303112567bbb915bbb88058050e2ad1c048815a3b57c054635d5dc7df458b956089d785475290132236cb0edcfae830f5d749de29a9a3213eeaf0b20
|
||||
CACHE STRING "libuv source hash")
|
||||
|
||||
set(ZLIB_VERSION 1.2.13 CACHE STRING "zlib version")
|
||||
set(ZLIB_MIRROR ${LOCAL_MIRROR} https://zlib.net
|
||||
CACHE STRING "zlib mirror(s)")
|
||||
|
@ -109,9 +102,18 @@ endfunction()
|
|||
set(cross_host "")
|
||||
set(cross_rc "")
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(cross_host "--host=${ARCH_TRIPLET}")
|
||||
if (ARCH_TRIPLET MATCHES mingw AND CMAKE_RC_COMPILER)
|
||||
set(cross_rc "WINDRES=${CMAKE_RC_COMPILER}")
|
||||
if(APPLE_TARGET_TRIPLE)
|
||||
if(PLATFORM MATCHES "OS64" OR PLATFORM MATCHES "SIMULATORARM64")
|
||||
set(APPLE_TARGET_TRIPLE aarch64-apple-ios)
|
||||
elseif(PLATFORM MATCHES "SIMULATOR64")
|
||||
set(APPLE_TARGET_TRIPLE x86_64-apple-ios)
|
||||
endif()
|
||||
set(cross_host "--host=${APPLE_TARGET_TRIPLE}")
|
||||
else()
|
||||
set(cross_host "--host=${ARCH_TRIPLET}")
|
||||
if (ARCH_TRIPLET MATCHES mingw AND CMAKE_RC_COMPILER)
|
||||
set(cross_rc "WINDRES=${CMAKE_RC_COMPILER}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if(ANDROID)
|
||||
|
@ -162,11 +164,6 @@ if(WITH_LTO)
|
|||
set(deps_CFLAGS "${deps_CFLAGS} -flto")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(deps_CFLAGS "${deps_CFLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
set(deps_CXXFLAGS "${deps_CXXFLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
endif()
|
||||
|
||||
if(_winver)
|
||||
set(deps_CFLAGS "${deps_CFLAGS} -D_WIN32_WINNT=${_winver}")
|
||||
set(deps_CXXFLAGS "${deps_CXXFLAGS} -D_WIN32_WINNT=${_winver}")
|
||||
|
@ -179,6 +176,15 @@ else()
|
|||
set(_make make)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
foreach(lang C CXX)
|
||||
string(APPEND deps_${lang}FLAGS " ${CMAKE_${lang}_SYSROOT_FLAG} ${CMAKE_OSX_SYSROOT} ${CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
set(deps_noarch_${lang}FLAGS "${deps_${lang}FLAGS}")
|
||||
foreach(arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
string(APPEND deps_${lang}FLAGS " -arch ${arch}")
|
||||
endforeach()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Builds a target; takes the target name (e.g. "readline") and builds it in an external project with
|
||||
# target name suffixed with `_external`. Its upper-case value is used to get the download details
|
||||
|
@ -219,15 +225,6 @@ function(build_external target)
|
|||
)
|
||||
endfunction()
|
||||
|
||||
build_external(libuv
|
||||
CONFIGURE_COMMAND ./autogen.sh && ./configure ${cross_host} ${cross_rc} --prefix=${DEPS_DESTDIR} --with-pic --disable-shared --enable-static "CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}"
|
||||
BUILD_BYPRODUCTS
|
||||
${DEPS_DESTDIR}/lib/libuv.a
|
||||
${DEPS_DESTDIR}/include/uv.h
|
||||
)
|
||||
add_static_target(libuv libuv_external libuv.a)
|
||||
target_link_libraries(libuv INTERFACE ${CMAKE_DL_LIBS})
|
||||
|
||||
|
||||
build_external(zlib
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env "CC=${deps_cc}" "CFLAGS=${deps_CFLAGS} -fPIC" ${cross_extra} ./configure --prefix=${DEPS_DESTDIR} --static
|
||||
|
@ -242,7 +239,7 @@ set(openssl_system_env "")
|
|||
set(openssl_arch "")
|
||||
set(openssl_configure_command ./config)
|
||||
set(openssl_flags "CFLAGS=${deps_CFLAGS}")
|
||||
set(unbound_ldflags "")
|
||||
set(openssl_cc "${deps_cc}")
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
if(ARCH_TRIPLET STREQUAL x86_64-w64-mingw32)
|
||||
set(openssl_arch mingw64)
|
||||
|
@ -255,6 +252,15 @@ if(CMAKE_CROSSCOMPILING)
|
|||
set(openssl_system_env LD=${deps_ld} RANLIB=${deps_ranlib} AR=${deps_ar} ANDROID_NDK_ROOT=${CMAKE_ANDROID_NDK} "PATH=${CMAKE_ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/bin:$ENV{PATH}")
|
||||
list(APPEND openssl_flags "CPPFLAGS=-D__ANDROID_API__=${ANDROID_API}")
|
||||
set(openssl_extra_opts no-asm)
|
||||
elseif(IOS)
|
||||
get_filename_component(apple_toolchain "${CMAKE_C_COMPILER}" DIRECTORY)
|
||||
get_filename_component(apple_sdk "${CMAKE_OSX_SYSROOT}" NAME)
|
||||
if(NOT ${apple_toolchain} MATCHES Xcode OR NOT ${apple_sdk} MATCHES "iPhone(OS|Simulator)")
|
||||
message(FATAL_ERROR "didn't find your toolchain and sdk correctly from ${CMAKE_C_COMPILER}/${CMAKE_OSX_SYSROOT}: found toolchain=${apple_toolchain}, sdk=${apple_sdk}")
|
||||
endif()
|
||||
set(openssl_system_env CROSS_COMPILE=${apple_toolchain}/ CROSS_TOP=${CMAKE_DEVELOPER_ROOT}/ CROSS_SDK=${apple_sdk}/)
|
||||
set(openssl_configure_command ./Configure iphoneos-cross)
|
||||
set(openssl_cc "clang")
|
||||
elseif(ARCH_TRIPLET STREQUAL mips64-linux-gnuabi64)
|
||||
set(openssl_arch linux-mips64)
|
||||
elseif(ARCH_TRIPLET STREQUAL mips-linux-gnu)
|
||||
|
@ -281,7 +287,7 @@ endif()
|
|||
|
||||
|
||||
build_external(openssl
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env CC=${deps_cc} ${openssl_system_env} ${openssl_configure_command}
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env CC=${openssl_cc} ${openssl_system_env} ${openssl_configure_command}
|
||||
--prefix=${DEPS_DESTDIR} --libdir=lib ${openssl_extra_opts}
|
||||
no-shared no-capieng no-dso no-dtls1 no-ec_nistp_64_gcc_128 no-gost
|
||||
no-md2 no-rc5 no-rdrand no-rfc3779 no-sctp no-ssl-trace no-ssl3
|
||||
|
@ -311,6 +317,12 @@ build_external(expat
|
|||
add_static_target(expat expat_external libexpat.a)
|
||||
|
||||
|
||||
set(unbound_extra)
|
||||
if(APPLE AND IOS)
|
||||
set(unbound_extra CPP=cpp)
|
||||
endif()
|
||||
|
||||
|
||||
if(WIN32)
|
||||
set(unbound_patch
|
||||
PATCH_COMMAND ${PROJECT_SOURCE_DIR}/contrib/apply-patches.sh
|
||||
|
@ -320,10 +332,10 @@ build_external(unbound
|
|||
DEPENDS openssl_external expat_external
|
||||
${unbound_patch}
|
||||
CONFIGURE_COMMAND ./configure ${cross_host} ${cross_rc} --prefix=${DEPS_DESTDIR} --disable-shared
|
||||
--enable-static --with-libunbound-only --with-pic
|
||||
--enable-static --with-libunbound-only --with-pic --disable-gost
|
||||
--$<IF:$<BOOL:${WITH_LTO}>,enable,disable>-flto --with-ssl=${DEPS_DESTDIR}
|
||||
--with-libexpat=${DEPS_DESTDIR}
|
||||
"CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}" "LDFLAGS=${unbound_ldflags}"
|
||||
"CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}" ${unbound_extra}
|
||||
)
|
||||
add_static_target(libunbound unbound_external libunbound.a)
|
||||
if(NOT WIN32)
|
||||
|
@ -340,7 +352,9 @@ add_static_target(sodium sodium_external libsodium.a)
|
|||
|
||||
|
||||
if(WITH_PEERSTATS_BACKEND)
|
||||
build_external(sqlite3)
|
||||
build_external(sqlite3 CONFIGURE_COMMAND ./configure ${cross_host} ${cross_rc} --prefix=${DEPS_DESTDIR} --enable-static --disable-shared --disable-readline --with-pic "CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}"
|
||||
BUILD_COMMAND true
|
||||
INSTALL_COMMAND make install-includeHEADERS install-libLTLIBRARIES)
|
||||
add_static_target(sqlite3 sqlite3_external libsqlite3.a)
|
||||
endif()
|
||||
|
||||
|
@ -359,10 +373,16 @@ if(CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
|
|||
${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-unistd.patch)
|
||||
endif()
|
||||
|
||||
set(zmq_cross_host "${cross_host}")
|
||||
if(IOS AND cross_host MATCHES "-ios$")
|
||||
# zmq doesn't like "-ios" for the host, so replace it with -darwin
|
||||
string(REGEX REPLACE "-ios$" "-darwin" zmq_cross_host ${cross_host})
|
||||
endif()
|
||||
|
||||
build_external(zmq
|
||||
DEPENDS sodium_external
|
||||
${zmq_patch}
|
||||
CONFIGURE_COMMAND ./configure ${cross_host} --prefix=${DEPS_DESTDIR} --enable-static --disable-shared
|
||||
CONFIGURE_COMMAND ./configure ${zmq_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 --disable-libbsd ${zmq_extra}
|
||||
"CC=${deps_cc}" "CXX=${deps_cxx}" "CFLAGS=${deps_CFLAGS} -fstack-protector" "CXXFLAGS=${deps_CXXFLAGS} -fstack-protector"
|
||||
|
|
30
cmake/combine_archives.cmake
Normal file
30
cmake/combine_archives.cmake
Normal file
|
@ -0,0 +1,30 @@
|
|||
function(combine_archives output_archive)
|
||||
set(FULL_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib${output_archive}.a)
|
||||
set(output_archive_dummy_file ${CMAKE_CURRENT_BINARY_DIR}/${output_archive}.dummy.cpp)
|
||||
add_custom_command(OUTPUT ${output_archive_dummy_file}
|
||||
COMMAND touch ${output_archive_dummy_file}
|
||||
DEPENDS ${ARGN})
|
||||
add_library(${output_archive} STATIC EXCLUDE_FROM_ALL ${output_archive_dummy_file})
|
||||
|
||||
if(NOT APPLE)
|
||||
set(mri_file ${CMAKE_CURRENT_BINARY_DIR}/${output_archive}.mri)
|
||||
set(mri_content "create ${FULL_OUTPUT_PATH}\n")
|
||||
foreach(in_archive ${ARGN})
|
||||
string(APPEND mri_content "addlib $<TARGET_FILE:${in_archive}>\n")
|
||||
endforeach()
|
||||
string(APPEND mri_content "save\nend\n")
|
||||
file(GENERATE OUTPUT ${mri_file} CONTENT "${mri_content}")
|
||||
|
||||
add_custom_command(TARGET ${output_archive}
|
||||
POST_BUILD
|
||||
COMMAND ar -M < ${mri_file})
|
||||
else()
|
||||
set(merge_libs)
|
||||
foreach(in_archive ${ARGN})
|
||||
list(APPEND merge_libs $<TARGET_FILE:${in_archive}>)
|
||||
endforeach()
|
||||
add_custom_command(TARGET ${output_archive}
|
||||
POST_BUILD
|
||||
COMMAND /usr/bin/libtool -static -o ${FULL_OUTPUT_PATH} ${merge_libs})
|
||||
endif()
|
||||
endfunction(combine_archives)
|
|
@ -1,8 +1,3 @@
|
|||
if(NOT APPLE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
option(MACOS_SYSTEM_EXTENSION
|
||||
"Build the network extension as a system extension rather than a plugin. This must be ON for non-app store release builds, and must be OFF for dev builds and Mac App Store distribution builds"
|
||||
OFF)
|
||||
|
|
|
@ -60,6 +60,9 @@ elif [ -e build-mac ]; then
|
|||
archive="$base.tar.xz"
|
||||
mv build-mac/Lokinet*/ "$base"
|
||||
tar cJvf "$archive" "$base"
|
||||
elif [ -e build/iphone/ ]; then
|
||||
archive="$base.tar.xz"
|
||||
mv build/iphone/*.tar.xz "$archive"
|
||||
else
|
||||
cp -av build/daemon/lokinet{,-vpn} "$base"
|
||||
cp -av contrib/bootstrap/mainnet.signed "$base/bootstrap.signed"
|
||||
|
|
|
@ -45,7 +45,7 @@ for arch in $archs ; do
|
|||
-DSTATIC_LINK=ON \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DBUILD_LIBLOKINET=OFF \
|
||||
-DWITH_EMBEDDED_LOKINET=OFF \
|
||||
-DWITH_TESTS=OFF \
|
||||
-DNATIVE_BUILD=OFF \
|
||||
-DSTATIC_LINK=ON \
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
CLANG_FORMAT_DESIRED_VERSION=14
|
||||
|
||||
CLANG_FORMAT=$(command -v clang-format-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null)
|
||||
|
|
85
contrib/ios.sh
Executable file
85
contrib/ios.sh
Executable file
|
@ -0,0 +1,85 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Builds embeded lokinet for iphone
|
||||
|
||||
set -e
|
||||
set -x
|
||||
if ! [ -f LICENSE ] || ! [ -d llarp ]; then
|
||||
echo "You need to run this as ./contrib/ios.sh from the top-level lokinet project directory"
|
||||
fi
|
||||
|
||||
|
||||
root="$(readlink -f $(dirname $0)/../)"
|
||||
|
||||
build_dir="$root/build/iphone"
|
||||
|
||||
deviceArchs=(arm64)
|
||||
devicePlat=(OS64)
|
||||
simArchs=(arm64 x86_64)
|
||||
simPlat=(SIMULATORARM64 SIMULATOR64)
|
||||
|
||||
for i in "${!deviceArchs[@]}"; do
|
||||
./contrib/ios/ios-configure.sh "$build_dir/device/${deviceArchs[i]}" ${devicePlat[i]} $@
|
||||
done
|
||||
|
||||
for i in "${!simArchs[@]}"; do
|
||||
./contrib/ios/ios-configure.sh "$build_dir/sim/${simArchs[i]}" ${simPlat[i]} $@
|
||||
done
|
||||
|
||||
for targ in ${deviceArchs[@]} ; do
|
||||
./contrib/ios/ios-build.sh "$build_dir/device/$targ"
|
||||
done
|
||||
|
||||
for targ in ${simArchs[@]} ; do
|
||||
./contrib/ios/ios-build.sh "$build_dir/sim/$targ"
|
||||
done
|
||||
|
||||
pkg_name="iphone_lokinet_embedded_$(date +%s)"
|
||||
pkg_dir="$build_dir/$pkg_name"
|
||||
|
||||
# Combine and device/simulator libraries into a single file so XCode doesn't complain
|
||||
function combineArchsIfNeeded() {
|
||||
local group=$1
|
||||
local destination=$2
|
||||
shift; shift
|
||||
local archs=("$@")
|
||||
|
||||
if [ ${#archs[@]} -gt 1 ]; then
|
||||
local dirs=("${archs[@]/#/$build_dir/${group}/}")
|
||||
local libs=("${dirs[@]/%//llarp/liblokinet-embedded.a}")
|
||||
|
||||
mkdir -p "$build_dir/$group/$destination/llarp"
|
||||
lipo -create "${libs[@]}" -output "$build_dir/$group/${destination}/llarp/liblokinet-embedded.a"
|
||||
fi
|
||||
}
|
||||
|
||||
deviceArchsString="${deviceArchs[*]}"
|
||||
joinedDeviceArchs="${deviceArchsString// /_}"
|
||||
simArchsString="${simArchs[*]}"
|
||||
joinedSimArchs="${simArchsString// /_}"
|
||||
|
||||
combineArchsIfNeeded "device" $joinedDeviceArchs ${deviceArchs[*]}
|
||||
combineArchsIfNeeded "sim" $joinedSimArchs ${simArchs[*]}
|
||||
|
||||
# Create a '.xcframework' so XCode can deal with the different architectures
|
||||
xcodebuild -create-xcframework \
|
||||
-library "$build_dir/device/$joinedDeviceArchs/llarp/liblokinet-embedded.a" \
|
||||
-library "$build_dir/sim/$joinedSimArchs/llarp/liblokinet-embedded.a" \
|
||||
-output "$pkg_dir/libLokinet.xcframework"
|
||||
|
||||
# Copy the headers over
|
||||
mkdir -p "$pkg_dir/libLokinet.xcframework/lokinet"
|
||||
cp -a "$root"/include/lokinet{,/*}.h "$pkg_dir/libLokinet.xcframework/lokinet"
|
||||
mv "$pkg_dir/libLokinet.xcframework/lokinet/lokinet.h" "$pkg_dir/libLokinet.xcframework/lokinet.h"
|
||||
|
||||
# The 'module.modulemap' is needed for XCode to be able to find the headers
|
||||
echo -e 'module Lokinet {' > "$pkg_dir/libLokinet.xcframework/module.modulemap"
|
||||
echo -e ' umbrella header "lokinet.h"' >> "$pkg_dir/libLokinet.xcframework/module.modulemap"
|
||||
echo -e ' export *' >> "$pkg_dir/libLokinet.xcframework/module.modulemap"
|
||||
echo -e '}' >> "$pkg_dir/libLokinet.xcframework/module.modulemap"
|
||||
|
||||
# Archive the result
|
||||
cd "$build_dir"
|
||||
tar cfv "$pkg_name.tar" $pkg_name
|
||||
cd -
|
||||
xz -T 0 "$build_dir/$pkg_name.tar"
|
7
contrib/ios/ios-build.sh
Executable file
7
contrib/ios/ios-build.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Build the shit for iphone
|
||||
|
||||
test -e $1 || ( echo "run ios-configure.sh first" ; exit 1 )
|
||||
|
||||
cmake --build $1 --target lokinet-embedded
|
44
contrib/ios/ios-configure.sh
Executable file
44
contrib/ios/ios-configure.sh
Executable file
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# configure step for ios
|
||||
|
||||
set -x
|
||||
|
||||
root=$(readlink -f "$( dirname $0 )/../../")
|
||||
|
||||
unset SDKROOT
|
||||
export SDKROOT="$(xcrun --sdk iphoneos --show-sdk-path)"
|
||||
|
||||
targ=$1
|
||||
plat=$2
|
||||
shift
|
||||
shift
|
||||
|
||||
mkdir -p $targ
|
||||
|
||||
cmake \
|
||||
-G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$root/external/ios-cmake/ios.toolchain.cmake" -DPLATFORM=$plat -DDEPLOYMENT_TARGET=13 -DENABLE_VISIBILITY=ON -DENABLE_BITCODE=OFF \
|
||||
-DAPPLE_IOS=ON \
|
||||
-DWITH_PEERSTATS=OFF \
|
||||
-DBUILD_STATIC_DEPS=ON \
|
||||
-DBUILD_PACKAGE=OFF \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DWITH_EMBEDDED_LOKINET=ON \
|
||||
-DWITH_TESTS=OFF \
|
||||
-DNATIVE_BUILD=OFF \
|
||||
-DSTATIC_LINK=ON \
|
||||
-DWITH_SYSTEMD=OFF \
|
||||
-DWITH_BOOTSTRAP=ON \
|
||||
-DBUILD_DAEMON=OFF \
|
||||
-DFORCE_OXENMQ_SUBMODULE=ON \
|
||||
-DFORCE_OXENC_SUBMODULE=ON \
|
||||
-DFORCE_NLOHMANN_SUBMODULE=ON \
|
||||
-DFORCE_LIBUV_SUBMODULE=ON \
|
||||
-DSUBMODULE_CHECK=ON \
|
||||
-DWITH_LTO=OFF \
|
||||
-DCMAKE_CXX_FLAGS='-Oz' -DCMAKE_C_FLAGS='-Oz' \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-S "$root" -B $targ \
|
||||
$@
|
10
contrib/ios/readme.txt
Normal file
10
contrib/ios/readme.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
our scientists have yet to reverse engineer the correct way to use the apple build process as dictated on the official apple documentation so we have a made a hack to make it work until that occurs.
|
||||
the build process for embedded lokinet on iphone is as follows:
|
||||
|
||||
* obtain holy water, sprinkle onto keyboard and single button trackpad accordingly.
|
||||
* run ./contrib/ios.sh
|
||||
* after it runs and the proper number of goats have been offered to the slaughter you will get an xz's tarball in the build/iphone/ directory
|
||||
|
||||
additional cmake flags can be passed to ./contrib/ios.sh as command line arguments like so:
|
||||
|
||||
$ ./contrib/ios.sh -DYOLO_SWAG=ON
|
|
@ -1,10 +1,14 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
#[[
|
||||
project(udptest LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
add_executable(udptest udptest.cpp)
|
||||
include_directories(../../include)
|
||||
target_link_libraries(udptest PUBLIC lokinet)
|
||||
]]
|
||||
|
||||
add_executable(tcp_listen
|
||||
tcp_listen.cpp)
|
||||
target_link_libraries(tcp_listen PUBLIC lokinet-embedded-api)
|
||||
|
||||
add_executable(tcp_connect
|
||||
tcp_connect.cpp)
|
||||
target_link_libraries(tcp_connect PUBLIC lokinet-embedded-api)
|
||||
|
|
120
contrib/liblokinet/tcp_connect.cpp
Normal file
120
contrib/liblokinet/tcp_connect.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Test utility to bind a local tcp socket listener with liblokinet
|
||||
|
||||
#include <lokinet.h>
|
||||
|
||||
#include <llarp/util/logging.hpp>
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
bool run{true};
|
||||
|
||||
void
|
||||
signal_handler(int)
|
||||
{
|
||||
run = false;
|
||||
int a;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 3 || argc > 4)
|
||||
{
|
||||
std::cerr << "Usage: " << argv[0] << " something.{loki,snode} port [testnet]\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string netid = "lokinet";
|
||||
std::string data_dir = "./tcp_connect_data_dir";
|
||||
|
||||
if (argc == 4) // if testnet
|
||||
{
|
||||
netid = "gamma"; // testnet netid
|
||||
data_dir += "/testnet";
|
||||
}
|
||||
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
||||
if (auto* loglevel = getenv("LOKINET_LOG"))
|
||||
lokinet_log_level(loglevel);
|
||||
else
|
||||
lokinet_log_level("info");
|
||||
|
||||
std::cerr << "starting up\n";
|
||||
|
||||
lokinet_set_netid(netid.c_str());
|
||||
auto shared_ctx = std::shared_ptr<lokinet_context>(lokinet_context_new(), lokinet_context_free);
|
||||
auto* ctx = shared_ctx.get();
|
||||
lokinet_set_data_dir(data_dir.c_str(), ctx);
|
||||
if (lokinet_context_start(ctx))
|
||||
throw std::runtime_error{"could not start context"};
|
||||
|
||||
int status;
|
||||
for (status = lokinet_status(ctx); run and status == -1; status = lokinet_status(ctx))
|
||||
{
|
||||
std::cerr << "waiting for lokinet to be ready..." << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{500});
|
||||
}
|
||||
if (not run)
|
||||
{
|
||||
std::cerr << "exit requested before context was ready.\n";
|
||||
return 0;
|
||||
}
|
||||
if (status != 0)
|
||||
{
|
||||
std::cerr << "lokinet_status = " << status << " after waiting for ready.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (auto* loglevel = getenv("QUIC_LOG"))
|
||||
llarp::log::set_level("quic", llarp::log::level_from_string(loglevel));
|
||||
else
|
||||
llarp::log::set_level("quic", llarp::log::Level::trace);
|
||||
|
||||
std::cerr << "\n\nquic log level: " << llarp::log::to_string(llarp::log::get_level("quic")) << "\n\n";
|
||||
|
||||
auto addr_c = lokinet_address(ctx);
|
||||
std::string addr{addr_c};
|
||||
free(addr_c);
|
||||
std::cerr << "lokinet address: " << addr << "\n";
|
||||
|
||||
lokinet_tcp_result stream_res;
|
||||
|
||||
std::string target{argv[1]};
|
||||
target = target + ":" + argv[2];
|
||||
|
||||
// hard-coded IP:port for liblokinet to bind to
|
||||
// connect via tcp will stream traffic to whatever
|
||||
lokinet_outbound_tcp(&stream_res, target.c_str(), "127.0.0.1:54321", ctx, nullptr, nullptr, nullptr);
|
||||
|
||||
if (stream_res.error)
|
||||
{
|
||||
std::cerr << "failed to prepare outbound tcp: " << strerror(stream_res.error) << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{100});
|
||||
} while (run);
|
||||
|
||||
std::cerr << "tcp_connect shutting down...\n";
|
||||
|
||||
lokinet_close_tcp(stream_res.tcp_id, ctx);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1000});
|
||||
return 0;
|
||||
}
|
||||
|
96
contrib/liblokinet/tcp_listen.cpp
Normal file
96
contrib/liblokinet/tcp_listen.cpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
// Test utility to bind a local tcp socket listener with liblokinet
|
||||
|
||||
#include <lokinet.h>
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
bool run{true};
|
||||
|
||||
void
|
||||
signal_handler(int)
|
||||
{
|
||||
run = false;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
||||
if (auto* loglevel = getenv("LOKINET_LOG"))
|
||||
lokinet_log_level(loglevel);
|
||||
else
|
||||
lokinet_log_level("info");
|
||||
|
||||
std::cout << "starting up\n";
|
||||
|
||||
auto shared_ctx = std::shared_ptr<lokinet_context>(lokinet_context_new(), lokinet_context_free);
|
||||
auto* ctx = shared_ctx.get();
|
||||
if (lokinet_context_start(ctx))
|
||||
throw std::runtime_error{"could not start context"};
|
||||
|
||||
int status;
|
||||
for (status = lokinet_status(ctx); run and status == -1; status = lokinet_status(ctx))
|
||||
{
|
||||
std::cout << "waiting for lokinet to be ready..." << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{500});
|
||||
}
|
||||
if (not run)
|
||||
{
|
||||
std::cout << "exit requested before context was ready.\n";
|
||||
return 0;
|
||||
}
|
||||
if (status != 0)
|
||||
{
|
||||
std::cout << "lokinet_status = " << status << " after waiting for ready.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// wait a bit just so log output calms down so we can see stuff
|
||||
// printed from here
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{3000});
|
||||
|
||||
const auto port = 10000;
|
||||
|
||||
auto id = lokinet_inbound_tcp(port, ctx);
|
||||
if (id < 0)
|
||||
{
|
||||
std::cout << "failed to bind tcp socket\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::cout << "bound tcp on localhost port: " << port << "\n";
|
||||
|
||||
auto addr_c = lokinet_address(ctx);
|
||||
std::string addr{addr_c};
|
||||
free(addr_c);
|
||||
|
||||
std::cout << "lokinet address: " << addr << "\n";
|
||||
|
||||
size_t counter = 0;
|
||||
do
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{100});
|
||||
if (++counter % 30 == 0)
|
||||
std::cout << "lokinet address: " << addr << "\n";
|
||||
} while (run);
|
||||
|
||||
std::cout << "tcp_listen shutting down...\n";
|
||||
|
||||
lokinet_close_tcp(id, ctx);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ signit() {
|
|||
codesign \
|
||||
--verbose=4 \
|
||||
--force \
|
||||
--deep \
|
||||
-s "@CODESIGN_ID@" \
|
||||
--entitlements "$entitlements" \
|
||||
--strict \
|
||||
|
|
|
@ -47,7 +47,7 @@ set(NTRU_AVX_SRC
|
|||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag(-mavx2 COMPILER_SUPPORTS_AVX2)
|
||||
check_cxx_compiler_flag(-mfma COMPILER_SUPPORTS_FMA)
|
||||
if(COMPILER_SUPPORTS_AVX2 AND COMPILER_SUPPORTS_FMA AND (NOT ANDROID))
|
||||
if(COMPILER_SUPPORTS_AVX2 AND COMPILER_SUPPORTS_FMA AND (NOT (ANDROID OR IOS)))
|
||||
target_sources(lokinet-cryptography PRIVATE ${NTRU_AVX_SRC})
|
||||
set_property(SOURCE ${NTRU_AVX_SRC} APPEND PROPERTY COMPILE_FLAGS "-mavx2 -mfma")
|
||||
message(STATUS "Building libntrup with runtime AVX2/FMA support")
|
||||
|
|
5
external/CMakeLists.txt
vendored
5
external/CMakeLists.txt
vendored
|
@ -31,6 +31,7 @@ if(SUBMODULE_CHECK)
|
|||
check_submodule(sqlite_orm)
|
||||
check_submodule(oxen-mq)
|
||||
check_submodule(oxen-encoding)
|
||||
check_submodule(libuv)
|
||||
check_submodule(uvw)
|
||||
check_submodule(cpr)
|
||||
check_submodule(ngtcp2)
|
||||
|
@ -67,6 +68,8 @@ set(JSON_BuildTests OFF CACHE INTERNAL "")
|
|||
set(JSON_Install OFF CACHE INTERNAL "")
|
||||
system_or_submodule(NLOHMANN nlohmann_json nlohmann_json>=3.7.0 nlohmann)
|
||||
|
||||
system_or_submodule(LIBUV uv_a libuv>=1.44.2 libuv)
|
||||
|
||||
if (STATIC OR FORCE_SPDLOG_SUBMODULE OR FORCE_FMT_SUBMODULE)
|
||||
set(OXEN_LOGGING_FORCE_SUBMODULES ON CACHE INTERNAL "")
|
||||
endif()
|
||||
|
@ -92,7 +95,7 @@ endif()
|
|||
|
||||
add_library(uvw INTERFACE)
|
||||
target_include_directories(uvw INTERFACE uvw/src)
|
||||
target_link_libraries(uvw INTERFACE libuv)
|
||||
target_link_libraries(uvw INTERFACE uv_a::uv_a)
|
||||
|
||||
# ngtcp2 needs some massaging to build nicely:
|
||||
include(ngtcp2_lib)
|
||||
|
|
1
external/ios-cmake
vendored
Submodule
1
external/ios-cmake
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit ab8607a7f57970d99d590d420ecd8e2d7f9a9c77
|
1
external/libuv
vendored
Submodule
1
external/libuv
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 0c1fa696aa502eb749c2c4735005f41ba00a27b8
|
2
external/ngtcp2
vendored
2
external/ngtcp2
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 026b8434ebcbeec48939d1c7671a0a4d5c75202b
|
||||
Subproject commit 86206d86f185885da57a1b1fcc6518f267bf0052
|
|
@ -4,5 +4,5 @@
|
|||
#include "lokinet/lokinet_srv.h"
|
||||
#include "lokinet/lokinet_misc.h"
|
||||
#include "lokinet/lokinet_addr.h"
|
||||
#include "lokinet/lokinet_stream.h"
|
||||
#include "lokinet/lokinet_tcp.h"
|
||||
#include "lokinet/lokinet_udp.h"
|
||||
|
|
|
@ -50,6 +50,12 @@ extern "C"
|
|||
int EXPORT
|
||||
lokinet_add_bootstrap_rc(const char*, size_t, struct lokinet_context*);
|
||||
|
||||
/// set data directory for saving/loading node db
|
||||
/// does nothing if called after lokinet_context_start
|
||||
/// TODO: use for saving config changes in-client?
|
||||
void EXPORT
|
||||
lokinet_set_data_dir(const char*, struct lokinet_context*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "lokinet_context.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/// the result of a lokinet stream mapping attempt
|
||||
struct lokinet_stream_result
|
||||
{
|
||||
/// set to zero on success otherwise the error that happened
|
||||
/// use strerror(3) to get printable string of this error
|
||||
int error;
|
||||
|
||||
/// the local ip address we mapped the remote endpoint to
|
||||
/// null terminated
|
||||
char local_address[256];
|
||||
/// the local port we mapped the remote endpoint to
|
||||
int local_port;
|
||||
/// the id of the stream we created
|
||||
int stream_id;
|
||||
};
|
||||
|
||||
/// connect out to a remote endpoint
|
||||
/// remoteAddr is in the form of "name:port"
|
||||
/// localAddr is either NULL for any or in the form of "ip:port" to bind to an explicit address
|
||||
void EXPORT
|
||||
lokinet_outbound_stream(
|
||||
struct lokinet_stream_result* result,
|
||||
const char* remoteAddr,
|
||||
const char* localAddr,
|
||||
struct lokinet_context* context);
|
||||
|
||||
/// stream accept filter determines if we should accept a stream or not
|
||||
/// return 0 to accept
|
||||
/// return -1 to explicitly reject
|
||||
/// return -2 to silently drop
|
||||
typedef int (*lokinet_stream_filter)(const char* remote, uint16_t port, void* userdata);
|
||||
|
||||
/// set stream accepter filter
|
||||
/// passes user parameter into stream filter as void *
|
||||
/// returns stream id
|
||||
int EXPORT
|
||||
lokinet_inbound_stream_filter(
|
||||
lokinet_stream_filter acceptFilter, void* user, struct lokinet_context* context);
|
||||
|
||||
/// simple stream acceptor
|
||||
/// simple variant of lokinet_inbound_stream_filter that maps port to localhost:port
|
||||
int EXPORT
|
||||
lokinet_inbound_stream(uint16_t port, struct lokinet_context* context);
|
||||
|
||||
void EXPORT
|
||||
lokinet_close_stream(int stream_id, struct lokinet_context* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
63
include/lokinet/lokinet_tcp.h
Normal file
63
include/lokinet/lokinet_tcp.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include "lokinet_context.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/// the result of a lokinet tcp mapping attempt
|
||||
struct lokinet_tcp_result
|
||||
{
|
||||
/// set to zero on success otherwise the error that happened
|
||||
/// use strerror(3) to get printable string of this error
|
||||
int error;
|
||||
/// set once the tcp connection is successfully established
|
||||
bool success;
|
||||
/// the local ip address we mapped the remote endpoint to
|
||||
/// null terminated
|
||||
char local_address[256];
|
||||
/// the local port we mapped the remote endpoint to
|
||||
int local_port;
|
||||
/// the id (aka: 'pseudo-port') of the tcp we created
|
||||
int tcp_id;
|
||||
};
|
||||
|
||||
/// connect out to a remote endpoint
|
||||
/// remoteAddr is in the form of "name:port"
|
||||
/// localAddr is either NULL for any or in the form of "ip:port" to bind to an explicit address
|
||||
void EXPORT
|
||||
lokinet_outbound_tcp(
|
||||
struct lokinet_tcp_result* result,
|
||||
const char* remoteAddr,
|
||||
const char* localAddr,
|
||||
struct lokinet_context* context,
|
||||
void (*open_cb)(bool success, void* user_data),
|
||||
void (*close_cb)(int rv, void* user_data),
|
||||
void* user_data);
|
||||
|
||||
/// tcp accept filter determines if we should accept a tcp or not
|
||||
/// return 0 to accept
|
||||
/// return -1 to explicitly reject
|
||||
/// return -2 to silently drop
|
||||
typedef int (*lokinet_tcp_filter)(const char* remote, uint16_t port, void* userdata);
|
||||
|
||||
/// set tcp accepter filter
|
||||
/// passes user parameter into tcp filter as void *
|
||||
/// returns tcp id
|
||||
int EXPORT
|
||||
lokinet_inbound_tcp_filter(
|
||||
lokinet_tcp_filter acceptFilter, void* user, struct lokinet_context* context);
|
||||
|
||||
/// simple tcp acceptor
|
||||
/// simple variant of lokinet_inbound_tcp_filter that maps port to localhost:port
|
||||
int EXPORT
|
||||
lokinet_inbound_tcp(uint16_t port, struct lokinet_context* context);
|
||||
|
||||
void EXPORT
|
||||
lokinet_close_tcp(int tcp_id, struct lokinet_context* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -440,7 +440,7 @@ function(link_lokinet_layers)
|
|||
lokinet_link_lib(${ARGV1} ${lib})
|
||||
list(REMOVE_AT ARGV 1)
|
||||
target_link_libraries(${lib} PRIVATE ${ARGV1})
|
||||
# recursion :D
|
||||
# recursion :D
|
||||
link_lokinet_layers(${ARGV})
|
||||
else()
|
||||
lokinet_link_lib(${lib})
|
||||
|
@ -520,18 +520,35 @@ target_link_libraries(lokinet-plainquic PUBLIC
|
|||
|
||||
if(WITH_EMBEDDED_LOKINET)
|
||||
include(GNUInstallDirs)
|
||||
add_library(lokinet-shared SHARED lokinet_shared.cpp)
|
||||
target_link_libraries(lokinet-shared PUBLIC lokinet-amalgum)
|
||||
add_library(lokinet-embedded-api lokinet_shared.cpp)
|
||||
target_link_libraries(lokinet-embedded-api PUBLIC lokinet-amalgum)
|
||||
|
||||
if(BUILD_STATIC_DEPS)
|
||||
get_target_property(embedded-libs lokinet-amalgum INTERFACE_LINK_LIBRARIES)
|
||||
combine_archives(lokinet-embedded
|
||||
${embedded-libs}
|
||||
lokinet-embedded-api
|
||||
ngtcp2_static
|
||||
uv_a::uv_a
|
||||
sodium
|
||||
zlib
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto
|
||||
expat
|
||||
libunbound
|
||||
libzmq
|
||||
fmt::fmt
|
||||
spdlog::spdlog
|
||||
oxen::logging
|
||||
oxenmq::oxenmq)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX_CXX "")
|
||||
target_link_libraries(lokinet-embedded-api PUBLIC ws2_32 iphlpapi -fstack-protector)
|
||||
endif()
|
||||
set_target_properties(lokinet-shared PROPERTIES OUTPUT_NAME lokinet)
|
||||
if(WIN32)
|
||||
target_link_libraries(lokinet-shared PUBLIC ws2_32 iphlpapi -fstack-protector)
|
||||
install(TARGETS lokinet-shared DESTINATION bin COMPONENT liblokinet)
|
||||
elseif(NOT APPLE)
|
||||
install(TARGETS lokinet-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT liblokinet)
|
||||
endif()
|
||||
|
||||
install(TARGETS lokinet-embedded-api DESTINATION bin COMPONENT liblokinet)
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE docs_SRC */*.hpp *.hpp)
|
||||
|
|
|
@ -1654,7 +1654,8 @@ namespace llarp
|
|||
{
|
||||
auto config = std::make_shared<Config>();
|
||||
config->Load();
|
||||
config->logging.m_logLevel = log::Level::off;
|
||||
config->logging.m_logLevel = log::Level::debug;
|
||||
config->logging.m_logFile = "stderr";
|
||||
config->api.m_enableRPCServer = false;
|
||||
config->network.m_endpointType = "null";
|
||||
config->network.m_saveProfiles = false;
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace llarp
|
|||
virtual bool
|
||||
EnsurePathTo(
|
||||
AddressVariant_t addr,
|
||||
std::function<void(std::optional<service::ConvoTag>)> hook,
|
||||
std::function<void(std::optional<std::variant<service::Address, RouterID>>)> hook,
|
||||
llarp_time_t timeout) = 0;
|
||||
|
||||
virtual void
|
||||
|
@ -134,7 +134,9 @@ namespace llarp
|
|||
|
||||
virtual bool
|
||||
SendToOrQueue(
|
||||
service::ConvoTag tag, const llarp_buffer_t& payload, service::ProtocolType t) = 0;
|
||||
std::variant<service::Address, RouterID> addr,
|
||||
const llarp_buffer_t& payload,
|
||||
service::ProtocolType t) = 0;
|
||||
|
||||
/// lookup srv records async
|
||||
virtual void
|
||||
|
|
|
@ -119,7 +119,15 @@ namespace llarp
|
|||
if (not quic)
|
||||
return false;
|
||||
m_TxRate += buf.size();
|
||||
quic->receive_packet(tag, std::move(buf));
|
||||
|
||||
std::variant<service::Address, RouterID> addr;
|
||||
|
||||
if (auto maybe = m_Parent->GetEndpointWithConvoTag(tag))
|
||||
addr = *maybe;
|
||||
else
|
||||
return false;
|
||||
|
||||
quic->receive_packet(std::move(addr), std::move(buf));
|
||||
m_LastActive = m_Parent->Now();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -207,7 +207,15 @@ namespace llarp
|
|||
auto quic = m_Parent->GetQUICTunnel();
|
||||
if (not quic)
|
||||
return false;
|
||||
quic->receive_packet(tag, buf);
|
||||
|
||||
std::variant<service::Address, RouterID> addr;
|
||||
|
||||
if (auto maybe = m_Parent->GetEndpointWithConvoTag(tag))
|
||||
addr = *maybe;
|
||||
else
|
||||
return false;
|
||||
|
||||
quic->receive_packet(std::move(addr), buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,42 +97,40 @@ namespace llarp
|
|||
|
||||
bool
|
||||
ExitEndpoint::SendToOrQueue(
|
||||
service::ConvoTag tag, const llarp_buffer_t& payload, service::ProtocolType type)
|
||||
std::variant<service::Address, RouterID> addr,
|
||||
const llarp_buffer_t& payload,
|
||||
service::ProtocolType type)
|
||||
{
|
||||
if (auto maybeAddr = GetEndpointWithConvoTag(tag))
|
||||
if (std::holds_alternative<service::Address>(addr))
|
||||
return false;
|
||||
if (auto* rid = std::get_if<RouterID>(&addr))
|
||||
{
|
||||
if (std::holds_alternative<service::Address>(*maybeAddr))
|
||||
return false;
|
||||
if (auto* rid = std::get_if<RouterID>(&*maybeAddr))
|
||||
for (auto [itr, end] = m_ActiveExits.equal_range(PubKey{*rid}); itr != end; ++itr)
|
||||
{
|
||||
for (auto [itr, end] = m_ActiveExits.equal_range(PubKey{*rid}); itr != end; ++itr)
|
||||
if (not itr->second->LooksDead(Now()))
|
||||
{
|
||||
if (not itr->second->LooksDead(Now()))
|
||||
{
|
||||
if (itr->second->QueueInboundTraffic(payload.copy(), type))
|
||||
return true;
|
||||
}
|
||||
if (itr->second->QueueInboundTraffic(payload.copy(), type))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (not m_Router->PathToRouterAllowed(*rid))
|
||||
return false;
|
||||
|
||||
ObtainSNodeSession(*rid, [pkt = payload.copy(), type](auto session) mutable {
|
||||
if (session and session->IsReady())
|
||||
{
|
||||
session->SendPacketToRemote(std::move(pkt), type);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
|
||||
if (not m_Router->PathToRouterAllowed(*rid))
|
||||
return false;
|
||||
|
||||
ObtainSNodeSession(*rid, [pkt = payload.copy(), type](auto session) mutable {
|
||||
if (session and session->IsReady())
|
||||
{
|
||||
session->SendPacketToRemote(std::move(pkt), type);
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ExitEndpoint::EnsurePathTo(
|
||||
AddressVariant_t addr,
|
||||
std::function<void(std::optional<service::ConvoTag>)> hook,
|
||||
std::function<void(std::optional<std::variant<service::Address, RouterID>>)> hook,
|
||||
llarp_time_t)
|
||||
{
|
||||
if (std::holds_alternative<service::Address>(addr))
|
||||
|
@ -142,15 +140,11 @@ namespace llarp
|
|||
if (m_SNodeKeys.count(PubKey{*rid}) or m_Router->PathToRouterAllowed(*rid))
|
||||
{
|
||||
ObtainSNodeSession(
|
||||
*rid, [hook, routerID = *rid](std::shared_ptr<exit::BaseSession> session) {
|
||||
if (session and session->IsReady())
|
||||
*rid, [hook, routerID = *rid, this](std::shared_ptr<exit::BaseSession> session) {
|
||||
if (session and session->IsReady(); auto path = session->GetPathByRouter(routerID))
|
||||
{
|
||||
if (auto path = session->GetPathByRouter(routerID))
|
||||
{
|
||||
hook(service::ConvoTag{path->RXID().as_array()});
|
||||
}
|
||||
else
|
||||
hook(std::nullopt);
|
||||
auto tag = service::ConvoTag{path->RXID().as_array()};
|
||||
hook(GetEndpointWithConvoTag(tag));
|
||||
}
|
||||
else
|
||||
hook(std::nullopt);
|
||||
|
@ -159,7 +153,13 @@ namespace llarp
|
|||
else
|
||||
{
|
||||
// probably a client
|
||||
hook(GetBestConvoTagFor(addr));
|
||||
if (auto maybe_tag = GetBestConvoTagFor(addr);
|
||||
auto maybe_addr = GetEndpointWithConvoTag(*maybe_tag))
|
||||
{
|
||||
hook(maybe_addr);
|
||||
}
|
||||
else
|
||||
hook(std::nullopt);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace llarp
|
|||
bool
|
||||
EnsurePathTo(
|
||||
AddressVariant_t addr,
|
||||
std::function<void(std::optional<service::ConvoTag>)> hook,
|
||||
std::function<void(std::optional<std::variant<service::Address, RouterID>>)> hook,
|
||||
llarp_time_t timeout) override;
|
||||
|
||||
void
|
||||
|
@ -64,7 +64,9 @@ namespace llarp
|
|||
|
||||
bool
|
||||
SendToOrQueue(
|
||||
service::ConvoTag tag, const llarp_buffer_t& payload, service::ProtocolType t) override;
|
||||
std::variant<service::Address, RouterID> addr,
|
||||
const llarp_buffer_t& payload,
|
||||
service::ProtocolType t) override;
|
||||
|
||||
void
|
||||
Tick(llarp_time_t now);
|
||||
|
|
|
@ -70,7 +70,14 @@ namespace llarp::handlers
|
|||
LogWarn("invalid incoming quic packet, dropping");
|
||||
return false;
|
||||
}
|
||||
quic->receive_packet(tag, buf);
|
||||
|
||||
std::variant<service::Address, RouterID> addr;
|
||||
if (auto maybe = GetEndpointWithConvoTag(tag))
|
||||
addr = *maybe;
|
||||
else
|
||||
return false;
|
||||
|
||||
quic->receive_packet(std::move(addr), buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1255,9 +1255,10 @@ namespace llarp
|
|||
}
|
||||
// try sending it on an existing convotag
|
||||
// this succeds for inbound convos, probably.
|
||||
if (auto maybe = GetBestConvoTagFor(to))
|
||||
if (auto maybe_tag = GetBestConvoTagFor(to);
|
||||
auto maybe_addr = GetEndpointWithConvoTag(*maybe_tag))
|
||||
{
|
||||
if (SendToOrQueue(*maybe, pkt.ConstBuffer(), type))
|
||||
if (SendToOrQueue(*maybe_addr, pkt.ConstBuffer(), type))
|
||||
{
|
||||
MarkIPActive(dst);
|
||||
Router()->TriggerPump();
|
||||
|
@ -1314,6 +1315,14 @@ namespace llarp
|
|||
uint64_t seqno)
|
||||
{
|
||||
LogTrace("Inbound ", t, " packet (", buf.sz, "B) on convo ", tag);
|
||||
std::variant<service::Address, RouterID> addr;
|
||||
if (auto maybe = GetEndpointWithConvoTag(tag))
|
||||
{
|
||||
addr = *maybe;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
if (t == service::ProtocolType::QUIC)
|
||||
{
|
||||
auto* quic = GetQUICTunnel();
|
||||
|
@ -1327,21 +1336,15 @@ namespace llarp
|
|||
LogWarn("invalid incoming quic packet, dropping");
|
||||
return false;
|
||||
}
|
||||
LogInfo("tag active T=", tag);
|
||||
quic->receive_packet(tag, buf);
|
||||
log::trace(logcat, "tag active T={}", tag);
|
||||
|
||||
quic->receive_packet(std::move(addr), buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t != service::ProtocolType::TrafficV4 && t != service::ProtocolType::TrafficV6
|
||||
&& t != service::ProtocolType::Exit)
|
||||
return false;
|
||||
std::variant<service::Address, RouterID> addr;
|
||||
if (auto maybe = GetEndpointWithConvoTag(tag))
|
||||
{
|
||||
addr = *maybe;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
huint128_t src, dst;
|
||||
|
||||
net::IPPacket pkt;
|
||||
|
|
|
@ -6,11 +6,14 @@
|
|||
#include <llarp/router/abstractrouter.hpp>
|
||||
|
||||
#include <queue>
|
||||
#include "oxen/log.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace iwp
|
||||
{
|
||||
static auto logcat = log::Cat("endpoint");
|
||||
|
||||
ILinkSession::Packet_t
|
||||
CreatePacket(Command cmd, size_t plainsize, size_t minpad, size_t variance)
|
||||
{
|
||||
|
@ -141,6 +144,8 @@ namespace llarp
|
|||
void
|
||||
Session::EncryptAndSend(ILinkSession::Packet_t data)
|
||||
{
|
||||
if (m_State == State::Closed)
|
||||
return;
|
||||
m_EncryptNext.emplace_back(std::move(data));
|
||||
TriggerPump();
|
||||
if (!IsEstablished())
|
||||
|
@ -176,12 +181,9 @@ namespace llarp
|
|||
return;
|
||||
auto close_msg = CreatePacket(Command::eCLOS, 0, 16, 16);
|
||||
m_Parent->UnmapAddr(m_RemoteAddr);
|
||||
m_State = State::Closed;
|
||||
if (m_SentClosed.test_and_set())
|
||||
return;
|
||||
EncryptAndSend(std::move(close_msg));
|
||||
|
||||
LogInfo(m_Parent->PrintableName(), " closing connection to ", m_RemoteAddr);
|
||||
m_State = State::Closed;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -352,7 +354,7 @@ namespace llarp
|
|||
bool
|
||||
Session::TimedOut(llarp_time_t now) const
|
||||
{
|
||||
if (m_State == State::Ready)
|
||||
if (m_State == State::Ready || m_State == State::LinkIntro)
|
||||
{
|
||||
return now > m_LastRX
|
||||
&& now - m_LastRX
|
||||
|
@ -588,7 +590,7 @@ namespace llarp
|
|||
{
|
||||
if (pkt.size() <= PacketOverhead)
|
||||
{
|
||||
LogError("packet too small from ", m_RemoteAddr);
|
||||
log::error(logcat, "Packet too small from {}", m_RemoteAddr);
|
||||
return false;
|
||||
}
|
||||
const llarp_buffer_t buf(pkt);
|
||||
|
@ -598,30 +600,27 @@ namespace llarp
|
|||
curbuf.sz -= ShortHash::SIZE;
|
||||
if (not CryptoManager::instance()->hmac(H.data(), curbuf, m_SessionKey))
|
||||
{
|
||||
LogError("failed to caclulate keyed hash for ", m_RemoteAddr);
|
||||
log::error(logcat, "Failed to calculate keyed hash for {}", m_RemoteAddr);
|
||||
return false;
|
||||
}
|
||||
const ShortHash expected{buf.base};
|
||||
if (H != expected)
|
||||
{
|
||||
LogDebug(
|
||||
log::debug(
|
||||
logcat,
|
||||
"{} keyed hash mismatch {} != {} from {} state={} size={}",
|
||||
m_Parent->PrintableName(),
|
||||
" keyed hash mismatch ",
|
||||
H,
|
||||
" != ",
|
||||
expected,
|
||||
" from ",
|
||||
m_RemoteAddr,
|
||||
" state=",
|
||||
int(m_State),
|
||||
" size=",
|
||||
buf.sz);
|
||||
return false;
|
||||
}
|
||||
const TunnelNonce N{curbuf.base};
|
||||
curbuf.base += 32;
|
||||
curbuf.sz -= 32;
|
||||
LogTrace("decrypt: ", curbuf.sz, " bytes from ", m_RemoteAddr);
|
||||
log::trace(logcat, "Decrypt: {} bytes from {}", curbuf.sz, m_RemoteAddr);
|
||||
return CryptoManager::instance()->xchacha20(curbuf, m_SessionKey, N);
|
||||
}
|
||||
|
||||
|
|
|
@ -206,7 +206,6 @@ namespace llarp
|
|||
|
||||
std::atomic_flag m_PlaintextEmpty;
|
||||
llarp::thread::Queue<CryptoQueue_t> m_PlaintextRecv;
|
||||
std::atomic_flag m_SentClosed;
|
||||
|
||||
void
|
||||
EncryptWorker(CryptoQueue_t msgs);
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include <lokinet.h>
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <llarp.hpp>
|
||||
#include <llarp/config/config.hpp>
|
||||
#include <llarp/crypto/crypto_libsodium.hpp>
|
||||
|
@ -18,6 +21,8 @@
|
|||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include "lokinet/lokinet_tcp.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EHOSTDOWN ENETDOWN
|
||||
|
@ -25,6 +30,8 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
static auto logcat = llarp::log::Cat("liblokinet");
|
||||
|
||||
struct Context : public llarp::Context
|
||||
{
|
||||
using llarp::Context::Context;
|
||||
|
@ -32,7 +39,7 @@ namespace
|
|||
std::shared_ptr<llarp::NodeDB>
|
||||
makeNodeDB() override
|
||||
{
|
||||
return std::make_shared<llarp::NodeDB>();
|
||||
return llarp::Context::makeNodeDB();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -308,41 +315,47 @@ struct lokinet_context
|
|||
return impl->router->hiddenServiceContext().GetEndpointByName(name);
|
||||
}
|
||||
|
||||
std::unordered_map<int, bool> streams;
|
||||
/// false: outbound connection
|
||||
/// true: inbound connection
|
||||
std::unordered_map<int, bool> tcp_conns;
|
||||
/// maps address to pair of (stream_id, ready)
|
||||
std::unordered_map<std::string, lokinet_tcp_result> active_conns;
|
||||
|
||||
std::unordered_map<int, std::shared_ptr<UDPHandler>> udp_sockets;
|
||||
|
||||
void
|
||||
inbound_stream(int id)
|
||||
inbound_tcp(int id)
|
||||
{
|
||||
streams[id] = true;
|
||||
tcp_conns[id] = true;
|
||||
}
|
||||
|
||||
void
|
||||
outbound_stream(int id)
|
||||
outbound_tcp(std::string remote_addr, lokinet_tcp_result& res)
|
||||
{
|
||||
streams[id] = false;
|
||||
tcp_conns[res.tcp_id] = false;
|
||||
active_conns[remote_addr] = lokinet_tcp_result{res};
|
||||
}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
void
|
||||
stream_error(lokinet_stream_result* result, int err)
|
||||
tcp_error(lokinet_tcp_result* result, int err)
|
||||
{
|
||||
std::memset(result, 0, sizeof(lokinet_stream_result));
|
||||
*result = lokinet_tcp_result{};
|
||||
result->error = err;
|
||||
}
|
||||
|
||||
void
|
||||
stream_okay(lokinet_stream_result* result, std::string host, int port, int stream_id)
|
||||
tcp_okay(lokinet_tcp_result* result, std::string host, int port, int tcp_id)
|
||||
{
|
||||
stream_error(result, 0);
|
||||
tcp_error(result, 0);
|
||||
std::copy_n(
|
||||
host.c_str(),
|
||||
std::min(host.size(), sizeof(result->local_address) - 1),
|
||||
result->local_address);
|
||||
result->local_port = port;
|
||||
result->stream_id = stream_id;
|
||||
result->tcp_id = tcp_id;
|
||||
}
|
||||
|
||||
std::pair<std::string, int>
|
||||
|
@ -355,7 +368,7 @@ namespace
|
|||
portStr = data.substr(pos + 1);
|
||||
}
|
||||
else
|
||||
throw EINVAL;
|
||||
throw std::invalid_argument("Error: invalid address passed");
|
||||
|
||||
if (auto* serv = getservbyname(portStr.c_str(), proto.c_str()))
|
||||
{
|
||||
|
@ -395,7 +408,6 @@ struct lokinet_srv_lookup_private
|
|||
{
|
||||
std::promise<int> promise;
|
||||
{
|
||||
auto lock = ctx->acquire();
|
||||
if (ctx->impl and ctx->impl->IsUp())
|
||||
{
|
||||
ctx->impl->CallSafe([host, service, &promise, ctx, this]() {
|
||||
|
@ -483,6 +495,8 @@ extern "C"
|
|||
int EXPORT
|
||||
lokinet_add_bootstrap_rc(const char* data, size_t datalen, struct lokinet_context* ctx)
|
||||
{
|
||||
// FIXME: bootstrap loading was rewritten but this code needs updated to do
|
||||
// it how Router does now.
|
||||
if (data == nullptr or datalen == 0)
|
||||
return -3;
|
||||
llarp_buffer_t buf{data, datalen};
|
||||
|
@ -621,138 +635,199 @@ extern "C"
|
|||
}
|
||||
|
||||
void EXPORT
|
||||
lokinet_outbound_stream(
|
||||
struct lokinet_stream_result* result,
|
||||
lokinet_set_data_dir(const char* path, struct lokinet_context* ctx)
|
||||
{
|
||||
fs::path dir{path};
|
||||
dir = fs::canonical(dir);
|
||||
fs::current_path(dir);
|
||||
|
||||
if (not ctx)
|
||||
return;
|
||||
auto lock = ctx->acquire();
|
||||
|
||||
if (ctx->impl->IsUp() or ctx->impl->IsStopping())
|
||||
return;
|
||||
|
||||
ctx->config->router.m_dataDir = dir;
|
||||
}
|
||||
|
||||
void EXPORT
|
||||
lokinet_outbound_tcp(
|
||||
struct lokinet_tcp_result* result,
|
||||
const char* remote,
|
||||
const char* local,
|
||||
struct lokinet_context* ctx)
|
||||
struct lokinet_context* ctx,
|
||||
void (*open_cb)(bool success, void* user_data),
|
||||
void (*close_cb)(int rv, void* user_data),
|
||||
void* user_data)
|
||||
{
|
||||
if (ctx == nullptr)
|
||||
{
|
||||
stream_error(result, EHOSTDOWN);
|
||||
tcp_error(result, EHOSTDOWN);
|
||||
return;
|
||||
}
|
||||
std::promise<void> promise;
|
||||
|
||||
{
|
||||
auto lock = ctx->acquire();
|
||||
|
||||
if (not ctx->impl->IsUp())
|
||||
if (auto itr = ctx->active_conns.find(remote); itr != ctx->active_conns.end())
|
||||
{
|
||||
stream_error(result, EHOSTDOWN);
|
||||
*result = lokinet_tcp_result{itr->second};
|
||||
llarp::LogError("Active connection to {} already exists", remote);
|
||||
return;
|
||||
}
|
||||
std::string remotehost;
|
||||
int remoteport;
|
||||
try
|
||||
{
|
||||
auto [h, p] = split_host_port(remote);
|
||||
remotehost = h;
|
||||
remoteport = p;
|
||||
}
|
||||
catch (int err)
|
||||
{
|
||||
stream_error(result, err);
|
||||
return;
|
||||
}
|
||||
// TODO: make configurable (?)
|
||||
std::string endpoint{"default"};
|
||||
|
||||
llarp::SockAddr localAddr;
|
||||
try
|
||||
{
|
||||
if (local)
|
||||
localAddr = llarp::SockAddr{std::string{local}};
|
||||
else
|
||||
localAddr = llarp::SockAddr{"127.0.0.1:0"};
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
stream_error(result, EINVAL);
|
||||
return;
|
||||
}
|
||||
auto call = [&promise,
|
||||
ctx,
|
||||
result,
|
||||
router = ctx->impl->router,
|
||||
remotehost,
|
||||
remoteport,
|
||||
endpoint,
|
||||
localAddr]() {
|
||||
auto ep = ctx->endpoint();
|
||||
if (ep == nullptr)
|
||||
{
|
||||
stream_error(result, ENOTSUP);
|
||||
promise.set_value();
|
||||
return;
|
||||
}
|
||||
auto* quic = ep->GetQUICTunnel();
|
||||
if (quic == nullptr)
|
||||
{
|
||||
stream_error(result, ENOTSUP);
|
||||
promise.set_value();
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
auto [addr, id] = quic->open(
|
||||
remotehost, remoteport, [](auto) {}, localAddr);
|
||||
auto [host, port] = split_host_port(addr.ToString());
|
||||
ctx->outbound_stream(id);
|
||||
stream_okay(result, host, port, id);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << ex.what() << std::endl;
|
||||
stream_error(result, ECANCELED);
|
||||
}
|
||||
catch (int err)
|
||||
{
|
||||
stream_error(result, err);
|
||||
}
|
||||
promise.set_value();
|
||||
};
|
||||
|
||||
ctx->impl->CallSafe([call]() {
|
||||
// we dont want the mainloop to die in case setting the value on the promise fails
|
||||
try
|
||||
{
|
||||
call();
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
});
|
||||
}
|
||||
|
||||
auto future = promise.get_future();
|
||||
if (not ctx->impl->IsUp())
|
||||
{
|
||||
tcp_error(result, EHOSTDOWN);
|
||||
return;
|
||||
}
|
||||
std::string remotehost;
|
||||
int remoteport;
|
||||
try
|
||||
{
|
||||
if (auto status = future.wait_for(std::chrono::seconds{10});
|
||||
status == std::future_status::ready)
|
||||
{
|
||||
future.get();
|
||||
}
|
||||
auto [h, p] = split_host_port(remote);
|
||||
remotehost = h;
|
||||
remoteport = p;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
llarp::log::error(logcat, "Error: exception caught: {}", e.what());
|
||||
tcp_error(result, EINVAL);
|
||||
return;
|
||||
}
|
||||
// TODO: make configurable (?)
|
||||
// FIXME: appears unused?
|
||||
std::string endpoint{"default"};
|
||||
|
||||
llarp::SockAddr localAddr;
|
||||
try
|
||||
{
|
||||
if (local)
|
||||
localAddr = llarp::SockAddr{std::string{local}};
|
||||
else
|
||||
{
|
||||
stream_error(result, ETIMEDOUT);
|
||||
}
|
||||
localAddr = llarp::SockAddr{"127.0.0.1:0"};
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
stream_error(result, EBADF);
|
||||
tcp_error(result, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
auto on_open = [ctx, localAddr, remote, open_cb](bool success, void* user_data) {
|
||||
llarp::log::info(
|
||||
logcat,
|
||||
"Quic tunnel {}<->{}.",
|
||||
localAddr,
|
||||
remote,
|
||||
success ? "opened successfully" : "failed");
|
||||
|
||||
auto lock = ctx->acquire();
|
||||
|
||||
if (auto conn = ctx->active_conns.find(remote); conn != ctx->active_conns.end())
|
||||
{
|
||||
if (success)
|
||||
conn->second.success = success;
|
||||
else
|
||||
ctx->active_conns.erase(remote);
|
||||
}
|
||||
|
||||
if (open_cb)
|
||||
open_cb(success, user_data);
|
||||
};
|
||||
|
||||
auto on_close = [ctx, localAddr, remote, close_cb](int rv, void* user_data) {
|
||||
llarp::log::info(logcat, "Quic tunnel {}<->{} closed.", localAddr, remote);
|
||||
|
||||
{
|
||||
auto lock = ctx->acquire();
|
||||
ctx->active_conns.erase(remote);
|
||||
}
|
||||
|
||||
if (close_cb)
|
||||
close_cb(rv, user_data);
|
||||
};
|
||||
|
||||
std::promise<void> promise;
|
||||
std::future<void> future = promise.get_future();
|
||||
|
||||
ctx->impl->CallSafe([&promise,
|
||||
ctx,
|
||||
result,
|
||||
router = ctx->impl->router,
|
||||
remotehost,
|
||||
remoteport,
|
||||
on_open = std::move(on_open),
|
||||
on_close = std::move(on_close),
|
||||
localAddr]() mutable {
|
||||
try
|
||||
{
|
||||
auto ep = ctx->endpoint();
|
||||
if (not ep)
|
||||
throw std::runtime_error{"lokinet_context->endpoint() returned null pointer."};
|
||||
auto* quic = ep->GetQUICTunnel();
|
||||
if (not quic)
|
||||
throw std::runtime_error{"lokinet_context endpoint has no quic tunnel manager."};
|
||||
|
||||
auto [addr, id] =
|
||||
quic->open(remotehost, remoteport, std::move(on_open), std::move(on_close), localAddr);
|
||||
auto [host, port] = split_host_port(addr.ToString());
|
||||
result->tcp_id = id;
|
||||
tcp_okay(result, host, port, id);
|
||||
promise.set_value();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
promise.set_exception(std::current_exception());
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
future.get();
|
||||
}
|
||||
catch (std::invalid_argument& e)
|
||||
{
|
||||
llarp::log::error(logcat, "Error: exception caught: {}", e.what());
|
||||
tcp_error(result, EINVAL);
|
||||
return;
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
llarp::log::error(logcat, "Error: exception caught: {}", e.what());
|
||||
tcp_error(result, ENOTSUP);
|
||||
return;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
llarp::log::error(logcat, "Error: exception caught: {}", e.what());
|
||||
tcp_error(result, EBADF);
|
||||
return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
llarp::log::error(logcat, "Unknown exception caught.");
|
||||
tcp_error(result, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = ctx->acquire();
|
||||
ctx->outbound_tcp(remote, *result);
|
||||
assert(result->error == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int EXPORT
|
||||
lokinet_inbound_stream(uint16_t port, struct lokinet_context* ctx)
|
||||
lokinet_inbound_tcp(uint16_t port, struct lokinet_context* ctx)
|
||||
{
|
||||
/// FIXME: delete pointer later
|
||||
return lokinet_inbound_stream_filter(&accept_port, (void*)new std::uintptr_t{port}, ctx);
|
||||
return lokinet_inbound_tcp_filter(&accept_port, (void*)new std::uintptr_t{port}, ctx);
|
||||
}
|
||||
|
||||
int EXPORT
|
||||
lokinet_inbound_stream_filter(
|
||||
lokinet_stream_filter acceptFilter, void* user, struct lokinet_context* ctx)
|
||||
lokinet_inbound_tcp_filter(
|
||||
lokinet_tcp_filter acceptFilter, void* user, struct lokinet_context* ctx)
|
||||
{
|
||||
if (acceptFilter == nullptr)
|
||||
{
|
||||
|
@ -762,7 +837,6 @@ extern "C"
|
|||
return -1;
|
||||
std::promise<int> promise;
|
||||
{
|
||||
auto lock = ctx->acquire();
|
||||
if (not ctx->impl->IsUp())
|
||||
{
|
||||
return -1;
|
||||
|
@ -792,7 +866,7 @@ extern "C"
|
|||
auto id = ftr.get();
|
||||
{
|
||||
auto lock = ctx->acquire();
|
||||
ctx->inbound_stream(id);
|
||||
ctx->inbound_tcp(id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
@ -815,32 +889,50 @@ extern "C"
|
|||
}
|
||||
|
||||
void EXPORT
|
||||
lokinet_close_stream(int stream_id, struct lokinet_context* ctx)
|
||||
lokinet_close_tcp(int tcp_id, struct lokinet_context* ctx)
|
||||
{
|
||||
if (not ctx)
|
||||
return;
|
||||
auto lock = ctx->acquire();
|
||||
if (not ctx->impl->IsUp())
|
||||
return;
|
||||
|
||||
{
|
||||
auto lock = ctx->acquire();
|
||||
if (not ctx->impl->IsUp())
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
std::promise<void> promise;
|
||||
bool inbound = ctx->streams.at(stream_id);
|
||||
ctx->impl->CallSafe([stream_id, inbound, ctx, &promise]() {
|
||||
bool inbound{false};
|
||||
{
|
||||
auto lock = ctx->acquire();
|
||||
inbound = ctx->tcp_conns.at(tcp_id);
|
||||
}
|
||||
|
||||
ctx->impl->CallSafe([tcp_id, inbound, ctx, &promise]() {
|
||||
auto lock = ctx->acquire();
|
||||
auto ep = ctx->endpoint();
|
||||
auto* quic = ep->GetQUICTunnel();
|
||||
try
|
||||
{
|
||||
if (inbound)
|
||||
quic->forget(stream_id);
|
||||
quic->forget(tcp_id);
|
||||
else
|
||||
quic->close(stream_id);
|
||||
quic->close(tcp_id);
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
promise.set_value();
|
||||
});
|
||||
|
||||
{
|
||||
auto lock = ctx->acquire();
|
||||
for (auto& itr : ctx->active_conns)
|
||||
{
|
||||
if (itr.second.tcp_id == tcp_id)
|
||||
ctx->active_conns.erase(itr.first);
|
||||
}
|
||||
}
|
||||
promise.get_future().get();
|
||||
}
|
||||
catch (...)
|
||||
|
@ -958,9 +1050,10 @@ extern "C"
|
|||
return EINVAL;
|
||||
std::promise<int> ret;
|
||||
ctx->impl->router->loop()->call([addr = *maybe, pkt = std::move(pkt), ep, &ret]() {
|
||||
if (auto tag = ep->GetBestConvoTagFor(addr))
|
||||
if (auto tag = ep->GetBestConvoTagFor(addr); auto addr = ep->GetEndpointWithConvoTag(*tag))
|
||||
{
|
||||
if (ep->SendToOrQueue(*tag, pkt.ConstBuffer(), llarp::service::ProtocolType::TrafficV4))
|
||||
if (ep->SendToOrQueue(
|
||||
std::move(*addr), pkt.ConstBuffer(), llarp::service::ProtocolType::TrafficV4))
|
||||
{
|
||||
ret.set_value(0);
|
||||
return;
|
||||
|
|
|
@ -77,6 +77,6 @@ namespace llarp
|
|||
result = router->SendToOrQueue(session->GetPubKey(), reply);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
} // namespace llarp
|
||||
|
|
|
@ -274,7 +274,7 @@ namespace llarp
|
|||
return llarp::net::ToHost(x);
|
||||
}
|
||||
|
||||
[[deprecated("use llarp::net::ToHost instead")]] inline net::ipv4addr_t
|
||||
[[deprecated("use llarp::net::ToNet instead")]] inline net::ipv4addr_t
|
||||
xhtonl(huint32_t x)
|
||||
{
|
||||
return ToNet(x);
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace llarp
|
|||
init();
|
||||
fromString(addr);
|
||||
}
|
||||
|
||||
SockAddr::SockAddr(std::string_view addr, huint16_t port)
|
||||
{
|
||||
init();
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#include "address.hpp"
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
|
||||
namespace llarp::quic
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
Address::Address(const SockAddr& addr) : saddr{*addr.operator const sockaddr_in6*()}
|
||||
Address::Address(const SockAddr& addr, std::optional<std::variant<service::Address, RouterID>> ep)
|
||||
: saddr{*addr.operator const sockaddr_in6*()}, endpoint{ep}
|
||||
{}
|
||||
|
||||
Address&
|
||||
|
@ -14,6 +16,7 @@ namespace llarp::quic
|
|||
{
|
||||
std::memmove(&saddr, &other.saddr, sizeof(saddr));
|
||||
a.addrlen = other.a.addrlen;
|
||||
endpoint = other.endpoint;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -39,6 +42,7 @@ namespace llarp::quic
|
|||
return result;
|
||||
}
|
||||
|
||||
// FIXME: remote now has std::variant
|
||||
std::string
|
||||
Path::ToString() const
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
|
||||
|
@ -13,6 +14,7 @@
|
|||
|
||||
#include <llarp/net/sock_addr.hpp>
|
||||
#include <llarp/service/convotag.hpp>
|
||||
#include "llarp/service/address.hpp"
|
||||
|
||||
namespace llarp::quic
|
||||
{
|
||||
|
@ -25,13 +27,17 @@ namespace llarp::quic
|
|||
|
||||
public:
|
||||
Address() = default;
|
||||
Address(const SockAddr& addr);
|
||||
Address(
|
||||
const SockAddr& addr,
|
||||
std::optional<std::variant<service::Address, RouterID>> ep = std::nullopt);
|
||||
|
||||
Address(const Address& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
std::optional<std::variant<service::Address, RouterID>> endpoint{};
|
||||
|
||||
Address&
|
||||
operator=(const Address&);
|
||||
|
||||
|
@ -60,7 +66,7 @@ namespace llarp::quic
|
|||
return a;
|
||||
}
|
||||
|
||||
size_t
|
||||
ngtcp2_socklen
|
||||
sockaddr_size() const
|
||||
{
|
||||
return sizeof(sockaddr_in6);
|
||||
|
@ -89,7 +95,7 @@ namespace llarp::quic
|
|||
// ConvoTag operator
|
||||
operator SockAddr() const
|
||||
{
|
||||
return SockAddr(saddr);
|
||||
return SockAddr{saddr};
|
||||
}
|
||||
|
||||
std::string
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "client.hpp"
|
||||
#include "llarp/net/net_int.hpp"
|
||||
#include "tunnel.hpp"
|
||||
#include <llarp/util/logging/buffer.hpp>
|
||||
#include <llarp/util/logging.hpp>
|
||||
|
@ -12,7 +13,14 @@
|
|||
|
||||
namespace llarp::quic
|
||||
{
|
||||
Client::Client(EndpointBase& ep, const SockAddr& remote, uint16_t pseudo_port) : Endpoint{ep}
|
||||
static auto logcat = log::Cat("quic");
|
||||
|
||||
Client::Client(
|
||||
EndpointBase& ep,
|
||||
const uint16_t port,
|
||||
std::variant<service::Address, RouterID>&& remote,
|
||||
uint16_t pseudo_port)
|
||||
: Endpoint{ep}
|
||||
{
|
||||
default_stream_buffer_size =
|
||||
0; // We steal uvw's provided buffers so don't need an outgoing data buffer
|
||||
|
@ -21,8 +29,7 @@ namespace llarp::quic
|
|||
// back to *this* client.
|
||||
local_addr.port(ToNet(huint16_t{pseudo_port}));
|
||||
|
||||
uint16_t tunnel_port = remote.getPort();
|
||||
if (tunnel_port == 0)
|
||||
if (port == 0)
|
||||
throw std::logic_error{"Cannot tunnel to port 0"};
|
||||
|
||||
// TODO: need timers for:
|
||||
|
@ -34,10 +41,13 @@ namespace llarp::quic
|
|||
//
|
||||
// - key_update_timer
|
||||
|
||||
Path path{local_addr, remote};
|
||||
llarp::LogDebug("Connecting to ", remote);
|
||||
// to try: set ports to 0
|
||||
Path path{
|
||||
Address{SockAddr{"::1"sv, huint16_t{0}}, std::nullopt},
|
||||
Address{SockAddr{"::1"sv, huint16_t{pseudo_port}}, std::move(remote)}};
|
||||
|
||||
auto conn = std::make_shared<Connection>(*this, ConnectionID::random(), std::move(path), port);
|
||||
|
||||
auto conn = std::make_shared<Connection>(*this, ConnectionID::random(), path, tunnel_port);
|
||||
conn->io_ready();
|
||||
conns.emplace(conn->base_cid, std::move(conn));
|
||||
}
|
||||
|
|
|
@ -14,7 +14,11 @@ namespace llarp::quic
|
|||
// `remote.getPort()` on the remote's lokinet address. `pseudo_port` is *our* unique local
|
||||
// identifier which we include in outgoing packets (so that the remote server knows where to
|
||||
// send the back to *this* client).
|
||||
Client(EndpointBase& ep, const SockAddr& remote, uint16_t pseudo_port);
|
||||
Client(
|
||||
EndpointBase& ep,
|
||||
const uint16_t port,
|
||||
std::variant<service::Address, RouterID>&& remote,
|
||||
uint16_t pseudo_port);
|
||||
|
||||
// Returns a reference to the client's connection to the server. Returns a nullptr if there is
|
||||
// no connection.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -245,6 +245,9 @@ namespace llarp::quic
|
|||
int
|
||||
setup_server_crypto_initial();
|
||||
|
||||
int
|
||||
get_handshake_confirmed();
|
||||
|
||||
// Flush any streams with pending data. Note that, depending on available ngtcp2 state, we may
|
||||
// not fully flush all streams -- some streams can individually block while waiting for
|
||||
// confirmation.
|
||||
|
@ -276,9 +279,9 @@ namespace llarp::quic
|
|||
// called.
|
||||
std::function<void(Connection&)> on_handshake_complete;
|
||||
|
||||
// Returns true iff this connection has completed a handshake with the remote end.
|
||||
bool
|
||||
get_handshake_completed();
|
||||
// Returns non-zero iff this connection has not completed a handshake with the remote end.
|
||||
int
|
||||
complete_handshake();
|
||||
|
||||
// Callback that is invoked whenever new streams become available: i.e. after handshaking, or
|
||||
// after existing streams are closed. Note that this callback is invoked whenever the number of
|
||||
|
@ -287,6 +290,11 @@ namespace llarp::quic
|
|||
// least 1 when this callback is invoked).
|
||||
std::function<void(Connection&)> on_stream_available;
|
||||
|
||||
// Callback that is invoked by the Connection's owning Endpoint whenever the Connection
|
||||
// is put into a "closing" state (draining, closing, immediate dismissal, etc.) After
|
||||
// calling this once, the Endpoint clears it.
|
||||
std::function<void(Connection&)> on_closing;
|
||||
|
||||
// Returns the number of available streams that can currently be opened on the connection
|
||||
int
|
||||
get_streams_available();
|
||||
|
@ -322,8 +330,8 @@ namespace llarp::quic
|
|||
send_magic(ngtcp2_crypto_level level);
|
||||
int
|
||||
send_transport_params(ngtcp2_crypto_level level);
|
||||
void
|
||||
complete_handshake();
|
||||
// void
|
||||
// complete_handshake();
|
||||
};
|
||||
|
||||
} // namespace llarp::quic
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "endpoint.hpp"
|
||||
#include "client.hpp"
|
||||
#include "llarp/net/net_int.hpp"
|
||||
#include "ngtcp2/ngtcp2.h"
|
||||
#include "server.hpp"
|
||||
#include "uvw/async.h"
|
||||
#include <llarp/crypto/crypto.hpp>
|
||||
|
@ -22,6 +24,8 @@ extern "C"
|
|||
|
||||
namespace llarp::quic
|
||||
{
|
||||
static auto logcat = log::Cat("quic");
|
||||
|
||||
Endpoint::Endpoint(EndpointBase& ep) : service_endpoint{ep}
|
||||
{
|
||||
randombytes_buf(static_secret.data(), static_secret.size());
|
||||
|
@ -31,7 +35,7 @@ namespace llarp::quic
|
|||
expiry_timer->on<uvw::TimerEvent>([this](const auto&, auto&) { check_timeouts(); });
|
||||
expiry_timer->start(250ms, 250ms);
|
||||
|
||||
LogDebug("Created QUIC endpoint");
|
||||
log::debug(logcat, "Created QUIC endpoint");
|
||||
}
|
||||
|
||||
Endpoint::~Endpoint()
|
||||
|
@ -48,49 +52,60 @@ namespace llarp::quic
|
|||
return loop;
|
||||
}
|
||||
|
||||
// TODO: does the lookup need to be done every single packet?
|
||||
// revisit this during libQUICinet
|
||||
// Endpoint::receive_packet(const SockAddr& src, uint8_t ecn, bstring_view data)
|
||||
void
|
||||
Endpoint::receive_packet(const SockAddr& src, uint8_t ecn, bstring_view data)
|
||||
Endpoint::receive_packet(Address remote, uint8_t ecn, bstring_view data)
|
||||
{
|
||||
// ngtcp2 wants a local address but we don't necessarily have something so just set it to
|
||||
// IPv4 or IPv6 "unspecified" address (0.0.0.0 or ::)
|
||||
SockAddr local = src.isIPv6() ? SockAddr{in6addr_any} : SockAddr{nuint32_t{INADDR_ANY}};
|
||||
// SockAddr local = src.isIPv6() ? SockAddr{in6addr_any} : SockAddr{nuint32_t{INADDR_ANY}};
|
||||
|
||||
Packet pkt{Path{local, src}, data, ngtcp2_pkt_info{.ecn = ecn}};
|
||||
Packet pkt{
|
||||
Path{Address{SockAddr{"::1"sv, huint16_t{0}}, std::nullopt}, remote},
|
||||
data,
|
||||
ngtcp2_pkt_info{.ecn = ecn}};
|
||||
|
||||
LogTrace("[", pkt.path, ",ecn=", pkt.info.ecn, "]: received ", data.size(), " bytes");
|
||||
log::trace(logcat, "[{},ecn={}]: received {} bytes", pkt.path, pkt.info.ecn, data.size());
|
||||
|
||||
handle_packet(pkt);
|
||||
|
||||
LogTrace("Done handling packet");
|
||||
log::debug(logcat, "Done handling packet");
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::handle_packet(const Packet& p)
|
||||
{
|
||||
LogTrace("Handling incoming quic packet: ", buffer_printer{p.data});
|
||||
auto maybe_dcid = handle_packet_init(p);
|
||||
if (!maybe_dcid)
|
||||
{
|
||||
log::debug(logcat, "Handle packet init failed");
|
||||
return;
|
||||
}
|
||||
auto& dcid = *maybe_dcid;
|
||||
|
||||
// See if we have an existing connection already established for it
|
||||
LogTrace("Incoming connection id ", dcid);
|
||||
log::trace(logcat, "Incoming connection id {}", dcid);
|
||||
auto [connptr, alias] = get_conn(dcid);
|
||||
if (!connptr)
|
||||
{
|
||||
if (alias)
|
||||
{
|
||||
LogDebug("Incoming packet QUIC CID is an expired alias; dropping");
|
||||
log::debug(logcat, "Incoming packet QUIC CID is an expired alias; dropping");
|
||||
return;
|
||||
}
|
||||
connptr = accept_initial_connection(p);
|
||||
if (!connptr)
|
||||
{
|
||||
log::warning(logcat, "Connection could not be created");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (alias)
|
||||
LogTrace("CID is alias for primary CID ", connptr->base_cid);
|
||||
log::debug(logcat, "CID is alias for primary CID {}", connptr->base_cid);
|
||||
else
|
||||
LogTrace("CID is primary CID");
|
||||
log::debug(logcat, "CID is primary CID");
|
||||
|
||||
handle_conn_packet(*connptr, p);
|
||||
}
|
||||
|
@ -98,47 +113,40 @@ namespace llarp::quic
|
|||
std::optional<ConnectionID>
|
||||
Endpoint::handle_packet_init(const Packet& p)
|
||||
{
|
||||
version_info vi;
|
||||
auto rv = ngtcp2_pkt_decode_version_cid(
|
||||
&vi.version,
|
||||
&vi.dcid,
|
||||
&vi.dcid_len,
|
||||
&vi.scid,
|
||||
&vi.scid_len,
|
||||
u8data(p.data),
|
||||
p.data.size(),
|
||||
NGTCP2_MAX_CIDLEN);
|
||||
if (rv == 1)
|
||||
{ // 1 means Version Negotiation should be sent and otherwise the packet should be ignored
|
||||
ngtcp2_version_cid vi;
|
||||
auto rv = ngtcp2_pkt_decode_version_cid(&vi, u8data(p.data), p.data.size(), NGTCP2_MAX_CIDLEN);
|
||||
if (rv == NGTCP2_ERR_VERSION_NEGOTIATION)
|
||||
{ // Version Negotiation should be sent and otherwise the packet should be ignored
|
||||
send_version_negotiation(vi, p.path.remote);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (rv != 0)
|
||||
{
|
||||
LogWarn("QUIC packet header decode failed: ", ngtcp2_strerror(rv));
|
||||
log::warning(logcat, "QUIC packet header decode failed: {}", ngtcp2_strerror(rv));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (vi.dcid_len > ConnectionID::max_size())
|
||||
if (vi.dcidlen > ConnectionID::max_size())
|
||||
{
|
||||
LogWarn("Internal error: destination ID is longer than should be allowed");
|
||||
log::warning(logcat, "Internal error: destination ID is longer than should be allowed");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::make_optional<ConnectionID>(vi.dcid, vi.dcid_len);
|
||||
return std::make_optional<ConnectionID>(vi.dcid, vi.dcidlen);
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::handle_conn_packet(Connection& conn, const Packet& p)
|
||||
{
|
||||
if (ngtcp2_conn_is_in_closing_period(conn))
|
||||
{
|
||||
LogDebug("Connection is in closing period, dropping");
|
||||
log::debug(logcat, "Connection is in closing period, dropping");
|
||||
close_connection(conn);
|
||||
return;
|
||||
}
|
||||
if (conn.draining)
|
||||
{
|
||||
LogDebug("Connection is draining, dropping");
|
||||
log::debug(logcat, "Connection is draining, dropping");
|
||||
// "draining" state means we received a connection close and we're keeping the
|
||||
// connection alive just to catch (and discard) straggling packets that arrive
|
||||
// out of order w.r.t to connection close.
|
||||
|
@ -147,29 +155,52 @@ namespace llarp::quic
|
|||
|
||||
if (auto result = read_packet(p, conn); !result)
|
||||
{
|
||||
LogWarn("Read packet failed! ", ngtcp2_strerror(result.error_code));
|
||||
log::warning(logcat, "Read packet failed! {}", ngtcp2_strerror(result.error_code));
|
||||
log::debug(logcat, "Packet: {}", buffer_printer{p.data});
|
||||
}
|
||||
|
||||
// FIXME - reset idle timer?
|
||||
LogTrace("Done with incoming packet");
|
||||
log::trace(logcat, "Done with incoming packet");
|
||||
}
|
||||
|
||||
io_result
|
||||
Endpoint::read_packet(const Packet& p, Connection& conn)
|
||||
{
|
||||
LogTrace("Reading packet from ", p.path);
|
||||
auto rv =
|
||||
ngtcp2_conn_read_pkt(conn, p.path, &p.info, u8data(p.data), p.data.size(), get_timestamp());
|
||||
|
||||
if (rv == 0)
|
||||
conn.io_ready();
|
||||
else
|
||||
LogWarn("read pkt error: ", ngtcp2_strerror(rv));
|
||||
|
||||
if (rv == NGTCP2_ERR_DRAINING)
|
||||
else if (rv == NGTCP2_ERR_DRAINING)
|
||||
{
|
||||
log::debug(logcat, "Draining connection {}", conn.base_cid);
|
||||
start_draining(conn);
|
||||
else if (rv == NGTCP2_ERR_DROP_CONN)
|
||||
}
|
||||
else if (rv == NGTCP2_ERR_PROTO)
|
||||
{
|
||||
log::warning(
|
||||
logcat,
|
||||
"Immediately closing connection {} due to error {}",
|
||||
conn.base_cid,
|
||||
ngtcp2_strerror(rv));
|
||||
close_connection(conn, rv, "ERR_PROTO"sv);
|
||||
}
|
||||
else if (rv == NGTCP2_ERR_DROP_CONN) // drop connection w/o calling
|
||||
// ngtcp2_conn_write_connection_close()
|
||||
{
|
||||
log::warning(
|
||||
logcat, "Deleting connection {} due to error {}", conn.base_cid, ngtcp2_strerror(rv));
|
||||
delete_conn(conn.base_cid);
|
||||
}
|
||||
else
|
||||
{
|
||||
log::warning(
|
||||
logcat,
|
||||
"Immediately closing connection {} due to error {}",
|
||||
conn.base_cid,
|
||||
ngtcp2_strerror(rv));
|
||||
close_connection(conn, rv, ngtcp2_strerror(rv));
|
||||
}
|
||||
|
||||
return {rv};
|
||||
}
|
||||
|
@ -186,19 +217,24 @@ namespace llarp::quic
|
|||
bstring_view outgoing{buf_.data(), outgoing_len};
|
||||
|
||||
if (service_endpoint.SendToOrQueue(
|
||||
to, llarp_buffer_t{outgoing.data(), outgoing.size()}, service::ProtocolType::QUIC))
|
||||
*to.endpoint,
|
||||
llarp_buffer_t{outgoing.data(), outgoing.size()},
|
||||
service::ProtocolType::QUIC))
|
||||
{
|
||||
LogTrace("[", to, "]: sent ", buffer_printer{outgoing});
|
||||
log::trace(logcat, "[{}]: sent {}", to, buffer_printer{outgoing});
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug("Failed to send to quic endpoint ", to, "; was sending ", outgoing.size(), "B");
|
||||
log::warning(
|
||||
logcat, "Failed to send to quic endpoint {}; was sending {}B", to, outgoing.size());
|
||||
return io_result{-1};
|
||||
}
|
||||
return {};
|
||||
|
||||
return io_result{0};
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::send_version_negotiation(const version_info& vi, const Address& source)
|
||||
Endpoint::send_version_negotiation(const ngtcp2_version_cid& vi, const Address& source)
|
||||
{
|
||||
std::array<std::byte, Endpoint::max_pkt_size_v4> buf;
|
||||
std::array<uint32_t, NGTCP2_PROTO_VER_MAX - NGTCP2_PROTO_VER_MIN + 2> versions;
|
||||
|
@ -212,65 +248,85 @@ namespace llarp::quic
|
|||
buf.size(),
|
||||
std::uniform_int_distribution<uint8_t>{0, 255}(rng),
|
||||
vi.dcid,
|
||||
vi.dcid_len,
|
||||
vi.dcidlen,
|
||||
vi.scid,
|
||||
vi.scid_len,
|
||||
vi.scidlen,
|
||||
versions.data(),
|
||||
versions.size());
|
||||
if (nwrote < 0)
|
||||
LogWarn("Failed to construct version negotiation packet: ", ngtcp2_strerror(nwrote));
|
||||
log::warning(
|
||||
logcat, "Failed to construct version negotiation packet: {}", ngtcp2_strerror(nwrote));
|
||||
if (nwrote <= 0)
|
||||
return;
|
||||
|
||||
send_packet(source, bstring_view{buf.data(), static_cast<size_t>(nwrote)}, 0);
|
||||
if (auto rv = send_packet(source, bstring_view{buf.data(), static_cast<size_t>(nwrote)}, 0);
|
||||
not rv)
|
||||
log::warning(logcat, "Failed to send version negotiation packet");
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::close_connection(
|
||||
Connection& conn, uint64_t code, bool application, std::string_view close_reason)
|
||||
Endpoint::close_connection(Connection& conn, int code, std::string_view close_reason)
|
||||
{
|
||||
LogDebug("Closing connection ", conn.base_cid);
|
||||
if (!conn.closing)
|
||||
log::debug(logcat, "Closing connection {}", conn.base_cid);
|
||||
|
||||
if (!conn || conn.closing || conn.draining)
|
||||
return;
|
||||
|
||||
if (code == NGTCP2_ERR_IDLE_CLOSE)
|
||||
{
|
||||
conn.conn_buffer.resize(max_pkt_size_v4);
|
||||
Path path;
|
||||
ngtcp2_pkt_info pi;
|
||||
|
||||
auto write_close_func = application ? ngtcp2_conn_write_application_close_versioned
|
||||
: ngtcp2_conn_write_connection_close_versioned;
|
||||
|
||||
auto written = write_close_func(
|
||||
conn,
|
||||
path,
|
||||
NGTCP2_PKT_INFO_VERSION,
|
||||
&pi,
|
||||
u8data(conn.conn_buffer),
|
||||
conn.conn_buffer.size(),
|
||||
code,
|
||||
reinterpret_cast<const uint8_t*>(close_reason.data()),
|
||||
close_reason.size(),
|
||||
get_timestamp());
|
||||
if (written <= 0)
|
||||
{
|
||||
LogWarn(
|
||||
"Failed to write connection close packet: ",
|
||||
written < 0 ? ngtcp2_strerror(written) : "unknown error: closing is 0 bytes??");
|
||||
return;
|
||||
}
|
||||
assert(written <= (long)conn.conn_buffer.size());
|
||||
conn.conn_buffer.resize(written);
|
||||
conn.closing = true;
|
||||
|
||||
conn.path = path;
|
||||
log::warning(logcat, "Connection {} passed idle expiry timer, closing now", conn.base_cid);
|
||||
delete_conn(conn.base_cid);
|
||||
return;
|
||||
}
|
||||
|
||||
// "The error not specifically mentioned, including NGTCP2_ERR_HANDSHAKE_TIMEOUT,
|
||||
// should be dealt with by calling ngtcp2_conn_write_connection_close."
|
||||
// https://github.com/ngtcp2/ngtcp2/issues/670#issuecomment-1417300346
|
||||
if (code == NGTCP2_ERR_HANDSHAKE_TIMEOUT)
|
||||
{
|
||||
log::warning(logcat, "Connection {} handshake timed out, closing now", conn.base_cid);
|
||||
}
|
||||
|
||||
ngtcp2_connection_close_error err;
|
||||
ngtcp2_connection_close_error_set_transport_error_liberr(
|
||||
&err,
|
||||
code,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(close_reason.data())),
|
||||
close_reason.size());
|
||||
|
||||
conn.conn_buffer.resize(max_pkt_size_v4);
|
||||
ngtcp2_pkt_info pi;
|
||||
|
||||
auto written = ngtcp2_conn_write_connection_close(
|
||||
conn,
|
||||
&conn.path.path,
|
||||
&pi,
|
||||
u8data(conn.conn_buffer),
|
||||
conn.conn_buffer.size(),
|
||||
&err,
|
||||
get_timestamp());
|
||||
if (written <= 0)
|
||||
{
|
||||
log::warning(
|
||||
logcat,
|
||||
"Failed to write connection close packet: {}",
|
||||
written < 0 ? ngtcp2_strerror(written) : "unknown error: closing is 0 bytes??");
|
||||
log::warning(logcat, "Failed to write packet: removing connection {}", conn.base_cid);
|
||||
delete_conn(conn.base_cid);
|
||||
return;
|
||||
}
|
||||
assert(written <= (long)conn.conn_buffer.size());
|
||||
conn.conn_buffer.resize(written);
|
||||
conn.closing = true;
|
||||
|
||||
assert(conn.closing && !conn.conn_buffer.empty());
|
||||
|
||||
if (auto sent = send_packet(conn.path.remote, conn.conn_buffer, 0); not sent)
|
||||
{
|
||||
LogWarn(
|
||||
"Failed to send packet: ",
|
||||
log::warning(
|
||||
logcat,
|
||||
"Failed to send packet: {}; removing connection {}",
|
||||
strerror(sent.error_code),
|
||||
"; removing connection ",
|
||||
conn.base_cid);
|
||||
delete_conn(conn.base_cid);
|
||||
return;
|
||||
|
@ -285,7 +341,13 @@ namespace llarp::quic
|
|||
{
|
||||
if (conn.draining)
|
||||
return;
|
||||
LogDebug("Putting ", conn.base_cid, " into draining mode");
|
||||
if (conn.on_closing)
|
||||
{
|
||||
log::trace(logcat, "Calling Connection.on_closing for connection {}", conn.base_cid);
|
||||
conn.on_closing(conn); // only call once
|
||||
conn.on_closing = nullptr;
|
||||
}
|
||||
log::debug(logcat, "Putting {} into draining mode", conn.base_cid);
|
||||
conn.draining = true;
|
||||
// Recommended draining time is 3*Probe Timeout
|
||||
draining.emplace(conn.base_cid, get_time() + ngtcp2_conn_get_pto(conn) * 3 * 1ns);
|
||||
|
@ -295,7 +357,6 @@ namespace llarp::quic
|
|||
Endpoint::check_timeouts()
|
||||
{
|
||||
auto now = get_time();
|
||||
uint64_t now_ts = get_timestamp(now);
|
||||
|
||||
// Destroy any connections that are finished draining
|
||||
bool cleanup = false;
|
||||
|
@ -305,25 +366,14 @@ namespace llarp::quic
|
|||
{
|
||||
if (std::holds_alternative<primary_conn_ptr>(it->second))
|
||||
cleanup = true;
|
||||
LogDebug("Deleting connection ", it->first);
|
||||
log::debug(logcat, "Deleting connection {}", it->first);
|
||||
conns.erase(it);
|
||||
}
|
||||
draining.pop();
|
||||
}
|
||||
|
||||
if (cleanup)
|
||||
clean_alias_conns();
|
||||
|
||||
for (auto it = conns.begin(); it != conns.end(); ++it)
|
||||
{
|
||||
if (auto* conn_ptr = std::get_if<primary_conn_ptr>(&it->second))
|
||||
{
|
||||
Connection& conn = **conn_ptr;
|
||||
auto exp = ngtcp2_conn_get_idle_expiry(conn);
|
||||
if (exp >= now_ts || conn.draining)
|
||||
continue;
|
||||
start_draining(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<std::shared_ptr<Connection>, bool>
|
||||
|
@ -344,15 +394,27 @@ namespace llarp::quic
|
|||
auto it = conns.find(cid);
|
||||
if (it == conns.end())
|
||||
{
|
||||
LogDebug("Cannot delete connection ", cid, ": cid not found");
|
||||
log::debug(logcat, "Cannot delete connection {}: cid not found", cid);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool primary = std::holds_alternative<primary_conn_ptr>(it->second);
|
||||
LogDebug("Deleting ", primary ? "primary" : "alias", " connection ", cid);
|
||||
if (primary)
|
||||
{
|
||||
auto ptr = var::get<primary_conn_ptr>(it->second);
|
||||
if (ptr->on_closing)
|
||||
{
|
||||
log::trace(logcat, "Calling Connection.on_closing for connection {}", cid);
|
||||
ptr->on_closing(*ptr); // only call once
|
||||
ptr->on_closing = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
log::debug(logcat, "Deleting {} connection {}", primary ? "primary" : "alias", cid);
|
||||
conns.erase(it);
|
||||
if (primary)
|
||||
clean_alias_conns();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -378,7 +440,7 @@ namespace llarp::quic
|
|||
cid = ConnectionID::random(cid_length);
|
||||
inserted = conns.emplace(cid, conn.weak_from_this()).second;
|
||||
}
|
||||
LogDebug("Created cid ", cid, " alias for ", conn.base_cid);
|
||||
log::debug(logcat, "Created cid {} alias for {}", cid, conn.base_cid);
|
||||
return cid;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace llarp::quic
|
|||
/// address based on the convo tag. The port is not used.
|
||||
/// \param ecn - the packet ecn parameter
|
||||
void
|
||||
receive_packet(const SockAddr& src, uint8_t ecn, bstring_view data);
|
||||
receive_packet(Address addr, uint8_t ecn, bstring_view data);
|
||||
|
||||
/// Returns a shared pointer to the uvw loop.
|
||||
std::shared_ptr<uvw::Loop>
|
||||
|
@ -109,16 +109,6 @@ namespace llarp::quic
|
|||
|
||||
virtual ~Endpoint();
|
||||
|
||||
// Version & connection id info that we can potentially extract when decoding a packet
|
||||
struct version_info
|
||||
{
|
||||
uint32_t version;
|
||||
const uint8_t* dcid;
|
||||
size_t dcid_len;
|
||||
const uint8_t* scid;
|
||||
size_t scid_len;
|
||||
};
|
||||
|
||||
// Called to handle an incoming packet
|
||||
void
|
||||
handle_packet(const Packet& p);
|
||||
|
@ -185,7 +175,7 @@ namespace llarp::quic
|
|||
}
|
||||
|
||||
void
|
||||
send_version_negotiation(const version_info& vi, const Address& source);
|
||||
send_version_negotiation(const ngtcp2_version_cid& vi, const Address& source);
|
||||
|
||||
// Looks up a connection. Returns a shared_ptr (either copied for a primary connection, or
|
||||
// locked from an alias's weak pointer) if the connection was found or nullptr if not; and a
|
||||
|
@ -206,10 +196,7 @@ namespace llarp::quic
|
|||
// values.
|
||||
void
|
||||
close_connection(
|
||||
Connection& conn,
|
||||
uint64_t code = NGTCP2_NO_ERROR,
|
||||
bool application = false,
|
||||
std::string_view close_reason = ""sv);
|
||||
Connection& conn, int code = NGTCP2_NO_ERROR, std::string_view close_reason = ""sv);
|
||||
|
||||
/// Puts a connection into draining mode (i.e. after getting a connection close). This will
|
||||
/// keep the connection registered for the recommended 3*Probe Timeout, during which we drop
|
||||
|
@ -220,7 +207,7 @@ namespace llarp::quic
|
|||
void
|
||||
check_timeouts();
|
||||
|
||||
/// Deletes a connection from `conns`; if the connecion is a primary connection shared pointer
|
||||
/// Deletes a connection from `conns`; if the connection is a primary connection shared pointer
|
||||
/// then it is removed and clean_alias_conns() is immediately called to remove any aliases to
|
||||
/// the connection. If the given connection is an alias connection then it is removed but no
|
||||
/// cleanup is performed. Returns true if something was removed, false if the connection was
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
|
||||
namespace llarp::quic
|
||||
{
|
||||
// Cranks a value to "11", i.e. set it to its maximum
|
||||
static auto logcat = log::Cat("quic");
|
||||
|
||||
// "It's one louder, init?"
|
||||
// "Why not make '10' higher?"
|
||||
// "...These go to 11"
|
||||
template <typename T>
|
||||
void
|
||||
crank_to_eleven(T& val)
|
||||
|
@ -22,10 +26,11 @@ namespace llarp::quic
|
|||
}
|
||||
|
||||
void
|
||||
NullCrypto::client_initial(Connection& conn)
|
||||
NullCrypto::client_initial(ngtcp2_conn* conn)
|
||||
{
|
||||
log::debug(logcat, "Client initial null crypto setup");
|
||||
ngtcp2_conn_set_initial_crypto_ctx(conn, &null_ctx);
|
||||
ngtcp2_conn_install_initial_key(
|
||||
int rv = ngtcp2_conn_install_initial_key(
|
||||
conn,
|
||||
&null_aead_ctx,
|
||||
null_iv.data(),
|
||||
|
@ -34,16 +39,20 @@ namespace llarp::quic
|
|||
null_iv.data(),
|
||||
&null_cipher_ctx,
|
||||
null_iv.size());
|
||||
|
||||
if (rv != 0)
|
||||
log::debug(logcat, "Call to ngtcp2_conn_set_initial_crypto_ctx unsuccessful at {}", __LINE__);
|
||||
|
||||
ngtcp2_conn_set_retry_aead(conn, &null_aead, &null_aead_ctx);
|
||||
ngtcp2_conn_set_crypto_ctx(conn, &null_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
NullCrypto::server_initial(Connection& conn)
|
||||
NullCrypto::server_initial(ngtcp2_conn* conn)
|
||||
{
|
||||
LogDebug("Server initial null crypto setup");
|
||||
log::debug(logcat, "Server initial null crypto setup");
|
||||
ngtcp2_conn_set_initial_crypto_ctx(conn, &null_ctx);
|
||||
ngtcp2_conn_install_initial_key(
|
||||
int rv = ngtcp2_conn_install_initial_key(
|
||||
conn,
|
||||
&null_aead_ctx,
|
||||
null_iv.data(),
|
||||
|
@ -52,26 +61,33 @@ namespace llarp::quic
|
|||
null_iv.data(),
|
||||
&null_cipher_ctx,
|
||||
null_iv.size());
|
||||
|
||||
if (rv != 0)
|
||||
log::debug(logcat, "Call to ngtcp2_conn_set_initial_crypto_ctx unsuccessful at {}", __LINE__);
|
||||
|
||||
ngtcp2_conn_set_crypto_ctx(conn, &null_ctx);
|
||||
}
|
||||
|
||||
bool
|
||||
NullCrypto::install_tx_handshake_key(Connection& conn)
|
||||
NullCrypto::install_tx_handshake_key(ngtcp2_conn* conn)
|
||||
{
|
||||
log::debug(logcat, "Calling {}", __PRETTY_FUNCTION__);
|
||||
return ngtcp2_conn_install_tx_handshake_key(
|
||||
conn, &null_aead_ctx, null_iv.data(), null_iv.size(), &null_cipher_ctx)
|
||||
== 0;
|
||||
}
|
||||
bool
|
||||
NullCrypto::install_rx_handshake_key(Connection& conn)
|
||||
NullCrypto::install_rx_handshake_key(ngtcp2_conn* conn)
|
||||
{
|
||||
log::debug(logcat, "Calling {}", __PRETTY_FUNCTION__);
|
||||
return ngtcp2_conn_install_rx_handshake_key(
|
||||
conn, &null_aead_ctx, null_iv.data(), null_iv.size(), &null_cipher_ctx)
|
||||
== 0;
|
||||
}
|
||||
bool
|
||||
NullCrypto::install_tx_key(Connection& conn)
|
||||
NullCrypto::install_tx_key(ngtcp2_conn* conn)
|
||||
{
|
||||
log::debug(logcat, "Calling {}", __PRETTY_FUNCTION__);
|
||||
return ngtcp2_conn_install_tx_key(
|
||||
conn,
|
||||
null_iv.data(),
|
||||
|
@ -83,8 +99,9 @@ namespace llarp::quic
|
|||
== 0;
|
||||
}
|
||||
bool
|
||||
NullCrypto::install_rx_key(Connection& conn)
|
||||
NullCrypto::install_rx_key(ngtcp2_conn* conn)
|
||||
{
|
||||
log::debug(logcat, "Calling {}", __PRETTY_FUNCTION__);
|
||||
return ngtcp2_conn_install_rx_key(
|
||||
conn, nullptr, 0, &null_aead_ctx, null_iv.data(), null_iv.size(), &null_cipher_ctx)
|
||||
== 0;
|
||||
|
|
|
@ -16,20 +16,20 @@ namespace llarp::quic
|
|||
NullCrypto();
|
||||
|
||||
void
|
||||
client_initial(Connection& conn);
|
||||
client_initial(ngtcp2_conn* conn);
|
||||
|
||||
void
|
||||
server_initial(Connection& conn);
|
||||
server_initial(ngtcp2_conn* conn);
|
||||
|
||||
bool
|
||||
install_tx_handshake_key(Connection& conn);
|
||||
install_tx_handshake_key(ngtcp2_conn* conn);
|
||||
bool
|
||||
install_tx_key(Connection& conn);
|
||||
install_tx_key(ngtcp2_conn* conn);
|
||||
|
||||
bool
|
||||
install_rx_handshake_key(Connection& conn);
|
||||
install_rx_handshake_key(ngtcp2_conn* conn);
|
||||
bool
|
||||
install_rx_key(Connection& conn);
|
||||
install_rx_key(ngtcp2_conn* conn);
|
||||
|
||||
private:
|
||||
std::array<uint8_t, 8> null_iv{};
|
||||
|
|
|
@ -11,41 +11,45 @@
|
|||
|
||||
namespace llarp::quic
|
||||
{
|
||||
static auto logcat = log::Cat("quic");
|
||||
|
||||
std::shared_ptr<Connection>
|
||||
Server::accept_initial_connection(const Packet& p)
|
||||
{
|
||||
LogDebug("Accepting new connection");
|
||||
log::debug(logcat, "Accepting new connection");
|
||||
|
||||
// This is a new incoming connection
|
||||
ngtcp2_pkt_hd hd;
|
||||
auto rv = ngtcp2_accept(&hd, u8data(p.data), p.data.size());
|
||||
|
||||
if (rv == -1)
|
||||
{ // Invalid packet
|
||||
LogWarn("Invalid packet received, length=", p.data.size());
|
||||
LogTrace("packet body: ", buffer_printer{p.data});
|
||||
if (rv == NGTCP2_ERR_VERSION_NEGOTIATION)
|
||||
{ // Invalid/unexpected version, send a version negotiation
|
||||
log::debug(logcat, "Invalid/unsupported version; sending version negotiation");
|
||||
send_version_negotiation(
|
||||
ngtcp2_version_cid{
|
||||
hd.version, hd.dcid.data, hd.dcid.datalen, hd.scid.data, hd.scid.datalen},
|
||||
p.path.remote);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (rv == 1)
|
||||
{ // Invalid/unexpected version, send a version negotiation
|
||||
LogDebug("Invalid/unsupported version; sending version negotiation");
|
||||
send_version_negotiation(
|
||||
version_info{hd.version, hd.dcid.data, hd.dcid.datalen, hd.scid.data, hd.scid.datalen},
|
||||
p.path.remote);
|
||||
else if (rv < 0)
|
||||
{ // Invalid packet. rv could be NGTCP2_ERR_RETRY but that will only
|
||||
// happen if the incoming packet is 0RTT which we don't use.
|
||||
log::warning(logcat, "Invalid packet received, length={}", p.data.size());
|
||||
log::trace(logcat, "packet body: {}", buffer_printer{p.data});
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (hd.type == NGTCP2_PKT_0RTT)
|
||||
{
|
||||
LogWarn("Received 0-RTT packet, which shouldn't happen in our implementation; dropping");
|
||||
log::warning(
|
||||
logcat, "Received 0-RTT packet, which shouldn't happen in our implementation; dropping");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (hd.type == NGTCP2_PKT_INITIAL && hd.token.len)
|
||||
{
|
||||
// This is a normal QUIC thing, but we don't do it:
|
||||
LogWarn("Unexpected token in initial packet");
|
||||
log::warning(logcat, "Unexpected token in initial packet");
|
||||
}
|
||||
|
||||
// create and store Connection
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "stream.hpp"
|
||||
#include "connection.hpp"
|
||||
#include "endpoint.hpp"
|
||||
#include "llarp/util/logging/buffer.hpp"
|
||||
#include <llarp/util/logging.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
@ -43,6 +44,8 @@
|
|||
|
||||
namespace llarp::quic
|
||||
{
|
||||
static auto logcat = log::Cat("quic");
|
||||
|
||||
std::string
|
||||
StreamID::ToString() const
|
||||
{
|
||||
|
@ -71,7 +74,7 @@ namespace llarp::quic
|
|||
|
||||
Stream::~Stream()
|
||||
{
|
||||
LogTrace("Destroying stream ", stream_id);
|
||||
log::trace(logcat, "Destroying stream {}", stream_id);
|
||||
if (avail_trigger)
|
||||
{
|
||||
avail_trigger->close();
|
||||
|
@ -124,26 +127,24 @@ namespace llarp::quic
|
|||
auto data_split = data.begin() + (buffer.size() - wpos);
|
||||
std::copy(data.begin(), data_split, buffer.begin() + wpos);
|
||||
std::copy(data_split, data.end(), buffer.begin());
|
||||
LogTrace(
|
||||
"Wrote ",
|
||||
log::trace(
|
||||
logcat,
|
||||
"Wrote {} bytes to buffer ranges [{},)+[0,{})",
|
||||
data.size(),
|
||||
" bytes to buffer ranges [",
|
||||
wpos,
|
||||
",",
|
||||
buffer.size(),
|
||||
")+[0,",
|
||||
data.end() - data_split,
|
||||
")");
|
||||
data.end() - data_split);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No wrap needs, it fits before the end:
|
||||
std::copy(data.begin(), data.end(), buffer.begin() + wpos);
|
||||
LogTrace(
|
||||
"Wrote ", data.size(), " bytes to buffer range [", wpos, ",", wpos + data.size(), ")");
|
||||
log::trace(
|
||||
logcat, "Wrote {} bytes to buffer range [{},{})", data.size(), wpos, wpos + data.size());
|
||||
}
|
||||
size += data.size();
|
||||
LogTrace("New stream buffer: ", size, "/", buffer.size(), " bytes beginning at ", start);
|
||||
log::trace(
|
||||
logcat, "New stream buffer: {}/{} bytes beginning at {}", size, buffer.size(), start);
|
||||
conn.io_ready();
|
||||
return true;
|
||||
}
|
||||
|
@ -161,6 +162,7 @@ namespace llarp::quic
|
|||
Stream::append_buffer(const std::byte* buffer, size_t length)
|
||||
{
|
||||
assert(this->buffer.empty());
|
||||
log::debug(logcat, "buffer: {}", buffer_printer{buffer, length});
|
||||
user_buffers.emplace_back(buffer, length);
|
||||
size += length;
|
||||
conn.io_ready();
|
||||
|
@ -177,7 +179,7 @@ namespace llarp::quic
|
|||
//
|
||||
assert(bytes <= unacked_size && unacked_size <= size);
|
||||
|
||||
LogTrace("Acked ", bytes, " bytes of ", unacked_size, "/", size, " unacked/total");
|
||||
log::debug(logcat, "Acked {} bytes of {}/{} unacked/total", bytes, unacked_size, size);
|
||||
|
||||
unacked_size -= bytes;
|
||||
size -= bytes;
|
||||
|
@ -308,7 +310,7 @@ namespace llarp::quic
|
|||
// [ áaarrrrrr ] or [rr áaar]
|
||||
// to:
|
||||
// [ áaaaaarrr ] or [aa áaaa]
|
||||
LogTrace("wrote ", bytes, ", unsent=", unsent());
|
||||
log::debug(logcat, "wrote {}, unsent={}", bytes, unsent());
|
||||
assert(bytes <= unsent());
|
||||
unacked_size += bytes;
|
||||
}
|
||||
|
@ -316,20 +318,21 @@ namespace llarp::quic
|
|||
void
|
||||
Stream::close(std::optional<uint64_t> error_code)
|
||||
{
|
||||
LogDebug(
|
||||
"Closing ",
|
||||
log::debug(
|
||||
logcat,
|
||||
"Closing {} {}",
|
||||
stream_id,
|
||||
error_code ? " immediately with code " + std::to_string(*error_code) : " gracefully");
|
||||
|
||||
if (is_shutdown)
|
||||
LogDebug("Stream is already shutting down");
|
||||
else if (error_code)
|
||||
log::debug(logcat, "Stream is already shutting down");
|
||||
else if (error_code && *error_code != 0)
|
||||
{
|
||||
is_closing = is_shutdown = true;
|
||||
ngtcp2_conn_shutdown_stream(conn, stream_id.id, *error_code);
|
||||
}
|
||||
else if (is_closing)
|
||||
LogDebug("Stream is already closing");
|
||||
log::debug(logcat, "Stream is already closing");
|
||||
else
|
||||
is_closing = true;
|
||||
|
||||
|
|
|
@ -201,6 +201,20 @@ namespace llarp::quic
|
|||
return is_closing;
|
||||
}
|
||||
|
||||
// Informs the stream that TCP EOF has been received on this end
|
||||
void
|
||||
set_eof()
|
||||
{
|
||||
tcp_eof = true;
|
||||
}
|
||||
|
||||
// Returns true of the TCP connection on this end gave us EOF
|
||||
bool
|
||||
has_eof()
|
||||
{
|
||||
return tcp_eof;
|
||||
}
|
||||
|
||||
// Callback invoked when data is received
|
||||
using data_callback_t = std::function<void(Stream&, bstring_view)>;
|
||||
|
||||
|
@ -357,6 +371,7 @@ namespace llarp::quic
|
|||
bool is_closing{false};
|
||||
bool sent_fin{false};
|
||||
bool is_shutdown{false};
|
||||
bool tcp_eof{false};
|
||||
|
||||
// Async trigger we use to schedule when_available callbacks (so that we can make them happen in
|
||||
// batches rather than after each and every packet ack).
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <llarp/service/convotag.hpp>
|
||||
#include <llarp/service/endpoint.hpp>
|
||||
#include <llarp/service/name.hpp>
|
||||
#include "llarp/net/net_int.hpp"
|
||||
#include "stream.hpp"
|
||||
#include <limits>
|
||||
#include <llarp/util/logging.hpp>
|
||||
|
@ -16,6 +17,8 @@ namespace llarp::quic
|
|||
{
|
||||
namespace
|
||||
{
|
||||
static auto logcat = log::Cat("quic");
|
||||
|
||||
// Takes data from the tcp connection and pushes it down the quic tunnel
|
||||
void
|
||||
on_outgoing_data(uvw::DataEvent& event, uvw::TCPHandle& client)
|
||||
|
@ -24,21 +27,24 @@ namespace llarp::quic
|
|||
assert(stream);
|
||||
std::string_view data{event.data.get(), event.length};
|
||||
auto peer = client.peer();
|
||||
LogTrace(peer.ip, ":", peer.port, " → lokinet ", buffer_printer{data});
|
||||
// log::trace(logcat, "{}:{} → lokinet {}", peer.ip, peer.port, buffer_printer{data});
|
||||
log::debug(logcat, "{}:{} → lokinet {}", peer.ip, peer.port, buffer_printer{data});
|
||||
// Steal the buffer from the DataEvent's unique_ptr<char[]>:
|
||||
stream->append_buffer(reinterpret_cast<const std::byte*>(event.data.release()), event.length);
|
||||
if (stream->used() >= tunnel::PAUSE_SIZE)
|
||||
{
|
||||
LogDebug(
|
||||
"quic tunnel is congested (have ",
|
||||
stream->used(),
|
||||
" bytes in flight); pausing local tcp connection reads");
|
||||
log::debug(
|
||||
logcat,
|
||||
"quic tunnel is congested (have {} bytes in flight); pausing local tcp connection "
|
||||
"reads",
|
||||
stream->used());
|
||||
client.stop();
|
||||
stream->when_available([](Stream& s) {
|
||||
auto client = s.data<uvw::TCPHandle>();
|
||||
if (s.used() < tunnel::PAUSE_SIZE)
|
||||
{
|
||||
LogDebug("quic tunnel is no longer congested; resuming tcp connection reading");
|
||||
log::debug(
|
||||
logcat, "quic tunnel is no longer congested; resuming tcp connection reading");
|
||||
client->read();
|
||||
return true;
|
||||
}
|
||||
|
@ -47,7 +53,7 @@ namespace llarp::quic
|
|||
}
|
||||
else
|
||||
{
|
||||
LogDebug("Queued ", event.length, " bytes");
|
||||
log::debug(logcat, "Queued {} bytes", event.length);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +68,7 @@ namespace llarp::quic
|
|||
|
||||
std::string_view data{reinterpret_cast<const char*>(bdata.data()), bdata.size()};
|
||||
auto peer = tcp->peer();
|
||||
LogTrace(peer.ip, ":", peer.port, " ← lokinet ", buffer_printer{data});
|
||||
log::trace(logcat, "{}:{} ← lokinet {}", peer.ip, peer.port, buffer_printer{data});
|
||||
|
||||
if (data.empty())
|
||||
return;
|
||||
|
@ -85,7 +91,7 @@ namespace llarp::quic
|
|||
{
|
||||
if (auto tcp = st.data<uvw::TCPHandle>())
|
||||
{
|
||||
LogTrace("Closing TCP connection");
|
||||
log::trace(logcat, "Closing TCP connection");
|
||||
tcp->close();
|
||||
}
|
||||
};
|
||||
|
@ -96,42 +102,58 @@ namespace llarp::quic
|
|||
{
|
||||
tcp.data(stream.shared_from_this());
|
||||
stream.weak_data(tcp.weak_from_this());
|
||||
auto weak_conn = stream.get_connection().weak_from_this();
|
||||
|
||||
tcp.clear(); // Clear any existing initial event handlers
|
||||
|
||||
tcp.on<uvw::CloseEvent>([](auto&, uvw::TCPHandle& c) {
|
||||
tcp.on<uvw::CloseEvent>([weak_conn = std::move(weak_conn)](auto&, uvw::TCPHandle& c) {
|
||||
// This fires sometime after we call `close()` to signal that the close is done.
|
||||
if (auto stream = c.data<Stream>())
|
||||
{
|
||||
LogInfo("Local TCP connection closed, closing associated quic stream ", stream->id());
|
||||
stream->close();
|
||||
log::info(
|
||||
logcat,
|
||||
"Local TCP connection closed, closing associated quic stream {}",
|
||||
stream->id());
|
||||
|
||||
// There is an awkwardness with Stream ownership, so make sure the Connection
|
||||
// which it holds a reference to still exists, as stream->close will segfault
|
||||
// otherwise
|
||||
if (auto locked_conn = weak_conn.lock())
|
||||
{
|
||||
// If this end of the stream closed due to an abrupt close to the local TCP
|
||||
// connection rather than an EOF, send an error code along so the other end
|
||||
// knows this end is dead. Otherwise, the streams on either end should die
|
||||
// gracefully when both ends of the TCP connection are properly closed.
|
||||
stream->close(stream->has_eof() ? 0 : tunnel::ERROR_TCP);
|
||||
}
|
||||
stream->data(nullptr);
|
||||
}
|
||||
c.data(nullptr);
|
||||
});
|
||||
tcp.on<uvw::EndEvent>([](auto&, uvw::TCPHandle& c) {
|
||||
// This fires on eof, most likely because the other side of the TCP connection closed it.
|
||||
LogInfo("EOF on connection to ", c.peer().ip, ":", c.peer().port);
|
||||
log::info(logcat, "EOF on connection to {}:{}", c.peer().ip, c.peer().port);
|
||||
if (auto stream = c.data<Stream>())
|
||||
{
|
||||
stream->set_eof(); // CloseEvent will send graceful shutdown to other end
|
||||
}
|
||||
c.close();
|
||||
});
|
||||
tcp.on<uvw::ErrorEvent>([](const uvw::ErrorEvent& e, uvw::TCPHandle& tcp) {
|
||||
LogError(
|
||||
"ErrorEvent[",
|
||||
log::error(
|
||||
logcat,
|
||||
"ErrorEvent[{}:{}] on connection with {}:{}, shutting down quic stream",
|
||||
e.name(),
|
||||
": ",
|
||||
e.what(),
|
||||
"] on connection with ",
|
||||
tcp.peer().ip,
|
||||
":",
|
||||
tcp.peer().port,
|
||||
", shutting down quic stream");
|
||||
tcp.peer().port);
|
||||
if (auto stream = tcp.data<Stream>())
|
||||
{
|
||||
stream->close(tunnel::ERROR_TCP);
|
||||
stream->data(nullptr);
|
||||
tcp.data(nullptr);
|
||||
}
|
||||
// tcp.closeReset();
|
||||
tcp.close();
|
||||
});
|
||||
tcp.on<uvw::DataEvent>(on_outgoing_data);
|
||||
stream.data_callback = on_incoming_data;
|
||||
|
@ -147,7 +169,7 @@ namespace llarp::quic
|
|||
void
|
||||
initial_client_data_handler(uvw::TCPHandle& client, Stream& stream, bstring_view bdata)
|
||||
{
|
||||
LogTrace("initial client handler; data: ", buffer_printer{bdata});
|
||||
log::trace(logcat, "initial client handler; data: {}", buffer_printer{bdata});
|
||||
if (bdata.empty())
|
||||
return;
|
||||
client.clear(); // Clear these initial event handlers: we either set up the proper ones, or
|
||||
|
@ -164,14 +186,15 @@ namespace llarp::quic
|
|||
bdata.remove_prefix(1);
|
||||
stream.data_callback(stream, std::move(bdata));
|
||||
}
|
||||
LogTrace("starting client reading");
|
||||
log::trace(logcat, "starting client reading");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWarn(
|
||||
"Remote connection returned invalid initial byte (0x",
|
||||
oxenc::to_hex(bdata.begin(), bdata.begin() + 1),
|
||||
"); dropping connection");
|
||||
log::warning(
|
||||
logcat,
|
||||
"Remote connection returned invalid initial byte (0x{}); dropping "
|
||||
"connection",
|
||||
oxenc::to_hex(bdata.begin(), bdata.begin() + 1));
|
||||
stream.close(tunnel::ERROR_BAD_INIT);
|
||||
client.close();
|
||||
}
|
||||
|
@ -187,14 +210,14 @@ namespace llarp::quic
|
|||
uvw::TCPHandle& client, Stream& /*stream*/, std::optional<uint64_t> error_code)
|
||||
{
|
||||
if (error_code && *error_code == tunnel::ERROR_CONNECT)
|
||||
LogDebug("Remote TCP connection failed, closing local connection");
|
||||
log::debug(logcat, "Remote TCP connection failed, closing local connection");
|
||||
else
|
||||
LogWarn(
|
||||
"Stream connection closed ",
|
||||
error_code ? "with error " + std::to_string(*error_code) : "gracefully",
|
||||
"; closing local TCP connection.");
|
||||
log::warning(
|
||||
logcat,
|
||||
"Stream connection closed {}; closing local TCP connection.",
|
||||
error_code ? "with error " + std::to_string(*error_code) : "gracefully");
|
||||
auto peer = client.peer();
|
||||
LogDebug("Closing connection to ", peer.ip, ":", peer.port);
|
||||
log::debug(logcat, "Closing connection to {}:{}", peer.ip, peer.port);
|
||||
client.clear();
|
||||
if (error_code)
|
||||
client.close();
|
||||
|
@ -208,7 +231,7 @@ namespace llarp::quic
|
|||
{
|
||||
// Cleanup callback to clear out closed tunnel connections
|
||||
service_endpoint_.Loop()->call_every(500ms, timer_keepalive_, [this] {
|
||||
LogTrace("Checking quic tunnels for finished connections");
|
||||
log::trace(logcat, "Checking quic tunnels for finished connections");
|
||||
for (auto ctit = client_tunnels_.begin(); ctit != client_tunnels_.end();)
|
||||
{
|
||||
// Clear any accepted connections that have been closed:
|
||||
|
@ -220,7 +243,7 @@ namespace llarp::quic
|
|||
// stop the TCP connection when the quic side gets congested.
|
||||
if (not *it or not(*it)->data())
|
||||
{
|
||||
LogDebug("Cleanup up closed outgoing tunnel on quic:", port);
|
||||
log::debug(logcat, "Cleanup up closed outgoing tunnel on quic:{}", port);
|
||||
it = ct.conns.erase(it);
|
||||
}
|
||||
else
|
||||
|
@ -231,43 +254,40 @@ namespace llarp::quic
|
|||
// destroy the whole thing.
|
||||
if (ct.conns.empty() and (not ct.tcp or not ct.tcp->active()))
|
||||
{
|
||||
LogDebug("All sockets closed on quic:", port, ", destroying tunnel data");
|
||||
log::debug(logcat, "All sockets closed on quic:{}, destroying tunnel data", port);
|
||||
if (ct.close_cb)
|
||||
ct.close_cb(0, nullptr);
|
||||
ctit = client_tunnels_.erase(ctit);
|
||||
}
|
||||
else
|
||||
++ctit;
|
||||
}
|
||||
LogTrace("Done quic tunnel cleanup check");
|
||||
log::trace(logcat, "Done quic tunnel cleanup check");
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
TunnelManager::make_server()
|
||||
{
|
||||
// auto loop = get_loop();
|
||||
|
||||
server_ = std::make_unique<Server>(service_endpoint_);
|
||||
server_->stream_open_callback = [this](Stream& stream, uint16_t port) -> bool {
|
||||
stream.close_callback = close_tcp_pair;
|
||||
|
||||
// FIXME
|
||||
auto& conn = stream.get_connection();
|
||||
auto remote = service_endpoint_.GetEndpointWithConvoTag(conn.path.remote);
|
||||
if (!remote)
|
||||
{
|
||||
LogWarn("Received new stream open from invalid/unknown convo tag, dropping stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lokinet_addr = var::visit([](auto&& remote) { return remote.ToString(); }, *remote);
|
||||
auto lokinet_addr =
|
||||
var::visit([](auto&& remote) { return remote.ToString(); }, *conn.path.remote.endpoint);
|
||||
auto tunnel_to = allow_connection(lokinet_addr, port);
|
||||
if (not tunnel_to)
|
||||
return false;
|
||||
LogInfo("quic stream from ", lokinet_addr, " to ", port, " tunnelling to ", *tunnel_to);
|
||||
log::debug(
|
||||
logcat, "quic stream from {} to {} tunnelling to {}", lokinet_addr, port, *tunnel_to);
|
||||
|
||||
auto tcp = get_loop()->resource<uvw::TCPHandle>();
|
||||
auto error_handler = tcp->once<uvw::ErrorEvent>(
|
||||
[&stream, to = *tunnel_to](const uvw::ErrorEvent&, uvw::TCPHandle&) {
|
||||
LogWarn("Failed to connect to ", to, ", shutting down quic stream");
|
||||
log::warning(logcat, "Failed to connect to {}, shutting down quic stream", to);
|
||||
stream.close(tunnel::ERROR_CONNECT);
|
||||
});
|
||||
|
||||
|
@ -281,16 +301,16 @@ namespace llarp::quic
|
|||
auto stream = streamw.lock();
|
||||
if (!stream)
|
||||
{
|
||||
LogWarn(
|
||||
"Connected to TCP ",
|
||||
log::warning(
|
||||
logcat,
|
||||
"Connected to TCP {}:{} but quic stream has gone away; close/resetting local TCP "
|
||||
"connection",
|
||||
peer.ip,
|
||||
":",
|
||||
peer.port,
|
||||
" but quic stream has gone away; close/resetting local TCP connection");
|
||||
peer.port);
|
||||
tcp.close();
|
||||
return;
|
||||
}
|
||||
LogDebug("Connected to ", peer.ip, ":", peer.port, " for quic ", stream->id());
|
||||
log::debug(logcat, "Connected to {}:{} for quic {}", peer.ip, peer.port, stream->id());
|
||||
// Set up the data stream forwarding (which also clears these initial handlers).
|
||||
install_stream_forwarding(tcp, *stream);
|
||||
assert(stream->used() == 0);
|
||||
|
@ -324,7 +344,7 @@ namespace llarp::quic
|
|||
TunnelManager::listen(SockAddr addr)
|
||||
{
|
||||
return listen([addr](std::string_view, uint16_t p) -> std::optional<SockAddr> {
|
||||
LogInfo("try accepting ", addr.getPort());
|
||||
log::info(logcat, "try accepting {}", addr.getPort());
|
||||
if (p == addr.getPort())
|
||||
return addr;
|
||||
return std::nullopt;
|
||||
|
@ -349,19 +369,20 @@ namespace llarp::quic
|
|||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LogWarn(
|
||||
"Incoming quic connection from ",
|
||||
log::warning(
|
||||
logcat,
|
||||
"Incoming quic connection from {} to {} denied via exception ({})",
|
||||
lokinet_addr,
|
||||
" to ",
|
||||
port,
|
||||
" denied via exception (",
|
||||
e.what(),
|
||||
")");
|
||||
e.what());
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
LogWarn(
|
||||
"Incoming quic connection from ", lokinet_addr, " to ", port, " declined by all handlers");
|
||||
log::warning(
|
||||
logcat,
|
||||
"Incoming quic connection from {} to {} declined by all handlers",
|
||||
lokinet_addr,
|
||||
port);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -413,15 +434,15 @@ namespace llarp::quic
|
|||
auto it = client_tunnels_.find(pseudo_port);
|
||||
if (it == client_tunnels_.end())
|
||||
{
|
||||
LogDebug("QUIC tunnel to ", addr, " closed before ", step_name, " finished");
|
||||
log::debug(logcat, "QUIC tunnel to {} closed before {} finished", addr, step_name);
|
||||
return false;
|
||||
}
|
||||
if (!step_success)
|
||||
{
|
||||
LogWarn("QUIC tunnel to ", addr, " failed during ", step_name, "; aborting tunnel");
|
||||
log::warning(logcat, "QUIC tunnel to {} failed during {}; aborting tunnel", addr, step_name);
|
||||
it->second.tcp->close();
|
||||
if (it->second.open_cb)
|
||||
it->second.open_cb(false);
|
||||
it->second.open_cb(false, nullptr);
|
||||
client_tunnels_.erase(it);
|
||||
}
|
||||
return step_success;
|
||||
|
@ -429,7 +450,11 @@ namespace llarp::quic
|
|||
|
||||
std::pair<SockAddr, uint16_t>
|
||||
TunnelManager::open(
|
||||
std::string_view remote_address, uint16_t port, OpenCallback on_open, SockAddr bind_addr)
|
||||
std::string_view remote_address,
|
||||
uint16_t port,
|
||||
OpenCallback on_open,
|
||||
CloseCallback on_close,
|
||||
SockAddr bind_addr)
|
||||
{
|
||||
std::string remote_addr = lowercase_ascii_string(std::string{remote_address});
|
||||
|
||||
|
@ -494,24 +519,26 @@ namespace llarp::quic
|
|||
"Unable to open an outgoing quic connection: too many existing connections"};
|
||||
(next_pseudo_port_ = pport)++;
|
||||
|
||||
LogInfo("Bound TCP tunnel ", saddr, " for quic client :", pport);
|
||||
log::trace(logcat, "Bound TCP tunnel {} for quic client :{}", saddr, pport);
|
||||
|
||||
// We are emplacing into client_tunnels_ here: beyond this point we must not throw until we
|
||||
// return (or if we do, make sure we remove this row from client_tunnels_ first).
|
||||
assert(client_tunnels_.count(pport) == 0);
|
||||
auto& ct = client_tunnels_[pport];
|
||||
ct.open_cb = std::move(on_open);
|
||||
ct.close_cb = std::move(on_close);
|
||||
ct.tcp = std::move(tcp_tunnel);
|
||||
// We use this pport shared_ptr value on the listening tcp socket both to hand to pport into the
|
||||
// accept handler, and to let the accept handler know that `this` is still safe to use.
|
||||
ct.tcp->data(std::make_shared<uint16_t>(pport));
|
||||
|
||||
auto after_path = [this, port, pport = pport, remote_addr](auto maybe_convo) {
|
||||
if (not continue_connecting(pport, (bool)maybe_convo, "path build", remote_addr))
|
||||
auto after_path = [this, port, pport = pport, remote_addr](auto maybe_addr) {
|
||||
if (maybe_addr)
|
||||
{
|
||||
make_client(port, *maybe_addr, *client_tunnels_.find(pport));
|
||||
return;
|
||||
SockAddr dest{maybe_convo->ToV6()};
|
||||
dest.setPort(port);
|
||||
make_client(dest, *client_tunnels_.find(pport));
|
||||
}
|
||||
continue_connecting(pport, false, "path build", remote_addr);
|
||||
};
|
||||
|
||||
if (!maybe_remote)
|
||||
|
@ -520,10 +547,8 @@ namespace llarp::quic
|
|||
// then we have to build a path to that address.
|
||||
service_endpoint_.LookupNameAsync(
|
||||
remote_addr,
|
||||
[this,
|
||||
after_path = std::move(after_path),
|
||||
pport = pport,
|
||||
remote_addr = std::move(remote_addr)](auto maybe_remote) {
|
||||
[this, after_path = std::move(after_path), pport = pport, remote_addr](
|
||||
auto maybe_remote) {
|
||||
if (not continue_connecting(
|
||||
pport, (bool)maybe_remote, "endpoint ONS lookup", remote_addr))
|
||||
return;
|
||||
|
@ -536,8 +561,9 @@ namespace llarp::quic
|
|||
auto& remote = *maybe_remote;
|
||||
|
||||
// See if we have an existing convo tag we can use to start things immediately
|
||||
if (auto maybe_convo = service_endpoint_.GetBestConvoTagFor(remote))
|
||||
after_path(maybe_convo);
|
||||
if (auto maybe_convo = service_endpoint_.GetBestConvoTagFor(remote);
|
||||
auto maybe_addr = service_endpoint_.GetEndpointWithConvoTag(*maybe_convo))
|
||||
after_path(maybe_addr);
|
||||
else
|
||||
{
|
||||
service_endpoint_.MarkAddressOutbound(remote);
|
||||
|
@ -582,18 +608,47 @@ namespace llarp::quic
|
|||
}
|
||||
|
||||
void
|
||||
TunnelManager::make_client(const SockAddr& remote, std::pair<const uint16_t, ClientTunnel>& row)
|
||||
TunnelManager::make_client(
|
||||
const uint16_t port,
|
||||
std::variant<service::Address, RouterID> remote,
|
||||
std::pair<const uint16_t, ClientTunnel>& row)
|
||||
{
|
||||
assert(remote.getPort() > 0);
|
||||
assert(port > 0);
|
||||
auto& [pport, tunnel] = row;
|
||||
assert(not tunnel.client);
|
||||
tunnel.client = std::make_unique<Client>(service_endpoint_, remote, pport);
|
||||
tunnel.client = std::make_unique<Client>(service_endpoint_, port, std::move(remote), pport);
|
||||
auto conn = tunnel.client->get_connection();
|
||||
|
||||
conn->on_stream_available = [this, id = row.first](Connection&) {
|
||||
LogDebug("QUIC connection :", id, " established; streams now available");
|
||||
log::debug(logcat, "QUIC connection :{} established; streams now available", id);
|
||||
if (auto it = client_tunnels_.find(id); it != client_tunnels_.end())
|
||||
{
|
||||
flush_pending_incoming(it->second);
|
||||
if (it->second.open_cb)
|
||||
{
|
||||
log::trace(logcat, "Calling ClientTunnel.open_cb()");
|
||||
it->second.open_cb(true, nullptr);
|
||||
it->second.open_cb = nullptr; // only call once
|
||||
}
|
||||
}
|
||||
else
|
||||
log::warning(
|
||||
logcat, "Connection.on_stream_available fired but we have no associated ClientTunnel!");
|
||||
};
|
||||
conn->on_closing = [this, id = row.first](Connection&) {
|
||||
log::debug(logcat, "QUIC connection :{} closing, closing tunnel", id);
|
||||
if (auto it = client_tunnels_.find(id); it != client_tunnels_.end())
|
||||
{
|
||||
if (it->second.close_cb)
|
||||
{
|
||||
log::trace(logcat, "Calling ClientTunnel.close_cb()");
|
||||
it->second.close_cb(0, nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
log::debug(logcat, "Connection.on_closing fired but no associated ClientTunnel found.");
|
||||
|
||||
this->close(id);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -626,21 +681,22 @@ namespace llarp::quic
|
|||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LogWarn("Opening quic stream failed: ", e.what());
|
||||
log::warning(logcat, "Opening quic stream failed: {}", e.what());
|
||||
tcp_client->close();
|
||||
}
|
||||
|
||||
LogTrace("Set up new stream");
|
||||
log::trace(logcat, "Set up new stream");
|
||||
conn.io_ready();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TunnelManager::receive_packet(const service::ConvoTag& tag, const llarp_buffer_t& buf)
|
||||
TunnelManager::receive_packet(
|
||||
std::variant<service::Address, RouterID> remote, const llarp_buffer_t& buf)
|
||||
{
|
||||
if (buf.sz <= 4)
|
||||
{
|
||||
LogWarn("invalid quic packet: packet size (", buf.sz, ") too small");
|
||||
log::warning(logcat, "invalid quic packet: packet size ({}) too small", buf.sz);
|
||||
return;
|
||||
}
|
||||
auto type = static_cast<std::byte>(buf.base[0]);
|
||||
|
@ -650,51 +706,62 @@ namespace llarp::quic
|
|||
auto ecn = static_cast<uint8_t>(buf.base[3]);
|
||||
bstring_view data{reinterpret_cast<const std::byte*>(&buf.base[4]), buf.sz - 4};
|
||||
|
||||
SockAddr remote{tag.ToV6()};
|
||||
huint16_t remote_port{pseudo_port};
|
||||
|
||||
quic::Endpoint* ep = nullptr;
|
||||
|
||||
if (type == CLIENT_TO_SERVER)
|
||||
{
|
||||
LogTrace("packet is client-to-server from client pport ", pseudo_port);
|
||||
// Client-to-server: the header port is the return port
|
||||
remote.setPort(pseudo_port);
|
||||
log::debug(logcat, "packet is client-to-server from client pport {}", pseudo_port);
|
||||
|
||||
if (!server_)
|
||||
{
|
||||
LogWarn("Dropping incoming quic packet to server: no listeners");
|
||||
log::warning(logcat, "Dropping incoming quic packet to server: no listeners");
|
||||
return;
|
||||
}
|
||||
ep = server_.get();
|
||||
}
|
||||
else if (type == SERVER_TO_CLIENT)
|
||||
{
|
||||
LogTrace("packet is server-to-client to client pport ", pseudo_port);
|
||||
log::debug(logcat, "packet is server-to-client to client pport {}", pseudo_port);
|
||||
// Server-to-client: the header port tells us which client tunnel this is going to
|
||||
if (auto it = client_tunnels_.find(pseudo_port); it != client_tunnels_.end())
|
||||
ep = it->second.client.get();
|
||||
|
||||
if (not ep)
|
||||
{
|
||||
LogWarn("Incoming quic packet to invalid/closed client; dropping");
|
||||
log::warning(logcat, "Incoming quic packet to invalid/closed client; dropping");
|
||||
return;
|
||||
}
|
||||
|
||||
// The server doesn't send back the port because we already know it 1-to-1 from our outgoing
|
||||
// connection.
|
||||
// connection
|
||||
if (auto conn = static_cast<quic::Client&>(*ep).get_connection())
|
||||
{
|
||||
remote.setPort(conn->path.remote.port());
|
||||
LogTrace("remote port is ", remote.getPort());
|
||||
remote_port = llarp::net::ToHost(conn->path.remote.port());
|
||||
log::debug(logcat, "remote port is {}", remote_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWarn("Incoming quic to a quic::Client without an active quic::Connection; dropping");
|
||||
log::warning(
|
||||
logcat, "Incoming quic to a quic::Client without an active quic::Connection; dropping");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWarn("Invalid incoming quic packet type ", type, "; dropping packet");
|
||||
log::warning(logcat, "Invalid incoming quic packet type {}; dropping packet", type);
|
||||
return;
|
||||
}
|
||||
ep->receive_packet(remote, ecn, data);
|
||||
|
||||
log::debug(
|
||||
logcat,
|
||||
"remote_port = {}, pseudo_port = {} at line {}",
|
||||
remote_port,
|
||||
pseudo_port,
|
||||
__LINE__);
|
||||
|
||||
auto remote_addr = Address{SockAddr{"::1"sv, remote_port}, std::move(remote)};
|
||||
ep->receive_packet(std::move(remote_addr), ecn, data);
|
||||
}
|
||||
} // namespace llarp::quic
|
||||
|
|
|
@ -78,7 +78,10 @@ namespace llarp::quic
|
|||
forget(int id);
|
||||
|
||||
/// Called when open succeeds or times out.
|
||||
using OpenCallback = std::function<void(bool success)>;
|
||||
using OpenCallback = std::function<void(bool success, void* user_data)>;
|
||||
|
||||
/// Called when the tunnel is closed for any reason
|
||||
using CloseCallback = std::function<void(int rv, void* user_data)>;
|
||||
|
||||
/// Opens a quic tunnel to some remote lokinet address. (Should only be called from the event
|
||||
/// loop thread.)
|
||||
|
@ -115,6 +118,7 @@ namespace llarp::quic
|
|||
std::string_view remote_addr,
|
||||
uint16_t port,
|
||||
OpenCallback on_open = {},
|
||||
CloseCallback on_close = {},
|
||||
SockAddr bind_addr = {127, 0, 0, 1});
|
||||
|
||||
/// Start closing an outgoing tunnel; takes the ID returned by `open()`. Note that an existing
|
||||
|
@ -129,7 +133,7 @@ namespace llarp::quic
|
|||
/// \param buf - the raw arriving packet
|
||||
///
|
||||
void
|
||||
receive_packet(const service::ConvoTag& tag, const llarp_buffer_t& buf);
|
||||
receive_packet(std::variant<service::Address, RouterID> remote, const llarp_buffer_t& buf);
|
||||
|
||||
/// return true if we have any listeners added
|
||||
inline bool
|
||||
|
@ -147,6 +151,8 @@ namespace llarp::quic
|
|||
std::unique_ptr<Client> client;
|
||||
// Callback to invoke on quic connection established (true argument) or failed (false arg)
|
||||
OpenCallback open_cb;
|
||||
// Callback to invoke when the tunnel is closed, if it was successfully opened
|
||||
CloseCallback close_cb;
|
||||
// TCP listening socket
|
||||
std::shared_ptr<uvw::TCPHandle> tcp;
|
||||
// Accepted TCP connections
|
||||
|
@ -170,7 +176,10 @@ namespace llarp::quic
|
|||
uint16_t pseudo_port, bool step_success, std::string_view step_name, std::string_view addr);
|
||||
|
||||
void
|
||||
make_client(const SockAddr& remote, std::pair<const uint16_t, ClientTunnel>& row);
|
||||
make_client(
|
||||
const uint16_t port,
|
||||
std::variant<service::Address, RouterID> ep,
|
||||
std::pair<const uint16_t, ClientTunnel>& row);
|
||||
|
||||
void
|
||||
flush_pending_incoming(ClientTunnel& ct);
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
static auto logcat = log::Cat("rc-lookup");
|
||||
|
||||
void
|
||||
RCLookupHandler::AddValidRouter(const RouterID& router)
|
||||
{
|
||||
|
@ -91,6 +93,11 @@ namespace llarp
|
|||
{
|
||||
itr_pair.first->second.push_back(callback);
|
||||
}
|
||||
log::trace(
|
||||
logcat,
|
||||
"RC Lookup for {} has {} pending callbacks.",
|
||||
router,
|
||||
itr_pair.first->second.size());
|
||||
shouldDoLookup = itr_pair.second;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace llarp
|
|||
_lastTick = llarp::time_now_ms();
|
||||
m_NextExploreAt = Clock_t::now();
|
||||
m_Pump = _loop->make_waker([this]() { PumpLL(); });
|
||||
m_Work = _loop->make_waker([this]() { submit_work(); });
|
||||
}
|
||||
|
||||
Router::~Router()
|
||||
|
@ -79,6 +80,15 @@ namespace llarp
|
|||
llarp_dht_context_free(_dht);
|
||||
}
|
||||
|
||||
void
|
||||
Router::submit_work()
|
||||
{
|
||||
m_lmq->job([work = std::move(m_WorkJobs)]() {
|
||||
for (const auto& job : work)
|
||||
job();
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Router::PumpLL()
|
||||
{
|
||||
|
@ -411,7 +421,7 @@ namespace llarp
|
|||
|
||||
if (log::get_level_default() != log::Level::off)
|
||||
log::reset_level(conf.logging.m_logLevel);
|
||||
log::clear_sinks();
|
||||
// log::clear_sinks();
|
||||
log::add_sink(log_type, log_type == log::Type::System ? "lokinet" : conf.logging.m_logFile);
|
||||
|
||||
// re-add rpc log sink if rpc enabled, else free it
|
||||
|
@ -482,8 +492,8 @@ namespace llarp
|
|||
LogError("RC is invalid, not saving");
|
||||
return false;
|
||||
}
|
||||
if (m_isServiceNode)
|
||||
_nodedb->Put(_rc);
|
||||
if (IsServiceNode())
|
||||
_nodedb->Put(rc());
|
||||
QueueDiskIO([&]() { HandleSaveRC(); });
|
||||
return true;
|
||||
}
|
||||
|
@ -1631,7 +1641,10 @@ namespace llarp
|
|||
void
|
||||
Router::QueueWork(std::function<void(void)> func)
|
||||
{
|
||||
m_lmq->job(std::move(func));
|
||||
_loop->call([this, func = std::move(func)]() mutable {
|
||||
m_WorkJobs.push_back(std::move(func));
|
||||
m_Work->Trigger();
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -78,6 +78,12 @@ namespace llarp
|
|||
path::BuildLimiter m_PathBuildLimiter;
|
||||
|
||||
std::shared_ptr<EventLoopWakeup> m_Pump;
|
||||
std::shared_ptr<EventLoopWakeup> m_Work;
|
||||
std::vector<std::function<void()>> m_WorkJobs;
|
||||
|
||||
/// submits cpu heavy work from last event loop tick cycle to worker threads.
|
||||
void
|
||||
submit_work();
|
||||
|
||||
path::BuildLimiter&
|
||||
pathBuildLimiter() override
|
||||
|
@ -196,9 +202,11 @@ namespace llarp
|
|||
return _vpnPlatform.get();
|
||||
}
|
||||
|
||||
/// queue functionally pure cpu heavy work to be done in another thread.
|
||||
void
|
||||
QueueWork(std::function<void(void)> func) override;
|
||||
|
||||
/// queue disk io bound work to be done in the disk io thread.
|
||||
void
|
||||
QueueDiskIO(std::function<void(void)> func) override;
|
||||
|
||||
|
|
|
@ -366,4 +366,4 @@ namespace llarp::rpc
|
|||
}
|
||||
}
|
||||
}
|
||||
} // namespace llarp::rpc
|
||||
} // namespace llarp::rpc
|
||||
|
|
|
@ -223,8 +223,9 @@ namespace llarp::rpc
|
|||
|
||||
try
|
||||
{
|
||||
// FIXME: real open/close callbacks
|
||||
auto [addr, id] = quic->open(
|
||||
quicconnect.request.remoteHost, quicconnect.request.port, [](auto&&) {}, laddr);
|
||||
quicconnect.request.remoteHost, quicconnect.request.port, nullptr, nullptr, laddr);
|
||||
|
||||
util::StatusObject status;
|
||||
status["addr"] = addr.ToString();
|
||||
|
|
|
@ -148,7 +148,10 @@ namespace llarp
|
|||
if (auto* quic = GetQUICTunnel())
|
||||
{
|
||||
if (quic->hasListeners())
|
||||
{
|
||||
log::debug(logcat, "IntroSet setting QUIC as available protocol.");
|
||||
introSet().supportedProtocols.push_back(ProtocolType::QUIC);
|
||||
}
|
||||
}
|
||||
|
||||
introSet().intros.clear();
|
||||
|
@ -1054,26 +1057,29 @@ namespace llarp
|
|||
{
|
||||
if (not NameIsValid(name))
|
||||
{
|
||||
handler(ParseAddress(name));
|
||||
log::warning(logcat, "\"{}\" is not a valid ONS name", name);
|
||||
handler(std::nullopt);
|
||||
return;
|
||||
}
|
||||
auto& cache = m_state->nameCache;
|
||||
const auto maybe = cache.Get(name);
|
||||
if (maybe.has_value())
|
||||
{
|
||||
log::debug(logcat, "Returning cached result for ONS name \"{}\"", name);
|
||||
handler(maybe);
|
||||
return;
|
||||
}
|
||||
LogInfo(Name(), " looking up LNS name: ", name);
|
||||
// log::info(logcat, "{} looking up ONS name \"{}\"", Name(), name);
|
||||
log::debug(logcat, "{} looking up ONS name \"{}\"", Name(), name);
|
||||
auto paths = GetUniqueEndpointsForLookup();
|
||||
// not enough paths
|
||||
if (not ReadyToDoLookup(paths.size()))
|
||||
{
|
||||
LogWarn(
|
||||
log::warning(
|
||||
logcat,
|
||||
"{} not enough paths for ONS lookup, have {} need {}",
|
||||
Name(),
|
||||
" not enough paths for lns lookup, have ",
|
||||
paths.size(),
|
||||
" need ",
|
||||
MIN_ENDPOINTS_FOR_LNS_LOOKUP);
|
||||
handler(std::nullopt);
|
||||
return;
|
||||
|
@ -1111,7 +1117,8 @@ namespace llarp
|
|||
|
||||
for (const auto& path : chosenpaths)
|
||||
{
|
||||
LogInfo(Name(), " lookup ", name, " from ", path->Endpoint());
|
||||
// log::info(logcat, "{} lookup \"{}\" via {}", Name(), name, path->Endpoint());
|
||||
log::debug(logcat, "{} lookup \"{}\" via {}", Name(), name, path->Endpoint());
|
||||
auto job = new LookupNameJob{this, GenTXID(), name, resultHandler};
|
||||
job->SendRequestViaPath(path, m_router);
|
||||
}
|
||||
|
@ -1696,37 +1703,6 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::SendToOrQueue(ConvoTag tag, const llarp_buffer_t& pkt, ProtocolType t)
|
||||
{
|
||||
if (tag.IsZero())
|
||||
{
|
||||
LogWarn("SendToOrQueue failed: convo tag is zero");
|
||||
return false;
|
||||
}
|
||||
LogDebug(Name(), " send ", pkt.sz, " bytes on T=", tag);
|
||||
if (auto maybe = GetEndpointWithConvoTag(tag))
|
||||
{
|
||||
if (auto* ptr = std::get_if<Address>(&*maybe))
|
||||
{
|
||||
if (*ptr == m_Identity.pub.Addr())
|
||||
{
|
||||
ConvoTagTX(tag);
|
||||
m_state->m_Router->TriggerPump();
|
||||
if (not HandleInboundPacket(tag, pkt, t, 0))
|
||||
return false;
|
||||
ConvoTagRX(tag);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (not SendToOrQueue(*maybe, pkt, t))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
LogDebug("SendToOrQueue failed: no endpoint for convo tag ", tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::SendToOrQueue(const RouterID& addr, const llarp_buffer_t& buf, ProtocolType t)
|
||||
{
|
||||
|
@ -1879,7 +1855,7 @@ namespace llarp
|
|||
bool
|
||||
Endpoint::EnsurePathTo(
|
||||
std::variant<Address, RouterID> addr,
|
||||
std::function<void(std::optional<ConvoTag>)> hook,
|
||||
std::function<void(std::optional<std::variant<Address, RouterID>>)> hook,
|
||||
llarp_time_t timeout)
|
||||
{
|
||||
if (auto ptr = std::get_if<Address>(&addr))
|
||||
|
@ -1888,14 +1864,15 @@ namespace llarp
|
|||
{
|
||||
ConvoTag tag{};
|
||||
|
||||
if (auto maybe = GetBestConvoTagFor(*ptr))
|
||||
tag = *maybe;
|
||||
if (auto maybe_tag = GetBestConvoTagFor(*ptr))
|
||||
tag = *maybe_tag;
|
||||
else
|
||||
tag.Randomize();
|
||||
PutSenderFor(tag, m_Identity.pub, true);
|
||||
ConvoTagTX(tag);
|
||||
Sessions()[tag].forever = true;
|
||||
Loop()->call_soon([tag, hook]() { hook(tag); });
|
||||
auto maybe_addr = GetEndpointWithConvoTag(tag);
|
||||
Loop()->call_soon([maybe_addr, hook]() { hook(maybe_addr); });
|
||||
return true;
|
||||
}
|
||||
if (not WantsOutboundSession(*ptr))
|
||||
|
@ -1907,10 +1884,11 @@ namespace llarp
|
|||
|
||||
return EnsurePathToService(
|
||||
*ptr,
|
||||
[hook](auto, auto* ctx) {
|
||||
[hook, this](auto, auto* ctx) {
|
||||
if (ctx)
|
||||
{
|
||||
hook(ctx->currentConvoTag);
|
||||
if (auto maybe_addr = GetEndpointWithConvoTag(ctx->currentConvoTag))
|
||||
hook(maybe_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1921,10 +1899,11 @@ namespace llarp
|
|||
}
|
||||
if (auto ptr = std::get_if<RouterID>(&addr))
|
||||
{
|
||||
return EnsurePathToSNode(*ptr, [hook](auto, auto session, auto tag) {
|
||||
return EnsurePathToSNode(*ptr, [hook, this](auto, auto session, auto tag) {
|
||||
if (session)
|
||||
{
|
||||
hook(tag);
|
||||
if (auto maybe_addr = GetEndpointWithConvoTag(tag))
|
||||
hook(maybe_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2075,7 +2054,7 @@ namespace llarp
|
|||
|
||||
bool
|
||||
Endpoint::SendToOrQueue(
|
||||
const std::variant<Address, RouterID>& addr, const llarp_buffer_t& data, ProtocolType t)
|
||||
std::variant<Address, RouterID> addr, const llarp_buffer_t& data, ProtocolType t)
|
||||
{
|
||||
return var::visit([&](auto& addr) { return SendToOrQueue(addr, data, t); }, addr);
|
||||
}
|
||||
|
|
|
@ -346,7 +346,7 @@ namespace llarp
|
|||
bool
|
||||
EnsurePathTo(
|
||||
std::variant<Address, RouterID> addr,
|
||||
std::function<void(std::optional<ConvoTag>)> hook,
|
||||
std::function<void(std::optional<std::variant<Address, RouterID>>)> hook,
|
||||
llarp_time_t timeout) override;
|
||||
|
||||
// passed a sendto context when we have a path established otherwise
|
||||
|
@ -468,19 +468,20 @@ namespace llarp
|
|||
|
||||
// Looks up the ConvoTag and, if it exists, calls SendToOrQueue to send it to a remote client
|
||||
// or a snode (or nothing, if the convo tag is unknown).
|
||||
bool
|
||||
SendToOrQueue(ConvoTag tag, const llarp_buffer_t& payload, ProtocolType t) override;
|
||||
// bool
|
||||
// SendToOrQueue(std::variant<service::Address, RouterID> addr, const llarp_buffer_t& payload,
|
||||
// ProtocolType t) override;
|
||||
|
||||
// Send a to (or queues for sending) to either an address or router id
|
||||
bool
|
||||
SendToOrQueue(
|
||||
const std::variant<Address, RouterID>& addr,
|
||||
std::variant<Address, RouterID> addr,
|
||||
const llarp_buffer_t& payload,
|
||||
ProtocolType t);
|
||||
ProtocolType t) override;
|
||||
|
||||
// Sends to (or queues for sending) to a remote client
|
||||
bool
|
||||
SendToOrQueue(const Address& addr, const llarp_buffer_t& payload, ProtocolType t);
|
||||
SendToOrQueue(const Address& remote, const llarp_buffer_t& payload, ProtocolType t);
|
||||
|
||||
// Sends to (or queues for sending) to a router
|
||||
bool
|
||||
|
|
93
llarp/vpn/null.hpp
Normal file
93
llarp/vpn/null.hpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
#pragma once
|
||||
#include "platform.hpp"
|
||||
#include <unistd.h>
|
||||
|
||||
namespace llarp::vpn
|
||||
{
|
||||
class NullInterface : public NetworkInterface
|
||||
{
|
||||
/// we use a pipe because it isnt going to poll itself
|
||||
int m_pipe[2];
|
||||
|
||||
public:
|
||||
NullInterface(InterfaceInfo info) : NetworkInterface{std::move(info)}
|
||||
{
|
||||
::pipe(m_pipe);
|
||||
}
|
||||
|
||||
virtual ~NullInterface()
|
||||
{
|
||||
::close(m_pipe[1]);
|
||||
::close(m_pipe[0]);
|
||||
}
|
||||
|
||||
int
|
||||
PollFD() const override
|
||||
{
|
||||
return m_pipe[0];
|
||||
}
|
||||
|
||||
net::IPPacket
|
||||
ReadNextPacket() override
|
||||
{
|
||||
return net::IPPacket{};
|
||||
}
|
||||
|
||||
/// write a packet to the interface
|
||||
/// returns false if we dropped it
|
||||
bool
|
||||
WritePacket(net::IPPacket) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class NopRouteManager : public IRouteManager
|
||||
{
|
||||
public:
|
||||
void AddRoute(net::ipaddr_t, net::ipaddr_t) override{};
|
||||
|
||||
void DelRoute(net::ipaddr_t, net::ipaddr_t) override{};
|
||||
|
||||
void
|
||||
AddDefaultRouteViaInterface(NetworkInterface&) override{};
|
||||
|
||||
void
|
||||
DelDefaultRouteViaInterface(NetworkInterface&) override{};
|
||||
|
||||
void
|
||||
AddRouteViaInterface(NetworkInterface&, IPRange) override{};
|
||||
|
||||
void
|
||||
DelRouteViaInterface(NetworkInterface&, IPRange) override{};
|
||||
|
||||
std::vector<net::ipaddr_t>
|
||||
GetGatewaysNotOnInterface(NetworkInterface&) override
|
||||
{
|
||||
return std::vector<net::ipaddr_t>{};
|
||||
};
|
||||
};
|
||||
|
||||
class NullPlatform : public Platform
|
||||
{
|
||||
NopRouteManager _routes;
|
||||
|
||||
public:
|
||||
NullPlatform() : Platform{}, _routes{}
|
||||
{}
|
||||
|
||||
virtual ~NullPlatform() = default;
|
||||
|
||||
std::shared_ptr<NetworkInterface>
|
||||
ObtainInterface(InterfaceInfo info, AbstractRouter*) override
|
||||
{
|
||||
return std::make_shared<NullInterface>(std::move(info));
|
||||
}
|
||||
|
||||
IRouteManager&
|
||||
RouteManager() override
|
||||
{
|
||||
return _routes;
|
||||
}
|
||||
};
|
||||
} // namespace llarp::vpn
|
|
@ -11,6 +11,9 @@
|
|||
#include "linux.hpp"
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include "null.hpp"
|
||||
#endif
|
||||
|
||||
#include <exception>
|
||||
|
||||
|
@ -38,8 +41,11 @@ namespace llarp::vpn
|
|||
#endif
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
throw std::runtime_error{"not supported"};
|
||||
plat = std::make_shared<NullPlatform>();
|
||||
#endif
|
||||
|
||||
if (not plat)
|
||||
throw std::runtime_error{"not supported"};
|
||||
return plat;
|
||||
}
|
||||
|
||||
|
|
16
misc_notes.txt
Normal file
16
misc_notes.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
add_stream_data for stream <> returned:
|
||||
[-240,0]
|
||||
increase buflen until == 1200
|
||||
add_stream_data for stream <> returned:
|
||||
[1200,-1]
|
||||
Send packet
|
||||
[0,-1]
|
||||
Congestion limited or nothing to do
|
||||
move on
|
||||
|
||||
add_stream_data for non-stream returned:
|
||||
[1200,-1] OR [{>0},-1]
|
||||
send data packet
|
||||
[0,-1]
|
||||
Congestion limited or nothing to do
|
12
rebuild.sh
Executable file
12
rebuild.sh
Executable file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
rm -rf build && \
|
||||
mkdir build && \
|
||||
cd build && \
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Debug -DWITH_EMBEDDED_LOKINET=ON -DLIBLOKINET_TEST_UTILS=ON -DOXEN_LOGGING_RELEASE_TRACE=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=1 && \
|
||||
make -j6 && \
|
||||
mkdir -p logs && \
|
||||
mkdir -p tcp_connect_data_dir/testnet && \
|
||||
cp ../contrib/bootstrap/mainnet.signed ./tcp_connect_data_dir/bootstrap.signed && \
|
||||
cp ../contrib/bootstrap/testnet.signed ./tcp_connect_data_dir/testnet/bootstrap.signed && \
|
||||
sudo setcap cap_net_admin,cap_net_bind_service=+eip daemon/lokinet
|
Loading…
Reference in a new issue