Compare commits

...
233 Commits
Author SHA1 Message Date
Adrien Beraud cf73feb056 dht: use max date for permanent puts 2025-11-28 13:41:29 -05:00
Adrien Béraud e028c1be8c update version to 3.6.0 2025-11-26 14:03:56 -05:00
Adrien Béraud 3e8d9835d4 utils: various fixes to build with c++23 2025-11-26 14:03:56 -05:00
Adrien Béraud 18df23bd50 build/cmake: support c++ other than 17 2025-11-26 14:03:56 -05:00
Adrien Béraud 6b8c3ea581 base64: use simdutf 2025-11-26 14:01:45 -05:00
dependabot[bot] 7645f284e4 build(deps): bump pypa/cibuildwheel from 3.2.1 to 3.3.0
Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.2.1 to 3.3.0.
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v3.2.1...v3.3.0)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-version: 3.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-25 10:54:55 -05:00
dependabot[bot] 2cec478dfc build(deps): bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-25 10:54:00 -05:00
Adrien Béraud 54f07e449c pkgconfig: link with fmt 2025-11-19 11:20:40 -05:00
Adrien Béraud 09308321f8 network_utils: cleanup 2025-11-19 11:20:02 -05:00
Adrien Béraud e4b333b672 add clang-format 2025-11-19 11:20:02 -05:00
Adrien Béraud 69f382449d add .vscode settings 2025-11-19 11:19:55 -05:00
Adrien Beraud 47d2f41930 proxy client: check for null resolver 2025-11-17 12:56:36 -05:00
ovari d6b124eec0 Update BUILD.md 2025-11-16 17:35:19 -05:00
ovari 0330ee6683 Update BUILD.md 2025-11-16 17:35:19 -05:00
Jean-Charles de Longueville 1b854b8a09 Update BUILD.md from reviewer's comments 2025-11-16 16:50:04 -05:00
Jean-Charles de Longueville 4f6c561540 Update BUILD.md: typo 2025-11-16 16:50:04 -05:00
Jean-Charles de Longueville 79ffe663f6 Update BUILD.md: add debian 13 trixie instructions 2025-11-16 16:50:04 -05:00
dependabot[bot] a14a97e3a2 build(deps): bump actions/download-artifact from 5 to 6
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-28 10:20:24 -04:00
dependabot[bot] bddc34d47b build(deps): bump actions/upload-artifact from 4 to 5
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-28 10:19:46 -04:00
kestrel de6ea1d632 Add support for io_uring for Autotools builds.
* configure.ac (liburing): Add --with-liburing option, tests for liburing.
* src/Makefile.am (libopendht_la_CPPFLAGS, libopendht_la_LIBS): Add relevant compiler and linker flags.
2025-10-15 15:13:19 -04:00
kestrel 1d2fd80fad Use pkg-config to test for llhttp for Autotools builds.
* configure.ac (llhttp_lib): Replaces existing tests with PKG_CHECK_MODULES.
* src/Makefile.am (libopendht_la_CPPFLAGS, libopendht_la_LIBS): Add relevant compiler and linker flags.
2025-10-15 15:13:19 -04:00
SASANO Takayoshi f7df3413e1 CMakeLists.txt: revise libreadline check on OpenBSD 2025-10-15 15:12:17 -04:00
SASANO Takayoshi 4cb67002e3 CMakeLists.txt: fix -lreadline not found error 2025-10-15 15:12:17 -04:00
SASANO Takayoshi 197a9a6bcd CMakeLists.txt: fix 'install TARGETS RUNTIME_DEPENDENCY_SET is not supported' 2025-10-15 15:12:17 -04:00
SASANO Takayoshi 8641de139d CMakeLists.txt: avoid libreadline check on OpenBSD 2025-10-15 15:12:17 -04:00
dependabot[bot] adcb61bbf9 build(deps): bump pypa/cibuildwheel from 3.2.0 to 3.2.1
Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v3.2.0...v3.2.1)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-version: 3.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-15 15:11:09 -04:00
dependabot[bot] 70709c9a68 build(deps): bump github/codeql-action from 3 to 4
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3 to 4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-15 15:10:42 -04:00
kestrel bf930de9e4 configure.ac: Fix llhttplib substituion.
* configure.ac (@http_lib@): Rename to llhttp_lib, replace the substituted value for a pkg-config module name.
2025-10-13 14:35:28 -04:00
Adrien Beraud bb4e716fc7 README: add pypi badge 2025-10-10 13:59:44 -04:00
Adrien Beraud 54fd6cf64f securedht: avoid calling identity announced callback multiple times 2025-10-10 13:59:44 -04:00
dependabot[bot] d905a02b32 build(deps): bump pypa/cibuildwheel from 3.1.4 to 3.2.0
Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.1.4 to 3.2.0.
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v3.1.4...v3.2.0)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-version: 3.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-10 11:11:56 -04:00
Adrien Béraud d12f9271b8 pht: use const reference for IndexEntry::TYPE
Prevents static initialization order issue
2025-09-22 14:41:22 -04:00
Adrien Béraud 3639d651a2 docker: add alpine edge container 2025-09-22 14:41:22 -04:00
Adrien Béraud 07824391a2 update version to 3.5.5 2025-09-22 14:41:22 -04:00
Adrien Béraud c855f495d0 ci/release: remove reference to removed artifact 2025-09-19 00:59:28 -04:00
Adrien Béraud cc5c148fc1 python: repair python installation with cmake 2025-09-19 00:41:18 -04:00
Adrien Béraud 949751f632 crypto: disable Oaep test for win32 2025-09-18 23:39:38 -04:00
Adrien Béraud 6dfc4e4ba1 ci: don't build with documentation on Windows/MSVC 2025-09-18 23:19:35 -04:00
Adrien Béraud db8d62e17b ci: don't build with documentation on Windows/MSVC 2025-09-18 23:02:22 -04:00
Adrien Béraud 7226775987 crypto: disable Oaep test for win32 2025-09-18 22:26:50 -04:00
Adrien Béraud 9c264e1cad python: add debug information for python install 2025-09-18 22:19:41 -04:00
Adrien Béraud deee57b6dd ci/github: call ctest directly 2025-09-14 18:27:19 -04:00
Adrien Béraud 95f0b27eae cmake: build tests as separate executables 2025-09-14 17:55:59 -04:00
ovari b6f98a8488 Update crypto.cpp 2025-09-14 13:38:35 -04:00
ovari 73acc27a11 Update CheckAtomic.cmake 2025-09-14 13:38:35 -04:00
ovari d46e302b3f Update network_engine.h 2025-09-14 13:38:35 -04:00
ovari 6f57e03b48 Update network_engine.h 2025-09-14 13:38:35 -04:00
ovari a5e39768e4 Update securedht.cpp 2025-09-14 13:38:35 -04:00
ovari 6f6fdba8dd Update value.cpp 2025-09-14 13:38:35 -04:00
ovari e5ef0a8900 Update dhtrunner.h 2025-09-14 13:38:35 -04:00
ovari b6f21933ab Update securedht.h 2025-09-14 13:38:35 -04:00
ovari e4b8b0259d Update http.cpp 2025-09-14 13:38:35 -04:00
ovari 8134d6201a Update network_engine.cpp 2025-09-14 13:38:35 -04:00
ovari db4cd7dcc1 Update peer_discovery.cpp 2025-09-14 13:38:35 -04:00
ovari 9d6107c01c Update storage.h 2025-09-14 13:38:35 -04:00
ovari de46d55b13 Update crypto.cpp
“ !” → “.”
bits → bit
can’t → unable to
wrong → incorrect
2025-09-14 13:38:35 -04:00
Adrien Béraud 75afd9d9dc ci/msvc: build without documentation 2025-09-14 13:36:45 -04:00
Adrien Beraud 99c56d13bb crypto: fix build on GnuTLS 3.8.3 and bellow 2025-09-08 16:38:25 -04:00
Adrien Béraud 95fa29d2ec securedht: add CertificateStoreQuery by PkId 2025-09-08 00:14:44 -04:00
Adrien Béraud f3d9d8414d crypto: add test for RSA OAEP 2025-09-07 23:45:40 -04:00
Adrien Béraud 0c9d715d6d crypto: allow to generate RSA OAEP private keys 2025-09-07 23:44:47 -04:00
Adrien Béraud cfff247e06 crypto: support RSA OAEP encryption and decryption 2025-09-07 22:15:00 -04:00
Adrien Béraud 04edc70fee dhtrunner: update documentation for join() 2025-09-06 17:14:10 -04:00
Adrien Béraud fdc4bdee68 ci: install cmake on Debian 12 2025-09-06 16:35:34 -04:00
Adrien Béraud 69bf7afe31 BUILD.md: add pkg-config and support for Debian 12 2025-09-06 16:33:48 -04:00
Adrien Béraud 7b3ee44175 ci: add proxy dependencies for Debian 12 2025-09-06 16:33:21 -04:00
Adrien Béraud 122c30cce8 ci: add Debian 12 2025-09-06 16:08:03 -04:00
Adrien Béraud 957e05319f BUILD.md: cleanup 2025-09-05 00:35:46 -04:00
Adrien Béraud 58f83ab3c6 build/cmake: python cleanup 2025-09-05 00:35:28 -04:00
Adrien Béraud 6151ee8c0b pyproject: remove unneeded install command 2025-09-04 23:23:27 -04:00
Adrien Béraud c08b6a7f5d add support for version 2025-09-04 23:22:34 -04:00
Adrien Béraud 0139e7a2d4 update README.md 2025-09-04 23:22:10 -04:00
Adrien Béraud 416de4b4f8 update version to 3.5.4 2025-09-02 23:52:56 -04:00
Adrien Béraud b45f32e8f8 README: update for new Python API 2025-09-02 23:51:36 -04:00
Adrien Béraud cda5b0afa2 python: update pingpong example for asyncio 2025-09-02 23:48:43 -04:00
Adrien Béraud f66a57b033 python: cleanup asynio layer 2025-09-02 23:48:34 -04:00
Adrien Béraud 72a688cd14 ci/release-package: remove deprecated python wheels build 2025-09-02 23:07:48 -04:00
Adrien Béraud e882efe89e build/cmake: use VCPKG_INSTALLED_DIR for python 2025-09-02 21:49:30 -04:00
Adrien Beraud 7b49ed873c build/python: install build for ci job 2025-09-02 19:49:02 -04:00
Adrien Béraud 3fec6e7636 pht: don't export IndexEntry::ValueType 2025-09-02 09:22:40 -04:00
Adrien Béraud 67ac7a4d86 python: update pingpong example for asyncio 2025-09-02 01:57:09 -04:00
Adrien Béraud 615534fa0f python: add initial asyncio implementation 2025-09-02 01:45:29 -04:00
Adrien Béraud 4250336951 .gitignore: add cmake files 2025-09-02 01:45:29 -04:00
Adrien Béraud 932cacbda3 python: use single to argument for putEncrypted 2025-09-02 01:40:28 -04:00
Adrien Béraud 3b254663ca build/python: install delvewheel from ci job 2025-09-02 01:37:59 -04:00
Adrien Béraud 18f74693e9 ci/github: merge windows python wheels 2025-09-01 21:06:11 -04:00
Adrien Béraud e0cc973aa4 build/cmake: enable python in full vcpkg preset 2025-09-01 20:17:42 -04:00
Adrien Béraud c866d46798 build/cmake: filter more windows dlls 2025-09-01 20:17:42 -04:00
Adrien Béraud c762e4e43f build/cmake: remove python from all taregts 2025-09-01 20:17:42 -04:00
Adrien Béraud 3eed83c22d ci/github: build windows python wheel 2025-09-01 20:17:42 -04:00
Adrien Béraud 234f47a018 python/setup.py: use appropriate flags for windows build 2025-09-01 20:17:42 -04:00
Adrien Béraud 615463e103 ci/python: add support for windows/msvc wheel build 2025-09-01 20:17:42 -04:00
Adrien Béraud d50585188d utils: add missing header 2025-09-01 19:42:41 -04:00
Adrien Béraud dd247d15ba python: call gnutls_global_init/gnutls_global_deinit on module load/unload 2025-09-01 19:40:20 -04:00
Adrien Béraud 4a34045c0f python/setup.py: add appropriate build definitions 2025-09-01 19:33:18 -04:00
Adrien Béraud edfdb39970 vcpkg: update description 2025-09-01 19:27:59 -04:00
Adrien Béraud 89551496c7 python: update readme 2025-08-31 00:21:46 -04:00
Adrien Beraud becb878f5f python: add bindings for sign, checkSignature 2025-08-31 00:04:00 -04:00
Adrien Beraud a94f99dcd2 python: add annotations and checks 2025-08-30 23:52:40 -04:00
Adrien Beraud 8de9584b72 dhtrunner: mark getId() deprecated 2025-08-30 22:20:32 -04:00
Adrien Beraud 303a3c2c5a python: unify putEncrypted 2025-08-30 22:18:49 -04:00
Adrien Beraud e6dcc3226d python: cleanup 2025-08-30 19:54:33 -04:00
Adrien Beraud ab71e5a59e python: add support for putEncrypted with PkId 2025-08-30 19:30:20 -04:00
Adrien Beraud bf9561c4af python: add binding for getLongId, getPublicKey 2025-08-30 19:27:57 -04:00
Adrien Beraud c139fc9791 python: add binding for PkId 2025-08-30 19:13:59 -04:00
dependabot[bot] 31ddf3cc27 build(deps): bump actions/download-artifact from 4 to 5
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 10:50:51 -04:00
Adrien Béraud 1bbdc3e673 add BUILD.md 2025-08-24 20:05:55 -04:00
Adrien Béraud 60ecb95cf6 build/python: copy README.md to build dir 2025-08-24 16:01:29 -04:00
Adrien Béraud 075ea59244 build/cmake: fix including jsoncpp on linux 2025-08-24 15:52:39 -04:00
Adrien Béraud 2f98f1f987 ci/pipy: build for Python 13 2025-08-24 11:22:49 -04:00
Adrien Béraud 2b22fe9055 setup.py: update metadata 2025-08-24 11:22:32 -04:00
Adrien BéraudandCopilot Autofix powered by AI e144460869 Potential fix for code scanning alert no. 17: Workflow does not contain permissions
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-08-24 01:47:50 -04:00
Adrien Béraud 6b54c42fdb build python with appropriate flags for public dependencies 2025-08-24 01:47:50 -04:00
Adrien Béraud 57587b6cd8 build/cmake: improve msgpack lookup logic 2025-08-24 01:47:50 -04:00
Adrien Béraud 0fd642f92d ci: add python-wheels.yml 2025-08-24 01:47:50 -04:00
Adrien Béraud 91310c83a7 setup.py.in: remove unneeded cythonize 2025-08-24 01:47:50 -04:00
Adrien Béraud daf2f8edaf value: add OPENDHT_PUBLIC to default store policy 2025-08-24 01:25:47 -04:00
Adrien Béraud a957cdba86 python: update copyright 2025-08-18 09:58:54 -04:00
Adrien Béraud 5a9a8dc67a dependabot: add cargo ecosystem for rust 2025-08-18 09:58:52 -04:00
Adrien Béraud 5fe0dad574 build/python: replace calls to setup.py 2025-08-17 22:08:13 -04:00
Adrien Béraud a051b391a8 python: update setup.py to use a SPDX license expression 2025-08-17 00:17:14 -04:00
Adrien Béraud ec27ff6c49 docker: update for Ubuntu 24.04 2025-08-17 00:00:09 -04:00
Adrien Béraud 0e1042124e docker: update to Ubuntu 24.04, drop Ubuntu 18.04 2025-08-16 23:45:42 -04:00
dependabot[bot] f7e7101abc build(deps): bump alpine from 3.19 to 3.22 in /docker
Bumps alpine from 3.19 to 3.22.

---
updated-dependencies:
- dependency-name: alpine
  dependency-version: '3.22'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-16 23:30:13 -04:00
