Compare commits

..
Author SHA1 Message Date
Adrien Béraud 62dcf640c8 proxy_client: use atomic bool for shared state flags 2017-12-05 16:32:45 +01:00
42 changed files with 835 additions and 1646 deletions

No files matched your search

+4 -58
View File
@@ -5,67 +5,13 @@ services:
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.proxyserverpush"
- OPENDHT_TEST_JOB="opendht.proxyclientpush"
- OPENDHT_TEST_JOB="opendht.all"
before_install:
- |
# non llvm builds
if [[ "$OPENDHT_TEST_JOB" != *"opendht.llvm"* ]]; then
docker pull aberaud/opendht-deps;
if [[ "$OPENDHT_TEST_JOB" != *"opendht.classic"* ]]; then
docker build -t opendht-deps-proxy -f docker/DockerfileDepsProxy .;
fi
fi
- |
# classic build
if [[ "$OPENDHT_TEST_JOB" == *"opendht.llvm"* ]]; then
docker pull aberaud/opendht-deps-llvm
fi
- docker pull aberaud/opendht-deps
- docker pull aberaud/opendht-deps-llvm
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='';
if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyserver"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyserverpush"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.all"* ]]; then
options+='-DOPENDHT_PROXY_SERVER=ON ';
else
options+='-DOPENDHT_PROXY_SERVER=OFF ';
fi
if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyclient"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyclientpush"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.all"* ]]; then
options+='-DOPENDHT_PROXY_CLIENT=ON ';
else
options+='-DOPENDHT_PROXY_CLIENT=OFF ';
fi
if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyserverpush"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyclientpush"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.all"* ]]; 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 $options .. && make -j8 && make install";
fi
- |
# llvm build
if [[ "$OPENDHT_TEST_JOB" == *"opendht.llvm"* ]]; then
docker build -f docker/DockerfileTravisLlvm .
fi
- docker build -f docker/DockerfileTravis .
- docker build -f docker/DockerfileTravisLlvm .
notifications:
email:
+3 -14
View File
@@ -1,7 +1,7 @@
cmake_minimum_required (VERSION 3.1)
project (opendht)
set (opendht_VERSION_MAJOR 1)
set (opendht_VERSION_MINOR 6.0)
set (opendht_VERSION_MINOR 5.0)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -17,10 +17,8 @@ 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 Restbed 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 Restbed and jsoncpp" OFF)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
find_package(Doxygen)
option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
@@ -132,6 +130,7 @@ list (APPEND opendht_SOURCES
src/network_engine.cpp
src/securedht.cpp
src/dhtrunner.cpp
src/indexation/pht.cpp
src/log.cpp
)
@@ -157,14 +156,9 @@ list (APPEND opendht_HEADERS
include/opendht/log.h
include/opendht/log_enable.h
include/opendht.h
include/opendht/indexation/pht.h
)
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()
if (OPENDHT_PROXY_SERVER)
add_definitions(-DOPENDHT_PROXY_SERVER=true)
if (OPENDHT_PROXY_SERVER_IDENTITY)
@@ -178,11 +172,6 @@ if (OPENDHT_PROXY_SERVER)
list (APPEND opendht_SOURCES
src/dht_proxy_server.cpp
)
if (OPENDHT_PUSH_NOTIFICATIONS)
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS=true)
else ()
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS=false)
endif ()
else ()
add_definitions(-DENABLE_PROXY_SERVER=false)
endif ()
+4 -11
View File
@@ -19,14 +19,11 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<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" />
@@ -39,8 +36,6 @@
<ClCompile Include="..\src\value.cpp" />
</ItemGroup>
<ItemGroup>
<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" />
@@ -48,7 +43,6 @@
<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" />
@@ -57,6 +51,7 @@
<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" />
@@ -64,11 +59,9 @@
<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\listener.h" />
<ClInclude Include="..\src\parsed_message.h" />
<ClInclude Include="..\src\request.h" />
<ClInclude Include="..\src\search.h" />
<ClInclude Include="..\src\storage.h" />
</ItemGroup>
@@ -222,9 +215,9 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)contrib\build\include;$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)contrib\build\msgpack-c\include;$(ProjectDir)contrib\build\argon2\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)contrib\build\include;$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)contrib\build\msgpack-c\include;$(ProjectDir)contrib\build\argon2\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
+51 -79
View File
@@ -31,6 +31,9 @@
<ClCompile Include="..\src\node_cache.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\indexation\pht.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\routing_table.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -43,102 +46,80 @@
<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" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\opendht\def.h" />
<ClInclude Include="..\include\opendht\sockaddr.h" />
<ClInclude Include="..\src\net.h" />
<ClInclude Include="..\src\parsed_message.h" />
<ClInclude Include="..\src\base64.h">
<Filter>Source Files</Filter>
<ClInclude Include="..\include\opendht\callbacks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\crypto.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\default_types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\dht.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\dhtrunner.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\infohash.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\listener.h">
<Filter>Source Files</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\request.h">
<Filter>Source Files</Filter>
<ClInclude Include="..\include\opendht\log.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\search.h">
<Filter>Source Files</Filter>
<ClInclude Include="..\include\opendht\log_enable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\storage.h">
<Filter>Source Files</Filter>
<ClInclude Include="..\include\opendht\network_engine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\node.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\node_cache.h">
<Filter>Header Files</Filter>
</ClInclude>
<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 Include="..\include\opendht\indexation\pht.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\rate_limiter.h">
<Filter>Header Files\opendht</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\request.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\rng.h">
<Filter>Header Files\opendht</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\routing_table.h">
<Filter>Header Files\opendht</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\scheduler.h">
<Filter>Header Files\opendht</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\search.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\securedht.h">
<Filter>Header Files\opendht</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\storage.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\utils.h">
<Filter>Header Files\opendht</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\value.h">
<Filter>Header Files\opendht</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\indexation\pht.h">
<Filter>Header Files\opendht\indexation</Filter>
</ClInclude>
<ClInclude Include="unistd.h" />
<ClInclude Include="wingetopt.h" />
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
@@ -147,14 +128,5 @@
<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>
+9 -11
View File
@@ -4,14 +4,14 @@
<a id="user-content-opendht-" class="anchor" href="/savoirfairelinux/opendht/blob/master/README.md#opendht-" aria-hidden="true"></a>OpenDHT
</h1>
A lightweight C++11 Distributed Hash Table implementation.
A lightweight C++11 Distributed Hash Table implementation originally based on https://github.com/jech/dht by Juliusz Chroboczek.
* Light and fast C++11 Kademlia DHT library
* Light and fast C++11 Kademlia DHT library.
* Distributed shared key->value data-store
* Clean and powerful distributed map API with storage of arbitrary binary values of up to 56 KB
* Public key cryptography layer providing optional data signature and encryption (using GnuTLS)
* IPv4 and IPv6 support
* Python binding
* Clean and powerful 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.
## Documentation
See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
@@ -93,7 +93,7 @@ for r in results:
- Nettle 2.4+, a GnuTLS dependency for crypto.
- (optional) restbed used for the REST API. commit fb84213e170bc171fecd825a8e47ed9f881a12cd (https://github.com/AmarOk1412/restbed/tree/async_read_until)
- (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 GCC 4.8+ (GNU/Linux, Android, Windows with MinGW), Clang/LLVM (Linux, macOS).
- Build tested with Microsoft Visual Studio 2015
## Contact
@@ -101,7 +101,7 @@ for r in results:
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
## Licence
Copyright (C) 2014-2018 Savoir-faire Linux Inc.
Copyright (C) 2014-2017 Savoir-faire Linux Inc.
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.
@@ -109,9 +109,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
See COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html for the full GPLv3 licence.
## 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.
This project is independent from another project called OpenDHT (Sean Rhea. Ph.D. Thesis, 2005), now extinct.
## Donations
We gratefully accept Bitcoin donations to support OpenDHT development at: `bitcoin:3EykSd1An888efq4Bq3KaV3hJ3JQ4FPnwm`.
+2 -18
View File
@@ -1,6 +1,6 @@
dnl define macros
m4_define([opendht_major_version], 1)
m4_define([opendht_minor_version], 6)
m4_define([opendht_minor_version], 5)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
@@ -32,13 +32,6 @@ AS_IF([test "x$enable_logs" != "xno"], [
AC_DEFINE([OPENDHT_LOG], [false], [Define if DHT logs are enabled])
])
dnl Check for indexation
AC_ARG_ENABLE([indexation], [AS_HELP_STRING([--enable-indexation], [Enable DHT indexation])])
AM_CONDITIONAL(ENABLE_INDEXATION, test x$enable_indexation == xyes)
AS_IF([test "x$enable_indexation" = "xyes"], [
AC_DEFINE([OPENDHT_INDEXATION], [1], [Define if DHT indexation 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"], [
@@ -137,8 +130,6 @@ AM_COND_IF([ENABLE_TOOLS], [
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)
@@ -147,18 +138,11 @@ AM_CONDITIONAL(ENABLE_PROXY_CLIENT, test x$proxy_client == xyes)
AM_COND_IF([ENABLE_PROXY_SERVER], [
AC_CHECK_LIB(restbed, exit,, AC_MSG_ERROR([Missing restbed files]))
PKG_CHECK_MODULES([Jsoncpp], [jsoncpp >= 1.7.2])
PKG_CHECK_MODULES([Jsoncpp], [jsoncpp >= 1.7.4])
CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=true -ljsoncpp -lrestbed"
], [
CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=false"
])
AM_COND_IF([ENABLE_PUSH_NOTIFICATIONS], [
CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=true"
], [
CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=false"
])
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)
-16
View File
@@ -1,16 +0,0 @@
FROM aberaud/opendht-deps
# install jsoncpp
RUN apt-get install libjsoncpp-dev -y
# install restbed dependencies
RUN sed -i -e 's/archive.ubuntu.com\|security.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list # LTS... avoid 404 for libasio-dev
RUN apt-get update -y
RUN apt-get install libasio-dev -y
# build restbed from sources
RUN git clone --recursive https://github.com/corvusoft/restbed.git
WORKDIR restbed/build
RUN cmake -DBUILD_TESTS=NO -DBUILD_EXAMPLES=NO -DBUILD_SSL=NO -DBUILD_SHARED=YES -DCMAKE_INSTALL_PREFIX=/usr ..
RUN make -j 8 install
RUN mv /usr/library/librestbed* /usr/lib/
+6
View File
@@ -0,0 +1,6 @@
FROM aberaud/opendht-deps-llvm
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 && make -j8 && make install \
&& cd ../.. && rm -rf opendht
+2 -1
View File
@@ -2,4 +2,5 @@ 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_LTO=On .. && make -j8 && make install
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On .. && make -j8 && make install \
&& cd ../.. && rm -rf opendht
+2 -1
View File
@@ -2,4 +2,5 @@ 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 .. && make -j8 && make install
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On .. && make -j8 && make install \
&& cd ../.. && rm -rf opendht
-3
View File
@@ -1,3 +0,0 @@
FROM opendht-deps-proxy
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
-2
View File
@@ -24,6 +24,4 @@
#endif
#include "opendht/log.h"
#include "opendht/default_types.h"
#ifdef OPENDHT_INDEXATION
#include "opendht/indexation/pht.h"
#endif
+2 -3
View File
@@ -1,8 +1,7 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* 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
@@ -52,7 +51,7 @@ struct OPENDHT_PUBLIC NodeStats {
unsigned table_depth {0};
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
std::string toString() const;
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#if OPENDHT_PROXY_SERVER
/**
* Build a json object from a NodeStats
*/
-1
View File
@@ -387,7 +387,6 @@ struct OPENDHT_PUBLIC Certificate {
/** 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;
/**
+9 -8
View File
@@ -1,8 +1,7 @@
/*
* Copyright (C) 2014-2017 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>
* 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
@@ -68,9 +67,14 @@ public:
* Initialise the Dht with two open sockets (for IPv4 and IP6)
* and an ID for the node.
*/
Dht(const int& s, const int& s6, Config config);
Dht(int s, int s6, Config config);
virtual ~Dht();
#if OPENDHT_PROXY_CLIENT
void startProxy(const std::string&) {};
#endif
/**
* Get the ID of the node.
*/
@@ -231,7 +235,7 @@ public:
*
* @return a token to cancel the listener later.
*/
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter={}, Where w = {});
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter&&={}, Where&& w = {});
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w = {}) {
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
@@ -290,9 +294,6 @@ public:
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0);
void pushNotificationReceived(const std::map<std::string, std::string>&) {}
void resubscribe(unsigned) {}
private:
/* When performing a search, we search for up to SEARCH_NODES closest nodes
+7 -18
View File
@@ -28,6 +28,10 @@ public:
DhtInterface() = default;
virtual ~DhtInterface() = default;
#if OPENDHT_PROXY_CLIENT
virtual void startProxy(const std::string& host) = 0;
#endif
// [[deprecated]]
using Status = NodeStatus;
// [[deprecated]]
@@ -163,7 +167,7 @@ public:
*
* @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&, GetCallback, Value::Filter&&={}, Where&& w = {}) = 0;
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w = {}) = 0;
virtual bool cancelListen(const InfoHash&, size_t token) = 0;
@@ -210,6 +214,7 @@ public:
virtual std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) = 0;
Logger DHT_LOG;
/**
* Enable or disable logging of DHT internal messages
*/
@@ -223,28 +228,12 @@ public:
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
virtual void setLogFilter(const InfoHash& f)
{
virtual void setLogFilter(const InfoHash& f) {
DHT_LOG.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;
/**
* Refresh a listen via a token
* @param token
*/
virtual void resubscribe(unsigned token) = 0;
protected:
bool logFilerEnable_ {};
InfoHash logFiler_ {};
Logger DHT_LOG;
};
} // namespace dht
+29 -64
View File
@@ -1,7 +1,6 @@
/*
* Copyright (C) 2016-2018 Savoir-faire Linux Inc.
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* 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
@@ -30,14 +29,11 @@
#include "dht_interface.h"
#include "scheduler.h"
namespace restbed {
namespace restbed
{
class Request;
}
namespace Json {
class Value;
}
namespace dht {
class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface {
@@ -45,13 +41,16 @@ public:
DhtProxyClient() : scheduler(DHT_LOG) {}
explicit DhtProxyClient(std::function<void()> loopSignal, const std::string& serverHost, const std::string& pushClientId = "");
virtual void setPushNotificationToken(const std::string& token) {
#if OPENDHT_PUSH_NOTIFICATIONS
deviceKey_ = token;
#endif
}
/**
* Initialise the DhtProxyClient with two open sockets (for IPv4 and IP6)
* and an ID for the node.
*/
explicit DhtProxyClient(const std::string& serverHost);
/**
* Start the connection with a server.
* @param serverHost the server address
*/
void startProxy(const std::string& serverHost);
virtual ~DhtProxyClient();
@@ -102,8 +101,6 @@ public:
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
void get(const InfoHash& key, const GetCallback& cb, DoneCallback donecb, const Value::Filter& filterChain);
/**
* Announce a value on all available protocols (IPv4, IPv6).
*
@@ -161,28 +158,22 @@ public:
*
* @return a token to cancel the listener later.
*/
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter={}, Where={});
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter&&={}, Where&&={});
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w = {}) {
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual bool cancelListen(const InfoHash&, size_t token);
/**
* Call linked callback with a push notification
* @param notification to process
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification);
/**
* Refresh a listen via a token
* @param token
*/
void resubscribe(const unsigned token);
time_point periodic(const uint8_t*, size_t, const SockAddr&);
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) {
return periodic(buf, buflen, SockAddr(from, fromlen));
}
/**
* TODO
* NOTE: For now, there is no endpoint in the DhtProxyServer to do the following methods.
* It will come in another version. (with push_notifications support)
*/
virtual bool cancelListen(const InfoHash&, size_t token);
/**
* Similar to Dht::get, but sends a Query to filter data remotely.
@@ -245,22 +236,11 @@ public:
private:
const ValueType NO_VALUE;
/**
* Start the connection with a server.
*/
void startProxy();
/**
* Get informations from the proxy node
* @return the JSON returned by the proxy
*/
void getProxyInfos();
void onProxyInfos(const Json::Value& val);
SockAddr parsePublicAddress(const Json::Value& val);
void opFailed();
Json::Value getProxyInfos() const;
/**
* Initialize statusIpvX_
*/
@@ -274,14 +254,8 @@ private:
*/
void cancelAllOperations();
std::string serverHost_;
std::string pushClientId_;
std::atomic_flag ongoingStatusUpdate_ = ATOMIC_FLAG_INIT;
NodeStatus statusIpv4_ {NodeStatus::Disconnected};
NodeStatus statusIpv6_ {NodeStatus::Disconnected};
NodeStats stats4_ {};
NodeStats stats6_ {};
SockAddr publicAddress_;
InfoHash myid {};
@@ -296,8 +270,6 @@ private:
GetCallback cb;
Value::Filter filterChain;
std::thread thread;
unsigned callbackId;
std::shared_ptr<unsigned> pushNotifToken; // NOTE: unused if not using push notifications
};
std::vector<Listener> listeners_;
size_t listener_token_ {0};
@@ -319,9 +291,7 @@ private:
*/
std::vector<std::function<void()>> callbacks_;
std::mutex lockCallbacks;
std::thread statusThread_;
mutable std::mutex lockCurrentProxyInfos_;
std::unique_ptr<std::mutex> lockCurrentProxyInfos_;
Scheduler scheduler;
/**
@@ -329,25 +299,20 @@ private:
*/
void confirmProxy();
Sp<Scheduler::Job> nextProxyConfirmation {};
/**
* Verify if we are still connected.
*/
void confirmConnectivity();
Sp<Scheduler::Job> nextConnectivityConfirmation {};
/**
* Relaunch LISTEN requests if the client disconnect/reconnect.
*/
void restartListeners();
/**
* If we want to use push notifications by default.
* NOTE: empty by default to avoid to use services like FCM or APN.
* Store the current proxy status
*/
std::string deviceKey_ {};
unsigned callbackId_ {0};
std::mutex lockCallback_;
const std::function<void()> loopSignal_;
#if OPENDHT_PUSH_NOTIFICATIONS
void fillBodyToGetToken(std::shared_ptr<restbed::Request> request, unsigned callbackId);
#endif // OPENDHT_PUSH_NOTIFICATIONS
std::unique_ptr<Json::Value> currentProxyInfos_;
};
}
+5 -72
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
* Copyright (C) 2017 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -29,10 +29,6 @@
#include <mutex>
#include <restbed>
namespace Json {
class Value;
}
namespace dht {
class DhtRunner;
@@ -47,11 +43,10 @@ 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(std::shared_ptr<DhtRunner> dht, in_port_t port = 8000, const std::string& pushServer = "");
DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port = 8000);
virtual ~DhtProxyServer();
DhtProxyServer(const DhtProxyServer& other) = delete;
@@ -75,7 +70,7 @@ private:
void getNodeInfo(const std::shared_ptr<restbed::Session>& session) const;
/**
* Return Values of an infoHash
* Return Values of a InfoHash
* Method: GET "/{InfoHash: .*}"
* Return: Multiple JSON object in parts. Example:
* Value in JSON format\n
@@ -87,7 +82,7 @@ private:
void get(const std::shared_ptr<restbed::Session>& session) const;
/**
* Listen incoming Values of an infoHash.
* Listen incoming Values of a InfoHash.
* Method: LISTEN "/{InfoHash: .*}"
* Return: Multiple JSON object in parts. Example:
* Value in JSON format\n
@@ -134,7 +129,7 @@ private:
#endif // OPENDHT_PROXY_SERVER_IDENTITY
/**
* Return Values of an infoHash filtered by a value id
* Return Values of a InfoHash filtered by a value id
* Method: GET "/{InfoHash: .*}/{ValueId: .*}"
* Return: Multiple JSON object in parts. Example:
* Value in JSON format\n
@@ -150,43 +145,9 @@ private:
* Method: OPTIONS "/{hash: .*}"
* Return: HTTP 200 + Allow: allowed methods
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
* @param session
*/
void handleOptionsMethod(const std::shared_ptr<restbed::Session>& session) const;
#if OPENDHT_PUSH_NOTIFICATIONS
/**
* Subscribe to push notifications for an iOS or Android device.
* Method: SUBSCRIBE "/{InfoHash: .*}"
* Body: {"key": "device_key", (optional)"callback_id":y,
* (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.
* @note: callback_id is used to add the possibility to have multiple listen
* on same hash for same device and must be > 0
* @param session
*/
void subscribe(const std::shared_ptr<restbed::Session>& session) const;
/**
* Unsubscribe to push notifications for an iOS or Android device.
* Method: UNSUBSCRIBE "/{InfoHash: .*}"
* Body: {"key": "device_key", "token": x, (optional)"callback_id":y"
* where x if the token to cancel
* Return: nothing
* @note: callback id is used to add the possibility to have multiple listen
* on same hash for same device
* @param session
*/
void unsubscribe(const std::shared_ptr<restbed::Session>& session) const;
/**
* 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, const Json::Value& json, bool isAndroid) const;
#endif //OPENDHT_PUSH_NOTIFICATIONS
std::thread server_thread {};
std::unique_ptr<restbed::Service> service_;
std::shared_ptr<DhtRunner> dht_;
@@ -202,34 +163,6 @@ private:
mutable std::vector<SessionToHashToken> currentListeners_;
mutable std::mutex lockListener_;
std::atomic_bool stopListeners {false};
#if OPENDHT_PUSH_NOTIFICATIONS
struct PushListener {
std::string pushToken;
InfoHash hash;
unsigned token;
std::future<size_t> internalToken;
std::chrono::steady_clock::time_point deadline;
bool started {false};
unsigned callbackId {0};
std::string clientId {};
bool isAndroid {true};
};
mutable std::mutex lockPushListeners_;
mutable std::vector<PushListener> pushListeners_;
mutable unsigned tokenPushNotif_ {0};
#endif //OPENDHT_PUSH_NOTIFICATIONS
const std::string pushServer_;
/**
* Remove finished listeners
* @param testSession if we remove the listener only if the session is closed
*/
void removeClosedListeners(bool testSession = true);
/**
* Launch or remove push listeners if needed
*/
void handlePushListeners();
};
}
+45 -72
View File
@@ -1,8 +1,7 @@
/*
* Copyright (C) 2014-2017 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>
* 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
@@ -20,6 +19,7 @@
#pragma once
//#include "securedht.h"
#include "infohash.h"
#include "value.h"
#include "callbacks.h"
@@ -36,6 +36,10 @@
#include <queue>
#include <chrono>
#if OPENDHT_PROXY_CLIENT
#include "dht_proxy_client.h"
#endif // OPENDHT_PROXY_CLIENT
namespace dht {
struct Node;
@@ -53,13 +57,6 @@ class OPENDHT_PUBLIC DhtRunner {
public:
typedef std::function<void(NodeStatus, NodeStatus)> StatusCallback;
struct Config {
SecureDhtConfig dht_config;
bool threaded;
std::string proxy_server;
std::string push_node_id;
};
DhtRunner();
virtual ~DhtRunner();
@@ -301,13 +298,25 @@ public:
void registerCertificate(std::shared_ptr<crypto::Certificate> cert);
void setLocalCertificateStore(CertificateStoreQuery&& query_method);
struct Config {
SecureDhtConfig dht_config;
bool threaded;
#if OPENDHT_PROXY_CLIENT
std::string proxy_server;
#endif //OPENDHT_PROXY_CLIENT
};
/**
* @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, const crypto::Identity identity, bool threaded = false, NetId network = 0) {
void run(in_port_t port, const crypto::Identity identity, bool threaded = false, NetId network = 0
#if OPENDHT_PROXY_CLIENT
, const std::string& proxy_server = "127.0.0.1:8000"
#endif //OPENDHT_PROXY_CLIENT
) {
run(port, {
/*.dht_config = */{
/*.node_config = */{
@@ -319,8 +328,9 @@ public:
/*.id = */identity
},
/*.threaded = */threaded,
/*.proxy_server = */"",
/*.push_node_id = */""
#if OPENDHT_PROXY_CLIENT
/*.proxy_server = */proxy_server
#endif //OPENDHT_PROXY_CLIENT
});
}
void run(in_port_t port, Config config);
@@ -351,13 +361,7 @@ public:
*/
time_point loop() {
std::lock_guard<std::mutex> lck(dht_mtx);
time_point wakeup = time_point::min();
try {
wakeup = loop_();
} catch (const dht::SocketException& e) {
startNetwork(bound4, bound6);
}
return wakeup;
return loop_();
}
/**
@@ -372,43 +376,17 @@ public:
*/
void join();
void setProxyServer(const std::string& proxy, const std::string& pushNodeId = "") {
#if OPENDHT_PROXY_CLIENT
if (config_.proxy_server == proxy and config_.push_node_id == pushNodeId)
return;
config_.proxy_server = proxy;
config_.push_node_id = pushNodeId;
enableProxy(use_proxy and not config_.proxy_server.empty());
#endif
void setProxyServer(const std::string& url = "127.0.0.1:8000") {
config_.proxy_server = url;
}
/**
* 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) const;
/**
* Refresh a listen via a token
* @param token
*/
void resubscribe(unsigned token);
/* Proxy server mothods */
#endif // OPENDHT_PROXY_CLIENT
#if OPENDHT_PROXY_SERVER
void forwardAllMessages(bool forward);
#endif // OPENDHT_PROXY_SERVER
static std::vector<SockAddr> getAddrInfo(const std::string& host, const std::string& service);
private:
static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
@@ -420,25 +398,14 @@ private:
*/
void tryBootstrapContinuously();
void startNetwork(const SockAddr sin4, const SockAddr sin6);
void doRun(const SockAddr& sin4, const SockAddr& sin6, SecureDhtConfig config);
time_point loop_();
NodeStatus getStatus() const {
return std::max(status4, status6);
}
/** 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
*/
@@ -447,11 +414,22 @@ private:
* @return the current active DHT
*/
SecureDht* activeDht() const;
#if OPENDHT_PROXY_CLIENT
/**
* true if we are currently using a proxy
*/
std::atomic_bool use_proxy {false};
/**
* The current proxy client
*/
std::unique_ptr<SecureDht> dht_via_proxy_;
Config config_;
#endif // OPENDHT_PROXY_CLIENT
/**
* Store current listeners and translates global tokens for each client.
*/
struct Listener {
size_t globalToken;
size_t tokenClassicDht;
size_t tokenProxyDht;
GetCallback gcb;
@@ -459,7 +437,7 @@ private:
Value::Filter f;
Where w;
};
std::map<size_t, Listener> listeners_ {};
std::vector<std::unique_ptr<Listener>> listeners_ {};
size_t listener_token_ {1};
mutable std::mutex dht_mtx {};
@@ -484,19 +462,14 @@ private:
std::queue<std::function<void(SecureDht&)>> pending_ops {};
std::mutex storage_mtx {};
std::atomic_bool running {false};
std::atomic_bool running_network {false};
std::atomic<bool> running {false};
NodeStatus status4 {NodeStatus::Disconnected},
status6 {NodeStatus::Disconnected};
StatusCallback statusCb {nullptr};
int s4 {-1}, s6 {-1};
SockAddr bound4 {};
SockAddr bound6 {};
/** Push notification token */
std::string pushToken_;
};
}
+1 -1
View File
@@ -378,7 +378,7 @@ struct OPENDHT_PUBLIC NodeExport {
void msgpack_unpack(msgpack::object o);
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const NodeExport& h);
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const InfoHash& h);
};
}
+4 -4
View File
@@ -202,8 +202,8 @@ public:
using RequestCb = std::function<void(const Request&, RequestAnswer&&)>;
using RequestExpiredCb = std::function<void(const Request&, bool)>;
NetworkEngine(Logger& log, Scheduler& scheduler, const int& s = -1, const int& s6 = -1);
NetworkEngine(InfoHash& myid, NetId net, const int& s, const int& s6, Logger& log, Scheduler& scheduler,
NetworkEngine(Logger& log, Scheduler& scheduler);
NetworkEngine(InfoHash& myid, NetId net, int s, int s6, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError) onError,
decltype(NetworkEngine::onNewNode) onNewNode,
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
@@ -505,8 +505,8 @@ private:
/* DHT info */
const InfoHash& myid;
const NetId network {0};
const int& dht_socket;
const int& dht_socket6;
const int dht_socket {-1};
const int dht_socket6 {-1};
const Logger& DHT_LOG;
NodeCache cache {};
+2 -2
View File
@@ -117,7 +117,7 @@ struct Node {
*/
Tid openSocket(SocketCb&& cb);
Sp<Socket> getSocket(Tid id);
Socket* getSocket(Tid id);
/**
* Closes a socket so that no further data will be red on that socket.
@@ -167,7 +167,7 @@ private:
using TransactionDist = std::uniform_int_distribution<decltype(transaction_id)>;
std::map<Tid, Sp<net::Request>> requests_ {};
std::map<Tid, Sp<Socket>> sockets_;
std::map<Tid, Socket> sockets_;
};
}
+12 -38
View File
@@ -1,8 +1,7 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* 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
@@ -100,7 +99,7 @@ public:
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
size_t listen(const InfoHash& id, GetCallback cb, Value::Filter = {}, Where w = {});
size_t listen(const InfoHash& id, GetCallback cb, Value::Filter&& = {}, Where&& w = {});
/**
* Will take ownership of the value, sign it using our private key and put it in the DHT.
@@ -293,44 +292,17 @@ public:
dht_->connectivityChanged();
}
#if OPENDHT_PROXY_CLIENT
void startProxy(const std::string& host) {
dht_->startProxy(host);
}
#endif
#if OPENDHT_PROXY_SERVER
void forwardAllMessages(bool forward) {
forward_all_ = forward;
}
void setPushNotificationToken(const std::string& token = "") {
dht_->setPushNotificationToken(token);
}
/**
* Call linked callback with push_notification
* @param notification to process
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) {
dht_->pushNotificationReceived(notification);
}
/**
* Refresh a listen via a token
* @param token
*/
void resubscribe(const unsigned token) {
dht_->resubscribe(token);
}
void setLoggers(LogMethod error = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG)
{
DHT_LOG.DEBUG = debug;
DHT_LOG.WARN = warn;
DHT_LOG.ERR = error;
dht_->setLoggers(std::forward<LogMethod>(error), std::forward<LogMethod>(warn), std::forward<LogMethod>(debug));
}
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
void setLogFilter(const InfoHash& f) {
DHT_LOG.setFilter(f);
dht_->setLogFilter(f);
}
#endif //OPENDHT_PROXY_SERVER
private:
std::unique_ptr<DhtInterface> dht_;
@@ -352,7 +324,9 @@ private:
std::uniform_int_distribution<Value::Id> rand_id {};
#if OPENDHT_PROXY_SERVER
std::atomic_bool forward_all_ {false};
#endif //OPENDHT_PROXY_SERVER
};
const ValueType CERTIFICATE_TYPE = {
+3 -22
View File
@@ -28,8 +28,6 @@ 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;
@@ -39,7 +37,6 @@ typedef uint16_t in_port_t;
#include <string>
#include <memory>
#include <vector>
#include <stdlib.h>
#include <cstring>
#include <cstddef>
@@ -70,19 +67,6 @@ public:
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.
*/
@@ -139,7 +123,7 @@ public:
}
if (new_length != len) {
len = new_length;
if (len) addr.reset((sockaddr*)::calloc(len, 1));
if (len) addr.reset((sockaddr*)std::calloc(len, 1));
else addr.reset();
}
if (len > sizeof(sa_family_t))
@@ -225,9 +209,6 @@ public:
bool isUnspecified() const;
bool isMappedIPv4() const;
SockAddr getMappedIPv4() const;
/**
* A comparator to classify IP addresses, only considering the
* first 64 bits in IPv6.
@@ -258,13 +239,13 @@ public:
};
private:
socklen_t len {0};
struct free_delete { void operator()(void* p) { ::free(p); } };
struct free_delete { void operator()(void* p) { std::free(p); } };
std::unique_ptr<sockaddr, free_delete> addr {};
void set(const sockaddr* sa, socklen_t length) {
if (len != length) {
len = length;
if (len) addr.reset((sockaddr*)::malloc(len));
if (len) addr.reset((sockaddr*)std::malloc(len));
else addr.reset();
}
if (len)
+3 -9
View File
@@ -55,15 +55,9 @@ void erase_if(std::map<Key, Item>& map, const Condition& condition)
}
class OPENDHT_PUBLIC DhtException : public std::runtime_error {
public:
DhtException(const std::string &str = "") :
std::runtime_error("DhtException occurred: " + str) {}
};
class OPENDHT_PUBLIC SocketException : public DhtException {
public:
SocketException(int err) :
DhtException(strerror(err)) {}
public:
DhtException(const std::string &str = "") :
std::runtime_error("DhtException occurred: " + str) {}
};
// Time related definitions and utility functions
+3 -3
View File
@@ -37,7 +37,7 @@
#include <chrono>
#include <set>
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#if OPENDHT_PROXY_SERVER
#include <json/json.h>
#endif //OPENDHT_PROXY_SERVER
@@ -350,7 +350,7 @@ 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) {}
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#if OPENDHT_PROXY_SERVER
/**
* Build a value from a json object
* @param json
@@ -429,7 +429,7 @@ struct OPENDHT_PUBLIC Value
return ss.str();
}
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#if OPENDHT_PROXY_SERVER
/**
* Build a json object from a value
* Example:
+3 -11
View File
@@ -23,6 +23,7 @@ libopendht_la_SOURCES = \
securedht.cpp \
dhtrunner.cpp \
default_types.cpp \
indexation/pht.cpp \
log.cpp
if WIN32
@@ -50,23 +51,14 @@ nobase_include_HEADERS = \
../include/opendht/default_types.h \
../include/opendht/log.h \
../include/opendht/log_enable.h \
../include/opendht/rng.h
../include/opendht/rng.h \
../include/opendht/indexation/pht.h
if ENABLE_PROXY_SERVER
libopendht_la_SOURCES += base64.h base64.cpp dht_proxy_server.cpp
nobase_include_HEADERS += ../include/opendht/dht_proxy_server.h
endif
if ENABLE_PROXY_CLIENT
libopendht_la_SOURCES += dht_proxy_client.cpp
nobase_include_HEADERS += ../include/opendht/dht_proxy_client.h ../include/opendht/dht_interface.h
endif
if ENABLE_INDEXATION
libopendht_la_SOURCES += indexation/pht.cpp
nobase_include_HEADERS += ../include/opendht/indexation/pht.h
endif
clean-local:
rm -rf libargon2.la
+1 -1
View File
@@ -68,7 +68,7 @@ NodeStats::toString() const
return ss.str();
}
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#if OPENDHT_PROXY_SERVER
/**
* Build a json object from a NodeStats
*/
+2 -22
View File
@@ -538,11 +538,7 @@ PublicKey::getId() const
return {};
InfoHash id;
size_t sz = id.size();
#if GNUTLS_VERSION_NUMBER < 0x030401
const int flags = 0;
#else
const int flags = (id.size() == 32) ? GNUTLS_KEYID_USE_SHA256 : 0;
#endif
if (auto err = gnutls_pubkey_get_key_id(pk, flags, id.data(), &sz))
throw CryptoException(std::string("Can't get public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
@@ -845,15 +841,6 @@ Certificate::addRevocationList(std::shared_ptr<RevocationList> list)
revocation_lists.emplace(std::move(list));
}
std::chrono::system_clock::time_point
Certificate::getActivation() const
{
auto t = gnutls_x509_crt_get_activation_time(cert);
if (t == (time_t)-1)
return std::chrono::system_clock::time_point::min();
return std::chrono::system_clock::from_time_t(t);
}
std::chrono::system_clock::time_point
Certificate::getExpiration() const
{
@@ -926,13 +913,8 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
return {};
Certificate ret {cert};
int64_t now = time(NULL);
/* 2038 bug: don't allow time wrap */
auto boundTime = [](int64_t t) -> time_t {
return std::min<int64_t>(t, std::numeric_limits<time_t>::max());
};
gnutls_x509_crt_set_activation_time(cert, boundTime(now));
gnutls_x509_crt_set_expiration_time(cert, boundTime(now + (10 * 365 * 24 * 60 * 60)));
gnutls_x509_crt_set_activation_time(cert, time(NULL));
gnutls_x509_crt_set_expiration_time(cert, time(NULL) + (20 * 365 * 24 * 60 * 60));
if (gnutls_x509_crt_set_key(cert, key.x509_key) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when setting certificate key" << std::endl;
return {};
@@ -1305,10 +1287,8 @@ std::ostream& operator<< (std::ostream& o, const TrustList::VerifyResult& h)
o << "* Certificate has expired" << std::endl;
if (h.result & GNUTLS_CERT_UNEXPECTED_OWNER)
o << "* The owner is not the expected one" << std::endl;
#if GNUTLS_VERSION_NUMBER >= 0x030401
if (h.result & GNUTLS_CERT_PURPOSE_MISMATCH)
o << "* Certificate or an intermediate does not match the intended purpose" << std::endl;
#endif
if (h.result & GNUTLS_CERT_MISMATCH)
o << "* Certificate presented isn't the expected one" << std::endl;
} else {
+44 -48
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -130,7 +130,7 @@ Dht::trySearchInsert(const Sp<Node>& node)
auto& s = *it->second;
if (s.insertNode(node, now)) {
inserted = true;
scheduler.edit(s.nextSearchStep, now);
scheduler.edit(s.nextSearchStep, s.getNextStepTime(now));
} else if (not s.expired and not s.done)
break;
++it;
@@ -142,7 +142,7 @@ Dht::trySearchInsert(const Sp<Node>& node)
auto& s = *it->second;
if (s.insertNode(node, now)) {
inserted = true;
scheduler.edit(s.nextSearchStep, now);
scheduler.edit(s.nextSearchStep, s.getNextStepTime(now));
} else if (not s.expired and not s.done)
break;
}
@@ -217,7 +217,6 @@ Dht::searchNodeGetDone(const net::Request& req,
{
const auto& now = scheduler.time();
if (auto sr = ws.lock()) {
sr->insertNode(req.node, now, answer.ntoken);
if (auto srn = sr->getNode(req.node)) {
/* all other get requests which are satisfied by this answer
should not be sent anymore */
@@ -229,12 +228,8 @@ Dht::searchNodeGetDone(const net::Request& req,
srn->getStatus[q] = std::move(dummy_req);
}
}
auto syncTime = srn->getSyncTime(scheduler.time());
if (srn->syncJob)
scheduler.edit(srn->syncJob, syncTime);
else
srn->syncJob = scheduler.add(syncTime, std::bind(&Dht::searchStep, this, sr));
}
sr->insertNode(req.node, now, answer.ntoken);
onGetValuesDone(req.node, answer, sr, query);
}
}
@@ -341,8 +336,8 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
if (not n)
return nullptr;
/*DHT_LOG.d(sr->id, n->node->id, "[search %s] [node %s] sending 'find_node'",
sr->id.toString().c_str(), n->node->toString().c_str());*/
DHT_LOG.w(sr->id, n->node->id, "[search %s] [node %s] sending 'find_node'",
sr->id.toString().c_str(), n->node->toString().c_str());
n->getStatus[query] = network_engine.sendFindNode(n->node,
sr->id,
-1,
@@ -355,8 +350,8 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
if (query and not query->select.getSelection().empty()) {
/* The request contains a select. No need to paginate... */
/*DHT_LOG.d(sr->id, n->node->id, "[search %s] [node %s] sending 'get'",
sr->id.toString().c_str(), n->node->toString().c_str());*/
DHT_LOG.w(sr->id, n->node->id, "[search %s] [node %s] sending 'get'",
sr->id.toString().c_str(), n->node->toString().c_str());
n->getStatus[query] = network_engine.sendGetValues(n->node,
sr->id,
*query,
@@ -416,7 +411,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
const auto& now = scheduler.time();
if (not sn->isSynced(now)) {
/* Search is now unsynced. Let's call searchStep to sync again. */
scheduler.edit(sr->nextSearchStep, now);
scheduler.edit(sr->nextSearchStep, sr->getNextStepTime(now));
return;
}
for (auto& a : sr->announce) {
@@ -554,8 +549,6 @@ Dht::searchStep(Sp<Search> sr)
{ /* on done */
if (auto sr = ws.lock()) {
scheduler.edit(sr->nextSearchStep, scheduler.time());
if (auto sn = sr->getNode(req.node))
scheduler.add(sn->getListenTime(query), std::bind(&Dht::searchStep, this, sr));
onListenDone(req.node, answer, sr);
}
},
@@ -613,8 +606,8 @@ Dht::searchStep(Sp<Search> sr)
/* dumpSearch(*sr, std::cout); */
/* periodic searchStep scheduling. */
//if (not sr->done)
// scheduler.edit(sr->nextSearchStep, now);
if (not sr->done)
scheduler.edit(sr->nextSearchStep, sr->getNextStepTime(now));
}
unsigned Dht::refill(Dht::Search& sr) {
@@ -702,7 +695,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
refill(*sr);
if (sr->nextSearchStep)
scheduler.edit(sr->nextSearchStep, scheduler.time());
scheduler.edit(sr->nextSearchStep, sr->getNextStepTime(scheduler.time()));
else
sr->nextSearchStep = scheduler.add(scheduler.time(), std::bind(&Dht::searchStep, this, sr));
@@ -789,12 +782,12 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, GetCallback cb, Value::Filter
sr->done = false;
auto token = ++sr->listener_token;
sr->listeners.emplace(token, LocalListener{q, f, cb});
scheduler.edit(sr->nextSearchStep, now);
scheduler.edit(sr->nextSearchStep, sr->getNextStepTime(now));
return token;
}
size_t
Dht::listen(const InfoHash& id, GetCallback cb, Value::Filter f, Where where)
Dht::listen(const InfoHash& id, GetCallback cb, Value::Filter&& f, Where&& where)
{
scheduler.syncTime();
@@ -1137,6 +1130,7 @@ Dht::cancelPut(const InfoHash& id, const Value::Id& vid)
void
Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v)
{
DHT_LOG.d(id, "[store %s] changed", id.toString().c_str());
if (not st.local_listeners.empty()) {
DHT_LOG.d(id, "[store %s] %lu local listeners", id.toString().c_str(), st.local_listeners.size());
std::vector<std::pair<GetCallback, std::vector<Sp<Value>>>> cbs;
@@ -1156,22 +1150,20 @@ Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v)
cb.first(cb.second);
}
if (not st.listeners.empty()) {
DHT_LOG.d(id, "[store %s] %lu remote listeners", id.toString().c_str(), st.listeners.size());
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
auto f = l.second.query.where.getFilter();
if (f and not f(*v.data))
continue;
DHT_LOG.w(id, node_listeners.first->id, "[store %s] [node %s] sending update",
id.toString().c_str(),
node_listeners.first->toString().c_str());
std::vector<Sp<Value>> vals {};
vals.push_back(v.data);
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
network_engine.tellListener(node_listeners.first, l.first, id, 0, ntoken, {}, {},
std::move(vals), l.second.query);
}
DHT_LOG.d(id, "[store %s] %lu remote listeners", id.toString().c_str(), st.listeners.size());
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
auto f = l.second.query.where.getFilter();
if (f and not f(*v.data))
continue;
DHT_LOG.w(id, node_listeners.first->id, "[store %s] [node %s] sending update",
id.toString().c_str(),
node_listeners.first->toString().c_str());
std::vector<Sp<Value>> vals {};
vals.push_back(v.data);
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
network_engine.tellListener(node_listeners.first, l.second.sid, id, 0, ntoken, {}, {},
std::move(vals), l.second.query);
}
}
}
@@ -1232,10 +1224,10 @@ Dht::storageAddListener(const InfoHash& id, const Sp<Node>& node, size_t socket_
buckets4.findClosestNodes(id, now, TARGET_NODES), buckets6.findClosestNodes(id, now, TARGET_NODES),
std::move(vals), query);
}
node_listeners->second.emplace(socket_id, Listener {now, std::forward<Query>(query)});
node_listeners->second.emplace(socket_id, Listener {socket_id, now, std::forward<Query>(query)});
}
else
l->second.refresh(now, std::forward<Query>(query));
l->second.refresh(socket_id, now, std::forward<Query>(query));
}
void
@@ -1442,8 +1434,10 @@ Dht::dumpSearch(const Search& sr, std::ostream& out) const
out << " [expired]";
bool synced = sr.isSynced(now);
out << (synced ? " [synced]" : " [not synced]");
if (synced && sr.isListening(now))
out << " [listening]";
if (synced && sr.isListening(now)) {
auto lt = sr.getListenTime(now);
out << " [listening, next in " << duration_cast<seconds>(lt-now).count() << " s]";
}
out << std::endl;
/*printing the queries*/
@@ -1655,7 +1649,7 @@ Dht::~Dht()
Dht::Dht() : store(), scheduler(DHT_LOG), network_engine(DHT_LOG, scheduler) {}
Dht::Dht(const int& s, const int& s6, Config config)
Dht::Dht(int s, int s6, Config config)
: myid(config.node_id ? config.node_id : InfoHash::getRandom()),
is_bootstrap(config.is_bootstrap),
maintain_storage(config.maintain_storage), store(), store_quota(),
@@ -2065,7 +2059,6 @@ Dht::onError(Sp<net::Request> req, net::DhtProtocolException e) {
n.token.clear();
n.last_get_reply = time_point::min();
searchSendGetValues(sr);
scheduler.edit(sr->nextSearchStep, scheduler.time());
break;
}
}
@@ -2120,6 +2113,8 @@ Dht::onGetValues(Sp<Node> node, const InfoHash& hash, want_t, const Query& query
if (st != store.end() && not st->second.empty()) {
answer.values = st->second.get(query.where.getFilter());
DHT_LOG.d(hash, "[node %s] sending %u values", node->toString().c_str(), answer.values.size());
} else {
DHT_LOG.d(hash, "[node %s] sending nodes", node->toString().c_str());
}
return answer;
}
@@ -2134,13 +2129,14 @@ void Dht::onGetValuesDone(const Sp<Node>& node,
return;
}
/*DHT_LOG.d(sr->id, "[search %s] [node %s] got reply to 'get' with %u nodes",
sr->id.toString().c_str(), node->toString().c_str(), a.nodes4.size()+a.nodes6.size());*/
DHT_LOG.d(sr->id, "[search %s] [node %s] got reply to 'get' with %u nodes",
sr->id.toString().c_str(), node->toString().c_str(), a.nodes4.size()+a.nodes6.size());
if (not a.ntoken.empty()) {
if (not a.values.empty() or not a.fields.empty()) {
DHT_LOG.d(sr->id, node->id, "[search %s] [node %s] found %u values",
sr->id.toString().c_str(), node->toString().c_str(), a.values.size());
DHT_LOG.d(sr->id, "[search %s IPv%c] found %u values",
sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6',
a.values.size());
for (auto& getp : sr->callbacks) { /* call all callbacks for this search */
auto& get = getp.second;
if (not (get.get_cb or get.query_cb) or
@@ -2225,7 +2221,7 @@ Dht::onListenDone(const Sp<Node>& node,
if (not sr->done) {
const auto& now = scheduler.time();
searchSendGetValues(sr);
scheduler.edit(sr->nextSearchStep, now);
scheduler.edit(sr->nextSearchStep, sr->getNextStepTime(now));
}
}
+174 -369
View File
@@ -1,7 +1,6 @@
/*
* Copyright (C) 2016-2018 Savoir-faire Linux Inc.
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* 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
@@ -28,30 +27,55 @@
#include "dhtrunner.h"
#include <iostream>
constexpr const char* const HTTP_PROTO {"http://"};
namespace dht {
DhtProxyClient::DhtProxyClient(std::function<void()> signal, const std::string& serverHost, const std::string& pushClientId)
: serverHost_(serverHost), pushClientId_(pushClientId), scheduler(DHT_LOG), loopSignal_(signal)
DhtProxyClient::DhtProxyClient(const std::string& serverHost)
: serverHost_(serverHost), lockCurrentProxyInfos_(new std::mutex()),
scheduler(DHT_LOG), currentProxyInfos_(new Json::Value())
{
if (!serverHost_.empty())
startProxy();
startProxy(serverHost_);
}
void
DhtProxyClient::confirmProxy()
{
if (serverHost_.empty()) return;
// Retrieve the connectivity each hours if connected, else every 5 seconds.
auto disconnected_old_status = statusIpv4_ == NodeStatus::Disconnected && statusIpv6_ == NodeStatus::Disconnected;
getConnectivityStatus();
auto disconnected_new_status = statusIpv4_ == NodeStatus::Disconnected && statusIpv6_ == NodeStatus::Disconnected;
auto time = disconnected_new_status ? std::chrono::seconds(5) : std::chrono::hours(1);
if (disconnected_old_status && !disconnected_new_status) {
restartListeners();
}
auto confirm_proxy_time = scheduler.time() + time;
scheduler.edit(nextProxyConfirmation, confirm_proxy_time);
}
void
DhtProxyClient::startProxy(const std::string& serverHost)
{
serverHost_ = serverHost;
if (serverHost_.empty()) return;
auto confirm_proxy_time = scheduler.time() + std::chrono::seconds(5);
nextProxyConfirmation = scheduler.add(confirm_proxy_time, std::bind(&DhtProxyClient::confirmProxy, this));
auto confirm_connectivity = scheduler.time() + std::chrono::seconds(5);
nextConnectivityConfirmation = scheduler.add(confirm_connectivity, std::bind(&DhtProxyClient::confirmConnectivity, this));
getConnectivityStatus();
}
void
DhtProxyClient::startProxy()
DhtProxyClient::confirmConnectivity()
{
if (serverHost_.empty()) return;
DHT_LOG.WARN("Staring proxy client to %s", serverHost_.c_str());
nextProxyConfirmation = scheduler.add(scheduler.time(), std::bind(&DhtProxyClient::confirmProxy, this));
// The scheduler must get if the proxy is disconnected
auto confirm_connectivity = scheduler.time() + std::chrono::seconds(3);
scheduler.edit(nextConnectivityConfirmation, confirm_connectivity);
}
DhtProxyClient::~DhtProxyClient()
@@ -103,7 +127,6 @@ DhtProxyClient::shutdown(ShutdownCallback cb)
NodeStatus
DhtProxyClient::getStatus(sa_family_t af) const
{
std::lock_guard<std::mutex> l(lockCurrentProxyInfos_);
switch (af)
{
case AF_INET:
@@ -118,13 +141,12 @@ DhtProxyClient::getStatus(sa_family_t af) const
bool
DhtProxyClient::isRunning(sa_family_t af) const
{
std::lock_guard<std::mutex> l(lockCurrentProxyInfos_);
switch (af)
{
case AF_INET:
return statusIpv4_ != NodeStatus::Disconnected;
return statusIpv4_ == NodeStatus::Connected;
case AF_INET6:
return statusIpv6_ != NodeStatus::Disconnected;
return statusIpv6_ == NodeStatus::Connected;
default:
return false;
}
@@ -162,10 +184,13 @@ DhtProxyClient::periodic(const uint8_t*, size_t, const SockAddr&)
}
void
DhtProxyClient::get(const InfoHash& key, const GetCallback& cb, DoneCallback donecb, const Value::Filter& filterChain)
DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb,
Value::Filter&& filter, Where&& where)
{
restbed::Uri uri(HTTP_PROTO + serverHost_ + "/" + key.toString());
auto req = std::make_shared<restbed::Request>(uri);
Query query {{}, where};
auto filterChain = filter.chain(query.where.getFilter());
auto finished = std::make_shared<std::atomic_bool>(false);
Operation o;
@@ -190,20 +215,16 @@ DhtProxyClient::get(const InfoHash& key, const GetCallback& cb, DoneCallback don
reply->get_body(body);
reply->set_body(""); // Reset the body for the next fetch
std::string err;
Json::Value json;
Json::CharReaderBuilder rbuilder;
auto* char_data = reinterpret_cast<const char*>(&body[0]);
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (reader->parse(char_data, char_data + body.size(), &json, &err)) {
Json::Reader reader;
if (reader.parse(body, json)) {
auto value = std::make_shared<Value>(json);
if ((not filterChain or filterChain(*value)) && cb) {
std::lock_guard<std::mutex> lock(lockCallbacks);
callbacks_.emplace_back([cb, value, finished]() {
if (not cb({value}))
if (not *finished and not cb({value}))
*finished = true;
});
loopSignal_();
}
} else {
*ok = false;
@@ -219,11 +240,10 @@ DhtProxyClient::get(const InfoHash& key, const GetCallback& cb, DoneCallback don
callbacks_.emplace_back([=](){
donecb(*ok, {});
});
loopSignal_();
}
if (!ok) {
// Connection failed, update connectivity
opFailed();
getConnectivityStatus();
}
*finished = true;
});
@@ -233,28 +253,17 @@ DhtProxyClient::get(const InfoHash& key, const GetCallback& cb, DoneCallback don
}
}
void
DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb,
Value::Filter&& filter, Where&& where)
{
Query query {{}, where};
auto filterChain = filter.chain(query.where.getFilter());
get(key, cb, donecb, filterChain);
}
void
DhtProxyClient::put(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_point, bool permanent)
{
restbed::Uri uri(HTTP_PROTO + serverHost_ + "/" + key.toString());
auto req = std::make_shared<restbed::Request>(uri);
req->set_method("POST");
Json::FastWriter writer;
auto json = val->toJson();
if (permanent)
json["permanent"] = true;
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto body = Json::writeString(wbuilder, json) + "\n";
auto body = writer.write(json);
req->set_body(body);
req->set_header("Content-Length", std::to_string(body.size()));
@@ -275,13 +284,10 @@ DhtProxyClient::put(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_po
reply->get_body(body);
reply->set_body(""); // Reset the body for the next fetch
Json::Value json;
Json::Reader reader;
try {
std::string err;
Json::Value json;
Json::CharReaderBuilder rbuilder;
auto* char_data = reinterpret_cast<const char*>(&body[0]);
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (not reader->parse(char_data, char_data + body.size(), &json, &err))
if (!reader.parse(body, json))
*ok = false;
} catch (...) {
*ok = false;
@@ -295,11 +301,10 @@ DhtProxyClient::put(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_po
callbacks_.emplace_back([=](){
cb(*ok, {});
});
loopSignal_();
}
if (!ok) {
// Connection failed, update connectivity
opFailed();
getConnectivityStatus();
}
*finished = true;
});
@@ -312,136 +317,100 @@ DhtProxyClient::put(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_po
NodeStats
DhtProxyClient::getNodesStats(sa_family_t af) const
{
return af == AF_INET ? stats4_ : stats6_;
lockCurrentProxyInfos_->lock();
auto proxyInfos = *currentProxyInfos_;
lockCurrentProxyInfos_->unlock();
NodeStats stats {};
auto identifier = af == AF_INET6 ? "ipv6" : "ipv4";
try {
stats = NodeStats(proxyInfos[identifier]);
} catch (...) { }
return stats;
}
void
DhtProxyClient::getProxyInfos()
Json::Value
DhtProxyClient::getProxyInfos() const
{
DHT_LOG.DEBUG("Requesting proxy server node information");
if (ongoingStatusUpdate_.test_and_set())
return;
{
std::lock_guard<std::mutex> l(lockCurrentProxyInfos_);
if (statusIpv4_ == NodeStatus::Disconnected)
statusIpv4_ = NodeStatus::Connecting;
if (statusIpv6_ == NodeStatus::Disconnected)
statusIpv6_ = NodeStatus::Connecting;
}
restbed::Uri uri(HTTP_PROTO + serverHost_ + "/");
auto req = std::make_shared<restbed::Request>(uri);
// Try to contact the proxy and set the status to connected when done.
// will change the connectivity status
statusThread_ = std::thread([this, req]{
restbed::Http::async(req,
[this](const std::shared_ptr<restbed::Request>&,
const std::shared_ptr<restbed::Response>& reply) {
auto code = reply->get_status_code();
Json::Value proxyInfos;
if (code == 200) {
restbed::Http::fetch("\n", reply);
std::string body;
reply->get_body(body);
restbed::Http::async(req,
[this](const std::shared_ptr<restbed::Request>&,
const std::shared_ptr<restbed::Response>& reply) {
auto code = reply->get_status_code();
std::string err;
Json::CharReaderBuilder rbuilder;
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
try {
reader->parse(body.data(), body.data() + body.size(), &proxyInfos, &err);
} catch (...) {
}
if (code == 200) {
restbed::Http::fetch("\n", reply);
std::string body;
reply->get_body(body);
Json::Reader reader;
lockCurrentProxyInfos_->lock();
try {
reader.parse(body, *currentProxyInfos_);
} catch (...) {
*currentProxyInfos_ = Json::Value();
}
onProxyInfos(proxyInfos);
ongoingStatusUpdate_.clear();
});
});
statusThread_.detach();
}
void
DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos)
{
std::lock_guard<std::mutex> l(lockCurrentProxyInfos_);
auto oldStatus = std::max(statusIpv4_, statusIpv6_);
try {
myid = InfoHash(proxyInfos["node_id"].asString());
stats4_ = NodeStats(proxyInfos["ipv4"]);
if (stats4_.good_nodes)
statusIpv4_ = NodeStatus::Connected;
else if (stats4_.dubious_nodes)
statusIpv4_ = NodeStatus::Connecting;
else
statusIpv4_ = NodeStatus::Disconnected;
stats6_ = NodeStats(proxyInfos["ipv6"]);
if (stats6_.good_nodes)
statusIpv6_ = NodeStatus::Connected;
else if (stats6_.dubious_nodes)
statusIpv6_ = NodeStatus::Connecting;
else
statusIpv6_ = NodeStatus::Disconnected;
publicAddress_ = parsePublicAddress(proxyInfos["public_ip"]);
} catch (...) {}
auto newStatus = std::max(statusIpv4_, statusIpv6_);
if (newStatus == NodeStatus::Connecting || newStatus == NodeStatus::Connected) {
if (oldStatus == NodeStatus::Disconnected) {
restartListeners();
lockCurrentProxyInfos_->unlock();
} else {
lockCurrentProxyInfos_->lock();
*currentProxyInfos_ = Json::Value();
lockCurrentProxyInfos_->unlock();
}
scheduler.edit(nextProxyConfirmation, scheduler.time() + std::chrono::minutes(15));
}
else if (newStatus == NodeStatus::Disconnected) {
scheduler.edit(nextProxyConfirmation, scheduler.time() + std::chrono::minutes(1));
}
loopSignal_();
}
SockAddr
DhtProxyClient::parsePublicAddress(const Json::Value& val)
{
auto public_ip = val.asString();
auto endIp = public_ip.find_last_of(':');
std::string service = public_ip.substr(endIp + 1);
std::string address = public_ip.substr(0, endIp - 1);
auto sa = SockAddr::resolve(address, service);
if (sa.empty()) return {};
return sa.front().getMappedIPv4();
}).wait();
lockCurrentProxyInfos_->lock();
auto result = *currentProxyInfos_;
lockCurrentProxyInfos_->unlock();
return result;
}
std::vector<SockAddr>
DhtProxyClient::getPublicAddress(sa_family_t family)
{
std::lock_guard<std::mutex> l(lockCurrentProxyInfos_);
if (not publicAddress_) return {};
return publicAddress_.getFamily() == family ? std::vector<SockAddr>{publicAddress_} : std::vector<SockAddr>{};
lockCurrentProxyInfos_->lock();
auto proxyInfos = *currentProxyInfos_;
lockCurrentProxyInfos_->unlock();
// json["public_ip"] contains [ipv6:ipv4]:port or ipv4:port
auto public_ip = proxyInfos["public_ip"].asString();
if (!proxyInfos.isMember("public_ip") || (public_ip.length() < 2)) return {};
std::string ipv4Address = "", ipv6Address = "", port = "";
if (public_ip[0] == '[') {
// ipv6 complient
auto endIp = public_ip.find(']');
if (public_ip.length() > endIp + 2) {
port = public_ip.substr(endIp + 2);
auto ips = public_ip.substr(1, endIp - 1);
auto ipv4And6Separator = ips.find_last_of(':');
ipv4Address = ips.substr(ipv4And6Separator + 1);
ipv6Address = ips.substr(0, ipv4And6Separator - 1);
}
} else {
auto endIp = public_ip.find_last_of(':');
port = public_ip.substr(endIp + 1);
ipv4Address = public_ip.substr(0, endIp - 1);
}
switch (family)
{
case AF_INET:
return SockAddr::resolve(ipv4Address, port);
case AF_INET6:
return SockAddr::resolve(ipv6Address, port);
default:
return {};
}
}
size_t
DhtProxyClient::listen(const InfoHash& key, GetCallback cb, Value::Filter filter, Where where)
DhtProxyClient::listen(const InfoHash& key, GetCallback cb, Value::Filter&& filter, Where&& where)
{
restbed::Uri uri(HTTP_PROTO + serverHost_ + "/" + key.toString());
auto req = std::make_shared<restbed::Request>(uri);
req->set_method(deviceKey_.empty() ? "LISTEN" : "SUBSCRIBE");
req->set_method("LISTEN");
Query query {{}, where};
auto filterChain = filter.chain(query.where.getFilter());
auto pushNotifToken = std::make_shared<unsigned>(0);
unsigned callbackId = 0;
{
std::lock_guard<std::mutex> lock(lockCallback_);
callbackId_ += 1;
callbackId = callbackId_;
}
Listener l;
++listener_token_;
@@ -449,20 +418,12 @@ DhtProxyClient::listen(const InfoHash& key, GetCallback cb, Value::Filter filter
l.token = listener_token_;
l.req = req;
l.cb = cb;
l.callbackId = callbackId;
l.pushNotifToken = pushNotifToken;
l.filterChain = std::move(filterChain);
l.thread = std::thread([=]()
{
auto settings = std::make_shared<restbed::Settings>();
if (deviceKey_.empty()) {
std::chrono::milliseconds timeout(std::numeric_limits<int>::max());
settings->set_connection_timeout(timeout); // Avoid the client to close the socket after 5 seconds.
}
#if OPENDHT_PUSH_NOTIFICATIONS
else
fillBodyToGetToken(req, callbackId);
#endif
std::chrono::milliseconds timeout(std::numeric_limits<int>::max());
settings->set_connection_timeout(timeout); // Avoid the client to close the socket after 5 seconds.
struct State {
std::atomic_bool ok {true};
@@ -470,54 +431,35 @@ DhtProxyClient::listen(const InfoHash& key, GetCallback cb, Value::Filter filter
};
auto state = std::make_shared<State>();
restbed::Http::async(req,
[this, filterChain, cb, pushNotifToken, state](const std::shared_ptr<restbed::Request>& req,
const std::shared_ptr<restbed::Response>& reply) {
[this, filterChain, cb, state](const std::shared_ptr<restbed::Request>& req,
const std::shared_ptr<restbed::Response>& reply) {
auto code = reply->get_status_code();
if (code == 200) {
try {
std::string err;
Json::Value json;
Json::CharReaderBuilder rbuilder;
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (!deviceKey_.empty()) {
while (restbed::Http::is_open(req) and not state->cancel) {
restbed::Http::fetch("\n", reply);
if (state->cancel)
return;
break;
std::string body;
reply->get_body(body);
reply->set_body(""); // Reset the body for the next fetch
auto* char_data = reinterpret_cast<const char*>(&body[0]);
if (reader->parse(char_data, char_data + body.size(), &json, &err)) {
if (!json.isMember("token")) return;
*pushNotifToken = json["token"].asLargestUInt();
Json::Value json;
Json::Reader reader;
if (reader.parse(body, json)) {
auto value = std::make_shared<Value>(json);
if ((not filterChain or filterChain(*value)) && cb) {
std::lock_guard<std::mutex> lock(lockCallbacks);
callbacks_.emplace_back([cb, value, state]() {
if (not state->cancel and not cb({value})) {
state->cancel = true;
}
});
}
} else {
state->ok = false;
}
} else {
while (restbed::Http::is_open(req) and not state->cancel) {
restbed::Http::fetch("\n", reply);
if (state->cancel)
break;
std::string body;
reply->get_body(body);
reply->set_body(""); // Reset the body for the next fetch
auto* char_data = reinterpret_cast<const char*>(&body[0]);
if (reader->parse(char_data, char_data + body.size(), &json, &err)) {
auto value = std::make_shared<Value>(json);
if ((not filterChain or filterChain(*value)) && cb) {
std::lock_guard<std::mutex> lock(lockCallbacks);
callbacks_.emplace_back([cb, value, state]() {
if (not state->cancel and not cb({value})) {
state->cancel = true;
}
});
loopSignal_();
}
} else {
state->ok = false;
}
}
}
} catch (std::runtime_error&) {
state->ok = false;
@@ -527,7 +469,7 @@ DhtProxyClient::listen(const InfoHash& key, GetCallback cb, Value::Filter filter
}
}, settings).get();
if (not state->ok) {
opFailed();
getConnectivityStatus();
}
}
);
@@ -545,69 +487,44 @@ DhtProxyClient::cancelListen(const InfoHash&, size_t token)
for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
auto& listener = *it;
if (listener.token == token) {
if (!deviceKey_.empty()) {
// First, be sure to have a token
if (listener.thread.joinable()) {
listener.thread.join();
}
// UNSUBSCRIBE
restbed::Uri uri(HTTP_PROTO + serverHost_ + "/" + listener.key);
auto req = std::make_shared<restbed::Request>(uri);
req->set_method("UNSUBSCRIBE");
// fill request body
Json::Value body;
body["key"] = deviceKey_;
body["client_id"] = pushClientId_;
body["token"] = std::to_string(token);
body["callback_id"] = listener.callbackId;
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto content = Json::writeString(wbuilder, body) + "\n";
std::replace(content.begin(), content.end(), '\n', ' ');
req->set_body(content);
req->set_header("Content-Length", std::to_string(content.size()));
restbed::Http::async(req,
[](const std::shared_ptr<restbed::Request>&,
const std::shared_ptr<restbed::Response>&){}
);
// And remove
if (listener.thread.joinable()) {
// Close connection to stop listener?
if (listener.req)
restbed::Http::close(listener.req);
listener.thread.join();
listeners_.erase(it);
return true;
} else {
// Just stop the request
if (listener.thread.joinable()) {
// Close connection to stop listener?
if (listener.req)
restbed::Http::close(listener.req);
listener.thread.join();
listeners_.erase(it);
return true;
}
}
}
}
return false;
}
void
DhtProxyClient::opFailed()
{
DHT_LOG.ERR("Proxy request failed");
{
std::lock_guard<std::mutex> l(lockCurrentProxyInfos_);
statusIpv4_ = NodeStatus::Disconnected;
statusIpv6_ = NodeStatus::Disconnected;
}
getConnectivityStatus();
loopSignal_();
}
void
DhtProxyClient::getConnectivityStatus()
{
getProxyInfos();
auto proxyInfos = getProxyInfos();
// NOTE: json["ipvX"] contains NodeStats::toJson()
try {
auto goodIpv4 = static_cast<long>(proxyInfos["ipv4"]["good"].asLargestUInt());
auto dubiousIpv4 = static_cast<long>(proxyInfos["ipv4"]["dubious"].asLargestUInt());
statusIpv4_ = (goodIpv4 + dubiousIpv4 > 0) ? NodeStatus::Connected : NodeStatus::Disconnected;
auto goodIpv6 = static_cast<long>(proxyInfos["ipv6"]["good"].asLargestUInt());
auto dubiousIpv6 = static_cast<long>(proxyInfos["ipv6"]["dubious"].asLargestUInt());
statusIpv6_ = (goodIpv6 + dubiousIpv6 > 0) ? NodeStatus::Connected : NodeStatus::Disconnected;
myid = InfoHash(proxyInfos["node_id"].asString());
if (statusIpv4_ == NodeStatus::Disconnected && statusIpv6_ == NodeStatus::Disconnected) {
const auto& now = scheduler.time();
scheduler.edit(nextProxyConfirmation, now);
}
} catch (...) {
statusIpv4_ = NodeStatus::Disconnected;
statusIpv6_ = NodeStatus::Disconnected;
const auto& now = scheduler.time();
scheduler.edit(nextProxyConfirmation, now);
}
}
void
@@ -630,10 +547,9 @@ DhtProxyClient::restartListeners()
std::chrono::milliseconds timeout(std::numeric_limits<int>::max());
settings->set_connection_timeout(timeout); // Avoid the client to close the socket after 5 seconds.
auto ok = std::make_shared<std::atomic_bool>(true);
restbed::Http::async(req,
[this, filterChain, cb, ok](const std::shared_ptr<restbed::Request>& req,
const std::shared_ptr<restbed::Response>& reply) {
[this, filterChain, cb](const std::shared_ptr<restbed::Request>& req,
const std::shared_ptr<restbed::Response>& reply) {
auto code = reply->get_status_code();
if (code == 200) {
@@ -645,11 +561,8 @@ DhtProxyClient::restartListeners()
reply->set_body(""); // Reset the body for the next fetch
Json::Value json;
std::string err;
Json::CharReaderBuilder rbuilder;
auto* char_data = reinterpret_cast<const char*>(&body[0]);
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (reader->parse(char_data, char_data + body.size(), &json, &err)) {
Json::Reader reader;
if (reader.parse(body, json)) {
auto value = std::make_shared<Value>(json);
if ((not filterChain or filterChain(*value)) && cb) {
auto okCb = std::make_shared<std::promise<bool>>();
@@ -659,7 +572,6 @@ DhtProxyClient::restartListeners()
callbacks_.emplace_back([cb, value, okCb](){
okCb->set_value(cb({value}));
});
loopSignal_();
}
futureCb.wait();
if (!futureCb.get()) {
@@ -671,125 +583,18 @@ DhtProxyClient::restartListeners()
} catch (std::runtime_error&) {
// NOTE: Http::close() can occurs here. Ignore this.
}
} else {
*ok = false;
this->statusIpv4_ = NodeStatus::Disconnected;
this->statusIpv6_ = NodeStatus::Disconnected;
}
}, settings).get();
if (!ok) opFailed();
getConnectivityStatus();
}
);
}
}
void
DhtProxyClient::pushNotificationReceived(const std::map<std::string, std::string>& notification)
{
#if OPENDHT_PUSH_NOTIFICATIONS
try {
auto token = std::stoul(notification.at("token"));
for (const auto& listener: listeners_) {
if (*(listener.pushNotifToken) != token)
continue;
if (notification.find("timeout") == notification.cend()) {
// Wake up daemon and get values
get(InfoHash(listener.key), listener.cb, {}, listener.filterChain);
} else {
// A timeout has occured, we need to relaunch the listener
resubscribe(token);
}
}
} catch (...) {
}
#endif
}
void
DhtProxyClient::resubscribe(const unsigned token)
{
#if OPENDHT_PUSH_NOTIFICATIONS
if (deviceKey_.empty()) return;
for (auto& listener: listeners_) {
if (*(listener.pushNotifToken) == token) {
// Subscribe
restbed::Uri uri(HTTP_PROTO + serverHost_ + "/" + listener.key);
auto req = std::make_shared<restbed::Request>(uri);
req->set_method("SUBSCRIBE");
auto pushNotifToken = std::make_shared<unsigned>(0);
if (listener.thread.joinable())
listener.thread.join();
listener.req = req;
listener.pushNotifToken = pushNotifToken;
auto callbackId = listener.callbackId;
listener.thread = std::thread([=]()
{
fillBodyToGetToken(req, callbackId);
auto settings = std::make_shared<restbed::Settings>();
auto ok = std::make_shared<std::atomic_bool>(true);
restbed::Http::async(req,
[this, pushNotifToken, ok](const std::shared_ptr<restbed::Request>&,
const std::shared_ptr<restbed::Response>& reply) {
auto code = reply->get_status_code();
if (code == 200) {
try {
restbed::Http::fetch("\n", reply);
std::string body;
reply->get_body(body);
std::string err;
Json::Value json;
Json::CharReaderBuilder rbuilder;
auto* char_data = reinterpret_cast<const char*>(&body[0]);
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (reader->parse(char_data, char_data + body.size(), &json, &err)) {
if (!json.isMember("token")) return;
*pushNotifToken = json["token"].asLargestUInt();
}
} catch (std::runtime_error&) {
// NOTE: Http::close() can occurs here. Ignore this.
}
} else {
*ok = false;
}
}, settings).get();
if (!ok) opFailed();
});
}
}
#endif
}
#if OPENDHT_PUSH_NOTIFICATIONS
void
DhtProxyClient::fillBodyToGetToken(std::shared_ptr<restbed::Request> req, unsigned callbackId)
{
// Fill body with
// {
// "key":"device_key",
// "callback_id": xxx
// }
Json::Value body;
body["key"] = deviceKey_;
body["client_id"] = pushClientId_;
body["callback_id"] = callbackId;
#ifdef __ANDROID__
body["platform"] = "android";
#endif
#ifdef __APPLE__
body["platform"] = "apple";
#endif
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto content = Json::writeString(wbuilder, body) + "\n";
std::replace(content.begin(), content.end(), '\n', ' ');
req->set_body(content);
req->set_header("Content-Length", std::to_string(content.size()));
}
#endif // OPENDHT_PUSH_NOTIFICATIONS
} // namespace dht
+61 -315
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
* Copyright (C) 2017 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -28,30 +28,16 @@
#include <json/json.h>
#include <limits>
#if OPENDHT_PUSH_NOTIFICATIONS
constexpr int const TIMEOUT {6 * 60 * 60}; // in seconds (so six hours)
constexpr const char* const HTTP_PROTO {"http://"}; // TODO, https for prod
#endif //OPENDHT_PUSH_NOTIFICATIONS
using namespace std::placeholders;
namespace dht {
DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port , const std::string& pushServer)
: dht_(dht) , pushServer_(pushServer)
DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port)
: dht_(dht)
{
// NOTE in c++14, use make_unique
service_ = std::unique_ptr<restbed::Service>(new restbed::Service());
std::cout << "Running DHT proxy server on port " << port << std::endl;
if (not pushServer.empty()) {
#if !OPENDHT_PUSH_NOTIFICATIONS
std::cerr << "Push server defined but built OpenDHT built without push notification support" << std::endl;
#else
std::cout << "Using push notification server: " << pushServer << std::endl;
#endif
}
server_thread = std::thread([this, port]() {
// Create endpoints
auto resource = std::make_shared<restbed::Resource>();
@@ -62,10 +48,6 @@ DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port ,
resource->set_path("/{hash: .*}");
resource->set_method_handler("GET", std::bind(&DhtProxyServer::get, this, _1));
resource->set_method_handler("LISTEN", std::bind(&DhtProxyServer::listen, this, _1));
#if OPENDHT_PUSH_NOTIFICATIONS
resource->set_method_handler("SUBSCRIBE", std::bind(&DhtProxyServer::subscribe, this, _1));
resource->set_method_handler("UNSUBSCRIBE", std::bind(&DhtProxyServer::unsubscribe, this, _1));
#endif //OPENDHT_PUSH_NOTIFICATIONS
resource->set_method_handler("POST", std::bind(&DhtProxyServer::put, this, _1));
#if OPENDHT_PROXY_SERVER_IDENTITY
resource->set_method_handler("SIGN", std::bind(&DhtProxyServer::putSigned, this, _1));
@@ -100,15 +82,33 @@ DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port ,
std::this_thread::sleep_for(std::chrono::seconds(1));
}
while (service_->is_up() && !stopListeners) {
removeClosedListeners();
// add listener from push notifs
#if OPENDHT_PUSH_NOTIFICATIONS
handlePushListeners();
#endif //OPENDHT_PUSH_NOTIFICATIONS
lockListener_.lock();
auto listener = currentListeners_.begin();
while (listener != currentListeners_.end()) {
if (dht_ && listener->session->is_closed()) {
dht_->cancelListen(listener->hash, std::move(listener->token));
// Remove listener if unused
listener = currentListeners_.erase(listener);
} else {
++listener;
}
}
lockListener_.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
// Remove last listeners
removeClosedListeners(false);
lockListener_.lock();
auto listener = currentListeners_.begin();
while (listener != currentListeners_.end()) {
if (dht_) {
dht_->cancelListen(listener->hash, std::move(listener->token.get()));
// Remove listener if unused
listener = currentListeners_.erase(listener);
} else {
++listener;
}
}
lockListener_.unlock();
});
dht->forwardAllMessages(true);
@@ -123,14 +123,13 @@ void
DhtProxyServer::stop()
{
service_->stop();
{
std::lock_guard<std::mutex> lock(lockListener_);
auto listener = currentListeners_.begin();
while (listener != currentListeners_.end()) {
listener->session->close();
++ listener;
}
lockListener_.lock();
auto listener = currentListeners_.begin();
while (listener != currentListeners_.end()) {
listener->session->close();
++ listener;
}
lockListener_.unlock();
stopListeners = true;
// listenThreads_ will stop because there is no more sessions
if (listenThread_.joinable())
@@ -156,11 +155,8 @@ DhtProxyServer::getNodeInfo(const std::shared_ptr<restbed::Session>& session) co
result["ipv4"] = dht_->getNodesStats(AF_INET).toJson();
result["ipv6"] = dht_->getNodesStats(AF_INET6).toJson();
result["public_ip"] = s->get_origin(); // [ipv6:ipv4]:port or ipv4:port
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(wbuilder, result) + "\n";
s->close(restbed::OK, output);
Json::FastWriter writer;
s->close(restbed::OK, writer.write(result));
}
else
s->close(restbed::SERVICE_UNAVAILABLE, "{\"err\":\"Incorrect DhtRunner\"}");
@@ -189,11 +185,8 @@ DhtProxyServer::get(const std::shared_ptr<restbed::Session>& session) const
auto s = cacheSession.lock();
if (!s) return false;
// Send values as soon as we get them
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(wbuilder, value->toJson()) + "\n";
s->yield(output, [](const std::shared_ptr<restbed::Session> /*session*/){ });
Json::FastWriter writer;
s->yield(writer.write(value->toJson()), [](const std::shared_ptr<restbed::Session> /*session*/){ });
return true;
}, [s](bool /*ok* */) {
// Communication is finished
@@ -241,18 +234,14 @@ DhtProxyServer::listen(const std::shared_ptr<restbed::Session>& session) const
if (!s) return false;
// Send values as soon as we get them
if (!s->is_closed()) {
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(wbuilder, value->toJson()) + "\n";
s->yield(output, [](const std::shared_ptr<restbed::Session>){ });
Json::FastWriter writer;
s->yield(writer.write(value->toJson()), [](const std::shared_ptr<restbed::Session>){ });
}
return !s->is_closed();
});
{
std::lock_guard<std::mutex> lock(lockListener_);
currentListeners_.emplace_back(std::move(listener));
}
lockListener_.lock();
currentListeners_.emplace_back(std::move(listener));
lockListener_.unlock();
} else {
session->close(restbed::SERVICE_UNAVAILABLE, "{\"err\":\"Incorrect DhtRunner\"}");
}
@@ -260,210 +249,6 @@ DhtProxyServer::listen(const std::shared_ptr<restbed::Session>& session) const
);
}
#if OPENDHT_PUSH_NOTIFICATIONS
void
DhtProxyServer::subscribe(const std::shared_ptr<restbed::Session>& session) const
{
const auto request = session->get_request();
int content_length = std::stoi(request->get_header("Content-Length", "0"));
auto hash = request->get_path_parameter("hash");
InfoHash infoHash(hash);
if (!infoHash)
infoHash = InfoHash::get(hash);
session->fetch(content_length,
[=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& b)
{
try {
restbed::Bytes buf(b);
std::string strJson(buf.begin(), buf.end());
std::string err;
Json::Value root;
Json::CharReaderBuilder rbuilder;
auto* char_data = reinterpret_cast<const char*>(&strJson[0]);
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (!reader->parse(char_data, char_data + strJson.size(), &root, &err)) {
s->close(restbed::BAD_REQUEST, "{\"err\":\"Incorrect JSON\"}");
return;
}
auto pushToken = root["key"].asString();
if (pushToken.empty()) return;
auto callbackId = root.isMember("callback_id") ? root["callback_id"].asLargestUInt() : 0;
auto platform = root["platform"].asString();
auto isAndroid = platform == "android";
auto clientId = root.isMember("client_id") ? root["client_id"].asString() : std::string();
auto token = 0;
{
std::lock_guard<std::mutex> lock(lockListener_);
// Check if listener is already present and refresh timeout if launched
for(auto& listener: pushListeners_) {
if (listener.pushToken == pushToken && listener.hash == infoHash
&& listener.callbackId == callbackId) {
if (listener.started)
listener.deadline = std::chrono::steady_clock::now()
+ std::chrono::seconds(TIMEOUT);
s->close(restbed::OK, "{\"token\": " + std::to_string(listener.token) + "}\n");
return;
}
}
// The listener is not found, so add it.
++tokenPushNotif_;
token = tokenPushNotif_;
PushListener listener;
listener.pushToken = pushToken;
listener.hash = std::move(infoHash);
listener.token = token;
listener.started = false;
listener.callbackId = callbackId;
listener.clientId = clientId;
listener.isAndroid = isAndroid;
pushListeners_.emplace_back(std::move(listener));
}
s->close(restbed::OK, "{\"token\": " + std::to_string(token) + "}\n");
} catch (...) {
// do nothing
}
}
);
}
void
DhtProxyServer::unsubscribe(const std::shared_ptr<restbed::Session>& session) const
{
const auto request = session->get_request();
int content_length = std::stoi(request->get_header("Content-Length", "0"));
auto hash = request->get_path_parameter("hash");
InfoHash infoHash(hash);
if (!infoHash)
infoHash = InfoHash::get(hash);
session->fetch(content_length,
[=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& b)
{
try {
restbed::Bytes buf(b);
std::string strJson(buf.begin(), buf.end());
std::string err;
Json::Value root;
Json::CharReaderBuilder rbuilder;
auto* char_data = reinterpret_cast<const char*>(&strJson[0]);
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (!reader->parse(char_data, char_data + strJson.size(), &root, &err)) {
s->close(restbed::BAD_REQUEST, "{\"err\":\"Incorrect JSON\"}");
return;
}
auto pushToken = root["key"].asString();
if (pushToken.empty()) return;
auto token = std::stoull(root["token"].asString());
if (token == 0) return;
auto callbackId = root.isMember("callback_id") ? root["callback_id"].asLargestUInt() : 0;
std::lock_guard<std::mutex> lock(lockListener_);
// Check if listener is already present and refresh timeout if launched
auto listener = pushListeners_.begin();
while (listener != pushListeners_.end()) {
if (listener->pushToken == pushToken && listener->token == token
&& listener->hash == infoHash && listener->callbackId == callbackId) {
if (dht_ && listener->started)
dht_->cancelListen(listener->hash, std::move(listener->internalToken.get()));
listener = pushListeners_.erase(listener);
} else {
++listener;
}
}
} catch (...) {
// do nothing
}
}
);
}
void
DhtProxyServer::sendPushNotification(const std::string& token, const Json::Value& json, bool isAndroid) const
{
restbed::Uri uri(HTTP_PROTO + pushServer_ + "/api/push");
auto req = std::make_shared<restbed::Request>(uri);
req->set_method("POST");
// NOTE: see https://github.com/appleboy/gorush
Json::Value notification(Json::objectValue);
Json::Value tokens(Json::arrayValue);
tokens[0] = token;
notification["tokens"] = tokens;
notification["platform"] = isAndroid ? 2 : 1;
notification["data"] = json;
notification["priority"] = "high";
notification["time_to_live"] = 600;
Json::Value notifications(Json::arrayValue);
notifications[0] = notification;
Json::Value content;
content["notifications"] = notifications;
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto valueStr = Json::writeString(wbuilder, content);
req->set_header("Content-Type", "application/json");
req->set_header("Accept", "*/*");
req->set_header("Host", pushServer_);
req->set_header("Content-Length", std::to_string(valueStr.length()));
req->set_body(valueStr);
// Send request.
restbed::Http::async(req, {});
}
void
DhtProxyServer::handlePushListeners()
{
std::lock_guard<std::mutex> lock(lockListener_);
auto pushListener = pushListeners_.begin();
while (pushListener != pushListeners_.end()) {
if (dht_ && !pushListener->started) {
// Try to start unstarted listeners
auto key = pushListener->pushToken;
auto token = pushListener->token;
auto callbackId = pushListener->callbackId;
auto isAndroid = pushListener->isAndroid;
auto clientId = pushListener->clientId;
pushListener->internalToken = dht_->listen(pushListener->hash,
[this, key, callbackId, token, isAndroid, clientId](std::vector<std::shared_ptr<Value>> /*value*/) {
// Build message content.
Json::Value json;
if (callbackId > 0) {
json["callback_id"] = callbackId;
}
json["to"] = clientId;
json["token"] = token;
sendPushNotification(key, json, isAndroid);
return true;
}
);
pushListener->deadline = std::chrono::steady_clock::now() + std::chrono::seconds(TIMEOUT);
pushListener->started = true;
pushListener++;
} else if (dht_ && pushListener->started && pushListener->deadline < std::chrono::steady_clock::now()) {
// Cancel listen if deadline has been reached
dht_->cancelListen(pushListener->hash, std::move(pushListener->internalToken.get()));
// Send a push notification to inform the client that this listen has timeout
Json::Value json;
json["timeout"] = pushListener->hash.toString();
if (pushListener->callbackId > 0) {
json["callback_id"] = pushListener->callbackId;
}
json["to"] = pushListener->clientId;
json["token"] = pushListener->token;
sendPushNotification(pushListener->pushToken, json, pushListener->isAndroid);
pushListener = pushListeners_.erase(pushListener);
} else {
pushListener++;
}
}
}
#endif //OPENDHT_PUSH_NOTIFICATIONS
void
DhtProxyServer::put(const std::shared_ptr<restbed::Session>& session) const
{
@@ -483,25 +268,20 @@ DhtProxyServer::put(const std::shared_ptr<restbed::Session>& session) const
s->close(restbed::BAD_REQUEST, response);
} else {
restbed::Bytes buf(b);
std::string strJson(buf.begin(), buf.end());
std::string err;
Json::Value root;
Json::CharReaderBuilder rbuilder;
auto* char_data = reinterpret_cast<const char*>(&strJson[0]);
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (reader->parse(char_data, char_data + strJson.size(), &root, &err)) {
Json::Reader reader;
std::string strJson(buf.begin(), buf.end());
bool parsingSuccessful = reader.parse(strJson.c_str(), root);
if (parsingSuccessful) {
// Build the Value from json
auto value = std::make_shared<Value>(root);
auto permanent = root.isMember("permanent") ? root["permanent"].asBool() : false;
dht_->put(infoHash, value, [s, value](bool ok) {
if (ok) {
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
Json::FastWriter writer;
if (s->is_open())
s->close(restbed::OK, Json::writeString(wbuilder, value->toJson()) + "\n");
s->close(restbed::OK, writer.write(value->toJson()));
} else {
if (s->is_open())
s->close(restbed::BAD_GATEWAY, "{\"err\":\"put failed\"}");
@@ -538,22 +318,16 @@ DhtProxyServer::putSigned(const std::shared_ptr<restbed::Session>& session) cons
s->close(restbed::BAD_REQUEST, response);
} else {
restbed::Bytes buf(b);
std::string strJson(buf.begin(), buf.end());
std::string err;
Json::Value root;
Json::CharReaderBuilder rbuilder;
auto* char_data = reinterpret_cast<const char*>(&strJson[0]);
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (reader->parse(char_data, char_data + strJson.size(), &root, &err)) {
Json::Reader reader;
std::string strJson(buf.begin(), buf.end());
bool parsingSuccessful = reader.parse(strJson.c_str(), root);
if (parsingSuccessful) {
auto value = std::make_shared<Value>(root);
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(wbuilder, value->toJson()) + "\n";
Json::FastWriter writer;
dht_->putSigned(infoHash, value);
s->close(restbed::OK, output);
s->close(restbed::OK, writer.write(value->toJson()));
} else {
s->close(restbed::BAD_REQUEST, "{\"err\":\"Incorrect JSON\"}");
}
@@ -584,23 +358,16 @@ DhtProxyServer::putEncrypted(const std::shared_ptr<restbed::Session>& session) c
s->close(restbed::BAD_REQUEST, response);
} else {
restbed::Bytes buf(b);
std::string strJson(buf.begin(), buf.end());
std::string err;
Json::Value root;
Json::CharReaderBuilder rbuilder;
auto* char_data = reinterpret_cast<const char*>(&strJson[0]);
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
bool parsingSuccessful = reader->parse(char_data, char_data + strJson.size(), &root, &err);
Json::Reader reader;
std::string strJson(buf.begin(), buf.end());
bool parsingSuccessful = reader.parse(strJson.c_str(), root);
InfoHash to(root["to"].asString());
if (parsingSuccessful && to) {
auto value = std::make_shared<Value>(root);
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(wbuilder, value->toJson()) + "\n";
Json::FastWriter writer;
dht_->putEncrypted(key, to, value);
s->close(restbed::OK, output);
s->close(restbed::OK, writer.write(value->toJson()));
} else {
if(!parsingSuccessful)
s->close(restbed::BAD_REQUEST, "{\"err\":\"Incorrect JSON\"}");
@@ -647,11 +414,8 @@ DhtProxyServer::getFiltered(const std::shared_ptr<restbed::Session>& session) co
s->yield(restbed::OK, "", [=]( const std::shared_ptr< restbed::Session > s) {
dht_->get(infoHash, [s](std::shared_ptr<Value> v) {
// Send values as soon as we get them
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(wbuilder, v->toJson()) + "\n";
s->yield(output, [](const std::shared_ptr<restbed::Session> /*session*/){ });
Json::FastWriter writer;
s->yield(writer.write(v->toJson()), [](const std::shared_ptr<restbed::Session> /*session*/){ });
return true;
}, [s](bool /*ok* */) {
// Communication is finished
@@ -665,23 +429,5 @@ DhtProxyServer::getFiltered(const std::shared_ptr<restbed::Session>& session) co
);
}
void
DhtProxyServer::removeClosedListeners(bool testSession)
{
// clean useless listeners
std::lock_guard<std::mutex> lock(lockListener_);
auto listener = currentListeners_.begin();
while (listener != currentListeners_.end()) {
auto cancel = testSession ? dht_ && listener->session->is_closed() : static_cast<bool>(dht_);
if (cancel) {
dht_->cancelListen(listener->hash, std::move(listener->token.get()));
// Remove listener if unused
listener = currentListeners_.erase(listener);
} else {
++listener;
}
}
}
}
#endif //OPENDHT_PROXY_SERVER
+160 -187
View File
@@ -1,8 +1,7 @@
/*
* Copyright (C) 2014-2017 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>
* 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
@@ -21,10 +20,6 @@
#include "dhtrunner.h"
#include "securedht.h"
#if OPENDHT_PROXY_CLIENT
#include "dht_proxy_client.h"
#endif
#ifndef _WIN32
#include <unistd.h>
#else
@@ -89,28 +84,20 @@ DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config
{
if (running)
return;
startNetwork(local4, local6);
auto dht = std::unique_ptr<DhtInterface>(new Dht(s4, s6, SecureDht::getConfig(config.dht_config)));
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config));
#if OPENDHT_PROXY_CLIENT
config_ = config;
#endif
enableProxy(not config.proxy_server.empty());
if (rcv_thread.joinable())
rcv_thread.join();
running = true;
#if OPENDHT_PROXY_CLIENT
config_.dht_config = config.dht_config;
config_.threaded = config.threaded;
#endif //OPENDHT_PROXY_CLIENT
doRun(local4, local6, config.dht_config);
if (not config.threaded)
return;
dht_thread = std::thread([this, local4, local6]() {
dht_thread = std::thread([this]() {
while (running) {
std::unique_lock<std::mutex> lk(dht_mtx);
time_point wakeup;
try {
wakeup = loop_();
} catch (const dht::SocketException& e) {
startNetwork(local4, local6);
}
auto wakeup = loop_();
cv.wait_until(lk, wakeup, [this]() {
if (not running)
return true;
@@ -136,8 +123,7 @@ DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config
void
DhtRunner::shutdown(ShutdownCallback cb) {
#if OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->shutdown(cb);
dht_via_proxy_->shutdown(cb);
#endif
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) mutable {
@@ -149,16 +135,15 @@ DhtRunner::shutdown(ShutdownCallback cb) {
void
DhtRunner::join()
{
running_network = false;
running = false;
cv.notify_all();
bootstrap_cv.notify_all();
if (dht_thread.joinable())
dht_thread.join();
if (bootstrap_thread.joinable())
bootstrap_thread.join();
if (rcv_thread.joinable())
rcv_thread.join();
if (bootstrap_thread.joinable())
bootstrap_thread.join();
{
std::lock_guard<std::mutex> lck(storage_mtx);
@@ -170,6 +155,8 @@ DhtRunner::join()
resetDht();
status4 = NodeStatus::Disconnected;
status6 = NodeStatus::Disconnected;
bound4 = {};
bound6 = {};
}
}
@@ -200,17 +187,17 @@ DhtRunner::getNodeId() const
std::pair<size_t, size_t>
DhtRunner::getStoreSize() const {
std::lock_guard<std::mutex> lck(dht_mtx);
if (!dht_)
if (!activeDht())
return {};
return dht_->getStoreSize();
return activeDht()->getStoreSize();
}
void
DhtRunner::setStorageLimit(size_t limit) {
std::lock_guard<std::mutex> lck(dht_mtx);
if (!dht_)
if (!activeDht())
throw std::runtime_error("dht is not running");
return dht_->setStorageLimit(limit);
return activeDht()->setStorageLimit(limit);
}
std::vector<NodeExport>
@@ -218,38 +205,27 @@ DhtRunner::exportNodes() const {
std::lock_guard<std::mutex> lck(dht_mtx);
if (!dht_)
return {};
return dht_->exportNodes();
return activeDht()->exportNodes();
}
std::vector<ValuesExport>
DhtRunner::exportValues() const {
std::lock_guard<std::mutex> lck(dht_mtx);
if (!dht_)
if (!activeDht())
return {};
return dht_->exportValues();
return activeDht()->exportValues();
}
void
DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
dht_->setLoggers(std::forward<LogMethod>(error), std::forward<LogMethod>(warn), std::forward<LogMethod>(debug));
#if OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLoggers(std::forward<LogMethod>(error), std::forward<LogMethod>(warn), std::forward<LogMethod>(debug));
#endif
activeDht()->setLoggers(std::forward<LogMethod>(error), std::forward<LogMethod>(warn), std::forward<LogMethod>(debug));
}
void
DhtRunner::setLogFilter(const InfoHash& f) {
std::lock_guard<std::mutex> lck(dht_mtx);
activeDht()->setLogFilter(f);
if (dht_)
dht_->setLogFilter(f);
#if OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLogFilter(f);
#endif
}
void
@@ -261,7 +237,7 @@ DhtRunner::registerType(const ValueType& type) {
void
DhtRunner::importValues(const std::vector<ValuesExport>& values) {
std::lock_guard<std::mutex> lck(dht_mtx);
dht_->importValues(values);
activeDht()->importValues(values);
}
unsigned
@@ -348,18 +324,15 @@ void
DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method) {
std::lock_guard<std::mutex> lck(dht_mtx);
#if OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
dht_via_proxy_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
#endif
if (dht_)
dht_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
dht_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
}
time_point
DhtRunner::loop_()
{
auto dht = activeDht();
if (not dht)
if (!activeDht())
return {};
decltype(pending_ops) ops {};
@@ -370,7 +343,7 @@ DhtRunner::loop_()
std::move(pending_ops) : std::move(pending_ops_prio);
}
while (not ops.empty()) {
ops.front()(*dht);
ops.front()(*activeDht());
ops.pop();
}
@@ -385,15 +358,15 @@ DhtRunner::loop_()
for (const auto& pck : received) {
auto& buf = pck.first;
auto& from = pck.second;
wakeup = dht->periodic(buf.data(), buf.size()-1, from);
wakeup = activeDht()->periodic(buf.data(), buf.size()-1, from);
}
received.clear();
} else {
wakeup = dht->periodic(nullptr, 0, nullptr, 0);
wakeup = activeDht()->periodic(nullptr, 0, nullptr, 0);
}
NodeStatus nstatus4 = dht->getStatus(AF_INET);
NodeStatus nstatus6 = dht->getStatus(AF_INET6);
NodeStatus nstatus4 = activeDht()->getStatus(AF_INET);
NodeStatus nstatus6 = activeDht()->getStatus(AF_INET6);
if (nstatus4 != status4 || nstatus6 != status6) {
status4 = nstatus4;
status6 = nstatus6;
@@ -437,13 +410,12 @@ int bindSocket(const SockAddr& addr, SockAddr& bound)
}
void
DhtRunner::startNetwork(const SockAddr sin4, const SockAddr sin6)
DhtRunner::doRun(const SockAddr& sin4, const SockAddr& sin6, SecureDht::Config config)
{
running_network = false;
if (rcv_thread.joinable())
rcv_thread.join();
s4 = -1;
s6 = -1;
resetDht();
int s4 = -1,
s6 = -1;
bound4 = {};
if (sin4)
@@ -455,10 +427,23 @@ DhtRunner::startNetwork(const SockAddr sin4, const SockAddr sin6)
s6 = bindSocket(sin6, bound6);
#endif
running_network = true;
rcv_thread = std::thread([this]() {
auto dht = std::unique_ptr<DhtInterface>(
new Dht(s4, s6, SecureDht::getConfig(config))
);
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config));
#if OPENDHT_PROXY_CLIENT
if (!dht_via_proxy_) {
auto dht_via_proxy = std::unique_ptr<DhtInterface>(
new DhtProxyClient(config_.proxy_server)
);
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
}
#endif
rcv_thread = std::thread([this,s4,s6]() {
try {
while (running_network) {
while (true) {
struct timeval tv {/*.tv_sec = */0, /*.tv_usec = */250000};
fd_set readfds;
@@ -476,7 +461,7 @@ DhtRunner::startNetwork(const SockAddr sin4, const SockAddr sin6)
}
}
if (not running_network)
if(!running)
break;
if(rc > 0) {
@@ -506,10 +491,6 @@ DhtRunner::startNetwork(const SockAddr sin4, const SockAddr sin6)
close(s4);
if (s6 >= 0)
close(s6);
s4 = -1;
s6 = -1;
bound4 = {};
bound6 = {};
});
}
@@ -547,29 +528,29 @@ DhtRunner::listen(InfoHash hash, GetCallback vcb, Value::Filter f, Where w)
auto ret_token = std::make_shared<std::promise<size_t>>();
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
auto tokenbGlobal = listener_token_++;
Listener listener {};
listener.hash = hash;
listener.f = std::move(f);
listener.w = std::move(w);
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals){
if (not vcb(vals)) {
#if OPENDHT_PROXY_CLIENT
cancelListen(hash, tokenbGlobal);
#endif
return false;
}
return true;
};
#if OPENDHT_PROXY_CLIENT
if (use_proxy)
listener.tokenProxyDht = dht.listen(hash, listener.gcb, listener.f, listener.w);
pending_ops.emplace([=](SecureDht&) mutable {
auto tokenProxy = 0, tokenClassic = 0;
if (!use_proxy)
tokenClassic = dht_->listen(hash, vcb, std::move(f), std::move(w));
else
tokenProxy = dht_via_proxy_->listen(hash, vcb, std::move(f), std::move(w));
#else
pending_ops.emplace([=](SecureDht& dht) mutable {
auto tokenClassic = dht.listen(hash, vcb, std::move(f), std::move(w));
auto tokenProxy = 0;
#endif
listener.tokenClassicDht = dht.listen(hash, listener.gcb, listener.f, listener.w);
listeners_.emplace(tokenbGlobal, std::move(listener));
ret_token->set_value(tokenbGlobal);
auto listener = std::unique_ptr<Listener>(new Listener());
listener->globalToken = listener_token_;
listener->tokenClassicDht = tokenClassic;
listener->tokenProxyDht = tokenProxy;
listener->gcb = vcb;
listener->hash = hash;
listener->f = f;
listener->w = w;
this->listeners_.emplace_back(std::move(listener));
ret_token->set_value(listener_token_);
listener_token_++;
});
}
cv.notify_all();
@@ -585,22 +566,33 @@ DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Wher
void
DhtRunner::cancelListen(InfoHash h, size_t token)
{
std::lock_guard<std::mutex> lck(storage_mtx);
{
#if OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(token);
auto it = listeners_.begin();
for (; it != listeners_.end(); ++it) {
auto& listener = *it;
if (listener->globalToken == token) {
break;
}
}
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
#else
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
#endif // OPENDHT_PROXY_CLIENT
std::lock_guard<std::mutex> lck(storage_mtx);
#if OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto& listener = *it;
if (listener->tokenClassicDht != 0) {
dht_->cancelListen(h, listener->tokenClassicDht);
}
if (listener->tokenProxyDht != 0) {
dht_via_proxy_->cancelListen(h, listener->tokenProxyDht);
}
#else
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
#endif // OPENDHT_PROXY_CLIENT
});
}
cv.notify_all();
}
@@ -767,6 +759,30 @@ DhtRunner::tryBootstrapContinuously()
});
}
std::vector<SockAddr>
DhtRunner::getAddrInfo(const std::string& host, const std::string& service)
{
std::vector<SockAddr> ips {};
if (host.empty())
return ips;
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
addrinfo* info = nullptr;
int rc = getaddrinfo(host.c_str(), service.c_str(), &hints, &info);
if(rc != 0)
throw std::invalid_argument(std::string("Error: `") + host + ":" + service + "`: " + gai_strerror(rc));
addrinfo* infop = info;
while (infop) {
ips.emplace_back(infop->ai_addr, infop->ai_addrlen);
infop = infop->ai_next;
}
freeaddrinfo(info);
return ips;
}
void
DhtRunner::bootstrap(const std::string& host, const std::string& service)
{
@@ -848,13 +864,12 @@ DhtRunner::findCertificate(InfoHash hash, std::function<void(const std::shared_p
}
void
DhtRunner::resetDht()
{
listeners_.clear();
DhtRunner::resetDht() {
#if OPENDHT_PROXY_CLIENT
dht_via_proxy_.reset();
#endif // OPENDHT_PROXY_CLIENT
use_proxy? dht_via_proxy_.reset() : dht_.reset();
#else
dht_.reset();
#endif // OPENDHT_PROXY_CLIENT
}
SecureDht*
@@ -867,98 +882,56 @@ DhtRunner::activeDht() const
#endif // OPENDHT_PROXY_CLIENT
}
void
DhtRunner::enableProxy(bool proxify)
{
#if OPENDHT_PROXY_CLIENT
if (dht_via_proxy_) {
dht_via_proxy_->shutdown({});
void
DhtRunner::enableProxy(bool proxify) {
if (!dht_via_proxy_) {
auto dht_via_proxy = std::unique_ptr<DhtInterface>(
new DhtProxyClient(config_.proxy_server)
);
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
}
if (proxify) {
// Init the proxy client
auto dht_via_proxy = std::unique_ptr<DhtInterface>(
new DhtProxyClient([this]{
if (config_.threaded) {
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht&) mutable {});
}
cv.notify_all();
}
}, config_.proxy_server, config_.push_node_id)
);
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
#if OPENDHT_PUSH_NOTIFICATIONS
if (not pushToken_.empty())
dht_via_proxy_->setPushNotificationToken(pushToken_);
#endif
dht_via_proxy_->startProxy(config_.proxy_server);
// add current listeners
for (auto& l: listeners_)
l.second.tokenProxyDht = dht_via_proxy_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w);
for (auto& listener: listeners_) {
auto tokenProxy = dht_via_proxy_->listen(listener->hash, listener->gcb, std::move(listener->f), std::move(listener->w));
listener->tokenProxyDht = tokenProxy;
}
// and use it
use_proxy = proxify;
} else {
use_proxy = proxify;
std::lock_guard<std::mutex> lck(storage_mtx);
if (not listeners_.empty()) {
pending_ops.emplace([this](SecureDht& /*dht*/) mutable {
if (not dht_)
return;
for (auto& l : listeners_) {
if (not l.second.tokenClassicDht) {
l.second.tokenClassicDht = dht_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w);
}
}
});
loop_(); // Restart the classic DHT.
// We doesn't need to maintain the connection with the proxy.
// Delete it
dht_via_proxy_->shutdown({});
// update all proxyToken for all proxyListener
auto it = listeners_.begin();
for (; it != listeners_.end(); ++it) {
auto& listener = *it;
if (listener->tokenClassicDht == 0) {
pending_ops.emplace([it](SecureDht& dht) mutable {
auto& listener = *it;
auto token = dht.listen(listener->hash, listener->gcb, std::move(listener->f), std::move(listener->w));
listener->tokenClassicDht = token;
});
}
listener->tokenProxyDht = 0;
}
}
#else
if (proxify)
std::cerr << "DHT proxy requested but OpenDHT built without proxy support." << std::endl;
#endif
}
#endif // OPENDHT_PROXY_CLIENT
#if OPENDHT_PROXY_SERVER
void
DhtRunner::forwardAllMessages(bool forward)
{
#if OPENDHT_PROXY_SERVER
#if OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->forwardAllMessages(forward);
dht_via_proxy_->forwardAllMessages(forward);
#endif // OPENDHT_PROXY_CLIENT
if (dht_)
dht_->forwardAllMessages(forward);
dht_->forwardAllMessages(forward);
}
#endif // OPENDHT_PROXY_SERVER
}
/**
* Updates the push notification device token
*/
void
DhtRunner::setPushNotificationToken(const std::string& token) {
#if OPENDHT_PROXY_CLIENT && OPENDHT_PUSH_NOTIFICATIONS
pushToken_ = token;
if (dht_via_proxy_)
dht_via_proxy_->setPushNotificationToken(token);
#endif
}
void
DhtRunner::pushNotificationReceived(const std::map<std::string, std::string>& data) const
{
#if OPENDHT_PROXY_CLIENT && OPENDHT_PUSH_NOTIFICATIONS
if (dht_via_proxy_)
dht_via_proxy_->pushNotificationReceived(data);
#endif
}
void
DhtRunner::resubscribe(unsigned token)
{
#if OPENDHT_PROXY_CLIENT && OPENDHT_PUSH_NOTIFICATIONS
if (dht_via_proxy_)
dht_via_proxy_->resubscribe(token);
#endif
}
}
+4 -2
View File
@@ -27,12 +27,14 @@ namespace dht {
* Foreign nodes asking for updates about an InfoHash.
*/
struct Listener {
size_t sid;
time_point time;
Query query;
Listener(time_point t, Query&& q) : time(t), query(std::move(q)) {}
Listener(size_t sid, time_point t, Query&& q) : sid(sid), time(t), query(std::move(q)) {}
void refresh(time_point t, Query&& q) {
void refresh(size_t s, time_point t, Query&& q) {
sid = s;
time = t;
query = std::move(q);
}
+4 -9
View File
@@ -126,10 +126,8 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
: ntoken(std::move(msg.token)), values(std::move(msg.values)), fields(std::move(msg.fields)),
nodes4(std::move(msg.nodes4)), nodes6(std::move(msg.nodes6)) {}
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, const int& s, const int& s6)
: myid(zeroes), DHT_LOG(log), scheduler(scheduler), dht_socket(s), dht_socket6(s6)
{}
NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, const int& s, const int& s6, Logger& log, Scheduler& scheduler,
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler) : myid(zeroes), DHT_LOG(log), scheduler(scheduler) {}
NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, int s, int s6, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError) onError,
decltype(NetworkEngine::onNewNode) onNewNode,
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
@@ -498,7 +496,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
sendPong(from, msg->tid);
break;
case MessageType::FindNode: {
//DHT_LOG.d(msg->target, node->id, "[node %s] got 'find' request for %s (%d)", node->toString().c_str(), msg->target.toString().c_str(), msg->want);
DHT_LOG.d(msg->target, node->id, "[node %s] got 'find' request for %s (%d)", node->toString().c_str(), msg->target.toString().c_str(), msg->want);
++in_stats.find;
RequestAnswer answer = onFindNode(node, msg->target, msg->want);
auto nnodes = bufferNodes(from.getFamily(), msg->target, msg->want, answer.nodes4, answer.nodes6);
@@ -506,7 +504,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
case MessageType::GetValues: {
//DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'get' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'get' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
++in_stats.get;
RequestAnswer answer = onGetValues(node, msg->info_hash, msg->want, msg->query);
auto nnodes = bufferNodes(from.getFamily(), msg->info_hash, msg->want, answer.nodes4, answer.nodes6);
@@ -591,9 +589,6 @@ NetworkEngine::send(const char *buf, size_t len, int flags, const SockAddr& addr
if (sendto(s, buf, len, flags, addr.get(), addr.getLength()) == -1) {
int err = errno;
DHT_LOG.e("Can't send message to %s: %s", addr.toString().c_str(), strerror(err));
if (err == EPIPE) {
throw SocketException(EPIPE);
}
return err;
}
return 0;
+5 -4
View File
@@ -30,10 +30,11 @@ constexpr std::chrono::minutes Node::NODE_EXPIRE_TIME;
constexpr std::chrono::minutes Node::NODE_GOOD_TIME;
constexpr std::chrono::seconds Node::MAX_RESPONSE_TIME;
Node::Node(const InfoHash& id, const SockAddr& addr, bool client)
: id(id), addr(addr), is_client(client), sockets_()
{
thread_local crypto::random_device rd {};
crypto::random_device rd;
transaction_id = std::uniform_int_distribution<Tid>{1}(rd);
}
@@ -133,18 +134,18 @@ Node::openSocket(SocketCb&& cb)
if (++transaction_id == 0)
transaction_id = 1;
auto sock = std::make_shared<Socket>(std::move(cb));
auto sock = Socket(std::move(cb));
auto s = sockets_.emplace(transaction_id, std::move(sock));
if (not s.second)
s.first->second = std::move(sock);
return transaction_id;
}
Sp<Socket>
Socket*
Node::getSocket(Tid id)
{
auto it = sockets_.find(id);
return it == sockets_.end() ? nullptr : it->second;
return it == sockets_.end() ? nullptr : &it->second;
}
void
+128 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 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
@@ -74,7 +74,6 @@ struct Dht::SearchNode {
time_point last_get_reply {time_point::min()}; /* last time received valid token */
bool candidate {false}; /* A search node is candidate if the search is/was synced and this
node is a new candidate for inclusion. */
Sp<Scheduler::Job> syncJob {};
SearchNode() : node() {}
SearchNode(const SearchNode&) = delete;
@@ -94,17 +93,11 @@ struct Dht::SearchNode {
/**
* Can we use this node to listen/announce now ?
*/
bool isSynced(const time_point& now) const {
bool isSynced(time_point now) const {
return not node->isExpired() and
not token.empty() and last_get_reply >= now - Node::NODE_EXPIRE_TIME;
}
time_point getSyncTime(const time_point& now) const {
if (node->isExpired() or token.empty())
return now;
return last_get_reply + Node::NODE_EXPIRE_TIME;
}
/**
* Could a particular "get" request be sent to this node now ?
*
@@ -428,6 +421,8 @@ struct Dht::Search {
done = true;
}
time_point getUpdateTime(time_point now) const;
bool isAnnounced(Value::Id id) const;
bool isListening(time_point now) const;
@@ -465,6 +460,26 @@ struct Dht::Search {
return count;
}
/**
* Returns the time of the next "announce" event for this search,
* or time_point::max() if no such event is planned.
* Only makes sense when the search is synced.
*/
time_point getAnnounceTime(time_point now) const;
/**
* Returns the time of the next "listen" event for this search,
* or time_point::max() if no such event is planned.
* Only makes sense when the search is synced.
*/
time_point getListenTime(time_point now) const;
/**
* Returns the time of the next event for this search,
* or time_point::max() if no such event is planned.
*/
time_point getNextStepTime(time_point now) const;
/**
* Removes a node which have been expired for at least
* NODE::NODE_EXPIRE_TIME minutes. The search for an expired node starts
@@ -706,6 +721,36 @@ Dht::Search::isDone(const Get& get) const
return true;
}
time_point
Dht::Search::getUpdateTime(time_point now) const
{
time_point ut = time_point::max();
const auto last_get = getLastGetTime();
unsigned i = 0, t = 0, d = 0;
const auto solicited_nodes = currentlySolicitedNodeCount();
for (const auto& sn : nodes) {
if (sn.node->isExpired() or (sn.candidate and t >= TARGET_NODES))
continue;
auto pending = sn.pendingGet();
if (sn.last_get_reply < std::max(now - Node::NODE_EXPIRE_TIME, last_get) or pending) {
// not isSynced
if (not pending and solicited_nodes < MAX_REQUESTED_SEARCH_NODES)
ut = std::min(ut, now);
if (not sn.candidate)
d++;
} else
ut = std::min(ut, sn.last_get_reply + Node::NODE_EXPIRE_TIME);
t++;
if (not sn.candidate and ++i == TARGET_NODES)
break;
}
if (not callbacks.empty() and d == 0)
// If all synced/updated but some callbacks remain, step now to clear them
return now;
return ut;
}
bool
Dht::Search::isAnnounced(Value::Id id) const
{
@@ -745,4 +790,78 @@ Dht::Search::isListening(time_point now) const
return i;
}
time_point
Dht::Search::getAnnounceTime(time_point now) const
{
if (nodes.empty())
return time_point::max();
time_point ret {time_point::max()};
for (const auto& a : announce) {
if (!a.value) continue;
unsigned i = 0, t = 0;
for (const auto& n : nodes) {
if (not n.isSynced(now) or (n.candidate and t >= TARGET_NODES))
continue;
ret = std::min(ret, n.getAnnounceTime(a.value->id));
t++;
if (not n.candidate and ++i == TARGET_NODES)
break;
}
}
return ret;
}
time_point
Dht::Search::getListenTime(time_point now) const
{
if (listeners.empty())
return time_point::max();
time_point listen_time {time_point::max()};
unsigned i = 0, t = 0;
for (const auto& sn : nodes) {
if (not sn.isSynced(now) or (sn.candidate and t >= LISTEN_NODES))
continue;
for (auto& l : listeners)
listen_time = std::min(listen_time, sn.getListenTime(l.second.query));
t++;
if (not sn.candidate and ++i == LISTEN_NODES)
break;
}
return listen_time;
}
time_point
Dht::Search::getNextStepTime(time_point now) const
{
auto next_step = time_point::max();
if (expired or done)
return next_step;
auto ut = getUpdateTime(now);
if (ut != time_point::max()) {
//std::cout << id.toString() << " IPv" << (af==AF_INET?"4":"6") << " update time in " << print_dt(ut - now) << " s" << std::endl;
next_step = std::min(next_step, ut);
}
if (isSynced(now))
{
auto at = getAnnounceTime(now);
if (at != time_point::max()) {
//std::cout << id.toString() << " IPv" << (af==AF_INET?"4":"6") << " announce time in " << print_dt(at - now) << " s" << std::endl;
next_step = std::min(next_step, at);
}
auto lt = getListenTime(now);
if (lt != time_point::max()) {
//std::cout << id.toString() << " IPv" << (af==AF_INET?"4":"6") << " listen time in " << print_dt(lt - now) << " s" << std::endl;
next_step = std::min(next_step, lt);
}
}
return next_step;
}
}
+2 -3
View File
@@ -1,8 +1,7 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* 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
@@ -277,7 +276,7 @@ SecureDht::get(const InfoHash& id, GetCallback cb, DoneCallback donecb, Value::F
}
size_t
SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter f, Where w)
SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter&& f, Where&& w)
{
return dht_->listen(id, getCallbackFilter(cb, std::forward<Value::Filter>(f)), {}, std::forward<Where>(w));
}
-26
View File
@@ -27,8 +27,6 @@
namespace dht {
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
std::vector<SockAddr>
SockAddr::resolve(const std::string& host, const std::string& service)
{
@@ -141,30 +139,6 @@ SockAddr::isPrivate() const
}
}
bool
SockAddr::isMappedIPv4() const
{
if (getFamily() != AF_INET6)
return false;
const uint8_t* addr6 = reinterpret_cast<const uint8_t*>(&getIPv6().sin6_addr);
return std::equal(MAPPED_IPV4_PREFIX.begin(), MAPPED_IPV4_PREFIX.end(), addr6);
}
SockAddr
SockAddr::getMappedIPv4() const
{
if (not isMappedIPv4())
return *this;
SockAddr ret;
ret.setFamily(AF_INET);
ret.setPort(getPort());
auto addr6 = reinterpret_cast<const uint8_t*>(&getIPv6().sin6_addr);
auto addr4 = reinterpret_cast<uint8_t*>(&ret.getIPv4().sin_addr);
addr6 += MAPPED_IPV4_PREFIX.size();
std::copy_n(addr6, sizeof(in_addr), addr4);
return ret;
}
bool operator==(const SockAddr& a, const SockAddr& b) {
return a.equals(b);
}
+2 -2
View File
@@ -22,7 +22,7 @@
#include "default_types.h"
#include "securedht.h" // print certificate ID
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#if OPENDHT_PROXY_SERVER
#include "base64.h"
#endif //OPENDHT_PROXY_SERVER
@@ -172,7 +172,7 @@ Value::msgpack_unpack_body(const msgpack::object& o)
}
}
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#if OPENDHT_PROXY_SERVER
Value::Value(Json::Value& json)
{
try {
+37 -94
View File
@@ -1,9 +1,8 @@
/*
* Copyright (C) 2014-2017 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>
* Author: 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
@@ -60,24 +59,14 @@ void print_help() {
#if OPENDHT_PROXY_SERVER
std::cout << std::endl << "Operations with the proxy:" << std::endl
#if OPENDHT_PUSH_NOTIFICATIONS
<< " pst [port] <pushServer> Start the proxy interface on port." << std::endl
#else
<< " pst [port] Start the proxy interface on port." << std::endl
#endif // OPENDHT_PUSH_NOTIFICATIONS
<< " psp [port] Stop the proxy interface on port." << std::endl;
<< " pst [port] Start the proxy interface on port." << std::endl
<< " psp [port] Stop the proxy interface on port." << std::endl;
#endif //OPENDHT_PROXY_SERVER
#if OPENDHT_PROXY_CLIENT
std::cout << std::endl << "Operations with the proxy:" << std::endl
#if OPENDHT_PUSH_NOTIFICATIONS
<< " stt [server_address] <device_key> Start the proxy client." << std::endl
<< " rs [token] Resubscribe to opendht." << std::endl
<< " rp [push_notification] Inject a push notification in Opendht." << std::endl
#else
<< " stt [server_address] Start the proxy client." << std::endl
#endif // OPENDHT_PUSH_NOTIFICATIONS
<< " stp Stop the proxy client." << std::endl;
<< " stt [server_address] Start the proxy client." << std::endl
<< " stp Stop the proxy client." << std::endl;
#endif //OPENDHT_PROXY_CLIENT
std::cout << std::endl << "Operations on the DHT:" << std::endl
@@ -90,20 +79,14 @@ void print_help() {
<< " s <key> <str> Put string value at <key>, signed with our generated private key." << std::endl
<< " e <key> <dest> <str> Put string value at <key>, encrypted for <dest> with its public key (if found)." << std::endl;
#ifdef OPENDHT_INDEXATION
std::cout << std::endl << "Indexation operations on the DHT:" << std::endl
<< " il <name> <key> [exact match] Lookup the index named <name> with the key <key>." << std::endl
<< " Set [exact match] to 'false' for inexact match lookup." << std::endl
<< " ii <name> <key> <value> Inserts the value <value> under the key <key> in the index named <name>." << std::endl
<< std::endl;
#endif
}
void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
#if OPENDHT_PROXY_SERVER
, std::map<in_port_t, std::unique_ptr<DhtProxyServer>>& proxies
#endif
)
void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params)
{
print_node_info(dht, params);
std::cout << " (type 'h' or 'help' for a list of possible commands)" << std::endl << std::endl;
@@ -113,9 +96,19 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
using_history();
#endif
#ifdef OPENDHT_INDEXATION
std::map<std::string, indexation::Pht> indexes;
#endif
#if OPENDHT_PROXY_SERVER
std::map<in_port_t, std::unique_ptr<DhtProxyServer>> proxies;
if (params.proxyserver != 0) {
proxies.emplace(params.proxyserver, new DhtProxyServer(dht, params.proxyserver));
}
#endif //OPENDHT_PROXY_SERVER
#if OPENDHT_PROXY_CLIENT
if (!params.proxyclient.empty()) {
dht->setProxyServer(params.proxyclient);
dht->enableProxy(true);
}
#endif //OPENDHT_PROXY_CLIENT
while (true)
{
@@ -125,7 +118,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
break;
std::istringstream iss(line);
std::string op, idstr, value, index, keystr, pushServer, deviceKey;
std::string op, idstr, value, index, keystr;
iss >> op;
if (op == "x" || op == "exit" || op == "quit") {
@@ -195,18 +188,10 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
}
#if OPENDHT_PROXY_SERVER
else if (op == "pst") {
#if OPENDHT_PUSH_NOTIFICATIONS
iss >> idstr >> pushServer;
#else
iss >> idstr;
#endif // OPENDHT_PUSH_NOTIFICATIONS
iss >> idstr;
try {
unsigned int port = std::stoi(idstr);
#if OPENDHT_PUSH_NOTIFICATIONS
proxies.emplace(port, std::unique_ptr<DhtProxyServer>(new DhtProxyServer(dht, port, pushServer)));
#else
proxies.emplace(port, std::unique_ptr<DhtProxyServer>(new DhtProxyServer(dht, port)));
#endif // OPENDHT_PUSH_NOTIFICATIONS
proxies.emplace(port, new DhtProxyServer(dht, port));
} catch (...) { }
continue;
} else if (op == "psp") {
@@ -221,26 +206,14 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
#endif //OPENDHT_PROXY_SERVER
#if OPENDHT_PROXY_CLIENT
else if (op == "stt") {
iss >> idstr;
dht->setProxyServer(idstr);
dht->enableProxy(true);
continue;
} else if (op == "stp") {
dht->enableProxy(false);
continue;
}
#if OPENDHT_PUSH_NOTIFICATIONS
else if (op == "rp") {
iss >> value;
dht->pushNotificationReceived({{"token", value}});
continue;
} else if (op == "re") {
iss >> value;
try {
unsigned token = std::stoul(value);
dht->resubscribe(token);
} catch (...) { }
continue;
}
#endif // OPENDHT_PUSH_NOTIFICATIONS
#endif //OPENDHT_PROXY_CLIENT
if (op.empty())
@@ -254,13 +227,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
}
dht::InfoHash id;
if (op == "cl") {
std::string hash, rem;
iss >> hash >> rem;
dht->cancelListen(dht::InfoHash(hash), std::stoul(rem));
}
#ifdef OPENDHT_INDEXATION
else if (op == "il" or op == "ii") {
if (op == "il" or op == "ii") {
// Pht syntax
iss >> index >> keystr;
auto new_index = std::find_if(indexes.begin(), indexes.end(),
@@ -282,7 +249,6 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
} catch (std::invalid_argument& e) { std::cout << e.what() << std::endl; }
}
}
#endif
else {
// Dht syntax
iss >> idstr;
@@ -335,8 +301,12 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
std::cout << "\t" << *value << std::endl;
return true;
}, {}, dht::Where {std::move(rem)});
auto t = token.get();
std::cout << "Listening, token: " << t << std::endl;
std::cout << "Listening, token: " << token.get() << std::endl;
}
else if (op == "cl") {
std::string rem;
iss >> rem;
dht->cancelListen(id, std::stoul(rem));
}
else if (op == "p") {
std::string v;
@@ -407,7 +377,6 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
std::cout << "Announce: " << (ok ? "success" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
});
}
#ifdef OPENDHT_INDEXATION
else if (op == "il") {
std::string exact_match;
iss >> exact_match;
@@ -453,7 +422,6 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
catch (std::invalid_argument& e) { std::cout << e.what() << std::endl; }
catch (std::out_of_range& e) { }
}
#endif
}
std::cout << std::endl << "Stopping node..." << std::endl;
@@ -474,7 +442,6 @@ main(int argc, char **argv)
print_usage();
return 0;
}
if (params.daemonize) {
daemonize();
} else if (params.service) {
@@ -484,19 +451,10 @@ main(int argc, char **argv)
dht::crypto::Identity crt {};
if (params.generate_identity) {
auto ca_tmp = dht::crypto::generateEcIdentity("DHT Node CA");
crt = dht::crypto::generateIdentity("DHT Node", ca_tmp);
crt = dht::crypto::generateEcIdentity("DHT Node", ca_tmp);
}
dht::DhtRunner::Config config;
config.dht_config.node_config.network = params.network;
config.dht_config.id = crt;
config.threaded = true;
config.proxy_server = params.proxyclient;
config.push_node_id = "dhtnode";
if (not params.proxyclient.empty())
dht->setPushNotificationToken(params.devicekey);
dht->run(params.port, config);
dht->run(params.port, crt, true, params.network);
if (params.log) {
if (params.syslog or (params.daemonize and params.logfile.empty()))
@@ -512,26 +470,11 @@ main(int argc, char **argv)
dht->bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str());
}
#if OPENDHT_PROXY_SERVER
std::map<in_port_t, std::unique_ptr<DhtProxyServer>> proxies;
#endif
if (params.proxyserver != 0) {
#if OPENDHT_PROXY_SERVER
proxies.emplace(params.proxyserver, std::unique_ptr<DhtProxyServer>(new DhtProxyServer(dht, params.proxyserver, params.pushserver)));
#else
std::cerr << "DHT proxy server requested but OpenDHT built without proxy server support." << std::endl;
exit(EXIT_FAILURE);
#endif
}
if (params.daemonize or params.service)
if (params.daemonize or params.service) {
while (runner.wait());
else
cmd_loop(dht, params
#if OPENDHT_PROXY_SERVER
, proxies
#endif
);
} else {
cmd_loop(dht, params);
}
} catch(const std::exception&e) {
std::cerr << std::endl << e.what() << std::endl;
-13
View File
@@ -2,7 +2,6 @@
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* 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
@@ -90,7 +89,6 @@ std::map<std::string, std::string> parseStringMap(std::string mapString) {
return map;
}
#ifdef OPENDHT_INDEXATION
dht::indexation::Pht::Key createPhtKey(std::map<std::string, std::string> pht_key_str_map) {
dht::indexation::Pht::Key pht_key;
for (auto f : pht_key_str_map) {
@@ -99,7 +97,6 @@ dht::indexation::Pht::Key createPhtKey(std::map<std::string, std::string> pht_ke
}
return pht_key;
}
#endif
bool isInfoHash(const dht::InfoHash& h) {
if (not h) {
@@ -124,8 +121,6 @@ struct dht_params {
std::pair<std::string, std::string> bootstrap {};
in_port_t proxyserver {0};
std::string proxyclient {};
std::string pushserver {};
std::string devicekey {};
};
static const constexpr struct option long_options[] = {
@@ -141,8 +136,6 @@ static const constexpr struct option long_options[] = {
{"syslog", no_argument , nullptr, 'L'},
{"proxyserver",required_argument, nullptr, 'S'},
{"proxyclient",required_argument, nullptr, 'C'},
{"pushserver", required_argument, nullptr, 'P'},
{"devicekey", required_argument, nullptr, 'D'},
{nullptr, 0 , nullptr, 0}
};
@@ -168,15 +161,9 @@ parseArgs(int argc, char **argv) {
std::cout << "Invalid port: " << port_arg << std::endl;
}
break;
case 'P':
params.pushserver = optarg;
break;
case 'C':
params.proxyclient = optarg;
break;
case 'D':
params.devicekey = optarg;
break;
case 'n':
params.network = strtoul(optarg, nullptr, 0);
break;