Compare commits

..
Author SHA1 Message Date
Adrien Béraud 4a5eedbf0a value: add common crypto ops 2016-06-14 18:13:02 -04:00
189 changed files with 9296 additions and 30045 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
Checks: '-*,clang-diagnostic-*,performance-*,bugprone-*,llvm-*,clang-analyzer-*,misc-*,-llvm-namespace-comment,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-llvm-header-guard,-llvm-include-order,-bugprone-suspicious-string-compare'
-34
View File
@@ -1,34 +0,0 @@
name: C/C++ CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: deps
run: |
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev
- name: autogen
run: ./autogen.sh
- name: argon2
run: |
cd argon2 && make && sudo make install && cd ..
- name: asio
run: |
wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \
&& tar -xvf b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz && cd asio-b2b7a1c166390459e1c169c8ae9ef3234b361e3f/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& sudo make install \
&& cd ../../ && rm -rf asio*
- name: configure
run: ./configure
- name: make
run: make
- name: make check
run: make check
-28
View File
@@ -45,31 +45,3 @@ Makefile.in
# KDevelop
.kdev4/
*.kdev4
# VSCode
.vscode/*
# Eclipse CDT
.cproject
.project
.autotools
language.settings.xml
# Python
*.pyc
*.stamp
python/opendht.cpp
python/setup.py
# Doxygen
doc/Doxyfile
# git backup files
*.orig
# vim swap files
*.swp
*.swo
# build dir
build
-4
View File
@@ -1,4 +0,0 @@
[submodule "argon2"]
path = argon2
url = https://github.com/P-H-C/phc-winner-argon2
ignore = dirty
+29 -53
View File
@@ -1,68 +1,44 @@
dist: xenial
sudo: required
sudo: false
services:
- docker
language: cpp
env:
matrix:
- OPENDHT_TEST_JOB="opendht.classic"
- OPENDHT_TEST_JOB="opendht.llvm"
- OPENDHT_TEST_JOB="opendht.proxyserver"
- OPENDHT_TEST_JOB="opendht.proxyclient"
- OPENDHT_TEST_JOB="opendht.push"
compiler:
- gcc
- clang
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-6
- g++-6
- libgnutls28-dev
- cmake
before_install:
- |
# non llvm builds
if [[ "$OPENDHT_TEST_JOB" != *"opendht.llvm"* ]]; then
docker pull aberaud/opendht-deps;
fi
- if [ $TRAVIS_OS_NAME == linux ] && [ $CXX == g++ ]; then export CXX=/usr/bin/g++-6 && export CC=/usr/bin/gcc-6; fi
- if [ $TRAVIS_OS_NAME == linux ]; then git clone https://github.com/msgpack/msgpack-c.git; fi
- if [ $TRAVIS_OS_NAME == linux ]; then cd msgpack-c && git checkout cpp-1.2.0 && mkdir build && mkdir -p $HOME/usr && cd build; fi
- if [ $TRAVIS_OS_NAME == linux ]; then cmake -DCMAKE_INSTALL_PREFIX=$HOME/usr -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF .. && make -j && make install && cd ../.. && pwd; fi
- if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install llvm36 && brew install msgpack && brew install gnutls && brew link --force llvm36; fi
- |
# classic build
if [[ "$OPENDHT_TEST_JOB" == *"opendht.llvm"* ]]; then
docker pull aberaud/opendht-deps-llvm
fi
before_script:
- if [ $TRAVIS_OS_NAME == linux ]; then travis_retry ./autogen.sh && ./configure --prefix=$HOME/usr; fi
- if [ $TRAVIS_OS_NAME == osx ]; then travis_retry ./autogen.sh && ./configure; fi
script:
- |
# classic build
if [[ "$OPENDHT_TEST_JOB" == *"opendht.classic"* ]]; then
docker build -t opendht -f docker/DockerfileTravis .;
fi
- |
# proxy builds
if [[ "$OPENDHT_TEST_JOB" != *"opendht.llvm"* ]] && [[ "$OPENDHT_TEST_JOB" != *"opendht.classic"* ]]; then
docker build -t opendht-proxy -f docker/DockerfileTravisProxy .;
options='-DOPENDHT_SANITIZE=On ';
if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyserver"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then
options+='-DOPENDHT_PROXY_SERVER=ON ';
else
options+='-DOPENDHT_PROXY_SERVER=OFF ';
fi
if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyclient"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then
options+='-DOPENDHT_PROXY_CLIENT=ON ';
else
options+='-DOPENDHT_PROXY_CLIENT=OFF ';
fi
if [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then
options+='-DOPENDHT_PUSH_NOTIFICATIONS=ON ';
else
options+='-DOPENDHT_PUSH_NOTIFICATIONS=OFF ';
fi
docker run opendht-proxy /bin/sh -c "cd /root/opendht && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=ON -DOPENDHT_LTO=ON -DOPENDHT_TESTS=ON $options .. && make -j8 && ./opendht_unit_tests && make install";
fi
- |
# llvm build
if [[ "$OPENDHT_TEST_JOB" == *"opendht.llvm"* ]]; then
docker build -f docker/DockerfileTravisLlvm .
fi
- make -j
notifications:
email:
- adrien.beraud@savoirfairelinux.com
env:
- LANG="en_US.UTF-8"
os:
- osx
+55 -346
View File
@@ -1,167 +1,43 @@
cmake_minimum_required (VERSION 3.1)
include(CMakePackageConfigHelpers)
include(CMakeDependentOption)
cmake_minimum_required (VERSION 2.8.6)
project (opendht)
set (opendht_VERSION_MAJOR 2)
set (opendht_VERSION_MINOR 0.0)
set (opendht_VERSION_MAJOR 0)
set (opendht_VERSION_MINOR 6.1)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
# Options
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
set (prefix ${CMAKE_INSTALL_PREFIX})
set (exec_prefix "\${prefix}")
set (libdir "\${exec_prefix}/lib")
set (includedir "\${prefix}/include")
option (OPENDHT_DEBUG "Build with debug flags" OFF)
option (OPENDHT_STATIC "Build static library" ON)
option (OPENDHT_SHARED "Build shared library" ON)
option (OPENDHT_LOG "Build with logs" ON)
option (OPENDHT_LTO "Build with LTO" OFF)
option (OPENDHT_PYTHON "Build Python bindings" OFF)
option (OPENDHT_TOOLS "Build DHT tools" ON)
option (OPENDHT_SYSTEMD "Install systemd module" OFF)
option (OPENDHT_ARGON2 "Use included argon2 sources" OFF)
option (OPENDHT_LTO "Build with LTO" OFF)
option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF)
option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restinio and jsoncpp" OFF)
option (OPENDHT_PUSH_NOTIFICATIONS "Enable push notifications support" OFF)
option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" OFF)
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF)
option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON)
option (OPENDHT_PROXY_HTTP_PARSER_FORK "Build DHT proxy with custom http_parser to support old API" OFF)
CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON)
option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
option (OPENDHT_TESTS "Add unit tests executable" OFF)
option (OPENDHT_C "Build C bindings" OFF)
find_package(Doxygen)
option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++11 -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
if (OPENDHT_LTO)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -fuse-linker-plugin")
if (CMAKE_COMPILER_IS_GNUCC)
SET (CMAKE_AR "gcc-ar")
SET (CMAKE_NM "gcc-nm")
SET (CMAKE_RANLIB "gcc-ranlib")
endif ()
endif ()
# Dependencies
list (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
find_package (Threads)
find_package (PkgConfig)
find_package (GnuTLS 3.3 REQUIRED)
pkg_search_module (Nettle nettle)
find_package (GnuTLS 3.1 REQUIRED)
find_package (Msgpack 1.2 REQUIRED)
if (OPENDHT_TOOLS)
find_package (Readline 6 REQUIRED)
endif ()
if (NOT OPENDHT_ARGON2)
find_package(PkgConfig)
pkg_search_module(argon2 libargon2)
if (argon2_FOUND)
message("-- Found Argon2: " ${argon2_LIBRARY_DIRS} " (found version \"" ${argon2_VERSION} "\")")
link_directories (${argon2_LIBRARY_DIRS})
else ()
message("Argon2 not found, using included version.")
set(OPENDHT_ARGON2 ON)
endif()
endif ()
pkg_search_module(Jsoncpp jsoncpp)
if (Jsoncpp_FOUND)
add_definitions(-DOPENDHT_JSONCPP)
list (APPEND opendht_SOURCES
src/base64.h
src/base64.cpp
)
endif()
if (OPENDHT_HTTP)
find_package(Restinio REQUIRED)
if (Restinio_FOUND)
find_library(FMT_LIBRARY fmt)
add_library(fmt SHARED IMPORTED)
find_library(HTTP_PARSER_LIBRARY http_parser)
add_library(http_parser SHARED IMPORTED)
endif()
if (NOT Jsoncpp_FOUND)
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
endif()
if (OPENDHT_PROXY_OPENSSL)
# https://cmake.org/cmake/help/latest/module/FindOpenSSL.html
pkg_search_module(OPENSSL REQUIRED openssl)
if (OPENSSL_FOUND)
message(STATUS "Found OpenSSL ${OPENSSL_VERSION}")
include_directories(${OPENSSL_INCLUDE_DIRS})
else ()
message(SEND_ERROR "OpenSSL is required for DHT proxy as specified")
endif()
endif()
if (OPENDHT_PROXY_HTTP_PARSER_FORK)
add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK)
endif()
else()
set(OPENDHT_PROXY_OPENSSL OFF)
endif()
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
add_definitions(-DASIO_STANDALONE)
endif()
# Build flags
set (CMAKE_CXX_STANDARD 14)
set (CMAKE_CXX_STANDARD_REQUIRED on)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -pedantic-errors -fvisibility=hidden")
if (OPENDHT_SANITIZE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fstack-protector-strong")
endif ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
add_definitions(-DPACKAGE_VERSION="${opendht_VERSION}")
if (OPENDHT_LOG)
add_definitions(-DOPENDHT_LOG=true)
else ()
add_definitions(-DOPENDHT_LOG=false)
endif()
if (OPENDHT_LTO)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
if (CMAKE_COMPILER_IS_GNUCC)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-linker-plugin")
set (CMAKE_AR "gcc-ar")
set (CMAKE_NM "gcc-nm")
set (CMAKE_RANLIB "gcc-ranlib")
endif ()
endif ()
if (MSGPACK_INCLUDE_DIRS)
include_directories (SYSTEM "${MSGPACK_INCLUDE_DIRS}")
endif ()
if (GNUTLS_INCLUDE_DIRS)
include_directories (SYSTEM "${GNUTLS_INCLUDE_DIRS}")
endif ()
if (Nettle_INCLUDE_DIRS)
include_directories (SYSTEM "${Nettle_INCLUDE_DIRS}")
endif ()
if (Restinio_INCLUDE_DIR)
include_directories (SYSTEM "${Restinio_INCLUDE_DIR}")
endif ()
if (Jsoncpp_INCLUDE_DIRS)
include_directories (SYSTEM "${Jsoncpp_INCLUDE_DIRS}")
endif ()
if (OpenSSL_INCLUDE_DIR)
include_directories (SYSTEM "${OpenSSL_INCLUDE_DIR}")
endif ()
link_directories (${Nettle_LIBRARY_DIRS})
link_directories (${Jsoncpp_LIBRARY_DIRS})
include_directories (
./
include/
include/opendht/
${CMAKE_CURRENT_BINARY_DIR}/include/
)
# Install dirs
include (GNUInstallDirs)
set (prefix ${CMAKE_INSTALL_PREFIX})
set (exec_prefix "\${prefix}")
set (libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
set (includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
set (bindir "${CMAKE_INSTALL_FULL_BINDIR}")
set (sysconfdir "${CMAKE_INSTALL_FULL_SYSCONFDIR}")
set (top_srcdir "${CMAKE_CURRENT_SOURCE_DIR}")
# Sources
list (APPEND opendht_SOURCES
src/utils.cpp
src/infohash.cpp
@@ -170,30 +46,22 @@ list (APPEND opendht_SOURCES
src/node.cpp
src/value.cpp
src/dht.cpp
src/op_cache.cpp
src/storage.h
src/listener.h
src/search.h
src/value_cache.h
src/op_cache.h
src/net.h
src/parsed_message.h
src/request.h
src/callbacks.cpp
src/routing_table.cpp
src/node_cache.cpp
src/network_engine.cpp
src/securedht.cpp
src/dhtrunner.cpp
src/log.cpp
src/network_utils.cpp
src/thread_pool.cpp
src/argon2/argon2.c
src/argon2/core.c
src/argon2/blake2/blake2b.c
src/argon2/thread.c
src/argon2/encoding.c
src/argon2/ref.c
)
list (APPEND opendht_HEADERS
include/opendht/def.h
include/opendht/utils.h
include/opendht/sockaddr.h
include/opendht/rng.h
include/opendht/crypto.h
include/opendht/infohash.h
@@ -201,109 +69,50 @@ list (APPEND opendht_HEADERS
include/opendht/node.h
include/opendht/value.h
include/opendht/dht.h
include/opendht/dht_interface.h
include/opendht/callbacks.h
include/opendht/routing_table.h
include/opendht/node_cache.h
include/opendht/network_engine.h
include/opendht/scheduler.h
include/opendht/rate_limiter.h
include/opendht/securedht.h
include/opendht/log.h
include/opendht/log_enable.h
include/opendht/thread_pool.h
include/opendht/network_utils.h
include/opendht.h
)
if (OPENDHT_PEER_DISCOVERY)
list (APPEND opendht_SOURCES src/peer_discovery.cpp)
list (APPEND opendht_HEADERS include/opendht/peer_discovery.h)
add_definitions(-DOPENDHT_PEER_DISCOVERY)
endif()
configure_file (
opendht.pc.in
opendht.pc
@ONLY
)
if (OPENDHT_PYTHON)
message("Indexation enabled since it is required for Python support")
set(OPENDHT_INDEX ON)
endif()
if (OPENDHT_INDEX)
list (APPEND opendht_SOURCES src/indexation/pht.cpp)
list (APPEND opendht_HEADERS include/opendht/indexation/pht.h)
add_definitions(-DOPENDHT_INDEXATION)
endif()
include_directories (
./
include/
include/opendht/
${CMAKE_CURRENT_BINARY_DIR}/include/
)
if (OPENDHT_PROXY_SERVER)
add_definitions(-DOPENDHT_PROXY_SERVER)
if (OPENDHT_PROXY_SERVER_IDENTITY)
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY)
endif()
list (APPEND opendht_HEADERS
include/opendht/dht_proxy_server.h
)
list (APPEND opendht_SOURCES
src/dht_proxy_server.cpp
)
if (OPENDHT_DEBUG)
set(CMAKE_BUILD_TYPE Debug)
else ()
set(CMAKE_BUILD_TYPE Release)
endif ()
if (OPENDHT_PROXY_CLIENT)
add_definitions(-DOPENDHT_PROXY_CLIENT)
list (APPEND opendht_HEADERS
include/opendht/dht_proxy_client.h
)
list (APPEND opendht_SOURCES
src/dht_proxy_client.cpp
)
if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR lib)
endif ()
if (OPENDHT_HTTP)
if (OPENDHT_PUSH_NOTIFICATIONS)
message("Using push notification")
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS)
endif ()
list (APPEND opendht_HEADERS
include/opendht/proxy.h
include/opendht/http.h
)
list (APPEND opendht_SOURCES
src/http.cpp
)
endif ()
if(OPENDHT_ARGON2)
# make sure argon2 submodule is up to date and initialized
message("Initializing Argon2 submodule")
execute_process(COMMAND git submodule update --init)
# add local argon2 files to build
list (APPEND opendht_SOURCES
argon2/src/argon2.c
argon2/src/core.c
argon2/src/blake2/blake2b.c
argon2/src/thread.c
argon2/src/ref.c
argon2/src/encoding.c
)
include_directories(argon2/include/)
endif()
# Targets
if (OPENDHT_STATIC)
add_library (opendht-static STATIC
${opendht_SOURCES}
${opendht_HEADERS}
)
set_target_properties (opendht-static PROPERTIES OUTPUT_NAME "opendht")
if (OPENDHT_ARGON2)
target_include_directories(opendht-static SYSTEM PRIVATE argon2)
else ()
target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
if (OPENDHT_LTO)
target_link_libraries(opendht-static -flto -fuse-linker-plugin)
endif ()
target_link_libraries(opendht-static
PRIVATE ${argon2_LIBRARIES}
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES} ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY}
${OPENSSL_LIBRARIES})
install (TARGETS opendht-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
target_link_libraries(opendht-static gnutls nettle)
install (TARGETS opendht-static DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif ()
if (OPENDHT_SHARED)
@@ -313,120 +122,20 @@ if (OPENDHT_SHARED)
)
set_target_properties (opendht PROPERTIES IMPORT_SUFFIX "_import.lib")
set_target_properties (opendht PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION})
target_compile_definitions(opendht PRIVATE OPENDHT_BUILD)
if (OPENDHT_ARGON2)
target_include_directories(opendht SYSTEM PRIVATE argon2)
else ()
target_link_libraries(opendht PRIVATE ${argon2_LIBRARIES})
target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
if (OPENDHT_LTO)
target_link_libraries(opendht -flto -fuse-linker-plugin)
endif ()
target_link_libraries(opendht
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY})
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
endif ()
if (OPENDHT_C)
add_library (opendht-c SHARED
c/opendht.cpp
c/opendht_c.h
)
target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD)
if (OPENDHT_SHARED)
target_link_libraries(opendht-c opendht)
else ()
target_link_libraries(opendht-c opendht-static)
endif ()
# PkgConfig module
configure_file (
opendht-c.pc.in
opendht-c.pc
@ONLY
)
install (TARGETS opendht-c DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendht-c.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
target_link_libraries(opendht gnutls nettle)
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif ()
if (OPENDHT_TOOLS)
add_subdirectory(tools)
endif ()
add_subdirectory(doc)
if (OPENDHT_PYTHON)
add_subdirectory(python)
endif ()
# CMake module
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake"
VERSION ${opendht_VERSION}
COMPATIBILITY AnyNewerVersion
)
# PkgConfig module
configure_file (
opendht.pc.in
opendht.pc
@ONLY
)
# Install targets
install (DIRECTORY include DESTINATION ${CMAKE_INSTALL_PREFIX})
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendht.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install (EXPORT opendht DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht FILE opendhtConfig.cmake)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht)
# Unit tests
if (OPENDHT_TESTS)
FIND_PACKAGE(Cppunit REQUIRED)
# unit testing
list (APPEND test_FILES
tests/infohashtester.h
tests/infohashtester.cpp
tests/valuetester.h
tests/valuetester.cpp
tests/cryptotester.h
tests/cryptotester.cpp
tests/dhtrunnertester.h
tests/dhtrunnertester.cpp
tests/threadpooltester.h
tests/threadpooltester.cpp
)
if (OPENDHT_PROXY_SERVER AND OPENDHT_PROXY_CLIENT)
list (APPEND test_FILES
tests/httptester.h
tests/httptester.cpp
tests/dhtproxytester.h
tests/dhtproxytester.cpp
)
endif()
if (OPENDHT_PEER_DISCOVERY)
list (APPEND test_FILES
tests/peerdiscoverytester.h
tests/peerdiscoverytester.cpp
)
endif()
add_executable(opendht_unit_tests
tests/tests_runner.cpp
${test_FILES}
)
target_include_directories(opendht_unit_tests SYSTEM PRIVATE ${CPPUNIT_INCLUDE_DIRS})
if (OPENDHT_SHARED)
target_link_libraries(opendht_unit_tests opendht)
else ()
target_link_libraries(opendht_unit_tests opendht-static)
endif ()
target_link_libraries(opendht_unit_tests
${CMAKE_THREAD_LIBS_INIT}
${CPPUNIT_LIBRARIES}
${GNUTLS_LIBRARIES}
${Jsoncpp_LIBRARIES}
)
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht_unit_tests ${OPENSSL_LIBRARIES})
endif()
enable_testing()
add_test(TEST opendht_unit_tests)
endif()
+2 -2
View File
@@ -15,6 +15,7 @@ Release/
*.VC.VC.opendb
*.VC.db
*.db
*.filters
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
@@ -244,5 +245,4 @@ _Pvt_Extensions
# FAKE - F# Make
.fake/
!config.h
contrib/build/
!config.h
-168
View File
@@ -1,168 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}</ProjectGuid>
<RootNamespace>dhtchat</RootNamespace>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<OutDir>$(ProjectDir)..\..\bin\x64</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\tools\dhtchat.cpp" />
<ClCompile Include="wingetopt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tools\tools_common.h" />
<ClInclude Include="wingetopt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-168
View File
@@ -1,168 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}</ProjectGuid>
<RootNamespace>dhtnode</RootNamespace>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<OutDir>$(ProjectDir)..\..\bin\x64</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\tools\dhtnode.cpp" />
<ClCompile Include="wingetopt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tools\tools_common.h" />
<ClInclude Include="wingetopt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-168
View File
@@ -1,168 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{78443BCD-4689-4007-A246-F8F34B27F561}</ProjectGuid>
<RootNamespace>dhtscanner</RootNamespace>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<OutDir>$(ProjectDir)..\..\bin\x64</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\tools\dhtscanner.cpp" />
<ClCompile Include="wingetopt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tools\tools_common.h" />
<ClInclude Include="wingetopt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+37 -84
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -19,29 +19,12 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\dht_proxy_client.cpp" />
<ClCompile Include="..\src\http.cpp" />
<ClCompile Include="..\src\network_utils.cpp" />
<ClCompile Include="..\src\op_cache.cpp" />
<ClCompile Include="..\src\peer_discovery.cpp" />
<ClCompile Include="..\src\rng.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\src\thread_pool.cpp" />
<ClCompile Include="wingetopt.c" />
<ClCompile Include="..\src\base64.cpp" />
<ClCompile Include="..\src\callbacks.cpp" />
<ClCompile Include="..\src\crypto.cpp" />
<ClCompile Include="..\src\default_types.cpp" />
<ClCompile Include="..\src\dht.cpp" />
<ClCompile Include="..\src\dhtrunner.cpp" />
<ClCompile Include="..\src\dht_proxy_server.cpp" />
<ClCompile Include="..\src\indexation\pht.cpp" />
<ClCompile Include="..\src\infohash.cpp" />
<ClCompile Include="..\src\log.cpp" />
<ClCompile Include="..\src\network_engine.cpp" />
<ClCompile Include="..\src\node.cpp" />
<ClCompile Include="..\src\node_cache.cpp" />
@@ -51,71 +34,54 @@
<ClCompile Include="..\src\value.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\opendht\http.h" />
<ClInclude Include="..\src\network_utils.h" />
<ClInclude Include="..\src\thread_pool.h" />
<ClInclude Include="unistd.h" />
<ClInclude Include="wingetopt.h" />
<ClInclude Include="..\include\opendht.h" />
<ClInclude Include="..\include\opendht\callbacks.h" />
<ClInclude Include="..\include\opendht\crypto.h" />
<ClInclude Include="..\include\opendht\def.h" />
<ClInclude Include="..\include\opendht\default_types.h" />
<ClInclude Include="..\include\opendht\dht.h" />
<ClInclude Include="..\include\opendht\dhtrunner.h" />
<ClInclude Include="..\include\opendht\dht_proxy_server.h" />
<ClInclude Include="..\include\opendht\indexation\pht.h" />
<ClInclude Include="..\include\opendht\infohash.h" />
<ClInclude Include="..\include\opendht\log.h" />
<ClInclude Include="..\include\opendht\log_enable.h" />
<ClInclude Include="..\include\opendht\network_engine.h" />
<ClInclude Include="..\include\opendht\node.h" />
<ClInclude Include="..\include\opendht\node_cache.h" />
<ClInclude Include="..\include\opendht\rate_limiter.h" />
<ClInclude Include="..\include\opendht\request.h" />
<ClInclude Include="..\include\opendht\rng.h" />
<ClInclude Include="..\include\opendht\routing_table.h" />
<ClInclude Include="..\include\opendht\scheduler.h" />
<ClInclude Include="..\include\opendht\securedht.h" />
<ClInclude Include="..\include\opendht\sockaddr.h" />
<ClInclude Include="..\include\opendht\utils.h" />
<ClInclude Include="..\include\opendht\value.h" />
<ClInclude Include="..\src\base64.h" />
<ClInclude Include="..\src\listener.h" />
<ClInclude Include="..\src\net.h" />
<ClInclude Include="..\src\parsed_message.h" />
<ClInclude Include="..\src\request.h" />
<ClInclude Include="..\src\search.h" />
<ClInclude Include="..\src\storage.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{711397CE-E5D5-467D-9457-8716C047E50C}</ProjectGuid>
<RootNamespace>opendht</RootNamespace>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
@@ -138,45 +104,42 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
<OutDir>$(ProjectDir)..\..\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>libopendht</TargetName>
<TargetName>opendhtd</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
<OutDir>$(ProjectDir)..\..\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>libopendht</TargetName>
<TargetName>opendht</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
<TargetName>libopendht</TargetName>
<OutDir>$(ProjectDir)..\..\</OutDir>
<TargetName>opendhtd</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
<TargetName>libopendht</TargetName>
<OutDir>$(ProjectDir)..\..\</OutDir>
<TargetName>opendht</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\openssl\inc32;$(ProjectDir)..\..\asio\asio\include;$(ProjectDir)..\..\restinio\dev;$(ProjectDir)..\..\fmt\include;$(ProjectDir)..\..\http_parser</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;ASIO_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNING;%(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<SuppressStartupBanner>false</SuppressStartupBanner>
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
mkdir $(OutDir)\include\opendht
mkdir $(OutDir)\include\opendht\indexation
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
<Lib>
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -184,22 +147,19 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\openssl\inc32;$(ProjectDir)..\..\asio\asio\include;$(ProjectDir)..\..\restinio\dev;$(ProjectDir)..\..\fmt\include;$(ProjectDir)..\..\http_parser</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;ASIO_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNING;%(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
mkdir $(OutDir)\include\opendht
mkdir $(OutDir)\include\opendht\indexation
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
<Lib>
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -209,11 +169,11 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\openssl\inc32;$(ProjectDir)..\..\asio\asio\include;$(ProjectDir)..\..\restinio\dev;$(ProjectDir)..\..\fmt\include;$(ProjectDir)..\..\http_parser</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;ASIO_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNING;%(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -222,13 +182,11 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
mkdir $(OutDir)\include\opendht
mkdir $(OutDir)\include\opendht\indexation
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
<Lib>
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
@@ -239,12 +197,11 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\openssl\inc32;$(ProjectDir)..\..\asio\asio\include;$(ProjectDir)..\..\restinio\dev;$(ProjectDir)..\..\fmt\include;$(ProjectDir)..\..\http_parser</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;ASIO_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNING;%(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -253,16 +210,12 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
mkdir $(OutDir)\include\opendht
mkdir $(OutDir)\include\opendht\indexation
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
<Lib>
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
<AdditionalLibraryDirectories>
</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-198
View File
@@ -1,198 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\src\callbacks.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\crypto.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\default_types.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\dht.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\dhtrunner.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\infohash.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\log.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\network_engine.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\node.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\node_cache.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\routing_table.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\securedht.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\value.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\base64.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\dht_proxy_server.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\indexation\pht.cpp">
<Filter>Source Files\indexation</Filter>
</ClCompile>
<ClCompile Include="wingetopt.c" />
<ClCompile Include="..\src\rng.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\op_cache.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\dht_proxy_client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\peer_discovery.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\network_utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\thread_pool.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\http.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\opendht.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\callbacks.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\crypto.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\default_types.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\dht.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\dht_proxy_server.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\dhtrunner.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\infohash.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\log.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\log_enable.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\network_engine.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\node.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\node_cache.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\rate_limiter.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\rng.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\routing_table.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\scheduler.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\securedht.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\utils.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\value.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\indexation\pht.h">
<Filter>Header Files\opendht\indexation</Filter>
</ClInclude>
<ClInclude Include="unistd.h" />
<ClInclude Include="wingetopt.h" />
<ClInclude Include="..\include\opendht\def.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\net.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\parsed_message.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\sockaddr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\network_utils.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\src\thread_pool.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\src\listener.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\base64.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\search.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\request.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\storage.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\http.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{be73d179-6cf2-4c05-8d91-53c8499a7134}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{d1ab5bfe-3ab1-45ee-9324-b4b071887668}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\indexation">
<UniqueIdentifier>{939134d3-d5a2-4458-bca8-a10ea9042ea2}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\opendht">
<UniqueIdentifier>{0b46e2d0-4874-404c-bae3-fae8d49b85b8}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\opendht\indexation">
<UniqueIdentifier>{03bd5139-2ae5-41b0-a77b-944814e1b2b6}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
+292
View File
@@ -0,0 +1,292 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opendht", "opendht.vcxproj", "{711397CE-E5D5-467D-9457-8716C047E50C}"
ProjectSection(ProjectDependencies) = postProject
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518} = {070FEF2B-0C3F-4F33-9D3C-53C7330BF518}
{122A2EA4-B283-4241-9655-786DE78283B2} = {122A2EA4-B283-4241-9655-786DE78283B2}
{6F610EE8-7F59-4191-AB88-F63843267C02} = {6F610EE8-7F59-4191-AB88-F63843267C02}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{71A1A9EC-1104-4335-A87E-AF8749FD5B34}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgmp", "..\..\gmp\MSVC\libgmp.vcxproj", "{02B94302-23D6-43EF-8865-95CDE99D5DC2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgnutls", "..\..\gnutls\MSVC\libgnutls.vcxproj", "{6F610EE8-7F59-4191-AB88-F63843267C02}"
ProjectSection(ProjectDependencies) = postProject
{02B94302-23D6-43EF-8865-95CDE99D5DC2} = {02B94302-23D6-43EF-8865-95CDE99D5DC2}
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518} = {070FEF2B-0C3F-4F33-9D3C-53C7330BF518}
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32} = {CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C} = {200F3D3C-8B84-46D8-953A-6C0EBD283B5C}
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B} = {CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libiconv", "..\..\libiconv\MSVC\libiconv.vcxproj", "{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libhogweed", "..\..\nettle\MSVC\libhogweed.vcxproj", "{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}"
ProjectSection(ProjectDependencies) = postProject
{02B94302-23D6-43EF-8865-95CDE99D5DC2} = {02B94302-23D6-43EF-8865-95CDE99D5DC2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnettle", "..\..\nettle\MSVC\libnettle.vcxproj", "{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzlib", "..\..\zlib\MSVC\libzlib.vcxproj", "{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MessagePack", "..\..\msgpack-c\msgpack_vc8.vcxproj", "{122A2EA4-B283-4241-9655-786DE78283B2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
DebugDLL|x64 = DebugDLL|x64
DebugDLL|x86 = DebugDLL|x86
DebugDLLStaticDeps|x64 = DebugDLLStaticDeps|x64
DebugDLLStaticDeps|x86 = DebugDLLStaticDeps|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
ReleaseDLL|x64 = ReleaseDLL|x64
ReleaseDLL|x86 = ReleaseDLL|x86
ReleaseDLLStaticDeps|x64 = ReleaseDLLStaticDeps|x64
ReleaseDLLStaticDeps|x86 = ReleaseDLLStaticDeps|x86
ReleaseLTO|x64 = ReleaseLTO|x64
ReleaseLTO|x86 = ReleaseLTO|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x64.ActiveCfg = Debug|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x64.Build.0 = Debug|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x86.ActiveCfg = Debug|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x86.Build.0 = Debug|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x64.ActiveCfg = Debug|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x64.Build.0 = Debug|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x86.ActiveCfg = Debug|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x86.Build.0 = Debug|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x64.ActiveCfg = Release|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x64.Build.0 = Release|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x86.ActiveCfg = Release|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x86.Build.0 = Release|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x64.ActiveCfg = Release|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x64.Build.0 = Release|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x86.ActiveCfg = Release|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x86.Build.0 = Release|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x64.ActiveCfg = Release|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x64.Build.0 = Release|x64
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x86.ActiveCfg = Release|Win32
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x86.Build.0 = Release|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x64.ActiveCfg = Debug|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x64.Build.0 = Debug|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x86.ActiveCfg = Debug|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x86.Build.0 = Debug|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x64.Build.0 = DebugDLL|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x86.Build.0 = DebugDLL|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x64.ActiveCfg = Release|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x64.Build.0 = Release|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x86.ActiveCfg = Release|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x86.Build.0 = Release|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x64.ActiveCfg = Debug|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x64.Build.0 = Debug|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x86.ActiveCfg = Debug|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x86.Build.0 = Debug|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x64.Build.0 = DebugDLL|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x86.Build.0 = DebugDLL|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLLStaticDeps|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x64.Build.0 = DebugDLLStaticDeps|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLLStaticDeps|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x86.Build.0 = DebugDLLStaticDeps|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x64.ActiveCfg = Release|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x64.Build.0 = Release|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x86.ActiveCfg = Release|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x86.Build.0 = Release|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLLStaticDeps|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLLStaticDeps|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLLStaticDeps|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLLStaticDeps|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x64.ActiveCfg = Debug|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x64.Build.0 = Debug|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x86.ActiveCfg = Debug|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x86.Build.0 = Debug|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x64.Build.0 = DebugDLL|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x86.Build.0 = DebugDLL|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x64.ActiveCfg = Release|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x64.Build.0 = Release|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x86.ActiveCfg = Release|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x86.Build.0 = Release|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x64.ActiveCfg = Debug|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x64.Build.0 = Debug|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x86.ActiveCfg = Debug|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x86.Build.0 = Debug|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x64.Build.0 = DebugDLL|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x86.Build.0 = DebugDLL|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLLStaticDeps|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x64.Build.0 = DebugDLLStaticDeps|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLLStaticDeps|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x86.Build.0 = DebugDLLStaticDeps|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x64.ActiveCfg = Release|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x64.Build.0 = Release|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x86.ActiveCfg = Release|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x86.Build.0 = Release|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLLStaticDeps|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLLStaticDeps|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLLStaticDeps|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLLStaticDeps|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x64.ActiveCfg = Debug|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x64.Build.0 = Debug|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x86.ActiveCfg = Debug|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x86.Build.0 = Debug|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x64.Build.0 = DebugDLL|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x86.Build.0 = DebugDLL|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x64.ActiveCfg = Release|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x64.Build.0 = Release|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x86.ActiveCfg = Release|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x86.Build.0 = Release|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x64.ActiveCfg = Debug|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x64.Build.0 = Debug|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x86.ActiveCfg = Debug|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x86.Build.0 = Debug|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x64.Build.0 = DebugDLL|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x86.Build.0 = DebugDLL|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x64.ActiveCfg = Release|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x64.Build.0 = Release|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x86.ActiveCfg = Release|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x86.Build.0 = Release|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x64.ActiveCfg = Debug|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x86.ActiveCfg = Debug|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x86.Build.0 = Debug|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x64.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x64.Build.0 = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x86.ActiveCfg = Debug|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x86.Build.0 = Debug|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x64.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x64.Build.0 = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x64.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x86.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x86.Build.0 = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x64.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x64.Build.0 = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x86.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x86.Build.0 = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x64.Build.0 = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x64.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x64.Build.0 = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x86.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{02B94302-23D6-43EF-8865-95CDE99D5DC2} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{6F610EE8-7F59-4191-AB88-F63843267C02} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{122A2EA4-B283-4241-9655-786DE78283B2} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
EndGlobalSection
EndGlobal
+71
View File
@@ -0,0 +1,71 @@
@ECHO OFF
SETLOCAL EnableDelayedExpansion
SET UPSTREAMURL=https://github.com/atraczyk
SET DEPENDENCIES=( ^
gmp, ^
gnutls, ^
nettle, ^
msgpack-c ^
)
SET PASSDEPENDENCIES=%~1
git status >NUL 2>&1
IF %ERRORLEVEL% EQU 128 (
git init
) ELSE (
IF %ERRORLEVEL% EQU 9009 (
ECHO git not installed.
EXIT /B 1
)
)
SET CURRDIR=%~dp1
cd ..\..
FOR %%I IN %DEPENDENCIES% DO (
ECHO !PASSDEPENDENCIES! | FINDSTR /C:"%%I" >NUL 2>&1 || (
CALL :cloneOrUpdateRepo "%%I" )
)
cd %CURRDIR% >NUL
GOTO exit
:cloneOrUpdateRepo
SET REPONAME=%~1
IF NOT EXIST "%REPONAME%" (
ECHO %REPONAME%: Existing folder not found. Cloning repository...
SET REPOURL=%UPSTREAMURL%/%REPONAME%.git
git clone !REPOURL! --quiet
cd %REPONAME%
git config --local core.autocrlf false
git rm --cached -r . --quiet
git reset --hard --quiet
cd ..\
)
SET PASSDEPENDENCIES=%PASSDEPENDENCIES% %REPONAME%
IF EXIST "%REPONAME%\MSVC\project_get_dependencies.bat" (
ECHO %REPONAME%: Found additional dependencies...
ECHO.
cd %REPONAME%\MSVC
project_get_dependencies.bat "!PASSDEPENDENCIES!" || GOTO exitOnError
cd ..\..
)
ECHO.
EXIT /B %ERRORLEVEL%
:exitOnError
cd %CURRDIR%
:exit
(
ENDLOCAL
SET PASSDEPENDENCIES=%PASSDEPENDENCIES%
)
ECHO %CMDCMDLINE% | FINDSTR /L %COMSPEC% >NUL 2>&1
IF %ERRORLEVEL% == 0 IF "%~1"=="" PAUSE
EXIT /B 0
-53
View File
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#ifndef __STRICT_ANSI__
#include <stdlib.h>
#include <process.h>
#include <direct.h>
#include <fcntl.h>
#define R_OK 4
#define W_OK 2
#define F_OK 0
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
#define srandom srand
#define random rand
#define inline __inline
typedef int mode_t;
#include <BaseTsd.h>
#endif
-971
View File
@@ -1,971 +0,0 @@
/* Getopt for Microsoft C
This code is a modification of the Free Software Foundation, Inc.
Getopt library for parsing command line argument the purpose was
to provide a Microsoft Visual C friendly derivative. This code
provides functionality for both Unicode and Multibyte builds.
Date: 02/03/2011 - Ludvik Jerabek - Initial Release
Version: 1.0
Comment: Supports getopt, getopt_long, and getopt_long_only
and POSIXLY_CORRECT environment flag
License: LGPL
Revisions:
02/03/2011 - Ludvik Jerabek - Initial Release
02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
**DISCLAIMER**
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include "wingetopt.h"
#ifdef __cplusplus
#define _GETOPT_THROW throw()
#else
#define _GETOPT_THROW
#endif
int optind = 1;
int opterr = 1;
int optopt = '?';
enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
//
//
// Ansi structures and functions follow
//
//
static struct _getopt_data_a
{
int optind;
int opterr;
int optopt;
char *optarg;
int __initialized;
char *__nextchar;
enum ENUM_ORDERING __ordering;
int __posixly_correct;
int __first_nonopt;
int __last_nonopt;
} getopt_data_a;
char *optarg_a;
static void exchange_a(char **argv, struct _getopt_data_a *d)
{
int bottom = d->__first_nonopt;
int middle = d->__last_nonopt;
int top = d->optind;
char *tem;
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
int len = middle - bottom;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
top -= len;
}
else
{
int len = top - middle;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
bottom += len;
}
}
d->__first_nonopt += (d->optind - d->__last_nonopt);
d->__last_nonopt = d->optind;
}
static const char *_getopt_initialize_a (const char *optstring, struct _getopt_data_a *d, int posixly_correct)
{
d->__first_nonopt = d->__last_nonopt = d->optind;
d->__nextchar = NULL;
d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT");
if (optstring[0] == '-')
{
d->__ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
d->__ordering = REQUIRE_ORDER;
++optstring;
}
else if (d->__posixly_correct)
d->__ordering = REQUIRE_ORDER;
else
d->__ordering = PERMUTE;
return optstring;
}
int _getopt_internal_r_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct)
{
int print_errors = d->opterr;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
{
if (d->optind == 0)
d->optind = 1;
optstring = _getopt_initialize_a (optstring, d, posixly_correct);
d->__initialized = 1;
}
else if (optstring[0] == '-' || optstring[0] == '+')
optstring++;
if (optstring[0] == ':')
print_errors = 0;
if (d->__nextchar == NULL || *d->__nextchar == '\0')
{
if (d->__last_nonopt > d->optind)
d->__last_nonopt = d->optind;
if (d->__first_nonopt > d->optind)
d->__first_nonopt = d->optind;
if (d->__ordering == PERMUTE)
{
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_a ((char **) argv, d);
else if (d->__last_nonopt != d->optind)
d->__first_nonopt = d->optind;
while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
d->optind++;
d->__last_nonopt = d->optind;
}
if (d->optind != argc && !strcmp(argv[d->optind], "--"))
{
d->optind++;
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_a((char **) argv, d);
else if (d->__first_nonopt == d->__last_nonopt)
d->__first_nonopt = d->optind;
d->__last_nonopt = argc;
d->optind = argc;
}
if (d->optind == argc)
{
if (d->__first_nonopt != d->__last_nonopt)
d->optind = d->__first_nonopt;
return -1;
}
if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
{
if (d->__ordering == REQUIRE_ORDER)
return -1;
d->optarg = argv[d->optind++];
return 1;
}
d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-'));
}
if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1])))))
{
char *nameend;
unsigned int namelen;
const struct option_a *p;
const struct option_a *pfound = NULL;
struct option_list
{
const struct option_a *p;
struct option_list *next;
} *ambig_list = NULL;
int exact = 0;
int indfound = -1;
int option_index;
for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++);
namelen = (unsigned int)(nameend - d->__nextchar);
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp(p->name, d->__nextchar, namelen))
{
if (namelen == (unsigned int)strlen(p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
{
struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
newp->p = p;
newp->next = ambig_list;
ambig_list = newp;
}
}
if (ambig_list != NULL && !exact)
{
if (print_errors)
{
struct option_list first;
first.p = pfound;
first.next = ambig_list;
ambig_list = &first;
fprintf (stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
do
{
fprintf (stderr, " '--%s'", ambig_list->p->name);
ambig_list = ambig_list->next;
}
while (ambig_list != NULL);
fputc ('\n', stderr);
}
d->__nextchar += strlen(d->__nextchar);
d->optind++;
d->optopt = 0;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
d->optind++;
if (*nameend)
{
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
if (argv[d->optind - 1][1] == '-')
{
fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
}
else
{
fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
}
}
d->__nextchar += strlen(d->__nextchar);
d->optopt = pfound->val;
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
fprintf(stderr,"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
}
d->__nextchar += strlen(d->__nextchar);
d->optopt = pfound->val;
return optstring[0] == ':' ? ':' : '?';
}
}
d->__nextchar += strlen(d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL)
{
if (print_errors)
{
if (argv[d->optind][1] == '-')
{
fprintf(stderr, "%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
}
else
{
fprintf(stderr, "%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
}
}
d->__nextchar = (char *)"";
d->optind++;
d->optopt = 0;
return '?';
}
}
{
char c = *d->__nextchar++;
char *temp = (char*)strchr(optstring, c);
if (*d->__nextchar == '\0')
++d->optind;
if (temp == NULL || c == ':' || c == ';')
{
if (print_errors)
{
fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c);
}
d->optopt = c;
return '?';
}
if (temp[0] == 'W' && temp[1] == ';')
{
char *nameend;
const struct option_a *p;
const struct option_a *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = 0;
int option_index;
if (longopts == NULL)
goto no_longs;
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
}
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
return c;
}
else
d->optarg = argv[d->optind++];
for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++);
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar))
{
if ((unsigned int) (nameend - d->__nextchar) == strlen(p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
ambig = 1;
}
if (ambig && !exact)
{
if (print_errors)
{
fprintf(stderr, "%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
}
d->__nextchar += strlen(d->__nextchar);
d->optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
if (*nameend)
{
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
}
d->__nextchar += strlen(d->__nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
fprintf(stderr, "%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
}
d->__nextchar += strlen(d->__nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
else
d->optarg = NULL;
d->__nextchar += strlen(d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
no_longs:
d->__nextchar = NULL;
return 'W';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else
d->optarg = NULL;
d->__nextchar = NULL;
}
else
{
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
}
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
d->optarg = argv[d->optind++];
d->__nextchar = NULL;
}
}
return c;
}
}
int _getopt_internal_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct)
{
int result;
getopt_data_a.optind = optind;
getopt_data_a.opterr = opterr;
result = _getopt_internal_r_a (argc, argv, optstring, longopts,longind, long_only, &getopt_data_a,posixly_correct);
optind = getopt_data_a.optind;
optarg_a = getopt_data_a.optarg;
optopt = getopt_data_a.optopt;
return result;
}
int getopt_a (int argc, char *const *argv, const char *optstring) _GETOPT_THROW
{
return _getopt_internal_a (argc, argv, optstring, (const struct option_a *) 0, (int *) 0, 0, 0);
}
int getopt_long_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
{
return _getopt_internal_a (argc, argv, options, long_options, opt_index, 0, 0);
}
int getopt_long_only_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
{
return _getopt_internal_a (argc, argv, options, long_options, opt_index, 1, 0);
}
int _getopt_long_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
{
return _getopt_internal_r_a (argc, argv, options, long_options, opt_index,0, d, 0);
}
int _getopt_long_only_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
{
return _getopt_internal_r_a (argc, argv, options, long_options, opt_index, 1, d, 0);
}
//
//
// Unicode Structures and Functions
//
//
static struct _getopt_data_w
{
int optind;
int opterr;
int optopt;
wchar_t *optarg;
int __initialized;
wchar_t *__nextchar;
enum ENUM_ORDERING __ordering;
int __posixly_correct;
int __first_nonopt;
int __last_nonopt;
} getopt_data_w;
wchar_t *optarg_w;
static void exchange_w(wchar_t **argv, struct _getopt_data_w *d)
{
int bottom = d->__first_nonopt;
int middle = d->__last_nonopt;
int top = d->optind;
wchar_t *tem;
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
int len = middle - bottom;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
top -= len;
}
else
{
int len = top - middle;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
bottom += len;
}
}
d->__first_nonopt += (d->optind - d->__last_nonopt);
d->__last_nonopt = d->optind;
}
static const wchar_t *_getopt_initialize_w (const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct)
{
d->__first_nonopt = d->__last_nonopt = d->optind;
d->__nextchar = NULL;
d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT");
if (optstring[0] == L'-')
{
d->__ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == L'+')
{
d->__ordering = REQUIRE_ORDER;
++optstring;
}
else if (d->__posixly_correct)
d->__ordering = REQUIRE_ORDER;
else
d->__ordering = PERMUTE;
return optstring;
}
int _getopt_internal_r_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct)
{
int print_errors = d->opterr;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
{
if (d->optind == 0)
d->optind = 1;
optstring = _getopt_initialize_w (optstring, d, posixly_correct);
d->__initialized = 1;
}
else if (optstring[0] == L'-' || optstring[0] == L'+')
optstring++;
if (optstring[0] == L':')
print_errors = 0;
if (d->__nextchar == NULL || *d->__nextchar == L'\0')
{
if (d->__last_nonopt > d->optind)
d->__last_nonopt = d->optind;
if (d->__first_nonopt > d->optind)
d->__first_nonopt = d->optind;
if (d->__ordering == PERMUTE)
{
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_w((wchar_t **) argv, d);
else if (d->__last_nonopt != d->optind)
d->__first_nonopt = d->optind;
while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
d->optind++;
d->__last_nonopt = d->optind;
}
if (d->optind != argc && !wcscmp(argv[d->optind], L"--"))
{
d->optind++;
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_w((wchar_t **) argv, d);
else if (d->__first_nonopt == d->__last_nonopt)
d->__first_nonopt = d->optind;
d->__last_nonopt = argc;
d->optind = argc;
}
if (d->optind == argc)
{
if (d->__first_nonopt != d->__last_nonopt)
d->optind = d->__first_nonopt;
return -1;
}
if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
{
if (d->__ordering == REQUIRE_ORDER)
return -1;
d->optarg = argv[d->optind++];
return 1;
}
d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-'));
}
if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1])))))
{
wchar_t *nameend;
unsigned int namelen;
const struct option_w *p;
const struct option_w *pfound = NULL;
struct option_list
{
const struct option_w *p;
struct option_list *next;
} *ambig_list = NULL;
int exact = 0;
int indfound = -1;
int option_index;
for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++);
namelen = (unsigned int)(nameend - d->__nextchar);
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!wcsncmp(p->name, d->__nextchar, namelen))
{
if (namelen == (unsigned int)wcslen(p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
{
struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
newp->p = p;
newp->next = ambig_list;
ambig_list = newp;
}
}
if (ambig_list != NULL && !exact)
{
if (print_errors)
{
struct option_list first;
first.p = pfound;
first.next = ambig_list;
ambig_list = &first;
fwprintf(stderr, L"%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
do
{
fwprintf (stderr, L" '--%s'", ambig_list->p->name);
ambig_list = ambig_list->next;
}
while (ambig_list != NULL);
fputwc (L'\n', stderr);
}
d->__nextchar += wcslen(d->__nextchar);
d->optind++;
d->optopt = 0;
return L'?';
}
if (pfound != NULL)
{
option_index = indfound;
d->optind++;
if (*nameend)
{
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
if (argv[d->optind - 1][1] == L'-')
{
fwprintf(stderr, L"%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
}
else
{
fwprintf(stderr, L"%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
}
}
d->__nextchar += wcslen(d->__nextchar);
d->optopt = pfound->val;
return L'?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
fwprintf(stderr,L"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
}
d->__nextchar += wcslen(d->__nextchar);
d->optopt = pfound->val;
return optstring[0] == L':' ? L':' : L'?';
}
}
d->__nextchar += wcslen(d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL)
{
if (print_errors)
{
if (argv[d->optind][1] == L'-')
{
fwprintf(stderr, L"%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
}
else
{
fwprintf(stderr, L"%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
}
}
d->__nextchar = (wchar_t *)L"";
d->optind++;
d->optopt = 0;
return L'?';
}
}
{
wchar_t c = *d->__nextchar++;
wchar_t *temp = (wchar_t*)wcschr(optstring, c);
if (*d->__nextchar == L'\0')
++d->optind;
if (temp == NULL || c == L':' || c == L';')
{
if (print_errors)
{
fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c);
}
d->optopt = c;
return L'?';
}
if (temp[0] == L'W' && temp[1] == L';')
{
wchar_t *nameend;
const struct option_w *p;
const struct option_w *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = 0;
int option_index;
if (longopts == NULL)
goto no_longs;
if (*d->__nextchar != L'\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c);
}
d->optopt = c;
if (optstring[0] == L':')
c = L':';
else
c = L'?';
return c;
}
else
d->optarg = argv[d->optind++];
for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++);
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
{
if ((unsigned int) (nameend - d->__nextchar) == wcslen(p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
ambig = 1;
}
if (ambig && !exact)
{
if (print_errors)
{
fwprintf(stderr, L"%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
}
d->__nextchar += wcslen(d->__nextchar);
d->optind++;
return L'?';
}
if (pfound != NULL)
{
option_index = indfound;
if (*nameend)
{
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
fwprintf(stderr, L"%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
}
d->__nextchar += wcslen(d->__nextchar);
return L'?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
fwprintf(stderr, L"%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
}
d->__nextchar += wcslen(d->__nextchar);
return optstring[0] == L':' ? L':' : L'?';
}
}
else
d->optarg = NULL;
d->__nextchar += wcslen(d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
no_longs:
d->__nextchar = NULL;
return L'W';
}
if (temp[1] == L':')
{
if (temp[2] == L':')
{
if (*d->__nextchar != L'\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else
d->optarg = NULL;
d->__nextchar = NULL;
}
else
{
if (*d->__nextchar != L'\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c);
}
d->optopt = c;
if (optstring[0] == L':')
c = L':';
else
c = L'?';
}
else
d->optarg = argv[d->optind++];
d->__nextchar = NULL;
}
}
return c;
}
}
int _getopt_internal_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct)
{
int result;
getopt_data_w.optind = optind;
getopt_data_w.opterr = opterr;
result = _getopt_internal_r_w (argc, argv, optstring, longopts,longind, long_only, &getopt_data_w,posixly_correct);
optind = getopt_data_w.optind;
optarg_w = getopt_data_w.optarg;
optopt = getopt_data_w.optopt;
return result;
}
int getopt_w (int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW
{
return _getopt_internal_w (argc, argv, optstring, (const struct option_w *) 0, (int *) 0, 0, 0);
}
int getopt_long_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
{
return _getopt_internal_w (argc, argv, options, long_options, opt_index, 0, 0);
}
int getopt_long_only_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
{
return _getopt_internal_w (argc, argv, options, long_options, opt_index, 1, 0);
}
int _getopt_long_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
{
return _getopt_internal_r_w (argc, argv, options, long_options, opt_index,0, d, 0);
}
int _getopt_long_only_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
{
return _getopt_internal_r_w (argc, argv, options, long_options, opt_index, 1, d, 0);
}
-97
View File
@@ -1,97 +0,0 @@
#ifndef __WINGETOPT_H_
#define __WINGETOPT_H_
#ifdef _GETOPT_API
#undef _GETOPT_API
#endif
#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT)
#error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually"
#elif defined(STATIC_GETOPT)
#define _GETOPT_API
#elif defined(EXPORTS_GETOPT)
#define _GETOPT_API __declspec(dllexport)
#else
#define _GETOPT_API __declspec(dllimport)
#endif
// Change behavior for C\C++
#ifdef __cplusplus
#define _BEGIN_EXTERN_C extern "C" {
#define _END_EXTERN_C }
#define _GETOPT_THROW throw()
#else
#define _BEGIN_EXTERN_C
#define _END_EXTERN_C
#define _GETOPT_THROW
#endif
// Standard GNU options
#define null_argument 0 /*Argument Null*/
#define no_argument 0 /*Argument Switch Only*/
#define required_argument 1 /*Argument Required*/
#define optional_argument 2 /*Argument Optional*/
// Shorter Options
#define ARG_NULL 0 /*Argument Null*/
#define ARG_NONE 0 /*Argument Switch Only*/
#define ARG_REQ 1 /*Argument Required*/
#define ARG_OPT 2 /*Argument Optional*/
#include <string.h>
#include <wchar.h>
_BEGIN_EXTERN_C
extern _GETOPT_API int optind;
extern _GETOPT_API int opterr;
extern _GETOPT_API int optopt;
// Ansi
struct option_a
{
const char* name;
int has_arg;
int *flag;
int val;
};
extern _GETOPT_API char *optarg_a;
extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
// Unicode
struct option_w
{
const wchar_t* name;
int has_arg;
int *flag;
int val;
};
extern _GETOPT_API wchar_t *optarg_w;
extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
_END_EXTERN_C
#undef _BEGIN_EXTERN_C
#undef _END_EXTERN_C
#undef _GETOPT_THROW
#undef _GETOPT_API
#ifdef _UNICODE
#define getopt getopt_w
#define getopt_long getopt_long_w
#define getopt_long_only getopt_long_only_w
#define option option_w
#define optarg optarg_w
#else
#define getopt getopt_a
#define getopt_long getopt_long_a
#define getopt_long_only getopt_long_only_a
#define option option_a
#define optarg optarg_a
#endif
#endif // __WINGETOPT_H_
+4 -8
View File
@@ -1,8 +1,6 @@
AM_CXXFLAGS = -pthread
SUBDIRS =
SUBDIRS += src
SUBDIRS = src
if ENABLE_TOOLS
SUBDIRS += tools
@@ -12,17 +10,15 @@ if USE_CYTHON
SUBDIRS += python
endif
if ENABLE_TESTS
SUBDIRS += tests
endif
if HAVE_DOXYGEN
SUBDIRS += doc
endif
ACLOCAL_AMFLAGS = -I m4
DOC_FILES = \
README.md \
COPYING
LICENSE
EXTRA_DIST = \
$(DOC_FILES)
+30 -46
View File
@@ -1,39 +1,32 @@
<img src="https://raw.githubusercontent.com/savoirfairelinux/opendht/master/resources/opendht_logo_512.png" width="100" align="right">
<br>
<h1 style="margin-top:10px">
<a id="user-content-opendht-" class="anchor" href="/savoirfairelinux/opendht/blob/master/README.md#opendht-" aria-hidden="true"></a>OpenDHT
</h1>
OpenDHT
===
A lightweight C++11 Distributed Hash Table implementation originally based on https://github.com/jech/dht by Juliusz Chroboczek.
A lightweight C++14 Distributed Hash Table implementation.
* Light and fast C++11 Kademlia DHT library.
* Distributed shared key->value data-store
* Clean and powerfull distributed map API with storage of arbitrary binary values of up to 56 KB.
* Optional public key cryptography layer providing data signature and encryption (using GnuTLS).
* IPv4 and IPv6 support.
* Python binding.
OpenDHT provides an easy to use distributed in-memory data store.
Every node in the network can read and write values to the store.
Values are distributed over the network, with redundancy.
* Lightweight and scalable, designed for large networks and small devices
* High resilience to network disruption
* Public key cryptography layer providing optional data signature and encryption (using GnuTLS)
* IPv4 and IPv6 support
* Clean and powerful **C++14** map API
* Bindings for **C, Rust & Python 3**
* REST API with optional HTTP client+server with push notification support
## Documentation
Documentation
-
See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
#### How-to build and install
Build instructions: <https://github.com/savoirfairelinux/opendht/wiki/Build-the-library>
Build instructions : <https://github.com/savoirfairelinux/opendht/wiki/Build-the-library>
#### How-to build a simple client app
```bash
g++ main.cpp -std=c++14 -lopendht
g++ main.cpp -std=c++11 -lopendht -lgnutls
```
## Examples
Examples
-
### C++ example
The `tools` directory includes simple example programs :
* `dhtnode`, a command line tool, allowing to run a DHT node and perform operations supported by the library (get, put etc.) with text values.
* `dhtnode`, a command line tool, mostly used for debuging, allowing to perform operations supported by the library (get, put etc.) with text values.
* `dhtchat`, a very simple IM client working over the dht.
Example program launching a DHT node, connecting to the network and performing some basic operations:
@@ -51,7 +44,7 @@ int main()
// Join the network through any running node,
// here using a known bootstrap node.
node.bootstrap("bootstrap.jami.net", "4222");
node.bootstrap("bootstrap.ring.cx", "4222");
// put some data on the dht
std::vector<uint8_t> some_data(5, 10);
@@ -82,7 +75,7 @@ node.run()
# Join the network through any running node,
# here using a known bootstrap node.
node.bootstrap("bootstrap.jami.net", "4222")
node.bootstrap("bootstrap.ring.cx", "4222")
# blocking call (provide callback arguments to make the call non-blocking)
node.put(dht.InfoHash.get("unique_key"), dht.Value(b'some binary data'))
@@ -92,31 +85,22 @@ for r in results:
print(r)
```
## Dependencies
Dependencies
-
- msgpack-c 1.2+, used for data serialization.
- GnuTLS 3.3+, used for cryptographic operations.
- GnuTLS 3.1+, used for cryptographic operations.
- Nettle 2.4+, a GnuTLS dependency for crypto.
- (optional) restinio used for the REST API.
- (optional) jsoncpp 1.7.4-3+, used for the REST API.
- Build tested with GCC 5.2+ (GNU/Linux, Windows with MinGW), Clang/LLVM (GNU/Linux, Android, macOS, iOS).
- Build tested with Microsoft Visual Studio 2015, 2017, 2019
- Build tested with GCC 4.8+ (GNU/Linux, Android, Windows with MinGW), Clang/LLVM (Linux, OS X).
- Build tested with Microsoft Visual Studio 2015
## Contact
Licence
-
Copyright (C) 2014-2016 Savoir-faire Linux Inc.
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
Licenced under the GNU General Public License version 3 (see COPYING for the full licence).
## License
Copyright (C) 2014-2020 Savoir-faire Linux Inc.
This project is independent from another project called OpenDHT (Sean Rhea. Ph.D. Thesis, 2005), now extinct.
OpenDHT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
See COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html for the full GPLv3 license.
## Acknowledgements
This project was originally based on https://github.com/jech/dht by Juliusz Chroboczek.
It is independent from another project called OpenDHT (Sean Rhea. Ph.D. Thesis, 2005), now extinct.
## Donations
Donations
-
We gratefully accept Bitcoin donations to support OpenDHT development at: `bitcoin:3EykSd1An888efq4Bq3KaV3hJ3JQ4FPnwm`.
Submodule argon2 deleted from 62358ba212.
-1
View File
@@ -1,2 +1 @@
git submodule update --init
autoreconf --install --verbose -Wall
-430
View File
@@ -1,430 +0,0 @@
#include "opendht_c.h"
#include "opendht.h"
using ValueSp = std::shared_ptr<dht::Value>;
using PrivkeySp = std::shared_ptr<dht::crypto::PrivateKey>;
using PubkeySp = std::shared_ptr<const dht::crypto::PublicKey>;
using CertSp = std::shared_ptr<dht::crypto::Certificate>;
#ifdef __cplusplus
extern "C" {
#endif
// dht::InfoHash
inline dht_infohash dht_infohash_to_c(const dht::InfoHash& h) {
dht_infohash ret;
*reinterpret_cast<dht::InfoHash*>(&ret) = h;
return ret;
}
inline dht_pkid dht_pkid_to_c(const dht::PkId& h) {
dht_pkid ret;
*reinterpret_cast<dht::PkId*>(&ret) = h;
return ret;
}
const char* dht_infohash_print(const dht_infohash* h) {
return reinterpret_cast<const dht::InfoHash*>(h)->to_c_str();
}
void dht_infohash_zero(dht_infohash* h) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash{};
}
void dht_infohash_random(dht_infohash* h) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash::getRandom();
}
void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash::get(dat, dat_size);
}
void dht_infohash_get_from_string(dht_infohash* h, const char* dat) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash::get((const uint8_t*)dat, (size_t)strlen(dat));
}
bool dht_infohash_is_zero(const dht_infohash* h) {
return !static_cast<bool>(*reinterpret_cast<const dht::InfoHash*>(h));
}
void dht_infohash_from_hex(dht_infohash* h, const char* dat) {
*h = dht_infohash_to_c(dht::InfoHash(std::string(dat, HASH_LEN*2)));
}
const char* dht_pkid_print(const dht_pkid* h) {
return reinterpret_cast<const dht::PkId*>(h)->to_c_str();
}
// dht::Blob
void dht_blob_delete(dht_blob* data) {
delete reinterpret_cast<dht::Blob*>(data);
}
dht_data_view dht_blob_get_data(const dht_blob* data) {
dht_data_view view;
view.data = reinterpret_cast<const dht::Blob*>(data)->data();
view.size = reinterpret_cast<const dht::Blob*>(data)->size();
return view;
}
// dht::Value
dht_data_view dht_value_get_data(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
dht_data_view view;
view.data = vsp->data.data();
view.size = vsp->data.size();
return view;
}
dht_value_id dht_value_get_id(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return vsp->id;
}
dht_publickey* dht_value_get_owner(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return vsp->owner ? reinterpret_cast<dht_publickey*>(new PubkeySp(vsp->owner)) : nullptr;
}
dht_infohash dht_value_get_recipient(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return dht_infohash_to_c(vsp->recipient);
}
const char* dht_value_get_user_type(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return vsp->user_type.c_str();
}
dht_value* dht_value_new(const uint8_t* data, size_t size) {
return reinterpret_cast<dht_value*>(new ValueSp(std::make_shared<dht::Value>(data, size)));
}
dht_value* dht_value_ref(const dht_value* v) {
return reinterpret_cast<dht_value*>(new ValueSp(*reinterpret_cast<const ValueSp*>(v)));
}
void dht_value_unref(dht_value* v) {
delete reinterpret_cast<ValueSp*>(v);
}
// dht::crypto::PublicKey
dht_publickey* dht_publickey_import(const uint8_t* dat, size_t dat_size) {
try {
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<const dht::crypto::PublicKey>(dat, dat_size)));
} catch (const dht::crypto::CryptoException& e) {
return nullptr;
}
}
void dht_publickey_delete(dht_publickey* pk) {
delete reinterpret_cast<PubkeySp*>(pk);
}
int dht_publickey_export(const dht_publickey* pk, char* out, size_t* outlen) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return pkey->pack((uint8_t*)out, outlen);
}
dht_infohash dht_publickey_get_id(const dht_publickey* pk) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return dht_infohash_to_c(pkey->getId());
}
dht_pkid dht_publickey_get_long_id(const dht_publickey* pk) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return dht_pkid_to_c(pkey->getLongId());
}
bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, size_t data_size, const char* signature, size_t signature_size) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return pkey->checkSignature((const uint8_t*)data, data_size, (const uint8_t*)signature, signature_size);
}
dht_blob* dht_publickey_encrypt(const dht_publickey* pk, const char* data, size_t data_size) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
auto rdata = new dht::Blob;
*rdata = pkey->encrypt((const uint8_t*)data, data_size);
return (dht_blob*)rdata;
}
// dht::crypto::PrivateKey
dht_privatekey* dht_privatekey_generate(unsigned key_length_bits) {
if (key_length_bits == 0)
key_length_bits = 4096;
return reinterpret_cast<dht_privatekey*>(new PrivkeySp(std::make_shared<dht::crypto::PrivateKey>(dht::crypto::PrivateKey::generate(key_length_bits))));
}
dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password) {
try {
return reinterpret_cast<dht_privatekey*>(new PrivkeySp(std::make_shared<dht::crypto::PrivateKey>(dat, dat_size, password)));
} catch (const dht::crypto::CryptoException& e) {
return nullptr;
}
}
int dht_privatekey_export(const dht_privatekey* k, char* out, size_t* out_size, const char* password) {
if (!out or !out_size or !*out_size)
return -1;
const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
return key->serialize((uint8_t*)out, out_size, password);
}
dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* k) {
const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(key->getPublicKey())));
}
void dht_privatekey_delete(dht_privatekey* pk) {
delete reinterpret_cast<PrivkeySp*>(pk);
}
// dht::crypto::Certificate
dht_certificate* dht_certificate_import(const uint8_t* dat, size_t dat_size) {
try {
return reinterpret_cast<dht_certificate*>(new CertSp(std::make_shared<dht::crypto::Certificate>(dat, dat_size)));
} catch (const dht::crypto::CryptoException& e) {
return nullptr;
}
}
void dht_certificate_delete(dht_certificate* c) {
delete reinterpret_cast<CertSp*>(c);
}
dht_infohash dht_certificate_get_id(const dht_certificate* c) {
const auto& cert = *reinterpret_cast<const CertSp*>(c);
return dht_infohash_to_c(cert->getId());
}
dht_pkid dht_certificate_get_long_id(const dht_certificate* c) {
const auto& cert = *reinterpret_cast<const CertSp*>(c);
return dht_pkid_to_c(cert->getLongId());
}
dht_publickey* dht_certificate_get_publickey(const dht_certificate* c) {
const auto& cert = *reinterpret_cast<const CertSp*>(c);
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(cert->getPublicKey())));
}
// dht::crypto::Identity
inline dht::crypto::Identity dht_identity_from_c(const dht_identity* cid) {
dht::crypto::Identity id {};
if (cid and cid->privatekey)
id.first = *reinterpret_cast<const PrivkeySp*>(cid->privatekey);
if (cid and cid->certificate)
id.second = *reinterpret_cast<const CertSp*>(cid->certificate);
return id;
}
inline dht_identity dht_identity_to_c(const dht::crypto::Identity& id) {
dht_identity cid {};
cid.privatekey = id.first ? reinterpret_cast<dht_privatekey*>(new PrivkeySp(id.first)) : NULL;
cid.certificate = id.second ? reinterpret_cast<dht_certificate*>(new CertSp(id.second)) : NULL;
return cid;
}
OPENDHT_C_PUBLIC dht_identity dht_identity_generate(const char* common_name, const dht_identity* ca) {
return dht_identity_to_c(dht::crypto::generateIdentity(common_name, dht_identity_from_c(ca)));
}
OPENDHT_C_PUBLIC void dht_identity_delete(dht_identity* id) {
if (id->certificate) {
dht_certificate_delete(id->certificate);
id->certificate = NULL;
}
if (id->privatekey) {
dht_privatekey_delete(id->privatekey);
id->privatekey = NULL;
}
}
// config
void dht_runner_config_default(dht_runner_config* config) {
bzero(config, sizeof(dht_runner_config));
config->threaded = true;
}
// dht::DhtRunner
dht_runner* dht_runner_new() {
return reinterpret_cast<dht_runner*>(new dht::DhtRunner);
}
void dht_runner_delete(dht_runner* runner) {
delete reinterpret_cast<dht::DhtRunner*>(runner);
}
void dht_runner_run(dht_runner* r, in_port_t port) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
runner->run(port, {}, true);
}
void dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config* conf) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
dht::DhtRunner::Config config;
config.dht_config.node_config.is_bootstrap = conf->dht_config.node_config.is_bootstrap;
config.dht_config.node_config.maintain_storage = conf->dht_config.node_config.maintain_storage;
config.dht_config.node_config.node_id = *reinterpret_cast<const dht::InfoHash*>(&conf->dht_config.node_config.node_id);
config.dht_config.node_config.network = conf->dht_config.node_config.network;
config.dht_config.node_config.persist_path = conf->dht_config.node_config.persist_path
? std::string(conf->dht_config.node_config.persist_path) : std::string{};
if (conf->dht_config.id.privatekey)
config.dht_config.id.first = *reinterpret_cast<const PrivkeySp*>(conf->dht_config.id.privatekey);
if (conf->dht_config.id.certificate)
config.dht_config.id.second = *reinterpret_cast<const CertSp*>(conf->dht_config.id.certificate);
config.threaded = conf->threaded;
config.proxy_server = conf->proxy_server ? std::string(conf->proxy_server) : std::string{};
config.push_node_id = conf->push_node_id ? std::string(conf->push_node_id) : std::string{};
config.push_token = conf->push_token ? std::string(conf->push_token) : std::string{};
config.peer_discovery = conf->peer_discovery;
config.peer_publish = conf->peer_publish;
runner->run(port, config);
}
void dht_runner_ping(dht_runner* r, struct sockaddr* addr, socklen_t addr_len) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
runner->bootstrap(dht::SockAddr(addr, addr_len));
}
void dht_runner_bootstrap(dht_runner* r, const char* host, const char* service) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
if (service)
runner->bootstrap(host, service);
else
runner->bootstrap(host);
}
void dht_runner_get(dht_runner* r, const dht_infohash* h, dht_get_cb cb, dht_done_cb done_cb, void* cb_user_data) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
runner->get(*hash, [cb,cb_user_data](std::shared_ptr<dht::Value> value){
return cb(reinterpret_cast<const dht_value*>(&value), cb_user_data);
}, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
});
}
struct ScopeGuardCb {
ScopeGuardCb(dht_shutdown_cb cb, void* data)
: onDestroy(cb), userData(data) {}
~ScopeGuardCb() {
if (onDestroy)
onDestroy((void*)userData);
}
private:
const dht_shutdown_cb onDestroy;
void const* userData;
};
dht_op_token* dht_runner_listen(dht_runner* r, const dht_infohash* h, dht_value_cb cb, dht_shutdown_cb done_cb, void* cb_user_data) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto fret = new std::future<size_t>;
auto guard = done_cb ? std::make_shared<ScopeGuardCb>(done_cb, cb_user_data) : std::shared_ptr<ScopeGuardCb>{};
*fret = runner->listen(*hash, [cb,cb_user_data, guard](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired) {
for (const auto& value : values) {
if (not cb(reinterpret_cast<const dht_value*>(&value), expired, cb_user_data))
return false;
}
return true;
});
return (dht_op_token*)fret;
}
void dht_runner_cancel_listen(dht_runner* r, const dht_infohash* h, dht_op_token* t) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto token = reinterpret_cast<std::future<size_t>*>(t);
runner->cancelListen(*hash, std::move(*token));
}
void dht_op_token_delete(dht_op_token* token) {
delete reinterpret_cast<std::future<size_t>*>(token);
}
void dht_runner_put(dht_runner* r, const dht_infohash* h, const dht_value* v, dht_done_cb done_cb, void* cb_user_data, bool permanent) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto value = reinterpret_cast<const ValueSp*>(v);
runner->put(*hash, *value, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
}, dht::time_point::max(), permanent);
}
void dht_runner_put_signed(dht_runner* r, const dht_infohash* h, const dht_value* v, dht_done_cb done_cb, void* cb_user_data, bool permanent) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto value = reinterpret_cast<const ValueSp*>(v);
runner->putSigned(*hash, *value, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
}, permanent);
}
void dht_runner_put_encrypted(dht_runner* r, const dht_infohash* h, const dht_infohash* to, const dht_value* v, dht_done_cb done_cb, void* cb_user_data, bool permanent) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto toHash = reinterpret_cast<const dht::InfoHash*>(to);
auto value = reinterpret_cast<const ValueSp*>(v);
runner->putEncrypted(*hash, *toHash, *value, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
}, permanent);
}
void dht_runner_cancel_put(dht_runner* r, const dht_infohash* h, dht_value_id value_id) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
runner->cancelPut(*hash, value_id);
}
void dht_runner_shutdown(dht_runner* r, dht_shutdown_cb done_cb, void* cb_user_data) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
runner->shutdown([done_cb, cb_user_data](){
if (done_cb)
done_cb(cb_user_data);
});
}
dht_infohash dht_runner_get_node_id(const dht_runner* r) {
auto runner = reinterpret_cast<const dht::DhtRunner*>(r);
dht_infohash ret;
*reinterpret_cast<dht::InfoHash*>(&ret) = runner->getNodeId();
return ret;
}
dht_infohash dht_runner_get_id(const dht_runner* r) {
auto runner = reinterpret_cast<const dht::DhtRunner*>(r);
dht_infohash ret;
*reinterpret_cast<dht::InfoHash*>(&ret) = runner->getId();
return ret;
}
struct sockaddr** dht_runner_get_public_address(const dht_runner* r) {
auto runner = reinterpret_cast<const dht::DhtRunner*>(r);
auto addrs = const_cast<dht::DhtRunner*>(runner)->getPublicAddress();
if (addrs.empty())
return nullptr;
auto ret = (struct sockaddr**)malloc(sizeof(struct sockaddr*) * (addrs.size() + 1));
for (size_t i=0; i<addrs.size(); i++) {
if (auto len = addrs[i].getLength()) {
ret[i] = (struct sockaddr*)malloc(len);
memcpy((struct sockaddr*)ret[i], addrs[i].get(), len);
} else {
ret[i] = nullptr;
}
}
ret[addrs.size()] = nullptr;
return ret;
}
#ifdef __cplusplus
}
#endif
-156
View File
@@ -1,156 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "def.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
// Non-owning data view
struct OPENDHT_C_PUBLIC dht_data_view {
const uint8_t* data;
size_t size;
};
typedef struct dht_data_view dht_data_view;
// dht::Blob
struct OPENDHT_C_PUBLIC dht_blob;
typedef struct dht_blob dht_blob;
OPENDHT_C_PUBLIC dht_data_view dht_blob_get_data(const dht_blob* data);
OPENDHT_C_PUBLIC void dht_blob_delete(dht_blob* data);
// dht::InfoHash
struct OPENDHT_C_PUBLIC dht_infohash { uint8_t d[HASH_LEN]; };
typedef struct dht_infohash dht_infohash;
OPENDHT_C_PUBLIC void dht_infohash_zero(dht_infohash* h);
OPENDHT_C_PUBLIC void dht_infohash_random(dht_infohash* h);
OPENDHT_C_PUBLIC void dht_infohash_from_hex(dht_infohash* h, const char* dat);
OPENDHT_C_PUBLIC void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC void dht_infohash_get_from_string(dht_infohash* h, const char* str);
OPENDHT_C_PUBLIC const char* dht_infohash_print(const dht_infohash* h);
OPENDHT_C_PUBLIC bool dht_infohash_is_zero(const dht_infohash* h);
// dht::PkId
struct OPENDHT_C_PUBLIC dht_pkid { uint8_t d[32]; };
typedef struct dht_pkid dht_pkid;
OPENDHT_C_PUBLIC const char* dht_pkid_print(const dht_pkid* h);
// dht::crypto::PublicKey
struct OPENDHT_C_PUBLIC dht_publickey;
typedef struct dht_publickey dht_publickey;
OPENDHT_C_PUBLIC dht_publickey* dht_publickey_import(const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC void dht_publickey_delete(dht_publickey* pk);
OPENDHT_C_PUBLIC int dht_publickey_export(const dht_publickey* pk, char* out, size_t* out_size);
OPENDHT_C_PUBLIC dht_infohash dht_publickey_get_id(const dht_publickey* pk);
OPENDHT_C_PUBLIC dht_pkid dht_publickey_get_long_id(const dht_publickey* pk);
OPENDHT_C_PUBLIC bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, size_t data_size, const char* signature, size_t signature_size);
OPENDHT_C_PUBLIC dht_blob* dht_publickey_encrypt(const dht_publickey* pk, const char* data, size_t data_size);
// dht::crypto::PrivateKey
struct OPENDHT_C_PUBLIC dht_privatekey;
typedef struct dht_privatekey dht_privatekey;
OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_generate(unsigned key_length_bits);
OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password);
OPENDHT_C_PUBLIC int dht_privatekey_export(const dht_privatekey*, char* out, size_t* out_size, const char* password);
OPENDHT_C_PUBLIC dht_publickey* dht_privatekey_get_publickey(const dht_privatekey*);
OPENDHT_C_PUBLIC void dht_privatekey_delete(dht_privatekey*);
// dht::crypto::Certificate
struct OPENDHT_C_PUBLIC dht_certificate;
typedef struct dht_certificate dht_certificate;
OPENDHT_C_PUBLIC dht_certificate* dht_certificate_import(const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC dht_infohash dht_certificate_get_id(const dht_certificate*);
OPENDHT_C_PUBLIC dht_pkid dht_certificate_get_long_id(const dht_certificate*);
OPENDHT_C_PUBLIC dht_publickey* dht_certificate_get_publickey(const dht_certificate*);
OPENDHT_C_PUBLIC void dht_certificate_delete(dht_certificate*);
struct OPENDHT_PUBLIC dht_identity {
dht_privatekey* privatekey;
dht_certificate* certificate;
};
typedef struct dht_identity dht_identity;
OPENDHT_C_PUBLIC dht_identity dht_identity_generate(const char* common_name, const dht_identity* ca);
OPENDHT_C_PUBLIC void dht_identity_delete(dht_identity*);
// dht::Value
struct OPENDHT_C_PUBLIC dht_value;
typedef struct dht_value dht_value;
typedef uint64_t dht_value_id;
OPENDHT_C_PUBLIC dht_value* dht_value_new(const uint8_t* data, size_t size);
OPENDHT_C_PUBLIC dht_value* dht_value_ref(const dht_value*);
OPENDHT_C_PUBLIC void dht_value_unref(dht_value*);
OPENDHT_C_PUBLIC dht_data_view dht_value_get_data(const dht_value* data);
OPENDHT_C_PUBLIC dht_value_id dht_value_get_id(const dht_value* data);
OPENDHT_C_PUBLIC dht_publickey* dht_value_get_owner(const dht_value* data);
OPENDHT_C_PUBLIC dht_infohash dht_value_get_recipient(const dht_value* data);
OPENDHT_C_PUBLIC const char* dht_value_get_user_type(const dht_value* data);
// callbacks
typedef bool (*dht_get_cb)(const dht_value* value, void* user_data);
typedef bool (*dht_value_cb)(const dht_value* value, bool expired, void* user_data);
typedef void (*dht_done_cb)(bool ok, void* user_data);
typedef void (*dht_shutdown_cb)(void* user_data);
struct OPENDHT_C_PUBLIC dht_op_token;
typedef struct dht_op_token dht_op_token;
OPENDHT_C_PUBLIC void dht_op_token_delete(dht_op_token* token);
// config
struct OPENDHT_PUBLIC dht_node_config {
dht_infohash node_id;
uint32_t network;
bool is_bootstrap;
bool maintain_storage;
const char* persist_path;
};
typedef struct dht_node_config dht_node_config;
struct OPENDHT_PUBLIC dht_secure_config {
dht_node_config node_config;
dht_identity id;
};
typedef struct dht_secure_config dht_secure_config;
struct OPENDHT_PUBLIC dht_runner_config {
dht_secure_config dht_config;
bool threaded;
const char* proxy_server;
const char* push_node_id;
const char* push_token;
bool peer_discovery;
bool peer_publish;
dht_certificate* server_ca;
dht_identity client_identity;
};
typedef struct dht_runner_config dht_runner_config;
OPENDHT_C_PUBLIC void dht_runner_config_default(dht_runner_config* config);
// dht::DhtRunner
struct OPENDHT_C_PUBLIC dht_runner;
typedef struct dht_runner dht_runner;
OPENDHT_C_PUBLIC dht_runner* dht_runner_new();
OPENDHT_C_PUBLIC void dht_runner_delete(dht_runner* runner);
OPENDHT_C_PUBLIC void dht_runner_run(dht_runner* runner, in_port_t port);
OPENDHT_C_PUBLIC void dht_runner_run_config(dht_runner* runner, in_port_t port, const dht_runner_config* config);
OPENDHT_C_PUBLIC void dht_runner_ping(dht_runner* runner, struct sockaddr* addr, socklen_t addr_len);
OPENDHT_C_PUBLIC void dht_runner_bootstrap(dht_runner* runner, const char* host, const char* service);
OPENDHT_C_PUBLIC void dht_runner_get(dht_runner* runner, const dht_infohash* hash, dht_get_cb cb, dht_done_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC dht_op_token* dht_runner_listen(dht_runner* runner, const dht_infohash* hash, dht_value_cb cb, dht_shutdown_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC void dht_runner_cancel_listen(dht_runner* runner, const dht_infohash* hash, dht_op_token* token);
OPENDHT_C_PUBLIC void dht_runner_put(dht_runner* runner, const dht_infohash* hash, const dht_value* value, dht_done_cb done_cb, void* cb_user_data, bool permanent);
OPENDHT_C_PUBLIC void dht_runner_put_signed(dht_runner* runner, const dht_infohash* hash, const dht_value* value, dht_done_cb done_cb, void* cb_user_data, bool permanent);
OPENDHT_C_PUBLIC void dht_runner_put_encrypted(dht_runner* runner, const dht_infohash* hash, const dht_infohash* to, const dht_value* value, dht_done_cb done_cb, void* cb_user_data, bool permanent);
OPENDHT_C_PUBLIC void dht_runner_cancel_put(dht_runner* runner, const dht_infohash* hash, dht_value_id value_id);
OPENDHT_C_PUBLIC void dht_runner_shutdown(dht_runner* runner, dht_shutdown_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC dht_infohash dht_runner_get_node_id(const dht_runner* runner);
OPENDHT_C_PUBLIC dht_infohash dht_runner_get_id(const dht_runner* runner);
OPENDHT_C_PUBLIC struct sockaddr** dht_runner_get_public_address(const dht_runner* runner);
#ifdef __cplusplus
}
#endif
-28
View File
@@ -1,28 +0,0 @@
INCLUDE(FindPkgConfig)
PKG_CHECK_MODULES(PC_CPPUNIT "cppunit")
FIND_PATH(CPPUNIT_INCLUDE_DIRS
NAMES cppunit/TestCase.h
HINTS ${PC_CPPUNIT_INCLUDE_DIR}
${CMAKE_INSTALL_PREFIX}/include
PATHS
/usr/local/include
/usr/include
)
FIND_LIBRARY(CPPUNIT_LIBRARIES
NAMES cppunit
HINTS ${PC_CPPUNIT_LIBDIR}
${CMAKE_INSTALL_PREFIX}/lib
${CMAKE_INSTALL_PREFIX}/lib64
PATHS
${CPPUNIT_INCLUDE_DIRS}/../lib
/usr/local/lib
/usr/lib
)
LIST(APPEND CPPUNIT_LIBRARIES ${CMAKE_DL_LIBS})
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
MARK_AS_ADVANCED(CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
-14
View File
@@ -1,14 +0,0 @@
# header-only does not produce a library
if(NOT Restinio_FOUND)
find_path (Restinio_INCLUDE_DIR restinio
HINTS
"/usr/include"
"/usr/local/include"
"/opt/local/include")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Restinio DEFAULT_MSG Restinio_INCLUDE_DIR)
if (Restinio_INCLUDE_DIR)
set(Restinio_FOUND TRUE)
set(Restinio_INCLUDE_DIRS ${Restinio_INCLUDE_DIR})
endif()
endif()
+17 -145
View File
@@ -1,53 +1,23 @@
dnl define macros
m4_define([opendht_major_version], 2)
m4_define([opendht_minor_version], 0)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
AC_INIT(opendht, [opendht_version])
AC_INIT(opendht, 0.6.1)
AC_CONFIG_AUX_DIR(ac)
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AC_SUBST(OPENDHT_MAJOR_VERSION, opendht_major_version)
AC_SUBST(OPENDHT_MINOR_VERSION, opendht_minor_version)
AC_SUBST(OPENDHT_PATCH_VERSION, opendht_patch_version)
AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [Build in debug mode, adds stricter warnings, disables optimization]))
AS_IF([test "x$enable_debug" = "xyes"],
[CXXFLAGS="${CXXFLAGS} -g -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -O0 -pedantic-errors"],
[CXXFLAGS="${CXXFLAGS} -O3 -pedantic-errors"])
[CXXFLAGS="${CXXFLAGS} -g -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -O0"],
[CXXFLAGS="${CXXFLAGS} -O3"])
AC_PROG_CXX
AM_PROG_AR
dnl Check for logs
AC_ARG_ENABLE([logs], [AS_HELP_STRING([--disable-logs], [Disable DHT logs])])
AS_IF([test "x$enable_logs" != "xno"], [
AC_DEFINE([OPENDHT_LOG], [true], [Define if DHT logs are enabled])
], [
AC_DEFINE([OPENDHT_LOG], [false], [Define if DHT logs are enabled])
])
dnl Check for indexation
AC_ARG_ENABLE([indexation], [AS_HELP_STRING([--disable-indexation], [Disable DHT indexation])])
AM_CONDITIONAL(ENABLE_INDEXATION, test x$enable_indexation != "xno")
AM_COND_IF(ENABLE_INDEXATION, [
AC_DEFINE([OPENDHT_INDEXATION], [], [Define if DHT indexation is enabled])
])
AC_ARG_ENABLE([peer-discovery], [AS_HELP_STRING([--disable-peer-discovery], [Disable peer-discovery])])
AM_CONDITIONAL(ENABLE_PEER_DISCOVERY, test x$enable_peer_discovery != "xno")
AM_COND_IF(ENABLE_PEER_DISCOVERY, [AC_DEFINE([OPENDHT_PEER_DISCOVERY], [], [Define if peer discovery is enabled])])
dnl Check for Doxygen
AC_ARG_ENABLE([doc], AS_HELP_STRING([--enable-doc], [Enable documentation generation (doxygen)]))
AS_IF([test "x$enable_doc" = "xyes"], [
AC_CHECK_PROGS([DOXYGEN], [doxygen])
AS_IF([test -z "$DOXYGEN"], [AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])])
AS_IF([test -z "$DOXYGEN"], [AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])])
])
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
@@ -56,8 +26,8 @@ AC_ARG_ENABLE([python], [AS_HELP_STRING([--disable-python], [Disble python bindi
AS_IF([test "x$enable_python" != "xno"], [
AM_PATH_PYTHON([3.3],, [:])
AS_IF([test -n "$PYTHON"],[
echo 'import Cython' | $PYTHON
AS_IF([test $? == 0],[CYTHON=yes],[AC_MSG_WARN([Cython not found - continuing without python support])])
AC_CHECK_PROGS([CYTHON], [cython3])
AS_IF([test -z "$CYTHON"],[AC_MSG_WARN([Cython not found - continuing without python support])])
AC_CHECK_PROGS([PIP], [pip3])
AS_IF([test -z "$PIP"],[AC_MSG_WARN([pip not found - continuing without python uninstall support])])
])
@@ -102,108 +72,14 @@ AS_IF([test "x$SYS" = "xandroid"],
LT_INIT()
LT_LANG(C++)
AX_CXX_COMPILE_STDCXX(14,[noext],[mandatory])
AX_CXX_COMPILE_STDCXX(11,[noext],[mandatory])
PKG_PROG_PKG_CONFIG()
AC_ARG_ENABLE([proxy_server], AS_HELP_STRING([--enable-proxy-server], [Enable proxy server ability]), proxy_server=yes, proxy_server=no)
AM_CONDITIONAL(ENABLE_PROXY_SERVER, test x$proxy_server == xyes)
AC_ARG_ENABLE([push_notifications], AS_HELP_STRING([--enable-push-notifications], [Enable push notifications support]), push_notifications=yes, push_notifications=no)
AM_CONDITIONAL(ENABLE_PUSH_NOTIFICATIONS, test x$push_notifications == xyes)
AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity],
[Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no)
AM_CONDITIONAL(ENABLE_PROXY_SERVER_IDENTITY, test x$proxy_server_identity == xyes -a x$proxy_server == xyes)
AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity],
[Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no)
AC_ARG_ENABLE([proxy_client], AS_HELP_STRING([--enable-proxy-client], [Enable proxy client ability]), proxy_client=yes, proxy_client=no)
AM_CONDITIONAL(ENABLE_PROXY_CLIENT, test x$proxy_client == xyes)
AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests], [Enable tests]), build_tests=yes, build_tests=no)
AM_CONDITIONAL(ENABLE_TESTS, test x$build_tests == xyes)
AM_COND_IF([ENABLE_TESTS], [
PKG_CHECK_MODULES([CppUnit], [cppunit >= 1.12])
])
AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes || test x$proxy_server == xyes)
PKG_CHECK_MODULES([Nettle], [nettle >= 2.4])
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3])
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.1])
PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2])
AC_ARG_WITH([jsoncpp], AS_HELP_STRING([--without-jsoncpp], [Build without JsonCpp support]))
AS_IF([test "x$with_jsoncpp" != "xno"],
[PKG_CHECK_MODULES([JsonCpp], [jsoncpp >= 1.7.2], [have_jsoncpp=yes], [have_jsoncpp=no])],
[have_jsoncpp=no])
AS_IF([test "x$have_jsoncpp" = "xyes"], [
AC_MSG_NOTICE([Using JsonCpp])
CPPFLAGS+=" -DOPENDHT_JSONCPP"
AC_SUBST(jsoncpp_lib, [", jsoncpp"])
], [
AC_MSG_NOTICE([Not using JsonCpp])
AM_COND_IF(PROXY_CLIENT_OR_SERVER, AC_MSG_ERROR(["JsonCpp is required for proxy/push notification support"]))
])
AC_ARG_WITH([openssl], AS_HELP_STRING([--without-openssl], [Build with OpenSSL support]))
AS_IF([test "x$with_openssl" != "xno"],
[PKG_CHECK_MODULES([OpenSSL], [openssl >= 1.1], [have_openssl=yes], [have_openssl=no])],
[have_openssl=no])
AS_IF([test "x$have_openssl" = "xyes"], [
AC_MSG_NOTICE([Using OpenSSL])
AC_SUBST(openssl_lib, [", openssl"])
], [
AC_MSG_NOTICE([Not using OpenSSL])
])
AC_ARG_WITH([http_parser_fork], AS_HELP_STRING([--with-http-parser-fork], [Build with http_parser fork to support old API]))
AS_IF([test "x$with_http_parser_fork" = "xyes"],[
AC_MSG_NOTICE([Using http_parser fork])
AC_DEFINE([OPENDHT_PROXY_HTTP_PARSER_FORK], [], [Define if using http parser fork])
], [
AC_MSG_NOTICE([Not using http_parser fork])
])
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
AC_CHECK_HEADERS([asio.hpp], exit,, AC_MSG_ERROR([Missing Asio headers files]))
CXXFLAGS="${CXXFLAGS} -DASIO_STANDALONE"
PKG_CHECK_MODULES([Fmt], [fmt >= 5.3.0], [have_fmt=yes], [have_fmt=no])
AS_IF([test "x$have_fmt" = "xyes"], [
AC_MSG_NOTICE([Using libfmt])
], [
AC_MSG_NOTICE([Missing libfmt files])
])
# http_parser has no pkgconfig, instead we check with:
AC_CHECK_LIB(http_parser, exit,, AC_MSG_ERROR([Missing HttpParser library files]))
AC_CHECK_HEADERS([http_parser.h], [http_parser_headers=yes; break;])
AC_SUBST(http_parser_lib, ["-lhttp_parser"])
AS_IF([test "x$http_parser_headers" != "xyes"], AC_MSG_ERROR([Missing HttpParser headers files]))
])
CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
dnl Check for Argon2
AC_ARG_WITH([argon2], AS_HELP_STRING([--without-argon2], [Use included Argon2]))
AS_IF([test "x$with_argon2" != "xno"],
[PKG_CHECK_MODULES([Argon2], [libargon2], [have_argon2=yes], [have_argon2=no])],
[have_argon2=no])
AS_IF([test "x$have_argon2" = "xyes"], [
AC_MSG_NOTICE([Using system Argon2])
AC_SUBST(argon2_lib, [", libargon2"])
], [
AS_IF([test "x$with_argon2" = "xyes"], [
AC_MSG_ERROR([Argon2 requested but not found])
],[
AC_MSG_NOTICE([Using included Argon2])
AC_SUBST(Argon2_CFLAGS, "-I\${top_srcdir}/argon2/src -I\${top_srcdir}/argon2/include")
AC_SUBST(Argon2_LIBS, "libargon2.la")
AC_SUBST(Argon2_LDFLAGS, "-L\${abs_top_srcdir}/argon2/src/.libs")
])
])
AM_CONDITIONAL([WITH_INCLUDED_ARGON2], [test "x$have_argon2" = "xno"])
AC_ARG_ENABLE([tools], AS_HELP_STRING([--disable-tools],[Disable tools (CLI DHT node)]),,build_tools=yes)
AM_CONDITIONAL(ENABLE_TOOLS, test x$build_tools == xyes)
AM_COND_IF([ENABLE_TOOLS], [
@@ -212,24 +88,20 @@ AM_COND_IF([ENABLE_TOOLS], [
])
])
AM_COND_IF(ENABLE_PROXY_SERVER, AC_DEFINE([OPENDHT_PROXY_SERVER], [], [Building with proxy server]))
AM_COND_IF(ENABLE_PROXY_CLIENT, AC_DEFINE([OPENDHT_PROXY_CLIENT], [], [Building with proxy client]))
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS, [CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS"], [])
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY"], [])
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])])
dnl Configure setup.py if we build the python module
AC_SUBST(CURRENT_SOURCE_DIR, ".")
AC_SUBST(CURRENT_BINARY_DIR, ".")
AC_SUBST(PROJECT_SOURCE_DIR, "..")
AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs")
AM_COND_IF([USE_CYTHON], [
AC_SUBST(CURRENT_SOURCE_DIR, ".")
AC_SUBST(CURRENT_BINARY_DIR, ".")
AC_SUBST(PROJECT_SOURCE_DIR, "..")
AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs")
AC_CONFIG_FILES([python/Makefile python/setup.py])
])
AC_CONFIG_FILES([Makefile
src/Makefile
src/argon2/Makefile
tools/Makefile
python/Makefile
python/setup.py
tests/Makefile
doc/Makefile
doc/Doxyfile
opendht.pc])
AC_OUTPUT
-16
View File
@@ -1,16 +0,0 @@
if (OPENDHT_TOOLS)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dhtnode.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1)
endif ()
if (OPENDHT_DOCUMENTATION)
if (NOT DOXYGEN_FOUND)
message(FATAL_ERROR "Doxygen is needed to build the documentation.")
endif()
configure_file (Doxyfile.in Doxyfile @ONLY)
add_custom_target(doc ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc/opendht)
endif()
+1 -8
View File
@@ -1,10 +1,4 @@
dist_man1_MANS = dhtnode.1
noinst_HEADERS = \
Doxyfile
if HAVE_DOXYGEN
doxyfile.stamp: Doxyfile
doxyfile.stamp:
$(DOXYGEN) Doxyfile
echo stamp > doxyfile.stamp
@@ -13,4 +7,3 @@ CLEANFILES = doxyfile.stamp
all-local: doxyfile.stamp
clean-local:
rm -rf $(top_srcdir)/doc/man $(top_srcdir)/doc/html
endif
Binary file not shown.
@@ -1,142 +0,0 @@
\documentclass[11pt]{article}
\usepackage[utf8x]{inputenc}
\usepackage[top=2cm,bottom=2cm]{geometry}
\usepackage{forloop}
\newcounter{counter}
% maths
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{mathrsfs}
\usepackage{shadethm}
\usepackage{amsthm}
\newshadetheorem{shadeDef}{Definition}[section]
\newtheorem{remark}{Remark}[section]
\renewcommand{\P}{\mathbb{P}}
\usepackage{float}
\usepackage{booktabs}
\setlength{\parindent}{0ex}
\setlength{\parskip}{0.5em}
\begin{document}
\title{Annex 1: Probabilistic analysis of connectivity changes}
\author{Adrien Béraud, Simon Désaulniers, Guillaume Roguez}
\maketitle
\pagestyle{empty}
\begin{shadeDef}
A node flagged as \emph{``expired''} by a node $n$ is a node which has not responded to any
of $n$'s last three requests.
\end{shadeDef}
\begin{remark}
An expired node will not be contacted before 10 minutes from its expiration time.
\end{remark}
Let $N$ the DHT network, $n_0\in N$, a given node and the following probabilistic events:
\begin{itemize}
\item $A$: $\forall n \in N$ $n$ is unreachable by $n_0$, \emph{i.e.} $n_0$ lost connection
with $N$;
\item $B$: $S\subset N$, the nodes unreachable by $n_0$ with $k={|S|\over|N|}$;
\item $C$: $m \le |N|$ nodes are flagged as ``expired''.
\end{itemize}
We are interested in knowing $\P(A|C)$, \emph{i.e.} the probability of the event where $A$ occurs
prior to $C$. From the above, we immediately get
$$\left\{
\begin{array}{ll}
\P(C|A) & = 1\\
\P(A) + \P(B) & = 1
\end{array}
\right.$$
Also, the event $A|C$ can be abstracted as the urn problem of draw without replacement. Then,
$$\P(C|B) = \prod_{i=0}^m \left[k|N| - i \over |N|\right] = \prod_{i=0}^m \left[k - { i \over |N| }\right]$$
Furthermore, using Bayes' theroem we have
\begin{align*}
\P(A|C) & = { \P(C|A)\P(A) \over \P(C|A)\P(A) + \P(C|B)\P(B)}\\
& = { \P(A) \over \P(A) + \P(C|B)\P(B) }\\
& = { \P(A) \over \P(A) + \P(C|B)\left[1 - \P(A)\right] }\\
\Rightarrow \forloop{counter}{0}{\value{counter} < 5}{\qquad}\quad \P(A) & =
\P(A|C)\left[\P(A) + \P(C|B)\left(1 - \P(A)\right) \right] \\
\Rightarrow \forloop{counter}{0}{\value{counter} < 2}{\qquad}\;\:\, \P(A)\left[{ 1 \over \P(A|C)} - 1\right] & =
\P(C|B)\left(1 - \P(A)\right) \\
\end{align*}
Finally,
\begin{equation}
\label{eq:final}
\left[{\P(A) \over 1 - \P(A)}\right]\left[{ 1 \over \P(A|C)} - 1\right] =
\prod_{i=0}^m \left[k - { i \over |N| }\right]
\end{equation}
From \eqref{eq:final}, we may set a plausible configuration $\{\P(A),\P(A|C),k,|N|\}$ letting us
produce results such as in table \ref{tbl:k_1_2}, \ref{tbl:k_2_3} and \ref{tbl:k_3_4}.
\begin{table}[H]
\centering
\caption{The values for $m$ assuming $\P(A|C) \ge 0.95,\, k = {1 \over 2}$}
\label{tbl:k_1_2}
\begin{tabular}{lcccc}
\toprule
$|N| \diagdown \P(A)$ & ${1 \over 10 }$ & ${1 \over 100 }$ & ${1 \over 1000 }$ & ${1 \over 10000 }$\\
\midrule
$2^0$ & 1 & 1 & 1 & 1\\
$2^1$ & 1 & 1 & 1 & 1\\
$2^2$ & 2 & 2 & 2 & 2\\
$2^3$ & 4 & 4 & 4 & 4\\
$2^4$ & 5 & 6 & 7 & 8\\
$2^5$ & 5 & 7 & 9 & 10\\
$2^6$ & 6 & 9 & 11 & 13\\
$2^7$ & 6 & 9 & 12 & 14\\
$2^8$ & 7 & 10 & 13 & 16\\
$2^9$ & 7 & 10 & 13 & 16\\
$2^{10}$ & 7 & 10 & 13 & 17\\
\bottomrule
\end{tabular}
\end{table}
\begin{table}[H]
\centering
\caption{The values for $m$ assuming $\P(A|C) \ge 0.95,\, k = {2 \over 3}$}
\label{tbl:k_2_3}
\begin{tabular}{lcccc}
\toprule
$|N| \diagdown \P(A)$ & ${1 \over 10 }$ & ${1 \over 100 }$ & ${1 \over 1000 }$ & ${1 \over 10000 }$\\
\midrule
$2^0$ & 1 & 1 & 1 & 1\\
$2^1$ & 2 & 2 & 2 & 2\\
$2^2$ & 3 & 3 & 4 & 4\\
$2^3$ & 5 & 5 & 6 & 8\\
$2^4$ & 6 & 8 & 9 & 10\\
$2^5$ & 8 & 10 & 12 & 14\\
$2^6$ & 9 & 13 & 16 & 18\\
$2^7$ & 11 & 15 & 18 & 22\\
$2^8$ & 11 & 16 & 21 & 25\\
$2^9$ & 12 & 17 & 22 & 27\\
$2^{10}$ & 12 & 18 & 23 & 28\\
\bottomrule
\end{tabular}
\end{table}
\begin{table}[H]
\centering
\caption{The values for $m$ assuming $\P(A|C) \ge 0.95,\, k = {3 \over 4}$}
\label{tbl:k_3_4}
\begin{tabular}{lcccc}
\toprule
$|N| \diagdown \P(A)$ & ${1 \over 10 }$ & ${1 \over 100 }$ & ${1 \over 1000 }$ & ${1 \over 10000 }$\\
\midrule
$2^0$ & 1 & 1 & 1 & 1\\
$2^1$ & 2 & 2 & 2 & 2\\
$2^2$ & 3 & 3 & 3 & 3\\
$2^3$ & 5 & 6 & 6 & 6\\
$2^4$ & 7 & 9 & 10 & 11\\
$2^5$ & 10 & 12 & 14 & 16\\
$2^6$ & 12 & 16 & 19 & 22\\
$2^7$ & 14 & 19 & 23 & 27\\
$2^8$ & 15 & 21 & 27 & 32\\
$2^9$ & 16 & 23 & 30 & 36\\
$2^{10}$ & 17 & 24 & 31 & 38\\
\bottomrule
\end{tabular}
\end{table}
\end{document}
-109
View File
@@ -1,109 +0,0 @@
.TH DHTNODE 1 2019-06-08
.SH NAME
.B dhtnode
- a simple OpenDHT command line node runner.
.SH SYNOPSIS
.B dhtnode
[\fB\-h\fR]
[\fB\-v\fR [\fB\-l\fR \fIlogfile\fR] [\fB\-L\fR]]
[\fB\-i\fR [\fB\-\-save\-identity\fR \fIfile\fR]]
[\fB\-d\fR] [\fB\-s\fR]
[\fB\-n\fR \fInetwork_id\fR]
[\fB\-p\fR \fIlocal_port\fR]
[\fB\-b\fR \fIbootstrap_host\fR[:\fIport\fR]]
[\fB\-\-certificate\fR \fIfile\fR]
[\fB\-\-privkey\fR \fIfile\fR]
[\fB\-\-privkey\-password\fR \fIpassword\fR]
[\fB\-\-proxyserver\fR \fIport\fR]
[\fB\-\-proxyclient\fR \fIserver\fR]
.SH DESCRIPTION
Runs an OpenDHT node, with a CLI (default) or as a daemon (with \fB'-d'\fP or \fB'-s'\fP).
Commands available in the interactive shell are:
.EE
h, help Print this help message.
q, quit Quit the program.
log Start/stop printing DHT logs.
Node information:
ll Print basic information and stats about the current node.
ls Print basic information about current searches.
ld Print basic information about currenty stored values on this node.
lr Print the full current routing table of this node
Operations on the DHT:
b ip:port Ping potential node at given IP address/port.
g [key] Get values at [key].
l [key] Listen for value changes at [key].
p [key] [str] Put string value at [key].
s [key] [str] Put string value at [key], signed with our generated
private key.
e [key] [dest] [str] Put string value at [key], encrypted for [dest] with
its public key (if found).
.SH OPTIONS
.TP
\fB\-h\fP
Prints some help.
.TP
\fB\-v\fP
Enable the verbose mode (log to stdout/stderr by default)
.TP
\fB\-l\fP \fIlog_file\fP
Write log to file instead of stdout/stderr
.TP
\fB\-L\fP
Write log to syslog instead of stdout/stderr
.TP
\fB\-i\fP
Generate cryptographic identity for the node.
.TP
\fB\-\-save\-identity\fP \fIfile\fP
Save generated identity (certificate and private key) to given file prefix.
.TP
\fB\-\-certificate\fP \fIfile\fP
Load identity certificate from given file.
.TP
\fB\-\-privkey\fP \fIfile\fP
Load identity private key from given file.
.TP
\fB\-\-privkey\-password\fP \fIpassword\fP
Password to use for private key encryption or decryption (optional).
.TP
\fB\-d\fP
Run the program in daemon mode (will fork in the background).
.TP
\fB\-s\fP
Run the program in service mode (non\-forking daemon).
.TP
\fB\-D\fP
Enables multicast automatic local peer discovery.
.TP
\fB\-f\fP \fIfile\fP
Specify a file path to persist/load the node state.
.TP
\fB\-n\fP \fInetwork_id\fP
Specify the network id. This let you connect to distinct networks and prevents
the merge of two different networks (available since OpenDHT v0.6.1).
.TP
\fB\-p\fP \fIlocal_port\fP
Use UDP port \fIlocal_port\fP for the program to bind to.
.TP
\fB\-b\fP \fIbootstrap_host\fP[:\fIport\fP]
The program needs to be given a node to connect to the network. You use this
option to provide the ip address of that node.
.TP
\fB\-\-proxyserver\fP \fIlocal_port\fP
Run a proxy server bound to this DHT node on HTTP port \fIlocal_port\fP
.TP
\fB\-\-proxyclient\fP \fIserver\fP
Run this DHT node in proxy client mode, and connect to \fIserver\fP
.SH AUTHORS
.TP
Program written by
.IP \(bu
.\}
Adrien Béraud <adrien.beraud@savoirfairelinux.com>
.TP
Man page written by
.IP \(bu
.\}
Simon Désaulniers <sim.desaulniers@gmail.com>
-6
View File
@@ -1,6 +0,0 @@
FROM aberaud/opendht-deps
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On && make -j8 && make install \
&& cd ../.. && rm -rf opendht
-13
View File
@@ -1,13 +0,0 @@
FROM docker.pkg.github.com/savoirfairelinux/opendht/opendht-deps-bionic:2.0.0
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DOPENDHT_PROXY_CLIENT=On \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_C=On \
-DOPENDHT_PYTHON=On \
-DOPENDHT_LTO=On \
&& make -j8 && make install \
&& cd ../.. && rm -rf opendht
-56
View File
@@ -1,56 +0,0 @@
FROM ubuntu:16.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN apt-get update && apt-get install -y \
build-essential cmake git wget libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libssl-dev \
&& apt-get clean
RUN echo "*** Installing libfmt ***" \
&& wget https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz \
&& tar -xzf 5.3.0.tar.gz && cd fmt-5.3.0/ \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On -DFMT_TEST=Off -DFMT_DOC=Off . \
&& make -j8 && make install \
&& cd ../ && rm -rf fmt*
# libhttp-parser-dev is 2.1-2 which is too old
RUN echo "*** Building nodejs/http_parser dependency ***" \
&& wget https://github.com/nodejs/http-parser/archive/v2.9.2.tar.gz \
&& tar xvf v2.9.2.tar.gz && cd http-parser-2.9.2/ \
&& PREFIX=/usr make -j8 install \
&& cd ../ && rm -rf http-parser*
# libasio-dev (1.10.6-3) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& make install \
&& cd ../../ && rm -rf asio*
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../ && rm -rf restinio*
# build restbed from sources
RUN git clone --recursive https://github.com/corvusoft/restbed.git \
&& cd restbed && mkdir build && cd build \
&& cmake -DBUILD_TESTS=NO -DBUILD_EXAMPLES=NO -DBUILD_SSL=NO -DBUILD_SHARED=YES -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib .. \
&& make -j8 install \
&& cd .. && rm -rf restbed
#build msgpack from source
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.1.5/msgpack-2.1.5.tar.gz \
&& tar -xzf msgpack-2.1.5.tar.gz \
&& cd msgpack-2.1.5 && mkdir build && cd build \
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
&& make -j8 && make install \
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
-28
View File
@@ -1,28 +0,0 @@
FROM ubuntu:18.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN echo "APT::Acquire::Retries \"3\";" > /etc/apt/apt.conf.d/80-retries
RUN apt-get update && apt-get install -y \
apt-transport-https build-essential cmake git wget libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libssl-dev \
&& apt-get clean
# libasio-dev (1.10) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& make install \
&& cd ../../ && rm -rf asio*
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& ls -l && tar -xzf 8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& cd restinio-8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../ && rm -rf restinio*
-62
View File
@@ -1,62 +0,0 @@
FROM ubuntu:16.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN apt-get update \
&& apt-get install -y llvm llvm-dev clang make cmake git wget libncurses5-dev libreadline-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev cython3 python3-dev \
python3-setuptools libcppunit-dev python3-pip \
autotools-dev autoconf libssl-dev \
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
ENV CC cc
ENV CXX c++
RUN echo "*** Installing libfmt ***" \
&& wget https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz \
&& tar -xzf 5.3.0.tar.gz && cd fmt-5.3.0/ \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On -DFMT_TEST=Off -DFMT_DOC=Off . \
&& make -j8 && make install \
&& cd ../ && rm -rf fmt*
# libhttp-parser-dev is 2.1-2 which is too old
RUN echo "*** Building nodejs/http_parser dependency ***" \
&& wget https://github.com/nodejs/http-parser/archive/v2.9.2.tar.gz \
&& tar xvf v2.9.2.tar.gz && cd http-parser-2.9.2/ \
&& PREFIX=/usr make -j8 install \
&& cd ../ && rm -rf http-parser*
# libasio-dev (1.10.6-3) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& make install \
&& cd ../../ && rm -rf asio*
#patch for https://github.com/Stiffstream/restinio-conan-example/issues/2
RUN apt-get update && apt-get install -y python3-pip && pip3 install --upgrade cmake
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../ && rm -rf restinio*
# build restbed from sources
RUN git clone --recursive https://github.com/corvusoft/restbed.git \
&& cd restbed && mkdir build && cd build \
&& cmake -DBUILD_TESTS=NO -DBUILD_EXAMPLES=NO -DBUILD_SSL=NO -DBUILD_SHARED=YES -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib .. \
&& make -j8 install \
&& cd .. && rm -rf restbed
#build msgpack from source
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.1.5/msgpack-2.1.5.tar.gz \
&& tar -xzf msgpack-2.1.5.tar.gz \
&& cd msgpack-2.1.5 && mkdir build && cd build \
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
&& make -j8 && make install \
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
-7
View File
@@ -1,7 +0,0 @@
FROM aberaud/opendht-deps
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
RUN cd /root/opendht && mkdir build && cd build \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_LTO=On -DOPENDHT_TESTS=ON .. \
&& make -j8 && ./opendht_unit_tests && make install
-7
View File
@@ -1,7 +0,0 @@
FROM aberaud/opendht-deps-llvm
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
RUN cd /root/opendht && mkdir build && cd build \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_TESTS=ON .. \
&& make -j8 && ./opendht_unit_tests && make install
-4
View File
@@ -1,4 +0,0 @@
FROM aberaud/opendht-deps
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
+4 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,10 +13,12 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "opendht/dhtrunner.h"
#include "opendht/log.h"
#include "opendht/default_types.h"
+18 -130
View File
@@ -1,8 +1,6 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +13,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
@@ -26,163 +25,52 @@
#include <vector>
#include <memory>
#include <functional>
#include <string>
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
#endif
namespace dht {
struct Node;
/**
* Current status of a DHT node.
*/
enum class NodeStatus {
Disconnected, // 0 nodes
Connecting, // 1+ nodes
Connected // 1+ good nodes
};
inline constexpr const char*
statusToStr(NodeStatus status) {
return status == NodeStatus::Connected ? "connected" : (
status == NodeStatus::Connecting ? "connecting" :
"disconnected");
}
struct OPENDHT_PUBLIC NodeStats {
unsigned good_nodes {0},
dubious_nodes {0},
cached_nodes {0},
incoming_nodes {0};
unsigned table_depth {0};
unsigned searches {0};
unsigned node_cache_size {0};
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
unsigned long getNetworkSizeEstimation() const { return 8 * std::exp2(table_depth); }
std::string toString() const;
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const;
NodeStats() {};
explicit NodeStats(const Json::Value& v);
#endif
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth, searches, node_cache_size)
};
struct OPENDHT_PUBLIC NodeInfo {
InfoHash id;
struct Config {
InfoHash node_id;
NodeStats ipv4 {};
NodeStats ipv6 {};
size_t ongoing_ops {0};
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const;
NodeInfo() {};
explicit NodeInfo(const Json::Value& v);
#endif
MSGPACK_DEFINE_MAP(id, node_id, ipv4, ipv6)
bool is_bootstrap;
};
/**
* Dht configuration.
*/
struct OPENDHT_PUBLIC Config {
/** DHT node ID */
InfoHash node_id {};
/**
* DHT network ID. A node will only talk with other nodes having
* the same network ID.
* Network ID 0 (default) represents the main public network.
*/
NetId network {0};
/** For testing purposes only, enables bootstrap mode */
bool is_bootstrap {false};
/** Makes the DHT responsible to maintain its stored values. Consumes more ressources. */
bool maintain_storage {false};
/** If set, the dht will load its state from this file on start and save its state in this file on shutdown */
std::string persist_path {};
/** If non-0, overrides the default global rate-limit. -1 means no limit. */
ssize_t max_req_per_sec {0};
/** If non-0, overrides the default per-IP address rate-limit. -1 means no limit. */
ssize_t max_peer_req_per_sec {0};
/* If non-0, overrides the default maximum number of searches. -1 means no limit. */
ssize_t max_searches {0};
/* If non-0, overrides the default maximum store size. -1 means no limit. */
ssize_t max_store_size {0};
/**
* Use appropriate bahavior for a public IP, stable node:
* - No connectivity change triggered when a search fails
* - Larger listen refresh time
*/
bool public_stable {false};
};
/**
* SecureDht configuration.
*/
struct OPENDHT_PUBLIC SecureDhtConfig
struct SecureDhtConfig
{
Config node_config {};
crypto::Identity id {};
/**
* Cache all encountered public keys and certificates,
* for use by the certificate store, putEncrypted and putSigned
*/
bool cert_cache_all {false};
Config node_config;
crypto::Identity id;
};
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
using ValuesExport = std::pair<InfoHash, Blob>;
using QueryCallback = std::function<bool(const std::vector<std::shared_ptr<FieldValueIndex>>& fields)>;
using GetCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values)>;
using ValueCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values, bool expired)>;
using GetCallbackSimple = std::function<bool(std::shared_ptr<Value> value)>;
using ShutdownCallback = std::function<void()>;
using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::Certificate>>(const InfoHash& pk_id)>;
typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data);
typedef bool (*ValueCallbackRaw)(std::shared_ptr<Value>, bool expired, void *user_data);
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
GetCallback bindGetCb(GetCallbackSimple cb);
using DoneCallback = std::function<void(bool success, const std::vector<std::shared_ptr<Node>>& nodes)>;
typedef void (*DoneCallbackRaw)(bool, std::vector<std::shared_ptr<Node>>*, void *user_data);
typedef void (*ShutdownCallbackRaw)(void *user_data);
typedef void (*DoneCallbackSimpleRaw)(bool, void *user_data);
typedef bool (*FilterRaw)(const Value&, void *user_data);
using DoneCallbackSimple = std::function<void(bool success)>;
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(const GetCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC GetCallback bindGetCb(const GetCallbackSimple& cb);
OPENDHT_PUBLIC ValueCallback bindValueCb(const ValueCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data);
OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackSimple donecb);
OPENDHT_PUBLIC DoneCallback bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC Value::Filter bindFilterRaw(const FilterRaw& raw_filter, void* user_data);
ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data);
DoneCallback bindDoneCb(DoneCallbackSimple donecb);
DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data);
}
+37 -393
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,14 +13,14 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "infohash.h"
#include "utils.h"
#include "rng.h"
extern "C" {
#include <gnutls/gnutls.h>
@@ -36,50 +36,38 @@ extern "C" {
#endif
namespace dht {
/**
* Contains all crypto primitives
*/
namespace crypto {
class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
public:
explicit CryptoException(const std::string& str) : std::runtime_error(str) {};
explicit CryptoException(const char* str) : std::runtime_error(str) {};
CryptoException(const CryptoException& e) noexcept = default;
CryptoException& operator=(const CryptoException&) noexcept = default;
class CryptoException : public std::runtime_error {
public:
CryptoException(const std::string& str) : std::runtime_error(str) {};
};
/**
* Exception thrown when a decryption error happened.
*/
class OPENDHT_PUBLIC DecryptError : public CryptoException {
public:
explicit DecryptError(const std::string& str) : CryptoException(str) {};
explicit DecryptError(const char* str) : CryptoException(str) {};
DecryptError(const DecryptError& e) noexcept = default;
DecryptError& operator=(const DecryptError&) noexcept = default;
class DecryptError : public CryptoException {
public:
DecryptError(const std::string& str = "") : CryptoException(str) {};
};
struct PrivateKey;
struct Certificate;
class RevocationList;
using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certificate>>;
/**
* A public key.
*/
struct OPENDHT_PUBLIC PublicKey
struct PublicKey
{
PublicKey();
PublicKey() {}
/**
* Takes ownership of an existing gnutls_pubkey.
*/
PublicKey(gnutls_pubkey_t k) : pk(k) {}
PublicKey(const uint8_t* dat, size_t dat_size);
PublicKey(const Blob& pk) : PublicKey(pk.data(), pk.size()) {}
PublicKey(const Blob& pk);
PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; };
~PublicKey();
@@ -93,32 +81,13 @@ struct OPENDHT_PUBLIC PublicKey
PublicKey& operator=(PublicKey&& o) noexcept;
/**
* Get public key fingerprint
*/
InfoHash getId() const;
/**
* Get public key long fingerprint
*/
PkId getLongId() const;
bool checkSignature(const uint8_t* data, size_t data_len, const uint8_t* signature, size_t signature_len) const;
bool checkSignature(const Blob& data, const Blob& signature) const {
return checkSignature(data.data(), data.size(), signature.data(), signature.size());
}
Blob encrypt(const uint8_t* data, size_t data_len) const;
Blob encrypt(const Blob& data) const {
return encrypt(data.data(), data.size());
}
bool checkSignature(const Blob& data, const Blob& signature) const;
Blob encrypt(const Blob&) const;
void pack(Blob& b) const;
int pack(uint8_t* out, size_t* out_len) const;
void unpack(const uint8_t* dat, size_t dat_size);
std::string toString() const;
template <typename Packer>
void msgpack_pack(Packer& p) const
{
@@ -128,11 +97,9 @@ struct OPENDHT_PUBLIC PublicKey
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(const msgpack::object& o);
void msgpack_unpack(msgpack::object o);
gnutls_digest_algorithm_t getPreferredDigest() const;
gnutls_pubkey_t pk {nullptr};
gnutls_pubkey_t pk {};
private:
PublicKey(const PublicKey&) = delete;
PublicKey& operator=(const PublicKey&) = delete;
@@ -142,7 +109,7 @@ private:
/**
* A private key, including the corresponding public key.
*/
struct OPENDHT_PUBLIC PrivateKey
struct PrivateKey
{
PrivateKey();
//PrivateKey(gnutls_privkey_t k) : key(k) {}
@@ -155,13 +122,10 @@ struct OPENDHT_PUBLIC PrivateKey
PrivateKey(PrivateKey&& o) noexcept;
PrivateKey& operator=(PrivateKey&& o) noexcept;
PrivateKey(const uint8_t* src, size_t src_size, const char* password = nullptr);
PrivateKey(const Blob& src, const std::string& password = {}) : PrivateKey(src.data(), src.size(), password.data()) {}
PrivateKey(const Blob& import, const std::string& password = {});
~PrivateKey();
explicit operator bool() const { return key; }
PublicKey getPublicKey() const;
int serialize(uint8_t* out, size_t* out_len, const std::string& password = {}) const;
Blob serialize(const std::string& password = {}) const;
/**
@@ -184,7 +148,6 @@ struct OPENDHT_PUBLIC PrivateKey
* Recommended values: 4096, 8192
*/
static PrivateKey generate(unsigned key_length = 4096);
static PrivateKey generateEC();
gnutls_privkey_t key {};
gnutls_x509_privkey_t x509_key {};
@@ -196,126 +159,13 @@ private:
//friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length);
};
class OPENDHT_PUBLIC RevocationList
{
using clock = std::chrono::system_clock;
using time_point = clock::time_point;
using duration = clock::duration;
public:
RevocationList();
RevocationList(const Blob& b);
RevocationList(RevocationList&& o) noexcept : crl(o.crl) { o.crl = nullptr; }
~RevocationList();
RevocationList& operator=(RevocationList&& o) { crl = o.crl; o.crl = nullptr; return *this; }
void pack(Blob& b) const;
void unpack(const uint8_t* dat, size_t dat_size);
Blob getPacked() const {
Blob b;
pack(b);
return b;
}
template <typename Packer>
void msgpack_pack(Packer& p) const
{
Blob b = getPacked();
p.pack_bin(b.size());
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(const msgpack::object& o);
void revoke(const Certificate& crt, time_point t = time_point::min());
bool isRevoked(const Certificate& crt) const;
/**
* Sign this revocation list using provided key and certificate.
* Validity_period sets the duration until next update (default to no next update).
*/
void sign(const PrivateKey&, const Certificate&, duration validity_period = {});
void sign(const Identity& id) { sign(*id.first, *id.second); }
bool isSignedBy(const Certificate& issuer) const;
std::string toString() const;
/**
* Read the CRL number extension field.
*/
Blob getNumber() const;
/** Read CRL issuer Common Name (CN) */
std::string getIssuerName() const;
/** Read CRL issuer User ID (UID) */
std::string getIssuerUID() const;
time_point getUpdateTime() const;
time_point getNextUpdateTime() const;
gnutls_x509_crl_t get() { return crl; }
gnutls_x509_crl_t getCopy() const {
if (not crl)
return nullptr;
auto copy = RevocationList(getPacked());
gnutls_x509_crl_t ret = copy.crl;
copy.crl = nullptr;
return ret;
}
private:
gnutls_x509_crl_t crl {};
RevocationList(const RevocationList&) = delete;
RevocationList& operator=(const RevocationList&) = delete;
};
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
class OPENDHT_PUBLIC CertificateRequest {
public:
CertificateRequest();
CertificateRequest(const uint8_t* data, size_t size);
CertificateRequest(const Blob& data) : CertificateRequest(data.data(), data.size()) {}
CertificateRequest(CertificateRequest&& o) noexcept : request(std::move(o.request)) {
o.request = nullptr;
}
CertificateRequest& operator=(CertificateRequest&& o) noexcept;
~CertificateRequest();
void setName(const std::string& name);
void setUID(const std::string& name);
void setAltName(NameType type, const std::string& name);
std::string getName() const;
std::string getUID() const;
void sign(const PrivateKey& key, const std::string& password = {});
bool verify() const;
Blob pack() const;
std::string toString() const;
gnutls_x509_crq_t get() const { return request; }
private:
CertificateRequest(const CertificateRequest& o) = delete;
CertificateRequest& operator=(const CertificateRequest& o) = delete;
gnutls_x509_crq_t request {nullptr};
};
struct OPENDHT_PUBLIC Certificate {
Certificate() noexcept {}
struct Certificate {
Certificate() {}
/**
* Take ownership of existing gnutls structure
*/
Certificate(gnutls_x509_crt_t crt) noexcept : cert(crt) {}
Certificate(gnutls_x509_crt_t crt) : cert(crt) {}
Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
@@ -324,10 +174,7 @@ struct OPENDHT_PUBLIC Certificate {
* ordered from subject to issuer
*/
Certificate(const Blob& crt);
Certificate(const std::string& pem) : cert(nullptr) {
unpack((const uint8_t*)pem.data(), pem.size());
}
Certificate(const uint8_t* dat, size_t dat_size) : cert(nullptr) {
Certificate(const uint8_t* dat, size_t dat_size) {
unpack(dat, dat_size);
}
@@ -424,15 +271,13 @@ struct OPENDHT_PUBLIC Certificate {
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(const msgpack::object& o);
void msgpack_unpack(msgpack::object o);
explicit operator bool() const { return cert; }
PublicKey getPublicKey() const;
/** Same as getPublicKey().getId() */
InfoHash getId() const;
/** Same as getPublicKey().getLongId() */
PkId getLongId() const;
/** Read certificate Common Name (CN) */
std::string getName() const;
@@ -446,15 +291,13 @@ struct OPENDHT_PUBLIC Certificate {
/** Read certificate issuer User ID (UID) */
std::string getIssuerUID() const;
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
/** Read certificate alternative names */
std::vector<std::pair<NameType, std::string>> getAltNames() const;
std::chrono::system_clock::time_point getActivation() const;
std::chrono::system_clock::time_point getExpiration() const;
/**
* Returns true if the certificate is marked as a Certificate Authority
* and has necessary key usage flags to sign certificates.
* Returns true if the certificate is marked as a Certificate Authority.
*/
bool isCA() const;
@@ -464,200 +307,15 @@ struct OPENDHT_PUBLIC Certificate {
*/
std::string toString(bool chain = true) const;
std::string print() const;
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false);
/**
* As a CA, revoke a certificate, adding it to
* the attached Certificate Revocation List (CRL)
*/
void revoke(const PrivateKey&, const Certificate&);
/**
* Get the list of certificates revoked as as CA.
*/
std::vector<std::shared_ptr<RevocationList>> getRevocationLists() const;
/**
* Attach existing revocation list.
*/
void addRevocationList(RevocationList&&);
void addRevocationList(std::shared_ptr<RevocationList>);
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false);
static Certificate generate(const CertificateRequest& request, const Identity& ca);
gnutls_x509_crt_t getCopy() const {
if (not cert)
return nullptr;
auto copy = Certificate(getPacked());
gnutls_x509_crt_t ret = copy.cert;
copy.cert = nullptr;
return ret;
}
std::vector<gnutls_x509_crt_t>
getChain(bool copy = false) const
{
if (not cert)
return {};
std::vector<gnutls_x509_crt_t> crts;
for (auto c = this; c; c = c->issuer.get())
crts.emplace_back(copy ? c->getCopy() : c->cert);
return crts;
}
std::pair<
std::vector<gnutls_x509_crt_t>,
std::vector<gnutls_x509_crl_t>
>
getChainWithRevocations(bool copy = false) const
{
if (not cert)
return {};
std::vector<gnutls_x509_crt_t> crts;
std::vector<gnutls_x509_crl_t> crls;
for (auto c = this; c; c = c->issuer.get()) {
crts.emplace_back(copy ? c->getCopy() : c->cert);
crls.reserve(crls.size() + c->revocation_lists.size());
for (const auto& crl : c->revocation_lists)
crls.emplace_back(copy ? crl->getCopy() : crl->get());
}
return {crts, crls};
}
gnutls_digest_algorithm_t getPreferredDigest() const;
gnutls_x509_crt_t cert {nullptr};
gnutls_x509_crt_t cert {};
std::shared_ptr<Certificate> issuer {};
private:
Certificate(const Certificate&) = delete;
Certificate& operator=(const Certificate&) = delete;
struct crlNumberCmp {
bool operator() (const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const {
return lhs->getNumber() < rhs->getNumber();
}
};
std::set<std::shared_ptr<RevocationList>, crlNumberCmp> revocation_lists;
};
struct OPENDHT_PUBLIC TrustList
{
struct VerifyResult {
int ret;
unsigned result;
bool hasError() const { return ret < 0; }
bool isValid() const { return !hasError() and !(result & GNUTLS_CERT_INVALID); }
explicit operator bool() const { return isValid(); }
std::string toString() const;
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const VerifyResult& h);
};
TrustList();
TrustList(TrustList&& o) noexcept : trust(std::move(o.trust)) {
o.trust = nullptr;
}
TrustList& operator=(TrustList&& o) noexcept;
~TrustList();
void add(const Certificate& crt);
void add(const RevocationList& crl);
void remove(const Certificate& crt, bool parents = true);
VerifyResult verify(const Certificate& crt) const;
private:
TrustList(const TrustList& o) = delete;
TrustList& operator=(const TrustList& o) = delete;
gnutls_x509_trust_list_t trust {nullptr};
};
template <class T>
class OPENDHT_PUBLIC secure_vector
{
public:
secure_vector() {}
secure_vector(secure_vector<T> const&) = default;
secure_vector(secure_vector<T> &&) = default;
explicit secure_vector(unsigned size): data_(size) {}
explicit secure_vector(unsigned size, T _item): data_(size, _item) {}
explicit secure_vector(const std::vector<T>& c): data_(c) {}
secure_vector(std::vector<T>&& c): data_(std::move(c)) {}
~secure_vector() { clean(); }
static secure_vector<T> getRandom(size_t size) {
secure_vector<T> ret(size);
crypto::random_device rdev;
#ifdef _WIN32
std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
#else
std::uniform_int_distribution<uint8_t> rand_byte;
#endif
std::generate_n((uint8_t*)ret.data_.data(), ret.size()*sizeof(T), std::bind(rand_byte, std::ref(rdev)));
return ret;
}
secure_vector<T>& operator=(const secure_vector<T>& c) {
if (&c == this)
return *this;
clean();
data_ = c.data_;
return *this;
}
secure_vector<T>& operator=(secure_vector<T>&& c) {
if (&c == this)
return *this;
clean();
data_ = std::move(c.data_);
return *this;
}
secure_vector<T>& operator=(std::vector<T>&& c) {
clean();
data_ = std::move(c);
return *this;
}
std::vector<T>& writable() { clean(); return data_; }
const std::vector<T>& makeInsecure() const { return data_; }
const uint8_t* data() const { return data_.data(); }
void clean() {
clean(data_.begin(), data_.end());
}
void clear() { clean(); data_.clear(); }
size_t size() const { return data_.size(); }
bool empty() const { return data_.empty(); }
void swap(secure_vector<T>& other) { data_.swap(other.data_); }
void resize(size_t s) {
if (s == data_.size()) return;
if (s < data_.size()) {
//shrink
clean(data_.begin()+s, data_.end());
data_.resize(s);
} else {
//grow
auto data = std::move(data_); // move protected data
clear();
data_.resize(s);
std::copy(data.begin(), data.end(), data_.begin());
clean(data.begin(), data.end());
}
}
private:
/**
* Securely wipe memory
*/
static void clean(const typename std::vector<T>::iterator& i, const typename std::vector<T>::iterator& j) {
volatile uint8_t* b = reinterpret_cast<uint8_t*>(&*i);
volatile uint8_t* e = reinterpret_cast<uint8_t*>(&*j);
std::fill(b, e, 0);
}
std::vector<T> data_;
};
using SecureBlob = secure_vector<uint8_t>;
/**
* Generate an RSA key pair (4096 bits) and a certificate.
@@ -666,25 +324,14 @@ using SecureBlob = secure_vector<uint8_t>;
* If not set, the generated certificate will be a self-signed CA.
* @param key_length stength of the generated private key (bits).
*/
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca);
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", const Identity& ca = {}, unsigned key_length = 4096);
Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca);
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", const Identity& ca = {});
OPENDHT_PUBLIC void saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password = {});
/**
* Performs SHA512, SHA256 or SHA1, depending on hash_length.
* Attempts to choose an hash function with
* output size of at least hash_length bytes, Current implementation
* will use SHA1 for hash_length up to 20 bytes,
* will use SHA256 for hash_length up to 32 bytes,
* will use SHA512 for hash_length of 33 bytes and more.
* SHA512
*/
OPENDHT_PUBLIC Blob hash(const Blob& data, size_t hash_length = 512/8);
OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length);
Blob hash(const Blob& data);
/**
* Generates an encryption key from a text password,
@@ -693,22 +340,19 @@ OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash,
* that can be transmitted in clear, and will be generated if
* not provided (32 bytes).
*/
OPENDHT_PUBLIC Blob stretchKey(const std::string& password, Blob& salt, size_t key_length = 512/8);
Blob stretchKey(const std::string& password, Blob& salt);
/**
* AES-GCM encryption. Key must be 128, 192 or 256 bits long (16, 24 or 32 bytes).
*/
OPENDHT_PUBLIC Blob aesEncrypt(const uint8_t* data, size_t data_length, const Blob& key);
OPENDHT_PUBLIC inline Blob aesEncrypt(const Blob& data, const Blob& key) {
return aesEncrypt(data.data(), data.size(), key);
}
OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password);
Blob aesEncrypt(const Blob& data, const Blob& key);
Blob aesEncrypt(const Blob& data, const std::string& password);
/**
* AES-GCM decryption.
*/
OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key);
OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password);
Blob aesDecrypt(const Blob& data, const Blob& key);
Blob aesDecrypt(const Blob& data, const std::string& password);
}
}
-44
View File
@@ -1,44 +0,0 @@
#pragma once
// Generic helper definitions for shared library support
#if defined _WIN32 || defined __CYGWIN__
#define OPENDHT_IMPORT __declspec(dllimport)
#define OPENDHT_EXPORT __declspec(dllexport)
#define OPENDHT_HIDDEN
#else
#define OPENDHT_IMPORT __attribute__ ((visibility ("default")))
#define OPENDHT_EXPORT __attribute__ ((visibility ("default")))
#define OPENDHT_HIDDEN __attribute__ ((visibility ("hidden")))
#endif
// Now we use the generic helper definitions above to define OPENDHT_PUBLIC and OPENDHT_LOCAL.
// OPENDHT_PUBLIC is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)
// OPENDHT_LOCAL is used for non-api symbols.
#ifdef opendht_EXPORTS // defined if OpenDHT is compiled as a shared library
#ifdef OPENDHT_BUILD // defined if we are building the OpenDHT shared library (instead of using it)
#define OPENDHT_PUBLIC OPENDHT_EXPORT
#else
#define OPENDHT_PUBLIC OPENDHT_IMPORT
#endif // OPENDHT_BUILD
#define OPENDHT_LOCAL OPENDHT_HIDDEN
#else // opendht_EXPORTS is not defined: this means OpenDHT is a static lib.
#define OPENDHT_PUBLIC
#define OPENDHT_LOCAL
#endif // opendht_EXPORTS
#ifdef opendht_c_EXPORTS // defined if OpenDHT is compiled as a shared library
#ifdef OPENDHT_C_BUILD // defined if we are building the OpenDHT shared library (instead of using it)
#define OPENDHT_C_PUBLIC OPENDHT_EXPORT
#else
#define OPENDHT_C_PUBLIC OPENDHT_IMPORT
#endif // OPENDHT_BUILD
#define OPENDHT_C_LOCAL OPENDHT_HIDDEN
#else // opendht_EXPORTS is not defined: this means OpenDHT is a static lib.
#define OPENDHT_C_PUBLIC
#define OPENDHT_C_LOCAL
#endif // opendht_EXPORTS
// bytes
#define HASH_LEN 20u
+55 -46
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,13 +13,13 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "value.h"
#include "sockaddr.h"
namespace dht {
enum class ImStatus : uint8_t {
@@ -29,16 +29,16 @@ enum class ImStatus : uint8_t {
READ
};
}
MSGPACK_ADD_ENUM(dht::ImStatus)
MSGPACK_ADD_ENUM(dht::ImStatus);
namespace dht {
class OPENDHT_PUBLIC DhtMessage : public Value::Serializable<DhtMessage>
class DhtMessage : public Value::Serializable<DhtMessage>
{
public:
static const ValueType TYPE;
DhtMessage(const std::string& s = {}, const Blob& msg = {}) : service(s), data(msg) {}
DhtMessage(std::string s = {}, Blob msg = {}) : service(s), data(msg) {}
std::string getService() const {
return service;
@@ -46,20 +46,20 @@ public:
static Value::Filter getFilter() { return {}; }
static bool storePolicy(InfoHash key, std::shared_ptr<Value>& value, const InfoHash& from, const SockAddr&);
static bool storePolicy(InfoHash key, std::shared_ptr<Value>& value, InfoHash from, const sockaddr* from_addr, socklen_t from_len);
static Value::Filter ServiceFilter(const std::string& s);
static Value::Filter ServiceFilter(std::string s);
/** print value for debugging */
friend std::ostream& operator<< (std::ostream&, const DhtMessage&);
std::string service;
Blob data;
MSGPACK_DEFINE(service, data)
MSGPACK_DEFINE(service, data);
};
template <typename T>
class OPENDHT_PUBLIC SignedValue : public Value::Serializable<T>
class SignedValue : public Value::Serializable<T>
{
private:
using BaseClass = Value::Serializable<T>;
@@ -79,7 +79,7 @@ public:
};
template <typename T>
class OPENDHT_PUBLIC EncryptedValue : public SignedValue<T>
class EncryptedValue : public SignedValue<T>
{
public:
using BaseClass = SignedValue<T>;
@@ -93,7 +93,7 @@ public:
static Value::Filter getFilter() {
return Value::Filter::chain(
BaseClass::getFilter(),
[](const Value& v) { return static_cast<bool>(v.recipient); }
[](const Value& v){ return v.recipient != InfoHash(); }
);
}
@@ -103,7 +103,7 @@ public:
class OPENDHT_PUBLIC ImMessage : public SignedValue<ImMessage>
class ImMessage : public SignedValue<ImMessage>
{
private:
using BaseClass = SignedValue<ImMessage>;
@@ -114,10 +114,6 @@ public:
ImMessage() {}
ImMessage(dht::Value::Id id, std::string&& m, long d = 0)
: id(id), msg(std::move(m)), date(d) {}
ImMessage(dht::Value::Id id, std::string &&dt, std::string &&m, long d = 0)
: id(id), msg(std::move(m)), datatype(std::move(dt)), date(d) {}
ImMessage(dht::Value::Id id, std::string &&dt, std::string &&m, std::map<std::string, std::string> &&md, long d = 0)
: id(id), msg(std::move(m)), datatype(std::move(dt)), metadatas(std::move(md)), date(d) {}
virtual void unpackValue(const Value& v) override {
to = v.recipient;
@@ -125,17 +121,15 @@ public:
}
dht::InfoHash to;
dht::Value::Id id {0};
dht::Value::Id id;
std::string msg;
std::string datatype;
std::map<std::string, std::string> metadatas;
long date {0};
ImStatus status {ImStatus::NONE};
MSGPACK_DEFINE_MAP(id, msg, date, status, datatype, metadatas)
MSGPACK_DEFINE_MAP(id, msg, date, status);
};
class OPENDHT_PUBLIC TrustRequest : public EncryptedValue<TrustRequest>
class TrustRequest : public EncryptedValue<TrustRequest>
{
private:
using BaseClass = EncryptedValue<TrustRequest>;
@@ -153,11 +147,10 @@ public:
std::string service;
Blob payload;
bool confirm {false};
MSGPACK_DEFINE_MAP(service, payload, confirm)
MSGPACK_DEFINE(service, payload);
};
class OPENDHT_PUBLIC IceCandidates : public EncryptedValue<IceCandidates>
class IceCandidates : public EncryptedValue<IceCandidates>
{
private:
using BaseClass = EncryptedValue<IceCandidates>;
@@ -182,14 +175,14 @@ public:
pk.pack_bin_body((const char*)ice_data.data(), ice_data.size());
#else
// hack for backward compatibility with old opendht compiled with msgpack 1.0
// remove when enough people have moved to new versions
// remove when enough people have moved to new versions
pk.pack_array(ice_data.size());
for (uint8_t b : ice_data)
pk.pack(b);
#endif
}
virtual void msgpack_unpack(const msgpack::object& o)
virtual void msgpack_unpack(msgpack::object o)
{
if (o.type != msgpack::type::ARRAY) throw msgpack::type_error();
if (o.via.array.size < 2) throw msgpack::type_error();
@@ -197,13 +190,13 @@ public:
ice_data = unpackBlob(o.via.array.ptr[1]);
}
Value::Id id {0};
Value::Id id;
Blob ice_data;
};
/* "Peer" announcement
*/
class OPENDHT_PUBLIC IpServiceAnnouncement : public Value::Serializable<IpServiceAnnouncement>
class IpServiceAnnouncement : public Value::Serializable<IpServiceAnnouncement>
{
private:
using BaseClass = Value::Serializable<IpServiceAnnouncement>;
@@ -211,12 +204,15 @@ private:
public:
static const ValueType TYPE;
IpServiceAnnouncement(sa_family_t family = AF_UNSPEC, in_port_t p = 0) {
addr.setFamily(family);
addr.setPort(p);
IpServiceAnnouncement(in_port_t p = 0) {
ss.ss_family = 0;
setPort(p);
}
IpServiceAnnouncement(const SockAddr& sa) : addr(sa) {}
IpServiceAnnouncement(const sockaddr* sa, socklen_t sa_len) {
if (sa)
std::copy_n((const uint8_t*)sa, sa_len, (uint8_t*)&ss);
}
IpServiceAnnouncement(const Blob& b) {
msgpack_unpack(unpackMsg(b).get());
@@ -225,45 +221,58 @@ public:
template <typename Packer>
void msgpack_pack(Packer& pk) const
{
pk.pack_bin(addr.getLength());
pk.pack_bin_body((const char*)addr.get(), addr.getLength());
pk.pack_array(2);
pk.pack(getPort());
if (ss.ss_family == AF_INET) {
pk.pack_bin(sizeof(in_addr));
pk.pack_bin_body((const char*)&reinterpret_cast<const sockaddr_in*>(&ss)->sin_addr, sizeof(in_addr));
} else if (ss.ss_family == AF_INET6) {
pk.pack_bin(sizeof(in6_addr));
pk.pack_bin_body((const char*)&reinterpret_cast<const sockaddr_in6*>(&ss)->sin6_addr, sizeof(in6_addr));
}
}
virtual void msgpack_unpack(const msgpack::object& o)
virtual void msgpack_unpack(msgpack::object o)
{
if (o.type == msgpack::type::BIN)
addr = {(sockaddr*)o.via.bin.ptr, (socklen_t)o.via.bin.size};
if (o.type != msgpack::type::ARRAY) throw msgpack::type_error();
if (o.via.array.size < 2) throw msgpack::type_error();
setPort(o.via.array.ptr[0].as<in_port_t>());
auto ip_dat = o.via.array.ptr[1].as<Blob>();
if (ip_dat.size() == sizeof(in_addr))
std::copy(ip_dat.begin(), ip_dat.end(), (char*)&reinterpret_cast<sockaddr_in*>(&ss)->sin_addr);
else if (ip_dat.size() == sizeof(in6_addr))
std::copy(ip_dat.begin(), ip_dat.end(), (char*)&reinterpret_cast<sockaddr_in6*>(&ss)->sin6_addr);
else
throw msgpack::type_error();
}
in_port_t getPort() const {
return addr.getPort();
return ntohs(reinterpret_cast<const sockaddr_in*>(&ss)->sin_port);
}
void setPort(in_port_t p) {
addr.setPort(p);
reinterpret_cast<sockaddr_in*>(&ss)->sin_port = htons(p);
}
const SockAddr& getPeerAddr() const {
return addr;
sockaddr_storage getPeerAddr() const {
return ss;
}
virtual const ValueType& getType() const {
return TYPE;
}
static bool storePolicy(InfoHash, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&);
static bool storePolicy(InfoHash, std::shared_ptr<Value>&, InfoHash, const sockaddr*, socklen_t);
/** print value for debugging */
friend std::ostream& operator<< (std::ostream&, const IpServiceAnnouncement&);
private:
SockAddr addr;
sockaddr_storage ss;
};
OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 5> DEFAULT_TYPES;
extern const std::array<std::reference_wrapper<const ValueType>, 5> DEFAULT_TYPES;
OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_INSECURE_TYPES;
extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_INSECURE_TYPES;
}
+230 -330
View File
@@ -1,8 +1,7 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,9 +14,11 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "infohash.h"
@@ -27,13 +28,15 @@
#include "scheduler.h"
#include "routing_table.h"
#include "callbacks.h"
#include "dht_interface.h"
#include <string>
#include <array>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <functional>
#include <algorithm>
#include <memory>
#ifdef _WIN32
@@ -42,15 +45,7 @@
namespace dht {
namespace net {
struct Request;
} /* namespace net */
struct Storage;
struct ValueStorage;
class StorageBucket;
struct Listener;
struct LocalListener;
/**
* Main Dht class.
@@ -59,46 +54,42 @@ struct LocalListener;
* Must be given open UDP sockets and ::periodic must be
* called regularly.
*/
class OPENDHT_PUBLIC Dht final : public DhtInterface {
class Dht {
public:
// [[deprecated]]
using NodeExport = dht::NodeExport;
// [[deprecated]]
using Status = NodeStatus;
Dht();
/**
* Initialise the Dht with two open sockets (for IPv4 and IP6)
* and an ID for the node.
*/
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Sp<Logger>& l = {});
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {})
: Dht(std::move(sock), config, std::make_shared<Logger>(l)) {}
Dht(int s, int s6, Config config);
virtual ~Dht();
/**
* Get the ID of the node.
*/
inline const InfoHash& getNodeId() const override { return myid; }
NodeStatus updateStatus(sa_family_t af) override;
inline const InfoHash& getNodeId() const { return myid; }
/**
* Get the current status of the node for the given family.
*/
NodeStatus getStatus(sa_family_t af) const override {
return dht(af).status;
}
NodeStatus getStatus(sa_family_t af) const;
NodeStatus getStatus() const override {
NodeStatus getStatus() const {
return std::max(getStatus(AF_INET), getStatus(AF_INET6));
}
net::DatagramSocket* getSocket() const override { return network_engine.getSocket(); };
/**
* Performs final operations before quitting.
*/
void shutdown(ShutdownCallback cb) override;
void shutdown(ShutdownCallback cb);
/**
* Returns true if the node is running (have access to an open socket).
@@ -106,22 +97,19 @@ public:
* af: address family. If non-zero, will return true if the node
* is running for the provided family.
*/
bool isRunning(sa_family_t af = 0) const override;
bool isRunning(sa_family_t af = 0) const;
virtual void registerType(const ValueType& type) override {
types.registerType(type);
}
const ValueType& getType(ValueType::Id type_id) const override {
return types.getType(type_id);
}
/**
* Enable or disable logging of DHT internal messages
*/
void setLoggers(LogMethod error = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG);
void addBootstrap(const std::string& host, const std::string& service) override {
bootstrap_nodes.emplace_back(host, service);
onDisconnected();
virtual void registerType(const ValueType& type) {
types[type.id] = type;
}
void clearBootstrap() override {
bootstrap_nodes.clear();
const ValueType& getType(ValueType::Id type_id) const {
const auto& t_it = types.find(type_id);
return (t_it == types.end()) ? ValueType::USER_DATA : t_it->second;
}
/**
@@ -129,17 +117,14 @@ public:
* The node is not pinged, so this should be
* used to bootstrap efficiently from previously known nodes.
*/
void insertNode(const InfoHash& id, const SockAddr&) override;
void insertNode(const NodeExport& n) override {
insertNode(n.id, SockAddr(n.ss, n.sslen));
bool insertNode(const InfoHash& id, const sockaddr*, socklen_t);
bool insertNode(const NodeExport& n) {
return insertNode(n.id, reinterpret_cast<const sockaddr*>(&n.ss), n.sslen);
}
void pingNode(SockAddr, DoneCallbackSimple&& cb={}) override;
int pingNode(const sockaddr*, socklen_t);
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr, const time_point& now) override;
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
return periodic(buf, buflen, SockAddr(from, fromlen), now);
}
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr *from, socklen_t fromlen);
/**
* Get a value by searching on all available protocols (IPv4, IPv6),
@@ -148,60 +133,50 @@ public:
* @param cb a function called when new values are found on the network.
* It should return false to stop the operation.
* @param donecb a function called when the operation is complete.
cb and donecb won't be called again afterward.
cb and donecb won't be called again afterward.
* @param f a filter function used to prefilter values.
*/
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override;
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={});
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}) {
get(key, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f));
}
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f), std::forward<Where>(w));
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}) {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f));
}
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
/**
* Similar to Dht::get, but sends a Query to filter data remotely.
* @param key the key for which to query data for.
* @param cb a function called when new values are found on the network.
* It should return false to stop the operation.
* @param done_cb a function called when the operation is complete.
cb and done_cb won't be called again afterward.
* @param q a query used to filter values on the remotes before they send a
* response.
*/
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {}) override;
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override {
query(key, cb, bindDoneCb(done_cb), std::forward<Query>(q));
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}) {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f));
}
/**
* Get locally stored data for the given hash.
*/
std::vector<Sp<Value>> getLocal(const InfoHash& key, const Value::Filter& f = {}) const override;
std::vector<std::shared_ptr<Value>> getLocal(const InfoHash& key, Value::Filter f = Value::AllFilter()) const;
/**
* Get locally stored data for the given key and value id.
*/
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const override;
std::shared_ptr<Value> getLocalById(const InfoHash& key, Value::Id vid) const;
/**
* Announce a value on all available protocols (IPv4, IPv6).
*
* Announce a value on all available protocols (IPv4, IPv6), and
* automatically re-announce when it's about to expire.
* The operation will start as soon as the node is connected to the network.
* The done callback will be called once, when the first announce succeeds, or fails.
*
* A "put" operation will never end by itself because the value will need to be
* reannounced on a regular basis.
* User can call #cancelPut(InfoHash, Value::Id) to cancel a put operation.
*/
void put(const InfoHash& key,
Sp<Value>,
std::shared_ptr<Value>,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false) override;
bool permanent = false);
void put(const InfoHash& key,
const Sp<Value>& v,
const std::shared_ptr<Value>& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false) override
bool permanent = false)
{
put(key, v, bindDoneCb(cb), created, permanent);
}
@@ -210,7 +185,7 @@ public:
Value&& v,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false) override
bool permanent = false)
{
put(key, std::make_shared<Value>(std::move(v)), cb, created, permanent);
}
@@ -218,7 +193,7 @@ public:
Value&& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false) override
bool permanent = false)
{
put(key, std::forward<Value>(v), bindDoneCb(cb), created, permanent);
}
@@ -226,18 +201,18 @@ public:
/**
* Get data currently being put at the given hash.
*/
std::vector<Sp<Value>> getPut(const InfoHash&) const override;
std::vector<std::shared_ptr<Value>> getPut(const InfoHash&);
/**
* Get data currently being put at the given hash with the given id.
*/
Sp<Value> getPut(const InfoHash&, const Value::Id&) const override;
std::shared_ptr<Value> getPut(const InfoHash&, const Value::Id&);
/**
* Stop any put/announce operation at the given location,
* for the value with the given id.
*/
bool cancelPut(const InfoHash&, const Value::Id&) override;
bool cancelPut(const InfoHash&, const Value::Id&);
/**
* Listen on the network for any changes involving a specified hash.
@@ -246,63 +221,44 @@ public:
*
* @return a token to cancel the listener later.
*/
size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where={}) override;
size_t listen(const InfoHash& key, GetCallback cb, Value::Filter f={}, Where w={}) override {
return listen(key, [cb](const std::vector<Sp<Value>>& vals, bool expired){
if (not expired)
return cb(vals);
return true;
}, std::forward<Value::Filter>(f), std::forward<Where>(w));
}
size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) override {
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter&&={});
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}) {
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f));
}
bool cancelListen(const InfoHash&, size_t token) override;
virtual bool cancelListen(const InfoHash&, size_t token);
/**
* Inform the DHT of lower-layer connectivity changes.
* This will cause the DHT to assume a public IP address change.
* The DHT will recontact neighbor nodes, re-register for listen ops etc.
*/
void connectivityChanged(sa_family_t) override;
void connectivityChanged() override {
reported_addr.clear();
connectivityChanged(AF_INET);
connectivityChanged(AF_INET6);
}
void connectivityChanged();
/**
* Get the list of good nodes for local storage saving purposes
* The list is ordered to minimize the back-to-work delay.
*/
std::vector<NodeExport> exportNodes() const override;
std::vector<NodeExport> exportNodes();
std::vector<ValuesExport> exportValues() const override;
void importValues(const std::vector<ValuesExport>&) override;
std::vector<ValuesExport> exportValues() const;
void importValues(const std::vector<ValuesExport>&);
void saveState(const std::string& path) const;
void loadState(const std::string& path);
int getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return,
unsigned *incoming_return) const;
std::string getStorageLog() const;
std::string getRoutingTablesLog(sa_family_t) const;
std::string getSearchesLog(sa_family_t) const;
NodeStats getNodesStats(sa_family_t af) const override;
std::string getStorageLog() const override;
std::string getStorageLog(const InfoHash&) const override;
std::string getRoutingTablesLog(sa_family_t) const override;
std::string getSearchesLog(sa_family_t) const override;
std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const override;
void dumpTables() const override;
std::vector<unsigned> getNodeMessageStats(bool in = false) override {
void dumpTables() const;
std::vector<unsigned> getNodeMessageStats(bool in = false) {
return network_engine.getNodeMessageStats(in);
}
/**
* Set the in-memory storage limit in bytes
*/
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override {
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) {
max_store_size = limit;
}
@@ -310,14 +266,14 @@ public:
* Returns the total memory usage of stored values and the number
* of stored values.
*/
std::pair<size_t, size_t> getStoreSize() const override {
std::pair<size_t, size_t> getStoreSize() const {
return {total_store_size, total_values};
}
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override;
std::vector<Address> getPublicAddress(sa_family_t family = 0);
void pushNotificationReceived(const std::map<std::string, std::string>&) override {}
void resubscribe(unsigned) {}
protected:
Logger DHT_LOG;
private:
@@ -326,27 +282,20 @@ private:
the target 8 turn out to be dead. */
static constexpr unsigned SEARCH_NODES {14};
/* The number of bad nodes is limited in order to help determine
* presence of connectivity changes. See
* https://github.com/savoirfairelinux/opendht/issues/137 for details.
*
* According to the tables, 25 is a good average value for big networks. If
* the network is small, normal search expiration process will handle the
* situation.
* */
static constexpr unsigned SEARCH_MAX_BAD_NODES {25};
/* Concurrent search nodes requested count */
static constexpr unsigned MAX_REQUESTED_SEARCH_NODES {4};
/* Concurrent requests during a search */
static constexpr unsigned SEARCH_REQUESTS {4};
/* Number of listening nodes */
static constexpr unsigned LISTEN_NODES {4};
/* The maximum number of values we store for a given hash. */
static constexpr unsigned MAX_VALUES {1024};
/* The maximum number of hashes we're willing to track. */
static constexpr unsigned MAX_HASHES {1024 * 1024};
static constexpr unsigned MAX_HASHES {16384};
/* The maximum number of searches we keep data about. */
static constexpr unsigned MAX_SEARCHES {1024 * 1024};
static constexpr unsigned MAX_SEARCHES {2048};
static constexpr std::chrono::minutes MAX_STORAGE_MAINTENANCE_EXPIRE_TIME {10};
@@ -354,269 +303,220 @@ private:
static constexpr std::chrono::minutes SEARCH_EXPIRE_TIME {62};
/* Timeout for listen */
static constexpr duration LISTEN_EXPIRE_TIME {std::chrono::seconds(30)};
static constexpr duration LISTEN_EXPIRE_TIME_PUBLIC {std::chrono::minutes(5)};
static constexpr std::chrono::seconds LISTEN_EXPIRE_TIME {30};
static constexpr duration REANNOUNCE_MARGIN {std::chrono::seconds(10)};
static constexpr std::chrono::seconds REANNOUNCE_MARGIN {5};
static constexpr size_t TOKEN_SIZE {32};
static constexpr size_t TOKEN_SIZE {64};
// internal structures
struct SearchNode;
struct Get;
struct Announce;
/**
* A single "get" operation data
*/
struct Get {
time_point start;
Value::Filter filter;
GetCallback get_cb;
DoneCallback done_cb;
};
/**
* A single "put" operation data
*/
struct Announce {
bool permanent;
std::shared_ptr<Value> value;
time_point created;
DoneCallback callback;
};
/**
* A single "listen" operation data
*/
struct LocalListener {
Value::Filter filter;
GetCallback get_cb;
};
/**
* A search is a list of the nodes we think are responsible
* for storing values for a given hash.
*/
struct Search;
struct ValueStorage {
std::shared_ptr<Value> data {};
time_point time {};
ValueStorage() {}
ValueStorage(const std::shared_ptr<Value>& v, time_point t) : data(v), time(t) {}
};
/**
* Foreign nodes asking for updates about an InfoHash.
*/
struct Listener {
size_t rid {};
time_point time {};
/*constexpr*/ Listener(size_t rid, time_point t) : rid(rid), time(t) {}
void refresh(size_t tid, time_point t) {
rid = tid;
time = t;
}
};
struct Storage;
// prevent copy
Dht(const Dht&) = delete;
Dht& operator=(const Dht&) = delete;
InfoHash myid {};
uint64_t secret {};
uint64_t oldsecret {};
std::array<uint8_t, 8> secret {{}};
std::array<uint8_t, 8> oldsecret {{}};
// registred types
TypeStore types;
using SearchMap = std::map<InfoHash, Sp<Search>>;
struct Kad {
RoutingTable buckets {};
SearchMap searches {};
unsigned pending_pings {0};
NodeStatus status;
NodeStatus getStatus(time_point now) const;
NodeStats getNodesStats(time_point now, const InfoHash& myid) const;
};
Kad dht4 {};
Kad dht6 {};
std::vector<std::pair<std::string,std::string>> bootstrap_nodes {};
std::chrono::steady_clock::duration bootstrap_period {std::chrono::seconds(10)};
Sp<Scheduler::Job> bootstrapJob {};
std::map<InfoHash, Storage> store;
std::map<SockAddr, StorageBucket, SockAddr::ipCmp> store_quota;
size_t total_values {0};
size_t total_store_size {0};
size_t max_store_keys {MAX_HASHES};
size_t max_store_size {DEFAULT_STORAGE_LIMIT};
size_t max_searches {MAX_SEARCHES};
size_t search_id {0};
// map a global listen token to IPv4, IPv6 specific listen tokens.
// 0 is the invalid token.
std::map<size_t, std::tuple<size_t, size_t, size_t>> listeners {};
size_t listener_token {1};
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
// timing
Scheduler scheduler;
Sp<Scheduler::Job> nextNodesConfirmation {};
Sp<Scheduler::Job> nextStorageMaintenance {};
net::NetworkEngine network_engine;
using ReportedAddr = std::pair<unsigned, SockAddr>;
std::vector<ReportedAddr> reported_addr;
std::string persistPath;
std::map<ValueType::Id, ValueType> types;
// are we a bootstrap node ?
// note: Any running node can be used as a bootstrap node.
// Only nodes running only as bootstrap nodes should
// be put in bootstrap mode.
const bool is_bootstrap {false};
const bool maintain_storage {false};
const bool public_stable {false};
inline const duration& getListenExpiration() const {
return public_stable ? LISTEN_EXPIRE_TIME_PUBLIC : LISTEN_EXPIRE_TIME;
}
// the stuff
RoutingTable buckets {};
RoutingTable buckets6 {};
std::vector<Storage> store;
size_t total_values {0};
size_t total_store_size {0};
size_t max_store_size {DEFAULT_STORAGE_LIMIT};
std::map<InfoHash, std::shared_ptr<Search>> searches4 {};
std::map<InfoHash, std::shared_ptr<Search>> searches6 {};
uint16_t search_id {0};
// map a global listen token to IPv4, IPv6 specific listen tokens.
// 0 is the invalid token.
std::map<size_t, std::tuple<size_t, size_t, size_t>> listeners {};
size_t listener_token {1};
// timing
Scheduler scheduler {};
std::shared_ptr<Scheduler::Job> nextNodesConfirmation {};
time_point mybucket_grow_time {time_point::min()}, mybucket6_grow_time {time_point::min()};
NetworkEngine network_engine;
using ReportedAddr = std::pair<unsigned, Address>;
std::vector<ReportedAddr> reported_addr;
void rotateSecrets();
Blob makeToken(const SockAddr&, bool old) const;
bool tokenMatch(const Blob& token, const SockAddr&) const;
Blob makeToken(const sockaddr *sa, bool old) const;
bool tokenMatch(const Blob& token, const sockaddr *sa) const;
void reportedAddr(const SockAddr&);
void reportedAddr(const sockaddr *sa, socklen_t sa_len);
// Storage
void storageAddListener(const InfoHash& id, const Sp<Node>& node, size_t tid, Query&& = {});
bool storageStore(const InfoHash& id, const Sp<Value>& value, time_point created, const SockAddr& sa = {}, bool permanent = false);
bool storageErase(const InfoHash& id, Value::Id vid);
bool storageRefresh(const InfoHash& id, Value::Id vid);
void expireStore();
void expireStorage(InfoHash h);
void expireStore(decltype(store)::iterator);
decltype(Dht::store)::iterator findStorage(const InfoHash& id);
decltype(Dht::store)::const_iterator findStorage(const InfoHash& id) const;
void storageChanged(const InfoHash& id, Storage& st, ValueStorage&, bool newValue);
std::string printStorageLog(const decltype(store)::value_type&) const;
void storageAddListener(const InfoHash& id, const std::shared_ptr<Node>& node, size_t tid);
bool storageStore(const InfoHash& id, const std::shared_ptr<Value>& value, time_point created);
void expireStorage();
void storageChanged(Storage& st, ValueStorage&);
/**
* For a given storage, if values don't belong there anymore because this
* node is too far from the target, values are sent to the appropriate
* nodes.
*/
void dataPersistence(InfoHash id);
size_t maintainStorage(decltype(store)::value_type&, bool force=false, const DoneCallback& donecb={});
void dataPersistence();
size_t maintainStorage(InfoHash id, bool force=false, DoneCallback donecb=nullptr);
// Buckets
Kad& dht(sa_family_t af) { return af == AF_INET ? dht4 : dht6; }
const Kad& dht(sa_family_t af) const { return af == AF_INET ? dht4 : dht6; }
RoutingTable& buckets(sa_family_t af) { return dht(af).buckets; }
const RoutingTable& buckets(sa_family_t af) const { return dht(af).buckets; }
Bucket* findBucket(const InfoHash& id, sa_family_t af) {
auto& b = buckets(af);
auto it = b.findBucket(id);
return it == b.end() ? nullptr : &(*it);
RoutingTable::iterator b;
switch (af) {
case AF_INET:
b = buckets.findBucket(id);
return b == buckets.end() ? nullptr : &(*b);
case AF_INET6:
b = buckets6.findBucket(id);
return b == buckets6.end() ? nullptr : &(*b);
default:
return nullptr;
}
}
const Bucket* findBucket(const InfoHash& id, sa_family_t af) const {
return const_cast<Dht*>(this)->findBucket(id, af);
}
void expireBuckets(RoutingTable&);
void sendCachedPing(Bucket& b);
int sendCachedPing(Bucket& b);
bool bucketMaintenance(RoutingTable&);
void dumpBucket(const Bucket& b, std::ostream& out) const;
// Nodes
void onNewNode(const Sp<Node>& node, int confirm);
const Sp<Node> findNode(const InfoHash& id, sa_family_t af) const;
bool trySearchInsert(const Sp<Node>& node);
void onNewNode(const std::shared_ptr<Node>& node, int confirm);
std::shared_ptr<Node> findNode(const InfoHash& id, sa_family_t af);
const std::shared_ptr<Node> findNode(const InfoHash& id, sa_family_t af) const;
bool trySearchInsert(const std::shared_ptr<Node>& node);
// Searches
inline SearchMap& searches(sa_family_t af) { return dht(af).searches; }
inline const SearchMap& searches(sa_family_t af) const { return dht(af).searches; }
/**
* Low-level method that will perform a search on the DHT for the specified
* infohash (id), using the specified IP version (IPv4 or IPv6).
* Low-level method that will perform a search on the DHT for the
* specified infohash (id), using the specified IP version (IPv4 or IPv6).
* The values can be filtered by an arbitrary provided filter.
*/
Sp<Search> search(const InfoHash& id, sa_family_t af, GetCallback = {}, QueryCallback = {}, DoneCallback = {}, Value::Filter = {}, const Sp<Query>& q = {});
std::shared_ptr<Search> search(const InfoHash& id, sa_family_t af, GetCallback = nullptr, DoneCallback = nullptr, Value::Filter = Value::AllFilter());
void announce(const InfoHash& id, sa_family_t af, std::shared_ptr<Value> value, DoneCallback callback, time_point created=time_point::max(), bool permanent = false);
size_t listenTo(const InfoHash& id, sa_family_t af, GetCallback cb, Value::Filter f = Value::AllFilter());
void announce(const InfoHash& id, sa_family_t af, Sp<Value> value, DoneCallback callback, time_point created=time_point::max(), bool permanent = false);
size_t listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filter f = {}, const Sp<Query>& q = {});
/**
* Refill the search with good nodes if possible.
*
* @param sr The search to refill.
*
* @return the number inserted nodes.
*/
unsigned refill(Search& sr);
void bootstrapSearch(Search& sr);
Search *findSearch(unsigned short tid, sa_family_t af);
void expireSearches();
void confirmNodes();
void expire();
void onDisconnected();
/**
* Generic function to execute when a 'get' request has completed.
*
* @param status The request passed by the network engine.
* @param answer The answer from the network engine.
* @param ws A weak pointer to the search concerned by the request.
* @param query The query sent to the node.
*/
void searchNodeGetDone(const net::Request& status,
net::RequestAnswer&& answer,
std::weak_ptr<Search> ws,
Sp<Query> query);
/**
* Generic function to execute when a 'get' request expires.
*
* @param status The request passed by the network engine.
* @param over Whether we're done to try sending the request to the node
* or not. This lets us mark a node as candidate.
* @param ws A weak pointer to the search concerned by the request.
* @param query The query sent to the node.
*/
void searchNodeGetExpired(const net::Request& status, bool over, std::weak_ptr<Search> ws, Sp<Query> query);
/**
* This method recovers sends individual request for values per id.
*
* @param ws A weak pointer to the Search.
* @param query The initial query passed through the API.
* @param n The node to which send the requests.
*/
void paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n);
/**
* If update is true, this method will also send message to synced but non-updated search nodes.
*/
SearchNode* searchSendGetValues(Sp<Search> sr, SearchNode *n = nullptr, bool update = true);
/**
* Forwards an 'announce' request for a list of nodes to the network engine.
*
* @param sr The search for which we want to announce a value.
* @param announce The 'announce' structure.
*/
void searchSendAnnounceValue(const Sp<Search>& sr);
/**
* Main process of a Search's operations. This function will demand the
* network engine to send requests packets for all pending operations
* ('get', 'put' and 'listen').
*
* @param sr The search to execute its operations.
*/
void searchStep(Sp<Search>);
void searchSynchedNodeListen(const Sp<Search>&, SearchNode&);
SearchNode* searchSendGetValues(std::shared_ptr<Search> sr, SearchNode *n = nullptr, bool update = true);
void searchStep(std::shared_ptr<Search> sr);
void dumpSearch(const Search& sr, std::ostream& out) const;
bool neighbourhoodMaintenance(RoutingTable&);
void onError(Sp<net::Request> node, net::DhtProtocolException e);
void processMessage(const uint8_t *buf, size_t buflen, const sockaddr *from, socklen_t fromlen);
void onError(std::shared_ptr<Request> node, DhtProtocolException e);
/* when our address is reported by a distant peer. */
void onReportedAddr(const InfoHash& id, const SockAddr&);
void onReportedAddr(const InfoHash& id, sockaddr* sa , socklen_t salen);
/* when we receive a ping request */
net::RequestAnswer onPing(Sp<Node> node);
NetworkEngine::RequestAnswer onPing(std::shared_ptr<Node> node);
/* when we receive a "find node" request */
net::RequestAnswer onFindNode(Sp<Node> node, const InfoHash& hash, want_t want);
void onFindNodeDone(const Sp<Node>& status,
net::RequestAnswer& a,
Sp<Search> sr);
NetworkEngine::RequestAnswer onFindNode(std::shared_ptr<Node> node, InfoHash& hash, want_t want);
void onFindNodeDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search> sr);
/* when we receive a "get values" request */
net::RequestAnswer onGetValues(Sp<Node> node,
const InfoHash& hash,
want_t want,
const Query& q);
void onGetValuesDone(const Sp<Node>& status,
net::RequestAnswer& a,
Sp<Search>& sr,
const Sp<Query>& orig_query);
NetworkEngine::RequestAnswer onGetValues(std::shared_ptr<Node> node, InfoHash& hash, want_t want);
void onGetValuesDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search> sr);
/* when we receive a listen request */
net::RequestAnswer onListen(Sp<Node> node,
const InfoHash& hash,
const Blob& token,
size_t socket_id,
const Query& query);
void onListenDone(const Sp<Node>& status,
net::RequestAnswer& a,
Sp<Search>& sr);
NetworkEngine::RequestAnswer onListen(std::shared_ptr<Node> node, InfoHash& hash, Blob& token, size_t rid);
void onListenDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search>& sr);
/* when we receive an announce request */
net::RequestAnswer onAnnounce(Sp<Node> node,
const InfoHash& hash,
const Blob& token,
const std::vector<Sp<Value>>& v,
const time_point& created);
net::RequestAnswer onRefresh(Sp<Node> node,
const InfoHash& hash,
const Blob& token,
const Value::Id& vid);
void onAnnounceDone(const Sp<Node>& status,
net::RequestAnswer& a,
Sp<Search>& sr);
NetworkEngine::RequestAnswer onAnnounce(std::shared_ptr<Node> node,
InfoHash& hash, Blob& token, std::vector<std::shared_ptr<Value>> v, time_point created);
void onAnnounceDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search>& sr);
};
}
-269
View File
@@ -1,269 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "infohash.h"
#include "log_enable.h"
namespace dht {
namespace net {
class DatagramSocket;
}
class OPENDHT_PUBLIC DhtInterface {
public:
DhtInterface() = default;
DhtInterface(const Logger& l) : logger_(std::make_shared<Logger>(l)) {};
DhtInterface(const std::shared_ptr<Logger>& l) : logger_(l) {};
virtual ~DhtInterface() = default;
// [[deprecated]]
using Status = NodeStatus;
// [[deprecated]]
using NodeExport = dht::NodeExport;
/**
* Get the current status of the node for the given family.
*/
virtual NodeStatus updateStatus(sa_family_t af) { return getStatus(af); };
virtual NodeStatus getStatus(sa_family_t af) const = 0;
virtual NodeStatus getStatus() const = 0;
virtual net::DatagramSocket* getSocket() const { return {}; };
/**
* Get the ID of the DHT node.
*/
virtual const InfoHash& getNodeId() const = 0;
/**
* Performs final operations before quitting.
*/
virtual void shutdown(ShutdownCallback cb) = 0;
/**
* Returns true if the node is running (have access to an open socket).
*
* af: address family. If non-zero, will return true if the node
* is running for the provided family.
*/
virtual bool isRunning(sa_family_t af = 0) const = 0;
virtual void registerType(const ValueType& type) = 0;
virtual const ValueType& getType(ValueType::Id type_id) const = 0;
virtual void addBootstrap(const std::string& /*host*/, const std::string& /*service*/) {};
virtual void clearBootstrap() {};
/**
* Insert a node in the main routing table.
* The node is not pinged, so this should be
* used to bootstrap efficiently from previously known nodes.
*/
virtual void insertNode(const InfoHash& id, const SockAddr&) = 0;
virtual void insertNode(const NodeExport& n) = 0;
virtual void pingNode(SockAddr, DoneCallbackSimple&& cb={}) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, SockAddr, const time_point& now) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) = 0;
/**
* Get a value by searching on all available protocols (IPv4, IPv6),
* and call the provided get callback when values are found at key.
* The operation will start as soon as the node is connected to the network.
* @param cb a function called when new values are found on the network.
* It should return false to stop the operation.
* @param donecb a function called when the operation is complete.
cb and donecb won't be called again afterward.
* @param f a filter function used to prefilter values.
*/
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) = 0;
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) = 0;
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) = 0;
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) = 0;
/**
* Similar to Dht::get, but sends a Query to filter data remotely.
* @param key the key for which to query data for.
* @param cb a function called when new values are found on the network.
* It should return false to stop the operation.
* @param done_cb a function called when the operation is complete.
cb and done_cb won't be called again afterward.
* @param q a query used to filter values on the remotes before they send a
* response.
*/
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {}) = 0;
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) = 0;
/**
* Get locally stored data for the given hash.
*/
virtual std::vector<Sp<Value>> getLocal(const InfoHash& key, const Value::Filter& f = {}) const = 0;
/**
* Get locally stored data for the given key and value id.
*/
virtual Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const = 0;
/**
* Announce a value on all available protocols (IPv4, IPv6).
*
* The operation will start as soon as the node is connected to the network.
* The done callback will be called once, when the first announce succeeds, or fails.
*/
virtual void put(const InfoHash& key,
Sp<Value>,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false) = 0;
virtual void put(const InfoHash& key,
const Sp<Value>& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false) = 0;
virtual void put(const InfoHash& key,
Value&& v,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false) = 0;
virtual void put(const InfoHash& key,
Value&& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false) = 0;
/**
* Get data currently being put at the given hash.
*/
virtual std::vector<Sp<Value>> getPut(const InfoHash&) const = 0;
/**
* Get data currently being put at the given hash with the given id.
*/
virtual Sp<Value> getPut(const InfoHash&, const Value::Id&) const = 0;
/**
* Stop any put/announce operation at the given location,
* for the value with the given id.
*/
virtual bool cancelPut(const InfoHash&, const Value::Id&) = 0;
/**
* Listen on the network for any changes involving a specified hash.
* The node will register to receive updates from relevent nodes when
* new values are added or removed.
*
* @return a token to cancel the listener later.
*/
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter={}, Where w = {}) = 0;
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w = {}) = 0;
virtual size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where w = {}) = 0;
virtual bool cancelListen(const InfoHash&, size_t token) = 0;
/**
* Inform the DHT of lower-layer connectivity changes.
* This will cause the DHT to assume a public IP address change.
* The DHT will recontact neighbor nodes, re-register for listen ops etc.
*/
virtual void connectivityChanged(sa_family_t) = 0;
virtual void connectivityChanged() = 0;
/**
* Get the list of good nodes for local storage saving purposes
* The list is ordered to minimize the back-to-work delay.
*/
virtual std::vector<NodeExport> exportNodes() const = 0;
virtual std::vector<ValuesExport> exportValues() const = 0;
virtual void importValues(const std::vector<ValuesExport>&) = 0;
virtual NodeStats getNodesStats(sa_family_t af) const = 0;
virtual std::string getStorageLog() const = 0;
virtual std::string getStorageLog(const InfoHash&) const = 0;
virtual std::string getRoutingTablesLog(sa_family_t) const = 0;
virtual std::string getSearchesLog(sa_family_t) const = 0;
virtual std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const = 0;
virtual void dumpTables() const = 0;
virtual std::vector<unsigned> getNodeMessageStats(bool in = false) = 0;
/**
* Set the in-memory storage limit in bytes
*/
virtual void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) = 0;
/**
* Returns the total memory usage of stored values and the number
* of stored values.
*/
virtual std::pair<size_t, size_t> getStoreSize() const = 0;
virtual std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) = 0;
/**
* Enable or disable logging of DHT internal messages
*/
virtual void setLoggers(LogMethod error = {}, LogMethod warn = {}, LogMethod debug = {}) {
if (logger_) {
logger_->DBG = std::move(debug);
logger_->WARN = std::move(warn);
logger_->ERR = std::move(error);
} else
logger_= std::make_shared<Logger>(std::move(error), std::move(warn), std::move(debug));
}
virtual void setLogger(const Logger& l) {
if (logger_)
*logger_ = l;
else
logger_= std::make_shared<Logger>(l);
}
virtual void setLogger(const std::shared_ptr<Logger>& l) {
logger_ = l;
}
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
virtual void setLogFilter(const InfoHash& f)
{
if (logger_)
logger_->setFilter(f);
}
virtual void setPushNotificationToken(const std::string&) {};
/**
* Call linked callback with a push notification
* @param notification to process
*/
virtual void pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
protected:
std::shared_ptr<Logger> logger_ {};
};
} // namespace dht
-415
View File
@@ -1,415 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <functional>
#include <mutex>
#include "callbacks.h"
#include "def.h"
#include "dht_interface.h"
#include "proxy.h"
#include "http.h"
#include <restinio/all.hpp>
#include <json/json.h>
#include <chrono>
#include <vector>
#include <functional>
namespace Json {
class Value;
}
namespace http {
class Resolver;
class Request;
}
namespace dht {
class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface {
public:
DhtProxyClient();
explicit DhtProxyClient(
std::shared_ptr<crypto::Certificate> serverCA, crypto::Identity clientIdentity,
std::function<void()> loopSignal, const std::string& serverHost,
const std::string& pushClientId = "", std::shared_ptr<Logger> logger = {});
void setHeaderFields(http::Request& request);
virtual void setPushNotificationToken(const std::string& token) override {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
deviceKey_ = token;
#else
(void) token;
#endif
}
virtual ~DhtProxyClient();
/**
* Get the ID of the node.
*/
inline const InfoHash& getNodeId() const override { return myid; }
/**
* Get the current status of the node for the given family.
*/
NodeStatus getStatus(sa_family_t af) const override;
NodeStatus getStatus() const override {
return std::max(getStatus(AF_INET), getStatus(AF_INET6));
}
/**
* Performs final operations before quitting.
*/
void shutdown(ShutdownCallback cb) override;
/**
* Returns true if the node is running (have access to an open socket).
*
* af: address family. If non-zero, will return true if the node
* is running for the provided family.
*/
bool isRunning(sa_family_t af = 0) const override;
/**
* Get a value by asking the proxy and call the provided get callback when
* values are found at key.
* The operation will start as soon as the node is connected to the network.
* @param cb a function called when new values are found on the network.
* It should return false to stop the operation.
* @param donecb a function called when the operation is complete.
cb and donecb won't be called again afterward.
* @param f a filter function used to prefilter values.
*/
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override;
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
/**
* Announce a value on all available protocols (IPv4, IPv6).
*
* The operation will start as soon as the node is connected to the network.
* The done callback will be called once, when the first announce succeeds, or fails.
* NOTE: For now, created parameter is ignored.
*/
void put(const InfoHash& key,
Sp<Value>,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false) override;
void put(const InfoHash& key,
const Sp<Value>& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false) override
{
put(key, v, bindDoneCb(cb), created, permanent);
}
void put(const InfoHash& key,
Value&& v,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false) override
{
put(key, std::make_shared<Value>(std::move(v)), cb, created, permanent);
}
void put(const InfoHash& key,
Value&& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false) override
{
put(key, std::forward<Value>(v), bindDoneCb(cb), created, permanent);
}
/**
* @param af the socket family
* @return node stats from the proxy
*/
NodeStats getNodesStats(sa_family_t af) const override;
/**
* @param family the socket family
* @return public address
*/
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override;
/**
* Listen on the network for any changes involving a specified hash.
* The node will register to receive updates from relevent nodes when
* new values are added or removed.
*
* @return a token to cancel the listener later.
*/
virtual size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where={}) override;
virtual size_t listen(const InfoHash& key, GetCallback cb, Value::Filter f={}, Where w={}) override {
return listen(key, [cb](const std::vector<Sp<Value>>& vals, bool expired){
if (not expired)
return cb(vals);
return true;
}, std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) override {
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
/*
* This function relies on the cache implementation.
* It means that there are no true cancel here, it keeps the caching in higher priority.
*/
virtual bool cancelListen(const InfoHash& key, size_t token) override;
/**
* Call linked callback with a push notification
* @param notification to process
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override;
time_point periodic(const uint8_t*, size_t, SockAddr, const time_point& now) override;
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
return periodic(buf, buflen, SockAddr(from, fromlen), now);
}
/**
* Similar to Dht::get, but sends a Query to filter data remotely.
* @param key the key for which to query data for.
* @param cb a function called when new values are found on the network.
* It should return false to stop the operation.
* @param done_cb a function called when the operation is complete.
cb and done_cb won't be called again afterward.
* @param q a query used to filter values on the remotes before they send a
* response.
*/
virtual void query(const InfoHash& /*key*/, QueryCallback /*cb*/, DoneCallback /*done_cb*/ = {}, Query&& /*q*/ = {}) override { }
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override {
query(key, cb, bindDoneCb(done_cb), std::forward<Query>(q));
}
/**
* Get data currently being put at the given hash.
*/
std::vector<Sp<Value>> getPut(const InfoHash&) const override;
/**
* Get data currently being put at the given hash with the given id.
*/
Sp<Value> getPut(const InfoHash&, const Value::Id&) const override;
/**
* Stop any put/announce operation at the given location,
* for the value with the given id.
*/
bool cancelPut(const InfoHash&, const Value::Id&) override;
void pingNode(SockAddr, DoneCallbackSimple&& /*cb*/={}) override { }
virtual void registerType(const ValueType& type) override {
types.registerType(type);
}
const ValueType& getType(ValueType::Id type_id) const override {
return types.getType(type_id);
}
std::vector<Sp<Value>> getLocal(const InfoHash& k, const Value::Filter& filter) const override;
Sp<Value> getLocalById(const InfoHash& k, Value::Id id) const override;
/**
* NOTE: The following methods will not be implemented because the
* DhtProxyClient doesn't have any storage nor synchronization process
*/
void insertNode(const InfoHash&, const SockAddr&) override { }
void insertNode(const NodeExport&) override { }
std::pair<size_t, size_t> getStoreSize() const override { return {}; }
std::vector<NodeExport> exportNodes() const override { return {}; }
std::vector<ValuesExport> exportValues() const override { return {}; }
void importValues(const std::vector<ValuesExport>&) override {}
std::string getStorageLog() const override { return {}; }
std::string getStorageLog(const InfoHash&) const override { return {}; }
std::string getRoutingTablesLog(sa_family_t) const override { return {}; }
std::string getSearchesLog(sa_family_t) const override { return {}; }
std::string getSearchLog(const InfoHash&, sa_family_t) const override { return {}; }
void dumpTables() const override {}
std::vector<unsigned> getNodeMessageStats(bool) override { return {}; }
void setStorageLimit(size_t) override {}
void connectivityChanged(sa_family_t) override {
restartListeners();
}
void connectivityChanged() override {
getProxyInfos();
restartListeners();
loopSignal_();
}
private:
/**
* Start the connection with a server.
*/
void startProxy();
void stop();
/**
* Get informations from the proxy node
* @return the JSON returned by the proxy
*/
struct InfoState;
void getProxyInfos();
void queryProxyInfo(const std::shared_ptr<InfoState>& infoState, const std::shared_ptr<http::Resolver>& resolver, sa_family_t family);
void onProxyInfos(const Json::Value& val, const sa_family_t family);
SockAddr parsePublicAddress(const Json::Value& val);
void opFailed();
void handleExpireListener(const asio::error_code &ec, const InfoHash& key);
struct Listener;
struct OperationState;
enum class ListenMethod {
LISTEN,
SUBSCRIBE,
RESUBSCRIBE,
};
using CacheValueCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values, bool expired, system_clock::time_point)>;
/**
* Send Listen with httpClient_
*/
void sendListen(const restinio::http_request_header_t& header, const CacheValueCallback& cb,
const Sp<OperationState>& opstate, Listener& listener, ListenMethod method = ListenMethod::LISTEN);
void handleResubscribe(const asio::error_code& ec, const InfoHash& key,
const size_t token, std::shared_ptr<OperationState> opstate);
void doPut(const InfoHash&, Sp<Value>, DoneCallbackSimple, time_point created, bool permanent);
void handleRefreshPut(const asio::error_code& ec, InfoHash key, Value::Id id);
/**
* Initialize statusIpvX_
*/
void getConnectivityStatus();
/**
* cancel all Listeners
*/
void cancelAllListeners();
std::atomic_bool isDestroying_ {false};
std::string proxyUrl_;
dht::crypto::Identity clientIdentity_;
std::shared_ptr<dht::crypto::Certificate> serverCertificate_;
//std::pair<std::string, std::string> serverHostService_;
std::string pushClientId_;
std::string pushSessionId_;
mutable std::mutex lockCurrentProxyInfos_;
NodeStatus statusIpv4_ {NodeStatus::Disconnected};
NodeStatus statusIpv6_ {NodeStatus::Disconnected};
NodeStats stats4_ {};
NodeStats stats6_ {};
SockAddr publicAddressV4_;
SockAddr publicAddressV6_;
InfoHash myid {};
// registred types
TypeStore types;
/*
* ASIO I/O Context for sockets in httpClient_
* Note: Each context is used in one thread only
*/
asio::io_context httpContext_;
std::shared_ptr<http::Resolver> resolver_;
mutable std::mutex requestLock_;
std::map<unsigned, std::shared_ptr<http::Request>> requests_;
/*
* Thread for executing the http io_context.run() blocking call
*/
std::thread httpClientThread_;
/**
* Store listen requests.
*/
struct ProxySearch;
mutable std::mutex searchLock_;
size_t listenerToken_ {0};
std::map<InfoHash, ProxySearch> searches_;
/**
* Callbacks should be executed in the main thread.
*/
std::mutex lockCallbacks_;
std::vector<std::function<void()>> callbacks_;
Sp<InfoState> infoState_;
/**
* Retrieve if we can connect to the proxy (update statusIpvX_)
*/
void handleProxyConfirm(const asio::error_code &ec);
Sp<asio::steady_timer> nextProxyConfirmationTimer_;
Sp<asio::steady_timer> listenerRestartTimer_;
/**
* Relaunch LISTEN requests if the client disconnect/reconnect.
*/
void restartListeners();
/**
* Refresh a listen via a token
* @param token
*/
void resubscribe(const InfoHash& key, const size_t token, Listener& listener);
/**
* If we want to use push notifications by default.
* NOTE: empty by default to avoid to use services like FCM or APN.
*/
std::string deviceKey_ {};
const std::function<void()> loopSignal_;
#ifdef OPENDHT_PUSH_NOTIFICATIONS
std::string fillBody(bool resubscribe);
void getPushRequest(Json::Value&) const;
#endif // OPENDHT_PUSH_NOTIFICATIONS
Json::StreamWriterBuilder jsonBuilder_;
std::unique_ptr<Json::CharReader> jsonReader_;
std::shared_ptr<http::Request> buildRequest(const std::string& target = {});
};
}
-385
View File
@@ -1,385 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "callbacks.h"
#include "def.h"
#include "infohash.h"
#include "proxy.h"
#include "scheduler.h"
#include "sockaddr.h"
#include "value.h"
#include "http.h"
#include <restinio/all.hpp>
#include <restinio/tls.hpp>
#include <json/json.h>
#include <memory>
#include <mutex>
namespace http {
class Request;
struct ListenerSession;
}
namespace Json {
class Value;
}
namespace dht {
class DhtRunner;
using RestRouter = restinio::router::express_router_t<>;
using RequestStatus = restinio::request_handling_status_t;
/**
* Describes the REST API
*/
class OPENDHT_PUBLIC DhtProxyServer
{
public:
/**
* Start the Http server for OpenDHT
* @param dht the DhtRunner linked to this proxy server
* @param port to listen
* @param pushServer where to push notifications
* @note if the server fails to start (if port is already used or reserved),
* it will fails silently
*/
DhtProxyServer(
dht::crypto::Identity identity,
std::shared_ptr<DhtRunner> dht, in_port_t port = 8000, const std::string& pushServer = "",
std::shared_ptr<dht::Logger> logger = {});
virtual ~DhtProxyServer();
DhtProxyServer(const DhtProxyServer& other) = delete;
DhtProxyServer(DhtProxyServer&& other) = delete;
DhtProxyServer& operator=(const DhtProxyServer& other) = delete;
DhtProxyServer& operator=(DhtProxyServer&& other) = delete;
asio::io_context& io_context() const;
struct ServerStats {
/** Current number of listen operations */
size_t listenCount {0};
/** Current number of permanent put operations */
size_t putCount {0};
/** Current number of push tokens with at least one listen operation */
size_t pushListenersCount {0};
/** Average requests per second */
double requestRate {0};
/** Node Info **/
std::shared_ptr<NodeInfo> nodeInfo {};
std::string toString() const {
std::ostringstream ss;
ss << "Listens: " << listenCount << " Puts: " << putCount << " PushListeners: " << pushListenersCount << std::endl;
ss << "Requests: " << requestRate << " per second." << std::endl;
if (nodeInfo) {
auto& ipv4 = nodeInfo->ipv4;
if (ipv4.table_depth > 1)
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
auto& ipv6 = nodeInfo->ipv6;
if (ipv6.table_depth > 1)
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
}
return ss.str();
}
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const {
Json::Value result;
result["listenCount"] = static_cast<Json::UInt64>(listenCount);
result["putCount"] = static_cast<Json::UInt64>(putCount);
result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount);
result["requestRate"] = requestRate;
if (nodeInfo)
result["nodeInfo"] = nodeInfo->toJson();
return result;
}
};
std::shared_ptr<ServerStats> stats() const { return stats_; }
std::shared_ptr<ServerStats> updateStats(std::shared_ptr<NodeInfo> info) const;
std::shared_ptr<DhtRunner> getNode() const { return dht_; }
private:
class ConnectionListener;
struct RestRouterTraitsTls;
struct RestRouterTraits;
template <typename HttpResponse>
static HttpResponse initHttpResponse(HttpResponse response);
static restinio::request_handling_status_t serverError(restinio::request_t& request);
template< typename ServerSettings >
void addServerSettings(ServerSettings& serverSettings,
const unsigned int max_pipelined_requests = 16);
std::unique_ptr<RestRouter> createRestRouter();
void onConnectionClosed(restinio::connection_id_t);
/**
* Return the PublicKey id, the node id and node stats
* Method: GET "/"
* Result: HTTP 200, body: Node infos in JSON format
* On error: HTTP 503, body: {"err":"xxxx"}
* @param session
*/
RequestStatus getNodeInfo(restinio::request_handle_t request,
restinio::router::route_params_t params) const;
/**
* Return ServerStats in JSON format
* Method: STATS "/"
* Result: HTTP 200, body: Node infos in JSON format
* @param session
*/
RequestStatus getStats(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Return Values of an infoHash
* Method: GET "/{InfoHash: .*}"
* Return: Multiple JSON object in parts. Example:
* Value in JSON format\n
* Value in JSON format
*
* On error: HTTP 503, body: {"err":"xxxx"}
* @param session
*/
RequestStatus get(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Listen incoming Values of an infoHash.
* Method: LISTEN "/{InfoHash: .*}"
* Return: Multiple JSON object in parts. Example:
* Value in JSON format\n
* Value in JSON format
*
* On error: HTTP 503, body: {"err":"xxxx"}
* @param session
*/
RequestStatus listen(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Put a value on the DHT
* Method: POST "/{InfoHash: .*}"
* body = Value to put in JSON
* Return: HTTP 200 if success and the value put in JSON
* On error: HTTP 503, body: {"err":"xxxx"} if no dht
* HTTP 400, body: {"err":"xxxx"} if bad json or HTTP 502 if put fails
* @param session
*/
RequestStatus put(restinio::request_handle_t request,
restinio::router::route_params_t params);
void handleCancelPermamentPut(const asio::error_code &ec, const InfoHash& key, Value::Id vid);
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
/**
* Put a value to sign by the proxy on the DHT
* Method: SIGN "/{InfoHash: .*}"
* body = Value to put in JSON
* Return: HTTP 200 if success and the value put in JSON
* On error: HTTP 503, body: {"err":"xxxx"} if no dht
* HTTP 400, body: {"err":"xxxx"} if bad json
* @param session
*/
RequestStatus putSigned(restinio::request_handle_t request,
restinio::router::route_params_t params) const;
/**
* Put a value to encrypt by the proxy on the DHT
* Method: ENCRYPT "/{hash: .*}"
* body = Value to put in JSON + "to":"infoHash"
* Return: HTTP 200 if success and the value put in JSON
* On error: HTTP 503, body: {"err":"xxxx"} if no dht
* HTTP 400, body: {"err":"xxxx"} if bad json
* @param session
*/
RequestStatus putEncrypted(restinio::request_handle_t request,
restinio::router::route_params_t params);
#endif // OPENDHT_PROXY_SERVER_IDENTITY
/**
* Return Values of an infoHash filtered by a value id
* Method: GET "/{InfoHash: .*}/{ValueId: .*}"
* Return: Multiple JSON object in parts. Example:
* Value in JSON format\n
* Value in JSON format
*
* On error: HTTP 503, body: {"err":"xxxx"}
* @param session
*/
RequestStatus getFiltered(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Respond allowed Methods
* Method: OPTIONS "/{hash: .*}"
* Return: HTTP 200 + Allow: allowed methods
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
* @param session
*/
RequestStatus options(restinio::request_handle_t request,
restinio::router::route_params_t params);
#ifdef OPENDHT_PUSH_NOTIFICATIONS
/**
* Subscribe to push notifications for an iOS or Android device.
* Method: SUBSCRIBE "/{InfoHash: .*}"
* Body: {"key": "device_key", (optional)"isAndroid":false (default true)}"
* Return: {"token": x}" where x if a token to save
* @note: the listen will timeout after six hours (and send a push notification).
* so you need to refresh the operation each six hours.
* @param session
*/
RequestStatus subscribe(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Unsubscribe to push notifications for an iOS or Android device.
* Method: UNSUBSCRIBE "/{InfoHash: .*}"
* Body: {"key": "device_key", "token": x} where x if the token to cancel
* Return: nothing
* @param session
*/
RequestStatus unsubscribe(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Send a push notification via a gorush push gateway
* @param key of the device
* @param json, the content to send
*/
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid, bool highPriority);
/**
* Send push notification with an expire timeout.
* @param ec
* @param pushToken
* @param json
* @param isAndroid
*/
void handleNotifyPushListenExpire(const asio::error_code &ec, const std::string pushToken,
std::function<Json::Value()> json, const bool isAndroid);
/**
* Remove a push listener between a client and a hash
* @param ec
* @param pushToken
* @param key
* @param clientId
*/
void handleCancelPushListen(const asio::error_code &ec, const std::string pushToken,
const InfoHash key, const std::string clientId);
#endif //OPENDHT_PUSH_NOTIFICATIONS
void handlePrintStats(const asio::error_code &ec);
void updateStats();
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;
std::shared_ptr<asio::io_context> ioContext_;
std::shared_ptr<DhtRunner> dht_;
Json::StreamWriterBuilder jsonBuilder_;
Json::CharReaderBuilder jsonReaderBuilder_;
// http server
std::thread serverThread_;
std::unique_ptr<restinio::http_server_t<RestRouterTraitsTls>> httpsServer_;
std::unique_ptr<restinio::http_server_t<RestRouterTraits>> httpServer_;
// http client
std::pair<std::string, std::string> pushHostPort_;
mutable std::mutex requestLock_;
std::map<unsigned int /*id*/, std::shared_ptr<http::Request>> requests_;
std::shared_ptr<dht::Logger> logger_;
std::shared_ptr<ServerStats> stats_;
std::shared_ptr<NodeInfo> nodeInfo_ {};
std::unique_ptr<asio::steady_timer> printStatsTimer_;
// Thread-safe access to listeners map.
std::mutex lockListener_;
// Shared with connection listener.
std::map<restinio::connection_id_t, http::ListenerSession> listeners_;
// Connection Listener observing conn state changes.
std::shared_ptr<ConnectionListener> connListener_;
struct PushSessionContext {
std::mutex lock;
std::string sessionId;
};
struct PermanentPut {
time_point expiration;
std::string pushToken;
std::string clientId;
std::shared_ptr<PushSessionContext> sessionCtx;
std::unique_ptr<asio::steady_timer> expireTimer;
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
Sp<Value> value;
};
struct SearchPuts {
std::map<dht::Value::Id, PermanentPut> puts;
};
std::mutex lockSearchPuts_;
std::map<InfoHash, SearchPuts> puts_;
mutable std::atomic<size_t> requestNum_ {0};
mutable std::atomic<time_point> lastStatsReset_ {time_point::min()};
std::string pushServer_;
#ifdef OPENDHT_PUSH_NOTIFICATIONS
struct Listener {
std::string clientId;
std::shared_ptr<PushSessionContext> sessionCtx;
std::future<size_t> internalToken;
std::unique_ptr<asio::steady_timer> expireTimer;
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
};
struct PushListener {
std::map<InfoHash, std::vector<Listener>> listeners;
};
std::mutex lockPushListeners_;
std::map<std::string, PushListener> pushListeners_;
proxy::ListenToken tokenPushNotif_ {0};
#endif //OPENDHT_PUSH_NOTIFICATIONS
};
}
+90 -260
View File
@@ -1,8 +1,7 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,18 +14,16 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "def.h"
//#include "securedht.h"
#include "infohash.h"
#include "value.h"
#include "callbacks.h"
#include "sockaddr.h"
#include "log_enable.h"
#include "network_utils.h"
#include <thread>
#include <mutex>
@@ -41,7 +38,6 @@ namespace dht {
struct Node;
class SecureDht;
class PeerDiscovery;
struct SecureDhtConfig;
/**
@@ -50,49 +46,28 @@ struct SecureDhtConfig;
* either wait for (expectedly frequent) calls to ::loop() or start an internal
* thread that will update the DHT when appropriate.
*/
class OPENDHT_PUBLIC DhtRunner {
class DhtRunner {
public:
using StatusCallback = std::function<void(NodeStatus, NodeStatus)>;
struct Config {
SecureDhtConfig dht_config {};
bool threaded {true};
std::string proxy_server {};
std::string push_node_id {};
std::string push_token {};
bool peer_discovery {false};
bool peer_publish {false};
std::shared_ptr<dht::crypto::Certificate> server_ca;
dht::crypto::Identity client_identity;
};
struct Context {
std::shared_ptr<Logger> logger {};
std::unique_ptr<net::DatagramSocket> sock;
std::shared_ptr<PeerDiscovery> peerDiscovery {};
StatusCallback statusChangedCallback {};
CertificateStoreQuery certificateStore {};
Context() {}
};
typedef std::function<void(NodeStatus, NodeStatus)> StatusCallback;
DhtRunner();
virtual ~DhtRunner();
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = {}, Where w = {}) {
get(id, bindGetCb(cb), donecb, f, w);
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = Value::AllFilter()) {
get(id, bindGetCb(cb), donecb, f);
}
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = {}, Where w = {}) {
get(id, bindGetCb(cb), donecb, f, w);
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter()) {
get(id, bindGetCb(cb), donecb, f);
}
void get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f={}, Where w = {});
void get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f={});
void get(InfoHash id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter f = {}, Where w = {}) {
get(id, cb, bindDoneCb(donecb), f, w);
void get(InfoHash id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter()) {
get(id, cb, bindDoneCb(donecb), f);
}
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = {}, Where w = {});
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = Value::AllFilter());
template <class T>
void get(InfoHash hash, std::function<bool(std::vector<T>&&)> cb, DoneCallbackSimple dcb={})
@@ -121,7 +96,7 @@ public:
getFilterSet<T>());
}
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = {}, Where w = {}) {
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = Value::AllFilter()) {
auto p = std::make_shared<std::promise<std::vector<std::shared_ptr< dht::Value >>>>();
auto values = std::make_shared<std::vector<std::shared_ptr< dht::Value >>>();
get(key, [=](const std::vector<std::shared_ptr<dht::Value>>& vlist) {
@@ -130,7 +105,7 @@ public:
}, [=](bool) {
p->set_value(std::move(*values));
},
f, w);
f);
return p->get_future();
}
@@ -147,23 +122,10 @@ public:
return p->get_future();
}
void query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb = {}, Query q = {});
void query(const InfoHash& hash, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query q = {}) {
query(hash, cb, bindDoneCb(done_cb), q);
}
std::future<size_t> listen(InfoHash key, ValueCallback vcb, Value::Filter f = {}, Where w = {});
std::future<size_t> listen(InfoHash key, GetCallback cb, Value::Filter f={}, Where w={}) {
return listen(key, [cb](const std::vector<Sp<Value>>& vals, bool expired){
if (not expired)
return cb(vals);
return true;
}, std::forward<Value::Filter>(f), std::forward<Where>(w));
}
std::future<size_t> listen(const std::string& key, GetCallback vcb, Value::Filter f = {}, Where w = {});
std::future<size_t> listen(InfoHash key, GetCallbackSimple cb, Value::Filter f = {}, Where w = {}) {
return listen(key, bindGetCb(cb), f, w);
std::future<size_t> listen(InfoHash key, GetCallback vcb, Value::Filter f = Value::AllFilter());
std::future<size_t> listen(const std::string& key, GetCallback vcb, Value::Filter f = Value::AllFilter());
std::future<size_t> listen(InfoHash key, GetCallbackSimple cb, Value::Filter f = Value::AllFilter()) {
return listen(key, bindGetCb(cb), f);
}
template <class T>
@@ -174,17 +136,8 @@ public:
},
getFilterSet<T>());
}
template <class T>
std::future<size_t> listen(InfoHash hash, std::function<bool(std::vector<T>&&, bool)> cb)
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals, bool expired) {
return cb(unpackVector<T>(vals), expired);
},
getFilterSet<T>());
}
template <typename T>
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = {}, Where w = {})
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = Value::AllFilter())
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals) {
for (const auto& v : vals) {
@@ -197,97 +150,51 @@ public:
}
return true;
},
getFilterSet<T>(f), w);
}
template <typename T>
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&, bool)> cb, Value::Filter f = {}, Where w = {})
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals, bool expired) {
for (const auto& v : vals) {
try {
if (not cb(Value::unpack<T>(*v), expired))
return false;
} catch (const std::exception&) {
continue;
}
}
return true;
},
getFilterSet<T>(f), w);
getFilterSet<T>(f));
}
void cancelListen(InfoHash h, size_t token);
void cancelListen(InfoHash h, std::shared_future<size_t> token);
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={}, time_point created=time_point::max(), bool permanent = false);
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb, time_point created=time_point::max(), bool permanent = false) {
put(hash, value, bindDoneCb(cb), created, permanent);
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
put(hash, value, bindDoneCb(cb), permanent);
}
void put(InfoHash hash, Value&& value, DoneCallback cb={}, time_point created=time_point::max(), bool permanent = false);
void put(InfoHash hash, Value&& value, DoneCallbackSimple cb, time_point created=time_point::max(), bool permanent = false) {
put(hash, std::forward<Value>(value), bindDoneCb(cb), created, permanent);
void put(InfoHash hash, Value&& value, DoneCallback cb={}, bool permanent = false);
void put(InfoHash hash, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
put(hash, std::forward<Value>(value), bindDoneCb(cb), permanent);
}
void put(const std::string& key, Value&& value, DoneCallbackSimple cb={}, time_point created=time_point::max(), bool permanent = false);
void put(const std::string& key, Value&& value, DoneCallbackSimple cb={}, bool permanent = false);
void cancelPut(const InfoHash& h, Value::Id id);
void cancelPut(const InfoHash& h, const std::shared_ptr<Value>& value);
void cancelPut(const InfoHash& h, const Value::Id& id);
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
putSigned(hash, value, bindDoneCb(cb), permanent);
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={});
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb) {
putSigned(hash, value, bindDoneCb(cb));
}
void putSigned(InfoHash hash, Value&& value, DoneCallback cb={}, bool permanent = false);
void putSigned(InfoHash hash, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
putSigned(hash, std::forward<Value>(value), bindDoneCb(cb), permanent);
void putSigned(InfoHash hash, Value&& value, DoneCallback cb={});
void putSigned(InfoHash hash, Value&& value, DoneCallbackSimple cb) {
putSigned(hash, std::forward<Value>(value), bindDoneCb(cb));
}
void putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb={}, bool permanent = false);
void putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb={});
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, value, bindDoneCb(cb), permanent);
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb={});
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallbackSimple cb) {
putEncrypted(hash, to, value, bindDoneCb(cb));
}
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, std::forward<Value>(value), bindDoneCb(cb), permanent);
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb={});
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallbackSimple cb) {
putEncrypted(hash, to, std::forward<Value>(value), bindDoneCb(cb));
}
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={});
/**
* Insert known nodes to the routing table, without necessarly ping them.
* Usefull to restart a node and get things running fast without putting load on the network.
*/
void bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple&& cb={});
void bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb={});
/**
* Insert known nodes to the routing table, without necessarly ping them.
* Usefull to restart a node and get things running fast without putting load on the network.
*/
void bootstrap(const char* host, const char* service);
void bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes);
void bootstrap(const std::vector<NodeExport>& nodes);
/**
* Add host:service to bootstrap nodes, and ping this node.
* DNS resolution is performed asynchronously.
* When disconnected, all bootstrap nodes added with this method will be tried regularly until connection
* to the DHT network is established.
*/
void bootstrap(const std::string& host, const std::string& service);
void bootstrap(const std::string& hostService);
/**
* Insert known nodes to the routing table, without necessarly ping them.
* Usefull to restart a node and get things running fast without putting load on the network.
*/
void bootstrap(const InfoHash& id, const SockAddr& address);
/**
* Clear the list of bootstrap added using bootstrap(const std::string&, const std::string&).
*/
void clearBootstrap();
/**
* Inform the DHT of lower-layer connectivity changes.
* This will cause the DHT to assume an IP address change.
@@ -297,27 +204,25 @@ public:
void dumpTables() const;
/**
* Get the public key fingerprint if an identity is used with this node, 0 otherwise.
*/
InfoHash getId() const;
/**
* Get the ID of the DHT node.
*/
InfoHash getNodeId() const;
/**
* Returns the currently bound address.
* @param f: address family of the bound address to retreive.
*/
SockAddr getBound(sa_family_t f = AF_INET) const;
const Address& getBound(sa_family_t f = AF_INET) const {
return (f == AF_INET) ? bound4 : bound6;
}
/**
* Returns the currently bound port, in host byte order.
* @param f: address family of the bound port to retreive.
*/
in_port_t getBoundPort(sa_family_t f = AF_INET) const;
in_port_t getBoundPort(sa_family_t f = AF_INET) const {
return ntohs(((sockaddr_in*)&getBound(f).first)->sin_port);
}
std::pair<size_t, size_t> getStoreSize() const;
@@ -327,59 +232,55 @@ public:
std::vector<ValuesExport> exportValues() const;
void setLogger(const Sp<Logger>& logger = {});
void setLogger(const Logger& logger) {
setLogger(std::make_shared<Logger>(logger));
}
void setLoggers(LogMethod err = {}, LogMethod warn = {}, LogMethod debug = {});
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
void setLogFilter(const InfoHash& f = {});
void setLoggers(LogMethod err = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG);
void registerType(const ValueType& type);
void importValues(const std::vector<ValuesExport>& values);
bool isRunning() const {
return running != State::Idle;
return running;
}
NodeStats getNodesStats(sa_family_t af) const;
unsigned getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
NodeInfo getNodeInfo() const;
void getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)>);
int getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
std::vector<unsigned> getNodeMessageStats(bool in = false) const;
std::string getStorageLog() const;
std::string getStorageLog(const InfoHash&) const;
std::string getRoutingTablesLog(sa_family_t af) const;
std::string getSearchesLog(sa_family_t af = AF_UNSPEC) const;
std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const;
std::vector<SockAddr> getPublicAddress(sa_family_t af = AF_UNSPEC);
std::vector<std::string> getPublicAddressStr(sa_family_t af = AF_UNSPEC);
std::string getSearchesLog(sa_family_t af = 0) const;
std::vector<Address> getPublicAddress(sa_family_t af = 0);
std::vector<std::string> getPublicAddressStr(sa_family_t af = 0);
// securedht methods
void findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)>);
void findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>)>);
void registerCertificate(std::shared_ptr<crypto::Certificate> cert);
void setLocalCertificateStore(CertificateStoreQuery&& query_method);
struct Config {
SecureDhtConfig dht_config;
bool threaded;
};
/**
* @param port: Local port to bind. Both IPv4 and IPv6 will be tried (ANY).
* @param identity: RSA key pair to use for cryptographic operations.
* @param threaded: If false, ::loop() must be called periodically. Otherwise a thread is launched.
* @param cb: Optional callback to receive general state information.
*/
void run(in_port_t port = dht::net::DHT_DEFAULT_PORT, const crypto::Identity& identity = {}, bool threaded = true, NetId network = 0) {
Config config;
config.dht_config.node_config.network = network;
config.dht_config.id = identity;
config.threaded = threaded;
run(port, config);
void run(in_port_t port, const crypto::Identity identity, bool threaded = false, bool is_bootstrap = false) {
run(port, {
/*.dht_config = */{
/*.node_config = */{
/*.node_id = */{},
/*.is_bootstrap = */is_bootstrap
},
/*.id = */identity
},
/*.threaded = */threaded
});
}
void run(in_port_t port, const Config& config, Context&& context = {});
void run(in_port_t port, Config config);
/**
* @param local4: Local IPv4 address and port to bind. Can be null.
@@ -389,14 +290,12 @@ public:
* @param threaded: If false, loop() must be called periodically. Otherwise a thread is launched.
* @param cb: Optional callback to receive general state information.
*/
void run(const SockAddr& local4, const SockAddr& local6, const Config& config, Context&& context = {});
void run(const sockaddr_in* local4, const sockaddr_in6* local6, Config config);
/**
* Same as @run(sockaddr_in, sockaddr_in6, Identity, bool, StatusCallback), but with string IP addresses and service (port).
*/
void run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context = {});
void run(const Config& config, Context&& context);
void run(const char* ip4, const char* ip6, const char* service, Config config);
void setOnStatusChanged(StatusCallback&& cb) {
statusCb = std::move(cb);
@@ -415,7 +314,7 @@ public:
/**
* Gracefuly disconnect from network.
*/
void shutdown(ShutdownCallback cb = {});
void shutdown(ShutdownCallback cb);
/**
* Quit and wait for all threads to terminate.
@@ -424,107 +323,38 @@ public:
*/
void join();
std::shared_ptr<PeerDiscovery> getPeerDiscovery() const { return peerDiscovery_; };
void setProxyServer(const std::string& proxy, const std::string& pushNodeId = "");
/**
* Start or stop the proxy
* @param proxify if we want to use the proxy
* @param deviceKey non empty to enable push notifications
*/
void enableProxy(bool proxify);
/* Push notification methods */
/**
* Updates the push notification device token
*/
void setPushNotificationToken(const std::string& token);
/**
* Insert a push notification to process for OpenDHT
*/
void pushNotificationReceived(const std::map<std::string, std::string>& data);
/* Proxy server mothods */
void forwardAllMessages(bool forward);
private:
static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
enum class State {
Idle,
Running,
Stopping
};
void doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDhtConfig config);
time_point loop_();
static std::vector<std::pair<sockaddr_storage, socklen_t>> getAddrInfo(const char* host, const char* service);
NodeStatus getStatus() const {
return std::max(status4, status6);
}
bool checkShutdown();
void opEnded();
DoneCallback bindOpDoneCallback(DoneCallback&& cb);
DoneCallbackSimple bindOpDoneCallback(DoneCallbackSimple&& cb);
/** Local DHT instance */
std::unique_ptr<SecureDht> dht_;
/** Proxy client instance */
std::unique_ptr<SecureDht> dht_via_proxy_;
/** true if we are currently using a proxy */
std::atomic_bool use_proxy {false};
/** Current configuration */
Config config_;
/**
* reset dht clients
*/
void resetDht();
/**
* @return the current active DHT
*/
SecureDht* activeDht() const;
/**
* Store current listeners and translates global tokens for each client.
*/
struct Listener;
std::map<size_t, Listener> listeners_;
size_t listener_token_ {1};
mutable std::mutex dht_mtx {};
std::thread dht_thread {};
std::condition_variable cv {};
std::thread rcv_thread {};
std::mutex sock_mtx {};
net::PacketList rcv {};
decltype(rcv) rcv_free {};
std::vector<std::pair<Blob, std::pair<sockaddr_storage, socklen_t>>> rcv {};
std::queue<std::function<void(SecureDht&)>> pending_ops_prio {};
std::queue<std::function<void(SecureDht&)>> pending_ops {};
std::mutex storage_mtx {};
std::atomic<State> running {State::Idle};
std::atomic_size_t ongoing_ops {0};
std::vector<ShutdownCallback> shutdownCallbacks_;
std::atomic<bool> running {false};
NodeStatus status4 {NodeStatus::Disconnected},
status6 {NodeStatus::Disconnected};
StatusCallback statusCb {nullptr};
/** PeerDiscovery Parameters */
std::shared_ptr<PeerDiscovery> peerDiscovery_;
/**
* The Logger instance is used in enableProxy and other methods that
* would create instances of classes using a common logger.
*/
std::shared_ptr<dht::Logger> logger_;
Address bound4 {};
Address bound6 {};
};
}
-378
View File
@@ -1,378 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "def.h"
#include "infohash.h"
#include "crypto.h"
// some libraries may try to redefine snprintf
// but restinio will use it in std namespace
#ifdef _MSC_VER
# undef snprintf
# define snprintf snprintf
#endif
#include <asio/ssl/context.hpp>
#include <restinio/http_headers.hpp>
#include <restinio/message_builders.hpp>
#include <memory>
#include <queue>
#include <mutex>
namespace Json {
class Value;
}
extern "C" {
struct http_parser;
struct http_parser_settings;
}
namespace restinio {
namespace impl {
class tls_socket_t;
}
}
namespace dht {
struct Logger;
namespace crypto {
struct Certificate;
}
namespace http {
using HandlerCb = std::function<void(const asio::error_code& ec)>;
using BytesHandlerCb = std::function<void(const asio::error_code& ec, size_t bytes)>;
using ConnectHandlerCb = std::function<void(const asio::error_code& ec,
const asio::ip::tcp::endpoint& endpoint)>;
using ssl_socket_t = restinio::impl::tls_socket_t;
using socket_t = asio::ip::tcp::socket;
class OPENDHT_PUBLIC Url
{
public:
Url(){};
Url(const std::string& url);
std::string url;
std::string protocol {"http"};
std::string host;
std::string service {"80"};
std::string target {"/"};
std::string query;
std::string fragment;
};
class OPENDHT_PUBLIC Connection : public std::enable_shared_from_this<Connection>
{
public:
Connection(asio::io_context& ctx, const bool ssl = true, std::shared_ptr<dht::Logger> l = {});
Connection(asio::io_context& ctx, std::shared_ptr<dht::crypto::Certificate> server_ca,
const dht::crypto::Identity& identity, std::shared_ptr<dht::Logger> l = {});
~Connection();
inline unsigned int id() const { return id_; };
bool is_open() const;
bool is_ssl() const;
void set_ssl_verification(const asio::ip::tcp::endpoint& endpoint, const asio::ssl::verify_mode verify_mode);
asio::streambuf& input();
std::istream& data() { return istream_; }
std::string read_bytes(size_t bytes = 0);
std::string read_until(const char delim);
void async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, ConnectHandlerCb);
void async_handshake(HandlerCb cb);
void async_write(BytesHandlerCb cb);
void async_read_until(const char* delim, BytesHandlerCb cb);
void async_read_until(char delim, BytesHandlerCb cb);
void async_read(size_t bytes, BytesHandlerCb cb);
void async_read_some(size_t bytes, BytesHandlerCb cb);
void timeout(const std::chrono::seconds timeout, HandlerCb cb = {});
void close();
private:
template<typename T>
T wrapCallabck(T cb) const {
return [t=shared_from_this(),cb=std::move(cb)](auto ...params) {
cb(params...);
};
}
mutable std::mutex mutex_;
unsigned int id_;
static std::atomic_uint ids_;
asio::io_context& ctx_;
std::unique_ptr<socket_t> socket_;
std::shared_ptr<asio::ssl::context> ssl_ctx_;
std::unique_ptr<ssl_socket_t> ssl_socket_;
asio::ip::tcp::endpoint endpoint_;
asio::streambuf write_buf_;
asio::streambuf read_buf_;
std::istream istream_;
std::unique_ptr<asio::steady_timer> timeout_timer_;
std::shared_ptr<dht::Logger> logger_;
};
/**
* Session value associated with a connection_id_t key.
*/
struct ListenerSession
{
ListenerSession() = default;
dht::InfoHash hash;
std::future<size_t> token;
std::shared_ptr<restinio::response_builder_t<restinio::chunked_output_t>> response;
};
/* @class Resolver
* @brief The purpose is to only resolve once to avoid mutliple dns requests per operation.
*/
class OPENDHT_PUBLIC Resolver
{
public:
using ResolverCb = std::function<void(const asio::error_code& ec,
const std::vector<asio::ip::tcp::endpoint>& endpoints)>;
Resolver(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Resolver(asio::io_context& ctx, const std::string& host, const std::string& service,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
// use already resolved endpoints with classes using this resolver
Resolver(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint> endpoints,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
Resolver(asio::io_context& ctx, const std::string& url, std::vector<asio::ip::tcp::endpoint> endpoints,
std::shared_ptr<dht::Logger> logger = {});
~Resolver();
inline const Url& get_url() const {
return url_;
}
void add_callback(ResolverCb cb, sa_family_t family = AF_UNSPEC);
std::shared_ptr<Logger> getLogger() const {
return logger_;
}
private:
void resolve(const std::string& host, const std::string& service);
mutable std::mutex mutex_;
Url url_;
asio::error_code ec_;
asio::ip::tcp::resolver resolver_;
std::shared_ptr<bool> destroyed_;
std::vector<asio::ip::tcp::endpoint> endpoints_;
bool completed_ {false};
std::queue<ResolverCb> cbs_;
std::shared_ptr<dht::Logger> logger_;
};
class Request;
struct Response
{
unsigned status_code {0};
std::map<std::string, std::string> headers;
std::string body;
bool aborted {false};
std::weak_ptr<Request> request;
};
class OPENDHT_PUBLIC Request : public std::enable_shared_from_this<Request>
{
public:
enum class State {
CREATED,
SENDING,
HEADER_RECEIVED,
RECEIVING,
DONE
};
using OnStatusCb = std::function<void(unsigned status_code)>;
using OnDataCb = std::function<void(const char* at, size_t length)>;
using OnStateChangeCb = std::function<void(State state, const Response& response)>;
using OnJsonCb = std::function<void(Json::Value value, unsigned status_code)>;
using OnDoneCb = std::function<void(const Response& response)>;
// resolves implicitly
Request(asio::io_context& ctx, const std::string& url, const Json::Value& json, OnJsonCb jsoncb,
std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& host, const std::string& service,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, OnDoneCb onDone, std::shared_ptr<dht::Logger> logger = {});
// user defined resolver
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, sa_family_t family = AF_UNSPEC);
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, const std::string& target, sa_family_t family = AF_UNSPEC);
// user defined resolved endpoints
Request(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint>&& endpoints,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
~Request();
inline unsigned int id() const { return id_; };
void set_connection(std::shared_ptr<Connection> connection);
std::shared_ptr<Connection> get_connection() const;
inline const Url& get_url() const {
return resolver_->get_url();
};
/** The previous request in case of redirect following */
std::shared_ptr<Request> getPrevious() const {
return prev_.lock();
}
inline std::string& to_string() {
return request_;
}
void set_certificate_authority(std::shared_ptr<dht::crypto::Certificate> certificate);
void set_identity(const dht::crypto::Identity& identity);
void set_logger(std::shared_ptr<dht::Logger> logger);
/**
* Define the HTTP header/body as per https://tools.ietf.org/html/rfc7230.
*/
void set_header(restinio::http_request_header_t header);
void set_method(restinio::http_method_id_t method);
void set_target(std::string target);
void set_header_field(restinio::http_field_t field, std::string value);
void set_connection_type(restinio::http_connection_header_t connection);
void set_body(std::string body);
void set_auth(const std::string& username, const std::string& password);
void add_on_status_callback(OnStatusCb cb);
void add_on_body_callback(OnDataCb cb);
void add_on_state_change_callback(OnStateChangeCb cb);
void add_on_done_callback(OnDoneCb cb);
void send();
/**
* User action to cancel the Request and call the completion callbacks.
*/
void cancel();
private:
using OnCompleteCb = std::function<void()>;
struct Callbacks {
OnStatusCb on_status;
OnDataCb on_header_field;
OnDataCb on_header_value;
OnDataCb on_body;
OnStateChangeCb on_state_change;
};
void notify_state_change(State state);
void build();
void init_default_headers();
/**
* Initialized and wraps the http_parser callbacks with our user defined callbacks.
*/
void init_parser();
void connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb = {});
void terminate(const asio::error_code& ec);
void post();
void handle_request(const asio::error_code& ec);
void handle_response(const asio::error_code& ec, size_t bytes);
void onHeadersComplete();
void onBody(const char* at, size_t length);
void onComplete();
mutable std::mutex mutex_;
std::shared_ptr<dht::Logger> logger_;
restinio::http_request_header_t header_;
std::map<restinio::http_field_t, std::string> headers_;
restinio::http_connection_header_t connection_type_ {restinio::http_connection_header_t::close};
std::string body_;
Callbacks cbs_;
State state_;
dht::crypto::Identity client_identity_;
std::shared_ptr<dht::crypto::Certificate> server_ca_;
std::string service_;
std::string host_;
unsigned int id_;
static std::atomic_uint ids_;
asio::io_context& ctx_;
sa_family_t family_ = AF_UNSPEC;
std::shared_ptr<Connection> conn_;
std::shared_ptr<Resolver> resolver_;
Response response_ {};
std::string request_;
std::atomic<bool> finishing_ {false};
std::unique_ptr<http_parser> parser_;
std::unique_ptr<http_parser_settings> parser_s_;
// Next request in case of redirect following
std::shared_ptr<Request> next_;
std::weak_ptr<Request> prev_;
unsigned num_redirect {0};
bool follow_redirect {true};
};
} // namespace http
} // namespace dht
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
namespace restinio
{
/* Custom HTTP-methods for RESTinio > 0.5.0.
* https://github.com/Stiffstream/restinio/issues/26
*/
constexpr const restinio::http_method_id_t method_listen {HTTP_LISTEN, "LISTEN"};
constexpr const restinio::http_method_id_t method_stats {HTTP_STATS, "STATS"};
constexpr const restinio::http_method_id_t method_sign {HTTP_SIGN, "SIGN"};
constexpr const restinio::http_method_id_t method_encrypt {HTTP_ENCRYPT, "ENCRYPT"};
} // namespace restinio
#endif
-533
View File
@@ -1,533 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <map>
#include <functional>
#include <stdexcept>
#include <bitset>
#include <iostream>
#include <sstream>
#include "../value.h"
#include "../dhtrunner.h"
#include "../infohash.h"
namespace dht {
namespace indexation {
/*!
* @class Prefix
* @brief A blob structure which prefixes a Key in the PHT.
* @details
* Since the PHT structure is a "trie", every node in this structure have a
* label which is defined by the path from the root of the trie to the node. If
* the node in question is a leaf, *the label is a prefix of all the keys
* contained in the leaf*.
*/
struct OPENDHT_PUBLIC Prefix {
Prefix() {}
Prefix(InfoHash h) : size_(h.size() * 8), content_(h.begin(), h.end()) { }
Prefix(const Blob& d, const Blob& f={}) : size_(d.size()*8), flags_(f), content_(d) { }
Prefix(const Prefix& p, size_t first) :
size_(std::min(first, p.content_.size()*8)),
content_(Blob(p.content_.begin(), p.content_.begin()+size_/8))
{
auto rem = size_ % 8;
if ( not p.flags_.empty() ) {
flags_ = Blob(p.flags_.begin(), p.flags_.begin()+size_/8);
if (rem)
flags_.push_back(p.flags_[size_/8] & (0xFF << (8 - rem)));
}
if (rem)
content_.push_back(p.content_[size_/8] & (0xFF << (8 - rem)));
}
/**
* Get a sub prefix of the Prefix
*
* @param len lenght of the prefix to get, could be negative
* if len is negativ then you will get the prefix
* of size of the previous prefix minus len
*
* @return Sub-prefix of size len or if len is negative sub-prefix of size
* of prefix minus len
*
* @throw out_of_range if len is larger than size of the content
*/
Prefix getPrefix(ssize_t len) const {
if ((size_t)std::abs(len) >= content_.size() * 8)
throw std::out_of_range("len larger than prefix size.");
if (len < 0)
len += size_;
return Prefix(*this, len);
}
/**
* Flags are considered as active if flag is empty or if the flag
* at pos 'pos' is active
ee *
* @see isActiveBit in private function
*/
bool isFlagActive(size_t pos) const {
return flags_.empty() or isActiveBit(flags_, pos);
}
/**
* @see isActiveBit in private function
*/
bool isContentBitActive(size_t pos) const {
return isActiveBit(content_, pos);
}
Prefix getFullSize() { return Prefix(*this, content_.size()*8); }
/**
* This methods gets the prefix of its sibling in the PHT structure.
*
* @return The prefix of this sibling.
*/
Prefix getSibling() const {
Prefix copy = *this;
if ( size_ )
copy.swapContentBit(size_ - 1);
return copy;
}
InfoHash hash() const {
Blob copy(content_);
copy.push_back(size_);
return InfoHash::get(copy);
}
/**
* This method count total of bit in common between 2 prefix
*
* @param p1 first prefix to compared
* @param p2 second prefix to compared
* @return Lenght of the larger common prefix between both
*/
static inline unsigned commonBits(const Prefix& p1, const Prefix& p2) {
unsigned i, j;
uint8_t x;
auto longest_prefix_size = std::min(p1.size_, p2.size_);
for (i = 0; i < longest_prefix_size; i++) {
if (p1.content_.data()[i] != p2.content_.data()[i]
or not p1.isFlagActive(i)
or not p2.isFlagActive(i) ) {
break;
}
}
if (i == longest_prefix_size)
return 8*longest_prefix_size;
x = p1.content_.data()[i] ^ p2.content_.data()[i];
j = 0;
while ((x & 0x80) == 0) {
x <<= 1;
j++;
}
return 8 * i + j;
}
/**
* @see doc of swap private function
*/
void swapContentBit(size_t bit) {
swapBit(content_, bit);
}
/**
* @see doc of swap private function
*/
void swapFlagBit(size_t bit) {
swapBit(flags_, bit);
}
/**
* @see doc of addPadding private function
*/
void addPaddingContent(size_t size) {
content_ = addPadding(content_, size);
}
void updateFlags() {
/* Fill first known bit */
auto csize = size_ - flags_.size() * 8;
while(csize >= 8) {
flags_.push_back(0xFF);
csize -= 8;
}
/* if needed fill remaining bit */
if ( csize )
flags_.push_back(0xFF << (8 - csize));
/* Complet vector space missing */
for ( auto i = flags_.size(); i < content_.size(); i++ )
flags_.push_back(0xFF);
}
std::string toString() const;
size_t size_ {0};
/* Will contain flags according to content_.
If flags_[i] == 0, then content_[i] is unknown
else if flags_[i] == 1, then content_[i] is known */
Blob flags_ {};
Blob content_ {};
private:
/**
* Add a padding to the input blob
*
* @param toP : Prefix where to add a padding
* @param size : Final size of the prefix with padding
*
* @return Copy of the input Blob but with a padding
*/
Blob addPadding(Blob toP, size_t size) {
Blob copy = toP;
for ( auto i = copy.size(); i < size; i++ )
copy.push_back(0);
swapBit(copy, size_ + 1);
return copy;
}
/**
* Check if the bit a pos 'pos' is active, i.e. equal to 1
*
* @param b : Blob to check
* @param pos : Position to check
*
* @return true if the bit is equal to 1, false otherwise
*
* @throw out_of_range if bit is superior to blob size * 8
*/
bool isActiveBit(const Blob &b, size_t pos) const {
if ( pos >= content_.size() * 8 )
throw std::out_of_range("Can't detect active bit at pos, pos larger than prefix size or empty prefix");
return ((b[pos / 8] >> (7 - (pos % 8)) ) & 1) == 1;
}
/**
* Swap bit at position bit [from 0 to 1 and vice-versa]
*
* @param b : Blob to swap
* @param bit : Bit to swap on b
*
* @return the input prefix with the bit at pos 'bit' swapped
*
* @throw out_of_range if bit is superior to blob size * 8
*/
void swapBit(Blob &b, size_t bit) {
if ( bit >= b.size() * 8 )
throw std::out_of_range("bit larger than prefix size.");
size_t offset_bit = (8 - bit) % 8;
b[bit / 8] ^= (1 << offset_bit);
}
};
using Value = std::pair<InfoHash, dht::Value::Id>;
struct OPENDHT_PUBLIC IndexEntry : public dht::Value::Serializable<IndexEntry> {
static const ValueType TYPE;
virtual void unpackValue(const dht::Value& v) {
Serializable<IndexEntry>::unpackValue(v);
name = v.user_type;
}
virtual dht::Value packValue() const {
auto pack = Serializable<IndexEntry>::packValue();
pack.user_type = name;
return pack;
}
Blob prefix;
Value value;
std::string name;
MSGPACK_DEFINE_MAP(prefix, value)
};
class OPENDHT_PUBLIC Pht {
static constexpr const char* INVALID_KEY = "Key does not match the PHT key spec.";
/* Prefixes the user_type for all dht values put on the DHT */
static constexpr const char* INDEX_PREFIX = "index.pht.";
public:
/* This is the maximum number of entries per node. This parameter is
* critical and influences the traffic a lot during a lookup operation.
*/
static constexpr const size_t MAX_NODE_ENTRY_COUNT {16};
/* A key for a an index entry */
using Key = std::map<std::string, Blob>;
/* Specifications of the keys. It defines the number, the length and the
* serialization order of fields. */
using KeySpec = std::map<std::string, size_t>;
using LookupCallback = std::function<void(std::vector<std::shared_ptr<Value>>& values, const Prefix& p)>;
typedef void (*LookupCallbackRaw)(std::vector<std::shared_ptr<Value>>* values, Prefix* p, void *user_data);
static LookupCallback
bindLookupCb(LookupCallbackRaw raw_cb, void* user_data) {
if (not raw_cb) return {};
return [=](std::vector<std::shared_ptr<Value>>& values, const Prefix& p) {
raw_cb((std::vector<std::shared_ptr<Value>>*) &values, (Prefix*) &p, user_data);
};
}
using LookupCallbackSimple = std::function<void(std::vector<std::shared_ptr<Value>>& values)>;
typedef void (*LookupCallbackSimpleRaw)(std::vector<std::shared_ptr<Value>>* values, void *user_data);
static LookupCallbackSimple
bindLookupCbSimple(LookupCallbackSimpleRaw raw_cb, void* user_data) {
if (not raw_cb) return {};
return [=](std::vector<std::shared_ptr<Value>>& values) {
raw_cb((std::vector<std::shared_ptr<Value>>*) &values, user_data);
};
}
Pht(std::string name, KeySpec k_spec, std::shared_ptr<DhtRunner> dht)
: name_(INDEX_PREFIX + name), canary_(name_ + ".canary"), keySpec_(k_spec), dht_(dht) {}
virtual ~Pht () { }
/**
* Lookup a key for a value.
*/
void lookup(Key k, LookupCallback cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true);
void lookup(Key k, LookupCallbackSimple cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true)
{
lookup(k, [=](std::vector<std::shared_ptr<Value>>& values, Prefix) { cb(values); }, done_cb, exact_match);
}
/**
* Wrapper function which call the private one.
*
* @param k : Key to insert [i.e map of string, blob]
* @param v : Value to insert
* @param done_cb : Callbakc which going to be call when all the insert is done
*/
void insert(Key k, Value v, DoneCallbackSimple done_cb = {}) {
Prefix p = linearize(k);
auto lo = std::make_shared<int>(0);
auto hi = std::make_shared<int>(p.size_);
IndexEntry entry;
entry.value = v;
entry.prefix = p.content_;
entry.name = name_;
Pht::insert(p, entry, lo, hi, clock::now(), true, done_cb);
}
private:
/**
* Insert function which really insert onto the pht
*
* @param kp : Prefix to insert (linearize the the key)
* @param entry : Entry created from the value
* @param lo : Lowest point to start in the prefix
* @param hi : Highest point to end in the prefix
* @param time_p : Timepoint to use for the insertion into the dht (must be < now)
* @param check_split : If this flag is true then the algoritm will not use the merge algorithm
* @param done_cb : Callback to call when the insert is done
*/
void insert(const Prefix& kp, IndexEntry entry, std::shared_ptr<int> lo, std::shared_ptr<int> hi, time_point time_p,
bool check_split, DoneCallbackSimple done_cb = {});
class Cache {
public:
/**
* Insert all needed node into the tree according to a prefix
* @param p : Prefix that we need to insert
*/
void insert(const Prefix& p);
/**
* Lookup into the tree to return the maximum prefix length in the cache tree
*
* @param p : Prefix that we are looking for
*
* @return : The size of the longest prefix known in the cache between 0 and p.size_
*/
int lookup(const Prefix& p);
private:
static constexpr const size_t MAX_ELEMENT {1024};
static constexpr const std::chrono::minutes NODE_EXPIRE_TIME {5};
struct Node {
time_point last_reply; /* Made the assocation between leaves and leaves multimap */
std::shared_ptr<Node> parent; /* Share_ptr to the parent, it allow the self destruction of tree */
std::weak_ptr<Node> left_child; /* Left child, for bit equal to 1 */
std::weak_ptr<Node> right_child; /* Right child, for bit equal to 0 */
};
std::weak_ptr<Node> root_; /* Root of the tree */
/**
* This mutlimap contains all prefix insert in the tree in time order
* We could then delete the last one if there is too much node
* The tree will self destroy is branch ( thanks to share_ptr )
*/
std::multimap<time_point, std::shared_ptr<Node>> leaves_;
};
/* Callback used for insert value by using the pht */
using RealInsertCallback = std::function<void(const Prefix& p, IndexEntry entry)>;
using LookupCallbackWrapper = std::function<void(std::vector<std::shared_ptr<IndexEntry>>& values, const Prefix& p)>;
/**
* Performs a step in the lookup operation. Each steps are performed
* asynchronously.
*
* @param k : Prefix on which the lookup is performed
* @param lo : lowest bound on the prefix (where to start)
* @param hi : highest bound on the prefix (where to stop)
* @param vals : Shared ptr to a vector of IndexEntry (going to contains all values found)
* @param cb : Callback to use at the end of the lookupStep (call on the value of vals)
* @param done_cb : Callback at the end of the lookupStep
* @param max_common_prefix_len: used in the inexacte lookup match case, indicate the longest common prefix found
* @param start : If start is set then lo and hi will be ignore for the first step, if the step fail lo and hi will be used
* @param all_values : If all value is true then all value met during the lookupstep will be in the vector vals
*/
void lookupStep(Prefix k, std::shared_ptr<int> lo, std::shared_ptr<int> hi,
std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals,
LookupCallbackWrapper cb, DoneCallbackSimple done_cb,
std::shared_ptr<unsigned> max_common_prefix_len,
int start = -1, bool all_values = false);
/**
* Apply the zcurve algorithm on the list of input prefix
*
* @param all_prefix : Vector of prefix to interleave
*
* @return The output prefix where all flags and content are interleaves
*/
Prefix zcurve(const std::vector<Prefix>& all_prefix) const;
/**
* Linearizes the key into a unidimensional key. A pht only takes
* unidimensional key.
*
* @param Key The initial key.
*
* @return the prefix of the linearized key.
*/
virtual Prefix linearize(Key k) const;
/**
* Looking where to put the data cause if there is free space on the node
* above then this node will became the real leave.
*
* @param p Share_ptr on the Prefix to check
* @param entry The entry to put at the prefix p
* @param end_cb Callback to use at the end of counting
*/
void getRealPrefix(const std::shared_ptr<Prefix>& p, IndexEntry entry, RealInsertCallback end_cb );
/**
* Looking where to put the data cause if there is free space on the node
* above then this node will became the real leave.
*
* @param p Share_ptr on the Prefix to check
* @param entry The entry to put at the prefix p
* @param end_cb Callback to use at the end of counting
*/
void checkPhtUpdate(Prefix p, IndexEntry entry, time_point time_p);
/**
* Search for the split location by comparing 'compared' to all values in vals.
*
* @param compared : Value which going to be compared
* @param vals : The vector of values to compare with comapred
* @return position compared diverge from all others
*/
static size_t findSplitLocation(const Prefix& compared, const std::vector<std::shared_ptr<IndexEntry>>& vals) {
for ( size_t i = 0; i < compared.content_.size() * 8 - 1; i++ )
for ( auto const& v : vals)
if ( Prefix(v->prefix).isContentBitActive(i) != compared.isContentBitActive(i) )
return i + 1;
return compared.content_.size() * 8 - 1;
}
/**
* Put canary from the split point until the last known canary and add the prefix at the good place
*
* @param insert : Prefix to insertm but also prefix which going to check where we need to split
* @param vals : Vector of vals for the comparaison
* @param entry : Entry to put on the pht
* @param end_cb : Callback to apply to the insert prefi (here does the insert)
*/
void split(const Prefix& insert, const std::vector<std::shared_ptr<IndexEntry>>& vals, IndexEntry entry, RealInsertCallback end_cb);
/**
* Tells if the key is valid according to the key spec.
*/
bool validKey(const Key& k) const {
return k.size() == keySpec_.size() and
std::equal(k.begin(), k.end(), keySpec_.begin(),
[&](const Key::value_type& key, const KeySpec::value_type& key_spec) {
return key.first == key_spec.first and key.second.size() <= key_spec.second;
}
);
}
/**
* Updates the canary token on the node responsible for the specified
* Prefix.
*/
void updateCanary(Prefix p);
const std::string name_;
const std::string canary_;
const KeySpec keySpec_;
Cache cache_;
std::shared_ptr<DhtRunner> dht_;
};
} /* indexation */
} /* dht */
+67 -225
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,14 +13,12 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "def.h"
#include "rng.h"
#include <msgpack.hpp>
#ifndef _WIN32
@@ -42,102 +40,54 @@ typedef uint16_t in_port_t;
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <sstream>
#include <cstring>
// bytes
#define HASH_LEN 20u
namespace dht {
using byte = uint8_t;
namespace crypto {
OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length);
}
/**
* Represents an InfoHash.
* An InfoHash is a byte array of HASH_LEN bytes.
* InfoHashes identify nodes and values in the Dht.
*/
template <size_t N>
class OPENDHT_PUBLIC Hash {
class InfoHash final : public std::array<uint8_t, HASH_LEN> {
public:
using T = std::array<uint8_t, N>;
typedef typename T::iterator iterator;
typedef typename T::const_iterator const_iterator;
Hash () noexcept {
data_.fill(0);
}
Hash (const uint8_t* h, size_t data_len) {
if (data_len < N)
data_.fill(0);
constexpr InfoHash() : std::array<uint8_t, HASH_LEN>() {}
constexpr InfoHash(const std::array<uint8_t, HASH_LEN>& h) : std::array<uint8_t, HASH_LEN>(h) {}
InfoHash(const uint8_t* h, size_t h_len) : std::array<uint8_t, HASH_LEN>() {
if (h_len < HASH_LEN)
fill(0);
else
std::copy_n(h, N, data_.begin());
std::copy_n(h, HASH_LEN, begin());
}
/**
* Constructor from an hexadecimal string (without "0x").
* hex must be at least 2.HASH_LEN characters long.
* If too long, only the first 2.HASH_LEN characters are read.
*/
explicit Hash(const std::string& hex);
explicit InfoHash(const std::string& hex);
Hash(const msgpack::object& o) {
InfoHash(const msgpack::object& o) {
msgpack_unpack(o);
}
static constexpr size_t size() noexcept { return N; }
const uint8_t* data() const { return data_.data(); }
uint8_t* data() { return data_.data(); }
iterator begin() { return data_.begin(); }
const_iterator cbegin() const { return data_.cbegin(); }
iterator end() { return data_.end(); }
const_iterator cend() const { return data_.cend(); }
bool operator==(const Hash& h) const {
auto a = reinterpret_cast<const uint32_t*>(data_.data());
auto b = reinterpret_cast<const uint32_t*>(h.data_.data());
constexpr unsigned n = N / sizeof(uint32_t);
for (unsigned i=0; i < n; i++)
if (a[i] != b[i])
return false;
return true;
}
bool operator!=(const Hash& h) const { return !(*this == h); }
bool operator<(const Hash& o) const {
for(unsigned i = 0; i < N; i++) {
if(data_[i] != o.data_[i])
return data_[i] < o.data_[i];
}
return false;
}
explicit operator bool() const {
auto a = reinterpret_cast<const uint32_t*>(data_.data());
auto b = reinterpret_cast<const uint32_t*>(data_.data() + N);
for (; a != b; a++) {
if (*a)
return true;
}
return false;
}
uint8_t& operator[](size_t index) { return data_[index]; }
const uint8_t& operator[](size_t index) const { return data_[index]; }
/**
* Find the lowest 1 bit in an id.
* Result will allways be lower than 8*N
* Result will allways be lower than 8*HASH_LEN
*/
inline int lowbit() const {
inline unsigned lowbit() const {
int i, j;
for(i = N-1; i >= 0; i--)
if(data_[i] != 0)
for(i = HASH_LEN-1; i >= 0; i--)
if((*this)[i] != 0)
break;
if(i < 0)
return -1;
for(j = 7; j >= 0; j--)
if((data_[i] & (0x80 >> j)) != 0)
if(((*this)[i] & (0x80 >> j)) != 0)
break;
return 8 * i + j;
}
@@ -146,25 +96,29 @@ public:
* Forget about the ``XOR-metric''. An id is just a path from the
* root of the tree, so bits are numbered from the start.
*/
static inline int cmp(const Hash& id1, const Hash& id2) {
return std::memcmp(id1.data_.data(), id2.data_.data(), N);
#ifdef WIN32_NATIVE
static inline int cmp(const InfoHash& __restrict id1, const InfoHash& __restrict id2) {
#else
static inline int cmp(const InfoHash& __restrict__ id1, const InfoHash& __restrict__ id2) {
#endif
return std::memcmp(id1.data(), id2.data(), HASH_LEN);
}
/** Find how many bits two ids have in common. */
static inline unsigned
commonBits(const Hash& id1, const Hash& id2)
commonBits(const InfoHash& id1, const InfoHash& id2)
{
unsigned i, j;
uint8_t x;
for(i = 0; i < N; i++) {
if(id1.data_[i] != id2.data_[i])
for(i = 0; i < HASH_LEN; i++) {
if(id1[i] != id2[i])
break;
}
if(i == N)
return 8*N;
if(i == HASH_LEN)
return 8*HASH_LEN;
x = id1.data_[i] ^ id2.data_[i];
x = id1[i] ^ id2[i];
j = 0;
while((x & 0x80) == 0) {
@@ -177,14 +131,14 @@ public:
/** Determine whether id1 or id2 is closer to this */
int
xorCmp(const Hash& id1, const Hash& id2) const
xorCmp(const InfoHash& id1, const InfoHash& id2) const
{
for(unsigned i = 0; i < N; i++) {
for(unsigned i = 0; i < HASH_LEN; i++) {
uint8_t xor1, xor2;
if(id1.data_[i] == id2.data_[i])
if(id1[i] == id2[i])
continue;
xor1 = id1.data_[i] ^ data_[i];
xor2 = id2.data_[i] ^ data_[i];
xor1 = id1[i] ^ (*this)[i];
xor2 = id2[i] ^ (*this)[i];
if(xor1 < xor2)
return -1;
else
@@ -196,7 +150,7 @@ public:
bool
getBit(unsigned nbit) const
{
auto& num = *(data_.cbegin()+(nbit/8));
auto& num = *(cbegin()+(nbit/8));
unsigned bit = 7 - (nbit % 8);
return (num >> bit) & 1;
}
@@ -204,181 +158,69 @@ public:
void
setBit(unsigned nbit, bool b)
{
auto& num = data_[nbit/8];
auto& num = (*this)[nbit/8];
unsigned bit = 7 - (nbit % 8);
num ^= (-b ^ num) & (1 << bit);
}
double toFloat() const {
using D = size_t;
double
toFloat() const
{
double v = 0.;
for (size_t i = 0; i < std::min<size_t>(N, sizeof(D)-1); i++)
v += *(data_.cbegin()+i) / (double)((D)1 << 8*(i+1));
for (unsigned i = 0; i < std::min<size_t>(HASH_LEN, sizeof(unsigned)-1); i++)
v += *(cbegin()+i)/(double)(1<<(8*(i+1)));
return v;
}
static inline Hash get(const std::string& data) {
bool
operator<(const InfoHash& o) const {
for(unsigned i = 0; i < HASH_LEN; i++) {
if((*this)[i] != o[i])
return (*this)[i] < o[i];
}
return false;
}
static inline InfoHash get(const std::string& data) {
return get((const uint8_t*)data.data(), data.size());
}
static inline Hash get(const std::vector<uint8_t>& data) {
static inline InfoHash get(const std::vector<uint8_t>& data) {
return get(data.data(), data.size());
}
/**
* Computes the hash from a given data buffer of size data_len.
*/
static Hash get(const uint8_t* data, size_t data_len)
{
Hash ret;
crypto::hash(data, data_len, ret.data(), N);
return ret;
}
static InfoHash get(const uint8_t* data, size_t data_len);
static Hash getRandom();
static InfoHash getRandom();
template <size_t M>
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Hash<M>& h);
template <size_t M>
OPENDHT_PUBLIC friend std::istream& operator>> (std::istream& s, Hash<M>& h);
const char* to_c_str() const;
friend std::ostream& operator<< (std::ostream& s, const InfoHash& h);
std::string toString() const;
template <typename Packer>
void msgpack_pack(Packer& pk) const
{
pk.pack_bin(N);
pk.pack_bin_body((char*)data_.data(), N);
pk.pack_bin(HASH_LEN);
pk.pack_bin_body((char*)data(), HASH_LEN);
}
void msgpack_unpack(msgpack::object o) {
if (o.type != msgpack::type::BIN or o.via.bin.size != N)
if (o.type != msgpack::type::BIN or o.via.bin.size != HASH_LEN)
throw msgpack::type_error();
std::copy_n(o.via.bin.ptr, N, data_.data());
std::copy_n(o.via.bin.ptr, HASH_LEN, data());
}
private:
T data_;
void fromString(const char*);
};
#define HASH_LEN 20u
using InfoHash = Hash<HASH_LEN>;
using h256 = Hash<32>;
using PkId = h256;
static constexpr const InfoHash zeroes {};
template <size_t N>
std::ostream& operator<< (std::ostream& s, const Hash<N>& h)
{
s.write(h.to_c_str(), N*2);
return s;
}
template <size_t N>
std::istream& operator>> (std::istream& s, Hash<N>& h)
{
std::array<char, h.size()*2> dat;
s.exceptions(std::istream::eofbit | std::istream::failbit);
s.read(&(*dat.begin()), dat.size());
fromString(dat.data());
return s;
}
template <size_t N>
Hash<N>::Hash(const std::string& hex) {
if (hex.size() < 2*N)
data_.fill(0);
else
fromString(hex.c_str());
}
template <size_t N>
void
Hash<N>::fromString(const char* in) {
auto hex2bin = [](char c) -> uint8_t {
if (c >= 'a' and c <= 'f') return 10 + c - 'a';
else if (c >= 'A' and c <= 'F') return 10 + c - 'A';
else if (c >= '0' and c <= '9') return c - '0';
else throw std::domain_error("not an hex character");
};
try {
for (size_t i=0; i<N; i++)
data_[i] = (hex2bin(in[2*i]) << 4) | hex2bin(in[2*i+1]);
} catch (const std::domain_error&) {
data_.fill(0);
}
}
template <size_t N>
Hash<N>
Hash<N>::getRandom()
{
Hash h;
crypto::random_device rdev;
std::uniform_int_distribution<uint32_t> rand_int;
auto a = reinterpret_cast<uint32_t*>(h.data());
auto b = reinterpret_cast<uint32_t*>(h.data() + h.size());
std::generate(a, b, std::bind(rand_int, std::ref(rdev)));
return h;
}
struct HexMap : public std::array<std::array<char, 2>, 256> {
HexMap() {
for (size_t i=0; i<size(); i++) {
auto& e = (*this)[i];
e[0] = hex_digits[(i >> 4) & 0x0F];
e[1] = hex_digits[i & 0x0F];
}
}
private:
static constexpr const char* hex_digits = "0123456789abcdef";
};
OPENDHT_PUBLIC extern const HexMap hex_map;
template <size_t N>
const char*
Hash<N>::to_c_str() const
{
thread_local std::array<char, N*2+1> buf;
for (size_t i=0; i<N; i++) {
auto b = buf.data()+i*2;
const auto& m = hex_map[data_[i]];
*((uint16_t*)b) = *((uint16_t*)&m);
}
return buf.data();
}
template <size_t N>
std::string
Hash<N>::toString() const
{
return std::string(to_c_str(), N*2);
}
const InfoHash zeroes {};
struct OPENDHT_PUBLIC NodeExport {
struct NodeExport {
InfoHash id;
sockaddr_storage ss;
socklen_t sslen;
template <typename Packer>
void msgpack_pack(Packer& pk) const
{
pk.pack_map(2);
pk.pack(std::string("id"));
pk.pack(id);
pk.pack(std::string("addr"));
pk.pack_bin(sslen);
pk.pack_bin_body((char*)&ss, sslen);
}
void msgpack_unpack(msgpack::object o);
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const NodeExport& h);
};
}
+43 -30
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -14,24 +14,18 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "def.h"
#include "log_enable.h"
#include "dhtrunner.h"
#include <iostream>
#include <memory>
#include <fstream>
namespace dht {
class DhtRunner;
/**
* Logging-related functions
*/
namespace log {
/**
@@ -67,29 +61,48 @@ constexpr const Color::Modifier yellow(Color::FG_YELLOW);
/**
* Print va_list to std::ostream (used for logging).
*/
OPENDHT_PUBLIC void
printLog(std::ostream &s, char const *m, va_list args);
void
printLog(std::ostream& s, char const* m, va_list args) {
static constexpr int BUF_SZ = 8192;
char buffer[BUF_SZ];
int ret = vsnprintf(buffer, sizeof(buffer), m, args);
if (ret < 0)
return;
s.write(buffer, std::min(ret, BUF_SZ));
if (ret >= BUF_SZ)
s << "[[TRUNCATED]]";
s.put('\n');
}
OPENDHT_PUBLIC
std::shared_ptr<Logger> getStdLogger();
void
enableLogging(dht::DhtRunner& dht)
{
dht.setLoggers(
[](char const* m, va_list args){ std::cerr << red; printLog(std::cerr, m, args); std::cerr << def; },
[](char const* m, va_list args){ std::cout << yellow; printLog(std::cout, m, args); std::cout << def; },
[](char const* m, va_list args){ printLog(std::cout, m, args); }
);
}
OPENDHT_PUBLIC
std::shared_ptr<Logger> getFileLogger(const std::string &path);
void
enableFileLogging(dht::DhtRunner& dht, const std::string& path)
{
auto logfile = std::make_shared<std::fstream>();
logfile->open(path, std::ios::out);
OPENDHT_PUBLIC
std::shared_ptr<Logger> getSyslogLogger(const char* name);
dht.setLoggers(
[=](char const* m, va_list args){ printLog(*logfile, m, args); },
[=](char const* m, va_list args){ printLog(*logfile, m, args); },
[=](char const* m, va_list args){ printLog(*logfile, m, args); }
);
}
OPENDHT_PUBLIC void
enableLogging(dht::DhtRunner &dht);
OPENDHT_PUBLIC void
enableFileLogging(dht::DhtRunner &dht, const std::string &path);
OPENDHT_PUBLIC void
disableLogging(dht::DhtRunner &dht);
OPENDHT_PUBLIC void
enableSyslog(dht::DhtRunner &dht, const char* name);
void
disableLogging(dht::DhtRunner& dht)
{
dht.setLoggers(dht::NOLOG, dht::NOLOG, dht::NOLOG);
}
} /* log */
} /* dht */
-191
View File
@@ -1,191 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "infohash.h"
#include <cstdarg>
#ifndef OPENDHT_LOG
#define OPENDHT_LOG true
#endif
namespace dht {
// Logging related utility functions
/**
* Wrapper for logging methods
*/
struct LogMethod {
LogMethod() = default;
LogMethod(LogMethod&& l) : func(std::move(l.func)) {}
LogMethod(const LogMethod& l) : func(l.func) {}
LogMethod& operator=(dht::LogMethod&& l) {
func = std::forward<LogMethod>(l.func);
return *this;
}
LogMethod& operator=(const dht::LogMethod& l) {
func = l.func;
return *this;
}
template<typename T>
explicit LogMethod(T&& t) : func(std::forward<T>(t)) {}
template<typename T>
LogMethod(const T& t) : func(t) {}
void operator()(char const* format, ...) const {
va_list args;
va_start(args, format);
func(format, args);
va_end(args);
}
inline void log(char const* format, va_list args) const {
func(format, args);
}
explicit operator bool() const {
return (bool)func;
}
void logPrintable(const uint8_t *buf, size_t buflen) const {
std::string buf_clean(buflen, '\0');
for (size_t i=0; i<buflen; i++)
buf_clean[i] = isprint(buf[i]) ? buf[i] : '.';
(*this)("%s", buf_clean.c_str());
}
private:
std::function<void(char const*, va_list)> func;
};
struct Logger {
LogMethod DBG = {};
LogMethod WARN = {};
LogMethod ERR = {};
Logger() = default;
Logger(LogMethod&& err, LogMethod&& warn, LogMethod&& dbg)
: DBG(std::move(dbg)), WARN(std::move(warn)), ERR(std::move(err)) {}
void setFilter(const InfoHash& f) {
filter_ = f;
filterEnable_ = static_cast<bool>(filter_);
}
inline void log0(const LogMethod& logger, char const* format, va_list args) const {
#if OPENDHT_LOG
if (logger and not filterEnable_)
logger.log(format, args);
#endif
}
inline void log1(const LogMethod& logger, const InfoHash& f, char const* format, va_list args) const {
#if OPENDHT_LOG
if (logger and (not filterEnable_ or f == filter_))
logger.log(format, args);
#endif
}
inline void log2(const LogMethod& logger, const InfoHash& f1, const InfoHash& f2, char const* format, va_list args) const {
#if OPENDHT_LOG
if (logger and (not filterEnable_ or f1 == filter_ or f2 == filter_))
logger.log(format, args);
#endif
}
inline void d(char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(DBG, format, args);
va_end(args);
#endif
}
inline void d(const InfoHash& f, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(DBG, f, format, args);
va_end(args);
#endif
}
inline void d(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(DBG, f1, f2, format, args);
va_end(args);
#endif
}
inline void w(char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(WARN, format, args);
va_end(args);
#endif
}
inline void w(const InfoHash& f, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(WARN, f, format, args);
va_end(args);
#endif
}
inline void w(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(WARN, f1, f2, format, args);
va_end(args);
#endif
}
inline void e(char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(ERR, format, args);
va_end(args);
#endif
}
inline void e(const InfoHash& f, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(ERR, f, format, args);
va_end(args);
#endif
}
inline void e(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(ERR, f1, f2, format, args);
va_end(args);
#endif
}
private:
bool filterEnable_ {false};
InfoHash filter_ {};
};
}
+256 -360
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,9 +14,11 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "node_cache.h"
@@ -26,40 +28,26 @@
#include "scheduler.h"
#include "utils.h"
#include "rng.h"
#include "rate_limiter.h"
#include "log_enable.h"
#include "network_utils.h"
#include <vector>
#include <string>
#include <functional>
#include <algorithm>
#include <memory>
#include <random>
#include <queue>
namespace dht {
namespace net {
struct Request;
struct Socket;
struct TransId;
#ifndef MSG_CONFIRM
#define MSG_CONFIRM 0
#endif
struct NetworkConfig {
NetId network {0};
ssize_t max_req_per_sec {0};
ssize_t max_peer_req_per_sec {0};
};
class DhtProtocolException : public DhtException {
public:
// sent to another peer (http-like).
static const constexpr uint16_t NON_AUTHORITATIVE_INFORMATION {203}; /* incomplete request packet. */
static const constexpr uint16_t UNAUTHORIZED {401}; /* wrong tokens. */
static const constexpr uint16_t NOT_FOUND {404}; /* storage not found */
// for internal use (custom).
static const constexpr uint16_t INVALID_TID_SIZE {421}; /* id was truncated. */
static const constexpr uint16_t UNKNOWN_TID {422}; /* unknown tid */
@@ -70,40 +58,23 @@ public:
static const std::string LISTEN_WRONG_TOKEN; /* wrong token in "listen" request */
static const std::string PUT_NO_INFOHASH; /* no infohash in "put" request */
static const std::string PUT_WRONG_TOKEN; /* got "put" request with wrong token */
static const std::string STORAGE_NOT_FOUND; /* got access request for an unknown storage */
static const std::string PUT_INVALID_ID; /* invalid id in "put" request */
DhtProtocolException(uint16_t code, const std::string& msg="", InfoHash failing_node_id={})
: DhtException(msg), msg(msg), code(code), failing_node_id(failing_node_id) {}
const std::string& getMsg() const { return msg; }
std::string getMsg() const { return msg; }
uint16_t getCode() const { return code; }
const InfoHash& getNodeId() const { return failing_node_id; }
const InfoHash getNodeId() const { return failing_node_id; }
private:
std::string msg;
uint16_t code;
InfoHash failing_node_id;
const InfoHash failing_node_id;
};
struct ParsedMessage;
/**
* Answer for a request.
*/
struct RequestAnswer {
Blob ntoken {};
Value::Id vid {};
std::vector<Sp<Value>> values {};
std::vector<Value::Id> refreshed_values {};
std::vector<Value::Id> expired_values {};
std::vector<Sp<FieldValueIndex>> fields {};
std::vector<Sp<Node>> nodes4 {};
std::vector<Sp<Node>> nodes6 {};
RequestAnswer() {}
RequestAnswer(ParsedMessage&& msg);
};
/*!
* @class NetworkEngine
* @brief An abstraction of communication protocol on the network.
@@ -120,287 +91,247 @@ struct RequestAnswer {
* @param onGetValues callback for "get values" request.
* @param onListen callback for "listen" request.
* @param onAnnounce callback for "announce" request.
* @param onRefresh callback for "refresh" request.
*/
class NetworkEngine final
{
private:
/**
* Called when we receive an error message.
class NetworkEngine final {
struct TransPrefix : public std::array<uint8_t, 2> {
TransPrefix(const std::string& str) : std::array<uint8_t, 2>({{(uint8_t)str[0], (uint8_t)str[1]}}) {}
static const TransPrefix PING;
static const TransPrefix FIND_NODE;
static const TransPrefix GET_VALUES;
static const TransPrefix ANNOUNCE_VALUES;
static const TransPrefix LISTEN;
};
public:
/* Transaction-ids are 4-bytes long, with the first two bytes identifying
* the kind of request, and the remaining two a sequence number in
* host order.
*/
std::function<void(Sp<Request>, DhtProtocolException)> onError;
struct TransId final : public std::array<uint8_t, 4> {
static const constexpr uint16_t INVALID {0};
TransId() {}
TransId(const std::array<char, 4>& o) { std::copy(o.begin(), o.end(), begin()); }
TransId(const TransPrefix prefix, uint16_t seqno = 0) {
std::copy_n(prefix.begin(), prefix.size(), begin());
*reinterpret_cast<uint16_t*>(data()+prefix.size()) = seqno;
}
TransId(const char* q, size_t l) : array<uint8_t, 4>() {
if (l > 4) {
length = 0;
} else {
std::copy_n(q, l, begin());
length = l;
}
}
uint16_t getTid() const {
return *reinterpret_cast<const uint16_t*>(&(*this)[2]);
}
bool matches(const TransPrefix prefix, uint16_t* tid = nullptr) const {
if (std::equal(begin(), begin()+2, prefix.begin())) {
if (tid)
*tid = getTid();
return true;
} else
return false;
}
unsigned length {4};
};
/*!
* @class RequestAnswer
* @brief Answer for a request.
* @details
* Answer for a request to be (de)serialized. Used for reponding to a node
* and looking up the response from a node.
*/
struct RequestAnswer {
Blob ntoken {};
Value::Id vid {};
std::vector<std::shared_ptr<Value>> values {};
std::vector<std::shared_ptr<Node>> nodes4 {};
std::vector<std::shared_ptr<Node>> nodes6 {};
RequestAnswer() {}
RequestAnswer(ParsedMessage&& msg);
};
/**
* Cancel a request. Setting req->cancelled = true is not enough in the case
* a request is "persistent".
*/
void cancelRequest(std::shared_ptr<Request>& req);
void connectivityChanged();
private:
/**
* @brief when we receive an error message.
*
* @param node (type: std::shared_ptr<Request>) the associated request for
* which we got an error;
*/
std::function<void(std::shared_ptr<Request>, DhtProtocolException)> onError;
/**
* @brief when a new node happens.
*
* Called for every packets received for handling new nodes contacting us.
*
* @param node: the node
* @param confirm: 1 if the node sent a message, 2 if it sent us a reply.
* @param id (type: InfoHash) id of the node.
* @param saddr (type: sockaddr*) sockaddr* pointer containing address ip information.
* @param saddr_len (type: socklen_t) lenght of the sockaddr struct.
* @param confirm (type: int) 1 if the node sent a message, 2 if it sent us a reply.
*/
std::function<void(const Sp<Node>&, int)> onNewNode;
std::function<void(const std::shared_ptr<Node>&, int)> onNewNode;
/**
* Called when an addres is reported from a requested node.
* @brief when an addres is reported from a distant node.
*
* @param h: id
* @param id (type: InfoHash) id of the node.
* @param saddr (type: sockaddr*) sockaddr* pointer containing address ip information.
* @param saddr_len (type: socklen_t) lenght of the sockaddr struct.
*/
std::function<void(const InfoHash&, const SockAddr&)> onReportedAddr;
std::function<void(const InfoHash&, sockaddr*, socklen_t)> onReportedAddr;
/**
* Called on ping reception.
* @brief on ping request callback.
*
* @param node (type: Sp<Node>) the requesting node.
* @param node (type: std::shared_ptr<Node>) the requesting node.
*/
std::function<RequestAnswer(Sp<Node>)> onPing {};
std::function<RequestAnswer(std::shared_ptr<Node>)> onPing {};
/**
* Called on find node request.
* @brief on find node request callback.
*
* @param node (type: Sp<Node>) the requesting node.
* @param h (type: InfoHash) hash of the value of interest.
* @param node (type: std::shared_ptr<Node>) the requesting node.
* @param vhash (type: InfoHash) hash of the value of interest.
* @param want (type: want_t) states if nodes sent in the response are ipv4
* or ipv6.
*/
std::function<RequestAnswer(Sp<Node>, const InfoHash&, want_t)> onFindNode {};
std::function<RequestAnswer(std::shared_ptr<Node>,
InfoHash&,
want_t)> onFindNode {};
/**
* Called on "get values" request.
* @brief on "get values" request callback.
*
* @param node (type: Sp<Node>) the requesting node.
* @param h (type: InfoHash) hash of the value of interest.
* @param node (type: std::shared_ptr<Node>) the requesting node.
* @param vhash (type: InfoHash) hash of the value of interest.
* @param want (type: want_t) states if nodes sent in the response are ipv4
* or ipv6.
*/
std::function<RequestAnswer(Sp<Node>, const InfoHash&, want_t, const Query&)> onGetValues {};
std::function<RequestAnswer(std::shared_ptr<Node>,
InfoHash&,
want_t)> onGetValues {};
/**
* Called on listen request.
* @brief on listen request callback.
*
* @param node (type: Sp<Node>) the requesting node.
* @param h (type: InfoHash) hash of the value of interest.
* @param node (type: std::shared_ptr<Node>) the requesting node.
* @param vhash (type: InfoHash) hash of the value of interest.
* @param token (type: Blob) security token.
* @param rid (type: uint16_t) request id.
*/
std::function<RequestAnswer(Sp<Node>,
const InfoHash&,
const Blob&,
Tid,
const Query&)> onListen {};
std::function<RequestAnswer(std::shared_ptr<Node>,
InfoHash&,
Blob&,
uint16_t)> onListen {};
/**
* Called on announce request.
* @brief on announce request callback.
*
* @param node (type: Sp<Node>) the requesting node.
* @param h (type: InfoHash) hash of the value of interest.
* @param node (type: std::shared_ptr<Node>) the requesting node.
* @param vhash (type: InfoHash) hash of the value of interest.
* @param token (type: Blob) security token.
* @param values (type: std::vector<Sp<Value>>) values to store.
* @param values (type: std::vector<std::shared_ptr<Value>>) values to store.
* @param created (type: time_point) time when the value was created.
*/
std::function<RequestAnswer(Sp<Node>,
const InfoHash&,
const Blob&,
const std::vector<Sp<Value>>&,
const time_point&)> onAnnounce {};
/**
* Called on refresh request.
*
* @param node (type: Sp<Node>) the requesting node.
* @param h (type: InfoHash) hash of the value of interest.
* @param token (type: Blob) security token.
* @param vid (type: Value::id) the value id.
*/
std::function<RequestAnswer(Sp<Node>,
const InfoHash&,
const Blob&,
const Value::Id&)> onRefresh {};
std::function<RequestAnswer(std::shared_ptr<Node>,
InfoHash&,
Blob&,
std::vector<std::shared_ptr<Value>>,
time_point)> onAnnounce {};
public:
using RequestCb = std::function<void(const Request&, RequestAnswer&&)>;
using RequestExpiredCb = std::function<void(const Request&, bool)>;
NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rd, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
NetworkEngine(
InfoHash& myid,
NetworkConfig config,
std::unique_ptr<DatagramSocket>&& sock,
const Sp<Logger>& log,
std::mt19937_64& rd,
Scheduler& scheduler,
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
decltype(NetworkEngine::onPing)&& onPing,
decltype(NetworkEngine::onFindNode)&& onFindNode,
decltype(NetworkEngine::onGetValues)&& onGetValues,
decltype(NetworkEngine::onListen)&& onListen,
decltype(NetworkEngine::onAnnounce)&& onAnnounce,
decltype(NetworkEngine::onRefresh)&& onRefresh);
~NetworkEngine();
net::DatagramSocket* getSocket() const { return dht_socket.get(); };
NetworkEngine(Logger& log, Scheduler& scheduler) : myid(zeroes), DHT_LOG(log), scheduler(scheduler) {}
NetworkEngine(InfoHash& myid, int s, int s6, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError) onError,
decltype(NetworkEngine::onNewNode) onNewNode,
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
decltype(NetworkEngine::onPing) onPing,
decltype(NetworkEngine::onFindNode) onFindNode,
decltype(NetworkEngine::onGetValues) onGetValues,
decltype(NetworkEngine::onListen) onListen,
decltype(NetworkEngine::onAnnounce) onAnnounce) :
onError(onError), onNewNode(onNewNode), onReportedAddr(onReportedAddr), onPing(onPing), onFindNode(onFindNode),
onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), myid(myid),
dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
{
transaction_id = std::uniform_int_distribution<decltype(transaction_id)>{1}(rd_device);
}
virtual ~NetworkEngine() {
clear();
};
void clear();
/**
* Sends values (with closest nodes) to a listenner.
*
* @param sa The address of the listenner.
* @param sslen The length of the sockaddr structure.
* @param socket_id The tid to use to write to the request socket.
* @param hash The hash key of the value.
* @param want Wether to send ipv4 and/or ipv6 nodes.
* @param ntoken Listen security token.
* @param nodes The ipv4 closest nodes.
* @param nodes6 The ipv6 closest nodes.
* @param values The values to send.
* @param sa The address of the listenner.
* @param sslen The length of the sockaddr structure.
* @param rid The request id of the initial listen request.
* @param hash The hash key of the value.
* @param want Wether to send ipv4 and/or ipv6 nodes.
* @param ntoken Listen security token.
* @param nodes The ipv4 closest nodes.
* @param nodes6 The ipv6 closest nodes.
* @param values The values to send.
*/
void tellListener(Sp<Node> n, Tid socket_id, const InfoHash& hash, want_t want, const Blob& ntoken,
std::vector<Sp<Node>>&& nodes, std::vector<Sp<Node>>&& nodes6,
std::vector<Sp<Value>>&& values, const Query& q);
void tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector<Value::Id>& values);
void tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector<Value::Id>& values);
void tellListener(std::shared_ptr<Node> n, uint16_t rid, InfoHash hash, want_t want, Blob ntoken,
std::vector<std::shared_ptr<Node>> nodes, std::vector<std::shared_ptr<Node>> nodes6,
std::vector<std::shared_ptr<Value>> values);
bool isRunning(sa_family_t af) const;
inline want_t want () const { return dht_socket->hasIPv4() and dht_socket->hasIPv6() ? (WANT4 | WANT6) : -1; }
void connectivityChanged(sa_family_t);
inline want_t want () const { return dht_socket >= 0 && dht_socket6 >= 0 ? (WANT4 | WANT6) : -1; }
/**************
* Requests *
**************/
/**
* Send a "ping" request to a given node.
*
* @param n The node.
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
Sp<Request>
sendPing(Sp<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
/**
* Send a "ping" request to a given node.
*
* @param sa The node's ip sockaddr info.
* @param salen The associated sockaddr struct length.
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
Sp<Request>
sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
return sendPing(std::make_shared<Node>(zeroes, std::move(sa), rd),
std::forward<RequestCb>(on_done),
std::forward<RequestExpiredCb>(on_expired));
}
/**
* Send a "find node" request to a given node.
*
* @param n The node.
* @param target The target hash.
* @param want Indicating wether IPv4 or IPv6 are wanted in response.
* Use NetworkEngine::want()
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
Sp<Request> sendFindNode(Sp<Node> n,
const InfoHash& hash,
want_t want = -1,
RequestCb&& on_done = {},
RequestExpiredCb&& on_expired = {});
/**
* Send a "get" request to a given node.
*
* @param n The node.
* @param hash The target hash.
* @param query The query describing filters.
* @param token A security token.
* @param want Indicating wether IPv4 or IPv6 are wanted in response.
* Use NetworkEngine::want()
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
Sp<Request> sendGetValues(Sp<Node> n,
const InfoHash& hash,
const Query& query,
want_t want,
RequestCb&& on_done,
RequestExpiredCb&& on_expired);
/**
* Send a "listen" request to a given node.
*
* @param n The node.
* @param hash The storage's hash.
* @param query The query describing filters.
* @param token A security token.
* @param previous The previous request "listen" sent to this node.
* @param socket **UNUSED** The socket for further response.
*
* For backward compatibility purpose, sendListen has to
* handle creation of the socket. Therefor, you cannot
* use openSocket yourself. TODO: Once we don't support
* the old "listen" negociation, sendListen shall not
* create the socket itself.
*
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
* @param socket_cb Callback to execute each time new updates arrive on
* the socket.
*
* @return the request with information concerning its success.
*/
Sp<Request> sendListen(Sp<Node> n,
const InfoHash& hash,
const Query& query,
const Blob& token,
Sp<Request> previous,
RequestCb&& on_done,
RequestExpiredCb&& on_expired,
SocketCb&& socket_cb);
/**
* Send a "announce" request to a given node.
*
* @param n The node.
* @param hash The target hash.
* @param created The time when the value was created (avoiding extended
* value lifetime)
* @param token A security token.
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
Sp<Request> sendAnnounceValue(Sp<Node> n,
const InfoHash& hash,
const Sp<Value>& v,
time_point created,
const Blob& token,
RequestCb&& on_done,
RequestExpiredCb&& on_expired);
/**
* Send a "refresh" request to a given node. Asks a node to keep the
* associated value Value.type.expiration more minutes in its storage.
*
* @param n The node.
* @param hash The target hash.
* @param vid The value id.
* @param token A security token.
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
Sp<Request> sendRefreshValue(Sp<Node> n,
const InfoHash& hash,
const Value::Id& vid,
const Blob& token,
RequestCb&& on_done,
RequestExpiredCb&& on_expired);
std::shared_ptr<Request>
sendPing(std::shared_ptr<Node> n, RequestCb on_done, RequestExpiredCb on_expired);
std::shared_ptr<Request>
sendPing(const sockaddr* sa, socklen_t salen, RequestCb on_done, RequestExpiredCb on_expired) {
return sendPing(std::make_shared<Node>(zeroes, sa, salen), on_done, on_expired);
}
std::shared_ptr<Request>
sendFindNode(std::shared_ptr<Node> n,
const InfoHash& target,
want_t want,
RequestCb on_done,
RequestExpiredCb on_expired);
std::shared_ptr<Request>
sendGetValues(std::shared_ptr<Node> n,
const InfoHash& target,
want_t want,
RequestCb on_done,
RequestExpiredCb on_expired);
std::shared_ptr<Request>
sendListen(std::shared_ptr<Node> n,
const InfoHash& infohash,
const Blob& token,
RequestCb on_done,
RequestExpiredCb on_expired);
std::shared_ptr<Request>
sendAnnounceValue(std::shared_ptr<Node> n,
const InfoHash& infohash,
const Value& v,
time_point created,
const Blob& token,
RequestCb on_done,
RequestExpiredCb on_expired);
/**
* Parses a message and calls appropriate callbacks.
@@ -411,12 +342,10 @@ public:
* @param fromlen The length of the corresponding sockaddr structure.
* @param now The time to adjust the clock in the network engine.
*/
void processMessage(const uint8_t *buf, size_t buflen, SockAddr addr);
void processMessage(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen);
Sp<Node> insertNode(const InfoHash& myid, const SockAddr& addr) {
auto n = cache.getNode(myid, addr, scheduler.time(), 0);
onNewNode(n, 0);
return n;
std::shared_ptr<Node> insertNode(const InfoHash& myid, const sockaddr* from, socklen_t fromlen) {
return cache.getNode(myid, from, fromlen, scheduler.time(), 0);
}
std::vector<unsigned> getNodeMessageStats(bool in) {
@@ -426,146 +355,113 @@ public:
return stats;
}
void blacklistNode(const Sp<Node>& n);
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) {
return cache.getCachedNodes(id, sa_f, count);
}
size_t getNodeCacheSize() const {
return cache.size();
}
size_t getNodeCacheSize(sa_family_t af) const {
return cache.size(af);
}
size_t getRateLimiterSize() const {
return address_rate_limiter.size();
}
size_t getPartialCount() const {
return partial_messages.size();
}
void blacklistNode(const std::shared_ptr<Node>& n);
private:
struct PartialMessage;
/***************
* Constants *
***************/
static constexpr long unsigned MAX_REQUESTS_PER_SEC {1600};
/* the length of a node info buffer in ipv4 format */
static const constexpr size_t NODE4_INFO_BUF_LEN {HASH_LEN + sizeof(in_addr) + sizeof(in_port_t)};
static const constexpr size_t NODE4_INFO_BUF_LEN {26};
/* the length of a node info buffer in ipv6 format */
static const constexpr size_t NODE6_INFO_BUF_LEN {HASH_LEN + sizeof(in6_addr) + sizeof(in_port_t)};
/* after a UDP reply, the period during which we tell the link layer about it */
static const constexpr size_t NODE6_INFO_BUF_LEN {38};
/* TODO */
static constexpr std::chrono::seconds UDP_REPLY_TIME {15};
/* Max. time to receive a full fragmented packet */
static constexpr std::chrono::seconds RX_MAX_PACKET_TIME {10};
/* Max. time between packet fragments */
static constexpr std::chrono::seconds RX_TIMEOUT {3};
/* The maximum number of nodes that we snub. There is probably little
reason to increase this value. */
static constexpr unsigned BLACKLISTED_MAX {10};
static constexpr size_t MTU {1280};
static constexpr size_t MAX_PACKET_VALUE_SIZE {600};
/* TODO */
static const std::string my_v;
void process(std::unique_ptr<ParsedMessage>&&, const SockAddr& from);
/* DHT info */
const InfoHash& myid;
const int dht_socket {-1};
const int dht_socket6 {-1};
const Logger& DHT_LOG;
bool rateLimit(const SockAddr& addr);
NodeCache cache {};
sockaddr_storage blacklist[BLACKLISTED_MAX] {};
unsigned next_blacklisted = 0;
static bool isMartian(const SockAddr& addr);
bool isNodeBlacklisted(const SockAddr& addr) const;
bool rateLimit();
void requestStep(Sp<Request> req);
static bool isMartian(const sockaddr* sa, socklen_t len);
bool isNodeBlacklisted(const sockaddr*, socklen_t) const;
void requestStep(std::shared_ptr<Request> req);
/**
* Sends a request to a node. Request::MAX_ATTEMPT_COUNT attempts will
* be made before the request expires.
*/
void sendRequest(const Sp<Request>& request);
void sendRequest(std::shared_ptr<Request>& request);
/**
* Generates a new request id, skipping the invalid id.
*
* @return the new id.
*/
uint16_t getNewTid() {
++transaction_id;
return transaction_id == TransId::INVALID ? ++transaction_id : transaction_id;
}
struct MessageStats {
unsigned ping {0};
unsigned find {0};
unsigned get {0};
unsigned put {0};
unsigned listen {0};
unsigned refresh {0};
unsigned ping {0};
unsigned find {0};
unsigned get {0};
unsigned put {0};
unsigned listen {0};
};
// basic wrapper for socket sendto function
int send(const SockAddr& addr, const char *buf, size_t len, bool confirmed = false);
void sendValueParts(const TransId& tid, const std::vector<Blob>& svals, const SockAddr& addr);
std::vector<Blob> packValueHeader(msgpack::sbuffer&, const std::vector<Sp<Value>>&);
void maintainRxBuffer(Tid tid);
int send(const char *buf, size_t len, int flags, const sockaddr *sa, socklen_t salen);
/*************
* Answers *
*************/
/* answer to a ping request */
void sendPong(const SockAddr& addr, Tid tid);
void sendPong(const sockaddr* sa, socklen_t salen, TransId tid);
/* answer to findnodes/getvalues request */
void sendNodesValues(const SockAddr& addr,
Tid tid,
void sendNodesValues(const sockaddr* sa,
socklen_t salen,
TransId tid,
const Blob& nodes,
const Blob& nodes6,
const std::vector<Sp<Value>>& st,
const Query& query,
const std::vector<std::shared_ptr<Value>>& st,
const Blob& token);
Blob bufferNodes(sa_family_t af, const InfoHash& id, std::vector<Sp<Node>>& nodes);
Blob bufferNodes(sa_family_t af, const InfoHash& id, std::vector<std::shared_ptr<Node>>& nodes);
std::pair<Blob, Blob> bufferNodes(sa_family_t af,
const InfoHash& id,
want_t want,
std::vector<Sp<Node>>& nodes,
std::vector<Sp<Node>>& nodes6);
std::vector<std::shared_ptr<Node>>& nodes,
std::vector<std::shared_ptr<Node>>& nodes6);
/* answer to a listen request */
void sendListenConfirmation(const SockAddr& addr, Tid tid);
void sendListenConfirmation(const sockaddr* sa, socklen_t salen, TransId tid);
/* answer to put request */
void sendValueAnnounced(const SockAddr& addr, Tid, Value::Id);
void sendValueAnnounced(const sockaddr* sa, socklen_t salen, TransId, Value::Id);
/* answer in case of error */
void sendError(const SockAddr& addr,
Tid tid,
void sendError(const sockaddr* sa,
socklen_t salen,
TransId tid,
uint16_t code,
const std::string& message,
bool include_id=false);
void deserializeNodes(ParsedMessage& msg, const SockAddr& from);
void deserializeNodesValues(ParsedMessage& msg);
/* DHT info */
const InfoHash& myid;
const NetworkConfig config {};
const std::unique_ptr<DatagramSocket> dht_socket;
Sp<Logger> logger_;
std::mt19937_64& rd;
NodeCache cache;
// global limiting should be triggered by at least 8 different IPs
using IpLimiter = RateLimiter;
using IpLimiterMap = std::map<SockAddr, IpLimiter, SockAddr::ipCmp>;
IpLimiterMap address_rate_limiter;
RateLimiter rate_limiter;
ssize_t limiter_maintenance {0};
std::queue<time_point> rate_limit_time {};
static std::mt19937 rd_device;
// requests handling
std::map<Tid, Sp<Request>> requests {};
std::map<Tid, PartialMessage> partial_messages;
uint16_t transaction_id {1};
std::map<uint16_t, std::shared_ptr<Request>> requests {};
MessageStats in_stats {}, out_stats {};
std::set<SockAddr> blacklist {};
Scheduler& scheduler;
bool logIncoming_ {false};
};
} /* namespace net */
} /* namespace dht */
}
-161
View File
@@ -1,161 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "def.h"
#include "sockaddr.h"
#include "utils.h"
#include "log_enable.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
#include <functional>
#include <thread>
#include <atomic>
#include <mutex>
#include <list>
namespace dht {
namespace net {
static const constexpr in_port_t DHT_DEFAULT_PORT = 4222;
static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16;
static const constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(650);
int bindSocket(const SockAddr& addr, SockAddr& bound);
bool setNonblocking(int fd, bool nonblocking = true);
#ifdef _WIN32
void udpPipe(int fds[2]);
#endif
struct ReceivedPacket {
Blob data;
SockAddr from;
time_point received;
};
using PacketList = std::list<ReceivedPacket>;
class OPENDHT_PUBLIC DatagramSocket {
public:
/** A function that takes a list of new received packets and
* optionally returns consumed packets for recycling.
**/
using OnReceive = std::function<PacketList(PacketList&& packets)>;
virtual ~DatagramSocket() {};
virtual int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) = 0;
inline void setOnReceive(OnReceive&& cb) {
std::lock_guard<std::mutex> lk(lock);
rx_callback = std::move(cb);
}
virtual bool hasIPv4() const = 0;
virtual bool hasIPv6() const = 0;
SockAddr getBound(sa_family_t family = AF_UNSPEC) const {
std::lock_guard<std::mutex> lk(lock);
return getBoundRef(family);
}
in_port_t getPort(sa_family_t family = AF_UNSPEC) const {
std::lock_guard<std::mutex> lk(lock);
return getBoundRef(family).getPort();
}
virtual const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const = 0;
/** Virtual resolver mothod allows to implement custom resolver */
virtual std::vector<SockAddr> resolve(const std::string& host, const std::string& service = {}) {
return SockAddr::resolve(host, service);
}
virtual void stop() = 0;
protected:
PacketList getNewPacket() {
PacketList pkts;
if (toRecycle_.empty()) {
pkts.emplace_back();
} else {
auto begIt = toRecycle_.begin();
auto begItNext = std::next(begIt);
pkts.splice(pkts.end(), toRecycle_, begIt, begItNext);
}
return pkts;
}
inline void onReceived(PacketList&& packets) {
std::lock_guard<std::mutex> lk(lock);
if (rx_callback) {
auto r = rx_callback(std::move(packets));
if (not r.empty() and toRecycle_.size() < RX_QUEUE_MAX_SIZE)
toRecycle_.splice(toRecycle_.end(), std::move(r));
}
}
protected:
mutable std::mutex lock;
private:
OnReceive rx_callback;
PacketList toRecycle_;
};
class OPENDHT_PUBLIC UdpSocket : public DatagramSocket {
public:
UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l = {});
UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l = {});
~UdpSocket();
int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) override;
const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const override {
return (family == AF_INET6) ? bound6 : bound4;
}
bool hasIPv4() const override {
std::lock_guard<std::mutex> lk(lock);
return s4 != -1;
}
bool hasIPv6() const override {
std::lock_guard<std::mutex> lk(lock);
return s6 != -1;
}
void stop() override;
private:
std::shared_ptr<Logger> logger;
int s4 {-1};
int s6 {-1};
int stopfd {-1};
SockAddr bound4, bound6;
std::thread rcv_thread {};
std::atomic_bool running {false};
void openSockets(const SockAddr& bind4, const SockAddr& bind6);
};
}
}
+36 -107
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,137 +14,70 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "infohash.h" // includes socket structures
#include "utils.h"
#include "sockaddr.h"
#include <list>
#include <map>
namespace dht {
struct Node;
namespace net {
struct Request;
struct Socket;
struct RequestAnswer;
} /* namespace net */
using Tid = uint32_t;
using SocketCb = std::function<void(const Sp<Node>&, net::RequestAnswer&&)>;
struct Socket {
Socket() {}
Socket(SocketCb&& on_receive) :
on_receive(std::move(on_receive)) {}
SocketCb on_receive {};
};
struct Node {
const InfoHash id;
friend class NetworkEngine;
Node(const InfoHash& id, const SockAddr& addr, std::mt19937_64& rd, bool client=false);
Node(const InfoHash& id, SockAddr&& addr, std::mt19937_64& rd, bool client=false);
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen, std::mt19937_64& rd)
: Node(id, SockAddr(sa, salen), rd) {}
InfoHash id;
socklen_t sslen {0};
sockaddr_storage ss;
time_point time {time_point::min()}; /* last time eared about */
time_point reply_time {time_point::min()}; /* time of last correct reply received */
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen)
: id(id), sslen(salen), ss() {
std::copy_n((const uint8_t*)sa, salen, (uint8_t*)&ss);
if ((unsigned)salen < sizeof(ss))
std::fill_n((uint8_t*)&ss+salen, sizeof(ss)-salen, 0);
}
InfoHash getId() const {
return id;
}
const SockAddr& getAddr() const { return addr; }
std::pair<const sockaddr*, socklen_t> getAddr() const {
return {(const sockaddr*)&ss, sslen};
}
std::string getAddrStr() const {
return addr.toString();
return print_addr(ss, sslen);
}
bool isClient() const { return is_client; }
bool isIncoming() { return time > reply_time; }
const time_point& getTime() const { return time; }
const time_point& getReplyTime() const { return reply_time; }
void setTime(const time_point& t) { time = t; }
/**
* Makes notice about an additionnal authentication error with this node. Up
* to MAX_AUTH_ERRORS errors are accepted in order to let the node recover.
* Upon this limit, the node expires.
*/
void authError() {
if (++auth_errors > MAX_AUTH_ERRORS)
setExpired();
}
void authSuccess() { auth_errors = 0; }
bool isExpired() const { return expired_; }
bool isGood(time_point now) const;
bool isPendingMessage() const;
size_t getPendingMessageCount() const;
bool isOld(const time_point& now) const {
return time + NODE_EXPIRE_TIME < now;
}
bool isRemovable(const time_point& now) const {
return isExpired() and isOld(now);
}
NodeExport exportNode() const { return NodeExport {id, ss, sslen}; }
sa_family_t getFamily() const { return ss.ss_family; }
NodeExport exportNode() const {
NodeExport ne;
ne.id = id;
ne.sslen = addr.getLength();
std::memcpy(&ne.ss, addr.get(), ne.sslen);
return ne;
}
sa_family_t getFamily() const { return addr.getFamily(); }
void update(const sockaddr* sa, socklen_t salen);
void update(const SockAddr&);
void requested(const Sp<net::Request>& req);
void received(time_point now, const Sp<net::Request>& req);
Sp<net::Request> getRequest(Tid tid);
void cancelRequest(const Sp<net::Request>& req);
void requested(std::shared_ptr<Request>& req);
void received(time_point now, std::shared_ptr<Request> req);
void setExpired();
/**
* Opens a socket on which a node will be able allowed to write for further
* additionnal updates following the response to a previous request.
*
* @param node The node which will be allowed to write on this socket.
* @param cb The callback to execute once updates arrive on the socket.
*
* @return the socket.
*/
Tid openSocket(SocketCb&& cb);
Sp<Socket> getSocket(Tid id);
/**
* Closes a socket so that no further data will be red on that socket.
*
* @param socket The socket to close.
*/
void closeSocket(Tid id);
/**
* Resets the state of the node so it's not expired anymore.
*/
void reset() { expired_ = false; reply_time = time_point::min(); }
/**
* Generates a new request id, skipping the invalid id.
*
* @return the new id.
*/
Tid getNewTid() {
++transaction_id;
return transaction_id ? ++transaction_id : transaction_id;
}
void reset() { expired_ = false; }
std::string toString() const;
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Node& h);
friend std::ostream& operator<< (std::ostream& s, const Node& h);
static constexpr const std::chrono::minutes NODE_GOOD_TIME {120};
@@ -155,20 +88,16 @@ struct Node {
static constexpr const std::chrono::seconds MAX_RESPONSE_TIME {1};
private:
/* Number of times we accept authentication errors from this node. */
static const constexpr unsigned MAX_AUTH_ERRORS {3};
SockAddr addr;
bool is_client {false};
time_point time {time_point::min()}; /* last time eared about */
time_point reply_time {time_point::min()}; /* time of last correct reply received */
unsigned auth_errors {0};
std::list<std::weak_ptr<Request>> requests_ {};
bool expired_ {false};
Tid transaction_id;
using TransactionDist = std::uniform_int_distribution<decltype(transaction_id)>;
std::map<Tid, Sp<net::Request>> requests_ {};
std::map<Tid, Sp<Socket>> sockets_;
void clearPendingQueue() {
requests_.remove_if([](std::weak_ptr<Request>& w) {
return w.expired();
});
}
};
}
+8 -27
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,7 +13,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
@@ -26,16 +27,8 @@
namespace dht {
struct NodeCache {
size_t size(sa_family_t family) const {
return cache(family).count();
}
size_t size() const {
return size(AF_INET) + size(AF_INET6);
}
Sp<Node> getNode(const InfoHash& id, sa_family_t family);
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client=false);
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) const;
std::shared_ptr<Node> getNode(const InfoHash& id, sa_family_t family);
std::shared_ptr<Node> getNode(const InfoHash& id, const sockaddr* sa, socklen_t sa_len, time_point now, int confirmed);
/**
* Reset the connectivity state of every node,
@@ -44,28 +37,16 @@ struct NodeCache {
*/
void clearBadNodes(sa_family_t family = 0);
NodeCache(std::mt19937_64& r) : rd(r) {};
~NodeCache();
private:
class NodeMap : private std::map<InfoHash, std::weak_ptr<Node>> {
class NodeMap : public std::map<InfoHash, std::weak_ptr<Node>> {
public:
Sp<Node> getNode(const InfoHash& id);
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client, std::mt19937_64& rd);
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, size_t count) const;
std::shared_ptr<Node> getNode(const InfoHash& id);
std::shared_ptr<Node> getNode(const InfoHash& id, const sockaddr* sa, socklen_t sa_len, time_point now, int confirmed);
void clearBadNodes();
void setExpired();
void cleanup();
size_t count() const { return size(); }
private:
size_t cleanup_counter {0};
};
const NodeMap& cache(sa_family_t af) const { return af == AF_INET ? cache_4 : cache_6; }
NodeMap& cache(sa_family_t af) { return af == AF_INET ? cache_4 : cache_6; }
NodeMap cache_4;
NodeMap cache_6;
std::mt19937_64& rd;
};
}
-95
View File
@@ -1,95 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "def.h"
#include "sockaddr.h"
#include "infohash.h"
#include "log_enable.h"
#include <thread>
namespace asio {
class io_context;
}
namespace dht {
class OPENDHT_PUBLIC PeerDiscovery
{
public:
static constexpr in_port_t DEFAULT_PORT = 8888;
using ServiceDiscoveredCallback = std::function<void(msgpack::object&&, SockAddr&&)>;
PeerDiscovery(in_port_t port = DEFAULT_PORT, std::shared_ptr<asio::io_context> ioContext = {}, std::shared_ptr<Logger> logger = {});
~PeerDiscovery();
/**
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
*/
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
template<typename T>
void startDiscovery(const std::string &type, std::function<void(T&&, SockAddr&&)> cb) {
startDiscovery(type, [cb](msgpack::object&& ob, SockAddr&& addr) {
cb(ob.as<T>(), std::move(addr));
});
}
/**
* startPublish - Keeping sending data until node is joinned or stop is called
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
void startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf);
template<typename T>
void startPublish(const std::string &type, const T& object) {
msgpack::sbuffer buf;
msgpack::pack(buf, object);
startPublish(type, buf);
}
/**
* Thread Stopper
*/
void stop();
/**
* Remove possible callBack to discovery
*/
bool stopDiscovery(const std::string &type);
/**
* Remove different serivce message to send
*/
bool stopPublish(const std::string &type);
bool stopPublish(sa_family_t domain, const std::string &type);
void connectivityChanged();
private:
class DomainPeerDiscovery;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery6_;
std::shared_ptr<asio::io_context> ioContext_;
std::thread ioRunnner_;
};
}
-31
View File
@@ -1,31 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <chrono>
namespace dht {
namespace proxy {
constexpr const std::chrono::hours OP_TIMEOUT {24}; // one day
constexpr const std::chrono::hours OP_MARGIN {2}; // two hours
constexpr const char* const HTTP_PROTO {"http://"};
using ListenToken = uint64_t;
}
}
-56
View File
@@ -1,56 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "utils.h"
#include <queue>
namespace dht {
class RateLimiter {
public:
RateLimiter(size_t quota, const duration& period = std::chrono::seconds(1))
: quota_(quota), period_(period) {}
/** Clear outdated records and return current quota usage */
size_t maintain(const time_point& now) {
auto limit = now - period_;
while (not records.empty() and records.front() < limit)
records.pop();
return records.size();
}
/** Return false if quota is reached, insert record and return true otherwise. */
bool limit(const time_point& now) {
if (quota_ == std::numeric_limits<size_t>::max())
return true;
if (maintain(now) >= quota_)
return false;
records.emplace(now);
return true;
}
bool empty() const {
return records.empty();
}
private:
const size_t quota_;
const duration period_;
std::queue<time_point> records {};
};
}
+23 -49
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,17 +14,11 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "net.h"
#include "value.h"
namespace dht {
struct Node;
namespace net {
class NetworkEngine;
struct ParsedMessage;
@@ -38,9 +32,8 @@ struct ParsedMessage;
* request is done.
*/
struct Request {
friend class dht::net::NetworkEngine;
Sp<Node> node {}; /* the node to whom the request is destined. */
friend class dht::NetworkEngine;
std::shared_ptr<Node> node {}; /* the node to whom the request is destined. */
time_point reply_time {time_point::min()}; /* time when we received the response to the request. */
enum class State
@@ -57,30 +50,15 @@ struct Request {
bool pending() const { return state_ == State::PENDING; }
bool over() const { return not pending(); }
State getState() const { return state_; }
char getStateChar() const {
switch (state_) {
case State::PENDING: return 'f';
case State::CANCELLED: return 'c';
case State::EXPIRED: return 'e';
case State::COMPLETED: return 'a';
default: return '?';
}
}
Request(State state = State::PENDING) : state_(state) {}
Request(MessageType type, Tid tid,
Sp<Node> node,
Request() {}
Request(uint16_t tid,
std::shared_ptr<Node> node,
Blob&& msg,
std::function<void(const Request&, ParsedMessage&&)> on_done,
std::function<void(const Request&, bool)> on_expired,
Tid socket = 0) :
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)), socket(socket) { }
Tid getTid() const { return tid; }
MessageType getType() const { return type; }
Tid getSocket() { return socket; }
Tid closeSocket() { auto ret = socket; socket = 0; return ret; }
std::function<void(const Request& req_status, ParsedMessage&&)> on_done,
std::function<void(const Request& req_status, bool)> on_expired,
bool persistent = false) :
node(node), on_done(on_done), on_expired(on_expired), tid(tid), msg(std::move(msg)), persistent(persistent) { }
void setExpired() {
if (pending()) {
@@ -90,10 +68,11 @@ struct Request {
}
}
void setDone(ParsedMessage&& msg) {
if (pending()) {
if (pending() or persistent) {
state_ = Request::State::COMPLETED;
on_done(*this, std::forward<ParsedMessage>(msg));
clear();
if (not persistent)
clear();
}
}
@@ -108,32 +87,27 @@ private:
static const constexpr size_t MAX_ATTEMPT_COUNT {3};
bool isExpired(time_point now) const {
return pending() and now > last_try + attempt_duration and attempt_count >= Request::MAX_ATTEMPT_COUNT;
return pending() and now > last_try + Node::MAX_RESPONSE_TIME and attempt_count >= Request::MAX_ATTEMPT_COUNT;
}
void clear() {
on_done = {};
on_expired = {};
msg = {};
parts = {};
msg.clear();
}
const Tid tid {0}; /* the request id. */
const MessageType type {};
State state_ {State::PENDING};
unsigned attempt_count {0}; /* number of attempt to process the request. */
duration attempt_duration {((duration)Node::MAX_RESPONSE_TIME)/2};
time_point start {time_point::min()}; /* time when the request is created. */
time_point last_try {time_point::min()}; /* time of the last attempt to process the request. */
std::function<void(const Request&, ParsedMessage&&)> on_done {};
std::function<void(const Request&, bool)> on_expired {};
std::function<void(const Request& req_status, ParsedMessage&&)> on_done {};
std::function<void(const Request& req_status, bool)> on_expired {};
Blob msg {}; /* the serialized message. */
std::vector<Blob> parts;
Tid socket; /* the socket used for further reponses. */
const uint16_t tid {0}; /* the request id. */
Blob msg {}; /* the serialized message. */
const bool persistent {false}; /* the request is not erased upon completion. */
};
} /* namespace net */
}
+6 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,19 +13,18 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <random>
#include <algorithm>
#include <functional>
namespace dht {
namespace crypto {
#ifndef _MSC_VER
#ifndef WIN32_NATIVE
#ifdef _WIN32
/**
@@ -43,8 +42,8 @@ public:
* result_type is unsigned int so this is currently safe.
*/
static_assert(
sizeof(result_type) == 2 ||
sizeof(result_type) == 4 ||
sizeof(result_type) == 2 ||
sizeof(result_type) == 4 ||
sizeof(result_type) == 8,
"result_type must be 16, 32 or 64 bits");
@@ -108,14 +107,4 @@ using random_device = std::random_device;
using random_device = std::random_device;
#endif
template<class T = std::mt19937, std::size_t N = T::state_size>
auto getSeededRandomEngine () -> typename std::enable_if<!!N, T>::type {
typename T::result_type random_data[N];
random_device source;
std::generate(std::begin(random_data), std::end(random_data), std::ref(source));
std::seed_seq seeds(std::begin(random_data), std::end(random_data));
T seededEngine (seeds);
return seededEngine;
}
}} // dht::crypto
+9 -32
View File
@@ -1,7 +1,6 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,7 +13,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
@@ -23,42 +23,27 @@
namespace dht {
static constexpr unsigned TARGET_NODES {8};
namespace net {
class NetworkEngine;
}
struct Bucket {
Bucket() : cached() {}
Bucket(sa_family_t af, const InfoHash& f = {}, time_point t = time_point::min())
: af(af), first(f), time(t), cached() {}
sa_family_t af {0};
InfoHash first {};
time_point time {time_point::min()}; /* time of last reply in this bucket */
std::list<Sp<Node>> nodes {};
Sp<Node> cached; /* the address of a likely candidate */
time_point time {time_point::min()}; /* time of last reply in this bucket */
std::list<std::shared_ptr<Node>> nodes {};
std::shared_ptr<Node> cached; /* the address of a likely candidate */
/** Return a random node in a bucket. */
Sp<Node> randomNode(std::mt19937_64& rd);
void sendCachedPing(net::NetworkEngine& ne);
void connectivityChanged() {
time = time_point::min();
for (auto& node : nodes)
node->setTime(time_point::min());
}
std::shared_ptr<Node> randomNode();
};
class RoutingTable : public std::list<Bucket> {
public:
using std::list<Bucket>::list;
time_point grow_time {time_point::min()};
bool is_client {false};
InfoHash middle(const RoutingTable::const_iterator&) const;
std::vector<Sp<Node>> findClosestNodes(const InfoHash id, time_point now, size_t count = TARGET_NODES) const;
std::vector<std::shared_ptr<Node>> findClosestNodes(const InfoHash id, time_point now, size_t count = TARGET_NODES) const;
RoutingTable::iterator findBucket(const InfoHash& id);
RoutingTable::const_iterator findBucket(const InfoHash& id) const;
@@ -78,18 +63,10 @@ public:
return empty() || (size() == 1 && front().nodes.empty());
}
void connectivityChanged(const time_point& now) {
grow_time = now;
for (auto& b : *this)
b.connectivityChanged();
}
bool onNewNode(const Sp<Node>& node, int comfirm, const time_point& now, const InfoHash& myid, net::NetworkEngine& ne);
/**
* Return a random id in the bucket's range.
*/
InfoHash randomId(const RoutingTable::const_iterator& bucket, std::mt19937_64& rd) const;
InfoHash randomId(const RoutingTable::const_iterator& bucket) const;
unsigned depth(const RoutingTable::const_iterator& bucket) const;
+20 -25
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,7 +14,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
@@ -36,9 +37,8 @@ namespace dht {
class Scheduler {
public:
struct Job {
Job(std::function<void()>&& f) : do_(std::move(f)) {}
Job(std::function<void()>&& f) : do_(std::forward<std::function<void()>>(f)) {}
std::function<void()> do_;
void cancel() { do_ = {}; }
};
/**
@@ -49,33 +49,27 @@ public:
*
* @return pointer to the newly scheduled job.
*/
Sp<Scheduler::Job> add(time_point t, std::function<void()>&& job_func) {
auto job = std::make_shared<Job>(std::move(job_func));
std::shared_ptr<Scheduler::Job> add(time_point t, std::function<void()>&& job_func) {
auto job = std::make_shared<Job>(std::forward<std::function<void()>>(job_func));
if (t != time_point::max())
timers.emplace(std::move(t), job);
return job;
}
void add(const Sp<Scheduler::Job>& job, time_point t) {
if (t != time_point::max())
timers.emplace(std::move(t), job);
}
/**
* Reschedules a job.
*
* @param time The time at which the job shall be rescheduled.
* @param job The job to edit.
* @param t The time at which the job shall be rescheduled.
*
* @return pointer to the newly scheduled job.
*/
void edit(Sp<Scheduler::Job>& job, time_point t) {
void edit(std::shared_ptr<Scheduler::Job>& job, time_point t) {
if (not job) {
std::cerr << "editing an empty job" << std::endl;
return;
}
// std::function move doesn't garantee to leave the object empty.
// Force clearing old value.
auto task = std::move(job->do_);
job->do_ = {};
job = add(t, std::move(task));
job = add(t, std::move(job->do_));
}
/**
@@ -84,6 +78,7 @@ public:
* @return The time for the next job to run.
*/
time_point run() {
syncTime();
while (not timers.empty()) {
auto timer = timers.begin();
/*
@@ -94,16 +89,17 @@ public:
if (timer->first > now)
break;
auto job = std::move(timer->second);
const auto& job = *timer->second;
if (job.do_)
job.do_();
timers.erase(timer);
if (job->do_)
job->do_();
}
return getNextJobTime();
}
inline time_point getNextJobTime() const {
//if (not timers.empty())
// std::cout << "Next job in " << print_dt(timers.begin()->first - clock::now()) << std::endl;
return timers.empty() ? time_point::max() : timers.begin()->first;
}
@@ -113,11 +109,10 @@ public:
*/
inline const time_point& time() const { return now; }
inline time_point syncTime() { return (now = clock::now()); }
inline void syncTime(const time_point& n) { now = n; }
private:
time_point now {clock::now()};
std::multimap<time_point, Sp<Job>> timers {}; /* the jobs ordered by time */
std::multimap<time_point, std::shared_ptr<Job>> timers {}; /* the jobs ordered by time */
};
}
+52 -248
View File
@@ -1,8 +1,6 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +13,19 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#pragma once
@@ -30,21 +40,13 @@
namespace dht {
class OPENDHT_PUBLIC SecureDht final : public DhtInterface {
class SecureDht : public Dht {
public:
typedef std::function<void(bool)> SignatureCheckCallback;
using Config = SecureDhtConfig;
static dht::Config getConfig(const SecureDht::Config& conf)
{
auto c = conf.node_config;
if (not c.node_id and conf.id.second)
c.node_id = InfoHash::get("node:"+conf.id.second->getId().toString());
return c;
}
SecureDht() {}
/**
@@ -53,16 +55,13 @@ public:
* id: the identity to use for the crypto layer and to compute
* our own hash on the Dht.
*/
SecureDht(std::unique_ptr<DhtInterface> dht, Config config);
SecureDht(int s, int s6, Config config);
virtual ~SecureDht();
InfoHash getId() const {
return key_ ? key_->getPublicKey().getId() : InfoHash();
}
PkId getLongId() const {
return key_ ? key_->getPublicKey().getLongId() : PkId();
}
ValueType secureType(ValueType&& type);
@@ -71,17 +70,14 @@ public:
return secureType(std::move(tmp_type));
}
void registerType(const ValueType& type) override {
if (dht_)
dht_->registerType(secureType(type));
virtual void registerType(const ValueType& type) {
Dht::registerType(secureType(type));
}
void registerType(ValueType&& type) {
if (dht_)
dht_->registerType(secureType(std::forward<ValueType>(type)));
virtual void registerType(ValueType&& type) {
Dht::registerType(secureType(std::forward<ValueType>(type)));
}
void registerInsecureType(const ValueType& type) {
if (dht_)
dht_->registerType(type);
virtual void registerInsecureType(const ValueType& type) {
Dht::registerType(type);
}
/**
@@ -89,21 +85,23 @@ public:
* If the signature can't be checked, or if the data can't be decrypted, it is not returned.
* Public, non-signed & non-encrypted data is retransmitted as-is.
*/
void get(const InfoHash& id, GetCallback cb, DoneCallback donecb={}, Value::Filter&& = {}, Where&& w = {}) override;
void get(const InfoHash& id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f = {}, Where&& w = {}) override {
get(id, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
virtual void get(const InfoHash& id, GetCallback cb, DoneCallback donecb={}, Value::Filter&& = {}) override;
virtual void get(const InfoHash& id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f = {}) override {
get(id, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f));
}
void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f), std::forward<Where>(w));
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}) override {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f));
}
void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}) override {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f));
}
virtual size_t listen(const InfoHash& id, GetCallback cb, Value::Filter&& = {}) override;
/**
* Will take ownership of the value, sign it using our private key and put it in the DHT.
*/
void putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback, bool permanent = false);
void putSigned(const InfoHash& hash, std::shared_ptr<Value> val, DoneCallback callback, bool permanent = false);
void putSigned(const InfoHash& hash, Value&& v, DoneCallback callback, bool permanent = false) {
putSigned(hash, std::make_shared<Value>(std::move(v)), callback, permanent);
}
@@ -113,7 +111,7 @@ public:
* and put it in the DHT.
* The operation will be immediate if the recipient' public key is known (otherwise it will be retrived first).
*/
void putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val, DoneCallback callback, bool permanent = false);
void putEncrypted(const InfoHash& hash, const InfoHash& to, std::shared_ptr<Value> val, DoneCallback callback, bool permanent = false);
void putEncrypted(const InfoHash& hash, const InfoHash& to, Value&& v, DoneCallback callback, bool permanent = false) {
putEncrypted(hash, to, std::make_shared<Value>(std::move(v)), callback, permanent);
}
@@ -127,14 +125,17 @@ public:
Value decrypt(const Value& v);
void findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb);
void findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb);
void findCertificate(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::Certificate>)> cb);
void findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::PublicKey>)> cb);
const Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
void registerCertificate(Sp<crypto::Certificate>& cert);
const std::shared_ptr<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
void registerCertificate(std::shared_ptr<crypto::Certificate>& cert);
const Sp<crypto::Certificate> getCertificate(const InfoHash& node) const;
const Sp<const crypto::PublicKey> getPublicKey(const InfoHash& node) const;
const std::shared_ptr<crypto::Certificate> getCertificate(const InfoHash& node) const;
const std::shared_ptr<crypto::PublicKey> getPublicKey(const InfoHash& node) const;
/**
* Allows to set a custom callback called by the library to find a locally-stored certificate.
@@ -145,227 +146,30 @@ public:
localQueryMethod_ = std::move(query_method);
}
/**
* SecureDht to Dht proxy
*/
void shutdown(ShutdownCallback cb) override {
dht_->shutdown(cb);
}
void dumpTables() const override {
dht_->dumpTables();
}
inline const InfoHash& getNodeId() const override { return dht_->getNodeId(); }
std::pair<size_t, size_t> getStoreSize() const override {
return dht_->getStoreSize();
}
std::string getStorageLog() const override {
return dht_->getStorageLog();
}
std::string getStorageLog(const InfoHash& h) const override {
return dht_->getStorageLog(h);
}
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override {
dht_->setStorageLimit(limit);
}
std::vector<NodeExport> exportNodes() const override {
return dht_->exportNodes();
}
std::vector<ValuesExport> exportValues() const override {
return dht_->exportValues();
}
void importValues(const std::vector<ValuesExport>& v) override {
dht_->importValues(v);
}
NodeStats getNodesStats(sa_family_t af) const override {
return dht_->getNodesStats(af);
}
std::vector<unsigned> getNodeMessageStats(bool in = false) override {
return dht_->getNodeMessageStats(in);
}
std::string getRoutingTablesLog(sa_family_t af) const override {
return dht_->getRoutingTablesLog(af);
}
std::string getSearchesLog(sa_family_t af) const override {
return dht_->getSearchesLog(af);
}
std::string getSearchLog(const InfoHash& h, sa_family_t af = AF_UNSPEC) const override {
return dht_->getSearchLog(h, af);
}
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override {
return dht_->getPublicAddress(family);
}
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr sa, const time_point& now) override {
return dht_->periodic(buf, buflen, std::move(sa), now);
}
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
return dht_->periodic(buf, buflen, from, fromlen, now);
}
NodeStatus updateStatus(sa_family_t af) override {
return dht_->updateStatus(af);
}
NodeStatus getStatus(sa_family_t af) const override {
return dht_->getStatus(af);
}
NodeStatus getStatus() const override {
return dht_->getStatus();
}
net::DatagramSocket* getSocket() const override {
return dht_->getSocket();
};
bool isRunning(sa_family_t af = 0) const override {
return dht_->isRunning(af);
}
const ValueType& getType(ValueType::Id type_id) const override {
return dht_->getType(type_id);
}
void addBootstrap(const std::string& host, const std::string& service) override {
dht_->addBootstrap(host, service);
}
void clearBootstrap() override {
dht_->clearBootstrap();
}
void insertNode(const InfoHash& id, const SockAddr& sa) override {
dht_->insertNode(id, sa);
}
void insertNode(const NodeExport& n) override {
dht_->insertNode(n);
}
void pingNode(SockAddr sa, DoneCallbackSimple&& cb={}) override {
dht_->pingNode(std::move(sa), std::move(cb));
}
void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {}) override {
dht_->query(key, cb, done_cb, std::move(q));
}
void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override {
dht_->query(key, cb, done_cb, std::move(q));
}
std::vector<Sp<Value>> getLocal(const InfoHash& key, const Value::Filter& f = {}) const override {
return dht_->getLocal(key, f);
}
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const override {
return dht_->getLocalById(key, vid);
}
void put(const InfoHash& key,
Sp<Value> v,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false) override
{
dht_->put(key, v, cb, created, permanent);
}
void put(const InfoHash& key,
const Sp<Value>& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false) override
{
dht_->put(key, v, cb, created, permanent);
}
void put(const InfoHash& key,
Value&& v,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false) override
{
dht_->put(key, std::move(v), cb, created, permanent);
}
void put(const InfoHash& key,
Value&& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false) override
{
dht_->put(key, std::move(v), cb, created, permanent);
}
std::vector<Sp<Value>> getPut(const InfoHash& h) const override {
return dht_->getPut(h);
}
Sp<Value> getPut(const InfoHash& h, const Value::Id& vid) const override {
return dht_->getPut(h, vid);
}
bool cancelPut(const InfoHash& h, const Value::Id& vid) override {
return dht_->cancelPut(h, vid);
}
size_t listen(const InfoHash& key, ValueCallback, Value::Filter={}, Where={}) override;
size_t listen(const InfoHash& key, GetCallback cb, Value::Filter = {}, Where w = {}) override;
size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w = {}) override {
return listen(key, bindGetCb(cb), f, w);
}
bool cancelListen(const InfoHash& h, size_t token) override {
return dht_->cancelListen(h, token);
}
void connectivityChanged(sa_family_t af) override {
dht_->connectivityChanged(af);
}
void connectivityChanged() override {
dht_->connectivityChanged();
}
void forwardAllMessages(bool forward) {
forward_all_ = forward;
}
void setPushNotificationToken(const std::string& token = "") override {
dht_->setPushNotificationToken(token);
}
/**
* Call linked callback with push_notification
* @param notification to process
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override {
dht_->pushNotificationReceived(notification);
}
void setLogger(const Logger& logger) override {
DhtInterface::setLogger(logger);
dht_->setLogger(logger);
}
void setLogger(const std::shared_ptr<Logger>& logger) override {
DhtInterface::setLogger(logger);
dht_->setLogger(logger);
}
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
void setLogFilter(const InfoHash& f) override {
DhtInterface::setLogFilter(f);
dht_->setLogFilter(f);
}
private:
std::unique_ptr<DhtInterface> dht_;
// prevent copy
SecureDht(const SecureDht&) = delete;
SecureDht& operator=(const SecureDht&) = delete;
Sp<Value> checkValue(const Sp<Value>& v);
ValueCallback getCallbackFilter(const ValueCallback&, Value::Filter&&);
GetCallback getCallbackFilter(const GetCallback&, Value::Filter&&);
GetCallback getCallbackFilter(GetCallback, Value::Filter&&);
Sp<crypto::PrivateKey> key_ {};
Sp<crypto::Certificate> certificate_ {};
std::shared_ptr<crypto::PrivateKey> key_ {};
std::shared_ptr<crypto::Certificate> certificate_ {};
// method to query the local certificate store
CertificateStoreQuery localQueryMethod_ {};
// our certificate cache
std::map<InfoHash, Sp<crypto::Certificate>> nodesCertificates_ {};
std::map<InfoHash, Sp<const crypto::PublicKey>> nodesPubKeys_ {};
std::map<InfoHash, std::shared_ptr<crypto::Certificate>> nodesCertificates_ {};
std::map<InfoHash, std::shared_ptr<crypto::PublicKey>> nodesPubKeys_ {};
std::atomic_bool forward_all_ {false};
bool enableCache_ {false};
std::uniform_int_distribution<Value::Id> rand_id {};
};
const ValueType CERTIFICATE_TYPE = {
8, "Certificate", std::chrono::hours(24 * 7),
// A certificate can only be stored at its public key ID.
[](InfoHash id, Sp<Value>& v, const InfoHash&, const SockAddr&) {
// A certificate can only be stored at it's public key ID.
[](InfoHash id, std::shared_ptr<Value>& v, InfoHash, const sockaddr*, socklen_t) {
try {
crypto::Certificate crt(v->data);
// TODO check certificate signature
@@ -373,7 +177,7 @@ const ValueType CERTIFICATE_TYPE = {
} catch (const std::exception& e) {}
return false;
},
[](InfoHash, const Sp<Value>& o, Sp<Value>& n, const InfoHash&, const SockAddr&) {
[](InfoHash, const std::shared_ptr<Value>& o, std::shared_ptr<Value>& n, InfoHash, const sockaddr*, socklen_t) {
try {
return crypto::Certificate(o->data).getPublicKey().getId() == crypto::Certificate(n->data).getPublicKey().getId();
} catch (const std::exception& e) {}
-302
View File
@@ -1,302 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "def.h"
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef __ANDROID__
typedef uint16_t in_port_t;
#endif
#else
#include <iso646.h>
#include <stdint.h>
#include <winsock2.h>
#include <ws2def.h>
#include <ws2tcpip.h>
typedef uint16_t sa_family_t;
typedef uint16_t in_port_t;
#endif
#include <string>
#include <memory>
#include <vector>
#include <stdexcept>
#include <stdlib.h>
#include <cstring>
#include <cstddef>
namespace dht {
OPENDHT_PUBLIC std::string print_addr(const sockaddr* sa, socklen_t slen);
OPENDHT_PUBLIC std::string print_addr(const sockaddr_storage& ss, socklen_t sslen);
/**
* A Socket Address (sockaddr*), with abstraction for IPv4, IPv6 address families.
*/
class OPENDHT_PUBLIC SockAddr {
public:
SockAddr() {}
SockAddr(const SockAddr& o) {
set(o.get(), o.getLength());
}
SockAddr(SockAddr&& o) noexcept : addr(std::move(o.addr)), len(o.len) {
o.len = 0;
}
/**
* Build from existing address.
*/
SockAddr(const sockaddr* sa, socklen_t length) {
if (length > sizeof(sockaddr_storage))
throw std::runtime_error("Socket address length is too large");
set(sa, length);
}
SockAddr(const sockaddr* sa) {
socklen_t len = 0;
if (sa) {
if (sa->sa_family == AF_INET)
len = sizeof(sockaddr_in);
else if(sa->sa_family == AF_INET6)
len = sizeof(sockaddr_in6);
else
throw std::runtime_error("Unknown address family");
}
set(sa, len);
}
/**
* Build from an existing sockaddr_storage structure.
*/
SockAddr(const sockaddr_storage& ss, socklen_t len) : SockAddr((const sockaddr*)&ss, len) {}
static std::vector<SockAddr> resolve(const std::string& host, const std::string& service = {});
bool operator<(const SockAddr& o) const {
if (len != o.len)
return len < o.len;
return std::memcmp((const uint8_t*)get(), (const uint8_t*)o.get(), len) < 0;
}
bool equals(const SockAddr& o) const {
return len == o.len
&& std::memcmp((const uint8_t*)get(), (const uint8_t*)o.get(), len) == 0;
}
SockAddr& operator=(const SockAddr& o) {
set(o.get(), o.getLength());
return *this;
}
SockAddr& operator=(SockAddr&& o) {
len = o.len;
o.len = 0;
addr = std::move(o.addr);
return *this;
}
std::string toString() const {
return print_addr(get(), getLength());
}
/**
* Returns the address family or AF_UNSPEC if the address is not set.
*/
sa_family_t getFamily() const { return len ? addr->sa_family : AF_UNSPEC; }
/**
* Resize the managed structure to the appropriate size (if needed),
* in which case the sockaddr structure is cleared to zero,
* and set the address family field (sa_family).
*/
void setFamily(sa_family_t af) {
socklen_t new_length;
switch(af) {
case AF_INET:
new_length = sizeof(sockaddr_in);
break;
case AF_INET6:
new_length = sizeof(sockaddr_in6);
break;
default:
new_length = 0;
}
if (new_length != len) {
len = new_length;
if (len) addr.reset((sockaddr*)::calloc(len, 1));
else addr.reset();
}
if (len > sizeof(sa_family_t))
addr->sa_family = af;
}
/**
* Set Network Interface to any
*/
void setAny() {
auto family = getFamily();
switch(family) {
case AF_INET:
getIPv4().sin_addr.s_addr = htonl(INADDR_ANY);
break;
case AF_INET6:
getIPv6().sin6_addr = in6addr_any;
break;
}
}
/**
* Retreive the port (in host byte order) or 0 if the address is not
* of a supported family.
*/
in_port_t getPort() const {
switch(getFamily()) {
case AF_INET:
return ntohs(getIPv4().sin_port);
case AF_INET6:
return ntohs(getIPv6().sin6_port);
default:
return 0;
}
}
/**
* Set the port. The address must be of a supported family.
* @param p The port in host byte order.
*/
void setPort(in_port_t p) {
switch(getFamily()) {
case AF_INET:
getIPv4().sin_port = htons(p);
break;
case AF_INET6:
getIPv6().sin6_port = htons(p);
break;
}
}
/**
* Set the address part of the socket address from a numeric IP address (string representation).
* Family must be already set. Throws in case of parse failue.
*/
void setAddress(const char* address);
/**
* Returns the accessible byte length at the pointer returned by #get().
* If zero, #get() returns null.
*/
socklen_t getLength() const { return len; }
/**
* An address is defined to be true if its length is not zero.
*/
explicit operator bool() const noexcept {
return len;
}
/**
* Returns the address to the managed sockaddr structure.
* The accessible length is returned by #getLength().
*/
const sockaddr* get() const { return addr.get(); }
/**
* Returns the address to the managed sockaddr structure.
* The accessible length is returned by #getLength().
*/
sockaddr* get() { return addr.get(); }
const sockaddr_in& getIPv4() const {
return *reinterpret_cast<const sockaddr_in*>(get());
}
const sockaddr_in6& getIPv6() const {
return *reinterpret_cast<const sockaddr_in6*>(get());
}
sockaddr_in& getIPv4() {
return *reinterpret_cast<sockaddr_in*>(get());
}
sockaddr_in6& getIPv6() {
return *reinterpret_cast<sockaddr_in6*>(get());
}
/**
* Return true if address is a loopback IP address.
*/
bool isLoopback() const;
/**
* Return true if address is not a public IP address.
*/
bool isPrivate() const;
bool isUnspecified() const;
bool isMappedIPv4() const;
SockAddr getMappedIPv4();
SockAddr getMappedIPv6();
/**
* A comparator to classify IP addresses, only considering the
* first 64 bits in IPv6.
*/
struct ipCmp {
bool operator()(const SockAddr& a, const SockAddr& b) const {
if (a.len != b.len)
return a.len < b.len;
socklen_t start, len;
switch(a.getFamily()) {
case AF_INET:
start = offsetof(sockaddr_in, sin_addr);
len = sizeof(in_addr);
break;
case AF_INET6:
start = offsetof(sockaddr_in6, sin6_addr);
// don't consider more than 64 bits (IPv6)
len = 8;
break;
default:
start = 0;
len = a.len;
break;
}
return std::memcmp((uint8_t*)a.get()+start,
(uint8_t*)b.get()+start, len) < 0;
}
};
private:
struct free_delete { void operator()(void* p) { ::free(p); } };
std::unique_ptr<sockaddr, free_delete> addr {};
socklen_t len {0};
void set(const sockaddr* sa, socklen_t length) {
if (len != length) {
len = length;
if (len) addr.reset((sockaddr*)::malloc(len));
else addr.reset();
}
if (len)
std::memcpy((uint8_t*)get(), (const uint8_t*)sa, len);
}
};
OPENDHT_PUBLIC bool operator==(const SockAddr& a, const SockAddr& b);
}
-96
View File
@@ -1,96 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "def.h"
#include <condition_variable>
#include <vector>
#include <queue>
#include <future>
#include <functional>
namespace dht {
class OPENDHT_PUBLIC ThreadPool {
public:
static ThreadPool& computation();
static ThreadPool& io();
ThreadPool();
ThreadPool(size_t maxThreads);
~ThreadPool();
void run(std::function<void()>&& cb);
template<class T>
std::future<T> get(std::function<T()>&& cb) {
auto ret = std::make_shared<std::promise<T>>();
run([cb = std::move(cb), ret]() mutable {
try {
ret->set_value(cb());
} catch (...) {
try {
ret->set_exception(std::current_exception());
} catch(...) {}
}
});
return ret->get_future();
}
template<class T>
std::shared_future<T> getShared(std::function<T()>&& cb) {
return get(std::move(cb));
}
void stop();
void join();
private:
struct ThreadState;
std::queue<std::function<void()>> tasks_ {};
std::vector<std::unique_ptr<ThreadState>> threads_;
unsigned readyThreads_ {0};
std::mutex lock_ {};
std::condition_variable cv_ {};
const unsigned maxThreads_;
bool running_ {true};
};
class OPENDHT_PUBLIC Executor : public std::enable_shared_from_this<Executor> {
public:
Executor(ThreadPool& pool, unsigned maxConcurrent = 1)
: threadPool_(pool), maxConcurrent_(maxConcurrent)
{}
void run(std::function<void()>&& task);
private:
std::reference_wrapper<ThreadPool> threadPool_;
const unsigned maxConcurrent_ {1};
std::mutex lock_ {};
unsigned current_ {0};
std::queue<std::function<void()>> tasks_ {};
void run_(std::function<void()>&& task);
void schedule();
};
}
+63 -70
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,15 +13,24 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "def.h"
#define WANT4 1
#define WANT6 2
#include <msgpack.hpp>
#ifndef _WIN32
#include <sys/socket.h>
#else
#include <ws2def.h>
#include <ws2tcpip.h>
#endif
#include <chrono>
#include <random>
#include <functional>
@@ -29,22 +38,16 @@
#include <cstdarg>
#define WANT4 1
#define WANT6 2
/**
* OpenDHT C++ namespace
*/
namespace dht {
using NetId = uint32_t;
static constexpr unsigned TARGET_NODES {8};
using Address = std::pair<sockaddr_storage, socklen_t>;
using want_t = int_fast8_t;
OPENDHT_PUBLIC const char* version();
// shortcut for std::shared_ptr
template<class T>
using Sp = std::shared_ptr<T>;
std::string print_addr(const sockaddr* sa, socklen_t slen);
std::string print_addr(const sockaddr_storage& ss, socklen_t sslen);
std::string printAddr(const Address& addr);
template <typename Key, typename Item, typename Condition>
void erase_if(std::map<Key, Item>& map, const Condition& condition)
@@ -56,41 +59,22 @@ void erase_if(std::map<Key, Item>& map, const Condition& condition)
}
}
/**
* Split "[host]:port" or "host:port" to pair<"host", "port">.
*/
OPENDHT_PUBLIC std::pair<std::string, std::string>
splitPort(const std::string& s);
class OPENDHT_PUBLIC DhtException : public std::runtime_error {
public:
DhtException(const std::string &str = "") :
std::runtime_error("DhtException occurred: " + str) {}
class DhtException : public std::runtime_error {
public:
DhtException(const std::string &str = "") :
std::runtime_error("DhtException occured: " + str) {}
};
class OPENDHT_PUBLIC SocketException : public DhtException {
public:
SocketException(int err) :
DhtException(strerror(err)) {}
};
// Time related definitions and utility functions
using clock = std::chrono::steady_clock;
using system_clock = std::chrono::system_clock;
using time_point = clock::time_point;
using duration = clock::duration;
time_point from_time_t(std::time_t t);
std::time_t to_time_t(time_point t);
inline std::string
to_str(double d) {
char buf[16];
auto ret = snprintf(buf, sizeof(buf), "%.3g", d);
return (ret < 0) ? std::to_string(d) : std::string(buf, ret);
}
/**
* Converts std::chrono::duration to floating-point seconds.
*/
@@ -100,32 +84,8 @@ print_dt(DT d) {
return std::chrono::duration_cast<std::chrono::duration<double>>(d).count();
}
template <class DT>
static std::string
print_duration(DT d) {
if (d < std::chrono::seconds(0)) {
return "-" + print_duration(-d);
} else if (d < std::chrono::milliseconds(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
} else if (d < std::chrono::seconds(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
} else if (d < std::chrono::minutes(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double>>(d).count()) + " s";
} else if (d < std::chrono::hours(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count()) + " min";
} else {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count()) + " h";
}
}
template <class TimePoint>
static std::string
print_time_relative(TimePoint now, TimePoint d) {
if (d == TimePoint::min()) return "never";
if (d == now) return "now";
return (d > now) ? std::string("in ") + print_duration(d - now)
: print_duration(now - d) + std::string(" ago");
}
static /*constexpr*/ const time_point TIME_INVALID = {time_point::min()};
static /*constexpr*/ const time_point TIME_MAX {time_point::max()};
template <typename Duration = duration>
class uniform_duration_distribution : public std::uniform_int_distribution<typename Duration::rep> {
@@ -143,17 +103,53 @@ public:
}
};
// Serialization related definitions and utility functions
// Logging related utility functions
/**
* Arbitrary binary data.
* Dummy function used to disable logging
*/
inline void NOLOG(char const*, va_list) {}
/**
* Wrapper for logging methods
*/
struct LogMethod {
LogMethod() = default;
template<typename T>
LogMethod(T&& t) : func(std::forward<T>(t)) {}
void operator()(char const* format, ...) const {
va_list args;
va_start(args, format);
func(format, args);
va_end(args);
}
void logPrintable(const uint8_t *buf, size_t buflen) const {
std::string buf_clean(buflen, '\0');
for (size_t i=0; i<buflen; i++)
buf_clean[i] = isprint(buf[i]) ? buf[i] : '.';
(*this)("%s", buf_clean.c_str());
}
private:
std::function<void(char const*, va_list)> func;
};
struct Logger {
LogMethod DEBUG = NOLOG;
LogMethod WARN = NOLOG;
LogMethod ERR = NOLOG;
};
// Serialization related definitions and utility functions
using Blob = std::vector<uint8_t>;
/**
* Provides backward compatibility with msgpack 1.0
*/
OPENDHT_PUBLIC Blob unpackBlob(const msgpack::object& o);
Blob unpackBlob(msgpack::object& o);
template <typename Type>
Blob
@@ -173,7 +169,4 @@ unpackMsg(Blob b) {
msgpack::unpacked unpackMsg(Blob b);
msgpack::object* findMapValue(const msgpack::object& map, const char* key);
msgpack::object* findMapValue(const msgpack::object& map, const std::string& key);
} // namespace dht
+45 -586
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,7 +14,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
@@ -22,7 +23,6 @@
#include "infohash.h"
#include "crypto.h"
#include "utils.h"
#include "sockaddr.h"
#include <msgpack.hpp>
@@ -35,29 +35,10 @@
#include <functional>
#include <memory>
#include <chrono>
#include <set>
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
#endif
namespace dht {
static const std::string VALUE_KEY_ID("id");
static const std::string VALUE_KEY_DAT("dat");
static const std::string VALUE_KEY_PRIO("p");
static const std::string VALUE_KEY_SIGNATURE("sig");
static const std::string VALUE_KEY_SEQ("seq");
static const std::string VALUE_KEY_DATA("data");
static const std::string VALUE_KEY_OWNER("owner");
static const std::string VALUE_KEY_TYPE("type");
static const std::string VALUE_KEY_TO("to");
static const std::string VALUE_KEY_BODY("body");
static const std::string VALUE_KEY_USERTYPE("utype");
struct Value;
struct Query;
/**
* A storage policy is applied once to every incoming value storage requests.
@@ -69,7 +50,7 @@ struct Query;
* @param form_addr: network address of the incoming request.
* @param from_len: network address lendth of the incoming request.
*/
using StorePolicy = std::function<bool(InfoHash key, std::shared_ptr<Value>& value, const InfoHash& from, const SockAddr& addr)>;
using StorePolicy = std::function<bool(InfoHash key, std::shared_ptr<Value>& value, InfoHash from, const sockaddr* from_addr, socklen_t from_len)>;
/**
* An edition policy is applied once to every incoming value storage requests,
@@ -85,15 +66,15 @@ using StorePolicy = std::function<bool(InfoHash key, std::shared_ptr<Value>& val
* @param form_addr: network address of the incoming request.
* @param from_len: network address lendth of the incoming request.
*/
using EditPolicy = std::function<bool(InfoHash key, const std::shared_ptr<Value>& old_val, std::shared_ptr<Value>& new_val, const InfoHash& from, const SockAddr& addr)>;
using EditPolicy = std::function<bool(InfoHash key, const std::shared_ptr<Value>& old_val, std::shared_ptr<Value>& new_val, InfoHash from, const sockaddr* from_addr, socklen_t from_len)>;
static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
static constexpr const size_t MAX_VALUE_SIZE {1024 * 14};
struct OPENDHT_PUBLIC ValueType {
struct ValueType {
typedef uint16_t Id;
static bool DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
static bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&) {
static bool DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, InfoHash, const sockaddr*, socklen_t);
static bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, InfoHash, const sockaddr*, socklen_t) {
return false;
}
@@ -122,21 +103,6 @@ struct OPENDHT_PUBLIC ValueType {
EditPolicy editPolicy {DEFAULT_EDIT_POLICY};
};
class TypeStore {
public:
void registerType(const ValueType& type) {
types[type.id] = type;
}
const ValueType& getType(ValueType::Id type_id) const {
const auto& t_it = types.find(type_id);
return (t_it == types.end()) ? ValueType::USER_DATA : t_it->second;
}
private:
std::map<ValueType::Id, ValueType> types {};
};
struct CryptoValueCache;
/**
* A "value" is data potentially stored on the Dht, with some metadata.
*
@@ -146,29 +112,14 @@ struct CryptoValueCache;
* Values are stored at a given InfoHash in the Dht, but also have a
* unique ID to distinguish between values stored at the same location.
*/
struct OPENDHT_PUBLIC Value
struct Value
{
enum class Field : int {
None = 0,
Id, /* Value::id */
ValueType, /* Value::type */
OwnerPk, /* Value::owner */
SeqNum, /* Value::seq */
UserType, /* Value::user_type */
COUNT /* the total number of fields */
};
typedef uint64_t Id;
static const constexpr Id INVALID_ID {0};
static const Id INVALID_ID {0};
class Filter : public std::function<bool(const Value&)> {
using std::function<bool(const Value&)>::function;
public:
Filter() {}
template<typename Functor>
Filter(Functor f) : std::function<bool(const Value&)>::function(f) {}
Filter chain(Filter&& f2) {
auto f1 = *this;
return chain(std::move(f1), std::move(f2));
@@ -178,56 +129,31 @@ struct OPENDHT_PUBLIC Value
return chainOr(std::move(f1), std::move(f2));
}
static Filter chain(Filter&& f1, Filter&& f2) {
if (not f1) return std::move(f2);
if (not f2) return std::move(f1);
return [f1 = std::move(f1), f2 = std::move(f2)](const Value& v) {
return f1(v) and f2(v);
};
}
static Filter chain(const Filter& f1, const Filter& f2) {
if (not f1) return f2;
if (not f2) return f1;
return [f1,f2](const Value& v) {
return f1(v) and f2(v);
};
}
static Filter chainAll(std::vector<Filter>&& set) {
if (set.empty()) return {};
return [set = std::move(set)](const Value& v) {
for (const auto& f : set)
static Filter chain(std::initializer_list<Filter> l) {
const std::vector<Filter> list(l.begin(), l.end());
return [list](const Value& v){
for (const auto& f : list)
if (f and not f(v))
return false;
return true;
};
}
static Filter chain(std::initializer_list<Filter> l) {
return chainAll(std::vector<Filter>(l.begin(), l.end()));
}
static Filter chainOr(Filter&& f1, Filter&& f2) {
if (not f1 or not f2) return {};
if (not f1 or not f2) return AllFilter();
return [f1,f2](const Value& v) {
return f1(v) or f2(v);
};
}
static Filter notFilter(Filter&& f) {
if (not f) return [](const Value&) { return false; };
return [f](const Value& v) { return not f(v); };
}
std::vector<Sp<Value>> filter(const std::vector<Sp<Value>>& values) {
if (not (*this))
return values;
std::vector<Sp<Value>> ret;
for (const auto& v : values)
if ((*this)(v))
ret.emplace_back(v);
return ret;
}
};
/* Sneaky functions disguised in classes */
static const Filter AllFilter() {
return {};
return [](const Value&){return true;};
}
static Filter TypeFilter(const ValueType& t) {
@@ -236,11 +162,6 @@ struct OPENDHT_PUBLIC Value
return v.type == tid;
};
}
static Filter TypeFilter(const ValueType::Id& tid) {
return [tid](const Value& v) {
return v.type == tid;
};
}
static Filter IdFilter(const Id id) {
return [id](const Value& v) {
@@ -248,34 +169,12 @@ struct OPENDHT_PUBLIC Value
};
}
static Filter RecipientFilter(const InfoHash& r) {
static Filter recipientFilter(const InfoHash& r) {
return [r](const Value& v) {
return v.recipient == r;
};
}
static Filter OwnerFilter(const crypto::PublicKey& pk) {
return OwnerFilter(pk.getId());
}
static Filter OwnerFilter(const InfoHash& pkh) {
return [pkh](const Value& v) {
return v.owner and v.owner->getId() == pkh;
};
}
static Filter SeqNumFilter(uint16_t seq_no) {
return [seq_no](const Value& v) {
return v.seq == seq_no;
};
}
static Filter UserTypeFilter(const std::string& ut) {
return [ut](const Value& v) {
return v.user_type == ut;
};
}
class SerializableBase
{
public:
@@ -357,7 +256,7 @@ struct OPENDHT_PUBLIC Value
void sign(const crypto::PrivateKey& key) {
if (isEncrypted())
throw DhtException("Can't sign encrypted data.");
owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey());
owner = std::make_shared<crypto::PublicKey>(key.getPublicKey());
signature = key.sign(getToSign());
}
@@ -374,7 +273,7 @@ struct OPENDHT_PUBLIC Value
}
/**
* Sign the value with from and returns the encrypted version for to.
*
*/
Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) {
if (isEncrypted())
@@ -398,14 +297,6 @@ struct OPENDHT_PUBLIC Value
Value(ValueType::Id t, const uint8_t* dat_ptr, size_t dat_len, Id id = INVALID_ID)
: id(id), type(t), data(dat_ptr, dat_ptr+dat_len) {}
#ifdef OPENDHT_JSONCPP
/**
* Build a value from a json object
* @param json
*/
Value(const Json::Value& json);
#endif
template <typename Type>
Value(ValueType::Id t, const Type& d, Id id = INVALID_ID)
: id(id), type(t), data(packMsg(d)) {}
@@ -421,9 +312,7 @@ struct OPENDHT_PUBLIC Value
Value(Value&& o) noexcept
: id(o.id), owner(std::move(o.owner)), recipient(o.recipient),
type(o.type), data(std::move(o.data)), user_type(std::move(o.user_type)), seq(o.seq)
, signature(std::move(o.signature)), cypher(std::move(o.cypher))
, priority(o.priority) {}
type(o.type), data(std::move(o.data)), user_type(std::move(o.user_type)), seq(o.seq), signature(std::move(o.signature)), cypher(std::move(o.cypher)) {}
template <typename Type>
Value(const Type& vs)
@@ -436,20 +325,10 @@ struct OPENDHT_PUBLIC Value
msgpack_unpack(o);
}
/**
* Returns true if value contents are equals (not considering the value ID)
*/
inline bool contentEquals(const Value& o) {
return isEncrypted() ? cypher == o.cypher :
((owner == o.owner || (owner and o.owner and *owner == *o.owner))
&& type == o.type
&& data == o.data
&& user_type == o.user_type
&& signature == o.signature);
}
inline bool operator== (const Value& o) {
return id == o.id and contentEquals(o);
return id == o.id &&
(isEncrypted() ? cypher == o.cypher :
((owner == o.owner || *owner == *o.owner) && type == o.type && data == o.data && user_type == o.user_type && signature == o.signature));
}
void setRecipient(const InfoHash& r) {
@@ -481,7 +360,7 @@ struct OPENDHT_PUBLIC Value
}
/** print value for debugging */
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Value& v);
friend std::ostream& operator<< (std::ostream& s, const Value& v);
std::string toString() const {
std::stringstream ss;
@@ -489,18 +368,6 @@ struct OPENDHT_PUBLIC Value
return ss.str();
}
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a value
* Example:
* {
* "data":"base64ofdata",
* id":"0", "seq":0,"type":3
* }
*/
Json::Value toJson() const;
#endif
/** Return the size in bytes used by this value in memory (minimum). */
size_t size() const;
@@ -508,19 +375,19 @@ struct OPENDHT_PUBLIC Value
void msgpack_pack_to_sign(Packer& pk) const
{
bool has_owner = owner && *owner;
pk.pack_map((user_type.empty()?0:1) + (has_owner?(recipient ? 5 : 4):2));
pk.pack_map((user_type.empty()?0:1) + (has_owner?(recipient == InfoHash() ? 4 : 5):2));
if (has_owner) { // isSigned
pk.pack(VALUE_KEY_SEQ); pk.pack(seq);
pk.pack(VALUE_KEY_OWNER); owner->msgpack_pack(pk);
if (recipient) {
pk.pack(VALUE_KEY_TO); pk.pack(recipient);
pk.pack(std::string("seq")); pk.pack(seq);
pk.pack(std::string("owner")); owner->msgpack_pack(pk);
if (recipient != InfoHash()) {
pk.pack(std::string("to")); pk.pack(recipient);
}
}
pk.pack(VALUE_KEY_TYPE); pk.pack(type);
pk.pack(VALUE_KEY_DATA); pk.pack_bin(data.size());
pk.pack_bin_body((const char*)data.data(), data.size());
pk.pack(std::string("type")); pk.pack(type);
pk.pack(std::string("data")); pk.pack_bin(data.size());
pk.pack_bin_body((const char*)data.data(), data.size());
if (not user_type.empty()) {
pk.pack(VALUE_KEY_USERTYPE); pk.pack(user_type);
pk.pack(std::string("utype")); pk.pack(user_type);
}
}
@@ -532,10 +399,10 @@ struct OPENDHT_PUBLIC Value
pk.pack_bin_body((const char*)cypher.data(), cypher.size());
} else {
pk.pack_map(isSigned() ? 2 : 1);
pk.pack(VALUE_KEY_BODY); msgpack_pack_to_sign(pk);
pk.pack(std::string("body")); msgpack_pack_to_sign(pk);
if (isSigned()) {
pk.pack(VALUE_KEY_SIGNATURE); pk.pack_bin(signature.size());
pk.pack_bin_body((const char*)signature.data(), signature.size());
pk.pack(std::string("sig")); pk.pack_bin(signature.size());
pk.pack_bin_body((const char*)signature.data(), signature.size());
}
}
}
@@ -543,43 +410,12 @@ struct OPENDHT_PUBLIC Value
template <typename Packer>
void msgpack_pack(Packer& pk) const
{
pk.pack_map(2 + (priority?1:0));
pk.pack(VALUE_KEY_ID); pk.pack(id);
pk.pack(VALUE_KEY_DAT); msgpack_pack_to_encrypt(pk);
if (priority) {
pk.pack(VALUE_KEY_PRIO); pk.pack(priority);
}
pk.pack_map(2);
pk.pack(std::string("id")); pk.pack(id);
pk.pack(std::string("dat")); msgpack_pack_to_encrypt(pk);
}
template <typename Packer>
void msgpack_pack_fields(const std::set<Value::Field>& fields, Packer& pk) const
{
for (const auto& field : fields)
switch (field) {
case Value::Field::Id:
pk.pack(static_cast<uint64_t>(id));
break;
case Value::Field::ValueType:
pk.pack(static_cast<uint64_t>(type));
break;
case Value::Field::OwnerPk:
if (owner)
owner->msgpack_pack(pk);
else
InfoHash().msgpack_pack(pk);
break;
case Value::Field::SeqNum:
pk.pack(static_cast<uint64_t>(seq));
break;
case Value::Field::UserType:
pk.pack(user_type);
break;
default:
break;
}
}
void msgpack_unpack(const msgpack::object& o);
void msgpack_unpack(msgpack::object o);
void msgpack_unpack_body(const msgpack::object& o);
Blob getPacked() const {
msgpack::sbuffer buffer;
@@ -588,14 +424,12 @@ struct OPENDHT_PUBLIC Value
return {buffer.data(), buffer.data()+buffer.size()};
}
void msgpack_unpack_fields(const std::set<Value::Field>& fields, const msgpack::object& o, unsigned offset);
Id id {INVALID_ID};
/**
* Public key of the signer.
*/
std::shared_ptr<const crypto::PublicKey> owner {};
std::shared_ptr<crypto::PublicKey> owner {};
/**
* Hash of the recipient (optional).
@@ -629,379 +463,10 @@ struct OPENDHT_PUBLIC Value
* Hold encrypted version of the data.
*/
Blob cypher {};
/**
* Priority of this value (used for push notifications)
* 0 = high priority
* 1 = normal priority
*/
unsigned priority {0};
private:
friend class SecureDht;
/* Cache for crypto ops */
bool signatureChecked {false};
bool signatureValid {false};
bool decrypted {false};
Sp<Value> decryptedValue {};
};
using ValuesExport = std::pair<InfoHash, Blob>;
/**
* @class FieldValue
* @brief Describes a value filter.
* @details
* This structure holds the value for a specified field. It's type can either be
* uint64_t, InfoHash or Blob.
*/
struct OPENDHT_PUBLIC FieldValue
{
FieldValue() {}
FieldValue(Value::Field f, uint64_t int_value) : field(f), intValue(int_value) {}
FieldValue(Value::Field f, InfoHash hash_value) : field(f), hashValue(hash_value) {}
FieldValue(Value::Field f, Blob blob_value) : field(f), blobValue(blob_value) {}
bool operator==(const FieldValue& fd) const;
// accessors
Value::Field getField() const { return field; }
uint64_t getInt() const { return intValue; }
InfoHash getHash() const { return hashValue; }
Blob getBlob() const { return blobValue; }
template <typename Packer>
void msgpack_pack(Packer& p) const {
p.pack_map(2);
p.pack(std::string("f")); p.pack(static_cast<uint8_t>(field));
p.pack(std::string("v"));
switch (field) {
case Value::Field::Id:
case Value::Field::ValueType:
p.pack(intValue);
break;
case Value::Field::OwnerPk:
p.pack(hashValue);
break;
case Value::Field::UserType:
p.pack_bin(blobValue.size());
p.pack_bin_body((const char*)blobValue.data(), blobValue.size());
break;
default:
throw msgpack::type_error();
}
}
void msgpack_unpack(const msgpack::object& msg) {
hashValue = {};
blobValue.clear();
if (auto f = findMapValue(msg, "f"))
field = (Value::Field)f->as<unsigned>();
else
throw msgpack::type_error();
auto v = findMapValue(msg, "v");
if (not v)
throw msgpack::type_error();
else
switch (field) {
case Value::Field::Id:
case Value::Field::ValueType:
intValue = v->as<decltype(intValue)>();
break;
case Value::Field::OwnerPk:
hashValue = v->as<decltype(hashValue)>();
break;
case Value::Field::UserType:
blobValue = unpackBlob(*v);
break;
default:
throw msgpack::type_error();
}
}
Value::Filter getLocalFilter() const;
private:
Value::Field field {Value::Field::None};
// three possible value types
uint64_t intValue {};
InfoHash hashValue {};
Blob blobValue {};
};
/**
* @class Select
* @brief Serializable Value field selection.
* @details
* This is a container for a list of FieldSelectorDescription instances. It
* describes a complete SELECT query for dht::Value.
*/
struct OPENDHT_PUBLIC Select
{
Select() { }
Select(const std::string& q_str);
bool isSatisfiedBy(const Select& os) const;
/**
* Selects a field of type Value::Field.
*
* @param field the field to require.
*
* @return the resulting Select instance.
*/
Select& field(Value::Field field) {
if (std::find(fieldSelection_.begin(), fieldSelection_.end(), field) == fieldSelection_.end())
fieldSelection_.emplace_back(field);
return *this;
}
/**
* Computes the set of selected fields based on previous require* calls.
*
* @return the set of fields.
*/
std::set<Value::Field> getSelection() const {
return {fieldSelection_.begin(), fieldSelection_.end()};
}
template <typename Packer>
void msgpack_pack(Packer& pk) const { pk.pack(fieldSelection_); }
void msgpack_unpack(const msgpack::object& o) {
fieldSelection_ = o.as<decltype(fieldSelection_)>();
}
std::string toString() const {
std::stringstream ss;
ss << *this;
return ss.str();
}
bool empty() const { return fieldSelection_.empty(); }
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Select& q);
private:
std::vector<Value::Field> fieldSelection_ {};
};
/**
* @class Where
* @brief Serializable dht::Value filter.
* @details
* This is container for a list of FieldValue instances. It describes a
* complete WHERE query for dht::Value.
*/
struct OPENDHT_PUBLIC Where
{
Where() { }
Where(const std::string& q_str);
bool isSatisfiedBy(const Where& where) const;
/**
* Adds restriction on Value::Id based on the id argument.
*
* @param id the id.
*
* @return the resulting Where instance.
*/
Where& id(Value::Id id) {
FieldValue fv {Value::Field::Id, id};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
}
/**
* Adds restriction on Value::ValueType based on the type argument.
*
* @param type the value type.
*
* @return the resulting Where instance.
*/
Where& valueType(ValueType::Id type) {
FieldValue fv {Value::Field::ValueType, type};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
}
/**
* Adds restriction on Value::OwnerPk based on the owner_pk_hash argument.
*
* @param owner_pk_hash the owner public key fingerprint.
*
* @return the resulting Where instance.
*/
Where& owner(InfoHash owner_pk_hash) {
FieldValue fv {Value::Field::OwnerPk, owner_pk_hash};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
}
/**
* Adds restriction on Value::OwnerPk based on the owner_pk_hash argument.
*
* @param owner_pk_hash the owner public key fingerprint.
*
* @return the resulting Where instance.
*/
Where& seq(uint16_t seq_no) {
FieldValue fv {Value::Field::SeqNum, seq_no};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
}
/**
* Adds restriction on Value::UserType based on the user_type argument.
*
* @param user_type the user type.
*
* @return the resulting Where instance.
*/
Where& userType(std::string user_type) {
FieldValue fv {Value::Field::UserType, Blob {user_type.begin(), user_type.end()}};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
}
/**
* Computes the Value::Filter based on the list of field value set.
*
* @return the resulting Value::Filter.
*/
Value::Filter getFilter() const {
if (filters_.empty()) return {};
std::vector<Value::Filter> fset;
fset.reserve(filters_.size());
for (const auto& f : filters_) {
if (auto lf = f.getLocalFilter())
fset.emplace_back(std::move(lf));
}
return Value::Filter::chainAll(std::move(fset));
}
template <typename Packer>
void msgpack_pack(Packer& pk) const { pk.pack(filters_); }
void msgpack_unpack(const msgpack::object& o) {
filters_.clear();
filters_ = o.as<decltype(filters_)>();
}
std::string toString() const {
std::stringstream ss;
ss << *this;
return ss.str();
}
bool empty() const {
return filters_.empty();
}
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Where& q);
private:
std::vector<FieldValue> filters_;
};
/**
* @class Query
* @brief Describes a query destined to another peer.
* @details
* This class describes the list of filters on field values and the field
* itselves to include in the peer response to a GET operation. See
* FieldValue.
*/
struct OPENDHT_PUBLIC Query
{
static const std::string QUERY_PARSE_ERROR;
Query(Select s = {}, Where w = {}, bool none = false) : select(std::move(s)), where(std::move(w)), none(none) { };
/**
* Initializes a query based on a SQL-ish formatted string. The abstract
* form of such a string is the following:
*
* [SELECT $field$ [WHERE $field$=$value$]]
*
* where
*
* - $field$ = *|id|value_type|owner_pk|user_type
* - $value$ = $string$|$integer$
* - $string$: a simple string WITHOUT SPACES.
* - $integer$: a simple integer.
*/
Query(std::string q_str) {
auto pos_W = q_str.find("WHERE");
auto pos_w = q_str.find("where");
auto pos = std::min(pos_W != std::string::npos ? pos_W : q_str.size(),
pos_w != std::string::npos ? pos_w : q_str.size());
select = q_str.substr(0, pos);
where = q_str.substr(pos, q_str.size()-pos);
}
/**
* Tell if the query is satisfied by another query.
*/
bool isSatisfiedBy(const Query& q) const;
template <typename Packer>
void msgpack_pack(Packer& pk) const {
pk.pack_map(2);
pk.pack(std::string("s")); pk.pack(select); /* packing field selectors */
pk.pack(std::string("w")); pk.pack(where); /* packing filters */
}
void msgpack_unpack(const msgpack::object& o);
std::string toString() const {
std::stringstream ss;
ss << *this;
return ss.str();
}
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Query& q) {
return s << "Query[" << q.select << " " << q.where << "]";
}
Select select {};
Where where {};
bool none {false}; /* When true, any query satisfies this. */
};
/*!
* @class FieldValueIndex
* @brief An index for field values.
* @details
* This structures is meant to manipulate a subset of fields normally contained
* in Value.
*/
struct OPENDHT_PUBLIC FieldValueIndex {
FieldValueIndex() {}
FieldValueIndex(const Value& v, const Select& s = {});
/**
* Tells if all the fields of this are contained in the other
* FieldValueIndex with the same value.
*
* @param other The other FieldValueIndex instance.
*/
bool containedIn(const FieldValueIndex& other) const;
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi);
void msgpack_unpack_fields(const std::set<Value::Field>& fields,
const msgpack::object& o,
unsigned offset);
std::map<Value::Field, FieldValue> index {};
};
template <typename T,
typename std::enable_if<std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
Value::Filter
@@ -1038,7 +503,7 @@ template <typename T,
Value::Filter
getFilterSet()
{
return {};
return Value::AllFilter();
}
template <class T>
@@ -1054,10 +519,4 @@ unpackVector(const std::vector<std::shared_ptr<Value>>& vals) {
return ret;
}
#ifdef OPENDHT_JSONCPP
uint64_t unpackId(const Json::Value& json, const std::string& key);
#endif
}
MSGPACK_ADD_ENUM(dht::Value::Field)
+30 -419
View File
@@ -1,5 +1,5 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
@@ -33,23 +33,21 @@
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 11
#serial 4
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
m4_if([$1], [11], [],
[$1], [14], [],
[$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
@@ -61,11 +59,18 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[ax_cv_cxx_compile_cxx$1=yes],
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
fi
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for alternative in ${ax_cxx_compile_alternatives}; do
switch="-std=gnu++${alternative}"
for switch in -std=gnu++$1 -std=gnu++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
@@ -91,27 +96,22 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
done
if test x$ac_success = xyes; then
ac_success=yes
break
fi
done
@@ -148,11 +148,6 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
dnl Tests for new features in C++11
@@ -190,13 +185,11 @@ namespace cxx11
struct Base
{
virtual ~Base() {}
virtual void f() {}
};
struct Derived : public Base
{
virtual ~Derived() override {}
virtual void f() override {}
};
@@ -525,7 +518,7 @@ namespace cxx14
}
namespace test_digit_separators
namespace test_digit_seperators
{
constexpr auto ten_million = 100'000'000;
@@ -567,385 +560,3 @@ namespace cxx14
#endif // __cplusplus >= 201402L
]])
dnl Tests for new features in C++17
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201703L
#error "This is not a C++17 compiler"
#else
#include <initializer_list>
#include <utility>
#include <type_traits>
namespace cxx17
{
namespace test_constexpr_lambdas
{
constexpr int foo = [](){return 42;}();
}
namespace test::nested_namespace::definitions
{
}
namespace test_fold_expression
{
template<typename... Args>
int multiply(Args... args)
{
return (args * ... * 1);
}
template<typename... Args>
bool all(Args... args)
{
return (args && ...);
}
}
namespace test_extended_static_assert
{
static_assert (true);
}
namespace test_auto_brace_init_list
{
auto foo = {5};
auto bar {5};
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
static_assert(std::is_same<int, decltype(bar)>::value);
}
namespace test_typename_in_template_template_parameter
{
template<template<typename> typename X> struct D;
}
namespace test_fallthrough_nodiscard_maybe_unused_attributes
{
int f1()
{
return 42;
}
[[nodiscard]] int f2()
{
[[maybe_unused]] auto unused = f1();
switch (f1())
{
case 17:
f1();
[[fallthrough]];
case 42:
f1();
}
return f1();
}
}
namespace test_extended_aggregate_initialization
{
struct base1
{
int b1, b2 = 42;
};
struct base2
{
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1 {{1, 2}, {}, 4}; // full initialization
derived d2 {{}, {}, 4}; // value-initialized bases
}
namespace test_general_range_based_for_loop
{
struct iter
{
int i;
int& operator* ()
{
return i;
}
const int& operator* () const
{
return i;
}
iter& operator++()
{
++i;
return *this;
}
};
struct sentinel
{
int i;
};
bool operator== (const iter& i, const sentinel& s)
{
return i.i == s.i;
}
bool operator!= (const iter& i, const sentinel& s)
{
return !(i == s);
}
struct range
{
iter begin() const
{
return {0};
}
sentinel end() const
{
return {5};
}
};
void f()
{
range r {};
for (auto i : r)
{
[[maybe_unused]] auto v = i;
}
}
}
namespace test_lambda_capture_asterisk_this_by_value
{
struct t
{
int i;
int foo()
{
return [*this]()
{
return i;
}();
}
};
}
namespace test_enum_class_construction
{
enum class byte : unsigned char
{};
byte foo {42};
}
namespace test_constexpr_if
{
template <bool cond>
int f ()
{
if constexpr(cond)
{
return 13;
}
else
{
return 42;
}
}
}
namespace test_selection_statement_with_initializer
{
int f()
{
return 13;
}
int f2()
{
if (auto i = f(); i > 0)
{
return 3;
}
switch (auto i = f(); i + 4)
{
case 17:
return 2;
default:
return 1;
}
}
}
namespace test_template_argument_deduction_for_class_templates
{
template <typename T1, typename T2>
struct pair
{
pair (T1 p1, T2 p2)
: m1 {p1},
m2 {p2}
{}
T1 m1;
T2 m2;
};
void f()
{
[[maybe_unused]] auto p = pair{13, 42u};
}
}
namespace test_non_type_auto_template_parameters
{
template <auto n>
struct B
{};
B<5> b1;
B<'a'> b2;
}
namespace test_structured_bindings
{
int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 };
auto f1() -> int(&)[2]
{
return arr;
}
auto f2() -> std::pair<int, int>&
{
return pr;
}
struct S
{
int x1 : 2;
volatile double y1;
};
S f3()
{
return {};
}
auto [ x1, y1 ] = f1();
auto& [ xr1, yr1 ] = f1();
auto [ x2, y2 ] = f2();
auto& [ xr2, yr2 ] = f2();
const auto [ x3, y3 ] = f3();
}
namespace test_exception_spec_type_system
{
struct Good {};
struct Bad {};
void g1() noexcept;
void g2();
template<typename T>
Bad
f(T*, T*);
template<typename T1, typename T2>
Good
f(T1*, T2*);
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
}
namespace test_inline_variables
{
template<class T> void f(T)
{}
template<class T> inline T g(T)
{
return T{};
}
template<> inline void f<>(int)
{}
template<> int g<>(int)
{
return 5;
}
}
} // namespace cxx17
#endif // __cplusplus < 201703L
]])
-10
View File
@@ -1,10 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: OpenDHT (C Wrapper)
Description: Distributed Hash Table library (C Wrapper)
Version: @VERSION@
Libs: -L${libdir} -lopendht-c
Requires.private: opendht gnutls >= 3.1 @argon2_lib@
Cflags: -I${includedir}
+3 -3
View File
@@ -3,9 +3,9 @@ exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: OpenDHT
Description: C++14 Distributed Hash Table library
Description: C++ Distributed Hash Table library
Version: @VERSION@
Libs: -L${libdir} -lopendht
Libs.private: @http_parser_lib@ -pthread
Requires.private: gnutls >= 3.3, nettle >= 2.4@argon2_lib@@jsoncpp_lib@@openssl_lib@
Libs.private: -lpthread
Requires.private: gnutls >= 3.1
Cflags: -I${includedir}
-3
View File
@@ -9,6 +9,3 @@ add_custom_target(python ALL
DEPENDS opendht opendht_cpp.pxd opendht.pyx)
install(CODE "execute_process(COMMAND python3 setup.py install --root=\$ENV{DESTDIR}/ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
if (OPENDHT_TOOLS)
install(PROGRAMS tools/dhtcluster.py DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME dhtcluster)
endif()
-4
View File
@@ -1,9 +1,5 @@
if USE_CYTHON
noinst_HEADERS = \
opendht.pyx \
opendht_cpp.pxd
PYTHON_INSTALL_RECORD = $(builddir)/install_record.txt
pybuild.stamp:
+56 -364
View File
@@ -1,11 +1,11 @@
# distutils: language = c++
# distutils: extra_compile_args = -std=c++14
# distutils: extra_compile_args = -std=c++11
# distutils: include_dirs = ../../include
# distutils: library_dirs = ../../src
# distutils: libraries = opendht gnutls
# cython: language_level=3
#
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Author(s): Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
@@ -25,13 +25,12 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with OpenDHT Python Wrapper. If not, see <https://www.gnu.org/licenses/>.
# along with OpenDHT Python Wrapper. If not, see <http://www.gnu.org/licenses/>.
from libcpp.map cimport map as map
from libcpp cimport bool
from libcpp.utility cimport pair
from libcpp.string cimport string
from libcpp.memory cimport shared_ptr
from cython.parallel import parallel, prange
from cython.operator cimport dereference as deref, preincrement as inc, predecrement as dec
@@ -41,39 +40,19 @@ cimport opendht_cpp as cpp
import threading
cdef inline void lookup_callback(cpp.vector[cpp.shared_ptr[cpp.IndexValue]]* values, cpp.Prefix* p, void *user_data) with gil:
cbs = <object>user_data
if 'lookup' in cbs and cbs['lookup']:
vals = []
for val in deref(values):
v = IndexValue()
v._value = val
vals.append(v)
cbs['lookup'](vals, p.toString())
cdef inline void shutdown_callback(void* user_data) with gil:
cbs = <object>user_data
if 'shutdown' in cbs and cbs['shutdown']:
cbs['shutdown']()
ref.Py_DECREF(cbs)
cdef inline bool get_callback(shared_ptr[cpp.Value] value, void *user_data) with gil:
cbs = <object>user_data
cb = cbs['get']
f = cbs['filter'] if 'filter' in cbs else None
cdef inline bool get_callback(cpp.shared_ptr[cpp.Value] value, void *user_data) with gil:
cb = (<object>user_data)['get']
pv = Value()
pv._value = value
return cb(pv) if not f or f(pv) else True
return cb(pv)
cdef inline bool value_callback(shared_ptr[cpp.Value] value, bool expired, void *user_data) with gil:
cbs = <object>user_data
cb = cbs['valcb']
f = cbs['filter'] if 'filter' in cbs else None
pv = Value()
pv._value = value
return cb(pv, expired) if not f or f(pv) else True
cdef inline void done_callback(bool done, cpp.vector[shared_ptr[cpp.Node]]* nodes, void *user_data) with gil:
cdef inline void done_callback(bool done, cpp.vector[cpp.shared_ptr[cpp.Node]]* nodes, void *user_data) with gil:
node_ids = []
for n in deref(nodes):
h = NodeEntry()
@@ -85,12 +64,6 @@ cdef inline void done_callback(bool done, cpp.vector[shared_ptr[cpp.Node]]* node
cbs['done'](done, node_ids)
ref.Py_DECREF(cbs)
cdef inline void done_callback_simple(bool done, void *user_data) with gil:
cbs = <object>user_data
if 'done' in cbs and cbs['done']:
cbs['done'](done)
ref.Py_DECREF(cbs)
cdef class _WithID(object):
def __repr__(self):
return "<%s '%s'>" % (self.__class__.__name__, str(self))
@@ -99,10 +72,10 @@ cdef class _WithID(object):
cdef class InfoHash(_WithID):
cdef cpp.InfoHash _infohash
def __cinit__(self, bytes str=b''):
self._infohash = cpp.InfoHash(str) if str else cpp.InfoHash()
def __init__(self, bytes str=b''):
self._infohash = cpp.InfoHash(str)
def __bool__(InfoHash self):
return <bool>self._infohash
return not (self._infohash == cpp.InfoHash())
def __richcmp__(InfoHash self, InfoHash other, int op):
if op == 0:
return self._infohash < other._infohash
@@ -135,31 +108,8 @@ cdef class InfoHash(_WithID):
h._infohash = cpp.InfoHash.getRandom()
return h
cdef class SockAddr(object):
cdef cpp.SockAddr _addr
def toString(SockAddr self):
return self._addr.toString()
def getPort(SockAddr self):
return self._addr.getPort()
def getFamily(SockAddr self):
return self._addr.getFamily()
def setPort(SockAddr self, cpp.in_port_t port):
return self._addr.setPort(port)
def setFamily(SockAddr self, cpp.sa_family_t af):
return self._addr.setFamily(af)
def isLoopback(SockAddr self):
return self._addr.isLoopback()
def isPrivate(SockAddr self):
return self._addr.isPrivate()
def isUnspecified(SockAddr self):
return self._addr.isUnspecified()
def __str__(self):
return self.toString().decode()
def __repr__(self):
return "<%s '%s'>" % (self.__class__.__name__, str(self))
cdef class Node(_WithID):
cdef shared_ptr[cpp.Node] _node
cdef cpp.shared_ptr[cpp.Node] _node
def getId(self):
h = InfoHash()
h._infohash = self._node.get().getId()
@@ -170,7 +120,7 @@ cdef class Node(_WithID):
return self._node.get().isExpired()
cdef class NodeEntry(_WithID):
cdef cpp.pair[cpp.InfoHash, shared_ptr[cpp.Node]] _v
cdef cpp.pair[cpp.InfoHash, cpp.shared_ptr[cpp.Node]] _v
def getId(self):
h = InfoHash()
h._infohash = self._v.first
@@ -180,61 +130,8 @@ cdef class NodeEntry(_WithID):
n._node = self._v.second
return n
cdef class Query(object):
cdef cpp.Query _query
def __cinit__(self, str q_str=''):
self._query = cpp.Query(q_str.encode())
def __str__(self):
return self._query.toString().decode()
def buildFrom(self, Select s, Where w):
self._query = cpp.Query(s._select, w._where)
def isSatisfiedBy(self, Query q):
return self._query.isSatisfiedBy(q._query)
cdef class Select(object):
cdef cpp.Select _select
def __cinit__(self, str q_str=None):
if q_str:
self._select = cpp.Select(q_str.encode())
else:
self._select = cpp.Select()
def __str__(self):
return self._select.toString().decode()
def isSatisfiedBy(self, Select os):
return self._select.isSatisfiedBy(os._select)
def field(self, int field):
self._select.field(<cpp.Field> field)
return self
cdef class Where(object):
cdef cpp.Where _where
def __cinit__(self, str q_str=None):
if q_str:
self._where = cpp.Where(q_str.encode())
else:
self._where = cpp.Where()
def __str__(self):
return self._where.toString().decode()
def isSatisfiedBy(self, Where where):
return self._where.isSatisfiedBy(where._where)
def id(self, cpp.uint64_t id):
self._where.id(id)
return self
def valueType(self, cpp.uint16_t type):
self._where.valueType(type)
return self
def owner(self, InfoHash owner_pk_hash):
self._where.owner(owner_pk_hash._infohash)
return self
def seq(self, cpp.uint16_t seq_no):
self._where.seq(seq_no)
return self
def userType(self, str user_type):
self._where.userType(user_type.encode())
return self
cdef class Value(object):
cdef shared_ptr[cpp.Value] _value
cdef cpp.shared_ptr[cpp.Value] _value
def __init__(self, bytes val=b''):
self._value.reset(new cpp.Value(val, len(val)))
def __str__(self):
@@ -256,11 +153,6 @@ cdef class Value(object):
return string(<char*>self._value.get().data.data(), self._value.get().data.size())
def __set__(self, bytes value):
self._value.get().data = value
property user_type:
def __get__(self):
return self._value.get().user_type.decode()
def __set__(self, str t):
self._value.get().user_type = t.encode()
property id:
def __get__(self):
return self._value.get().id
@@ -271,8 +163,8 @@ cdef class Value(object):
return self._value.get().size()
cdef class NodeSetIter(object):
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]]* _nodes
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]].iterator _curIter
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]]* _nodes
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]].iterator _curIter
def __init__(self, NodeSet s):
self._nodes = &s._nodes
self._curIter = self._nodes.begin()
@@ -285,11 +177,11 @@ cdef class NodeSetIter(object):
return h
cdef class NodeSet(object):
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]] _nodes
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]] _nodes
def size(self):
return self._nodes.size()
def insert(self, NodeEntry l):
return self._nodes.insert(l._v).second
self._nodes.insert(l._v)
def extend(self, li):
for n in li:
self.insert(n)
@@ -307,7 +199,7 @@ cdef class NodeSet(object):
return h
def __str__(self):
s = ''
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]].iterator it = self._nodes.begin()
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]].iterator it = self._nodes.begin()
while it != self._nodes.end():
s += deref(it).first.toString().decode() + ' ' + deref(it).second.get().getAddrStr().decode() + '\n'
inc(it)
@@ -315,100 +207,19 @@ cdef class NodeSet(object):
def __iter__(self):
return NodeSetIter(self)
cdef class PrivateKey(_WithID):
cdef shared_ptr[cpp.PrivateKey] _key
def getId(self):
h = InfoHash()
h._infohash = self._key.get().getPublicKey().getId()
return h
def getPublicKey(self):
pk = PublicKey()
pk._key = self._key.get().getPublicKey()
return pk
def decrypt(self, bytes dat):
cdef size_t d_len = len(dat)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>dat
cdef cpp.Blob indat
indat.assign(d_ptr, <cpp.uint8_t*>(d_ptr + d_len))
cdef cpp.Blob decrypted = self._key.get().decrypt(indat)
cdef char* decrypted_c_str = <char *>decrypted.data()
cdef Py_ssize_t length = decrypted.size()
return decrypted_c_str[:length]
def __str__(self):
return self.getId().toString().decode()
@staticmethod
def generate():
k = PrivateKey()
k._key = cpp.make_shared[cpp.PrivateKey](cpp.PrivateKey.generate())
return k
@staticmethod
def generateEC():
k = PrivateKey()
k._key = cpp.make_shared[cpp.PrivateKey](cpp.PrivateKey.generateEC())
return k
cdef class PublicKey(_WithID):
cdef cpp.PublicKey _key
def getId(self):
h = InfoHash()
h._infohash = self._key.getId()
return h
def encrypt(self, bytes dat):
cdef size_t d_len = len(dat)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>dat
cdef cpp.Blob indat
indat.assign(d_ptr, <cpp.uint8_t*>(d_ptr + d_len))
cdef cpp.Blob encrypted = self._key.encrypt(indat)
cdef char* encrypted_c_str = <char *>encrypted.data()
cdef Py_ssize_t length = encrypted.size()
return encrypted_c_str[:length]
cdef class Certificate(_WithID):
cdef shared_ptr[cpp.Certificate] _cert
def __init__(self, bytes dat = None):
if dat:
self._cert = cpp.make_shared[cpp.Certificate](<cpp.string>dat)
cdef cpp.shared_ptr[cpp.Certificate] _cert
def getId(self):
h = InfoHash()
if self._cert:
h._infohash = self._cert.get().getId()
h._infohash = self._cert.get().getId()
return h
def toString(self):
return self._cert.get().toString().decode()
def getName(self):
return self._cert.get().getName()
def revoke(self, PrivateKey k, Certificate c):
self._cert.get().revoke(deref(k._key.get()), deref(c._cert.get()));
def __bytes__(self):
return self._cert.get().toString() if self._cert else b''
property issuer:
def __get__(self):
c = Certificate()
c._cert = self._cert.get().issuer
return c;
@staticmethod
def generate(PrivateKey k, str name, Identity i = Identity(), bool is_ca = False):
c = Certificate()
c._cert = cpp.make_shared[cpp.Certificate](cpp.Certificate.generate(deref(k._key.get()), name.encode(), i._id, is_ca))
return c
cdef class VerifyResult(object):
cdef cpp.TrustListVerifyResult _result
def __bool__(self):
return self._result.isValid()
def __str(self):
return self._result.toString()
cdef class TrustList(object):
cdef cpp.TrustList _trust
def add(self, Certificate cert):
self._trust.add(deref(cert._cert.get()))
def remove(self, Certificate cert):
self._trust.remove(deref(cert._cert.get()))
def verify(self, Certificate cert):
r = VerifyResult()
r._result = self._trust.verify(deref(cert._cert.get()))
return r
cdef class ListenToken(object):
cdef cpp.InfoHash _h
@@ -417,31 +228,18 @@ cdef class ListenToken(object):
cdef class Identity(object):
cdef cpp.Identity _id
def __init__(self, PrivateKey k = None, Certificate c = None):
if k:
self._id.first = k._key
if c:
self._id.second = c._cert
@staticmethod
def generate(str name = "pydht", Identity ca = Identity(), unsigned bits = 4096):
i = Identity()
i._id = cpp.generateIdentity(name.encode(), ca._id, bits)
return i
property publickey:
def generate(self, str name = "pydht", Identity ca = Identity(), unsigned bits = 4096):
self._id = cpp.generateIdentity(name.encode(), ca._id, bits)
property PublicKey:
def __get__(self):
k = PublicKey()
k._key = self._id.first.get().getPublicKey()
return k
property certificate:
property Certificate:
def __get__(self):
c = Certificate()
c._cert = self._id.second
return c
property key:
def __get__(self):
k = PrivateKey()
k._key = self._id.first
return k
cdef class DhtConfig(object):
cdef cpp.DhtRunnerConfig _config
@@ -454,108 +252,66 @@ cdef class DhtConfig(object):
self._config.dht_config.node_config.is_bootstrap = bootstrap
def setNodeId(self, InfoHash id):
self._config.dht_config.node_config.node_id = id._infohash
def setNetwork(self, unsigned netid):
self._config.dht_config.node_config.network = netid
def setMaintainStorage(self, bool maintain_storage):
self._config.dht_config.node_config.maintain_storage = maintain_storage
def setRateLimit(self, ssize_t max_req_per_sec, ssize_t max_peer_req_per_sec):
self._config.dht_config.node_config.max_req_per_sec = max_req_per_sec
self._config.dht_config.node_config.max_peer_req_per_sec = max_peer_req_per_sec
cdef class DhtRunner(_WithID):
cdef cpp.shared_ptr[cpp.DhtRunner] thisptr
cdef cpp.DhtRunner* thisptr
def __cinit__(self):
self.thisptr.reset(new cpp.DhtRunner())
self.thisptr = new cpp.DhtRunner()
def getId(self):
h = InfoHash()
if self.thisptr:
h._infohash = self.thisptr.get().getId()
h._infohash = self.thisptr.getId()
return h
def getNodeId(self):
return self.thisptr.get().getNodeId().toString()
def ping(self, SockAddr addr, done_cb=None):
if done_cb:
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().bootstrap(addr._addr, cpp.bindDoneCbSimple(done_callback_simple, <void*>cb_obj))
else:
lock = threading.Condition()
pending = 0
ok = False
def tmp_done(ok_ret):
nonlocal pending, ok, lock
with lock:
ok = ok_ret
pending -= 1
lock.notify()
with lock:
pending += 1
self.ping(addr, done_cb=tmp_done)
while pending > 0:
lock.wait()
return ok
def bootstrap(self, str host, str port=None):
host_bytes = host.encode()
port_bytes = port.encode() if port else b'4222'
self.thisptr.get().bootstrap(<cpp.const_char*>host_bytes, <cpp.const_char*>port_bytes)
return self.thisptr.getNodeId().toString()
def bootstrap(self, str host, str port):
self.thisptr.bootstrap(host.encode(), port.encode())
def run(self, Identity id=None, is_bootstrap=False, cpp.in_port_t port=0, str ipv4="", str ipv6="", DhtConfig config=DhtConfig()):
if id:
config.setIdentity(id)
if ipv4 or ipv6:
bind4 = ipv4.encode() if ipv4 else b''
bind6 = ipv6.encode() if ipv6 else b''
self.thisptr.get().run(bind4, bind6, str(port).encode(), config._config)
self.thisptr.run(bind4, bind6, str(port).encode(), config._config)
else:
self.thisptr.get().run(port, config._config)
self.thisptr.run(port, config._config)
def join(self):
self.thisptr.get().join()
self.thisptr.join()
def shutdown(self, shutdown_cb=None):
cb_obj = {'shutdown':shutdown_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().shutdown(cpp.bindShutdownCb(shutdown_callback, <void*>cb_obj))
self.thisptr.shutdown(cpp.bindShutdownCb(shutdown_callback, <void*>cb_obj))
def enableLogging(self):
cpp.enableLogging(self.thisptr.get()[0])
cpp.enableLogging(self.thisptr[0])
def disableLogging(self):
cpp.disableLogging(self.thisptr.get()[0])
cpp.disableLogging(self.thisptr[0])
def enableFileLogging(self, str path):
cpp.enableFileLogging(self.thisptr.get()[0], path.encode())
cpp.enableFileLogging(self.thisptr[0], path)
def isRunning(self):
return self.thisptr.get().isRunning()
def getBound(self, cpp.sa_family_t af = 0):
s = SockAddr()
s._addr = self.thisptr.get().getBound(af)
return s
return self.thisptr.isRunning()
def getStorageLog(self):
return self.thisptr.get().getStorageLog().decode()
return self.thisptr.getStorageLog().decode()
def getRoutingTablesLog(self, cpp.sa_family_t af):
return self.thisptr.get().getRoutingTablesLog(af).decode()
return self.thisptr.getRoutingTablesLog(af).decode()
def getSearchesLog(self, cpp.sa_family_t af):
return self.thisptr.get().getSearchesLog(af).decode()
return self.thisptr.getSearchesLog(af).decode()
def getNodeMessageStats(self):
stats = []
cdef cpp.vector[unsigned] res = self.thisptr.get().getNodeMessageStats(False)
cdef cpp.vector[unsigned] res = self.thisptr.getNodeMessageStats(False)
for n in res:
stats.append(n)
return stats
def get(self, InfoHash key, get_cb=None, done_cb=None, filter=None, Where where=None):
def get(self, InfoHash key, get_cb=None, done_cb=None):
"""Retreive values associated with a key on the DHT.
key -- the key for which to search
get_cb -- is set, makes the operation non-blocking. Called when a value
is found on the DHT.
done_cb -- optional callback used when get_cb is set. Called when the
operation is completed.
key -- the key for which to search
get_cb -- is set, makes the operation non-blocking. Called when a value is found on the DHT.
done_cb -- optional callback used when get_cb is set. Called when the operation is completed.
"""
if get_cb:
cb_obj = {'get':get_cb, 'done':done_cb, 'filter':filter}
cb_obj = {'get':get_cb, 'done':done_cb}
ref.Py_INCREF(cb_obj)
if where is None:
where = Where()
self.thisptr.get().get(key._infohash, cpp.bindGetCb(get_callback, <void*>cb_obj),
cpp.bindDoneCb(done_callback, <void*>cb_obj),
cpp.nullptr, #filter implemented in the get_callback
where._where)
self.thisptr.get(key._infohash, cpp.bindGetCb(get_callback, <void*>cb_obj), cpp.bindDoneCb(done_callback, <void*>cb_obj))
else:
lock = threading.Condition()
pending = 0
@@ -571,21 +327,21 @@ cdef class DhtRunner(_WithID):
lock.notify()
with lock:
pending += 1
self.get(key, get_cb=tmp_get, done_cb=tmp_done, filter=filter, where=where)
self.get(key, get_cb=tmp_get, done_cb=tmp_done)
while pending > 0:
lock.wait()
return res
def put(self, InfoHash key, Value val, done_cb=None):
"""Publish a new value on the DHT at key.
key -- the DHT key where to put the value
val -- the value to put on the DHT
key -- the DHT key where to put the value
val -- the value to put on the DHT
done_cb -- optional callback called when the operation is completed.
"""
if done_cb:
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().put(key._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj))
self.thisptr.put(key._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj))
else:
lock = threading.Condition()
pending = 0
@@ -602,80 +358,16 @@ cdef class DhtRunner(_WithID):
while pending > 0:
lock.wait()
return ok
def listen(self, InfoHash key, value_cb):
def listen(self, InfoHash key, get_cb):
t = ListenToken()
t._h = key._infohash
cb_obj = {'valcb':value_cb}
cb_obj = {'get':get_cb}
t._cb['cb'] = cb_obj
# avoid the callback being destructed if the token is destroyed
ref.Py_INCREF(cb_obj)
t._t = self.thisptr.get().listen(t._h, cpp.bindValueCb(value_callback, <void*>cb_obj)).share()
t._t = self.thisptr.listen(t._h, cpp.bindGetCb(get_callback, <void*>cb_obj)).share()
return t
def cancelListen(self, ListenToken token):
self.thisptr.get().cancelListen(token._h, token._t)
self.thisptr.cancelListen(token._h, token._t)
ref.Py_DECREF(<object>token._cb['cb'])
# fixme: not thread safe
cdef class IndexValue(object):
cdef cpp.shared_ptr[cpp.IndexValue] _value
def __init__(self, InfoHash h=None, cpp.uint64_t vid=0):
cdef cpp.InfoHash hh = h._infohash
self._value.reset(new cpp.IndexValue(hh, vid))
def __str__(self):
return "(" + self.getKey().toString().decode() +", "+ str(self.getValueId()) +")"
def getKey(self):
h = InfoHash()
h._infohash = self._value.get().first
return h
def getValueId(self):
return self._value.get().second
cdef class Pht(object):
cdef cpp.Pht* thisptr
def __cinit__(self, bytes name, key_spec, DhtRunner dht):
cdef cpp.IndexKeySpec cpp_key_spec
for kk, size in key_spec.items():
cpp_key_spec[bytes(kk, 'utf-8')] = size
self.thisptr = new cpp.Pht(name, cpp_key_spec, dht.thisptr)
property MAX_NODE_ENTRY_COUNT:
def __get__(self):
return cpp.PHT_MAX_NODE_ENTRY_COUNT
def lookup(self, key, lookup_cb=None, done_cb=None):
"""Query the Index with a specified key.
key -- the key for to the entry in the index.
lookup_cb -- function called when the operation is completed. This
function takes a list of IndexValue objects and a string
representation of the prefix where the value was indexed in
the PHT.
"""
cb_obj = {'lookup':lookup_cb, 'done':done_cb} # TODO: donecallback is to be removed
ref.Py_INCREF(cb_obj)
cdef cpp.IndexKey cppk
for kk, v in key.items():
cppk[bytes(kk, 'utf-8')] = bytes(v)
self.thisptr.lookup(
cppk,
cpp.Pht.bindLookupCb(lookup_callback, <void*>cb_obj),
cpp.bindDoneCbSimple(done_callback_simple, <void*>cb_obj)
)
def insert(self, key, IndexValue value, done_cb=None):
"""Add an index entry to the Index.
key -- the key for to the entry in the index.
value -- an IndexValue object describing the indexed value.
done_cb -- Called when the operation is completed.
"""
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
cdef cpp.IndexKey cppk
for kk, v in key.items():
cppk[bytes(kk, 'utf-8')] = bytes(v)
cdef cpp.IndexValue val
val.first = (<InfoHash>value.getKey())._infohash
val.second = value.getValueId()
self.thisptr.insert(
cppk,
val,
cpp.bindDoneCbSimple(done_callback_simple, <void*>cb_obj)
)
+11 -125
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
@@ -13,15 +13,13 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <https://www.gnu.org/licenses/>.
# along with this program; If not, see <http://www.gnu.org/licenses/>.
from libc.stdint cimport *
from libcpp cimport bool, nullptr_t, nullptr
from libcpp cimport bool
from libcpp.string cimport string
from libcpp.vector cimport vector
from libcpp.utility cimport pair
from libcpp.map cimport map
from libc.string cimport const_char, const_uchar
ctypedef uint16_t in_port_t
ctypedef unsigned short int sa_family_t;
@@ -29,12 +27,9 @@ ctypedef unsigned short int sa_family_t;
cdef extern from "<memory>" namespace "std" nogil:
cdef cppclass shared_ptr[T]:
shared_ptr() except +
shared_ptr(T*) except +
T* get()
T operator*()
bool operator bool() const
void reset(T*)
shared_ptr[T] make_shared[T](...) except +
cdef extern from "<functional>" namespace "std" nogil:
cdef cppclass hash[T]:
@@ -65,23 +60,8 @@ cdef extern from "opendht/infohash.h" namespace "dht":
InfoHash get(string s)
@staticmethod
InfoHash getRandom()
bool operator==(InfoHash) const
bool operator<(InfoHash) const
bool operator bool() const
cdef extern from "opendht/sockaddr.h" namespace "dht":
cdef cppclass SockAddr:
SockAddr() except +
string toString() const
in_port_t getPort() const
void setPort(in_port_t p)
sa_family_t getFamily() const
void setFamily(sa_family_t f)
bool isLoopback() const
bool isPrivate() const
bool isUnspecified() const
ctypedef vector[uint8_t] Blob
bool operator==(InfoHash)
bool operator<(InfoHash)
cdef extern from "opendht/crypto.h" namespace "dht::crypto":
ctypedef pair[shared_ptr[PrivateKey], shared_ptr[Certificate]] Identity
@@ -90,52 +70,14 @@ cdef extern from "opendht/crypto.h" namespace "dht::crypto":
cdef cppclass PrivateKey:
PrivateKey()
PublicKey getPublicKey() const
Blob decrypt(Blob data) const
@staticmethod
PrivateKey generate()
@staticmethod
PrivateKey generateEC()
cdef cppclass PublicKey:
PublicKey()
InfoHash getId() const
Blob encrypt(Blob data) const
cdef cppclass Certificate:
Certificate()
Certificate(string pem)
InfoHash getId() const
string toString() const
string getName() const
void revoke(PrivateKey key, Certificate cert)
@staticmethod
Certificate generate(PrivateKey key, string name, Identity ca, bool is_ca)
shared_ptr[Certificate] issuer
cdef cppclass TrustList:
cppclass VerifyResult:
bool operator bool() const
bool isValid() const
string toString() const
TrustList()
void add(Certificate)
void remove(Certificate)
VerifyResult verify(Certificate);
ctypedef TrustList.VerifyResult TrustListVerifyResult
cdef extern from "opendht/value.h" namespace "dht::Value":
cdef cppclass Field:
pass
cdef extern from "opendht/value.h" namespace "dht::Value::Field":
cdef Field None
cdef Field Id
cdef Field ValueType
cdef Field OwnerPk
cdef Field SeqNum
cdef Field UserType
cdef Field COUNT
cdef extern from "opendht/value.h" namespace "dht":
cdef cppclass Value:
@@ -150,31 +92,6 @@ cdef extern from "opendht/value.h" namespace "dht":
vector[uint8_t] data
string user_type
cdef cppclass Query:
Query() except +
Query(Select s, Where w) except +
Query(string q_str) except +
bool isSatisfiedBy(const Query& q) const
string toString() const
cdef cppclass Select:
Select() except +
Select(const string& q_str) except +
bool isSatisfiedBy(const Select& os) const
Select& field(Field field)
string toString() const
cdef cppclass Where:
Where() except +
Where(const string& q_str)
bool isSatisfiedBy(const Where& where) const
Where& id(uint64_t id)
Where& valueType(uint16_t type)
Where& owner(InfoHash owner_pk_hash)
Where& seq(uint16_t seq_no)
Where& userType(string user_type)
string toString() const
cdef extern from "opendht/node.h" namespace "dht":
cdef cppclass Node:
Node() except +
@@ -185,35 +102,24 @@ cdef extern from "opendht/node.h" namespace "dht":
cdef extern from "opendht/callbacks.h" namespace "dht":
ctypedef void (*ShutdownCallbackRaw)(void *user_data)
ctypedef bool (*GetCallbackRaw)(shared_ptr[Value] values, void *user_data)
ctypedef bool (*ValueCallbackRaw)(shared_ptr[Value] values, bool expired, void *user_data)
ctypedef void (*DoneCallbackRaw)(bool done, vector[shared_ptr[Node]]* nodes, void *user_data)
ctypedef void (*DoneCallbackSimpleRaw)(bool done, void *user_data)
cppclass ShutdownCallback:
ShutdownCallback() except +
cppclass GetCallback:
GetCallback() except +
cppclass ValueCallback:
ValueCallback() except +
#GetCallback(GetCallbackRaw cb, void *user_data) except +
cppclass DoneCallback:
DoneCallback() except +
cppclass DoneCallbackSimple:
DoneCallbackSimple() except +
#DoneCallback(DoneCallbackRaw, void *user_data) except +
cdef ShutdownCallback bindShutdownCb(ShutdownCallbackRaw cb, void *user_data)
cdef GetCallback bindGetCb(GetCallbackRaw cb, void *user_data)
cdef ValueCallback bindValueCb(ValueCallbackRaw cb, void *user_data)
cdef DoneCallback bindDoneCb(DoneCallbackRaw cb, void *user_data)
cdef DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw cb, void *user_data)
cppclass Config:
InfoHash node_id
uint32_t network
bool is_bootstrap
bool maintain_storage
string persist_path
size_t max_req_per_sec
size_t max_peer_req_per_sec
cppclass SecureDhtConfig:
Config node_config
Identity id
@@ -228,20 +134,18 @@ cdef extern from "opendht/dhtrunner.h" namespace "dht":
bool threaded
InfoHash getId() const
InfoHash getNodeId() const
void bootstrap(const_char*, const_char*)
void bootstrap(const SockAddr&, DoneCallbackSimple done_cb)
void bootstrap(const char*, const char*)
void run(in_port_t, Config config)
void run(const_char*, const_char*, const_char*, Config config)
void run(const char*, const char*, const char*, Config config)
void join()
void shutdown(ShutdownCallback)
bool isRunning()
SockAddr getBound(sa_family_t af) const
string getStorageLog() const
string getRoutingTablesLog(sa_family_t af) const
string getSearchesLog(sa_family_t af) const
void get(InfoHash key, GetCallback get_cb, DoneCallback done_cb, nullptr_t f, Where w)
void get(InfoHash key, GetCallback get_cb, DoneCallback done_cb)
void put(InfoHash key, shared_ptr[Value] val, DoneCallback done_cb)
ListenToken listen(InfoHash key, ValueCallback get_cb)
ListenToken listen(InfoHash key, GetCallback get_cb)
void cancelListen(InfoHash key, SharedListenToken token)
vector[unsigned] getNodeMessageStats(bool i)
@@ -252,21 +156,3 @@ cdef extern from "opendht/log.h" namespace "dht::log":
void disableLogging(DhtRunner& dht)
void enableFileLogging(DhtRunner& dht, const string& path)
cdef extern from "opendht/indexation/pht.h" namespace "dht::indexation":
size_t PHT_MAX_NODE_ENTRY_COUNT "dht::indexation::Pht::MAX_NODE_ENTRY_COUNT"
cdef cppclass Prefix:
Prefix() except +
Prefix(vector[uint8_t]) except +
string toString() const
ctypedef pair[InfoHash, uint64_t] IndexValue "dht::indexation::Value"
ctypedef map[string, vector[uint8_t]] IndexKey "dht::indexation::Pht::Key"
ctypedef map[string, uint32_t] IndexKeySpec "dht::indexation::Pht::KeySpec"
ctypedef void (*LookupCallbackRaw)(vector[shared_ptr[IndexValue]]* values, Prefix* p, void* user_data);
cdef cppclass Pht:
cppclass LookupCallback:
LookupCallback() except +
Pht(string, IndexKeySpec, shared_ptr[DhtRunner]) except +
void lookup(IndexKey k, LookupCallback cb, DoneCallbackSimple doneCb);
void insert(IndexKey k, IndexValue v, DoneCallbackSimple cb)
@staticmethod
LookupCallback bindLookupCb(LookupCallbackRaw cb, void *user_data)
+5 -5
View File
@@ -1,4 +1,4 @@
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
# Copyright (C) 2015-2016 Savoir-faire Linux Inc.
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
@@ -18,7 +18,7 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with OpenDHT Python Wrapper. If not, see <https://www.gnu.org/licenses/>.
# along with OpenDHT Python Wrapper. If not, see <http://www.gnu.org/licenses/>.
#
from setuptools import setup, Extension
@@ -27,7 +27,7 @@ from Cython.Distutils import build_ext
setup(name="opendht",
version="@PACKAGE_VERSION@",
description="Python wrapper for OpenDHT",
description="Python wrapper for opendht",
url='https://github.com/savoirfairelinux/opendht',
author="Adrien Béraud, Guillaume Roguez, Simon Désaulniers",
license="GPLv3",
@@ -50,8 +50,8 @@ setup(name="opendht",
["@CURRENT_SOURCE_DIR@/opendht.pyx"],
include_dirs = ['@PROJECT_SOURCE_DIR@/include'],
language="c++",
extra_compile_args=["-std=c++14"],
extra_link_args=["-std=c++14"],
extra_compile_args=["-std=c++11"],
extra_link_args=["-std=c++11"],
libraries=["opendht"],
library_dirs = ['@CURRENT_BINARY_DIR@', '@PROJECT_BINARY_DIR@']
))
-53
View File
@@ -1,53 +0,0 @@
import unittest
import opendht as dht
class OpenDhtTester(unittest.TestCase):
# test that DhtRunner can be instatiated and deleted without throwing
def test_instance(self):
for i in range(10):
r = dht.DhtRunner()
r.run()
del r
# test that bootstraping works (raw address)
def test_bootstrap(self):
a = dht.DhtRunner()
a.run()
b = dht.DhtRunner()
b.run()
self.assertTrue(b.ping(a.getBound()))
def test_crypto(self):
i = dht.Identity.generate("id")
message = dht.InfoHash.getRandom().toString()
encrypted = i.publickey.encrypt(message)
decrypted = i.key.decrypt(encrypted)
self.assertTrue(message == decrypted)
def test_crypto_ec(self):
key = dht.PrivateKey.generateEC()
cert = dht.Certificate.generate(key, "CA", is_ca=True)
ca_id = dht.Identity(key, cert)
self.assertTrue(cert.getId() == key.getPublicKey().getId())
key2 = dht.PrivateKey.generateEC()
cert2 = dht.Certificate.generate(key2, "cert", ca_id)
trust = dht.TrustList()
trust.add(cert)
self.assertTrue(trust.verify(cert2))
def test_trust(self):
main_id = dht.Identity.generate("id_1")
sub_id1 = dht.Identity.generate("sid_1", main_id)
sub_id2 = dht.Identity.generate("sid_2", main_id)
main_id.certificate.revoke(main_id.key, sub_id2.certificate)
main_id2 = dht.Identity.generate("id_2")
trust = dht.TrustList()
trust.add(main_id.certificate)
self.assertTrue(trust.verify(main_id.certificate))
self.assertTrue(trust.verify(sub_id1.certificate))
self.assertFalse(trust.verify(sub_id2.certificate))
self.assertFalse(trust.verify(main_id2.certificate))
if __name__ == '__main__':
unittest.main()
-45
View File
@@ -1,45 +0,0 @@
# Benchmark
The `benchmark.py` script is used for testing OpenDHT in various cases. If you
run `benchmark.py --help`, you should find the following text:
optional arguments:
-h, --help show this help message and exit
--performance Launches performance benchmark test. Available args
for "-t" are: gets.
--data-persistence Launches data persistence benchmark test. Available
args for "-t" are: delete, replace, mult_time.
Available args for "-o" are : dump_str_log,
keep_alive, trigger, traffic_plot, op_plot. Use "-m"
to specify the number of producers on the DHT.Use "-e"
to specify the number of values to put on the DHT.
These options specify the feature to be tested. Each feature has its own tests.
You specify the test by using `-t` flag (see `benchmark.py --help` for full
help).
## Python dependencies
- pyroute2 >=0.3.14
- matplotlib
- GeoIP (used by `scanner.py` for drawing map of the world)
- ipaddress
- netifaces
- networkx
- numpy
## Usage
Before running the script, you have to build and install OpenDHT and its cython
wrapper (`cython3` has to be installed) on the system so that it can be found by
the benchmark script.
$ cd $OPENDHT_SRC_DIR
$ ./autogen.sh
$ ./configure
$ make && sudo make install
Then, you can use the script like so:
$ cd $OPENDHT_SRC_DIR/python/tools/
$ python3 benchmark.py --performance -t gets -n 2048
+9 -29
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
# Copyright (C) 2015-2016 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
@@ -27,7 +27,7 @@ import random
from dht.network import DhtNetwork
from dht.network import DhtNetworkSubProcess
from dht.tests import PerformanceTest, PersistenceTest, PhtTest
from dht.tests import PerformanceTest, PersistenceTest
from dht import virtual_network_builder
from dht import network as dhtnetwork
@@ -66,11 +66,7 @@ class WorkBench():
def create_virtual_net(self):
if self.virtual_locs > 1:
cmd = ["python3", os.path.abspath(virtual_network_builder.__file__),
"-i", self.ifname,
"-n", str(self.clusters),
'-l', str(self.loss),
'-d', str(self.delay)]
cmd = ["python3", os.path.abspath(virtual_network_builder.__file__), "-i", self.ifname, "-n", str(self.clusters), '-l', str(self.loss), '-d', str(self.delay)]
if not self.disable_ipv4:
cmd.append('-4')
if not self.disable_ipv6:
@@ -94,17 +90,10 @@ class WorkBench():
cmd.extend(['-b', self.local_bootstrap.ip4])
if not self.disable_ipv6 and self.local_bootstrap.ip6:
cmd.extend(['-b6', self.local_bootstrap.ip6])
lock = threading.Condition()
def dcb(success):
nonlocal lock
if not success:
DhtNetwork.Log.err("Failed to initialize network...")
with lock:
lock.notify()
with lock:
self.procs[i] = DhtNetworkSubProcess('node'+str(i), cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
self.procs[i].sendPing(done_cb=dcb)
lock.wait()
self.procs[i] = DhtNetworkSubProcess('node'+str(i), cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
while DhtNetworkSubProcess.NOTIFY_TOKEN not in self.procs[i].getline():
# waiting for process to spawn
time.sleep(0.5)
else:
raise Exception('First create bootstrap.')
@@ -168,16 +157,11 @@ if __name__ == '__main__':
featureArgs = parser.add_mutually_exclusive_group(required=True)
featureArgs.add_argument('--performance', action='store_true', default=False,
help='Launches performance benchmark test. Available args for "-t" are: gets.')
featureArgs.add_argument('--pht', action='store_true', default=False,
help='Launches PHT benchmark test. '\
'Available args for "-t" are: insert. '\
'Timer available by adding "timer" to "-o" args'\
'Use "-m" option for fixing number of keys to create during the test.')
featureArgs.add_argument('--data-persistence', action='store_true', default=0,
help='Launches data persistence benchmark test. '\
'Available args for "-t" are: delete, replace, mult_time. '\
'Available args for "-o" are : dump_str_log, keep_alive, trigger, traffic_plot, op_plot. '\
'Use "-m" to specify the number of producers on the DHT. '\
'Use "-m" to specify the number of producers on the DHT.'\
'Use "-e" to specify the number of values to put on the DHT.')
args = parser.parse_args()
@@ -186,7 +170,6 @@ if __name__ == '__main__':
wb = WorkBench(args.ifname, args.virtual_locs, args.node_num, loss=args.loss,
delay=args.delay, disable_ipv4=args.disable_ipv4,
disable_ipv6=args.disable_ipv6)
wb.create_virtual_net()
bootstrap = wb.get_bootstrap()
bs_dht_log_enabled = False
@@ -204,6 +187,7 @@ if __name__ == '__main__':
bs_dht_log_enabled = True
bootstrap.front().enableLogging()
wb.create_virtual_net()
bootstrap.resize(1)
print("Launching", wb.node_num, "nodes (", wb.clusters, "clusters of", wb.node_per_loc, "nodes)")
@@ -222,10 +206,6 @@ if __name__ == '__main__':
PerformanceTest(args.test, wb, test_opt).run()
elif args.data_persistence:
PersistenceTest(args.test, wb, test_opt).run()
elif args.pht:
if args.m:
test_opt.update({ 'num_keys' : args.m })
PhtTest(args.test, wb, test_opt).run()
except Exception as e:
print(e)
+175 -235
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
@@ -25,13 +25,11 @@ import time
import threading
import queue
import re
import traceback
import ipaddress
import netifaces
import numpy as np
from pyroute2.netns.process.proxy import NSPopen
import msgpack
from opendht import *
@@ -39,6 +37,8 @@ from opendht import *
# useful functions
b_space_join = lambda *l: b' '.join(map(bytes, l))
# TODO: find where token "notifyend" gets printed... Or switch to MSGPACK for
# serialisation of packets between both processes.
class DhtNetworkSubProcess(NSPopen):
"""
Handles communication with DhtNetwork sub process.
@@ -47,21 +47,20 @@ class DhtNetworkSubProcess(NSPopen):
process' stdout until it finds 'DhtNetworkSubProcess.NOTIFY_TOKEN' token,
therefor, waits for the sub process to spawn.
"""
# Packet types
REQUEST = 'DhtNetworkSubProcess.request'
ANSWER = 'DhtNetworkSubProcess.answer'
OUT = 'DhtNetworkSubProcess.out'
# requests
PING_REQ = "p"
NODE_PUT_REQ = "np" # "np <hash> <value>"
NEW_NODE_REQ = "nn" # "nn"
REMOVE_NODE_REQ = "rn" # "rn <id0>[ <id1>[ id2[...]]]"
SHUTDOWN_NODE_REQ = "sdn" # "sdn <id0>[ <id1>[ id2[...]]]"
SHUTDOWN_REPLACE_NODE_REQ = "sdrn" # "sdn <id0>[ <id1>[ id2[...]]]"
SHUTDOWN_CLUSTER_REQ = "sdc" # "sdc"
DUMP_STORAGE_REQ = "strl" # "strl"
MESSAGE_STATS = "gms" # "gms"
NODE_PUT_REQ = b"np"
NEW_NODE_REQ = b"nn"
REMOVE_NODE_REQ = b"rn"
SHUTDOWN_NODE_REQ = b"sdn"
SHUTDOWN_REPLACE_NODE_REQ = b'sdrn'
SHUTDOWN_CLUSTER_REQ = b"sdc"
DUMP_STORAGE_REQ = b"strl"
MESSAGE_STATS = b"gms"
# tokens
NOTIFY_TOKEN = 'notify'
NOTIFY_END_TOKEN = 'notifyend'
def __init__(self, ns, cmd, quit=False, **kwargs):
super(DhtNetworkSubProcess, self).__init__(ns, cmd, **kwargs)
@@ -71,11 +70,11 @@ class DhtNetworkSubProcess(NSPopen):
self._quit = quit
self._lock = threading.Condition()
self._in_queue = queue.Queue()
self._callbacks = {}
self._tid = 0
self._out_queue = queue.Queue()
# starting thread
self._thread = threading.Thread(target=self._communicate)
self._thread.daemon = True
self._thread.start()
def __repr__(self):
@@ -93,38 +92,42 @@ class DhtNetworkSubProcess(NSPopen):
"""
Communication thread. This reads and writes to the sub process.
"""
ENCODING = 'utf-8'
sleep_time = 0.1
stdin_line, stdout_line = '', ''
# first read of process living. Expecting NOTIFY_TOKEN
while DhtNetworkSubProcess.NOTIFY_TOKEN not in stdout_line:
stdout_line = self.stdout.readline().decode()
time.sleep(sleep_time)
with self._lock:
self._out_queue.put(stdout_line)
while not self._quit:
with self._lock:
try:
packet = self._in_queue.get_nowait()
stdin_line = self._in_queue.get_nowait()
# sending data to sub process
self.stdin.write(packet)
self.stdin.write(stdin_line if isinstance(stdin_line, bytes) else
bytes(str(stdin_line), encoding=ENCODING))
self.stdin.flush()
except queue.Empty:
pass
#waiting for next stdin req to send
self._lock.wait(timeout=sleep_time)
# reading from sub process
out_string = ''
for p in msgpack.Unpacker(self.stdout):
if isinstance(p, dict):
self._process_packet(p)
else:
# Some non-msgpack data could slip into the stream. We
# have to treat those as characters.
out_string += chr(p)
if out_string:
print(out_string)
#waiting for next stdin req to send
self._lock.wait(timeout=sleep_time)
# reading response from sub process
for stdout_line in iter(self.stdout.readline, b''):
stdout_line = stdout_line.decode().replace('\n', '')
if stdout_line:
with self._lock:
self._out_queue.put(stdout_line)
with self._lock:
self._lock.notify()
def _stop_communicating(self):
def stop_communicating(self):
"""
Stops the I/O thread from communicating with the subprocess.
"""
@@ -139,12 +142,12 @@ class DhtNetworkSubProcess(NSPopen):
Notifies thread and sub process to terminate. This is blocking call
until the sub process finishes.
"""
self._stop_communicating()
self.stop_communicating()
self.send_signal(signal.SIGINT);
self.wait()
self.release()
def _send(self, msg):
def send(self, msg):
"""
Send data to sub process.
"""
@@ -152,76 +155,83 @@ class DhtNetworkSubProcess(NSPopen):
self._in_queue.put(msg)
self._lock.notify()
def _process_packet(self, p):
def getline(self):
"""
Process msgpack packet received from
Read line from sub process.
@return: A line on sub process' stdout.
@rtype : str
"""
if not b'tid' in p:
DhtNetwork.Log.err('Bad packet...')
try:
self._callbacks[p[b'tid']](p)
except KeyError:
DhtNetwork.Log.err('Unknown tid...')
line = ''
with self._lock:
try:
line = self._out_queue.get_nowait()
except queue.Empty:
pass
return line
def getlinesUntilNotify(self, answer_cb=None):
"""
Reads the stdout queue until a proper notification is given by the sub
process.
def _sendRequest(self, request, tid, done_cb):
@param answer_cb: Callback to call when an answer is given after notify.
The function takes a list of strings as argument.
@type answer_cb: function
"""
notified = False
answer = []
while True:
out = self.getline()
if out.split(' ')[0] == DhtNetworkSubProcess.NOTIFY_TOKEN:
notified = True
elif notified and out.split(' ')[0] == DhtNetworkSubProcess.NOTIFY_END_TOKEN:
if answer_cb:
answer_cb(answer)
break
elif notified:
answer.append(out)
elif out:
yield out
else:
time.sleep(0.1)
def _sendRequest(self, request, answer_cb=None):
"""
Sends a request to the sub network and wait for output.
@param request: The serialized request.
@type request: Msgpack object
@type request: bytes
"""
self._callbacks[tid] = done_cb
self._send(request)
self.send(request + b'\n')
for line in self.getlinesUntilNotify(answer_cb=answer_cb):
DhtNetwork.log(line)
def sendPing(self, done_cb=None):
"""Sends a ping request to the DhtNetworkSubProcess.
@param done_cb: The callback to be executed when we get a response. This
function takes a boolean "success" as parameter.
@type done_cb: Function
"""
self._tid += 1
def dcb(packet):
try:
done_cb(packet[b'success'])
except KeyError:
done_cb(False)
self._sendRequest(msgpack.packb({
DhtNetworkSubProcess.REQUEST : True,
'tid' : self._tid,
'req' : DhtNetworkSubProcess.PING_REQ
}), self._tid, dcb)
def sendGetMessageStats(self, done_cb=None):
def sendGetMessageStats(self):
"""
Sends DhtNetwork sub process statistics request about nodes messages
sent.
@param done_cb: A function taking as parameter the returned list of
stats.
@type done_cb: function
@return: A list [num_nodes, ping, find, get, put, listen].
@rtype : list
"""
self._tid += 1
def dcb(packet):
nonlocal done_cb
if not done_cb:
return
try:
stats = packet[b'stats']
done_cb([] if not isinstance(stats, list) else done_cb(stats))
except KeyError:
done_cb([])
self._sendRequest(msgpack.packb({
DhtNetworkSubProcess.REQUEST : True,
'tid' : self._tid,
'req' : DhtNetworkSubProcess.MESSAGE_STATS
}), self._tid, dcb)
stats = []
def cb(answer):
"""
Callback fed to getlinesUntilNotify made to recover answer from the
DhtNetwork sub process.
def sendClusterPutRequest(self, _hash, value, done_cb=None):
@param answer: the list of lines answered by the sub process.
@type answer: function
"""
nonlocal stats
if answer:
stats = [int(v) for v in re.findall("[0-9]+", answer.pop())]
self._sendRequest(DhtNetworkSubProcess.MESSAGE_STATS, answer_cb=cb)
return stats
def sendNodePutRequest(self, _hash, value):
"""
Sends a put operation request.
@@ -229,89 +239,40 @@ class DhtNetworkSubProcess(NSPopen):
@type _hash: bytes.
@param value: the value.
@type value: bytes.
@param done_cb: A function taking as parameter a boolean "success".
@type done_cb: function
"""
self._tid += 1
def dcb(packet):
nonlocal done_cb
if not done_cb:
return
try:
done_cb(packet[b'success'])
except KeyError:
done_cb(False)
self._sendRequest(msgpack.packb({
DhtNetworkSubProcess.REQUEST : True,
'tid' : self._tid,
'req' : DhtNetworkSubProcess.NODE_PUT_REQ,
'hash' : _hash,
'value' : value
}), self._tid, dcb)
self._sendRequest(b_space_join(DhtNetworkSubProcess.NODE_PUT_REQ, _hash,
value))
def sendClusterRequest(self, request, ids=[], done_cb=None):
def sendNodesRequest(self, request, ids=b''):
"""
Send request to a list of nodes or the whole cluster.
@param request: The request. Possible values are:
DhtNetworkSubProcess.NODE_PUT_REQ
DhtNetworkSubProcess.REMOVE_NODE_REQ
DhtNetworkSubProcess.SHUTDOWN_NODE_REQ
DhtNetworkSubProcess.SHUTDOWN_REPLACE_NODE_REQ
DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ
DhtNetworkSubProcess.DUMP_STORAGE_REQ
DhtNetworkSubProcess.MESSAGE_STATS
@type request: bytes
@param ids: The list of ids concerned by the request.
@type ids: list
"""
self._tid += 1
def dcb(packet):
nonlocal done_cb
if not done_cb:
return
try:
done_cb(packet[b'success'])
except KeyError:
done_cb(False)
self._sendRequest(msgpack.packb({
DhtNetworkSubProcess.REQUEST : True,
'tid' : self._tid,
'req' : request,
'ids' : ids
}), self._tid, dcb)
self._sendRequest(b_space_join(request, b_space_join(*ids)))
class DhtNetwork(object):
nodes = []
class Log(object):
@staticmethod
def log(*to_print):
BOLD = "\033[1m"
NORMAL = "\033[0m"
WHITE = "\033[97m"
RED = "\033[31m"
YELLOW = "\033[33m"
@staticmethod
def _log_with_color(*to_print, color=None):
color = color if color else DhtNetwork.Log.WHITE
print('%s%s[DhtNetwork-%s]%s%s' %
(DhtNetwork.Log.BOLD, color, DhtNetwork.iface, DhtNetwork.Log.NORMAL, color),
*to_print, DhtNetwork.Log.NORMAL, file=sys.stderr)
@staticmethod
def log(*to_print):
DhtNetwork.Log._log_with_color(*to_print, color=DhtNetwork.Log.WHITE)
@staticmethod
def warn(*to_print):
DhtNetwork.Log._log_with_color(*to_print, color=DhtNetwork.Log.YELLOW)
@staticmethod
def err(*to_print):
DhtNetwork.Log._log_with_color(*to_print, color=DhtNetwork.Log.RED)
print('%s[DhtNetwork-%s]%s' % (BOLD, DhtNetwork.iface, NORMAL), ':' , *to_print, file=sys.stderr)
@staticmethod
def run_node(ip4, ip6, p, bootstrap=[], is_bootstrap=False):
DhtNetwork.Log.log("run_node", ip4, ip6, p, bootstrap)
DhtNetwork.log("run_node", ip4, ip6, p, bootstrap)
n = DhtRunner()
n.run(ipv4=ip4 if ip4 else "", ipv6=ip6 if ip6 else "", port=p, is_bootstrap=is_bootstrap)
for b in bootstrap:
@@ -336,7 +297,7 @@ class DhtNetwork(object):
self.ip6 = ip6 if ip6 else ips[1]
self.bootstrap = bootstrap
if first_bootstrap:
DhtNetwork.Log.log("Starting bootstrap node")
DhtNetwork.log("Starting bootstrap node")
self.nodes.append(DhtNetwork.run_node(self.ip4, self.ip6, self.port, self.bootstrap, is_bootstrap=True))
self.bootstrap = [(self.ip4, str(self.port))]
self.port += 1
@@ -348,9 +309,6 @@ class DhtNetwork(object):
return self.nodes[0][1]
def get(self, i=None):
if not self.nodes:
return None
if i is None:
l = list(self.nodes)
random.shuffle(l)
@@ -363,13 +321,14 @@ class DhtNetwork(object):
for n in self.nodes:
if n[1].getNodeId() == id:
return n
return None
else:
return None
def launch_node(self):
n = DhtNetwork.run_node(self.ip4, self.ip6, self.port, self.bootstrap)
self.nodes.append(n)
if not self.bootstrap:
DhtNetwork.Log.log("Using fallback bootstrap", self.ip4, self.port)
DhtNetwork.log("Using fallback bootstrap", self.ip4, self.port)
self.bootstrap = [(self.ip4, str(self.port))]
self.port += 1
return n
@@ -387,25 +346,25 @@ class DhtNetwork(object):
lock = threading.Condition()
def shutdown_cb():
nonlocal lock
DhtNetwork.Log.log('Done.')
DhtNetwork.log('Done.')
with lock:
lock.notify()
if not self.nodes:
return
elif id:
elif id is not None:
n = self.getNodeInfoById(id)
if n:
if shutdown:
with lock:
DhtNetwork.Log.log('Waiting for node to shutdown... ')
DhtNetwork.log('Waiting for node to shutdown... ')
n[1].shutdown(shutdown_cb)
lock.wait()
if last_msg_stats:
last_msg_stats.append(self.getMessageStats())
n[1].join()
self.nodes.remove(n)
DhtNetwork.Log.log(id, 'deleted !')
DhtNetwork.log(id, 'deleted !')
return True
else:
return False
@@ -426,11 +385,11 @@ class DhtNetwork(object):
if n == l:
return
if n > l:
DhtNetwork.Log.log("Launching", n-l, "nodes", self.ip4, self.ip6)
DhtNetwork.log("Launching", n-l, "nodes", self.ip4, self.ip6)
for i in range(l, n):
self.launch_node()
else:
DhtNetwork.Log.log("Ending", l-n, "nodes", self.ip4, self.ip6)
DhtNetwork.log("Ending", l-n, "nodes", self.ip4, self.ip6)
#random.shuffle(self.nodes)
for i in range(n, l):
self.end_node()
@@ -450,39 +409,30 @@ if __name__ == '__main__':
lock = threading.Condition()
quit = False
def send_msgpack_packet(packet):
sys.stdout.buffer.write(packet)
sys.stdout.buffer.flush()
def notify_benchmark(answer=[]):
sys.stdout.write('%s\n' % DhtNetworkSubProcess.NOTIFY_TOKEN)
for line in answer:
sys.stdout.write(str(line)+'\n')
sys.stdout.write('%s\n' % DhtNetworkSubProcess.NOTIFY_END_TOKEN)
sys.stdout.flush()
def notify_benchmark(packet, success):
"""Notifies the benchmark when an operation has been completed.
@param success: If the operation has been successful
@type success: boolean
@param packet: The packet we are providing an answer for.
@type packet: dict
"""
send_msgpack_packet(msgpack.packb({
DhtNetworkSubProcess.ANSWER : True,
'tid' : packet[b'tid'],
'success' : success
}))
def send_stats(packet, stats):
send_msgpack_packet(msgpack.packb({
DhtNetworkSubProcess.ANSWER : True,
'tid' : packet[b'tid'],
'stats' : stats
}))
def listen_to_mother_nature(q):
def listen_to_mother_nature(stdin, q):
global quit
def parse_req(req):
split_req = req.split(' ')
op = split_req[0]
hashes = [this_hash.replace('\n', '').encode() for this_hash in split_req[1:]]
return (op, hashes)
while not quit:
for p in msgpack.Unpacker(sys.stdin.buffer.raw):
if isinstance(p, dict) and DhtNetworkSubProcess.REQUEST.encode() in p:
with lock:
q.put(p)
lock.notify()
req = stdin.readline()
parsed_req = parse_req(req)
q.put(parsed_req)
with lock:
lock.notify()
def handler(signum, frame):
global quit
@@ -516,52 +466,48 @@ if __name__ == '__main__':
net.resize(args.node_num)
q = queue.Queue()
t = threading.Thread(target=listen_to_mother_nature, args=tuple([q]))
t = threading.Thread(target=listen_to_mother_nature, args=(sys.stdin, q))
t.daemon = True
t.start()
notify_benchmark()
msg_stats = []
with lock:
while not quit:
lock.wait()
try:
packet = q.get_nowait()
req,req_args = q.get_nowait()
except queue.Empty:
lock.wait()
pass
else:
NODE_PUT_REQ = DhtNetworkSubProcess.NODE_PUT_REQ
NEW_NODE_REQ = DhtNetworkSubProcess.NEW_NODE_REQ
REMOVE_NODE_REQ = DhtNetworkSubProcess.REMOVE_NODE_REQ
SHUTDOWN_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_NODE_REQ
SHUTDOWN_REPLACE_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_REPLACE_NODE_REQ
SHUTDOWN_CLUSTER_REQ = DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ
DUMP_STORAGE_REQ = DhtNetworkSubProcess.DUMP_STORAGE_REQ
MESSAGE_STATS = DhtNetworkSubProcess.MESSAGE_STATS
NODE_PUT_REQ = DhtNetworkSubProcess.NODE_PUT_REQ.decode()
NEW_NODE_REQ = DhtNetworkSubProcess.NEW_NODE_REQ.decode()
REMOVE_NODE_REQ = DhtNetworkSubProcess.REMOVE_NODE_REQ.decode()
SHUTDOWN_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_NODE_REQ.decode()
SHUTDOWN_REPLACE_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_REPLACE_NODE_REQ.decode()
SHUTDOWN_CLUSTER_REQ = DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ.decode()
DUMP_STORAGE_REQ = DhtNetworkSubProcess.DUMP_STORAGE_REQ.decode()
MESSAGE_STATS = DhtNetworkSubProcess.MESSAGE_STATS.decode()
req = packet[b'req'].decode()
success = True
if req in [SHUTDOWN_NODE_REQ, SHUTDOWN_REPLACE_NODE_REQ, REMOVE_NODE_REQ]:
def delete_request(req, nid):
if req in [SHUTDOWN_NODE_REQ,
SHUTDOWN_REPLACE_NODE_REQ,
REMOVE_NODE_REQ]:
def delete_request(req, n):
global msg_stats
if not nid:
return
if req == SHUTDOWN_NODE_REQ:
net.end_node(id=nid, shutdown=True, last_msg_stats=msg_stats)
net.end_node(id=n, shutdown=True, last_msg_stats=msg_stats)
elif req == SHUTDOWN_REPLACE_NODE_REQ:
net.replace_node(id=nid, shutdown=True, last_msg_stats=msg_stats)
net.replace_node(id=n, shutdown=True, last_msg_stats=msg_stats)
elif req == REMOVE_NODE_REQ:
net.end_node(id=nid, last_msg_stats=msg_stats)
net.end_node(id=n, last_msg_stats=msg_stats)
nodes = packet[b'ids']
if nodes:
for nid in nodes:
delete_request(req, nid)
if len(req) > 0:
for n in req_args:
delete_request(req, n)
else:
n = net.get()
if n:
delete_request(req, n.getNodeId())
else:
success = False
delete_request(req, net.get().getNodeId())
elif req == SHUTDOWN_CLUSTER_REQ:
for n in net.nodes:
net.end_node(id=n[2], shutdown=True, last_msg_stats=msg_stats)
@@ -569,26 +515,20 @@ if __name__ == '__main__':
elif req == NEW_NODE_REQ:
net.launch_node()
elif req == NODE_PUT_REQ:
_hash = packet[b'hash']
v = packet[b'value']
n = net.get()
if n:
n.put(InfoHash(_hash), Value(v))
else:
success = False
_hash, v = req_args[:2]
net.get().put(InfoHash(_hash), Value(v))
elif req == DUMP_STORAGE_REQ:
hashes = packet[b'ids']
for n in [m[1] for m in net.nodes if m[1].getNodeId() in hashes]:
for n in [m[1] for m in net.nodes if m[1].getNodeId() in req_args]:
net.log(n.getStorageLog())
elif req == MESSAGE_STATS:
elif MESSAGE_STATS in req:
stats = sum([np.array(x) for x in [net.getMessageStats()]+msg_stats])
send_stats(packet, [int(_) for _ in stats])
notify_benchmark(answer=[stats])
msg_stats.clear()
continue
notify_benchmark(packet, success)
notify_benchmark()
except Exception as e:
traceback.print_tb(e.__traceback__)
print(type(e).__name__+':', e, file=sys.stderr)
DhtNetwork.log(e)
finally:
if net:
net.resize(0)
+120 -363
View File
@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2019 Savoir-Faire Linux Inc.
# Copyright (C) 2015 Savoir-Faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
import sys
import os
import threading
import random
@@ -11,17 +10,10 @@ import string
import time
import subprocess
import re
import traceback
import collections
from matplotlib.ticker import FuncFormatter
import math
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from networkx.drawing.nx_agraph import graphviz_layout
from matplotlib.ticker import FuncFormatter
from opendht import *
from dht.network import DhtNetwork, DhtNetworkSubProcess
@@ -35,40 +27,8 @@ bit_format = None
Kbit_format = FuncFormatter(lambda x, pos: '%1.1f' % (x*1024**-1) + 'Kb')
Mbit_format = FuncFormatter(lambda x, pos: '%1.1f' % (x*1024**-2) + 'Mb')
def random_str_val(size=1024):
"""Creates a random string value of specified size.
@param size: Size, in bytes, of the value.
@type size: int
@return: Random string value
@rtype : str
"""
return ''.join(random.choice(string.hexdigits) for _ in range(size))
def random_hash():
"""Creates random InfoHash.
"""
return InfoHash(random_str_val(size=40).encode())
def timer(f, *args):
"""
Start a timer which count time taken for execute function f
@param f : Function to time
@type f : function
@param args : Arguments of the function f
@type args : list
@rtype : timer
@return : Time taken by the function f
"""
start = time.time()
f(*args)
return time.time() - start
return InfoHash(''.join(random.SystemRandom().choice(string.hexdigits) for _ in range(40)).encode())
def reset_before_test(featureTestMethod):
"""
@@ -110,21 +70,6 @@ def display_plot(yvals, xvals=None, yformatter=None, display_time=3, **kwargs):
plt.plot(yvals, **kwargs)
plt.pause(display_time)
def display_traffic_plot(ifname):
"""Displays the traffic plot for a given interface name.
@param ifname: Interface name.
@type ifname: string
"""
ydata = []
xdata = []
# warning: infinite loop
interval = 2
for rate in iftop_traffic_data(ifname, interval=interval):
ydata.append(rate)
xdata.append((xdata[-1] if len(xdata) > 0 else 0) + interval)
display_plot(ydata, xvals=xdata, yformatter=Kbit_format, color='blue')
def iftop_traffic_data(ifname, interval=2, rate_type='send_receive'):
"""
Generator (yields data) function collecting traffic data from iftop
@@ -180,13 +125,13 @@ def iftop_traffic_data(ifname, interval=2, rate_type='send_receive'):
###########
class FeatureTest(object):
done = 0
lock = None
"""
This is a base test.
"""
done = 0
lock = None
def __init__(self, test, workbench):
"""
@param test: The test string indicating the test to run. This string is
@@ -198,7 +143,6 @@ class FeatureTest(object):
"""
self._test = test
self._workbench = workbench
self._bootstrap = self._workbench.get_bootstrap()
def _reset(self):
"""
@@ -212,155 +156,7 @@ class FeatureTest(object):
def run(self):
raise NotImplementedError('This method must be implemented.')
##################################
# PHT #
##################################
class PhtTest(FeatureTest):
"""TODO
"""
indexEntries = None
prefix = None
key = None
def __init__(self, test, workbench, opts):
"""
@param test: is one of the following:
- 'insert': indexes a considerable amount of data in
the PHT structure.
TODO
@type test: string
@param opts: Dictionnary containing options for the test. Allowed
options are:
- 'num_keys': this specifies the number of keys to insert
in the PHT during the test.
@type opts: dict
"""
super(PhtTest, self).__init__(test, workbench)
self._num_keys = opts['num_keys'] if 'num_keys' in opts else 32
self._timer = True if 'timer' in opts else False
def _reset(self):
super(PhtTest, self)._reset()
PhtTest.indexEntries = []
@staticmethod
def lookupCb(vals, prefix):
PhtTest.indexEntries = list(vals)
PhtTest.prefix = prefix.decode()
DhtNetwork.log('Index name: <todo>')
DhtNetwork.log('Leaf prefix:', prefix)
for v in vals:
DhtNetwork.log('[ENTRY]:', v)
@staticmethod
def lookupDoneCb(ok):
DhtNetwork.log('[LOOKUP]:', PhtTest.key, "--", "success!" if ok else "Fail...")
with FeatureTest.lock:
FeatureTest.lock.notify()
@staticmethod
def insertDoneCb(ok):
DhtNetwork.log('[INSERT]:', PhtTest.key, "--", "success!" if ok else "Fail...")
with FeatureTest.lock:
FeatureTest.lock.notify()
@staticmethod
def drawTrie(trie_dict):
"""
Draws the trie structure of the PHT from dictionnary.
@param trie_dict: Dictionnary of index entries (prefix -> entry).
@type trie_dict: dict
"""
prefixes = list(trie_dict.keys())
if len(prefixes) == 0:
return
edges = list([])
for prefix in prefixes:
for i in range(-1, len(prefix)-1):
u = prefix[:i+1]
x = ("." if i == -1 else u, u+"0")
y = ("." if i == -1 else u, u+"1")
if x not in edges:
edges.append(x)
if y not in edges:
edges.append(y)
# TODO: use a binary tree position layout...
# UPDATE : In a better way [change lib]
G = nx.Graph(sorted(edges, key=lambda x: len(x[0])))
plt.title("PHT: Tree")
pos=graphviz_layout(G,prog='dot')
nx.draw(G, pos, with_labels=True, node_color='white')
plt.show()
def run(self):
try:
if self._test == 'insert':
self._insertTest()
except Exception as e:
print(e)
finally:
self._bootstrap.resize(1)
###########
# Tests #
###########
@reset_before_test
def _insertTest(self):
"""TODO: Docstring for _massIndexTest.
"""
bootstrap = self._bootstrap
bootstrap.resize(2)
dht = bootstrap.get(1)
NUM_DIG = max(math.log(self._num_keys, 2)/4, 5) # at least 5 digit keys.
keyspec = collections.OrderedDict([('foo', NUM_DIG)])
pht = Pht(b'foo_index', keyspec, dht)
DhtNetwork.log('PHT has',
pht.MAX_NODE_ENTRY_COUNT,
'node'+ ('s' if pht.MAX_NODE_ENTRY_COUNT > 1 else ''),
'per leaf bucket.')
keys = [{
[_ for _ in keyspec.keys()][0] :
''.join(random.SystemRandom().choice(string.hexdigits)
for _ in range(NUM_DIG)).encode()
} for n in range(self._num_keys)]
all_entries = {}
# Index all entries.
for key in keys:
PhtTest.key = key
with FeatureTest.lock:
time_taken = timer(pht.insert, key, IndexValue(random_hash()), PhtTest.insertDoneCb)
if self._timer:
DhtNetwork.log('This insert step took : ', time_taken, 'second')
FeatureTest.lock.wait()
time.sleep(1)
# Recover entries now that the trie is complete.
for key in keys:
PhtTest.key = key
with FeatureTest.lock:
time_taken = timer(pht.lookup, key, PhtTest.lookupCb, PhtTest.lookupDoneCb)
if self._timer:
DhtNetwork.log('This lookup step took : ', time_taken, 'second')
FeatureTest.lock.wait()
all_entries[PhtTest.prefix] = [e.__str__()
for e in PhtTest.indexEntries]
for p in all_entries.keys():
DhtNetwork.log('All entries under prefix', p, ':')
DhtNetwork.log(all_entries[p])
PhtTest.drawTrie(all_entries)
##################################
# DHT #
@@ -368,7 +164,7 @@ class PhtTest(FeatureTest):
class DhtFeatureTest(FeatureTest):
"""
This is a base dht test.
This is base test. A method run() implementation is required.
"""
#static variables used by class callbacks
successfullTransfer = lambda lv,fv: len(lv) == len(fv)
@@ -377,6 +173,7 @@ class DhtFeatureTest(FeatureTest):
def __init__(self, test, workbench):
super(DhtFeatureTest, self).__init__(test, workbench)
self.bootstrap = self._workbench.get_bootstrap()
def _reset(self):
super(DhtFeatureTest, self)._reset()
@@ -386,15 +183,15 @@ class DhtFeatureTest(FeatureTest):
@staticmethod
def getcb(value):
vstr = value.__str__()[:100]
DhtNetwork.Log.log('[GET]: %s' % vstr + ("..." if len(vstr) > 100 else ""))
DhtNetwork.log('[GET]: %s' % vstr + ("..." if len(vstr) > 100 else ""))
DhtFeatureTest.foreignValues.append(value)
return True
@staticmethod
def putDoneCb(ok, nodes):
if not ok:
DhtNetwork.log("[PUT]: failed!")
with FeatureTest.lock:
if not ok:
DhtNetwork.Log.log("[PUT]: failed!")
FeatureTest.done -= 1
FeatureTest.lock.notify()
@@ -402,7 +199,7 @@ class DhtFeatureTest(FeatureTest):
def getDoneCb(ok, nodes):
with FeatureTest.lock:
if not ok:
DhtNetwork.Log.log("[GET]: failed!")
DhtNetwork.log("[GET]: failed!")
else:
for node in nodes:
if not node.getNode().isExpired():
@@ -413,10 +210,10 @@ class DhtFeatureTest(FeatureTest):
def _dhtPut(self, producer, _hash, *values):
with FeatureTest.lock:
for val in values:
vstr = val.__str__()[:100]
DhtNetwork.Log.log('[PUT]:', _hash.toString(), '->', vstr + ("..." if len(vstr) > 100 else ""))
FeatureTest.done += 1
producer.put(_hash, val, DhtFeatureTest.putDoneCb)
vstr = val.__str__()[:100]
DhtNetwork.log('[PUT]:', _hash.toString(), '->', vstr + ("..." if len(vstr) > 100 else ""))
FeatureTest.done += 1
producer.put(_hash, val, DhtFeatureTest.putDoneCb)
while FeatureTest.done > 0:
FeatureTest.lock.wait()
@@ -425,7 +222,7 @@ class DhtFeatureTest(FeatureTest):
DhtFeatureTest.foreignNodes = []
with FeatureTest.lock:
FeatureTest.done += 1
DhtNetwork.Log.log('[GET]:', _hash.toString())
DhtNetwork.log('[GET]:', _hash.toString())
consumer.get(_hash, DhtFeatureTest.getcb, DhtFeatureTest.getDoneCb)
while FeatureTest.done > 0:
FeatureTest.lock.wait()
@@ -437,6 +234,7 @@ class DhtFeatureTest(FeatureTest):
for n in DhtFeatureTest.foreignNodes:
nodes.add(n)
class PersistenceTest(DhtFeatureTest):
"""
This tests persistence of data on the network.
@@ -494,8 +292,8 @@ class PersistenceTest(DhtFeatureTest):
config.setNodeId(InfoHash(_hash_str.encode()))
n = DhtRunner()
n.run(config=config)
n.bootstrap(self._bootstrap.ip4,
str(self._bootstrap.port))
n.bootstrap(self.bootstrap.ip4,
str(self.bootstrap.port))
DhtNetwork.log('Node','['+_hash_str+']',
'started around', _hash.toString().decode()
if n.isRunning() else
@@ -504,24 +302,24 @@ class PersistenceTest(DhtFeatureTest):
trigger_nodes.append(n)
def _result(self, local_values, new_nodes):
bootstrap = self._bootstrap
bootstrap = self.bootstrap
if not DhtFeatureTest.successfullTransfer(local_values, DhtFeatureTest.foreignValues):
DhtNetwork.Log.log('[GET]: Only %s on %s values persisted.' %
DhtNetwork.log('[GET]: Only %s on %s values persisted.' %
(len(DhtFeatureTest.foreignValues), len(local_values)))
else:
DhtNetwork.Log.log('[GET]: All values successfully persisted.')
DhtNetwork.log('[GET]: All values successfully persisted.')
if DhtFeatureTest.foreignValues:
if new_nodes:
DhtNetwork.Log.log('Values are newly found on:')
DhtNetwork.log('Values are newly found on:')
for node in new_nodes:
DhtNetwork.Log.log(node)
DhtNetwork.log(node)
if self._dump_storage:
DhtNetwork.Log.log('Dumping all storage log from '\
DhtNetwork.log('Dumping all storage log from '\
'hosting nodes.')
for proc in self._workbench.procs:
proc.sendClusterRequest(DhtNetworkSubProcess.DUMP_STORAGE_REQ, DhtFeatureTest.foreignNodes)
proc.sendNodesRequest(DhtNetworkSubProcess.DUMP_STORAGE_REQ, DhtFeatureTest.foreignNodes)
else:
DhtNetwork.Log.log("Values didn't reach new hosting nodes after shutdown.")
DhtNetwork.log("Values didn't reach new hosting nodes after shutdown.")
def run(self):
try:
@@ -536,14 +334,13 @@ class PersistenceTest(DhtFeatureTest):
else:
raise NameError("This test is not defined '" + self._test + "'")
except Exception as e:
traceback.print_tb(e.__traceback__)
print(type(e).__name__+':', e, file=sys.stderr)
print(e)
finally:
if self._traffic_plot or self._op_plot:
plot_fname = "traffic-plot"
print('plot saved to', plot_fname)
plt.savefig(plot_fname)
self._bootstrap.resize(1)
self.bootstrap.resize(1)
###########
# Tests #
@@ -556,89 +353,71 @@ class PersistenceTest(DhtFeatureTest):
"""
trigger_nodes = []
wb = self._workbench
bootstrap = self._bootstrap
bootstrap = self.bootstrap
# Value representing an ICE packet. Each ICE packet is around 1KB.
VALUE_SIZE = 1024
num_values_per_hash = self._num_values/wb.node_num if self._num_values else 5
# nodes and values counters
total_nr_values = 0
NUM_VALUES = self._num_values/wb.node_num if self._num_values else 5
nr_values = NUM_VALUES * wb.node_num
nr_nodes = wb.node_num
op_cv = threading.Condition()
nr_nodes_cv = threading.Condition()
# values string in string format. Used for sending cluster request.
values = [b''.join(random.choice(string.hexdigits).encode() for _ in range(VALUE_SIZE)) for __ in range(NUM_VALUES)]
hashes = [random_hash() for _ in range(wb.node_num)]
def normalBehavior(do, t):
nonlocal total_nr_values, op_cv
# initial set of values
i = 0
for h in hashes:
self._dhtPut(bootstrap.front(), h, *[Value(v) for v in values])
print("at: ", i)
i += 1
def normalBehavior(do, t, log=None):
nonlocal nr_values
while True:
with op_cv:
do()
time.sleep(random.uniform(0.0, float(t)))
do()
time.sleep(random.choice(range(t)))
def putRequest():
nonlocal hashes, VALUE_SIZE, total_nr_values
lock = threading.Condition()
def dcb(success):
nonlocal total_nr_values, lock
if success:
total_nr_values += 1
DhtNetwork.Log.log("INFO: "+ str(total_nr_values)+" values put on the dht since begining")
with lock:
lock.notify()
with lock:
DhtNetwork.Log.warn("Random value put on the DHT...")
random.choice(wb.procs).sendClusterPutRequest(random.choice(hashes).toString(),
random_str_val(size=VALUE_SIZE).encode(),
done_cb=dcb)
lock.wait()
puts = threading.Thread(target=normalBehavior, args=(putRequest, 30.0/wb.node_num))
nonlocal hashes, values, nr_values
nr_values += 1
DhtNetwork.log("Random value put on the DHT.", "(now "+ str(nr_values)+" values on the dht)")
random.choice(wb.procs).sendNodePutRequest(random.choice(hashes).toString(), random.choice(values))
puts = threading.Thread(target=normalBehavior, args=(putRequest, 30))
puts.daemon = True
puts.start()
def newNodeRequest():
nonlocal nr_nodes
lock = threading.Condition()
def dcb(success):
nonlocal nr_nodes, lock
with nr_nodes_cv:
nr_nodes += 1
DhtNetwork.Log.log("INFO: now "+str(nr_nodes)+" nodes on the dht")
with lock:
lock.notify()
with lock:
DhtNetwork.Log.warn("Node joining...")
random.choice(wb.procs).sendClusterRequest(DhtNetworkSubProcess.NEW_NODE_REQ, done_cb=dcb)
lock.wait()
connections = threading.Thread(target=normalBehavior, args=(newNodeRequest, 1*50.0/wb.node_num))
DhtNetwork.log("Node joining the DHT.", "(now "+str(nr_nodes)+" nodes on the dht)")
nr_nodes_cv.notify()
random.choice(wb.procs).sendNodesRequest(DhtNetworkSubProcess.NEW_NODE_REQ)
connections = threading.Thread(target=normalBehavior, args=(newNodeRequest, 1*60))
connections.daemon = True
connections.start()
def shutdownNodeRequest():
nonlocal nr_nodes
lock = threading.Condition()
def dcb(success):
nonlocal nr_nodes, lock
if success:
nr_nodes -= 1
DhtNetwork.Log.log("INFO: now "+str(nr_nodes)+" nodes on the dht")
else:
DhtNetwork.Log.err("Oops.. No node to shutodwn.")
with lock:
lock.notify()
with lock:
DhtNetwork.Log.warn("Node shutting down...")
random.choice(wb.procs).sendClusterRequest(DhtNetworkSubProcess.SHUTDOWN_NODE_REQ, done_cb=dcb)
lock.wait()
shutdowns = threading.Thread(target=normalBehavior, args=(shutdownNodeRequest, 1*60.0/wb.node_num))
with nr_nodes_cv:
nr_nodes -= 1
DhtNetwork.log("Node quitting the DHT.", "(now "+str(nr_nodes)+" nodes on the dht)")
nr_nodes_cv.notify()
random.choice(wb.procs).sendNodesRequest(DhtNetworkSubProcess.SHUTDOWN_NODE_REQ)
shutdowns = threading.Thread(target=normalBehavior, args=(shutdownNodeRequest, 1*60))
shutdowns.daemon = True
shutdowns.start()
for h in hashes:
self._trigger_dp(trigger_nodes, h)
if self._traffic_plot:
display_traffic_plot('br'+wb.ifname)
ydata = []
xdata = []
# warning: infinite loop
interval = 2
for rate in iftop_traffic_data("br"+wb.ifname, interval=interval):
ydata.append(rate)
xdata.append((xdata[-1] if len(xdata) > 0 else 0) + interval)
display_plot(ydata, xvals=xdata, yformatter=Kbit_format, color='blue')
else:
# blocks in matplotlib thread
while True:
@@ -651,7 +430,7 @@ class PersistenceTest(DhtFeatureTest):
It uses Dht shutdown call from the API to gracefuly finish the nodes one
after the other.
"""
bootstrap = self._bootstrap
bootstrap = self.bootstrap
ops_count = []
@@ -668,54 +447,36 @@ class PersistenceTest(DhtFeatureTest):
self._dhtGet(consumer, myhash)
if not DhtFeatureTest.successfullTransfer(local_values, DhtFeatureTest.foreignValues):
if DhtFeatureTest.foreignValues:
DhtNetwork.Log.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
DhtNetwork.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
len(local_values), ' values successfully put.')
else:
DhtNetwork.Log.log('[GET]: 0 values successfully put')
DhtNetwork.log('[GET]: 0 values successfully put')
if DhtFeatureTest.foreignValues and DhtFeatureTest.foreignNodes:
DhtNetwork.Log.log('Values are found on :')
DhtNetwork.log('Values are found on :')
for node in DhtFeatureTest.foreignNodes:
DhtNetwork.Log.log(node)
DhtNetwork.log(node)
for _ in range(max(1, int(self._workbench.node_num/32))):
DhtNetwork.Log.log('Removing all nodes hosting target values...')
DhtNetwork.log('Removing all nodes hosting target values...')
cluster_ops_count = 0
for proc in self._workbench.procs:
DhtNetwork.Log.log('[REMOVE]: sending shutdown request to', proc)
lock = threading.Condition()
def dcb(success):
nonlocal lock
if not success:
DhtNetwork.Log.err("Failed to shutdown.")
with lock:
lock.notify()
with lock:
proc.sendClusterRequest(
DhtNetwork.log('[REMOVE]: sending shutdown request to', proc)
proc.sendNodesRequest(
DhtNetworkSubProcess.SHUTDOWN_NODE_REQ,
DhtFeatureTest.foreignNodes,
done_cb=dcb
)
lock.wait()
DhtNetwork.Log.log('sending message stats request')
def msg_dcb(stats):
nonlocal cluster_ops_count, lock
if stats:
cluster_ops_count += sum(stats[1:])
with lock:
lock.notify()
with lock:
proc.sendGetMessageStats(done_cb=msg_dcb)
lock.wait()
DhtNetwork.Log.log("5 seconds wait...")
DhtFeatureTest.foreignNodes
)
DhtNetwork.log('sending message stats request')
stats = proc.sendGetMessageStats()
cluster_ops_count += sum(stats[1:])
DhtNetwork.log("5 seconds wait...")
time.sleep(5)
ops_count.append(cluster_ops_count/self._workbench.node_num)
# checking if values were transfered to new nodes
foreignNodes_before_delete = DhtFeatureTest.foreignNodes
DhtNetwork.Log.log('[GET]: trying to fetch persistent values')
DhtNetwork.log('[GET]: trying to fetch persistent values')
self._dhtGet(consumer, myhash)
new_nodes = set(DhtFeatureTest.foreignNodes) - set(foreignNodes_before_delete)
@@ -724,11 +485,7 @@ class PersistenceTest(DhtFeatureTest):
if self._op_plot:
display_plot(ops_count, color='blue')
else:
DhtNetwork.Log.log("[GET]: either couldn't fetch values or nodes hosting values...")
if traffic_plot_thread:
print("Traffic plot running for ever. Ctrl-c for stopping it.")
traffic_plot_thread.join()
DhtNetwork.log("[GET]: either couldn't fetch values or nodes hosting values...")
@reset_before_test
def _replaceClusterTest(self):
@@ -737,7 +494,7 @@ class PersistenceTest(DhtFeatureTest):
"""
clusters = 8
bootstrap = self._bootstrap
bootstrap = self.bootstrap
bootstrap.resize(3)
consumer = bootstrap.get(1)
@@ -750,16 +507,16 @@ class PersistenceTest(DhtFeatureTest):
self._dhtGet(consumer, myhash)
initial_nodes = DhtFeatureTest.foreignNodes
DhtNetwork.Log.log('Replacing', clusters, 'random clusters successively...')
DhtNetwork.log('Replacing', clusters, 'random clusters successively...')
for n in range(clusters):
i = random.randint(0, len(self._workbench.procs)-1)
proc = self._workbench.procs[i]
DhtNetwork.Log.log('Replacing', proc)
proc.sendClusterRequest(DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ)
DhtNetwork.log('Replacing', proc)
proc.sendNodesRequest(DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ)
self._workbench.stop_cluster(i)
self._workbench.start_cluster(i)
DhtNetwork.Log.log('[GET]: trying to fetch persistent values')
DhtNetwork.log('[GET]: trying to fetch persistent values')
self._dhtGet(consumer, myhash)
new_nodes = set(DhtFeatureTest.foreignNodes) - set(initial_nodes)
@@ -774,17 +531,17 @@ class PersistenceTest(DhtFeatureTest):
minutes for the nodes to trigger storage maintenance.
"""
trigger_nodes = []
bootstrap = self._bootstrap
bootstrap = self.bootstrap
N_PRODUCERS = self._num_producers if self._num_values else 16
DP_TIMEOUT = 1
hashes = []
# Generating considerable amount of values of size 1KB.
# Generating considerable amount of values of size 1KB.
VALUE_SIZE = 1024
NUM_VALUES = self._num_values if self._num_values else 50
values = [Value(random_str_val(size=VALUE_SIZE).encode()) for _ in range(NUM_VALUES)]
values = [Value(''.join(random.choice(string.hexdigits) for _ in range(VALUE_SIZE)).encode()) for _ in range(NUM_VALUES)]
bootstrap.resize(N_PRODUCERS+2)
consumer = bootstrap.get(N_PRODUCERS+1)
@@ -798,21 +555,21 @@ class PersistenceTest(DhtFeatureTest):
nodes = set([])
self._gottaGetThemAllPokeNodes(consumer, hashes, nodes=nodes)
DhtNetwork.Log.log("Values are found on:")
DhtNetwork.log("Values are found on:")
for n in nodes:
DhtNetwork.Log.log(n)
DhtNetwork.log(n)
DhtNetwork.Log.log("Creating 8 nodes around all of these hashes...")
DhtNetwork.log("Creating 8 nodes around all of these hashes...")
for _hash in hashes:
self._trigger_dp(trigger_nodes, _hash, count=8)
DhtNetwork.Log.log('Waiting', DP_TIMEOUT+1, 'minutes for normal storage maintenance.')
DhtNetwork.log('Waiting', DP_TIMEOUT+1, 'minutes for normal storage maintenance.')
time.sleep((DP_TIMEOUT+1)*60)
DhtNetwork.Log.log('Deleting old nodes from previous search.')
DhtNetwork.log('Deleting old nodes from previous search.')
for proc in self._workbench.procs:
DhtNetwork.Log.log('[REMOVE]: sending delete request to', proc)
proc.sendClusterRequest(
DhtNetwork.log('[REMOVE]: sending delete request to', proc)
proc.sendNodesRequest(
DhtNetworkSubProcess.REMOVE_NODE_REQ,
nodes)
@@ -853,10 +610,9 @@ class PerformanceTest(DhtFeatureTest):
else:
raise NameError("This test is not defined '" + self._test + "'")
except Exception as e:
traceback.print_tb(e.__traceback__)
print(type(e).__name__+':', e, file=sys.stderr)
print(e)
finally:
self._bootstrap.resize(1)
self.bootstrap.resize(1)
###########
@@ -868,7 +624,7 @@ class PerformanceTest(DhtFeatureTest):
"""
Tests for performance of the DHT doing multiple get() operation.
"""
bootstrap = self._bootstrap
bootstrap = self.bootstrap
plt.ion()
@@ -893,7 +649,7 @@ class PerformanceTest(DhtFeatureTest):
def getcb(v):
nonlocal bootstrap
DhtNetwork.Log.log("found", v)
DhtNetwork.log("found", v)
return True
def donecb(ok, nodes, start):
@@ -901,7 +657,7 @@ class PerformanceTest(DhtFeatureTest):
t = time.time()-start
with lock:
if not ok:
DhtNetwork.Log.log("failed !")
DhtNetwork.log("failed !")
times.append(t)
done -= 1
lock.notify()
@@ -933,7 +689,7 @@ class PerformanceTest(DhtFeatureTest):
for n in range(10):
self._workbench.replace_cluster()
plt.pause(2)
DhtNetwork.Log.log("Getting 50 random hashes succesively.")
DhtNetwork.log("Getting 50 random hashes succesively.")
for i in range(50):
with lock:
for _ in range(1):
@@ -957,7 +713,8 @@ class PerformanceTest(DhtFeatureTest):
deleting around the target hash.
"""
bootstrap = self._bootstrap
bootstrap = self.bootstrap
bootstrap.resize(3)
consumer = bootstrap.get(1)
@@ -968,28 +725,28 @@ class PerformanceTest(DhtFeatureTest):
for _ in range(max(1, int(self._workbench.node_num/32))):
self._dhtGet(consumer, myhash)
DhtNetwork.Log.log("Waiting 15 seconds...")
DhtNetwork.log("Waiting 15 seconds...")
time.sleep(15)
self._dhtPut(producer, myhash, *local_values)
#checking if values were transfered
self._dhtGet(consumer, myhash)
DhtNetwork.Log.log('Values are found on :')
DhtNetwork.log('Values are found on :')
for node in DhtFeatureTest.foreignNodes:
DhtNetwork.Log.log(node)
DhtNetwork.log(node)
if not DhtFeatureTest.successfullTransfer(local_values, DhtFeatureTest.foreignValues):
if DhtFeatureTest.foreignValues:
DhtNetwork.Log.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
DhtNetwork.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
len(local_values), ' values successfully put.')
else:
DhtNetwork.Log.log('[GET]: 0 values successfully put')
DhtNetwork.log('[GET]: 0 values successfully put')
DhtNetwork.Log.log('Removing all nodes hosting target values...')
DhtNetwork.log('Removing all nodes hosting target values...')
for proc in self._workbench.procs:
DhtNetwork.Log.log('[REMOVE]: sending shutdown request to', proc)
proc.sendClusterRequest(
DhtNetwork.log('[REMOVE]: sending shutdown request to', proc)
proc.sendNodesRequest(
DhtNetworkSubProcess.SHUTDOWN_NODE_REQ,
DhtFeatureTest.foreignNodes
)
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
-270
View File
@@ -1,270 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <http://www.gnu.org/licenses/>.
import os, sys, time, cmd
import signal
import argparse
import logging
import logging.handlers
import opendht as dht
logger = logging.getLogger('dhtcluster')
class NodeCluster(object):
nodes = []
node_uid = 0
@staticmethod
def run_node(ip4, ip6, p, bootstrap=None, is_bootstrap=False, logfile=None):
logger.info("Running node on port %s with bootstrap %s", p, bootstrap)
n = dht.DhtRunner()
n.run(ipv4=ip4 if ip4 else "", ipv6=ip6 if ip6 else "", port=p, is_bootstrap=is_bootstrap)
if logfile:
n.enableFileLogging(logfile)
if bootstrap:
n.bootstrap(bootstrap[0], bootstrap[1])
time.sleep(.01)
return ((ip4, ip6, p), n, id)
@staticmethod
def find_ip(iface):
if not iface or iface == 'any':
return ('0.0.0.0','::0')
if_ip4 = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr']
if_ip6 = netifaces.ifaddresses(iface)[netifaces.AF_INET6][0]['addr']
return (if_ip4, if_ip6)
def __init__(self, iface=None, ip4=None, ip6=None, port=4000, bootstrap=None, first_bootstrap=False, logfile=None):
NodeCluster.iface = iface
self.port = port
ips = NodeCluster.find_ip(iface)
self.logfile = logfile
self.ip4 = ip4 if ip4 else ips[0]
self.ip6 = ip6 if ip6 else ips[1]
self.bootstrap = bootstrap
if bootstrap:
self.bootstrap = (bootstrap.hostname, str(bootstrap.port) if bootstrap.port else "4222")
else:
logger.info("Using fallback bootstrap %s %s", self.ip4, self.port)
self.bootstrap = ((self.ip4, str(self.port)))
if first_bootstrap:
logger.info("Starting bootstrap node")
self.nodes.append(NodeCluster.run_node(self.ip4, self.ip6, self.port, self.bootstrap, is_bootstrap=True))
self.bootstrap = ((self.ip4, str(self.port)))
self.port += 1
#print(self.ip4, self.ip6, self.port)
def front(self):
return self.nodes[0][1] if self.nodes else None
def get(self, i):
if not self.nodes or i < 0 or i >= len(self.nodes):
return None
return self.nodes[i][1]
def getNodeInfoById(self, id=None):
if id:
for n in self.nodes:
if n[1].getNodeId() == id:
return n
return None
def launch_node(self):
node_logfile = (self.logfile + str(self.node_uid) + '.log') if self.logfile else None
n = NodeCluster.run_node(self.ip4, self.ip6, self.port, self.bootstrap, logfile=node_logfile)
self.nodes.append(n)
self.port += 1
self.node_uid += 1
return n
def end_node(self):
if not self.nodes:
return
else:
n = self.nodes.pop()
n[1].join()
return True
def resize(self, n):
n = min(n, 500)
l = len(self.nodes)
if n == l:
return
if n > l:
logger.info("Launching %d nodes bound on IPv4 %s IPv6 %s", n-l, self.ip4, self.ip6)
for i in range(l, n):
self.launch_node()
else:
logger.info("Ending %d nodes", l-n)
for i in range(n, l):
self.end_node()
def close(self):
self.resize(0)
def getMessageStats(self):
stats = np.array([0,0,0,0,0])
for n in self.nodes:
stats += np.array(n[1].getNodeMessageStats())
stats_list = [len(self.nodes)]
stats_list.extend(stats.tolist())
return stats_list
class ClusterShell(cmd.Cmd):
intro = 'Welcome to the OpenDHT node cluster control. Type help or ? to list commands.\n'
prompt = '>> '
net = None
node = None
log = False
def __init__(self, network):
super(ClusterShell, self).__init__()
self.net = network
def setNode(self, node=None, num=0):
if node == self.node:
return
if self.node:
self.node.disableLogging()
self.node = node
if self.node:
self.prompt = '('+str(num)+') >> '
if self.log:
self.node.enableLogging()
else:
self.prompt = '>> '
def do_exit(self, arg):
self.close()
return True
def do_node(self, arg):
if not arg:
self.setNode()
else:
nodenum = int(arg)
node = self.net.get(nodenum-1)
if not node:
print("Invalid node number:", nodenum, " (accepted: 1-", len(self.net.nodes), ")")
else:
self.setNode(node, nodenum)
def do_resize(self, arg):
if not arg:
return
try:
nodenum = int(arg)
self.net.resize(nodenum)
except Exception as e:
print("Can't resize:", e)
def do_ll(self, arg):
if self.node:
print('Node', self.node.getNodeId().decode())
else:
print(len(self.net.nodes), 'nodes running.')
def do_ls(self, arg):
if self.node:
print(self.node.getSearchesLog(0))
else:
print('No node selected.')
def do_log(self, arg):
if self.node:
self.log = not self.log
if self.log:
self.node.enableLogging()
else:
self.node.disableLogging()
def do_EOF(self, line):
self.close()
return True
def close(self):
if self.net:
self.net.close()
self.net = None
if __name__ == '__main__':
import argparse
from urllib.parse import urlparse
net = None
run = True
def clean_quit():
global net, run
if run:
run = False
if net:
net.resize(0)
net = None
def quit_signal(signum, frame):
clean_quit()
try:
parser = argparse.ArgumentParser(description='Create a dht network of -n nodes')
parser.add_argument('-n', '--node-num', help='number of dht nodes to run', type=int, default=32)
parser.add_argument('-I', '--iface', help='local interface to bind', default='any')
parser.add_argument('-p', '--port', help='start of port range (port, port+node_num)', type=int, default=4000)
parser.add_argument('-b', '--bootstrap', help='bootstrap address')
group = parser.add_mutually_exclusive_group()
group.add_argument('-d', '--daemonize', help='daemonize process', action='store_true')
group.add_argument('-s', '--service', help='service mode (not forking)', action='store_true')
parser.add_argument('-l', '--log', help='log file prefix')
args = parser.parse_args()
if args.bootstrap:
args.bootstrap = urlparse('dht://'+args.bootstrap)
# setup logging
if args.daemonize or args.service:
syslog = logging.handlers.SysLogHandler(address = '/dev/log')
syslog.setLevel(logging.DEBUG)
logger.setLevel(logging.DEBUG)
logger.addHandler(syslog)
else:
logging.basicConfig(stream=sys.stdout,level=logging.DEBUG)
# start cluster
net = NodeCluster(iface=args.iface, port=args.port, bootstrap=args.bootstrap, logfile=args.log)
# main loop
if args.daemonize:
import daemon
context = daemon.DaemonContext()
context.signal_map = {
signal.SIGHUP: 'terminate',
signal.SIGTERM: quit_signal,
signal.SIGINT: quit_signal,
signal.SIGQUIT: quit_signal
}
with context:
net.resize(args.node_num)
while net:
time.sleep(1)
elif args.service:
signal.signal(signal.SIGTERM, quit_signal)
signal.signal(signal.SIGINT, quit_signal)
signal.signal(signal.SIGQUIT, quit_signal)
net.resize(args.node_num)
while net:
time.sleep(1)
else:
net.resize(args.node_num)
ClusterShell(net).cmdloop()
except Exception:
logger.error("Exception ", exc_info=1)
finally:
clean_quit()
logger.warning("Ending node cluster")
for handler in logger.handlers:
handler.close()
logger.removeHandler(handler)
-78
View File
@@ -1,78 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2016-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <http://www.gnu.org/licenses/>.
from twisted.web import server, resource
from twisted.internet import reactor, endpoints
from urllib.parse import urlparse
import opendht as dht
import base64, json
class DhtServer(resource.Resource):
isLeaf = True
node = dht.DhtRunner()
def __init__(self, port, bootstrap):
self.node.run(port=port)
b_url = urlparse('//'+bootstrap)
self.node.bootstrap(b_url.hostname, str(b_url.port) if b_url.port else '4222')
def render_GET(self, req):
uri = req.uri[1:].decode().rsplit('?', 1)[0]
h = dht.InfoHash(uri.encode()) if len(uri) == 40 else dht.InfoHash.get(uri)
w = dht.Where('WHERE '+''.join(k.decode()+'='+req.args[k][0].decode()+','
for k in req.args.keys()
if k in [b'id', b'user_type', b'value_type', b'owner', b'seq'])[:-1])
print('GET', '"'+uri+'"', h, w)
res = self.node.get(h, where=w)
req.setHeader(b"content-type", b"application/json")
return json.dumps({'{:x}'.format(v.id):{'base64':base64.b64encode(v.data).decode()} for v in res}).encode()
def render_POST(self, req):
uri = req.uri[1:]
data = req.args[b'data'][0] if b'data' in req.args else None
user_type = req.args[b'user_type'][0].decode() if b'user_type' in req.args else ""
try:
vid = int(req.args[b'id'][0].decode()) if b'id' in req.args else 0
except ValueError:
vid = 0
if not data and b'base64' in req.args:
data = base64.b64decode(req.args[b'base64'][0])
h = dht.InfoHash(uri) if len(uri) == 40 else dht.InfoHash.get(uri.decode())
print('POST', h, data)
req.setHeader(b"content-type", b"application/json")
if data:
v = dht.Value(data)
if vid != 0:
v.id = vid
v.user_type = user_type
self.node.put(h, v)
return json.dumps({'success':True}).encode()
else:
req.setResponseCode(400)
return json.dumps({'success':False, 'error':'no data parameter'}).encode()
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description='Launch an OpenDHT node with an HTTP control interface')
parser.add_argument('-p', '--port', help='OpenDHT port to bind', type=int, default=4222)
parser.add_argument('-hp', '--http-port', help='HTTP port to bind', type=int, default=8080)
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default="bootstrap.ring.cx:4222")
args = parser.parse_args()
endpoints.serverFromString(reactor, "tcp:"+str(args.http_port)).listen(server.Site(DhtServer(args.port, args.bootstrap)))
reactor.run()
-83
View File
@@ -1,83 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <http://www.gnu.org/licenses/>.
import time
import argparse
import time
import asyncio
from datetime import datetime
import opendht as dht
parser = argparse.ArgumentParser(description='Create a dht network of -n nodes')
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default='bootstrap.ring.cx')
parser.add_argument('-n', '--num-ops', help='number of concurrent operations on the DHT', type=int, default=8)
parser.add_argument('-p', '--period', help='duration between each test (seconds)', type=int, default=60)
parser.add_argument('-t', '--timeout', help='timeout for a test to complete (seconds)', type=float, default=15)
args = parser.parse_args()
node1 = dht.DhtRunner()
node1.run()
node2 = dht.DhtRunner()
node2.run()
node1.bootstrap(args.bootstrap)
node2.bootstrap(args.bootstrap)
loop = asyncio.get_event_loop()
pending_tests = {}
keys = [dht.InfoHash.getRandom() for _ in range(args.num_ops)]
def listen_cb(key, val, expired):
global pending_tests
kstr = str(key)
if kstr in pending_tests:
if pending_tests[kstr]['v'].id == val.id:
pending_tests.pop(kstr, None)
else:
print("Expected vid", val.id, "got", pending_tests[kstr]['v'].id)
return True
def listen(key):
node1.listen(key, lambda v, e: loop.call_soon_threadsafe(listen_cb, key, v, e))
for key in keys:
listen(key)
next_test = time.time()
while True:
start = time.time()
#print(datetime.fromtimestamp(start).strftime('%Y-%m-%d %H:%M:%S'), 'Test started')
for key in keys:
val = dht.Value(str(dht.InfoHash.getRandom()).encode())
pending_tests[str(key)] = {'v':val, 'c':0}
node2.put(key, val, lambda ok, nodes: ok)
while len(pending_tests):
loop.stop()
loop.run_forever()
time.sleep(1)
if time.time()-start > args.timeout:
print('Test timeout !')
exit(1)
end = time.time()
print(datetime.fromtimestamp(end).strftime('%Y-%m-%d %H:%M:%S'),
'Test completed successfully in', end-start)
next_test += args.period
if next_test > end:
time.sleep(next_test-end)
-79
View File
@@ -1,79 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <https://www.gnu.org/licenses/>.
import opendht as dht
import time
import asyncio
config = dht.DhtConfig()
config.setRateLimit(-1, -1)
ping_node = dht.DhtRunner()
ping_node.run(config=config)
#ping_node.enableLogging()
#ping_node.bootstrap("bootstrap.ring.cx", "4222")
pong_node = dht.DhtRunner()
pong_node.run(config=config)
#pong_node.enableLogging()
pong_node.ping(ping_node.getBound())
loc_ping = dht.InfoHash.get("toto99")
loc_pong = dht.InfoHash.get(str(loc_ping))
net = []
for i in range(1,10):
node = dht.DhtRunner()
node.run(config=config)
node.ping(ping_node.getBound())
net.append(node)
i = 0
MAX = 2048
loop = asyncio.get_event_loop()
def done(h, ok):
pass
#print(h, "over", ok)
def ping(node, h):
global i
i += 1
if i < MAX:
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
else:
loop.stop()
def pong(node, h):
#print(node.getNodeId().decode(), "got ping", h, i)
loop.call_soon_threadsafe(ping, node, h)
return True
t1 = time.time()
ping_node.listen(loc_ping, lambda v, e: pong(pong_node, loc_pong) if not e else True)
pong_node.listen(loc_pong, lambda v, e: pong(ping_node, loc_ping) if not e else True)
ping(pong_node, loc_ping)
loop.run_forever()
t2 = time.time()
print(MAX, "ping-pong done, took", t2 - t1, "s")
print(1000 * (t2 - t1)/MAX, "ms per rt", MAX/(t2 - t1), "rt per s")
+95 -133
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
@@ -18,9 +18,9 @@
import time, sys, os
from pprint import pprint
from math import cos, sin, pi
import urllib3
from urllib import request
import gzip
import queue
import asyncio
sys.path.append('..')
from opendht import *
@@ -35,27 +35,14 @@ from mpl_toolkits.basemap import Basemap
import GeoIP
http = urllib3.PoolManager()
run = True
done = 0
all_nodes = NodeSet()
nodes_ip4s = {}
nodes_ip6s = {}
lats = []
lons = []
cities=[]
xys = []
colors = []
all_lines = []
points = []
not_found = []
plt.ion()
plt.figaspect(2.)
fig, axes = plt.subplots(2, 1)
fig.set_size_inches(8,16,forward=True)
fig.set_size_inches(12,16,forward=True)
fig.tight_layout()
fig.canvas.set_window_title('OpenDHT scanner')
@@ -81,20 +68,11 @@ exitbtn = Button(exitax, 'Exit')
reloadax = plt.axes([0.92, 0.90, 0.07, 0.04])
button = Button(reloadax, 'Reload')
collection = None
infos = [ringx.text(1.2, -0.8, ""),
ringx.text(1.2, -0.9, "")]
def exitcb(arg):
global run
run = False
exitbtn.on_clicked(exitcb)
def check_dl(fname, url):
if os.path.isfile(fname):
return
print('downloading', url)
ghandle = gzip.GzipFile(fileobj=http.request('GET', url, headers={'User-Agent': 'Mozilla/5.0'}, preload_content=False))
ghandle = gzip.GzipFile(fileobj=request.urlopen(url))
with open(fname, 'wb') as out:
for line in ghandle:
out.write(line)
@@ -112,35 +90,35 @@ r = DhtRunner()
r.run(port=4112)
r.bootstrap("bootstrap.ring.cx", "4222")
plt.pause(1)
all_lines = []
q = queue.Queue()
plt.pause(2)
loop = asyncio.get_event_loop()
def step(cur_h, cur_depth):
global done
global done, all_nodes, all_lines
done += 1
a = 2.*pi*cur_h.toFloat()
b = a + 2.*pi/(2**(cur_depth))
arc = []
lines = []
q.put((stepUi, (cur_h, cur_depth, arc, lines)))
print("step", cur_h, cur_depth)
r.get(cur_h, gcb, lambda d, nodes: stepdone(cur_h, cur_depth, d, nodes, arc, lines))
arc = ringx.add_patch(mpatches.Wedge([0.,0,], 1., a*180/pi, b*180/pi, fill=True, color="blue", alpha=0.5))
lines = ringx.plot([0, cos(a)], [0, sin(a)], 'k-', lw=1.2)
all_lines.extend(lines)
r.get(cur_h, gcb, lambda d, nodes: loop.call_soon_threadsafe(nextstep, cur_h, cur_depth, d, nodes, arc, lines))
def stepdone(cur_h, cur_depth, d, nodes, arc, lines):
#print("stepdone", cur_h, cur_depth)
q.put((nextstepUi, (nodes, arc, lines)))
nextstep(cur_h, cur_depth, d, nodes)
def nextstep(cur_h, cur_depth, ok, nodes):
global done
def nextstep(cur_h, cur_depth, ok, nodes, arc=None, lines=[]):
global done, all_nodes
if arc:
arc.remove()
del arc
if nodes:
commonBits = 0
if len(nodes) > 1:
snodes = NodeSet()
snodes.extend(nodes)
commonBits = InfoHash.commonBits(snodes.first(), snodes.last())
depth = min(8, commonBits+6)
for l in lines:
l.set_color('#444444')
snodes = NodeSet()
snodes.extend(nodes)
all_nodes.extend(nodes)
depth = min(8, InfoHash.commonBits(snodes.first(), snodes.last())+6)
if cur_depth < depth:
for b in range(cur_depth, depth):
new_h = InfoHash(cur_h.toString());
@@ -150,62 +128,14 @@ def nextstep(cur_h, cur_depth, ok, nodes):
print("step done with no nodes", ok, cur_h.toString().decode())
done -= 1
def stepUi(cur_h, cur_depth, arc, lines):
global all_lines
a = 2.*pi*cur_h.toFloat()
b = a + 2.*pi/(2**(cur_depth))
arc.append(ringx.add_patch(mpatches.Wedge([0.,0,], 1., a*180/pi, b*180/pi, fill=True, color="blue", alpha=0.5)))
lines.extend(ringx.plot([0, cos(a)], [0, sin(a)], 'k-', lw=1.2))
all_lines.extend(lines)
def nextstepUi(nodes, arc=None, lines=[]):
for a in arc:
if a:
a.remove()
del a
for l in lines:
l.set_color('#aaaaaa')
if nodes:
appendNodes(nodes)
def appendNodes(nodes):
global all_nodes
for n in nodes:
if all_nodes.insert(n):
appendNewNode(n)
def appendNewNode(n):
global nodes_ip4s, nodes_ip6s, colors, xys
addr = b':'.join(n.getNode().getAddr().split(b':')[0:-1]).decode()
colors.append('red' if n.getNode().isExpired() else 'blue')
node_val = n.getId().toFloat()
xys.append((cos(node_val*2*pi), sin(node_val*2*pi)))
georecord = None
if addr[0] == '[':
addr = addr[1:-1]
if addr in nodes_ip6s:
nodes_ip6s[addr][1] += 1
else:
georecord = gi6.record_by_name_v6(addr)
nodes_ip6s[addr] = [n, 1, georecord]
else:
if addr in nodes_ip4s:
nodes_ip4s[addr][1] += 1
else:
georecord = gi.record_by_name(addr)
nodes_ip4s[addr] = [n, 1, georecord]
if georecord:
appendMapPoint(georecord)
def appendMapPoint(res):
global lons, lats, cities
lons.append(res['longitude'])
lats.append(res['latitude'])
cities.append(res['city'] if res['city'] else (str(int(res['latitude']))+'-'+str(int(res['longitude']))))
run = True
def exitcb(arg):
global run
run = False
exitbtn.on_clicked(exitcb)
def restart(arg):
global collection, all_lines, all_nodes, points, done, nodes_ip4s, nodes_ip6s, lats, lons, cities, xys, colors
global collection, all_lines, all_nodes, points, done
if done:
return
for l in all_lines:
@@ -213,13 +143,6 @@ def restart(arg):
del l
all_lines = []
all_nodes = NodeSet()
nodes_ip4s = {}
nodes_ip6s = {}
lats = []
lons = []
cities=[]
xys = []
colors = []
if collection:
collection.remove()
del collection
@@ -235,43 +158,78 @@ def restart(arg):
step(start_h, 0)
plt.draw()
collection = None
points = []
not_found = []
infos = [ringx.text(1.2, -0.8, ""),
ringx.text(1.2, -0.9, "")]
def num_nodes(node_set):
return sorted([x for x in node_set.items()], key=lambda ip: ip[1][1])
def generate_set():
node_ipv4 = {}
node_ipv6 = {}
for n in all_nodes:
addr = b''.join(n.getNode().getAddr().split(b':')[0:-1]).decode()
if addr[0] == '[':
addr = addr[1:-1]
if addr in node_ipv6:
node_ipv6[addr][1] += 1
else:
node_ipv6[addr] = [n, 1, gi6.record_by_name_v6(addr)]
else:
if addr in node_ipv4:
node_ipv4[addr][1] += 1
else:
node_ipv4[addr] = [n, 1, gi.record_by_name(addr)]
return num_nodes(node_ipv4), num_nodes(node_ipv6)
def update_plot():
#print("update_plot", done)
global m, collection, points
global done, m, collection, not_found, points
for p in points:
p.remove()
del p
points = []
lats = []
lons = []
cities=[]
colors=[]
not_found.clear()
ip4s, ip6s = generate_set()
ares = []
for addr, n in ip4s:
ares.append((addr, n[0].getNode(), n[2]))
for addr, n in ip6s:
ares.append((addr, n[0].getNode(), n[2]))
for r in ares:
res = r[2]
n = r[1]
if res:
lats.append(res['latitude'])
lons.append(res['longitude'])
cities.append(res['city'] if res['city'] else (str(int(res['latitude']))+'-'+str(int(res['longitude']))))
colors.append('red' if n.isExpired() else 'blue')
else:
not_found.append(r[0])
x,y = m(lons,lats)
points.extend(m.plot(x,y,'bo'))
for name, xpt, ypt in zip(cities, x, y):
points.append(mpx.text(xpt+50000, ypt+50000, name))
node_val = [n.getId().toFloat() for n in all_nodes]
xys = [(cos(d*2*pi), sin(d*2*pi)) for d in node_val]
if collection:
collection.remove()
del collection
collection = None
collection = ringx.add_collection(RegularPolyCollection(
int(fig.dpi), 6, sizes=(10,), facecolors=colors,
fig.dpi, 6, sizes=(10,), facecolors=colors,
offsets = xys, transOffset = ringx.transData))
infos[0].set_text("{} different IPv4s".format(len(nodes_ip4s)))
infos[1].set_text("{} different IPv6s".format(len(nodes_ip6s)))
def d(arg):
pass
def handle_tasks():
while True:
try:
f = q.get_nowait()
f[0](*f[1])
q.task_done()
except Exception as e:
break;
update_plot()
node_ip4s, node_ip6s = generate_set()
infos[0].set_text("{} different IPv4s".format(len(node_ip4s)))
infos[1].set_text("{} different IPv6s".format(len(node_ip6s)))
if run:
# start first step
@@ -279,9 +237,15 @@ if run:
start_h.setBit(159, 1)
step(start_h, 0)
def d(arg):
pass
while run:
while run and done > 0:
handle_tasks()
loop.stop()
loop.run_forever()
update_plot()
plt.draw()
plt.pause(.5)
if not run:
@@ -289,14 +253,13 @@ while run:
button.on_clicked(restart)
node_ip4s = num_nodes(nodes_ip4s)
node_ip6s = num_nodes(nodes_ip6s)
node_ip4s, node_ip6s = generate_set()
print(all_nodes.size(), " nodes found")
print(all_nodes)
#print(len(not_found), " nodes not geolocalized")
#for n in not_found:
# print(n)
print(len(not_found), " nodes not geolocalized")
for n in not_found:
print(n)
print('')
print(len(node_ip4s), " different IPv4s :")
for ip in node_ip4s:
@@ -306,7 +269,6 @@ while run:
for ip in node_ip6s:
print(ip[0], ":", str(ip[1][1]), "nodes", ("(" + ip[1][2]['city'] + ")") if ip[1][2] and ip[1][2]['city'] else "")
handle_tasks()
while run and done == 0:
plt.pause(.5)
button.on_clicked(d)
-105
View File
@@ -1,105 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg3492"
version="1.1"
inkscape:version="0.91 r13725"
xml:space="preserve"
width="256"
height="256"
viewBox="0 0 256 255.99999"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><title
id="title3357">OpenDHT</title><metadata
id="metadata3498"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title>OpenDHT</dc:title><dc:rights><cc:Agent><dc:title></dc:title></cc:Agent></dc:rights><dc:creator><cc:Agent><dc:title>Savoir-faire Linux Inc.</dc:title></cc:Agent></dc:creator><dc:relation>https://opendht.net</dc:relation></cc:Work></rdf:RDF></metadata><defs
id="defs3496"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath3534"><path
d="m 0,0 1152,0 0,648 L 0,648 0,0 Z"
id="path3536"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1855"
inkscape:window-height="1056"
id="namedview3494"
showgrid="false"
units="px"
fit-margin-top="5"
fit-margin-right="5"
fit-margin-bottom="5"
fit-margin-left="5"
inkscape:zoom="1.9555556"
inkscape:cx="63.161953"
inkscape:cy="141.16919"
inkscape:window-x="1985"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="g3532" /><g
id="g3500"
inkscape:groupmode="layer"
inkscape:label="SFL-logo-DHT"
transform="matrix(1.25,0,0,-1.25,-589.00821,604.10631)"><g
id="g3530"><g
id="g3532"
clip-path="url(#clipPath3534)"><g
id="g3359"
transform="matrix(0.9931555,0,0,0.99058777,1.5489503,0.9813209)"><g
transform="translate(485.3798,383.7826)"
id="g3538"><path
inkscape:connector-curvature="0"
id="path3540"
style="fill:#47b3d1;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0,50.03 40.554,90.586 90.586,90.586 50.028,0 90.587,-40.556 90.587,-90.586 0,-50.03 -40.559,-90.588 -90.587,-90.588 C 40.554,-90.588 0,-50.03 0,0" /></g><g
transform="translate(576.0338,313.2273)"
id="g3542"><path
inkscape:connector-curvature="0"
id="path3544"
style="fill:#0091ba;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0,54.307 -24.009,102.977 -61.954,136.075 -17.613,-16.526 -28.632,-39.996 -28.632,-66.056 0,-49.629 39.916,-89.912 89.393,-90.555 0.396,-0.009 0.792,-0.033 1.193,-0.033 L 0,-0.082 0,0 Z" /></g><g
transform="translate(575.9661,292.6626)"
id="g3546"><path
inkscape:connector-curvature="0"
id="path3548"
style="fill:#007aa3;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -1.439,49.482 -41.105,89.355 -90.504,91.12 0,-0.178 -0.015,-0.355 -0.015,-0.536 C -90.519,40.578 -49.998,0.039 0,0" /></g><g
transform="translate(532.4411,337.497)"
id="g3550"><path
inkscape:connector-curvature="0"
id="path3552"
style="fill:#006382;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -10.555,0 -20.236,-3.754 -27.777,-10 16.565,-21.182 42.472,-34.815 71.442,-34.834 0.01,0.415 -0.072,0.821 -0.072,1.241 C 43.593,-19.516 24.077,0 0,0" /></g><g
transform="translate(576.0338,313.2273)"
id="g3554"><path
inkscape:connector-curvature="0"
id="path3556"
style="fill:#0091ba;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C 0,54.307 24.014,102.977 61.954,136.075 79.567,119.549 90.586,96.079 90.586,70.019 90.586,20.39 50.675,-19.893 1.198,-20.536 0.797,-20.545 0.406,-20.569 0.005,-20.569 l 0,20.487 C 0.005,-0.053 0,-0.029 0,0" /></g><g
transform="translate(576.1063,292.6626)"
id="g3558"><path
inkscape:connector-curvature="0"
id="path3560"
style="fill:#007aa3;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 1.44,49.482 41.105,89.355 90.504,91.12 0,-0.178 0.01,-0.355 0.01,-0.536 C 90.514,40.578 49.998,0.039 0,0" /></g><g
transform="translate(619.6266,337.497)"
id="g3562"><path
inkscape:connector-curvature="0"
id="path3564"
style="fill:#006382;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 10.56,0 20.241,-3.754 27.782,-10 -16.57,-21.182 -42.405,-34.815 -71.375,-34.834 -0.009,0.415 0,0.821 0,1.241 C -43.593,-19.516 -24.072,0 0,0" /></g></g></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

-2
View File
@@ -1,2 +0,0 @@
*.lock
target
-11
View File
@@ -1,11 +0,0 @@
[package]
name = "opendht"
version = "0.1.0"
authors = ["Sébastien Blin <sebastien.blin@savoirfairelinux.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc="0.2.0"
os_socketaddr="0.1.0"
-21
View File
@@ -1,21 +0,0 @@
# Rust bindings for opendht
## Build
Install rust on your system (https://rustup.rs/ is the recommanded way). Once done:
```
cargo build
```
## Run tests
```
cargo test
```
## Run dht node
```
cargo run --example dhtnode
```
-73
View File
@@ -1,73 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
extern crate opendht;
use std::{ thread, time };
use opendht::{ InfoHash, DhtRunner, DhtRunnerConfig, Value };
// use opendht::crypto::*;
fn main() {
println!("{}", InfoHash::random());
println!("{}", InfoHash::new());
println!("{}", InfoHash::new().is_zero());
println!("{}", InfoHash::get("alice"));
println!("{}", InfoHash::get("alice").is_zero());
let mut dht = DhtRunner::new();
let /*mut*/ config = DhtRunnerConfig::new();
//// If you want to inject a certificate, uncomment the following lines and previous mut.
//// Note: you can generate a certificate with
//// openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout example.key -out example.crt -subj /CN=example.com
//let cert = DhtCertificate::import("example.crt").ok().expect("Invalid cert file");
//let pk = PrivateKey::import("example.key", "");
//config.set_identity(cert, pk);
dht.run_config(1412, config);
dht.bootstrap("bootstrap.jami.net", 4222);
println!("Current node id: {}", dht.node_id());
let /* mut */ data = 42;
let mut get_cb = |v: Box<Value>| {
//data += 1;
println!("GET: VALUE CB - data: {} - v: {}", data, v);
true
};
let mut done_cb = |ok: bool| {
println!("GET: DONE CB - data: {} - ok: {}", data, ok);
};
dht.get(&InfoHash::get("alice"), &mut get_cb, &mut done_cb);
let mut put_done_cb = |ok: bool| {
println!("PUT: DONE CB - data: {} - ok: {}", data, ok);
};
dht.put(&InfoHash::get("bob"), Value::new("hi!"), &mut put_done_cb, false);
println!("Start listening /foo");
let mut value_cb = |v, expired| {
println!("LISTEN: DONE CB - data: {} - v: {} - expired: {}", data, v, expired);
true
};
let token = dht.listen(&InfoHash::get("foo"), &mut value_cb);
let one_min = time::Duration::from_secs(10);
thread::sleep(one_min);
dht.cancel_listen(&InfoHash::get("foo"), token);
println!("Public ips: {:#?}", dht.public_addresses());
}
-37
View File
@@ -1,37 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use crate::ffi::*;
pub use crate::ffi::Blob;
impl Blob {
pub fn data(&self) -> DataView {
unsafe {
dht_blob_get_data(self)
}
}
}
impl Drop for Blob {
fn drop(&mut self) {
unsafe {
dht_blob_delete(&mut *self)
}
}
}
-194
View File
@@ -1,194 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(dead_code)]
pub use crate::ffi::*;
use std::ffi::CString;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::ptr;
impl PublicKey {
pub fn new(data: &str) -> Box<PublicKey> {
unsafe {
Box::from_raw(dht_publickey_import(data.as_ptr(), data.len()))
}
}
pub fn unpack(&mut self, data: Vec<u8>) -> i32 {
unsafe {
dht_publickey_unpack(&mut *self, data.as_ptr(), data.len())
}
}
pub fn pack(&mut self, data: &str) -> i32 {
let data = CString::new(data).unwrap();
unsafe {
dht_publickey_pack(&mut *self,
data.as_ptr(),
data.as_bytes().len())
}
}
pub fn id(&self) -> InfoHash {
unsafe {
dht_publickey_get_id(self)
}
}
pub fn long_id(&self) -> PkId {
unsafe {
dht_publickey_get_long_id(self)
}
}
pub fn check_signature(&self, data: &str, signature: &str) -> bool {
let data = CString::new(data).unwrap();
let signature = CString::new(signature).unwrap();
unsafe {
dht_publickey_check_signature(self,
data.as_ptr(), data.as_bytes().len(),
signature.as_ptr(), signature.as_bytes().len())
}
}
pub fn encrypt(&self, data: &str) -> Box<Blob> {
let data = CString::new(data).unwrap();
unsafe {
Box::from_raw(dht_publickey_encrypt(self,
data.as_ptr(), data.as_bytes().len()))
}
}
}
impl Drop for PublicKey {
fn drop(&mut self) {
unsafe {
dht_publickey_delete(&mut *self)
}
}
}
impl PrivateKey {
pub fn new(key_length_bits: u32) -> Box<PrivateKey> {
unsafe {
Box::from_raw(dht_privatekey_generate(key_length_bits))
}
}
pub fn import(file: &str, password: &str) -> io::Result<Box<PrivateKey>> {
let mut f = File::open(file)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
Ok(PrivateKey::from_bytes(&buffer, password))
}
pub fn from_bytes(buffer: &Vec<u8>, password: &str) -> Box<PrivateKey> {
unsafe {
Box::from_raw(dht_privatekey_import((&*buffer).as_ptr(), buffer.len(),
password.as_ptr() as *const i8))
}
}
pub fn public_key(&self) -> Box<PublicKey> {
unsafe {
Box::from_raw(dht_privatekey_get_publickey(self))
}
}
}
impl Drop for PrivateKey {
fn drop(&mut self) {
unsafe {
dht_privatekey_delete(&mut *self)
}
}
}
impl DhtCertificate {
pub fn import(file: &str) -> io::Result<Box<DhtCertificate>> {
let mut f = File::open(file)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
Ok(DhtCertificate::from_bytes(&buffer))
}
pub fn from_bytes(buffer: &Vec<u8>) -> Box<DhtCertificate> {
unsafe {
Box::from_raw(dht_certificate_import((&*buffer).as_ptr(), buffer.len()))
}
}
pub fn from_slice(buffer: &str) -> Box<DhtCertificate> {
unsafe {
Box::from_raw(dht_certificate_import((&*buffer).as_ptr(), buffer.len()))
}
}
pub fn id(&self) -> InfoHash {
unsafe {
dht_certificate_get_id(&*self)
}
}
pub fn long_id(&self) -> PkId {
unsafe {
dht_certificate_get_long_id(&*self)
}
}
pub fn publickey(&self) -> Box<PublicKey> {
unsafe {
Box::from_raw(dht_certificate_get_publickey(&*self))
}
}
}
impl Drop for DhtCertificate {
fn drop(&mut self) {
unsafe {
dht_certificate_delete(&mut *self)
}
}
}
impl DhtIdentity {
pub fn new(common_name: &str) -> DhtIdentity {
unsafe {
DhtIdentity::generate(common_name, Box::from_raw(ptr::null_mut()))
}
}
pub fn generate(common_name: &str, ca: Box<DhtIdentity>) -> DhtIdentity {
let common_name = CString::new(common_name).unwrap();
unsafe {
dht_identity_generate(common_name.as_ptr(), &*ca)
}
}
}
impl Drop for DhtIdentity {
fn drop(&mut self) {
unsafe {
dht_identity_delete(&mut *self)
}
}
}
-315
View File
@@ -1,315 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(dead_code)]
use libc::c_void;
use std::ffi::CString;
use std::ptr;
pub use crate::ffi::*;
use std::net::SocketAddr;
use os_socketaddr::OsSocketAddr;
impl DhtRunnerConfig {
pub fn new() -> Box<DhtRunnerConfig> {
let mut config: Box<DhtRunnerConfig> = Box::new(DhtRunnerConfig {
dht_config: DhtSecureConfig {
node_config: DhtNodeConfig {
node_id: InfoHash::new(),
network: 0,
is_bootstrap: false,
maintain_storage: false,
persist_path: ptr::null(),
},
id: DhtIdentity {
privatekey: ptr::null_mut(),
certificate: ptr::null_mut(),
},
},
threaded: false,
proxy_server: ptr::null(),
push_node_id: ptr::null(),
push_token: ptr::null(),
peer_discovery: false,
peer_publish: false,
server_ca: ptr::null_mut(),
client_identity: DhtIdentity {
privatekey: ptr::null_mut(),
certificate: ptr::null_mut(),
},
});
unsafe {
dht_runner_config_default(&mut *config);
}
config
}
pub fn set_proxy_server(&mut self, proxy_server: &str) {
self.proxy_server = CString::new(proxy_server).unwrap().as_ptr();
}
pub fn set_push_node_id(&mut self, push_node_id: &str) {
self.push_node_id = CString::new(push_node_id).unwrap().as_ptr();
}
pub fn set_push_token(&mut self, push_token: &str) {
self.push_token = CString::new(push_token).unwrap().as_ptr();
}
pub fn set_identity(&mut self, certificate: Box<DhtCertificate>, privatekey: Box<PrivateKey>) {
self.dht_config.id.privatekey = Box::into_raw(privatekey);
self.dht_config.id.certificate = Box::into_raw(certificate);
}
}
impl DhtNodeConfig
{
pub fn set_persist_path(&mut self, persist_path: &str) {
self.persist_path = CString::new(persist_path).unwrap().as_ptr();
}
}
struct GetHandler<'a>
{
get_cb: &'a mut(dyn FnMut(Box<Value>) -> bool),
done_cb: &'a mut(dyn FnMut(bool))
}
impl<'a> GetHandler<'a>
{
fn get_cb(&mut self, v: Box<Value>) -> bool{
(self.get_cb)(v)
}
fn done_cb(&mut self, ok: bool) {
(self.done_cb)(ok)
}
}
extern fn get_handler_cb(v: *mut Value, ptr: *mut c_void) -> bool {
if ptr.is_null() {
return true;
}
unsafe {
let handler = ptr as *mut GetHandler;
(*handler).get_cb((*v).boxed())
}
}
extern fn done_handler_cb(ok: bool, ptr: *mut c_void) {
unsafe {
let handler = Box::from_raw(ptr as *mut GetHandler);
(*handler.done_cb)(ok)
}
}
struct PutHandler<'a>
{
done_cb: &'a mut(dyn FnMut(bool))
}
impl<'a> PutHandler<'a>
{
fn done_cb(&mut self, ok: bool) {
(self.done_cb)(ok)
}
}
extern fn put_handler_done(ok: bool, ptr: *mut c_void) {
unsafe {
let handler = Box::from_raw(ptr as *mut PutHandler);
(*handler.done_cb)(ok)
}
}
struct ListenHandler<'a>
{
cb: &'a mut(dyn FnMut(Box<Value>, bool) -> bool)
}
impl<'a> ListenHandler<'a>
{
fn cb(&mut self, v: Box<Value>, expired: bool) -> bool {
(self.cb)(v, expired)
}
}
extern fn listen_handler(v: *mut Value, expired: bool, ptr: *mut c_void) -> bool {
unsafe {
let handler = ptr as *mut ListenHandler;
(*handler).cb((*v).boxed(), expired)
}
}
extern fn listen_handler_done(ptr: *mut c_void) {
unsafe {
Box::from_raw(ptr as *mut ListenHandler);
}
}
impl DhtRunner {
pub fn new() -> Box<DhtRunner> {
unsafe {
Box::from_raw(dht_runner_new())
}
}
pub fn run(&mut self, port: u16) {
unsafe {
dht_runner_run(&mut *self, port)
}
}
pub fn run_config(&mut self, port: u16, config: Box<DhtRunnerConfig>) {
unsafe {
dht_runner_run_config(&mut *self, port, &*config)
}
}
pub fn bootstrap(&mut self, host: &str, service: u16) {
unsafe {
dht_runner_bootstrap(&mut *self,
CString::new(host).unwrap().as_ptr(),
CString::new(service.to_string()).unwrap().as_ptr())
}
}
pub fn node_id(&self) -> InfoHash {
unsafe {
dht_runner_get_node_id(&*self)
}
}
pub fn id(&self) -> InfoHash {
unsafe {
dht_runner_get_id(&*self)
}
}
pub fn get<'a>(&mut self, h: &InfoHash,
get_cb: &'a mut(dyn FnMut(Box<Value>) -> bool),
done_cb: &'a mut(dyn FnMut(bool))) {
let handler = Box::new(GetHandler {
get_cb,
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_get(&mut *self, h, get_handler_cb, done_handler_cb, handler)
}
}
pub fn put<'a>(&mut self, h: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool)), permanent: bool) {
let handler = Box::new(PutHandler {
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_put(&mut *self, h, &*v, put_handler_done, handler, permanent)
}
}
pub fn put_signed<'a>(&mut self, h: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool)), permanent: bool) {
let handler = Box::new(PutHandler {
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_put_signed(&mut *self, h, &*v, put_handler_done, handler, permanent)
}
}
pub fn put_encrypted<'a>(&mut self, h: &InfoHash, to: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool)), permanent: bool) {
let handler = Box::new(PutHandler {
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_put_encrypted(&mut *self, h, to, &*v, put_handler_done, handler, permanent)
}
}
pub fn cancel_put<'a>(&mut self, h: &InfoHash, vid: u64) {
unsafe {
dht_runner_cancel_put(&mut *self, h, vid)
}
}
pub fn listen<'a>(&mut self, h: &InfoHash,
cb: &'a mut(dyn FnMut(Box<Value>, bool) -> bool)) -> Box<OpToken> {
let handler = Box::new(ListenHandler {
cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
Box::from_raw(dht_runner_listen(&mut *self, h, listen_handler, listen_handler_done, handler))
}
}
pub fn cancel_listen(&mut self, h: &InfoHash, token: Box<OpToken>) {
unsafe {
dht_runner_cancel_listen(&mut *self, h, &*token)
}
}
pub fn shutdown(&mut self,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void)
{
unsafe {
dht_runner_shutdown(&mut *self, done_cb, cb_user_data)
}
}
pub fn public_addresses(&self) -> Vec<SocketAddr> {
let mut result = Vec::new();
unsafe {
let mut addresses = dht_runner_get_public_address(&*self);
while !addresses.is_null() && !(*addresses).is_null() {
let sock = (*(*addresses)).into_addr();
if sock.is_some() {
result.push(sock.unwrap());
}
addresses = (addresses as usize + std::mem::size_of::<*mut OsSocketAddr>()) as *mut *mut OsSocketAddr;
}
}
result
}
}
impl Drop for DhtRunner {
fn drop(&mut self) {
unsafe {
dht_runner_delete(&mut *self)
}
}
}
impl Drop for OpToken {
fn drop(&mut self) {
unsafe {
dht_op_token_delete(&mut *self)
}
}
}
-222
View File
@@ -1,222 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(dead_code)]
use libc::{c_char, c_int, c_uint, c_void, in_port_t, size_t};
use os_socketaddr::OsSocketAddr;
const HASH_LEN: usize = 20;
const PKID_LEN: usize = 32;
#[repr(C)]
pub struct DataView
{
pub data: *const u8,
pub size: size_t
}
#[repr(C)]
pub struct Value
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct Blob
{
_opaque: [u8; 0]
}
#[repr(C)]
#[derive(PartialEq)]
pub struct InfoHash
{
pub d: [u8; HASH_LEN],
}
#[repr(C)]
pub struct PkId
{
pub d: [u8; PKID_LEN],
}
#[repr(C)]
pub struct PublicKey
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct PrivateKey
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct OpToken
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct DhtRunner
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct DhtNodeConfig
{
pub node_id: InfoHash,
pub network: u32,
pub is_bootstrap: bool,
pub maintain_storage: bool,
pub persist_path: *const c_char,
}
#[repr(C)]
pub struct DhtCertificate
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct DhtIdentity
{
pub privatekey: *mut PrivateKey,
pub certificate: *mut DhtCertificate,
}
#[repr(C)]
pub struct DhtSecureConfig
{
pub node_config: DhtNodeConfig,
pub id: DhtIdentity,
}
#[repr(C)]
pub struct DhtRunnerConfig
{
pub dht_config: DhtSecureConfig,
pub threaded: bool,
pub proxy_server: *const c_char,
pub push_node_id: *const c_char,
pub push_token: *const c_char,
pub peer_discovery: bool,
pub peer_publish: bool,
pub server_ca: *mut DhtCertificate,
pub client_identity: DhtIdentity,
}
#[link(name = "opendht-c")]
extern {
// dht::Value
pub fn dht_value_new(data: *const u8, size: size_t) -> *mut Value;
pub fn dht_value_ref(data: *const Value) -> *mut Value;
pub fn dht_value_unref(data: *mut Value);
pub fn dht_value_get_data(data: *const Value) -> DataView;
pub fn dht_value_get_id(data: *const Value) -> u64;
pub fn dht_value_get_owner(data: *const Value) -> *mut PublicKey;
pub fn dht_value_get_recipient(data: *const Value) -> InfoHash;
pub fn dht_value_get_user_type(data: *const Value) -> *const c_char;
// dht::Blob
pub fn dht_blob_get_data(data: *const Blob) -> DataView;
pub fn dht_blob_delete(data: *mut Blob);
// dht::InfoHash
pub fn dht_infohash_print(h: *const InfoHash) -> *const c_char;
pub fn dht_infohash_random(h: *mut InfoHash);
pub fn dht_infohash_get(h: *mut InfoHash, dat: *mut u8, dat_size: size_t);
pub fn dht_infohash_from_hex(h: *mut InfoHash, dat: *const c_char);
pub fn dht_infohash_is_zero(j: *const InfoHash) -> bool;
// dht::PkId
pub fn dht_pkid_print(h: *const PkId) -> *const c_char;
// dht::crypto::PublicKey
pub fn dht_publickey_import(dat: *const u8, dat_size: size_t) -> *mut PublicKey;
pub fn dht_publickey_delete(pk: *mut PublicKey);
pub fn dht_publickey_unpack(pk: *mut PublicKey, dat: *const u8, dat_size: size_t) -> c_int;
pub fn dht_publickey_pack(pk: *mut PublicKey, out: *const c_char, out_size: size_t) -> c_int;
pub fn dht_publickey_get_id(pk: *const PublicKey) -> InfoHash;
pub fn dht_publickey_get_long_id(pk: *const PublicKey) -> PkId;
pub fn dht_publickey_check_signature(pk: *const PublicKey, data: *const c_char, data_size: size_t, signature: *const c_char, signature_size: size_t) -> bool;
pub fn dht_publickey_encrypt(pk: *const PublicKey, data: *const c_char, data_size: size_t) -> *mut Blob;
// dht::crypto::PrivateKey
pub fn dht_privatekey_generate(key_length_bits: c_uint) -> *mut PrivateKey;
pub fn dht_privatekey_import(dat: *const u8, data_size: size_t, password: *const c_char) -> *mut PrivateKey;
pub fn dht_privatekey_get_publickey(pk: *const PrivateKey) -> *mut PublicKey;
pub fn dht_privatekey_delete(pk: *mut PrivateKey);
// dht::crypto::Certificate
pub fn dht_certificate_import(dat: *const u8, dat_size: size_t) -> *mut DhtCertificate;
pub fn dht_certificate_get_id(cert: *const DhtCertificate) -> InfoHash;
pub fn dht_certificate_get_long_id(cert: *const DhtCertificate) -> PkId;
pub fn dht_certificate_get_publickey(cert: *const DhtCertificate) -> *mut PublicKey;
pub fn dht_certificate_delete(cert: *mut DhtCertificate);
pub fn dht_identity_generate(common_name: *const c_char, ca: *const DhtIdentity) -> DhtIdentity;
pub fn dht_identity_delete(ca: *mut DhtIdentity);
// dht::OpToken
pub fn dht_op_token_delete(token: *mut OpToken);
// dht::DhtRunner
pub fn dht_runner_config_default(config: *mut DhtRunnerConfig);
pub fn dht_runner_new() -> *mut DhtRunner;
pub fn dht_runner_get_id(dht: *const DhtRunner) -> InfoHash;
pub fn dht_runner_get_node_id(dht: *const DhtRunner) -> InfoHash;
pub fn dht_runner_delete(dht: *mut DhtRunner);
pub fn dht_runner_run(dht: *mut DhtRunner, port: in_port_t);
pub fn dht_runner_run_config(dht: *mut DhtRunner, port: in_port_t, config: *const DhtRunnerConfig);
pub fn dht_runner_bootstrap(dht: *mut DhtRunner, host: *const c_char, service: *const c_char);
pub fn dht_runner_get(dht: *mut DhtRunner, h: *const InfoHash,
get_cb: extern fn(*mut Value, *mut c_void) -> bool,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
pub fn dht_runner_put(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void,
permanent: bool);
pub fn dht_runner_put_signed(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void,
permanent: bool);
pub fn dht_runner_put_encrypted(dht: *mut DhtRunner, h: *const InfoHash,
to: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void,
permanent: bool);
pub fn dht_runner_put_permanent(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
pub fn dht_runner_cancel_put(dht: *mut DhtRunner, h: *const InfoHash, vid: u64);
pub fn dht_runner_listen(dht: *mut DhtRunner, h: *const InfoHash,
cb: extern fn(*mut Value, bool, *mut c_void) -> bool,
done_cb: extern fn(*mut c_void),
cb_user_data: *mut c_void) -> *mut OpToken;
pub fn dht_runner_cancel_listen(dht: *mut DhtRunner, h: *const InfoHash,
token: *const OpToken);
pub fn dht_runner_shutdown(dht: *mut DhtRunner, done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
pub fn dht_runner_get_public_address(dht: *const DhtRunner) -> *mut *mut OsSocketAddr;
}
-83
View File
@@ -1,83 +0,0 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use crate::ffi::*;
use std::ffi::CStr;
use std::ffi::CString;
use std::fmt;
pub use crate::ffi::InfoHash;
impl InfoHash {
pub fn new() -> InfoHash {
InfoHash {
d: [0; 20]
}
}
pub fn random() -> InfoHash {
let mut h = InfoHash::new();
unsafe {
dht_infohash_random(&mut h);
}
h
}
pub fn get(data: &str) -> InfoHash {
let mut h = InfoHash::new();
unsafe {
let c_str = CString::new(data).unwrap();
dht_infohash_get(&mut h, c_str.as_ptr() as *mut u8, data.len());
}
h
}
pub fn from_bytes(data: &Vec<u8>) -> InfoHash {
let mut h = InfoHash::new();
unsafe {
dht_infohash_get(&mut h, data.as_ptr() as *mut u8, data.len());
}
h
}
pub fn from_hex(data: &str) -> InfoHash {
let mut h = InfoHash::new();
unsafe {
let c_str = CString::new(data).unwrap();
dht_infohash_from_hex(&mut h, c_str.as_ptr());
}
h
}
pub fn is_zero(&self) -> bool {
unsafe {
dht_infohash_is_zero(self)
}
}
}
impl fmt::Display for InfoHash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unsafe {
let self_str = CStr::from_ptr(
dht_infohash_print(self)
).to_str().unwrap_or("");
write!(f, "{}", self_str)
}
}
}
Loaded 100 of 189 files, more files were not shown because too many files have changed in this diff. Show more