dependabot[bot] 26957ee632 build(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-16 23:29:14 -04:00
dependabot[bot] 04fa07edfe build(deps): bump actions/download-artifact from 4 to 5
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-16 23:28:15 -04:00
dependabot[bot] 6cf763dfa4 build(deps): bump docker/build-push-action from 5 to 6
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-16 23:27:13 -04:00
Adrien Béraud c41e42e58c Create dependabot.yml 2025-08-16 23:20:39 -04:00
Adrien BéraudandCopilot Autofix powered by AI 1b238083d3 Potential fix for code scanning alert no. 7: Workflow does not contain permissions
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-08-16 22:12:56 -04:00
Adrien Béraud 0784270c2e ci/github: use codeql for github actions 2025-08-16 21:49:02 -04:00
Adrien Béraud e675bb62fd update version to 3.5.1 2025-08-16 21:34:13 -04:00
Adrien Béraud 43ac0e14e0 python: fix syntax error in setup.py.in 2025-08-16 21:22:57 -04:00
Adrien Béraud f4d494cb3d python: build inplace in build directory 2025-08-16 21:22:57 -04:00
Adrien Béraud b3dfbf13d8 tools: header cleanup 2025-08-16 21:22:57 -04:00
Adrien Béraud 93538e89c6 build/cmake: add appropriate llhttp flags to opendht.pc 2025-08-16 21:22:57 -04:00
Adrien Béraud 947e845dcd meson: require meson 1.1 2025-08-16 21:22:57 -04:00
Adrien Béraud 6b49de7e4b build/cmake: update presets 2025-08-16 21:22:57 -04:00
Adrien Béraud f6191fa2a5 devcontainer: update 2025-08-16 21:22:57 -04:00
Adrien Béraud b167887d51 build/cmake: move WIN32_WINNT version detection to dedicated script 2025-08-05 20:25:12 -04:00
Adrien Béraud 77769898ea ci/release: install wix 2025-08-04 09:45:43 -04:00
Adrien Béraud 42189e3cf7 build/cmake: cleanup 2025-08-04 09:45:29 -04:00
Adrien Béraud 73f8000e49 ci/release: build with cpack 2025-08-04 09:25:46 -04:00
Adrien Béraud 298e334482 build/cmake: always find asio by header 2025-08-04 09:25:32 -04:00
Adrien Béraud bb982b8cf9 build/cmake: always find asio by header 2025-08-04 09:15:40 -04:00
Adrien Béraud 80145c37bb build/cmake: enable OPENDHT_DOWNLOAD_DEPS by default 2025-08-04 09:15:19 -04:00
Adrien Béraud bc8503a21e ci/release: create vcpkg directories before install 2025-08-03 23:31:50 -04:00
Adrien Béraud 2947dbfe5f update version to 3.5.0 2025-08-03 23:25:57 -04:00
Adrien Béraud bf9ddfc72f build/cmake: add build presets 2025-08-03 23:25:43 -04:00
Adrien Béraud c848a7e70b ci/release: build static dhtnode 2025-08-03 22:53:00 -04:00
Adrien Béraud e7c5b0e36f ci/windows: use dependency cache 2025-08-03 22:48:48 -04:00
Adrien Béraud 41282c99f9 build/cmake: dhtscanner, dhtchat are examples 2025-08-03 22:31:43 -04:00
Adrien Béraud e25f6f131a build/vcpkg: update to 2025.07.25 2025-08-03 21:37:39 -04:00
Adrien Béraud e69f0fd01e ci/vcpkg: cache vcpkg binary output 2025-08-02 10:19:04 -04:00
Adrien Béraud 30c9534bc5 build/vcpkg: link to appropriate target for jsoncpp 2025-08-02 10:19:04 -04:00
Adrien Béraud 6d56fb7510 build/cmake: add vcpkg_manifest_static 2025-08-02 10:19:04 -04:00
Adrien Beraud e46d03b440 ci: enable back OPENDHT_DOWNLOAD_DEPS in CI 2025-07-21 16:30:57 -04:00
Adrien Beraud 8255596171 cmake: various fixes on Linux 2025-07-21 15:49:34 -04:00
Adrien Beraud baae3ba701 cmake/presets: build ninja with proxy 2025-07-21 13:28:36 -04:00
Maxim Cournoyer 6c43be2a03 configure.ac: Improve the error message when readline is missing.
* configure.ac[tools]: Mention that the requirement is due to the
tools.
2025-07-21 08:24:03 -04:00
Maxim Cournoyer ee4c8a19d6 configure.ac: Error out when doc is requested but Doxygen is missing.
Previously, documentation would be automatically disabled when Doxygen
was found missing.

* configure.ac: Change AC_MSG_WARN into AC_MSG_ERROR and adjust error
message.
2025-07-21 08:24:03 -04:00
Maxim Cournoyer e8cf9dd25f configure.ac: Make the Python option depend on the indexation option.
Mimic what is done already in the CMakeLists.txt file, with one
distinction: do not automagically turn on indexation when Python is
selected; rather, stop and tell the user that it is required for
Python support.  Remove the automatic downgrade to --disable-python
when Cython is not found.

* configure.ac: Enforce dependencies on indexation and Cython when
Python support is requested.
2025-07-21 08:24:03 -04:00
Maxim Cournoyer df21c4524c configure.ac: Fix the description of the '--without-openssl' option. 2025-07-21 08:24:03 -04:00
Maxim Cournoyer ccec6c2f67 replace usleep with nanosleep
* src/compat/msvc/unistd.h (usleep): Delete.
* tools/dhtcnode.c (main) <usleep>: Replace with nanosleep on non
Windows platform, or Sleep on Windows.

Fixes: #607
2025-07-20 22:25:28 -04:00
Adrien Béraud 5ab450491c Merge remote-tracking branch 'origin/master' into pulls/1772757862/750 2025-07-20 11:59:30 -04:00
Adrien Béraud 3b0cce8c25 Added and tested build scenarios for Windows (MSYS2, MSVC) 2025-07-20 11:55:40 -04:00
copilot-swe-agent[bot]andaberaud d6b6f30275 Replace hardcoded documentation path with CMAKE_INSTALL_DOCDIR
Co-authored-by: aberaud <101827+aberaud@users.noreply.github.com>
2025-07-19 23:08:08 -04:00
Adrien Béraud c9f18c8349 Pull Request #750: Added and tested build scenarios for Windows (MSYS2, MSVC) 2025-07-19 14:36:26 -04:00
Adrien Beraud df3186ad95 proxy server: export ServerStats 2025-07-16 11:29:18 -04:00
Andrey Vukolov 58956549b8 Merge branch 'savoirfairelinux:master' into winbuild 2025-07-15 16:47:24 +02:00
Adrien Beraud 74ed041791 tests/dhtrunner: create value as shared_ptr 2025-07-10 13:50:42 -04:00
Adrien Beraud 312f883387 proxy server: move ServerStats impl to cpp 2025-07-10 13:46:17 -04:00
Andrey Vukolov fad4093183 CI fix (squashed 17 commits) 2025-06-27 14:27:48 +02:00
Andrey Vukolov 5c005e097e Harmonizing CMakeLists 2025-06-26 16:20:27 +02:00
Andrey Vukolov 69f23e49c4 Preparing for rebase and merge #750
Addresses:
        - https://github.com/savoirfairelinux/opendht/pull/750#discussion_r2157723135
        - https://github.com/savoirfairelinux/opendht/pull/750#discussion_r2157794234
        - https://github.com/savoirfairelinux/opendht/pull/750#discussion_r2157795386
        - https://github.com/savoirfairelinux/opendht/pull/750#discussion_r2161542551
        - https://github.com/savoirfairelinux/opendht/pull/750#discussion_r2161546768
2025-06-24 18:06:52 +02:00
Andrey Vukolov f53976dc2f Merge branch 'savoirfairelinux:master' into winbuild 2025-06-23 10:34:11 +02:00
Adrien Béraud 1d80a77e55 build/cmake: avoid overriding "" for CMAKE_MSVC_RUNTIME_LIBRARY 2025-06-20 19:06:08 -04:00
Adrien Béraud fb8734c448 c: use c++ linkage for some non-exported functions 2025-06-20 19:04:59 -04:00
Andrey Vukolov 090fe75b7f OpenSSL link MSVC workflow workaround 2025-06-19 12:56:44 +02:00
Andrey Vukolov 173ca3d923 OpenSSL link Clang workflow workaround 2025-06-19 12:52:30 +02:00
Andrey Vukolov f5c875a19d OpenSSL link CMake workflow check 2025-06-19 12:46:20 +02:00
Andrey Vukolov 6780013f50 Unit tests workaround for possible issue with OpenSSL link 2025-06-19 12:17:10 +02:00
Andrey Vukolov 2f21a6e35a Unit tests workaround for possible issue with OpenSSL link 2025-06-19 12:07:36 +02:00
Andrey Vukolov 9e9e364048 C tools CFLAGS workaround for STATIC builds 2025-06-19 11:59:50 +02:00
Andrey Vukolov 2c3296542b Crypt32.dll fix 2025-06-18 17:14:05 +02:00
Andrey Vukolov 72988cca28 Regression fix 2025-06-18 16:53:54 +02:00
Andrey Vukolov a105513750 Attempt to fix OpenSSL for MSYS2 builds on CI 2025-06-18 16:48:05 +02:00
Andrey Vukolov bece03eab8 Attempt to fix llhttp for MSYS2 builds on CI 2025-06-18 16:32:28 +02:00
Andrey Vukolov 0fdb6979dd Attempt to fix OpenSSL for MSYS2 builds on CI 2025-06-18 16:21:57 +02:00
Andrey Vukolov a77c1d9538 Attempt to fix llhttp for MSYS2 builds on CI 2025-06-18 16:13:10 +02:00
Andrey Vukolov 4a7e1aba15 Attempt to fix llhttp for MSYS2 builds on CI 2025-06-18 16:08:38 +02:00
Andrey Vukolov a4263b9b54 Attempt to fix llhttp for MSYS2 builds on CI 2025-06-18 15:59:41 +02:00
Andrey Vukolov e26ed26e05 Attempt to fix restinio for MSYS2 builds on CI 2025-06-18 15:47:31 +02:00
Andrey Vukolov 526b11f973 C binding fixes, libreadline support for MSVC 2025-06-18 15:30:51 +02:00
Andrey Vukolov 627af36085 MSYS2 Crypto library fix 2025-06-18 12:07:51 +02:00
Andrey Vukolov a22c84d013 MSVC static runtime fix 2025-06-18 11:41:52 +02:00
Andrey Vukolov 3707f6294e libreadline fix for C tools 2025-06-18 11:29:26 +02:00
Andrey Vukolov 94cb17ef63 libreadline fix, WINVER typo fix 2025-06-18 11:22:55 +02:00
Andrey Vukolov 9bb08fa194 Merge branch 'master' into winbuild 2025-06-18 10:40:02 +02:00
Adrien Béraud 425cd58ea6 ci: build a static windows release 2025-06-17 20:49:05 -04:00
Adrien Béraud 43eb062ac5 build/cmake: use appropriate definitions for shared c lib 2025-06-17 20:25:56 -04:00
Adrien Béraud 29d878fad7 build/cmake: inherit build dir for msvc 2025-06-17 20:22:22 -04:00
Adrien Béraud a3a95a8f59 build/cmake: use appropriate definitions for shared c lib 2025-06-17 20:22:22 -04:00
Adrien Béraud 550721e233 build/cmake: use global MSVC_RUNTIME_LIBRARY 2025-06-17 20:22:22 -04:00
Adrien Béraud fa11d60672 c: use OPENDHT_C_PUBLIC for all symbols 2025-06-17 20:22:22 -04:00
Andrey Vukolov 6f8c681b26 Boost fix 2025-06-17 20:23:45 +02:00
Andrey Vukolov 718e445370 typo fix 2025-06-17 19:37:05 +02:00
Andrey Vukolov 5e469cba0f Boost fetcher (MSYS2/MinGW dependency) 2025-06-17 19:26:40 +02:00
Andrey Vukolov a05479e2dc Merge branch 'master' into winbuild
- Built and tested on MSVC for static and dynamic builds, tested.
2025-06-17 18:59:51 +02:00
Andrey Vukolov fb630e29b9 Merge branch 'savoirfairelinux:master' into winbuild 2025-06-12 09:28:10 +02:00
Andrey Vukolov 3a0b09816b Merge remote-tracking branch 'refs/remotes/twdragon/winbuild' into winbuild 2025-06-12 09:23:14 +02:00
Andrey Vukolov 8ab6b5b06e Fixes for current MSVC build, presets deleted 2025-06-12 09:22:30 +02:00
Andrey Vukolov 9ca1c45ae7 CMakeLists.txt - remove occasional regression to cjson 2025-06-10 14:01:14 +02:00
Andrey Vukolov b9a6b1001c Merge branch 'master' into winbuild 2025-06-10 09:31:47 +02:00
Andrey Vukolov 798adefcde Fixes for MSYS2
- Set populated only for msgpack-cxx that does not exist for
      MinGW GCC x86_64
      https://packages.msys2.org/base/mingw-w64-msgpack-cxx
    - .gitignore fix for vcpkg (incorporated #760)
    - GnuTLS version handler fix (#755, #758)
2025-06-09 15:31:38 +02:00
Andrey Vukolov 72afb61079 Merge branch 'savoirfairelinux:master' into winbuild 2025-06-09 09:40:26 +02:00
Andrey Vukolov c27f0f8fdc Merge branch 'master' into winbuild 2025-06-07 22:32:26 +02:00
Andrey Vukolov 8d8b082ae2 Temporary fix https://github.com/savoirfairelinux/opendht/pull/750#discussion_r2129833074 2025-06-06 11:09:43 +02:00
Andrey Vukolov 5377a48074 Rebase regression fix in tools_common.h 2025-06-06 11:00:35 +02:00
Andrey Vukolov ca8998e62b Merge branch 'winbuild' of github.com:twdragon/opendht into winbuild 2025-06-05 18:38:49 +02:00
Andrey Vukolov 62359d9011 Edited CMakeLists.txt file for building over vcpkg only 2025-06-05 18:38:21 +02:00
Andrey Vukolov 3022c4b378 Merge branch 'savoirfairelinux:master' into winbuild 2025-06-05 17:52:47 +02:00
Andrey Vukolov de8b441dae Merge branch 'master' into winbuild 2025-06-02 16:37:57 +02:00
Andrey Vukolov 5c4997d07e Merge master branch changes
- Applies master branch changes from #753 #754 #755 #756
      and commits for version 3.4.0 by @aberaud to winbuild branch
      for #750
	- CMake version handler for MINIMUM requirement setup to 3.5
2025-06-02 16:26:45 +02:00
Andrey Vukolov 49b1daec38 Indentation fix 2025-05-23 15:43:08 +02:00
Andrey Vukolov 1eba919dbd Trailing newline fix 2025-05-23 14:42:43 +02:00
Andrey Vukolov 3cd5338890 opendht_EXPORTS fix for shared builds 2025-04-27 22:53:17 +02:00
Andrey Vukolov 2fc81ad2dd GnuTLS build fix for MSVC
- Removed GNUTLS_INTERNAL_BUILD definition to avoid
	  usage of POSIX free() function
	- Autotools build fix
2025-04-26 16:55:58 +02:00
Andrey Vukolov 63a49896bf Fix Meson build 2025-04-24 16:00:04 +02:00
Andrey Vukolov 80755e5f15 Fix Meson build 2025-04-24 15:55:06 +02:00
Andrey Vukolov ba25b8aeba Incorporated commits for version 3.3.1 + MSVC build fixes
- Incorporated code for version 3.3.1
	- Reverted constexpr commits for hex_map:
	  - 352e36500c
	  - 6a264d6f73
	  as they created a lot of problems during builds on
	  Windows/MSVC.
	- Tested binaried linked dynamically with:
	  - MSYS2 (production-ready)
	  - MSVC (only for testing) !!!danger of memory leaks!!!
	- Tested binaries linked statically on win32 x64 platform
	- Populated libasio for both MSYS2 and MSVC builds on Windows
	- Pipeline fixes to build on Windows using only:
	  - vcpkg for MSVC
	  - MSYS2 pacman for MinGW
	  and remove the external dependency directory

The reference Windows builds are accessible in the following IPFS directory:

https://bafybeihsrak7orgubrnl5lvpcyzb4xf6kc7cd4tfvctucftg6vfqdhphlq.ipfs.dweb.link/
2025-04-24 14:50:23 +02:00
Andrey Vukolov 279589fa78 Pre-master 2025-04-23 18:18:58 +02:00
Andrey Vukolov 1c1c99974a Added and tested build scenarios for Windows (MSYS2, MSVC static)
- Based on Windows build adjustment code from @novemus
	  (see his magnificient code merge request #716)
	- Determined full-static and dynamic link libraries for
	  Windows if built using MSYS2 or MSVC
	- Built without restinio and llhttp [TODO]
	- Set for automatic fetching and population from the network
	  the following libraries for MSYS2:
		- GnuTLS 3.8.4 for 64-bit Windows (tested for dynamic
		  and static builds)
			- Auto name adjustments for GnuTLS
		- GnuTLS 3.8.9 for 32-bit Windows (untested)
		- cJSON as a dependency for msgpack
		- msgpack 6.1.1
		- jsoncpp 1.9.5
		- libfmt 11.1.2
		- libasio 1.30.2
	  for MSVC:
		- cJSON (used by msgpack in dynamic builds)
		- jsoncpp 1.9.5
		- libfmt 11.1.2
	- Various build scenario fixes for MSVC dynamic builds
	- Added modular codebase for infohash.cpp to avoid header
	  treatment mismatches in MSVC when compiling DLL
	- Added convenience prints in the build scenario
	- Fixed inconvenient usage of pkgconfig in Windows, the
	  link scenarios adjusted accordingly
	- Fixed hardcoded find_library calls
	- Added standard CMake handler for Boost library using
	  BOOST_ROOT variable, including environmental definition
	- Fixed libreadline linkage on POSIX when the default link
	  point is turned off for OPENDHT_TOOLS (Mint Linux)
	- Added versioned handler for CMP0167 policy (from CMake 3.30)
	- Code fixes for compatibility headers in Windows (crypto.cpp,
	  network_utils.h, utils.h)
	- Urgent fix for improper redefinition of _WINNT_VERSION for
	  Windows 10/11
	  (https://github.com/savoirfairelinux/opendht/pull/716#issuecomment-2793129052)
	- Compile definitions fixed for opendht_EXPORTS and OPENDHT_BUILD
	  in build scenario for OPENDHT_TOOLS
	- Urgent fix for GnuTLS version handler in the code (type
	  redefinition in version 3.8.7 and later)
	  https://github.com/savoirfairelinux/opendht/pull/716#issuecomment-2792592951
	- Various fixes for proper dynamic linking in Windows
	- Built and tested in dynamic and static build scenarios under
	  MSYS2 in Windows 10 and Windows 11, proven working. The
	  static build does not seem fully static, the redevelopment
	  of the MSVC build scenario is proposed by @novemus
	- Built and tested in static mode under MSVC/Visual Studio 2022.
	  Proven working
	- Improper usage of the C's free() function is detected in GnuTLS
	  dynamically linked in Windows (shiftmedia-gnutls 3.7.2 to 3.8.7)
	- Added a MSVC-specific source hack to avoid using gnutls_free()
	  function when built in Windows using dynamic link.
	  !!! CAUTION !!!
	  This implementation should be considered as a dirty hack likely
	  leading to memory leaks! The code should be thoroughly tested
	  and refactored to avoid memory leaks, but the true origin of
	  errors is still not revealed [TODO]
	- My respect to @novemus and his works over #716
2025-04-22 14:46:41 +02:00
novemus 3be70cd90d msvc build adjustment 2024-07-13 09:42:34 +03:00
81 changed files with 4179 additions and 1949 deletions

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignArrayOfStructures: Left
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignConsecutiveMacros: true
AlignEscapedNewlines: DontAlign
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: TopLevelDefinitions
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- forever # avoids { wrapped to next line
- foreach
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 150
PenaltyBreakBeforeFirstCallParameter: 300
PenaltyBreakComment: 500
PenaltyBreakFirstLessLess: 400
PenaltyBreakString: 600
PenaltyExcessCharacter: 50
PenaltyReturnTypeOnItsOwnLine: 300
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: c++17
TabWidth: 4
UseTab: Never
+7 -4
View File
@@ -4,9 +4,12 @@
"dockerfile": "../docker/DockerfileDepsLlvm",
},
"runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"],
"settings": {},
"extensions": [
"ms-vscode.cpptools"
],
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools"
]
}
},
"forwardPorts": [4222],
}
+22
View File
@@ -0,0 +1,22 @@
version: 2
updates:
- package-ecosystem: "docker"
directory: "/docker"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "vcpkg"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "devcontainers"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/rust"
schedule:
interval: "weekly"
+75 -5
View File
@@ -7,6 +7,7 @@ env:
UBUNTU_FULL_DEPS: "libncurses5-dev libreadline-dev nettle-dev libasio-dev libgnutls28-dev libuv1-dev python3-pip python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-dev"
UBUNTU_MESON_DEPS: "ninja-build libncurses5-dev libreadline-dev nettle-dev libasio-dev libgnutls28-dev libuv1-dev python3-dev python3-setuptools python3-pip libcppunit-dev libjsoncpp-dev libfmt-dev libmsgpack-dev libargon2-dev"
UBUNTU_MINIMAL_DEPS: "libncurses5-dev libreadline-dev nettle-dev libfmt-dev libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-dev"
DEBIAN12_DEPS: "git autotools-dev autoconf libtool m4 automake pkg-config wget cmake libncurses5-dev libreadline-dev nettle-dev libasio-dev libgnutls28-dev libuv1-dev python3-pip python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev libfmt-dev libmsgpack-dev libargon2-dev"
on: [push, pull_request]
@@ -15,7 +16,7 @@ jobs:
name: Ubuntu/GCC Autotools build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install Dependencies
run: |
@@ -38,6 +39,15 @@ jobs:
run: |
sudo mkdir -p /usr/local/include/nonstd
sudo wget "${EXPECTED_LITE_URL}" -O /usr/local/include/nonstd/expected.hpp
- name: Install simdutf
run: |
wget https://github.com/simdutf/simdutf/archive/refs/tags/v7.7.0.tar.gz -O simdutf.tar.gz
tar -xzf simdutf.tar.gz
mv simdutf-7.7.0 simdutf
mkdir simdutf/build && cd simdutf/build
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DSIMDUTF_CXX_STANDARD=17 -DSIMDUTF_TOOLS=Off -DSIMDUTF_TESTS=Off .. && make -j2 && sudo make install
cd ../../ && rm -rf simdutf
- name: Build restinio dependency
run: |
@@ -65,7 +75,7 @@ jobs:
name: Ubuntu/GCC Meson build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install Dependencies
run: |
@@ -86,7 +96,7 @@ jobs:
name: Ubuntu/GCC minimal build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install Minimal Dependencies
run: |
@@ -107,13 +117,72 @@ jobs:
run: cd build && make
- name: Run Unit tests
run: cd build && ./opendht_unit_tests
run: ctest --output-on-failure --test-dir build
build-debian12:
name: Debian 12/GCC build
runs-on: ubuntu-latest
container:
image: debian:12
volumes:
- .:/workspace
options: --workdir /workspace
env:
DEBIAN_FRONTEND: noninteractive
steps:
- uses: actions/checkout@v6
- name: Install Dependencies
run: |
apt-get update
apt-get install -y $DEBIAN12_DEPS
- name: Build llhttp dependency
run: |
mkdir llhttp
wget "https://github.com/nodejs/llhttp/archive/refs/tags/release/${LLHTTP_VERSION}.tar.gz" -O llhttp.tar.gz
tar -xzf llhttp.tar.gz -C llhttp --strip-components=1
cd llhttp && cmake -DCMAKE_INSTALL_PREFIX=/usr . && make -j2 && make install
cd ../ && rm -rf llhttp*
- name: Install expected-lite header
run: |
mkdir -p /usr/local/include/nonstd
wget "${EXPECTED_LITE_URL}" -O /usr/local/include/nonstd/expected.hpp
- name: Build restinio dependency
run: |
mkdir restinio && cd restinio
wget "https://github.com/Stiffstream/restinio/releases/download/v${RESTINIO_VERSION}/restinio-${RESTINIO_VERSION}.tar.bz2"
tar -xjf restinio-${RESTINIO_VERSION}.tar.bz2
cd restinio-${RESTINIO_VERSION}/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr/local \
-DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off \
-DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system .
make install
cd ../../ && rm -rf restinio*
- name: Configure project with CMake
run: |
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=On -DBUILD_TESTING=On \
-DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On
- name: Build
run: cd build && make
build-macos:
name: macOS/Clang build
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install Homebrew Dependencies
run: brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl cppunit
@@ -146,6 +215,7 @@ jobs:
export CPPFLAGS="-I/usr/local/opt/openssl@3/include"
export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig"
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
-DOPENDHT_DOWNLOAD_DEPS=ON \
-DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=On -DBUILD_TESTING=On \
-DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off \
+2 -2
View File
@@ -6,7 +6,7 @@ jobs:
name: Clang Static Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: deps
run: |
sudo apt update && \
@@ -37,6 +37,6 @@ jobs:
- name: cmake
run: |
mkdir build && cd build && \
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DOPENDHT_C=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off -DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On -DOPENDHT_PUSH_NOTIFICATIONS=On
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DOPENDHT_C=On -DOPENDHT_DOWNLOAD_DEPS=ON -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off -DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On -DOPENDHT_PUSH_NOTIFICATIONS=On
- name: scan-build
run: cd build && scan-build --status-bugs make
+5 -3
View File
@@ -22,18 +22,20 @@ jobs:
include:
- language: c-cpp
build-mode: autobuild
- language: actions
build-mode: none
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{matrix.language}}"
+108
View File
@@ -0,0 +1,108 @@
name: Python Package
permissions:
contents: read
on:
release:
types: [published]
push:
pull_request:
workflow_dispatch:
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest]
steps:
- uses: actions/checkout@v6
# Run locally with: pipx run cibuildwheel --platform linux python
- name: Build wheels
uses: pypa/cibuildwheel@v3.3.0
with:
package-dir: python
- uses: actions/upload-artifact@v5
with:
name: opendht-wheels-${{ matrix.os }}
path: ./wheelhouse/*.whl
build_wheels_windows:
name: Build wheels on Windows
runs-on: windows-latest
env:
VCPKG_VERSION: "2025.07.25"
VCPKG_INSTALLATION_ROOT: "C:\\vcpkg"
VCPKG_DISABLE_METRICS: "1"
VCPKG_DEFAULT_TRIPLET: x64-windows-release
VCPKG_INSTALLED_DIR: ${{ github.workspace }}\vcpkg_installed
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}\vcpkg_binary_cache
steps:
- uses: actions/checkout@v6
- name: Cache vcpkg installed packages
id: cache-vcpkg
uses: actions/cache@v4
with:
path: |
${{ env.VCPKG_INSTALLED_DIR }}
${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
key: ${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ env.VCPKG_DEFAULT_TRIPLET }}-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}-${{ hashFiles('.github/workflows/windows-build.yml') }}
- name: Setup vcpkg and install dependencies
if: steps.cache-vcpkg.outputs.cache-hit != 'true'
run: |
New-Item -Path "${{ env.VCPKG_INSTALLED_DIR }}" -ItemType Directory -Force
New-Item -Path "${{ env.VCPKG_DEFAULT_BINARY_CACHE }}" -ItemType Directory -Force
vcpkg install `
--recurse `
--clean-after-build `
--triplet=${{ env.VCPKG_DEFAULT_TRIPLET }} `
--x-install-root=${{ env.VCPKG_INSTALLED_DIR }}
shell: pwsh
- name: Build wheels
run: |
pip install cython delvewheel build
cmake -S . -B build `
-DCMAKE_BUILD_TYPE=Release `
-DVCPKG_TARGET_TRIPLET=${{ env.VCPKG_DEFAULT_TRIPLET }} `
-DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_INSTALLATION_ROOT }}\scripts\buildsystems\vcpkg.cmake `
-DVCPKG_INSTALLED_DIR=${{ env.VCPKG_INSTALLED_DIR }} `
-DBUILD_TESTING=OFF `
-DOPENDHT_C=OFF `
-DOPENDHT_TOOLS=OFF `
-DOPENDHT_PYTHON=ON `
-DOPENDHT_DOCUMENTATION=OFF `
-DOPENDHT_PROXY_CLIENT=ON `
-DOPENDHT_PROXY_SERVER=ON
cd build
pipx run cibuildwheel python
shell: pwsh
- uses: actions/upload-artifact@v5
with:
name: opendht-wheels-win_amd64
path: ./build/wheelhouse/*.whl
publish:
runs-on: ubuntu-latest
needs: [build_wheels, build_wheels_windows]
steps:
- uses: actions/download-artifact@v6
with:
pattern: opendht-wheels-*
path: dist
merge-multiple: true
- name: Publish package
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
+139 -52
View File
@@ -25,7 +25,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Log in to the Container registry
uses: docker/login-action@v3
@@ -41,7 +41,7 @@ jobs:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: docker/DockerfileDeps
@@ -58,7 +58,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Log in to the Container registry
uses: docker/login-action@v3
@@ -75,7 +75,7 @@ jobs:
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile
@@ -92,7 +92,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Log in to the Container registry
uses: docker/login-action@v3
@@ -108,7 +108,7 @@ jobs:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: docker/DockerfileDepsLlvm
@@ -125,7 +125,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Log in to the Container registry
uses: docker/login-action@v3
@@ -142,7 +142,7 @@ jobs:
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: docker/DockerfileLlvm
@@ -159,7 +159,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Log in to the Container registry
uses: docker/login-action@v3
@@ -176,7 +176,7 @@ jobs:
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DHTNODE }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: docker/DockerfileDhtnode
@@ -193,7 +193,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Log in to the Container registry
uses: docker/login-action@v3
@@ -210,7 +210,7 @@ jobs:
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_ALPINE_DEPS }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: docker/DockerfileDepsAlpine
@@ -227,7 +227,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Log in to the Container registry
uses: docker/login-action@v3
@@ -244,7 +244,7 @@ jobs:
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_ALPINE }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: docker/DockerfileAlpine
@@ -256,20 +256,50 @@ jobs:
name: Build Windows MSI Installer
runs-on: windows-latest
env:
VCPKG_VERSION: "2025.04.09"
VCPKG_VERSION: "2025.07.25"
VCPKG_INSTALLATION_ROOT: "C:\\vcpkg"
VCPKG_DISABLE_METRICS: "1"
VCPKG_DEFAULT_TRIPLET: x64-windows
VCPKG_ROOT: "C:\\vcpkg"
VCPKG_INSTALLED_DIR: ${{ github.workspace }}\vcpkg_installed
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}\vcpkg_binary_cache
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
submodules: recursive
- name: Set up MSVC developer environment
uses: microsoft/setup-msbuild@v2
- name: Install WIX using .net tools
run: |
dotnet tool install --global wix --version 6.0.1
wix extension add --global WixToolset.UI.wixext/6.0.1
shell: pwsh
- name: Cache vcpkg installed packages
id: cache-vcpkg
uses: actions/cache@v4
with:
path: |
${{ env.VCPKG_INSTALLED_DIR }}
${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
key: ${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-x64-shared-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}-${{ hashFiles('.github/workflows/windows-build.yml') }}
- name: Setup vcpkg and install dependencies
if: steps.cache-vcpkg.outputs.cache-hit != 'true'
run: |
New-Item -Path "${{ env.VCPKG_INSTALLED_DIR }}" -ItemType Directory -Force
New-Item -Path "${{ env.VCPKG_DEFAULT_BINARY_CACHE }}" -ItemType Directory -Force
vcpkg install `
--recurse `
--clean-after-build `
--triplet=x64-windows `
--x-install-root=${{ env.VCPKG_INSTALLED_DIR }} `
--x-feature=test
shell: pwsh
- name: Configure CMake for MSI
shell: pwsh
@@ -277,22 +307,30 @@ jobs:
mkdir build -ErrorAction SilentlyContinue
cmake -B build `
-S . `
-DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake `
-DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_INSTALLATION_ROOT }}/scripts/buildsystems/vcpkg.cmake `
-DVCPKG_TARGET_TRIPLET=x64-windows `
-DVCPKG_INSTALLED_DIR=${{ env.VCPKG_INSTALLED_DIR }} `
-DVCPKG_MANIFEST_FEATURES=test `
-DCMAKE_BUILD_TYPE=Release `
-DOPENDHT_C=On `
-DOPENDHT_TOOLS=On `
-DOPENDHT_PYTHON=Off `
-DOPENDHT_DOCUMENTATION=OFF `
-DOPENDHT_PEER_DISCOVERY=On `
-DOPENDHT_PROXY_SERVER=On `
-DOPENDHT_PROXY_CLIENT=On `
-DOPENDHT_HTTP=On `
-DBUILD_TESTING=Off `
-DOPENDHT_CPACK=On `
-A x64
- name: Build with MSVC
shell: pwsh
run: |
cmake --build build --config Release --parallel $([System.Environment]::ProcessorCount)
# Copy vcpkg installed libraries to the build directory
Copy-Item -Path "${{ env.VCPKG_INSTALLED_DIR }}\x64-windows\lib\*.lib" -Destination "build" -Force
Copy-Item -Path "${{ env.VCPKG_INSTALLED_DIR }}\x64-windows\bin\*.dll" -Destination "build" -Force
- name: Package MSI with CPack
shell: pwsh
@@ -312,66 +350,115 @@ jobs:
}
- name: Upload MSI Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: opendht-windows-msi
path: build/${{ steps.cpack_msi.outputs.msi_path }} # Path to the MSI in the build directory
retention-days: 7
build-python-wheels:
name: Build Python Wheels
runs-on: ubuntu-latest
container: ghcr.io/savoirfairelinux/opendht/opendht-deps:latest
build-windows-dhtnode:
name: Build Windows dhtnode
runs-on: windows-latest
env:
VCPKG_VERSION: "2025.07.25"
VCPKG_INSTALLATION_ROOT: "C:\\vcpkg"
VCPKG_DISABLE_METRICS: "1"
VCPKG_DEFAULT_TRIPLET: x64-windows-static-release
VCPKG_INSTALLED_DIR: ${{ github.workspace }}\vcpkg_installed
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}\vcpkg_binary_cache
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: cmake (for Python wheel)
run: |
mkdir build_python && cd build_python && \
cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DOPENDHT_STATIC=Off \
-DOPENDHT_PYTHON=On \
-DOPENDHT_C=Off \
-DOPENDHT_PEER_DISCOVERY=On \
-DOPENDHT_TOOLS=Off \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On
- name: build (for Python wheel)
run: cd build_python && make dist
- uses: actions/upload-artifact@v4
uses: actions/checkout@v6
with:
name: opendht-wheels-linux
path: build_python/python/dist/*.whl
submodules: recursive
- name: Set up MSVC developer environment
uses: microsoft/setup-msbuild@v2
- name: Cache vcpkg static installed packages
id: cache-vcpkg-static
uses: actions/cache@v4
with:
path: |
${{ env.VCPKG_INSTALLED_DIR }}
${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
key: ${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-x64-static-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}-${{ hashFiles('.github/workflows/windows-build.yml') }}
restore-keys: |
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-x64-static-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-x64-static-
- name: Setup vcpkg and install static dependencies
if: steps.cache-vcpkg-static.outputs.cache-hit != 'true'
shell: pwsh
run: |
New-Item -Path "${{ env.VCPKG_INSTALLED_DIR }}" -ItemType Directory -Force
New-Item -Path "${{ env.VCPKG_DEFAULT_BINARY_CACHE }}" -ItemType Directory -Force
vcpkg install `
--recurse `
--clean-after-build `
--triplet=x64-windows-static-release `
--x-install-root=${{ env.VCPKG_INSTALLED_DIR }} `
--x-feature=test
- name: Configure CMake for Static Build
shell: pwsh
run: |
mkdir build_static -ErrorAction SilentlyContinue
cmake -B build_static `
-S . `
-DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_INSTALLATION_ROOT }}/scripts/buildsystems/vcpkg.cmake `
-DVCPKG_TARGET_TRIPLET=x64-windows-static-release `
-DVCPKG_INSTALLED_DIR=${{ env.VCPKG_INSTALLED_DIR }} `
-DVCPKG_MANIFEST_FEATURES=test `
-DCMAKE_BUILD_TYPE=Release `
-DBUILD_SHARED_LIBS=OFF `
-DOPENDHT_PROXY_CLIENT=ON `
-DOPENDHT_PROXY_SERVER=ON `
-DOPENDHT_C=ON `
-DOPENDHT_TOOLS=ON `
-DOPENDHT_DOCUMENTATION=OFF `
-DOPENDHT_PYTHON=OFF `
-DOPENDHT_PEER_DISCOVERY=ON `
-DOPENDHT_HTTP=ON `
-A x64
- name: Build Static dhtnode
shell: pwsh
run: |
cmake --build build_static --config Release --parallel $([System.Environment]::ProcessorCount)
- name: Upload Static dhtnode Artifact
uses: actions/upload-artifact@v5
with:
name: opendht-windows-dhtnode
path: |
build_static/**/*dhtnode.exe
retention-days: 7
create-github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [build-windows-msi, build-python-wheels]
needs: [build-windows-msi, build-windows-dhtnode]
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Download Windows MSI artifact
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: opendht-windows-msi
path: downloaded_artifacts/windows_msi
- name: Download Linux Wheels artifact
uses: actions/download-artifact@v4
- name: Download Static dhtnode artifact
uses: actions/download-artifact@v6
with:
name: opendht-wheels-linux
path: downloaded_artifacts/linux_wheels
name: opendht-windows-dhtnode
path: downloaded_artifacts/static_dhtnode
- name: Create Release
id: create_release
@@ -379,5 +466,5 @@ jobs:
with:
draft: true
files: |
downloaded_artifacts/linux_wheels/*.whl
downloaded_artifacts/windows_msi/*.msi
downloaded_artifacts/static_dhtnode/**/*dhtnode.exe
+143 -13
View File
@@ -1,4 +1,6 @@
name: Windows Build
permissions:
contents: read
on:
push:
@@ -7,10 +9,11 @@ on:
branches: [ main, master ]
env:
VCPKG_VERSION: "2025.04.09"
VCPKG_VERSION: "2025.07.25"
VCPKG_INSTALLATION_ROOT: "C:\\vcpkg"
VCPKG_DISABLE_METRICS: "1"
VCPKG_INSTALLED_DIR: ${{ github.workspace }}\vcpkg_installed
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}\vcpkg_binary_cache
jobs:
prepare-dependencies:
@@ -24,7 +27,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up MSVC
uses: microsoft/setup-msbuild@v2
@@ -33,22 +36,26 @@ jobs:
id: generate_cache_key
shell: pwsh
run: |
$key_value = "${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}-${{ hashFiles('.github/workflow/windows-build.yml') }}"
$key_value = "${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-shared-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}-${{ hashFiles('.github/workflows/windows-build.yml') }}"
echo "key=$key_value" >> $env:GITHUB_OUTPUT
- name: Cache vcpkg installed packages
id: cache-vcpkg
uses: actions/cache@v4
with:
path: ${{ env.VCPKG_INSTALLED_DIR }}
path: |
${{ env.VCPKG_INSTALLED_DIR }}
${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
key: ${{ steps.generate_cache_key.outputs.key }}
restore-keys: |
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-shared-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-shared-
- name: Setup vcpkg and install dependencies
if: steps.cache-vcpkg.outputs.cache-hit != 'true'
run: |
New-Item -Path "${{ env.VCPKG_INSTALLED_DIR }}" -ItemType Directory -Force
New-Item -Path "${{ env.VCPKG_DEFAULT_BINARY_CACHE }}" -ItemType Directory -Force
vcpkg install `
--recurse `
--clean-after-build `
@@ -57,6 +64,54 @@ jobs:
--x-feature=test
shell: pwsh
prepare-static-dependencies:
name: Prepare Windows Static Dependencies
runs-on: windows-latest
outputs:
vcpkg_static_cache_key: ${{ steps.generate_static_cache_key.outputs.key }}
strategy:
matrix:
arch: [x64]
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up MSVC
uses: microsoft/setup-msbuild@v2
- name: Generate Cache Key for Static Libs
id: generate_static_cache_key
shell: pwsh
run: |
$key_value = "${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-static-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}-${{ hashFiles('.github/workflows/windows-build.yml') }}"
echo "key=$key_value" >> $env:GITHUB_OUTPUT
- name: Cache vcpkg static installed packages
id: cache-vcpkg-static
uses: actions/cache@v4
with:
path: |
${{ env.VCPKG_INSTALLED_DIR }}
${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
key: ${{ steps.generate_static_cache_key.outputs.key }}
restore-keys: |
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-static-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-static-
- name: Setup vcpkg and install static dependencies
if: steps.cache-vcpkg-static.outputs.cache-hit != 'true'
shell: pwsh
run: |
New-Item -Path "${{ env.VCPKG_INSTALLED_DIR }}" -ItemType Directory -Force
New-Item -Path "${{ env.VCPKG_DEFAULT_BINARY_CACHE }}" -ItemType Directory -Force
vcpkg install `
--recurse `
--clean-after-build `
--triplet=${{ matrix.arch }}-windows-static-release `
--x-install-root=${{ env.VCPKG_INSTALLED_DIR }} `
--x-feature=test
build-windows:
name: Windows MSVC Build
runs-on: windows-latest
@@ -69,7 +124,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up MSVC
uses: microsoft/setup-msbuild@v2
@@ -78,11 +133,13 @@ jobs:
id: cache-vcpkg-restore
uses: actions/cache/restore@v4
with:
path: ${{ env.VCPKG_INSTALLED_DIR }}
path: |
${{ env.VCPKG_INSTALLED_DIR }}
${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
key: ${{ needs.prepare-dependencies.outputs.vcpkg_cache_key }}
restore-keys: |
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-shared-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-shared-
- name: Configure CMake
shell: pwsh
@@ -101,6 +158,7 @@ jobs:
-DOPENDHT_C=ON `
-DOPENDHT_TOOLS=ON `
-DOPENDHT_PYTHON=OFF `
-DOPENDHT_DOCUMENTATION=OFF `
-DOPENDHT_PEER_DISCOVERY=ON `
-DOPENDHT_HTTP=ON `
-A ${{ matrix.arch }}
@@ -120,7 +178,7 @@ jobs:
- name: Upload build artifacts
if: matrix.build_type == 'Release'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: opendht-windows-${{ matrix.arch }}-${{ matrix.build_type }}
path: |
@@ -129,6 +187,77 @@ jobs:
build/**/*.lib
retention-days: 7
build-windows-static:
name: Windows Static MSVC Build
runs-on: windows-latest
needs: prepare-static-dependencies
strategy:
matrix:
build_type: [Release]
arch: [x64]
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up MSVC
uses: microsoft/setup-msbuild@v2
- name: Restore vcpkg static installed packages
id: cache-vcpkg-static-restore
uses: actions/cache/restore@v4
with:
path: |
${{ env.VCPKG_INSTALLED_DIR }}
${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
key: ${{ needs.prepare-static-dependencies.outputs.vcpkg_static_cache_key }}
restore-keys: |
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-static-${{ hashFiles('**/vcpkg.json', '**/vcpkg-configuration.json') }}
${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.arch }}-static-
- name: Configure CMake for Static Build
shell: pwsh
run: |
mkdir build -ErrorAction SilentlyContinue
cmake -B build `
-S . `
-DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_INSTALLATION_ROOT }}/scripts/buildsystems/vcpkg.cmake `
-DVCPKG_TARGET_TRIPLET=${{ matrix.arch }}-windows-static-release `
-DVCPKG_INSTALLED_DIR=${{ env.VCPKG_INSTALLED_DIR }} `
-DVCPKG_MANIFEST_FEATURES=test `
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} `
-DBUILD_SHARED_LIBS=OFF `
-DBUILD_TESTING=ON `
-DOPENDHT_PROXY_CLIENT=ON `
-DOPENDHT_PROXY_SERVER=ON `
-DOPENDHT_C=ON `
-DOPENDHT_TOOLS=ON `
-DOPENDHT_PYTHON=OFF `
-DOPENDHT_DOCUMENTATION=OFF `
-DOPENDHT_PEER_DISCOVERY=ON `
-DOPENDHT_HTTP=ON `
-A ${{ matrix.arch }}
- name: Build Static
shell: pwsh
run: |
cmake --build build --config ${{ matrix.build_type }} --parallel 4
- name: Test Static Build
shell: pwsh
run: |
cd build
ctest --build-config ${{ matrix.build_type }} --output-on-failure --parallel 4
- name: Upload static build artifacts
uses: actions/upload-artifact@v5
with:
name: opendht-windows-static-${{ matrix.arch }}-${{ matrix.build_type }}
path: |
build/**/*.exe
build/**/*.lib
retention-days: 7
build-windows-mingw:
name: Windows MinGW Build
runs-on: windows-latest
@@ -140,7 +269,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup MinGW
uses: msys2/setup-msys2@v2
@@ -227,6 +356,7 @@ jobs:
-DOPENDHT_C=ON \
-DOPENDHT_TOOLS=ON \
-DOPENDHT_PYTHON=OFF \
-DOPENDHT_DOCUMENTATION=OFF \
-DOPENDHT_PEER_DISCOVERY=ON \
-DOPENDHT_HTTP=ON
cmake --build . --parallel 4
@@ -239,7 +369,7 @@ jobs:
- name: Upload MinGW artifacts
if: matrix.build_type == 'Release'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: opendht-windows-mingw-${{ matrix.build_type }}
path: |
+8 -3
View File
@@ -45,9 +45,11 @@ Makefile.in
*~
*.pc
# KDevelop
.kdev4/
*.kdev4
# CMake
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
*ConfigVersion.cmake
# VSCode
.vscode/*
@@ -67,6 +69,9 @@ language.settings.xml
*.stamp
python/opendht.cpp
python/setup.py
python/dist/
wheelhouse/
*.egg-info/
# Doxygen
doc/Doxyfile
+10
View File
@@ -0,0 +1,10 @@
{
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
"C_Cpp.default.cppStandard": "c++17",
"C_Cpp.default.cStandard": "c11",
"C_Cpp.autoAddFileAssociations": false,
"cmake.configureOnOpen": false,
"cmake.configureOnEdit": false,
"editor.formatOnSave": true,
"files.eol": "\n",
}
+124
View File
@@ -0,0 +1,124 @@
# Build the library
The build is currently tested on GNU/Linux, macOS, and Windows.
## Unix-like systems (Linux, macOS, MSYS2/MinGW, etc.)
## Install dependencies
### Debian 13
```sh
# Install dependencies
sudo apt install pkg-config libncurses5-dev libreadline-dev nettle-dev libgnutls28-dev libargon2-dev libmsgpack-dev libssl-dev libfmt-dev libjsoncpp-dev libhttp-parser-dev libasio-dev libmsgpack-cxx-dev
# Install Python binding dependencies
sudo apt-get install cython3 python3-dev python3-setuptools python3-build
```
Optionally, install RESTinio to enable the OpenDHT proxy client and server:
```sh
mkdir /usr/include/nonstd
wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp -O /usr/include/nonstd/expected.hpp
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2
tar -xjf restinio-0.7.3.tar.bz2
cd restinio-0.7.3/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off -DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system -DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system .
make -j2 && make install
```
To run openDHT on a different computer from the build computer, the following runtime dependencies are required:
```sh
sudo apt install libargon2-1 libjsoncpp26
```
### Ubuntu 24.04 and Debian 12
```sh
# Install dependencies
sudo apt install pkg-config libncurses5-dev libreadline-dev nettle-dev libgnutls28-dev libargon2-0-dev libmsgpack-dev libssl-dev libfmt-dev libjsoncpp-dev libhttp-parser-dev libasio-dev
# Install Python binding dependencies
sudo apt-get install cython3 python3-dev python3-setuptools python3-build
```
Optionally, install RESTinio to enable the OpenDHT proxy client and server:
```sh
mkdir /usr/include/nonstd
wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp -O /usr/include/nonstd/expected.hpp
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2
tar -xjf restinio-0.7.3.tar.bz2
cd restinio-0.7.3/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off -DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system -DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system .
make -j2 && make install
```
### Fedora
```sh
# Install GnuTLS, Readline and msgpack-c
sudo dnf install readline-devel gnutls-devel msgpack-devel asio-devel libargon2-devel fmt-devel
# Install python binding dependencies
sudo dnf install python3-Cython python3-devel redhat-rpm-config
```
### macOS
```sh
brew install gnutls msgpack-cxx argon2 asio readline jsoncpp fmt
```
## Build
Using CMake:
```sh
# Clone the repository
git clone https://github.com/savoirfairelinux/opendht.git
# Build and install
cd opendht
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make -j$(nproc)
sudo make install
```
#### Example Configurations
Minimal build (libraries only):
```sh
cmake -DOPENDHT_TOOLS=OFF ..
```
Full-featured build with proxy support, Python, and C bindings:
```sh
cmake -DOPENDHT_PYTHON=ON \
-DOPENDHT_C=ON \
-DOPENDHT_PROXY_SERVER=ON \
-DOPENDHT_PROXY_SERVER_IDENTITY=ON \
-DOPENDHT_PROXY_CLIENT=ON \
-DOPENDHT_PUSH_NOTIFICATIONS=ON \
-DCMAKE_INSTALL_PREFIX=/usr ..
```
## Windows/MSVC
Building on Windows with MSVC is supported with VCPKG and CMake.
### Build with VCPKG in manifest mode
1. Install [VCPKG](https://github.com/microsoft/vcpkg) and required dependencies:
```ps1
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg; .\bootstrap-vcpkg.bat
```
2. Use CMake preset for vcpkg:
```ps1
cd opendht
cmake --preset=vcpkg_manifest .
cmake --build .
```
+528 -312
View File
File diff suppressed because it is too large. Load diff
+104 -19
View File
@@ -12,7 +12,34 @@
"generator": "Unix Makefiles",
"inherits": "default",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
"CMAKE_EXPORT_COMPILE_COMMANDS": true
}
},
{
"name": "unix-make-full",
"description": "Unix Makefiles (Full build)",
"inherits": "unix-make",
"cacheVariables": {
"OPENDHT_C": true,
"OPENDHT_PROXY_CLIENT": true,
"OPENDHT_PROXY_SERVER": true,
"OPENDHT_PUSH_NOTIFICATIONS": true,
"OPENDHT_PYTHON": true,
"OPENDHT_INDEX": true,
"BUILD_TESTING": true,
"OPENDHT_EXAMPLES": true
}
},
{
"name": "unix-make-release",
"description": "Unix Makefiles (Release build)",
"inherits": "unix-make-full",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"BUILD_SHARED_LIBS": true,
"BUILD_TESTING": false,
"OPENDHT_SANITIZE": false,
"OPENDHT_EXAMPLES": false
}
},
{
@@ -20,14 +47,27 @@
"generator": "Ninja",
"inherits": "default",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
"CMAKE_EXPORT_COMPILE_COMMANDS": true
}
},
{
"name": "ninja-release",
"inherits": "ninja",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"BUILD_SHARED_LIBS": true,
"BUILD_TESTING": false,
"OPENDHT_SANITIZE": false,
"OPENDHT_CPACK": true,
"OPENDHT_C": true,
"OPENDHT_PROXY_CLIENT": true,
"OPENDHT_PROXY_SERVER": true
}
},
{
"name": "msvc",
"generator": "Visual Studio 17 2022",
"inherits": "default",
"binaryDir": "${sourceDir}/build-vs",
"cacheVariables": {
"BUILD_TESTING": true,
"VCPKG_MANIFEST_FEATURES": "test",
@@ -41,17 +81,25 @@
"inherits": "msvc",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"BUILD_SHARED_LIBS": "On",
"BUILD_SHARED_LIBS": true,
"CMAKE_BUILD_TYPE": "Debug",
"VCPKG_MANIFEST_MODE": true
}
},
{
"name": "vcpkg_manifest_static",
"inherits": "vcpkg_manifest",
"cacheVariables": {
"BUILD_SHARED_LIBS": false,
"VCPKG_TARGET_TRIPLET": "x64-windows-static"
}
},
{
"name": "vcpkg_local",
"inherits": "msvc",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"BUILD_SHARED_LIBS": "On",
"BUILD_SHARED_LIBS": true,
"CMAKE_BUILD_TYPE": "Debug",
"BUILD_TESTING": true,
"VCPKG_MANIFEST_MODE": false
@@ -71,25 +119,23 @@
},
{
"name": "vcpkg_release_full",
"inherits": "vcpkg_manifest",
"inherits": "vcpkg_release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"VCPKG_TARGET_TRIPLET": "x64-windows-release",
"VCPKG_OVERLAY_TRIPLETS": "x64-windows-release;x64-windows-rel;x64-windows",
"BUILD_TESTING": false,
"OPENDHT_PROXY_CLIENT": true,
"OPENDHT_PROXY_SERVER": true,
"OPENDHT_CPACK": true
"OPENDHT_C": true,
"OPENDHT_PYTHON": true,
"OPENDHT_CPACK": true,
"OPENDHT_DOCUMENTATION": false
}
},
{
"name": "vcpkg_release_static",
"inherits": "vcpkg_manifest",
"inherits": "vcpkg_manifest_static",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"BUILD_SHARED_LIBS": "Off",
"VCPKG_TARGET_TRIPLET": "x64-windows-static-release",
"VCPKG_OVERLAY_TRIPLETS": "x64-windows-static-release;x64-windows-static-rel;x64-windows-static",
"BUILD_TESTING": false,
"OPENDHT_CPACK": true,
"OPENDHT_C": false
@@ -97,16 +143,16 @@
},
{
"name": "vcpkg_release_static_full",
"inherits": "vcpkg_manifest",
"inherits": "vcpkg_manifest_static",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"BUILD_SHARED_LIBS": "Off",
"VCPKG_TARGET_TRIPLET": "x64-windows-static-release",
"VCPKG_OVERLAY_TRIPLETS": "x64-windows-static-release;x64-windows-static-rel;x64-windows-static",
"BUILD_TESTING": false,
"OPENDHT_PROXY_CLIENT": true,
"OPENDHT_PROXY_SERVER": true,
"OPENDHT_CPACK": true
"OPENDHT_C": true,
"OPENDHT_CPACK": true,
"OPENDHT_DOCUMENTATION": false
}
},
{
@@ -139,7 +185,7 @@
"inherits": "vcpkg_local",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"BUILD_SHARED_LIBS": "Off",
"BUILD_SHARED_LIBS": false,
"VCPKG_TARGET_TRIPLET": "x64-windows-static-release",
"VCPKG_OVERLAY_TRIPLETS": "x64-windows-static-release;x64-windows-static-rel;x64-windows-static",
"BUILD_TESTING": false,
@@ -152,7 +198,7 @@
"inherits": "vcpkg_local",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"BUILD_SHARED_LIBS": "Off",
"BUILD_SHARED_LIBS": false,
"VCPKG_TARGET_TRIPLET": "x64-windows-static-release",
"VCPKG_OVERLAY_TRIPLETS": "x64-windows-static-release;x64-windows-static-rel;x64-windows-static",
"BUILD_TESTING": false,
@@ -161,5 +207,44 @@
"OPENDHT_CPACK": true
}
}
],
"buildPresets": [
{
"name": "default",
"configurePreset": "default",
"hidden": true
},
{
"name": "unix-make",
"inherits": "default",
"configurePreset": "unix-make"
},
{
"name": "ninja",
"inherits": "default",
"configurePreset": "ninja"
},
{
"name": "msvc",
"inherits": "default",
"configurePreset": "msvc"
},
{
"name": "vcpkg-dev",
"inherits": "default",
"configurePreset": "vcpkg_manifest"
},
{
"name": "vcpkg-release-static",
"inherits": "default",
"configurePreset": "vcpkg_release_static_full",
"configuration": "Release"
},
{
"name": "vcpkg-release",
"inherits": "default",
"configurePreset": "vcpkg_release_full",
"configuration": "Release"
}
]
}
+53 -7
View File
@@ -4,6 +4,8 @@
<a id="user-content-opendht-" class="anchor" href="/savoirfairelinux/opendht/blob/master/README.md#opendht-" aria-hidden="true"></a>OpenDHT
</h1>
![PyPI - Version](https://img.shields.io/pypi/v/opendht?style=flat)
A lightweight C++17 Distributed Hash Table implementation.
OpenDHT provides an easy to use distributed in-memory data store.
@@ -23,12 +25,12 @@ See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
#### How to run a node
You can help contributing to the public network by running a stable node with a public IP address.
You can help contribute to the public network by running a stable node with a public IP address.
https://github.com/savoirfairelinux/opendht/wiki/Running-a-node-with-dhtnode
#### How-to build and install
Build instructions: <https://github.com/savoirfairelinux/opendht/wiki/Build-the-library>
Build instructions: see [BUILD.md](BUILD.md)
## Examples
### C++ example
@@ -73,14 +75,22 @@ int main()
return 0;
}
```
### Python 3 example
Install on Linux, macOS and Windows with:
```sh
pip install opendht
```
Using the simple, blocking API:
```python
import opendht as dht
node = dht.DhtRunner()
node.run()
# Join the network through any running node,
# Join the DHT network through any running node,
# here using a known bootstrap node.
node.bootstrap("bootstrap.jami.net", "4222")
@@ -88,8 +98,45 @@ node.bootstrap("bootstrap.jami.net", "4222")
node.put(dht.InfoHash.get("unique_key"), dht.Value(b'some binary data'))
results = node.get(dht.InfoHash.get("unique_key"))
for r in results:
print(r)
for value in results:
print(value)
```
Or using asyncio:
```python
import asyncio
import opendht.aio as dht
async def dht_async_demo(key_str: str):
# Start a new node using an async context manager.
# It is also possible to call run()/await shutdown() manually.
async with dht.DhtRunner(
bootstrap=(("bootstrap.jami.net", "4222"),)
) as node:
# compute key hash
key = dht.InfoHash.get(key_str)
# put data, waiting for completion
await node.put(key, dht.Value(b'tata data'))
# get all values at key
results = await node.getAll(key)
for value in results:
print(value)
# same operation, but stream values as they come from the network
with node.get(key) as results:
async for value in results:
print(value)
# listen for change of values at key
with node.listen(key) as values:
async for value, expired in values:
print(value)
if value.data == b'tata data':
break
asyncio.run(dht_async_demo("unique_key"))
```
## Dependencies
@@ -100,7 +147,7 @@ for r in results:
- (optional) restinio used for the REST API.
- (optional) llhttp used for the REST API.
- (optional) jsoncpp 1.7.4-3+, used for the REST API.
- Build tested with GCC 7+ (GNU/Linux, Windows with MinGW), Clang/LLVM (GNU/Linux, Android, macOS, iOS).
- Build tested with GCC 9+ (GNU/Linux, Windows with MinGW), Clang/LLVM (GNU/Linux, Android, macOS, iOS).
- Build tested with Microsoft Visual Studio 2019, 2022
## Contact
@@ -118,4 +165,3 @@ See COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html for the full GPLv3 l
## Acknowledgements
This project was originally based on https://github.com/jech/dht by Juliusz Chroboczek.
It is independent from another (now extinct) project called OpenDHT (Sean Rhea. Ph.D. Thesis, 2005).
+9
View File
@@ -268,6 +268,11 @@ dht_publickey* dht_certificate_get_publickey(const dht_certificate* c) {
return reinterpret_cast<dht_publickey*>(new PubkeySp(cert->getSharedPublicKey()));
}
#ifdef __cplusplus
} // extern "C"
// Function with internal C++ linkage
#endif
// dht::crypto::Identity
inline dht::crypto::Identity dht_identity_from_c(const dht_identity* cid) {
dht::crypto::Identity id {};
@@ -285,6 +290,10 @@ inline dht_identity dht_identity_to_c(const dht::crypto::Identity& id) {
return cid;
}
#ifdef __cplusplus
extern "C" {
#endif
OPENDHT_C_PUBLIC dht_identity dht_identity_generate(const char* common_name, const dht_identity* ca) {
return dht_identity_to_c(dht::crypto::generateIdentity(common_name, dht_identity_from_c(ca)));
}
+3 -3
View File
@@ -135,7 +135,7 @@ typedef struct dht_op_token dht_op_token;
OPENDHT_C_PUBLIC void dht_op_token_delete(dht_op_token* token);
// config
struct OPENDHT_PUBLIC dht_node_config {
struct OPENDHT_C_PUBLIC dht_node_config {
dht_infohash node_id;
uint32_t network;
bool is_bootstrap;
@@ -144,13 +144,13 @@ struct OPENDHT_PUBLIC dht_node_config {
};
typedef struct dht_node_config dht_node_config;
struct OPENDHT_PUBLIC dht_secure_config {
struct OPENDHT_C_PUBLIC dht_secure_config {
dht_node_config node_config;
dht_identity id;
};
typedef struct dht_secure_config dht_secure_config;
struct OPENDHT_PUBLIC dht_runner_config {
struct OPENDHT_C_PUBLIC dht_runner_config {
dht_secure_config dht_config;
bool threaded;
const char* proxy_server;
+3 -3
View File
@@ -57,7 +57,7 @@ elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
message(FATAL_ERROR "Host compiler must support std::atomic!")
endif()
else()
#message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
#message(FATAL_ERROR "Host compiler appears to require libatomic, but unable to find it.")
endif()
endif()
endif()
@@ -78,7 +78,7 @@ elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
endif()
else()
#message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.")
#message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but unable to find it.")
endif()
endif()
endif()
@@ -123,4 +123,4 @@ int main() {
if( NOT LLVM_HAS_ATOMICS )
message(STATUS "Warning: LLVM will be built thread-unsafe because atomic builtins are missing")
endif()
endif()
+21
View File
@@ -0,0 +1,21 @@
# Windows utility functions and macros
# Determine Windows NT version for compatibility
# https://stackoverflow.com/a/40217291/9560245
macro(get_WIN32_WINNT version)
if(CMAKE_SYSTEM_VERSION)
set(ver ${CMAKE_SYSTEM_VERSION})
string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver})
string(REGEX MATCH "^([0-9]+)" verMajor ${ver})
# Check for Windows 10, b/c we'll need to convert to hex 'A'.
if("${verMajor}" MATCHES "10")
set(verMajor "A")
string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver})
endif()
# Remove all remaining '.' characters.
string(REPLACE "." "" ver ${ver})
# Prepend each digit with a zero.
string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver})
set(${version} "0x${ver}")
endif()
endmacro()
+37 -22
View File
@@ -1,11 +1,12 @@
dnl define macros
m4_define([opendht_major_version], 3)
m4_define([opendht_minor_version], 4)
m4_define([opendht_minor_version], 6)
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_MSG_WARN([The Autotools build system for OpenDHT is deprecated and will be removed in a future release. Please use CMake or Meson instead.])
AC_CONFIG_AUX_DIR(ac)
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_CONFIG_HEADERS([config.h])
@@ -56,21 +57,25 @@ dnl Check for Doxygen
AC_ARG_ENABLE([doc], AS_HELP_STRING([--enable-doc], [Enable documentation generation (doxygen)]))
AS_IF([test "x$enable_doc" = "xyes"], [
AC_CHECK_PROGS([DOXYGEN], [doxygen])
AS_IF([test -z "$DOXYGEN"], [AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])])
AS_IF([test -z "$DOXYGEN"],
[AC_MSG_ERROR([Doxygen is required to generate the documentation.])])
])
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
dnl Check for Python
AC_ARG_ENABLE([python], [AS_HELP_STRING([--disable-python], [Disble python binding])])
AS_IF([test "x$enable_python" != "xno"], [
AM_PATH_PYTHON([3.3],, [:])
AS_IF([test -n "$PYTHON"],[
echo 'import Cython' | $PYTHON
AS_IF([test $? == 0],[CYTHON=yes],[AC_MSG_WARN([Cython not found - continuing without python support])])
AC_CHECK_PROGS([PIP], [pip3])
AS_IF([test -z "$PIP"],[AC_MSG_WARN([pip not found - continuing without python uninstall support])])
])
])
AC_ARG_ENABLE([python], [AS_HELP_STRING([--disable-python], [Disable python binding])])
AS_IF([test "x$enable_python" = "xyes"], [
AM_COND_IF([ENABLE_INDEXATION], [
AM_PATH_PYTHON([3.3],, [:])
AS_IF([test -n "$PYTHON"],[
echo 'import Cython' | $PYTHON
AS_IF([test $? == 0],
[CYTHON=yes],
[AC_MSG_ERROR([Cython not found, but required for Python support.])])
AC_CHECK_PROGS([PIP], [pip3])
AS_IF([test -z "$PIP"],
[AC_MSG_WARN([pip not found - continuing without python uninstall support])])])
], [AC_MSG_ERROR([Python support requires DHT indexation to be turned on.])])])
AM_CONDITIONAL([USE_CYTHON], [test -n "$CYTHON"])
AM_CONDITIONAL([HAVE_PIP], [test -n "$PIP"])
@@ -83,6 +88,7 @@ case "${host_os}" in
;;
linux*)
SYS=linux
CPPFLAGS="$CPPFLAGS -D_POSIX_C_SOURCE=200809L"
;;
darwin*)
SYS=darwin
@@ -136,25 +142,27 @@ AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes || test x$pro
PKG_CHECK_MODULES([Nettle], [nettle >= 2.4])
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3])
AC_CHECK_HEADERS([msgpack.hpp], [], [
PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2])
PKG_CHECK_MODULES([MsgPack], [msgpack-cxx >= 1.2])
])
PKG_CHECK_MODULES([Argon2], [libargon2])
AC_SUBST(argon2_lib, [", libargon2"])
AC_ARG_WITH([jsoncpp], AS_HELP_STRING([--without-jsoncpp], [Build without JsonCpp support]))
AS_IF([test "x$with_jsoncpp" != "xno"],
[PKG_CHECK_MODULES([JsonCpp], [jsoncpp >= 1.7.2], [have_jsoncpp=yes], [have_jsoncpp=no])],
[PKG_CHECK_MODULES([JsonCpp], [jsoncpp >= 1.7.2], [have_jsoncpp=yes], [have_jsoncpp=no])
PKG_CHECK_MODULES([simdutf], [simdutf >= 6], [have_simdutf=yes], [have_simdutf=no])],
[have_jsoncpp=no])
AS_IF([test "x$have_jsoncpp" = "xyes"], [
AC_MSG_NOTICE([Using JsonCpp])
CPPFLAGS="${CPPFLAGS} -DOPENDHT_JSONCPP"
AC_SUBST(jsoncpp_lib, [", jsoncpp"])
AC_SUBST(simdutf_lib, [", simdutf"])
], [
AC_MSG_NOTICE([Not using JsonCpp])
AM_COND_IF(PROXY_CLIENT_OR_SERVER, AC_MSG_ERROR(["JsonCpp is required for proxy/push notification support"]))
])
AC_ARG_WITH([openssl], AS_HELP_STRING([--without-openssl], [Build with OpenSSL support]))
AC_ARG_WITH([openssl], AS_HELP_STRING([--without-openssl], [Build without OpenSSL support]))
AS_IF([test "x$with_openssl" != "xno"],
[PKG_CHECK_MODULES([OpenSSL], [openssl >= 1.1], [have_openssl=yes], [have_openssl=no])],
[have_openssl=no])
@@ -175,20 +183,26 @@ AS_IF([test "x$have_fmt" = "xyes"], [
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
AC_CHECK_HEADERS([asio.hpp],, AC_MSG_ERROR([Missing Asio headers files]))
CXXFLAGS="${CXXFLAGS} -DASIO_STANDALONE"
# llhttp has no pkgconfig, instead we check with:
AC_CHECK_LIB(llhttp, exit,, AC_MSG_ERROR([Missing llhttp library files]))
AC_CHECK_HEADERS([llhttp.h], [llhttp_headers=yes; break;])
AC_SUBST(http_lib, ["-lllhttp"])
AS_IF([test "x$llhttp_headers" != "xyes"], AC_MSG_ERROR([Missing llhttp headers files]))
PKG_CHECK_MODULES([Llhttp], [libllhttp])
llhttp_lib=", libllhttp"
])
AC_SUBST(llhttp_lib)
AC_ARG_WITH([liburing], AS_HELP_STRING([--with-liburing], [Build with io_uring support(Linux only)]),[], [with_liburing=no])
AS_IF([test "x$with_liburing" != "xno"], [
CXX_FLAGS="${CXXFLAGS} -DASIO_HAS_IO_URING -DASIO_DISABLE_EPOLL"
PKG_CHECK_MODULES([Liburing], [liburing])
iouring_lib=", liburing"
])
AC_SUBST(iouring_lib)
CXXFLAGS="${CXXFLAGS} -DMSGPACK_NO_BOOST -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)
AM_CONDITIONAL(ENABLE_TOOLS, test x$build_tools == xyes)
AM_COND_IF([ENABLE_TOOLS], [
AC_CHECK_HEADERS([readline/readline.h readline/history.h], [], [
AC_MSG_ERROR([unable to find readline.h])
AC_CHECK_HEADERS([readline/readline.h readline/history.h], [],
[AC_MSG_ERROR([Unable to find readline.h. Readline is required for the tools.])
])
])
@@ -213,4 +227,5 @@ AC_CONFIG_FILES([Makefile
doc/Makefile
doc/Doxyfile
opendht.pc])
AC_MSG_WARN([The Autotools build system for OpenDHT is deprecated and will be removed in a future release. Please use CMake or Meson instead.])
AC_OUTPUT
+1 -1
View File
@@ -12,5 +12,5 @@ if (OPENDHT_DOCUMENTATION)
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc/opendht)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR}/opendht)
endif()
+1 -1
View File
@@ -1,6 +1,6 @@
FROM ghcr.io/savoirfairelinux/opendht/opendht-deps:latest
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
COPY . opendht
+3 -3
View File
@@ -1,11 +1,11 @@
FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-alpine:latest AS build
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
COPY . opendht
RUN mkdir /install
ENV DESTDIR /install
ENV DESTDIR=/install
RUN cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
@@ -19,7 +19,7 @@ RUN cd opendht && mkdir build && cd build \
-DOPENDHT_SYSTEMD=On \
&& make -j8 && make install
FROM alpine:3.19 AS install
FROM alpine:3.22 AS install
COPY --from=build /install /
RUN apk add --no-cache \
libstdc++ \
+41
View File
@@ -0,0 +1,41 @@
FROM opendht-alpine-edge-deps:latest AS build
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
COPY . opendht
RUN mkdir /install
ENV DESTDIR=/install
RUN cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DOPENDHT_DOWNLOAD_DEPS=Off \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \
-DOPENDHT_C=On \
-DOPENDHT_PEER_DISCOVERY=On \
-DOPENDHT_PYTHON=On \
-DOPENDHT_TOOLS=On \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On \
-DOPENDHT_SYSTEMD=On \
&& make -j8 && make install
FROM alpine:edge AS install
COPY --from=build /install /
RUN apk add --no-cache \
libstdc++ \
gnutls \
nettle \
openssl \
argon2-dev \
jsoncpp \
llhttp \
fmt \
readline \
ncurses \
gdb
#CMD ["dhtnode", "-b", "bootstrap.jami.net", "-p", "4222", "--proxyserver", "8080"]
EXPOSE 4222/udp
EXPOSE 8080/tcp
CMD ["/bin/sh"]
-17
View File
@@ -1,17 +0,0 @@
FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-bionic:latest
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
COPY . opendht
RUN cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \
-DOPENDHT_C=On \
-DOPENDHT_PEER_DISCOVERY=On \
-DOPENDHT_PYTHON=On \
-DOPENDHT_TOOLS=On \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On \
&& make -j8 && make install \
&& cd ../.. && rm -rf opendht
+4 -6
View File
@@ -1,6 +1,6 @@
FROM ubuntu:22.04
FROM ubuntu:24.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
RUN apt-get update && apt-get install -y \
dialog apt-utils \
@@ -8,16 +8,14 @@ RUN apt-get update && apt-get install -y \
&& echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
RUN apt-get update && apt-get install -y \
build-essential pkg-config cmake git wget \
build-essential pkg-config cmake git wget meson \
libtool autotools-dev autoconf \
python3-pip python3-dev python3-setuptools python3-build python3-virtualenv \
python3-dev python3-setuptools python3-build python3-virtualenv cython3 \
libncurses5-dev libreadline-dev nettle-dev libcppunit-dev \
libgnutls28-dev libuv1-dev libjsoncpp-dev libargon2-dev \
libssl-dev libfmt-dev libasio-dev libmsgpack-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install meson Cython
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
+2 -2
View File
@@ -1,6 +1,6 @@
FROM alpine:3.19
FROM alpine:3.22
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
RUN apk add --no-cache \
build-base cmake ninja git wget \
+27
View File
@@ -0,0 +1,27 @@
FROM alpine:edge
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
RUN apk add --no-cache \
build-base cmake ninja git wget \
cython python3-dev py3-setuptools \
ncurses-dev readline-dev nettle-dev \
cppunit-dev gnutls-dev jsoncpp-dev \
argon2-dev openssl-dev fmt-dev \
llhttp-dev asio-dev msgpack-cxx-dev \
&& rm -rf /var/cache/apk/*
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
-36
View File
@@ -1,36 +0,0 @@
FROM ubuntu:18.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
RUN echo "APT::Acquire::Retries \"3\";" > /etc/apt/apt.conf.d/80-retries
RUN apt-get update && apt-get install -y \
apt-transport-https build-essential pkg-config git wget libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
libargon2-0-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libssl-dev python3-pip \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install --upgrade cmake meson Cython
# libasio-dev (1.10) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& make install \
&& cd ../../ && rm -rf asio*
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
+1 -1
View File
@@ -1,6 +1,6 @@
FROM ubuntu:20.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
RUN apt-get update && apt-get install -y \
dialog apt-utils \
+3 -3
View File
@@ -1,6 +1,6 @@
FROM ubuntu:24.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
RUN apt-get update && apt-get install -y \
dialog apt-utils \
@@ -19,8 +19,8 @@ RUN apt-get update \
RUN pip3 install Cython --break-system-packages
ENV CC cc
ENV CXX c++
ENV CC=cc
ENV CXX=c++
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
+2 -2
View File
@@ -1,6 +1,6 @@
FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-bionic:latest
FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-focal:latest
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
COPY . opendht
+1 -1
View File
@@ -1,6 +1,6 @@
FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-llvm:latest
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
COPY . opendht
+3 -1
View File
@@ -189,7 +189,9 @@ using ShutdownCallback = std::function<void()>;
using IdentityAnnouncedCb = std::function<void(bool)>;
using PublicAddressChangedCb = std::function<void(std::vector<SockAddr>)>;
using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::Certificate>>(const InfoHash& pk_id)>;
using CertificateStoreQueryLegacy = std::function<std::vector<std::shared_ptr<crypto::Certificate>>(const InfoHash& pk_id)>;
using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::Certificate>>(const PkId& pk_id)>;
using DoneCallback = std::function<void(bool success, const std::vector<std::shared_ptr<Node>>& nodes)>;
using DoneCallbackSimple = std::function<void(bool success)>;
+2 -1
View File
@@ -204,8 +204,9 @@ struct OPENDHT_PUBLIC PrivateKey
* @param key_length : size of the modulus in bits
* Minimim value: 2048
* Recommended values: 4096, 8192
* @param algo : the public key algorithm to use, GNUTLS_PK_RSA or GNUTLS_PK_RSA_OAEP
*/
static PrivateKey generate(unsigned key_length = 4096);
static PrivateKey generate(unsigned key_length = 4096, gnutls_pk_algorithm_t algo = GNUTLS_PK_RSA);
static PrivateKey generateEC();
gnutls_privkey_t key {};
+3 -35
View File
@@ -124,7 +124,7 @@ public:
}
};
struct ServerStats {
struct OPENDHT_PUBLIC ServerStats {
/** Current number of listen operations */
size_t listenCount {0};
/** Current number of permanent put operations (hash used) */
@@ -149,44 +149,12 @@ public:
/** Node Info **/
std::shared_ptr<NodeInfo> nodeInfo {};
std::string toString() const {
auto ret = fmt::format("Listens: {}, Puts: {}, PushListeners: {}\n"
"Push requests in the last {}: [Android: {}], [iOS: {}], [Unified: {}]\n"
"Requests: {} per second.",
listenCount, putCount, pushListenersCount,
print_duration(lastUpdated - serverStartTime),
androidPush.toString(), iosPush.toString(), unifiedPush.toString(),
requestRate);
if (nodeInfo) {
auto& ipv4 = nodeInfo->ipv4;
if (ipv4.table_depth > 1)
ret += fmt::format("IPv4 Network estimation: {}\n", ipv4.getNetworkSizeEstimation());
auto& ipv6 = nodeInfo->ipv6;
if (ipv6.table_depth > 1)
ret += fmt::format("IPv6 Network estimation: {}\n", ipv6.getNetworkSizeEstimation());
}
return ret;
}
std::string toString() const;
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const {
Json::Value result;
result["listenCount"] = static_cast<Json::UInt64>(listenCount);
result["putCount"] = static_cast<Json::UInt64>(putCount);
result["totalPermanentPuts"] = static_cast<Json::UInt64>(totalPermanentPuts);
result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount);
result["serverStartTime"] = static_cast<Json::LargestInt>(to_time_t(serverStartTime));
result["lastUpdated"] = static_cast<Json::LargestInt>(to_time_t(lastUpdated));
result["androidPush"] = androidPush.toJson();
result["iosPush"] = iosPush.toJson();
result["unifiedPush"] = unifiedPush.toJson();
result["requestRate"] = requestRate;
if (nodeInfo)
result["nodeInfo"] = nodeInfo->toJson();
return result;
}
Json::Value toJson() const;
};
std::shared_ptr<ServerStats> stats() const { return stats_; }
+9 -5
View File
@@ -77,7 +77,8 @@ public:
std::unique_ptr<net::DatagramSocket> sock;
std::shared_ptr<PeerDiscovery> peerDiscovery {};
StatusCallback statusChangedCallback {};
CertificateStoreQuery certificateStore {};
CertificateStoreQueryLegacy certificateStore {};
CertificateStoreQuery certificateStorePkId {};
IdentityAnnouncedCb identityAnnouncedCb {};
PublicAddressChangedCb publicAddressChangedCb {};
std::unique_ptr<std::mt19937_64> rng {};
@@ -325,7 +326,7 @@ public:
/**
* Get the public key fingerprint if an identity is used with this node, 0 otherwise.
*/
InfoHash getId() const;
[[deprecated("Use getPublicKey()->getLongId() instead")]] InfoHash getId() const;
std::shared_ptr<crypto::PublicKey> getPublicKey() const;
/**
@@ -393,6 +394,7 @@ public:
void findCertificate(PkId hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)>);
void registerCertificate(const std::shared_ptr<crypto::Certificate>& cert);
void setLocalCertificateStore(CertificateStoreQueryLegacy&& query_method);
void setLocalCertificateStore(CertificateStoreQuery&& query_method);
/**
@@ -438,9 +440,11 @@ public:
void shutdown(ShutdownCallback cb = {}, bool stop = false);
/**
* Quit and wait for all threads to terminate.
* No callbacks will be called after this method returns.
* All internal state will be lost. The DHT can then be run again with @run().
* Stop the node and wait for all threads to terminate.
* The node is reset to its default state. The DHT can then be run again with @run().
* No DHT callbacks will run after this method returns.
* Calling this method is optional. It allows to ensure the destructor won't block.
* This method is unable to be called from a DHT callback.
*/
void join();
+1 -1
View File
@@ -266,7 +266,7 @@ private:
using Value = std::pair<InfoHash, dht::Value::Id>;
struct OPENDHT_PUBLIC IndexEntry : public dht::Value::Serializable<IndexEntry> {
static const ValueType TYPE;
static const ValueType& TYPE;
virtual void unpackValue(const dht::Value& v) {
Serializable<IndexEntry>::unpackValue(v);
+59 -41
View File
@@ -30,89 +30,107 @@
namespace dht {
namespace log {
enum class LogLevel {
debug, warning, error
};
enum class LogLevel { debug, warning, error };
using LogMethod = std::function<void(LogLevel, std::string&&)>;
struct OPENDHT_PUBLIC Logger {
struct OPENDHT_PUBLIC Logger
{
Logger() = delete;
Logger(LogMethod&& l)
: logger(std::move(l)) {
if (!logger)
throw std::invalid_argument{"logger and loggerf must be set"};
}
void setFilter(const InfoHash& f) {
: logger(std::move(l))
{
if (!logger)
throw std::invalid_argument {"logger and loggerf must be set"};
}
void setFilter(const InfoHash& f)
{
filter_ = f;
filterEnable_ = static_cast<bool>(filter_);
}
inline void log0(LogLevel level, fmt::string_view format, fmt::printf_args args) const {
inline void log0(LogLevel level, fmt::string_view format, fmt::printf_args args) const
{
if (not filterEnable_)
logger(level, fmt::vsprintf(format, args));
}
inline void log1(LogLevel level, const InfoHash& f, fmt::string_view format, fmt::printf_args args) const {
inline void log1(LogLevel level, const InfoHash& f, fmt::string_view format, fmt::printf_args args) const
{
if (not filterEnable_ or f == filter_)
logger(level, fmt::vsprintf(format, args));
}
inline void log2(LogLevel level, const InfoHash& f1, const InfoHash& f2, fmt::string_view format, fmt::printf_args args) const {
inline void log2(
LogLevel level, const InfoHash& f1, const InfoHash& f2, fmt::string_view format, fmt::printf_args args) const
{
if (not filterEnable_ or f1 == filter_ or f2 == filter_)
logger(level, fmt::vsprintf(format, args));
}
template<typename S, typename... Args>
inline void debug(S&& format, Args&&... args) const {
logger(LogLevel::debug, fmt::format(format, args...));
template<typename... Args>
inline void debug(fmt::format_string<Args...> format, Args&&... args) const
{
logger(LogLevel::debug, fmt::format(format, std::forward<Args>(args)...));
}
template<typename S, typename... Args>
inline void warn(S&& format, Args&&... args) const {
logger(LogLevel::warning, fmt::format(format, args...));
template<typename... Args>
inline void warn(fmt::format_string<Args...> format, Args&&... args) const
{
logger(LogLevel::warning, fmt::format(format, std::forward<Args>(args)...));
}
template<typename S, typename... Args>
inline void error(S&& format, Args&&... args) const {
logger(LogLevel::error, fmt::format(format, args...));
template<typename... Args>
inline void error(fmt::format_string<Args...> format, Args&&... args) const
{
logger(LogLevel::error, fmt::format(format, std::forward<Args>(args)...));
}
template <typename... T>
inline void d(fmt::format_string<T...> format, T&&... args) const {
template<typename... T>
inline void d(fmt::format_string<T...> format, T&&... args) const
{
log0(LogLevel::debug, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void d(const InfoHash& f, fmt::format_string<T...> format, T&&... args) const {
template<typename... T>
inline void d(const InfoHash& f, fmt::format_string<T...> format, T&&... args) const
{
log1(LogLevel::debug, f, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void d(const InfoHash& f1, const InfoHash& f2, fmt::format_string<T...> format, T&&... args) const {
template<typename... T>
inline void d(const InfoHash& f1, const InfoHash& f2, fmt::format_string<T...> format, T&&... args) const
{
log2(LogLevel::debug, f1, f2, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void w(fmt::format_string<T...> format, T&&... args) const {
template<typename... T>
inline void w(fmt::format_string<T...> format, T&&... args) const
{
log0(LogLevel::warning, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void w(const InfoHash& f, fmt::format_string<T...> format, T&&... args) const {
template<typename... T>
inline void w(const InfoHash& f, fmt::format_string<T...> format, T&&... args) const
{
log1(LogLevel::warning, f, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void w(const InfoHash& f1, const InfoHash& f2, fmt::format_string<T...> format, T&&... args) const {
template<typename... T>
inline void w(const InfoHash& f1, const InfoHash& f2, fmt::format_string<T...> format, T&&... args) const
{
log2(LogLevel::warning, f1, f2, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void e(fmt::format_string<T...> format, T&&... args) const {
template<typename... T>
inline void e(fmt::format_string<T...> format, T&&... args) const
{
log0(LogLevel::error, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void e(const InfoHash& f, fmt::format_string<T...> format, T&&... args) const {
template<typename... T>
inline void e(const InfoHash& f, fmt::format_string<T...> format, T&&... args) const
{
log1(LogLevel::error, f, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void e(const InfoHash& f1, const InfoHash& f2, fmt::format_string<T...> format, T&&... args) const {
template<typename... T>
inline void e(const InfoHash& f1, const InfoHash& f2, fmt::format_string<T...> format, T&&... args) const
{
log2(LogLevel::error, f1, f2, format, fmt::make_printf_args(args...));
}
private:
LogMethod logger = {};
bool filterEnable_ {false};
InfoHash filter_ {};
};
}
} // namespace log
using Logger = log::Logger;
}
} // namespace dht
+9 -9
View File
@@ -59,18 +59,18 @@ class DhtProtocolException : public DhtException {
public:
// sent to another peer (http-like).
static const constexpr uint16_t NON_AUTHORITATIVE_INFORMATION {203}; /* incomplete request packet. */
static const constexpr uint16_t UNAUTHORIZED {401}; /* wrong tokens. */
static const constexpr uint16_t UNAUTHORIZED {401}; /* incorrect 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 */
static const constexpr uint16_t WRONG_NODE_INFO_BUF_LEN {423}; /* node info length is wrong */
static const constexpr uint16_t WRONG_NODE_INFO_BUF_LEN {423}; /* node info length is incorrect */
static const std::string GET_NO_INFOHASH; /* received "get" request with no infohash */
static const std::string LISTEN_NO_INFOHASH; /* got "listen" request without infohash */
static const std::string LISTEN_WRONG_TOKEN; /* wrong token in "listen" request */
static const std::string LISTEN_WRONG_TOKEN; /* incorrect 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 PUT_WRONG_TOKEN; /* got "put" request with incorrect 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 */
@@ -345,11 +345,11 @@ public:
* @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.
* For backward compatibility purposes, sendListen has to
* handle creation of the socket. Therefore, you are unable to
* use openSocket yourself.
* TODO: Once we don't support the old "listen" negotiation,
* 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.
+5 -1
View File
@@ -87,7 +87,7 @@ public:
/**
* "Secure" get(), that will check the signature of signed data, and decrypt encrypted data.
* If the signature can't be checked, or if the data can't be decrypted, it is not returned.
* If the signature is unable to be checked, or if the data is unable to be decrypted, it is not returned.
* Public, non-signed & non-encrypted data is retransmitted as-is.
*/
void get(const InfoHash& id, GetCallback cb, DoneCallback donecb={}, Value::Filter&& = {}, Where&& w = {}) override;
@@ -157,6 +157,9 @@ public:
* The search key used is the public key ID, so there may be multiple certificates retured, signed with
* the same private key.
*/
void setLocalCertificateStore(CertificateStoreQueryLegacy&& query_method) {
localQueryMethodLegacy_ = std::move(query_method);
}
void setLocalCertificateStore(CertificateStoreQuery&& query_method) {
localQueryMethod_ = std::move(query_method);
}
@@ -379,6 +382,7 @@ private:
// method to query the local certificate store
CertificateStoreQuery localQueryMethod_ {};
CertificateStoreQueryLegacy localQueryMethodLegacy_ {};
// our certificate cache
std::map<InfoHash, Sp<crypto::Certificate>> nodesCertificates_ {};
+68 -40
View File
@@ -20,6 +20,7 @@
#include "def.h"
#include <type_traits>
#include <msgpack.hpp>
#include <fmt/format.h>
@@ -27,6 +28,7 @@
#include <random>
#include <functional>
#include <map>
#include <string_view>
#include <cstdarg>
@@ -47,32 +49,38 @@ OPENDHT_PUBLIC const char* version();
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)
template<typename Key, typename Item, typename Condition>
void
erase_if(std::map<Key, Item>& map, const Condition& condition)
{
for (auto it = map.begin(); it != map.end(); ) {
for (auto it = map.begin(); it != map.end();) {
if (condition(*it)) {
it = map.erase(it);
} else { ++it; }
} else {
++it;
}
}
}
/**
* Split "[host]:port" or "host:port" to pair<"host", "port">.
*/
OPENDHT_PUBLIC std::pair<std::string, std::string>
splitPort(std::string_view s);
OPENDHT_PUBLIC std::pair<std::string, std::string> splitPort(std::string_view s);
class OPENDHT_PUBLIC DhtException : public std::runtime_error {
class OPENDHT_PUBLIC DhtException : public std::runtime_error
{
public:
DhtException(const std::string &str = "") :
std::runtime_error("DhtException occurred: " + str) {}
DhtException(const std::string& str = "")
: std::runtime_error("DhtException occurred: " + str)
{}
};
class OPENDHT_PUBLIC SocketException : public DhtException {
class OPENDHT_PUBLIC SocketException : public DhtException
{
public:
SocketException(int err) :
DhtException(strerror(err)) {}
SocketException(int err)
: DhtException(strerror(err))
{}
};
// Time related definitions and utility functions
@@ -85,47 +93,61 @@ using duration = clock::duration;
time_point from_time_t(std::time_t t);
std::time_t to_time_t(time_point t);
template <class DT>
template<class DT>
static std::string
print_duration(DT d) {
print_duration(DT d)
{
if (d < std::chrono::seconds(0)) {
return "-" + print_duration(-d);
} else if (d < std::chrono::milliseconds(1)) {
return fmt::format("{:.3g} us", std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count());
return fmt::format("{:.3g} us",
std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count());
} else if (d < std::chrono::seconds(1)) {
return fmt::format("{:.3g} ms", std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count());
return fmt::format("{:.3g} ms",
std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count());
} else if (d < std::chrono::minutes(1)) {
return fmt::format("{:.3g} s", std::chrono::duration_cast<std::chrono::duration<double>>(d).count());
} else if (d < std::chrono::hours(1)) {
return fmt::format("{:.3g} min", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count());
return fmt::format("{:.3g} min",
std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count());
} else if (d < std::chrono::hours(72)) {
return fmt::format("{:.3g} h", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count());
return fmt::format("{:.3g} h",
std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count());
} else {
return fmt::format("{:.3g} days", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<86400>>>(d).count());
return fmt::format("{:.3g} days",
std::chrono::duration_cast<std::chrono::duration<double, std::ratio<86400>>>(d).count());
}
}
template <class TimePoint>
template<class TimePoint>
static std::string
print_time_relative(TimePoint now, TimePoint d) {
if (d == TimePoint::min()) return "never";
if (d == now) return "now";
return (d > now) ? std::string("in ") + print_duration(d - now)
: print_duration(now - d) + std::string(" ago");
print_time_relative(TimePoint now, TimePoint d)
{
if (d == TimePoint::min())
return "never";
if (d == now)
return "now";
return (d > now) ? std::string("in ") + print_duration(d - now) : print_duration(now - d) + std::string(" ago");
}
template <typename Duration = duration>
class uniform_duration_distribution : public std::uniform_int_distribution<typename Duration::rep> {
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>;
using param_type = typename Base::param_type;
public:
uniform_duration_distribution(Duration min, Duration max) : Base(min.count(), max.count()) {}
template <class Generator>
Duration operator()(Generator && g) {
uniform_duration_distribution(Duration min, Duration max)
: Base(min.count(), max.count())
{}
template<class Generator>
Duration operator()(Generator&& g)
{
return Duration(Base::operator()(g));
}
template< class Generator >
Duration operator()( Generator && g, const param_type& params ) {
template<class Generator>
Duration operator()(Generator&& g, const param_type& params)
{
return Duration(Base::operator()(g, params));
}
};
@@ -142,19 +164,21 @@ using Blob = std::vector<uint8_t>;
*/
OPENDHT_PUBLIC Blob unpackBlob(const msgpack::object& o);
template <typename Type>
template<typename Type>
Blob
packMsg(const Type& t) {
packMsg(const Type& t)
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack(t);
return {buffer.data(), buffer.data()+buffer.size()};
return {buffer.data(), buffer.data() + buffer.size()};
}
template <typename Type>
template<typename Type>
Type
unpackMsg(Blob b) {
msgpack::unpacked msg_res = msgpack::unpack((const char*)b.data(), b.size());
unpackMsg(Blob b)
{
msgpack::unpacked msg_res = msgpack::unpack((const char*) b.data(), b.size());
return msg_res.get().as<Type>();
}
@@ -162,10 +186,14 @@ msgpack::unpacked unpackMsg(Blob b);
msgpack::object* findMapValue(const msgpack::object& map, const char* key, size_t length);
inline msgpack::object* findMapValue(const msgpack::object& map, const char* key) {
inline msgpack::object*
findMapValue(const msgpack::object& map, const char* key)
{
return findMapValue(map, key, strlen(key));
}
inline msgpack::object* findMapValue(const msgpack::object& map, std::string_view key) {
inline msgpack::object*
findMapValue(const msgpack::object& map, std::string_view key)
{
return findMapValue(map, key.data(), key.size());
}
+5 -4
View File
@@ -90,18 +90,19 @@ 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, const InfoHash& from, const SockAddr& addr)>;
static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
static constexpr const duration DEFAULT_VALUE_EXPIRATION {std::chrono::minutes(10)};
struct ValueType {
typedef uint16_t Id;
static bool DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
static bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&) {
OPENDHT_PUBLIC static bool DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
static inline bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&) {
return false;
}
ValueType () {}
ValueType (Id id, std::string name, duration e = std::chrono::minutes(10))
ValueType (Id id, std::string name, duration e = DEFAULT_VALUE_EXPIRATION)
: id(id), name(name), expiration(e) {}
ValueType (Id id, std::string name, duration e, StorePolicy sp, EditPolicy ep = DEFAULT_EDIT_POLICY)
@@ -119,7 +120,7 @@ struct ValueType {
Id id {0};
std::string name {};
duration expiration {std::chrono::minutes(10)};
duration expiration {DEFAULT_VALUE_EXPIRATION};
StorePolicy storePolicy {DEFAULT_STORE_POLICY};
EditPolicy editPolicy {DEFAULT_EDIT_POLICY};
};
+197 -119
View File
@@ -1,29 +1,53 @@
project('opendht', 'c', 'cpp', 'cython',
version: '3.4.0',
default_options: [
'cpp_std=c++17',
'warning_level=3'
])
project(
'opendht',
'c',
'cpp',
'cython',
version: '3.6.0',
meson_version: '>=1.1.0',
default_options: ['cpp_std=c++17', 'warning_level=3'],
)
gnutls = dependency('gnutls')
nettle = dependency('nettle')
msgpack = dependency('msgpack-cxx', required : false)
msgpack = dependency('msgpack-cxx', required: false)
argon2 = dependency('libargon2')
fmt = dependency('fmt')
openssl = dependency('openssl', required: get_option('proxy_client'))
jsoncpp = dependency('jsoncpp', required: get_option('proxy_client'))
fmt = dependency('fmt')
llhttp = dependency('llhttp', 'libllhttp', required: get_option('proxy_client'))
io_uring = dependency('liburing', required: false)
simdutf = dependency('simdutf', required: get_option('proxy_client'))
io_uring = host_machine.system() == 'linux' ? dependency('liburing', required: false) : disabler()
deps = [fmt, gnutls, nettle, msgpack, argon2, openssl, jsoncpp, llhttp, io_uring]
deps = [
fmt,
gnutls,
nettle,
msgpack,
argon2,
openssl,
jsoncpp,
simdutf,
llhttp,
io_uring,
]
conf_data = configuration_data()
add_project_arguments('-DMSGPACK_NO_BOOST', '-DASIO_STANDALONE', language : 'cpp')
add_project_arguments('-DMSGPACK_NO_BOOST', '-DASIO_STANDALONE', language: 'cpp')
if io_uring.found()
add_project_arguments('-DASIO_HAS_IO_URING', '-DASIO_DISABLE_EPOLL', language : 'cpp')
add_project_arguments('-DASIO_HAS_IO_URING', '-DASIO_DISABLE_EPOLL', language: 'cpp')
conf_data.set('iouring_lib', ', liburing')
endif
add_project_arguments(['-Wno-return-type','-Wno-deprecated','-Wnon-virtual-dtor','-pedantic-errors','-fvisibility=hidden'], language : 'cpp')
add_project_arguments(
[
'-Wno-return-type',
'-Wno-deprecated',
'-Wnon-virtual-dtor',
'-pedantic-errors',
'-fvisibility=hidden',
],
language: 'cpp',
)
opendht_inc = include_directories('include/opendht')
opendht_interface_inc = include_directories('include', is_system: true)
@@ -48,17 +72,17 @@ opendht_src = [
if get_option('indexation').enabled()
opendht_src += 'src/indexation/pht.cpp'
add_project_arguments('-DOPENDHT_INDEXATION', language : 'cpp')
add_project_arguments('-DOPENDHT_INDEXATION', language: 'cpp')
endif
if jsoncpp.found()
opendht_src += ['src/base64.cpp']
add_project_arguments('-DOPENDHT_JSONCPP', language : 'cpp')
add_project_arguments('-DOPENDHT_JSONCPP', language: 'cpp')
conf_data.set('jsoncpp_lib', ', jsoncpp')
endif
if llhttp.found()
opendht_src += ['src/http.cpp', 'src/compat/os_cert.cpp']
if host_machine.system() == 'darwin'
deps+=dependency('appleframeworks', modules : ['CoreFoundation', 'Security'])
deps += dependency('appleframeworks', modules: ['CoreFoundation', 'Security'])
endif
conf_data.set('http_lib', '-lllhttp')
endif
@@ -67,25 +91,27 @@ if openssl.found()
endif
if get_option('proxy_client').enabled()
opendht_src += ['src/dht_proxy_client.cpp']
add_project_arguments('-DOPENDHT_PROXY_CLIENT', language : 'cpp')
add_project_arguments('-DOPENDHT_PROXY_CLIENT', language: 'cpp')
endif
if get_option('proxy_server').enabled()
opendht_src += 'src/dht_proxy_server.cpp'
add_project_arguments('-DOPENDHT_PROXY_SERVER', language : 'cpp')
add_project_arguments('-DOPENDHT_PROXY_SERVER', language: 'cpp')
endif
if get_option('push_notifications').enabled()
add_project_arguments('-DOPENDHT_PUSH_NOTIFICATIONS', language : 'cpp')
add_project_arguments('-DOPENDHT_PUSH_NOTIFICATIONS', language: 'cpp')
endif
if get_option('peer_discovery').enabled()
opendht_src += 'src/peer_discovery.cpp'
add_project_arguments('-DOPENDHT_PEER_DISCOVERY', language : 'cpp')
add_project_arguments('-DOPENDHT_PEER_DISCOVERY', language: 'cpp')
endif
opendht = library('opendht',
opendht = library(
'opendht',
opendht_src,
include_directories : opendht_inc,
dependencies : deps,
cpp_args : ['-DOPENDHT_BUILD', '-Dopendht_EXPORTS'],
install : true)
include_directories: opendht_inc,
dependencies: deps,
cpp_args: ['-DOPENDHT_BUILD', '-Dopendht_EXPORTS'],
install: true,
)
conf_data.set('VERSION', meson.project_version())
conf_data.set('prefix', get_option('prefix'))
@@ -93,74 +119,99 @@ conf_data.set('exec_prefix', get_option('prefix'))
conf_data.set('libdir', join_paths(get_option('prefix'), get_option('libdir')))
conf_data.set('includedir', join_paths(get_option('prefix'), get_option('includedir')))
conf_data.set('argon2_lib', ', libargon2')
conf_data.set('simdutf_lib', ', simdutf')
configure_file(input : 'opendht.pc.in',
output : 'opendht.pc',
configuration : conf_data,
install: true,
install_dir: join_paths(get_option('prefix'), get_option('libdir'), 'pkgconfig'))
configure_file(
input: 'opendht.pc.in',
output: 'opendht.pc',
configuration: conf_data,
install: true,
install_dir: join_paths(get_option('prefix'), get_option('libdir'), 'pkgconfig'),
)
readline = meson.get_compiler('c').find_library('readline', required: get_option('tools'))
if get_option('c').enabled()
opendht_c = library('opendht-c',
['c/opendht.cpp', 'c/opendht_c.h'],
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [msgpack, jsoncpp, fmt],
cpp_args : ['-DOPENDHT_C_BUILD', '-Dopendht_c_EXPORTS'],
install : true)
configure_file(input : 'opendht-c.pc.in',
output : 'opendht-c.pc',
configuration : conf_data,
install: true,
install_dir: join_paths(get_option('prefix'), get_option('libdir'), 'pkgconfig'))
opendht_c = library(
'opendht-c',
['c/opendht.cpp', 'c/opendht_c.h'],
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [msgpack, jsoncpp, fmt],
cpp_args: ['-DOPENDHT_C_BUILD', '-Dopendht_c_EXPORTS'],
install: true,
)
configure_file(
input: 'opendht-c.pc.in',
output: 'opendht-c.pc',
configuration: conf_data,
install: true,
install_dir: join_paths(get_option('prefix'), get_option('libdir'), 'pkgconfig'),
)
if get_option('tools').enabled()
dhtcnode = executable('dhtcnode', 'tools/dhtcnode.c',
include_directories : ['c', opendht_interface_inc],
link_with : opendht_c,
dependencies : [readline],
install : true)
dhtcnode = executable(
'dhtcnode',
'tools/dhtcnode.c',
include_directories: ['c', opendht_interface_inc],
link_with: opendht_c,
dependencies: [readline],
install: true,
)
endif
endif
if get_option('python').require(get_option('indexation').enabled(), error_message: 'python requires indexation').allowed()
if get_option('python').require(
get_option('indexation').enabled(),
error_message: 'python requires indexation',
).allowed()
py = import('python').find_installation()
dep_py = py.dependency()
py.extension_module(
'opendht',
'python/opendht.pyx',
include_directories : opendht_interface_inc,
override_options : ['cython_language=cpp'],
link_with : [opendht],
dependencies : [msgpack, jsoncpp, fmt, dep_py],
install : true
include_directories: opendht_interface_inc,
override_options: ['cython_language=cpp'],
link_with: [opendht],
dependencies: [msgpack, jsoncpp, fmt, dep_py],
install: true,
)
endif
if get_option('tools').enabled()
dhtnode = executable('dhtnode', 'tools/dhtnode.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [readline, jsoncpp, msgpack, fmt, openssl],
install : true)
dhtchat = executable('dhtchat', 'tools/dhtchat.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [readline, jsoncpp, msgpack, fmt, openssl],
install : true)
dhtscanner = executable('dhtscanner', 'tools/dhtscanner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [readline, jsoncpp, msgpack, fmt, openssl],
install : true)
dhtnode = executable(
'dhtnode',
'tools/dhtnode.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [readline, jsoncpp, msgpack, fmt, openssl],
install: true,
)
dhtchat = executable(
'dhtchat',
'tools/dhtchat.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [readline, jsoncpp, msgpack, fmt, openssl],
install: true,
)
dhtscanner = executable(
'dhtscanner',
'tools/dhtscanner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [readline, jsoncpp, msgpack, fmt, openssl],
install: true,
)
if llhttp.found()
durl = executable('durl', 'tools/durl.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [msgpack, openssl])
durl = executable(
'durl',
'tools/durl.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [msgpack, openssl],
)
endif
endif
@@ -168,74 +219,101 @@ endif
if get_option('tests').enabled()
cppunit = dependency('cppunit')
test_infohash = executable('test_infohash',
'tests/infohashtester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test_infohash = executable(
'test_infohash',
'tests/infohashtester.cpp',
'tests/tests_runner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
)
test('Infohash', test_infohash)
test_value = executable('test_value',
'tests/valuetester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test_value = executable(
'test_value',
'tests/valuetester.cpp',
'tests/tests_runner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
)
test('Value', test_value)
test_crypto = executable('test_crypto',
'tests/cryptotester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test_crypto = executable(
'test_crypto',
'tests/cryptotester.cpp',
'tests/tests_runner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
)
test('Crypto', test_crypto)
test_dhtrunner = executable('test_dhtrunner',
'tests/dhtrunnertester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test_dhtrunner = executable(
'test_dhtrunner',
'tests/dhtrunnertester.cpp',
'tests/tests_runner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
)
test('DhtRunner', test_dhtrunner)
test_threadpool = executable('test_threadpool',
'tests/threadpooltester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test_threadpool = executable(
'test_threadpool',
'tests/threadpooltester.cpp',
'tests/tests_runner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
)
test('ThreadPool', test_threadpool)
if get_option('proxy_client').enabled() or get_option('proxy_server').enabled()
test_http = executable('test_http',
'tests/httptester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test_http = executable(
'test_http',
'tests/httptester.cpp',
'tests/tests_runner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
)
test('Http', test_http)
endif
if get_option('peer_discovery').enabled()
test_peerdiscovery = executable('test_peerdiscovery',
'tests/peerdiscoverytester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test_peerdiscovery = executable(
'test_peerdiscovery',
'tests/peerdiscoverytester.cpp',
'tests/tests_runner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
)
test('PeerDiscovery', test_peerdiscovery)
endif
if get_option('proxy_server').enabled()
test_proxy = executable('test_dhtproxy',
'tests/dhtproxytester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test_proxy = executable(
'test_dhtproxy',
'tests/dhtproxytester.cpp',
'tests/tests_runner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
)
test('DhtProxy', test_proxy)
if get_option('long_tests').enabled()
test_proxystress = executable('test_dhtproxystress',
'tests/dhtproxy_stress_tester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test_proxystress = executable(
'test_dhtproxystress',
'tests/dhtproxy_stress_tester.cpp',
'tests/tests_runner.cpp',
include_directories: opendht_interface_inc,
link_with: opendht,
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
)
test('DhtProxy Stress', test_proxystress)
endif
endif
endif
endif
+2 -2
View File
@@ -5,8 +5,8 @@ includedir=@includedir@
Name: OpenDHT
Description: C++17 Distributed Hash Table library
Version: @VERSION@
Libs: -L${libdir} -lopendht
Libs: -L${libdir} -lopendht -lfmt
Libs.private: @http_lib@ -pthread
Requires: gnutls >= 3.3@jsoncpp_lib@@openssl_lib@
Requires.private: nettle >= 2.4@argon2_lib@@iouring_lib@
Requires.private: nettle >= 2.4@argon2_lib@@llhttp_lib@@iouring_lib@@simdutf_lib@
Cflags: -I${includedir}
+39 -9
View File
@@ -1,19 +1,49 @@
set(CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
configure_file(setup.py.in setup.py)
configure_file(pyproject.toml pyproject.toml COPYONLY)
configure_file(README.md README.md COPYONLY)
add_custom_target(python ALL
COMMAND python3 setup.py build
DEPENDS opendht opendht_cpp.pxd opendht.pyx pyproject.toml)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
add_custom_target(dist
COMMAND python3 -m build
DEPENDS opendht opendht_cpp.pxd opendht.pyx pyproject.toml)
add_custom_target(python
COMMAND ${Python3_EXECUTABLE} -m build "${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS opendht opendht_cpp.pxd opendht.pyx pyproject.toml
${CURRENT_SOURCE_DIR}/opendht/__init__.py
${CURRENT_SOURCE_DIR}/opendht/aio.py)
install(CODE [[
if(NOT Python3_EXECUTABLE)
find_package(Python3 COMPONENTS Interpreter)
endif()
if(NOT Python3_EXECUTABLE)
message(WARNING "Skipping Python package install: Python interpreter not found.")
else()
execute_process(
COMMAND ${Python3_EXECUTABLE} -m pip --version
OUTPUT_QUIET
ERROR_QUIET
RESULT_VARIABLE _pip_check)
if(NOT _pip_check EQUAL 0)
message(WARNING "Skipping Python package install: pip not available for ${Python3_EXECUTABLE}.")
else()
execute_process(
COMMAND ${Python3_EXECUTABLE} -m pip install --no-deps --break-system-packages .
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/python
OUTPUT_VARIABLE _pip_output
ERROR_VARIABLE _pip_error
RESULT_VARIABLE _pip_result)
install(CODE "execute_process(COMMAND python3 setup.py install --root=\$ENV{DESTDIR}/ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
if(_pip_result EQUAL 0)
message(STATUS "Successfully installed Python package")
message(STATUS "Output: ${_pip_output}")
else()
message(WARNING "pip install failed (code: ${_pip_result})\nOutput: ${_pip_output}\nError: ${_pip_error}")
endif()
endif()
endif()
]])
if (OPENDHT_TOOLS)
install(PROGRAMS tools/dhtcluster.py DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME dhtcluster)
endif()
endif()
+3 -3
View File
@@ -8,7 +8,7 @@ noinst_HEADERS = \
PYTHON_INSTALL_RECORD = $(builddir)/install_record.txt
pybuild.stamp:
LDFLAGS="-L$(top_srcdir)/src/.libs" $(PYTHON) setup.py build_ext --inplace
LDFLAGS="-L$(top_srcdir)/src/.libs" $(PYTHON) -m build .
echo stamp > pybuild.stamp
CLEANFILES = pybuild.stamp
@@ -18,7 +18,8 @@ clean-local:
rm -rf $(builddir)/build $(builddir)/*.so $(PYTHON_INSTALL_RECORD)
install-exec-local:
$(PYTHON) setup.py install --root=$(DESTDIR)/ --record $(PYTHON_INSTALL_RECORD)
$(PYTHON) -m pip install --no-deps --no-build-isolation . \
--root=$(DESTDIR)/ --prefix=$(prefix)
rm -rf $(builddir)/build
if HAVE_PIP
@@ -27,4 +28,3 @@ uninstall-local:
endif
endif
+89
View File
@@ -0,0 +1,89 @@
# OpenDHT
OpenDHT is a lightweight Distributed Hash Table implementation providing an easy to use distributed in-memory data store.
## Key Features
* Lightweight and scalable, designed for large networks and small devices
* High resilience to network disruption
* Public key cryptography layer providing optional data signature and encryption
* IPv4 and IPv6 support
* Python 3 bindings
* REST API with optional HTTP client+server with push notification support
Every node in the network can read and write values to the store. Values are distributed over the network with redundancy.
## Installation
Install on Linux, macOS and Windows with:
```sh
pip install opendht
```
## Quick Example
Using the simple, blocking API:
```python
import opendht as dht
node = dht.DhtRunner()
node.run()
# Join the DHT network through any running node,
# here using a known bootstrap node.
node.bootstrap("bootstrap.jami.net", "4222")
# blocking call (provide callback arguments to make the call non-blocking)
node.put(dht.InfoHash.get("unique_key"), dht.Value(b'some binary data'))
results = node.get(dht.InfoHash.get("unique_key"))
for value in results:
print(value)
```
Or using asyncio:
```python
import asyncio
import opendht.aio as dht
async def dht_async_demo(key_str: str):
# Start a new node using an async context manager.
# It is also possible to call run()/await shutdown() manually.
async with dht.DhtRunner(
bootstrap=(("bootstrap.jami.net", "4222"),)
) as node:
# compute key hash
key = dht.InfoHash.get(key_str)
# put data, waiting for completion
await node.put(key, dht.Value(b'tata data'))
# get all values at key
results = await node.getAll(key)
for value in results:
print(value)
# same operation, but stream values as they come from the network
with node.get(key) as results:
async for value in results:
print(value)
# listen for change of values at key
with node.listen(key) as values:
async for value, expired in values:
print(value)
if value.data == b'tata data':
break
asyncio.run(dht_async_demo("unique_key"))
```
## Documentation
For more information, examples and documentation, or to repport issues, visit: https://opendht.net
## License
Copyright (C) 2014-2025 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.
+250 -116
View File
@@ -5,27 +5,20 @@
# distutils: libraries = opendht gnutls
# cython: language_level=3
#
# Copyright (c) 2015-2023 Savoir-faire Linux Inc.
# Author(s): Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
# Copyright (C) 2014-2025 Savoir-faire Linux Inc.
#
# This wrapper is written for Cython 0.22
#
# This file is part of OpenDHT Python Wrapper.
#
# OpenDHT Python Wrapper is free software: you can redistribute it and/or modify
# 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.
#
# OpenDHT Python Wrapper is distributed in the hope that it will be useful,
# 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
# 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 OpenDHT Python Wrapper. If not, see <https://www.gnu.org/licenses/>.
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from libcpp.map cimport map as map
from libcpp cimport bool
@@ -33,7 +26,6 @@ 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
from cpython cimport ref
from datetime import timedelta
@@ -42,6 +34,23 @@ cimport opendht_cpp as cpp
import threading
cdef inline void _initialize_gnutls():
cdef int err = cpp.gnutls_global_init()
if err != 0:
print(f"Failed to initialize GnuTLS: {cpp.gnutls_strerror(err).decode()}")
else:
import atexit
atexit.register(_deinitialize_gnutls)
cdef inline _deinitialize_gnutls():
cpp.gnutls_global_deinit()
# Initialize GnuTLS when this module is imported
_initialize_gnutls()
def version() -> str:
return cpp.version().decode()
cdef inline void lookup_callback(cpp.vector[cpp.shared_ptr[cpp.IndexValue]]* values, cpp.Prefix* p, void *user_data) noexcept with gil:
cbs = <object>user_data
if 'lookup' in cbs and cbs['lookup']:
@@ -98,6 +107,12 @@ cdef class _WithID(object):
def __str__(self):
return self.getId().toString().decode()
cdef class _WithPk(object):
def __repr__(self):
return "<%s '%s'>" % (self.__class__.__name__, str(self))
def __str__(self):
return self.getLongId().toString().decode()
cdef class InfoHash(_WithID):
cdef cpp.InfoHash _infohash
def __cinit__(self, bytes str=b''):
@@ -123,19 +138,57 @@ cdef class InfoHash(_WithID):
def toFloat(InfoHash self):
return self._infohash.toFloat()
@staticmethod
def commonBits(InfoHash a, InfoHash b):
def commonBits(InfoHash a, InfoHash b) -> int:
return cpp.InfoHash.commonBits(a._infohash, b._infohash)
@staticmethod
def get(str key):
def get(str key) -> InfoHash:
h = InfoHash()
h._infohash = cpp.InfoHash.get(key.encode())
return h
@staticmethod
def getRandom():
def getRandom() -> InfoHash:
h = InfoHash()
h._infohash = cpp.InfoHash.getRandom()
return h
cdef class PkId(_WithPk):
cdef cpp.PkId _pkid
def __cinit__(self, bytes str=b''):
self._pkid = cpp.PkId(str) if str else cpp.PkId()
def __bool__(PkId self):
return <bool>self._pkid
def __richcmp__(PkId self, PkId other, int op):
if op == 0:
return self._pkid < other._pkid
if op == 1:
return self._pkid < other._pkid or self._pkid == other._pkid
if op == 2:
return self._pkid == other._pkid
return NotImplemented
def getBit(PkId self, bit):
return self._pkid.getBit(bit)
def setBit(PkId self, bit, b):
self._pkid.setBit(bit, b)
def getLongId(PkId self):
return self
def toString(PkId self):
return self._pkid.toString()
def toFloat(PkId self) -> float:
return self._pkid.toFloat()
@staticmethod
def commonBits(PkId a, PkId b) -> int:
return cpp.PkId.commonBits(a._pkid, b._pkid)
@staticmethod
def get(str key) -> PkId:
h = PkId()
h._pkid = cpp.PkId.get(key.encode())
return h
@staticmethod
def getRandom() -> PkId:
h = PkId()
h._pkid = cpp.PkId.getRandom()
return h
cdef class SockAddr(object):
cdef cpp.SockAddr _addr
def toString(SockAddr self):
@@ -225,7 +278,7 @@ cdef class Where(object):
self._where = cpp.Where()
def __str__(self):
return self._where.toString().decode()
def isSatisfiedBy(self, Where where):
def isSatisfiedBy(self, Where where) -> bool:
return self._where.isSatisfiedBy(where._where)
def id(self, cpp.uint64_t id):
self._where.id(id)
@@ -247,39 +300,44 @@ cdef class Value(object):
cdef shared_ptr[cpp.Value] _value
def __init__(self, bytes val=b'', cpp.uint16_t id=0):
self._value.reset(new cpp.Value(id, val, len(val)))
def __str__(self):
return self._value.get().toString().decode()
property owner:
def __get__(self):
h = InfoHash()
h._infohash = self._value.get().owner.get().getId()
return h
property recipient:
def __get__(self):
h = InfoHash()
h._infohash = self._value.get().recipient
return h
def __set__(self, InfoHash h):
self._value.get().recipient = h._infohash
property data:
def __get__(self):
return string(<char*>self._value.get().data.data(), self._value.get().data.size())
def __set__(self, bytes value):
self._value.get().data = value
property user_type:
def __get__(self):
return self._value.get().user_type.decode()
def __set__(self, str t):
self._value.get().user_type = t.encode()
property id:
def __get__(self):
return self._value.get().id
def __set__(self, cpp.uint64_t value):
self._value.get().id = value
property size:
def __get__(self):
return self._value.get().size()
@property
def owner(self) -> PublicKey:
h = PublicKey()
h._key = self._value.get().owner
return h
@property
def recipient(self) -> InfoHash:
h = InfoHash()
h._infohash = self._value.get().recipient
return h
@recipient.setter
def recipient(self, InfoHash h):
self._value.get().recipient = h._infohash
@property
def data(self) -> bytes:
cdef char* data_ptr = <char*>self._value.get().data.data()
cdef int data_size = self._value.get().data.size()
return data_ptr[:data_size]
@data.setter
def data(self, bytes value):
self._value.get().data = value
@property
def user_type(self) -> str:
return self._value.get().user_type.decode()
@user_type.setter
def user_type(self, str t):
self._value.get().user_type = t.encode()
@property
def id(self):
return self._value.get().id
@id.setter
def id(self, cpp.uint64_t value):
self._value.get().id = value
@property
def size(self) -> int:
return self._value.get().size()
cdef class ValueType(object):
cdef cpp.ValueType * _value
@@ -334,17 +392,31 @@ cdef class NodeSet(object):
def __iter__(self):
return NodeSetIter(self)
cdef class PrivateKey(_WithID):
cdef class PrivateKey(_WithPk):
cdef shared_ptr[cpp.PrivateKey] _key
def getId(self):
def getId(self) -> InfoHash:
if not self._key:
raise ValueError("PrivateKey is not initialized")
h = InfoHash()
h._infohash = self._key.get().getSharedPublicKey().get().getId()
return h
def getPublicKey(self):
def getLongId(self) -> PkId:
if not self._key:
raise ValueError("PrivateKey is not initialized")
id = PkId()
id._pkid = self._key.get().getSharedPublicKey().get().getLongId()
return id
def getPublicKey(self) -> PublicKey:
if not self._key:
raise ValueError("PrivateKey is not initialized")
pk = PublicKey()
pk._key = self._key.get().getSharedPublicKey()
return pk
def decrypt(self, bytes dat):
def decrypt(self, bytes dat) -> bytes:
cdef size_t d_len = len(dat)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>dat
cdef cpp.Blob indat
@@ -353,26 +425,49 @@ cdef class PrivateKey(_WithID):
cdef char* decrypted_c_str = <char *>decrypted.data()
cdef Py_ssize_t length = decrypted.size()
return decrypted_c_str[:length]
def __str__(self):
return self.getId().toString().decode()
def sign(self, bytes dat) -> bytes:
if not self._key:
raise ValueError("PrivateKey is not initialized")
cdef size_t d_len = len(dat)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>dat
cdef cpp.Blob indat
indat.assign(d_ptr, <cpp.uint8_t*>(d_ptr + d_len))
cdef cpp.Blob signature = self._key.get().sign(indat)
cdef char* signature_c_str = <char *>signature.data()
cdef Py_ssize_t length = signature.size()
return signature_c_str[:length]
@staticmethod
def generate():
def generate() -> PrivateKey:
k = PrivateKey()
k._key = cpp.make_shared[cpp.PrivateKey](cpp.PrivateKey.generate())
return k
@staticmethod
def generateEC():
def generateEC() -> PrivateKey:
k = PrivateKey()
k._key = cpp.make_shared[cpp.PrivateKey](cpp.PrivateKey.generateEC())
return k
cdef class PublicKey(_WithID):
cdef class PublicKey(_WithPk):
cdef cpp.shared_ptr[cpp.PublicKey] _key
def getId(self):
def getId(self) -> InfoHash:
if not self._key:
raise ValueError("PublicKey is not initialized")
h = InfoHash()
h._infohash = self._key.get().getId()
return h
def encrypt(self, bytes dat):
def getLongId(self) -> PkId:
if not self._key:
raise ValueError("PublicKey is not initialized")
id = PkId()
id._pkid = self._key.get().getLongId()
return id
def encrypt(self, bytes dat) -> bytes:
if not self._key:
raise ValueError("PublicKey is not initialized")
cdef size_t d_len = len(dat)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>dat
cdef cpp.Blob indat
@@ -382,29 +477,53 @@ cdef class PublicKey(_WithID):
cdef Py_ssize_t length = encrypted.size()
return encrypted_c_str[:length]
cdef class Certificate(_WithID):
def checkSignature(self, bytes dat, bytes signature) -> bool:
if not self._key:
raise ValueError("PublicKey is not initialized")
cdef size_t d_len = len(dat)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>dat
cdef cpp.Blob indat
indat.assign(d_ptr, <cpp.uint8_t*>(d_ptr + d_len))
cdef size_t s_len = len(signature)
cdef cpp.uint8_t* s_ptr = <cpp.uint8_t*>signature
cdef cpp.Blob sig
sig.assign(s_ptr, <cpp.uint8_t*>(s_ptr + s_len))
return self._key.get().checkSignature(indat, sig)
cdef class Certificate(_WithPk):
cdef shared_ptr[cpp.Certificate] _cert
def __init__(self, bytes dat = None):
if dat:
self._cert = cpp.make_shared[cpp.Certificate](<cpp.string>dat)
def getId(self):
def getId(self) -> InfoHash:
if not self._cert:
raise ValueError("Certificate is not initialized")
h = InfoHash()
if self._cert:
h._infohash = self._cert.get().getId()
h._infohash = self._cert.get().getId()
return h
def toString(self):
def getLongId(self) -> PkId:
if not self._cert:
raise ValueError("Certificate is not initialized")
id = PkId()
id._pkid = self._cert.get().getLongId()
return id
def toString(self) -> str:
if not self._cert:
return ""
return self._cert.get().toString().decode()
def getName(self):
return self._cert.get().getName()
def getName(self) -> str:
return self._cert.get().getName().decode()
def revoke(self, PrivateKey k, Certificate c):
self._cert.get().revoke(deref(k._key.get()), deref(c._cert.get()));
def __bytes__(self):
return self._cert.get().toString() if self._cert else b''
property issuer:
def __get__(self):
return self._cert.get().toString().encode() if self._cert else b''
@property
def issuer(self) -> Certificate|None:
if self._cert and self._cert.get().issuer:
c = Certificate()
c._cert = self._cert.get().issuer
return c;
return c
return None
@staticmethod
def generate(PrivateKey k, str name, Identity i = Identity(), bool is_ca = False):
c = Certificate()
@@ -446,21 +565,27 @@ cdef class Identity(object):
i = Identity()
i._id = cpp.generateIdentity(name.encode(), ca._id, bits)
return i
property publickey:
def __get__(self):
k = PublicKey()
k._key = self._id.first.get().getSharedPublicKey()
return k
property certificate:
def __get__(self):
c = Certificate()
c._cert = self._id.second
return c
property key:
def __get__(self):
k = PrivateKey()
k._key = self._id.first
return k
@property
def publickey(self) -> PublicKey|None:
if not self._id.first:
return None
k = PublicKey()
k._key = self._id.first.get().getSharedPublicKey()
return k
@property
def certificate(self) -> Certificate|None:
if not self._id.second:
return None
c = Certificate()
c._cert = self._id.second
return c
@property
def key(self) -> PrivateKey|None:
if not self._id.first:
return None
k = PrivateKey()
k._key = self._id.first
return k
def aesEncrypt(bytes data, str password) -> bytes :
cdef size_t d_len = len(data)
@@ -519,13 +644,22 @@ cdef class DhtRunner(_WithID):
cdef cpp.shared_ptr[cpp.DhtRunner] thisptr
def __cinit__(self):
self.thisptr.reset(new cpp.DhtRunner())
def getId(self):
def getId(self) -> InfoHash:
h = InfoHash()
if self.thisptr:
h._infohash = self.thisptr.get().getId()
return h
def getNodeId(self):
return self.thisptr.get().getNodeId().toString()
def getPublicKey(self) -> PublicKey:
if not self.thisptr:
raise ValueError("DhtRunner is not initialized")
pk = PublicKey()
pk._key = self.thisptr.get().getPublicKey()
return pk
def getNodeId(self) -> InfoHash:
h = InfoHash()
if self.thisptr:
h._infohash = self.thisptr.get().getNodeId()
return h
def ping(self, SockAddr addr, done_cb=None):
if done_cb:
cb_obj = {'done':done_cb}
@@ -681,11 +815,33 @@ cdef class DhtRunner(_WithID):
lock.wait()
return ok
def putEncrypted(self, InfoHash key, InfoHash to, Value val, done_cb=None, bool permanent=False):
def putEncrypted(self, InfoHash key, Value val, to, done_cb=None, bool permanent=False):
if to is None:
raise ValueError("'to' must be provided")
if done_cb:
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().putEncrypted(key._infohash, to._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj), permanent)
try:
if isinstance(to, PublicKey):
self.thisptr.get().putEncrypted(
key._infohash, (<PublicKey>to)._key, val._value,
cpp.bindDoneCb(done_callback, <void*>cb_obj), permanent
)
elif isinstance(to, PkId):
self.thisptr.get().putEncrypted(
key._infohash, (<PkId>to)._pkid, val._value,
cpp.bindDoneCb(done_callback, <void*>cb_obj), permanent
)
elif isinstance(to, InfoHash):
self.thisptr.get().putEncrypted(
key._infohash, (<InfoHash>to)._infohash, val._value,
cpp.bindDoneCb(done_callback, <void*>cb_obj), permanent
)
else:
raise TypeError("'to' must be PublicKey, PkId, or InfoHash")
except:
ref.Py_DECREF(cb_obj)
raise
else:
lock = threading.Condition()
pending = 0
@@ -698,29 +854,7 @@ cdef class DhtRunner(_WithID):
lock.notify()
with lock:
pending += 1
self.putEncrypted(key, to, val, done_cb=tmp_done, permanent=permanent)
while pending > 0:
lock.wait()
return ok
def putEncrypted(self, InfoHash key, PublicKey to, Value val, done_cb=None, bool permanent=False):
if done_cb:
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().putEncrypted(key._infohash, to._key, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj), permanent)
else:
lock = threading.Condition()
pending = 0
ok = False
def tmp_done(ok_ret, nodes):
nonlocal pending, ok, lock
with lock:
ok = ok_ret
pending -= 1
lock.notify()
with lock:
pending += 1
self.putEncrypted(key, to, val, done_cb=tmp_done, permanent=permanent)
self.putEncrypted(key, val, to=to, done_cb=tmp_done, permanent=permanent)
while pending > 0:
lock.wait()
return ok
@@ -763,9 +897,9 @@ cdef class Pht(object):
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
@property
def MAX_NODE_ENTRY_COUNT(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.
+12
View File
@@ -0,0 +1,12 @@
"""
Python package facade for OpenDHT.
This package re-exports the Cython-built core bindings from ``opendht._core``
to preserve the public API (e.g., ``opendht.DhtRunner``), and also exposes a
pure-Python asyncio-friendly wrapper under ``opendht.aio``.
"""
from ._core import * # re-export core Cython bindings
__version__ = version()
__all__ = [name for name in dir() if not name.startswith("_")]
+293
View File
@@ -0,0 +1,293 @@
# Copyright (C) 2014-2025 Savoir-faire Linux Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations
import asyncio
from typing import Any, Callable, Iterable, List, Optional, Tuple
from . import _core as _dht
# Re-export core types for convenience
from ._core import InfoHash, Value, ValueType, Where, SockAddr, PublicKey, PkId, DhtConfig, Identity
class _Listener:
"""Async iterator around DHT listen callback.
Yields tuples (Value, expired: bool).
"""
__slots__ = ("_runner", "_token", "_loop", "_queue", "_closed")
def __init__(self, runner: DhtRunner, key: InfoHash) -> None:
self._runner = runner
self._loop = runner._loop
self._queue: asyncio.Queue[Tuple[Value, bool]] = asyncio.Queue()
self._closed = False
def _on_value(v: Value, expired: bool) -> bool:
if self._closed:
return False
self._loop.call_soon_threadsafe(self._queue.put_nowait, (v, expired))
return True # continue listening
self._token = self._runner._dht.listen(key, _on_value)
def __enter__(self) -> _Listener:
return self
def __exit__(self, exc_type, exc, tb) -> None:
self.cancel()
def __aiter__(self) -> _Listener:
return self
async def __anext__(self) -> Tuple[Value, bool]:
if self._closed:
raise StopAsyncIteration
item = await self._queue.get()
if item is None:
self._closed = True
raise StopAsyncIteration
return item
def cancel(self) -> None:
if self._closed:
return
self._closed = True
try:
self._runner._dht.cancelListen(self._token)
finally:
# Unblock any pending __anext__
self._queue.put_nowait(None)
class _GetStream:
"""Async iterator around DHT get callback.
Yields Value instances as they are found, then ends.
Raises on failure.
"""
__slots__ = ("_runner", "_loop", "_queue", "_closed", "_error")
def __init__(
self,
runner: DhtRunner,
key: InfoHash,
where: Optional[Where],
filter: Optional[Callable[[Value], bool]],
) -> None:
self._runner = runner
self._loop = runner._loop
self._queue: asyncio.Queue[Optional[Value]] = asyncio.Queue()
self._closed = False
self._error: Optional[BaseException] = None
def _on_value(v: Value) -> bool:
# Called on DHT thread
if self._closed:
return False
self._loop.call_soon_threadsafe(self._queue.put_nowait, v)
return True
def _on_done(ok: bool, _nodes: Iterable[Any]) -> None:
# Called on DHT thread
if self._closed:
return
if not ok:
self._error = RuntimeError("DHT get failed")
self._loop.call_soon_threadsafe(self._queue.put_nowait, None)
self._runner._dht.get(key, _on_value, _on_done, filter, where)
def __enter__(self) -> _GetStream:
return self
def __exit__(self, exc_type, exc, tb) -> None:
self.cancel()
def __aiter__(self) -> _GetStream:
return self
async def __anext__(self) -> Value:
if self._closed:
raise StopAsyncIteration
item = await self._queue.get()
if item is None:
self._closed = True
if self._error is not None:
raise self._error
raise StopAsyncIteration
return item
def cancel(self) -> None:
if self._closed:
return
self._closed = True
# Unblock any pending __anext__
self._queue.put_nowait(None)
class DhtRunner:
"""Async wrapper around opendht.DhtRunner.
"""
__slots__ = ("_dht", "_loop", "_config", "_bootstrap")
def __init__(
self,
*,
loop: Optional[asyncio.AbstractEventLoop] = None,
core: Optional[_dht.DhtRunner] = None,
config: Optional[DhtConfig] = None,
bootstrap: Optional[Iterable[Tuple[str, Optional[str]]]] = None,
) -> None:
try:
self._loop = loop or asyncio.get_running_loop()
except RuntimeError:
self._loop = asyncio.get_event_loop()
self._dht = core or _dht.DhtRunner()
self._config = config
self._bootstrap = list(bootstrap) if bootstrap is not None else None
def run(
self,
id: Optional[Identity] = None,
is_bootstrap: bool = False,
port: int = 0,
ipv4: str = "",
ipv6: str = "",
config: Optional[DhtConfig] = None,
) -> None:
cfg = config or self._config or DhtConfig()
self._dht.run(id, is_bootstrap, port, ipv4, ipv6, cfg)
if self._bootstrap:
for host, port_str in self._bootstrap:
self._dht.bootstrap(host, port_str)
def bootstrap(self, host: str, port: Optional[str] = None) -> None:
self._dht.bootstrap(host, port)
async def ping(self, addr: SockAddr) -> bool:
fut: asyncio.Future[bool] = self._loop.create_future()
self._dht.ping(addr, lambda ok: self._loop.call_soon_threadsafe(fut.set_result, bool(ok)))
return await fut
def get(
self,
key: InfoHash,
*,
where: Optional[Where] = None,
filter: Optional[Callable[[Value], bool]] = None,
):
# Return a streaming iterator of values; it ends on completion and raises on failure.
return _GetStream(self, key, where, filter)
async def getAll(
self,
key: InfoHash,
*,
where: Optional[Where] = None,
filter: Optional[Callable[[Value], bool]] = None,
) -> List[Value]:
"""Collect all values for a key and return them as a list."""
results: List[Value] = []
async for v in self.get(key, where=where, filter=filter):
results.append(v)
return results
async def getFirst(
self,
key: InfoHash,
*,
where: Optional[Where] = None,
predicate: Optional[Callable[[Value], Any]] = None,
filter: Optional[Callable[[Value], bool]] = None,
) -> Optional[Value]:
"""Return the first value matching an (optionally async) predicate, or None."""
with self.get(key, where=where, filter=filter) as stream:
async for value in stream:
if predicate is None:
return value
result = predicate(value)
if asyncio.iscoroutine(result):
result = await result
if result:
return value
return None
async def put(self, key: InfoHash, val: Value, *, permanent: bool = False) -> bool:
fut: asyncio.Future[bool] = self._loop.create_future()
def _done(ok: bool, _nodes: Iterable[Any]) -> None:
self._loop.call_soon_threadsafe(fut.set_result, bool(ok))
self._dht.put(key, val, _done, permanent)
return await fut
async def putSigned(self, key: InfoHash, val: Value, *, permanent: bool = False) -> bool:
fut: asyncio.Future[bool] = self._loop.create_future()
def _done(ok: bool, _nodes: Iterable[Any]) -> None:
self._loop.call_soon_threadsafe(fut.set_result, bool(ok))
self._dht.putSigned(key, val, _done, permanent)
return await fut
async def putEncrypted(
self,
key: InfoHash,
to: InfoHash | PublicKey | PkId,
val: Value,
*,
permanent: bool = False,
) -> bool:
fut: asyncio.Future[bool] = self._loop.create_future()
def _done(ok: bool, _nodes: Iterable[Any]) -> None:
self._loop.call_soon_threadsafe(fut.set_result, bool(ok))
self._dht.putEncrypted(key, val, to, _done, permanent)
return await fut
def listen(self, key: InfoHash) -> _Listener:
return _Listener(self, key)
async def cancelListen(self, listener: _Listener) -> None:
await listener.cancel()
async def shutdown(self) -> None:
fut: asyncio.Future[None] = self._loop.create_future()
self._dht.shutdown(lambda: self._loop.call_soon_threadsafe(fut.set_result, None))
await fut
async def join(self) -> None:
await asyncio.to_thread(self._dht.join)
async def __aenter__(self):
if not self.isRunning():
self.run()
return self
async def __aexit__(self, exc_type, exc, tb):
if self.isRunning():
try:
await self.shutdown()
finally:
await self.join()
return False
def __getattr__(self, name: str) -> Any:
return getattr(self._dht, name)
+39 -10
View File
@@ -1,31 +1,29 @@
# Copyright (c) 2015-2023 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
# Copyright (C) 2014-2025 Savoir-faire Linux Inc.
#
# This program is free software; you can redistribute it and/or modify
# 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
# 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
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <https://www.gnu.org/licenses/>.
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from libc.stdint cimport *
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t
from libcpp cimport bool, nullptr_t, nullptr
from libcpp.string cimport string
from libcpp.vector cimport vector
from libcpp.utility cimport pair
from libcpp.map cimport map
from libcpp.memory cimport shared_ptr, make_shared
from libc.string cimport const_char, const_uchar
from libc.string cimport const_char
ctypedef uint16_t in_port_t
ctypedef unsigned short int sa_family_t;
ctypedef unsigned short int sa_family_t
cdef extern from "<chrono>" namespace "std::chrono" nogil:
cdef cppclass duration[ulong]:
@@ -51,6 +49,7 @@ cdef extern from "<future>" namespace "std" nogil:
shared_future[T] share()
cdef extern from "opendht/utils.h" namespace "dht":
const char* version()
cdef cppclass time_point:
@staticmethod
time_point min() const
@@ -74,6 +73,24 @@ cdef extern from "opendht/infohash.h" namespace "dht":
bool operator==(InfoHash) const
bool operator<(InfoHash) const
bool operator bool() const
cdef cppclass PkId:
PkId() except +
PkId(string s) except +
string toString() const
bool getBit(unsigned bit) const
void setBit(unsigned bit, bool b)
double toFloat() const
@staticmethod
unsigned commonBits(PkId a, PkId b)
@staticmethod
PkId get(string s)
@staticmethod
PkId getRandom()
bool operator==(PkId) const
bool operator<(PkId) const
bool operator bool() const
cdef extern from "opendht/sockaddr.h" namespace "dht":
cdef cppclass SockAddr:
@@ -101,6 +118,7 @@ cdef extern from "opendht/crypto.h" namespace "dht::crypto":
PrivateKey()
shared_ptr[PublicKey] getSharedPublicKey() const
Blob decrypt(Blob data) const
Blob sign(Blob data) const
@staticmethod
PrivateKey generate()
@staticmethod
@@ -109,12 +127,16 @@ cdef extern from "opendht/crypto.h" namespace "dht::crypto":
cdef cppclass PublicKey:
PublicKey()
InfoHash getId() const
PkId getLongId() const
Blob encrypt(Blob data) const
bool checkSignature(Blob data, Blob signature) const
bool operator==(PublicKey) const
cdef cppclass Certificate:
Certificate()
Certificate(string pem)
InfoHash getId() const
PkId getLongId() const
string toString() const
string getName() const
void revoke(PrivateKey key, Certificate cert)
@@ -255,6 +277,7 @@ cdef extern from "opendht/dhtrunner.h" namespace "dht":
SockAddr bind6
InfoHash getId() const
shared_ptr[PublicKey] getPublicKey() const
InfoHash getNodeId() const
void bootstrap(const_char*, const_char*)
void bootstrap(const SockAddr&, DoneCallbackSimple done_cb)
@@ -272,6 +295,7 @@ cdef extern from "opendht/dhtrunner.h" namespace "dht":
void put(InfoHash key, shared_ptr[Value] val, DoneCallback done_cb, time_point created, bool permanent)
void putSigned(InfoHash key, shared_ptr[Value] val, DoneCallback done_cb, bool permanent)
void putEncrypted(InfoHash key, InfoHash to, shared_ptr[Value] val, DoneCallback done_cb, bool permanent)
void putEncrypted(InfoHash key, PkId to, shared_ptr[Value] val, DoneCallback done_cb, bool permanent)
void putEncrypted(InfoHash key, shared_ptr[PublicKey] to, shared_ptr[Value] val, DoneCallback done_cb, bool permanent)
void cancelPut(InfoHash key, shared_ptr[Value] val)
ListenToken listen(InfoHash key, ValueCallback get_cb)
@@ -303,3 +327,8 @@ cdef extern from "opendht/indexation/pht.h" namespace "dht::indexation":
void insert(IndexKey k, IndexValue v, DoneCallbackSimple cb)
@staticmethod
LookupCallback bindLookupCb(LookupCallbackRaw cb, void *user_data)
cdef extern from "gnutls/gnutls.h" nogil:
int gnutls_global_init()
void gnutls_global_deinit()
const char* gnutls_strerror(int error)
+45
View File
@@ -1,3 +1,48 @@
[build-system]
requires = ["setuptools", "wheel", "Cython"]
build-backend = "setuptools.build_meta"
[tool.cibuildwheel]
build = [
'cp3{9,10,11,12,13}-manylinux_x86_64',
'cp3{10,11,12,13}-manylinux_aarch64',
'cp3{11,12,13}-macosx_x86_64',
'cp3{11,12,13}-macosx_arm64',
'cp3{11,12,13}-win_amd64',
]
[tool.cibuildwheel.linux]
manylinux-x86_64-image = 'manylinux_2_34'
manylinux-aarch64-image = 'manylinux_2_34'
before-all = [
'dnf install -y epel-release',
'dnf install -y gnutls-devel msgpack-devel readline-devel libargon2-devel asio-devel fmt-devel',
]
before-build = [
'pip install cython',
'cmake -DOPENDHT_PYTHON=ON -DOPENDHT_TOOLS=OFF -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release .',
'cmake --build .',
]
# Point auditwheel to libopendht.so.* in the current dir when repairing
repair-wheel-command = 'LD_LIBRARY_PATH=$PWD auditwheel repair -w {dest_dir} {wheel}'
[tool.cibuildwheel.macos]
environment = { MACOSX_DEPLOYMENT_TARGET = "15.0" }
before-all = [
'brew update',
'brew install gnutls msgpack-cxx readline argon2 asio fmt',
]
before-build = [
'pip install cython delocate',
'cmake -DOPENDHT_PYTHON=ON -DOPENDHT_TOOLS=OFF -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release .',
'cmake --build .',
]
# Bundle dependent dylibs into the wheel; ensure local libopendht.dylib is found
repair-wheel-command = 'DYLD_LIBRARY_PATH=$PWD delocate-wheel -w {dest_dir} {wheel}'
[tool.cibuildwheel.windows]
# Configure first, then from 'build' directory run: with pipx run cibuildwheel python
before-build = [
'cmake --build . --config Release',
]
repair-wheel-command = "delvewheel repair -w {dest_dir} {wheel} --add-path ./Release --add-path ./vcpkg_installed/x64-windows-release/bin"
+58 -36
View File
@@ -1,55 +1,77 @@
# Copyright (C) 2014-2025 Savoir-faire Linux Inc.
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# A Python3 wrapper to access to OpenDHT API
# This wrapper is written for Cython 0.22
# 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 file is part of OpenDHT Python Wrapper.
#
# OpenDHT Python Wrapper 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.
#
# OpenDHT Python Wrapper 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 OpenDHT Python Wrapper. If not, see <https://www.gnu.org/licenses/>.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from setuptools import setup, Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext
from setuptools import setup, Extension, find_packages
from setuptools.command.build_ext import build_ext as _build_ext
import os
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'README.md'), 'r', encoding='utf-8') as f:
long_description = f.read()
extra_compile_args = {
'msvc': ['/std:c++17', '/EHsc', '/utf-8'],
'unix': ['-std=c++17'],
}
extra_link_args = {
'msvc': ['wsock32.lib', 'ws2_32.lib'],
'unix': ['-std=c++17']
}
extra_libraries = {
'msvc': ['opendht_import', 'gnutls'],
'unix': ['opendht']
}
class build_ext(_build_ext):
def build_extensions(self):
compile_args = extra_compile_args.get(self.compiler.compiler_type, [])
link_args = extra_link_args.get(self.compiler.compiler_type, [])
libraries = extra_libraries.get(self.compiler.compiler_type, ['opendht'])
for ext in self.extensions:
ext.extra_compile_args.extend(compile_args)
ext.extra_link_args.extend(link_args)
ext.libraries = libraries
super().build_extensions()
setup(name="opendht",
version="@PACKAGE_VERSION@",
description="Python wrapper for OpenDHT",
description="OpenDHT: A lightweight Distributed Hash Table",
long_description=long_description,
long_description_content_type="text/markdown",
url='https://github.com/savoirfairelinux/opendht',
author="Adrien Béraud, Guillaume Roguez, Simon Désaulniers",
license="GPLv3",
author="Adrien Beraud <adrien.beraud@savoirfairelinux.com>",
license="GPL-3.0-or-later",
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: System :: Distributed Computing',
'Topic :: System :: Networking'
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
'Topic :: System :: Networking',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.9',
],
cmdclass = { 'build_ext' : build_ext },
ext_modules = cythonize(Extension(
"opendht",
cmdclass=dict(build_ext=build_ext),
packages=find_packages(where='@CURRENT_SOURCE_DIR@'),
package_dir={"": "@CURRENT_SOURCE_DIR@"},
ext_modules=[Extension(
"opendht._core",
["@CURRENT_SOURCE_DIR@/opendht.pyx"],
include_dirs = ['@PROJECT_SOURCE_DIR@/include'],
language="c++",
extra_compile_args=["-std=c++17"],
extra_link_args=["-std=c++17"],
libraries=["opendht"],
library_dirs = ['@CURRENT_BINARY_DIR@', '@PROJECT_BINARY_DIR@']
))
extra_compile_args=["-DMSGPACK_NO_BOOST", "-DMSGPACK_DISABLE_LEGACY_NIL", "-DMSGPACK_DISABLE_LEGACY_CONVERT", "-DOPENDHT_INDEXATION", "-Dopendht_EXPORTS"],
libraries=["opendht", "gnutls"],
include_dirs = ['@PROJECT_SOURCE_DIR@/include'@OPENDHT_PYTHON_INCLUDE_DIRS@],
library_dirs = ['@CURRENT_BINARY_DIR@', '@PROJECT_BINARY_DIR@'@OPENDHT_PYTHON_LIBRARY_DIRS@]
)]
)
+46 -48
View File
@@ -15,64 +15,62 @@
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <https://www.gnu.org/licenses/>.
import opendht as dht
import time
import asyncio
import time
config = dht.DhtConfig()
config.setRateLimit(-1, -1)
from opendht import aio as dht
ping_node = dht.DhtRunner()
ping_node.run(config=config)
#ping_node.enableLogging()
#ping_node.bootstrap("bootstrap.jami.net", "4222")
pong_node = dht.DhtRunner()
pong_node.run(config=config)
#pong_node.enableLogging()
pong_node.ping(ping_node.getBound())
loc_ping = dht.InfoHash.get("toto99")
loc_pong = dht.InfoHash.get(str(loc_ping))
async def main():
config = dht.DhtConfig()
config.setRateLimit(-1, -1)
net = []
for i in range(1,10):
node = dht.DhtRunner()
node.run(config=config)
node.ping(ping_node.getBound())
net.append(node)
ping_node = dht.DhtRunner()
pong_node = dht.DhtRunner()
# ping_node.enableLogging()
# pong_node.enableLogging()
# ping_node.bootstrap("bootstrap.jami.net", "4222")
ping_node.run(config=config)
pong_node.run(config=config)
await pong_node.ping(ping_node.getBound())
i = 0
MAX = 2048
net = [dht.DhtRunner() for _ in range(1, 10)]
for n in net:
n.run(config=config)
n.ping(ping_node.getBound())
loop = asyncio.get_event_loop()
MAX = 2048
counter = 0
loc_ping = dht.InfoHash.get(f"ping-{ping_node.getNodeId()}")
loc_pong = dht.InfoHash.get(str(loc_ping))
def done(h, ok):
pass
#print(h, "over", ok)
async def ponger(listener_node: dht.DhtRunner, listen_key, responder_node: dht.DhtRunner, respond_key):
nonlocal counter
with listener_node.listen(listen_key) as listener:
async for value, expired in listener:
if not expired:
await responder_node.put(respond_key, dht.Value(b"hey"))
counter += 1
if counter >= MAX:
break
def ping(node, h):
global i
i += 1
if i < MAX:
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
else:
loop.stop()
start = time.time()
await asyncio.gather(
ponger(ping_node, loc_ping, pong_node, loc_pong),
ponger(pong_node, loc_pong, ping_node, loc_ping),
pong_node.put(loc_ping, dht.Value(b"hey"))
)
duration = time.time() - start
def pong(node, h):
#print(node.getNodeId().decode(), "got ping", h, i)
loop.call_soon_threadsafe(ping, node, h)
return True
await asyncio.gather(
ping_node.shutdown(),
pong_node.shutdown(),
*(n.shutdown() for n in net),
)
t1 = time.time()
print(MAX, "ping-pong done, took", duration, "s")
print(1000 * duration / MAX, "ms per rt", MAX / duration, "rt per s")
ping_node.listen(loc_ping, lambda v, e: pong(pong_node, loc_pong) if not e else True)
pong_node.listen(loc_pong, lambda v, e: pong(ping_node, loc_ping) if not e else True)
ping(pong_node, loc_ping)
loop.run_forever()
t2 = time.time()
print(MAX, "ping-pong done, took", t2 - t1, "s")
print(1000 * (t2 - t1)/MAX, "ms per rt", MAX/(t2 - t1), "rt per s")
if __name__ == "__main__":
asyncio.run(main())
+5 -6
View File
@@ -1,19 +1,18 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2023 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Copyright (C) 2014-2025 Savoir-faire Linux Inc.
#
# This program is free software; you can redistribute it and/or modify
# 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
# 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
# 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/>.
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import time, sys, os
from pprint import pprint
+2 -2
View File
@@ -1,7 +1,7 @@
lib_LTLIBRARIES = libopendht.la
libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@ @OpenSSL_CFLAGS@ @Fmt_CFLAGS@
libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@ @OpenSSL_LIBS@ @Fmt_LIBS@
libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@ @OpenSSL_CFLAGS@ @Fmt_CFLAGS@ @Llhttp_CFLAGS@ @Liburing_CFLAGS@ @simdutf_CFLAGS@
libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@ @OpenSSL_LIBS@ @Fmt_LIBS@ @Llhttp_LIBS@ @Liburing_LIBS@ @simdutf_LIBS@
libopendht_la_LDFLAGS = @LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_SOURCES = \
dht.cpp \
+15 -112
View File
@@ -17,127 +17,30 @@
#include "base64.h"
#include <simdutf.h>
#include <vector>
#include <cstdint>
#include <cstdlib>
/* Mainly based on the following stackoverflow question:
* http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
*/
static const char encoding_table[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2',
'3', '4', '5', '6', '7', '8', '9', '+', '/'
};
static const size_t mod_table[] = { 0, 2, 1 };
char *base64_encode(const uint8_t *input, size_t input_length,
char *output, size_t *output_length)
{
size_t i, j;
size_t out_sz = *output_length;
*output_length = 4 * ((input_length + 2) / 3);
if (out_sz < *output_length || output == nullptr)
return nullptr;
for (i = 0, j = 0; i < input_length; ) {
uint8_t octet_a = i < input_length ? input[i++] : 0;
uint8_t octet_b = i < input_length ? input[i++] : 0;
uint8_t octet_c = i < input_length ? input[i++] : 0;
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
output[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
output[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
output[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
output[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
}
for (i = 0; i < mod_table[input_length % 3]; i++)
output[*output_length - 1 - i] = '=';
return output;
}
uint8_t *base64_decode(const char *input, size_t input_length,
uint8_t *output, size_t *output_length)
{
size_t i, j;
uint8_t decoding_table[256];
uint8_t c;
for (c = 0; c < 64; c++)
decoding_table[static_cast<int>(encoding_table[c])] = c;
if (input_length % 4 != 0 || input_length < 2)
return nullptr;
size_t out_sz = *output_length;
*output_length = input_length / 4 * 3;
if (input[input_length - 1] == '=')
(*output_length)--;
if (input[input_length - 2] == '=')
(*output_length)--;
if (out_sz < *output_length || output == nullptr)
return nullptr;
for (i = 0, j = 0; i < input_length;) {
uint8_t sextet_a = input[i] == '=' ? 0 & i++
: decoding_table[static_cast<int>(input[i++])];
uint8_t sextet_b = input[i] == '=' ? 0 & i++
: decoding_table[static_cast<int>(input[i++])];
uint8_t sextet_c = input[i] == '=' ? 0 & i++
: decoding_table[static_cast<int>(input[i++])];
uint8_t sextet_d = input[i] == '=' ? 0 & i++
: decoding_table[static_cast<int>(input[i++])];
uint32_t triple = (sextet_a << 3 * 6) +
(sextet_b << 2 * 6) +
(sextet_c << 1 * 6) +
(sextet_d << 0 * 6);
if (j < *output_length)
output[j++] = (triple >> 2 * 8) & 0xFF;
if (j < *output_length)
output[j++] = (triple >> 1 * 8) & 0xFF;
if (j < *output_length)
output[j++] = (triple >> 0 * 8) & 0xFF;
}
return output;
}
std::string
base64_encode(const std::vector<uint8_t>::const_iterator begin,
const std::vector<uint8_t>::const_iterator end)
{
size_t output_length = 4 * ((std::distance(begin, end) + 2) / 3);
std::string out;
out.resize(output_length);
base64_encode(&(*begin), std::distance(begin, end),
&(*out.begin()), &output_length);
out.resize(output_length);
return out;
}
std::string
base64_encode(const std::vector<unsigned char>& str)
{
return base64_encode(str.cbegin(), str.cend());
std::string buffer(simdutf::base64_length_from_binary(str.size()), '\0');
simdutf::binary_to_base64((const char*)str.data(), str.size(), buffer.data());
return buffer;
}
std::vector<unsigned char>
base64_decode(const std::string& str)
{
size_t output_length = str.length() / 4 * 3 + 2;
std::vector<uint8_t> output;
output.resize(output_length);
base64_decode(str.data(), str.size(), output.data(), &output_length);
output.resize(output_length);
return output;
std::vector<unsigned char> buffer(simdutf::maximal_binary_length_from_base64(str.data(), str.size()));
simdutf::result r = simdutf::base64_to_binary(str.data(), str.size(), (char *)buffer.data());
if(r.error) {
// Decoding error, return an empty vector
return std::vector<unsigned char>();
} else {
buffer.resize(r.count); // resize the buffer according to actual number of bytes
}
return buffer;
}
-2
View File
@@ -51,6 +51,4 @@
typedef int mode_t;
#include <BaseTsd.h>
#define usleep(x) Sleep((x) / 1000)
#endif
+151 -72
View File
@@ -79,6 +79,31 @@ bool aesKeySizeGood(size_t key_size)
return false;
}
class Spki {
public:
Spki() {
gnutls_x509_spki_init(&spki);
}
Spki(gnutls_pubkey_t pubkey): Spki() {
auto err = gnutls_pubkey_get_spki(pubkey, spki, 0);
if (err < 0) {
gnutls_x509_spki_deinit(spki);
throw CryptoException(fmt::format("Unable to get SPKI from public key: {}", gnutls_strerror(err)));
}
}
~Spki() {
gnutls_x509_spki_deinit(spki);
}
inline gnutls_x509_spki_t& get() {
return spki;
}
private:
gnutls_x509_spki_t spki;
};
#ifndef GCM_DIGEST_SIZE
#define GCM_DIGEST_SIZE GCM_BLOCK_SIZE
#endif
@@ -86,7 +111,7 @@ bool aesKeySizeGood(size_t key_size)
Blob aesEncrypt(const uint8_t* data, size_t data_length, const Blob& key)
{
if (not aesKeySizeGood(key.size()))
throw DecryptError("Wrong key size");
throw DecryptError("Incorrect key size");
Blob ret(data_length + GCM_IV_SIZE + GCM_DIGEST_SIZE);
{
@@ -127,10 +152,10 @@ Blob aesEncrypt(const Blob& data, std::string_view password, const Blob& salt)
Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key)
{
if (not aesKeySizeGood(key.size()))
throw DecryptError("Wrong key size");
throw DecryptError("Incorrect key size");
if (data_length <= GCM_IV_SIZE + GCM_DIGEST_SIZE)
throw DecryptError("Wrong data size");
throw DecryptError("Incorrect data size");
std::array<uint8_t, GCM_DIGEST_SIZE> digest;
@@ -158,7 +183,7 @@ Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key)
}
if (not std::equal(digest.begin(), digest.end(), data + data_length - GCM_DIGEST_SIZE)) {
throw DecryptError("Can't decrypt data");
throw DecryptError("Unable to decrypt data");
}
return ret;
@@ -175,14 +200,14 @@ Blob aesDecrypt(const uint8_t* data, size_t data_length, std::string_view passwo
Blob aesGetSalt(const uint8_t* data, size_t data_length)
{
if (data_length <= PASSWORD_SALT_LENGTH)
throw DecryptError("Wrong data size");
throw DecryptError("Incorrect data size");
return Blob {data, data+PASSWORD_SALT_LENGTH};
}
std::string_view aesGetEncrypted(const uint8_t* data, size_t data_length)
{
if (data_length <= PASSWORD_SALT_LENGTH)
throw DecryptError("Wrong data size");
throw DecryptError("Incorrect data size");
return std::string_view((const char*)(data+PASSWORD_SALT_LENGTH), data_length - PASSWORD_SALT_LENGTH);
}
@@ -212,7 +237,7 @@ Blob stretchKey(std::string_view password, Blob& salt, size_t key_length)
res.resize(32);
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 !");
throw CryptoException("Unable to compute Argon2i.");
return hash(res, key_length);
}
@@ -224,7 +249,7 @@ Blob hash(const Blob& data, size_t hash_len)
res.resize(res_size);
const gnutls_datum_t gdat {(uint8_t*)data.data(), (unsigned)data.size()};
if (auto err = gnutls_fingerprint(algo, &gdat, res.data(), &res_size))
throw CryptoException(std::string("Can't compute hash: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to compute hash: ") + gnutls_strerror(err));
res.resize(std::min(hash_len, res_size));
return res;
}
@@ -235,7 +260,7 @@ void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_le
size_t res_size = hash_length;
const gnutls_datum_t gdat {(uint8_t*)data, (unsigned)data_length};
if (auto err = gnutls_fingerprint(algo, &gdat, hash, &res_size))
throw CryptoException(std::string("Can't compute hash: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to compute hash: ") + gnutls_strerror(err));
}
PrivateKey::PrivateKey()
@@ -246,7 +271,7 @@ PrivateKey::PrivateKey(gnutls_x509_privkey_t k) : x509_key(k)
gnutls_privkey_init(&key);
if (gnutls_privkey_import_x509(key, k, GNUTLS_PRIVKEY_IMPORT_COPY) != GNUTLS_E_SUCCESS) {
key = nullptr;
throw CryptoException("Can't load generic private key !");
throw CryptoException("Unable to load generic private key.");
}
}
@@ -254,7 +279,7 @@ PrivateKey::PrivateKey(const uint8_t* src, size_t src_size, const char* password
{
int err = gnutls_x509_privkey_init(&x509_key);
if (err != GNUTLS_E_SUCCESS)
throw CryptoException("Can't initialize private key !");
throw CryptoException("Unable to initialize private key.");
const gnutls_datum_t dt {(uint8_t*)src, static_cast<unsigned>(src_size)};
int flags = (password_ptr == NULL || strlen(password_ptr)==0) ? GNUTLS_PKCS_PLAIN
@@ -267,16 +292,16 @@ PrivateKey::PrivateKey(const uint8_t* src, size_t src_size, const char* password
if (err_der != GNUTLS_E_SUCCESS) {
gnutls_x509_privkey_deinit(x509_key);
if (err == GNUTLS_E_DECRYPTION_FAILED or err_der == GNUTLS_E_DECRYPTION_FAILED)
throw DecryptError("Can't decrypt private key");
throw DecryptError("Unable to decrypt private key");
else
throw CryptoException(std::string("Can't load private key: PEM: ") + gnutls_strerror(err)
throw CryptoException(std::string("Unable to load private key: PEM: ") + gnutls_strerror(err)
+ " DER: " + gnutls_strerror(err_der));
}
}
gnutls_privkey_init(&key);
if (gnutls_privkey_import_x509(key, x509_key, GNUTLS_PRIVKEY_IMPORT_COPY) != GNUTLS_E_SUCCESS) {
throw CryptoException("Can't load generic private key !");
throw CryptoException("Unable to load generic private key.");
}
}
@@ -318,13 +343,13 @@ Blob
PrivateKey::sign(const uint8_t* data, size_t data_length) const
{
if (!key)
throw CryptoException("Can't sign data: no private key set !");
throw CryptoException("Unable to sign data: no private key set.");
if (std::numeric_limits<unsigned>::max() < data_length)
throw CryptoException("Can't sign data: too large !");
throw CryptoException("Unable to sign data: too large.");
gnutls_datum_t sig {nullptr, 0};
const gnutls_datum_t dat {(unsigned char*)data, (unsigned)data_length};
if (gnutls_privkey_sign_data(key, GNUTLS_DIG_SHA512, 0, &dat, &sig) != GNUTLS_E_SUCCESS)
throw CryptoException("Can't sign data !");
throw CryptoException("Unable to sign data.");
Blob ret(sig.data, sig.data+sig.size);
gnutls_free(sig.data);
return ret;
@@ -337,7 +362,7 @@ PrivateKey::decryptBloc(const uint8_t* src, size_t src_size) const
gnutls_datum_t out {nullptr, 0};
int err = gnutls_privkey_decrypt_data(key, 0, &dat, &out);
if (err != GNUTLS_E_SUCCESS)
throw DecryptError(std::string("Can't decrypt data: ") + gnutls_strerror(err));
throw DecryptError(std::string("Unable to decrypt data: ") + gnutls_strerror(err));
Blob ret {out.data, out.data+out.size};
gnutls_free(out.data);
return ret;
@@ -347,13 +372,17 @@ Blob
PrivateKey::decrypt(const uint8_t* cypher, size_t cypher_len) const
{
if (!key)
throw CryptoException("Can't decrypt data without private key !");
throw CryptoException("Unable to decrypt data without private key.");
unsigned key_len = 0;
int err = gnutls_privkey_get_pk_algorithm(key, &key_len);
if (err < 0)
throw CryptoException("Can't read public key length !");
if (err != GNUTLS_PK_RSA)
int algo = gnutls_privkey_get_pk_algorithm(key, &key_len);
if (algo < 0)
throw CryptoException("Unable to read public key length.");
if (algo != GNUTLS_PK_RSA
#if GNUTLS_VERSION_NUMBER >= 0x030804
&& algo != GNUTLS_PK_RSA_OAEP
#endif
)
throw CryptoException("Must be an RSA key");
unsigned cypher_block_sz = key_len / 8;
@@ -405,7 +434,7 @@ PrivateKey::getSharedPublicKey() const
if (not publicKey_) {
auto pk = std::make_shared<PublicKey>();
if (auto err = gnutls_pubkey_import_privkey(pk->pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to retreive public key: ") + gnutls_strerror(err));
publicKey_ = std::move(pk);
}
return publicKey_;
@@ -414,7 +443,7 @@ PrivateKey::getSharedPublicKey() const
PublicKey::PublicKey()
{
if (auto err = gnutls_pubkey_init(&pk))
throw CryptoException(std::string("Can't initialize public key: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to initialize public key: ") + gnutls_strerror(err));
}
PublicKey::PublicKey(const uint8_t* dat, size_t dat_size) : PublicKey()
@@ -515,7 +544,7 @@ PublicKey::encryptBloc(const uint8_t* src, size_t src_size, uint8_t* dst, size_t
gnutls_datum_t encrypted {nullptr, 0};
auto err = gnutls_pubkey_encrypt_data(pk, 0, &key_dat, &encrypted);
if (err != GNUTLS_E_SUCCESS)
throw CryptoException(std::string("Can't encrypt data: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to encrypt data: ") + gnutls_strerror(err));
if (encrypted.size != dst_size)
throw CryptoException("Unexpected cypherblock size");
std::copy_n(encrypted.data, encrypted.size, dst);
@@ -526,18 +555,37 @@ Blob
PublicKey::encrypt(const uint8_t* data, size_t data_len) const
{
if (!pk)
throw CryptoException("Can't read public key !");
throw CryptoException("Unable to read public key.");
unsigned key_len = 0;
int err = gnutls_pubkey_get_pk_algorithm(pk, &key_len);
if (err < 0)
throw CryptoException("Can't read public key length !");
if (err != GNUTLS_PK_RSA)
int algo = gnutls_pubkey_get_pk_algorithm(pk, &key_len);
if (algo < 0)
throw CryptoException("Unable to read public key length.");
unsigned max_block_sz = 0;
if (algo == GNUTLS_PK_RSA) {
max_block_sz = key_len / 8 - 11;
}
#if GNUTLS_VERSION_NUMBER >= 0x030804
else if (algo == GNUTLS_PK_RSA_OAEP) {
Spki spki(pk);
gnutls_digest_algorithm_t dig;
gnutls_datum_t label = {nullptr, 0};
if (gnutls_x509_spki_get_rsa_oaep_params(spki.get(), &dig, &label) < 0) {
throw CryptoException("Unable to get OAEP params");
}
size_t hash_size = gnutlsHashSize(dig);
if (hash_size == 0) {
throw CryptoException("Invalid digest algorithm for OAEP: GNUTLS_DIG_UNKNOWN");
}
max_block_sz = key_len / 8 - 2 * hash_size - 2 - label.size;
}
#endif
else {
throw CryptoException("Must be an RSA key");
const unsigned max_block_sz = key_len / 8 - 11;
}
const unsigned cypher_block_sz = key_len / 8;
/* Use plain RSA if the data is small enough */
if (data_len <= max_block_sz) {
Blob ret(cypher_block_sz);
@@ -574,9 +622,9 @@ PublicKey::getId() const
InfoHash id;
size_t sz = id.size();
if (auto err = gnutls_pubkey_get_key_id(pk, 0, id.data(), &sz))
throw CryptoException(std::string("Can't get public key ID: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to get public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get public key ID: wrong output length.");
throw CryptoException("Unable to get public key ID: incorrect output length.");
cachedId_ = id;
idCached_.store(true);
}
@@ -590,9 +638,9 @@ PublicKey::getLongId() const
PkId h;
size_t sz = h.size();
if (auto err = gnutls_pubkey_get_key_id(pk, GNUTLS_KEYID_USE_SHA256, h.data(), &sz))
throw CryptoException(std::string("Can't get 256 bits public key ID: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to get 256-bit public key ID: ") + gnutls_strerror(err));
if (sz != h.size())
throw CryptoException("Can't get 256 bits public key ID: wrong output length.");
throw CryptoException("Unable to get 256-bit public key ID: incorrect output length.");
cachedLongId_ = h;
longIdCached_.store(true);
}
@@ -661,14 +709,14 @@ readDN(gnutls_x509_crq_t request, const char* oid)
CertificateRequest::CertificateRequest()
{
if (auto err = gnutls_x509_crq_init(&request))
throw CryptoException(std::string("Can't initialize certificate request: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to initialize certificate request: ") + gnutls_strerror(err));
}
CertificateRequest::CertificateRequest(const uint8_t* data, size_t size) : CertificateRequest()
{
const gnutls_datum_t dat {(uint8_t*)data, (unsigned)size};
if (auto err = gnutls_x509_crq_import(request, &dat, GNUTLS_X509_FMT_PEM))
throw CryptoException(std::string("Can't import certificate request: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to import certificate request: ") + gnutls_strerror(err));
}
CertificateRequest::~CertificateRequest()
@@ -727,14 +775,14 @@ CertificateRequest::sign(const PrivateKey& key, const std::string& password)
gnutls_x509_crq_set_challenge_password(request, password.c_str());
if (auto err = gnutls_x509_crq_set_key(request, key.x509_key))
throw CryptoException(std::string("Can't set certificate request key: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to set certificate request key: ") + gnutls_strerror(err));
#if GNUTLS_VERSION_NUMBER < 0x030601
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, key.getPublicKey().getPreferredDigest(), 0))
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to sign certificate request: ") + gnutls_strerror(err));
#else
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, GNUTLS_DIG_UNKNOWN, 0))
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to sign certificate request: ") + gnutls_strerror(err));
#endif
}
@@ -749,7 +797,7 @@ CertificateRequest::pack() const
{
gnutls_datum_t dat {nullptr, 0};
if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat))
throw CryptoException(std::string("Can't export certificate request: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to export certificate request: ") + gnutls_strerror(err));
Blob ret(dat.data, dat.data + dat.size);
gnutls_free(dat.data);
return ret;
@@ -760,7 +808,7 @@ CertificateRequest::toString() const
{
gnutls_datum_t dat {nullptr, 0};
if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat))
throw CryptoException(std::string("Can't export certificate request: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to export certificate request: ") + gnutls_strerror(err));
std::string ret(dat.data, dat.data + dat.size);
gnutls_free(dat.data);
return ret;
@@ -891,7 +939,7 @@ Certificate::getSharedPublicKey() const
if (not publicKey_) {
auto pk = std::make_shared<PublicKey>();
if (auto err = gnutls_pubkey_import_x509(pk->pk, cert, 0))
throw CryptoException(std::string("Can't get certificate public key: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to get certificate public key: ") + gnutls_strerror(err));
publicKey_ = std::move(pk);
}
return publicKey_;
@@ -904,9 +952,9 @@ Certificate::getId() const
InfoHash id;
size_t sz = id.size();
if (auto err = gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz))
throw CryptoException(std::string("Can't get certificate public key ID: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to get certificate public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get certificate public key ID: wrong output length.");
throw CryptoException("Unable to get certificate public key ID: incorrect output length.");
cachedId_ = id;
idCached_.store(true);
}
@@ -920,9 +968,9 @@ Certificate::getLongId() const
PkId id;
size_t sz = id.size();
if (auto err = gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, id.data(), &sz))
throw CryptoException(std::string("Can't get certificate 256 bits public key ID: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to get certificate 256-bit public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get certificate 256 bits public key ID: wrong output length.");
throw CryptoException("Unable to get certificate 256-bit public key ID: incorrect output length.");
cachedLongId_ = id;
longIdCached_.store(true);
}
@@ -1129,15 +1177,46 @@ Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
// PrivateKey
PrivateKey
PrivateKey::generate(unsigned key_length)
PrivateKey::generate(unsigned key_length, gnutls_pk_algorithm_t algo)
{
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_RSA, key_length, 0);
if (err != GNUTLS_E_SUCCESS) {
throw CryptoException("Unable to initialize private key.");
if (algo == GNUTLS_PK_RSA) {
int err = gnutls_x509_privkey_generate(key, algo, key_length, 0);
if (err != GNUTLS_E_SUCCESS) {
gnutls_x509_privkey_deinit(key);
throw CryptoException(std::string("Unable to generate RSA key pair: ") + gnutls_strerror(err));
}
}
#if GNUTLS_VERSION_NUMBER >= 0x030804
else if (algo == GNUTLS_PK_RSA_OAEP) {
int err;
Spki spki;
err = gnutls_x509_spki_set_rsa_oaep_params(spki.get(), GNUTLS_DIG_SHA256, nullptr);
if (err != GNUTLS_E_SUCCESS) {
gnutls_x509_privkey_deinit(key);
throw CryptoException(std::string("Unable to set RSA-OAEP params: ") + gnutls_strerror(err));
}
/*gnutls_keygen_data_st params;
params.type = GNUTLS_KEYGEN_SPKI;
params.data = (uint8_t*)&spki.get();
params.size = spki.size();*/
err = gnutls_x509_privkey_generate2(key, algo, key_length, 0, nullptr, 0);
if (err != GNUTLS_E_SUCCESS) {
gnutls_x509_privkey_deinit(key);
throw CryptoException(std::string("Unable to generate RSA key pair: ") + gnutls_strerror(err));
}
err = gnutls_x509_privkey_set_spki(key, spki.get(), 0);
if (err != GNUTLS_E_SUCCESS) {
gnutls_x509_privkey_deinit(key);
throw CryptoException(std::string("Unable to set SPKI: ") + gnutls_strerror(err));
}
}
#endif
else {
gnutls_x509_privkey_deinit(key);
throw CryptoException(std::string("Can't generate RSA key pair: ") + gnutls_strerror(err));
throw CryptoException("Only RSA and RSA-OAEP keys are supported");
}
return PrivateKey{key};
}
@@ -1147,11 +1226,11 @@ PrivateKey::generateEC()
{
gnutls_x509_privkey_t key;
if (gnutls_x509_privkey_init(&key) != GNUTLS_E_SUCCESS)
throw CryptoException("Can't initialize private key.");
throw CryptoException("Unable to 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));
throw CryptoException(std::string("Unable to generate EC key pair: ") + gnutls_strerror(err));
}
return PrivateKey{key};
}
@@ -1328,20 +1407,20 @@ Certificate::generate(const CertificateRequest& request, const Identity& ca, int
{
gnutls_x509_crt_t cert;
if (auto err = gnutls_x509_crt_init(&cert))
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to initialize certificate: ") + gnutls_strerror(err));
Certificate ret {cert};
if (auto err = gnutls_x509_crt_set_crq(cert, request.get()))
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to initialize certificate: ") + gnutls_strerror(err));
if (auto err = gnutls_x509_crt_set_version(cert, 3)) {
throw CryptoException(std::string("Can't set certificate version: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to set certificate version: ") + gnutls_strerror(err));
}
setValidityPeriod(cert, validity <= 0 ? 10 * 365 * 24 * 60 * 60 : validity);
setRandomSerial(cert);
if (auto err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) {
throw CryptoException(std::string("Can't sign certificate: ") + gnutls_strerror(err));
throw CryptoException(std::string("Unable to sign certificate: ") + gnutls_strerror(err));
}
ret.issuer = ca.second;
@@ -1628,7 +1707,7 @@ 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));
throw CryptoException(std::string("Unable to export CRL: ") + gnutls_strerror(err));
}
b.insert(b.end(), gdat.data, gdat.data + gdat.size);
gnutls_free(gdat.data);
@@ -1638,11 +1717,11 @@ 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!");
throw CryptoException("Unable to 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)
throw CryptoException(std::string("Unable to load CRL: PEM: ") + gnutls_strerror(err_pem)
+ " DER: " + gnutls_strerror(err_der));
}
}
@@ -1667,7 +1746,7 @@ 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));
throw CryptoException(std::string("Unable to check certificate revocation status: ") + gnutls_strerror(ret));
return ret != 0;
}
@@ -1677,7 +1756,7 @@ RevocationList::revoke(const Certificate& crt, std::chrono::system_clock::time_p
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));
throw CryptoException(std::string("Unable to revoke certificate: ") + gnutls_strerror(err));
}
static std::string
@@ -1753,13 +1832,13 @@ 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));
throw CryptoException(std::string("Unable to 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));
throw CryptoException(std::string("Unable to 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));
throw CryptoException(std::string("Unable to set CRL next update time: ") + gnutls_strerror(err));
uint64_t number {0};
size_t number_sz {sizeof(number)};
unsigned critical {0};
@@ -1772,9 +1851,9 @@ RevocationList::sign(const PrivateKey& key, const Certificate& ca, duration vali
} 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));
throw CryptoException(std::string("Unable to 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));
throw CryptoException(std::string("Unable to 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());
@@ -1786,7 +1865,7 @@ 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;
//std::cout << "Unable to verify CRL: " << err << " " << result << " " << gnutls_strerror(err) << std::endl;
return false;
}
return result == 0;
+763 -512
View File
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -208,7 +208,8 @@ DhtProxyClient::stop()
std::lock_guard<std::mutex> l(resolverLock_);
resolver = std::move(resolver_);
}
resolver->cancel();
if (resolver)
resolver->cancel();
cancelAllListeners();
if (infoState_)
infoState_->cancel = true;
+41
View File
@@ -100,6 +100,47 @@ private:
std::shared_ptr<Logger> m_logger;
};
std::string
DhtProxyServer::ServerStats::toString() const
{
auto ret = fmt::format("Listens: {}, Puts: {}, PushListeners: {}\n"
"Push requests in the last {}: [Android: {}], [iOS: {}], [Unified: {}]\n"
"Requests: {} per second.",
listenCount, putCount, pushListenersCount,
print_duration(lastUpdated - serverStartTime),
androidPush.toString(), iosPush.toString(), unifiedPush.toString(),
requestRate);
if (nodeInfo) {
auto& ipv4 = nodeInfo->ipv4;
if (ipv4.table_depth > 1)
ret += fmt::format("IPv4 Network estimation: {}\n", ipv4.getNetworkSizeEstimation());
auto& ipv6 = nodeInfo->ipv6;
if (ipv6.table_depth > 1)
ret += fmt::format("IPv6 Network estimation: {}\n", ipv6.getNetworkSizeEstimation());
}
return ret;
}
Json::Value
DhtProxyServer::ServerStats::toJson() const
{
Json::Value result;
result["listenCount"] = static_cast<Json::UInt64>(listenCount);
result["putCount"] = static_cast<Json::UInt64>(putCount);
result["totalPermanentPuts"] = static_cast<Json::UInt64>(totalPermanentPuts);
result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount);
result["serverStartTime"] = static_cast<Json::LargestInt>(to_time_t(serverStartTime));
result["lastUpdated"] = static_cast<Json::LargestInt>(to_time_t(lastUpdated));
result["androidPush"] = androidPush.toJson();
result["iosPush"] = iosPush.toJson();
result["unifiedPush"] = unifiedPush.toJson();
result["requestRate"] = requestRate;
if (nodeInfo)
result["nodeInfo"] = nodeInfo->toJson();
return result;
}
restinio::request_handling_status_t
DhtProxyServer::serverError(restinio::request_t& request) {
auto response = initHttpResponse(request.create_response(restinio::status_internal_server_error()));
+11 -1
View File
@@ -188,6 +188,9 @@ DhtRunner::run(const Config& config, Context&& context)
if (context.certificateStore) {
dht_->setLocalCertificateStore(std::move(context.certificateStore));
}
if (context.certificateStorePkId) {
dht_->setLocalCertificateStore(std::move(context.certificateStorePkId));
}
if (context.publicAddressChangedCb) {
dht_->setOnPublicAddressChanged(std::move(context.publicAddressChangedCb));
}
@@ -627,7 +630,14 @@ DhtRunner::registerCertificate(const std::shared_ptr<crypto::Certificate>& cert)
}
void
DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method) {
DhtRunner::setLocalCertificateStore(CertificateStoreQueryLegacy&& query_method) {
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
dht_->setLocalCertificateStore(std::forward<CertificateStoreQueryLegacy>(query_method));
}
void DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method)
{
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
dht_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
+2 -2
View File
@@ -881,7 +881,7 @@ Request::Request(asio::io_context& ctx, const std::string& url, const Json::Valu
Json::CharReaderBuilder rbuilder;
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (!reader->parse(response.body.data(), response.body.data() + response.body.size(), &json, &err) and logger_)
logger_->error("[http:request:{:d}] can't parse response to json: {:s}", id_, err);
logger_->error("[http:request:{:d}] Unable to parse response to JSON: {:s}", id_, err);
}
if (jsoncb)
jsoncb(std::move(json), response);
@@ -903,7 +903,7 @@ Request::Request(asio::io_context& ctx, const std::string& url, OnJsonCb jsoncb,
Json::CharReaderBuilder rbuilder;
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (!reader->parse(response.body.data(), response.body.data() + response.body.size(), &json, &err) and logger_)
logger_->error("[http:request:{:d}] can't parse response to json: {:s}", id_, err);
logger_->error("[http:request:{:d}] Unable to parse response to JSON: {:s}", id_, err);
}
if (jsoncb)
jsoncb(std::move(json), response);
+1 -1
View File
@@ -145,7 +145,7 @@ int Pht::Cache::lookup(const Prefix& p) {
return pos;
}
const ValueType IndexEntry::TYPE = ValueType::USER_DATA;
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,
+14 -14
View File
@@ -33,10 +33,10 @@ using namespace std::chrono_literals;
const std::string DhtProtocolException::GET_NO_INFOHASH {"Get_values with no info_hash"};
const std::string DhtProtocolException::LISTEN_NO_INFOHASH {"Listen with no info_hash"};
const std::string DhtProtocolException::LISTEN_WRONG_TOKEN {"Listen with wrong token"};
const std::string DhtProtocolException::LISTEN_WRONG_TOKEN {"Listen with incorrect token"};
const std::string DhtProtocolException::PUT_NO_INFOHASH {"Put with no info_hash"};
const std::string DhtProtocolException::PUT_WRONG_TOKEN {"Put with wrong token"};
const std::string DhtProtocolException::PUT_INVALID_ID {"Put with invalid id"};
const std::string DhtProtocolException::PUT_WRONG_TOKEN {"Put with incorrect token"};
const std::string DhtProtocolException::PUT_INVALID_ID {"Put with invalid ID"};
const std::string DhtProtocolException::STORAGE_NOT_FOUND {"Access operation for unknown storage"};
constexpr std::chrono::seconds NetworkEngine::UDP_REPLY_TIME;
@@ -133,7 +133,7 @@ NetworkEngine::tellListener(const Sp<Node>& node, Tid socket_id, const InfoHash&
}
} catch (const std::overflow_error& e) {
if (logger_)
logger_->e("Can't send value: buffer not large enough !");
logger_->e("Unable to send value: buffer not large enough.");
}
}
@@ -288,7 +288,7 @@ NetworkEngine::requestStep(Sp<Request> sreq)
auto& node = *req.node;
if (req.isExpired(now)) {
// if (logger_)
// logger_->d(node.id, "[node %s] expired !", node.toString().c_str());
// logger_->d(node.id, "[node %s] expired.", node.toString().c_str());
node.setExpired();
if (not node.id)
requests.erase(req.tid);
@@ -429,7 +429,7 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
msg->msgpack_unpack(msg_res.get());
} catch (const std::exception& e) {
if (logger_)
logger_->w("Can't parse message of size %lu: %s", buflen, e.what());
logger_->w("Unable to parse message of size %lu: %s", buflen, e.what());
// if (logger_)
// logger_->DBG.logPrintable(buf, buflen);
return;
@@ -449,7 +449,7 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
if (pmsg_it == partial_messages.end()) {
if (logIncoming_)
if (logger_)
logger_->d("Can't find partial message");
logger_->d("Unable to find partial message");
rateLimit(from);
return;
}
@@ -523,7 +523,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
if (msg->type == MessageType::ValueUpdate) {
auto rsocket = node->getSocket(msg->tid);
if (not rsocket)
throw DhtProtocolException {DhtProtocolException::UNKNOWN_TID, "Can't find socket", msg->id};
throw DhtProtocolException {DhtProtocolException::UNKNOWN_TID, "Unable to find socket", msg->id};
node->received(now, {});
onNewNode(node, 2);
try {
@@ -531,7 +531,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
rsocket->on_receive(node, std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
logger_->w("Unable to deserialize nodes %s", e.what());
}
}
else if (msg->type == MessageType::Error or msg->type == MessageType::Reply) {
@@ -550,7 +550,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
if (not node->isClient())
onNewNode(node, 1);
if (logger_)
logger_->d(node->id, "[node %s] can't find transaction with id %u", node->toString().c_str(), msg->tid);
logger_->d(node->id, "[node %s] Unable to find transaction with id %u", node->toString().c_str(), msg->tid);
return;
}
}
@@ -600,7 +600,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
r.setDone(std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
logger_->w("Unable to deserialize nodes %s", e.what());
}
break;
} else { /* request socket data */
@@ -609,7 +609,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
rsocket->on_receive(node, std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
logger_->w("Unable to deserialize nodes %s", e.what());
}
}
break;
@@ -694,7 +694,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
}
} catch (const std::overflow_error& e) {
if (logger_)
logger_->e("Can't send value: buffer not large enough !");
logger_->e("Unable to send value: buffer not large enough.");
} catch (const DhtProtocolException& e) {
sendError(from, msg->tid, e.getCode(), e.getMsg().c_str(), true);
}
@@ -744,7 +744,7 @@ NetworkEngine::sendPing(const Sp<Node>& node, RequestCb&& on_done, RequestExpire
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&&) {
if (logger_)
logger_->d(req_status.node->id, "[node %s] got pong !", req_status.node->toString().c_str());
logger_->d(req_status.node->id, "[node %s] got pong.", req_status.node->toString().c_str());
if (on_done) {
on_done(req_status, {});
}
+42 -30
View File
@@ -23,8 +23,8 @@
#include <io.h>
#include <string>
#include <cstring>
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int) strlen(b), 0)
#define _poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)
#else
#include <fcntl.h>
@@ -49,10 +49,10 @@ bindSocket(const SockAddr& addr, SockAddr& bound)
throw DhtException(std::string("Can't open socket: ") + strerror(sock));
int set = 1;
#ifdef SO_NOSIGPIPE
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&set, sizeof(set));
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char*) &set, sizeof(set));
#endif
if (is_ipv6)
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&set, sizeof(set));
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*) &set, sizeof(set));
net::setNonblocking(sock);
int rc = bind(sock, addr.get(), addr.getLength());
if (rc < 0) {
@@ -62,7 +62,7 @@ bindSocket(const SockAddr& addr, SockAddr& bound)
}
sockaddr_storage ss;
socklen_t ss_len = sizeof(ss);
getsockname(sock, (sockaddr*)&ss, &ss_len);
getsockname(sock, (sockaddr*) &ss, &ss_len);
bound = {ss, ss_len};
return sock;
}
@@ -84,7 +84,8 @@ setNonblocking(int fd, bool nonblocking)
}
#ifdef _WIN32
void udpPipe(int fds[2])
void
udpPipe(int fds[2])
{
int lst = socket(AF_INET, SOCK_DGRAM, 0);
if (lst < 0)
@@ -97,11 +98,12 @@ void udpPipe(int fds[2])
inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
inaddr.sin_port = 0;
int yes = 1;
setsockopt(lst, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
int rc = bind(lst, (sockaddr*)&inaddr, sizeof(inaddr));
setsockopt(lst, SOL_SOCKET, SO_REUSEADDR, (char*) &yes, sizeof(yes));
int rc = bind(lst, (sockaddr*) &inaddr, sizeof(inaddr));
if (rc < 0) {
close(lst);
throw DhtException("Can't bind socket on " + print_addr((sockaddr*)&inaddr, sizeof(inaddr)) + " " + strerror(rc));
throw DhtException("Can't bind socket on " + print_addr((sockaddr*) &inaddr, sizeof(inaddr)) + " "
+ strerror(rc));
}
socklen_t len = sizeof(addr);
getsockname(lst, &addr, &len);
@@ -111,7 +113,9 @@ void udpPipe(int fds[2])
}
#endif
UdpSocket::UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l) : logger(l) {
UdpSocket::UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l)
: logger(l)
{
SockAddr bind4;
bind4.setFamily(AF_INET);
bind4.setPort(port);
@@ -122,28 +126,37 @@ UdpSocket::UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l) : logger(
openSockets(bind4, bind6);
}
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l) : logger(l)
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l)
: logger(l)
{
std::lock_guard<std::mutex> lk(lock);
openSockets(bind4, bind6);
}
UdpSocket::~UdpSocket() {
UdpSocket::~UdpSocket()
{
stop();
if (rcv_thread.joinable())
rcv_thread.join();
}
int
UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) {
UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, [[maybe_unused]] bool replied)
{
if (not dest)
return EFAULT;
int s;
switch (dest.getFamily()) {
case AF_INET: s = s4; break;
case AF_INET6: s = s6; break;
default: s = -1; break;
case AF_INET:
s = s4;
break;
case AF_INET6:
s = s6;
break;
default:
s = -1;
break;
}
if (s < 0)
@@ -153,14 +166,12 @@ UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool r
#ifdef MSG_CONFIRM
if (replied)
flags |= MSG_CONFIRM;
#else
(void) replied;
#endif
#ifdef MSG_NOSIGNAL
flags |= MSG_NOSIGNAL;
#endif
if (sendto(s, (const char*)data, size, flags, dest.get(), dest.getLength()) == -1) {
if (sendto(s, (const char*) data, size, flags, dest.get(), dest.getLength()) == -1) {
int err = errno;
if (logger)
logger->d("Can't send message to %s: %s", dest.toString().c_str(), strerror(err));
@@ -239,7 +250,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
}
running = true;
rcv_thread = std::thread([this, stop_readfd, ls4=s4, ls6=s6]() mutable {
rcv_thread = std::thread([this, stop_readfd, ls4 = s4, ls6 = s6]() mutable {
struct pollfd fds[NUM_FDS];
for (int i = 0; i < NUM_FDS; i++)
fds[i].events = POLLIN;
@@ -270,23 +281,22 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
socklen_t from_len = sizeof(from);
if (fds[stop_readfd_index].revents & POLLIN) {
if (recv(stop_readfd, (char*)buf.data(), buf.size(), 0) < 0) {
if (recv(stop_readfd, (char*) buf.data(), buf.size(), 0) < 0) {
if (logger)
logger->e("Got stop packet error: %s", strerror(errno));
break;
}
}
else if (fds[ls4_index].revents & POLLIN)
rc = recvfrom(ls4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
} else if (fds[ls4_index].revents & POLLIN)
rc = recvfrom(ls4, (char*) buf.data(), buf.size(), 0, (sockaddr*) &from, &from_len);
else if (fds[ls6_index].revents & POLLIN)
rc = recvfrom(ls6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
rc = recvfrom(ls6, (char*) buf.data(), buf.size(), 0, (sockaddr*) &from, &from_len);
else
continue;
if (rc > 0) {
auto pkts = getNewPacket();
auto& pkt = pkts.front();
pkt.data.insert(pkt.data.end(), buf.begin(), buf.begin()+rc);
pkt.data.insert(pkt.data.end(), buf.begin(), buf.begin() + rc);
pkt.from = {from, from_len};
pkt.received = clock::now();
onReceived(std::move(pkts));
@@ -295,10 +305,12 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
logger->e("Error receiving packet: %s", strerror(errno));
int err = errno;
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
if (not running) break;
if (not running)
break;
std::unique_lock<std::mutex> lk(lock, std::try_to_lock);
if (lk.owns_lock()) {
if (not running) break;
if (not running)
break;
if (ls4 >= 0) {
close(ls4);
try {
@@ -363,5 +375,5 @@ UdpSocket::stop()
}
}
}
}
} // namespace net
} // namespace dht
+7 -7
View File
@@ -115,13 +115,13 @@ PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in
sockFd_.bind({domain, port});
} catch(const std::exception& e){
if (logger_)
logger_->error("Can't start peer discovery using android workaround: {}", e.what());
logger_->error("Unable to start peer discovery using android workaround: {}", e.what());
}
}
else
#endif
if (logger_)
logger_->error("Can't start peer discovery for {}: {}",
logger_->error("Unable to start peer discovery for {}: {}",
domain.family() == AF_INET ? "IPv4" : "IPv6", e.what());
}
}
@@ -322,9 +322,9 @@ PeerDiscovery::DomainPeerDiscovery::reDiscover()
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address()), ec);
if (ec and logger_)
logger_->w("can't multicast on %s: %s",
sockAddrSend_.address().to_string().c_str(),
ec.message().c_str());
logger_->w("Unable to multicast on %s: %s",
sockAddrSend_.address().to_string().c_str(),
ec.message().c_str());
query(sockAddrSend_);
}
@@ -382,13 +382,13 @@ PeerDiscovery::PeerDiscovery(in_port_t port, Sp<asio::io_context> ioContext, Sp<
peerDiscovery4_.reset(new DomainPeerDiscovery(asio::ip::udp::v4(), port, ioContext, logger));
} catch(const std::exception& e){
if (logger)
logger->e("[peerdiscovery] can't start IPv4: %s", e.what());
logger->e("[peerdiscovery] Unable to start IPv4: %s", e.what());
}
try {
peerDiscovery6_.reset(new DomainPeerDiscovery(asio::ip::udp::v6(), port, ioContext, logger));
} catch(const std::exception& e) {
if (logger)
logger->e("[peerdiscovery] can't start IPv6: %s", e.what());
logger->e("[peerdiscovery] Unable to start IPv6: %s", e.what());
}
}
+147 -112
View File
@@ -36,10 +36,18 @@ extern "C" {
namespace dht {
SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf, IdentityAnnouncedCb iacb, const std::shared_ptr<Logger>& l)
: DhtInterface(l), dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all)
SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht,
SecureDht::Config conf,
IdentityAnnouncedCb iacb,
const std::shared_ptr<Logger>& l)
: DhtInterface(l)
, dht_(std::move(dht))
, key_(conf.id.first)
, certificate_(conf.id.second)
, enableCache_(conf.cert_cache_all)
{
if (!dht_) return;
if (!dht_)
return;
for (const auto& type : DEFAULT_TYPES)
registerType(type);
@@ -53,30 +61,28 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf,
auto certLongId = certificate_->getLongId();
if (key_ and (certId != key_->getPublicKey().getId() or certLongId != key_->getPublicKey().getLongId()))
throw DhtException("SecureDht: provided certificate doesn't match private key.");
dht_->addOnConnectedCallback([this, certId, certLongId, cb=std::move(iacb)]{
dht_->put(certId, Value {
CERTIFICATE_TYPE,
*certificate_,
1
}, [this, certId, cb=std::move(cb)](bool ok) {
if (cb) cb(ok);
if (logger_)
logger_->d(certId, "SecureDht: certificate announcement %s", ok ? "succeeded" : "failed");
}, {}, true);
dht_->put(InfoHash::get(certLongId), Value {
CERTIFICATE_TYPE,
*certificate_,
1
}, [this, cb=std::move(cb)](bool ok) {
if (cb) cb(ok);
if (logger_)
logger_->debug("SecureDht: certificate announcement {}", ok ? "succeeded" : "failed");
}, {}, true);
auto cb = iacb ? [
this,
completedState = std::make_shared<std::pair<unsigned,bool>>(2, true),
iacb = std::move(iacb)
](bool ok) {
if (logger_)
logger_->d("SecureDht: certificate announcement %s", ok ? "succeeded" : "failed");
completedState->second = completedState->second and ok;
if (--completedState->first == 0)
iacb(completedState->second);
} : iacb;
dht_->addOnConnectedCallback([this, certId, certLongId, cb = std::move(cb)] {
dht_->put(certId, Value {CERTIFICATE_TYPE, *certificate_, 1}, cb, time_point::max(), true);
dht_->put(InfoHash::get(certLongId), Value {CERTIFICATE_TYPE, *certificate_, 1}, cb, time_point::max(), true);
});
}
}
SecureDht::~SecureDht(){
SecureDht::~SecureDht()
{
dht_.reset();
}
@@ -88,12 +94,13 @@ SecureDht::secureType(ValueType&& type)
return v->checkSignature();
return type.storePolicy(id, v, nid, a);
};
type.editPolicy = [this,type](InfoHash id, const Sp<Value>& o, Sp<Value>& n, const InfoHash& nid, const SockAddr& a) {
type.editPolicy = [this,
type](InfoHash id, const Sp<Value>& o, Sp<Value>& n, const InfoHash& nid, const SockAddr& a) {
if (not o->isSigned())
return type.editPolicy(id, o, n, nid, a);
if (*o->owner != *n->owner or not n->isSigned()) {
if (logger_)
logger_->w("Edition forbidden: not signed or wrong owner.");
logger_->w("Edition forbidden: not signed or incorrect owner.");
return false;
}
if (not n->checkSignature()) {
@@ -109,8 +116,7 @@ SecureDht::secureType(ValueType&& type)
logger_->w("Edition forbidden: sequence number must be increasing.");
return false;
}
}
else if (n->seq < o->seq)
} else if (n->seq < o->seq)
return false;
return true;
};
@@ -228,12 +234,13 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
cb(b);
return;
}
if (localQueryMethod_) {
auto res = localQueryMethod_(node);
if (localQueryMethodLegacy_) {
auto res = localQueryMethodLegacy_(node);
if (not res.empty()) {
if (logger_)
logger_->d("Registering certificate from local store for %s", node.to_c_str());
nodesCertificates_.emplace(node, res.front());
nodesCertificatesLong_.emplace(res.front()->getLongId(), res.front());
if (cb)
cb(res.front());
return;
@@ -241,22 +248,26 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
}
auto found = std::make_shared<bool>(false);
dht_->get(node, [cb,node,found,this](const std::vector<Sp<Value>>& vals) {
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
if (logger_)
logger_->d(node, "Found certificate for %s", node.to_c_str());
if (cb)
cb(cert);
return false;
dht_->get(
node,
[cb, node, found, this](const std::vector<Sp<Value>>& vals) {
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
if (logger_)
logger_->d(node, "Found certificate for %s", node.to_c_str());
if (cb)
cb(cert);
return false;
}
}
}
return !*found;
}, [cb,found](bool) {
if (!*found and cb)
cb(nullptr);
}, Value::TypeFilter(CERTIFICATE_TYPE));
return !*found;
},
[cb, found](bool) {
if (!*found and cb)
cb(nullptr);
},
Value::TypeFilter(CERTIFICATE_TYPE));
}
void
@@ -276,11 +287,13 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp
if (*pk) {
nodesPubKeys_[pk->getId()] = pk;
nodesPubKeysLong_[pk->getLongId()] = pk;
if (cb) cb(pk);
if (cb)
cb(pk);
return;
}
}
if (cb) cb(nullptr);
if (cb)
cb(nullptr);
});
}
@@ -296,23 +309,40 @@ SecureDht::findCertificate(const PkId& node, const std::function<void(const Sp<c
return;
}
auto found = std::make_shared<bool>(false);
dht_->get(InfoHash::get(node), [cb,node,found,this](const std::vector<Sp<Value>>& vals) {
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
if (logger_)
logger_->debug("Found certificate for {}", node.to_c_str());
if (cb)
cb(cert);
return false;
}
if (localQueryMethod_) {
auto res = localQueryMethod_(node);
if (not res.empty()) {
if (logger_)
logger_->debug("Registering certificate from local store for {}", node.to_c_str());
nodesCertificates_.emplace(res.front()->getId(), res.front());
nodesCertificatesLong_.emplace(node, res.front());
if (cb)
cb(res.front());
return;
}
return !*found;
}, [cb,found](bool) {
if (!*found and cb)
cb(nullptr);
}, Value::TypeFilter(CERTIFICATE_TYPE));
}
auto found = std::make_shared<bool>(false);
dht_->get(
InfoHash::get(node),
[cb, node, found, this](const std::vector<Sp<Value>>& vals) {
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
if (logger_)
logger_->debug("Found certificate for {}", node.to_c_str());
if (cb)
cb(cert);
return false;
}
}
return !*found;
},
[cb, found](bool) {
if (!*found and cb)
cb(nullptr);
},
Value::TypeFilter(CERTIFICATE_TYPE));
}
void
@@ -332,11 +362,13 @@ SecureDht::findPublicKey(const PkId& node, const std::function<void(const Sp<cry
if (*pk) {
nodesPubKeys_[pk->getId()] = pk;
nodesPubKeysLong_[pk->getLongId()] = pk;
if (cb) cb(pk);
if (cb)
cb(pk);
return;
}
}
if (cb) cb(nullptr);
if (cb)
cb(nullptr);
});
}
@@ -404,7 +436,6 @@ SecureDht::getCallbackFilter(const ValueCallback& cb, Value::Filter&& filter)
};
}
GetCallback
SecureDht::getCallbackFilter(const GetCallback& cb, Value::Filter&& filter)
{
@@ -435,7 +466,6 @@ SecureDht::listen(const InfoHash& id, ValueCallback cb, Value::Filter f, Where w
return dht_->listen(id, getCallbackFilter(cb, std::forward<Value::Filter>(f)), {}, std::forward<Where>(w));
}
size_t
SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter f, Where w)
{
@@ -445,7 +475,7 @@ SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter f, Where w)
void
SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_ or not hash or not val) {
if (not key_ or not hash or not val) {
if (callback)
callback(false, {});
return;
@@ -463,8 +493,9 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
}
// Check if data already exists on the dht
get(hash,
[val,this] (const std::vector<Sp<Value>>& vals) {
get(
hash,
[val, this](const std::vector<Sp<Value>>& vals) {
if (logger_)
logger_->d("Found online previous value being announced.");
for (const auto& v : vals) {
@@ -479,73 +510,77 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
}
return true;
},
[hash,val,this,callback,permanent] (bool /* ok */) {
[hash, val, this, callback, permanent](bool /* ok */) {
sign(*val);
dht_->put(hash, val, callback, time_point::max(), permanent);
},
Value::IdFilter(val->id),
Where().id(val->id)
);
Where().id(val->id));
}
void
SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (not key_) {
if (callback)
callback(false, {});
return;
}
findPublicKey(to, [this, hash, val = std::move(val), callback = std::move(callback), permanent](const Sp<crypto::PublicKey>& pk) {
if(!pk || !*pk) {
if (callback)
callback(false, {});
return;
}
if (logger_)
logger_->w("Encrypting data for PK: %s", pk->getId().toString().c_str());
try {
dht_->put(hash, encrypt(*val, *pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
});
findPublicKey(to,
[this, hash, val = std::move(val), callback = std::move(callback), permanent](
const Sp<crypto::PublicKey>& pk) {
if (!pk || !*pk) {
if (callback)
callback(false, {});
return;
}
if (logger_)
logger_->w("Encrypting data for PK: %s", pk->getId().toString().c_str());
try {
dht_->put(hash, encrypt(*val, *pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
});
}
void
SecureDht::putEncrypted(const InfoHash& hash, const PkId& to, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (not key_) {
if (callback)
callback(false, {});
return;
}
findPublicKey(to, [this, hash, val = std::move(val), callback = std::move(callback), permanent](const Sp<crypto::PublicKey>& pk) {
if(!pk || !*pk) {
if (callback)
callback(false, {});
return;
}
if (logger_)
logger_->warn("Encrypting data for PK: {}", pk->getLongId());
try {
dht_->put(hash, encrypt(*val, *pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
});
findPublicKey(to,
[this, hash, val = std::move(val), callback = std::move(callback), permanent](
const Sp<crypto::PublicKey>& pk) {
if (!pk || !*pk) {
if (callback)
callback(false, {});
return;
}
if (logger_)
logger_->warn("Encrypting data for PK: {}", pk->getLongId());
try {
dht_->put(hash, encrypt(*val, *pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
});
}
void
SecureDht::putEncrypted(const InfoHash& hash, const crypto::PublicKey& pk, Sp<Value> val, DoneCallback callback, bool permanent)
SecureDht::putEncrypted(
const InfoHash& hash, const crypto::PublicKey& pk, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (not key_) {
if (callback)
callback(false, {});
return;
@@ -583,7 +618,7 @@ SecureDht::decrypt(const Value& v)
auto decrypted = key_->decrypt(v.cypher);
Value ret {v.id};
auto msg = msgpack::unpack((const char*)decrypted.data(), decrypted.size());
auto msg = msgpack::unpack((const char*) decrypted.data(), decrypted.size());
ret.msgpack_unpack_body(msg.get());
if (ret.recipient != getId())
@@ -594,4 +629,4 @@ SecureDht::decrypt(const Value& v)
return ret;
}
}
} // namespace dht
+2 -2
View File
@@ -46,7 +46,7 @@ public:
} else
++rit;
}
// printf("StorageBucket::erase can't find value %s %016" PRIx64 "\n", id.to_c_str(), value.id);
// printf("StorageBucket::erase unable to find value %s %016" PRIx64 "\n", id.to_c_str(), value.id);
}
void refresh(const InfoHash& id, const Value& value, time_point old_expiration, time_point expiration) {
auto range = storedValues_.equal_range(old_expiration);
@@ -58,7 +58,7 @@ public:
} else
++rit;
}
// printf("StorageBucket::refresh can't find value %s %016" PRIx64 "\n", id.to_c_str(), value.id);
// printf("StorageBucket::refresh unable to find value %s %016" PRIx64 "\n", id.to_c_str(), value.id);
insert(id, value, expiration);
}
size_t size() const { return totalSize_; }
+7
View File
@@ -20,6 +20,13 @@
#include "config.h"
#endif
#if defined(_WIN32) && (_WIN32_WINNT < 0x0502) && (NTDDI_VERSION >= NTDDI_VISTA)
#define _WIN32_WINNT _WIN32_WINNT_WIN10
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#endif // inet_pton() workaround for MSVC in Windows 10/11
#include "utils.h"
#include "sockaddr.h"
#include "default_types.h"
+2 -2
View File
@@ -73,7 +73,7 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
s << "data(" << v.user_type << "):";
if (v.user_type == "text/plain") {
s << '"';
s.write((const char*)v.data.data(), v.data.size());
s.write(reinterpret_cast<const char*>(v.data.data()), v.data.size());
s << '"';
} else if (v.data.size() < 1024) {
s << toHex(v.data.data(), v.data.size());
@@ -527,7 +527,7 @@ Where::Where(std::string_view q_str) {
else if (field_str == "user_type")
userType(s);
else
throw std::invalid_argument(Query::QUERY_PARSE_ERROR + " (WHERE) wrong token near: " + field_str);
throw std::invalid_argument(Query::QUERY_PARSE_ERROR + " (WHERE) incorrect token near: " + field_str);
}
}
}
+42
View File
@@ -260,6 +260,48 @@ void CryptoTester::testAesEncryptionWithMultipleKeySizes() {
}
}
void CryptoTester::testOaep() {
#if GNUTLS_VERSION_NUMBER >= 0x030804 && !defined(_WIN32)
auto data = std::vector<uint8_t>(446, 10);
auto ca = dht::crypto::generateIdentity("n1");
auto key = dht::crypto::PrivateKey::generate(4096, GNUTLS_PK_RSA_OAEP);
auto pk = key.getSharedPublicKey();
auto encrypted = pk->encrypt(data);
auto decrypted = key.decrypt(encrypted);
CPPUNIT_ASSERT(data == decrypted);
auto crt = dht::crypto::Certificate::generate(key, "dhtnode", ca);
auto pk2 = crt.getSharedPublicKey();
auto encrypted2 = pk2->encrypt(data);
auto decrypted2 = key.decrypt(encrypted2);
CPPUNIT_ASSERT(data == decrypted2);
auto exported = crt.getPacked();
dht::crypto::Certificate imported(exported);
auto pk3 = imported.getSharedPublicKey();
auto encrypted3 = pk3->encrypt(data);
auto decrypted3 = key.decrypt(encrypted3);
CPPUNIT_ASSERT(data == decrypted3);
auto exportedPk = pk->toString();
dht::crypto::PublicKey importedPk(exportedPk);
auto encrypted4 = importedPk.encrypt(data);
auto decrypted4 = key.decrypt(encrypted4);
CPPUNIT_ASSERT(data == decrypted4);
auto exportedKey = key.serialize();
dht::crypto::PrivateKey importedKey(exportedKey);
auto decrypted5 = importedKey.decrypt(encrypted);
CPPUNIT_ASSERT(data == decrypted5);
#else
std::cerr << "Skipping OAEP test, not supported by the current GnuTLS version" << std::endl;
#endif
}
void
CryptoTester::tearDown() {
+3
View File
@@ -35,6 +35,7 @@ class CryptoTester : public CppUnit::TestFixture {
CPPUNIT_TEST(testOcsp);
CPPUNIT_TEST(testAesEncryption);
CPPUNIT_TEST(testAesEncryptionWithMultipleKeySizes);
CPPUNIT_TEST(testOaep);
CPPUNIT_TEST_SUITE_END();
public:
@@ -71,6 +72,8 @@ class CryptoTester : public CppUnit::TestFixture {
*/
void testAesEncryption();
void testAesEncryptionWithMultipleKeySizes();
void testOaep();
};
} // namespace test
+48 -33
View File
@@ -52,13 +52,13 @@ DhtRunnerTester::tearDown() {
std::condition_variable cv;
std::mutex cv_m;
auto shutdown = [&]{
std::lock_guard<std::mutex> lk(cv_m);
std::lock_guard lk(cv_m);
done++;
cv.notify_all();
};
node1.shutdown(shutdown);
node2.shutdown(shutdown);
std::unique_lock<std::mutex> lk(cv_m);
std::unique_lock lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return done == 2u; }));
node1.join();
node2.join();
@@ -207,13 +207,13 @@ DhtRunnerTester::testListen() {
for (unsigned i=0; i<N; i++) {
node2.put(a, dht::Value("v1"), [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
std::lock_guard lock(mutex);
putCount++;
if (ok) putOkCount1++;
cv.notify_all();
});
node2.put(b, dht::Value("v2"), [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
std::lock_guard lock(mutex);
putCount++;
if (ok) putOkCount2++;
cv.notify_all();
@@ -221,7 +221,7 @@ DhtRunnerTester::testListen() {
auto bigVal = std::make_shared<dht::Value>();
bigVal->data = mtu;
node2.put(c, std::move(bigVal), [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
std::lock_guard lock(mutex);
putCount++;
if (ok) putOkCount3++;
cv.notify_all();
@@ -229,7 +229,7 @@ DhtRunnerTester::testListen() {
}
{
std::unique_lock<std::mutex> lk(mutex);
std::unique_lock lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == N * 3u; }));
CPPUNIT_ASSERT_EQUAL(N, putOkCount1);
CPPUNIT_ASSERT_EQUAL(N, putOkCount2);
@@ -264,6 +264,7 @@ void
DhtRunnerTester::testIdOps() {
std::mutex mutex;
std::condition_variable cv;
unsigned identityCount(0);
unsigned valueCount(0);
unsigned valueCountEdit(0);
@@ -275,8 +276,8 @@ DhtRunnerTester::testIdOps() {
dht::DhtRunner::Context context2;
context2.identityAnnouncedCb = [&](bool ok) {
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
std::lock_guard lk(mutex);
identityCount++;
cv.notify_all();
};
@@ -288,27 +289,28 @@ DhtRunnerTester::testIdOps() {
node2.bootstrap(bound);
{
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 1; }));
std::unique_lock lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return identityCount == 1; }));
}
node1.findCertificate(node2.getId(), [&](const std::shared_ptr<dht::crypto::Certificate>& crt){
CPPUNIT_ASSERT(crt);
std::lock_guard<std::mutex> lk(mutex);
std::lock_guard lk(mutex);
valueCount++;
cv.notify_all();
});
{
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 2; }));
std::unique_lock lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 1u; }));
CPPUNIT_ASSERT_EQUAL(1u, identityCount);
}
dht::DhtRunner::Context context1;
context1.identityAnnouncedCb = [&](bool ok) {
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
std::lock_guard lk(mutex);
identityCount++;
cv.notify_all();
};
@@ -323,21 +325,21 @@ DhtRunnerTester::testIdOps() {
auto key = dht::InfoHash::get("key");
node1.putEncrypted(key, node2.getId(), dht::Value("yo"), [&](bool ok){
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
std::lock_guard lk(mutex);
valueCount++;
cv.notify_all();
});
node1.putEncrypted(key, node2.getPublicKey(), dht::Value("yo"), [&](bool ok){
node1.putEncrypted(key, node2.getPublicKey(), std::make_shared<dht::Value>("yo"), [&](bool ok){
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
std::lock_guard lk(mutex);
valueCount++;
cv.notify_all();
});
node2.listen<std::string>(key, [&](std::string&& value){
CPPUNIT_ASSERT_EQUAL("yo"s, value);
std::lock_guard<std::mutex> lk(mutex);
std::lock_guard lk(mutex);
valueCount++;
cv.notify_all();
return true;
@@ -347,7 +349,7 @@ DhtRunnerTester::testIdOps() {
auto editValue = std::make_shared<dht::Value>("v1");
node1.putSigned(key2, editValue, [&](bool ok){
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
std::lock_guard lk(mutex);
valueCountEdit++;
cv.notify_all();
});
@@ -359,16 +361,29 @@ DhtRunnerTester::testIdOps() {
CPPUNIT_ASSERT_EQUAL("v2"s, dht::unpackMsg<std::string>(v->data));
CPPUNIT_ASSERT_EQUAL(v->owner->getLongId(), node1.getPublicKey()->getLongId());
}
std::lock_guard<std::mutex> lk(mutex);
std::lock_guard lk(mutex);
valueCountEdit += values.size();
cv.notify_all();
return true;
});
{
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 7; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCountEdit == 2; }));
std::unique_lock lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return identityCount == 2u; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 5u; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCountEdit == 2u; }));
}
node2.findCertificate(node1.getPublicKey()->getLongId(), [&](const std::shared_ptr<dht::crypto::Certificate>& crt){
CPPUNIT_ASSERT(crt);
std::lock_guard lk(mutex);
valueCount++;
cv.notify_all();
});
{
std::unique_lock lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 6u; }));
}
// editValue->data = dht::packMsg("v2");
@@ -376,12 +391,12 @@ DhtRunnerTester::testIdOps() {
editValue->data = dht::packMsg("v2");
node1.putSigned(key2, editValue, [&](bool ok){
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
std::lock_guard lk(mutex);
valueCountEdit++;
cv.notify_all();
});
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCountEdit == 4; }));
std::unique_lock lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCountEdit == 4u; }));
}
void
@@ -399,14 +414,14 @@ DhtRunnerTester::testListenLotOfBytes() {
for (unsigned i=0; i<N; i++) {
node2.put(foo, data, [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
std::lock_guard lock(mutex);
putCount++;
if (ok) putOkCount++;
cv.notify_all();
});
}
{
std::unique_lock<std::mutex> lk(mutex);
std::unique_lock lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == N; }));
}
@@ -427,7 +442,7 @@ DhtRunnerTester::testListenLotOfBytes() {
});
{
std::unique_lock<std::mutex> lk(mutex);
std::unique_lock lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return valueCount == N; }));
}
@@ -447,7 +462,7 @@ DhtRunnerTester::testMultithread() {
for (unsigned i=0; i<N; i++) {
dht::ThreadPool::computation().run([&]{
node2.put(dht::InfoHash::get("123" + std::to_string(i)), "hehe", [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
std::lock_guard lock(mutex);
putCount++;
if (ok) putOkCount++;
cv.notify_all();
@@ -455,14 +470,14 @@ DhtRunnerTester::testMultithread() {
node2.get(dht::InfoHash::get("123" + std::to_string(N-i-1)), [](const std::shared_ptr<dht::Value>&){
return true;
}, [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
std::lock_guard lock(mutex);
putCount++;
if (ok) putOkCount++;
cv.notify_all();
});
});
}
std::unique_lock<std::mutex> lk(mutex);
std::unique_lock lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == 2*N; }));
CPPUNIT_ASSERT_EQUAL(2*N, putOkCount);
+15 -13
View File
@@ -9,21 +9,19 @@ function (configure_tool name extra_files)
add_dependencies(${name} opendht)
if (MSVC)
target_sources(${name} PRIVATE ${MSC_COMPAT_SOURCES})
target_link_libraries (${name} PUBLIC opendht wsock32 ws2_32)
if(NOT BUILD_SHARED_LIBS)
set_target_properties(${name} PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
target_link_libraries (${name} PUBLIC opendht)
target_include_directories (${name} PRIVATE SYSTEM ${MSC_COMPAT_DIR} ${MSVC_COMPAT_DIR})
else()
target_link_libraries (${name} LINK_PUBLIC opendht ${readline_LIBRARIES})
target_link_libraries (${name} LINK_PUBLIC opendht ${READLINE_LIBRARIES})
target_include_directories (${name} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
endif ()
endfunction ()
configure_tool (dhtnode tools_common.h)
configure_tool (dhtscanner tools_common.h)
configure_tool (dhtchat tools_common.h)
if (OPENDHT_EXAMPLES)
configure_tool (dhtscanner tools_common.h)
configure_tool (dhtchat tools_common.h)
endif ()
if (NOT MSVC)
configure_tool (perftest tools_common.h)
endif ()
@@ -34,17 +32,15 @@ endif ()
if (OPENDHT_C)
add_executable (dhtcnode dhtcnode.c)
add_dependencies(dhtcnode opendht-c)
target_link_libraries (dhtcnode PUBLIC opendht-c ${readline_LIBRARIES})
target_link_libraries (dhtcnode PUBLIC opendht-c)
target_include_directories (dhtcnode SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/c)
if (WIN32)
target_link_libraries (dhtcnode PUBLIC ws2_32)
endif()
if (MSVC)
target_sources(dhtcnode PRIVATE ${MSC_COMPAT_SOURCES})
target_link_libraries(dhtcnode PRIVATE unofficial::readline-win32::readline)
target_include_directories (dhtcnode SYSTEM PRIVATE ${MSC_COMPAT_DIR} ${MSVC_COMPAT_DIR})
if(NOT BUILD_SHARED_LIBS)
set_target_properties(dhtcnode PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
endif()
endif ()
@@ -52,9 +48,15 @@ if (NOT DEFINED CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR bin)
endif ()
install (TARGETS dhtnode dhtscanner dhtchat RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install (TARGETS dhtnode RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if (OPENDHT_EXAMPLES)
install (TARGETS dhtscanner dhtchat RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif ()
if(MSVC)
install(FILES $<TARGET_PDB_FILE:dhtnode> $<TARGET_PDB_FILE:dhtscanner> $<TARGET_PDB_FILE:dhtchat> CONFIGURATIONS "Debug" "RelWithDebInfo" DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES $<TARGET_PDB_FILE:dhtnode> CONFIGURATIONS "Debug" "RelWithDebInfo" DESTINATION ${CMAKE_INSTALL_BINDIR})
if (OPENDHT_EXAMPLES)
install(FILES $<TARGET_PDB_FILE:dhtscanner> $<TARGET_PDB_FILE:dhtchat> CONFIGURATIONS "Debug" "RelWithDebInfo" DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
endif()
if (OPENDHT_SYSTEMD)
+8 -1
View File
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include <stdatomic.h>
#include <inttypes.h>
#include <time.h>
#ifdef _MSC_VER
#include "wingetopt.h"
@@ -33,6 +34,7 @@
#include <readline/readline.h>
#include <readline/history.h>
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
@@ -296,7 +298,12 @@ int main(int argc, char **argv)
// Wait until shutdown callback is called
while (!atomic_load(&ctx.stop)) {
usleep(10000);
#ifdef _WIN32
Sleep(10); // 10ms
#else
struct timespec ts = {0, 10000000}; // 10ms
nanosleep(&ts, NULL);
#endif
}
dht_runner_delete(runner);
return EXIT_SUCCESS;
+12 -12
View File
@@ -34,21 +34,21 @@
#include <fmt/ranges.h>
#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(__NT__)
#pragma message "Building on UNIX-like platform, linking system getopt"
#include <getopt.h>
#include <readline/readline.h>
#include <readline/history.h>
#endif
#ifdef _MSC_VER
#pragma message("Building on WIN32 platform using MSVC, linking wingetopt")
#include "wingetopt.h"
#endif
#if defined(__MINGW32__) || defined (__MINGW64__)
#pragma message "Building on MinGW, linking system-wide getopt"
#ifndef _WIN32
#include <getopt.h>
#include <readline/readline.h>
#include <readline/history.h>
#else
#ifdef _MSC_VER
#pragma message("Building on WIN32 platform using MSVC, linking wingetopt")
#include "wingetopt.h"
#endif
#if defined(__MINGW32__) || defined (__MINGW64__)
#pragma message "Building on MinGW, linking system-wide getopt"
#include <getopt.h>
#include <readline/readline.h>
#include <readline/history.h>
#endif
#endif
#if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MINGW64__)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"default-registry": {
"kind": "git",
"baseline": "654410ee8e11f0610c11a4a49a8827a84be5e187",
"baseline": "dd3097e305afa53f7b4312371f62058d2e665320",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": [
+13 -9
View File
@@ -1,18 +1,18 @@
{
"name": "opendht",
"version-string": "3.4.0",
"version-string": "3.6.0",
"port-version": 1,
"description": "OpenDHT is a distributed hash table (DHT) implementation that provides a decentralized and fault-tolerant way to store and retrieve data across a network of nodes.",
"description": "OpenDHT: A lightweight C++17 Distributed Hash Table library.",
"homepage": "https://opendht.net",
"license": "GPL-3.0-or-later",
"dependencies": [
{
"name" : "vcpkg-cmake",
"host" : true
"name": "vcpkg-cmake",
"host": true
},
{
"name" : "vcpkg-cmake-config",
"host" : true
"name": "vcpkg-cmake-config",
"host": true
},
"fmt",
"nettle",
@@ -20,9 +20,13 @@
"msgpack",
"jsoncpp",
"asio",
"argon2"
"argon2",
"simdutf"
],
"default-features": [
"proxy",
"tools"
],
"default-features": ["proxy", "tools"],
"features": {
"proxy": {
"description": "DHT Proxy",
@@ -45,4 +49,4 @@
]
}
}
}
}