Ryan Tharp 6 years ago
commit 5d90cbe895

@ -0,0 +1 @@
build/

2
.gitignore vendored

@ -37,4 +37,6 @@ testnet_tmp
vsproject/
daemon.ini
lokinet-win32.exe
lokinet
rapidjson/

@ -8,7 +8,7 @@
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "enter program name, for example ${workspaceFolder}/a.out",
"program": "${workspaceFolder}/lokinet",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",

@ -6,7 +6,7 @@
{
"label": "build",
"type": "shell",
"command": "make",
"command": "make -j8 JSONRPC=ON",
"group": "build",
"problemMatcher": [
"$gcc"

@ -5,13 +5,29 @@ set(PROJECT_NAME lokinet)
project(${PROJECT_NAME} C CXX ASM)
option(USE_LIBABYSS "enable libabyss" OFF)
option(USE_CXX17 "enable c++17 features" OFF)
option(USE_AVX2 "enable avx2 code" OFF)
# Require C++11
set(CMAKE_CXX_STANDARD 11)
# or C++17 on win32
if (NOT WIN32)
if(USE_CXX17)
set(CMAKE_CXX_STANDARD 17)
else()
set(CMAKE_CXX_STANDARD 11)
endif()
else()
set(CMAKE_CXX_STANDARD 17)
endif(NOT WIN32)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_compile_options( -fpermissive )
# turns off those annoying warnings for
# target-specific crypto code paths not
# applicable to the host's FPU -rick
add_compile_options(-Wall)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
add_compile_options(-Wno-unused-function -Wno-deprecated-declarations -Wno-unknown-pragmas)
if (WOW64_CROSS_COMPILE OR WIN64_CROSS_COMPILE)
if (USING_CLANG)
@ -31,7 +47,7 @@ set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
if(STATIC_LINK)
add_compile_options( -static -Wl,--whole-archive -lpthread -Wl,--no-whole-archive )
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static" )
endif()
if(DNS_PORT)
@ -48,10 +64,8 @@ if(TESTNET)
add_definitions(-DTESTNET=1)
endif()
add_compile_options( -Wall )
set(OPTIMIZE_FLAGS -O3 )
set(DEBUG_FLAGS -O0 -g3 )
set(OPTIMIZE_FLAGS -O3)
set(DEBUG_FLAGS -O0 -g3)
if(ASAN)
set(DEBUG_FLAGS "${DEBUG_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
@ -81,13 +95,18 @@ if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
add_compile_options( ${DEBUG_FLAGS} )
endif()
set(CRYPTO_FLAGS "-march=native")
set(CMAKE_ASM_FLAGS "-march=native")
if (NOT USE_AVX2)
set(CRYPTO_FLAGS -march=native)
set(CMAKE_ASM_FLAGS "-march=native ${CMAKE_ASM_FLAGS} $ENV{ASFLAGS}")
else()
set(CRYPTO_FLAGS -march=haswell -mtune=native)
set(CMAKE_ASM_FLAGS "-march=haswell -mtune=native ${CMAKE_ASM_FLAGS} $ENV{ASFLAGS}")
endif(NOT USE_AVX2)
add_compile_options( -Wall -Wno-deprecated-declarations ${OPTIMIZE_FLAGS} ${CRYPTO_FLAGS} )
add_compile_options(${OPTIMIZE_FLAGS} ${CRYPTO_FLAGS})
if(SHADOW)
add_compile_options( -fPIC)
add_compile_options(-fPIC)
endif()
if(NOT GIT_VERSION)
@ -111,7 +130,12 @@ if(JEMALLOC)
set(MALLOC_LIB jemalloc)
endif()
#set(FS_LIB stdc++fs)
if (WIN32)
set(FS_LIB stdc++fs)
endif(WIN32)
# FS_LIB should resolve to nothing on all other platforms
# it is only required on win32 -rick
set(LIBS Threads::Threads ${MALLOC_LIB} ${FS_LIB})
set(LIB lokinet)
@ -143,6 +167,7 @@ if(UNIX)
set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-freebsd.c ${TT_ROOT}/tuntap-unix-bsd.c)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-darwin.c ${TT_ROOT}/tuntap-unix-bsd.c)
# TODO: _actually_ port to solaris/illumos (it's fairly complete...except for TUN) -rick
elseif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-sunos.c)
else()
@ -178,7 +203,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(ISOLATE_PROC_SRC llarp/linux/netns.cpp)
endif()
if(NOT WIN32)
set(CXX_COMPAT_SRC
vendor/cppbackport-master/lib/fs/rename.cpp
vendor/cppbackport-master/lib/fs/filestatus.cpp
@ -198,6 +223,7 @@ set(CXX_COMPAT_SRC
vendor/cppbackport-master/lib/fs/direntry.cpp
)
include_directories(vendor/cppbackport-master/lib)
endif(NOT WIN32)
set(LIB_PLATFORM_SRC
# string stuff
@ -347,7 +373,7 @@ set(CRYPTOGRAPHY_SRC
${SHA512_SRC}
${NTRU_SRC})
add_library(${CRYPTOGRAPHY_LIB} ${CRYPTOGRAPHY_SRC})
add_library(${CRYPTOGRAPHY_LIB} STATIC ${CRYPTOGRAPHY_SRC})
set(UTP_SRC
@ -466,33 +492,38 @@ set(CLIENT_SRC
include_directories(include)
# TODO: exclude this from includes and expose stuff properly for rcutil
include_directories(llarp)
<<<<<<< HEAD
#include_directories(include)
#include_directories(vendor/cppbackport-master/lib)
#include_directories(${sodium_INCLUDE_DIR})
=======
>>>>>>> 2fb8d734613b5665d789c99afd06e7223b073c2c
set(RC_EXE rcutil)
set(DNS_EXE dns)
set(ALL_SRC ${CLIENT_SRC} ${RC_SRC} ${EXE_SRC} ${DNS_SRC} ${LIB_PLATFORM_SRC} ${LIB_SRC} ${TEST_SRC})
if(USE_LIBABYSS)
add_definitions(-DUSE_ABYSS=1)
set(ABYSS libabyss)
set(ABYSS_LIB abyss)
set(ABYSS_EXE ${ABYSS_LIB}-main)
include_directories(${ABYSS}/include)
set(ABYSS_SRC
${ABYSS}/src/http.cpp
${ABYSS}/src/client.cpp
${ABYSS}/src/server.cpp
${ABYSS}/src/json.cpp)
add_library(${ABYSS_LIB} ${ABYSS_SRC})
add_library(${ABYSS_LIB} STATIC ${ABYSS_SRC})
set(ALL_SRC ${ALL_SRC} ${ABYSS_SRC} ${ABYSS}/main.cpp)
add_executable(${ABYSS_EXE} ${ABYSS}/main.cpp)
target_link_libraries(${ABYSS_EXE} ${PLATFORM_LIB})
set(TEST_SRC ${TEST_SRC} test/jsonrpc_unittest.cpp)
# for freebsd
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
include_directories(/usr/local/include)
endif()
endif()
foreach(F ${ALL_SRC})
@ -526,16 +557,17 @@ if(WITH_STATIC)
endif()
target_link_libraries(${STATIC_LIB} ${CRYPTOGRAPHY_LIB} ${LIBS} ${PLATFORM_LIB})
if(NOT WITH_SHARED)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB})
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB})
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB})
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${PLATFORM_LIB})
target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB})
if (WIN32)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
endif(WIN32)
if (WIN32)
target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} Threads::Threads ws2_32 iphlpapi)

@ -32,10 +32,12 @@ TESTNET_SERVERS ?= 50
TESTNET_DEBUG ?= 0
JSONRPC = OFF
CXX17 = ON
BUILD_ROOT = $(REPO)/build
CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -DUSE_LIBABYSS=$(JSONRPC) '$(REPO)'")
CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -DUSE_CXX17=$(CXX17) -DUSE_LIBABYSS=$(JSONRPC) '$(REPO)'")
SCAN_BUILD ?= scan-build
ANALYZE_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "$(SCAN_BUILD) cmake -DUSE_LIBABYSS=$(JSONRPC) '$(REPO)' && cd '$(BUILD_ROOT)' && $(SCAN_BUILD) $(MAKE)")
@ -63,11 +65,11 @@ clean:
debug-configure:
mkdir -p '$(BUILD_ROOT)'
$(CONFIG_CMD) -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) -DDNS_PORT=$(DNS_PORT)
$(CONFIG_CMD) -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) -DDNS_PORT=$(DNS_PORT) -DCMAKE_ASM_FLAGS='$(ASFLAGS)' -DCMAKE_C_FLAGS='$(CFLAGS)' -DCMAKE_CXX_FLAGS='$(CXXFLAGS)'
release-configure: clean
mkdir -p '$(BUILD_ROOT)'
$(CONFIG_CMD) -DSTATIC_LINK=ON -DCMAKE_BUILD_TYPE=Release -DRELEASE_MOTTO="$(shell cat motto.txt)" -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX)
$(CONFIG_CMD) -DSTATIC_LINK=ON -DCMAKE_BUILD_TYPE=Release -DRELEASE_MOTTO="$(shell cat motto.txt)" -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) -DCMAKE_ASM_FLAGS='$(ASFLAGS)' -DCMAKE_C_FLAGS='$(CFLAGS)' -DCMAKE_CXX_FLAGS='$(CXXFLAGS)'
debug: debug-configure
$(MAKE) -C $(BUILD_ROOT)
@ -129,7 +131,7 @@ abyss: debug
$(ABYSS_EXE)
format:
clang-format -i $$(find daemon llarp include | grep -E '\.[h,c](pp)?$$')
clang-format -i $$(find daemon llarp include libabyss | grep -E '\.[h,c](pp)?$$')
analyze: clean
mkdir -p '$(BUILD_ROOT)'
@ -140,6 +142,12 @@ lint: $(LINT_CHECK)
%.cpp-check: %.cpp
clang-tidy $^ -- -I$(REPO)/include -I$(REPO)/crypto/libntrup/include -I$(REPO)/llarp
docker-debian:
docker build -f docker/debian.Dockerfile .
docker-fedora:
docker build -f docker/fedora.Dockerfile .
install:
rm -f $(PREFIX)/bin/lokinet
cp $(EXE) $(PREFIX)/bin/lokinet

@ -0,0 +1,50 @@
# lokinet builder for windows
## Building for Windows (mingw-w64 native, or wow64/linux/unix cross-compiler)
#i686 or x86_64
$ pacman -Sy base-devel mingw-w64-$ARCH-toolchain git libtool autoconf cmake (or your distro/OS package mgr)
$ git clone https://github.com/loki-project/loki-network.git
$ cd loki-network
$ mkdir -p build; cd build
$ cmake .. -DCMAKE_BUILD_TYPE=Debug -DSTATIC_LINK=ON -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DDNS_PORT=53
# if cross-compiling do
$ mkdir -p build; cd build
$ export COMPILER=clang # if using clang for windows
$ cmake .. -DCMAKE_BUILD_TYPE=[Debug|Release] -DSTATIC_LINK=ON -DCMAKE_CROSSCOMPILING=ON -DCMAKE_C_COMPILER=$ARCH-w64-mingw32-[gcc|clang] -DCMAKE_CXX_COMPILER=$ARCH-w64-mingw32-[g|clang]++ -DDNS_PORT=53 -DCMAKE_TOOLCHAIN_FILE=../contrib/cross/mingw[32].cmake
## running
if the machine you run lokinet on has a public address (at the moment) it `will` automatically become a relay,
otherwise it will run in client mode.
**NEVER** run lokinet with elevated privileges.
to set up a lokinet to start on boot:
C:\> (not ready yet. TODO: write up some SCM install code in the win32 setup)
alternatively:
set up the configs and bootstrap (first time only):
C:\> lokinet -g && lokinet-bootstrap
run it (foreground):
C:\> lokinet
to force client mode edit `$APPDATA/.lokinet/daemon.ini`
comment out the `[bind]` section, so it looks like this:
...
# [bind]
# {B7F2ECAC-BB10-4736-8BBD-6E9444E27030}=1090
-despair

@ -0,0 +1,26 @@
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
add_definitions("-DWINNT_CROSS_COMPILE")
# target environment on the build host system
# second one is for non-root installs
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX} /home/$ENV{USER}/mingw32 /home/$ENV{USER}/mingw32/${TOOLCHAIN_PREFIX})
# modify default behavior of FIND_XXX() commands
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# cross compilers to use
if($ENV{COMPILER} MATCHES "clang")
set(USING_CLANG ON)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-clang)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-clang++)
else()
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
endif()
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(WIN64_CROSS_COMPILE ON)

@ -0,0 +1,26 @@
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX i686-w64-mingw32)
add_definitions("-DWINNT_CROSS_COMPILE")
# target environment on the build host system
# second one is for non-root installs
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX} /home/$ENV{USER}/mingw32 /home/$ENV{USER}/mingw32/${TOOLCHAIN_PREFIX})
# modify default behavior of FIND_XXX() commands
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# cross compilers to use
if($ENV{COMPILER} MATCHES "clang")
set(USING_CLANG ON)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-clang)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-clang++)
else()
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
endif()
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(WOW64_CROSS_COMPILE ON)

@ -0,0 +1,4 @@
*.o
mbedtls/
*.a
*.exe

@ -0,0 +1,17 @@
Copyright (c)2018 Rick V. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -0,0 +1,54 @@
# makefile for windows bootstrap
# requires mbedtls to be installed somewhere, for both native and windows targets
# requires wget to be installed for ca bundle download
# to build:
# $ [g]make prepare;[g]make lokinet-bootstrap
# set this beforehand if you use clang
CC ?= i686-w64-mingw32-gcc
NATIVE_CC ?= cc
# set these for the native system
INCLUDE ?=
LIBS ?=
# set these for 32-bit windows if cross-compiling
WINNT_INCLUDE ?=
WINNT_LIBS ?=
.PHONY: download prepare all default
# windows target only
.c.o:
$(CC) $(WINNT_INCLUDE) -Ofast -march=core2 -mfpmath=sse $< -c
zpipe: zpipe.c miniz.c
$(NATIVE_CC) $(INCLUDE) $(LIBS) $^ -s -static -o $@
base64enc: base64enc.c
$(NATIVE_CC) $(INCLUDE) $(LIBS) $^ -s -static -o $@ -lmbedx509 -lmbedtls -lmbedcrypto
download:
wget -O ./cacert.pem https://curl.haxx.se/ca/cacert.pem
prepare: zpipe base64enc download
./zpipe < cacert.pem > data.enc
./base64enc < data.enc > out.bin
sed -ie "s/.\{76\}/&\n/g" out.bin
sed -i 's/.*/\"&\"/g' out.bin
sed -i '49,2192d' bootstrap.c
echo ';' >> out.bin
sed -i '48r out.bin' bootstrap.c
lokinet-bootstrap: bootstrap.o miniz.o
$(CC) $(WINNT_LIBS) -static -s $^ -o $@.exe -lmbedx509 -lmbedtls -lmbedcrypto -lws2_32
clean:
-@rm lokinet-bootstrap.exe
-@rm base64enc
-@rm zpipe
-@rm cacert.pem
-@rm data.enc
-@rm out.*
-@rm *.o

@ -0,0 +1,35 @@
# LokiNET bootstrap for Windows
This is a tiny executable that does the same thing as the `lokinet-bootstrap` shell script for Linux, specifically for the purpose of bypassing broken or outdated versions of Schannel that do not support current versions of TLS.
# Building
## requirements
- mbedtls 2.13.0 or later, for both host and windows
- wget for host (to download Netscape CA bundle from cURL website)
- Also included is a patch that can be applied to the mbedtls source to enable features like AES-NI in protected mode, plus some networking fixes for win32
native build:
$ export INCLUDE=/mingw32/include LIBS=/mingw32/lib # or a different path
$ export CC=cc # change these if you use clang
$ export NATIVE_CC=$CC
$ export WINNT_INCLUDE=$INCLUDE WINNT_LIBS=$LIBS
$ make prepare;make lokinet-bootstrap
cross-compile build:
$ export INCLUDE=/usr/local/include LIBS=/usr/local/lib # or a different path
$ export CC=i686-w64-mingw32-gcc # change these if you use clang, make sure these are in your system $PATH!
$ export NATIVE_CC=cc
$ export WINNT_INCLUDE=/path/to/win32/headers WINNT_LIBS=/path/to/win32/libs
$ make prepare;make lokinet-bootstrap
# Usage
C:\>lokinet-bootstrap [uri] [local download path]
this is also included in the lokinet installer package.
-despair86

