mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-12 14:26:54 +00:00
Compare commits
347
Commits
0.6.2
...
crypto_checks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93c5ad7cbc | ||
|
|
03d52e4284 | ||
|
|
9d83ee169b | ||
|
|
43b181ebbf | ||
|
|
ac65ca5177 | ||
|
|
42671be21e | ||
|
|
efa6930de2 | ||
|
|
19c47ec781 | ||
|
|
435cd554e6 | ||
|
|
10c70ebd12 | ||
|
|
7da3ff1bba | ||
|
|
a222e30428 | ||
|
|
bd822fce19 | ||
|
|
cabe9dbeb5 | ||
|
|
99b7a07350 | ||
|
|
756e0bd3d8 | ||
|
|
9b0ce12b5f | ||
|
|
e29c2df002 | ||
|
|
b03a8b5b50 | ||
|
|
32f5175d68 | ||
|
|
7d3a54db57 | ||
|
|
3fb7c2acfe | ||
|
|
bce5d35b51 | ||
|
|
b6dca5ccd6 | ||
|
|
23b2712400 | ||
|
|
63bec73885 | ||
|
|
af5e0c8982 | ||
|
|
5a7c8753e1 | ||
|
|
19fdec96ca | ||
|
|
2208a06232 | ||
|
|
2cfcaf3909 | ||
|
|
620868b5d6 | ||
|
|
e7295bac7b | ||
|
|
38aa86de2a | ||
|
|
fdf476a3f3 | ||
|
|
22f27a6cc0 | ||
|
|
c72ea8ce77 | ||
|
|
ea168353b9 | ||
|
|
79b9c4838e | ||
|
|
d6e86ebcc9 | ||
|
|
197aaa47f0 | ||
|
|
ad234004aa | ||
|
|
a88e6a4c5f | ||
|
|
c776dad96f | ||
|
|
31fedd529b | ||
|
|
e9adff9dc5 | ||
|
|
bfd58a204b | ||
|
|
867bcf1514 | ||
|
|
fb882ee440 | ||
|
|
215d3d2847 | ||
|
|
43a345ba0c | ||
|
|
f73f5e2798 | ||
|
|
3724670fcc | ||
|
|
e7db64bd74 | ||
|
|
9c29b8a29e | ||
|
|
c22f0e4d43 | ||
|
|
4e2b11c24c | ||
|
|
8c34e927ea | ||
|
|
8a5de47aa0 | ||
|
|
7f84c1e397 | ||
|
|
65c915fd9d | ||
|
|
0fd4f73ab1 | ||
|
|
01117567b1 | ||
|
|
d68cc5cf40 | ||
|
|
6db16be2fa | ||
|
|
5166b1add9 | ||
|
|
9fadcc907c | ||
|
|
42171efc3f | ||
|
|
206f12648f | ||
|
|
ecd0573c4d | ||
|
|
2d9f6241a9 | ||
|
|
77ee50f5a6 | ||
|
|
297c37e609 | ||
|
|
9bb1ab43eb | ||
|
|
cd36b13c30 | ||
|
|
5d63084627 | ||
|
|
ab7d1d6582 | ||
|
|
77ea6d8c2f | ||
|
|
b5cd629160 | ||
|
|
39467c8b71 | ||
|
|
87740e3b38 | ||
|
|
19848a9b72 | ||
|
|
36e9998fe2 | ||
|
|
b2529c241e | ||
|
|
83c47037d2 | ||
|
|
125b6f9236 | ||
|
|
e260ba6b78 | ||
|
|
eafb934e85 | ||
|
|
c3d3da20f6 | ||
|
|
6036ccdbaa | ||
|
|
9404a4d069 | ||
|
|
274621dcec | ||
|
|
2ab756906d | ||
|
|
2b3f63443f | ||
|
|
c71f960948 | ||
|
|
9d3514e087 | ||
|
|
6703e039b1 | ||
|
|
29b81750ad | ||
|
|
d6fff53f6b | ||
|
|
7ee6281426 | ||
|
|
28a5740c37 | ||
|
|
09a3332cf0 | ||
|
|
f584c4849b | ||
|
|
e3663c995a | ||
|
|
1d62b3ca64 | ||
|
|
3af04a4259 | ||
|
|
78d98822a5 | ||
|
|
8c04ddc66b | ||
|
|
5277b8d23e | ||
|
|
86fea49178 | ||
|
|
5b1242f786 | ||
|
|
a8cfdbe762 | ||
|
|
70b1ebae0b | ||
|
|
9dc6004329 | ||
|
|
d4bd17a2dc | ||
|
|
6c73e5fa5c | ||
|
|
24edfb8eaf | ||
|
|
4ef5a2216e | ||
|
|
0d646eb244 | ||
|
|
757fea37f3 | ||
|
|
09e41cc9f2 | ||
|
|
71ad92e286 | ||
|
|
d4f3d3aa98 | ||
|
|
c0612a1b2c | ||
|
|
6743cbbf50 | ||
|
|
da1bdf9d4c | ||
|
|
96da4cd85d | ||
|
|
f233340cb2 | ||
|
|
cfb817d37f | ||
|
|
9440c03048 | ||
|
|
aa611bde50 | ||
|
|
7af856508e | ||
|
|
aaed64039a | ||
|
|
7c5e8c3234 | ||
|
|
a56bf3f115 | ||
|
|
2d2fa9cfa9 | ||
|
|
9f11930f3d | ||
|
|
013b1dfe2e | ||
|
|
733f699ff2 | ||
|
|
a366d502a2 | ||
|
|
eed8ffc792 | ||
|
|
998547e1a1 | ||
|
|
8567b7ad84 | ||
|
|
64118404fe | ||
|
|
bb74dc846c | ||
|
|
659d893dee | ||
|
|
e3f371c2d8 | ||
|
|
f53c7a6785 | ||
|
|
261c193b50 | ||
|
|
dc0b650aa3 | ||
|
|
87cf6faedd | ||
|
|
ca6aa6706d | ||
|
|
16e55416a6 | ||
|
|
3e24058175 | ||
|
|
d1c2b20b28 | ||
|
|
ccd0cbd8f2 | ||
|
|
e5213674e3 | ||
|
|
b9cc848810 | ||
|
|
65bdfaf22b | ||
|
|
de31d836b4 | ||
|
|
25b339956e | ||
|
|
23bb6e7a45 | ||
|
|
b44f7ec653 | ||
|
|
6d38c18572 | ||
|
|
8eaf78bfe2 | ||
|
|
dc836b38a6 | ||
|
|
b01f8d079b | ||
|
|
6f7ac21a85 | ||
|
|
7c5db84f33 | ||
|
|
4fecb2066b | ||
|
|
eabdddcfb3 | ||
|
|
ceab27d723 | ||
|
|
a9cc669a95 | ||
|
|
927c835b8f | ||
|
|
5415eaaf60 | ||
|
|
ec587f9b58 | ||
|
|
babfed73f3 | ||
|
|
2c0ce576e3 | ||
|
|
8f2cc937c5 | ||
|
|
c9f6567128 | ||
|
|
d60672e8ba | ||
|
|
fd4cce4883 | ||
|
|
df15d3d48e | ||
|
|
76fd216386 | ||
|
|
48735aad94 | ||
|
|
91a1471de5 | ||
|
|
047ba76ff1 | ||
|
|
e57eb63c87 | ||
|
|
8461f4018d | ||
|
|
c33c2e7e95 | ||
|
|
e5a9a2af4c | ||
|
|
7919ca8de1 | ||
|
|
00ef660952 | ||
|
|
862a03713b | ||
|
|
89d0d2f109 | ||
|
|
3283e34dcf | ||
|
|
34c6b264df | ||
|
|
2d8fe502f2 | ||
|
|
73df308250 | ||
|
|
cdca40cb59 | ||
|
|
2a3c301314 | ||
|
|
6f4923da2e | ||
|
|
ae26a2b39a | ||
|
|
48c40c8a27 | ||
|
|
a4a4eee495 | ||
|
|
d185428d1d | ||
|
|
6855aaa6f4 | ||
|
|
2aee4f418f | ||
|
|
95aef01a59 | ||
|
|
d2ccde4859 | ||
|
|
7ab64ea0e6 | ||
|
|
fe1b8b88e1 | ||
|
|
b6832869b1 | ||
|
|
6da8d39a0e | ||
|
|
f8cf1316ad | ||
|
|
736606a845 | ||
|
|
cba240e15e | ||
|
|
eb90fffb5e | ||
|
|
041e280bde | ||
|
|
33fae1cb66 | ||
|
|
4e8408e225 | ||
|
|
e85a423f6a | ||
|
|
532cb40665 | ||
|
|
dd58b0497e | ||
|
|
cc070c80ba | ||
|
|
e332dae576 | ||
|
|
727fd4e98b | ||
|
|
5a5f7012d8 | ||
|
|
5a239cddf7 | ||
|
|
c4928553ba | ||
|
|
48b0cff08e | ||
|
|
c8fcffbe6b | ||
|
|
63c4eeb9c9 | ||
|
|
d45f777099 | ||
|
|
9c4035dd8f | ||
|
|
acc2b71c86 | ||
|
|
09d849c93d | ||
|
|
1be1ad88c6 | ||
|
|
8ecaf25339 | ||
|
|
7a6dce4727 | ||
|
|
b357ffb0e6 | ||
|
|
517bd5f22b | ||
|
|
d1d0a67d35 | ||
|
|
85a9dbafc6 | ||
|
|
79390f72fa | ||
|
|
b7a37dd771 | ||
|
|
b24d1ccc8b | ||
|
|
4f53e10e7e | ||
|
|
a608ad3cf6 | ||
|
|
a135f81073 | ||
|
|
2da48557ff | ||
|
|
73686debaf | ||
|
|
97950621cd | ||
|
|
b3401828e4 | ||
|
|
0a7d4a68b3 | ||
|
|
8d7deffa6a | ||
|
|
669c08210e | ||
|
|
27a3231a55 | ||
|
|
86ce695939 | ||
|
|
2759a136df | ||
|
|
690682408b | ||
|
|
bfdb8a24e9 | ||
|
|
e9bf042ac5 | ||
|
|
5aab3078c8 | ||
|
|
1ac5840bb1 | ||
|
|
426b3d6834 | ||
|
|
97b573c182 | ||
|
|
5c41cbb964 | ||
|
|
e192e3beaf | ||
|
|
5dacb50d63 | ||
|
|
86d837b5a9 | ||
|
|
6454a6dc3f | ||
|
|
bbd1200ad7 | ||
|
|
aa59242843 | ||
|
|
c04ede4909 | ||
|
|
a1eaf2e83c | ||
|
|
a21d4d4adc | ||
|
|
f0a92d999c | ||
|
|
28a3498a69 | ||
|
|
7eb5d892f1 | ||
|
|
f6cd79952c | ||
|
|
9c1a0ae27f | ||
|
|
29c1a955d0 | ||
|
|
b366432a8a | ||
|
|
af8bfdc1c1 | ||
|
|
88040ad467 | ||
|
|
a35e67bcdf | ||
|
|
df3317a5b2 | ||
|
|
33f95c00a9 | ||
|
|
7383505dcc | ||
|
|
2c9a29af0e | ||
|
|
5847273b79 | ||
|
|
98204991ec | ||
|
|
b8e10bfe15 | ||
|
|
132fe66699 | ||
|
|
a28fc4dfb1 | ||
|
|
7721aa5643 | ||
|
|
68707aff17 | ||
|
|
3ecbc9adff | ||
|
|
b5a7a0ca31 | ||
|
|
2362db8528 | ||
|
|
62835bdc54 | ||
|
|
fe1cf209f1 | ||
|
|
2f72563b1f | ||
|
|
0d754d6ca8 | ||
|
|
f474f6499b | ||
|
|
97baacf609 | ||
|
|
0fa8cfdb71 | ||
|
|
78c7cae7e9 | ||
|
|
a4834efd37 | ||
|
|
07e4435a07 | ||
|
|
9f93771771 | ||
|
|
a533807fcf | ||
|
|
49129ec1b2 | ||
|
|
803354552f | ||
|
|
fa6c365679 | ||
|
|
6ac1ae3527 | ||
|
|
29834b714e | ||
|
|
bba27adf4d | ||
|
|
e3a280d7a9 | ||
|
|
63f1a736f4 | ||
|
|
0f8720c433 | ||
|
|
7a6263b940 | ||
|
|
b09e3df2e2 | ||
|
|
041a9e0e7f | ||
|
|
fa9730dd07 | ||
|
|
33f29e95f4 | ||
|
|
fdfa10bd2e | ||
|
|
f200f9dfc2 | ||
|
|
9615774114 | ||
|
|
c6b0e531c2 | ||
|
|
8e5f12dbf1 | ||
|
|
5bcf1da505 | ||
|
|
97d88fcfed | ||
|
|
963dd6779e | ||
|
|
54a4327039 | ||
|
|
10e5439048 | ||
|
|
dcca94aab7 | ||
|
|
173a9ee642 | ||
|
|
ed1ca6db8f | ||
|
|
7367158284 | ||
|
|
cf8d9ccd0d | ||
|
|
fdbdc91d55 | ||
|
|
cf9c63abb7 | ||
|
|
475b26048f | ||
|
|
df1615e8d1 | ||
|
|
9e461e0960 |
No files matched your search
+10
@@ -45,3 +45,13 @@ Makefile.in
|
||||
# KDevelop
|
||||
.kdev4/
|
||||
*.kdev4
|
||||
|
||||
# Python
|
||||
*.pyc
|
||||
|
||||
# git backup files
|
||||
*.orig
|
||||
|
||||
# vim swap files
|
||||
*.swp
|
||||
*.swo
|
||||
+5
-31
@@ -1,44 +1,18 @@
|
||||
sudo: false
|
||||
sudo: required
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
language: cpp
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-6
|
||||
- g++-6
|
||||
- libgnutls28-dev
|
||||
- cmake
|
||||
|
||||
before_install:
|
||||
- if [ $TRAVIS_OS_NAME == linux ] && [ $CXX == g++ ]; then export CXX=/usr/bin/g++-6 && export CC=/usr/bin/gcc-6; fi
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then git clone https://github.com/msgpack/msgpack-c.git; fi
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then cd msgpack-c && git checkout cpp-1.2.0 && mkdir build && mkdir -p $HOME/usr && cd build; fi
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then cmake -DCMAKE_INSTALL_PREFIX=$HOME/usr -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF .. && make -j && make install && cd ../.. && pwd; fi
|
||||
- if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install llvm36 && brew install msgpack && brew install gnutls && brew link --force llvm36; fi
|
||||
|
||||
before_script:
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then travis_retry ./autogen.sh && ./configure --prefix=$HOME/usr; fi
|
||||
- if [ $TRAVIS_OS_NAME == osx ]; then travis_retry ./autogen.sh && ./configure; fi
|
||||
- docker pull aberaud/opendht-deps
|
||||
- docker pull aberaud/opendht-deps-llvm
|
||||
|
||||
script:
|
||||
- make -j
|
||||
- docker build -f docker/DockerfileTravis .
|
||||
- docker build -f docker/DockerfileTravisLlvm .
|
||||
|
||||
notifications:
|
||||
email:
|
||||
- adrien.beraud@savoirfairelinux.com
|
||||
|
||||
env:
|
||||
- LANG="en_US.UTF-8"
|
||||
|
||||
os:
|
||||
- osx
|
||||
+49
-28
@@ -1,42 +1,52 @@
|
||||
cmake_minimum_required (VERSION 2.8.6)
|
||||
project (opendht)
|
||||
set (opendht_VERSION_MAJOR 0)
|
||||
set (opendht_VERSION_MINOR 6.1)
|
||||
set (opendht_VERSION_MAJOR 1)
|
||||
set (opendht_VERSION_MINOR 3.0)
|
||||
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
|
||||
set (PACKAGE_VERSION ${opendht_VERSION})
|
||||
set (VERSION "${opendht_VERSION}")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
set (prefix ${CMAKE_INSTALL_PREFIX})
|
||||
set (exec_prefix "\${prefix}")
|
||||
set (libdir "\${exec_prefix}/lib")
|
||||
set (includedir "\${prefix}/include")
|
||||
set (libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
|
||||
set (includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
option (OPENDHT_DEBUG "Build with debug flags" OFF)
|
||||
option (OPENDHT_STATIC "Build static library" ON)
|
||||
option (OPENDHT_SHARED "Build shared library" ON)
|
||||
option (OPENDHT_LTO "Build with LTO" OFF)
|
||||
|
||||
option (OPENDHT_LOG "Build with logs" ON)
|
||||
option (OPENDHT_PYTHON "Build Python bindings" OFF)
|
||||
option (OPENDHT_TOOLS "Build DHT tools" ON)
|
||||
option (OPENDHT_LTO "Build with LTO" OFF)
|
||||
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++11 -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor")
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
|
||||
if (OPENDHT_LTO)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -fuse-linker-plugin")
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
SET (CMAKE_AR "gcc-ar")
|
||||
SET (CMAKE_NM "gcc-nm")
|
||||
SET (CMAKE_RANLIB "gcc-ranlib")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
find_package (GnuTLS 3.1 REQUIRED)
|
||||
find_package (GnuTLS 3.3 REQUIRED)
|
||||
find_package (Msgpack 1.2 REQUIRED)
|
||||
if (OPENDHT_TOOLS)
|
||||
find_package (Readline 6 REQUIRED)
|
||||
endif ()
|
||||
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++11 -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -pedantic-errors -fvisibility=hidden")
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif ()
|
||||
if (OPENDHT_LOG)
|
||||
add_definitions(-DOPENDHT_LOG=true)
|
||||
else ()
|
||||
add_definitions(-DOPENDHT_LOG=false)
|
||||
endif()
|
||||
if (OPENDHT_LTO)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-linker-plugin")
|
||||
set (CMAKE_AR "gcc-ar")
|
||||
set (CMAKE_NM "gcc-nm")
|
||||
set (CMAKE_RANLIB "gcc-ranlib")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
list (APPEND opendht_SOURCES
|
||||
src/utils.cpp
|
||||
src/infohash.cpp
|
||||
@@ -57,10 +67,14 @@ list (APPEND opendht_SOURCES
|
||||
src/argon2/thread.c
|
||||
src/argon2/encoding.c
|
||||
src/argon2/ref.c
|
||||
src/indexation/pht.cpp
|
||||
src/log.cpp
|
||||
)
|
||||
|
||||
list (APPEND opendht_HEADERS
|
||||
include/opendht/def.h
|
||||
include/opendht/utils.h
|
||||
include/opendht/sockaddr.h
|
||||
include/opendht/rng.h
|
||||
include/opendht/crypto.h
|
||||
include/opendht/infohash.h
|
||||
@@ -72,10 +86,14 @@ list (APPEND opendht_HEADERS
|
||||
include/opendht/routing_table.h
|
||||
include/opendht/node_cache.h
|
||||
include/opendht/network_engine.h
|
||||
include/opendht/net.h
|
||||
include/opendht/scheduler.h
|
||||
include/opendht/rate_limiter.h
|
||||
include/opendht/securedht.h
|
||||
include/opendht/log.h
|
||||
include/opendht/log_enable.h
|
||||
include/opendht.h
|
||||
include/opendht/indexation/pht.h
|
||||
)
|
||||
|
||||
configure_file (
|
||||
@@ -91,12 +109,6 @@ include_directories (
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/
|
||||
)
|
||||
|
||||
if (OPENDHT_DEBUG)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
else ()
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||
set(CMAKE_INSTALL_LIBDIR lib)
|
||||
endif ()
|
||||
@@ -111,7 +123,7 @@ if (OPENDHT_STATIC)
|
||||
target_link_libraries(opendht-static -flto -fuse-linker-plugin)
|
||||
endif ()
|
||||
target_link_libraries(opendht-static gnutls nettle)
|
||||
install (TARGETS opendht-static DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install (TARGETS opendht-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
|
||||
endif ()
|
||||
|
||||
if (OPENDHT_SHARED)
|
||||
@@ -120,21 +132,30 @@ if (OPENDHT_SHARED)
|
||||
${opendht_HEADERS}
|
||||
)
|
||||
set_target_properties (opendht PROPERTIES IMPORT_SUFFIX "_import.lib")
|
||||
#set_target_properties (opendht PROPERTIES SOVERSION 1 VERSION 1.0.0)
|
||||
set_target_properties (opendht PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION})
|
||||
target_compile_definitions(opendht PRIVATE OPENDHT_BUILD)
|
||||
if (OPENDHT_LTO)
|
||||
target_link_libraries(opendht -flto -fuse-linker-plugin)
|
||||
endif ()
|
||||
target_link_libraries(opendht gnutls nettle)
|
||||
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
|
||||
endif ()
|
||||
|
||||
if (OPENDHT_TOOLS)
|
||||
add_subdirectory(tools)
|
||||
endif ()
|
||||
add_subdirectory(doc)
|
||||
|
||||
if (OPENDHT_PYTHON)
|
||||
add_subdirectory(python)
|
||||
endif ()
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake"
|
||||
VERSION ${opendht_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
install (DIRECTORY include DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendht.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
install (EXPORT opendht DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht FILE opendhtConfig.cmake)
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht)
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
#output directories
|
||||
DebugLib/
|
||||
Debug/
|
||||
ReleaseLib/
|
||||
Release/
|
||||
.config/
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.VC.VC.opendb
|
||||
*.VC.db
|
||||
*.db
|
||||
*.filters
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Microsoft Azure ApplicationInsights config file
|
||||
ApplicationInsights.config
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
!config.h
|
||||
@@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}</ProjectGuid>
|
||||
<RootNamespace>argon</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\argon2\argon2.c" />
|
||||
<ClCompile Include="..\src\argon2\core.c" />
|
||||
<ClCompile Include="..\src\argon2\encoding.c" />
|
||||
<ClCompile Include="..\src\argon2\opt.c" />
|
||||
<ClCompile Include="..\src\argon2\ref.c" />
|
||||
<ClCompile Include="..\src\argon2\thread.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\argon2\argon2.h" />
|
||||
<ClInclude Include="..\src\argon2\core.h" />
|
||||
<ClInclude Include="..\src\argon2\encoding.h" />
|
||||
<ClInclude Include="..\src\argon2\opt.h" />
|
||||
<ClInclude Include="..\src\argon2\ref.h" />
|
||||
<ClInclude Include="..\src\argon2\thread.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}</ProjectGuid>
|
||||
<RootNamespace>blake</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\argon2\blake2\blake2b.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\argon2\blake2\blake2-impl.h" />
|
||||
<ClInclude Include="..\src\argon2\blake2\blake2.h" />
|
||||
<ClInclude Include="..\src\argon2\blake2\blamka-round-opt.h" />
|
||||
<ClInclude Include="..\src\argon2\blake2\blamka-round-ref.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}</ProjectGuid>
|
||||
<RootNamespace>dhtchat</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</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>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</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>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<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>
|
||||
<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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<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>
|
||||
<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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\tools\dhtchat.cpp" />
|
||||
<ClCompile Include="wingetopt.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tools\tools_common.h" />
|
||||
<ClInclude Include="wingetopt.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}</ProjectGuid>
|
||||
<RootNamespace>dhtnode</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</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>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</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>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<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>
|
||||
<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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<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>
|
||||
<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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\tools\dhtnode.cpp" />
|
||||
<ClCompile Include="wingetopt.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tools\tools_common.h" />
|
||||
<ClInclude Include="wingetopt.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{78443BCD-4689-4007-A246-F8F34B27F561}</ProjectGuid>
|
||||
<RootNamespace>dhtscanner</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</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>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</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>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<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>
|
||||
<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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<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>
|
||||
<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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_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>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\tools\dhtscanner.cpp" />
|
||||
<ClCompile Include="wingetopt.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tools\tools_common.h" />
|
||||
<ClInclude Include="wingetopt.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,221 @@
|
||||
--- /dev/null
|
||||
+++ b/msgpack_vc8.vcxproj
|
||||
@@ -0,0 +1,214 @@
|
||||
+<?xml version="1.0" encoding="utf-8"?>
|
||||
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
+ <ItemGroup Label="ProjectConfigurations">
|
||||
+ <ProjectConfiguration Include="Debug|Win32">
|
||||
+ <Configuration>Debug</Configuration>
|
||||
+ <Platform>Win32</Platform>
|
||||
+ </ProjectConfiguration>
|
||||
+ <ProjectConfiguration Include="Debug|x64">
|
||||
+ <Configuration>Debug</Configuration>
|
||||
+ <Platform>x64</Platform>
|
||||
+ </ProjectConfiguration>
|
||||
+ <ProjectConfiguration Include="Release|Win32">
|
||||
+ <Configuration>Release</Configuration>
|
||||
+ <Platform>Win32</Platform>
|
||||
+ </ProjectConfiguration>
|
||||
+ <ProjectConfiguration Include="Release|x64">
|
||||
+ <Configuration>Release</Configuration>
|
||||
+ <Platform>x64</Platform>
|
||||
+ </ProjectConfiguration>
|
||||
+ </ItemGroup>
|
||||
+ <PropertyGroup Label="Globals">
|
||||
+ <ProjectName>MessagePack</ProjectName>
|
||||
+ <ProjectGuid>{122A2EA4-B283-4241-9655-786DE78283B2}</ProjectGuid>
|
||||
+ <RootNamespace>MessagePack</RootNamespace>
|
||||
+ <Keyword>Win32Proj</Keyword>
|
||||
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
+ </PropertyGroup>
|
||||
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
+ <ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
+ <PlatformToolset>v140</PlatformToolset>
|
||||
+ <CharacterSet>Unicode</CharacterSet>
|
||||
+ <WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
+ </PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
+ <ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
+ <PlatformToolset>v140</PlatformToolset>
|
||||
+ <CharacterSet>Unicode</CharacterSet>
|
||||
+ <WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
+ </PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
+ <ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
+ <PlatformToolset>v140</PlatformToolset>
|
||||
+ <CharacterSet>Unicode</CharacterSet>
|
||||
+ </PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
+ <ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
+ <PlatformToolset>v140</PlatformToolset>
|
||||
+ <CharacterSet>Unicode</CharacterSet>
|
||||
+ </PropertyGroup>
|
||||
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
+ <ImportGroup Label="ExtensionSettings">
|
||||
+ </ImportGroup>
|
||||
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
+ </ImportGroup>
|
||||
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
+ </ImportGroup>
|
||||
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
+ </ImportGroup>
|
||||
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
+ </ImportGroup>
|
||||
+ <PropertyGroup Label="UserMacros" />
|
||||
+ <PropertyGroup>
|
||||
+ <_ProjectFileVersion>14.0.25123.0</_ProjectFileVersion>
|
||||
+ </PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
+ <OutDir>$(ProjectDir)..\</OutDir>
|
||||
+ <IntDir>$(Configuration)\</IntDir>
|
||||
+ <TargetName>msgpackd</TargetName>
|
||||
+ </PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
+ <TargetName>msgpackd</TargetName>
|
||||
+ <OutDir>$(ProjectDir)..\</OutDir>
|
||||
+ <IntDir>$(Configuration)\</IntDir>
|
||||
+ </PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
+ <OutDir>$(ProjectDir)..\</OutDir>
|
||||
+ <IntDir>$(Configuration)\</IntDir>
|
||||
+ <TargetName>msgpack</TargetName>
|
||||
+ </PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
+ <TargetName>msgpack</TargetName>
|
||||
+ <OutDir>$(ProjectDir)..\</OutDir>
|
||||
+ <IntDir>$(Configuration)\</IntDir>
|
||||
+ </PropertyGroup>
|
||||
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
+ <ClCompile>
|
||||
+ <Optimization>Disabled</Optimization>
|
||||
+ <AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
+ <PreprocessorDefinitions>WIN32_NATIVE;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
+ <MinimalRebuild>true</MinimalRebuild>
|
||||
+ <BasicRuntimeChecks>StackFrameRuntimeCheck</BasicRuntimeChecks>
|
||||
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
+ <PrecompiledHeader />
|
||||
+ <WarningLevel>Level3</WarningLevel>
|
||||
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
+ </ClCompile>
|
||||
+ <Lib>
|
||||
+ <OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
+ </Lib>
|
||||
+ <PostBuildEvent>
|
||||
+ <Command>mkdir $(OutDir)\include
|
||||
+
|
||||
+mkdir $(OutDir)\include\msgpack
|
||||
+
|
||||
+copy include\*.h $(OutDir)\include\
|
||||
+
|
||||
+copy include\*.hpp $(OutDir)\include\
|
||||
+xcopy /S /Y include\msgpack\*.h $(OutDir)\include\msgpack
|
||||
+xcopy /S /Y include\msgpack\*.hpp $(OutDir)\include\msgpack
|
||||
+</Command>
|
||||
+ </PostBuildEvent>
|
||||
+ </ItemDefinitionGroup>
|
||||
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
+ <ClCompile>
|
||||
+ <Optimization>Disabled</Optimization>
|
||||
+ <AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
+ <PreprocessorDefinitions>WIN32_NATIVE;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
+ <BasicRuntimeChecks>StackFrameRuntimeCheck</BasicRuntimeChecks>
|
||||
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
+ <PrecompiledHeader>
|
||||
+ </PrecompiledHeader>
|
||||
+ <WarningLevel>Level3</WarningLevel>
|
||||
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
+ </ClCompile>
|
||||
+ <Lib>
|
||||
+ <OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
+ </Lib>
|
||||
+ <PostBuildEvent>
|
||||
+ <Command>mkdir $(OutDir)\include
|
||||
+
|
||||
+mkdir $(OutDir)\include\msgpack
|
||||
+
|
||||
+copy include\*.h $(OutDir)\include\
|
||||
+
|
||||
+copy include\*.hpp $(OutDir)\include\
|
||||
+xcopy /S /Y include\msgpack\*.h $(OutDir)\include\msgpack
|
||||
+xcopy /S /Y include\msgpack\*.hpp $(OutDir)\include\msgpack
|
||||
+</Command>
|
||||
+ </PostBuildEvent>
|
||||
+ </ItemDefinitionGroup>
|
||||
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
+ <ClCompile>
|
||||
+ <AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
+ <PreprocessorDefinitions>WIN32_NATIVE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
+ <PrecompiledHeader />
|
||||
+ <WarningLevel>Level3</WarningLevel>
|
||||
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
+ <ProgramDataBaseFileName>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
+ </ClCompile>
|
||||
+ <Lib>
|
||||
+ <OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
+ <LinkTimeCodeGeneration />
|
||||
+ </Lib>
|
||||
+ <PostBuildEvent>
|
||||
+ <Command>mkdir $(OutDir)\include
|
||||
+
|
||||
+mkdir $(OutDir)\include\msgpack
|
||||
+
|
||||
+copy include\*.h $(OutDir)\include\
|
||||
+
|
||||
+copy include\*.hpp $(OutDir)\include\
|
||||
+xcopy /S /Y include\msgpack\*.h $(OutDir)\include\msgpack
|
||||
+xcopy /S /Y include\msgpack\*.hpp $(OutDir)\include\msgpack
|
||||
+</Command>
|
||||
+ </PostBuildEvent>
|
||||
+ </ItemDefinitionGroup>
|
||||
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
+ <ClCompile>
|
||||
+ <AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
+ <PreprocessorDefinitions>MSGPACK_USE_CPP03;WIN32_NATIVE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
+ <PrecompiledHeader>
|
||||
+ </PrecompiledHeader>
|
||||
+ <WarningLevel>Level3</WarningLevel>
|
||||
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
+ <ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
+ </ClCompile>
|
||||
+ <Lib>
|
||||
+ <OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
+ <LinkTimeCodeGeneration />
|
||||
+ </Lib>
|
||||
+ <PostBuildEvent>
|
||||
+ <Command>mkdir $(OutDir)\include
|
||||
+
|
||||
+mkdir $(OutDir)\include\msgpack
|
||||
+
|
||||
+copy include\*.h $(OutDir)\include\
|
||||
+
|
||||
+copy include\*.hpp $(OutDir)\include\
|
||||
+xcopy /S /Y include\msgpack\*.h $(OutDir)\include\msgpack
|
||||
+xcopy /S /Y include\msgpack\*.hpp $(OutDir)\include\msgpack
|
||||
+</Command>
|
||||
+ </PostBuildEvent>
|
||||
+ </ItemDefinitionGroup>
|
||||
+ <ItemGroup>
|
||||
+ <ClCompile Include="src\objectc.c" />
|
||||
+ <ClCompile Include="src\unpack.c" />
|
||||
+ <ClCompile Include="src\version.c" />
|
||||
+ <ClCompile Include="src\vrefbuffer.c" />
|
||||
+ <ClCompile Include="src\zone.c" />
|
||||
+ </ItemGroup>
|
||||
+ <ItemGroup>
|
||||
+ <ClInclude Include="include\msgpack.hpp" />
|
||||
+ </ItemGroup>
|
||||
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
+ <ImportGroup Label="ExtensionTargets">
|
||||
+ </ImportGroup>
|
||||
+</Project>
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.8.1.windows.1
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25123.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opendht", "opendht.vcxproj", "{711397CE-E5D5-467D-9457-8716C047E50C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
DebugDLL|x64 = DebugDLL|x64
|
||||
DebugDLL|x86 = DebugDLL|x86
|
||||
DebugDLLStaticDeps|x64 = DebugDLLStaticDeps|x64
|
||||
DebugDLLStaticDeps|x86 = DebugDLLStaticDeps|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
ReleaseDLL|x64 = ReleaseDLL|x64
|
||||
ReleaseDLL|x86 = ReleaseDLL|x86
|
||||
ReleaseDLLStaticDeps|x64 = ReleaseDLLStaticDeps|x64
|
||||
ReleaseDLLStaticDeps|x86 = ReleaseDLLStaticDeps|x86
|
||||
ReleaseLTO|x64 = ReleaseLTO|x64
|
||||
ReleaseLTO|x86 = ReleaseLTO|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x64.Build.0 = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x86.Build.0 = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x64.ActiveCfg = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x64.Build.0 = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x86.ActiveCfg = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x86.Build.0 = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x64.ActiveCfg = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x64.Build.0 = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x86.ActiveCfg = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x86.Build.0 = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x64.ActiveCfg = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x64.Build.0 = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x86.ActiveCfg = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x86.Build.0 = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x64.ActiveCfg = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x64.Build.0 = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x86.ActiveCfg = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x86.Build.0 = Release|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x64.Build.0 = Debug|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x86.Build.0 = Debug|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x64.ActiveCfg = Release|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x64.Build.0 = Release|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x86.ActiveCfg = Release|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x86.Build.0 = Release|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x64.Build.0 = Debug|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x86.Build.0 = Debug|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLLStaticDeps|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x64.Build.0 = DebugDLLStaticDeps|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLLStaticDeps|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x86.Build.0 = DebugDLLStaticDeps|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x64.ActiveCfg = Release|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x64.Build.0 = Release|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x86.ActiveCfg = Release|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x86.Build.0 = Release|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLLStaticDeps|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLLStaticDeps|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLLStaticDeps|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLLStaticDeps|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x64.Build.0 = Debug|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x64.ActiveCfg = Release|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x64.Build.0 = Release|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x86.Build.0 = Release|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x64.Build.0 = Debug|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x86.Build.0 = Debug|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLLStaticDeps|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x64.Build.0 = DebugDLLStaticDeps|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLLStaticDeps|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x86.Build.0 = DebugDLLStaticDeps|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x64.ActiveCfg = Release|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x64.Build.0 = Release|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x86.ActiveCfg = Release|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x86.Build.0 = Release|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLLStaticDeps|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLLStaticDeps|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLLStaticDeps|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLLStaticDeps|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x64.Build.0 = Debug|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x86.Build.0 = Debug|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x64.ActiveCfg = Release|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x64.Build.0 = Release|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x86.ActiveCfg = Release|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x86.Build.0 = Release|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x64.Build.0 = Release|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x86.Build.0 = Release|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x64.Build.0 = Debug|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x86.Build.0 = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x64.ActiveCfg = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x64.Build.0 = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x86.ActiveCfg = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x86.Build.0 = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x64.ActiveCfg = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x64.Build.0 = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x64.ActiveCfg = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x64.Build.0 = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x86.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x86.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x64.ActiveCfg = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x64.Build.0 = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x86.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x86.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x64.ActiveCfg = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x64.Build.0 = Release|x64
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x86.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,236 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\callbacks.cpp" />
|
||||
<ClCompile Include="..\src\crypto.cpp" />
|
||||
<ClCompile Include="..\src\default_types.cpp" />
|
||||
<ClCompile Include="..\src\dht.cpp" />
|
||||
<ClCompile Include="..\src\dhtrunner.cpp" />
|
||||
<ClCompile Include="..\src\indexation\pht.cpp" />
|
||||
<ClCompile Include="..\src\infohash.cpp" />
|
||||
<ClCompile Include="..\src\network_engine.cpp" />
|
||||
<ClCompile Include="..\src\node.cpp" />
|
||||
<ClCompile Include="..\src\node_cache.cpp" />
|
||||
<ClCompile Include="..\src\routing_table.cpp" />
|
||||
<ClCompile Include="..\src\securedht.cpp" />
|
||||
<ClCompile Include="..\src\utils.cpp" />
|
||||
<ClCompile Include="..\src\value.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\include\opendht.h" />
|
||||
<ClInclude Include="..\include\opendht\callbacks.h" />
|
||||
<ClInclude Include="..\include\opendht\crypto.h" />
|
||||
<ClInclude Include="..\include\opendht\default_types.h" />
|
||||
<ClInclude Include="..\include\opendht\dht.h" />
|
||||
<ClInclude Include="..\include\opendht\dhtrunner.h" />
|
||||
<ClInclude Include="..\include\opendht\indexation\pht.h" />
|
||||
<ClInclude Include="..\include\opendht\infohash.h" />
|
||||
<ClInclude Include="..\include\opendht\log.h" />
|
||||
<ClInclude Include="..\include\opendht\log_enable.h" />
|
||||
<ClInclude Include="..\include\opendht\network_engine.h" />
|
||||
<ClInclude Include="..\include\opendht\node.h" />
|
||||
<ClInclude Include="..\include\opendht\node_cache.h" />
|
||||
<ClInclude Include="..\include\opendht\rate_limiter.h" />
|
||||
<ClInclude Include="..\include\opendht\request.h" />
|
||||
<ClInclude Include="..\include\opendht\rng.h" />
|
||||
<ClInclude Include="..\include\opendht\routing_table.h" />
|
||||
<ClInclude Include="..\include\opendht\scheduler.h" />
|
||||
<ClInclude Include="..\include\opendht\securedht.h" />
|
||||
<ClInclude Include="..\include\opendht\utils.h" />
|
||||
<ClInclude Include="..\include\opendht\value.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{711397CE-E5D5-467D-9457-8716C047E50C}</ProjectGuid>
|
||||
<RootNamespace>opendht</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>opendhtd</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>opendht</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
<TargetName>opendhtd</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(ProjectDir)..\..\</OutDir>
|
||||
<TargetName>opendht</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_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<SuppressStartupBanner>false</SuppressStartupBanner>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>mkdir $(OutDir)\include
|
||||
mkdir $(OutDir)\include\opendht
|
||||
mkdir $(OutDir)\include\opendht\indexation
|
||||
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
|
||||
copy ..\include\opendht\*.h $(OutDir)\include\opendht
|
||||
copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
</PostBuildEvent>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<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_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>mkdir $(OutDir)\include
|
||||
mkdir $(OutDir)\include\opendht
|
||||
mkdir $(OutDir)\include\opendht\indexation
|
||||
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
|
||||
copy ..\include\opendht\*.h $(OutDir)\include\opendht
|
||||
copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
</PostBuildEvent>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<ProgramDataBaseFileName>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>mkdir $(OutDir)\include
|
||||
mkdir $(OutDir)\include\opendht
|
||||
mkdir $(OutDir)\include\opendht\indexation
|
||||
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
|
||||
copy ..\include\opendht\*.h $(OutDir)\include\opendht
|
||||
copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
</PostBuildEvent>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Full</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
|
||||
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
|
||||
<ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>mkdir $(OutDir)\include
|
||||
mkdir $(OutDir)\include\opendht
|
||||
mkdir $(OutDir)\include\opendht\indexation
|
||||
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
|
||||
copy ..\include\opendht\*.h $(OutDir)\include\opendht
|
||||
copy ..\include\opendht.h $(OutDir)\include\</Command>
|
||||
</PostBuildEvent>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,462 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opendht", "opendht.vcxproj", "{711397CE-E5D5-467D-9457-8716C047E50C}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA} = {2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518} = {070FEF2B-0C3F-4F33-9D3C-53C7330BF518}
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2} = {122A2EA4-B283-4241-9655-786DE78283B2}
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02} = {6F610EE8-7F59-4191-AB88-F63843267C02}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{71A1A9EC-1104-4335-A87E-AF8749FD5B34}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgmp", "..\..\gmp\SMP\libgmp.vcxproj", "{02B94302-23D6-43EF-8865-95CDE99D5DC2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgnutls", "..\..\gnutls\SMP\libgnutls.vcxproj", "{6F610EE8-7F59-4191-AB88-F63843267C02}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2} = {02B94302-23D6-43EF-8865-95CDE99D5DC2}
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518} = {070FEF2B-0C3F-4F33-9D3C-53C7330BF518}
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32} = {CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C} = {200F3D3C-8B84-46D8-953A-6C0EBD283B5C}
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B} = {CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libiconv", "..\..\libiconv\SMP\libiconv.vcxproj", "{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libhogweed", "..\..\nettle\SMP\libhogweed.vcxproj", "{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2} = {02B94302-23D6-43EF-8865-95CDE99D5DC2}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnettle", "..\..\nettle\SMP\libnettle.vcxproj", "{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzlib", "..\..\zlib\SMP\libzlib.vcxproj", "{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MessagePack", "..\..\msgpack-c\msgpack_vc8.vcxproj", "{122A2EA4-B283-4241-9655-786DE78283B2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "argon", "argon.vcxproj", "{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6} = {36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blake", "blake.vcxproj", "{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{296E2989-CF09-43AC-BBD2-BCF1A4B56D07}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dhtnode", "dhtnode.vcxproj", "{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C} = {711397CE-E5D5-467D-9457-8716C047E50C}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dhtscanner", "dhtscanner.vcxproj", "{78443BCD-4689-4007-A246-F8F34B27F561}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C} = {711397CE-E5D5-467D-9457-8716C047E50C}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dhtchat", "dhtchat.vcxproj", "{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C} = {711397CE-E5D5-467D-9457-8716C047E50C}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
DebugDLL|x64 = DebugDLL|x64
|
||||
DebugDLL|x86 = DebugDLL|x86
|
||||
DebugDLLStaticDeps|x64 = DebugDLLStaticDeps|x64
|
||||
DebugDLLStaticDeps|x86 = DebugDLLStaticDeps|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
ReleaseDLL|x64 = ReleaseDLL|x64
|
||||
ReleaseDLL|x86 = ReleaseDLL|x86
|
||||
ReleaseDLLStaticDeps|x64 = ReleaseDLLStaticDeps|x64
|
||||
ReleaseDLLStaticDeps|x86 = ReleaseDLLStaticDeps|x86
|
||||
ReleaseLTO|x64 = ReleaseLTO|x64
|
||||
ReleaseLTO|x86 = ReleaseLTO|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x64.Build.0 = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Debug|x86.Build.0 = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x64.ActiveCfg = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x64.Build.0 = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x86.ActiveCfg = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLL|x86.Build.0 = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x64.ActiveCfg = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x64.Build.0 = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x86.ActiveCfg = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.Release|x86.Build.0 = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x64.ActiveCfg = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x64.Build.0 = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x86.ActiveCfg = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLL|x86.Build.0 = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x64.ActiveCfg = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x64.Build.0 = Release|x64
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x86.ActiveCfg = Release|Win32
|
||||
{711397CE-E5D5-467D-9457-8716C047E50C}.ReleaseLTO|x86.Build.0 = Release|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x64.Build.0 = Debug|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Debug|x86.Build.0 = Debug|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x64.ActiveCfg = Release|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x64.Build.0 = Release|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x86.ActiveCfg = Release|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.Release|x86.Build.0 = Release|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x64.Build.0 = Debug|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Debug|x86.Build.0 = Debug|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLLStaticDeps|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x64.Build.0 = DebugDLLStaticDeps|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLLStaticDeps|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.DebugDLLStaticDeps|x86.Build.0 = DebugDLLStaticDeps|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x64.ActiveCfg = Release|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x64.Build.0 = Release|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x86.ActiveCfg = Release|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.Release|x86.Build.0 = Release|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLLStaticDeps|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLLStaticDeps|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLLStaticDeps|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLLStaticDeps|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x64.Build.0 = Debug|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x64.ActiveCfg = Release|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x64.Build.0 = Release|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.Release|x86.Build.0 = Release|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x64.Build.0 = Debug|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Debug|x86.Build.0 = Debug|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLLStaticDeps|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x64.Build.0 = DebugDLLStaticDeps|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLLStaticDeps|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.DebugDLLStaticDeps|x86.Build.0 = DebugDLLStaticDeps|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x64.ActiveCfg = Release|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x64.Build.0 = Release|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x86.ActiveCfg = Release|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.Release|x86.Build.0 = Release|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLLStaticDeps|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLLStaticDeps|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLLStaticDeps|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLLStaticDeps|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x64.Build.0 = Debug|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Debug|x86.Build.0 = Debug|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x64.ActiveCfg = Release|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x64.Build.0 = Release|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x86.ActiveCfg = Release|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.Release|x86.Build.0 = Release|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x64.ActiveCfg = DebugDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x64.Build.0 = DebugDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLL|x86.Build.0 = DebugDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x64.ActiveCfg = DebugDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x64.Build.0 = DebugDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x86.ActiveCfg = DebugDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.DebugDLLStaticDeps|x86.Build.0 = DebugDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x64.Build.0 = Release|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.Release|x86.Build.0 = Release|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x64.ActiveCfg = ReleaseDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x64.Build.0 = ReleaseDLL|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x86.ActiveCfg = ReleaseDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseDLLStaticDeps|x86.Build.0 = ReleaseDLL|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x64.ActiveCfg = ReleaseLTO|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x64.Build.0 = ReleaseLTO|x64
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x86.ActiveCfg = ReleaseLTO|Win32
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}.ReleaseLTO|x86.Build.0 = ReleaseLTO|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Debug|x86.Build.0 = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x64.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x64.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x86.ActiveCfg = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLL|x86.Build.0 = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x64.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x64.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x64.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x86.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.Release|x86.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x64.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x64.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x86.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLL|x86.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x64.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x64.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x64.Build.0 = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x86.ActiveCfg = Release|Win32
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x86.Build.0 = Release|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Debug|x64.Build.0 = Debug|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Debug|x86.Build.0 = Debug|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLL|x64.ActiveCfg = Debug|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLL|x64.Build.0 = Debug|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLL|x86.ActiveCfg = Debug|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLL|x86.Build.0 = Debug|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Release|x64.Build.0 = Release|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Release|x86.ActiveCfg = Release|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Release|x86.Build.0 = Release|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLL|x64.ActiveCfg = Release|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLL|x64.Build.0 = Release|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLL|x86.ActiveCfg = Release|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLL|x86.Build.0 = Release|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseLTO|x64.ActiveCfg = Release|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseLTO|x64.Build.0 = Release|x64
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseLTO|x86.ActiveCfg = Release|Win32
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseLTO|x86.Build.0 = Release|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Debug|x64.Build.0 = Debug|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Debug|x86.Build.0 = Debug|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLL|x64.ActiveCfg = Debug|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLL|x64.Build.0 = Debug|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLL|x86.ActiveCfg = Debug|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLL|x86.Build.0 = Debug|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Release|x64.ActiveCfg = Release|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Release|x64.Build.0 = Release|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Release|x86.ActiveCfg = Release|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Release|x86.Build.0 = Release|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLL|x64.ActiveCfg = Release|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLL|x64.Build.0 = Release|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLL|x86.ActiveCfg = Release|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLL|x86.Build.0 = Release|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseLTO|x64.ActiveCfg = Release|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseLTO|x64.Build.0 = Release|x64
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseLTO|x86.ActiveCfg = Release|Win32
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseLTO|x86.Build.0 = Release|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Debug|x64.Build.0 = Debug|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Debug|x86.Build.0 = Debug|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLL|x64.ActiveCfg = Debug|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLL|x64.Build.0 = Debug|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLL|x86.ActiveCfg = Debug|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLL|x86.Build.0 = Debug|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Release|x64.ActiveCfg = Release|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Release|x64.Build.0 = Release|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Release|x86.ActiveCfg = Release|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Release|x86.Build.0 = Release|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLL|x64.ActiveCfg = Release|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLL|x64.Build.0 = Release|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLL|x86.ActiveCfg = Release|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLL|x86.Build.0 = Release|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseLTO|x64.ActiveCfg = Release|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseLTO|x64.Build.0 = Release|x64
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseLTO|x86.ActiveCfg = Release|Win32
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseLTO|x86.Build.0 = Release|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.Debug|x64.Build.0 = Debug|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.Debug|x86.Build.0 = Debug|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLL|x64.ActiveCfg = Debug|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLL|x64.Build.0 = Debug|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLL|x86.ActiveCfg = Debug|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLL|x86.Build.0 = Debug|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.Release|x64.ActiveCfg = Release|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.Release|x64.Build.0 = Release|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.Release|x86.ActiveCfg = Release|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.Release|x86.Build.0 = Release|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLL|x64.ActiveCfg = Release|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLL|x64.Build.0 = Release|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLL|x86.ActiveCfg = Release|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLL|x86.Build.0 = Release|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseLTO|x64.ActiveCfg = Release|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseLTO|x64.Build.0 = Release|x64
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseLTO|x86.ActiveCfg = Release|Win32
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseLTO|x86.Build.0 = Release|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Debug|x64.Build.0 = Debug|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Debug|x86.Build.0 = Debug|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLL|x64.ActiveCfg = Debug|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLL|x64.Build.0 = Debug|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLL|x86.ActiveCfg = Debug|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLL|x86.Build.0 = Debug|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Release|x64.ActiveCfg = Release|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Release|x64.Build.0 = Release|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Release|x86.ActiveCfg = Release|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Release|x86.Build.0 = Release|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLL|x64.ActiveCfg = Release|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLL|x64.Build.0 = Release|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLL|x86.ActiveCfg = Release|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLL|x86.Build.0 = Release|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseLTO|x64.ActiveCfg = Release|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseLTO|x64.Build.0 = Release|x64
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseLTO|x86.ActiveCfg = Release|Win32
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseLTO|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{02B94302-23D6-43EF-8865-95CDE99D5DC2} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
|
||||
{6F610EE8-7F59-4191-AB88-F63843267C02} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
|
||||
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
|
||||
{200F3D3C-8B84-46D8-953A-6C0EBD283B5C} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
|
||||
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
|
||||
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
|
||||
{122A2EA4-B283-4241-9655-786DE78283B2} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
|
||||
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
|
||||
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
|
||||
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5} = {296E2989-CF09-43AC-BBD2-BCF1A4B56D07}
|
||||
{78443BCD-4689-4007-A246-F8F34B27F561} = {296E2989-CF09-43AC-BBD2-BCF1A4B56D07}
|
||||
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA} = {296E2989-CF09-43AC-BBD2-BCF1A4B56D07}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,79 @@
|
||||
@ECHO OFF
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
SET UPSTREAMURL=https://github.com/ShiftMediaProject
|
||||
SET DEPENDENCIES=( ^
|
||||
gmp, ^
|
||||
gnutls, ^
|
||||
nettle ^
|
||||
)
|
||||
|
||||
SET PASSDEPENDENCIES=%~1
|
||||
|
||||
git status >NUL 2>&1
|
||||
IF %ERRORLEVEL% EQU 128 (
|
||||
git init
|
||||
) ELSE (
|
||||
IF %ERRORLEVEL% EQU 9009 (
|
||||
ECHO git not installed.
|
||||
EXIT /B 1
|
||||
)
|
||||
)
|
||||
|
||||
SET CURRDIR=%~dp1
|
||||
|
||||
cd ..\..
|
||||
set MSGPACK_VERSION=1df97bc37b363a340c5ad06c5cbcc53310aaff80
|
||||
set MSGPACK_URL="https://github.com/msgpack/msgpack-c.git"
|
||||
ECHO Cloning msgpack-c...
|
||||
git clone %MSGPACK_URL% --quiet
|
||||
cd msgpack-c
|
||||
git checkout %MSGPACK_VERSION%
|
||||
git apply --reject --whitespace=fix ..\opendht\MSVC\msgpack-msvc.patch
|
||||
cd ..
|
||||
|
||||
FOR %%I IN %DEPENDENCIES% DO (
|
||||
ECHO !PASSDEPENDENCIES! | FINDSTR /C:"%%I" >NUL 2>&1 || (
|
||||
CALL :cloneOrUpdateRepo "%%I" )
|
||||
)
|
||||
cd %CURRDIR% >NUL
|
||||
GOTO exit
|
||||
|
||||
:cloneOrUpdateRepo
|
||||
SET REPONAME=%~1
|
||||
IF NOT EXIST "%REPONAME%" (
|
||||
ECHO %REPONAME%: Existing folder not found. Cloning repository...
|
||||
SET REPOURL=%UPSTREAMURL%/%REPONAME%.git
|
||||
git clone !REPOURL! --quiet
|
||||
cd %REPONAME%
|
||||
git config --local core.autocrlf false
|
||||
git rm --cached -r . --quiet
|
||||
git reset --hard --quiet
|
||||
cd ..\
|
||||
)
|
||||
|
||||
SET PASSDEPENDENCIES=%PASSDEPENDENCIES% %REPONAME%
|
||||
|
||||
IF EXIST "%REPONAME%\SMP\project_get_dependencies.bat" (
|
||||
ECHO %REPONAME%: Found additional dependencies...
|
||||
ECHO.
|
||||
cd %REPONAME%\SMP
|
||||
project_get_dependencies.bat "!PASSDEPENDENCIES!" || GOTO exitOnError
|
||||
cd ..\..
|
||||
)
|
||||
ECHO.
|
||||
EXIT /B %ERRORLEVEL%
|
||||
|
||||
:exitOnError
|
||||
cd %CURRDIR%
|
||||
|
||||
:exit
|
||||
(
|
||||
ENDLOCAL
|
||||
SET PASSDEPENDENCIES=%PASSDEPENDENCIES%
|
||||
)
|
||||
|
||||
ECHO %CMDCMDLINE% | FINDSTR /L %COMSPEC% >NUL 2>&1
|
||||
IF %ERRORLEVEL% == 0 IF "%~1"=="" PAUSE
|
||||
|
||||
EXIT /B 0
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <process.h>
|
||||
#include <direct.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define R_OK 4
|
||||
#define W_OK 2
|
||||
#define F_OK 0
|
||||
|
||||
#ifndef STDIN_FILENO
|
||||
#define STDIN_FILENO 0
|
||||
#endif
|
||||
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
|
||||
#ifndef STDERR_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
#define srandom srand
|
||||
#define random rand
|
||||
|
||||
#define inline __inline
|
||||
typedef int mode_t;
|
||||
#include <BaseTsd.h>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,971 @@
|
||||
/* Getopt for Microsoft C
|
||||
This code is a modification of the Free Software Foundation, Inc.
|
||||
Getopt library for parsing command line argument the purpose was
|
||||
to provide a Microsoft Visual C friendly derivative. This code
|
||||
provides functionality for both Unicode and Multibyte builds.
|
||||
Date: 02/03/2011 - Ludvik Jerabek - Initial Release
|
||||
Version: 1.0
|
||||
Comment: Supports getopt, getopt_long, and getopt_long_only
|
||||
and POSIXLY_CORRECT environment flag
|
||||
License: LGPL
|
||||
Revisions:
|
||||
02/03/2011 - Ludvik Jerabek - Initial Release
|
||||
02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
|
||||
07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
|
||||
08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
|
||||
08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
|
||||
02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
|
||||
08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
|
||||
10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
|
||||
06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
|
||||
**DISCLAIMER**
|
||||
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
|
||||
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
|
||||
APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
|
||||
DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
|
||||
USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
|
||||
PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
|
||||
YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
|
||||
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include "wingetopt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define _GETOPT_THROW throw()
|
||||
#else
|
||||
#define _GETOPT_THROW
|
||||
#endif
|
||||
|
||||
int optind = 1;
|
||||
int opterr = 1;
|
||||
int optopt = '?';
|
||||
enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
|
||||
|
||||
//
|
||||
//
|
||||
// Ansi structures and functions follow
|
||||
//
|
||||
//
|
||||
|
||||
static struct _getopt_data_a
|
||||
{
|
||||
int optind;
|
||||
int opterr;
|
||||
int optopt;
|
||||
char *optarg;
|
||||
int __initialized;
|
||||
char *__nextchar;
|
||||
enum ENUM_ORDERING __ordering;
|
||||
int __posixly_correct;
|
||||
int __first_nonopt;
|
||||
int __last_nonopt;
|
||||
} getopt_data_a;
|
||||
char *optarg_a;
|
||||
|
||||
static void exchange_a(char **argv, struct _getopt_data_a *d)
|
||||
{
|
||||
int bottom = d->__first_nonopt;
|
||||
int middle = d->__last_nonopt;
|
||||
int top = d->optind;
|
||||
char *tem;
|
||||
while (top > middle && middle > bottom)
|
||||
{
|
||||
if (top - middle > middle - bottom)
|
||||
{
|
||||
int len = middle - bottom;
|
||||
register int i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
||||
argv[top - (middle - bottom) + i] = tem;
|
||||
}
|
||||
top -= len;
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = top - middle;
|
||||
register int i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[middle + i];
|
||||
argv[middle + i] = tem;
|
||||
}
|
||||
bottom += len;
|
||||
}
|
||||
}
|
||||
d->__first_nonopt += (d->optind - d->__last_nonopt);
|
||||
d->__last_nonopt = d->optind;
|
||||
}
|
||||
static const char *_getopt_initialize_a (const char *optstring, struct _getopt_data_a *d, int posixly_correct)
|
||||
{
|
||||
d->__first_nonopt = d->__last_nonopt = d->optind;
|
||||
d->__nextchar = NULL;
|
||||
d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT");
|
||||
if (optstring[0] == '-')
|
||||
{
|
||||
d->__ordering = RETURN_IN_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (optstring[0] == '+')
|
||||
{
|
||||
d->__ordering = REQUIRE_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (d->__posixly_correct)
|
||||
d->__ordering = REQUIRE_ORDER;
|
||||
else
|
||||
d->__ordering = PERMUTE;
|
||||
return optstring;
|
||||
}
|
||||
int _getopt_internal_r_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct)
|
||||
{
|
||||
int print_errors = d->opterr;
|
||||
if (argc < 1)
|
||||
return -1;
|
||||
d->optarg = NULL;
|
||||
if (d->optind == 0 || !d->__initialized)
|
||||
{
|
||||
if (d->optind == 0)
|
||||
d->optind = 1;
|
||||
optstring = _getopt_initialize_a (optstring, d, posixly_correct);
|
||||
d->__initialized = 1;
|
||||
}
|
||||
else if (optstring[0] == '-' || optstring[0] == '+')
|
||||
optstring++;
|
||||
if (optstring[0] == ':')
|
||||
print_errors = 0;
|
||||
if (d->__nextchar == NULL || *d->__nextchar == '\0')
|
||||
{
|
||||
if (d->__last_nonopt > d->optind)
|
||||
d->__last_nonopt = d->optind;
|
||||
if (d->__first_nonopt > d->optind)
|
||||
d->__first_nonopt = d->optind;
|
||||
if (d->__ordering == PERMUTE)
|
||||
{
|
||||
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
|
||||
exchange_a ((char **) argv, d);
|
||||
else if (d->__last_nonopt != d->optind)
|
||||
d->__first_nonopt = d->optind;
|
||||
while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
|
||||
d->optind++;
|
||||
d->__last_nonopt = d->optind;
|
||||
}
|
||||
if (d->optind != argc && !strcmp(argv[d->optind], "--"))
|
||||
{
|
||||
d->optind++;
|
||||
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
|
||||
exchange_a((char **) argv, d);
|
||||
else if (d->__first_nonopt == d->__last_nonopt)
|
||||
d->__first_nonopt = d->optind;
|
||||
d->__last_nonopt = argc;
|
||||
d->optind = argc;
|
||||
}
|
||||
if (d->optind == argc)
|
||||
{
|
||||
if (d->__first_nonopt != d->__last_nonopt)
|
||||
d->optind = d->__first_nonopt;
|
||||
return -1;
|
||||
}
|
||||
if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
|
||||
{
|
||||
if (d->__ordering == REQUIRE_ORDER)
|
||||
return -1;
|
||||
d->optarg = argv[d->optind++];
|
||||
return 1;
|
||||
}
|
||||
d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-'));
|
||||
}
|
||||
if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1])))))
|
||||
{
|
||||
char *nameend;
|
||||
unsigned int namelen;
|
||||
const struct option_a *p;
|
||||
const struct option_a *pfound = NULL;
|
||||
struct option_list
|
||||
{
|
||||
const struct option_a *p;
|
||||
struct option_list *next;
|
||||
} *ambig_list = NULL;
|
||||
int exact = 0;
|
||||
int indfound = -1;
|
||||
int option_index;
|
||||
for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++);
|
||||
namelen = (unsigned int)(nameend - d->__nextchar);
|
||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||
if (!strncmp(p->name, d->__nextchar, namelen))
|
||||
{
|
||||
if (namelen == (unsigned int)strlen(p->name))
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
|
||||
{
|
||||
struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
|
||||
newp->p = p;
|
||||
newp->next = ambig_list;
|
||||
ambig_list = newp;
|
||||
}
|
||||
}
|
||||
if (ambig_list != NULL && !exact)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
struct option_list first;
|
||||
first.p = pfound;
|
||||
first.next = ambig_list;
|
||||
ambig_list = &first;
|
||||
fprintf (stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
|
||||
do
|
||||
{
|
||||
fprintf (stderr, " '--%s'", ambig_list->p->name);
|
||||
ambig_list = ambig_list->next;
|
||||
}
|
||||
while (ambig_list != NULL);
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
d->__nextchar += strlen(d->__nextchar);
|
||||
d->optind++;
|
||||
d->optopt = 0;
|
||||
return '?';
|
||||
}
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
d->optind++;
|
||||
if (*nameend)
|
||||
{
|
||||
if (pfound->has_arg)
|
||||
d->optarg = nameend + 1;
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
if (argv[d->optind - 1][1] == '-')
|
||||
{
|
||||
fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
|
||||
}
|
||||
}
|
||||
d->__nextchar += strlen(d->__nextchar);
|
||||
d->optopt = pfound->val;
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (d->optind < argc)
|
||||
d->optarg = argv[d->optind++];
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fprintf(stderr,"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
|
||||
}
|
||||
d->__nextchar += strlen(d->__nextchar);
|
||||
d->optopt = pfound->val;
|
||||
return optstring[0] == ':' ? ':' : '?';
|
||||
}
|
||||
}
|
||||
d->__nextchar += strlen(d->__nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
if (argv[d->optind][1] == '-')
|
||||
{
|
||||
fprintf(stderr, "%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
|
||||
}
|
||||
}
|
||||
d->__nextchar = (char *)"";
|
||||
d->optind++;
|
||||
d->optopt = 0;
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
{
|
||||
char c = *d->__nextchar++;
|
||||
char *temp = (char*)strchr(optstring, c);
|
||||
if (*d->__nextchar == '\0')
|
||||
++d->optind;
|
||||
if (temp == NULL || c == ':' || c == ';')
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c);
|
||||
}
|
||||
d->optopt = c;
|
||||
return '?';
|
||||
}
|
||||
if (temp[0] == 'W' && temp[1] == ';')
|
||||
{
|
||||
char *nameend;
|
||||
const struct option_a *p;
|
||||
const struct option_a *pfound = NULL;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
int indfound = 0;
|
||||
int option_index;
|
||||
if (longopts == NULL)
|
||||
goto no_longs;
|
||||
if (*d->__nextchar != '\0')
|
||||
{
|
||||
d->optarg = d->__nextchar;
|
||||
d->optind++;
|
||||
}
|
||||
else if (d->optind == argc)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
|
||||
}
|
||||
d->optopt = c;
|
||||
if (optstring[0] == ':')
|
||||
c = ':';
|
||||
else
|
||||
c = '?';
|
||||
return c;
|
||||
}
|
||||
else
|
||||
d->optarg = argv[d->optind++];
|
||||
for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++);
|
||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||
if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar))
|
||||
{
|
||||
if ((unsigned int) (nameend - d->__nextchar) == strlen(p->name))
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
|
||||
ambig = 1;
|
||||
}
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fprintf(stderr, "%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
|
||||
}
|
||||
d->__nextchar += strlen(d->__nextchar);
|
||||
d->optind++;
|
||||
return '?';
|
||||
}
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
if (*nameend)
|
||||
{
|
||||
if (pfound->has_arg)
|
||||
d->optarg = nameend + 1;
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
|
||||
}
|
||||
d->__nextchar += strlen(d->__nextchar);
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (d->optind < argc)
|
||||
d->optarg = argv[d->optind++];
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fprintf(stderr, "%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
|
||||
}
|
||||
d->__nextchar += strlen(d->__nextchar);
|
||||
return optstring[0] == ':' ? ':' : '?';
|
||||
}
|
||||
}
|
||||
else
|
||||
d->optarg = NULL;
|
||||
d->__nextchar += strlen(d->__nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
no_longs:
|
||||
d->__nextchar = NULL;
|
||||
return 'W';
|
||||
}
|
||||
if (temp[1] == ':')
|
||||
{
|
||||
if (temp[2] == ':')
|
||||
{
|
||||
if (*d->__nextchar != '\0')
|
||||
{
|
||||
d->optarg = d->__nextchar;
|
||||
d->optind++;
|
||||
}
|
||||
else
|
||||
d->optarg = NULL;
|
||||
d->__nextchar = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*d->__nextchar != '\0')
|
||||
{
|
||||
d->optarg = d->__nextchar;
|
||||
d->optind++;
|
||||
}
|
||||
else if (d->optind == argc)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
|
||||
}
|
||||
d->optopt = c;
|
||||
if (optstring[0] == ':')
|
||||
c = ':';
|
||||
else
|
||||
c = '?';
|
||||
}
|
||||
else
|
||||
d->optarg = argv[d->optind++];
|
||||
d->__nextchar = NULL;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
int _getopt_internal_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct)
|
||||
{
|
||||
int result;
|
||||
getopt_data_a.optind = optind;
|
||||
getopt_data_a.opterr = opterr;
|
||||
result = _getopt_internal_r_a (argc, argv, optstring, longopts,longind, long_only, &getopt_data_a,posixly_correct);
|
||||
optind = getopt_data_a.optind;
|
||||
optarg_a = getopt_data_a.optarg;
|
||||
optopt = getopt_data_a.optopt;
|
||||
return result;
|
||||
}
|
||||
int getopt_a (int argc, char *const *argv, const char *optstring) _GETOPT_THROW
|
||||
{
|
||||
return _getopt_internal_a (argc, argv, optstring, (const struct option_a *) 0, (int *) 0, 0, 0);
|
||||
}
|
||||
int getopt_long_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
|
||||
{
|
||||
return _getopt_internal_a (argc, argv, options, long_options, opt_index, 0, 0);
|
||||
}
|
||||
int getopt_long_only_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
|
||||
{
|
||||
return _getopt_internal_a (argc, argv, options, long_options, opt_index, 1, 0);
|
||||
}
|
||||
int _getopt_long_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
|
||||
{
|
||||
return _getopt_internal_r_a (argc, argv, options, long_options, opt_index,0, d, 0);
|
||||
}
|
||||
int _getopt_long_only_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
|
||||
{
|
||||
return _getopt_internal_r_a (argc, argv, options, long_options, opt_index, 1, d, 0);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Unicode Structures and Functions
|
||||
//
|
||||
//
|
||||
|
||||
static struct _getopt_data_w
|
||||
{
|
||||
int optind;
|
||||
int opterr;
|
||||
int optopt;
|
||||
wchar_t *optarg;
|
||||
int __initialized;
|
||||
wchar_t *__nextchar;
|
||||
enum ENUM_ORDERING __ordering;
|
||||
int __posixly_correct;
|
||||
int __first_nonopt;
|
||||
int __last_nonopt;
|
||||
} getopt_data_w;
|
||||
wchar_t *optarg_w;
|
||||
|
||||
static void exchange_w(wchar_t **argv, struct _getopt_data_w *d)
|
||||
{
|
||||
int bottom = d->__first_nonopt;
|
||||
int middle = d->__last_nonopt;
|
||||
int top = d->optind;
|
||||
wchar_t *tem;
|
||||
while (top > middle && middle > bottom)
|
||||
{
|
||||
if (top - middle > middle - bottom)
|
||||
{
|
||||
int len = middle - bottom;
|
||||
register int i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
||||
argv[top - (middle - bottom) + i] = tem;
|
||||
}
|
||||
top -= len;
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = top - middle;
|
||||
register int i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[middle + i];
|
||||
argv[middle + i] = tem;
|
||||
}
|
||||
bottom += len;
|
||||
}
|
||||
}
|
||||
d->__first_nonopt += (d->optind - d->__last_nonopt);
|
||||
d->__last_nonopt = d->optind;
|
||||
}
|
||||
static const wchar_t *_getopt_initialize_w (const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct)
|
||||
{
|
||||
d->__first_nonopt = d->__last_nonopt = d->optind;
|
||||
d->__nextchar = NULL;
|
||||
d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT");
|
||||
if (optstring[0] == L'-')
|
||||
{
|
||||
d->__ordering = RETURN_IN_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (optstring[0] == L'+')
|
||||
{
|
||||
d->__ordering = REQUIRE_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (d->__posixly_correct)
|
||||
d->__ordering = REQUIRE_ORDER;
|
||||
else
|
||||
d->__ordering = PERMUTE;
|
||||
return optstring;
|
||||
}
|
||||
int _getopt_internal_r_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct)
|
||||
{
|
||||
int print_errors = d->opterr;
|
||||
if (argc < 1)
|
||||
return -1;
|
||||
d->optarg = NULL;
|
||||
if (d->optind == 0 || !d->__initialized)
|
||||
{
|
||||
if (d->optind == 0)
|
||||
d->optind = 1;
|
||||
optstring = _getopt_initialize_w (optstring, d, posixly_correct);
|
||||
d->__initialized = 1;
|
||||
}
|
||||
else if (optstring[0] == L'-' || optstring[0] == L'+')
|
||||
optstring++;
|
||||
if (optstring[0] == L':')
|
||||
print_errors = 0;
|
||||
if (d->__nextchar == NULL || *d->__nextchar == L'\0')
|
||||
{
|
||||
if (d->__last_nonopt > d->optind)
|
||||
d->__last_nonopt = d->optind;
|
||||
if (d->__first_nonopt > d->optind)
|
||||
d->__first_nonopt = d->optind;
|
||||
if (d->__ordering == PERMUTE)
|
||||
{
|
||||
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
|
||||
exchange_w((wchar_t **) argv, d);
|
||||
else if (d->__last_nonopt != d->optind)
|
||||
d->__first_nonopt = d->optind;
|
||||
while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
|
||||
d->optind++;
|
||||
d->__last_nonopt = d->optind;
|
||||
}
|
||||
if (d->optind != argc && !wcscmp(argv[d->optind], L"--"))
|
||||
{
|
||||
d->optind++;
|
||||
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
|
||||
exchange_w((wchar_t **) argv, d);
|
||||
else if (d->__first_nonopt == d->__last_nonopt)
|
||||
d->__first_nonopt = d->optind;
|
||||
d->__last_nonopt = argc;
|
||||
d->optind = argc;
|
||||
}
|
||||
if (d->optind == argc)
|
||||
{
|
||||
if (d->__first_nonopt != d->__last_nonopt)
|
||||
d->optind = d->__first_nonopt;
|
||||
return -1;
|
||||
}
|
||||
if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
|
||||
{
|
||||
if (d->__ordering == REQUIRE_ORDER)
|
||||
return -1;
|
||||
d->optarg = argv[d->optind++];
|
||||
return 1;
|
||||
}
|
||||
d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-'));
|
||||
}
|
||||
if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1])))))
|
||||
{
|
||||
wchar_t *nameend;
|
||||
unsigned int namelen;
|
||||
const struct option_w *p;
|
||||
const struct option_w *pfound = NULL;
|
||||
struct option_list
|
||||
{
|
||||
const struct option_w *p;
|
||||
struct option_list *next;
|
||||
} *ambig_list = NULL;
|
||||
int exact = 0;
|
||||
int indfound = -1;
|
||||
int option_index;
|
||||
for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++);
|
||||
namelen = (unsigned int)(nameend - d->__nextchar);
|
||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||
if (!wcsncmp(p->name, d->__nextchar, namelen))
|
||||
{
|
||||
if (namelen == (unsigned int)wcslen(p->name))
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
|
||||
{
|
||||
struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
|
||||
newp->p = p;
|
||||
newp->next = ambig_list;
|
||||
ambig_list = newp;
|
||||
}
|
||||
}
|
||||
if (ambig_list != NULL && !exact)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
struct option_list first;
|
||||
first.p = pfound;
|
||||
first.next = ambig_list;
|
||||
ambig_list = &first;
|
||||
fwprintf(stderr, L"%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
|
||||
do
|
||||
{
|
||||
fwprintf (stderr, L" '--%s'", ambig_list->p->name);
|
||||
ambig_list = ambig_list->next;
|
||||
}
|
||||
while (ambig_list != NULL);
|
||||
fputwc (L'\n', stderr);
|
||||
}
|
||||
d->__nextchar += wcslen(d->__nextchar);
|
||||
d->optind++;
|
||||
d->optopt = 0;
|
||||
return L'?';
|
||||
}
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
d->optind++;
|
||||
if (*nameend)
|
||||
{
|
||||
if (pfound->has_arg)
|
||||
d->optarg = nameend + 1;
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
if (argv[d->optind - 1][1] == L'-')
|
||||
{
|
||||
fwprintf(stderr, L"%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
fwprintf(stderr, L"%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
|
||||
}
|
||||
}
|
||||
d->__nextchar += wcslen(d->__nextchar);
|
||||
d->optopt = pfound->val;
|
||||
return L'?';
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (d->optind < argc)
|
||||
d->optarg = argv[d->optind++];
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fwprintf(stderr,L"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
|
||||
}
|
||||
d->__nextchar += wcslen(d->__nextchar);
|
||||
d->optopt = pfound->val;
|
||||
return optstring[0] == L':' ? L':' : L'?';
|
||||
}
|
||||
}
|
||||
d->__nextchar += wcslen(d->__nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
if (argv[d->optind][1] == L'-')
|
||||
{
|
||||
fwprintf(stderr, L"%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
|
||||
}
|
||||
else
|
||||
{
|
||||
fwprintf(stderr, L"%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
|
||||
}
|
||||
}
|
||||
d->__nextchar = (wchar_t *)L"";
|
||||
d->optind++;
|
||||
d->optopt = 0;
|
||||
return L'?';
|
||||
}
|
||||
}
|
||||
{
|
||||
wchar_t c = *d->__nextchar++;
|
||||
wchar_t *temp = (wchar_t*)wcschr(optstring, c);
|
||||
if (*d->__nextchar == L'\0')
|
||||
++d->optind;
|
||||
if (temp == NULL || c == L':' || c == L';')
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c);
|
||||
}
|
||||
d->optopt = c;
|
||||
return L'?';
|
||||
}
|
||||
if (temp[0] == L'W' && temp[1] == L';')
|
||||
{
|
||||
wchar_t *nameend;
|
||||
const struct option_w *p;
|
||||
const struct option_w *pfound = NULL;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
int indfound = 0;
|
||||
int option_index;
|
||||
if (longopts == NULL)
|
||||
goto no_longs;
|
||||
if (*d->__nextchar != L'\0')
|
||||
{
|
||||
d->optarg = d->__nextchar;
|
||||
d->optind++;
|
||||
}
|
||||
else if (d->optind == argc)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c);
|
||||
}
|
||||
d->optopt = c;
|
||||
if (optstring[0] == L':')
|
||||
c = L':';
|
||||
else
|
||||
c = L'?';
|
||||
return c;
|
||||
}
|
||||
else
|
||||
d->optarg = argv[d->optind++];
|
||||
for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++);
|
||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||
if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
|
||||
{
|
||||
if ((unsigned int) (nameend - d->__nextchar) == wcslen(p->name))
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
|
||||
ambig = 1;
|
||||
}
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fwprintf(stderr, L"%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
|
||||
}
|
||||
d->__nextchar += wcslen(d->__nextchar);
|
||||
d->optind++;
|
||||
return L'?';
|
||||
}
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
if (*nameend)
|
||||
{
|
||||
if (pfound->has_arg)
|
||||
d->optarg = nameend + 1;
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fwprintf(stderr, L"%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
|
||||
}
|
||||
d->__nextchar += wcslen(d->__nextchar);
|
||||
return L'?';
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (d->optind < argc)
|
||||
d->optarg = argv[d->optind++];
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fwprintf(stderr, L"%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
|
||||
}
|
||||
d->__nextchar += wcslen(d->__nextchar);
|
||||
return optstring[0] == L':' ? L':' : L'?';
|
||||
}
|
||||
}
|
||||
else
|
||||
d->optarg = NULL;
|
||||
d->__nextchar += wcslen(d->__nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
no_longs:
|
||||
d->__nextchar = NULL;
|
||||
return L'W';
|
||||
}
|
||||
if (temp[1] == L':')
|
||||
{
|
||||
if (temp[2] == L':')
|
||||
{
|
||||
if (*d->__nextchar != L'\0')
|
||||
{
|
||||
d->optarg = d->__nextchar;
|
||||
d->optind++;
|
||||
}
|
||||
else
|
||||
d->optarg = NULL;
|
||||
d->__nextchar = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*d->__nextchar != L'\0')
|
||||
{
|
||||
d->optarg = d->__nextchar;
|
||||
d->optind++;
|
||||
}
|
||||
else if (d->optind == argc)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c);
|
||||
}
|
||||
d->optopt = c;
|
||||
if (optstring[0] == L':')
|
||||
c = L':';
|
||||
else
|
||||
c = L'?';
|
||||
}
|
||||
else
|
||||
d->optarg = argv[d->optind++];
|
||||
d->__nextchar = NULL;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
int _getopt_internal_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct)
|
||||
{
|
||||
int result;
|
||||
getopt_data_w.optind = optind;
|
||||
getopt_data_w.opterr = opterr;
|
||||
result = _getopt_internal_r_w (argc, argv, optstring, longopts,longind, long_only, &getopt_data_w,posixly_correct);
|
||||
optind = getopt_data_w.optind;
|
||||
optarg_w = getopt_data_w.optarg;
|
||||
optopt = getopt_data_w.optopt;
|
||||
return result;
|
||||
}
|
||||
int getopt_w (int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW
|
||||
{
|
||||
return _getopt_internal_w (argc, argv, optstring, (const struct option_w *) 0, (int *) 0, 0, 0);
|
||||
}
|
||||
int getopt_long_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
|
||||
{
|
||||
return _getopt_internal_w (argc, argv, options, long_options, opt_index, 0, 0);
|
||||
}
|
||||
int getopt_long_only_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
|
||||
{
|
||||
return _getopt_internal_w (argc, argv, options, long_options, opt_index, 1, 0);
|
||||
}
|
||||
int _getopt_long_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
|
||||
{
|
||||
return _getopt_internal_r_w (argc, argv, options, long_options, opt_index,0, d, 0);
|
||||
}
|
||||
int _getopt_long_only_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
|
||||
{
|
||||
return _getopt_internal_r_w (argc, argv, options, long_options, opt_index, 1, d, 0);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#ifndef __WINGETOPT_H_
|
||||
#define __WINGETOPT_H_
|
||||
|
||||
#ifdef _GETOPT_API
|
||||
#undef _GETOPT_API
|
||||
#endif
|
||||
|
||||
#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT)
|
||||
#error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually"
|
||||
#elif defined(STATIC_GETOPT)
|
||||
#define _GETOPT_API
|
||||
#elif defined(EXPORTS_GETOPT)
|
||||
#define _GETOPT_API __declspec(dllexport)
|
||||
#else
|
||||
#define _GETOPT_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
// Change behavior for C\C++
|
||||
#ifdef __cplusplus
|
||||
#define _BEGIN_EXTERN_C extern "C" {
|
||||
#define _END_EXTERN_C }
|
||||
#define _GETOPT_THROW throw()
|
||||
#else
|
||||
#define _BEGIN_EXTERN_C
|
||||
#define _END_EXTERN_C
|
||||
#define _GETOPT_THROW
|
||||
#endif
|
||||
|
||||
// Standard GNU options
|
||||
#define null_argument 0 /*Argument Null*/
|
||||
#define no_argument 0 /*Argument Switch Only*/
|
||||
#define required_argument 1 /*Argument Required*/
|
||||
#define optional_argument 2 /*Argument Optional*/
|
||||
|
||||
|
||||
// Shorter Options
|
||||
#define ARG_NULL 0 /*Argument Null*/
|
||||
#define ARG_NONE 0 /*Argument Switch Only*/
|
||||
#define ARG_REQ 1 /*Argument Required*/
|
||||
#define ARG_OPT 2 /*Argument Optional*/
|
||||
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
_BEGIN_EXTERN_C
|
||||
|
||||
extern _GETOPT_API int optind;
|
||||
extern _GETOPT_API int opterr;
|
||||
extern _GETOPT_API int optopt;
|
||||
|
||||
// Ansi
|
||||
struct option_a
|
||||
{
|
||||
const char* name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
extern _GETOPT_API char *optarg_a;
|
||||
extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW;
|
||||
extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
|
||||
extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
|
||||
|
||||
// Unicode
|
||||
struct option_w
|
||||
{
|
||||
const wchar_t* name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
extern _GETOPT_API wchar_t *optarg_w;
|
||||
extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW;
|
||||
extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
|
||||
extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
|
||||
|
||||
_END_EXTERN_C
|
||||
|
||||
#undef _BEGIN_EXTERN_C
|
||||
#undef _END_EXTERN_C
|
||||
#undef _GETOPT_THROW
|
||||
#undef _GETOPT_API
|
||||
|
||||
#ifdef _UNICODE
|
||||
#define getopt getopt_w
|
||||
#define getopt_long getopt_long_w
|
||||
#define getopt_long_only getopt_long_only_w
|
||||
#define option option_w
|
||||
#define optarg optarg_w
|
||||
#else
|
||||
#define getopt getopt_a
|
||||
#define getopt_long getopt_long_a
|
||||
#define getopt_long_only getopt_long_only_a
|
||||
#define option option_a
|
||||
#define optarg optarg_a
|
||||
#endif
|
||||
#endif // __WINGETOPT_H_
|
||||
+1
-3
@@ -10,15 +10,13 @@ if USE_CYTHON
|
||||
SUBDIRS += python
|
||||
endif
|
||||
|
||||
if HAVE_DOXYGEN
|
||||
SUBDIRS += doc
|
||||
endif
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
DOC_FILES = \
|
||||
README.md \
|
||||
LICENSE
|
||||
COPYING
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(DOC_FILES)
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
OpenDHT
|
||||
===
|
||||
<img src="https://raw.githubusercontent.com/savoirfairelinux/opendht/master/resources/opendht_logo_512.png" width="100" align="right">
|
||||
<br>
|
||||
<h1 style="margin-top:10px">
|
||||
<a id="user-content-opendht-" class="anchor" href="/savoirfairelinux/opendht/blob/master/README.md#opendht-" aria-hidden="true"></a>OpenDHT
|
||||
</h1>
|
||||
|
||||
A lightweight C++11 Distributed Hash Table implementation originally based on https://github.com/jech/dht by Juliusz Chroboczek.
|
||||
|
||||
* Light and fast C++11 Kademlia DHT library.
|
||||
* Distributed shared key->value data-store
|
||||
* Clean and powerfull distributed map API with storage of arbitrary binary values of up to 56 KB.
|
||||
* Clean and powerful distributed map API with storage of arbitrary binary values of up to 56 KB.
|
||||
* Optional public key cryptography layer providing data signature and encryption (using GnuTLS).
|
||||
* IPv4 and IPv6 support.
|
||||
* Python binding.
|
||||
|
||||
Documentation
|
||||
-
|
||||
## Documentation
|
||||
See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
|
||||
|
||||
#### How-to build and install
|
||||
@@ -22,8 +25,7 @@ Build instructions : <https://github.com/savoirfairelinux/opendht/wiki/Build-the
|
||||
g++ main.cpp -std=c++11 -lopendht -lgnutls
|
||||
```
|
||||
|
||||
Examples
|
||||
-
|
||||
## 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.
|
||||
@@ -85,21 +87,27 @@ for r in results:
|
||||
print(r)
|
||||
```
|
||||
|
||||
Dependencies
|
||||
-
|
||||
## Dependencies
|
||||
- msgpack-c 1.2+, used for data serialization.
|
||||
- GnuTLS 3.1+, used for cryptographic operations.
|
||||
- GnuTLS 3.3+, used for cryptographic operations.
|
||||
- Nettle 2.4+, a GnuTLS dependency for crypto.
|
||||
- Build tested with GCC 4.8+ (GNU/Linux, Android, Windows with MinGW), Clang/LLVM (Linux, OS X).
|
||||
- Build tested with Microsoft Visual Studio 2015
|
||||
|
||||
Licence
|
||||
-
|
||||
Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
## Contact
|
||||
|
||||
Licenced under the GNU General Public License version 3 (see COPYING for the full licence).
|
||||
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
|
||||
|
||||
## Licence
|
||||
Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
|
||||
OpenDHT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
See COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html for the full GPLv3 licence.
|
||||
|
||||
This project is independent from another project called OpenDHT (Sean Rhea. Ph.D. Thesis, 2005), now extinct.
|
||||
|
||||
Donations
|
||||
-
|
||||
## Donations
|
||||
We gratefully accept Bitcoin donations to support OpenDHT development at: `bitcoin:3EykSd1An888efq4Bq3KaV3hJ3JQ4FPnwm`.
|
||||
+32
-13
@@ -1,24 +1,43 @@
|
||||
AC_INIT(opendht, 0.6.1)
|
||||
dnl define macros
|
||||
m4_define([opendht_major_version], 1)
|
||||
m4_define([opendht_minor_version], 3)
|
||||
m4_define([opendht_patch_version], 0)
|
||||
m4_define([opendht_version],
|
||||
[opendht_major_version.opendht_minor_version.opendht_patch_version])
|
||||
|
||||
AC_INIT(opendht, [opendht_version])
|
||||
AC_CONFIG_AUX_DIR(ac)
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
AC_SUBST(OPENDHT_MAJOR_VERSION, opendht_major_version)
|
||||
AC_SUBST(OPENDHT_MINOR_VERSION, opendht_minor_version)
|
||||
AC_SUBST(OPENDHT_PATCH_VERSION, opendht_patch_version)
|
||||
|
||||
AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [Build in debug mode, adds stricter warnings, disables optimization]))
|
||||
AS_IF([test "x$enable_debug" = "xyes"],
|
||||
[CXXFLAGS="${CXXFLAGS} -g -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -O0"],
|
||||
[CXXFLAGS="${CXXFLAGS} -O3"])
|
||||
[CXXFLAGS="${CXXFLAGS} -g -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -O0 -pedantic-errors"],
|
||||
[CXXFLAGS="${CXXFLAGS} -O3 -pedantic-errors"])
|
||||
|
||||
AC_PROG_CXX
|
||||
AM_PROG_AR
|
||||
|
||||
dnl Check for logs
|
||||
AC_ARG_ENABLE([logs], [AS_HELP_STRING([--disable-logs], [Disble DHT logs])])
|
||||
AS_IF([test "x$enable_logs" != "xno"], [
|
||||
AC_DEFINE([OPENDHT_LOG], [true], [Define if DHT logs are enabled])
|
||||
], [
|
||||
AC_DEFINE([OPENDHT_LOG], [false], [Define if DHT logs are enabled])
|
||||
])
|
||||
|
||||
dnl Check for Doxygen
|
||||
AC_ARG_ENABLE([doc], [AS_HELP_STRING([--disable-doc], [Disable documentation generation (doxygen)])])
|
||||
AS_IF([test "x$enable_doc" != "xno"], [
|
||||
AC_ARG_ENABLE([doc], AS_HELP_STRING([--enable-doc], [Enable documentation generation (doxygen)]))
|
||||
AS_IF([test "x$enable_doc" = "xyes"], [
|
||||
AC_CHECK_PROGS([DOXYGEN], [doxygen])
|
||||
AS_IF([test -z "$DOXYGEN"],[AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])])
|
||||
])
|
||||
AS_IF([test -z "$DOXYGEN"], [AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])])
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
|
||||
|
||||
dnl Check for Python
|
||||
@@ -26,8 +45,8 @@ AC_ARG_ENABLE([python], [AS_HELP_STRING([--disable-python], [Disble python bindi
|
||||
AS_IF([test "x$enable_python" != "xno"], [
|
||||
AM_PATH_PYTHON([3.3],, [:])
|
||||
AS_IF([test -n "$PYTHON"],[
|
||||
AC_CHECK_PROGS([CYTHON], [cython3])
|
||||
AS_IF([test -z "$CYTHON"],[AC_MSG_WARN([Cython not found - continuing without python support])])
|
||||
echo 'import Cython' | $PYTHON
|
||||
AS_IF([test $? == 0],[CYTHON=yes],[AC_MSG_WARN([Cython not found - continuing without python support])])
|
||||
AC_CHECK_PROGS([PIP], [pip3])
|
||||
AS_IF([test -z "$PIP"],[AC_MSG_WARN([pip not found - continuing without python uninstall support])])
|
||||
])
|
||||
@@ -75,9 +94,9 @@ LT_LANG(C++)
|
||||
AX_CXX_COMPILE_STDCXX(11,[noext],[mandatory])
|
||||
|
||||
PKG_PROG_PKG_CONFIG()
|
||||
PKG_CHECK_MODULES([nettle], [nettle >= 2.4])
|
||||
PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.1])
|
||||
PKG_CHECK_MODULES([msgpack], [msgpack >= 1.2])
|
||||
PKG_CHECK_MODULES([Nettle], [nettle >= 2.4])
|
||||
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3])
|
||||
PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2])
|
||||
CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
|
||||
|
||||
AC_ARG_ENABLE([tools], AS_HELP_STRING([--disable-tools],[Disable tools (CLI DHT node)]),,build_tools=yes)
|
||||
@@ -88,7 +107,7 @@ AM_COND_IF([ENABLE_TOOLS], [
|
||||
])
|
||||
])
|
||||
|
||||
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])])
|
||||
AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])
|
||||
|
||||
dnl Configure setup.py if we build the python module
|
||||
AM_COND_IF([USE_CYTHON], [
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
if (OPENDHT_TOOLS)
|
||||
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dhtnode.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1)
|
||||
endif ()
|
||||
@@ -1,3 +1,6 @@
|
||||
dist_man1_MANS = dhtnode.1
|
||||
|
||||
if HAVE_DOXYGEN
|
||||
doxyfile.stamp:
|
||||
$(DOXYGEN) Doxyfile
|
||||
echo stamp > doxyfile.stamp
|
||||
@@ -7,3 +10,4 @@ CLEANFILES = doxyfile.stamp
|
||||
all-local: doxyfile.stamp
|
||||
clean-local:
|
||||
rm -rf $(top_srcdir)/doc/man $(top_srcdir)/doc/html
|
||||
endif
|
||||
Binary file not shown.
@@ -0,0 +1,142 @@
|
||||
\documentclass[11pt]{article}
|
||||
|
||||
\usepackage[utf8x]{inputenc}
|
||||
\usepackage[top=2cm,bottom=2cm]{geometry}
|
||||
|
||||
\usepackage{forloop}
|
||||
\newcounter{counter}
|
||||
|
||||
% maths
|
||||
\usepackage{amssymb}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{mathrsfs}
|
||||
\usepackage{shadethm}
|
||||
\usepackage{amsthm}
|
||||
\newshadetheorem{shadeDef}{Definition}[section]
|
||||
\newtheorem{remark}{Remark}[section]
|
||||
\renewcommand{\P}{\mathbb{P}}
|
||||
|
||||
\usepackage{float}
|
||||
\usepackage{booktabs}
|
||||
|
||||
\setlength{\parindent}{0ex}
|
||||
\setlength{\parskip}{0.5em}
|
||||
|
||||
\begin{document}
|
||||
\title{Annex 1: Probabilistic analysis of connectivity changes}
|
||||
\author{Adrien Béraud, Simon Désaulniers, Guillaume Roguez}
|
||||
\maketitle
|
||||
\pagestyle{empty}
|
||||
\begin{shadeDef}
|
||||
A node flagged as \emph{``expired''} by a node $n$ is a node which has not responded to any
|
||||
of $n$'s last three requests.
|
||||
\end{shadeDef}
|
||||
\begin{remark}
|
||||
An expired node will not be contacted before 10 minutes from its expiration time.
|
||||
\end{remark}
|
||||
|
||||
Let $N$ the DHT network, $n_0\in N$, a given node and the following probabilistic events:
|
||||
\begin{itemize}
|
||||
\item $A$: $\forall n \in N$ $n$ is unreachable by $n_0$, \emph{i.e.} $n_0$ lost connection
|
||||
with $N$;
|
||||
\item $B$: $S\subset N$, the nodes unreachable by $n_0$ with $k={|S|\over|N|}$;
|
||||
\item $C$: $m \le |N|$ nodes are flagged as ``expired''.
|
||||
\end{itemize}
|
||||
|
||||
We are interested in knowing $\P(A|C)$, \emph{i.e.} the probability of the event where $A$ occurs
|
||||
prior to $C$. From the above, we immediately get
|
||||
$$\left\{
|
||||
\begin{array}{ll}
|
||||
\P(C|A) & = 1\\
|
||||
\P(A) + \P(B) & = 1
|
||||
\end{array}
|
||||
\right.$$
|
||||
Also, the event $A|C$ can be abstracted as the urn problem of draw without replacement. Then,
|
||||
$$\P(C|B) = \prod_{i=0}^m \left[k|N| - i \over |N|\right] = \prod_{i=0}^m \left[k - { i \over |N| }\right]$$
|
||||
Furthermore, using Bayes' theroem we have
|
||||
\begin{align*}
|
||||
\P(A|C) & = { \P(C|A)\P(A) \over \P(C|A)\P(A) + \P(C|B)\P(B)}\\
|
||||
& = { \P(A) \over \P(A) + \P(C|B)\P(B) }\\
|
||||
& = { \P(A) \over \P(A) + \P(C|B)\left[1 - \P(A)\right] }\\
|
||||
\Rightarrow \forloop{counter}{0}{\value{counter} < 5}{\qquad}\quad \P(A) & =
|
||||
\P(A|C)\left[\P(A) + \P(C|B)\left(1 - \P(A)\right) \right] \\
|
||||
\Rightarrow \forloop{counter}{0}{\value{counter} < 2}{\qquad}\;\:\, \P(A)\left[{ 1 \over \P(A|C)} - 1\right] & =
|
||||
\P(C|B)\left(1 - \P(A)\right) \\
|
||||
\end{align*}
|
||||
Finally,
|
||||
\begin{equation}
|
||||
\label{eq:final}
|
||||
\left[{\P(A) \over 1 - \P(A)}\right]\left[{ 1 \over \P(A|C)} - 1\right] =
|
||||
\prod_{i=0}^m \left[k - { i \over |N| }\right]
|
||||
\end{equation}
|
||||
|
||||
From \eqref{eq:final}, we may set a plausible configuration $\{\P(A),\P(A|C),k,|N|\}$ letting us
|
||||
produce results such as in table \ref{tbl:k_1_2}, \ref{tbl:k_2_3} and \ref{tbl:k_3_4}.
|
||||
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\caption{The values for $m$ assuming $\P(A|C) \ge 0.95,\, k = {1 \over 2}$}
|
||||
\label{tbl:k_1_2}
|
||||
\begin{tabular}{lcccc}
|
||||
\toprule
|
||||
$|N| \diagdown \P(A)$ & ${1 \over 10 }$ & ${1 \over 100 }$ & ${1 \over 1000 }$ & ${1 \over 10000 }$\\
|
||||
\midrule
|
||||
$2^0$ & 1 & 1 & 1 & 1\\
|
||||
$2^1$ & 1 & 1 & 1 & 1\\
|
||||
$2^2$ & 2 & 2 & 2 & 2\\
|
||||
$2^3$ & 4 & 4 & 4 & 4\\
|
||||
$2^4$ & 5 & 6 & 7 & 8\\
|
||||
$2^5$ & 5 & 7 & 9 & 10\\
|
||||
$2^6$ & 6 & 9 & 11 & 13\\
|
||||
$2^7$ & 6 & 9 & 12 & 14\\
|
||||
$2^8$ & 7 & 10 & 13 & 16\\
|
||||
$2^9$ & 7 & 10 & 13 & 16\\
|
||||
$2^{10}$ & 7 & 10 & 13 & 17\\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\caption{The values for $m$ assuming $\P(A|C) \ge 0.95,\, k = {2 \over 3}$}
|
||||
\label{tbl:k_2_3}
|
||||
\begin{tabular}{lcccc}
|
||||
\toprule
|
||||
$|N| \diagdown \P(A)$ & ${1 \over 10 }$ & ${1 \over 100 }$ & ${1 \over 1000 }$ & ${1 \over 10000 }$\\
|
||||
\midrule
|
||||
$2^0$ & 1 & 1 & 1 & 1\\
|
||||
$2^1$ & 2 & 2 & 2 & 2\\
|
||||
$2^2$ & 3 & 3 & 4 & 4\\
|
||||
$2^3$ & 5 & 5 & 6 & 8\\
|
||||
$2^4$ & 6 & 8 & 9 & 10\\
|
||||
$2^5$ & 8 & 10 & 12 & 14\\
|
||||
$2^6$ & 9 & 13 & 16 & 18\\
|
||||
$2^7$ & 11 & 15 & 18 & 22\\
|
||||
$2^8$ & 11 & 16 & 21 & 25\\
|
||||
$2^9$ & 12 & 17 & 22 & 27\\
|
||||
$2^{10}$ & 12 & 18 & 23 & 28\\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\caption{The values for $m$ assuming $\P(A|C) \ge 0.95,\, k = {3 \over 4}$}
|
||||
\label{tbl:k_3_4}
|
||||
\begin{tabular}{lcccc}
|
||||
\toprule
|
||||
$|N| \diagdown \P(A)$ & ${1 \over 10 }$ & ${1 \over 100 }$ & ${1 \over 1000 }$ & ${1 \over 10000 }$\\
|
||||
\midrule
|
||||
$2^0$ & 1 & 1 & 1 & 1\\
|
||||
$2^1$ & 2 & 2 & 2 & 2\\
|
||||
$2^2$ & 3 & 3 & 3 & 3\\
|
||||
$2^3$ & 5 & 6 & 6 & 6\\
|
||||
$2^4$ & 7 & 9 & 10 & 11\\
|
||||
$2^5$ & 10 & 12 & 14 & 16\\
|
||||
$2^6$ & 12 & 16 & 19 & 22\\
|
||||
$2^7$ & 14 & 19 & 23 & 27\\
|
||||
$2^8$ & 15 & 21 & 27 & 32\\
|
||||
$2^9$ & 16 & 23 & 30 & 36\\
|
||||
$2^{10}$ & 17 & 24 & 31 & 38\\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
\end{document}
|
||||
@@ -0,0 +1,87 @@
|
||||
.TH DHTNODE 1 2016-07-29
|
||||
|
||||
.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]]
|
||||
|
||||
.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:
|
||||
|
||||
.EE
|
||||
h, help Print this help message.
|
||||
q, quit Quit the program.
|
||||
log Start/stop printing DHT logs.
|
||||
|
||||
Node information:
|
||||
ll Print basic information and stats about the current node.
|
||||
ls Print basic information about current searches.
|
||||
ld Print basic information about currenty stored values on this node.
|
||||
lr Print the full current routing table of this node
|
||||
|
||||
Operations on the DHT:
|
||||
b ip:port Ping potential node at given IP address/port.
|
||||
g [key] Get values at [key].
|
||||
l [key] Listen for value changes at [key].
|
||||
p [key] [str] Put string value at [key].
|
||||
s [key] [str] Put string value at [key], signed with our generated
|
||||
private key.
|
||||
e [key] [dest] [str] Put string value at [key], encrypted for [dest] with
|
||||
its public key (if found).
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
\fB-h\fP
|
||||
Prints some help.
|
||||
|
||||
.TP
|
||||
\fB-v\fP
|
||||
Enable the verbose mode (log to stdout by default)
|
||||
|
||||
.TP
|
||||
\fB-l\fP \fIlog_file\fP
|
||||
Write log to file instead of stdout
|
||||
|
||||
.TP
|
||||
\fB-i\fP
|
||||
Generate cryptographic identity for the node.
|
||||
|
||||
.TP
|
||||
\fB-d\fP
|
||||
Run the program in daemon mode (will fork in the background).
|
||||
|
||||
.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.
|
||||
|
||||
.TP
|
||||
\fB-b\fP \fIbootstrap_host\fP[:\fIport\fP]
|
||||
The program needs to be given a node to connect to the network. You use this
|
||||
option to provide the ip address of that node.
|
||||
|
||||
.SH AUTHORS
|
||||
.TP
|
||||
Program written by
|
||||
.IP \(bu
|
||||
.\}
|
||||
Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
.TP
|
||||
Man page written by
|
||||
.IP \(bu
|
||||
.\}
|
||||
Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
@@ -0,0 +1,6 @@
|
||||
FROM aberaud/opendht-deps
|
||||
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
RUN git clone https://github.com/savoirfairelinux/opendht.git \
|
||||
&& cd opendht && mkdir build && cd build \
|
||||
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On && make -j8 && make install \
|
||||
&& cd ../.. && rm -rf opendht
|
||||
@@ -0,0 +1,9 @@
|
||||
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 libgnutls-dev cython3 python3-dev python3-setuptools && apt-get clean
|
||||
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.0.0/msgpack-2.0.0.tar.gz \
|
||||
&& tar -xzf msgpack-2.0.0.tar.gz \
|
||||
&& cd msgpack-2.0.0 && 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.0.0 msgpack-2.0.0.tar.gz
|
||||
@@ -0,0 +1,13 @@
|
||||
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 libgnutls-dev cython3 python3-dev python3-setuptools \
|
||||
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
|
||||
ENV CC cc
|
||||
ENV CXX c++
|
||||
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.0.0/msgpack-2.0.0.tar.gz \
|
||||
&& tar -xzf msgpack-2.0.0.tar.gz \
|
||||
&& cd msgpack-2.0.0 && 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.0.0 msgpack-2.0.0.tar.gz
|
||||
@@ -0,0 +1,6 @@
|
||||
FROM aberaud/opendht-deps-llvm
|
||||
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
RUN git clone https://github.com/savoirfairelinux/opendht.git \
|
||||
&& cd opendht && mkdir build && cd build \
|
||||
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On && make -j8 && make install \
|
||||
&& cd ../.. && rm -rf opendht
|
||||
@@ -0,0 +1,6 @@
|
||||
FROM aberaud/opendht-deps
|
||||
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
COPY . /root/opendht
|
||||
RUN cd /root/opendht && mkdir build && cd build \
|
||||
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On .. && make -j8 && make install \
|
||||
&& cd ../.. && rm -rf opendht
|
||||
@@ -0,0 +1,6 @@
|
||||
FROM aberaud/opendht-deps-llvm
|
||||
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
COPY . /root/opendht
|
||||
RUN cd /root/opendht && mkdir build && cd build \
|
||||
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On .. && make -j8 && make install \
|
||||
&& cd ../.. && rm -rf opendht
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,3 +22,4 @@
|
||||
#include "opendht/dhtrunner.h"
|
||||
#include "opendht/log.h"
|
||||
#include "opendht/default_types.h"
|
||||
#include "opendht/indexation/pht.h"
|
||||
+49
-14
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -28,27 +29,62 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
class Node;
|
||||
struct Node;
|
||||
|
||||
/**
|
||||
* Current status of a DHT node.
|
||||
*/
|
||||
enum class NodeStatus {
|
||||
Disconnected, // 0 nodes
|
||||
Connecting, // 1+ nodes
|
||||
Connected // 1+ good nodes
|
||||
};
|
||||
|
||||
struct Config {
|
||||
InfoHash node_id;
|
||||
bool is_bootstrap;
|
||||
struct OPENDHT_PUBLIC NodeStats {
|
||||
unsigned good_nodes,
|
||||
dubious_nodes,
|
||||
cached_nodes,
|
||||
incoming_nodes;
|
||||
unsigned table_depth;
|
||||
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
|
||||
std::string toString() const;
|
||||
};
|
||||
|
||||
struct SecureDhtConfig
|
||||
/**
|
||||
* Dht configuration.
|
||||
*/
|
||||
struct OPENDHT_PUBLIC Config {
|
||||
/** DHT node ID */
|
||||
InfoHash node_id;
|
||||
|
||||
/**
|
||||
* DHT network ID. A node will only talk with other nodes having
|
||||
* the same network ID.
|
||||
* Network ID 0 (default) represents the main public network.
|
||||
*/
|
||||
NetId network;
|
||||
|
||||
/** For testing purposes only, enables bootstrap mode */
|
||||
bool is_bootstrap;
|
||||
|
||||
/** Makes the DHT responsible to maintain its stored values. Consumes more ressources. */
|
||||
bool maintain_storage;
|
||||
};
|
||||
|
||||
/**
|
||||
* SecureDht configuration.
|
||||
*/
|
||||
struct OPENDHT_PUBLIC SecureDhtConfig
|
||||
{
|
||||
Config node_config;
|
||||
crypto::Identity id;
|
||||
};
|
||||
|
||||
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
|
||||
|
||||
using ValuesExport = std::pair<InfoHash, Blob>;
|
||||
|
||||
using QueryCallback = std::function<bool(const std::vector<std::shared_ptr<FieldValueIndex>>& fields)>;
|
||||
using GetCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values)>;
|
||||
using GetCallbackSimple = std::function<bool(std::shared_ptr<Value> value)>;
|
||||
using ShutdownCallback = std::function<void()>;
|
||||
@@ -57,20 +93,19 @@ using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::
|
||||
|
||||
typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data);
|
||||
|
||||
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
|
||||
|
||||
GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
|
||||
GetCallback bindGetCb(GetCallbackSimple cb);
|
||||
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
|
||||
OPENDHT_PUBLIC GetCallback bindGetCb(GetCallbackSimple cb);
|
||||
|
||||
using DoneCallback = std::function<void(bool success, const std::vector<std::shared_ptr<Node>>& nodes)>;
|
||||
typedef void (*DoneCallbackRaw)(bool, std::vector<std::shared_ptr<Node>>*, void *user_data);
|
||||
typedef void (*ShutdownCallbackRaw)(void *user_data);
|
||||
typedef void (*DoneCallbackSimpleRaw)(bool, void *user_data);
|
||||
|
||||
using DoneCallbackSimple = std::function<void(bool success)>;
|
||||
|
||||
ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data);
|
||||
DoneCallback bindDoneCb(DoneCallbackSimple donecb);
|
||||
DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data);
|
||||
|
||||
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(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);
|
||||
|
||||
}
|
||||
+117
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 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,10 +31,14 @@ extern "C" {
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <iso646.h>
|
||||
#endif
|
||||
|
||||
namespace dht {
|
||||
namespace crypto {
|
||||
|
||||
class CryptoException : public std::runtime_error {
|
||||
class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
|
||||
public:
|
||||
CryptoException(const std::string& str) : std::runtime_error(str) {};
|
||||
};
|
||||
@@ -42,20 +46,21 @@ class CryptoException : public std::runtime_error {
|
||||
/**
|
||||
* Exception thrown when a decryption error happened.
|
||||
*/
|
||||
class DecryptError : public CryptoException {
|
||||
class OPENDHT_PUBLIC DecryptError : public CryptoException {
|
||||
public:
|
||||
DecryptError(const std::string& str = "") : CryptoException(str) {};
|
||||
};
|
||||
|
||||
struct PrivateKey;
|
||||
struct Certificate;
|
||||
class RevocationList;
|
||||
|
||||
using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certificate>>;
|
||||
|
||||
/**
|
||||
* A public key.
|
||||
*/
|
||||
struct PublicKey
|
||||
struct OPENDHT_PUBLIC PublicKey
|
||||
{
|
||||
PublicKey() {}
|
||||
|
||||
@@ -78,6 +83,7 @@ struct PublicKey
|
||||
PublicKey& operator=(PublicKey&& o) noexcept;
|
||||
|
||||
InfoHash getId() const;
|
||||
PkId getLongId() const;
|
||||
bool checkSignature(const Blob& data, const Blob& signature) const;
|
||||
Blob encrypt(const Blob&) const;
|
||||
|
||||
@@ -105,7 +111,7 @@ private:
|
||||
/**
|
||||
* A private key, including the corresponding public key.
|
||||
*/
|
||||
struct PrivateKey
|
||||
struct OPENDHT_PUBLIC PrivateKey
|
||||
{
|
||||
PrivateKey();
|
||||
//PrivateKey(gnutls_privkey_t k) : key(k) {}
|
||||
@@ -144,6 +150,7 @@ struct PrivateKey
|
||||
* Recommended values: 4096, 8192
|
||||
*/
|
||||
static PrivateKey generate(unsigned key_length = 4096);
|
||||
static PrivateKey generateEC();
|
||||
|
||||
gnutls_privkey_t key {};
|
||||
gnutls_x509_privkey_t x509_key {};
|
||||
@@ -155,7 +162,77 @@ private:
|
||||
//friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length);
|
||||
};
|
||||
|
||||
struct Certificate {
|
||||
|
||||
class OPENDHT_PUBLIC RevocationList
|
||||
{
|
||||
using clock = std::chrono::system_clock;
|
||||
using time_point = clock::time_point;
|
||||
using duration = clock::duration;
|
||||
public:
|
||||
RevocationList();
|
||||
RevocationList(const Blob& b);
|
||||
RevocationList(RevocationList&& o) : crl(o.crl) { o.crl = nullptr; }
|
||||
~RevocationList();
|
||||
|
||||
RevocationList& operator=(RevocationList&& o) { crl = o.crl; o.crl = nullptr; return *this; }
|
||||
|
||||
void pack(Blob& b) const;
|
||||
void unpack(const uint8_t* dat, size_t dat_size);
|
||||
Blob getPacked() const {
|
||||
Blob b;
|
||||
pack(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& p) const
|
||||
{
|
||||
Blob b = getPacked();
|
||||
p.pack_bin(b.size());
|
||||
p.pack_bin_body((const char*)b.data(), b.size());
|
||||
}
|
||||
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
|
||||
void revoke(const Certificate& crt, time_point t = time_point::min());
|
||||
|
||||
bool isRevoked(const Certificate& crt) const;
|
||||
|
||||
/**
|
||||
* Sign this revocation list using provided key and certificate.
|
||||
* Validity_period sets the duration until next update (default to no next update).
|
||||
*/
|
||||
void sign(const PrivateKey&, const Certificate&, duration validity_period = {});
|
||||
void sign(const Identity& id) { sign(*id.first, *id.second); }
|
||||
|
||||
bool isSignedBy(const Certificate& issuer) const;
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
/**
|
||||
* Read the CRL number extension field.
|
||||
*/
|
||||
Blob getNumber() const;
|
||||
|
||||
/** Read CRL issuer Common Name (CN) */
|
||||
std::string getIssuerName() const;
|
||||
|
||||
/** Read CRL issuer User ID (UID) */
|
||||
std::string getIssuerUID() const;
|
||||
|
||||
time_point getUpdateTime() const;
|
||||
time_point getNextUpdateTime() const;
|
||||
|
||||
gnutls_x509_crl_t get() { return crl; }
|
||||
|
||||
private:
|
||||
gnutls_x509_crl_t crl {};
|
||||
RevocationList(const RevocationList&) = delete;
|
||||
RevocationList& operator=(const RevocationList&) = delete;
|
||||
};
|
||||
|
||||
|
||||
struct OPENDHT_PUBLIC Certificate {
|
||||
Certificate() {}
|
||||
|
||||
/**
|
||||
@@ -274,6 +351,7 @@ struct Certificate {
|
||||
|
||||
/** Same as getPublicKey().getId() */
|
||||
InfoHash getId() const;
|
||||
PkId getLongId() const;
|
||||
|
||||
/** Read certificate Common Name (CN) */
|
||||
std::string getName() const;
|
||||
@@ -292,8 +370,11 @@ struct Certificate {
|
||||
/** Read certificate alternative names */
|
||||
std::vector<std::pair<NameType, std::string>> getAltNames() const;
|
||||
|
||||
std::chrono::system_clock::time_point getExpiration() const;
|
||||
|
||||
/**
|
||||
* Returns true if the certificate is marked as a Certificate Authority.
|
||||
* Returns true if the certificate is marked as a Certificate Authority
|
||||
* and has necessary key usage flags to sign certificates.
|
||||
*/
|
||||
bool isCA() const;
|
||||
|
||||
@@ -303,6 +384,13 @@ struct Certificate {
|
||||
*/
|
||||
std::string toString(bool chain = true) const;
|
||||
|
||||
std::string print() const;
|
||||
|
||||
void revoke(const PrivateKey&, const Certificate&);
|
||||
std::vector<std::shared_ptr<RevocationList>> getRevocationLists() const;
|
||||
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);
|
||||
|
||||
gnutls_x509_crt_t cert {};
|
||||
@@ -310,6 +398,14 @@ struct Certificate {
|
||||
private:
|
||||
Certificate(const Certificate&) = delete;
|
||||
Certificate& operator=(const Certificate&) = delete;
|
||||
|
||||
struct crlNumberCmp {
|
||||
bool operator() (const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const {
|
||||
return lhs->getNumber() < rhs->getNumber();
|
||||
}
|
||||
};
|
||||
|
||||
std::set<std::shared_ptr<RevocationList>, crlNumberCmp> revocation_lists;
|
||||
};
|
||||
|
||||
|
||||
@@ -320,14 +416,19 @@ private:
|
||||
* If not set, the generated certificate will be a self-signed CA.
|
||||
* @param key_length stength of the generated private key (bits).
|
||||
*/
|
||||
Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
|
||||
Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
|
||||
OPENDHT_PUBLIC Identity 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);
|
||||
|
||||
|
||||
/**
|
||||
* SHA512
|
||||
* Performs SHA512, SHA256 or SHA1, depending on hash_length.
|
||||
* Attempts to choose an hash function with
|
||||
* output size of at least hash_length bytes, Current implementation
|
||||
* will use SHA1 for hash_length up to 20 bytes,
|
||||
* will use SHA256 for hash_length up to 32 bytes,
|
||||
* will use SHA512 for hash_length of 33 bytes and more.
|
||||
*/
|
||||
Blob hash(const Blob& data);
|
||||
OPENDHT_PUBLIC Blob hash(const Blob& data, size_t hash_length = 512/8);
|
||||
|
||||
/**
|
||||
* Generates an encryption key from a text password,
|
||||
@@ -336,19 +437,19 @@ Blob hash(const Blob& data);
|
||||
* that can be transmitted in clear, and will be generated if
|
||||
* not provided (32 bytes).
|
||||
*/
|
||||
Blob stretchKey(const std::string& password, Blob& salt);
|
||||
OPENDHT_PUBLIC Blob stretchKey(const std::string& password, Blob& salt, size_t key_length = 512/8);
|
||||
|
||||
/**
|
||||
* AES-GCM encryption. Key must be 128, 192 or 256 bits long (16, 24 or 32 bytes).
|
||||
*/
|
||||
Blob aesEncrypt(const Blob& data, const Blob& key);
|
||||
Blob aesEncrypt(const Blob& data, const std::string& password);
|
||||
OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const Blob& key);
|
||||
OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password);
|
||||
|
||||
/**
|
||||
* AES-GCM decryption.
|
||||
*/
|
||||
Blob aesDecrypt(const Blob& data, const Blob& key);
|
||||
Blob aesDecrypt(const Blob& data, const std::string& password);
|
||||
OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key);
|
||||
OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
// Generic helper definitions for shared library support
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
#define OPENDTH_IMPORT __declspec(dllimport)
|
||||
#define OPENDHT_EXPORT __declspec(dllexport)
|
||||
#define OPENDHT_HIDDEN
|
||||
#else
|
||||
#define OPENDTH_IMPORT __attribute__ ((visibility ("default")))
|
||||
#define OPENDHT_EXPORT __attribute__ ((visibility ("default")))
|
||||
#define OPENDHT_HIDDEN __attribute__ ((visibility ("hidden")))
|
||||
#endif
|
||||
|
||||
// Now we use the generic helper definitions above to define OPENDHT_PUBLIC and OPENDHT_LOCAL.
|
||||
// OPENDHT_PUBLIC is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)
|
||||
// OPENDHT_LOCAL is used for non-api symbols.
|
||||
|
||||
#ifdef opendht_EXPORTS // defined if OpenDHT is compiled as a shared library
|
||||
#ifdef OPENDHT_BUILD // defined if we are building the OpenDHT shared library (instead of using it)
|
||||
#define OPENDHT_PUBLIC OPENDHT_EXPORT
|
||||
#else
|
||||
#define OPENDHT_PUBLIC OPENDTH_IMPORT
|
||||
#endif // OPENDHT_BUILD
|
||||
#define OPENDHT_LOCAL OPENDHT_HIDDEN
|
||||
#else // opendht_EXPORTS is not defined: this means OpenDHT is a static lib.
|
||||
#define OPENDHT_PUBLIC
|
||||
#define OPENDHT_LOCAL
|
||||
#endif // opendht_EXPORTS
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "value.h"
|
||||
|
||||
MSGPACK_ADD_ENUM(dht::Value::Field)
|
||||
|
||||
namespace dht {
|
||||
enum class ImStatus : uint8_t {
|
||||
NONE = 0,
|
||||
@@ -29,11 +31,11 @@ enum class ImStatus : uint8_t {
|
||||
READ
|
||||
};
|
||||
}
|
||||
MSGPACK_ADD_ENUM(dht::ImStatus);
|
||||
MSGPACK_ADD_ENUM(dht::ImStatus)
|
||||
|
||||
namespace dht {
|
||||
|
||||
class DhtMessage : public Value::Serializable<DhtMessage>
|
||||
class OPENDHT_PUBLIC DhtMessage : public Value::Serializable<DhtMessage>
|
||||
{
|
||||
public:
|
||||
static const ValueType TYPE;
|
||||
@@ -55,11 +57,11 @@ public:
|
||||
|
||||
std::string service;
|
||||
Blob data;
|
||||
MSGPACK_DEFINE(service, data);
|
||||
MSGPACK_DEFINE(service, data)
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SignedValue : public Value::Serializable<T>
|
||||
class OPENDHT_PUBLIC SignedValue : public Value::Serializable<T>
|
||||
{
|
||||
private:
|
||||
using BaseClass = Value::Serializable<T>;
|
||||
@@ -79,7 +81,7 @@ public:
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class EncryptedValue : public SignedValue<T>
|
||||
class OPENDHT_PUBLIC EncryptedValue : public SignedValue<T>
|
||||
{
|
||||
public:
|
||||
using BaseClass = SignedValue<T>;
|
||||
@@ -103,7 +105,7 @@ public:
|
||||
|
||||
|
||||
|
||||
class ImMessage : public SignedValue<ImMessage>
|
||||
class OPENDHT_PUBLIC ImMessage : public SignedValue<ImMessage>
|
||||
{
|
||||
private:
|
||||
using BaseClass = SignedValue<ImMessage>;
|
||||
@@ -126,10 +128,10 @@ public:
|
||||
long date {0};
|
||||
ImStatus status {ImStatus::NONE};
|
||||
|
||||
MSGPACK_DEFINE_MAP(id, msg, date, status);
|
||||
MSGPACK_DEFINE_MAP(id, msg, date, status)
|
||||
};
|
||||
|
||||
class TrustRequest : public EncryptedValue<TrustRequest>
|
||||
class OPENDHT_PUBLIC TrustRequest : public EncryptedValue<TrustRequest>
|
||||
{
|
||||
private:
|
||||
using BaseClass = EncryptedValue<TrustRequest>;
|
||||
@@ -147,10 +149,11 @@ public:
|
||||
|
||||
std::string service;
|
||||
Blob payload;
|
||||
MSGPACK_DEFINE(service, payload);
|
||||
bool confirm {false};
|
||||
MSGPACK_DEFINE_MAP(service, payload, confirm)
|
||||
};
|
||||
|
||||
class IceCandidates : public EncryptedValue<IceCandidates>
|
||||
class OPENDHT_PUBLIC IceCandidates : public EncryptedValue<IceCandidates>
|
||||
{
|
||||
private:
|
||||
using BaseClass = EncryptedValue<IceCandidates>;
|
||||
@@ -175,7 +178,7 @@ public:
|
||||
pk.pack_bin_body((const char*)ice_data.data(), ice_data.size());
|
||||
#else
|
||||
// hack for backward compatibility with old opendht compiled with msgpack 1.0
|
||||
// remove when enough people have moved to new versions
|
||||
// remove when enough people have moved to new versions
|
||||
pk.pack_array(ice_data.size());
|
||||
for (uint8_t b : ice_data)
|
||||
pk.pack(b);
|
||||
@@ -196,7 +199,7 @@ public:
|
||||
|
||||
/* "Peer" announcement
|
||||
*/
|
||||
class IpServiceAnnouncement : public Value::Serializable<IpServiceAnnouncement>
|
||||
class OPENDHT_PUBLIC IpServiceAnnouncement : public Value::Serializable<IpServiceAnnouncement>
|
||||
{
|
||||
private:
|
||||
using BaseClass = Value::Serializable<IpServiceAnnouncement>;
|
||||
@@ -271,8 +274,8 @@ private:
|
||||
};
|
||||
|
||||
|
||||
extern const std::array<std::reference_wrapper<const ValueType>, 5> DEFAULT_TYPES;
|
||||
OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 5> DEFAULT_TYPES;
|
||||
|
||||
extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_INSECURE_TYPES;
|
||||
OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_INSECURE_TYPES;
|
||||
|
||||
}
|
||||
+260
-155
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,11 +14,9 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "infohash.h"
|
||||
@@ -28,20 +26,24 @@
|
||||
#include "scheduler.h"
|
||||
#include "routing_table.h"
|
||||
#include "callbacks.h"
|
||||
#include "log_enable.h"
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <iso646.h>
|
||||
#endif
|
||||
|
||||
namespace dht {
|
||||
|
||||
namespace net {
|
||||
struct Request;
|
||||
} /* namespace net */
|
||||
|
||||
/**
|
||||
* Main Dht class.
|
||||
@@ -50,7 +52,7 @@ struct Request;
|
||||
* Must be given open UDP sockets and ::periodic must be
|
||||
* called regularly.
|
||||
*/
|
||||
class Dht {
|
||||
class OPENDHT_PUBLIC Dht {
|
||||
public:
|
||||
|
||||
// [[deprecated]]
|
||||
@@ -98,7 +100,14 @@ public:
|
||||
/**
|
||||
* Enable or disable logging of DHT internal messages
|
||||
*/
|
||||
void setLoggers(LogMethod&& error = NOLOG, LogMethod&& warn = NOLOG, LogMethod&& debug = NOLOG);
|
||||
void setLoggers(LogMethod error = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG);
|
||||
|
||||
/**
|
||||
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
|
||||
*/
|
||||
void setLogFilter(const InfoHash& f) {
|
||||
DHT_LOG.setFilter(f);
|
||||
}
|
||||
|
||||
virtual void registerType(const ValueType& type) {
|
||||
types[type.id] = type;
|
||||
@@ -113,14 +122,20 @@ public:
|
||||
* The node is not pinged, so this should be
|
||||
* used to bootstrap efficiently from previously known nodes.
|
||||
*/
|
||||
bool insertNode(const InfoHash& id, const sockaddr*, socklen_t);
|
||||
bool insertNode(const NodeExport& n) {
|
||||
return insertNode(n.id, reinterpret_cast<const sockaddr*>(&n.ss), n.sslen);
|
||||
void insertNode(const InfoHash& id, const SockAddr&);
|
||||
void insertNode(const InfoHash& id, const sockaddr* sa, socklen_t salen) {
|
||||
insertNode(id, SockAddr(sa, salen));
|
||||
}
|
||||
void insertNode(const NodeExport& n) {
|
||||
insertNode(n.id, SockAddr(n.ss, n.sslen));
|
||||
}
|
||||
|
||||
int pingNode(const sockaddr*, socklen_t);
|
||||
void pingNode(const sockaddr*, socklen_t, DoneCallbackSimple&& cb={});
|
||||
|
||||
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, const SockAddr&);
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) {
|
||||
return periodic(buf, buflen, SockAddr(from, fromlen));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value by searching on all available protocols (IPv4, IPv6),
|
||||
@@ -129,61 +144,90 @@ public:
|
||||
* @param cb a function called when new values are found on the network.
|
||||
* It should return false to stop the operation.
|
||||
* @param donecb a function called when the operation is complete.
|
||||
cb and donecb won't be called again afterward.
|
||||
cb and donecb won't be called again afterward.
|
||||
* @param f a filter function used to prefilter values.
|
||||
*/
|
||||
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={});
|
||||
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}) {
|
||||
get(key, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f));
|
||||
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {});
|
||||
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) {
|
||||
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={}) {
|
||||
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f));
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) {
|
||||
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={}) {
|
||||
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f));
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) {
|
||||
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
/**
|
||||
* Similar to Dht::get, but sends a Query to filter data remotely.
|
||||
* @param key the key for which to query data for.
|
||||
* @param cb a function called when new values are found on the network.
|
||||
* It should return false to stop the operation.
|
||||
* @param donecb a function called when the operation is complete.
|
||||
cb and donecb won't be called again afterward.
|
||||
* @param q a query used to filter values on the remotes before they send a
|
||||
* response.
|
||||
*/
|
||||
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {});
|
||||
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) {
|
||||
query(key, cb, bindDoneCb(done_cb), std::forward<Query>(q));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get locally stored data for the given hash.
|
||||
*/
|
||||
std::vector<std::shared_ptr<Value>> getLocal(const InfoHash& key, Value::Filter f = Value::AllFilter()) const;
|
||||
std::vector<Sp<Value>> getLocal(const InfoHash& key, Value::Filter f = Value::AllFilter()) const;
|
||||
|
||||
/**
|
||||
* Get locally stored data for the given key and value id.
|
||||
*/
|
||||
std::shared_ptr<Value> getLocalById(const InfoHash& key, Value::Id vid) const;
|
||||
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const;
|
||||
|
||||
/**
|
||||
* Announce a value on all available protocols (IPv4, IPv6), and
|
||||
* automatically re-announce when it's about to expire.
|
||||
* Announce a value on all available protocols (IPv4, IPv6).
|
||||
*
|
||||
* The operation will start as soon as the node is connected to the network.
|
||||
* The done callback will be called once, when the first announce succeeds, or fails.
|
||||
*
|
||||
* A "put" operation will never end by itself because the value will need to be
|
||||
* reannounced on a regular basis.
|
||||
* User can call #cancelPut(InfoHash, Value::Id) to cancel a put operation.
|
||||
*/
|
||||
void put(const InfoHash& key, std::shared_ptr<Value>, DoneCallback cb=nullptr, time_point created=time_point::max());
|
||||
void put(const InfoHash& key, const std::shared_ptr<Value>& v, DoneCallbackSimple cb, time_point created=time_point::max()) {
|
||||
put(key, v, bindDoneCb(cb), created);
|
||||
void put(const InfoHash& key,
|
||||
Sp<Value>,
|
||||
DoneCallback cb=nullptr,
|
||||
time_point created=time_point::max(),
|
||||
bool permanent = false);
|
||||
void put(const InfoHash& key,
|
||||
const Sp<Value>& v,
|
||||
DoneCallbackSimple cb,
|
||||
time_point created=time_point::max(),
|
||||
bool permanent = false)
|
||||
{
|
||||
put(key, v, bindDoneCb(cb), created, permanent);
|
||||
}
|
||||
|
||||
void put(const InfoHash& key, Value&& v, DoneCallback cb=nullptr, time_point created=time_point::max()) {
|
||||
put(key, std::make_shared<Value>(std::move(v)), cb, created);
|
||||
void put(const InfoHash& key,
|
||||
Value&& v,
|
||||
DoneCallback cb=nullptr,
|
||||
time_point created=time_point::max(),
|
||||
bool permanent = false)
|
||||
{
|
||||
put(key, std::make_shared<Value>(std::move(v)), cb, created, permanent);
|
||||
}
|
||||
void put(const InfoHash& key, Value&& v, DoneCallbackSimple cb, time_point created=time_point::max()) {
|
||||
put(key, std::forward<Value>(v), bindDoneCb(cb), created);
|
||||
void put(const InfoHash& key,
|
||||
Value&& v,
|
||||
DoneCallbackSimple cb,
|
||||
time_point created=time_point::max(),
|
||||
bool permanent = false)
|
||||
{
|
||||
put(key, std::forward<Value>(v), bindDoneCb(cb), created, permanent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data currently being put at the given hash.
|
||||
*/
|
||||
std::vector<std::shared_ptr<Value>> getPut(const InfoHash&);
|
||||
std::vector<Sp<Value>> getPut(const InfoHash&);
|
||||
|
||||
/**
|
||||
* Get data currently being put at the given hash with the given id.
|
||||
*/
|
||||
std::shared_ptr<Value> getPut(const InfoHash&, const Value::Id&);
|
||||
Sp<Value> getPut(const InfoHash&, const Value::Id&);
|
||||
|
||||
/**
|
||||
* Stop any put/announce operation at the given location,
|
||||
@@ -198,9 +242,9 @@ public:
|
||||
*
|
||||
* @return a token to cancel the listener later.
|
||||
*/
|
||||
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter&&={});
|
||||
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}) {
|
||||
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f));
|
||||
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter&&={}, Where&& w = {});
|
||||
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w = {}) {
|
||||
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
|
||||
virtual bool cancelListen(const InfoHash&, size_t token);
|
||||
@@ -210,7 +254,12 @@ public:
|
||||
* 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();
|
||||
void connectivityChanged(sa_family_t);
|
||||
void connectivityChanged() {
|
||||
reported_addr.clear();
|
||||
connectivityChanged(AF_INET);
|
||||
connectivityChanged(AF_INET6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of good nodes for local storage saving purposes
|
||||
@@ -221,11 +270,14 @@ public:
|
||||
std::vector<ValuesExport> exportValues() const;
|
||||
void importValues(const std::vector<ValuesExport>&);
|
||||
|
||||
int getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return,
|
||||
unsigned *incoming_return) const;
|
||||
NodeStats getNodesStats(sa_family_t af) const;
|
||||
|
||||
std::string getStorageLog() const;
|
||||
std::string getStorageLog(const InfoHash&) const;
|
||||
|
||||
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;
|
||||
|
||||
void dumpTables() const;
|
||||
std::vector<unsigned> getNodeMessageStats(bool in = false) {
|
||||
@@ -247,10 +299,12 @@ public:
|
||||
return {total_store_size, total_values};
|
||||
}
|
||||
|
||||
std::vector<Address> getPublicAddress(sa_family_t family = 0);
|
||||
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0);
|
||||
|
||||
protected:
|
||||
Logger DHT_LOG;
|
||||
bool logFilerEnable_ {};
|
||||
InfoHash logFiler_ {};
|
||||
|
||||
private:
|
||||
|
||||
@@ -259,8 +313,18 @@ private:
|
||||
the target 8 turn out to be dead. */
|
||||
static constexpr unsigned SEARCH_NODES {14};
|
||||
|
||||
/* Concurrent requests during a search */
|
||||
static constexpr unsigned SEARCH_REQUESTS {4};
|
||||
/* The number of bad nodes is limited in order to help determine
|
||||
* presence of connectivity changes. See
|
||||
* https://github.com/savoirfairelinux/opendht/issues/137 for details.
|
||||
*
|
||||
* According to the tables, 25 is a good average value for big networks. If
|
||||
* the network is small, normal search expiration process will handle the
|
||||
* situation.
|
||||
* */
|
||||
static constexpr unsigned SEARCH_MAX_BAD_NODES {25};
|
||||
|
||||
/* Concurrent search nodes requested count */
|
||||
static constexpr unsigned MAX_REQUESTED_SEARCH_NODES {4};
|
||||
|
||||
/* Number of listening nodes */
|
||||
static constexpr unsigned LISTEN_NODES {4};
|
||||
@@ -282,68 +346,19 @@ private:
|
||||
/* Timeout for listen */
|
||||
static constexpr std::chrono::seconds LISTEN_EXPIRE_TIME {30};
|
||||
|
||||
static constexpr std::chrono::seconds REANNOUNCE_MARGIN {5};
|
||||
static constexpr std::chrono::seconds REANNOUNCE_MARGIN {10};
|
||||
|
||||
static constexpr size_t TOKEN_SIZE {64};
|
||||
static constexpr size_t TOKEN_SIZE {32};
|
||||
|
||||
// internal structures
|
||||
struct SearchNode;
|
||||
|
||||
/**
|
||||
* A single "get" operation data
|
||||
*/
|
||||
struct Get {
|
||||
time_point start;
|
||||
Value::Filter filter;
|
||||
GetCallback get_cb;
|
||||
DoneCallback done_cb;
|
||||
};
|
||||
|
||||
/**
|
||||
* A single "put" operation data
|
||||
*/
|
||||
struct Announce {
|
||||
std::shared_ptr<Value> value;
|
||||
time_point created;
|
||||
DoneCallback callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* A single "listen" operation data
|
||||
*/
|
||||
struct LocalListener {
|
||||
Value::Filter filter;
|
||||
GetCallback get_cb;
|
||||
};
|
||||
|
||||
/**
|
||||
* A search is a list of the nodes we think are responsible
|
||||
* for storing values for a given hash.
|
||||
*/
|
||||
struct Get;
|
||||
struct Announce;
|
||||
struct LocalListener;
|
||||
struct Search;
|
||||
|
||||
struct ValueStorage {
|
||||
std::shared_ptr<Value> data {};
|
||||
time_point time {};
|
||||
|
||||
ValueStorage() {}
|
||||
ValueStorage(const std::shared_ptr<Value>& v, time_point t) : data(v), time(t) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Foreign nodes asking for updates about an InfoHash.
|
||||
*/
|
||||
struct Listener {
|
||||
size_t rid {};
|
||||
time_point time {};
|
||||
|
||||
/*constexpr*/ Listener(size_t rid, time_point t) : rid(rid), time(t) {}
|
||||
|
||||
void refresh(size_t tid, time_point t) {
|
||||
rid = tid;
|
||||
time = t;
|
||||
}
|
||||
};
|
||||
|
||||
struct ValueStorage;
|
||||
class StorageBucket;
|
||||
struct Listener;
|
||||
struct Storage;
|
||||
|
||||
// prevent copy
|
||||
@@ -363,18 +378,21 @@ private:
|
||||
// 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 buckets {};
|
||||
RoutingTable buckets4 {};
|
||||
RoutingTable buckets6 {};
|
||||
|
||||
std::vector<Storage> store;
|
||||
std::map<InfoHash, Storage> store;
|
||||
std::map<SockAddr, StorageBucket, SockAddr::ipCmp> store_quota;
|
||||
size_t total_values {0};
|
||||
size_t total_store_size {0};
|
||||
size_t max_store_size {DEFAULT_STORAGE_LIMIT};
|
||||
|
||||
std::map<InfoHash, std::shared_ptr<Search>> searches4 {};
|
||||
std::map<InfoHash, std::shared_ptr<Search>> searches6 {};
|
||||
using SearchMap = std::map<InfoHash, Sp<Search>>;
|
||||
SearchMap searches4 {};
|
||||
SearchMap searches6 {};
|
||||
uint16_t search_id {0};
|
||||
|
||||
// map a global listen token to IPv4, IPv6 specific listen tokens.
|
||||
@@ -383,13 +401,16 @@ private:
|
||||
size_t listener_token {1};
|
||||
|
||||
// timing
|
||||
Scheduler scheduler {};
|
||||
std::shared_ptr<Scheduler::Job> nextNodesConfirmation {};
|
||||
Scheduler scheduler;
|
||||
Sp<Scheduler::Job> nextNodesConfirmation {};
|
||||
Sp<Scheduler::Job> nextStorageMaintenance {};
|
||||
time_point mybucket_grow_time {time_point::min()}, mybucket6_grow_time {time_point::min()};
|
||||
|
||||
NetworkEngine network_engine;
|
||||
net::NetworkEngine network_engine;
|
||||
unsigned pending_pings4 {0};
|
||||
unsigned pending_pings6 {0};
|
||||
|
||||
using ReportedAddr = std::pair<unsigned, Address>;
|
||||
using ReportedAddr = std::pair<unsigned, SockAddr>;
|
||||
std::vector<ReportedAddr> reported_addr;
|
||||
|
||||
void rotateSecrets();
|
||||
@@ -397,32 +418,36 @@ private:
|
||||
Blob makeToken(const sockaddr *sa, bool old) const;
|
||||
bool tokenMatch(const Blob& token, const sockaddr *sa) const;
|
||||
|
||||
void reportedAddr(const sockaddr *sa, socklen_t sa_len);
|
||||
void reportedAddr(const SockAddr&);
|
||||
|
||||
// Storage
|
||||
decltype(Dht::store)::iterator findStorage(const InfoHash& id);
|
||||
decltype(Dht::store)::const_iterator findStorage(const InfoHash& id) const;
|
||||
void storageAddListener(const InfoHash& id, const Sp<Node>& node, size_t tid, Query&& = {});
|
||||
bool storageStore(const InfoHash& id, const Sp<Value>& value, time_point created, const SockAddr* sa = nullptr);
|
||||
void expireStore();
|
||||
void expireStorage(InfoHash h);
|
||||
void expireStore(decltype(store)::iterator);
|
||||
|
||||
void storageAddListener(const InfoHash& id, const std::shared_ptr<Node>& node, size_t tid);
|
||||
bool storageStore(const InfoHash& id, const std::shared_ptr<Value>& value, time_point created);
|
||||
void expireStorage();
|
||||
void storageChanged(Storage& st, ValueStorage&);
|
||||
void storageChanged(const InfoHash& id, Storage& st, ValueStorage&);
|
||||
std::string printStorageLog(const decltype(store)::value_type&) const;
|
||||
void printStorageQuota(std::ostream& out, const decltype(store_quota)::value_type& ip) const;
|
||||
|
||||
/**
|
||||
* For a given storage, if values don't belong there anymore because this
|
||||
* node is too far from the target, values are sent to the appropriate
|
||||
* nodes.
|
||||
*/
|
||||
void dataPersistence();
|
||||
size_t maintainStorage(InfoHash id, bool force=false, DoneCallback donecb=nullptr);
|
||||
void dataPersistence(InfoHash id);
|
||||
size_t maintainStorage(decltype(store)::value_type&, bool force=false, DoneCallback donecb=nullptr);
|
||||
|
||||
// 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 = buckets.findBucket(id);
|
||||
return b == buckets.end() ? nullptr : &(*b);
|
||||
b = buckets4.findBucket(id);
|
||||
return b == buckets4.end() ? nullptr : &(*b);
|
||||
case AF_INET6:
|
||||
b = buckets6.findBucket(id);
|
||||
return b == buckets6.end() ? nullptr : &(*b);
|
||||
@@ -440,59 +465,139 @@ private:
|
||||
void dumpBucket(const Bucket& b, std::ostream& out) const;
|
||||
|
||||
// Nodes
|
||||
void onNewNode(const std::shared_ptr<Node>& node, int confirm);
|
||||
std::shared_ptr<Node> findNode(const InfoHash& id, sa_family_t af);
|
||||
const std::shared_ptr<Node> findNode(const InfoHash& id, sa_family_t af) const;
|
||||
bool trySearchInsert(const std::shared_ptr<Node>& node);
|
||||
void onNewNode(const Sp<Node>& node, int confirm);
|
||||
Sp<Node> findNode(const InfoHash& id, sa_family_t af);
|
||||
const Sp<Node> findNode(const InfoHash& id, sa_family_t af) const;
|
||||
bool trySearchInsert(const Sp<Node>& node);
|
||||
|
||||
// Searches
|
||||
|
||||
/**
|
||||
* Low-level method that will perform a search on the DHT for the
|
||||
* specified infohash (id), using the specified IP version (IPv4 or IPv6).
|
||||
* The values can be filtered by an arbitrary provided filter.
|
||||
*/
|
||||
std::shared_ptr<Search> search(const InfoHash& id, sa_family_t af, GetCallback = nullptr, DoneCallback = nullptr, Value::Filter = Value::AllFilter());
|
||||
void announce(const InfoHash& id, sa_family_t af, std::shared_ptr<Value> value, DoneCallback callback, time_point created=time_point::max());
|
||||
size_t listenTo(const InfoHash& id, sa_family_t af, GetCallback cb, Value::Filter f = Value::AllFilter());
|
||||
inline SearchMap& searches(sa_family_t af) { return af == AF_INET ? searches4 : searches6; }
|
||||
inline const SearchMap& searches(sa_family_t af) const { return af == AF_INET ? searches4 : searches6; }
|
||||
|
||||
void bootstrapSearch(Search& sr);
|
||||
Search *findSearch(unsigned short tid, sa_family_t af);
|
||||
/**
|
||||
* Low-level method that will perform a search on the DHT for the specified
|
||||
* infohash (id), using the specified IP version (IPv4 or IPv6).
|
||||
*/
|
||||
Sp<Search> search(const InfoHash& id, sa_family_t af, GetCallback = {}, QueryCallback = {}, DoneCallback = {}, Value::Filter = {}, 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, GetCallback cb, Value::Filter f = Value::AllFilter(), const Sp<Query>& q = {});
|
||||
|
||||
/**
|
||||
* Refill the search with good nodes if possible.
|
||||
*
|
||||
* @param sr The search to refill.
|
||||
*
|
||||
* @return the number inserted nodes.
|
||||
*/
|
||||
unsigned refill(Search& sr);
|
||||
void expireSearches();
|
||||
|
||||
void confirmNodes();
|
||||
void expire();
|
||||
|
||||
/**
|
||||
* Generic function to execute when a 'get' request has completed.
|
||||
*
|
||||
* @param status The request passed by the network engine.
|
||||
* @param answer The answer from the network engine.
|
||||
* @param ws A weak pointer to the search concerned by the request.
|
||||
* @param query The query sent to the node.
|
||||
*/
|
||||
void searchNodeGetDone(const net::Request& status,
|
||||
net::NetworkEngine::RequestAnswer&& answer,
|
||||
std::weak_ptr<Search> ws,
|
||||
Sp<Query> query);
|
||||
|
||||
/**
|
||||
* Generic function to execute when a 'get' request expires.
|
||||
*
|
||||
* @param status The request passed by the network engine.
|
||||
* @param over Whether we're done to try sending the request to the node
|
||||
* or not. This lets us mark a node as candidate.
|
||||
* @param ws A weak pointer to the search concerned by the request.
|
||||
* @param query The query sent to the node.
|
||||
*/
|
||||
void searchNodeGetExpired(const net::Request& status, bool over, std::weak_ptr<Search> ws, Sp<Query> query);
|
||||
|
||||
/**
|
||||
* This method recovers sends individual request for values per id.
|
||||
*
|
||||
* @param ws A weak pointer to the Search.
|
||||
* @param query The initial query passed through the API.
|
||||
* @param n The node to which send the requests.
|
||||
*/
|
||||
void paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n);
|
||||
|
||||
/**
|
||||
* If update is true, this method will also send message to synced but non-updated search nodes.
|
||||
*/
|
||||
SearchNode* searchSendGetValues(std::shared_ptr<Search> sr, SearchNode *n = nullptr, bool update = true);
|
||||
SearchNode* searchSendGetValues(Sp<Search> sr, SearchNode *n = nullptr, bool update = true);
|
||||
|
||||
void searchStep(std::shared_ptr<Search> sr);
|
||||
/**
|
||||
* Forwards an 'announce' request for a list of nodes to the network engine.
|
||||
*
|
||||
* @param sr The search for which we want to announce a value.
|
||||
* @param announce The 'announce' structure.
|
||||
*/
|
||||
void searchSendAnnounceValue(const Sp<Search>& sr);
|
||||
|
||||
/**
|
||||
* Main process of a Search's operations. This function will demand the
|
||||
* network engine to send requests packets for all pending operations
|
||||
* ('get', 'put' and 'listen').
|
||||
*
|
||||
* @param sr The search to execute its operations.
|
||||
*/
|
||||
void searchStep(Sp<Search> sr);
|
||||
void dumpSearch(const Search& sr, std::ostream& out) const;
|
||||
|
||||
bool neighbourhoodMaintenance(RoutingTable&);
|
||||
|
||||
void processMessage(const uint8_t *buf, size_t buflen, const sockaddr *from, socklen_t fromlen);
|
||||
void processMessage(const uint8_t *buf, size_t buflen, const SockAddr&);
|
||||
|
||||
void onError(std::shared_ptr<Request> node, DhtProtocolException e);
|
||||
void onError(Sp<net::Request> node, net::DhtProtocolException e);
|
||||
/* when our address is reported by a distant peer. */
|
||||
void onReportedAddr(const InfoHash& id, sockaddr* sa , socklen_t salen);
|
||||
void onReportedAddr(const InfoHash& id, const SockAddr&);
|
||||
/* when we receive a ping request */
|
||||
NetworkEngine::RequestAnswer onPing(std::shared_ptr<Node> node);
|
||||
net::NetworkEngine::RequestAnswer onPing(Sp<Node> node);
|
||||
/* when we receive a "find node" request */
|
||||
NetworkEngine::RequestAnswer onFindNode(std::shared_ptr<Node> node, InfoHash& hash, want_t want);
|
||||
void onFindNodeDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search> sr);
|
||||
net::NetworkEngine::RequestAnswer onFindNode(Sp<Node> node, const InfoHash& hash, want_t want);
|
||||
void onFindNodeDone(const Sp<Node>& status,
|
||||
net::NetworkEngine::RequestAnswer& a,
|
||||
Sp<Search> sr);
|
||||
/* when we receive a "get values" request */
|
||||
NetworkEngine::RequestAnswer onGetValues(std::shared_ptr<Node> node, InfoHash& hash, want_t want);
|
||||
void onGetValuesDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search> sr);
|
||||
net::NetworkEngine::RequestAnswer onGetValues(Sp<Node> node,
|
||||
const InfoHash& hash,
|
||||
want_t want,
|
||||
const Query& q);
|
||||
void onGetValuesDone(const Sp<Node>& status,
|
||||
net::NetworkEngine::RequestAnswer& a,
|
||||
Sp<Search>& sr,
|
||||
const Sp<Query>& orig_query);
|
||||
/* when we receive a listen request */
|
||||
NetworkEngine::RequestAnswer onListen(std::shared_ptr<Node> node, InfoHash& hash, Blob& token, size_t rid);
|
||||
void onListenDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search>& sr);
|
||||
net::NetworkEngine::RequestAnswer onListen(Sp<Node> node,
|
||||
const InfoHash& hash,
|
||||
const Blob& token,
|
||||
size_t socket_id,
|
||||
const Query& query);
|
||||
void onListenDone(const Sp<Node>& status,
|
||||
net::NetworkEngine::RequestAnswer& a,
|
||||
Sp<Search>& sr);
|
||||
/* when we receive an announce request */
|
||||
NetworkEngine::RequestAnswer onAnnounce(std::shared_ptr<Node> node,
|
||||
InfoHash& hash, Blob& token, std::vector<std::shared_ptr<Value>> v, time_point created);
|
||||
void onAnnounceDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search>& sr);
|
||||
net::NetworkEngine::RequestAnswer onAnnounce(Sp<Node> node,
|
||||
const InfoHash& hash,
|
||||
const Blob& token,
|
||||
const std::vector<Sp<Value>>& v,
|
||||
const time_point& created);
|
||||
net::NetworkEngine::RequestAnswer onRefresh(Sp<Node> node,
|
||||
const InfoHash& hash,
|
||||
const Blob& token,
|
||||
const Value::Id& vid);
|
||||
void onAnnounceDone(const Sp<Node>& status,
|
||||
net::NetworkEngine::RequestAnswer& a,
|
||||
Sp<Search>& sr);
|
||||
};
|
||||
|
||||
}
|
||||
+103
-45
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,6 +24,9 @@
|
||||
#include "infohash.h"
|
||||
#include "value.h"
|
||||
#include "callbacks.h"
|
||||
#include "sockaddr.h"
|
||||
#include "log_enable.h"
|
||||
#include "def.h"
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
@@ -46,7 +49,7 @@ struct SecureDhtConfig;
|
||||
* either wait for (expectedly frequent) calls to ::loop() or start an internal
|
||||
* thread that will update the DHT when appropriate.
|
||||
*/
|
||||
class DhtRunner {
|
||||
class OPENDHT_PUBLIC DhtRunner {
|
||||
|
||||
public:
|
||||
typedef std::function<void(NodeStatus, NodeStatus)> StatusCallback;
|
||||
@@ -54,20 +57,20 @@ public:
|
||||
DhtRunner();
|
||||
virtual ~DhtRunner();
|
||||
|
||||
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = Value::AllFilter()) {
|
||||
get(id, bindGetCb(cb), donecb, f);
|
||||
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
|
||||
get(id, bindGetCb(cb), donecb, f, w);
|
||||
}
|
||||
|
||||
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter()) {
|
||||
get(id, bindGetCb(cb), donecb, f);
|
||||
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
|
||||
get(id, bindGetCb(cb), donecb, f, w);
|
||||
}
|
||||
|
||||
void get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f={});
|
||||
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()) {
|
||||
get(id, cb, bindDoneCb(donecb), f);
|
||||
void get(InfoHash id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
|
||||
get(id, cb, bindDoneCb(donecb), f, w);
|
||||
}
|
||||
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = Value::AllFilter());
|
||||
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = Value::AllFilter(), Where w = {});
|
||||
|
||||
template <class T>
|
||||
void get(InfoHash hash, std::function<bool(std::vector<T>&&)> cb, DoneCallbackSimple dcb={})
|
||||
@@ -96,7 +99,7 @@ public:
|
||||
getFilterSet<T>());
|
||||
}
|
||||
|
||||
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = Value::AllFilter()) {
|
||||
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = Value::AllFilter(), 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) {
|
||||
@@ -105,7 +108,7 @@ public:
|
||||
}, [=](bool) {
|
||||
p->set_value(std::move(*values));
|
||||
},
|
||||
f);
|
||||
f, w);
|
||||
return p->get_future();
|
||||
}
|
||||
|
||||
@@ -122,10 +125,15 @@ public:
|
||||
return p->get_future();
|
||||
}
|
||||
|
||||
std::future<size_t> listen(InfoHash key, GetCallback vcb, Value::Filter f = Value::AllFilter());
|
||||
std::future<size_t> listen(const std::string& key, GetCallback vcb, Value::Filter f = Value::AllFilter());
|
||||
std::future<size_t> listen(InfoHash key, GetCallbackSimple cb, Value::Filter f = Value::AllFilter()) {
|
||||
return listen(key, bindGetCb(cb), f);
|
||||
void query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb = {}, Query q = {});
|
||||
void query(const InfoHash& hash, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query q = {}) {
|
||||
query(hash, cb, bindDoneCb(done_cb), q);
|
||||
}
|
||||
|
||||
std::future<size_t> listen(InfoHash key, GetCallback vcb, Value::Filter f = Value::AllFilter(), 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 = {}) {
|
||||
return listen(key, bindGetCb(cb), f, w);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -137,7 +145,7 @@ public:
|
||||
getFilterSet<T>());
|
||||
}
|
||||
template <typename T>
|
||||
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = Value::AllFilter())
|
||||
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = Value::AllFilter(), Where w = {})
|
||||
{
|
||||
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals) {
|
||||
for (const auto& v : vals) {
|
||||
@@ -150,22 +158,22 @@ public:
|
||||
}
|
||||
return true;
|
||||
},
|
||||
getFilterSet<T>(f));
|
||||
getFilterSet<T>(f), w);
|
||||
}
|
||||
|
||||
void cancelListen(InfoHash h, size_t token);
|
||||
void cancelListen(InfoHash h, std::shared_future<size_t> token);
|
||||
|
||||
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={});
|
||||
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb) {
|
||||
put(hash, value, bindDoneCb(cb));
|
||||
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={}, time_point created=time_point::max(), bool permanent = false);
|
||||
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb, time_point created=time_point::max(), bool permanent = false) {
|
||||
put(hash, value, bindDoneCb(cb), created, permanent);
|
||||
}
|
||||
|
||||
void put(InfoHash hash, Value&& value, DoneCallback cb={});
|
||||
void put(InfoHash hash, Value&& value, DoneCallbackSimple cb) {
|
||||
put(hash, std::forward<Value>(value), bindDoneCb(cb));
|
||||
void put(InfoHash hash, Value&& value, DoneCallback cb={}, time_point created=time_point::max(), bool permanent = false);
|
||||
void put(InfoHash hash, Value&& value, DoneCallbackSimple cb, time_point created=time_point::max(), bool permanent = false) {
|
||||
put(hash, std::forward<Value>(value), bindDoneCb(cb), created, permanent);
|
||||
}
|
||||
void put(const std::string& key, Value&& value, DoneCallbackSimple cb={});
|
||||
void put(const std::string& key, Value&& value, DoneCallbackSimple cb={}, time_point created=time_point::max(), bool permanent = false);
|
||||
|
||||
void cancelPut(const InfoHash& h, const Value::Id& id);
|
||||
|
||||
@@ -191,10 +199,31 @@ public:
|
||||
}
|
||||
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={});
|
||||
|
||||
void bootstrap(const char* host, const char* service);
|
||||
void bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes);
|
||||
/**
|
||||
* 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 std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes, DoneCallbackSimple&& cb={});
|
||||
|
||||
/**
|
||||
* Insert known nodes to the routing table, without necessarly ping them.
|
||||
* Usefull to restart a node and get things running fast without putting load on the network.
|
||||
*/
|
||||
void bootstrap(const std::vector<NodeExport>& nodes);
|
||||
|
||||
/**
|
||||
* Add host:service to bootstrap nodes, and ping this node.
|
||||
* DNS resolution is performed asynchronously.
|
||||
* When disconnected, all bootstrap nodes added with this method will be tried regularly until connection
|
||||
* to the DHT network is established.
|
||||
*/
|
||||
void bootstrap(const std::string& host, const std::string& service);
|
||||
|
||||
/**
|
||||
* Clear the list of bootstrap added using bootstrap(const std::string&, const std::string&).
|
||||
*/
|
||||
void clearBootstrap();
|
||||
|
||||
/**
|
||||
* Inform the DHT of lower-layer connectivity changes.
|
||||
* This will cause the DHT to assume an IP address change.
|
||||
@@ -212,7 +241,7 @@ public:
|
||||
* Returns the currently bound address.
|
||||
* @param f: address family of the bound address to retreive.
|
||||
*/
|
||||
const Address& getBound(sa_family_t f = AF_INET) const {
|
||||
const SockAddr& getBound(sa_family_t f = AF_INET) const {
|
||||
return (f == AF_INET) ? bound4 : bound6;
|
||||
}
|
||||
|
||||
@@ -232,7 +261,12 @@ public:
|
||||
|
||||
std::vector<ValuesExport> exportValues() const;
|
||||
|
||||
void setLoggers(LogMethod&& error = NOLOG, LogMethod&& warn = NOLOG, LogMethod&& debug = NOLOG);
|
||||
void setLoggers(LogMethod err = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG);
|
||||
|
||||
/**
|
||||
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
|
||||
*/
|
||||
void setLogFilter(const InfoHash& f = {});
|
||||
|
||||
void registerType(const ValueType& type);
|
||||
|
||||
@@ -242,14 +276,17 @@ public:
|
||||
return running;
|
||||
}
|
||||
|
||||
int getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
|
||||
NodeStats getNodesStats(sa_family_t af) const;
|
||||
unsigned getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
|
||||
|
||||
std::vector<unsigned> getNodeMessageStats(bool in = false) const;
|
||||
std::string getStorageLog() const;
|
||||
std::string getStorageLog(const InfoHash&) const;
|
||||
std::string getRoutingTablesLog(sa_family_t af) const;
|
||||
std::string getSearchesLog(sa_family_t af = 0) const;
|
||||
std::vector<Address> getPublicAddress(sa_family_t af = 0);
|
||||
std::vector<std::string> getPublicAddressStr(sa_family_t af = 0);
|
||||
std::string getSearchesLog(sa_family_t af = AF_UNSPEC) const;
|
||||
std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const;
|
||||
std::vector<SockAddr> getPublicAddress(sa_family_t af = AF_UNSPEC);
|
||||
std::vector<std::string> getPublicAddressStr(sa_family_t af = AF_UNSPEC);
|
||||
|
||||
// securedht methods
|
||||
|
||||
@@ -268,16 +305,18 @@ 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, const crypto::Identity identity, bool threaded = false, bool is_bootstrap = false) {
|
||||
void run(in_port_t port, const crypto::Identity identity, bool threaded = false, NetId network = 0) {
|
||||
run(port, {
|
||||
.dht_config = {
|
||||
.node_config = {
|
||||
.node_id = {},
|
||||
.is_bootstrap = is_bootstrap
|
||||
/*.dht_config = */{
|
||||
/*.node_config = */{
|
||||
/*.node_id = */{},
|
||||
/*.network = */network,
|
||||
/*.is_bootstrap = */false,
|
||||
/*.maintain_storage*/false
|
||||
},
|
||||
.id = identity
|
||||
/*.id = */identity
|
||||
},
|
||||
.threaded = threaded
|
||||
/*.threaded = */threaded
|
||||
});
|
||||
}
|
||||
void run(in_port_t port, Config config);
|
||||
@@ -324,11 +363,20 @@ public:
|
||||
void join();
|
||||
|
||||
private:
|
||||
static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
|
||||
|
||||
/**
|
||||
* Will try to resolve the list of hostnames `bootstrap_nodes` on seperate
|
||||
* thread and then queue ping requests. This list should contain reliable
|
||||
* nodes so that the DHT node can recover quickly from losing connection
|
||||
* with the network.
|
||||
*/
|
||||
void tryBootstrapContinuously();
|
||||
|
||||
void doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDhtConfig config);
|
||||
time_point loop_();
|
||||
|
||||
static std::vector<std::pair<sockaddr_storage, socklen_t>> getAddrInfo(const char* host, const char* service);
|
||||
static std::vector<std::pair<sockaddr_storage, socklen_t>> getAddrInfo(const std::string& host, const std::string& service);
|
||||
|
||||
NodeStatus getStatus() const {
|
||||
return std::max(status4, status6);
|
||||
@@ -341,7 +389,17 @@ private:
|
||||
|
||||
std::thread rcv_thread {};
|
||||
std::mutex sock_mtx {};
|
||||
std::vector<std::pair<Blob, std::pair<sockaddr_storage, socklen_t>>> rcv {};
|
||||
std::vector<std::pair<Blob, SockAddr>> rcv {};
|
||||
|
||||
/** true if currently actively boostraping */
|
||||
std::atomic_bool bootstraping {false};
|
||||
/* bootstrap nodes given as (host, service) pairs */
|
||||
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 {};
|
||||
|
||||
std::queue<std::function<void(SecureDht&)>> pending_ops_prio {};
|
||||
std::queue<std::function<void(SecureDht&)>> pending_ops {};
|
||||
@@ -353,8 +411,8 @@ private:
|
||||
status6 {NodeStatus::Disconnected};
|
||||
StatusCallback statusCb {nullptr};
|
||||
|
||||
Address bound4 {};
|
||||
Address bound6 {};
|
||||
SockAddr bound4 {};
|
||||
SockAddr bound6 {};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,534 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <bitset>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "../value.h"
|
||||
#include "../dhtrunner.h"
|
||||
#include "../infohash.h"
|
||||
|
||||
namespace dht {
|
||||
namespace indexation {
|
||||
|
||||
/*!
|
||||
* @class Prefix
|
||||
* @brief A blob structure which prefixes a Key in the PHT.
|
||||
* @details
|
||||
* Since the PHT structure is a "trie", every node in this structure have a
|
||||
* label which is defined by the path from the root of the trie to the node. If
|
||||
* the node in question is a leaf, *the label is a prefix of all the keys
|
||||
* contained in the leaf*.
|
||||
*/
|
||||
struct OPENDHT_PUBLIC Prefix {
|
||||
Prefix() {}
|
||||
Prefix(InfoHash h) : size_(h.size() * 8), content_(h.begin(), h.end()) { }
|
||||
Prefix(const Blob& d, const Blob& f={}) : size_(d.size()*8), flags_(f), content_(d) { }
|
||||
|
||||
Prefix(const Prefix& p, size_t first) :
|
||||
size_(std::min(first, p.content_.size()*8)),
|
||||
content_(Blob(p.content_.begin(), p.content_.begin()+size_/8))
|
||||
{
|
||||
|
||||
auto rem = size_ % 8;
|
||||
if ( not p.flags_.empty() ) {
|
||||
flags_ = Blob(p.flags_.begin(), p.flags_.begin()+size_/8);
|
||||
if (rem)
|
||||
flags_.push_back(p.flags_[size_/8] & (0xFF << (8 - rem)));
|
||||
}
|
||||
|
||||
if (rem)
|
||||
content_.push_back(p.content_[size_/8] & (0xFF << (8 - rem)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sub prefix of the Prefix
|
||||
*
|
||||
* @param len lenght of the prefix to get, could be negative
|
||||
* if len is negativ then you will get the prefix
|
||||
* of size of the previous prefix minus len
|
||||
*
|
||||
* @return Sub-prefix of size len or if len is negative sub-prefix of size
|
||||
* of prefix minus len
|
||||
*
|
||||
* @throw out_of_range if len is larger than size of the content
|
||||
*/
|
||||
Prefix getPrefix(ssize_t len) const {
|
||||
if ((size_t)std::abs(len) >= content_.size() * 8)
|
||||
throw std::out_of_range("len larger than prefix size.");
|
||||
if (len < 0)
|
||||
len += size_;
|
||||
|
||||
return Prefix(*this, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags are considered as active if flag is empty or if the flag
|
||||
* at pos 'pos' is active
|
||||
ee *
|
||||
* @see isActiveBit in private function
|
||||
*/
|
||||
bool isFlagActive(size_t pos) const {
|
||||
return flags_.empty() or isActiveBit(flags_, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see isActiveBit in private function
|
||||
*/
|
||||
bool isContentBitActive(size_t pos) const {
|
||||
return isActiveBit(content_, pos);
|
||||
}
|
||||
|
||||
Prefix getFullSize() { return Prefix(*this, content_.size()*8); }
|
||||
|
||||
/**
|
||||
* This methods gets the prefix of its sibling in the PHT structure.
|
||||
*
|
||||
* @return The prefix of this sibling.
|
||||
*/
|
||||
Prefix getSibling() const {
|
||||
Prefix copy = *this;
|
||||
if ( size_ )
|
||||
copy.swapContentBit(size_ - 1);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
InfoHash hash() const {
|
||||
Blob copy(content_);
|
||||
copy.push_back(size_);
|
||||
return InfoHash::get(copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method count total of bit in common between 2 prefix
|
||||
*
|
||||
* @param p1 first prefix to compared
|
||||
* @param p2 second prefix to compared
|
||||
* @return Lenght of the larger common prefix between both
|
||||
*/
|
||||
static inline unsigned commonBits(const Prefix& p1, const Prefix& p2) {
|
||||
unsigned i, j;
|
||||
uint8_t x;
|
||||
auto longest_prefix_size = std::min(p1.size_, p2.size_);
|
||||
|
||||
for (i = 0; i < longest_prefix_size; i++) {
|
||||
if (p1.content_.data()[i] != p2.content_.data()[i]
|
||||
or not p1.isFlagActive(i)
|
||||
or not p2.isFlagActive(i) ) {
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == longest_prefix_size)
|
||||
return 8*longest_prefix_size;
|
||||
|
||||
x = p1.content_.data()[i] ^ p2.content_.data()[i];
|
||||
|
||||
j = 0;
|
||||
while ((x & 0x80) == 0) {
|
||||
x <<= 1;
|
||||
j++;
|
||||
}
|
||||
|
||||
return 8 * i + j;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see doc of swap private function
|
||||
*/
|
||||
void swapContentBit(size_t bit) {
|
||||
swapBit(content_, bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see doc of swap private function
|
||||
*/
|
||||
void swapFlagBit(size_t bit) {
|
||||
swapBit(flags_, bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see doc of addPadding private function
|
||||
*/
|
||||
void addPaddingContent(size_t size) {
|
||||
content_ = addPadding(content_, size);
|
||||
}
|
||||
|
||||
void updateFlags() {
|
||||
/* Fill first known bit */
|
||||
auto csize = size_ - flags_.size() * 8;
|
||||
while(csize >= 8) {
|
||||
flags_.push_back(0xFF);
|
||||
csize -= 8;
|
||||
}
|
||||
|
||||
/* if needed fill remaining bit */
|
||||
if ( csize )
|
||||
flags_.push_back(0xFF << (8 - csize));
|
||||
|
||||
/* Complet vector space missing */
|
||||
for ( auto i = flags_.size(); i < content_.size(); i++ )
|
||||
flags_.push_back(0xFF);
|
||||
}
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
size_t size_ {0};
|
||||
|
||||
/* Will contain flags according to content_.
|
||||
If flags_[i] == 0, then content_[i] is unknown
|
||||
else if flags_[i] == 1, then content_[i] is known */
|
||||
Blob flags_ {};
|
||||
Blob content_ {};
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Add a padding to the input blob
|
||||
*
|
||||
* @param toP : Prefix where to add a padding
|
||||
* @param size : Final size of the prefix with padding
|
||||
*
|
||||
* @return Copy of the input Blob but with a padding
|
||||
*/
|
||||
Blob addPadding(Blob toP, size_t size) {
|
||||
Blob copy = toP;
|
||||
for ( auto i = copy.size(); i < size; i++ )
|
||||
copy.push_back(0);
|
||||
|
||||
swapBit(copy, size_ + 1);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the bit a pos 'pos' is active, i.e. equal to 1
|
||||
*
|
||||
* @param b : Blob to check
|
||||
* @param pos : Position to check
|
||||
*
|
||||
* @return true if the bit is equal to 1, false otherwise
|
||||
*
|
||||
* @throw out_of_range if bit is superior to blob size * 8
|
||||
*/
|
||||
bool isActiveBit(const Blob &b, size_t pos) const {
|
||||
if ( pos >= content_.size() * 8 )
|
||||
throw std::out_of_range("Can't detect active bit at pos, pos larger than prefix size or empty prefix");
|
||||
|
||||
return ((b[pos / 8] >> (7 - (pos % 8)) ) & 1) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap bit at position bit [from 0 to 1 and vice-versa]
|
||||
*
|
||||
* @param b : Blob to swap
|
||||
* @param bit : Bit to swap on b
|
||||
*
|
||||
* @return the input prefix with the bit at pos 'bit' swapped
|
||||
*
|
||||
* @throw out_of_range if bit is superior to blob size * 8
|
||||
*/
|
||||
void swapBit(Blob &b, size_t bit) {
|
||||
if ( bit >= b.size() * 8 )
|
||||
throw std::out_of_range("bit larger than prefix size.");
|
||||
|
||||
size_t offset_bit = (8 - bit) % 8;
|
||||
b[bit / 8] ^= (1 << offset_bit);
|
||||
}
|
||||
};
|
||||
|
||||
using Value = std::pair<InfoHash, dht::Value::Id>;
|
||||
struct OPENDHT_PUBLIC IndexEntry : public dht::Value::Serializable<IndexEntry> {
|
||||
static const ValueType TYPE;
|
||||
|
||||
virtual void unpackValue(const dht::Value& v) {
|
||||
Serializable<IndexEntry>::unpackValue(v);
|
||||
name = v.user_type;
|
||||
}
|
||||
|
||||
virtual dht::Value packValue() const {
|
||||
auto pack = Serializable<IndexEntry>::packValue();
|
||||
pack.user_type = name;
|
||||
return pack;
|
||||
}
|
||||
|
||||
Blob prefix;
|
||||
Value value;
|
||||
std::string name;
|
||||
MSGPACK_DEFINE_MAP(prefix, value)
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC Pht {
|
||||
static constexpr const char* INVALID_KEY = "Key does not match the PHT key spec.";
|
||||
|
||||
/* Prefixes the user_type for all dht values put on the DHT */
|
||||
static constexpr const char* INDEX_PREFIX = "index.pht.";
|
||||
|
||||
public:
|
||||
|
||||
/* This is the maximum number of entries per node. This parameter is
|
||||
* critical and influences the traffic a lot during a lookup operation.
|
||||
*/
|
||||
static constexpr const size_t MAX_NODE_ENTRY_COUNT {16};
|
||||
|
||||
/* A key for a an index entry */
|
||||
using Key = std::map<std::string, Blob>;
|
||||
|
||||
/* Specifications of the keys. It defines the number, the length and the
|
||||
* serialization order of fields. */
|
||||
using KeySpec = std::map<std::string, size_t>;
|
||||
using LookupCallback = std::function<void(std::vector<std::shared_ptr<Value>>& values, Prefix p)>;
|
||||
|
||||
typedef void (*LookupCallbackRaw)(std::vector<std::shared_ptr<Value>>* values, Prefix* p, void *user_data);
|
||||
static LookupCallback
|
||||
bindLookupCb(LookupCallbackRaw raw_cb, void* user_data) {
|
||||
if (not raw_cb) return {};
|
||||
return [=](std::vector<std::shared_ptr<Value>>& values, Prefix p) {
|
||||
raw_cb((std::vector<std::shared_ptr<Value>>*) &values, (Prefix*) &p, user_data);
|
||||
};
|
||||
}
|
||||
using LookupCallbackSimple = std::function<void(std::vector<std::shared_ptr<Value>>& values)>;
|
||||
typedef void (*LookupCallbackSimpleRaw)(std::vector<std::shared_ptr<Value>>* values, void *user_data);
|
||||
static LookupCallbackSimple
|
||||
bindLookupCbSimple(LookupCallbackSimpleRaw raw_cb, void* user_data) {
|
||||
if (not raw_cb) return {};
|
||||
return [=](std::vector<std::shared_ptr<Value>>& values) {
|
||||
raw_cb((std::vector<std::shared_ptr<Value>>*) &values, user_data);
|
||||
};
|
||||
}
|
||||
|
||||
Pht(std::string name, KeySpec k_spec, std::shared_ptr<DhtRunner> dht)
|
||||
: name_(INDEX_PREFIX + name), canary_(name_ + ".canary"), keySpec_(k_spec), dht_(dht) {}
|
||||
|
||||
virtual ~Pht () { }
|
||||
|
||||
/**
|
||||
* Lookup a key for a value.
|
||||
*/
|
||||
void lookup(Key k, LookupCallback cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true);
|
||||
void lookup(Key k, LookupCallbackSimple cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true)
|
||||
{
|
||||
lookup(k, [=](std::vector<std::shared_ptr<Value>>& values, Prefix) { cb(values); }, done_cb, exact_match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function which call the private one.
|
||||
*
|
||||
* @param k : Key to insert [i.e map of string, blob]
|
||||
* @param v : Value to insert
|
||||
* @param done_cb : Callbakc which going to be call when all the insert is done
|
||||
*/
|
||||
void insert(Key k, Value v, DoneCallbackSimple done_cb = {}) {
|
||||
Prefix p = linearize(k);
|
||||
|
||||
auto lo = std::make_shared<int>(0);
|
||||
auto hi = std::make_shared<int>(p.size_);
|
||||
|
||||
IndexEntry entry;
|
||||
entry.value = v;
|
||||
entry.prefix = p.content_;
|
||||
entry.name = name_;
|
||||
|
||||
Pht::insert(p, entry, lo, hi, clock::now(), true, done_cb);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Insert function which really insert onto the pht
|
||||
*
|
||||
* @param kp : Prefix to insert (linearize the the key)
|
||||
* @param entry : Entry created from the value
|
||||
* @param lo : Lowest point to start in the prefix
|
||||
* @param hi : Highest point to end in the prefix
|
||||
* @param time_p : Timepoint to use for the insertion into the dht (must be < now)
|
||||
* @param check_split : If this flag is true then the algoritm will not use the merge algorithm
|
||||
* @param done_cb : Callback to call when the insert is done
|
||||
*/
|
||||
|
||||
void insert(Prefix kp, IndexEntry entry, std::shared_ptr<int> lo, std::shared_ptr<int> hi, time_point time_p,
|
||||
bool check_split, DoneCallbackSimple done_cb = {});
|
||||
|
||||
class Cache {
|
||||
public:
|
||||
/**
|
||||
* Insert all needed node into the tree according to a prefix
|
||||
* @param p : Prefix that we need to insert
|
||||
*/
|
||||
void insert(const Prefix& p);
|
||||
|
||||
/**
|
||||
* Lookup into the tree to return the maximum prefix length in the cache tree
|
||||
*
|
||||
* @param p : Prefix that we are looking for
|
||||
*
|
||||
* @return : The size of the longest prefix known in the cache between 0 and p.size_
|
||||
*/
|
||||
|
||||
int lookup(const Prefix& p);
|
||||
|
||||
private:
|
||||
static constexpr const size_t MAX_ELEMENT {1024};
|
||||
static constexpr const std::chrono::minutes NODE_EXPIRE_TIME {5};
|
||||
|
||||
struct Node {
|
||||
time_point last_reply; /* Made the assocation between leaves and leaves multimap */
|
||||
std::shared_ptr<Node> parent; /* Share_ptr to the parent, it allow the self destruction of tree */
|
||||
std::weak_ptr<Node> left_child; /* Left child, for bit equal to 1 */
|
||||
std::weak_ptr<Node> right_child; /* Right child, for bit equal to 0 */
|
||||
};
|
||||
|
||||
std::weak_ptr<Node> root_; /* Root of the tree */
|
||||
|
||||
/**
|
||||
* This mutlimap contains all prefix insert in the tree in time order
|
||||
* We could then delete the last one if there is too much node
|
||||
* The tree will self destroy is branch ( thanks to share_ptr )
|
||||
*/
|
||||
std::multimap<time_point, std::shared_ptr<Node>> leaves_;
|
||||
};
|
||||
|
||||
/* Callback used for insert value by using the pht */
|
||||
using RealInsertCallback = std::function<void(std::shared_ptr<Prefix> p, IndexEntry entry)>;
|
||||
using LookupCallbackWrapper = std::function<void(std::vector<std::shared_ptr<IndexEntry>>& values, Prefix p)>;
|
||||
|
||||
/**
|
||||
* Performs a step in the lookup operation. Each steps are performed
|
||||
* asynchronously.
|
||||
*
|
||||
* @param k : Prefix on which the lookup is performed
|
||||
* @param lo : lowest bound on the prefix (where to start)
|
||||
* @param hi : highest bound on the prefix (where to stop)
|
||||
* @param vals : Shared ptr to a vector of IndexEntry (going to contains all values found)
|
||||
* @param cb : Callback to use at the end of the lookupStep (call on the value of vals)
|
||||
* @param done_cb : Callback at the end of the lookupStep
|
||||
* @param max_common_prefix_len: used in the inexacte lookup match case, indicate the longest common prefix found
|
||||
* @param start : If start is set then lo and hi will be ignore for the first step, if the step fail lo and hi will be used
|
||||
* @param all_values : If all value is true then all value met during the lookupstep will be in the vector vals
|
||||
*/
|
||||
void lookupStep(Prefix k, std::shared_ptr<int> lo, std::shared_ptr<int> hi,
|
||||
std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals,
|
||||
LookupCallbackWrapper cb, DoneCallbackSimple done_cb,
|
||||
std::shared_ptr<unsigned> max_common_prefix_len,
|
||||
int start = -1, bool all_values = false);
|
||||
|
||||
/**
|
||||
* Apply the zcurve algorithm on the list of input prefix
|
||||
*
|
||||
* @param all_prefix : Vector of prefix to interleave
|
||||
*
|
||||
* @return The output prefix where all flags and content are interleaves
|
||||
*/
|
||||
Prefix zcurve(const std::vector<Prefix>& all_prefix) const;
|
||||
|
||||
/**
|
||||
* Linearizes the key into a unidimensional key. A pht only takes
|
||||
* unidimensional key.
|
||||
*
|
||||
* @param Key The initial key.
|
||||
*
|
||||
* @return the prefix of the linearized key.
|
||||
*/
|
||||
virtual Prefix linearize(Key k) const;
|
||||
|
||||
/**
|
||||
* Looking where to put the data cause if there is free space on the node
|
||||
* above then this node will became the real leave.
|
||||
*
|
||||
* @param p Share_ptr on the Prefix to check
|
||||
* @param entry The entry to put at the prefix p
|
||||
* @param end_cb Callback to use at the end of counting
|
||||
*/
|
||||
void getRealPrefix(std::shared_ptr<Prefix> p, IndexEntry entry, RealInsertCallback end_cb );
|
||||
|
||||
/**
|
||||
* Looking where to put the data cause if there is free space on the node
|
||||
* above then this node will became the real leave.
|
||||
*
|
||||
* @param p Share_ptr on the Prefix to check
|
||||
* @param entry The entry to put at the prefix p
|
||||
* @param end_cb Callback to use at the end of counting
|
||||
*/
|
||||
void checkPhtUpdate(Prefix p, IndexEntry entry, time_point time_p);
|
||||
|
||||
/**
|
||||
* Search for the split location by comparing 'compared' to all values in vals.
|
||||
*
|
||||
* @param compared : Value which going to be compared
|
||||
* @param vals : The vector of values to compare with comapred
|
||||
* @return position compared diverge from all others
|
||||
*/
|
||||
size_t foundSplitLocation(Prefix compared, std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals) {
|
||||
for ( size_t i = 0; i < compared.content_.size() * 8 - 1; i++ )
|
||||
for ( auto const& v : *vals)
|
||||
if ( Prefix(v->prefix).isContentBitActive(i) != compared.isContentBitActive(i) )
|
||||
return i + 1;
|
||||
|
||||
return compared.content_.size() * 8 - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put canary from the split point until the last known canary and add the prefix at the good place
|
||||
*
|
||||
* @param insert : Prefix to insertm but also prefix which going to check where we need to split
|
||||
* @param vals : Vector of vals for the comparaison
|
||||
* @param entry : Entry to put on the pht
|
||||
* @param end_cb : Callback to apply to the insert prefi (here does the insert)
|
||||
*/
|
||||
void split(Prefix insert, std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals, IndexEntry entry, RealInsertCallback end_cb);
|
||||
|
||||
/**
|
||||
* Tells if the key is valid according to the key spec.
|
||||
*/
|
||||
bool validKey(const Key& k) const {
|
||||
return k.size() == keySpec_.size() and
|
||||
std::equal(k.begin(), k.end(), keySpec_.begin(),
|
||||
[&](const Key::value_type& key, const KeySpec::value_type& key_spec) {
|
||||
return key.first == key_spec.first and key.second.size() <= key_spec.second;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the canary token on the node responsible for the specified
|
||||
* Prefix.
|
||||
*/
|
||||
void updateCanary(Prefix p);
|
||||
|
||||
const std::string name_;
|
||||
const std::string canary_;
|
||||
const KeySpec keySpec_;
|
||||
Cache cache_;
|
||||
std::shared_ptr<DhtRunner> dht_;
|
||||
};
|
||||
|
||||
} /* indexation */
|
||||
} /* dht */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 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,6 +19,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "def.h"
|
||||
|
||||
#include <msgpack.hpp>
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -28,6 +30,7 @@
|
||||
typedef uint16_t in_port_t;
|
||||
#endif
|
||||
#else
|
||||
#include <iso646.h>
|
||||
#include <ws2tcpip.h>
|
||||
typedef uint16_t sa_family_t;
|
||||
typedef uint16_t in_port_t;
|
||||
@@ -39,19 +42,102 @@ typedef uint16_t in_port_t;
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
// bytes
|
||||
#define HASH_LEN 20u
|
||||
|
||||
namespace dht {
|
||||
|
||||
using byte = uint8_t;
|
||||
|
||||
template <size_t N>
|
||||
class OPENDHT_PUBLIC Hash
|
||||
{
|
||||
public:
|
||||
Hash() {
|
||||
data_.fill(0);
|
||||
}
|
||||
Hash(const msgpack::object& o) {
|
||||
msgpack_unpack(o);
|
||||
}
|
||||
byte* data() {
|
||||
return data_.data();
|
||||
}
|
||||
const byte* data() const {
|
||||
return data_.data();
|
||||
}
|
||||
constexpr size_t size() const { return data_.size(); }
|
||||
explicit operator bool() const { return std::any_of(data_.begin(), data_.end(), [](byte _b) { return _b != 0; }); }
|
||||
bool operator==(Hash const& _c) const { return data_ == _c.data_; }
|
||||
bool operator!=(Hash const& _c) const { return data_ != _c.data_; }
|
||||
bool operator<(Hash const& _c) const { for (unsigned i = 0; i < N; ++i) if (data_[i] < _c.data_[i]) return true; else if (data_[i] > _c.data_[i]) return false; return false; }
|
||||
bool operator>=(Hash const& _c) const { return !operator<(_c); }
|
||||
bool operator<=(Hash const& _c) const { return operator==(_c) || operator<(_c); }
|
||||
bool operator>(Hash const& _c) const { return !operator<=(_c); }
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& pk) const
|
||||
{
|
||||
pk.pack_bin(N);
|
||||
pk.pack_bin_body((char*)data_.data(), N);
|
||||
}
|
||||
void msgpack_unpack(msgpack::object o) {
|
||||
if (o.type != msgpack::type::BIN or o.via.bin.size != N)
|
||||
throw msgpack::type_error();
|
||||
std::copy_n(o.via.bin.ptr, N, data_.data());
|
||||
}
|
||||
|
||||
template <size_t M>
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Hash<M>& h);
|
||||
|
||||
template <size_t M>
|
||||
OPENDHT_PUBLIC friend std::istream& operator>> (std::istream& s, Hash<M>& h);
|
||||
|
||||
std::string toString() const {
|
||||
std::stringstream ss;
|
||||
ss << *this;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<byte, N> data_;
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
std::ostream& operator<< (std::ostream& s, const Hash<N>& h)
|
||||
{
|
||||
s << std::hex;
|
||||
for (unsigned i=0; i<h.size(); i++)
|
||||
s << std::setfill('0') << std::setw(2) << (unsigned)h.data_[i];
|
||||
s << std::dec;
|
||||
return s;
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
std::istream& operator>> (std::istream& s, Hash<N>& h)
|
||||
{
|
||||
std::array<char, h.size()*2> dat;
|
||||
s.exceptions(std::istream::eofbit | std::istream::failbit);
|
||||
s.read(&(*dat.begin()), dat.size());
|
||||
for (size_t i = 0; i < h.size(); i++) {
|
||||
unsigned res = 0;
|
||||
sscanf(dat.data() + 2*i, "%02x", &res);
|
||||
h[i] = res;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
using h256 = Hash<32>;
|
||||
using PkId = h256;
|
||||
|
||||
/**
|
||||
* Represents an InfoHash.
|
||||
* An InfoHash is a byte array of HASH_LEN bytes.
|
||||
* InfoHashes identify nodes and values in the Dht.
|
||||
*/
|
||||
class InfoHash final : public std::array<uint8_t, HASH_LEN> {
|
||||
class OPENDHT_PUBLIC InfoHash final : public std::array<uint8_t, HASH_LEN> {
|
||||
public:
|
||||
constexpr InfoHash() : std::array<uint8_t, HASH_LEN>() {}
|
||||
constexpr InfoHash(const std::array<uint8_t, HASH_LEN>& h) : std::array<uint8_t, HASH_LEN>(h) {}
|
||||
@@ -94,7 +180,7 @@ public:
|
||||
* Forget about the ``XOR-metric''. An id is just a path from the
|
||||
* root of the tree, so bits are numbered from the start.
|
||||
*/
|
||||
static inline int cmp(const InfoHash& __restrict__ id1, const InfoHash& __restrict__ id2) {
|
||||
static inline int cmp(const InfoHash& id1, const InfoHash& id2) {
|
||||
return std::memcmp(id1.data(), id2.data(), HASH_LEN);
|
||||
}
|
||||
|
||||
@@ -190,7 +276,8 @@ public:
|
||||
|
||||
static InfoHash getRandom();
|
||||
|
||||
friend std::ostream& operator<< (std::ostream& s, const InfoHash& h);
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const InfoHash& h);
|
||||
OPENDHT_PUBLIC friend std::istream& operator>> (std::istream& s, InfoHash& h);
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
|
||||
+10
-40
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
|
||||
namespace dht {
|
||||
namespace log {
|
||||
@@ -61,48 +62,17 @@ constexpr const Color::Modifier yellow(Color::FG_YELLOW);
|
||||
/**
|
||||
* Print va_list to std::ostream (used for logging).
|
||||
*/
|
||||
void
|
||||
printLog(std::ostream& s, char const* m, va_list args) {
|
||||
static constexpr int BUF_SZ = 8192;
|
||||
char buffer[BUF_SZ];
|
||||
int ret = vsnprintf(buffer, sizeof(buffer), m, args);
|
||||
if (ret < 0)
|
||||
return;
|
||||
s.write(buffer, std::min(ret, BUF_SZ));
|
||||
if (ret >= BUF_SZ)
|
||||
s << "[[TRUNCATED]]";
|
||||
s.put('\n');
|
||||
}
|
||||
OPENDHT_PUBLIC void
|
||||
printLog(std::ostream &s, char const *m, va_list args);
|
||||
|
||||
void
|
||||
enableLogging(dht::DhtRunner& dht)
|
||||
{
|
||||
dht.setLoggers(
|
||||
[](char const* m, va_list args){ std::cerr << red; printLog(std::cerr, m, args); std::cerr << def; },
|
||||
[](char const* m, va_list args){ std::cout << yellow; printLog(std::cout, m, args); std::cout << def; },
|
||||
[](char const* m, va_list args){ printLog(std::cout, m, args); }
|
||||
);
|
||||
}
|
||||
OPENDHT_PUBLIC void
|
||||
enableLogging(dht::DhtRunner &dht);
|
||||
|
||||
void
|
||||
enableFileLogging(dht::DhtRunner& dht, const std::string& path)
|
||||
{
|
||||
auto logfile = std::make_shared<std::fstream>();
|
||||
logfile->open(path, std::ios::out);
|
||||
OPENDHT_PUBLIC void
|
||||
enableFileLogging(dht::DhtRunner &dht, const std::string &path);
|
||||
|
||||
dht.setLoggers(
|
||||
[=](char const* m, va_list args){ printLog(*logfile, m, args); },
|
||||
[=](char const* m, va_list args){ printLog(*logfile, m, args); },
|
||||
[=](char const* m, va_list args){ printLog(*logfile, m, args); }
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
disableLogging(dht::DhtRunner& dht)
|
||||
{
|
||||
dht.setLoggers(dht::NOLOG, dht::NOLOG, dht::NOLOG);
|
||||
}
|
||||
OPENDHT_PUBLIC void
|
||||
disableLogging(dht::DhtRunner &dht);
|
||||
|
||||
} /* log */
|
||||
} /* dht */
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "infohash.h"
|
||||
|
||||
#ifndef OPENDHT_LOG
|
||||
#define OPENDHT_LOG true
|
||||
#endif
|
||||
|
||||
namespace dht {
|
||||
|
||||
// Logging related utility functions
|
||||
|
||||
/**
|
||||
* Dummy function used to disable logging
|
||||
*/
|
||||
inline void NOLOG(char const*, va_list) {}
|
||||
|
||||
/**
|
||||
* Wrapper for logging methods
|
||||
*/
|
||||
struct LogMethod {
|
||||
LogMethod() = default;
|
||||
|
||||
template<typename T>
|
||||
LogMethod(T&& t) : func(std::forward<T>(t)) {}
|
||||
|
||||
void operator()(char const* format, ...) const {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
func(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
void log(char const* format, va_list args) const {
|
||||
func(format, args);
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return (bool)func;
|
||||
}
|
||||
|
||||
void logPrintable(const uint8_t *buf, size_t buflen) const {
|
||||
std::string buf_clean(buflen, '\0');
|
||||
for (size_t i=0; i<buflen; i++)
|
||||
buf_clean[i] = isprint(buf[i]) ? buf[i] : '.';
|
||||
(*this)("%s", buf_clean.c_str());
|
||||
}
|
||||
private:
|
||||
std::function<void(char const*, va_list)> func;
|
||||
};
|
||||
|
||||
struct Logger {
|
||||
LogMethod DEBUG = NOLOG;
|
||||
LogMethod WARN = NOLOG;
|
||||
LogMethod ERR = NOLOG;
|
||||
void setFilter(const InfoHash& f) {
|
||||
filter_ = f;
|
||||
filterEnable_ = filter_ != InfoHash{};
|
||||
}
|
||||
inline void log0(const LogMethod& logger, char const* format, va_list args) const {
|
||||
#if OPENDHT_LOG
|
||||
if (logger and not filterEnable_)
|
||||
logger.log(format, args);
|
||||
#endif
|
||||
}
|
||||
inline void log1(const LogMethod& logger, const InfoHash& f, char const* format, va_list args) const {
|
||||
#if OPENDHT_LOG
|
||||
if (logger and (not filterEnable_ or f == filter_))
|
||||
logger.log(format, args);
|
||||
#endif
|
||||
}
|
||||
inline void log2(const LogMethod& logger, const InfoHash& f1, const InfoHash& f2, char const* format, va_list args) const {
|
||||
#if OPENDHT_LOG
|
||||
if (logger and (not filterEnable_ or f1 == filter_ or f2 == filter_))
|
||||
logger.log(format, args);
|
||||
#endif
|
||||
}
|
||||
inline void d(char const* format, ...) const {
|
||||
#if OPENDHT_LOG
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log0(DEBUG, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
inline void d(const InfoHash& f, char const* format, ...) const {
|
||||
#if OPENDHT_LOG
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log1(DEBUG, f, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
inline void d(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
|
||||
#if OPENDHT_LOG
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log2(DEBUG, f1, f2, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
inline void w(char const* format, ...) const {
|
||||
#if OPENDHT_LOG
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log0(WARN, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
inline void w(const InfoHash& f, char const* format, ...) const {
|
||||
#if OPENDHT_LOG
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log1(WARN, f, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
inline void w(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
|
||||
#if OPENDHT_LOG
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log2(WARN, f1, f2, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
inline void e(char const* format, ...) const {
|
||||
#if OPENDHT_LOG
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log0(ERR, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
inline void e(const InfoHash& f, char const* format, ...) const {
|
||||
#if OPENDHT_LOG
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log1(ERR, f, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
inline void e(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
|
||||
#if OPENDHT_LOG
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log2(ERR, f1, f2, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
bool filterEnable_ {false};
|
||||
InfoHash filter_ {};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace dht {
|
||||
namespace net {
|
||||
|
||||
struct TransPrefix : public std::array<uint8_t, 2> {
|
||||
TransPrefix(const std::string& str) : std::array<uint8_t, 2>({{(uint8_t)str[0], (uint8_t)str[1]}}) {}
|
||||
static const TransPrefix PING;
|
||||
static const TransPrefix FIND_NODE;
|
||||
static const TransPrefix GET_VALUES;
|
||||
static const TransPrefix ANNOUNCE_VALUES;
|
||||
static const TransPrefix REFRESH;
|
||||
static const TransPrefix LISTEN;
|
||||
};
|
||||
|
||||
/* Transaction-ids are 4-bytes long, with the first two bytes identifying
|
||||
* the kind of request, and the remaining two a sequence number in
|
||||
* host order.
|
||||
*/
|
||||
struct TransId final : public std::array<uint8_t, 4> {
|
||||
static const constexpr uint16_t INVALID {0};
|
||||
|
||||
TransId() { std::fill_n(begin(), 4, 0); }
|
||||
TransId(const std::array<char, 4>& o) { std::copy(o.begin(), o.end(), begin()); }
|
||||
TransId(const TransPrefix prefix, uint16_t seqno = 0) {
|
||||
std::copy_n(prefix.begin(), prefix.size(), begin());
|
||||
*reinterpret_cast<uint16_t*>(data()+prefix.size()) = seqno;
|
||||
}
|
||||
|
||||
TransId(const char* q, size_t l) : array<uint8_t, 4>() {
|
||||
if (l > 4) {
|
||||
length = 0;
|
||||
} else {
|
||||
std::copy_n(q, l, begin());
|
||||
length = l;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getTid() const {
|
||||
return *reinterpret_cast<const uint16_t*>(&(*this)[2]);
|
||||
}
|
||||
|
||||
uint32_t toInt() const {
|
||||
return *reinterpret_cast<const uint32_t*>(&(*this)[0]);
|
||||
}
|
||||
|
||||
bool matches(const TransPrefix prefix, uint16_t* tid = nullptr) const {
|
||||
if (std::equal(begin(), begin()+2, prefix.begin())) {
|
||||
if (tid)
|
||||
*tid = getTid();
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned length {4};
|
||||
};
|
||||
|
||||
} /* namespace net */
|
||||
} /* dht */
|
||||
+347
-211
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,11 +14,9 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "node_cache.h"
|
||||
@@ -28,6 +26,8 @@
|
||||
#include "scheduler.h"
|
||||
#include "utils.h"
|
||||
#include "rng.h"
|
||||
#include "rate_limiter.h"
|
||||
#include "net.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -38,6 +38,10 @@
|
||||
#include <queue>
|
||||
|
||||
namespace dht {
|
||||
namespace net {
|
||||
|
||||
struct Request;
|
||||
struct Socket;
|
||||
|
||||
#ifndef MSG_CONFIRM
|
||||
#define MSG_CONFIRM 0
|
||||
@@ -48,6 +52,7 @@ public:
|
||||
// sent to another peer (http-like).
|
||||
static const constexpr uint16_t NON_AUTHORITATIVE_INFORMATION {203}; /* incomplete request packet. */
|
||||
static const constexpr uint16_t UNAUTHORIZED {401}; /* wrong tokens. */
|
||||
static const constexpr uint16_t NOT_FOUND {404}; /* storage not found */
|
||||
// for internal use (custom).
|
||||
static const constexpr uint16_t INVALID_TID_SIZE {421}; /* id was truncated. */
|
||||
static const constexpr uint16_t UNKNOWN_TID {422}; /* unknown tid */
|
||||
@@ -58,6 +63,7 @@ public:
|
||||
static const std::string LISTEN_WRONG_TOKEN; /* wrong token in "listen" request */
|
||||
static const std::string PUT_NO_INFOHASH; /* no infohash in "put" request */
|
||||
static const std::string PUT_WRONG_TOKEN; /* got "put" request with wrong token */
|
||||
static const std::string STORAGE_NOT_FOUND; /* got access request for an unknown storage */
|
||||
static const std::string PUT_INVALID_ID; /* invalid id in "put" request */
|
||||
|
||||
DhtProtocolException(uint16_t code, const std::string& msg="", InfoHash failing_node_id={})
|
||||
@@ -91,57 +97,11 @@ struct ParsedMessage;
|
||||
* @param onGetValues callback for "get values" request.
|
||||
* @param onListen callback for "listen" request.
|
||||
* @param onAnnounce callback for "announce" request.
|
||||
* @param onRefresh callback for "refresh" request.
|
||||
*/
|
||||
class NetworkEngine final {
|
||||
struct TransPrefix : public std::array<uint8_t, 2> {
|
||||
TransPrefix(const std::string& str) : std::array<uint8_t, 2>({{(uint8_t)str[0], (uint8_t)str[1]}}) {}
|
||||
static const TransPrefix PING;
|
||||
static const TransPrefix FIND_NODE;
|
||||
static const TransPrefix GET_VALUES;
|
||||
static const TransPrefix ANNOUNCE_VALUES;
|
||||
static const TransPrefix LISTEN;
|
||||
};
|
||||
class NetworkEngine final
|
||||
{
|
||||
public:
|
||||
|
||||
/* Transaction-ids are 4-bytes long, with the first two bytes identifying
|
||||
* the kind of request, and the remaining two a sequence number in
|
||||
* host order.
|
||||
*/
|
||||
struct TransId final : public std::array<uint8_t, 4> {
|
||||
static const constexpr uint16_t INVALID {0};
|
||||
|
||||
TransId() {}
|
||||
TransId(const std::array<char, 4>& o) { std::copy(o.begin(), o.end(), begin()); }
|
||||
TransId(const TransPrefix prefix, uint16_t seqno = 0) {
|
||||
std::copy_n(prefix.begin(), prefix.size(), begin());
|
||||
*reinterpret_cast<uint16_t*>(data()+prefix.size()) = seqno;
|
||||
}
|
||||
|
||||
TransId(const char* q, size_t l) : array<uint8_t, 4>() {
|
||||
if (l > 4) {
|
||||
length = 0;
|
||||
} else {
|
||||
std::copy_n(q, l, begin());
|
||||
length = l;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getTid() const {
|
||||
return *reinterpret_cast<const uint16_t*>(&(*this)[2]);
|
||||
}
|
||||
|
||||
bool matches(const TransPrefix prefix, uint16_t* tid = nullptr) const {
|
||||
if (std::equal(begin(), begin()+2, prefix.begin())) {
|
||||
if (tid)
|
||||
*tid = getTid();
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned length {4};
|
||||
};
|
||||
|
||||
/*!
|
||||
* @class RequestAnswer
|
||||
* @brief Answer for a request.
|
||||
@@ -152,111 +112,106 @@ public:
|
||||
struct RequestAnswer {
|
||||
Blob ntoken {};
|
||||
Value::Id vid {};
|
||||
std::vector<std::shared_ptr<Value>> values {};
|
||||
std::vector<std::shared_ptr<Node>> nodes4 {};
|
||||
std::vector<std::shared_ptr<Node>> nodes6 {};
|
||||
std::vector<Sp<Value>> values {};
|
||||
std::vector<Sp<FieldValueIndex>> fields {};
|
||||
std::vector<Sp<Node>> nodes4 {};
|
||||
std::vector<Sp<Node>> nodes6 {};
|
||||
RequestAnswer() {}
|
||||
RequestAnswer(ParsedMessage&& msg);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cancel a request. Setting req->cancelled = true is not enough in the case
|
||||
* a request is "persistent".
|
||||
*/
|
||||
void cancelRequest(std::shared_ptr<Request>& req);
|
||||
|
||||
void connectivityChanged();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called when we receive an error message.
|
||||
*/
|
||||
std::function<void(Sp<Request>, DhtProtocolException)> onError;
|
||||
|
||||
/**
|
||||
* @brief when we receive an error message.
|
||||
*
|
||||
* @param node (type: std::shared_ptr<Request>) the associated request for
|
||||
* which we got an error;
|
||||
*/
|
||||
std::function<void(std::shared_ptr<Request>, DhtProtocolException)> onError;
|
||||
/**
|
||||
* @brief when a new node happens.
|
||||
*
|
||||
* Called for every packets received for handling new nodes contacting us.
|
||||
*
|
||||
* @param id (type: InfoHash) id of the node.
|
||||
* @param saddr (type: sockaddr*) sockaddr* pointer containing address ip information.
|
||||
* @param saddr_len (type: socklen_t) lenght of the sockaddr struct.
|
||||
* @param confirm (type: int) 1 if the node sent a message, 2 if it sent us a reply.
|
||||
* @param node: the node
|
||||
* @param confirm: 1 if the node sent a message, 2 if it sent us a reply.
|
||||
*/
|
||||
std::function<void(const std::shared_ptr<Node>&, int)> onNewNode;
|
||||
std::function<void(const Sp<Node>&, int)> onNewNode;
|
||||
/**
|
||||
* @brief when an addres is reported from a distant node.
|
||||
* Called when an addres is reported from a requested node.
|
||||
*
|
||||
* @param id (type: InfoHash) id of the node.
|
||||
* @param saddr (type: sockaddr*) sockaddr* pointer containing address ip information.
|
||||
* @param h: id
|
||||
* @param saddr_len (type: socklen_t) lenght of the sockaddr struct.
|
||||
*/
|
||||
std::function<void(const InfoHash&, sockaddr*, socklen_t)> onReportedAddr;
|
||||
std::function<void(const InfoHash&, const SockAddr&)> onReportedAddr;
|
||||
/**
|
||||
* @brief on ping request callback.
|
||||
* Called on ping reception.
|
||||
*
|
||||
* @param node (type: std::shared_ptr<Node>) the requesting node.
|
||||
* @param node (type: Sp<Node>) the requesting node.
|
||||
*/
|
||||
std::function<RequestAnswer(std::shared_ptr<Node>)> onPing {};
|
||||
std::function<RequestAnswer(Sp<Node>)> onPing {};
|
||||
/**
|
||||
* @brief on find node request callback.
|
||||
* Called on find node request.
|
||||
*
|
||||
* @param node (type: std::shared_ptr<Node>) the requesting node.
|
||||
* @param vhash (type: InfoHash) hash of the value of interest.
|
||||
* @param node (type: Sp<Node>) the requesting node.
|
||||
* @param h (type: InfoHash) hash of the value of interest.
|
||||
* @param want (type: want_t) states if nodes sent in the response are ipv4
|
||||
* or ipv6.
|
||||
*/
|
||||
std::function<RequestAnswer(std::shared_ptr<Node>,
|
||||
InfoHash&,
|
||||
want_t)> onFindNode {};
|
||||
std::function<RequestAnswer(Sp<Node>, const InfoHash&, want_t)> onFindNode {};
|
||||
/**
|
||||
* @brief on "get values" request callback.
|
||||
* Called on "get values" request.
|
||||
*
|
||||
* @param node (type: std::shared_ptr<Node>) the requesting node.
|
||||
* @param vhash (type: InfoHash) hash of the value of interest.
|
||||
* @param node (type: Sp<Node>) the requesting node.
|
||||
* @param h (type: InfoHash) hash of the value of interest.
|
||||
* @param want (type: want_t) states if nodes sent in the response are ipv4
|
||||
* or ipv6.
|
||||
*/
|
||||
std::function<RequestAnswer(std::shared_ptr<Node>,
|
||||
InfoHash&,
|
||||
want_t)> onGetValues {};
|
||||
std::function<RequestAnswer(Sp<Node>, const InfoHash&, want_t, const Query&)> onGetValues {};
|
||||
/**
|
||||
* @brief on listen request callback.
|
||||
* Called on listen request.
|
||||
*
|
||||
* @param node (type: std::shared_ptr<Node>) the requesting node.
|
||||
* @param vhash (type: InfoHash) hash of the value of interest.
|
||||
* @param node (type: Sp<Node>) the requesting node.
|
||||
* @param h (type: InfoHash) hash of the value of interest.
|
||||
* @param token (type: Blob) security token.
|
||||
* @param rid (type: uint16_t) request id.
|
||||
*/
|
||||
std::function<RequestAnswer(std::shared_ptr<Node>,
|
||||
InfoHash&,
|
||||
Blob&,
|
||||
uint16_t)> onListen {};
|
||||
std::function<RequestAnswer(Sp<Node>,
|
||||
const InfoHash&,
|
||||
const Blob&,
|
||||
uint32_t,
|
||||
const Query&)> onListen {};
|
||||
/**
|
||||
* @brief on announce request callback.
|
||||
* Called on announce request.
|
||||
*
|
||||
* @param node (type: std::shared_ptr<Node>) the requesting node.
|
||||
* @param vhash (type: InfoHash) hash of the value of interest.
|
||||
* @param node (type: Sp<Node>) the requesting node.
|
||||
* @param h (type: InfoHash) hash of the value of interest.
|
||||
* @param token (type: Blob) security token.
|
||||
* @param values (type: std::vector<std::shared_ptr<Value>>) values to store.
|
||||
* @param values (type: std::vector<Sp<Value>>) values to store.
|
||||
* @param created (type: time_point) time when the value was created.
|
||||
*/
|
||||
std::function<RequestAnswer(std::shared_ptr<Node>,
|
||||
InfoHash&,
|
||||
Blob&,
|
||||
std::vector<std::shared_ptr<Value>>,
|
||||
time_point)> onAnnounce {};
|
||||
std::function<RequestAnswer(Sp<Node>,
|
||||
const InfoHash&,
|
||||
const Blob&,
|
||||
const std::vector<Sp<Value>>&,
|
||||
const time_point&)> onAnnounce {};
|
||||
/**
|
||||
* Called on refresh request.
|
||||
*
|
||||
* @param node (type: Sp<Node>) the requesting node.
|
||||
* @param h (type: InfoHash) hash of the value of interest.
|
||||
* @param token (type: Blob) security token.
|
||||
* @param vid (type: Value::id) the value id.
|
||||
*/
|
||||
std::function<RequestAnswer(Sp<Node>,
|
||||
const InfoHash&,
|
||||
const Blob&,
|
||||
const Value::Id&)> onRefresh {};
|
||||
|
||||
public:
|
||||
using SocketCb = std::function<void(const Sp<Node>&, RequestAnswer&&)>;
|
||||
using RequestCb = std::function<void(const Request&, RequestAnswer&&)>;
|
||||
using RequestExpiredCb = std::function<void(const Request&, bool)>;
|
||||
|
||||
NetworkEngine(Logger& log, Scheduler& scheduler) : myid(zeroes), DHT_LOG(log), scheduler(scheduler) {}
|
||||
NetworkEngine(InfoHash& myid, int s, int s6, Logger& log, Scheduler& scheduler,
|
||||
NetworkEngine(Logger& log, Scheduler& scheduler);
|
||||
NetworkEngine(InfoHash& myid, NetId net, int s, int s6, Logger& log, Scheduler& scheduler,
|
||||
decltype(NetworkEngine::onError) onError,
|
||||
decltype(NetworkEngine::onNewNode) onNewNode,
|
||||
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
|
||||
@@ -264,74 +219,196 @@ public:
|
||||
decltype(NetworkEngine::onFindNode) onFindNode,
|
||||
decltype(NetworkEngine::onGetValues) onGetValues,
|
||||
decltype(NetworkEngine::onListen) onListen,
|
||||
decltype(NetworkEngine::onAnnounce) onAnnounce) :
|
||||
onError(onError), onNewNode(onNewNode), onReportedAddr(onReportedAddr), onPing(onPing), onFindNode(onFindNode),
|
||||
onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), myid(myid),
|
||||
dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
|
||||
{
|
||||
transaction_id = std::uniform_int_distribution<decltype(transaction_id)>{1}(rd_device);
|
||||
}
|
||||
virtual ~NetworkEngine() {
|
||||
clear();
|
||||
};
|
||||
decltype(NetworkEngine::onAnnounce) onAnnounce,
|
||||
decltype(NetworkEngine::onRefresh) onRefresh);
|
||||
|
||||
virtual ~NetworkEngine();
|
||||
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Sends values (with closest nodes) to a listenner.
|
||||
*
|
||||
* @param sa The address of the listenner.
|
||||
* @param sslen The length of the sockaddr structure.
|
||||
* @param rid The request id of the initial listen request.
|
||||
* @param hash The hash key of the value.
|
||||
* @param want Wether to send ipv4 and/or ipv6 nodes.
|
||||
* @param ntoken Listen security token.
|
||||
* @param nodes The ipv4 closest nodes.
|
||||
* @param nodes6 The ipv6 closest nodes.
|
||||
* @param values The values to send.
|
||||
* @param sa The address of the listenner.
|
||||
* @param sslen The length of the sockaddr structure.
|
||||
* @param socket_id The tid to use to write to the request socket.
|
||||
* @param hash The hash key of the value.
|
||||
* @param want Wether to send ipv4 and/or ipv6 nodes.
|
||||
* @param ntoken Listen security token.
|
||||
* @param nodes The ipv4 closest nodes.
|
||||
* @param nodes6 The ipv6 closest nodes.
|
||||
* @param values The values to send.
|
||||
*/
|
||||
void tellListener(std::shared_ptr<Node> n, uint16_t rid, InfoHash hash, want_t want, Blob ntoken,
|
||||
std::vector<std::shared_ptr<Node>> nodes, std::vector<std::shared_ptr<Node>> nodes6,
|
||||
std::vector<std::shared_ptr<Value>> values);
|
||||
void tellListener(Sp<Node> n, uint32_t socket_id, const InfoHash& hash, want_t want, const Blob& ntoken,
|
||||
std::vector<Sp<Node>>&& nodes, std::vector<Sp<Node>>&& nodes6,
|
||||
std::vector<Sp<Value>>&& values, const Query& q);
|
||||
|
||||
bool isRunning(sa_family_t af) const;
|
||||
inline want_t want () const { return dht_socket >= 0 && dht_socket6 >= 0 ? (WANT4 | WANT6) : -1; }
|
||||
|
||||
/**
|
||||
* Cancel a request. Setting req->cancelled = true is not enough in the case
|
||||
* a request is "persistent".
|
||||
*/
|
||||
void cancelRequest(Sp<Request>& req);
|
||||
|
||||
void connectivityChanged(sa_family_t);
|
||||
|
||||
/**************
|
||||
* Requests *
|
||||
**************/
|
||||
std::shared_ptr<Request>
|
||||
sendPing(std::shared_ptr<Node> n, RequestCb on_done, RequestExpiredCb on_expired);
|
||||
std::shared_ptr<Request>
|
||||
sendPing(const sockaddr* sa, socklen_t salen, RequestCb on_done, RequestExpiredCb on_expired) {
|
||||
return sendPing(std::make_shared<Node>(zeroes, sa, salen), on_done, on_expired);
|
||||
|
||||
/**
|
||||
* Send a "ping" request to a given node.
|
||||
*
|
||||
* @param n The node.
|
||||
* @param on_done Request callback when the request is completed.
|
||||
* @param on_expired Request callback when the request expires.
|
||||
*
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request>
|
||||
sendPing(Sp<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
|
||||
/**
|
||||
* Send a "ping" request to a given node.
|
||||
*
|
||||
* @param sa The node's ip sockaddr info.
|
||||
* @param salen The associated sockaddr struct length.
|
||||
* @param on_done Request callback when the request is completed.
|
||||
* @param on_expired Request callback when the request expires.
|
||||
*
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request>
|
||||
sendPing(const sockaddr* sa, socklen_t salen, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
|
||||
return sendPing(std::make_shared<Node>(zeroes, sa, salen),
|
||||
std::forward<RequestCb>(on_done),
|
||||
std::forward<RequestExpiredCb>(on_expired));
|
||||
}
|
||||
std::shared_ptr<Request>
|
||||
sendFindNode(std::shared_ptr<Node> n,
|
||||
const InfoHash& target,
|
||||
want_t want,
|
||||
RequestCb on_done,
|
||||
RequestExpiredCb on_expired);
|
||||
std::shared_ptr<Request>
|
||||
sendGetValues(std::shared_ptr<Node> n,
|
||||
const InfoHash& target,
|
||||
want_t want,
|
||||
RequestCb on_done,
|
||||
RequestExpiredCb on_expired);
|
||||
std::shared_ptr<Request>
|
||||
sendListen(std::shared_ptr<Node> n,
|
||||
const InfoHash& infohash,
|
||||
const Blob& token,
|
||||
RequestCb on_done,
|
||||
RequestExpiredCb on_expired);
|
||||
std::shared_ptr<Request>
|
||||
sendAnnounceValue(std::shared_ptr<Node> n,
|
||||
const InfoHash& infohash,
|
||||
const Value& v,
|
||||
time_point created,
|
||||
const Blob& token,
|
||||
RequestCb on_done,
|
||||
RequestExpiredCb on_expired);
|
||||
/**
|
||||
* Send a "find node" request to a given node.
|
||||
*
|
||||
* @param n The node.
|
||||
* @param target The target hash.
|
||||
* @param want Indicating wether IPv4 or IPv6 are wanted in response.
|
||||
* Use NetworkEngine::want()
|
||||
* @param on_done Request callback when the request is completed.
|
||||
* @param on_expired Request callback when the request expires.
|
||||
*
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request> sendFindNode(Sp<Node> n,
|
||||
const InfoHash& hash,
|
||||
want_t want,
|
||||
RequestCb&& on_done,
|
||||
RequestExpiredCb&& on_expired);
|
||||
/**
|
||||
* Send a "get" request to a given node.
|
||||
*
|
||||
* @param n The node.
|
||||
* @param hash The target hash.
|
||||
* @param query The query describing filters.
|
||||
* @param token A security token.
|
||||
* @param want Indicating wether IPv4 or IPv6 are wanted in response.
|
||||
* Use NetworkEngine::want()
|
||||
* @param on_done Request callback when the request is completed.
|
||||
* @param on_expired Request callback when the request expires.
|
||||
*
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request> sendGetValues(Sp<Node> n,
|
||||
const InfoHash& hash,
|
||||
const Query& query,
|
||||
want_t want,
|
||||
RequestCb&& on_done,
|
||||
RequestExpiredCb&& on_expired);
|
||||
/**
|
||||
* Send a "listen" request to a given node.
|
||||
*
|
||||
* @param n The node.
|
||||
* @param hash The storage's hash.
|
||||
* @param query The query describing filters.
|
||||
* @param token A security token.
|
||||
* @param previous The previous request "listen" sent to this node.
|
||||
* @param socket **UNUSED** The socket for further response.
|
||||
*
|
||||
* For backward compatibility purpose, sendListen has to
|
||||
* handle creation of the socket. Therefor, you cannot
|
||||
* use openSocket yourself. TODO: Once we don't support
|
||||
* the old "listen" negociation, sendListen shall not
|
||||
* create the socket itself.
|
||||
*
|
||||
* @param on_done Request callback when the request is completed.
|
||||
* @param on_expired Request callback when the request expires.
|
||||
* @param socket_cb Callback to execute each time new updates arrive on
|
||||
* the socket.
|
||||
*
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request> sendListen(Sp<Node> n,
|
||||
const InfoHash& hash,
|
||||
const Query& query,
|
||||
const Blob& token,
|
||||
Sp<Request> previous,
|
||||
RequestCb&& on_done,
|
||||
RequestExpiredCb&& on_expired,
|
||||
SocketCb&& socket_cb);
|
||||
/**
|
||||
* Send a "announce" request to a given node.
|
||||
*
|
||||
* @param n The node.
|
||||
* @param hash The target hash.
|
||||
* @param created The time when the value was created (avoiding extended
|
||||
* value lifetime)
|
||||
* @param token A security token.
|
||||
* @param on_done Request callback when the request is completed.
|
||||
* @param on_expired Request callback when the request expires.
|
||||
*
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request> sendAnnounceValue(Sp<Node> n,
|
||||
const InfoHash& hash,
|
||||
const Sp<Value>& v,
|
||||
time_point created,
|
||||
const Blob& token,
|
||||
RequestCb&& on_done,
|
||||
RequestExpiredCb&& on_expired);
|
||||
/**
|
||||
* Send a "refresh" request to a given node. Asks a node to keep the
|
||||
* associated value Value.type.expiration more minutes in its storage.
|
||||
*
|
||||
* @param n The node.
|
||||
* @param hash The target hash.
|
||||
* @param vid The value id.
|
||||
* @param token A security token.
|
||||
* @param on_done Request callback when the request is completed.
|
||||
* @param on_expired Request callback when the request expires.
|
||||
*
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request> sendRefreshValue(Sp<Node> n,
|
||||
const InfoHash& hash,
|
||||
const Value::Id& vid,
|
||||
const Blob& token,
|
||||
RequestCb&& on_done,
|
||||
RequestExpiredCb&& on_expired);
|
||||
/**
|
||||
* Opens a socket on which a node will be able allowed to write for further
|
||||
* additionnal updates following the response to a previous request.
|
||||
*
|
||||
* @param node The node which will be allowed to write on this socket.
|
||||
* @param cb The callback to execute once updates arrive on the socket.
|
||||
*
|
||||
* @return the socket.
|
||||
*/
|
||||
Sp<Socket> openSocket(const Sp<Node>& node, TransPrefix tp, SocketCb&& cb);
|
||||
|
||||
/**
|
||||
* Closes a socket so that no further data will be red on that socket.
|
||||
*
|
||||
* @param socket The socket to close.
|
||||
*/
|
||||
void closeSocket(Sp<Socket> socket);
|
||||
|
||||
/**
|
||||
* Parses a message and calls appropriate callbacks.
|
||||
@@ -342,10 +419,12 @@ 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* from, socklen_t fromlen);
|
||||
void processMessage(const uint8_t *buf, size_t buflen, const SockAddr& addr);
|
||||
|
||||
std::shared_ptr<Node> insertNode(const InfoHash& myid, const sockaddr* from, socklen_t fromlen) {
|
||||
return cache.getNode(myid, from, fromlen, scheduler.time(), 0);
|
||||
Sp<Node> insertNode(const InfoHash& myid, const SockAddr& addr) {
|
||||
auto n = cache.getNode(myid, addr, scheduler.time(), 0);
|
||||
onNewNode(n, 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
std::vector<unsigned> getNodeMessageStats(bool in) {
|
||||
@@ -355,9 +434,16 @@ public:
|
||||
return stats;
|
||||
}
|
||||
|
||||
void blacklistNode(const std::shared_ptr<Node>& n);
|
||||
void blacklistNode(const Sp<Node>& n);
|
||||
|
||||
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) {
|
||||
return cache.getCachedNodes(id, sa_f, count);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct PartialMessage;
|
||||
|
||||
/***************
|
||||
* Constants *
|
||||
***************/
|
||||
@@ -366,36 +452,37 @@ private:
|
||||
static const constexpr size_t NODE4_INFO_BUF_LEN {26};
|
||||
/* the length of a node info buffer in ipv6 format */
|
||||
static const constexpr size_t NODE6_INFO_BUF_LEN {38};
|
||||
/* TODO */
|
||||
/* after a UDP reply, the period during which we tell the link layer about it */
|
||||
static constexpr std::chrono::seconds UDP_REPLY_TIME {15};
|
||||
|
||||
/* Max. time to receive a full fragmented packet */
|
||||
static constexpr std::chrono::seconds RX_MAX_PACKET_TIME {10};
|
||||
/* Max. time between packet fragments */
|
||||
static constexpr std::chrono::seconds RX_TIMEOUT {3};
|
||||
/* The maximum number of nodes that we snub. There is probably little
|
||||
reason to increase this value. */
|
||||
static constexpr unsigned BLACKLISTED_MAX {10};
|
||||
/* TODO */
|
||||
|
||||
static constexpr size_t MTU {1280};
|
||||
static constexpr size_t MAX_PACKET_VALUE_SIZE {8 * 1024};
|
||||
|
||||
static const std::string my_v;
|
||||
static std::mt19937 rd_device;
|
||||
|
||||
/* DHT info */
|
||||
const InfoHash& myid;
|
||||
const int dht_socket {-1};
|
||||
const int dht_socket6 {-1};
|
||||
const Logger& DHT_LOG;
|
||||
void process(std::unique_ptr<ParsedMessage>&&, const SockAddr& from);
|
||||
|
||||
NodeCache cache {};
|
||||
sockaddr_storage blacklist[BLACKLISTED_MAX] {};
|
||||
unsigned next_blacklisted = 0;
|
||||
bool rateLimit(const SockAddr& addr);
|
||||
|
||||
bool rateLimit();
|
||||
static bool isMartian(const SockAddr& addr);
|
||||
bool isNodeBlacklisted(const SockAddr& addr) const;
|
||||
|
||||
static bool isMartian(const sockaddr* sa, socklen_t len);
|
||||
bool isNodeBlacklisted(const sockaddr*, socklen_t) const;
|
||||
|
||||
void requestStep(std::shared_ptr<Request> req);
|
||||
void requestStep(Sp<Request> req);
|
||||
|
||||
/**
|
||||
* Sends a request to a node. Request::MAX_ATTEMPT_COUNT attempts will
|
||||
* be made before the request expires.
|
||||
*/
|
||||
void sendRequest(std::shared_ptr<Request>& request);
|
||||
void sendRequest(Sp<Request>& request);
|
||||
|
||||
/**
|
||||
* Generates a new request id, skipping the invalid id.
|
||||
@@ -408,60 +495,109 @@ private:
|
||||
}
|
||||
|
||||
struct MessageStats {
|
||||
unsigned ping {0};
|
||||
unsigned find {0};
|
||||
unsigned get {0};
|
||||
unsigned put {0};
|
||||
unsigned listen {0};
|
||||
unsigned ping {0};
|
||||
unsigned find {0};
|
||||
unsigned get {0};
|
||||
unsigned put {0};
|
||||
unsigned listen {0};
|
||||
unsigned refresh {0};
|
||||
};
|
||||
|
||||
|
||||
// basic wrapper for socket sendto function
|
||||
int send(const char *buf, size_t len, int flags, const sockaddr *sa, socklen_t salen);
|
||||
int send(const char *buf, size_t len, int flags, const SockAddr& addr);
|
||||
|
||||
void sendValueParts(TransId tid, const std::vector<Blob>& svals, const SockAddr& addr);
|
||||
std::vector<Blob> packValueHeader(msgpack::sbuffer&, const std::vector<Sp<Value>>&);
|
||||
void maintainRxBuffer(const TransId& tid);
|
||||
|
||||
/*************
|
||||
* Answers *
|
||||
*************/
|
||||
/* answer to a ping request */
|
||||
void sendPong(const sockaddr* sa, socklen_t salen, TransId tid);
|
||||
void sendPong(const SockAddr& addr, TransId tid);
|
||||
/* answer to findnodes/getvalues request */
|
||||
void sendNodesValues(const sockaddr* sa,
|
||||
socklen_t salen,
|
||||
void sendNodesValues(const SockAddr& addr,
|
||||
TransId tid,
|
||||
const Blob& nodes,
|
||||
const Blob& nodes6,
|
||||
const std::vector<std::shared_ptr<Value>>& st,
|
||||
const std::vector<Sp<Value>>& st,
|
||||
const Query& query,
|
||||
const Blob& token);
|
||||
Blob bufferNodes(sa_family_t af, const InfoHash& id, std::vector<std::shared_ptr<Node>>& nodes);
|
||||
Blob bufferNodes(sa_family_t af, const InfoHash& id, std::vector<Sp<Node>>& nodes);
|
||||
|
||||
std::pair<Blob, Blob> bufferNodes(sa_family_t af,
|
||||
const InfoHash& id,
|
||||
want_t want,
|
||||
std::vector<std::shared_ptr<Node>>& nodes,
|
||||
std::vector<std::shared_ptr<Node>>& nodes6);
|
||||
std::vector<Sp<Node>>& nodes,
|
||||
std::vector<Sp<Node>>& nodes6);
|
||||
/* answer to a listen request */
|
||||
void sendListenConfirmation(const sockaddr* sa, socklen_t salen, TransId tid);
|
||||
void sendListenConfirmation(const SockAddr& addr, TransId tid);
|
||||
/* answer to put request */
|
||||
void sendValueAnnounced(const sockaddr* sa, socklen_t salen, TransId, Value::Id);
|
||||
void sendValueAnnounced(const SockAddr& addr, TransId, Value::Id);
|
||||
/* answer in case of error */
|
||||
void sendError(const sockaddr* sa,
|
||||
socklen_t salen,
|
||||
void sendError(const SockAddr& addr,
|
||||
TransId tid,
|
||||
uint16_t code,
|
||||
const std::string& message,
|
||||
bool include_id=false);
|
||||
|
||||
void deserializeNodesValues(ParsedMessage& msg);
|
||||
void deserializeNodes(ParsedMessage& msg);
|
||||
|
||||
std::queue<time_point> rate_limit_time {};
|
||||
static std::mt19937 rd_device;
|
||||
/* DHT info */
|
||||
const InfoHash& myid;
|
||||
const NetId network {0};
|
||||
const int dht_socket {-1};
|
||||
const int dht_socket6 {-1};
|
||||
const Logger& DHT_LOG;
|
||||
|
||||
NodeCache cache {};
|
||||
|
||||
/**
|
||||
* A comparator to classify IP addresses, only considering the
|
||||
* first 64 bits in IPv6.
|
||||
*/
|
||||
struct cmpSockAddr {
|
||||
bool operator()(const SockAddr& a, const SockAddr& b) const {
|
||||
if (a.second != b.second)
|
||||
return a.second < b.second;
|
||||
socklen_t start, len;
|
||||
switch(a.getFamily()) {
|
||||
case AF_INET:
|
||||
start = offsetof(sockaddr_in, sin_addr);
|
||||
len = sizeof(in_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
start = offsetof(sockaddr_in6, sin6_addr);
|
||||
// don't consider more than 64 bits (IPv6)
|
||||
len = 8;
|
||||
break;
|
||||
default:
|
||||
start = 0;
|
||||
len = a.second;
|
||||
break;
|
||||
}
|
||||
|
||||
return std::memcmp((uint8_t*)&a.first+start, (uint8_t*)&b.first+start, len) < 0;
|
||||
}
|
||||
};
|
||||
// global limiting should be triggered by at least 8 different IPs
|
||||
using IpLimiter = RateLimiter<MAX_REQUESTS_PER_SEC/8>;
|
||||
using IpLimiterMap = std::map<SockAddr, IpLimiter, SockAddr::ipCmp>;
|
||||
IpLimiterMap address_rate_limiter {};
|
||||
RateLimiter<MAX_REQUESTS_PER_SEC> rate_limiter {};
|
||||
|
||||
// requests handling
|
||||
uint16_t transaction_id {1};
|
||||
std::map<uint16_t, std::shared_ptr<Request>> requests {};
|
||||
std::map<TransId, Sp<Request>> requests {};
|
||||
std::map<TransId, PartialMessage> partial_messages;
|
||||
std::map<TransId, Sp<Socket>> opened_sockets {};
|
||||
|
||||
MessageStats in_stats {}, out_stats {};
|
||||
std::set<SockAddr> blacklist {};
|
||||
|
||||
Scheduler& scheduler;
|
||||
};
|
||||
|
||||
}
|
||||
} /* namespace net */
|
||||
} /* namespace dht */
|
||||
+36
-25
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,62 +22,71 @@
|
||||
|
||||
#include "infohash.h" // includes socket structures
|
||||
#include "utils.h"
|
||||
#include "sockaddr.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace dht {
|
||||
|
||||
class Request;
|
||||
namespace net {
|
||||
struct Request;
|
||||
} /* namespace net */
|
||||
|
||||
struct Node {
|
||||
friend class NetworkEngine;
|
||||
|
||||
InfoHash id;
|
||||
|
||||
socklen_t sslen {0};
|
||||
sockaddr_storage ss;
|
||||
SockAddr addr;
|
||||
|
||||
time_point time {time_point::min()}; /* last time eared about */
|
||||
time_point reply_time {time_point::min()}; /* time of last correct reply received */
|
||||
|
||||
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen)
|
||||
: id(id), sslen(salen), ss() {
|
||||
std::copy_n((const uint8_t*)sa, salen, (uint8_t*)&ss);
|
||||
if ((unsigned)salen < sizeof(ss))
|
||||
std::fill_n((uint8_t*)&ss+salen, sizeof(ss)-salen, 0);
|
||||
}
|
||||
: id(id), addr(sa, salen) {}
|
||||
Node(const InfoHash& id, const SockAddr& addr) : id(id), addr(addr) {}
|
||||
|
||||
InfoHash getId() const {
|
||||
return id;
|
||||
}
|
||||
std::pair<const sockaddr*, socklen_t> getAddr() const {
|
||||
return {(const sockaddr*)&ss, sslen};
|
||||
return {(const sockaddr*)&addr.first, addr.second};
|
||||
}
|
||||
std::string getAddrStr() const {
|
||||
return print_addr(ss, sslen);
|
||||
return addr.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes notice about an additionnal authentication error with this node. Up
|
||||
* to MAX_AUTH_ERRORS errors are accepted in order to let the node recover.
|
||||
* Upon this limit, the node expires.
|
||||
*/
|
||||
void authError() {
|
||||
if (++auth_errors > MAX_AUTH_ERRORS)
|
||||
setExpired();
|
||||
}
|
||||
void authSuccess() { auth_errors = 0; }
|
||||
|
||||
bool isExpired() const { return expired_; }
|
||||
bool isGood(time_point now) const;
|
||||
bool isPendingMessage() const;
|
||||
size_t getPendingMessageCount() const;
|
||||
|
||||
NodeExport exportNode() const { return NodeExport {id, ss, sslen}; }
|
||||
sa_family_t getFamily() const { return ss.ss_family; }
|
||||
NodeExport exportNode() const { return NodeExport {id, addr.first, addr.second}; }
|
||||
sa_family_t getFamily() const { return addr.getFamily(); }
|
||||
|
||||
void update(const sockaddr* sa, socklen_t salen);
|
||||
void update(const SockAddr&);
|
||||
|
||||
void requested(std::shared_ptr<Request>& req);
|
||||
void received(time_point now, std::shared_ptr<Request> req);
|
||||
void requested(std::shared_ptr<net::Request>& req);
|
||||
void received(time_point now, std::shared_ptr<net::Request> req);
|
||||
|
||||
void setExpired();
|
||||
|
||||
/**
|
||||
* Resets the state of the node so it's not expired anymore.
|
||||
*/
|
||||
void reset() { expired_ = false; }
|
||||
void reset() { expired_ = false; reply_time = time_point::min(); }
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
friend std::ostream& operator<< (std::ostream& s, const Node& h);
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Node& h);
|
||||
|
||||
static constexpr const std::chrono::minutes NODE_GOOD_TIME {120};
|
||||
|
||||
@@ -88,16 +97,18 @@ struct Node {
|
||||
static constexpr const std::chrono::seconds MAX_RESPONSE_TIME {1};
|
||||
|
||||
private:
|
||||
/* Number of times we accept authentication errors from this node. */
|
||||
static const constexpr unsigned MAX_AUTH_ERRORS {3};
|
||||
|
||||
std::list<std::weak_ptr<Request>> requests_ {};
|
||||
std::list<std::weak_ptr<net::Request>> requests_ {};
|
||||
unsigned auth_errors {0};
|
||||
bool expired_ {false};
|
||||
|
||||
void clearPendingQueue() {
|
||||
requests_.remove_if([](std::weak_ptr<Request>& w) {
|
||||
requests_.remove_if([](std::weak_ptr<net::Request>& w) {
|
||||
return w.expired();
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -28,7 +28,8 @@ namespace dht {
|
||||
|
||||
struct NodeCache {
|
||||
std::shared_ptr<Node> getNode(const InfoHash& id, sa_family_t family);
|
||||
std::shared_ptr<Node> getNode(const InfoHash& id, const sockaddr* sa, socklen_t sa_len, time_point now, int confirmed);
|
||||
std::shared_ptr<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed);
|
||||
std::vector<std::shared_ptr<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count);
|
||||
|
||||
/**
|
||||
* Reset the connectivity state of every node,
|
||||
@@ -41,7 +42,7 @@ private:
|
||||
class NodeMap : public std::map<InfoHash, std::weak_ptr<Node>> {
|
||||
public:
|
||||
std::shared_ptr<Node> getNode(const InfoHash& id);
|
||||
std::shared_ptr<Node> getNode(const InfoHash& id, const sockaddr* sa, socklen_t sa_len, time_point now, int confirmed);
|
||||
std::shared_ptr<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed);
|
||||
void clearBadNodes();
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 "utils.h"
|
||||
#include <queue>
|
||||
|
||||
namespace dht {
|
||||
|
||||
template<size_t Quota, unsigned long Perdiod=1>
|
||||
class RateLimiter {
|
||||
public:
|
||||
/** Clear outdated records and return current quota usage */
|
||||
size_t maintain(const time_point& now) {
|
||||
using namespace std::chrono;
|
||||
while (not records.empty() and duration_cast<seconds>(now - records.front()) >= seconds(Perdiod))
|
||||
records.pop();
|
||||
return records.size();
|
||||
}
|
||||
/** Return false if quota is reached, insert record and return true otherwise. */
|
||||
bool limit(const time_point& now) {
|
||||
if (maintain(now) >= Quota)
|
||||
return false;
|
||||
records.emplace(now);
|
||||
return true;
|
||||
}
|
||||
bool empty() const {
|
||||
return records.empty();
|
||||
}
|
||||
private:
|
||||
std::queue<time_point> records {};
|
||||
};
|
||||
|
||||
}
|
||||
+43
-16
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,10 +18,36 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "net.h"
|
||||
|
||||
namespace dht {
|
||||
namespace net {
|
||||
|
||||
class NetworkEngine;
|
||||
class ParsedMessage;
|
||||
struct ParsedMessage;
|
||||
|
||||
/*!
|
||||
* @class Socket
|
||||
* @brief Open route to a node for continous incoming packets.
|
||||
* @details
|
||||
* A socket lets a remote node send us continuous packets treated using a
|
||||
* given callback. This is intended to provide an easy management of
|
||||
* specific updates nodes can send. For e.g, this is used in the case of the
|
||||
* "listen" operation for treating updates a node has for a given storage.
|
||||
*/
|
||||
struct Socket {
|
||||
Socket() {}
|
||||
Socket(std::shared_ptr<Node> node,
|
||||
TransId id,
|
||||
std::function<void(const std::shared_ptr<Node>&, ParsedMessage&&)> on_receive) :
|
||||
node(node), id(id), on_receive(on_receive) {}
|
||||
|
||||
std::shared_ptr<Node> node;
|
||||
TransId id;
|
||||
std::function<void(const std::shared_ptr<Node>&, ParsedMessage&&)> on_receive {};
|
||||
};
|
||||
|
||||
/*!
|
||||
* @class Request
|
||||
@@ -32,7 +58,8 @@ class ParsedMessage;
|
||||
* request is done.
|
||||
*/
|
||||
struct Request {
|
||||
friend class dht::NetworkEngine;
|
||||
friend class dht::net::NetworkEngine;
|
||||
|
||||
std::shared_ptr<Node> node {}; /* the node to whom the request is destined. */
|
||||
time_point reply_time {time_point::min()}; /* time when we received the response to the request. */
|
||||
|
||||
@@ -52,13 +79,13 @@ struct Request {
|
||||
State getState() const { return state_; }
|
||||
|
||||
Request() {}
|
||||
Request(uint16_t tid,
|
||||
Request(TransId tid,
|
||||
std::shared_ptr<Node> node,
|
||||
Blob&& msg,
|
||||
std::function<void(const Request& req_status, ParsedMessage&&)> on_done,
|
||||
std::function<void(const Request& req_status, bool)> on_expired,
|
||||
bool persistent = false) :
|
||||
node(node), on_done(on_done), on_expired(on_expired), tid(tid), msg(std::move(msg)), persistent(persistent) { }
|
||||
std::function<void(const Request&, ParsedMessage&&)> on_done,
|
||||
std::function<void(const Request&, bool)> on_expired,
|
||||
std::shared_ptr<Socket> socket = {}) :
|
||||
node(node), on_done(on_done), on_expired(on_expired), tid(tid), msg(std::move(msg)), socket(socket) { }
|
||||
|
||||
void setExpired() {
|
||||
if (pending()) {
|
||||
@@ -68,11 +95,10 @@ struct Request {
|
||||
}
|
||||
}
|
||||
void setDone(ParsedMessage&& msg) {
|
||||
if (pending() or persistent) {
|
||||
if (pending()) {
|
||||
state_ = Request::State::COMPLETED;
|
||||
on_done(*this, std::forward<ParsedMessage>(msg));
|
||||
if (not persistent)
|
||||
clear();
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,12 +128,13 @@ private:
|
||||
time_point start {time_point::min()}; /* time when the request is created. */
|
||||
time_point last_try {time_point::min()}; /* time of the last attempt to process the request. */
|
||||
|
||||
std::function<void(const Request& req_status, ParsedMessage&&)> on_done {};
|
||||
std::function<void(const Request& req_status, bool)> on_expired {};
|
||||
std::function<void(const Request&, ParsedMessage&&)> on_done {};
|
||||
std::function<void(const Request&, bool)> on_expired {};
|
||||
|
||||
const uint16_t tid {0}; /* the request id. */
|
||||
Blob msg {}; /* the serialized message. */
|
||||
const bool persistent {false}; /* the request is not erased upon completion. */
|
||||
const TransId tid; /* the request id. */
|
||||
Blob msg {}; /* the serialized message. */
|
||||
std::shared_ptr<Socket> socket; /* the socket used for further reponses. */
|
||||
};
|
||||
|
||||
} /* namespace net */
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -24,6 +24,7 @@
|
||||
namespace dht {
|
||||
namespace crypto {
|
||||
|
||||
#ifndef WIN32_NATIVE
|
||||
#ifdef _WIN32
|
||||
|
||||
/**
|
||||
@@ -101,6 +102,9 @@ private:
|
||||
|
||||
using random_device = std::random_device;
|
||||
|
||||
#endif
|
||||
#else
|
||||
using random_device = std::random_device;
|
||||
#endif
|
||||
|
||||
}} // dht::crypto
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* 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
|
||||
@@ -23,18 +24,20 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
static constexpr unsigned TARGET_NODES {8};
|
||||
|
||||
struct Bucket {
|
||||
Bucket() : cached() {}
|
||||
Bucket(sa_family_t af, const InfoHash& f = {}, time_point t = time_point::min())
|
||||
: af(af), first(f), time(t), cached() {}
|
||||
sa_family_t af {0};
|
||||
InfoHash first {};
|
||||
time_point time {time_point::min()}; /* time of last reply in this bucket */
|
||||
std::list<std::shared_ptr<Node>> nodes {};
|
||||
std::shared_ptr<Node> cached; /* the address of a likely candidate */
|
||||
time_point time {time_point::min()}; /* time of last reply in this bucket */
|
||||
std::list<Sp<Node>> nodes {};
|
||||
Sp<Node> cached; /* the address of a likely candidate */
|
||||
|
||||
/** Return a random node in a bucket. */
|
||||
std::shared_ptr<Node> randomNode();
|
||||
Sp<Node> randomNode();
|
||||
};
|
||||
|
||||
class RoutingTable : public std::list<Bucket> {
|
||||
@@ -43,7 +46,7 @@ public:
|
||||
|
||||
InfoHash middle(const RoutingTable::const_iterator&) const;
|
||||
|
||||
std::vector<std::shared_ptr<Node>> findClosestNodes(const InfoHash id, time_point now, size_t count = TARGET_NODES) const;
|
||||
std::vector<Sp<Node>> findClosestNodes(const InfoHash id, time_point now, size_t count = TARGET_NODES) const;
|
||||
|
||||
RoutingTable::iterator findBucket(const InfoHash& id);
|
||||
RoutingTable::const_iterator findBucket(const InfoHash& id) const;
|
||||
|
||||
+21
-14
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,6 +22,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils.h"
|
||||
#include "log_enable.h"
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
@@ -36,8 +37,10 @@ namespace dht {
|
||||
*/
|
||||
class Scheduler {
|
||||
public:
|
||||
Scheduler(const Logger& l) : DHT_LOG(l) {}
|
||||
|
||||
struct Job {
|
||||
Job(std::function<void()>&& f) : do_(std::forward<std::function<void()>>(f)) {}
|
||||
Job(std::function<void()>&& f) : do_(std::move(f)) {}
|
||||
std::function<void()> do_;
|
||||
};
|
||||
|
||||
@@ -49,8 +52,8 @@ public:
|
||||
*
|
||||
* @return pointer to the newly scheduled job.
|
||||
*/
|
||||
std::shared_ptr<Scheduler::Job> add(time_point t, std::function<void()>&& job_func) {
|
||||
auto job = std::make_shared<Job>(std::forward<std::function<void()>>(job_func));
|
||||
Sp<Scheduler::Job> add(time_point t, std::function<void()>&& job_func) {
|
||||
auto job = std::make_shared<Job>(std::move(job_func));
|
||||
if (t != time_point::max())
|
||||
timers.emplace(std::move(t), job);
|
||||
return job;
|
||||
@@ -64,12 +67,16 @@ public:
|
||||
*
|
||||
* @return pointer to the newly scheduled job.
|
||||
*/
|
||||
void edit(std::shared_ptr<Scheduler::Job>& job, time_point t) {
|
||||
void edit(Sp<Scheduler::Job>& job, time_point t) {
|
||||
if (not job) {
|
||||
std::cerr << "editing an empty job" << std::endl;
|
||||
DHT_LOG.ERR("editing an empty job");
|
||||
return;
|
||||
}
|
||||
job = add(t, std::move(job->do_));
|
||||
// std::function move doesn't garantee to leave the object empty.
|
||||
// Force clearing old value.
|
||||
auto task = std::move(job->do_);
|
||||
job->do_ = {};
|
||||
job = add(t, std::move(task));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,17 +96,16 @@ public:
|
||||
if (timer->first > now)
|
||||
break;
|
||||
|
||||
const auto& job = *timer->second;
|
||||
if (job.do_)
|
||||
job.do_();
|
||||
auto job = std::move(timer->second);
|
||||
timers.erase(timer);
|
||||
|
||||
if (job->do_)
|
||||
job->do_();
|
||||
}
|
||||
return getNextJobTime();
|
||||
}
|
||||
|
||||
inline time_point getNextJobTime() const {
|
||||
//if (not timers.empty())
|
||||
// std::cout << "Next job in " << print_dt(timers.begin()->first - clock::now()) << std::endl;
|
||||
return timers.empty() ? time_point::max() : timers.begin()->first;
|
||||
}
|
||||
|
||||
@@ -112,7 +118,8 @@ public:
|
||||
|
||||
private:
|
||||
time_point now {clock::now()};
|
||||
std::multimap<time_point, std::shared_ptr<Job>> timers {}; /* the jobs ordered by time */
|
||||
std::multimap<time_point, Sp<Job>> timers {}; /* the jobs ordered by time */
|
||||
const Logger& DHT_LOG;
|
||||
};
|
||||
|
||||
}
|
||||
+34
-33
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -40,7 +41,7 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
class SecureDht : public Dht {
|
||||
class OPENDHT_PUBLIC SecureDht : public Dht {
|
||||
public:
|
||||
|
||||
typedef std::function<void(bool)> SignatureCheckCallback;
|
||||
@@ -62,6 +63,9 @@ public:
|
||||
InfoHash getId() const {
|
||||
return key_ ? key_->getPublicKey().getId() : InfoHash();
|
||||
}
|
||||
PkId getLongId() const {
|
||||
return key_ ? key_->getPublicKey().getLongId() : PkId();
|
||||
}
|
||||
|
||||
ValueType secureType(ValueType&& type);
|
||||
|
||||
@@ -70,7 +74,7 @@ public:
|
||||
return secureType(std::move(tmp_type));
|
||||
}
|
||||
|
||||
virtual void registerType(const ValueType& type) {
|
||||
virtual void registerType(const ValueType& type) override {
|
||||
Dht::registerType(secureType(type));
|
||||
}
|
||||
virtual void registerType(ValueType&& type) {
|
||||
@@ -85,25 +89,25 @@ public:
|
||||
* If the signature can't be checked, or if the data can't be decrypted, it is not returned.
|
||||
* Public, non-signed & non-encrypted data is retransmitted as-is.
|
||||
*/
|
||||
virtual void get(const InfoHash& id, GetCallback cb, DoneCallback donecb={}, Value::Filter&& = {}) override;
|
||||
virtual void get(const InfoHash& id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f = {}) override {
|
||||
get(id, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f));
|
||||
virtual void get(const InfoHash& id, GetCallback cb, DoneCallback donecb={}, Value::Filter&& = {}, Where&& w = {}) override;
|
||||
virtual void get(const InfoHash& id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f = {}, Where&& w = {}) override {
|
||||
get(id, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}) override {
|
||||
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f));
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
|
||||
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}) override {
|
||||
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f));
|
||||
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override {
|
||||
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
|
||||
}
|
||||
|
||||
virtual size_t listen(const InfoHash& id, GetCallback cb, Value::Filter&& = {}) override;
|
||||
virtual size_t listen(const InfoHash& id, GetCallback cb, Value::Filter&& = {}, Where&& w = {}) override;
|
||||
|
||||
/**
|
||||
* Will take ownership of the value, sign it using our private key and put it in the DHT.
|
||||
*/
|
||||
void putSigned(const InfoHash& hash, std::shared_ptr<Value> val, DoneCallback callback);
|
||||
void putSigned(const InfoHash& hash, Value&& v, DoneCallback callback) {
|
||||
putSigned(hash, std::make_shared<Value>(std::move(v)), callback);
|
||||
void putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback, bool permanent = false);
|
||||
void putSigned(const InfoHash& hash, Value&& v, DoneCallback callback, bool permanent = false) {
|
||||
putSigned(hash, std::make_shared<Value>(std::move(v)), callback, permanent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,9 +115,9 @@ public:
|
||||
* and put it in the DHT.
|
||||
* The operation will be immediate if the recipient' public key is known (otherwise it will be retrived first).
|
||||
*/
|
||||
void putEncrypted(const InfoHash& hash, const InfoHash& to, std::shared_ptr<Value> val, DoneCallback callback);
|
||||
void putEncrypted(const InfoHash& hash, const InfoHash& to, Value&& v, DoneCallback callback) {
|
||||
putEncrypted(hash, to, std::make_shared<Value>(std::move(v)), callback);
|
||||
void putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val, DoneCallback callback, bool permanent = false);
|
||||
void putEncrypted(const InfoHash& hash, const InfoHash& to, Value&& v, DoneCallback callback, bool permanent = false) {
|
||||
putEncrypted(hash, to, std::make_shared<Value>(std::move(v)), callback, permanent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,17 +129,14 @@ public:
|
||||
|
||||
Value decrypt(const Value& v);
|
||||
|
||||
void findCertificate(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::Certificate>)> cb);
|
||||
void findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::PublicKey>)> cb);
|
||||
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);
|
||||
|
||||
const std::shared_ptr<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
|
||||
void registerCertificate(std::shared_ptr<crypto::Certificate>& cert);
|
||||
const Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
|
||||
void registerCertificate(Sp<crypto::Certificate>& cert);
|
||||
|
||||
const std::shared_ptr<crypto::Certificate> getCertificate(const InfoHash& node) const;
|
||||
const std::shared_ptr<crypto::PublicKey> getPublicKey(const InfoHash& node) const;
|
||||
|
||||
|
||||
|
||||
const Sp<crypto::Certificate> getCertificate(const InfoHash& node) const;
|
||||
const Sp<const crypto::PublicKey> getPublicKey(const InfoHash& node) const;
|
||||
|
||||
/**
|
||||
* Allows to set a custom callback called by the library to find a locally-stored certificate.
|
||||
@@ -153,23 +154,23 @@ private:
|
||||
|
||||
GetCallback getCallbackFilter(GetCallback, Value::Filter&&);
|
||||
|
||||
std::shared_ptr<crypto::PrivateKey> key_ {};
|
||||
std::shared_ptr<crypto::Certificate> certificate_ {};
|
||||
Sp<crypto::PrivateKey> key_ {};
|
||||
Sp<crypto::Certificate> certificate_ {};
|
||||
|
||||
// method to query the local certificate store
|
||||
CertificateStoreQuery localQueryMethod_ {};
|
||||
|
||||
// our certificate cache
|
||||
std::map<InfoHash, std::shared_ptr<crypto::Certificate>> nodesCertificates_ {};
|
||||
std::map<InfoHash, std::shared_ptr<crypto::PublicKey>> nodesPubKeys_ {};
|
||||
std::map<InfoHash, Sp<crypto::Certificate>> nodesCertificates_ {};
|
||||
std::map<InfoHash, Sp<const crypto::PublicKey>> nodesPubKeys_ {};
|
||||
|
||||
std::uniform_int_distribution<Value::Id> rand_id {};
|
||||
};
|
||||
|
||||
const ValueType CERTIFICATE_TYPE = {
|
||||
8, "Certificate", std::chrono::hours(24 * 7),
|
||||
// A certificate can only be stored at it's public key ID.
|
||||
[](InfoHash id, std::shared_ptr<Value>& v, InfoHash, const sockaddr*, socklen_t) {
|
||||
// A certificate can only be stored at its public key ID.
|
||||
[](InfoHash id, Sp<Value>& v, InfoHash, const sockaddr*, socklen_t) {
|
||||
try {
|
||||
crypto::Certificate crt(v->data);
|
||||
// TODO check certificate signature
|
||||
@@ -177,7 +178,7 @@ const ValueType CERTIFICATE_TYPE = {
|
||||
} catch (const std::exception& e) {}
|
||||
return false;
|
||||
},
|
||||
[](InfoHash, const std::shared_ptr<Value>& o, std::shared_ptr<Value>& n, InfoHash, const sockaddr*, socklen_t) {
|
||||
[](InfoHash, const Sp<Value>& o, Sp<Value>& n, InfoHash, const sockaddr*, socklen_t) {
|
||||
try {
|
||||
return crypto::Certificate(o->data).getPublicKey().getId() == crypto::Certificate(n->data).getPublicKey().getId();
|
||||
} catch (const std::exception& e) {}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#else
|
||||
#include <iso646.h>
|
||||
#include <ws2def.h>
|
||||
#include <ws2tcpip.h>
|
||||
typedef uint16_t sa_family_t;
|
||||
typedef uint16_t in_port_t;
|
||||
#endif
|
||||
|
||||
namespace dht {
|
||||
|
||||
OPENDHT_PUBLIC std::string print_addr(const sockaddr* sa, socklen_t slen);
|
||||
OPENDHT_PUBLIC std::string print_addr(const sockaddr_storage& ss, socklen_t sslen);
|
||||
|
||||
struct OPENDHT_PUBLIC SockAddr : public std::pair<sockaddr_storage, socklen_t> {
|
||||
public:
|
||||
SockAddr() : pair<sockaddr_storage, socklen_t>::pair({},0) {}
|
||||
SockAddr(const SockAddr& o) : pair<sockaddr_storage, socklen_t>::pair({},o.second) {
|
||||
std::copy_n((uint8_t*)&o.first, o.second, (uint8_t*)&first);
|
||||
}
|
||||
SockAddr(const sockaddr* sa, socklen_t len) : pair<sockaddr_storage, socklen_t>::pair({},len) {
|
||||
if (len > sizeof(sockaddr_storage))
|
||||
throw std::runtime_error("Socket address length is too large");
|
||||
std::copy_n((uint8_t*)sa, len, (uint8_t*)&first);
|
||||
}
|
||||
SockAddr(const sockaddr_storage& ss, socklen_t len) : SockAddr((const sockaddr*)&ss, len) {}
|
||||
|
||||
bool operator<(const SockAddr& o) const {
|
||||
if (second != o.second)
|
||||
return second < o.second;
|
||||
return std::memcmp((uint8_t*)&first, (uint8_t*)&o.first, second) < 0;
|
||||
}
|
||||
|
||||
bool equals(const SockAddr& o) const {
|
||||
return second == o.second
|
||||
&& std::memcmp((uint8_t*)&first, (uint8_t*)&o.first, second) == 0;
|
||||
}
|
||||
SockAddr& operator=(const SockAddr& o) {
|
||||
std::copy_n((const uint8_t*)&o.first, o.second, (uint8_t*)&first);
|
||||
second = o.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
return print_addr(first, second);
|
||||
}
|
||||
sa_family_t getFamily() const { return second > sizeof(sa_family_t) ? first.ss_family : AF_UNSPEC; }
|
||||
|
||||
/**
|
||||
* A comparator to classify IP addresses, only considering the
|
||||
* first 64 bits in IPv6.
|
||||
*/
|
||||
struct ipCmp {
|
||||
bool operator()(const SockAddr& a, const SockAddr& b) const {
|
||||
if (a.second != b.second)
|
||||
return a.second < b.second;
|
||||
socklen_t start, len;
|
||||
switch(a.getFamily()) {
|
||||
case AF_INET:
|
||||
start = offsetof(sockaddr_in, sin_addr);
|
||||
len = sizeof(in_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
start = offsetof(sockaddr_in6, sin6_addr);
|
||||
// don't consider more than 64 bits (IPv6)
|
||||
len = 8;
|
||||
break;
|
||||
default:
|
||||
start = 0;
|
||||
len = a.second;
|
||||
break;
|
||||
}
|
||||
|
||||
return std::memcmp((uint8_t*)&a.first+start, (uint8_t*)&b.first+start, len) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
OPENDHT_PUBLIC bool operator==(const SockAddr& a, const SockAddr& b);
|
||||
|
||||
OPENDHT_PUBLIC std::string printAddr(const SockAddr& addr);
|
||||
|
||||
}
|
||||
+15
-63
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -13,23 +13,15 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WANT4 1
|
||||
#define WANT6 2
|
||||
#include "def.h"
|
||||
|
||||
#include <msgpack.hpp>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#else
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <functional>
|
||||
@@ -37,16 +29,17 @@
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
#define WANT4 1
|
||||
#define WANT6 2
|
||||
|
||||
namespace dht {
|
||||
|
||||
static constexpr unsigned TARGET_NODES {8};
|
||||
|
||||
using Address = std::pair<sockaddr_storage, socklen_t>;
|
||||
using NetId = uint32_t;
|
||||
using want_t = int_fast8_t;
|
||||
|
||||
std::string print_addr(const sockaddr* sa, socklen_t slen);
|
||||
std::string print_addr(const sockaddr_storage& ss, socklen_t sslen);
|
||||
std::string printAddr(const Address& addr);
|
||||
// shortcut for std::shared_ptr
|
||||
template<class T>
|
||||
using Sp = std::shared_ptr<T>;
|
||||
|
||||
template <typename Key, typename Item, typename Condition>
|
||||
void erase_if(std::map<Key, Item>& map, const Condition& condition)
|
||||
@@ -58,13 +51,12 @@ void erase_if(std::map<Key, Item>& map, const Condition& condition)
|
||||
}
|
||||
}
|
||||
|
||||
class DhtException : public std::runtime_error {
|
||||
class OPENDHT_PUBLIC DhtException : public std::runtime_error {
|
||||
public:
|
||||
DhtException(const std::string &str = "") :
|
||||
std::runtime_error("DhtException occured: " + str) {}
|
||||
std::runtime_error("DhtException occurred: " + str) {}
|
||||
};
|
||||
|
||||
|
||||
// Time related definitions and utility functions
|
||||
|
||||
using clock = std::chrono::steady_clock;
|
||||
@@ -83,9 +75,6 @@ print_dt(DT d) {
|
||||
return std::chrono::duration_cast<std::chrono::duration<double>>(d).count();
|
||||
}
|
||||
|
||||
static /*constexpr*/ const time_point TIME_INVALID = {time_point::min()};
|
||||
static /*constexpr*/ const time_point TIME_MAX {time_point::max()};
|
||||
|
||||
template <typename Duration = duration>
|
||||
class uniform_duration_distribution : public std::uniform_int_distribution<typename Duration::rep> {
|
||||
using Base = std::uniform_int_distribution<typename Duration::rep>;
|
||||
@@ -102,45 +91,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Logging related utility functions
|
||||
|
||||
/**
|
||||
* Dummy function used to disable logging
|
||||
*/
|
||||
inline void NOLOG(char const*, va_list) {}
|
||||
|
||||
/**
|
||||
* Wrapper for logging methods
|
||||
*/
|
||||
struct LogMethod {
|
||||
LogMethod() = default;
|
||||
|
||||
template<typename T>
|
||||
LogMethod(T&& t) : func(std::forward<T>(t)) {}
|
||||
|
||||
void operator()(char const* format, ...) const {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
func(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void logPrintable(const uint8_t *buf, size_t buflen) const {
|
||||
std::string buf_clean(buflen, '\0');
|
||||
for (size_t i=0; i<buflen; i++)
|
||||
buf_clean[i] = std::isprint(buf[i]) ? buf[i] : '.';
|
||||
(*this)("%s", buf_clean.c_str());
|
||||
}
|
||||
private:
|
||||
std::function<void(char const*, va_list)> func;
|
||||
};
|
||||
|
||||
struct Logger {
|
||||
LogMethod DEBUG = NOLOG;
|
||||
LogMethod WARN = NOLOG;
|
||||
LogMethod ERR = NOLOG;
|
||||
};
|
||||
|
||||
// Serialization related definitions and utility functions
|
||||
|
||||
using Blob = std::vector<uint8_t>;
|
||||
@@ -148,7 +98,7 @@ using Blob = std::vector<uint8_t>;
|
||||
/**
|
||||
* Provides backward compatibility with msgpack 1.0
|
||||
*/
|
||||
Blob unpackBlob(msgpack::object& o);
|
||||
OPENDHT_PUBLIC Blob unpackBlob(msgpack::object& o);
|
||||
|
||||
template <typename Type>
|
||||
Blob
|
||||
@@ -168,4 +118,6 @@ unpackMsg(Blob b) {
|
||||
|
||||
msgpack::unpacked unpackMsg(Blob b);
|
||||
|
||||
msgpack::object* findMapValue(msgpack::object& map, const std::string& key);
|
||||
|
||||
} // namespace dht
|
||||
+500
-22
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,10 +35,12 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <set>
|
||||
|
||||
namespace dht {
|
||||
|
||||
struct Value;
|
||||
struct Query;
|
||||
|
||||
/**
|
||||
* A storage policy is applied once to every incoming value storage requests.
|
||||
@@ -68,17 +70,23 @@ using StorePolicy = std::function<bool(InfoHash key, std::shared_ptr<Value>& val
|
||||
*/
|
||||
using EditPolicy = std::function<bool(InfoHash key, const std::shared_ptr<Value>& old_val, std::shared_ptr<Value>& new_val, InfoHash from, const sockaddr* from_addr, socklen_t from_len)>;
|
||||
|
||||
static constexpr const size_t MAX_VALUE_SIZE {1024 * 14};
|
||||
static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
|
||||
|
||||
struct ValueType {
|
||||
struct OPENDHT_PUBLIC ValueType {
|
||||
typedef uint16_t Id;
|
||||
|
||||
static bool DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, InfoHash, const sockaddr*, socklen_t);
|
||||
static bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, InfoHash, const sockaddr*, socklen_t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ValueType () {}
|
||||
|
||||
ValueType (Id id, std::string name, duration e = std::chrono::minutes(10))
|
||||
: id(id), name(name), expiration(e) {}
|
||||
|
||||
ValueType (Id id, std::string name, duration e, StorePolicy&& sp, EditPolicy&& ep)
|
||||
: id(id), name(name), expiration(e), storePolicy(std::move(sp)), editPolicy(std::move(ep)) {}
|
||||
ValueType (Id id, std::string name, duration e, StorePolicy sp, EditPolicy ep = DEFAULT_EDIT_POLICY)
|
||||
: id(id), name(name), expiration(e), storePolicy(sp), editPolicy(ep) {}
|
||||
|
||||
virtual ~ValueType() {}
|
||||
|
||||
@@ -89,10 +97,6 @@ struct ValueType {
|
||||
// Generic value type
|
||||
static const ValueType USER_DATA;
|
||||
|
||||
static bool DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, InfoHash, const sockaddr*, socklen_t);
|
||||
static bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, InfoHash, const sockaddr*, socklen_t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Id id {0};
|
||||
std::string name {};
|
||||
@@ -110,14 +114,29 @@ struct ValueType {
|
||||
* Values are stored at a given InfoHash in the Dht, but also have a
|
||||
* unique ID to distinguish between values stored at the same location.
|
||||
*/
|
||||
struct Value
|
||||
struct OPENDHT_PUBLIC Value
|
||||
{
|
||||
enum class Field : int {
|
||||
None = 0,
|
||||
Id, /* Value::id */
|
||||
ValueType, /* Value::type */
|
||||
OwnerPk, /* Value::owner */
|
||||
SeqNum, /* Value::seq */
|
||||
UserType, /* Value::user_type */
|
||||
|
||||
COUNT /* the total number of fields */
|
||||
};
|
||||
|
||||
typedef uint64_t Id;
|
||||
static const Id INVALID_ID {0};
|
||||
static const constexpr Id INVALID_ID {0};
|
||||
|
||||
class Filter : public std::function<bool(const Value&)> {
|
||||
using std::function<bool(const Value&)>::function;
|
||||
public:
|
||||
Filter() {}
|
||||
|
||||
template<typename Functor>
|
||||
Filter(Functor f) : std::function<bool(const Value&)>::function(f) {}
|
||||
|
||||
Filter chain(Filter&& f2) {
|
||||
auto f1 = *this;
|
||||
return chain(std::move(f1), std::move(f2));
|
||||
@@ -133,14 +152,17 @@ struct Value
|
||||
return f1(v) and f2(v);
|
||||
};
|
||||
}
|
||||
static Filter chain(std::initializer_list<Filter> l) {
|
||||
const std::vector<Filter> list(l.begin(), l.end());
|
||||
return [list](const Value& v){
|
||||
for (const auto& f : list)
|
||||
static Filter chainAll(std::vector<Filter>&& set) {
|
||||
if (set.empty()) return {};
|
||||
return std::bind([](const Value& v, std::vector<Filter>& s) {
|
||||
for (const auto& f : s)
|
||||
if (f and not f(v))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
}, std::placeholders::_1, std::move(set));
|
||||
}
|
||||
static Filter chain(std::initializer_list<Filter> l) {
|
||||
return chainAll(std::vector<Filter>(l.begin(), l.end()));
|
||||
}
|
||||
static Filter chainOr(Filter&& f1, Filter&& f2) {
|
||||
if (not f1 or not f2) return AllFilter();
|
||||
@@ -150,8 +172,10 @@ struct Value
|
||||
}
|
||||
};
|
||||
|
||||
/* Sneaky functions disguised in classes */
|
||||
|
||||
static const Filter AllFilter() {
|
||||
return [](const Value&){return true;};
|
||||
return {};
|
||||
}
|
||||
|
||||
static Filter TypeFilter(const ValueType& t) {
|
||||
@@ -160,6 +184,11 @@ struct Value
|
||||
return v.type == tid;
|
||||
};
|
||||
}
|
||||
static Filter TypeFilter(const ValueType::Id& tid) {
|
||||
return [tid](const Value& v) {
|
||||
return v.type == tid;
|
||||
};
|
||||
}
|
||||
|
||||
static Filter IdFilter(const Id id) {
|
||||
return [id](const Value& v) {
|
||||
@@ -167,12 +196,34 @@ struct Value
|
||||
};
|
||||
}
|
||||
|
||||
static Filter recipientFilter(const InfoHash& r) {
|
||||
static Filter RecipientFilter(const InfoHash& r) {
|
||||
return [r](const Value& v) {
|
||||
return v.recipient == r;
|
||||
};
|
||||
}
|
||||
|
||||
static Filter OwnerFilter(const crypto::PublicKey& pk) {
|
||||
return OwnerFilter(pk.getId());
|
||||
}
|
||||
|
||||
static Filter OwnerFilter(const InfoHash& pkh) {
|
||||
return [pkh](const Value& v) {
|
||||
return v.owner and v.owner->getId() == pkh;
|
||||
};
|
||||
}
|
||||
|
||||
static Filter SeqNumFilter(uint16_t seq_no) {
|
||||
return [seq_no](const Value& v) {
|
||||
return v.seq == seq_no;
|
||||
};
|
||||
}
|
||||
|
||||
static Filter UserTypeFilter(const std::string& ut) {
|
||||
return [ut](const Value& v) {
|
||||
return v.user_type == ut;
|
||||
};
|
||||
}
|
||||
|
||||
class SerializableBase
|
||||
{
|
||||
public:
|
||||
@@ -246,6 +297,43 @@ struct Value
|
||||
return owner and not signature.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the value using the provided private key.
|
||||
* Afterward, checkSignature() will return true and owner will
|
||||
* be set to the corresponding public key.
|
||||
*/
|
||||
void sign(const crypto::PrivateKey& key) {
|
||||
if (isEncrypted())
|
||||
throw DhtException("Can't sign encrypted data.");
|
||||
owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey());
|
||||
signature = key.sign(getToSign());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the value is signed and that the signature matches.
|
||||
* If true, the owner field will contain the signer public key.
|
||||
*/
|
||||
bool checkSignature() const {
|
||||
return isSigned() and owner->checkSignature(getToSign(), signature);
|
||||
}
|
||||
|
||||
std::shared_ptr<const crypto::PublicKey> getOwner() const {
|
||||
return std::static_pointer_cast<const crypto::PublicKey>(owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the value with from and returns the encrypted version for to.
|
||||
*/
|
||||
Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) {
|
||||
if (isEncrypted())
|
||||
throw DhtException("Data is already encrypted.");
|
||||
setRecipient(to.getId());
|
||||
sign(from);
|
||||
Value nv {id};
|
||||
nv.setCypher(to.encrypt(getToEncrypt()));
|
||||
return nv;
|
||||
}
|
||||
|
||||
Value() {}
|
||||
|
||||
Value (Id id) : id(id) {}
|
||||
@@ -321,7 +409,7 @@ struct Value
|
||||
}
|
||||
|
||||
/** print value for debugging */
|
||||
friend std::ostream& operator<< (std::ostream& s, const Value& v);
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Value& v);
|
||||
|
||||
std::string toString() const {
|
||||
std::stringstream ss;
|
||||
@@ -376,15 +464,51 @@ struct Value
|
||||
pk.pack(std::string("dat")); msgpack_pack_to_encrypt(pk);
|
||||
}
|
||||
|
||||
template <typename Packer>
|
||||
void msgpack_pack_fields(const std::set<Value::Field>& fields, Packer& pk) const
|
||||
{
|
||||
for (const auto& field : fields)
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
pk.pack(static_cast<uint64_t>(id));
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
pk.pack(static_cast<uint64_t>(type));
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
if (owner)
|
||||
owner->msgpack_pack(pk);
|
||||
else
|
||||
InfoHash().msgpack_pack(pk);
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
pk.pack(static_cast<uint64_t>(seq));
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
pk.pack(user_type);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
void msgpack_unpack_body(const msgpack::object& o);
|
||||
Blob getPacked() const {
|
||||
msgpack::sbuffer buffer;
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack(*this);
|
||||
return {buffer.data(), buffer.data()+buffer.size()};
|
||||
}
|
||||
|
||||
void msgpack_unpack_fields(const std::set<Value::Field>& fields, const msgpack::object& o, unsigned offset);
|
||||
|
||||
Id id {INVALID_ID};
|
||||
|
||||
/**
|
||||
* Public key of the signer.
|
||||
*/
|
||||
std::shared_ptr<crypto::PublicKey> owner {};
|
||||
std::shared_ptr<const crypto::PublicKey> owner {};
|
||||
|
||||
/**
|
||||
* Hash of the recipient (optional).
|
||||
@@ -422,6 +546,360 @@ struct Value
|
||||
|
||||
using ValuesExport = std::pair<InfoHash, Blob>;
|
||||
|
||||
/**
|
||||
* @class FieldValue
|
||||
* @brief Describes a value filter.
|
||||
* @details
|
||||
* This structure holds the value for a specified field. It's type can either be
|
||||
* uint64_t, InfoHash or Blob.
|
||||
*/
|
||||
struct OPENDHT_PUBLIC FieldValue
|
||||
{
|
||||
FieldValue() {}
|
||||
FieldValue(Value::Field f, uint64_t int_value) : field(f), intValue(int_value) {}
|
||||
FieldValue(Value::Field f, InfoHash hash_value) : field(f), hashValue(hash_value) {}
|
||||
FieldValue(Value::Field f, Blob blob_value) : field(f), blobValue(blob_value) {}
|
||||
|
||||
bool operator==(const FieldValue& fd) const;
|
||||
|
||||
// accessors
|
||||
Value::Field getField() const { return field; }
|
||||
uint64_t getInt() const { return intValue; }
|
||||
InfoHash getHash() const { return hashValue; }
|
||||
Blob getBlob() const { return blobValue; }
|
||||
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& p) const {
|
||||
p.pack_map(2);
|
||||
p.pack(std::string("f")); p.pack(static_cast<uint8_t>(field));
|
||||
|
||||
p.pack(std::string("v"));
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
p.pack(intValue);
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
p.pack(hashValue);
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
p.pack_bin(blobValue.size());
|
||||
p.pack_bin_body((const char*)blobValue.data(), blobValue.size());
|
||||
break;
|
||||
default:
|
||||
throw msgpack::type_error();
|
||||
}
|
||||
}
|
||||
|
||||
void msgpack_unpack(msgpack::object msg) {
|
||||
hashValue = {};
|
||||
blobValue.clear();
|
||||
|
||||
if (auto f = findMapValue(msg, "f"))
|
||||
field = (Value::Field)f->as<unsigned>();
|
||||
else
|
||||
throw msgpack::type_error();
|
||||
|
||||
auto v = findMapValue(msg, "v");
|
||||
if (not v)
|
||||
throw msgpack::type_error();
|
||||
else
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
intValue = v->as<decltype(intValue)>();
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
hashValue = v->as<decltype(hashValue)>();
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
blobValue = unpackBlob(*v);
|
||||
break;
|
||||
default:
|
||||
throw msgpack::type_error();
|
||||
}
|
||||
}
|
||||
|
||||
Value::Filter getLocalFilter() const;
|
||||
|
||||
private:
|
||||
Value::Field field {Value::Field::None};
|
||||
// three possible value types
|
||||
uint64_t intValue {};
|
||||
InfoHash hashValue {};
|
||||
Blob blobValue {};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @struct FieldSelectorDescription
|
||||
* @brief Describes a selection.
|
||||
* @details
|
||||
* This is meant to narrow data to a set of specified fields. This structure is
|
||||
* used to construct a Select structure.
|
||||
*/
|
||||
struct OPENDHT_PUBLIC FieldSelectorDescription
|
||||
{
|
||||
FieldSelectorDescription() {}
|
||||
FieldSelectorDescription(Value::Field f) : field(f) {}
|
||||
|
||||
Value::Field getField() const { return field; }
|
||||
|
||||
bool operator==(const FieldSelectorDescription& fd) const { return field == fd.field; }
|
||||
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& p) const { p.pack(static_cast<uint8_t>(field)); }
|
||||
void msgpack_unpack(msgpack::object msg) { field = static_cast<Value::Field>(msg.as<int>()); }
|
||||
private:
|
||||
Value::Field field {Value::Field::None};
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Select
|
||||
* @brief Serializable Value field selection.
|
||||
* @details
|
||||
* This is a container for a list of FieldSelectorDescription instances. It
|
||||
* describes a complete SELECT query for dht::Value.
|
||||
*/
|
||||
struct OPENDHT_PUBLIC Select
|
||||
{
|
||||
Select() { }
|
||||
Select(const std::string& q_str);
|
||||
|
||||
bool isSatisfiedBy(const Select& os) const;
|
||||
|
||||
/**
|
||||
* Selects a field of type Value::Field.
|
||||
*
|
||||
* @param field the field to require.
|
||||
*
|
||||
* @return the resulting Select instance.
|
||||
*/
|
||||
Select& field(Value::Field field) {
|
||||
fieldSelection_.emplace_back(field);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the set of selected fields based on previous require* calls.
|
||||
*
|
||||
* @return the set of fields.
|
||||
*/
|
||||
std::set<Value::Field> getSelection() const {
|
||||
std::set<Value::Field> fields {};
|
||||
for (const auto& f : fieldSelection_) {
|
||||
fields.insert(f.getField());
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& pk) const { pk.pack(fieldSelection_); }
|
||||
void msgpack_unpack(const msgpack::object& o) {
|
||||
fieldSelection_.clear();
|
||||
fieldSelection_ = o.as<decltype(fieldSelection_)>();
|
||||
}
|
||||
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Select& q);
|
||||
private:
|
||||
std::vector<FieldSelectorDescription> fieldSelection_ {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Where
|
||||
* @brief Serializable dht::Value filter.
|
||||
* @details
|
||||
* This is container for a list of FieldValue instances. It describes a
|
||||
* complete WHERE query for dht::Value.
|
||||
*/
|
||||
struct OPENDHT_PUBLIC Where
|
||||
{
|
||||
Where() { }
|
||||
Where(const std::string& q_str);
|
||||
|
||||
bool isSatisfiedBy(const Where& where) const;
|
||||
|
||||
/**
|
||||
* Adds restriction on Value::Id based on the id argument.
|
||||
*
|
||||
* @param id the id.
|
||||
*
|
||||
* @return the resulting Where instance.
|
||||
*/
|
||||
Where& id(Value::Id id) {
|
||||
filters_.emplace_back(Value::Field::Id, id);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds restriction on Value::ValueType based on the type argument.
|
||||
*
|
||||
* @param type the value type.
|
||||
*
|
||||
* @return the resulting Where instance.
|
||||
*/
|
||||
Where& valueType(ValueType::Id type) {
|
||||
filters_.emplace_back(Value::Field::ValueType, type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds restriction on Value::OwnerPk based on the owner_pk_hash argument.
|
||||
*
|
||||
* @param owner_pk_hash the owner public key fingerprint.
|
||||
*
|
||||
* @return the resulting Where instance.
|
||||
*/
|
||||
Where& owner(InfoHash owner_pk_hash) {
|
||||
filters_.emplace_back(Value::Field::OwnerPk, owner_pk_hash);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds restriction on Value::OwnerPk based on the owner_pk_hash argument.
|
||||
*
|
||||
* @param owner_pk_hash the owner public key fingerprint.
|
||||
*
|
||||
* @return the resulting Where instance.
|
||||
*/
|
||||
Where& seq(uint16_t seq_no) {
|
||||
filters_.emplace_back(Value::Field::SeqNum, seq_no);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds restriction on Value::UserType based on the user_type argument.
|
||||
*
|
||||
* @param user_type the user type.
|
||||
*
|
||||
* @return the resulting Where instance.
|
||||
*/
|
||||
Where& userType(std::string user_type) {
|
||||
filters_.emplace_back(Value::Field::UserType, Blob {user_type.begin(), user_type.end()});
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the Value::Filter based on the list of field value set.
|
||||
*
|
||||
* @return the resulting Value::Filter.
|
||||
*/
|
||||
Value::Filter getFilter() const {
|
||||
if (filters_.empty()) return {};
|
||||
std::vector<Value::Filter> fset;
|
||||
fset.reserve(filters_.size());
|
||||
for (const auto& f : filters_) {
|
||||
if (auto lf = f.getLocalFilter())
|
||||
fset.emplace_back(std::move(lf));
|
||||
}
|
||||
return Value::Filter::chainAll(std::move(fset));
|
||||
}
|
||||
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& pk) const { pk.pack(filters_); }
|
||||
void msgpack_unpack(const msgpack::object& o) {
|
||||
filters_.clear();
|
||||
filters_ = o.as<decltype(filters_)>();
|
||||
}
|
||||
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Where& q);
|
||||
|
||||
private:
|
||||
std::vector<FieldValue> filters_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Query
|
||||
* @brief Describes a query destined to another peer.
|
||||
* @details
|
||||
* This class describes the list of filters on field values and the field
|
||||
* itselves to include in the peer response to a GET operation. See
|
||||
* FieldValue.
|
||||
*/
|
||||
struct OPENDHT_PUBLIC Query
|
||||
{
|
||||
static const std::string QUERY_PARSE_ERROR;
|
||||
|
||||
Query(Select s = {}, Where w = {}, bool none = false) : select(s), where(w), none(none) { };
|
||||
|
||||
/**
|
||||
* Initializes a query based on a SQL-ish formatted string. The abstract
|
||||
* form of such a string is the following:
|
||||
*
|
||||
* [SELECT $field$ [WHERE $field$=$value$]]
|
||||
*
|
||||
* where
|
||||
*
|
||||
* - $field$ = *|id|value_type|owner_pk|user_type
|
||||
* - $value$ = $string$|$integer$
|
||||
* - $string$: a simple string WITHOUT SPACES.
|
||||
* - $integer$: a simple integer.
|
||||
*/
|
||||
Query(std::string q_str) {
|
||||
auto pos_W = q_str.find("WHERE");
|
||||
auto pos_w = q_str.find("where");
|
||||
auto pos = std::min(pos_W != std::string::npos ? pos_W : q_str.size(),
|
||||
pos_w != std::string::npos ? pos_w : q_str.size());
|
||||
select = q_str.substr(0, pos);
|
||||
where = q_str.substr(pos, q_str.size()-pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the query is satisfied by another query.
|
||||
*/
|
||||
bool isSatisfiedBy(const Query& q) const;
|
||||
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& pk) const {
|
||||
pk.pack_map(2);
|
||||
pk.pack(std::string("s")); pk.pack(select); /* packing field selectors */
|
||||
pk.pack(std::string("w")); pk.pack(where); /* packing filters */
|
||||
}
|
||||
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
|
||||
std::string toString() {
|
||||
std::stringstream ss;
|
||||
ss << *this;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Query& q) {
|
||||
return s << "Query[" << q.select << " " << q.where << "]";
|
||||
}
|
||||
|
||||
Select select {};
|
||||
Where where {};
|
||||
bool none {false}; /* When true, any query satisfies this. */
|
||||
};
|
||||
|
||||
/*!
|
||||
* @class FieldValueIndex
|
||||
* @brief An index for field values.
|
||||
* @details
|
||||
* This structures is meant to manipulate a subset of fields normally contained
|
||||
* in Value.
|
||||
*/
|
||||
struct OPENDHT_PUBLIC FieldValueIndex {
|
||||
FieldValueIndex() {}
|
||||
FieldValueIndex(const Value& v, Select s = {});
|
||||
/**
|
||||
* Tells if all the fields of this are contained in the other
|
||||
* FieldValueIndex with the same value.
|
||||
*
|
||||
* @param other The other FieldValueIndex instance.
|
||||
*/
|
||||
bool containedIn(const FieldValueIndex& other) const;
|
||||
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi);
|
||||
|
||||
void msgpack_unpack_fields(const std::set<Value::Field>& fields,
|
||||
const msgpack::object& o,
|
||||
unsigned offset);
|
||||
|
||||
std::map<Value::Field, FieldValue> index {};
|
||||
};
|
||||
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
|
||||
Value::Filter
|
||||
|
||||
@@ -6,4 +6,6 @@ Name: OpenDHT
|
||||
Description: C++ Distributed Hash Table library
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lopendht
|
||||
Libs.private: -lpthread
|
||||
Requires.private: gnutls >= 3.1
|
||||
Cflags: -I${includedir}
|
||||
@@ -8,4 +8,4 @@ add_custom_target(python ALL
|
||||
COMMAND python3 setup.py build
|
||||
DEPENDS opendht opendht_cpp.pxd opendht.pyx)
|
||||
|
||||
install(CODE "execute_process(COMMAND python3 setup.py install WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
|
||||
install(CODE "execute_process(COMMAND python3 setup.py install --root=\$ENV{DESTDIR}/ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
|
||||
+5
-1
@@ -1,5 +1,9 @@
|
||||
if USE_CYTHON
|
||||
|
||||
noinst_HEADERS = \
|
||||
opendht.pyx \
|
||||
opendht_cpp.pxd
|
||||
|
||||
PYTHON_INSTALL_RECORD = $(builddir)/install_record.txt
|
||||
|
||||
pybuild.stamp:
|
||||
@@ -13,7 +17,7 @@ clean-local:
|
||||
rm -rf $(builddir)/build $(builddir)/*.so $(PYTHON_INSTALL_RECORD)
|
||||
|
||||
install-exec-local:
|
||||
$(PYTHON) setup.py install --record $(PYTHON_INSTALL_RECORD)
|
||||
$(PYTHON) setup.py install --root=$(DESTDIR)/ --record $(PYTHON_INSTALL_RECORD)
|
||||
rm -rf $(builddir)/build
|
||||
|
||||
if HAVE_PIP
|
||||
|
||||
+129
-38
@@ -31,6 +31,7 @@ from libcpp.map cimport map as map
|
||||
from libcpp cimport bool
|
||||
from libcpp.utility cimport pair
|
||||
from libcpp.string cimport string
|
||||
from libcpp.memory cimport shared_ptr
|
||||
|
||||
from cython.parallel import parallel, prange
|
||||
from cython.operator cimport dereference as deref, preincrement as inc, predecrement as dec
|
||||
@@ -40,19 +41,29 @@ cimport opendht_cpp as cpp
|
||||
|
||||
import threading
|
||||
|
||||
cdef inline void lookup_callback(cpp.vector[cpp.shared_ptr[cpp.IndexValue]]* values, cpp.Prefix* p, void *user_data) with gil:
|
||||
cbs = <object>user_data
|
||||
if 'lookup' in cbs and cbs['lookup']:
|
||||
vals = []
|
||||
for val in deref(values):
|
||||
v = IndexValue()
|
||||
v._value = val
|
||||
vals.append(v)
|
||||
cbs['lookup'](vals, p.toString())
|
||||
|
||||
cdef inline void shutdown_callback(void* user_data) with gil:
|
||||
cbs = <object>user_data
|
||||
if 'shutdown' in cbs and cbs['shutdown']:
|
||||
cbs['shutdown']()
|
||||
ref.Py_DECREF(cbs)
|
||||
|
||||
cdef inline bool get_callback(cpp.shared_ptr[cpp.Value] value, void *user_data) with gil:
|
||||
cdef inline bool get_callback(shared_ptr[cpp.Value] value, void *user_data) with gil:
|
||||
cb = (<object>user_data)['get']
|
||||
pv = Value()
|
||||
pv._value = value
|
||||
return cb(pv)
|
||||
|
||||
cdef inline void done_callback(bool done, cpp.vector[cpp.shared_ptr[cpp.Node]]* nodes, void *user_data) with gil:
|
||||
cdef inline void done_callback(bool done, cpp.vector[shared_ptr[cpp.Node]]* nodes, void *user_data) with gil:
|
||||
node_ids = []
|
||||
for n in deref(nodes):
|
||||
h = NodeEntry()
|
||||
@@ -64,6 +75,12 @@ cdef inline void done_callback(bool done, cpp.vector[cpp.shared_ptr[cpp.Node]]*
|
||||
cbs['done'](done, node_ids)
|
||||
ref.Py_DECREF(cbs)
|
||||
|
||||
cdef inline void done_callback_simple(bool done, void *user_data) with gil:
|
||||
cbs = <object>user_data
|
||||
if 'done' in cbs and cbs['done']:
|
||||
cbs['done'](done)
|
||||
ref.Py_DECREF(cbs)
|
||||
|
||||
cdef class _WithID(object):
|
||||
def __repr__(self):
|
||||
return "<%s '%s'>" % (self.__class__.__name__, str(self))
|
||||
@@ -72,7 +89,7 @@ cdef class _WithID(object):
|
||||
|
||||
cdef class InfoHash(_WithID):
|
||||
cdef cpp.InfoHash _infohash
|
||||
def __init__(self, bytes str=b''):
|
||||
def __cinit__(self, bytes str=b''):
|
||||
self._infohash = cpp.InfoHash(str)
|
||||
def __bool__(InfoHash self):
|
||||
return not (self._infohash == cpp.InfoHash())
|
||||
@@ -109,7 +126,7 @@ cdef class InfoHash(_WithID):
|
||||
return h
|
||||
|
||||
cdef class Node(_WithID):
|
||||
cdef cpp.shared_ptr[cpp.Node] _node
|
||||
cdef shared_ptr[cpp.Node] _node
|
||||
def getId(self):
|
||||
h = InfoHash()
|
||||
h._infohash = self._node.get().getId()
|
||||
@@ -120,7 +137,7 @@ cdef class Node(_WithID):
|
||||
return self._node.get().isExpired()
|
||||
|
||||
cdef class NodeEntry(_WithID):
|
||||
cdef cpp.pair[cpp.InfoHash, cpp.shared_ptr[cpp.Node]] _v
|
||||
cdef cpp.pair[cpp.InfoHash, shared_ptr[cpp.Node]] _v
|
||||
def getId(self):
|
||||
h = InfoHash()
|
||||
h._infohash = self._v.first
|
||||
@@ -131,7 +148,7 @@ cdef class NodeEntry(_WithID):
|
||||
return n
|
||||
|
||||
cdef class Value(object):
|
||||
cdef cpp.shared_ptr[cpp.Value] _value
|
||||
cdef shared_ptr[cpp.Value] _value
|
||||
def __init__(self, bytes val=b''):
|
||||
self._value.reset(new cpp.Value(val, len(val)))
|
||||
def __str__(self):
|
||||
@@ -163,8 +180,8 @@ cdef class Value(object):
|
||||
return self._value.get().size()
|
||||
|
||||
cdef class NodeSetIter(object):
|
||||
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]]* _nodes
|
||||
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]].iterator _curIter
|
||||
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]]* _nodes
|
||||
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]].iterator _curIter
|
||||
def __init__(self, NodeSet s):
|
||||
self._nodes = &s._nodes
|
||||
self._curIter = self._nodes.begin()
|
||||
@@ -177,7 +194,7 @@ cdef class NodeSetIter(object):
|
||||
return h
|
||||
|
||||
cdef class NodeSet(object):
|
||||
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]] _nodes
|
||||
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]] _nodes
|
||||
def size(self):
|
||||
return self._nodes.size()
|
||||
def insert(self, NodeEntry l):
|
||||
@@ -199,7 +216,7 @@ cdef class NodeSet(object):
|
||||
return h
|
||||
def __str__(self):
|
||||
s = ''
|
||||
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]].iterator it = self._nodes.begin()
|
||||
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]].iterator it = self._nodes.begin()
|
||||
while it != self._nodes.end():
|
||||
s += deref(it).first.toString().decode() + ' ' + deref(it).second.get().getAddrStr().decode() + '\n'
|
||||
inc(it)
|
||||
@@ -215,7 +232,7 @@ cdef class PublicKey(_WithID):
|
||||
return h
|
||||
|
||||
cdef class Certificate(_WithID):
|
||||
cdef cpp.shared_ptr[cpp.Certificate] _cert
|
||||
cdef shared_ptr[cpp.Certificate] _cert
|
||||
def getId(self):
|
||||
h = InfoHash()
|
||||
h._infohash = self._cert.get().getId()
|
||||
@@ -252,51 +269,58 @@ cdef class DhtConfig(object):
|
||||
self._config.dht_config.node_config.is_bootstrap = bootstrap
|
||||
def setNodeId(self, InfoHash id):
|
||||
self._config.dht_config.node_config.node_id = id._infohash
|
||||
def setNetwork(self, unsigned netid):
|
||||
self._config.dht_config.node_config.network = netid
|
||||
def setMaintainStorage(self, bool maintain_storage):
|
||||
self._config.dht_config.node_config.maintain_storage = maintain_storage
|
||||
|
||||
cdef class DhtRunner(_WithID):
|
||||
cdef cpp.DhtRunner* thisptr
|
||||
cdef cpp.shared_ptr[cpp.DhtRunner] thisptr
|
||||
def __cinit__(self):
|
||||
self.thisptr = new cpp.DhtRunner()
|
||||
self.thisptr.reset(new cpp.DhtRunner())
|
||||
def getId(self):
|
||||
h = InfoHash()
|
||||
h._infohash = self.thisptr.getId()
|
||||
h._infohash = self.thisptr.get().getId()
|
||||
return h
|
||||
def getNodeId(self):
|
||||
return self.thisptr.getNodeId().toString()
|
||||
def bootstrap(self, str host, str port):
|
||||
self.thisptr.bootstrap(host.encode(), port.encode())
|
||||
return self.thisptr.get().getNodeId().toString()
|
||||
def bootstrap(self, str host, str port=None):
|
||||
if port:
|
||||
self.thisptr.get().bootstrap(host.encode(), port.encode())
|
||||
else:
|
||||
self.thisptr.get().bootstrap(host.encode(), b'4222')
|
||||
def run(self, Identity id=None, is_bootstrap=False, cpp.in_port_t port=0, str ipv4="", str ipv6="", DhtConfig config=DhtConfig()):
|
||||
if id:
|
||||
config.setIdentity(id)
|
||||
if ipv4 or ipv6:
|
||||
bind4 = ipv4.encode() if ipv4 else b''
|
||||
bind6 = ipv6.encode() if ipv6 else b''
|
||||
self.thisptr.run(bind4, bind6, str(port).encode(), config._config)
|
||||
self.thisptr.get().run(bind4, bind6, str(port).encode(), config._config)
|
||||
else:
|
||||
self.thisptr.run(port, config._config)
|
||||
self.thisptr.get().run(port, config._config)
|
||||
def join(self):
|
||||
self.thisptr.join()
|
||||
self.thisptr.get().join()
|
||||
def shutdown(self, shutdown_cb=None):
|
||||
cb_obj = {'shutdown':shutdown_cb}
|
||||
ref.Py_INCREF(cb_obj)
|
||||
self.thisptr.shutdown(cpp.bindShutdownCb(shutdown_callback, <void*>cb_obj))
|
||||
self.thisptr.get().shutdown(cpp.bindShutdownCb(shutdown_callback, <void*>cb_obj))
|
||||
def enableLogging(self):
|
||||
cpp.enableLogging(self.thisptr[0])
|
||||
cpp.enableLogging(self.thisptr.get()[0])
|
||||
def disableLogging(self):
|
||||
cpp.disableLogging(self.thisptr[0])
|
||||
cpp.disableLogging(self.thisptr.get()[0])
|
||||
def enableFileLogging(self, str path):
|
||||
cpp.enableFileLogging(self.thisptr[0], path)
|
||||
cpp.enableFileLogging(self.thisptr.get()[0], path.encode())
|
||||
def isRunning(self):
|
||||
return self.thisptr.isRunning()
|
||||
return self.thisptr.get().isRunning()
|
||||
def getStorageLog(self):
|
||||
return self.thisptr.getStorageLog().decode()
|
||||
return self.thisptr.get().getStorageLog().decode()
|
||||
def getRoutingTablesLog(self, cpp.sa_family_t af):
|
||||
return self.thisptr.getRoutingTablesLog(af).decode()
|
||||
return self.thisptr.get().getRoutingTablesLog(af).decode()
|
||||
def getSearchesLog(self, cpp.sa_family_t af):
|
||||
return self.thisptr.getSearchesLog(af).decode()
|
||||
return self.thisptr.get().getSearchesLog(af).decode()
|
||||
def getNodeMessageStats(self):
|
||||
stats = []
|
||||
cdef cpp.vector[unsigned] res = self.thisptr.getNodeMessageStats(False)
|
||||
cdef cpp.vector[unsigned] res = self.thisptr.get().getNodeMessageStats(False)
|
||||
for n in res:
|
||||
stats.append(n)
|
||||
return stats
|
||||
@@ -304,14 +328,16 @@ cdef class DhtRunner(_WithID):
|
||||
def get(self, InfoHash key, get_cb=None, done_cb=None):
|
||||
"""Retreive values associated with a key on the DHT.
|
||||
|
||||
key -- the key for which to search
|
||||
get_cb -- is set, makes the operation non-blocking. Called when a value is found on the DHT.
|
||||
done_cb -- optional callback used when get_cb is set. Called when the operation is completed.
|
||||
key -- the key for which to search
|
||||
get_cb -- is set, makes the operation non-blocking. Called when a value
|
||||
is found on the DHT.
|
||||
done_cb -- optional callback used when get_cb is set. Called when the
|
||||
operation is completed.
|
||||
"""
|
||||
if get_cb:
|
||||
cb_obj = {'get':get_cb, 'done':done_cb}
|
||||
ref.Py_INCREF(cb_obj)
|
||||
self.thisptr.get(key._infohash, cpp.bindGetCb(get_callback, <void*>cb_obj), cpp.bindDoneCb(done_callback, <void*>cb_obj))
|
||||
self.thisptr.get().get(key._infohash, cpp.bindGetCb(get_callback, <void*>cb_obj), cpp.bindDoneCb(done_callback, <void*>cb_obj))
|
||||
else:
|
||||
lock = threading.Condition()
|
||||
pending = 0
|
||||
@@ -334,14 +360,14 @@ cdef class DhtRunner(_WithID):
|
||||
def put(self, InfoHash key, Value val, done_cb=None):
|
||||
"""Publish a new value on the DHT at key.
|
||||
|
||||
key -- the DHT key where to put the value
|
||||
val -- the value to put on the DHT
|
||||
key -- the DHT key where to put the value
|
||||
val -- the value to put on the DHT
|
||||
done_cb -- optional callback called when the operation is completed.
|
||||
"""
|
||||
if done_cb:
|
||||
cb_obj = {'done':done_cb}
|
||||
ref.Py_INCREF(cb_obj)
|
||||
self.thisptr.put(key._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj))
|
||||
self.thisptr.get().put(key._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj))
|
||||
else:
|
||||
lock = threading.Condition()
|
||||
pending = 0
|
||||
@@ -365,9 +391,74 @@ cdef class DhtRunner(_WithID):
|
||||
t._cb['cb'] = cb_obj
|
||||
# avoid the callback being destructed if the token is destroyed
|
||||
ref.Py_INCREF(cb_obj)
|
||||
t._t = self.thisptr.listen(t._h, cpp.bindGetCb(get_callback, <void*>cb_obj)).share()
|
||||
t._t = self.thisptr.get().listen(t._h, cpp.bindGetCb(get_callback, <void*>cb_obj)).share()
|
||||
return t
|
||||
def cancelListen(self, ListenToken token):
|
||||
self.thisptr.cancelListen(token._h, token._t)
|
||||
self.thisptr.get().cancelListen(token._h, token._t)
|
||||
ref.Py_DECREF(<object>token._cb['cb'])
|
||||
# fixme: not thread safe
|
||||
|
||||
cdef class IndexValue(object):
|
||||
cdef cpp.shared_ptr[cpp.IndexValue] _value
|
||||
def __init__(self, InfoHash h=None, cpp.uint64_t vid=0):
|
||||
cdef cpp.InfoHash hh = h._infohash
|
||||
self._value.reset(new cpp.IndexValue(hh, vid))
|
||||
def __str__(self):
|
||||
return "(" + self.getKey().toString().decode() +", "+ str(self.getValueId()) +")"
|
||||
def getKey(self):
|
||||
h = InfoHash()
|
||||
h._infohash = self._value.get().first
|
||||
return h
|
||||
def getValueId(self):
|
||||
return self._value.get().second
|
||||
|
||||
cdef class Pht(object):
|
||||
cdef cpp.Pht* thisptr
|
||||
def __cinit__(self, bytes name, key_spec, DhtRunner dht):
|
||||
cdef cpp.IndexKeySpec cpp_key_spec
|
||||
for kk, size in key_spec.items():
|
||||
cpp_key_spec[bytes(kk, 'utf-8')] = size
|
||||
self.thisptr = new cpp.Pht(name, cpp_key_spec, dht.thisptr)
|
||||
property MAX_NODE_ENTRY_COUNT:
|
||||
def __get__(self):
|
||||
return cpp.PHT_MAX_NODE_ENTRY_COUNT
|
||||
def lookup(self, key, lookup_cb=None, done_cb=None):
|
||||
"""Query the Index with a specified key.
|
||||
|
||||
key -- the key for to the entry in the index.
|
||||
lookup_cb -- function called when the operation is completed. This
|
||||
function takes a list of IndexValue objects and a string
|
||||
representation of the prefix where the value was indexed in
|
||||
the PHT.
|
||||
"""
|
||||
cb_obj = {'lookup':lookup_cb, 'done':done_cb} # TODO: donecallback is to be removed
|
||||
ref.Py_INCREF(cb_obj)
|
||||
cdef cpp.IndexKey cppk
|
||||
for kk, v in key.items():
|
||||
cppk[bytes(kk, 'utf-8')] = bytes(v)
|
||||
self.thisptr.lookup(
|
||||
cppk,
|
||||
cpp.Pht.bindLookupCb(lookup_callback, <void*>cb_obj),
|
||||
cpp.bindDoneCbSimple(done_callback_simple, <void*>cb_obj)
|
||||
)
|
||||
def insert(self, key, IndexValue value, done_cb=None):
|
||||
"""Add an index entry to the Index.
|
||||
|
||||
key -- the key for to the entry in the index.
|
||||
value -- an IndexValue object describing the indexed value.
|
||||
done_cb -- Called when the operation is completed.
|
||||
"""
|
||||
cb_obj = {'done':done_cb}
|
||||
ref.Py_INCREF(cb_obj)
|
||||
cdef cpp.IndexKey cppk
|
||||
for kk, v in key.items():
|
||||
cppk[bytes(kk, 'utf-8')] = bytes(v)
|
||||
cdef cpp.IndexValue val
|
||||
val.first = (<InfoHash>value.getKey())._infohash
|
||||
val.second = value.getValueId()
|
||||
self.thisptr.insert(
|
||||
cppk,
|
||||
val,
|
||||
cpp.bindDoneCbSimple(done_callback_simple, <void*>cb_obj)
|
||||
)
|
||||
|
||||
+27
-2
@@ -20,6 +20,7 @@ from libcpp cimport bool
|
||||
from libcpp.string cimport string
|
||||
from libcpp.vector cimport vector
|
||||
from libcpp.utility cimport pair
|
||||
from libcpp.map cimport map
|
||||
|
||||
ctypedef uint16_t in_port_t
|
||||
ctypedef unsigned short int sa_family_t;
|
||||
@@ -27,6 +28,7 @@ ctypedef unsigned short int sa_family_t;
|
||||
cdef extern from "<memory>" namespace "std" nogil:
|
||||
cdef cppclass shared_ptr[T]:
|
||||
shared_ptr() except +
|
||||
shared_ptr(T*) except +
|
||||
T* get()
|
||||
T operator*()
|
||||
void reset(T*)
|
||||
@@ -103,23 +105,27 @@ cdef extern from "opendht/callbacks.h" namespace "dht":
|
||||
ctypedef void (*ShutdownCallbackRaw)(void *user_data)
|
||||
ctypedef bool (*GetCallbackRaw)(shared_ptr[Value] values, void *user_data)
|
||||
ctypedef void (*DoneCallbackRaw)(bool done, vector[shared_ptr[Node]]* nodes, void *user_data)
|
||||
ctypedef void (*DoneCallbackSimpleRaw)(bool done, void *user_data)
|
||||
|
||||
cppclass ShutdownCallback:
|
||||
ShutdownCallback() except +
|
||||
cppclass GetCallback:
|
||||
GetCallback() except +
|
||||
#GetCallback(GetCallbackRaw cb, void *user_data) except +
|
||||
cppclass DoneCallback:
|
||||
DoneCallback() except +
|
||||
#DoneCallback(DoneCallbackRaw, void *user_data) except +
|
||||
cppclass DoneCallbackSimple:
|
||||
DoneCallbackSimple() except +
|
||||
|
||||
cdef ShutdownCallback bindShutdownCb(ShutdownCallbackRaw cb, void *user_data)
|
||||
cdef GetCallback bindGetCb(GetCallbackRaw cb, void *user_data)
|
||||
cdef DoneCallback bindDoneCb(DoneCallbackRaw cb, void *user_data)
|
||||
cdef DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw cb, void *user_data)
|
||||
|
||||
cppclass Config:
|
||||
InfoHash node_id
|
||||
uint32_t network
|
||||
bool is_bootstrap
|
||||
bool maintain_storage
|
||||
cppclass SecureDhtConfig:
|
||||
Config node_config
|
||||
Identity id
|
||||
@@ -156,3 +162,22 @@ cdef extern from "opendht/log.h" namespace "dht::log":
|
||||
void disableLogging(DhtRunner& dht)
|
||||
void enableFileLogging(DhtRunner& dht, const string& path)
|
||||
|
||||
cdef extern from "opendht/indexation/pht.h" namespace "dht::indexation":
|
||||
size_t PHT_MAX_NODE_ENTRY_COUNT "dht::indexation::Pht::MAX_NODE_ENTRY_COUNT"
|
||||
cdef cppclass Prefix:
|
||||
Prefix() except +
|
||||
Prefix(vector[uint8_t]) except +
|
||||
string toString() const
|
||||
ctypedef pair[InfoHash, uint64_t] IndexValue "dht::indexation::Value"
|
||||
ctypedef map[string, vector[uint8_t]] IndexKey "dht::indexation::Pht::Key"
|
||||
ctypedef map[string, uint32_t] IndexKeySpec "dht::indexation::Pht::KeySpec"
|
||||
ctypedef void (*LookupCallbackRaw)(vector[shared_ptr[IndexValue]]* values, Prefix* p, void* user_data);
|
||||
cdef cppclass Pht:
|
||||
cppclass LookupCallback:
|
||||
LookupCallback() except +
|
||||
Pht(string, IndexKeySpec, shared_ptr[DhtRunner]) except +
|
||||
void lookup(IndexKey k, LookupCallback cb, DoneCallbackSimple doneCb);
|
||||
void insert(IndexKey k, IndexValue v, DoneCallbackSimple cb)
|
||||
@staticmethod
|
||||
LookupCallback bindLookupCb(LookupCallbackRaw cb, void *user_data)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Copyright (C) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Benchmark
|
||||
|
||||
The `benchmark.py` script is used for testing OpenDHT in various cases. If you
|
||||
run `benchmark.py --help`, you should find the following text:
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--performance Launches performance benchmark test. Available args
|
||||
for "-t" are: gets.
|
||||
--data-persistence Launches data persistence benchmark test. Available
|
||||
args for "-t" are: delete, replace, mult_time.
|
||||
Available args for "-o" are : dump_str_log,
|
||||
keep_alive, trigger, traffic_plot, op_plot. Use "-m"
|
||||
to specify the number of producers on the DHT.Use "-e"
|
||||
to specify the number of values to put on the DHT.
|
||||
|
||||
These options specify the feature to be tested. Each feature has its own tests.
|
||||
You specify the test by using `-t` flag (see `benchmark.py --help` for full
|
||||
help).
|
||||
|
||||
## Python dependencies
|
||||
|
||||
- pyroute2 >=0.3.14
|
||||
- matplotlib
|
||||
- GeoIP (used by `scanner.py` for drawing map of the world)
|
||||
- ipaddress
|
||||
- netifaces
|
||||
- networkx
|
||||
- numpy
|
||||
|
||||
## Usage
|
||||
|
||||
Before running the script, you have to build and install OpenDHT and its cython
|
||||
wrapper (`cython3` has to be installed) on the system so that it can be found by
|
||||
the benchmark script.
|
||||
|
||||
$ cd $OPENDHT_SRC_DIR
|
||||
$ ./autogen.sh
|
||||
$ ./configure
|
||||
$ make && sudo make install
|
||||
|
||||
Then, you can use the script like so:
|
||||
|
||||
$ cd $OPENDHT_SRC_DIR/python/tools/
|
||||
$ python3 benchmark.py --performance -t gets -n 2048
|
||||
@@ -27,7 +27,7 @@ import random
|
||||
|
||||
from dht.network import DhtNetwork
|
||||
from dht.network import DhtNetworkSubProcess
|
||||
from dht.tests import PerformanceTest, PersistenceTest
|
||||
from dht.tests import PerformanceTest, PersistenceTest, PhtTest
|
||||
from dht import virtual_network_builder
|
||||
from dht import network as dhtnetwork
|
||||
|
||||
@@ -66,7 +66,11 @@ class WorkBench():
|
||||
|
||||
def create_virtual_net(self):
|
||||
if self.virtual_locs > 1:
|
||||
cmd = ["python3", os.path.abspath(virtual_network_builder.__file__), "-i", self.ifname, "-n", str(self.clusters), '-l', str(self.loss), '-d', str(self.delay)]
|
||||
cmd = ["python3", os.path.abspath(virtual_network_builder.__file__),
|
||||
"-i", self.ifname,
|
||||
"-n", str(self.clusters),
|
||||
'-l', str(self.loss),
|
||||
'-d', str(self.delay)]
|
||||
if not self.disable_ipv4:
|
||||
cmd.append('-4')
|
||||
if not self.disable_ipv6:
|
||||
@@ -90,10 +94,17 @@ class WorkBench():
|
||||
cmd.extend(['-b', self.local_bootstrap.ip4])
|
||||
if not self.disable_ipv6 and self.local_bootstrap.ip6:
|
||||
cmd.extend(['-b6', self.local_bootstrap.ip6])
|
||||
self.procs[i] = DhtNetworkSubProcess('node'+str(i), cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
while DhtNetworkSubProcess.NOTIFY_TOKEN not in self.procs[i].getline():
|
||||
# waiting for process to spawn
|
||||
time.sleep(0.5)
|
||||
lock = threading.Condition()
|
||||
def dcb(success):
|
||||
nonlocal lock
|
||||
if not success:
|
||||
DhtNetwork.Log.err("Failed to initialize network...")
|
||||
with lock:
|
||||
lock.notify()
|
||||
with lock:
|
||||
self.procs[i] = DhtNetworkSubProcess('node'+str(i), cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
self.procs[i].sendPing(done_cb=dcb)
|
||||
lock.wait()
|
||||
else:
|
||||
raise Exception('First create bootstrap.')
|
||||
|
||||
@@ -157,11 +168,16 @@ if __name__ == '__main__':
|
||||
featureArgs = parser.add_mutually_exclusive_group(required=True)
|
||||
featureArgs.add_argument('--performance', action='store_true', default=False,
|
||||
help='Launches performance benchmark test. Available args for "-t" are: gets.')
|
||||
featureArgs.add_argument('--pht', action='store_true', default=False,
|
||||
help='Launches PHT benchmark test. '\
|
||||
'Available args for "-t" are: insert. '\
|
||||
'Timer available by adding "timer" to "-o" args'\
|
||||
'Use "-m" option for fixing number of keys to create during the test.')
|
||||
featureArgs.add_argument('--data-persistence', action='store_true', default=0,
|
||||
help='Launches data persistence benchmark test. '\
|
||||
'Available args for "-t" are: delete, replace, mult_time. '\
|
||||
'Available args for "-o" are : dump_str_log, keep_alive, trigger, traffic_plot, op_plot. '\
|
||||
'Use "-m" to specify the number of producers on the DHT.'\
|
||||
'Use "-m" to specify the number of producers on the DHT. '\
|
||||
'Use "-e" to specify the number of values to put on the DHT.')
|
||||
|
||||
args = parser.parse_args()
|
||||
@@ -206,6 +222,10 @@ if __name__ == '__main__':
|
||||
PerformanceTest(args.test, wb, test_opt).run()
|
||||
elif args.data_persistence:
|
||||
PersistenceTest(args.test, wb, test_opt).run()
|
||||
elif args.pht:
|
||||
if args.m:
|
||||
test_opt.update({ 'num_keys' : args.m })
|
||||
PhtTest(args.test, wb, test_opt).run()
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
Executable
+265
@@ -0,0 +1,265 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os, sys, time, cmd
|
||||
import subprocess
|
||||
import signal
|
||||
import argparse
|
||||
import threading
|
||||
|
||||
import opendht as dht
|
||||
|
||||
class NodeCluster(object):
|
||||
nodes = []
|
||||
node_uid = 0
|
||||
|
||||
@staticmethod
|
||||
def run_node(ip4, ip6, p, bootstrap=None, is_bootstrap=False, logfile=None):
|
||||
print("run_node", ip4, ip6, p, bootstrap, logfile)
|
||||
n = dht.DhtRunner()
|
||||
n.run(ipv4=ip4 if ip4 else "", ipv6=ip6 if ip6 else "", port=p, is_bootstrap=is_bootstrap)
|
||||
if logfile:
|
||||
n.enableFileLogging(logfile)
|
||||
if bootstrap:
|
||||
n.bootstrap(bootstrap[0], bootstrap[1])
|
||||
time.sleep(.01)
|
||||
return ((ip4, ip6, p), n, id)
|
||||
|
||||
@staticmethod
|
||||
def find_ip(iface):
|
||||
if not iface or iface == 'any':
|
||||
return ('0.0.0.0','')
|
||||
|
||||
if_ip4 = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr']
|
||||
if_ip6 = netifaces.ifaddresses(iface)[netifaces.AF_INET6][0]['addr']
|
||||
return (if_ip4, if_ip6)
|
||||
|
||||
def __init__(self, iface=None, ip4=None, ip6=None, port=4000, bootstrap=None, first_bootstrap=False, logfile=None):
|
||||
NodeCluster.iface = iface
|
||||
self.port = port
|
||||
ips = NodeCluster.find_ip(iface)
|
||||
self.logfile = logfile
|
||||
self.ip4 = ip4 if ip4 else ips[0]
|
||||
self.ip6 = ip6 if ip6 else ips[1]
|
||||
self.bootstrap = bootstrap
|
||||
if bootstrap:
|
||||
self.bootstrap = (bootstrap.hostname, str(bootstrap.port) if bootstrap.port else "4222")
|
||||
else:
|
||||
print("Using fallback bootstrap", self.ip4, self.port)
|
||||
self.bootstrap = ((self.ip4, str(self.port)))
|
||||
if first_bootstrap:
|
||||
print("Starting bootstrap node")
|
||||
self.nodes.append(NodeCluster.run_node(self.ip4, self.ip6, self.port, self.bootstrap, is_bootstrap=True))
|
||||
self.bootstrap = ((self.ip4, str(self.port)))
|
||||
self.port += 1
|
||||
#print(self.ip4, self.ip6, self.port)
|
||||
|
||||
def front(self):
|
||||
if len(self.nodes) == 0:
|
||||
return None
|
||||
return self.nodes[0][1]
|
||||
|
||||
def get(self, i=None):
|
||||
if not self.nodes:
|
||||
return None
|
||||
|
||||
if i is None:
|
||||
l = list(self.nodes)
|
||||
random.shuffle(l)
|
||||
return l[0][1]
|
||||
else:
|
||||
return self.nodes[i][1]
|
||||
|
||||
def getNodeInfoById(self, id=None):
|
||||
if id:
|
||||
for n in self.nodes:
|
||||
if n[1].getNodeId() == id:
|
||||
return n
|
||||
return None
|
||||
|
||||
def launch_node(self):
|
||||
node_logfile = (self.logfile + str(self.node_uid) + '.log') if self.logfile else None
|
||||
n = NodeCluster.run_node(self.ip4, self.ip6, self.port, self.bootstrap, logfile=node_logfile)
|
||||
self.nodes.append(n)
|
||||
self.port += 1
|
||||
self.node_uid += 1
|
||||
return n
|
||||
|
||||
def end_node(self, id=None, shutdown=False, last_msg_stats=None):
|
||||
"""
|
||||
Ends a running node.
|
||||
|
||||
@param id: The 40 hex chars id of the node.
|
||||
@type id: bytes
|
||||
|
||||
@return: If a node was deleted or not.
|
||||
@rtype : boolean
|
||||
"""
|
||||
lock = threading.Condition()
|
||||
def shutdown_cb():
|
||||
nonlocal lock
|
||||
NodeCluster.Log.log('Done.')
|
||||
with lock:
|
||||
lock.notify()
|
||||
|
||||
if not self.nodes:
|
||||
return
|
||||
elif id:
|
||||
n = self.getNodeInfoById(id)
|
||||
if n:
|
||||
if shutdown:
|
||||
with lock:
|
||||
print('Waiting for node to shutdown... ')
|
||||
n[1].shutdown(shutdown_cb)
|
||||
lock.wait()
|
||||
if last_msg_stats:
|
||||
last_msg_stats.append(self.getMessageStats())
|
||||
n[1].join()
|
||||
self.nodes.remove(n)
|
||||
print(id, 'deleted !')
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
n = self.nodes.pop()
|
||||
n[1].join()
|
||||
return True
|
||||
|
||||
def replace_node(self, id=None, shutdown=False, last_msg_stats=None):
|
||||
random.shuffle(self.nodes)
|
||||
deleted = self.end_node(id=id, shutdown=shutdown, last_msg_stats=last_msg_stats)
|
||||
if deleted:
|
||||
self.launch_node()
|
||||
|
||||
def resize(self, n):
|
||||
n = min(n, 500)
|
||||
l = len(self.nodes)
|
||||
if n == l:
|
||||
return
|
||||
if n > l:
|
||||
print("Launching", n-l, "nodes", self.ip4, self.ip6)
|
||||
for i in range(l, n):
|
||||
self.launch_node()
|
||||
else:
|
||||
print("Ending", l-n, "nodes", self.ip4, self.ip6)
|
||||
#random.shuffle(self.nodes)
|
||||
for i in range(n, l):
|
||||
self.end_node()
|
||||
|
||||
def close(self):
|
||||
self.resize(0)
|
||||
|
||||
def getMessageStats(self):
|
||||
stats = np.array([0,0,0,0,0])
|
||||
for n in self.nodes:
|
||||
stats += np.array(n[1].getNodeMessageStats())
|
||||
stats_list = [len(self.nodes)]
|
||||
stats_list.extend(stats.tolist())
|
||||
return stats_list
|
||||
|
||||
class ClusterShell(cmd.Cmd):
|
||||
intro = 'Welcome to the OpenDHT node cluster control. Type help or ? to list commands.\n'
|
||||
prompt = '>> '
|
||||
net = None
|
||||
node = None
|
||||
log = False
|
||||
def __init__(self, network):
|
||||
super(ClusterShell, self).__init__()
|
||||
self.net = network
|
||||
def setNode(self, node=None, num=0):
|
||||
if node == self.node:
|
||||
return
|
||||
if self.node:
|
||||
self.node.disableLogging()
|
||||
self.node = node
|
||||
if self.node:
|
||||
self.prompt = '('+str(num)+') >> '
|
||||
if self.log:
|
||||
self.node.enableLogging()
|
||||
else:
|
||||
self.prompt = '>> '
|
||||
def do_exit(self, arg):
|
||||
self.close()
|
||||
return True
|
||||
def do_node(self, arg):
|
||||
if not arg:
|
||||
setNode()
|
||||
else:
|
||||
nodenum = int(arg)
|
||||
if nodenum > len(self.net.nodes) or nodenum < 1:
|
||||
print("Invalid node number:", nodenum, " (accepted: 1-", len(self.net.nodes), ")")
|
||||
else:
|
||||
self.setNode(self.net.nodes[nodenum-1][1], nodenum)
|
||||
def do_ll(self, arg):
|
||||
if self.node:
|
||||
print('Node', self.node.getNodeId().decode())
|
||||
else:
|
||||
print(len(self.net.nodes), 'nodes running.')
|
||||
def do_ls(self, arg):
|
||||
if self.node:
|
||||
print(self.node.getSearchesLog(0))
|
||||
else:
|
||||
print('No node selected.')
|
||||
def do_log(self, arg):
|
||||
if self.node:
|
||||
self.log = not self.log
|
||||
if self.log:
|
||||
self.node.enableLogging()
|
||||
else:
|
||||
self.node.disableLogging()
|
||||
def do_EOF(self, line):
|
||||
self.close()
|
||||
return True
|
||||
def close(self):
|
||||
if self.net:
|
||||
self.net.close()
|
||||
self.net = None
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
from urllib.parse import urlparse
|
||||
net = None
|
||||
try:
|
||||
parser = argparse.ArgumentParser(description='Create a dht network of -n nodes')
|
||||
parser.add_argument('-n', '--node-num', help='number of dht nodes to run', type=int, default=32)
|
||||
parser.add_argument('-I', '--iface', help='local interface to bind', default='any')
|
||||
parser.add_argument('-p', '--port', help='start of port range (port, port+node_num)', type=int, default=4000)
|
||||
parser.add_argument('-b', '--bootstrap', help='bootstrap address')
|
||||
parser.add_argument('-d', '--daemonize', help='daemonize process', action='store_true')
|
||||
parser.add_argument('-l', '--log', help='log file prefix')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.bootstrap:
|
||||
args.bootstrap = urlparse('dht://'+args.bootstrap)
|
||||
|
||||
net = NodeCluster(iface=args.iface, port=args.port, bootstrap=args.bootstrap, logfile=args.log)
|
||||
net.resize(args.node_num)
|
||||
if args.daemonize:
|
||||
import daemon, lockfile
|
||||
#pidfile=lockfile.FileLock('/var/run/dhtcluster.'+str(args.port))
|
||||
with daemon.DaemonContext():
|
||||
while True:
|
||||
time.sleep(2)
|
||||
else:
|
||||
ClusterShell(net).cmdloop()
|
||||
except Exception as e:
|
||||
traceback.print_tb(e.__traceback__)
|
||||
print(type(e).__name__+':', e, file=sys.stderr)
|
||||
finally:
|
||||
if net:
|
||||
net.resize(0)
|
||||
+234
-174
@@ -25,11 +25,13 @@ import time
|
||||
import threading
|
||||
import queue
|
||||
import re
|
||||
import traceback
|
||||
|
||||
import ipaddress
|
||||
import netifaces
|
||||
import numpy as np
|
||||
from pyroute2.netns.process.proxy import NSPopen
|
||||
import msgpack
|
||||
|
||||
from opendht import *
|
||||
|
||||
@@ -37,8 +39,6 @@ from opendht import *
|
||||
# useful functions
|
||||
b_space_join = lambda *l: b' '.join(map(bytes, l))
|
||||
|
||||
# TODO: find where token "notifyend" gets printed... Or switch to MSGPACK for
|
||||
# serialisation of packets between both processes.
|
||||
class DhtNetworkSubProcess(NSPopen):
|
||||
"""
|
||||
Handles communication with DhtNetwork sub process.
|
||||
@@ -47,20 +47,21 @@ class DhtNetworkSubProcess(NSPopen):
|
||||
process' stdout until it finds 'DhtNetworkSubProcess.NOTIFY_TOKEN' token,
|
||||
therefor, waits for the sub process to spawn.
|
||||
"""
|
||||
# Packet types
|
||||
REQUEST = 'DhtNetworkSubProcess.request'
|
||||
ANSWER = 'DhtNetworkSubProcess.answer'
|
||||
OUT = 'DhtNetworkSubProcess.out'
|
||||
|
||||
# requests
|
||||
NODE_PUT_REQ = b"np"
|
||||
NEW_NODE_REQ = b"nn"
|
||||
REMOVE_NODE_REQ = b"rn"
|
||||
SHUTDOWN_NODE_REQ = b"sdn"
|
||||
SHUTDOWN_REPLACE_NODE_REQ = b'sdrn'
|
||||
SHUTDOWN_CLUSTER_REQ = b"sdc"
|
||||
DUMP_STORAGE_REQ = b"strl"
|
||||
MESSAGE_STATS = b"gms"
|
||||
|
||||
|
||||
# tokens
|
||||
NOTIFY_TOKEN = 'notify'
|
||||
NOTIFY_END_TOKEN = 'notifyend'
|
||||
PING_REQ = "p"
|
||||
NODE_PUT_REQ = "np" # "np <hash> <value>"
|
||||
NEW_NODE_REQ = "nn" # "nn"
|
||||
REMOVE_NODE_REQ = "rn" # "rn <id0>[ <id1>[ id2[...]]]"
|
||||
SHUTDOWN_NODE_REQ = "sdn" # "sdn <id0>[ <id1>[ id2[...]]]"
|
||||
SHUTDOWN_REPLACE_NODE_REQ = "sdrn" # "sdn <id0>[ <id1>[ id2[...]]]"
|
||||
SHUTDOWN_CLUSTER_REQ = "sdc" # "sdc"
|
||||
DUMP_STORAGE_REQ = "strl" # "strl"
|
||||
MESSAGE_STATS = "gms" # "gms"
|
||||
|
||||
def __init__(self, ns, cmd, quit=False, **kwargs):
|
||||
super(DhtNetworkSubProcess, self).__init__(ns, cmd, **kwargs)
|
||||
@@ -70,11 +71,11 @@ class DhtNetworkSubProcess(NSPopen):
|
||||
self._quit = quit
|
||||
self._lock = threading.Condition()
|
||||
self._in_queue = queue.Queue()
|
||||
self._out_queue = queue.Queue()
|
||||
self._callbacks = {}
|
||||
self._tid = 0
|
||||
|
||||
# starting thread
|
||||
self._thread = threading.Thread(target=self._communicate)
|
||||
self._thread.daemon = True
|
||||
self._thread.start()
|
||||
|
||||
def __repr__(self):
|
||||
@@ -92,42 +93,38 @@ class DhtNetworkSubProcess(NSPopen):
|
||||
"""
|
||||
Communication thread. This reads and writes to the sub process.
|
||||
"""
|
||||
ENCODING = 'utf-8'
|
||||
sleep_time = 0.1
|
||||
stdin_line, stdout_line = '', ''
|
||||
|
||||
# first read of process living. Expecting NOTIFY_TOKEN
|
||||
while DhtNetworkSubProcess.NOTIFY_TOKEN not in stdout_line:
|
||||
stdout_line = self.stdout.readline().decode()
|
||||
time.sleep(sleep_time)
|
||||
|
||||
with self._lock:
|
||||
self._out_queue.put(stdout_line)
|
||||
|
||||
while not self._quit:
|
||||
with self._lock:
|
||||
try:
|
||||
stdin_line = self._in_queue.get_nowait()
|
||||
packet = self._in_queue.get_nowait()
|
||||
|
||||
# sending data to sub process
|
||||
self.stdin.write(stdin_line if isinstance(stdin_line, bytes) else
|
||||
bytes(str(stdin_line), encoding=ENCODING))
|
||||
self.stdin.write(packet)
|
||||
self.stdin.flush()
|
||||
except queue.Empty:
|
||||
#waiting for next stdin req to send
|
||||
self._lock.wait(timeout=sleep_time)
|
||||
pass
|
||||
|
||||
# reading response from sub process
|
||||
for stdout_line in iter(self.stdout.readline, b''):
|
||||
stdout_line = stdout_line.decode().replace('\n', '')
|
||||
if stdout_line:
|
||||
with self._lock:
|
||||
self._out_queue.put(stdout_line)
|
||||
# reading from sub process
|
||||
out_string = ''
|
||||
for p in msgpack.Unpacker(self.stdout):
|
||||
if isinstance(p, dict):
|
||||
self._process_packet(p)
|
||||
else:
|
||||
# Some non-msgpack data could slip into the stream. We
|
||||
# have to treat those as characters.
|
||||
out_string += chr(p)
|
||||
if out_string:
|
||||
print(out_string)
|
||||
|
||||
#waiting for next stdin req to send
|
||||
self._lock.wait(timeout=sleep_time)
|
||||
|
||||
with self._lock:
|
||||
self._lock.notify()
|
||||
|
||||
def stop_communicating(self):
|
||||
def _stop_communicating(self):
|
||||
"""
|
||||
Stops the I/O thread from communicating with the subprocess.
|
||||
"""
|
||||
@@ -142,12 +139,12 @@ class DhtNetworkSubProcess(NSPopen):
|
||||
Notifies thread and sub process to terminate. This is blocking call
|
||||
until the sub process finishes.
|
||||
"""
|
||||
self.stop_communicating()
|
||||
self._stop_communicating()
|
||||
self.send_signal(signal.SIGINT);
|
||||
self.wait()
|
||||
self.release()
|
||||
|
||||
def send(self, msg):
|
||||
def _send(self, msg):
|
||||
"""
|
||||
Send data to sub process.
|
||||
"""
|
||||
@@ -155,83 +152,76 @@ class DhtNetworkSubProcess(NSPopen):
|
||||
self._in_queue.put(msg)
|
||||
self._lock.notify()
|
||||
|
||||
def getline(self):
|
||||
def _process_packet(self, p):
|
||||
"""
|
||||
Read line from sub process.
|
||||
|
||||
@return: A line on sub process' stdout.
|
||||
@rtype : str
|
||||
Process msgpack packet received from
|
||||
"""
|
||||
line = ''
|
||||
with self._lock:
|
||||
try:
|
||||
line = self._out_queue.get_nowait()
|
||||
except queue.Empty:
|
||||
pass
|
||||
return line
|
||||
if not b'tid' in p:
|
||||
DhtNetwork.Log.err('Bad packet...')
|
||||
try:
|
||||
self._callbacks[p[b'tid']](p)
|
||||
except KeyError:
|
||||
DhtNetwork.Log.err('Unknown tid...')
|
||||
|
||||
def getlinesUntilNotify(self, answer_cb=None):
|
||||
"""
|
||||
Reads the stdout queue until a proper notification is given by the sub
|
||||
process.
|
||||
|
||||
@param answer_cb: Callback to call when an answer is given after notify.
|
||||
The function takes a list of strings as argument.
|
||||
@type answer_cb: function
|
||||
"""
|
||||
notified = False
|
||||
answer = []
|
||||
while True:
|
||||
out = self.getline()
|
||||
if out.split(' ')[0] == DhtNetworkSubProcess.NOTIFY_TOKEN:
|
||||
notified = True
|
||||
elif notified and out.split(' ')[0] == DhtNetworkSubProcess.NOTIFY_END_TOKEN:
|
||||
if answer_cb:
|
||||
answer_cb(answer)
|
||||
break
|
||||
elif notified:
|
||||
answer.append(out)
|
||||
elif out:
|
||||
yield out
|
||||
else:
|
||||
time.sleep(0.1)
|
||||
|
||||
def _sendRequest(self, request, answer_cb=None):
|
||||
def _sendRequest(self, request, tid, done_cb):
|
||||
"""
|
||||
Sends a request to the sub network and wait for output.
|
||||
|
||||
@param request: The serialized request.
|
||||
@type request: bytes
|
||||
@type request: Msgpack object
|
||||
"""
|
||||
self.send(request + b'\n')
|
||||
for line in self.getlinesUntilNotify(answer_cb=answer_cb):
|
||||
DhtNetwork.log(line)
|
||||
self._callbacks[tid] = done_cb
|
||||
self._send(request)
|
||||
|
||||
def sendGetMessageStats(self):
|
||||
def sendPing(self, done_cb=None):
|
||||
"""Sends a ping request to the DhtNetworkSubProcess.
|
||||
|
||||
@param done_cb: The callback to be executed when we get a response. This
|
||||
function takes a boolean "success" as parameter.
|
||||
@type done_cb: Function
|
||||
"""
|
||||
self._tid += 1
|
||||
def dcb(packet):
|
||||
try:
|
||||
done_cb(packet[b'success'])
|
||||
except KeyError:
|
||||
done_cb(False)
|
||||
self._sendRequest(msgpack.packb({
|
||||
DhtNetworkSubProcess.REQUEST : True,
|
||||
'tid' : self._tid,
|
||||
'req' : DhtNetworkSubProcess.PING_REQ
|
||||
}), self._tid, dcb)
|
||||
|
||||
def sendGetMessageStats(self, done_cb=None):
|
||||
"""
|
||||
Sends DhtNetwork sub process statistics request about nodes messages
|
||||
sent.
|
||||
|
||||
@param done_cb: A function taking as parameter the returned list of
|
||||
stats.
|
||||
@type done_cb: function
|
||||
|
||||
@return: A list [num_nodes, ping, find, get, put, listen].
|
||||
@rtype : list
|
||||
"""
|
||||
stats = []
|
||||
def cb(answer):
|
||||
"""
|
||||
Callback fed to getlinesUntilNotify made to recover answer from the
|
||||
DhtNetwork sub process.
|
||||
self._tid += 1
|
||||
def dcb(packet):
|
||||
nonlocal done_cb
|
||||
if not done_cb:
|
||||
return
|
||||
try:
|
||||
stats = packet[b'stats']
|
||||
done_cb([] if not isinstance(stats, list) else done_cb(stats))
|
||||
except KeyError:
|
||||
done_cb([])
|
||||
self._sendRequest(msgpack.packb({
|
||||
DhtNetworkSubProcess.REQUEST : True,
|
||||
'tid' : self._tid,
|
||||
'req' : DhtNetworkSubProcess.MESSAGE_STATS
|
||||
}), self._tid, dcb)
|
||||
|
||||
@param answer: the list of lines answered by the sub process.
|
||||
@type answer: function
|
||||
"""
|
||||
nonlocal stats
|
||||
if answer:
|
||||
stats = [int(v) for v in re.findall("[0-9]+", answer.pop())]
|
||||
|
||||
self._sendRequest(DhtNetworkSubProcess.MESSAGE_STATS, answer_cb=cb)
|
||||
return stats
|
||||
|
||||
def sendNodePutRequest(self, _hash, value):
|
||||
def sendClusterPutRequest(self, _hash, value, done_cb=None):
|
||||
"""
|
||||
Sends a put operation request.
|
||||
|
||||
@@ -239,40 +229,89 @@ class DhtNetworkSubProcess(NSPopen):
|
||||
@type _hash: bytes.
|
||||
@param value: the value.
|
||||
@type value: bytes.
|
||||
@param done_cb: A function taking as parameter a boolean "success".
|
||||
@type done_cb: function
|
||||
"""
|
||||
self._sendRequest(b_space_join(DhtNetworkSubProcess.NODE_PUT_REQ, _hash,
|
||||
value))
|
||||
self._tid += 1
|
||||
def dcb(packet):
|
||||
nonlocal done_cb
|
||||
if not done_cb:
|
||||
return
|
||||
try:
|
||||
done_cb(packet[b'success'])
|
||||
except KeyError:
|
||||
done_cb(False)
|
||||
self._sendRequest(msgpack.packb({
|
||||
DhtNetworkSubProcess.REQUEST : True,
|
||||
'tid' : self._tid,
|
||||
'req' : DhtNetworkSubProcess.NODE_PUT_REQ,
|
||||
'hash' : _hash,
|
||||
'value' : value
|
||||
}), self._tid, dcb)
|
||||
|
||||
def sendNodesRequest(self, request, ids=b''):
|
||||
def sendClusterRequest(self, request, ids=[], done_cb=None):
|
||||
"""
|
||||
Send request to a list of nodes or the whole cluster.
|
||||
|
||||
@param request: The request. Possible values are:
|
||||
DhtNetworkSubProcess.NODE_PUT_REQ
|
||||
DhtNetworkSubProcess.REMOVE_NODE_REQ
|
||||
DhtNetworkSubProcess.SHUTDOWN_NODE_REQ
|
||||
DhtNetworkSubProcess.SHUTDOWN_REPLACE_NODE_REQ
|
||||
DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ
|
||||
DhtNetworkSubProcess.DUMP_STORAGE_REQ
|
||||
DhtNetworkSubProcess.MESSAGE_STATS
|
||||
@type request: bytes
|
||||
@param ids: The list of ids concerned by the request.
|
||||
@type ids: list
|
||||
"""
|
||||
self._sendRequest(b_space_join(request, b_space_join(*ids)))
|
||||
self._tid += 1
|
||||
def dcb(packet):
|
||||
nonlocal done_cb
|
||||
if not done_cb:
|
||||
return
|
||||
try:
|
||||
done_cb(packet[b'success'])
|
||||
except KeyError:
|
||||
done_cb(False)
|
||||
self._sendRequest(msgpack.packb({
|
||||
DhtNetworkSubProcess.REQUEST : True,
|
||||
'tid' : self._tid,
|
||||
'req' : request,
|
||||
'ids' : ids
|
||||
}), self._tid, dcb)
|
||||
|
||||
|
||||
class DhtNetwork(object):
|
||||
nodes = []
|
||||
|
||||
@staticmethod
|
||||
def log(*to_print):
|
||||
class Log(object):
|
||||
BOLD = "\033[1m"
|
||||
NORMAL = "\033[0m"
|
||||
print('%s[DhtNetwork-%s]%s' % (BOLD, DhtNetwork.iface, NORMAL), ':' , *to_print, file=sys.stderr)
|
||||
WHITE = "\033[97m"
|
||||
RED = "\033[31m"
|
||||
YELLOW = "\033[33m"
|
||||
|
||||
@staticmethod
|
||||
def _log_with_color(*to_print, color=None):
|
||||
color = color if color else DhtNetwork.Log.WHITE
|
||||
print('%s%s[DhtNetwork-%s]%s%s' %
|
||||
(DhtNetwork.Log.BOLD, color, DhtNetwork.iface, DhtNetwork.Log.NORMAL, color),
|
||||
*to_print, DhtNetwork.Log.NORMAL, file=sys.stderr)
|
||||
|
||||
@staticmethod
|
||||
def log(*to_print):
|
||||
DhtNetwork.Log._log_with_color(*to_print, color=DhtNetwork.Log.WHITE)
|
||||
|
||||
@staticmethod
|
||||
def warn(*to_print):
|
||||
DhtNetwork.Log._log_with_color(*to_print, color=DhtNetwork.Log.YELLOW)
|
||||
|
||||
@staticmethod
|
||||
def err(*to_print):
|
||||
DhtNetwork.Log._log_with_color(*to_print, color=DhtNetwork.Log.RED)
|
||||
|
||||
@staticmethod
|
||||
def run_node(ip4, ip6, p, bootstrap=[], is_bootstrap=False):
|
||||
DhtNetwork.log("run_node", ip4, ip6, p, bootstrap)
|
||||
DhtNetwork.Log.log("run_node", ip4, ip6, p, bootstrap)
|
||||
n = DhtRunner()
|
||||
n.run(ipv4=ip4 if ip4 else "", ipv6=ip6 if ip6 else "", port=p, is_bootstrap=is_bootstrap)
|
||||
for b in bootstrap:
|
||||
@@ -297,7 +336,7 @@ class DhtNetwork(object):
|
||||
self.ip6 = ip6 if ip6 else ips[1]
|
||||
self.bootstrap = bootstrap
|
||||
if first_bootstrap:
|
||||
DhtNetwork.log("Starting bootstrap node")
|
||||
DhtNetwork.Log.log("Starting bootstrap node")
|
||||
self.nodes.append(DhtNetwork.run_node(self.ip4, self.ip6, self.port, self.bootstrap, is_bootstrap=True))
|
||||
self.bootstrap = [(self.ip4, str(self.port))]
|
||||
self.port += 1
|
||||
@@ -309,6 +348,9 @@ class DhtNetwork(object):
|
||||
return self.nodes[0][1]
|
||||
|
||||
def get(self, i=None):
|
||||
if not self.nodes:
|
||||
return None
|
||||
|
||||
if i is None:
|
||||
l = list(self.nodes)
|
||||
random.shuffle(l)
|
||||
@@ -321,14 +363,13 @@ class DhtNetwork(object):
|
||||
for n in self.nodes:
|
||||
if n[1].getNodeId() == id:
|
||||
return n
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
def launch_node(self):
|
||||
n = DhtNetwork.run_node(self.ip4, self.ip6, self.port, self.bootstrap)
|
||||
self.nodes.append(n)
|
||||
if not self.bootstrap:
|
||||
DhtNetwork.log("Using fallback bootstrap", self.ip4, self.port)
|
||||
DhtNetwork.Log.log("Using fallback bootstrap", self.ip4, self.port)
|
||||
self.bootstrap = [(self.ip4, str(self.port))]
|
||||
self.port += 1
|
||||
return n
|
||||
@@ -346,25 +387,25 @@ class DhtNetwork(object):
|
||||
lock = threading.Condition()
|
||||
def shutdown_cb():
|
||||
nonlocal lock
|
||||
DhtNetwork.log('Done.')
|
||||
DhtNetwork.Log.log('Done.')
|
||||
with lock:
|
||||
lock.notify()
|
||||
|
||||
if not self.nodes:
|
||||
return
|
||||
elif id is not None:
|
||||
elif id:
|
||||
n = self.getNodeInfoById(id)
|
||||
if n:
|
||||
if shutdown:
|
||||
with lock:
|
||||
DhtNetwork.log('Waiting for node to shutdown... ')
|
||||
DhtNetwork.Log.log('Waiting for node to shutdown... ')
|
||||
n[1].shutdown(shutdown_cb)
|
||||
lock.wait()
|
||||
if last_msg_stats:
|
||||
last_msg_stats.append(self.getMessageStats())
|
||||
n[1].join()
|
||||
self.nodes.remove(n)
|
||||
DhtNetwork.log(id, 'deleted !')
|
||||
DhtNetwork.Log.log(id, 'deleted !')
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -385,11 +426,11 @@ class DhtNetwork(object):
|
||||
if n == l:
|
||||
return
|
||||
if n > l:
|
||||
DhtNetwork.log("Launching", n-l, "nodes", self.ip4, self.ip6)
|
||||
DhtNetwork.Log.log("Launching", n-l, "nodes", self.ip4, self.ip6)
|
||||
for i in range(l, n):
|
||||
self.launch_node()
|
||||
else:
|
||||
DhtNetwork.log("Ending", l-n, "nodes", self.ip4, self.ip6)
|
||||
DhtNetwork.Log.log("Ending", l-n, "nodes", self.ip4, self.ip6)
|
||||
#random.shuffle(self.nodes)
|
||||
for i in range(n, l):
|
||||
self.end_node()
|
||||
@@ -409,30 +450,39 @@ if __name__ == '__main__':
|
||||
lock = threading.Condition()
|
||||
quit = False
|
||||
|
||||
def notify_benchmark(answer=[]):
|
||||
sys.stdout.write('%s\n' % DhtNetworkSubProcess.NOTIFY_TOKEN)
|
||||
for line in answer:
|
||||
sys.stdout.write(str(line)+'\n')
|
||||
sys.stdout.write('%s\n' % DhtNetworkSubProcess.NOTIFY_END_TOKEN)
|
||||
sys.stdout.flush()
|
||||
def send_msgpack_packet(packet):
|
||||
sys.stdout.buffer.write(packet)
|
||||
sys.stdout.buffer.flush()
|
||||
|
||||
def listen_to_mother_nature(stdin, q):
|
||||
def notify_benchmark(packet, success):
|
||||
"""Notifies the benchmark when an operation has been completed.
|
||||
|
||||
@param success: If the operation has been successful
|
||||
@type success: boolean
|
||||
@param packet: The packet we are providing an answer for.
|
||||
@type packet: dict
|
||||
"""
|
||||
send_msgpack_packet(msgpack.packb({
|
||||
DhtNetworkSubProcess.ANSWER : True,
|
||||
'tid' : packet[b'tid'],
|
||||
'success' : success
|
||||
}))
|
||||
|
||||
def send_stats(packet, stats):
|
||||
send_msgpack_packet(msgpack.packb({
|
||||
DhtNetworkSubProcess.ANSWER : True,
|
||||
'tid' : packet[b'tid'],
|
||||
'stats' : stats
|
||||
}))
|
||||
|
||||
def listen_to_mother_nature(q):
|
||||
global quit
|
||||
|
||||
def parse_req(req):
|
||||
split_req = req.split(' ')
|
||||
|
||||
op = split_req[0]
|
||||
hashes = [this_hash.replace('\n', '').encode() for this_hash in split_req[1:]]
|
||||
|
||||
return (op, hashes)
|
||||
|
||||
while not quit:
|
||||
req = stdin.readline()
|
||||
parsed_req = parse_req(req)
|
||||
q.put(parsed_req)
|
||||
with lock:
|
||||
lock.notify()
|
||||
for p in msgpack.Unpacker(sys.stdin.buffer.raw):
|
||||
if isinstance(p, dict) and DhtNetworkSubProcess.REQUEST.encode() in p:
|
||||
with lock:
|
||||
q.put(p)
|
||||
lock.notify()
|
||||
|
||||
def handler(signum, frame):
|
||||
global quit
|
||||
@@ -466,48 +516,52 @@ if __name__ == '__main__':
|
||||
net.resize(args.node_num)
|
||||
|
||||
q = queue.Queue()
|
||||
t = threading.Thread(target=listen_to_mother_nature, args=(sys.stdin, q))
|
||||
t = threading.Thread(target=listen_to_mother_nature, args=tuple([q]))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
notify_benchmark()
|
||||
|
||||
msg_stats = []
|
||||
|
||||
with lock:
|
||||
while not quit:
|
||||
lock.wait()
|
||||
try:
|
||||
req,req_args = q.get_nowait()
|
||||
packet = q.get_nowait()
|
||||
except queue.Empty:
|
||||
pass
|
||||
lock.wait()
|
||||
else:
|
||||
NODE_PUT_REQ = DhtNetworkSubProcess.NODE_PUT_REQ.decode()
|
||||
NEW_NODE_REQ = DhtNetworkSubProcess.NEW_NODE_REQ.decode()
|
||||
REMOVE_NODE_REQ = DhtNetworkSubProcess.REMOVE_NODE_REQ.decode()
|
||||
SHUTDOWN_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_NODE_REQ.decode()
|
||||
SHUTDOWN_REPLACE_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_REPLACE_NODE_REQ.decode()
|
||||
SHUTDOWN_CLUSTER_REQ = DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ.decode()
|
||||
DUMP_STORAGE_REQ = DhtNetworkSubProcess.DUMP_STORAGE_REQ.decode()
|
||||
MESSAGE_STATS = DhtNetworkSubProcess.MESSAGE_STATS.decode()
|
||||
NODE_PUT_REQ = DhtNetworkSubProcess.NODE_PUT_REQ
|
||||
NEW_NODE_REQ = DhtNetworkSubProcess.NEW_NODE_REQ
|
||||
REMOVE_NODE_REQ = DhtNetworkSubProcess.REMOVE_NODE_REQ
|
||||
SHUTDOWN_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_NODE_REQ
|
||||
SHUTDOWN_REPLACE_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_REPLACE_NODE_REQ
|
||||
SHUTDOWN_CLUSTER_REQ = DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ
|
||||
DUMP_STORAGE_REQ = DhtNetworkSubProcess.DUMP_STORAGE_REQ
|
||||
MESSAGE_STATS = DhtNetworkSubProcess.MESSAGE_STATS
|
||||
|
||||
if req in [SHUTDOWN_NODE_REQ,
|
||||
SHUTDOWN_REPLACE_NODE_REQ,
|
||||
REMOVE_NODE_REQ]:
|
||||
def delete_request(req, n):
|
||||
req = packet[b'req'].decode()
|
||||
success = True
|
||||
if req in [SHUTDOWN_NODE_REQ, SHUTDOWN_REPLACE_NODE_REQ, REMOVE_NODE_REQ]:
|
||||
def delete_request(req, nid):
|
||||
global msg_stats
|
||||
if not nid:
|
||||
return
|
||||
if req == SHUTDOWN_NODE_REQ:
|
||||
net.end_node(id=n, shutdown=True, last_msg_stats=msg_stats)
|
||||
net.end_node(id=nid, shutdown=True, last_msg_stats=msg_stats)
|
||||
elif req == SHUTDOWN_REPLACE_NODE_REQ:
|
||||
net.replace_node(id=n, shutdown=True, last_msg_stats=msg_stats)
|
||||
net.replace_node(id=nid, shutdown=True, last_msg_stats=msg_stats)
|
||||
elif req == REMOVE_NODE_REQ:
|
||||
net.end_node(id=n, last_msg_stats=msg_stats)
|
||||
net.end_node(id=nid, last_msg_stats=msg_stats)
|
||||
|
||||
if len(req) > 0:
|
||||
for n in req_args:
|
||||
delete_request(req, n)
|
||||
nodes = packet[b'ids']
|
||||
if nodes:
|
||||
for nid in nodes:
|
||||
delete_request(req, nid)
|
||||
else:
|
||||
delete_request(req, net.get().getNodeId())
|
||||
n = net.get()
|
||||
if n:
|
||||
delete_request(req, n.getNodeId())
|
||||
else:
|
||||
success = False
|
||||
elif req == SHUTDOWN_CLUSTER_REQ:
|
||||
for n in net.nodes:
|
||||
net.end_node(id=n[2], shutdown=True, last_msg_stats=msg_stats)
|
||||
@@ -515,20 +569,26 @@ if __name__ == '__main__':
|
||||
elif req == NEW_NODE_REQ:
|
||||
net.launch_node()
|
||||
elif req == NODE_PUT_REQ:
|
||||
_hash, v = req_args[:2]
|
||||
net.get().put(InfoHash(_hash), Value(v))
|
||||
|
||||
_hash = packet[b'hash']
|
||||
v = packet[b'value']
|
||||
n = net.get()
|
||||
if n:
|
||||
n.put(InfoHash(_hash), Value(v))
|
||||
else:
|
||||
success = False
|
||||
elif req == DUMP_STORAGE_REQ:
|
||||
for n in [m[1] for m in net.nodes if m[1].getNodeId() in req_args]:
|
||||
hashes = packet[b'ids']
|
||||
for n in [m[1] for m in net.nodes if m[1].getNodeId() in hashes]:
|
||||
net.log(n.getStorageLog())
|
||||
elif MESSAGE_STATS in req:
|
||||
elif req == MESSAGE_STATS:
|
||||
stats = sum([np.array(x) for x in [net.getMessageStats()]+msg_stats])
|
||||
notify_benchmark(answer=[stats])
|
||||
send_stats(packet, [int(_) for _ in stats])
|
||||
msg_stats.clear()
|
||||
continue
|
||||
notify_benchmark()
|
||||
notify_benchmark(packet, success)
|
||||
except Exception as e:
|
||||
DhtNetwork.log(e)
|
||||
traceback.print_tb(e.__traceback__)
|
||||
print(type(e).__name__+':', e, file=sys.stderr)
|
||||
finally:
|
||||
if net:
|
||||
net.resize(0)
|
||||
+365
-120
@@ -3,6 +3,7 @@
|
||||
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
# Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
|
||||
import sys
|
||||
import os
|
||||
import threading
|
||||
import random
|
||||
@@ -10,10 +11,16 @@ import string
|
||||
import time
|
||||
import subprocess
|
||||
import re
|
||||
import collections
|
||||
|
||||
from matplotlib.ticker import FuncFormatter
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.ticker import FuncFormatter
|
||||
import networkx as nx
|
||||
from networkx.drawing.nx_agraph import graphviz_layout
|
||||
|
||||
|
||||
from opendht import *
|
||||
from dht.network import DhtNetwork, DhtNetworkSubProcess
|
||||
@@ -27,8 +34,40 @@ bit_format = None
|
||||
Kbit_format = FuncFormatter(lambda x, pos: '%1.1f' % (x*1024**-1) + 'Kb')
|
||||
Mbit_format = FuncFormatter(lambda x, pos: '%1.1f' % (x*1024**-2) + 'Mb')
|
||||
|
||||
def random_str_val(size=1024):
|
||||
"""Creates a random string value of specified size.
|
||||
|
||||
@param size: Size, in bytes, of the value.
|
||||
@type size: int
|
||||
|
||||
@return: Random string value
|
||||
@rtype : str
|
||||
"""
|
||||
return ''.join(random.choice(string.hexdigits) for _ in range(size))
|
||||
|
||||
|
||||
def random_hash():
|
||||
return InfoHash(''.join(random.SystemRandom().choice(string.hexdigits) for _ in range(40)).encode())
|
||||
"""Creates random InfoHash.
|
||||
"""
|
||||
return InfoHash(random_str_val(size=40).encode())
|
||||
|
||||
def timer(f, *args):
|
||||
"""
|
||||
Start a timer which count time taken for execute function f
|
||||
|
||||
@param f : Function to time
|
||||
@type f : function
|
||||
|
||||
@param args : Arguments of the function f
|
||||
@type args : list
|
||||
|
||||
@rtype : timer
|
||||
@return : Time taken by the function f
|
||||
"""
|
||||
start = time.time()
|
||||
f(*args)
|
||||
|
||||
return time.time() - start
|
||||
|
||||
def reset_before_test(featureTestMethod):
|
||||
"""
|
||||
@@ -70,6 +109,21 @@ def display_plot(yvals, xvals=None, yformatter=None, display_time=3, **kwargs):
|
||||
plt.plot(yvals, **kwargs)
|
||||
plt.pause(display_time)
|
||||
|
||||
def display_traffic_plot(ifname):
|
||||
"""Displays the traffic plot for a given interface name.
|
||||
|
||||
@param ifname: Interface name.
|
||||
@type ifname: string
|
||||
"""
|
||||
ydata = []
|
||||
xdata = []
|
||||
# warning: infinite loop
|
||||
interval = 2
|
||||
for rate in iftop_traffic_data(ifname, interval=interval):
|
||||
ydata.append(rate)
|
||||
xdata.append((xdata[-1] if len(xdata) > 0 else 0) + interval)
|
||||
display_plot(ydata, xvals=xdata, yformatter=Kbit_format, color='blue')
|
||||
|
||||
def iftop_traffic_data(ifname, interval=2, rate_type='send_receive'):
|
||||
"""
|
||||
Generator (yields data) function collecting traffic data from iftop
|
||||
@@ -125,13 +179,13 @@ def iftop_traffic_data(ifname, interval=2, rate_type='send_receive'):
|
||||
###########
|
||||
|
||||
class FeatureTest(object):
|
||||
done = 0
|
||||
lock = None
|
||||
|
||||
"""
|
||||
This is a base test.
|
||||
"""
|
||||
|
||||
done = 0
|
||||
lock = None
|
||||
|
||||
def __init__(self, test, workbench):
|
||||
"""
|
||||
@param test: The test string indicating the test to run. This string is
|
||||
@@ -143,6 +197,7 @@ class FeatureTest(object):
|
||||
"""
|
||||
self._test = test
|
||||
self._workbench = workbench
|
||||
self._bootstrap = self._workbench.get_bootstrap()
|
||||
|
||||
def _reset(self):
|
||||
"""
|
||||
@@ -156,7 +211,155 @@ class FeatureTest(object):
|
||||
def run(self):
|
||||
raise NotImplementedError('This method must be implemented.')
|
||||
|
||||
##################################
|
||||
# PHT #
|
||||
##################################
|
||||
|
||||
class PhtTest(FeatureTest):
|
||||
"""TODO
|
||||
"""
|
||||
|
||||
indexEntries = None
|
||||
prefix = None
|
||||
key = None
|
||||
|
||||
def __init__(self, test, workbench, opts):
|
||||
"""
|
||||
@param test: is one of the following:
|
||||
- 'insert': indexes a considerable amount of data in
|
||||
the PHT structure.
|
||||
TODO
|
||||
@type test: string
|
||||
|
||||
@param opts: Dictionnary containing options for the test. Allowed
|
||||
options are:
|
||||
- 'num_keys': this specifies the number of keys to insert
|
||||
in the PHT during the test.
|
||||
@type opts: dict
|
||||
"""
|
||||
super(PhtTest, self).__init__(test, workbench)
|
||||
self._num_keys = opts['num_keys'] if 'num_keys' in opts else 32
|
||||
self._timer = True if 'timer' in opts else False
|
||||
|
||||
def _reset(self):
|
||||
super(PhtTest, self)._reset()
|
||||
PhtTest.indexEntries = []
|
||||
|
||||
@staticmethod
|
||||
def lookupCb(vals, prefix):
|
||||
PhtTest.indexEntries = list(vals)
|
||||
PhtTest.prefix = prefix.decode()
|
||||
DhtNetwork.log('Index name: <todo>')
|
||||
DhtNetwork.log('Leaf prefix:', prefix)
|
||||
for v in vals:
|
||||
DhtNetwork.log('[ENTRY]:', v)
|
||||
|
||||
@staticmethod
|
||||
def lookupDoneCb(ok):
|
||||
DhtNetwork.log('[LOOKUP]:', PhtTest.key, "--", "success!" if ok else "Fail...")
|
||||
with FeatureTest.lock:
|
||||
FeatureTest.lock.notify()
|
||||
|
||||
@staticmethod
|
||||
def insertDoneCb(ok):
|
||||
DhtNetwork.log('[INSERT]:', PhtTest.key, "--", "success!" if ok else "Fail...")
|
||||
with FeatureTest.lock:
|
||||
FeatureTest.lock.notify()
|
||||
|
||||
@staticmethod
|
||||
def drawTrie(trie_dict):
|
||||
"""
|
||||
Draws the trie structure of the PHT from dictionnary.
|
||||
|
||||
@param trie_dict: Dictionnary of index entries (prefix -> entry).
|
||||
@type trie_dict: dict
|
||||
"""
|
||||
prefixes = list(trie_dict.keys())
|
||||
if len(prefixes) == 0:
|
||||
return
|
||||
|
||||
edges = list([])
|
||||
for prefix in prefixes:
|
||||
for i in range(-1, len(prefix)-1):
|
||||
u = prefix[:i+1]
|
||||
x = ("." if i == -1 else u, u+"0")
|
||||
y = ("." if i == -1 else u, u+"1")
|
||||
if x not in edges:
|
||||
edges.append(x)
|
||||
if y not in edges:
|
||||
edges.append(y)
|
||||
|
||||
# TODO: use a binary tree position layout...
|
||||
# UPDATE : In a better way [change lib]
|
||||
G = nx.Graph(sorted(edges, key=lambda x: len(x[0])))
|
||||
plt.title("PHT: Tree")
|
||||
pos=graphviz_layout(G,prog='dot')
|
||||
nx.draw(G, pos, with_labels=True, node_color='white')
|
||||
plt.show()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
if self._test == 'insert':
|
||||
self._insertTest()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
self._bootstrap.resize(1)
|
||||
|
||||
###########
|
||||
# Tests #
|
||||
###########
|
||||
|
||||
@reset_before_test
|
||||
def _insertTest(self):
|
||||
"""TODO: Docstring for _massIndexTest.
|
||||
"""
|
||||
bootstrap = self._bootstrap
|
||||
bootstrap.resize(2)
|
||||
dht = bootstrap.get(1)
|
||||
|
||||
NUM_DIG = max(math.log(self._num_keys, 2)/4, 5) # at least 5 digit keys.
|
||||
keyspec = collections.OrderedDict([('foo', NUM_DIG)])
|
||||
pht = Pht(b'foo_index', keyspec, dht)
|
||||
|
||||
DhtNetwork.log('PHT has',
|
||||
pht.MAX_NODE_ENTRY_COUNT,
|
||||
'node'+ ('s' if pht.MAX_NODE_ENTRY_COUNT > 1 else ''),
|
||||
'per leaf bucket.')
|
||||
keys = [{
|
||||
[_ for _ in keyspec.keys()][0] :
|
||||
''.join(random.SystemRandom().choice(string.hexdigits)
|
||||
for _ in range(NUM_DIG)).encode()
|
||||
} for n in range(self._num_keys)]
|
||||
all_entries = {}
|
||||
|
||||
# Index all entries.
|
||||
for key in keys:
|
||||
PhtTest.key = key
|
||||
with FeatureTest.lock:
|
||||
time_taken = timer(pht.insert, key, IndexValue(random_hash()), PhtTest.insertDoneCb)
|
||||
if self._timer:
|
||||
DhtNetwork.log('This insert step took : ', time_taken, 'second')
|
||||
FeatureTest.lock.wait()
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# Recover entries now that the trie is complete.
|
||||
for key in keys:
|
||||
PhtTest.key = key
|
||||
with FeatureTest.lock:
|
||||
time_taken = timer(pht.lookup, key, PhtTest.lookupCb, PhtTest.lookupDoneCb)
|
||||
if self._timer:
|
||||
DhtNetwork.log('This lookup step took : ', time_taken, 'second')
|
||||
FeatureTest.lock.wait()
|
||||
|
||||
all_entries[PhtTest.prefix] = [e.__str__()
|
||||
for e in PhtTest.indexEntries]
|
||||
|
||||
for p in all_entries.keys():
|
||||
DhtNetwork.log('All entries under prefix', p, ':')
|
||||
DhtNetwork.log(all_entries[p])
|
||||
PhtTest.drawTrie(all_entries)
|
||||
|
||||
##################################
|
||||
# DHT #
|
||||
@@ -164,7 +367,7 @@ class FeatureTest(object):
|
||||
|
||||
class DhtFeatureTest(FeatureTest):
|
||||
"""
|
||||
This is base test. A method run() implementation is required.
|
||||
This is a base dht test.
|
||||
"""
|
||||
#static variables used by class callbacks
|
||||
successfullTransfer = lambda lv,fv: len(lv) == len(fv)
|
||||
@@ -173,7 +376,6 @@ class DhtFeatureTest(FeatureTest):
|
||||
|
||||
def __init__(self, test, workbench):
|
||||
super(DhtFeatureTest, self).__init__(test, workbench)
|
||||
self.bootstrap = self._workbench.get_bootstrap()
|
||||
|
||||
def _reset(self):
|
||||
super(DhtFeatureTest, self)._reset()
|
||||
@@ -183,15 +385,15 @@ class DhtFeatureTest(FeatureTest):
|
||||
@staticmethod
|
||||
def getcb(value):
|
||||
vstr = value.__str__()[:100]
|
||||
DhtNetwork.log('[GET]: %s' % vstr + ("..." if len(vstr) > 100 else ""))
|
||||
DhtNetwork.Log.log('[GET]: %s' % vstr + ("..." if len(vstr) > 100 else ""))
|
||||
DhtFeatureTest.foreignValues.append(value)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def putDoneCb(ok, nodes):
|
||||
if not ok:
|
||||
DhtNetwork.log("[PUT]: failed!")
|
||||
with FeatureTest.lock:
|
||||
if not ok:
|
||||
DhtNetwork.Log.log("[PUT]: failed!")
|
||||
FeatureTest.done -= 1
|
||||
FeatureTest.lock.notify()
|
||||
|
||||
@@ -199,7 +401,7 @@ class DhtFeatureTest(FeatureTest):
|
||||
def getDoneCb(ok, nodes):
|
||||
with FeatureTest.lock:
|
||||
if not ok:
|
||||
DhtNetwork.log("[GET]: failed!")
|
||||
DhtNetwork.Log.log("[GET]: failed!")
|
||||
else:
|
||||
for node in nodes:
|
||||
if not node.getNode().isExpired():
|
||||
@@ -208,23 +410,23 @@ class DhtFeatureTest(FeatureTest):
|
||||
FeatureTest.lock.notify()
|
||||
|
||||
def _dhtPut(self, producer, _hash, *values):
|
||||
for val in values:
|
||||
with FeatureTest.lock:
|
||||
with FeatureTest.lock:
|
||||
for val in values:
|
||||
vstr = val.__str__()[:100]
|
||||
DhtNetwork.log('[PUT]:', _hash.toString(), '->', vstr + ("..." if len(vstr) > 100 else ""))
|
||||
DhtNetwork.Log.log('[PUT]:', _hash.toString(), '->', vstr + ("..." if len(vstr) > 100 else ""))
|
||||
FeatureTest.done += 1
|
||||
while FeatureTest.done > 0:
|
||||
producer.put(_hash, val, DhtFeatureTest.putDoneCb)
|
||||
FeatureTest.lock.wait()
|
||||
producer.put(_hash, val, DhtFeatureTest.putDoneCb)
|
||||
while FeatureTest.done > 0:
|
||||
FeatureTest.lock.wait()
|
||||
|
||||
def _dhtGet(self, consumer, _hash):
|
||||
DhtFeatureTest.foreignValues = []
|
||||
DhtFeatureTest.foreignNodes = []
|
||||
with FeatureTest.lock:
|
||||
FeatureTest.done += 1
|
||||
DhtNetwork.Log.log('[GET]:', _hash.toString())
|
||||
consumer.get(_hash, DhtFeatureTest.getcb, DhtFeatureTest.getDoneCb)
|
||||
while FeatureTest.done > 0:
|
||||
DhtNetwork.log('[GET]:', _hash.toString())
|
||||
consumer.get(_hash, DhtFeatureTest.getcb, DhtFeatureTest.getDoneCb)
|
||||
FeatureTest.lock.wait()
|
||||
|
||||
def _gottaGetThemAllPokeNodes(self, consumer, hashes, nodes=None):
|
||||
@@ -234,7 +436,6 @@ class DhtFeatureTest(FeatureTest):
|
||||
for n in DhtFeatureTest.foreignNodes:
|
||||
nodes.add(n)
|
||||
|
||||
|
||||
class PersistenceTest(DhtFeatureTest):
|
||||
"""
|
||||
This tests persistence of data on the network.
|
||||
@@ -292,8 +493,8 @@ class PersistenceTest(DhtFeatureTest):
|
||||
config.setNodeId(InfoHash(_hash_str.encode()))
|
||||
n = DhtRunner()
|
||||
n.run(config=config)
|
||||
n.bootstrap(self.bootstrap.ip4,
|
||||
str(self.bootstrap.port))
|
||||
n.bootstrap(self._bootstrap.ip4,
|
||||
str(self._bootstrap.port))
|
||||
DhtNetwork.log('Node','['+_hash_str+']',
|
||||
'started around', _hash.toString().decode()
|
||||
if n.isRunning() else
|
||||
@@ -302,24 +503,24 @@ class PersistenceTest(DhtFeatureTest):
|
||||
trigger_nodes.append(n)
|
||||
|
||||
def _result(self, local_values, new_nodes):
|
||||
bootstrap = self.bootstrap
|
||||
bootstrap = self._bootstrap
|
||||
if not DhtFeatureTest.successfullTransfer(local_values, DhtFeatureTest.foreignValues):
|
||||
DhtNetwork.log('[GET]: Only %s on %s values persisted.' %
|
||||
DhtNetwork.Log.log('[GET]: Only %s on %s values persisted.' %
|
||||
(len(DhtFeatureTest.foreignValues), len(local_values)))
|
||||
else:
|
||||
DhtNetwork.log('[GET]: All values successfully persisted.')
|
||||
DhtNetwork.Log.log('[GET]: All values successfully persisted.')
|
||||
if DhtFeatureTest.foreignValues:
|
||||
if new_nodes:
|
||||
DhtNetwork.log('Values are newly found on:')
|
||||
DhtNetwork.Log.log('Values are newly found on:')
|
||||
for node in new_nodes:
|
||||
DhtNetwork.log(node)
|
||||
DhtNetwork.Log.log(node)
|
||||
if self._dump_storage:
|
||||
DhtNetwork.log('Dumping all storage log from '\
|
||||
DhtNetwork.Log.log('Dumping all storage log from '\
|
||||
'hosting nodes.')
|
||||
for proc in self._workbench.procs:
|
||||
proc.sendNodesRequest(DhtNetworkSubProcess.DUMP_STORAGE_REQ, DhtFeatureTest.foreignNodes)
|
||||
proc.sendClusterRequest(DhtNetworkSubProcess.DUMP_STORAGE_REQ, DhtFeatureTest.foreignNodes)
|
||||
else:
|
||||
DhtNetwork.log("Values didn't reach new hosting nodes after shutdown.")
|
||||
DhtNetwork.Log.log("Values didn't reach new hosting nodes after shutdown.")
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
@@ -334,13 +535,14 @@ class PersistenceTest(DhtFeatureTest):
|
||||
else:
|
||||
raise NameError("This test is not defined '" + self._test + "'")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
traceback.print_tb(e.__traceback__)
|
||||
print(type(e).__name__+':', e, file=sys.stderr)
|
||||
finally:
|
||||
if self._traffic_plot or self._op_plot:
|
||||
plot_fname = "traffic-plot"
|
||||
print('plot saved to', plot_fname)
|
||||
plt.savefig(plot_fname)
|
||||
self.bootstrap.resize(1)
|
||||
self._bootstrap.resize(1)
|
||||
|
||||
###########
|
||||
# Tests #
|
||||
@@ -353,68 +555,89 @@ class PersistenceTest(DhtFeatureTest):
|
||||
"""
|
||||
trigger_nodes = []
|
||||
wb = self._workbench
|
||||
bootstrap = self.bootstrap
|
||||
bootstrap = self._bootstrap
|
||||
# Value representing an ICE packet. Each ICE packet is around 1KB.
|
||||
VALUE_SIZE = 1024
|
||||
NUM_VALUES = self._num_values/wb.node_num if self._num_values else 50
|
||||
nr_values = NUM_VALUES * wb.node_num
|
||||
nr_nodes = wb.node_num
|
||||
nr_nodes_cv = threading.Condition()
|
||||
num_values_per_hash = self._num_values/wb.node_num if self._num_values else 5
|
||||
|
||||
values = [b''.join(random.choice(string.hexdigits).encode() for _ in range(VALUE_SIZE)) for __ in range(NUM_VALUES)]
|
||||
# nodes and values counters
|
||||
total_nr_values = 0
|
||||
nr_nodes = wb.node_num
|
||||
op_cv = threading.Condition()
|
||||
|
||||
# values string in string format. Used for sending cluster request.
|
||||
hashes = [random_hash() for _ in range(wb.node_num)]
|
||||
|
||||
# initial set of values
|
||||
for h in hashes:
|
||||
self._dhtPut(bootstrap.front(), h, *[Value(v) for v in values])
|
||||
|
||||
def normalBehavior(do, t, log=None):
|
||||
nonlocal nr_values
|
||||
def normalBehavior(do, t):
|
||||
nonlocal total_nr_values, op_cv
|
||||
while True:
|
||||
do()
|
||||
time.sleep(random.choice(range(t)))
|
||||
with op_cv:
|
||||
do()
|
||||
time.sleep(random.uniform(0.0, float(t)))
|
||||
|
||||
def putRequest():
|
||||
nonlocal hashes, values, nr_values
|
||||
nr_values += 1
|
||||
DhtNetwork.log("Random value put on the DHT.", "(now "+ str(nr_values)+" values on the dht)")
|
||||
random.choice(wb.procs).sendNodePutRequest(random.choice(hashes).toString(), random.choice(values))
|
||||
puts = threading.Thread(target=normalBehavior, args=(putRequest, 30))
|
||||
nonlocal hashes, VALUE_SIZE, total_nr_values
|
||||
lock = threading.Condition()
|
||||
def dcb(success):
|
||||
nonlocal total_nr_values, lock
|
||||
if success:
|
||||
total_nr_values += 1
|
||||
DhtNetwork.Log.log("INFO: "+ str(total_nr_values)+" values put on the dht since begining")
|
||||
with lock:
|
||||
lock.notify()
|
||||
with lock:
|
||||
DhtNetwork.Log.warn("Random value put on the DHT...")
|
||||
random.choice(wb.procs).sendClusterPutRequest(random.choice(hashes).toString(),
|
||||
random_str_val(size=VALUE_SIZE).encode(),
|
||||
done_cb=dcb)
|
||||
lock.wait()
|
||||
|
||||
puts = threading.Thread(target=normalBehavior, args=(putRequest, 30.0/wb.node_num))
|
||||
puts.daemon = True
|
||||
puts.start()
|
||||
|
||||
def newNodeRequest():
|
||||
nonlocal nr_nodes
|
||||
with nr_nodes_cv:
|
||||
lock = threading.Condition()
|
||||
def dcb(success):
|
||||
nonlocal nr_nodes, lock
|
||||
nr_nodes += 1
|
||||
DhtNetwork.log("Node joining the DHT.", "(now "+str(nr_nodes)+" nodes on the dht)")
|
||||
nr_nodes_cv.notify()
|
||||
random.choice(wb.procs).sendNodesRequest(DhtNetworkSubProcess.NEW_NODE_REQ)
|
||||
connections = threading.Thread(target=normalBehavior, args=(newNodeRequest, 1*60))
|
||||
DhtNetwork.Log.log("INFO: now "+str(nr_nodes)+" nodes on the dht")
|
||||
with lock:
|
||||
lock.notify()
|
||||
with lock:
|
||||
DhtNetwork.Log.warn("Node joining...")
|
||||
random.choice(wb.procs).sendClusterRequest(DhtNetworkSubProcess.NEW_NODE_REQ, done_cb=dcb)
|
||||
lock.wait()
|
||||
|
||||
connections = threading.Thread(target=normalBehavior, args=(newNodeRequest, 1*50.0/wb.node_num))
|
||||
connections.daemon = True
|
||||
connections.start()
|
||||
|
||||
def shutdownNodeRequest():
|
||||
nonlocal nr_nodes
|
||||
with nr_nodes_cv:
|
||||
nr_nodes -= 1
|
||||
DhtNetwork.log("Node quitting the DHT.", "(now "+str(nr_nodes)+" nodes on the dht)")
|
||||
nr_nodes_cv.notify()
|
||||
random.choice(wb.procs).sendNodesRequest(DhtNetworkSubProcess.SHUTDOWN_NODE_REQ)
|
||||
shutdowns = threading.Thread(target=normalBehavior, args=(shutdownNodeRequest, 1*60))
|
||||
lock = threading.Condition()
|
||||
def dcb(success):
|
||||
nonlocal nr_nodes, lock
|
||||
if success:
|
||||
nr_nodes -= 1
|
||||
DhtNetwork.Log.log("INFO: now "+str(nr_nodes)+" nodes on the dht")
|
||||
else:
|
||||
DhtNetwork.Log.err("Oops.. No node to shutodwn.")
|
||||
|
||||
with lock:
|
||||
lock.notify()
|
||||
with lock:
|
||||
DhtNetwork.Log.warn("Node shutting down...")
|
||||
random.choice(wb.procs).sendClusterRequest(DhtNetworkSubProcess.SHUTDOWN_NODE_REQ, done_cb=dcb)
|
||||
lock.wait()
|
||||
|
||||
shutdowns = threading.Thread(target=normalBehavior, args=(shutdownNodeRequest, 1*60.0/wb.node_num))
|
||||
shutdowns.daemon = True
|
||||
shutdowns.start()
|
||||
|
||||
for h in hashes:
|
||||
self._trigger_dp(trigger_nodes, h)
|
||||
|
||||
if self._traffic_plot:
|
||||
ydata = []
|
||||
xdata = []
|
||||
# warning: infinite loop
|
||||
interval = 2
|
||||
for rate in iftop_traffic_data("br"+wb.ifname, interval=interval):
|
||||
ydata.append(rate)
|
||||
xdata.append((xdata[-1] if len(xdata) > 0 else 0) + interval)
|
||||
display_plot(ydata, xvals=xdata, yformatter=Kbit_format, color='blue')
|
||||
display_traffic_plot('br'+wb.ifname)
|
||||
else:
|
||||
# blocks in matplotlib thread
|
||||
while True:
|
||||
@@ -427,7 +650,7 @@ class PersistenceTest(DhtFeatureTest):
|
||||
It uses Dht shutdown call from the API to gracefuly finish the nodes one
|
||||
after the other.
|
||||
"""
|
||||
bootstrap = self.bootstrap
|
||||
bootstrap = self._bootstrap
|
||||
|
||||
ops_count = []
|
||||
|
||||
@@ -444,36 +667,54 @@ class PersistenceTest(DhtFeatureTest):
|
||||
self._dhtGet(consumer, myhash)
|
||||
if not DhtFeatureTest.successfullTransfer(local_values, DhtFeatureTest.foreignValues):
|
||||
if DhtFeatureTest.foreignValues:
|
||||
DhtNetwork.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
|
||||
DhtNetwork.Log.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
|
||||
len(local_values), ' values successfully put.')
|
||||
else:
|
||||
DhtNetwork.log('[GET]: 0 values successfully put')
|
||||
DhtNetwork.Log.log('[GET]: 0 values successfully put')
|
||||
|
||||
|
||||
if DhtFeatureTest.foreignValues and DhtFeatureTest.foreignNodes:
|
||||
DhtNetwork.log('Values are found on :')
|
||||
DhtNetwork.Log.log('Values are found on :')
|
||||
for node in DhtFeatureTest.foreignNodes:
|
||||
DhtNetwork.log(node)
|
||||
DhtNetwork.Log.log(node)
|
||||
|
||||
for _ in range(max(1, int(self._workbench.node_num/32))):
|
||||
DhtNetwork.log('Removing all nodes hosting target values...')
|
||||
DhtNetwork.Log.log('Removing all nodes hosting target values...')
|
||||
cluster_ops_count = 0
|
||||
for proc in self._workbench.procs:
|
||||
DhtNetwork.log('[REMOVE]: sending shutdown request to', proc)
|
||||
proc.sendNodesRequest(
|
||||
DhtNetwork.Log.log('[REMOVE]: sending shutdown request to', proc)
|
||||
lock = threading.Condition()
|
||||
def dcb(success):
|
||||
nonlocal lock
|
||||
if not success:
|
||||
DhtNetwork.Log.err("Failed to shutdown.")
|
||||
with lock:
|
||||
lock.notify()
|
||||
|
||||
with lock:
|
||||
proc.sendClusterRequest(
|
||||
DhtNetworkSubProcess.SHUTDOWN_NODE_REQ,
|
||||
DhtFeatureTest.foreignNodes
|
||||
)
|
||||
DhtNetwork.log('sending message stats request')
|
||||
stats = proc.sendGetMessageStats()
|
||||
cluster_ops_count += sum(stats[1:])
|
||||
DhtNetwork.log("5 seconds wait...")
|
||||
DhtFeatureTest.foreignNodes,
|
||||
done_cb=dcb
|
||||
)
|
||||
lock.wait()
|
||||
DhtNetwork.Log.log('sending message stats request')
|
||||
def msg_dcb(stats):
|
||||
nonlocal cluster_ops_count, lock
|
||||
if stats:
|
||||
cluster_ops_count += sum(stats[1:])
|
||||
with lock:
|
||||
lock.notify()
|
||||
with lock:
|
||||
proc.sendGetMessageStats(done_cb=msg_dcb)
|
||||
lock.wait()
|
||||
DhtNetwork.Log.log("5 seconds wait...")
|
||||
time.sleep(5)
|
||||
ops_count.append(cluster_ops_count/self._workbench.node_num)
|
||||
|
||||
# checking if values were transfered to new nodes
|
||||
foreignNodes_before_delete = DhtFeatureTest.foreignNodes
|
||||
DhtNetwork.log('[GET]: trying to fetch persistent values')
|
||||
DhtNetwork.Log.log('[GET]: trying to fetch persistent values')
|
||||
self._dhtGet(consumer, myhash)
|
||||
new_nodes = set(DhtFeatureTest.foreignNodes) - set(foreignNodes_before_delete)
|
||||
|
||||
@@ -482,7 +723,11 @@ class PersistenceTest(DhtFeatureTest):
|
||||
if self._op_plot:
|
||||
display_plot(ops_count, color='blue')
|
||||
else:
|
||||
DhtNetwork.log("[GET]: either couldn't fetch values or nodes hosting values...")
|
||||
DhtNetwork.Log.log("[GET]: either couldn't fetch values or nodes hosting values...")
|
||||
|
||||
if traffic_plot_thread:
|
||||
print("Traffic plot running for ever. Ctrl-c for stopping it.")
|
||||
traffic_plot_thread.join()
|
||||
|
||||
@reset_before_test
|
||||
def _replaceClusterTest(self):
|
||||
@@ -491,7 +736,7 @@ class PersistenceTest(DhtFeatureTest):
|
||||
"""
|
||||
clusters = 8
|
||||
|
||||
bootstrap = self.bootstrap
|
||||
bootstrap = self._bootstrap
|
||||
|
||||
bootstrap.resize(3)
|
||||
consumer = bootstrap.get(1)
|
||||
@@ -504,16 +749,16 @@ class PersistenceTest(DhtFeatureTest):
|
||||
self._dhtGet(consumer, myhash)
|
||||
initial_nodes = DhtFeatureTest.foreignNodes
|
||||
|
||||
DhtNetwork.log('Replacing', clusters, 'random clusters successively...')
|
||||
DhtNetwork.Log.log('Replacing', clusters, 'random clusters successively...')
|
||||
for n in range(clusters):
|
||||
i = random.randint(0, len(self._workbench.procs)-1)
|
||||
proc = self._workbench.procs[i]
|
||||
DhtNetwork.log('Replacing', proc)
|
||||
proc.sendNodesRequest(DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ)
|
||||
DhtNetwork.Log.log('Replacing', proc)
|
||||
proc.sendClusterRequest(DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ)
|
||||
self._workbench.stop_cluster(i)
|
||||
self._workbench.start_cluster(i)
|
||||
|
||||
DhtNetwork.log('[GET]: trying to fetch persistent values')
|
||||
DhtNetwork.Log.log('[GET]: trying to fetch persistent values')
|
||||
self._dhtGet(consumer, myhash)
|
||||
new_nodes = set(DhtFeatureTest.foreignNodes) - set(initial_nodes)
|
||||
|
||||
@@ -528,17 +773,17 @@ class PersistenceTest(DhtFeatureTest):
|
||||
minutes for the nodes to trigger storage maintenance.
|
||||
"""
|
||||
trigger_nodes = []
|
||||
bootstrap = self.bootstrap
|
||||
bootstrap = self._bootstrap
|
||||
|
||||
N_PRODUCERS = self._num_producers if self._num_values else 16
|
||||
DP_TIMEOUT = 1
|
||||
|
||||
hashes = []
|
||||
|
||||
# Generating considerable amount of values of size 1KB.
|
||||
# Generating considerable amount of values of size 1KB.
|
||||
VALUE_SIZE = 1024
|
||||
NUM_VALUES = self._num_values if self._num_values else 50
|
||||
values = [Value(''.join(random.choice(string.hexdigits) for _ in range(VALUE_SIZE)).encode()) for _ in range(NUM_VALUES)]
|
||||
values = [Value(random_str_val(size=VALUE_SIZE).encode()) for _ in range(NUM_VALUES)]
|
||||
|
||||
bootstrap.resize(N_PRODUCERS+2)
|
||||
consumer = bootstrap.get(N_PRODUCERS+1)
|
||||
@@ -552,21 +797,21 @@ class PersistenceTest(DhtFeatureTest):
|
||||
nodes = set([])
|
||||
self._gottaGetThemAllPokeNodes(consumer, hashes, nodes=nodes)
|
||||
|
||||
DhtNetwork.log("Values are found on:")
|
||||
DhtNetwork.Log.log("Values are found on:")
|
||||
for n in nodes:
|
||||
DhtNetwork.log(n)
|
||||
DhtNetwork.Log.log(n)
|
||||
|
||||
DhtNetwork.log("Creating 8 nodes around all of these hashes...")
|
||||
DhtNetwork.Log.log("Creating 8 nodes around all of these hashes...")
|
||||
for _hash in hashes:
|
||||
self._trigger_dp(trigger_nodes, _hash, count=8)
|
||||
|
||||
DhtNetwork.log('Waiting', DP_TIMEOUT+1, 'minutes for normal storage maintenance.')
|
||||
DhtNetwork.Log.log('Waiting', DP_TIMEOUT+1, 'minutes for normal storage maintenance.')
|
||||
time.sleep((DP_TIMEOUT+1)*60)
|
||||
|
||||
DhtNetwork.log('Deleting old nodes from previous search.')
|
||||
DhtNetwork.Log.log('Deleting old nodes from previous search.')
|
||||
for proc in self._workbench.procs:
|
||||
DhtNetwork.log('[REMOVE]: sending delete request to', proc)
|
||||
proc.sendNodesRequest(
|
||||
DhtNetwork.Log.log('[REMOVE]: sending delete request to', proc)
|
||||
proc.sendClusterRequest(
|
||||
DhtNetworkSubProcess.REMOVE_NODE_REQ,
|
||||
nodes)
|
||||
|
||||
@@ -607,9 +852,10 @@ class PerformanceTest(DhtFeatureTest):
|
||||
else:
|
||||
raise NameError("This test is not defined '" + self._test + "'")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
traceback.print_tb(e.__traceback__)
|
||||
print(type(e).__name__+':', e, file=sys.stderr)
|
||||
finally:
|
||||
self.bootstrap.resize(1)
|
||||
self._bootstrap.resize(1)
|
||||
|
||||
|
||||
###########
|
||||
@@ -621,7 +867,7 @@ class PerformanceTest(DhtFeatureTest):
|
||||
"""
|
||||
Tests for performance of the DHT doing multiple get() operation.
|
||||
"""
|
||||
bootstrap = self.bootstrap
|
||||
bootstrap = self._bootstrap
|
||||
|
||||
plt.ion()
|
||||
|
||||
@@ -646,7 +892,7 @@ class PerformanceTest(DhtFeatureTest):
|
||||
|
||||
def getcb(v):
|
||||
nonlocal bootstrap
|
||||
DhtNetwork.log("found", v)
|
||||
DhtNetwork.Log.log("found", v)
|
||||
return True
|
||||
|
||||
def donecb(ok, nodes, start):
|
||||
@@ -654,7 +900,7 @@ class PerformanceTest(DhtFeatureTest):
|
||||
t = time.time()-start
|
||||
with lock:
|
||||
if not ok:
|
||||
DhtNetwork.log("failed !")
|
||||
DhtNetwork.Log.log("failed !")
|
||||
times.append(t)
|
||||
done -= 1
|
||||
lock.notify()
|
||||
@@ -686,7 +932,7 @@ class PerformanceTest(DhtFeatureTest):
|
||||
for n in range(10):
|
||||
self._workbench.replace_cluster()
|
||||
plt.pause(2)
|
||||
DhtNetwork.log("Getting 50 random hashes succesively.")
|
||||
DhtNetwork.Log.log("Getting 50 random hashes succesively.")
|
||||
for i in range(50):
|
||||
with lock:
|
||||
for _ in range(1):
|
||||
@@ -710,8 +956,7 @@ class PerformanceTest(DhtFeatureTest):
|
||||
deleting around the target hash.
|
||||
"""
|
||||
|
||||
|
||||
bootstrap = self.bootstrap
|
||||
bootstrap = self._bootstrap
|
||||
|
||||
bootstrap.resize(3)
|
||||
consumer = bootstrap.get(1)
|
||||
@@ -722,28 +967,28 @@ class PerformanceTest(DhtFeatureTest):
|
||||
|
||||
for _ in range(max(1, int(self._workbench.node_num/32))):
|
||||
self._dhtGet(consumer, myhash)
|
||||
DhtNetwork.log("Waiting 15 seconds...")
|
||||
DhtNetwork.Log.log("Waiting 15 seconds...")
|
||||
time.sleep(15)
|
||||
|
||||
self._dhtPut(producer, myhash, *local_values)
|
||||
|
||||
#checking if values were transfered
|
||||
self._dhtGet(consumer, myhash)
|
||||
DhtNetwork.log('Values are found on :')
|
||||
DhtNetwork.Log.log('Values are found on :')
|
||||
for node in DhtFeatureTest.foreignNodes:
|
||||
DhtNetwork.log(node)
|
||||
DhtNetwork.Log.log(node)
|
||||
|
||||
if not DhtFeatureTest.successfullTransfer(local_values, DhtFeatureTest.foreignValues):
|
||||
if DhtFeatureTest.foreignValues:
|
||||
DhtNetwork.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
|
||||
DhtNetwork.Log.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
|
||||
len(local_values), ' values successfully put.')
|
||||
else:
|
||||
DhtNetwork.log('[GET]: 0 values successfully put')
|
||||
DhtNetwork.Log.log('[GET]: 0 values successfully put')
|
||||
|
||||
DhtNetwork.log('Removing all nodes hosting target values...')
|
||||
DhtNetwork.Log.log('Removing all nodes hosting target values...')
|
||||
for proc in self._workbench.procs:
|
||||
DhtNetwork.log('[REMOVE]: sending shutdown request to', proc)
|
||||
proc.sendNodesRequest(
|
||||
DhtNetwork.Log.log('[REMOVE]: sending shutdown request to', proc)
|
||||
proc.sendClusterRequest(
|
||||
DhtNetworkSubProcess.SHUTDOWN_NODE_REQ,
|
||||
DhtFeatureTest.foreignNodes
|
||||
)
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016 Savoir-faire Linux Inc.
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from twisted.web import server, resource
|
||||
from twisted.internet import reactor, endpoints
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import opendht as dht
|
||||
import base64, json
|
||||
|
||||
class DhtServer(resource.Resource):
|
||||
isLeaf = True
|
||||
node = dht.DhtRunner()
|
||||
|
||||
def __init__(self, port, bootstrap):
|
||||
self.node.run(port=port)
|
||||
b_url = urlparse('//'+bootstrap)
|
||||
self.node.bootstrap(b_url.hostname, str(b_url.port) if b_url.port else '4222')
|
||||
|
||||
def render_GET(self, req):
|
||||
uri = req.uri[1:]
|
||||
h = dht.InfoHash(uri) if len(uri) == 40 else dht.InfoHash.get(uri.decode())
|
||||
print('GET', '"'+uri.decode()+'"', h)
|
||||
res = self.node.get(h)
|
||||
req.setHeader(b"content-type", b"application/json")
|
||||
return json.dumps({'{:x}'.format(v.id):{'base64':base64.b64encode(v.data).decode()} for v in res}).encode()
|
||||
|
||||
def render_POST(self, req):
|
||||
uri = req.uri[1:]
|
||||
data = req.args[b'data'][0] if b'data' in req.args else None
|
||||
if not data and b'base64' in req.args:
|
||||
data = base64.b64decode(req.args[b'base64'][0])
|
||||
h = dht.InfoHash(uri) if len(uri) == 40 else dht.InfoHash.get(uri.decode())
|
||||
print('POST', h, data)
|
||||
req.setHeader(b"content-type", b"application/json")
|
||||
if data:
|
||||
self.node.put(h, dht.Value(data))
|
||||
return json.dumps({'success':True}).encode()
|
||||
else:
|
||||
req.setResponseCode(400)
|
||||
return json.dumps({'success':False, 'error':'no data parameter'}).encode()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description='Launch an OpenDHT node with an HTTP control interface')
|
||||
parser.add_argument('-p', '--port', help='OpenDHT port to bind', type=int, default=4222)
|
||||
parser.add_argument('-hp', '--http-port', help='HTTP port to bind', type=int, default=8080)
|
||||
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default="bootstrap.ring.cx:4222")
|
||||
args = parser.parse_args()
|
||||
endpoints.serverFromString(reactor, "tcp:"+str(args.http_port)).listen(server.Site(DhtServer(args.port, args.bootstrap)))
|
||||
reactor.run()
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import time
|
||||
import argparse
|
||||
import time
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
|
||||
import opendht as dht
|
||||
|
||||
parser = argparse.ArgumentParser(description='Create a dht network of -n nodes')
|
||||
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default='bootstrap.ring.cx')
|
||||
parser.add_argument('-n', '--num-ops', help='number of concurrent operations on the DHT', type=int, default=8)
|
||||
parser.add_argument('-p', '--period', help='duration between each test (seconds)', type=int, default=60)
|
||||
parser.add_argument('-t', '--timeout', help='timeout for a test to complete (seconds)', type=float, default=15)
|
||||
args = parser.parse_args()
|
||||
|
||||
node1 = dht.DhtRunner()
|
||||
node1.run()
|
||||
|
||||
node2 = dht.DhtRunner()
|
||||
node2.run()
|
||||
|
||||
node1.bootstrap(args.bootstrap)
|
||||
node2.bootstrap(args.bootstrap)
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
pending_tests = {}
|
||||
keys = [dht.InfoHash.getRandom() for _ in range(args.num_ops)]
|
||||
|
||||
def listen_cb(key, val):
|
||||
global pending_tests
|
||||
kstr = str(key)
|
||||
if kstr in pending_tests:
|
||||
if pending_tests[kstr]['v'].id == val.id:
|
||||
pending_tests.pop(kstr, None)
|
||||
else:
|
||||
print("Expected vid", val.id, "got", pending_tests[kstr]['v'].id)
|
||||
return True
|
||||
|
||||
def listen(key):
|
||||
node1.listen(key, lambda v: loop.call_soon_threadsafe(listen_cb, key, v))
|
||||
|
||||
for key in keys:
|
||||
listen(key)
|
||||
|
||||
next_test = time.time()
|
||||
while True:
|
||||
start = time.time()
|
||||
#print(datetime.fromtimestamp(start).strftime('%Y-%m-%d %H:%M:%S'), 'Test started')
|
||||
for key in keys:
|
||||
val = dht.Value(str(dht.InfoHash.getRandom()).encode())
|
||||
pending_tests[str(key)] = {'v':val, 'c':0}
|
||||
node2.put(key, val, lambda ok, nodes: ok)
|
||||
while len(pending_tests):
|
||||
loop.stop()
|
||||
loop.run_forever()
|
||||
time.sleep(1)
|
||||
if time.time()-start > args.timeout:
|
||||
print('Test timeout !')
|
||||
exit(1)
|
||||
|
||||
end = time.time()
|
||||
print(datetime.fromtimestamp(end).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'Test completed successfully in', end-start)
|
||||
next_test += args.period
|
||||
if next_test > end:
|
||||
time.sleep(next_test-end)
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import opendht as dht
|
||||
import time
|
||||
import asyncio
|
||||
|
||||
ping_node = dht.DhtRunner()
|
||||
ping_node.run(port = 5632)
|
||||
#ping_node.enableLogging()
|
||||
#ping_node.bootstrap("bootstrap.ring.cx", "4222")
|
||||
|
||||
pong_node = dht.DhtRunner()
|
||||
pong_node.run(port = 5633)
|
||||
#pong_node.enableLogging()
|
||||
pong_node.bootstrap("192.168.49.55", "5632");
|
||||
#pong_node.bootstrap("192.168.49.55", "5632");
|
||||
|
||||
loc_ping = dht.InfoHash.get("toto99")
|
||||
loc_pong = dht.InfoHash.get(str(loc_ping))
|
||||
|
||||
i = 0
|
||||
MAX = 8192
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
def done(h, ok):
|
||||
print(h, "over", ok)
|
||||
|
||||
def ping(node, h):
|
||||
global i
|
||||
time.sleep(0.0075)
|
||||
i += 1
|
||||
if i < MAX:
|
||||
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
|
||||
else:
|
||||
loop.stop()
|
||||
|
||||
def pong(node, h):
|
||||
print(node.getNodeId().decode(), "got ping", h, i)
|
||||
loop.call_soon_threadsafe(ping, node, h);
|
||||
return True
|
||||
|
||||
ping_node.listen(loc_ping, lambda v: pong(pong_node, loc_pong))
|
||||
pong_node.listen(loc_pong, lambda v: pong(ping_node, loc_ping))
|
||||
|
||||
ping(pong_node, loc_ping)
|
||||
|
||||
loop.run_forever()
|
||||
@@ -18,7 +18,7 @@
|
||||
import time, sys, os
|
||||
from pprint import pprint
|
||||
from math import cos, sin, pi
|
||||
from urllib import request
|
||||
import urllib3
|
||||
import gzip
|
||||
import asyncio
|
||||
|
||||
@@ -35,6 +35,8 @@ from mpl_toolkits.basemap import Basemap
|
||||
|
||||
import GeoIP
|
||||
|
||||
http = urllib3.PoolManager()
|
||||
|
||||
done = 0
|
||||
all_nodes = NodeSet()
|
||||
|
||||
@@ -72,7 +74,7 @@ def check_dl(fname, url):
|
||||
if os.path.isfile(fname):
|
||||
return
|
||||
print('downloading', url)
|
||||
ghandle = gzip.GzipFile(fileobj=request.urlopen(url))
|
||||
ghandle = gzip.GzipFile(fileobj=http.request('GET', url, headers={'User-Agent': 'Mozilla/5.0'}, preload_content=False))
|
||||
with open(fname, 'wb') as out:
|
||||
for line in ghandle:
|
||||
out.write(line)
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg3492"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
xml:space="preserve"
|
||||
width="256"
|
||||
height="256"
|
||||
viewBox="0 0 256 255.99999"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"><title
|
||||
id="title3357">OpenDHT</title><metadata
|
||||
id="metadata3498"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title>OpenDHT</dc:title><dc:rights><cc:Agent><dc:title></dc:title></cc:Agent></dc:rights><dc:creator><cc:Agent><dc:title>Savoir-faire Linux Inc.</dc:title></cc:Agent></dc:creator><dc:relation>https://opendht.net</dc:relation></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs3496"><clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath3534"><path
|
||||
d="m 0,0 1152,0 0,648 L 0,648 0,0 Z"
|
||||
id="path3536"
|
||||
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
id="namedview3494"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
fit-margin-top="5"
|
||||
fit-margin-right="5"
|
||||
fit-margin-bottom="5"
|
||||
fit-margin-left="5"
|
||||
inkscape:zoom="1.9555556"
|
||||
inkscape:cx="63.161953"
|
||||
inkscape:cy="141.16919"
|
||||
inkscape:window-x="1985"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g3532" /><g
|
||||
id="g3500"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="SFL-logo-DHT"
|
||||
transform="matrix(1.25,0,0,-1.25,-589.00821,604.10631)"><g
|
||||
id="g3530"><g
|
||||
id="g3532"
|
||||
clip-path="url(#clipPath3534)"><g
|
||||
id="g3359"
|
||||
transform="matrix(0.9931555,0,0,0.99058777,1.5489503,0.9813209)"><g
|
||||
transform="translate(485.3798,383.7826)"
|
||||
id="g3538"><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3540"
|
||||
style="fill:#47b3d1;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0,50.03 40.554,90.586 90.586,90.586 50.028,0 90.587,-40.556 90.587,-90.586 0,-50.03 -40.559,-90.588 -90.587,-90.588 C 40.554,-90.588 0,-50.03 0,0" /></g><g
|
||||
transform="translate(576.0338,313.2273)"
|
||||
id="g3542"><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3544"
|
||||
style="fill:#0091ba;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0,54.307 -24.009,102.977 -61.954,136.075 -17.613,-16.526 -28.632,-39.996 -28.632,-66.056 0,-49.629 39.916,-89.912 89.393,-90.555 0.396,-0.009 0.792,-0.033 1.193,-0.033 L 0,-0.082 0,0 Z" /></g><g
|
||||
transform="translate(575.9661,292.6626)"
|
||||
id="g3546"><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3548"
|
||||
style="fill:#007aa3;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -1.439,49.482 -41.105,89.355 -90.504,91.12 0,-0.178 -0.015,-0.355 -0.015,-0.536 C -90.519,40.578 -49.998,0.039 0,0" /></g><g
|
||||
transform="translate(532.4411,337.497)"
|
||||
id="g3550"><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3552"
|
||||
style="fill:#006382;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -10.555,0 -20.236,-3.754 -27.777,-10 16.565,-21.182 42.472,-34.815 71.442,-34.834 0.01,0.415 -0.072,0.821 -0.072,1.241 C 43.593,-19.516 24.077,0 0,0" /></g><g
|
||||
transform="translate(576.0338,313.2273)"
|
||||
id="g3554"><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3556"
|
||||
style="fill:#0091ba;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 C 0,54.307 24.014,102.977 61.954,136.075 79.567,119.549 90.586,96.079 90.586,70.019 90.586,20.39 50.675,-19.893 1.198,-20.536 0.797,-20.545 0.406,-20.569 0.005,-20.569 l 0,20.487 C 0.005,-0.053 0,-0.029 0,0" /></g><g
|
||||
transform="translate(576.1063,292.6626)"
|
||||
id="g3558"><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3560"
|
||||
style="fill:#007aa3;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 1.44,49.482 41.105,89.355 90.504,91.12 0,-0.178 0.01,-0.355 0.01,-0.536 C 90.514,40.578 49.998,0.039 0,0" /></g><g
|
||||
transform="translate(619.6266,337.497)"
|
||||
id="g3562"><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3564"
|
||||
style="fill:#006382;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 10.56,0 20.241,-3.754 27.782,-10 -16.57,-21.182 -42.405,-34.815 -71.375,-34.834 -0.009,0.415 0,0.821 0,1.241 C -43.593,-19.516 -24.072,0 0,0" /></g></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
+15
-4
@@ -4,7 +4,7 @@ lib_LTLIBRARIES = libopendht.la
|
||||
|
||||
AM_CPPFLAGS = -I../include/opendht
|
||||
libopendht_la_CXXFLAGS = @CXXFLAGS@
|
||||
libopendht_la_LDFLAGS = @LDFLAGS@ @GNUTLS_LIBS@ @nettle_LIBS@
|
||||
libopendht_la_LDFLAGS = @LDFLAGS@ @GnuTLS_LIBS@ @Nettle_LIBS@
|
||||
libopendht_la_LIBADD = ./argon2/libargon2.la
|
||||
|
||||
libopendht_la_SOURCES = \
|
||||
@@ -20,7 +20,9 @@ libopendht_la_SOURCES = \
|
||||
crypto.cpp \
|
||||
securedht.cpp \
|
||||
dhtrunner.cpp \
|
||||
default_types.cpp
|
||||
default_types.cpp \
|
||||
indexation/pht.cpp \
|
||||
log.cpp
|
||||
|
||||
if WIN32
|
||||
libopendht_la_SOURCES += rng.cpp
|
||||
@@ -28,13 +30,17 @@ endif
|
||||
|
||||
nobase_include_HEADERS = \
|
||||
../include/opendht.h \
|
||||
../include/opendht/def.h \
|
||||
../include/opendht/dht.h \
|
||||
../include/opendht/callbacks.h \
|
||||
../include/opendht/node_cache.h \
|
||||
../include/opendht/routing_table.h \
|
||||
../include/opendht/routing_table.h \
|
||||
../include/opendht/network_engine.h \
|
||||
../include/opendht/net.h \
|
||||
../include/opendht/scheduler.h \
|
||||
../include/opendht/rate_limiter.h \
|
||||
../include/opendht/utils.h \
|
||||
../include/opendht/sockaddr.h \
|
||||
../include/opendht/infohash.h \
|
||||
../include/opendht/node.h \
|
||||
../include/opendht/value.h \
|
||||
@@ -43,4 +49,9 @@ nobase_include_HEADERS = \
|
||||
../include/opendht/dhtrunner.h \
|
||||
../include/opendht/default_types.h \
|
||||
../include/opendht/log.h \
|
||||
../include/opendht/rng.h
|
||||
../include/opendht/log_enable.h \
|
||||
../include/opendht/rng.h \
|
||||
../include/opendht/indexation/pht.h
|
||||
|
||||
nobase_noinst_HEADERS = \
|
||||
../include/opendht/request.h
|
||||
+11
-1
@@ -10,4 +10,14 @@ libargon2_la_SOURCES = \
|
||||
encoding.c \
|
||||
ref.c
|
||||
|
||||
EXTRA_libargon2_la_SOURCES = opt.c
|
||||
noinst_HEADERS = \
|
||||
argon2.h \
|
||||
core.h \
|
||||
blake2/blake2.h \
|
||||
blake2/blake2-impl.h \
|
||||
blake2/blamka-round-ref.h \
|
||||
blake2/blamka-round-opt.h \
|
||||
thread.h \
|
||||
encoding.h \
|
||||
opt.h \
|
||||
ref.h
|
||||
+73
-22
@@ -1,14 +1,18 @@
|
||||
/*
|
||||
* Argon2 source code package
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with
|
||||
* this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@@ -19,6 +23,18 @@
|
||||
#include "encoding.h"
|
||||
#include "core.h"
|
||||
|
||||
const char *argon2_type2string(argon2_type type, int uppercase) {
|
||||
switch (type) {
|
||||
case Argon2_d:
|
||||
return uppercase ? "Argon2d" : "argon2d";
|
||||
case Argon2_i:
|
||||
return uppercase ? "Argon2i" : "argon2i";
|
||||
case Argon2_id:
|
||||
return uppercase ? "Argon2id" : "argon2id";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int argon2_ctx(argon2_context *context, argon2_type type) {
|
||||
/* 1. Validate all inputs */
|
||||
@@ -30,7 +46,7 @@ int argon2_ctx(argon2_context *context, argon2_type type) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (Argon2_d != type && Argon2_i != type) {
|
||||
if (Argon2_d != type && Argon2_i != type && Argon2_id != type) {
|
||||
return ARGON2_INCORRECT_TYPE;
|
||||
}
|
||||
|
||||
@@ -81,25 +97,19 @@ int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
|
||||
const uint32_t parallelism, const void *pwd,
|
||||
const size_t pwdlen, const void *salt, const size_t saltlen,
|
||||
void *hash, const size_t hashlen, char *encoded,
|
||||
const size_t encodedlen, argon2_type type,
|
||||
const size_t encodedlen, argon2_type type,
|
||||
const uint32_t version){
|
||||
|
||||
argon2_context context;
|
||||
int result;
|
||||
uint8_t *out;
|
||||
|
||||
/* Detect and reject overflowing sizes */
|
||||
/* TODO: This should probably be fixed in the function signature */
|
||||
if (pwdlen > ARGON2_MAX_PWD_LENGTH) {
|
||||
return ARGON2_PWD_TOO_LONG;
|
||||
}
|
||||
|
||||
if (hashlen > ARGON2_MAX_OUTLEN) {
|
||||
return ARGON2_OUTPUT_TOO_LONG;
|
||||
}
|
||||
|
||||
if (saltlen > ARGON2_MAX_SALT_LENGTH) {
|
||||
return ARGON2_SALT_TOO_LONG;
|
||||
if (hashlen < ARGON2_MIN_OUTLEN) {
|
||||
return ARGON2_OUTPUT_TOO_SHORT;
|
||||
}
|
||||
|
||||
out = malloc(hashlen);
|
||||
@@ -194,6 +204,26 @@ int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
|
||||
hash, hashlen, NULL, 0, Argon2_d, ARGON2_VERSION_NUMBER);
|
||||
}
|
||||
|
||||
int argon2id_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
|
||||
const uint32_t parallelism, const void *pwd,
|
||||
const size_t pwdlen, const void *salt,
|
||||
const size_t saltlen, const size_t hashlen,
|
||||
char *encoded, const size_t encodedlen) {
|
||||
|
||||
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
|
||||
NULL, hashlen, encoded, encodedlen, Argon2_id,
|
||||
ARGON2_VERSION_NUMBER);
|
||||
}
|
||||
|
||||
int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
|
||||
const uint32_t parallelism, const void *pwd,
|
||||
const size_t pwdlen, const void *salt,
|
||||
const size_t saltlen, void *hash, const size_t hashlen) {
|
||||
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
|
||||
hash, hashlen, NULL, 0, Argon2_id,
|
||||
ARGON2_VERSION_NUMBER);
|
||||
}
|
||||
|
||||
static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) {
|
||||
size_t i;
|
||||
uint8_t d = 0U;
|
||||
@@ -212,13 +242,19 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
|
||||
int ret;
|
||||
int decode_result;
|
||||
uint32_t encoded_len;
|
||||
size_t encoded_len_tmp;
|
||||
|
||||
if(encoded == NULL) {
|
||||
return ARGON2_DECODING_FAIL;
|
||||
}
|
||||
|
||||
encoded_len_tmp = strlen(encoded);
|
||||
/* max values, to be updated in decode_string */
|
||||
encoded_len = strlen(encoded);
|
||||
if (UINT32_MAX < encoded_len_tmp) {
|
||||
return ARGON2_DECODING_FAIL;
|
||||
}
|
||||
|
||||
encoded_len = (uint32_t)encoded_len_tmp;
|
||||
ctx.adlen = encoded_len;
|
||||
ctx.saltlen = encoded_len;
|
||||
ctx.outlen = encoded_len;
|
||||
@@ -226,6 +262,8 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
|
||||
ctx.free_cbk = NULL;
|
||||
ctx.secret = NULL;
|
||||
ctx.secretlen = 0;
|
||||
ctx.pwdlen = 0;
|
||||
ctx.pwd = NULL;
|
||||
ctx.ad = malloc(ctx.adlen);
|
||||
ctx.salt = malloc(ctx.saltlen);
|
||||
ctx.out = malloc(ctx.outlen);
|
||||
@@ -277,6 +315,11 @@ int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) {
|
||||
return argon2_verify(encoded, pwd, pwdlen, Argon2_d);
|
||||
}
|
||||
|
||||
int argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) {
|
||||
|
||||
return argon2_verify(encoded, pwd, pwdlen, Argon2_id);
|
||||
}
|
||||
|
||||
int argon2d_ctx(argon2_context *context) {
|
||||
return argon2_ctx(context, Argon2_d);
|
||||
}
|
||||
@@ -285,6 +328,10 @@ int argon2i_ctx(argon2_context *context) {
|
||||
return argon2_ctx(context, Argon2_i);
|
||||
}
|
||||
|
||||
int argon2id_ctx(argon2_context *context) {
|
||||
return argon2_ctx(context, Argon2_id);
|
||||
}
|
||||
|
||||
int argon2_verify_ctx(argon2_context *context, const char *hash,
|
||||
argon2_type type) {
|
||||
int result;
|
||||
@@ -309,6 +356,10 @@ int argon2i_verify_ctx(argon2_context *context, const char *hash) {
|
||||
return argon2_verify_ctx(context, hash, Argon2_i);
|
||||
}
|
||||
|
||||
int argon2id_verify_ctx(argon2_context *context, const char *hash) {
|
||||
return argon2_verify_ctx(context, hash, Argon2_id);
|
||||
}
|
||||
|
||||
const char *argon2_error_message(int error_code) {
|
||||
switch (error_code) {
|
||||
case ARGON2_OK:
|
||||
@@ -389,8 +440,8 @@ const char *argon2_error_message(int error_code) {
|
||||
}
|
||||
|
||||
size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism,
|
||||
uint32_t saltlen, uint32_t hashlen) {
|
||||
return strlen("$argon2x$v=$m=,t=,p=$$") + numlen(t_cost) + numlen(m_cost)
|
||||
+ numlen(parallelism) + b64len(saltlen) + b64len(hashlen)
|
||||
+ numlen(ARGON2_VERSION_NUMBER);
|
||||
uint32_t saltlen, uint32_t hashlen, argon2_type type) {
|
||||
return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) +
|
||||
numlen(t_cost) + numlen(m_cost) + numlen(parallelism) +
|
||||
b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + 1;
|
||||
}
|
||||
+66
-8
@@ -1,13 +1,18 @@
|
||||
/*
|
||||
* Argon2 source code package
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef ARGON2_H
|
||||
@@ -24,6 +29,8 @@ extern "C" {
|
||||
/* Symbols visibility control */
|
||||
#ifdef A2_VISCTL
|
||||
#define ARGON2_PUBLIC __attribute__((visibility("default")))
|
||||
#elif _MSC_VER
|
||||
#define ARGON2_PUBLIC __declspec(dllexport)
|
||||
#else
|
||||
#define ARGON2_PUBLIC
|
||||
#endif
|
||||
@@ -204,7 +211,11 @@ typedef struct Argon2_Context {
|
||||
} argon2_context;
|
||||
|
||||
/* Argon2 primitive type */
|
||||
typedef enum Argon2_type { Argon2_d = 0, Argon2_i = 1 } argon2_type;
|
||||
typedef enum Argon2_type {
|
||||
Argon2_d = 0,
|
||||
Argon2_i = 1,
|
||||
Argon2_id = 2
|
||||
} argon2_type;
|
||||
|
||||
/* Version of the algorithm */
|
||||
typedef enum Argon2_version {
|
||||
@@ -213,6 +224,14 @@ typedef enum Argon2_version {
|
||||
ARGON2_VERSION_NUMBER = ARGON2_VERSION_13
|
||||
} argon2_version;
|
||||
|
||||
/*
|
||||
* Function that gives the string representation of an argon2_type.
|
||||
* @param type The argon2_type that we want the string for
|
||||
* @param uppercase Whether the string should have the first letter uppercase
|
||||
* @return NULL if invalid type, otherwise the string representation.
|
||||
*/
|
||||
ARGON2_PUBLIC const char *argon2_type2string(argon2_type type, int uppercase);
|
||||
|
||||
/*
|
||||
* Function that performs memory-hard hashing with certain degree of parallelism
|
||||
* @param context Pointer to the Argon2 internal structure
|
||||
@@ -278,6 +297,21 @@ ARGON2_PUBLIC int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
|
||||
const size_t saltlen, void *hash,
|
||||
const size_t hashlen);
|
||||
|
||||
ARGON2_PUBLIC int argon2id_hash_encoded(const uint32_t t_cost,
|
||||
const uint32_t m_cost,
|
||||
const uint32_t parallelism,
|
||||
const void *pwd, const size_t pwdlen,
|
||||
const void *salt, const size_t saltlen,
|
||||
const size_t hashlen, char *encoded,
|
||||
const size_t encodedlen);
|
||||
|
||||
ARGON2_PUBLIC int argon2id_hash_raw(const uint32_t t_cost,
|
||||
const uint32_t m_cost,
|
||||
const uint32_t parallelism, const void *pwd,
|
||||
const size_t pwdlen, const void *salt,
|
||||
const size_t saltlen, void *hash,
|
||||
const size_t hashlen);
|
||||
|
||||
/* generic function underlying the above ones */
|
||||
ARGON2_PUBLIC int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
|
||||
const uint32_t parallelism, const void *pwd,
|
||||
@@ -300,6 +334,9 @@ ARGON2_PUBLIC int argon2i_verify(const char *encoded, const void *pwd,
|
||||
ARGON2_PUBLIC int argon2d_verify(const char *encoded, const void *pwd,
|
||||
const size_t pwdlen);
|
||||
|
||||
ARGON2_PUBLIC int argon2id_verify(const char *encoded, const void *pwd,
|
||||
const size_t pwdlen);
|
||||
|
||||
/* generic function underlying the above ones */
|
||||
ARGON2_PUBLIC int argon2_verify(const char *encoded, const void *pwd,
|
||||
const size_t pwdlen, argon2_type type);
|
||||
@@ -324,6 +361,17 @@ ARGON2_PUBLIC int argon2d_ctx(argon2_context *context);
|
||||
*/
|
||||
ARGON2_PUBLIC int argon2i_ctx(argon2_context *context);
|
||||
|
||||
/**
|
||||
* Argon2id: Version of Argon2 where the first half-pass over memory is
|
||||
* password-independent, the rest are password-dependent (on the password and
|
||||
* salt). OK against side channels (they reduce to 1/2-pass Argon2i), and
|
||||
* better with w.r.t. tradeoff attacks (similar to Argon2d).
|
||||
*****
|
||||
* @param context Pointer to current Argon2 context
|
||||
* @return Zero if successful, a non zero error code otherwise
|
||||
*/
|
||||
ARGON2_PUBLIC int argon2id_ctx(argon2_context *context);
|
||||
|
||||
/**
|
||||
* Verify if a given password is correct for Argon2d hashing
|
||||
* @param context Pointer to current Argon2 context
|
||||
@@ -342,6 +390,16 @@ ARGON2_PUBLIC int argon2d_verify_ctx(argon2_context *context, const char *hash);
|
||||
*/
|
||||
ARGON2_PUBLIC int argon2i_verify_ctx(argon2_context *context, const char *hash);
|
||||
|
||||
/**
|
||||
* Verify if a given password is correct for Argon2id hashing
|
||||
* @param context Pointer to current Argon2 context
|
||||
* @param hash The password hash to verify. The length of the hash is
|
||||
* specified by the context outlen member
|
||||
* @return Zero if successful, a non zero error code otherwise
|
||||
*/
|
||||
ARGON2_PUBLIC int argon2id_verify_ctx(argon2_context *context,
|
||||
const char *hash);
|
||||
|
||||
/* generic function underlying the above ones */
|
||||
ARGON2_PUBLIC int argon2_verify_ctx(argon2_context *context, const char *hash,
|
||||
argon2_type type);
|
||||
@@ -363,7 +421,7 @@ ARGON2_PUBLIC const char *argon2_error_message(int error_code);
|
||||
*/
|
||||
ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost,
|
||||
uint32_t parallelism, uint32_t saltlen,
|
||||
uint32_t hashlen);
|
||||
uint32_t hashlen, argon2_type type);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef PORTABLE_BLAKE2_IMPL_H
|
||||
#define PORTABLE_BLAKE2_IMPL_H
|
||||
|
||||
@@ -134,10 +151,6 @@ static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) {
|
||||
return (w >> c) | (w << (64 - c));
|
||||
}
|
||||
|
||||
/* prevents compiler optimizing out memset() */
|
||||
static BLAKE2_INLINE void burn(void *v, size_t n) {
|
||||
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
|
||||
memset_v(v, 0, n);
|
||||
}
|
||||
void secure_wipe_memory(void *v, size_t n);
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef PORTABLE_BLAKE2_H
|
||||
#define PORTABLE_BLAKE2_H
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@@ -44,7 +61,7 @@ static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S,
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) {
|
||||
burn(S, sizeof(*S)); /* wipe */
|
||||
secure_wipe_memory(S, sizeof(*S)); /* wipe */
|
||||
blake2b_set_lastblock(S); /* invalidate for further use */
|
||||
}
|
||||
|
||||
@@ -140,7 +157,7 @@ int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
|
||||
memset(block, 0, BLAKE2B_BLOCKBYTES);
|
||||
memcpy(block, key, keylen);
|
||||
blake2b_update(S, block, BLAKE2B_BLOCKBYTES);
|
||||
burn(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */
|
||||
secure_wipe_memory(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -267,9 +284,9 @@ int blake2b_final(blake2b_state *S, void *out, size_t outlen) {
|
||||
}
|
||||
|
||||
memcpy(out, buffer, S->outlen);
|
||||
burn(buffer, sizeof(buffer));
|
||||
burn(S->buf, sizeof(S->buf));
|
||||
burn(S->h, sizeof(S->h));
|
||||
secure_wipe_memory(buffer, sizeof(buffer));
|
||||
secure_wipe_memory(S->buf, sizeof(S->buf));
|
||||
secure_wipe_memory(S->h, sizeof(S->h));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -307,7 +324,7 @@ int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
|
||||
ret = blake2b_final(&S, out, outlen);
|
||||
|
||||
fail:
|
||||
burn(&S, sizeof(S));
|
||||
secure_wipe_memory(&S, sizeof(S));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -365,7 +382,7 @@ int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) {
|
||||
memcpy(out, out_buffer, toproduce);
|
||||
}
|
||||
fail:
|
||||
burn(&blake_state, sizeof(blake_state));
|
||||
secure_wipe_memory(&blake_state, sizeof(blake_state));
|
||||
return ret;
|
||||
#undef TRY
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef BLAKE_ROUND_MKA_OPT_H
|
||||
#define BLAKE_ROUND_MKA_OPT_H
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef BLAKE_ROUND_MKA_H
|
||||
#define BLAKE_ROUND_MKA_H
|
||||
|
||||
|
||||
+31
-28
@@ -1,14 +1,18 @@
|
||||
/*
|
||||
* Argon2 source code package
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with
|
||||
* this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
/*For memory wiping*/
|
||||
@@ -252,26 +256,28 @@ int fill_memory_blocks(argon2_instance_t *instance) {
|
||||
uint32_t r, s;
|
||||
argon2_thread_handle_t *thread = NULL;
|
||||
argon2_thread_data *thr_data = NULL;
|
||||
int rc = ARGON2_OK;
|
||||
|
||||
if (instance == NULL || instance->lanes == 0) {
|
||||
return ARGON2_THREAD_FAIL;
|
||||
rc = ARGON2_THREAD_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 1. Allocating space for threads */
|
||||
thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t));
|
||||
if (thread == NULL) {
|
||||
return ARGON2_MEMORY_ALLOCATION_ERROR;
|
||||
rc = ARGON2_MEMORY_ALLOCATION_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
thr_data = calloc(instance->lanes, sizeof(argon2_thread_data));
|
||||
if (thr_data == NULL) {
|
||||
free(thread);
|
||||
return ARGON2_MEMORY_ALLOCATION_ERROR;
|
||||
rc = ARGON2_MEMORY_ALLOCATION_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (r = 0; r < instance->passes; ++r) {
|
||||
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
|
||||
int rc;
|
||||
uint32_t l;
|
||||
|
||||
/* 2. Calling threads */
|
||||
@@ -280,11 +286,9 @@ int fill_memory_blocks(argon2_instance_t *instance) {
|
||||
|
||||
/* 2.1 Join a thread if limit is exceeded */
|
||||
if (l >= instance->threads) {
|
||||
rc = argon2_thread_join(thread[l - instance->threads]);
|
||||
if (rc) {
|
||||
free(thr_data);
|
||||
free(thread);
|
||||
return ARGON2_THREAD_FAIL;
|
||||
if (argon2_thread_join(thread[l - instance->threads])) {
|
||||
rc = ARGON2_THREAD_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,12 +301,10 @@ int fill_memory_blocks(argon2_instance_t *instance) {
|
||||
instance; /* preparing the thread input */
|
||||
memcpy(&(thr_data[l].pos), &position,
|
||||
sizeof(argon2_position_t));
|
||||
rc = argon2_thread_create(&thread[l], &fill_segment_thr,
|
||||
(void *)&thr_data[l]);
|
||||
if (rc) {
|
||||
free(thr_data);
|
||||
free(thread);
|
||||
return ARGON2_THREAD_FAIL;
|
||||
if (argon2_thread_create(&thread[l], &fill_segment_thr,
|
||||
(void *)&thr_data[l])) {
|
||||
rc = ARGON2_THREAD_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* fill_segment(instance, position); */
|
||||
@@ -312,9 +314,9 @@ int fill_memory_blocks(argon2_instance_t *instance) {
|
||||
/* 3. Joining remaining threads */
|
||||
for (l = instance->lanes - instance->threads; l < instance->lanes;
|
||||
++l) {
|
||||
rc = argon2_thread_join(thread[l]);
|
||||
if (rc) {
|
||||
return ARGON2_THREAD_FAIL;
|
||||
if (argon2_thread_join(thread[l])) {
|
||||
rc = ARGON2_THREAD_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,13 +326,14 @@ int fill_memory_blocks(argon2_instance_t *instance) {
|
||||
#endif
|
||||
}
|
||||
|
||||
fail:
|
||||
if (thread != NULL) {
|
||||
free(thread);
|
||||
}
|
||||
if (thr_data != NULL) {
|
||||
free(thr_data);
|
||||
}
|
||||
return ARGON2_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int validate_inputs(const argon2_context *context) {
|
||||
@@ -575,7 +578,7 @@ int initialize(argon2_instance_t *instance, argon2_context *context) {
|
||||
if (ARGON2_OK != result) {
|
||||
return result;
|
||||
}
|
||||
memcpy(&(instance->memory), p, sizeof(instance->memory));
|
||||
instance->memory = (block *)p;
|
||||
} else {
|
||||
result = allocate_memory(&(instance->memory), instance->memory_blocks);
|
||||
if (ARGON2_OK != result) {
|
||||
|
||||
+11
-7
@@ -1,14 +1,18 @@
|
||||
/*
|
||||
* Argon2 source code package
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with
|
||||
* this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef ARGON2_CORE_H
|
||||
|
||||
+48
-12
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -291,21 +308,26 @@ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
|
||||
size_t maxsaltlen = ctx->saltlen;
|
||||
size_t maxoutlen = ctx->outlen;
|
||||
int validation_result;
|
||||
const char* type_string;
|
||||
|
||||
ctx->adlen = 0;
|
||||
ctx->saltlen = 0;
|
||||
ctx->outlen = 0;
|
||||
ctx->pwdlen = 0;
|
||||
|
||||
if (type == Argon2_i)
|
||||
CC("$argon2i");
|
||||
else if (type == Argon2_d)
|
||||
CC("$argon2d");
|
||||
else
|
||||
/* We should start with the argon2_type we are using */
|
||||
CC("$");
|
||||
type_string = argon2_type2string(type, 0);
|
||||
if (type_string) {
|
||||
CC(type_string);
|
||||
} else {
|
||||
return ARGON2_INCORRECT_TYPE;
|
||||
ctx->version = ARGON2_VERSION_10;
|
||||
}
|
||||
|
||||
/* Reading the version number if the default is suppressed */
|
||||
ctx->version = ARGON2_VERSION_10;
|
||||
CC_opt("$v=", DECIMAL(ctx->version));
|
||||
|
||||
CC("$m=");
|
||||
DECIMAL(ctx->m_cost);
|
||||
CC(",t=");
|
||||
@@ -370,16 +392,19 @@ int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
|
||||
dst_len -= sb_len; \
|
||||
} while ((void)0, 0)
|
||||
|
||||
if (type == Argon2_i)
|
||||
SS("$argon2i$v=");
|
||||
else if (type == Argon2_d)
|
||||
SS("$argon2d$v=");
|
||||
else
|
||||
const char* type_string = argon2_type2string(type, 0);
|
||||
SS("$");
|
||||
if (type_string) {
|
||||
SS(type_string);
|
||||
} else {
|
||||
return ARGON2_ENCODING_FAIL;
|
||||
}
|
||||
|
||||
if (validate_inputs(ctx) != ARGON2_OK) {
|
||||
return validate_inputs(ctx);
|
||||
}
|
||||
|
||||
SS("$v=");
|
||||
SX(ctx->version);
|
||||
SS("$m=");
|
||||
SX(ctx->m_cost);
|
||||
@@ -412,7 +437,18 @@ int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
|
||||
}
|
||||
|
||||
size_t b64len(uint32_t len) {
|
||||
return (((size_t)len + 2) / 3) * 4;
|
||||
size_t olen = ((size_t)len / 3) << 2;
|
||||
|
||||
switch (len % 3) {
|
||||
case 2:
|
||||
olen++;
|
||||
/* fall through */
|
||||
case 1:
|
||||
olen += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return olen;
|
||||
}
|
||||
|
||||
size_t numlen(uint32_t num) {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef ENCODING_H
|
||||
#define ENCODING_H
|
||||
#include "argon2.h"
|
||||
|
||||
+15
-8
@@ -1,14 +1,18 @@
|
||||
/*
|
||||
* Argon2 source code package
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with
|
||||
* this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -135,7 +139,10 @@ void fill_segment(const argon2_instance_t *instance,
|
||||
return;
|
||||
}
|
||||
|
||||
data_independent_addressing = (instance->type == Argon2_i);
|
||||
data_independent_addressing =
|
||||
(instance->type == Argon2_i) ||
|
||||
(instance->type == Argon2_id && (position.pass == 0) &&
|
||||
(position.slice < ARGON2_SYNC_POINTS / 2));
|
||||
|
||||
pseudo_rands =
|
||||
(uint64_t *)malloc(sizeof(uint64_t) * instance->segment_length);
|
||||
|
||||
+11
-7
@@ -1,14 +1,18 @@
|
||||
/*
|
||||
* Argon2 source code package
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with
|
||||
* this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef ARGON2_OPT_H
|
||||
|
||||
+15
-8
@@ -1,14 +1,18 @@
|
||||
/*
|
||||
* Argon2 source code package
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with
|
||||
* this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -145,7 +149,10 @@ void fill_segment(const argon2_instance_t *instance,
|
||||
return;
|
||||
}
|
||||
|
||||
data_independent_addressing = (instance->type == Argon2_i);
|
||||
data_independent_addressing =
|
||||
(instance->type == Argon2_i) ||
|
||||
(instance->type == Argon2_id && (position.pass == 0) &&
|
||||
(position.slice < ARGON2_SYNC_POINTS / 2));
|
||||
|
||||
pseudo_rands =
|
||||
(uint64_t *)malloc(sizeof(uint64_t) * (instance->segment_length));
|
||||
|
||||
+11
-7
@@ -1,14 +1,18 @@
|
||||
/*
|
||||
* Argon2 source code package
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication along
|
||||
* with
|
||||
* this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef ARGON2_REF_H
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#include "thread.h"
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef ARGON2_THREAD_H
|
||||
#define ARGON2_THREAD_H
|
||||
/*
|
||||
|
||||
+22
-1
@@ -47,4 +47,25 @@ bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
DoneCallbackSimple
|
||||
bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) {
|
||||
if (not raw_cb) return {};
|
||||
return [=](bool success) {
|
||||
raw_cb(success, user_data);
|
||||
};
|
||||
}
|
||||
|
||||
std::string
|
||||
NodeStats::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Known nodes: " << good_nodes << " good, " << dubious_nodes << " dubious, " << incoming_nodes << " incoming." << std::endl;
|
||||
if (table_depth > 1) {
|
||||
ss << "Routing table depth: " << table_depth << std::endl;
|
||||
unsigned long tot_nodes = 8 * std::exp2(table_depth);
|
||||
ss << "Network size estimation: " << tot_nodes << " nodes" << std::endl;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}
|
||||
+355
-48
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -35,7 +35,11 @@ extern "C" {
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
|
||||
#else
|
||||
static std::uniform_int_distribution<uint8_t> rand_byte;
|
||||
#endif
|
||||
|
||||
static gnutls_digest_algorithm_t get_dig_for_pub(gnutls_pubkey_t pubkey)
|
||||
{
|
||||
@@ -79,6 +83,18 @@ namespace crypto {
|
||||
static constexpr std::array<size_t, 3> AES_LENGTHS {{128/8, 192/8, 256/8}};
|
||||
static constexpr size_t PASSWORD_SALT_LENGTH {16};
|
||||
|
||||
constexpr gnutls_digest_algorithm_t gnutlsHashAlgo(size_t min_res) {
|
||||
return (min_res > 256/8) ? GNUTLS_DIG_SHA512 : (
|
||||
(min_res > 128/8) ? GNUTLS_DIG_SHA256 : (
|
||||
GNUTLS_DIG_SHA1));
|
||||
}
|
||||
|
||||
constexpr size_t gnutlsHashSize(int algo) {
|
||||
return (algo == GNUTLS_DIG_SHA512) ? 512/8 : (
|
||||
(algo == GNUTLS_DIG_SHA256) ? 256/8 : (
|
||||
(algo == GNUTLS_DIG_SHA1) ? 160/8 : 0 ));
|
||||
}
|
||||
|
||||
size_t aesKeySize(size_t max)
|
||||
{
|
||||
size_t aes_key_len = 0;
|
||||
@@ -124,8 +140,7 @@ Blob aesEncrypt(const Blob& data, const Blob& key)
|
||||
Blob aesEncrypt(const Blob& data, const std::string& password)
|
||||
{
|
||||
Blob salt;
|
||||
Blob key = stretchKey(password, salt);
|
||||
key.resize(256 / 8);
|
||||
Blob key = stretchKey(password, salt, 256 / 8);
|
||||
Blob encrypted = aesEncrypt(data, key);
|
||||
encrypted.insert(encrypted.begin(), salt.begin(), salt.end());
|
||||
return encrypted;
|
||||
@@ -171,13 +186,12 @@ Blob aesDecrypt(const Blob& data, const std::string& password)
|
||||
if (data.size() <= PASSWORD_SALT_LENGTH)
|
||||
throw DecryptError("Wrong data size");
|
||||
Blob salt {data.begin(), data.begin()+PASSWORD_SALT_LENGTH};
|
||||
Blob key = stretchKey(password, salt);
|
||||
key.resize(256 / 8);
|
||||
Blob key = stretchKey(password, salt, 256/8);
|
||||
Blob encrypted {data.begin()+PASSWORD_SALT_LENGTH, data.end()};
|
||||
return aesDecrypt(encrypted, key);
|
||||
}
|
||||
|
||||
Blob stretchKey(const std::string& password, Blob& salt)
|
||||
Blob stretchKey(const std::string& password, Blob& salt, size_t key_length)
|
||||
{
|
||||
if (salt.empty()) {
|
||||
salt.resize(PASSWORD_SALT_LENGTH);
|
||||
@@ -189,35 +203,27 @@ Blob stretchKey(const std::string& password, Blob& salt)
|
||||
auto ret = argon2i_hash_raw(16, 64*1024, 1, password.data(), password.size(), salt.data(), salt.size(), res.data(), res.size());
|
||||
if (ret != ARGON2_OK)
|
||||
throw CryptoException("Can't compute argon2i !");
|
||||
return hash(res);
|
||||
return hash(res, key_length);
|
||||
}
|
||||
|
||||
Blob hash(const Blob& data)
|
||||
Blob hash(const Blob& data, size_t hash_len)
|
||||
{
|
||||
auto algo = gnutlsHashAlgo(hash_len);
|
||||
size_t res_size = gnutlsHashSize(algo);
|
||||
Blob res;
|
||||
size_t res_size = 64;
|
||||
res.resize(res_size);
|
||||
const gnutls_datum_t gdat {(uint8_t*)data.data(), (unsigned)data.size()};
|
||||
if (gnutls_fingerprint(GNUTLS_DIG_SHA512, &gdat, res.data(), &res_size))
|
||||
if (gnutls_fingerprint(algo, &gdat, res.data(), &res_size))
|
||||
throw CryptoException("Can't compute hash !");
|
||||
res.resize(res_size);
|
||||
res.resize(std::min(hash_len, res_size));
|
||||
return res;
|
||||
}
|
||||
|
||||
PrivateKey::PrivateKey()
|
||||
{
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030300
|
||||
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException("Can't initialize GnuTLS.");
|
||||
#endif
|
||||
}
|
||||
{}
|
||||
|
||||
PrivateKey::PrivateKey(gnutls_x509_privkey_t k) : x509_key(k)
|
||||
{
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030300
|
||||
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException("Can't initialize GnuTLS.");
|
||||
#endif
|
||||
gnutls_privkey_init(&key);
|
||||
if (gnutls_privkey_import_x509(key, k, GNUTLS_PRIVKEY_IMPORT_COPY) != GNUTLS_E_SUCCESS) {
|
||||
key = nullptr;
|
||||
@@ -227,10 +233,6 @@ PrivateKey::PrivateKey(gnutls_x509_privkey_t k) : x509_key(k)
|
||||
|
||||
PrivateKey::PrivateKey(const Blob& import, const std::string& password)
|
||||
{
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030300
|
||||
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException("Can't initialize GnuTLS.");
|
||||
#endif
|
||||
int err = gnutls_x509_privkey_init(&x509_key);
|
||||
if (err != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException("Can't initialize private key !");
|
||||
@@ -262,14 +264,9 @@ PrivateKey::PrivateKey(const Blob& import, const std::string& password)
|
||||
|
||||
PrivateKey::PrivateKey(PrivateKey&& o) noexcept : key(o.key), x509_key(o.x509_key)
|
||||
{
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030300
|
||||
// gnutls_global_init already succeeded at least once here so no real need to check.
|
||||
int ret = gnutls_global_init();
|
||||
assert(ret == GNUTLS_E_SUCCESS);
|
||||
#endif
|
||||
o.key = nullptr;
|
||||
o.x509_key = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
PrivateKey::~PrivateKey()
|
||||
{
|
||||
@@ -281,9 +278,6 @@ PrivateKey::~PrivateKey()
|
||||
gnutls_x509_privkey_deinit(x509_key);
|
||||
x509_key = nullptr;
|
||||
}
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030300
|
||||
gnutls_global_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
PrivateKey&
|
||||
@@ -307,6 +301,8 @@ PrivateKey::sign(const Blob& data) const
|
||||
{
|
||||
if (!key)
|
||||
throw CryptoException("Can't sign data: no private key set !");
|
||||
if (std::numeric_limits<unsigned>::max() < data.size())
|
||||
throw CryptoException("Can't sign data: too large !");
|
||||
gnutls_datum_t sig;
|
||||
const gnutls_datum_t dat {(unsigned char*)data.data(), (unsigned)data.size()};
|
||||
if (gnutls_privkey_sign_data(key, GNUTLS_DIG_SHA512, 0, &dat, &sig) != GNUTLS_E_SUCCESS)
|
||||
@@ -521,6 +517,16 @@ PublicKey::getId() const
|
||||
return id;
|
||||
}
|
||||
|
||||
PkId
|
||||
PublicKey::getLongId() const
|
||||
{
|
||||
PkId h;
|
||||
size_t sz = h.size();
|
||||
if (gnutls_pubkey_get_key_id(pk, GNUTLS_KEYID_USE_SHA256, h.data(), &sz) != GNUTLS_E_SUCCESS || sz != h.size())
|
||||
return {};
|
||||
return h;
|
||||
}
|
||||
|
||||
Certificate::Certificate(const Blob& certData) : cert(nullptr)
|
||||
{
|
||||
unpack(certData.data(), certData.size());
|
||||
@@ -625,6 +631,18 @@ Certificate::getId() const
|
||||
return id;
|
||||
}
|
||||
|
||||
PkId
|
||||
Certificate::getLongId() const
|
||||
{
|
||||
if (not cert)
|
||||
return {};
|
||||
PkId id;
|
||||
size_t sz = id.size();
|
||||
if (gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, id.data(), &sz) != GNUTLS_E_SUCCESS || sz != id.size())
|
||||
throw CryptoException("Can't get certificate public key ID.");
|
||||
return id;
|
||||
}
|
||||
|
||||
static std::string
|
||||
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
|
||||
{
|
||||
@@ -704,7 +722,20 @@ bool
|
||||
Certificate::isCA() const
|
||||
{
|
||||
unsigned critical;
|
||||
return gnutls_x509_crt_get_ca_status(cert, &critical) > 0;
|
||||
bool ca_flag = gnutls_x509_crt_get_ca_status(cert, &critical) > 0;
|
||||
if (ca_flag) {
|
||||
unsigned usage;
|
||||
auto ret = gnutls_x509_crt_get_key_usage(cert, &usage, &critical);
|
||||
/* Conforming CAs MUST include this extension in certificates that
|
||||
contain public keys that are used to validate digital signatures on
|
||||
other public key certificates or CRLs. */
|
||||
if (ret < 0)
|
||||
return false;
|
||||
if (not critical)
|
||||
return true;
|
||||
return usage & GNUTLS_KEY_KEY_CERT_SIGN;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -729,13 +760,54 @@ Certificate::toString(bool chain) const
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
Certificate::print() const
|
||||
{
|
||||
gnutls_datum_t out;
|
||||
gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &out);
|
||||
std::string ret(out.data, out.data+out.size);
|
||||
gnutls_free(out.data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
Certificate::revoke(const PrivateKey& key, const Certificate& to_revoke)
|
||||
{
|
||||
if (revocation_lists.empty())
|
||||
revocation_lists.emplace(std::make_shared<RevocationList>());
|
||||
auto& list = *(*revocation_lists.begin());
|
||||
list.revoke(to_revoke);
|
||||
list.sign(key, *this);
|
||||
}
|
||||
|
||||
void
|
||||
Certificate::addRevocationList(RevocationList&& list)
|
||||
{
|
||||
addRevocationList(std::make_shared<RevocationList>(std::forward<RevocationList>(list)));
|
||||
}
|
||||
|
||||
void
|
||||
Certificate::addRevocationList(std::shared_ptr<RevocationList> list)
|
||||
{
|
||||
if (revocation_lists.find(list) != revocation_lists.end())
|
||||
return; // Already in the list
|
||||
if (not list->isSignedBy(*this))
|
||||
throw CryptoException("CRL is not signed by this certificate");
|
||||
revocation_lists.emplace(std::move(list));
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point
|
||||
Certificate::getExpiration() const
|
||||
{
|
||||
auto t = gnutls_x509_crt_get_expiration_time(cert);
|
||||
if (t == (time_t)-1)
|
||||
return std::chrono::system_clock::time_point::min();
|
||||
return std::chrono::system_clock::from_time_t(t);
|
||||
}
|
||||
|
||||
PrivateKey
|
||||
PrivateKey::generate(unsigned key_length)
|
||||
{
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030300
|
||||
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException("Can't initialize GnuTLS.");
|
||||
#endif
|
||||
gnutls_x509_privkey_t key;
|
||||
if (gnutls_x509_privkey_init(&key) != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException("Can't initialize private key.");
|
||||
@@ -747,20 +819,25 @@ PrivateKey::generate(unsigned key_length)
|
||||
return PrivateKey{key};
|
||||
}
|
||||
|
||||
PrivateKey
|
||||
PrivateKey::generateEC()
|
||||
{
|
||||
gnutls_x509_privkey_t key;
|
||||
if (gnutls_x509_privkey_init(&key) != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException("Can't initialize private key.");
|
||||
int err = gnutls_x509_privkey_generate(key, GNUTLS_PK_EC, gnutls_sec_param_to_pk_bits(GNUTLS_PK_EC, GNUTLS_SEC_PARAM_ULTRA), 0);
|
||||
if (err != GNUTLS_E_SUCCESS) {
|
||||
gnutls_x509_privkey_deinit(key);
|
||||
throw CryptoException(std::string("Can't generate EC key pair: ") + gnutls_strerror(err));
|
||||
}
|
||||
return PrivateKey{key};
|
||||
}
|
||||
|
||||
Identity
|
||||
generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_length, bool is_ca)
|
||||
{
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030300
|
||||
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
|
||||
return {};
|
||||
#endif
|
||||
auto key = std::make_shared<PrivateKey>(PrivateKey::generate(key_length));
|
||||
|
||||
auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030300
|
||||
gnutls_global_deinit();
|
||||
#endif
|
||||
return {std::move(key), std::move(cert)};
|
||||
}
|
||||
|
||||
@@ -812,6 +889,10 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
|
||||
gnutls_x509_crt_set_key_usage(cert, key_usage);
|
||||
|
||||
if (ca.first && ca.second) {
|
||||
if (not ca.second->isCA()) {
|
||||
// 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) {
|
||||
std::cerr << "Error when signing certificate" << std::endl;
|
||||
@@ -829,5 +910,231 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<RevocationList>>
|
||||
Certificate::getRevocationLists() const
|
||||
{
|
||||
std::vector<std::shared_ptr<RevocationList>> ret;
|
||||
ret.reserve(revocation_lists.size());
|
||||
for (const auto& crl : revocation_lists)
|
||||
ret.emplace_back(crl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
RevocationList::RevocationList()
|
||||
{
|
||||
gnutls_x509_crl_init(&crl);
|
||||
}
|
||||
|
||||
RevocationList::RevocationList(const Blob& b)
|
||||
{
|
||||
gnutls_x509_crl_init(&crl);
|
||||
try {
|
||||
unpack(b.data(), b.size());
|
||||
} catch (const std::exception& e) {
|
||||
gnutls_x509_crl_deinit(crl);
|
||||
crl = nullptr;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
RevocationList::~RevocationList()
|
||||
{
|
||||
if (crl) {
|
||||
gnutls_x509_crl_deinit(crl);
|
||||
crl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RevocationList::pack(Blob& b) const
|
||||
{
|
||||
gnutls_datum_t gdat {nullptr, 0};
|
||||
if (auto err = gnutls_x509_crl_export2(crl, GNUTLS_X509_FMT_DER, &gdat)) {
|
||||
throw CryptoException(std::string("Can't export CRL: ") + gnutls_strerror(err));
|
||||
}
|
||||
b.insert(b.end(), gdat.data, gdat.data + gdat.size);
|
||||
}
|
||||
|
||||
void
|
||||
RevocationList::unpack(const uint8_t* dat, size_t dat_size)
|
||||
{
|
||||
if (std::numeric_limits<unsigned>::max() < dat_size)
|
||||
throw CryptoException("Can't load CRL: too large!");
|
||||
const gnutls_datum_t gdat {(uint8_t*)dat, (unsigned)dat_size};
|
||||
if (auto err_pem = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_PEM))
|
||||
if (auto err_der = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_DER)) {
|
||||
throw CryptoException(std::string("Can't load CRL: PEM: ") + gnutls_strerror(err_pem)
|
||||
+ " DER: " + gnutls_strerror(err_der));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RevocationList::msgpack_unpack(msgpack::object o)
|
||||
{
|
||||
try {
|
||||
if (o.type == msgpack::type::BIN)
|
||||
unpack((const uint8_t*)o.via.bin.ptr, o.via.bin.size);
|
||||
else {
|
||||
Blob dat = unpackBlob(o);
|
||||
unpack(dat.data(), dat.size());
|
||||
}
|
||||
} catch (...) {
|
||||
throw msgpack::type_error();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RevocationList::isRevoked(const Certificate& crt) const
|
||||
{
|
||||
auto ret = gnutls_x509_crt_check_revocation(crt.cert, &crl, 1);
|
||||
if (ret < 0)
|
||||
throw CryptoException(std::string("Can't check certificate revocation status: ") + gnutls_strerror(ret));
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
void
|
||||
RevocationList::revoke(const Certificate& crt, std::chrono::system_clock::time_point t)
|
||||
{
|
||||
if (t == time_point::min())
|
||||
t = clock::now();
|
||||
if (auto err = gnutls_x509_crl_set_crt(crl, crt.cert, std::chrono::system_clock::to_time_t(t)))
|
||||
throw CryptoException(std::string("Can't revoke certificate: ") + gnutls_strerror(err));
|
||||
}
|
||||
|
||||
static std::string
|
||||
getCRLIssuerDN(gnutls_x509_crl_t cert, const char* oid)
|
||||
{
|
||||
std::string dn;
|
||||
dn.resize(512);
|
||||
size_t dn_sz = dn.size();
|
||||
int ret = gnutls_x509_crl_get_issuer_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
|
||||
RevocationList::getIssuerName() const
|
||||
{
|
||||
return getCRLIssuerDN(crl, GNUTLS_OID_X520_COMMON_NAME);
|
||||
}
|
||||
|
||||
/** Read CRL issuer User ID (UID) */
|
||||
std::string
|
||||
RevocationList::getIssuerUID() const
|
||||
{
|
||||
return getCRLIssuerDN(crl, GNUTLS_OID_LDAP_UID);
|
||||
}
|
||||
|
||||
RevocationList::time_point
|
||||
RevocationList::getNextUpdateTime() const
|
||||
{
|
||||
auto t = gnutls_x509_crl_get_next_update(crl);
|
||||
if (t == (time_t)-1)
|
||||
return std::chrono::system_clock::time_point::min();
|
||||
return std::chrono::system_clock::from_time_t(t);
|
||||
}
|
||||
|
||||
RevocationList::time_point
|
||||
RevocationList::getUpdateTime() const
|
||||
{
|
||||
auto t = gnutls_x509_crl_get_this_update(crl);
|
||||
if (t == (time_t)-1)
|
||||
return std::chrono::system_clock::time_point::min();
|
||||
return std::chrono::system_clock::from_time_t(t);
|
||||
}
|
||||
|
||||
enum class Endian : uint32_t
|
||||
{
|
||||
LITTLE = 0,
|
||||
BIG = 1
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T endian(T w, Endian endian = Endian::BIG)
|
||||
{
|
||||
// this gets optimized out into if (endian == host_endian) return w;
|
||||
union { uint64_t quad; uint32_t islittle; } t;
|
||||
t.quad = 1;
|
||||
if (t.islittle ^ (uint32_t)endian) return w;
|
||||
T r = 0;
|
||||
|
||||
// decent compilers will unroll this (gcc)
|
||||
// or even convert straight into single bswap (clang)
|
||||
for (size_t i = 0; i < sizeof(r); i++) {
|
||||
r <<= 8;
|
||||
r |= w & 0xff;
|
||||
w >>= 8;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
RevocationList::sign(const PrivateKey& key, const Certificate& ca, duration validity)
|
||||
{
|
||||
if (auto err = gnutls_x509_crl_set_version(crl, 2))
|
||||
throw CryptoException(std::string("Can't set CRL version: ") + gnutls_strerror(err));
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto next_update = (validity == duration{}) ? ca.getExpiration() : now + validity;
|
||||
if (auto err = gnutls_x509_crl_set_this_update(crl, std::chrono::system_clock::to_time_t(now)))
|
||||
throw CryptoException(std::string("Can't set CRL update time: ") + gnutls_strerror(err));
|
||||
if (auto err = gnutls_x509_crl_set_next_update(crl, std::chrono::system_clock::to_time_t(next_update)))
|
||||
throw CryptoException(std::string("Can't set CRL next update time: ") + gnutls_strerror(err));
|
||||
uint64_t number {0};
|
||||
size_t number_sz {sizeof(number)};
|
||||
unsigned critical {0};
|
||||
gnutls_x509_crl_get_number(crl, &number, &number_sz, &critical);
|
||||
if (number == 0) {
|
||||
// initialize to a random number
|
||||
number_sz = sizeof(number);
|
||||
random_device rdev;
|
||||
std::generate_n((uint8_t*)&number, sizeof(number), std::bind(rand_byte, std::ref(rdev)));
|
||||
} else
|
||||
number = endian(endian(number) + 1);
|
||||
if (auto err = gnutls_x509_crl_set_number(crl, &number, sizeof(number)))
|
||||
throw CryptoException(std::string("Can't set CRL update time: ") + gnutls_strerror(err));
|
||||
if (auto err = gnutls_x509_crl_sign2(crl, ca.cert, key.x509_key, GNUTLS_DIG_SHA512, 0))
|
||||
throw CryptoException(std::string("Can't sign certificate revocation list: ") + gnutls_strerror(err));
|
||||
// to be able to actually use the CRL we need to serialize/deserialize it
|
||||
auto packed = getPacked();
|
||||
unpack(packed.data(), packed.size());
|
||||
}
|
||||
|
||||
bool
|
||||
RevocationList::isSignedBy(const Certificate& issuer) const
|
||||
{
|
||||
unsigned result {0};
|
||||
auto err = gnutls_x509_crl_verify(crl, &issuer.cert, 1, 0, &result);
|
||||
if (err < 0) {
|
||||
//std::cout << "Can't verify CRL: " << err << " " << result << " " << gnutls_strerror(err) << std::endl;
|
||||
return false;
|
||||
}
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
|
||||
Blob
|
||||
RevocationList::getNumber() const
|
||||
{
|
||||
Blob number(20);
|
||||
size_t number_sz {number.size()};
|
||||
unsigned critical {0};
|
||||
gnutls_x509_crl_get_number(crl, number.data(), &number_sz, &critical);
|
||||
if (number_sz != number.size())
|
||||
number.resize(number_sz);
|
||||
return number;
|
||||
}
|
||||
|
||||
std::string
|
||||
RevocationList::toString() const
|
||||
{
|
||||
gnutls_datum_t out;
|
||||
gnutls_x509_crl_print(crl, GNUTLS_CRT_PRINT_FULL, &out);
|
||||
std::string ret(out.data, out.data+out.size);
|
||||
gnutls_free(out.data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -83,8 +83,8 @@ IpServiceAnnouncement::storePolicy(InfoHash h, std::shared_ptr<Value>& v, InfoHa
|
||||
return false;
|
||||
}
|
||||
|
||||
const ValueType DhtMessage::TYPE = {1, "DHT message", std::chrono::minutes(5), DhtMessage::storePolicy, ValueType::DEFAULT_EDIT_POLICY};
|
||||
const ValueType IpServiceAnnouncement::TYPE = {2, "Internet Service Announcement", std::chrono::minutes(15), IpServiceAnnouncement::storePolicy, ValueType::DEFAULT_EDIT_POLICY};
|
||||
const ValueType DhtMessage::TYPE(1, "DHT message", std::chrono::minutes(5), DhtMessage::storePolicy);
|
||||
const ValueType IpServiceAnnouncement::TYPE(2, "Internet Service Announcement", std::chrono::minutes(15), IpServiceAnnouncement::storePolicy);
|
||||
const ValueType ImMessage::TYPE = {3, "IM message", std::chrono::minutes(5)};
|
||||
const ValueType TrustRequest::TYPE = {4, "Certificate trust request", std::chrono::hours(24*7)};
|
||||
const ValueType IceCandidates::TYPE = {5, "ICE candidates", std::chrono::minutes(5)};
|
||||
|
||||
+1859
-978
File diff suppressed because it is too large.
Load diff
+250
-95
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,7 +21,11 @@
|
||||
#include "dhtrunner.h"
|
||||
#include "securedht.h"
|
||||
|
||||
#include <unistd.h> // close(fd)
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
@@ -33,6 +37,8 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD;
|
||||
|
||||
DhtRunner::DhtRunner() : dht_()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -100,7 +106,8 @@ DhtRunner::run(const sockaddr_in* local4, const sockaddr_in6* local6, DhtRunner:
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
if (not pending_ops_prio.empty())
|
||||
return true;
|
||||
if (not pending_ops.empty() and getStatus() >= NodeStatus::Connecting)
|
||||
auto s = getStatus();
|
||||
if (not pending_ops.empty() and (s == NodeStatus::Connected or (s == NodeStatus::Disconnected and not bootstraping)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -123,10 +130,14 @@ DhtRunner::join()
|
||||
{
|
||||
running = false;
|
||||
cv.notify_all();
|
||||
bootstrap_cv.notify_all();
|
||||
if (dht_thread.joinable())
|
||||
dht_thread.join();
|
||||
if (rcv_thread.joinable())
|
||||
rcv_thread.join();
|
||||
if (bootstrap_thread.joinable())
|
||||
bootstrap_thread.join();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops = decltype(pending_ops)();
|
||||
@@ -199,11 +210,17 @@ DhtRunner::exportValues() const {
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setLoggers(LogMethod&& error, LogMethod&& warn, LogMethod&& debug) {
|
||||
DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
dht_->setLoggers(std::forward<LogMethod>(error), std::forward<LogMethod>(warn), std::forward<LogMethod>(debug));
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setLogFilter(const InfoHash& f) {
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
dht_->setLogFilter(f);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::registerType(const ValueType& type) {
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
@@ -216,11 +233,27 @@ DhtRunner::importValues(const std::vector<ValuesExport>& values) {
|
||||
dht_->importValues(values);
|
||||
}
|
||||
|
||||
int
|
||||
unsigned
|
||||
DhtRunner::getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
return dht_->getNodesStats(af, good_return, dubious_return, cached_return, incoming_return);
|
||||
const auto stats = dht_->getNodesStats(af);
|
||||
if (good_return)
|
||||
*good_return = stats.good_nodes;
|
||||
if (dubious_return)
|
||||
*dubious_return = stats.dubious_nodes;
|
||||
if (cached_return)
|
||||
*cached_return = stats.cached_nodes;
|
||||
if (incoming_return)
|
||||
*incoming_return = stats.incoming_nodes;
|
||||
return stats.good_nodes + stats.dubious_nodes;
|
||||
}
|
||||
|
||||
NodeStats
|
||||
DhtRunner::getNodesStats(sa_family_t af) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
return dht_->getNodesStats(af);
|
||||
}
|
||||
|
||||
std::vector<unsigned>
|
||||
@@ -237,6 +270,12 @@ DhtRunner::getStorageLog() const
|
||||
return dht_->getStorageLog();
|
||||
}
|
||||
std::string
|
||||
DhtRunner::getStorageLog(const InfoHash& f) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
return dht_->getStorageLog(f);
|
||||
}
|
||||
std::string
|
||||
DhtRunner::getRoutingTablesLog(sa_family_t af) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
@@ -248,7 +287,13 @@ DhtRunner::getSearchesLog(sa_family_t af) const
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
return dht_->getSearchesLog(af);
|
||||
}
|
||||
std::vector<Address>
|
||||
std::string
|
||||
DhtRunner::getSearchLog(const InfoHash& f, sa_family_t af) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
return dht_->getSearchLog(f, af);
|
||||
}
|
||||
std::vector<SockAddr>
|
||||
DhtRunner::getPublicAddress(sa_family_t af)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
@@ -283,22 +328,14 @@ DhtRunner::loop_()
|
||||
decltype(pending_ops) ops {};
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
ops = std::move(pending_ops_prio);
|
||||
auto s = getStatus();
|
||||
ops = (pending_ops_prio.empty() && (s == NodeStatus::Connected or (s == NodeStatus::Disconnected and not bootstraping))) ?
|
||||
std::move(pending_ops) : std::move(pending_ops_prio);
|
||||
}
|
||||
while (not ops.empty()) {
|
||||
ops.front()(*dht_);
|
||||
ops.pop();
|
||||
}
|
||||
if (getStatus() >= NodeStatus::Connecting) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
ops = std::move(pending_ops);
|
||||
}
|
||||
while (not ops.empty()) {
|
||||
ops.front()(*dht_);
|
||||
ops.pop();
|
||||
}
|
||||
}
|
||||
|
||||
time_point wakeup {};
|
||||
decltype(rcv) received {};
|
||||
@@ -311,7 +348,7 @@ DhtRunner::loop_()
|
||||
for (const auto& pck : received) {
|
||||
auto& buf = pck.first;
|
||||
auto& from = pck.second;
|
||||
wakeup = dht_->periodic(buf.data(), buf.size()-1, (sockaddr*)&from.first, from.second);
|
||||
wakeup = dht_->periodic(buf.data(), buf.size()-1, from);
|
||||
}
|
||||
received.clear();
|
||||
} else {
|
||||
@@ -323,6 +360,15 @@ DhtRunner::loop_()
|
||||
if (nstatus4 != status4 || nstatus6 != status6) {
|
||||
status4 = nstatus4;
|
||||
status6 = nstatus6;
|
||||
if (status4 == NodeStatus::Disconnected and status6 == NodeStatus::Disconnected) {
|
||||
// We have lost connection with the DHT. Try to recover using bootstrap nodes.
|
||||
std::unique_lock<std::mutex> lck(bootstrap_mtx);
|
||||
bootstrap_nodes = bootstrap_nodes_all;
|
||||
tryBootstrapContinuously();
|
||||
} else {
|
||||
std::unique_lock<std::mutex> lck(bootstrap_mtx);
|
||||
bootstrap_nodes.clear();
|
||||
}
|
||||
if (statusCb)
|
||||
statusCb(status4, status6);
|
||||
}
|
||||
@@ -374,7 +420,7 @@ DhtRunner::doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDht::C
|
||||
rcv_thread = std::thread([this,s4,s6]() {
|
||||
try {
|
||||
while (true) {
|
||||
struct timeval tv {.tv_sec = 0, .tv_usec = 250000};
|
||||
struct timeval tv {/*.tv_sec = */0, /*.tv_usec = */250000};
|
||||
fd_set readfds;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
@@ -396,19 +442,19 @@ DhtRunner::doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDht::C
|
||||
|
||||
if(rc > 0) {
|
||||
std::array<uint8_t, 1024 * 64> buf;
|
||||
sockaddr_storage from;
|
||||
socklen_t fromlen {sizeof(from)};
|
||||
SockAddr from;
|
||||
from.second = sizeof(from.first);
|
||||
|
||||
if(s4 >= 0 && FD_ISSET(s4, &readfds))
|
||||
rc = recvfrom(s4, (char*)buf.data(), buf.size(), 0, (struct sockaddr*)&from, &fromlen);
|
||||
rc = recvfrom(s4, (char*)buf.data(), buf.size(), 0, (struct sockaddr*)&from.first, &from.second);
|
||||
else if(s6 >= 0 && FD_ISSET(s6, &readfds))
|
||||
rc = recvfrom(s6, (char*)buf.data(), buf.size(), 0, (struct sockaddr*)&from, &fromlen);
|
||||
rc = recvfrom(s6, (char*)buf.data(), buf.size(), 0, (struct sockaddr*)&from.first, &from.second);
|
||||
else
|
||||
break;
|
||||
if (rc > 0) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(sock_mtx);
|
||||
rcv.emplace_back(Blob {buf.begin(), buf.begin()+rc+1}, std::make_pair(from, fromlen));
|
||||
rcv.emplace_back(Blob {buf.begin(), buf.begin()+rc+1}, from);
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
@@ -425,104 +471,129 @@ DhtRunner::doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDht::C
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f)
|
||||
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::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) mutable {
|
||||
dht.get(hash, vcb, dcb, std::move(f), std::move(w));
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, Value::Filter f)
|
||||
DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, Value::Filter f, Where w)
|
||||
{
|
||||
get(InfoHash::get(key), vcb, dcb, f);
|
||||
get(InfoHash::get(key), vcb, dcb, f, 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));
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
std::future<size_t>
|
||||
DhtRunner::listen(InfoHash hash, GetCallback vcb, Value::Filter f)
|
||||
DhtRunner::listen(InfoHash hash, GetCallback vcb, Value::Filter f, Where w)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
auto ret_token = std::make_shared<std::promise<size_t>>();
|
||||
pending_ops.emplace([=](SecureDht& dht) mutable {
|
||||
ret_token->set_value(dht.listen(hash, vcb, std::move(f)));
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) mutable {
|
||||
ret_token->set_value(dht.listen(hash, vcb, std::move(f), std::move(w)));
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
return ret_token->get_future();
|
||||
}
|
||||
|
||||
std::future<size_t>
|
||||
DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f)
|
||||
DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Where w)
|
||||
{
|
||||
return listen(InfoHash::get(key), vcb, f);
|
||||
return listen(InfoHash::get(key), vcb, f, w);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::cancelListen(InfoHash h, size_t token)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.cancelListen(h, token);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.cancelListen(h, token);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> token)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
auto tk = token.get();
|
||||
dht.cancelListen(h, tk);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
auto tk = token.get();
|
||||
dht.cancelListen(h, tk);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb)
|
||||
DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created, bool permanent)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
auto sv = std::make_shared<Value>(std::move(value));
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.put(hash, sv, cb);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
auto sv = std::make_shared<Value>(std::move(value));
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.put(hash, sv, cb, created, permanent);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb)
|
||||
DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, time_point created, bool permanent)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.put(hash, value, cb);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.put(hash, value, cb, created, permanent);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb)
|
||||
DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, time_point created, bool permanent)
|
||||
{
|
||||
put(InfoHash::get(key), std::forward<Value>(value), cb);
|
||||
put(InfoHash::get(key), std::forward<Value>(value), cb, created, permanent);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::cancelPut(const InfoHash& h , const Value::Id& id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.cancelPut(h, id);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.cancelPut(h, id);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.putSigned(hash, value, cb);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.putSigned(hash, value, cb);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -541,10 +612,12 @@ DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple c
|
||||
void
|
||||
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.putEncrypted(hash, to, value, cb);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.putEncrypted(hash, to, value, cb);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -560,18 +633,77 @@ DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, Done
|
||||
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), cb);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::tryBootstrapContinuously()
|
||||
{
|
||||
if (bootstrap_thread.joinable()) {
|
||||
if (bootstraping)
|
||||
return; // already running
|
||||
else
|
||||
bootstrap_thread.join();
|
||||
}
|
||||
bootstraping = true;
|
||||
bootstrap_thread = std::thread([this]() {
|
||||
auto next = clock::now();
|
||||
do {
|
||||
decltype(bootstrap_nodes) nodes;
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(bootstrap_mtx);
|
||||
nodes = bootstrap_nodes;
|
||||
}
|
||||
|
||||
next += BOOTSTRAP_PERIOD;
|
||||
{
|
||||
std::mutex mtx;
|
||||
std::unique_lock<std::mutex> blck(mtx);
|
||||
unsigned ping_count(0);
|
||||
// Reverse: try last inserted bootstrap nodes first
|
||||
for (auto it = nodes.rbegin(); it != nodes.rend(); it++) {
|
||||
++ping_count;
|
||||
try {
|
||||
bootstrap(getAddrInfo(it->first, it->second), [&](bool) {
|
||||
if (not running)
|
||||
return;
|
||||
{
|
||||
std::unique_lock<std::mutex> blck(mtx);
|
||||
--ping_count;
|
||||
}
|
||||
bootstrap_cv.notify_all();
|
||||
});
|
||||
} catch (std::invalid_argument& e) {
|
||||
--ping_count;
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
// wait at least until the next BOOTSTRAP_PERIOD
|
||||
bootstrap_cv.wait_until(blck, next, [&]() { return not running; });
|
||||
// wait for bootstrap requests to end.
|
||||
if (running)
|
||||
bootstrap_cv.wait(blck, [&]() { return not running or ping_count == 0; });
|
||||
}
|
||||
// update state
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
bootstraping = running and
|
||||
status4 == NodeStatus::Disconnected and
|
||||
status6 == NodeStatus::Disconnected;
|
||||
}
|
||||
} while (bootstraping);
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<std::pair<sockaddr_storage, socklen_t>>
|
||||
DhtRunner::getAddrInfo(const char* host, const char* service)
|
||||
DhtRunner::getAddrInfo(const std::string& host, const std::string& service)
|
||||
{
|
||||
std::vector<std::pair<sockaddr_storage, socklen_t>> ips {};
|
||||
if (not host or not service or strlen(host) == 0)
|
||||
if (host.empty())
|
||||
return ips;
|
||||
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
addrinfo* info = nullptr;
|
||||
int rc = getaddrinfo(host, service, &hints, &info);
|
||||
int rc = getaddrinfo(host.c_str(), service.c_str(), &hints, &info);
|
||||
if(rc != 0)
|
||||
throw std::invalid_argument(std::string("Error: `") + host + ":" + service + "`: " + gai_strerror(rc));
|
||||
|
||||
@@ -586,18 +718,35 @@ DhtRunner::getAddrInfo(const char* host, const char* service)
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::bootstrap(const char* host, const char* service)
|
||||
DhtRunner::bootstrap(const std::string& host, const std::string& service)
|
||||
{
|
||||
bootstrap(getAddrInfo(host, service));
|
||||
std::lock_guard<std::mutex> lck(bootstrap_mtx);
|
||||
bootstrap_nodes_all.emplace_back(host, service);
|
||||
bootstrap_nodes.emplace_back(host, service);
|
||||
tryBootstrapContinuously();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes)
|
||||
DhtRunner::clearBootstrap()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(bootstrap_mtx);
|
||||
bootstrap_nodes_all.clear();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes, DoneCallbackSimple&& cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([=](SecureDht& dht) {
|
||||
pending_ops_prio.emplace([=](SecureDht& dht) mutable {
|
||||
auto rem = cb ? std::make_shared<std::pair<size_t, bool>>(nodes.size(), false) : nullptr;
|
||||
for (auto& node : nodes)
|
||||
dht.pingNode((sockaddr*)&node.first, node.second);
|
||||
dht.pingNode((sockaddr*)&node.first, node.second, cb ? [rem,cb](bool ok) {
|
||||
auto& r = *rem;
|
||||
r.first--;
|
||||
r.second |= ok;
|
||||
if (not r.first)
|
||||
cb(r.second);
|
||||
} : DoneCallbackSimple{});
|
||||
});
|
||||
cv.notify_all();
|
||||
}
|
||||
@@ -605,30 +754,36 @@ DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>&
|
||||
void
|
||||
DhtRunner::bootstrap(const std::vector<NodeExport>& nodes)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([=](SecureDht& dht) {
|
||||
for (auto& node : nodes)
|
||||
dht.insertNode(node);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([=](SecureDht& dht) {
|
||||
for (auto& node : nodes)
|
||||
dht.insertNode(node);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::connectivityChanged()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.connectivityChanged();
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.connectivityChanged();
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>)> cb) {
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.findCertificate(hash, cb);
|
||||
});
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.findCertificate(hash, cb);
|
||||
});
|
||||
}
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,538 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "indexation/pht.h"
|
||||
#include "rng.h"
|
||||
|
||||
namespace dht {
|
||||
namespace indexation {
|
||||
|
||||
/**
|
||||
* Output the blob into string and readable way
|
||||
*
|
||||
* @param bl : Blob to print
|
||||
*
|
||||
* @return string that represent the blob into a readable way
|
||||
*/
|
||||
static std::string blobToString(const Blob &bl) {
|
||||
std::stringstream ss;
|
||||
auto bn = bl.size() % 8;
|
||||
auto n = bl.size() / 8;
|
||||
|
||||
for (size_t i = 0; i < bl.size(); i++)
|
||||
ss << std::bitset<8>(bl[i]) << " ";
|
||||
if (bn)
|
||||
for (unsigned b=0; b < bn; b++)
|
||||
ss << (char)((bl[n] & (1 << (7 - b))) ? '1':'0');
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string Prefix::toString() const {
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "Prefix : " << std::endl << "\tContent_ : \"";
|
||||
ss << blobToString(content_);
|
||||
ss << "\"" << std::endl;
|
||||
|
||||
ss << "\tFlags_ : \"";
|
||||
ss << blobToString(flags_);
|
||||
ss << "\"" << std::endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void Pht::Cache::insert(const Prefix& p) {
|
||||
size_t i = 0;
|
||||
auto now = clock::now();
|
||||
|
||||
std::shared_ptr<Node> curr_node;
|
||||
|
||||
while ((leaves_.size() > 0
|
||||
and leaves_.begin()->first + NODE_EXPIRE_TIME < now)
|
||||
or leaves_.size() > MAX_ELEMENT) {
|
||||
|
||||
leaves_.erase(leaves_.begin());
|
||||
}
|
||||
|
||||
if (not (curr_node = root_.lock()) ) {
|
||||
/* Root does not exist, need to create one*/
|
||||
curr_node = std::make_shared<Node>();
|
||||
root_ = curr_node;
|
||||
}
|
||||
|
||||
curr_node->last_reply = now;
|
||||
|
||||
/* Iterate through all bit of the Blob */
|
||||
for ( i = 0; i < p.size_; i++ ) {
|
||||
|
||||
/* According to the bit define which node is the next one */
|
||||
auto& next = ( p.isContentBitActive(i) ) ? curr_node->right_child : curr_node->left_child;
|
||||
|
||||
/**
|
||||
* If lock, node exists
|
||||
* else create it
|
||||
*/
|
||||
if (auto n = next.lock()) {
|
||||
curr_node = std::move(n);
|
||||
} else {
|
||||
/* Create the next node if doesn't exist*/
|
||||
auto tmp_curr_node = std::make_shared<Node>();
|
||||
tmp_curr_node->parent = curr_node;
|
||||
next = tmp_curr_node;
|
||||
curr_node = std::move(tmp_curr_node);
|
||||
}
|
||||
|
||||
curr_node->last_reply = now;
|
||||
}
|
||||
|
||||
/* Insert the leaf (curr_node) into the multimap */
|
||||
leaves_.emplace(std::move(now), std::move(curr_node) );
|
||||
}
|
||||
|
||||
int Pht::Cache::lookup(const Prefix& p) {
|
||||
int pos = -1;
|
||||
auto now = clock::now(), last_node_time = now;
|
||||
|
||||
/* Before lookup remove the useless one [i.e. too old] */
|
||||
while ( leaves_.size() > 0
|
||||
and leaves_.begin()->first + NODE_EXPIRE_TIME < now ) {
|
||||
|
||||
leaves_.erase(leaves_.begin());
|
||||
}
|
||||
|
||||
auto next = root_;
|
||||
std::shared_ptr<Node> curr_node;
|
||||
|
||||
while ( auto n = next.lock() ) {
|
||||
++pos;
|
||||
/* Safe since pos is equal to 0 until here */
|
||||
if ( (unsigned) pos >= p.content_.size() * 8) break;
|
||||
|
||||
curr_node = n;
|
||||
last_node_time = curr_node->last_reply;
|
||||
curr_node->last_reply = now;
|
||||
|
||||
/* Get the Prefix bit by bit, starting from left */
|
||||
next = ( p.isContentBitActive(pos) ) ? curr_node->right_child : curr_node->left_child;
|
||||
}
|
||||
|
||||
if ( pos >= 0 ) {
|
||||
auto to_erase = leaves_.find(last_node_time);
|
||||
if ( to_erase != leaves_.end() )
|
||||
leaves_.erase( to_erase );
|
||||
|
||||
leaves_.emplace( std::move(now), std::move(curr_node) );
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
const ValueType IndexEntry::TYPE = ValueType::USER_DATA;
|
||||
constexpr std::chrono::minutes Pht::Cache::NODE_EXPIRE_TIME;
|
||||
|
||||
void Pht::lookupStep(Prefix p, std::shared_ptr<int> lo, std::shared_ptr<int> hi,
|
||||
std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals,
|
||||
LookupCallbackWrapper cb, DoneCallbackSimple done_cb,
|
||||
std::shared_ptr<unsigned> max_common_prefix_len,
|
||||
int start, bool all_values)
|
||||
{
|
||||
struct node_lookup_result {
|
||||
bool done {false};
|
||||
bool is_pht {false};
|
||||
};
|
||||
|
||||
/* start could be under 0 but after the compare it to 0 it always will be unsigned, so we can cast it*/
|
||||
auto mid = (start >= 0) ? (unsigned) start : (*lo + *hi)/2;
|
||||
|
||||
auto first_res = std::make_shared<node_lookup_result>();
|
||||
auto second_res = std::make_shared<node_lookup_result>();
|
||||
|
||||
auto on_done = [=](bool ok) {
|
||||
bool is_leaf = first_res->is_pht and not second_res->is_pht;
|
||||
if (not ok) {
|
||||
if (done_cb)
|
||||
done_cb(false);
|
||||
}
|
||||
else if (is_leaf or *lo > *hi) {
|
||||
// leaf node
|
||||
Prefix to_insert = p.getPrefix(mid);
|
||||
cache_.insert(to_insert);
|
||||
|
||||
if (cb) {
|
||||
if (vals->size() == 0 and max_common_prefix_len and mid > 0) {
|
||||
auto p_ = (p.getPrefix(mid)).getSibling().getFullSize();
|
||||
*lo = mid;
|
||||
*hi = p_.size_;
|
||||
lookupStep(p_, lo, hi, vals, cb, done_cb, max_common_prefix_len, -1, all_values);
|
||||
}
|
||||
|
||||
cb(*vals, to_insert);
|
||||
}
|
||||
|
||||
if (done_cb)
|
||||
done_cb(true);
|
||||
} else if (first_res->is_pht) {
|
||||
// internal node
|
||||
*lo = mid+1;
|
||||
lookupStep(p, lo, hi, vals, cb, done_cb, max_common_prefix_len, -1, all_values);
|
||||
} else {
|
||||
// first get failed before second.
|
||||
if (done_cb)
|
||||
done_cb(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (*lo <= *hi) {
|
||||
auto pht_filter = [&](const dht::Value& v) {
|
||||
return v.user_type.compare(0, name_.size(), name_) == 0;
|
||||
};
|
||||
|
||||
auto on_get = [=](const std::shared_ptr<dht::Value>& value, std::shared_ptr<node_lookup_result> res) {
|
||||
if (value->user_type == canary_) {
|
||||
res->is_pht = true;
|
||||
}
|
||||
else {
|
||||
IndexEntry entry;
|
||||
entry.unpackValue(*value);
|
||||
|
||||
auto it = std::find_if(vals->cbegin(), vals->cend(), [&](const std::shared_ptr<IndexEntry>& ie) {
|
||||
return ie->value == entry.value;
|
||||
});
|
||||
|
||||
/* If we already got the value then get the next one */
|
||||
if (it != vals->cend())
|
||||
return true;
|
||||
|
||||
if (max_common_prefix_len) { /* inexact match case */
|
||||
auto common_bits = Prefix::commonBits(p, entry.prefix);
|
||||
|
||||
if (vals->empty()) {
|
||||
vals->emplace_back(std::make_shared<IndexEntry>(entry));
|
||||
*max_common_prefix_len = common_bits;
|
||||
}
|
||||
else {
|
||||
if (common_bits == *max_common_prefix_len) /* this is the max so far */
|
||||
vals->emplace_back(std::make_shared<IndexEntry>(entry));
|
||||
else if (common_bits > *max_common_prefix_len) { /* new max found! */
|
||||
vals->clear();
|
||||
vals->emplace_back(std::make_shared<IndexEntry>(entry));
|
||||
*max_common_prefix_len = common_bits;
|
||||
}
|
||||
}
|
||||
} else if (all_values or entry.prefix == p.content_) /* exact match case */
|
||||
vals->emplace_back(std::make_shared<IndexEntry>(entry));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
dht_->get(p.getPrefix(mid).hash(),
|
||||
std::bind(on_get, std::placeholders::_1, first_res),
|
||||
[=](bool ok) {
|
||||
if (not ok) {
|
||||
// DHT failed
|
||||
first_res->done = true;
|
||||
if (done_cb and second_res->done)
|
||||
on_done(false);
|
||||
}
|
||||
else {
|
||||
if (not first_res->is_pht) {
|
||||
// Not a PHT node.
|
||||
*hi = mid-1;
|
||||
lookupStep(p, lo, hi, vals, cb, done_cb, max_common_prefix_len, -1, all_values);
|
||||
} else {
|
||||
first_res->done = true;
|
||||
if (second_res->done or mid >= p.size_ - 1)
|
||||
on_done(true);
|
||||
}
|
||||
}
|
||||
}, pht_filter);
|
||||
|
||||
if (mid < p.size_ - 1)
|
||||
dht_->get(p.getPrefix(mid+1).hash(),
|
||||
std::bind(on_get, std::placeholders::_1, second_res),
|
||||
[=](bool ok) {
|
||||
if (not ok) {
|
||||
// DHT failed
|
||||
second_res->done = true;
|
||||
if (done_cb and first_res->done)
|
||||
on_done(false);
|
||||
}
|
||||
else {
|
||||
second_res->done = true;
|
||||
if (first_res->done)
|
||||
on_done(true);
|
||||
}
|
||||
}, pht_filter);
|
||||
} else {
|
||||
on_done(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Pht::lookup(Key k, Pht::LookupCallback cb, DoneCallbackSimple done_cb, bool exact_match) {
|
||||
auto prefix = linearize(k);
|
||||
auto values = std::make_shared<std::vector<std::shared_ptr<IndexEntry>>>();
|
||||
|
||||
auto lo = std::make_shared<int>(0);
|
||||
auto hi = std::make_shared<int>(prefix.size_);
|
||||
std::shared_ptr<unsigned> max_common_prefix_len = not exact_match ? std::make_shared<unsigned>(0) : nullptr;
|
||||
|
||||
lookupStep(prefix, lo, hi, values,
|
||||
[=](std::vector<std::shared_ptr<IndexEntry>>& entries, Prefix p) {
|
||||
std::vector<std::shared_ptr<Value>> vals(entries.size());
|
||||
|
||||
std::transform(entries.begin(), entries.end(), vals.begin(),
|
||||
[](const std::shared_ptr<IndexEntry>& ie) {
|
||||
return std::make_shared<Value>(ie->value);
|
||||
});
|
||||
|
||||
cb(vals, p);
|
||||
}, done_cb, max_common_prefix_len, cache_.lookup(prefix));
|
||||
}
|
||||
|
||||
void Pht::updateCanary(Prefix p) {
|
||||
// TODO: change this... copy value
|
||||
dht::Value canary_value;
|
||||
canary_value.user_type = canary_;
|
||||
|
||||
dht_->put(p.hash(), std::move(canary_value),
|
||||
[=](bool){
|
||||
static std::bernoulli_distribution d(0.5);
|
||||
crypto::random_device rd;
|
||||
if (p.size_ and d(rd))
|
||||
updateCanary(p.getPrefix(-1));
|
||||
}
|
||||
);
|
||||
|
||||
if (p.size_) {
|
||||
dht::Value canary_second_value;
|
||||
canary_second_value.user_type = canary_;
|
||||
dht_->put(p.getSibling().hash(), std::move(canary_second_value));
|
||||
}
|
||||
}
|
||||
|
||||
void Pht::insert(Prefix kp, IndexEntry entry, std::shared_ptr<int> lo, std::shared_ptr<int> hi, time_point time_p,
|
||||
bool check_split, DoneCallbackSimple done_cb) {
|
||||
|
||||
if (time_p + ValueType::USER_DATA.expiration < clock::now()) return;
|
||||
|
||||
auto vals = std::make_shared<std::vector<std::shared_ptr<IndexEntry>>>();
|
||||
auto final_prefix = std::make_shared<Prefix>();
|
||||
|
||||
lookupStep(kp, lo, hi, vals,
|
||||
[=](std::vector<std::shared_ptr<IndexEntry>>&, Prefix p) {
|
||||
*final_prefix = Prefix(p);
|
||||
},
|
||||
[=](bool ok){
|
||||
if (not ok) {
|
||||
if (done_cb)
|
||||
done_cb(false);
|
||||
} else {
|
||||
|
||||
RealInsertCallback real_insert = [=]( std::shared_ptr<Prefix> p, IndexEntry entry) {
|
||||
updateCanary(*p);
|
||||
checkPhtUpdate(*p, entry, time_p);
|
||||
cache_.insert(*p);
|
||||
dht_->put(p->hash(), std::move(entry), done_cb , time_p);
|
||||
};
|
||||
|
||||
if ( not check_split or final_prefix->size_ == kp.size_ ) {
|
||||
real_insert(final_prefix, std::move(entry));
|
||||
} else {
|
||||
if ( vals->size() < MAX_NODE_ENTRY_COUNT ) {
|
||||
getRealPrefix(final_prefix, std::move(entry), real_insert);
|
||||
}
|
||||
else {
|
||||
split(*final_prefix, vals, entry, real_insert);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, nullptr, cache_.lookup(kp), true
|
||||
);
|
||||
}
|
||||
|
||||
Prefix Pht::zcurve(const std::vector<Prefix>& all_prefix) const {
|
||||
Prefix p;
|
||||
|
||||
if ( all_prefix.size() == 1 )
|
||||
return all_prefix[0];
|
||||
|
||||
/* All prefix got the same size (thanks to padding) */
|
||||
size_t prefix_size = all_prefix[0].content_.size();
|
||||
|
||||
/* Loop on all uint8_t of the input prefix */
|
||||
for ( size_t j = 0, bit = 0; j < prefix_size; j++) {
|
||||
|
||||
uint8_t mask = 0x80;
|
||||
/* For each of the 8 bits of the input uint8_t */
|
||||
for ( int i = 0; i < 8; ) {
|
||||
|
||||
uint8_t flags = 0;
|
||||
uint8_t content = 0;
|
||||
|
||||
/* For each bit of the output uint8_t */
|
||||
for ( int k = 0 ; k < 8; k++ ) {
|
||||
|
||||
auto diff = k - i;
|
||||
|
||||
/*get the content 'c', and the flag 'f' of the input prefix */
|
||||
auto c = all_prefix[bit].content_[j] & mask;
|
||||
auto f = all_prefix[bit].flags_[j] & mask;
|
||||
|
||||
/* Move this bit at the right position according to the diff
|
||||
and merge it into content and flags in the same way */
|
||||
content |= ( diff >= 0 ) ? c >> diff : c << std::abs(diff);
|
||||
flags |= ( diff >= 0 ) ? f >> diff : f << std::abs(diff);
|
||||
|
||||
/* If we are on the last prefix of the vector get back to the first and
|
||||
,move the mask in order to get the n + 1nth bit */
|
||||
if ( ++bit == all_prefix.size() ) { bit = 0; ++i; mask >>= 1; }
|
||||
}
|
||||
|
||||
/* Add the next flags + content to the output prefix */
|
||||
p.content_.push_back(content);
|
||||
p.flags_.push_back(flags);
|
||||
p.size_ += 8;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Prefix Pht::linearize(Key k) const {
|
||||
if (not validKey(k)) { throw std::invalid_argument(INVALID_KEY); }
|
||||
|
||||
std::vector<Prefix> all_prefix;
|
||||
all_prefix.reserve(k.size());
|
||||
|
||||
/* Get the max size of the keyspec and take it for size limit (for padding) */
|
||||
auto max = std::max_element(keySpec_.begin(), keySpec_.end(),
|
||||
[](const std::pair<std::string, size_t>& a, const std::pair<std::string, size_t>& b) {
|
||||
return a.second < b.second;
|
||||
})->second + 1;
|
||||
|
||||
for ( auto const& it : k ) {
|
||||
Prefix p = Blob {it.second.begin(), it.second.end()};
|
||||
p.addPaddingContent(max);
|
||||
p.updateFlags();
|
||||
|
||||
all_prefix.emplace_back(std::move(p));
|
||||
}
|
||||
|
||||
return zcurve(all_prefix);
|
||||
}
|
||||
|
||||
void Pht::getRealPrefix(std::shared_ptr<Prefix> p, IndexEntry entry, RealInsertCallback end_cb ) {
|
||||
|
||||
if ( p->size_ == 0 ) {
|
||||
end_cb(p, std::move(entry));
|
||||
return;
|
||||
}
|
||||
|
||||
auto total = std::make_shared<unsigned int>(0); /* Will contains the total number of data on 3 nodes */
|
||||
auto ended = std::make_shared<unsigned int>(0); /* Just indicate how many have end */
|
||||
|
||||
auto parent = std::make_shared<Prefix>(p->getPrefix(-1));
|
||||
auto sibling = std::make_shared<Prefix>(p->getSibling());
|
||||
|
||||
auto pht_filter = [&](const dht::Value& v) {
|
||||
return v.user_type.compare(0, name_.size(), name_) == 0;
|
||||
};
|
||||
|
||||
/* Lambda will count total number of data node */
|
||||
auto count = [=]( const std::shared_ptr<dht::Value> value ) {
|
||||
if ( value->user_type != canary_)
|
||||
(*total)++;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto on_done = [=] ( bool ) {
|
||||
(*ended)++;
|
||||
/* Only the last one do the CallBack*/
|
||||
if ( *ended == 3 ) {
|
||||
if ( *total < MAX_NODE_ENTRY_COUNT )
|
||||
end_cb(parent, std::move(entry));
|
||||
else
|
||||
end_cb(p, std::move(entry));
|
||||
}
|
||||
};
|
||||
|
||||
dht_->get(parent->hash(),
|
||||
count,
|
||||
on_done,
|
||||
pht_filter
|
||||
);
|
||||
|
||||
dht_->get(p->hash(),
|
||||
count,
|
||||
on_done,
|
||||
pht_filter
|
||||
);
|
||||
|
||||
dht_->get(sibling->hash(),
|
||||
count,
|
||||
on_done,
|
||||
pht_filter
|
||||
);
|
||||
}
|
||||
|
||||
void Pht::checkPhtUpdate(Prefix p, IndexEntry entry, time_point time_p) {
|
||||
|
||||
Prefix full = entry.prefix;
|
||||
if ( p.content_.size() * 8 >= full.content_.size() * 8 ) return;
|
||||
|
||||
auto next_prefix = full.getPrefix( p.size_ + 1 );
|
||||
|
||||
dht_->listen(next_prefix.hash(),
|
||||
[=](const std::shared_ptr<dht::Value> &value) {
|
||||
if (value->user_type == canary_) {
|
||||
insert(full, entry, std::make_shared<int>(0), std::make_shared<int>(full.size_), time_p, false, nullptr);
|
||||
|
||||
/* Cancel listen since we found where we need to update*/
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
[=](const dht::Value& v) {
|
||||
/* Filter value v thats start with the same name as ours */
|
||||
return v.user_type.compare(0, name_.size(), name_) == 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void Pht::split(Prefix insert, std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals, IndexEntry entry, RealInsertCallback end_cb ) {
|
||||
auto full = Prefix(entry.prefix);
|
||||
|
||||
auto loc = foundSplitLocation(full, vals);
|
||||
auto prefix_to_insert = std::make_shared<Prefix>(full.getPrefix(loc));
|
||||
|
||||
for(;loc != insert.size_ - 1; loc--) {
|
||||
updateCanary(full.getPrefix(loc));
|
||||
}
|
||||
|
||||
end_cb(prefix_to_insert, entry);
|
||||
}
|
||||
|
||||
} /* indexation */
|
||||
|
||||
} /* dht */
|
||||
+19
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2017 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,11 @@ InfoHash::getRandom()
|
||||
{
|
||||
InfoHash h;
|
||||
crypto::random_device rdev;
|
||||
std::uniform_int_distribution<uint8_t> rand_byte;
|
||||
#ifdef _WIN32
|
||||
static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
|
||||
#else
|
||||
static std::uniform_int_distribution<uint8_t> rand_byte;
|
||||
#endif
|
||||
std::generate(h.begin(), h.end(), std::bind(rand_byte, std::ref(rdev)));
|
||||
return h;
|
||||
}
|
||||
@@ -87,4 +91,17 @@ std::ostream& operator<< (std::ostream& s, const InfoHash& h)
|
||||
return s;
|
||||
}
|
||||
|
||||
std::istream& operator>> (std::istream& s, InfoHash& h)
|
||||
{
|
||||
std::array<char, HASH_LEN*2> dat;
|
||||
s.exceptions(std::istream::eofbit | std::istream::failbit);
|
||||
s.read(&(*dat.begin()), dat.size());
|
||||
for (size_t i = 0; i < HASH_LEN; i++) {
|
||||
unsigned res = 0;
|
||||
sscanf(dat.data() + 2*i, "%02x", &res);
|
||||
h[i] = res;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace dht {
|
||||
namespace log {
|
||||
|
||||
/**
|
||||
* Print va_list to std::ostream (used for logging).
|
||||
*/
|
||||
void
|
||||
printLog(std::ostream& s, char const *m, va_list args) {
|
||||
// print log to buffer
|
||||
std::array<char, 8192> buffer;
|
||||
int ret = vsnprintf(buffer.data(), buffer.size(), m, args);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
// write timestamp
|
||||
using namespace std::chrono;
|
||||
using log_precision = microseconds;
|
||||
constexpr auto den = log_precision::period::den;
|
||||
auto micro = duration_cast<log_precision>(steady_clock::now().time_since_epoch()).count();
|
||||
s << "[" << std::setfill('0') << std::setw(6) << micro / den << "."
|
||||
<< std::setfill('0') << std::setw(6) << micro % den << "]" << " ";
|
||||
|
||||
// write log
|
||||
s.write(buffer.data(), std::min((size_t) ret, buffer.size()));
|
||||
if ((size_t) ret >= buffer.size())
|
||||
s << "[[TRUNCATED]]";
|
||||
s << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
enableLogging(dht::DhtRunner &dht) {
|
||||
dht.setLoggers(
|
||||
[](char const *m, va_list args) {
|
||||
std::cerr << red;
|
||||
printLog(std::cerr, m, args);
|
||||
std::cerr << def;
|
||||
},
|
||||
[](char const *m, va_list args) {
|
||||
std::cout << yellow;
|
||||
printLog(std::cout, m, args);
|
||||
std::cout << def;
|
||||
},
|
||||
[](char const *m, va_list args) { printLog(std::cout, m, args); }
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
|
||||
auto logfile = std::make_shared<std::fstream>();
|
||||
logfile->open(path, std::ios::out);
|
||||
|
||||
dht.setLoggers(
|
||||
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
|
||||
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
|
||||
[=](char const *m, va_list args) { printLog(*logfile, m, args); }
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
disableLogging(dht::DhtRunner &dht) {
|
||||
dht.setLoggers(dht::NOLOG, dht::NOLOG, dht::NOLOG);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+761
-339
File diff suppressed because it is too large.
Load diff
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user