mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-09 15:50:26 +03:00
commit
9037e8b2b1
12
.github/workflows/build-deb.yml
vendored
12
.github/workflows/build-deb.yml
vendored
@ -32,26 +32,30 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Commit Hash
|
||||||
|
id: commit
|
||||||
|
uses: prompt/actions-commit-hash@v3.0.0
|
||||||
|
|
||||||
- name: Build package
|
- name: Build package
|
||||||
uses: jtdor/build-deb-action@v1
|
uses: jtdor/build-deb-action@v1
|
||||||
with:
|
with:
|
||||||
docker-image: debian:${{ matrix.dist }}-slim
|
docker-image: debian:${{ matrix.dist }}-slim
|
||||||
buildpackage-opts: --build=binary --no-sign
|
buildpackage-opts: --build=binary --no-sign
|
||||||
before-build-hook: debchange --controlmaint --local "+${{ github.sha }}~${{ matrix.dist }}" -b --distribution ${{ matrix.dist }} "CI build"
|
before-build-hook: debchange --controlmaint --local "+${{ steps.commit.outputs.short }}~${{ matrix.dist }}" -b --distribution ${{ matrix.dist }} "CI build"
|
||||||
extra-build-deps: devscripts git
|
extra-build-deps: devscripts git
|
||||||
|
|
||||||
- name: Upload package
|
- name: Upload package
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: i2pd_${{ matrix.dist }}
|
name: i2pd_${{ matrix.dist }}
|
||||||
path: debian/artifacts/i2pd_*.deb
|
path: debian/artifacts/i2pd_*.deb
|
||||||
|
|
||||||
- name: Upload debugging symbols
|
- name: Upload debugging symbols
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: i2pd-dbgsym_${{ matrix.dist }}
|
name: i2pd-dbgsym_${{ matrix.dist }}
|
||||||
path: debian/artifacts/i2pd-dbgsym_*.deb
|
path: debian/artifacts/i2pd-dbgsym_*.deb
|
||||||
|
6
.github/workflows/build-freebsd.yml
vendored
6
.github/workflows/build-freebsd.yml
vendored
@ -13,7 +13,7 @@ on:
|
|||||||
- libi2pd/**
|
- libi2pd/**
|
||||||
- libi2pd_client/**
|
- libi2pd_client/**
|
||||||
- Makefile
|
- Makefile
|
||||||
- Makefile.homebrew
|
- Makefile.bsd
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
pull_request:
|
pull_request:
|
||||||
@ -27,7 +27,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Test in FreeBSD
|
- name: Test in FreeBSD
|
||||||
id: test
|
id: test
|
||||||
@ -44,7 +44,7 @@ jobs:
|
|||||||
gmake -j2
|
gmake -j2
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: i2pd-freebsd
|
name: i2pd-freebsd
|
||||||
path: build/i2pd
|
path: build/i2pd
|
||||||
|
9
.github/workflows/build-osx.yml
vendored
9
.github/workflows/build-osx.yml
vendored
@ -30,13 +30,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: install packages
|
- name: Install required formulae
|
||||||
run: |
|
run: |
|
||||||
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
|
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
|
||||||
brew update
|
brew update
|
||||||
brew install boost miniupnpc openssl@1.1
|
brew install boost miniupnpc openssl@1.1
|
||||||
|
|
||||||
- name: build application
|
- name: List installed formulae
|
||||||
|
run: brew list
|
||||||
|
|
||||||
|
- name: Build application
|
||||||
run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3
|
run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3
|
||||||
|
@ -32,7 +32,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ jobs:
|
|||||||
run: cmake --build . --config Debug -- -m
|
run: cmake --build . --config Debug -- -m
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: i2pd-msvc
|
name: i2pd-msvc
|
||||||
path: build/Debug/i2pd.*
|
path: build/Debug/i2pd.*
|
||||||
|
131
.github/workflows/build-windows.yml
vendored
131
.github/workflows/build-windows.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ jobs:
|
|||||||
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes -j3
|
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes -j3
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: i2pd-${{ matrix.arch_short }}.exe
|
name: i2pd-${{ matrix.arch_short }}.exe
|
||||||
path: i2pd.exe
|
path: i2pd.exe
|
||||||
@ -84,7 +84,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ jobs:
|
|||||||
cmake --build . -- -j3
|
cmake --build . -- -j3
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: i2pd-cmake-${{ matrix.arch_short }}.exe
|
name: i2pd-cmake-${{ matrix.arch_short }}.exe
|
||||||
path: build/i2pd.exe
|
path: build/i2pd.exe
|
||||||
@ -116,7 +116,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@ -125,34 +125,117 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
msystem: MINGW32
|
msystem: MINGW32
|
||||||
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc
|
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc
|
||||||
|
cache: true
|
||||||
update: true
|
update: true
|
||||||
|
|
||||||
- name: Build WinXP-capable CRT packages
|
- name: Clone MinGW packages repository
|
||||||
run: |
|
run: git clone https://github.com/msys2/MINGW-packages
|
||||||
git clone https://github.com/msys2/MINGW-packages
|
|
||||||
pushd MINGW-packages
|
|
||||||
pushd mingw-w64-headers-git
|
|
||||||
sed -i 's/0x601/0x501/' PKGBUILD
|
|
||||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
|
|
||||||
pacman --noconfirm -U mingw-w64-i686-headers-git-*-any.pkg.tar.zst
|
|
||||||
popd
|
|
||||||
pushd mingw-w64-crt-git
|
|
||||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
|
|
||||||
pacman --noconfirm -U mingw-w64-i686-crt-git-*-any.pkg.tar.zst
|
|
||||||
popd
|
|
||||||
pushd mingw-w64-winpthreads-git
|
|
||||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
|
|
||||||
pacman --noconfirm -U mingw-w64-i686-libwinpthread-git-*-any.pkg.tar.zst mingw-w64-i686-winpthreads-git-*-any.pkg.tar.zst
|
|
||||||
popd
|
|
||||||
popd
|
|
||||||
|
|
||||||
|
# headers
|
||||||
|
- name: Get headers package version
|
||||||
|
id: version-headers
|
||||||
|
run: |
|
||||||
|
echo "version=$(pacman -Si mingw-w64-i686-headers-git | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||||
|
- name: Cache headers package
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: cache-headers
|
||||||
|
with:
|
||||||
|
path: MINGW-packages/mingw-w64-headers-git/*.zst
|
||||||
|
key: winxp-headers-${{ steps.version-headers.outputs.version }}
|
||||||
|
- name: Build WinXP-capable headers package
|
||||||
|
if: steps.cache-headers.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
cd MINGW-packages/mingw-w64-headers-git
|
||||||
|
sed -i 's/0x601/0x501/' PKGBUILD
|
||||||
|
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||||
|
- name: Install headers package
|
||||||
|
run: pacman --noconfirm -U MINGW-packages/mingw-w64-headers-git/mingw-w64-i686-*-any.pkg.tar.zst
|
||||||
|
|
||||||
|
# CRT
|
||||||
|
- name: Get crt package version
|
||||||
|
id: version-crt
|
||||||
|
run: |
|
||||||
|
echo "version=$(pacman -Si mingw-w64-i686-crt-git | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||||
|
- name: Cache crt package
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: cache-crt
|
||||||
|
with:
|
||||||
|
path: MINGW-packages/mingw-w64-crt-git/*.zst
|
||||||
|
key: winxp-crt-${{ steps.version-crt.outputs.version }}
|
||||||
|
- name: Build WinXP-capable crt package
|
||||||
|
if: steps.cache-crt.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
cd MINGW-packages/mingw-w64-crt-git
|
||||||
|
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||||
|
- name: Install crt package
|
||||||
|
run: pacman --noconfirm -U MINGW-packages/mingw-w64-crt-git/mingw-w64-i686-*-any.pkg.tar.zst
|
||||||
|
|
||||||
|
# winpthreads
|
||||||
|
- name: Get winpthreads package version
|
||||||
|
id: version-winpthreads
|
||||||
|
run: |
|
||||||
|
echo "version=$(pacman -Si mingw-w64-i686-winpthreads-git | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||||
|
- name: Cache winpthreads package
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: cache-winpthreads
|
||||||
|
with:
|
||||||
|
path: MINGW-packages/mingw-w64-winpthreads-git/*.zst
|
||||||
|
key: winxp-winpthreads-${{ steps.version-winpthreads.outputs.version }}
|
||||||
|
- name: Build WinXP-capable winpthreads package
|
||||||
|
if: steps.cache-winpthreads.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
cd MINGW-packages/mingw-w64-winpthreads-git
|
||||||
|
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||||
|
- name: Install winpthreads package
|
||||||
|
run: pacman --noconfirm -U MINGW-packages/mingw-w64-winpthreads-git/mingw-w64-i686-*-any.pkg.tar.zst
|
||||||
|
|
||||||
|
# OpenSSL
|
||||||
|
- name: Get openssl package version
|
||||||
|
id: version-openssl
|
||||||
|
run: |
|
||||||
|
echo "version=$(pacman -Si mingw-w64-i686-openssl | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||||
|
- name: Cache openssl package
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: cache-openssl
|
||||||
|
with:
|
||||||
|
path: MINGW-packages/mingw-w64-openssl/*.zst
|
||||||
|
key: winxp-openssl-${{ steps.version-openssl.outputs.version }}
|
||||||
|
- name: Build WinXP-capable openssl package
|
||||||
|
if: steps.cache-openssl.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
cd MINGW-packages/mingw-w64-openssl
|
||||||
|
gpg --recv-keys D894E2CE8B3D79F5
|
||||||
|
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||||
|
- name: Install openssl package
|
||||||
|
run: pacman --noconfirm -U MINGW-packages/mingw-w64-openssl/mingw-w64-i686-*-any.pkg.tar.zst
|
||||||
|
|
||||||
|
# Boost
|
||||||
|
- name: Get boost package version
|
||||||
|
id: version-boost
|
||||||
|
run: |
|
||||||
|
echo "version=$(pacman -Si mingw-w64-i686-boost | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||||
|
- name: Cache boost package
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: cache-boost
|
||||||
|
with:
|
||||||
|
path: MINGW-packages/mingw-w64-boost/*.zst
|
||||||
|
key: winxp-winpthreads-${{ steps.version-boost.outputs.version }}
|
||||||
|
- name: Build WinXP-capable boost package
|
||||||
|
if: steps.cache-boost.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
cd MINGW-packages/mingw-w64-boost
|
||||||
|
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||||
|
- name: Install boost package
|
||||||
|
run: pacman --noconfirm -U MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst
|
||||||
|
|
||||||
|
# Building i2pd
|
||||||
- name: Build application
|
- name: Build application
|
||||||
run: |
|
run: |
|
||||||
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
|
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
|
||||||
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes USE_WINXP_FLAGS=yes -j3
|
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes USE_WINXP_FLAGS=yes -j3
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: i2pd-xp.exe
|
name: i2pd-xp.exe
|
||||||
path: i2pd.exe
|
path: i2pd.exe
|
||||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: install packages
|
- name: install packages
|
||||||
run: |
|
run: |
|
||||||
@ -53,7 +53,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: install packages
|
- name: install packages
|
||||||
run: |
|
run: |
|
||||||
|
22
.github/workflows/docker.yml
vendored
22
.github/workflows/docker.yml
vendored
@ -37,29 +37,29 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GitHub Container registry
|
- name: Login to GitHub Container registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build container for ${{ matrix.archname }}
|
- name: Build container for ${{ matrix.archname }}
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: ./contrib/docker
|
context: ./contrib/docker
|
||||||
file: ./contrib/docker/Dockerfile
|
file: ./contrib/docker/Dockerfile
|
||||||
@ -82,22 +82,22 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GitHub Container registry
|
- name: Login to GitHub Container registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
|
59
ChangeLog
59
ChangeLog
@ -1,6 +1,65 @@
|
|||||||
# for this file format description,
|
# for this file format description,
|
||||||
# see https://github.com/olivierlacan/keep-a-changelog
|
# see https://github.com/olivierlacan/keep-a-changelog
|
||||||
|
|
||||||
|
## [2.53.1] - 2024-07-29
|
||||||
|
### Changed
|
||||||
|
- I2CP performance improvement
|
||||||
|
### Fixed
|
||||||
|
- 100% CPU usage after I2CP/SAM/BOB session termination
|
||||||
|
- Incorrect client limits returned through I2CP
|
||||||
|
- Build with LibreSSL
|
||||||
|
|
||||||
|
## [2.53.0] - 2024-07-19
|
||||||
|
### Added
|
||||||
|
- New congestion control algorithm for streaming
|
||||||
|
- Support miniupnp-2.2.8
|
||||||
|
- Limit stream's outbound speed
|
||||||
|
- Flood to next day closest floodfills before UTC midnight
|
||||||
|
- Recognize duplicated routers and bypass them
|
||||||
|
- Random SSU2 resend interval
|
||||||
|
### Changed
|
||||||
|
- Set minimal version to 0.9.69 for floodfills and 0.9.58 for client tunnels
|
||||||
|
- Removed openssl 1.0.2 support
|
||||||
|
- Move unsent I2NP messages to the new session if replaced
|
||||||
|
- Use mt19937 RNG instead rand()
|
||||||
|
- Update router's congestion caps before initial publishing
|
||||||
|
- Don't try introducer with invalid address
|
||||||
|
- Select newest introducers to publish
|
||||||
|
- Don't request relay tag for every session if we have enough introducers
|
||||||
|
- Update timestamp for non-reachable or hidden router
|
||||||
|
- Reset streaming routing path if duplicated SYN received
|
||||||
|
- Update LeaseSet if inbound tunnel failed
|
||||||
|
- Reseeds list
|
||||||
|
### Fixed
|
||||||
|
- Crash when a destination gets terminated
|
||||||
|
- Expired offline signature upon destination creation
|
||||||
|
- Race condition between local RouterInfo buffer creation and sending it through the transports
|
||||||
|
|
||||||
|
## [2.52.0] - 2024-05-12
|
||||||
|
### Added
|
||||||
|
- Separate threads for persisting RouterInfos and profiles to disk
|
||||||
|
- Give preference to address with direct connection
|
||||||
|
- Exclude addresses with incorrect static or intro key
|
||||||
|
- Avoid two firewalled routers in the row in tunnel
|
||||||
|
- Drop unsolicited database search replies
|
||||||
|
### Changed
|
||||||
|
- Increase number of hashes to 16 in exploratory lookup reply
|
||||||
|
- Reduce number of a RouterInfo lookup attempts to 5
|
||||||
|
- Reset stream RTO if outbound tunnel was changed
|
||||||
|
- Insert previously excluded floodfill back when successfully connected
|
||||||
|
- Increase maximum stream resend attempts to 9
|
||||||
|
- Reply to exploratory lookups with only confirmed routers if low tunnel build rate
|
||||||
|
- Don't accept too old RouterInfo
|
||||||
|
- Build client tunnels through confirmed routers only if low tunnel build rate
|
||||||
|
- Manage netDb requests more frequently
|
||||||
|
- Don't reply with closer than us only floodfills for lookup
|
||||||
|
### Fixed
|
||||||
|
- Crash on router lookup if exploratory pool is not ready
|
||||||
|
- Race condition in excluded peers for next lookup
|
||||||
|
- Excessive number of lookups for same destination
|
||||||
|
- Race condition with transport peers during shutdown
|
||||||
|
- Corrupted RouterInfo files
|
||||||
|
|
||||||
## [2.51.0] - 2024-04-06
|
## [2.51.0] - 2024-04-06
|
||||||
### Added
|
### Added
|
||||||
- Non-blocking mode for UDP sockets
|
- Non-blocking mode for UDP sockets
|
||||||
|
@ -15,4 +15,4 @@ endif
|
|||||||
DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1
|
DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1
|
||||||
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
||||||
LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||||
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_filesystem -lboost_program_options -lpthread
|
||||||
|
@ -2,7 +2,7 @@ CXX = g++
|
|||||||
CXXFLAGS := -Wall -std=c++11
|
CXXFLAGS := -Wall -std=c++11
|
||||||
INCFLAGS = -I/system/develop/headers
|
INCFLAGS = -I/system/develop/headers
|
||||||
DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE
|
DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE
|
||||||
LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread
|
||||||
|
|
||||||
ifeq ($(USE_UPNP),yes)
|
ifeq ($(USE_UPNP),yes)
|
||||||
DEFINES += -DUSE_UPNP
|
DEFINES += -DUSE_UPNP
|
||||||
|
@ -1,41 +1,40 @@
|
|||||||
# root directory holding homebrew
|
# root directory holding homebrew
|
||||||
BREWROOT = /usr/local
|
BREWROOT = /opt/homebrew
|
||||||
BOOSTROOT = ${BREWROOT}/opt/boost
|
BOOSTROOT = ${BREWROOT}/opt/boost
|
||||||
SSLROOT = ${BREWROOT}/opt/openssl@1.1
|
SSLROOT = ${BREWROOT}/opt/openssl@1.1
|
||||||
UPNPROOT = ${BREWROOT}/opt/miniupnpc
|
UPNPROOT = ${BREWROOT}/opt/miniupnpc
|
||||||
CXXFLAGS = ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual
|
|
||||||
INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
|
|
||||||
LDFLAGS = ${LD_DEBUG}
|
|
||||||
|
|
||||||
ifndef TRAVIS
|
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wno-overloaded-virtual
|
||||||
CXX = clang++
|
NEEDED_CXXFLAGS ?= -std=c++11
|
||||||
endif
|
INCFLAGS ?= -I${SSLROOT}/include -I${BOOSTROOT}/include
|
||||||
|
LDFLAGS ?= ${LD_DEBUG}
|
||||||
|
DEFINES += -DMAC_OSX
|
||||||
|
|
||||||
ifeq ($(USE_STATIC),yes)
|
ifeq ($(USE_STATIC),yes)
|
||||||
LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a -lpthread
|
LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a
|
||||||
|
ifeq ($(USE_UPNP),yes)
|
||||||
|
LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a
|
||||||
|
endif
|
||||||
|
LDLIBS += -lpthread -ldl
|
||||||
else
|
else
|
||||||
LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib
|
LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib
|
||||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread
|
||||||
|
ifeq ($(USE_UPNP),yes)
|
||||||
|
LDFLAGS += -L${UPNPROOT}/lib
|
||||||
|
LDLIBS += -lminiupnpc
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_UPNP),yes)
|
ifeq ($(USE_UPNP),yes)
|
||||||
LDFLAGS += -ldl
|
DEFINES += -DUSE_UPNP
|
||||||
CXXFLAGS += -DUSE_UPNP
|
|
||||||
INCFLAGS += -I${UPNPROOT}/include
|
INCFLAGS += -I${UPNPROOT}/include
|
||||||
ifeq ($(USE_STATIC),yes)
|
|
||||||
LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a
|
|
||||||
else
|
|
||||||
LDFLAGS += -L${UPNPROOT}/lib
|
|
||||||
LDLIBS += -lminiupnpc
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# OSX Notes
|
|
||||||
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html
|
|
||||||
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
|
|
||||||
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
|
|
||||||
ifeq ($(USE_AESNI),yes)
|
ifeq ($(USE_AESNI),yes)
|
||||||
CXXFLAGS += -D__AES__ -maes
|
ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that
|
||||||
|
NEEDED_CXXFLAGS += -maes
|
||||||
|
DEFINES += -D__AES__
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
@ -39,7 +39,6 @@ ifeq ($(USE_STATIC),yes)
|
|||||||
# the shared libraries from the glibc version used for linking
|
# the shared libraries from the glibc version used for linking
|
||||||
LIBDIR := /usr/lib/$(SYS)
|
LIBDIR := /usr/lib/$(SYS)
|
||||||
LDLIBS += $(LIBDIR)/libboost_system.a
|
LDLIBS += $(LIBDIR)/libboost_system.a
|
||||||
LDLIBS += $(LIBDIR)/libboost_date_time.a
|
|
||||||
LDLIBS += $(LIBDIR)/libboost_filesystem.a
|
LDLIBS += $(LIBDIR)/libboost_filesystem.a
|
||||||
LDLIBS += $(LIBDIR)/libboost_program_options.a
|
LDLIBS += $(LIBDIR)/libboost_program_options.a
|
||||||
LDLIBS += $(LIBDIR)/libssl.a
|
LDLIBS += $(LIBDIR)/libssl.a
|
||||||
@ -50,7 +49,7 @@ ifeq ($(USE_UPNP),yes)
|
|||||||
endif
|
endif
|
||||||
LDLIBS += -lpthread -ldl
|
LDLIBS += -lpthread -ldl
|
||||||
else
|
else
|
||||||
LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_filesystem -lboost_program_options -lpthread
|
||||||
ifeq ($(USE_UPNP),yes)
|
ifeq ($(USE_UPNP),yes)
|
||||||
LDLIBS += -lminiupnpc
|
LDLIBS += -lminiupnpc
|
||||||
endif
|
endif
|
||||||
|
@ -18,7 +18,6 @@ endif
|
|||||||
|
|
||||||
LDLIBS += \
|
LDLIBS += \
|
||||||
$(MINGW_PREFIX)/lib/libboost_system-mt.a \
|
$(MINGW_PREFIX)/lib/libboost_system-mt.a \
|
||||||
$(MINGW_PREFIX)/lib/libboost_date_time-mt.a \
|
|
||||||
$(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \
|
$(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \
|
||||||
$(MINGW_PREFIX)/lib/libboost_program_options-mt.a \
|
$(MINGW_PREFIX)/lib/libboost_program_options-mt.a \
|
||||||
$(MINGW_PREFIX)/lib/libssl.a \
|
$(MINGW_PREFIX)/lib/libssl.a \
|
||||||
|
@ -7,9 +7,9 @@ LDFLAGS += -Wl,-dead_strip
|
|||||||
LDFLAGS += -Wl,-dead_strip_dylibs
|
LDFLAGS += -Wl,-dead_strip_dylibs
|
||||||
|
|
||||||
ifeq ($(USE_STATIC),yes)
|
ifeq ($(USE_STATIC),yes)
|
||||||
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
||||||
else
|
else
|
||||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_UPNP),yes)
|
ifeq ($(USE_UPNP),yes)
|
||||||
|
@ -73,16 +73,24 @@ void UnSubscribeFromEvents()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pNetEvent)
|
if (pNetEvent)
|
||||||
|
{
|
||||||
pNetEvent->Release();
|
pNetEvent->Release();
|
||||||
|
}
|
||||||
|
|
||||||
if (pCPContainer)
|
if (pCPContainer)
|
||||||
|
{
|
||||||
pCPContainer->Release();
|
pCPContainer->Release();
|
||||||
|
}
|
||||||
|
|
||||||
if (pNetworkListManager)
|
if (pNetworkListManager)
|
||||||
|
{
|
||||||
pNetworkListManager->Release();
|
pNetworkListManager->Release();
|
||||||
|
}
|
||||||
|
|
||||||
if (pUnknown)
|
if (pUnknown)
|
||||||
|
{
|
||||||
pUnknown->Release();
|
pUnknown->Release();
|
||||||
|
}
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,11 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
|
|
||||||
class CNetworkListManagerEvent : public INetworkListManagerEvents
|
class CNetworkListManagerEvent final : public INetworkListManagerEvents
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CNetworkListManagerEvent() : m_ref(1) { }
|
CNetworkListManagerEvent() : m_ref(1) { }
|
||||||
|
~CNetworkListManagerEvent() { }
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
||||||
{
|
{
|
||||||
|
@ -277,14 +277,14 @@ else()
|
|||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||||
endif()
|
endif()
|
||||||
add_definitions(-DBOOST_ATOMIC_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
|
add_definitions(-DBOOST_ATOMIC_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(Boost_USE_STATIC_LIBS OFF)
|
set(Boost_USE_STATIC_LIBS OFF)
|
||||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Boost REQUIRED COMPONENTS system filesystem program_options date_time OPTIONAL_COMPONENTS atomic)
|
find_package(Boost REQUIRED COMPONENTS system filesystem program_options OPTIONAL_COMPONENTS atomic)
|
||||||
if(NOT DEFINED Boost_FOUND)
|
if(NOT DEFINED Boost_FOUND)
|
||||||
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
|
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
|
||||||
endif()
|
endif()
|
||||||
|
@ -24,7 +24,7 @@ ExtraDiskSpaceRequired=15
|
|||||||
|
|
||||||
AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2}
|
AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2}
|
||||||
AppVerName={#I2Pd_AppName}
|
AppVerName={#I2Pd_AppName}
|
||||||
AppCopyright=Copyright (c) 2013-2022, The PurpleI2P Project
|
AppCopyright=Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
AppPublisherURL=http://i2pd.website/
|
AppPublisherURL=http://i2pd.website/
|
||||||
AppSupportURL=https://github.com/PurpleI2P/i2pd/issues
|
AppSupportURL=https://github.com/PurpleI2P/i2pd/issues
|
||||||
AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases
|
AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
#include <tunables/global>
|
#include <tunables/global>
|
||||||
|
|
||||||
profile i2pd /{usr/,}sbin/i2pd {
|
profile i2pd /{usr/,}bin/i2pd {
|
||||||
#include <abstractions/base>
|
#include <abstractions/base>
|
||||||
#include <abstractions/openssl>
|
#include <abstractions/openssl>
|
||||||
#include <abstractions/nameservice>
|
#include <abstractions/nameservice>
|
||||||
@ -14,12 +14,12 @@ profile i2pd /{usr/,}sbin/i2pd {
|
|||||||
/var/lib/i2pd/** rw,
|
/var/lib/i2pd/** rw,
|
||||||
/var/log/i2pd/i2pd.log w,
|
/var/log/i2pd/i2pd.log w,
|
||||||
/{var/,}run/i2pd/i2pd.pid rwk,
|
/{var/,}run/i2pd/i2pd.pid rwk,
|
||||||
/{usr/,}sbin/i2pd mr,
|
/{usr/,}bin/i2pd mr,
|
||||||
@{system_share_dirs}/i2pd/** r,
|
@{system_share_dirs}/i2pd/** r,
|
||||||
|
|
||||||
# user homedir (if started not by init.d or systemd)
|
# user homedir (if started not by init.d or systemd)
|
||||||
owner @{HOME}/.i2pd/ rw,
|
owner @{HOME}/.i2pd/ rw,
|
||||||
owner @{HOME}/.i2pd/** rwk,
|
owner @{HOME}/.i2pd/** rwk,
|
||||||
|
|
||||||
#include if exists <local/usr.sbin.i2pd>
|
#include if exists <local/usr.bin.i2pd>
|
||||||
}
|
}
|
@ -1,32 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFdTCCA12gAwIBAgIEQ5vCxzANBgkqhkiG9w0BAQ0FADBrMQswCQYDVQQGEwJY
|
|
||||||
WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnlt
|
|
||||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEUMBIGA1UEAwwLbHNAbWFpbC5pMnAw
|
|
||||||
HhcNMjMxMDE2MjAwNTA5WhcNMzMxMDEzMjAwNTA5WjBrMQswCQYDVQQGEwJYWDEL
|
|
||||||
MAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnltb3Vz
|
|
||||||
IE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEUMBIGA1UEAwwLbHNAbWFpbC5pMnAwggIi
|
|
||||||
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDPcbKRtf4PzrDa0iRit0XrwnmA
|
|
||||||
2c1fJhkBipdPor7gMOAlkR82H1lkZSizR7kTZnr7vYqjDrOQr7bl5Dy3qo8/YCbZ
|
|
||||||
jsnUCTIIgIJQUxUlR40RjaSXphqzUEiXKHR6b0RahhFisQ3hlbbgzSch5YgSLKws
|
|
||||||
hOLi+eDSXw+HlwHlWFlT1XOKxSTJ/F3Bv40gxqZVC2pbxiPOeRZHQ6Ojw75lxTSF
|
|
||||||
gww2WzgztiWt4X9BO1yepnVqhAVRPmTfGUMfKzq9jkMzZKeQFV4uZSP9nCqzEpYd
|
|
||||||
WNDUfpTWiAQ9F+BwFXGusXXA3tGVwS7s6IEoiJFM5fsoJYfRoWGh3/1eirhBXW7U
|
|
||||||
M6oubMSTADyrvfjLfJBMmMnc2hNblRlKr0ZKUjMfv8cnyT4kQxlXLAHHXY2P89TM
|
|
||||||
TEVODkU48gnv6tC4t1JCb1/Da+3yVMjNX6rCzQfUwnLFrWthrwiI0NivAKFtiZjq
|
|
||||||
w1/ZQcYke2YyeqcfXMn+NTUA22Sm2mJoMo7jUf+rbM9Pi27/DncJgRGj5qwY0D3S
|
|
||||||
gc7829EjuZNPttGBmae1EmO7WQMB32cqdmItnV2FXpMhnn9h0u5H52kYqwn+mdtc
|
|
||||||
dTJRcbfKG1RTr3UjFISaTwL8qigMIkVXIzcpnr/R/sSeEs8xCqfsJ6rb4dCyFx+M
|
|
||||||
hqQcOCL5tumyd4W/LQIDAQABoyEwHzAdBgNVHQ4EFgQUgfaOG5HCnlW82wZ5BahL
|
|
||||||
GRO06igwDQYJKoZIhvcNAQENBQADggIBAKdVpqS9qF7gGotgXaVA1iP5YNsWlTvG
|
|
||||||
daGqeA/87//U21W6gpq82FhzsmsvUtXZfIeVIlDPI7WNDzS+A3K/KKrwM7dLgSie
|
|
||||||
r9eMl3D8WYPU95QF4mAlRyl7PCCsYoVjyvfro0iq3/iudIA5476rjfLdTXRi5hAT
|
|
||||||
qemPj0S+6sRjKEldRtGXrQATFlvLIWVYpgHijdDDx5M2hAz2y0mFxlDZTlA4BhL4
|
|
||||||
DwtGlVKmbc2x5MvIQM4UhbQqkxYS4gXnzf5Qx9QIytHfTr/hmbrkhKR1GCO31BSk
|
|
||||||
x9LhZxdI8LlwKSo6YgwXEB9E0M/tplaK9iZJFv4HPYLZrVJpb4IklMumyLMrgW5P
|
|
||||||
fR0dgKn+R9lk0emJ1Cu+qyyzf1vsLycYBwaEztINn4VK+/HfDFpnVCvJOyNuDmj5
|
|
||||||
KBLIoGdGoVfylmnc+e8zAXe+DY41fgniHMISOO78P8Bx9vTB+rhqnOUr9MzlUxPB
|
|
||||||
sKGjbXy2YynEqiGb+9g344v/+ukTSDenqTPHVzJ5uOi0iedy+3ASzUNN6GJocovP
|
|
||||||
167VOhwaETM0FwiKe0VdZRLLbbZ79CtJC0tmgcgPQPRa9Ldr6KN7u1J3D6lUp6zl
|
|
||||||
byPom10ueKONRb36t7ai79l2SEUZRSMkx6AXIU0JJ1SMtQtav7b5LkpYJfdL7+vO
|
|
||||||
dDx2/Za0VmdD
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -2,7 +2,7 @@ Description: Disable LogsDirectory and LogsDirectoryMode options in service
|
|||||||
Author: r4sas <r4sas@i2pmail.org>
|
Author: r4sas <r4sas@i2pmail.org>
|
||||||
|
|
||||||
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
||||||
Last-Update: 2023-05-17
|
Last-Update: 2024-07-19
|
||||||
|
|
||||||
--- a/contrib/i2pd.service
|
--- a/contrib/i2pd.service
|
||||||
+++ b/contrib/i2pd.service
|
+++ b/contrib/i2pd.service
|
||||||
@ -15,5 +15,5 @@ Last-Update: 2023-05-17
|
|||||||
+#LogsDirectory=i2pd
|
+#LogsDirectory=i2pd
|
||||||
+#LogsDirectoryMode=0700
|
+#LogsDirectoryMode=0700
|
||||||
Type=forking
|
Type=forking
|
||||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
ExecStart=/usr/bin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||||
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
||||||
|
@ -2,7 +2,7 @@ Description: Disable LogsDirectory and LogsDirectoryMode options in service
|
|||||||
Author: r4sas <r4sas@i2pmail.org>
|
Author: r4sas <r4sas@i2pmail.org>
|
||||||
|
|
||||||
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
||||||
Last-Update: 2023-05-17
|
Last-Update: 2024-07-19
|
||||||
|
|
||||||
--- a/contrib/i2pd.service
|
--- a/contrib/i2pd.service
|
||||||
+++ b/contrib/i2pd.service
|
+++ b/contrib/i2pd.service
|
||||||
@ -15,5 +15,5 @@ Last-Update: 2023-05-17
|
|||||||
+#LogsDirectory=i2pd
|
+#LogsDirectory=i2pd
|
||||||
+#LogsDirectoryMode=0700
|
+#LogsDirectoryMode=0700
|
||||||
Type=forking
|
Type=forking
|
||||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
ExecStart=/usr/bin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||||
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
||||||
|
@ -11,7 +11,7 @@ RuntimeDirectoryMode=0700
|
|||||||
LogsDirectory=i2pd
|
LogsDirectory=i2pd
|
||||||
LogsDirectoryMode=0700
|
LogsDirectoryMode=0700
|
||||||
Type=forking
|
Type=forking
|
||||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
ExecStart=/usr/bin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||||
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
||||||
PIDFile=/run/i2pd/i2pd.pid
|
PIDFile=/run/i2pd/i2pd.pid
|
||||||
### Uncomment, if auto restart needed
|
### Uncomment, if auto restart needed
|
||||||
|
@ -7,7 +7,7 @@ tunconf="/etc/i2pd/tunnels.conf"
|
|||||||
tundir="/etc/i2pd/tunnels.conf.d"
|
tundir="/etc/i2pd/tunnels.conf.d"
|
||||||
|
|
||||||
name="i2pd"
|
name="i2pd"
|
||||||
command="/usr/sbin/i2pd"
|
command="/usr/bin/i2pd"
|
||||||
command_args="--service --daemon --log=file --logfile=$logfile --conf=$mainconf --tunconf=$tunconf --tunnelsdir=$tundir --pidfile=$pidfile"
|
command_args="--service --daemon --log=file --logfile=$logfile --conf=$mainconf --tunconf=$tunconf --tunnelsdir=$tundir --pidfile=$pidfile"
|
||||||
description="i2p router written in C++"
|
description="i2p router written in C++"
|
||||||
required_dirs="/var/lib/i2pd"
|
required_dirs="/var/lib/i2pd"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||||
|
|
||||||
Name: i2pd-git
|
Name: i2pd-git
|
||||||
Version: 2.51.0
|
Version: 2.53.1
|
||||||
Release: git%{git_hash}%{?dist}
|
Release: git%{git_hash}%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd
|
Conflicts: i2pd
|
||||||
@ -24,6 +24,10 @@ BuildRequires: openssl-devel
|
|||||||
BuildRequires: miniupnpc-devel
|
BuildRequires: miniupnpc-devel
|
||||||
BuildRequires: systemd-units
|
BuildRequires: systemd-units
|
||||||
|
|
||||||
|
%if 0%{?fedora} > 40 || 0%{?eln}
|
||||||
|
BuildRequires: openssl-devel-engine
|
||||||
|
%endif
|
||||||
|
|
||||||
Requires: logrotate
|
Requires: logrotate
|
||||||
Requires: systemd
|
Requires: systemd
|
||||||
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
|
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
|
||||||
@ -93,7 +97,7 @@ pushd build
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
chrpath -d i2pd
|
chrpath -d i2pd
|
||||||
%{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
%{__install} -D -m 755 i2pd %{buildroot}%{_bindir}/i2pd
|
||||||
%{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
|
%{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
|
||||||
%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
|
%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
|
||||||
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
|
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
|
||||||
@ -129,7 +133,7 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
%files
|
%files
|
||||||
%doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d
|
%doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d
|
||||||
%{_sbindir}/i2pd
|
%{_bindir}/i2pd
|
||||||
%config(noreplace) %{_sysconfdir}/i2pd/*.conf
|
%config(noreplace) %{_sysconfdir}/i2pd/*.conf
|
||||||
%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/*.conf
|
%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/*.conf
|
||||||
%config %{_sysconfdir}/i2pd/subscriptions.txt
|
%config %{_sysconfdir}/i2pd/subscriptions.txt
|
||||||
@ -144,6 +148,15 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Jul 30 2024 orignal <orignal@i2pmail.org> - 2.53.1
|
||||||
|
- update to 2.53.1
|
||||||
|
|
||||||
|
* Fri Jul 19 2024 orignal <orignal@i2pmail.org> - 2.53.0
|
||||||
|
- update to 2.53.0
|
||||||
|
|
||||||
|
* Sun May 12 2024 orignal <orignal@i2pmail.org> - 2.52.0
|
||||||
|
- update to 2.52.0
|
||||||
|
|
||||||
* Sat Apr 06 2024 orignal <orignal@i2pmail.org> - 2.51.0
|
* Sat Apr 06 2024 orignal <orignal@i2pmail.org> - 2.51.0
|
||||||
- update to 2.51.0
|
- update to 2.51.0
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Name: i2pd
|
Name: i2pd
|
||||||
Version: 2.51.0
|
Version: 2.53.1
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd-git
|
Conflicts: i2pd-git
|
||||||
@ -22,6 +22,10 @@ BuildRequires: openssl-devel
|
|||||||
BuildRequires: miniupnpc-devel
|
BuildRequires: miniupnpc-devel
|
||||||
BuildRequires: systemd-units
|
BuildRequires: systemd-units
|
||||||
|
|
||||||
|
%if 0%{?fedora} > 40 || 0%{?eln}
|
||||||
|
BuildRequires: openssl-devel-engine
|
||||||
|
%endif
|
||||||
|
|
||||||
Requires: logrotate
|
Requires: logrotate
|
||||||
Requires: systemd
|
Requires: systemd
|
||||||
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
|
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
|
||||||
@ -91,7 +95,7 @@ pushd build
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
chrpath -d i2pd
|
chrpath -d i2pd
|
||||||
%{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
%{__install} -D -m 755 i2pd %{buildroot}%{_bindir}/i2pd
|
||||||
%{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
|
%{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
|
||||||
%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
|
%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
|
||||||
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
|
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
|
||||||
@ -127,7 +131,7 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
%files
|
%files
|
||||||
%doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d
|
%doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d
|
||||||
%{_sbindir}/i2pd
|
%{_bindir}/i2pd
|
||||||
%config(noreplace) %{_sysconfdir}/i2pd/*.conf
|
%config(noreplace) %{_sysconfdir}/i2pd/*.conf
|
||||||
%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/*.conf
|
%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/*.conf
|
||||||
%config %{_sysconfdir}/i2pd/subscriptions.txt
|
%config %{_sysconfdir}/i2pd/subscriptions.txt
|
||||||
@ -142,6 +146,15 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Jul 30 2024 orignal <orignal@i2pmail.org> - 2.53.1
|
||||||
|
- update to 2.53.1
|
||||||
|
|
||||||
|
* Fri Jul 19 2024 orignal <orignal@i2pmail.org> - 2.53.0
|
||||||
|
- update to 2.53.0
|
||||||
|
|
||||||
|
* Sun May 12 2024 orignal <orignal@i2pmail.org> - 2.52.0
|
||||||
|
- update to 2.52.0
|
||||||
|
|
||||||
* Sat Apr 06 2024 orignal <orignal@i2pmail.org> - 2.51.0
|
* Sat Apr 06 2024 orignal <orignal@i2pmail.org> - 2.51.0
|
||||||
- update to 2.51.0
|
- update to 2.51.0
|
||||||
|
|
||||||
|
@ -8,4 +8,4 @@ env LOGFILE="/var/log/i2pd/i2pd.log"
|
|||||||
|
|
||||||
expect fork
|
expect fork
|
||||||
|
|
||||||
exec /usr/sbin/i2pd --daemon --service --log=file --logfile=$LOGFILE
|
exec /usr/bin/i2pd --daemon --service --log=file --logfile=$LOGFILE
|
||||||
|
@ -188,7 +188,7 @@ namespace util
|
|||||||
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
|
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
|
||||||
if (bandwidth.length () > 0)
|
if (bandwidth.length () > 0)
|
||||||
{
|
{
|
||||||
if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X')
|
if (bandwidth.length () == 1 && ((bandwidth[0] >= 'K' && bandwidth[0] <= 'P') || bandwidth[0] == 'X' ))
|
||||||
{
|
{
|
||||||
i2p::context.SetBandwidth (bandwidth[0]);
|
i2p::context.SetBandwidth (bandwidth[0]);
|
||||||
LogPrint(eLogInfo, "Daemon: Bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps");
|
LogPrint(eLogInfo, "Daemon: Bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps");
|
||||||
|
@ -417,6 +417,15 @@ namespace http {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ShowHop(std::stringstream& s, const i2p::data::IdentityEx& ident)
|
||||||
|
{
|
||||||
|
auto identHash = ident.GetIdentHash();
|
||||||
|
auto router = i2p::data::netdb.FindRouter(identHash);
|
||||||
|
s << i2p::data::GetIdentHashAbbreviation(identHash);
|
||||||
|
if (router)
|
||||||
|
s << "<small style=\"color:gray\"> " << router->GetBandwidthCap() << "</small>";
|
||||||
|
}
|
||||||
|
|
||||||
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token)
|
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token)
|
||||||
{
|
{
|
||||||
s << "<b>Base32:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"1\">";
|
s << "<b>Base32:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"1\">";
|
||||||
@ -482,7 +491,9 @@ namespace http {
|
|||||||
it->VisitTunnelHops(
|
it->VisitTunnelHops(
|
||||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||||
{
|
{
|
||||||
s << "⇒ " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ";
|
s << "⇒ ";
|
||||||
|
ShowHop(s, *hopIdent);
|
||||||
|
s << " ";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -503,7 +514,9 @@ namespace http {
|
|||||||
it->VisitTunnelHops(
|
it->VisitTunnelHops(
|
||||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||||
{
|
{
|
||||||
s << " " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ⇒";
|
s << " ";
|
||||||
|
ShowHop(s, *hopIdent);
|
||||||
|
s << " ⇒";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -699,7 +712,9 @@ namespace http {
|
|||||||
it->VisitTunnelHops(
|
it->VisitTunnelHops(
|
||||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||||
{
|
{
|
||||||
s << "⇒ " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ";
|
s << "⇒ ";
|
||||||
|
ShowHop(s, *hopIdent);
|
||||||
|
s << " ";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -720,7 +735,9 @@ namespace http {
|
|||||||
it->VisitTunnelHops(
|
it->VisitTunnelHops(
|
||||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||||
{
|
{
|
||||||
s << " " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ⇒";
|
s << " ";
|
||||||
|
ShowHop(s, *hopIdent);
|
||||||
|
s << " ⇒";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,12 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
// Use global placeholders from boost introduced when local_time.hpp is loaded
|
// Use global placeholders from boost introduced when local_time.hpp is loaded
|
||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||||
|
|
||||||
#include <boost/date_time/local_time/local_time.hpp>
|
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
@ -258,9 +256,9 @@ namespace client
|
|||||||
header << "Content-Length: " << boost::lexical_cast<std::string>(len) << "\r\n";
|
header << "Content-Length: " << boost::lexical_cast<std::string>(len) << "\r\n";
|
||||||
header << "Content-Type: application/json\r\n";
|
header << "Content-Type: application/json\r\n";
|
||||||
header << "Date: ";
|
header << "Date: ";
|
||||||
auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT");
|
std::time_t t = std::time (nullptr);
|
||||||
header.imbue(std::locale (header.getloc(), facet));
|
std::tm tm = *std::gmtime (&t);
|
||||||
header << boost::posix_time::second_clock::local_time() << "\r\n";
|
header << std::put_time(&tm, "%a, %d %b %Y %T GMT") << "\r\n";
|
||||||
header << "\r\n";
|
header << "\r\n";
|
||||||
offset = header.str ().size ();
|
offset = header.str ().size ();
|
||||||
memcpy (buf->data (), header.str ().c_str (), offset);
|
memcpy (buf->data (), header.str ().c_str (), offset);
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
|
*
|
||||||
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
|
*
|
||||||
|
* See full license text in LICENSE file at top of project tree
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <boost/thread/thread.hpp>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
@ -110,10 +115,16 @@ namespace transport
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (MINIUPNPC_API_VERSION >= 18)
|
||||||
|
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr),
|
||||||
|
m_externalIPAddress, sizeof (m_externalIPAddress));
|
||||||
|
#else
|
||||||
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
||||||
|
#endif
|
||||||
m_upnpUrlsInitialized=err!=0;
|
m_upnpUrlsInitialized=err!=0;
|
||||||
if (err == UPNP_IGD_VALID_CONNECTED)
|
if (err == UPNP_IGD_VALID_CONNECTED)
|
||||||
{
|
{
|
||||||
|
#if (MINIUPNPC_API_VERSION < 18)
|
||||||
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
||||||
if(err != UPNPCOMMAND_SUCCESS)
|
if(err != UPNPCOMMAND_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -121,6 +132,7 @@ namespace transport
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "UPnP: Found Internet Gateway Device ", m_upnpUrls.controlURL);
|
LogPrint (eLogError, "UPnP: Found Internet Gateway Device ", m_upnpUrls.controlURL);
|
||||||
if (!m_externalIPAddress[0])
|
if (!m_externalIPAddress[0])
|
||||||
@ -166,11 +178,11 @@ namespace transport
|
|||||||
if (address && !address->host.is_v6 () && address->port)
|
if (address && !address->host.is_v6 () && address->port)
|
||||||
TryPortMapping (address);
|
TryPortMapping (address);
|
||||||
}
|
}
|
||||||
m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes
|
m_Timer.expires_from_now (boost::posix_time::minutes(UPNP_PORT_FORWARDING_INTERVAL)); // every 20 minutes
|
||||||
m_Timer.async_wait ([this](const boost::system::error_code& ecode)
|
m_Timer.async_wait ([this](const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
PortMapping ();
|
PortMapping ();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -28,7 +28,8 @@ namespace i2p
|
|||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
const int UPNP_RESPONSE_TIMEOUT = 2000; // in milliseconds
|
const int UPNP_RESPONSE_TIMEOUT = 2000; // in milliseconds
|
||||||
|
const int UPNP_PORT_FORWARDING_INTERVAL = 20; // in minutes
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
UPNP_IGD_NONE = 0,
|
UPNP_IGD_NONE = 0,
|
||||||
|
@ -162,12 +162,21 @@ namespace i2p
|
|||||||
|
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
if (lockf(pidFH, F_TLOCK, 0) != 0)
|
if (lockf(pidFH, F_TLOCK, 0) != 0)
|
||||||
|
#else
|
||||||
|
struct flock fl;
|
||||||
|
fl.l_len = 0;
|
||||||
|
fl.l_type = F_WRLCK;
|
||||||
|
fl.l_whence = SEEK_SET;
|
||||||
|
fl.l_start = 0;
|
||||||
|
|
||||||
|
if (fcntl(pidFH, F_SETLK, &fl) != 0)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
LogPrint(eLogError, "Daemon: Could not lock pid file ", pidfile, ": ", strerror(errno));
|
LogPrint(eLogError, "Daemon: Could not lock pid file ", pidfile, ": ", strerror(errno));
|
||||||
std::cerr << "i2pd: Could not lock pid file " << pidfile << ": " << strerror(errno) << std::endl;
|
std::cerr << "i2pd: Could not lock pid file " << pidfile << ": " << strerror(errno) << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
char pid[10];
|
char pid[10];
|
||||||
sprintf(pid, "%d\n", getpid());
|
sprintf(pid, "%d\n", getpid());
|
||||||
ftruncate(pidFH, 0);
|
ftruncate(pidFH, 0);
|
||||||
|
5
debian/NEWS
vendored
Normal file
5
debian/NEWS
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
i2pd (2.53.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
i2pd binary moved from /usr/sbin to /usr/bin. Please check your scripts if you used the old path.
|
||||||
|
|
||||||
|
-- r4sas <r4sas@i2pmail.org> Fri, 19 Jul 2024 16:00:00 +0000
|
19
debian/changelog
vendored
19
debian/changelog
vendored
@ -1,3 +1,22 @@
|
|||||||
|
i2pd (2.53.1-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.53.1
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Tue, 30 Jul 2024 16:00:00 +0000
|
||||||
|
|
||||||
|
i2pd (2.53.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.53.0/0.9.63
|
||||||
|
* binary moved from /usr/sbin to /usr/bin
|
||||||
|
|
||||||
|
-- r4sas <r4sas@i2pmail.org> Sat, 20 Jul 2024 15:10:00 +0000
|
||||||
|
|
||||||
|
i2pd (2.52.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.52.0
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Sun, 12 May 2024 16:00:00 +0000
|
||||||
|
|
||||||
i2pd (2.51.0-1) unstable; urgency=medium
|
i2pd (2.51.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
* updated to version 2.51.0/0.9.62
|
* updated to version 2.51.0/0.9.62
|
||||||
|
2
debian/i2pd.init
vendored
2
debian/i2pd.init
vendored
@ -13,7 +13,7 @@
|
|||||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||||
DESC=i2pd # Introduce a short description here
|
DESC=i2pd # Introduce a short description here
|
||||||
NAME=i2pd # Introduce the short server's name here
|
NAME=i2pd # Introduce the short server's name here
|
||||||
DAEMON=/usr/sbin/$NAME # Introduce the server's location here
|
DAEMON=/usr/bin/$NAME # Introduce the server's location here
|
||||||
DAEMON_OPTS="" # Arguments to run the daemon with
|
DAEMON_OPTS="" # Arguments to run the daemon with
|
||||||
PIDFILE=/var/run/$NAME/$NAME.pid
|
PIDFILE=/var/run/$NAME/$NAME.pid
|
||||||
I2PCONF=/etc/$NAME/i2pd.conf
|
I2PCONF=/etc/$NAME/i2pd.conf
|
||||||
|
4
debian/i2pd.install
vendored
4
debian/i2pd.install
vendored
@ -1,6 +1,6 @@
|
|||||||
i2pd usr/sbin/
|
i2pd usr/bin/
|
||||||
contrib/i2pd.conf etc/i2pd/
|
contrib/i2pd.conf etc/i2pd/
|
||||||
contrib/tunnels.conf etc/i2pd/
|
contrib/tunnels.conf etc/i2pd/
|
||||||
contrib/certificates/ usr/share/i2pd/
|
contrib/certificates/ usr/share/i2pd/
|
||||||
contrib/tunnels.d/README etc/i2pd/tunnels.conf.d/
|
contrib/tunnels.d/README etc/i2pd/tunnels.conf.d/
|
||||||
contrib/apparmor/usr.sbin.i2pd etc/apparmor.d
|
contrib/apparmor/usr.bin.i2pd etc/apparmor.d
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -64,11 +64,12 @@ namespace chinese // language namespace
|
|||||||
{"Full cone NAT", "全锥型NAT"},
|
{"Full cone NAT", "全锥型NAT"},
|
||||||
{"No Descriptors", "无描述符"},
|
{"No Descriptors", "无描述符"},
|
||||||
{"Uptime", "运行时间"},
|
{"Uptime", "运行时间"},
|
||||||
{"Network status", "IPv4 网络状态"},
|
{"Network status", "网络状态"},
|
||||||
{"Network status v6", "IPv6 网络状态"},
|
{"Network status v6", "IPv6 网络状态"},
|
||||||
{"Stopping in", "距停止还有:"},
|
{"Stopping in", "距停止还有:"},
|
||||||
{"Family", "家族"},
|
{"Family", "家族"},
|
||||||
{"Tunnel creation success rate", "隧道创建成功率"},
|
{"Tunnel creation success rate", "隧道创建成功率"},
|
||||||
|
{"Total tunnel creation success rate", "当前隧道创建成功率"},
|
||||||
{"Received", "已接收"},
|
{"Received", "已接收"},
|
||||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||||
{"Sent", "已发送"},
|
{"Sent", "已发送"},
|
||||||
@ -95,6 +96,7 @@ namespace chinese // language namespace
|
|||||||
{"Address", "地址"},
|
{"Address", "地址"},
|
||||||
{"Type", "类型"},
|
{"Type", "类型"},
|
||||||
{"EncType", "加密类型"},
|
{"EncType", "加密类型"},
|
||||||
|
{"Expire LeaseSet", "到期租约集"},
|
||||||
{"Inbound tunnels", "入站隧道"},
|
{"Inbound tunnels", "入站隧道"},
|
||||||
{"%dms", "%dms"},
|
{"%dms", "%dms"},
|
||||||
{"Outbound tunnels", "出站隧道"},
|
{"Outbound tunnels", "出站隧道"},
|
||||||
@ -151,6 +153,8 @@ namespace chinese // language namespace
|
|||||||
{"StreamID can't be null", "StreamID 不能为空"},
|
{"StreamID can't be null", "StreamID 不能为空"},
|
||||||
{"Return to destination page", "返回目标页面"},
|
{"Return to destination page", "返回目标页面"},
|
||||||
{"You will be redirected in %d seconds", "您将在%d秒内被重定向"},
|
{"You will be redirected in %d seconds", "您将在%d秒内被重定向"},
|
||||||
|
{"LeaseSet expiration time updated", "租约集到期时间已更新"},
|
||||||
|
{"LeaseSet is not found or already expired", "租约集未找到或已过期"},
|
||||||
{"Transit tunnels count must not exceed %d", "中转隧道数量限制为 %d"},
|
{"Transit tunnels count must not exceed %d", "中转隧道数量限制为 %d"},
|
||||||
{"Back to commands list", "返回命令列表"},
|
{"Back to commands list", "返回命令列表"},
|
||||||
{"Register at reg.i2p", "在 reg.i2p 注册域名"},
|
{"Register at reg.i2p", "在 reg.i2p 注册域名"},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -36,18 +36,18 @@ namespace czech // language namespace
|
|||||||
{"%.2f GiB", "%.2f GiB"},
|
{"%.2f GiB", "%.2f GiB"},
|
||||||
{"building", "vytváří se"},
|
{"building", "vytváří se"},
|
||||||
{"failed", "selhalo"},
|
{"failed", "selhalo"},
|
||||||
{"expiring", "končící"},
|
{"expiring", "vyprší platnost"},
|
||||||
{"established", "vytvořeno"},
|
{"established", "vytvořeno"},
|
||||||
{"unknown", "neznámý"},
|
{"unknown", "neznámý"},
|
||||||
{"exploratory", "průzkumné"},
|
{"exploratory", "průzkumné"},
|
||||||
{"Purple I2P Webconsole", "Purple I2P Webkonsole"},
|
{"Purple I2P Webconsole", "Purple I2P webová konzole"},
|
||||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> webkonsole"},
|
{"<b>i2pd</b> webconsole", "<b>i2pd</b> webová konzole"},
|
||||||
{"Main page", "Hlavní stránka"},
|
{"Main page", "Hlavní stránka"},
|
||||||
{"Router commands", "Router příkazy"},
|
{"Router commands", "Router příkazy"},
|
||||||
{"Local Destinations", "Lokální destinace"},
|
{"Local Destinations", "Místní cíle"},
|
||||||
{"LeaseSets", "LeaseSety"},
|
{"LeaseSets", "Sety pronájmu"},
|
||||||
{"Tunnels", "Tunely"},
|
{"Tunnels", "Tunely"},
|
||||||
{"Transit Tunnels", "Transitní tunely"},
|
{"Transit Tunnels", "Tranzitní tunely"},
|
||||||
{"Transports", "Transporty"},
|
{"Transports", "Transporty"},
|
||||||
{"I2P tunnels", "I2P tunely"},
|
{"I2P tunnels", "I2P tunely"},
|
||||||
{"SAM sessions", "SAM relace"},
|
{"SAM sessions", "SAM relace"},
|
||||||
@ -61,18 +61,21 @@ namespace czech // language namespace
|
|||||||
{"Clock skew", "Časová nesrovnalost"},
|
{"Clock skew", "Časová nesrovnalost"},
|
||||||
{"Offline", "Offline"},
|
{"Offline", "Offline"},
|
||||||
{"Symmetric NAT", "Symetrický NAT"},
|
{"Symmetric NAT", "Symetrický NAT"},
|
||||||
|
{"Full cone NAT", "Full cone NAT"},
|
||||||
|
{"No Descriptors", "Žádné popisovače"},
|
||||||
{"Uptime", "Doba provozu"},
|
{"Uptime", "Doba provozu"},
|
||||||
{"Network status", "Status sítě"},
|
{"Network status", "Stav sítě"},
|
||||||
{"Network status v6", "Status sítě v6"},
|
{"Network status v6", "Stav sítě v6"},
|
||||||
{"Stopping in", "Zastavuji za"},
|
{"Stopping in", "Zastavuji za"},
|
||||||
{"Family", "Rodina"},
|
{"Family", "Rodina"},
|
||||||
{"Tunnel creation success rate", "Úspěšnost vytváření tunelů"},
|
{"Tunnel creation success rate", "Úspěšnost vytváření tunelů"},
|
||||||
|
{"Total tunnel creation success rate", "Celková míra úspěšnosti vytváření tunelů"},
|
||||||
{"Received", "Přijato"},
|
{"Received", "Přijato"},
|
||||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||||
{"Sent", "Odesláno"},
|
{"Sent", "Odesláno"},
|
||||||
{"Transit", "Tranzit"},
|
{"Transit", "Tranzit"},
|
||||||
{"Data path", "Cesta k data souborům"},
|
{"Data path", "Cesta k datovým souborům"},
|
||||||
{"Hidden content. Press on text to see.", "Skrytý kontent. Pro zobrazení, klikni na text."},
|
{"Hidden content. Press on text to see.", "Skrytý obsah. Pro zobrazení klikněte sem."},
|
||||||
{"Router Ident", "Routerová Identita"},
|
{"Router Ident", "Routerová Identita"},
|
||||||
{"Router Family", "Rodina routerů"},
|
{"Router Family", "Rodina routerů"},
|
||||||
{"Router Caps", "Omezení Routerů"},
|
{"Router Caps", "Omezení Routerů"},
|
||||||
@ -93,6 +96,7 @@ namespace czech // language namespace
|
|||||||
{"Address", "Adresa"},
|
{"Address", "Adresa"},
|
||||||
{"Type", "Typ"},
|
{"Type", "Typ"},
|
||||||
{"EncType", "EncType"},
|
{"EncType", "EncType"},
|
||||||
|
{"Expire LeaseSet", "Zrušit platnost setu pronájmu"},
|
||||||
{"Inbound tunnels", "Příchozí tunely"},
|
{"Inbound tunnels", "Příchozí tunely"},
|
||||||
{"%dms", "%dms"},
|
{"%dms", "%dms"},
|
||||||
{"Outbound tunnels", "Odchozí tunely"},
|
{"Outbound tunnels", "Odchozí tunely"},
|
||||||
@ -103,21 +107,24 @@ namespace czech // language namespace
|
|||||||
{"Amount", "Množství"},
|
{"Amount", "Množství"},
|
||||||
{"Incoming Tags", "Příchozí štítky"},
|
{"Incoming Tags", "Příchozí štítky"},
|
||||||
{"Tags sessions", "Relace štítků"},
|
{"Tags sessions", "Relace štítků"},
|
||||||
{"Status", "Status"},
|
{"Status", "Stav"},
|
||||||
{"Local Destination", "Lokální Destinace"},
|
{"Local Destination", "Místní cíl"},
|
||||||
{"Streams", "Toky"},
|
{"Streams", "Toky"},
|
||||||
{"Close stream", "Uzavřít tok"},
|
{"Close stream", "Uzavřít tok"},
|
||||||
|
{"Such destination is not found", "Takováto destinace nebyla nalezena"},
|
||||||
{"I2CP session not found", "I2CP relace nenalezena"},
|
{"I2CP session not found", "I2CP relace nenalezena"},
|
||||||
{"I2CP is not enabled", "I2CP není zapnuto"},
|
{"I2CP is not enabled", "I2CP není zapnuto"},
|
||||||
{"Invalid", "Neplatný"},
|
{"Invalid", "Neplatný"},
|
||||||
{"Store type", "Druh uložení"},
|
{"Store type", "Druh uložení"},
|
||||||
{"Expires", "Vyprší"},
|
{"Expires", "Vyprší"},
|
||||||
{"Non Expired Leases", "Nevypršené Leasy"},
|
{"Non Expired Leases", "Pronájmy, kterým nevypršela platnost"},
|
||||||
{"Gateway", "Brána"},
|
{"Gateway", "Brána"},
|
||||||
{"TunnelID", "ID tunelu"},
|
{"TunnelID", "ID tunelu"},
|
||||||
{"EndDate", "Datum ukončení"},
|
{"EndDate", "Datum ukončení"},
|
||||||
|
{"floodfill mode is disabled", "režim floodfill je vypnut"},
|
||||||
{"Queue size", "Velikost fronty"},
|
{"Queue size", "Velikost fronty"},
|
||||||
{"Run peer test", "Spustit peer test"},
|
{"Run peer test", "Spustit peer test"},
|
||||||
|
{"Reload tunnels configuration", "Znovu načíst nastavení tunelů"},
|
||||||
{"Decline transit tunnels", "Odmítnout tranzitní tunely"},
|
{"Decline transit tunnels", "Odmítnout tranzitní tunely"},
|
||||||
{"Accept transit tunnels", "Přijmout tranzitní tunely"},
|
{"Accept transit tunnels", "Přijmout tranzitní tunely"},
|
||||||
{"Cancel graceful shutdown", "Zrušit hladké vypnutí"},
|
{"Cancel graceful shutdown", "Zrušit hladké vypnutí"},
|
||||||
@ -145,14 +152,17 @@ namespace czech // language namespace
|
|||||||
{"Destination not found", "Destinace nenalezena"},
|
{"Destination not found", "Destinace nenalezena"},
|
||||||
{"StreamID can't be null", "StreamID nemůže být null"},
|
{"StreamID can't be null", "StreamID nemůže být null"},
|
||||||
{"Return to destination page", "Zpět na stránku destinací"},
|
{"Return to destination page", "Zpět na stránku destinací"},
|
||||||
{"Back to commands list", "Zpět na list příkazů"},
|
{"You will be redirected in %d seconds", "Budete přesměrováni za %d sekund"},
|
||||||
|
{"LeaseSet expiration time updated", "Aktualizován čas vypršení platnosti setu pronájmu"},
|
||||||
|
{"LeaseSet is not found or already expired", "Set pronájmu není k nalezení nebo již vypršela jeho platnost"},
|
||||||
|
{"Transit tunnels count must not exceed %d", "Počet tranzitních tunelů nesmí překročit %d"},
|
||||||
|
{"Back to commands list", "Zpět na seznam příkazů"},
|
||||||
{"Register at reg.i2p", "Zaregistrovat na reg.i2p"},
|
{"Register at reg.i2p", "Zaregistrovat na reg.i2p"},
|
||||||
{"Description", "Popis"},
|
{"Description", "Popis"},
|
||||||
{"A bit information about service on domain", "Trochu informací o službě na doméně"},
|
{"A bit information about service on domain", "Trochu informací o službě na doméně"},
|
||||||
{"Submit", "Odeslat"},
|
{"Submit", "Odeslat"},
|
||||||
{"Domain can't end with .b32.i2p", "Doména nesmí končit na .b32.i2p"},
|
{"Domain can't end with .b32.i2p", "Doména nesmí končit na .b32.i2p"},
|
||||||
{"Domain must end with .i2p", "Doména musí končit s .i2p"},
|
{"Domain must end with .i2p", "Doména musí končit s .i2p"},
|
||||||
{"Such destination is not found", "Takováto destinace nebyla nalezena"},
|
|
||||||
{"Unknown command", "Neznámý příkaz"},
|
{"Unknown command", "Neznámý příkaz"},
|
||||||
{"Command accepted", "Příkaz přijat"},
|
{"Command accepted", "Příkaz přijat"},
|
||||||
{"Proxy error", "Chyba proxy serveru"},
|
{"Proxy error", "Chyba proxy serveru"},
|
||||||
@ -162,6 +172,15 @@ namespace czech // language namespace
|
|||||||
{"You may try to find this host on jump services below", "Můžete se pokusit najít tohoto hostitele na startovacích službách níže"},
|
{"You may try to find this host on jump services below", "Můžete se pokusit najít tohoto hostitele na startovacích službách níže"},
|
||||||
{"Invalid request", "Neplatný požadavek"},
|
{"Invalid request", "Neplatný požadavek"},
|
||||||
{"Proxy unable to parse your request", "Proxy server nemohl zpracovat váš požadavek"},
|
{"Proxy unable to parse your request", "Proxy server nemohl zpracovat váš požadavek"},
|
||||||
|
{"Addresshelper is not supported", "Addresshelper není podporován"},
|
||||||
|
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Hostitel %s je <font color=red>již v adresáři routeru</font>. <b>Buďte opatrní: zdroj této URL může být škodlivý!</b> Klikněte zde pro aktualizaci záznamu: <a href=\"%s%s%s&update=true\">Pokračovat</a>."},
|
||||||
|
{"Addresshelper forced update rejected", "Addresshelperem vynucená aktualizace zamítnuta"},
|
||||||
|
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Pro přidání hostitele <b>%s</b> do adresáře routeru, klikněte zde: <a href=\"%s%s%s\">Pokračovat</a>."},
|
||||||
|
{"Addresshelper request", "Požadavek Addresshelperu"},
|
||||||
|
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Hostitel %s přidán do adresáře routeru od pomocníka. Klikněte zde pro pokračování: <a href=\"%s\">Pokračovat</a>."},
|
||||||
|
{"Addresshelper adding", "Addresshelper přidávání"},
|
||||||
|
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Hostitel %s je <font color=red>již v adresáři routeru</font>. Klikněte zde pro aktualizaci záznamu: <a href=\"%s%s%s&update=true\">Pokračovat</a>."},
|
||||||
|
{"Addresshelper update", "Addresshelper aktualizace"},
|
||||||
{"Invalid request URI", "Neplatný URI požadavek"},
|
{"Invalid request URI", "Neplatný URI požadavek"},
|
||||||
{"Can't detect destination host from request", "Nelze zjistit cílového hostitele z požadavku"},
|
{"Can't detect destination host from request", "Nelze zjistit cílového hostitele z požadavku"},
|
||||||
{"Outproxy failure", "Outproxy selhání"},
|
{"Outproxy failure", "Outproxy selhání"},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -58,7 +58,7 @@ namespace french // language namespace
|
|||||||
{"Unknown", "Inconnu"},
|
{"Unknown", "Inconnu"},
|
||||||
{"Proxy", "Proxy"},
|
{"Proxy", "Proxy"},
|
||||||
{"Mesh", "Maillé"},
|
{"Mesh", "Maillé"},
|
||||||
{"Clock skew", "Horloge décalée"},
|
{"Clock skew", "Décalage de l'horloge"},
|
||||||
{"Offline", "Hors ligne"},
|
{"Offline", "Hors ligne"},
|
||||||
{"Symmetric NAT", "NAT symétrique"},
|
{"Symmetric NAT", "NAT symétrique"},
|
||||||
{"Full cone NAT", "NAT à cône complet"},
|
{"Full cone NAT", "NAT à cône complet"},
|
||||||
@ -68,8 +68,8 @@ namespace french // language namespace
|
|||||||
{"Network status v6", "État du réseau v6"},
|
{"Network status v6", "État du réseau v6"},
|
||||||
{"Stopping in", "Arrêt dans"},
|
{"Stopping in", "Arrêt dans"},
|
||||||
{"Family", "Famille"},
|
{"Family", "Famille"},
|
||||||
{"Tunnel creation success rate", "Taux de succès de création de tunnels"},
|
{"Tunnel creation success rate", "Taux de création de tunnel réussie"},
|
||||||
{"Total tunnel creation success rate", "Taux de réussite de création de tunnel"},
|
{"Total tunnel creation success rate", "Taux total de création de tunnel réussie"},
|
||||||
{"Received", "Reçu"},
|
{"Received", "Reçu"},
|
||||||
{"%.2f KiB/s", "%.2f Kio/s"},
|
{"%.2f KiB/s", "%.2f Kio/s"},
|
||||||
{"Sent", "Envoyé"},
|
{"Sent", "Envoyé"},
|
||||||
|
168
i18n/Polish.cpp
168
i18n/Polish.cpp
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, The PurpleI2P Project
|
* Copyright (c) 2023-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -31,22 +31,186 @@ namespace polish // language namespace
|
|||||||
|
|
||||||
static std::map<std::string, std::string> strings
|
static std::map<std::string, std::string> strings
|
||||||
{
|
{
|
||||||
|
{"%.2f KiB", "%.2f KiB"},
|
||||||
|
{"%.2f MiB", "%.2f MiB"},
|
||||||
|
{"%.2f GiB", "%.2f GiB"},
|
||||||
{"building", "Kompilowanie"},
|
{"building", "Kompilowanie"},
|
||||||
{"failed", "nieudane"},
|
{"failed", "nieudane"},
|
||||||
{"expiring", "wygasający"},
|
{"expiring", "wygasający"},
|
||||||
{"established", "ustanowiony"},
|
{"established", "ustanowiony"},
|
||||||
|
{"unknown", "nieznany"},
|
||||||
|
{"exploratory", "eksploracyjny"},
|
||||||
|
{"Purple I2P Webconsole", "Konsola webowa Purple I2P"},
|
||||||
|
{"<b>i2pd</b> webconsole", "<b>i2pd</b> konsola webowa"},
|
||||||
{"Main page", "Strona główna"},
|
{"Main page", "Strona główna"},
|
||||||
{"Router commands", "Komendy routera"},
|
{"Router commands", "Komendy routera"},
|
||||||
|
{"Local Destinations", "Lokalne miejsca docelowe"},
|
||||||
|
{"LeaseSets", "ZestawyNajmu"},
|
||||||
{"Tunnels", "Tunele"},
|
{"Tunnels", "Tunele"},
|
||||||
|
{"Transit Tunnels", "Tunele Tranzytu"},
|
||||||
|
{"Transports", "Transportery"},
|
||||||
|
{"I2P tunnels", "Tunele I2P"},
|
||||||
|
{"SAM sessions", "Sesje SAM"},
|
||||||
|
{"ERROR", "BŁĄD"},
|
||||||
{"OK", "Ok"},
|
{"OK", "Ok"},
|
||||||
|
{"Testing", "Testowanie"},
|
||||||
|
{"Firewalled", "Za zaporą sieciową"},
|
||||||
|
{"Unknown", "Nieznany"},
|
||||||
|
{"Proxy", "Proxy"},
|
||||||
|
{"Mesh", "Sieć"},
|
||||||
|
{"Clock skew", "Przesunięcie czasu"},
|
||||||
|
{"Offline", "Offline"},
|
||||||
|
{"Symmetric NAT", "Symetryczny NAT"},
|
||||||
|
{"Full cone NAT", "Pełny stożek NAT"},
|
||||||
|
{"No Descriptors", "Brak deskryptorów"},
|
||||||
{"Uptime", "Czas pracy"},
|
{"Uptime", "Czas pracy"},
|
||||||
|
{"Network status", "Stan sieci"},
|
||||||
|
{"Network status v6", "Stan sieci v6"},
|
||||||
|
{"Stopping in", "Zatrzymywanie za"},
|
||||||
|
{"Family", "Rodzina"},
|
||||||
|
{"Tunnel creation success rate", "Wskaźnik sukcesu tworzenia tunelu"},
|
||||||
|
{"Total tunnel creation success rate", "Całkowity wskaźnik sukcesu tworzenia tunelu"},
|
||||||
|
{"Received", "Odebrano"},
|
||||||
|
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||||
{"Sent", "Wysłane"},
|
{"Sent", "Wysłane"},
|
||||||
|
{"Transit", "Tranzyt"},
|
||||||
|
{"Data path", "Ścieżka do danych"},
|
||||||
|
{"Hidden content. Press on text to see.", "Ukryta zawartość. Naciśnij tekst, aby zobaczyć."},
|
||||||
|
{"Router Ident", "Identyfikator routera"},
|
||||||
|
{"Router Family", "Rodzina routera"},
|
||||||
|
{"Router Caps", "Możliwości routera"},
|
||||||
|
{"Version", "Wersja"},
|
||||||
|
{"Our external address", "Nasz zewnętrzny adres"},
|
||||||
|
{"supported", "wspierane"},
|
||||||
|
{"Routers", "Routery"},
|
||||||
|
{"Floodfills", "Floodfille"},
|
||||||
|
{"Client Tunnels", "Tunele Klienta"},
|
||||||
|
{"Services", "Usługi"},
|
||||||
|
{"Enabled", "Aktywny"},
|
||||||
|
{"Disabled", "Wyłączony"},
|
||||||
|
{"Encrypted B33 address", "Zaszyfrowany adres B33"},
|
||||||
|
{"Address registration line", "Linia rejestracji adresu"},
|
||||||
|
{"Domain", "Domena"},
|
||||||
|
{"Generate", "Generuj"},
|
||||||
|
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Uwaga:</b> wynik string może być używany tylko do rejestracji domen 2LD (przykład.i2p). Do rejestracji subdomen należy użyć narzędzi i2pd."},
|
||||||
|
{"Address", "Adres"},
|
||||||
|
{"Type", "Typ"},
|
||||||
|
{"EncType", "TypEnkrypcji"},
|
||||||
|
{"Expire LeaseSet", "Wygaśnij LeaseSet"},
|
||||||
|
{"Inbound tunnels", "Tunele przychodzące"},
|
||||||
|
{"%dms", "%dms"},
|
||||||
|
{"Outbound tunnels", "Tunele wychodzące"},
|
||||||
|
{"Tags", "Tagi"},
|
||||||
|
{"Incoming", "Przychodzące"},
|
||||||
|
{"Outgoing", "Wychodzące"},
|
||||||
|
{"Destination", "Miejsce docelowe"},
|
||||||
|
{"Amount", "Ilość"},
|
||||||
|
{"Incoming Tags", "Przychodzące tagi"},
|
||||||
|
{"Tags sessions", "Sesje tagów"},
|
||||||
|
{"Status", "Status"},
|
||||||
|
{"Local Destination", "Lokalne miejsce docelowe"},
|
||||||
|
{"Streams", "Strumienie"},
|
||||||
|
{"Close stream", "Zamknij strumień"},
|
||||||
|
{"Such destination is not found", "Nie znaleziono takiego miejsca docelowego"},
|
||||||
|
{"I2CP session not found", "Sesja I2CP nie została znaleziona"},
|
||||||
|
{"I2CP is not enabled", "I2CP nie jest włączone"},
|
||||||
|
{"Invalid", "Niepoprawny"},
|
||||||
|
{"Store type", "Rodzaj przechowywania"},
|
||||||
|
{"Expires", "Wygasa za"},
|
||||||
|
{"Non Expired Leases", "Leasingi niewygasłe"},
|
||||||
|
{"Gateway", "Brama"},
|
||||||
|
{"TunnelID", "IDTunelu"},
|
||||||
|
{"EndDate", "DataZakończenia"},
|
||||||
|
{"floodfill mode is disabled", "tryb floodfill jest wyłączony"},
|
||||||
|
{"Queue size", "Wielkość kolejki"},
|
||||||
|
{"Run peer test", "Wykonaj test peer"},
|
||||||
|
{"Reload tunnels configuration", "Załaduj ponownie konfigurację tuneli"},
|
||||||
|
{"Decline transit tunnels", "Odrzuć tunele tranzytowe"},
|
||||||
|
{"Accept transit tunnels", "Akceptuj tunele tranzytowe"},
|
||||||
|
{"Cancel graceful shutdown", "Anuluj łagodne wyłączenie"},
|
||||||
|
{"Start graceful shutdown", "Rozpocznij łagodne wyłączenie"},
|
||||||
|
{"Force shutdown", "Wymuś wyłączenie"},
|
||||||
|
{"Reload external CSS styles", "Odśwież zewnętrzne style CSS"},
|
||||||
|
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Uwaga:</b> każda akcja wykonana tutaj nie jest trwała i nie zmienia Twoich plików konfiguracyjnych."},
|
||||||
|
{"Logging level", "Poziom logowania"},
|
||||||
|
{"Transit tunnels limit", "Limit tuneli tranzytowych"},
|
||||||
|
{"Change", "Zmień"},
|
||||||
|
{"Change language", "Zmień język"},
|
||||||
|
{"no transit tunnels currently built", "brak obecnie zbudowanych tuneli tranzytowych"},
|
||||||
|
{"SAM disabled", "SAM wyłączony"},
|
||||||
|
{"no sessions currently running", "brak aktualnie uruchomionych sesji"},
|
||||||
|
{"SAM session not found", "Sesja SAM nie została znaleziona"},
|
||||||
|
{"SAM Session", "Sesja SAM"},
|
||||||
|
{"Server Tunnels", "Tunele Serwera"},
|
||||||
|
{"Client Forwards", "Przekierowania Klienta"},
|
||||||
|
{"Server Forwards", "Przekierowania Serwera"},
|
||||||
|
{"Unknown page", "Nieznana strona"},
|
||||||
|
{"Invalid token", "Nieprawidłowy token"},
|
||||||
|
{"SUCCESS", "SUKCES"},
|
||||||
|
{"Stream closed", "Strumień zamknięty"},
|
||||||
|
{"Stream not found or already was closed", "Strumień nie został znaleziony lub został już zamknięty"},
|
||||||
|
{"Destination not found", "Nie znaleziono punktu docelowego"},
|
||||||
|
{"StreamID can't be null", "StreamID nie może być null"},
|
||||||
|
{"Return to destination page", "Wróć do strony miejsca docelowego"},
|
||||||
|
{"You will be redirected in %d seconds", "Zostaniesz prekierowany za %d sekund"},
|
||||||
|
{"LeaseSet expiration time updated", "Zaktualizowano czas wygaśnięcia LeaseSet"},
|
||||||
|
{"LeaseSet is not found or already expired", "LeaseSet nie został znaleziony lub już wygasł"},
|
||||||
|
{"Transit tunnels count must not exceed %d", "Liczba tuneli tranzytowych nie może przekraczać %d"},
|
||||||
|
{"Back to commands list", "Powrót do listy poleceń"},
|
||||||
|
{"Register at reg.i2p", "Zarejestruj się na reg.i2p"},
|
||||||
|
{"Description", "Opis"},
|
||||||
|
{"A bit information about service on domain", "Trochę informacji o usłudze w domenie"},
|
||||||
|
{"Submit", "Zatwierdź"},
|
||||||
|
{"Domain can't end with .b32.i2p", "Domena nie może kończyć się na .b32.i2p"},
|
||||||
|
{"Domain must end with .i2p", "Domena musi kończyć się na .i2p"},
|
||||||
|
{"Unknown command", "Nieznana komenda"},
|
||||||
|
{"Command accepted", "Polecenie zaakceptowane"},
|
||||||
|
{"Proxy error", "Błąd serwera proxy"},
|
||||||
|
{"Proxy info", "Informacje o proxy"},
|
||||||
|
{"Proxy error: Host not found", "Błąd proxy: Nie znaleziono hosta"},
|
||||||
|
{"Remote host not found in router's addressbook", "Nie znaleziono zdalnego hosta w książce adresowej routera"},
|
||||||
|
{"You may try to find this host on jump services below", "Możesz znaleźć tego hosta na poniższych usługach skoku"},
|
||||||
|
{"Invalid request", "Nieprawidłowe żądanie"},
|
||||||
|
{"Proxy unable to parse your request", "Serwer proxy nie może przetworzyć Twojego żądania"},
|
||||||
|
{"Addresshelper is not supported", "Adresshelper nie jest obsługiwany"},
|
||||||
|
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Host %s <font color=red>jest już w książce adresowej routera</font>. <b>Uważaj: źródło tego adresu URL może być szkodliwe!</b> Kliknij tutaj, aby zaktualizować rekord: <a href=\"%s%s%s&update=true\">Kontynuuj</a>."},
|
||||||
|
{"Addresshelper forced update rejected", "Wymuszona aktualizacja Addreshelper odrzucona"},
|
||||||
|
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Aby dodać host <b>%s</b> w książce adresowej routera, kliknij tutaj: <a href=\"%s%s%s\">Kontynuuj</a>."},
|
||||||
|
{"Addresshelper request", "Prośba Addresshelper"},
|
||||||
|
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Host %s dodany do książki adresowej routera od pomocnika. Kliknij tutaj, aby kontynuować: <a href=\"%s\">Kontynuuj</a>."},
|
||||||
|
{"Addresshelper adding", "Dodawanie Addresshelper"},
|
||||||
|
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Host %s jest <font color=red>już w książce adresowej routera</font>. Kliknij tutaj, aby zaktualizować rekord: <a href=\"%s%s%s&update=true\">Kontynuuj</a>."},
|
||||||
|
{"Addresshelper update", "Aktualizacja Adresshelper"},
|
||||||
|
{"Invalid request URI", "Nieprawidłowe URI żądania"},
|
||||||
|
{"Can't detect destination host from request", "Nie można wykryć hosta docelowego z żądania"},
|
||||||
|
{"Outproxy failure", "Błąd proxy wyjściowego"},
|
||||||
|
{"Bad outproxy settings", "Błędne ustawienia proxy wyjściowych"},
|
||||||
|
{"Host %s is not inside I2P network, but outproxy is not enabled", "Host %s nie jest wewnątrz sieci I2P, a proxy wyjściowe nie jest włączone"},
|
||||||
|
{"Unknown outproxy URL", "Nieznany adres URL proxy wyjściowego"},
|
||||||
|
{"Cannot resolve upstream proxy", "Nie można rozwiązać serwera proxy upstream"},
|
||||||
|
{"Hostname is too long", "Nazwa hosta jest zbyt długa"},
|
||||||
|
{"Cannot connect to upstream SOCKS proxy", "Nie można połączyć się z proxy SOCKS upstream"},
|
||||||
|
{"Cannot negotiate with SOCKS proxy", "Nie można negocjować z proxy SOCKS"},
|
||||||
|
{"CONNECT error", "Błąd POŁĄCZENIE"},
|
||||||
|
{"Failed to connect", "Nie udało się połączyć"},
|
||||||
|
{"SOCKS proxy error", "Błąd proxy SOCKS"},
|
||||||
|
{"Failed to send request to upstream", "Nie udało się wysłać żądania do upstream"},
|
||||||
|
{"No reply from SOCKS proxy", "Brak odpowiedzi od serwera proxy SOCKS"},
|
||||||
|
{"Cannot connect", "Nie można się połączyć"},
|
||||||
|
{"HTTP out proxy not implemented", "Serwer wyjściowy proxy HTTP nie został zaimplementowany"},
|
||||||
|
{"Cannot connect to upstream HTTP proxy", "Nie można połączyć się z proxy HTTP upstream"},
|
||||||
|
{"Host is down", "Host jest niedostępny"},
|
||||||
|
{"Can't create connection to requested host, it may be down. Please try again later.", "Nie można utworzyć połączenia z żądanym hostem, może być wyłączony. Spróbuj ponownie później."},
|
||||||
{"", ""},
|
{"", ""},
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::map<std::string, std::vector<std::string>> plurals
|
static std::map<std::string, std::vector<std::string>> plurals
|
||||||
{
|
{
|
||||||
{"", {"", "", ""}},
|
{"%d days", {"%d dzień", "%d dni", "%d dni", "%d dni"}},
|
||||||
|
{"%d hours", {"%d godzina", "%d godziny", "%d godzin", "%d godzin"}},
|
||||||
|
{"%d minutes", {"%d minuta", "%d minuty", "%d minut", "%d minut"}},
|
||||||
|
{"%d seconds", {"%d sekunda", "%d sekundy", "%d sekund", "%d sekund"}},
|
||||||
|
{"", {"", "", "", ""}},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, The PurpleI2P Project
|
* Copyright (c) 2023-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -58,7 +58,7 @@ namespace portuguese // language namespace
|
|||||||
{"Unknown", "Desconhecido"},
|
{"Unknown", "Desconhecido"},
|
||||||
{"Proxy", "Proxy"},
|
{"Proxy", "Proxy"},
|
||||||
{"Mesh", "Malha"},
|
{"Mesh", "Malha"},
|
||||||
{"Clock skew", "Defasagem do Relógio"},
|
{"Clock skew", "Desvio de Relógio"},
|
||||||
{"Offline", "Desligado"},
|
{"Offline", "Desligado"},
|
||||||
{"Symmetric NAT", "NAT Simétrico"},
|
{"Symmetric NAT", "NAT Simétrico"},
|
||||||
{"Full cone NAT", "Full cone NAT"},
|
{"Full cone NAT", "Full cone NAT"},
|
||||||
@ -74,7 +74,7 @@ namespace portuguese // language namespace
|
|||||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||||
{"Sent", "Enviado"},
|
{"Sent", "Enviado"},
|
||||||
{"Transit", "Trânsito"},
|
{"Transit", "Trânsito"},
|
||||||
{"Data path", "Diretório dos dados"},
|
{"Data path", "Diretório de dados"},
|
||||||
{"Hidden content. Press on text to see.", "Conteúdo oculto. Clique no texto para revelar."},
|
{"Hidden content. Press on text to see.", "Conteúdo oculto. Clique no texto para revelar."},
|
||||||
{"Router Ident", "Identidade do Roteador"},
|
{"Router Ident", "Identidade do Roteador"},
|
||||||
{"Router Family", "Família do Roteador"},
|
{"Router Family", "Família do Roteador"},
|
||||||
@ -106,9 +106,9 @@ namespace portuguese // language namespace
|
|||||||
{"Destination", "Destinos"},
|
{"Destination", "Destinos"},
|
||||||
{"Amount", "Quantidade"},
|
{"Amount", "Quantidade"},
|
||||||
{"Incoming Tags", "Etiquetas de Entrada"},
|
{"Incoming Tags", "Etiquetas de Entrada"},
|
||||||
{"Tags sessions", "Sessões de etiquetas"},
|
{"Tags sessions", "Sessões de Etiquetas"},
|
||||||
{"Status", "Estado"},
|
{"Status", "Estado"},
|
||||||
{"Local Destination", "Destinos Locais"},
|
{"Local Destination", "Destino Local"},
|
||||||
{"Streams", "Fluxos"},
|
{"Streams", "Fluxos"},
|
||||||
{"Close stream", "Fechar fluxo"},
|
{"Close stream", "Fechar fluxo"},
|
||||||
{"Such destination is not found", "Tal destino não foi encontrado"},
|
{"Such destination is not found", "Tal destino não foi encontrado"},
|
||||||
@ -148,7 +148,7 @@ namespace portuguese // language namespace
|
|||||||
{"Invalid token", "Token Inválido"},
|
{"Invalid token", "Token Inválido"},
|
||||||
{"SUCCESS", "SUCESSO"},
|
{"SUCCESS", "SUCESSO"},
|
||||||
{"Stream closed", "Fluxo fechado"},
|
{"Stream closed", "Fluxo fechado"},
|
||||||
{"Stream not found or already was closed", "Fluxo não encontrado ou já encerrado"},
|
{"Stream not found or already was closed", "Fluxo não encontrado ou já fechado"},
|
||||||
{"Destination not found", "Destino não encontrado"},
|
{"Destination not found", "Destino não encontrado"},
|
||||||
{"StreamID can't be null", "StreamID não pode ser nulo"},
|
{"StreamID can't be null", "StreamID não pode ser nulo"},
|
||||||
{"Return to destination page", "Retornar para à página de destino"},
|
{"Return to destination page", "Retornar para à página de destino"},
|
||||||
@ -157,7 +157,7 @@ namespace portuguese // language namespace
|
|||||||
{"LeaseSet is not found or already expired", "LeaseSet não foi encontrado ou já expirou"},
|
{"LeaseSet is not found or already expired", "LeaseSet não foi encontrado ou já expirou"},
|
||||||
{"Transit tunnels count must not exceed %d", "A contagem de túneis de trânsito não deve exceder %d"},
|
{"Transit tunnels count must not exceed %d", "A contagem de túneis de trânsito não deve exceder %d"},
|
||||||
{"Back to commands list", "Voltar para a lista de comandos"},
|
{"Back to commands list", "Voltar para a lista de comandos"},
|
||||||
{"Register at reg.i2p", "Registrar na reg.i2p"},
|
{"Register at reg.i2p", "Registrar em reg.i2p"},
|
||||||
{"Description", "Descrição"},
|
{"Description", "Descrição"},
|
||||||
{"A bit information about service on domain", "Algumas informações sobre o serviço no domínio"},
|
{"A bit information about service on domain", "Algumas informações sobre o serviço no domínio"},
|
||||||
{"Submit", "Enviar"},
|
{"Submit", "Enviar"},
|
||||||
@ -169,22 +169,22 @@ namespace portuguese // language namespace
|
|||||||
{"Proxy info", "Informações do proxy"},
|
{"Proxy info", "Informações do proxy"},
|
||||||
{"Proxy error: Host not found", "Erro no proxy: Host não encontrado"},
|
{"Proxy error: Host not found", "Erro no proxy: Host não encontrado"},
|
||||||
{"Remote host not found in router's addressbook", "O host remoto não foi encontrado no livro de endereços do roteador"},
|
{"Remote host not found in router's addressbook", "O host remoto não foi encontrado no livro de endereços do roteador"},
|
||||||
{"You may try to find this host on jump services below", "Você pode tentar encontrar este host nos jump services abaixo"},
|
{"You may try to find this host on jump services below", "Você pode tentar encontrar este host nos serviços de jump abaixo"},
|
||||||
{"Invalid request", "Requisição inválida"},
|
{"Invalid request", "Requisição inválida"},
|
||||||
{"Proxy unable to parse your request", "O proxy foi incapaz de processar a sua requisição"},
|
{"Proxy unable to parse your request", "O proxy foi incapaz de processar a sua requisição"},
|
||||||
{"Addresshelper is not supported", "O Auxiliar de Endereços não é suportado"},
|
{"Addresshelper is not supported", "O Auxiliar de Endereços não é suportado"},
|
||||||
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "O host %s já <font color=red>está no catálogo de endereços do roteador</font>. <b>Cuidado: a fonte desta URL pode ser perigosa!</b> Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
|
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "O host %s já <font color=red>está no catálogo de endereços do roteador</font>. <b>Cuidado: a fonte desta URL pode ser perigosa!</b> Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
|
||||||
{"Addresshelper forced update rejected", "A atualização forçada do Auxiliar de Endereços foi rejeitada"},
|
{"Addresshelper forced update rejected", "A atualização forçada do Auxiliar de Endereços foi rejeitada"},
|
||||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Para adicionar o host <b> %s </b> ao catálogo de endereços do roteador, clique aqui: <a href='%s%s%s'>Continuar </a>."},
|
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Para adicionar o host <b> %s </b> ao catálogo de endereços do roteador, clique aqui: <a href='%s%s%s'>Continuar </a>."},
|
||||||
{"Addresshelper request", "Requisição do Auxiliar de Endereços"},
|
{"Addresshelper request", "Requisição ao Auxiliar de Endereços"},
|
||||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "O host %s foi adicionado ao catálogo de endereços do roteador por um auxiliar. Clique aqui para proceder: <a href='%s'> Continuar </a>."},
|
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "O host %s foi adicionado ao catálogo de endereços do roteador por um auxiliar. Clique aqui para prosseguir: <a href='%s'> Continuar </a>."},
|
||||||
{"Addresshelper adding", "Auxiliar de Endereço adicionando"},
|
{"Addresshelper adding", "Auxiliar de Endereço adicionando"},
|
||||||
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "O host %s já <font color=red>está no catálogo de endereços do roteador </font>. Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
|
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "O host %s já <font color=red>está no catálogo de endereços do roteador </font>. Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
|
||||||
{"Addresshelper update", "Atualização do Auxiliar de Endereços"},
|
{"Addresshelper update", "Atualização do Auxiliar de Endereços"},
|
||||||
{"Invalid request URI", "A URI de requisição é inválida"},
|
{"Invalid request URI", "A URI de requisição é inválida"},
|
||||||
{"Can't detect destination host from request", "Incapaz de detectar o host de destino da requisição"},
|
{"Can't detect destination host from request", "Incapaz de detectar o host de destino da requisição"},
|
||||||
{"Outproxy failure", "Falha no outproxy"},
|
{"Outproxy failure", "Falha no outproxy"},
|
||||||
{"Bad outproxy settings", "Configurações ruins de outproxy"},
|
{"Bad outproxy settings", "Má configurações do outproxy"},
|
||||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "O host %s não está dentro da rede I2P, mas o outproxy não está ativado"},
|
{"Host %s is not inside I2P network, but outproxy is not enabled", "O host %s não está dentro da rede I2P, mas o outproxy não está ativado"},
|
||||||
{"Unknown outproxy URL", "URL de outproxy desconhecida"},
|
{"Unknown outproxy URL", "URL de outproxy desconhecida"},
|
||||||
{"Cannot resolve upstream proxy", "Não é possível resolver o proxy de entrada"},
|
{"Cannot resolve upstream proxy", "Não é possível resolver o proxy de entrada"},
|
||||||
|
@ -1,137 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
|
||||||
*
|
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
|
||||||
*
|
|
||||||
* See full license text in LICENSE file at top of project tree
|
|
||||||
*
|
|
||||||
* Kovri go write your own code
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "I2PEndian.h"
|
|
||||||
#include "ChaCha20.h"
|
|
||||||
|
|
||||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace crypto
|
|
||||||
{
|
|
||||||
namespace chacha
|
|
||||||
{
|
|
||||||
void u32t8le(uint32_t v, uint8_t * p)
|
|
||||||
{
|
|
||||||
p[0] = v & 0xff;
|
|
||||||
p[1] = (v >> 8) & 0xff;
|
|
||||||
p[2] = (v >> 16) & 0xff;
|
|
||||||
p[3] = (v >> 24) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t u8t32le(const uint8_t * p)
|
|
||||||
{
|
|
||||||
uint32_t value = p[3];
|
|
||||||
|
|
||||||
value = (value << 8) | p[2];
|
|
||||||
value = (value << 8) | p[1];
|
|
||||||
value = (value << 8) | p[0];
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t rotl32(uint32_t x, int n)
|
|
||||||
{
|
|
||||||
return x << n | (x >> (-n & 31));
|
|
||||||
}
|
|
||||||
|
|
||||||
void quarterround(uint32_t *x, int a, int b, int c, int d)
|
|
||||||
{
|
|
||||||
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16);
|
|
||||||
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12);
|
|
||||||
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8);
|
|
||||||
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Chacha20Block::operator << (const Chacha20State & st)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 16; i++)
|
|
||||||
u32t8le(st.data[i], data + (i << 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void block (Chacha20State &input, int rounds)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Chacha20State x;
|
|
||||||
x.Copy(input);
|
|
||||||
|
|
||||||
for (i = rounds; i > 0; i -= 2)
|
|
||||||
{
|
|
||||||
quarterround(x.data, 0, 4, 8, 12);
|
|
||||||
quarterround(x.data, 1, 5, 9, 13);
|
|
||||||
quarterround(x.data, 2, 6, 10, 14);
|
|
||||||
quarterround(x.data, 3, 7, 11, 15);
|
|
||||||
quarterround(x.data, 0, 5, 10, 15);
|
|
||||||
quarterround(x.data, 1, 6, 11, 12);
|
|
||||||
quarterround(x.data, 2, 7, 8, 13);
|
|
||||||
quarterround(x.data, 3, 4, 9, 14);
|
|
||||||
}
|
|
||||||
x += input;
|
|
||||||
input.block << x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter)
|
|
||||||
{
|
|
||||||
state.data[0] = 0x61707865;
|
|
||||||
state.data[1] = 0x3320646e;
|
|
||||||
state.data[2] = 0x79622d32;
|
|
||||||
state.data[3] = 0x6b206574;
|
|
||||||
for (size_t i = 0; i < 8; i++)
|
|
||||||
state.data[4 + i] = chacha::u8t32le(key + i * 4);
|
|
||||||
|
|
||||||
state.data[12] = htole32 (counter);
|
|
||||||
for (size_t i = 0; i < 3; i++)
|
|
||||||
state.data[13 + i] = chacha::u8t32le(nonce + i * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Chacha20SetCounter (Chacha20State& state, uint32_t counter)
|
|
||||||
{
|
|
||||||
state.data[12] = htole32 (counter);
|
|
||||||
state.offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
|
|
||||||
{
|
|
||||||
if (state.offset > 0)
|
|
||||||
{
|
|
||||||
// previous block if any
|
|
||||||
auto s = chacha::blocksize - state.offset;
|
|
||||||
if (sz < s) s = sz;
|
|
||||||
for (size_t i = 0; i < s; i++)
|
|
||||||
buf[i] ^= state.block.data[state.offset + i];
|
|
||||||
buf += s;
|
|
||||||
sz -= s;
|
|
||||||
state.offset += s;
|
|
||||||
if (state.offset >= chacha::blocksize) state.offset = 0;
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < sz; i += chacha::blocksize)
|
|
||||||
{
|
|
||||||
chacha::block(state, chacha::rounds);
|
|
||||||
state.data[12]++;
|
|
||||||
for (size_t j = i; j < i + chacha::blocksize; j++)
|
|
||||||
{
|
|
||||||
if (j >= sz)
|
|
||||||
{
|
|
||||||
state.offset = j & 0x3F; // % 64
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf[j] ^= state.block.data[j - i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace chacha
|
|
||||||
} // namespace crypto
|
|
||||||
} // namespace i2p
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
|
||||||
*
|
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
|
||||||
*
|
|
||||||
* See full license text in LICENSE file at top of project tree
|
|
||||||
*
|
|
||||||
* Kovri go write your own code
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef LIBI2PD_CHACHA20_H
|
|
||||||
#define LIBI2PD_CHACHA20_H
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "Crypto.h"
|
|
||||||
|
|
||||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace crypto
|
|
||||||
{
|
|
||||||
const std::size_t CHACHA20_KEY_BYTES = 32;
|
|
||||||
const std::size_t CHACHA20_NOUNCE_BYTES = 12;
|
|
||||||
|
|
||||||
namespace chacha
|
|
||||||
{
|
|
||||||
constexpr std::size_t blocksize = 64;
|
|
||||||
constexpr int rounds = 20;
|
|
||||||
|
|
||||||
struct Chacha20State;
|
|
||||||
struct Chacha20Block
|
|
||||||
{
|
|
||||||
Chacha20Block () {};
|
|
||||||
Chacha20Block (Chacha20Block &&) = delete;
|
|
||||||
|
|
||||||
uint8_t data[blocksize];
|
|
||||||
|
|
||||||
void operator << (const Chacha20State & st);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Chacha20State
|
|
||||||
{
|
|
||||||
Chacha20State (): offset (0) {};
|
|
||||||
Chacha20State (Chacha20State &&) = delete;
|
|
||||||
|
|
||||||
Chacha20State & operator += (const Chacha20State & other)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < 16; i++)
|
|
||||||
data[i] += other.data[i];
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Copy(const Chacha20State & other)
|
|
||||||
{
|
|
||||||
memcpy(data, other.data, sizeof(uint32_t) * 16);
|
|
||||||
}
|
|
||||||
uint32_t data[16];
|
|
||||||
Chacha20Block block;
|
|
||||||
size_t offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter);
|
|
||||||
void Chacha20SetCounter (Chacha20State& state, uint32_t counter);
|
|
||||||
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz); // encrypt buf in place
|
|
||||||
} // namespace chacha
|
|
||||||
} // namespace crypto
|
|
||||||
} // namespace i2p
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
@ -168,6 +168,8 @@ namespace config {
|
|||||||
("i2cp.address", value<std::string>()->default_value("127.0.0.1"), "I2CP listen address")
|
("i2cp.address", value<std::string>()->default_value("127.0.0.1"), "I2CP listen address")
|
||||||
("i2cp.port", value<uint16_t>()->default_value(7654), "I2CP listen port")
|
("i2cp.port", value<uint16_t>()->default_value(7654), "I2CP listen port")
|
||||||
("i2cp.singlethread", value<bool>()->default_value(true), "Destinations run in the I2CP server's thread")
|
("i2cp.singlethread", value<bool>()->default_value(true), "Destinations run in the I2CP server's thread")
|
||||||
|
("i2cp.inboundlimit", value<uint32_t>()->default_value(0), "Client inbound limit in KBps to return in BandwidthLimitsMessage. Router's bandwidth by default")
|
||||||
|
("i2cp.outboundlimit", value<uint32_t>()->default_value(0), "Client outbound limit in KBps to return in BandwidthLimitsMessage. Router's bandwidth by default")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description i2pcontrol("I2PControl options");
|
options_description i2pcontrol("I2PControl options");
|
||||||
@ -205,7 +207,7 @@ namespace config {
|
|||||||
reseed.add_options()
|
reseed.add_options()
|
||||||
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature")
|
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature")
|
||||||
("reseed.threshold", value<uint16_t>()->default_value(25), "Minimum number of known routers before requesting reseed")
|
("reseed.threshold", value<uint16_t>()->default_value(25), "Minimum number of known routers before requesting reseed")
|
||||||
("reseed.floodfill", value<std::string>()->default_value(""), "Path to router info of floodfill to reseed from")
|
("reseed.floodfill", value<std::string>()->default_value(""), "Ignored. Always empty")
|
||||||
("reseed.file", value<std::string>()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from")
|
("reseed.file", value<std::string>()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from")
|
||||||
("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from")
|
("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from")
|
||||||
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks")
|
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks")
|
||||||
@ -229,8 +231,7 @@ namespace config {
|
|||||||
"http://[301:65b9:c7cd:9a36::1]:18801/,"
|
"http://[301:65b9:c7cd:9a36::1]:18801/,"
|
||||||
"http://[320:8936:ec1a:31f1::216]/,"
|
"http://[320:8936:ec1a:31f1::216]/,"
|
||||||
"http://[306:3834:97b9:a00a::1]/,"
|
"http://[306:3834:97b9:a00a::1]/,"
|
||||||
"http://[316:f9e0:f22e:a74f::216]/,"
|
"http://[316:f9e0:f22e:a74f::216]/"
|
||||||
"http://[300:eaff:7fab:181b::e621]:7170"
|
|
||||||
), "Reseed URLs through the Yggdrasil, separated by comma")
|
), "Reseed URLs through the Yggdrasil, separated by comma")
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -19,16 +19,11 @@
|
|||||||
#if OPENSSL_HKDF
|
#if OPENSSL_HKDF
|
||||||
#include <openssl/kdf.h>
|
#include <openssl/kdf.h>
|
||||||
#endif
|
#endif
|
||||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
|
||||||
#include "ChaCha20.h"
|
|
||||||
#include "Poly1305.h"
|
|
||||||
#endif
|
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "Ed25519.h"
|
#include "Ed25519.h"
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace crypto
|
namespace crypto
|
||||||
@ -988,7 +983,6 @@ namespace crypto
|
|||||||
if (len < msgLen) return false;
|
if (len < msgLen) return false;
|
||||||
if (encrypt && len < msgLen + 16) return false;
|
if (encrypt && len < msgLen + 16) return false;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
#if OPENSSL_AEAD_CHACHA20_POLY1305
|
|
||||||
int outlen = 0;
|
int outlen = 0;
|
||||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
||||||
if (encrypt)
|
if (encrypt)
|
||||||
@ -1003,6 +997,15 @@ namespace crypto
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||||
|
std::vector<uint8_t> m(msgLen + 16);
|
||||||
|
if (msg == buf)
|
||||||
|
{
|
||||||
|
// we have to use different buffers otherwise verification fails
|
||||||
|
memcpy (m.data (), msg, msgLen + 16);
|
||||||
|
msg = m.data ();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0);
|
EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0);
|
||||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0);
|
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0);
|
||||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, (uint8_t *)(msg + msgLen));
|
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, (uint8_t *)(msg + msgLen));
|
||||||
@ -1013,73 +1016,12 @@ namespace crypto
|
|||||||
}
|
}
|
||||||
|
|
||||||
EVP_CIPHER_CTX_free (ctx);
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
#else
|
|
||||||
chacha::Chacha20State state;
|
|
||||||
// generate one time poly key
|
|
||||||
chacha::Chacha20Init (state, nonce, key, 0);
|
|
||||||
uint64_t polyKey[8];
|
|
||||||
memset(polyKey, 0, sizeof(polyKey));
|
|
||||||
chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64);
|
|
||||||
// create Poly1305 hash
|
|
||||||
Poly1305 polyHash (polyKey);
|
|
||||||
if (!ad) adLen = 0;
|
|
||||||
uint8_t padding[16]; memset (padding, 0, 16);
|
|
||||||
if (ad)
|
|
||||||
{
|
|
||||||
polyHash.Update (ad, adLen);// additional authenticated data
|
|
||||||
auto rem = adLen & 0x0F; // %16
|
|
||||||
if (rem)
|
|
||||||
{
|
|
||||||
// padding1
|
|
||||||
rem = 16 - rem;
|
|
||||||
polyHash.Update (padding, rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// encrypt/decrypt data and add to hash
|
|
||||||
Chacha20SetCounter (state, 1);
|
|
||||||
if (buf != msg)
|
|
||||||
memcpy (buf, msg, msgLen);
|
|
||||||
if (encrypt)
|
|
||||||
{
|
|
||||||
chacha::Chacha20Encrypt (state, buf, msgLen); // encrypt
|
|
||||||
polyHash.Update (buf, msgLen); // after encryption
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
polyHash.Update (buf, msgLen); // before decryption
|
|
||||||
chacha::Chacha20Encrypt (state, buf, msgLen); // decrypt
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rem = msgLen & 0x0F; // %16
|
|
||||||
if (rem)
|
|
||||||
{
|
|
||||||
// padding2
|
|
||||||
rem = 16 - rem;
|
|
||||||
polyHash.Update (padding, rem);
|
|
||||||
}
|
|
||||||
// adLen and msgLen
|
|
||||||
htole64buf (padding, adLen);
|
|
||||||
htole64buf (padding + 8, msgLen);
|
|
||||||
polyHash.Update (padding, 16);
|
|
||||||
|
|
||||||
if (encrypt)
|
|
||||||
// calculate Poly1305 tag and write in after encrypted data
|
|
||||||
polyHash.Finish ((uint64_t *)(buf + msgLen));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint64_t tag[4];
|
|
||||||
// calculate Poly1305 tag
|
|
||||||
polyHash.Finish (tag);
|
|
||||||
if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac)
|
void AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac)
|
||||||
{
|
{
|
||||||
if (bufs.empty ()) return;
|
if (bufs.empty ()) return;
|
||||||
#if OPENSSL_AEAD_CHACHA20_POLY1305
|
|
||||||
int outlen = 0;
|
int outlen = 0;
|
||||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
||||||
EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0);
|
EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0);
|
||||||
@ -1090,45 +1032,10 @@ namespace crypto
|
|||||||
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
|
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
|
||||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac);
|
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac);
|
||||||
EVP_CIPHER_CTX_free (ctx);
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
#else
|
|
||||||
chacha::Chacha20State state;
|
|
||||||
// generate one time poly key
|
|
||||||
chacha::Chacha20Init (state, nonce, key, 0);
|
|
||||||
uint64_t polyKey[8];
|
|
||||||
memset(polyKey, 0, sizeof(polyKey));
|
|
||||||
chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64);
|
|
||||||
Poly1305 polyHash (polyKey);
|
|
||||||
// encrypt buffers
|
|
||||||
Chacha20SetCounter (state, 1);
|
|
||||||
size_t size = 0;
|
|
||||||
for (const auto& it: bufs)
|
|
||||||
{
|
|
||||||
chacha::Chacha20Encrypt (state, it.first, it.second);
|
|
||||||
polyHash.Update (it.first, it.second); // after encryption
|
|
||||||
size += it.second;
|
|
||||||
}
|
|
||||||
// padding
|
|
||||||
uint8_t padding[16];
|
|
||||||
memset (padding, 0, 16);
|
|
||||||
auto rem = size & 0x0F; // %16
|
|
||||||
if (rem)
|
|
||||||
{
|
|
||||||
// padding2
|
|
||||||
rem = 16 - rem;
|
|
||||||
polyHash.Update (padding, rem);
|
|
||||||
}
|
|
||||||
// adLen and msgLen
|
|
||||||
// adLen is always zero
|
|
||||||
htole64buf (padding + 8, size);
|
|
||||||
polyHash.Update (padding, 16);
|
|
||||||
// MAC
|
|
||||||
polyHash.Finish ((uint64_t *)mac);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
|
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
|
||||||
{
|
{
|
||||||
#if OPENSSL_AEAD_CHACHA20_POLY1305
|
|
||||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
||||||
uint32_t iv[4];
|
uint32_t iv[4];
|
||||||
iv[0] = htole32 (1); memcpy (iv + 1, nonce, 12); // counter | nonce
|
iv[0] = htole32 (1); memcpy (iv + 1, nonce, 12); // counter | nonce
|
||||||
@ -1137,12 +1044,6 @@ namespace crypto
|
|||||||
EVP_EncryptUpdate(ctx, out, &outlen, msg, msgLen);
|
EVP_EncryptUpdate(ctx, out, &outlen, msg, msgLen);
|
||||||
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
|
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
|
||||||
EVP_CIPHER_CTX_free (ctx);
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
#else
|
|
||||||
chacha::Chacha20State state;
|
|
||||||
chacha::Chacha20Init (state, nonce, key, 1);
|
|
||||||
if (out != msg) memcpy (out, msg, msgLen);
|
|
||||||
chacha::Chacha20Encrypt (state, out, msgLen);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info,
|
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info,
|
||||||
@ -1295,9 +1196,6 @@ namespace crypto
|
|||||||
void InitCrypto (bool precomputation, bool aesni, bool force)
|
void InitCrypto (bool precomputation, bool aesni, bool force)
|
||||||
{
|
{
|
||||||
i2p::cpu::Detect (aesni, force);
|
i2p::cpu::Detect (aesni, force);
|
||||||
#if LEGACY_OPENSSL
|
|
||||||
SSL_library_init ();
|
|
||||||
#endif
|
|
||||||
/* auto numLocks = CRYPTO_num_locks();
|
/* auto numLocks = CRYPTO_num_locks();
|
||||||
for (int i = 0; i < numLocks; i++)
|
for (int i = 0; i < numLocks; i++)
|
||||||
m_OpenSSLMutexes.emplace_back (new std::mutex);
|
m_OpenSSLMutexes.emplace_back (new std::mutex);
|
||||||
|
102
libi2pd/Crypto.h
102
libi2pd/Crypto.h
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -21,7 +21,6 @@
|
|||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/engine.h>
|
|
||||||
#include <openssl/opensslv.h>
|
#include <openssl/opensslv.h>
|
||||||
|
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
@ -29,24 +28,12 @@
|
|||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
|
|
||||||
// recognize openssl version and features
|
// recognize openssl version and features
|
||||||
#if (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x3050200fL)) // LibreSSL 3.5.2 and above
|
#if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
||||||
# define LEGACY_OPENSSL 0
|
# define OPENSSL_HKDF 1
|
||||||
#elif ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL
|
# define OPENSSL_EDDSA 1
|
||||||
# define LEGACY_OPENSSL 1
|
# define OPENSSL_X25519 1
|
||||||
# define X509_getm_notBefore X509_get_notBefore
|
# if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL
|
||||||
# define X509_getm_notAfter X509_get_notAfter
|
# define OPENSSL_SIPHASH 1
|
||||||
#else
|
|
||||||
# define LEGACY_OPENSSL 0
|
|
||||||
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
|
||||||
# define OPENSSL_HKDF 1
|
|
||||||
# define OPENSSL_EDDSA 1
|
|
||||||
# define OPENSSL_X25519 1
|
|
||||||
# if (OPENSSL_VERSION_NUMBER != 0x030000000) // 3.0.0, regression in SipHash
|
|
||||||
# define OPENSSL_SIPHASH 1
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
# if !defined OPENSSL_NO_CHACHA && !defined OPENSSL_NO_POLY1305 // some builds might not include them
|
|
||||||
# define OPENSSL_AEAD_CHACHA20_POLY1305 1
|
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -312,79 +299,4 @@ namespace crypto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// take care about openssl below 1.1.0
|
|
||||||
#if LEGACY_OPENSSL
|
|
||||||
// define getters and setters introduced in 1.1.0
|
|
||||||
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
|
||||||
{
|
|
||||||
if (d->p) BN_free (d->p);
|
|
||||||
if (d->q) BN_free (d->q);
|
|
||||||
if (d->g) BN_free (d->g);
|
|
||||||
d->p = p; d->q = q; d->g = g; return 1;
|
|
||||||
}
|
|
||||||
inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
|
|
||||||
{
|
|
||||||
if (d->pub_key) BN_free (d->pub_key);
|
|
||||||
if (d->priv_key) BN_free (d->priv_key);
|
|
||||||
d->pub_key = pub_key; d->priv_key = priv_key; return 1;
|
|
||||||
}
|
|
||||||
inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
|
|
||||||
{ *pub_key = d->pub_key; *priv_key = d->priv_key; }
|
|
||||||
inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
|
||||||
{
|
|
||||||
if (sig->r) BN_free (sig->r);
|
|
||||||
if (sig->s) BN_free (sig->s);
|
|
||||||
sig->r = r; sig->s = s; return 1;
|
|
||||||
}
|
|
||||||
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
|
||||||
{ *pr = sig->r; *ps = sig->s; }
|
|
||||||
|
|
||||||
inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
|
||||||
{
|
|
||||||
if (sig->r) BN_free (sig->r);
|
|
||||||
if (sig->s) BN_free (sig->s);
|
|
||||||
sig->r = r; sig->s = s; return 1;
|
|
||||||
}
|
|
||||||
inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
|
||||||
{ *pr = sig->r; *ps = sig->s; }
|
|
||||||
|
|
||||||
inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
|
|
||||||
{
|
|
||||||
if (r->n) BN_free (r->n);
|
|
||||||
if (r->e) BN_free (r->e);
|
|
||||||
if (r->d) BN_free (r->d);
|
|
||||||
r->n = n; r->e = e; r->d = d; return 1;
|
|
||||||
}
|
|
||||||
inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
|
|
||||||
{ *n = r->n; *e = r->e; *d = r->d; }
|
|
||||||
|
|
||||||
inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
|
||||||
{
|
|
||||||
if (dh->p) BN_free (dh->p);
|
|
||||||
if (dh->q) BN_free (dh->q);
|
|
||||||
if (dh->g) BN_free (dh->g);
|
|
||||||
dh->p = p; dh->q = q; dh->g = g; return 1;
|
|
||||||
}
|
|
||||||
inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
|
|
||||||
{
|
|
||||||
if (dh->pub_key) BN_free (dh->pub_key);
|
|
||||||
if (dh->priv_key) BN_free (dh->priv_key);
|
|
||||||
dh->pub_key = pub_key; dh->priv_key = priv_key; return 1;
|
|
||||||
}
|
|
||||||
inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
|
|
||||||
{ *pub_key = dh->pub_key; *priv_key = dh->priv_key; }
|
|
||||||
|
|
||||||
inline RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
|
|
||||||
{ return pkey->pkey.rsa; }
|
|
||||||
|
|
||||||
inline EVP_MD_CTX *EVP_MD_CTX_new ()
|
|
||||||
{ return EVP_MD_CTX_create(); }
|
|
||||||
inline void EVP_MD_CTX_free (EVP_MD_CTX *ctx)
|
|
||||||
{ EVP_MD_CTX_destroy (ctx); }
|
|
||||||
|
|
||||||
// ssl
|
|
||||||
#define TLS_method TLSv1_method
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -288,8 +288,8 @@ namespace datagram
|
|||||||
|
|
||||||
DatagramSession::DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
DatagramSession::DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
||||||
const i2p::data::IdentHash & remoteIdent) :
|
const i2p::data::IdentHash & remoteIdent) :
|
||||||
m_LocalDestination(localDestination),
|
m_LocalDestination(localDestination), m_RemoteIdent(remoteIdent),
|
||||||
m_RemoteIdent(remoteIdent),
|
m_LastUse (0), m_LastFlush (0),
|
||||||
m_RequestingLS(false)
|
m_RequestingLS(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -310,8 +310,12 @@ namespace datagram
|
|||||||
if (msg || m_SendQueue.empty ())
|
if (msg || m_SendQueue.empty ())
|
||||||
m_SendQueue.push_back(msg);
|
m_SendQueue.push_back(msg);
|
||||||
// flush queue right away if full
|
// flush queue right away if full
|
||||||
if (!msg || m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE)
|
if (!msg || m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE ||
|
||||||
|
m_LastUse > m_LastFlush + DATAGRAM_MAX_FLUSH_INTERVAL)
|
||||||
|
{
|
||||||
FlushSendQueue();
|
FlushSendQueue();
|
||||||
|
m_LastFlush = m_LastUse;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
||||||
@ -344,7 +348,7 @@ namespace datagram
|
|||||||
if(path)
|
if(path)
|
||||||
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
|
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
if (IsRatchets ())
|
if (IsRatchets ())
|
||||||
SendMsg (nullptr); // send empty message in case if we have some data to send
|
SendMsg (nullptr); // send empty message in case if we don't have some data to send
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath ()
|
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath ()
|
||||||
@ -383,8 +387,8 @@ namespace datagram
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto path = m_RoutingSession->GetSharedRoutingPath();
|
auto path = m_RoutingSession->GetSharedRoutingPath();
|
||||||
if (path && m_RoutingSession->IsRatchets () &&
|
if (path && m_RoutingSession->IsRatchets () && (m_RoutingSession->CleanupUnconfirmedTags () ||
|
||||||
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT)
|
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT))
|
||||||
{
|
{
|
||||||
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||||
path = nullptr;
|
path = nullptr;
|
||||||
@ -413,7 +417,14 @@ namespace datagram
|
|||||||
auto sz = ls.size();
|
auto sz = ls.size();
|
||||||
if (sz)
|
if (sz)
|
||||||
{
|
{
|
||||||
auto idx = rand() % sz;
|
int idx = -1;
|
||||||
|
if (m_LocalDestination)
|
||||||
|
{
|
||||||
|
auto pool = m_LocalDestination->GetTunnelPool ();
|
||||||
|
if (pool)
|
||||||
|
idx = m_LocalDestination->GetTunnelPool ()->GetRng ()() % sz;
|
||||||
|
}
|
||||||
|
if (idx < 0) idx = rand () % sz;
|
||||||
path->remoteLease = ls[idx];
|
path->remoteLease = ls[idx];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -439,7 +450,14 @@ namespace datagram
|
|||||||
auto sz = ls.size();
|
auto sz = ls.size();
|
||||||
if (sz)
|
if (sz)
|
||||||
{
|
{
|
||||||
auto idx = rand() % sz;
|
int idx = -1;
|
||||||
|
if (m_LocalDestination)
|
||||||
|
{
|
||||||
|
auto pool = m_LocalDestination->GetTunnelPool ();
|
||||||
|
if (pool)
|
||||||
|
idx = m_LocalDestination->GetTunnelPool ()->GetRng ()() % sz;
|
||||||
|
}
|
||||||
|
if (idx < 0) idx = rand () % sz;
|
||||||
path->remoteLease = ls[idx];
|
path->remoteLease = ls[idx];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -43,6 +43,7 @@ namespace datagram
|
|||||||
const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000;
|
const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000;
|
||||||
// max 64 messages buffered in send queue for each datagram session
|
// max 64 messages buffered in send queue for each datagram session
|
||||||
const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64;
|
const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64;
|
||||||
|
const uint64_t DATAGRAM_MAX_FLUSH_INTERVAL = 5; // in milliseconds
|
||||||
|
|
||||||
class DatagramSession : public std::enable_shared_from_this<DatagramSession>
|
class DatagramSession : public std::enable_shared_from_this<DatagramSession>
|
||||||
{
|
{
|
||||||
@ -98,7 +99,7 @@ namespace datagram
|
|||||||
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
||||||
std::vector<std::shared_ptr<i2p::garlic::GarlicRoutingSession> > m_PendingRoutingSessions;
|
std::vector<std::shared_ptr<i2p::garlic::GarlicRoutingSession> > m_PendingRoutingSessions;
|
||||||
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||||
uint64_t m_LastUse;
|
uint64_t m_LastUse, m_LastFlush; // milliseconds
|
||||||
bool m_RequestingLS;
|
bool m_RequestingLS;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -801,7 +801,7 @@ namespace client
|
|||||||
|
|
||||||
void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey)
|
void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey)
|
||||||
{
|
{
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::unordered_set<i2p::data::IdentHash> excluded;
|
||||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded);
|
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded);
|
||||||
if (floodfill)
|
if (floodfill)
|
||||||
{
|
{
|
||||||
@ -979,8 +979,10 @@ namespace client
|
|||||||
bool isPublic, const std::map<std::string, std::string> * params):
|
bool isPublic, const std::map<std::string, std::string> * params):
|
||||||
LeaseSetDestination (service, isPublic, params),
|
LeaseSetDestination (service, isPublic, params),
|
||||||
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
||||||
|
m_StreamingOutboundSpeed (DEFAULT_MAX_OUTBOUND_SPEED),
|
||||||
|
m_StreamingInboundSpeed (DEFAULT_MAX_INBOUND_SPEED),
|
||||||
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0),
|
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0),
|
||||||
m_DatagramDestination (nullptr), m_RefCounter (0),
|
m_DatagramDestination (nullptr), m_RefCounter (0), m_LastPublishedTimestamp (0),
|
||||||
m_ReadyChecker(service)
|
m_ReadyChecker(service)
|
||||||
{
|
{
|
||||||
if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||||
@ -1047,6 +1049,12 @@ namespace client
|
|||||||
auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY);
|
auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
m_StreamingAckDelay = std::stoi(it->second);
|
m_StreamingAckDelay = std::stoi(it->second);
|
||||||
|
it = params->find (I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED);
|
||||||
|
if (it != params->end ())
|
||||||
|
m_StreamingOutboundSpeed = std::stoi(it->second);
|
||||||
|
it = params->find (I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED);
|
||||||
|
if (it != params->end ())
|
||||||
|
m_StreamingInboundSpeed = std::stoi(it->second);
|
||||||
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
|
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true
|
m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true
|
||||||
@ -1097,7 +1105,6 @@ namespace client
|
|||||||
void ClientDestination::Stop ()
|
void ClientDestination::Stop ()
|
||||||
{
|
{
|
||||||
LogPrint(eLogDebug, "Destination: Stopping destination ", GetIdentHash().ToBase32(), ".b32.i2p");
|
LogPrint(eLogDebug, "Destination: Stopping destination ", GetIdentHash().ToBase32(), ".b32.i2p");
|
||||||
LeaseSetDestination::Stop ();
|
|
||||||
m_ReadyChecker.cancel();
|
m_ReadyChecker.cancel();
|
||||||
LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination");
|
LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination");
|
||||||
m_StreamingDestination->Stop ();
|
m_StreamingDestination->Stop ();
|
||||||
@ -1119,6 +1126,7 @@ namespace client
|
|||||||
delete m_DatagramDestination;
|
delete m_DatagramDestination;
|
||||||
m_DatagramDestination = nullptr;
|
m_DatagramDestination = nullptr;
|
||||||
}
|
}
|
||||||
|
LeaseSetDestination::Stop ();
|
||||||
LogPrint(eLogDebug, "Destination: -> Stopping done");
|
LogPrint(eLogDebug, "Destination: -> Stopping done");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1426,12 +1434,19 @@ namespace client
|
|||||||
if (m_StandardEncryptionKey)
|
if (m_StandardEncryptionKey)
|
||||||
keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub} );
|
keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub} );
|
||||||
|
|
||||||
|
auto publishedTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
if (publishedTimestamp <= m_LastPublishedTimestamp)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "Destination: LeaseSet update at the same second");
|
||||||
|
publishedTimestamp++; // force newer timestamp
|
||||||
|
}
|
||||||
bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
|
bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
|
||||||
auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
|
auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
|
||||||
m_Keys, keySections, tunnels, IsPublic (), isPublishedEncrypted);
|
m_Keys, keySections, tunnels, IsPublic (), publishedTimestamp, isPublishedEncrypted);
|
||||||
if (isPublishedEncrypted) // encrypt if type 5
|
if (isPublishedEncrypted) // encrypt if type 5
|
||||||
ls2 = std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (ls2, m_Keys, GetAuthType (), m_AuthKeys);
|
ls2 = std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (ls2, m_Keys, GetAuthType (), m_AuthKeys);
|
||||||
leaseSet = ls2;
|
leaseSet = ls2;
|
||||||
|
m_LastPublishedTimestamp = publishedTimestamp;
|
||||||
}
|
}
|
||||||
SetLeaseSet (leaseSet);
|
SetLeaseSet (leaseSet);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <set>
|
#include <unordered_set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
@ -84,6 +84,10 @@ namespace client
|
|||||||
// streaming
|
// streaming
|
||||||
const char I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY[] = "i2p.streaming.initialAckDelay";
|
const char I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY[] = "i2p.streaming.initialAckDelay";
|
||||||
const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds
|
const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds
|
||||||
|
const char I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED[] = "i2p.streaming.maxOutboundSpeed"; // bytes/sec
|
||||||
|
const int DEFAULT_MAX_OUTBOUND_SPEED = 1730000000; // no more than 1.73 Gbytes/s
|
||||||
|
const char I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED[] = "i2p.streaming.maxInboundSpeed"; // bytes/sec
|
||||||
|
const int DEFAULT_MAX_INBOUND_SPEED = 1730000000; // no more than 1.73 Gbytes/s
|
||||||
const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings";
|
const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings";
|
||||||
const int DEFAULT_ANSWER_PINGS = true;
|
const int DEFAULT_ANSWER_PINGS = true;
|
||||||
|
|
||||||
@ -97,7 +101,7 @@ namespace client
|
|||||||
struct LeaseSetRequest
|
struct LeaseSetRequest
|
||||||
{
|
{
|
||||||
LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {};
|
LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {};
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::unordered_set<i2p::data::IdentHash> excluded;
|
||||||
uint64_t requestTime;
|
uint64_t requestTime;
|
||||||
boost::asio::deadline_timer requestTimeoutTimer;
|
boost::asio::deadline_timer requestTimeoutTimer;
|
||||||
std::list<RequestComplete> requestComplete;
|
std::list<RequestComplete> requestComplete;
|
||||||
@ -195,7 +199,7 @@ namespace client
|
|||||||
bool m_IsPublic;
|
bool m_IsPublic;
|
||||||
uint32_t m_PublishReplyToken;
|
uint32_t m_PublishReplyToken;
|
||||||
uint64_t m_LastSubmissionTime; // in seconds
|
uint64_t m_LastSubmissionTime; // in seconds
|
||||||
std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
|
std::unordered_set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
|
||||||
|
|
||||||
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer,
|
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer,
|
||||||
m_PublishDelayTimer, m_CleanupTimer;
|
m_PublishDelayTimer, m_CleanupTimer;
|
||||||
@ -259,6 +263,8 @@ namespace client
|
|||||||
bool IsAcceptingStreams () const;
|
bool IsAcceptingStreams () const;
|
||||||
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
|
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
|
||||||
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
|
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
|
||||||
|
int GetStreamingOutboundSpeed () const { return m_StreamingOutboundSpeed; }
|
||||||
|
int GetStreamingInboundSpeed () const { return m_StreamingInboundSpeed; }
|
||||||
bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; }
|
bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; }
|
||||||
|
|
||||||
// datagram
|
// datagram
|
||||||
@ -296,12 +302,15 @@ namespace client
|
|||||||
std::unique_ptr<EncryptionKey> m_ECIESx25519EncryptionKey;
|
std::unique_ptr<EncryptionKey> m_ECIESx25519EncryptionKey;
|
||||||
|
|
||||||
int m_StreamingAckDelay;
|
int m_StreamingAckDelay;
|
||||||
|
int m_StreamingOutboundSpeed;
|
||||||
|
int m_StreamingInboundSpeed;
|
||||||
bool m_IsStreamingAnswerPings;
|
bool m_IsStreamingAnswerPings;
|
||||||
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
||||||
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
|
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
|
||||||
std::shared_ptr<i2p::stream::StreamingDestination> m_LastStreamingDestination; uint16_t m_LastPort; // for server tunnels
|
std::shared_ptr<i2p::stream::StreamingDestination> m_LastStreamingDestination; uint16_t m_LastPort; // for server tunnels
|
||||||
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
||||||
int m_RefCounter; // how many clients(tunnels) use this destination
|
int m_RefCounter; // how many clients(tunnels) use this destination
|
||||||
|
uint64_t m_LastPublishedTimestamp;
|
||||||
|
|
||||||
boost::asio::deadline_timer m_ReadyChecker;
|
boost::asio::deadline_timer m_ReadyChecker;
|
||||||
|
|
||||||
|
@ -229,6 +229,29 @@ namespace garlic
|
|||||||
tagsetNsr->NextSessionTagRatchet ();
|
tagsetNsr->NextSessionTagRatchet ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::MessageConfirmed (uint32_t msgID)
|
||||||
|
{
|
||||||
|
auto ret = GarlicRoutingSession::MessageConfirmed (msgID); // LeaseSet
|
||||||
|
if (m_AckRequestMsgID && m_AckRequestMsgID == msgID)
|
||||||
|
{
|
||||||
|
m_AckRequestMsgID = 0;
|
||||||
|
m_AckRequestNumAttempts = 0;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::CleanupUnconfirmedTags ()
|
||||||
|
{
|
||||||
|
if (m_AckRequestMsgID && m_AckRequestNumAttempts > ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS)
|
||||||
|
{
|
||||||
|
m_AckRequestMsgID = 0;
|
||||||
|
m_AckRequestNumAttempts = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len)
|
bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (!GetOwner ()) return false;
|
if (!GetOwner ()) return false;
|
||||||
@ -333,8 +356,9 @@ namespace garlic
|
|||||||
auto offset1 = offset;
|
auto offset1 = offset;
|
||||||
for (auto i = 0; i < numAcks; i++)
|
for (auto i = 0; i < numAcks; i++)
|
||||||
{
|
{
|
||||||
offset1 += 2; // tagsetid
|
uint32_t tagsetid = bufbe16toh (buf + offset1); offset1 += 2; // tagsetid
|
||||||
MessageConfirmed (bufbe16toh (buf + offset1)); offset1 += 2; // N
|
uint16_t n = bufbe16toh (buf + offset1); offset1 += 2; // N
|
||||||
|
MessageConfirmed ((tagsetid << 16) + n); // msgid = (tagsetid << 16) + N
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -397,7 +421,6 @@ namespace garlic
|
|||||||
{
|
{
|
||||||
uint16_t keyID = bufbe16toh (buf); buf += 2; // keyID
|
uint16_t keyID = bufbe16toh (buf); buf += 2; // keyID
|
||||||
bool newKey = flag & ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG;
|
bool newKey = flag & ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG;
|
||||||
m_SendReverseKey = true;
|
|
||||||
if (!m_NextReceiveRatchet)
|
if (!m_NextReceiveRatchet)
|
||||||
m_NextReceiveRatchet.reset (new DHRatchet ());
|
m_NextReceiveRatchet.reset (new DHRatchet ());
|
||||||
else
|
else
|
||||||
@ -409,15 +432,14 @@ namespace garlic
|
|||||||
}
|
}
|
||||||
m_NextReceiveRatchet->keyID = keyID;
|
m_NextReceiveRatchet->keyID = keyID;
|
||||||
}
|
}
|
||||||
int tagsetID = 2*keyID;
|
|
||||||
if (newKey)
|
if (newKey)
|
||||||
{
|
{
|
||||||
m_NextReceiveRatchet->key = i2p::transport::transports.GetNextX25519KeysPair ();
|
m_NextReceiveRatchet->key = i2p::transport::transports.GetNextX25519KeysPair ();
|
||||||
m_NextReceiveRatchet->newKey = true;
|
m_NextReceiveRatchet->newKey = true;
|
||||||
tagsetID++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_NextReceiveRatchet->newKey = false;
|
m_NextReceiveRatchet->newKey = false;
|
||||||
|
auto tagsetID = m_NextReceiveRatchet->GetReceiveTagSetID ();
|
||||||
if (flag & ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG)
|
if (flag & ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG)
|
||||||
memcpy (m_NextReceiveRatchet->remote, buf, 32);
|
memcpy (m_NextReceiveRatchet->remote, buf, 32);
|
||||||
|
|
||||||
@ -431,7 +453,9 @@ namespace garlic
|
|||||||
GenerateMoreReceiveTags (newTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ?
|
GenerateMoreReceiveTags (newTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ?
|
||||||
GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MAX_NUM_GENERATED_TAGS);
|
GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MAX_NUM_GENERATED_TAGS);
|
||||||
receiveTagset->Expire ();
|
receiveTagset->Expire ();
|
||||||
|
|
||||||
LogPrint (eLogDebug, "Garlic: Next receive tagset ", tagsetID, " created");
|
LogPrint (eLogDebug, "Garlic: Next receive tagset ", tagsetID, " created");
|
||||||
|
m_SendReverseKey = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -753,7 +777,8 @@ namespace garlic
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4
|
moreTags = (receiveTagset->GetTagSetID () > 0) ? ECIESX25519_MAX_NUM_GENERATED_TAGS : // for non first tagset
|
||||||
|
(ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 1)); // N/2
|
||||||
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
|
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
|
||||||
moreTags -= (receiveTagset->GetNextIndex () - index);
|
moreTags -= (receiveTagset->GetNextIndex () - index);
|
||||||
index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind
|
index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind
|
||||||
@ -780,6 +805,8 @@ namespace garlic
|
|||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
#endif
|
#endif
|
||||||
case eSessionStateEstablished:
|
case eSessionStateEstablished:
|
||||||
|
if (m_SendReverseKey && receiveTagset->GetTagSetID () == m_NextReceiveRatchet->GetReceiveTagSetID ())
|
||||||
|
m_SendReverseKey = false; // tag received on new tagset
|
||||||
if (receiveTagset->IsNS ())
|
if (receiveTagset->IsNS ())
|
||||||
{
|
{
|
||||||
// our of sequence NSR
|
// our of sequence NSR
|
||||||
@ -857,6 +884,7 @@ namespace garlic
|
|||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
size_t payloadLen = 0;
|
size_t payloadLen = 0;
|
||||||
|
bool sendAckRequest = false;
|
||||||
if (first) payloadLen += 7;// datatime
|
if (first) payloadLen += 7;// datatime
|
||||||
if (msg)
|
if (msg)
|
||||||
{
|
{
|
||||||
@ -875,13 +903,28 @@ namespace garlic
|
|||||||
payloadLen += leaseSet->GetBufferLen () + DATABASE_STORE_HEADER_SIZE + 13;
|
payloadLen += leaseSet->GetBufferLen () + DATABASE_STORE_HEADER_SIZE + 13;
|
||||||
if (!first)
|
if (!first)
|
||||||
{
|
{
|
||||||
// ack request
|
// ack request for LeaseSet
|
||||||
|
m_AckRequestMsgID = m_SendTagset->GetMsgID ();
|
||||||
|
sendAckRequest = true;
|
||||||
|
// update LeaseSet status
|
||||||
SetLeaseSetUpdateStatus (eLeaseSetSubmitted);
|
SetLeaseSetUpdateStatus (eLeaseSetSubmitted);
|
||||||
SetLeaseSetUpdateMsgID (m_SendTagset->GetNextIndex ());
|
SetLeaseSetUpdateMsgID (m_AckRequestMsgID);
|
||||||
SetLeaseSetSubmissionTime (ts);
|
SetLeaseSetSubmissionTime (ts);
|
||||||
payloadLen += 4;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!sendAckRequest && !first &&
|
||||||
|
((!m_AckRequestMsgID && ts > m_LastAckRequestSendTime + ECIESX25519_ACK_REQUEST_INTERVAL) || // regular request
|
||||||
|
(m_AckRequestMsgID && ts > m_LastAckRequestSendTime + LEASESET_CONFIRMATION_TIMEOUT))) // previous request failed. try again
|
||||||
|
{
|
||||||
|
// not LeaseSet
|
||||||
|
m_AckRequestMsgID = m_SendTagset->GetMsgID ();
|
||||||
|
if (m_AckRequestMsgID)
|
||||||
|
{
|
||||||
|
m_AckRequestNumAttempts++;
|
||||||
|
sendAckRequest = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sendAckRequest) payloadLen += 4;
|
||||||
if (m_AckRequests.size () > 0)
|
if (m_AckRequests.size () > 0)
|
||||||
payloadLen += m_AckRequests.size ()*4 + 3;
|
payloadLen += m_AckRequests.size ()*4 + 3;
|
||||||
if (m_SendReverseKey)
|
if (m_SendReverseKey)
|
||||||
@ -933,16 +976,15 @@ namespace garlic
|
|||||||
}
|
}
|
||||||
// LeaseSet
|
// LeaseSet
|
||||||
if (leaseSet)
|
if (leaseSet)
|
||||||
{
|
|
||||||
offset += CreateLeaseSetClove (leaseSet, ts, payload + offset, payloadLen - offset);
|
offset += CreateLeaseSetClove (leaseSet, ts, payload + offset, payloadLen - offset);
|
||||||
if (!first)
|
// ack request
|
||||||
{
|
if (sendAckRequest)
|
||||||
// ack request
|
{
|
||||||
payload[offset] = eECIESx25519BlkAckRequest; offset++;
|
payload[offset] = eECIESx25519BlkAckRequest; offset++;
|
||||||
htobe16buf (payload + offset, 1); offset += 2;
|
htobe16buf (payload + offset, 1); offset += 2;
|
||||||
payload[offset] = 0; offset++; // flags
|
payload[offset] = 0; offset++; // flags
|
||||||
}
|
m_LastAckRequestSendTime = ts;
|
||||||
}
|
}
|
||||||
// msg
|
// msg
|
||||||
if (msg)
|
if (msg)
|
||||||
offset += CreateGarlicClove (msg, payload + offset, payloadLen - offset);
|
offset += CreateGarlicClove (msg, payload + offset, payloadLen - offset);
|
||||||
@ -977,7 +1019,6 @@ namespace garlic
|
|||||||
memcpy (payload + offset, m_NextReceiveRatchet->key->GetPublicKey (), 32);
|
memcpy (payload + offset, m_NextReceiveRatchet->key->GetPublicKey (), 32);
|
||||||
offset += 32; // public key
|
offset += 32; // public key
|
||||||
}
|
}
|
||||||
m_SendReverseKey = false;
|
|
||||||
}
|
}
|
||||||
if (m_SendForwardKey)
|
if (m_SendForwardKey)
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,9 @@ namespace garlic
|
|||||||
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
||||||
const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds
|
const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds
|
||||||
const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds
|
const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds
|
||||||
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
|
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // in seconds
|
||||||
|
const int ECIESX25519_ACK_REQUEST_INTERVAL = 33000; // in milliseconds
|
||||||
|
const int ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS = 3;
|
||||||
const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 8192; // number of tags we request new tagset after
|
const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 8192; // number of tags we request new tagset after
|
||||||
const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24;
|
const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24;
|
||||||
const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 320;
|
const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 320;
|
||||||
@ -57,6 +59,8 @@ namespace garlic
|
|||||||
int GetTagSetID () const { return m_TagSetID; };
|
int GetTagSetID () const { return m_TagSetID; };
|
||||||
void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; };
|
void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; };
|
||||||
|
|
||||||
|
uint32_t GetMsgID () const { return (m_TagSetID << 16) + m_NextIndex; }; // (tagsetid << 16) + N
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
i2p::data::Tag<64> m_SessionTagKeyData;
|
i2p::data::Tag<64> m_SessionTagKeyData;
|
||||||
@ -149,6 +153,7 @@ namespace garlic
|
|||||||
std::shared_ptr<i2p::crypto::X25519Keys> key;
|
std::shared_ptr<i2p::crypto::X25519Keys> key;
|
||||||
uint8_t remote[32]; // last remote public key
|
uint8_t remote[32]; // last remote public key
|
||||||
bool newKey = true;
|
bool newKey = true;
|
||||||
|
int GetReceiveTagSetID () const { return newKey ? (2*keyID + 1) : 2*keyID; }
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -177,14 +182,16 @@ namespace garlic
|
|||||||
bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; };
|
bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; };
|
||||||
bool IsTerminated () const { return m_IsTerminated; }
|
bool IsTerminated () const { return m_IsTerminated; }
|
||||||
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
|
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
|
||||||
|
bool CleanupUnconfirmedTags (); // return true if unaswered Ack requests, called from I2CP
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; };
|
i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; };
|
||||||
void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; };
|
void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; };
|
||||||
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
||||||
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index);
|
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index);
|
||||||
|
bool MessageConfirmed (uint32_t msgID);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
|
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
|
||||||
@ -218,11 +225,15 @@ namespace garlic
|
|||||||
m_LastSentTimestamp = 0; // in milliseconds
|
m_LastSentTimestamp = 0; // in milliseconds
|
||||||
std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRSendTagset;
|
std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRSendTagset;
|
||||||
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
|
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
|
||||||
std::list<std::pair<uint16_t, int> > m_AckRequests; // (tagsetid, index)
|
std::list<std::pair<uint16_t, int> > m_AckRequests; // incoming (tagsetid, index)
|
||||||
bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false;
|
bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false;
|
||||||
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
|
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
|
||||||
uint8_t m_PaddingSizes[32], m_NextPaddingSize;
|
uint8_t m_PaddingSizes[32], m_NextPaddingSize;
|
||||||
|
|
||||||
|
uint64_t m_LastAckRequestSendTime = 0; // milliseconds
|
||||||
|
uint32_t m_AckRequestMsgID = 0;
|
||||||
|
int m_AckRequestNumAttempts = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
|
@ -54,7 +54,11 @@ namespace fs {
|
|||||||
|
|
||||||
const std::string GetUTF8DataDir () {
|
const std::string GetUTF8DataDir () {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#if (BOOST_VERSION >= 108500)
|
||||||
|
boost::filesystem::path path (dataDir);
|
||||||
|
#else
|
||||||
boost::filesystem::wpath path (dataDir);
|
boost::filesystem::wpath path (dataDir);
|
||||||
|
#endif
|
||||||
auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16<wchar_t>() ) ); // convert path to UTF-8
|
auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16<wchar_t>() ) ); // convert path to UTF-8
|
||||||
auto dataDirUTF8 = path.string();
|
auto dataDirUTF8 = path.string();
|
||||||
boost::filesystem::path::imbue(loc); // Return locale settings back
|
boost::filesystem::path::imbue(loc); // Return locale settings back
|
||||||
@ -87,7 +91,11 @@ namespace fs {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if (BOOST_VERSION >= 108500)
|
||||||
|
dataDir = boost::filesystem::path(commonAppData).string() + "\\" + appName;
|
||||||
|
#else
|
||||||
dataDir = boost::filesystem::wpath(commonAppData).string() + "\\" + appName;
|
dataDir = boost::filesystem::wpath(commonAppData).string() + "\\" + appName;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
dataDir = "/var/lib/" + appName;
|
dataDir = "/var/lib/" + appName;
|
||||||
@ -112,7 +120,11 @@ namespace fs {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if (BOOST_VERSION >= 108500)
|
||||||
|
auto execPath = boost::filesystem::path(localAppData).parent_path();
|
||||||
|
#else
|
||||||
auto execPath = boost::filesystem::wpath(localAppData).parent_path();
|
auto execPath = boost::filesystem::wpath(localAppData).parent_path();
|
||||||
|
#endif
|
||||||
|
|
||||||
// if config file exists in .exe's folder use it
|
// if config file exists in .exe's folder use it
|
||||||
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
|
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
|
||||||
@ -131,7 +143,11 @@ namespace fs {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if (BOOST_VERSION >= 108500)
|
||||||
|
dataDir = boost::filesystem::path(localAppData).string() + "\\" + appName;
|
||||||
|
#else
|
||||||
dataDir = boost::filesystem::wpath(localAppData).string() + "\\" + appName;
|
dataDir = boost::filesystem::wpath(localAppData).string() + "\\" + appName;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,19 +273,19 @@ namespace fs {
|
|||||||
if (boost::filesystem::exists(p))
|
if (boost::filesystem::exists(p))
|
||||||
continue;
|
continue;
|
||||||
#if TARGET_OS_SIMULATOR
|
#if TARGET_OS_SIMULATOR
|
||||||
// ios simulator fs says it is case sensitive, but it is not
|
// ios simulator fs says it is case sensitive, but it is not
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
if (boost::filesystem::create_directory(p, ec))
|
if (boost::filesystem::create_directory(p, ec))
|
||||||
continue;
|
continue;
|
||||||
switch (ec.value()) {
|
switch (ec.value()) {
|
||||||
case boost::system::errc::file_exists:
|
case boost::system::errc::file_exists:
|
||||||
case boost::system::errc::success:
|
case boost::system::errc::success:
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
throw boost::system::system_error( ec, __func__ );
|
throw boost::system::system_error( ec, __func__ );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (boost::filesystem::create_directory(p))
|
if (boost::filesystem::create_directory(p))
|
||||||
continue; /* ^ throws exception on failure */
|
continue; /* ^ throws exception on failure */
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
|
@ -45,22 +45,17 @@ namespace garlic
|
|||||||
{
|
{
|
||||||
if (!m_SharedRoutingPath) return nullptr;
|
if (!m_SharedRoutingPath) return nullptr;
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
if (m_SharedRoutingPath->numTimesUsed >= ROUTING_PATH_MAX_NUM_TIMES_USED ||
|
if (!m_SharedRoutingPath->outboundTunnel->IsEstablished () ||
|
||||||
!m_SharedRoutingPath->outboundTunnel->IsEstablished () ||
|
|
||||||
ts*1000LL > m_SharedRoutingPath->remoteLease->endDate ||
|
ts*1000LL > m_SharedRoutingPath->remoteLease->endDate ||
|
||||||
ts > m_SharedRoutingPath->updateTime + ROUTING_PATH_EXPIRATION_TIMEOUT)
|
ts > m_SharedRoutingPath->updateTime + ROUTING_PATH_EXPIRATION_TIMEOUT)
|
||||||
m_SharedRoutingPath = nullptr;
|
m_SharedRoutingPath = nullptr;
|
||||||
if (m_SharedRoutingPath) m_SharedRoutingPath->numTimesUsed++;
|
|
||||||
return m_SharedRoutingPath;
|
return m_SharedRoutingPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GarlicRoutingSession::SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path)
|
void GarlicRoutingSession::SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path)
|
||||||
{
|
{
|
||||||
if (path && path->outboundTunnel && path->remoteLease)
|
if (path && path->outboundTunnel && path->remoteLease)
|
||||||
{
|
|
||||||
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
|
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
path->numTimesUsed = 0;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
path = nullptr;
|
path = nullptr;
|
||||||
m_SharedRoutingPath = path;
|
m_SharedRoutingPath = path;
|
||||||
|
@ -51,8 +51,7 @@ namespace garlic
|
|||||||
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
|
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
|
||||||
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
|
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
|
||||||
const int LEASESET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
|
const int LEASESET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
|
||||||
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
|
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 120; // in seconds
|
||||||
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
|
|
||||||
|
|
||||||
struct SessionTag: public i2p::data::Tag<32>
|
struct SessionTag: public i2p::data::Tag<32>
|
||||||
{
|
{
|
||||||
@ -89,7 +88,6 @@ namespace garlic
|
|||||||
std::shared_ptr<const i2p::data::Lease> remoteLease;
|
std::shared_ptr<const i2p::data::Lease> remoteLease;
|
||||||
int rtt; // RTT
|
int rtt; // RTT
|
||||||
uint32_t updateTime; // seconds since epoch
|
uint32_t updateTime; // seconds since epoch
|
||||||
int numTimesUsed;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class GarlicDestination;
|
class GarlicDestination;
|
||||||
@ -111,7 +109,7 @@ namespace garlic
|
|||||||
GarlicRoutingSession ();
|
GarlicRoutingSession ();
|
||||||
virtual ~GarlicRoutingSession ();
|
virtual ~GarlicRoutingSession ();
|
||||||
virtual std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) = 0;
|
virtual std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) = 0;
|
||||||
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession
|
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession and ECIESX25519AEADRatchetSession
|
||||||
virtual bool MessageConfirmed (uint32_t msgID);
|
virtual bool MessageConfirmed (uint32_t msgID);
|
||||||
virtual bool IsRatchets () const { return false; };
|
virtual bool IsRatchets () const { return false; };
|
||||||
virtual bool IsReadyToSend () const { return true; };
|
virtual bool IsReadyToSend () const { return true; };
|
||||||
|
@ -147,7 +147,7 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||||
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
|
uint32_t replyTunnelID, bool exploratory, std::unordered_set<i2p::data::IdentHash> * excludedPeers)
|
||||||
{
|
{
|
||||||
int cnt = excludedPeers ? excludedPeers->size () : 0;
|
int cnt = excludedPeers ? excludedPeers->size () : 0;
|
||||||
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
|
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
|
||||||
@ -192,7 +192,7 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
||||||
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
const std::unordered_set<i2p::data::IdentHash>& excludedFloodfills,
|
||||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
|
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
|
||||||
const uint8_t * replyTag, bool replyECIES)
|
const uint8_t * replyTag, bool replyECIES)
|
||||||
{
|
{
|
||||||
@ -862,12 +862,14 @@ namespace i2p
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case eI2NPDatabaseStore:
|
case eI2NPDatabaseStore:
|
||||||
case eI2NPDatabaseSearchReply:
|
|
||||||
// forward to netDb if came directly or through exploratory tunnel as response to our request
|
// forward to netDb if came directly or through exploratory tunnel as response to our request
|
||||||
if (!msg->from || !msg->from->GetTunnelPool () || msg->from->GetTunnelPool ()->IsExploratory ())
|
if (!msg->from || !msg->from->GetTunnelPool () || msg->from->GetTunnelPool ()->IsExploratory ())
|
||||||
i2p::data::netdb.PostI2NPMsg (msg);
|
i2p::data::netdb.PostI2NPMsg (msg);
|
||||||
break;
|
break;
|
||||||
|
case eI2NPDatabaseSearchReply:
|
||||||
|
if (!msg->from || !msg->from->GetTunnelPool () || msg->from->GetTunnelPool ()->IsExploratory ())
|
||||||
|
i2p::data::netdb.PostDatabaseSearchReplyMsg (msg);
|
||||||
|
break;
|
||||||
case eI2NPDatabaseLookup:
|
case eI2NPDatabaseLookup:
|
||||||
// forward to netDb if floodfill and came directly
|
// forward to netDb if floodfill and came directly
|
||||||
if (!msg->from && i2p::context.IsFloodfill ())
|
if (!msg->from && i2p::context.IsFloodfill ())
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <set>
|
#include <unordered_set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
@ -294,9 +294,9 @@ namespace tunnel
|
|||||||
std::shared_ptr<I2NPMessage> CreateTunnelTestMsg (uint32_t msgID);
|
std::shared_ptr<I2NPMessage> CreateTunnelTestMsg (uint32_t msgID);
|
||||||
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
|
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
|
||||||
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||||
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
|
uint32_t replyTunnelID, bool exploratory = false, std::unordered_set<i2p::data::IdentHash> * excludedPeers = nullptr);
|
||||||
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
||||||
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
const std::unordered_set<i2p::data::IdentHash>& excludedFloodfills,
|
||||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
|
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
|
||||||
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false);
|
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false);
|
||||||
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
|
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -420,6 +420,14 @@ namespace data
|
|||||||
return CreateEncryptor (GetCryptoKeyType (), key);
|
return CreateEncryptor (GetCryptoKeyType (), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t GetIdentityBufferLen (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
if (len < DEFAULT_IDENTITY_SIZE) return 0;
|
||||||
|
size_t l = DEFAULT_IDENTITY_SIZE + bufbe16toh (buf + DEFAULT_IDENTITY_SIZE - 2);
|
||||||
|
if (l > len) return 0;
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
PrivateKeys& PrivateKeys::operator=(const Keys& keys)
|
PrivateKeys& PrivateKeys::operator=(const Keys& keys)
|
||||||
{
|
{
|
||||||
m_Public = std::make_shared<IdentityEx>(Identity (keys));
|
m_Public = std::make_shared<IdentityEx>(Identity (keys));
|
||||||
@ -479,7 +487,12 @@ namespace data
|
|||||||
{
|
{
|
||||||
// offline information
|
// offline information
|
||||||
const uint8_t * offlineInfo = buf + ret;
|
const uint8_t * offlineInfo = buf + ret;
|
||||||
ret += 4; // expires timestamp
|
uint32_t expires = bufbe32toh (buf + ret); ret += 4; // expires timestamp
|
||||||
|
if (expires < i2p::util::GetSecondsSinceEpoch ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Identity: Offline signature expired");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
SigningKeyType keyType = bufbe16toh (buf + ret); ret += 2; // key type
|
SigningKeyType keyType = bufbe16toh (buf + ret); ret += 2; // key type
|
||||||
std::unique_ptr<i2p::crypto::Verifier> transientVerifier (IdentityEx::CreateVerifier (keyType));
|
std::unique_ptr<i2p::crypto::Verifier> transientVerifier (IdentityEx::CreateVerifier (keyType));
|
||||||
if (!transientVerifier) return 0;
|
if (!transientVerifier) return 0;
|
||||||
@ -790,11 +803,14 @@ namespace data
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentHash CreateRoutingKey (const IdentHash& ident)
|
IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay)
|
||||||
{
|
{
|
||||||
uint8_t buf[41]; // ident + yyyymmdd
|
uint8_t buf[41]; // ident + yyyymmdd
|
||||||
memcpy (buf, (const uint8_t *)ident, 32);
|
memcpy (buf, (const uint8_t *)ident, 32);
|
||||||
i2p::util::GetCurrentDate ((char *)(buf + 32));
|
if (nextDay)
|
||||||
|
i2p::util::GetNextDayDate ((char *)(buf + 32));
|
||||||
|
else
|
||||||
|
i2p::util::GetCurrentDate ((char *)(buf + 32));
|
||||||
IdentHash key;
|
IdentHash key;
|
||||||
SHA256(buf, 40, key);
|
SHA256(buf, 40, key);
|
||||||
return key;
|
return key;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -136,6 +136,8 @@ namespace data
|
|||||||
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
|
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
size_t GetIdentityBufferLen (const uint8_t * buf, size_t len); // return actual identity length in buffer
|
||||||
|
|
||||||
class PrivateKeys // for eepsites
|
class PrivateKeys // for eepsites
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -206,7 +208,7 @@ namespace data
|
|||||||
bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; };
|
bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
IdentHash CreateRoutingKey (const IdentHash& ident);
|
IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay = false);
|
||||||
XORMetric operator^(const IdentHash& key1, const IdentHash& key2);
|
XORMetric operator^(const IdentHash& key1, const IdentHash& key2);
|
||||||
|
|
||||||
// destination for delivery instructions
|
// destination for delivery instructions
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -728,25 +728,41 @@ namespace data
|
|||||||
memset (m_Buffer + offset, 0, signingKeyLen);
|
memset (m_Buffer + offset, 0, signingKeyLen);
|
||||||
offset += signingKeyLen;
|
offset += signingKeyLen;
|
||||||
// num leases
|
// num leases
|
||||||
|
auto numLeasesPos = offset;
|
||||||
m_Buffer[offset] = num;
|
m_Buffer[offset] = num;
|
||||||
offset++;
|
offset++;
|
||||||
// leases
|
// leases
|
||||||
m_Leases = m_Buffer + offset;
|
m_Leases = m_Buffer + offset;
|
||||||
auto currentTime = i2p::util::GetMillisecondsSinceEpoch ();
|
auto currentTime = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
int skipped = 0;
|
||||||
for (int i = 0; i < num; i++)
|
for (int i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
|
uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration
|
||||||
|
ts *= 1000; // in milliseconds
|
||||||
|
if (ts <= currentTime)
|
||||||
|
{
|
||||||
|
// already expired, skip
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ts > m_ExpirationTime) m_ExpirationTime = ts;
|
||||||
|
// make sure leaseset is newer than previous, but adding some time to expiration date
|
||||||
|
ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs
|
||||||
memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32);
|
memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32);
|
||||||
offset += 32; // gateway id
|
offset += 32; // gateway id
|
||||||
htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ());
|
htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ());
|
||||||
offset += 4; // tunnel id
|
offset += 4; // tunnel id
|
||||||
uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration
|
|
||||||
ts *= 1000; // in milliseconds
|
|
||||||
if (ts > m_ExpirationTime) m_ExpirationTime = ts;
|
|
||||||
// make sure leaseset is newer than previous, but adding some time to expiration date
|
|
||||||
ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs
|
|
||||||
htobe64buf (m_Buffer + offset, ts);
|
htobe64buf (m_Buffer + offset, ts);
|
||||||
offset += 8; // end date
|
offset += 8; // end date
|
||||||
}
|
}
|
||||||
|
if (skipped > 0)
|
||||||
|
{
|
||||||
|
// adjust num leases
|
||||||
|
if (skipped > num) skipped = num;
|
||||||
|
num -= skipped;
|
||||||
|
m_BufferLen -= skipped*LEASE_SIZE;
|
||||||
|
m_Buffer[numLeasesPos] = num;
|
||||||
|
}
|
||||||
// we don't sign it yet. must be signed later on
|
// we don't sign it yet. must be signed later on
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,7 +824,7 @@ namespace data
|
|||||||
|
|
||||||
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||||
const KeySections& encryptionKeys, const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels,
|
const KeySections& encryptionKeys, const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels,
|
||||||
bool isPublic, bool isPublishedEncrypted):
|
bool isPublic, uint64_t publishedTimestamp, bool isPublishedEncrypted):
|
||||||
LocalLeaseSet (keys.GetPublic (), nullptr, 0)
|
LocalLeaseSet (keys.GetPublic (), nullptr, 0)
|
||||||
{
|
{
|
||||||
auto identity = keys.GetPublic ();
|
auto identity = keys.GetPublic ();
|
||||||
@ -837,8 +853,7 @@ namespace data
|
|||||||
m_Buffer[0] = storeType;
|
m_Buffer[0] = storeType;
|
||||||
// LS2 header
|
// LS2 header
|
||||||
auto offset = identity->ToBuffer (m_Buffer + 1, m_BufferLen) + 1;
|
auto offset = identity->ToBuffer (m_Buffer + 1, m_BufferLen) + 1;
|
||||||
auto timestamp = i2p::util::GetSecondsSinceEpoch ();
|
htobe32buf (m_Buffer + offset, publishedTimestamp); offset += 4; // published timestamp (seconds)
|
||||||
htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
|
|
||||||
uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later
|
uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later
|
||||||
htobe16buf (m_Buffer + offset, flags); offset += 2; // flags
|
htobe16buf (m_Buffer + offset, flags); offset += 2; // flags
|
||||||
if (keys.IsOfflineSignature ())
|
if (keys.IsOfflineSignature ())
|
||||||
@ -859,29 +874,44 @@ namespace data
|
|||||||
}
|
}
|
||||||
// leases
|
// leases
|
||||||
uint32_t expirationTime = 0; // in seconds
|
uint32_t expirationTime = 0; // in seconds
|
||||||
|
int skipped = 0; auto numLeasesPos = offset;
|
||||||
m_Buffer[offset] = num; offset++; // num leases
|
m_Buffer[offset] = num; offset++; // num leases
|
||||||
for (int i = 0; i < num; i++)
|
for (int i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
|
auto ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // in seconds, 1 minute before expiration
|
||||||
|
if (ts <= publishedTimestamp)
|
||||||
|
{
|
||||||
|
// already expired, skip
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ts > expirationTime) expirationTime = ts;
|
||||||
memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32);
|
memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32);
|
||||||
offset += 32; // gateway id
|
offset += 32; // gateway id
|
||||||
htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ());
|
htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ());
|
||||||
offset += 4; // tunnel id
|
offset += 4; // tunnel id
|
||||||
auto ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // in seconds, 1 minute before expiration
|
|
||||||
if (ts > expirationTime) expirationTime = ts;
|
|
||||||
htobe32buf (m_Buffer + offset, ts);
|
htobe32buf (m_Buffer + offset, ts);
|
||||||
offset += 4; // end date
|
offset += 4; // end date
|
||||||
}
|
}
|
||||||
|
if (skipped > 0)
|
||||||
|
{
|
||||||
|
// adjust num leases
|
||||||
|
if (skipped > num) skipped = num;
|
||||||
|
num -= skipped;
|
||||||
|
m_BufferLen -= skipped*LEASE2_SIZE;
|
||||||
|
m_Buffer[numLeasesPos] = num;
|
||||||
|
}
|
||||||
// update expiration
|
// update expiration
|
||||||
if (expirationTime)
|
if (expirationTime)
|
||||||
{
|
{
|
||||||
SetExpirationTime (expirationTime*1000LL);
|
SetExpirationTime (expirationTime*1000LL);
|
||||||
auto expires = (int)expirationTime - timestamp;
|
auto expires = (int)expirationTime - publishedTimestamp;
|
||||||
htobe16buf (expiresBuf, expires > 0 ? expires : 0);
|
htobe16buf (expiresBuf, expires > 0 ? expires : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// no tunnels or withdraw
|
// no tunnels or withdraw
|
||||||
SetExpirationTime (timestamp*1000LL);
|
SetExpirationTime (publishedTimestamp*1000LL);
|
||||||
memset (expiresBuf, 0, 2); // expires immeditely
|
memset (expiresBuf, 0, 2); // expires immeditely
|
||||||
}
|
}
|
||||||
// sign
|
// sign
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -256,7 +256,8 @@ namespace data
|
|||||||
LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||||
const KeySections& encryptionKeys,
|
const KeySections& encryptionKeys,
|
||||||
const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels,
|
const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels,
|
||||||
bool isPublic, bool isPublishedEncrypted = false);
|
bool isPublic, uint64_t publishedTimestamp,
|
||||||
|
bool isPublishedEncrypted = false);
|
||||||
|
|
||||||
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
||||||
|
|
||||||
|
@ -108,10 +108,10 @@ namespace transport
|
|||||||
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
|
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Establisher::CreateSessionRequestMessage ()
|
void NTCP2Establisher::CreateSessionRequestMessage (std::mt19937& rng)
|
||||||
{
|
{
|
||||||
// create buffer and fill padding
|
// create buffer and fill padding
|
||||||
auto paddingLength = rand () % (NTCP2_SESSION_REQUEST_MAX_SIZE - 64); // message length doesn't exceed 287 bytes
|
auto paddingLength = rng () % (NTCP2_SESSION_REQUEST_MAX_SIZE - 64); // message length doesn't exceed 287 bytes
|
||||||
m_SessionRequestBufferLen = paddingLength + 64;
|
m_SessionRequestBufferLen = paddingLength + 64;
|
||||||
RAND_bytes (m_SessionRequestBuffer + 64, paddingLength);
|
RAND_bytes (m_SessionRequestBuffer + 64, paddingLength);
|
||||||
// encrypt X
|
// encrypt X
|
||||||
@ -129,7 +129,8 @@ namespace transport
|
|||||||
options[1] = 2; // ver
|
options[1] = 2; // ver
|
||||||
htobe16buf (options + 2, paddingLength); // padLen
|
htobe16buf (options + 2, paddingLength); // padLen
|
||||||
// m3p2Len
|
// m3p2Len
|
||||||
auto bufLen = i2p::context.GetRouterInfo ().GetBufferLen ();
|
auto riBuffer = i2p::context.CopyRouterInfoBuffer ();
|
||||||
|
auto bufLen = riBuffer->GetBufferLen ();
|
||||||
m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options
|
m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options
|
||||||
htobe16buf (options + 4, m3p2Len);
|
htobe16buf (options + 4, m3p2Len);
|
||||||
// fill m3p2 payload (RouterInfo block)
|
// fill m3p2 payload (RouterInfo block)
|
||||||
@ -138,7 +139,7 @@ namespace transport
|
|||||||
m3p2[0] = eNTCP2BlkRouterInfo; // block
|
m3p2[0] = eNTCP2BlkRouterInfo; // block
|
||||||
htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI
|
htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI
|
||||||
m3p2[3] = 0; // flag
|
m3p2[3] = 0; // flag
|
||||||
memcpy (m3p2 + 4, i2p::context.GetRouterInfo ().GetBuffer (), bufLen); // TODO: own RI should be protected by mutex
|
memcpy (m3p2 + 4, riBuffer->data (), bufLen); // TODO: eliminate extra copy
|
||||||
// 2 bytes reserved
|
// 2 bytes reserved
|
||||||
htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsA, rounded to seconds
|
htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsA, rounded to seconds
|
||||||
// 4 bytes reserved
|
// 4 bytes reserved
|
||||||
@ -148,9 +149,9 @@ namespace transport
|
|||||||
i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt
|
i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Establisher::CreateSessionCreatedMessage ()
|
void NTCP2Establisher::CreateSessionCreatedMessage (std::mt19937& rng)
|
||||||
{
|
{
|
||||||
auto paddingLen = rand () % (NTCP2_SESSION_CREATED_MAX_SIZE - 64);
|
auto paddingLen = rng () % (NTCP2_SESSION_CREATED_MAX_SIZE - 64);
|
||||||
m_SessionCreatedBufferLen = paddingLen + 64;
|
m_SessionCreatedBufferLen = paddingLen + 64;
|
||||||
RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen);
|
RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen);
|
||||||
// encrypt Y
|
// encrypt Y
|
||||||
@ -348,7 +349,7 @@ namespace transport
|
|||||||
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 address");
|
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 address");
|
||||||
}
|
}
|
||||||
m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL +
|
m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL +
|
||||||
rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
|
m_Server.GetRng ()() % NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTCP2Session::~NTCP2Session ()
|
NTCP2Session::~NTCP2Session ()
|
||||||
@ -410,7 +411,8 @@ namespace transport
|
|||||||
{
|
{
|
||||||
m_IsEstablished = true;
|
m_IsEstablished = true;
|
||||||
m_Establisher.reset (nullptr);
|
m_Establisher.reset (nullptr);
|
||||||
SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT);
|
SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT + m_Server.GetRng ()() % NTCP2_TERMINATION_TIMEOUT_VARIANCE);
|
||||||
|
SendQueue ();
|
||||||
transports.PeerConnected (shared_from_this ());
|
transports.PeerConnected (shared_from_this ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,7 +464,7 @@ namespace transport
|
|||||||
|
|
||||||
void NTCP2Session::SendSessionRequest ()
|
void NTCP2Session::SendSessionRequest ()
|
||||||
{
|
{
|
||||||
m_Establisher->CreateSessionRequestMessage ();
|
m_Establisher->CreateSessionRequestMessage (m_Server.GetRng ());
|
||||||
// send message
|
// send message
|
||||||
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
|
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (),
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (),
|
||||||
@ -540,7 +542,7 @@ namespace transport
|
|||||||
|
|
||||||
void NTCP2Session::SendSessionCreated ()
|
void NTCP2Session::SendSessionCreated ()
|
||||||
{
|
{
|
||||||
m_Establisher->CreateSessionCreatedMessage ();
|
m_Establisher->CreateSessionCreatedMessage (m_Server.GetRng ());
|
||||||
// send message
|
// send message
|
||||||
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
|
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (),
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (),
|
||||||
@ -1119,7 +1121,7 @@ namespace transport
|
|||||||
if (GetLastActivityTimestamp () > m_NextRouterInfoResendTime)
|
if (GetLastActivityTimestamp () > m_NextRouterInfoResendTime)
|
||||||
{
|
{
|
||||||
m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL +
|
m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL +
|
||||||
rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
|
m_Server.GetRng ()() % NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
|
||||||
SendRouterInfo ();
|
SendRouterInfo ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1132,7 +1134,7 @@ namespace transport
|
|||||||
|
|
||||||
void NTCP2Session::SendQueue ()
|
void NTCP2Session::SendQueue ()
|
||||||
{
|
{
|
||||||
if (!m_SendQueue.empty ())
|
if (!m_SendQueue.empty () && m_IsEstablished)
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<I2NPMessage> > msgs;
|
std::vector<std::shared_ptr<I2NPMessage> > msgs;
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
@ -1169,6 +1171,21 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::MoveSendQueue (std::shared_ptr<NTCP2Session> other)
|
||||||
|
{
|
||||||
|
if (!other || m_SendQueue.empty ()) return;
|
||||||
|
std::vector<std::shared_ptr<I2NPMessage> > msgs;
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
for (auto it: m_SendQueue)
|
||||||
|
if (!it->IsExpired (ts))
|
||||||
|
msgs.push_back (it);
|
||||||
|
else
|
||||||
|
it->Drop ();
|
||||||
|
m_SendQueue.clear ();
|
||||||
|
if (!msgs.empty ())
|
||||||
|
other->PostI2NPMessages (msgs);
|
||||||
|
}
|
||||||
|
|
||||||
size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len)
|
size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (len < 3) return 0;
|
if (len < 3) return 0;
|
||||||
@ -1200,7 +1217,8 @@ namespace transport
|
|||||||
void NTCP2Session::SendRouterInfo ()
|
void NTCP2Session::SendRouterInfo ()
|
||||||
{
|
{
|
||||||
if (!IsEstablished ()) return;
|
if (!IsEstablished ()) return;
|
||||||
auto riLen = i2p::context.GetRouterInfo ().GetBufferLen ();
|
auto riBuffer = i2p::context.CopyRouterInfoBuffer ();
|
||||||
|
auto riLen = riBuffer->GetBufferLen ();
|
||||||
size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime
|
size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime
|
||||||
m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding
|
m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding
|
||||||
// DateTime block
|
// DateTime block
|
||||||
@ -1211,7 +1229,7 @@ namespace transport
|
|||||||
m_NextSendBuffer[9] = eNTCP2BlkRouterInfo;
|
m_NextSendBuffer[9] = eNTCP2BlkRouterInfo;
|
||||||
htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size
|
htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size
|
||||||
m_NextSendBuffer[12] = 0; // flag
|
m_NextSendBuffer[12] = 0; // flag
|
||||||
memcpy (m_NextSendBuffer + 13, i2p::context.GetRouterInfo ().GetBuffer (), riLen);
|
memcpy (m_NextSendBuffer + 13, riBuffer->data (), riLen); // TODO: eliminate extra copy
|
||||||
// padding block
|
// padding block
|
||||||
auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64);
|
auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64);
|
||||||
payloadLen += paddingSize;
|
payloadLen += paddingSize;
|
||||||
@ -1261,7 +1279,7 @@ namespace transport
|
|||||||
else
|
else
|
||||||
m_SendQueue.push_back (std::move (it));
|
m_SendQueue.push_back (std::move (it));
|
||||||
|
|
||||||
if (!m_IsSending)
|
if (!m_IsSending && m_IsEstablished)
|
||||||
SendQueue ();
|
SendQueue ();
|
||||||
else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
|
else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
|
||||||
{
|
{
|
||||||
@ -1280,7 +1298,8 @@ namespace transport
|
|||||||
|
|
||||||
NTCP2Server::NTCP2Server ():
|
NTCP2Server::NTCP2Server ():
|
||||||
RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()),
|
RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()),
|
||||||
m_ProxyType(eNoProxy), m_Resolver(GetService ())
|
m_ProxyType(eNoProxy), m_Resolver(GetService ()),
|
||||||
|
m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1424,6 +1443,7 @@ namespace transport
|
|||||||
{
|
{
|
||||||
// replace by new session
|
// replace by new session
|
||||||
auto s = it->second;
|
auto s = it->second;
|
||||||
|
s->MoveSendQueue (session);
|
||||||
m_NTCP2Sessions.erase (it);
|
m_NTCP2Sessions.erase (it);
|
||||||
s->Terminate ();
|
s->Terminate ();
|
||||||
}
|
}
|
||||||
@ -1622,7 +1642,8 @@ namespace transport
|
|||||||
|
|
||||||
void NTCP2Server::ScheduleTermination ()
|
void NTCP2Server::ScheduleTermination ()
|
||||||
{
|
{
|
||||||
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP2_TERMINATION_CHECK_TIMEOUT));
|
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(
|
||||||
|
NTCP2_TERMINATION_CHECK_TIMEOUT + m_Rng () % NTCP2_TERMINATION_CHECK_TIMEOUT_VARIANCE));
|
||||||
m_TerminationTimer.async_wait (std::bind (&NTCP2Server::HandleTerminationTimer,
|
m_TerminationTimer.async_wait (std::bind (&NTCP2Server::HandleTerminationTimer,
|
||||||
this, std::placeholders::_1));
|
this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <random>
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
@ -35,8 +36,10 @@ namespace transport
|
|||||||
|
|
||||||
const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds
|
const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||||
const int NTCP2_ESTABLISH_TIMEOUT = 10; // 10 seconds
|
const int NTCP2_ESTABLISH_TIMEOUT = 10; // 10 seconds
|
||||||
const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes
|
const int NTCP2_TERMINATION_TIMEOUT = 115; // 2 minutes - 5 seconds
|
||||||
const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
const int NTCP2_TERMINATION_TIMEOUT_VARIANCE = 10; // 10 seconds
|
||||||
|
const int NTCP2_TERMINATION_CHECK_TIMEOUT = 28; // 28 seconds
|
||||||
|
const int NTCP2_TERMINATION_CHECK_TIMEOUT_VARIANCE = 5; // 5 seconds
|
||||||
const int NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT = 3; // 3 seconds
|
const int NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT = 3; // 3 seconds
|
||||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL = 25*60; // 25 minuntes in seconds
|
const int NTCP2_ROUTERINFO_RESEND_INTERVAL = 25*60; // 25 minuntes in seconds
|
||||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD = 25*60; // 25 minuntes
|
const int NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD = 25*60; // 25 minuntes
|
||||||
@ -103,8 +106,8 @@ namespace transport
|
|||||||
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
|
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
|
||||||
void CreateEphemeralKey ();
|
void CreateEphemeralKey ();
|
||||||
|
|
||||||
void CreateSessionRequestMessage ();
|
void CreateSessionRequestMessage (std::mt19937& rng);
|
||||||
void CreateSessionCreatedMessage ();
|
void CreateSessionCreatedMessage (std::mt19937& rng);
|
||||||
void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
|
void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
|
||||||
void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
|
void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
|
||||||
|
|
||||||
@ -151,7 +154,8 @@ namespace transport
|
|||||||
|
|
||||||
void SendLocalRouterInfo (bool update) override; // after handshake or by update
|
void SendLocalRouterInfo (bool update) override; // after handshake or by update
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
||||||
|
void MoveSendQueue (std::shared_ptr<NTCP2Session> other);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Established ();
|
void Established ();
|
||||||
@ -247,6 +251,7 @@ namespace transport
|
|||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||||
|
std::mt19937& GetRng () { return m_Rng; };
|
||||||
|
|
||||||
bool AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming = false);
|
bool AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming = false);
|
||||||
void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session);
|
void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session);
|
||||||
@ -285,6 +290,7 @@ namespace transport
|
|||||||
boost::asio::ip::tcp::resolver m_Resolver;
|
boost::asio::ip::tcp::resolver m_Resolver;
|
||||||
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
|
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
|
||||||
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
|
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
|
||||||
|
std::mt19937 m_Rng;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <random>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@ -36,7 +38,9 @@ namespace data
|
|||||||
{
|
{
|
||||||
NetDb netdb;
|
NetDb netdb;
|
||||||
|
|
||||||
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true)
|
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr),
|
||||||
|
m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true),
|
||||||
|
m_LastExploratorySelectionUpdateTime (0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +58,12 @@ namespace data
|
|||||||
m_Families.LoadCertificates ();
|
m_Families.LoadCertificates ();
|
||||||
Load ();
|
Load ();
|
||||||
|
|
||||||
|
if (!m_Requests)
|
||||||
|
{
|
||||||
|
m_Requests = std::make_shared<NetDbRequests>();
|
||||||
|
m_Requests->Start ();
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
|
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
|
||||||
if (m_RouterInfos.size () < threshold || m_Floodfills.GetSize () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
|
if (m_RouterInfos.size () < threshold || m_Floodfills.GetSize () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
|
||||||
{
|
{
|
||||||
@ -75,13 +85,15 @@ namespace data
|
|||||||
m_Floodfills.Insert (i2p::context.GetSharedRouterInfo ());
|
m_Floodfills.Insert (i2p::context.GetSharedRouterInfo ());
|
||||||
|
|
||||||
i2p::config::GetOption("persist.profiles", m_PersistProfiles);
|
i2p::config::GetOption("persist.profiles", m_PersistProfiles);
|
||||||
|
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&NetDb::Run, this));
|
m_Thread = new std::thread (std::bind (&NetDb::Run, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::Stop ()
|
void NetDb::Stop ()
|
||||||
{
|
{
|
||||||
|
if (m_Requests)
|
||||||
|
m_Requests->Stop ();
|
||||||
if (m_IsRunning)
|
if (m_IsRunning)
|
||||||
{
|
{
|
||||||
if (m_PersistProfiles)
|
if (m_PersistProfiles)
|
||||||
@ -98,23 +110,23 @@ namespace data
|
|||||||
m_Thread = 0;
|
m_Thread = 0;
|
||||||
}
|
}
|
||||||
m_LeaseSets.clear();
|
m_LeaseSets.clear();
|
||||||
m_Requests.Stop ();
|
|
||||||
}
|
}
|
||||||
|
m_Requests = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::Run ()
|
void NetDb::Run ()
|
||||||
{
|
{
|
||||||
i2p::util::SetThreadName("NetDB");
|
i2p::util::SetThreadName("NetDB");
|
||||||
|
|
||||||
uint64_t lastManage = 0, lastExploratory = 0, lastManageRequest = 0;
|
uint64_t lastManage = 0;
|
||||||
uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch ();
|
uint64_t lastProfilesCleanup = i2p::util::GetMonotonicMilliseconds (), lastObsoleteProfilesCleanup = lastProfilesCleanup;
|
||||||
int16_t profilesCleanupVariance = 0;
|
int16_t profilesCleanupVariance = 0, obsoleteProfilesCleanVariance = 0;
|
||||||
|
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto msg = m_Queue.GetNextWithTimeout (15000); // 15 sec
|
auto msg = m_Queue.GetNextWithTimeout (1000); // 1 sec
|
||||||
if (msg)
|
if (msg)
|
||||||
{
|
{
|
||||||
int numMsgs = 0;
|
int numMsgs = 0;
|
||||||
@ -126,9 +138,6 @@ namespace data
|
|||||||
case eI2NPDatabaseStore:
|
case eI2NPDatabaseStore:
|
||||||
HandleDatabaseStoreMsg (msg);
|
HandleDatabaseStoreMsg (msg);
|
||||||
break;
|
break;
|
||||||
case eI2NPDatabaseSearchReply:
|
|
||||||
HandleDatabaseSearchReplyMsg (msg);
|
|
||||||
break;
|
|
||||||
case eI2NPDatabaseLookup:
|
case eI2NPDatabaseLookup:
|
||||||
HandleDatabaseLookupMsg (msg);
|
HandleDatabaseLookupMsg (msg);
|
||||||
break;
|
break;
|
||||||
@ -146,53 +155,55 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_IsRunning) break;
|
if (!m_IsRunning) break;
|
||||||
if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline
|
if (!i2p::transport::transports.IsOnline () || !i2p::transport::transports.IsRunning ())
|
||||||
|
continue; // don't manage netdb when offline or transports are not running
|
||||||
|
|
||||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint64_t mts = i2p::util::GetMonotonicMilliseconds ();
|
||||||
if (ts - lastManageRequest >= MANAGE_REQUESTS_INTERVAL || ts + MANAGE_REQUESTS_INTERVAL < lastManageRequest) // manage requests every 15 seconds
|
if (mts >= lastManage + 60000) // manage routers and leasesets every minute
|
||||||
{
|
|
||||||
m_Requests.ManageRequests ();
|
|
||||||
lastManageRequest = ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ts - lastManage >= 60 || ts + 60 < lastManage) // manage routers and leasesets every minute
|
|
||||||
{
|
{
|
||||||
if (lastManage)
|
if (lastManage)
|
||||||
{
|
{
|
||||||
ManageRouterInfos ();
|
ManageRouterInfos ();
|
||||||
ManageLeaseSets ();
|
ManageLeaseSets ();
|
||||||
}
|
}
|
||||||
lastManage = ts;
|
lastManage = mts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance) ||
|
if (mts >= lastProfilesCleanup + (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance)*1000)
|
||||||
ts + i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT < lastProfilesCleanup)
|
|
||||||
{
|
{
|
||||||
m_RouterProfilesPool.CleanUpMt ();
|
m_RouterProfilesPool.CleanUpMt ();
|
||||||
if (m_PersistProfiles) PersistProfiles ();
|
if (m_PersistProfiles)
|
||||||
DeleteObsoleteProfiles ();
|
{
|
||||||
lastProfilesCleanup = ts;
|
bool isSaving = m_SavingProfiles.valid ();
|
||||||
profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE);
|
if (isSaving && m_SavingProfiles.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active?
|
||||||
|
{
|
||||||
|
m_SavingProfiles.get ();
|
||||||
|
isSaving = false;
|
||||||
|
}
|
||||||
|
if (!isSaving)
|
||||||
|
m_SavingProfiles = PersistProfiles ();
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "NetDb: Can't persist profiles. Profiles are being saved to disk");
|
||||||
|
}
|
||||||
|
lastProfilesCleanup = mts;
|
||||||
|
profilesCleanupVariance = rand () % i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ts - lastExploratory >= 30 || ts + 30 < lastExploratory) // exploratory every 30 seconds
|
if (mts >= lastObsoleteProfilesCleanup + (uint64_t)(i2p::data::PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_TIMEOUT + obsoleteProfilesCleanVariance)*1000)
|
||||||
{
|
{
|
||||||
auto numRouters = m_RouterInfos.size ();
|
bool isDeleting = m_DeletingProfiles.valid ();
|
||||||
if (!numRouters)
|
if (isDeleting && m_DeletingProfiles.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active?
|
||||||
throw std::runtime_error("No known routers, reseed seems to be totally failed");
|
|
||||||
else // we have peers now
|
|
||||||
m_FloodfillBootstrap = nullptr;
|
|
||||||
if (numRouters < 2500 || ts - lastExploratory >= 90)
|
|
||||||
{
|
{
|
||||||
numRouters = 800/numRouters;
|
m_DeletingProfiles.get ();
|
||||||
if (numRouters < 1) numRouters = 1;
|
isDeleting = false;
|
||||||
if (numRouters > 9) numRouters = 9;
|
}
|
||||||
m_Requests.ManageRequests ();
|
if (!isDeleting)
|
||||||
if(!i2p::context.IsHidden ())
|
m_DeletingProfiles = DeleteObsoleteProfiles ();
|
||||||
Explore (numRouters);
|
else
|
||||||
lastExploratory = ts;
|
LogPrint (eLogWarning, "NetDb: Can't delete profiles. Profiles are being deleted from disk");
|
||||||
}
|
lastObsoleteProfilesCleanup = mts;
|
||||||
}
|
obsoleteProfilesCleanVariance = rand () % i2p::data::PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
@ -238,7 +249,7 @@ namespace data
|
|||||||
if (!r->Update (buf, len))
|
if (!r->Update (buf, len))
|
||||||
{
|
{
|
||||||
updated = false;
|
updated = false;
|
||||||
m_Requests.RequestComplete (ident, r);
|
m_Requests->RequestComplete (ident, r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
if (r->IsUnreachable () ||
|
if (r->IsUnreachable () ||
|
||||||
@ -251,7 +262,7 @@ namespace data
|
|||||||
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
||||||
m_Floodfills.Remove (r->GetIdentHash ());
|
m_Floodfills.Remove (r->GetIdentHash ());
|
||||||
}
|
}
|
||||||
m_Requests.RequestComplete (ident, nullptr);
|
m_Requests->RequestComplete (ident, nullptr);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,7 +280,7 @@ namespace data
|
|||||||
if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD || r->GetProfile ()->IsReal ())
|
if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD || r->GetProfile ()->IsReal ())
|
||||||
m_Floodfills.Insert (r);
|
m_Floodfills.Insert (r);
|
||||||
else
|
else
|
||||||
r->ResetFlooldFill ();
|
r->ResetFloodfill ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,8 +294,14 @@ namespace data
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
r = std::make_shared<RouterInfo> (buf, len);
|
r = std::make_shared<RouterInfo> (buf, len);
|
||||||
if (!r->IsUnreachable () && r->HasValidAddresses () && (!r->IsFloodfill () || !r->GetProfile ()->IsUnreachable ()) &&
|
bool isValid = !r->IsUnreachable () && r->HasValidAddresses () && (!r->IsFloodfill () || !r->GetProfile ()->IsUnreachable ());
|
||||||
i2p::util::GetMillisecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL > r->GetTimestamp ())
|
if (isValid)
|
||||||
|
{
|
||||||
|
auto mts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
isValid = mts + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL > r->GetTimestamp () && // from future
|
||||||
|
mts < r->GetTimestamp () + NETDB_MAX_EXPIRATION_TIMEOUT*1000LL; // too old
|
||||||
|
}
|
||||||
|
if (isValid)
|
||||||
{
|
{
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
{
|
{
|
||||||
@ -304,7 +321,7 @@ namespace data
|
|||||||
m_Floodfills.Insert (r);
|
m_Floodfills.Insert (r);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
r->ResetFlooldFill ();
|
r->ResetFloodfill ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -317,7 +334,7 @@ namespace data
|
|||||||
updated = false;
|
updated = false;
|
||||||
}
|
}
|
||||||
// take care about requested destination
|
// take care about requested destination
|
||||||
m_Requests.RequestComplete (ident, r);
|
m_Requests->RequestComplete (ident, r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,7 +446,17 @@ namespace data
|
|||||||
r->SetUnreachable (unreachable);
|
r->SetUnreachable (unreachable);
|
||||||
auto profile = r->GetProfile ();
|
auto profile = r->GetProfile ();
|
||||||
if (profile)
|
if (profile)
|
||||||
|
{
|
||||||
profile->Unreachable (unreachable);
|
profile->Unreachable (unreachable);
|
||||||
|
if (!unreachable && r->IsDeclaredFloodfill () && !r->IsFloodfill () &&
|
||||||
|
r->IsEligibleFloodfill () && profile->IsReal ())
|
||||||
|
{
|
||||||
|
// enable previously disabled floodfill
|
||||||
|
r->SetFloodfill ();
|
||||||
|
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
||||||
|
m_Floodfills.Insert (r);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,28 +478,6 @@ namespace data
|
|||||||
m_Reseeder->LoadCertificates (); // we need certificates for SU3 verification
|
m_Reseeder->LoadCertificates (); // we need certificates for SU3 verification
|
||||||
}
|
}
|
||||||
|
|
||||||
// try reseeding from floodfill first if specified
|
|
||||||
std::string riPath; i2p::config::GetOption("reseed.floodfill", riPath);
|
|
||||||
if (!riPath.empty())
|
|
||||||
{
|
|
||||||
auto ri = std::make_shared<RouterInfo>(riPath);
|
|
||||||
if (ri->IsFloodfill())
|
|
||||||
{
|
|
||||||
const uint8_t * riData = ri->GetBuffer();
|
|
||||||
int riLen = ri->GetBufferLen();
|
|
||||||
if (!i2p::data::netdb.AddRouterInfo(riData, riLen))
|
|
||||||
{
|
|
||||||
// bad router info
|
|
||||||
LogPrint(eLogError, "NetDb: Bad router info");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_FloodfillBootstrap = ri;
|
|
||||||
ReseedFromFloodfill(*ri);
|
|
||||||
// don't try reseed servers if trying to bootstrap from floodfill
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Reseeder->Bootstrap ();
|
m_Reseeder->Bootstrap ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,6 +617,17 @@ namespace data
|
|||||||
|
|
||||||
void NetDb::SaveUpdated ()
|
void NetDb::SaveUpdated ()
|
||||||
{
|
{
|
||||||
|
if (m_PersistingRouters.valid ())
|
||||||
|
{
|
||||||
|
if (m_PersistingRouters.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
|
||||||
|
m_PersistingRouters.get ();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NetDb: Can't save updated routers. Routers are being saved to disk");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0;
|
int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0;
|
||||||
auto total = m_RouterInfos.size ();
|
auto total = m_RouterInfos.size ();
|
||||||
auto totalFloodfills = m_Floodfills.GetSize ();
|
auto totalFloodfills = m_Floodfills.GetSize ();
|
||||||
@ -622,11 +638,14 @@ namespace data
|
|||||||
i2p::config::GetOption("limits.zombies", minTunnelCreationSuccessRate);
|
i2p::config::GetOption("limits.zombies", minTunnelCreationSuccessRate);
|
||||||
bool isLowRate = i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < minTunnelCreationSuccessRate;
|
bool isLowRate = i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < minTunnelCreationSuccessRate;
|
||||||
// routers don't expire if less than 90 or uptime is less than 1 hour
|
// routers don't expire if less than 90 or uptime is less than 1 hour
|
||||||
bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes
|
bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > NETDB_CHECK_FOR_EXPIRATION_UPTIME; // 10 minutes
|
||||||
if (checkForExpiration && uptime > 3600) // 1 hour
|
if (checkForExpiration && uptime > i2p::transport::SSU2_TO_INTRODUCER_SESSION_DURATION) // 1 hour
|
||||||
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
|
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
|
||||||
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
|
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
|
||||||
|
|
||||||
|
std::list<std::pair<std::string, std::shared_ptr<RouterInfo::Buffer> > > saveToDisk;
|
||||||
|
std::list<std::string> removeFromDisk;
|
||||||
|
|
||||||
auto own = i2p::context.GetSharedRouterInfo ();
|
auto own = i2p::context.GetSharedRouterInfo ();
|
||||||
for (auto& it: m_RouterInfos)
|
for (auto& it: m_RouterInfos)
|
||||||
{
|
{
|
||||||
@ -637,10 +656,15 @@ namespace data
|
|||||||
if (it.second->GetBuffer ())
|
if (it.second->GetBuffer ())
|
||||||
{
|
{
|
||||||
// we have something to save
|
// we have something to save
|
||||||
it.second->SaveToFile (m_Storage.Path(ident));
|
std::shared_ptr<RouterInfo::Buffer> buffer;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_RouterInfosMutex); // possible collision between DeleteBuffer and Update
|
||||||
|
buffer = it.second->GetSharedBuffer ();
|
||||||
|
it.second->DeleteBuffer ();
|
||||||
|
}
|
||||||
|
if (buffer && !it.second->IsUnreachable ()) // don't save bad router
|
||||||
|
saveToDisk.push_back(std::make_pair(ident, buffer));
|
||||||
it.second->SetUnreachable (false);
|
it.second->SetUnreachable (false);
|
||||||
std::lock_guard<std::mutex> l(m_RouterInfosMutex); // possible collision between DeleteBuffer and Update
|
|
||||||
it.second->DeleteBuffer ();
|
|
||||||
}
|
}
|
||||||
it.second->SetUpdated (false);
|
it.second->SetUpdated (false);
|
||||||
updatedCount++;
|
updatedCount++;
|
||||||
@ -681,12 +705,18 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (it.second->IsFloodfill ()) deletedFloodfillsCount++;
|
if (it.second->IsFloodfill ()) deletedFloodfillsCount++;
|
||||||
// delete RI file
|
// delete RI file
|
||||||
m_Storage.Remove(ident);
|
removeFromDisk.push_back (ident);
|
||||||
deletedCount++;
|
deletedCount++;
|
||||||
if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
|
if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
|
||||||
}
|
}
|
||||||
} // m_RouterInfos iteration
|
} // m_RouterInfos iteration
|
||||||
|
|
||||||
|
if (!saveToDisk.empty () || !removeFromDisk.empty ())
|
||||||
|
{
|
||||||
|
m_PersistingRouters = std::async (std::launch::async, &NetDb::PersistRouters,
|
||||||
|
this, std::move (saveToDisk), std::move (removeFromDisk));
|
||||||
|
}
|
||||||
|
|
||||||
m_RouterInfoBuffersPool.CleanUpMt ();
|
m_RouterInfoBuffersPool.CleanUpMt ();
|
||||||
m_RouterInfoAddressesPool.CleanUpMt ();
|
m_RouterInfoAddressesPool.CleanUpMt ();
|
||||||
m_RouterInfoAddressVectorsPool.CleanUpMt ();
|
m_RouterInfoAddressVectorsPool.CleanUpMt ();
|
||||||
@ -722,66 +752,22 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetDb::PersistRouters (std::list<std::pair<std::string, std::shared_ptr<RouterInfo::Buffer> > >&& update,
|
||||||
|
std::list<std::string>&& remove)
|
||||||
|
{
|
||||||
|
for (auto it: update)
|
||||||
|
RouterInfo::SaveToFile (m_Storage.Path(it.first), it.second);
|
||||||
|
for (auto it: remove)
|
||||||
|
m_Storage.Remove (it);
|
||||||
|
}
|
||||||
|
|
||||||
void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete, bool direct)
|
void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete, bool direct)
|
||||||
{
|
{
|
||||||
if (direct && i2p::transport::transports.RoutesRestricted ()) direct = false; // always use tunnels for restricted routes
|
if (direct && i2p::transport::transports.RoutesRestricted ()) direct = false; // always use tunnels for restricted routes
|
||||||
auto dest = m_Requests.CreateRequest (destination, false, direct, requestComplete); // non-exploratory
|
if (m_Requests)
|
||||||
if (!dest)
|
m_Requests->PostRequestDestination (destination, requestComplete, direct);
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
|
|
||||||
if (floodfill)
|
|
||||||
{
|
|
||||||
if (direct && !floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
|
|
||||||
!i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
|
|
||||||
direct = false; // floodfill can't be reached directly
|
|
||||||
if (direct)
|
|
||||||
{
|
|
||||||
auto msg = dest->CreateRequestMessage (floodfill->GetIdentHash ());
|
|
||||||
msg->onDrop = [this, dest]() { this->m_Requests.SendNextRequest (dest); };
|
|
||||||
transports.SendMessage (floodfill->GetIdentHash (), msg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
|
||||||
auto outbound = pool ? pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
|
|
||||||
auto inbound = pool ? pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
|
|
||||||
if (outbound && inbound)
|
|
||||||
{
|
|
||||||
auto msg = dest->CreateRequestMessage (floodfill, inbound);
|
|
||||||
msg->onDrop = [this, dest]() { this->m_Requests.SendNextRequest (dest); };
|
|
||||||
outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0,
|
|
||||||
i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found");
|
|
||||||
m_Requests.RequestComplete (destination, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
LogPrint (eLogError, "NetDb: Requests is null");
|
||||||
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no floodfills found");
|
|
||||||
m_Requests.RequestComplete (destination, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploratory, RequestedDestination::RequestComplete requestComplete)
|
|
||||||
{
|
|
||||||
|
|
||||||
auto dest = m_Requests.CreateRequest (destination, exploratory, true, requestComplete); // non-exploratory
|
|
||||||
if (!dest)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LogPrint(eLogInfo, "NetDb: Destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64());
|
|
||||||
// direct
|
|
||||||
transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m)
|
void NetDb::HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m)
|
||||||
@ -926,61 +912,16 @@ namespace data
|
|||||||
{
|
{
|
||||||
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + payloadOffset, msgLen);
|
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + payloadOffset, msgLen);
|
||||||
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
|
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
|
||||||
Flood (ident, floodMsg);
|
int minutesBeforeMidnight = 24*60 - i2p::util::GetMinutesSinceEpoch () % (24*60);
|
||||||
|
bool andNextDay = storeType ? minutesBeforeMidnight < NETDB_NEXT_DAY_LEASESET_THRESHOLD:
|
||||||
|
minutesBeforeMidnight < NETDB_NEXT_DAY_ROUTER_INFO_THRESHOLD;
|
||||||
|
Flood (ident, floodMsg, andNextDay);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "NetDb: Database store message is too long ", floodMsg->len);
|
LogPrint (eLogError, "NetDb: Database store message is too long ", floodMsg->len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
|
|
||||||
{
|
|
||||||
const uint8_t * buf = msg->GetPayload ();
|
|
||||||
char key[48];
|
|
||||||
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
|
|
||||||
key[l] = 0;
|
|
||||||
int num = buf[32]; // num
|
|
||||||
LogPrint (eLogDebug, "NetDb: DatabaseSearchReply for ", key, " num=", num);
|
|
||||||
IdentHash ident (buf);
|
|
||||||
auto dest = m_Requests.FindRequest (ident);
|
|
||||||
if (dest)
|
|
||||||
{
|
|
||||||
if (num > 0)
|
|
||||||
// try to send next requests
|
|
||||||
m_Requests.SendNextRequest (dest);
|
|
||||||
else
|
|
||||||
// no more requests for destination possible. delete it
|
|
||||||
m_Requests.RequestComplete (ident, nullptr);
|
|
||||||
}
|
|
||||||
else if(!m_FloodfillBootstrap)
|
|
||||||
LogPrint (eLogWarning, "NetDb: Requested destination for ", key, " not found");
|
|
||||||
|
|
||||||
// try responses
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
const uint8_t * router = buf + 33 + i*32;
|
|
||||||
char peerHash[48];
|
|
||||||
int l1 = i2p::data::ByteStreamToBase64 (router, 32, peerHash, 48);
|
|
||||||
peerHash[l1] = 0;
|
|
||||||
LogPrint (eLogDebug, "NetDb: ", i, ": ", peerHash);
|
|
||||||
|
|
||||||
auto r = FindRouter (router);
|
|
||||||
if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
|
|
||||||
{
|
|
||||||
// router with ident not found or too old (1 hour)
|
|
||||||
LogPrint (eLogDebug, "NetDb: Found new/outdated router. Requesting RouterInfo...");
|
|
||||||
if(m_FloodfillBootstrap)
|
|
||||||
RequestDestinationFrom(router, m_FloodfillBootstrap->GetIdentHash(), true);
|
|
||||||
else if (!IsRouterBanned (router))
|
|
||||||
RequestDestination (router);
|
|
||||||
else
|
|
||||||
LogPrint (eLogDebug, "NetDb: Router ", peerHash, " is banned. Skipped");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint (eLogDebug, "NetDb: [:|||:]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetDb::HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg)
|
void NetDb::HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
const uint8_t * buf = msg->GetPayload ();
|
const uint8_t * buf = msg->GetPayload ();
|
||||||
@ -1024,24 +965,15 @@ namespace data
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded");
|
LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded");
|
||||||
std::set<IdentHash> excludedRouters;
|
std::unordered_set<IdentHash> excludedRouters;
|
||||||
const uint8_t * excluded_ident = excluded;
|
const uint8_t * excluded_ident = excluded;
|
||||||
for (int i = 0; i < numExcluded; i++)
|
for (int i = 0; i < numExcluded; i++)
|
||||||
{
|
{
|
||||||
excludedRouters.insert (excluded_ident);
|
excludedRouters.insert (excluded_ident);
|
||||||
excluded_ident += 32;
|
excluded_ident += 32;
|
||||||
}
|
}
|
||||||
std::vector<IdentHash> routers;
|
replyMsg = CreateDatabaseSearchReply (ident, GetExploratoryNonFloodfill (ident,
|
||||||
for (int i = 0; i < 3; i++)
|
NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES, excludedRouters));
|
||||||
{
|
|
||||||
auto r = GetClosestNonFloodfill (ident, excludedRouters);
|
|
||||||
if (r)
|
|
||||||
{
|
|
||||||
routers.push_back (r->GetIdentHash ());
|
|
||||||
excludedRouters.insert (r->GetIdentHash ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
replyMsg = CreateDatabaseSearchReply (ident, routers);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1085,16 +1017,16 @@ namespace data
|
|||||||
|
|
||||||
if (!replyMsg)
|
if (!replyMsg)
|
||||||
{
|
{
|
||||||
std::set<IdentHash> excludedRouters;
|
std::unordered_set<IdentHash> excludedRouters;
|
||||||
const uint8_t * exclude_ident = excluded;
|
const uint8_t * exclude_ident = excluded;
|
||||||
for (int i = 0; i < numExcluded; i++)
|
for (int i = 0; i < numExcluded; i++)
|
||||||
{
|
{
|
||||||
excludedRouters.insert (exclude_ident);
|
excludedRouters.insert (exclude_ident);
|
||||||
exclude_ident += 32;
|
exclude_ident += 32;
|
||||||
}
|
}
|
||||||
auto closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true);
|
auto closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, false);
|
||||||
if (closestFloodfills.empty ())
|
if (closestFloodfills.empty ())
|
||||||
LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
|
LogPrint (eLogWarning, "NetDb: No more floodfills for ", key, " found. ", numExcluded, " peers excluded");
|
||||||
replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
|
replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1152,74 +1084,43 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::Explore (int numDestinations)
|
void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg, bool andNextDay)
|
||||||
{
|
{
|
||||||
// new requests
|
std::unordered_set<IdentHash> excluded;
|
||||||
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
|
||||||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
|
|
||||||
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
|
|
||||||
bool throughTunnels = outbound && inbound;
|
|
||||||
|
|
||||||
uint8_t randomHash[32];
|
|
||||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
|
||||||
LogPrint (eLogInfo, "NetDb: Exploring new ", numDestinations, " routers ...");
|
|
||||||
for (int i = 0; i < numDestinations; i++)
|
|
||||||
{
|
|
||||||
RAND_bytes (randomHash, 32);
|
|
||||||
auto dest = m_Requests.CreateRequest (randomHash, true, !throughTunnels); // exploratory
|
|
||||||
if (!dest)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "NetDb: Exploratory destination is requested already");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
|
|
||||||
if (floodfill)
|
|
||||||
{
|
|
||||||
if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
|
|
||||||
throughTunnels = false;
|
|
||||||
if (throughTunnels)
|
|
||||||
{
|
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
|
||||||
{
|
|
||||||
i2p::tunnel::eDeliveryTypeRouter,
|
|
||||||
floodfill->GetIdentHash (), 0,
|
|
||||||
CreateDatabaseStoreMsg () // tell floodfill about us
|
|
||||||
});
|
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
|
||||||
{
|
|
||||||
i2p::tunnel::eDeliveryTypeRouter,
|
|
||||||
floodfill->GetIdentHash (), 0,
|
|
||||||
dest->CreateRequestMessage (floodfill, inbound) // explore
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_Requests.RequestComplete (randomHash, nullptr);
|
|
||||||
}
|
|
||||||
if (throughTunnels && msgs.size () > 0)
|
|
||||||
outbound->SendTunnelDataMsgs (msgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg)
|
|
||||||
{
|
|
||||||
std::set<IdentHash> excluded;
|
|
||||||
excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself
|
excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself
|
||||||
excluded.insert (ident); // don't flood back
|
excluded.insert (ident); // don't flood back
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
auto floodfill = GetClosestFloodfill (ident, excluded);
|
auto floodfill = GetClosestFloodfill (ident, excluded, false); // current day
|
||||||
if (floodfill)
|
if (floodfill)
|
||||||
{
|
{
|
||||||
auto h = floodfill->GetIdentHash();
|
const auto& h = floodfill->GetIdentHash();
|
||||||
LogPrint(eLogDebug, "NetDb: Flood lease set for ", ident.ToBase32(), " to ", h.ToBase64());
|
|
||||||
transports.SendMessage (h, CopyI2NPMessage(floodMsg));
|
transports.SendMessage (h, CopyI2NPMessage(floodMsg));
|
||||||
excluded.insert (h);
|
excluded.insert (h);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
return; // no more floodfills
|
||||||
}
|
}
|
||||||
|
if (andNextDay)
|
||||||
|
{
|
||||||
|
// flood to two more closest flodfills for next day
|
||||||
|
std::unordered_set<IdentHash> excluded1;
|
||||||
|
excluded1.insert (i2p::context.GetIdentHash ()); // don't flood to itself
|
||||||
|
excluded1.insert (ident); // don't flood back
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
auto floodfill = GetClosestFloodfill (ident, excluded1, true); // next day
|
||||||
|
if (floodfill)
|
||||||
|
{
|
||||||
|
const auto& h = floodfill->GetIdentHash();
|
||||||
|
if (!excluded.count (h)) // we didn't send for current day, otherwise skip
|
||||||
|
transports.SendMessage (h, CopyI2NPMessage(floodMsg));
|
||||||
|
excluded1.insert (h);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter () const
|
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter () const
|
||||||
@ -1239,13 +1140,13 @@ namespace data
|
|||||||
{
|
{
|
||||||
return !router->IsHidden () && router != compatibleWith &&
|
return !router->IsHidden () && router != compatibleWith &&
|
||||||
(reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)):
|
(reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)):
|
||||||
router->IsReachableFrom (*compatibleWith)) &&
|
router->IsReachableFrom (*compatibleWith)) && !router->IsNAT2NATOnly (*compatibleWith) &&
|
||||||
router->IsECIES () && !router->IsHighCongestion (false) &&
|
router->IsECIES () && !router->IsHighCongestion (false) &&
|
||||||
(!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
|
(!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const
|
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2PeerTestRouter (bool v4, const std::unordered_set<IdentHash>& excluded) const
|
||||||
{
|
{
|
||||||
return GetRandomRouter (
|
return GetRandomRouter (
|
||||||
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
||||||
@ -1255,7 +1156,7 @@ namespace data
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const
|
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2Introducer (bool v4, const std::unordered_set<IdentHash>& excluded) const
|
||||||
{
|
{
|
||||||
return GetRandomRouter (
|
return GetRandomRouter (
|
||||||
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
||||||
@ -1268,15 +1169,18 @@ namespace data
|
|||||||
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith,
|
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith,
|
||||||
bool reverse, bool endpoint) const
|
bool reverse, bool endpoint) const
|
||||||
{
|
{
|
||||||
|
bool checkIsReal = i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < NETDB_TUNNEL_CREATION_RATE_THRESHOLD && // too low rate
|
||||||
|
context.GetUptime () > NETDB_CHECK_FOR_EXPIRATION_UPTIME; // after 10 minutes uptime
|
||||||
return GetRandomRouter (
|
return GetRandomRouter (
|
||||||
[compatibleWith, reverse, endpoint](std::shared_ptr<const RouterInfo> router)->bool
|
[compatibleWith, reverse, endpoint, checkIsReal](std::shared_ptr<const RouterInfo> router)->bool
|
||||||
{
|
{
|
||||||
return !router->IsHidden () && router != compatibleWith &&
|
return !router->IsHidden () && router != compatibleWith &&
|
||||||
(reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)) :
|
(reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)) :
|
||||||
router->IsReachableFrom (*compatibleWith)) &&
|
router->IsReachableFrom (*compatibleWith)) && !router->IsNAT2NATOnly (*compatibleWith) &&
|
||||||
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
|
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
|
||||||
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
|
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
|
||||||
router->IsECIES () && !router->IsHighCongestion (true) &&
|
router->IsECIES () && !router->IsHighCongestion (true) &&
|
||||||
|
(!checkIsReal || router->GetProfile ()->IsReal ()) &&
|
||||||
(!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
|
(!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -1347,10 +1251,16 @@ namespace data
|
|||||||
if (msg) m_Queue.Put (msg);
|
if (msg) m_Queue.Put (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
|
void NetDb::PostDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
|
||||||
const std::set<IdentHash>& excluded) const
|
|
||||||
{
|
{
|
||||||
IdentHash destKey = CreateRoutingKey (destination);
|
if (msg && m_Requests)
|
||||||
|
m_Requests->PostDatabaseSearchReplyMsg (msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
|
||||||
|
const std::unordered_set<IdentHash>& excluded, bool nextDay) const
|
||||||
|
{
|
||||||
|
IdentHash destKey = CreateRoutingKey (destination, nextDay);
|
||||||
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
||||||
return m_Floodfills.FindClosest (destKey, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
|
return m_Floodfills.FindClosest (destKey, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
|
||||||
{
|
{
|
||||||
@ -1360,7 +1270,7 @@ namespace data
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
|
std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
|
||||||
std::set<IdentHash>& excluded, bool closeThanUsOnly) const
|
std::unordered_set<IdentHash>& excluded, bool closeThanUsOnly) const
|
||||||
{
|
{
|
||||||
std::vector<IdentHash> res;
|
std::vector<IdentHash> res;
|
||||||
IdentHash destKey = CreateRoutingKey (destination);
|
IdentHash destKey = CreateRoutingKey (destination);
|
||||||
@ -1394,27 +1304,63 @@ namespace data
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetClosestNonFloodfill (const IdentHash& destination,
|
std::vector<IdentHash> NetDb::GetExploratoryNonFloodfill (const IdentHash& destination,
|
||||||
const std::set<IdentHash>& excluded) const
|
size_t num, const std::unordered_set<IdentHash>& excluded)
|
||||||
{
|
{
|
||||||
std::shared_ptr<const RouterInfo> r;
|
std::vector<IdentHash> ret;
|
||||||
XORMetric minMetric;
|
if (!num || m_RouterInfos.empty ()) return ret; // empty list
|
||||||
IdentHash destKey = CreateRoutingKey (destination);
|
auto ts = i2p::util::GetMonotonicSeconds ();
|
||||||
minMetric.SetMax ();
|
if (ts > m_LastExploratorySelectionUpdateTime + NETDB_EXPLORATORY_SELECTION_UPDATE_INTERVAL)
|
||||||
// must be called from NetDb thread only
|
|
||||||
for (const auto& it: m_RouterInfos)
|
|
||||||
{
|
{
|
||||||
if (!it.second->IsFloodfill ())
|
// update selection
|
||||||
|
m_ExploratorySelection.clear ();
|
||||||
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
|
std::vector<std::shared_ptr<const RouterInfo> > eligible;
|
||||||
|
eligible.reserve (m_RouterInfos.size ());
|
||||||
|
#else
|
||||||
|
auto& eligible = m_ExploratorySelection;
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
XORMetric m = destKey ^ it.first;
|
// collect eligible from current netdb
|
||||||
if (m < minMetric && !excluded.count (it.first))
|
bool checkIsReal = i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < NETDB_TUNNEL_CREATION_RATE_THRESHOLD; // too low rate
|
||||||
{
|
std::lock_guard<std::mutex> l(m_RouterInfosMutex);
|
||||||
minMetric = m;
|
for (const auto& it: m_RouterInfos)
|
||||||
r = it.second;
|
if (!it.second->IsDeclaredFloodfill () &&
|
||||||
}
|
(!checkIsReal || (it.second->HasProfile () && it.second->GetProfile ()->IsReal ())))
|
||||||
|
eligible.push_back (it.second);
|
||||||
}
|
}
|
||||||
}
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
return r;
|
if (eligible.size () > NETDB_MAX_EXPLORATORY_SELECTION_SIZE)
|
||||||
|
{
|
||||||
|
std::sample (eligible.begin(), eligible.end(), std::back_inserter(m_ExploratorySelection),
|
||||||
|
NETDB_MAX_EXPLORATORY_SELECTION_SIZE, std::mt19937(ts));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
std::swap (m_ExploratorySelection, eligible);
|
||||||
|
#else
|
||||||
|
if (m_ExploratorySelection.size () > NETDB_MAX_EXPLORATORY_SELECTION_SIZE)
|
||||||
|
{
|
||||||
|
// reduce number of eligible to max selection size
|
||||||
|
std::shuffle (m_ExploratorySelection.begin(), m_ExploratorySelection.end(), std::mt19937(ts));
|
||||||
|
m_ExploratorySelection.resize (NETDB_MAX_EXPLORATORY_SELECTION_SIZE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
m_LastExploratorySelectionUpdateTime = ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort by distance
|
||||||
|
IdentHash destKey = CreateRoutingKey (destination);
|
||||||
|
std::map<XORMetric, std::shared_ptr<const RouterInfo> > sorted;
|
||||||
|
for (const auto& it: m_ExploratorySelection)
|
||||||
|
if (!excluded.count (it->GetIdentHash ()))
|
||||||
|
sorted.emplace (destKey ^ it->GetIdentHash (), it);
|
||||||
|
// return first num closest routers
|
||||||
|
for (const auto& it: sorted)
|
||||||
|
{
|
||||||
|
ret.push_back (it.second->GetIdentHash ());
|
||||||
|
if (ret.size () >= num) break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::ManageRouterInfos ()
|
void NetDb::ManageRouterInfos ()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -10,11 +10,12 @@
|
|||||||
#define NETDB_H__
|
#define NETDB_H__
|
||||||
// this file is called NetDb.hpp to resolve conflict with libc's netdb.h on case insensitive fs
|
// this file is called NetDb.hpp to resolve conflict with libc's netdb.h on case insensitive fs
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <set>
|
#include <unordered_set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "Gzip.h"
|
#include "Gzip.h"
|
||||||
@ -38,16 +39,23 @@ namespace data
|
|||||||
{
|
{
|
||||||
const int NETDB_MIN_ROUTERS = 90;
|
const int NETDB_MIN_ROUTERS = 90;
|
||||||
const int NETDB_MIN_FLOODFILLS = 5;
|
const int NETDB_MIN_FLOODFILLS = 5;
|
||||||
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1500;
|
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1200;
|
||||||
const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD;
|
const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD;
|
||||||
|
const int NETDB_TUNNEL_CREATION_RATE_THRESHOLD = 10; // in %
|
||||||
|
const int NETDB_CHECK_FOR_EXPIRATION_UPTIME = 600; // 10 minutes, in seconds
|
||||||
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
|
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
|
||||||
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
|
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
|
||||||
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
|
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
|
||||||
const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days
|
const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days
|
||||||
const int NETDB_EXPIRATION_TIMEOUT_THRESHOLD = 2*60; // 2 minutes
|
const int NETDB_EXPIRATION_TIMEOUT_THRESHOLD = 2*60; // 2 minutes
|
||||||
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 58); // 0.9.58
|
||||||
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 59); // 0.9.59
|
||||||
const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
||||||
|
const size_t NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES = 16;
|
||||||
|
const size_t NETDB_MAX_EXPLORATORY_SELECTION_SIZE = 500;
|
||||||
|
const int NETDB_EXPLORATORY_SELECTION_UPDATE_INTERVAL = 82; // in seconds. for floodfill
|
||||||
|
const int NETDB_NEXT_DAY_ROUTER_INFO_THRESHOLD = 45; // in minutes
|
||||||
|
const int NETDB_NEXT_DAY_LEASESET_THRESHOLD = 10; // in minutes
|
||||||
|
|
||||||
/** function for visiting a leaseset stored in a floodfill */
|
/** function for visiting a leaseset stored in a floodfill */
|
||||||
typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor;
|
typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor;
|
||||||
@ -77,27 +85,22 @@ namespace data
|
|||||||
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
|
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
|
||||||
|
|
||||||
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr, bool direct = true);
|
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr, bool direct = true);
|
||||||
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
|
|
||||||
|
|
||||||
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
|
|
||||||
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
|
||||||
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
|
|
||||||
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
||||||
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
|
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::unordered_set<IdentHash>& excluded) const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
|
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::unordered_set<IdentHash>& excluded) const;
|
||||||
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::unordered_set<IdentHash>& excluded, bool nextDay = false) const;
|
||||||
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
|
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
|
||||||
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
std::unordered_set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
||||||
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
std::vector<IdentHash> GetExploratoryNonFloodfill (const IdentHash& destination, size_t num, const std::unordered_set<IdentHash>& excluded);
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
|
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
|
||||||
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
||||||
void ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports);
|
void ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports);
|
||||||
|
|
||||||
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
|
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
void PostDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg); // to NetdbReq thread
|
||||||
|
|
||||||
void Reseed ();
|
void Reseed ();
|
||||||
Families& GetFamilies () { return m_Families; };
|
Families& GetFamilies () { return m_Families; };
|
||||||
@ -117,7 +120,11 @@ namespace data
|
|||||||
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
|
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
|
||||||
|
|
||||||
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
||||||
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
|
template<typename... TArgs>
|
||||||
|
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer (TArgs&&... args)
|
||||||
|
{
|
||||||
|
return m_RouterInfoBuffersPool.AcquireSharedMt (std::forward<TArgs>(args)...);
|
||||||
|
}
|
||||||
bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
|
bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
|
||||||
std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); };
|
std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); };
|
||||||
boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses ()
|
boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses ()
|
||||||
@ -131,16 +138,15 @@ namespace data
|
|||||||
std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) { return m_IdentitiesPool.AcquireSharedMt (buf, len); };
|
std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) { return m_IdentitiesPool.AcquireSharedMt (buf, len); };
|
||||||
std::shared_ptr<RouterProfile> NewRouterProfile () { return m_RouterProfilesPool.AcquireSharedMt (); };
|
std::shared_ptr<RouterProfile> NewRouterProfile () { return m_RouterProfilesPool.AcquireSharedMt (); };
|
||||||
|
|
||||||
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Load ();
|
void Load ();
|
||||||
bool LoadRouterInfo (const std::string& path, uint64_t ts);
|
bool LoadRouterInfo (const std::string& path, uint64_t ts);
|
||||||
void SaveUpdated ();
|
void SaveUpdated ();
|
||||||
void Run (); // exploratory thread
|
void PersistRouters (std::list<std::pair<std::string, std::shared_ptr<RouterInfo::Buffer> > >&& update,
|
||||||
void Explore (int numDestinations);
|
std::list<std::string>&& remove);
|
||||||
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg);
|
void Run ();
|
||||||
|
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg, bool andNextDay = false);
|
||||||
void ManageRouterInfos ();
|
void ManageRouterInfos ();
|
||||||
void ManageLeaseSets ();
|
void ManageLeaseSets ();
|
||||||
void ManageRequests ();
|
void ManageRequests ();
|
||||||
@ -153,6 +159,10 @@ namespace data
|
|||||||
template<typename Filter>
|
template<typename Filter>
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
|
||||||
|
|
||||||
|
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
mutable std::mutex m_LeaseSetsMutex;
|
mutable std::mutex m_LeaseSetsMutex;
|
||||||
@ -171,16 +181,13 @@ namespace data
|
|||||||
Families m_Families;
|
Families m_Families;
|
||||||
i2p::fs::HashedStorage m_Storage;
|
i2p::fs::HashedStorage m_Storage;
|
||||||
|
|
||||||
friend class NetDbRequests;
|
std::shared_ptr<NetDbRequests> m_Requests;
|
||||||
NetDbRequests m_Requests;
|
|
||||||
|
|
||||||
bool m_PersistProfiles;
|
bool m_PersistProfiles;
|
||||||
|
std::future<void> m_SavingProfiles, m_DeletingProfiles, m_PersistingRouters;
|
||||||
|
|
||||||
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
|
std::vector<std::shared_ptr<const RouterInfo> > m_ExploratorySelection;
|
||||||
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
|
uint64_t m_LastExploratorySelectionUpdateTime; // in monotonic seconds
|
||||||
|
|
||||||
std::set<IdentHash> m_PublishExcluded;
|
|
||||||
uint32_t m_PublishReplyToken = 0;
|
|
||||||
|
|
||||||
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
|
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
|
||||||
i2p::util::MemoryPoolMt<RouterInfo::Address> m_RouterInfoAddressesPool;
|
i2p::util::MemoryPoolMt<RouterInfo::Address> m_RouterInfoAddressesPool;
|
||||||
|
@ -10,22 +10,26 @@
|
|||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
#include "NetDb.hpp"
|
#include "NetDb.hpp"
|
||||||
#include "NetDbRequests.h"
|
|
||||||
#include "ECIESX25519AEADRatchetSession.h"
|
#include "ECIESX25519AEADRatchetSession.h"
|
||||||
|
#include "RouterContext.h"
|
||||||
|
#include "Timestamp.h"
|
||||||
|
#include "NetDbRequests.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct):
|
RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct):
|
||||||
m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct),
|
m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_IsActive (true),
|
||||||
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_LastRequestTime (0)
|
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_LastRequestTime (0), m_NumAttempts (0)
|
||||||
{
|
{
|
||||||
|
if (i2p::context.IsFloodfill ())
|
||||||
|
m_ExcludedPeers.insert (i2p::context.GetIdentHash ()); // exclude self if floodfill
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestedDestination::~RequestedDestination ()
|
RequestedDestination::~RequestedDestination ()
|
||||||
{
|
{
|
||||||
if (m_RequestComplete) m_RequestComplete (nullptr);
|
InvokeRequestComplete (nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
|
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
|
||||||
@ -41,6 +45,7 @@ namespace data
|
|||||||
if(router)
|
if(router)
|
||||||
m_ExcludedPeers.insert (router->GetIdentHash ());
|
m_ExcludedPeers.insert (router->GetIdentHash ());
|
||||||
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch ();
|
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
m_NumAttempts++;
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,101 +54,154 @@ namespace data
|
|||||||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||||
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
||||||
m_ExcludedPeers.insert (floodfill);
|
m_ExcludedPeers.insert (floodfill);
|
||||||
|
m_NumAttempts++;
|
||||||
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch ();
|
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RequestedDestination::IsExcluded (const IdentHash& ident) const
|
||||||
|
{
|
||||||
|
return m_ExcludedPeers.count (ident);
|
||||||
|
}
|
||||||
|
|
||||||
void RequestedDestination::ClearExcludedPeers ()
|
void RequestedDestination::ClearExcludedPeers ()
|
||||||
{
|
{
|
||||||
m_ExcludedPeers.clear ();
|
m_ExcludedPeers.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RequestedDestination::InvokeRequestComplete (std::shared_ptr<RouterInfo> r)
|
||||||
|
{
|
||||||
|
if (!m_RequestComplete.empty ())
|
||||||
|
{
|
||||||
|
for (auto it: m_RequestComplete)
|
||||||
|
if (it != nullptr) it (r);
|
||||||
|
m_RequestComplete.clear ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
|
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
|
||||||
{
|
{
|
||||||
if (m_RequestComplete)
|
if (m_IsActive)
|
||||||
{
|
{
|
||||||
m_RequestComplete (r);
|
m_IsActive = false;
|
||||||
m_RequestComplete = nullptr;
|
InvokeRequestComplete (r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestedDestination::Fail ()
|
void RequestedDestination::Fail ()
|
||||||
{
|
{
|
||||||
if (m_RequestComplete)
|
if (m_IsActive)
|
||||||
{
|
{
|
||||||
m_RequestComplete (nullptr);
|
m_IsActive = false;
|
||||||
m_RequestComplete = nullptr;
|
InvokeRequestComplete (nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetDbRequests::NetDbRequests ():
|
||||||
|
RunnableServiceWithWork ("NetDbReq"),
|
||||||
|
m_ManageRequestsTimer (GetIOService ()), m_ExploratoryTimer (GetIOService ()),
|
||||||
|
m_CleanupTimer (GetIOService ()), m_DiscoveredRoutersTimer (GetIOService ()),
|
||||||
|
m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NetDbRequests::~NetDbRequests ()
|
||||||
|
{
|
||||||
|
Stop ();
|
||||||
|
}
|
||||||
|
|
||||||
void NetDbRequests::Start ()
|
void NetDbRequests::Start ()
|
||||||
{
|
{
|
||||||
|
if (!IsRunning ())
|
||||||
|
{
|
||||||
|
StartIOService ();
|
||||||
|
ScheduleManageRequests ();
|
||||||
|
ScheduleCleanup ();
|
||||||
|
if (!i2p::context.IsHidden ())
|
||||||
|
ScheduleExploratory (EXPLORATORY_REQUEST_INTERVAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDbRequests::Stop ()
|
void NetDbRequests::Stop ()
|
||||||
{
|
{
|
||||||
m_RequestedDestinations.clear ();
|
if (IsRunning ())
|
||||||
|
{
|
||||||
|
m_ManageRequestsTimer.cancel ();
|
||||||
|
m_ExploratoryTimer.cancel ();
|
||||||
|
m_CleanupTimer.cancel ();
|
||||||
|
StopIOService ();
|
||||||
|
|
||||||
|
m_RequestedDestinations.clear ();
|
||||||
|
m_RequestedDestinationsPool.CleanUpMt ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::ScheduleCleanup ()
|
||||||
|
{
|
||||||
|
m_CleanupTimer.expires_from_now (boost::posix_time::seconds(REQUESTED_DESTINATIONS_POOL_CLEANUP_INTERVAL));
|
||||||
|
m_CleanupTimer.async_wait (std::bind (&NetDbRequests::HandleCleanupTimer,
|
||||||
|
this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::HandleCleanupTimer (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
m_RequestedDestinationsPool.CleanUpMt ();
|
||||||
|
ScheduleCleanup ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination,
|
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination,
|
||||||
bool isExploratory, bool direct, RequestedDestination::RequestComplete requestComplete)
|
bool isExploratory, bool direct, RequestedDestination::RequestComplete requestComplete)
|
||||||
{
|
{
|
||||||
// request RouterInfo directly
|
// request RouterInfo directly
|
||||||
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory, direct);
|
auto dest = m_RequestedDestinationsPool.AcquireSharedMt (destination, isExploratory, direct);
|
||||||
dest->SetRequestComplete (requestComplete);
|
if (requestComplete)
|
||||||
{
|
dest->AddRequestComplete (requestComplete);
|
||||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
|
||||||
auto ret = m_RequestedDestinations.emplace (destination, dest);
|
auto ret = m_RequestedDestinations.emplace (destination, dest);
|
||||||
if (!ret.second) // not inserted
|
if (!ret.second) // not inserted
|
||||||
|
{
|
||||||
|
dest->ResetRequestComplete (); // don't call requestComplete in destructor
|
||||||
|
dest = ret.first->second; // existing one
|
||||||
|
if (requestComplete)
|
||||||
{
|
{
|
||||||
dest->SetRequestComplete (nullptr); // don't call requestComplete in destructor
|
if (dest->IsActive ())
|
||||||
if (requestComplete)
|
dest->AddRequestComplete (requestComplete);
|
||||||
{
|
else
|
||||||
auto prev = ret.first->second->GetRequestComplete ();
|
requestComplete (nullptr);
|
||||||
if (prev) // if already set
|
|
||||||
ret.first->second->SetRequestComplete (
|
|
||||||
[requestComplete, prev](std::shared_ptr<RouterInfo> r)
|
|
||||||
{
|
|
||||||
prev (r); // call previous
|
|
||||||
requestComplete (r); // then new
|
|
||||||
});
|
|
||||||
else
|
|
||||||
ret.first->second->SetRequestComplete (requestComplete);
|
|
||||||
}
|
|
||||||
if (i2p::util::GetSecondsSinceEpoch () > ret.first->second->GetLastRequestTime () + MIN_REQUEST_TIME)
|
|
||||||
if (!SendNextRequest (ret.first->second)) // try next floodfill
|
|
||||||
m_RequestedDestinations.erase (ret.first); // delete request if failed
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
return nullptr;
|
||||||
|
}
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r)
|
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r)
|
||||||
{
|
{
|
||||||
std::shared_ptr<RequestedDestination> request;
|
GetIOService ().post ([this, ident, r]()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
std::shared_ptr<RequestedDestination> request;
|
||||||
auto it = m_RequestedDestinations.find (ident);
|
auto it = m_RequestedDestinations.find (ident);
|
||||||
if (it != m_RequestedDestinations.end ())
|
if (it != m_RequestedDestinations.end ())
|
||||||
{
|
{
|
||||||
request = it->second;
|
request = it->second;
|
||||||
m_RequestedDestinations.erase (it);
|
if (request->IsExploratory ())
|
||||||
}
|
m_RequestedDestinations.erase (it);
|
||||||
}
|
// otherwise cache for a while
|
||||||
if (request)
|
}
|
||||||
{
|
if (request)
|
||||||
if (r)
|
{
|
||||||
request->Success (r);
|
if (r)
|
||||||
else
|
request->Success (r);
|
||||||
request->Fail ();
|
else
|
||||||
}
|
request->Fail ();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
|
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
|
||||||
auto it = m_RequestedDestinations.find (ident);
|
auto it = m_RequestedDestinations.find (ident);
|
||||||
if (it != m_RequestedDestinations.end ())
|
if (it != m_RequestedDestinations.end ())
|
||||||
return it->second;
|
return it->second;
|
||||||
@ -153,31 +211,48 @@ namespace data
|
|||||||
void NetDbRequests::ManageRequests ()
|
void NetDbRequests::ManageRequests ()
|
||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
|
||||||
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
|
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
|
||||||
{
|
{
|
||||||
auto& dest = it->second;
|
auto& dest = it->second;
|
||||||
bool done = false;
|
if (dest->IsActive () || ts < dest->GetCreationTime () + REQUEST_CACHE_TIME)
|
||||||
if (ts < dest->GetCreationTime () + MAX_REQUEST_TIME) // request becomes worthless
|
{
|
||||||
{
|
if (!dest->IsExploratory ())
|
||||||
if (ts > dest->GetLastRequestTime () + MIN_REQUEST_TIME) // try next floodfill if no response after min interval
|
{
|
||||||
done = !SendNextRequest (dest);
|
// regular request
|
||||||
}
|
bool done = false;
|
||||||
else // delete obsolete request
|
if (ts < dest->GetCreationTime () + MAX_REQUEST_TIME)
|
||||||
done = true;
|
{
|
||||||
|
if (ts > dest->GetLastRequestTime () + MIN_REQUEST_TIME) // try next floodfill if no response after min interval
|
||||||
if (done)
|
done = !SendNextRequest (dest);
|
||||||
it = m_RequestedDestinations.erase (it);
|
}
|
||||||
|
else // request is expired
|
||||||
|
done = true;
|
||||||
|
if (done)
|
||||||
|
dest->Fail ();
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// exploratory
|
||||||
|
if (ts >= dest->GetCreationTime () + MAX_EXPLORATORY_REQUEST_TIME)
|
||||||
|
{
|
||||||
|
dest->Fail ();
|
||||||
|
it = m_RequestedDestinations.erase (it); // delete expired exploratory request right a way
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
++it;
|
it = m_RequestedDestinations.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetDbRequests::SendNextRequest (std::shared_ptr<RequestedDestination> dest)
|
bool NetDbRequests::SendNextRequest (std::shared_ptr<RequestedDestination> dest)
|
||||||
{
|
{
|
||||||
if (!dest) return false;
|
if (!dest || !dest->IsActive ()) return false;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
auto count = dest->GetExcludedPeers ().size ();
|
auto count = dest->GetNumAttempts ();
|
||||||
if (!dest->IsExploratory () && count < MAX_NUM_REQUEST_ATTEMPTS)
|
if (!dest->IsExploratory () && count < MAX_NUM_REQUEST_ATTEMPTS)
|
||||||
{
|
{
|
||||||
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||||
@ -187,47 +262,294 @@ namespace data
|
|||||||
if (direct && !nextFloodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
|
if (direct && !nextFloodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
|
||||||
!i2p::transport::transports.IsConnected (nextFloodfill->GetIdentHash ()))
|
!i2p::transport::transports.IsConnected (nextFloodfill->GetIdentHash ()))
|
||||||
direct = false; // floodfill can't be reached directly
|
direct = false; // floodfill can't be reached directly
|
||||||
|
auto s = shared_from_this ();
|
||||||
|
auto onDrop = [s, dest]()
|
||||||
|
{
|
||||||
|
if (dest->IsActive ())
|
||||||
|
{
|
||||||
|
s->GetIOService ().post ([s, dest]()
|
||||||
|
{
|
||||||
|
if (dest->IsActive ()) s->SendNextRequest (dest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
if (direct)
|
if (direct)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " directly");
|
if (CheckLogLevel (eLogDebug))
|
||||||
|
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " directly");
|
||||||
auto msg = dest->CreateRequestMessage (nextFloodfill->GetIdentHash ());
|
auto msg = dest->CreateRequestMessage (nextFloodfill->GetIdentHash ());
|
||||||
msg->onDrop = [this, dest]() { this->SendNextRequest (dest); };
|
msg->onDrop = onDrop;
|
||||||
i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), msg);
|
i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||||
auto outbound = pool->GetNextOutboundTunnel ();
|
if (pool)
|
||||||
auto inbound = pool->GetNextInboundTunnel ();
|
{
|
||||||
if (nextFloodfill && outbound && inbound)
|
auto outbound = pool->GetNextOutboundTunnel ();
|
||||||
{
|
auto inbound = pool->GetNextInboundTunnel ();
|
||||||
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " through tunnels");
|
if (nextFloodfill && outbound && inbound)
|
||||||
auto msg = dest->CreateRequestMessage (nextFloodfill, inbound);
|
{
|
||||||
msg->onDrop = [this, dest]() { this->SendNextRequest (dest); };
|
if (CheckLogLevel (eLogDebug))
|
||||||
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
|
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " through tunnels");
|
||||||
i2p::garlic::WrapECIESX25519MessageForRouter (msg, nextFloodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
auto msg = dest->CreateRequestMessage (nextFloodfill, inbound);
|
||||||
|
msg->onDrop = onDrop;
|
||||||
|
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
|
||||||
|
i2p::garlic::WrapECIESX25519MessageForRouter (msg, nextFloodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels");
|
||||||
|
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = false;
|
ret = false;
|
||||||
if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels");
|
LogPrint (eLogWarning, "NetDbReq: Exploratory pool is not ready");
|
||||||
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = false;
|
ret = false;
|
||||||
if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills");
|
LogPrint (eLogWarning, "NetDbReq: No more floodfills for ", dest->GetDestination ().ToBase64 (), " after ", count, "attempts");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!dest->IsExploratory ())
|
if (!dest->IsExploratory ())
|
||||||
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
|
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after ", MAX_NUM_REQUEST_ATTEMPTS," attempts");
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::ScheduleManageRequests ()
|
||||||
|
{
|
||||||
|
m_ManageRequestsTimer.expires_from_now (boost::posix_time::seconds(MANAGE_REQUESTS_INTERVAL));
|
||||||
|
m_ManageRequestsTimer.async_wait (std::bind (&NetDbRequests::HandleManageRequestsTimer,
|
||||||
|
this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::HandleManageRequestsTimer (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
if (i2p::tunnel::tunnels.GetExploratoryPool ()) // expolratory pool is ready?
|
||||||
|
ManageRequests ();
|
||||||
|
ScheduleManageRequests ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::PostDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
|
||||||
|
{
|
||||||
|
GetIOService ().post ([this, msg]()
|
||||||
|
{
|
||||||
|
HandleDatabaseSearchReplyMsg (msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
|
||||||
|
{
|
||||||
|
const uint8_t * buf = msg->GetPayload ();
|
||||||
|
char key[48];
|
||||||
|
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
|
||||||
|
key[l] = 0;
|
||||||
|
size_t num = buf[32]; // num
|
||||||
|
LogPrint (eLogDebug, "NetDbReq: DatabaseSearchReply for ", key, " num=", num);
|
||||||
|
IdentHash ident (buf);
|
||||||
|
bool isExploratory = false;
|
||||||
|
auto dest = FindRequest (ident);
|
||||||
|
if (dest && dest->IsActive ())
|
||||||
|
{
|
||||||
|
isExploratory = dest->IsExploratory ();
|
||||||
|
if (!isExploratory && (num > 0 || dest->GetNumAttempts () < 3)) // before 3-rd attempt might be just bad luck
|
||||||
|
{
|
||||||
|
// try to send next requests
|
||||||
|
if (!SendNextRequest (dest))
|
||||||
|
RequestComplete (ident, nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// no more requests for destination possible. delete it
|
||||||
|
RequestComplete (ident, nullptr);
|
||||||
|
}
|
||||||
|
else /*if (!m_FloodfillBootstrap)*/
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "NetDbReq: Unsolicited or late database search reply for ", key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try responses
|
||||||
|
if (num > NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NetDbReq: Too many peer hashes ", num, " in database search reply, Reduced to ", NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES);
|
||||||
|
num = NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES;
|
||||||
|
}
|
||||||
|
if (isExploratory && !m_DiscoveredRouterHashes.empty ())
|
||||||
|
{
|
||||||
|
// request outstanding routers
|
||||||
|
for (auto it: m_DiscoveredRouterHashes)
|
||||||
|
RequestRouter (it);
|
||||||
|
m_DiscoveredRouterHashes.clear ();
|
||||||
|
m_DiscoveredRoutersTimer.cancel ();
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
IdentHash router (buf + 33 + i*32);
|
||||||
|
if (CheckLogLevel (eLogDebug))
|
||||||
|
LogPrint (eLogDebug, "NetDbReq: ", i, ": ", router.ToBase64 ());
|
||||||
|
|
||||||
|
if (isExploratory)
|
||||||
|
// postpone request
|
||||||
|
m_DiscoveredRouterHashes.push_back (router);
|
||||||
|
else
|
||||||
|
// send request right a way
|
||||||
|
RequestRouter (router);
|
||||||
|
}
|
||||||
|
if (isExploratory && !m_DiscoveredRouterHashes.empty ())
|
||||||
|
ScheduleDiscoveredRoutersRequest ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::RequestRouter (const IdentHash& router)
|
||||||
|
{
|
||||||
|
auto r = netdb.FindRouter (router);
|
||||||
|
if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
|
||||||
|
{
|
||||||
|
// router with ident not found or too old (1 hour)
|
||||||
|
LogPrint (eLogDebug, "NetDbReq: Found new/outdated router. Requesting RouterInfo...");
|
||||||
|
if (!IsRouterBanned (router))
|
||||||
|
RequestDestination (router, nullptr, true);
|
||||||
|
else
|
||||||
|
LogPrint (eLogDebug, "NetDbReq: Router ", router.ToBase64 (), " is banned. Skipped");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogDebug, "NetDbReq: [:|||:]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::PostRequestDestination (const IdentHash& destination,
|
||||||
|
const RequestedDestination::RequestComplete& requestComplete, bool direct)
|
||||||
|
{
|
||||||
|
GetIOService ().post ([this, destination, requestComplete, direct]()
|
||||||
|
{
|
||||||
|
RequestDestination (destination, requestComplete, direct);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::RequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct)
|
||||||
|
{
|
||||||
|
auto dest = CreateRequest (destination, false, direct, requestComplete); // non-exploratory
|
||||||
|
if (dest)
|
||||||
|
{
|
||||||
|
if (!SendNextRequest (dest))
|
||||||
|
RequestComplete (destination, nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "NetDbReq: Destination ", destination.ToBase64(), " is requested already or cached");
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::Explore (int numDestinations)
|
||||||
|
{
|
||||||
|
// new requests
|
||||||
|
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||||
|
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
|
||||||
|
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
|
||||||
|
bool throughTunnels = outbound && inbound;
|
||||||
|
|
||||||
|
uint8_t randomHash[32];
|
||||||
|
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||||
|
LogPrint (eLogInfo, "NetDbReq: Exploring new ", numDestinations, " routers ...");
|
||||||
|
for (int i = 0; i < numDestinations; i++)
|
||||||
|
{
|
||||||
|
RAND_bytes (randomHash, 32);
|
||||||
|
auto dest = CreateRequest (randomHash, true, !throughTunnels); // exploratory
|
||||||
|
if (!dest)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NetDbReq: Exploratory destination is requested already");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto floodfill = netdb.GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
|
||||||
|
if (floodfill)
|
||||||
|
{
|
||||||
|
if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
|
||||||
|
throughTunnels = false;
|
||||||
|
if (throughTunnels)
|
||||||
|
{
|
||||||
|
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||||
|
{
|
||||||
|
i2p::tunnel::eDeliveryTypeRouter,
|
||||||
|
floodfill->GetIdentHash (), 0,
|
||||||
|
CreateDatabaseStoreMsg () // tell floodfill about us
|
||||||
|
});
|
||||||
|
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||||
|
{
|
||||||
|
i2p::tunnel::eDeliveryTypeRouter,
|
||||||
|
floodfill->GetIdentHash (), 0,
|
||||||
|
dest->CreateRequestMessage (floodfill, inbound) // explore
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
RequestComplete (randomHash, nullptr);
|
||||||
|
}
|
||||||
|
if (throughTunnels && msgs.size () > 0)
|
||||||
|
outbound->SendTunnelDataMsgs (msgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::ScheduleExploratory (uint64_t interval)
|
||||||
|
{
|
||||||
|
m_ExploratoryTimer.expires_from_now (boost::posix_time::seconds(interval));
|
||||||
|
m_ExploratoryTimer.async_wait (std::bind (&NetDbRequests::HandleExploratoryTimer,
|
||||||
|
this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::HandleExploratoryTimer (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
auto numRouters = netdb.GetNumRouters ();
|
||||||
|
auto nextExploratoryInterval = numRouters < 2500 ? (EXPLORATORY_REQUEST_INTERVAL + m_Rng () % EXPLORATORY_REQUEST_INTERVAL)/2 :
|
||||||
|
EXPLORATORY_REQUEST_INTERVAL + m_Rng () % EXPLORATORY_REQUEST_INTERVAL_VARIANCE;
|
||||||
|
if (numRouters)
|
||||||
|
{
|
||||||
|
if (i2p::transport::transports.IsOnline () && i2p::transport::transports.IsRunning ())
|
||||||
|
{
|
||||||
|
// explore only if online
|
||||||
|
numRouters = 800/numRouters;
|
||||||
|
if (numRouters < 1) numRouters = 1;
|
||||||
|
if (numRouters > 9) numRouters = 9;
|
||||||
|
Explore (numRouters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "NetDbReq: No known routers, reseed seems to be totally failed");
|
||||||
|
ScheduleExploratory (nextExploratoryInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::ScheduleDiscoveredRoutersRequest ()
|
||||||
|
{
|
||||||
|
m_DiscoveredRoutersTimer.expires_from_now (boost::posix_time::milliseconds(
|
||||||
|
DISCOVERED_REQUEST_INTERVAL + m_Rng () % DISCOVERED_REQUEST_INTERVAL_VARIANCE));
|
||||||
|
m_DiscoveredRoutersTimer.async_wait (std::bind (&NetDbRequests::HandleDiscoveredRoutersTimer,
|
||||||
|
this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDbRequests::HandleDiscoveredRoutersTimer (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
if (!m_DiscoveredRouterHashes.empty ())
|
||||||
|
{
|
||||||
|
RequestRouter (m_DiscoveredRouterHashes.front ());
|
||||||
|
m_DiscoveredRouterHashes.pop_front ();
|
||||||
|
if (!m_DiscoveredRouterHashes.empty ()) // more hashes to request
|
||||||
|
ScheduleDiscoveredRoutersRequest ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,19 +11,29 @@
|
|||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <random>
|
||||||
|
#include <unordered_set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <list>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
const size_t MAX_NUM_REQUEST_ATTEMPTS = 7;
|
const int MAX_NUM_REQUEST_ATTEMPTS = 5;
|
||||||
const uint64_t MANAGE_REQUESTS_INTERVAL = 15; // in seconds
|
const uint64_t MANAGE_REQUESTS_INTERVAL = 1; // in seconds
|
||||||
const uint64_t MIN_REQUEST_TIME = 5; // in seconds
|
const uint64_t MIN_REQUEST_TIME = 5; // in seconds
|
||||||
const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS*MANAGE_REQUESTS_INTERVAL;
|
const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS * (MIN_REQUEST_TIME + MANAGE_REQUESTS_INTERVAL);
|
||||||
|
const uint64_t EXPLORATORY_REQUEST_INTERVAL = 55; // in seconds
|
||||||
|
const uint64_t EXPLORATORY_REQUEST_INTERVAL_VARIANCE = 170; // in seconds
|
||||||
|
const uint64_t DISCOVERED_REQUEST_INTERVAL = 360; // in milliseconds
|
||||||
|
const uint64_t DISCOVERED_REQUEST_INTERVAL_VARIANCE = 540; // in milliseconds
|
||||||
|
const uint64_t MAX_EXPLORATORY_REQUEST_TIME = 30; // in seconds
|
||||||
|
const uint64_t REQUEST_CACHE_TIME = MAX_REQUEST_TIME + 40; // in seconds
|
||||||
|
const uint64_t REQUESTED_DESTINATIONS_POOL_CLEANUP_INTERVAL = 191; // in seconds
|
||||||
|
|
||||||
class RequestedDestination
|
class RequestedDestination
|
||||||
{
|
{
|
||||||
@ -35,50 +45,82 @@ namespace data
|
|||||||
~RequestedDestination ();
|
~RequestedDestination ();
|
||||||
|
|
||||||
const IdentHash& GetDestination () const { return m_Destination; };
|
const IdentHash& GetDestination () const { return m_Destination; };
|
||||||
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
|
const std::unordered_set<IdentHash>& GetExcludedPeers () const { return m_ExcludedPeers; };
|
||||||
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
|
int GetNumAttempts () const { return m_NumAttempts; };
|
||||||
void ClearExcludedPeers ();
|
void ClearExcludedPeers ();
|
||||||
bool IsExploratory () const { return m_IsExploratory; };
|
bool IsExploratory () const { return m_IsExploratory; };
|
||||||
bool IsDirect () const { return m_IsDirect; };
|
bool IsDirect () const { return m_IsDirect; };
|
||||||
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
|
bool IsActive () const { return m_IsActive; };
|
||||||
|
bool IsExcluded (const IdentHash& ident) const;
|
||||||
uint64_t GetCreationTime () const { return m_CreationTime; };
|
uint64_t GetCreationTime () const { return m_CreationTime; };
|
||||||
uint64_t GetLastRequestTime () const { return m_LastRequestTime; };
|
uint64_t GetLastRequestTime () const { return m_LastRequestTime; };
|
||||||
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
|
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
|
||||||
std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill);
|
std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill);
|
||||||
|
|
||||||
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
|
void AddRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete.push_back (requestComplete); };
|
||||||
RequestComplete GetRequestComplete () const { return m_RequestComplete; };
|
void ResetRequestComplete () { m_RequestComplete.clear (); };
|
||||||
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
|
|
||||||
void Success (std::shared_ptr<RouterInfo> r);
|
void Success (std::shared_ptr<RouterInfo> r);
|
||||||
void Fail ();
|
void Fail ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
IdentHash m_Destination;
|
void InvokeRequestComplete (std::shared_ptr<RouterInfo> r);
|
||||||
bool m_IsExploratory, m_IsDirect;
|
|
||||||
std::set<IdentHash> m_ExcludedPeers;
|
private:
|
||||||
uint64_t m_CreationTime, m_LastRequestTime; // in seconds
|
|
||||||
RequestComplete m_RequestComplete;
|
IdentHash m_Destination;
|
||||||
};
|
bool m_IsExploratory, m_IsDirect, m_IsActive;
|
||||||
|
std::unordered_set<IdentHash> m_ExcludedPeers;
|
||||||
class NetDbRequests
|
uint64_t m_CreationTime, m_LastRequestTime; // in seconds
|
||||||
{
|
std::list<RequestComplete> m_RequestComplete;
|
||||||
public:
|
int m_NumAttempts;
|
||||||
|
};
|
||||||
void Start ();
|
|
||||||
void Stop ();
|
class NetDbRequests: public std::enable_shared_from_this<NetDbRequests>,
|
||||||
|
private i2p::util::RunnableServiceWithWork
|
||||||
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory,
|
{
|
||||||
bool direct = false, RequestedDestination::RequestComplete requestComplete = nullptr);
|
public:
|
||||||
void RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r);
|
|
||||||
std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const;
|
NetDbRequests ();
|
||||||
void ManageRequests ();
|
~NetDbRequests ();
|
||||||
bool SendNextRequest (std::shared_ptr<RequestedDestination> dest);
|
|
||||||
|
void Start ();
|
||||||
|
void Stop ();
|
||||||
|
|
||||||
|
void RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r);
|
||||||
|
void PostDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
void PostRequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory,
|
||||||
|
bool direct = false, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||||
|
std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const;
|
||||||
|
bool SendNextRequest (std::shared_ptr<RequestedDestination> dest);
|
||||||
|
|
||||||
|
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
void RequestRouter (const IdentHash& router);
|
||||||
|
void RequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct);
|
||||||
|
void Explore (int numDestinations);
|
||||||
|
void ManageRequests ();
|
||||||
|
// timer
|
||||||
|
void ScheduleManageRequests ();
|
||||||
|
void HandleManageRequestsTimer (const boost::system::error_code& ecode);
|
||||||
|
void ScheduleExploratory (uint64_t interval);
|
||||||
|
void HandleExploratoryTimer (const boost::system::error_code& ecode);
|
||||||
|
void ScheduleCleanup ();
|
||||||
|
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||||
|
void ScheduleDiscoveredRoutersRequest ();
|
||||||
|
void HandleDiscoveredRoutersTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
mutable std::mutex m_RequestedDestinationsMutex;
|
|
||||||
std::unordered_map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
|
std::unordered_map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
|
||||||
|
std::list<IdentHash> m_DiscoveredRouterHashes;
|
||||||
|
i2p::util::MemoryPoolMt<RequestedDestination> m_RequestedDestinationsPool;
|
||||||
|
boost::asio::deadline_timer m_ManageRequestsTimer, m_ExploratoryTimer,
|
||||||
|
m_CleanupTimer, m_DiscoveredRoutersTimer;
|
||||||
|
std::mt19937 m_Rng;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/**
|
|
||||||
* This code is licensed under the MCGSI Public License
|
|
||||||
* Copyright 2018 Jeff Becker
|
|
||||||
*
|
|
||||||
*Kovri go write your own code
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Poly1305.h"
|
|
||||||
|
|
||||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace crypto
|
|
||||||
{
|
|
||||||
void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz)
|
|
||||||
{
|
|
||||||
Poly1305 p(key);
|
|
||||||
p.Update(buf, sz);
|
|
||||||
p.Finish(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,261 +0,0 @@
|
|||||||
/**
|
|
||||||
* This code is licensed under the MCGSI Public License
|
|
||||||
* Copyright 2018 Jeff Becker
|
|
||||||
*
|
|
||||||
* Kovri go write your own code
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBI2PD_POLY1305_H
|
|
||||||
#define LIBI2PD_POLY1305_H
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include "Crypto.h"
|
|
||||||
|
|
||||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace crypto
|
|
||||||
{
|
|
||||||
const std::size_t POLY1305_DIGEST_BYTES = 16;
|
|
||||||
const std::size_t POLY1305_DIGEST_DWORDS = 4;
|
|
||||||
const std::size_t POLY1305_KEY_BYTES = 32;
|
|
||||||
const std::size_t POLY1305_KEY_DWORDS = 8;
|
|
||||||
const std::size_t POLY1305_BLOCK_BYTES = 16;
|
|
||||||
|
|
||||||
namespace poly1305
|
|
||||||
{
|
|
||||||
struct LongBlock
|
|
||||||
{
|
|
||||||
unsigned long data[17];
|
|
||||||
operator unsigned long * ()
|
|
||||||
{
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Block
|
|
||||||
{
|
|
||||||
unsigned char data[17];
|
|
||||||
|
|
||||||
void Zero()
|
|
||||||
{
|
|
||||||
memset(data, 0, sizeof(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
operator uint8_t * ()
|
|
||||||
{
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block & operator += (const Block & other)
|
|
||||||
{
|
|
||||||
unsigned short u;
|
|
||||||
unsigned int i;
|
|
||||||
for(u = 0, i = 0; i < 17; i++)
|
|
||||||
{
|
|
||||||
u += (unsigned short) data[i] + (unsigned short) other.data[i];
|
|
||||||
data[i] = (unsigned char) u & 0xff;
|
|
||||||
u >>= 8;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block & operator %=(const LongBlock & other)
|
|
||||||
{
|
|
||||||
unsigned long u;
|
|
||||||
unsigned int i;
|
|
||||||
u = 0;
|
|
||||||
for (i = 0; i < 16; i++) {
|
|
||||||
u += other.data[i];
|
|
||||||
data[i] = (unsigned char)u & 0xff;
|
|
||||||
u >>= 8;
|
|
||||||
}
|
|
||||||
u += other.data[16];
|
|
||||||
data[16] = (unsigned char)u & 0x03;
|
|
||||||
u >>= 2;
|
|
||||||
u += (u << 2);
|
|
||||||
for (i = 0; i < 16; i++) {
|
|
||||||
u += data[i];
|
|
||||||
data[i] = (unsigned char)u & 0xff;
|
|
||||||
u >>= 8;
|
|
||||||
}
|
|
||||||
data[16] += (unsigned char)u;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block & operator = (const Block & other)
|
|
||||||
{
|
|
||||||
memcpy(data, other.data, sizeof(data));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block & operator ~ ()
|
|
||||||
{
|
|
||||||
static const Block minusp = {
|
|
||||||
0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0xfc
|
|
||||||
};
|
|
||||||
Block orig;
|
|
||||||
unsigned char neg;
|
|
||||||
unsigned int i;
|
|
||||||
orig = *this;
|
|
||||||
*this += minusp;
|
|
||||||
neg = -(data[16] >> 7);
|
|
||||||
for(i = 0; i < 17; i++)
|
|
||||||
data[i] ^= neg & (orig.data[i] ^ data[i]);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PutKey(const uint64_t * key_l)
|
|
||||||
{
|
|
||||||
const uint8_t * key = (const uint8_t*) key_l;
|
|
||||||
data[0] = key[0] & 0xff;
|
|
||||||
data[1] = key[1] & 0xff;
|
|
||||||
data[2] = key[2] & 0xff;
|
|
||||||
data[3] = key[3] & 0x0f;
|
|
||||||
data[4] = key[4] & 0xfc;
|
|
||||||
data[5] = key[5] & 0xff;
|
|
||||||
data[6] = key[6] & 0xff;
|
|
||||||
data[7] = key[7] & 0x0f;
|
|
||||||
data[8] = key[8] & 0xfc;
|
|
||||||
data[9] = key[9] & 0xff;
|
|
||||||
data[10] = key[10] & 0xff;
|
|
||||||
data[11] = key[11] & 0x0f;
|
|
||||||
data[12] = key[12] & 0xfc;
|
|
||||||
data[13] = key[13] & 0xff;
|
|
||||||
data[14] = key[14] & 0xff;
|
|
||||||
data[15] = key[15] & 0x0f;
|
|
||||||
data[16] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Int_t>
|
|
||||||
void Put(const Int_t * d, uint8_t last=0)
|
|
||||||
{
|
|
||||||
memcpy(data, d, 16);
|
|
||||||
data[16] = last;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Buffer
|
|
||||||
{
|
|
||||||
uint8_t data[POLY1305_BLOCK_BYTES];
|
|
||||||
|
|
||||||
operator uint8_t * ()
|
|
||||||
{
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Poly1305
|
|
||||||
{
|
|
||||||
Poly1305(const uint64_t * key)
|
|
||||||
{
|
|
||||||
m_Leftover = 0;
|
|
||||||
m_H.Zero();
|
|
||||||
m_Final = 0;
|
|
||||||
m_R.PutKey(key);
|
|
||||||
m_Pad.Put(key + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Update(const uint8_t * buf, size_t sz)
|
|
||||||
{
|
|
||||||
// process leftover
|
|
||||||
if(m_Leftover)
|
|
||||||
{
|
|
||||||
size_t want = POLY1305_BLOCK_BYTES - m_Leftover;
|
|
||||||
if(want > sz) want = sz;
|
|
||||||
memcpy(m_Buffer + m_Leftover, buf, want);
|
|
||||||
sz -= want;
|
|
||||||
buf += want;
|
|
||||||
m_Leftover += want;
|
|
||||||
if(m_Leftover < POLY1305_BLOCK_BYTES) return;
|
|
||||||
Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
|
|
||||||
m_Leftover = 0;
|
|
||||||
}
|
|
||||||
// process blocks
|
|
||||||
if(sz >= POLY1305_BLOCK_BYTES)
|
|
||||||
{
|
|
||||||
size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1));
|
|
||||||
Blocks(buf, want);
|
|
||||||
buf += want;
|
|
||||||
sz -= want;
|
|
||||||
}
|
|
||||||
// leftover
|
|
||||||
if(sz)
|
|
||||||
{
|
|
||||||
memcpy(m_Buffer+m_Leftover, buf, sz);
|
|
||||||
m_Leftover += sz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blocks(const uint8_t * buf, size_t sz)
|
|
||||||
{
|
|
||||||
const unsigned char hi = m_Final ^ 1;
|
|
||||||
while (sz >= POLY1305_BLOCK_BYTES) {
|
|
||||||
unsigned long u;
|
|
||||||
unsigned int i, j;
|
|
||||||
m_Msg.Put(buf, hi);
|
|
||||||
/* h += m */
|
|
||||||
m_H += m_Msg;
|
|
||||||
|
|
||||||
/* h *= r */
|
|
||||||
for (i = 0; i < 17; i++) {
|
|
||||||
u = 0;
|
|
||||||
for (j = 0; j <= i ; j++) {
|
|
||||||
u += (unsigned short)m_H.data[j] * m_R.data[i - j];
|
|
||||||
}
|
|
||||||
for (j = i + 1; j < 17; j++) {
|
|
||||||
unsigned long v = (unsigned short)m_H.data[j] * m_R.data[i + 17 - j];
|
|
||||||
v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */
|
|
||||||
u += v;
|
|
||||||
}
|
|
||||||
m_HR[i] = u;
|
|
||||||
}
|
|
||||||
/* (partial) h %= p */
|
|
||||||
m_H %= m_HR;
|
|
||||||
buf += POLY1305_BLOCK_BYTES;
|
|
||||||
sz -= POLY1305_BLOCK_BYTES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Finish(uint64_t * out)
|
|
||||||
{
|
|
||||||
// process leftovers
|
|
||||||
if(m_Leftover)
|
|
||||||
{
|
|
||||||
size_t idx = m_Leftover;
|
|
||||||
m_Buffer[idx++] = 1;
|
|
||||||
for(; idx < POLY1305_BLOCK_BYTES; idx++)
|
|
||||||
m_Buffer[idx] = 0;
|
|
||||||
m_Final = 1;
|
|
||||||
Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
// freeze H
|
|
||||||
~m_H;
|
|
||||||
// add pad
|
|
||||||
m_H += m_Pad;
|
|
||||||
// copy digest
|
|
||||||
memcpy(out, m_H, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t m_Leftover;
|
|
||||||
poly1305::Buffer m_Buffer;
|
|
||||||
poly1305::Block m_H;
|
|
||||||
poly1305::Block m_R;
|
|
||||||
poly1305::Block m_Pad;
|
|
||||||
poly1305::Block m_Msg;
|
|
||||||
poly1305::LongBlock m_HR;
|
|
||||||
uint8_t m_Final;
|
|
||||||
};
|
|
||||||
|
|
||||||
void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -10,6 +10,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <iomanip>
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
#include <boost/property_tree/ini_parser.hpp>
|
#include <boost/property_tree/ini_parser.hpp>
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
@ -27,22 +28,18 @@ namespace data
|
|||||||
static std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > g_Profiles;
|
static std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > g_Profiles;
|
||||||
static std::mutex g_ProfilesMutex;
|
static std::mutex g_ProfilesMutex;
|
||||||
|
|
||||||
static boost::posix_time::ptime GetTime ()
|
|
||||||
{
|
|
||||||
return boost::posix_time::second_clock::local_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
RouterProfile::RouterProfile ():
|
RouterProfile::RouterProfile ():
|
||||||
m_LastUpdateTime (GetTime ()), m_IsUpdated (false),
|
m_IsUpdated (false), m_LastDeclineTime (0), m_LastUnreachableTime (0),
|
||||||
m_LastDeclineTime (0), m_LastUnreachableTime (0),
|
m_LastUpdateTime (i2p::util::GetSecondsSinceEpoch ()),
|
||||||
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
|
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
|
||||||
m_NumTimesTaken (0), m_NumTimesRejected (0), m_HasConnected (false)
|
m_NumTimesTaken (0), m_NumTimesRejected (0), m_HasConnected (false),
|
||||||
|
m_IsDuplicated (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterProfile::UpdateTime ()
|
void RouterProfile::UpdateTime ()
|
||||||
{
|
{
|
||||||
m_LastUpdateTime = GetTime ();
|
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
m_IsUpdated = true;
|
m_IsUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,9 +54,11 @@ namespace data
|
|||||||
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
|
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
|
||||||
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
|
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
|
||||||
usage.put (PEER_PROFILE_USAGE_CONNECTED, m_HasConnected);
|
usage.put (PEER_PROFILE_USAGE_CONNECTED, m_HasConnected);
|
||||||
|
if (m_IsDuplicated)
|
||||||
|
usage.put (PEER_PROFILE_USAGE_DUPLICATED, true);
|
||||||
// fill property tree
|
// fill property tree
|
||||||
boost::property_tree::ptree pt;
|
boost::property_tree::ptree pt;
|
||||||
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
|
pt.put (PEER_PROFILE_LAST_UPDATE_TIMESTAMP, m_LastUpdateTime);
|
||||||
if (m_LastUnreachableTime)
|
if (m_LastUnreachableTime)
|
||||||
pt.put (PEER_PROFILE_LAST_UNREACHABLE_TIME, m_LastUnreachableTime);
|
pt.put (PEER_PROFILE_LAST_UNREACHABLE_TIME, m_LastUnreachableTime);
|
||||||
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
|
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
|
||||||
@ -101,10 +100,22 @@ namespace data
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
|
auto ts = pt.get (PEER_PROFILE_LAST_UPDATE_TIMESTAMP, 0);
|
||||||
if (t.length () > 0)
|
if (ts)
|
||||||
m_LastUpdateTime = boost::posix_time::time_from_string (t);
|
m_LastUpdateTime = ts;
|
||||||
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
|
else
|
||||||
|
{
|
||||||
|
// try old lastupdatetime
|
||||||
|
auto ut = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
|
||||||
|
if (ut.length () > 0)
|
||||||
|
{
|
||||||
|
std::istringstream ss (ut); std::tm t;
|
||||||
|
ss >> std::get_time(&t, "%Y-%b-%d %H:%M:%S");
|
||||||
|
if (!ss.fail())
|
||||||
|
m_LastUpdateTime = mktime (&t); // t is local time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i2p::util::GetSecondsSinceEpoch () - m_LastUpdateTime < PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
m_LastUnreachableTime = pt.get (PEER_PROFILE_LAST_UNREACHABLE_TIME, 0);
|
m_LastUnreachableTime = pt.get (PEER_PROFILE_LAST_UNREACHABLE_TIME, 0);
|
||||||
try
|
try
|
||||||
@ -126,6 +137,7 @@ namespace data
|
|||||||
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
|
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
|
||||||
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
|
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
|
||||||
m_HasConnected = usage.get (PEER_PROFILE_USAGE_CONNECTED, false);
|
m_HasConnected = usage.get (PEER_PROFILE_USAGE_CONNECTED, false);
|
||||||
|
m_IsDuplicated = usage.get (PEER_PROFILE_USAGE_DUPLICATED, false);
|
||||||
}
|
}
|
||||||
catch (boost::property_tree::ptree_bad_path& ex)
|
catch (boost::property_tree::ptree_bad_path& ex)
|
||||||
{
|
{
|
||||||
@ -178,6 +190,11 @@ namespace data
|
|||||||
UpdateTime ();
|
UpdateTime ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RouterProfile::Duplicated ()
|
||||||
|
{
|
||||||
|
m_IsDuplicated = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool RouterProfile::IsLowPartcipationRate () const
|
bool RouterProfile::IsLowPartcipationRate () const
|
||||||
{
|
{
|
||||||
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
|
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
|
||||||
@ -201,7 +218,7 @@ namespace data
|
|||||||
|
|
||||||
bool RouterProfile::IsBad ()
|
bool RouterProfile::IsBad ()
|
||||||
{
|
{
|
||||||
if (IsDeclinedRecently () || IsUnreachable ()) return true;
|
if (IsDeclinedRecently () || IsUnreachable () || m_IsDuplicated) return true;
|
||||||
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
||||||
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
||||||
{
|
{
|
||||||
@ -260,15 +277,21 @@ namespace data
|
|||||||
g_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
|
g_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PersistProfiles ()
|
static void SaveProfilesToDisk (std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > >&& profiles)
|
||||||
{
|
{
|
||||||
auto ts = GetTime ();
|
for (auto& it: profiles)
|
||||||
|
if (it.second) it.second->Save (it.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::future<void> PersistProfiles ()
|
||||||
|
{
|
||||||
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > > tmp;
|
std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > > tmp;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||||
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
||||||
{
|
{
|
||||||
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () > PEER_PROFILE_PERSIST_INTERVAL)
|
if (ts - it->second->GetLastUpdateTime () > PEER_PROFILE_PERSIST_INTERVAL)
|
||||||
{
|
{
|
||||||
if (it->second->IsUpdated ())
|
if (it->second->IsUpdated ())
|
||||||
tmp.push_back (std::make_pair (it->first, it->second));
|
tmp.push_back (std::make_pair (it->first, it->second));
|
||||||
@ -278,8 +301,9 @@ namespace data
|
|||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto& it: tmp)
|
if (!tmp.empty ())
|
||||||
if (it.second) it.second->Save (it.first);
|
return std::async (std::launch::async, SaveProfilesToDisk, std::move (tmp));
|
||||||
|
return std::future<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveProfiles ()
|
void SaveProfiles ()
|
||||||
@ -287,44 +311,51 @@ namespace data
|
|||||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > tmp;
|
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > tmp;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||||
tmp = g_Profiles;
|
std::swap (tmp, g_Profiles);
|
||||||
g_Profiles.clear ();
|
|
||||||
}
|
}
|
||||||
auto ts = GetTime ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
for (auto& it: tmp)
|
for (auto& it: tmp)
|
||||||
if (it.second->IsUseful() && (it.second->IsUpdated () || (ts - it.second->GetLastUpdateTime ()).total_seconds () < PEER_PROFILE_EXPIRATION_TIMEOUT*3600))
|
if (it.second->IsUseful() && (it.second->IsUpdated () || ts - it.second->GetLastUpdateTime () < PEER_PROFILE_EXPIRATION_TIMEOUT))
|
||||||
it.second->Save (it.first);
|
it.second->Save (it.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteObsoleteProfiles ()
|
static void DeleteFilesFromDisk ()
|
||||||
|
{
|
||||||
|
std::vector<std::string> files;
|
||||||
|
g_ProfilesStorage.Traverse(files);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
std::time_t now = std::time(nullptr);
|
||||||
|
for (const auto& path: files)
|
||||||
|
{
|
||||||
|
if (stat(path.c_str(), &st) != 0)
|
||||||
|
{
|
||||||
|
LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (now - st.st_mtime >= PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||||
|
{
|
||||||
|
LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path);
|
||||||
|
i2p::fs::Remove(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::future<void> DeleteObsoleteProfiles ()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
auto ts = GetTime ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||||
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
||||||
{
|
{
|
||||||
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600)
|
if (ts - it->second->GetLastUpdateTime () >= PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||||
it = g_Profiles.erase (it);
|
it = g_Profiles.erase (it);
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stat st;
|
return std::async (std::launch::async, DeleteFilesFromDisk);
|
||||||
std::time_t now = std::time(nullptr);
|
|
||||||
|
|
||||||
std::vector<std::string> files;
|
|
||||||
g_ProfilesStorage.Traverse(files);
|
|
||||||
for (const auto& path: files) {
|
|
||||||
if (stat(path.c_str(), &st) != 0) {
|
|
||||||
LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (now - st.st_mtime >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600) {
|
|
||||||
LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path);
|
|
||||||
i2p::fs::Remove(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#define PROFILING_H__
|
#define PROFILING_H__
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
#include <future>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@ -21,7 +21,8 @@ namespace data
|
|||||||
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
|
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
|
||||||
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
|
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
|
||||||
// params
|
// params
|
||||||
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
|
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime"; // deprecated
|
||||||
|
const char PEER_PROFILE_LAST_UPDATE_TIMESTAMP[] = "lastupdatetimestamp";
|
||||||
const char PEER_PROFILE_LAST_UNREACHABLE_TIME[] = "lastunreachabletime";
|
const char PEER_PROFILE_LAST_UNREACHABLE_TIME[] = "lastunreachabletime";
|
||||||
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
|
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
|
||||||
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
|
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
|
||||||
@ -29,10 +30,13 @@ namespace data
|
|||||||
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
|
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
|
||||||
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
|
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
|
||||||
const char PEER_PROFILE_USAGE_CONNECTED[] = "connected";
|
const char PEER_PROFILE_USAGE_CONNECTED[] = "connected";
|
||||||
|
const char PEER_PROFILE_USAGE_DUPLICATED[] = "duplicated";
|
||||||
|
|
||||||
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36; // in hours (1.5 days)
|
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36*60*60; // in seconds (1.5 days)
|
||||||
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 3 * 3600; // in seconds (3 hours)
|
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 1500; // in seconds (25 minutes)
|
||||||
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3600; // in seconds (1 hour)
|
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 900; // in seconds (15 minutes)
|
||||||
|
const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_TIMEOUT = 5400; // in seconds (1.5 hours)
|
||||||
|
const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE = 2400; // in seconds (40 minutes)
|
||||||
const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes)
|
const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes)
|
||||||
const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes)
|
const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes)
|
||||||
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes)
|
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes)
|
||||||
@ -56,11 +60,13 @@ namespace data
|
|||||||
|
|
||||||
void Unreachable (bool unreachable);
|
void Unreachable (bool unreachable);
|
||||||
void Connected ();
|
void Connected ();
|
||||||
|
void Duplicated ();
|
||||||
|
|
||||||
boost::posix_time::ptime GetLastUpdateTime () const { return m_LastUpdateTime; };
|
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||||
bool IsUpdated () const { return m_IsUpdated; };
|
bool IsUpdated () const { return m_IsUpdated; };
|
||||||
|
|
||||||
bool IsUseful() const;
|
bool IsUseful() const;
|
||||||
|
bool IsDuplicated () const { return m_IsDuplicated; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -73,9 +79,8 @@ namespace data
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
boost::posix_time::ptime m_LastUpdateTime; // TODO: use std::chrono
|
|
||||||
bool m_IsUpdated;
|
bool m_IsUpdated;
|
||||||
uint64_t m_LastDeclineTime, m_LastUnreachableTime; // in seconds
|
uint64_t m_LastDeclineTime, m_LastUnreachableTime, m_LastUpdateTime; // in seconds
|
||||||
// participation
|
// participation
|
||||||
uint32_t m_NumTunnelsAgreed;
|
uint32_t m_NumTunnelsAgreed;
|
||||||
uint32_t m_NumTunnelsDeclined;
|
uint32_t m_NumTunnelsDeclined;
|
||||||
@ -84,14 +89,15 @@ namespace data
|
|||||||
uint32_t m_NumTimesTaken;
|
uint32_t m_NumTimesTaken;
|
||||||
uint32_t m_NumTimesRejected;
|
uint32_t m_NumTimesRejected;
|
||||||
bool m_HasConnected; // successful trusted(incoming or NTCP2) connection
|
bool m_HasConnected; // successful trusted(incoming or NTCP2) connection
|
||||||
|
bool m_IsDuplicated;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
||||||
bool IsRouterBanned (const IdentHash& identHash); // check only existing profiles
|
bool IsRouterBanned (const IdentHash& identHash); // check only existing profiles
|
||||||
void InitProfilesStorage ();
|
void InitProfilesStorage ();
|
||||||
void DeleteObsoleteProfiles ();
|
std::future<void> DeleteObsoleteProfiles ();
|
||||||
void SaveProfiles ();
|
void SaveProfiles ();
|
||||||
void PersistProfiles ();
|
std::future<void> PersistProfiles ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,11 +57,8 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
m_Service.reset (new RouterService);
|
m_Service.reset (new RouterService);
|
||||||
m_Service->Start ();
|
m_Service->Start ();
|
||||||
if (!m_IsHiddenMode)
|
m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||||
{
|
ScheduleInitialPublish ();
|
||||||
m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
|
||||||
ScheduleInitialPublish ();
|
|
||||||
}
|
|
||||||
m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||||
ScheduleCongestionUpdate ();
|
ScheduleCongestionUpdate ();
|
||||||
m_CleanupTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
m_CleanupTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||||
@ -78,9 +75,16 @@ namespace i2p
|
|||||||
if (m_CongestionUpdateTimer)
|
if (m_CongestionUpdateTimer)
|
||||||
m_CongestionUpdateTimer->cancel ();
|
m_CongestionUpdateTimer->cancel ();
|
||||||
m_Service->Stop ();
|
m_Service->Stop ();
|
||||||
|
CleanUp (); // GarlicDestination
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<i2p::data::RouterInfo::Buffer> RouterContext::CopyRouterInfoBuffer () const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_RouterInfoMutex);
|
||||||
|
return m_RouterInfo.CopyBuffer ();
|
||||||
|
}
|
||||||
|
|
||||||
void RouterContext::CreateNewRouter ()
|
void RouterContext::CreateNewRouter ()
|
||||||
{
|
{
|
||||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
||||||
@ -249,7 +253,10 @@ namespace i2p
|
|||||||
|
|
||||||
void RouterContext::UpdateRouterInfo ()
|
void RouterContext::UpdateRouterInfo ()
|
||||||
{
|
{
|
||||||
m_RouterInfo.CreateBuffer (m_Keys);
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_RouterInfoMutex);
|
||||||
|
m_RouterInfo.CreateBuffer (m_Keys);
|
||||||
|
}
|
||||||
m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO));
|
m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO));
|
||||||
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
}
|
}
|
||||||
@ -560,10 +567,10 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
m_IsFloodfill = floodfill;
|
m_IsFloodfill = floodfill;
|
||||||
if (floodfill)
|
if (floodfill)
|
||||||
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eFloodfill);
|
m_RouterInfo.UpdateFloodfillProperty (true);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
|
m_RouterInfo.UpdateFloodfillProperty (false);
|
||||||
// we don't publish number of routers and leaseset for non-floodfill
|
// we don't publish number of routers and leaseset for non-floodfill
|
||||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS);
|
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS);
|
||||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS);
|
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS);
|
||||||
@ -1324,9 +1331,15 @@ namespace i2p
|
|||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
if (m_RouterInfo.IsReachableBy (i2p::data::RouterInfo::eAllTransports))
|
if (m_RouterInfo.IsReachableBy (i2p::data::RouterInfo::eAllTransports))
|
||||||
|
{
|
||||||
|
UpdateCongestion ();
|
||||||
HandlePublishTimer (ecode);
|
HandlePublishTimer (ecode);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
|
||||||
ScheduleInitialPublish ();
|
ScheduleInitialPublish ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1348,16 +1361,21 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
m_PublishExcluded.clear ();
|
|
||||||
m_PublishReplyToken = 0;
|
|
||||||
if (IsFloodfill ())
|
|
||||||
{
|
|
||||||
UpdateStats (); // for floodfill
|
|
||||||
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // don't publish to ourselves
|
|
||||||
}
|
|
||||||
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
|
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
|
||||||
Publish ();
|
if (!m_IsHiddenMode)
|
||||||
SchedulePublishResend ();
|
{
|
||||||
|
m_PublishExcluded.clear ();
|
||||||
|
m_PublishReplyToken = 0;
|
||||||
|
if (IsFloodfill ())
|
||||||
|
{
|
||||||
|
UpdateStats (); // for floodfill
|
||||||
|
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // don't publish to ourselves
|
||||||
|
}
|
||||||
|
Publish ();
|
||||||
|
SchedulePublishResend ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SchedulePublish ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1382,8 +1400,9 @@ namespace i2p
|
|||||||
if (m_Service)
|
if (m_Service)
|
||||||
m_Service->GetService ().post ([this]() { HandlePublishResendTimer (boost::system::error_code ()); });
|
m_Service->GetService ().post ([this]() { HandlePublishResendTimer (boost::system::error_code ()); });
|
||||||
};
|
};
|
||||||
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
|
if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()) || // already connected
|
||||||
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
|
(floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) && // are we able to connect
|
||||||
|
!i2p::transport::transports.RoutesRestricted ())) // and routes not restricted
|
||||||
{
|
{
|
||||||
// send directly
|
// send directly
|
||||||
auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken);
|
auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken);
|
||||||
@ -1454,23 +1473,28 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
auto c = i2p::data::RouterInfo::eLowCongestion;
|
UpdateCongestion ();
|
||||||
if (!AcceptsTunnels () || !m_ShareRatio)
|
|
||||||
c = i2p::data::RouterInfo::eRejectAll;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int congestionLevel = GetCongestionLevel (true);
|
|
||||||
if (congestionLevel > CONGESTION_LEVEL_HIGH)
|
|
||||||
c = i2p::data::RouterInfo::eHighCongestion;
|
|
||||||
else if (congestionLevel > CONGESTION_LEVEL_MEDIUM)
|
|
||||||
c = i2p::data::RouterInfo::eMediumCongestion;
|
|
||||||
}
|
|
||||||
if (m_RouterInfo.UpdateCongestion (c))
|
|
||||||
UpdateRouterInfo ();
|
|
||||||
ScheduleCongestionUpdate ();
|
ScheduleCongestionUpdate ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RouterContext::UpdateCongestion ()
|
||||||
|
{
|
||||||
|
auto c = i2p::data::RouterInfo::eLowCongestion;
|
||||||
|
if (!AcceptsTunnels () || !m_ShareRatio)
|
||||||
|
c = i2p::data::RouterInfo::eRejectAll;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int congestionLevel = GetCongestionLevel (true);
|
||||||
|
if (congestionLevel > CONGESTION_LEVEL_HIGH)
|
||||||
|
c = i2p::data::RouterInfo::eHighCongestion;
|
||||||
|
else if (congestionLevel > CONGESTION_LEVEL_MEDIUM)
|
||||||
|
c = i2p::data::RouterInfo::eMediumCongestion;
|
||||||
|
}
|
||||||
|
if (m_RouterInfo.UpdateCongestion (c))
|
||||||
|
UpdateRouterInfo ();
|
||||||
|
}
|
||||||
|
|
||||||
void RouterContext::ScheduleCleanupTimer ()
|
void RouterContext::ScheduleCleanupTimer ()
|
||||||
{
|
{
|
||||||
if (m_CleanupTimer)
|
if (m_CleanupTimer)
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <unordered_set>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
@ -114,7 +114,8 @@ namespace garlic
|
|||||||
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
|
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
|
||||||
[](i2p::garlic::GarlicDestination *) {});
|
[](i2p::garlic::GarlicDestination *) {});
|
||||||
}
|
}
|
||||||
|
std::shared_ptr<i2p::data::RouterInfo::Buffer> CopyRouterInfoBuffer () const;
|
||||||
|
|
||||||
const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; };
|
const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; };
|
||||||
const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; };
|
const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; };
|
||||||
const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
|
const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
|
||||||
@ -229,6 +230,7 @@ namespace garlic
|
|||||||
void HandlePublishResendTimer (const boost::system::error_code& ecode);
|
void HandlePublishResendTimer (const boost::system::error_code& ecode);
|
||||||
void ScheduleCongestionUpdate ();
|
void ScheduleCongestionUpdate ();
|
||||||
void HandleCongestionUpdateTimer (const boost::system::error_code& ecode);
|
void HandleCongestionUpdateTimer (const boost::system::error_code& ecode);
|
||||||
|
void UpdateCongestion ();
|
||||||
void ScheduleCleanupTimer ();
|
void ScheduleCleanupTimer ();
|
||||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
@ -255,9 +257,10 @@ namespace garlic
|
|||||||
// publish
|
// publish
|
||||||
std::unique_ptr<RouterService> m_Service;
|
std::unique_ptr<RouterService> m_Service;
|
||||||
std::unique_ptr<boost::asio::deadline_timer> m_PublishTimer, m_CongestionUpdateTimer, m_CleanupTimer;
|
std::unique_ptr<boost::asio::deadline_timer> m_PublishTimer, m_CongestionUpdateTimer, m_CleanupTimer;
|
||||||
std::set<i2p::data::IdentHash> m_PublishExcluded;
|
std::unordered_set<i2p::data::IdentHash> m_PublishExcluded;
|
||||||
uint32_t m_PublishReplyToken;
|
uint32_t m_PublishReplyToken;
|
||||||
bool m_IsHiddenMode; // not publish
|
bool m_IsHiddenMode; // not publish
|
||||||
|
mutable std::mutex m_RouterInfoMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern RouterContext context;
|
extern RouterContext context;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/make_shared.hpp>
|
#include <boost/make_shared.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp> // for boost::to_lower
|
||||||
#if (BOOST_VERSION >= 105300)
|
#if (BOOST_VERSION >= 105300)
|
||||||
#include <boost/atomic.hpp>
|
#include <boost/atomic.hpp>
|
||||||
#endif
|
#endif
|
||||||
@ -34,6 +35,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (len > size ()) len = size ();
|
if (len > size ()) len = size ();
|
||||||
memcpy (data (), buf, len);
|
memcpy (data (), buf, len);
|
||||||
|
m_BufferLen = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
RouterInfo::RouterInfo (): m_Buffer (nullptr)
|
RouterInfo::RouterInfo (): m_Buffer (nullptr)
|
||||||
@ -42,8 +44,8 @@ namespace data
|
|||||||
}
|
}
|
||||||
|
|
||||||
RouterInfo::RouterInfo (const std::string& fullPath):
|
RouterInfo::RouterInfo (const std::string& fullPath):
|
||||||
m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false),
|
m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false), m_IsFloodfill (false),
|
||||||
m_SupportedTransports (0),m_ReachableTransports (0),
|
m_SupportedTransports (0),m_ReachableTransports (0), m_PublishedTransports (0),
|
||||||
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
|
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
|
||||||
{
|
{
|
||||||
m_Addresses = boost::make_shared<Addresses>(); // create empty list
|
m_Addresses = boost::make_shared<Addresses>(); // create empty list
|
||||||
@ -52,15 +54,15 @@ namespace data
|
|||||||
}
|
}
|
||||||
|
|
||||||
RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len):
|
RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len):
|
||||||
m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false),
|
m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false), m_IsFloodfill (false),
|
||||||
m_SupportedTransports (0), m_ReachableTransports (0),
|
m_SupportedTransports (0), m_ReachableTransports (0), m_PublishedTransports (0),
|
||||||
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
|
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
|
||||||
{
|
{
|
||||||
if (len <= MAX_RI_BUFFER_SIZE)
|
if (len <= MAX_RI_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
m_Addresses = boost::make_shared<Addresses>(); // create empty list
|
m_Addresses = boost::make_shared<Addresses>(); // create empty list
|
||||||
m_Buffer = buf;
|
m_Buffer = buf;
|
||||||
m_BufferLen = len;
|
if (m_Buffer) m_Buffer->SetBufferLen (len);
|
||||||
ReadFromBuffer (true);
|
ReadFromBuffer (true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -96,7 +98,8 @@ namespace data
|
|||||||
m_IsUnreachable = false;
|
m_IsUnreachable = false;
|
||||||
m_SupportedTransports = 0;
|
m_SupportedTransports = 0;
|
||||||
m_ReachableTransports = 0;
|
m_ReachableTransports = 0;
|
||||||
m_Caps = 0;
|
m_PublishedTransports = 0;
|
||||||
|
m_Caps = 0; m_IsFloodfill = false;
|
||||||
// don't clean up m_Addresses, it will be replaced in ReadFromStream
|
// don't clean up m_Addresses, it will be replaced in ReadFromStream
|
||||||
ClearProperties ();
|
ClearProperties ();
|
||||||
// skip identity
|
// skip identity
|
||||||
@ -128,8 +131,8 @@ namespace data
|
|||||||
if (s.is_open ())
|
if (s.is_open ())
|
||||||
{
|
{
|
||||||
s.seekg (0,std::ios::end);
|
s.seekg (0,std::ios::end);
|
||||||
m_BufferLen = s.tellg ();
|
size_t bufferLen = s.tellg ();
|
||||||
if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
|
if (bufferLen < 40 || bufferLen > MAX_RI_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
LogPrint(eLogError, "RouterInfo: File ", fullPath, " is malformed");
|
LogPrint(eLogError, "RouterInfo: File ", fullPath, " is malformed");
|
||||||
return false;
|
return false;
|
||||||
@ -137,7 +140,8 @@ namespace data
|
|||||||
s.seekg(0, std::ios::beg);
|
s.seekg(0, std::ios::beg);
|
||||||
if (!m_Buffer)
|
if (!m_Buffer)
|
||||||
m_Buffer = NewBuffer ();
|
m_Buffer = NewBuffer ();
|
||||||
s.read((char *)m_Buffer->data (), m_BufferLen);
|
s.read((char *)m_Buffer->data (), bufferLen);
|
||||||
|
m_Buffer->SetBufferLen (bufferLen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -162,11 +166,12 @@ namespace data
|
|||||||
m_IsUnreachable = true;
|
m_IsUnreachable = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_RouterIdentity = NewIdentity (m_Buffer->data (), m_BufferLen);
|
size_t bufferLen = m_Buffer->GetBufferLen ();
|
||||||
|
m_RouterIdentity = NewIdentity (m_Buffer->data (), bufferLen);
|
||||||
size_t identityLen = m_RouterIdentity->GetFullLen ();
|
size_t identityLen = m_RouterIdentity->GetFullLen ();
|
||||||
if (identityLen >= m_BufferLen)
|
if (identityLen >= bufferLen)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "RouterInfo: Identity length ", identityLen, " exceeds buffer size ", m_BufferLen);
|
LogPrint (eLogError, "RouterInfo: Identity length ", identityLen, " exceeds buffer size ", bufferLen);
|
||||||
m_IsUnreachable = true;
|
m_IsUnreachable = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -180,7 +185,7 @@ namespace data
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// verify signature
|
// verify signature
|
||||||
int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
|
int l = bufferLen - m_RouterIdentity->GetSignatureLen ();
|
||||||
if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer->data (), l, (uint8_t *)m_Buffer->data () + l))
|
if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer->data (), l, (uint8_t *)m_Buffer->data () + l))
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "RouterInfo: Signature verification failed");
|
LogPrint (eLogError, "RouterInfo: Signature verification failed");
|
||||||
@ -190,7 +195,7 @@ namespace data
|
|||||||
}
|
}
|
||||||
// parse RI
|
// parse RI
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str.write ((const char *)m_Buffer->data () + identityLen, m_BufferLen - identityLen);
|
str.write ((const char *)m_Buffer->data () + identityLen, bufferLen - identityLen);
|
||||||
ReadFromStream (str);
|
ReadFromStream (str);
|
||||||
if (!str)
|
if (!str)
|
||||||
{
|
{
|
||||||
@ -216,7 +221,7 @@ namespace data
|
|||||||
uint8_t cost; // ignore
|
uint8_t cost; // ignore
|
||||||
s.read ((char *)&cost, sizeof (cost));
|
s.read ((char *)&cost, sizeof (cost));
|
||||||
s.read ((char *)&address->date, sizeof (address->date));
|
s.read ((char *)&address->date, sizeof (address->date));
|
||||||
bool isHost = false, isStaticKey = false, isV2 = false;
|
bool isHost = false, isStaticKey = false, isV2 = false, isIntroKey = false;
|
||||||
char transportStyle[6];
|
char transportStyle[6];
|
||||||
ReadString (transportStyle, 6, s);
|
ReadString (transportStyle, 6, s);
|
||||||
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
|
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
|
||||||
@ -293,26 +298,38 @@ namespace data
|
|||||||
address->caps = ExtractAddressCaps (value);
|
address->caps = ExtractAddressCaps (value);
|
||||||
else if (!strcmp (key, "s")) // ntcp2 or ssu2 static key
|
else if (!strcmp (key, "s")) // ntcp2 or ssu2 static key
|
||||||
{
|
{
|
||||||
Base64ToByteStream (value, strlen (value), address->s, 32);
|
if (Base64ToByteStream (value, strlen (value), address->s, 32) == 32 &&
|
||||||
if (!(address->s[31] & 0x80)) // check if x25519 public key
|
!(address->s[31] & 0x80)) // check if x25519 public key
|
||||||
isStaticKey = true;
|
isStaticKey = true;
|
||||||
|
else
|
||||||
|
address->transportStyle = eTransportUnknown; // invalid address
|
||||||
}
|
}
|
||||||
else if (!strcmp (key, "i")) // ntcp2 iv or ssu2 intro
|
else if (!strcmp (key, "i")) // ntcp2 iv or ssu2 intro
|
||||||
{
|
{
|
||||||
if (address->IsNTCP2 ())
|
if (address->IsNTCP2 ())
|
||||||
{
|
{
|
||||||
Base64ToByteStream (value, strlen (value), address->i, 16);
|
if (Base64ToByteStream (value, strlen (value), address->i, 16) == 16)
|
||||||
address->published = true; // presence of "i" means "published" NTCP2
|
address->published = true; // presence of "i" means "published" NTCP2
|
||||||
|
else
|
||||||
|
address->transportStyle = eTransportUnknown; // invalid address
|
||||||
}
|
}
|
||||||
else if (address->IsSSU2 ())
|
else if (address->IsSSU2 ())
|
||||||
Base64ToByteStream (value, strlen (value), address->i, 32);
|
{
|
||||||
|
if (Base64ToByteStream (value, strlen (value), address->i, 32) == 32)
|
||||||
|
isIntroKey = true;
|
||||||
|
else
|
||||||
|
address->transportStyle = eTransportUnknown; // invalid address
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!strcmp (key, "v"))
|
else if (!strcmp (key, "v"))
|
||||||
{
|
{
|
||||||
if (!strcmp (value, "2"))
|
if (!strcmp (value, "2"))
|
||||||
isV2 = true;
|
isV2 = true;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogPrint (eLogWarning, "RouterInfo: Unexpected value ", value, " for v");
|
LogPrint (eLogWarning, "RouterInfo: Unexpected value ", value, " for v");
|
||||||
|
address->transportStyle = eTransportUnknown; // invalid address
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (key[0] == 'i')
|
else if (key[0] == 'i')
|
||||||
{
|
{
|
||||||
@ -375,7 +392,7 @@ namespace data
|
|||||||
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
|
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
|
||||||
else
|
else
|
||||||
supportedTransports |= eNTCP2V4;
|
supportedTransports |= eNTCP2V4;
|
||||||
m_ReachableTransports |= supportedTransports;
|
m_PublishedTransports |= supportedTransports;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -390,17 +407,17 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (address->transportStyle == eTransportSSU2 && isV2 && isStaticKey)
|
else if (address->transportStyle == eTransportSSU2 && isV2 && isStaticKey && isIntroKey)
|
||||||
{
|
{
|
||||||
if (address->IsV4 ()) supportedTransports |= eSSU2V4;
|
if (address->IsV4 ()) supportedTransports |= eSSU2V4;
|
||||||
if (address->IsV6 ()) supportedTransports |= eSSU2V6;
|
if (address->IsV6 ()) supportedTransports |= eSSU2V6;
|
||||||
if (isHost && address->port)
|
if (isHost && address->port)
|
||||||
{
|
{
|
||||||
if (address->host.is_v4 ()) m_ReachableTransports |= eSSU2V4;
|
if (address->host.is_v4 ()) m_PublishedTransports |= eSSU2V4;
|
||||||
if (address->host.is_v6 ()) m_ReachableTransports |= eSSU2V6;
|
if (address->host.is_v6 ()) m_PublishedTransports |= eSSU2V6;
|
||||||
address->published = true;
|
address->published = true;
|
||||||
}
|
}
|
||||||
if (address->ssu && !address->ssu->introducers.empty ())
|
else if (address->ssu && !address->ssu->introducers.empty ())
|
||||||
{
|
{
|
||||||
// exclude invalid introducers
|
// exclude invalid introducers
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
@ -420,6 +437,7 @@ namespace data
|
|||||||
m_SupportedTransports |= supportedTransports;
|
m_SupportedTransports |= supportedTransports;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_ReachableTransports |= m_PublishedTransports;
|
||||||
// update addresses
|
// update addresses
|
||||||
#if (BOOST_VERSION >= 105300)
|
#if (BOOST_VERSION >= 105300)
|
||||||
boost::atomic_store (&m_Addresses, addresses);
|
boost::atomic_store (&m_Addresses, addresses);
|
||||||
@ -449,7 +467,10 @@ namespace data
|
|||||||
|
|
||||||
// extract caps
|
// extract caps
|
||||||
if (!strcmp (key, "caps"))
|
if (!strcmp (key, "caps"))
|
||||||
|
{
|
||||||
ExtractCaps (value);
|
ExtractCaps (value);
|
||||||
|
m_IsFloodfill = IsDeclaredFloodfill ();
|
||||||
|
}
|
||||||
// extract version
|
// extract version
|
||||||
else if (!strcmp (key, ROUTER_INFO_PROPERTY_VERSION))
|
else if (!strcmp (key, ROUTER_INFO_PROPERTY_VERSION))
|
||||||
{
|
{
|
||||||
@ -514,13 +535,20 @@ namespace data
|
|||||||
case CAPS_FLAG_FLOODFILL:
|
case CAPS_FLAG_FLOODFILL:
|
||||||
m_Caps |= Caps::eFloodfill;
|
m_Caps |= Caps::eFloodfill;
|
||||||
break;
|
break;
|
||||||
|
case CAPS_FLAG_LOW_BANDWIDTH1:
|
||||||
|
case CAPS_FLAG_LOW_BANDWIDTH2:
|
||||||
|
case CAPS_FLAG_LOW_BANDWIDTH3:
|
||||||
|
m_BandwidthCap = *cap;
|
||||||
|
break;
|
||||||
case CAPS_FLAG_HIGH_BANDWIDTH1:
|
case CAPS_FLAG_HIGH_BANDWIDTH1:
|
||||||
case CAPS_FLAG_HIGH_BANDWIDTH2:
|
case CAPS_FLAG_HIGH_BANDWIDTH2:
|
||||||
m_Caps |= Caps::eHighBandwidth;
|
m_Caps |= Caps::eHighBandwidth;
|
||||||
|
m_BandwidthCap = *cap;
|
||||||
break;
|
break;
|
||||||
case CAPS_FLAG_EXTRA_BANDWIDTH1:
|
case CAPS_FLAG_EXTRA_BANDWIDTH1:
|
||||||
case CAPS_FLAG_EXTRA_BANDWIDTH2:
|
case CAPS_FLAG_EXTRA_BANDWIDTH2:
|
||||||
m_Caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth;
|
m_Caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth;
|
||||||
|
m_BandwidthCap = *cap;
|
||||||
break;
|
break;
|
||||||
case CAPS_FLAG_HIDDEN:
|
case CAPS_FLAG_HIDDEN:
|
||||||
m_Caps |= Caps::eHidden;
|
m_Caps |= Caps::eHidden;
|
||||||
@ -608,6 +636,19 @@ namespace data
|
|||||||
return m_Buffer->data ();
|
return m_Buffer->data ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RouterInfo::SaveToFile (const std::string& fullPath, std::shared_ptr<Buffer> buf)
|
||||||
|
{
|
||||||
|
if (!buf) return false;
|
||||||
|
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||||
|
if (!f.is_open ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "RouterInfo: Can't save to ", fullPath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
f.write ((char *)buf->data (), buf->GetBufferLen ());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool RouterInfo::SaveToFile (const std::string& fullPath)
|
bool RouterInfo::SaveToFile (const std::string& fullPath)
|
||||||
{
|
{
|
||||||
if (m_IsUnreachable) return false; // don't save bad router
|
if (m_IsUnreachable) return false; // don't save bad router
|
||||||
@ -616,14 +657,7 @@ namespace data
|
|||||||
LogPrint (eLogWarning, "RouterInfo: Can't save, m_Buffer == NULL");
|
LogPrint (eLogWarning, "RouterInfo: Can't save, m_Buffer == NULL");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
return SaveToFile (fullPath, m_Buffer);
|
||||||
if (!f.is_open ())
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "RouterInfo: Can't save to ", fullPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
f.write ((char *)m_Buffer->data (), m_BufferLen);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RouterInfo::ReadString (char * str, size_t len, std::istream& s) const
|
size_t RouterInfo::ReadString (char * str, size_t len, std::istream& s) const
|
||||||
@ -988,21 +1022,28 @@ namespace data
|
|||||||
|
|
||||||
bool RouterInfo::IsEligibleFloodfill () const
|
bool RouterInfo::IsEligibleFloodfill () const
|
||||||
{
|
{
|
||||||
// floodfill must have published ipv4, >= 0.9.38 and not DSA
|
// floodfill must have published ipv4 or reachable ipv4 and published ipv6
|
||||||
return m_Version >= NETDB_MIN_FLOODFILL_VERSION && IsPublished (true) &&
|
// >= 0.9.59 and not DSA
|
||||||
|
return m_Version >= NETDB_MIN_FLOODFILL_VERSION && (IsPublished (true) ||
|
||||||
|
(IsReachableBy (eNTCP2V4 | eSSU2V4) && IsPublished (false))) &&
|
||||||
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterInfo::IsPublished (bool v4) const
|
bool RouterInfo::IsPublished (bool v4) const
|
||||||
{
|
{
|
||||||
if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addresses are not published
|
if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addresses are not published
|
||||||
auto addr = GetAddresses ();
|
return IsPublishedOn (v4 ? (eNTCP2V4 | eSSU2V4) : (eNTCP2V6 | eSSU2V6));
|
||||||
if (v4)
|
}
|
||||||
return ((*addr)[eNTCP2V4Idx] && ((*addr)[eNTCP2V4Idx])->published) ||
|
|
||||||
((*addr)[eSSU2V4Idx] && ((*addr)[eSSU2V4Idx])->published);
|
bool RouterInfo::IsPublishedOn (CompatibleTransports transports) const
|
||||||
else
|
{
|
||||||
return ((*addr)[eNTCP2V6Idx] && ((*addr)[eNTCP2V6Idx])->published) ||
|
return m_PublishedTransports & transports;
|
||||||
((*addr)[eSSU2V6Idx] && ((*addr)[eSSU2V6Idx])->published);
|
}
|
||||||
|
|
||||||
|
bool RouterInfo::IsNAT2NATOnly (const RouterInfo& other) const
|
||||||
|
{
|
||||||
|
return !(m_PublishedTransports & other.m_SupportedTransports) &&
|
||||||
|
!(other.m_PublishedTransports & m_SupportedTransports);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterInfo::IsSSU2PeerTesting (bool v4) const
|
bool RouterInfo::IsSSU2PeerTesting (bool v4) const
|
||||||
@ -1091,9 +1132,15 @@ namespace data
|
|||||||
m_Buffer = NewBuffer ();
|
m_Buffer = NewBuffer ();
|
||||||
if (len > m_Buffer->size ()) len = m_Buffer->size ();
|
if (len > m_Buffer->size ()) len = m_Buffer->size ();
|
||||||
memcpy (m_Buffer->data (), buf, len);
|
memcpy (m_Buffer->data (), buf, len);
|
||||||
m_BufferLen = len;
|
m_Buffer->SetBufferLen (len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<RouterInfo::Buffer> RouterInfo::CopyBuffer () const
|
||||||
|
{
|
||||||
|
if (!m_Buffer) return nullptr;
|
||||||
|
return netdb.NewRouterInfoBuffer (*m_Buffer);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<RouterInfo::Buffer> RouterInfo::NewBuffer () const
|
std::shared_ptr<RouterInfo::Buffer> RouterInfo::NewBuffer () const
|
||||||
{
|
{
|
||||||
return netdb.NewRouterInfoBuffer ();
|
return netdb.NewRouterInfoBuffer ();
|
||||||
@ -1425,6 +1472,20 @@ namespace data
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LocalRouterInfo::UpdateFloodfillProperty (bool floodfill)
|
||||||
|
{
|
||||||
|
if (floodfill)
|
||||||
|
{
|
||||||
|
UpdateCaps (GetCaps () | i2p::data::RouterInfo::eFloodfill);
|
||||||
|
SetFloodfill ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateCaps (GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
|
||||||
|
ResetFloodfill ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LocalRouterInfo::WriteString (const std::string& str, std::ostream& s) const
|
void LocalRouterInfo::WriteString (const std::string& str, std::ostream& s) const
|
||||||
{
|
{
|
||||||
uint8_t len = str.size ();
|
uint8_t len = str.size ();
|
||||||
|
@ -188,6 +188,14 @@ namespace data
|
|||||||
|
|
||||||
Buffer () = default;
|
Buffer () = default;
|
||||||
Buffer (const uint8_t * buf, size_t len);
|
Buffer (const uint8_t * buf, size_t len);
|
||||||
|
Buffer (const Buffer& other): Buffer (other.data (), other.m_BufferLen) {};
|
||||||
|
|
||||||
|
size_t GetBufferLen () const { return m_BufferLen; };
|
||||||
|
void SetBufferLen (size_t len) { m_BufferLen = len; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
size_t m_BufferLen = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::array<std::shared_ptr<Address>, eNumTransports> Addresses;
|
typedef std::array<std::shared_ptr<Address>, eNumTransports> Addresses;
|
||||||
@ -227,8 +235,9 @@ namespace data
|
|||||||
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
|
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
|
||||||
void UpdateSupportedTransports ();
|
void UpdateSupportedTransports ();
|
||||||
void UpdateIntroducers (uint64_t ts); // ts in seconds
|
void UpdateIntroducers (uint64_t ts); // ts in seconds
|
||||||
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
|
bool IsFloodfill () const { return m_IsFloodfill; };
|
||||||
void ResetFlooldFill () { m_Caps &= ~Caps::eFloodfill; };
|
void SetFloodfill () { m_IsFloodfill = true; };
|
||||||
|
void ResetFloodfill () { m_IsFloodfill = false; };
|
||||||
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
||||||
bool IsNTCP2 (bool v4only = true) const;
|
bool IsNTCP2 (bool v4only = true) const;
|
||||||
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
|
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
|
||||||
@ -247,17 +256,22 @@ namespace data
|
|||||||
bool IsReachableFrom (const RouterInfo& other) const { return m_ReachableTransports & other.m_SupportedTransports; };
|
bool IsReachableFrom (const RouterInfo& other) const { return m_ReachableTransports & other.m_SupportedTransports; };
|
||||||
bool IsReachableBy (CompatibleTransports transports) const { return m_ReachableTransports & transports; };
|
bool IsReachableBy (CompatibleTransports transports) const { return m_ReachableTransports & transports; };
|
||||||
CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; };
|
CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; };
|
||||||
|
CompatibleTransports GetPublishedTransports () const { return m_PublishedTransports; };
|
||||||
bool HasValidAddresses () const { return m_SupportedTransports; };
|
bool HasValidAddresses () const { return m_SupportedTransports; };
|
||||||
bool IsHidden () const { return m_Caps & eHidden; };
|
bool IsHidden () const { return m_Caps & eHidden; };
|
||||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||||
bool IsEligibleFloodfill () const;
|
bool IsEligibleFloodfill () const;
|
||||||
|
bool IsDeclaredFloodfill () const { return m_Caps & RouterInfo::eFloodfill; };
|
||||||
bool IsPublished (bool v4) const;
|
bool IsPublished (bool v4) const;
|
||||||
|
bool IsPublishedOn (CompatibleTransports transports) const;
|
||||||
|
bool IsNAT2NATOnly (const RouterInfo& other) const; // only NAT-to-NAT connection is possible
|
||||||
bool IsSSU2PeerTesting (bool v4) const;
|
bool IsSSU2PeerTesting (bool v4) const;
|
||||||
bool IsSSU2Introducer (bool v4) const;
|
bool IsSSU2Introducer (bool v4) const;
|
||||||
bool IsHighCongestion (bool highBandwidth) const;
|
bool IsHighCongestion (bool highBandwidth) const;
|
||||||
|
|
||||||
uint8_t GetCaps () const { return m_Caps; };
|
uint8_t GetCaps () const { return m_Caps; };
|
||||||
|
char GetBandwidthCap() const { return m_BandwidthCap; };
|
||||||
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
||||||
|
|
||||||
Congestion GetCongestion () const { return m_Congestion; };
|
Congestion GetCongestion () const { return m_Congestion; };
|
||||||
@ -268,17 +282,21 @@ namespace data
|
|||||||
|
|
||||||
const uint8_t * GetBuffer () const { return m_Buffer ? m_Buffer->data () : nullptr; };
|
const uint8_t * GetBuffer () const { return m_Buffer ? m_Buffer->data () : nullptr; };
|
||||||
const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary
|
const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary
|
||||||
size_t GetBufferLen () const { return m_BufferLen; };
|
size_t GetBufferLen () const { return m_Buffer ? m_Buffer->GetBufferLen () : 0; };
|
||||||
|
void DeleteBuffer () { m_Buffer = nullptr; };
|
||||||
|
std::shared_ptr<Buffer> GetSharedBuffer () const { return m_Buffer; };
|
||||||
|
std::shared_ptr<Buffer> CopyBuffer () const;
|
||||||
|
|
||||||
bool IsUpdated () const { return m_IsUpdated; };
|
bool IsUpdated () const { return m_IsUpdated; };
|
||||||
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
||||||
bool SaveToFile (const std::string& fullPath);
|
bool SaveToFile (const std::string& fullPath);
|
||||||
|
static bool SaveToFile (const std::string& fullPath, std::shared_ptr<Buffer> buf);
|
||||||
|
|
||||||
std::shared_ptr<RouterProfile> GetProfile () const;
|
std::shared_ptr<RouterProfile> GetProfile () const;
|
||||||
void DropProfile () { m_Profile = nullptr; };
|
void DropProfile () { m_Profile = nullptr; };
|
||||||
|
bool HasProfile () const { return (bool)m_Profile; };
|
||||||
|
|
||||||
bool Update (const uint8_t * buf, size_t len);
|
bool Update (const uint8_t * buf, size_t len);
|
||||||
void DeleteBuffer () { m_Buffer = nullptr; };
|
|
||||||
bool IsNewer (const uint8_t * buf, size_t len) const;
|
bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||||
|
|
||||||
/** return true if we are in a router family and the signature is valid */
|
/** return true if we are in a router family and the signature is valid */
|
||||||
@ -295,7 +313,7 @@ namespace data
|
|||||||
RouterInfo ();
|
RouterInfo ();
|
||||||
uint8_t * GetBufferPointer (size_t offset = 0 ) { return m_Buffer->data () + offset; };
|
uint8_t * GetBufferPointer (size_t offset = 0 ) { return m_Buffer->data () + offset; };
|
||||||
void UpdateBuffer (const uint8_t * buf, size_t len);
|
void UpdateBuffer (const uint8_t * buf, size_t len);
|
||||||
void SetBufferLen (size_t len) { m_BufferLen = len; };
|
void SetBufferLen (size_t len) { if (m_Buffer) m_Buffer->SetBufferLen (len); };
|
||||||
void RefreshTimestamp ();
|
void RefreshTimestamp ();
|
||||||
CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; };
|
CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; };
|
||||||
void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
|
void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
|
||||||
@ -323,12 +341,12 @@ namespace data
|
|||||||
FamilyID m_FamilyID;
|
FamilyID m_FamilyID;
|
||||||
std::shared_ptr<const IdentityEx> m_RouterIdentity;
|
std::shared_ptr<const IdentityEx> m_RouterIdentity;
|
||||||
std::shared_ptr<Buffer> m_Buffer;
|
std::shared_ptr<Buffer> m_Buffer;
|
||||||
size_t m_BufferLen;
|
|
||||||
uint64_t m_Timestamp; // in milliseconds
|
uint64_t m_Timestamp; // in milliseconds
|
||||||
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
|
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
|
||||||
bool m_IsUpdated, m_IsUnreachable;
|
bool m_IsUpdated, m_IsUnreachable, m_IsFloodfill;
|
||||||
CompatibleTransports m_SupportedTransports, m_ReachableTransports;
|
CompatibleTransports m_SupportedTransports, m_ReachableTransports, m_PublishedTransports;
|
||||||
uint8_t m_Caps;
|
uint8_t m_Caps;
|
||||||
|
char m_BandwidthCap;
|
||||||
int m_Version;
|
int m_Version;
|
||||||
Congestion m_Congestion;
|
Congestion m_Congestion;
|
||||||
mutable std::shared_ptr<RouterProfile> m_Profile;
|
mutable std::shared_ptr<RouterProfile> m_Profile;
|
||||||
@ -347,7 +365,8 @@ namespace data
|
|||||||
void DeleteProperty (const std::string& key);
|
void DeleteProperty (const std::string& key);
|
||||||
std::string GetProperty (const std::string& key) const;
|
std::string GetProperty (const std::string& key) const;
|
||||||
void ClearProperties () override { m_Properties.clear (); };
|
void ClearProperties () override { m_Properties.clear (); };
|
||||||
|
void UpdateFloodfillProperty (bool floodfill);
|
||||||
|
|
||||||
bool AddSSU2Introducer (const Introducer& introducer, bool v4);
|
bool AddSSU2Introducer (const Introducer& introducer, bool v4);
|
||||||
bool RemoveSSU2Introducer (const IdentHash& h, bool v4);
|
bool RemoveSSU2Introducer (const IdentHash& h, bool v4);
|
||||||
|
|
||||||
|
231
libi2pd/SSU2.cpp
231
libi2pd/SSU2.cpp
@ -25,7 +25,7 @@ namespace transport
|
|||||||
m_TerminationTimer (GetService ()), m_CleanupTimer (GetService ()), m_ResendTimer (GetService ()),
|
m_TerminationTimer (GetService ()), m_CleanupTimer (GetService ()), m_ResendTimer (GetService ()),
|
||||||
m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()),
|
m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()),
|
||||||
m_IsPublished (true), m_IsSyncClockFromPeers (true), m_PendingTimeOffset (0),
|
m_IsPublished (true), m_IsSyncClockFromPeers (true), m_PendingTimeOffset (0),
|
||||||
m_IsThroughProxy (false)
|
m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), m_IsThroughProxy (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,10 +455,12 @@ namespace transport
|
|||||||
if (ident)
|
if (ident)
|
||||||
{
|
{
|
||||||
auto ret = m_SessionsByRouterHash.emplace (ident->GetIdentHash (), session);
|
auto ret = m_SessionsByRouterHash.emplace (ident->GetIdentHash (), session);
|
||||||
if (!ret.second)
|
if (!ret.second && ret.first->second != session)
|
||||||
{
|
{
|
||||||
// session already exists
|
// session already exists
|
||||||
LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists");
|
LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists");
|
||||||
|
// move unsent msgs to new session
|
||||||
|
ret.first->second->MoveSendQueue (session);
|
||||||
// terminate existing
|
// terminate existing
|
||||||
GetService ().post (std::bind (&SSU2Session::RequestTermination, ret.first->second, eSSU2TerminationReasonReplacedByNewSession));
|
GetService ().post (std::bind (&SSU2Session::RequestTermination, ret.first->second, eSSU2TerminationReasonReplacedByNewSession));
|
||||||
// update session
|
// update session
|
||||||
@ -499,17 +501,15 @@ namespace transport
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SSU2Session> SSU2Server::GetRandomPeerTestSession (
|
std::shared_ptr<SSU2Session> SSU2Server::GetRandomPeerTestSession (
|
||||||
i2p::data::RouterInfo::CompatibleTransports remoteTransports, const i2p::data::IdentHash& excluded) const
|
i2p::data::RouterInfo::CompatibleTransports remoteTransports, const i2p::data::IdentHash& excluded)
|
||||||
{
|
{
|
||||||
if (m_Sessions.empty ()) return nullptr;
|
if (m_Sessions.empty ()) return nullptr;
|
||||||
uint16_t ind;
|
int ind = m_Rng () % m_Sessions.size ();
|
||||||
RAND_bytes ((uint8_t *)&ind, sizeof (ind));
|
|
||||||
ind %= m_Sessions.size ();
|
|
||||||
auto it = m_Sessions.begin ();
|
auto it = m_Sessions.begin ();
|
||||||
std::advance (it, ind);
|
std::advance (it, ind);
|
||||||
while (it != m_Sessions.end ())
|
while (it != m_Sessions.end ())
|
||||||
{
|
{
|
||||||
if ((it->second->GetRemotePeerTestTransports () & remoteTransports) &&
|
if (it->second->IsEstablished () && (it->second->GetRemotePeerTestTransports () & remoteTransports) &&
|
||||||
it->second->GetRemoteIdentity ()->GetIdentHash () != excluded)
|
it->second->GetRemoteIdentity ()->GetIdentHash () != excluded)
|
||||||
return it->second;
|
return it->second;
|
||||||
it++;
|
it++;
|
||||||
@ -518,7 +518,7 @@ namespace transport
|
|||||||
it = m_Sessions.begin ();
|
it = m_Sessions.begin ();
|
||||||
while (it != m_Sessions.end () && ind)
|
while (it != m_Sessions.end () && ind)
|
||||||
{
|
{
|
||||||
if ((it->second->GetRemotePeerTestTransports () & remoteTransports) &&
|
if (it->second->IsEstablished () && (it->second->GetRemotePeerTestTransports () & remoteTransports) &&
|
||||||
it->second->GetRemoteIdentity ()->GetIdentHash () != excluded)
|
it->second->GetRemoteIdentity ()->GetIdentHash () != excluded)
|
||||||
return it->second;
|
return it->second;
|
||||||
it++; ind--;
|
it++; ind--;
|
||||||
@ -773,82 +773,119 @@ namespace transport
|
|||||||
auto address = session->GetAddress ();
|
auto address = session->GetAddress ();
|
||||||
if (!address) return;
|
if (!address) return;
|
||||||
session->WaitForIntroduction ();
|
session->WaitForIntroduction ();
|
||||||
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
std::vector<int> indices; int i = 0;
|
||||||
// try to find existing session first
|
// try to find existing session first
|
||||||
for (auto& it: address->ssu->introducers)
|
for (auto& it: address->ssu->introducers)
|
||||||
{
|
{
|
||||||
auto it1 = m_SessionsByRouterHash.find (it.iH);
|
if (it.iTag && ts < it.iExp)
|
||||||
if (it1 != m_SessionsByRouterHash.end ())
|
|
||||||
{
|
{
|
||||||
it1->second->Introduce (session, it.iTag);
|
auto it1 = m_SessionsByRouterHash.find (it.iH);
|
||||||
return;
|
if (it1 != m_SessionsByRouterHash.end ())
|
||||||
}
|
{
|
||||||
|
auto addr = it1->second->GetAddress ();
|
||||||
|
if (addr && addr->IsIntroducer ())
|
||||||
|
{
|
||||||
|
it1->second->Introduce (session, it.iTag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
indices.push_back(i);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
// we have to start a new session to an introducer
|
// we have to start a new session to an introducer
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
std::vector<i2p::data::IdentHash> newRouters;
|
||||||
std::shared_ptr<i2p::data::RouterInfo> r;
|
std::shared_ptr<i2p::data::RouterInfo> r;
|
||||||
|
std::shared_ptr<const i2p::data::RouterInfo::Address> addr;
|
||||||
uint32_t relayTag = 0;
|
uint32_t relayTag = 0;
|
||||||
if (!address->ssu->introducers.empty ())
|
if (!indices.empty ())
|
||||||
{
|
{
|
||||||
std::vector<int> indices;
|
|
||||||
for (int i = 0; i < (int)address->ssu->introducers.size (); i++) indices.push_back(i);
|
|
||||||
if (indices.size () > 1)
|
if (indices.size () > 1)
|
||||||
std::shuffle (indices.begin(), indices.end(), std::mt19937(std::random_device()()));
|
std::shuffle (indices.begin(), indices.end(), m_Rng);
|
||||||
|
|
||||||
for (auto i: indices)
|
for (auto ind: indices)
|
||||||
{
|
{
|
||||||
const auto& introducer = address->ssu->introducers[indices[i]];
|
const auto& introducer = address->ssu->introducers[ind];
|
||||||
if (introducer.iTag && ts < introducer.iExp)
|
// introducer is not expired, because in indices
|
||||||
{
|
r = i2p::data::netdb.FindRouter (introducer.iH);
|
||||||
r = i2p::data::netdb.FindRouter (introducer.iH);
|
if (r)
|
||||||
if (r && r->IsReachableFrom (i2p::context.GetRouterInfo ()))
|
{
|
||||||
|
if (r->IsPublishedOn (i2p::context.GetRouterInfo ().GetCompatibleTransports (false) & // outgoing
|
||||||
|
(i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)))
|
||||||
{
|
{
|
||||||
relayTag = introducer.iTag;
|
relayTag = introducer.iTag;
|
||||||
if (relayTag) break;
|
addr = address->IsV6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address ();
|
||||||
|
if (addr && addr->IsIntroducer () && !addr->host.is_unspecified () && addr->port &&
|
||||||
|
!i2p::transport::transports.IsInReservedRange(addr->host))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// address is invalid or not intrudcer, try another SSU2 address if exists
|
||||||
|
if (address->IsV4 ())
|
||||||
|
{
|
||||||
|
if (i2p::context.SupportsV6 ())
|
||||||
|
addr = r->GetSSU2V6Address ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (i2p::context.SupportsV4 ())
|
||||||
|
addr = r->GetSSU2V4Address ();
|
||||||
|
}
|
||||||
|
if (addr && addr->IsIntroducer () && !addr->host.is_unspecified () && addr->port &&
|
||||||
|
!i2p::transport::transports.IsInReservedRange(addr->host))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// all addresses are invalid, try next introducer
|
||||||
|
relayTag = 0;
|
||||||
|
addr = nullptr;
|
||||||
|
r = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
r = nullptr;
|
||||||
|
}
|
||||||
|
else if (!i2p::data::IsRouterBanned (introducer.iH))
|
||||||
|
newRouters.push_back (introducer.iH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
if (relayTag)
|
if (relayTag && addr)
|
||||||
{
|
{
|
||||||
// introducer and tag found connect to it through SSU2
|
// introducer and tag found connect to it through SSU2
|
||||||
auto addr = address->IsV6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address ();
|
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (addr->host, addr->port));
|
||||||
if (addr)
|
if (!s)
|
||||||
{
|
{
|
||||||
bool isValidEndpoint = !addr->host.is_unspecified () && addr->port &&
|
s = std::make_shared<SSU2Session> (*this, r, addr);
|
||||||
!i2p::transport::transports.IsInReservedRange(addr->host);
|
s->SetOnEstablished ([session, s, relayTag]() { s->Introduce (session, relayTag); });
|
||||||
if (isValidEndpoint)
|
s->Connect ();
|
||||||
{
|
}
|
||||||
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (addr->host, addr->port));
|
else
|
||||||
if (!s)
|
{
|
||||||
{
|
auto onEstablished = s->GetOnEstablished ();
|
||||||
s = std::make_shared<SSU2Session> (*this, r, addr);
|
if (onEstablished)
|
||||||
s->SetOnEstablished ([session, s, relayTag]() { s->Introduce (session, relayTag); });
|
s->SetOnEstablished ([session, s, relayTag, onEstablished]()
|
||||||
s->Connect ();
|
{
|
||||||
}
|
onEstablished ();
|
||||||
else
|
s->Introduce (session, relayTag);
|
||||||
{
|
});
|
||||||
auto onEstablished = s->GetOnEstablished ();
|
else
|
||||||
if (onEstablished)
|
s->SetOnEstablished ([session, s, relayTag]() {s->Introduce (session, relayTag); });
|
||||||
s->SetOnEstablished ([session, s, relayTag, onEstablished]()
|
|
||||||
{
|
|
||||||
onEstablished ();
|
|
||||||
s->Introduce (session, relayTag);
|
|
||||||
});
|
|
||||||
else
|
|
||||||
s->SetOnEstablished ([session, s, relayTag]() {s->Introduce (session, relayTag); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
session->Done ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// introducers not found, try to request them
|
// introducers not found, try to request them
|
||||||
for (auto& it: address->ssu->introducers)
|
for (auto& it: newRouters)
|
||||||
if (it.iTag && ts < it.iExp)
|
i2p::data::netdb.RequestDestination (it);
|
||||||
i2p::data::netdb.RequestDestination (it.iH);
|
session->Done (); // don't wait for connect timeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -877,7 +914,8 @@ namespace transport
|
|||||||
|
|
||||||
void SSU2Server::ScheduleTermination ()
|
void SSU2Server::ScheduleTermination ()
|
||||||
{
|
{
|
||||||
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(SSU2_TERMINATION_CHECK_TIMEOUT));
|
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(
|
||||||
|
SSU2_TERMINATION_CHECK_TIMEOUT + m_Rng () % SSU2_TERMINATION_CHECK_TIMEOUT_VARIANCE));
|
||||||
m_TerminationTimer.async_wait (std::bind (&SSU2Server::HandleTerminationTimer,
|
m_TerminationTimer.async_wait (std::bind (&SSU2Server::HandleTerminationTimer,
|
||||||
this, std::placeholders::_1));
|
this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
@ -973,8 +1011,9 @@ namespace transport
|
|||||||
|
|
||||||
void SSU2Server::ScheduleResend (bool more)
|
void SSU2Server::ScheduleResend (bool more)
|
||||||
{
|
{
|
||||||
m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ? SSU2_RESEND_CHECK_MORE_TIMEOUT :
|
m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ?
|
||||||
(SSU2_RESEND_CHECK_TIMEOUT + rand () % SSU2_RESEND_CHECK_TIMEOUT_VARIANCE)));
|
(SSU2_RESEND_CHECK_MORE_TIMEOUT + m_Rng () % SSU2_RESEND_CHECK_MORE_TIMEOUT_VARIANCE):
|
||||||
|
(SSU2_RESEND_CHECK_TIMEOUT + m_Rng () % SSU2_RESEND_CHECK_TIMEOUT_VARIANCE)));
|
||||||
m_ResendTimer.async_wait (std::bind (&SSU2Server::HandleResendTimer,
|
m_ResendTimer.async_wait (std::bind (&SSU2Server::HandleResendTimer,
|
||||||
this, std::placeholders::_1));
|
this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
@ -987,7 +1026,8 @@ namespace transport
|
|||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
for (auto it: m_Sessions)
|
for (auto it: m_Sessions)
|
||||||
{
|
{
|
||||||
resentPacketsNum += it.second->Resend (ts);
|
if (ts >= it.second->GetLastResendTime () + SSU2_RESEND_CHECK_TIMEOUT)
|
||||||
|
resentPacketsNum += it.second->Resend (ts);
|
||||||
if (resentPacketsNum > SSU2_MAX_RESEND_PACKETS) break;
|
if (resentPacketsNum > SSU2_MAX_RESEND_PACKETS) break;
|
||||||
}
|
}
|
||||||
for (auto it: m_PendingOutgoingSessions)
|
for (auto it: m_PendingOutgoingSessions)
|
||||||
@ -1044,30 +1084,32 @@ namespace transport
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<SSU2Session> > SSU2Server::FindIntroducers (int maxNumIntroducers,
|
std::vector<std::shared_ptr<SSU2Session> > SSU2Server::FindIntroducers (int maxNumIntroducers,
|
||||||
bool v4, const std::set<i2p::data::IdentHash>& excluded) const
|
bool v4, const std::unordered_set<i2p::data::IdentHash>& excluded) const
|
||||||
{
|
{
|
||||||
std::list<std::shared_ptr<SSU2Session> > ret;
|
std::vector<std::shared_ptr<SSU2Session> > ret;
|
||||||
|
if (maxNumIntroducers <= 0) return ret;
|
||||||
|
auto newer = [](const std::shared_ptr<SSU2Session>& s1, const std::shared_ptr<SSU2Session>& s2) -> bool
|
||||||
|
{
|
||||||
|
auto t1 = s1->GetCreationTime (), t2 = s2->GetCreationTime ();
|
||||||
|
return (t1 != t2) ? (t1 > t2) : (s1->GetConnID () > s2->GetConnID ());
|
||||||
|
};
|
||||||
|
std::set<std::shared_ptr<SSU2Session>, decltype (newer)> introducers(newer);
|
||||||
for (const auto& s : m_Sessions)
|
for (const auto& s : m_Sessions)
|
||||||
{
|
{
|
||||||
if (s.second->IsEstablished () && (s.second->GetRelayTag () && s.second->IsOutgoing ()) &&
|
if (s.second->IsEstablished () && (s.second->GetRelayTag () && s.second->IsOutgoing ()) &&
|
||||||
!excluded.count (s.second->GetRemoteIdentity ()->GetIdentHash ()) &&
|
!excluded.count (s.second->GetRemoteIdentity ()->GetIdentHash ()) &&
|
||||||
((v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V4)) ||
|
((v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V4)) ||
|
||||||
(!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6))))
|
(!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6))))
|
||||||
ret.push_back (s.second);
|
introducers.insert (s.second);
|
||||||
}
|
}
|
||||||
if ((int)ret.size () > maxNumIntroducers)
|
int i = 0;
|
||||||
|
for (auto it: introducers)
|
||||||
{
|
{
|
||||||
// shink ret randomly
|
ret.push_back (it);
|
||||||
int sz = ret.size () - maxNumIntroducers;
|
i++;
|
||||||
for (int i = 0; i < sz; i++)
|
if (i >= maxNumIntroducers) break;
|
||||||
{
|
}
|
||||||
auto ind = rand () % ret.size ();
|
|
||||||
auto it = ret.begin ();
|
|
||||||
std::advance (it, ind);
|
|
||||||
ret.erase (it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1076,7 +1118,7 @@ namespace transport
|
|||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
std::list<i2p::data::IdentHash> newList, impliedList;
|
std::list<i2p::data::IdentHash> newList, impliedList;
|
||||||
auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
|
auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::unordered_set<i2p::data::IdentHash> excluded;
|
||||||
for (const auto& it : introducers)
|
for (const auto& it : introducers)
|
||||||
{
|
{
|
||||||
std::shared_ptr<SSU2Session> session;
|
std::shared_ptr<SSU2Session> session;
|
||||||
@ -1086,22 +1128,21 @@ namespace transport
|
|||||||
session = it1->second;
|
session = it1->second;
|
||||||
excluded.insert (it);
|
excluded.insert (it);
|
||||||
}
|
}
|
||||||
if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) // still session with introducer?
|
if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing () && // still session with introducer?
|
||||||
{
|
ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
|
||||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
|
{
|
||||||
|
session->SendKeepAlive ();
|
||||||
|
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
|
||||||
|
newList.push_back (it);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
session->SendKeepAlive ();
|
impliedList.push_back (it); // keep in introducers list, but not publish
|
||||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
|
session = nullptr;
|
||||||
newList.push_back (it);
|
}
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
impliedList.push_back (it); // keep in introducers list, but not publish
|
session = nullptr;
|
||||||
session = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
session = nullptr;
|
|
||||||
}
|
|
||||||
if (!session)
|
if (!session)
|
||||||
i2p::context.RemoveSSU2Introducer (it, v4);
|
i2p::context.RemoveSSU2Introducer (it, v4);
|
||||||
}
|
}
|
||||||
@ -1180,7 +1221,7 @@ namespace transport
|
|||||||
if (m_IsPublished)
|
if (m_IsPublished)
|
||||||
{
|
{
|
||||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
|
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
|
||||||
SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
|
SSU2_KEEP_ALIVE_INTERVAL + m_Rng () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
|
||||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||||
this, std::placeholders::_1, true));
|
this, std::placeholders::_1, true));
|
||||||
}
|
}
|
||||||
@ -1194,7 +1235,7 @@ namespace transport
|
|||||||
i2p::context.ClearSSU2Introducers (true);
|
i2p::context.ClearSSU2Introducers (true);
|
||||||
m_Introducers.clear ();
|
m_Introducers.clear ();
|
||||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
|
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
|
||||||
(SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
|
(SSU2_KEEP_ALIVE_INTERVAL + m_Rng () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
|
||||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||||
this, std::placeholders::_1, true));
|
this, std::placeholders::_1, true));
|
||||||
}
|
}
|
||||||
@ -1205,7 +1246,7 @@ namespace transport
|
|||||||
if (m_IsPublished)
|
if (m_IsPublished)
|
||||||
{
|
{
|
||||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
|
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
|
||||||
SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
|
SSU2_KEEP_ALIVE_INTERVAL + m_Rng () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
|
||||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||||
this, std::placeholders::_1, false));
|
this, std::placeholders::_1, false));
|
||||||
}
|
}
|
||||||
@ -1219,7 +1260,7 @@ namespace transport
|
|||||||
i2p::context.ClearSSU2Introducers (false);
|
i2p::context.ClearSSU2Introducers (false);
|
||||||
m_IntroducersV6.clear ();
|
m_IntroducersV6.clear ();
|
||||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
|
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
|
||||||
(SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
|
(SSU2_KEEP_ALIVE_INTERVAL + m_Rng () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
|
||||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||||
this, std::placeholders::_1, false));
|
this, std::placeholders::_1, false));
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,10 @@
|
|||||||
#define SSU2_H__
|
#define SSU2_H__
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <random>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "SSU2Session.h"
|
#include "SSU2Session.h"
|
||||||
#include "Socks5.h"
|
#include "Socks5.h"
|
||||||
@ -19,11 +22,13 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
const int SSU2_TERMINATION_CHECK_TIMEOUT = 25; // in seconds
|
const int SSU2_TERMINATION_CHECK_TIMEOUT = 23; // in seconds
|
||||||
|
const int SSU2_TERMINATION_CHECK_TIMEOUT_VARIANCE = 5; // in seconds
|
||||||
const int SSU2_CLEANUP_INTERVAL = 72; // in seconds
|
const int SSU2_CLEANUP_INTERVAL = 72; // in seconds
|
||||||
const int SSU2_RESEND_CHECK_TIMEOUT = 40; // in milliseconds
|
const int SSU2_RESEND_CHECK_TIMEOUT = 40; // in milliseconds
|
||||||
const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 10; // in milliseconds
|
const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 10; // in milliseconds
|
||||||
const int SSU2_RESEND_CHECK_MORE_TIMEOUT = 10; // in milliseconds
|
const int SSU2_RESEND_CHECK_MORE_TIMEOUT = 4; // in milliseconds
|
||||||
|
const int SSU2_RESEND_CHECK_MORE_TIMEOUT_VARIANCE = 9; // in milliseconds
|
||||||
const size_t SSU2_MAX_RESEND_PACKETS = 128; // packets to resend at the time
|
const size_t SSU2_MAX_RESEND_PACKETS = 128; // packets to resend at the time
|
||||||
const uint64_t SSU2_SOCKET_MIN_BUFFER_SIZE = 128 * 1024;
|
const uint64_t SSU2_SOCKET_MIN_BUFFER_SIZE = 128 * 1024;
|
||||||
const uint64_t SSU2_SOCKET_MAX_BUFFER_SIZE = 4 * 1024 * 1024;
|
const uint64_t SSU2_SOCKET_MAX_BUFFER_SIZE = 4 * 1024 * 1024;
|
||||||
@ -67,6 +72,8 @@ namespace transport
|
|||||||
bool UsesProxy () const { return m_IsThroughProxy; };
|
bool UsesProxy () const { return m_IsThroughProxy; };
|
||||||
bool IsSupported (const boost::asio::ip::address& addr) const;
|
bool IsSupported (const boost::asio::ip::address& addr) const;
|
||||||
uint16_t GetPort (bool v4) const;
|
uint16_t GetPort (bool v4) const;
|
||||||
|
std::mt19937& GetRng () { return m_Rng; }
|
||||||
|
bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; }
|
||||||
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
|
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
|
||||||
void AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from);
|
void AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from);
|
||||||
|
|
||||||
@ -78,7 +85,7 @@ namespace transport
|
|||||||
std::shared_ptr<SSU2Session> FindSession (const i2p::data::IdentHash& ident) const;
|
std::shared_ptr<SSU2Session> FindSession (const i2p::data::IdentHash& ident) const;
|
||||||
std::shared_ptr<SSU2Session> FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const;
|
std::shared_ptr<SSU2Session> FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const;
|
||||||
std::shared_ptr<SSU2Session> GetRandomPeerTestSession (i2p::data::RouterInfo::CompatibleTransports remoteTransports,
|
std::shared_ptr<SSU2Session> GetRandomPeerTestSession (i2p::data::RouterInfo::CompatibleTransports remoteTransports,
|
||||||
const i2p::data::IdentHash& excluded) const;
|
const i2p::data::IdentHash& excluded);
|
||||||
|
|
||||||
void AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay);
|
void AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay);
|
||||||
void RemoveRelay (uint32_t tag);
|
void RemoveRelay (uint32_t tag);
|
||||||
@ -125,8 +132,8 @@ namespace transport
|
|||||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void ConnectThroughIntroducer (std::shared_ptr<SSU2Session> session);
|
void ConnectThroughIntroducer (std::shared_ptr<SSU2Session> session);
|
||||||
std::list<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers,
|
std::vector<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers,
|
||||||
bool v4, const std::set<i2p::data::IdentHash>& excluded) const;
|
bool v4, const std::unordered_set<i2p::data::IdentHash>& excluded) const;
|
||||||
void UpdateIntroducers (bool v4);
|
void UpdateIntroducers (bool v4);
|
||||||
void ScheduleIntroducersUpdateTimer ();
|
void ScheduleIntroducersUpdateTimer ();
|
||||||
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4);
|
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4);
|
||||||
@ -166,6 +173,7 @@ namespace transport
|
|||||||
bool m_IsSyncClockFromPeers;
|
bool m_IsSyncClockFromPeers;
|
||||||
int64_t m_PendingTimeOffset; // during peer test
|
int64_t m_PendingTimeOffset; // during peer test
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> m_PendingTimeOffsetFrom;
|
std::shared_ptr<const i2p::data::IdentityEx> m_PendingTimeOffsetFrom;
|
||||||
|
std::mt19937 m_Rng;
|
||||||
|
|
||||||
// proxy
|
// proxy
|
||||||
bool m_IsThroughProxy;
|
bool m_IsThroughProxy;
|
||||||
|
@ -90,7 +90,8 @@ namespace transport
|
|||||||
m_WindowSize (SSU2_MIN_WINDOW_SIZE),
|
m_WindowSize (SSU2_MIN_WINDOW_SIZE),
|
||||||
m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0),m_ConnectTimer (server.GetService ()),
|
m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0),m_ConnectTimer (server.GetService ()),
|
||||||
m_TerminationReason (eSSU2TerminationReasonNormalClose),
|
m_TerminationReason (eSSU2TerminationReasonNormalClose),
|
||||||
m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size
|
m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32), // min size
|
||||||
|
m_LastResendTime (0), m_LastResendAttemptTime (0)
|
||||||
{
|
{
|
||||||
m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState);
|
m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState);
|
||||||
if (in_RemoteRouter && m_Address)
|
if (in_RemoteRouter && m_Address)
|
||||||
@ -143,7 +144,7 @@ namespace transport
|
|||||||
|
|
||||||
void SSU2Session::HandleConnectTimer (const boost::system::error_code& ecode)
|
void SSU2Session::HandleConnectTimer (const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (!ecode)
|
if (!ecode && m_State != eSSU2SessionStateTerminated)
|
||||||
{
|
{
|
||||||
// timeout expired
|
// timeout expired
|
||||||
if (m_State == eSSU2SessionStateIntroduced) // WaitForIntroducer
|
if (m_State == eSSU2SessionStateIntroduced) // WaitForIntroducer
|
||||||
@ -312,6 +313,7 @@ namespace transport
|
|||||||
m_SentHandshakePacket.reset (nullptr);
|
m_SentHandshakePacket.reset (nullptr);
|
||||||
m_ConnectTimer.cancel ();
|
m_ConnectTimer.cancel ();
|
||||||
SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
|
SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
|
||||||
|
SendQueue ();
|
||||||
transports.PeerConnected (shared_from_this ());
|
transports.PeerConnected (shared_from_this ());
|
||||||
if (m_OnEstablished)
|
if (m_OnEstablished)
|
||||||
{
|
{
|
||||||
@ -336,7 +338,7 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (!s->IsEstablished ()) return;
|
if (!s->IsEstablished ()) return;
|
||||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
||||||
size_t payloadSize = s->CreateRouterInfoBlock (payload, s->m_MaxPayloadSize - 32, i2p::context.GetSharedRouterInfo ());
|
size_t payloadSize = s->CreateRouterInfoBlock (payload, s->m_MaxPayloadSize - 32, i2p::context.CopyRouterInfoBuffer ());
|
||||||
if (payloadSize)
|
if (payloadSize)
|
||||||
{
|
{
|
||||||
if (payloadSize < s->m_MaxPayloadSize)
|
if (payloadSize < s->m_MaxPayloadSize)
|
||||||
@ -381,16 +383,33 @@ namespace transport
|
|||||||
m_SendQueue.push_back (std::move (it));
|
m_SendQueue.push_back (std::move (it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SendQueue ();
|
if (IsEstablished ())
|
||||||
|
{
|
||||||
if (m_SendQueue.size () > 0) // windows is full
|
SendQueue ();
|
||||||
Resend (i2p::util::GetMillisecondsSinceEpoch ());
|
if (m_SendQueue.size () > 0) // windows is full
|
||||||
|
Resend (i2p::util::GetMillisecondsSinceEpoch ());
|
||||||
|
}
|
||||||
SetSendQueueSize (m_SendQueue.size ());
|
SetSendQueueSize (m_SendQueue.size ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSU2Session::MoveSendQueue (std::shared_ptr<SSU2Session> other)
|
||||||
|
{
|
||||||
|
if (!other || m_SendQueue.empty ()) return;
|
||||||
|
std::vector<std::shared_ptr<I2NPMessage> > msgs;
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
for (auto it: m_SendQueue)
|
||||||
|
if (!it->IsExpired (ts))
|
||||||
|
msgs.push_back (it);
|
||||||
|
else
|
||||||
|
it->Drop ();
|
||||||
|
m_SendQueue.clear ();
|
||||||
|
if (!msgs.empty ())
|
||||||
|
other->PostI2NPMessages (msgs);
|
||||||
|
}
|
||||||
|
|
||||||
bool SSU2Session::SendQueue ()
|
bool SSU2Session::SendQueue ()
|
||||||
{
|
{
|
||||||
if (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize)
|
if (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize && IsEstablished ())
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
uint64_t mts = i2p::util::GetMonotonicMicroseconds ();
|
uint64_t mts = i2p::util::GetMonotonicMicroseconds ();
|
||||||
@ -497,7 +516,7 @@ namespace transport
|
|||||||
else
|
else
|
||||||
extraSize -= packet->payloadSize;
|
extraSize -= packet->payloadSize;
|
||||||
}
|
}
|
||||||
size_t offset = extraSize > 0 ? (rand () % extraSize) : 0;
|
size_t offset = extraSize > 0 ? (m_Server.GetRng ()() % extraSize) : 0;
|
||||||
if (offset + packet->payloadSize >= m_MaxPayloadSize) offset = 0;
|
if (offset + packet->payloadSize >= m_MaxPayloadSize) offset = 0;
|
||||||
auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - offset - packet->payloadSize, msg);
|
auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - offset - packet->payloadSize, msg);
|
||||||
if (!size) return false;
|
if (!size) return false;
|
||||||
@ -509,7 +528,7 @@ namespace transport
|
|||||||
uint8_t fragmentNum = 0;
|
uint8_t fragmentNum = 0;
|
||||||
while (msg->offset < msg->len)
|
while (msg->offset < msg->len)
|
||||||
{
|
{
|
||||||
offset = extraSize > 0 ? (rand () % extraSize) : 0;
|
offset = extraSize > 0 ? (m_Server.GetRng ()() % extraSize) : 0;
|
||||||
packet = m_Server.GetSentPacketsPool ().AcquireShared ();
|
packet = m_Server.GetSentPacketsPool ().AcquireShared ();
|
||||||
packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - offset, msg, fragmentNum, msgID);
|
packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - offset, msg, fragmentNum, msgID);
|
||||||
extraSize -= offset;
|
extraSize -= offset;
|
||||||
@ -529,6 +548,8 @@ namespace transport
|
|||||||
|
|
||||||
size_t SSU2Session::Resend (uint64_t ts)
|
size_t SSU2Session::Resend (uint64_t ts)
|
||||||
{
|
{
|
||||||
|
if (ts + SSU2_RESEND_ATTEMPT_MIN_INTERVAL < m_LastResendAttemptTime) return 0;
|
||||||
|
m_LastResendAttemptTime = ts;
|
||||||
// resend handshake packet
|
// resend handshake packet
|
||||||
if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->sendTime + SSU2_HANDSHAKE_RESEND_INTERVAL)
|
if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->sendTime + SSU2_HANDSHAKE_RESEND_INTERVAL)
|
||||||
{
|
{
|
||||||
@ -565,6 +586,7 @@ namespace transport
|
|||||||
it++;
|
it++;
|
||||||
if (!resentPackets.empty ())
|
if (!resentPackets.empty ())
|
||||||
{
|
{
|
||||||
|
m_LastResendTime = ts;
|
||||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
m_SentPackets.merge (resentPackets);
|
m_SentPackets.merge (resentPackets);
|
||||||
#else
|
#else
|
||||||
@ -660,10 +682,14 @@ namespace transport
|
|||||||
size_t payloadSize = 7;
|
size_t payloadSize = 7;
|
||||||
if (GetRouterStatus () == eRouterStatusFirewalled && m_Address->IsIntroducer ())
|
if (GetRouterStatus () == eRouterStatusFirewalled && m_Address->IsIntroducer ())
|
||||||
{
|
{
|
||||||
// relay tag request
|
if (!m_Server.IsMaxNumIntroducers (m_RemoteEndpoint.address ().is_v4 ()) ||
|
||||||
payload[payloadSize] = eSSU2BlkRelayTagRequest;
|
m_Server.GetRng ()() & 0x01) // request tag with probability 1/2 if we have enough introducers
|
||||||
memset (payload + payloadSize + 1, 0, 2); // size = 0
|
{
|
||||||
payloadSize += 3;
|
// relay tag request
|
||||||
|
payload[payloadSize] = eSSU2BlkRelayTagRequest;
|
||||||
|
memset (payload + payloadSize + 1, 0, 2); // size = 0
|
||||||
|
payloadSize += 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
payloadSize += CreatePaddingBlock (payload + payloadSize, 40 - payloadSize, 1);
|
payloadSize += CreatePaddingBlock (payload + payloadSize, 40 - payloadSize, 1);
|
||||||
// KDF for session request
|
// KDF for session request
|
||||||
@ -881,12 +907,12 @@ namespace transport
|
|||||||
// payload
|
// payload
|
||||||
size_t maxPayloadSize = m_MaxPayloadSize - 48; // for part 2, 48 is part1
|
size_t maxPayloadSize = m_MaxPayloadSize - 48; // for part 2, 48 is part1
|
||||||
uint8_t * payload = m_SentHandshakePacket->payload;
|
uint8_t * payload = m_SentHandshakePacket->payload;
|
||||||
size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ());
|
size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ());
|
||||||
if (!payloadSize)
|
if (!payloadSize)
|
||||||
{
|
{
|
||||||
// split by two fragments
|
// split by two fragments
|
||||||
maxPayloadSize += m_MaxPayloadSize;
|
maxPayloadSize += m_MaxPayloadSize;
|
||||||
payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ());
|
payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ());
|
||||||
header.h.flags[0] = 0x02; // frag 0, total fragments 2
|
header.h.flags[0] = 0x02; // frag 0, total fragments 2
|
||||||
// TODO: check if we need more fragments
|
// TODO: check if we need more fragments
|
||||||
}
|
}
|
||||||
@ -914,7 +940,7 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (payloadSize > m_MaxPayloadSize - 48)
|
if (payloadSize > m_MaxPayloadSize - 48)
|
||||||
{
|
{
|
||||||
payloadSize = m_MaxPayloadSize - 48 - (rand () % 16);
|
payloadSize = m_MaxPayloadSize - 48 - (m_Server.GetRng ()() % 16);
|
||||||
if (m_SentHandshakePacket->payloadSize - payloadSize < 24)
|
if (m_SentHandshakePacket->payloadSize - payloadSize < 24)
|
||||||
payloadSize -= 24;
|
payloadSize -= 24;
|
||||||
}
|
}
|
||||||
@ -1101,6 +1127,23 @@ namespace transport
|
|||||||
LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is from future for ", (ri->GetTimestamp () - ts)/1000LL, " seconds");
|
LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is from future for ", (ri->GetTimestamp () - ts)/1000LL, " seconds");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// update RouterInfo in netdb
|
||||||
|
auto ri1 = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // ri points to one from netdb now
|
||||||
|
if (!ri1)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "SSU2: Couldn't update RouterInfo from SessionConfirmed in netdb");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::shared_ptr<i2p::data::RouterProfile> profile; // not null if older
|
||||||
|
if (ri->GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ())
|
||||||
|
{
|
||||||
|
// received RouterInfo is older than one in netdb
|
||||||
|
profile = i2p::data::GetRouterProfile (ri->GetIdentHash ()); // retrieve profile
|
||||||
|
if (profile && profile->IsDuplicated ())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ri = ri1;
|
||||||
|
|
||||||
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address ();
|
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address ();
|
||||||
if (!m_Address || memcmp (S, m_Address->s, 32))
|
if (!m_Address || memcmp (S, m_Address->s, 32))
|
||||||
{
|
{
|
||||||
@ -1111,15 +1154,11 @@ namespace transport
|
|||||||
(!m_RemoteEndpoint.address ().is_v6 () ||
|
(!m_RemoteEndpoint.address ().is_v6 () ||
|
||||||
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), m_Address->host.to_v6 ().to_bytes ().data (), 8))) // temporary address
|
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), m_Address->host.to_v6 ().to_bytes ().data (), 8))) // temporary address
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "SSU2: Host mismatch between published address ", m_Address->host,
|
if (profile) // older router?
|
||||||
" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
profile->Duplicated (); // mark router as duplicated in profile
|
||||||
return false;
|
else
|
||||||
}
|
LogPrint (eLogError, "SSU2: Host mismatch between published address ", m_Address->host,
|
||||||
// update RouterInfo in netdb
|
" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
||||||
ri = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // ri points to one from netdb now
|
|
||||||
if (!ri)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU2: Couldn't update RouterInfo from SessionConfirmed in netdb");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SetRemoteIdentity (ri->GetRouterIdentity ());
|
SetRemoteIdentity (ri->GetRouterIdentity ());
|
||||||
@ -1551,14 +1590,9 @@ namespace transport
|
|||||||
LogPrint (eLogDebug, "SSU2: Options");
|
LogPrint (eLogDebug, "SSU2: Options");
|
||||||
break;
|
break;
|
||||||
case eSSU2BlkRouterInfo:
|
case eSSU2BlkRouterInfo:
|
||||||
{
|
|
||||||
// not from SessionConfirmed, we must add it instantly to use in next block
|
|
||||||
LogPrint (eLogDebug, "SSU2: RouterInfo");
|
LogPrint (eLogDebug, "SSU2: RouterInfo");
|
||||||
auto ri = ExtractRouterInfo (buf + offset, size);
|
HandleRouterInfo (buf + offset, size);
|
||||||
if (ri)
|
break;
|
||||||
i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // TODO: add ri
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case eSSU2BlkI2NPMessage:
|
case eSSU2BlkI2NPMessage:
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SSU2: I2NP message");
|
LogPrint (eLogDebug, "SSU2: I2NP message");
|
||||||
@ -1633,8 +1667,12 @@ namespace transport
|
|||||||
LogPrint (eLogDebug, "SSU2: RelayTagRequest");
|
LogPrint (eLogDebug, "SSU2: RelayTagRequest");
|
||||||
if (!m_RelayTag)
|
if (!m_RelayTag)
|
||||||
{
|
{
|
||||||
RAND_bytes ((uint8_t *)&m_RelayTag, 4);
|
auto addr = FindLocalAddress ();
|
||||||
m_Server.AddRelay (m_RelayTag, shared_from_this ());
|
if (addr && addr->IsIntroducer ())
|
||||||
|
{
|
||||||
|
RAND_bytes ((uint8_t *)&m_RelayTag, 4);
|
||||||
|
m_Server.AddRelay (m_RelayTag, shared_from_this ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case eSSU2BlkRelayTag:
|
case eSSU2BlkRelayTag:
|
||||||
@ -1714,6 +1752,32 @@ namespace transport
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSU2Session::HandleRouterInfo (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
auto ri = ExtractRouterInfo (buf, len);
|
||||||
|
if (ri)
|
||||||
|
{
|
||||||
|
// not from SessionConfirmed, we must add it instantly to use in next block
|
||||||
|
auto newRi = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // TODO: add ri
|
||||||
|
if (newRi)
|
||||||
|
{
|
||||||
|
auto remoteIdentity = GetRemoteIdentity ();
|
||||||
|
if (remoteIdentity && remoteIdentity->GetIdentHash () == newRi->GetIdentHash ())
|
||||||
|
{
|
||||||
|
// peer's RouterInfo update
|
||||||
|
SetRemoteIdentity (newRi->GetIdentity ());
|
||||||
|
auto address = m_RemoteEndpoint.address ().is_v6 () ? newRi->GetSSU2V6Address () : newRi->GetSSU2V4Address ();
|
||||||
|
if (address)
|
||||||
|
{
|
||||||
|
m_Address = address;
|
||||||
|
if (IsOutgoing () && m_RelayTag && !address->IsIntroducer ())
|
||||||
|
m_RelayTag = 0; // not longer introducer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SSU2Session::HandleAck (const uint8_t * buf, size_t len)
|
void SSU2Session::HandleAck (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (m_State == eSSU2SessionStateSessionConfirmedSent)
|
if (m_State == eSSU2SessionStateSessionConfirmedSent)
|
||||||
@ -2454,6 +2518,8 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (m_Address)
|
if (m_Address)
|
||||||
return i2p::context.GetRouterInfo ().GetSSU2Address (m_Address->IsV4 ());
|
return i2p::context.GetRouterInfo ().GetSSU2Address (m_Address->IsV4 ());
|
||||||
|
else if (!m_RemoteEndpoint.address ().is_unspecified ())
|
||||||
|
return i2p::context.GetRouterInfo ().GetSSU2Address (m_RemoteEndpoint.address ().is_v4 ());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2535,27 +2601,34 @@ namespace transport
|
|||||||
|
|
||||||
size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r)
|
size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r)
|
||||||
{
|
{
|
||||||
if (!r || !r->GetBuffer () || len < 5) return 0;
|
if (!r || len < 5) return 0;
|
||||||
|
return CreateRouterInfoBlock (buf, len, r->GetSharedBuffer ());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo::Buffer> riBuffer)
|
||||||
|
{
|
||||||
|
if (!riBuffer || len < 5) return 0;
|
||||||
buf[0] = eSSU2BlkRouterInfo;
|
buf[0] = eSSU2BlkRouterInfo;
|
||||||
size_t size = r->GetBufferLen ();
|
size_t size = riBuffer->GetBufferLen ();
|
||||||
if (size + 5 < len)
|
if (size + 5 < len)
|
||||||
{
|
{
|
||||||
memcpy (buf + 5, r->GetBuffer (), size);
|
memcpy (buf + 5, riBuffer->data (), size);
|
||||||
buf[3] = 0; // flag
|
buf[3] = 0; // flag
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
i2p::data::GzipDeflator deflator;
|
i2p::data::GzipDeflator deflator;
|
||||||
deflator.SetCompressionLevel (9);
|
deflator.SetCompressionLevel (9);
|
||||||
size = deflator.Deflate (r->GetBuffer (), r->GetBufferLen (), buf + 5, len - 5);
|
size = deflator.Deflate (riBuffer->data (), riBuffer->GetBufferLen (), buf + 5, len - 5);
|
||||||
if (!size) return 0; // doesn't fit
|
if (!size) return 0; // doesn't fit
|
||||||
buf[3] = SSU2_ROUTER_INFO_FLAG_GZIP; // flag
|
buf[3] = SSU2_ROUTER_INFO_FLAG_GZIP; // flag
|
||||||
}
|
}
|
||||||
htobe16buf (buf + 1, size + 2); // size
|
htobe16buf (buf + 1, size + 2); // size
|
||||||
buf[4] = 1; // frag
|
buf[4] = 1; // frag
|
||||||
return size + 5;
|
return size + 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t SSU2Session::CreateAckBlock (uint8_t * buf, size_t len)
|
size_t SSU2Session::CreateAckBlock (uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (len < 8) return 0;
|
if (len < 8) return 0;
|
||||||
@ -2668,7 +2741,7 @@ namespace transport
|
|||||||
size_t SSU2Session::CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize)
|
size_t SSU2Session::CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize)
|
||||||
{
|
{
|
||||||
if (len < 3 || len < minSize) return 0;
|
if (len < 3 || len < minSize) return 0;
|
||||||
size_t paddingSize = rand () & 0x0F; // 0 - 15
|
size_t paddingSize = m_Server.GetRng ()() & 0x0F; // 0 - 15
|
||||||
if (paddingSize + 3 > len) paddingSize = len - 3;
|
if (paddingSize + 3 > len) paddingSize = len - 3;
|
||||||
else if (paddingSize + 3 < minSize) paddingSize = minSize - 3;
|
else if (paddingSize + 3 < minSize) paddingSize = minSize - 3;
|
||||||
buf[0] = eSSU2BlkPadding;
|
buf[0] = eSSU2BlkPadding;
|
||||||
@ -2954,7 +3027,7 @@ namespace transport
|
|||||||
{
|
{
|
||||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
||||||
payload[0] = eSSU2BlkPathChallenge;
|
payload[0] = eSSU2BlkPathChallenge;
|
||||||
size_t len = rand () % (m_MaxPayloadSize - 3);
|
size_t len = m_Server.GetRng ()() % (m_MaxPayloadSize - 3);
|
||||||
htobe16buf (payload + 1, len);
|
htobe16buf (payload + 1, len);
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
{
|
{
|
||||||
@ -3060,6 +3133,8 @@ namespace transport
|
|||||||
m_Handler.Flush ();
|
m_Handler.Flush ();
|
||||||
m_IsDataReceived = false;
|
m_IsDataReceived = false;
|
||||||
}
|
}
|
||||||
|
else if (!sent && !m_SentPackets.empty ()) // if only acks received, nothing sent and we still have something to resend
|
||||||
|
Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ namespace transport
|
|||||||
const size_t SSU2_MIN_PACKET_SIZE = 1280;
|
const size_t SSU2_MIN_PACKET_SIZE = 1280;
|
||||||
const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in milliseconds
|
const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in milliseconds
|
||||||
const int SSU2_MAX_NUM_RESENDS = 5;
|
const int SSU2_MAX_NUM_RESENDS = 5;
|
||||||
|
const int SSU2_RESEND_ATTEMPT_MIN_INTERVAL = 3; // in milliseconds
|
||||||
const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
||||||
const int SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS = 5000; // how many msgID we store for duplicates check
|
const int SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS = 5000; // how many msgID we store for duplicates check
|
||||||
const int SSU2_RECEIVED_I2NP_MSGIDS_CLEANUP_TIMEOUT = 10; // in seconds
|
const int SSU2_RECEIVED_I2NP_MSGIDS_CLEANUP_TIMEOUT = 10; // in seconds
|
||||||
@ -255,8 +256,10 @@ namespace transport
|
|||||||
void Done () override;
|
void Done () override;
|
||||||
void SendLocalRouterInfo (bool update) override;
|
void SendLocalRouterInfo (bool update) override;
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
||||||
|
void MoveSendQueue (std::shared_ptr<SSU2Session> other);
|
||||||
uint32_t GetRelayTag () const override { return m_RelayTag; };
|
uint32_t GetRelayTag () const override { return m_RelayTag; };
|
||||||
size_t Resend (uint64_t ts); // return number or resent packets
|
size_t Resend (uint64_t ts); // return number of resent packets
|
||||||
|
uint64_t GetLastResendTime () const { return m_LastResendTime; };
|
||||||
bool IsEstablished () const override { return m_State == eSSU2SessionStateEstablished; };
|
bool IsEstablished () const override { return m_State == eSSU2SessionStateEstablished; };
|
||||||
uint64_t GetConnID () const { return m_SourceConnID; };
|
uint64_t GetConnID () const { return m_SourceConnID; };
|
||||||
SSU2SessionState GetState () const { return m_State; };
|
SSU2SessionState GetState () const { return m_State; };
|
||||||
@ -301,6 +304,7 @@ namespace transport
|
|||||||
|
|
||||||
void HandlePayload (const uint8_t * buf, size_t len);
|
void HandlePayload (const uint8_t * buf, size_t len);
|
||||||
void HandleDateTime (const uint8_t * buf, size_t len);
|
void HandleDateTime (const uint8_t * buf, size_t len);
|
||||||
|
void HandleRouterInfo (const uint8_t * buf, size_t len);
|
||||||
void HandleAck (const uint8_t * buf, size_t len);
|
void HandleAck (const uint8_t * buf, size_t len);
|
||||||
void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts);
|
void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts);
|
||||||
void HandleAddress (const uint8_t * buf, size_t len);
|
void HandleAddress (const uint8_t * buf, size_t len);
|
||||||
@ -325,6 +329,7 @@ namespace transport
|
|||||||
|
|
||||||
size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
|
size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
|
||||||
size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r);
|
size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r);
|
||||||
|
size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo::Buffer> riBuffer);
|
||||||
size_t CreateAckBlock (uint8_t * buf, size_t len);
|
size_t CreateAckBlock (uint8_t * buf, size_t len);
|
||||||
size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0);
|
size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0);
|
||||||
size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg);
|
size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg);
|
||||||
@ -369,6 +374,7 @@ namespace transport
|
|||||||
size_t m_MaxPayloadSize;
|
size_t m_MaxPayloadSize;
|
||||||
std::unique_ptr<i2p::data::IdentHash> m_PathChallenge;
|
std::unique_ptr<i2p::data::IdentHash> m_PathChallenge;
|
||||||
std::unordered_map<uint32_t, uint32_t> m_ReceivedI2NPMsgIDs; // msgID -> timestamp in seconds
|
std::unordered_map<uint32_t, uint32_t> m_ReceivedI2NPMsgIDs; // msgID -> timestamp in seconds
|
||||||
|
uint64_t m_LastResendTime, m_LastResendAttemptTime; // in milliseconds
|
||||||
};
|
};
|
||||||
|
|
||||||
inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce)
|
inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce)
|
||||||
|
@ -69,28 +69,55 @@ namespace stream
|
|||||||
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local,
|
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local,
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> remote, int port): m_Service (service),
|
std::shared_ptr<const i2p::data::LeaseSet> remote, int port): m_Service (service),
|
||||||
m_SendStreamID (0), m_SequenceNumber (0),
|
m_SendStreamID (0), m_SequenceNumber (0),
|
||||||
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1),
|
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1),
|
||||||
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local),
|
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
|
||||||
m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service),
|
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
|
||||||
|
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true),
|
||||||
|
m_IsTimeOutResend (false), m_LocalDestination (local),
|
||||||
|
m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service),
|
||||||
m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port),
|
m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port),
|
||||||
m_RTT (INITIAL_RTT), m_WindowSize (MIN_WINDOW_SIZE), m_RTO (INITIAL_RTO),
|
m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO),
|
||||||
m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
|
m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT),
|
||||||
m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU)
|
m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0),
|
||||||
|
m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_LastSendTime (0),
|
||||||
|
m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed
|
||||||
|
m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU)
|
||||||
{
|
{
|
||||||
RAND_bytes ((uint8_t *)&m_RecvStreamID, 4);
|
RAND_bytes ((uint8_t *)&m_RecvStreamID, 4);
|
||||||
m_RemoteIdentity = remote->GetIdentity ();
|
m_RemoteIdentity = remote->GetIdentity ();
|
||||||
|
auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed ();
|
||||||
|
if (outboundSpeed)
|
||||||
|
m_MinPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed;
|
||||||
|
|
||||||
|
auto inboundSpeed = local.GetOwner ()->GetStreamingInboundSpeed (); // for limit inbound speed
|
||||||
|
if (inboundSpeed)
|
||||||
|
m_PacketACKInterval = (1000000LL*STREAMING_MTU)/inboundSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local):
|
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local):
|
||||||
m_Service (service), m_SendStreamID (0), m_SequenceNumber (0),
|
m_Service (service), m_SendStreamID (0), m_SequenceNumber (0),
|
||||||
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1),
|
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1),
|
||||||
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local),
|
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
|
||||||
m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
|
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
|
||||||
m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT),
|
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (true),
|
||||||
m_WindowSize (MIN_WINDOW_SIZE), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
|
m_IsTimeOutResend (false), m_LocalDestination (local),
|
||||||
m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU)
|
m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
|
||||||
|
m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT),
|
||||||
|
m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowIncCounter (0),
|
||||||
|
m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
|
||||||
|
m_PrevRTTSample (INITIAL_RTT), m_PrevRTT (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0),
|
||||||
|
m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_DropWindowDelayTime (0), m_LastSendTime (0),
|
||||||
|
m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed
|
||||||
|
m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU)
|
||||||
{
|
{
|
||||||
RAND_bytes ((uint8_t *)&m_RecvStreamID, 4);
|
RAND_bytes ((uint8_t *)&m_RecvStreamID, 4);
|
||||||
|
auto outboundSpeed = local.GetOwner ()->GetStreamingOutboundSpeed ();
|
||||||
|
if (outboundSpeed)
|
||||||
|
m_MinPacingTime = (1000000LL*STREAMING_MTU)/outboundSpeed;
|
||||||
|
|
||||||
|
auto inboundSpeed = local.GetOwner ()->GetStreamingInboundSpeed (); // for limit inbound speed
|
||||||
|
if (inboundSpeed)
|
||||||
|
m_PacketACKInterval = (1000000LL*STREAMING_MTU)/inboundSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::~Stream ()
|
Stream::~Stream ()
|
||||||
@ -105,6 +132,7 @@ namespace stream
|
|||||||
m_AckSendTimer.cancel ();
|
m_AckSendTimer.cancel ();
|
||||||
m_ReceiveTimer.cancel ();
|
m_ReceiveTimer.cancel ();
|
||||||
m_ResendTimer.cancel ();
|
m_ResendTimer.cancel ();
|
||||||
|
m_SendTimer.cancel ();
|
||||||
//CleanUp (); /* Need to recheck - broke working on windows */
|
//CleanUp (); /* Need to recheck - broke working on windows */
|
||||||
if (deleteFromDestination)
|
if (deleteFromDestination)
|
||||||
m_LocalDestination.DeleteStream (shared_from_this ());
|
m_LocalDestination.DeleteStream (shared_from_this ());
|
||||||
@ -119,6 +147,8 @@ namespace stream
|
|||||||
m_ReceiveQueue.pop ();
|
m_ReceiveQueue.pop ();
|
||||||
m_LocalDestination.DeletePacket (packet);
|
m_LocalDestination.DeletePacket (packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_NACKedPackets.clear ();
|
||||||
|
|
||||||
for (auto it: m_SentPackets)
|
for (auto it: m_SentPackets)
|
||||||
m_LocalDestination.DeletePacket (it);
|
m_LocalDestination.DeletePacket (it);
|
||||||
@ -203,8 +233,20 @@ namespace stream
|
|||||||
{
|
{
|
||||||
// we have received duplicate
|
// we have received duplicate
|
||||||
LogPrint (eLogWarning, "Streaming: Duplicate message ", receivedSeqn, " on sSID=", m_SendStreamID);
|
LogPrint (eLogWarning, "Streaming: Duplicate message ", receivedSeqn, " on sSID=", m_SendStreamID);
|
||||||
SendQuickAck (); // resend ack for previous message again
|
if (receivedSeqn <= m_PreviousReceivedSequenceNumber || receivedSeqn == m_LastReceivedSequenceNumber)
|
||||||
|
{
|
||||||
|
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel);
|
||||||
|
UpdateCurrentRemoteLease ();
|
||||||
|
}
|
||||||
|
m_PreviousReceivedSequenceNumber = receivedSeqn;
|
||||||
m_LocalDestination.DeletePacket (packet); // packet dropped
|
m_LocalDestination.DeletePacket (packet); // packet dropped
|
||||||
|
if (!m_IsAckSendScheduled)
|
||||||
|
{
|
||||||
|
SendQuickAck (); // resend ack for previous message again
|
||||||
|
auto ackTimeout = m_RTT/10;
|
||||||
|
if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay;
|
||||||
|
ScheduleAck (ackTimeout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -216,7 +258,8 @@ namespace stream
|
|||||||
if (!m_IsAckSendScheduled)
|
if (!m_IsAckSendScheduled)
|
||||||
{
|
{
|
||||||
// send NACKs for missing messages
|
// send NACKs for missing messages
|
||||||
int ackTimeout = MIN_SEND_ACK_TIMEOUT*m_SavedPackets.size ();
|
SendQuickAck ();
|
||||||
|
auto ackTimeout = m_RTT/10;
|
||||||
if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay;
|
if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay;
|
||||||
ScheduleAck (ackTimeout);
|
ScheduleAck (ackTimeout);
|
||||||
}
|
}
|
||||||
@ -277,6 +320,11 @@ namespace stream
|
|||||||
{
|
{
|
||||||
const uint8_t * optionData = packet->GetOptionData ();
|
const uint8_t * optionData = packet->GetOptionData ();
|
||||||
size_t optionSize = packet->GetOptionSize ();
|
size_t optionSize = packet->GetOptionSize ();
|
||||||
|
if (optionSize > packet->len)
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Streaming: Invalid option size ", optionSize, " Discarded");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (flags & PACKET_FLAG_DELAY_REQUESTED)
|
if (flags & PACKET_FLAG_DELAY_REQUESTED)
|
||||||
{
|
{
|
||||||
if (!m_IsAckSendScheduled)
|
if (!m_IsAckSendScheduled)
|
||||||
@ -290,7 +338,10 @@ namespace stream
|
|||||||
shared_from_this (), std::placeholders::_1));
|
shared_from_this (), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
if (delayRequested >= DELAY_CHOKING)
|
if (delayRequested >= DELAY_CHOKING)
|
||||||
|
{
|
||||||
m_WindowSize = 1;
|
m_WindowSize = 1;
|
||||||
|
m_WindowIncCounter = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
optionData += 2;
|
optionData += 2;
|
||||||
}
|
}
|
||||||
@ -403,13 +454,15 @@ namespace stream
|
|||||||
bool acknowledged = false;
|
bool acknowledged = false;
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
uint32_t ackThrough = packet->GetAckThrough ();
|
uint32_t ackThrough = packet->GetAckThrough ();
|
||||||
|
m_NACKedPackets.clear ();
|
||||||
if (ackThrough > m_SequenceNumber)
|
if (ackThrough > m_SequenceNumber)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Streaming: Unexpected ackThrough=", ackThrough, " > seqn=", m_SequenceNumber);
|
LogPrint (eLogError, "Streaming: Unexpected ackThrough=", ackThrough, " > seqn=", m_SequenceNumber);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int rttSample = INT_MAX;
|
int rttSample = INT_MAX;
|
||||||
bool firstRttSample = false;
|
m_IsNAcked = false;
|
||||||
|
m_IsResendNeeded = false;
|
||||||
int nackCount = packet->GetNACKCount ();
|
int nackCount = packet->GetNACKCount ();
|
||||||
for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();)
|
for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();)
|
||||||
{
|
{
|
||||||
@ -422,6 +475,8 @@ namespace stream
|
|||||||
for (int i = 0; i < nackCount; i++)
|
for (int i = 0; i < nackCount; i++)
|
||||||
if (seqn == packet->GetNACK (i))
|
if (seqn == packet->GetNACK (i))
|
||||||
{
|
{
|
||||||
|
m_NACKedPackets.insert (*it);
|
||||||
|
m_IsNAcked = true;
|
||||||
nacked = true;
|
nacked = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -438,7 +493,7 @@ namespace stream
|
|||||||
LogPrint (eLogError, "Streaming: Packet ", seqn, "sent from the future, sendTime=", sentPacket->sendTime);
|
LogPrint (eLogError, "Streaming: Packet ", seqn, "sent from the future, sendTime=", sentPacket->sendTime);
|
||||||
if (!seqn)
|
if (!seqn)
|
||||||
{
|
{
|
||||||
firstRttSample = true;
|
m_IsFirstRttSample = true;
|
||||||
rttSample = rtt < 0 ? 1 : rtt;
|
rttSample = rtt < 0 ? 1 : rtt;
|
||||||
}
|
}
|
||||||
else if (!sentPacket->resent && seqn > m_TunnelsChangeSequenceNumber && rtt >= 0)
|
else if (!sentPacket->resent && seqn > m_TunnelsChangeSequenceNumber && rtt >= 0)
|
||||||
@ -447,42 +502,86 @@ namespace stream
|
|||||||
m_SentPackets.erase (it++);
|
m_SentPackets.erase (it++);
|
||||||
m_LocalDestination.DeletePacket (sentPacket);
|
m_LocalDestination.DeletePacket (sentPacket);
|
||||||
acknowledged = true;
|
acknowledged = true;
|
||||||
if (m_WindowSize < WINDOW_SIZE)
|
if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK)
|
||||||
m_WindowSize++; // slow start
|
m_WindowIncCounter++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (rttSample != INT_MAX)
|
if (rttSample != INT_MAX)
|
||||||
{
|
{
|
||||||
if (firstRttSample)
|
if (m_IsFirstRttSample)
|
||||||
|
{
|
||||||
m_RTT = rttSample;
|
m_RTT = rttSample;
|
||||||
|
m_SlowRTT = rttSample;
|
||||||
|
m_PrevRTTSample = rttSample;
|
||||||
|
if (m_RoutingSession)
|
||||||
|
m_RoutingSession->SetSharedRoutingPath (
|
||||||
|
std::make_shared<i2p::garlic::GarlicRoutingPath> (
|
||||||
|
i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, (int)m_RTT, 0}));
|
||||||
|
m_IsFirstRttSample = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
m_RTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_RTT;
|
m_RTT = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * rttSample;
|
||||||
|
// calculate jitter
|
||||||
|
int jitter = 0;
|
||||||
|
if (rttSample > m_PrevRTTSample)
|
||||||
|
jitter = rttSample - m_PrevRTTSample;
|
||||||
|
else if (rttSample < m_PrevRTTSample)
|
||||||
|
jitter = m_PrevRTTSample - rttSample;
|
||||||
|
else
|
||||||
|
jitter = std::round (rttSample / 10); // 10%
|
||||||
|
jitter += 5; // for low-latency connections
|
||||||
|
m_Jitter = std::round (RTT_EWMA_ALPHA * jitter + (1.0 - RTT_EWMA_ALPHA) * m_Jitter);
|
||||||
|
m_PrevRTTSample = rttSample;
|
||||||
|
//
|
||||||
|
// delay-based CC
|
||||||
|
if ((m_PrevRTT > m_SlowRTT + m_Jitter) && (m_RTT > m_SlowRTT + m_Jitter) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection
|
||||||
|
{
|
||||||
|
if (m_LastWindowDropSize)
|
||||||
|
m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2;
|
||||||
|
else
|
||||||
|
m_LastWindowDropSize = m_WindowSize;
|
||||||
|
m_WindowSize = m_WindowSize / 2; // /2
|
||||||
|
if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE;
|
||||||
|
m_WindowIncCounter = 0;
|
||||||
|
m_DropWindowDelayTime = ts + m_SlowRTT;
|
||||||
|
m_IsFirstACK = true;
|
||||||
|
m_IsWinDropped = true; // don't drop window twice
|
||||||
|
}
|
||||||
|
UpdatePacingTime ();
|
||||||
|
if (rttSample < m_RTT) // need for delay-based CC
|
||||||
|
m_SlowRTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_SlowRTT;
|
||||||
|
else
|
||||||
|
m_SlowRTT = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * m_SlowRTT;
|
||||||
|
m_PrevRTT = m_RTT;
|
||||||
|
|
||||||
bool wasInitial = m_RTO == INITIAL_RTO;
|
bool wasInitial = m_RTO == INITIAL_RTO;
|
||||||
m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5)); // TODO: implement it better
|
m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better
|
||||||
|
|
||||||
if (wasInitial)
|
if (wasInitial)
|
||||||
ScheduleResend ();
|
ScheduleResend ();
|
||||||
}
|
}
|
||||||
if (acknowledged && m_WindowSize >= WINDOW_SIZE)
|
if ( ts > m_DropWindowDelayTime)
|
||||||
|
m_IsWinDropped = false;
|
||||||
|
if (acknowledged || m_IsNAcked)
|
||||||
{
|
{
|
||||||
// linear growth
|
ScheduleResend ();
|
||||||
if (ts > m_LastWindowSizeIncreaseTime + m_RTT)
|
|
||||||
{
|
|
||||||
m_WindowSize++;
|
|
||||||
if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE;
|
|
||||||
m_LastWindowSizeIncreaseTime = ts;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (firstRttSample && m_RoutingSession)
|
if ((m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss
|
||||||
m_RoutingSession->SetSharedRoutingPath (
|
|| int(m_SentPackets.size ()) > m_WindowSize) // or we drop window
|
||||||
std::make_shared<i2p::garlic::GarlicRoutingPath> (
|
{
|
||||||
i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, (int)m_RTT, 0, 0}));
|
m_IsResendNeeded = true;
|
||||||
if (m_SentPackets.empty ())
|
}
|
||||||
|
if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ())
|
||||||
|
{
|
||||||
m_ResendTimer.cancel ();
|
m_ResendTimer.cancel ();
|
||||||
|
m_SendTimer.cancel ();
|
||||||
|
}
|
||||||
if (acknowledged)
|
if (acknowledged)
|
||||||
{
|
{
|
||||||
m_NumResendAttempts = 0;
|
m_NumResendAttempts = 0;
|
||||||
|
m_IsFirstACK = false;
|
||||||
SendBuffer ();
|
SendBuffer ();
|
||||||
}
|
}
|
||||||
if (m_Status == eStreamStatusClosed)
|
if (m_Status == eStreamStatusClosed)
|
||||||
@ -557,9 +656,16 @@ namespace stream
|
|||||||
|
|
||||||
void Stream::SendBuffer ()
|
void Stream::SendBuffer ()
|
||||||
{
|
{
|
||||||
|
ScheduleSend ();
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
int numMsgs = m_WindowSize - m_SentPackets.size ();
|
int numMsgs = m_WindowSize - m_SentPackets.size ();
|
||||||
if (numMsgs <= 0) return; // window is full
|
if (numMsgs <= 0 || !m_IsSendTime) // window is full
|
||||||
|
{
|
||||||
|
m_LastSendTime = ts;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (numMsgs > m_NumPacketsToSend)
|
||||||
|
numMsgs = m_NumPacketsToSend;
|
||||||
bool isNoAck = m_LastReceivedSequenceNumber < 0; // first packet
|
bool isNoAck = m_LastReceivedSequenceNumber < 0; // first packet
|
||||||
std::vector<Packet *> packets;
|
std::vector<Packet *> packets;
|
||||||
while ((m_Status == eStreamStatusNew) || (IsEstablished () && !m_SendBuffer.IsEmpty () && numMsgs > 0))
|
while ((m_Status == eStreamStatusNew) || (IsEstablished () && !m_SendBuffer.IsEmpty () && numMsgs > 0))
|
||||||
@ -653,13 +759,15 @@ namespace stream
|
|||||||
m_AckSendTimer.cancel ();
|
m_AckSendTimer.cancel ();
|
||||||
}
|
}
|
||||||
bool isEmpty = m_SentPackets.empty ();
|
bool isEmpty = m_SentPackets.empty ();
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
// auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
for (auto& it: packets)
|
for (auto& it: packets)
|
||||||
{
|
{
|
||||||
it->sendTime = ts;
|
it->sendTime = ts;
|
||||||
m_SentPackets.insert (it);
|
m_SentPackets.insert (it);
|
||||||
}
|
}
|
||||||
SendPackets (packets);
|
SendPackets (packets);
|
||||||
|
m_LastSendTime = ts;
|
||||||
|
m_IsSendTime = false;
|
||||||
if (m_Status == eStreamStatusClosing && m_SendBuffer.IsEmpty ())
|
if (m_Status == eStreamStatusClosing && m_SendBuffer.IsEmpty ())
|
||||||
SendClose ();
|
SendClose ();
|
||||||
if (isEmpty)
|
if (isEmpty)
|
||||||
@ -670,10 +778,26 @@ namespace stream
|
|||||||
void Stream::SendQuickAck ()
|
void Stream::SendQuickAck ()
|
||||||
{
|
{
|
||||||
int32_t lastReceivedSeqn = m_LastReceivedSequenceNumber;
|
int32_t lastReceivedSeqn = m_LastReceivedSequenceNumber;
|
||||||
|
// for limit inbound speed
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
int numPackets = 0;
|
||||||
|
int64_t passedTime = m_PacketACKInterval * INITIAL_WINDOW_SIZE; // in microseconds // while m_LastACKSendTime == 0
|
||||||
|
if (m_LastACKSendTime)
|
||||||
|
passedTime = (ts - m_LastACKSendTime)*1000; // in microseconds
|
||||||
|
numPackets = (passedTime + m_PacketACKIntervalRem) / m_PacketACKInterval;
|
||||||
|
m_PacketACKIntervalRem = (passedTime + m_PacketACKIntervalRem) - (numPackets * m_PacketACKInterval);
|
||||||
|
if (m_LastConfirmedReceivedSequenceNumber + numPackets < m_LastReceivedSequenceNumber)
|
||||||
|
lastReceivedSeqn = m_LastConfirmedReceivedSequenceNumber + numPackets;
|
||||||
|
if (numPackets == 0) return;
|
||||||
|
// for limit inbound speed
|
||||||
if (!m_SavedPackets.empty ())
|
if (!m_SavedPackets.empty ())
|
||||||
{
|
{
|
||||||
int32_t seqn = (*m_SavedPackets.rbegin ())->GetSeqn ();
|
for (auto it: m_SavedPackets)
|
||||||
if (seqn > lastReceivedSeqn) lastReceivedSeqn = seqn;
|
{
|
||||||
|
auto seqn = it->GetSeqn ();
|
||||||
|
if (m_LastConfirmedReceivedSequenceNumber + numPackets < int(seqn)) break; // for limit inbound speed
|
||||||
|
if ((int)seqn > lastReceivedSeqn) lastReceivedSeqn = seqn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (lastReceivedSeqn < 0)
|
if (lastReceivedSeqn < 0)
|
||||||
{
|
{
|
||||||
@ -702,6 +826,11 @@ namespace stream
|
|||||||
for (auto it: m_SavedPackets)
|
for (auto it: m_SavedPackets)
|
||||||
{
|
{
|
||||||
auto seqn = it->GetSeqn ();
|
auto seqn = it->GetSeqn ();
|
||||||
|
if (m_LastConfirmedReceivedSequenceNumber + numPackets < int(seqn)) // for limit inbound speed
|
||||||
|
{
|
||||||
|
htobe32buf (packet + 12, nextSeqn - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (numNacks + (seqn - nextSeqn) >= 256)
|
if (numNacks + (seqn - nextSeqn) >= 256)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Streaming: Number of NACKs exceeds 256. seqn=", seqn, " nextSeqn=", nextSeqn);
|
LogPrint (eLogError, "Streaming: Number of NACKs exceeds 256. seqn=", seqn, " nextSeqn=", nextSeqn);
|
||||||
@ -743,6 +872,8 @@ namespace stream
|
|||||||
p.len = size;
|
p.len = size;
|
||||||
|
|
||||||
SendPackets (std::vector<Packet *> { &p });
|
SendPackets (std::vector<Packet *> { &p });
|
||||||
|
m_LastACKSendTime = ts; // for limit inbound speed
|
||||||
|
m_LastConfirmedReceivedSequenceNumber = lastReceivedSeqn; // for limit inbound speed
|
||||||
LogPrint (eLogDebug, "Streaming: Quick Ack sent. ", (int)numNacks, " NACKs");
|
LogPrint (eLogDebug, "Streaming: Quick Ack sent. ", (int)numNacks, " NACKs");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -873,6 +1004,7 @@ namespace stream
|
|||||||
m_IsAckSendScheduled = false;
|
m_IsAckSendScheduled = false;
|
||||||
m_AckSendTimer.cancel ();
|
m_AckSendTimer.cancel ();
|
||||||
}
|
}
|
||||||
|
if (!packet->sendTime) packet->sendTime = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
SendPackets (std::vector<Packet *> { packet });
|
SendPackets (std::vector<Packet *> { packet });
|
||||||
bool isEmpty = m_SentPackets.empty ();
|
bool isEmpty = m_SentPackets.empty ();
|
||||||
m_SentPackets.insert (packet);
|
m_SentPackets.insert (packet);
|
||||||
@ -906,7 +1038,7 @@ namespace stream
|
|||||||
m_CurrentOutboundTunnel = routingPath->outboundTunnel;
|
m_CurrentOutboundTunnel = routingPath->outboundTunnel;
|
||||||
m_CurrentRemoteLease = routingPath->remoteLease;
|
m_CurrentRemoteLease = routingPath->remoteLease;
|
||||||
m_RTT = routingPath->rtt;
|
m_RTT = routingPath->rtt;
|
||||||
m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5)); // TODO: implement it better
|
m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -925,12 +1057,7 @@ namespace stream
|
|||||||
freshTunnel = true;
|
freshTunnel = true;
|
||||||
}
|
}
|
||||||
else if (!m_CurrentOutboundTunnel->IsEstablished ())
|
else if (!m_CurrentOutboundTunnel->IsEstablished ())
|
||||||
{
|
std::tie(m_CurrentOutboundTunnel, freshTunnel) = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel);
|
||||||
auto oldOutboundTunnel = m_CurrentOutboundTunnel;
|
|
||||||
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel);
|
|
||||||
if (m_CurrentOutboundTunnel && oldOutboundTunnel->GetEndpointIdentHash() != m_CurrentOutboundTunnel->GetEndpointIdentHash())
|
|
||||||
freshTunnel = true;
|
|
||||||
}
|
|
||||||
if (!m_CurrentOutboundTunnel)
|
if (!m_CurrentOutboundTunnel)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Streaming: No outbound tunnels in the pool, sSID=", m_SendStreamID);
|
LogPrint (eLogError, "Streaming: No outbound tunnels in the pool, sSID=", m_SendStreamID);
|
||||||
@ -940,7 +1067,7 @@ namespace stream
|
|||||||
if (freshTunnel)
|
if (freshTunnel)
|
||||||
{
|
{
|
||||||
m_RTO = INITIAL_RTO;
|
m_RTO = INITIAL_RTO;
|
||||||
m_TunnelsChangeSequenceNumber = m_SequenceNumber; // should be determined more precisely
|
// m_TunnelsChangeSequenceNumber = m_SequenceNumber; // should be determined more precisely
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||||
@ -993,6 +1120,68 @@ namespace stream
|
|||||||
SendQuickAck ();
|
SendQuickAck ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stream::ScheduleSend ()
|
||||||
|
{
|
||||||
|
if (m_Status != eStreamStatusTerminated)
|
||||||
|
{
|
||||||
|
m_SendTimer.cancel ();
|
||||||
|
m_SendTimer.expires_from_now (boost::posix_time::microseconds(SEND_INTERVAL));
|
||||||
|
m_SendTimer.async_wait (std::bind (&Stream::HandleSendTimer,
|
||||||
|
shared_from_this (), std::placeholders::_1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::HandleSendTimer (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE)
|
||||||
|
{
|
||||||
|
if (m_LastWindowDropSize && (m_LastWindowDropSize > m_WindowSize))
|
||||||
|
{
|
||||||
|
m_WindowSize += 2.001-(2/((m_LastWindowDropSize+(1/m_WindowSize))/m_WindowSize)); // some magic here
|
||||||
|
m_WindowIncCounter --;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_WindowSize += 1;
|
||||||
|
m_WindowIncCounter --;
|
||||||
|
}
|
||||||
|
if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE;
|
||||||
|
UpdatePacingTime ();
|
||||||
|
}
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
if (m_LastSendTime && ts*1000 > m_LastSendTime*1000 + m_PacingTime)
|
||||||
|
{
|
||||||
|
m_NumPacketsToSend = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) / m_PacingTime;
|
||||||
|
m_PacingTimeRem = ((ts*1000 - m_LastSendTime*1000) + m_PacingTimeRem) - (m_NumPacketsToSend * m_PacingTime);
|
||||||
|
m_IsSendTime = true;
|
||||||
|
if (m_IsNAcked || m_IsResendNeeded) // resend packets
|
||||||
|
ResendPacket ();
|
||||||
|
// delay-based CC
|
||||||
|
else if (!m_IsWinDropped && int(m_SentPackets.size ()) == m_WindowSize) // we sending packets too fast, early detection
|
||||||
|
{
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
if (m_LastWindowDropSize)
|
||||||
|
m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2;
|
||||||
|
else
|
||||||
|
m_LastWindowDropSize = m_WindowSize;
|
||||||
|
m_WindowSize = m_WindowSize / 2; // /2
|
||||||
|
if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE;
|
||||||
|
m_WindowIncCounter = 0;
|
||||||
|
m_DropWindowDelayTime = ts + m_SlowRTT;
|
||||||
|
m_IsFirstACK = true;
|
||||||
|
m_IsWinDropped = true; // don't drop window twice
|
||||||
|
UpdatePacingTime ();
|
||||||
|
}
|
||||||
|
else if (m_WindowSize > int(m_SentPackets.size ())) // send packets
|
||||||
|
SendBuffer ();
|
||||||
|
}
|
||||||
|
else // pass
|
||||||
|
ScheduleSend ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Stream::ScheduleResend ()
|
void Stream::ScheduleResend ()
|
||||||
{
|
{
|
||||||
if (m_Status != eStreamStatusTerminated)
|
if (m_Status != eStreamStatusTerminated)
|
||||||
@ -1010,6 +1199,19 @@ namespace stream
|
|||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
|
m_IsSendTime = true;
|
||||||
|
if (m_RTO > INITIAL_RTO) m_RTO = INITIAL_RTO;
|
||||||
|
m_SendTimer.cancel (); // if no ack's in RTO, disable fast retransmit
|
||||||
|
m_IsTimeOutResend = true;
|
||||||
|
m_IsNAcked = false;
|
||||||
|
m_IsResendNeeded = false;
|
||||||
|
m_NumPacketsToSend = 1;
|
||||||
|
ResendPacket (); // send one packet per RTO, waiting for ack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::ResendPacket ()
|
||||||
|
{
|
||||||
// check for resend attempts
|
// check for resend attempts
|
||||||
if (m_NumResendAttempts >= MAX_NUM_RESEND_ATTEMPTS)
|
if (m_NumResendAttempts >= MAX_NUM_RESEND_ATTEMPTS)
|
||||||
{
|
{
|
||||||
@ -1022,31 +1224,74 @@ namespace stream
|
|||||||
// collect packets to resend
|
// collect packets to resend
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
std::vector<Packet *> packets;
|
std::vector<Packet *> packets;
|
||||||
for (auto it : m_SentPackets)
|
if (m_IsNAcked)
|
||||||
{
|
{
|
||||||
if (ts >= it->sendTime + m_RTO)
|
for (auto it : m_NACKedPackets)
|
||||||
{
|
{
|
||||||
it->resent = true;
|
if (ts >= it->sendTime + m_RTO)
|
||||||
it->sendTime = ts;
|
{
|
||||||
packets.push_back (it);
|
if (ts < it->sendTime + m_RTO*2)
|
||||||
|
it->resent = true;
|
||||||
|
else
|
||||||
|
it->resent = false;
|
||||||
|
it->sendTime = ts;
|
||||||
|
packets.push_back (it);
|
||||||
|
if ((int)packets.size () >= m_NumPacketsToSend) break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// select tunnels if necessary and send
|
|
||||||
if (packets.size () > 0)
|
|
||||||
{
|
{
|
||||||
m_NumResendAttempts++;
|
for (auto it : m_SentPackets)
|
||||||
|
{
|
||||||
|
if (ts >= it->sendTime + m_RTO)
|
||||||
|
{
|
||||||
|
if (ts < it->sendTime + m_RTO*2)
|
||||||
|
it->resent = true;
|
||||||
|
else
|
||||||
|
it->resent = false;
|
||||||
|
it->sendTime = ts;
|
||||||
|
packets.push_back (it);
|
||||||
|
if ((int)packets.size () >= m_NumPacketsToSend) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// select tunnels if necessary and send
|
||||||
|
if (packets.size () > 0 && m_IsSendTime)
|
||||||
|
{
|
||||||
|
if (m_IsNAcked) m_NumResendAttempts = 1;
|
||||||
|
else if (m_IsTimeOutResend) m_NumResendAttempts++;
|
||||||
if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO)
|
if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO)
|
||||||
{
|
{
|
||||||
// congestion avoidance
|
// loss-based CC
|
||||||
m_RTO *= 2;
|
if (!m_IsWinDropped)
|
||||||
m_WindowSize -= (m_WindowSize + WINDOW_SIZE_DROP_FRACTION) / WINDOW_SIZE_DROP_FRACTION; // adjustment >= 1
|
{
|
||||||
if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE;
|
if (m_LastWindowDropSize)
|
||||||
|
m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2;
|
||||||
|
else
|
||||||
|
m_LastWindowDropSize = m_WindowSize;
|
||||||
|
m_WindowSize = m_WindowSize / 2; // /2
|
||||||
|
if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE;
|
||||||
|
m_WindowIncCounter = 0;
|
||||||
|
m_IsWinDropped = true; // don't drop window twice
|
||||||
|
m_DropWindowDelayTime = ts + m_SlowRTT;
|
||||||
|
m_IsFirstACK = true;
|
||||||
|
UpdatePacingTime ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (m_IsTimeOutResend)
|
||||||
{
|
{
|
||||||
m_TunnelsChangeSequenceNumber = m_SequenceNumber;
|
m_IsTimeOutResend = false;
|
||||||
m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change
|
m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change
|
||||||
|
m_WindowSize = INITIAL_WINDOW_SIZE;
|
||||||
|
m_LastWindowDropSize = 0;
|
||||||
|
m_WindowIncCounter = 0;
|
||||||
|
m_IsWinDropped = true;
|
||||||
|
m_IsFirstRttSample = true;
|
||||||
|
m_DropWindowDelayTime = 0;
|
||||||
|
m_IsFirstACK = true;
|
||||||
|
UpdatePacingTime ();
|
||||||
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
|
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||||
if (m_NumResendAttempts & 1)
|
if (m_NumResendAttempts & 1)
|
||||||
{
|
{
|
||||||
@ -1063,9 +1308,13 @@ namespace stream
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SendPackets (packets);
|
SendPackets (packets);
|
||||||
|
m_LastSendTime = ts;
|
||||||
|
m_IsSendTime = false;
|
||||||
|
if (m_IsNAcked || m_IsResendNeeded) ScheduleSend ();
|
||||||
}
|
}
|
||||||
ScheduleResend ();
|
else
|
||||||
}
|
SendBuffer ();
|
||||||
|
if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::ScheduleAck (int timeout)
|
void Stream::ScheduleAck (int timeout)
|
||||||
@ -1187,8 +1436,35 @@ namespace stream
|
|||||||
LogPrint (eLogWarning, "Streaming: Remote LeaseSet not found");
|
LogPrint (eLogWarning, "Streaming: Remote LeaseSet not found");
|
||||||
m_CurrentRemoteLease = nullptr;
|
m_CurrentRemoteLease = nullptr;
|
||||||
}
|
}
|
||||||
|
// drop window to initial upon RemoteLease change
|
||||||
|
m_RTO = INITIAL_RTO;
|
||||||
|
m_WindowSize = INITIAL_WINDOW_SIZE;
|
||||||
|
m_LastWindowDropSize = 0;
|
||||||
|
m_WindowIncCounter = 0;
|
||||||
|
m_IsWinDropped = true;
|
||||||
|
m_IsFirstRttSample = true;
|
||||||
|
m_DropWindowDelayTime = 0;
|
||||||
|
m_IsFirstACK = true;
|
||||||
|
UpdatePacingTime ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stream::ResetRoutingPath ()
|
||||||
|
{
|
||||||
|
m_CurrentOutboundTunnel = nullptr;
|
||||||
|
m_CurrentRemoteLease = nullptr;
|
||||||
|
m_RTT = INITIAL_RTT;
|
||||||
|
m_RTO = INITIAL_RTO;
|
||||||
|
if (m_RoutingSession)
|
||||||
|
m_RoutingSession->SetSharedRoutingPath (nullptr); // TODO: count failures
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::UpdatePacingTime ()
|
||||||
|
{
|
||||||
|
m_PacingTime = std::round (m_RTT*1000/m_WindowSize);
|
||||||
|
if (m_MinPacingTime && m_PacingTime < m_MinPacingTime)
|
||||||
|
m_PacingTime = m_MinPacingTime;
|
||||||
|
}
|
||||||
|
|
||||||
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip):
|
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip):
|
||||||
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
|
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
|
||||||
m_PendingIncomingTimer (m_Owner->GetService ())
|
m_PendingIncomingTimer (m_Owner->GetService ())
|
||||||
@ -1269,6 +1545,7 @@ namespace stream
|
|||||||
{
|
{
|
||||||
// already pending
|
// already pending
|
||||||
LogPrint(eLogWarning, "Streaming: Incoming streaming with rSID=", receiveStreamID, " already exists");
|
LogPrint(eLogWarning, "Streaming: Incoming streaming with rSID=", receiveStreamID, " already exists");
|
||||||
|
it1->second->ResetRoutingPath (); // Ack was not delivered, changing path
|
||||||
DeletePacket (packet); // drop it, because previous should be connected
|
DeletePacket (packet); // drop it, because previous should be connected
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -52,21 +52,22 @@ namespace stream
|
|||||||
const size_t STREAMING_MTU_RATCHETS = 1812;
|
const size_t STREAMING_MTU_RATCHETS = 1812;
|
||||||
const size_t MAX_PACKET_SIZE = 4096;
|
const size_t MAX_PACKET_SIZE = 4096;
|
||||||
const size_t COMPRESSION_THRESHOLD_SIZE = 66;
|
const size_t COMPRESSION_THRESHOLD_SIZE = 66;
|
||||||
const int MAX_NUM_RESEND_ATTEMPTS = 9;
|
const int MAX_NUM_RESEND_ATTEMPTS = 10;
|
||||||
const int WINDOW_SIZE = 6; // in messages
|
const int INITIAL_WINDOW_SIZE = 10;
|
||||||
const int MIN_WINDOW_SIZE = 1;
|
const int MIN_WINDOW_SIZE = 1;
|
||||||
const int MAX_WINDOW_SIZE = 128;
|
const int MAX_WINDOW_SIZE = 1024;
|
||||||
const int WINDOW_SIZE_DROP_FRACTION = 10; // 1/10
|
|
||||||
const double RTT_EWMA_ALPHA = 0.125;
|
const double RTT_EWMA_ALPHA = 0.125;
|
||||||
const int MIN_RTO = 20; // in milliseconds
|
const int MIN_RTO = 20; // in milliseconds
|
||||||
const int INITIAL_RTT = 8000; // in milliseconds
|
const int INITIAL_RTT = 8000; // in milliseconds
|
||||||
const int INITIAL_RTO = 9000; // in milliseconds
|
const int INITIAL_RTO = 9000; // in milliseconds
|
||||||
|
const int INITIAL_PACING_TIME = 1000 * INITIAL_RTT / INITIAL_WINDOW_SIZE; // in microseconds
|
||||||
const int MIN_SEND_ACK_TIMEOUT = 2; // in milliseconds
|
const int MIN_SEND_ACK_TIMEOUT = 2; // in milliseconds
|
||||||
const int SYN_TIMEOUT = 200; // how long we wait for SYN after follow-on, in milliseconds
|
const int SYN_TIMEOUT = 200; // how long we wait for SYN after follow-on, in milliseconds
|
||||||
const size_t MAX_PENDING_INCOMING_BACKLOG = 128;
|
const size_t MAX_PENDING_INCOMING_BACKLOG = 1024;
|
||||||
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
|
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
|
||||||
const int MAX_RECEIVE_TIMEOUT = 20; // in seconds
|
const int MAX_RECEIVE_TIMEOUT = 20; // in seconds
|
||||||
const uint16_t DELAY_CHOKING = 60000; // in milliseconds
|
const uint16_t DELAY_CHOKING = 60000; // in milliseconds
|
||||||
|
const uint64_t SEND_INTERVAL = 1000; // in microseconds
|
||||||
|
|
||||||
struct Packet
|
struct Packet
|
||||||
{
|
{
|
||||||
@ -77,7 +78,7 @@ namespace stream
|
|||||||
|
|
||||||
Packet (): len (0), offset (0), sendTime (0), resent (false) {};
|
Packet (): len (0), offset (0), sendTime (0), resent (false) {};
|
||||||
uint8_t * GetBuffer () { return buf + offset; };
|
uint8_t * GetBuffer () { return buf + offset; };
|
||||||
size_t GetLength () const { return len - offset; };
|
size_t GetLength () const { return len > offset ? len - offset : 0; };
|
||||||
|
|
||||||
uint32_t GetSendStreamID () const { return bufbe32toh (buf); };
|
uint32_t GetSendStreamID () const { return bufbe32toh (buf); };
|
||||||
uint32_t GetReceiveStreamID () const { return bufbe32toh (buf + 4); };
|
uint32_t GetReceiveStreamID () const { return bufbe32toh (buf + 4); };
|
||||||
@ -180,6 +181,7 @@ namespace stream
|
|||||||
bool IsEstablished () const { return m_SendStreamID; };
|
bool IsEstablished () const { return m_SendStreamID; };
|
||||||
StreamStatus GetStatus () const { return m_Status; };
|
StreamStatus GetStatus () const { return m_Status; };
|
||||||
StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
|
StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
|
||||||
|
void ResetRoutingPath ();
|
||||||
|
|
||||||
void HandleNextPacket (Packet * packet);
|
void HandleNextPacket (Packet * packet);
|
||||||
void HandlePing (Packet * packet);
|
void HandlePing (Packet * packet);
|
||||||
@ -230,19 +232,33 @@ namespace stream
|
|||||||
template<typename Buffer, typename ReceiveHandler>
|
template<typename Buffer, typename ReceiveHandler>
|
||||||
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout);
|
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout);
|
||||||
|
|
||||||
|
void ScheduleSend ();
|
||||||
|
void HandleSendTimer (const boost::system::error_code& ecode);
|
||||||
void ScheduleResend ();
|
void ScheduleResend ();
|
||||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||||
|
void ResendPacket ();
|
||||||
void ScheduleAck (int timeout);
|
void ScheduleAck (int timeout);
|
||||||
void HandleAckSendTimer (const boost::system::error_code& ecode);
|
void HandleAckSendTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
|
void UpdatePacingTime ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
boost::asio::io_service& m_Service;
|
boost::asio::io_service& m_Service;
|
||||||
uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber;
|
uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber;
|
||||||
uint32_t m_TunnelsChangeSequenceNumber;
|
uint32_t m_TunnelsChangeSequenceNumber;
|
||||||
int32_t m_LastReceivedSequenceNumber;
|
int32_t m_LastReceivedSequenceNumber;
|
||||||
|
int32_t m_PreviousReceivedSequenceNumber;
|
||||||
|
int32_t m_LastConfirmedReceivedSequenceNumber; // for limit inbound speed
|
||||||
StreamStatus m_Status;
|
StreamStatus m_Status;
|
||||||
bool m_IsAckSendScheduled;
|
bool m_IsAckSendScheduled;
|
||||||
|
bool m_IsNAcked;
|
||||||
|
bool m_IsFirstACK;
|
||||||
|
bool m_IsResendNeeded;
|
||||||
|
bool m_IsFirstRttSample;
|
||||||
|
bool m_IsSendTime;
|
||||||
|
bool m_IsWinDropped;
|
||||||
|
bool m_IsTimeOutResend;
|
||||||
StreamingDestination& m_LocalDestination;
|
StreamingDestination& m_LocalDestination;
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
||||||
std::shared_ptr<const i2p::crypto::Verifier> m_TransientVerifier; // in case of offline key
|
std::shared_ptr<const i2p::crypto::Verifier> m_TransientVerifier; // in case of offline key
|
||||||
@ -253,15 +269,18 @@ namespace stream
|
|||||||
std::queue<Packet *> m_ReceiveQueue;
|
std::queue<Packet *> m_ReceiveQueue;
|
||||||
std::set<Packet *, PacketCmp> m_SavedPackets;
|
std::set<Packet *, PacketCmp> m_SavedPackets;
|
||||||
std::set<Packet *, PacketCmp> m_SentPackets;
|
std::set<Packet *, PacketCmp> m_SentPackets;
|
||||||
boost::asio::deadline_timer m_ReceiveTimer, m_ResendTimer, m_AckSendTimer;
|
std::set<Packet *, PacketCmp> m_NACKedPackets;
|
||||||
|
boost::asio::deadline_timer m_ReceiveTimer, m_SendTimer, m_ResendTimer, m_AckSendTimer;
|
||||||
size_t m_NumSentBytes, m_NumReceivedBytes;
|
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||||
uint16_t m_Port;
|
uint16_t m_Port;
|
||||||
|
|
||||||
SendBufferQueue m_SendBuffer;
|
SendBufferQueue m_SendBuffer;
|
||||||
double m_RTT;
|
double m_RTT, m_SlowRTT;
|
||||||
int m_WindowSize, m_RTO, m_AckDelay;
|
float m_WindowSize, m_LastWindowDropSize;
|
||||||
uint64_t m_LastWindowSizeIncreaseTime;
|
int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_PrevRTT, m_Jitter;
|
||||||
int m_NumResendAttempts;
|
uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, m_DropWindowDelayTime, m_LastSendTime; // microseconds
|
||||||
|
uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed
|
||||||
|
int m_NumResendAttempts, m_NumPacketsToSend;
|
||||||
size_t m_MTU;
|
size_t m_MTU;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,6 +255,11 @@ namespace util
|
|||||||
GetDateString (GetSecondsSinceEpoch (), date);
|
GetDateString (GetSecondsSinceEpoch (), date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetNextDayDate (char * date)
|
||||||
|
{
|
||||||
|
GetDateString (GetSecondsSinceEpoch () + 24*60*60, date);
|
||||||
|
}
|
||||||
|
|
||||||
void GetDateString (uint64_t timestamp, char * date)
|
void GetDateString (uint64_t timestamp, char * date)
|
||||||
{
|
{
|
||||||
using clock = std::chrono::system_clock;
|
using clock = std::chrono::system_clock;
|
||||||
|
@ -28,7 +28,8 @@ namespace util
|
|||||||
uint64_t GetMonotonicMilliseconds ();
|
uint64_t GetMonotonicMilliseconds ();
|
||||||
uint64_t GetMonotonicSeconds ();
|
uint64_t GetMonotonicSeconds ();
|
||||||
|
|
||||||
void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes
|
void GetCurrentDate (char * date); // returns UTC date as YYYYMMDD string, 9 bytes
|
||||||
|
void GetNextDayDate (char * date); // returns next UTC day as YYYYMMDD string, 9 bytes
|
||||||
void GetDateString (uint64_t timestamp, char * date); // timestamp is seconds since epoch, returns date as YYYYMMDD string, 9 bytes
|
void GetDateString (uint64_t timestamp, char * date); // timestamp is seconds since epoch, returns date as YYYYMMDD string, 9 bytes
|
||||||
void AdjustTimeOffset (int64_t offset); // in seconds from current
|
void AdjustTimeOffset (int64_t offset); // in seconds from current
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <boost/algorithm/string.hpp> // for boost::to_lower
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
@ -131,6 +132,17 @@ namespace transport
|
|||||||
LogPrint(eLogError, "Transports: Return null DHKeys");
|
LogPrint(eLogError, "Transports: Return null DHKeys");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Peer::UpdateParams (std::shared_ptr<const i2p::data::RouterInfo> router)
|
||||||
|
{
|
||||||
|
if (router)
|
||||||
|
{
|
||||||
|
isHighBandwidth = router->IsHighBandwidth ();
|
||||||
|
isEligible =(bool)router->GetCompatibleTransports (true) && // reachable
|
||||||
|
router->GetCongestion () != i2p::data::RouterInfo::eRejectAll && // accepts tunnel
|
||||||
|
router->IsECIES () && router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION; // not too old
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Transports transports;
|
Transports transports;
|
||||||
|
|
||||||
Transports::Transports ():
|
Transports::Transports ():
|
||||||
@ -328,7 +340,6 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (m_PeerCleanupTimer) m_PeerCleanupTimer->cancel ();
|
if (m_PeerCleanupTimer) m_PeerCleanupTimer->cancel ();
|
||||||
if (m_PeerTestTimer) m_PeerTestTimer->cancel ();
|
if (m_PeerTestTimer) m_PeerTestTimer->cancel ();
|
||||||
m_Peers.clear ();
|
|
||||||
|
|
||||||
if (m_SSU2Server)
|
if (m_SSU2Server)
|
||||||
{
|
{
|
||||||
@ -353,6 +364,7 @@ namespace transport
|
|||||||
delete m_Thread;
|
delete m_Thread;
|
||||||
m_Thread = nullptr;
|
m_Thread = nullptr;
|
||||||
}
|
}
|
||||||
|
m_Peers.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::Run ()
|
void Transports::Run ()
|
||||||
@ -457,6 +469,7 @@ namespace transport
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(RoutesRestricted() && !IsRestrictedPeer(ident)) return;
|
if(RoutesRestricted() && !IsRestrictedPeer(ident)) return;
|
||||||
|
std::shared_ptr<Peer> peer;
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it == m_Peers.end ())
|
if (it == m_Peers.end ())
|
||||||
{
|
{
|
||||||
@ -470,10 +483,12 @@ namespace transport
|
|||||||
if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable
|
if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
peer = std::make_shared<Peer>(r, ts);
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, {r, ts})).first;
|
peer = m_Peers.emplace (ident, peer).first->second;
|
||||||
}
|
}
|
||||||
connected = ConnectToPeer (ident, it->second);
|
if (peer)
|
||||||
|
connected = ConnectToPeer (ident, peer);
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
@ -481,11 +496,15 @@ namespace transport
|
|||||||
}
|
}
|
||||||
if (!connected) return;
|
if (!connected) return;
|
||||||
}
|
}
|
||||||
if (it->second.IsConnected ())
|
else
|
||||||
it->second.sessions.front ()->SendI2NPMessages (msgs);
|
peer = it->second;
|
||||||
|
|
||||||
|
if (!peer) return;
|
||||||
|
if (peer->IsConnected ())
|
||||||
|
peer->sessions.front ()->SendI2NPMessages (msgs);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto sz = it->second.delayedMessages.size ();
|
auto sz = peer->delayedMessages.size ();
|
||||||
if (sz < MAX_NUM_DELAYED_MESSAGES)
|
if (sz < MAX_NUM_DELAYED_MESSAGES)
|
||||||
{
|
{
|
||||||
if (sz < CHECK_PROFILE_NUM_DELAYED_MESSAGES && sz + msgs.size () >= CHECK_PROFILE_NUM_DELAYED_MESSAGES)
|
if (sz < CHECK_PROFILE_NUM_DELAYED_MESSAGES && sz + msgs.size () >= CHECK_PROFILE_NUM_DELAYED_MESSAGES)
|
||||||
@ -494,7 +513,7 @@ namespace transport
|
|||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
|
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (it);
|
m_Peers.erase (ident);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -502,30 +521,30 @@ namespace transport
|
|||||||
if (sz > MAX_NUM_DELAYED_MESSAGES/2 && it1->onDrop)
|
if (sz > MAX_NUM_DELAYED_MESSAGES/2 && it1->onDrop)
|
||||||
it1->Drop (); // drop earlier because we can handle it
|
it1->Drop (); // drop earlier because we can handle it
|
||||||
else
|
else
|
||||||
it->second.delayedMessages.push_back (it1);
|
peer->delayedMessages.push_back (it1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: Delayed messages queue size to ",
|
LogPrint (eLogWarning, "Transports: Delayed messages queue size to ",
|
||||||
ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES);
|
ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES);
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (it);
|
m_Peers.erase (ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer)
|
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr<Peer> peer)
|
||||||
{
|
{
|
||||||
if (!peer.router) // reconnect
|
if (!peer->router) // reconnect
|
||||||
peer.SetRouter (netdb.FindRouter (ident)); // try to get new one from netdb
|
peer->SetRouter (netdb.FindRouter (ident)); // try to get new one from netdb
|
||||||
if (peer.router) // we have RI already
|
if (peer->router) // we have RI already
|
||||||
{
|
{
|
||||||
if (peer.priority.empty ())
|
if (peer->priority.empty ())
|
||||||
SetPriority (peer);
|
SetPriority (peer);
|
||||||
while (peer.numAttempts < (int)peer.priority.size ())
|
while (peer->numAttempts < (int)peer->priority.size ())
|
||||||
{
|
{
|
||||||
auto tr = peer.priority[peer.numAttempts];
|
auto tr = peer->priority[peer->numAttempts];
|
||||||
peer.numAttempts++;
|
peer->numAttempts++;
|
||||||
switch (tr)
|
switch (tr)
|
||||||
{
|
{
|
||||||
case i2p::data::RouterInfo::eNTCP2V4:
|
case i2p::data::RouterInfo::eNTCP2V4:
|
||||||
@ -533,12 +552,12 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (!m_NTCP2Server) continue;
|
if (!m_NTCP2Server) continue;
|
||||||
std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eNTCP2V6) ?
|
std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eNTCP2V6) ?
|
||||||
peer.router->GetPublishedNTCP2V6Address () : peer.router->GetPublishedNTCP2V4Address ();
|
peer->router->GetPublishedNTCP2V6Address () : peer->router->GetPublishedNTCP2V4Address ();
|
||||||
if (address && IsInReservedRange(address->host))
|
if (address && IsInReservedRange(address->host))
|
||||||
address = nullptr;
|
address = nullptr;
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer->router, address);
|
||||||
if( m_NTCP2Server->UsingProxy())
|
if( m_NTCP2Server->UsingProxy())
|
||||||
m_NTCP2Server->ConnectWithProxy(s);
|
m_NTCP2Server->ConnectWithProxy(s);
|
||||||
else
|
else
|
||||||
@ -552,12 +571,12 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (!m_SSU2Server) continue;
|
if (!m_SSU2Server) continue;
|
||||||
std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eSSU2V6) ?
|
std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eSSU2V6) ?
|
||||||
peer.router->GetSSU2V6Address () : peer.router->GetSSU2V4Address ();
|
peer->router->GetSSU2V6Address () : peer->router->GetSSU2V4Address ();
|
||||||
if (address && IsInReservedRange(address->host))
|
if (address && IsInReservedRange(address->host))
|
||||||
address = nullptr;
|
address = nullptr;
|
||||||
if (address && address->IsReachableSSU ())
|
if (address && address->IsReachableSSU ())
|
||||||
{
|
{
|
||||||
if (m_SSU2Server->CreateSession (peer.router, address))
|
if (m_SSU2Server->CreateSession (peer->router, address))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -565,10 +584,10 @@ namespace transport
|
|||||||
case i2p::data::RouterInfo::eNTCP2V6Mesh:
|
case i2p::data::RouterInfo::eNTCP2V6Mesh:
|
||||||
{
|
{
|
||||||
if (!m_NTCP2Server) continue;
|
if (!m_NTCP2Server) continue;
|
||||||
auto address = peer.router->GetYggdrasilAddress ();
|
auto address = peer->router->GetYggdrasilAddress ();
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer->router, address);
|
||||||
m_NTCP2Server->Connect (s);
|
m_NTCP2Server->Connect (s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -580,9 +599,9 @@ namespace transport
|
|||||||
}
|
}
|
||||||
|
|
||||||
LogPrint (eLogInfo, "Transports: No compatible addresses available");
|
LogPrint (eLogInfo, "Transports: No compatible addresses available");
|
||||||
if (peer.router->IsReachableFrom (i2p::context.GetRouterInfo ()))
|
if (peer->router->IsReachableFrom (i2p::context.GetRouterInfo ()))
|
||||||
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them
|
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them
|
||||||
peer.Done ();
|
peer->Done ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (ident);
|
m_Peers.erase (ident);
|
||||||
return false;
|
return false;
|
||||||
@ -590,7 +609,7 @@ namespace transport
|
|||||||
else if (i2p::data::IsRouterBanned (ident))
|
else if (i2p::data::IsRouterBanned (ident))
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
|
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
|
||||||
peer.Done ();
|
peer->Done ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (ident);
|
m_Peers.erase (ident);
|
||||||
return false;
|
return false;
|
||||||
@ -604,7 +623,7 @@ namespace transport
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::SetPriority (Peer& peer) const
|
void Transports::SetPriority (std::shared_ptr<Peer> peer) const
|
||||||
{
|
{
|
||||||
static const std::vector<i2p::data::RouterInfo::SupportedTransports>
|
static const std::vector<i2p::data::RouterInfo::SupportedTransports>
|
||||||
ntcp2Priority =
|
ntcp2Priority =
|
||||||
@ -623,16 +642,36 @@ namespace transport
|
|||||||
i2p::data::RouterInfo::eNTCP2V4,
|
i2p::data::RouterInfo::eNTCP2V4,
|
||||||
i2p::data::RouterInfo::eNTCP2V6Mesh
|
i2p::data::RouterInfo::eNTCP2V6Mesh
|
||||||
};
|
};
|
||||||
if (!peer.router) return;
|
if (!peer || !peer->router) return;
|
||||||
auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) &
|
auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) &
|
||||||
peer.router->GetCompatibleTransports (true);
|
peer->router->GetCompatibleTransports (true);
|
||||||
peer.numAttempts = 0;
|
auto directTransports = compatibleTransports & peer->router->GetPublishedTransports ();
|
||||||
peer.priority.clear ();
|
peer->numAttempts = 0;
|
||||||
bool ssu2 = peer.router->GetProfile ()->IsReal () ? (rand () & 1) : false; // try NTCP2 if router is not confirmed real
|
peer->priority.clear ();
|
||||||
|
bool isReal = peer->router->GetProfile ()->IsReal ();
|
||||||
|
bool ssu2 = isReal ? (rand () & 1) : false; // try NTCP2 if router is not confirmed real
|
||||||
const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority;
|
const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority;
|
||||||
for (auto transport: priority)
|
if (directTransports)
|
||||||
if (transport & compatibleTransports)
|
{
|
||||||
peer.priority.push_back (transport);
|
// direct connections have higher priority
|
||||||
|
if (!isReal && (directTransports & (i2p::data::RouterInfo::eNTCP2V4 | i2p::data::RouterInfo::eNTCP2V6)))
|
||||||
|
{
|
||||||
|
// Non-confirmed router and a NTCP2 direct connection is presented
|
||||||
|
compatibleTransports &= ~directTransports; // exclude SSU2 direct connections
|
||||||
|
directTransports &= ~(i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6);
|
||||||
|
}
|
||||||
|
for (auto transport: priority)
|
||||||
|
if (transport & directTransports)
|
||||||
|
peer->priority.push_back (transport);
|
||||||
|
compatibleTransports &= ~directTransports;
|
||||||
|
}
|
||||||
|
if (compatibleTransports)
|
||||||
|
{
|
||||||
|
// then remaining
|
||||||
|
for (auto transport: priority)
|
||||||
|
if (transport & compatibleTransports)
|
||||||
|
peer->priority.push_back (transport);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
||||||
@ -648,8 +687,8 @@ namespace transport
|
|||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
|
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
|
||||||
it->second.SetRouter (r);
|
it->second->SetRouter (r);
|
||||||
if (!it->second.IsConnected ())
|
if (!it->second->IsConnected ())
|
||||||
ConnectToPeer (ident, it->second);
|
ConnectToPeer (ident, it->second);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -681,7 +720,7 @@ namespace transport
|
|||||||
if (ipv4 && i2p::context.SupportsV4 ())
|
if (ipv4 && i2p::context.SupportsV4 ())
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Transports: Started peer test IPv4");
|
LogPrint (eLogInfo, "Transports: Started peer test IPv4");
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::unordered_set<i2p::data::IdentHash> excluded;
|
||||||
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
||||||
int testDelay = 0;
|
int testDelay = 0;
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
@ -719,7 +758,7 @@ namespace transport
|
|||||||
if (ipv6 && i2p::context.SupportsV6 ())
|
if (ipv6 && i2p::context.SupportsV6 ())
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Transports: Started peer test IPv6");
|
LogPrint (eLogInfo, "Transports: Started peer test IPv6");
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::unordered_set<i2p::data::IdentHash> excluded;
|
||||||
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
||||||
int testDelay = 0;
|
int testDelay = 0;
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
@ -776,31 +815,32 @@ namespace transport
|
|||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
if (it->second.numAttempts > 1)
|
auto peer = it->second;
|
||||||
|
if (peer->numAttempts > 1)
|
||||||
{
|
{
|
||||||
// exclude failed transports
|
// exclude failed transports
|
||||||
i2p::data::RouterInfo::CompatibleTransports transports = 0;
|
i2p::data::RouterInfo::CompatibleTransports transports = 0;
|
||||||
int numExcluded = it->second.numAttempts - 1;
|
int numExcluded = peer->numAttempts - 1;
|
||||||
if (numExcluded > (int)it->second.priority.size ()) numExcluded = it->second.priority.size ();
|
if (numExcluded > (int)peer->priority.size ()) numExcluded = peer->priority.size ();
|
||||||
for (int i = 0; i < numExcluded; i++)
|
for (int i = 0; i < numExcluded; i++)
|
||||||
transports |= it->second.priority[i];
|
transports |= peer->priority[i];
|
||||||
i2p::data::netdb.ExcludeReachableTransports (ident, transports);
|
i2p::data::netdb.ExcludeReachableTransports (ident, transports);
|
||||||
}
|
}
|
||||||
if (it->second.router && it->second.numAttempts)
|
if (peer->router && peer->numAttempts)
|
||||||
{
|
{
|
||||||
auto transport = it->second.priority[it->second.numAttempts-1];
|
auto transport = peer->priority[peer->numAttempts-1];
|
||||||
if (transport == i2p::data::RouterInfo::eNTCP2V4 ||
|
if (transport == i2p::data::RouterInfo::eNTCP2V4 ||
|
||||||
transport == i2p::data::RouterInfo::eNTCP2V6 || transport == i2p::data::RouterInfo::eNTCP2V6Mesh)
|
transport == i2p::data::RouterInfo::eNTCP2V6 || transport == i2p::data::RouterInfo::eNTCP2V6Mesh)
|
||||||
it->second.router->GetProfile ()->Connected (); // outgoing NTCP2 connection if always real
|
peer->router->GetProfile ()->Connected (); // outgoing NTCP2 connection if always real
|
||||||
i2p::data::netdb.SetUnreachable (ident, false); // clear unreachable
|
i2p::data::netdb.SetUnreachable (ident, false); // clear unreachable
|
||||||
}
|
}
|
||||||
it->second.numAttempts = 0;
|
peer->numAttempts = 0;
|
||||||
it->second.router = nullptr; // we don't need RouterInfo after successive connect
|
peer->router = nullptr; // we don't need RouterInfo after successive connect
|
||||||
bool sendDatabaseStore = true;
|
bool sendDatabaseStore = true;
|
||||||
if (it->second.delayedMessages.size () > 0)
|
if (it->second->delayedMessages.size () > 0)
|
||||||
{
|
{
|
||||||
// check if first message is our DatabaseStore (publishing)
|
// check if first message is our DatabaseStore (publishing)
|
||||||
auto firstMsg = it->second.delayedMessages[0];
|
auto firstMsg = peer->delayedMessages[0];
|
||||||
if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore &&
|
if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore &&
|
||||||
i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ())
|
i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ())
|
||||||
sendDatabaseStore = false; // we have it in the list already
|
sendDatabaseStore = false; // we have it in the list already
|
||||||
@ -809,9 +849,9 @@ namespace transport
|
|||||||
session->SendLocalRouterInfo ();
|
session->SendLocalRouterInfo ();
|
||||||
else
|
else
|
||||||
session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds
|
session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds
|
||||||
it->second.sessions.push_back (session);
|
peer->sessions.push_back (session);
|
||||||
session->SendI2NPMessages (it->second.delayedMessages);
|
session->SendI2NPMessages (peer->delayedMessages);
|
||||||
it->second.delayedMessages.clear ();
|
peer->delayedMessages.clear ();
|
||||||
}
|
}
|
||||||
else // incoming connection or peer test
|
else // incoming connection or peer test
|
||||||
{
|
{
|
||||||
@ -826,10 +866,11 @@ namespace transport
|
|||||||
auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed
|
auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed
|
||||||
if (r) r->GetProfile ()->Connected ();
|
if (r) r->GetProfile ()->Connected ();
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
auto peer = std::make_shared<Peer>(r, ts);
|
||||||
|
peer->sessions.push_back (session);
|
||||||
|
peer->router = nullptr;
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
auto it = m_Peers.insert (std::make_pair (ident, Peer{ r, ts })).first;
|
m_Peers.emplace (ident, peer);
|
||||||
it->second.sessions.push_back (session);
|
|
||||||
it->second.router = nullptr;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -844,15 +885,16 @@ namespace transport
|
|||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
bool wasConnected = it->second.IsConnected ();
|
auto peer = it->second;
|
||||||
it->second.sessions.remove (session);
|
bool wasConnected = peer->IsConnected ();
|
||||||
if (!it->second.IsConnected ())
|
peer->sessions.remove (session);
|
||||||
|
if (!peer->IsConnected ())
|
||||||
{
|
{
|
||||||
if (it->second.delayedMessages.size () > 0)
|
if (peer->delayedMessages.size () > 0)
|
||||||
{
|
{
|
||||||
if (wasConnected) // we had an active session before
|
if (wasConnected) // we had an active session before
|
||||||
it->second.numAttempts = 0; // start over
|
peer->numAttempts = 0; // start over
|
||||||
ConnectToPeer (ident, it->second);
|
ConnectToPeer (ident, peer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -878,12 +920,12 @@ namespace transport
|
|||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
for (auto it = m_Peers.begin (); it != m_Peers.end (); )
|
for (auto it = m_Peers.begin (); it != m_Peers.end (); )
|
||||||
{
|
{
|
||||||
it->second.sessions.remove_if (
|
it->second->sessions.remove_if (
|
||||||
[](std::shared_ptr<TransportSession> session)->bool
|
[](std::shared_ptr<TransportSession> session)->bool
|
||||||
{
|
{
|
||||||
return !session || !session->IsEstablished ();
|
return !session || !session->IsEstablished ();
|
||||||
});
|
});
|
||||||
if (!it->second.IsConnected () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
|
if (!it->second->IsConnected () && ts > it->second->creationTime + SESSION_CREATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
|
LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
|
||||||
/* if (!it->second.router)
|
/* if (!it->second.router)
|
||||||
@ -897,12 +939,12 @@ namespace transport
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ts > it->second.nextRouterInfoUpdateTime)
|
if (ts > it->second->nextRouterInfoUpdateTime)
|
||||||
{
|
{
|
||||||
auto session = it->second.sessions.front ();
|
auto session = it->second->sessions.front ();
|
||||||
if (session)
|
if (session)
|
||||||
session->SendLocalRouterInfo (true);
|
session->SendLocalRouterInfo (true);
|
||||||
it->second.nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL +
|
it->second->nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL +
|
||||||
rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE;
|
rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE;
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
@ -936,6 +978,7 @@ namespace transport
|
|||||||
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (Filter filter) const
|
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (Filter filter) const
|
||||||
{
|
{
|
||||||
if (m_Peers.empty()) return nullptr;
|
if (m_Peers.empty()) return nullptr;
|
||||||
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
bool found = false;
|
bool found = false;
|
||||||
i2p::data::IdentHash ident;
|
i2p::data::IdentHash ident;
|
||||||
{
|
{
|
||||||
@ -976,9 +1019,11 @@ namespace transport
|
|||||||
it = it1;
|
it = it1;
|
||||||
while (it != it2 && it != m_Peers.end ())
|
while (it != it2 && it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
if (filter (it->second))
|
if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL &&
|
||||||
|
filter (it->second))
|
||||||
{
|
{
|
||||||
ident = it->first;
|
ident = it->first;
|
||||||
|
it->second->lastSelectionTime = ts;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -990,9 +1035,11 @@ namespace transport
|
|||||||
it = m_Peers.begin ();
|
it = m_Peers.begin ();
|
||||||
while (it != it1 && it != m_Peers.end ())
|
while (it != it1 && it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
if (filter (it->second))
|
if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL &&
|
||||||
|
filter (it->second))
|
||||||
{
|
{
|
||||||
ident = it->first;
|
ident = it->first;
|
||||||
|
it->second->lastSelectionTime = ts;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1004,9 +1051,11 @@ namespace transport
|
|||||||
it = it2;
|
it = it2;
|
||||||
while (it != m_Peers.end ())
|
while (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
if (filter (it->second))
|
if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL &&
|
||||||
|
filter (it->second))
|
||||||
{
|
{
|
||||||
ident = it->first;
|
ident = it->first;
|
||||||
|
it->second->lastSelectionTime = ts;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1022,13 +1071,13 @@ namespace transport
|
|||||||
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (bool isHighBandwidth) const
|
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (bool isHighBandwidth) const
|
||||||
{
|
{
|
||||||
return GetRandomPeer (
|
return GetRandomPeer (
|
||||||
[isHighBandwidth](const Peer& peer)->bool
|
[isHighBandwidth](std::shared_ptr<const Peer> peer)->bool
|
||||||
{
|
{
|
||||||
// connected, not overloaded and not slow
|
// connected, not overloaded and not slow
|
||||||
return !peer.router && peer.IsConnected () && peer.isReachable &&
|
return !peer->router && peer->IsConnected () && peer->isEligible &&
|
||||||
peer.sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE &&
|
peer->sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE &&
|
||||||
!peer.sessions.front ()->IsSlow () && !peer.sessions.front ()->IsBandwidthExceeded (peer.isHighBandwidth) &&
|
!peer->sessions.front ()->IsSlow () && !peer->sessions.front ()->IsBandwidthExceeded (peer->isHighBandwidth) &&
|
||||||
(!isHighBandwidth || peer.isHighBandwidth);
|
(!isHighBandwidth || peer->isHighBandwidth);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,26 +64,23 @@ namespace transport
|
|||||||
const int PEER_ROUTER_INFO_UPDATE_INTERVAL = 31*60; // in seconds
|
const int PEER_ROUTER_INFO_UPDATE_INTERVAL = 31*60; // in seconds
|
||||||
const int PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE = 7*60; // in seconds
|
const int PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE = 7*60; // in seconds
|
||||||
const size_t PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE = 25;
|
const size_t PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE = 25;
|
||||||
|
const int PEER_SELECTION_MIN_INTERVAL = 20; // in seconds
|
||||||
struct Peer
|
struct Peer
|
||||||
{
|
{
|
||||||
int numAttempts;
|
int numAttempts;
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> router;
|
std::shared_ptr<const i2p::data::RouterInfo> router;
|
||||||
std::list<std::shared_ptr<TransportSession> > sessions;
|
std::list<std::shared_ptr<TransportSession> > sessions;
|
||||||
uint64_t creationTime, nextRouterInfoUpdateTime;
|
uint64_t creationTime, nextRouterInfoUpdateTime, lastSelectionTime;
|
||||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
|
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
|
||||||
std::vector<i2p::data::RouterInfo::SupportedTransports> priority;
|
std::vector<i2p::data::RouterInfo::SupportedTransports> priority;
|
||||||
bool isHighBandwidth, isReachable;
|
bool isHighBandwidth, isEligible;
|
||||||
|
|
||||||
Peer (std::shared_ptr<const i2p::data::RouterInfo> r, uint64_t ts):
|
Peer (std::shared_ptr<const i2p::data::RouterInfo> r, uint64_t ts):
|
||||||
numAttempts (0), router (r), creationTime (ts),
|
numAttempts (0), router (r), creationTime (ts),
|
||||||
nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL),
|
nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL),
|
||||||
isHighBandwidth (false), isReachable (false)
|
lastSelectionTime (0), isHighBandwidth (false), isEligible (false)
|
||||||
{
|
{
|
||||||
if (router)
|
UpdateParams (router);
|
||||||
{
|
|
||||||
isHighBandwidth = router->IsHighBandwidth ();
|
|
||||||
isReachable = (bool)router->GetCompatibleTransports (true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Done ()
|
void Done ()
|
||||||
@ -98,14 +95,11 @@ namespace transport
|
|||||||
void SetRouter (std::shared_ptr<const i2p::data::RouterInfo> r)
|
void SetRouter (std::shared_ptr<const i2p::data::RouterInfo> r)
|
||||||
{
|
{
|
||||||
router = r;
|
router = r;
|
||||||
if (router)
|
UpdateParams (router);
|
||||||
{
|
|
||||||
isHighBandwidth = router->IsHighBandwidth ();
|
|
||||||
isReachable = (bool)router->GetCompatibleTransports (true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsConnected () const { return !sessions.empty (); }
|
bool IsConnected () const { return !sessions.empty (); }
|
||||||
|
void UpdateParams (std::shared_ptr<const i2p::data::RouterInfo> router);
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint64_t SESSION_CREATION_TIMEOUT = 15; // in seconds
|
const uint64_t SESSION_CREATION_TIMEOUT = 15; // in seconds
|
||||||
@ -134,6 +128,7 @@ namespace transport
|
|||||||
|
|
||||||
void Start (bool enableNTCP2=true, bool enableSSU2=true);
|
void Start (bool enableNTCP2=true, bool enableSSU2=true);
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
bool IsRunning () const { return m_IsRunning; }
|
||||||
|
|
||||||
bool IsBoundSSU2() const { return m_SSU2Server != nullptr; }
|
bool IsBoundSSU2() const { return m_SSU2Server != nullptr; }
|
||||||
bool IsBoundNTCP2() const { return m_NTCP2Server != nullptr; }
|
bool IsBoundNTCP2() const { return m_NTCP2Server != nullptr; }
|
||||||
@ -191,8 +186,8 @@ namespace transport
|
|||||||
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
||||||
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
|
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
|
||||||
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
||||||
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
|
bool ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr<Peer> peer);
|
||||||
void SetPriority (Peer& peer) const;
|
void SetPriority (std::shared_ptr<Peer> peer) const;
|
||||||
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
||||||
void HandlePeerTestTimer (const boost::system::error_code& ecode);
|
void HandlePeerTestTimer (const boost::system::error_code& ecode);
|
||||||
void HandleUpdateBandwidthTimer (const boost::system::error_code& ecode);
|
void HandleUpdateBandwidthTimer (const boost::system::error_code& ecode);
|
||||||
@ -215,7 +210,7 @@ namespace transport
|
|||||||
SSU2Server * m_SSU2Server;
|
SSU2Server * m_SSU2Server;
|
||||||
NTCP2Server * m_NTCP2Server;
|
NTCP2Server * m_NTCP2Server;
|
||||||
mutable std::mutex m_PeersMutex;
|
mutable std::mutex m_PeersMutex;
|
||||||
std::unordered_map<i2p::data::IdentHash, Peer> m_Peers;
|
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<Peer> > m_Peers;
|
||||||
|
|
||||||
X25519KeysPairSupplier m_X25519KeysPairSupplier;
|
X25519KeysPairSupplier m_X25519KeysPairSupplier;
|
||||||
|
|
||||||
|
@ -592,17 +592,6 @@ namespace tunnel
|
|||||||
auto typeID = msg->GetTypeID ();
|
auto typeID = msg->GetTypeID ();
|
||||||
LogPrint (eLogDebug, "Tunnel: Gateway of ", (int) len, " bytes for tunnel ", tunnel->GetTunnelID (), ", msg type ", (int)typeID);
|
LogPrint (eLogDebug, "Tunnel: Gateway of ", (int) len, " bytes for tunnel ", tunnel->GetTunnelID (), ", msg type ", (int)typeID);
|
||||||
|
|
||||||
if (typeID == eI2NPDatabaseSearchReply)
|
|
||||||
// DatabaseSearchReply with new routers
|
|
||||||
i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg));
|
|
||||||
else if (IsRouterInfoMsg (msg))
|
|
||||||
{
|
|
||||||
// transit DatabaseStore might contain new/updated RI
|
|
||||||
auto m = CopyI2NPMessage (msg);
|
|
||||||
if (bufbe32toh (m->GetPayload () + DATABASE_STORE_REPLY_TOKEN_OFFSET))
|
|
||||||
memset (m->GetPayload () + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0xFF, 4); // fake replyToken meaning no reply
|
|
||||||
i2p::data::netdb.PostI2NPMsg (m);
|
|
||||||
}
|
|
||||||
tunnel->SendTunnelDataMsg (msg);
|
tunnel->SendTunnelDataMsg (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,8 @@ namespace tunnel
|
|||||||
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
|
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
|
||||||
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels),
|
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels),
|
||||||
m_InboundVariance (inboundVariance), m_OutboundVariance (outboundVariance),
|
m_InboundVariance (inboundVariance), m_OutboundVariance (outboundVariance),
|
||||||
m_IsActive (true), m_CustomPeerSelector(nullptr), m_Rng(m_Rd())
|
m_IsActive (true), m_CustomPeerSelector(nullptr),
|
||||||
|
m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL)
|
||||||
{
|
{
|
||||||
if (m_NumInboundTunnels > TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY)
|
if (m_NumInboundTunnels > TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY)
|
||||||
m_NumInboundTunnels = TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY;
|
m_NumInboundTunnels = TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY;
|
||||||
@ -59,7 +60,7 @@ namespace tunnel
|
|||||||
m_InboundVariance = (m_NumInboundHops < STANDARD_NUM_RECORDS) ? STANDARD_NUM_RECORDS - m_NumInboundHops : 0;
|
m_InboundVariance = (m_NumInboundHops < STANDARD_NUM_RECORDS) ? STANDARD_NUM_RECORDS - m_NumInboundHops : 0;
|
||||||
if (m_OutboundVariance > 0 && m_NumOutboundHops + m_OutboundVariance > STANDARD_NUM_RECORDS)
|
if (m_OutboundVariance > 0 && m_NumOutboundHops + m_OutboundVariance > STANDARD_NUM_RECORDS)
|
||||||
m_OutboundVariance = (m_NumOutboundHops < STANDARD_NUM_RECORDS) ? STANDARD_NUM_RECORDS - m_NumOutboundHops : 0;
|
m_OutboundVariance = (m_NumOutboundHops < STANDARD_NUM_RECORDS) ? STANDARD_NUM_RECORDS - m_NumOutboundHops : 0;
|
||||||
m_NextManageTime = i2p::util::GetSecondsSinceEpoch () + rand () % TUNNEL_POOL_MANAGE_INTERVAL;
|
m_NextManageTime = i2p::util::GetSecondsSinceEpoch () + m_Rng () % TUNNEL_POOL_MANAGE_INTERVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
TunnelPool::~TunnelPool ()
|
TunnelPool::~TunnelPool ()
|
||||||
@ -210,14 +211,14 @@ namespace tunnel
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OutboundTunnel> TunnelPool::GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded,
|
std::shared_ptr<OutboundTunnel> TunnelPool::GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded,
|
||||||
i2p::data::RouterInfo::CompatibleTransports compatible) const
|
i2p::data::RouterInfo::CompatibleTransports compatible)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
return GetNextTunnel (m_OutboundTunnels, excluded, compatible);
|
return GetNextTunnel (m_OutboundTunnels, excluded, compatible);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<InboundTunnel> TunnelPool::GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded,
|
std::shared_ptr<InboundTunnel> TunnelPool::GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded,
|
||||||
i2p::data::RouterInfo::CompatibleTransports compatible) const
|
i2p::data::RouterInfo::CompatibleTransports compatible)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
return GetNextTunnel (m_InboundTunnels, excluded, compatible);
|
return GetNextTunnel (m_InboundTunnels, excluded, compatible);
|
||||||
@ -225,10 +226,10 @@ namespace tunnel
|
|||||||
|
|
||||||
template<class TTunnels>
|
template<class TTunnels>
|
||||||
typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels,
|
typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels,
|
||||||
typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible) const
|
typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible)
|
||||||
{
|
{
|
||||||
if (tunnels.empty ()) return nullptr;
|
if (tunnels.empty ()) return nullptr;
|
||||||
uint32_t ind = rand () % (tunnels.size ()/2 + 1), i = 0;
|
uint32_t ind = m_Rng () % (tunnels.size ()/2 + 1), i = 0;
|
||||||
bool skipped = false;
|
bool skipped = false;
|
||||||
typename TTunnels::value_type tunnel = nullptr;
|
typename TTunnels::value_type tunnel = nullptr;
|
||||||
for (const auto& it: tunnels)
|
for (const auto& it: tunnels)
|
||||||
@ -248,7 +249,7 @@ namespace tunnel
|
|||||||
}
|
}
|
||||||
if (!tunnel && skipped)
|
if (!tunnel && skipped)
|
||||||
{
|
{
|
||||||
ind = rand () % (tunnels.size ()/2 + 1), i = 0;
|
ind = m_Rng () % (tunnels.size ()/2 + 1), i = 0;
|
||||||
for (const auto& it: tunnels)
|
for (const auto& it: tunnels)
|
||||||
{
|
{
|
||||||
if (it->IsEstablished () && it != excluded)
|
if (it->IsEstablished () && it != excluded)
|
||||||
@ -263,10 +264,11 @@ namespace tunnel
|
|||||||
return tunnel;
|
return tunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OutboundTunnel> TunnelPool::GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const
|
std::pair<std::shared_ptr<OutboundTunnel>, bool> TunnelPool::GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old)
|
||||||
{
|
{
|
||||||
if (old && old->IsEstablished ()) return old;
|
if (old && old->IsEstablished ()) return std::make_pair(old, false);
|
||||||
std::shared_ptr<OutboundTunnel> tunnel;
|
std::shared_ptr<OutboundTunnel> tunnel;
|
||||||
|
bool freshTunnel = false;
|
||||||
if (old)
|
if (old)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
@ -279,8 +281,11 @@ namespace tunnel
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!tunnel)
|
if (!tunnel)
|
||||||
|
{
|
||||||
tunnel = GetNextOutboundTunnel ();
|
tunnel = GetNextOutboundTunnel ();
|
||||||
return tunnel;
|
freshTunnel = true;
|
||||||
|
}
|
||||||
|
return std::make_pair(tunnel, freshTunnel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::CreateTunnels ()
|
void TunnelPool::CreateTunnels ()
|
||||||
@ -360,11 +365,19 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
it.second.second->SetState (eTunnelStateFailed);
|
it.second.second->SetState (eTunnelStateFailed);
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
bool failed = false;
|
||||||
if (m_InboundTunnels.size () > 1 || m_NumInboundTunnels <= 1) // don't fail last tunnel
|
{
|
||||||
m_InboundTunnels.erase (it.second.second);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
else
|
if (m_InboundTunnels.size () > 1 || m_NumInboundTunnels <= 1) // don't fail last tunnel
|
||||||
it.second.second->SetState (eTunnelStateTestFailed);
|
{
|
||||||
|
m_InboundTunnels.erase (it.second.second);
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it.second.second->SetState (eTunnelStateTestFailed);
|
||||||
|
}
|
||||||
|
if (failed && m_LocalDestination)
|
||||||
|
m_LocalDestination->SetLeaseSetUpdated ();
|
||||||
}
|
}
|
||||||
if (m_LocalDestination)
|
if (m_LocalDestination)
|
||||||
m_LocalDestination->SetLeaseSetUpdated ();
|
m_LocalDestination->SetLeaseSetUpdated ();
|
||||||
@ -451,7 +464,7 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
CreateTunnels ();
|
CreateTunnels ();
|
||||||
TestTunnels ();
|
TestTunnels ();
|
||||||
m_NextManageTime = ts + TUNNEL_POOL_MANAGE_INTERVAL + (rand () % TUNNEL_POOL_MANAGE_INTERVAL)/2;
|
m_NextManageTime = ts + TUNNEL_POOL_MANAGE_INTERVAL + (m_Rng () % TUNNEL_POOL_MANAGE_INTERVAL)/2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,7 +627,7 @@ namespace tunnel
|
|||||||
numHops = m_NumInboundHops;
|
numHops = m_NumInboundHops;
|
||||||
if (m_InboundVariance)
|
if (m_InboundVariance)
|
||||||
{
|
{
|
||||||
int offset = rand () % (std::abs (m_InboundVariance) + 1);
|
int offset = m_Rng () % (std::abs (m_InboundVariance) + 1);
|
||||||
if (m_InboundVariance < 0) offset = -offset;
|
if (m_InboundVariance < 0) offset = -offset;
|
||||||
numHops += offset;
|
numHops += offset;
|
||||||
}
|
}
|
||||||
@ -624,7 +637,7 @@ namespace tunnel
|
|||||||
numHops = m_NumOutboundHops;
|
numHops = m_NumOutboundHops;
|
||||||
if (m_OutboundVariance)
|
if (m_OutboundVariance)
|
||||||
{
|
{
|
||||||
int offset = rand () % (std::abs (m_OutboundVariance) + 1);
|
int offset = m_Rng () % (std::abs (m_OutboundVariance) + 1);
|
||||||
if (m_OutboundVariance < 0) offset = -offset;
|
if (m_OutboundVariance < 0) offset = -offset;
|
||||||
numHops += offset;
|
numHops += offset;
|
||||||
}
|
}
|
||||||
|
@ -78,10 +78,10 @@ namespace tunnel
|
|||||||
void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel);
|
void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel);
|
||||||
std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const;
|
std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const;
|
||||||
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr,
|
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr,
|
||||||
i2p::data::RouterInfo::CompatibleTransports compatible = i2p::data::RouterInfo::eAllTransports) const;
|
i2p::data::RouterInfo::CompatibleTransports compatible = i2p::data::RouterInfo::eAllTransports);
|
||||||
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr,
|
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr,
|
||||||
i2p::data::RouterInfo::CompatibleTransports compatible = i2p::data::RouterInfo::eAllTransports) const;
|
i2p::data::RouterInfo::CompatibleTransports compatible = i2p::data::RouterInfo::eAllTransports);
|
||||||
std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const;
|
std::pair<std::shared_ptr<OutboundTunnel>, bool> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old);
|
||||||
void ManageTunnels (uint64_t ts);
|
void ManageTunnels (uint64_t ts);
|
||||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg);
|
void ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg);
|
||||||
@ -129,7 +129,7 @@ namespace tunnel
|
|||||||
void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
|
void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
|
||||||
template<class TTunnels>
|
template<class TTunnels>
|
||||||
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels,
|
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels,
|
||||||
typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible) const;
|
typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible);
|
||||||
bool SelectPeers (Path& path, bool isInbound);
|
bool SelectPeers (Path& path, bool isInbound);
|
||||||
bool SelectExplicitPeers (Path& path, bool isInbound);
|
bool SelectExplicitPeers (Path& path, bool isInbound);
|
||||||
bool ValidatePeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers) const;
|
bool ValidatePeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers) const;
|
||||||
@ -154,7 +154,6 @@ namespace tunnel
|
|||||||
int m_MinLatency = 0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms
|
int m_MinLatency = 0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms
|
||||||
int m_MaxLatency = 0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms
|
int m_MaxLatency = 0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms
|
||||||
|
|
||||||
std::random_device m_Rd;
|
|
||||||
std::mt19937 m_Rng;
|
std::mt19937 m_Rng;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
|
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
|
||||||
|
|
||||||
#define I2PD_VERSION_MAJOR 2
|
#define I2PD_VERSION_MAJOR 2
|
||||||
#define I2PD_VERSION_MINOR 51
|
#define I2PD_VERSION_MINOR 53
|
||||||
#define I2PD_VERSION_MICRO 0
|
#define I2PD_VERSION_MICRO 1
|
||||||
#define I2PD_VERSION_PATCH 0
|
#define I2PD_VERSION_PATCH 0
|
||||||
#ifdef GITVER
|
#ifdef GITVER
|
||||||
#define I2PD_VERSION XSTRINGIZE(GITVER)
|
#define I2PD_VERSION XSTRINGIZE(GITVER)
|
||||||
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#define I2P_VERSION_MAJOR 0
|
#define I2P_VERSION_MAJOR 0
|
||||||
#define I2P_VERSION_MINOR 9
|
#define I2P_VERSION_MINOR 9
|
||||||
#define I2P_VERSION_MICRO 62
|
#define I2P_VERSION_MICRO 63
|
||||||
#define I2P_VERSION_PATCH 0
|
#define I2P_VERSION_PATCH 0
|
||||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
|
@ -471,6 +471,8 @@ namespace client
|
|||||||
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY);
|
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY);
|
||||||
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY);
|
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY);
|
||||||
options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY);
|
options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY);
|
||||||
|
options[I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED, DEFAULT_MAX_OUTBOUND_SPEED);
|
||||||
|
options[I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, DEFAULT_MAX_INBOUND_SPEED);
|
||||||
options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false);
|
options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false);
|
||||||
options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
|
options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
|
||||||
std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4");
|
std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4");
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -16,6 +16,7 @@
|
|||||||
#include "ClientContext.h"
|
#include "ClientContext.h"
|
||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
#include "Signature.h"
|
#include "Signature.h"
|
||||||
|
#include "Config.h"
|
||||||
#include "I2CP.h"
|
#include "I2CP.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@ -24,18 +25,19 @@ namespace client
|
|||||||
{
|
{
|
||||||
|
|
||||||
I2CPDestination::I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner,
|
I2CPDestination::I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner,
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params):
|
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, bool isSameThread,
|
||||||
|
const std::map<std::string, std::string>& params):
|
||||||
LeaseSetDestination (service, isPublic, ¶ms),
|
LeaseSetDestination (service, isPublic, ¶ms),
|
||||||
m_Owner (owner), m_Identity (identity), m_EncryptionKeyType (m_Identity->GetCryptoKeyType ()),
|
m_Owner (owner), m_Identity (identity), m_EncryptionKeyType (m_Identity->GetCryptoKeyType ()),
|
||||||
m_IsCreatingLeaseSet (false), m_LeaseSetCreationTimer (service)
|
m_IsCreatingLeaseSet (false), m_IsSameThread (isSameThread), m_LeaseSetCreationTimer (service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPDestination::Stop ()
|
void I2CPDestination::Stop ()
|
||||||
{
|
{
|
||||||
|
m_LeaseSetCreationTimer.cancel ();
|
||||||
LeaseSetDestination::Stop ();
|
LeaseSetDestination::Stop ();
|
||||||
m_Owner = nullptr;
|
m_Owner = nullptr;
|
||||||
m_LeaseSetCreationTimer.cancel ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key)
|
void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key)
|
||||||
@ -100,15 +102,15 @@ namespace client
|
|||||||
i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only
|
i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only
|
||||||
m_LeaseSetExpirationTime = ls.GetExpirationTime ();
|
m_LeaseSetExpirationTime = ls.GetExpirationTime ();
|
||||||
uint8_t * leases = ls.GetLeases ();
|
uint8_t * leases = ls.GetLeases ();
|
||||||
leases[-1] = tunnels.size ();
|
int numLeases = leases[-1];
|
||||||
if (m_Owner)
|
if (m_Owner && numLeases)
|
||||||
{
|
{
|
||||||
uint16_t sessionID = m_Owner->GetSessionID ();
|
uint16_t sessionID = m_Owner->GetSessionID ();
|
||||||
if (sessionID != 0xFFFF)
|
if (sessionID != 0xFFFF)
|
||||||
{
|
{
|
||||||
m_IsCreatingLeaseSet = true;
|
m_IsCreatingLeaseSet = true;
|
||||||
htobe16buf (leases - 3, sessionID);
|
htobe16buf (leases - 3, sessionID);
|
||||||
size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size ();
|
size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*numLeases;
|
||||||
m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l);
|
m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l);
|
||||||
m_LeaseSetCreationTimer.expires_from_now (boost::posix_time::seconds (I2CP_LEASESET_CREATION_TIMEOUT));
|
m_LeaseSetCreationTimer.expires_from_now (boost::posix_time::seconds (I2CP_LEASESET_CREATION_TIMEOUT));
|
||||||
auto s = GetSharedFromThis ();
|
auto s = GetSharedFromThis ();
|
||||||
@ -122,6 +124,8 @@ namespace client
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "I2CP: Can't request LeaseSet");
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len)
|
void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len)
|
||||||
@ -152,20 +156,32 @@ namespace client
|
|||||||
memcpy (buf + 4, payload, len);
|
memcpy (buf + 4, payload, len);
|
||||||
msg->len += len + 4;
|
msg->len += len + 4;
|
||||||
msg->FillI2NPMessageHeader (eI2NPData);
|
msg->FillI2NPMessageHeader (eI2NPData);
|
||||||
auto s = GetSharedFromThis ();
|
|
||||||
auto remote = FindLeaseSet (ident);
|
auto remote = FindLeaseSet (ident);
|
||||||
if (remote)
|
if (remote)
|
||||||
{
|
{
|
||||||
GetService ().post (
|
if (m_IsSameThread)
|
||||||
[s, msg, remote, nonce]()
|
{
|
||||||
{
|
// send right a way
|
||||||
bool sent = s->SendMsg (msg, remote);
|
bool sent = SendMsg (msg, remote);
|
||||||
if (s->m_Owner)
|
if (m_Owner)
|
||||||
s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
|
m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
|
||||||
});
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// send in destination's thread
|
||||||
|
auto s = GetSharedFromThis ();
|
||||||
|
GetService ().post (
|
||||||
|
[s, msg, remote, nonce]()
|
||||||
|
{
|
||||||
|
bool sent = s->SendMsg (msg, remote);
|
||||||
|
if (s->m_Owner)
|
||||||
|
s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
auto s = GetSharedFromThis ();
|
||||||
RequestDestination (ident,
|
RequestDestination (ident,
|
||||||
[s, msg, nonce](std::shared_ptr<i2p::data::LeaseSet> ls)
|
[s, msg, nonce](std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||||
{
|
{
|
||||||
@ -189,6 +205,7 @@ namespace client
|
|||||||
LogPrint (eLogError, "I2CP: Failed to create remote session");
|
LogPrint (eLogError, "I2CP: Failed to create remote session");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
auto garlic = remoteSession->WrapSingleMessage (msg); // shared routing path mitgh be dropped here
|
||||||
auto path = remoteSession->GetSharedRoutingPath ();
|
auto path = remoteSession->GetSharedRoutingPath ();
|
||||||
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
|
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
|
||||||
std::shared_ptr<const i2p::data::Lease> remoteLease;
|
std::shared_ptr<const i2p::data::Lease> remoteLease;
|
||||||
@ -202,7 +219,7 @@ namespace client
|
|||||||
else
|
else
|
||||||
remoteSession->SetSharedRoutingPath (nullptr);
|
remoteSession->SetSharedRoutingPath (nullptr);
|
||||||
}
|
}
|
||||||
else
|
if (!outboundTunnel || !remoteLease)
|
||||||
{
|
{
|
||||||
auto leases = remote->GetNonExpiredLeases (false); // without threshold
|
auto leases = remote->GetNonExpiredLeases (false); // without threshold
|
||||||
if (leases.empty ())
|
if (leases.empty ())
|
||||||
@ -216,21 +233,28 @@ namespace client
|
|||||||
}
|
}
|
||||||
if (remoteLease && outboundTunnel)
|
if (remoteLease && outboundTunnel)
|
||||||
remoteSession->SetSharedRoutingPath (std::make_shared<i2p::garlic::GarlicRoutingPath> (
|
remoteSession->SetSharedRoutingPath (std::make_shared<i2p::garlic::GarlicRoutingPath> (
|
||||||
i2p::garlic::GarlicRoutingPath{outboundTunnel, remoteLease, 10000, 0, 0})); // 10 secs RTT
|
i2p::garlic::GarlicRoutingPath{outboundTunnel, remoteLease, 10000, 0})); // 10 secs RTT
|
||||||
else
|
else
|
||||||
remoteSession->SetSharedRoutingPath (nullptr);
|
remoteSession->SetSharedRoutingPath (nullptr);
|
||||||
}
|
}
|
||||||
|
m_Owner->AddRoutingSession (remote->GetIdentity ()->GetStandardIdentity ().signingKey + 96, remoteSession); // last 32 bytes
|
||||||
|
return SendMsg (garlic, outboundTunnel, remoteLease);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I2CPDestination::SendMsg (std::shared_ptr<I2NPMessage> garlic,
|
||||||
|
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel, std::shared_ptr<const i2p::data::Lease> remoteLease)
|
||||||
|
{
|
||||||
if (remoteLease && outboundTunnel)
|
if (remoteLease && outboundTunnel)
|
||||||
{
|
{
|
||||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
outboundTunnel->SendTunnelDataMsgs (
|
||||||
auto garlic = remoteSession->WrapSingleMessage (msg);
|
{
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
i2p::tunnel::TunnelMessageBlock
|
||||||
{
|
{
|
||||||
i2p::tunnel::eDeliveryTypeTunnel,
|
i2p::tunnel::eDeliveryTypeTunnel,
|
||||||
remoteLease->tunnelGateway, remoteLease->tunnelID,
|
remoteLease->tunnelGateway, remoteLease->tunnelID,
|
||||||
garlic
|
garlic
|
||||||
|
}
|
||||||
});
|
});
|
||||||
outboundTunnel->SendTunnelDataMsgs (msgs);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -240,13 +264,55 @@ namespace client
|
|||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "I2CP: Failed to send message. No outbound tunnels");
|
LogPrint (eLogWarning, "I2CP: Failed to send message. No outbound tunnels");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I2CPDestination::SendMsg (const uint8_t * payload, size_t len,
|
||||||
|
std::shared_ptr<i2p::garlic::GarlicRoutingSession> remoteSession, uint32_t nonce)
|
||||||
|
{
|
||||||
|
if (!remoteSession) return false;
|
||||||
|
auto path = remoteSession->GetSharedRoutingPath ();
|
||||||
|
if (!path) return false;
|
||||||
|
// get tunnels
|
||||||
|
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
|
||||||
|
std::shared_ptr<const i2p::data::Lease> remoteLease;
|
||||||
|
if (!remoteSession->CleanupUnconfirmedTags ()) // no stuck tags
|
||||||
|
{
|
||||||
|
outboundTunnel = path->outboundTunnel;
|
||||||
|
remoteLease = path->remoteLease;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remoteSession->SetSharedRoutingPath (nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// create Data message
|
||||||
|
auto msg = m_I2NPMsgsPool.AcquireSharedMt ();
|
||||||
|
uint8_t * buf = msg->GetPayload ();
|
||||||
|
htobe32buf (buf, len);
|
||||||
|
memcpy (buf + 4, payload, len);
|
||||||
|
msg->len += len + 4;
|
||||||
|
msg->FillI2NPMessageHeader (eI2NPData);
|
||||||
|
// wrap in gralic
|
||||||
|
auto garlic = remoteSession->WrapSingleMessage (msg);
|
||||||
|
// send
|
||||||
|
bool sent = SendMsg (garlic, outboundTunnel, remoteLease);
|
||||||
|
m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
|
||||||
|
if (!sent)
|
||||||
|
remoteSession->SetSharedRoutingPath (nullptr);
|
||||||
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2CPDestination::CleanupDestination ()
|
||||||
|
{
|
||||||
|
m_I2NPMsgsPool.CleanUpMt ();
|
||||||
|
if (m_Owner) m_Owner->CleanupRoutingSessions ();
|
||||||
|
}
|
||||||
|
|
||||||
RunnableI2CPDestination::RunnableI2CPDestination (std::shared_ptr<I2CPSession> owner,
|
RunnableI2CPDestination::RunnableI2CPDestination (std::shared_ptr<I2CPSession> owner,
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params):
|
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params):
|
||||||
RunnableService ("I2CP"),
|
RunnableService ("I2CP"),
|
||||||
I2CPDestination (GetIOService (), owner, identity, isPublic, params)
|
I2CPDestination (GetIOService (), owner, identity, isPublic, false, params)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,8 +341,8 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
||||||
m_Owner (owner), m_Socket (socket), m_SessionID (0xFFFF),
|
m_Owner (owner), m_Socket (socket), m_SessionID (0xFFFF), m_MessageID (0),
|
||||||
m_MessageID (0), m_IsSendAccepted (true), m_IsSending (false)
|
m_IsSendAccepted (true), m_IsSending (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +353,11 @@ namespace client
|
|||||||
|
|
||||||
void I2CPSession::Start ()
|
void I2CPSession::Start ()
|
||||||
{
|
{
|
||||||
|
if (m_Socket)
|
||||||
|
{
|
||||||
|
m_Socket->set_option (boost::asio::socket_base::receive_buffer_size (I2CP_MAX_MESSAGE_LENGTH));
|
||||||
|
m_Socket->set_option (boost::asio::socket_base::send_buffer_size (I2CP_MAX_MESSAGE_LENGTH));
|
||||||
|
}
|
||||||
ReadProtocolByte ();
|
ReadProtocolByte ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +404,27 @@ namespace client
|
|||||||
if (m_PayloadLen > 0)
|
if (m_PayloadLen > 0)
|
||||||
{
|
{
|
||||||
if (m_PayloadLen <= I2CP_MAX_MESSAGE_LENGTH)
|
if (m_PayloadLen <= I2CP_MAX_MESSAGE_LENGTH)
|
||||||
ReceivePayload ();
|
{
|
||||||
|
if (!m_Socket) return;
|
||||||
|
boost::system::error_code ec;
|
||||||
|
size_t moreBytes = m_Socket->available(ec);
|
||||||
|
if (!ec)
|
||||||
|
{
|
||||||
|
if (moreBytes >= m_PayloadLen)
|
||||||
|
{
|
||||||
|
// read and process payload immediately if available
|
||||||
|
moreBytes = boost::asio::read (*m_Socket, boost::asio::buffer(m_Payload, m_PayloadLen), boost::asio::transfer_all (), ec);
|
||||||
|
HandleReceivedPayload (ec, moreBytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ReceivePayload ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "I2CP: Socket error: ", ec.message ());
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2CP: Unexpected payload length ", m_PayloadLen);
|
LogPrint (eLogError, "I2CP: Unexpected payload length ", m_PayloadLen);
|
||||||
@ -558,13 +649,13 @@ namespace client
|
|||||||
if (!m_Destination)
|
if (!m_Destination)
|
||||||
{
|
{
|
||||||
m_Destination = m_Owner.IsSingleThread () ?
|
m_Destination = m_Owner.IsSingleThread () ?
|
||||||
std::make_shared<I2CPDestination>(m_Owner.GetService (), shared_from_this (), identity, true, params):
|
std::make_shared<I2CPDestination>(m_Owner.GetService (), shared_from_this (), identity, true, true, params):
|
||||||
std::make_shared<RunnableI2CPDestination>(shared_from_this (), identity, true, params);
|
std::make_shared<RunnableI2CPDestination>(shared_from_this (), identity, true, params);
|
||||||
if (m_Owner.InsertSession (shared_from_this ()))
|
if (m_Owner.InsertSession (shared_from_this ()))
|
||||||
{
|
{
|
||||||
SendSessionStatusMessage (eI2CPSessionStatusCreated); // created
|
|
||||||
LogPrint (eLogDebug, "I2CP: Session ", m_SessionID, " created");
|
LogPrint (eLogDebug, "I2CP: Session ", m_SessionID, " created");
|
||||||
m_Destination->Start ();
|
m_Destination->Start ();
|
||||||
|
SendSessionStatusMessage (eI2CPSessionStatusCreated); // created
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -584,7 +675,7 @@ namespace client
|
|||||||
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::DestroySessionMessageHandler (const uint8_t * buf, size_t len)
|
void I2CPSession::DestroySessionMessageHandler (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
SendSessionStatusMessage (eI2CPSessionStatusDestroyed); // destroy
|
SendSessionStatusMessage (eI2CPSessionStatusDestroyed); // destroy
|
||||||
@ -669,6 +760,25 @@ namespace client
|
|||||||
SendI2CPMessage (I2CP_MESSAGE_STATUS_MESSAGE, buf, 15);
|
SendI2CPMessage (I2CP_MESSAGE_STATUS_MESSAGE, buf, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2CPSession::AddRoutingSession (const i2p::data::IdentHash& signingKey, std::shared_ptr<i2p::garlic::GarlicRoutingSession> remoteSession)
|
||||||
|
{
|
||||||
|
if (!remoteSession) return;
|
||||||
|
std::lock_guard<std::mutex> l(m_RoutingSessionsMutex);
|
||||||
|
m_RoutingSessions[signingKey] = remoteSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CPSession::CleanupRoutingSessions ()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_RoutingSessionsMutex);
|
||||||
|
for (auto it = m_RoutingSessions.begin (); it != m_RoutingSessions.end ();)
|
||||||
|
{
|
||||||
|
if (it->second->IsTerminated ())
|
||||||
|
it = m_RoutingSessions.erase (it);
|
||||||
|
else
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void I2CPSession::CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len)
|
void I2CPSession::CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
uint16_t sessionID = bufbe16toh (buf);
|
uint16_t sessionID = bufbe16toh (buf);
|
||||||
@ -739,19 +849,44 @@ namespace client
|
|||||||
size_t offset = 2;
|
size_t offset = 2;
|
||||||
if (m_Destination)
|
if (m_Destination)
|
||||||
{
|
{
|
||||||
i2p::data::IdentityEx identity;
|
const uint8_t * ident = buf + offset;
|
||||||
size_t identsize = identity.FromBuffer (buf + offset, len - offset);
|
size_t identSize = i2p::data::GetIdentityBufferLen (ident, len - offset);
|
||||||
if (identsize)
|
if (identSize)
|
||||||
{
|
{
|
||||||
offset += identsize;
|
offset += identSize;
|
||||||
uint32_t payloadLen = bufbe32toh (buf + offset);
|
uint32_t payloadLen = bufbe32toh (buf + offset);
|
||||||
if (payloadLen + offset <= len)
|
if (payloadLen + offset <= len)
|
||||||
{
|
{
|
||||||
offset += 4;
|
offset += 4;
|
||||||
uint32_t nonce = bufbe32toh (buf + offset + payloadLen);
|
uint32_t nonce = bufbe32toh (buf + offset + payloadLen);
|
||||||
if (m_IsSendAccepted)
|
if (m_Destination->IsReady ())
|
||||||
SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted
|
{
|
||||||
m_Destination->SendMsgTo (buf + offset, payloadLen, identity.GetIdentHash (), nonce);
|
if (m_IsSendAccepted)
|
||||||
|
SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted
|
||||||
|
std::shared_ptr<i2p::garlic::GarlicRoutingSession> remoteSession;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_RoutingSessionsMutex);
|
||||||
|
auto it = m_RoutingSessions.find (ident + i2p::data::DEFAULT_IDENTITY_SIZE - 35); // 32 bytes signing key
|
||||||
|
if (it != m_RoutingSessions.end ())
|
||||||
|
{
|
||||||
|
if (!it->second->IsTerminated ())
|
||||||
|
remoteSession = it->second;
|
||||||
|
else
|
||||||
|
m_RoutingSessions.erase (it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!remoteSession || !m_Destination->SendMsg (buf + offset, payloadLen, remoteSession, nonce))
|
||||||
|
{
|
||||||
|
i2p::data::IdentHash identHash;
|
||||||
|
SHA256(ident, identSize, identHash); // caclulate ident hash, because we don't need full identity
|
||||||
|
m_Destination->SendMsgTo (buf + offset, payloadLen, identHash, nonce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint(eLogInfo, "I2CP: Destination is not ready");
|
||||||
|
SendMessageStatusMessage (nonce, eI2CPMessageStatusNoLocalTunnels);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint(eLogError, "I2CP: Cannot send message, too big");
|
LogPrint(eLogError, "I2CP: Cannot send message, too big");
|
||||||
@ -891,8 +1026,12 @@ namespace client
|
|||||||
{
|
{
|
||||||
uint8_t limits[64];
|
uint8_t limits[64];
|
||||||
memset (limits, 0, 64);
|
memset (limits, 0, 64);
|
||||||
htobe32buf (limits, i2p::transport::transports.GetInBandwidth ()); // inbound
|
uint32_t limit; i2p::config::GetOption("i2cp.inboundlimit", limit);
|
||||||
htobe32buf (limits + 4, i2p::transport::transports.GetOutBandwidth ()); // outbound
|
if (!limit) limit = i2p::context.GetBandwidthLimit ();
|
||||||
|
htobe32buf (limits, limit); // inbound
|
||||||
|
i2p::config::GetOption("i2cp.outboundlimit", limit);
|
||||||
|
if (!limit) limit = i2p::context.GetBandwidthLimit ();
|
||||||
|
htobe32buf (limits + 4, limit); // outbound
|
||||||
SendI2CPMessage (I2CP_BANDWIDTH_LIMITS_MESSAGE, limits, 64);
|
SendI2CPMessage (I2CP_BANDWIDTH_LIMITS_MESSAGE, limits, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@ -12,8 +12,10 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "Destination.h"
|
#include "Destination.h"
|
||||||
@ -58,6 +60,7 @@ namespace client
|
|||||||
eI2CPMessageStatusAccepted = 1,
|
eI2CPMessageStatusAccepted = 1,
|
||||||
eI2CPMessageStatusGuaranteedSuccess = 4,
|
eI2CPMessageStatusGuaranteedSuccess = 4,
|
||||||
eI2CPMessageStatusGuaranteedFailure = 5,
|
eI2CPMessageStatusGuaranteedFailure = 5,
|
||||||
|
eI2CPMessageStatusNoLocalTunnels = 16,
|
||||||
eI2CPMessageStatusNoLeaseSet = 21
|
eI2CPMessageStatusNoLeaseSet = 21
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,7 +82,8 @@ namespace client
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner,
|
I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner,
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params);
|
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, bool isSameThread,
|
||||||
|
const std::map<std::string, std::string>& params);
|
||||||
~I2CPDestination () {};
|
~I2CPDestination () {};
|
||||||
|
|
||||||
void Stop ();
|
void Stop ();
|
||||||
@ -90,7 +94,8 @@ namespace client
|
|||||||
void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
|
void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
|
||||||
void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession
|
void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession
|
||||||
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
|
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
|
||||||
|
bool SendMsg (const uint8_t * payload, size_t len, std::shared_ptr<i2p::garlic::GarlicRoutingSession> remoteSession, uint32_t nonce);
|
||||||
|
|
||||||
// implements LocalDestination
|
// implements LocalDestination
|
||||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const;
|
bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||||
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const;
|
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const;
|
||||||
@ -99,6 +104,7 @@ namespace client
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
void CleanupDestination ();
|
||||||
// I2CP
|
// I2CP
|
||||||
void HandleDataMessage (const uint8_t * buf, size_t len);
|
void HandleDataMessage (const uint8_t * buf, size_t len);
|
||||||
void CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels);
|
void CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels);
|
||||||
@ -108,7 +114,9 @@ namespace client
|
|||||||
std::shared_ptr<I2CPDestination> GetSharedFromThis ()
|
std::shared_ptr<I2CPDestination> GetSharedFromThis ()
|
||||||
{ return std::static_pointer_cast<I2CPDestination>(shared_from_this ()); }
|
{ return std::static_pointer_cast<I2CPDestination>(shared_from_this ()); }
|
||||||
bool SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
|
bool SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
|
||||||
|
bool SendMsg (std::shared_ptr<I2NPMessage> garlic,
|
||||||
|
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel, std::shared_ptr<const i2p::data::Lease> remoteLease);
|
||||||
|
|
||||||
void PostCreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
|
void PostCreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -120,7 +128,7 @@ namespace client
|
|||||||
std::shared_ptr<i2p::crypto::ECIESX25519AEADRatchetDecryptor> m_ECIESx25519Decryptor;
|
std::shared_ptr<i2p::crypto::ECIESX25519AEADRatchetDecryptor> m_ECIESx25519Decryptor;
|
||||||
uint8_t m_ECIESx25519PrivateKey[32];
|
uint8_t m_ECIESx25519PrivateKey[32];
|
||||||
uint64_t m_LeaseSetExpirationTime;
|
uint64_t m_LeaseSetExpirationTime;
|
||||||
bool m_IsCreatingLeaseSet;
|
bool m_IsCreatingLeaseSet, m_IsSameThread;
|
||||||
boost::asio::deadline_timer m_LeaseSetCreationTimer;
|
boost::asio::deadline_timer m_LeaseSetCreationTimer;
|
||||||
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool;
|
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool;
|
||||||
};
|
};
|
||||||
@ -155,6 +163,8 @@ namespace client
|
|||||||
void SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len);
|
void SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len);
|
||||||
void SendMessagePayloadMessage (const uint8_t * payload, size_t len);
|
void SendMessagePayloadMessage (const uint8_t * payload, size_t len);
|
||||||
void SendMessageStatusMessage (uint32_t nonce, I2CPMessageStatus status);
|
void SendMessageStatusMessage (uint32_t nonce, I2CPMessageStatus status);
|
||||||
|
void AddRoutingSession (const i2p::data::IdentHash& signingKey, std::shared_ptr<i2p::garlic::GarlicRoutingSession> remoteSession);
|
||||||
|
void CleanupRoutingSessions ();
|
||||||
|
|
||||||
// message handlers
|
// message handlers
|
||||||
void GetDateMessageHandler (const uint8_t * buf, size_t len);
|
void GetDateMessageHandler (const uint8_t * buf, size_t len);
|
||||||
@ -186,7 +196,7 @@ namespace client
|
|||||||
void ExtractMapping (const uint8_t * buf, size_t len, std::map<std::string, std::string>& mapping);
|
void ExtractMapping (const uint8_t * buf, size_t len, std::map<std::string, std::string>& mapping);
|
||||||
void SendSessionStatusMessage (I2CPSessionStatus status);
|
void SendSessionStatusMessage (I2CPSessionStatus status);
|
||||||
void SendHostReplyMessage (uint32_t requestID, std::shared_ptr<const i2p::data::IdentityEx> identity);
|
void SendHostReplyMessage (uint32_t requestID, std::shared_ptr<const i2p::data::IdentityEx> identity);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
I2CPServer& m_Owner;
|
I2CPServer& m_Owner;
|
||||||
@ -195,6 +205,8 @@ namespace client
|
|||||||
size_t m_PayloadLen;
|
size_t m_PayloadLen;
|
||||||
|
|
||||||
std::shared_ptr<I2CPDestination> m_Destination;
|
std::shared_ptr<I2CPDestination> m_Destination;
|
||||||
|
std::mutex m_RoutingSessionsMutex;
|
||||||
|
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<i2p::garlic::GarlicRoutingSession> > m_RoutingSessions; // signing key->session
|
||||||
uint16_t m_SessionID;
|
uint16_t m_SessionID;
|
||||||
uint32_t m_MessageID;
|
uint32_t m_MessageID;
|
||||||
bool m_IsSendAccepted;
|
bool m_IsSendAccepted;
|
||||||
@ -224,8 +236,6 @@ namespace client
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
|
||||||
|
|
||||||
void Accept ();
|
void Accept ();
|
||||||
|
|
||||||
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||||
|
Loading…
Reference in New Issue
Block a user