@ -0,0 +1,54 @@
/*
* Copyright (c)2018 Rick V. All rights reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sysconf.h"
#ifdef HAVE_SETMODE
# define SET_BINARY_MODE(handle) setmode(handle, O_BINARY)
#else
# define SET_BINARY_MODE(handle) ((void)0)
#endif
#include <mbedtls/base64.h>
#include <mbedtls/error.h>
main(argc, argv)
char** argv;
{
int size,r, inl;
unsigned char in[524288];
unsigned char out[1048576];
unsigned char err[1024];
memset(&in, 0, 524288);
memset(&out, 0, 1048576);
SET_BINARY_MODE(0);
/* Read up to 512K of data from stdin */
inl = fread(in, 1, 524288, stdin);
r = mbedtls_base64_encode(out, 1048576, &size, in, inl);
if (r)
{
mbedtls_strerror(r, err, 1024);
printf("error: %s\n", err);
return r;
}
fprintf(stdout, "%s", out);
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,205 @@
diff -ruN polarssl-master/include/mbedtls/aesni.h polarssl/include/mbedtls/aesni.h
--- polarssl-master/include/mbedtls/aesni.h 2018-03-16 11:25:12.000000000 -0500
+++ polarssl/include/mbedtls/aesni.h 2018-04-17 15:47:59.320514100 -0500
@@ -26,17 +26,16 @@
#include "aes.h"
+/*
+ * despair: This code appears to be 32-bit clean. Remove the CPP macros
+ * that restrict usage to AMD64 and EM64T processors.
+ * Obviously, you still need to have this insn set available in order to
+ * use it in either of protected or long mode anyway.
+ */
+
#define MBEDTLS_AESNI_AES 0x02000000u
#define MBEDTLS_AESNI_CLMUL 0x00000002u
-#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && \
- ( defined(__amd64__) || defined(__x86_64__) ) && \
- ! defined(MBEDTLS_HAVE_X86_64)
-#define MBEDTLS_HAVE_X86_64
-#endif
-
-#if defined(MBEDTLS_HAVE_X86_64)
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -107,6 +106,4 @@
}
#endif
-#endif /* MBEDTLS_HAVE_X86_64 */
-
#endif /* MBEDTLS_AESNI_H */
diff -ruN polarssl-master/include/mbedtls/bn_mul.h polarssl/include/mbedtls/bn_mul.h
--- polarssl-master/include/mbedtls/bn_mul.h 2018-03-16 11:25:12.000000000 -0500
+++ polarssl/include/mbedtls/bn_mul.h 2018-04-17 15:42:09.045117300 -0500
@@ -754,7 +754,9 @@
#if defined(MBEDTLS_HAVE_SSE2)
#define EMIT __asm _emit
-
+/* Because the Visual C++ inline assembler STILL does
+ not support MMX insns! reeeeee (old -GM flag no longer exists)
+ */
#define MULADDC_HUIT \
EMIT 0x0F EMIT 0x6E EMIT 0xC9 \
EMIT 0x0F EMIT 0x6E EMIT 0xC3 \
diff -ruN polarssl-master/include/mbedtls/config.h polarssl/include/mbedtls/config.h
--- polarssl-master/include/mbedtls/config.h 2018-03-16 11:25:12.000000000 -0500
+++ polarssl/include/mbedtls/config.h 2018-04-17 17:27:18.350938700 -0500
@@ -91,7 +91,7 @@
*
* Uncomment if the CPU supports SSE2 (IA-32 specific).
*/
-//#define MBEDTLS_HAVE_SSE2
+#define MBEDTLS_HAVE_SSE2
/**
* \def MBEDTLS_HAVE_TIME
@@ -1571,7 +1571,7 @@
* Module: library/aesni.c
* Caller: library/aes.c
*
- * Requires: MBEDTLS_HAVE_ASM
+ * Requires: None. Enable only for i386 or AMD64 targets only! -despair
*
* This modules adds support for the AES-NI instructions on x86-64
*/
@@ -1850,7 +1850,7 @@
* Requires: MBEDTLS_AES_C or MBEDTLS_DES_C
*
*/
-//#define MBEDTLS_CMAC_C
+#define MBEDTLS_CMAC_C
/**
* \def MBEDTLS_CTR_DRBG_C
@@ -2055,7 +2055,7 @@
*
* Uncomment to enable the HAVEGE random generator.
*/
-//#define MBEDTLS_HAVEGE_C
+#define MBEDTLS_HAVEGE_C
/**
* \def MBEDTLS_HMAC_DRBG_C
diff -ruN polarssl-master/library/aes.c polarssl/library/aes.c
--- polarssl-master/library/aes.c 2018-03-16 11:25:12.000000000 -0500
+++ polarssl/library/aes.c 2018-04-17 16:51:37.098413400 -0500
@@ -514,7 +514,7 @@
#endif
ctx->rk = RK = ctx->buf;
-#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+#if defined(MBEDTLS_AESNI_C)
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) )
return( mbedtls_aesni_setkey_enc( (unsigned char *) ctx->rk, key, keybits ) );
#endif
@@ -621,7 +621,7 @@
ctx->nr = cty.nr;
-#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+#if defined(MBEDTLS_AESNI_C)
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) )
{
mbedtls_aesni_inverse_key( (unsigned char *) ctx->rk,
@@ -850,7 +850,7 @@
const unsigned char input[16],
unsigned char output[16] )
{
-#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+#if defined(MBEDTLS_AESNI_C)
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) )
return( mbedtls_aesni_crypt_ecb( ctx, mode, input, output ) );
#endif
diff -ruN polarssl-master/library/aesni.c polarssl/library/aesni.c
--- polarssl-master/library/aesni.c 2018-03-16 11:25:12.000000000 -0500
+++ polarssl/library/aesni.c 2018-04-17 16:09:26.050605000 -0500
@@ -30,7 +30,16 @@
#include MBEDTLS_CONFIG_FILE
#endif
-#if defined(MBEDTLS_AESNI_C)
+
+/*
+ * despair: This code appears to be 32-bit clean. Remove the CPP macros
+ * that restrict usage to AMD64 and EM64T processors.
+ * Obviously, you still need to have this insn set available in order to
+ * use it in either of protected or long mode anyway.
+ * GCC or Clang only, no MSVC here, sorry. (Must pass -march=core2 or later
+ * if your compiler's default is anything older or generic.)
+ */
+#if defined(MBEDTLS_AESNI_C) && !defined(_MSC_VER)
#include "mbedtls/aesni.h"
@@ -40,8 +49,6 @@
#define asm __asm
#endif
-#if defined(MBEDTLS_HAVE_X86_64)
-
/*
* AES-NI support detection routine
*/
@@ -459,6 +466,4 @@
return( 0 );
}
-#endif /* MBEDTLS_HAVE_X86_64 */
-
#endif /* MBEDTLS_AESNI_C */
diff -ruN polarssl-master/library/entropy_poll.c polarssl/library/entropy_poll.c
--- polarssl-master/library/entropy_poll.c 2018-03-16 11:25:12.000000000 -0500
+++ polarssl/library/entropy_poll.c 2018-04-17 15:52:13.013004200 -0500
@@ -56,6 +56,12 @@
#include <windows.h>
#include <wincrypt.h>
+/*
+ * WARNING(despair): The next release of PolarSSL will remove the existing codepaths
+ * to enable Windows RT and UWP app support. This also breaks NT 5.x and early Longhorn.
+ *
+ * TODO(despair): create CPP macro to switch between old and new CAPI codepaths
+ */
int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len,
size_t *olen )
{
diff -ruN polarssl-master/library/gcm.c polarssl/library/gcm.c
--- polarssl-master/library/gcm.c 2018-03-16 11:25:12.000000000 -0500
+++ polarssl/library/gcm.c 2018-04-17 16:53:18.630262400 -0500
@@ -126,7 +126,7 @@
ctx->HL[8] = vl;
ctx->HH[8] = vh;
-#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+#if defined(MBEDTLS_AESNI_C)
/* With CLMUL support, we need only h, not the rest of the table */
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) )
return( 0 );
@@ -217,7 +217,7 @@
unsigned char lo, hi, rem;
uint64_t zh, zl;
-#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
+#if defined(MBEDTLS_AESNI_C)
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) ) {
unsigned char h[16];
diff -ruN polarssl-master/library/net_sockets.c polarssl/library/net_sockets.c
--- polarssl-master/library/net_sockets.c 2018-03-16 11:25:12.000000000 -0500
+++ polarssl/library/net_sockets.c 2018-04-17 15:50:08.118440600 -0500
@@ -51,7 +51,8 @@
/* Enables getaddrinfo() & Co */
#define _WIN32_WINNT 0x0501
#include <ws2tcpip.h>
-
+/* despair: re-enable Windows 2000/XP */
+#include <wspiapi.h>
#include <winsock2.h>
#include <windows.h>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,95 @@
/**
* sysconf.h -- system-dependent macros and settings
*
* Copyright (C) 2002-2004 Cosmin Truta.
* Permission to use and distribute freely.
* No warranty.
**/
#ifndef SYSCONF_H
#define SYSCONF_H
/*****************************************************************************/
/* Platform identifiers */
/* Detect Unix. */
#if defined(unix) || defined(__linux__) || defined(BSD) || defined(__CYGWIN__)
/* Add more systems here. */
# ifndef UNIX
# define UNIX
# endif
#endif
/* Detect MS-DOS. */
#if defined(__MSDOS__)
# ifndef MSDOS
# define MSDOS
# endif
#endif
/* TO DO: Detect OS/2. */
/* Detect Windows. */
#if defined(_WIN32) || defined(__WIN32__)
# ifndef WIN32
# define WIN32
# endif
#endif
#if defined(_WIN64)
# ifndef WIN64
# define WIN64
# endif
#endif
#if defined(_WINDOWS) || defined(WIN32) || defined(WIN64)
# ifndef WINDOWS
# define WINDOWS
# endif
#endif
/* Enable POSIX-friendly symbols on Microsoft (Visual) C. */
#ifdef _MSC_VER
# define _POSIX_
#endif
/*****************************************************************************/
/* Library access */
#if defined(UNIX)
# include <unistd.h>
#endif
#if defined(_POSIX_VERSION)
# include <fcntl.h>
# ifndef HAVE_ISATTY
# define HAVE_ISATTY
# endif
#endif
#if defined(MSDOS) || defined(OS2) || defined(WINDOWS) || defined(__CYGWIN__)
/* Add more systems here, e.g. MacOS 9 and earlier. */
# include <fcntl.h>
# include <io.h>
# ifndef HAVE_ISATTY
# define HAVE_ISATTY
# endif
# ifndef HAVE_SETMODE
# define HAVE_SETMODE
# endif
#endif
/* Standard I/O handles. */
#define STDIN 0
#define STDOUT 1
#define STDERR 2
/* Provide a placeholder for O_BINARY, if it doesn't exist. */
#ifndef O_BINARY
# define O_BINARY 0
#endif
#endif /* SYSCONF_H */

@ -0,0 +1,204 @@
/* zpipe.c: example of proper use of zlib's inflate() and deflate()
Not copyrighted -- provided to the public domain
Version 1.4 11 December 2005 Mark Adler */
/* Version history:
1.0 30 Oct 2004 First version
1.1 8 Nov 2004 Add void casting for unused return values
Use switch statement for inflate() return values
1.2 9 Nov 2004 Add assertions to document zlib guarantees
1.3 6 Apr 2005 Remove incorrect assertion in inf()
1.4 11 Dec 2005 Add hack to avoid MSDOS end-of-line conversions
Avoid some compiler warnings for input and output buffers
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "miniz.h"
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
# include <fcntl.h>
# include <io.h>
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
# define SET_BINARY_MODE(file)
#endif
#define CHUNK 16384
/* Compress from file source to file dest until EOF on source.
def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_STREAM_ERROR if an invalid compression
level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
version of the library linked do not match, or Z_ERRNO if there is
an error reading or writing the files. */
int def(FILE *source, FILE *dest, int level)
{
int ret, flush;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];unsigned char out[CHUNK];
/* allocate deflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm, level);
if (ret != Z_OK)
return ret;
/* compress until end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = in;
/* run deflate() on input until output buffer not full, finish
compression if all of source has been read in */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, flush); /* no bad return value */
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
assert(strm.avail_in == 0); /* all input will be used */
/* done when last data in file processed */
} while (flush != Z_FINISH);
assert(ret == Z_STREAM_END); /* stream will be complete */
/* clean up and return */
(void)deflateEnd(&strm);
return Z_OK;
}
/* Decompress from file source to file dest until stream ends or EOF.
inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_DATA_ERROR if the deflate data is
invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
the version of the library linked do not match, or Z_ERRNO if there
is an error reading or writing the files. */
int inf(FILE *source, FILE *dest)
{
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
if (strm.avail_in == 0)
break;
strm.next_in = in;
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
/* report a zlib or i/o error */
void zerr(int ret)
{
fputs("zpipe: ", stderr);
switch (ret) {
case Z_ERRNO:
if (ferror(stdin))
fputs("error reading stdin\n", stderr);
if (ferror(stdout))
fputs("error writing stdout\n", stderr);
break;
case Z_STREAM_ERROR:
fputs("invalid compression level\n", stderr);
break;
case Z_DATA_ERROR:
fputs("invalid or incomplete deflate data\n", stderr);
break;
case Z_MEM_ERROR:
fputs("out of memory\n", stderr);
break;
case Z_VERSION_ERROR:
fputs("zlib version mismatch!\n", stderr);
}
}
/* compress or decompress from stdin to stdout */
int main(int argc, char **argv)
{
int ret;
/* avoid end-of-line conversions */
SET_BINARY_MODE(stdin);
SET_BINARY_MODE(stdout);
/* do compression if no arguments */
if (argc == 1) {
ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
if (ret != Z_OK)
zerr(ret);
return ret;
}
/* do decompression if -d specified */
else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
ret = inf(stdin, stdout);
if (ret != Z_OK)
zerr(ret);
return ret;
}
/* otherwise, report usage */
else {
fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
return 1;
}
}

@ -0,0 +1,17 @@
# TUN/TAP driver v9 for Windows
in order to set up tunnels on Windows, you will need
to instal this driver.
* v9.9.2.3 is for Windows 2000/XP/2003 (NDIS 5.0-based)
* v9.21.2 is for Windows Vista/7/8.1 and 10 (NDIS 6.0, forward-compatible with NDIS 10.0)
to instal, extract the corresponding version of the driver for your
platform and run `%ARCH%/install_tap.cmd` in an elevated shell
to remove *ALL* virtual tunnel adapters, run `%ARCH%/del_tap.cmd` in an elevated shell. Use the
Device Manager snap-in to remove individual adapter instances.
Both are signed by OpenVPN Inc, and are available for 32- and 64-bit archs.
-despair86

@ -22,6 +22,15 @@
#include <smmintrin.h>
#include <tmmintrin.h>
#ifndef __amd64__
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("sse2")))
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtsi64_si128(long long __a)
{
return (__m128i){ __a, 0 };
}
#endif
#include "../stream_chacha20.h"
#include "chacha20_dolbeau-avx2.h"

@ -41,13 +41,9 @@
#ifdef _WIN32
#include <windows.h>
#include <sys/timeb.h>
#define RtlGenRandom SystemFunction036
#if defined(__cplusplus)
extern "C"
#endif
BOOLEAN NTAPI
RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
#pragma comment(lib, "advapi32.lib")
#include <wincrypt.h>
#include <bcrypt.h>
typedef NTSTATUS (FAR PASCAL* CNGAPI_DRBG)(BCRYPT_ALG_HANDLE, UCHAR*, ULONG, ULONG);
#ifdef __BORLANDC__
#define _ftime ftime
#define _timeb timeb
@ -73,7 +69,7 @@ extern "C"
#ifndef TLS
#ifdef _WIN32
#define TLS __declspec(thread)
#define TLS __thread
#else
#define TLS
#endif
@ -114,10 +110,7 @@ static uint64_t
sodium_hrtime(void)
{
struct _timeb tb;
#pragma warning(push)
#pragma warning(disable : 4996)
_ftime(&tb);
#pragma warning(pop)
return ((uint64_t)tb.time) * 1000000U + ((uint64_t)tb.millitm) * 1000U;
}
@ -391,9 +384,40 @@ randombytes_salsa20_random_stir(void)
#endif
#else /* _WIN32 */
if(!RtlGenRandom((PVOID)m0, (ULONG)sizeof m0))
HANDLE hCAPINg;
BOOL rtld;
CNGAPI_DRBG getrandom;
HCRYPTPROV hProv;
/* load bcrypt dynamically, see if we're already loaded */
rtld = FALSE;
hCAPINg = GetModuleHandle("bcrypt.dll");
/* otherwise, load CNG manually */
if (!hCAPINg)
{
sodium_misuse(); /* LCOV_EXCL_LINE */
hCAPINg = LoadLibraryEx("bcrypt.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
rtld = TRUE;
}
if (hCAPINg)
{
/* call BCryptGenRandom(2) */
getrandom = GetProcAddress(hCAPINg, "BCryptGenRandom");
if(!BCRYPT_SUCCESS(getrandom(NULL, m0, sizeof m0,BCRYPT_USE_SYSTEM_PREFERRED_RNG)))
{
sodium_misuse();
}
/* don't leak lib refs */
if (rtld)
FreeLibrary(hCAPINg);
}
/* if that fails use the regular ARC4-SHA1 RNG (!!!) *cringes* */
else
{
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
if (!CryptGenRandom(hProv, sizeof m0, m0))
{
sodium_misuse(); /* LCOV_EXCL_LINE */
}
CryptReleaseContext(hProv, 0);
}
#endif

@ -4,6 +4,12 @@
#include <sodium/export.h>
// optimise the bit-flipping codepaths if we're on ix86
#if defined(_WIN32) || defined(_M_IX86) || defined(_M_X64) \
|| defined(__i386__) || defined(__amd64__)
#define NATIVE_LITTLE_ENDIAN 1
#endif
#ifdef __cplusplus
extern "C"
{

@ -61,7 +61,7 @@ crypto_stream_salsa20_keygen(unsigned char k[crypto_stream_salsa20_KEYBYTES])
int
_crypto_stream_salsa20_pick_best_implementation(void)
{
#if __AVX2__
#if __AVX2__ && __amd64__
implementation = &crypto_stream_salsa20_xmm6_implementation;
#else
implementation = &crypto_stream_salsa20_ref_implementation;

@ -1,4 +1,4 @@
#if __AVX2__
#if __AVX2__ && __amd64__
.text
.p2align 5

@ -2,7 +2,7 @@
#include <stdint.h>
#include <sodium/utils.h>
#ifdef __amd64__
#include "../stream_salsa20.h"
#include "salsa20_xmm6.h"
@ -27,3 +27,4 @@ struct crypto_stream_salsa20_implementation
SODIUM_C99(.stream =) stream_salsa20_xmm6,
SODIUM_C99(.stream_xor_ic =) stream_salsa20_xmm6_xor_ic,
};
#endif

@ -22,6 +22,15 @@
#include <smmintrin.h>
#include <tmmintrin.h>
#ifndef __amd64__
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("sse2")))
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtsi64_si128(long long __a)
{
return (__m128i){ __a, 0 };
}
#endif
#include "../stream_salsa20.h"
#include "salsa20_xmm6int-avx2.h"

@ -1,3 +1,7 @@
/* [Rtl]SecureZeroMemory is an inline procedure in the windows headers */
#ifdef _WIN32
#include <windows.h>
#endif
#include <sodium/utils.h>
void

@ -1,7 +1,4 @@
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <llarp.h>
#include <llarp/dns_iptracker.hpp>
#include <llarp/dnsd.hpp>
@ -10,11 +7,6 @@
#include <llarp/threading.hpp> // for multithreaded version (multiplatorm)
#include <signal.h> // Linux needs this for SIGINT
// keep this once jeff reenables concurrency
#ifdef _MSC_VER
extern "C" void
SetThreadName(DWORD dwThreadID, LPCSTR szThreadName);
#endif
#ifdef _WIN32
#define uint UINT

