mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-08 12:28:42 +00:00
Compare commits
364
Commits
crypto
...
proxy_restinio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29fe7d5f92 | ||
|
|
459217b6d6 | ||
|
|
d8aa94c8f5 | ||
|
|
8a88ca94db | ||
|
|
a72ddfdb03 | ||
|
|
e7b03e4d53 | ||
|
|
baf43d96ff | ||
|
|
0f9df9a62b | ||
|
|
630112601c | ||
|
|
b0500af062 | ||
|
|
6c985e8fda | ||
|
|
9c1e55279c | ||
|
|
593d024f51 | ||
|
|
a6e57d95d6 | ||
|
|
846f495202 | ||
|
|
6f603bfc0a | ||
|
|
9c106f9efe | ||
|
|
ff288fb4a3 | ||
|
|
17ff4c0224 | ||
|
|
45a2c6dadb | ||
|
|
477ff59e91 | ||
|
|
a001e0cafd | ||
|
|
ac63527e0b | ||
|
|
4b3d8d1231 | ||
|
|
d04a741d5e | ||
|
|
ac2b7deda8 | ||
|
|
c8b08b5ed1 | ||
|
|
f556987e47 | ||
|
|
2daf36c97e | ||
|
|
2a2555f0c2 | ||
|
|
bdfb0148e4 | ||
|
|
01be4d2eb8 | ||
|
|
93f7251805 | ||
|
|
a8718242cd | ||
|
|
297a23fb1f | ||
|
|
0d641161e8 | ||
|
|
27b3c0d47e | ||
|
|
149b33ef57 | ||
|
|
150e62de0b | ||
|
|
89bdfce840 | ||
|
|
bce41ecd69 | ||
|
|
4374d206ab | ||
|
|
b64820af59 | ||
|
|
0e509318bb | ||
|
|
bcc2baa94a | ||
|
|
bbed9d530d | ||
|
|
5a3612be98 | ||
|
|
8202c1f7d7 | ||
|
|
a200b0e14c | ||
|
|
bd32edc6c5 | ||
|
|
d0d3ef7394 | ||
|
|
712da15ae2 | ||
|
|
fcdc997d29 | ||
|
|
cf18effebb | ||
|
|
b8c2ff8a11 | ||
|
|
1fad1b9ce3 | ||
|
|
117fedb641 | ||
|
|
422f5a6c45 | ||
|
|
51a42aa2c8 | ||
|
|
be0baefee8 | ||
|
|
2ac5157ab8 | ||
|
|
fbe8834e04 | ||
|
|
89ff131750 | ||
|
|
feb498305f | ||
|
|
b00f56c94a | ||
|
|
2067cb052f | ||
|
|
51aeaeaeab | ||
|
|
c0bb8f065c | ||
|
|
126318956a | ||
|
|
9014c0a7bb | ||
|
|
728782921c | ||
|
|
d438d4ef1b | ||
|
|
2959709462 | ||
|
|
4a26168248 | ||
|
|
9c348b1df4 | ||
|
|
7e7654d1ae | ||
|
|
69ee1d212a | ||
|
|
21ec9129c3 | ||
|
|
b7185fa87c | ||
|
|
54acd67a1f | ||
|
|
045de8602c | ||
|
|
390fa48700 | ||
|
|
0d08f0d356 | ||
|
|
738424b1ae | ||
|
|
d123d8f768 | ||
|
|
a20a48506d | ||
|
|
063a2b4860 | ||
|
|
829d365475 | ||
|
|
11e6671e60 | ||
|
|
6fe473d3cc | ||
|
|
9f493b9572 | ||
|
|
2164c5ddc7 | ||
|
|
a57a4d55e8 | ||
|
|
b98cc78b42 | ||
|
|
789d41ff07 | ||
|
|
632403875c | ||
|
|
bc2737cdc9 | ||
|
|
0c6bfde1c5 | ||
|
|
cfeeaf7950 | ||
|
|
e31ebfea32 | ||
|
|
07efe8c76e | ||
|
|
5c78bf386d | ||
|
|
86088b043b | ||
|
|
fad8bb1631 | ||
|
|
9a56c099a1 | ||
|
|
8298c0c868 | ||
|
|
971f590941 | ||
|
|
1813d83273 | ||
|
|
e87d164f0b | ||
|
|
b9604807ea | ||
|
|
9f12b44179 | ||
|
|
0772d5435c | ||
|
|
368ee9e22e | ||
|
|
dd56bdd8e2 | ||
|
|
71b36e0643 | ||
|
|
61b43759df | ||
|
|
96e12e88c3 | ||
|
|
8da933c01a | ||
|
|
20c0069867 | ||
|
|
8942e0d00e | ||
|
|
bc760f9348 | ||
|
|
59702190a7 | ||
|
|
cb3e94d0be | ||
|
|
ab7b8f6027 | ||
|
|
6e5231047b | ||
|
|
777505434c | ||
|
|
18c3161261 | ||
|
|
1060038bdf | ||
|
|
9d427a6a80 | ||
|
|
f1dbac2aff | ||
|
|
a63c5d172b | ||
|
|
9c6de8cc16 | ||
|
|
fe9de44867 | ||
|
|
4bfd6bb545 | ||
|
|
120c017399 | ||
|
|
7fc7597564 | ||
|
|
f8d62dc6a7 | ||
|
|
fc3686d817 | ||
|
|
a692f7fbe2 | ||
|
|
cb349d9cf6 | ||
|
|
6266f88cd5 | ||
|
|
0a3320e2c8 | ||
|
|
d6ad67d8e2 | ||
|
|
19d0aa55f7 | ||
|
|
941e53425f | ||
|
|
10971f700f | ||
|
|
2e7767d192 | ||
|
|
baf811bfe9 | ||
|
|
76f0672e63 | ||
|
|
330ad8ed12 | ||
|
|
3252e6daa3 | ||
|
|
07599239a6 | ||
|
|
eac61678f4 | ||
|
|
078c1198b0 | ||
|
|
3d525030b9 | ||
|
|
3733fc2890 | ||
|
|
c40f35fa06 | ||
|
|
13661929d1 | ||
|
|
4e934f8902 | ||
|
|
125a05a5fc | ||
|
|
868c114bcb | ||
|
|
f0acc3e735 | ||
|
|
171e2b130b | ||
|
|
cb5a261b82 | ||
|
|
feb8bd0d4f | ||
|
|
3955368c01 | ||
|
|
b841ff1b83 | ||
|
|
7a04c0eb66 | ||
|
|
fe1659bd2f | ||
|
|
b90e14edd6 | ||
|
|
9e3e9e65e6 | ||
|
|
1c3132e0ef | ||
|
|
f3e304e661 | ||
|
|
2545282624 | ||
|
|
52c413f056 | ||
|
|
ab082543ea | ||
|
|
ff6be81929 | ||
|
|
bd994384f0 | ||
|
|
598e38dbf4 | ||
|
|
b1a35b82a2 | ||
|
|
e4516772ee | ||
|
|
c7844fc320 | ||
|
|
c7e2483160 | ||
|
|
37b12c114d | ||
|
|
77bd34ad9c | ||
|
|
44490bd9ca | ||
|
|
ca01568824 | ||
|
|
2b259639d2 | ||
|
|
84d322e428 | ||
|
|
6d5e3d8cd2 | ||
|
|
b56518f258 | ||
|
|
d807af3951 | ||
|
|
5f393490a5 | ||
|
|
efe869fe42 | ||
|
|
a31cecdeac | ||
|
|
4a4becdbec | ||
|
|
eef2838a12 | ||
|
|
a520657fac | ||
|
|
29003700db | ||
|
|
b143bc459d | ||
|
|
4d6e5ab877 | ||
|
|
248d2e3f73 | ||
|
|
0692bd9bc9 | ||
|
|
7f48c4808b | ||
|
|
32a443a1d8 | ||
|
|
6d0fcba3b5 | ||
|
|
76e2efb19b | ||
|
|
bbe1b9233f | ||
|
|
7558ca0dca | ||
|
|
38141322f1 | ||
|
|
6c5ea125ca | ||
|
|
d0362e58e0 | ||
|
|
1b3a40f345 | ||
|
|
38d854e6f4 | ||
|
|
e0241ccfbd | ||
|
|
d4311925b4 | ||
|
|
9aa56dd464 | ||
|
|
ec3b259ead | ||
|
|
332cab10ef | ||
|
|
85f2b618c7 | ||
|
|
bcf18fda53 | ||
|
|
6b78a4cad6 | ||
|
|
66d3a8aeaa | ||
|
|
958cb250a3 | ||
|
|
6a5724a868 | ||
|
|
11ac84de54 | ||
|
|
f65e8c1a1f | ||
|
|
c2fdf6ae92 | ||
|
|
91a81f64ac | ||
|
|
17b772e6cc | ||
|
|
75738ac28b | ||
|
|
84a2d771c1 | ||
|
|
f6273f9efc | ||
|
|
5881c91510 | ||
|
|
e09c55ca42 | ||
|
|
c737e4690e | ||
|
|
35a9d1f612 | ||
|
|
0f3396cd66 | ||
|
|
98cd6cc61e | ||
|
|
092cb9551e | ||
|
|
a2bbca792c | ||
|
|
5ec72e213e | ||
|
|
0f51115f44 | ||
|
|
683a111726 | ||
|
|
0fd4fed537 | ||
|
|
18aa6ddb7b | ||
|
|
0a436e17b0 | ||
|
|
763ffddf51 | ||
|
|
ef82652a1e | ||
|
|
4f03a5c64e | ||
|
|
5257ac314f | ||
|
|
0580a4e7dd | ||
|
|
fd1f2cd0e4 | ||
|
|
af940c63b1 | ||
|
|
15da502354 | ||
|
|
b7a9a52f97 | ||
|
|
6e10756e28 | ||
|
|
aad4ad03cf | ||
|
|
3d1e055c7b | ||
|
|
b02e9cfff7 | ||
|
|
453db29058 | ||
|
|
a8ba536d44 | ||
|
|
a238183031 | ||
|
|
73827cd34d | ||
|
|
876190a392 | ||
|
|
7fe321e4fc | ||
|
|
7f7075ca9a | ||
|
|
9b9f12d87e | ||
|
|
26ad6de3a4 | ||
|
|
ae91f8bd55 | ||
|
|
28eeee24ba | ||
|
|
671c55a01d | ||
|
|
a4f2e6efdd | ||
|
|
60831ee898 | ||
|
|
98dbe1cba7 | ||
|
|
6c705e525f | ||
|
|
96347d83e1 | ||
|
|
01d8e513a1 | ||
|
|
b5921b0d9d | ||
|
|
8ee7883c53 | ||
|
|
4240820463 | ||
|
|
7ebbf17f37 | ||
|
|
6821e5bd96 | ||
|
|
c4ec1e78e0 | ||
|
|
e86d717e81 | ||
|
|
db2b48d2af | ||
|
|
2b938110fd | ||
|
|
c647b19e91 | ||
|
|
8cd14646a6 | ||
|
|
d80aab9399 | ||
|
|
9b881d4e95 | ||
|
|
b4c3c2cba0 | ||
|
|
4519a23996 | ||
|
|
1ac4e08f45 | ||
|
|
5e92777702 | ||
|
|
4401e47002 | ||
|
|
215b44ca3b | ||
|
|
379fdae212 | ||
|
|
1e10e28fd7 | ||
|
|
dccdb84836 | ||
|
|
71599da8ea | ||
|
|
f418b3651f | ||
|
|
313f54c840 | ||
|
|
cdb721ade4 | ||
|
|
57ea09808e | ||
|
|
fec5a6ede7 | ||
|
|
5f8e9d9480 | ||
|
|
311a8981fc | ||
|
|
04850e1701 | ||
|
|
a30f1b8032 | ||
|
|
41f8b06743 | ||
|
|
1c74c2207f | ||
|
|
9319bec7b8 | ||
|
|
e5f2a6eef5 | ||
|
|
55f6c847b8 | ||
|
|
00cc4ebe28 | ||
|
|
aa93db4fa6 | ||
|
|
683570a3da | ||
|
|
43559577f6 | ||
|
|
ba2e179abe | ||
|
|
a5d29c904c | ||
|
|
989f32eb56 | ||
|
|
b66fa73c56 | ||
|
|
1ca181db1d | ||
|
|
1f3bf697c3 | ||
|
|
a1f8cc906c | ||
|
|
35c6a57526 | ||
|
|
39e69f813c | ||
|
|
8045c2cbf2 | ||
|
|
79a2f4280f | ||
|
|
769ce45740 | ||
|
|
75a14d3608 | ||
|
|
d523e9f259 | ||
|
|
3a3933e6d5 | ||
|
|
70f09ded3f | ||
|
|
824a1bf5fa | ||
|
|
e5b56cc0a5 | ||
|
|
36cf70f2a7 | ||
|
|
459c1344aa | ||
|
|
c0e376e15a | ||
|
|
71b9672b96 | ||
|
|
086f37a71a | ||
|
|
87e76a5e4e | ||
|
|
7f0a5dfda3 | ||
|
|
6d7f8004bf | ||
|
|
8168c39b63 | ||
|
|
d0fdbe5340 | ||
|
|
c7604fbb8d | ||
|
|
56773baa98 | ||
|
|
e6cf67c575 | ||
|
|
00ebc5e2bf | ||
|
|
ccef94c11b | ||
|
|
0066be49b9 | ||
|
|
592ed4ee90 | ||
|
|
353a6f9db6 | ||
|
|
7ebad7d3c5 | ||
|
|
14f6e6e5f3 | ||
|
|
9ce5b30931 | ||
|
|
92979fa96a | ||
|
|
0c1e7d2763 | ||
|
|
14a744f6cd | ||
|
|
3b26684a87 | ||
|
|
0a764ee440 | ||
|
|
7dda5a3d5a |
No files matched your search
@@ -0,0 +1 @@
|
||||
Checks: '-*,clang-diagnostic-*,performance-*,bugprone-*,llvm-*,clang-analyzer-*,misc-*,-llvm-namespace-comment,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-llvm-header-guard,-llvm-include-order,-bugprone-suspicious-string-compare'
|
||||
@@ -46,6 +46,15 @@ Makefile.in
|
||||
.kdev4/
|
||||
*.kdev4
|
||||
|
||||
# VSCode
|
||||
.vscode/*
|
||||
|
||||
# Eclipse CDT
|
||||
.cproject
|
||||
.project
|
||||
.autotools
|
||||
language.settings.xml
|
||||
|
||||
# Python
|
||||
*.pyc
|
||||
*.stamp
|
||||
|
||||
+53
-27
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required (VERSION 3.1)
|
||||
project (opendht)
|
||||
set (opendht_VERSION_MAJOR 1)
|
||||
set (opendht_VERSION_MINOR 8.0)
|
||||
set (opendht_VERSION_MINOR 10.0)
|
||||
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
|
||||
set (PACKAGE_VERSION ${opendht_VERSION})
|
||||
set (VERSION "${opendht_VERSION}")
|
||||
@@ -16,10 +16,10 @@ option (OPENDHT_SYSTEMD "Install systemd module" OFF)
|
||||
option (OPENDHT_ARGON2 "Use included argon2 sources" OFF)
|
||||
option (OPENDHT_LTO "Build with LTO" OFF)
|
||||
option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF)
|
||||
option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restbed and jsoncpp" OFF)
|
||||
option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restinio and jsoncpp" OFF)
|
||||
option (OPENDHT_PUSH_NOTIFICATIONS "Enable push notifications support" OFF)
|
||||
option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" OFF)
|
||||
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restbed and jsoncpp" OFF)
|
||||
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF)
|
||||
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
|
||||
option (OPENDHT_TESTS "Add unit tests executable" OFF)
|
||||
|
||||
@@ -58,14 +58,20 @@ if (Jsoncpp_FOUND)
|
||||
endif()
|
||||
|
||||
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
|
||||
find_package(Restbed REQUIRED)
|
||||
find_package(Restinio REQUIRED)
|
||||
if (Restinio_FOUND)
|
||||
find_library(FMT_LIBRARY fmt)
|
||||
add_library(fmt SHARED IMPORTED)
|
||||
find_library(HTTP_PARSER_LIBRARY http_parser)
|
||||
add_library(http_parser SHARED IMPORTED)
|
||||
endif()
|
||||
if (NOT Jsoncpp_FOUND)
|
||||
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Build flags
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
set (CMAKE_CXX_STANDARD_REQUIRED on)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -pedantic-errors -fvisibility=hidden")
|
||||
if (OPENDHT_SANITIZE)
|
||||
@@ -75,6 +81,7 @@ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif ()
|
||||
add_definitions(-DPACKAGE_VERSION="${opendht_VERSION}")
|
||||
if (OPENDHT_LOG)
|
||||
add_definitions(-DOPENDHT_LOG=true)
|
||||
else ()
|
||||
@@ -99,8 +106,8 @@ endif ()
|
||||
if (Nettle_INCLUDE_DIRS)
|
||||
include_directories (SYSTEM "${Nettle_INCLUDE_DIRS}")
|
||||
endif ()
|
||||
if (Restbed_INCLUDE_DIR)
|
||||
include_directories (SYSTEM "${Restbed_INCLUDE_DIR}")
|
||||
if (Restinio_INCLUDE_DIR)
|
||||
include_directories (SYSTEM "${Restinio_INCLUDE_DIR}")
|
||||
endif ()
|
||||
if (Jsoncpp_INCLUDE_DIRS)
|
||||
include_directories (SYSTEM "${Jsoncpp_INCLUDE_DIRS}")
|
||||
@@ -149,6 +156,9 @@ list (APPEND opendht_SOURCES
|
||||
src/securedht.cpp
|
||||
src/dhtrunner.cpp
|
||||
src/log.cpp
|
||||
src/peer_discovery.cpp
|
||||
src/network_utils.cpp
|
||||
src/thread_pool.cpp
|
||||
)
|
||||
|
||||
list (APPEND opendht_HEADERS
|
||||
@@ -172,9 +182,16 @@ list (APPEND opendht_HEADERS
|
||||
include/opendht/securedht.h
|
||||
include/opendht/log.h
|
||||
include/opendht/log_enable.h
|
||||
include/opendht/peer_discovery.h
|
||||
include/opendht/thread_pool.h
|
||||
include/opendht/network_utils.h
|
||||
include/opendht.h
|
||||
)
|
||||
|
||||
if (OPENDHT_PYTHON)
|
||||
message("Indexation enabled since it is required for Python support")
|
||||
set(OPENDHT_INDEX ON)
|
||||
endif()
|
||||
if (OPENDHT_INDEX)
|
||||
list (APPEND opendht_SOURCES src/indexation/pht.cpp)
|
||||
list (APPEND opendht_HEADERS include/opendht/indexation/pht.h)
|
||||
@@ -182,11 +199,9 @@ if (OPENDHT_INDEX)
|
||||
endif()
|
||||
|
||||
if (OPENDHT_PROXY_SERVER)
|
||||
add_definitions(-DOPENDHT_PROXY_SERVER=true)
|
||||
add_definitions(-DOPENDHT_PROXY_SERVER)
|
||||
if (OPENDHT_PROXY_SERVER_IDENTITY)
|
||||
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY=true)
|
||||
else ()
|
||||
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY=false)
|
||||
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY)
|
||||
endif()
|
||||
list (APPEND opendht_HEADERS
|
||||
include/opendht/dht_proxy_server.h
|
||||
@@ -194,31 +209,29 @@ if (OPENDHT_PROXY_SERVER)
|
||||
list (APPEND opendht_SOURCES
|
||||
src/dht_proxy_server.cpp
|
||||
)
|
||||
else ()
|
||||
add_definitions(-DENABLE_PROXY_SERVER=false)
|
||||
endif ()
|
||||
|
||||
if (OPENDHT_PROXY_CLIENT)
|
||||
add_definitions(-DOPENDHT_PROXY_CLIENT=true)
|
||||
add_definitions(-DOPENDHT_PROXY_CLIENT)
|
||||
list (APPEND opendht_HEADERS
|
||||
include/opendht/dht_proxy_client.h
|
||||
)
|
||||
list (APPEND opendht_SOURCES
|
||||
src/dht_proxy_client.cpp
|
||||
)
|
||||
else ()
|
||||
add_definitions(-DOPENDHT_PROXY_CLIENT=false)
|
||||
endif ()
|
||||
|
||||
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
|
||||
if (OPENDHT_PUSH_NOTIFICATIONS)
|
||||
message("Using push notification")
|
||||
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS=true)
|
||||
else ()
|
||||
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS=false)
|
||||
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS)
|
||||
endif ()
|
||||
list (APPEND opendht_HEADERS
|
||||
include/opendht/proxy.h
|
||||
include/opendht/http.h
|
||||
)
|
||||
list (APPEND opendht_SOURCES
|
||||
src/http.cpp
|
||||
)
|
||||
endif ()
|
||||
|
||||
@@ -252,8 +265,9 @@ if (OPENDHT_STATIC)
|
||||
target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
|
||||
endif ()
|
||||
target_link_libraries(opendht-static
|
||||
PRIVATE ${Restbed_LIBRARY} ${argon2_LIBRARIES}
|
||||
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES} ${Jsoncpp_LIBRARIES})
|
||||
PRIVATE ${argon2_LIBRARIES}
|
||||
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
|
||||
${Jsoncpp_LIBRARIES} ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY})
|
||||
install (TARGETS opendht-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
|
||||
endif ()
|
||||
|
||||
@@ -271,7 +285,12 @@ if (OPENDHT_SHARED)
|
||||
target_link_libraries(opendht PRIVATE ${argon2_LIBRARIES})
|
||||
target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
|
||||
endif ()
|
||||
target_link_libraries(opendht PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES} ${Restbed_LIBRARY} ${Jsoncpp_LIBRARIES})
|
||||
target_link_libraries(opendht
|
||||
PUBLIC ${CMAKE_THREAD_LIBS_INIT}
|
||||
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
|
||||
${Jsoncpp_LIBRARIES}
|
||||
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY})
|
||||
|
||||
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
|
||||
endif ()
|
||||
|
||||
@@ -304,16 +323,22 @@ install (EXPORT opendht DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht FILE o
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht)
|
||||
|
||||
# Unit tests
|
||||
IF(OPENDHT_TESTS)
|
||||
if (OPENDHT_TESTS)
|
||||
FIND_PACKAGE(Cppunit REQUIRED)
|
||||
# unit testing
|
||||
list (APPEND test_FILES
|
||||
tests/infohashtester.h
|
||||
tests/infohashtester.cpp
|
||||
tests/valuetester.h
|
||||
tests/valuetester.cpp
|
||||
tests/cryptotester.h
|
||||
tests/cryptotester.cpp
|
||||
tests/dhtrunnertester.h
|
||||
tests/dhtrunnertester.cpp
|
||||
tests/peerdiscoverytester.h
|
||||
tests/peerdiscoverytester.cpp
|
||||
tests/threadpooltester.h
|
||||
tests/threadpooltester.cpp
|
||||
)
|
||||
if (OPENDHT_PROXY_SERVER AND OPENDHT_PROXY_CLIENT)
|
||||
list (APPEND test_FILES
|
||||
@@ -325,16 +350,17 @@ IF(OPENDHT_TESTS)
|
||||
tests/tests_runner.cpp
|
||||
${test_FILES}
|
||||
)
|
||||
target_include_directories(opendht_unit_tests SYSTEM PRIVATE ${CPPUNIT_INCLUDE_DIRS})
|
||||
if (OPENDHT_SHARED)
|
||||
TARGET_LINK_LIBRARIES(opendht_unit_tests opendht)
|
||||
target_link_libraries(opendht_unit_tests opendht)
|
||||
else ()
|
||||
TARGET_LINK_LIBRARIES(opendht_unit_tests opendht-static)
|
||||
target_link_libraries(opendht_unit_tests opendht-static)
|
||||
endif ()
|
||||
TARGET_LINK_LIBRARIES(opendht_unit_tests
|
||||
target_link_libraries(opendht_unit_tests
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CPPUNIT_LIBRARIES}
|
||||
${GNUTLS_LIBRARIES}
|
||||
)
|
||||
enable_testing()
|
||||
add_test(TEST opendht_unit_tests)
|
||||
ENDIF()
|
||||
endif()
|
||||
+22
-22
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -21,32 +21,32 @@
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}</ProjectGuid>
|
||||
<RootNamespace>dhtchat</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@@ -86,14 +86,14 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -102,14 +102,14 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -120,16 +120,16 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -140,16 +140,16 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;$(ProjectDir)contrib\build\include;$(ProjectDir)contrib\build\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>crypt32.lib;Argon2Ref.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)contrib\build\lib\x64;$(ProjectDir)..\..\lib\x64;$(ProjectDir)vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
|
||||
+22
-22
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -21,32 +21,32 @@
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}</ProjectGuid>
|
||||
<RootNamespace>dhtnode</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@@ -86,14 +86,14 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -102,14 +102,14 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -120,16 +120,16 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -140,16 +140,16 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;$(ProjectDir)contrib\build\include;$(ProjectDir)contrib\build\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>crypt32.lib;Argon2Ref.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)contrib\build\lib\x64;$(ProjectDir)..\..\lib\x64;$(ProjectDir)vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
|
||||
+22
-22
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -21,32 +21,32 @@
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{78443BCD-4689-4007-A246-F8F34B27F561}</ProjectGuid>
|
||||
<RootNamespace>dhtscanner</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@@ -86,14 +86,14 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -102,14 +102,14 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -120,16 +120,16 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -140,16 +140,16 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;$(ProjectDir)contrib\build\include;$(ProjectDir)contrib\build\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>crypt32.lib;Argon2Ref.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)contrib\build\lib\x64;$(ProjectDir)..\..\lib\x64;$(ProjectDir)vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
|
||||
+50
-35
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -19,6 +19,17 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\dht_proxy_client.cpp" />
|
||||
<ClCompile Include="..\src\network_utils.cpp" />
|
||||
<ClCompile Include="..\src\op_cache.cpp" />
|
||||
<ClCompile Include="..\src\peer_discovery.cpp" />
|
||||
<ClCompile Include="..\src\rng.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\thread_pool.cpp" />
|
||||
<ClCompile Include="wingetopt.c" />
|
||||
<ClCompile Include="..\src\base64.cpp" />
|
||||
<ClCompile Include="..\src\callbacks.cpp" />
|
||||
@@ -39,6 +50,8 @@
|
||||
<ClCompile Include="..\src\value.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\network_utils.h" />
|
||||
<ClInclude Include="..\src\thread_pool.h" />
|
||||
<ClInclude Include="unistd.h" />
|
||||
<ClInclude Include="wingetopt.h" />
|
||||
<ClInclude Include="..\include\opendht.h" />
|
||||
@@ -75,32 +88,32 @@
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{711397CE-E5D5-467D-9457-8716C047E50C}</ProjectGuid>
|
||||
<RootNamespace>opendht</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@@ -123,33 +136,34 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
|
||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>opendhtd</TargetName>
|
||||
<TargetName>libopendht</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
|
||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>opendht</TargetName>
|
||||
<TargetName>libopendht</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
<TargetName>opendhtd</TargetName>
|
||||
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
|
||||
<TargetName>libopendht</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
<TargetName>opendht</TargetName>
|
||||
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
|
||||
<TargetName>libopendht</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<SuppressStartupBanner>false</SuppressStartupBanner>
|
||||
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>mkdir $(OutDir)\include
|
||||
@@ -160,7 +174,7 @@ copy ..\include\opendht\*.h $(OutDir)\include\opendht
|
||||
copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
</PostBuildEvent>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -168,10 +182,11 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>mkdir $(OutDir)\include
|
||||
@@ -182,7 +197,7 @@ copy ..\include\opendht\*.h $(OutDir)\include\opendht
|
||||
copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
</PostBuildEvent>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -192,11 +207,11 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<ProgramDataBaseFileName>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
@@ -211,7 +226,7 @@ copy ..\include\opendht\*.h $(OutDir)\include\opendht
|
||||
copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
</PostBuildEvent>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -222,11 +237,11 @@ 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>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
@@ -241,7 +256,7 @@ copy ..\include\opendht\*.h $(OutDir)\include\opendht
|
||||
copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
</PostBuildEvent>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
|
||||
<AdditionalLibraryDirectories>
|
||||
</AdditionalLibraryDirectories>
|
||||
|
||||
@@ -53,12 +53,26 @@
|
||||
<Filter>Source Files\indexation</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="wingetopt.c" />
|
||||
<ClCompile Include="..\src\rng.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\op_cache.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\dht_proxy_client.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\peer_discovery.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\network_utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\thread_pool.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</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>
|
||||
@@ -139,6 +153,24 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="unistd.h" />
|
||||
<ClInclude Include="wingetopt.h" />
|
||||
<ClInclude Include="..\include\opendht\def.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\net.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\parsed_message.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\opendht\sockaddr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\network_utils.h">
|
||||
<Filter>Header Files\opendht</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\thread_pool.h">
|
||||
<Filter>Header Files\opendht</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<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++14 Distributed Hash Table implementation.
|
||||
|
||||
OpenDHT provides an easy to use distributed in-memory data store.
|
||||
Every node in the network can read and write values to the store.
|
||||
@@ -14,7 +14,7 @@ Values are distributed over the network, with redundancy.
|
||||
* High resilience to network disruption
|
||||
* Public key cryptography layer providing optional data signature and encryption (using GnuTLS)
|
||||
* IPv4 and IPv6 support
|
||||
* Clean and powerful C++11 map API
|
||||
* Clean and powerful C++14 map API
|
||||
* Python 3 bindings
|
||||
* REST API
|
||||
|
||||
@@ -27,13 +27,13 @@ Build instructions: <https://github.com/savoirfairelinux/opendht/wiki/Build-the-
|
||||
|
||||
#### How-to build a simple client app
|
||||
```bash
|
||||
g++ main.cpp -std=c++11 -lopendht -lgnutls
|
||||
g++ main.cpp -std=c++14 -lopendht -lgnutls
|
||||
```
|
||||
|
||||
## Examples
|
||||
### C++ example
|
||||
The `tools` directory includes simple example programs :
|
||||
* `dhtnode`, a command line tool, mostly used for debuging, allowing to perform operations supported by the library (get, put etc.) with text values.
|
||||
* `dhtnode`, a command line tool, allowing to run a DHT node and perform operations supported by the library (get, put etc.) with text values.
|
||||
* `dhtchat`, a very simple IM client working over the dht.
|
||||
|
||||
Example program launching a DHT node, connecting to the network and performing some basic operations:
|
||||
@@ -96,7 +96,7 @@ for r in results:
|
||||
- msgpack-c 1.2+, used for data serialization.
|
||||
- GnuTLS 3.3+, used for cryptographic operations.
|
||||
- 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) restinio used for the REST API.
|
||||
- (optional) jsoncpp 1.7.4-3+, used for the REST API.
|
||||
- Build tested with GCC 5.2+ (GNU/Linux, Windows with MinGW), Clang/LLVM (GNU/Linux, Android, macOS, iOS).
|
||||
- Build tested with Microsoft Visual Studio 2015
|
||||
@@ -106,7 +106,7 @@ for r in results:
|
||||
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
|
||||
|
||||
## License
|
||||
Copyright (C) 2014-2018 Savoir-faire Linux Inc.
|
||||
Copyright (C) 2014-2019 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.
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
if(NOT Restbed_FOUND)
|
||||
find_path (Restbed_INCLUDE_DIR restbed
|
||||
HINTS
|
||||
"/usr/include"
|
||||
"/usr/local/include"
|
||||
"/opt/local/include")
|
||||
find_library(Restbed_LIBRARY restbed
|
||||
HINTS ${Restbed_ROOT_DIR} PATH_SUFFIXES lib)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Restbed DEFAULT_MSG Restbed_LIBRARY Restbed_INCLUDE_DIR)
|
||||
if (Restbed_INCLUDE_DIR)
|
||||
set(Restbed_FOUND TRUE)
|
||||
set(Restbed_LIBRARIES ${Restbed_LIBRARY})
|
||||
set(Restbed_INCLUDE_DIRS ${Restbed_INCLUDE_DIR})
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,14 @@
|
||||
# header-only does not produce a library
|
||||
if(NOT Restinio_FOUND)
|
||||
find_path (Restinio_INCLUDE_DIR restinio
|
||||
HINTS
|
||||
"/usr/include"
|
||||
"/usr/local/include"
|
||||
"/opt/local/include")
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Restinio DEFAULT_MSG Restinio_INCLUDE_DIR)
|
||||
if (Restinio_INCLUDE_DIR)
|
||||
set(Restinio_FOUND TRUE)
|
||||
set(Restinio_INCLUDE_DIRS ${Restinio_INCLUDE_DIR})
|
||||
endif()
|
||||
endif()
|
||||
+11
-18
@@ -1,6 +1,6 @@
|
||||
dnl define macros
|
||||
m4_define([opendht_major_version], 1)
|
||||
m4_define([opendht_minor_version], 8)
|
||||
m4_define([opendht_minor_version], 10)
|
||||
m4_define([opendht_patch_version], 0)
|
||||
m4_define([opendht_version],
|
||||
[opendht_major_version.opendht_minor_version.opendht_patch_version])
|
||||
@@ -142,8 +142,12 @@ AS_IF([test "x$have_jsoncpp" = "xyes"], [
|
||||
])
|
||||
|
||||
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
|
||||
AC_CHECK_LIB(restbed, exit,, AC_MSG_ERROR([Missing restbed files]))
|
||||
LDFLAGS="${LDFLAGS} -lrestbed"
|
||||
PKG_CHECK_MODULES([Asio], [fmt >= 1.12.2])
|
||||
PKG_CHECK_MODULES([Fmt], [fmt >= 5.3.0])
|
||||
# http_parser has no pkgconfig, instead we check with:
|
||||
AC_CHECK_LIB(http_parser, exit,, AC_MSG_ERROR([Missing HttpParser library files]))
|
||||
AC_CHECK_HEADERS([http_parser.h], [http_parser_headers=yes; break;])
|
||||
AS_IF([test "x$http_parser_headers" != "xyes"], AC_MSG_ERROR([Missing HttpParser headers files]))
|
||||
])
|
||||
|
||||
CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
|
||||
@@ -177,21 +181,10 @@ AM_COND_IF([ENABLE_TOOLS], [
|
||||
])
|
||||
])
|
||||
|
||||
AM_COND_IF(ENABLE_PROXY_SERVER,
|
||||
[CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=true"],
|
||||
[CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=false"])
|
||||
|
||||
AM_COND_IF(ENABLE_PROXY_CLIENT,
|
||||
[CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=true"],
|
||||
[CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=false"])
|
||||
|
||||
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS,
|
||||
[CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=true"],
|
||||
[CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=false"])
|
||||
|
||||
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY,
|
||||
[CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=true"],
|
||||
[CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=false"])
|
||||
AM_COND_IF(ENABLE_PROXY_SERVER, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER"], [])
|
||||
AM_COND_IF(ENABLE_PROXY_CLIENT, [CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT"], [])
|
||||
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS, [CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS"], [])
|
||||
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY"], [])
|
||||
|
||||
AM_COND_IF([HAVE_DOXYGEN], [
|
||||
AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])
|
||||
|
||||
+57
-35
@@ -1,22 +1,24 @@
|
||||
.TH DHTNODE 1 2016-07-29
|
||||
|
||||
.TH DHTNODE 1 2019-06-08
|
||||
.SH NAME
|
||||
.B dhtnode
|
||||
- a simple OpenDHT command line node runner.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B dhtnode [-h]
|
||||
|
||||
.B dhtnode [-v [-l \fIlogfile\fP]] [-i] [-d] [-n \fInetwork_id\fP] [-p \fIlocal_port\fP] [-b \fIbootstrap_host\fP[:\fIport\fP]]
|
||||
|
||||
.B dhtnode
|
||||
[\fB\-h\fR]
|
||||
[\fB\-v\fR [\fB\-l\fR \fIlogfile\fR] [\fB\-L\fR]]
|
||||
[\fB\-i\fR [\fB\-\-save\-identity\fR \fIfile\fR]]
|
||||
[\fB\-d\fR] [\fB\-s\fR]
|
||||
[\fB\-n\fR \fInetwork_id\fR]
|
||||
[\fB\-p\fR \fIlocal_port\fR]
|
||||
[\fB\-b\fR \fIbootstrap_host\fR[:\fIport\fR]]
|
||||
[\fB\-\-certificate\fR \fIfile\fR]
|
||||
[\fB\-\-privkey\fR \fIfile\fR]
|
||||
[\fB\-\-privkey\-password\fR \fIpassword\fR]
|
||||
[\fB\-\-proxyserver\fR \fIport\fR]
|
||||
[\fB\-\-proxyclient\fR \fIserver\fR]
|
||||
.SH DESCRIPTION
|
||||
|
||||
This program runs a simple OpenDHT node in an interactive way. If you rather
|
||||
want to run the node in daemon mode, option \fB'-d'\fP is provided. When running
|
||||
in the interactive shell, you benefit from the readline capabilities for writing
|
||||
your commands such as command history. Here are the available commands in the
|
||||
interactive shell:
|
||||
|
||||
Runs an OpenDHT node, with a CLI (default) or as a daemon (with \fB'-d'\fP or \fB'-s'\fP).
|
||||
Commands available in the interactive shell are:
|
||||
.EE
|
||||
h, help Print this help message.
|
||||
q, quit Quit the program.
|
||||
@@ -37,43 +39,63 @@ interactive shell:
|
||||
private key.
|
||||
e [key] [dest] [str] Put string value at [key], encrypted for [dest] with
|
||||
its public key (if found).
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
\fB-h\fP
|
||||
\fB\-h\fP
|
||||
Prints some help.
|
||||
|
||||
.TP
|
||||
\fB-v\fP
|
||||
Enable the verbose mode (log to stdout by default)
|
||||
|
||||
\fB\-v\fP
|
||||
Enable the verbose mode (log to stdout/stderr by default)
|
||||
.TP
|
||||
\fB-l\fP \fIlog_file\fP
|
||||
Write log to file instead of stdout
|
||||
|
||||
\fB\-l\fP \fIlog_file\fP
|
||||
Write log to file instead of stdout/stderr
|
||||
.TP
|
||||
\fB-i\fP
|
||||
\fB\-L\fP
|
||||
Write log to syslog instead of stdout/stderr
|
||||
.TP
|
||||
\fB\-i\fP
|
||||
Generate cryptographic identity for the node.
|
||||
|
||||
.TP
|
||||
\fB-d\fP
|
||||
\fB\-\-save\-identity\fP \fIfile\fP
|
||||
Save generated identity (certificate and private key) to given file prefix.
|
||||
.TP
|
||||
\fB\-\-certificate\fP \fIfile\fP
|
||||
Load identity certificate from given file.
|
||||
.TP
|
||||
\fB\-\-privkey\fP \fIfile\fP
|
||||
Load identity private key from given file.
|
||||
.TP
|
||||
\fB\-\-privkey\-password\fP \fIpassword\fP
|
||||
Password to use for private key encryption or decryption (optional).
|
||||
.TP
|
||||
\fB\-d\fP
|
||||
Run the program in daemon mode (will fork in the background).
|
||||
|
||||
.TP
|
||||
\fB-n\fP \fInetwork_id\fP
|
||||
\fB\-s\fP
|
||||
Run the program in service mode (non\-forking daemon).
|
||||
.TP
|
||||
\fB\-D\fP
|
||||
Enables multicast automatic local peer discovery.
|
||||
.TP
|
||||
\fB\-f\fP \fIfile\fP
|
||||
Specify a file path to persist/load the node state.
|
||||
.TP
|
||||
\fB\-n\fP \fInetwork_id\fP
|
||||
Specify the network id. This let you connect to distinct networks and prevents
|
||||
the merge of two different networks (available since OpenDHT v0.6.1).
|
||||
|
||||
.TP
|
||||
\fB-p\fP \fIlocal_port\fP
|
||||
Use port \fIlocal_port\fP for the program to bind to.
|
||||
|
||||
\fB\-p\fP \fIlocal_port\fP
|
||||
Use UDP port \fIlocal_port\fP for the program to bind to.
|
||||
.TP
|
||||
\fB-b\fP \fIbootstrap_host\fP[:\fIport\fP]
|
||||
\fB\-b\fP \fIbootstrap_host\fP[:\fIport\fP]
|
||||
The program needs to be given a node to connect to the network. You use this
|
||||
option to provide the ip address of that node.
|
||||
|
||||
.TP
|
||||
\fB\-\-proxyserver\fP \fIlocal_port\fP
|
||||
Run a proxy server bound to this DHT node on HTTP port \fIlocal_port\fP
|
||||
.TP
|
||||
\fB\-\-proxyclient\fP \fIserver\fP
|
||||
Run this DHT node in proxy client mode, and connect to \fIserver\fP
|
||||
.SH AUTHORS
|
||||
.TP
|
||||
Program written by
|
||||
|
||||
+39
-12
@@ -1,18 +1,45 @@
|
||||
FROM ubuntu:16.04
|
||||
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
RUN apt-get update && apt-get install -y build-essential cmake git wget libncurses5-dev libreadline-dev nettle-dev libgnutls28-dev libuv1-dev cython3 python3-dev libcppunit-dev libjsoncpp-dev libasio-dev libssl-dev python3-setuptools && apt-get clean
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential cmake git wget libncurses5-dev libreadline-dev nettle-dev \
|
||||
libgnutls28-dev libuv1-dev cython3 python3-dev libcppunit-dev libjsoncpp-dev \
|
||||
libasio-dev libssl-dev python3-setuptools \
|
||||
&& apt-get clean
|
||||
|
||||
# build restbed from sources
|
||||
RUN git clone --recursive https://github.com/corvusoft/restbed.git \
|
||||
&& cd restbed && mkdir build && cd build \
|
||||
&& cmake -DBUILD_TESTS=NO -DBUILD_EXAMPLES=NO -DBUILD_SSL=NO -DBUILD_SHARED=YES -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib .. \
|
||||
&& make -j8 install \
|
||||
&& cd .. && rm -rf restbed
|
||||
#patch for https://github.com/Stiffstream/restinio-conan-example/issues/2
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3-pip libasio-dev
|
||||
RUN pip3 install --upgrade cmake
|
||||
#install conan & add restinio remotes
|
||||
RUN pip3 install conan && \
|
||||
conan remote add stiffstream https://api.bintray.com/conan/stiffstream/public && \
|
||||
conan remote add public-conan https://api.bintray.com/conan/bincrafters/public-conan
|
||||
#setup restinio docker project
|
||||
RUN mkdir restinio-conan
|
||||
COPY conan/restinio/conanfile.txt restinio-conan/conanfile.txt
|
||||
COPY conan/restinio/conanfile.py restinio-conan/conanfile.py
|
||||
#build restinio from source
|
||||
RUN echo "*** Installing RESTinio & dependencies ***" \
|
||||
&& cd restinio-conan \
|
||||
&& conan source . \
|
||||
&& conan install -o restinio:boost_libs=none --build=missing . \
|
||||
&& conan package . -pf /usr/local \
|
||||
&& cd ../ && rm -rf restinio*
|
||||
#installing dependencies
|
||||
RUN echo "*** Installing asio & fmt dependencies ***" \
|
||||
&& cp -r ~/.conan/data/asio/*/bincrafters/stable/package/*/include/* /usr/local/include/ \
|
||||
&& cp -r ~/.conan/data/fmt/*/bincrafters/stable/package/*/lib/* /usr/local/lib/ \
|
||||
&& cp -r ~/.conan/data/fmt/*/bincrafters/stable/package/*/include/* /usr/local/include/
|
||||
#build http_parser fork
|
||||
RUN echo "*** Building http_parser dependency for custom HTTP methods ***" \
|
||||
&& git clone https://github.com/eao197/http-parser.git \
|
||||
&& cd http-parser && make -j8 && make install PREFIX=/usr \
|
||||
&& cd ../ && rm -rf restinio-conan/
|
||||
|
||||
#build msgpack from source
|
||||
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.1.5/msgpack-2.1.5.tar.gz \
|
||||
&& tar -xzf msgpack-2.1.5.tar.gz \
|
||||
&& cd msgpack-2.1.5 && mkdir build && cd build \
|
||||
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
|
||||
&& make -j8 && make install \
|
||||
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
|
||||
&& tar -xzf msgpack-2.1.5.tar.gz \
|
||||
&& cd msgpack-2.1.5 && mkdir build && cd build \
|
||||
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
|
||||
&& make -j8 && make install \
|
||||
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
|
||||
+36
-13
@@ -1,23 +1,46 @@
|
||||
FROM ubuntu:16.04
|
||||
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y llvm llvm-dev clang make cmake git wget libncurses5-dev libreadline-dev nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev libasio-dev cython3 python3-dev python3-setuptools libcppunit-dev \
|
||||
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
|
||||
&& apt-get install -y llvm llvm-dev clang make cmake git wget libncurses5-dev libreadline-dev nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev libasio-dev cython3 python3-dev python3-setuptools libcppunit-dev python3-pip \
|
||||
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
|
||||
|
||||
ENV CC cc
|
||||
ENV CXX c++
|
||||
|
||||
# build restbed from sources
|
||||
RUN git clone --recursive https://github.com/corvusoft/restbed.git \
|
||||
&& cd restbed && mkdir build && cd build \
|
||||
&& cmake -DBUILD_TESTS=NO -DBUILD_EXAMPLES=NO -DBUILD_SSL=NO -DBUILD_SHARED=YES -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib .. \
|
||||
&& make -j8 install \
|
||||
&& cd .. && rm -rf restbed
|
||||
#patch for https://github.com/Stiffstream/restinio-conan-example/issues/2
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3-pip libasio-dev
|
||||
RUN pip3 install --upgrade cmake
|
||||
#install conan & add restinio remotes
|
||||
RUN pip3 install conan && \
|
||||
conan remote add stiffstream https://api.bintray.com/conan/stiffstream/public && \
|
||||
conan remote add public-conan https://api.bintray.com/conan/bincrafters/public-conan
|
||||
#setup restinio docker project
|
||||
RUN mkdir restinio-conan
|
||||
COPY conan/restinio/conanfile.txt restinio-conan/conanfile.txt
|
||||
COPY conan/restinio/conanfile.py restinio-conan/conanfile.py
|
||||
#build restinio from source
|
||||
RUN echo "*** Installing RESTinio & dependencies ***" \
|
||||
&& cd restinio-conan \
|
||||
&& conan source . \
|
||||
&& conan install -o restinio:boost_libs=none --build=missing . \
|
||||
&& conan package . -pf /usr/local \
|
||||
&& cd ../ && rm -rf restinio*
|
||||
#installing dependencies
|
||||
RUN echo "*** Installing asio & fmt dependencies ***" \
|
||||
&& cp -r ~/.conan/data/asio/*/bincrafters/stable/package/*/include/* /usr/local/include/ \
|
||||
&& cp -r ~/.conan/data/fmt/*/bincrafters/stable/package/*/lib/* /usr/local/lib/ \
|
||||
&& cp -r ~/.conan/data/fmt/*/bincrafters/stable/package/*/include/* /usr/local/include/
|
||||
#build http_parser fork
|
||||
RUN echo "*** Building http_parser dependency for custom HTTP methods ***" \
|
||||
&& git clone https://github.com/eao197/http-parser.git \
|
||||
&& cd http-parser && make -j8 && make install PREFIX=/usr \
|
||||
&& cd ../ && rm -rf restinio-conan/
|
||||
|
||||
#build msgpack from source
|
||||
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.1.5/msgpack-2.1.5.tar.gz \
|
||||
&& tar -xzf msgpack-2.1.5.tar.gz \
|
||||
&& cd msgpack-2.1.5 && mkdir build && cd build \
|
||||
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
|
||||
&& make -j8 && make install \
|
||||
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
|
||||
&& tar -xzf msgpack-2.1.5.tar.gz \
|
||||
&& cd msgpack-2.1.5 && mkdir build && cd build \
|
||||
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
|
||||
&& make -j8 && make install \
|
||||
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
|
||||
@@ -0,0 +1,59 @@
|
||||
from conans import ConanFile, CMake, tools
|
||||
import os
|
||||
|
||||
|
||||
class SobjectizerConan(ConanFile):
|
||||
name = "restinio"
|
||||
version = "0.5.1"
|
||||
|
||||
license = "BSD-3-Clause"
|
||||
url = "https://github.com/Stiffstream/restinio-conan"
|
||||
|
||||
description = (
|
||||
"RESTinio is a header-only C++14 library that gives you "
|
||||
"an embedded HTTP/Websocket server."
|
||||
)
|
||||
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
options = {'boost_libs': ['none', 'static', 'shared']}
|
||||
default_options = {'boost_libs': 'none'}
|
||||
generators = "cmake"
|
||||
source_subfolder = "restinio"
|
||||
build_policy = "missing"
|
||||
|
||||
def requirements(self):
|
||||
self.requires.add("http-parser/2.8.1@bincrafters/stable")
|
||||
self.requires.add("fmt/5.3.0@bincrafters/stable")
|
||||
|
||||
if self.options.boost_libs == "none":
|
||||
self.requires.add("asio/1.12.2@bincrafters/stable")
|
||||
else:
|
||||
self.requires.add("boost/1.69.0@conan/stable")
|
||||
if self.options.boost_libs == "shared":
|
||||
self.options["boost"].shared = True
|
||||
else:
|
||||
self.options["boost"].shared = False
|
||||
|
||||
def source(self):
|
||||
source_url = "https://bitbucket.org/sobjectizerteam/restinio/downloads"
|
||||
tools.get("{0}/restinio-{1}.zip".format(source_url, self.version))
|
||||
extracted_dir = "restinio-" + self.version
|
||||
os.rename(extracted_dir, self.source_subfolder)
|
||||
|
||||
def _configure_cmake(self):
|
||||
cmake = CMake(self)
|
||||
cmake.definitions['RESTINIO_INSTALL'] = True
|
||||
cmake.definitions['RESTINIO_FIND_DEPS'] = False
|
||||
cmake.definitions['RESTINIO_USE_BOOST_ASIO'] = self.options.boost_libs
|
||||
cmake.configure(source_folder = self.source_subfolder + "/dev/restinio")
|
||||
return cmake
|
||||
|
||||
def package(self):
|
||||
cmake = self._configure_cmake()
|
||||
self.output.info(cmake.definitions)
|
||||
cmake.install()
|
||||
|
||||
def package_info(self):
|
||||
self.info.header_only()
|
||||
if self.options.boost_libs != "none":
|
||||
self.cpp_info.defines.append("RESTINIO_USE_BOOST_ASIO")
|
||||
@@ -0,0 +1,11 @@
|
||||
[requires]
|
||||
restinio/0.5.1@stiffstream/stable
|
||||
|
||||
[generators]
|
||||
cmake
|
||||
|
||||
[options]
|
||||
|
||||
[imports]
|
||||
bin, *.dll -> ./bin # Copies all dll files from packages bin folder to my "bin" folder
|
||||
lib, *.dylib* -> ./bin # Copies all dylib files from packages lib folder to my "bin" folder
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,10 +19,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "opendht/dhtrunner.h"
|
||||
#if OPENDHT_PROXY_SERVER
|
||||
#ifdef OPENDHT_PROXY_SERVER
|
||||
#include "opendht/dht_proxy_server.h"
|
||||
#endif
|
||||
#include "opendht/log.h"
|
||||
#include "opendht/default_types.h"
|
||||
#ifdef OPENDHT_INDEXATION
|
||||
#include "opendht/indexation/pht.h"
|
||||
|
||||
+16
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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>
|
||||
@@ -89,20 +89,23 @@ struct OPENDHT_PUBLIC NodeInfo {
|
||||
*/
|
||||
struct OPENDHT_PUBLIC Config {
|
||||
/** DHT node ID */
|
||||
InfoHash node_id;
|
||||
InfoHash node_id {};
|
||||
|
||||
/**
|
||||
* DHT network ID. A node will only talk with other nodes having
|
||||
* the same network ID.
|
||||
* Network ID 0 (default) represents the main public network.
|
||||
*/
|
||||
NetId network;
|
||||
NetId network {0};
|
||||
|
||||
/** For testing purposes only, enables bootstrap mode */
|
||||
bool is_bootstrap;
|
||||
bool is_bootstrap {false};
|
||||
|
||||
/** Makes the DHT responsible to maintain its stored values. Consumes more ressources. */
|
||||
bool maintain_storage;
|
||||
bool maintain_storage {false};
|
||||
|
||||
/** If set, the dht will load its state from this file on start and save its state in this file on shutdown */
|
||||
std::string persist_path {};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -110,8 +113,8 @@ struct OPENDHT_PUBLIC Config {
|
||||
*/
|
||||
struct OPENDHT_PUBLIC SecureDhtConfig
|
||||
{
|
||||
Config node_config;
|
||||
crypto::Identity id;
|
||||
Config node_config {};
|
||||
crypto::Identity id {};
|
||||
};
|
||||
|
||||
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
|
||||
@@ -128,8 +131,8 @@ using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::
|
||||
|
||||
typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data);
|
||||
|
||||
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
|
||||
OPENDHT_PUBLIC GetCallback bindGetCb(GetCallbackSimple cb);
|
||||
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(const GetCallbackRaw& raw_cb, void* user_data);
|
||||
OPENDHT_PUBLIC GetCallback bindGetCb(const GetCallbackSimple& cb);
|
||||
|
||||
using DoneCallback = std::function<void(bool success, const std::vector<std::shared_ptr<Node>>& nodes)>;
|
||||
typedef void (*DoneCallbackRaw)(bool, std::vector<std::shared_ptr<Node>>*, void *user_data);
|
||||
@@ -139,10 +142,10 @@ typedef bool (*FilterRaw)(const Value&, void *user_data);
|
||||
|
||||
using DoneCallbackSimple = std::function<void(bool success)>;
|
||||
|
||||
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data);
|
||||
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data);
|
||||
OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackSimple donecb);
|
||||
OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data);
|
||||
OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data);
|
||||
OPENDHT_PUBLIC Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data);
|
||||
OPENDHT_PUBLIC DoneCallback bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data);
|
||||
OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data);
|
||||
OPENDHT_PUBLIC Value::Filter bindFilterRaw(const FilterRaw& raw_filter, void* user_data);
|
||||
|
||||
}
|
||||
+55
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -66,7 +66,7 @@ using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certific
|
||||
*/
|
||||
struct OPENDHT_PUBLIC PublicKey
|
||||
{
|
||||
PublicKey() {}
|
||||
PublicKey();
|
||||
|
||||
/**
|
||||
* Takes ownership of an existing gnutls_pubkey.
|
||||
@@ -115,7 +115,9 @@ struct OPENDHT_PUBLIC PublicKey
|
||||
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
|
||||
gnutls_pubkey_t pk {};
|
||||
gnutls_digest_algorithm_t getPreferredDigest() const;
|
||||
|
||||
gnutls_pubkey_t pk {nullptr};
|
||||
private:
|
||||
PublicKey(const PublicKey&) = delete;
|
||||
PublicKey& operator=(const PublicKey&) = delete;
|
||||
@@ -186,7 +188,7 @@ class OPENDHT_PUBLIC RevocationList
|
||||
public:
|
||||
RevocationList();
|
||||
RevocationList(const Blob& b);
|
||||
RevocationList(RevocationList&& o) : crl(o.crl) { o.crl = nullptr; }
|
||||
RevocationList(RevocationList&& o) noexcept : crl(o.crl) { o.crl = nullptr; }
|
||||
~RevocationList();
|
||||
|
||||
RevocationList& operator=(RevocationList&& o) { crl = o.crl; o.crl = nullptr; return *this; }
|
||||
@@ -254,14 +256,48 @@ private:
|
||||
RevocationList& operator=(const RevocationList&) = delete;
|
||||
};
|
||||
|
||||
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
|
||||
|
||||
class OPENDHT_PUBLIC CertificateRequest {
|
||||
public:
|
||||
CertificateRequest();
|
||||
CertificateRequest(const uint8_t* data, size_t size);
|
||||
CertificateRequest(const Blob& data) : CertificateRequest(data.data(), data.size()) {}
|
||||
|
||||
CertificateRequest(CertificateRequest&& o) noexcept : request(std::move(o.request)) {
|
||||
o.request = nullptr;
|
||||
}
|
||||
CertificateRequest& operator=(CertificateRequest&& o) noexcept;
|
||||
|
||||
~CertificateRequest();
|
||||
|
||||
void setName(const std::string& name);
|
||||
void setUID(const std::string& name);
|
||||
void setAltName(NameType type, const std::string& name);
|
||||
|
||||
std::string getName() const;
|
||||
std::string getUID() const;
|
||||
|
||||
void sign(const PrivateKey& key, const std::string& password = {});
|
||||
|
||||
bool verify() const;
|
||||
|
||||
Blob pack() const;
|
||||
|
||||
gnutls_x509_crq_t get() const { return request; }
|
||||
private:
|
||||
CertificateRequest(const CertificateRequest& o) = delete;
|
||||
CertificateRequest& operator=(const CertificateRequest& o) = delete;
|
||||
gnutls_x509_crq_t request {nullptr};
|
||||
};
|
||||
|
||||
struct OPENDHT_PUBLIC Certificate {
|
||||
Certificate() {}
|
||||
Certificate() noexcept {}
|
||||
|
||||
/**
|
||||
* Take ownership of existing gnutls structure
|
||||
*/
|
||||
Certificate(gnutls_x509_crt_t crt) : cert(crt) {}
|
||||
Certificate(gnutls_x509_crt_t crt) noexcept : cert(crt) {}
|
||||
|
||||
Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
|
||||
|
||||
@@ -392,8 +428,6 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
/** Read certificate issuer User ID (UID) */
|
||||
std::string getIssuerUID() const;
|
||||
|
||||
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
|
||||
|
||||
/** Read certificate alternative names */
|
||||
std::vector<std::pair<NameType, std::string>> getAltNames() const;
|
||||
|
||||
@@ -431,7 +465,8 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
void addRevocationList(RevocationList&&);
|
||||
void addRevocationList(std::shared_ptr<RevocationList>);
|
||||
|
||||
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false);
|
||||
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false);
|
||||
static Certificate generate(const CertificateRequest& request, const Identity& ca);
|
||||
|
||||
gnutls_x509_crt_t getCopy() const {
|
||||
if (not cert)
|
||||
@@ -472,7 +507,9 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
return {crts, crls};
|
||||
}
|
||||
|
||||
gnutls_x509_crt_t cert {};
|
||||
gnutls_digest_algorithm_t getPreferredDigest() const;
|
||||
|
||||
gnutls_x509_crt_t cert {nullptr};
|
||||
std::shared_ptr<Certificate> issuer {};
|
||||
private:
|
||||
Certificate(const Certificate&) = delete;
|
||||
@@ -500,10 +537,10 @@ struct OPENDHT_PUBLIC TrustList
|
||||
};
|
||||
|
||||
TrustList();
|
||||
TrustList(TrustList&& o) : trust(std::move(o.trust)) {
|
||||
TrustList(TrustList&& o) noexcept : trust(std::move(o.trust)) {
|
||||
o.trust = nullptr;
|
||||
}
|
||||
TrustList& operator=(TrustList&& o);
|
||||
TrustList& operator=(TrustList&& o) noexcept;
|
||||
~TrustList();
|
||||
void add(const Certificate& crt);
|
||||
void add(const RevocationList& crl);
|
||||
@@ -513,7 +550,7 @@ struct OPENDHT_PUBLIC TrustList
|
||||
private:
|
||||
TrustList(const TrustList& o) = delete;
|
||||
TrustList& operator=(const TrustList& o) = delete;
|
||||
gnutls_x509_trust_list_t trust;
|
||||
gnutls_x509_trust_list_t trust {nullptr};
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -611,12 +648,13 @@ using SecureBlob = secure_vector<uint8_t>;
|
||||
* If not set, the generated certificate will be a self-signed CA.
|
||||
* @param key_length stength of the generated private key (bits).
|
||||
*/
|
||||
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
|
||||
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
|
||||
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca);
|
||||
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", const Identity& ca = {}, unsigned key_length = 4096);
|
||||
|
||||
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, Identity ca, bool is_ca);
|
||||
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", Identity ca = {});
|
||||
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca);
|
||||
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", const Identity& ca = {});
|
||||
|
||||
OPENDHT_PUBLIC void saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password = {});
|
||||
|
||||
/**
|
||||
* Performs SHA512, SHA256 or SHA1, depending on hash_length.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -38,7 +38,7 @@ class OPENDHT_PUBLIC DhtMessage : public Value::Serializable<DhtMessage>
|
||||
public:
|
||||
static const ValueType TYPE;
|
||||
|
||||
DhtMessage(std::string s = {}, Blob msg = {}) : service(s), data(msg) {}
|
||||
DhtMessage(const std::string& s = {}, const Blob& msg = {}) : service(s), data(msg) {}
|
||||
|
||||
std::string getService() const {
|
||||
return service;
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
|
||||
static bool storePolicy(InfoHash key, std::shared_ptr<Value>& value, const InfoHash& from, const SockAddr&);
|
||||
|
||||
static Value::Filter ServiceFilter(std::string s);
|
||||
static Value::Filter ServiceFilter(const std::string& s);
|
||||
|
||||
/** print value for debugging */
|
||||
friend std::ostream& operator<< (std::ostream&, const DhtMessage&);
|
||||
@@ -114,8 +114,10 @@ public:
|
||||
ImMessage() {}
|
||||
ImMessage(dht::Value::Id id, std::string&& m, long d = 0)
|
||||
: id(id), msg(std::move(m)), date(d) {}
|
||||
ImMessage(dht::Value::Id id, std::string&& dt, std::string&& m, long d = 0)
|
||||
ImMessage(dht::Value::Id id, std::string &&dt, std::string &&m, long d = 0)
|
||||
: id(id), msg(std::move(m)), datatype(std::move(dt)), date(d) {}
|
||||
ImMessage(dht::Value::Id id, std::string &&dt, std::string &&m, std::map<std::string, std::string> &&md, long d = 0)
|
||||
: id(id), msg(std::move(m)), datatype(std::move(dt)), metadatas(std::move(md)), date(d) {}
|
||||
|
||||
virtual void unpackValue(const Value& v) override {
|
||||
to = v.recipient;
|
||||
@@ -126,10 +128,11 @@ public:
|
||||
dht::Value::Id id {0};
|
||||
std::string msg;
|
||||
std::string datatype;
|
||||
std::map<std::string, std::string> metadatas;
|
||||
long date {0};
|
||||
ImStatus status {ImStatus::NONE};
|
||||
|
||||
MSGPACK_DEFINE_MAP(id, msg, date, status, datatype)
|
||||
MSGPACK_DEFINE_MAP(id, msg, date, status, datatype, metadatas)
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC TrustRequest : public EncryptedValue<TrustRequest>
|
||||
|
||||
+72
-73
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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>
|
||||
@@ -68,27 +68,29 @@ 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(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {});
|
||||
virtual ~Dht();
|
||||
|
||||
/**
|
||||
* Get the ID of the node.
|
||||
*/
|
||||
inline const InfoHash& getNodeId() const { return myid; }
|
||||
inline const InfoHash& getNodeId() const override { return myid; }
|
||||
|
||||
/**
|
||||
* Get the current status of the node for the given family.
|
||||
*/
|
||||
NodeStatus getStatus(sa_family_t af) const;
|
||||
NodeStatus getStatus(sa_family_t af) const override;
|
||||
|
||||
NodeStatus getStatus() const {
|
||||
NodeStatus getStatus() const override {
|
||||
return std::max(getStatus(AF_INET), getStatus(AF_INET6));
|
||||
}
|
||||
|
||||
net::DatagramSocket* getSocket() const override { return network_engine.getSocket(); };
|
||||
|
||||
/**
|
||||
* Performs final operations before quitting.
|
||||
*/
|
||||
void shutdown(ShutdownCallback cb);
|
||||
void shutdown(ShutdownCallback cb) override;
|
||||
|
||||
/**
|
||||
* Returns true if the node is running (have access to an open socket).
|
||||
@@ -96,12 +98,12 @@ public:
|
||||
* af: address family. If non-zero, will return true if the node
|
||||
* is running for the provided family.
|
||||
*/
|
||||
bool isRunning(sa_family_t af = 0) const;
|
||||
bool isRunning(sa_family_t af = 0) const override;
|
||||
|
||||
virtual void registerType(const ValueType& type) {
|
||||
virtual void registerType(const ValueType& type) override {
|
||||
types.registerType(type);
|
||||
}
|
||||
const ValueType& getType(ValueType::Id type_id) const {
|
||||
const ValueType& getType(ValueType::Id type_id) const override {
|
||||
return types.getType(type_id);
|
||||
}
|
||||
|
||||
@@ -110,18 +112,18 @@ public:
|
||||
* The node is not pinged, so this should be
|
||||
* used to bootstrap efficiently from previously known nodes.
|
||||
*/
|
||||
void insertNode(const InfoHash& id, const SockAddr&);
|
||||
void insertNode(const InfoHash& id, const sockaddr* sa, socklen_t salen) {
|
||||
void insertNode(const InfoHash& id, const SockAddr&) override;
|
||||
void insertNode(const InfoHash& id, const sockaddr* sa, socklen_t salen) override {
|
||||
insertNode(id, SockAddr(sa, salen));
|
||||
}
|
||||
void insertNode(const NodeExport& n) {
|
||||
void insertNode(const NodeExport& n) override {
|
||||
insertNode(n.id, SockAddr(n.ss, n.sslen));
|
||||
}
|
||||
|
||||
void pingNode(const sockaddr*, socklen_t, DoneCallbackSimple&& cb={});
|
||||
void pingNode(const sockaddr*, socklen_t, DoneCallbackSimple&& cb={}) override;
|
||||
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, const SockAddr&);
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) {
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr) override;
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
|
||||
return periodic(buf, buflen, SockAddr(from, fromlen));
|
||||
}
|
||||
|
||||
@@ -135,14 +137,14 @@ public:
|
||||
cb and donecb won't be called again afterward.
|
||||
* @param f a filter function used to prefilter values.
|
||||
*/
|
||||
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {});
|
||||
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) {
|
||||
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override;
|
||||
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
|
||||
get(key, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) {
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
|
||||
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) {
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override {
|
||||
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
/**
|
||||
@@ -155,20 +157,20 @@ public:
|
||||
* @param q a query used to filter values on the remotes before they send a
|
||||
* response.
|
||||
*/
|
||||
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {});
|
||||
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) {
|
||||
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {}) override;
|
||||
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override {
|
||||
query(key, cb, bindDoneCb(done_cb), std::forward<Query>(q));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get locally stored data for the given hash.
|
||||
*/
|
||||
std::vector<Sp<Value>> getLocal(const InfoHash& key, Value::Filter f = Value::AllFilter()) const;
|
||||
std::vector<Sp<Value>> getLocal(const InfoHash& key, const Value::Filter& f = {}) const override;
|
||||
|
||||
/**
|
||||
* Get locally stored data for the given key and value id.
|
||||
*/
|
||||
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const;
|
||||
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const override;
|
||||
|
||||
/**
|
||||
* Announce a value on all available protocols (IPv4, IPv6).
|
||||
@@ -180,12 +182,12 @@ public:
|
||||
Sp<Value>,
|
||||
DoneCallback cb=nullptr,
|
||||
time_point created=time_point::max(),
|
||||
bool permanent = false);
|
||||
bool permanent = false) override;
|
||||
void put(const InfoHash& key,
|
||||
const Sp<Value>& v,
|
||||
DoneCallbackSimple cb,
|
||||
time_point created=time_point::max(),
|
||||
bool permanent = false)
|
||||
bool permanent = false) override
|
||||
{
|
||||
put(key, v, bindDoneCb(cb), created, permanent);
|
||||
}
|
||||
@@ -194,7 +196,7 @@ public:
|
||||
Value&& v,
|
||||
DoneCallback cb=nullptr,
|
||||
time_point created=time_point::max(),
|
||||
bool permanent = false)
|
||||
bool permanent = false) override
|
||||
{
|
||||
put(key, std::make_shared<Value>(std::move(v)), cb, created, permanent);
|
||||
}
|
||||
@@ -202,7 +204,7 @@ public:
|
||||
Value&& v,
|
||||
DoneCallbackSimple cb,
|
||||
time_point created=time_point::max(),
|
||||
bool permanent = false)
|
||||
bool permanent = false) override
|
||||
{
|
||||
put(key, std::forward<Value>(v), bindDoneCb(cb), created, permanent);
|
||||
}
|
||||
@@ -210,18 +212,18 @@ public:
|
||||
/**
|
||||
* Get data currently being put at the given hash.
|
||||
*/
|
||||
std::vector<Sp<Value>> getPut(const InfoHash&);
|
||||
std::vector<Sp<Value>> getPut(const InfoHash&) const override;
|
||||
|
||||
/**
|
||||
* Get data currently being put at the given hash with the given id.
|
||||
*/
|
||||
Sp<Value> getPut(const InfoHash&, const Value::Id&);
|
||||
Sp<Value> getPut(const InfoHash&, const Value::Id&) const override;
|
||||
|
||||
/**
|
||||
* Stop any put/announce operation at the given location,
|
||||
* for the value with the given id.
|
||||
*/
|
||||
bool cancelPut(const InfoHash&, const Value::Id&);
|
||||
bool cancelPut(const InfoHash&, const Value::Id&) override;
|
||||
|
||||
/**
|
||||
* Listen on the network for any changes involving a specified hash.
|
||||
@@ -230,28 +232,28 @@ public:
|
||||
*
|
||||
* @return a token to cancel the listener later.
|
||||
*/
|
||||
virtual size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where={});
|
||||
size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where={}) override;
|
||||
|
||||
virtual size_t listen(const InfoHash& key, GetCallback cb, Value::Filter f={}, Where w={}) {
|
||||
size_t listen(const InfoHash& key, GetCallback cb, Value::Filter f={}, Where w={}) override {
|
||||
return listen(key, [cb](const std::vector<Sp<Value>>& vals, bool expired){
|
||||
if (not expired)
|
||||
return cb(vals);
|
||||
return true;
|
||||
}, std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) {
|
||||
size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) override {
|
||||
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
|
||||
virtual bool cancelListen(const InfoHash&, size_t token);
|
||||
bool cancelListen(const InfoHash&, size_t token) override;
|
||||
|
||||
/**
|
||||
* Inform the DHT of lower-layer connectivity changes.
|
||||
* This will cause the DHT to assume a public IP address change.
|
||||
* The DHT will recontact neighbor nodes, re-register for listen ops etc.
|
||||
*/
|
||||
void connectivityChanged(sa_family_t);
|
||||
void connectivityChanged() {
|
||||
void connectivityChanged(sa_family_t) override;
|
||||
void connectivityChanged() override {
|
||||
reported_addr.clear();
|
||||
connectivityChanged(AF_INET);
|
||||
connectivityChanged(AF_INET6);
|
||||
@@ -261,29 +263,32 @@ public:
|
||||
* Get the list of good nodes for local storage saving purposes
|
||||
* The list is ordered to minimize the back-to-work delay.
|
||||
*/
|
||||
std::vector<NodeExport> exportNodes();
|
||||
std::vector<NodeExport> exportNodes() const override;
|
||||
|
||||
std::vector<ValuesExport> exportValues() const;
|
||||
void importValues(const std::vector<ValuesExport>&);
|
||||
std::vector<ValuesExport> exportValues() const override;
|
||||
void importValues(const std::vector<ValuesExport>&) override;
|
||||
|
||||
NodeStats getNodesStats(sa_family_t af) const;
|
||||
void saveState(const std::string& path) const;
|
||||
void loadState(const std::string& path);
|
||||
|
||||
std::string getStorageLog() const;
|
||||
std::string getStorageLog(const InfoHash&) const;
|
||||
NodeStats getNodesStats(sa_family_t af) const override;
|
||||
|
||||
std::string getRoutingTablesLog(sa_family_t) const;
|
||||
std::string getSearchesLog(sa_family_t) const;
|
||||
std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const;
|
||||
std::string getStorageLog() const override;
|
||||
std::string getStorageLog(const InfoHash&) const override;
|
||||
|
||||
void dumpTables() const;
|
||||
std::vector<unsigned> getNodeMessageStats(bool in = false) {
|
||||
std::string getRoutingTablesLog(sa_family_t) const override;
|
||||
std::string getSearchesLog(sa_family_t) const override;
|
||||
std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const override;
|
||||
|
||||
void dumpTables() const override;
|
||||
std::vector<unsigned> getNodeMessageStats(bool in = false) override {
|
||||
return network_engine.getNodeMessageStats(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the in-memory storage limit in bytes
|
||||
*/
|
||||
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) {
|
||||
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override {
|
||||
max_store_size = limit;
|
||||
}
|
||||
|
||||
@@ -291,13 +296,13 @@ public:
|
||||
* Returns the total memory usage of stored values and the number
|
||||
* of stored values.
|
||||
*/
|
||||
std::pair<size_t, size_t> getStoreSize() const {
|
||||
std::pair<size_t, size_t> getStoreSize() const override {
|
||||
return {total_store_size, total_values};
|
||||
}
|
||||
|
||||
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0);
|
||||
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override;
|
||||
|
||||
void pushNotificationReceived(const std::map<std::string, std::string>&) {}
|
||||
void pushNotificationReceived(const std::map<std::string, std::string>&) override {}
|
||||
void resubscribe(unsigned) {}
|
||||
|
||||
private:
|
||||
@@ -324,10 +329,10 @@ private:
|
||||
static constexpr unsigned LISTEN_NODES {4};
|
||||
|
||||
/* The maximum number of hashes we're willing to track. */
|
||||
static constexpr unsigned MAX_HASHES {16384};
|
||||
static constexpr unsigned MAX_HASHES {64 * 1024};
|
||||
|
||||
/* The maximum number of searches we keep data about. */
|
||||
static constexpr unsigned MAX_SEARCHES {16384};
|
||||
static constexpr unsigned MAX_SEARCHES {64 * 1024};
|
||||
|
||||
static constexpr std::chrono::minutes MAX_STORAGE_MAINTENANCE_EXPIRE_TIME {10};
|
||||
|
||||
@@ -359,13 +364,6 @@ private:
|
||||
// registred types
|
||||
TypeStore types;
|
||||
|
||||
// are we a bootstrap node ?
|
||||
// note: Any running node can be used as a bootstrap node.
|
||||
// Only nodes running only as bootstrap nodes should
|
||||
// be put in bootstrap mode.
|
||||
const bool is_bootstrap {false};
|
||||
const bool maintain_storage {false};
|
||||
|
||||
// the stuff
|
||||
RoutingTable buckets4 {};
|
||||
RoutingTable buckets6 {};
|
||||
@@ -400,6 +398,15 @@ private:
|
||||
|
||||
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
|
||||
|
||||
std::string persistPath;
|
||||
|
||||
// are we a bootstrap node ?
|
||||
// note: Any running node can be used as a bootstrap node.
|
||||
// Only nodes running only as bootstrap nodes should
|
||||
// be put in bootstrap mode.
|
||||
const bool is_bootstrap {false};
|
||||
const bool maintain_storage {false};
|
||||
|
||||
void rotateSecrets();
|
||||
|
||||
Blob makeToken(const SockAddr&, bool old) const;
|
||||
@@ -425,23 +432,15 @@ private:
|
||||
* nodes.
|
||||
*/
|
||||
void dataPersistence(InfoHash id);
|
||||
size_t maintainStorage(decltype(store)::value_type&, bool force=false, DoneCallback donecb=nullptr);
|
||||
size_t maintainStorage(decltype(store)::value_type&, bool force=false, const DoneCallback& donecb={});
|
||||
|
||||
// Buckets
|
||||
RoutingTable& buckets(sa_family_t af) { return af == AF_INET ? buckets4 : buckets6; }
|
||||
const RoutingTable& buckets(sa_family_t af) const { return af == AF_INET ? buckets4 : buckets6; }
|
||||
Bucket* findBucket(const InfoHash& id, sa_family_t af) {
|
||||
RoutingTable::iterator b;
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
b = buckets4.findBucket(id);
|
||||
return b == buckets4.end() ? nullptr : &(*b);
|
||||
case AF_INET6:
|
||||
b = buckets6.findBucket(id);
|
||||
return b == buckets6.end() ? nullptr : &(*b);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
auto& b = buckets(af);
|
||||
auto it = b.findBucket(id);
|
||||
return it == b.end() ? nullptr : &(*it);
|
||||
}
|
||||
const Bucket* findBucket(const InfoHash& id, sa_family_t af) const {
|
||||
return const_cast<Dht*>(this)->findBucket(id, af);
|
||||
@@ -469,7 +468,7 @@ private:
|
||||
Sp<Search> search(const InfoHash& id, sa_family_t af, GetCallback = {}, QueryCallback = {}, DoneCallback = {}, Value::Filter = {}, const Sp<Query>& q = {});
|
||||
|
||||
void announce(const InfoHash& id, sa_family_t af, Sp<Value> value, DoneCallback callback, time_point created=time_point::max(), bool permanent = false);
|
||||
size_t listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filter f = Value::AllFilter(), const Sp<Query>& q = {});
|
||||
size_t listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filter f = {}, const Sp<Query>& q = {});
|
||||
|
||||
/**
|
||||
* Refill the search with good nodes if possible.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -23,9 +23,14 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
namespace net {
|
||||
class DatagramSocket;
|
||||
}
|
||||
|
||||
class OPENDHT_PUBLIC DhtInterface {
|
||||
public:
|
||||
DhtInterface() = default;
|
||||
DhtInterface(const Logger& l) : DHT_LOG(l) {};
|
||||
virtual ~DhtInterface() = default;
|
||||
|
||||
// [[deprecated]]
|
||||
@@ -39,6 +44,8 @@ public:
|
||||
virtual NodeStatus getStatus(sa_family_t af) const = 0;
|
||||
virtual NodeStatus getStatus() const = 0;
|
||||
|
||||
virtual net::DatagramSocket* getSocket() const { return {}; };
|
||||
|
||||
/**
|
||||
* Get the ID of the DHT node.
|
||||
*/
|
||||
@@ -72,7 +79,7 @@ public:
|
||||
|
||||
virtual void pingNode(const sockaddr*, socklen_t, DoneCallbackSimple&& cb={}) = 0;
|
||||
|
||||
virtual time_point periodic(const uint8_t *buf, size_t buflen, const SockAddr&) = 0;
|
||||
virtual time_point periodic(const uint8_t *buf, size_t buflen, SockAddr) = 0;
|
||||
virtual time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) = 0;
|
||||
|
||||
/**
|
||||
@@ -106,7 +113,7 @@ public:
|
||||
/**
|
||||
* Get locally stored data for the given hash.
|
||||
*/
|
||||
virtual std::vector<Sp<Value>> getLocal(const InfoHash& key, Value::Filter f = Value::AllFilter()) const = 0;
|
||||
virtual std::vector<Sp<Value>> getLocal(const InfoHash& key, const Value::Filter& f = {}) const = 0;
|
||||
|
||||
/**
|
||||
* Get locally stored data for the given key and value id.
|
||||
@@ -143,12 +150,12 @@ public:
|
||||
/**
|
||||
* Get data currently being put at the given hash.
|
||||
*/
|
||||
virtual std::vector<Sp<Value>> getPut(const InfoHash&) = 0;
|
||||
virtual std::vector<Sp<Value>> getPut(const InfoHash&) const = 0;
|
||||
|
||||
/**
|
||||
* Get data currently being put at the given hash with the given id.
|
||||
*/
|
||||
virtual Sp<Value> getPut(const InfoHash&, const Value::Id&) = 0;
|
||||
virtual Sp<Value> getPut(const InfoHash&, const Value::Id&) const = 0;
|
||||
|
||||
/**
|
||||
* Stop any put/announce operation at the given location,
|
||||
@@ -181,7 +188,7 @@ public:
|
||||
* Get the list of good nodes for local storage saving purposes
|
||||
* The list is ordered to minimize the back-to-work delay.
|
||||
*/
|
||||
virtual std::vector<NodeExport> exportNodes() = 0;
|
||||
virtual std::vector<NodeExport> exportNodes() const = 0;
|
||||
|
||||
virtual std::vector<ValuesExport> exportValues() const = 0;
|
||||
virtual void importValues(const std::vector<ValuesExport>&) = 0;
|
||||
@@ -214,13 +221,18 @@ public:
|
||||
/**
|
||||
* Enable or disable logging of DHT internal messages
|
||||
*/
|
||||
virtual void setLoggers(LogMethod error = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG)
|
||||
{
|
||||
virtual void setLoggers(LogMethod error = {}, LogMethod warn = {}, LogMethod debug = {}) {
|
||||
DHT_LOG.DBG = debug;
|
||||
DHT_LOG.WARN = warn;
|
||||
DHT_LOG.ERR = error;
|
||||
}
|
||||
|
||||
virtual void setLogger(const Logger& l) {
|
||||
DHT_LOG.DBG = l.DBG;
|
||||
DHT_LOG.WARN = l.WARN;
|
||||
DHT_LOG.ERR = l.ERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
|
||||
*/
|
||||
@@ -238,8 +250,6 @@ public:
|
||||
virtual void pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
|
||||
|
||||
protected:
|
||||
bool logFilerEnable_ {};
|
||||
InfoHash logFiler_ {};
|
||||
Logger DHT_LOG;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,42 +18,51 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
#include "callbacks.h"
|
||||
#include "def.h"
|
||||
#include "dht_interface.h"
|
||||
#include "scheduler.h"
|
||||
#include "proxy.h"
|
||||
|
||||
namespace restbed {
|
||||
class Request;
|
||||
}
|
||||
#include <restinio/all.hpp>
|
||||
#include <http_parser.h>
|
||||
#include <json/json.h>
|
||||
#include "http.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace Json {
|
||||
class Value;
|
||||
}
|
||||
|
||||
namespace dht {
|
||||
namespace http {
|
||||
class Client;
|
||||
}
|
||||
|
||||
class SearchCache;
|
||||
namespace dht {
|
||||
|
||||
class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface {
|
||||
public:
|
||||
|
||||
DhtProxyClient();
|
||||
|
||||
explicit DhtProxyClient(std::function<void()> loopSignal, const std::string& serverHost, const std::string& pushClientId = "");
|
||||
explicit DhtProxyClient(std::function<void()> loopSignal, const std::string& serverHost,
|
||||
const std::string& pushClientId = "",
|
||||
std::shared_ptr<dht::Logger> logger = {});
|
||||
|
||||
restinio::http_header_fields_t initHeaderFields();
|
||||
|
||||
virtual void setPushNotificationToken(const std::string& token) {
|
||||
#if OPENDHT_PUSH_NOTIFICATIONS
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
deviceKey_ = token;
|
||||
#else
|
||||
(void) token;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -174,6 +184,10 @@ public:
|
||||
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));
|
||||
}
|
||||
/*
|
||||
* This function relies on the cache implementation.
|
||||
* It means that there are no true cancel here, it keeps the caching in higher priority.
|
||||
*/
|
||||
virtual bool cancelListen(const InfoHash& key, size_t token);
|
||||
|
||||
/**
|
||||
@@ -182,12 +196,11 @@ public:
|
||||
*/
|
||||
void pushNotificationReceived(const std::map<std::string, std::string>& notification);
|
||||
|
||||
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) {
|
||||
time_point periodic(const uint8_t*, size_t, SockAddr);
|
||||
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen) {
|
||||
return periodic(buf, buflen, SockAddr(from, fromlen));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Similar to Dht::get, but sends a Query to filter data remotely.
|
||||
* @param key the key for which to query data for.
|
||||
@@ -206,12 +219,12 @@ public:
|
||||
/**
|
||||
* Get data currently being put at the given hash.
|
||||
*/
|
||||
std::vector<Sp<Value>> getPut(const InfoHash&);
|
||||
std::vector<Sp<Value>> getPut(const InfoHash&) const;
|
||||
|
||||
/**
|
||||
* Get data currently being put at the given hash with the given id.
|
||||
*/
|
||||
Sp<Value> getPut(const InfoHash&, const Value::Id&);
|
||||
Sp<Value> getPut(const InfoHash&, const Value::Id&) const;
|
||||
|
||||
/**
|
||||
* Stop any put/announce operation at the given location,
|
||||
@@ -228,7 +241,7 @@ public:
|
||||
return types.getType(type_id);
|
||||
}
|
||||
|
||||
std::vector<Sp<Value>> getLocal(const InfoHash& k, Value::Filter filter) const;
|
||||
std::vector<Sp<Value>> getLocal(const InfoHash& k, const Value::Filter& filter) const;
|
||||
Sp<Value> getLocalById(const InfoHash& k, Value::Id id) const;
|
||||
|
||||
/**
|
||||
@@ -239,7 +252,7 @@ public:
|
||||
void insertNode(const InfoHash&, const sockaddr*, socklen_t) { }
|
||||
void insertNode(const NodeExport&) { }
|
||||
std::pair<size_t, size_t> getStoreSize() const { return {}; }
|
||||
std::vector<NodeExport> exportNodes() { return {}; }
|
||||
std::vector<NodeExport> exportNodes() const { return {}; }
|
||||
std::vector<ValuesExport> exportValues() const { return {}; }
|
||||
void importValues(const std::vector<ValuesExport>&) {}
|
||||
std::string getStorageLog() const { return {}; }
|
||||
@@ -264,6 +277,7 @@ private:
|
||||
* Start the connection with a server.
|
||||
*/
|
||||
void startProxy();
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Get informations from the proxy node
|
||||
@@ -271,19 +285,34 @@ private:
|
||||
*/
|
||||
struct InfoState;
|
||||
void getProxyInfos();
|
||||
void handleProxyStatus(const asio::error_code &ec, std::shared_ptr<InfoState> infoState);
|
||||
void onProxyInfos(const Json::Value& val, sa_family_t family);
|
||||
SockAddr parsePublicAddress(const Json::Value& val);
|
||||
|
||||
void opFailed();
|
||||
|
||||
size_t doListen(const InfoHash& key, ValueCallback, Value::Filter);
|
||||
bool doCancelListen(const InfoHash& key, size_t token);
|
||||
void handleExpireListener(const asio::error_code &ec, const InfoHash& key);
|
||||
|
||||
struct Listener;
|
||||
struct ListenState;
|
||||
void sendListen(const std::shared_ptr<restbed::Request>& request, const ValueCallback&, const Value::Filter& filter, const Sp<ListenState>& state);
|
||||
void sendSubscribe(const std::shared_ptr<restbed::Request>& request, const Sp<proxy::ListenToken>&, const Sp<ListenState>& state);
|
||||
enum class ListenMethod {
|
||||
LISTEN,
|
||||
SUBSCRIBE,
|
||||
RESUBSCRIBE,
|
||||
};
|
||||
/**
|
||||
* Send Listen with httpClient_
|
||||
*/
|
||||
void sendListen(const restinio::http_request_header_t header,
|
||||
const ValueCallback &cb,
|
||||
const Sp<ListenState> &state, Listener &listener,
|
||||
ListenMethod method = ListenMethod::LISTEN);
|
||||
void handleResubscribe(const asio::error_code &ec, const InfoHash& key,
|
||||
const size_t token, std::shared_ptr<ListenState> state);
|
||||
|
||||
void doPut(const InfoHash&, Sp<Value>, DoneCallback, time_point created, bool permanent);
|
||||
void handleRefreshPut(const asio::error_code &ec, const InfoHash& key, const Value::Id id,
|
||||
std::shared_ptr<std::atomic_bool> ok);
|
||||
|
||||
/**
|
||||
* Initialize statusIpvX_
|
||||
@@ -298,9 +327,23 @@ private:
|
||||
*/
|
||||
void cancelAllOperations();
|
||||
|
||||
std::string serverHost_;
|
||||
std::pair<std::string, std::string> serverHostService_;
|
||||
std::string pushClientId_;
|
||||
|
||||
/*
|
||||
* ASIO I/O Context for sockets in httpClient_
|
||||
* Note: Each context is used in one thread only
|
||||
*/
|
||||
asio::io_context httpContext_;
|
||||
/*
|
||||
* http::Client instance used on http io_context
|
||||
*/
|
||||
std::unique_ptr<http::Client> httpClient_;
|
||||
/*
|
||||
* Thread for executing the http io_context.run() blocking call
|
||||
*/
|
||||
std::thread httpClientThread_;
|
||||
|
||||
mutable std::mutex lockCurrentProxyInfos_;
|
||||
NodeStatus statusIpv4_ {NodeStatus::Disconnected};
|
||||
NodeStatus statusIpv6_ {NodeStatus::Disconnected};
|
||||
@@ -317,40 +360,29 @@ private:
|
||||
/**
|
||||
* Store listen requests.
|
||||
*/
|
||||
struct Listener;
|
||||
struct ProxySearch;
|
||||
|
||||
size_t listenerToken_ {0};
|
||||
std::map<InfoHash, ProxySearch> searches_;
|
||||
mutable std::mutex searchLock_;
|
||||
|
||||
/**
|
||||
* Store current put and get requests.
|
||||
*/
|
||||
struct Operation
|
||||
{
|
||||
std::shared_ptr<restbed::Request> req;
|
||||
std::thread thread;
|
||||
std::shared_ptr<std::atomic_bool> finished;
|
||||
};
|
||||
std::vector<Operation> operations_;
|
||||
std::mutex lockOperations_;
|
||||
/**
|
||||
* Callbacks should be executed in the main thread.
|
||||
*/
|
||||
std::vector<std::function<void()>> callbacks_;
|
||||
std::mutex lockCallbacks;
|
||||
std::mutex lockCallbacks_;
|
||||
|
||||
Sp<InfoState> infoState_;
|
||||
std::thread statusThread_;
|
||||
Sp<asio::steady_timer> statusTimer_;
|
||||
mutable std::mutex statusLock_;
|
||||
|
||||
Scheduler scheduler;
|
||||
/**
|
||||
* Retrieve if we can connect to the proxy (update statusIpvX_)
|
||||
*/
|
||||
void confirmProxy();
|
||||
Sp<Scheduler::Job> nextProxyConfirmation {};
|
||||
void handleProxyConfirm(const asio::error_code &ec);
|
||||
Sp<asio::steady_timer> nextProxyConfirmationTimer_;
|
||||
Sp<asio::steady_timer> listenerRestartTimer_;
|
||||
|
||||
/**
|
||||
* Relaunch LISTEN requests if the client disconnect/reconnect.
|
||||
*/
|
||||
@@ -360,7 +392,7 @@ private:
|
||||
* Refresh a listen via a token
|
||||
* @param token
|
||||
*/
|
||||
void resubscribe(const InfoHash& key, Listener& listener);
|
||||
void resubscribe(const InfoHash& key, const size_t token, Listener& listener);
|
||||
|
||||
/**
|
||||
* If we want to use push notifications by default.
|
||||
@@ -370,14 +402,14 @@ private:
|
||||
|
||||
const std::function<void()> loopSignal_;
|
||||
|
||||
#if OPENDHT_PUSH_NOTIFICATIONS
|
||||
void fillBodyToGetToken(std::shared_ptr<restbed::Request> request, unsigned token = 0);
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
std::string fillBody(bool resubscribe);
|
||||
void getPushRequest(Json::Value&) const;
|
||||
#endif // OPENDHT_PUSH_NOTIFICATIONS
|
||||
|
||||
std::atomic_bool isDestroying_ {false};
|
||||
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // OPENDHT_PROXY_CLIENT
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,8 +18,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if OPENDHT_PROXY_SERVER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "callbacks.h"
|
||||
@@ -28,16 +27,43 @@
|
||||
#include "scheduler.h"
|
||||
#include "sockaddr.h"
|
||||
#include "value.h"
|
||||
#include "dht_proxy_client.h"
|
||||
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <restbed>
|
||||
#include <restinio/all.hpp>
|
||||
#include "http.h"
|
||||
|
||||
#ifdef OPENDHT_JSONCPP
|
||||
#include <json/json.h>
|
||||
#endif
|
||||
|
||||
namespace http {
|
||||
class Client;
|
||||
class opendht_logger_t;
|
||||
struct ListenerSession;
|
||||
class ConnectionListener;
|
||||
}
|
||||
|
||||
namespace restinio {
|
||||
class opendht_logger_t;
|
||||
struct custom_http_methods_t;
|
||||
}
|
||||
|
||||
using RestRouter = restinio::router::express_router_t<>;
|
||||
struct RestRouterTraits : public restinio::default_traits_t
|
||||
{
|
||||
using timer_manager_t = restinio::asio_timer_manager_t;
|
||||
using http_methods_mapper_t = restinio::custom_http_methods_t;
|
||||
using logger_t = restinio::opendht_logger_t;
|
||||
using request_handler_t = RestRouter;
|
||||
using connection_state_listener_t = http::ConnectionListener;
|
||||
};
|
||||
using ServerSettings = restinio::run_on_this_thread_settings_t<RestRouterTraits>;
|
||||
using RequestStatus = restinio::request_handling_status_t;
|
||||
using ResponseByParts = restinio::chunked_output_t;
|
||||
using ResponseByPartsBuilder = restinio::response_builder_t<ResponseByParts>;
|
||||
|
||||
namespace Json {
|
||||
class Value;
|
||||
}
|
||||
@@ -60,7 +86,9 @@ public:
|
||||
* @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,
|
||||
const std::string& pushServer = "",
|
||||
std::shared_ptr<dht::Logger> logger = {});
|
||||
virtual ~DhtProxyServer();
|
||||
|
||||
DhtProxyServer(const DhtProxyServer& other) = delete;
|
||||
@@ -124,6 +152,14 @@ public:
|
||||
void stop();
|
||||
|
||||
private:
|
||||
template <typename HttpResponse>
|
||||
HttpResponse initHttpResponse(HttpResponse response) const;
|
||||
|
||||
ServerSettings makeHttpServerSettings(
|
||||
const unsigned int max_pipelined_requests = 16);
|
||||
|
||||
std::unique_ptr<RestRouter> createRestRouter();
|
||||
|
||||
/**
|
||||
* Return the PublicKey id, the node id and node stats
|
||||
* Method: GET "/"
|
||||
@@ -131,7 +167,8 @@ private:
|
||||
* On error: HTTP 503, body: {"err":"xxxx"}
|
||||
* @param session
|
||||
*/
|
||||
void getNodeInfo(const std::shared_ptr<restbed::Session>& session) const;
|
||||
RequestStatus getNodeInfo(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params) const;
|
||||
|
||||
/**
|
||||
* Return ServerStats in JSON format
|
||||
@@ -139,7 +176,8 @@ private:
|
||||
* Result: HTTP 200, body: Node infos in JSON format
|
||||
* @param session
|
||||
*/
|
||||
void getStats(const std::shared_ptr<restbed::Session>& session) const;
|
||||
RequestStatus getStats(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
/**
|
||||
* Return Values of an infoHash
|
||||
@@ -151,7 +189,8 @@ private:
|
||||
* On error: HTTP 503, body: {"err":"xxxx"}
|
||||
* @param session
|
||||
*/
|
||||
void get(const std::shared_ptr<restbed::Session>& session) const;
|
||||
RequestStatus get(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
/**
|
||||
* Listen incoming Values of an infoHash.
|
||||
@@ -163,7 +202,8 @@ private:
|
||||
* On error: HTTP 503, body: {"err":"xxxx"}
|
||||
* @param session
|
||||
*/
|
||||
void listen(const std::shared_ptr<restbed::Session>& session);
|
||||
RequestStatus listen(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
/**
|
||||
* Put a value on the DHT
|
||||
@@ -174,11 +214,12 @@ private:
|
||||
* HTTP 400, body: {"err":"xxxx"} if bad json or HTTP 502 if put fails
|
||||
* @param session
|
||||
*/
|
||||
void put(const std::shared_ptr<restbed::Session>& session);
|
||||
RequestStatus put(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
void cancelPut(const InfoHash& key, Value::Id vid);
|
||||
void handleCancelPermamentPut(const asio::error_code &ec, const InfoHash& key, Value::Id vid);
|
||||
|
||||
#if OPENDHT_PROXY_SERVER_IDENTITY
|
||||
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
|
||||
/**
|
||||
* Put a value to sign by the proxy on the DHT
|
||||
* Method: SIGN "/{InfoHash: .*}"
|
||||
@@ -188,7 +229,8 @@ private:
|
||||
* HTTP 400, body: {"err":"xxxx"} if bad json
|
||||
* @param session
|
||||
*/
|
||||
void putSigned(const std::shared_ptr<restbed::Session>& session) const;
|
||||
RequestStatus putSigned(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params) const;
|
||||
|
||||
/**
|
||||
* Put a value to encrypt by the proxy on the DHT
|
||||
@@ -199,7 +241,9 @@ private:
|
||||
* HTTP 400, body: {"err":"xxxx"} if bad json
|
||||
* @param session
|
||||
*/
|
||||
void putEncrypted(const std::shared_ptr<restbed::Session>& session) const;
|
||||
RequestStatus putEncrypted(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
#endif // OPENDHT_PROXY_SERVER_IDENTITY
|
||||
|
||||
/**
|
||||
@@ -212,7 +256,8 @@ private:
|
||||
* On error: HTTP 503, body: {"err":"xxxx"}
|
||||
* @param session
|
||||
*/
|
||||
void getFiltered(const std::shared_ptr<restbed::Session>& session) const;
|
||||
RequestStatus getFiltered(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
/**
|
||||
* Respond allowed Methods
|
||||
@@ -221,15 +266,10 @@ private:
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
|
||||
* @param session
|
||||
*/
|
||||
void handleOptionsMethod(const std::shared_ptr<restbed::Session>& session) const;
|
||||
RequestStatus options(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
/**
|
||||
* Remove finished listeners
|
||||
* @param testSession if we remove the listener only if the session is closed
|
||||
*/
|
||||
void removeClosedListeners(bool testSession = true);
|
||||
|
||||
#if OPENDHT_PUSH_NOTIFICATIONS
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
/**
|
||||
* Subscribe to push notifications for an iOS or Android device.
|
||||
* Method: SUBSCRIBE "/{InfoHash: .*}"
|
||||
@@ -239,7 +279,9 @@ private:
|
||||
* so you need to refresh the operation each six hours.
|
||||
* @param session
|
||||
*/
|
||||
void subscribe(const std::shared_ptr<restbed::Session>& session);
|
||||
RequestStatus subscribe(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
/**
|
||||
* Unsubscribe to push notifications for an iOS or Android device.
|
||||
* Method: UNSUBSCRIBE "/{InfoHash: .*}"
|
||||
@@ -247,55 +289,75 @@ private:
|
||||
* Return: nothing
|
||||
* @param session
|
||||
*/
|
||||
void unsubscribe(const std::shared_ptr<restbed::Session>& session);
|
||||
RequestStatus unsubscribe(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
/**
|
||||
* Send a push notification via a gorush push gateway
|
||||
* @param key of the device
|
||||
* @param json, the content to send
|
||||
*/
|
||||
void sendPushNotification(const std::string& key, const Json::Value& json, bool isAndroid) const;
|
||||
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid) const;
|
||||
|
||||
/**
|
||||
* Send push notification with an expire timeout.
|
||||
* @param ec
|
||||
* @param pushToken
|
||||
* @param json
|
||||
* @param isAndroid
|
||||
*/
|
||||
void handleNotifyPushListenExpire(const asio::error_code &ec, const std::string pushToken,
|
||||
Json::Value json, const bool isAndroid);
|
||||
|
||||
/**
|
||||
* Remove a push listener between a client and a hash
|
||||
* @param ec
|
||||
* @param pushToken
|
||||
* @param key
|
||||
* @param clientId
|
||||
*/
|
||||
void cancelPushListen(const std::string& pushToken, const InfoHash& key, const std::string& clientId);
|
||||
|
||||
void handleCancelPushListen(const asio::error_code &ec, const std::string pushToken,
|
||||
const InfoHash key, const std::string clientId);
|
||||
|
||||
#endif //OPENDHT_PUSH_NOTIFICATIONS
|
||||
|
||||
void handlePrintStats(const asio::error_code &ec);
|
||||
|
||||
using clock = std::chrono::steady_clock;
|
||||
using time_point = clock::time_point;
|
||||
|
||||
std::thread server_thread {};
|
||||
std::unique_ptr<restbed::Service> service_;
|
||||
std::shared_ptr<DhtRunner> dht_;
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
Json::StreamWriterBuilder jsonBuilder_;
|
||||
|
||||
std::mutex schedulerLock_;
|
||||
std::condition_variable schedulerCv_;
|
||||
Scheduler scheduler_;
|
||||
std::thread schedulerThread_;
|
||||
std::thread httpServerThread_;
|
||||
std::unique_ptr<restinio::http_server_t<RestRouterTraits>> httpServer_;
|
||||
std::unique_ptr<http::Client> httpClient_;
|
||||
|
||||
Sp<Scheduler::Job> printStatsJob_;
|
||||
mutable std::mutex statsMutex_;
|
||||
mutable ServerStats stats_;
|
||||
mutable NodeInfo nodeInfo_ {};
|
||||
std::unique_ptr<asio::steady_timer> printStatsTimer_;
|
||||
|
||||
// Handle client quit for listen.
|
||||
// NOTE: can be simplified when we will supports restbed 5.0
|
||||
std::thread listenThread_;
|
||||
struct SessionToHashToken {
|
||||
std::shared_ptr<restbed::Session> session;
|
||||
InfoHash hash;
|
||||
std::future<size_t> token;
|
||||
// Thread-safe access to listeners map.
|
||||
std::shared_ptr<std::mutex> lockListener_;
|
||||
// Shared with connection listener.
|
||||
std::shared_ptr<std::map<restinio::connection_id_t,
|
||||
http::ListenerSession>> listeners_;
|
||||
// Connection Listener observing conn state changes.
|
||||
std::shared_ptr<http::ConnectionListener> connListener_;
|
||||
|
||||
struct PermanentPut {
|
||||
time_point expiration;
|
||||
std::string pushToken;
|
||||
std::string clientId;
|
||||
std::unique_ptr<asio::steady_timer> expireTimer;
|
||||
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
|
||||
};
|
||||
std::vector<SessionToHashToken> currentListeners_;
|
||||
std::mutex lockListener_;
|
||||
std::atomic_bool stopListeners {false};
|
||||
|
||||
struct PermanentPut;
|
||||
struct SearchPuts;
|
||||
struct SearchPuts {
|
||||
std::map<dht::Value::Id, PermanentPut> puts;
|
||||
};
|
||||
std::mutex lockSearchPuts_;
|
||||
std::map<InfoHash, SearchPuts> puts_;
|
||||
|
||||
mutable std::atomic<size_t> requestNum_ {0};
|
||||
@@ -303,11 +365,16 @@ private:
|
||||
|
||||
const std::string pushServer_;
|
||||
|
||||
mutable ServerStats stats_;
|
||||
|
||||
#if OPENDHT_PUSH_NOTIFICATIONS
|
||||
struct Listener;
|
||||
struct PushListener;
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
struct Listener {
|
||||
std::string clientId;
|
||||
std::future<size_t> internalToken;
|
||||
std::unique_ptr<asio::steady_timer> expireTimer;
|
||||
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
|
||||
};
|
||||
struct PushListener {
|
||||
std::map<InfoHash, std::vector<Listener>> listeners;
|
||||
};
|
||||
std::mutex lockPushListeners_;
|
||||
std::map<std::string, PushListener> pushListeners_;
|
||||
proxy::ListenToken tokenPushNotif_ {0};
|
||||
@@ -315,5 +382,3 @@ private:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //OPENDHT_PROXY_SERVER
|
||||
+63
-64
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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>
|
||||
@@ -20,12 +20,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "def.h"
|
||||
#include "infohash.h"
|
||||
#include "value.h"
|
||||
#include "callbacks.h"
|
||||
#include "sockaddr.h"
|
||||
#include "log_enable.h"
|
||||
#include "def.h"
|
||||
#include "network_utils.h"
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
@@ -40,6 +41,7 @@ namespace dht {
|
||||
|
||||
struct Node;
|
||||
class SecureDht;
|
||||
class PeerDiscovery;
|
||||
struct SecureDhtConfig;
|
||||
|
||||
/**
|
||||
@@ -51,32 +53,43 @@ struct SecureDhtConfig;
|
||||
class OPENDHT_PUBLIC DhtRunner {
|
||||
|
||||
public:
|
||||
typedef std::function<void(NodeStatus, NodeStatus)> StatusCallback;
|
||||
using StatusCallback = std::function<void(NodeStatus, NodeStatus)>;
|
||||
|
||||
struct Config {
|
||||
SecureDhtConfig dht_config;
|
||||
bool threaded;
|
||||
std::string proxy_server;
|
||||
std::string push_node_id;
|
||||
SecureDhtConfig dht_config {};
|
||||
bool threaded {true};
|
||||
std::string proxy_server {};
|
||||
std::string push_node_id {};
|
||||
bool peer_discovery {false};
|
||||
bool peer_publish {false};
|
||||
};
|
||||
|
||||
struct Context {
|
||||
std::shared_ptr<Logger> logger {};
|
||||
std::unique_ptr<net::DatagramSocket> sock;
|
||||
std::shared_ptr<PeerDiscovery> peerDiscovery {};
|
||||
StatusCallback statusChangedCallback {};
|
||||
CertificateStoreQuery certificateStore {};
|
||||
Context() {}
|
||||
};
|
||||
|
||||
DhtRunner();
|
||||
virtual ~DhtRunner();
|
||||
|
||||
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
|
||||
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = {}, Where w = {}) {
|
||||
get(id, bindGetCb(cb), donecb, f, w);
|
||||
}
|
||||
|
||||
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
|
||||
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = {}, Where w = {}) {
|
||||
get(id, bindGetCb(cb), donecb, f, w);
|
||||
}
|
||||
|
||||
void get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f={}, Where w = {});
|
||||
|
||||
void get(InfoHash id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
|
||||
void get(InfoHash id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter f = {}, Where w = {}) {
|
||||
get(id, cb, bindDoneCb(donecb), f, w);
|
||||
}
|
||||
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = Value::AllFilter(), Where w = {});
|
||||
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = {}, Where w = {});
|
||||
|
||||
template <class T>
|
||||
void get(InfoHash hash, std::function<bool(std::vector<T>&&)> cb, DoneCallbackSimple dcb={})
|
||||
@@ -105,7 +118,7 @@ public:
|
||||
getFilterSet<T>());
|
||||
}
|
||||
|
||||
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = Value::AllFilter(), Where w = {}) {
|
||||
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = {}, Where w = {}) {
|
||||
auto p = std::make_shared<std::promise<std::vector<std::shared_ptr< dht::Value >>>>();
|
||||
auto values = std::make_shared<std::vector<std::shared_ptr< dht::Value >>>();
|
||||
get(key, [=](const std::vector<std::shared_ptr<dht::Value>>& vlist) {
|
||||
@@ -136,7 +149,7 @@ public:
|
||||
query(hash, cb, bindDoneCb(done_cb), q);
|
||||
}
|
||||
|
||||
std::future<size_t> listen(InfoHash key, ValueCallback vcb, Value::Filter f = Value::AllFilter(), Where w = {});
|
||||
std::future<size_t> listen(InfoHash key, ValueCallback vcb, Value::Filter f = {}, Where w = {});
|
||||
|
||||
std::future<size_t> listen(InfoHash key, GetCallback cb, Value::Filter f={}, Where w={}) {
|
||||
return listen(key, [cb](const std::vector<Sp<Value>>& vals, bool expired){
|
||||
@@ -145,8 +158,8 @@ public:
|
||||
return true;
|
||||
}, std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
std::future<size_t> listen(const std::string& key, GetCallback vcb, Value::Filter f = Value::AllFilter(), Where w = {});
|
||||
std::future<size_t> listen(InfoHash key, GetCallbackSimple cb, Value::Filter f = Value::AllFilter(), Where w = {}) {
|
||||
std::future<size_t> listen(const std::string& key, GetCallback vcb, Value::Filter f = {}, Where w = {});
|
||||
std::future<size_t> listen(InfoHash key, GetCallbackSimple cb, Value::Filter f = {}, Where w = {}) {
|
||||
return listen(key, bindGetCb(cb), f, w);
|
||||
}
|
||||
|
||||
@@ -168,7 +181,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = Value::AllFilter(), Where w = {})
|
||||
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = {}, Where w = {})
|
||||
{
|
||||
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals) {
|
||||
for (const auto& v : vals) {
|
||||
@@ -184,7 +197,7 @@ public:
|
||||
getFilterSet<T>(f), w);
|
||||
}
|
||||
template <typename T>
|
||||
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&, bool)> cb, Value::Filter f = Value::AllFilter(), Where w = {})
|
||||
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&, bool)> cb, Value::Filter f = {}, Where w = {})
|
||||
{
|
||||
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals, bool expired) {
|
||||
for (const auto& v : vals) {
|
||||
@@ -259,6 +272,12 @@ public:
|
||||
*/
|
||||
void bootstrap(const std::string& host, const std::string& service);
|
||||
|
||||
/**
|
||||
* Insert known nodes to the routing table, without necessarly ping them.
|
||||
* Usefull to restart a node and get things running fast without putting load on the network.
|
||||
*/
|
||||
void bootstrap(const InfoHash& id, const SockAddr& address);
|
||||
|
||||
/**
|
||||
* Clear the list of bootstrap added using bootstrap(const std::string&, const std::string&).
|
||||
*/
|
||||
@@ -287,9 +306,7 @@ public:
|
||||
* Returns the currently bound address.
|
||||
* @param f: address family of the bound address to retreive.
|
||||
*/
|
||||
const SockAddr& getBound(sa_family_t f = AF_INET) const {
|
||||
return (f == AF_INET) ? bound4 : bound6;
|
||||
}
|
||||
SockAddr getBound(sa_family_t f = AF_INET) const;
|
||||
|
||||
/**
|
||||
* Returns the currently bound port, in host byte order.
|
||||
@@ -307,7 +324,8 @@ public:
|
||||
|
||||
std::vector<ValuesExport> exportValues() const;
|
||||
|
||||
void setLoggers(LogMethod err = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG);
|
||||
void setLogger(const Logger& logger = {});
|
||||
void setLoggers(LogMethod err = {}, LogMethod warn = {}, LogMethod debug = {});
|
||||
|
||||
/**
|
||||
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
|
||||
@@ -347,23 +365,14 @@ public:
|
||||
* @param threaded: If false, ::loop() must be called periodically. Otherwise a thread is launched.
|
||||
* @param cb: Optional callback to receive general state information.
|
||||
*/
|
||||
void run(in_port_t port = 4222, const crypto::Identity identity = {}, bool threaded = false, NetId network = 0) {
|
||||
run(port, {
|
||||
/*.dht_config = */{
|
||||
/*.node_config = */{
|
||||
/*.node_id = */{},
|
||||
/*.network = */network,
|
||||
/*.is_bootstrap = */false,
|
||||
/*.maintain_storage*/false
|
||||
},
|
||||
/*.id = */identity
|
||||
},
|
||||
/*.threaded = */threaded,
|
||||
/*.proxy_server = */"",
|
||||
/*.push_node_id = */""
|
||||
});
|
||||
void run(in_port_t port = 4222, const crypto::Identity& identity = {}, bool threaded = true, NetId network = 0) {
|
||||
Config config;
|
||||
config.dht_config.node_config.network = network;
|
||||
config.dht_config.id = identity;
|
||||
config.threaded = threaded;
|
||||
run(port, config);
|
||||
}
|
||||
void run(in_port_t port, Config config);
|
||||
void run(in_port_t port, const Config& config, Context&& context = {});
|
||||
|
||||
/**
|
||||
* @param local4: Local IPv4 address and port to bind. Can be null.
|
||||
@@ -373,12 +382,14 @@ public:
|
||||
* @param threaded: If false, loop() must be called periodically. Otherwise a thread is launched.
|
||||
* @param cb: Optional callback to receive general state information.
|
||||
*/
|
||||
void run(const SockAddr& local4, const SockAddr& local6, Config config);
|
||||
void run(const SockAddr& local4, const SockAddr& local6, const Config& config, Context&& context = {});
|
||||
|
||||
/**
|
||||
* Same as @run(sockaddr_in, sockaddr_in6, Identity, bool, StatusCallback), but with string IP addresses and service (port).
|
||||
*/
|
||||
void run(const char* ip4, const char* ip6, const char* service, Config config);
|
||||
void run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context = {});
|
||||
|
||||
void run(const Config& config, Context&& context);
|
||||
|
||||
void setOnStatusChanged(StatusCallback&& cb) {
|
||||
statusCb = std::move(cb);
|
||||
@@ -391,13 +402,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_();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,6 +417,8 @@ public:
|
||||
*/
|
||||
void join();
|
||||
|
||||
std::shared_ptr<PeerDiscovery> getPeerDiscovery() const { return peerDiscovery_; };
|
||||
|
||||
void setProxyServer(const std::string& proxy, const std::string& pushNodeId = "");
|
||||
|
||||
/**
|
||||
@@ -447,8 +454,6 @@ private:
|
||||
*/
|
||||
void tryBootstrapContinuously();
|
||||
|
||||
void stopNetwork();
|
||||
void startNetwork(const SockAddr sin4, const SockAddr sin6);
|
||||
time_point loop_();
|
||||
|
||||
NodeStatus getStatus() const {
|
||||
@@ -486,16 +491,8 @@ private:
|
||||
mutable std::mutex dht_mtx {};
|
||||
std::thread dht_thread {};
|
||||
std::condition_variable cv {};
|
||||
|
||||
std::thread rcv_thread {};
|
||||
std::mutex sock_mtx {};
|
||||
|
||||
struct ReceivedPacket {
|
||||
Blob data;
|
||||
SockAddr from;
|
||||
time_point received;
|
||||
};
|
||||
std::queue<ReceivedPacket> rcv {};
|
||||
std::queue<std::unique_ptr<net::ReceivedPacket>> rcv {};
|
||||
|
||||
/** true if currently actively boostraping */
|
||||
std::atomic_bool bootstraping {false};
|
||||
@@ -503,7 +500,6 @@ private:
|
||||
std::vector<std::pair<std::string,std::string>> bootstrap_nodes_all {};
|
||||
std::vector<std::pair<std::string,std::string>> bootstrap_nodes {};
|
||||
std::thread bootstrap_thread {};
|
||||
/** protects bootstrap_nodes, bootstrap_thread */
|
||||
std::mutex bootstrap_mtx {};
|
||||
std::condition_variable bootstrap_cv {};
|
||||
|
||||
@@ -512,19 +508,22 @@ private:
|
||||
std::mutex storage_mtx {};
|
||||
|
||||
std::atomic_bool running {false};
|
||||
std::atomic_bool running_network {false};
|
||||
|
||||
NodeStatus status4 {NodeStatus::Disconnected},
|
||||
status6 {NodeStatus::Disconnected};
|
||||
StatusCallback statusCb {nullptr};
|
||||
|
||||
int stop_writefd {-1};
|
||||
int s4 {-1}, s6 {-1};
|
||||
SockAddr bound4 {};
|
||||
SockAddr bound6 {};
|
||||
|
||||
/** Push notification token */
|
||||
std::string pushToken_;
|
||||
|
||||
/** PeerDiscovery Parameters */
|
||||
std::shared_ptr<PeerDiscovery> peerDiscovery_;
|
||||
|
||||
/**
|
||||
* The Logger instance is used in enableProxy and other methods that
|
||||
* would create instances of classes using a common logger.
|
||||
*/
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <asio.hpp>
|
||||
#include <json/json.h>
|
||||
#include <http_parser.h>
|
||||
#include <restinio/all.hpp>
|
||||
#include <opendht.h>
|
||||
#include <opendht/def.h>
|
||||
#include <opendht/log.h>
|
||||
|
||||
namespace http {
|
||||
|
||||
class Connection;
|
||||
|
||||
// basic types
|
||||
using Id = unsigned int;
|
||||
|
||||
// asio handlers callbacks
|
||||
using HandlerCb = std::function<void(const asio::error_code& ec)>;
|
||||
using ConnectionCb = std::function<void(const asio::error_code& ec, std::shared_ptr<Connection>)>;
|
||||
|
||||
class OPENDHT_PUBLIC Connection
|
||||
{
|
||||
public:
|
||||
Connection(asio::ip::tcp::socket socket, std::shared_ptr<dht::Logger> logger = {});
|
||||
~Connection();
|
||||
|
||||
Id id();
|
||||
bool is_open();
|
||||
bool is_v6();
|
||||
void timeout(const std::chrono::seconds timeout, HandlerCb cb = {});
|
||||
// TODO abort to silence error in request?
|
||||
void close();
|
||||
|
||||
private:
|
||||
friend class Client;
|
||||
|
||||
Id id_;
|
||||
static Id ids_;
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
|
||||
asio::ip::tcp::socket socket_;
|
||||
asio::ip::tcp::endpoint endpoint_;
|
||||
|
||||
asio::streambuf request_;
|
||||
std::string response_body_;
|
||||
asio::streambuf response_chunk_;
|
||||
|
||||
std::unique_ptr<asio::steady_timer> timeout_timer_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Session value associated with a connection_id_t key.
|
||||
*/
|
||||
struct ListenerSession
|
||||
{
|
||||
ListenerSession() = default;
|
||||
dht::InfoHash hash;
|
||||
std::future<size_t> token;
|
||||
std::shared_ptr<restinio::response_builder_t<restinio::chunked_output_t>> response;
|
||||
};
|
||||
|
||||
class ConnectionListener
|
||||
{
|
||||
public:
|
||||
ConnectionListener();
|
||||
ConnectionListener(std::shared_ptr<dht::DhtRunner> dht,
|
||||
std::shared_ptr<std::map<restinio::connection_id_t, http::ListenerSession>> listeners,
|
||||
std::shared_ptr<std::mutex> lock, std::shared_ptr<dht::Logger> logger);
|
||||
~ConnectionListener();
|
||||
|
||||
/**
|
||||
* Connection state change used to handle Listeners disconnects.
|
||||
* RESTinio >= 0.5.1 https://github.com/Stiffstream/restinio/issues/28
|
||||
*/
|
||||
void state_changed(const restinio::connection_state::notice_t& notice) noexcept;
|
||||
|
||||
private:
|
||||
std::string to_str( restinio::connection_state::cause_t cause ) noexcept;
|
||||
|
||||
std::shared_ptr<dht::DhtRunner> dht_;
|
||||
std::shared_ptr<std::mutex> lock_;
|
||||
std::shared_ptr<std::map<restinio::connection_id_t,
|
||||
http::ListenerSession>> listeners_;
|
||||
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
};
|
||||
|
||||
|
||||
class Resolver {
|
||||
Resolver(asio::io_context& ctx, const std::string& host, const std::string& service = "80");
|
||||
|
||||
using ResolvedCb = std::function<void(const asio::error_code&, const asio::ip::basic_resolver_results<asio::ip::tcp>&)>;
|
||||
void addOnResolved(ResolvedCb cb);
|
||||
|
||||
private:
|
||||
std::mutex cbsMutex_;
|
||||
asio::ip::tcp::resolver resolver_;
|
||||
asio::error_code error_;
|
||||
asio::ip::basic_resolver_results<asio::ip::tcp> endpoints_;
|
||||
std::queue<ResolvedCb> cbs_;
|
||||
bool completed_ {false};
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC Request
|
||||
{
|
||||
public:
|
||||
Request(asio::io_context& ctx, const std::string host, const std::string service = "80",
|
||||
const bool resolve = true, std::shared_ptr<dht::Logger> logger = {});
|
||||
~Request();
|
||||
|
||||
void set_logger(std::shared_ptr<dht::Logger> logger);
|
||||
|
||||
void terminate();
|
||||
|
||||
void resolve(const std::string host, const std::string service, HandlerCb cb = {});
|
||||
bool resolved();
|
||||
|
||||
void connect(ConnectionCb cb = {});
|
||||
|
||||
std::string build(const restinio::http_request_header_t header,
|
||||
const restinio::http_header_fields_t header_fields,
|
||||
const restinio::http_connection_header_t connection, const std::string body);
|
||||
|
||||
void send(std::string request, std::unique_ptr<http_parser> parser,
|
||||
std::unique_ptr<http_parser_settings> parser_s, HandlerCb cb = {});
|
||||
|
||||
private:
|
||||
void handle_request(const asio::error_code& ec, HandlerCb cb = {});
|
||||
|
||||
void handle_response_header(const asio::error_code& ec, const size_t bytes, HandlerCb cb = {});
|
||||
|
||||
void handle_response_body(const asio::error_code& ec, const size_t bytes, HandlerCb cb = {});
|
||||
|
||||
void parse_request(const std::string request);
|
||||
|
||||
size_t get_content_length(const std::string str);
|
||||
|
||||
Resolver resolver_;
|
||||
/* std::string service_;
|
||||
std::string host_;
|
||||
|
||||
asio::ip::tcp::resolver resolver_;
|
||||
asio::ip::basic_resolver_results<asio::ip::tcp> endpoints_;
|
||||
*/
|
||||
Id id_;
|
||||
static Id ids_;
|
||||
std::shared_ptr<Connection> conn_;
|
||||
|
||||
std::string request_;
|
||||
std::unique_ptr<http_parser> parser_;
|
||||
std::unique_ptr<http_parser_settings> parser_s_;
|
||||
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
namespace restinio
|
||||
{
|
||||
|
||||
class opendht_logger_t
|
||||
{
|
||||
public:
|
||||
opendht_logger_t(std::shared_ptr<dht::Logger> logger = {}){
|
||||
if (logger)
|
||||
m_logger = logger;
|
||||
}
|
||||
|
||||
template <typename Builder>
|
||||
void trace(Builder && msg_builder){
|
||||
if (m_logger)
|
||||
m_logger->d("[proxy:server] %s", msg_builder().c_str());
|
||||
}
|
||||
|
||||
template <typename Builder>
|
||||
void info(Builder && msg_builder){
|
||||
if (m_logger)
|
||||
m_logger->d("[proxy:server] %s", msg_builder().c_str());
|
||||
}
|
||||
|
||||
template <typename Builder>
|
||||
void warn(Builder && msg_builder){
|
||||
if (m_logger)
|
||||
m_logger->w("[proxy:server] %s", msg_builder().c_str());
|
||||
}
|
||||
|
||||
template <typename Builder>
|
||||
void error(Builder && msg_builder){
|
||||
if (m_logger)
|
||||
m_logger->e("[proxy:server] %s", msg_builder().c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<dht::Logger> m_logger;
|
||||
};
|
||||
|
||||
/* Custom HTTP-methods for RESTinio > 0.5.0.
|
||||
* https://github.com/Stiffstream/restinio/issues/26
|
||||
*/
|
||||
constexpr const restinio::http_method_id_t method_listen{HTTP_LISTEN, "LISTEN"};
|
||||
constexpr const restinio::http_method_id_t method_stats{HTTP_STATS, "STATS"};
|
||||
constexpr const restinio::http_method_id_t method_sign{HTTP_SIGN, "SIGN"};
|
||||
constexpr const restinio::http_method_id_t method_encrypt{HTTP_ENCRYPT, "ENCRYPT"};
|
||||
|
||||
struct custom_http_methods_t
|
||||
{
|
||||
static constexpr restinio::http_method_id_t from_nodejs(int m) noexcept {
|
||||
if(m == method_listen.raw_id())
|
||||
return method_listen;
|
||||
else if(m == method_stats.raw_id())
|
||||
return method_stats;
|
||||
else if(m == method_sign.raw_id())
|
||||
return method_sign;
|
||||
else if(m == method_encrypt.raw_id())
|
||||
return method_encrypt;
|
||||
else
|
||||
return restinio::default_http_methods_t::from_nodejs(m);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace restinio
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
typedef typename T::iterator iterator;
|
||||
typedef typename T::const_iterator const_iterator;
|
||||
|
||||
Hash () {
|
||||
Hash () noexcept {
|
||||
data_.fill(0);
|
||||
}
|
||||
Hash (const uint8_t* h, size_t data_len) {
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
msgpack_unpack(o);
|
||||
}
|
||||
|
||||
size_t size() const { return data_.size(); }
|
||||
static constexpr size_t size() noexcept { return N; }
|
||||
const uint8_t* data() const { return data_.data(); }
|
||||
uint8_t* data() { return data_.data(); }
|
||||
iterator begin() { return data_.begin(); }
|
||||
|
||||
+10
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
@@ -66,6 +66,15 @@ constexpr const Color::Modifier yellow(Color::FG_YELLOW);
|
||||
OPENDHT_PUBLIC void
|
||||
printLog(std::ostream &s, char const *m, va_list args);
|
||||
|
||||
OPENDHT_PUBLIC
|
||||
std::unique_ptr<Logger> getStdLogger();
|
||||
|
||||
OPENDHT_PUBLIC
|
||||
std::unique_ptr<Logger> getFileLogger(const std::string &path);
|
||||
|
||||
OPENDHT_PUBLIC
|
||||
std::unique_ptr<Logger> getSyslogLogger(const char* name);
|
||||
|
||||
OPENDHT_PUBLIC void
|
||||
enableLogging(dht::DhtRunner &dht);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,11 +32,6 @@ namespace dht {
|
||||
|
||||
// Logging related utility functions
|
||||
|
||||
/**
|
||||
* Dummy function used to disable logging
|
||||
*/
|
||||
inline void NOLOG(char const*, va_list) {}
|
||||
|
||||
/**
|
||||
* Wrapper for logging methods
|
||||
*/
|
||||
@@ -85,9 +80,13 @@ private:
|
||||
};
|
||||
|
||||
struct Logger {
|
||||
LogMethod DBG = NOLOG;
|
||||
LogMethod WARN = NOLOG;
|
||||
LogMethod ERR = NOLOG;
|
||||
LogMethod DBG = {};
|
||||
LogMethod WARN = {};
|
||||
LogMethod ERR = {};
|
||||
|
||||
Logger() = default;
|
||||
Logger(LogMethod&& err, LogMethod&& warn, LogMethod&& dbg)
|
||||
: DBG(std::move(dbg)), WARN(std::move(warn)), ERR(std::move(err)) {}
|
||||
void setFilter(const InfoHash& f) {
|
||||
filter_ = f;
|
||||
filterEnable_ = static_cast<bool>(filter_);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "utils.h"
|
||||
#include "rng.h"
|
||||
#include "rate_limiter.h"
|
||||
#include "log_enable.h"
|
||||
#include "network_utils.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -68,14 +70,14 @@ public:
|
||||
DhtProtocolException(uint16_t code, const std::string& msg="", InfoHash failing_node_id={})
|
||||
: DhtException(msg), msg(msg), code(code), failing_node_id(failing_node_id) {}
|
||||
|
||||
std::string getMsg() const { return msg; }
|
||||
const std::string& getMsg() const { return msg; }
|
||||
uint16_t getCode() const { return code; }
|
||||
const InfoHash getNodeId() const { return failing_node_id; }
|
||||
const InfoHash& getNodeId() const { return failing_node_id; }
|
||||
|
||||
private:
|
||||
std::string msg;
|
||||
uint16_t code;
|
||||
const InfoHash failing_node_id;
|
||||
InfoHash failing_node_id;
|
||||
};
|
||||
|
||||
struct ParsedMessage;
|
||||
@@ -204,19 +206,21 @@ 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,
|
||||
decltype(NetworkEngine::onError) onError,
|
||||
decltype(NetworkEngine::onNewNode) onNewNode,
|
||||
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
|
||||
decltype(NetworkEngine::onPing) onPing,
|
||||
decltype(NetworkEngine::onFindNode) onFindNode,
|
||||
decltype(NetworkEngine::onGetValues) onGetValues,
|
||||
decltype(NetworkEngine::onListen) onListen,
|
||||
decltype(NetworkEngine::onAnnounce) onAnnounce,
|
||||
decltype(NetworkEngine::onRefresh) onRefresh);
|
||||
NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
|
||||
NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
|
||||
decltype(NetworkEngine::onError)&& onError,
|
||||
decltype(NetworkEngine::onNewNode)&& onNewNode,
|
||||
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
|
||||
decltype(NetworkEngine::onPing)&& onPing,
|
||||
decltype(NetworkEngine::onFindNode)&& onFindNode,
|
||||
decltype(NetworkEngine::onGetValues)&& onGetValues,
|
||||
decltype(NetworkEngine::onListen)&& onListen,
|
||||
decltype(NetworkEngine::onAnnounce)&& onAnnounce,
|
||||
decltype(NetworkEngine::onRefresh)&& onRefresh);
|
||||
|
||||
virtual ~NetworkEngine();
|
||||
~NetworkEngine();
|
||||
|
||||
net::DatagramSocket* getSocket() const { return dht_socket.get(); };
|
||||
|
||||
void clear();
|
||||
|
||||
@@ -241,7 +245,7 @@ public:
|
||||
void tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector<Value::Id>& values);
|
||||
|
||||
bool isRunning(sa_family_t af) const;
|
||||
inline want_t want () const { return dht_socket >= 0 && dht_socket6 >= 0 ? (WANT4 | WANT6) : -1; }
|
||||
inline want_t want () const { return dht_socket->hasIPv4() and dht_socket->hasIPv6() ? (WANT4 | WANT6) : -1; }
|
||||
|
||||
void connectivityChanged(sa_family_t);
|
||||
|
||||
@@ -290,9 +294,9 @@ public:
|
||||
*/
|
||||
Sp<Request> sendFindNode(Sp<Node> n,
|
||||
const InfoHash& hash,
|
||||
want_t want,
|
||||
RequestCb&& on_done,
|
||||
RequestExpiredCb&& on_expired);
|
||||
want_t want = -1,
|
||||
RequestCb&& on_done = {},
|
||||
RequestExpiredCb&& on_expired = {});
|
||||
/**
|
||||
* Send a "get" request to a given node.
|
||||
*
|
||||
@@ -393,7 +397,7 @@ public:
|
||||
* @param fromlen The length of the corresponding sockaddr structure.
|
||||
* @param now The time to adjust the clock in the network engine.
|
||||
*/
|
||||
void processMessage(const uint8_t *buf, size_t buflen, const SockAddr& addr);
|
||||
void processMessage(const uint8_t *buf, size_t buflen, SockAddr addr);
|
||||
|
||||
Sp<Node> insertNode(const InfoHash& myid, const SockAddr& addr) {
|
||||
auto n = cache.getNode(myid, addr, scheduler.time(), 0);
|
||||
@@ -468,7 +472,7 @@ private:
|
||||
|
||||
|
||||
// basic wrapper for socket sendto function
|
||||
int send(const char *buf, size_t len, int flags, const SockAddr& addr);
|
||||
int send(const SockAddr& addr, const char *buf, size_t len, bool confirmed = false);
|
||||
|
||||
void sendValueParts(const TransId& tid, const std::vector<Blob>& svals, const SockAddr& addr);
|
||||
std::vector<Blob> packValueHeader(msgpack::sbuffer&, const std::vector<Sp<Value>>&);
|
||||
@@ -510,8 +514,7 @@ private:
|
||||
/* DHT info */
|
||||
const InfoHash& myid;
|
||||
const NetId network {0};
|
||||
const int& dht_socket;
|
||||
const int& dht_socket6;
|
||||
const std::unique_ptr<DatagramSocket> dht_socket;
|
||||
const Logger& DHT_LOG;
|
||||
|
||||
NodeCache cache {};
|
||||
@@ -531,6 +534,8 @@ private:
|
||||
std::set<SockAddr> blacklist {};
|
||||
|
||||
Scheduler& scheduler;
|
||||
|
||||
bool logIncoming_ {false};
|
||||
};
|
||||
|
||||
} /* namespace net */
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "def.h"
|
||||
|
||||
#include "sockaddr.h"
|
||||
#include "utils.h"
|
||||
#include "log_enable.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
|
||||
namespace dht {
|
||||
namespace net {
|
||||
|
||||
int bindSocket(const SockAddr& addr, SockAddr& bound);
|
||||
|
||||
bool setNonblocking(int fd, bool nonblocking = true);
|
||||
|
||||
#ifdef _WIN32
|
||||
void udpPipe(int fds[2]);
|
||||
#endif
|
||||
struct ReceivedPacket {
|
||||
Blob data;
|
||||
SockAddr from;
|
||||
time_point received;
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC DatagramSocket {
|
||||
public:
|
||||
using OnReceive = std::function<void(std::unique_ptr<ReceivedPacket>&& packet)>;
|
||||
virtual ~DatagramSocket() {};
|
||||
|
||||
virtual int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) = 0;
|
||||
|
||||
inline void setOnReceive(OnReceive&& cb) {
|
||||
rx_callback = std::move(cb);
|
||||
}
|
||||
|
||||
virtual const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const = 0;
|
||||
virtual bool hasIPv4() const = 0;
|
||||
virtual bool hasIPv6() const = 0;
|
||||
|
||||
in_port_t getPort(sa_family_t family = AF_UNSPEC) const {
|
||||
return getBound(family).getPort();
|
||||
}
|
||||
|
||||
virtual void stop() = 0;
|
||||
protected:
|
||||
|
||||
inline void onReceived(std::unique_ptr<ReceivedPacket>&& packet) {
|
||||
if (rx_callback)
|
||||
rx_callback(std::move(packet));
|
||||
}
|
||||
private:
|
||||
OnReceive rx_callback;
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC UdpSocket : public DatagramSocket {
|
||||
public:
|
||||
UdpSocket(in_port_t port, const Logger& l = {});
|
||||
UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l = {});
|
||||
~UdpSocket();
|
||||
|
||||
int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) override;
|
||||
|
||||
const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const override {
|
||||
return (family == AF_INET6) ? bound6 : bound4;
|
||||
}
|
||||
|
||||
bool hasIPv4() const override { return s4 != -1; }
|
||||
bool hasIPv6() const override { return s6 != -1; }
|
||||
|
||||
void stop() override;
|
||||
private:
|
||||
Logger logger;
|
||||
int s4 {-1};
|
||||
int s6 {-1};
|
||||
int stopfd {-1};
|
||||
SockAddr bound4, bound6;
|
||||
std::thread rcv_thread {};
|
||||
std::atomic_bool running {false};
|
||||
|
||||
void openSockets(const SockAddr& bind4, const SockAddr& bind6);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "def.h"
|
||||
#include "sockaddr.h"
|
||||
#include "infohash.h"
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace dht {
|
||||
|
||||
class OPENDHT_PUBLIC PeerDiscovery
|
||||
{
|
||||
public:
|
||||
static constexpr in_port_t DEFAULT_PORT = 8888;
|
||||
using ServiceDiscoveredCallback = std::function<void(msgpack::object&&, SockAddr&&)>;
|
||||
|
||||
PeerDiscovery(in_port_t port = DEFAULT_PORT);
|
||||
~PeerDiscovery();
|
||||
|
||||
/**
|
||||
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
|
||||
*/
|
||||
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
|
||||
|
||||
template<typename T>
|
||||
void startDiscovery(const std::string &type, std::function<void(T&&, SockAddr&&)> cb) {
|
||||
startDiscovery(type, [cb](msgpack::object&& ob, SockAddr&& addr) {
|
||||
cb(ob.as<T>(), std::move(addr));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* startPublish - Keeping sending data until node is joinned or stop is called - msgpack
|
||||
*/
|
||||
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
|
||||
void startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf);
|
||||
|
||||
template<typename T>
|
||||
void startPublish(const std::string &type, const T& object) {
|
||||
msgpack::sbuffer buf;
|
||||
msgpack::pack(buf, object);
|
||||
startPublish(type, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread Stopper
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Remove possible callBack to discovery
|
||||
*/
|
||||
bool stopDiscovery(const std::string &type);
|
||||
|
||||
/**
|
||||
* Remove different serivce message to send
|
||||
*/
|
||||
bool stopPublish(const std::string &type);
|
||||
bool stopPublish(sa_family_t domain, const std::string &type);
|
||||
|
||||
/**
|
||||
* Configure the sockopt to be able to listen multicast group
|
||||
*/
|
||||
static void socketJoinMulticast(int sockfd, sa_family_t family);
|
||||
|
||||
/**
|
||||
* Join the threads
|
||||
*/
|
||||
void join();
|
||||
|
||||
private:
|
||||
class DomainPeerDiscovery;
|
||||
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
|
||||
std::unique_ptr<DomainPeerDiscovery> peerDiscovery6_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -43,8 +43,8 @@ public:
|
||||
* result_type is unsigned int so this is currently safe.
|
||||
*/
|
||||
static_assert(
|
||||
sizeof(result_type) == 2 ||
|
||||
sizeof(result_type) == 4 ||
|
||||
sizeof(result_type) == 2 ||
|
||||
sizeof(result_type) == 4 ||
|
||||
sizeof(result_type) == 8,
|
||||
"result_type must be 16, 32 or 64 bits");
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -42,6 +42,11 @@ struct Bucket {
|
||||
Sp<Node> randomNode();
|
||||
|
||||
void sendCachedPing(net::NetworkEngine& ne);
|
||||
void connectivityChanged() {
|
||||
time = time_point::min();
|
||||
for (auto& node : nodes)
|
||||
node->setTime(time_point::min());
|
||||
}
|
||||
};
|
||||
|
||||
class RoutingTable : public std::list<Bucket> {
|
||||
@@ -76,7 +81,7 @@ public:
|
||||
void connectivityChanged(const time_point& now) {
|
||||
grow_time = now;
|
||||
for (auto& b : *this)
|
||||
b.time = time_point::min();
|
||||
b.connectivityChanged();
|
||||
}
|
||||
|
||||
bool onNewNode(const Sp<Node>& node, int comfirm, const time_point& now, const InfoHash& myid, net::NetworkEngine& ne);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -21,7 +21,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils.h"
|
||||
#include "log_enable.h"
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
+19
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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>
|
||||
@@ -37,9 +37,9 @@ public:
|
||||
|
||||
using Config = SecureDhtConfig;
|
||||
|
||||
static dht::Config& getConfig(SecureDht::Config& conf)
|
||||
static dht::Config getConfig(const SecureDht::Config& conf)
|
||||
{
|
||||
auto& c = conf.node_config;
|
||||
auto c = conf.node_config;
|
||||
if (not c.node_id and conf.id.second)
|
||||
c.node_id = InfoHash::get("node:"+conf.id.second->getId().toString());
|
||||
return c;
|
||||
@@ -127,8 +127,8 @@ public:
|
||||
|
||||
Value decrypt(const Value& v);
|
||||
|
||||
void findCertificate(const InfoHash& node, std::function<void(const Sp<crypto::Certificate>)> cb);
|
||||
void findPublicKey(const InfoHash& node, std::function<void(const Sp<const crypto::PublicKey>)> cb);
|
||||
void findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb);
|
||||
void findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb);
|
||||
|
||||
const Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
|
||||
void registerCertificate(Sp<crypto::Certificate>& cert);
|
||||
@@ -168,7 +168,7 @@ public:
|
||||
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override {
|
||||
dht_->setStorageLimit(limit);
|
||||
}
|
||||
std::vector<NodeExport> exportNodes() override {
|
||||
std::vector<NodeExport> exportNodes() const override {
|
||||
return dht_->exportNodes();
|
||||
}
|
||||
std::vector<ValuesExport> exportValues() const override {
|
||||
@@ -195,8 +195,8 @@ public:
|
||||
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override {
|
||||
return dht_->getPublicAddress(family);
|
||||
}
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, const SockAddr& sa) override {
|
||||
return dht_->periodic(buf, buflen, sa);
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr sa) override {
|
||||
return dht_->periodic(buf, buflen, std::move(sa));
|
||||
}
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
|
||||
return dht_->periodic(buf, buflen, from, fromlen);
|
||||
@@ -207,6 +207,9 @@ public:
|
||||
NodeStatus getStatus() const override {
|
||||
return dht_->getStatus();
|
||||
}
|
||||
net::DatagramSocket* getSocket() const override {
|
||||
return dht_->getSocket();
|
||||
};
|
||||
bool isRunning(sa_family_t af = 0) const override {
|
||||
return dht_->isRunning(af);
|
||||
}
|
||||
@@ -231,7 +234,7 @@ public:
|
||||
void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override {
|
||||
dht_->query(key, cb, done_cb, std::move(q));
|
||||
}
|
||||
std::vector<Sp<Value>> getLocal(const InfoHash& key, Value::Filter f = Value::AllFilter()) const override {
|
||||
std::vector<Sp<Value>> getLocal(const InfoHash& key, const Value::Filter& f = {}) const override {
|
||||
return dht_->getLocal(key, f);
|
||||
}
|
||||
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const override {
|
||||
@@ -270,10 +273,10 @@ public:
|
||||
{
|
||||
dht_->put(key, std::move(v), cb, created, permanent);
|
||||
}
|
||||
std::vector<Sp<Value>> getPut(const InfoHash& h) override {
|
||||
std::vector<Sp<Value>> getPut(const InfoHash& h) const override {
|
||||
return dht_->getPut(h);
|
||||
}
|
||||
Sp<Value> getPut(const InfoHash& h, const Value::Id& vid) override {
|
||||
Sp<Value> getPut(const InfoHash& h, const Value::Id& vid) const override {
|
||||
return dht_->getPut(h, vid);
|
||||
}
|
||||
bool cancelPut(const InfoHash& h, const Value::Id& vid) override {
|
||||
@@ -311,10 +314,9 @@ public:
|
||||
dht_->pushNotificationReceived(notification);
|
||||
}
|
||||
|
||||
void setLoggers(LogMethod error = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG) override
|
||||
{
|
||||
DhtInterface::setLoggers(error, warn, debug);
|
||||
dht_->setLoggers(error, warn, debug);
|
||||
void setLogger(const Logger& logger) override {
|
||||
DhtInterface::setLogger(logger);
|
||||
dht_->setLogger(logger);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,8 +334,8 @@ private:
|
||||
SecureDht& operator=(const SecureDht&) = delete;
|
||||
|
||||
Sp<Value> checkValue(const Sp<Value>& v);
|
||||
ValueCallback getCallbackFilter(ValueCallback, Value::Filter&&);
|
||||
GetCallback getCallbackFilter(GetCallback, Value::Filter&&);
|
||||
ValueCallback getCallbackFilter(const ValueCallback&, Value::Filter&&);
|
||||
GetCallback getCallbackFilter(const GetCallback&, Value::Filter&&);
|
||||
|
||||
Sp<crypto::PrivateKey> key_ {};
|
||||
Sp<crypto::Certificate> certificate_ {};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#ifdef __ANDROID__
|
||||
typedef uint16_t in_port_t;
|
||||
#endif
|
||||
@@ -58,7 +59,7 @@ public:
|
||||
SockAddr(const SockAddr& o) {
|
||||
set(o.get(), o.getLength());
|
||||
}
|
||||
SockAddr(SockAddr&& o) : len(o.len), addr(std::move(o.addr)) {
|
||||
SockAddr(SockAddr&& o) noexcept : addr(std::move(o.addr)), len(o.len) {
|
||||
o.len = 0;
|
||||
}
|
||||
|
||||
@@ -118,7 +119,7 @@ public:
|
||||
/**
|
||||
* Returns the address family or AF_UNSPEC if the address is not set.
|
||||
*/
|
||||
sa_family_t getFamily() const { return len > sizeof(sa_family_t) ? addr->sa_family : AF_UNSPEC; }
|
||||
sa_family_t getFamily() const { return len ? addr->sa_family : AF_UNSPEC; }
|
||||
|
||||
/**
|
||||
* Resize the managed structure to the appropriate size (if needed),
|
||||
@@ -146,6 +147,21 @@ public:
|
||||
addr->sa_family = af;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Network Interface to any
|
||||
*/
|
||||
void setAny() {
|
||||
auto family = getFamily();
|
||||
switch(family) {
|
||||
case AF_INET:
|
||||
getIPv4().sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
break;
|
||||
case AF_INET6:
|
||||
getIPv6().sin6_addr = in6addr_any;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreive the port (in host byte order) or 0 if the address is not
|
||||
* of a supported family.
|
||||
@@ -175,6 +191,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address part of the socket address from a numeric IP address (string representation).
|
||||
* Family must be already set. Throws in case of parse failue.
|
||||
*/
|
||||
void setAddress(const char* address);
|
||||
|
||||
/**
|
||||
* Returns the accessible byte length at the pointer returned by #get().
|
||||
* If zero, #get() returns null.
|
||||
@@ -226,7 +248,8 @@ public:
|
||||
bool isUnspecified() const;
|
||||
|
||||
bool isMappedIPv4() const;
|
||||
SockAddr getMappedIPv4() const;
|
||||
SockAddr getMappedIPv4();
|
||||
SockAddr getMappedIPv6();
|
||||
|
||||
/**
|
||||
* A comparator to classify IP addresses, only considering the
|
||||
@@ -257,9 +280,9 @@ public:
|
||||
}
|
||||
};
|
||||
private:
|
||||
socklen_t len {0};
|
||||
struct free_delete { void operator()(void* p) { ::free(p); } };
|
||||
std::unique_ptr<sockaddr, free_delete> addr {};
|
||||
socklen_t len {0};
|
||||
|
||||
void set(const sockaddr* sa, socklen_t length) {
|
||||
if (len != length) {
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "def.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <future>
|
||||
#include <functional>
|
||||
|
||||
namespace dht {
|
||||
|
||||
class OPENDHT_PUBLIC ThreadPool {
|
||||
public:
|
||||
static ThreadPool& computation();
|
||||
static ThreadPool& io();
|
||||
|
||||
ThreadPool();
|
||||
ThreadPool(size_t maxThreads);
|
||||
~ThreadPool();
|
||||
|
||||
void run(std::function<void()>&& cb);
|
||||
|
||||
template<class T>
|
||||
std::future<T> get(std::function<T()>&& cb) {
|
||||
auto ret = std::make_shared<std::promise<T>>();
|
||||
run(std::bind([=](std::function<T()>& mcb) mutable {
|
||||
ret->set_value(mcb());
|
||||
}, std::move(cb)));
|
||||
return ret->get_future();
|
||||
}
|
||||
template<class T>
|
||||
std::shared_future<T> getShared(std::function<T()>&& cb) {
|
||||
return get(std::move(cb));
|
||||
}
|
||||
|
||||
void stop();
|
||||
void join();
|
||||
|
||||
private:
|
||||
struct ThreadState;
|
||||
std::queue<std::function<void()>> tasks_ {};
|
||||
std::vector<std::unique_ptr<ThreadState>> threads_;
|
||||
unsigned readyThreads_ {0};
|
||||
std::mutex lock_ {};
|
||||
std::condition_variable cv_ {};
|
||||
|
||||
const unsigned maxThreads_;
|
||||
bool running_ {true};
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC Executor : public std::enable_shared_from_this<Executor> {
|
||||
public:
|
||||
Executor(ThreadPool& pool, unsigned maxConcurrent = 1)
|
||||
: threadPool_(pool), maxConcurrent_(maxConcurrent)
|
||||
{}
|
||||
|
||||
void run(std::function<void()>&& task);
|
||||
|
||||
private:
|
||||
std::reference_wrapper<ThreadPool> threadPool_;
|
||||
const unsigned maxConcurrent_ {1};
|
||||
std::mutex lock_ {};
|
||||
unsigned current_ {0};
|
||||
std::queue<std::function<void()>> tasks_ {};
|
||||
|
||||
void run_(std::function<void()>&& task);
|
||||
void schedule();
|
||||
};
|
||||
|
||||
}
|
||||
+15
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -40,6 +40,8 @@ namespace dht {
|
||||
using NetId = uint32_t;
|
||||
using want_t = int_fast8_t;
|
||||
|
||||
OPENDHT_PUBLIC const char* version();
|
||||
|
||||
// shortcut for std::shared_ptr
|
||||
template<class T>
|
||||
using Sp = std::shared_ptr<T>;
|
||||
@@ -90,6 +92,18 @@ print_dt(DT d) {
|
||||
return std::chrono::duration_cast<std::chrono::duration<double>>(d).count();
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
static std::string
|
||||
print_duration(DT d) {
|
||||
if (d < std::chrono::milliseconds(1)) {
|
||||
return std::to_string(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
|
||||
} else if (d < std::chrono::seconds(1)) {
|
||||
return std::to_string(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
|
||||
} else {
|
||||
return std::to_string(print_dt(d)) + " s";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Duration = duration>
|
||||
class uniform_duration_distribution : public std::uniform_int_distribution<typename Duration::rep> {
|
||||
using Base = std::uniform_int_distribution<typename Duration::rep>;
|
||||
|
||||
+17
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -79,7 +79,7 @@ static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
|
||||
struct OPENDHT_PUBLIC ValueType {
|
||||
typedef uint16_t Id;
|
||||
|
||||
static bool DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
|
||||
static bool DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
|
||||
static bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&) {
|
||||
return false;
|
||||
}
|
||||
@@ -165,6 +165,13 @@ struct OPENDHT_PUBLIC Value
|
||||
return chainOr(std::move(f1), std::move(f2));
|
||||
}
|
||||
static Filter chain(Filter&& f1, Filter&& f2) {
|
||||
if (not f1) return std::move(f2);
|
||||
if (not f2) return std::move(f1);
|
||||
return [f1,f2](const Value& v) {
|
||||
return f1(v) and f2(v);
|
||||
};
|
||||
}
|
||||
static Filter chain(const Filter& f1, const Filter& f2) {
|
||||
if (not f1) return f2;
|
||||
if (not f2) return f1;
|
||||
return [f1,f2](const Value& v) {
|
||||
@@ -184,11 +191,15 @@ struct OPENDHT_PUBLIC Value
|
||||
return chainAll(std::vector<Filter>(l.begin(), l.end()));
|
||||
}
|
||||
static Filter chainOr(Filter&& f1, Filter&& f2) {
|
||||
if (not f1 or not f2) return AllFilter();
|
||||
if (not f1 or not f2) return {};
|
||||
return [f1,f2](const Value& v) {
|
||||
return f1(v) or f2(v);
|
||||
};
|
||||
}
|
||||
static Filter notFilter(Filter&& f) {
|
||||
if (not f) return [](const Value&) { return false; };
|
||||
return [f](const Value& v) { return not f(v); };
|
||||
}
|
||||
std::vector<Sp<Value>> filter(const std::vector<Sp<Value>>& values) {
|
||||
if (not (*this))
|
||||
return values;
|
||||
@@ -874,7 +885,7 @@ struct OPENDHT_PUBLIC Query
|
||||
{
|
||||
static const std::string QUERY_PARSE_ERROR;
|
||||
|
||||
Query(Select s = {}, Where w = {}, bool none = false) : select(s), where(w), none(none) { };
|
||||
Query(Select s = {}, Where w = {}, bool none = false) : select(std::move(s)), where(std::move(w)), none(none) { };
|
||||
|
||||
/**
|
||||
* Initializes a query based on a SQL-ish formatted string. The abstract
|
||||
@@ -936,7 +947,7 @@ struct OPENDHT_PUBLIC Query
|
||||
*/
|
||||
struct OPENDHT_PUBLIC FieldValueIndex {
|
||||
FieldValueIndex() {}
|
||||
FieldValueIndex(const Value& v, Select s = {});
|
||||
FieldValueIndex(const Value& v, const Select& s = {});
|
||||
/**
|
||||
* Tells if all the fields of this are contained in the other
|
||||
* FieldValueIndex with the same value.
|
||||
@@ -990,7 +1001,7 @@ template <typename T,
|
||||
Value::Filter
|
||||
getFilterSet()
|
||||
{
|
||||
return Value::AllFilter();
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
+8
-2
@@ -1,11 +1,11 @@
|
||||
# distutils: language = c++
|
||||
# distutils: extra_compile_args = -std=c++11
|
||||
# distutils: extra_compile_args = -std=c++14
|
||||
# distutils: include_dirs = ../../include
|
||||
# distutils: library_dirs = ../../src
|
||||
# distutils: libraries = opendht gnutls
|
||||
# cython: language_level=3
|
||||
#
|
||||
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author(s): Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
|
||||
# Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
# Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
@@ -139,6 +139,12 @@ cdef class SockAddr(object):
|
||||
return self._addr.setPort(port)
|
||||
def setFamily(SockAddr self, cpp.sa_family_t af):
|
||||
return self._addr.setFamily(af)
|
||||
def isLoopback(SockAddr self):
|
||||
return self._addr.isLoopback()
|
||||
def isPrivate(SockAddr self):
|
||||
return self._addr.isPrivate()
|
||||
def isUnspecified(SockAddr self):
|
||||
return self._addr.isUnspecified()
|
||||
def __str__(self):
|
||||
return self.toString().decode()
|
||||
def __repr__(self):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
# Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
#
|
||||
@@ -77,6 +77,9 @@ cdef extern from "opendht/sockaddr.h" namespace "dht":
|
||||
void setPort(in_port_t p)
|
||||
sa_family_t getFamily() const
|
||||
void setFamily(sa_family_t f)
|
||||
bool isLoopback() const
|
||||
bool isPrivate() const
|
||||
bool isUnspecified() const
|
||||
|
||||
ctypedef vector[uint8_t] Blob
|
||||
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2015-2017 Savoir-faire Linux Inc.
|
||||
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
@@ -50,8 +50,8 @@ setup(name="opendht",
|
||||
["@CURRENT_SOURCE_DIR@/opendht.pyx"],
|
||||
include_dirs = ['@PROJECT_SOURCE_DIR@/include'],
|
||||
language="c++",
|
||||
extra_compile_args=["-std=c++11"],
|
||||
extra_link_args=["-std=c++11"],
|
||||
extra_compile_args=["-std=c++14"],
|
||||
extra_link_args=["-std=c++14"],
|
||||
libraries=["opendht"],
|
||||
library_dirs = ['@CURRENT_BINARY_DIR@', '@PROJECT_BINARY_DIR@']
|
||||
))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
# Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
# Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
#
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2015 Savoir-Faire Linux Inc.
|
||||
# Copyright (C) 2015-2019 Savoir-Faire Linux Inc.
|
||||
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
# Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2015-2017 Savoir-faire Linux Inc.
|
||||
# Copyright (C) 2015-2019 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016 Savoir-faire Linux Inc.
|
||||
# Copyright (c) 2016-2019 Savoir-faire Linux Inc.
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015-2017 Savoir-faire Linux Inc.
|
||||
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -27,7 +27,7 @@ ping_node.run()
|
||||
pong_node = dht.DhtRunner()
|
||||
pong_node.run()
|
||||
#pong_node.enableLogging()
|
||||
pong_node.ping(ping_node.getBound());
|
||||
pong_node.ping(ping_node.getBound())
|
||||
|
||||
loc_ping = dht.InfoHash.get("toto99")
|
||||
loc_pong = dht.InfoHash.get(str(loc_ping))
|
||||
@@ -42,7 +42,7 @@ def done(h, ok):
|
||||
|
||||
def ping(node, h):
|
||||
global i
|
||||
time.sleep(0.0075)
|
||||
time.sleep(0.0075)
|
||||
i += 1
|
||||
if i < MAX:
|
||||
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
|
||||
@@ -51,7 +51,7 @@ def ping(node, h):
|
||||
|
||||
def pong(node, h):
|
||||
print(node.getNodeId().decode(), "got ping", h, i)
|
||||
loop.call_soon_threadsafe(ping, node, h);
|
||||
loop.call_soon_threadsafe(ping, node, h)
|
||||
return True
|
||||
|
||||
ping_node.listen(loc_ping, lambda v: pong(pong_node, loc_pong))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+9
-3
@@ -2,7 +2,7 @@ lib_LTLIBRARIES = libopendht.la
|
||||
|
||||
libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@
|
||||
libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@
|
||||
libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@
|
||||
libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
|
||||
libopendht_la_SOURCES = \
|
||||
dht.cpp \
|
||||
storage.h \
|
||||
@@ -26,7 +26,10 @@ libopendht_la_SOURCES = \
|
||||
securedht.cpp \
|
||||
dhtrunner.cpp \
|
||||
default_types.cpp \
|
||||
log.cpp
|
||||
log.cpp \
|
||||
peer_discovery.cpp \
|
||||
network_utils.cpp \
|
||||
thread_pool.cpp
|
||||
|
||||
if WIN32
|
||||
libopendht_la_SOURCES += rng.cpp
|
||||
@@ -53,7 +56,10 @@ nobase_include_HEADERS = \
|
||||
../include/opendht/default_types.h \
|
||||
../include/opendht/log.h \
|
||||
../include/opendht/log_enable.h \
|
||||
../include/opendht/rng.h
|
||||
../include/opendht/peer_discovery.h \
|
||||
../include/opendht/network_utils.h \
|
||||
../include/opendht/rng.h \
|
||||
../include/opendht/thread_pool.h
|
||||
|
||||
if ENABLE_PROXY_SERVER
|
||||
libopendht_la_SOURCES += dht_proxy_server.cpp
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* 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
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
/* Mainly based on the following stackoverflow question:
|
||||
* http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
+5
-5
@@ -4,7 +4,7 @@ namespace dht {
|
||||
|
||||
|
||||
GetCallbackSimple
|
||||
bindGetCb(GetCallbackRaw raw_cb, void* user_data)
|
||||
bindGetCb(const GetCallbackRaw& raw_cb, void* user_data)
|
||||
{
|
||||
if (not raw_cb) return {};
|
||||
return [=](const std::shared_ptr<Value>& value) {
|
||||
@@ -13,7 +13,7 @@ bindGetCb(GetCallbackRaw raw_cb, void* user_data)
|
||||
}
|
||||
|
||||
GetCallback
|
||||
bindGetCb(GetCallbackSimple cb)
|
||||
bindGetCb(const GetCallbackSimple& cb)
|
||||
{
|
||||
if (not cb) return {};
|
||||
return [=](const std::vector<std::shared_ptr<Value>>& values) {
|
||||
@@ -25,7 +25,7 @@ bindGetCb(GetCallbackSimple cb)
|
||||
}
|
||||
|
||||
ShutdownCallback
|
||||
bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data)
|
||||
bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data)
|
||||
{
|
||||
return [=]() { shutdown_cb_raw(user_data); };
|
||||
}
|
||||
@@ -39,7 +39,7 @@ bindDoneCb(DoneCallbackSimple donecb)
|
||||
}
|
||||
|
||||
DoneCallback
|
||||
bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
|
||||
bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data)
|
||||
{
|
||||
if (not raw_cb) return {};
|
||||
return [=](bool success, const std::vector<std::shared_ptr<Node>>& nodes) {
|
||||
@@ -48,7 +48,7 @@ bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
|
||||
}
|
||||
|
||||
DoneCallbackSimple
|
||||
bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) {
|
||||
bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data) {
|
||||
if (not raw_cb) return {};
|
||||
return [=](bool success) {
|
||||
raw_cb(success, user_data);
|
||||
|
||||
+281
-106
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -31,6 +31,7 @@ extern "C" {
|
||||
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
|
||||
@@ -40,31 +41,6 @@ static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint
|
||||
static std::uniform_int_distribution<uint8_t> rand_byte;
|
||||
#endif
|
||||
|
||||
static gnutls_digest_algorithm_t get_dig_for_pub(gnutls_pubkey_t pubkey)
|
||||
{
|
||||
gnutls_digest_algorithm_t dig;
|
||||
int result = gnutls_pubkey_get_preferred_hash_algorithm(pubkey, &dig, nullptr);
|
||||
if (result < 0)
|
||||
return GNUTLS_DIG_UNKNOWN;
|
||||
return dig;
|
||||
}
|
||||
|
||||
static gnutls_digest_algorithm_t get_dig(gnutls_x509_crt_t crt)
|
||||
{
|
||||
gnutls_pubkey_t pubkey;
|
||||
gnutls_pubkey_init(&pubkey);
|
||||
|
||||
int result = gnutls_pubkey_import_x509(pubkey, crt, 0);
|
||||
if (result < 0) {
|
||||
gnutls_pubkey_deinit(pubkey);
|
||||
return GNUTLS_DIG_UNKNOWN;
|
||||
}
|
||||
|
||||
gnutls_digest_algorithm_t dig = get_dig_for_pub(pubkey);
|
||||
gnutls_pubkey_deinit(pubkey);
|
||||
return dig;
|
||||
}
|
||||
|
||||
// support for GnuTLS < 3.4.
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030400
|
||||
#define GNUTLS_PKCS_PKCS12_3DES GNUTLS_PKCS_USE_PKCS12_3DES
|
||||
@@ -377,15 +353,19 @@ PrivateKey::serialize(const std::string& password) const
|
||||
PublicKey
|
||||
PrivateKey::getPublicKey() const
|
||||
{
|
||||
gnutls_pubkey_t pk;
|
||||
gnutls_pubkey_init(&pk);
|
||||
PublicKey pk_ret {pk};
|
||||
if (gnutls_pubkey_import_privkey(pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0) != GNUTLS_E_SUCCESS)
|
||||
return {};
|
||||
return pk_ret;
|
||||
PublicKey pk;
|
||||
if (auto err = gnutls_pubkey_import_privkey(pk.pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
|
||||
throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
|
||||
return pk;
|
||||
}
|
||||
|
||||
PublicKey::PublicKey(const Blob& dat) : pk(nullptr)
|
||||
PublicKey::PublicKey()
|
||||
{
|
||||
if (auto err = gnutls_pubkey_init(&pk))
|
||||
throw CryptoException(std::string("Can't initialize public key: ") + gnutls_strerror(err));
|
||||
}
|
||||
|
||||
PublicKey::PublicKey(const Blob& dat) : PublicKey()
|
||||
{
|
||||
unpack(dat.data(), dat.size());
|
||||
}
|
||||
@@ -415,8 +395,7 @@ PublicKey::pack(Blob& b) const
|
||||
throw CryptoException(std::string("Could not export public key: null key"));
|
||||
std::vector<uint8_t> tmp(2048);
|
||||
size_t sz = tmp.size();
|
||||
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz);
|
||||
if (err != GNUTLS_E_SUCCESS)
|
||||
if (int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz))
|
||||
throw CryptoException(std::string("Could not export public key: ") + gnutls_strerror(err));
|
||||
tmp.resize(sz);
|
||||
b.insert(b.end(), tmp.begin(), tmp.end());
|
||||
@@ -425,9 +404,6 @@ PublicKey::pack(Blob& b) const
|
||||
void
|
||||
PublicKey::unpack(const uint8_t* data, size_t data_size)
|
||||
{
|
||||
if (pk)
|
||||
gnutls_pubkey_deinit(pk);
|
||||
gnutls_pubkey_init(&pk);
|
||||
const gnutls_datum_t dat {(uint8_t*)data, (unsigned)data_size};
|
||||
int err = gnutls_pubkey_import(pk, &dat, GNUTLS_X509_FMT_PEM);
|
||||
if (err != GNUTLS_E_SUCCESS)
|
||||
@@ -446,10 +422,9 @@ PublicKey::toString() const
|
||||
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
|
||||
if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) {
|
||||
ret.resize(sz);
|
||||
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
|
||||
if (err != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException(std::string("Could not print public key: ") + gnutls_strerror(err));
|
||||
} else if (err != GNUTLS_E_SUCCESS)
|
||||
err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
|
||||
}
|
||||
if (err != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException(std::string("Could not print public key: ") + gnutls_strerror(err));
|
||||
return ret;
|
||||
}
|
||||
@@ -572,7 +547,180 @@ PublicKey::getLongId() const
|
||||
#endif
|
||||
}
|
||||
|
||||
Certificate::Certificate(const Blob& certData) : cert(nullptr)
|
||||
gnutls_digest_algorithm_t
|
||||
PublicKey::getPreferredDigest() const
|
||||
{
|
||||
gnutls_digest_algorithm_t dig;
|
||||
int result = gnutls_pubkey_get_preferred_hash_algorithm(pk, &dig, nullptr);
|
||||
if (result < 0)
|
||||
return GNUTLS_DIG_UNKNOWN;
|
||||
return dig;
|
||||
}
|
||||
|
||||
// Certificate Request
|
||||
|
||||
static NameType
|
||||
typeFromGnuTLS(gnutls_x509_subject_alt_name_t type)
|
||||
{
|
||||
switch(type) {
|
||||
case GNUTLS_SAN_DNSNAME:
|
||||
return NameType::DNS;
|
||||
case GNUTLS_SAN_RFC822NAME:
|
||||
return NameType::RFC822;
|
||||
case GNUTLS_SAN_URI:
|
||||
return NameType::URI;
|
||||
case GNUTLS_SAN_IPADDRESS:
|
||||
return NameType::IP;
|
||||
default:
|
||||
return NameType::UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static gnutls_x509_subject_alt_name_t
|
||||
GnuTLSFromType(NameType type)
|
||||
{
|
||||
switch(type) {
|
||||
case NameType::DNS:
|
||||
return GNUTLS_SAN_DNSNAME;
|
||||
case NameType::RFC822:
|
||||
return GNUTLS_SAN_RFC822NAME;
|
||||
case NameType::URI:
|
||||
return GNUTLS_SAN_URI;
|
||||
case NameType::IP:
|
||||
return GNUTLS_SAN_IPADDRESS;
|
||||
default:
|
||||
return (gnutls_x509_subject_alt_name_t)0;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string
|
||||
getDN(gnutls_x509_crq_t request, const char* oid)
|
||||
{
|
||||
std::string dn;
|
||||
dn.resize(512);
|
||||
size_t dn_sz = dn.size();
|
||||
int ret = gnutls_x509_crq_get_dn_by_oid(request, oid, 0, 0, &(*dn.begin()), &dn_sz);
|
||||
if (ret != GNUTLS_E_SUCCESS)
|
||||
return {};
|
||||
dn.resize(dn_sz);
|
||||
return dn;
|
||||
}
|
||||
|
||||
CertificateRequest::CertificateRequest()
|
||||
{
|
||||
if (auto err = gnutls_x509_crq_init(&request))
|
||||
throw CryptoException(std::string("Can't initialize certificate request: ") + gnutls_strerror(err));
|
||||
}
|
||||
|
||||
CertificateRequest::CertificateRequest(const uint8_t* data, size_t size) : CertificateRequest()
|
||||
{
|
||||
const gnutls_datum_t dat {(uint8_t*)data, (unsigned)size};
|
||||
if (auto err = gnutls_x509_crq_import(request, &dat, GNUTLS_X509_FMT_PEM))
|
||||
throw CryptoException(std::string("Can't import certificate request: ") + gnutls_strerror(err));
|
||||
}
|
||||
|
||||
CertificateRequest::~CertificateRequest()
|
||||
{
|
||||
if (request) {
|
||||
gnutls_x509_crq_deinit(request);
|
||||
request = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CertificateRequest&
|
||||
CertificateRequest::operator=(CertificateRequest&& o) noexcept
|
||||
{
|
||||
if (request)
|
||||
gnutls_x509_crq_deinit(request);
|
||||
request = o.request;
|
||||
o.request = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
CertificateRequest::setAltName(NameType type, const std::string& name)
|
||||
{
|
||||
gnutls_x509_crq_set_subject_alt_name(request, GnuTLSFromType(type), name.data(), name.size(), 0);
|
||||
}
|
||||
|
||||
void
|
||||
CertificateRequest::setName(const std::string& name)
|
||||
{
|
||||
gnutls_x509_crq_set_dn_by_oid(request, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
|
||||
}
|
||||
|
||||
std::string
|
||||
CertificateRequest::getName() const
|
||||
{
|
||||
return getDN(request, GNUTLS_OID_X520_COMMON_NAME);
|
||||
}
|
||||
|
||||
std::string
|
||||
CertificateRequest::getUID() const
|
||||
{
|
||||
return getDN(request, GNUTLS_OID_LDAP_UID);
|
||||
}
|
||||
|
||||
void
|
||||
CertificateRequest::setUID(const std::string& uid)
|
||||
{
|
||||
gnutls_x509_crq_set_dn_by_oid(request, GNUTLS_OID_LDAP_UID, 0, uid.data(), uid.length());
|
||||
}
|
||||
|
||||
void
|
||||
CertificateRequest::sign(const PrivateKey& key, const std::string& password)
|
||||
{
|
||||
gnutls_x509_crq_set_version(request, 1);
|
||||
if (not password.empty())
|
||||
gnutls_x509_crq_set_challenge_password(request, password.c_str());
|
||||
|
||||
if (auto err = gnutls_x509_crq_set_key(request, key.x509_key))
|
||||
throw CryptoException(std::string("Can't set certificate request key: ") + gnutls_strerror(err));
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030601
|
||||
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, key.getPublicKey().getPreferredDigest(), 0))
|
||||
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
|
||||
#else
|
||||
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, GNUTLS_DIG_UNKNOWN, 0))
|
||||
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
CertificateRequest::verify() const
|
||||
{
|
||||
return gnutls_x509_crq_verify(request, 0) >= 0;
|
||||
}
|
||||
|
||||
Blob
|
||||
CertificateRequest::pack() const
|
||||
{
|
||||
gnutls_datum_t dat {nullptr, 0};
|
||||
if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat))
|
||||
throw CryptoException(std::string("Can't export certificate request: ") + gnutls_strerror(err));
|
||||
Blob ret(dat.data, dat.data + dat.size);
|
||||
gnutls_free(dat.data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Certificate
|
||||
|
||||
static std::string
|
||||
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
|
||||
{
|
||||
std::string dn;
|
||||
dn.resize(512);
|
||||
size_t dn_sz = dn.size();
|
||||
int ret = issuer
|
||||
? gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, 0, 0, &(*dn.begin()), &dn_sz)
|
||||
: gnutls_x509_crt_get_dn_by_oid( cert, oid, 0, 0, &(*dn.begin()), &dn_sz);
|
||||
if (ret != GNUTLS_E_SUCCESS)
|
||||
return {};
|
||||
dn.resize(dn_sz);
|
||||
return dn;
|
||||
}
|
||||
|
||||
Certificate::Certificate(const Blob& certData)
|
||||
{
|
||||
unpack(certData.data(), certData.size());
|
||||
}
|
||||
@@ -656,11 +804,9 @@ Certificate::~Certificate()
|
||||
PublicKey
|
||||
Certificate::getPublicKey() const
|
||||
{
|
||||
gnutls_pubkey_t pk;
|
||||
gnutls_pubkey_init(&pk);
|
||||
PublicKey pk_ret(pk);
|
||||
if (gnutls_pubkey_import_x509(pk, cert, 0) != GNUTLS_E_SUCCESS)
|
||||
return {};
|
||||
PublicKey pk_ret;
|
||||
if (auto err = gnutls_pubkey_import_x509(pk_ret.pk, cert, 0))
|
||||
throw CryptoException(std::string("Can't get certificate public key: ") + gnutls_strerror(err));
|
||||
return pk_ret;
|
||||
}
|
||||
|
||||
@@ -696,21 +842,6 @@ Certificate::getLongId() const
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::string
|
||||
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
|
||||
{
|
||||
std::string dn;
|
||||
dn.resize(512);
|
||||
size_t dn_sz = dn.size();
|
||||
int ret = issuer
|
||||
? gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, 0, 0, &(*dn.begin()), &dn_sz)
|
||||
: gnutls_x509_crt_get_dn_by_oid( cert, oid, 0, 0, &(*dn.begin()), &dn_sz);
|
||||
if (ret != GNUTLS_E_SUCCESS)
|
||||
return {};
|
||||
dn.resize(dn_sz);
|
||||
return dn;
|
||||
}
|
||||
|
||||
std::string
|
||||
Certificate::getName() const
|
||||
{
|
||||
@@ -735,24 +866,7 @@ Certificate::getIssuerUID() const
|
||||
return getDN(cert, GNUTLS_OID_LDAP_UID, true);
|
||||
}
|
||||
|
||||
static Certificate::NameType
|
||||
typeFromGnuTLS(gnutls_x509_subject_alt_name_t type)
|
||||
{
|
||||
switch(type) {
|
||||
case GNUTLS_SAN_DNSNAME:
|
||||
return Certificate::NameType::DNS;
|
||||
case GNUTLS_SAN_RFC822NAME:
|
||||
return Certificate::NameType::RFC822;
|
||||
case GNUTLS_SAN_URI:
|
||||
return Certificate::NameType::URI;
|
||||
case GNUTLS_SAN_IPADDRESS:
|
||||
return Certificate::NameType::IP;
|
||||
default:
|
||||
return Certificate::NameType::UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<Certificate::NameType, std::string>>
|
||||
std::vector<std::pair<NameType, std::string>>
|
||||
Certificate::getAltNames() const
|
||||
{
|
||||
std::vector<std::pair<NameType, std::string>> names;
|
||||
@@ -867,6 +981,14 @@ Certificate::getExpiration() const
|
||||
return std::chrono::system_clock::from_time_t(t);
|
||||
}
|
||||
|
||||
gnutls_digest_algorithm_t
|
||||
Certificate::getPreferredDigest() const
|
||||
{
|
||||
return getPublicKey().getPreferredDigest();
|
||||
}
|
||||
|
||||
// PrivateKey
|
||||
|
||||
PrivateKey
|
||||
PrivateKey::generate(unsigned key_length)
|
||||
{
|
||||
@@ -896,7 +1018,7 @@ PrivateKey::generateEC()
|
||||
}
|
||||
|
||||
Identity
|
||||
generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_length, bool is_ca)
|
||||
generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca)
|
||||
{
|
||||
auto key = std::make_shared<PrivateKey>(PrivateKey::generate(key_length));
|
||||
auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
|
||||
@@ -905,12 +1027,12 @@ generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_leng
|
||||
|
||||
|
||||
Identity
|
||||
generateIdentity(const std::string& name, Identity ca, unsigned key_length) {
|
||||
generateIdentity(const std::string& name, const Identity& ca, unsigned key_length) {
|
||||
return generateIdentity(name, ca, key_length, !ca.first || !ca.second);
|
||||
}
|
||||
|
||||
Identity
|
||||
generateEcIdentity(const std::string& name, crypto::Identity ca, bool is_ca)
|
||||
generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca)
|
||||
{
|
||||
auto key = std::make_shared<PrivateKey>(PrivateKey::generateEC());
|
||||
auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
|
||||
@@ -918,25 +1040,55 @@ generateEcIdentity(const std::string& name, crypto::Identity ca, bool is_ca)
|
||||
}
|
||||
|
||||
Identity
|
||||
generateEcIdentity(const std::string& name, Identity ca) {
|
||||
generateEcIdentity(const std::string& name, const Identity& ca) {
|
||||
return generateEcIdentity(name, ca, !ca.first || !ca.second);
|
||||
}
|
||||
|
||||
void
|
||||
saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password)
|
||||
{
|
||||
{
|
||||
auto ca_key_data = id.first->serialize(privkey_password);
|
||||
std::ofstream key_file(path + ".pem");
|
||||
key_file.write((char*)ca_key_data.data(), ca_key_data.size());
|
||||
}
|
||||
{
|
||||
auto ca_key_data = id.second->getPacked();
|
||||
std::ofstream crt_file(path + ".crt");
|
||||
crt_file.write((char*)ca_key_data.data(), ca_key_data.size());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
setValidityPeriod(gnutls_x509_crt_t cert, int64_t validity)
|
||||
{
|
||||
int64_t now = time(nullptr);
|
||||
/* 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 + validity));
|
||||
}
|
||||
|
||||
void
|
||||
setRandomSerial(gnutls_x509_crt_t cert)
|
||||
{
|
||||
random_device rdev;
|
||||
std::uniform_int_distribution<uint64_t> dist{};
|
||||
uint64_t cert_serial = dist(rdev);
|
||||
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
|
||||
}
|
||||
|
||||
Certificate
|
||||
Certificate::generate(const PrivateKey& key, const std::string& name, Identity ca, bool is_ca)
|
||||
Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca)
|
||||
{
|
||||
gnutls_x509_crt_t cert;
|
||||
if (not key.x509_key or gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS)
|
||||
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)));
|
||||
setValidityPeriod(cert, 10 * 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 {};
|
||||
@@ -947,19 +1099,15 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
|
||||
}
|
||||
|
||||
// TODO: compute the subject key using the recommended RFC method
|
||||
auto pk_id = key.getPublicKey().getId();
|
||||
auto pk = key.getPublicKey();
|
||||
auto pk_id = pk.getId();
|
||||
const std::string uid_str = pk_id.toString();
|
||||
|
||||
gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id));
|
||||
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
|
||||
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length());
|
||||
|
||||
{
|
||||
random_device rdev;
|
||||
std::uniform_int_distribution<uint64_t> dist{};
|
||||
uint64_t cert_serial = dist(rdev);
|
||||
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
|
||||
}
|
||||
setRandomSerial(cert);
|
||||
|
||||
unsigned key_usage = 0;
|
||||
if (is_ca) {
|
||||
@@ -975,15 +1123,13 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
|
||||
// Signing certificate must be CA.
|
||||
return {};
|
||||
}
|
||||
//if (gnutls_x509_crt_sign2(cert, ca.second->cert, ca.first->x509_key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
|
||||
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
|
||||
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
|
||||
std::cerr << "Error when signing certificate" << std::endl;
|
||||
return {};
|
||||
}
|
||||
ret.issuer = ca.second;
|
||||
} else {
|
||||
//if (gnutls_x509_crt_sign2(cert, cert, key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
|
||||
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
|
||||
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
|
||||
std::cerr << "Error when signing certificate" << std::endl;
|
||||
return {};
|
||||
}
|
||||
@@ -992,6 +1138,31 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
|
||||
return ret.getPacked();
|
||||
}
|
||||
|
||||
Certificate
|
||||
Certificate::generate(const CertificateRequest& request, const Identity& ca)
|
||||
{
|
||||
gnutls_x509_crt_t cert;
|
||||
if (auto err = gnutls_x509_crt_init(&cert))
|
||||
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
|
||||
Certificate ret {cert};
|
||||
if (auto err = gnutls_x509_crt_set_crq(cert, request.get()))
|
||||
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
|
||||
|
||||
if (auto err = gnutls_x509_crt_set_version(cert, 3)) {
|
||||
throw CryptoException(std::string("Can't set certificate version: ") + gnutls_strerror(err));
|
||||
}
|
||||
|
||||
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
|
||||
setRandomSerial(cert);
|
||||
|
||||
if (auto err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) {
|
||||
throw CryptoException(std::string("Can't sign certificate: ") + gnutls_strerror(err));
|
||||
}
|
||||
ret.issuer = ca.second;
|
||||
|
||||
return ret.getPacked();
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<RevocationList>>
|
||||
Certificate::getRevocationLists() const
|
||||
{
|
||||
@@ -1002,6 +1173,8 @@ Certificate::getRevocationLists() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
// RevocationList
|
||||
|
||||
RevocationList::RevocationList()
|
||||
{
|
||||
gnutls_x509_crl_init(&crl);
|
||||
@@ -1219,6 +1392,8 @@ RevocationList::toString() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TrustList
|
||||
|
||||
TrustList::TrustList() {
|
||||
gnutls_x509_trust_list_init(&trust, 0);
|
||||
}
|
||||
@@ -1228,11 +1403,11 @@ TrustList::~TrustList() {
|
||||
}
|
||||
|
||||
TrustList&
|
||||
TrustList::operator=(TrustList&& o)
|
||||
TrustList::operator=(TrustList&& o) noexcept
|
||||
{
|
||||
if (trust)
|
||||
gnutls_x509_trust_list_deinit(trust, true);
|
||||
trust = std::move(o.trust);
|
||||
trust = o.trust;
|
||||
o.trust = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -38,7 +38,7 @@ DhtMessage::storePolicy(InfoHash h, std::shared_ptr<Value>& v, const InfoHash& f
|
||||
}
|
||||
|
||||
Value::Filter
|
||||
DhtMessage::ServiceFilter(std::string s)
|
||||
DhtMessage::ServiceFilter(const std::string& s)
|
||||
{
|
||||
return Value::Filter::chain(
|
||||
Value::TypeFilter(TYPE),
|
||||
|
||||
+243
-212
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
namespace dht {
|
||||
|
||||
@@ -54,6 +55,9 @@ Dht::getStatus(sa_family_t af) const
|
||||
void
|
||||
Dht::shutdown(ShutdownCallback cb)
|
||||
{
|
||||
if (not persistPath.empty())
|
||||
saveState(persistPath);
|
||||
|
||||
if (not maintain_storage) {
|
||||
if (cb) cb();
|
||||
return;
|
||||
@@ -125,19 +129,16 @@ Dht::trySearchInsert(const Sp<Node>& node)
|
||||
bool inserted {false};
|
||||
|
||||
// insert forward
|
||||
auto it = closest;
|
||||
while (it != srs.end()) {
|
||||
for (auto it = closest; it != srs.end(); it++) {
|
||||
auto& s = *it->second;
|
||||
if (s.insertNode(node, now)) {
|
||||
inserted = true;
|
||||
scheduler.edit(s.nextSearchStep, now);
|
||||
} else if (not s.expired and not s.done)
|
||||
break;
|
||||
++it;
|
||||
}
|
||||
// insert backward
|
||||
it = closest;
|
||||
while (it != srs.begin()) {
|
||||
for (auto it = closest; it != srs.begin();) {
|
||||
--it;
|
||||
auto& s = *it->second;
|
||||
if (s.insertNode(node, now)) {
|
||||
@@ -167,8 +168,14 @@ Dht::reportedAddr(const SockAddr& addr)
|
||||
void
|
||||
Dht::onNewNode(const Sp<Node>& node, int confirm)
|
||||
{
|
||||
if (buckets(node->getFamily()).onNewNode(node, confirm, scheduler.time(), myid, network_engine) or confirm) {
|
||||
const auto& now = scheduler.time();
|
||||
auto& b = buckets(node->getFamily());
|
||||
auto wasEmpty = confirm < 2 && b.grow_time < now - std::chrono::minutes(5);
|
||||
if (b.onNewNode(node, confirm, now, myid, network_engine) or confirm) {
|
||||
trySearchInsert(node);
|
||||
if (wasEmpty) {
|
||||
scheduler.edit(nextNodesConfirmation, now + std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +286,7 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
|
||||
if (vid == Value::INVALID_ID) continue;
|
||||
auto query_for_vid = std::make_shared<Query>(Select {}, Where {}.id(vid));
|
||||
sn->pagination_queries[query].push_back(query_for_vid);
|
||||
DHT_LOG.w(id, sn->node->id, "[search %s] [node %s] sending %s",
|
||||
DHT_LOG.d(id, sn->node->id, "[search %s] [node %s] sending %s",
|
||||
id.toString().c_str(), sn->node->toString().c_str(), query_for_vid->toString().c_str());
|
||||
sn->getStatus[query_for_vid] = network_engine.sendGetValues(status.node,
|
||||
id,
|
||||
@@ -298,7 +305,7 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
|
||||
/* add pagination query key for tracking ongoing requests. */
|
||||
n->pagination_queries[query].push_back(select_q);
|
||||
|
||||
DHT_LOG.w(sr->id, n->node->id, "[search %s] [node %s] sending %s",
|
||||
DHT_LOG.d(sr->id, n->node->id, "[search %s] [node %s] sending %s",
|
||||
sr->id.toString().c_str(), n->node->toString().c_str(), select_q->toString().c_str());
|
||||
n->getStatus[select_q] = network_engine.sendGetValues(n->node,
|
||||
sr->id,
|
||||
@@ -432,24 +439,20 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
|
||||
auto next_refresh_time = now + getType(a.value->type).expiration;
|
||||
/* only put the value if the node doesn't already have it */
|
||||
if (not hasValue or seq_no < a.value->seq) {
|
||||
DHT_LOG.w(sr->id, sn->node->id, "[search %s] [node %s] sending 'put' (vid: %d)",
|
||||
DHT_LOG.d(sr->id, sn->node->id, "[search %s] [node %s] sending 'put' (vid: %d)",
|
||||
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
|
||||
sn->acked[a.value->id] = std::make_pair(network_engine.sendAnnounceValue(sn->node,
|
||||
sr->id,
|
||||
a.value,
|
||||
a.permanent ? time_point::max() : a.created,
|
||||
sn->token,
|
||||
onDone,
|
||||
onExpired), next_refresh_time);
|
||||
auto created = a.permanent ? time_point::max() : a.created;
|
||||
sn->acked[a.value->id] = {
|
||||
network_engine.sendAnnounceValue(sn->node, sr->id, a.value, created, sn->token, onDone, onExpired),
|
||||
next_refresh_time
|
||||
};
|
||||
} else if (hasValue and a.permanent) {
|
||||
DHT_LOG.w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %d)",
|
||||
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
|
||||
sn->acked[a.value->id] = std::make_pair(network_engine.sendRefreshValue(sn->node,
|
||||
sr->id,
|
||||
a.value->id,
|
||||
sn->token,
|
||||
onDone,
|
||||
onExpired), next_refresh_time);
|
||||
sn->acked[a.value->id] = {
|
||||
network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone, onExpired),
|
||||
next_refresh_time
|
||||
};
|
||||
} else {
|
||||
DHT_LOG.w(sr->id, sn->node->id, "[search %s] [node %s] already has value (vid: %d). Aborting.",
|
||||
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
|
||||
@@ -500,7 +503,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
|
||||
if (sendQuery) {
|
||||
if (not probe_query)
|
||||
probe_query = std::make_shared<Query>(Select {}.field(Value::Field::Id).field(Value::Field::SeqNum));
|
||||
DHT_LOG.w(sr->id, n.node->id, "[search %s] [node %s] sending %s",
|
||||
DHT_LOG.d(sr->id, n.node->id, "[search %s] [node %s] sending %s",
|
||||
sr->id.toString().c_str(), n.node->toString().c_str(), probe_query->toString().c_str());
|
||||
n.probe_query = probe_query;
|
||||
n.getStatus[probe_query] = network_engine.sendGetValues(n.node,
|
||||
@@ -524,8 +527,8 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
|
||||
auto list_token = l.first;
|
||||
if (n.getListenTime(query) > scheduler.time())
|
||||
continue;
|
||||
DHT_LOG.w(sr->id, n.node->id, "[search %s] [node %s] sending 'listen'",
|
||||
sr->id.toString().c_str(), n.node->toString().c_str());
|
||||
// DHT_LOG.d(sr->id, n.node->id, "[search %s] [node %s] sending 'listen'",
|
||||
// sr->id.toString().c_str(), n.node->toString().c_str());
|
||||
|
||||
auto r = n.listenStatus.find(query);
|
||||
if (r == n.listenStatus.end()) {
|
||||
@@ -534,7 +537,14 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
|
||||
if (auto sr = ws.lock()) {
|
||||
auto l = sr->listeners.find(list_token);
|
||||
if (l != sr->listeners.end()) {
|
||||
l->second.get_cb(l->second.filter.filter(values), expired);
|
||||
l->second.get_cb(values, expired);
|
||||
}
|
||||
}
|
||||
}, [ws,list_token] (ListenSyncStatus status) {
|
||||
if (auto sr = ws.lock()) {
|
||||
auto l = sr->listeners.find(list_token);
|
||||
if (l != sr->listeners.end()) {
|
||||
l->second.sync_cb(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,8 +564,10 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
|
||||
{ /* on done */
|
||||
if (auto sr = ws.lock()) {
|
||||
scheduler.edit(sr->nextSearchStep, scheduler.time());
|
||||
if (auto sn = sr->getNode(req.node))
|
||||
if (auto sn = sr->getNode(req.node)) {
|
||||
scheduler.add(sn->getListenTime(query), std::bind(&Dht::searchStep, this, sr));
|
||||
sn->onListenSynced(query);
|
||||
}
|
||||
onListenDone(req.node, answer, sr);
|
||||
}
|
||||
},
|
||||
@@ -595,9 +607,9 @@ Dht::searchStep(Sp<Search> sr)
|
||||
if (not sr or sr->expired or sr->done) return;
|
||||
|
||||
const auto& now = scheduler.time();
|
||||
if (auto req_count = sr->currentlySolicitedNodeCount())
|
||||
/*if (auto req_count = sr->currentlySolicitedNodeCount())
|
||||
DHT_LOG.d(sr->id, "[search %s IPv%c] step (%d requests)",
|
||||
sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6', req_count);
|
||||
sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6', req_count);*/
|
||||
sr->step_time = now;
|
||||
|
||||
if (sr->refill_time + Node::NODE_EXPIRE_TIME < now and sr->nodes.size()-sr->getNumberOfBadNodes() < SEARCH_NODES)
|
||||
@@ -656,18 +668,7 @@ Dht::searchStep(Sp<Search> sr)
|
||||
sr->setDone();
|
||||
}
|
||||
|
||||
if (sr->currentlySolicitedNodeCount() < MAX_REQUESTED_SEARCH_NODES) {
|
||||
unsigned i = 0;
|
||||
SearchNode* sent;
|
||||
do {
|
||||
sent = searchSendGetValues(sr);
|
||||
if (sent and not sent->candidate)
|
||||
i++;
|
||||
}
|
||||
while (sent and sr->currentlySolicitedNodeCount() < MAX_REQUESTED_SEARCH_NODES);
|
||||
/*DHT_LOG_DBG("[search %s IPv%c] step: sent %u requests (total %u).",
|
||||
sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6', i, sr->currentlySolicitedNodeCount());*/
|
||||
}
|
||||
while (sr->currentlySolicitedNodeCount() < MAX_REQUESTED_SEARCH_NODES and searchSendGetValues(sr));
|
||||
|
||||
if (sr->getNumberOfConsecutiveBadNodes() >= std::min(sr->nodes.size(),
|
||||
static_cast<size_t>(SEARCH_MAX_BAD_NODES)))
|
||||
@@ -678,10 +679,6 @@ Dht::searchStep(Sp<Search> sr)
|
||||
}
|
||||
|
||||
/* dumpSearch(*sr, std::cout); */
|
||||
|
||||
/* periodic searchStep scheduling. */
|
||||
//if (not sr->done)
|
||||
// scheduler.edit(sr->nextSearchStep, now);
|
||||
}
|
||||
|
||||
unsigned Dht::refill(Dht::Search& sr) {
|
||||
@@ -839,39 +836,31 @@ Dht::listen(const InfoHash& id, ValueCallback cb, Value::Filter f, Where where)
|
||||
{
|
||||
scheduler.syncTime();
|
||||
|
||||
Query q {{}, where};
|
||||
auto vals = std::make_shared<std::map<Value::Id, Sp<Value>>>();
|
||||
auto token = ++listener_token;
|
||||
auto gcb = OpValueCache::cacheCallback(std::move(cb), [this, id, token]{
|
||||
cancelListen(id, token);
|
||||
});
|
||||
|
||||
auto gcb = OpValueCache::cacheCallback(std::move(cb));
|
||||
|
||||
auto query = std::make_shared<Query>(q);
|
||||
auto filter = f.chain(q.where.getFilter());
|
||||
size_t tokenlocal = 0;
|
||||
auto query = std::make_shared<Query>(Select{}, std::move(where));
|
||||
auto filter = f.chain(query->where.getFilter());
|
||||
auto st = store.find(id);
|
||||
if (st == store.end() && store.size() < MAX_HASHES)
|
||||
st = store.emplace(id, Storage(scheduler.time() + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME)).first;
|
||||
st = store.emplace(id, scheduler.time() + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME).first;
|
||||
|
||||
size_t tokenlocal = 0;
|
||||
if (st != store.end()) {
|
||||
if (not st->second.empty()) {
|
||||
std::vector<Sp<Value>> newvals = st->second.get(filter);
|
||||
if (not newvals.empty()) {
|
||||
if (!gcb(newvals, false))
|
||||
return 0;
|
||||
for (const auto& v : newvals) {
|
||||
auto it = vals->emplace(v->id, v);
|
||||
if (not it.second)
|
||||
it.first->second = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
tokenlocal = ++st->second.listener_token;
|
||||
st->second.local_listeners.emplace(tokenlocal, LocalListener{query, filter, gcb});
|
||||
tokenlocal = st->second.listen(gcb, filter, query);
|
||||
if (tokenlocal == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto token4 = Dht::listenTo(id, AF_INET, gcb, filter, query);
|
||||
auto token6 = Dht::listenTo(id, AF_INET6, gcb, filter, query);
|
||||
auto token6 = token4 == 0 ? 0 : Dht::listenTo(id, AF_INET6, gcb, filter, query);
|
||||
if (token6 == 0 && st != store.end()) {
|
||||
st->second.cancelListen(tokenlocal);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DHT_LOG.d(id, "Added listen : %d -> %d %d %d", token, tokenlocal, token4, token6);
|
||||
listeners.emplace(token, std::make_tuple(tokenlocal, token4, token6));
|
||||
return token;
|
||||
}
|
||||
@@ -887,15 +876,17 @@ Dht::cancelListen(const InfoHash& id, size_t token)
|
||||
return false;
|
||||
}
|
||||
DHT_LOG.d(id, "cancelListen %s with token %d", id.toString().c_str(), token);
|
||||
auto st = store.find(id);
|
||||
auto tokenlocal = std::get<0>(it->second);
|
||||
if (st != store.end() && tokenlocal)
|
||||
st->second.local_listeners.erase(tokenlocal);
|
||||
|
||||
if (auto tokenlocal = std::get<0>(it->second)) {
|
||||
auto st = store.find(id);
|
||||
if (st != store.end())
|
||||
st->second.cancelListen(tokenlocal);
|
||||
}
|
||||
auto searches_cancel_listen = [this,&id](std::map<InfoHash, Sp<Search>>& srs, size_t token) {
|
||||
auto srp = srs.find(id);
|
||||
if (srp != srs.end() and token)
|
||||
srp->second->cancelListen(token, scheduler);
|
||||
if (token) {
|
||||
auto srp = srs.find(id);
|
||||
if (srp != srs.end())
|
||||
srp->second->cancelListen(token, scheduler);
|
||||
}
|
||||
};
|
||||
searches_cancel_listen(searches4, std::get<1>(it->second));
|
||||
searches_cancel_listen(searches6, std::get<2>(it->second));
|
||||
@@ -916,7 +907,7 @@ struct OpStatus {
|
||||
|
||||
template <typename T>
|
||||
struct GetStatus : public OpStatus {
|
||||
std::vector<Sp<T>> values;
|
||||
T values;
|
||||
std::vector<Sp<Node>> nodes;
|
||||
};
|
||||
|
||||
@@ -975,20 +966,16 @@ void doneCallbackWrapper(DoneCallback dcb, const std::vector<Sp<Node>>& nodes, G
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Cb>
|
||||
bool callbackWrapper(Cb get_cb,
|
||||
DoneCallback done_cb,
|
||||
const std::vector<Sp<T>>& values,
|
||||
std::function<std::vector<Sp<T>>(const std::vector<Sp<T>>&)> add_values,
|
||||
Sp<GetStatus<T>> o)
|
||||
template <typename T, typename St, typename Cb, typename Av, typename Cv>
|
||||
bool callbackWrapper(Cb get_cb, DoneCallback done_cb, const std::vector<Sp<T>>& values,
|
||||
Av add_values, Cv cache_values, GetStatus<St>& op)
|
||||
{
|
||||
auto& op = *o;
|
||||
if (op.status.done)
|
||||
return false;
|
||||
auto newvals = add_values(values);
|
||||
if (not newvals.empty()) {
|
||||
op.status.ok = !get_cb(newvals);
|
||||
op.values.insert(op.values.end(), newvals.begin(), newvals.end());
|
||||
cache_values(newvals);
|
||||
}
|
||||
doneCallbackWrapper(done_cb, {}, op);
|
||||
return !op.status.ok;
|
||||
@@ -999,24 +986,26 @@ Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filt
|
||||
{
|
||||
scheduler.syncTime();
|
||||
|
||||
auto q = std::make_shared<Query>(Select {}, std::move(where));
|
||||
auto op = std::make_shared<GetStatus<Value>>();
|
||||
auto f = filter.chain(q->where.getFilter());
|
||||
|
||||
auto add_values = [op,f](const std::vector<Sp<Value>>& values) {
|
||||
std::vector<Sp<Value>> newvals {};
|
||||
for (const auto& v : values) {
|
||||
auto it = std::find_if(op->values.cbegin(), op->values.cend(), [&](const Sp<Value>& sv) {
|
||||
return sv == v or *sv == *v;
|
||||
});
|
||||
if (it == op->values.cend()) {
|
||||
if (not f or f(*v))
|
||||
newvals.push_back(v);
|
||||
auto op = std::make_shared<GetStatus<std::map<Value::Id, Sp<Value>>>>();
|
||||
auto gcb = [getcb, donecb, op](const std::vector<Sp<Value>>& vals) {
|
||||
auto& o = *op;
|
||||
return callbackWrapper(getcb, donecb, vals, [&o](const std::vector<Sp<Value>>& values) {
|
||||
std::vector<Sp<Value>> newvals {};
|
||||
for (const auto& v : values) {
|
||||
auto it = o.values.find(v->id);
|
||||
if (it == o.values.cend() or (it->second != v && !(*it->second == *v))) {
|
||||
newvals.push_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newvals;
|
||||
return newvals;
|
||||
}, [&o](const std::vector<Sp<Value>>& newvals) {
|
||||
for (const auto& v : newvals)
|
||||
o.values[v->id] = v;
|
||||
}, o);
|
||||
};
|
||||
auto gcb = std::bind(callbackWrapper<Value, GetCallback>, getcb, donecb, _1, add_values, op);
|
||||
|
||||
auto q = std::make_shared<Query>(Select {}, std::move(where));
|
||||
auto f = filter.chain(q->where.getFilter());
|
||||
|
||||
/* Try to answer this search locally. */
|
||||
gcb(getLocal(id, f));
|
||||
@@ -1036,36 +1025,39 @@ Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filt
|
||||
void Dht::query(const InfoHash& id, QueryCallback cb, DoneCallback done_cb, Query&& q)
|
||||
{
|
||||
scheduler.syncTime();
|
||||
auto op = std::make_shared<GetStatus<FieldValueIndex>>();
|
||||
|
||||
auto op = std::make_shared<GetStatus<std::vector<Sp<FieldValueIndex>>>>();
|
||||
auto f = q.where.getFilter();
|
||||
auto values = getLocal(id, f);
|
||||
auto add_fields = [=](const std::vector<Sp<FieldValueIndex>>& fields) {
|
||||
std::vector<Sp<FieldValueIndex>> newvals {};
|
||||
for (const auto& f : fields) {
|
||||
auto it = std::find_if(op->values.cbegin(), op->values.cend(),
|
||||
[&](const Sp<FieldValueIndex>& sf) {
|
||||
return sf == f or f->containedIn(*sf);
|
||||
});
|
||||
if (it == op->values.cend()) {
|
||||
auto lesser = std::find_if(op->values.begin(), op->values.end(),
|
||||
auto qcb = [cb, done_cb, op](const std::vector<Sp<FieldValueIndex>>& fields){
|
||||
auto& o = *op;
|
||||
return callbackWrapper(cb, done_cb, fields, [&](const std::vector<Sp<FieldValueIndex>>& fields) {
|
||||
std::vector<Sp<FieldValueIndex>> newvals {};
|
||||
for (const auto& f : fields) {
|
||||
auto it = std::find_if(o.values.cbegin(), o.values.cend(),
|
||||
[&](const Sp<FieldValueIndex>& sf) {
|
||||
return sf->containedIn(*f);
|
||||
return sf == f or f->containedIn(*sf);
|
||||
});
|
||||
if (lesser != op->values.end())
|
||||
op->values.erase(lesser);
|
||||
newvals.push_back(f);
|
||||
if (it == o.values.cend()) {
|
||||
auto lesser = std::find_if(o.values.begin(), o.values.end(),
|
||||
[&](const Sp<FieldValueIndex>& sf) {
|
||||
return sf->containedIn(*f);
|
||||
});
|
||||
if (lesser != o.values.end())
|
||||
o.values.erase(lesser);
|
||||
newvals.push_back(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newvals;
|
||||
return newvals;
|
||||
}, [&](const std::vector<Sp<FieldValueIndex>>& fields){
|
||||
o.values.insert(o.values.end(), fields.begin(), fields.end());
|
||||
}, o);
|
||||
};
|
||||
|
||||
/* Try to answer this search locally. */
|
||||
auto values = getLocal(id, f);
|
||||
std::vector<Sp<FieldValueIndex>> local_fields(values.size());
|
||||
std::transform(values.begin(), values.end(), local_fields.begin(), [&q](const Sp<Value>& v) {
|
||||
return std::make_shared<FieldValueIndex>(*v, q.select);
|
||||
});
|
||||
auto qcb = std::bind(callbackWrapper<FieldValueIndex, QueryCallback>, cb, done_cb, _1, add_fields, op);
|
||||
|
||||
/* Try to answer this search locally. */
|
||||
qcb(local_fields);
|
||||
|
||||
auto sq = std::make_shared<Query>(std::move(q));
|
||||
@@ -1082,7 +1074,7 @@ void Dht::query(const InfoHash& id, QueryCallback cb, DoneCallback done_cb, Quer
|
||||
}
|
||||
|
||||
std::vector<Sp<Value>>
|
||||
Dht::getLocal(const InfoHash& id, Value::Filter f) const
|
||||
Dht::getLocal(const InfoHash& id, const Value::Filter& f) const
|
||||
{
|
||||
auto s = store.find(id);
|
||||
if (s == store.end()) return {};
|
||||
@@ -1099,17 +1091,14 @@ Dht::getLocalById(const InfoHash& id, Value::Id vid) const
|
||||
}
|
||||
|
||||
std::vector<Sp<Value>>
|
||||
Dht::getPut(const InfoHash& id)
|
||||
Dht::getPut(const InfoHash& id) const
|
||||
{
|
||||
std::vector<Sp<Value>> ret;
|
||||
auto find_values = [&](std::map<InfoHash, Sp<Search>> srs) {
|
||||
auto find_values = [&](const std::map<InfoHash, Sp<Search>>& srs) {
|
||||
auto srp = srs.find(id);
|
||||
if (srp == srs.end())
|
||||
return;
|
||||
auto& search = srp->second;
|
||||
ret.reserve(ret.size() + search->announce.size());
|
||||
for (const auto& a : search->announce)
|
||||
ret.push_back(a.value);
|
||||
if (srp == srs.end()) return;
|
||||
auto vals = srp->second->getPut();
|
||||
ret.insert(ret.end(), vals.begin(), vals.end());
|
||||
};
|
||||
find_values(searches4);
|
||||
find_values(searches6);
|
||||
@@ -1117,18 +1106,11 @@ Dht::getPut(const InfoHash& id)
|
||||
}
|
||||
|
||||
Sp<Value>
|
||||
Dht::getPut(const InfoHash& id, const Value::Id& vid)
|
||||
Dht::getPut(const InfoHash& id, const Value::Id& vid) const
|
||||
{
|
||||
auto find_value = [&](std::map<InfoHash, Sp<Search>> srs) {
|
||||
auto find_value = [&](const std::map<InfoHash, Sp<Search>>& srs) {
|
||||
auto srp = srs.find(id);
|
||||
if (srp == srs.end())
|
||||
return Sp<Value> {};
|
||||
auto& search = srp->second;
|
||||
for (auto& a : search->announce) {
|
||||
if (a.value->id == vid)
|
||||
return a.value;
|
||||
}
|
||||
return Sp<Value> {};
|
||||
return (srp != srs.end()) ? srp->second->getPut(vid) : Sp<Value> {};
|
||||
};
|
||||
if (auto v4 = find_value(searches4))
|
||||
return v4;
|
||||
@@ -1141,29 +1123,17 @@ bool
|
||||
Dht::cancelPut(const InfoHash& id, const Value::Id& vid)
|
||||
{
|
||||
bool canceled {false};
|
||||
if (storageErase(id, vid))
|
||||
canceled = true;
|
||||
auto sr_cancel_put = [&](std::map<InfoHash, Sp<Search>> srs) {
|
||||
auto sr_cancel_put = [&](std::map<InfoHash, Sp<Search>>& srs) {
|
||||
auto srp = srs.find(id);
|
||||
if (srp == srs.end())
|
||||
return;
|
||||
|
||||
auto& sr = srp->second;
|
||||
for (auto it = sr->announce.begin(); it != sr->announce.end();) {
|
||||
if (it->value->id == vid) {
|
||||
canceled = true;
|
||||
it = sr->announce.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
return (srp != srs.end()) ? srp->second->cancelPut(vid) : false;
|
||||
};
|
||||
sr_cancel_put(searches4);
|
||||
sr_cancel_put(searches6);
|
||||
canceled |= sr_cancel_put(searches4);
|
||||
canceled |= sr_cancel_put(searches6);
|
||||
if (canceled)
|
||||
storageErase(id, vid);
|
||||
return canceled;
|
||||
}
|
||||
|
||||
|
||||
// Storage
|
||||
|
||||
void
|
||||
@@ -1173,6 +1143,7 @@ Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v, bool newVa
|
||||
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<ValueCallback, std::vector<Sp<Value>>>> cbs;
|
||||
cbs.reserve(st.local_listeners.size());
|
||||
for (const auto& l : st.local_listeners) {
|
||||
std::vector<Sp<Value>> vals;
|
||||
if (not l.second.filter or l.second.filter(*v.data))
|
||||
@@ -1223,7 +1194,7 @@ Dht::storageStore(const InfoHash& id, const Sp<Value>& value, time_point created
|
||||
if (st == store.end()) {
|
||||
if (store.size() >= MAX_HASHES)
|
||||
return false;
|
||||
auto st_i = store.emplace(id, Storage(now));
|
||||
auto st_i = store.emplace(id, now);
|
||||
st = st_i.first;
|
||||
if (maintain_storage and st_i.second)
|
||||
scheduler.add(st->second.maintenance_time, std::bind(&Dht::dataPersistence, this, id));
|
||||
@@ -1269,18 +1240,18 @@ Dht::storageAddListener(const InfoHash& id, const Sp<Node>& node, size_t socket_
|
||||
if (st == store.end()) {
|
||||
if (store.size() >= MAX_HASHES)
|
||||
return;
|
||||
st = store.emplace(id, Storage(now)).first;
|
||||
st = store.emplace(id, now).first;
|
||||
}
|
||||
auto node_listeners = st->second.listeners.emplace(node, std::map<size_t, Listener> {}).first;
|
||||
auto l = node_listeners->second.find(socket_id);
|
||||
if (l == node_listeners->second.end()) {
|
||||
auto& node_listeners = st->second.listeners[node];
|
||||
auto l = node_listeners.find(socket_id);
|
||||
if (l == node_listeners.end()) {
|
||||
auto vals = st->second.get(query.where.getFilter());
|
||||
if (not vals.empty()) {
|
||||
network_engine.tellListener(node, socket_id, id, WANT4 | WANT6, makeToken(node->getAddr(), false),
|
||||
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.emplace(socket_id, Listener {now, std::forward<Query>(query)});
|
||||
}
|
||||
else
|
||||
l->second.refresh(now, std::forward<Query>(query));
|
||||
@@ -1388,12 +1359,6 @@ Dht::connectivityChanged(sa_family_t af)
|
||||
scheduler.edit(nextNodesConfirmation, now);
|
||||
buckets(af).connectivityChanged(now);
|
||||
network_engine.connectivityChanged(af);
|
||||
for (auto& sp : searches(af))
|
||||
for (auto& sn : sp.second->nodes) {
|
||||
for (auto& ls : sn.listenStatus)
|
||||
sn.node->cancelRequest(ls.second.req);
|
||||
sn.listenStatus.clear();
|
||||
}
|
||||
reported_addr.erase(std::remove_if(reported_addr.begin(), reported_addr.end(), [&](const ReportedAddr& addr){
|
||||
return addr.second.getFamily() == af;
|
||||
}), reported_addr.end());
|
||||
@@ -1724,13 +1689,11 @@ Dht::~Dht()
|
||||
s.second->clear();
|
||||
}
|
||||
|
||||
Dht::Dht() : store(), network_engine(DHT_LOG, scheduler) {}
|
||||
Dht::Dht() : store(), network_engine(DHT_LOG, scheduler, {}) {}
|
||||
|
||||
Dht::Dht(const int& s, const 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(),
|
||||
network_engine(myid, config.network, s, s6, DHT_LOG, scheduler,
|
||||
Dht::Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l)
|
||||
: DhtInterface(l), myid(config.node_id ? config.node_id : InfoHash::getRandom()), store(), store_quota(),
|
||||
network_engine(myid, config.network, std::move(sock), DHT_LOG, scheduler,
|
||||
std::bind(&Dht::onError, this, _1, _2),
|
||||
std::bind(&Dht::onNewNode, this, _1, _2),
|
||||
std::bind(&Dht::onReportedAddr, this, _1, _2),
|
||||
@@ -1739,16 +1702,20 @@ Dht::Dht(const int& s, const int& s6, Config config)
|
||||
std::bind(&Dht::onGetValues, this, _1, _2, _3, _4),
|
||||
std::bind(&Dht::onListen, this, _1, _2, _3, _4, _5),
|
||||
std::bind(&Dht::onAnnounce, this, _1, _2, _3, _4, _5),
|
||||
std::bind(&Dht::onRefresh, this, _1, _2, _3, _4))
|
||||
std::bind(&Dht::onRefresh, this, _1, _2, _3, _4)),
|
||||
persistPath(config.persist_path),
|
||||
is_bootstrap(config.is_bootstrap),
|
||||
maintain_storage(config.maintain_storage)
|
||||
{
|
||||
scheduler.syncTime();
|
||||
if (s < 0 && s6 < 0)
|
||||
return;
|
||||
if (s >= 0) {
|
||||
auto s = network_engine.getSocket();
|
||||
if (not s or (not s->hasIPv4() and not s->hasIPv6()))
|
||||
throw DhtException("Opened socket required");
|
||||
if (s->hasIPv4()) {
|
||||
buckets4 = {Bucket {AF_INET}};
|
||||
buckets4.is_client = config.is_bootstrap;
|
||||
}
|
||||
if (s6 >= 0) {
|
||||
if (s->hasIPv6()) {
|
||||
buckets6 = {Bucket {AF_INET6}};
|
||||
buckets6.is_client = config.is_bootstrap;
|
||||
}
|
||||
@@ -1756,9 +1723,7 @@ Dht::Dht(const int& s, const int& s6, Config config)
|
||||
search_id = std::uniform_int_distribution<decltype(search_id)>{}(rd);
|
||||
|
||||
uniform_duration_distribution<> time_dis {std::chrono::seconds(3), std::chrono::seconds(5)};
|
||||
auto confirm_nodes_time = scheduler.time() + time_dis(rd);
|
||||
DHT_LOG.d(myid, "Scheduling %s", myid.toString().c_str());
|
||||
nextNodesConfirmation = scheduler.add(confirm_nodes_time, std::bind(&Dht::confirmNodes, this));
|
||||
nextNodesConfirmation = scheduler.add(scheduler.time() + time_dis(rd), std::bind(&Dht::confirmNodes, this));
|
||||
|
||||
// Fill old secret
|
||||
{
|
||||
@@ -1769,9 +1734,11 @@ Dht::Dht(const int& s, const int& s6, Config config)
|
||||
|
||||
expire();
|
||||
|
||||
DHT_LOG.d("DHT initialised with node ID %s", myid.toString().c_str());
|
||||
}
|
||||
DHT_LOG.d("DHT node initialised with ID %s", myid.toString().c_str());
|
||||
|
||||
if (not persistPath.empty())
|
||||
loadState(persistPath);
|
||||
}
|
||||
|
||||
bool
|
||||
Dht::neighbourhoodMaintenance(RoutingTable& list)
|
||||
@@ -1805,7 +1772,7 @@ Dht::neighbourhoodMaintenance(RoutingTable& list)
|
||||
n->toString().c_str(), id.toString().c_str());
|
||||
/* Since our node-id is the same in both DHTs, it's probably
|
||||
profitable to query both families. */
|
||||
network_engine.sendFindNode(n, id, network_engine.want(), nullptr, nullptr);
|
||||
network_engine.sendFindNode(n, id, network_engine.want());
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1855,12 +1822,12 @@ Dht::bucketMaintenance(RoutingTable& list)
|
||||
}
|
||||
|
||||
DHT_LOG.d(id, n->id, "[node %s] sending find %s for bucket maintenance", n->toString().c_str(), id.toString().c_str());
|
||||
auto start = scheduler.time();
|
||||
network_engine.sendFindNode(n, id, want, nullptr, [this,start,n](const net::Request&, bool over) {
|
||||
//auto start = scheduler.time();
|
||||
network_engine.sendFindNode(n, id, want, nullptr, [this,n](const net::Request&, bool over) {
|
||||
if (over) {
|
||||
const auto& end = scheduler.time();
|
||||
using namespace std::chrono;
|
||||
DHT_LOG.d(n->id, "[node %s] bucket maintenance op expired after %llu ms", n->toString().c_str(), duration_cast<milliseconds>(end-start).count());
|
||||
// using namespace std::chrono;
|
||||
// DHT_LOG.d(n->id, "[node %s] bucket maintenance op expired after %llu ms", n->toString().c_str(), duration_cast<milliseconds>(end-start).count());
|
||||
scheduler.edit(nextNodesConfirmation, end + Node::MAX_RESPONSE_TIME);
|
||||
}
|
||||
});
|
||||
@@ -1886,7 +1853,7 @@ Dht::dataPersistence(InfoHash id)
|
||||
}
|
||||
|
||||
size_t
|
||||
Dht::maintainStorage(decltype(store)::value_type& storage, bool force, DoneCallback donecb)
|
||||
Dht::maintainStorage(decltype(store)::value_type& storage, bool force, const DoneCallback& donecb)
|
||||
{
|
||||
const auto& now = scheduler.time();
|
||||
size_t announce_per_af = 0;
|
||||
@@ -1934,14 +1901,14 @@ Dht::maintainStorage(decltype(store)::value_type& storage, bool force, DoneCallb
|
||||
}
|
||||
|
||||
time_point
|
||||
Dht::periodic(const uint8_t *buf, size_t buflen, const SockAddr& from)
|
||||
Dht::periodic(const uint8_t *buf, size_t buflen, SockAddr from)
|
||||
{
|
||||
scheduler.syncTime();
|
||||
if (buflen) {
|
||||
try {
|
||||
network_engine.processMessage(buf, buflen, from);
|
||||
network_engine.processMessage(buf, buflen, std::move(from));
|
||||
} catch (const std::exception& e) {
|
||||
DHT_LOG.e("Can't process message from %s: %s", from.toString().c_str(), e.what());
|
||||
DHT_LOG.e("Can't process message: %s", e.what());
|
||||
}
|
||||
}
|
||||
return scheduler.run();
|
||||
@@ -2025,14 +1992,15 @@ Dht::exportValues() const
|
||||
void
|
||||
Dht::importValues(const std::vector<ValuesExport>& import)
|
||||
{
|
||||
for (const auto& h : import) {
|
||||
if (h.second.empty())
|
||||
const auto& now = scheduler.time();
|
||||
|
||||
for (const auto& node : import) {
|
||||
if (node.second.empty())
|
||||
continue;
|
||||
|
||||
const auto& now = scheduler.time();
|
||||
try {
|
||||
msgpack::unpacked msg;
|
||||
msgpack::unpack(msg, (const char*)h.second.data(), h.second.size());
|
||||
msgpack::unpack(msg, (const char*)node.second.data(), node.second.size());
|
||||
auto valarr = msg.get();
|
||||
if (valarr.type != msgpack::type::ARRAY)
|
||||
throw msgpack::type_error();
|
||||
@@ -2046,14 +2014,14 @@ Dht::importValues(const std::vector<ValuesExport>& import)
|
||||
val_time = time_point{time_point::duration{valel.via.array.ptr[0].as<time_point::duration::rep>()}};
|
||||
tmp_val.msgpack_unpack(valel.via.array.ptr[1]);
|
||||
} catch (const std::exception&) {
|
||||
DHT_LOG.e(h.first, "Error reading value at %s", h.first.toString().c_str());
|
||||
DHT_LOG.e(node.first, "Error reading value at %s", node.first.toString().c_str());
|
||||
continue;
|
||||
}
|
||||
val_time = std::min(val_time, now);
|
||||
storageStore(h.first, std::make_shared<Value>(std::move(tmp_val)), val_time);
|
||||
storageStore(node.first, std::make_shared<Value>(std::move(tmp_val)), val_time);
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
DHT_LOG.e(h.first, "Error reading values at %s", h.first.toString().c_str());
|
||||
DHT_LOG.e(node.first, "Error reading values at %s", node.first.toString().c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -2061,7 +2029,7 @@ Dht::importValues(const std::vector<ValuesExport>& import)
|
||||
|
||||
|
||||
std::vector<NodeExport>
|
||||
Dht::exportNodes()
|
||||
Dht::exportNodes() const
|
||||
{
|
||||
const auto& now = scheduler.time();
|
||||
std::vector<NodeExport> nodes;
|
||||
@@ -2288,12 +2256,10 @@ Dht::onListen(Sp<Node> node, const InfoHash& hash, const Blob& token, size_t soc
|
||||
}
|
||||
|
||||
void
|
||||
Dht::onListenDone(const Sp<Node>& node,
|
||||
net::RequestAnswer& answer,
|
||||
Sp<Search>& sr)
|
||||
Dht::onListenDone(const Sp<Node>& /* node */, net::RequestAnswer& /* answer */, Sp<Search>& sr)
|
||||
{
|
||||
DHT_LOG.d(sr->id, node->id, "[search %s] [node %s] got listen confirmation",
|
||||
sr->id.toString().c_str(), node->toString().c_str(), answer.values.size());
|
||||
// DHT_LOG.d(sr->id, node->id, "[search %s] [node %s] got listen confirmation",
|
||||
// sr->id.toString().c_str(), node->toString().c_str(), answer.values.size());
|
||||
|
||||
if (not sr->done) {
|
||||
const auto& now = scheduler.time();
|
||||
@@ -2361,7 +2327,7 @@ Dht::onAnnounce(Sp<Node> n,
|
||||
// Allow the value to be edited by the storage policy
|
||||
const auto& type = getType(vc->type);
|
||||
if (type.storePolicy(hash, vc, node.id, node.getAddr())) {
|
||||
DHT_LOG.d(hash, node.id, "[store %s] storing %s", hash.toString().c_str(), vc->toString().c_str());
|
||||
//DHT_LOG.d(hash, node.id, "[store %s] storing %s", hash.toString().c_str(), std::to_string(vc->id).c_str());
|
||||
storageStore(hash, vc, created, node.getAddr());
|
||||
} else {
|
||||
DHT_LOG.d(hash, node.id, "[store %s] rejecting storage of %s",
|
||||
@@ -2397,6 +2363,23 @@ Dht::storageRefresh(const InfoHash& id, Value::Id vid)
|
||||
const auto& now = scheduler.time();
|
||||
auto s = store.find(id);
|
||||
if (s != store.end()) {
|
||||
// Values like for a permanent put can be refreshed. So, inform remote listeners that the value
|
||||
// need to be refreshed
|
||||
auto& st = s->second;
|
||||
if (not st.listeners.empty()) {
|
||||
DHT_LOG.d(id, "[store %s] %lu remote listeners", id.toString().c_str(), st.listeners.size());
|
||||
std::vector<Value::Id> ids = {vid};
|
||||
for (const auto& node_listeners : st.listeners) {
|
||||
for (const auto& l : node_listeners.second) {
|
||||
DHT_LOG.w(id, node_listeners.first->id, "[store %s] [node %s] sending refresh",
|
||||
id.toString().c_str(),
|
||||
node_listeners.first->toString().c_str());
|
||||
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
|
||||
network_engine.tellListenerRefreshed(node_listeners.first, l.first, id, ntoken, ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto expiration = s->second.refresh(now, vid, types);
|
||||
if (expiration != time_point::max())
|
||||
scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id));
|
||||
@@ -2414,4 +2397,52 @@ Dht::onAnnounceDone(const Sp<Node>& node, net::RequestAnswer& answer, Sp<Search>
|
||||
sr->checkAnnounced(answer.vid);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Dht::saveState(const std::string& path) const
|
||||
{
|
||||
std::ofstream file(path);
|
||||
msgpack::pack(file, exportNodes());
|
||||
msgpack::pack(file, exportValues());
|
||||
}
|
||||
|
||||
void
|
||||
Dht::loadState(const std::string& path)
|
||||
{
|
||||
DHT_LOG.d("Importing state from %s", path.c_str());
|
||||
try {
|
||||
// Import nodes from binary file
|
||||
msgpack::unpacker pac;
|
||||
{
|
||||
// Read whole file
|
||||
std::ifstream file(path, std::ios::binary|std::ios::ate);
|
||||
if (!file.is_open()) {
|
||||
return;
|
||||
}
|
||||
auto size = file.tellg();
|
||||
file.seekg (0, std::ios::beg);
|
||||
pac.reserve_buffer(size);
|
||||
file.read (pac.buffer(), size);
|
||||
pac.buffer_consumed(size);
|
||||
}
|
||||
// Import nodes
|
||||
msgpack::object_handle oh;
|
||||
if (pac.next(oh)) {
|
||||
{
|
||||
auto imported_nodes = oh.get().as<std::vector<NodeExport>>();
|
||||
DHT_LOG.d("Importing %zu nodes", imported_nodes.size());
|
||||
for (const auto& node : imported_nodes)
|
||||
insertNode(node);
|
||||
}
|
||||
if (pac.next(oh)) {
|
||||
auto imported_values = oh.get().as<std::vector<ValuesExport>>();
|
||||
DHT_LOG.d("Importing %zu values", imported_values.size());
|
||||
importValues(imported_values);
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
DHT_LOG.w("Error importing state from %s: %s", path.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+939
-659
File diff suppressed because it is too large.
Load diff
+873
-688
File diff suppressed because it is too large.
Load diff
+226
-253
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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>
|
||||
@@ -20,22 +20,15 @@
|
||||
|
||||
#include "dhtrunner.h"
|
||||
#include "securedht.h"
|
||||
#include "peer_discovery.h"
|
||||
#include "network_utils.h"
|
||||
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
#include "dht_proxy_client.h"
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#ifdef _WIN32
|
||||
#include <cstring>
|
||||
#define close(x) closesocket(x)
|
||||
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
|
||||
#endif
|
||||
@@ -44,18 +37,27 @@ namespace dht {
|
||||
|
||||
constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD;
|
||||
static constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16;
|
||||
static constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(500);
|
||||
static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht";
|
||||
|
||||
struct DhtRunner::Listener {
|
||||
size_t tokenClassicDht;
|
||||
size_t tokenProxyDht;
|
||||
size_t tokenClassicDht {0};
|
||||
size_t tokenProxyDht {0};
|
||||
ValueCallback gcb;
|
||||
InfoHash hash;
|
||||
InfoHash hash {};
|
||||
Value::Filter f;
|
||||
Where w;
|
||||
};
|
||||
|
||||
struct NodeInsertionPack {
|
||||
dht::InfoHash nodeId;
|
||||
in_port_t port;
|
||||
dht::NetId net;
|
||||
MSGPACK_DEFINE(nodeId, port, net)
|
||||
};
|
||||
|
||||
DhtRunner::DhtRunner() : dht_()
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
, dht_via_proxy_()
|
||||
#endif //OPENDHT_PROXY_CLIENT
|
||||
{
|
||||
@@ -75,7 +77,7 @@ DhtRunner::~DhtRunner()
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::run(in_port_t port, DhtRunner::Config config)
|
||||
DhtRunner::run(in_port_t port, const Config& config, Context&& context)
|
||||
{
|
||||
SockAddr sin4;
|
||||
sin4.setFamily(AF_INET);
|
||||
@@ -83,45 +85,76 @@ DhtRunner::run(in_port_t port, DhtRunner::Config config)
|
||||
SockAddr sin6;
|
||||
sin6.setFamily(AF_INET6);
|
||||
sin6.setPort(port);
|
||||
run(sin4, sin6, config);
|
||||
run(sin4, sin6, config, std::move(context));
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::run(const char* ip4, const char* ip6, const char* service, DhtRunner::Config config)
|
||||
DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context)
|
||||
{
|
||||
auto res4 = SockAddr::resolve(ip4, service);
|
||||
auto res6 = SockAddr::resolve(ip6, service);
|
||||
run(res4.empty() ? SockAddr() : res4.front(),
|
||||
res6.empty() ? SockAddr() : res6.front(), config);
|
||||
res6.empty() ? SockAddr() : res6.front(), config, std::move(context));
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config config)
|
||||
DhtRunner::run(const SockAddr& local4, const SockAddr& local6, const Config& config, Context&& context)
|
||||
{
|
||||
if (not running) {
|
||||
if (not context.sock)
|
||||
context.sock.reset(new net::UdpSocket(local4, local6, context.logger ? *context.logger : Logger{}));
|
||||
run(config, std::move(context));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::run(const Config& config, Context&& context)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (running)
|
||||
return;
|
||||
startNetwork(local4, local6);
|
||||
|
||||
auto dht = std::unique_ptr<DhtInterface>(new Dht(s4, s6, SecureDht::getConfig(config.dht_config)));
|
||||
if (context.logger)
|
||||
logger_ = context.logger;
|
||||
|
||||
context.sock->setOnReceive([&] (std::unique_ptr<net::ReceivedPacket>&& pkt) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(sock_mtx);
|
||||
if (rcv.size() >= RX_QUEUE_MAX_SIZE) {
|
||||
std::cerr << "Dropping packet: queue is full!" << std::endl;
|
||||
rcv.pop();
|
||||
}
|
||||
rcv.emplace(std::move(pkt));
|
||||
}
|
||||
cv.notify_all();
|
||||
});
|
||||
|
||||
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config)));
|
||||
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config));
|
||||
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
config_ = config;
|
||||
#endif
|
||||
enableProxy(not config.proxy_server.empty());
|
||||
if (context.logger and dht_via_proxy_) {
|
||||
dht_via_proxy_->setLogger(*context.logger);
|
||||
}
|
||||
if (context.statusChangedCallback) {
|
||||
statusCb = std::move(context.statusChangedCallback);
|
||||
}
|
||||
if (context.certificateStore) {
|
||||
dht_->setLocalCertificateStore(std::move(context.certificateStore));
|
||||
if (dht_via_proxy_)
|
||||
dht_via_proxy_->setLocalCertificateStore(std::move(context.certificateStore));
|
||||
}
|
||||
|
||||
running = true;
|
||||
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);
|
||||
}
|
||||
time_point wakeup = loop_();
|
||||
|
||||
auto hasJobToDo = [this]() {
|
||||
if (not running)
|
||||
@@ -147,17 +180,57 @@ DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config
|
||||
cv.wait_until(lk, wakeup, hasJobToDo);
|
||||
}
|
||||
});
|
||||
|
||||
if (config.peer_discovery or config.peer_publish) {
|
||||
peerDiscovery_ = context.peerDiscovery ?
|
||||
std::move(context.peerDiscovery) :
|
||||
std::make_shared<PeerDiscovery>();
|
||||
}
|
||||
|
||||
auto netId = config.dht_config.node_config.network;
|
||||
if (config.peer_discovery) {
|
||||
peerDiscovery_->startDiscovery<NodeInsertionPack>(PEER_DISCOVERY_DHT_SERVICE, [this, netId](NodeInsertionPack&& v, SockAddr&& addr){
|
||||
addr.setPort(v.port);
|
||||
if (v.nodeId != dht_->getNodeId() && netId == v.net){
|
||||
bootstrap(v.nodeId, addr);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (config.peer_publish) {
|
||||
msgpack::sbuffer sbuf_node;
|
||||
NodeInsertionPack adc;
|
||||
adc.net = netId;
|
||||
adc.nodeId = dht_->getNodeId();
|
||||
// IPv4
|
||||
if (auto bound4 = dht_->getSocket()->getBound(AF_INET)) {
|
||||
adc.port = bound4.getPort();
|
||||
msgpack::pack(sbuf_node, adc);
|
||||
peerDiscovery_->startPublish(AF_INET, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
|
||||
}
|
||||
// IPv6
|
||||
if (auto bound6 = dht_->getSocket()->getBound(AF_INET6)) {
|
||||
adc.port = bound6.getPort();
|
||||
sbuf_node.clear();
|
||||
msgpack::pack(sbuf_node, adc);
|
||||
peerDiscovery_->startPublish(AF_INET6, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::shutdown(ShutdownCallback cb) {
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
if (dht_via_proxy_)
|
||||
dht_via_proxy_->shutdown(cb);
|
||||
#endif
|
||||
if (not running) {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([=](SecureDht& dht) mutable {
|
||||
dht.shutdown(cb);
|
||||
pending_ops_prio.emplace([=](SecureDht&) mutable {
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
if (dht_via_proxy_)
|
||||
dht_via_proxy_->shutdown(cb);
|
||||
#endif
|
||||
if (dht_)
|
||||
dht_->shutdown(cb);
|
||||
});
|
||||
cv.notify_all();
|
||||
}
|
||||
@@ -165,16 +238,28 @@ DhtRunner::shutdown(ShutdownCallback cb) {
|
||||
void
|
||||
DhtRunner::join()
|
||||
{
|
||||
stopNetwork();
|
||||
running = false;
|
||||
cv.notify_all();
|
||||
bootstrap_cv.notify_all();
|
||||
if (peerDiscovery_)
|
||||
peerDiscovery_->stop();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
running = false;
|
||||
cv.notify_all();
|
||||
bootstrap_cv.notify_all();
|
||||
if (dht_)
|
||||
if (auto sock = dht_->getSocket())
|
||||
sock->stop();
|
||||
}
|
||||
|
||||
if (dht_thread.joinable())
|
||||
dht_thread.join();
|
||||
|
||||
if (bootstrap_thread.joinable())
|
||||
bootstrap_thread.join();
|
||||
if (rcv_thread.joinable())
|
||||
rcv_thread.join();
|
||||
|
||||
if (peerDiscovery_) {
|
||||
peerDiscovery_->join();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
@@ -189,6 +274,15 @@ DhtRunner::join()
|
||||
}
|
||||
}
|
||||
|
||||
SockAddr
|
||||
DhtRunner::getBound(sa_family_t af) const {
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (dht_)
|
||||
if (auto sock = dht_->getSocket())
|
||||
return sock->getBound(af);
|
||||
return SockAddr{};
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::dumpTables() const
|
||||
{
|
||||
@@ -199,17 +293,17 @@ DhtRunner::dumpTables() const
|
||||
InfoHash
|
||||
DhtRunner::getId() const
|
||||
{
|
||||
if (!activeDht())
|
||||
return {};
|
||||
return activeDht()->getId();
|
||||
if (auto dht = activeDht())
|
||||
return dht->getId();
|
||||
return {};
|
||||
}
|
||||
|
||||
InfoHash
|
||||
DhtRunner::getNodeId() const
|
||||
{
|
||||
if (!activeDht())
|
||||
return {};
|
||||
return activeDht()->getNodeId();
|
||||
if (auto dht = activeDht())
|
||||
return dht->getNodeId();
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -246,23 +340,29 @@ DhtRunner::exportValues() const {
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
|
||||
DhtRunner::setLogger(const Logger& logger) {
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (dht_)
|
||||
dht_->setLoggers(error, warn, debug);
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
dht_->setLogger(logger);
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
if (dht_via_proxy_)
|
||||
dht_via_proxy_->setLoggers(error, warn, debug);
|
||||
dht_via_proxy_->setLogger(logger);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
|
||||
Logger logger {std::move(error), std::move(warn), std::move(debug)};
|
||||
setLogger(logger);
|
||||
}
|
||||
|
||||
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
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
if (dht_via_proxy_)
|
||||
dht_via_proxy_->setLogFilter(f);
|
||||
#endif
|
||||
@@ -376,7 +476,7 @@ DhtRunner::registerCertificate(std::shared_ptr<crypto::Certificate> cert) {
|
||||
void
|
||||
DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method) {
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
if (dht_via_proxy_)
|
||||
dht_via_proxy_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
|
||||
#endif
|
||||
@@ -410,20 +510,35 @@ DhtRunner::loop_()
|
||||
// move to stack
|
||||
received = std::move(rcv);
|
||||
}
|
||||
|
||||
// Discard old packets
|
||||
size_t dropped {0};
|
||||
if (not received.empty()) {
|
||||
auto now = clock::now();
|
||||
while (not received.empty() and now - received.front()->received > RX_QUEUE_MAX_DELAY) {
|
||||
received.pop();
|
||||
dropped++;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle packets
|
||||
if (not received.empty()) {
|
||||
while (not received.empty()) {
|
||||
auto& pck = received.front();
|
||||
auto delay = clock::now() - pck.received;
|
||||
if (delay > std::chrono::milliseconds(500))
|
||||
std::cerr << "Dropping packet with high delay: " << print_dt(delay) << std::endl;
|
||||
if (clock::now() - pck->received > RX_QUEUE_MAX_DELAY)
|
||||
dropped++;
|
||||
else
|
||||
wakeup = dht->periodic(pck.data.data(), pck.data.size()-1, pck.from);
|
||||
wakeup = dht->periodic(pck->data.data(), pck->data.size(), std::move(pck->from));
|
||||
received.pop();
|
||||
}
|
||||
} else {
|
||||
// Or just run the scheduler
|
||||
wakeup = dht->periodic(nullptr, 0, nullptr, 0);
|
||||
}
|
||||
|
||||
if (dropped)
|
||||
std::cerr << "Dropped " << dropped << " packets with high delay" << std::endl;
|
||||
|
||||
NodeStatus nstatus4 = dht->getStatus(AF_INET);
|
||||
NodeStatus nstatus6 = dht->getStatus(AF_INET6);
|
||||
if (nstatus4 != status4 || nstatus6 != status6) {
|
||||
@@ -445,176 +560,13 @@ DhtRunner::loop_()
|
||||
return wakeup;
|
||||
}
|
||||
|
||||
|
||||
int bindSocket(const SockAddr& addr, SockAddr& bound)
|
||||
{
|
||||
bool is_ipv6 = addr.getFamily() == AF_INET6;
|
||||
int sock = socket(is_ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0)
|
||||
throw DhtException(std::string("Can't open socket: ") + strerror(sock));
|
||||
int set = 1;
|
||||
#ifdef SO_NOSIGPIPE
|
||||
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&set, sizeof(set));
|
||||
#endif
|
||||
if (is_ipv6)
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&set, sizeof(set));
|
||||
int rc = bind(sock, addr.get(), addr.getLength());
|
||||
if(rc < 0) {
|
||||
close(sock);
|
||||
throw DhtException("Can't bind socket on " + addr.toString() + " " + strerror(rc));
|
||||
}
|
||||
sockaddr_storage ss;
|
||||
socklen_t ss_len = sizeof(ss);
|
||||
getsockname(sock, (sockaddr*)&ss, &ss_len);
|
||||
bound = {ss, ss_len};
|
||||
return sock;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline void udpPipe(int fds[2])
|
||||
{
|
||||
int lst = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (lst < 0)
|
||||
throw DhtException(std::string("Can't open socket: ") + strerror(lst));
|
||||
sockaddr_in inaddr;
|
||||
sockaddr addr;
|
||||
memset(&inaddr, 0, sizeof(inaddr));
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
inaddr.sin_family = AF_INET;
|
||||
inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
inaddr.sin_port = 0;
|
||||
int yes=1;
|
||||
setsockopt(lst, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
|
||||
int rc = bind(lst, (sockaddr*)&inaddr, sizeof(inaddr));
|
||||
if (rc < 0) {
|
||||
close(lst);
|
||||
throw DhtException("Can't bind socket on " + print_addr((sockaddr*)&addr, sizeof(inaddr)) + " " + strerror(rc));
|
||||
}
|
||||
socklen_t len = sizeof(inaddr);
|
||||
getsockname(lst, &addr, &len);
|
||||
fds[0] = lst;
|
||||
fds[1] = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
connect(fds[1], &addr, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
DhtRunner::stopNetwork()
|
||||
{
|
||||
running_network = false;
|
||||
if (stop_writefd != -1) {
|
||||
if (write(stop_writefd, "\0", 1) == -1) {
|
||||
perror("write");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::startNetwork(const SockAddr sin4, const SockAddr sin6)
|
||||
{
|
||||
stopNetwork();
|
||||
if (rcv_thread.joinable())
|
||||
rcv_thread.join();
|
||||
|
||||
int stopfds[2];
|
||||
#ifndef _WIN32
|
||||
auto status = pipe(stopfds);
|
||||
if (status == -1) {
|
||||
throw DhtException("Can't open pipe");
|
||||
}
|
||||
#else
|
||||
udpPipe(stopfds);
|
||||
#endif
|
||||
int stop_readfd = stopfds[0];
|
||||
stop_writefd = stopfds[1];
|
||||
|
||||
s4 = -1;
|
||||
s6 = -1;
|
||||
|
||||
bound4 = {};
|
||||
if (sin4)
|
||||
s4 = bindSocket(sin4, bound4);
|
||||
|
||||
#if 1
|
||||
bound6 = {};
|
||||
if (sin6)
|
||||
s6 = bindSocket(sin6, bound6);
|
||||
#endif
|
||||
|
||||
running_network = true;
|
||||
rcv_thread = std::thread([this, stop_readfd]() {
|
||||
try {
|
||||
while (running_network) {
|
||||
fd_set readfds;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(stop_readfd, &readfds);
|
||||
if(s4 >= 0)
|
||||
FD_SET(s4, &readfds);
|
||||
if(s6 >= 0)
|
||||
FD_SET(s6, &readfds);
|
||||
|
||||
int rc = select(s4 > s6 ? s4 + 1 : s6 + 1, &readfds, nullptr, nullptr, nullptr);
|
||||
if(rc < 0) {
|
||||
if(errno != EINTR) {
|
||||
perror("select");
|
||||
std::this_thread::sleep_for( std::chrono::seconds(1) );
|
||||
}
|
||||
}
|
||||
|
||||
if (not running_network)
|
||||
break;
|
||||
|
||||
if(rc > 0) {
|
||||
std::array<uint8_t, 1024 * 64> buf;
|
||||
sockaddr_storage from;
|
||||
socklen_t from_len = sizeof(from);
|
||||
|
||||
if(s4 >= 0 && FD_ISSET(s4, &readfds))
|
||||
rc = recvfrom(s4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
|
||||
else if(s6 >= 0 && FD_ISSET(s6, &readfds))
|
||||
rc = recvfrom(s6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
|
||||
else
|
||||
continue;
|
||||
if (rc > 0) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(sock_mtx);
|
||||
if (rcv.size() >= RX_QUEUE_MAX_SIZE) {
|
||||
std::cerr << "Dropping packet: queue is full!" << std::endl;
|
||||
rcv.pop();
|
||||
}
|
||||
rcv.emplace(ReceivedPacket {Blob {buf.begin(), buf.begin()+rc+1}, SockAddr(from, from_len), clock::now()});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error in DHT networking thread: " << e.what() << std::endl;
|
||||
}
|
||||
if (s4 >= 0)
|
||||
close(s4);
|
||||
if (s6 >= 0)
|
||||
close(s6);
|
||||
s4 = -1;
|
||||
s6 = -1;
|
||||
bound4 = {};
|
||||
bound6 = {};
|
||||
if (stop_readfd != -1)
|
||||
close(stop_readfd);
|
||||
if (stop_writefd != -1)
|
||||
close(stop_writefd);
|
||||
stop_writefd = -1;
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f, Where w)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) mutable {
|
||||
dht.get(hash, vcb, dcb, std::move(f), std::move(w));
|
||||
dht.get(hash, std::move(vcb), std::move(dcb), std::move(f), std::move(w));
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
@@ -623,14 +575,14 @@ DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f
|
||||
void
|
||||
DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, Value::Filter f, Where w)
|
||||
{
|
||||
get(InfoHash::get(key), vcb, dcb, f, w);
|
||||
get(InfoHash::get(key), std::move(vcb), std::move(dcb), std::move(f), std::move(w));
|
||||
}
|
||||
void
|
||||
DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) mutable {
|
||||
dht.query(hash, cb, done_cb, std::move(q));
|
||||
dht.query(hash, std::move(cb), std::move(done_cb), std::move(q));
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
@@ -643,27 +595,26 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) mutable {
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
auto tokenbGlobal = listener_token_++;
|
||||
Listener listener {};
|
||||
auto& listener = listeners_[tokenbGlobal];
|
||||
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, bool expired){
|
||||
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals, bool expired) {
|
||||
if (not vcb(vals, expired)) {
|
||||
cancelListen(hash, tokenbGlobal);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if (use_proxy)
|
||||
listener.tokenProxyDht = dht.listen(hash, listener.gcb, listener.f, listener.w);
|
||||
else
|
||||
listener.tokenClassicDht = dht.listen(hash, listener.gcb, listener.f, listener.w);
|
||||
listeners_.emplace(tokenbGlobal, std::move(listener));
|
||||
if (auto token = dht.listen(hash, listener.gcb, listener.f, listener.w)) {
|
||||
if (use_proxy) listener.tokenProxyDht = token;
|
||||
else listener.tokenClassicDht = token;
|
||||
}
|
||||
ret_token->set_value(tokenbGlobal);
|
||||
#else
|
||||
ret_token->set_value(dht.listen(hash, vcb, f, w));
|
||||
ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
|
||||
#endif
|
||||
});
|
||||
}
|
||||
@@ -674,7 +625,7 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
|
||||
std::future<size_t>
|
||||
DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Where w)
|
||||
{
|
||||
return listen(InfoHash::get(key), vcb, f, w);
|
||||
return listen(InfoHash::get(key), std::move(vcb), std::move(f), std::move(w));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -682,7 +633,7 @@ DhtRunner::cancelListen(InfoHash h, size_t token)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
pending_ops.emplace([=](SecureDht&) {
|
||||
auto it = listeners_.find(token);
|
||||
if (it == listeners_.end()) return;
|
||||
@@ -706,7 +657,7 @@ DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> ftoken)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
pending_ops.emplace([=](SecureDht&) {
|
||||
auto it = listeners_.find(ftoken.get());
|
||||
if (it == listeners_.end()) return;
|
||||
@@ -753,7 +704,7 @@ DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, tim
|
||||
void
|
||||
DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, time_point created, bool permanent)
|
||||
{
|
||||
put(InfoHash::get(key), std::forward<Value>(value), cb, created, permanent);
|
||||
put(InfoHash::get(key), std::forward<Value>(value), std::move(cb), created, permanent);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -783,13 +734,13 @@ DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback c
|
||||
void
|
||||
DhtRunner::putSigned(InfoHash hash, Value&& value, DoneCallback cb)
|
||||
{
|
||||
putSigned(hash, std::make_shared<Value>(std::move(value)), cb);
|
||||
putSigned(hash, std::make_shared<Value>(std::move(value)), std::move(cb));
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb)
|
||||
{
|
||||
putSigned(InfoHash::get(key), std::forward<Value>(value), cb);
|
||||
putSigned(InfoHash::get(key), std::forward<Value>(value), std::move(cb));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -807,13 +758,13 @@ DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value
|
||||
void
|
||||
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb)
|
||||
{
|
||||
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), cb);
|
||||
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb));
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb)
|
||||
{
|
||||
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), cb);
|
||||
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -919,6 +870,18 @@ DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable {
|
||||
dht.insertNode(id, address);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::bootstrap(const std::vector<NodeExport>& nodes)
|
||||
{
|
||||
@@ -958,7 +921,8 @@ DhtRunner::findCertificate(InfoHash hash, std::function<void(const std::shared_p
|
||||
void
|
||||
DhtRunner::resetDht()
|
||||
{
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
peerDiscovery_.reset();
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
listeners_.clear();
|
||||
dht_via_proxy_.reset();
|
||||
#endif // OPENDHT_PROXY_CLIENT
|
||||
@@ -968,7 +932,7 @@ DhtRunner::resetDht()
|
||||
SecureDht*
|
||||
DhtRunner::activeDht() const
|
||||
{
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
return use_proxy? dht_via_proxy_.get() : dht_.get();
|
||||
#else
|
||||
return dht_.get();
|
||||
@@ -978,7 +942,8 @@ DhtRunner::activeDht() const
|
||||
void
|
||||
DhtRunner::setProxyServer(const std::string& proxy, const std::string& pushNodeId)
|
||||
{
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (config_.proxy_server == proxy and config_.push_node_id == pushNodeId)
|
||||
return;
|
||||
config_.proxy_server = proxy;
|
||||
@@ -993,7 +958,7 @@ DhtRunner::setProxyServer(const std::string& proxy, const std::string& pushNodeI
|
||||
void
|
||||
DhtRunner::enableProxy(bool proxify)
|
||||
{
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
if (dht_via_proxy_) {
|
||||
dht_via_proxy_->shutdown({});
|
||||
}
|
||||
@@ -1008,10 +973,10 @@ DhtRunner::enableProxy(bool proxify)
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
}, config_.proxy_server, config_.push_node_id)
|
||||
}, config_.proxy_server, config_.push_node_id, logger_)
|
||||
);
|
||||
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
|
||||
#if OPENDHT_PUSH_NOTIFICATIONS
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
if (not pushToken_.empty())
|
||||
dht_via_proxy_->setPushNotificationToken(pushToken_);
|
||||
#endif
|
||||
@@ -1044,13 +1009,16 @@ DhtRunner::enableProxy(bool proxify)
|
||||
void
|
||||
DhtRunner::forwardAllMessages(bool forward)
|
||||
{
|
||||
#if OPENDHT_PROXY_SERVER
|
||||
#if OPENDHT_PROXY_CLIENT
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
#ifdef OPENDHT_PROXY_SERVER
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
if (dht_via_proxy_)
|
||||
dht_via_proxy_->forwardAllMessages(forward);
|
||||
#endif // OPENDHT_PROXY_CLIENT
|
||||
if (dht_)
|
||||
dht_->forwardAllMessages(forward);
|
||||
#else
|
||||
(void) forward;
|
||||
#endif // OPENDHT_PROXY_SERVER
|
||||
}
|
||||
|
||||
@@ -1059,17 +1027,20 @@ DhtRunner::forwardAllMessages(bool forward)
|
||||
*/
|
||||
void
|
||||
DhtRunner::setPushNotificationToken(const std::string& token) {
|
||||
#if OPENDHT_PROXY_CLIENT && OPENDHT_PUSH_NOTIFICATIONS
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
|
||||
pushToken_ = token;
|
||||
if (dht_via_proxy_)
|
||||
dht_via_proxy_->setPushNotificationToken(token);
|
||||
#else
|
||||
(void) token;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::pushNotificationReceived(const std::map<std::string, std::string>& data)
|
||||
{
|
||||
#if OPENDHT_PROXY_CLIENT && OPENDHT_PUSH_NOTIFICATIONS
|
||||
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([=](SecureDht&) {
|
||||
@@ -1078,6 +1049,8 @@ DhtRunner::pushNotificationReceived(const std::map<std::string, std::string>& da
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
#else
|
||||
(void) data;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+519
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "http.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
constexpr char HTTP_HEADER_CONTENT_LENGTH[] = "Content-Length:";
|
||||
|
||||
// connection
|
||||
|
||||
Connection::Connection(asio::ip::tcp::socket socket, std::shared_ptr<dht::Logger> logger):
|
||||
id_(++ids_), socket_(std::move(socket)), logger_(logger)
|
||||
{}
|
||||
|
||||
Connection::~Connection(){
|
||||
close();
|
||||
}
|
||||
|
||||
ConnectionId
|
||||
Connection::id(){
|
||||
return id_;
|
||||
}
|
||||
|
||||
bool
|
||||
Connection::is_open(){
|
||||
return socket_.is_open();
|
||||
}
|
||||
|
||||
bool
|
||||
Connection::is_v6(){
|
||||
return endpoint_.address().is_v6();
|
||||
}
|
||||
|
||||
void
|
||||
Connection::timeout(const std::chrono::seconds timeout, HandlerCb cb)
|
||||
{
|
||||
if (!is_open()){
|
||||
if (logger_)
|
||||
logger_->e("[connection:%i] closed, can't timeout", id_);
|
||||
return;
|
||||
}
|
||||
if (!timeout_timer_)
|
||||
timeout_timer_ = std::make_unique<asio::steady_timer>(io_context());
|
||||
timeout_timer_->expires_at(std::chrono::steady_clock::now() + timeout);
|
||||
timeout_timer_->async_wait([this, cb](const asio::error_code &ec){
|
||||
if (ec == asio::error_code::operation_aborted)
|
||||
return;
|
||||
else if (ec){
|
||||
if (logger_)
|
||||
logger_->e("[connection:%i] timeout error: %s", id_, ec.message().c_str());
|
||||
}
|
||||
if (cb)
|
||||
cb(ec);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Connection::close(){
|
||||
socket_.close();
|
||||
}
|
||||
|
||||
// connection listener
|
||||
|
||||
ConnectionListener::ConnectionListener()
|
||||
{}
|
||||
|
||||
ConnectionListener::ConnectionListener(std::shared_ptr<dht::DhtRunner> dht,
|
||||
std::shared_ptr<std::map<restinio::connection_id_t, http::ListenerSession>> listeners,
|
||||
std::shared_ptr<std::mutex> lock, std::shared_ptr<dht::Logger> logger):
|
||||
dht_(dht), lock_(lock), listeners_(listeners), logger_(logger)
|
||||
{}
|
||||
|
||||
ConnectionListener::~ConnectionListener()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ConnectionListener::state_changed(const restinio::connection_state::notice_t& notice) noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*lock_);
|
||||
auto id = notice.connection_id();
|
||||
auto cause = to_str(notice.cause());
|
||||
|
||||
if (listeners_->find(id) != listeners_->end()){
|
||||
if (notice.cause() == restinio::connection_state::cause_t::closed){
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] [connection:%li] cancelling listener", id);
|
||||
dht_->cancelListen(listeners_->at(id).hash,
|
||||
std::move(listeners_->at(id).token));
|
||||
listeners_->erase(id);
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] %li listeners are connected", listeners_->size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
ConnectionListener::to_str(restinio::connection_state::cause_t cause) noexcept
|
||||
{
|
||||
std::string result;
|
||||
switch(cause)
|
||||
{
|
||||
case restinio::connection_state::cause_t::accepted:
|
||||
result = "accepted";
|
||||
break;
|
||||
case restinio::connection_state::cause_t::closed:
|
||||
result = "closed";
|
||||
break;
|
||||
case restinio::connection_state::cause_t::upgraded_to_websocket:
|
||||
result = "upgraded";
|
||||
break;
|
||||
default:
|
||||
result = "unknown";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// request
|
||||
|
||||
Request::Request(asio::io_context& ctx, const std::string host, const std::string service,
|
||||
const bool resolve, std::shared_ptr<dht::Logger> logger):
|
||||
id_(++ids_), resolver_(ctx), logger_(logger)
|
||||
{
|
||||
if (resolve)
|
||||
resolve(host, service);
|
||||
}
|
||||
|
||||
Request::~Request()
|
||||
{
|
||||
terminate();
|
||||
}
|
||||
|
||||
void
|
||||
Request::set_logger(std::shared_ptr<dht::Logger> logger)
|
||||
{
|
||||
logger_ = logger;
|
||||
}
|
||||
|
||||
void
|
||||
Request::terminate()
|
||||
{
|
||||
if (parser_)
|
||||
// ensure on_message_complete callback is called
|
||||
http_parser_execute(parser_.get(), parser_s_.get(), "", 0);
|
||||
if (logger_)
|
||||
logger_->d("[http:request:%i] done", id_);
|
||||
}
|
||||
|
||||
bool
|
||||
Request::resolved()
|
||||
{
|
||||
return !endpoints_.empty();
|
||||
}
|
||||
|
||||
void
|
||||
Request::resolve(const std::string host, const std::string service, HandlerCb cb)
|
||||
{
|
||||
// build the query
|
||||
asio::ip::tcp::resolver::query query(host, service);
|
||||
|
||||
// resolve the query to the server
|
||||
resolver_.async_resolve(query, [this, host, service, cb]
|
||||
(const asio::error_code& ec, asio::ip::tcp::resolver::results_type endpoints)
|
||||
{
|
||||
if (ec){
|
||||
if (logger_)
|
||||
logger_->e("[http:request:%i] error resolving %s:%s: %s",
|
||||
id_, host.c_str(), service.c_str(), ec.message().c_str());
|
||||
}
|
||||
else {
|
||||
for (auto it = endpoints.begin(); it != endpoints.end(); ++it){
|
||||
if (logger_){
|
||||
asio::ip::tcp::endpoint endpoint = *it;
|
||||
logger_->d("[http:request:%i] resolved %s:%s: address=%s ipv%i",
|
||||
id_, host.c_str(), service.c_str(), endpoint.address().to_string().c_str(),
|
||||
endpoint.address().is_v6() ? 6 : 4);
|
||||
}
|
||||
}
|
||||
endpoints_ = endpoints;
|
||||
}
|
||||
if (cb)
|
||||
cb(ec);
|
||||
});
|
||||
}
|
||||
|
||||
std::string
|
||||
Request::build(const restinio::http_request_header_t header,
|
||||
const restinio::http_header_fields_t header_fields,
|
||||
const restinio::http_connection_header_t connection, const std::string body)
|
||||
{
|
||||
std::stringstream request;
|
||||
|
||||
// first header
|
||||
request << header.method().c_str() << " " << header.request_target() << " " <<
|
||||
"HTTP/" << header.http_major() << "." << header.http_minor() << "\r\n";
|
||||
|
||||
// other headers
|
||||
for (auto header_field: header_fields)
|
||||
request << header_field.name() << ": " << header_field.value() << "\r\n";
|
||||
|
||||
// last connection header
|
||||
std::string conn_str;
|
||||
switch (connection){
|
||||
case restinio::http_connection_header_t::keep_alive:
|
||||
conn_str = "keep-alive";
|
||||
break;
|
||||
case restinio::http_connection_header_t::close:
|
||||
conn_str = "close";
|
||||
break;
|
||||
case restinio::http_connection_header_t::upgrade:
|
||||
throw std::invalid_argument("upgrade");
|
||||
break;
|
||||
}
|
||||
request << "Connection: " << conn_str << "\r\n";
|
||||
|
||||
// body & content-length
|
||||
if (!body.empty()){
|
||||
request << "Content-Length: " << body.size() << "\r\n\r\n";
|
||||
request << body;
|
||||
}
|
||||
|
||||
// last delim
|
||||
request << "\r\n";
|
||||
return request.str();
|
||||
}
|
||||
|
||||
void
|
||||
Request::connect(ConnectionCb cb)
|
||||
{
|
||||
if (endpoints_.empty()){
|
||||
if (logger_)
|
||||
logger_->e("[http:request] [connect] host not resolved");
|
||||
if (cb)
|
||||
cb(asio::error::connection_aborted, nullptr);
|
||||
return;
|
||||
}
|
||||
auto socket = asio::ip::tcp::socket{resolver_.get_io_context()};
|
||||
conn_ = std::make_shared<Connection>(std::move(socket));
|
||||
|
||||
// try to connect to any until one works
|
||||
asio::async_connect(conn_->socket_, endpoints_, [this, conn, cb]
|
||||
(const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint){
|
||||
if (ec){ // all endpoints failed
|
||||
if (logger_)
|
||||
logger_->e("[http:request:%i] [connect] failed to connect to any endpoints", id_);
|
||||
}
|
||||
else {
|
||||
if (logger_)
|
||||
logger_->d("[http:request:%i] [connect] success", id_);
|
||||
// save the associated endpoint
|
||||
conn_->endpoint_ = endpoint;
|
||||
}
|
||||
if (cb)
|
||||
cb(ec, conn_);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Request::send(std::string request, std::unique_ptr<http_parser> parser,
|
||||
std::unique_ptr<http_parser_settings> parser_s, HandlerCb cb)
|
||||
{
|
||||
if (endpoints_.empty()){
|
||||
if (logger_)
|
||||
logger_->e("[http:request:%i] [send] unresolved destination", id_);
|
||||
if (cb)
|
||||
cb(asio::error::addrinfo_errors::service_not_found);
|
||||
}
|
||||
if (!conn_){
|
||||
if (logger_)
|
||||
logger_->e("[http:request:%i] [send] uninitialized connection", id_);
|
||||
if (cb)
|
||||
cb(asio::error::not_connected);
|
||||
}
|
||||
else if (!conn_->is_open()){
|
||||
if (logger_)
|
||||
logger_->e("[http:request] [send] closed connection");
|
||||
if (cb)
|
||||
cb(asio::error::not_connected);
|
||||
}
|
||||
else {
|
||||
// save the request context
|
||||
request_ = request;
|
||||
parser_ = std::move(parser);
|
||||
parser_s_ = std::move(parser_s);
|
||||
|
||||
// write the request to buffer
|
||||
std::ostream request_stream(&conn_->request_);
|
||||
request_stream << request;
|
||||
|
||||
// send the request
|
||||
asio::async_write(conn_->socket_, conn_->request_,
|
||||
std::bind(&Request::handle_request, this, std::placeholders::_1, cb));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Request::handle_request(const asio::error_code& ec, HandlerCb cb)
|
||||
{
|
||||
if (!conn_->is_open()){
|
||||
if (logger_)
|
||||
logger_->e("[http:request:%i] [write] closed connection", id_);
|
||||
terminate();
|
||||
if (cb)
|
||||
cb(asio::error::not_connected);
|
||||
return;
|
||||
}
|
||||
if (ec and ec != asio::error::eof){
|
||||
if (logger_)
|
||||
logger_->e("[http:request:%i] [write] error: %s", id_, ec.message().c_str());
|
||||
terminate();
|
||||
if (cb)
|
||||
cb(ec);
|
||||
return;
|
||||
}
|
||||
if (logger_)
|
||||
logger_->d("[http:request:%i] [write] success", id_);
|
||||
|
||||
// read response
|
||||
asio::async_read_until(conn_->socket_, conn_->response_chunk_, "\r\n\r\n",
|
||||
std::bind(&Request::handle_response_header, this,
|
||||
std::placeholders::_1, std::placeholders::_2, cb));
|
||||
}
|
||||
|
||||
void
|
||||
Request::handle_response_header(const asio::error_code& ec, const size_t bytes, HandlerCb cb)
|
||||
{
|
||||
if (!conn_->is_open()){
|
||||
if (logger_)
|
||||
logger_->e("[http:request:%i] [read:header] closed connection", id_);
|
||||
terminate();
|
||||
if (cb)
|
||||
cb(asio::error::not_connected);
|
||||
return;
|
||||
}
|
||||
if (ec && ec != asio::error::eof){
|
||||
if (logger_)
|
||||
logger_->e("[http:request:%i] [read:header] error: %s", id_, ec.message().c_str());
|
||||
terminate();
|
||||
if (cb)
|
||||
cb(ec);
|
||||
return;
|
||||
}
|
||||
else if ((ec == asio::error::eof) || (ec == asio::error::connection_reset)){
|
||||
terminate();
|
||||
if (cb)
|
||||
cb(ec);
|
||||
return;
|
||||
}
|
||||
// read the response buffer
|
||||
std::ostringstream str_s;
|
||||
str_s << &conn_->response_chunk_;
|
||||
auto chunk = str_s.str();
|
||||
auto header = chunk.substr(0, bytes);
|
||||
if (logger_)
|
||||
logger_->d("[http:request:%i] [read:header]:\n%s", id_, header.c_str());
|
||||
// parse the header right away
|
||||
parse_request(header, conn_->id());
|
||||
|
||||
unsigned int content_length = get_content_length(header);
|
||||
// has body size
|
||||
if (content_length){
|
||||
// append current body chunk
|
||||
auto body_chunk = chunk.substr(bytes, std::string::npos);
|
||||
conn_->response_body_.append(body_chunk);
|
||||
// read the rest of body
|
||||
asio::async_read(conn_->socket_, conn_->response_chunk_,
|
||||
asio::transfer_exactly(content_length - (body_chunk.size())),
|
||||
std::bind(&Request::handle_response_body, this,
|
||||
std::placeholders::_1, content_length, conn, cb));
|
||||
return;
|
||||
}
|
||||
// has potential body but no content-length (current proxy behavior on key get/listen)
|
||||
else if (header.find("Content-Type: application/json") != std::string::npos){
|
||||
auto body_chunk = chunk.substr(bytes, std::string::npos);
|
||||
if (!body_chunk.empty()){
|
||||
parse_request(body_chunk, conn_->id());
|
||||
}
|
||||
// keep reading
|
||||
asio::async_read(conn_->socket_, conn_->response_chunk_, asio::transfer_at_least(1),
|
||||
std::bind(&Request::handle_response_body, this,
|
||||
std::placeholders::_1, std::placeholders::_2, conn, cb));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Request::handle_response_body(const asio::error_code& ec, const size_t bytes,
|
||||
std::shared_ptr<Connection> conn, HandlerCb cb)
|
||||
{
|
||||
if (!conn_->is_open()){
|
||||
if (logger_)
|
||||
logger_->e("[http:request] [read:body] closed connection");
|
||||
terminate();
|
||||
if (cb)
|
||||
cb(asio::error::not_connected);
|
||||
return;
|
||||
}
|
||||
if (ec && ec != asio::error::eof){
|
||||
if (logger_)
|
||||
logger_->e("[http:request:%i] [read:body] error: %s", id_, ec.message().c_str());
|
||||
terminate();
|
||||
if (cb)
|
||||
cb(ec);
|
||||
return;
|
||||
}
|
||||
else if ((ec == asio::error::eof) || (ec == asio::error::connection_reset)){
|
||||
terminate();
|
||||
if (cb)
|
||||
cb(ec);
|
||||
return;
|
||||
}
|
||||
std::string body;
|
||||
if (!conn_->response_body_.empty()){
|
||||
// append previous incomplete chunk from header
|
||||
body.append(conn_->response_body_);
|
||||
}
|
||||
// read the response buffer
|
||||
std::ostringstream str_s;
|
||||
str_s << &conn_->response_chunk_;
|
||||
body.append(str_s.str().substr(0, bytes));
|
||||
if (logger_)
|
||||
logger_->d("[http:request:%i] [read:body] success:\n%s", id_, body.c_str());
|
||||
|
||||
parse_request(body);
|
||||
conn_->response_body_.clear();
|
||||
|
||||
asio::async_read(conn_->socket_, conn_->response_chunk_, asio::transfer_at_least(1),
|
||||
std::bind(&Request::handle_response_body, this,
|
||||
std::placeholders::_1, std::placeholders::_2, conn, cb));
|
||||
}
|
||||
|
||||
void
|
||||
Request::parse_request(const std::string request)
|
||||
{
|
||||
http_parser_execute(parser_.get(), parser_s_.get(), request.c_str(), request.size());
|
||||
// detect parsing errors
|
||||
if (HPE_OK != parser_->http_errno && HPE_PAUSED != parser_->http_errno){
|
||||
if (logger_){
|
||||
auto err = HTTP_PARSER_ERRNO(parser_.get());
|
||||
logger_->e("[http:request:%i] [parse] error: %s", id_, http_errno_name(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
Request::get_content_length(const std::string str)
|
||||
{
|
||||
size_t content_length = 0;
|
||||
auto content_length_i = str.find(HTTP_HEADER_CONTENT_LENGTH);
|
||||
if (content_length_i != std::string::npos){
|
||||
auto content_length_str = str.substr(content_length_i + std::strlen(HTTP_HEADER_CONTENT_LENGTH) + 1,
|
||||
str.find("\r\n", content_length_i));
|
||||
try {
|
||||
content_length = atoi(content_length_str.c_str());
|
||||
}
|
||||
catch (const std::exception& e){
|
||||
if (logger_)
|
||||
logger_->d("[http:request:%i] [content-length] invalid '%s': %s",
|
||||
id_, content_length_str.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
return content_length;
|
||||
}
|
||||
|
||||
|
||||
Resolver::Resolver(asio::io_context& ctx, const std::string& host, const std::string& service)
|
||||
{
|
||||
resolver_.async_resolve({host, service}, [this]
|
||||
(const asio::error_code& ec, asio::ip::tcp::resolver::results_type endpoints)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(cbsMutex_);
|
||||
while (not cbs_.empty()) {
|
||||
cbs_.front()(ec, endpoints);
|
||||
cbs_.pop();
|
||||
}
|
||||
error_ = ec;
|
||||
endpoints_ = endpoints;
|
||||
completed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Resolver::addOnResolved(ResolvedCb cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(cbsMutex_);
|
||||
if (completed_) {
|
||||
cb(error_, endpoints_);
|
||||
} else {
|
||||
cbs_.push(std::move(cb));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
private:
|
||||
std::mutex cbsMutex_;
|
||||
std::queue<ResolvedCb> cbs_;
|
||||
|
||||
asio::ip::tcp::resolver resolver_;
|
||||
asio::error_code error_;
|
||||
asio::ip::basic_resolver_results<asio::ip::tcp> endpoints_;
|
||||
} */
|
||||
|
||||
|
||||
} // namespace http
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+1
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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
|
||||
@@ -48,11 +48,4 @@ struct LocalListener {
|
||||
ValueCallback get_cb;
|
||||
};
|
||||
|
||||
|
||||
struct SearchListener {
|
||||
Sp<Query> query;
|
||||
Value::Filter filter;
|
||||
ValueCallback get_cb;
|
||||
};
|
||||
|
||||
}
|
||||
+32
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
@@ -55,9 +55,9 @@ printLog(std::ostream& s, char const *m, va_list args) {
|
||||
s << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
enableLogging(dht::DhtRunner &dht) {
|
||||
dht.setLoggers(
|
||||
std::unique_ptr<Logger>
|
||||
getStdLogger() {
|
||||
return std::unique_ptr<Logger>(new Logger(
|
||||
[](char const *m, va_list args) {
|
||||
std::cerr << red;
|
||||
printLog(std::cerr, m, args);
|
||||
@@ -69,23 +69,23 @@ enableLogging(dht::DhtRunner &dht) {
|
||||
std::cout << def;
|
||||
},
|
||||
[](char const *m, va_list args) { printLog(std::cout, m, args); }
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
void
|
||||
enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
|
||||
auto logfile = std::make_shared<std::fstream>();
|
||||
std::unique_ptr<Logger>
|
||||
getFileLogger(const std::string &path) {
|
||||
auto logfile = std::make_shared<std::ofstream>();
|
||||
logfile->open(path, std::ios::out);
|
||||
|
||||
dht.setLoggers(
|
||||
return std::unique_ptr<Logger>(new Logger(
|
||||
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
|
||||
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
|
||||
[=](char const *m, va_list args) { printLog(*logfile, m, args); }
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
OPENDHT_PUBLIC void
|
||||
enableSyslog(dht::DhtRunner &dht, const char* name) {
|
||||
std::unique_ptr<Logger>
|
||||
getSyslogLogger(const char* name) {
|
||||
#ifndef _WIN32
|
||||
struct Syslog {
|
||||
Syslog(const char* n) {
|
||||
@@ -102,17 +102,34 @@ enableSyslog(dht::DhtRunner &dht, const char* name) {
|
||||
logfile = std::make_shared<Syslog>(name);
|
||||
opened_logfile = logfile;
|
||||
}
|
||||
dht.setLoggers(
|
||||
return std::unique_ptr<Logger>(new Logger(
|
||||
[logfile](char const *m, va_list args) { vsyslog(LOG_ERR, m, args); },
|
||||
[logfile](char const *m, va_list args) { vsyslog(LOG_WARNING, m, args); },
|
||||
[logfile](char const *m, va_list args) { vsyslog(LOG_INFO, m, args); }
|
||||
);
|
||||
));
|
||||
#else
|
||||
return std::unique_ptr<Logger>(new Logger());
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
enableLogging(dht::DhtRunner &dht) {
|
||||
dht.setLogger(*getStdLogger());
|
||||
}
|
||||
|
||||
void
|
||||
enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
|
||||
dht.setLogger(*getFileLogger(path));
|
||||
}
|
||||
|
||||
OPENDHT_PUBLIC void
|
||||
enableSyslog(dht::DhtRunner &dht, const char* name) {
|
||||
dht.setLogger(*getSyslogLogger(name));
|
||||
}
|
||||
|
||||
void
|
||||
disableLogging(dht::DhtRunner &dht) {
|
||||
dht.setLoggers(dht::NOLOG, dht::NOLOG, dht::NOLOG);
|
||||
dht.setLogger({});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 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
|
||||
|
||||
+190
-250
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -17,7 +17,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "network_engine.h"
|
||||
#include "request.h"
|
||||
#include "default_types.h"
|
||||
@@ -26,17 +25,6 @@
|
||||
|
||||
#include <msgpack.hpp>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace dht {
|
||||
namespace net {
|
||||
|
||||
@@ -55,38 +43,10 @@ constexpr std::chrono::seconds NetworkEngine::RX_TIMEOUT;
|
||||
const std::string NetworkEngine::my_v {"RNG1"};
|
||||
constexpr size_t NetworkEngine::MAX_REQUESTS_PER_SEC;
|
||||
|
||||
static const uint8_t v4prefix[16] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0
|
||||
};
|
||||
static constexpr uint8_t v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
|
||||
|
||||
constexpr unsigned SEND_NODES {8};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static bool
|
||||
set_nonblocking(int fd, int nonblocking)
|
||||
{
|
||||
unsigned long mode = !!nonblocking;
|
||||
int rc = ioctlsocket(fd, FIONBIO, &mode);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
extern const char *inet_ntop(int, const void *, char *, socklen_t);
|
||||
|
||||
#else
|
||||
|
||||
static bool
|
||||
set_nonblocking(int fd, int nonblocking)
|
||||
{
|
||||
int rc = fcntl(fd, F_GETFL, 0);
|
||||
if (rc < 0)
|
||||
return false;
|
||||
rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK));
|
||||
return rc >= 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Transaction-ids are 4-bytes long, with the first two bytes identifying
|
||||
* the kind of request, and the remaining two a sequence number in
|
||||
@@ -139,32 +99,31 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
|
||||
nodes6(std::move(msg.nodes6))
|
||||
{}
|
||||
|
||||
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, const int& s, const int& s6)
|
||||
: myid(zeroes), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
|
||||
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock)
|
||||
: myid(zeroes), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler)
|
||||
{}
|
||||
|
||||
NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
|
||||
decltype(NetworkEngine::onError)&& onError,
|
||||
decltype(NetworkEngine::onNewNode)&& onNewNode,
|
||||
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
|
||||
decltype(NetworkEngine::onPing)&& onPing,
|
||||
decltype(NetworkEngine::onFindNode)&& onFindNode,
|
||||
decltype(NetworkEngine::onGetValues)&& onGetValues,
|
||||
decltype(NetworkEngine::onListen)&& onListen,
|
||||
decltype(NetworkEngine::onAnnounce)&& onAnnounce,
|
||||
decltype(NetworkEngine::onRefresh)&& onRefresh) :
|
||||
onError(std::move(onError)),
|
||||
onNewNode(std::move(onNewNode)),
|
||||
onReportedAddr(std::move(onReportedAddr)),
|
||||
onPing(std::move(onPing)),
|
||||
onFindNode(std::move(onFindNode)),
|
||||
onGetValues(std::move(onGetValues)),
|
||||
onListen(std::move(onListen)),
|
||||
onAnnounce(std::move(onAnnounce)),
|
||||
onRefresh(std::move(onRefresh)),
|
||||
myid(myid), network(net), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler)
|
||||
{}
|
||||
NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, const int& s, const int& s6, Logger& log, Scheduler& scheduler,
|
||||
decltype(NetworkEngine::onError) onError,
|
||||
decltype(NetworkEngine::onNewNode) onNewNode,
|
||||
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
|
||||
decltype(NetworkEngine::onPing) onPing,
|
||||
decltype(NetworkEngine::onFindNode) onFindNode,
|
||||
decltype(NetworkEngine::onGetValues) onGetValues,
|
||||
decltype(NetworkEngine::onListen) onListen,
|
||||
decltype(NetworkEngine::onAnnounce) onAnnounce,
|
||||
decltype(NetworkEngine::onRefresh) onRefresh) :
|
||||
onError(onError), onNewNode(onNewNode), onReportedAddr(onReportedAddr), onPing(onPing), onFindNode(onFindNode),
|
||||
onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), onRefresh(onRefresh), myid(myid),
|
||||
network(net), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
|
||||
{
|
||||
if (dht_socket >= 0) {
|
||||
if (!set_nonblocking(dht_socket, 1))
|
||||
throw DhtException("Can't set socket to non-blocking mode");
|
||||
}
|
||||
if (dht_socket6 >= 0) {
|
||||
if (!set_nonblocking(dht_socket6, 1))
|
||||
throw DhtException("Can't set socket to non-blocking mode");
|
||||
}
|
||||
}
|
||||
|
||||
NetworkEngine::~NetworkEngine() {
|
||||
clear();
|
||||
@@ -191,27 +150,27 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(4+(network?1:0));
|
||||
|
||||
pk.pack(std::string("u"));
|
||||
pk.pack(KEY_U);
|
||||
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
if (not token.empty()) {
|
||||
pk.pack(std::string("token")); packToken(pk, token);
|
||||
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
|
||||
}
|
||||
if (not values.empty()) {
|
||||
pk.pack(std::string("re"));
|
||||
pk.pack(KEY_REQ_REFRESHED);
|
||||
pk.pack(values);
|
||||
DHT_LOG.d(n->id, "[node %s] sending %zu refreshed values", n->toString().c_str(), values.size());
|
||||
}
|
||||
|
||||
pk.pack(std::string("t")); pk.pack(socket_id);
|
||||
pk.pack(std::string("y")); pk.pack(std::string("r"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_TID); pk.pack(socket_id);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_R);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
// send response
|
||||
send(buffer.data(), buffer.size(), 0, n->getAddr());
|
||||
send(n->getAddr(), buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -221,27 +180,27 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(4+(network?1:0));
|
||||
|
||||
pk.pack(std::string("u"));
|
||||
pk.pack(KEY_U);
|
||||
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
if (not token.empty()) {
|
||||
pk.pack(std::string("token")); packToken(pk, token);
|
||||
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
|
||||
}
|
||||
if (not values.empty()) {
|
||||
pk.pack(std::string("exp"));
|
||||
pk.pack(KEY_REQ_EXPIRED);
|
||||
pk.pack(values);
|
||||
DHT_LOG.d(n->id, "[node %s] sending %zu expired values", n->toString().c_str(), values.size());
|
||||
}
|
||||
|
||||
pk.pack(std::string("t")); pk.pack(socket_id);
|
||||
pk.pack(std::string("y")); pk.pack(std::string("r"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_TID); pk.pack(socket_id);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_R);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
// send response
|
||||
send(buffer.data(), buffer.size(), 0, n->getAddr());
|
||||
send(n->getAddr(), buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -250,11 +209,11 @@ NetworkEngine::isRunning(sa_family_t af) const
|
||||
{
|
||||
switch (af) {
|
||||
case 0:
|
||||
return dht_socket >= 0 || dht_socket6 >= 0;
|
||||
return dht_socket->hasIPv4() or dht_socket->hasIPv6();
|
||||
case AF_INET:
|
||||
return dht_socket >= 0;
|
||||
return dht_socket->hasIPv4();
|
||||
case AF_INET6:
|
||||
return dht_socket6 >= 0;
|
||||
return dht_socket->hasIPv6();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -295,9 +254,7 @@ NetworkEngine::requestStep(Sp<Request> sreq)
|
||||
req.on_expired(req, false);
|
||||
}
|
||||
|
||||
auto err = send((char*)req.msg.data(), req.msg.size(),
|
||||
(node.getReplyTime() >= now - UDP_REPLY_TIME) ? 0 : MSG_CONFIRM,
|
||||
node.getAddr());
|
||||
auto err = send(node.getAddr(), (char*)req.msg.data(), req.msg.size(), node.getReplyTime() < now - UDP_REPLY_TIME);
|
||||
if (err == ENETUNREACH ||
|
||||
err == EHOSTUNREACH ||
|
||||
err == EAFNOSUPPORT ||
|
||||
@@ -327,11 +284,11 @@ NetworkEngine::requestStep(Sp<Request> sreq)
|
||||
void
|
||||
NetworkEngine::sendRequest(const Sp<Request>& request)
|
||||
{
|
||||
auto& node = request->node;
|
||||
if (not node->id)
|
||||
auto& node = *request->node;
|
||||
if (not node.id)
|
||||
requests.emplace(request->tid, request);
|
||||
request->start = scheduler.time();
|
||||
node->requested(request);
|
||||
node.requested(request);
|
||||
requestStep(request);
|
||||
}
|
||||
|
||||
@@ -353,9 +310,8 @@ NetworkEngine::rateLimit(const SockAddr& addr)
|
||||
limiter_maintenance = 0;
|
||||
}
|
||||
|
||||
auto it = address_rate_limiter.emplace(addr, IpLimiter{});
|
||||
// invoke per IP, then global rate limiter
|
||||
return it.first->second.limit(now) and rate_limiter.limit(now);
|
||||
return address_rate_limiter[addr].limit(now) and rate_limiter.limit(now);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -401,8 +357,9 @@ NetworkEngine::isNodeBlacklisted(const SockAddr& addr) const
|
||||
}
|
||||
|
||||
void
|
||||
NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, const SockAddr& from)
|
||||
NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
|
||||
{
|
||||
auto from = f.getMappedIPv4();
|
||||
if (isMartian(from)) {
|
||||
DHT_LOG.w("Received packet from martian node %s", from.toString().c_str());
|
||||
return;
|
||||
@@ -434,7 +391,8 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, const SockAddr&
|
||||
if (msg->type == MessageType::ValueData) {
|
||||
auto pmsg_it = partial_messages.find(msg->tid);
|
||||
if (pmsg_it == partial_messages.end()) {
|
||||
DHT_LOG.d("Can't find partial message");
|
||||
if (logIncoming_)
|
||||
DHT_LOG.d("Can't find partial message");
|
||||
rateLimit(from);
|
||||
return;
|
||||
}
|
||||
@@ -474,15 +432,15 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, const SockAddr&
|
||||
process(std::move(msg), from);
|
||||
} else {
|
||||
// starting partial message session
|
||||
PartialMessage pmsg;
|
||||
pmsg.from = from;
|
||||
pmsg.msg = std::move(msg);
|
||||
pmsg.start = now;
|
||||
pmsg.last_part = now;
|
||||
auto wmsg = partial_messages.emplace(pmsg.msg->tid, std::move(pmsg));
|
||||
if (wmsg.second) {
|
||||
scheduler.add(now + RX_MAX_PACKET_TIME, std::bind(&NetworkEngine::maintainRxBuffer, this, wmsg.first->first));
|
||||
scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, wmsg.first->first));
|
||||
auto k = msg->tid;
|
||||
auto& pmsg = partial_messages[k];
|
||||
if (not pmsg.msg) {
|
||||
pmsg.from = from;
|
||||
pmsg.msg = std::move(msg);
|
||||
pmsg.start = now;
|
||||
pmsg.last_part = now;
|
||||
scheduler.add(now + RX_MAX_PACKET_TIME, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
|
||||
scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
|
||||
} else
|
||||
DHT_LOG.e("Partial message with given TID already exists");
|
||||
}
|
||||
@@ -544,19 +502,21 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
req->reply_time = time_point::min();
|
||||
onError(req, DhtProtocolException {msg->error_code});
|
||||
} else {
|
||||
DHT_LOG.w(msg->id, "[node %s %s] received unknown error message %u",
|
||||
if (logIncoming_)
|
||||
DHT_LOG.w(msg->id, "[node %s %s] received unknown error message %u",
|
||||
msg->id.toString().c_str(), from.toString().c_str(), msg->error_code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MessageType::Reply:
|
||||
if (req) { /* request reply */
|
||||
if (req->getType() == MessageType::AnnounceValue or req->getType() == MessageType::Listen)
|
||||
req->node->authSuccess();
|
||||
req->reply_time = scheduler.time();
|
||||
auto& r = *req;
|
||||
if (r.getType() == MessageType::AnnounceValue or r.getType() == MessageType::Listen)
|
||||
r.node->authSuccess();
|
||||
r.reply_time = scheduler.time();
|
||||
|
||||
deserializeNodes(*msg, from);
|
||||
req->setDone(std::move(*msg));
|
||||
r.setDone(std::move(*msg));
|
||||
break;
|
||||
} else { /* request socket data */
|
||||
deserializeNodes(*msg, from);
|
||||
@@ -574,7 +534,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
switch (msg->type) {
|
||||
case MessageType::Ping:
|
||||
++in_stats.ping;
|
||||
DHT_LOG.d(node->id, "[node %s] sending pong", node->toString().c_str());
|
||||
if (logIncoming_)
|
||||
DHT_LOG.d(node->id, "[node %s] sending pong", node->toString().c_str());
|
||||
onPing(node);
|
||||
sendPong(from, msg->tid);
|
||||
break;
|
||||
@@ -595,7 +556,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
break;
|
||||
}
|
||||
case MessageType::AnnounceValue: {
|
||||
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'put' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
if (logIncoming_)
|
||||
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'put' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
++in_stats.put;
|
||||
onAnnounce(node, msg->info_hash, msg->token, msg->values, msg->created);
|
||||
|
||||
@@ -608,13 +570,15 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
break;
|
||||
}
|
||||
case MessageType::Refresh:
|
||||
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'refresh' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
if (logIncoming_)
|
||||
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'refresh' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
onRefresh(node, msg->info_hash, msg->token, msg->value_id);
|
||||
/* Same note as above in MessageType::AnnounceValue applies. */
|
||||
sendValueAnnounced(from, msg->tid, msg->value_id);
|
||||
break;
|
||||
case MessageType::Listen: {
|
||||
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'listen' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
if (logIncoming_)
|
||||
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'listen' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
++in_stats.listen;
|
||||
RequestAnswer answer = onListen(node, msg->info_hash, msg->token, msg->socket_id, std::move(msg->query));
|
||||
auto nnodes = bufferNodes(from.getFamily(), msg->info_hash, msg->want, answer.nodes4, answer.nodes6);
|
||||
@@ -645,33 +609,9 @@ insertAddr(msgpack::packer<msgpack::sbuffer>& pk, const SockAddr& addr)
|
||||
}
|
||||
|
||||
int
|
||||
NetworkEngine::send(const char *buf, size_t len, int flags, const SockAddr& addr)
|
||||
NetworkEngine::send(const SockAddr& addr, const char *buf, size_t len, bool confirmed)
|
||||
{
|
||||
if (not addr)
|
||||
return EFAULT;
|
||||
|
||||
int s;
|
||||
if (addr.getFamily() == AF_INET)
|
||||
s = dht_socket;
|
||||
else if (addr.getFamily() == AF_INET6)
|
||||
s = dht_socket6;
|
||||
else
|
||||
s = -1;
|
||||
|
||||
if (s < 0)
|
||||
return EAFNOSUPPORT;
|
||||
#ifdef MSG_NOSIGNAL
|
||||
flags |= MSG_NOSIGNAL;
|
||||
#endif
|
||||
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;
|
||||
return dht_socket ? dht_socket->sendTo(addr, (const uint8_t*)buf, len, confirmed) : ENOTCONN;
|
||||
}
|
||||
|
||||
Sp<Request>
|
||||
@@ -681,16 +621,16 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(5+(network?1:0));
|
||||
|
||||
pk.pack(std::string("a")); pk.pack_map(1);
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(KEY_A); pk.pack_map(1);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
|
||||
pk.pack(std::string("q")); pk.pack(std::string("ping"));
|
||||
pk.pack(std::string("t")); pk.pack_bin(tid.size());
|
||||
pk.pack(KEY_Q); pk.pack(QUERY_PING);
|
||||
pk.pack(KEY_TID); pk.pack_bin(tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("q"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_Q);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
auto req = std::make_shared<Request>(MessageType::Ping, tid.toInt(), node,
|
||||
@@ -718,20 +658,20 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(4+(network?1:0));
|
||||
|
||||
pk.pack(std::string("r")); pk.pack_map(2);
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(KEY_R); pk.pack_map(2);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
insertAddr(pk, addr);
|
||||
|
||||
TransId t (tid);
|
||||
pk.pack(std::string("t")); pk.pack_bin(t.size());
|
||||
pk.pack(KEY_TID); pk.pack_bin(t.size());
|
||||
pk.pack_bin_body((const char*)t.data(), t.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("r"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_R);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
send(buffer.data(), buffer.size(), 0, addr);
|
||||
send(addr, buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
Sp<Request>
|
||||
@@ -742,23 +682,23 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(5+(network?1:0));
|
||||
|
||||
pk.pack(std::string("a")); pk.pack_map(2 + (want>0?1:0));
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(std::string("target")); pk.pack(target);
|
||||
pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_TARGET); pk.pack(target);
|
||||
if (want > 0) {
|
||||
pk.pack(std::string("w"));
|
||||
pk.pack(KEY_REQ_WANT);
|
||||
pk.pack_array(((want & WANT4)?1:0) + ((want & WANT6)?1:0));
|
||||
if (want & WANT4) pk.pack(AF_INET);
|
||||
if (want & WANT6) pk.pack(AF_INET6);
|
||||
}
|
||||
|
||||
pk.pack(std::string("q")); pk.pack(std::string("find"));
|
||||
pk.pack(std::string("t")); pk.pack_bin(tid.size());
|
||||
pk.pack(KEY_Q); pk.pack(QUERY_FIND);
|
||||
pk.pack(KEY_TID); pk.pack_bin(tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("q"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_Q);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
auto req = std::make_shared<Request>(MessageType::FindNode, tid.toInt(), n,
|
||||
@@ -788,26 +728,26 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query&
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(5+(network?1:0));
|
||||
|
||||
pk.pack(std::string("a")); pk.pack_map(2 +
|
||||
pk.pack(KEY_A); pk.pack_map(2 +
|
||||
(query.where.getFilter() or not query.select.getSelection().empty() ? 1:0) +
|
||||
(want>0?1:0));
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(std::string("h")); pk.pack(info_hash);
|
||||
pk.pack(std::string("q")); pk.pack(query);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_H); pk.pack(info_hash);
|
||||
pk.pack(KEY_Q); pk.pack(query);
|
||||
if (want > 0) {
|
||||
pk.pack(std::string("w"));
|
||||
pk.pack(KEY_REQ_WANT);
|
||||
pk.pack_array(((want & WANT4)?1:0) + ((want & WANT6)?1:0));
|
||||
if (want & WANT4) pk.pack(AF_INET);
|
||||
if (want & WANT6) pk.pack(AF_INET6);
|
||||
}
|
||||
|
||||
pk.pack(std::string("q")); pk.pack(std::string("get"));
|
||||
pk.pack(std::string("t")); pk.pack_bin(tid.size());
|
||||
pk.pack(KEY_Q); pk.pack(QUERY_GET);
|
||||
pk.pack(KEY_TID); pk.pack_bin(tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("q"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_Q);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
auto req = std::make_shared<Request>(MessageType::GetValues, tid.toInt(), n,
|
||||
@@ -895,13 +835,13 @@ NetworkEngine::packValueHeader(msgpack::sbuffer& buffer, const std::vector<Sp<Va
|
||||
total_size += v.size();
|
||||
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack(std::string("values"));
|
||||
pk.pack(KEY_REQ_VALUES);
|
||||
pk.pack_array(svals.size());
|
||||
// try to put everything in a single UDP packet
|
||||
if (svals.size() < 50 && total_size < MAX_PACKET_VALUE_SIZE) {
|
||||
for (const auto& b : svals)
|
||||
buffer.write((const char*)b.data(), b.size());
|
||||
DHT_LOG.d("sending %lu bytes of values", total_size);
|
||||
// DHT_LOG.d("sending %lu bytes of values", total_size);
|
||||
svals.clear();
|
||||
} else {
|
||||
for (const auto& b : svals)
|
||||
@@ -923,17 +863,17 @@ NetworkEngine::sendValueParts(const TransId& tid, const std::vector<Blob>& svals
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(3+(network?1:0));
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
pk.pack(std::string("y")); pk.pack(std::string("v"));
|
||||
pk.pack(std::string("t")); pk.pack_bin(tid.size());
|
||||
pk.pack(KEY_Y); pk.pack(KEY_V);
|
||||
pk.pack(KEY_TID); pk.pack_bin(tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack(std::string("p")); pk.pack_map(1);
|
||||
pk.pack(KEY_V); pk.pack_map(1);
|
||||
pk.pack(i); pk.pack_map(2);
|
||||
pk.pack(std::string("o")); pk.pack(start);
|
||||
pk.pack(std::string("d")); pk.pack_bin(end-start);
|
||||
pk.pack_bin_body((const char*)v.data()+start, end-start);
|
||||
send(buffer.data(), buffer.size(), 0, addr);
|
||||
send(addr, buffer.data(), buffer.size());
|
||||
start = end;
|
||||
} while (start != v.size());
|
||||
i++;
|
||||
@@ -948,22 +888,22 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(4+(network?1:0));
|
||||
|
||||
pk.pack(std::string("r"));
|
||||
pk.pack(KEY_R);
|
||||
pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0));
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
insertAddr(pk, addr);
|
||||
if (nodes.size() > 0) {
|
||||
pk.pack(std::string("n4"));
|
||||
pk.pack(KEY_REQ_NODES4);
|
||||
pk.pack_bin(nodes.size());
|
||||
pk.pack_bin_body((const char*)nodes.data(), nodes.size());
|
||||
}
|
||||
if (nodes6.size() > 0) {
|
||||
pk.pack(std::string("n6"));
|
||||
pk.pack(KEY_REQ_NODES6);
|
||||
pk.pack_bin(nodes6.size());
|
||||
pk.pack_bin_body((const char*)nodes6.data(), nodes6.size());
|
||||
}
|
||||
if (not token.empty()) {
|
||||
pk.pack(std::string("token")); packToken(pk, token);
|
||||
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
|
||||
}
|
||||
std::vector<Blob> svals {};
|
||||
if (not st.empty()) { /* pack complete values */
|
||||
@@ -971,7 +911,7 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
|
||||
if (fields.empty()) {
|
||||
svals = packValueHeader(buffer, st);
|
||||
} else { /* pack fields */
|
||||
pk.pack(std::string("fields"));
|
||||
pk.pack(KEY_REQ_FIELDS);
|
||||
pk.pack_map(2);
|
||||
pk.pack(std::string("f")); pk.pack(fields);
|
||||
pk.pack(std::string("v")); pk.pack_array(st.size()*fields.size());
|
||||
@@ -983,16 +923,16 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
|
||||
}
|
||||
|
||||
TransId t (tid);
|
||||
pk.pack(std::string("t")); pk.pack_bin(t.size());
|
||||
pk.pack_bin_body((const char*)t.data(), t.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("r"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_TID); pk.pack_bin(t.size());
|
||||
pk.pack_bin_body((const char*)t.data(), t.size());
|
||||
pk.pack(KEY_Y); pk.pack(KEY_R);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
// send response
|
||||
send(buffer.data(), buffer.size(), 0, addr);
|
||||
send(addr, buffer.data(), buffer.size());
|
||||
|
||||
// send parts
|
||||
if (not svals.empty())
|
||||
@@ -1080,23 +1020,23 @@ NetworkEngine::sendListen(Sp<Node> n,
|
||||
pk.pack_map(5+(network?1:0));
|
||||
|
||||
auto has_query = query.where.getFilter() or not query.select.getSelection().empty();
|
||||
pk.pack(std::string("a")); pk.pack_map(4 + has_query);
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(std::string("h")); pk.pack(hash);
|
||||
pk.pack(std::string("token")); packToken(pk, token);
|
||||
pk.pack(std::string("sid")); pk.pack_bin(sid.size());
|
||||
pk.pack_bin_body((const char*)sid.data(), sid.size());
|
||||
pk.pack(KEY_A); pk.pack_map(4 + has_query);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_H); pk.pack(hash);
|
||||
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
|
||||
pk.pack(KEY_REQ_SID); pk.pack_bin(sid.size());
|
||||
pk.pack_bin_body((const char*)sid.data(), sid.size());
|
||||
if (has_query) {
|
||||
pk.pack(std::string("q")); pk.pack(query);
|
||||
pk.pack(KEY_REQ_QUERY); pk.pack(query);
|
||||
}
|
||||
|
||||
pk.pack(std::string("q")); pk.pack(std::string("listen"));
|
||||
pk.pack(std::string("t")); pk.pack_bin(tid.size());
|
||||
pk.pack(KEY_Q); pk.pack(QUERY_LISTEN);
|
||||
pk.pack(KEY_TID); pk.pack_bin(tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("q"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_Q);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
auto req = std::make_shared<Request>(MessageType::Listen, tid.toInt(), n,
|
||||
@@ -1122,20 +1062,20 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(4+(network?1:0));
|
||||
|
||||
pk.pack(std::string("r")); pk.pack_map(2);
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(KEY_R); pk.pack_map(2);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
insertAddr(pk, addr);
|
||||
|
||||
TransId t (tid);
|
||||
pk.pack(std::string("t")); pk.pack_bin(t.size());
|
||||
pk.pack(KEY_TID); pk.pack_bin(t.size());
|
||||
pk.pack_bin_body((const char*)t.data(), t.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("r"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_R);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
send(buffer.data(), buffer.size(), 0, addr);
|
||||
send(addr, buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
Sp<Request>
|
||||
@@ -1152,23 +1092,23 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(5+(network?1:0));
|
||||
|
||||
pk.pack(std::string("a")); pk.pack_map((created < scheduler.time() ? 5 : 4));
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(std::string("h")); pk.pack(infohash);
|
||||
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4));
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_H); pk.pack(infohash);
|
||||
auto v = packValueHeader(buffer, {value});
|
||||
if (created < scheduler.time()) {
|
||||
pk.pack(std::string("c"));
|
||||
pk.pack(KEY_REQ_CREATION);
|
||||
pk.pack(to_time_t(created));
|
||||
}
|
||||
pk.pack(std::string("token")); pk.pack(token);
|
||||
pk.pack(KEY_REQ_TOKEN); pk.pack(token);
|
||||
|
||||
pk.pack(std::string("q")); pk.pack(std::string("put"));
|
||||
pk.pack(std::string("t")); pk.pack_bin(tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("q"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Q); pk.pack(QUERY_PUT);
|
||||
pk.pack(KEY_TID); pk.pack_bin(tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack(KEY_Y); pk.pack(KEY_Q);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid.toInt(), n,
|
||||
@@ -1210,19 +1150,19 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(5+(network?1:0));
|
||||
|
||||
pk.pack(std::string("a")); pk.pack_map(4);
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(std::string("h")); pk.pack(infohash);
|
||||
pk.pack(std::string("vid")); pk.pack(vid);
|
||||
pk.pack(std::string("token")); pk.pack(token);
|
||||
pk.pack(KEY_A); pk.pack_map(4);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_H); pk.pack(infohash);
|
||||
pk.pack(KEY_REQ_VALUE_ID); pk.pack(vid);
|
||||
pk.pack(KEY_REQ_TOKEN); pk.pack(token);
|
||||
|
||||
pk.pack(std::string("q")); pk.pack(std::string("refresh"));
|
||||
pk.pack(std::string("t")); pk.pack_bin(tid.size());
|
||||
pk.pack(KEY_Q); pk.pack(QUERY_REFRESH);
|
||||
pk.pack(KEY_TID); pk.pack_bin(tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("q"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_Q);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
auto req = std::make_shared<Request>(MessageType::Refresh, tid.toInt(), n,
|
||||
@@ -1255,21 +1195,21 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(4+(network?1:0));
|
||||
|
||||
pk.pack(std::string("r")); pk.pack_map(3);
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(std::string("vid")); pk.pack(vid);
|
||||
pk.pack(KEY_R); pk.pack_map(3);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_VALUE_ID); pk.pack(vid);
|
||||
insertAddr(pk, addr);
|
||||
|
||||
TransId t(tid);
|
||||
pk.pack(std::string("t")); pk.pack_bin(t.size());
|
||||
pk.pack(KEY_TID); pk.pack_bin(t.size());
|
||||
pk.pack_bin_body((const char*)t.data(), t.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("r"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_R);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
send(buffer.data(), buffer.size(), 0, addr);
|
||||
send(addr, buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1283,25 +1223,25 @@ NetworkEngine::sendError(const SockAddr& addr,
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(4 + (include_id?1:0));
|
||||
|
||||
pk.pack(std::string("e")); pk.pack_array(2);
|
||||
pk.pack(KEY_E); pk.pack_array(2);
|
||||
pk.pack(code);
|
||||
pk.pack(message);
|
||||
|
||||
if (include_id) {
|
||||
pk.pack(std::string("r")); pk.pack_map(1);
|
||||
pk.pack(std::string("id")); pk.pack(myid);
|
||||
pk.pack(KEY_R); pk.pack_map(1);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
}
|
||||
|
||||
TransId t(tid);
|
||||
pk.pack(std::string("t")); pk.pack_bin(t.size());
|
||||
pk.pack(KEY_TID); pk.pack_bin(t.size());
|
||||
pk.pack_bin_body((const char*)t.data(), t.size());
|
||||
pk.pack(std::string("y")); pk.pack(std::string("e"));
|
||||
pk.pack(std::string("v")); pk.pack(my_v);
|
||||
pk.pack(KEY_Y); pk.pack(KEY_E);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (network) {
|
||||
pk.pack(std::string("n")); pk.pack(network);
|
||||
pk.pack(KEY_NETID); pk.pack(network);
|
||||
}
|
||||
|
||||
send(buffer.data(), buffer.size(), 0, addr);
|
||||
send(addr, buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "network_utils.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "utils.h"
|
||||
#include <io.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#define close(x) closesocket(x)
|
||||
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace dht {
|
||||
namespace net {
|
||||
|
||||
int
|
||||
bindSocket(const SockAddr& addr, SockAddr& bound)
|
||||
{
|
||||
bool is_ipv6 = addr.getFamily() == AF_INET6;
|
||||
int sock = socket(is_ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0)
|
||||
throw DhtException(std::string("Can't open socket: ") + strerror(sock));
|
||||
int set = 1;
|
||||
#ifdef SO_NOSIGPIPE
|
||||
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&set, sizeof(set));
|
||||
#endif
|
||||
if (is_ipv6)
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&set, sizeof(set));
|
||||
net::setNonblocking(sock);
|
||||
int rc = bind(sock, addr.get(), addr.getLength());
|
||||
if (rc < 0) {
|
||||
rc = errno;
|
||||
close(sock);
|
||||
throw DhtException("Can't bind socket on " + addr.toString() + " " + strerror(rc));
|
||||
}
|
||||
sockaddr_storage ss;
|
||||
socklen_t ss_len = sizeof(ss);
|
||||
getsockname(sock, (sockaddr*)&ss, &ss_len);
|
||||
bound = {ss, ss_len};
|
||||
return sock;
|
||||
}
|
||||
|
||||
bool
|
||||
setNonblocking(int fd, bool nonblocking)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned long mode = !!nonblocking;
|
||||
int rc = ioctlsocket(fd, FIONBIO, &mode);
|
||||
return rc == 0;
|
||||
#else
|
||||
int rc = fcntl(fd, F_GETFL, 0);
|
||||
if (rc < 0)
|
||||
return false;
|
||||
rc = fcntl(fd, F_SETFL, nonblocking ? (rc | O_NONBLOCK) : (rc & ~O_NONBLOCK));
|
||||
return rc >= 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void udpPipe(int fds[2])
|
||||
{
|
||||
int lst = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (lst < 0)
|
||||
throw DhtException(std::string("Can't open socket: ") + strerror(WSAGetLastError()));
|
||||
sockaddr_in inaddr;
|
||||
sockaddr addr;
|
||||
memset(&inaddr, 0, sizeof(inaddr));
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
inaddr.sin_family = AF_INET;
|
||||
inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
inaddr.sin_port = 0;
|
||||
int yes = 1;
|
||||
setsockopt(lst, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
|
||||
int rc = bind(lst, (sockaddr*)&inaddr, sizeof(inaddr));
|
||||
if (rc < 0) {
|
||||
close(lst);
|
||||
throw DhtException("Can't bind socket on " + print_addr((sockaddr*)&inaddr, sizeof(inaddr)) + " " + strerror(rc));
|
||||
}
|
||||
socklen_t len = sizeof(addr);
|
||||
getsockname(lst, &addr, &len);
|
||||
fds[0] = lst;
|
||||
fds[1] = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
connect(fds[1], &addr, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
UdpSocket::UdpSocket(in_port_t port, const Logger& l) : logger(l) {
|
||||
SockAddr bind4;
|
||||
bind4.setFamily(AF_INET);
|
||||
bind4.setPort(port);
|
||||
SockAddr bind6;
|
||||
bind6.setFamily(AF_INET6);
|
||||
bind6.setPort(port);
|
||||
openSockets(bind4, bind6);
|
||||
}
|
||||
|
||||
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l) : logger(l)
|
||||
{
|
||||
openSockets(bind4, bind6);
|
||||
}
|
||||
|
||||
UdpSocket::~UdpSocket() {
|
||||
stop();
|
||||
if (rcv_thread.joinable())
|
||||
rcv_thread.join();
|
||||
}
|
||||
|
||||
int
|
||||
UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) {
|
||||
if (not dest)
|
||||
return EFAULT;
|
||||
|
||||
int s;
|
||||
switch (dest.getFamily()) {
|
||||
case AF_INET: s = s4; break;
|
||||
case AF_INET6: s = s6; break;
|
||||
default: s = -1; break;
|
||||
}
|
||||
|
||||
if (s < 0)
|
||||
return EAFNOSUPPORT;
|
||||
|
||||
int flags = 0;
|
||||
#ifdef MSG_CONFIRM
|
||||
if (replied)
|
||||
flags |= MSG_CONFIRM;
|
||||
#endif
|
||||
#ifdef MSG_NOSIGNAL
|
||||
flags |= MSG_NOSIGNAL;
|
||||
#endif
|
||||
|
||||
if (sendto(s, (const char*)data, size, flags, dest.get(), dest.getLength()) == -1) {
|
||||
int err = errno;
|
||||
logger.d("Can't send message to %s: %s", dest.toString().c_str(), strerror(err));
|
||||
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
|
||||
auto bind4 = std::move(bound4), bind6 = std::move(bound6);
|
||||
openSockets(bind4, bind6);
|
||||
return sendTo(dest, data, size, false);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
|
||||
{
|
||||
stop();
|
||||
if (rcv_thread.joinable())
|
||||
rcv_thread.join();
|
||||
|
||||
int stopfds[2];
|
||||
#ifndef _WIN32
|
||||
auto status = pipe(stopfds);
|
||||
if (status == -1) {
|
||||
throw DhtException(std::string("Can't open pipe: ") + strerror(errno));
|
||||
}
|
||||
#else
|
||||
udpPipe(stopfds);
|
||||
#endif
|
||||
int stop_readfd = stopfds[0];
|
||||
stopfd = stopfds[1];
|
||||
|
||||
s4 = -1;
|
||||
s6 = -1;
|
||||
|
||||
bound4 = {};
|
||||
if (bind4) {
|
||||
try {
|
||||
s4 = bindSocket(bind4, bound4);
|
||||
} catch (const DhtException& e) {
|
||||
logger.e("Can't bind inet socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
bound6 = {};
|
||||
if (bind6) {
|
||||
if (bind6.getPort() == 0) {
|
||||
// Attempt to use the same port as IPv4 with IPv6
|
||||
if (auto p4 = bound4.getPort()) {
|
||||
auto b6 = bind6;
|
||||
b6.setPort(p4);
|
||||
try {
|
||||
s6 = bindSocket(b6, bound6);
|
||||
} catch (const DhtException& e) {
|
||||
logger.e("Can't bind inet6 socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s6 == -1) {
|
||||
try {
|
||||
s6 = bindSocket(bind6, bound6);
|
||||
} catch (const DhtException& e) {
|
||||
logger.e("Can't bind inet6 socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s4 == -1 && s6 == -1) {
|
||||
throw DhtException("Can't bind socket");
|
||||
}
|
||||
|
||||
running = true;
|
||||
rcv_thread = std::thread([this, stop_readfd]() {
|
||||
int selectFd = std::max({s4, s6, stop_readfd}) + 1;
|
||||
try {
|
||||
while (running) {
|
||||
fd_set readfds;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(stop_readfd, &readfds);
|
||||
if(s4 >= 0)
|
||||
FD_SET(s4, &readfds);
|
||||
if(s6 >= 0)
|
||||
FD_SET(s6, &readfds);
|
||||
|
||||
int rc = select(selectFd, &readfds, nullptr, nullptr, nullptr);
|
||||
if (rc < 0) {
|
||||
if (errno != EINTR) {
|
||||
logger.e("Select error: %s", strerror(errno));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
if (not running)
|
||||
break;
|
||||
|
||||
if (rc > 0) {
|
||||
std::array<uint8_t, 1024 * 64> buf;
|
||||
sockaddr_storage from;
|
||||
socklen_t from_len = sizeof(from);
|
||||
|
||||
if (FD_ISSET(stop_readfd, &readfds)) {
|
||||
if (recv(stop_readfd, (char*)buf.data(), buf.size(), 0) < 0) {
|
||||
logger.e("Got stop packet error: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (s4 >= 0 && FD_ISSET(s4, &readfds))
|
||||
rc = recvfrom(s4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
|
||||
else if (s6 >= 0 && FD_ISSET(s6, &readfds))
|
||||
rc = recvfrom(s6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
|
||||
else
|
||||
continue;
|
||||
|
||||
if (rc > 0) {
|
||||
auto pkt = std::unique_ptr<ReceivedPacket>(new ReceivedPacket);
|
||||
pkt->data = {buf.begin(), buf.begin()+rc};
|
||||
pkt->from = {from, from_len};
|
||||
pkt->received = clock::now();
|
||||
onReceived(std::move(pkt));
|
||||
} else if (rc == -1) {
|
||||
logger.e("Error receiving packet: %s", strerror(errno));
|
||||
int err = errno;
|
||||
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
|
||||
if (s4 >= 0) {
|
||||
close(s4);
|
||||
try {
|
||||
s4 = bindSocket(bound4, bound4);
|
||||
} catch (const DhtException& e) {
|
||||
logger.e("Can't bind inet socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
if (s6 >= 0) {
|
||||
close(s6);
|
||||
try {
|
||||
s6 = bindSocket(bound6, bound6);
|
||||
} catch (const DhtException& e) {
|
||||
logger.e("Can't bind inet6 socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
if (s4 < 0 && s6 < 0)
|
||||
break;
|
||||
selectFd = std::max({s4, s6, stop_readfd}) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
logger.e("Error in UdpSocket rx thread: %s", e.what());
|
||||
}
|
||||
if (s4 >= 0)
|
||||
close(s4);
|
||||
if (s6 >= 0)
|
||||
close(s6);
|
||||
s4 = -1;
|
||||
s6 = -1;
|
||||
bound4 = {};
|
||||
bound6 = {};
|
||||
if (stop_readfd != -1)
|
||||
close(stop_readfd);
|
||||
if (stopfd != -1)
|
||||
close(stopfd);
|
||||
stopfd = -1;
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
UdpSocket::stop()
|
||||
{
|
||||
if (running.exchange(false)) {
|
||||
auto sfd = stopfd;
|
||||
if (sfd != -1 && write(sfd, "\0", 1) == -1) {
|
||||
logger.e("Can't write to stop fd");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -49,7 +49,7 @@ Node::isGood(time_point now) const
|
||||
bool
|
||||
Node::isPendingMessage() const
|
||||
{
|
||||
for (auto r : requests_) {
|
||||
for (const auto& r : requests_) {
|
||||
if (r.second->pending())
|
||||
return true;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ size_t
|
||||
Node::getPendingMessageCount() const
|
||||
{
|
||||
size_t count {0};
|
||||
for (auto r : requests_) {
|
||||
for (const auto& r : requests_) {
|
||||
if (r.second->pending())
|
||||
count++;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 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
|
||||
@@ -25,7 +25,7 @@ bool
|
||||
OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals) {
|
||||
std::vector<Sp<Value>> newValues;
|
||||
for (const auto& v : vals) {
|
||||
auto viop = values.emplace(v->id, OpCacheValueStorage{v});
|
||||
auto viop = values.emplace(v->id, v);
|
||||
if (viop.second) {
|
||||
newValues.emplace_back(v);
|
||||
} else {
|
||||
@@ -34,6 +34,7 @@ OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals) {
|
||||
}
|
||||
return newValues.empty() ? true : callback(newValues, false);
|
||||
}
|
||||
|
||||
bool
|
||||
OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
|
||||
std::vector<Sp<Value>> expiredValues;
|
||||
@@ -49,8 +50,26 @@ OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
|
||||
}
|
||||
return expiredValues.empty() ? true : callback(expiredValues, true);
|
||||
}
|
||||
|
||||
bool
|
||||
OpValueCache::onValuesExpired(const std::vector<Value::Id>& vids)
|
||||
{
|
||||
std::vector<Sp<Value>> expiredValues;
|
||||
for (const auto& vid : vids) {
|
||||
auto vit = values.find(vid);
|
||||
if (vit != values.end()) {
|
||||
vit->second.refCount--;
|
||||
if (not vit->second.refCount) {
|
||||
expiredValues.emplace_back(std::move(vit->second.data));
|
||||
values.erase(vit);
|
||||
}
|
||||
}
|
||||
}
|
||||
return expiredValues.empty() ? true : callback(expiredValues, true);
|
||||
}
|
||||
|
||||
std::vector<Sp<Value>>
|
||||
OpValueCache::get(Value::Filter& filter) const {
|
||||
OpValueCache::get(const Value::Filter& filter) const {
|
||||
std::vector<Sp<Value>> ret;
|
||||
if (not filter)
|
||||
ret.reserve(values.size());
|
||||
@@ -108,33 +127,57 @@ OpCache::getExpiration() const {
|
||||
return lastRemoved + EXPIRATION;
|
||||
}
|
||||
|
||||
size_t
|
||||
SearchCache::listen(ValueCallback get_cb, Sp<Query> q, Value::Filter filter, std::function<size_t(Sp<Query>, ValueCallback)> onListen)
|
||||
SearchCache::OpMap::iterator
|
||||
SearchCache::getOp(const Sp<Query>& q)
|
||||
{
|
||||
// find exact match
|
||||
auto op = ops.find(q);
|
||||
if (op == ops.end()) {
|
||||
// find satisfying query
|
||||
for (auto it = ops.begin(); it != ops.end(); it++) {
|
||||
if (q->isSatisfiedBy(*it->first)) {
|
||||
op = it;
|
||||
break;
|
||||
}
|
||||
if (op != ops.end())
|
||||
return op;
|
||||
// find satisfying query
|
||||
for (auto it = ops.begin(); it != ops.end(); it++) {
|
||||
if (q->isSatisfiedBy(*it->first)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return ops.end();
|
||||
}
|
||||
|
||||
SearchCache::OpMap::const_iterator
|
||||
SearchCache::getOp(const Sp<Query>& q) const
|
||||
{
|
||||
// find exact match
|
||||
auto op = ops.find(q);
|
||||
if (op != ops.cend())
|
||||
return op;
|
||||
// find satisfying query
|
||||
for (auto it = ops.begin(); it != ops.end(); it++) {
|
||||
if (q->isSatisfiedBy(*it->first)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return ops.cend();
|
||||
}
|
||||
|
||||
size_t
|
||||
SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen)
|
||||
{
|
||||
// find exact match
|
||||
auto op = getOp(q);
|
||||
if (op == ops.end()) {
|
||||
// New query
|
||||
op = ops.emplace(q, std::unique_ptr<OpCache>(new OpCache)).first;
|
||||
auto& cache = *op->second;
|
||||
cache.searchToken = onListen(q, [&](const std::vector<Sp<Value>>& values, bool expired){
|
||||
return cache.onValue(values, expired);
|
||||
}, [&](ListenSyncStatus status) {
|
||||
cache.onNodeChanged(status);
|
||||
});
|
||||
}
|
||||
auto token = nextToken_++;
|
||||
if (nextToken_ == 0)
|
||||
nextToken_++;
|
||||
op->second->addListener(token, get_cb, q, filter);
|
||||
return token;
|
||||
return op->second->addListener(token, get_cb, q, filter) ? token : 0;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -149,7 +192,7 @@ SearchCache::cancelListen(size_t gtoken, const time_point& now) {
|
||||
}
|
||||
|
||||
void
|
||||
SearchCache::cancelAll(std::function<void(size_t)> onCancel) {
|
||||
SearchCache::cancelAll(const std::function<void(size_t)>& onCancel) {
|
||||
for (auto& op : ops) {
|
||||
auto cache = std::move(op.second);
|
||||
cache->removeAll();
|
||||
@@ -159,7 +202,7 @@ SearchCache::cancelAll(std::function<void(size_t)> onCancel) {
|
||||
}
|
||||
|
||||
time_point
|
||||
SearchCache::expire(const time_point& now, std::function<void(size_t)> onCancel) {
|
||||
SearchCache::expire(const time_point& now, const std::function<void(size_t)>& onCancel) {
|
||||
nextExpiration_ = time_point::max();
|
||||
auto ret = nextExpiration_;
|
||||
for (auto it = ops.begin(); it != ops.end();) {
|
||||
@@ -177,8 +220,22 @@ SearchCache::expire(const time_point& now, std::function<void(size_t)> onCancel)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
SearchCache::get(const Value::Filter& f, const Sp<Query>& q, const GetCallback& gcb, const DoneCallback& dcb) const
|
||||
{
|
||||
auto op = getOp(q);
|
||||
if (op != ops.end()) {
|
||||
auto vals = op->second->get(f);
|
||||
if ((not vals.empty() and not gcb(vals)) or op->second->isSynced()) {
|
||||
dcb(true, {});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Sp<Value>>
|
||||
SearchCache::get(Value::Filter& filter) const {
|
||||
SearchCache::get(const Value::Filter& filter) const {
|
||||
if (ops.size() == 1)
|
||||
return ops.begin()->second->get(filter);
|
||||
std::map<Value::Id, Sp<Value>> c;
|
||||
|
||||
+51
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 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
|
||||
@@ -27,20 +27,23 @@ struct OpCacheValueStorage
|
||||
{
|
||||
Sp<Value> data {};
|
||||
unsigned refCount {1};
|
||||
OpCacheValueStorage(Sp<Value> val = {}) : data(val) {}
|
||||
OpCacheValueStorage(Sp<Value> val) : data(val) {}
|
||||
};
|
||||
|
||||
class OpValueCache {
|
||||
public:
|
||||
OpValueCache(ValueCallback&& cb) : callback(std::forward<ValueCallback>(cb)) {}
|
||||
OpValueCache(OpValueCache&& o) : values(std::move(o.values)), callback(std::move(o.callback)) {
|
||||
OpValueCache(ValueCallback&& cb) noexcept : callback(std::forward<ValueCallback>(cb)) {}
|
||||
OpValueCache(OpValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)) {
|
||||
o.callback = {};
|
||||
}
|
||||
|
||||
static ValueCallback cacheCallback(ValueCallback&& cb) {
|
||||
static ValueCallback cacheCallback(ValueCallback&& cb, std::function<void()>&& onCancel) {
|
||||
auto cache = std::make_shared<OpValueCache>(std::forward<ValueCallback>(cb));
|
||||
return [cache](const std::vector<Sp<Value>>& vals, bool expired){
|
||||
return cache->onValue(vals, expired);
|
||||
return [cache, onCancel](const std::vector<Sp<Value>>& vals, bool expired){
|
||||
auto ret = cache->onValue(vals, expired);
|
||||
if (not ret)
|
||||
onCancel();
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -53,8 +56,20 @@ public:
|
||||
|
||||
bool onValuesAdded(const std::vector<Sp<Value>>& vals);
|
||||
bool onValuesExpired(const std::vector<Sp<Value>>& vals);
|
||||
bool onValuesExpired(const std::vector<Value::Id>& vals);
|
||||
|
||||
std::vector<Sp<Value>> get(Value::Filter& filter) const;
|
||||
void onNodeChanged(ListenSyncStatus status) {
|
||||
switch (status) {
|
||||
case ListenSyncStatus::ADDED: nodes++; break;
|
||||
case ListenSyncStatus::REMOVED: nodes--; break;
|
||||
case ListenSyncStatus::SYNCED : syncedNodes++; break;
|
||||
case ListenSyncStatus::UNSYNCED: syncedNodes--; break;
|
||||
}
|
||||
}
|
||||
|
||||
bool isSynced() const { return nodes > 0 and syncedNodes == nodes; }
|
||||
|
||||
std::vector<Sp<Value>> get(const Value::Filter& filter) const;
|
||||
Sp<Value> get(Value::Id id) const;
|
||||
std::vector<Sp<Value>> getValues() const;
|
||||
|
||||
@@ -62,6 +77,8 @@ private:
|
||||
OpValueCache(const OpValueCache&) = delete;
|
||||
OpValueCache& operator=(const OpValueCache&) = delete;
|
||||
|
||||
size_t nodes {0};
|
||||
size_t syncedNodes {0};
|
||||
std::map<Value::Id, OpCacheValueStorage> values {};
|
||||
ValueCallback callback;
|
||||
};
|
||||
@@ -80,13 +97,20 @@ public:
|
||||
cache.onValue(vals, expired);
|
||||
return not listeners.empty();
|
||||
}
|
||||
void onNodeChanged(ListenSyncStatus status) {
|
||||
cache.onNodeChanged(status);
|
||||
}
|
||||
|
||||
void onValuesAdded(const std::vector<Sp<Value>>& vals);
|
||||
void onValuesExpired(const std::vector<Sp<Value>>& vals);
|
||||
|
||||
void addListener(size_t token, ValueCallback cb, Sp<Query> q, Value::Filter filter) {
|
||||
bool addListener(size_t token, const ValueCallback& cb, const Sp<Query>& q, const Value::Filter& filter) {
|
||||
auto cached = cache.get(filter);
|
||||
if (not cached.empty() and not cb(cached, false)) {
|
||||
return false;
|
||||
}
|
||||
listeners.emplace(token, LocalListener{q, filter, cb});
|
||||
cb(cache.get(filter), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool removeListener(size_t token, const time_point& now) {
|
||||
@@ -102,7 +126,7 @@ public:
|
||||
return listeners.empty();
|
||||
}
|
||||
|
||||
std::vector<Sp<Value>> get(Value::Filter& filter) const {
|
||||
std::vector<Sp<Value>> get(const Value::Filter& filter) const {
|
||||
return cache.get(filter);
|
||||
}
|
||||
|
||||
@@ -110,6 +134,10 @@ public:
|
||||
return cache.get(id);
|
||||
}
|
||||
|
||||
bool isSynced() const {
|
||||
return cache.isSynced();
|
||||
}
|
||||
|
||||
bool isExpired(const time_point& now) const {
|
||||
return listeners.empty() and (lastRemoved + EXPIRATION < now);
|
||||
}
|
||||
@@ -130,24 +158,31 @@ class SearchCache {
|
||||
public:
|
||||
SearchCache() {}
|
||||
SearchCache(SearchCache&&) = default;
|
||||
size_t listen(ValueCallback get_cb, Sp<Query> q, Value::Filter filter, std::function<size_t(Sp<Query>, ValueCallback)> onListen);
|
||||
|
||||
using OnListen = std::function<size_t(Sp<Query>, ValueCallback, SyncCallback)>;
|
||||
size_t listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen);
|
||||
|
||||
bool cancelListen(size_t gtoken, const time_point& now);
|
||||
void cancelAll(std::function<void(size_t)> onCancel);
|
||||
void cancelAll(const std::function<void(size_t)>& onCancel);
|
||||
|
||||
time_point expire(const time_point& now, std::function<void(size_t)> onCancel);
|
||||
time_point expire(const time_point& now, const std::function<void(size_t)>& onCancel);
|
||||
time_point getExpiration() const {
|
||||
return nextExpiration_;
|
||||
}
|
||||
|
||||
std::vector<Sp<Value>> get(Value::Filter& filter) const;
|
||||
bool get(const Value::Filter& f, const Sp<Query>& q, const GetCallback& gcb, const DoneCallback& dcb) const;
|
||||
std::vector<Sp<Value>> get(const Value::Filter& filter) const;
|
||||
Sp<Value> get(Value::Id id) const;
|
||||
|
||||
private:
|
||||
SearchCache(const SearchCache&) = delete;
|
||||
SearchCache& operator=(const SearchCache&) = delete;
|
||||
|
||||
std::map<Sp<Query>, std::unique_ptr<OpCache>> ops {};
|
||||
using OpMap = std::map<Sp<Query>, std::unique_ptr<OpCache>>;
|
||||
OpMap ops {};
|
||||
OpMap::iterator getOp(const Sp<Query>& q);
|
||||
OpMap::const_iterator getOp(const Sp<Query>& q) const;
|
||||
|
||||
size_t nextToken_ {1};
|
||||
time_point nextExpiration_ {time_point::max()};
|
||||
};
|
||||
|
||||
+159
-96
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 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
|
||||
@@ -26,6 +26,42 @@
|
||||
namespace dht {
|
||||
namespace net {
|
||||
|
||||
static const std::string KEY_Y {"y"};
|
||||
static const std::string KEY_R {"r"};
|
||||
static const std::string KEY_U {"u"};
|
||||
static const std::string KEY_E {"e"};
|
||||
static const std::string KEY_V {"p"};
|
||||
static const std::string KEY_TID {"t"};
|
||||
static const std::string KEY_UA {"v"};
|
||||
static const std::string KEY_NETID {"n"};
|
||||
static const std::string KEY_ISCLIENT {"s"};
|
||||
static const std::string KEY_Q {"q"};
|
||||
static const std::string KEY_A {"a"};
|
||||
|
||||
static const std::string KEY_REQ_SID {"sid"};
|
||||
static const std::string KEY_REQ_ID {"id"};
|
||||
static const std::string KEY_REQ_H {"h"};
|
||||
static const std::string KEY_REQ_TARGET {"target"};
|
||||
static const std::string KEY_REQ_QUERY {"q"};
|
||||
static const std::string KEY_REQ_TOKEN {"token"};
|
||||
static const std::string KEY_REQ_VALUE_ID {"vid"};
|
||||
static const std::string KEY_REQ_NODES4 {"n4"};
|
||||
static const std::string KEY_REQ_NODES6 {"n6"};
|
||||
static const std::string KEY_REQ_CREATION {"c"};
|
||||
static const std::string KEY_REQ_ADDRESS {"sa"};
|
||||
static const std::string KEY_REQ_VALUES {"values"};
|
||||
static const std::string KEY_REQ_EXPIRED {"exp"};
|
||||
static const std::string KEY_REQ_REFRESHED {"re"};
|
||||
static const std::string KEY_REQ_FIELDS {"fileds"};
|
||||
static const std::string KEY_REQ_WANT {"w"};
|
||||
|
||||
static const std::string QUERY_PING {"ping"};
|
||||
static const std::string QUERY_FIND {"find"};
|
||||
static const std::string QUERY_GET {"get"};
|
||||
static const std::string QUERY_PUT {"put"};
|
||||
static const std::string QUERY_LISTEN {"listen"};
|
||||
static const std::string QUERY_REFRESH {"refresh"};
|
||||
|
||||
Tid unpackTid(const msgpack::object& o) {
|
||||
switch (o.type) {
|
||||
case msgpack::type::POSITIVE_INTEGER:
|
||||
@@ -48,13 +84,13 @@ struct ParsedMessage {
|
||||
/* target id around which to find nodes */
|
||||
InfoHash target;
|
||||
/* transaction id */
|
||||
Tid tid;
|
||||
Tid tid {0};
|
||||
/* tid for packets going through request socket */
|
||||
Tid socket_id;
|
||||
Tid socket_id {0};
|
||||
/* security token */
|
||||
Blob token;
|
||||
/* the value id (announce confirmation) */
|
||||
Value::Id value_id;
|
||||
Value::Id value_id {0};
|
||||
/* time when value was first created */
|
||||
time_point created { time_point::max() };
|
||||
/* IPv4 nodes in response to a 'find' request */
|
||||
@@ -78,7 +114,7 @@ struct ParsedMessage {
|
||||
/* reported address by the distant node */
|
||||
std::string ua;
|
||||
SockAddr addr;
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
|
||||
bool append(const ParsedMessage& block);
|
||||
bool complete();
|
||||
@@ -123,63 +159,79 @@ ParsedMessage::complete()
|
||||
}
|
||||
|
||||
void
|
||||
ParsedMessage::msgpack_unpack(msgpack::object msg)
|
||||
ParsedMessage::msgpack_unpack(const msgpack::object& msg)
|
||||
{
|
||||
auto y = findMapValue(msg, "y");
|
||||
auto r = findMapValue(msg, "r");
|
||||
auto u = findMapValue(msg, "u");
|
||||
auto e = findMapValue(msg, "e");
|
||||
auto v = findMapValue(msg, "p");
|
||||
if (msg.type != msgpack::type::MAP) throw msgpack::type_error();
|
||||
|
||||
if (auto t = findMapValue(msg, "t"))
|
||||
tid = unpackTid(*t);
|
||||
struct ParsedMsg {
|
||||
msgpack::object* y;
|
||||
msgpack::object* r;
|
||||
msgpack::object* u;
|
||||
msgpack::object* e;
|
||||
msgpack::object* v;
|
||||
msgpack::object* a;
|
||||
std::string q;
|
||||
} parsed {};
|
||||
|
||||
if (auto rv = findMapValue(msg, "v"))
|
||||
ua = rv->as<std::string>();
|
||||
|
||||
if (auto netid = findMapValue(msg, "n"))
|
||||
network = netid->as<NetId>();
|
||||
|
||||
if (auto is_client_v = findMapValue(msg, "s"))
|
||||
is_client = is_client_v->as<bool>();
|
||||
|
||||
std::string q;
|
||||
if (auto rq = findMapValue(msg, "q")) {
|
||||
if (rq->type != msgpack::type::STR)
|
||||
throw msgpack::type_error();
|
||||
q = rq->as<std::string>();
|
||||
for (unsigned i = 0; i < msg.via.map.size; i++) {
|
||||
auto& o = msg.via.map.ptr[i];
|
||||
if (o.key.type != msgpack::type::STR)
|
||||
continue;
|
||||
auto key = o.key.as<std::string>();
|
||||
if (key == KEY_Y)
|
||||
parsed.y = &o.val;
|
||||
else if (key == KEY_R)
|
||||
parsed.r = &o.val;
|
||||
else if (key == KEY_U)
|
||||
parsed.u = &o.val;
|
||||
else if (key == KEY_E)
|
||||
parsed.e = &o.val;
|
||||
else if (key == KEY_V)
|
||||
parsed.v = &o.val;
|
||||
else if (key == KEY_TID)
|
||||
tid = unpackTid(o.val);
|
||||
else if (key == KEY_UA)
|
||||
ua = o.val.as<std::string>();
|
||||
else if (key == KEY_NETID)
|
||||
network = o.val.as<NetId>();
|
||||
else if (key == KEY_ISCLIENT)
|
||||
is_client = o.val.as<bool>();
|
||||
else if (key == KEY_Q)
|
||||
parsed.q = o.val.as<std::string>();
|
||||
else if (key == KEY_A)
|
||||
parsed.a = &o.val;
|
||||
}
|
||||
|
||||
if (e)
|
||||
if (parsed.e)
|
||||
type = MessageType::Error;
|
||||
else if (r)
|
||||
else if (parsed.r)
|
||||
type = MessageType::Reply;
|
||||
else if (v)
|
||||
else if (parsed.v)
|
||||
type = MessageType::ValueData;
|
||||
else if (u)
|
||||
else if (parsed.u)
|
||||
type = MessageType::ValueUpdate;
|
||||
else if (y and y->as<std::string>() != "q")
|
||||
else if (parsed.y and parsed.y->as<std::string>() != "q")
|
||||
throw msgpack::type_error();
|
||||
else if (q == "ping")
|
||||
else if (parsed.q == QUERY_PING)
|
||||
type = MessageType::Ping;
|
||||
else if (q == "find")
|
||||
else if (parsed.q == QUERY_FIND)
|
||||
type = MessageType::FindNode;
|
||||
else if (q == "get")
|
||||
else if (parsed.q == QUERY_GET)
|
||||
type = MessageType::GetValues;
|
||||
else if (q == "listen")
|
||||
else if (parsed.q == QUERY_LISTEN)
|
||||
type = MessageType::Listen;
|
||||
else if (q == "put")
|
||||
else if (parsed.q == QUERY_PUT)
|
||||
type = MessageType::AnnounceValue;
|
||||
else if (q == "refresh")
|
||||
else if (parsed.q == QUERY_REFRESH)
|
||||
type = MessageType::Refresh;
|
||||
else
|
||||
throw msgpack::type_error();
|
||||
|
||||
if (type == MessageType::ValueData) {
|
||||
if (v->type != msgpack::type::MAP)
|
||||
if (parsed.v->type != msgpack::type::MAP)
|
||||
throw msgpack::type_error();
|
||||
for (size_t i = 0; i < v->via.map.size; ++i) {
|
||||
auto& vdat = v->via.map.ptr[i];
|
||||
for (size_t i = 0; i < parsed.v->via.map.size; ++i) {
|
||||
auto& vdat = parsed.v->via.map.ptr[i];
|
||||
auto o = findMapValue(vdat.val, "o");
|
||||
auto d = findMapValue(vdat.val, "d");
|
||||
if (not o or not d)
|
||||
@@ -189,70 +241,85 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
|
||||
return;
|
||||
}
|
||||
|
||||
auto a = findMapValue(msg, "a");
|
||||
if (!a && !r && !e && !u)
|
||||
if (!parsed.a && !parsed.r && !parsed.e && !parsed.u)
|
||||
throw msgpack::type_error();
|
||||
auto& req = a ? *a : (r ? *r : (u ? *u : *e));
|
||||
auto& req = parsed.a ? *parsed.a : (parsed.r ? *parsed.r : (parsed.u ? *parsed.u : *parsed.e));
|
||||
|
||||
if (e) {
|
||||
if (e->type != msgpack::type::ARRAY)
|
||||
if (parsed.e) {
|
||||
if (parsed.e->type != msgpack::type::ARRAY)
|
||||
throw msgpack::type_error();
|
||||
error_code = e->via.array.ptr[0].as<uint16_t>();
|
||||
error_code = parsed.e->via.array.ptr[0].as<uint16_t>();
|
||||
}
|
||||
|
||||
if (auto t = findMapValue(req, "sid"))
|
||||
socket_id = unpackTid(*t);
|
||||
struct ParsedReq {
|
||||
msgpack::object* values;
|
||||
msgpack::object* fields;
|
||||
msgpack::object* sa;
|
||||
msgpack::object* want;
|
||||
} parsedReq {};
|
||||
|
||||
if (auto rid = findMapValue(req, "id"))
|
||||
id = {*rid};
|
||||
for (unsigned i = 0; i < req.via.map.size; i++) {
|
||||
auto& o = req.via.map.ptr[i];
|
||||
if (o.key.type != msgpack::type::STR)
|
||||
continue;
|
||||
auto key = o.key.as<std::string>();
|
||||
if (key == KEY_REQ_SID)
|
||||
socket_id = unpackTid(o.val);
|
||||
else if (key == KEY_REQ_ID)
|
||||
id = {o.val};
|
||||
else if (key == KEY_REQ_H)
|
||||
info_hash = {o.val};
|
||||
else if (key == KEY_REQ_TARGET)
|
||||
target = {o.val};
|
||||
else if (key == KEY_REQ_QUERY)
|
||||
query.msgpack_unpack(o.val);
|
||||
else if (key == KEY_REQ_TOKEN)
|
||||
token = unpackBlob(o.val);
|
||||
else if (key == KEY_REQ_VALUE_ID)
|
||||
value_id = o.val.as<Value::Id>();
|
||||
else if (key == KEY_REQ_NODES4)
|
||||
nodes4_raw = unpackBlob(o.val);
|
||||
else if (key == KEY_REQ_NODES6)
|
||||
nodes6_raw = unpackBlob(o.val);
|
||||
else if (key == KEY_REQ_ADDRESS)
|
||||
parsedReq.sa = &o.val;
|
||||
else if (key == KEY_REQ_CREATION)
|
||||
created = from_time_t(o.val.as<std::time_t>());
|
||||
else if (key == KEY_REQ_VALUES)
|
||||
parsedReq.values = &o.val;
|
||||
else if (key == KEY_REQ_EXPIRED)
|
||||
expired_values = o.val.as<decltype(expired_values)>();
|
||||
else if (key == KEY_REQ_REFRESHED)
|
||||
refreshed_values = o.val.as<decltype(refreshed_values)>();
|
||||
else if (key == KEY_REQ_FIELDS)
|
||||
parsedReq.fields = &o.val;
|
||||
else if (key == KEY_REQ_WANT)
|
||||
parsedReq.want = &o.val;
|
||||
}
|
||||
|
||||
if (auto rh = findMapValue(req, "h"))
|
||||
info_hash = {*rh};
|
||||
|
||||
if (auto rtarget = findMapValue(req, "target"))
|
||||
target = {*rtarget};
|
||||
|
||||
if (auto rquery = findMapValue(req, "q"))
|
||||
query.msgpack_unpack(*rquery);
|
||||
|
||||
if (auto otoken = findMapValue(req, "token"))
|
||||
token = unpackBlob(*otoken);
|
||||
|
||||
if (auto vid = findMapValue(req, "vid"))
|
||||
value_id = vid->as<Value::Id>();
|
||||
|
||||
if (auto rnodes4 = findMapValue(req, "n4"))
|
||||
nodes4_raw = unpackBlob(*rnodes4);
|
||||
|
||||
if (auto rnodes6 = findMapValue(req, "n6"))
|
||||
nodes6_raw = unpackBlob(*rnodes6);
|
||||
|
||||
if (auto sa = findMapValue(req, "sa")) {
|
||||
if (sa->type != msgpack::type::BIN)
|
||||
if (parsedReq.sa) {
|
||||
if (parsedReq.sa->type != msgpack::type::BIN)
|
||||
throw msgpack::type_error();
|
||||
auto l = sa->via.bin.size;
|
||||
auto l = parsedReq.sa->via.bin.size;
|
||||
if (l == sizeof(in_addr)) {
|
||||
addr.setFamily(AF_INET);
|
||||
auto& a = addr.getIPv4();
|
||||
a.sin_port = 0;
|
||||
std::copy_n(sa->via.bin.ptr, l, (char*)&a.sin_addr);
|
||||
std::copy_n(parsedReq.sa->via.bin.ptr, l, (char*)&a.sin_addr);
|
||||
} else if (l == sizeof(in6_addr)) {
|
||||
addr.setFamily(AF_INET6);
|
||||
auto& a = addr.getIPv6();
|
||||
a.sin6_port = 0;
|
||||
std::copy_n(sa->via.bin.ptr, l, (char*)&a.sin6_addr);
|
||||
std::copy_n(parsedReq.sa->via.bin.ptr, l, (char*)&a.sin6_addr);
|
||||
}
|
||||
} else
|
||||
addr = {};
|
||||
|
||||
if (auto rcreated = findMapValue(req, "c"))
|
||||
created = from_time_t(rcreated->as<std::time_t>());
|
||||
|
||||
if (auto rvalues = findMapValue(req, "values")) {
|
||||
if (rvalues->type != msgpack::type::ARRAY)
|
||||
if (parsedReq.values) {
|
||||
if (parsedReq.values->type != msgpack::type::ARRAY)
|
||||
throw msgpack::type_error();
|
||||
for (size_t i = 0; i < rvalues->via.array.size; i++) {
|
||||
auto& packed_v = rvalues->via.array.ptr[i];
|
||||
for (size_t i = 0; i < parsedReq.values->via.array.size; i++) {
|
||||
auto& packed_v = parsedReq.values->via.array.ptr[i];
|
||||
if (packed_v.type == msgpack::type::POSITIVE_INTEGER) {
|
||||
// Skip oversize values with a small margin for header overhead
|
||||
if (packed_v.via.u64 > MAX_VALUE_SIZE + 32)
|
||||
@@ -260,16 +327,16 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
|
||||
value_parts.emplace(i, std::make_pair(packed_v.via.u64, Blob{}));
|
||||
} else {
|
||||
try {
|
||||
values.emplace_back(std::make_shared<Value>(rvalues->via.array.ptr[i]));
|
||||
values.emplace_back(std::make_shared<Value>(parsedReq.values->via.array.ptr[i]));
|
||||
} catch (const std::exception& e) {
|
||||
//DHT_LOG_WARN("Error reading value: %s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (auto raw_fields = findMapValue(req, "fields")) {
|
||||
if (auto rfields = findMapValue(*raw_fields, "f")) {
|
||||
} else if (parsedReq.fields) {
|
||||
if (auto rfields = findMapValue(*parsedReq.fields, "f")) {
|
||||
auto vfields = rfields->as<std::set<Value::Field>>();
|
||||
if (auto rvalues = findMapValue(*raw_fields, "v")) {
|
||||
if (auto rvalues = findMapValue(*parsedReq.fields, "v")) {
|
||||
if (rvalues->type != msgpack::type::ARRAY)
|
||||
throw msgpack::type_error();
|
||||
size_t val_num = rvalues->via.array.size / vfields.size();
|
||||
@@ -284,18 +351,14 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
|
||||
} else {
|
||||
throw msgpack::type_error();
|
||||
}
|
||||
} else if (auto raw_fields = findMapValue(req, "exp")) {
|
||||
expired_values = raw_fields->as<decltype(expired_values)>();
|
||||
} else if (auto raw_fields = findMapValue(req, "re")) {
|
||||
refreshed_values = raw_fields->as<decltype(refreshed_values)>();
|
||||
}
|
||||
|
||||
if (auto w = findMapValue(req, "w")) {
|
||||
if (w->type != msgpack::type::ARRAY)
|
||||
if (parsedReq.want) {
|
||||
if (parsedReq.want->type != msgpack::type::ARRAY)
|
||||
throw msgpack::type_error();
|
||||
want = 0;
|
||||
for (unsigned i=0; i<w->via.array.size; i++) {
|
||||
auto& val = w->via.array.ptr[i];
|
||||
for (unsigned i=0; i<parsedReq.want->via.array.size; i++) {
|
||||
auto& val = parsedReq.want->via.array.ptr[i];
|
||||
try {
|
||||
auto w = val.as<sa_family_t>();
|
||||
if (w == AF_INET)
|
||||
|
||||
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "peer_discovery.h"
|
||||
#include "network_utils.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
|
||||
#include <Windows.h>
|
||||
#include <cstring>
|
||||
#if defined(_MSC_VER)
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
#define close(x) closesocket(x)
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef IPV6_JOIN_GROUP
|
||||
#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
|
||||
#endif
|
||||
|
||||
namespace dht {
|
||||
|
||||
// Organization-local Scope multicast
|
||||
constexpr char MULTICAST_ADDRESS_IPV4[12] = "239.192.0.1";
|
||||
constexpr char MULTICAST_ADDRESS_IPV6[10] = "ff08::101";
|
||||
|
||||
|
||||
class PeerDiscovery::DomainPeerDiscovery
|
||||
{
|
||||
public:
|
||||
DomainPeerDiscovery(sa_family_t domain, in_port_t port);
|
||||
~DomainPeerDiscovery();
|
||||
|
||||
/**
|
||||
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
|
||||
*/
|
||||
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
|
||||
|
||||
/**
|
||||
* startPublish - Keeping sending data until node is joinned or stop is called - msgpack
|
||||
*/
|
||||
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
|
||||
|
||||
/**
|
||||
* Thread Stopper
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Remove possible callBack to discovery
|
||||
*/
|
||||
bool stopDiscovery(const std::string &type);
|
||||
|
||||
/**
|
||||
* Remove different serivce message to send
|
||||
*/
|
||||
bool stopPublish(const std::string &type);
|
||||
|
||||
/**
|
||||
* Configure the sockopt to be able to listen multicast group
|
||||
*/
|
||||
static void socketJoinMulticast(int sockfd, sa_family_t family);
|
||||
|
||||
/**
|
||||
* Join the threads
|
||||
*/
|
||||
void join() {
|
||||
if(running_listen_.joinable()) running_listen_.join();
|
||||
if(running_send_.joinable()) running_send_.join();
|
||||
}
|
||||
private:
|
||||
//dmtx_ for callbackmap_ and drunning_ (write)
|
||||
std::mutex dmtx_;
|
||||
//mtx_ for messages_ and lrunning (listen)
|
||||
std::mutex mtx_;
|
||||
std::condition_variable cv_;
|
||||
bool lrunning_ {false};
|
||||
bool drunning_ {false};
|
||||
sa_family_t domain_ {AF_UNSPEC};
|
||||
int port_;
|
||||
int sockfd_ {-1};
|
||||
int stop_writefd_ {-1};
|
||||
|
||||
SockAddr sockAddrSend_;
|
||||
|
||||
//Thread export to be joined
|
||||
std::thread running_listen_;
|
||||
std::thread running_send_;
|
||||
|
||||
msgpack::sbuffer sbuf_;
|
||||
std::map<std::string, msgpack::sbuffer> messages_;
|
||||
std::map<std::string, ServiceDiscoveredCallback> callbackmap_;
|
||||
|
||||
/**
|
||||
* Multicast Socket Initialization, accept IPV4, IPV6
|
||||
*/
|
||||
static int initialize_socket(sa_family_t domain);
|
||||
|
||||
/**
|
||||
* Receive messages
|
||||
*/
|
||||
std::pair<SockAddr, msgpack::object_handle> recvFrom();
|
||||
|
||||
/**
|
||||
* Listener pack thread loop
|
||||
*/
|
||||
void listenerpack_thread();
|
||||
|
||||
/**
|
||||
* Listener Parameters Setup
|
||||
*/
|
||||
void listener_setup();
|
||||
|
||||
/**
|
||||
* Sender Parameters Setup
|
||||
*/
|
||||
void sender_setup();
|
||||
/**
|
||||
* Sender Parameters Setup
|
||||
*/
|
||||
void messages_reload();
|
||||
|
||||
void stopDiscovery();
|
||||
void stopPublish();
|
||||
};
|
||||
|
||||
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(sa_family_t domain, in_port_t port)
|
||||
: domain_(domain), port_(port), sockfd_(initialize_socket(domain))
|
||||
{
|
||||
socketJoinMulticast(sockfd_, domain);
|
||||
listener_setup();
|
||||
sender_setup();
|
||||
}
|
||||
|
||||
PeerDiscovery::DomainPeerDiscovery::~DomainPeerDiscovery()
|
||||
{
|
||||
stop();
|
||||
join();
|
||||
if (sockfd_ != -1)
|
||||
close(sockfd_);
|
||||
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
PeerDiscovery::DomainPeerDiscovery::initialize_socket(sa_family_t domain)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(0x0101, &wsaData)) {
|
||||
throw std::runtime_error(std::string("Can't initialize Winsock2 ") + strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
int sockfd = socket(domain, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0) {
|
||||
throw std::runtime_error(std::string("Socket Creation Error: ") + strerror(errno));
|
||||
}
|
||||
net::setNonblocking(sockfd);
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::listener_setup()
|
||||
{
|
||||
SockAddr sockAddrListen_;
|
||||
sockAddrListen_.setFamily(domain_);
|
||||
sockAddrListen_.setPort(port_);
|
||||
sockAddrListen_.setAny();
|
||||
|
||||
unsigned int opt = 1;
|
||||
if (setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) {
|
||||
std::cerr << "setsockopt SO_REUSEADDR failed: " << strerror(errno) << std::endl;
|
||||
}
|
||||
#ifdef SO_REUSEPORT
|
||||
if (setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, (char*)&opt, sizeof(opt)) < 0) {
|
||||
std::cerr << "setsockopt SO_REUSEPORT failed: " << strerror(errno) << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// bind to receive address
|
||||
if (bind(sockfd_, sockAddrListen_.get(), sockAddrListen_.getLength()) < 0){
|
||||
throw std::runtime_error(std::string("Error binding socket: ") + strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::socketJoinMulticast(int sockfd, sa_family_t family)
|
||||
{
|
||||
switch (family)
|
||||
{
|
||||
case AF_INET:{
|
||||
ip_mreq config_ipv4;
|
||||
|
||||
//This option can be used to set the interface for sending outbound
|
||||
//multicast datagrams from the sockets application.
|
||||
config_ipv4.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if( setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (char*)&config_ipv4.imr_interface, sizeof( struct in_addr )) < 0 ) {
|
||||
throw std::runtime_error(std::string("Bound Network Interface IPv4 Error: ") + strerror(errno));
|
||||
}
|
||||
|
||||
//The IP_MULTICAST_TTL socket option allows the application to primarily
|
||||
//limit the lifetime of the packet in the Internet and prevent it from circulating indefinitely
|
||||
unsigned char ttl4 = 20;
|
||||
if( setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl4, sizeof( ttl4 )) < 0 ) {
|
||||
throw std::runtime_error(std::string("TTL Sockopt Error: ") + strerror(errno));
|
||||
}
|
||||
|
||||
// config the listener to be interested in joining in the multicast group
|
||||
config_ipv4.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDRESS_IPV4);
|
||||
config_ipv4.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&config_ipv4, sizeof(config_ipv4)) < 0){
|
||||
throw std::runtime_error(std::string(" Member Addition IPv4 Error: ") + strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
ipv6_mreq config_ipv6;
|
||||
|
||||
/* unsigned int outif = 0;
|
||||
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &outif, sizeof(outif)) < 0) {
|
||||
std::cerr << "Can't assign multicast interface: " << strerror(errno) << std::endl;
|
||||
} */
|
||||
|
||||
unsigned int ttl6 = 20;
|
||||
if( setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl6, sizeof( ttl6 )) < 0 ) {
|
||||
throw std::runtime_error(std::string("Hop Count Set Error: ") + strerror(errno));
|
||||
}
|
||||
|
||||
config_ipv6.ipv6mr_interface = 0;
|
||||
inet_pton(AF_INET6, MULTICAST_ADDRESS_IPV6, &config_ipv6.ipv6mr_multiaddr);
|
||||
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&config_ipv6, sizeof(config_ipv6)) < 0){
|
||||
throw std::runtime_error(std::string("Member Addition IPv6 Error: ") + strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(dmtx_);
|
||||
callbackmap_[type] = callback;
|
||||
if (not drunning_) {
|
||||
if (running_listen_.joinable())
|
||||
running_listen_.join();
|
||||
drunning_ = true;
|
||||
running_listen_ = std::thread(&DomainPeerDiscovery::listenerpack_thread, this);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<SockAddr, msgpack::object_handle>
|
||||
PeerDiscovery::DomainPeerDiscovery::recvFrom()
|
||||
{
|
||||
sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
std::array<uint8_t, 64 * 1024> buf;
|
||||
ssize_t nbytes = recvfrom(
|
||||
sockfd_,
|
||||
(char*)buf.data(), buf.size(),
|
||||
0,
|
||||
(sockaddr*)&sa, &sa_len
|
||||
);
|
||||
if (nbytes < 0)
|
||||
throw std::runtime_error(std::string("Error receiving packet: ") + strerror(errno));
|
||||
|
||||
return { SockAddr { sa, sa_len }, msgpack::unpack(reinterpret_cast<char*>(buf.data()), nbytes) };
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::listenerpack_thread()
|
||||
{
|
||||
int stopfds_pipe[2];
|
||||
#ifndef _WIN32
|
||||
if (pipe(stopfds_pipe) == -1)
|
||||
throw std::runtime_error(std::string("Can't open pipe: ") + strerror(errno));
|
||||
#else
|
||||
net::udpPipe(stopfds_pipe);
|
||||
#endif
|
||||
int stop_readfd = stopfds_pipe[0];
|
||||
stop_writefd_ = stopfds_pipe[1];
|
||||
|
||||
while (true) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dmtx_);
|
||||
if (not drunning_)
|
||||
break;
|
||||
}
|
||||
|
||||
fd_set readfds;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(stop_readfd, &readfds);
|
||||
FD_SET(sockfd_, &readfds);
|
||||
|
||||
int data_coming = select(std::max(sockfd_, stop_readfd) + 1, &readfds, nullptr, nullptr, nullptr);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dmtx_);
|
||||
if (not drunning_)
|
||||
break;
|
||||
}
|
||||
|
||||
if (data_coming < 0) {
|
||||
if(errno != EINTR) {
|
||||
perror("Select Error");
|
||||
std::this_thread::sleep_for( std::chrono::seconds(1) );
|
||||
}
|
||||
} else if (data_coming > 0) {
|
||||
if (FD_ISSET(stop_readfd, &readfds)) {
|
||||
std::array<uint8_t, 64 * 1024> buf;
|
||||
recv(stop_readfd, (char*)buf.data(), buf.size(), 0);
|
||||
}
|
||||
|
||||
try {
|
||||
auto rcv = recvFrom();
|
||||
msgpack::object obj = rcv.second.get();
|
||||
|
||||
if (obj.type != msgpack::type::MAP)
|
||||
continue;
|
||||
for (unsigned i = 0; i < obj.via.map.size; i++) {
|
||||
auto& o = obj.via.map.ptr[i];
|
||||
if (o.key.type != msgpack::type::STR)
|
||||
continue;
|
||||
auto key = o.key.as<std::string>();
|
||||
ServiceDiscoveredCallback cb;
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dmtx_);
|
||||
auto callback = callbackmap_.find(key);
|
||||
if (callback != callbackmap_.end())
|
||||
cb = callback->second;
|
||||
}
|
||||
if (cb)
|
||||
cb(std::move(o.val), std::move(rcv.first));
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error receiving packet: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stop_readfd != -1)
|
||||
close(stop_readfd);
|
||||
if (stop_writefd_ != -1) {
|
||||
close(stop_writefd_);
|
||||
stop_writefd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::sender_setup()
|
||||
{
|
||||
// Setup sender address
|
||||
sockAddrSend_.setFamily(domain_);
|
||||
sockAddrSend_.setAddress(domain_ == AF_INET ? MULTICAST_ADDRESS_IPV4 : MULTICAST_ADDRESS_IPV6);
|
||||
sockAddrSend_.setPort(port_);
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
|
||||
{
|
||||
//Set up New Sending pack
|
||||
msgpack::sbuffer pack_buf_c;
|
||||
pack_buf_c.write(pack_buf.data(),pack_buf.size());
|
||||
|
||||
std::unique_lock<std::mutex> lck(mtx_);
|
||||
messages_[type] = std::move(pack_buf_c);
|
||||
messages_reload();
|
||||
if (not lrunning_) {
|
||||
if (running_send_.joinable())
|
||||
running_send_.join();
|
||||
lrunning_ = true;
|
||||
running_send_ = std::thread([this](){
|
||||
std::unique_lock<std::mutex> lck(mtx_);
|
||||
while (lrunning_) {
|
||||
ssize_t nbytes = sendto(
|
||||
sockfd_,
|
||||
sbuf_.data(),
|
||||
sbuf_.size(),
|
||||
0,
|
||||
sockAddrSend_.get(),
|
||||
sockAddrSend_.getLength()
|
||||
);
|
||||
if (nbytes < 0) {
|
||||
std::cerr << "Error sending packet: " << strerror(errno) << std::endl;
|
||||
}
|
||||
if (cv_.wait_for(lck,std::chrono::seconds(3),[&]{ return !lrunning_; }))
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string &type)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dmtx_);
|
||||
if (callbackmap_.erase(type) > 0) {
|
||||
if (callbackmap_.empty())
|
||||
stopDiscovery();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string &type)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mtx_);
|
||||
if (messages_.erase(type) > 0) {
|
||||
if (messages_.empty())
|
||||
stopPublish();
|
||||
else
|
||||
messages_reload();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::stopDiscovery()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#define write(s, b, f) send((s), (b), (f), 0)
|
||||
#endif
|
||||
if (drunning_) {
|
||||
drunning_ = false;
|
||||
if (stop_writefd_ != -1) {
|
||||
if (write(stop_writefd_, "\0", 1) == -1) {
|
||||
std::cerr << "Can't send stop message: " << strerror(errno) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
#undef write
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::stopPublish()
|
||||
{
|
||||
if (lrunning_) {
|
||||
lrunning_ = false;
|
||||
cv_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::stop()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(dmtx_);
|
||||
stopDiscovery();
|
||||
}
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(mtx_);
|
||||
stopPublish();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::messages_reload()
|
||||
{
|
||||
sbuf_.clear();
|
||||
msgpack::packer<msgpack::sbuffer> pk(&sbuf_);
|
||||
pk.pack_map(messages_.size());
|
||||
for (const auto& m : messages_) {
|
||||
pk.pack(m.first);
|
||||
sbuf_.write(m.second.data(), m.second.size());
|
||||
}
|
||||
}
|
||||
|
||||
PeerDiscovery::PeerDiscovery(in_port_t port)
|
||||
{
|
||||
try {
|
||||
peerDiscovery4_.reset(new DomainPeerDiscovery(AF_INET, port));
|
||||
} catch(const std::exception& e){
|
||||
std::cerr << "Can't start peer discovery (IPv4): " << e.what() << std::endl;
|
||||
}
|
||||
try {
|
||||
peerDiscovery6_.reset(new DomainPeerDiscovery(AF_INET6, port));
|
||||
} catch(const std::exception& e) {
|
||||
std::cerr << "Can't start peer discovery (IPv6): " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
PeerDiscovery::~PeerDiscovery(){}
|
||||
|
||||
void
|
||||
PeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
|
||||
{
|
||||
if(peerDiscovery4_) peerDiscovery4_->startDiscovery(type, callback);
|
||||
if(peerDiscovery6_) peerDiscovery6_->startDiscovery(type, callback);
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
|
||||
{
|
||||
if(peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
|
||||
if(peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf)
|
||||
{
|
||||
if (domain == AF_INET) {
|
||||
if (peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
|
||||
} else if (domain == AF_INET6) {
|
||||
if (peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::stop()
|
||||
{
|
||||
if(peerDiscovery4_) peerDiscovery4_->stop();
|
||||
if(peerDiscovery6_) peerDiscovery6_->stop();
|
||||
}
|
||||
|
||||
bool
|
||||
PeerDiscovery::stopDiscovery(const std::string &type)
|
||||
{
|
||||
bool stopped4 = peerDiscovery4_ and peerDiscovery4_->stopDiscovery(type);
|
||||
bool stopped6 = peerDiscovery6_ and peerDiscovery6_->stopDiscovery(type);
|
||||
return stopped4 or stopped6;
|
||||
}
|
||||
|
||||
bool
|
||||
PeerDiscovery::stopPublish(const std::string &type)
|
||||
{
|
||||
bool stopped4 = peerDiscovery4_ and peerDiscovery4_->stopPublish(type);
|
||||
bool stopped6 = peerDiscovery6_ and peerDiscovery6_->stopPublish(type);
|
||||
return stopped4 or stopped6;
|
||||
}
|
||||
|
||||
bool
|
||||
PeerDiscovery::stopPublish(sa_family_t domain, const std::string &type)
|
||||
{
|
||||
if (domain == AF_INET) {
|
||||
return peerDiscovery4_ and peerDiscovery4_->stopPublish(type);
|
||||
} else if (domain == AF_INET6) {
|
||||
return peerDiscovery6_ and peerDiscovery6_->stopPublish(type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::join() {
|
||||
if(peerDiscovery4_) peerDiscovery4_->join();
|
||||
if(peerDiscovery6_) peerDiscovery6_->join();
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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
|
||||
@@ -92,7 +92,7 @@ RoutingTable::middle(const RoutingTable::const_iterator& it) const
|
||||
throw std::out_of_range("End of table");
|
||||
|
||||
InfoHash id = it->first;
|
||||
id.setBit(bit, 1);
|
||||
id.setBit(bit, true);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
+53
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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
|
||||
@@ -65,7 +65,8 @@ struct Dht::SearchNode {
|
||||
ValueCache cache;
|
||||
Sp<Scheduler::Job> cacheExpirationJob {};
|
||||
Sp<net::Request> req {};
|
||||
CachedListenStatus(ValueStateCallback&& cb) : cache(std::forward<ValueStateCallback>(cb)) {}
|
||||
CachedListenStatus(ValueStateCallback&& cb, SyncCallback&& scb)
|
||||
: cache(std::forward<ValueStateCallback>(cb), std::forward<SyncCallback>(scb)) {}
|
||||
CachedListenStatus(CachedListenStatus&&) = default;
|
||||
CachedListenStatus(const CachedListenStatus&) = delete;
|
||||
CachedListenStatus& operator=(const CachedListenStatus&) = delete;
|
||||
@@ -225,6 +226,13 @@ struct Dht::SearchNode {
|
||||
}
|
||||
}
|
||||
|
||||
void onListenSynced(const Sp<Query>& q, bool synced = true) {
|
||||
auto l = listenStatus.find(q);
|
||||
if (l != listenStatus.end()) {
|
||||
l->second.cache.onSynced(synced);
|
||||
}
|
||||
}
|
||||
|
||||
void expireValues(const Sp<Query>& q, Scheduler& scheduler) {
|
||||
auto l = listenStatus.find(q);
|
||||
if (l != listenStatus.end()) {
|
||||
@@ -377,6 +385,11 @@ struct Dht::Search {
|
||||
std::multimap<time_point, Get> callbacks {};
|
||||
|
||||
/* listeners */
|
||||
struct SearchListener {
|
||||
Sp<Query> query;
|
||||
ValueCallback get_cb;
|
||||
SyncCallback sync_cb;
|
||||
};
|
||||
std::map<size_t, SearchListener> listeners {};
|
||||
size_t listener_token = 1;
|
||||
|
||||
@@ -475,23 +488,22 @@ struct Dht::Search {
|
||||
bool isAnnounced(Value::Id id) const;
|
||||
bool isListening(time_point now) const;
|
||||
|
||||
void get(Value::Filter f, const Sp<Query>& q, const QueryCallback& qcb, const GetCallback& gcb, const DoneCallback& dcb, Scheduler& scheduler) {
|
||||
void get(const Value::Filter& f, const Sp<Query>& q, const QueryCallback& qcb, const GetCallback& gcb, const DoneCallback& dcb, Scheduler& scheduler) {
|
||||
if (gcb or qcb) {
|
||||
const auto& now = scheduler.time();
|
||||
callbacks.emplace(now, Get { now, f, q, qcb, gcb, dcb });
|
||||
auto values = cache.get(f);
|
||||
if (not values.empty())
|
||||
gcb(values);
|
||||
scheduler.edit(nextSearchStep, now);
|
||||
if (not cache.get(f, q, gcb, dcb)) {
|
||||
const auto& now = scheduler.time();
|
||||
callbacks.emplace(now, Get { now, f, q, qcb, gcb, dcb });
|
||||
scheduler.edit(nextSearchStep, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t listen(ValueCallback cb, Value::Filter f, const Sp<Query>& q, Scheduler& scheduler) {
|
||||
size_t listen(const ValueCallback& cb, const Value::Filter& f, const Sp<Query>& q, Scheduler& scheduler) {
|
||||
//DHT_LOG.e(id, "[search %s IPv%c] listen", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
|
||||
return cache.listen(cb, q, f, [&](const Sp<Query>& q, ValueCallback vcb){
|
||||
return cache.listen(cb, q, f, [&](const Sp<Query>& q, ValueCallback vcb, SyncCallback scb){
|
||||
done = false;
|
||||
auto token = ++listener_token;
|
||||
listeners.emplace(token, SearchListener{q, f, vcb});
|
||||
listeners.emplace(token, SearchListener{q, vcb, scb});
|
||||
scheduler.edit(nextSearchStep, scheduler.time());
|
||||
return token;
|
||||
});
|
||||
@@ -520,6 +532,35 @@ struct Dht::Search {
|
||||
scheduler.edit(opExpirationJob, cache.getExpiration());
|
||||
}
|
||||
|
||||
std::vector<Sp<Value>> getPut() const {
|
||||
std::vector<Sp<Value>> ret;
|
||||
ret.reserve(announce.size());
|
||||
for (const auto& a : announce)
|
||||
ret.push_back(a.value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Sp<Value> getPut(Value::Id vid) const {
|
||||
for (auto& a : announce) {
|
||||
if (a.value->id == vid)
|
||||
return a.value;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool cancelPut(Value::Id vid) {
|
||||
bool canceled {false};
|
||||
for (auto it = announce.begin(); it != announce.end();) {
|
||||
if (it->value->id == vid) {
|
||||
canceled = true;
|
||||
it = announce.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
return canceled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of non-good search nodes.
|
||||
*/
|
||||
|
||||
+32
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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>
|
||||
@@ -54,15 +54,14 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
|
||||
CERTIFICATE_TYPE,
|
||||
*certificate_,
|
||||
1
|
||||
}, [this](bool ok) {
|
||||
}, [this, certId](bool ok) {
|
||||
if (ok)
|
||||
DHT_LOG.DBG("SecureDht: public key announced successfully");
|
||||
DHT_LOG.d(certId, "SecureDht: public key announced successfully");
|
||||
}, {}, true);
|
||||
}
|
||||
}
|
||||
|
||||
SecureDht::~SecureDht()
|
||||
{}
|
||||
SecureDht::~SecureDht() = default;
|
||||
|
||||
ValueType
|
||||
SecureDht::secureType(ValueType&& type)
|
||||
@@ -74,7 +73,7 @@ SecureDht::secureType(ValueType&& type)
|
||||
v->signatureValid = v->owner and v->owner->checkSignature(v->getToSign(), v->signature);
|
||||
}
|
||||
if (!v->signatureValid) {
|
||||
DHT_LOG.WARN("Signature verification failed");
|
||||
DHT_LOG.w("Signature verification failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -84,7 +83,7 @@ SecureDht::secureType(ValueType&& type)
|
||||
if (!o->isSigned())
|
||||
return type.editPolicy(id, o, n, nid, a);
|
||||
if (o->owner != n->owner) {
|
||||
DHT_LOG.WARN("Edition forbidden: owner changed.");
|
||||
DHT_LOG.w("Edition forbidden: owner changed.");
|
||||
return false;
|
||||
}
|
||||
if (!n->signatureChecked) {
|
||||
@@ -92,14 +91,14 @@ SecureDht::secureType(ValueType&& type)
|
||||
n->signatureValid = o->owner and o->owner->checkSignature(n->getToSign(), n->signature);
|
||||
}
|
||||
if (!n->signatureValid) {
|
||||
DHT_LOG.WARN("Edition forbidden: signature verification failed.");
|
||||
DHT_LOG.w("Edition forbidden: signature verification failed.");
|
||||
return false;
|
||||
}
|
||||
if (o->seq == n->seq) {
|
||||
// If the data is exactly the same,
|
||||
// it can be reannounced, possibly by someone else.
|
||||
if (o->getToSign() != n->getToSign()) {
|
||||
DHT_LOG.WARN("Edition forbidden: sequence number must be increasing.");
|
||||
DHT_LOG.w("Edition forbidden: sequence number must be increasing.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -145,7 +144,7 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
|
||||
}
|
||||
InfoHash h = crt->getPublicKey().getId();
|
||||
if (node == h) {
|
||||
DHT_LOG.DBG("Registering certificate for %s", h.toString().c_str());
|
||||
DHT_LOG.d("Registering certificate for %s", h.toString().c_str());
|
||||
auto it = nodesCertificates_.find(h);
|
||||
if (it == nodesCertificates_.end())
|
||||
std::tie(it, std::ignore) = nodesCertificates_.emplace(h, std::move(crt));
|
||||
@@ -153,7 +152,7 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
|
||||
it->second = std::move(crt);
|
||||
return it->second;
|
||||
} else {
|
||||
DHT_LOG.WARN("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
|
||||
DHT_LOG.w("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -166,11 +165,11 @@ SecureDht::registerCertificate(Sp<crypto::Certificate>& cert)
|
||||
}
|
||||
|
||||
void
|
||||
SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<crypto::Certificate>)> cb)
|
||||
SecureDht::findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb)
|
||||
{
|
||||
Sp<crypto::Certificate> b = getCertificate(node);
|
||||
if (b && *b) {
|
||||
DHT_LOG.DBG("Using certificate from cache for %s", node.toString().c_str());
|
||||
DHT_LOG.d("Using certificate from cache for %s", node.toString().c_str());
|
||||
if (cb)
|
||||
cb(b);
|
||||
return;
|
||||
@@ -178,7 +177,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<cry
|
||||
if (localQueryMethod_) {
|
||||
auto res = localQueryMethod_(node);
|
||||
if (not res.empty()) {
|
||||
DHT_LOG.DBG("Registering certificate from local store for %s", node.toString().c_str());
|
||||
DHT_LOG.d("Registering certificate from local store for %s", node.toString().c_str());
|
||||
nodesCertificates_.emplace(node, res.front());
|
||||
if (cb)
|
||||
cb(res.front());
|
||||
@@ -193,7 +192,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<cry
|
||||
for (const auto& v : vals) {
|
||||
if (auto cert = registerCertificate(node, v->data)) {
|
||||
*found = true;
|
||||
DHT_LOG.DBG("Found certificate for %s", node.toString().c_str());
|
||||
DHT_LOG.d("Found certificate for %s", node.toString().c_str());
|
||||
if (cb)
|
||||
cb(cert);
|
||||
return false;
|
||||
@@ -207,11 +206,11 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<cry
|
||||
}
|
||||
|
||||
void
|
||||
SecureDht::findPublicKey(const InfoHash& node, std::function<void(const Sp<const crypto::PublicKey>)> cb)
|
||||
SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb)
|
||||
{
|
||||
auto pk = getPublicKey(node);
|
||||
if (pk && *pk) {
|
||||
DHT_LOG.DBG("Found public key from cache for %s", node.toString().c_str());
|
||||
DHT_LOG.d("Found public key from cache for %s", node.toString().c_str());
|
||||
if (cb)
|
||||
cb(pk);
|
||||
return;
|
||||
@@ -235,7 +234,7 @@ SecureDht::checkValue(const Sp<Value>& v)
|
||||
// Decrypt encrypted values
|
||||
if (v->isEncrypted()) {
|
||||
if (not key_) {
|
||||
#if OPENDHT_PROXY_SERVER
|
||||
#ifdef OPENDHT_PROXY_SERVER
|
||||
if (forward_all_) // We are currently a proxy, send messages to clients.
|
||||
return v;
|
||||
#endif
|
||||
@@ -255,7 +254,7 @@ SecureDht::checkValue(const Sp<Value>& v)
|
||||
}
|
||||
// Ignore values belonging to other people
|
||||
} catch (const std::exception& e) {
|
||||
DHT_LOG.WARN("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
|
||||
DHT_LOG.w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
|
||||
}
|
||||
}
|
||||
// Check signed values
|
||||
@@ -270,7 +269,7 @@ SecureDht::checkValue(const Sp<Value>& v)
|
||||
return v;
|
||||
}
|
||||
else
|
||||
DHT_LOG.WARN("Signature verification failed for %s", v->toString().c_str());
|
||||
DHT_LOG.w("Signature verification failed for %s", v->toString().c_str());
|
||||
}
|
||||
// Forward normal values
|
||||
else {
|
||||
@@ -280,10 +279,12 @@ SecureDht::checkValue(const Sp<Value>& v)
|
||||
}
|
||||
|
||||
ValueCallback
|
||||
SecureDht::getCallbackFilter(ValueCallback cb, Value::Filter&& filter)
|
||||
SecureDht::getCallbackFilter(const ValueCallback& cb, Value::Filter&& filter)
|
||||
{
|
||||
return [=](const std::vector<Sp<Value>>& values, bool expired) {
|
||||
std::vector<Sp<Value>> tmpvals {};
|
||||
if (not filter)
|
||||
tmpvals.reserve(values.size());
|
||||
for (const auto& v : values) {
|
||||
if (auto nv = checkValue(v))
|
||||
if (not filter or filter(*nv))
|
||||
@@ -297,10 +298,12 @@ SecureDht::getCallbackFilter(ValueCallback cb, Value::Filter&& filter)
|
||||
|
||||
|
||||
GetCallback
|
||||
SecureDht::getCallbackFilter(GetCallback cb, Value::Filter&& filter)
|
||||
SecureDht::getCallbackFilter(const GetCallback& cb, Value::Filter&& filter)
|
||||
{
|
||||
return [=](const std::vector<Sp<Value>>& values) {
|
||||
std::vector<Sp<Value>> tmpvals {};
|
||||
if (not filter)
|
||||
tmpvals.reserve(values.size());
|
||||
for (const auto& v : values) {
|
||||
if (auto nv = checkValue(v))
|
||||
if (not filter or filter(*nv))
|
||||
@@ -349,12 +352,12 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
|
||||
// Check if data already exists on the dht
|
||||
get(hash,
|
||||
[val,this] (const std::vector<Sp<Value>>& vals) {
|
||||
DHT_LOG.DBG("Found online previous value being announced.");
|
||||
DHT_LOG.d("Found online previous value being announced.");
|
||||
for (const auto& v : vals) {
|
||||
if (!v->isSigned())
|
||||
DHT_LOG.ERR("Existing non-signed value seems to exists at this location.");
|
||||
DHT_LOG.e("Existing non-signed value seems to exists at this location.");
|
||||
else if (not v->owner or v->owner->getId() != getId())
|
||||
DHT_LOG.ERR("Existing signed value belonging to someone else seems to exists at this location.");
|
||||
DHT_LOG.e("Existing signed value belonging to someone else seems to exists at this location.");
|
||||
else if (val->seq <= v->seq)
|
||||
val->seq = v->seq + 1;
|
||||
}
|
||||
@@ -364,7 +367,8 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
|
||||
sign(*val);
|
||||
dht_->put(hash, val, callback, time_point::max(), permanent);
|
||||
},
|
||||
Value::IdFilter(val->id)
|
||||
Value::IdFilter(val->id),
|
||||
std::move(Where().id(val->id))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -377,11 +381,11 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val,
|
||||
callback(false, {});
|
||||
return;
|
||||
}
|
||||
DHT_LOG.WARN("Encrypting data for PK: %s", pk->getId().toString().c_str());
|
||||
DHT_LOG.w("Encrypting data for PK: %s", pk->getId().toString().c_str());
|
||||
try {
|
||||
dht_->put(hash, encrypt(*val, *pk), callback, time_point::max(), permanent);
|
||||
} catch (const std::exception& e) {
|
||||
DHT_LOG.ERR("Error putting encrypted data: %s", e.what());
|
||||
DHT_LOG.e("Error putting encrypted data: %s", e.what());
|
||||
if (callback)
|
||||
callback(false, {});
|
||||
}
|
||||
|
||||
+24
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 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
|
||||
@@ -90,20 +90,7 @@ struct Storage {
|
||||
|
||||
Storage() {}
|
||||
Storage(time_point t) : maintenance_time(t) {}
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 || defined(_WIN32)
|
||||
// GCC-bug: remove me when support of GCC < 4.9.2 is abandoned
|
||||
Storage(Storage&& o) noexcept
|
||||
: maintenance_time(std::move(o.maintenance_time))
|
||||
, listeners(std::move(o.listeners))
|
||||
, local_listeners(std::move(o.local_listeners))
|
||||
, listener_token(std::move(o.listener_token))
|
||||
, values(std::move(o.values))
|
||||
, total_size(std::move(o.total_size)) {}
|
||||
#else
|
||||
Storage(Storage&& o) noexcept = default;
|
||||
#endif
|
||||
|
||||
Storage& operator=(Storage&& o) = default;
|
||||
|
||||
bool empty() const {
|
||||
@@ -128,7 +115,7 @@ struct Storage {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<Sp<Value>> get(Value::Filter f = {}) const {
|
||||
std::vector<Sp<Value>> get(const Value::Filter& f = {}) const {
|
||||
std::vector<Sp<Value>> newvals {};
|
||||
if (not f) newvals.reserve(values.size());
|
||||
for (auto& v : values) {
|
||||
@@ -166,6 +153,12 @@ struct Storage {
|
||||
return time_point::max();
|
||||
}
|
||||
|
||||
size_t listen(ValueCallback& cb, Value::Filter& f, const Sp<Query>& q);
|
||||
|
||||
void cancelListen(size_t token) {
|
||||
local_listeners.erase(token);
|
||||
}
|
||||
|
||||
StoreDiff remove(const InfoHash& id, Value::Id);
|
||||
|
||||
std::pair<ssize_t, std::vector<Sp<Value>>> expire(const InfoHash& id, time_point now);
|
||||
@@ -179,6 +172,22 @@ private:
|
||||
};
|
||||
|
||||
|
||||
size_t
|
||||
Storage::listen(ValueCallback& gcb, Value::Filter& filter, const Sp<Query>& query)
|
||||
{
|
||||
if (not empty()) {
|
||||
std::vector<Sp<Value>> newvals = get(filter);
|
||||
if (not newvals.empty()) {
|
||||
if (!gcb(newvals, false))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
auto tokenlocal = ++listener_token;
|
||||
local_listeners.emplace(tokenlocal, LocalListener{query, filter, gcb});
|
||||
return tokenlocal;
|
||||
}
|
||||
|
||||
|
||||
std::pair<ValueStorage*, Storage::StoreDiff>
|
||||
Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, time_point expiration, StorageBucket* sb)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "thread_pool.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <ciso646> // fix windows compiler bug
|
||||
|
||||
namespace dht {
|
||||
|
||||
constexpr const size_t IO_THREADS_MAX {64};
|
||||
|
||||
struct ThreadPool::ThreadState
|
||||
{
|
||||
std::thread thread {};
|
||||
std::atomic_bool run {true};
|
||||
};
|
||||
|
||||
ThreadPool&
|
||||
ThreadPool::computation()
|
||||
{
|
||||
static ThreadPool pool;
|
||||
return pool;
|
||||
}
|
||||
|
||||
ThreadPool&
|
||||
ThreadPool::io()
|
||||
{
|
||||
static ThreadPool pool(IO_THREADS_MAX);
|
||||
return pool;
|
||||
}
|
||||
|
||||
|
||||
ThreadPool::ThreadPool(size_t maxThreads) : maxThreads_(maxThreads)
|
||||
{
|
||||
threads_.reserve(maxThreads_);
|
||||
}
|
||||
|
||||
ThreadPool::ThreadPool()
|
||||
: ThreadPool(std::max<size_t>(std::thread::hardware_concurrency(), 4))
|
||||
{}
|
||||
|
||||
ThreadPool::~ThreadPool()
|
||||
{
|
||||
join();
|
||||
}
|
||||
|
||||
void
|
||||
ThreadPool::run(std::function<void()>&& cb)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(lock_);
|
||||
if (not running_) return;
|
||||
|
||||
// launch new thread if necessary
|
||||
if (not readyThreads_ && threads_.size() < maxThreads_) {
|
||||
threads_.emplace_back(new ThreadState());
|
||||
auto& t = *threads_.back();
|
||||
t.thread = std::thread([&]() {
|
||||
while (t.run) {
|
||||
std::function<void()> task;
|
||||
|
||||
// pick task from queue
|
||||
{
|
||||
std::unique_lock<std::mutex> l(lock_);
|
||||
readyThreads_++;
|
||||
cv_.wait(l, [&](){
|
||||
return not t.run or not tasks_.empty();
|
||||
});
|
||||
readyThreads_--;
|
||||
if (not t.run)
|
||||
break;
|
||||
task = std::move(tasks_.front());
|
||||
tasks_.pop();
|
||||
}
|
||||
|
||||
// run task
|
||||
try {
|
||||
if (task)
|
||||
task();
|
||||
} catch (const std::exception& e) {
|
||||
// LOG_ERR("Exception running task: %s", e.what());
|
||||
std::cerr << "Exception running task: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// push task to queue
|
||||
tasks_.emplace(std::move(cb));
|
||||
|
||||
// notify thread
|
||||
l.unlock();
|
||||
cv_.notify_one();
|
||||
}
|
||||
|
||||
void
|
||||
ThreadPool::stop()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> l(lock_);
|
||||
running_ = false;
|
||||
}
|
||||
for (auto& t : threads_)
|
||||
t->run = false;
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
ThreadPool::join()
|
||||
{
|
||||
stop();
|
||||
for (auto& t : threads_)
|
||||
t->thread.join();
|
||||
threads_.clear();
|
||||
}
|
||||
|
||||
void
|
||||
Executor::run(std::function<void()>&& task)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(lock_);
|
||||
if (current_ < maxConcurrent_) {
|
||||
run_(std::move(task));
|
||||
} else {
|
||||
tasks_.emplace(std::move(task));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Executor::run_(std::function<void()>&& task)
|
||||
{
|
||||
current_++;
|
||||
std::weak_ptr<Executor> w = shared_from_this();
|
||||
threadPool_.get().run([w,task] {
|
||||
try {
|
||||
task();
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception running task: " << e.what() << std::endl;
|
||||
}
|
||||
if (auto sthis = w.lock()) {
|
||||
auto& this_ = *sthis;
|
||||
std::lock_guard<std::mutex> l(this_.lock_);
|
||||
this_.current_--;
|
||||
this_.schedule();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Executor::schedule()
|
||||
{
|
||||
if (not tasks_.empty() and current_ < maxConcurrent_) {
|
||||
run_(std::move(tasks_.front()));
|
||||
tasks_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+50
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -16,6 +16,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "sockaddr.h"
|
||||
#include "default_types.h"
|
||||
@@ -25,10 +29,18 @@
|
||||
#define IN_IS_ADDR_UNSPECIFIED(a) (((long int) (a)->s_addr) == 0x00000000)
|
||||
#endif /* IN_IS_ADDR_UNSPECIFIED */
|
||||
|
||||
#ifndef PACKAGE_VERSION
|
||||
#define PACKAGE_VERSION "(unknown version)"
|
||||
#endif
|
||||
|
||||
namespace dht {
|
||||
|
||||
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
|
||||
|
||||
const char* version() {
|
||||
return PACKAGE_VERSION;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string>
|
||||
splitPort(const std::string& s) {
|
||||
if (s.empty())
|
||||
@@ -73,6 +85,24 @@ SockAddr::resolve(const std::string& host, const std::string& service)
|
||||
return ips;
|
||||
}
|
||||
|
||||
void
|
||||
SockAddr::setAddress(const char* address)
|
||||
{
|
||||
auto family = getFamily();
|
||||
void* addr = nullptr;
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
addr = &getIPv4().sin_addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
addr = &getIPv6().sin6_addr;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown address family");
|
||||
}
|
||||
if (inet_pton(family, address, addr) <= 0)
|
||||
throw std::runtime_error(std::string("Can't parse IP address: ") + strerror(errno));
|
||||
}
|
||||
|
||||
std::string
|
||||
print_addr(const sockaddr* sa, socklen_t slen)
|
||||
@@ -80,7 +110,7 @@ print_addr(const sockaddr* sa, socklen_t slen)
|
||||
char hbuf[NI_MAXHOST];
|
||||
char sbuf[NI_MAXSERV];
|
||||
std::stringstream out;
|
||||
if (!getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
|
||||
if (sa and slen and !getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
|
||||
if (sa->sa_family == AF_INET6)
|
||||
out << "[" << hbuf << "]";
|
||||
else
|
||||
@@ -171,10 +201,10 @@ SockAddr::isMappedIPv4() const
|
||||
}
|
||||
|
||||
SockAddr
|
||||
SockAddr::getMappedIPv4() const
|
||||
SockAddr::getMappedIPv4()
|
||||
{
|
||||
if (not isMappedIPv4())
|
||||
return *this;
|
||||
return std::move(*this);
|
||||
SockAddr ret;
|
||||
ret.setFamily(AF_INET);
|
||||
ret.setPort(getPort());
|
||||
@@ -185,6 +215,22 @@ SockAddr::getMappedIPv4() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
SockAddr
|
||||
SockAddr::getMappedIPv6()
|
||||
{
|
||||
auto family = getFamily();
|
||||
if (family != AF_INET)
|
||||
return std::move(*this);
|
||||
SockAddr ret;
|
||||
ret.setFamily(AF_INET6);
|
||||
ret.setPort(getPort());
|
||||
auto addr4 = reinterpret_cast<const uint8_t*>(&getIPv4().sin_addr);
|
||||
auto addr6 = reinterpret_cast<uint8_t*>(&ret.getIPv6().sin6_addr);
|
||||
std::copy(MAPPED_IPV4_PREFIX.begin(), MAPPED_IPV4_PREFIX.end(), addr6);
|
||||
std::copy_n(addr4, sizeof(in_addr), addr6 + MAPPED_IPV4_PREFIX.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool operator==(const SockAddr& a, const SockAddr& b) {
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
+15
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -54,17 +54,19 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
|
||||
s << IpServiceAnnouncement(v.data);
|
||||
} else if (v.type == CERTIFICATE_TYPE.id) {
|
||||
s << "Certificate";
|
||||
#ifdef OPENDHT_LOG_CRT_ID
|
||||
try {
|
||||
InfoHash h = crypto::Certificate(v.data).getPublicKey().getId();
|
||||
auto h = crypto::Certificate(v.data).getPublicKey().getLongId();
|
||||
s << " with ID " << h;
|
||||
} catch (const std::exception& e) {
|
||||
s << " (invalid)";
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
s << "Data (type: " << v.type << " ): ";
|
||||
s << std::hex;
|
||||
for (size_t i=0; i<v.data.size(); i++)
|
||||
s << std::setfill('0') << std::setw(2) << (unsigned)v.data[i];
|
||||
for (auto i : v.data)
|
||||
s << std::setfill('0') << std::setw(2) << (unsigned)i;
|
||||
s << std::dec;
|
||||
}
|
||||
}
|
||||
@@ -76,7 +78,7 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
|
||||
const ValueType ValueType::USER_DATA = {0, "User Data"};
|
||||
|
||||
bool
|
||||
ValueType::DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&)
|
||||
ValueType::DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&)
|
||||
{
|
||||
return v->size() <= MAX_VALUE_SIZE;
|
||||
}
|
||||
@@ -286,11 +288,11 @@ FieldValue::getLocalFilter() const
|
||||
case Value::Field::UserType:
|
||||
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
|
||||
default:
|
||||
return Value::AllFilter();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
FieldValueIndex::FieldValueIndex(const Value& v, Select s)
|
||||
FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
|
||||
{
|
||||
auto selection = s.getSelection();
|
||||
if (not selection.empty()) {
|
||||
@@ -397,8 +399,8 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
|
||||
}
|
||||
|
||||
void trim_str(std::string& str) {
|
||||
auto first = std::min(str.size(), str.find_first_not_of(" "));
|
||||
auto last = std::min(str.size(), str.find_last_not_of(" "));
|
||||
auto first = std::min(str.size(), str.find_first_not_of(' '));
|
||||
auto last = std::min(str.size(), str.find_last_not_of(' '));
|
||||
str = str.substr(first, last - first + 1);
|
||||
}
|
||||
|
||||
@@ -495,8 +497,7 @@ template <typename T>
|
||||
bool subset(std::vector<T> fds, std::vector<T> qfds)
|
||||
{
|
||||
for (auto& fd : fds) {
|
||||
auto correspondance = std::find_if(qfds.begin(), qfds.end(), [&fd](T& _vfd) { return fd == _vfd; });
|
||||
if (correspondance == qfds.end())
|
||||
if (std::find_if(qfds.begin(), qfds.end(), [&fd](T& _vfd) { return fd == _vfd; }) == qfds.end())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -504,10 +505,9 @@ bool subset(std::vector<T> fds, std::vector<T> qfds)
|
||||
|
||||
bool Select::isSatisfiedBy(const Select& os) const {
|
||||
/* empty, means all values are selected. */
|
||||
if (fieldSelection_.empty() and not os.fieldSelection_.empty())
|
||||
return false;
|
||||
else
|
||||
return subset(fieldSelection_, os.fieldSelection_);
|
||||
return fieldSelection_.empty() ?
|
||||
os.fieldSelection_.empty() :
|
||||
subset(fieldSelection_, os.fieldSelection_);
|
||||
}
|
||||
|
||||
bool Where::isSatisfiedBy(const Where& ow) const {
|
||||
|
||||
+27
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 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
|
||||
@@ -22,19 +22,32 @@
|
||||
namespace dht {
|
||||
|
||||
using ValueStateCallback = std::function<void(const std::vector<Sp<Value>>&, bool)>;
|
||||
enum class ListenSyncStatus { ADDED, SYNCED, UNSYNCED, REMOVED };
|
||||
using SyncCallback = std::function<void(ListenSyncStatus)>;
|
||||
using CallbackQueue = std::list<std::function<void()>>;
|
||||
|
||||
class ValueCache {
|
||||
public:
|
||||
ValueCache(ValueStateCallback&& cb) : callback(std::forward<ValueStateCallback>(cb)) {}
|
||||
ValueCache(ValueCache&& o) : values(std::move(o.values)), callback(std::move(o.callback)) {
|
||||
ValueCache(ValueStateCallback&& cb, SyncCallback&& scb = {})
|
||||
: callback(std::forward<ValueStateCallback>(cb)), syncCallback(std::move(scb))
|
||||
{
|
||||
if (syncCallback)
|
||||
syncCallback(ListenSyncStatus::ADDED);
|
||||
}
|
||||
ValueCache(ValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)), syncCallback(std::move(o.syncCallback)) {
|
||||
o.callback = {};
|
||||
o.syncCallback = {};
|
||||
}
|
||||
|
||||
~ValueCache() {
|
||||
auto q = clear();
|
||||
for (auto& cb: q)
|
||||
cb();
|
||||
if (syncCallback) {
|
||||
if (status == ListenSyncStatus::SYNCED)
|
||||
syncCallback(ListenSyncStatus::UNSYNCED);
|
||||
syncCallback(ListenSyncStatus::REMOVED);
|
||||
}
|
||||
}
|
||||
|
||||
CallbackQueue clear() {
|
||||
@@ -120,6 +133,15 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void onSynced(bool synced) {
|
||||
auto newStatus = synced ? ListenSyncStatus::SYNCED : ListenSyncStatus::UNSYNCED;
|
||||
if (status != newStatus) {
|
||||
status = newStatus;
|
||||
if (syncCallback)
|
||||
syncCallback(newStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// prevent copy
|
||||
ValueCache(const ValueCache&) = delete;
|
||||
@@ -141,6 +163,8 @@ private:
|
||||
|
||||
std::map<Value::Id, CacheValueStorage> values;
|
||||
ValueStateCallback callback;
|
||||
SyncCallback syncCallback;
|
||||
ListenSyncStatus status {ListenSyncStatus::UNSYNCED};
|
||||
|
||||
CallbackQueue addValues(const std::vector<Sp<Value>>& new_values, const TypeStore& types, const time_point& now) {
|
||||
std::vector<Sp<Value>> nvals;
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ bin_PROGRAMS = opendht_unit_tests
|
||||
|
||||
AM_CPPFLAGS = -I../include
|
||||
|
||||
nobase_include_HEADERS = infohashtester.h cryptotester.h dhtrunnertester.h dhtproxytester.h
|
||||
opendht_unit_tests_SOURCES = tests_runner.cpp cryptotester.cpp infohashtester.cpp dhtrunnertester.cpp dhtproxytester.cpp
|
||||
nobase_include_HEADERS = infohashtester.h valuetester.h cryptotester.h dhtrunnertester.h dhtproxytester.h
|
||||
opendht_unit_tests_SOURCES = tests_runner.cpp cryptotester.cpp infohashtester.cpp valuetester.cpp dhtrunnertester.cpp dhtproxytester.cpp
|
||||
opendht_unit_tests_LDFLAGS = -lopendht -lcppunit -L@top_builddir@/src/.libs @GnuTLS_LIBS@
|
||||
endif
|
||||
+30
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
@@ -54,7 +54,6 @@ CryptoTester::testCertificateRevocation()
|
||||
auto device11 = dht::crypto::generateIdentity("dev11", account1);
|
||||
auto device12 = dht::crypto::generateIdentity("dev12", account1);
|
||||
|
||||
|
||||
dht::crypto::TrustList list;
|
||||
list.add(*ca1.second);
|
||||
auto v = list.verify(*account1.second);
|
||||
@@ -72,7 +71,7 @@ CryptoTester::testCertificateRevocation()
|
||||
|
||||
v = list.verify(*device2.second);
|
||||
CPPUNIT_ASSERT_MESSAGE(v.toString(), !v);
|
||||
|
||||
|
||||
account1.second->revoke(*account1.first, *device11.second);
|
||||
dht::crypto::TrustList list2;
|
||||
list2.add(*account1.second);
|
||||
@@ -83,6 +82,34 @@ CryptoTester::testCertificateRevocation()
|
||||
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::testCertificateRequest()
|
||||
{
|
||||
// Generate CA
|
||||
auto ca = dht::crypto::generateIdentity("Test CA");
|
||||
|
||||
// Generate signed request
|
||||
auto deviceKey = dht::crypto::PrivateKey::generate();
|
||||
auto request = dht::crypto::CertificateRequest();
|
||||
request.setName("Test Device");
|
||||
request.sign(deviceKey);
|
||||
|
||||
// Export/import request
|
||||
auto importedRequest = dht::crypto::CertificateRequest(request.pack());
|
||||
CPPUNIT_ASSERT(importedRequest.verify());
|
||||
|
||||
// Generate/sign certificate from request
|
||||
auto signedCert = dht::crypto::Certificate::generate(request, ca);
|
||||
CPPUNIT_ASSERT_EQUAL(ca.second->getName(), signedCert.getIssuerName());
|
||||
CPPUNIT_ASSERT_EQUAL(request.getName(), signedCert.getName());
|
||||
|
||||
// Check generated certificate
|
||||
dht::crypto::TrustList list;
|
||||
list.add(*ca.second);
|
||||
auto v = list.verify(signedCert);
|
||||
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::tearDown() {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
@@ -29,6 +29,7 @@ class CryptoTester : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(CryptoTester);
|
||||
CPPUNIT_TEST(testSignatureEncryption);
|
||||
CPPUNIT_TEST(testCertificateRevocation);
|
||||
CPPUNIT_TEST(testCertificateRequest);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@@ -48,6 +49,10 @@ class CryptoTester : public CppUnit::TestFixture {
|
||||
* Test certificate generation, validation and revocation
|
||||
*/
|
||||
void testCertificateRevocation();
|
||||
/**
|
||||
* Test certificate requests
|
||||
*/
|
||||
void testCertificateRequest();
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
+111
-38
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -32,26 +33,32 @@ CPPUNIT_TEST_SUITE_REGISTRATION(DhtProxyTester);
|
||||
|
||||
void
|
||||
DhtProxyTester::setUp() {
|
||||
nodePeer.run(42222, {}, true);
|
||||
logger = dht::log::getStdLogger();
|
||||
|
||||
nodePeer.run(0, /*identity*/{}, /*threaded*/true);
|
||||
|
||||
nodeProxy = std::make_shared<dht::DhtRunner>();
|
||||
nodeClient = std::make_shared<dht::DhtRunner>();
|
||||
|
||||
nodeProxy->run(42232, {}, true);
|
||||
nodeProxy->run(0, /*identity*/{}, /*threaded*/true);
|
||||
nodeProxy->bootstrap(nodePeer.getBound());
|
||||
server = std::unique_ptr<dht::DhtProxyServer>(new dht::DhtProxyServer(nodeProxy, 8080));
|
||||
serverProxy = std::unique_ptr<dht::DhtProxyServer>(new dht::DhtProxyServer(
|
||||
nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090", logger));
|
||||
|
||||
nodeClient->run(42242, {}, true);
|
||||
nodeClient = std::make_shared<dht::DhtRunner>();
|
||||
nodeClient->run(0, /*identity*/{}, /*threaded*/true);
|
||||
nodeClient->bootstrap(nodePeer.getBound());
|
||||
nodeClient->setProxyServer("127.0.0.1:8080");
|
||||
nodeClient->enableProxy(true);
|
||||
nodeClient->enableProxy(true); // creates DhtProxyClient
|
||||
}
|
||||
|
||||
void
|
||||
DhtProxyTester::tearDown() {
|
||||
logger->d("[tester:proxy] stopping peer node");
|
||||
nodePeer.join();
|
||||
nodeClient->join();
|
||||
server->stop();
|
||||
server = nullptr;
|
||||
logger->d("[tester:proxy] stopping proxy server");
|
||||
serverProxy->stop();
|
||||
serverProxy = nullptr;
|
||||
logger->d("[tester:proxy] stopping proxy node");
|
||||
nodeProxy->join();
|
||||
}
|
||||
|
||||
@@ -65,21 +72,75 @@ DhtProxyTester::testGetPut() {
|
||||
dht::Value val {"Hey! It's been a long time. How have you been?"};
|
||||
auto val_data = val.data;
|
||||
|
||||
nodePeer.put(key, std::move(val), [&](bool) {
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
std::unique_lock<std::mutex> lk(cv_m);
|
||||
cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; });
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(cv_m);
|
||||
nodePeer.put(key, std::move(val), [&](bool) {
|
||||
std::lock_guard<std::mutex> lk(cv_m);
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
|
||||
}
|
||||
|
||||
auto vals = nodeClient->get(key).get();
|
||||
CPPUNIT_ASSERT(not vals.empty());
|
||||
CPPUNIT_ASSERT(vals.front()->data == val_data);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DhtProxyTester::testListen() {
|
||||
std::condition_variable cv;
|
||||
std::mutex cv_m;
|
||||
std::unique_lock<std::mutex> lk(cv_m);
|
||||
auto key = dht::InfoHash::get("GLaDOs");
|
||||
bool done = false;
|
||||
|
||||
// If a peer send a value, the listen operation from the client
|
||||
// should retrieve this value
|
||||
dht::Value firstVal {"Hey! It's been a long time. How have you been?"};
|
||||
auto firstVal_data = firstVal.data;
|
||||
nodePeer.put(key, std::move(firstVal), [&](bool ok) {
|
||||
CPPUNIT_ASSERT(ok);
|
||||
std::lock_guard<std::mutex> lk(cv_m);
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
|
||||
done = false;
|
||||
|
||||
std::vector<dht::Blob> values;
|
||||
auto token = nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
|
||||
if (not expired) {
|
||||
std::lock_guard<std::mutex> lk(cv_m);
|
||||
for (const auto& value : v)
|
||||
values.emplace_back(value->data);
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
|
||||
done = false;
|
||||
// Here values should contains 1 values
|
||||
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 1);
|
||||
CPPUNIT_ASSERT(values.front() == firstVal_data);
|
||||
|
||||
// And the listen should retrieve futures values
|
||||
// All values
|
||||
dht::Value secondVal {"You're a monster"};
|
||||
auto secondVal_data = secondVal.data;
|
||||
nodePeer.put(key, std::move(secondVal));
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
|
||||
nodeClient->cancelListen(key, std::move(token));
|
||||
// Here values should contains 2 values
|
||||
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 2);
|
||||
CPPUNIT_ASSERT(values.back() == secondVal_data);
|
||||
}
|
||||
|
||||
void
|
||||
DhtProxyTester::testResubscribeGetValues() {
|
||||
nodeClient->setPushNotificationToken("atlas");
|
||||
|
||||
bool done = false;
|
||||
std::condition_variable cv;
|
||||
std::mutex cv_m;
|
||||
@@ -91,36 +152,48 @@ DhtProxyTester::testListen() {
|
||||
dht::Value firstVal {"Hey! It's been a long time. How have you been?"};
|
||||
auto firstVal_data = firstVal.data;
|
||||
nodePeer.put(key, std::move(firstVal), [&](bool) {
|
||||
std::lock_guard<std::mutex> lk(cv_m);
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; });
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
|
||||
done = false;
|
||||
|
||||
// Send a first subscribe, the value is sent via a push notification
|
||||
// So ignore values here.
|
||||
nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>&, bool) {
|
||||
return true;
|
||||
});
|
||||
cv.wait_for(lk, std::chrono::seconds(1));
|
||||
|
||||
// Reboot node (to avoid cache)
|
||||
nodeClient->join();
|
||||
nodeClient->run(0, {}, true);
|
||||
nodeClient->bootstrap(nodePeer.getBound());
|
||||
nodeClient->setProxyServer("127.0.0.1:8080");
|
||||
nodeClient->enableProxy(true);
|
||||
nodeClient->setPushNotificationToken("atlas");
|
||||
|
||||
// For the second subscribe, the proxy will return the value in the body
|
||||
auto values = std::vector<dht::Blob>();
|
||||
nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool) {
|
||||
for (const auto& value : v)
|
||||
values.emplace_back(value->data);
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
auto ftoken = nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
|
||||
if (not expired) {
|
||||
std::lock_guard<std::mutex> lk(cv_m);
|
||||
for (const auto& value : v)
|
||||
values.emplace_back(value->data);
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; });
|
||||
done = false;
|
||||
// Here values should contains 2 values
|
||||
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 1);
|
||||
CPPUNIT_ASSERT(values.front() == firstVal_data);
|
||||
|
||||
// And the listen should retrieve futures values
|
||||
// All values
|
||||
dht::Value secondVal {"You're a monster"};
|
||||
auto secondVal_data = secondVal.data;
|
||||
nodePeer.put(key, std::move(secondVal));
|
||||
cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; });
|
||||
// Here values should contains 3 values
|
||||
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 2);
|
||||
CPPUNIT_ASSERT(values.back() == secondVal_data);
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
|
||||
auto token = ftoken.get();
|
||||
CPPUNIT_ASSERT(token);
|
||||
nodeClient->cancelListen(key, token);
|
||||
// Here values should still contains 1 values
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)1u, values.size());
|
||||
CPPUNIT_ASSERT(firstVal_data == values.front());
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
+18
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <opendht/dhtrunner.h>
|
||||
#include <opendht/dht_proxy_server.h>
|
||||
#include <opendht/log.h>
|
||||
|
||||
namespace test {
|
||||
|
||||
@@ -32,6 +33,7 @@ class DhtProxyTester : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(DhtProxyTester);
|
||||
CPPUNIT_TEST(testGetPut);
|
||||
CPPUNIT_TEST(testListen);
|
||||
CPPUNIT_TEST(testResubscribeGetValues);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@@ -39,26 +41,35 @@ class DhtProxyTester : public CppUnit::TestFixture {
|
||||
* Method automatically called before each test by CppUnit
|
||||
* Init nodes
|
||||
*/
|
||||
void setUp();
|
||||
void setUp();
|
||||
/**
|
||||
* Method automatically called after each test CppUnit
|
||||
*/
|
||||
void tearDown();
|
||||
void tearDown();
|
||||
/**
|
||||
* Test get and put methods
|
||||
*/
|
||||
void testGetPut();
|
||||
void testGetPut();
|
||||
/**
|
||||
* Test listen
|
||||
*/
|
||||
void testListen();
|
||||
void testListen();
|
||||
|
||||
/**
|
||||
* When a proxy redo a subscribe on the proxy
|
||||
* it should retrieve existant values
|
||||
*/
|
||||
void testResubscribeGetValues();
|
||||
|
||||
private:
|
||||
dht::DhtRunner nodePeer {};
|
||||
dht::DhtRunner nodePeer;
|
||||
|
||||
std::shared_ptr<dht::DhtRunner> nodeClient;
|
||||
std::shared_ptr<dht::DhtRunner> nodeProxy;
|
||||
std::unique_ptr<dht::DhtProxyServer> server;
|
||||
std::unique_ptr<dht::DhtProxyServer> serverProxy;
|
||||
|
||||
dht::DhtRunner::Config config {};
|
||||
std::shared_ptr<dht::Logger> logger {};
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
#include "dhtrunnertester.h"
|
||||
|
||||
// std
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace test {
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(DhtRunnerTester);
|
||||
@@ -50,15 +50,85 @@ DhtRunnerTester::testGetPut() {
|
||||
auto key = dht::InfoHash::get("123");
|
||||
dht::Value val {"hey"};
|
||||
auto val_data = val.data;
|
||||
node1.put(key, std::move(val));
|
||||
auto vals = node2.get(key).get();
|
||||
std::promise<bool> p;
|
||||
node2.put(key, std::move(val), [&](bool ok){
|
||||
p.set_value(ok);
|
||||
});
|
||||
CPPUNIT_ASSERT(p.get_future().get());
|
||||
auto vals = node1.get(key).get();
|
||||
CPPUNIT_ASSERT(not vals.empty());
|
||||
CPPUNIT_ASSERT(vals.front()->data == val_data);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunnerTester::testListen() {
|
||||
// TODO
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
std::atomic_uint valueCount(0);
|
||||
unsigned putCount(0);
|
||||
unsigned putOkCount(0);
|
||||
|
||||
auto a = dht::InfoHash::get("234");
|
||||
auto b = dht::InfoHash::get("2345");
|
||||
auto c = dht::InfoHash::get("23456");
|
||||
constexpr unsigned N = 32;
|
||||
|
||||
auto ftokena = node1.listen(a, [&](const std::shared_ptr<dht::Value>&) {
|
||||
valueCount++;
|
||||
return true;
|
||||
});
|
||||
|
||||
auto ftokenb = node1.listen(b, [&](const std::shared_ptr<dht::Value>&) {
|
||||
valueCount++;
|
||||
return false;
|
||||
});
|
||||
|
||||
auto ftokenc = node1.listen(c, [&](const std::shared_ptr<dht::Value>&) {
|
||||
valueCount++;
|
||||
return true;
|
||||
});
|
||||
|
||||
for (unsigned i=0; i<N; i++) {
|
||||
node2.put(a, dht::Value("v1"), [&](bool ok) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
putCount++;
|
||||
if (ok) putOkCount++;
|
||||
}
|
||||
cv.notify_all();
|
||||
});
|
||||
node2.put(b, dht::Value("v2"), [&](bool ok) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
putCount++;
|
||||
if (ok) putOkCount++;
|
||||
}
|
||||
cv.notify_all();
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
cv.wait_for(lk, std::chrono::seconds(30), [&]{ return putCount == N * 2u; });
|
||||
CPPUNIT_ASSERT_EQUAL(N * 2u, putCount);
|
||||
CPPUNIT_ASSERT_EQUAL(N * 2u, putOkCount);
|
||||
}
|
||||
|
||||
CPPUNIT_ASSERT(ftokena.valid());
|
||||
CPPUNIT_ASSERT(ftokenb.valid());
|
||||
CPPUNIT_ASSERT(ftokenc.valid());
|
||||
|
||||
auto tokena = ftokena.get();
|
||||
auto tokenc = ftokenc.get();
|
||||
// tokenb might be 0 since the callback returns false.
|
||||
|
||||
CPPUNIT_ASSERT(tokena);
|
||||
CPPUNIT_ASSERT(tokenc);
|
||||
CPPUNIT_ASSERT_EQUAL(N + 1u, valueCount.load());
|
||||
|
||||
node1.cancelListen(a, tokena);
|
||||
node1.cancelListen(b, std::move(ftokenb));
|
||||
node1.cancelListen(c, tokenc);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
Loaded 100 of 116 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user