@ -4,9 +4,7 @@
#include <getopt.h>
#include <string>
#include <iostream>
#ifndef _MSC_VER
#include <libgen.h>
#endif
#include "fs.hpp"
#include "config.hpp" // for ensure_config
@ -37,9 +35,6 @@ startWinsock()
{
WSADATA wsockd;
int err;
// We used to defer starting winsock until
// we got to the iocp event loop
// but getaddrinfo(3) requires that winsock be in core already
err = ::WSAStartup(MAKEWORD(2, 2), &wsockd);
if(err)
{
@ -86,8 +81,8 @@ main(int argc, char *argv[])
case 'r':
#ifdef _WIN32
llarp::LogError(
"we will not run as relay because you're running windows, install "
"a real operating system please");
"please don't try this at home, the relay feature is untested on "
"windows server --R.");
return 1;
#endif
asRouter = true;

@ -0,0 +1,10 @@
FROM debian:latest
RUN apt update && \
apt install -y build-essential cmake git libcap-dev wget rapidjson-dev
WORKDIR /src/
COPY . /src/
RUN make -j 8 JSONRPC=ON

@ -0,0 +1,11 @@
FROM fedora:latest
RUN dnf update -y && \
dnf upgrade -y && \
dnf install -y cmake make git gcc gcc-c++ libcap-devel wget rapidjson-devel
WORKDIR /src/
COPY . /src/
RUN make -j8 JSONRPC=ON

@ -1,11 +1,5 @@
#ifndef LLARP_CODEL_QUEUE_HPP
#define LLARP_CODEL_QUEUE_HPP
#ifdef _MSC_VER
#define NOMINMAX
#ifdef min
#undef min
#endif
#endif
#include <llarp/time.h>
#include <llarp/logger.hpp>
#include <llarp/mem.hpp>

@ -20,11 +20,23 @@ namespace llarp
operator^(const Key_t& other) const
{
Key_t dist;
for(size_t idx = 0; idx < 4; ++idx)
for(size_t idx = 0; idx < (size() / sizeof(l[0])); ++idx)
dist.l[idx] = l[idx] ^ other.l[idx];
return dist;
}
bool
operator==(const Key_t& other) const
{
return memcmp(data(), other.data(), 32) == 0;
}
bool
operator!=(const Key_t& other) const
{
return memcmp(data(), other.data(), 32) != 0;
}
bool
operator<(const Key_t& other) const
{

@ -1,6 +1,6 @@
#ifndef LLARP_EV_H
#define LLARP_EV_H
#if defined(__MINGW32__) || defined(_WIN32)
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
@ -8,7 +8,6 @@
#define ssize_t long
#endif
#else
#include <netinet/in.h>
#include <sys/socket.h>
#endif
@ -17,6 +16,7 @@
#include <stdlib.h>
#include <tuntap.h>
#include <llarp/time.h>
/**
* ev.h
*
@ -113,6 +113,29 @@ llarp_tcp_conn_async_write(struct llarp_tcp_conn *, const void *, size_t);
void
llarp_tcp_conn_close(struct llarp_tcp_conn *);
/// handles outbound connections to 1 endpoint
struct llarp_tcp_connecter
{
/// remote address family
int af;
/// remote address string
char remote[512];
/// userdata pointer
void *user;
/// parent event loop (dont set me)
struct llarp_ev_loop *loop;
/// handle outbound connection made
void (*connected)(struct llarp_tcp_connecter *, struct llarp_tcp_conn *);
/// handle outbound connection error
void (*error)(struct llarp_tcp_connecter *);
};
/// async try connecting to a remote connection 1 time
void
llarp_tcp_async_try_connect(struct llarp_ev_loop *l,
struct llarp_tcp_connecter *tcp);
/// handles inbound connections
struct llarp_tcp_acceptor
{
/// userdata pointer
@ -121,7 +144,7 @@ struct llarp_tcp_acceptor
void *impl;
/// parent event loop (dont set me)
struct llarp_ev_loop *loop;
/// handle tick
/// handle event loop tick
void (*tick)(struct llarp_tcp_acceptor *);
/// handle inbound connection
void (*accepted)(struct llarp_tcp_acceptor *, struct llarp_tcp_conn *);

@ -160,11 +160,11 @@ namespace llarp
// update ip packet (after packet gets out of network)
void
UpdatePacketOnDst(huint32_t nSrcIP, huint32_t nDstIP);
UpdateIPv4PacketOnDst(huint32_t newSrcIP, huint32_t newDstIP);
// update ip packet (before packet gets inserted into network)
void
UpdatePacketOnSrc();
UpdateIPv4PacketOnSrc();
};
} // namespace net

@ -5,7 +5,6 @@
#include <ws2tcpip.h>
#include <wspiapi.h>
// because this shit is not defined for Windows NT reeeee
#ifndef _MSC_VER
#ifdef __cplusplus
extern "C"
{
@ -17,7 +16,6 @@ extern "C"
#ifdef __cplusplus
}
#endif
#endif
#ifndef ssize_t
#define ssize_t long
#endif

@ -6,7 +6,7 @@
#include <iostream>
#include "logger.hpp"
#include "mem.hpp"
#include <llarp/string_view.hpp>
#include <vector>
#include <stdlib.h> // for itoa

@ -3,6 +3,8 @@
#include <llarp/time.h>
#include <llarp/ev.h>
#include <string>
#include <functional>
#include <llarp/crypto.hpp>
// forward declare
struct llarp_router;
@ -13,6 +15,7 @@ namespace llarp
{
struct ServerImpl;
/// jsonrpc server
struct Server
{
Server(llarp_router* r);
@ -25,6 +28,27 @@ namespace llarp
ServerImpl* m_Impl;
};
struct CallerImpl;
/// jsonrpc caller
struct Caller
{
Caller(llarp_router* r);
~Caller();
/// start with jsonrpc endpoint address
bool
Start(const std::string& remote);
/// async test if a router is valid via jsonrpc
void
AsyncVerifyRouter(llarp::PubKey pkey,
std::function< void(llarp::PubKey, bool) > handler);
private:
CallerImpl* m_Impl;
};
} // namespace rpc
} // namespace llarp

@ -0,0 +1,29 @@
#ifndef LLARP_STRING_VIEW_HPP
#define LLARP_STRING_VIEW_HPP
#if __cplusplus >= 201703L
#include <string_view>
#include <string>
namespace llarp
{
typedef std::string_view string_view;
static std::string
string_view_string(const string_view& v)
{
return std::string(v.data(), v.size());
}
} // namespace llarp
#else
#include <string>
namespace llarp
{
typedef std::string string_view;
static std::string
string_view_string(const string_view& v)
{
return v;
};
} // namespace llarp
#endif
#endif

@ -0,0 +1,118 @@
#ifndef __ABYSS_CLIENT_HPP__
#define __ABYSS_CLIENT_HPP__
#include <string>
#include <memory>
#include <list>
#include <deque>
#include <unordered_map>
#include <functional>
#include <llarp/string_view.hpp>
#include <abyss/json.hpp>
#include <llarp/ev.h>
namespace abyss
{
namespace http
{
typedef std::string RPC_Method_t;
typedef json::Value RPC_Params;
typedef json::Document RPC_Response;
typedef std::unordered_multimap< std::string, std::string > Headers_t;
struct ConnImpl;
/// jsonrpc response handler for client
struct IRPCClientHandler
{
IRPCClientHandler(ConnImpl* impl);
virtual ~IRPCClientHandler();
/// handle response from rpc server
/// return true on successful handling
/// return false on errors while handling
virtual bool
HandleResponse(const RPC_Response& response) = 0;
/// populate http request headers
virtual void
PopulateReqHeaders(Headers_t& hdr) = 0;
/// handle fatal internal error while doing request
virtual void
HandleError() = 0;
/// return true if we should close
bool
ShouldClose() const;
/// close underlying connection
void
Close() const;
private:
ConnImpl* m_Impl;
};
/// jsonrpc client
struct JSONRPC
{
typedef std::function< IRPCClientHandler*(ConnImpl*) > HandlerFactory;
JSONRPC();
~JSONRPC();
/// start runing on event loop async
/// return true on success otherwise return false
bool
RunAsync(llarp_ev_loop* loop, const std::string& endpoint);
/// must be called after RunAsync returns true
/// queue a call for rpc
void
QueueRPC(RPC_Method_t method, RPC_Params params,
HandlerFactory createHandler);
/// drop all pending calls on the floor
void
DropAllCalls();
/// handle new outbound connection
void
Connected(llarp_tcp_conn* conn);
/// flush queued rpc calls
void
Flush();
private:
struct Call
{
Call(RPC_Method_t&& m, RPC_Params&& p, HandlerFactory&& f)
: method(std::move(m))
, params(std::move(p))
, createHandler(std::move(f))
{
}
RPC_Method_t method;
RPC_Params params;
HandlerFactory createHandler;
};
static void
OnConnected(llarp_tcp_connecter* connect, llarp_tcp_conn* conn);
static void
OnConnectFail(llarp_tcp_connecter* connect);
static void
OnTick(llarp_tcp_connecter* connect);
llarp_tcp_connecter m_connect;
llarp_ev_loop* m_Loop;
std::deque< Call > m_PendingCalls;
std::list< std::unique_ptr< IRPCClientHandler > > m_Conns;
};
} // namespace http
} // namespace abyss
#endif

@ -0,0 +1,36 @@
#ifndef __ABYSS_HTTP_HPP__
#define __ABYSS_HTTP_HPP__
#include <string>
#include <unordered_map>
#include <llarp/string_view.hpp>
#include <abyss/json.hpp>
namespace abyss
{
namespace http
{
struct RequestHeader
{
typedef std::unordered_multimap< std::string, std::string > Headers_t;
Headers_t Headers;
std::string Method;
std::string Path;
};
struct HeaderReader
{
RequestHeader Header;
virtual ~HeaderReader()
{
}
bool
ProcessHeaderLine(abyss::string_view line, bool& done);
virtual bool
ShouldProcessHeader(const abyss::string_view& line) const = 0;
};
} // namespace http
} // namespace abyss
#endif

@ -7,12 +7,13 @@
#include <list>
#include <memory>
#include <string>
#include <llarp/string_view.hpp>
#include <abyss/json.hpp>
#include <unordered_map>
namespace abyss
{
namespace http
namespace httpd
{
struct ConnImpl;
@ -49,6 +50,10 @@ namespace abyss
void
RemoveConn(IRPCHandler* handler);
/// close the handler and acceptor
void
Close();
llarp_time_t
now() const
{
@ -57,7 +62,7 @@ namespace abyss
protected:
virtual IRPCHandler*
CreateHandler(ConnImpl* connimpl) const = 0;
CreateHandler(ConnImpl* connimpl) = 0;
private:
static void
@ -75,7 +80,7 @@ namespace abyss
std::list< std::unique_ptr< IRPCHandler > > m_Conns;
llarp_time_t m_ReqTimeout;
};
} // namespace http
} // namespace httpd
} // namespace abyss
#endif

@ -1,5 +1,5 @@
#ifndef __LIB_ABYSS_HPP__
#define __LIB_ABYSS_HPP__
#include <abyss/server.hpp>
#include <abyss/json.hpp>
#include <abyss/client.hpp>
#endif

@ -1,10 +1,12 @@
#include <libabyss.hpp>
#include <llarp/net.hpp>
#ifndef _WIN32
#include <sys/signal.h>
#endif
struct DemoHandler : public abyss::http::IRPCHandler
struct DemoHandler : public abyss::httpd::IRPCHandler
{
DemoHandler(abyss::http::ConnImpl* impl) : abyss::http::IRPCHandler(impl)
DemoHandler(abyss::httpd::ConnImpl* impl) : abyss::httpd::IRPCHandler(impl)
{
}
@ -18,14 +20,61 @@ struct DemoHandler : public abyss::http::IRPCHandler
}
};
struct DemoServer : public abyss::http::BaseReqHandler
struct DemoCall : public abyss::http::IRPCClientHandler
{
DemoServer() : abyss::http::BaseReqHandler(1000)
DemoCall(abyss::http::ConnImpl* impl) : abyss::http::IRPCClientHandler(impl)
{
llarp::LogInfo("new call");
}
abyss::http::IRPCHandler*
CreateHandler(abyss::http::ConnImpl* impl) const
bool
HandleResponse(const abyss::http::RPC_Response& resp)
{
std::string body;
abyss::json::ToString(resp, body);
llarp::LogInfo("got response body: ", body);
return true;
}
void
PopulateReqHeaders(abyss::http::Headers_t& hdr)
{
}
void
HandleError()
{
llarp::LogError("error while handling call: ", strerror(errno));
}
};
struct DemoClient : public abyss::http::JSONRPC
{
abyss::http::IRPCClientHandler*
NewConn(abyss::http::ConnImpl* impl)
{
return new DemoCall(impl);
}
void
DoDemoRequest()
{
abyss::json::Value params;
params.SetObject();
QueueRPC("test", std::move(params),
std::bind(&DemoClient::NewConn, this, std::placeholders::_1));
Flush();
};
};
struct DemoServer : public abyss::httpd::BaseReqHandler
{
DemoServer() : abyss::httpd::BaseReqHandler(1000)
{
}
abyss::httpd::IRPCHandler*
CreateHandler(abyss::httpd::ConnImpl* impl)
{
return new DemoHandler(impl);
}
@ -34,7 +83,22 @@ struct DemoServer : public abyss::http::BaseReqHandler
int
main(int argc, char* argv[])
{
// Ignore on Windows, we don't even get SIGPIPE (even though native *and*
// emulated UNIX pipes exist - CreatePipe(2), pipe(3))
// Microsoft libc only covers six signals
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#else
WSADATA wsockd;
int err;
err = ::WSAStartup(MAKEWORD(2, 2), &wsockd);
if(err)
{
perror("Failed to start Windows Sockets");
return err;
}
#endif
llarp::SetLogLevel(llarp::eLogDebug);
llarp_threadpool* threadpool = llarp_init_same_process_threadpool();
llarp_ev_loop* loop = nullptr;
llarp_ev_loop_alloc(&loop);
@ -44,12 +108,15 @@ main(int argc, char* argv[])
addr.sin_port = htons(1222);
addr.sin_family = AF_INET;
DemoServer serv;
DemoClient client;
llarp::Addr a(addr);
while(true)
{
llarp::LogInfo("bind to ", a);
if(serv.ServeAsync(loop, logic, a))
{
client.RunAsync(loop, a.ToString());
client.DoDemoRequest();
llarp_ev_loop_run_single_process(loop, threadpool, logic);
return 0;
}

@ -0,0 +1,399 @@
#include <abyss/client.hpp>
#include <abyss/http.hpp>
#include <llarp/logger.hpp>
#include <llarp/crypto.hpp>
namespace abyss
{
namespace http
{
struct ConnImpl : HeaderReader
{
// big
static const size_t MAX_BODY_SIZE = (1024 * 1024);
llarp_tcp_conn* m_Conn;
json::Document m_RequestBody;
Headers_t m_SendHeaders;
IRPCClientHandler* handler;
std::unique_ptr< abyss::json::IParser > m_BodyParser;
json::Document m_Response;
enum State
{
eInitial,
eReadStatusLine,
eReadResponseHeader,
eReadResponseBody,
eCloseMe
};
State state;
ConnImpl(llarp_tcp_conn* conn, RPC_Method_t method, RPC_Params params,
JSONRPC::HandlerFactory factory)
: m_Conn(conn), state(eInitial)
{
srand(time(nullptr));
conn->user = this;
conn->closed = &ConnImpl::OnClosed;
conn->read = &ConnImpl::OnRead;
conn->tick = &ConnImpl::OnTick;
handler = factory(this);
m_RequestBody.SetObject();
auto& alloc = m_RequestBody.GetAllocator();
m_RequestBody.AddMember("jsonrpc", json::Value().SetString("2.0"),
alloc);
m_RequestBody.AddMember("id", json::Value(abs(rand())), alloc);
m_RequestBody.AddMember(
"method", json::Value().SetString(method.c_str(), alloc), alloc);
m_RequestBody.AddMember("params", params, alloc);
}
static void
OnClosed(llarp_tcp_conn* conn)
{
ConnImpl* self = static_cast< ConnImpl* >(conn->user);
self->state = eCloseMe;
}
static void
OnRead(llarp_tcp_conn* conn, const void* buf, size_t sz)
{
ConnImpl* self = static_cast< ConnImpl* >(conn->user);
if(!self->ProcessRead((const char*)buf, sz))
self->CloseError();
}
static void
OnTick(llarp_tcp_conn* conn)
{
}
bool
ProcessStatusLine(string_view line) const
{
auto idx = line.find_first_of(' ');
if(idx == string_view::npos)
return false;
string_view codePart = line.substr(1 + idx);
idx = codePart.find_first_of(' ');
if(idx == string_view::npos)
return false;
return HandleStatusCode(codePart.substr(0, idx));
}
bool
ShouldProcessHeader(const abyss::string_view& name) const
{
return name == "content-length" || name == "content-type";
}
/// return true if we get a 200 status code
bool
HandleStatusCode(string_view code) const
{
return code == "200";
}
bool
ProcessBody(const char* buf, size_t sz)
{
// init parser
if(m_BodyParser == nullptr)
{
size_t contentSize = 0;
auto itr = Header.Headers.find("content-length");
// no content-length header
if(itr == Header.Headers.end())
return false;
// check size
contentSize = std::stoul(itr->second);
if(contentSize > MAX_BODY_SIZE)
return false;
m_BodyParser.reset(abyss::json::MakeParser(contentSize));
}
if(m_BodyParser && m_BodyParser->FeedData(buf, sz))
{
switch(m_BodyParser->Parse(m_Response))
{
case json::IParser::eNeedData:
return true;
case json::IParser::eDone:
handler->HandleResponse(m_Response);
Close();
return true;
case json::IParser::eParseError:
handler->HandleError();
return false;
default:
return false;
}
}
else
return false;
}
bool
ProcessRead(const char* buf, size_t sz)
{
if(state == eInitial)
return true;
if(sz == 0)
return true;
bool done = false;
while(state < eReadResponseBody)
{
const char* end = strstr(buf, "\r\n");
if(end == nullptr)
return false;
string_view line(buf, end - buf);
switch(state)
{
case eReadStatusLine:
if(!ProcessStatusLine(line))
return false;
sz -= line.size() + (2 * sizeof(char));
state = eReadResponseHeader;
break;
case eReadResponseHeader:
if(!ProcessHeaderLine(line, done))
return false;
sz -= line.size() + (2 * sizeof(char));
if(done)
state = eReadResponseBody;
break;
default:
break;
}
buf = end + (2 * sizeof(char));
end = strstr(buf, "\r\n");
}
if(state == eReadResponseBody)
return ProcessBody(buf, sz);
return state == eCloseMe;
}
bool
ShouldClose() const
{
return state == eCloseMe;
}
void
CloseError()
{
if(handler)
handler->HandleError();
handler = nullptr;
Close();
}
void
Close()
{
if(m_Conn)
llarp_tcp_conn_close(m_Conn);
m_Conn = nullptr;
}
void
SendRequest()
{
// populate request headers
handler->PopulateReqHeaders(m_SendHeaders);
// create request body
std::string body;
json::ToString(m_RequestBody, body);
// request base
char buf[512] = {0};
int sz = snprintf(buf, sizeof(buf),
"POST /rpc HTTP/1.0\r\nContent-Type: "
"application/json\r\nContent-Length: %lu\r\nAccept: "
"application/json\r\n",
body.size());
if(sz <= 0)
return;
if(!llarp_tcp_conn_async_write(m_Conn, buf, sz))
{
llarp::LogError("failed to write first part of request");
CloseError();
return;
}
// header delimiter
buf[0] = ':';
buf[1] = ' ';
// CRLF
buf[2] = '\r';
buf[3] = '\n';
// write extra request header
for(const auto& item : m_SendHeaders)
{
// header name
if(!llarp_tcp_conn_async_write(m_Conn, item.first.c_str(),
item.first.size()))
{
CloseError();
return;
}
// header delimiter
if(!llarp_tcp_conn_async_write(m_Conn, buf, 2 * sizeof(char)))
{
CloseError();
return;
}
// header value
if(!llarp_tcp_conn_async_write(m_Conn, item.second.c_str(),
item.second.size()))
{
CloseError();
return;
}
// CRLF
if(!llarp_tcp_conn_async_write(m_Conn, buf + 2, 2 * sizeof(char)))
{
CloseError();
return;
}
}
// CRLF
if(!llarp_tcp_conn_async_write(m_Conn, buf + 2, 2 * sizeof(char)))
{
CloseError();
return;
}
// request body
if(!llarp_tcp_conn_async_write(m_Conn, body.c_str(), body.size()))
{
CloseError();
return;
}
llarp::LogDebug("request sent");
state = eReadStatusLine;
}
};
void
JSONRPC::Flush()
{
/// close idle connections
auto itr = m_Conns.begin();
while(itr != m_Conns.end())
{
if((*itr)->ShouldClose())
{
(*itr)->Close();
itr = m_Conns.erase(itr);
}
else
++itr;
}
// open at most 10 connections
size_t numCalls = std::min(m_PendingCalls.size(), 10UL);
llarp::LogDebug("tick connect to rpc ", numCalls, " times");
while(numCalls--)
{
llarp_tcp_async_try_connect(m_Loop, &m_connect);
}
}
IRPCClientHandler::IRPCClientHandler(ConnImpl* impl) : m_Impl(impl)
{
}
bool
IRPCClientHandler::ShouldClose() const
{
return m_Impl && m_Impl->ShouldClose();
}
void
IRPCClientHandler::Close() const
{
if(m_Impl)
m_Impl->Close();
}
IRPCClientHandler::~IRPCClientHandler()
{
if(m_Impl)
delete m_Impl;
}
JSONRPC::JSONRPC()
{
}
JSONRPC::~JSONRPC()
{
}
void
JSONRPC::QueueRPC(RPC_Method_t method, RPC_Params params,
HandlerFactory createHandler)
{
m_PendingCalls.emplace_back(std::move(method), std::move(params),
std::move(createHandler));
}
bool
JSONRPC::RunAsync(llarp_ev_loop* loop, const std::string& remote)
{
strncpy(m_connect.remote, remote.c_str(), sizeof(m_connect.remote));
// TODO: ipv6
m_connect.connected = &JSONRPC::OnConnected;
m_connect.error = &JSONRPC::OnConnectFail;
m_connect.user = this;
m_connect.af = AF_INET;
m_Loop = loop;
return true;
}
void
JSONRPC::OnConnectFail(llarp_tcp_connecter* tcp)
{
JSONRPC* self = static_cast< JSONRPC* >(tcp->user);
llarp::LogError("failed to connect to RPC, dropped all pending calls");
self->DropAllCalls();
}
void
JSONRPC::OnConnected(llarp_tcp_connecter* tcp, llarp_tcp_conn* conn)
{
JSONRPC* self = static_cast< JSONRPC* >(tcp->user);
llarp::LogDebug("connected to RPC");
self->Connected(conn);
}
void
JSONRPC::Connected(llarp_tcp_conn* conn)
{
auto& front = m_PendingCalls.front();
ConnImpl* connimpl =
new ConnImpl(conn, std::move(front.method), std::move(front.params),
std::move(front.createHandler));
m_PendingCalls.pop_front();
m_Conns.emplace_back(connimpl->handler);
connimpl->SendRequest();
}
void
JSONRPC::DropAllCalls()
{
while(m_PendingCalls.size())
{
auto& front = m_PendingCalls.front();
IRPCClientHandler* h = front.createHandler(nullptr);
h->HandleError();
delete h;
m_PendingCalls.pop_front();
}
}
} // namespace http
} // namespace abyss

@ -0,0 +1,36 @@
#include <abyss/http.hpp>
#include <algorithm>
namespace abyss
{
namespace http
{
bool
HeaderReader::ProcessHeaderLine(string_view line, bool& done)
{
if(line.size() == 0)
{
done = true;
return true;
}
auto idx = line.find_first_of(':');
if(idx == string_view::npos)
return false;
string_view header = line.substr(0, idx);
string_view val = line.substr(1 + idx);
// to lowercase
std::string lowerHeader;
auto itr = header.begin();
while(itr != header.end())
{
lowerHeader += ::tolower(*itr);
++itr;
}
if(ShouldProcessHeader(string_view(lowerHeader)))
{
val = val.substr(val.find_first_not_of(' '));
Header.Headers.insert(std::make_pair(lowerHeader, val));
}
return true;
}
} // namespace http
} // namespace abyss

@ -1,3 +1,4 @@
#include <llarp/string_view.hpp>
#include <abyss/json.hpp>
#include <vector>
#include <cstring>

@ -1,4 +1,5 @@
#include <abyss/server.hpp>
#include <abyss/http.hpp>
#include <llarp/time.h>
#include <sstream>
#include <unordered_map>
@ -8,17 +9,9 @@
namespace abyss
{
namespace http
namespace httpd
{
struct RequestHeader
{
typedef std::unordered_multimap< std::string, std::string > Headers_t;
Headers_t Headers;
std::string Method;
std::string Path;
};
struct ConnImpl
struct ConnImpl : abyss::http::HeaderReader
{
llarp_tcp_conn* _conn;
IRPCHandler* handler;
@ -26,7 +19,6 @@ namespace abyss
llarp_time_t m_LastActive;
llarp_time_t m_ReadTimeout;
bool m_Bad;
RequestHeader m_Header;
std::unique_ptr< abyss::json::IParser > m_BodyParser;
json::Document m_Request;
json::Document m_Response;
@ -66,12 +58,17 @@ namespace abyss
bool
FeedLine(std::string& line)
{
bool done = false;
switch(m_State)
{
case eReadHTTPMethodLine:
return ProcessMethodLine(line);
case eReadHTTPHeaders:
return ProcessHeaderLine(line);
if(!ProcessHeaderLine(line, done))
return false;
if(done)
m_State = eReadHTTPBody;
return true;
default:
return false;
}
@ -83,13 +80,13 @@ namespace abyss
auto idx = line.find_first_of(' ');
if(idx == string_view::npos)
return false;
m_Header.Method = line.substr(0, idx);
line = line.substr(idx + 1);
idx = line.find_first_of(' ');
Header.Method = line.substr(0, idx);
line = line.substr(idx + 1);
idx = line.find_first_of(' ');
if(idx == string_view::npos)
return false;
m_Header.Path = line.substr(0, idx);
m_State = eReadHTTPHeaders;
Header.Path = line.substr(0, idx);
m_State = eReadHTTPHeaders;
return true;
}
@ -100,82 +97,37 @@ namespace abyss
return name == "content-type" || name == "content-length";
}
bool
ProcessHeaderLine(string_view line)
{
if(line.size() == 0)
{
// end of headers
m_State = eReadHTTPBody;
return true;
}
auto idx = line.find_first_of(':');
if(idx == string_view::npos)
return false;
string_view header = line.substr(0, idx);
string_view val = line.substr(1 + idx);
// to lowercase
std::transform(header.begin(), header.end(), header.begin(),
[](char ch) -> char { return ::tolower(ch); });
if(ShouldProcessHeader(header))
{
val = val.substr(val.find_first_not_of(' '));
m_Header.Headers.insert(std::make_pair(header, val));
}
return true;
}
bool
WriteStatusLine(int code, const std::string& message)
{
char buf[128] = {0};
int sz = snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\r\n", code,
message.c_str());
if(sz > 0)
{
return llarp_tcp_conn_async_write(_conn, buf, sz);
}
else
return false;
}
bool
WriteResponseSimple(int code, const std::string& msg,
const char* contentType, const char* content)
{
if(!WriteStatusLine(code, msg))
return false;
char buf[128] = {0};
int sz =
snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", contentType);
if(sz <= 0)
return false;
if(!llarp_tcp_conn_async_write(_conn, buf, sz))
return false;
char buf[512] = {0};
size_t contentLength = strlen(content);
sz = snprintf(buf, sizeof(buf), "Content-Length: %zu\r\n\r\n",
contentLength);
int sz = snprintf(buf, sizeof(buf),
"HTTP/1.0 %d %s\r\nContent-Type: "
"%s\r\nContent-Length: %zu\r\n\r\n",
code, msg.c_str(), contentType, contentLength);
if(sz <= 0)
return false;
if(!llarp_tcp_conn_async_write(_conn, buf, sz))
return false;
if(!llarp_tcp_conn_async_write(_conn, content, contentLength))
return false;
m_State = eWriteHTTPBody;
return true;
return llarp_tcp_conn_async_write(_conn, content, contentLength);
}
bool
FeedBody(const char* buf, size_t sz)
{
if(m_Header.Method != "POST")
if(Header.Method != "POST")
{
return WriteResponseSimple(405, "Method Not Allowed", "text/plain",
"nope");
}
{
auto itr = m_Header.Headers.find("content-type");
if(itr == m_Header.Headers.end())
auto itr = Header.Headers.find("content-type");
if(itr == Header.Headers.end())
{
return WriteResponseSimple(415, "Unsupported Media Type",
"text/plain",
@ -192,8 +144,8 @@ namespace abyss
if(m_BodyParser == nullptr)
{
ssize_t contentLength = 0;
auto itr = m_Header.Headers.find("content-length");
if(itr == m_Header.Headers.end())
auto itr = Header.Headers.find("content-length");
if(itr == Header.Headers.end())
{
return WriteResponseSimple(400, "Bad Request", "text/plain",
"no content length");
@ -265,13 +217,18 @@ namespace abyss
return false;
}
if(sz == 0)
return true;
bool done = false;
m_LastActive = _parent->now();
if(m_State < eReadHTTPBody)
{
const char* end = strstr(buf, "\r\n");
while(end)
{
string_view line(buf, end);
string_view line(buf, end - buf);
switch(m_State)
{
case eReadHTTPMethodLine:
@ -280,9 +237,11 @@ namespace abyss
sz -= line.size() + (2 * sizeof(char));
break;
case eReadHTTPHeaders:
if(!ProcessHeaderLine(line))
if(!ProcessHeaderLine(line, done))
return false;
sz -= line.size() + (2 * sizeof(char));
if(done)
m_State = eReadHTTPBody;
break;
default:
break;
@ -399,18 +358,23 @@ namespace abyss
auto itr = m_Conns.begin();
while(itr != m_Conns.end())
{
if((*itr)->ShouldClose(_now)
if((*itr)->ShouldClose(_now))
itr = m_Conns.erase(itr);
else
++itr;
}
}
BaseReqHandler::~BaseReqHandler()
void
BaseReqHandler::Close()
{
llarp_tcp_acceptor_close(&m_acceptor);
}
BaseReqHandler::~BaseReqHandler()
{
}
void
BaseReqHandler::OnAccept(llarp_tcp_acceptor* acceptor, llarp_tcp_conn* conn)
{
@ -426,5 +390,5 @@ namespace abyss
connimpl->handler = rpcHandler;
self->m_Conns.emplace_back(rpcHandler);
}
} // namespace http
} // namespace httpd
} // namespace abyss

@ -3,10 +3,6 @@
#include <stdarg.h>
#include <stdio.h>
#ifndef ssize_t
#define ssize_t long
#endif
size_t
llarp_buffer_size_left(llarp_buffer_t buff)
{

@ -2,9 +2,7 @@
#include <llarp.h>
#include <llarp/logger.h>
#include <signal.h>
#ifndef _MSC_VER
#include <sys/param.h> // for MIN
#endif
#include <llarp.hpp>
#include "router.hpp"
@ -15,12 +13,6 @@
#include <pthread_np.h>
#endif
// keep this once jeff reenables concurrency
#ifdef _MSC_VER
extern "C" void
SetThreadName(DWORD dwThreadID, LPCSTR szThreadName);
#endif
#if _WIN32 || __sun
#define wmin(x, y) (((x) < (y)) ? (x) : (y))
#define MIN wmin

@ -385,9 +385,9 @@ namespace llarp
{
if(handleResult)
handleResult(valuesFound);
else
parent->DHTSendTo(whoasked.node,
new GotIntroMessage(valuesFound, whoasked.txid));
parent->DHTSendTo(whoasked.node,
new GotIntroMessage(valuesFound, whoasked.txid));
}
};
@ -398,7 +398,7 @@ namespace llarp
LocalServiceAddressLookup(const PathID_t &pathid, uint64_t txid,
const service::Address &addr, Context *ctx,
const Key_t &askpeer)
: ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, 4,
: ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, 5,
nullptr)
, localPath(pathid)
{

@ -147,8 +147,8 @@ namespace llarp
}
else
{
llarp::LogError(
"cannot find closer peers for introset lookup for ", S);
// no more closer peers
replies.emplace_back(new GotIntroMessage({}, T));
return true;
}
}
@ -165,7 +165,9 @@ namespace llarp
}
else
{
llarp::LogWarn("no closer peers for tag ", N.ToString());
// no more closer peers
replies.emplace_back(new GotIntroMessage({}, T));
return true;
}
}
else

@ -10,9 +10,7 @@
#include <stdlib.h> /* exit */
#include <string.h> /* memset */
#include <sys/types.h>
#ifndef _MSC_VER
#include <unistd.h> /* close */
#endif
#include <algorithm> // for std::find_if
#include <llarp/net.hpp> // for llarp::Addr

@ -1,5 +1,6 @@
#include <llarp/ev.h>
#include <llarp/logic.h>
#include <llarp/string_view.hpp>
#include "mem.hpp"
#define EV_TICK_INTERVAL 100
@ -7,13 +8,13 @@
// apparently current Solaris will emulate epoll.
#if __linux__ || __sun__
#include "ev_epoll.hpp"
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| (__APPLE__ && __MACH__)
#include "ev_kqueue.hpp"
#endif
#if defined(_WIN32) || defined(_WIN64) || defined(__NT__)
#elif defined(_WIN32) || defined(_WIN64) || defined(__NT__)
#include "ev_win32.hpp"
#else
#error No async event loop for your platform, subclass llarp_ev_loop
#endif
void
@ -21,13 +22,13 @@ llarp_ev_loop_alloc(struct llarp_ev_loop **ev)
{
#if __linux__ || __sun__
*ev = new llarp_epoll_loop;
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| (__APPLE__ && __MACH__)
*ev = new llarp_kqueue_loop;
#endif
#if defined(_WIN32) || defined(_WIN64) || defined(__NT__)
#elif defined(_WIN32) || defined(_WIN64) || defined(__NT__)
*ev = new llarp_win32_loop;
#else
#error no event loop subclass
#endif
(*ev)->init();
(*ev)->_now = llarp_time_now_ms();
@ -105,7 +106,7 @@ llarp_ev_udp_sendto(struct llarp_udp_io *udp, const sockaddr *to,
const void *buf, size_t sz)
{
auto ret = static_cast< llarp::ev_io * >(udp->impl)->sendto(to, buf, sz);
if(ret == -1 || errno)
if(ret == -1 && errno != 0)
{
llarp::LogWarn("sendto failed ", strerror(errno));
errno = 0;
@ -120,7 +121,7 @@ llarp_ev_add_tun(struct llarp_ev_loop *loop, struct llarp_tun_io *tun)
tun->impl = dev;
if(dev)
{
return loop->add_ev(dev);
return loop->add_ev(dev, false);
}
return false;
}
@ -132,7 +133,10 @@ llarp_tcp_conn_async_write(struct llarp_tcp_conn *conn, const void *pkt,
const byte_t *ptr = (const byte_t *)pkt;
llarp::tcp_conn *impl = static_cast< llarp::tcp_conn * >(conn->impl);
if(impl->_shouldClose)
{
llarp::LogError("write on closed connection");
return false;
}
while(sz > EV_WRITE_BUF_SZ)
{
if(!impl->queue_write((const byte_t *)ptr, EV_WRITE_BUF_SZ))
@ -143,6 +147,43 @@ llarp_tcp_conn_async_write(struct llarp_tcp_conn *conn, const void *pkt,
return impl->queue_write(ptr, sz);
}
void
llarp_tcp_async_try_connect(struct llarp_ev_loop *loop,
struct llarp_tcp_connecter *tcp)
{
tcp->loop = loop;
llarp::string_view addr_str, port_str;
// try parsing address
const char *begin = tcp->remote;
const char *ptr = strstr(tcp->remote, ":");
// get end of address
if(ptr == nullptr)
{
llarp::LogError("bad address: ", tcp->remote);
if(tcp->error)
tcp->error(tcp);
return;
}
const char *end = ptr;
while(*end && (end - begin) < sizeof(tcp->remote))
{
++end;
}
addr_str = llarp::string_view(begin, ptr - begin);
++ptr;
port_str = llarp::string_view(ptr, end - ptr);
// actually parse address
llarp::Addr addr(addr_str, port_str);
if(!loop->tcp_connect(tcp, addr))
{
llarp::LogError("async connect failed");
if(tcp->error)
tcp->error(tcp);
}
}
bool
llarp_tcp_serve(struct llarp_ev_loop *loop, struct llarp_tcp_acceptor *tcp,
const struct sockaddr *bindaddr)
@ -151,8 +192,7 @@ llarp_tcp_serve(struct llarp_ev_loop *loop, struct llarp_tcp_acceptor *tcp,
llarp::ev_io *impl = loop->bind_tcp(tcp, bindaddr);
if(impl)
{
tcp->impl = impl;
return loop->add_ev(impl);
return loop->add_ev(impl, false);
}
return false;
}
@ -193,75 +233,13 @@ namespace llarp
{
if(_shouldClose)
{
if(tcp && tcp->closed)
tcp->closed(tcp);
if(tcp.closed)
tcp.closed(&tcp);
return false;
}
else if(tcp->tick)
tcp->tick(tcp);
else if(tcp.tick)
tcp.tick(&tcp);
return true;
}
int
tcp_serv::read(void *, size_t)
{
int new_fd = ::accept(fd, nullptr, nullptr);
if(new_fd == -1)
{
llarp::LogError("failed to accept on ", fd, ":", strerror(errno));
return -1;
}
llarp_tcp_conn *conn = new llarp_tcp_conn;
// zero out callbacks
conn->tick = nullptr;
conn->closed = nullptr;
conn->read = nullptr;
// build handler
llarp::tcp_conn *connimpl = new tcp_conn(new_fd, conn);
conn->impl = connimpl;
conn->loop = loop;
if(loop->add_ev(connimpl, true))
{
// call callback
if(tcp->accepted)
tcp->accepted(tcp, conn);
return 0;
}
// cleanup error
delete conn;
delete connimpl;
return -1;
}
} // namespace llarp
llarp::ev_io *
llarp_ev_loop::bind_tcp(llarp_tcp_acceptor *tcp, const sockaddr *bindaddr)
{
int fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
{
sz = sizeof(sockaddr_in6);
}
else if(bindaddr->sa_family == AF_UNIX)
{
sz = sizeof(sockaddr_un);
}
if(::bind(fd, bindaddr, sz) == -1)
{
::close(fd);
return nullptr;
}
if(::listen(fd, 5) == -1)
{
::close(fd);
return nullptr;
}
llarp::ev_io *serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
return serv;
}
} // namespace llarp

@ -10,6 +10,7 @@
#include <llarp/codel.hpp>
#include <list>
#include <deque>
#include <algorithm>
#ifdef _WIN32
#include <variant>
@ -28,13 +29,14 @@
namespace llarp
{
struct ev_io
#ifdef _WIN32
struct win32_ev_io
{
struct WriteBuffer
{
llarp_time_t timestamp = 0;
size_t bufsz;
byte_t buf[EV_WRITE_BUF_SZ];
byte_t buf[EV_WRITE_BUF_SZ] = {0};
WriteBuffer() = default;
@ -89,36 +91,33 @@ namespace llarp
typedef std::deque< WriteBuffer > LosslessWriteQueue_t;
#ifndef _WIN32
int fd;
int flags = 0;
ev_io(int f) : fd(f)
{
}
// on windows, tcp/udp event loops are socket fds
// and TUN device is a plain old fd
std::variant< SOCKET, HANDLE > fd;
ULONG_PTR listener_id = 0;
bool isTCP = false;
bool write = false;
WSAOVERLAPPED portfd[2];
/// for tun
ev_io(int f, LossyWriteQueue_t* q) : fd(f), m_LossyWriteQueue(q)
// constructors
// for udp
win32_ev_io(SOCKET f) : fd(f)
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
};
// for tun
win32_ev_io(HANDLE t, LossyWriteQueue_t* q) : fd(t), m_LossyWriteQueue(q)
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
}
/// for tcp
ev_io(int f, LosslessWriteQueue_t* q) : fd(f), m_BlockingWriteQueue(q)
// for tcp
win32_ev_io(SOCKET f, LosslessWriteQueue_t* q)
: fd(f), m_BlockingWriteQueue(q)
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
isTCP = true;
}
#else
// on windows, udp event loops are socket fds
// and TUN device is a plain old fd
std::variant< SOCKET, HANDLE > fd;
// the unique completion key that helps us to
// identify the object instance for which we receive data
// Here, we'll use the address of the udp_listener instance, converted
// to its literal int/int64 representation.
ULONG_PTR listener_id = 0;
ev_io(SOCKET f) : fd(f), m_writeq("writequeue"){};
ev_io(HANDLE t)
: fd(t), m_writeq("writequeue"){}; // overload for TUN device, which
// _is_ a regular file descriptor
#endif
virtual int
read(void* buf, size_t sz) = 0;
@ -139,13 +138,20 @@ namespace llarp
virtual ssize_t
do_write(void* data, size_t sz)
{
#ifndef _WIN32
return write(fd, data, sz);
#else
DWORD w;
WriteFile(std::get< HANDLE >(fd), data, sz, &w, nullptr);
if(std::holds_alternative< HANDLE >(fd))
{
WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, &portfd[1]);
GetOverlappedResult(std::get< HANDLE >(fd), &portfd[1], &w, TRUE);
}
else
{
WriteFile((HANDLE)std::get< SOCKET >(fd), data, sz, nullptr,
&portfd[1]);
GetOverlappedResult((HANDLE)std::get< SOCKET >(fd), &portfd[1], &w,
TRUE);
}
return w;
#endif
}
bool
@ -206,77 +212,331 @@ namespace llarp
}
/// reset errno
errno = 0;
#if _WIN32
SetLastError(0);
#endif
}
std::unique_ptr< LossyWriteQueue_t > m_LossyWriteQueue;
std::unique_ptr< LosslessWriteQueue_t > m_BlockingWriteQueue;
virtual ~ev_io()
virtual ~win32_ev_io()
{
#ifndef _WIN32
::close(fd);
#else
closesocket(std::get< SOCKET >(fd));
#endif
};
};
#endif
struct tcp_conn : public ev_io
struct posix_ev_io
{
bool _shouldClose = false;
llarp_tcp_conn* tcp;
tcp_conn(int fd, llarp_tcp_conn* conn)
: ev_io(fd, new LosslessWriteQueue_t{}), tcp(conn)
struct WriteBuffer
{
llarp_time_t timestamp = 0;
size_t bufsz;
byte_t buf[EV_WRITE_BUF_SZ];
WriteBuffer() = default;
WriteBuffer(const byte_t* ptr, size_t sz)
{
if(sz <= sizeof(buf))
{
bufsz = sz;
memcpy(buf, ptr, bufsz);
}
else
bufsz = 0;
}
struct GetTime
{
llarp_time_t
operator()(const WriteBuffer& buf) const
{
return buf.timestamp;
}
};
struct PutTime
{
llarp_ev_loop* loop;
PutTime(llarp_ev_loop* l) : loop(l)
{
}
void
operator()(WriteBuffer& buf)
{
buf.timestamp = llarp_ev_loop_time_now_ms(loop);
}
};
struct Compare
{
bool
operator()(const WriteBuffer& left, const WriteBuffer& right) const
{
return left.timestamp < right.timestamp;
}
};
};
typedef llarp::util::CoDelQueue< WriteBuffer, WriteBuffer::GetTime,
WriteBuffer::PutTime, WriteBuffer::Compare,
llarp::util::NullMutex,
llarp::util::NullLock, 5, 100, 128 >
LossyWriteQueue_t;
typedef std::deque< WriteBuffer > LosslessWriteQueue_t;
int fd;
int flags = 0;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| (__APPLE__ && __MACH__)
struct kevent change;
#endif
posix_ev_io(int f) : fd(f)
{
}
virtual ~tcp_conn()
/// for tun
posix_ev_io(int f, LossyWriteQueue_t* q) : fd(f), m_LossyWriteQueue(q)
{
}
/// for tcp
posix_ev_io(int f, LosslessWriteQueue_t* q) : fd(f), m_BlockingWriteQueue(q)
{
}
virtual void
error()
{
delete tcp;
llarp::LogError(strerror(errno));
}
virtual int
read(void* buf, size_t sz) = 0;
virtual int
sendto(const sockaddr* dst, const void* data, size_t sz)
{
return -1;
};
/// return false if we want to deregister and remove ourselves
virtual bool
tick()
{
return true;
};
/// used for tun interface and tcp conn
virtual ssize_t
do_write(void* buf, size_t sz)
do_write(void* data, size_t sz)
{
if(_shouldClose)
return -1;
#ifdef __linux__
return ::send(fd, buf, sz, MSG_NOSIGNAL); // ignore sigpipe
#else
return ::send(fd, buf, sz, 0);
#endif
return write(fd, data, sz);
}
int
read(void* buf, size_t sz)
bool
queue_write(const byte_t* buf, size_t sz)
{
if(_shouldClose)
return -1;
ssize_t amount = ::read(fd, buf, sz);
if(amount > 0)
if(m_LossyWriteQueue)
{
m_LossyWriteQueue->Emplace(buf, sz);
return true;
}
else if(m_BlockingWriteQueue)
{
if(tcp->read)
tcp->read(tcp, buf, amount);
m_BlockingWriteQueue->emplace_back(buf, sz);
return true;
}
else
return false;
}
virtual void
flush_write()
{
flush_write_buffers(0);
}
/// called in event loop when fd is ready for writing
/// requeues anything not written
/// this assumes fd is set to non blocking
virtual void
flush_write_buffers(size_t amount)
{
if(m_LossyWriteQueue)
m_LossyWriteQueue->Process([&](WriteBuffer& buffer) {
do_write(buffer.buf, buffer.bufsz);
// if we would block we save the entries for later
// discard entry
});
else if(m_BlockingWriteQueue)
{
if(amount)
{
while(amount && m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, std::min(amount, itr.bufsz));
if(result == -1)
return;
ssize_t dlt = itr.bufsz - result;
if(dlt > 0)
{
// queue remaining to front of queue
WriteBuffer buff(itr.buf + dlt, itr.bufsz - dlt);
m_BlockingWriteQueue->pop_front();
m_BlockingWriteQueue->push_front(buff);
// TODO: errno?
return;
}
m_BlockingWriteQueue->pop_front();
amount -= result;
}
}
else
{
// write buffers
while(m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, itr.bufsz);
if(result == -1)
return;
ssize_t dlt = itr.bufsz - result;
if(dlt > 0)
{
// queue remaining to front of queue
WriteBuffer buff(itr.buf + dlt, itr.bufsz - dlt);
m_BlockingWriteQueue->pop_front();
m_BlockingWriteQueue->push_front(buff);
// TODO: errno?
return;
}
m_BlockingWriteQueue->pop_front();
if(errno == EAGAIN || errno == EWOULDBLOCK)
{
errno = 0;
return;
}
}
}
}
/// reset errno
errno = 0;
}
std::unique_ptr< LossyWriteQueue_t > m_LossyWriteQueue;
std::unique_ptr< LosslessWriteQueue_t > m_BlockingWriteQueue;
virtual ~posix_ev_io()
{
close(fd);
};
};
// finally create aliases by platform
#ifdef _WIN32
using ev_io = win32_ev_io;
#else
using ev_io = posix_ev_io;
#endif
// wew, managed to get away with using
// 'int fd' across all platforms
// since we're operating entirely
// on sockets
struct tcp_conn : public ev_io
{
sockaddr_storage _addr;
bool _shouldClose = false;
bool _calledConnected = false;
llarp_tcp_conn tcp;
// null if inbound otherwise outbound
llarp_tcp_connecter* _conn;
/// inbound
tcp_conn(llarp_ev_loop* loop, int fd)
: ev_io(fd, new LosslessWriteQueue_t{}), _conn(nullptr)
{
tcp.impl = this;
tcp.loop = loop;
tcp.closed = nullptr;
tcp.user = nullptr;
tcp.read = nullptr;
tcp.tick = nullptr;
}
/// outbound
tcp_conn(llarp_ev_loop* loop, int fd, const sockaddr* addr,
llarp_tcp_connecter* conn)
: ev_io(fd, new LosslessWriteQueue_t{}), _conn(conn)
{
socklen_t slen = sizeof(sockaddr_in);
if(addr->sa_family == AF_INET6)
slen = sizeof(sockaddr_in6);
else if(addr->sa_family == AF_UNIX)
slen = sizeof(sockaddr_un);
memcpy(&_addr, addr, slen);
tcp.impl = this;
tcp.loop = loop;
tcp.closed = nullptr;
tcp.user = nullptr;
tcp.read = nullptr;
tcp.tick = nullptr;
}
virtual ~tcp_conn()
{
}
/// start connecting
void
connect();
/// calls connected hooks
void
connected()
{
// we are connected yeh boi
if(_conn)
{
// error
_shouldClose = true;
return -1;
if(_conn->connected && !_calledConnected)
_conn->connected(_conn, &tcp);
}
return 0;
_calledConnected = true;
}
bool
tick();
void
flush_write();
int
sendto(const sockaddr*, const void*, size_t)
void
flush_write_buffers(size_t a)
{
return -1;
connected();
ev_io::flush_write_buffers(a);
}
void
error()
{
if(_conn)
{
llarp::LogError("tcp_conn error: ", strerror(errno));
if(_conn->error)
_conn->error(_conn);
}
}
virtual ssize_t
do_write(void* buf, size_t sz);
virtual int
read(void* buf, size_t sz);
bool
tick();
};
struct tcp_serv : public ev_io
@ -286,6 +546,7 @@ namespace llarp
tcp_serv(llarp_ev_loop* l, int fd, llarp_tcp_acceptor* t)
: ev_io(fd), loop(l), tcp(t)
{
tcp->impl = this;
}
bool
@ -303,10 +564,12 @@ namespace llarp
}; // namespace llarp
// this (nearly!) abstract base class
// is overriden for each platform
struct llarp_ev_loop
{
byte_t readbuf[EV_READ_BUF_SZ];
llarp_time_t _now = 0;
byte_t readbuf[EV_READ_BUF_SZ] = {0};
llarp_time_t _now = 0;
virtual bool
init() = 0;
virtual int
@ -318,20 +581,8 @@ struct llarp_ev_loop
virtual void
stop() = 0;
bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
{
#ifdef _WIN32
l->fd = std::get< SOCKET >(ev->fd);
#else
l->fd = ev->fd;
#endif
}
return ev && add_ev(ev, false);
}
virtual bool
udp_listen(llarp_udp_io* l, const sockaddr* src) = 0;
virtual llarp::ev_io*
create_udp(llarp_udp_io* l, const sockaddr* src) = 0;
@ -345,12 +596,16 @@ struct llarp_ev_loop
virtual llarp::ev_io*
create_tun(llarp_tun_io* tun) = 0;
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* addr);
virtual llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* addr) = 0;
/// return false on socket error (non blocking)
virtual bool
tcp_connect(llarp_tcp_connecter* tcp, const sockaddr* addr) = 0;
/// register event listener
virtual bool
add_ev(llarp::ev_io* ev, bool write = false) = 0;
add_ev(llarp::ev_io* ev, bool write) = 0;
virtual bool
running() const = 0;

@ -18,6 +18,98 @@
namespace llarp
{
int
tcp_conn::read(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
ssize_t amount = ::read(fd, buf, sz);
if(amount > 0)
{
if(tcp.read)
tcp.read(&tcp, buf, amount);
}
else
{
// error
_shouldClose = true;
return -1;
}
return 0;
}
void
tcp_conn::flush_write()
{
connected();
ev_io::flush_write();
}
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
// pretty much every UNIX system still extant, _including_ solaris
// (on both sides of the fork) can ignore SIGPIPE....except
// the other vendored systems... -rick
return ::send(fd, buf, sz, MSG_NOSIGNAL); // ignore sigpipe
}
void
tcp_conn::connect()
{
socklen_t slen = sizeof(sockaddr_in);
if(_addr.ss_family == AF_UNIX)
slen = sizeof(sockaddr_un);
else if(_addr.ss_family == AF_INET6)
slen = sizeof(sockaddr_in6);
int result = ::connect(fd, (const sockaddr*)&_addr, slen);
if(result == 0)
{
llarp::LogDebug("connected immedidately");
connected();
}
else if(errno == EINPROGRESS)
{
// in progress
llarp::LogDebug("connect in progress");
errno = 0;
return;
}
else if(_conn->error)
{
// wtf?
llarp::LogError("error connecting ", strerror(errno));
_conn->error(_conn);
}
}
int
tcp_serv::read(void*, size_t)
{
int new_fd = ::accept(fd, nullptr, nullptr);
if(new_fd == -1)
{
llarp::LogError("failed to accept on ", fd, ":", strerror(errno));
return -1;
}
// build handler
llarp::tcp_conn* connimpl = new tcp_conn(loop, new_fd);
if(loop->add_ev(connimpl, true))
{
// call callback
if(tcp->accepted)
tcp->accepted(tcp, &connimpl->tcp);
return 0;
}
// cleanup error
delete connimpl;
return -1;
}
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
@ -169,6 +261,68 @@ struct llarp_epoll_loop : public llarp_ev_loop
{
}
bool
tcp_connect(struct llarp_tcp_connecter* tcp, const sockaddr* remoteaddr)
{
// create socket
int fd = ::socket(remoteaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return false;
// set non blocking
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
{
::close(fd);
return false;
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
::close(fd);
return false;
}
llarp::tcp_conn* conn = new llarp::tcp_conn(this, fd, remoteaddr, tcp);
add_ev(conn, true);
conn->connect();
return true;
}
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
int fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
{
sz = sizeof(sockaddr_in6);
}
else if(bindaddr->sa_family == AF_UNIX)
{
sz = sizeof(sockaddr_un);
}
if(::bind(fd, bindaddr, sz) == -1)
{
::close(fd);
return nullptr;
}
if(::listen(fd, 5) == -1)
{
::close(fd);
return nullptr;
}
return new llarp::tcp_serv(this, fd, tcp);
}
virtual bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = ev->fd;
return ev && add_ev(ev, false);
}
~llarp_epoll_loop()
{
if(epollfd != -1)
@ -203,13 +357,20 @@ struct llarp_epoll_loop : public llarp_ev_loop
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev)
{
if(events[idx].events & EPOLLIN)
if(events[idx].events & EPOLLERR)
{
ev->read(readbuf, sizeof(readbuf));
ev->error();
}
if(events[idx].events & EPOLLOUT)
else
{
ev->flush_write();
if(events[idx].events & EPOLLIN)
{
ev->read(readbuf, sizeof(readbuf));
}
if(events[idx].events & EPOLLOUT)
{
ev->flush_write();
}
}
}
++idx;
@ -236,13 +397,20 @@ struct llarp_epoll_loop : public llarp_ev_loop
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev)
{
if(events[idx].events & EPOLLIN)
if(events[idx].events & EPOLLERR)
{
ev->read(readbuf, sizeof(readbuf));
ev->error();
}
if(events[idx].events & EPOLLOUT)
else
{
ev->flush_write();
if(events[idx].events & EPOLLIN)
{
ev->read(readbuf, sizeof(readbuf));
}
if(events[idx].events & EPOLLOUT)
{
ev->flush_write();
}
}
}
++idx;
@ -334,7 +502,7 @@ struct llarp_epoll_loop : public llarp_ev_loop
{
epoll_event ev;
ev.data.ptr = e;
ev.events = EPOLLIN;
ev.events = EPOLLIN | EPOLLERR;
if(write)
ev.events |= EPOLLOUT;
if(epoll_ctl(epollfd, EPOLL_CTL_ADD, e->fd, &ev) == -1)

@ -9,11 +9,11 @@
// kqueue / kevent
#include <sys/event.h>
#include <sys/time.h>
#include <fcntl.h>
#endif
// MacOS needs this
#ifndef SOCK_NONBLOCK
#include <fcntl.h>
#define SOCK_NONBLOCK O_NONBLOCK
#endif
@ -26,6 +26,122 @@
namespace llarp
{
int
tcp_conn::read(void* buf, size_t sz)
{
if(sz == 0)
{
if(tcp.read)
tcp.read(&tcp, 0, 0);
return 0;
}
if(_shouldClose)
return -1;
ssize_t amount = ::read(fd, buf, sz);
if(amount >= 0)
{
if(tcp.read)
tcp.read(&tcp, buf, amount);
}
else
{
if(errno == EAGAIN || errno == EWOULDBLOCK)
{
errno = 0;
return 0;
}
_shouldClose = true;
return -1;
}
return 0;
}
void
tcp_conn::flush_write()
{
connected();
ev_io::flush_write();
}
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
// macintosh uses a weird sockopt
return ::send(fd, buf, sz, MSG_NOSIGNAL); // ignore sigpipe
#else
return ::send(fd, buf, sz, 0);
#endif
}
void
tcp_conn::connect()
{
socklen_t slen = sizeof(sockaddr_in);
if(_addr.ss_family == AF_UNIX)
slen = sizeof(sockaddr_un);
else if(_addr.ss_family == AF_INET6)
slen = sizeof(sockaddr_in6);
int result = ::connect(fd, (const sockaddr*)&_addr, slen);
if(result == 0)
{
llarp::LogDebug("Connected");
connected();
}
else if(errno == EINPROGRESS)
{
llarp::LogDebug("connect in progress");
errno = 0;
return;
}
else if(_conn)
{
_conn->error(_conn);
}
}
int
tcp_serv::read(void*, size_t)
{
int new_fd = ::accept(fd, nullptr, nullptr);
if(new_fd == -1)
{
llarp::LogError("failed to accept on ", fd, ": ", strerror(errno));
return -1;
}
// get flags
int flags = fcntl(new_fd, F_GETFL, 0);
if(flags == -1)
{
::close(new_fd);
return -1;
}
// set flags
if(fcntl(new_fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
llarp::LogError("Failed to set non block on ", fd, ": ", strerror(errno));
::close(new_fd);
return -1;
}
// build handler
llarp::tcp_conn* connimpl = new llarp::tcp_conn(loop, new_fd);
if(loop->add_ev(connimpl, true))
{
// call callback
if(tcp->accepted)
tcp->accepted(tcp, &connimpl->tcp);
return 0;
}
// cleanup error
delete connimpl;
return -1;
}
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
@ -158,7 +274,7 @@ namespace llarp
const size_t offset = 0;
#endif
ssize_t ret = tuntap_read(tunif, buf, sz);
if(ret > 4 && t->recvpkt)
if(ret > offset && t->recvpkt)
t->recvpkt(t, ((byte_t*)buf) + offset, ret - offset);
return ret;
}
@ -188,12 +304,53 @@ namespace llarp
struct llarp_kqueue_loop : public llarp_ev_loop
{
int kqueuefd;
struct kevent change; /* event we want to monitor */
llarp_kqueue_loop() : kqueuefd(-1)
{
}
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
int fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
{
sz = sizeof(sockaddr_in6);
}
else if(bindaddr->sa_family == AF_UNIX)
{
sz = sizeof(sockaddr_un);
}
if(::bind(fd, bindaddr, sz) == -1)
{
::close(fd);
return nullptr;
}
if(::listen(fd, 5) == -1)
{
::close(fd);
return nullptr;
}
// set non blocking
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
{
::close(fd);
return nullptr;
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
::close(fd);
return nullptr;
}
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
return serv;
}
~llarp_kqueue_loop()
{
}
@ -224,6 +381,30 @@ struct llarp_kqueue_loop : public llarp_ev_loop
return kqueuefd != -1;
}
bool
tcp_connect(llarp_tcp_connecter* tcp, const sockaddr* addr)
{
int fd = ::socket(addr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return false;
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
{
::close(fd);
return false;
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
::close(fd);
return false;
}
llarp::tcp_conn* conn = new llarp::tcp_conn(this, fd, addr, tcp);
add_ev(conn, true);
conn->connect();
return true;
}
int
tick(int ms)
{
@ -243,9 +424,10 @@ struct llarp_kqueue_loop : public llarp_ev_loop
if(ev)
{
if(events[idx].filter & EVFILT_READ)
ev->read(readbuf, sizeof(readbuf));
ev->read(readbuf,
std::min(sizeof(readbuf), size_t(events[idx].data)));
if(events[idx].filter & EVFILT_WRITE)
ev->flush_write();
ev->flush_write_buffers(events[idx].data);
}
++idx;
}
@ -260,7 +442,7 @@ struct llarp_kqueue_loop : public llarp_ev_loop
{
timespec t;
t.tv_sec = 0;
t.tv_nsec = 1000UL * EV_TICK_INTERVAL;
t.tv_nsec = 1000000UL * EV_TICK_INTERVAL;
struct kevent events[1024];
int result;
do
@ -276,9 +458,10 @@ struct llarp_kqueue_loop : public llarp_ev_loop
if(ev)
{
if(events[idx].filter & EVFILT_READ)
ev->read(readbuf, sizeof(readbuf));
ev->read(readbuf,
std::min(sizeof(readbuf), size_t(events[idx].data)));
if(events[idx].filter & EVFILT_WRITE)
ev->flush_write();
ev->flush_write_buffers(events[idx].data);
}
else
{
@ -351,11 +534,20 @@ struct llarp_kqueue_loop : public llarp_ev_loop
return fd;
}
virtual bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = ev->fd;
return ev && add_ev(ev, false);
}
bool
close_ev(llarp::ev_io* ev)
{
EV_SET(&change, ev->fd, ev->flags, EV_DELETE, 0, 0, nullptr);
return kevent(kqueuefd, &change, 1, nullptr, 0, nullptr) != -1;
EV_SET(&ev->change, ev->fd, ev->flags, EV_DELETE, 0, 0, nullptr);
return kevent(kqueuefd, &ev->change, 1, nullptr, 0, nullptr) != -1;
}
llarp::ev_io*
@ -370,18 +562,27 @@ struct llarp_kqueue_loop : public llarp_ev_loop
}
bool
add_ev(llarp::ev_io* ev, bool write)
add_ev(llarp::ev_io* ev, bool w)
{
ev->flags = EVFILT_READ;
if(write)
ev->flags |= EVFILT_WRITE;
EV_SET(&change, ev->fd, ev->flags, EV_ADD, 0, 0, ev);
if(kevent(kqueuefd, &change, 1, nullptr, 0, nullptr) == -1)
EV_SET(&ev->change, ev->fd, EVFILT_READ, EV_ADD, 0, 0, ev);
if(kevent(kqueuefd, &ev->change, 1, nullptr, 0, nullptr) == -1)
{
llarp::LogError("Failed to add event: ", strerror(errno));
delete ev;
return false;
}
if(w)
{
ev->flags |= EVFILT_WRITE;
EV_SET(&ev->change, ev->fd, EVFILT_WRITE, EV_ADD, 0, 0, ev);
if(kevent(kqueuefd, &ev->change, 1, nullptr, 0, nullptr) == -1)
{
llarp::LogError("Failed to add event: ", strerror(errno));
delete ev;
return false;
}
}
handlers.emplace_back(ev);
return true;
}

@ -10,29 +10,95 @@
namespace llarp
{
struct udp_listener : public ev_io
int
tcp_conn::read(void* buf, size_t sz)
{
llarp_udp_io* udp;
if(_shouldClose)
return -1;
WSABUF r_buf = {sz, (char*)buf};
DWORD amount = 0;
WSARecv(std::get< SOCKET >(fd), &r_buf, 1, nullptr, 0, &portfd[0], nullptr);
GetOverlappedResult((HANDLE)std::get< SOCKET >(fd), &portfd[0], &amount,
TRUE);
if(amount > 0)
{
if(tcp->read)
tcp->read(tcp, buf, amount);
}
else
{
// error
_shouldClose = true;
return -1;
}
return 0;
}
// we receive queued data in the OVERLAPPED data field,
// much like the pipefds in the UNIX kqueue and loonix
// epoll handles
WSAOVERLAPPED portfd[2];
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
WSABUF s_buf = {sz, (char*)buf};
DWORD sent = 0;
if(_shouldClose)
return -1;
udp_listener(SOCKET fd, llarp_udp_io* u) : ev_io(fd), udp(u)
WSASend(std::get< SOCKET >(fd), &s_buf, 1, nullptr, 0, &portfd[1], nullptr);
GetOverlappedResult((HANDLE)std::get< SOCKET >(fd), &portfd[1], &sent,
TRUE);
return sent;
}
int
tcp_serv::read(void*, size_t)
{
SOCKET new_fd = ::accept(std::get< SOCKET >(fd), nullptr, nullptr);
if(new_fd == INVALID_SOCKET)
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
};
llarp::LogError("failed to accept on ", std::get< SOCKET >(fd), ":",
strerror(errno));
return -1;
}
llarp_tcp_conn* conn = new llarp_tcp_conn;
// zero out callbacks
conn->tick = nullptr;
conn->closed = nullptr;
conn->read = nullptr;
// build handler
llarp::tcp_conn* connimpl = new tcp_conn(new_fd, conn);
conn->impl = connimpl;
conn->loop = loop;
if(loop->add_ev(connimpl, true))
{
// call callback
if(tcp->accepted)
tcp->accepted(tcp, conn);
return 0;
}
// cleanup error
delete conn;
delete connimpl;
return -1;
}
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
udp_listener(SOCKET fd, llarp_udp_io* u) : ev_io(fd), udp(u){};
~udp_listener()
{
}
virtual void
bool
tick()
{
if(udp->tick)
udp->tick(udp);
return true;
}
virtual int
@ -54,7 +120,6 @@ namespace llarp
llarp::LogWarn("recv socket error ", s_errno);
return -1;
}
// get the _real_ payload size from tick()
udp->recvfrom(udp, addr, buf, sz);
return 0;
}
@ -94,14 +159,11 @@ namespace llarp
llarp_tun_io* t;
device* tunif;
OVERLAPPED* tun_async[2];
tun(llarp_tun_io* tio)
: ev_io(INVALID_HANDLE_VALUE)
tun(llarp_tun_io* tio, llarp_ev_loop* l)
: ev_io(INVALID_HANDLE_VALUE,
new LossyWriteQueue_t("win32_tun_write", l))
, t(tio)
, tunif(tuntap_init())
{
};
, tunif(tuntap_init()){};
int
sendto(const sockaddr* to, const void* data, size_t sz)
@ -119,14 +181,16 @@ namespace llarp
ev_io::flush_write();
}
void
bool
tick()
{
if(t->tick)
t->tick(t);
flush_write();
return true;
}
bool
ssize_t
do_write(void* data, size_t sz)
{
return WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, tun_async[1]);
@ -136,9 +200,10 @@ namespace llarp
read(void* buf, size_t sz)
{
ssize_t ret = tuntap_read(tunif, buf, sz);
if(ret > 4 && t->recvpkt)
if(ret > 0 && t->recvpkt)
// should have pktinfo
t->recvpkt(t, ((byte_t*)buf) + 4, ret - 4);
// I have no idea...
t->recvpkt(t, (byte_t*)buf, ret);
return ret;
}
@ -178,6 +243,7 @@ namespace llarp
{
}
};
}; // namespace llarp
struct llarp_win32_loop : public llarp_ev_loop
@ -192,6 +258,44 @@ struct llarp_win32_loop : public llarp_ev_loop
{
if(iocpfd != INVALID_HANDLE_VALUE)
::CloseHandle(iocpfd);
iocpfd = INVALID_HANDLE_VALUE;
}
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
DWORD on = 1;
SOCKET fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == INVALID_SOCKET)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
{
sz = sizeof(sockaddr_in6);
}
// keep. inexplicably, windows now has unix domain sockets
// for now, use the ID numbers directly until this comes out of
// beta
else if(bindaddr->sa_family == AF_UNIX)
{
sz = 110; // current size in 10.0.17763, verify each time the beta PSDK
// is updated
}
if(::bind(fd, bindaddr, sz) == SOCKET_ERROR)
{
::closesocket(fd);
return nullptr;
}
if(::listen(fd, 5) == SOCKET_ERROR)
{
::closesocket(fd);
return nullptr;
}
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
ioctlsocket(fd, FIONBIO, &on);
return serv;
}
bool
@ -212,7 +316,7 @@ struct llarp_win32_loop : public llarp_ev_loop
{
// The only field we really care about is
// the listener_id, as it contains the address
// of the udp_listener instance.
// of the ev_io instance.
DWORD iolen = 0;
// ULONG_PTR is guaranteed to be the same size
// as an arch-specific pointer value
@ -222,16 +326,14 @@ struct llarp_win32_loop : public llarp_ev_loop
BOOL result =
::GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, ms);
if(result && qdata)
llarp::ev_io* ev = reinterpret_cast< llarp::ev_io* >(ev_id);
if(ev && qdata)
{
llarp::udp_listener* ev = reinterpret_cast< llarp::udp_listener* >(ev_id);
if(ev)
{
llarp::LogDebug("size: ", iolen, "\tev_id: ", ev_id,
"\tqdata: ", qdata);
if(iolen <= sizeof(readbuf))
ev->read(readbuf, iolen);
}
llarp::LogDebug("size: ", iolen, "\tev_id: ", ev_id, "\tqdata: ", qdata);
if(ev->write)
ev->flush_write();
else
ev->read(readbuf, iolen);
++idx;
}
@ -339,11 +441,27 @@ struct llarp_win32_loop : public llarp_ev_loop
bool
close_ev(llarp::ev_io* ev)
{
// On Windows, just close the socket to decrease the iocp refcount
// On Windows, just close the descriptor to decrease the iocp refcount
// and stop any pending I/O
BOOL stopped =
::CancelIo(reinterpret_cast< HANDLE >(std::get< SOCKET >(ev->fd)));
return closesocket(std::get< SOCKET >(ev->fd)) == 0 && stopped == TRUE;
BOOL stopped;
int close_fd;
if(std::holds_alternative< SOCKET >(ev->fd))
{
stopped =
::CancelIo(reinterpret_cast< HANDLE >(std::get< SOCKET >(ev->fd)));
close_fd = closesocket(std::get< SOCKET >(ev->fd));
}
else
{
stopped = ::CancelIo(std::get< HANDLE >(ev->fd));
close_fd = CloseHandle(std::get< HANDLE >(ev->fd));
if(close_fd)
close_fd = 0; // must be zero
else
close_fd = 1;
}
return close_fd == 0 && stopped == TRUE;
}
llarp::ev_io*
@ -361,7 +479,7 @@ struct llarp_win32_loop : public llarp_ev_loop
llarp::ev_io*
create_tun(llarp_tun_io* tun)
{
llarp::tun* t = new llarp::tun(tun);
llarp::tun* t = new llarp::tun(tun, this);
if(t->setup())
return t;
delete t;
@ -371,38 +489,51 @@ struct llarp_win32_loop : public llarp_ev_loop
bool
add_ev(llarp::ev_io* ev, bool write)
{
uint8_t buf[1024];
llarp::udp_listener* udp = nullptr;
llarp::tun* t = nullptr;
ev->listener_id = reinterpret_cast< ULONG_PTR >(ev);
memset(&buf, 0, 1024);
switch(ev->fd.index())
{
case 0:
udp = dynamic_cast< llarp::udp_listener* >(ev);
if(!::CreateIoCompletionPort((HANDLE)std::get< 0 >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
::ReadFile((HANDLE)std::get< 0 >(ev->fd), &buf, 1024, nullptr,
&udp->portfd[0]);
break;
case 1:
t = dynamic_cast< llarp::tun* >(ev);
if(!::CreateIoCompletionPort(std::get< 1 >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
::ReadFile(std::get< 1 >(ev->fd), &buf, 1024, nullptr, t->tun_async[0]);
break;
default:
ev->listener_id = reinterpret_cast< ULONG_PTR >(ev);
// if the write flag was set earlier,
// clear it on demand
if(ev->write && !write)
ev->write = false;
if(write)
ev->write = true;
// now write a blank packet containing nothing but the address of
// the event listener
if(ev->isTCP)
{
if(!::CreateIoCompletionPort((HANDLE)std::get< SOCKET >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
else
goto start_loop;
}
if(std::holds_alternative< SOCKET >(ev->fd))
{
if(!::CreateIoCompletionPort((HANDLE)std::get< SOCKET >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
}
else
{
if(!::CreateIoCompletionPort(std::get< HANDLE >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
}
start_loop:
PostQueuedCompletionStatus(iocpfd, 0, ev->listener_id, nullptr);
handlers.emplace_back(ev);
return true;
}
@ -415,10 +546,18 @@ struct llarp_win32_loop : public llarp_ev_loop
static_cast< llarp::udp_listener* >(l->impl);
if(listener)
{
ret = close_ev(listener);
close_ev(listener);
// remove handler
auto itr = handlers.begin();
while(itr != handlers.end())
{
if(itr->get() == listener)
itr = handlers.erase(itr);
else
++itr;
}
l->impl = nullptr;
delete listener;
ret = true;
ret = true;
}
return ret;
}
@ -429,10 +568,24 @@ struct llarp_win32_loop : public llarp_ev_loop
return iocpfd != INVALID_HANDLE_VALUE;
}
bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = std::get< SOCKET >(ev->fd);
return ev && add_ev(ev, false);
}
void
stop()
{
// still does nothing
// Are we leaking any file descriptors?
// This was part of the reason I had this
// in the destructor.
/*if(iocpfd != INVALID_HANDLE_VALUE)
::CloseHandle(iocpfd);
iocpfd = INVALID_HANDLE_VALUE;*/
}
};

@ -8,9 +8,8 @@
#define PATH_SEP "/"
#endif
#if 0
#ifdef _WIN32
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#else
#include "filesystem.h"

@ -305,7 +305,7 @@ namespace llarp
// prepare packet for insertion into network
// this includes clearing IP addresses, recalculating checksums, etc
pkt.UpdatePacketOnSrc();
pkt.UpdateIPv4PacketOnSrc();
if(!SendToOrQueue(itr->second, pkt.Buffer(), service::eProtocolTraffic))
{
@ -343,7 +343,7 @@ namespace llarp
return false;
}
// update packet to use proper addresses, recalc checksums
pkt.UpdatePacketOnDst(themIP, usIP);
pkt.UpdateIPv4PacketOnDst(themIP, usIP);
return true;
}))

@ -68,15 +68,16 @@ namespace llarp
}
#endif
static uint16_t
deltachksum(uint16_t old_sum, huint32_t old_src_ip, huint32_t old_dst_ip,
huint32_t new_src_ip, huint32_t new_dst_ip)
static nuint16_t
deltaIPv4Checksum(nuint16_t old_sum, nuint32_t old_src_ip,
nuint32_t old_dst_ip, nuint32_t new_src_ip,
nuint32_t new_dst_ip)
{
#define ADDIPCS(x) ((uint32_t)(x.h & 0xFFff) + (uint32_t)(x.h >> 16))
#define SUBIPCS(x) ((uint32_t)((~x.h) & 0xFFff) + (uint32_t)((~x.h) >> 16))
#define ADDIPCS(x) ((uint32_t)(x.n & 0xFFff) + (uint32_t)(x.n >> 16))
#define SUBIPCS(x) ((uint32_t)((~x.n) & 0xFFff) + (uint32_t)((~x.n) >> 16))
uint32_t sum = ntohs(old_sum) + ADDIPCS(old_src_ip) + ADDIPCS(old_dst_ip)
+ SUBIPCS(new_src_ip) + SUBIPCS(new_dst_ip);
uint32_t sum = uint32_t(old_sum.n) + ADDIPCS(old_src_ip)
+ ADDIPCS(old_dst_ip) + SUBIPCS(new_src_ip) + SUBIPCS(new_dst_ip);
#undef ADDIPCS
#undef SUBIPCS
@ -86,61 +87,64 @@ namespace llarp
sum = (sum & 0xFFff) + (sum >> 16);
sum += sum >> 16;
return htons(uint16_t(sum & 0xFFff));
return nuint16_t{uint16_t(sum & 0xFFff)};
}
static void
checksumDstTCP(byte_t *pld, size_t psz, size_t fragoff, size_t chksumoff,
huint32_t oSrcIP, huint32_t oDstIP, huint32_t nSrcIP,
huint32_t nDstIP)
checksumDstIPv4TCP(byte_t *pld, size_t psz, size_t fragoff,
size_t chksumoff, nuint32_t oSrcIP, nuint32_t oDstIP,
nuint32_t nSrcIP, nuint32_t nDstIP)
{
if(fragoff > chksumoff)
return;
uint16_t *check = (uint16_t *)(pld + chksumoff - fragoff);
auto check = (nuint16_t *)(pld + chksumoff - fragoff);
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
*check = deltaIPv4Checksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
// usually, TCP checksum field cannot be 0xFFff,
// because one's complement addition cannot result in 0x0000,
// and there's inversion in the end;
// emulate that.
if(*check == 0xFFff)
*check = 0x0000;
if(check->n == 0xFFff)
check->n = 0x0000;
}
static void
checksumDstUDP(const ip_header *ohdr, byte_t *pld, size_t psz,
size_t fragoff, huint32_t oSrcIP, huint32_t oDstIP,
huint32_t nSrcIP, huint32_t nDstIP)
checksumDstIPv4UDP(byte_t *pld, size_t psz, size_t fragoff,
nuint32_t oSrcIP, nuint32_t oDstIP, nuint32_t nSrcIP,
nuint32_t nDstIP)
{
if(fragoff > 6)
return;
uint16_t *check = (uint16_t *)(pld + 6);
if(*check == 0x0000)
auto check = (nuint16_t *)(pld + 6);
if(check->n == 0x0000)
return; // 0 is used to indicate "no checksum", don't change
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
*check = deltaIPv4Checksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
// 0 is used to indicate "no checksum"
// 0xFFff and 0 are equivalent in one's complement math
// 0xFFff + 1 = 0x10000 -> 0x0001 (same as 0 + 1)
// infact it's impossible to get 0 with such addition,
// when starting from non-0 value.
// inside deltachksum we don't invert so it's safe to skip check there
// if(*check == 0x0000)
// *check = 0xFFff;
// if(check->n == 0x0000)
// check->n = 0xFFff;
}
void
IPv4Packet::UpdatePacketOnDst(huint32_t nSrcIP, huint32_t nDstIP)
IPv4Packet::UpdateIPv4PacketOnDst(huint32_t newSrcIP, huint32_t newDstIP)
{
auto hdr = Header();
auto oSrcIP = xntohl(nuint32_t{hdr->saddr});
auto oDstIP = xntohl(nuint32_t{hdr->daddr});
auto oSrcIP = nuint32_t{hdr->saddr};
auto oDstIP = nuint32_t{hdr->daddr};
auto nSrcIP = xhtonl(newSrcIP);
auto nDstIP = xhtonl(newDstIP);
// IPv4 checksum
hdr->check = deltachksum(hdr->check, oSrcIP, oDstIP, nSrcIP, nDstIP);
auto v4chk = (nuint16_t *)&(hdr->check);
*v4chk = deltaIPv4Checksum(*v4chk, oSrcIP, oDstIP, nSrcIP, nDstIP);
// L4 checksum
auto ihs = size_t(hdr->ihl * 4);
@ -154,73 +158,75 @@ namespace llarp
switch(hdr->protocol)
{
case 6: // TCP
checksumDstTCP(pld, psz, fragoff, 16, oSrcIP, oDstIP, nSrcIP,
nDstIP);
checksumDstIPv4TCP(pld, psz, fragoff, 16, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
case 17: // UDP
case 136: // UDP-Lite - same checksum place, same 0->0xFFff condition
checksumDstUDP(hdr, pld, psz, fragoff, oSrcIP, oDstIP, nSrcIP,
nDstIP);
checksumDstIPv4UDP(pld, psz, fragoff, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
case 33: // DCCP
checksumDstTCP(pld, psz, fragoff, 6, oSrcIP, oDstIP, nSrcIP,
nDstIP);
checksumDstIPv4TCP(pld, psz, fragoff, 6, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
}
}
// write new IP addresses
hdr->saddr = xhtonl(nSrcIP).n;
hdr->daddr = xhtonl(nDstIP).n;
hdr->saddr = nSrcIP.n;
hdr->daddr = nDstIP.n;
}
static void
checksumSrcTCP(byte_t *pld, size_t psz, size_t fragoff, size_t chksumoff,
huint32_t oSrcIP, huint32_t oDstIP)
checksumSrcIPv4TCP(byte_t *pld, size_t psz, size_t fragoff,
size_t chksumoff, nuint32_t oSrcIP, nuint32_t oDstIP)
{
if(fragoff > chksumoff)
return;
uint16_t *check = (uint16_t *)(pld + chksumoff - fragoff);
auto check = (nuint16_t *)(pld + chksumoff - fragoff);
*check = deltachksum(*check, oSrcIP, oDstIP, huint32_t{0}, huint32_t{0});
*check =
deltaIPv4Checksum(*check, oSrcIP, oDstIP, nuint32_t{0}, nuint32_t{0});
// usually, TCP checksum field cannot be 0xFFff,
// because one's complement addition cannot result in 0x0000,
// and there's inversion in the end;
// emulate that.
if(*check == 0xFFff)
*check = 0x0000;
if(check->n == 0xFFff)
check->n = 0x0000;
}
static void
checksumSrcUDP(const ip_header *ohdr, byte_t *pld, size_t psz,
size_t fragoff, huint32_t oSrcIP, huint32_t oDstIP)
checksumSrcIPv4UDP(byte_t *pld, size_t psz, size_t fragoff,
nuint32_t oSrcIP, nuint32_t oDstIP)
{
if(fragoff > 6)
return;
uint16_t *check = (uint16_t *)(pld + 6);
if(*check == 0x0000)
auto check = (nuint16_t *)(pld + 6);
if(check->n == 0x0000)
return; // 0 is used to indicate "no checksum", don't change
*check = deltachksum(*check, oSrcIP, oDstIP, huint32_t{0}, huint32_t{0});
*check =
deltaIPv4Checksum(*check, oSrcIP, oDstIP, nuint32_t{0}, nuint32_t{0});
// 0 is used to indicate "no checksum"
// 0xFFff and 0 are equivalent in one's complement math
// 0xFFff + 1 = 0x10000 -> 0x0001 (same as 0 + 1)
// infact it's impossible to get 0 with such addition,
// when starting from non-0 value.
// inside deltachksum we don't invert so it's safe to skip check there
// if(*check == 0x0000)
// *check = 0xFFff;
// if(check->n == 0x0000)
// check->n = 0xFFff;
}
void
IPv4Packet::UpdatePacketOnSrc()
IPv4Packet::UpdateIPv4PacketOnSrc()
{
auto hdr = Header();
auto oSrcIP = xntohl(nuint32_t{hdr->saddr});
auto oDstIP = xntohl(nuint32_t{hdr->daddr});
auto oSrcIP = nuint32_t{hdr->saddr};
auto oDstIP = nuint32_t{hdr->daddr};
// L4
auto ihs = size_t(hdr->ihl * 4);
@ -234,21 +240,22 @@ namespace llarp
switch(hdr->protocol)
{
case 6: // TCP
checksumSrcTCP(pld, psz, fragoff, 16, oSrcIP, oDstIP);
checksumSrcIPv4TCP(pld, psz, fragoff, 16, oSrcIP, oDstIP);
break;
case 17: // UDP
case 136: // UDP-Lite
checksumSrcUDP(hdr, pld, psz, fragoff, oSrcIP, oDstIP);
checksumSrcIPv4UDP(pld, psz, fragoff, oSrcIP, oDstIP);
break;
case 33: // DCCP
checksumSrcTCP(pld, psz, fragoff, 6, oSrcIP, oDstIP);
checksumSrcIPv4TCP(pld, psz, fragoff, 6, oSrcIP, oDstIP);
break;
}
}
// IPv4
hdr->check =
deltachksum(hdr->check, oSrcIP, oDstIP, huint32_t{0}, huint32_t{0});
auto v4chk = (nuint16_t *)&(hdr->check);
*v4chk =
deltaIPv4Checksum(*v4chk, oSrcIP, oDstIP, nuint32_t{0}, nuint32_t{0});
// clear addresses
hdr->saddr = 0;

@ -279,6 +279,7 @@ _llarp_nt_getadaptersinfo(struct llarp_nt_ifaddrs_t** ifap)
return true;
}
#if 0
/* Supports both IPv4 and IPv6 addressing. The size of IP_ADAPTER_ADDRESSES
* changes between Windows XP, XP SP1, and Vista with additional members.
*
@ -296,7 +297,6 @@ _llarp_nt_getadaptersinfo(struct llarp_nt_ifaddrs_t** ifap)
* NOTE(despair): an inline implementation is provided, much like
* getaddrinfo(3) for old hosts. See "win32_intrnl.*"
*/
#ifdef _MSC_VER
static bool
_llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
{
@ -312,22 +312,12 @@ _llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
fprintf(stderr, "IP_ADAPTER_ADDRESSES buffer length %lu bytes.\n", dwSize);
#endif
pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize);
#if defined(_MSC_VER) || defined(_WIN64)
dwRet = GetAdaptersAddresses(AF_UNSPEC,
/* requires Windows XP SP1 */
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
| GAA_FLAG_SKIP_MULTICAST,
nullptr, pAdapterAddresses, &dwSize);
#else
dwRet = _GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME
| GAA_FLAG_SKIP_MULTICAST,
nullptr, pAdapterAddresses, &dwSize);
#endif
if(ERROR_BUFFER_OVERFLOW == dwRet)
{
_llarp_nt_heap_free(pAdapterAddresses);
@ -659,19 +649,11 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
for(unsigned i = 3; i; i--)
{
pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize);
#ifdef _MSC_VER
dwRet = GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST,
nullptr, pAdapterAddresses, &dwSize);
#else
dwRet = _GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST,
nullptr, pAdapterAddresses, &dwSize);
#endif
if(ERROR_BUFFER_OVERFLOW == dwRet)
{
@ -725,11 +707,7 @@ llarp_nt_getifaddrs(struct llarp_nt_ifaddrs_t** ifap)
fprintf(stderr, "llarp_nt_getifaddrs (ifap:%p error:%p)\n", (void*)ifap,
(void*)errno);
#endif
#ifdef _MSC_VER
return _llarp_nt_getadaptersaddresses(ifap);
#else
return _llarp_nt_getadaptersinfo(ifap);
#endif
}
static void

@ -103,11 +103,16 @@ struct llarp_router
bool
ShouldCreateDefaultHiddenService();
std::string DefaultRPCBindAddr = "127.0.0.1:1190";
bool enableRPCServer = true;
const std::string DefaultRPCBindAddr = "127.0.0.1:1190";
bool enableRPCServer = true;
std::unique_ptr< llarp::rpc::Server > rpcServer;
std::string rpcBindAddr = DefaultRPCBindAddr;
/// lokid caller
const std::string DefaultLokidRPCAddr = "127.0.0.1:22023";
std::unique_ptr< llarp::rpc::Caller > rpcCaller;
std::string lokidRPCAddr = DefaultLokidRPCAddr;
std::unique_ptr< llarp::ILinkLayer > outboundLink;
std::vector< std::unique_ptr< llarp::ILinkLayer > > inboundLinks;

@ -9,11 +9,101 @@ namespace llarp
namespace rpc
{
#ifdef USE_ABYSS
struct Handler : public ::abyss::http::IRPCHandler
struct CallerHandler : public ::abyss::http::IRPCClientHandler
{
CallerHandler(::abyss::http::ConnImpl* impl)
: ::abyss::http::IRPCClientHandler(impl)
{
}
~CallerHandler()
{
}
void
PopulateReqHeaders(abyss::http::Headers_t& hdr)
{
}
};
struct VerifyRouterHandler : public CallerHandler
{
llarp::PubKey pk;
std::function< void(llarp::PubKey, bool) > handler;
~VerifyRouterHandler()
{
}
VerifyRouterHandler(::abyss::http::ConnImpl* impl, const llarp::PubKey& k,
std::function< void(llarp::PubKey, bool) > h)
: CallerHandler(impl), pk(k), handler(h)
{
}
bool
HandleResponse(const ::abyss::http::RPC_Response& response)
{
handler(pk, true);
return true;
}
void
HandleError()
{
llarp::LogInfo("failed to verify router ", pk);
handler(pk, false);
}
};
struct CallerImpl : public ::abyss::http::JSONRPC
{
llarp_router* router;
CallerImpl(llarp_router* r) : ::abyss::http::JSONRPC(), router(r)
{
}
void
Tick()
{
Flush();
}
bool
Start(const std::string& remote)
{
return RunAsync(router->netloop, remote);
}
abyss::http::IRPCClientHandler*
NewConn(PubKey k, std::function< void(llarp::PubKey, bool) > handler,
abyss::http::ConnImpl* impl)
{
return new VerifyRouterHandler(impl, k, handler);
}
void
AsyncVerifyRouter(llarp::PubKey pk,
std::function< void(llarp::PubKey, bool) > handler)
{
abyss::json::Value params;
params.SetObject();
QueueRPC("get_service_node", std::move(params),
std::bind(&CallerImpl::NewConn, this, pk, handler,
std::placeholders::_1));
}
~CallerImpl()
{
}
};
struct Handler : public ::abyss::httpd::IRPCHandler
{
llarp_router* router;
Handler(::abyss::http::ConnImpl* conn, llarp_router* r)
: ::abyss::http::IRPCHandler(conn), router(r)
Handler(::abyss::httpd::ConnImpl* conn, llarp_router* r)
: ::abyss::httpd::IRPCHandler(conn), router(r)
{
}
@ -59,15 +149,15 @@ namespace llarp
}
};
struct ReqHandlerImpl : public ::abyss::http::BaseReqHandler
struct ReqHandlerImpl : public ::abyss::httpd::BaseReqHandler
{
ReqHandlerImpl(llarp_router* r, llarp_time_t reqtimeout)
: ::abyss::http::BaseReqHandler(reqtimeout), router(r)
: ::abyss::httpd::BaseReqHandler(reqtimeout), router(r)
{
}
llarp_router* router;
::abyss::http::IRPCHandler*
CreateHandler(::abyss::http::ConnImpl* conn) const
::abyss::httpd::IRPCHandler*
CreateHandler(::abyss::httpd::ConnImpl* conn)
{
return new Handler(conn, router);
}
@ -115,8 +205,61 @@ namespace llarp
return true;
}
};
struct CallerImpl
{
CallerImpl(llarp_router* r)
{
}
~CallerImpl()
{
}
bool
Start(const std::string&)
{
return true;
}
void
Tick()
{
}
void
AsyncVerifyRouter(llarp::PubKey pk,
std::function< void(llarp::PubKey, bool) > result)
{
// always allow routers when not using libabyss
result(pk, true);
}
};
#endif
Caller::Caller(llarp_router* r) : m_Impl(new CallerImpl(r))
{
}
Caller::~Caller()
{
delete m_Impl;
}
bool
Caller::Start(const std::string& addr)
{
return m_Impl->Start(addr);
}
void
Caller::AsyncVerifyRouter(
llarp::PubKey pk, std::function< void(llarp::PubKey, bool) > handler)
{
m_Impl->AsyncVerifyRouter(pk, handler);
}
Server::Server(llarp_router* r) : m_Impl(new ServerImpl(r))
{
}

@ -1,7 +1,3 @@
#ifdef _MSC_VER
#define NOMINMAX
#endif
#include <llarp/service.hpp>
#include "buffer.hpp"
#include "fs.hpp"

@ -259,8 +259,7 @@ namespace llarp
}
// construct
service = std::unique_ptr< llarp::service::Endpoint >(
itr->second(conf.first, m_Router));
service.reset(itr->second(conf.first, m_Router));
}
// configure
for(const auto &option : conf.second)

@ -1,7 +1,5 @@
#include "threadpool.hpp"
#ifndef _MSC_VER
#include <pthread.h>
#endif
#include <cstring>
#include <llarp/time.h>

@ -311,7 +311,4 @@ _GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved,
return NO_ERROR;
}
#elif _MSC_VER
/* just a comment */
static void* unused;
#endif

@ -175,8 +175,10 @@ tdiGetIpAddrsForIpEntity(HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs,
{
NTSTATUS status;
#ifdef DEBUG
fprintf(stderr, "TdiGetIpAddrsForIpEntity(tcpFile 0x%p, entityId 0x%lx)\n",
tcpFile, ent->tei_instance);
#endif
status = tdiGetSetOfThings(tcpFile, INFO_CLASS_PROTOCOL, INFO_TYPE_PROVIDER,
0x102, CL_NL_ENTITY, ent->tei_instance, 0,
@ -448,6 +450,8 @@ getInterfaceIndexTableInt(BOOL nonLoopbackOnly)
HANDLE tcpFile;
NTSTATUS status = openTcpFile(&tcpFile, FILE_READ_DATA);
ifInfo = NULL;
if(NT_SUCCESS(status))
{
status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
@ -494,14 +498,10 @@ getInterfaceIndexTable(void)
#endif
/*
* We need this in the Microsoft C/C++ port, as we're not using Pthreads, and
* jeff insists on naming the threads at runtime. Apparently throwing exception
* 1080890248 is only visible when running under a machine code monitor.
*
* -despair86 30/07/18
*/
#ifdef _MSC_VER
// there's probably an use case for a _newer_ implementation
// of pthread_setname_np(3), in fact, I may just merge _this_
// upstream...
#if 0
#include <windows.h>
typedef HRESULT(FAR PASCAL *p_SetThreadDescription)(void *, const wchar_t *);

Binary file not shown.

@ -54,7 +54,30 @@ TEST_F(KademliaDHTTest, TestBucketFindClosest)
ASSERT_TRUE(oldResult == result);
};
TEST_F(KademliaDHTTest, TestBucketRandomzied)
TEST_F(KademliaDHTTest, TestBucketOperators)
{
llarp::dht::Key_t zero;
llarp::dht::Key_t one;
llarp::dht::Key_t three;
zero.Zero();
one.Fill(1);
three.Fill(3);
ASSERT_TRUE(zero < one);
ASSERT_TRUE(zero < three);
ASSERT_FALSE(zero > one);
ASSERT_FALSE(zero > three);
ASSERT_TRUE(zero != three);
ASSERT_FALSE(zero == three);
ASSERT_TRUE((zero ^ one) == one);
ASSERT_TRUE(one < three);
ASSERT_TRUE(three > one);
ASSERT_TRUE(one != three);
ASSERT_FALSE(one == three);
ASSERT_TRUE((one ^ three) == (three ^ one));
};
TEST_F(KademliaDHTTest, TestBucketRandomzied_1000)
{
size_t moreNodes = 100;
while(moreNodes--)
@ -63,9 +86,35 @@ TEST_F(KademliaDHTTest, TestBucketRandomzied)
n.ID.Randomize();
nodes->PutNode(n);
}
llarp::dht::Key_t result;
llarp::dht::Key_t target;
llarp::dht::Key_t oldResult;
target.Randomize();
ASSERT_TRUE(nodes->FindClosest(target, result));
const size_t count = 1000;
size_t left = count;
while(left--)
{
llarp::dht::Key_t result;
llarp::dht::Key_t target;
llarp::dht::Key_t expect;
target.Randomize();
expect = target;
ASSERT_TRUE(nodes->FindClosest(target, result));
if(target == result)
{
ASSERT_FALSE((result ^ target) < (expect ^ target));
ASSERT_FALSE((result ^ target) != (expect ^ target));
ASSERT_TRUE((result ^ target) == (expect ^ target));
}
else
{
Key_t dist = result ^ target;
Key_t oldDist = expect ^ target;
ASSERT_TRUE((result ^ target) != (expect ^ target));
if((result ^ target) < (expect ^ target))
{
std::cout << "result=" << result << "expect=" << expect << std::endl;
std::cout << dist << ">=" << oldDist << "iteration=" << (count - left)
<< std::endl;
ASSERT_TRUE(false);
}
ASSERT_FALSE((result ^ target) == (expect ^ target));
}
}
};

@ -123,7 +123,7 @@ macro(config_compiler_and_linker)
set(cxx_no_rtti_flags "")
endif()
if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed.
if (CMAKE_USE_PTHREADS_INIT AND NOT WIN32) # The pthreads library is available and allowed.
set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1")
else()
set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0")

@ -0,0 +1,190 @@
#include <gtest/gtest.h>
#include <libabyss.hpp>
#include <llarp/ev.h>
#include <llarp/threading.hpp>
#include <llarp/net.hpp>
struct AbyssTestBase : public ::testing::Test
{
llarp_crypto crypto;
llarp_threadpool* threadpool = nullptr;
llarp_ev_loop* loop = nullptr;
llarp_logic* logic = nullptr;
abyss::httpd::BaseReqHandler* server = nullptr;
abyss::http::JSONRPC* client = nullptr;
const std::string method = "test.method";
bool called = false;
void
AssertMethod(const std::string& meth) const
{
ASSERT_TRUE(meth == method);
}
void
SetUp()
{
// for llarp_randint
llarp_crypto_init(&crypto);
}
static void
CancelIt(void* u, uint64_t orig, uint64_t left)
{
if(left)
return;
static_cast< AbyssTestBase* >(u)->Stop();
}
void
Start()
{
threadpool = llarp_init_same_process_threadpool();
llarp_ev_loop_alloc(&loop);
logic = llarp_init_single_process_logic(threadpool);
sockaddr_in addr;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons((llarp_randint() % 2000) + 2000);
addr.sin_family = AF_INET;
llarp::Addr a(addr);
while(true)
{
if(server->ServeAsync(loop, logic, a))
{
client->RunAsync(loop, a.ToString());
llarp_logic_call_later(logic, {1000, this, &CancelIt});
return;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void
Stop()
{
if(server)
server->Close();
llarp_logic_stop(logic);
llarp_ev_loop_stop(loop);
llarp_threadpool_stop(threadpool);
}
void
TearDown()
{
if(loop && threadpool && logic)
{
llarp_free_logic(&logic);
llarp_ev_loop_free(&loop);
llarp_free_threadpool(&threadpool);
}
}
};
struct ClientHandler : public abyss::http::IRPCClientHandler
{
AbyssTestBase* test;
ClientHandler(abyss::http::ConnImpl* impl, AbyssTestBase* parent)
: abyss::http::IRPCClientHandler(impl), test(parent)
{
}
void
HandleError()
{
ASSERT_TRUE(false);
}
void
PopulateReqHeaders(abyss::http::Headers_t& hdr)
{
}
bool
HandleResponse(const abyss::http::RPC_Response& response)
{
test->Stop();
return true;
}
};
struct ServerHandler : public abyss::httpd::IRPCHandler
{
AbyssTestBase* test;
ServerHandler(abyss::httpd::ConnImpl* impl, AbyssTestBase* parent)
: abyss::httpd::IRPCHandler(impl), test(parent)
{
}
bool
HandleJSONRPC(Method_t method, const Params& params, Response& response)
{
test->AssertMethod(method);
test->called = true;
return true;
}
};
struct AbyssTest : public AbyssTestBase,
public abyss::http::JSONRPC,
public abyss::httpd::BaseReqHandler
{
AbyssTest()
: AbyssTestBase()
, abyss::http::JSONRPC()
, abyss::httpd::BaseReqHandler(1000)
{
}
abyss::http::IRPCClientHandler*
NewConn(abyss::http::ConnImpl* impl)
{
return new ClientHandler(impl, this);
}
abyss::httpd::IRPCHandler*
CreateHandler(abyss::httpd::ConnImpl* impl)
{
return new ServerHandler(impl, this);
}
void
SetUp()
{
AbyssTestBase::SetUp();
client = this;
server = this;
}
static void
FlushIt(void* u)
{
static_cast< AbyssTest* >(u)->Flush();
}
void
AsyncFlush()
{
llarp_logic_queue_job(logic, {this, &FlushIt});
}
void
RunLoop()
{
llarp_ev_loop_run_single_process(loop, threadpool, logic);
}
};
TEST_F(AbyssTest, TestClientAndServer)
{
Start();
abyss::json::Value params;
params.SetObject();
QueueRPC(method, std::move(params),
std::bind(&AbyssTest::NewConn, this, std::placeholders::_1));
AsyncFlush();
RunLoop();
ASSERT_TRUE(called);
};

@ -69,7 +69,7 @@ TEST_F(DNSTest, TestDecodeDNSstring)
TEST_F(DNSTest, TestCodeDomain)
{
char buffer[16];
llarp::Zero(&buffer, 15);
llarp::Zero(buffer, 16);
char *write_buffer = buffer;
std::string url = "bob.com";
code_domain(write_buffer, url);

@ -30,12 +30,6 @@
#ifndef PBL_CPP_FILESYSTEM_H
#define PBL_CPP_FILESYSTEM_H
#if _MSC_VER >= 1900
#define CPP17
#define CPP11
#define CPP14
#endif
#include "version.h"
#if defined(CPP17) && defined(USE_CXX17_FILESYSTEM)

@ -31,11 +31,7 @@
#include <cerrno>
#ifndef _MSC_VER
#include <unistd.h>
#else
#include <direct.h>
#endif
namespace cpp17
{

@ -30,9 +30,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
namespace cpp17
{

@ -31,113 +31,12 @@
#include <iostream>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include "path.h"
#ifdef _MSC_VER
#include <Windows.h>
#include <stdint.h>
#include <io.h>
typedef unsigned short mode_t;
typedef uint32_t id_t; /* Internal uids/gids are 32-bits */
typedef SSIZE_T ssize_t;
#ifndef _OFF_T_DEFINED
typedef DWORD64 off_t;
#endif
typedef uint32_t uid_t; /* [???] user IDs */
#ifndef S_IFIFO
#define S_IFIFO 0010000 /* [XSI] named pipe (fifo) */
#endif
#ifndef S_IFBLK
#define S_IFBLK 0060000 /* [XSI] block special */
#endif
#ifndef S_IFLNK
#define S_IFLNK 0120000 /* [XSI] symbolic link */
#endif
#ifndef S_IFSOCK
#define S_IFSOCK 0140000 /* [XSI] socket */
#endif
#ifndef S_ISBLK
#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) /* block special */
#endif
#ifndef S_ISCHR
#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) /* char special */
#endif
#ifndef S_ISDIR
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) /* directory */
#endif
#ifndef S_ISFIFO
#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) /* fifo or socket */
#endif
#ifndef S_ISREG
#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) /* regular file */
#endif
#ifndef S_ISLNK
#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) /* symbolic link */
#endif
#ifndef S_ISSOCK
#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) /* socket */
#endif
#ifndef makedev
#define makedev(x, y) ((dev_t)(((x) << 24) | (y)))
#endif
#ifndef DT_UNKNOWN
#define DT_UNKNOWN 0
#endif
#ifndef DT_FIFO
#define DT_FIFO 1
#endif
#ifndef DT_CHR
#define DT_CHR 2
#endif
#ifndef DT_DIR
#define DT_DIR 4
#endif
#ifndef DT_BLK
#define DT_BLK 6
#endif
#ifndef DT_REG
#define DT_REG 8
#endif
#ifndef DT_LNK
#define DT_LNK 10
#endif
#ifndef DT_SOCK
#define DT_SOCK 12
#endif
#ifndef DT_WHT
#define DT_WHT 14
#endif
#endif
namespace
{
::cpp17::filesystem::file_status

@ -175,6 +175,10 @@ tuntap_start(struct device *dev, int mode, int tun)
char *deviceid;
char buf[60];
/* put something in there to avoid problems (uninitialised field access) */
tun_fd = TUNFD_INVALID_VALUE;
deviceid = NULL;
/* Don't re-initialise a previously started device */
if(dev->tun_fd != TUNFD_INVALID_VALUE)
{
@ -198,6 +202,7 @@ tuntap_start(struct device *dev, int mode, int tun)
else if(mode != TUNTAP_MODE_ETHERNET)
{
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'mode'");
free(deviceid);
return -1;
}
@ -205,10 +210,12 @@ tuntap_start(struct device *dev, int mode, int tun)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
free(deviceid);
return -1;
}
dev->tun_fd = tun_fd;
free(deviceid);
return 0;
}
@ -345,16 +352,30 @@ tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask)
sock[1] = sock[0] & sock[2];
ret = DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_TUN, &sock, sizeof(sock),
&sock, sizeof(sock), &len, NULL);
if(!ret)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
ep[0] = s->S_un.S_addr;
ep[1] = mask;
ep[2] = (s->S_un.S_addr | ~mask)
- (mask + 1); /* For the 10.x.0.y subnet (in a class C config), _should_
be 10.x.0.254 i think */
ep[3] = 3153600; /* one year */
ep[3] = 3153600; /* one year */
ret = DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_MASQ, ep, sizeof(ep),
ep, sizeof(ep), &len, NULL);
if(!ret)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
/* set DNS address to 127.0.0.1 as lokinet-client runs its own DNS resolver
* inline */
dns.dhcp_opt = 6;
@ -370,7 +391,6 @@ tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask)
if(!ret)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
@ -392,42 +412,37 @@ tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s, uint32_t mask)
int
tuntap_read(struct device *dev, void *buf, size_t size)
{
DWORD len;
if(ReadFile(dev->tun_fd, buf, (DWORD)size, &len, &dev->ovl[0]) == 0)
if(size)
{
ReadFile(dev->tun_fd, buf, (DWORD)size, NULL, &dev->ovl[0]);
int errcode = GetLastError();
if (errcode != 997)
{
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
else
return 0;
if(errcode != 997)
{
tuntap_log(TUNTAP_LOG_ERR,
(const char *)formated_error(L"%1%0", errcode));
return -1;
}
}
return 0;
}
int
tuntap_write(struct device *dev, void *buf, size_t size)
{
DWORD len;
if(WriteFile(dev->tun_fd, buf, (DWORD)size, &len, &dev->ovl[1]) == 0)
if(size)
{
int errcode = GetLastError();
if (errcode != 997)
{
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
else
return 0;
}
WriteFile(dev->tun_fd, buf, (DWORD)size, NULL, &dev->ovl[1]);
int errcode = GetLastError();
if(errcode != 997)
{
tuntap_log(TUNTAP_LOG_ERR,
(const char *)formated_error(L"%1%0", errcode));
return -1;
}
}
return 0;
}
@ -446,7 +461,8 @@ tuntap_set_nonblocking(struct device *dev, int set)
(void)dev;
(void)set;
tuntap_log(TUNTAP_LOG_NOTICE,
"TUN/TAP devices on Windows are non-blocking by default using either overlapped I/O or IOCPs");
"TUN/TAP devices on Windows are non-blocking by default using "
"either overlapped I/O or IOCPs");
return -1;
}

@ -31,12 +31,10 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#ifndef _MSC_VER
extern "C" int
inet_pton(int af, const char *src, void *dst);
extern "C" const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
#else
#include <arpa/inet.h>
#include <netinet/in.h>

Binary file not shown.

@ -0,0 +1,137 @@
; Script generated by the Inno Script Studio Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "loki-network"
#define MyAppVersion "0.3.0"
#define MyAppPublisher "Loki Project"
#define MyAppURL "https://loki.network"
#define MyAppExeName "lokinet.exe"
; change this to avoid compiler errors -despair
#define DevPath "D:\dev\external\llarp\"
#include <idp.iss>
; see ../LICENSE
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{11335EAC-0385-4C78-A3AA-67731326B653}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppPublisher}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
LicenseFile={#DevPath}LICENSE
OutputDir={#DevPath}win32-setup
OutputBaseFilename=lokinet-win32
Compression=lzma
SolidCompression=yes
VersionInfoVersion=0.3.0
VersionInfoCompany=Loki Project
VersionInfoDescription=lokinet for windows
VersionInfoTextVersion=0.3.0-dev
VersionInfoProductName=loki-network
VersionInfoProductVersion=0.3.0
VersionInfoProductTextVersion=0.3.0-dev
InternalCompressLevel=ultra64
MinVersion=0,5.0
ArchitecturesInstallIn64BitMode=x64
VersionInfoCopyright=Copyright ©2018 Loki Project
AlwaysRestart=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Files]
; we're grabbing the builds from jenkins-ci now, which are fully linked
; only one of these is installed
Source: "{#DevPath}build\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion 32bit; Check: not IsWin64
Source: "{#DevPath}build\lokinet64.exe"; DestDir: "{app}"; Flags: ignoreversion 64bit; Check: IsWin64
; eh, might as well ship the 32-bit port of everything else
Source: "{#DevPath}build\dns.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#DevPath}build\llarpc.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#DevPath}build\rcutil.exe"; DestDir: "{app}"; Flags: ignoreversion
; delet this after finishing setup, we only need it to extract the drivers
; and download an initial RC
Source: "{#DevPath}lokinet-bootstrap.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
Source: "{#DevPath}win32-setup\7z.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
Source: "{tmp}\inet6.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
; Copy the correct tuntap driver for the selected platform
Source: "{tmp}\tuntapv9.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; OnlyBelowVersion: 0, 6.0
Source: "{tmp}\tuntapv9_n6.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; MinVersion: 0,6.0
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[UninstallDelete]
Type: filesandordirs; Name: "{app}\tap-windows*"
Type: filesandordirs; Name: "{app}\inet6_driver"; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
Type: filesandordirs; Name: "{userappdata}\.lokinet"
[UninstallRun]
Filename: "{app}\tap-windows-9.21.2\remove.bat"; WorkingDir: "{app}\tap-windows-9.21.2"; MinVersion: 0,6.0; Flags: runascurrentuser
Filename: "{app}\tap-windows-9.9.2\remove.bat"; WorkingDir: "{app}\tap-windows-9.9.2"; OnlyBelowVersion: 0,6.0; Flags: runascurrentuser
[Registry]
; TODO: BindView to activate inet6 protocol driver after restart
Root: "HKLM"; Subkey: "Software\Microsoft\Windows\CurrentVersion\RunOnce"; ValueType: string; ValueName: "ActivateInet6"; ValueData: "[insert bindview cmd line here]"; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
[Code]
procedure InitializeWizard();
var
Version: TWindowsVersion;
S: String;
begin
GetWindowsVersionEx(Version);
if Version.NTPlatform and
(Version.Major < 6) then
begin
// Windows 2000, XP, .NET Svr 2003
// these have a horribly crippled WinInet that issues Triple-DES as its most secure
// cipher suite
idpAddFile('http://www.rvx86.net/files/tuntapv9.7z', ExpandConstant('{tmp}\tuntapv9.7z'));
// Windows 2000 only, we need to install inet6 separately
if (FileExists(ExpandConstant('{sys}\drivers\tcpip6.sys')) = false) and (Version.Major = 5) and (Version.Minor = 0) then
begin
idpAddFile('http://www.rvx86.net/files/inet6.7z', ExpandConstant('{tmp}\inet6.7z'));
end;
end
else
begin
// current versions of windows :-)
// (Arguably, one could pull this from any of the forks.)
idpAddFile('https://github.com/despair86/loki-network/raw/master/contrib/tuntapv9-ndis/tap-windows-9.21.2.7z', ExpandConstant('{tmp}\tuntapv9_n6.7z'));
end;
idpDownloadAfter(wpReady);
end;
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon; OnlyBelowVersion: 0, 6.1
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon; MinVersion: 0, 6.1
[Run]
Filename: "{app}\{#MyAppExeName}"; Flags: nowait postinstall skipifsilent; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"
; wait until either one or two of these terminates
Filename: "{tmp}\7z.exe"; Parameters: "x tuntapv9.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract TUN/TAP-v9 driver"; StatusMsg: "Extracting driver..."; OnlyBelowVersion: 0, 6.0
Filename: "{tmp}\7z.exe"; Parameters: "x tuntapv9_n6.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract TUN/TAP-v9 driver"; StatusMsg: "Extracting driver..."; MinVersion: 0, 6.0
Filename: "{tmp}\7z.exe"; Parameters: "x inet6.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract inet6 driver"; StatusMsg: "Extracting IPv6 driver..."; MinVersion: 0, 5.0; OnlyBelowVersion: 0, 5.1
Filename: "{tmp}\lokinet-bootstrap.exe"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "bootstrap dht"; StatusMsg: "Downloading initial RC..."
; then ask to install drivers
Filename: "{app}\tap-windows-9.9.2\install.bat"; WorkingDir: "{app}\tap-windows-9.9.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; OnlyBelowVersion: 0, 6.0
Filename: "{app}\tap-windows-9.21.2\install.bat"; WorkingDir: "{app}\tap-windows-9.21.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; MinVersion: 0, 6.0
; install inet6 if not present. (I'd assume netsh displays something helpful if inet6 is already set up and configured.)
Filename: "{app}\inet6_driver\setup\hotfix.exe"; Parameters: "/m /z"; WorkingDir: "{app}\inet6_driver\setup\"; Flags: runascurrentuser waituntilterminated; Description: "Install IPv6 driver"; StatusMsg: "Installing IPv6..."; OnlyBelowVersion: 0, 5.1
Filename: "{sys}\netsh.exe"; Parameters: "int ipv6 install"; Flags: runascurrentuser waituntilterminated; Description: "install ipv6 on whistler"; StatusMsg: "Installing IPv6..."; MinVersion: 0,5.1; OnlyBelowVersion: 0,6.0
Loading…
Cancel
Save