mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-07 06:09:42 +00:00
Compare commits
4 Commits
2.48.0
...
static-bui
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7a882582f | ||
|
|
250696a7b5 | ||
|
|
af7905744e | ||
|
|
db2364e9aa |
@@ -30,7 +30,3 @@ indent_size = 4
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
25
.github/workflows/build-deb.yml
vendored
25
.github/workflows/build-deb.yml
vendored
@@ -6,34 +6,27 @@ jobs:
|
||||
build:
|
||||
name: ${{ matrix.dist }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
dist: ['buster', 'bullseye', 'bookworm']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build package
|
||||
uses: jtdor/build-deb-action@v1
|
||||
- name: change debian changelog
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install devscripts
|
||||
debchange -v "`git describe --tags`-${{ matrix.dist }}" -b -M --distribution ${{ matrix.dist }} "trunk build"
|
||||
- uses: jtdor/build-deb-action@v1
|
||||
with:
|
||||
docker-image: debian:${{ matrix.dist }}-slim
|
||||
buildpackage-opts: --build=binary --no-sign
|
||||
before-build-hook: debchange --controlmaint --local "+${{ github.sha }}~${{ matrix.dist }}" -b --distribution ${{ matrix.dist }} "CI build"
|
||||
extra-build-deps: devscripts git
|
||||
|
||||
- name: Upload package
|
||||
uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: i2pd_${{ matrix.dist }}
|
||||
path: debian/artifacts/i2pd_*.deb
|
||||
|
||||
- name: Upload debugging symbols
|
||||
uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: i2pd-dbgsym_${{ matrix.dist }}
|
||||
path: debian/artifacts/i2pd-dbgsym_*.deb
|
||||
|
||||
10
.github/workflows/build-freebsd.yml
vendored
10
.github/workflows/build-freebsd.yml
vendored
@@ -6,11 +6,8 @@ jobs:
|
||||
build:
|
||||
runs-on: macos-12
|
||||
name: with UPnP
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v0.3.0
|
||||
@@ -24,9 +21,8 @@ jobs:
|
||||
cd build
|
||||
cmake -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release .
|
||||
gmake -j2
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: i2pd-freebsd
|
||||
path: build/i2pd
|
||||
path: build/i2pd
|
||||
7
.github/workflows/build-osx.yml
vendored
7
.github/workflows/build-osx.yml
vendored
@@ -6,21 +6,16 @@ jobs:
|
||||
build:
|
||||
name: With USE_UPNP=${{ matrix.with_upnp }}
|
||||
runs-on: macOS-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
with_upnp: ['yes', 'no']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: install packages
|
||||
run: |
|
||||
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
|
||||
brew update
|
||||
brew install boost miniupnpc openssl@1.1
|
||||
|
||||
- name: build application
|
||||
run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3
|
||||
|
||||
52
.github/workflows/build-windows-msvc.yml
vendored
52
.github/workflows/build-windows-msvc.yml
vendored
@@ -1,52 +0,0 @@
|
||||
name: Build on Windows with MSVC
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build and install zlib
|
||||
run: |
|
||||
powershell -Command "(Invoke-WebRequest -Uri https://raw.githubusercontent.com/r4sas/zlib.install/master/install.bat -OutFile install_zlib.bat)"
|
||||
powershell -Command "(Get-Content install_zlib.bat) | Set-Content install_zlib.bat" # fixing line endings
|
||||
set BUILD_TYPE=Debug
|
||||
./install_zlib.bat
|
||||
set BUILD_TYPE=Release
|
||||
./install_zlib.bat
|
||||
del install_zlib.bat
|
||||
|
||||
- name: Install Boost
|
||||
uses: crazy-max/ghaction-chocolatey@v2
|
||||
with:
|
||||
args: install boost-msvc-14.3
|
||||
|
||||
- name: Install OpenSSL
|
||||
uses: crazy-max/ghaction-chocolatey@v2
|
||||
with:
|
||||
args: install openssl
|
||||
|
||||
- name: Configure
|
||||
working-directory: build
|
||||
run: cmake -DWITH_STATIC=ON .
|
||||
|
||||
- name: Build
|
||||
working-directory: build
|
||||
run: cmake --build . --config Debug -- -m
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: i2pd-msvc
|
||||
path: build/Debug/i2pd.*
|
||||
|
||||
86
.github/workflows/build-windows.yml
vendored
86
.github/workflows/build-windows.yml
vendored
@@ -8,106 +8,44 @@ defaults:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.arch }}
|
||||
name: Building using ${{ matrix.arch }} toolchain
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
fail-fast: true
|
||||
matrix:
|
||||
include: [
|
||||
{ msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt, compiler: gcc },
|
||||
{ msystem: CLANG64, arch: clang-x86_64, arch_short: x64-clang, compiler: clang },
|
||||
{ msystem: MINGW64, arch: x86_64, arch_short: x64, compiler: gcc },
|
||||
{ msystem: MINGW32, arch: i686, arch_short: x86, compiler: gcc }
|
||||
{ msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt },
|
||||
{ msystem: MINGW64, arch: x86_64, arch_short: x64 },
|
||||
{ msystem: MINGW32, arch: i686, arch_short: x86 }
|
||||
]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
install: base-devel git mingw-w64-${{ matrix.arch }}-${{ matrix.compiler }} mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
|
||||
install: base-devel mingw-w64-${{ matrix.arch }}-gcc mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
|
||||
update: true
|
||||
|
||||
- name: Install additional clang packages
|
||||
if: ${{ matrix.msystem == 'CLANG64' }}
|
||||
run: pacman --noconfirm -S mingw-w64-${{ matrix.arch }}-gcc-compat
|
||||
|
||||
- name: Build application
|
||||
run: |
|
||||
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
|
||||
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes -j3
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: i2pd-${{ matrix.arch_short }}.exe
|
||||
path: i2pd.exe
|
||||
|
||||
build-cmake:
|
||||
name: CMake ${{ matrix.arch }}
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include: [
|
||||
{ msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt, compiler: gcc },
|
||||
{ msystem: CLANG64, arch: clang-x86_64, arch_short: x64-clang, compiler: clang },
|
||||
{ msystem: MINGW64, arch: x86_64, arch_short: x64, compiler: gcc },
|
||||
{ msystem: MINGW32, arch: i686, arch_short: x86, compiler: gcc }
|
||||
]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
install: base-devel git mingw-w64-${{ matrix.arch }}-cmake mingw-w64-${{ matrix.arch }}-ninja mingw-w64-${{ matrix.arch }}-${{ matrix.compiler }} mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
|
||||
update: true
|
||||
|
||||
- name: Build application
|
||||
run: |
|
||||
cd build
|
||||
cmake -DWITH_GIT_VERSION=ON -DWITH_STATIC=ON -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release .
|
||||
cmake --build . -- -j3
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: i2pd-cmake-${{ matrix.arch_short }}.exe
|
||||
path: build/i2pd.exe
|
||||
|
||||
build-xp:
|
||||
name: XP
|
||||
name: Building for Windows XP
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW32
|
||||
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc
|
||||
update: true
|
||||
|
||||
- name: Build WinXP-capable CRT packages
|
||||
run: |
|
||||
git clone https://github.com/msys2/MINGW-packages
|
||||
@@ -126,14 +64,12 @@ jobs:
|
||||
pacman --noconfirm -U mingw-w64-i686-libwinpthread-git-*-any.pkg.tar.zst mingw-w64-i686-winpthreads-git-*-any.pkg.tar.zst
|
||||
popd
|
||||
popd
|
||||
|
||||
- name: Build application
|
||||
run: |
|
||||
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
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: i2pd-xp.exe
|
||||
path: i2pd.exe
|
||||
|
||||
35
.github/workflows/build.yml
vendored
35
.github/workflows/build.yml
vendored
@@ -5,45 +5,50 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
build-make:
|
||||
name: Make with USE_UPNP=${{ matrix.with_upnp }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
with_upnp: ['yes', 'no']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: install packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
|
||||
|
||||
- name: build application
|
||||
run: make USE_UPNP=${{ matrix.with_upnp }} -j3
|
||||
|
||||
build-cmake:
|
||||
name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
with_upnp: ['ON', 'OFF']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: install packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential cmake libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
|
||||
|
||||
- name: build application
|
||||
run: |
|
||||
cd build
|
||||
cmake -DWITH_UPNP=${{ matrix.with_upnp }} .
|
||||
make -j3
|
||||
build-static:
|
||||
name: Static build with UPnP
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
|
||||
- name: build application
|
||||
run: make DEBUG=no USE_STATIC=yes USE_UPNP=yes -j`nproc`
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: i2pd-amd64-static
|
||||
path: i2pd
|
||||
|
||||
168
.github/workflows/docker.yml
vendored
168
.github/workflows/docker.yml
vendored
@@ -10,7 +10,6 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Building container for ${{ matrix.platform }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
@@ -26,44 +25,41 @@ jobs:
|
||||
]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login to GitHub Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build container for ${{ matrix.archname }}
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: ./contrib/docker
|
||||
file: ./contrib/docker/Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: true
|
||||
tags: |
|
||||
purplei2p/i2pd:latest-${{ matrix.archname }}
|
||||
ghcr.io/purplei2p/i2pd:latest-${{ matrix.archname }}
|
||||
provenance: false
|
||||
- name: Build container for ${{ matrix.archname }}
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: ./contrib/docker
|
||||
file: ./contrib/docker/Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: true
|
||||
tags: |
|
||||
purplei2p/i2pd:latest-${{ matrix.archname }}
|
||||
ghcr.io/purplei2p/i2pd:latest-${{ matrix.archname }}
|
||||
|
||||
push:
|
||||
name: Pushing merged manifest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
@@ -71,60 +67,74 @@ jobs:
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login to GitHub Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create and push latest manifest image to Docker Hub
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
inputs: purplei2p/i2pd:latest
|
||||
images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
- name: Create and push latest manifest image to Docker Hub
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
base-image: purplei2p/i2pd:latest
|
||||
extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
|
||||
- name: Create and push latest manifest image to GHCR
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
inputs: ghcr.io/purplei2p/i2pd:latest
|
||||
images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
- name: Create and push latest manifest image to GHCR
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
base-image: ghcr.io/purplei2p/i2pd:latest
|
||||
extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
|
||||
- name: Store release version to env
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
|
||||
- name: Store release version to env
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
|
||||
|
||||
- name: Create and push release manifest to Docker Hub
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
inputs: purplei2p/i2pd:latest,purplei2p/i2pd:latest-release,purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
|
||||
images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
- name: Create and push release manifest image to Docker Hub
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
base-image: purplei2p/i2pd:latest-release
|
||||
extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
|
||||
- name: Create and push release manifest to GHCR
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
inputs: ghcr.io/purplei2p/i2pd:latest,ghcr.io/purplei2p/i2pd:latest-release,ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
|
||||
images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
- name: Create and push release manifest image to GHCR
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
base-image: ghcr.io/purplei2p/i2pd:latest-release
|
||||
extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
|
||||
- name: Create and push versioned manifest image to Docker Hub
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
base-image: purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
|
||||
extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
|
||||
- name: Create and push versioned manifest image to GHCR
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
base-image: ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
|
||||
extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
|
||||
push: true
|
||||
|
||||
84
ChangeLog
84
ChangeLog
@@ -1,88 +1,6 @@
|
||||
# for this file format description,
|
||||
# see https://github.com/olivierlacan/keep-a-changelog
|
||||
|
||||
## [2.48.0] - 2023-06-12
|
||||
### Added
|
||||
- Allow user/password authentication method for SOCK5 proxy
|
||||
- Publish reject all congestion cap 'G' if transit is not accepted
|
||||
- 'critical' log level
|
||||
- Print b32 on webconsole destination page
|
||||
- Webconsole button to drop a remote LeaseSet
|
||||
- limits.zombies param - minimum percentage of successfully created tunnels for routers cleanup
|
||||
- Recognize real routers if successfully connected or responded to tunnel build request
|
||||
### Changed
|
||||
- Bypass slow transport sessions for first hop selection
|
||||
- Limit AESNI inline asm to x86/x64
|
||||
- Create smaller I2NP packets if possible
|
||||
- Make router unreachable if AEAD tag verification fails in SessionCreated
|
||||
- Don't include a router to floodfills list until it's confirmed as real
|
||||
- Drop LeaseSet store request if not floodfill
|
||||
- Bypass medium congestion('D') routers for client tunnels
|
||||
- Publish encrypted RouterInfo through tunnels
|
||||
- Check if s is valid x25519 public key
|
||||
- Check if socket is open before sending data in SSU2
|
||||
### Fixed
|
||||
- Webconsole empty page if destination is not found
|
||||
- i2p.streaming.answerPings param
|
||||
- Reload tunnels
|
||||
- Address caps for unspecified ipv6 address
|
||||
- Incomplete HTTP headers in I2P tunnels
|
||||
- SSU2 socket network exceptions on Windows
|
||||
- Use of 'server' type tunnel port as inport (#1936)
|
||||
|
||||
## [2.47.0] - 2023-03-11
|
||||
### Added
|
||||
- Congestion caps
|
||||
- SAM UDP port parameter
|
||||
- Support domain addresses for yggdrasil reseeds
|
||||
### Changed
|
||||
- DHT for floodfills instead plain list
|
||||
- Process router's messages in separate thread
|
||||
- Don't publish non-reachable router
|
||||
- Send and check target destination in first streaming SYN packet
|
||||
- Reseeds list
|
||||
### Fixed
|
||||
- Memory leak in windows network state detection
|
||||
- Reseed attempts from invalid address
|
||||
|
||||
## [2.46.1] - 2023-02-20
|
||||
### Fixed
|
||||
- Race condition while getting router's peer profile
|
||||
- Creation of new router.info
|
||||
- Displaying LeaseSets in the webconsole
|
||||
- Crash when processing ACK request
|
||||
|
||||
## [2.46.0] - 2023-02-15
|
||||
### Added
|
||||
- Limit number of acked SSU2 packets to 511
|
||||
- Localization to Swedish, Portuguese, Turkish, Polish
|
||||
- Periodically send Datetime block in NTCP2 and SSU2
|
||||
- Don't select random port from reserved
|
||||
- In memory table for peer profiles
|
||||
- Store if router was unreachable in it's peer profile
|
||||
- Show IPv6 addresses in square brackets in webconsole
|
||||
- Check referer when processing Addresshelper
|
||||
### Changed
|
||||
- Algorithm for tunnel creation success rate calculation
|
||||
- Drop incoming NTCP2 and SSU2 connection if published IP doesn't match actual endpoint
|
||||
- Exclude actually unreachable router from netdb for 2 hours
|
||||
- Select first hop from high bandwidth peers for client tunnels
|
||||
- Drop too long or too short LeaseSet
|
||||
- Delete router from netdb if became invalid after update
|
||||
- Terminate existing session if clock skew detected
|
||||
- Close previous UDP socket if open before reopening
|
||||
- Minimal version for floodfill is 0.9.51
|
||||
- Sort transports by endpoints in webconsole
|
||||
### Fixed
|
||||
- Deadlock during processing I2NP block with Garlic in ECIES encrypted message to router
|
||||
- Race condition with encrypted LeaseSets
|
||||
- HTTP query detection
|
||||
- Connection attempts to IPs from invalid ranges
|
||||
- Publish "0.0.0.0" in RouterInfo
|
||||
- Crash upon receiving PeerTest 7
|
||||
- Tunnels for closed SAM session socket
|
||||
- Missing NTCP2 address in RouterInfo if enabled back
|
||||
|
||||
## [2.45.1] - 2023-01-11
|
||||
### Added
|
||||
- Full Cone NAT status error
|
||||
@@ -91,7 +9,7 @@
|
||||
- Set rejection code 30 if tunnel with id already exists
|
||||
- Network status is always OK if peer test msg 5 received
|
||||
### Fixed
|
||||
- UPnP crash if SSU2 or NTCP2 is disabled
|
||||
- UPnP crash if SSU2 or NTCP2 is disabled
|
||||
- Crash on termination for some platforms
|
||||
|
||||
## [2.45.0] - 2023-01-03
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
||||
16
Makefile
16
Makefile
@@ -71,15 +71,13 @@ else # not supported
|
||||
$(error Not supported platform)
|
||||
endif
|
||||
|
||||
INCFLAGS += -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR)
|
||||
DEFINES += -DOPENSSL_SUPPRESS_DEPRECATED
|
||||
NEEDED_CXXFLAGS += -MMD -MP
|
||||
|
||||
ifeq ($(USE_GIT_VERSION),yes)
|
||||
GIT_VERSION := $(shell git describe --tags)
|
||||
DEFINES += -DGITVER=$(GIT_VERSION)
|
||||
NEEDED_CXXFLAGS += -DGITVER=\"$(GIT_VERSION)\"
|
||||
endif
|
||||
|
||||
NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR) -DOPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
||||
LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
||||
LANG_OBJS += $(patsubst %.cpp,obj/%.o,$(LANG_SRC))
|
||||
@@ -112,17 +110,17 @@ wrapper: api_client $(SHLIB_WRAP) $(ARLIB_WRAP)
|
||||
## custom FLAGS to work at build-time.
|
||||
|
||||
obj/%.o: %.cpp | mk_obj_dir
|
||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(DEFINES) $(INCFLAGS) -c -o $@ $<
|
||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -c -o $@ $<
|
||||
|
||||
# '-' is 'ignore if missing' on first run
|
||||
-include $(DEPS)
|
||||
|
||||
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG)
|
||||
$(CXX) -o $@ $(DEFINES) $(LDFLAGS) $^ $(LDLIBS)
|
||||
$(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS)
|
||||
|
||||
$(SHLIB): $(LIB_OBJS)
|
||||
$(SHLIB): $(LIB_OBJS) $(SHLIB_LANG)
|
||||
ifneq ($(USE_STATIC),yes)
|
||||
$(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS)
|
||||
$(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) $(SHLIB_LANG)
|
||||
endif
|
||||
|
||||
$(SHLIB_CLIENT): $(LIB_CLIENT_OBJS) $(SHLIB) $(SHLIB_LANG)
|
||||
|
||||
@@ -6,8 +6,7 @@ CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misl
|
||||
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
|
||||
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
|
||||
## custom FLAGS to work at build-time.
|
||||
NEEDED_CXXFLAGS = -std=c++11
|
||||
DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
||||
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
|
||||
|
||||
@@ -33,38 +33,26 @@ endif
|
||||
|
||||
NEEDED_CXXFLAGS += -fPIC
|
||||
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
# NOTE: on glibc you will get this warning:
|
||||
# Using 'getaddrinfo' in statically linked applications requires at runtime
|
||||
# the shared libraries from the glibc version used for linking
|
||||
LIBDIR := /usr/lib/$(SYS)
|
||||
LDLIBS += $(LIBDIR)/libboost_system.a
|
||||
LDLIBS += $(LIBDIR)/libboost_date_time.a
|
||||
LDLIBS += $(LIBDIR)/libboost_filesystem.a
|
||||
LDLIBS += $(LIBDIR)/libboost_program_options.a
|
||||
LDLIBS += $(LIBDIR)/libssl.a
|
||||
LDLIBS += $(LIBDIR)/libcrypto.a
|
||||
LDLIBS += $(LIBDIR)/libz.a
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDLIBS += $(LIBDIR)/libminiupnpc.a
|
||||
endif
|
||||
LDLIBS += -lpthread -ldl
|
||||
else
|
||||
LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDLIBS += -lminiupnpc
|
||||
endif
|
||||
endif
|
||||
LDLIBS += -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lssl -lcrypto -lz
|
||||
|
||||
# UPNP Support (miniupnpc 1.5 and higher)
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
DEFINES += -DUSE_UPNP
|
||||
LDLIBS += -lminiupnpc
|
||||
NEEDED_CXXFLAGS += -DUSE_UPNP
|
||||
endif
|
||||
|
||||
# NOTE: on glibc you will get this warning:
|
||||
# Using 'getaddrinfo' in statically linked applications requires at runtime
|
||||
# the shared libraries from the glibc version used for linking
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS += -static -ldl -lpthread -static-libgcc -static-libstdc++
|
||||
else
|
||||
LDLIBS += -lpthread
|
||||
endif
|
||||
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that
|
||||
NEEDED_CXXFLAGS += -maes
|
||||
DEFINES += -D__AES__
|
||||
NEEDED_CXXFLAGS += -D__AES__ -maes
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
@@ -4,18 +4,17 @@ USE_WIN32_APP := yes
|
||||
WINDRES = windres
|
||||
|
||||
CXXFLAGS := $(CXX_DEBUG) -fPIC -msse
|
||||
INCFLAGS := -I$(DAEMON_SRC_DIR) -IWin32
|
||||
INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32
|
||||
LDFLAGS := ${LD_DEBUG} -static
|
||||
|
||||
NEEDED_CXXFLAGS += -std=c++17
|
||||
DEFINES += -DWIN32_LEAN_AND_MEAN
|
||||
NEEDED_CXXFLAGS += -std=c++17 -DWIN32_LEAN_AND_MEAN
|
||||
|
||||
# Boost libraries suffix
|
||||
BOOST_SUFFIX = -mt
|
||||
|
||||
# UPNP Support
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
DEFINES += -DUSE_UPNP -DMINIUPNP_STATICLIB
|
||||
CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB
|
||||
LDLIBS = -lminiupnpc
|
||||
endif
|
||||
|
||||
@@ -36,19 +35,18 @@ LDLIBS += \
|
||||
-lpthread
|
||||
|
||||
ifeq ($(USE_WIN32_APP), yes)
|
||||
DEFINES += -DWIN32_APP
|
||||
NEEDED_CXXFLAGS += -DWIN32_APP
|
||||
LDFLAGS += -mwindows
|
||||
DAEMON_RC += Win32/Resource.rc
|
||||
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
||||
endif
|
||||
|
||||
ifeq ($(USE_WINXP_FLAGS), yes)
|
||||
DEFINES += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
|
||||
NEEDED_CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
|
||||
endif
|
||||
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
NEEDED_CXXFLAGS += -maes
|
||||
DEFINES += -D__AES__
|
||||
NEEDED_CXXFLAGS += -D__AES__ -maes
|
||||
endif
|
||||
|
||||
ifeq ($(USE_ASLR),yes)
|
||||
@@ -56,4 +54,4 @@ ifeq ($(USE_ASLR),yes)
|
||||
endif
|
||||
|
||||
obj/%.o : %.rc | mk_obj_dir
|
||||
$(WINDRES) $(DEFINES) $(INCFLAGS) --preprocessor-arg=-MMD --preprocessor-arg=-MP --preprocessor-arg=-MF$@.d -i $< -o $@
|
||||
$(WINDRES) -i $< -o $@
|
||||
|
||||
17
Makefile.osx
17
Makefile.osx
@@ -1,7 +1,6 @@
|
||||
CXX = clang++
|
||||
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11
|
||||
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX
|
||||
INCFLAGS = -I/usr/local/include
|
||||
DEFINES := -DMAC_OSX
|
||||
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
LDFLAGS += -Wl,-dead_strip
|
||||
LDFLAGS += -Wl,-dead_strip_dylibs
|
||||
@@ -15,7 +14,7 @@ endif
|
||||
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDFLAGS += -ldl
|
||||
DEFINES += -DUSE_UPNP
|
||||
CXXFLAGS += -DUSE_UPNP
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS += /usr/local/lib/libminiupnpc.a
|
||||
else
|
||||
@@ -23,12 +22,8 @@ ifeq ($(USE_UPNP),yes)
|
||||
endif
|
||||
endif
|
||||
|
||||
OSARCH = $(shell uname -p)
|
||||
|
||||
ifneq ($(OSARCH),powerpc)
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
CXXFLAGS += -D__AES__ -maes
|
||||
else
|
||||
CXXFLAGS += -msse
|
||||
endif
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
CXXFLAGS += -D__AES__ -maes
|
||||
else
|
||||
CXXFLAGS += -msse
|
||||
endif
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace util
|
||||
I2PService service((PSTR)SERVICE_NAME);
|
||||
if (!I2PService::Run(service))
|
||||
{
|
||||
LogPrint(eLogCritical, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
|
||||
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
@@ -64,7 +64,7 @@ namespace util
|
||||
//setlocale(LC_ALL, "Russian");
|
||||
setlocale(LC_TIME, "C");
|
||||
#ifdef WIN32_APP
|
||||
if (!i2p::win32::StartWin32App (isDaemon)) return false;
|
||||
if (!i2p::win32::StartWin32App ()) return false;
|
||||
#endif
|
||||
bool ret = Daemon_Singleton::start();
|
||||
if (ret && i2p::log::Logger().GetLogType() == eLogFile)
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
MAINICON ICON "mask.ico"
|
||||
#endif // English (United States) resources
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
#include "Resource.rc2"
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
MAINICON ICON "mask.ico"
|
||||
#endif // English (United States) resources
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
#include "Resource.rc2"
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#error this file is not editable by Microsoft Visual C++
|
||||
#endif //APSTUDIO_INVOKED
|
||||
|
||||
#include "version.h"
|
||||
#include "../libi2pd/version.h"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH
|
||||
@@ -25,7 +25,7 @@ BEGIN
|
||||
VALUE "FileDescription", "C++ I2P daemon"
|
||||
VALUE "FileVersion", I2PD_VERSION
|
||||
VALUE "InternalName", CODENAME
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013-2023, The PurpleI2P Project"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013-2022, The PurpleI2P Project"
|
||||
VALUE "OriginalFilename", "i2pd"
|
||||
VALUE "ProductName", "Purple I2P"
|
||||
VALUE "ProductVersion", I2P_VERSION
|
||||
|
||||
@@ -45,7 +45,6 @@ namespace i2p
|
||||
namespace win32
|
||||
{
|
||||
DWORD g_GracefulShutdownEndtime = 0;
|
||||
bool g_isWinService;
|
||||
|
||||
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
||||
{
|
||||
@@ -348,9 +347,6 @@ namespace win32
|
||||
}
|
||||
}
|
||||
}
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
}
|
||||
case WM_TRAYICON:
|
||||
{
|
||||
@@ -420,9 +416,8 @@ namespace win32
|
||||
return DefWindowProc( hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
bool StartWin32App (bool isWinService)
|
||||
bool StartWin32App ()
|
||||
{
|
||||
g_isWinService = isWinService;
|
||||
if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")))
|
||||
{
|
||||
MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK);
|
||||
@@ -451,9 +446,7 @@ namespace win32
|
||||
MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
|
||||
return false;
|
||||
}
|
||||
// COM requires message loop to work, which is not implemented in service mode
|
||||
if (!g_isWinService)
|
||||
SubscribeToEvents();
|
||||
SubscribeToEvents();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -473,8 +466,7 @@ namespace win32
|
||||
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
|
||||
if (hWnd)
|
||||
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0);
|
||||
else if(!g_isWinService)
|
||||
UnSubscribeFromEvents();
|
||||
// UnSubscribeFromEvents(); // TODO: understand why unsubscribing crashes app
|
||||
UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace win32
|
||||
{
|
||||
extern DWORD g_GracefulShutdownEndtime;
|
||||
|
||||
bool StartWin32App (bool isWinService);
|
||||
bool StartWin32App ();
|
||||
void StopWin32App ();
|
||||
int RunWin32App ();
|
||||
bool GracefulShutdown ();
|
||||
|
||||
@@ -15,7 +15,6 @@ IUnknown *pUnknown = nullptr;
|
||||
INetworkListManager *pNetworkListManager = nullptr;
|
||||
IConnectionPointContainer *pCPContainer = nullptr;
|
||||
IConnectionPoint *pConnectPoint = nullptr;
|
||||
CNetworkListManagerEvent *pNetEvent = nullptr;
|
||||
DWORD Cookie = 0;
|
||||
|
||||
void SubscribeToEvents()
|
||||
@@ -30,11 +29,7 @@ void SubscribeToEvents()
|
||||
if (SUCCEEDED(Result))
|
||||
{
|
||||
VARIANT_BOOL IsConnect = VARIANT_FALSE;
|
||||
#if defined(_MSC_VER)
|
||||
Result = pNetworkListManager->get_IsConnectedToInternet(&IsConnect);
|
||||
#else
|
||||
Result = pNetworkListManager->IsConnectedToInternet(&IsConnect);
|
||||
#endif
|
||||
if (SUCCEEDED(Result)) {
|
||||
i2p::transport::transports.SetOnline (true);
|
||||
LogPrint(eLogInfo, "NetState: Current state: ", IsConnect == VARIANT_TRUE ? "connected" : "disconnected");
|
||||
@@ -46,8 +41,8 @@ void SubscribeToEvents()
|
||||
Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint);
|
||||
if(SUCCEEDED(Result))
|
||||
{
|
||||
pNetEvent = new CNetworkListManagerEvent;
|
||||
Result = pConnectPoint->Advise((IUnknown *)pNetEvent, &Cookie);
|
||||
CNetworkListManagerEvent *NetEvent = new CNetworkListManagerEvent;
|
||||
Result = pConnectPoint->Advise((IUnknown *)NetEvent, &Cookie);
|
||||
if (SUCCEEDED(Result))
|
||||
LogPrint(eLogInfo, "NetState: Successfully subscribed to NetworkListManagerEvent messages");
|
||||
else
|
||||
@@ -64,7 +59,6 @@ void SubscribeToEvents()
|
||||
|
||||
void UnSubscribeFromEvents()
|
||||
{
|
||||
LogPrint(eLogInfo, "NetState: Unsubscribing from NetworkListManagerEvents");
|
||||
try
|
||||
{
|
||||
if (pConnectPoint) {
|
||||
@@ -72,9 +66,6 @@ void UnSubscribeFromEvents()
|
||||
pConnectPoint->Release();
|
||||
}
|
||||
|
||||
if (pNetEvent)
|
||||
pNetEvent->Release();
|
||||
|
||||
if (pCPContainer)
|
||||
pCPContainer->Release();
|
||||
|
||||
|
||||
@@ -19,18 +19,21 @@ class CNetworkListManagerEvent : public INetworkListManagerEvents
|
||||
{
|
||||
public:
|
||||
CNetworkListManagerEvent() : m_ref(1) { }
|
||||
~CNetworkListManagerEvent() { }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
||||
{
|
||||
HRESULT Result = S_OK;
|
||||
if (IsEqualIID(riid, IID_IUnknown)) {
|
||||
*ppvObject = (IUnknown *)this;
|
||||
} else if (IsEqualIID(riid ,IID_INetworkListManagerEvents)) {
|
||||
*ppvObject = (INetworkListManagerEvents *)this;
|
||||
} else {
|
||||
return E_NOINTERFACE;
|
||||
Result = E_NOINTERFACE;
|
||||
}
|
||||
AddRef();
|
||||
return S_OK;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef()
|
||||
|
||||
@@ -21,7 +21,7 @@ BOOL I2PService::isService()
|
||||
HWINSTA hWinStation = GetProcessWindowStation();
|
||||
if (hWinStation != NULL)
|
||||
{
|
||||
USEROBJECTFLAGS uof = { FALSE, FALSE, 0 };
|
||||
USEROBJECTFLAGS uof = { 0 };
|
||||
if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0))
|
||||
{
|
||||
bIsService = TRUE;
|
||||
@@ -119,12 +119,12 @@ void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogCritical, "Win32Service: Start error: ", dwError);
|
||||
LogPrint(eLogError, "Win32Service: Start error: ", dwError);
|
||||
SetServiceStatus(SERVICE_STOPPED, dwError);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogCritical, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE);
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ void I2PService::Stop()
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogCritical, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE);
|
||||
SetServiceStatus(dwOriginalState);
|
||||
}
|
||||
}
|
||||
@@ -191,12 +191,12 @@ void I2PService::Pause()
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogCritical, "Win32Service: Pause error: ", dwError);
|
||||
LogPrint(eLogError, "Win32Service: Pause error: ", dwError);
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogCritical, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE);
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
}
|
||||
@@ -215,12 +215,12 @@ void I2PService::Continue()
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogCritical, "Win32Service: Continue error: ", dwError);
|
||||
LogPrint(eLogError, "Win32Service: Continue error: ", dwError);
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogCritical, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE);
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
}
|
||||
@@ -238,11 +238,11 @@ void I2PService::Shutdown()
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogCritical, "Win32Service: Shutdown error: ", dwError);
|
||||
LogPrint(eLogError, "Win32Service: Shutdown error: ", dwError);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogCritical, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
14
build/.gitignore
vendored
14
build/.gitignore
vendored
@@ -1,13 +1,6 @@
|
||||
# Various generated files
|
||||
/CMakeFiles/
|
||||
/Testing/
|
||||
/tests/
|
||||
/.ninja_*
|
||||
/arch.c
|
||||
/build.ninja
|
||||
/i2pd
|
||||
/i2pd.exe
|
||||
/i2pd.exe.debug
|
||||
/libi2pd.a
|
||||
/libi2pdclient.a
|
||||
/libi2pdlang.a
|
||||
@@ -15,13 +8,8 @@
|
||||
/CMakeCache.txt
|
||||
/CPackConfig.cmake
|
||||
/CPackSourceConfig.cmake
|
||||
/CTestTestfile.cmake
|
||||
/install_manifest.txt
|
||||
/Makefile
|
||||
/arch.c
|
||||
# windows build script
|
||||
i2pd*.zip
|
||||
build*.log
|
||||
# MVS project files
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
*.sln
|
||||
|
||||
@@ -1,32 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.22)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.22)
|
||||
endif()
|
||||
cmake_policy(VERSION 3.7)
|
||||
project("i2pd")
|
||||
|
||||
# for debugging
|
||||
#set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
# paths
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
|
||||
set(CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||
|
||||
set(LIBI2PD_SRC_DIR ${CMAKE_SOURCE_DIR}/libi2pd)
|
||||
set(LIBI2PD_CLIENT_SRC_DIR ${CMAKE_SOURCE_DIR}/libi2pd_client)
|
||||
set(LANG_SRC_DIR ${CMAKE_SOURCE_DIR}/i18n)
|
||||
set(DAEMON_SRC_DIR ${CMAKE_SOURCE_DIR}/daemon)
|
||||
|
||||
include(Version)
|
||||
set_version("${LIBI2PD_SRC_DIR}/version.h" PROJECT_VERSION)
|
||||
|
||||
project(
|
||||
i2pd
|
||||
VERSION ${PROJECT_VERSION}
|
||||
HOMEPAGE_URL "https://i2pd.website/"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
# Win32 build with cmake is not supported
|
||||
if(WIN32 OR MSVC OR MSYS OR MINGW)
|
||||
message(SEND_ERROR "cmake build for windows is not supported. Please use MSYS2 with makefiles in project root.")
|
||||
endif()
|
||||
|
||||
# configurable options
|
||||
option(WITH_AESNI "Use AES-NI instructions set" ON)
|
||||
@@ -44,22 +26,27 @@ IF(BUILD_TESTING)
|
||||
enable_testing()
|
||||
ENDIF()
|
||||
|
||||
# paths
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
|
||||
set(CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||
|
||||
# Handle paths nicely
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Architecture
|
||||
# architecture
|
||||
include(TargetArch)
|
||||
target_architecture(ARCHITECTURE)
|
||||
|
||||
include(CheckAtomic)
|
||||
|
||||
if(WITH_STATIC)
|
||||
if(MSVC)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
endif()
|
||||
endif()
|
||||
set(LIBI2PD_SRC_DIR ../libi2pd)
|
||||
set(LIBI2PD_CLIENT_SRC_DIR ../libi2pd_client)
|
||||
set(LANG_SRC_DIR ../i18n)
|
||||
set(DAEMON_SRC_DIR ../daemon)
|
||||
|
||||
include_directories(${LIBI2PD_SRC_DIR})
|
||||
include_directories(${LIBI2PD_CLIENT_SRC_DIR})
|
||||
include_directories(${LANG_SRC_DIR})
|
||||
include_directories(${DAEMON_SRC_DIR})
|
||||
|
||||
FILE(GLOB LIBI2PD_SRC ${LIBI2PD_SRC_DIR}/*.cpp)
|
||||
add_library(libi2pd ${LIBI2PD_SRC})
|
||||
set_target_properties(libi2pd PROPERTIES PREFIX "")
|
||||
@@ -70,9 +57,11 @@ if(WITH_LIBRARY)
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
COMPONENT Libraries)
|
||||
# TODO Make libi2pd available to 3rd party projects via CMake as imported target
|
||||
# FIXME This pulls stdafx
|
||||
# install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
|
||||
include_directories(${LIBI2PD_CLIENT_SRC_DIR})
|
||||
FILE(GLOB CLIENT_SRC ${LIBI2PD_CLIENT_SRC_DIR}/*.cpp)
|
||||
add_library(libi2pdclient ${CLIENT_SRC})
|
||||
set_target_properties(libi2pdclient PROPERTIES PREFIX "")
|
||||
@@ -85,7 +74,6 @@ if(WITH_LIBRARY)
|
||||
COMPONENT Libraries)
|
||||
endif()
|
||||
|
||||
include_directories(${LANG_SRC_DIR})
|
||||
FILE(GLOB LANG_SRC ${LANG_SRC_DIR}/*.cpp)
|
||||
add_library(libi2pdlang ${LANG_SRC})
|
||||
set_target_properties(libi2pdlang PROPERTIES PREFIX "")
|
||||
@@ -98,8 +86,6 @@ if(WITH_LIBRARY)
|
||||
COMPONENT Libraries)
|
||||
endif()
|
||||
|
||||
include_directories(${DAEMON_SRC_DIR})
|
||||
|
||||
set(DAEMON_SRC
|
||||
"${DAEMON_SRC_DIR}/Daemon.cpp"
|
||||
"${DAEMON_SRC_DIR}/HTTPServer.cpp"
|
||||
@@ -109,22 +95,6 @@ set(DAEMON_SRC
|
||||
"${DAEMON_SRC_DIR}/UPnP.cpp"
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(WIN32_SRC_DIR ${CMAKE_SOURCE_DIR}/Win32)
|
||||
include_directories(${WIN32_SRC_DIR})
|
||||
|
||||
list(APPEND DAEMON_SRC
|
||||
"${WIN32_SRC_DIR}/DaemonWin32.cpp"
|
||||
"${WIN32_SRC_DIR}/Win32App.cpp"
|
||||
"${WIN32_SRC_DIR}/Win32Service.cpp"
|
||||
"${WIN32_SRC_DIR}/Win32NetState.cpp"
|
||||
)
|
||||
|
||||
file(GLOB WIN32_RC ${WIN32_SRC_DIR}/*.rc)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWIN32_APP -DWIN32_LEAN_AND_MEAN")
|
||||
|
||||
endif()
|
||||
|
||||
if(WITH_UPNP)
|
||||
add_definitions(-DUSE_UPNP)
|
||||
endif()
|
||||
@@ -132,40 +102,30 @@ endif()
|
||||
if(WITH_GIT_VERSION)
|
||||
include(GetGitRevisionDescription)
|
||||
git_describe(GIT_VERSION)
|
||||
add_definitions(-DGITVER=${GIT_VERSION})
|
||||
add_definitions(-DGITVER="${GIT_VERSION}")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
add_definitions(-DMAC_OSX)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-DWINVER=0x0600)
|
||||
add_definitions(-D_WIN32_WINNT=0x0600)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic")
|
||||
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
|
||||
# Multiple definitions of __stack_chk_fail(libssp & libc)
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above
|
||||
|
||||
# check for c++17 & c++11 support
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
|
||||
if(CXX17_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
elseif(CXX11_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter -Wno-uninitialized")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic")
|
||||
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
|
||||
# Multiple definitions of __stack_chk_fail(libssp & libc)
|
||||
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above
|
||||
|
||||
# check for c++17 & c++11 support
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
|
||||
|
||||
if(CXX17_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
elseif(CXX11_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?")
|
||||
endif()
|
||||
message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
@@ -197,12 +157,6 @@ endif()
|
||||
|
||||
# Note: AES-NI and AVX is available on x86-based CPU's.
|
||||
# Here also ARM64 implementation, but currently we don't support it.
|
||||
# MSVC is not supported.
|
||||
if(MSVC)
|
||||
message(STATUS "AES-NI is not supported on MSVC, option was disabled")
|
||||
set(WITH_AESNI OFF)
|
||||
endif()
|
||||
|
||||
if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386"))
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||
add_definitions(-D__AES__)
|
||||
@@ -224,7 +178,6 @@ endif()
|
||||
|
||||
# Use std::atomic instead of GCC builtins on macOS PowerPC:
|
||||
# For more information refer to: https://github.com/PurpleI2P/i2pd/issues/1726#issuecomment-1306335111
|
||||
# This has been fixed in Boost 1.81, nevertheless we retain the setting for the sake of compatibility.
|
||||
if(APPLE AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc")
|
||||
add_definitions(-DBOOST_SP_USE_STD_ATOMIC)
|
||||
endif()
|
||||
@@ -234,36 +187,10 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(WITH_STATIC)
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif()
|
||||
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
if(MSVC)
|
||||
set(Boost_USE_STATIC_RUNTIME ON)
|
||||
else()
|
||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set(OPENSSL_MSVC_STATIC_RT ON)
|
||||
endif()
|
||||
set(Boost_USE_STATIC_RUNTIME ON)
|
||||
set(OPENSSL_USE_STATIC_LIBS ON)
|
||||
|
||||
set(ZLIB_USE_STATIC_LIBS ON)
|
||||
if(MSVC)
|
||||
set(ZLIB_NAMES zlibstatic zlibstat)
|
||||
else()
|
||||
set(ZLIB_NAMES libz zlibstatic zlibstat zlib z)
|
||||
endif()
|
||||
|
||||
if(WITH_UPNP)
|
||||
set(MINIUPNPC_USE_STATIC_LIBS ON)
|
||||
add_definitions(-DMINIUPNP_STATICLIB)
|
||||
endif()
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
if(${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
# set(CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,--whole-archive -lpthread -Wl,--no-whole-archive")
|
||||
@@ -273,23 +200,17 @@ else()
|
||||
# TODO: Consider separate compilation for LIBI2PD_SRC for library.
|
||||
# No need in -fPIC overhead for binary if not interested in library
|
||||
# HINT: revert c266cff CMakeLists.txt: compilation speed up
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
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)
|
||||
if(WIN32)
|
||||
set(Boost_USE_STATIC_LIBS OFF)
|
||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
|
||||
endif()
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS system filesystem program_options date_time OPTIONAL_COMPONENTS atomic)
|
||||
if(NOT DEFINED Boost_FOUND)
|
||||
find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED)
|
||||
if(NOT DEFINED Boost_INCLUDE_DIRS)
|
||||
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
|
||||
endif()
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if(NOT DEFINED OPENSSL_FOUND)
|
||||
if(NOT DEFINED OPENSSL_INCLUDE_DIR)
|
||||
message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!")
|
||||
endif()
|
||||
|
||||
@@ -314,6 +235,8 @@ endif()
|
||||
# load includes
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
|
||||
|
||||
include(CheckAtomic)
|
||||
|
||||
# show summary
|
||||
message(STATUS "---------------------------------------")
|
||||
message(STATUS "Build type : ${CMAKE_BUILD_TYPE}")
|
||||
@@ -329,34 +252,16 @@ message(STATUS " LIBRARY : ${WITH_LIBRARY}")
|
||||
message(STATUS " BINARY : ${WITH_BINARY}")
|
||||
message(STATUS " STATIC BUILD : ${WITH_STATIC}")
|
||||
message(STATUS " UPnP : ${WITH_UPNP}")
|
||||
if(WITH_GIT_VERSION)
|
||||
message(STATUS " GIT VERSION : ${WITH_GIT_VERSION} (${GIT_VERSION})")
|
||||
else()
|
||||
message(STATUS " GIT VERSION : ${WITH_GIT_VERSION}")
|
||||
endif()
|
||||
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
|
||||
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
|
||||
message(STATUS "---------------------------------------")
|
||||
|
||||
if(WITH_BINARY)
|
||||
if(WIN32)
|
||||
add_executable("${PROJECT_NAME}" WIN32 ${DAEMON_SRC} ${WIN32_RC})
|
||||
else()
|
||||
add_executable("${PROJECT_NAME}" ${DAEMON_SRC})
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND MINGW_EXTRA "wsock32" "ws2_32" "iphlpapi")
|
||||
# OpenSSL may require Crypt32 library on MSVC build, which is not added by CMake lesser than 3.21
|
||||
if(MSVC AND ${CMAKE_VERSION} VERSION_LESS 3.21)
|
||||
list(APPEND MINGW_EXTRA "crypt32")
|
||||
endif()
|
||||
endif()
|
||||
add_executable("${PROJECT_NAME}" ${DAEMON_SRC})
|
||||
|
||||
if(WITH_STATIC)
|
||||
if(NOT MSVC)
|
||||
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static")
|
||||
endif()
|
||||
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static")
|
||||
endif()
|
||||
|
||||
if(WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
@@ -369,18 +274,11 @@ if(WITH_BINARY)
|
||||
list(REMOVE_AT Boost_LIBRARIES -1)
|
||||
endif()
|
||||
|
||||
# synchronization library is incompatible with Windows 7
|
||||
if(WIN32)
|
||||
get_target_property(BOOSTFSLIBS Boost::filesystem INTERFACE_LINK_LIBRARIES)
|
||||
list(REMOVE_ITEM BOOSTFSLIBS synchronization)
|
||||
set_target_properties(Boost::filesystem PROPERTIES INTERFACE_LINK_LIBRARIES "${BOOSTFSLIBS}")
|
||||
endif()
|
||||
|
||||
if(WITH_STATIC)
|
||||
set(DL_LIB ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto ${MINIUPNPC_LIBRARY} ZLIB::ZLIB Threads::Threads ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
|
||||
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto ${MINIUPNPC_LIBRARY} ZLIB::ZLIB Threads::Threads ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
|
||||
|
||||
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
|
||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2023, The PurpleI2P Project
|
||||
# Copyright (c) 2017-2022, 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
|
||||
|
||||
@@ -18,7 +18,7 @@ set(archdetect_c_code "
|
||||
|| defined(_M_ARM64) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 8)
|
||||
#error cmake_ARCH arm64
|
||||
#elif defined(__ARM_ARCH_7__) \\
|
||||
#if defined(__ARM_ARCH_7__) \\
|
||||
|| defined(__ARM_ARCH_7A__) \\
|
||||
|| defined(__ARM_ARCH_7R__) \\
|
||||
|| defined(__ARM_ARCH_7M__) \\
|
||||
@@ -83,13 +83,13 @@ function(target_architecture output_var)
|
||||
# First let's normalize the order of the values
|
||||
|
||||
# Note that it's not possible to compile PowerPC applications if you are using
|
||||
# the OS X SDK version 10.7 or later - you'll need 10.4/10.5/10.6 for that, so we
|
||||
# disable it by default. Also, ppc64 is not supported in 10.6.
|
||||
# the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
|
||||
# disable it by default
|
||||
# See this page for more information:
|
||||
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
|
||||
|
||||
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
|
||||
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise; 10.6 also supports ppc.
|
||||
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
|
||||
|
||||
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
|
||||
@@ -133,11 +133,11 @@ function(target_architecture output_var)
|
||||
enable_language(C)
|
||||
|
||||
# Detect the architecture in a rather creative way...
|
||||
# This compiles a small C program which is a series of ifdefs that selects
|
||||
# a particular #error preprocessor directive whose message string contains
|
||||
# the target architecture. The program will always fail to compile (both because
|
||||
# file is not a valid C program, and obviously because of the presence of
|
||||
# the #error preprocessor directives... but by exploiting the preprocessor in this
|
||||
# This compiles a small C program which is a series of ifdefs that selects a
|
||||
# particular #error preprocessor directive whose message string contains the
|
||||
# target architecture. The program will always fail to compile (both because
|
||||
# file is not a valid C program, and obviously because of the presence of the
|
||||
# #error preprocessor directives... but by exploiting the preprocessor in this
|
||||
# way, we can detect the correct target architecture even when cross-compiling,
|
||||
# since the program itself never needs to be run (only the compiler/preprocessor)
|
||||
try_run(
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# read version
|
||||
|
||||
function(set_version version_file output_var)
|
||||
file(READ "${version_file}" version_data)
|
||||
|
||||
string(REGEX MATCH "I2PD_VERSION_MAJOR ([0-9]*)" _ ${version_data})
|
||||
set(version_major ${CMAKE_MATCH_1})
|
||||
|
||||
string(REGEX MATCH "I2PD_VERSION_MINOR ([0-9]*)" _ ${version_data})
|
||||
set(version_minor ${CMAKE_MATCH_1})
|
||||
|
||||
string(REGEX MATCH "I2PD_VERSION_MICRO ([0-9]*)" _ ${version_data})
|
||||
set(version_micro ${CMAKE_MATCH_1})
|
||||
|
||||
set(${output_var} "${version_major}.${version_minor}.${version_micro}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -1,34 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF2TCCA8GgAwIBAgIQIHQPtSoFU+cUpYD8PZaWZjANBgkqhkiG9w0BAQsFADB2
|
||||
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
|
||||
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEfMB0GA1UEAwwW
|
||||
YXJuYXZiaGF0dDI4OEBtYWlsLmkycDAeFw0yMzAxMjUxODUzNDFaFw0zMzAxMjUx
|
||||
ODUzNDFaMHYxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgx
|
||||
HjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMR8w
|
||||
HQYDVQQDDBZhcm5hdmJoYXR0Mjg4QG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAg8AMIICCgKCAgEAtwG73sC0jYd3fgEzZh0SveAdUd5yD35nINJRrdPSrSwY
|
||||
n3i1qGe3fNLj877PvUDU+qiHH0fFZfyFkXTaq3TUp1u4YkmvaoPHy6FZlojB08lK
|
||||
FBm+iJ1hifQ7MFmvIKUGv+cjlN6xSoQ0U6B2QOy6iZnBgFZ/7jbRY4iZOIj7VJtY
|
||||
aodeHfy0bWe447VJovbkUi7NJPFZQS65LMcAIWcWTxrC0Gj8SmdxL3a5+hxpmmg0
|
||||
+KCQvWQDdxAQjsc16sgUCdUc6cWYO4yw9H6fgdq9GJX+LnXR9OB58GsAjjlLlFoI
|
||||
CZxdARDpoqcIj6AoKIanALf8yfbIyrqqJE47cuaqV9bht5MWKnXbwHplEkT4ZNkh
|
||||
PnRDia7B5HY3uwbt39CBm264PEWXvWG2sozTWKQqBjmMN2cj/NFDUEqKv6BggMY1
|
||||
HcqxWFKRcgKCtRvrmTmfp5l0/ou+OtUaFUg0a6Qhtb93Hj10vK6wZzidBqj0ggzB
|
||||
eJDI95b89u8JgzRoOBriuMKTc91WTkOvBLkB3dgUbUpx2p8KHjvf/pppBH9u0oxp
|
||||
qJFFK840DbnJydEvjKezeVe5Ax6YRSRxyEdKzRoWdvKVxb3qBBKMdCKTYEPxHPBu
|
||||
JMEQVUCXJMti++1KEiQGhcfWvLyT7OewbcIZNk9XWNrxlKcGrTp9AOwaaNC5m1kC
|
||||
AwEAAaNjMGEwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
|
||||
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB8GA1UdDgQYBBZhcm5hdmJoYXR0Mjg4
|
||||
QG1haWwuaTJwMA0GCSqGSIb3DQEBCwUAA4ICAQAHiK0ld/1PF9DIhutD660/bzBg
|
||||
mF2Z76hcBqDZ8tnQai/u/RXYrH9wso9BYyrVsvk3fr6tpGT49Ian0MVpPOxMoTU2
|
||||
oBEmQlYrfclQLFsOLmA0y2r1ggXzIrt69jB710Vhwdnz09oOE8rS4E2T5oDD8Wvy
|
||||
Kony+AarRceqtkOlzyquc42KjzdrbHsosF7G2iGhNI6t+T3BfWJ+Q+d5sj3OIh6e
|
||||
gSfvHL44E4vZt6dtofRN3MAZ60kNLF5YWyaUo3Snv9Lso1IwIz3AVr5ehv+8sFL/
|
||||
KxaXdkZ5Yn2YUX7p1t4VQd+eXVPYjf1befg4PvrwSkylu3Jpee3fllZSKXeSVx9x
|
||||
jpJiq5vIakqk22pnWb1Vn7xzSW1vtEG7QLjobOr1WrcGiwdv+HKiWcXJXDzKoWXs
|
||||
h3VEfr51Kap8cIJv+D6lJIG9IcIhiQ6CXWBmtjWJvbdVwFBy1/3Fhaou9liHi+gK
|
||||
4Yh5a5OGCzc7xjtpGaTmoLEz7NzDNOdd/r840qRDOh70izzmFZd5Gwq4hoVcPJcS
|
||||
EAySwtgqK0/4d0zDd2Wg9ASJV9DnDf8QuSmHZgZ9Efs47XcWz9TvkWUS1E66AJsN
|
||||
mmI1NDQ3mv3dv5+WPq+dqqYFsnx3xWL1g5Z3buk0opeuXMzoHwM7UfN8h7Q1M5+t
|
||||
+XBgkaYA4iEwYKqlCQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,33 +1,33 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFvjCCA6agAwIBAgIQBnsUOmOu2oZZIwHBmQc1BDANBgkqhkiG9w0BAQsFADBt
|
||||
MIIFvjCCA6agAwIBAgIQIDtv8tGMh0FyB2w5XjfZxTANBgkqhkiG9w0BAQsFADBt
|
||||
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
|
||||
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwN
|
||||
aWdvckBub3ZnLm5ldDAeFw0yMzAxMjgxNDM4MzFaFw0zMzAxMjgxNDM4MzFaMG0x
|
||||
aWdvckBub3ZnLm5ldDAeFw0xNzA3MjQxODI4NThaFw0yNzA3MjQxODI4NThaMG0x
|
||||
CzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHjAcBgNVBAoT
|
||||
FUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1p
|
||||
Z29yQG5vdmcubmV0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvLkf
|
||||
bM3uiYfp9m0vgdoftyXtk2/9bHf3u5iaM0WfoJIsw1iizo/mxJl+Iy7SxLC16nV0
|
||||
v5FpncVv+Z8x9dgoAYVuLq9zKfsAbpj6kuxAqw6vJMlD1TiIL3nSODV9BJLk47X5
|
||||
tmvoOSj9BgvemYThTE3nj+DbuJRW5q90KyBV/LdLrQJX3k5R3FFL5tTad2LKFNZ4
|
||||
vEOcYwwx6mvrkJ2lly6bAQUCtfc648Jyq+NO3Rba1fmn7gcP9zXXc5KYsj/ovyY2
|
||||
OaocSF5wMhzBuPxO+M2HqbYLMAkc6/GesGds8Rm8wofuhJoI5YtqJuLKZm6nQXSc
|
||||
fx6PKgbKcTIUWNFMsxyfghz9hpbg0rkvC7PtfAjtV0yaDtUum1eZeNEx1HbRWN2n
|
||||
TQNCVuv0yaKC41qxqzhEybkdjL9JlgUh7VuskaCelB0lz+kgYjGu8ezOa0ua2iKq
|
||||
4FC/1MbPulxN8NOt4pmbGqqoxmCdShp38wdnOBM3DsAS9f0JaQZd4CDyY4DCSfVn
|
||||
xPdWk31+VXVt3Ixh1EUqZWYTRSsZApkCyYzkiZ/qPGG6FR9Hq2SuhC5o4P44k7eo
|
||||
6wwBWD8a5RjsZhvr05E5yBrKXh/PjLwmtG73QC+ouR54/5xtedvdTwNS94FnNctX
|
||||
FT6QGZnRwCkhPaRe1oQMzP+88pGoCfO33GBAuwUCAwEAAaNaMFgwDgYDVR0PAQH/
|
||||
Z29yQG5vdmcubmV0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxst4
|
||||
cam3YibBtQHGPCPX13uRQti56U3XZytSZntaKrUFmJxjt41Q/mOy3KYo+lBvhfDF
|
||||
x3tWKjgP9LJOJ28zvddFhZVNxqZRjcnAoPuSOVCw88g01D9OAasKF11hCfdxZP6h
|
||||
vGm8WCnjD8KPcYFxJC4HJUiFeProAwuTzEAESTRk4CAQe3Ie91JspuqoLUc5Qxlm
|
||||
w5QpjnjfZY4kaVHmZDKGIZDgNIt5v85bu4pWwZ6O+o90xQqjxvjyz/xccIec3sHw
|
||||
MHJ8h8ZKMokCKEJTaRWBvdeNXki7nf3gUy/3GjYQlzo0Nxk/Hw4svPcA+eL0AYiy
|
||||
Jn83bIB5VToW2zYUdV4u3qHeAhEg8Y7HI0kKcSUGm9AQXzbzP8YCHxi0sbb0GAJy
|
||||
f1Xf3XzoPfT64giD8ReUHhwKpyMB6uvG/NfWSZAzeAO/NT7DAwXpKIVQdkVdqy8b
|
||||
mvHvjf9/kWKOirA2Nygf3r79Vbg2mqbYC/b63XI9hheU689+O7qyhTEhNz+11X0d
|
||||
Zax7UPrLrwOeB9TNfEnztsmrHNdv2n+KcOO2o11Wvz2nHP9g+dgwoZSD1ZEpFzWP
|
||||
0sD5knKLwAL/64qLlAQ1feqW7hMr80IADcKjLSODkIDIIGm0ksXqEzTjz1JzbRDq
|
||||
jUjq7EAlkw3G69rv1gHxIntllJRQidAqecyWHOMCAwEAAaNaMFgwDgYDVR0PAQH/
|
||||
BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8E
|
||||
BTADAQH/MBYGA1UdDgQPBA1pZ29yQG5vdmcubmV0MA0GCSqGSIb3DQEBCwUAA4IC
|
||||
AQCteAb5/bqhHr/i5CJbDzlofprXFC826c19GxQ/9Hw0kA52l0J9Q8Vz8Vy7VQyP
|
||||
QNa8MCv6FeNy8a/wXp6cafyFsBtvehVQO8lFlpCgMEl2Bma43+GaCwkrM6bFNXeW
|
||||
iQ9h4e1KjsUZ8cQDNEcamiJ80+xbMhBrj5bAZwKmZs8MoGEMyXKEZmcmwA+/fy1c
|
||||
cx4izsOsmRXmEHXsvB9ydJHZZeKW8+r0DAtgPslwXuXHG6MuBQo7dKCqn+iMxHXV
|
||||
Jxriq3yvNffdGx4maSLJrjQ1ealt/UMzql7huVSItnVFWoYf7GAELXNJ/PmqVyaK
|
||||
q11LQ8W/Aud6s/bblaJrFJnK8PbPpaw4RvHoWVLYaZYmQnV2msWs5EuESBlEADbv
|
||||
UklQXLMc2f9HKWPA5678nvYPrmu8IL5pMkAxgGRqmd+7vCz4lU9M5z3HObU+WRBt
|
||||
qEMYyXywV8o3tbmnlDS5S5Xxf+tLZn1cxz3ZrmcHPHDbLBNdvszF3CTJH/R2sQvD
|
||||
bizvYJM+p5F+GWM5mt6w0HrOut5MRlpOws/NRrkbijuVA/A45nzTtKplIFYE3qe8
|
||||
q5SAbwYLc8cJcZCN3PxtWwbEv81V33abMt5QcjnWGLH5t2+1Z2KLCgKLSCQTxM8s
|
||||
zBPHtUe8qtSQaElnNLILYbtJ1w67dPnGYTphHihC+CXjBg==
|
||||
AQADyPaec28qc1HQtAV5dscJr47k92RTfvan+GEgIwyQDHZQm38eyTb05xipQCdk
|
||||
5ruUDFXLB5qXXFJKUbQM6IpaktmWDJqk4Zn+1nGbtFEbKgrF55pd63+NQer5QW9o
|
||||
3+dGj0eZJa3HX5EBkd2r7j2LFuB6uxv3r/xiTeHaaflCnsmyDLfb7axvYhyEzHQS
|
||||
AUi1bR+ln+dXewdtuojqc1+YmVGDgzWZK2T0oOz2E21CpZUDiP3wv9QfMaotLEal
|
||||
zECnbhS++q889inN3GB4kIoN6WpPpeYtTV+/r7FLv9+KUOV1s2z6mxIqC5wBFhZs
|
||||
0Sr1kVo8hB/EW/YYhDp99LoAOjIO6nn1h+qttfzBYr6C16j+8lGK2A12REJ4LiUQ
|
||||
cQI/0zTjt2C8Ns6ueNzMLQN1Mvmlg1Z8wIB7Az7jsIbY2zFJ0M5qR5VJveTj33K4
|
||||
4WSbC/zMWOBYHTVBvGmc6JGhu5ZUTZ+mWP7QfimGu+tdhvtrybFjE9ROIE/4yFr6
|
||||
GkxEyt0UY87TeKXJ/3KygvkMwdvqGWiZhItb807iy99+cySujtbGfF2ZXYGjBXVW
|
||||
dJOVRbyGQkHh6lrWHQM4ntBv4x+5QA+OAan5PBF3tcDx1vefPx+asYslbOXpzII5
|
||||
qhvoQxuRs6j5jsVFG6RdsKNeQAt87Mb2u2zK2ZakMdyD1w==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
type = bgprocess
|
||||
run-as = i2pd
|
||||
command = /usr/bin/i2pd --conf=/var/lib/i2pd/i2pd.conf --pidfile=/var/lib/i2pd/i2pd.pid --daemon --service
|
||||
smooth-recovery = true
|
||||
depends-on = ntpd
|
||||
# uncomment if you want to use i2pd with yggdrasil
|
||||
# depends-on = yggdrasil
|
||||
pid-file = /var/lib/i2pd/i2pd.pid
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: i2pd\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\n"
|
||||
"POT-Creation-Date: 2023-06-10 01:25\n"
|
||||
"POT-Creation-Date: 2023-01-19 04:18\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@@ -18,28 +18,28 @@ msgstr ""
|
||||
"X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n"
|
||||
"X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n"
|
||||
|
||||
#: daemon/HTTPServer.cpp:107
|
||||
#: daemon/HTTPServer.cpp:106
|
||||
#, c-format
|
||||
msgid "%d day"
|
||||
msgid_plural "%d days"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:111
|
||||
#: daemon/HTTPServer.cpp:110
|
||||
#, c-format
|
||||
msgid "%d hour"
|
||||
msgid_plural "%d hours"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:115
|
||||
#: daemon/HTTPServer.cpp:114
|
||||
#, c-format
|
||||
msgid "%d minute"
|
||||
msgid_plural "%d minutes"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:118
|
||||
#: daemon/HTTPServer.cpp:117
|
||||
#, c-format
|
||||
msgid "%d second"
|
||||
msgid_plural "%d seconds"
|
||||
@@ -47,578 +47,560 @@ msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#. tr: Kibibyte
|
||||
#: daemon/HTTPServer.cpp:126
|
||||
#: daemon/HTTPServer.cpp:125 daemon/HTTPServer.cpp:153
|
||||
#, c-format
|
||||
msgid "%.2f KiB"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Mebibyte
|
||||
#: daemon/HTTPServer.cpp:128
|
||||
#: daemon/HTTPServer.cpp:127
|
||||
#, c-format
|
||||
msgid "%.2f MiB"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Gibibyte
|
||||
#: daemon/HTTPServer.cpp:130
|
||||
#: daemon/HTTPServer.cpp:129
|
||||
#, c-format
|
||||
msgid "%.2f GiB"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:147
|
||||
#: daemon/HTTPServer.cpp:146
|
||||
msgid "building"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:148
|
||||
#: daemon/HTTPServer.cpp:147
|
||||
msgid "failed"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:149
|
||||
#: daemon/HTTPServer.cpp:148
|
||||
msgid "expiring"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:150
|
||||
#: daemon/HTTPServer.cpp:149
|
||||
msgid "established"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:151
|
||||
#: daemon/HTTPServer.cpp:150
|
||||
msgid "unknown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:153
|
||||
#: daemon/HTTPServer.cpp:152
|
||||
msgid "exploratory"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Webconsole page title
|
||||
#: daemon/HTTPServer.cpp:185
|
||||
#: daemon/HTTPServer.cpp:183
|
||||
msgid "Purple I2P Webconsole"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:190
|
||||
#: daemon/HTTPServer.cpp:188
|
||||
msgid "<b>i2pd</b> webconsole"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:193
|
||||
#: daemon/HTTPServer.cpp:191
|
||||
msgid "Main page"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:194 daemon/HTTPServer.cpp:742
|
||||
#: daemon/HTTPServer.cpp:192 daemon/HTTPServer.cpp:712
|
||||
msgid "Router commands"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:395
|
||||
#: daemon/HTTPServer.cpp:407
|
||||
#: daemon/HTTPServer.cpp:193 daemon/HTTPServer.cpp:387
|
||||
#: daemon/HTTPServer.cpp:399
|
||||
msgid "Local Destinations"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:365
|
||||
#: daemon/HTTPServer.cpp:454 daemon/HTTPServer.cpp:474
|
||||
#: daemon/HTTPServer.cpp:636 daemon/HTTPServer.cpp:682
|
||||
#: daemon/HTTPServer.cpp:686
|
||||
#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:357
|
||||
#: daemon/HTTPServer.cpp:443 daemon/HTTPServer.cpp:449
|
||||
#: daemon/HTTPServer.cpp:609 daemon/HTTPServer.cpp:652
|
||||
#: daemon/HTTPServer.cpp:656
|
||||
msgid "LeaseSets"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:692
|
||||
#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:662
|
||||
msgid "Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:372
|
||||
#: daemon/HTTPServer.cpp:813 daemon/HTTPServer.cpp:830
|
||||
#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:364
|
||||
#: daemon/HTTPServer.cpp:781 daemon/HTTPServer.cpp:797
|
||||
msgid "Transit Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:203 daemon/HTTPServer.cpp:898
|
||||
#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:855
|
||||
msgid "Transports"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:204
|
||||
#: daemon/HTTPServer.cpp:202
|
||||
msgid "I2P tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:206 daemon/HTTPServer.cpp:927
|
||||
#: daemon/HTTPServer.cpp:937
|
||||
#: daemon/HTTPServer.cpp:204 daemon/HTTPServer.cpp:884
|
||||
#: daemon/HTTPServer.cpp:894
|
||||
msgid "SAM sessions"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:222 daemon/HTTPServer.cpp:1329
|
||||
#: daemon/HTTPServer.cpp:1332 daemon/HTTPServer.cpp:1335
|
||||
#: daemon/HTTPServer.cpp:1362 daemon/HTTPServer.cpp:1365
|
||||
#: daemon/HTTPServer.cpp:1379 daemon/HTTPServer.cpp:1424
|
||||
#: daemon/HTTPServer.cpp:1427 daemon/HTTPServer.cpp:1430
|
||||
#: daemon/HTTPServer.cpp:220 daemon/HTTPServer.cpp:1278
|
||||
#: daemon/HTTPServer.cpp:1281 daemon/HTTPServer.cpp:1284
|
||||
#: daemon/HTTPServer.cpp:1298 daemon/HTTPServer.cpp:1343
|
||||
#: daemon/HTTPServer.cpp:1346 daemon/HTTPServer.cpp:1349
|
||||
msgid "ERROR"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:229
|
||||
#: daemon/HTTPServer.cpp:227
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:230
|
||||
#: daemon/HTTPServer.cpp:228
|
||||
msgid "Testing"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:231
|
||||
#: daemon/HTTPServer.cpp:229
|
||||
msgid "Firewalled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:235
|
||||
#: daemon/HTTPServer.cpp:336
|
||||
#: daemon/HTTPServer.cpp:230 daemon/HTTPServer.cpp:233
|
||||
#: daemon/HTTPServer.cpp:329
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:382
|
||||
#: daemon/HTTPServer.cpp:383 daemon/HTTPServer.cpp:1003
|
||||
#: daemon/HTTPServer.cpp:1011
|
||||
#: daemon/HTTPServer.cpp:231 daemon/HTTPServer.cpp:374
|
||||
#: daemon/HTTPServer.cpp:375 daemon/HTTPServer.cpp:952
|
||||
#: daemon/HTTPServer.cpp:961
|
||||
msgid "Proxy"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:234
|
||||
#: daemon/HTTPServer.cpp:232
|
||||
msgid "Mesh"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:242
|
||||
#: daemon/HTTPServer.cpp:240
|
||||
msgid "Clock skew"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:245
|
||||
#: daemon/HTTPServer.cpp:243
|
||||
msgid "Offline"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:248
|
||||
#: daemon/HTTPServer.cpp:246
|
||||
msgid "Symmetric NAT"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:251
|
||||
#: daemon/HTTPServer.cpp:249
|
||||
msgid "Full cone NAT"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:254
|
||||
#: daemon/HTTPServer.cpp:252
|
||||
msgid "No Descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:263
|
||||
#: daemon/HTTPServer.cpp:261
|
||||
msgid "Uptime"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:266
|
||||
#: daemon/HTTPServer.cpp:264
|
||||
msgid "Network status"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:271
|
||||
#: daemon/HTTPServer.cpp:269
|
||||
msgid "Network status v6"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:277 daemon/HTTPServer.cpp:284
|
||||
#: daemon/HTTPServer.cpp:275 daemon/HTTPServer.cpp:282
|
||||
msgid "Stopping in"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:291
|
||||
#: daemon/HTTPServer.cpp:289
|
||||
msgid "Family"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:292
|
||||
#: daemon/HTTPServer.cpp:290
|
||||
msgid "Tunnel creation success rate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:296
|
||||
msgid "Total tunnel creation success rate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:298
|
||||
#: daemon/HTTPServer.cpp:291
|
||||
msgid "Received"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Kibibyte/s
|
||||
#: daemon/HTTPServer.cpp:300 daemon/HTTPServer.cpp:303
|
||||
#: daemon/HTTPServer.cpp:306
|
||||
#: daemon/HTTPServer.cpp:293 daemon/HTTPServer.cpp:296
|
||||
#: daemon/HTTPServer.cpp:299
|
||||
#, c-format
|
||||
msgid "%.2f KiB/s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:301
|
||||
#: daemon/HTTPServer.cpp:294
|
||||
msgid "Sent"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:304
|
||||
#: daemon/HTTPServer.cpp:297
|
||||
msgid "Transit"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:307
|
||||
#: daemon/HTTPServer.cpp:300
|
||||
msgid "Data path"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:310
|
||||
#: daemon/HTTPServer.cpp:303
|
||||
msgid "Hidden content. Press on text to see."
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:314
|
||||
#: daemon/HTTPServer.cpp:307
|
||||
msgid "Router Ident"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:316
|
||||
#: daemon/HTTPServer.cpp:309
|
||||
msgid "Router Family"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:317
|
||||
#: daemon/HTTPServer.cpp:310
|
||||
msgid "Router Caps"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:318
|
||||
#: daemon/HTTPServer.cpp:311
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:319
|
||||
#: daemon/HTTPServer.cpp:312
|
||||
msgid "Our external address"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Shown when router doesn't publish itself and have "Firewalled" state
|
||||
#: daemon/HTTPServer.cpp:349
|
||||
#: daemon/HTTPServer.cpp:341
|
||||
msgid "supported"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:363
|
||||
#: daemon/HTTPServer.cpp:355
|
||||
msgid "Routers"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:364
|
||||
#: daemon/HTTPServer.cpp:356
|
||||
msgid "Floodfills"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:987
|
||||
#: daemon/HTTPServer.cpp:363 daemon/HTTPServer.cpp:938
|
||||
msgid "Client Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:381
|
||||
#: daemon/HTTPServer.cpp:373
|
||||
msgid "Services"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:382 daemon/HTTPServer.cpp:383
|
||||
#: daemon/HTTPServer.cpp:384 daemon/HTTPServer.cpp:385
|
||||
#: daemon/HTTPServer.cpp:386 daemon/HTTPServer.cpp:387
|
||||
#: daemon/HTTPServer.cpp:374 daemon/HTTPServer.cpp:375
|
||||
#: daemon/HTTPServer.cpp:376 daemon/HTTPServer.cpp:377
|
||||
#: daemon/HTTPServer.cpp:378 daemon/HTTPServer.cpp:379
|
||||
msgid "Enabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:382 daemon/HTTPServer.cpp:383
|
||||
#: daemon/HTTPServer.cpp:384 daemon/HTTPServer.cpp:385
|
||||
#: daemon/HTTPServer.cpp:386 daemon/HTTPServer.cpp:387
|
||||
#: daemon/HTTPServer.cpp:374 daemon/HTTPServer.cpp:375
|
||||
#: daemon/HTTPServer.cpp:376 daemon/HTTPServer.cpp:377
|
||||
#: daemon/HTTPServer.cpp:378 daemon/HTTPServer.cpp:379
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:434
|
||||
#: daemon/HTTPServer.cpp:422
|
||||
msgid "Encrypted B33 address"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:442
|
||||
#: daemon/HTTPServer.cpp:431
|
||||
msgid "Address registration line"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:447
|
||||
#: daemon/HTTPServer.cpp:436
|
||||
msgid "Domain"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:448
|
||||
#: daemon/HTTPServer.cpp:437
|
||||
msgid "Generate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:449
|
||||
#: daemon/HTTPServer.cpp:438
|
||||
msgid ""
|
||||
"<b>Note:</b> result string can be used only for registering 2LD domains "
|
||||
"(example.i2p). For registering subdomains please use i2pd-tools."
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:457
|
||||
#: daemon/HTTPServer.cpp:444
|
||||
msgid "Address"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:459
|
||||
#: daemon/HTTPServer.cpp:444
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:460
|
||||
#: daemon/HTTPServer.cpp:444
|
||||
msgid "EncType"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:467
|
||||
msgid "Expire LeaseSet"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:479 daemon/HTTPServer.cpp:697
|
||||
#: daemon/HTTPServer.cpp:454 daemon/HTTPServer.cpp:667
|
||||
msgid "Inbound tunnels"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Milliseconds
|
||||
#: daemon/HTTPServer.cpp:494 daemon/HTTPServer.cpp:514
|
||||
#: daemon/HTTPServer.cpp:711 daemon/HTTPServer.cpp:731
|
||||
#: daemon/HTTPServer.cpp:469 daemon/HTTPServer.cpp:489
|
||||
#: daemon/HTTPServer.cpp:681 daemon/HTTPServer.cpp:701
|
||||
#, c-format
|
||||
msgid "%dms"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:499 daemon/HTTPServer.cpp:716
|
||||
#: daemon/HTTPServer.cpp:474 daemon/HTTPServer.cpp:686
|
||||
msgid "Outbound tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:521
|
||||
#: daemon/HTTPServer.cpp:496
|
||||
msgid "Tags"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:522
|
||||
#: daemon/HTTPServer.cpp:497
|
||||
msgid "Incoming"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:529 daemon/HTTPServer.cpp:535
|
||||
#: daemon/HTTPServer.cpp:504 daemon/HTTPServer.cpp:510
|
||||
msgid "Outgoing"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:532 daemon/HTTPServer.cpp:551
|
||||
#: daemon/HTTPServer.cpp:507 daemon/HTTPServer.cpp:526
|
||||
msgid "Destination"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:532 daemon/HTTPServer.cpp:814
|
||||
#: daemon/HTTPServer.cpp:507
|
||||
msgid "Amount"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:540
|
||||
#: daemon/HTTPServer.cpp:515
|
||||
msgid "Incoming Tags"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:548 daemon/HTTPServer.cpp:554
|
||||
#: daemon/HTTPServer.cpp:523 daemon/HTTPServer.cpp:529
|
||||
msgid "Tags sessions"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:551
|
||||
#: daemon/HTTPServer.cpp:526
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:561 daemon/HTTPServer.cpp:621
|
||||
#: daemon/HTTPServer.cpp:536 daemon/HTTPServer.cpp:594
|
||||
msgid "Local Destination"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:572 daemon/HTTPServer.cpp:960
|
||||
#: daemon/HTTPServer.cpp:547 daemon/HTTPServer.cpp:917
|
||||
msgid "Streams"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:595
|
||||
#: daemon/HTTPServer.cpp:570
|
||||
msgid "Close stream"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:613 daemon/HTTPServer.cpp:1430
|
||||
msgid "Such destination is not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:626
|
||||
#: daemon/HTTPServer.cpp:599
|
||||
msgid "I2CP session not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:629
|
||||
#: daemon/HTTPServer.cpp:602
|
||||
msgid "I2CP is not enabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:658
|
||||
#: daemon/HTTPServer.cpp:628
|
||||
msgid "Invalid"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:661
|
||||
#: daemon/HTTPServer.cpp:631
|
||||
msgid "Store type"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:662
|
||||
#: daemon/HTTPServer.cpp:632
|
||||
msgid "Expires"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:667
|
||||
#: daemon/HTTPServer.cpp:637
|
||||
msgid "Non Expired Leases"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:670
|
||||
#: daemon/HTTPServer.cpp:640
|
||||
msgid "Gateway"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:671
|
||||
#: daemon/HTTPServer.cpp:641
|
||||
msgid "TunnelID"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:672
|
||||
#: daemon/HTTPServer.cpp:642
|
||||
msgid "EndDate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:682
|
||||
#: daemon/HTTPServer.cpp:652
|
||||
msgid "floodfill mode is disabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:693
|
||||
#: daemon/HTTPServer.cpp:663
|
||||
msgid "Queue size"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:743
|
||||
#: daemon/HTTPServer.cpp:713
|
||||
msgid "Run peer test"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:744
|
||||
#: daemon/HTTPServer.cpp:714
|
||||
msgid "Reload tunnels configuration"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:747
|
||||
#: daemon/HTTPServer.cpp:717
|
||||
msgid "Decline transit tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:749
|
||||
#: daemon/HTTPServer.cpp:719
|
||||
msgid "Accept transit tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:753 daemon/HTTPServer.cpp:758
|
||||
#: daemon/HTTPServer.cpp:723 daemon/HTTPServer.cpp:728
|
||||
msgid "Cancel graceful shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:755 daemon/HTTPServer.cpp:760
|
||||
#: daemon/HTTPServer.cpp:725 daemon/HTTPServer.cpp:730
|
||||
msgid "Start graceful shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:763
|
||||
#: daemon/HTTPServer.cpp:733
|
||||
msgid "Force shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:764
|
||||
#: daemon/HTTPServer.cpp:734
|
||||
msgid "Reload external CSS styles"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:767
|
||||
#: daemon/HTTPServer.cpp:737
|
||||
msgid ""
|
||||
"<b>Note:</b> any action done here are not persistent and not changes your "
|
||||
"config files."
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:770
|
||||
#: daemon/HTTPServer.cpp:739
|
||||
msgid "Logging level"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:779
|
||||
#: daemon/HTTPServer.cpp:747
|
||||
msgid "Transit tunnels limit"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:784 daemon/HTTPServer.cpp:803
|
||||
#: daemon/HTTPServer.cpp:752 daemon/HTTPServer.cpp:771
|
||||
msgid "Change"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:791
|
||||
#: daemon/HTTPServer.cpp:759
|
||||
msgid "Change language"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:830
|
||||
#: daemon/HTTPServer.cpp:797
|
||||
msgid "no transit tunnels currently built"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:921 daemon/HTTPServer.cpp:944
|
||||
#: daemon/HTTPServer.cpp:878 daemon/HTTPServer.cpp:901
|
||||
msgid "SAM disabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:937
|
||||
#: daemon/HTTPServer.cpp:894
|
||||
msgid "no sessions currently running"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:950
|
||||
#: daemon/HTTPServer.cpp:907
|
||||
msgid "SAM session not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:955
|
||||
#: daemon/HTTPServer.cpp:912
|
||||
msgid "SAM Session"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1020
|
||||
#: daemon/HTTPServer.cpp:969
|
||||
msgid "Server Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1036
|
||||
#: daemon/HTTPServer.cpp:985
|
||||
msgid "Client Forwards"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1050
|
||||
#: daemon/HTTPServer.cpp:999
|
||||
msgid "Server Forwards"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1250
|
||||
#: daemon/HTTPServer.cpp:1199
|
||||
msgid "Unknown page"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1269
|
||||
#: daemon/HTTPServer.cpp:1218
|
||||
msgid "Invalid token"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1327 daemon/HTTPServer.cpp:1359
|
||||
#: daemon/HTTPServer.cpp:1414 daemon/HTTPServer.cpp:1454
|
||||
#: daemon/HTTPServer.cpp:1276 daemon/HTTPServer.cpp:1333
|
||||
#: daemon/HTTPServer.cpp:1373
|
||||
msgid "SUCCESS"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1327
|
||||
#: daemon/HTTPServer.cpp:1276
|
||||
msgid "Stream closed"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1329
|
||||
#: daemon/HTTPServer.cpp:1278
|
||||
msgid "Stream not found or already was closed"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1332 daemon/HTTPServer.cpp:1365
|
||||
#: daemon/HTTPServer.cpp:1281
|
||||
msgid "Destination not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1335
|
||||
#: daemon/HTTPServer.cpp:1284
|
||||
msgid "StreamID can't be null"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1337 daemon/HTTPServer.cpp:1367
|
||||
#: daemon/HTTPServer.cpp:1432
|
||||
#: daemon/HTTPServer.cpp:1286 daemon/HTTPServer.cpp:1351
|
||||
msgid "Return to destination page"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1338 daemon/HTTPServer.cpp:1368
|
||||
#: daemon/HTTPServer.cpp:1381 daemon/HTTPServer.cpp:1456
|
||||
#: daemon/HTTPServer.cpp:1287 daemon/HTTPServer.cpp:1300
|
||||
#: daemon/HTTPServer.cpp:1375
|
||||
#, c-format
|
||||
msgid "You will be redirected in %d seconds"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1359
|
||||
msgid "LeaseSet expiration time updated"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1362
|
||||
msgid "LeaseSet is not found or already expired"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1379
|
||||
#: daemon/HTTPServer.cpp:1298
|
||||
#, c-format
|
||||
msgid "Transit tunnels count must not exceed %d"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1380 daemon/HTTPServer.cpp:1455
|
||||
#: daemon/HTTPServer.cpp:1299 daemon/HTTPServer.cpp:1374
|
||||
msgid "Back to commands list"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1416
|
||||
#: daemon/HTTPServer.cpp:1335
|
||||
msgid "Register at reg.i2p"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1417
|
||||
#: daemon/HTTPServer.cpp:1336
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1417
|
||||
#: daemon/HTTPServer.cpp:1336
|
||||
msgid "A bit information about service on domain"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1418
|
||||
#: daemon/HTTPServer.cpp:1337
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1424
|
||||
#: daemon/HTTPServer.cpp:1343
|
||||
msgid "Domain can't end with .b32.i2p"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1427
|
||||
#: daemon/HTTPServer.cpp:1346
|
||||
msgid "Domain must end with .i2p"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1450
|
||||
#: daemon/HTTPServer.cpp:1349
|
||||
msgid "Such destination is not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1369
|
||||
msgid "Unknown command"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1454
|
||||
#: daemon/HTTPServer.cpp:1373
|
||||
msgid "Command accepted"
|
||||
msgstr ""
|
||||
|
||||
@@ -642,20 +624,20 @@ msgstr ""
|
||||
msgid "You may try to find this host on jump services below"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:333 libi2pd_client/HTTPProxy.cpp:348
|
||||
#: libi2pd_client/HTTPProxy.cpp:417 libi2pd_client/HTTPProxy.cpp:460
|
||||
#: libi2pd_client/HTTPProxy.cpp:309 libi2pd_client/HTTPProxy.cpp:324
|
||||
#: libi2pd_client/HTTPProxy.cpp:392 libi2pd_client/HTTPProxy.cpp:435
|
||||
msgid "Invalid request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:333
|
||||
#: libi2pd_client/HTTPProxy.cpp:309
|
||||
msgid "Proxy unable to parse your request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:348
|
||||
#: libi2pd_client/HTTPProxy.cpp:324
|
||||
msgid "Addresshelper is not supported"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:373
|
||||
#: libi2pd_client/HTTPProxy.cpp:349
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Host %s is <font color=red>already in router's addressbook</font>. <b>Be "
|
||||
@@ -663,121 +645,121 @@ msgid ""
|
||||
"<a href=\"%s%s%s&update=true\">Continue</a>."
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:375
|
||||
#: libi2pd_client/HTTPProxy.cpp:351
|
||||
msgid "Addresshelper forced update rejected"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:382
|
||||
#: libi2pd_client/HTTPProxy.cpp:358
|
||||
#, c-format
|
||||
msgid ""
|
||||
"To add host <b>%s</b> in router's addressbook, click here: <a "
|
||||
"href=\"%s%s%s\">Continue</a>."
|
||||
"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s"
|
||||
"\">Continue</a>."
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:384
|
||||
#: libi2pd_client/HTTPProxy.cpp:360
|
||||
msgid "Addresshelper request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:393
|
||||
#: libi2pd_client/HTTPProxy.cpp:369
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Host %s added to router's addressbook from helper. Click here to proceed: <a "
|
||||
"href=\"%s\">Continue</a>."
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:395
|
||||
#: libi2pd_client/HTTPProxy.cpp:370
|
||||
msgid "Addresshelper adding"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:402
|
||||
#: libi2pd_client/HTTPProxy.cpp:377
|
||||
#, c-format
|
||||
msgid ""
|
||||
"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>."
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:404
|
||||
#: libi2pd_client/HTTPProxy.cpp:379
|
||||
msgid "Addresshelper update"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:417
|
||||
#: libi2pd_client/HTTPProxy.cpp:392
|
||||
msgid "Invalid request URI"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:460
|
||||
#: libi2pd_client/HTTPProxy.cpp:435
|
||||
msgid "Can't detect destination host from request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:477 libi2pd_client/HTTPProxy.cpp:481
|
||||
#: libi2pd_client/HTTPProxy.cpp:452 libi2pd_client/HTTPProxy.cpp:456
|
||||
msgid "Outproxy failure"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:477
|
||||
#: libi2pd_client/HTTPProxy.cpp:452
|
||||
msgid "Bad outproxy settings"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:480
|
||||
#: libi2pd_client/HTTPProxy.cpp:455
|
||||
#, c-format
|
||||
msgid "Host %s is not inside I2P network, but outproxy is not enabled"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:569
|
||||
#: libi2pd_client/HTTPProxy.cpp:544
|
||||
msgid "Unknown outproxy URL"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:575
|
||||
#: libi2pd_client/HTTPProxy.cpp:550
|
||||
msgid "Cannot resolve upstream proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:583
|
||||
#: libi2pd_client/HTTPProxy.cpp:558
|
||||
msgid "Hostname is too long"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:610
|
||||
#: libi2pd_client/HTTPProxy.cpp:585
|
||||
msgid "Cannot connect to upstream SOCKS proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:616
|
||||
#: libi2pd_client/HTTPProxy.cpp:591
|
||||
msgid "Cannot negotiate with SOCKS proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:658
|
||||
#: libi2pd_client/HTTPProxy.cpp:633
|
||||
msgid "CONNECT error"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:658
|
||||
#: libi2pd_client/HTTPProxy.cpp:633
|
||||
msgid "Failed to connect"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:669 libi2pd_client/HTTPProxy.cpp:695
|
||||
#: libi2pd_client/HTTPProxy.cpp:644 libi2pd_client/HTTPProxy.cpp:670
|
||||
msgid "SOCKS proxy error"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:677
|
||||
#: libi2pd_client/HTTPProxy.cpp:652
|
||||
msgid "Failed to send request to upstream"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:698
|
||||
#: libi2pd_client/HTTPProxy.cpp:673
|
||||
msgid "No reply from SOCKS proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:705
|
||||
#: libi2pd_client/HTTPProxy.cpp:680
|
||||
msgid "Cannot connect"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:705
|
||||
#: libi2pd_client/HTTPProxy.cpp:680
|
||||
msgid "HTTP out proxy not implemented"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:706
|
||||
#: libi2pd_client/HTTPProxy.cpp:681
|
||||
msgid "Cannot connect to upstream HTTP proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:739
|
||||
#: libi2pd_client/HTTPProxy.cpp:714
|
||||
msgid "Host is down"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:739
|
||||
#: libi2pd_client/HTTPProxy.cpp:714
|
||||
msgid ""
|
||||
"Can't create connection to requested host, it may be down. Please try again "
|
||||
"later."
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
`xgettext` command for extracting translation
|
||||
---
|
||||
|
||||
```
|
||||
xgettext --omit-header -ctr: -ktr -kntr:1,2 daemon/HTTPServer.cpp libi2pd_client/HTTPProxy.cpp
|
||||
```
|
||||
|
||||
Regex for transforming gettext translations to our format:
|
||||
---
|
||||
|
||||
```
|
||||
in: ^(\"|#[:.,]|msgctxt)(.*)$\n
|
||||
out: <to empty line>
|
||||
```
|
||||
|
||||
```
|
||||
in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)?
|
||||
out: #{"$2", {"$3", "$5", "$7", "$9", "$11"}},\n
|
||||
```
|
||||
|
||||
```
|
||||
in: msgid\ \"(.*)\"\nmsgstr\ \"(.*)\"\n
|
||||
out: {"$1", "$2"},\n
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
in: \n\n
|
||||
out: \n
|
||||
```
|
||||
`xgettext` command for extracting translation
|
||||
---
|
||||
|
||||
```
|
||||
xgettext --omit-header -ctr: -ktr -ktr:1,2 daemon/HTTPServer.cpp libi2pd_client/HTTPProxy.cpp
|
||||
```
|
||||
|
||||
Regex for transforming gettext translations to our format:
|
||||
---
|
||||
|
||||
```
|
||||
in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)?
|
||||
out: #{"$2", {"$3", "$5", "$7", "$9", "$11"}},\n
|
||||
```
|
||||
|
||||
```
|
||||
in: msgid\ \"(.*)\"\nmsgstr\ \"(.*)\"\n
|
||||
out: {"$1", "$2"},\n
|
||||
```
|
||||
|
||||
```
|
||||
in: ^#[:.](.*)$\n
|
||||
out: <to empty line>
|
||||
```
|
||||
|
||||
```
|
||||
in: \n\n
|
||||
out: \n
|
||||
```
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
## Default: ~/.i2pd/certificates or /var/lib/i2pd/certificates
|
||||
# certsdir = /var/lib/i2pd/certificates
|
||||
|
||||
## Where to write pidfile (default: /run/i2pd.pid, not used in Windows)
|
||||
## Where to write pidfile (default: i2pd.pid, not used in Windows)
|
||||
# pidfile = /run/i2pd.pid
|
||||
|
||||
## Logging configuration section
|
||||
@@ -31,16 +31,15 @@
|
||||
## * file - log entries to a file
|
||||
## * syslog - use syslog, see man 3 syslog
|
||||
# log = file
|
||||
## Path to logfile (default: autodetect)
|
||||
## Path to logfile (default - autodetect)
|
||||
# logfile = /var/log/i2pd/i2pd.log
|
||||
## Log messages above this level (debug, info, *warn, error, critical, none)
|
||||
## Log messages above this level (debug, info, *warn, error, none)
|
||||
## If you set it to none, logging will be disabled
|
||||
# loglevel = warn
|
||||
## Write full CLF-formatted date and time to log (default: write only time)
|
||||
# logclftime = true
|
||||
|
||||
## Daemon mode. Router will go to background after start. Ignored on Windows
|
||||
## (default: true)
|
||||
# daemon = true
|
||||
|
||||
## Specify a family, router belongs to (default - none)
|
||||
@@ -71,60 +70,58 @@
|
||||
## don't just uncomment this
|
||||
# port = 4567
|
||||
|
||||
## Enable communication through ipv4 (default: true)
|
||||
## Enable communication through ipv4
|
||||
ipv4 = true
|
||||
## Enable communication through ipv6 (default: false)
|
||||
## Enable communication through ipv6
|
||||
ipv6 = false
|
||||
|
||||
## Enable SSU transport
|
||||
ssu = false
|
||||
|
||||
## Bandwidth configuration
|
||||
## L limit bandwidth to 32 KB/sec, O - to 256 KB/sec, P - to 2048 KB/sec,
|
||||
## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec,
|
||||
## X - unlimited
|
||||
## Default is L (regular node) and X if floodfill mode enabled.
|
||||
## If you want to share more bandwidth without floodfill mode, uncomment
|
||||
## that line and adjust value to your possibilities. Value can be set to
|
||||
## integer in kilobytes, it will apply that limit and flag will be used
|
||||
## from next upper limit (example: if you set 4096 flag will be X, but real
|
||||
## limit will be 4096 KB/s). Same can be done when floodfill mode is used,
|
||||
## but keep in mind that low values may be negatively evaluated by Java
|
||||
## router algorithms.
|
||||
## Default is L (regular node) and X if floodfill mode enabled. If you want to
|
||||
## share more bandwidth without floodfill mode, uncomment that line and adjust
|
||||
## value to your possibilities
|
||||
# bandwidth = L
|
||||
## Max % of bandwidth limit for transit. 0-100 (default: 100)
|
||||
## Max % of bandwidth limit for transit. 0-100. 100 by default
|
||||
# share = 100
|
||||
|
||||
## Router will not accept transit tunnels, disabling transit traffic completely
|
||||
## (default: false)
|
||||
## (default = false)
|
||||
# notransit = true
|
||||
|
||||
## Router will be floodfill (default: false)
|
||||
## Router will be floodfill
|
||||
## Note: that mode uses much more network connections and CPU!
|
||||
# floodfill = true
|
||||
|
||||
[ntcp2]
|
||||
## Enable NTCP2 transport (default: true)
|
||||
## Enable NTCP2 transport (default = true)
|
||||
# enabled = true
|
||||
## Publish address in RouterInfo (default: true)
|
||||
## Publish address in RouterInfo (default = true)
|
||||
# published = true
|
||||
## Port for incoming connections (default is global port option value)
|
||||
# port = 4567
|
||||
|
||||
[ssu2]
|
||||
## Enable SSU2 transport (default: true)
|
||||
## Enable SSU2 transport
|
||||
# enabled = true
|
||||
## Publish address in RouterInfo (default: true)
|
||||
## Publish address in RouterInfo
|
||||
# published = true
|
||||
## Port for incoming connections (default is global port option value)
|
||||
## Port for incoming connections (default is global port option value or port + 1 if SSU is enabled)
|
||||
# port = 4567
|
||||
|
||||
[http]
|
||||
## Web Console settings
|
||||
## Enable the Web Console (default: true)
|
||||
## Uncomment and set to 'false' to disable Web Console
|
||||
# enabled = true
|
||||
## Address and port service will listen on (default: 127.0.0.1:7070)
|
||||
# address = 127.0.0.1
|
||||
# port = 7070
|
||||
## Path to web console (default: /)
|
||||
## Address and port service will listen on
|
||||
address = 127.0.0.1
|
||||
port = 7070
|
||||
## Path to web console, default "/"
|
||||
# webroot = /
|
||||
## Enable Web Console authentication (default: false)
|
||||
## Uncomment following lines to enable Web Console authentication
|
||||
## You should not use Web Console via public networks without additional encryption.
|
||||
## HTTP authentication is not encryption layer!
|
||||
# auth = true
|
||||
@@ -132,17 +129,16 @@ ipv6 = false
|
||||
# pass = changeme
|
||||
## Select webconsole language
|
||||
## Currently supported english (default), afrikaans, armenian, chinese, czech, french,
|
||||
## german, italian, polish, portuguese, russian, spanish, turkish, turkmen, ukrainian
|
||||
## and uzbek languages
|
||||
## german, italian, russian, spanish, turkmen, ukrainian and uzbek languages
|
||||
# lang = english
|
||||
|
||||
[httpproxy]
|
||||
## Enable the HTTP proxy (default: true)
|
||||
## Uncomment and set to 'false' to disable HTTP Proxy
|
||||
# enabled = true
|
||||
## Address and port service will listen on (default: 127.0.0.1:4444)
|
||||
# address = 127.0.0.1
|
||||
# port = 4444
|
||||
## Optional keys file for proxy local destination (default: http-proxy-keys.dat)
|
||||
## Address and port service will listen on
|
||||
address = 127.0.0.1
|
||||
port = 4444
|
||||
## Optional keys file for proxy local destination
|
||||
# keys = http-proxy-keys.dat
|
||||
## Enable address helper for adding .i2p domains with "jump URLs" (default: true)
|
||||
## You should disable this feature if your i2pd HTTP Proxy is public,
|
||||
@@ -153,15 +149,15 @@ ipv6 = false
|
||||
## httpproxy section also accepts I2CP parameters, like "inbound.length" etc.
|
||||
|
||||
[socksproxy]
|
||||
## Enable the SOCKS proxy (default: true)
|
||||
## Uncomment and set to 'false' to disable SOCKS Proxy
|
||||
# enabled = true
|
||||
## Address and port service will listen on (default: 127.0.0.1:4447)
|
||||
# address = 127.0.0.1
|
||||
# port = 4447
|
||||
## Optional keys file for proxy local destination (default: socks-proxy-keys.dat)
|
||||
## Address and port service will listen on
|
||||
address = 127.0.0.1
|
||||
port = 4447
|
||||
## Optional keys file for proxy local destination
|
||||
# keys = socks-proxy-keys.dat
|
||||
## Socks outproxy. Example below is set to use Tor for all connections except i2p
|
||||
## Enable using of SOCKS outproxy (works only with SOCKS4, default: false)
|
||||
## Uncomment and set to 'true' to enable using of SOCKS outproxy
|
||||
# outproxy.enabled = false
|
||||
## Address and port of outproxy
|
||||
# outproxy = 127.0.0.1
|
||||
@@ -169,34 +165,33 @@ ipv6 = false
|
||||
## socksproxy section also accepts I2CP parameters, like "inbound.length" etc.
|
||||
|
||||
[sam]
|
||||
## Enable the SAM bridge (default: true)
|
||||
# enabled = false
|
||||
## Address and ports service will listen on (default: 127.0.0.1:7656, udp: 7655)
|
||||
## Comment or set to 'false' to disable SAM Bridge
|
||||
enabled = true
|
||||
## Address and port service will listen on
|
||||
# address = 127.0.0.1
|
||||
# port = 7656
|
||||
# portudp = 7655
|
||||
|
||||
[bob]
|
||||
## Enable the BOB command channel (default: false)
|
||||
## Uncomment and set to 'true' to enable BOB command channel
|
||||
# enabled = false
|
||||
## Address and port service will listen on (default: 127.0.0.1:2827)
|
||||
## Address and port service will listen on
|
||||
# address = 127.0.0.1
|
||||
# port = 2827
|
||||
|
||||
[i2cp]
|
||||
## Enable the I2CP protocol (default: false)
|
||||
## Uncomment and set to 'true' to enable I2CP protocol
|
||||
# enabled = false
|
||||
## Address and port service will listen on (default: 127.0.0.1:7654)
|
||||
## Address and port service will listen on
|
||||
# address = 127.0.0.1
|
||||
# port = 7654
|
||||
|
||||
[i2pcontrol]
|
||||
## Enable the I2PControl protocol (default: false)
|
||||
## Uncomment and set to 'true' to enable I2PControl protocol
|
||||
# enabled = false
|
||||
## Address and port service will listen on (default: 127.0.0.1:7650)
|
||||
## Address and port service will listen on
|
||||
# address = 127.0.0.1
|
||||
# port = 7650
|
||||
## Authentication password (default: itoopie)
|
||||
## Authentication password. "itoopie" by default
|
||||
# password = itoopie
|
||||
|
||||
[precomputation]
|
||||
@@ -207,11 +202,11 @@ ipv6 = false
|
||||
[upnp]
|
||||
## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID)
|
||||
# enabled = false
|
||||
## Name i2pd appears in UPnP forwardings list (default: I2Pd)
|
||||
## Name i2pd appears in UPnP forwardings list (default = I2Pd)
|
||||
# name = I2Pd
|
||||
|
||||
[meshnets]
|
||||
## Enable connectivity over the Yggdrasil network (default: false)
|
||||
## Enable connectivity over the Yggdrasil network
|
||||
# yggdrasil = false
|
||||
## You can bind address from your Yggdrasil subnet 300::/64
|
||||
## The address must first be added to the network interface
|
||||
@@ -219,7 +214,7 @@ ipv6 = false
|
||||
|
||||
[reseed]
|
||||
## Options for bootstrapping into I2P network, aka reseeding
|
||||
## Enable reseed data verification (default: true)
|
||||
## Enable or disable reseed data verification.
|
||||
verify = true
|
||||
## URLs to request reseed data from, separated by comma
|
||||
## Default: "mainline" I2P Network reseeds
|
||||
@@ -235,7 +230,7 @@ verify = true
|
||||
## If you run i2pd behind a proxy server, set proxy server for reseeding here
|
||||
## Should be http://address:port or socks://address:port
|
||||
# proxy = http://127.0.0.1:8118
|
||||
## Minimum number of known routers, below which i2pd triggers reseeding (default: 25)
|
||||
## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default
|
||||
# threshold = 25
|
||||
|
||||
[addressbook]
|
||||
@@ -255,13 +250,13 @@ verify = true
|
||||
# coresize = 0
|
||||
|
||||
[trust]
|
||||
## Enable explicit trust options. (default: false)
|
||||
## Enable explicit trust options. false by default
|
||||
# enabled = true
|
||||
## Make direct I2P connections only to routers in specified Family.
|
||||
# family = MyFamily
|
||||
## Make direct I2P connections only to routers specified here. Comma separated list of base64 identities.
|
||||
# routers =
|
||||
## Should we hide our router from other routers? (default: false)
|
||||
## Should we hide our router from other routers? false by default
|
||||
# hidden = true
|
||||
|
||||
[exploratory]
|
||||
@@ -282,6 +277,6 @@ verify = true
|
||||
# aesni = true
|
||||
## Use CPU AVX instructions set when work with cryptography when available (default: true)
|
||||
# avx = true
|
||||
## Force usage of CPU instructions set, even if they not found (default: false)
|
||||
## Force usage of CPU instructions set, even if they not found
|
||||
## DO NOT TOUCH that option if you really don't know what are you doing!
|
||||
# force = false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||
|
||||
Name: i2pd-git
|
||||
Version: 2.48.0
|
||||
Version: 2.45.1
|
||||
Release: git%{git_hash}%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd
|
||||
@@ -158,18 +158,6 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon Jun 12 2023 orignal <orignal@i2pmail.org> - 2.48.0
|
||||
- update to 2.48.0
|
||||
|
||||
* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
|
||||
- update to 2.47.0
|
||||
|
||||
* Mon Feb 20 2023 r4sas <r4sas@i2pmail.org> - 2.46.1
|
||||
- update to 2.46.1
|
||||
|
||||
* Wed Feb 15 2023 orignal <orignal@i2pmail.org> - 2.46.0
|
||||
- update to 2.46.0
|
||||
|
||||
* Wed Jan 11 2023 orignal <orignal@i2pmail.org> - 2.45.1
|
||||
- update to 2.45.1
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: i2pd
|
||||
Version: 2.48.0
|
||||
Version: 2.45.1
|
||||
Release: 1%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd-git
|
||||
@@ -155,18 +155,6 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon Jun 12 2023 orignal <orignal@i2pmail.org> - 2.48.0
|
||||
- update to 2.48.0
|
||||
|
||||
* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
|
||||
- update to 2.47.0
|
||||
|
||||
* Mon Feb 20 2023 r4sas <r4sas@i2pmail.org> - 2.46.1
|
||||
- update to 2.46.1
|
||||
|
||||
* Wed Feb 15 2023 orignal <orignal@i2pmail.org> - 2.46.0
|
||||
- update to 2.46.0
|
||||
|
||||
* Wed Jan 11 2023 orignal <orignal@i2pmail.org> - 2.45.1
|
||||
- update to 2.45.1
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace util
|
||||
uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
|
||||
if (isFloodfill && i2p::config::IsDefault ("limits.transittunnels"))
|
||||
transitTunnels *= 2; // double default number of transit tunnels for floodfill
|
||||
i2p::tunnel::tunnels.SetMaxNumTransitTunnels (transitTunnels);
|
||||
SetMaxNumTransitTunnels (transitTunnels);
|
||||
|
||||
/* this section also honors 'floodfill' flag, if set above */
|
||||
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
|
||||
@@ -269,7 +269,7 @@ namespace util
|
||||
if (hidden)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: Hidden mode enabled");
|
||||
i2p::context.SetHidden(true);
|
||||
i2p::data::netdb.SetHidden(true);
|
||||
}
|
||||
|
||||
std::string httpLang; i2p::config::GetOption("http.lang", httpLang);
|
||||
@@ -310,7 +310,7 @@ namespace util
|
||||
LogPrint(eLogInfo, "Daemon: Transports started");
|
||||
else
|
||||
{
|
||||
LogPrint(eLogCritical, "Daemon: Failed to start Transports");
|
||||
LogPrint(eLogError, "Daemon: Failed to start Transports");
|
||||
/** shut down netdb right away */
|
||||
i2p::transport::transports.Stop();
|
||||
i2p::data::netdb.Stop();
|
||||
@@ -329,17 +329,15 @@ namespace util
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogCritical, "Daemon: Failed to start Webconsole: ", ex.what ());
|
||||
LogPrint (eLogError, "Daemon: Failed to start Webconsole: ", ex.what ());
|
||||
ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: Starting Tunnels");
|
||||
i2p::tunnel::tunnels.Start();
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: Starting Router context");
|
||||
i2p::context.Start();
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: Starting Client");
|
||||
i2p::client::context.Start ();
|
||||
|
||||
@@ -356,7 +354,7 @@ namespace util
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogCritical, "Daemon: Failed to start I2PControl: ", ex.what ());
|
||||
LogPrint (eLogError, "Daemon: Failed to start I2PControl: ", ex.what ());
|
||||
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
|
||||
}
|
||||
}
|
||||
@@ -368,8 +366,6 @@ namespace util
|
||||
LogPrint(eLogInfo, "Daemon: Shutting down");
|
||||
LogPrint(eLogInfo, "Daemon: Stopping Client");
|
||||
i2p::client::context.Stop();
|
||||
LogPrint(eLogInfo, "Daemon: Stopping Router context");
|
||||
i2p::context.Stop();
|
||||
LogPrint(eLogInfo, "Daemon: Stopping Tunnels");
|
||||
i2p::tunnel::tunnels.Stop();
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ namespace http {
|
||||
const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string";
|
||||
const char HTTP_COMMAND_SETLANGUAGE[] = "setlanguage";
|
||||
const char HTTP_COMMAND_RELOAD_CSS[] = "reload_css";
|
||||
const char HTTP_COMMAND_EXPIRELEASE[] = "expirelease";
|
||||
|
||||
static std::string ConvertTime (uint64_t time)
|
||||
{
|
||||
@@ -157,7 +156,7 @@ namespace http {
|
||||
|
||||
static void SetLogLevel (const std::string& level)
|
||||
{
|
||||
if (level == "none" || level == "critical" || level == "error" || level == "warn" || level == "info" || level == "debug")
|
||||
if (level == "none" || level == "error" || level == "warn" || level == "info" || level == "debug")
|
||||
i2p::log::Logger().SetLogLevel(level);
|
||||
else {
|
||||
LogPrint(eLogError, "HTTPServer: Unknown loglevel set attempted");
|
||||
@@ -290,11 +289,6 @@ namespace http {
|
||||
if (family.length () > 0)
|
||||
s << "<b>"<< tr("Family") << ":</b> " << family << "<br>\r\n";
|
||||
s << "<b>" << tr("Tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n";
|
||||
bool isTotalTCSR;
|
||||
i2p::config::GetOption("http.showTotalTCSR", isTotalTCSR);
|
||||
if (isTotalTCSR) {
|
||||
s << "<b>" << tr("Total tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTotalTunnelCreationSuccessRate() << "%<br/>\r\n";
|
||||
}
|
||||
s << "<b>" << tr("Received") << ":</b> ";
|
||||
ShowTraffic (s, i2p::transport::transports.GetTotalReceivedBytes ());
|
||||
s << " (" << tr(/* tr: Kibibyte/s */ "%.2f KiB/s", (double) i2p::transport::transports.GetInBandwidth15s () / 1024) << ")<br>\r\n";
|
||||
@@ -335,15 +329,14 @@ namespace http {
|
||||
default:
|
||||
s << tr("Unknown");
|
||||
}
|
||||
bool v6 = address->IsV6 ();
|
||||
if (v6)
|
||||
if (address->IsV6 ())
|
||||
{
|
||||
if (address->IsV4 ()) s << "v4";
|
||||
s << "v6";
|
||||
}
|
||||
s << "</td>\r\n";
|
||||
if (address->published)
|
||||
s << "<td>" << (v6 ? "[" : "") << address->host.to_string() << (v6 ? "]:" : ":") << address->port << "</td>\r\n";
|
||||
s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n";
|
||||
else
|
||||
{
|
||||
s << "<td>" << tr(/* tr: Shown when router doesn't publish itself and have "Firewalled" state */ "supported");
|
||||
@@ -422,12 +415,8 @@ namespace http {
|
||||
|
||||
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 << dest->GetIdentHash ().ToBase32 () << "</textarea><br>\r\n<br>\r\n";
|
||||
|
||||
s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"8\">";
|
||||
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
|
||||
|
||||
if (dest->IsEncryptedLeaseSet ())
|
||||
{
|
||||
i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ());
|
||||
@@ -439,11 +428,12 @@ namespace http {
|
||||
if (dest->IsPublic() && token && !dest->IsEncryptedLeaseSet ())
|
||||
{
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
auto base32 = dest->GetIdentHash ().ToBase32 ();
|
||||
s << "<div class='slide'><label for='slide-regaddr'><b>" << tr("Address registration line") << "</b></label>\r\n<input type=\"checkbox\" id=\"slide-regaddr\" />\r\n<div class=\"slidecontent\">\r\n"
|
||||
"<form method=\"get\" action=\"" << webroot << "\">\r\n"
|
||||
" <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_GET_REG_STRING << "\">\r\n"
|
||||
" <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n"
|
||||
" <input type=\"hidden\" name=\"b32\" value=\"" << dest->GetIdentHash ().ToBase32 () << "\">\r\n"
|
||||
" <input type=\"hidden\" name=\"b32\" value=\"" << base32 << "\">\r\n"
|
||||
" <b>" << tr("Domain") << ":</b>\r\n<input type=\"text\" maxlength=\"67\" name=\"name\" placeholder=\"domain.i2p\" required>\r\n"
|
||||
" <button type=\"submit\">" << tr("Generate") << "</button>\r\n"
|
||||
"</form>\r\n<small>" << tr("<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.") << "</small>\r\n</div>\r\n</div>\r\n<br>\r\n";
|
||||
@@ -452,23 +442,9 @@ namespace http {
|
||||
if (dest->GetNumRemoteLeaseSets())
|
||||
{
|
||||
s << "<div class='slide'><label for='slide-lease'><b>" << tr("LeaseSets") << ":</b> <i>" << dest->GetNumRemoteLeaseSets ()
|
||||
<< "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n"
|
||||
<< "<table><thead>"
|
||||
<< "<th>" << tr("Address") << "</th>"
|
||||
<< "<th style=\"width:5px;\"> </th>" // LeaseSet expiration button column
|
||||
<< "<th>" << tr("Type") << "</th>"
|
||||
<< "<th>" << tr("EncType") << "</th>"
|
||||
<< "</thead><tbody class=\"tableitem\">";
|
||||
<< "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n<table><thead><th>"<< tr("Address") << "</th><th>" << tr("Type") << "</th><th>" << tr("EncType") << "</th></thead><tbody class=\"tableitem\">";
|
||||
for(auto& it: dest->GetLeaseSets ())
|
||||
{
|
||||
s << "<tr>"
|
||||
<< "<td>" << it.first.ToBase32 () << "</td>"
|
||||
<< "<td><a class=\"button\" href=\"/?cmd=" << HTTP_COMMAND_EXPIRELEASE<< "&b32=" << dest->GetIdentHash ().ToBase32 ()
|
||||
<< "&lease=" << it.first.ToBase32 () << "&token=" << token << "\" title=\"" << tr("Expire LeaseSet") << "\"> ✘ </a></td>"
|
||||
<< "<td>" << (int)it.second->GetStoreType () << "</td>"
|
||||
<< "<td>" << (int)it.second->GetEncryptionType () <<"</td>"
|
||||
<< "</tr>\r\n";
|
||||
}
|
||||
s << "<tr><td>" << it.first.ToBase32 () << "</td><td>" << (int)it.second->GetStoreType () << "</td><td>" << (int)it.second->GetEncryptionType () <<"</td></tr>\r\n";
|
||||
s << "</tbody></table>\r\n</div>\r\n</div>\r\n<br>\r\n";
|
||||
} else
|
||||
s << "<b>" << tr("LeaseSets") << ":</b> <i>0</i><br>\r\n<br>\r\n";
|
||||
@@ -572,7 +548,7 @@ namespace http {
|
||||
<< tr("Streams")
|
||||
<< "</caption>\r\n<thead>\r\n<tr>"
|
||||
<< "<th style=\"width:25px;\">StreamID</th>"
|
||||
<< "<th style=\"width:5px;\"> </th>" // Stream closing button column
|
||||
<< "<th style=\"width:5px;\" \\>" // Stream closing button column
|
||||
<< "<th class=\"streamdest\">Destination</th>"
|
||||
<< "<th>Sent</th>"
|
||||
<< "<th>Received</th>"
|
||||
@@ -609,8 +585,6 @@ namespace http {
|
||||
}
|
||||
s << "</tbody>\r\n</table>";
|
||||
}
|
||||
else
|
||||
ShowError(s, tr("Such destination is not found"));
|
||||
}
|
||||
|
||||
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id)
|
||||
@@ -645,10 +619,7 @@ namespace http {
|
||||
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||
ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
||||
else
|
||||
{
|
||||
ls.reset (new i2p::data::LeaseSet2 (storeType));
|
||||
ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), false);
|
||||
}
|
||||
ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
||||
if (!ls) return;
|
||||
s << "<div class=\"leaseset listitem";
|
||||
if (ls->IsExpired())
|
||||
@@ -768,14 +739,13 @@ namespace http {
|
||||
|
||||
auto loglevel = i2p::log::Logger().GetLogLevel();
|
||||
s << "<b>" << tr("Logging level") << "</b><br>\r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogNone ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\"> none </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogCritical ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=critical&token=" << token << "\"> critical </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogError ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\"> error </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogWarning ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\"> warn </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogInfo ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\"> info </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogDebug ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\"> debug </a><br>\r\n<br>\r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogNone ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\"> none </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogError ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\"> error </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogWarning ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\"> warn </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogInfo ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\"> info </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogDebug ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\"> debug </a><br>\r\n<br>\r\n";
|
||||
|
||||
uint16_t maxTunnels = i2p::tunnel::tunnels.GetMaxNumTransitTunnels ();
|
||||
uint16_t maxTunnels = GetMaxNumTransitTunnels ();
|
||||
s << "<b>" << tr("Transit tunnels limit") << "</b><br>\r\n";
|
||||
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
|
||||
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_LIMITTRANSIT << "\">\r\n";
|
||||
@@ -834,47 +804,37 @@ namespace http {
|
||||
template<typename Sessions>
|
||||
static void ShowTransportSessions (std::stringstream& s, const Sessions& sessions, const std::string name)
|
||||
{
|
||||
auto comp = [](typename Sessions::mapped_type a, typename Sessions::mapped_type b)
|
||||
{ return a->GetRemoteEndpoint() < b->GetRemoteEndpoint(); };
|
||||
std::set<typename Sessions::mapped_type, decltype(comp)> sortedSessions(comp);
|
||||
for (const auto& it : sessions)
|
||||
{
|
||||
auto ret = sortedSessions.insert(it.second);
|
||||
if (!ret.second)
|
||||
LogPrint(eLogError, "HTTPServer: Duplicate remote endpoint detected: ", (*ret.first)->GetRemoteEndpoint());
|
||||
}
|
||||
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
|
||||
for (const auto& it: sortedSessions)
|
||||
for (const auto& it: sessions )
|
||||
{
|
||||
auto endpoint = it->GetRemoteEndpoint ();
|
||||
if (it && it->IsEstablished () && endpoint.address ().is_v4 ())
|
||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||
if (it.second && it.second->IsEstablished () && endpoint.address ().is_v4 ())
|
||||
{
|
||||
tmp_s << "<div class=\"listitem\">\r\n";
|
||||
if (it->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||
tmp_s << i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||
if (it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||
tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||
<< endpoint.address ().to_string () << ":" << endpoint.port ();
|
||||
if (!it->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||
tmp_s << " [" << it->GetNumSentBytes () << ":" << it->GetNumReceivedBytes () << "]";
|
||||
if (it->GetRelayTag ())
|
||||
tmp_s << " [itag:" << it->GetRelayTag () << "]";
|
||||
if (it->GetSendQueueSize () > 0)
|
||||
tmp_s << " [queue:" << it->GetSendQueueSize () << "]";
|
||||
if (it->IsSlow ()) tmp_s << " [slow]";
|
||||
if (!it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
if (it.second->GetRelayTag ())
|
||||
tmp_s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||
if (it.second->GetSendQueueSize () > 0)
|
||||
tmp_s << " [queue:" << it.second->GetSendQueueSize () << "]";
|
||||
tmp_s << "</div>\r\n" << std::endl;
|
||||
cnt++;
|
||||
}
|
||||
if (it && it->IsEstablished () && endpoint.address ().is_v6 ())
|
||||
if (it.second && it.second->IsEstablished () && endpoint.address ().is_v6 ())
|
||||
{
|
||||
tmp_s6 << "<div class=\"listitem\">\r\n";
|
||||
if (it->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||
if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||
<< "[" << endpoint.address ().to_string () << "]:" << endpoint.port ();
|
||||
if (!it->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||
tmp_s6 << " [" << it->GetNumSentBytes () << ":" << it->GetNumReceivedBytes () << "]";
|
||||
if (it->GetRelayTag ())
|
||||
tmp_s6 << " [itag:" << it->GetRelayTag () << "]";
|
||||
if (it->GetSendQueueSize () > 0)
|
||||
tmp_s6 << " [queue:" << it->GetSendQueueSize () << "]";
|
||||
if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
if (it.second->GetRelayTag ())
|
||||
tmp_s6 << " [itag:" << it.second->GetRelayTag () << "]";
|
||||
if (it.second->GetSendQueueSize () > 0)
|
||||
tmp_s6 << " [queue:" << it.second->GetSendQueueSize () << "]";
|
||||
tmp_s6 << "</div>\r\n" << std::endl;
|
||||
cnt6++;
|
||||
}
|
||||
@@ -978,42 +938,34 @@ namespace http {
|
||||
void ShowI2PTunnels (std::stringstream& s)
|
||||
{
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
|
||||
auto& clientTunnels = i2p::client::context.GetClientTunnels ();
|
||||
auto httpProxy = i2p::client::context.GetHttpProxy ();
|
||||
auto socksProxy = i2p::client::context.GetSocksProxy ();
|
||||
if (!clientTunnels.empty () || httpProxy || socksProxy)
|
||||
s << "<b>" << tr("Client Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
for (auto& it: i2p::client::context.GetClientTunnels ())
|
||||
{
|
||||
s << "<b>" << tr("Client Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
if (!clientTunnels.empty ())
|
||||
{
|
||||
for (auto& it: clientTunnels)
|
||||
{
|
||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << it.second->GetName () << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
}
|
||||
if (httpProxy)
|
||||
{
|
||||
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << "HTTP " << tr("Proxy") << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
if (socksProxy)
|
||||
{
|
||||
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << "SOCKS " << tr("Proxy") << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
s << "</div>\r\n";
|
||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << it.second->GetName () << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
auto httpProxy = i2p::client::context.GetHttpProxy ();
|
||||
if (httpProxy)
|
||||
{
|
||||
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << "HTTP " << tr("Proxy") << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
auto socksProxy = i2p::client::context.GetSocksProxy ();
|
||||
if (socksProxy)
|
||||
{
|
||||
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << "SOCKS " << tr("Proxy") << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
s << "</div>\r\n";
|
||||
|
||||
auto& serverTunnels = i2p::client::context.GetServerTunnels ();
|
||||
if (!serverTunnels.empty ()) {
|
||||
@@ -1340,41 +1292,11 @@ namespace http {
|
||||
res.add_header("Refresh", redirect.c_str());
|
||||
return;
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_EXPIRELEASE)
|
||||
{
|
||||
std::string b32 = params["b32"];
|
||||
std::string lease = params["lease"];
|
||||
|
||||
i2p::data::IdentHash ident, leaseident;
|
||||
ident.FromBase32 (b32);
|
||||
leaseident.FromBase32 (lease);
|
||||
auto dest = i2p::client::context.FindLocalDestination (ident);
|
||||
|
||||
if (dest)
|
||||
{
|
||||
auto leaseset = dest->FindLeaseSet (leaseident);
|
||||
if (leaseset)
|
||||
{
|
||||
leaseset->ExpireLease ();
|
||||
s << "<b>" << tr("SUCCESS") << "</b>: " << tr("LeaseSet expiration time updated") << "<br>\r\n<br>\r\n";
|
||||
}
|
||||
else
|
||||
s << "<b>" << tr("ERROR") << "</b>: " << tr("LeaseSet is not found or already expired") << "<br>\r\n<br>\r\n";
|
||||
}
|
||||
else
|
||||
s << "<b>" << tr("ERROR") << "</b>: " << tr("Destination not found") << "<br>\r\n<br>\r\n";
|
||||
|
||||
s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a><br>\r\n";
|
||||
s << "<p>" << tr("You will be redirected in %d seconds", COMMAND_REDIRECT_TIMEOUT) << "</b>";
|
||||
redirect = std::to_string(COMMAND_REDIRECT_TIMEOUT) + "; url=" + webroot + "?page=local_destination&b32=" + b32;
|
||||
res.add_header("Refresh", redirect.c_str());
|
||||
return;
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_LIMITTRANSIT)
|
||||
{
|
||||
uint32_t limit = std::stoul(params["limit"], nullptr);
|
||||
if (limit > 0 && limit <= TRANSIT_TUNNELS_LIMIT)
|
||||
i2p::tunnel::tunnels.SetMaxNumTransitTunnels (limit);
|
||||
SetMaxNumTransitTunnels (limit);
|
||||
else {
|
||||
s << "<b>" << tr("ERROR") << "</b>: " << tr("Transit tunnels count must not exceed %d", TRANSIT_TUNNELS_LIMIT) << "\r\n<br>\r\n<br>\r\n";
|
||||
s << "<a href=\"" << webroot << "?page=commands\">" << tr("Back to commands list") << "</a>\r\n<br>\r\n";
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace i2p
|
||||
ftruncate(pidFH, 0);
|
||||
if (write(pidFH, pid, strlen(pid)) < 0)
|
||||
{
|
||||
LogPrint(eLogCritical, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno));
|
||||
LogPrint(eLogError, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno));
|
||||
std::cerr << "i2pd: Could not write pidfile " << pidfile << ": " << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
32
debian/changelog
vendored
32
debian/changelog
vendored
@@ -1,38 +1,8 @@
|
||||
i2pd (2.48.0-1) unstable; urgency=high
|
||||
|
||||
* updated to version 2.48.0/0.9.59
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Mon, 12 Jun 2023 16:00:00 +0000
|
||||
|
||||
i2pd (2.47.0-1) unstable; urgency=high
|
||||
|
||||
* updated to version 2.47.0/0.9.58
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Sat, 11 Mar 2023 16:00:00 +0000
|
||||
|
||||
i2pd (2.46.1-2) unstable; urgency=critical
|
||||
|
||||
* re-pushed release due to new critical bug
|
||||
|
||||
-- r4sas <r4sas@i2pmail.org> Mon, 20 Feb 2023 23:40:00 +0000
|
||||
|
||||
i2pd (2.46.1-1) unstable; urgency=high
|
||||
|
||||
* updated to version 2.46.1/0.9.57
|
||||
|
||||
-- r4sas <r4sas@i2pmail.org> Mon, 20 Feb 2023 02:45:00 +0000
|
||||
|
||||
i2pd (2.46.0-1) unstable; urgency=high
|
||||
|
||||
* updated to version 2.46.0/0.9.57
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Wed, 15 Feb 2023 19:00:00 +0000
|
||||
|
||||
i2pd (2.45.1-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.45.1/0.9.57
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Wed, 11 Jan 2023 19:00:00 +0000
|
||||
-- orignal <orignal@i2pmail.org> Wed, 11 Jan 2023 19:00:00 +0000
|
||||
|
||||
i2pd (2.45.0-1) unstable; urgency=high
|
||||
|
||||
|
||||
2
debian/conffiles
vendored
Normal file
2
debian/conffiles
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/etc/i2pd/i2pd.conf
|
||||
/etc/i2pd/tunnels.conf
|
||||
2
debian/rules
vendored
2
debian/rules
vendored
@@ -8,6 +8,6 @@ export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic
|
||||
export DEB_LDFLAGS_MAINT_APPEND =
|
||||
|
||||
%:
|
||||
dh $@
|
||||
dh $@ --parallel
|
||||
|
||||
override_dh_auto_install:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -40,7 +40,6 @@ namespace armenian // language namespace
|
||||
{"established", "կարգավոյված է"},
|
||||
{"unknown", "անհայտ"},
|
||||
{"exploratory", "հետազոտոկան"},
|
||||
{"Purple I2P Webconsole", "Վեբ-կոնսոլ Purple I2P"},
|
||||
{"<b>i2pd</b> webconsole", "Վեբ-կոնսոլ <b>i2pd</b>"},
|
||||
{"Main page", "Գլխավոր էջ"},
|
||||
{"Router commands", "Երթուղիչի հրահանգներ"},
|
||||
@@ -58,10 +57,10 @@ namespace armenian // language namespace
|
||||
{"Unknown", "Անհայտ"},
|
||||
{"Proxy", "Պրոկսի"},
|
||||
{"Mesh", "MESH-ցանց"},
|
||||
{"Error", "Սխալ"},
|
||||
{"Clock skew", "Ոչ ճշգրիտ ժամանակ"},
|
||||
{"Offline", "Օֆլայն"},
|
||||
{"Symmetric NAT", "Սիմետրիկ NAT"},
|
||||
{"Full cone NAT", "Full cone NAT"},
|
||||
{"Uptime", "Առկայություն"},
|
||||
{"Network status", "Ցանցի կարգավիճակ"},
|
||||
{"Network status v6", "Ցանցի կարգավիճակ v6"},
|
||||
@@ -90,7 +89,7 @@ namespace armenian // language namespace
|
||||
{"Address registration line", "Հասցեի գրանցման տող"},
|
||||
{"Domain", "Տիրույթ"},
|
||||
{"Generate", "Գեներացնել"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Նշում. </b> արդյունքի տողը կարող է օգտագործվել միայն 2LD տիրույթներ գրանցելու համար (example.i2p): Ենթատիրույթներ գրանցելու համար խնդրում ենք օգտագործել i2pd-tools գործիքակազմը:"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Նշում. </b> արդյունքի տողը կարող է օգտագործվել միայն 2LD տիրույթներ գրանցելու համար (example.i2p): Ենթատիրույթներ գրանցելու համար խնդրում ենք օգտագործել i2pd-tools գործիքակազմը"},
|
||||
{"Address", "Հասցե"},
|
||||
{"Type", "Տեսակը"},
|
||||
{"EncType", "Գաղտնագրի տեսակը"},
|
||||
@@ -113,10 +112,11 @@ namespace armenian // language namespace
|
||||
{"Invalid", "Անվավեր"},
|
||||
{"Store type", "Պահեստավորման տեսակը"},
|
||||
{"Expires", "Սպառվում է"},
|
||||
{"Non Expired Leases", "Չսպառված Lease-եր"},
|
||||
{"Non Expired Leases", "Չսպառված Lease-եր"},
|
||||
{"Gateway", "Դարպաս"},
|
||||
{"TunnelID", "Թունելի ID"},
|
||||
{"EndDate", "Ավարտ"},
|
||||
{"not floodfill", "ոչ floodfill-ներ"},
|
||||
{"Queue size", "Հերթի չափսը"},
|
||||
{"Run peer test", "Գործարկել փորձարկումը"},
|
||||
{"Decline transit tunnels", "Մերժել տարանցիկ թունելներ"},
|
||||
@@ -146,7 +146,10 @@ namespace armenian // language namespace
|
||||
{"Destination not found", "Հասցեի վայրը չի գտնվել"},
|
||||
{"StreamID can't be null", "StreamID-ն չի կարող լինել դատարկ"},
|
||||
{"Return to destination page", "Վերադառնալ նախորդ էջի հասցե"},
|
||||
{"You will be redirected in 5 seconds", "Դուք կտեղափոխվեք 5 վայրկյանից"},
|
||||
{"Transit tunnels count must not exceed 65535", "Տարանցիկ թունելների քանակը չպետք է գերազանցի 65535-ը"},
|
||||
{"Back to commands list", "Վերադառնալ հրահանգների ցուցակ"},
|
||||
{"Register at reg.i2p", "Գրանցել reg.i2p-ում"},
|
||||
{"Description", "Նկարագրություն"},
|
||||
{"A bit information about service on domain", "Մի փոքր տեղեկատվություն տիրոիյթում գտնվող ծառայության մասին"},
|
||||
{"Submit", "Ուղարկվել"},
|
||||
@@ -162,26 +165,34 @@ namespace armenian // language namespace
|
||||
{"You may try to find this host on jump services below", "Ստորև Դուք կարող եք գտնել այս հոսթը jump ծառայությունների միջոցով"},
|
||||
{"Invalid request", "Սխալ հարցում"},
|
||||
{"Proxy unable to parse your request", "Պրոկսին չի կարող հասկանալ Ձեր հարցումը"},
|
||||
{"Invalid request URI", "Սխալ ձևավորված URI հարցում"},
|
||||
{"addresshelper is not supported", "addresshelper-ը համատեղելի չէ"},
|
||||
{"Host", "Հոսթ"},
|
||||
{"added to router's addressbook from helper", "Ավելացված է երթուղիչի հասցեագրքում helper-ի միջոցով"},
|
||||
{"Click here to proceed:", "Շարունակելու համար սեղմեք այստեղ"},
|
||||
{"Continue", "Շարունակել"},
|
||||
{"Addresshelper found", "addresshelper-ը գնտված է"},
|
||||
{"already in router's addressbook", "արդեն առկա է երթուղիչի հասցեագրքում"},
|
||||
{"Click here to update record:", "Սեղմեկ այստեղ որպեսզի թարվացնեք գրառումը"},
|
||||
{"invalid request uri", "Սխալ ձևավորված URI հարցում"},
|
||||
{"Can't detect destination host from request", "Չհաջողվեց հայնտաբերեկ վայրի հասցեն նշված հարցմամբ"},
|
||||
{"Outproxy failure", "Սխալ արտաքին պրոքսի"},
|
||||
{"Bad outproxy settings", "Սխալ արտաքին պրոկսի կարգավորումներ"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Հոսթ %s Հարցումը I2P ցանցից դուրս է, բայց արտաքին պրոքսին միացված չէ"},
|
||||
{"Unknown outproxy URL", "Արտաքին պրոքսիի անհայտ URL"},
|
||||
{"Cannot resolve upstream proxy", "Չհաջողվեց որոշել վերադաս պրոկսին"},
|
||||
{"Hostname is too long", "Հոսթի անունը չափազանց երկար է"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Չհաջողվեց միանալ վերադաս SOCKS պրոկսի սերվերին"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Չհաջողվեց պայմանավորվել վերադաս SOCKS պրոկսիի հետ"},
|
||||
{"bad outproxy settings", "Սխալ արտաքին պրոկսի կարգավորումներ"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "Հարցումը I2P ցանցից դուրս է, բայց արտաքին պրոքսին միացված չէ"},
|
||||
{"unknown outproxy url", "արտաքին պրոքսիի անհայտ URL"},
|
||||
{"cannot resolve upstream proxy", "Չհաջողվեց որոշել վերադաս պրոկսին"},
|
||||
{"hostname too long", "Հոսթի անունը չափազանց երկար է"},
|
||||
{"cannot connect to upstream socks proxy", "չհաջողվեց միանալ վերադաս socks պրոկսիին"},
|
||||
{"Cannot negotiate with socks proxy", "Չհաջողվեց պայմանավորվել վերադաս socks պրոկսիի հետ"},
|
||||
{"CONNECT error", "Սխալ CONNECT հարցում"},
|
||||
{"Failed to connect", "Միանալ չhաջողվեց"},
|
||||
{"SOCKS proxy error", "Սխալ SOCKS պրոկսի"},
|
||||
{"Failed to send request to upstream", "Չհաջողվեց հարցումն ուղարկել վերադաս պրոկսիին"},
|
||||
{"No reply from SOCKS proxy", "Բացակայում է պատասխանը SOCKS պրոկսի սերվերի կողմից"},
|
||||
{"Cannot connect", "Հնարավոր չե միանալ"},
|
||||
{"HTTP out proxy not implemented", "Արտաքին HTTP պրոկսին դեռ իրականացված չէ"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Չհաջողվեց միանալ վերադաս HTTP պրոկսի սերվերին"},
|
||||
{"Failed to Connect", "Միանալ չhաջողվեց"},
|
||||
{"socks proxy error", "Սխալ SOCKS պրոկսի"},
|
||||
{"failed to send request to upstream", "Չհաջողվեց հարցումն ուղարկել վերադաս պրոկսիին"},
|
||||
{"No Reply From socks proxy", "Բացակայում է պատասխանը SOCKS պրոկսի սերվերի կողմից"},
|
||||
{"cannot connect", "Հնարավոր չե միանալ"},
|
||||
{"http out proxy not implemented", "Արտաքին http պրոկսին դեռ իրականացված չէ"},
|
||||
{"cannot connect to upstream http proxy", "Չհաջողվեց միանալ վերադաս http պրոկսի սերվերին"},
|
||||
{"Host is down", "Հոսթն անհասանելի է"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Հոսթի հետ կապը հաստատել չհաջողվեց, հնարավոր է այն անջատված է, փորձեք միանալ քիչ ուշ:"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Հոսթի հետ կապը հաստատել չհաջողվեց, հնարավոր է այն անջատված է, փորձեք միանալ քիչ ուշ"},
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "I18N.h"
|
||||
|
||||
// Simplified Chinese localization file
|
||||
// This is an example translation file without strings in it.
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
@@ -45,7 +46,7 @@ namespace chinese // language namespace
|
||||
{"Main page", "主页"},
|
||||
{"Router commands", "路由命令"},
|
||||
{"Local Destinations", "本地目标"},
|
||||
{"LeaseSets", "租约集"},
|
||||
{"LeaseSets", "租契集"},
|
||||
{"Tunnels", "隧道"},
|
||||
{"Transit Tunnels", "中转隧道"},
|
||||
{"Transports", "传输"},
|
||||
@@ -57,12 +58,11 @@ namespace chinese // language namespace
|
||||
{"Firewalled", "受到防火墙限制"},
|
||||
{"Unknown", "未知"},
|
||||
{"Proxy", "代理"},
|
||||
{"Mesh", "自组网"},
|
||||
{"Mesh", "Mesh组网"},
|
||||
{"Error", "错误"},
|
||||
{"Clock skew", "时钟偏移"},
|
||||
{"Offline", "离线"},
|
||||
{"Symmetric NAT", "对称 NAT"},
|
||||
{"Full cone NAT", "全锥型NAT"},
|
||||
{"No Descriptors", "无描述符"},
|
||||
{"Uptime", "运行时间"},
|
||||
{"Network status", "IPv4 网络状态"},
|
||||
{"Network status v6", "IPv6 网络状态"},
|
||||
@@ -91,12 +91,12 @@ namespace chinese // language namespace
|
||||
{"Address registration line", "地址域名注册"},
|
||||
{"Domain", "域名"},
|
||||
{"Generate", "生成"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>注意:</b> 结果字符串只能用于注册二级域名(例如:example.i2p)。若需注册三级域名,请使用 i2pd-tools。"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>注意:</b> 结果字符串只能用于注册次级域名(例如:example.i2p)。若需注册子域名,请使用 i2pd-tools。"},
|
||||
{"Address", "地址"},
|
||||
{"Type", "类型"},
|
||||
{"EncType", "加密类型"},
|
||||
{"Inbound tunnels", "入站隧道"},
|
||||
{"%dms", "%dms"},
|
||||
{"%dms", "%d毫秒"},
|
||||
{"Outbound tunnels", "出站隧道"},
|
||||
{"Tags", "标签"},
|
||||
{"Incoming", "传入"},
|
||||
@@ -109,7 +109,6 @@ namespace chinese // language namespace
|
||||
{"Local Destination", "本地目标"},
|
||||
{"Streams", "流"},
|
||||
{"Close stream", "断开流"},
|
||||
{"Such destination is not found", "找不到此目标"},
|
||||
{"I2CP session not found", "未找到 I2CP 会话"},
|
||||
{"I2CP is not enabled", "I2CP 未启用"},
|
||||
{"Invalid", "无效"},
|
||||
@@ -119,10 +118,9 @@ namespace chinese // language namespace
|
||||
{"Gateway", "网关"},
|
||||
{"TunnelID", "隧道 ID"},
|
||||
{"EndDate", "结束日期"},
|
||||
{"floodfill mode is disabled", "洪泛已禁用"},
|
||||
{"not floodfill", "非洪泛"},
|
||||
{"Queue size", "队列大小"},
|
||||
{"Run peer test", "运行节点测试"},
|
||||
{"Reload tunnels configuration", "重新载入隧道配置"},
|
||||
{"Decline transit tunnels", "拒绝中转隧道"},
|
||||
{"Accept transit tunnels", "允许中转隧道"},
|
||||
{"Cancel graceful shutdown", "取消平滑关闭"},
|
||||
@@ -130,7 +128,7 @@ namespace chinese // language namespace
|
||||
{"Force shutdown", "强制停止"},
|
||||
{"Reload external CSS styles", "重载外部 CSS 样式"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>注意:</b> 此处完成的任何操作都不是永久的,不会更改您的配置文件。"},
|
||||
{"Logging level", "日志级别"},
|
||||
{"Logging level", "日志记录级别"},
|
||||
{"Transit tunnels limit", "中转隧道限制"},
|
||||
{"Change", "修改"},
|
||||
{"Change language", "更改语言"},
|
||||
@@ -150,8 +148,8 @@ namespace chinese // language namespace
|
||||
{"Destination not found", "找不到目标"},
|
||||
{"StreamID can't be null", "StreamID 不能为空"},
|
||||
{"Return to destination page", "返回目标页面"},
|
||||
{"You will be redirected in %d seconds", "您将在%d秒内被重定向"},
|
||||
{"Transit tunnels count must not exceed %d", "中转隧道数量限制为 %d"},
|
||||
{"You will be redirected in 5 seconds", "您将在5秒内被重定向"},
|
||||
{"Transit tunnels count must not exceed 65535", "中转隧道数量不能超过 65535"},
|
||||
{"Back to commands list", "返回命令列表"},
|
||||
{"Register at reg.i2p", "在 reg.i2p 注册域名"},
|
||||
{"Description", "描述"},
|
||||
@@ -159,42 +157,42 @@ namespace chinese // language namespace
|
||||
{"Submit", "提交"},
|
||||
{"Domain can't end with .b32.i2p", "域名不能以 .b32.i2p 结尾"},
|
||||
{"Domain must end with .i2p", "域名必须以 .i2p 结尾"},
|
||||
{"Such destination is not found", "找不到此目标"},
|
||||
{"Unknown command", "未知指令"},
|
||||
{"Command accepted", "已接受指令"},
|
||||
{"Proxy error", "代理错误"},
|
||||
{"Proxy info", "代理信息"},
|
||||
{"Proxy error: Host not found", "代理错误:未找到主机"},
|
||||
{"Remote host not found in router's addressbook", "在路由地址簿中未找到远程主机"},
|
||||
{"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务中找到此主机"},
|
||||
{"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务中找到该主机"},
|
||||
{"Invalid request", "无效请求"},
|
||||
{"Proxy unable to parse your request", "代理无法解析您的请求"},
|
||||
{"Addresshelper is not supported", "不支持地址助手"},
|
||||
{"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>.", "主机 %s <font color=red>已在路由地址簿中</font>。<b>请注意:此地址的来源可能是有害的!</b>点击此处更新记录:<a href=\"%s%s%s&update=true\">继续</a>"},
|
||||
{"Addresshelper forced update rejected", "地址助手强制更新被拒绝"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "若要在路由器地址簿中添加主机 <b>%s</b> 请点击这里: <a href=\"%s%s%s\">继续</a>"},
|
||||
{"Addresshelper request", "请求地址助手"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "主机 %s 已通过地址助手添加到路由地址簿中。点击此处继续:<a href=\"%s\">继续</a>"},
|
||||
{"Addresshelper adding", "正在添加地址助手"},
|
||||
{"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>.", "主机 %s <font color=red>已在路由地址簿中</font>。点击此处更新记录:<a href=\"%s%s%s&update=true\">继续</a>"},
|
||||
{"Addresshelper update", "更新地址助手"},
|
||||
{"Invalid request URI", "无效的 URI 请求"},
|
||||
{"addresshelper is not supported", "不支持地址助手"},
|
||||
{"Host", "主机"},
|
||||
{"added to router's addressbook from helper", "将此地址从地址助手添加到路由地址簿"},
|
||||
{"Click here to proceed:", "点击此处继续:"},
|
||||
{"Continue", "继续"},
|
||||
{"Addresshelper found", "已找到地址助手"},
|
||||
{"already in router's addressbook", "已在路由地址簿中"},
|
||||
{"Click here to update record:", "点击此处更新地址簿记录"},
|
||||
{"invalid request uri", "无效的 URL 请求"},
|
||||
{"Can't detect destination host from request", "无法从请求中检测到目标主机"},
|
||||
{"Outproxy failure", "出口代理故障"},
|
||||
{"Bad outproxy settings", "错误的出口代理设置"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "主机 %s 不在 I2P 网络内,但出口代理未启用"},
|
||||
{"Unknown outproxy URL", "未知的出口代理地址"},
|
||||
{"Cannot resolve upstream proxy", "无法解析上游代理"},
|
||||
{"Hostname is too long", "主机名过长"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "无法连接到上游 SOCKS 代理"},
|
||||
{"Cannot negotiate with SOCKS proxy", "无法与 SOCKS 代理协商"},
|
||||
{"bad outproxy settings", "错误的出口代理设置"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "该地址不在 I2P 网络内,但未启用出口代理"},
|
||||
{"unknown outproxy url", "未知的出口代理地址"},
|
||||
{"cannot resolve upstream proxy", "无法解析上游代理"},
|
||||
{"hostname too long", "主机名过长"},
|
||||
{"cannot connect to upstream socks proxy", "无法连接到上游 socks 代理"},
|
||||
{"Cannot negotiate with socks proxy", "无法与 socks 代理协商"},
|
||||
{"CONNECT error", "连接错误"},
|
||||
{"Failed to connect", "连接失败"},
|
||||
{"SOCKS proxy error", "SOCKS 代理错误"},
|
||||
{"Failed to send request to upstream", "向上游发送请求失败"},
|
||||
{"No reply from SOCKS proxy", "没有来自 SOCKS 代理的回复"},
|
||||
{"Cannot connect", "无法连接"},
|
||||
{"HTTP out proxy not implemented", "HTTP 出口代理未实现"},
|
||||
{"Cannot connect to upstream HTTP proxy", "无法连接到上游 HTTP 代理"},
|
||||
{"Failed to Connect", "连接失败"},
|
||||
{"socks proxy error", "socks 代理错误"},
|
||||
{"failed to send request to upstream", "向上游发送请求失败"},
|
||||
{"No Reply From socks proxy", "没有来自 socks 代理的回复"},
|
||||
{"cannot connect", "无法连接"},
|
||||
{"http out proxy not implemented", "http 出口代理未实现"},
|
||||
{"cannot connect to upstream http proxy", "无法连接到上游 http 代理"},
|
||||
{"Host is down", "主机已关闭"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "无法创建到目标主机的连接。主机可能已下线,请稍后再试。"},
|
||||
{"", ""},
|
||||
@@ -202,9 +200,9 @@ namespace chinese // language namespace
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"%d days", {"%d 天"}},
|
||||
{"%d hours", {"%d 小时"}},
|
||||
{"%d minutes", {"%d 分钟"}},
|
||||
{"%d days", {"%d 日"}},
|
||||
{"%d hours", {"%d 时"}},
|
||||
{"%d minutes", {"%d 分"}},
|
||||
{"%d seconds", {"%d 秒"}},
|
||||
{"", {""}},
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -58,6 +58,7 @@ namespace czech // language namespace
|
||||
{"Unknown", "Neznámý"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Síť"},
|
||||
{"Error", "Chyba"},
|
||||
{"Clock skew", "Časová nesrovnalost"},
|
||||
{"Offline", "Offline"},
|
||||
{"Symmetric NAT", "Symetrický NAT"},
|
||||
@@ -116,6 +117,7 @@ namespace czech // language namespace
|
||||
{"Gateway", "Brána"},
|
||||
{"TunnelID", "ID tunelu"},
|
||||
{"EndDate", "Datum ukončení"},
|
||||
{"not floodfill", "není floodfill"},
|
||||
{"Queue size", "Velikost fronty"},
|
||||
{"Run peer test", "Spustit peer test"},
|
||||
{"Decline transit tunnels", "Odmítnout tranzitní tunely"},
|
||||
@@ -145,6 +147,8 @@ namespace czech // language namespace
|
||||
{"Destination not found", "Destinace nenalezena"},
|
||||
{"StreamID can't be null", "StreamID nemůže být null"},
|
||||
{"Return to destination page", "Zpět na stránku destinací"},
|
||||
{"You will be redirected in 5 seconds", "Budete přesměrováni za 5 vteřin"},
|
||||
{"Transit tunnels count must not exceed 65535", "Počet tranzitních tunelů nesmí přesáhnout 65535"},
|
||||
{"Back to commands list", "Zpět na list příkazů"},
|
||||
{"Register at reg.i2p", "Zaregistrovat na reg.i2p"},
|
||||
{"Description", "Popis"},
|
||||
@@ -162,24 +166,32 @@ 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"},
|
||||
{"Invalid request", "Neplatný požadavek"},
|
||||
{"Proxy unable to parse your request", "Proxy server nemohl zpracovat váš požadavek"},
|
||||
{"Invalid request URI", "Neplatný URI požadavek"},
|
||||
{"addresshelper is not supported", "Adresshelper není podporován"},
|
||||
{"Host", "Hostitel"},
|
||||
{"added to router's addressbook from helper", "přidáno do adresáře routeru od pomocníka"},
|
||||
{"Click here to proceed:", "Pro pokračování, klikněte zde:"},
|
||||
{"Continue", "Pokračovat"},
|
||||
{"Addresshelper found", "Adresář nalezen"},
|
||||
{"already in router's addressbook", "je již v adresáři routeru"},
|
||||
{"Click here to update record:", "Pro aktualizaci záznamu, klikněte zde:"},
|
||||
{"invalid request uri", "neplatný URI požadavek"},
|
||||
{"Can't detect destination host from request", "Nelze zjistit cílového hostitele z požadavku"},
|
||||
{"Outproxy failure", "Outproxy selhání"},
|
||||
{"Bad outproxy settings", "Špatné outproxy nastavení"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Hostitel %s není uvnitř I2P sítě a outproxy není nastavena"},
|
||||
{"Unknown outproxy URL", "Neznámá outproxy URL"},
|
||||
{"Cannot resolve upstream proxy", "Nelze rozluštit upstream proxy server"},
|
||||
{"Hostname is too long", "Název hostitele je příliš dlouhý"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Nelze se připojit k upstream SOCKS proxy serveru"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Nelze vyjednávat se SOCKS proxy serverem"},
|
||||
{"bad outproxy settings", "špatné outproxy nastavení"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "není uvnitř I2P sítě a outproxy není nastavena"},
|
||||
{"unknown outproxy url", "neznámá outproxy URL"},
|
||||
{"cannot resolve upstream proxy", "nelze rozluštit upstream proxy server"},
|
||||
{"hostname too long", "Název hostitele je příliš dlouhý"},
|
||||
{"cannot connect to upstream socks proxy", "nelze se připojit k upstream socks proxy serveru"},
|
||||
{"Cannot negotiate with socks proxy", "Nelze vyjednávat se socks proxy serverem"},
|
||||
{"CONNECT error", "Chyba PŘIPOJENÍ"},
|
||||
{"Failed to connect", "Připojení se nezdařilo"},
|
||||
{"SOCKS proxy error", "Chyba SOCKS proxy serveru"},
|
||||
{"Failed to send request to upstream", "Odeslání žádosti upstream serveru se nezdařilo"},
|
||||
{"No reply from SOCKS proxy", "Žádná odpověď od SOCKS proxy serveru"},
|
||||
{"Cannot connect", "Nelze se připojit"},
|
||||
{"HTTP out proxy not implemented", "HTTP out proxy není implementován"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Nelze se připojit k upstream HTTP proxy serveru"},
|
||||
{"Failed to Connect", "Připojení se nezdařilo"},
|
||||
{"socks proxy error", "chyba socks proxy serveru"},
|
||||
{"failed to send request to upstream", "odeslání žádosti upstream serveru se nezdařilo"},
|
||||
{"No Reply From socks proxy", "Žádná odpověď od socks proxy serveru"},
|
||||
{"cannot connect", "nelze se připojit"},
|
||||
{"http out proxy not implemented", "http out proxy není implementován"},
|
||||
{"cannot connect to upstream http proxy", "nelze se připojit k upstream socks proxy serveru"},
|
||||
{"Host is down", "Hostitel je nedostupný"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Připojení k požadovanému hostiteli nelze vytvořit, může být nedostupný. Zkuste to, prosím, znovu později."},
|
||||
{"", ""},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -58,20 +58,18 @@ namespace french // language namespace
|
||||
{"Unknown", "Inconnu"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Maillé"},
|
||||
{"Error", "Erreur"},
|
||||
{"Clock skew", "Horloge décalée"},
|
||||
{"Offline", "Hors ligne"},
|
||||
{"Symmetric NAT", "NAT symétrique"},
|
||||
{"Full cone NAT", "NAT à cône complet"},
|
||||
{"No Descriptors", "Aucuns Descripteurs"},
|
||||
{"Uptime", "Temps de fonctionnement"},
|
||||
{"Network status", "État du réseau"},
|
||||
{"Network status v6", "État du réseau v6"},
|
||||
{"Stopping in", "Arrêt dans"},
|
||||
{"Family", "Famille"},
|
||||
{"Tunnel creation success rate", "Taux de succès de création de tunnels"},
|
||||
{"Total tunnel creation success rate", "Taux de réussite de création de tunnel"},
|
||||
{"Received", "Reçu"},
|
||||
{"%.2f KiB/s", "%.2f Kio/s"},
|
||||
{"%.2f KiB/s", "%.2f kio/s"},
|
||||
{"Sent", "Envoyé"},
|
||||
{"Transit", "Transité"},
|
||||
{"Data path", "Emplacement des données"},
|
||||
@@ -83,7 +81,6 @@ namespace french // language namespace
|
||||
{"Our external address", "Notre adresse externe"},
|
||||
{"supported", "supporté"},
|
||||
{"Routers", "Routeurs"},
|
||||
{"Floodfills", "Remplisseurs"},
|
||||
{"Client Tunnels", "Tunnels clients"},
|
||||
{"Services", "Services"},
|
||||
{"Enabled", "Activé"},
|
||||
@@ -92,11 +89,9 @@ namespace french // language namespace
|
||||
{"Address registration line", "Ligne d'inscription de l'adresse"},
|
||||
{"Domain", "Domaine"},
|
||||
{"Generate", "Générer"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note :</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note:</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."},
|
||||
{"Address", "Adresse"},
|
||||
{"Type", "Type"},
|
||||
{"EncType", "EncType"},
|
||||
{"Expire LeaseSet", "Expiration du LeaseSet"},
|
||||
{"Inbound tunnels", "Tunnels entrants"},
|
||||
{"%dms", "%dms"},
|
||||
{"Outbound tunnels", "Tunnels sortants"},
|
||||
@@ -111,7 +106,6 @@ namespace french // language namespace
|
||||
{"Local Destination", "Destination locale"},
|
||||
{"Streams", "Flux"},
|
||||
{"Close stream", "Fermer le flux"},
|
||||
{"Such destination is not found", "Cette destination est introuvable"},
|
||||
{"I2CP session not found", "Session I2CP introuvable"},
|
||||
{"I2CP is not enabled", "I2CP est désactivé"},
|
||||
{"Invalid", "Invalide"},
|
||||
@@ -121,17 +115,15 @@ namespace french // language namespace
|
||||
{"Gateway", "Passerelle"},
|
||||
{"TunnelID", "ID du tunnel"},
|
||||
{"EndDate", "Date de fin"},
|
||||
{"floodfill mode is disabled", "le mode de remplissage est désactivé"},
|
||||
{"Queue size", "Longueur de la file"},
|
||||
{"Run peer test", "Lancer test des pairs"},
|
||||
{"Reload tunnels configuration", "Recharger la configuration des tunnels"},
|
||||
{"Decline transit tunnels", "Refuser les tunnels transitoires"},
|
||||
{"Accept transit tunnels", "Accepter les tunnels transitoires"},
|
||||
{"Cancel graceful shutdown", "Annuler l'arrêt gracieux"},
|
||||
{"Start graceful shutdown", "Démarrer l'arrêt gracieux"},
|
||||
{"Force shutdown", "Forcer l'arrêt"},
|
||||
{"Reload external CSS styles", "Rafraîchir les styles CSS externes"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Note :</b> Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Note:</b> Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."},
|
||||
{"Logging level", "Niveau de journalisation"},
|
||||
{"Transit tunnels limit", "Limite sur les tunnels transitoires"},
|
||||
{"Change", "Changer"},
|
||||
@@ -142,8 +134,6 @@ namespace french // language namespace
|
||||
{"SAM session not found", "session SAM introuvable"},
|
||||
{"SAM Session", "Session SAM"},
|
||||
{"Server Tunnels", "Tunnels serveurs"},
|
||||
{"Client Forwards", "Transmission du client"},
|
||||
{"Server Forwards", "Transmission du serveur"},
|
||||
{"Unknown page", "Page inconnue"},
|
||||
{"Invalid token", "Jeton invalide"},
|
||||
{"SUCCESS", "SUCCÈS"},
|
||||
@@ -152,10 +142,8 @@ namespace french // language namespace
|
||||
{"Destination not found", "Destination introuvable"},
|
||||
{"StreamID can't be null", "StreamID ne peut pas être vide"},
|
||||
{"Return to destination page", "Retourner à la page de destination"},
|
||||
{"You will be redirected in %d seconds", "Vous serez redirigé dans %d secondes"},
|
||||
{"LeaseSet expiration time updated", "Temps d'expiration du LeaseSet mis à jour"},
|
||||
{"LeaseSet is not found or already expired", "Le LeaseSet est introuvable ou a déjà expirée"},
|
||||
{"Transit tunnels count must not exceed %d", "Le nombre de tunnels de transit ne doit pas excéder %d"},
|
||||
{"You will be redirected in 5 seconds", "Vous allez être redirigé dans cinq secondes"},
|
||||
{"Transit tunnels count must not exceed 65535", "Le nombre de tunnels transitoires ne doit pas dépasser 65535"},
|
||||
{"Back to commands list", "Retour à la liste des commandes"},
|
||||
{"Register at reg.i2p", "Inscription à reg.i2p"},
|
||||
{"Description", "Description"},
|
||||
@@ -163,42 +151,42 @@ namespace french // language namespace
|
||||
{"Submit", "Soumettre"},
|
||||
{"Domain can't end with .b32.i2p", "Le domaine ne peut pas terminer par .b32.i2p"},
|
||||
{"Domain must end with .i2p", "Le domaine doit terminer par .i2p"},
|
||||
{"Such destination is not found", "Cette destination est introuvable"},
|
||||
{"Unknown command", "Commande inconnue"},
|
||||
{"Command accepted", "Commande acceptée"},
|
||||
{"Proxy error", "Erreur de proxy"},
|
||||
{"Proxy info", "Information sur le proxy"},
|
||||
{"Proxy error: Host not found", "Erreur de proxy : Hôte introuvable"},
|
||||
{"Proxy error: Host not found", "Erreur de proxy: Hôte introuvable"},
|
||||
{"Remote host not found in router's addressbook", "Hôte distant introuvable dans le carnet d'adresse du routeur"},
|
||||
{"You may try to find this host on jump services below", "Vous pouvez essayer de trouver cet hôte sur des services de redirection ci-dessous"},
|
||||
{"Invalid request", "Requête invalide"},
|
||||
{"Proxy unable to parse your request", "Proxy incapable de comprendre votre requête"},
|
||||
{"Addresshelper is not supported", "Assistant d'adresse non supporté"},
|
||||
{"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>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. <b>Attention : la source de cette URL peut être nuisible !</b> Cliquez ici pour mettre à jour l'enregistrement : <a href=\"%s%s%s&update=true\">Continuer</a>."},
|
||||
{"Addresshelper forced update rejected", "Mise à jour forcée des assistants d'adresses rejetée"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Pour ajouter l'hôte <b>%s</b> au carnet d'adresses du routeur, cliquez ici : <a href=\"%s%s%s\">Continuer</a>."},
|
||||
{"Addresshelper request", "Demande à l'assistant d'adresse"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "L'hôte %s a été ajouté au carnet d'adresses du routeur depuis l'assistant. Cliquez ici pour continuer : <a href=\"%s\">Continuer</a>."},
|
||||
{"Addresshelper adding", "Ajout de l'assistant d'adresse"},
|
||||
{"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>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. Cliquez ici pour mettre à jour le dossier : <a href=\"%s%s%s&update=true\">Continuer</a>."},
|
||||
{"Addresshelper update", "Mise à jour de l'assistant d'adresse"},
|
||||
{"Invalid request URI", "URI de la requête invalide"},
|
||||
{"addresshelper is not supported", "Assistant d'adresse non supporté"},
|
||||
{"Host", "Hôte"},
|
||||
{"added to router's addressbook from helper", "Ajouté au carnet d'adresse du routeur par l'assistant"},
|
||||
{"Click here to proceed:", "Cliquez ici pour continuer:"},
|
||||
{"Continue", "Continuer"},
|
||||
{"Addresshelper found", "Assistant d'adresse trouvé"},
|
||||
{"already in router's addressbook", "déjà dans le carnet d'adresses du routeur"},
|
||||
{"Click here to update record:", "Cliquez ici pour mettre à jour le carnet d'adresse:"},
|
||||
{"invalid request uri", "uri de la requête invalide"},
|
||||
{"Can't detect destination host from request", "Impossible de détecter l'hôte de destination à partir de la requête"},
|
||||
{"Outproxy failure", "Échec de proxy de sortie"},
|
||||
{"Bad outproxy settings", "Mauvaise configuration du proxy de sortie"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Hôte %s pas dans le réseau I2P, mais le proxy de sortie n'est pas activé"},
|
||||
{"Unknown outproxy URL", "URL du proxy de sortie inconnu"},
|
||||
{"Cannot resolve upstream proxy", "Impossible de résoudre l'adresse du proxy en amont"},
|
||||
{"Hostname is too long", "Nom d'hôte trop long"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Impossible de se connecter au proxy SOCKS en amont"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Impossible de négocier avec le proxy SOCKS"},
|
||||
{"bad outproxy settings", "Mauvaise configuration du proxy de sortie"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "pas dans le réseau I2P, mais le proxy de sortie n'est pas activé"},
|
||||
{"unknown outproxy url", "URL du proxy de sortie inconnu"},
|
||||
{"cannot resolve upstream proxy", "impossible de résoudre l'adresse du proxy en amont"},
|
||||
{"hostname too long", "nom d'hôte trop long"},
|
||||
{"cannot connect to upstream socks proxy", "impossible de se connecter au proxy socks en amont"},
|
||||
{"Cannot negotiate with socks proxy", "Impossible de négocier avec le proxy socks"},
|
||||
{"CONNECT error", "Erreur de connexion"},
|
||||
{"Failed to connect", "Échec de connexion"},
|
||||
{"SOCKS proxy error", "Erreur de proxy SOCKS"},
|
||||
{"Failed to send request to upstream", "Erreur lors de l'envoie de la requête en amont"},
|
||||
{"No reply from SOCKS proxy", "Pas de réponse du proxy SOCKS"},
|
||||
{"Cannot connect", "Impossible de connecter"},
|
||||
{"HTTP out proxy not implemented", "Proxy de sortie HTTP non implémenté"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Impossible de se connecter au proxy HTTP en amont"},
|
||||
{"Failed to Connect", "Échec de connexion"},
|
||||
{"socks proxy error", "Erreur de proxy socks"},
|
||||
{"failed to send request to upstream", "Erreur lors de l'envoie de la requête en amont"},
|
||||
{"No Reply From socks proxy", "Pas de réponse du proxy socks"},
|
||||
{"cannot connect", "impossible de connecter"},
|
||||
{"http out proxy not implemented", "Proxy de sortie HTTP non implémenté"},
|
||||
{"cannot connect to upstream http proxy", "impossible de se connecter au proxy HTTP en amont"},
|
||||
{"Host is down", "Hôte hors service"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Impossible d'établir une connexion avec l'hôte, il est peut-être hors service. Veuillez réessayer plus tard."},
|
||||
{"", ""},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -58,10 +58,10 @@ namespace german // language namespace
|
||||
{"Unknown", "Unbekannt"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Mesh"},
|
||||
{"Error", "Fehler"},
|
||||
{"Clock skew", "Zeitabweichung"},
|
||||
{"Offline", "Offline"},
|
||||
{"Symmetric NAT", "Symmetrisches NAT"},
|
||||
{"No Descriptors", "Keine Beschreibungen"},
|
||||
{"Uptime", "Laufzeit"},
|
||||
{"Network status", "Netzwerkstatus"},
|
||||
{"Network status v6", "Netzwerkstatus v6"},
|
||||
@@ -117,10 +117,9 @@ namespace german // language namespace
|
||||
{"Gateway", "Gateway"},
|
||||
{"TunnelID", "TunnelID"},
|
||||
{"EndDate", "Enddatum"},
|
||||
{"floodfill mode is disabled", "Floodfill Modus ist deaktiviert"},
|
||||
{"not floodfill", "kein Floodfill"},
|
||||
{"Queue size", "Größe der Warteschlange"},
|
||||
{"Run peer test", "Peer-Test durchführen"},
|
||||
{"Reload tunnels configuration", "Tunnel Konfiguration neu laden"},
|
||||
{"Decline transit tunnels", "Transittunnel ablehnen"},
|
||||
{"Accept transit tunnels", "Transittunnel akzeptieren"},
|
||||
{"Cancel graceful shutdown", "Beende das kontrollierte Herunterfahren"},
|
||||
@@ -148,8 +147,8 @@ namespace german // language namespace
|
||||
{"Destination not found", "Ziel nicht gefunden"},
|
||||
{"StreamID can't be null", "StreamID kann nicht null sein"},
|
||||
{"Return to destination page", "Zurück zur Ziel-Seite"},
|
||||
{"You will be redirected in %d seconds", "Du wirst umgeleitet in %d Sekunden"},
|
||||
{"Transit tunnels count must not exceed %d", "Die Anzahl der Transittunnel darf nicht über %d gehen"},
|
||||
{"You will be redirected in 5 seconds", "Du wirst in 5 Sekunden weitergeleitet"},
|
||||
{"Transit tunnels count must not exceed 65535", "Es darf maximal 65535 Transittunnel geben"},
|
||||
{"Back to commands list", "Zurück zur Befehlsliste"},
|
||||
{"Register at reg.i2p", "Auf reg.i2p registrieren"},
|
||||
{"Description", "Beschreibung"},
|
||||
@@ -167,33 +166,32 @@ namespace german // language namespace
|
||||
{"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einem der nachfolgenden Jump-Services finden"},
|
||||
{"Invalid request", "Ungültige Anfrage"},
|
||||
{"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht verarbeiten"},
|
||||
{"Addresshelper is not supported", "Adresshelfer wird nicht unterstützt"},
|
||||
{"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 ist <font color=red>bereits im Adressbuch des Routers</font>. <b>Vorsicht: Die Quelle dieser URL kann schädlich sein!</b> Klicken Sie hier, um den Datensatz zu aktualisieren: <a href=\"%s%s%s&update=true\">Weiter</a>."},
|
||||
{"Addresshelper forced update rejected", "Adresshelfer gezwungene Aktualisierung abgelehnt"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Um den Host <b>%s</b> im Adressbuch des Routers hinzuzufügen, klicken Sie hier: <a href=\"%s%s%s\">Weiter</a>."},
|
||||
{"Addresshelper request", "Adresshelfer gefunden"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Host %s wurde vom Helfer zum Adressbuch des Routers hinzugefügt. Klicken Sie hier, um fortzufahren: <a href=\"%s\">Weiter</a>."},
|
||||
{"Addresshelper adding", "Adresshelfer hinzufügen"},
|
||||
{"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 ist <font color=red>bereits im Adressbuch des Routers</font>. Klicken Sie hier, um den Eintrag zu aktualisieren: <a href=\"%s%s%s&update=true\">Weiter</a>."},
|
||||
{"Addresshelper update", "Adresshelfer aktualisieren"},
|
||||
{"Invalid request URI", "Ungültige Anfrage-URI"},
|
||||
{"addresshelper is not supported", "Addresshelfer wird nicht unterstützt"},
|
||||
{"Host", "Host"},
|
||||
{"added to router's addressbook from helper", "vom Helfer zum Router-Adressbuch hinzugefügt"},
|
||||
{"Click here to proceed:", "Klicke hier um fortzufahren:"},
|
||||
{"Continue", "Fortsetzen"},
|
||||
{"Addresshelper found", "Adresshelfer gefunden"},
|
||||
{"already in router's addressbook", "bereits im Adressbuch des Routers"},
|
||||
{"Click here to update record:", "Klicke hier, um den Eintrag zu aktualisieren:"},
|
||||
{"invalid request uri", "ungültige Anfrage-URI"},
|
||||
{"Can't detect destination host from request", "Kann den Ziel-Host von der Anfrage nicht erkennen"},
|
||||
{"Outproxy failure", "Outproxy-Fehler"},
|
||||
{"Bad outproxy settings", "Ungültige Outproxy-Einstellungen"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Host %s außerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"},
|
||||
{"Unknown outproxy URL", "Unbekannte Outproxy-URL"},
|
||||
{"Cannot resolve upstream proxy", "Kann den Upstream-Proxy nicht auflösen"},
|
||||
{"Hostname is too long", "Hostname zu lang"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Kann keine Verbindung zum Upstream-SOCKS-Proxy herstellen"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Kann nicht mit SOCKS-Proxy verhandeln"},
|
||||
{"bad outproxy settings", "ungültige Outproxy-Einstellungen"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "außerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"},
|
||||
{"unknown outproxy url", "unbekannte Outproxy-URL"},
|
||||
{"cannot resolve upstream proxy", "kann den Upstream-Proxy nicht auflösen"},
|
||||
{"hostname too long", "Hostname zu lang"},
|
||||
{"cannot connect to upstream socks proxy", "Kann keine Verbindung zum Upstream-Socks-Proxy herstellen"},
|
||||
{"Cannot negotiate with socks proxy", "Kann nicht mit Socks-Proxy verhandeln"},
|
||||
{"CONNECT error", "CONNECT-Fehler"},
|
||||
{"Failed to connect", "Verbindung konnte nicht hergestellt werden"},
|
||||
{"SOCKS proxy error", "SOCKS-Proxy-Fehler"},
|
||||
{"Failed to send request to upstream", "Anfrage an den Upstream zu senden ist gescheitert"},
|
||||
{"No reply from SOCKS proxy", "Keine Antwort vom SOCKS-Proxy"},
|
||||
{"Cannot connect", "Kann nicht verbinden"},
|
||||
{"HTTP out proxy not implemented", "HTTP-Outproxy nicht implementiert"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"},
|
||||
{"Failed to Connect", "Verbindung konnte nicht hergestellt werden"},
|
||||
{"socks proxy error", "Socks-Proxy-Fehler"},
|
||||
{"failed to send request to upstream", "Anfrage an den Upstream zu senden ist gescheitert"},
|
||||
{"No Reply From socks proxy", "Keine Antwort vom Socks-Proxy"},
|
||||
{"cannot connect", "kann nicht verbinden"},
|
||||
{"http out proxy not implemented", "HTTP-Outproxy nicht implementiert"},
|
||||
{"cannot connect to upstream http proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"},
|
||||
{"Host is down", "Host ist offline"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Konnte keine Verbindung zum angefragten Host aufbauen, vielleicht ist er offline. Versuche es später noch mal."},
|
||||
{"", ""},
|
||||
|
||||
@@ -95,8 +95,9 @@ std::string tr (TValue&& arg, TArgs&&... args)
|
||||
std::string tr_str = i2p::i18n::translate(std::forward<TValue>(arg));
|
||||
|
||||
size_t size = std::snprintf(NULL, 0, tr_str.c_str(), std::forward<TArgs>(args)...);
|
||||
size = size + 1;
|
||||
std::string str(size, 0);
|
||||
std::snprintf(&str.front(), size + 1, tr_str.c_str(), std::forward<TArgs>(args)...);
|
||||
std::snprintf(&str.front(), size, tr_str.c_str(), std::forward<TArgs>(args)...);
|
||||
|
||||
return str;
|
||||
}
|
||||
@@ -126,8 +127,9 @@ std::string ntr (TValue&& arg, TValue2&& arg2, int& n, TArgs&&... args)
|
||||
std::string tr_str = i2p::i18n::translate(std::forward<TValue>(arg), std::forward<TValue2>(arg2), std::forward<int>(n));
|
||||
|
||||
size_t size = std::snprintf(NULL, 0, tr_str.c_str(), std::forward<TArgs>(args)...);
|
||||
size = size + 1;
|
||||
std::string str(size, 0);
|
||||
std::snprintf(&str.front(), size + 1, tr_str.c_str(), std::forward<TArgs>(args)...);
|
||||
std::snprintf(&str.front(), size, tr_str.c_str(), std::forward<TArgs>(args)...);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2021-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -23,23 +23,20 @@ namespace i18n
|
||||
};
|
||||
|
||||
// Add localization here with language name as namespace
|
||||
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace chinese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace czech { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace italian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace polish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace portuguese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace spanish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace swedish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace turkish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace chinese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace czech { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace italian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace spanish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace swedish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
|
||||
/**
|
||||
* That map contains international language name lower-case, name in it's language and it's code
|
||||
@@ -54,12 +51,9 @@ namespace i18n
|
||||
{ "french", {"Français", "fr", i2p::i18n::french::GetLocale} },
|
||||
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
|
||||
{ "italian", {"Italiano", "it", i2p::i18n::italian::GetLocale} },
|
||||
{ "polish", {"Polski", "pl", i2p::i18n::polish::GetLocale} },
|
||||
{ "portuguese", {"Português", "pt", i2p::i18n::portuguese::GetLocale} },
|
||||
{ "russian", {"Русский язык", "ru", i2p::i18n::russian::GetLocale} },
|
||||
{ "spanish", {"Español", "es", i2p::i18n::spanish::GetLocale} },
|
||||
{ "swedish", {"Svenska", "sv", i2p::i18n::swedish::GetLocale} },
|
||||
{ "turkish", {"Türk dili", "tr", i2p::i18n::turkish::GetLocale} },
|
||||
{ "turkmen", {"Türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} },
|
||||
{ "ukrainian", {"Украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} },
|
||||
{ "uzbek", {"Oʻzbek", "uz", i2p::i18n::uzbek::GetLocale} },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -58,11 +58,10 @@ namespace italian // language namespace
|
||||
{"Unknown", "Sconosciuto"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Mesh"},
|
||||
{"Error", "Errore"},
|
||||
{"Clock skew", "Orologio disallineato"},
|
||||
{"Offline", "Disconnesso"},
|
||||
{"Symmetric NAT", "NAT simmetrico"},
|
||||
{"Full cone NAT", "Cono completo NAT"},
|
||||
{"No Descriptors", "Nessun descrittore"},
|
||||
{"Uptime", "In funzione da"},
|
||||
{"Network status", "Stato della rete"},
|
||||
{"Network status v6", "Stato della rete v6"},
|
||||
@@ -118,10 +117,9 @@ namespace italian // language namespace
|
||||
{"Gateway", "Gateway"},
|
||||
{"TunnelID", "TunnelID"},
|
||||
{"EndDate", "Data di fine"},
|
||||
{"floodfill mode is disabled", "la modalità floodfill è disabilitata"},
|
||||
{"not floodfill", "no floodfill"},
|
||||
{"Queue size", "Dimensione della coda"},
|
||||
{"Run peer test", "Esegui il test dei peer"},
|
||||
{"Reload tunnels configuration", "Ricarica la configurazione dei tunnel"},
|
||||
{"Decline transit tunnels", "Rifiuta tunnel di transito"},
|
||||
{"Accept transit tunnels", "Accetta tunnel di transito"},
|
||||
{"Cancel graceful shutdown", "Annulla l'interruzione controllata"},
|
||||
@@ -149,8 +147,8 @@ namespace italian // language namespace
|
||||
{"Destination not found", "Destinazione non trovata"},
|
||||
{"StreamID can't be null", "Lo StreamID non può essere null"},
|
||||
{"Return to destination page", "Ritorna alla pagina di destinazione"},
|
||||
{"You will be redirected in %d seconds", "Sarai reindirizzato tra %d secondi"},
|
||||
{"Transit tunnels count must not exceed %d", "Il conteggio dei tunnel di transito non deve superare %d"},
|
||||
{"You will be redirected in 5 seconds", "Verrai reindirizzato in 5 secondi"},
|
||||
{"Transit tunnels count must not exceed 65535", "Il numero di tunnel di transito non può superare i 65535"},
|
||||
{"Back to commands list", "Ritorna alla lista dei comandi"},
|
||||
{"Register at reg.i2p", "Registra a reg.i2p"},
|
||||
{"Description", "Descrizione"},
|
||||
@@ -168,33 +166,32 @@ namespace italian // language namespace
|
||||
{"You may try to find this host on jump services below", "Si può provare a trovare questo host sui servizi di salto qui sotto"},
|
||||
{"Invalid request", "Richiesta non valida"},
|
||||
{"Proxy unable to parse your request", "Il proxy non è in grado di elaborare la tua richiesta"},
|
||||
{"Addresshelper is not supported", "Addresshelper non è supportato"},
|
||||
{"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>.", "L'host %s è <font color=red>già nella rubrica del router</font>. <b>Attenzione: la fonte di questo URL potrebbe essere dannosa!</b> Fai clic qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</a>."},
|
||||
{"Addresshelper forced update rejected", "Aggiornamento forzato dell'helper degli indirizzi rifiutato"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Per aggiungere host <b>%s</b> nella rubrica del router, clicca qui: <a href=\"%s%s%s\">Continua</a>."},
|
||||
{"Addresshelper request", "Richiesta di indirizzo helper"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "L'host %s viene aggiunto alla rubrica del router dall'helper. Fai clic qui per procedere: <a href=\"%s\">Continua</a>."},
|
||||
{"Addresshelper adding", "Aggiunta di 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>.", "L'host %s è <font color=red>già nella rubrica del router</font>. Clicca qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</a>."},
|
||||
{"Addresshelper update", "Aggiornamento dell'helper degli indirizzi"},
|
||||
{"Invalid request URI", "URI della richiesta non valido"},
|
||||
{"addresshelper is not supported", "addresshelper non è supportato"},
|
||||
{"Host", "Host"},
|
||||
{"added to router's addressbook from helper", "aggiunto alla rubrica tramite l'helper"},
|
||||
{"Click here to proceed:", "Clicca qui per procedere:"},
|
||||
{"Continue", "Continua"},
|
||||
{"Addresshelper found", "Addresshelper trovato"},
|
||||
{"already in router's addressbook", "già presente nella rubrica del router"},
|
||||
{"Click here to update record:", "Clicca qui per aggiornare l'elemento:"},
|
||||
{"invalid request uri", "uri della richiesta non valido"},
|
||||
{"Can't detect destination host from request", "Impossibile determinare l'host di destinazione dalla richiesta"},
|
||||
{"Outproxy failure", "Fallimento del proxy di uscita"},
|
||||
{"Bad outproxy settings", "Impostazioni errate del proxy di uscita"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Host %s non all'interno della rete I2P, ma il proxy di uscita non è abilitato"},
|
||||
{"Unknown outproxy URL", "URL del proxy di uscita sconosciuto"},
|
||||
{"Cannot resolve upstream proxy", "Impossibile identificare il flusso a monte del proxy"},
|
||||
{"Hostname is too long", "Il nome dell'host è troppo lungo"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Impossibile connettersi al flusso a monte del proxy SOCKS"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Impossibile negoziare con il proxy SOCKS"},
|
||||
{"bad outproxy settings", "impostazioni errate del proxy di uscita"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "non all'interno della rete I2P, ma il proxy di uscita non è abilitato"},
|
||||
{"unknown outproxy url", "url del proxy di uscita sconosciuto"},
|
||||
{"cannot resolve upstream proxy", "impossibile identificare il flusso a monte del proxy"},
|
||||
{"hostname too long", "il nome dell'host è troppo lungo"},
|
||||
{"cannot connect to upstream socks proxy", "impossibile connettersi al flusso a monte del proxy socks"},
|
||||
{"Cannot negotiate with socks proxy", "Impossibile negoziare con il proxy socks"},
|
||||
{"CONNECT error", "Errore di connessione"},
|
||||
{"Failed to connect", "Connessione fallita"},
|
||||
{"SOCKS proxy error", "Errore del proxy SOCKS"},
|
||||
{"Failed to send request to upstream", "Invio della richiesta a monte non riuscito"},
|
||||
{"No reply from SOCKS proxy", "Nessuna risposta dal proxy SOCKS"},
|
||||
{"Cannot connect", "Impossibile connettersi"},
|
||||
{"HTTP out proxy not implemented", "Proxy HTTP di uscita non implementato"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Impossibile connettersi al flusso a monte del proxy HTTP"},
|
||||
{"Failed to Connect", "Connessione fallita"},
|
||||
{"socks proxy error", "errore del proxy socks"},
|
||||
{"failed to send request to upstream", "invio della richiesta a monte non riuscito"},
|
||||
{"No Reply From socks proxy", "Nessuna risposta dal proxy socks"},
|
||||
{"cannot connect", "impossibile connettersi"},
|
||||
{"http out proxy not implemented", "proxy http di uscita non implementato"},
|
||||
{"cannot connect to upstream http proxy", "impossibile connettersi al proxy http a monte"},
|
||||
{"Host is down", "L'host è offline"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Impossibile creare la connessione all'host richiesto, probabilmente è offline. Riprova più tardi."},
|
||||
{"", ""},
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "I18N.h"
|
||||
|
||||
// Polish localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace polish // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "polish";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
return (n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
{
|
||||
{"building", "Kompilowanie"},
|
||||
{"failed", "nieudane"},
|
||||
{"expiring", "wygasający"},
|
||||
{"established", "ustanowiony"},
|
||||
{"Main page", "Strona główna"},
|
||||
{"Router commands", "Komendy routera"},
|
||||
{"Tunnels", "Tunele"},
|
||||
{"OK", "Ok"},
|
||||
{"Uptime", "Czas pracy"},
|
||||
{"Sent", "Wysłane"},
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"", {"", "", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "I18N.h"
|
||||
|
||||
// Portuguese localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace portuguese // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "portuguese";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
{
|
||||
{"%.2f KiB", "%.2f KiB"},
|
||||
{"%.2f MiB", "%.2f MiB"},
|
||||
{"%.2f GiB", "%.2f GiB"},
|
||||
{"building", "construindo"},
|
||||
{"failed", "falhou"},
|
||||
{"expiring", "expirando"},
|
||||
{"established", "estabelecido"},
|
||||
{"unknown", "desconhecido"},
|
||||
{"exploratory", "exploratório"},
|
||||
{"Purple I2P Webconsole", "Webconsole Purple I2P"},
|
||||
{"<b>i2pd</b> webconsole", "webconsole <b>i2pd</b>"},
|
||||
{"Main page", "Página Principal"},
|
||||
{"Router commands", "Comandos do Roteador"},
|
||||
{"Local Destinations", "Destinos Locais"},
|
||||
{"LeaseSets", "LeaseSets"},
|
||||
{"Tunnels", "Túneis"},
|
||||
{"Transit Tunnels", "Túneis de Trânsito"},
|
||||
{"Transports", "Transportes"},
|
||||
{"I2P tunnels", "Túneis I2P"},
|
||||
{"SAM sessions", "Sessões do SAM"},
|
||||
{"ERROR", "ERRO"},
|
||||
{"OK", "OK"},
|
||||
{"Testing", "Testando"},
|
||||
{"Firewalled", "Sob Firewall"},
|
||||
{"Unknown", "Desconhecido"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Malha"},
|
||||
{"Clock skew", "Defasagem do Relógio"},
|
||||
{"Offline", "Desligado"},
|
||||
{"Symmetric NAT", "NAT Simétrico"},
|
||||
{"Full cone NAT", "Full cone NAT"},
|
||||
{"No Descriptors", "Sem Descritores"},
|
||||
{"Uptime", "Tempo Ativo"},
|
||||
{"Network status", "Estado da rede"},
|
||||
{"Network status v6", "Estado da rede v6"},
|
||||
{"Stopping in", "Parando em"},
|
||||
{"Family", "Família"},
|
||||
{"Tunnel creation success rate", "Taxa de sucesso na criação de túneis"},
|
||||
{"Received", "Recebido"},
|
||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||
{"Sent", "Enviado"},
|
||||
{"Transit", "Trânsito"},
|
||||
{"Data path", "Diretório dos dados"},
|
||||
{"Hidden content. Press on text to see.", "Conteúdo oculto. Clique no texto para revelar."},
|
||||
{"Router Ident", "Identidade do Roteador"},
|
||||
{"Router Family", "Família do Roteador"},
|
||||
{"Router Caps", "Limites do Roteador"},
|
||||
{"Version", "Versão"},
|
||||
{"Our external address", "Nosso endereço externo"},
|
||||
{"supported", "suportado"},
|
||||
{"Routers", "Roteadores"},
|
||||
{"Floodfills", "Modo Inundação"},
|
||||
{"Client Tunnels", "Túneis de Clientes"},
|
||||
{"Services", "Serviços"},
|
||||
{"Enabled", "Ativado"},
|
||||
{"Disabled", "Desativado"},
|
||||
{"Encrypted B33 address", "Endereço B33 criptografado"},
|
||||
{"Address registration line", "Linha de cadastro de endereço"},
|
||||
{"Domain", "Domínio"},
|
||||
{"Generate", "Gerar"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Nota: </b>A string resultante só pode ser usada para registrar domínios 2LD (exemplo.i2p). Para registrar subdomínios por favor utilize o i2pd-tools."},
|
||||
{"Address", "Endereço"},
|
||||
{"Type", "Tipo"},
|
||||
{"EncType", "Tipo de Criptografia"},
|
||||
{"Inbound tunnels", "Túneis de Entrada"},
|
||||
{"%dms", "%dms"},
|
||||
{"Outbound tunnels", "Túneis de Saída"},
|
||||
{"Tags", "Etiquetas"},
|
||||
{"Incoming", "Entradas"},
|
||||
{"Outgoing", "Saídas"},
|
||||
{"Destination", "Destinos"},
|
||||
{"Amount", "Quantidade"},
|
||||
{"Incoming Tags", "Etiquetas de Entrada"},
|
||||
{"Tags sessions", "Sessões de etiquetas"},
|
||||
{"Status", "Estado"},
|
||||
{"Local Destination", "Destinos Locais"},
|
||||
{"Streams", "Fluxos"},
|
||||
{"Close stream", "Fechar fluxo"},
|
||||
{"I2CP session not found", "Sessão do I2CP não encontrada"},
|
||||
{"I2CP is not enabled", "I2CP não está ativado"},
|
||||
{"Invalid", "Inválido"},
|
||||
{"Store type", "Tipo de armazenamento"},
|
||||
{"Expires", "Expira em"},
|
||||
{"Non Expired Leases", "Sessões não expiradas"},
|
||||
{"Gateway", "Gateway"},
|
||||
{"TunnelID", "TunnelID"},
|
||||
{"EndDate", "Data final"},
|
||||
{"floodfill mode is disabled", "Mode de inundação está desativado"},
|
||||
{"Queue size", "Tamanho da fila"},
|
||||
{"Run peer test", "Executar teste de peers"},
|
||||
{"Reload tunnels configuration", "Recarregar a configuração dos túneis"},
|
||||
{"Decline transit tunnels", "Negar túneis de trânsito"},
|
||||
{"Accept transit tunnels", "Aceitar túneis de trânsito"},
|
||||
{"Cancel graceful shutdown", "Cancelar desligamento gracioso"},
|
||||
{"Start graceful shutdown", "Iniciar desligamento gracioso"},
|
||||
{"Force shutdown", "Forçar desligamento"},
|
||||
{"Reload external CSS styles", "Recarregar estilos CSS externos"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b> Nota: </b> Qualquer ação feita aqui não será permanente e não altera os seus arquivos de configuração."},
|
||||
{"Logging level", "Nível de registro"},
|
||||
{"Transit tunnels limit", "Limite de túneis de trânsito"},
|
||||
{"Change", "Mudar"},
|
||||
{"Change language", "Trocar idioma"},
|
||||
{"no transit tunnels currently built", "Nenhum túnel de trânsito construido no momento"},
|
||||
{"SAM disabled", "SAM desativado"},
|
||||
{"no sessions currently running", "Nenhuma sessão funcionando no momento"},
|
||||
{"SAM session not found", "Nenhuma sessão do SAM encontrada"},
|
||||
{"SAM Session", "Sessão do SAM"},
|
||||
{"Server Tunnels", "Túneis de Servidor"},
|
||||
{"Client Forwards", "Túneis de Cliente"},
|
||||
{"Server Forwards", "Encaminhamentos de Servidor"},
|
||||
{"Unknown page", "Página desconhecida"},
|
||||
{"Invalid token", "Token Inválido"},
|
||||
{"SUCCESS", "SUCESSO"},
|
||||
{"Stream closed", "Fluxo fechado"},
|
||||
{"Stream not found or already was closed", "Fluxo não encontrado ou já encerrado"},
|
||||
{"Destination not found", "Destino não encontrado"},
|
||||
{"StreamID can't be null", "StreamID não pode ser nulo"},
|
||||
{"Return to destination page", "Retornar para à página de destino"},
|
||||
{"You will be redirected in %d seconds", "Você será redirecionado em %d segundos"},
|
||||
{"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"},
|
||||
{"Register at reg.i2p", "Registrar na reg.i2p"},
|
||||
{"Description", "Descrição"},
|
||||
{"A bit information about service on domain", "Algumas informações sobre o serviço no domínio"},
|
||||
{"Submit", "Enviar"},
|
||||
{"Domain can't end with .b32.i2p", "O domínio não pode terminar com .b32.i2p"},
|
||||
{"Domain must end with .i2p", "O domínio não pode terminar com .i2p"},
|
||||
{"Such destination is not found", "Tal destino não foi encontrado"},
|
||||
{"Unknown command", "Comando desconhecido"},
|
||||
{"Command accepted", "Comando aceito"},
|
||||
{"Proxy error", "Erro no proxy"},
|
||||
{"Proxy info", "Informações do proxy"},
|
||||
{"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"},
|
||||
{"You may try to find this host on jump services below", "Você pode tentar encontrar este host nos jump services abaixo"},
|
||||
{"Invalid request", "Requisição inválida"},
|
||||
{"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"},
|
||||
{"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"},
|
||||
{"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"},
|
||||
{"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>."},
|
||||
{"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>."},
|
||||
{"Addresshelper update", "Atualização do Auxiliar de Endereços"},
|
||||
{"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"},
|
||||
{"Outproxy failure", "Falha no outproxy"},
|
||||
{"Bad outproxy settings", "Configurações ruins de 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"},
|
||||
{"Unknown outproxy URL", "URL de outproxy desconhecida"},
|
||||
{"Cannot resolve upstream proxy", "Não é possível resolver o proxy de entrada"},
|
||||
{"Hostname is too long", "O hostname é muito longo"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Não é possível se conectar ao proxy SOCKS de entrada"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Não é possível negociar com o proxy SOCKS"},
|
||||
{"CONNECT error", "Erro de CONEXÃO"},
|
||||
{"Failed to connect", "Falha ao conectar"},
|
||||
{"SOCKS proxy error", "Erro no proxy SOCKS"},
|
||||
{"Failed to send request to upstream", "Falha ao enviar requisição para o fluxo de entrada"},
|
||||
{"No reply from SOCKS proxy", "Sem resposta do proxy SOCKS"},
|
||||
{"Cannot connect", "Impossível conectar"},
|
||||
{"HTTP out proxy not implemented", "proxy de saída HTTP não implementado"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Não é possível conectar ao proxy HTTP de entrada"},
|
||||
{"Host is down", "Host está desligado"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Não é possível se conectar ao host requisitado, talvez ele esteja for do ar. Por favor, tente novamente mais tarde."},
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"%d days", {"%d Dia", "%d Dias"}},
|
||||
{"%d hours", {"%d hora", "%d horas"}},
|
||||
{"%d minutes", {"%d minuto", "%d minutos"}},
|
||||
{"%d seconds", {"%d Segundo", "%d segundos"}},
|
||||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -40,7 +40,6 @@ namespace russian // language namespace
|
||||
{"established", "работает"},
|
||||
{"unknown", "неизвестно"},
|
||||
{"exploratory", "исследовательский"},
|
||||
{"Purple I2P Webconsole", "Веб-консоль Purple I2P"},
|
||||
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
|
||||
{"Main page", "Главная"},
|
||||
{"Router commands", "Команды роутера"},
|
||||
@@ -58,18 +57,16 @@ namespace russian // language namespace
|
||||
{"Unknown", "Неизвестно"},
|
||||
{"Proxy", "Прокси"},
|
||||
{"Mesh", "MESH-сеть"},
|
||||
{"Error", "Ошибка"},
|
||||
{"Clock skew", "Не точное время"},
|
||||
{"Offline", "Оффлайн"},
|
||||
{"Symmetric NAT", "Симметричный NAT"},
|
||||
{"Full cone NAT", "Full cone NAT"},
|
||||
{"No Descriptors", "Нет дескрипторов"},
|
||||
{"Uptime", "В сети"},
|
||||
{"Network status", "Сетевой статус"},
|
||||
{"Network status v6", "Сетевой статус v6"},
|
||||
{"Stopping in", "Остановка через"},
|
||||
{"Family", "Семейство"},
|
||||
{"Tunnel creation success rate", "Успешно построенных туннелей"},
|
||||
{"Total tunnel creation success rate", "Общий процент успешно построенных туннелей"},
|
||||
{"Received", "Получено"},
|
||||
{"%.2f KiB/s", "%.2f КиБ/с"},
|
||||
{"Sent", "Отправлено"},
|
||||
@@ -96,7 +93,6 @@ namespace russian // language namespace
|
||||
{"Address", "Адрес"},
|
||||
{"Type", "Тип"},
|
||||
{"EncType", "ТипШифр"},
|
||||
{"Expire LeaseSet", "Просрочить Лизсет"},
|
||||
{"Inbound tunnels", "Входящие туннели"},
|
||||
{"%dms", "%dмс"},
|
||||
{"Outbound tunnels", "Исходящие туннели"},
|
||||
@@ -111,7 +107,6 @@ namespace russian // language namespace
|
||||
{"Local Destination", "Локальное назначение"},
|
||||
{"Streams", "Стримы"},
|
||||
{"Close stream", "Закрыть стрим"},
|
||||
{"Such destination is not found", "Такая точка назначения не найдена"},
|
||||
{"I2CP session not found", "I2CP сессия не найдена"},
|
||||
{"I2CP is not enabled", "I2CP не включен"},
|
||||
{"Invalid", "Некорректный"},
|
||||
@@ -121,10 +116,9 @@ namespace russian // language namespace
|
||||
{"Gateway", "Шлюз"},
|
||||
{"TunnelID", "ID туннеля"},
|
||||
{"EndDate", "Заканчивается"},
|
||||
{"floodfill mode is disabled", "режим флудфила отключен"},
|
||||
{"not floodfill", "не флудфил"},
|
||||
{"Queue size", "Размер очереди"},
|
||||
{"Run peer test", "Запустить тестирование"},
|
||||
{"Reload tunnels configuration", "Перезагрузить конфигурацию туннелей"},
|
||||
{"Decline transit tunnels", "Отклонять транзитные туннели"},
|
||||
{"Accept transit tunnels", "Принимать транзитные туннели"},
|
||||
{"Cancel graceful shutdown", "Отменить плавную остановку"},
|
||||
@@ -152,10 +146,8 @@ namespace russian // language namespace
|
||||
{"Destination not found", "Точка назначения не найдена"},
|
||||
{"StreamID can't be null", "StreamID не может быть пустым"},
|
||||
{"Return to destination page", "Вернуться на страницу точки назначения"},
|
||||
{"You will be redirected in %d seconds", "Вы будете переадресованы через %d секунд"},
|
||||
{"LeaseSet expiration time updated", "Время действия LeaseSet обновлено"},
|
||||
{"LeaseSet is not found or already expired", "Лизсет не найден или время действия уже истекло"},
|
||||
{"Transit tunnels count must not exceed %d", "Число транзитных туннелей не должно превышать %d"},
|
||||
{"You will be redirected in 5 seconds", "Вы будете переадресованы через 5 секунд"},
|
||||
{"Transit tunnels count must not exceed 65535", "Число транзитных туннелей не должно превышать 65535"},
|
||||
{"Back to commands list", "Вернуться к списку команд"},
|
||||
{"Register at reg.i2p", "Зарегистрировать на reg.i2p"},
|
||||
{"Description", "Описание"},
|
||||
@@ -163,6 +155,7 @@ namespace russian // language namespace
|
||||
{"Submit", "Отправить"},
|
||||
{"Domain can't end with .b32.i2p", "Домен не может заканчиваться на .b32.i2p"},
|
||||
{"Domain must end with .i2p", "Домен должен заканчиваться на .i2p"},
|
||||
{"Such destination is not found", "Такая точка назначения не найдена"},
|
||||
{"Unknown command", "Неизвестная команда"},
|
||||
{"Command accepted", "Команда принята"},
|
||||
{"Proxy error", "Ошибка прокси"},
|
||||
@@ -172,33 +165,32 @@ namespace russian // language namespace
|
||||
{"You may try to find this host on jump services below", "Вы можете попробовать найти узел через джамп сервисы ниже"},
|
||||
{"Invalid request", "Некорректный запрос"},
|
||||
{"Proxy unable to parse your request", "Прокси не может разобрать ваш запрос"},
|
||||
{"Addresshelper is not supported", "Addresshelper не поддерживается"},
|
||||
{"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>.", "Узел %s <font color=red>уже в адресной книге роутера</font>. <b>Будьте осторожны: источник данной ссылки может быть вредоносным!</b> Нажмите здесь, чтобы обновить запись: <a href=\"%s%s%s&update=true\">Продолжить</a>."},
|
||||
{"Addresshelper forced update rejected", "Принудительное обновление через Addresshelper отклонено"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Чтобы добавить узел <b>%s</b> в адресную книгу роутера, нажмите здесь: <a href=\"%s%s%s\">Продолжить</a>."},
|
||||
{"Addresshelper request", "Запрос добавления Addresshelper"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Узел %s добавлен в адресную книгу роутера через хелпер. Нажмите здесь, чтобы продолжить: <a href=\"%s\">Продолжить</a>."},
|
||||
{"Addresshelper adding", "Добавление 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>.", "Узел %s <font color=red>уже в адресной книге роутера</font>. Нажмите здесь, чтобы обновить запись: <a href=\"%s%s%s&update=true\">Продолжить</a>."},
|
||||
{"Addresshelper update", "Обновление записи через Addresshelper"},
|
||||
{"Invalid request URI", "Некорректный URI запроса"},
|
||||
{"addresshelper is not supported", "addresshelper не поддерживается"},
|
||||
{"Host", "Узел"},
|
||||
{"added to router's addressbook from helper", "добавлен в адресную книгу роутера через хелпер"},
|
||||
{"Click here to proceed:", "Нажмите здесь, чтобы продолжить:"},
|
||||
{"Continue", "Продолжить"},
|
||||
{"Addresshelper found", "Найден addresshelper"},
|
||||
{"already in router's addressbook", "уже в адресной книге роутера"},
|
||||
{"Click here to update record:", "Нажмите здесь, чтобы обновить запись:"},
|
||||
{"invalid request uri", "некорректный URI запроса"},
|
||||
{"Can't detect destination host from request", "Не удалось определить адрес назначения из запроса"},
|
||||
{"Outproxy failure", "Ошибка внешнего прокси"},
|
||||
{"Bad outproxy settings", "Некорректные настройки внешнего прокси"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Узел %s не в I2P сети, но внешний прокси не включен"},
|
||||
{"Unknown outproxy URL", "Неизвестный URL внешнего прокси"},
|
||||
{"Cannot resolve upstream proxy", "Не удается определить вышестоящий прокси"},
|
||||
{"Hostname is too long", "Имя хоста слишком длинное"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Не удалось подключиться к вышестоящему SOCKS прокси серверу"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Не удается договориться с вышестоящим SOCKS прокси"},
|
||||
{"bad outproxy settings", "некорректные настройки внешнего прокси"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "не в I2P сети, но внешний прокси не включен"},
|
||||
{"unknown outproxy url", "неизвестный URL внешнего прокси"},
|
||||
{"cannot resolve upstream proxy", "не удается определить вышестоящий прокси"},
|
||||
{"hostname too long", "имя хоста слишком длинное"},
|
||||
{"cannot connect to upstream socks proxy", "не удается подключиться к вышестоящему SOCKS прокси"},
|
||||
{"Cannot negotiate with socks proxy", "Не удается договориться с вышестоящим SOCKS прокси"},
|
||||
{"CONNECT error", "Ошибка CONNECT запроса"},
|
||||
{"Failed to connect", "Не удалось соединиться"},
|
||||
{"SOCKS proxy error", "Ошибка SOCKS прокси"},
|
||||
{"Failed to send request to upstream", "Не удалось отправить запрос вышестоящему прокси серверу"},
|
||||
{"No reply from SOCKS proxy", "Нет ответа от SOCKS прокси сервера"},
|
||||
{"Cannot connect", "Не удалось подключиться"},
|
||||
{"HTTP out proxy not implemented", "Поддержка внешнего HTTP прокси сервера не реализована"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Не удалось подключиться к вышестоящему HTTP прокси серверу"},
|
||||
{"Failed to Connect", "Не удалось подключиться"},
|
||||
{"socks proxy error", "ошибка SOCKS прокси"},
|
||||
{"failed to send request to upstream", "не удалось отправить запрос вышестоящему прокси"},
|
||||
{"No Reply From socks proxy", "Нет ответа от SOCKS прокси сервера"},
|
||||
{"cannot connect", "не удалось подключиться"},
|
||||
{"http out proxy not implemented", "поддержка внешнего HTTP прокси сервера не реализована"},
|
||||
{"cannot connect to upstream http proxy", "не удалось подключиться к вышестоящему HTTP прокси серверу"},
|
||||
{"Host is down", "Узел недоступен"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Не удалось установить соединение к запрошенному узлу, возможно он не в сети. Попробуйте повторить запрос позже."},
|
||||
{"", ""},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -58,6 +58,7 @@ namespace spanish // language namespace
|
||||
{"Unknown", "Desconocido"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Malla"},
|
||||
{"Error", "Error"},
|
||||
{"Clock skew", "Reloj desfasado"},
|
||||
{"Offline", "Desconectado"},
|
||||
{"Symmetric NAT", "NAT simétrico"},
|
||||
@@ -116,6 +117,7 @@ namespace spanish // language namespace
|
||||
{"Gateway", "Puerta de enlace"},
|
||||
{"TunnelID", "TunnelID"},
|
||||
{"EndDate", "FechaVenc"},
|
||||
{"not floodfill", "no inundado"},
|
||||
{"Queue size", "Tamaño de cola"},
|
||||
{"Run peer test", "Ejecutar prueba de par"},
|
||||
{"Decline transit tunnels", "Rechazar túneles de tránsito"},
|
||||
@@ -145,6 +147,8 @@ namespace spanish // language namespace
|
||||
{"Destination not found", "Destino no encontrado"},
|
||||
{"StreamID can't be null", "StreamID no puede ser nulo"},
|
||||
{"Return to destination page", "Volver a la página de destino"},
|
||||
{"You will be redirected in 5 seconds", "Serás redirigido en 5 segundos"},
|
||||
{"Transit tunnels count must not exceed 65535", "La cantidad de túneles de tránsito no puede exceder 65535"},
|
||||
{"Back to commands list", "Volver a lista de comandos"},
|
||||
{"Register at reg.i2p", "Registrar en reg.i2p"},
|
||||
{"Description", "Descripción"},
|
||||
@@ -162,24 +166,32 @@ namespace spanish // language namespace
|
||||
{"You may try to find this host on jump services below", "Puede intentar encontrar este dominio en los siguientes servicios de salto"},
|
||||
{"Invalid request", "Solicitud inválida"},
|
||||
{"Proxy unable to parse your request", "Proxy no puede procesar su solicitud"},
|
||||
{"Invalid request URI", "URI de solicitud inválida"},
|
||||
{"addresshelper is not supported", "ayudante de dirección no soportado"},
|
||||
{"Host", "Dominio"},
|
||||
{"added to router's addressbook from helper", "añadido a la libreta de direcciones desde el ayudante"},
|
||||
{"Click here to proceed:", "Haga clic aquí para continuar:"},
|
||||
{"Continue", "Continuar"},
|
||||
{"Addresshelper found", "Se encontró ayudante de dirección"},
|
||||
{"already in router's addressbook", "ya se encontró en libreta de direcciones"},
|
||||
{"Click here to update record:", "Haga clic aquí para actualizar el registro:"},
|
||||
{"invalid request uri", "uri de solicitud inválida"},
|
||||
{"Can't detect destination host from request", "No se puede detectar el host de destino de la solicitud"},
|
||||
{"Outproxy failure", "Fallo en el proxy saliente"},
|
||||
{"Bad outproxy settings", "Configuración de outproxy incorrecta"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Dominio %s no está dentro de la red I2P, pero el proxy de salida no está activado"},
|
||||
{"Unknown outproxy URL", "URL de proxy outproxy desconocido"},
|
||||
{"Cannot resolve upstream proxy", "No se puede resolver el proxy de upstream"},
|
||||
{"Hostname is too long", "Nombre de dominio muy largo"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "No se puede conectar al proxy SOCKS principal"},
|
||||
{"Cannot negotiate with SOCKS proxy", "No se puede negociar con el proxy SOCKS"},
|
||||
{"bad outproxy settings", "configuración de outproxy incorrecta"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "no está dentro de la red I2P, pero el proxy de salida no está activado"},
|
||||
{"unknown outproxy url", "url de proxy outproxy desconocido"},
|
||||
{"cannot resolve upstream proxy", "no se puede resolver el proxy de upstream"},
|
||||
{"hostname too long", "nombre de dominio muy largo"},
|
||||
{"cannot connect to upstream socks proxy", "no se puede conectar al proxy socks principal"},
|
||||
{"Cannot negotiate with socks proxy", "No se puede negociar con el proxy socks"},
|
||||
{"CONNECT error", "Error de CONNECT"},
|
||||
{"Failed to connect", "Error al conectar"},
|
||||
{"SOCKS proxy error", "Error de proxy SOCKS"},
|
||||
{"Failed to send request to upstream", "No se pudo enviar petición al principal"},
|
||||
{"No reply from SOCKS proxy", "Sin respuesta del proxy SOCKS"},
|
||||
{"Cannot connect", "No se puede conectar"},
|
||||
{"HTTP out proxy not implemented", "Proxy externo HTTP no implementado"},
|
||||
{"Cannot connect to upstream HTTP proxy", "No se puede conectar al proxy HTTP principal"},
|
||||
{"Failed to Connect", "Error al Conectar"},
|
||||
{"socks proxy error", "error de proxy socks"},
|
||||
{"failed to send request to upstream", "no se pudo enviar petición al principal"},
|
||||
{"No Reply From socks proxy", "Sin respuesta del proxy socks"},
|
||||
{"cannot connect", "no se puede conectar"},
|
||||
{"http out proxy not implemented", "proxy externo http no implementado"},
|
||||
{"cannot connect to upstream http proxy", "no se puede conectar al proxy http principal"},
|
||||
{"Host is down", "Servidor caído"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "No se puede crear la conexión al servidor solicitado, puede estar caído. Intente de nuevo más tarde."},
|
||||
{"", ""},
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace swedish // language namespace
|
||||
{"unknown", "okänt"},
|
||||
{"exploratory", "utforskande"},
|
||||
{"Purple I2P Webconsole", "Purple I2P Webbkonsoll"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b>-Webbkonsoll"},
|
||||
{"<b>i2pd</b> webbkonsoll", "<b>i2pd</b>-Webbkonsoll"},
|
||||
{"Main page", "Huvudsida"},
|
||||
{"Router commands", "Routerkommandon"},
|
||||
{"Local Destinations", "Lokala Platser"},
|
||||
@@ -58,11 +58,10 @@ namespace swedish // language namespace
|
||||
{"Unknown", "Okänt"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Mesh"},
|
||||
{"Error", "Fel"},
|
||||
{"Clock skew", "Tidsförskjutning"},
|
||||
{"Offline", "Nedkopplad"},
|
||||
{"Symmetric NAT", "Symmetrisk NAT"},
|
||||
{"Full cone NAT", "Full kon NAT"},
|
||||
{"No Descriptors", "Inga Beskrivningar"},
|
||||
{"Uptime", "Upptid"},
|
||||
{"Network status", "Nätverkstillstånd"},
|
||||
{"Network status v6", "Nätverkstillstånd v6"},
|
||||
@@ -109,7 +108,6 @@ namespace swedish // language namespace
|
||||
{"Local Destination", "Lokal Plats"},
|
||||
{"Streams", "Strömmar"},
|
||||
{"Close stream", "Stäng strömmen"},
|
||||
{"Such destination is not found", "En sådan plats hittas ej"},
|
||||
{"I2CP session not found", "I2CP-period hittades inte"},
|
||||
{"I2CP is not enabled", "I2CP är inte påslaget"},
|
||||
{"Invalid", "Ogiltig"},
|
||||
@@ -119,10 +117,9 @@ namespace swedish // language namespace
|
||||
{"Gateway", "Gateway"},
|
||||
{"TunnelID", "TunnelID"},
|
||||
{"EndDate", "EndDate"},
|
||||
{"floodfill mode is disabled", "Floodfill läget är inaktiverat"},
|
||||
{"not floodfill", "inte Översvämningsfyllare"},
|
||||
{"Queue size", "Köstorlek"},
|
||||
{"Run peer test", "Utför utsiktstest"},
|
||||
{"Reload tunnels configuration", "Ladda om tunnelkonfiguration"},
|
||||
{"Decline transit tunnels", "Avvisa förmedlande tunnlar"},
|
||||
{"Accept transit tunnels", "Tillåt förmedlande tunnlar"},
|
||||
{"Cancel graceful shutdown", "Avbryt välvillig avstängning"},
|
||||
@@ -150,8 +147,8 @@ namespace swedish // language namespace
|
||||
{"Destination not found", "Plats hittades ej"},
|
||||
{"StreamID can't be null", "Ström-ID kan inte vara null"},
|
||||
{"Return to destination page", "Återvänd till platssidan"},
|
||||
{"You will be redirected in %d seconds", "Du omdirigeras inom %d sekunder"},
|
||||
{"Transit tunnels count must not exceed %d", "Förmedlande tunnlar får inte överstiga %d"},
|
||||
{"You will be redirected in 5 seconds", "Du omdirigeras inom fem sekunder"},
|
||||
{"Transit tunnels count must not exceed 65535", "Förmedlande tunnlar får inte överstiga 65535"},
|
||||
{"Back to commands list", "Tillbaka till kommandolistan"},
|
||||
{"Register at reg.i2p", "Registrera vid reg.i2p"},
|
||||
{"Description", "Beskrivning"},
|
||||
@@ -159,6 +156,7 @@ namespace swedish // language namespace
|
||||
{"Submit", "Skicka"},
|
||||
{"Domain can't end with .b32.i2p", "Domänen får inte sluta med .b32.i2p"},
|
||||
{"Domain must end with .i2p", "Domänen måste sluta med .i2p"},
|
||||
{"Such destination is not found", "En sådan plats hittas ej"},
|
||||
{"Unknown command", "Okänt kommando"},
|
||||
{"Command accepted", "Kommando accepterades"},
|
||||
{"Proxy error", "Proxyfel"},
|
||||
@@ -168,33 +166,32 @@ namespace swedish // language namespace
|
||||
{"You may try to find this host on jump services below", "Du kan försöka att hitta värden genom hopptjänsterna nedan"},
|
||||
{"Invalid request", "Ogiltig förfrågan"},
|
||||
{"Proxy unable to parse your request", "Proxyt kan inte behandla din förfrågan"},
|
||||
{"Addresshelper is not supported", "Adresshjälparen stöds ej"},
|
||||
{"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>.", "Värd %s är <font color=red>redan i routerns adressbok</font>. <b>Var försiktig: källan till denna URL kan vara skadlig!</b> Klicka här för att uppdatera registreringen: <a href=\"%s%s%s&update=true\">Fortsätt</a>."},
|
||||
{"Addresshelper forced update rejected", "Tvingad uppdatering av adresshjälparen nekad"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "För att lägga till värd <b>%s</b> i routerns adressbok, klicka här: <a href=\"%s%s%s\">Fortsätt</a>."},
|
||||
{"Addresshelper request", "Adresshjälpare förfrågan"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Värd %s tillagd i routerns adressbok från hjälparen. Klicka här för att fortsätta: <a href=\"%s\">Fortsätt</a>."},
|
||||
{"Addresshelper adding", "Adresshjälpare tilläggning"},
|
||||
{"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>.", "Värd %s är <font color=red>redan i routerns adressbok</font>. Klicka här för att uppdatera registreringen: <a href=\"%s%s%s&update=true\">Fortsätt</a>."},
|
||||
{"Addresshelper update", "Adresshjälpare uppdatering"},
|
||||
{"Invalid request URI", "Ogiltig förfrågnings-URI"},
|
||||
{"addresshelper is not supported", "adresshjälparen stöds ej"},
|
||||
{"Host", "Värd"},
|
||||
{"added to router's addressbook from helper", "tillagd i routerns adressbok från adresshjälparen"},
|
||||
{"Click here to proceed:", "Tryck här för att fortsätta:"},
|
||||
{"Continue", "Fortsätt"},
|
||||
{"Addresshelper found", "Adresshjälpare hittad"},
|
||||
{"already in router's addressbook", "finns redan i routerns adressbok"},
|
||||
{"Click here to update record:", "Tryck här för att uppdatera:"},
|
||||
{"invalid request uri", "ogiltig förfrågnings-URI"},
|
||||
{"Can't detect destination host from request", "Kan inte upptäcka platsvärden från förfrågan"},
|
||||
{"Outproxy failure", "Utproxyfel"},
|
||||
{"Bad outproxy settings", "Ogiltig utproxyinställning"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Värd %s är inte inom I2P-näverket, men utproxy är inte påslaget"},
|
||||
{"Unknown outproxy URL", "okänt Utproxy-URL"},
|
||||
{"Cannot resolve upstream proxy", "Hittar inte uppströmsproxyt"},
|
||||
{"Hostname is too long", "Värdnamnet är för långt"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Kan inte ansluta till uppström SOCKS-proxy"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Kan inte förhandla med SOCKSproxyt"},
|
||||
{"bad outproxy settings", "ogiltig utproxyinställning"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "adressen är inte inom I2P-näverket, men utproxy är inte påslaget"},
|
||||
{"unknown outproxy url", "okänt Utproxy-URL"},
|
||||
{"cannot resolve upstream proxy", "hittar inte uppströmsproxyt"},
|
||||
{"hostname too long", "värdnamnet är för långt"},
|
||||
{"cannot connect to upstream socks proxy", "kan inte ansluta till uppströmsproxyt"},
|
||||
{"Cannot negotiate with socks proxy", "Kan inte förhandla med socksproxyt"},
|
||||
{"CONNECT error", "CONNECT-fel"},
|
||||
{"Failed to connect", "Anslutningen misslyckades"},
|
||||
{"SOCKS proxy error", "SOCKSproxyfel"},
|
||||
{"Failed to send request to upstream", "Förfrågan uppströms kunde ej skickas"},
|
||||
{"No reply from SOCKS proxy", "Fick inget svar från SOCKSproxyt"},
|
||||
{"Cannot connect", "Kan inte ansluta"},
|
||||
{"HTTP out proxy not implemented", "HTTP-Utproxy ej implementerat"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Kan inte ansluta till uppströms HTTP-proxy"},
|
||||
{"Failed to Connect", "Anslutningen misslyckades"},
|
||||
{"socks proxy error", "Socksproxyfel"},
|
||||
{"failed to send request to upstream", "förfrågan uppströms kunde ej skickas"},
|
||||
{"No Reply From socks proxy", "Fick inget svar från socksproxyt"},
|
||||
{"cannot connect", "kan inte ansluta"},
|
||||
{"http out proxy not implemented", "HTTP-Utproxy ej implementerat"},
|
||||
{"cannot connect to upstream http proxy", "Kan inte ansluta till uppströms HTTP-proxy"},
|
||||
{"Host is down", "Värden är nere"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Kan inte ansluta till värden, den kan vara nere. Vänligen försök senare."},
|
||||
{"", ""},
|
||||
@@ -202,10 +199,10 @@ namespace swedish // language namespace
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"%d days", {"%d dag", "%d dagar"}},
|
||||
{"%d hours", {"%d timme", "%d timmar"}},
|
||||
{"%d minutes", {"%d minut", "%d minuter"}},
|
||||
{"%d seconds", {"%d sekund", "%d sekunder"}},
|
||||
{"%d days", {"%d Dag", "%d Dagar"}},
|
||||
{"%d hours", {"%d Timme", "%d Timmar"}},
|
||||
{"%d minutes", {"%d Minut", "%d Minuter"}},
|
||||
{"%d seconds", {"%d Sekund", "%d Sekunder"}},
|
||||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
|
||||
114
i18n/Turkish.cpp
114
i18n/Turkish.cpp
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "I18N.h"
|
||||
|
||||
// Turkish localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace turkish // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "turkish";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
{
|
||||
{"%.2f KiB", "%.2f KiB"},
|
||||
{"%.2f MiB", "%.2f MiB"},
|
||||
{"%.2f GiB", "%.2f GiB"},
|
||||
{"building", "kuruluyor"},
|
||||
{"failed", "başarısız"},
|
||||
{"expiring", "süresi geçiyor"},
|
||||
{"established", "kurulmuş"},
|
||||
{"unknown", "bilinmeyen"},
|
||||
{"Purple I2P Webconsole", "Mor I2P Webkonsolu"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> webkonsolu"},
|
||||
{"Main page", "Ana sayfa"},
|
||||
{"Router commands", "Router komutları"},
|
||||
{"Local Destinations", "Yerel Hedefler"},
|
||||
{"Tunnels", "Tüneller"},
|
||||
{"Transit Tunnels", "Transit Tünelleri"},
|
||||
{"Transports", "Taşıma"},
|
||||
{"I2P tunnels", "I2P tünelleri"},
|
||||
{"SAM sessions", "SAM oturumları"},
|
||||
{"ERROR", "HATA"},
|
||||
{"OK", "TAMAM"},
|
||||
{"Testing", "Test ediliyor"},
|
||||
{"Firewalled", "Güvenlik Duvarı Kısıtlaması"},
|
||||
{"Unknown", "Bilinmeyen"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Clock skew", "Saat sorunu"},
|
||||
{"Offline", "Çevrimdışı"},
|
||||
{"Symmetric NAT", "Simetrik NAT"},
|
||||
{"Full cone NAT", "Full cone NAT"},
|
||||
{"No Descriptors", "Tanımlayıcı Yok"},
|
||||
{"Uptime", "Bağlantı süresi"},
|
||||
{"Network status", "Ağ durumu"},
|
||||
{"Network status v6", "Ağ durumu v6"},
|
||||
{"Family", "Aile"},
|
||||
{"Tunnel creation success rate", "Tünel oluşturma başarı oranı"},
|
||||
{"Received", "Alındı"},
|
||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||
{"Sent", "Gönderildi"},
|
||||
{"Transit", "Transit"},
|
||||
{"Data path", "Veri yolu"},
|
||||
{"Hidden content. Press on text to see.", "Gizlenmiş içerik. Görmek için yazıya tıklayınız."},
|
||||
{"Router Family", "Router Familyası"},
|
||||
{"Decline transit tunnels", "Transit tünellerini reddet"},
|
||||
{"Accept transit tunnels", "Transit tünellerini kabul et"},
|
||||
{"Cancel graceful shutdown", "Düzgün durdurmayı iptal Et"},
|
||||
{"Start graceful shutdown", "Düzgün durdurmayı başlat"},
|
||||
{"Force shutdown", "Durdurmaya zorla"},
|
||||
{"Reload external CSS styles", "Harici CSS stilini yeniden yükle"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Not:</b> burada yapılan ayarların hiçbiri kalıcı değildir ve ayar dosyalarınızı değiştirmez."},
|
||||
{"Logging level", "Kayıt tutma seviyesi"},
|
||||
{"Transit tunnels limit", "Transit tünel limiti"},
|
||||
{"Change", "Değiştir"},
|
||||
{"Change language", "Dil değiştir"},
|
||||
{"no transit tunnels currently built", "kurulmuş bir transit tüneli bulunmamakta"},
|
||||
{"SAM disabled", "SAM devre dışı"},
|
||||
{"no sessions currently running", "hiçbir oturum şu anda çalışmıyor"},
|
||||
{"SAM session not found", "SAM oturumu bulunamadı"},
|
||||
{"SAM Session", "SAM oturumu"},
|
||||
{"Server Tunnels", "Sunucu Tünelleri"},
|
||||
{"Unknown page", "Bilinmeyen sayfa"},
|
||||
{"Invalid token", "Geçersiz token"},
|
||||
{"SUCCESS", "BAŞARILI"},
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"%d days", {"%d gün", "%d gün"}},
|
||||
{"%d hours", {"%d saat", "%d saat"}},
|
||||
{"%d minutes", {"%d dakika", "%d dakika"}},
|
||||
{"%d seconds", {"%d saniye", "%d saniye"}},
|
||||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2021-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -40,7 +40,6 @@ namespace turkmen // language namespace
|
||||
{"established", "işleýär"},
|
||||
{"unknown", "näbelli"},
|
||||
{"exploratory", "gözleg"},
|
||||
{"Purple I2P Webconsole", "Web konsoly Purple I2P"},
|
||||
{"<b>i2pd</b> webconsole", "Web konsoly <b>i2pd</b>"},
|
||||
{"Main page", "Esasy sahypa"},
|
||||
{"Router commands", "Marşrutizator buýruklary"},
|
||||
@@ -58,6 +57,7 @@ namespace turkmen // language namespace
|
||||
{"Unknown", "Näbelli"},
|
||||
{"Proxy", "Proksi"},
|
||||
{"Mesh", "MESH-tor"},
|
||||
{"Error", "Ýalňyşlyk"},
|
||||
{"Clock skew", "Takyk wagt däl"},
|
||||
{"Offline", "Awtonom"},
|
||||
{"Symmetric NAT", "Simmetriklik NAT"},
|
||||
@@ -116,6 +116,7 @@ namespace turkmen // language namespace
|
||||
{"Gateway", "Derweze"},
|
||||
{"TunnelID", "Tuneliň ID"},
|
||||
{"EndDate", "Gutarýar"},
|
||||
{"not floodfill", "fludfil däl"},
|
||||
{"Queue size", "Nobatyň ululygy"},
|
||||
{"Run peer test", "Synag başlaň"},
|
||||
{"Decline transit tunnels", "Tranzit tunellerini ret ediň"},
|
||||
@@ -145,6 +146,8 @@ namespace turkmen // language namespace
|
||||
{"Destination not found", "Niýetlenen ýeri tapylmady"},
|
||||
{"StreamID can't be null", "StreamID boş bolup bilmez"},
|
||||
{"Return to destination page", "Barmaly nokadynyň nokadyna gaýdyp geliň"},
|
||||
{"You will be redirected in 5 seconds", "5 sekuntdan soň täzeden ugrukdyrylarsyňyz"},
|
||||
{"Transit tunnels count must not exceed 65535", "Tranzit tagtalaryň sany 65535-den geçmeli däldir"},
|
||||
{"Back to commands list", "Topar sanawyna dolan"},
|
||||
{"Register at reg.i2p", "Reg.i2P-de hasaba duruň"},
|
||||
{"Description", "Beýany"},
|
||||
@@ -162,24 +165,32 @@ namespace turkmen // language namespace
|
||||
{"You may try to find this host on jump services below", "Aşakdaky böküş hyzmatlarynda bu öý eýesini tapmaga synanyşyp bilersiňiz"},
|
||||
{"Invalid request", "Nädogry haýyş"},
|
||||
{"Proxy unable to parse your request", "Proksi haýyşyňyzy derňäp bilmeýär"},
|
||||
{"Invalid request URI", "Nädogry haýyş URI"},
|
||||
{"addresshelper is not supported", "Salgylandyryjy goldanok"},
|
||||
{"Host", "Adres"},
|
||||
{"added to router's addressbook from helper", "marşruteriň adresini kömekçiden goşdy"},
|
||||
{"Click here to proceed:", "Dowam etmek bu ýerde basyň:"},
|
||||
{"Continue", "Dowam et"},
|
||||
{"Addresshelper found", "Forgelper tapyldy"},
|
||||
{"already in router's addressbook", "marşruteriň adres kitaby"},
|
||||
{"Click here to update record:", "Recordazgyny täzelemek üçin bu ýerde basyň:"},
|
||||
{"invalid request uri", "nädogry haýyş URI"},
|
||||
{"Can't detect destination host from request", "Haýyşdan barmaly ýerini tapyp bilemok"},
|
||||
{"Outproxy failure", "Daşarky proksi ýalňyşlyk"},
|
||||
{"Bad outproxy settings", "Daşarky Daşarky proksi sazlamalary nädogry"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Adres %s I2P torunda däl, ýöne daşarky proksi goşulmaýar"},
|
||||
{"Unknown outproxy URL", "Näbelli daşarky proksi URL"},
|
||||
{"Cannot resolve upstream proxy", "Has ýokary proksi kesgitläp bilmeýär"},
|
||||
{"Hostname is too long", "Hoster eýesi ady gaty uzyn"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Ýokary jorap SOCKS proksi bilen birigip bolmaýar"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Iň ýokary jorap SOCKS proksi bilen ylalaşyp bilmeýärler"},
|
||||
{"bad outproxy settings", "daşarky daşarky proksi sazlamalary nädogry"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "I2P torunda däl, ýöne daşarky proksi goşulmaýar"},
|
||||
{"unknown outproxy url", "näbelli daşarky proksi URL"},
|
||||
{"cannot resolve upstream proxy", "has ýokary proksi kesgitläp bilmeýär"},
|
||||
{"hostname too long", "hoster eýesi ady gaty uzyn"},
|
||||
{"cannot connect to upstream socks proxy", "ýokary jorap SOCKS proksi bilen birigip bolmaýar"},
|
||||
{"Cannot negotiate with socks proxy", "Iň ýokary jorap SOCKS proksi bilen ylalaşyp bilmeýärler"},
|
||||
{"CONNECT error", "Bagyr haýyşy säwligi"},
|
||||
{"Failed to connect", "Birikdirip bilmedi"},
|
||||
{"SOCKS proxy error", "SOCKS proksi ýalňyşlygy"},
|
||||
{"Failed to send request to upstream", "Öý eýesi proksi üçin haýyş iberip bilmedi"},
|
||||
{"No reply from SOCKS proxy", "Jorap SOCKS proksi serwerinden hiç hili jogap ýok"},
|
||||
{"Cannot connect", "Birikdirip bilmedi"},
|
||||
{"HTTP out proxy not implemented", "Daşarky HTTP proksi serwerini goldamak amala aşyrylmaýar"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Ýokary jorap HTTP proksi bilen birigip bolmaýar"},
|
||||
{"Failed to Connect", "Birikdirip bilmedi"},
|
||||
{"socks proxy error", "socks proksi ýalňyşlygy"},
|
||||
{"failed to send request to upstream", "öý eýesi proksi üçin haýyş iberip bilmedi"},
|
||||
{"No Reply From socks proxy", "Jorap proksi serwerinden hiç hili jogap ýok"},
|
||||
{"cannot connect", "birikdirip bilmedi"},
|
||||
{"http out proxy not implemented", "daşarky HTTP proksi serwerini goldamak amala aşyrylmaýar"},
|
||||
{"cannot connect to upstream http proxy", "ýokary akym HTTP proksi serwerine birigip bilmedi"},
|
||||
{"Host is down", "Salgy elýeterli däl"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Talap edilýän salgyda birikmäni gurup bilmedim, onlaýn bolup bilmez. Soňra haýyşy soň gaýtalamaga synanyşyň."},
|
||||
{"", ""},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -40,7 +40,6 @@ namespace ukrainian // language namespace
|
||||
{"established", "працює"},
|
||||
{"unknown", "невідомо"},
|
||||
{"exploratory", "дослідницький"},
|
||||
{"Purple I2P Webconsole", "Веб-консоль Purple I2P"},
|
||||
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
|
||||
{"Main page", "Головна"},
|
||||
{"Router commands", "Команди маршрутизатора"},
|
||||
@@ -58,11 +57,10 @@ namespace ukrainian // language namespace
|
||||
{"Unknown", "Невідомо"},
|
||||
{"Proxy", "Проксі"},
|
||||
{"Mesh", "MESH-мережа"},
|
||||
{"Error", "Помилка"},
|
||||
{"Clock skew", "Неточний час"},
|
||||
{"Offline", "Офлайн"},
|
||||
{"Symmetric NAT", "Симетричний NAT"},
|
||||
{"Full cone NAT", "Повний NAT"},
|
||||
{"No Descriptors", "Немає Описів"},
|
||||
{"Uptime", "У мережі"},
|
||||
{"Network status", "Мережевий статус"},
|
||||
{"Network status v6", "Мережевий статус v6"},
|
||||
@@ -118,10 +116,9 @@ namespace ukrainian // language namespace
|
||||
{"Gateway", "Шлюз"},
|
||||
{"TunnelID", "ID тунеля"},
|
||||
{"EndDate", "Закінчується"},
|
||||
{"floodfill mode is disabled", "режим floodfill вимкнено"},
|
||||
{"not floodfill", "не флудфіл"},
|
||||
{"Queue size", "Розмір черги"},
|
||||
{"Run peer test", "Запустити тестування"},
|
||||
{"Reload tunnels configuration", "Перезавантажити налаштування тунелів"},
|
||||
{"Decline transit tunnels", "Відхиляти транзитні тунелі"},
|
||||
{"Accept transit tunnels", "Ухвалювати транзитні тунелі"},
|
||||
{"Cancel graceful shutdown", "Скасувати плавну зупинку"},
|
||||
@@ -149,8 +146,8 @@ namespace ukrainian // language namespace
|
||||
{"Destination not found", "Точка призначення не знайдена"},
|
||||
{"StreamID can't be null", "Ідентифікатор потоку не може бути порожнім"},
|
||||
{"Return to destination page", "Повернутися на сторінку точки призначення"},
|
||||
{"You will be redirected in %d seconds", "Ви будете переадресовані через %d секунд"},
|
||||
{"Transit tunnels count must not exceed %d", "Кількість транзитних тунелів не повинна перевищувати %d"},
|
||||
{"You will be redirected in 5 seconds", "Ви будете переадресовані через 5 секунд"},
|
||||
{"Transit tunnels count must not exceed 65535", "Кількість транзитних тунелів не повинна перевищувати 65535"},
|
||||
{"Back to commands list", "Повернутися до списку команд"},
|
||||
{"Register at reg.i2p", "Зареєструвати на reg.i2p"},
|
||||
{"Description", "Опис"},
|
||||
@@ -168,33 +165,32 @@ namespace ukrainian // language namespace
|
||||
{"You may try to find this host on jump services below", "Ви можете спробувати знайти дану адресу на джамп сервісах нижче"},
|
||||
{"Invalid request", "Некоректний запит"},
|
||||
{"Proxy unable to parse your request", "Проксі не може розібрати ваш запит"},
|
||||
{"Addresshelper is not supported", "Адресна книга не підтримується"},
|
||||
{"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>.", "Хост %s <font color=red>вже в адресній книзі маршрутизатора</font>. <b>Будьте обережні: джерело цієї адреси може зашкодити!</b> Натисніть тут, щоб оновити запис: <a href=\"%s%s%s&update=true\">Продовжити</a>."},
|
||||
{"Addresshelper forced update rejected", "Адресна книга відхилила примусове оновлення"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Щоб додати хост <b>%s</b> в адресі маршрутизатора, натисніть тут: <a href=\"%s%s%s\">Продовжити</a>."},
|
||||
{"Addresshelper request", "Запит на адресну сторінку"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Хост %s доданий в адресну книгу маршрутизатора від помічника. Натисніть тут, щоб продовжити: <a href=\"%s\">Продовжити</a>."},
|
||||
{"Addresshelper adding", "Адреса додана"},
|
||||
{"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>.", "Хост %s <font color=red>вже в адресній книзі маршрутизатора</font>. Натисніть тут, щоб оновити запис: <a href=\"%s%s%s&update=true\">Продовжити</a>."},
|
||||
{"Addresshelper update", "Оновлення адресної книги"},
|
||||
{"Invalid request URI", "Некоректний URI запиту"},
|
||||
{"addresshelper is not supported", "addresshelper не підтримується"},
|
||||
{"Host", "Адреса"},
|
||||
{"added to router's addressbook from helper", "доданий в адресну книгу маршрутизатора через хелпер"},
|
||||
{"Click here to proceed:", "Натисніть тут щоб продовжити:"},
|
||||
{"Continue", "Продовжити"},
|
||||
{"Addresshelper found", "Знайдено addresshelper"},
|
||||
{"already in router's addressbook", "вже в адресній книзі маршрутизатора"},
|
||||
{"Click here to update record:", "Натисніть тут щоб оновити запис:"},
|
||||
{"invalid request uri", "некоректний URI запиту"},
|
||||
{"Can't detect destination host from request", "Не вдалось визначити адресу призначення з запиту"},
|
||||
{"Outproxy failure", "Помилка зовнішнього проксі"},
|
||||
{"Bad outproxy settings", "Некоректні налаштування зовнішнього проксі"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Адрес %s не в I2P мережі, але зовнішній проксі не включений"},
|
||||
{"Unknown outproxy URL", "Невідомий URL зовнішнього проксі"},
|
||||
{"Cannot resolve upstream proxy", "Не вдається визначити висхідний проксі"},
|
||||
{"Hostname is too long", "Ім'я вузла надто довге"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Не вдалося підключитися до висхідного SOCKS проксі сервера"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Не вдається домовитися з висхідним SOCKS проксі"},
|
||||
{"bad outproxy settings", "некоректні налаштування зовнішнього проксі"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "не в I2P мережі, але зовнішній проксі не включений"},
|
||||
{"unknown outproxy url", "невідомий URL зовнішнього проксі"},
|
||||
{"cannot resolve upstream proxy", "не вдається визначити висхідний проксі"},
|
||||
{"hostname too long", "ім'я вузла надто довге"},
|
||||
{"cannot connect to upstream socks proxy", "не вдається підключитися до висхідного SOCKS проксі"},
|
||||
{"Cannot negotiate with socks proxy", "Не вдається домовитися з висхідним SOCKS проксі"},
|
||||
{"CONNECT error", "Помилка CONNECT запиту"},
|
||||
{"Failed to connect", "Не вдалося підключитися"},
|
||||
{"SOCKS proxy error", "Помилка SOCKS проксі"},
|
||||
{"Failed to send request to upstream", "Не вдалося відправити запит висхідному проксі"},
|
||||
{"No reply from SOCKS proxy", "Немає відповіді від SOCKS проксі сервера"},
|
||||
{"Cannot connect", "Не вдалося підключитися"},
|
||||
{"HTTP out proxy not implemented", "Підтримка зовнішнього HTTP проксі сервера не реалізована"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Не вдалося підключитися до висхідного HTTP проксі сервера"},
|
||||
{"Failed to Connect", "Не вдалося підключитися"},
|
||||
{"socks proxy error", "помилка SOCKS проксі"},
|
||||
{"failed to send request to upstream", "не вдалося відправити запит висхідному проксі"},
|
||||
{"No Reply From socks proxy", "Немає відповіді від SOCKS проксі сервера"},
|
||||
{"cannot connect", "не вдалося підключитися"},
|
||||
{"http out proxy not implemented", "підтримка зовнішнього HTTP проксі сервера не реалізована"},
|
||||
{"cannot connect to upstream http proxy", "не вдалося підключитися до висхідного HTTP проксі сервера"},
|
||||
{"Host is down", "Вузол недоступний"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Не вдалося встановити з'єднання до запитаного вузла, можливо він не в мережі. Спробуйте повторити запит пізніше."},
|
||||
{"", ""},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2021-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -40,7 +40,6 @@ namespace uzbek // language namespace
|
||||
{"established", "aloqa o'rnatildi"},
|
||||
{"unknown", "noma'lum"},
|
||||
{"exploratory", "tadqiqiy"},
|
||||
{"Purple I2P Webconsole", "Veb-konsoli Purple I2P"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> veb-konsoli"},
|
||||
{"Main page", "Asosiy sahifa"},
|
||||
{"Router commands", "Router buyruqlari"},
|
||||
@@ -58,11 +57,10 @@ namespace uzbek // language namespace
|
||||
{"Unknown", "Notanish"},
|
||||
{"Proxy", "Proksi"},
|
||||
{"Mesh", "Mesh To'r"},
|
||||
{"Error", "Xato"},
|
||||
{"Clock skew", "Aniq vaqt emas"},
|
||||
{"Offline", "Oflayn"},
|
||||
{"Symmetric NAT", "Simmetrik NAT"},
|
||||
{"Full cone NAT", "Full cone NAT"},
|
||||
{"No Descriptors", "Deskriptorlar yo'q"},
|
||||
{"Uptime", "Ish vaqti"},
|
||||
{"Network status", "Tarmoq holati"},
|
||||
{"Network status v6", "Tarmoq holati v6"},
|
||||
@@ -118,10 +116,9 @@ namespace uzbek // language namespace
|
||||
{"Gateway", "Kirish yo'li"},
|
||||
{"TunnelID", "TunnelID"},
|
||||
{"EndDate", "Tugash Sanasi"},
|
||||
{"floodfill mode is disabled", "floodfill rejimi o'chirilgan"},
|
||||
{"not floodfill", "floodfill emas"},
|
||||
{"Queue size", "Navbat hajmi"},
|
||||
{"Run peer test", "Sinovni boshlang"},
|
||||
{"Reload tunnels configuration", "Tunnel konfiguratsiyasini qayta yuklash"},
|
||||
{"Decline transit tunnels", "Tranzit tunnellarini rad etish"},
|
||||
{"Accept transit tunnels", "Tranzit tunnellarni qabul qilish"},
|
||||
{"Cancel graceful shutdown", "Yumshoq to'xtashni bekor qilish"},
|
||||
@@ -149,8 +146,8 @@ namespace uzbek // language namespace
|
||||
{"Destination not found", "Yo'nalish topilmadi"},
|
||||
{"StreamID can't be null", "StreamID bo'sh bo'lishi mumkin emas"},
|
||||
{"Return to destination page", "Manzilgoh sahifasiga qaytish"},
|
||||
{"You will be redirected in %d seconds", "Siz %d soniyadan so‘ng boshqa yo‘nalishga yo‘naltirilasiz"},
|
||||
{"Transit tunnels count must not exceed %d", "Tranzit tunnellar soni %d dan oshmasligi kerak"},
|
||||
{"You will be redirected in 5 seconds", "Siz 5 soniya ichida qayta yo'naltirilasiz"},
|
||||
{"Transit tunnels count must not exceed 65535", "Tranzit tunnellar soni 65535 dan oshmasligi kerak"},
|
||||
{"Back to commands list", "Buyruqlar ro'yxatiga qaytish"},
|
||||
{"Register at reg.i2p", "Reg.i2p-da ro'yxatdan o'ting"},
|
||||
{"Description", "Tavsif"},
|
||||
@@ -168,33 +165,32 @@ namespace uzbek // language namespace
|
||||
{"You may try to find this host on jump services below", "Siz xost quyida o'tish xizmatlari orqali topishga harakat qilishingiz mumkin"},
|
||||
{"Invalid request", "Noto‘g‘ri so‘rov"},
|
||||
{"Proxy unable to parse your request", "Proksi sizning so'rovingizni aniqlab ololmayapti"},
|
||||
{"Addresshelper is not supported", "Addresshelper qo'llab-quvvatlanmaydi"},
|
||||
{"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>.", "%s xosti <font color=red>allaqachon routerning manzillar kitobida</font>. <b>Ehtiyot bo'ling: bu URL manbasi zararli bo'lishi mumkin!</b> Yozuvni yangilash uchun bu yerni bosing: <a href=\"%s%s%s&update=true\">Davom etish</a>."},
|
||||
{"Addresshelper forced update rejected", "Addresshelperni majburiy yangilash rad etildi"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Routerning manzillar kitobiga <b>%s</b> xostini qo'shish uchun bu yerni bosing: <a href=\"%s%s%s\">Davom etish</a>."},
|
||||
{"Addresshelper request", "Addresshelper so'rovi"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Yordamchidan router manzillar kitobiga %s xost qo‘shildi. Davom etish uchun bu yerga bosing: <a href=\"%s\">Davom etish</a>."},
|
||||
{"Addresshelper adding", "Addresshelperni qo'shish"},
|
||||
{"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>.", "%s xosti <font color=red>allaqachon routerning manzillar kitobida</font>. Yozuvni yangilash uchun shu yerni bosing: <a href=\"%s%s%s&update=true\">Davom etish</a>."},
|
||||
{"Addresshelper update", "Addresshelperni yangilash"},
|
||||
{"Invalid request URI", "Noto'g'ri URI so'rovi"},
|
||||
{"addresshelper is not supported", "addresshelper qo'llab -quvvatlanmaydi"},
|
||||
{"Host", "Xost"},
|
||||
{"added to router's addressbook from helper", "'helper'dan routerning 'addressbook'ga qo'shildi"},
|
||||
{"Click here to proceed:", "Davom etish uchun shu yerni bosing:"},
|
||||
{"Continue", "Davom etish"},
|
||||
{"Addresshelper found", "Addresshelper topildi"},
|
||||
{"already in router's addressbook", "allaqachon 'addressbook'da yozilgan"},
|
||||
{"Click here to update record:", "Yozuvni yangilash uchun shu yerni bosing:"},
|
||||
{"invalid request uri", "noto'g'ri URI so'rovi"},
|
||||
{"Can't detect destination host from request", "So‘rov orqali manzil xostini aniqlab bo'lmayapti"},
|
||||
{"Outproxy failure", "Tashqi proksi muvaffaqiyatsizligi"},
|
||||
{"Bad outproxy settings", "Noto'g'ri tashqi proksi-server sozlamalari"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Xost %s I2P tarmog'ida emas, lekin tashqi proksi yoqilmagan"},
|
||||
{"Unknown outproxy URL", "Noma'lum outproxy URL"},
|
||||
{"Cannot resolve upstream proxy", "Yuqoridagi 'proxy-server'ni aniqlab olib bolmayapti"},
|
||||
{"Hostname is too long", "Xost nomi juda uzun"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Yuqori 'SOCKS proxy'ga ulanib bo'lmayapti"},
|
||||
{"Cannot negotiate with SOCKS proxy", "'SOCKS proxy' bilan muzokara olib bo'lmaydi"},
|
||||
{"bad outproxy settings", "noto'g'ri tashqi proksi-server sozlamalari"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "I2P tarmog'ida emas, lekin tashqi proksi yoqilmagan"},
|
||||
{"unknown outproxy url", "noma'lum outproxy url"},
|
||||
{"cannot resolve upstream proxy", "yuqoridagi 'proxy-server'ni aniqlab olib bolmayapti"},
|
||||
{"hostname too long", "xost nomi juda uzun"},
|
||||
{"cannot connect to upstream socks proxy", "yuqori 'socks proxy'ga ulanib bo'lmayapti"},
|
||||
{"Cannot negotiate with socks proxy", "'Socks proxy' bilan muzokara olib bo'lmaydi"},
|
||||
{"CONNECT error", "CONNECT xatosi"},
|
||||
{"Failed to connect", "Ulanib bo'lmayapti"},
|
||||
{"SOCKS proxy error", "'SOCKS proxy' xatosi"},
|
||||
{"Failed to send request to upstream", "Yuqori proksi-serveriga so'rovni uborib bo'lmadi"},
|
||||
{"No reply from SOCKS proxy", "'SOCKS proxy'dan javob yo'q"},
|
||||
{"Cannot connect", "Ulanib bo'lmaydi"},
|
||||
{"HTTP out proxy not implemented", "Tashqi HTTP proksi-serverni qo'llab-quvvatlash amalga oshirilmagan"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Yuqori 'HTTP proxy'ga ulanib bo'lmayapti"},
|
||||
{"Failed to Connect", "Ulanib bo'lmayapti"},
|
||||
{"socks proxy error", "'socks proxy' xatosi"},
|
||||
{"failed to send request to upstream", "yuqori http proksi-serveriga so'rovni uborib bo'lmadi"},
|
||||
{"No Reply From socks proxy", "'Socks proxy'dan javob yo'q"},
|
||||
{"cannot connect", "ulanib bo'lmaydi"},
|
||||
{"http out proxy not implemented", "tashqi HTTP proksi-serverni qo'llab-quvvatlash amalga oshirilmagan"},
|
||||
{"cannot connect to upstream http proxy", "yuqori http 'proxy-server'iga ulanib bo'lmayapti"},
|
||||
{"Host is down", "Xost ishlamayapti"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Talab qilingan xost bilan aloqa o'rnatilmadi, u ishlamay qolishi mumkin. Iltimos keyinroq qayta urinib ko'ring."},
|
||||
{"", ""},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -45,7 +45,7 @@ namespace config {
|
||||
("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)")
|
||||
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
|
||||
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
|
||||
("host", value<std::string>()->default_value(""), "External IP")
|
||||
("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
|
||||
("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
|
||||
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4")
|
||||
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6")
|
||||
@@ -78,7 +78,6 @@ namespace config {
|
||||
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
|
||||
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
|
||||
("limits.transittunnels", value<uint16_t>()->default_value(5000), "Maximum active transit tunnels (default:5000)")
|
||||
("limits.zombies", value<double>()->default_value(0), "Minimum percentage of successfully created tunnels under which tunnel cleanup is paused (default [%]: 0.00)")
|
||||
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored")
|
||||
("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored")
|
||||
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored")
|
||||
@@ -96,7 +95,6 @@ namespace config {
|
||||
("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI")
|
||||
("http.webroot", value<std::string>()->default_value("/"), "WebUI root path (default: / )")
|
||||
("http.lang", value<std::string>()->default_value("english"), "WebUI language (default: english )")
|
||||
("http.showTotalTCSR", value<bool>()->default_value(false), "Show additional value with total TCSR since router's start (default: false)")
|
||||
;
|
||||
|
||||
options_description httpproxy("HTTP Proxy options");
|
||||
@@ -150,8 +148,7 @@ namespace config {
|
||||
sam.add_options()
|
||||
("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge")
|
||||
("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address")
|
||||
("sam.port", value<uint16_t>()->default_value(7656), "SAM listen TCP port")
|
||||
("sam.portudp", value<uint16_t>()->default_value(0), "SAM listen UDP port")
|
||||
("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port")
|
||||
("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread")
|
||||
;
|
||||
|
||||
@@ -217,11 +214,10 @@ namespace config {
|
||||
"https://reseed.onion.im/,"
|
||||
"https://i2pseed.creativecowpat.net:8443/,"
|
||||
"https://reseed.i2pgit.org/,"
|
||||
"https://i2p.novg.net/,"
|
||||
"https://banana.incognet.io/,"
|
||||
"https://reseed-pl.i2pd.xyz/,"
|
||||
"https://www2.mk16.de/,"
|
||||
"https://i2p.ghativega.in/,"
|
||||
"https://i2p.novg.net/"
|
||||
"https://www2.mk16.de/"
|
||||
), "Reseed URLs, separated by comma")
|
||||
("reseed.yggurls", value<std::string>()->default_value(
|
||||
"http://[324:71e:281a:9ed3::ace]:7070/,"
|
||||
@@ -288,7 +284,7 @@ namespace config {
|
||||
|
||||
options_description nettime("Time sync options");
|
||||
nettime.add_options()
|
||||
("nettime.enabled", value<bool>()->default_value(false), "Enable NTP time sync (default: disabled)")
|
||||
("nettime.enabled", value<bool>()->default_value(false), "Disable time sync (default: disabled)")
|
||||
("nettime.ntpservers", value<std::string>()->default_value(
|
||||
"0.pool.ntp.org,"
|
||||
"1.pool.ntp.org,"
|
||||
|
||||
@@ -555,7 +555,7 @@ namespace crypto
|
||||
}
|
||||
|
||||
// AES
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
#define KeyExpansion256(round0,round1) \
|
||||
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
|
||||
"movaps %%xmm1, %%xmm4 \n" \
|
||||
@@ -580,7 +580,7 @@ namespace crypto
|
||||
"movaps %%xmm3, "#round1"(%[sched]) \n"
|
||||
#endif
|
||||
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
void ECBCryptoAESNI::ExpandKey (const AESKey& key)
|
||||
{
|
||||
__asm__
|
||||
@@ -621,7 +621,7 @@ namespace crypto
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
#define EncryptAES256(sched) \
|
||||
"pxor (%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 16(%["#sched"]), %%xmm0 \n" \
|
||||
@@ -642,7 +642,7 @@ namespace crypto
|
||||
|
||||
void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
@@ -660,7 +660,7 @@ namespace crypto
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
#define DecryptAES256(sched) \
|
||||
"pxor 224(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 208(%["#sched"]), %%xmm0 \n" \
|
||||
@@ -681,7 +681,7 @@ namespace crypto
|
||||
|
||||
void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
@@ -699,7 +699,7 @@ namespace crypto
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
#define CallAESIMC(offset) \
|
||||
"movaps "#offset"(%[shed]), %%xmm0 \n" \
|
||||
"aesimc %%xmm0, %%xmm0 \n" \
|
||||
@@ -708,7 +708,7 @@ namespace crypto
|
||||
|
||||
void ECBEncryption::SetKey (const AESKey& key)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
ExpandKey (key);
|
||||
@@ -722,7 +722,7 @@ namespace crypto
|
||||
|
||||
void ECBDecryption::SetKey (const AESKey& key)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
ExpandKey (key); // expand encryption key first
|
||||
@@ -754,7 +754,7 @@ namespace crypto
|
||||
|
||||
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
@@ -799,7 +799,7 @@ namespace crypto
|
||||
|
||||
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
@@ -823,7 +823,7 @@ namespace crypto
|
||||
|
||||
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
@@ -869,7 +869,7 @@ namespace crypto
|
||||
|
||||
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
@@ -893,7 +893,7 @@ namespace crypto
|
||||
|
||||
void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
@@ -934,7 +934,7 @@ namespace crypto
|
||||
|
||||
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#if defined(__AES__) && (defined(__x86_64__) || defined(__i386__))
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -425,7 +425,7 @@ namespace datagram
|
||||
if (m)
|
||||
send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID, m});
|
||||
}
|
||||
routingPath->outboundTunnel->SendTunnelDataMsgs(send);
|
||||
routingPath->outboundTunnel->SendTunnelDataMsg(send);
|
||||
}
|
||||
m_SendQueue.clear();
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace client
|
||||
if (authType >= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE && authType <= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK)
|
||||
m_AuthType = authType;
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Unknown auth type: ", authType);
|
||||
LogPrint (eLogError, "Destination: Unknown auth type ", authType);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_LEASESET_PRIV_KEY);
|
||||
@@ -117,7 +117,7 @@ namespace client
|
||||
m_LeaseSetPrivKey.reset (new i2p::data::Tag<32>());
|
||||
if (m_LeaseSetPrivKey->FromBase64 (it->second) != 32)
|
||||
{
|
||||
LogPrint(eLogCritical, "Destination: Invalid value i2cp.leaseSetPrivKey: ", it->second);
|
||||
LogPrint(eLogError, "Destination: Invalid value i2cp.leaseSetPrivKey ", it->second);
|
||||
m_LeaseSetPrivKey.reset (nullptr);
|
||||
}
|
||||
}
|
||||
@@ -262,6 +262,17 @@ namespace client
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ls = i2p::data::netdb.FindLeaseSet (ident);
|
||||
if (ls && !ls->IsExpired ())
|
||||
{
|
||||
ls->PopulateLeases (); // since we don't store them in netdb
|
||||
std::lock_guard<std::mutex> _lock(m_RemoteLeaseSetsMutex);
|
||||
m_RemoteLeaseSets[ident] = ls;
|
||||
return ls;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -388,11 +399,6 @@ namespace client
|
||||
|
||||
void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (len < DATABASE_STORE_HEADER_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Database store msg is too short ", len);
|
||||
return;
|
||||
}
|
||||
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
|
||||
size_t offset = DATABASE_STORE_HEADER_SIZE;
|
||||
if (replyToken)
|
||||
@@ -400,11 +406,6 @@ namespace client
|
||||
LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore");
|
||||
offset += 36;
|
||||
}
|
||||
if (offset > len || len > i2p::data::MAX_LS_BUFFER_SIZE + offset)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Database store message is too long ", len);
|
||||
return;
|
||||
}
|
||||
i2p::data::IdentHash key (buf + DATABASE_STORE_KEY_OFFSET);
|
||||
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
|
||||
switch (buf[DATABASE_STORE_TYPE_OFFSET])
|
||||
@@ -466,15 +467,12 @@ namespace client
|
||||
{
|
||||
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset,
|
||||
it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ());
|
||||
if (ls2->IsValid () && !ls2->IsExpired ())
|
||||
if (ls2->IsValid ())
|
||||
{
|
||||
leaseSet = ls2;
|
||||
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
|
||||
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
|
||||
m_RemoteLeaseSets[key] = ls2; // also store as key for next lookup
|
||||
leaseSet = ls2;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Destination: New remote encrypted LeaseSet2 failed");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "Destination: Couldn't find request for encrypted LeaseSet2");
|
||||
@@ -624,7 +622,7 @@ namespace client
|
||||
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
||||
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0, msg);
|
||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
|
||||
m_LastSubmissionTime = ts;
|
||||
}
|
||||
|
||||
@@ -765,17 +763,9 @@ namespace client
|
||||
request->requestTime = ts;
|
||||
if (!SendLeaseSetRequest (dest, floodfill, request))
|
||||
{
|
||||
// try another
|
||||
LogPrint (eLogWarning, "Destination: Couldn't send LeaseSet request to ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another");
|
||||
request->excluded.insert (floodfill->GetIdentHash ());
|
||||
floodfill = i2p::data::netdb.GetClosestFloodfill (dest, request->excluded);
|
||||
if (!SendLeaseSetRequest (dest, floodfill, request))
|
||||
{
|
||||
// request failed
|
||||
LogPrint (eLogWarning, "Destination: LeaseSet request for ", dest.ToBase32 (), " was not sent");
|
||||
m_LeaseSetRequests.erase (ret.first);
|
||||
if (requestComplete) requestComplete (nullptr);
|
||||
}
|
||||
// request failed
|
||||
m_LeaseSetRequests.erase (ret.first);
|
||||
if (requestComplete) requestComplete (nullptr);
|
||||
}
|
||||
}
|
||||
else // duplicate
|
||||
@@ -802,11 +792,11 @@ namespace client
|
||||
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
|
||||
{
|
||||
if (!request->replyTunnel || !request->replyTunnel->IsEstablished ())
|
||||
request->replyTunnel = m_Pool->GetNextInboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (false)); // outbound from floodfill
|
||||
if (!request->replyTunnel) LogPrint (eLogWarning, "Destination: Can't send LeaseSet request, no compatible inbound tunnels found");
|
||||
request->replyTunnel = m_Pool->GetNextInboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (true));
|
||||
if (!request->replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no inbound tunnels found");
|
||||
if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ())
|
||||
request->outboundTunnel = m_Pool->GetNextOutboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (true)); // inbound from floodfill
|
||||
if (!request->outboundTunnel) LogPrint (eLogWarning, "Destination: Can't send LeaseSet request, no compatible outbound tunnels found");
|
||||
request->outboundTunnel = m_Pool->GetNextOutboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (false));
|
||||
if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
|
||||
|
||||
if (request->replyTunnel && request->outboundTunnel)
|
||||
{
|
||||
@@ -824,7 +814,7 @@ namespace client
|
||||
AddSessionKey (replyKey, replyTag);
|
||||
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
|
||||
request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
|
||||
request->outboundTunnel->SendTunnelDataMsgs (
|
||||
request->outboundTunnel->SendTunnelDataMsg (
|
||||
{
|
||||
i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
@@ -919,7 +909,7 @@ namespace client
|
||||
bool isPublic, const std::map<std::string, std::string> * params):
|
||||
LeaseSetDestination (service, isPublic, params),
|
||||
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
||||
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0),
|
||||
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS),
|
||||
m_DatagramDestination (nullptr), m_RefCounter (0),
|
||||
m_ReadyChecker(service)
|
||||
{
|
||||
@@ -989,7 +979,7 @@ namespace client
|
||||
m_StreamingAckDelay = std::stoi(it->second);
|
||||
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
|
||||
if (it != params->end ())
|
||||
m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true
|
||||
m_IsStreamingAnswerPings = (it->second == "true");
|
||||
|
||||
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||
{
|
||||
@@ -1003,12 +993,12 @@ namespace client
|
||||
else if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK)
|
||||
ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_PSK, params);
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Unexpected auth type: ", authType);
|
||||
LogPrint (eLogError, "Destination: Unexpected auth type ", authType);
|
||||
if (m_AuthKeys->size ())
|
||||
LogPrint (eLogInfo, "Destination: ", m_AuthKeys->size (), " auth keys read");
|
||||
else
|
||||
{
|
||||
LogPrint (eLogCritical, "Destination: No auth keys read for auth type: ", authType);
|
||||
LogPrint (eLogError, "Destination: No auth keys read for auth type ", authType);
|
||||
m_AuthKeys = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -1017,7 +1007,7 @@ namespace client
|
||||
}
|
||||
catch (std::exception & ex)
|
||||
{
|
||||
LogPrint(eLogCritical, "Destination: Unable to parse parameters for destination: ", ex.what());
|
||||
LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1036,30 +1026,22 @@ namespace client
|
||||
|
||||
void ClientDestination::Stop ()
|
||||
{
|
||||
LogPrint(eLogDebug, "Destination: Stopping destination ", GetIdentHash().ToBase32(), ".b32.i2p");
|
||||
LeaseSetDestination::Stop ();
|
||||
m_ReadyChecker.cancel();
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination");
|
||||
m_StreamingDestination->Stop ();
|
||||
//m_StreamingDestination->SetOwner (nullptr);
|
||||
m_StreamingDestination = nullptr;
|
||||
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination by ports");
|
||||
for (auto& it: m_StreamingDestinationsByPorts)
|
||||
{
|
||||
it.second->Stop ();
|
||||
//it.second->SetOwner (nullptr);
|
||||
}
|
||||
m_StreamingDestinationsByPorts.clear ();
|
||||
m_LastStreamingDestination = nullptr;
|
||||
|
||||
if (m_DatagramDestination)
|
||||
{
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping Datagram Destination");
|
||||
delete m_DatagramDestination;
|
||||
m_DatagramDestination = nullptr;
|
||||
}
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping done");
|
||||
}
|
||||
|
||||
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
||||
@@ -1079,15 +1061,9 @@ namespace client
|
||||
case PROTOCOL_TYPE_STREAMING:
|
||||
{
|
||||
// streaming protocol
|
||||
if (toPort != m_LastPort || !m_LastStreamingDestination)
|
||||
{
|
||||
m_LastStreamingDestination = GetStreamingDestination (toPort);
|
||||
if (!m_LastStreamingDestination)
|
||||
m_LastStreamingDestination = m_StreamingDestination; // if no destination on port use default
|
||||
m_LastPort = toPort;
|
||||
}
|
||||
if (m_LastStreamingDestination)
|
||||
m_LastStreamingDestination->HandleDataMessagePayload (buf, length);
|
||||
auto dest = GetStreamingDestination (toPort);
|
||||
if (dest)
|
||||
dest->HandleDataMessagePayload (buf, length);
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Missing streaming destination");
|
||||
}
|
||||
@@ -1111,7 +1087,7 @@ namespace client
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, uint16_t port)
|
||||
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port)
|
||||
{
|
||||
if (!streamRequestComplete)
|
||||
{
|
||||
@@ -1141,7 +1117,7 @@ namespace client
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port)
|
||||
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port)
|
||||
{
|
||||
if (!streamRequestComplete)
|
||||
{
|
||||
@@ -1160,7 +1136,7 @@ namespace client
|
||||
}
|
||||
|
||||
template<typename Dest>
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStreamSync (const Dest& dest, uint16_t port)
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStreamSync (const Dest& dest, int port)
|
||||
{
|
||||
volatile bool done = false;
|
||||
std::shared_ptr<i2p::stream::Stream> stream;
|
||||
@@ -1176,25 +1152,25 @@ namespace client
|
||||
},
|
||||
dest, port);
|
||||
while (!done)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> l(streamRequestCompleteMutex);
|
||||
if (!done)
|
||||
streamRequestComplete.wait (l);
|
||||
}
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::IdentHash& dest, uint16_t port)
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::IdentHash& dest, int port)
|
||||
{
|
||||
return CreateStreamSync (dest, port);
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port)
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port)
|
||||
{
|
||||
return CreateStreamSync (dest, port);
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, uint16_t port)
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
|
||||
{
|
||||
if (m_StreamingDestination)
|
||||
return m_StreamingDestination->CreateNewOutgoingStream (remote, port);
|
||||
@@ -1231,7 +1207,7 @@ namespace client
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (uint16_t port) const
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
|
||||
{
|
||||
if (port)
|
||||
{
|
||||
@@ -1239,9 +1215,8 @@ namespace client
|
||||
if (it != m_StreamingDestinationsByPorts.end ())
|
||||
return it->second;
|
||||
}
|
||||
else // if port is zero, use default destination
|
||||
return m_StreamingDestination;
|
||||
return nullptr;
|
||||
// if port is zero or not found, use default destination
|
||||
return m_StreamingDestination;
|
||||
}
|
||||
|
||||
void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor)
|
||||
@@ -1269,7 +1244,7 @@ namespace client
|
||||
m_StreamingDestination->AcceptOnce (acceptor);
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (uint16_t port, bool gzip)
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port, bool gzip)
|
||||
{
|
||||
auto dest = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis (), port, gzip);
|
||||
if (port)
|
||||
@@ -1279,7 +1254,7 @@ namespace client
|
||||
return dest;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::RemoveStreamingDestination (uint16_t port)
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::RemoveStreamingDestination (int port)
|
||||
{
|
||||
if (port)
|
||||
{
|
||||
@@ -1340,7 +1315,7 @@ namespace client
|
||||
f1.write ((char *)keys->priv, 256);
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogCritical, "Destinations: Can't save keys to ", path);
|
||||
LogPrint(eLogError, "Destinations: Can't save keys to ", path);
|
||||
}
|
||||
|
||||
void ClientDestination::CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels)
|
||||
@@ -1417,7 +1392,7 @@ namespace client
|
||||
if (pubKey.FromBase64 (it.second.substr (pos+1)))
|
||||
m_AuthKeys->push_back (pubKey);
|
||||
else
|
||||
LogPrint (eLogCritical, "Destination: Unexpected auth key: ", it.second.substr (pos+1));
|
||||
LogPrint (eLogError, "Destination: Unexpected auth key ", it.second.substr (pos+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
@@ -185,8 +184,8 @@ namespace client
|
||||
|
||||
boost::asio::io_service& m_Service;
|
||||
mutable std::mutex m_RemoteLeaseSetsMutex;
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
||||
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
||||
std::mutex m_LeaseSetMutex;
|
||||
@@ -242,15 +241,15 @@ namespace client
|
||||
int GetRefCounter () const { return m_RefCounter; };
|
||||
|
||||
// streaming
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (uint16_t port, bool gzip = true); // additional
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (uint16_t port = 0) const;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination (uint16_t port);
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination (int port);
|
||||
// following methods operate with default streaming destination
|
||||
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, uint16_t port = 0);
|
||||
void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port = 0);
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::IdentHash& dest, uint16_t port = 0); // sync
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port = 0); // sync
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, uint16_t port = 0);
|
||||
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
|
||||
void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0);
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::IdentHash& dest, int port = 0); // sync
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0); // sync
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||
void SendPing (const i2p::data::IdentHash& to);
|
||||
void SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to);
|
||||
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
|
||||
@@ -286,7 +285,7 @@ namespace client
|
||||
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
|
||||
|
||||
template<typename Dest>
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStreamSync (const Dest& dest, uint16_t port);
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStreamSync (const Dest& dest, int port);
|
||||
|
||||
private:
|
||||
|
||||
@@ -298,7 +297,6 @@ namespace client
|
||||
bool m_IsStreamingAnswerPings;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
||||
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
|
||||
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
||||
int m_RefCounter; // how many clients(tunnels) use this destination
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -335,8 +335,7 @@ namespace garlic
|
||||
case eECIESx25519BlkAckRequest:
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: Ack request");
|
||||
if (receiveTagset)
|
||||
m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index});
|
||||
m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index});
|
||||
break;
|
||||
}
|
||||
case eECIESx25519BlkTermination:
|
||||
@@ -1150,7 +1149,7 @@ namespace garlic
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
auto m = NewI2NPMessage ((msg ? msg->GetPayloadLength () : 0) + 128);
|
||||
auto m = NewI2NPMessage ();
|
||||
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
||||
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
|
||||
size_t offset = 0;
|
||||
@@ -1176,7 +1175,7 @@ namespace garlic
|
||||
// Noise_N, we are Alice, routerPublicKey is Bob's
|
||||
i2p::crypto::NoiseSymmetricState noiseState;
|
||||
i2p::crypto::InitNoiseNState (noiseState, routerPublicKey);
|
||||
auto m = NewI2NPMessage ((msg ? msg->GetPayloadLength () : 0) + 128);
|
||||
auto m = NewI2NPMessage ();
|
||||
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
||||
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
|
||||
size_t offset = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -413,7 +413,7 @@ namespace crypto
|
||||
BIGNUM * y = BN_new ();
|
||||
BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y);
|
||||
BIGNUM * x = RecoverX (y, ctx);
|
||||
if ((bool)BN_is_bit_set (x, 0) != isHighestBitSet)
|
||||
if (BN_is_bit_set (x, 0) != isHighestBitSet)
|
||||
BN_sub (x, q, x); // x = q - x
|
||||
BIGNUM * z = BN_new (), * t = BN_new ();
|
||||
BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -88,7 +88,7 @@ namespace data
|
||||
}
|
||||
EVP_PKEY_free (pkey);
|
||||
if (verifier && cn)
|
||||
m_SigningKeys.emplace (cn, std::make_pair(verifier, (int)m_SigningKeys.size () + 1));
|
||||
m_SigningKeys.emplace (cn, std::make_pair(verifier, m_SigningKeys.size () + 1));
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -588,7 +588,7 @@ namespace garlic
|
||||
auto it = m_ECIESx25519Tags.find (tag);
|
||||
if (it != m_ECIESx25519Tags.end ())
|
||||
{
|
||||
if (it->second.tagset && it->second.tagset->HandleNextMessage (buf, len, it->second.index))
|
||||
if (it->second.tagset->HandleNextMessage (buf, len, it->second.index))
|
||||
m_LastTagset = it->second.tagset;
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||
@@ -709,7 +709,7 @@ namespace garlic
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
|
||||
if (tunnel) // we have sent it through an outbound tunnel
|
||||
tunnel->SendTunnelDataMsgTo (gwHash, gwTunnel, msg);
|
||||
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg);
|
||||
else
|
||||
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
|
||||
}
|
||||
@@ -1075,7 +1075,7 @@ namespace garlic
|
||||
{
|
||||
auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel ();
|
||||
if (tunnel)
|
||||
tunnel->SendTunnelDataMsgTo (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset, msgID));
|
||||
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset, msgID));
|
||||
else
|
||||
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace data
|
||||
if (m_IsDirty) deflateReset (&m_Deflator);
|
||||
m_IsDirty = true;
|
||||
size_t offset = 0;
|
||||
int err = 0;
|
||||
int err;
|
||||
for (const auto& it: bufs)
|
||||
{
|
||||
m_Deflator.next_in = const_cast<uint8_t *>(it.first);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -93,18 +93,15 @@ namespace http
|
||||
std::size_t pos_c = 0; /* < work position */
|
||||
if(url.at(0) != '/' || pos_p > 0) {
|
||||
std::size_t pos_s = 0;
|
||||
|
||||
/* schema */
|
||||
pos_c = url.find("://");
|
||||
if (pos_c != std::string::npos) {
|
||||
schema = url.substr(0, pos_c);
|
||||
pos_p = pos_c + 3;
|
||||
}
|
||||
|
||||
/* user[:pass] */
|
||||
pos_s = url.find('/', pos_p); /* find first slash */
|
||||
pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */
|
||||
|
||||
if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) {
|
||||
std::size_t delim = url.find(':', pos_p);
|
||||
if (delim && delim != std::string::npos && delim < pos_c) {
|
||||
@@ -116,28 +113,21 @@ namespace http
|
||||
}
|
||||
pos_p = pos_c + 1;
|
||||
}
|
||||
|
||||
/* hostname[:port][/path] */
|
||||
if (url.at(pos_p) == '[') // ipv6
|
||||
if (url[pos_p] == '[') // ipv6
|
||||
{
|
||||
auto pos_b = url.find(']', pos_p);
|
||||
if (pos_b == std::string::npos) return false;
|
||||
ipv6 = true;
|
||||
pos_c = url.find_first_of(":/", pos_b);
|
||||
}
|
||||
else
|
||||
pos_c = url.find_first_of(":/", pos_p);
|
||||
|
||||
if (pos_c == std::string::npos) {
|
||||
/* only hostname, without post and path */
|
||||
host = ipv6 ?
|
||||
url.substr(pos_p + 1, url.length() - 1) :
|
||||
url.substr(pos_p, std::string::npos);
|
||||
host = url.substr(pos_p, std::string::npos);
|
||||
return true;
|
||||
} else if (url.at(pos_c) == ':') {
|
||||
host = ipv6 ?
|
||||
url.substr(pos_p + 1, pos_c - pos_p - 2) :
|
||||
url.substr(pos_p, pos_c - pos_p);
|
||||
host = url.substr(pos_p, pos_c - pos_p);
|
||||
/* port[/path] */
|
||||
pos_p = pos_c + 1;
|
||||
pos_c = url.find('/', pos_p);
|
||||
@@ -157,9 +147,7 @@ namespace http
|
||||
pos_p = pos_c;
|
||||
} else {
|
||||
/* start of path part found */
|
||||
host = ipv6 ?
|
||||
url.substr(pos_p + 1, pos_c - pos_p - 2) :
|
||||
url.substr(pos_p, pos_c - pos_p);
|
||||
host = url.substr(pos_p, pos_c - pos_p);
|
||||
pos_p = pos_c;
|
||||
}
|
||||
}
|
||||
@@ -172,7 +160,6 @@ namespace http
|
||||
return true;
|
||||
} else if (url.at(pos_c) == '?') {
|
||||
/* found query part */
|
||||
hasquery = true;
|
||||
path = url.substr(pos_p, pos_c - pos_p);
|
||||
pos_p = pos_c + 1;
|
||||
pos_c = url.find('#', pos_p);
|
||||
@@ -224,25 +211,15 @@ namespace http
|
||||
} else if (user != "") {
|
||||
out += user + "@";
|
||||
}
|
||||
if (ipv6) {
|
||||
if (port) {
|
||||
out += "[" + host + "]:" + std::to_string(port);
|
||||
} else {
|
||||
out += "[" + host + "]";
|
||||
}
|
||||
if (port) {
|
||||
out += host + ":" + std::to_string(port);
|
||||
} else {
|
||||
if (port) {
|
||||
out += host + ":" + std::to_string(port);
|
||||
} else {
|
||||
out += host;
|
||||
}
|
||||
out += host;
|
||||
}
|
||||
}
|
||||
out += path;
|
||||
if (hasquery) // add query even if it was empty
|
||||
out += "?";
|
||||
if (query != "")
|
||||
out += query;
|
||||
out += "?" + query;
|
||||
if (frag != "")
|
||||
out += "#" + frag;
|
||||
return out;
|
||||
@@ -370,14 +347,6 @@ namespace http
|
||||
return "";
|
||||
}
|
||||
|
||||
size_t HTTPReq::GetNumHeaders (const std::string& name) const
|
||||
{
|
||||
size_t num = 0;
|
||||
for (auto& it : headers)
|
||||
if (it.first == name) num++;
|
||||
return num;
|
||||
}
|
||||
|
||||
bool HTTPRes::is_chunked() const
|
||||
{
|
||||
auto it = headers.find("Transfer-Encoding");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -33,12 +33,10 @@ namespace http
|
||||
std::string host;
|
||||
unsigned short int port;
|
||||
std::string path;
|
||||
bool hasquery;
|
||||
std::string query;
|
||||
std::string frag;
|
||||
bool ipv6;
|
||||
|
||||
URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), hasquery(false), query(""), frag(""), ipv6(false) {};
|
||||
URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), query(""), frag("") {};
|
||||
|
||||
/**
|
||||
* @brief Tries to parse url from string
|
||||
@@ -103,8 +101,6 @@ namespace http
|
||||
void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt
|
||||
void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); };
|
||||
std::string GetHeader (const std::string& name) const;
|
||||
size_t GetNumHeaders (const std::string& name) const;
|
||||
size_t GetNumHeaders () const { return headers.size (); };
|
||||
};
|
||||
|
||||
struct HTTPRes : HTTPMsg {
|
||||
|
||||
@@ -36,11 +36,6 @@ namespace i2p
|
||||
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >();
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMediumMessage ()
|
||||
{
|
||||
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MEDIUM_MESSAGE_SIZE> >();
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint)
|
||||
{
|
||||
return i2p::tunnel::tunnels.NewI2NPTunnelMessage (endpoint);
|
||||
@@ -48,10 +43,7 @@ namespace i2p
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
|
||||
{
|
||||
len += I2NP_HEADER_SIZE + 2;
|
||||
if (len <= I2NP_MAX_SHORT_MESSAGE_SIZE) return NewI2NPShortMessage ();
|
||||
if (len <= I2NP_MAX_MEDIUM_MESSAGE_SIZE) return NewI2NPMediumMessage ();
|
||||
return NewI2NPMessage ();
|
||||
return (len < I2NP_MAX_SHORT_MESSAGE_SIZE - I2NP_HEADER_SIZE - 2) ? NewI2NPShortMessage () : NewI2NPMessage ();
|
||||
}
|
||||
|
||||
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID, bool checksum)
|
||||
@@ -134,8 +126,7 @@ namespace i2p
|
||||
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
|
||||
{
|
||||
int cnt = excludedPeers ? excludedPeers->size () : 0;
|
||||
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
|
||||
auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ();
|
||||
uint8_t * buf = m->GetPayload ();
|
||||
memcpy (buf, key, 32); // key
|
||||
buf += 32;
|
||||
@@ -156,6 +147,7 @@ namespace i2p
|
||||
|
||||
if (excludedPeers)
|
||||
{
|
||||
int cnt = excludedPeers->size ();
|
||||
htobe16buf (buf, cnt);
|
||||
buf += 2;
|
||||
for (auto& it: *excludedPeers)
|
||||
@@ -361,6 +353,21 @@ namespace i2p
|
||||
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
|
||||
}
|
||||
|
||||
static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
|
||||
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
|
||||
{
|
||||
if (maxNumTransitTunnels > 0 && g_MaxNumTransitTunnels != maxNumTransitTunnels)
|
||||
{
|
||||
LogPrint (eLogDebug, "I2NP: Max number of transit tunnels set to ", maxNumTransitTunnels);
|
||||
g_MaxNumTransitTunnels = maxNumTransitTunnels;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t GetMaxNumTransitTunnels ()
|
||||
{
|
||||
return g_MaxNumTransitTunnels;
|
||||
}
|
||||
|
||||
static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
|
||||
{
|
||||
for (int i = 0; i < num; i++)
|
||||
@@ -372,7 +379,10 @@ namespace i2p
|
||||
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false;
|
||||
uint8_t retCode = 0;
|
||||
// replace record to reply
|
||||
if (i2p::context.AcceptsTunnels () && !i2p::context.IsHighCongestion ())
|
||||
if (i2p::context.AcceptsTunnels () &&
|
||||
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
|
||||
!i2p::transport::transports.IsBandwidthExceeded () &&
|
||||
!i2p::transport::transports.IsTransitBandwidthExceeded ())
|
||||
{
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
@@ -424,11 +434,6 @@ namespace i2p
|
||||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
|
||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Too many records in VaribleTunnelBuild message ", num);
|
||||
return;
|
||||
}
|
||||
if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len);
|
||||
@@ -482,11 +487,6 @@ namespace i2p
|
||||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
|
||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Too many records in TunnelBuildReply message ", num);
|
||||
return;
|
||||
}
|
||||
size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE;
|
||||
if (len < num*recordSize + 1)
|
||||
{
|
||||
@@ -518,11 +518,6 @@ namespace i2p
|
||||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records");
|
||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Too many records in ShortTunnelBuild message ", num);
|
||||
return;
|
||||
}
|
||||
if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len);
|
||||
@@ -581,8 +576,11 @@ namespace i2p
|
||||
|
||||
// check if we accept this tunnel
|
||||
uint8_t retCode = 0;
|
||||
if (!i2p::context.AcceptsTunnels () || i2p::context.IsHighCongestion ())
|
||||
retCode = 30;
|
||||
if (!i2p::context.AcceptsTunnels () ||
|
||||
i2p::tunnel::tunnels.GetTransitTunnels ().size () > g_MaxNumTransitTunnels ||
|
||||
i2p::transport::transports.IsBandwidthExceeded () ||
|
||||
i2p::transport::transports.IsTransitBandwidthExceeded ())
|
||||
retCode = 30;
|
||||
if (!retCode)
|
||||
{
|
||||
// create new transit tunnel
|
||||
@@ -748,38 +746,46 @@ namespace i2p
|
||||
return l;
|
||||
}
|
||||
|
||||
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
void HandleI2NPMessage (uint8_t * msg, size_t len)
|
||||
{
|
||||
if (msg)
|
||||
if (len < I2NP_HEADER_SIZE)
|
||||
{
|
||||
uint8_t typeID = msg->GetTypeID();
|
||||
uint32_t msgID = msg->GetMsgID();
|
||||
LogPrint (eLogDebug, "I2NP: Handling tunnel build message with len=", msg->GetLength(),", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
|
||||
uint8_t * payload = msg->GetPayload();
|
||||
auto size = msg->GetPayloadLength();
|
||||
switch (typeID)
|
||||
{
|
||||
case eI2NPVariableTunnelBuild:
|
||||
HandleVariableTunnelBuildMsg (msgID, payload, size);
|
||||
break;
|
||||
case eI2NPShortTunnelBuild:
|
||||
HandleShortTunnelBuildMsg (msgID, payload, size);
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, payload, size, false);
|
||||
break;
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, payload, size, true);
|
||||
break;
|
||||
case eI2NPTunnelBuild:
|
||||
HandleTunnelBuildMsg (payload, size);
|
||||
break;
|
||||
case eI2NPTunnelBuildReply:
|
||||
// TODO:
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "I2NP: Unexpected message with type", (int)typeID, " during handling TBM; skipping");
|
||||
}
|
||||
LogPrint (eLogError, "I2NP: Message length ", len, " is smaller than header");
|
||||
return;
|
||||
}
|
||||
uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
|
||||
uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
|
||||
LogPrint (eLogDebug, "I2NP: Msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
|
||||
uint8_t * buf = msg + I2NP_HEADER_SIZE;
|
||||
auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
|
||||
len -= I2NP_HEADER_SIZE;
|
||||
if (size > len)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Payload size ", size, " exceeds buffer length ", len);
|
||||
size = len;
|
||||
}
|
||||
switch (typeID)
|
||||
{
|
||||
case eI2NPVariableTunnelBuild:
|
||||
HandleVariableTunnelBuildMsg (msgID, buf, size);
|
||||
break;
|
||||
case eI2NPShortTunnelBuild:
|
||||
HandleShortTunnelBuildMsg (msgID, buf, size);
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, buf, size, false);
|
||||
break;
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, buf, size, true);
|
||||
break;
|
||||
case eI2NPTunnelBuild:
|
||||
HandleTunnelBuildMsg (buf, size);
|
||||
break;
|
||||
case eI2NPTunnelBuildReply:
|
||||
// TODO:
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,12 +798,10 @@ namespace i2p
|
||||
switch (typeID)
|
||||
{
|
||||
case eI2NPTunnelData:
|
||||
if (!msg->from)
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
case eI2NPTunnelGateway:
|
||||
if (!msg->from)
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
case eI2NPGarlic:
|
||||
{
|
||||
@@ -808,16 +812,10 @@ namespace i2p
|
||||
break;
|
||||
}
|
||||
case eI2NPDatabaseStore:
|
||||
case eI2NPDatabaseSearchReply:
|
||||
// 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 ())
|
||||
i2p::data::netdb.PostI2NPMsg (msg);
|
||||
break;
|
||||
|
||||
case eI2NPDatabaseSearchReply:
|
||||
case eI2NPDatabaseLookup:
|
||||
// forward to netDb if floodfill and came directly
|
||||
if (!msg->from && i2p::context.IsFloodfill ())
|
||||
i2p::data::netdb.PostI2NPMsg (msg);
|
||||
// forward to netDb
|
||||
i2p::data::netdb.PostI2NPMsg (msg);
|
||||
break;
|
||||
case eI2NPDeliveryStatus:
|
||||
{
|
||||
@@ -828,20 +826,16 @@ namespace i2p
|
||||
break;
|
||||
}
|
||||
case eI2NPVariableTunnelBuild:
|
||||
case eI2NPTunnelBuild:
|
||||
case eI2NPShortTunnelBuild:
|
||||
// forward to tunnel thread
|
||||
if (!msg->from)
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
case eI2NPTunnelBuild:
|
||||
case eI2NPTunnelBuildReply:
|
||||
case eI2NPShortTunnelBuild:
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
// forward to tunnel thread
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
default:
|
||||
LogPrint(eLogError, "I2NP: Unexpected I2NP message with type ", int(typeID), " during handling; skipping");
|
||||
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -140,7 +140,6 @@ namespace tunnel
|
||||
|
||||
const size_t I2NP_MAX_MESSAGE_SIZE = 62708;
|
||||
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
|
||||
const size_t I2NP_MAX_MEDIUM_MESSAGE_SIZE = 16384;
|
||||
const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT)
|
||||
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
|
||||
|
||||
@@ -263,7 +262,6 @@ namespace tunnel
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage ();
|
||||
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMediumMessage ();
|
||||
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len);
|
||||
|
||||
@@ -295,7 +293,7 @@ namespace tunnel
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len);
|
||||
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void HandleI2NPMessage (uint8_t * msg, size_t len);
|
||||
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
class I2NPMessagesHandler
|
||||
@@ -310,6 +308,10 @@ namespace tunnel
|
||||
|
||||
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
|
||||
};
|
||||
|
||||
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 5000;
|
||||
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
|
||||
uint16_t GetMaxNumTransitTunnels ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,23 +36,6 @@
|
||||
#define le64toh(x) OSSwapLittleToHostInt64(x)
|
||||
|
||||
#elif defined(_WIN32)
|
||||
#if defined(_MSC_VER)
|
||||
#include <stdlib.h>
|
||||
#define htobe16(x) _byteswap_ushort(x)
|
||||
#define htole16(x) (x)
|
||||
#define be16toh(x) _byteswap_ushort(x)
|
||||
#define le16toh(x) (x)
|
||||
|
||||
#define htobe32(x) _byteswap_ulong(x)
|
||||
#define htole32(x) (x)
|
||||
#define be32toh(x) _byteswap_ulong(x)
|
||||
#define le32toh(x) (x)
|
||||
|
||||
#define htobe64(x) _byteswap_uint64(x)
|
||||
#define htole64(x) (x)
|
||||
#define be64toh(x) _byteswap_uint64(x)
|
||||
#define le64toh(x) (x)
|
||||
#else
|
||||
#define htobe16(x) __builtin_bswap16(x)
|
||||
#define htole16(x) (x)
|
||||
#define be16toh(x) __builtin_bswap16(x)
|
||||
@@ -67,7 +50,6 @@
|
||||
#define htole64(x) (x)
|
||||
#define be64toh(x) __builtin_bswap64(x)
|
||||
#define le64toh(x) (x)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define NEEDS_LOCAL_ENDIAN
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -187,6 +187,7 @@ namespace data
|
||||
|
||||
IdentityEx::~IdentityEx ()
|
||||
{
|
||||
delete m_Verifier;
|
||||
}
|
||||
|
||||
IdentityEx& IdentityEx::operator=(const IdentityEx& other)
|
||||
@@ -200,8 +201,9 @@ namespace data
|
||||
if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE;
|
||||
memcpy (m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen);
|
||||
}
|
||||
|
||||
delete m_Verifier;
|
||||
m_Verifier = nullptr;
|
||||
CreateVerifier ();
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -210,10 +212,11 @@ namespace data
|
||||
{
|
||||
m_StandardIdentity = standard;
|
||||
m_IdentHash = m_StandardIdentity.Hash ();
|
||||
|
||||
m_ExtendedLen = 0;
|
||||
|
||||
delete m_Verifier;
|
||||
m_Verifier = nullptr;
|
||||
CreateVerifier ();
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -246,8 +249,8 @@ namespace data
|
||||
m_ExtendedLen = 0;
|
||||
SHA256(buf, GetFullLen (), m_IdentHash);
|
||||
|
||||
delete m_Verifier;
|
||||
m_Verifier = nullptr;
|
||||
CreateVerifier ();
|
||||
|
||||
return GetFullLen ();
|
||||
}
|
||||
@@ -283,6 +286,7 @@ namespace data
|
||||
|
||||
size_t IdentityEx::GetSigningPublicKeyLen () const
|
||||
{
|
||||
if (!m_Verifier) CreateVerifier ();
|
||||
if (m_Verifier)
|
||||
return m_Verifier->GetPublicKeyLen ();
|
||||
return 128;
|
||||
@@ -297,6 +301,7 @@ namespace data
|
||||
|
||||
size_t IdentityEx::GetSigningPrivateKeyLen () const
|
||||
{
|
||||
if (!m_Verifier) CreateVerifier ();
|
||||
if (m_Verifier)
|
||||
return m_Verifier->GetPrivateKeyLen ();
|
||||
return GetSignatureLen ()/2;
|
||||
@@ -304,12 +309,14 @@ namespace data
|
||||
|
||||
size_t IdentityEx::GetSignatureLen () const
|
||||
{
|
||||
if (!m_Verifier) CreateVerifier ();
|
||||
if (m_Verifier)
|
||||
return m_Verifier->GetSignatureLen ();
|
||||
return i2p::crypto::DSA_SIGNATURE_LENGTH;
|
||||
}
|
||||
bool IdentityEx::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
if (!m_Verifier) CreateVerifier ();
|
||||
if (m_Verifier)
|
||||
return m_Verifier->Verify (buf, len, signature);
|
||||
return false;
|
||||
@@ -366,29 +373,52 @@ namespace data
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IdentityEx::CreateVerifier ()
|
||||
void IdentityEx::CreateVerifier () const
|
||||
{
|
||||
if (!m_Verifier)
|
||||
if (m_Verifier) return; // don't create again
|
||||
auto verifier = CreateVerifier (GetSigningKeyType ());
|
||||
if (verifier)
|
||||
{
|
||||
auto verifier = CreateVerifier (GetSigningKeyType ());
|
||||
if (verifier)
|
||||
auto keyLen = verifier->GetPublicKeyLen ();
|
||||
if (keyLen <= 128)
|
||||
verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen);
|
||||
else
|
||||
{
|
||||
auto keyLen = verifier->GetPublicKeyLen ();
|
||||
if (keyLen <= 128)
|
||||
verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen);
|
||||
else
|
||||
{
|
||||
// for P521
|
||||
uint8_t * signingKey = new uint8_t[keyLen];
|
||||
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
|
||||
size_t excessLen = keyLen - 128;
|
||||
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
|
||||
verifier->SetPublicKey (signingKey);
|
||||
delete[] signingKey;
|
||||
}
|
||||
// for P521
|
||||
uint8_t * signingKey = new uint8_t[keyLen];
|
||||
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
|
||||
size_t excessLen = keyLen - 128;
|
||||
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
|
||||
verifier->SetPublicKey (signingKey);
|
||||
delete[] signingKey;
|
||||
}
|
||||
m_Verifier.reset (verifier);
|
||||
}
|
||||
UpdateVerifier (verifier);
|
||||
}
|
||||
|
||||
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
|
||||
{
|
||||
bool del = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_VerifierMutex);
|
||||
if (!m_Verifier)
|
||||
m_Verifier = verifier;
|
||||
else
|
||||
del = true;
|
||||
}
|
||||
if (del)
|
||||
delete verifier;
|
||||
}
|
||||
|
||||
void IdentityEx::DropVerifier () const
|
||||
{
|
||||
i2p::crypto::Verifier * verifier;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_VerifierMutex);
|
||||
verifier = m_Verifier;
|
||||
m_Verifier = nullptr;
|
||||
}
|
||||
delete verifier;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -13,7 +13,9 @@
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include "Base.h"
|
||||
#include "Signature.h"
|
||||
#include "CryptoKey.h"
|
||||
@@ -116,6 +118,7 @@ namespace data
|
||||
SigningKeyType GetSigningKeyType () const;
|
||||
bool IsRSA () const; // signing key type
|
||||
CryptoKeyType GetCryptoKeyType () const;
|
||||
void DropVerifier () const; // to save memory
|
||||
|
||||
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
|
||||
void RecalculateIdentHash(uint8_t * buff=nullptr);
|
||||
@@ -125,13 +128,15 @@ namespace data
|
||||
|
||||
private:
|
||||
|
||||
void CreateVerifier ();
|
||||
|
||||
void CreateVerifier () const;
|
||||
void UpdateVerifier (i2p::crypto::Verifier * verifier) const;
|
||||
|
||||
private:
|
||||
|
||||
Identity m_StandardIdentity;
|
||||
IdentHash m_IdentHash;
|
||||
std::unique_ptr<i2p::crypto::Verifier> m_Verifier;
|
||||
mutable i2p::crypto::Verifier * m_Verifier = nullptr;
|
||||
mutable std::mutex m_VerifierMutex;
|
||||
size_t m_ExtendedLen;
|
||||
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KadDHT.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
DHTNode::DHTNode ():
|
||||
zero (nullptr), one (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
DHTNode::~DHTNode ()
|
||||
{
|
||||
if (zero) delete zero;
|
||||
if (one) delete one;
|
||||
}
|
||||
|
||||
void DHTNode::MoveRouterUp (bool fromOne)
|
||||
{
|
||||
DHTNode *& side = fromOne ? one : zero;
|
||||
if (side)
|
||||
{
|
||||
if (router) router = nullptr; // shouldn't happen
|
||||
router = side->router;
|
||||
side->router = nullptr;
|
||||
delete side;
|
||||
side = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DHTTable::DHTTable ():
|
||||
m_Size (0)
|
||||
{
|
||||
m_Root = new DHTNode;
|
||||
}
|
||||
|
||||
DHTTable::~DHTTable ()
|
||||
{
|
||||
delete m_Root;
|
||||
}
|
||||
|
||||
void DHTTable::Clear ()
|
||||
{
|
||||
m_Size = 0;
|
||||
delete m_Root;
|
||||
m_Root = new DHTNode;
|
||||
}
|
||||
|
||||
void DHTTable::Insert (const std::shared_ptr<RouterInfo>& r)
|
||||
{
|
||||
if (!r) return;
|
||||
return Insert (r, m_Root, 0);
|
||||
}
|
||||
|
||||
void DHTTable::Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level)
|
||||
{
|
||||
if (root->router)
|
||||
{
|
||||
if (root->router->GetIdentHash () == r->GetIdentHash ())
|
||||
{
|
||||
root->router = r; // replace
|
||||
return;
|
||||
}
|
||||
auto r2 = root->router;
|
||||
root->router = nullptr; m_Size--;
|
||||
int bit1, bit2;
|
||||
do
|
||||
{
|
||||
bit1 = r->GetIdentHash ().GetBit (level);
|
||||
bit2 = r2->GetIdentHash ().GetBit (level);
|
||||
if (bit1 == bit2)
|
||||
{
|
||||
if (bit1)
|
||||
{
|
||||
if (root->one) return; // something wrong
|
||||
root->one = new DHTNode;
|
||||
root = root->one;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (root->zero) return; // something wrong
|
||||
root->zero = new DHTNode;
|
||||
root = root->zero;
|
||||
}
|
||||
level++;
|
||||
}
|
||||
}
|
||||
while (bit1 == bit2);
|
||||
|
||||
if (!root->zero)
|
||||
root->zero = new DHTNode;
|
||||
if (!root->one)
|
||||
root->one = new DHTNode;
|
||||
if (bit1)
|
||||
{
|
||||
Insert (r2, root->zero, level + 1);
|
||||
Insert (r, root->one, level + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Insert (r2, root->one, level + 1);
|
||||
Insert (r, root->zero, level + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!root->zero && !root->one)
|
||||
{
|
||||
root->router = r; m_Size++;
|
||||
return;
|
||||
}
|
||||
int bit = r->GetIdentHash ().GetBit (level);
|
||||
if (bit)
|
||||
{
|
||||
if (!root->one)
|
||||
root->one = new DHTNode;
|
||||
Insert (r, root->one, level + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!root->zero)
|
||||
root->zero = new DHTNode;
|
||||
Insert (r, root->zero, level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DHTTable::Remove (const IdentHash& h)
|
||||
{
|
||||
return Remove (h, m_Root, 0);
|
||||
}
|
||||
|
||||
bool DHTTable::Remove (const IdentHash& h, DHTNode * root, int level)
|
||||
{
|
||||
if (root)
|
||||
{
|
||||
if (root->router && root->router->GetIdentHash () == h)
|
||||
{
|
||||
root->router = nullptr;
|
||||
m_Size--;
|
||||
return true;
|
||||
}
|
||||
int bit = h.GetBit (level);
|
||||
if (bit)
|
||||
{
|
||||
if (root->one && Remove (h, root->one, level + 1))
|
||||
{
|
||||
if (root->one->IsEmpty ())
|
||||
{
|
||||
delete root->one;
|
||||
root->one = nullptr;
|
||||
if (root->zero && root->zero->router)
|
||||
root->MoveRouterUp (false);
|
||||
}
|
||||
else if (root->one->router && !root->zero)
|
||||
root->MoveRouterUp (true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (root->zero && Remove (h, root->zero, level + 1))
|
||||
{
|
||||
if (root->zero->IsEmpty ())
|
||||
{
|
||||
delete root->zero;
|
||||
root->zero = nullptr;
|
||||
if (root->one && root->one->router)
|
||||
root->MoveRouterUp (true);
|
||||
}
|
||||
else if (root->zero->router && !root->one)
|
||||
root->MoveRouterUp (false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, const Filter& filter) const
|
||||
{
|
||||
if (filter) m_Filter = filter;
|
||||
auto r = FindClosest (h, m_Root, 0);
|
||||
m_Filter = nullptr;
|
||||
return r;
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level) const
|
||||
{
|
||||
bool split = false;
|
||||
do
|
||||
{
|
||||
if (root->router)
|
||||
return (!m_Filter || m_Filter (root->router)) ? root->router : nullptr;
|
||||
split = root->zero && root->one;
|
||||
if (!split)
|
||||
{
|
||||
if (root->zero) root = root->zero;
|
||||
else if (root->one) root = root->one;
|
||||
else return nullptr;
|
||||
level++;
|
||||
}
|
||||
}
|
||||
while (!split);
|
||||
int bit = h.GetBit (level);
|
||||
if (bit)
|
||||
{
|
||||
if (root->one)
|
||||
{
|
||||
auto r = FindClosest (h, root->one, level + 1);
|
||||
if (r) return r;
|
||||
}
|
||||
if (root->zero)
|
||||
{
|
||||
auto r = FindClosest (h, root->zero, level + 1);
|
||||
if (r) return r;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (root->zero)
|
||||
{
|
||||
auto r = FindClosest (h, root->zero, level + 1);
|
||||
if (r) return r;
|
||||
}
|
||||
if (root->one)
|
||||
{
|
||||
auto r = FindClosest (h, root->one, level + 1);
|
||||
if (r) return r;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<RouterInfo> > DHTTable::FindClosest (const IdentHash& h, size_t num, const Filter& filter) const
|
||||
{
|
||||
std::vector<std::shared_ptr<RouterInfo> > vec;
|
||||
if (num > 0)
|
||||
{
|
||||
if (filter) m_Filter = filter;
|
||||
FindClosest (h, num, m_Root, 0, vec);
|
||||
m_Filter = nullptr;
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const
|
||||
{
|
||||
if (hashes.size () >= num) return;
|
||||
bool split = false;
|
||||
do
|
||||
{
|
||||
if (root->router)
|
||||
{
|
||||
if (!m_Filter || m_Filter (root->router))
|
||||
hashes.push_back (root->router);
|
||||
return;
|
||||
}
|
||||
split = root->zero && root->one;
|
||||
if (!split)
|
||||
{
|
||||
if (root->zero) root = root->zero;
|
||||
else if (root->one) root = root->one;
|
||||
else return;
|
||||
level++;
|
||||
}
|
||||
}
|
||||
while (!split);
|
||||
int bit = h.GetBit (level);
|
||||
if (bit)
|
||||
{
|
||||
if (root->one)
|
||||
FindClosest (h, num, root->one, level + 1, hashes);
|
||||
if (hashes.size () < num && root->zero)
|
||||
FindClosest (h, num, root->zero, level + 1, hashes);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (root->zero)
|
||||
FindClosest (h, num, root->zero, level + 1, hashes);
|
||||
if (hashes.size () < num && root->one)
|
||||
FindClosest (h, num, root->one, level + 1, hashes);
|
||||
}
|
||||
}
|
||||
|
||||
void DHTTable::Cleanup (const Filter& filter)
|
||||
{
|
||||
if (filter)
|
||||
{
|
||||
m_Filter = filter;
|
||||
Cleanup (m_Root);
|
||||
m_Filter = nullptr;
|
||||
}
|
||||
else
|
||||
Clear ();
|
||||
}
|
||||
|
||||
void DHTTable::Cleanup (DHTNode * root)
|
||||
{
|
||||
if (!root) return;
|
||||
if (root->router)
|
||||
{
|
||||
if (!m_Filter || !m_Filter (root->router))
|
||||
{
|
||||
m_Size--;
|
||||
root->router = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (root->zero)
|
||||
{
|
||||
Cleanup (root->zero);
|
||||
if (root->zero->IsEmpty ())
|
||||
{
|
||||
delete root->zero;
|
||||
root->zero = nullptr;
|
||||
}
|
||||
}
|
||||
if (root->one)
|
||||
{
|
||||
Cleanup (root->one);
|
||||
if (root->one->IsEmpty ())
|
||||
{
|
||||
delete root->one;
|
||||
root->one = nullptr;
|
||||
if (root->zero && root->zero->router)
|
||||
root->MoveRouterUp (false);
|
||||
}
|
||||
else if (root->one->router && !root->zero)
|
||||
root->MoveRouterUp (true);
|
||||
}
|
||||
}
|
||||
|
||||
void DHTTable::Print (std::stringstream& s)
|
||||
{
|
||||
Print (s, m_Root, 0);
|
||||
}
|
||||
|
||||
void DHTTable::Print (std::stringstream& s, DHTNode * root, int level)
|
||||
{
|
||||
if (!root) return;
|
||||
s << std::string (level, '-');
|
||||
if (root->router)
|
||||
{
|
||||
if (!root->zero && !root->one)
|
||||
s << '>' << GetIdentHashAbbreviation (root->router->GetIdentHash ());
|
||||
else
|
||||
s << "error";
|
||||
}
|
||||
s << std::endl;
|
||||
if (root->zero)
|
||||
{
|
||||
s << std::string (level, '-') << "0" << std::endl;
|
||||
Print (s, root->zero, level + 1);
|
||||
}
|
||||
if (root->one)
|
||||
{
|
||||
s << std::string (level, '-') << "1" << std::endl;
|
||||
Print (s, root->one, level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KADDHT_H__
|
||||
#define KADDHT_H__
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <functional>
|
||||
#include "RouterInfo.h"
|
||||
|
||||
// Kademlia DHT (XOR distance)
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
struct DHTNode
|
||||
{
|
||||
DHTNode * zero, * one;
|
||||
std::shared_ptr<RouterInfo> router;
|
||||
|
||||
DHTNode ();
|
||||
~DHTNode ();
|
||||
|
||||
bool IsEmpty () const { return !zero && !one && !router; };
|
||||
void MoveRouterUp (bool fromOne);
|
||||
};
|
||||
|
||||
class DHTTable
|
||||
{
|
||||
typedef std::function<bool (const std::shared_ptr<RouterInfo>&)> Filter;
|
||||
public:
|
||||
|
||||
DHTTable ();
|
||||
~DHTTable ();
|
||||
|
||||
void Insert (const std::shared_ptr<RouterInfo>& r);
|
||||
bool Remove (const IdentHash& h);
|
||||
std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, const Filter& filter = nullptr) const;
|
||||
std::vector<std::shared_ptr<RouterInfo> > FindClosest (const IdentHash& h, size_t num, const Filter& filter = nullptr) const;
|
||||
|
||||
void Print (std::stringstream& s);
|
||||
size_t GetSize () const { return m_Size; };
|
||||
void Clear ();
|
||||
void Cleanup (const Filter& filter);
|
||||
|
||||
private:
|
||||
|
||||
void Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level); // recursive
|
||||
bool Remove (const IdentHash& h, DHTNode * root, int level);
|
||||
std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, DHTNode * root, int level) const;
|
||||
void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const;
|
||||
void Cleanup (DHTNode * root);
|
||||
void Print (std::stringstream& s, DHTNode * root, int level);
|
||||
|
||||
private:
|
||||
|
||||
DHTNode * m_Root;
|
||||
size_t m_Size;
|
||||
// transient
|
||||
mutable Filter m_Filter;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -50,7 +50,7 @@ namespace data
|
||||
void LeaseSet::ReadFromBuffer (bool readIdentity, bool verifySignature)
|
||||
{
|
||||
if (readIdentity || !m_Identity)
|
||||
m_Identity = netdb.NewIdentity (m_Buffer, m_BufferLen);
|
||||
m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
|
||||
size_t size = m_Identity->GetFullLen ();
|
||||
if (size + 256 > m_BufferLen)
|
||||
{
|
||||
@@ -76,7 +76,7 @@ namespace data
|
||||
LogPrint (eLogDebug, "LeaseSet: Read num=", (int)num);
|
||||
if (!num || num > MAX_NUM_LEASES)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: Incorrect number of leases", (int)num);
|
||||
LogPrint (eLogError, "LeaseSet: Rncorrect number of leases", (int)num);
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
@@ -315,9 +315,9 @@ namespace data
|
||||
{
|
||||
// standard LS2 header
|
||||
std::shared_ptr<const IdentityEx> identity;
|
||||
if (readIdentity || !GetIdentity ())
|
||||
if (readIdentity)
|
||||
{
|
||||
identity = netdb.NewIdentity (buf, len);
|
||||
identity = std::make_shared<IdentityEx>(buf, len);
|
||||
SetIdentity (identity);
|
||||
}
|
||||
else
|
||||
@@ -366,8 +366,6 @@ namespace data
|
||||
VerifySignature (identity, buf, len, offset);
|
||||
SetIsValid (verified);
|
||||
}
|
||||
else
|
||||
SetIsValid (true);
|
||||
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen ();
|
||||
if (offset > len) {
|
||||
LogPrint (eLogWarning, "LeaseSet2: short buffer: wanted ", int(offset), "bytes, have ", int(len));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -96,9 +96,6 @@ namespace data
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) const;
|
||||
bool IsDestination () const { return true; };
|
||||
|
||||
// used in webconsole
|
||||
void ExpireLease () { m_ExpirationTime = i2p::util::GetSecondsSinceEpoch (); };
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateLeasesBegin ();
|
||||
@@ -148,7 +145,6 @@ namespace data
|
||||
{
|
||||
public:
|
||||
|
||||
LeaseSet2 (uint8_t storeType): LeaseSet (true), m_StoreType (storeType) {}; // for update
|
||||
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL);
|
||||
LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); // store type 5, called from local netdb only
|
||||
uint8_t GetStoreType () const { return m_StoreType; };
|
||||
|
||||
@@ -20,12 +20,11 @@ namespace log {
|
||||
*/
|
||||
static const char *g_LogLevelStr[eNumLogLevels] =
|
||||
{
|
||||
"none", // eLogNone
|
||||
"critical", // eLogCritical
|
||||
"error", // eLogError
|
||||
"warn", // eLogWarning
|
||||
"info", // eLogInfo
|
||||
"debug" // eLogDebug
|
||||
"none", // eLogNone
|
||||
"error", // eLogError
|
||||
"warn", // eLogWarning
|
||||
"info", // eLogInfo
|
||||
"debug" // eLogDebug
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -33,11 +32,10 @@ namespace log {
|
||||
* @note Using ISO 6429 (ANSI) color sequences
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
static const char *LogMsgColors[] = { "", "", "", "", "", "", "" };
|
||||
static const char *LogMsgColors[] = { "", "", "", "", "", "" };
|
||||
#else /* UNIX */
|
||||
static const char *LogMsgColors[] = {
|
||||
"\033[1;32m", /* none: green */
|
||||
"\033[1;41m", /* critical: red background */
|
||||
"\033[1;31m", /* error: red */
|
||||
"\033[1;33m", /* warning: yellow */
|
||||
"\033[1;36m", /* info: cyan */
|
||||
@@ -55,7 +53,6 @@ namespace log {
|
||||
int priority = LOG_DEBUG;
|
||||
switch (l) {
|
||||
case eLogNone : priority = LOG_CRIT; break;
|
||||
case eLogCritical: priority = LOG_CRIT; break;
|
||||
case eLogError : priority = LOG_ERR; break;
|
||||
case eLogWarning : priority = LOG_WARNING; break;
|
||||
case eLogInfo : priority = LOG_INFO; break;
|
||||
@@ -126,14 +123,13 @@ namespace log {
|
||||
|
||||
void Log::SetLogLevel (const std::string& level_) {
|
||||
std::string level=str_tolower(level_);
|
||||
if (level == "none") { m_MinLevel = eLogNone; }
|
||||
else if (level == "critical") { m_MinLevel = eLogCritical; }
|
||||
else if (level == "error") { m_MinLevel = eLogError; }
|
||||
else if (level == "warn") { m_MinLevel = eLogWarning; }
|
||||
else if (level == "info") { m_MinLevel = eLogInfo; }
|
||||
else if (level == "debug") { m_MinLevel = eLogDebug; }
|
||||
if (level == "none") { m_MinLevel = eLogNone; }
|
||||
else if (level == "error") { m_MinLevel = eLogError; }
|
||||
else if (level == "warn") { m_MinLevel = eLogWarning; }
|
||||
else if (level == "info") { m_MinLevel = eLogInfo; }
|
||||
else if (level == "debug") { m_MinLevel = eLogDebug; }
|
||||
else {
|
||||
LogPrint(eLogCritical, "Log: Unknown loglevel: ", level);
|
||||
LogPrint(eLogError, "Log: Unknown loglevel: ", level);
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogInfo, "Log: Logging level set to ", level);
|
||||
@@ -216,7 +212,7 @@ namespace log {
|
||||
m_LogStream = os;
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogCritical, "Log: Can't open file ", path);
|
||||
LogPrint(eLogError, "Log: Can't open file ", path);
|
||||
}
|
||||
|
||||
void Log::SendTo (std::shared_ptr<std::ostream> os) {
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
enum LogLevel
|
||||
{
|
||||
eLogNone = 0,
|
||||
eLogCritical,
|
||||
eLogError,
|
||||
eLogWarning,
|
||||
eLogInfo,
|
||||
|
||||
@@ -452,7 +452,6 @@ namespace transport
|
||||
{
|
||||
m_Establisher->CreateSessionRequestMessage ();
|
||||
// send message
|
||||
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 (),
|
||||
std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
@@ -530,7 +529,6 @@ namespace transport
|
||||
{
|
||||
m_Establisher->CreateSessionCreatedMessage ();
|
||||
// send message
|
||||
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 (),
|
||||
std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
@@ -544,7 +542,6 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
|
||||
LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred);
|
||||
uint16_t paddingLen = 0;
|
||||
if (m_Establisher->ProcessSessionCreatedMessage (paddingLen))
|
||||
@@ -566,11 +563,7 @@ namespace transport
|
||||
SendSessionConfirmed ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetRemoteIdentity ())
|
||||
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,7 +646,6 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
|
||||
LogPrint (eLogDebug, "NTCP2: SessionConfirmed received");
|
||||
// part 1
|
||||
uint8_t nonce[12];
|
||||
@@ -701,20 +693,10 @@ namespace transport
|
||||
SendTerminationAndTerminate (eNTCP2Message3Error);
|
||||
return;
|
||||
}
|
||||
auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri.GetNTCP2V4Address () :
|
||||
(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri.GetYggdrasilAddress () : ri.GetNTCP2V6Address ());
|
||||
if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
|
||||
auto addr = ri.GetNTCP2AddressWithStaticKey (m_Establisher->m_RemoteStaticKey);
|
||||
if (!addr)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
if (addr->IsPublishedNTCP2 () && m_RemoteEndpoint.address () != addr->host &&
|
||||
(!m_RemoteEndpoint.address ().is_v6 () || (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ?
|
||||
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet
|
||||
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ());
|
||||
LogPrint (eLogError, "NTCP2: No NTCP2 address with static key found in SessionConfirmed");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
@@ -892,20 +874,8 @@ namespace transport
|
||||
switch (blk)
|
||||
{
|
||||
case eNTCP2BlkDateTime:
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: Datetime");
|
||||
if (m_IsEstablished)
|
||||
{
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
uint64_t tsA = bufbe32toh (frame + offset);
|
||||
if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: Established session time difference ", (int)(ts - tsA), " exceeds clock skew");
|
||||
SendTerminationAndTerminate (eNTCP2ClockSkew);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case eNTCP2BlkOptions:
|
||||
LogPrint (eLogDebug, "NTCP2: Options");
|
||||
break;
|
||||
@@ -1150,17 +1120,12 @@ namespace transport
|
||||
{
|
||||
if (!IsEstablished ()) return;
|
||||
auto riLen = i2p::context.GetRouterInfo ().GetBufferLen ();
|
||||
size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime
|
||||
size_t payloadLen = riLen + 4; // 3 bytes block header + 1 byte RI flag
|
||||
m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding
|
||||
// DateTime block
|
||||
m_NextSendBuffer[2] = eNTCP2BlkDateTime;
|
||||
htobe16buf (m_NextSendBuffer + 3, 4);
|
||||
htobe32buf (m_NextSendBuffer + 5, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
|
||||
// RouterInfo block
|
||||
m_NextSendBuffer[9] = eNTCP2BlkRouterInfo;
|
||||
htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size
|
||||
m_NextSendBuffer[12] = 0; // flag
|
||||
memcpy (m_NextSendBuffer + 13, i2p::context.GetRouterInfo ().GetBuffer (), riLen);
|
||||
m_NextSendBuffer[2] = eNTCP2BlkRouterInfo;
|
||||
htobe16buf (m_NextSendBuffer + 3, riLen + 1); // size
|
||||
m_NextSendBuffer[5] = 0; // flag
|
||||
memcpy (m_NextSendBuffer + 6, i2p::context.GetRouterInfo ().GetBuffer (), riLen);
|
||||
// padding block
|
||||
auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64);
|
||||
payloadLen += paddingSize;
|
||||
@@ -1246,7 +1211,7 @@ namespace transport
|
||||
boost::system::error_code e;
|
||||
auto itr = m_Resolver.resolve(q, e);
|
||||
if(e)
|
||||
LogPrint(eLogCritical, "NTCP2: Failed to resolve proxy ", e.message());
|
||||
LogPrint(eLogError, "NTCP2: Failed to resolve proxy ", e.message());
|
||||
else
|
||||
{
|
||||
m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr));
|
||||
@@ -1274,7 +1239,7 @@ namespace transport
|
||||
}
|
||||
catch ( std::exception & ex )
|
||||
{
|
||||
LogPrint(eLogCritical, "NTCP2: Failed to bind to v4 port ", address->port, ex.what());
|
||||
LogPrint(eLogError, "NTCP2: Failed to bind to v4 port ", address->port, ex.what());
|
||||
ThrowFatal ("Unable to start IPv4 NTCP2 transport at port ", address->port, ": ", ex.what ());
|
||||
continue;
|
||||
}
|
||||
@@ -1317,7 +1282,7 @@ namespace transport
|
||||
}
|
||||
catch ( std::exception & ex )
|
||||
{
|
||||
LogPrint(eLogCritical, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
|
||||
LogPrint(eLogError, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
|
||||
ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ());
|
||||
continue;
|
||||
}
|
||||
@@ -1465,7 +1430,7 @@ namespace transport
|
||||
|
||||
void NTCP2Server::HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
|
||||
{
|
||||
if (!error && conn)
|
||||
if (!error)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto ep = conn->GetSocket ().remote_endpoint(ec);
|
||||
@@ -1474,14 +1439,17 @@ namespace transport
|
||||
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
|
||||
if (!i2p::util::net::IsInReservedRange(ep.address ()))
|
||||
{
|
||||
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
|
||||
if (conn)
|
||||
{
|
||||
conn->SetRemoteEndpoint (ep);
|
||||
conn->ServerLogin ();
|
||||
conn = nullptr;
|
||||
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
|
||||
{
|
||||
conn->SetRemoteEndpoint (ep);
|
||||
conn->ServerLogin ();
|
||||
conn = nullptr;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ());
|
||||
@@ -1512,7 +1480,7 @@ namespace transport
|
||||
|
||||
void NTCP2Server::HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
|
||||
{
|
||||
if (!error && conn)
|
||||
if (!error)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto ep = conn->GetSocket ().remote_endpoint(ec);
|
||||
@@ -1522,14 +1490,17 @@ namespace transport
|
||||
if (!i2p::util::net::IsInReservedRange(ep.address ()) ||
|
||||
i2p::util::net::IsYggdrasilAddress (ep.address ()))
|
||||
{
|
||||
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
|
||||
if (conn)
|
||||
{
|
||||
conn->SetRemoteEndpoint (ep);
|
||||
conn->ServerLogin ();
|
||||
conn = nullptr;
|
||||
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
|
||||
{
|
||||
conn->SetRemoteEndpoint (ep);
|
||||
conn->ServerLogin ();
|
||||
conn = nullptr;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ());
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace data
|
||||
{
|
||||
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_HiddenMode(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace data
|
||||
Load ();
|
||||
|
||||
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.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
|
||||
{
|
||||
Reseed ();
|
||||
}
|
||||
@@ -66,13 +66,13 @@ namespace data
|
||||
if (it != m_RouterInfos.end ())
|
||||
{
|
||||
// remove own router
|
||||
m_Floodfills.Remove (it->second->GetIdentHash ());
|
||||
m_Floodfills.remove (it->second);
|
||||
m_RouterInfos.erase (it);
|
||||
}
|
||||
// insert own router
|
||||
m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ());
|
||||
if (i2p::context.IsFloodfill ())
|
||||
m_Floodfills.Insert (i2p::context.GetSharedRouterInfo ());
|
||||
m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ());
|
||||
|
||||
i2p::config::GetOption("persist.profiles", m_PersistProfiles);
|
||||
|
||||
@@ -85,10 +85,11 @@ namespace data
|
||||
if (m_IsRunning)
|
||||
{
|
||||
if (m_PersistProfiles)
|
||||
SaveProfiles ();
|
||||
for (auto& it: m_RouterInfos)
|
||||
it.second->SaveProfile ();
|
||||
DeleteObsoleteProfiles ();
|
||||
m_RouterInfos.clear ();
|
||||
m_Floodfills.Clear ();
|
||||
m_Floodfills.clear ();
|
||||
if (m_Thread)
|
||||
{
|
||||
m_IsRunning = false;
|
||||
@@ -106,7 +107,7 @@ namespace data
|
||||
{
|
||||
i2p::util::SetThreadName("NetDB");
|
||||
|
||||
uint64_t lastManage = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
|
||||
uint64_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
|
||||
uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch ();
|
||||
int16_t profilesCleanupVariance = 0;
|
||||
|
||||
@@ -132,6 +133,9 @@ namespace data
|
||||
case eI2NPDatabaseLookup:
|
||||
HandleDatabaseLookupMsg (msg);
|
||||
break;
|
||||
case eI2NPDeliveryStatus:
|
||||
HandleDeliveryStatusMsg (msg);
|
||||
break;
|
||||
case eI2NPDummyMsg:
|
||||
// plain RouterInfo from NTCP2 with flags for now
|
||||
HandleNTCP2RouterInfoMsg (msg);
|
||||
@@ -149,39 +153,62 @@ namespace data
|
||||
if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline
|
||||
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts - lastManageRequest >= 15 || ts + 15 < lastManageRequest) // manage requests every 15 seconds
|
||||
if (ts - lastManageRequest >= 15) // manage requests every 15 seconds
|
||||
{
|
||||
m_Requests.ManageRequests ();
|
||||
lastManageRequest = ts;
|
||||
}
|
||||
|
||||
if (ts - lastManage >= 60 || ts + 60 < lastManage) // manage routers and leasesets every minute
|
||||
if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute
|
||||
{
|
||||
if (lastManage)
|
||||
if (lastSave)
|
||||
{
|
||||
ManageRouterInfos ();
|
||||
SaveUpdated ();
|
||||
ManageLeaseSets ();
|
||||
}
|
||||
lastManage = ts;
|
||||
lastSave = ts;
|
||||
}
|
||||
|
||||
if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT ||
|
||||
ts + i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT < lastDestinationCleanup)
|
||||
if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT)
|
||||
{
|
||||
i2p::context.CleanupDestination ();
|
||||
lastDestinationCleanup = ts;
|
||||
}
|
||||
|
||||
if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance) ||
|
||||
ts + i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT < lastProfilesCleanup)
|
||||
if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance))
|
||||
{
|
||||
if (m_PersistProfiles) PersistProfiles ();
|
||||
DeleteObsoleteProfiles ();
|
||||
lastProfilesCleanup = ts;
|
||||
profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE);
|
||||
}
|
||||
|
||||
if (ts - lastExploratory >= 30 || ts + 30 < lastExploratory) // exploratory every 30 seconds
|
||||
// publish
|
||||
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
|
||||
{
|
||||
bool publish = false;
|
||||
if (m_PublishReplyToken)
|
||||
{
|
||||
// next publishing attempt
|
||||
if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true;
|
||||
}
|
||||
else if (i2p::context.GetLastUpdateTime () > lastPublish ||
|
||||
ts - lastPublish >= NETDB_PUBLISH_INTERVAL)
|
||||
{
|
||||
// new publish
|
||||
m_PublishExcluded.clear ();
|
||||
if (i2p::context.IsFloodfill ())
|
||||
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves
|
||||
publish = true;
|
||||
}
|
||||
if (publish) // update timestamp and publish
|
||||
{
|
||||
i2p::context.UpdateTimestamp (ts);
|
||||
Publish ();
|
||||
lastPublish = ts;
|
||||
}
|
||||
}
|
||||
|
||||
if (ts - lastExploratory >= 30) // exploratory every 30 seconds
|
||||
{
|
||||
auto numRouters = m_RouterInfos.size ();
|
||||
if (!numRouters)
|
||||
@@ -194,7 +221,7 @@ namespace data
|
||||
if (numRouters < 1) numRouters = 1;
|
||||
if (numRouters > 9) numRouters = 9;
|
||||
m_Requests.ManageRequests ();
|
||||
if(!i2p::context.IsHidden ())
|
||||
if(!m_HiddenMode)
|
||||
Explore (numRouters);
|
||||
lastExploratory = ts;
|
||||
}
|
||||
@@ -207,6 +234,12 @@ namespace data
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::SetHidden(bool hide)
|
||||
{
|
||||
// TODO: remove reachable addresses from router info
|
||||
m_HiddenMode = hide;
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len)
|
||||
{
|
||||
bool updated;
|
||||
@@ -240,24 +273,7 @@ namespace data
|
||||
bool wasFloodfill = r->IsFloodfill ();
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
if (!r->Update (buf, len))
|
||||
{
|
||||
updated = false;
|
||||
m_Requests.RequestComplete (ident, r);
|
||||
return r;
|
||||
}
|
||||
if (r->IsUnreachable ())
|
||||
{
|
||||
// delete router as invalid after update
|
||||
m_RouterInfos.erase (ident);
|
||||
if (wasFloodfill)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.Remove (r->GetIdentHash ());
|
||||
}
|
||||
m_Requests.RequestComplete (ident, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
r->Update (buf, len);
|
||||
}
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
|
||||
if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated
|
||||
@@ -265,14 +281,9 @@ namespace data
|
||||
LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
if (wasFloodfill)
|
||||
m_Floodfills.Remove (r->GetIdentHash ());
|
||||
m_Floodfills.remove (r);
|
||||
else if (r->IsEligibleFloodfill ())
|
||||
{
|
||||
if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD || r->GetProfile ()->IsReal ())
|
||||
m_Floodfills.Insert (r);
|
||||
else
|
||||
r->ResetFlooldFill ();
|
||||
}
|
||||
m_Floodfills.push_back (r);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -284,7 +295,7 @@ namespace data
|
||||
else
|
||||
{
|
||||
r = std::make_shared<RouterInfo> (buf, len);
|
||||
if (!r->IsUnreachable () && r->HasValidAddresses () && (!r->IsFloodfill () || !r->GetProfile ()->IsUnreachable ()) &&
|
||||
if (!r->IsUnreachable () && r->HasValidAddresses () &&
|
||||
i2p::util::GetMillisecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL > r->GetTimestamp ())
|
||||
{
|
||||
bool inserted = false;
|
||||
@@ -297,14 +308,8 @@ namespace data
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
|
||||
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
|
||||
{
|
||||
if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD ||
|
||||
r->GetProfile ()->IsReal ()) // don't insert floodfill until it's known real if we have enough
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.Insert (r);
|
||||
}
|
||||
else
|
||||
r->ResetFlooldFill ();
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.push_back (r);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -420,27 +425,9 @@ namespace data
|
||||
|
||||
void NetDb::SetUnreachable (const IdentHash& ident, bool unreachable)
|
||||
{
|
||||
auto r = FindRouter (ident);
|
||||
if (r)
|
||||
{
|
||||
r->SetUnreachable (unreachable);
|
||||
if (unreachable)
|
||||
{
|
||||
auto profile = r->GetProfile ();
|
||||
if (profile)
|
||||
profile->Unreachable ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports)
|
||||
{
|
||||
auto r = FindRouter (ident);
|
||||
if (r)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
r->ExcludeReachableTransports (transports);
|
||||
}
|
||||
auto it = m_RouterInfos.find (ident);
|
||||
if (it != m_RouterInfos.end ())
|
||||
return it->second->SetUnreachable (unreachable);
|
||||
}
|
||||
|
||||
void NetDb::Reseed ()
|
||||
@@ -452,8 +439,8 @@ namespace data
|
||||
}
|
||||
|
||||
// try reseeding from floodfill first if specified
|
||||
std::string riPath; i2p::config::GetOption("reseed.floodfill", riPath);
|
||||
if (!riPath.empty())
|
||||
std::string riPath;
|
||||
if(i2p::config::GetOption("reseed.floodfill", riPath))
|
||||
{
|
||||
auto ri = std::make_shared<RouterInfo>(riPath);
|
||||
if (ri->IsFloodfill())
|
||||
@@ -515,7 +502,7 @@ namespace data
|
||||
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
|
||||
{
|
||||
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
|
||||
m_Floodfills.Insert (r);
|
||||
m_Floodfills.push_back (r);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -599,7 +586,7 @@ namespace data
|
||||
{
|
||||
// make sure we cleanup netDb from previous attempts
|
||||
m_RouterInfos.clear ();
|
||||
m_Floodfills.Clear ();
|
||||
m_Floodfills.clear ();
|
||||
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||
std::vector<std::string> files;
|
||||
@@ -607,20 +594,18 @@ namespace data
|
||||
for (const auto& path : files)
|
||||
LoadRouterInfo (path, ts);
|
||||
|
||||
LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.GetSize (), " floodfils)");
|
||||
LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)");
|
||||
}
|
||||
|
||||
void NetDb::SaveUpdated ()
|
||||
{
|
||||
int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0;
|
||||
auto total = m_RouterInfos.size ();
|
||||
auto totalFloodfills = m_Floodfills.GetSize ();
|
||||
auto totalFloodfills = m_Floodfills.size ();
|
||||
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||
auto uptime = i2p::context.GetUptime ();
|
||||
double minTunnelCreationSuccessRate;
|
||||
i2p::config::GetOption("limits.zombies", minTunnelCreationSuccessRate);
|
||||
bool isLowRate = i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < minTunnelCreationSuccessRate;
|
||||
bool isLowRate = i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () < NETDB_MIN_TUNNEL_CREATION_SUCCESS_RATE;
|
||||
// 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
|
||||
if (checkForExpiration && uptime > 3600) // 1 hour
|
||||
@@ -634,37 +619,31 @@ namespace data
|
||||
std::string ident = it.second->GetIdentHashBase64();
|
||||
if (it.second->IsUpdated ())
|
||||
{
|
||||
if (it.second->GetBuffer ())
|
||||
{
|
||||
// we have something to save
|
||||
it.second->SaveToFile (m_Storage.Path(ident));
|
||||
it.second->SetUnreachable (false);
|
||||
it.second->DeleteBuffer ();
|
||||
}
|
||||
it.second->SaveToFile (m_Storage.Path(ident));
|
||||
it.second->SetUpdated (false);
|
||||
it.second->SetUnreachable (false);
|
||||
it.second->DeleteBuffer ();
|
||||
updatedCount++;
|
||||
continue;
|
||||
}
|
||||
if (it.second->GetProfile ()->IsUnreachable ())
|
||||
it.second->SetUnreachable (true);
|
||||
// make router reachable back if too few routers or floodfills
|
||||
if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate ||
|
||||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
|
||||
it.second->SetUnreachable (false);
|
||||
if (!it.second->IsUnreachable ())
|
||||
// find & mark expired routers
|
||||
if (!it.second->IsReachable () && (it.second->GetCompatibleTransports (true) & RouterInfo::eSSU2V4))
|
||||
// non-reachable router, but reachable by ipv4 SSU2 means introducers
|
||||
{
|
||||
// find & mark expired routers
|
||||
if (!it.second->GetCompatibleTransports (true)) // non reachable by any transport
|
||||
if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)
|
||||
// RouterInfo expires after 1 hour if uses introducer
|
||||
it.second->SetUnreachable (true);
|
||||
else if (checkForExpiration && ts > it.second->GetTimestamp () + expirationTimeout)
|
||||
it.second->SetUnreachable (true);
|
||||
else if (ts + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < it.second->GetTimestamp ())
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: RouterInfo is from future for ", (it.second->GetTimestamp () - ts)/1000LL, " seconds");
|
||||
it.second->SetUnreachable (true);
|
||||
}
|
||||
if (it.second->IsUnreachable () && i2p::transport::transports.IsConnected (it.second->GetIdentHash ()))
|
||||
it.second->SetUnreachable (false); // don't expire connected router
|
||||
}
|
||||
else if (checkForExpiration && ts > it.second->GetTimestamp () + expirationTimeout)
|
||||
it.second->SetUnreachable (true);
|
||||
else if (ts + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < it.second->GetTimestamp ())
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: RouterInfo is from future for ", (it.second->GetTimestamp () - ts)/1000LL, " seconds");
|
||||
it.second->SetUnreachable (true);
|
||||
}
|
||||
|
||||
if (it.second->IsUnreachable ())
|
||||
@@ -680,7 +659,6 @@ namespace data
|
||||
m_RouterInfoBuffersPool.CleanUpMt ();
|
||||
m_RouterInfoAddressesPool.CleanUpMt ();
|
||||
m_RouterInfoAddressVectorsPool.CleanUpMt ();
|
||||
m_IdentitiesPool.CleanUpMt ();
|
||||
|
||||
if (updatedCount > 0)
|
||||
LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers");
|
||||
@@ -693,21 +671,22 @@ namespace data
|
||||
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
|
||||
{
|
||||
if (it->second->IsUnreachable ())
|
||||
it = m_RouterInfos.erase (it);
|
||||
else
|
||||
{
|
||||
it->second->DropProfile ();
|
||||
it++;
|
||||
if (m_PersistProfiles) it->second->SaveProfile ();
|
||||
it = m_RouterInfos.erase (it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
// clean up expired floodfills or not floodfills anymore
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.Cleanup ([](const std::shared_ptr<RouterInfo>& r)->bool
|
||||
{
|
||||
return r && r->IsFloodfill () && !r->IsUnreachable ();
|
||||
});
|
||||
for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();)
|
||||
if ((*it)->IsUnreachable () || !(*it)->IsFloodfill ())
|
||||
it = m_Floodfills.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -735,11 +714,7 @@ namespace data
|
||||
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);
|
||||
outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0,
|
||||
i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
||||
}
|
||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound));
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found");
|
||||
@@ -804,22 +779,19 @@ namespace data
|
||||
LogPrint (eLogError, "NetDb: Database store msg with reply token is too short ", len, ". Dropped");
|
||||
return;
|
||||
}
|
||||
auto deliveryStatus = CreateDeliveryStatusMsg (replyToken);
|
||||
uint32_t tunnelID = bufbe32toh (buf + offset);
|
||||
offset += 4;
|
||||
if (replyToken != 0xFFFFFFFFU) // if not caught on OBEP or IBGW
|
||||
if (!tunnelID) // send response directly
|
||||
transports.SendMessage (buf + offset, deliveryStatus);
|
||||
else
|
||||
{
|
||||
auto deliveryStatus = CreateDeliveryStatusMsg (replyToken);
|
||||
if (!tunnelID) // send response directly
|
||||
transports.SendMessage (buf + offset, deliveryStatus);
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
|
||||
if (outbound)
|
||||
outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus);
|
||||
else
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
|
||||
if (outbound)
|
||||
outbound->SendTunnelDataMsgTo (buf + offset, tunnelID, deliveryStatus);
|
||||
else
|
||||
LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found");
|
||||
}
|
||||
LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found");
|
||||
}
|
||||
offset += 32;
|
||||
}
|
||||
@@ -839,13 +811,8 @@ namespace data
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: Database store message is too long ", len);
|
||||
return;
|
||||
}
|
||||
if (!context.IsFloodfill ())
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: Not Floodfill, LeaseSet store request ignored for ", ident.ToBase32());
|
||||
return;
|
||||
}
|
||||
else if (!m->from) // unsolicited LS must be received directly
|
||||
}
|
||||
if (!m->from) // unsolicited LS must be received directly
|
||||
{
|
||||
if (storeType == NETDB_STORE_TYPE_LEASESET) // 1
|
||||
{
|
||||
@@ -854,7 +821,7 @@ namespace data
|
||||
}
|
||||
else // all others are considered as LeaseSet2
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", int(storeType), " for ", ident.ToBase32());
|
||||
LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", storeType, " for ", ident.ToBase32());
|
||||
updated = AddLeaseSet2 (ident, buf + offset, len - offset, storeType);
|
||||
}
|
||||
}
|
||||
@@ -931,7 +898,7 @@ namespace data
|
||||
{
|
||||
// request destination
|
||||
LogPrint (eLogDebug, "NetDb: Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ());
|
||||
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
|
||||
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
|
||||
dest->CreateRequestMessage (nextFloodfill, inbound));
|
||||
deleteDest = false;
|
||||
}
|
||||
@@ -1039,10 +1006,11 @@ namespace data
|
||||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
|
||||
{
|
||||
auto router = FindRouter (ident);
|
||||
if (router && !router->IsUnreachable ())
|
||||
if (router)
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: Requested RouterInfo ", key, " found");
|
||||
if (PopulateRouterInfoBuffer (router))
|
||||
PopulateRouterInfoBuffer (router);
|
||||
if (router->GetBuffer ())
|
||||
replyMsg = CreateDatabaseStoreMsg (router);
|
||||
}
|
||||
}
|
||||
@@ -1111,7 +1079,7 @@ namespace data
|
||||
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
|
||||
if (outbound)
|
||||
outbound->SendTunnelDataMsgTo (replyIdent, replyTunnelID, replyMsg);
|
||||
outbound->SendTunnelDataMsg (replyIdent, replyTunnelID, replyMsg);
|
||||
else
|
||||
transports.SendMessage (replyIdent, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
|
||||
}
|
||||
@@ -1120,6 +1088,16 @@ namespace data
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg)
|
||||
{
|
||||
if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: Publishing confirmed. reply token=", m_PublishReplyToken);
|
||||
m_PublishExcluded.clear ();
|
||||
m_PublishReplyToken = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::Explore (int numDestinations)
|
||||
{
|
||||
// new requests
|
||||
@@ -1167,7 +1145,42 @@ namespace data
|
||||
m_Requests.RequestComplete (randomHash, nullptr);
|
||||
}
|
||||
if (throughTunnels && msgs.size () > 0)
|
||||
outbound->SendTunnelDataMsgs (msgs);
|
||||
outbound->SendTunnelDataMsg (msgs);
|
||||
}
|
||||
|
||||
void NetDb::Publish ()
|
||||
{
|
||||
i2p::context.UpdateStats (); // for floodfill
|
||||
|
||||
if (m_PublishExcluded.size () > NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS)
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
|
||||
m_PublishExcluded.clear ();
|
||||
}
|
||||
|
||||
auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
|
||||
if (floodfill)
|
||||
{
|
||||
uint32_t replyToken;
|
||||
RAND_bytes ((uint8_t *)&replyToken, 4);
|
||||
LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
|
||||
m_PublishExcluded.insert (floodfill->GetIdentHash ());
|
||||
m_PublishReplyToken = replyToken;
|
||||
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
|
||||
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
|
||||
// send directly
|
||||
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
|
||||
else
|
||||
{
|
||||
// otherwise through exploratory
|
||||
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
|
||||
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
|
||||
if (inbound && outbound)
|
||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
|
||||
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg)
|
||||
@@ -1207,7 +1220,7 @@ namespace data
|
||||
return !router->IsHidden () && router != compatibleWith &&
|
||||
(reverse ? compatibleWith->IsReachableFrom (*router) :
|
||||
router->IsReachableFrom (*compatibleWith)) &&
|
||||
router->IsECIES () && !router->IsHighCongestion (false);
|
||||
router->IsECIES ();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1241,7 +1254,7 @@ namespace data
|
||||
router->IsReachableFrom (*compatibleWith)) &&
|
||||
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
|
||||
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
|
||||
router->IsECIES () && !router->IsHighCongestion (true);
|
||||
router->IsECIES ();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1309,39 +1322,79 @@ namespace data
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
|
||||
const std::set<IdentHash>& excluded) const
|
||||
const std::set<IdentHash>& excluded, bool closeThanUsOnly) const
|
||||
{
|
||||
std::shared_ptr<const RouterInfo> r;
|
||||
XORMetric minMetric;
|
||||
IdentHash destKey = CreateRoutingKey (destination);
|
||||
if (closeThanUsOnly)
|
||||
minMetric = destKey ^ i2p::context.GetIdentHash ();
|
||||
else
|
||||
minMetric.SetMax ();
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
return m_Floodfills.FindClosest (destKey, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
|
||||
for (const auto& it: m_Floodfills)
|
||||
{
|
||||
if (!it->IsUnreachable ())
|
||||
{
|
||||
return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
|
||||
!excluded.count (r->GetIdentHash ());
|
||||
});
|
||||
XORMetric m = destKey ^ it->GetIdentHash ();
|
||||
if (m < minMetric && !excluded.count (it->GetIdentHash ()))
|
||||
{
|
||||
minMetric = m;
|
||||
r = it;
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
|
||||
std::set<IdentHash>& excluded, bool closeThanUsOnly) const
|
||||
{
|
||||
std::vector<IdentHash> res;
|
||||
IdentHash destKey = CreateRoutingKey (destination);
|
||||
std::vector<std::shared_ptr<RouterInfo> > v;
|
||||
struct Sorted
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
v = m_Floodfills.FindClosest (destKey, num, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
|
||||
{
|
||||
return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
|
||||
!excluded.count (r->GetIdentHash ());
|
||||
});
|
||||
}
|
||||
if (v.empty ()) return res;
|
||||
std::shared_ptr<const RouterInfo> r;
|
||||
XORMetric metric;
|
||||
bool operator< (const Sorted& other) const { return metric < other.metric; };
|
||||
};
|
||||
|
||||
std::set<Sorted> sorted;
|
||||
IdentHash destKey = CreateRoutingKey (destination);
|
||||
XORMetric ourMetric;
|
||||
if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
|
||||
for (auto& it: v)
|
||||
{
|
||||
if (closeThanUsOnly && ourMetric < (destKey ^ it->GetIdentHash ())) break;
|
||||
res.push_back (it->GetIdentHash ());
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
for (const auto& it: m_Floodfills)
|
||||
{
|
||||
if (!it->IsUnreachable ())
|
||||
{
|
||||
XORMetric m = destKey ^ it->GetIdentHash ();
|
||||
if (closeThanUsOnly && ourMetric < m) continue;
|
||||
if (sorted.size () < num)
|
||||
sorted.insert ({it, m});
|
||||
else if (m < sorted.rbegin ()->metric)
|
||||
{
|
||||
sorted.insert ({it, m});
|
||||
sorted.erase (std::prev (sorted.end ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<IdentHash> res;
|
||||
size_t i = 0;
|
||||
for (const auto& it: sorted)
|
||||
{
|
||||
if (i < num)
|
||||
{
|
||||
const auto& ident = it.r->GetIdentHash ();
|
||||
if (!excluded.count (ident))
|
||||
{
|
||||
res.push_back (ident);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1378,17 +1431,6 @@ namespace data
|
||||
return r;
|
||||
}
|
||||
|
||||
void NetDb::ManageRouterInfos ()
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
for (auto& it: m_RouterInfos)
|
||||
it.second->UpdateIntroducers (ts);
|
||||
}
|
||||
SaveUpdated ();
|
||||
}
|
||||
|
||||
void NetDb::ManageLeaseSets ()
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
@@ -1405,11 +1447,10 @@ namespace data
|
||||
m_LeasesPool.CleanUpMt ();
|
||||
}
|
||||
|
||||
bool NetDb::PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r)
|
||||
void NetDb::PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r)
|
||||
{
|
||||
if (!r) return false;
|
||||
if (r->GetBuffer ()) return true;
|
||||
return r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ()));
|
||||
if (!r || r->GetBuffer ()) return;
|
||||
r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
@@ -30,7 +31,6 @@
|
||||
#include "Family.h"
|
||||
#include "version.h"
|
||||
#include "util.h"
|
||||
#include "KadDHT.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
@@ -38,14 +38,18 @@ namespace data
|
||||
{
|
||||
const int NETDB_MIN_ROUTERS = 90;
|
||||
const int NETDB_MIN_FLOODFILLS = 5;
|
||||
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1500;
|
||||
const int NETDB_MIN_TUNNEL_CREATION_SUCCESS_RATE = 8; // in percents
|
||||
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
|
||||
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60;
|
||||
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_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days
|
||||
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_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
||||
const int NETDB_PUBLISH_INTERVAL = 60 * 40;
|
||||
const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||
const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
|
||||
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36
|
||||
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 38); // 0.9.38
|
||||
const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
||||
|
||||
/** function for visiting a leaseset stored in a floodfill */
|
||||
@@ -82,28 +86,31 @@ namespace data
|
||||
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
||||
void HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
||||
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::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::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
||||
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
|
||||
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
||||
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
|
||||
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
||||
void ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports);
|
||||
|
||||
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
/** set hidden mode, aka don't publish our RI to netdb and don't explore */
|
||||
void SetHidden(bool hide);
|
||||
|
||||
void Reseed ();
|
||||
Families& GetFamilies () { return m_Families; };
|
||||
|
||||
// for web interface
|
||||
int GetNumRouters () const { return m_RouterInfos.size (); };
|
||||
int GetNumFloodfills () const { return m_Floodfills.GetSize (); };
|
||||
int GetNumFloodfills () const { return m_Floodfills.size (); };
|
||||
int GetNumLeaseSets () const { return m_LeaseSets.size (); };
|
||||
|
||||
/** visit all lease sets we currently store */
|
||||
@@ -117,7 +124,7 @@ namespace data
|
||||
|
||||
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
||||
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
|
||||
bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
|
||||
void PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
|
||||
std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); };
|
||||
boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses ()
|
||||
{
|
||||
@@ -127,7 +134,6 @@ namespace data
|
||||
&m_RouterInfoAddressVectorsPool, std::placeholders::_1));
|
||||
};
|
||||
std::shared_ptr<Lease> NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); };
|
||||
std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) { return m_IdentitiesPool.AcquireSharedMt (buf, len); };
|
||||
|
||||
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
||||
|
||||
@@ -138,8 +144,8 @@ namespace data
|
||||
void SaveUpdated ();
|
||||
void Run (); // exploratory thread
|
||||
void Explore (int numDestinations);
|
||||
void Publish ();
|
||||
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg);
|
||||
void ManageRouterInfos ();
|
||||
void ManageLeaseSets ();
|
||||
void ManageRequests ();
|
||||
|
||||
@@ -158,7 +164,7 @@ namespace data
|
||||
mutable std::mutex m_RouterInfosMutex;
|
||||
std::unordered_map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
|
||||
mutable std::mutex m_FloodfillsMutex;
|
||||
DHTTable m_Floodfills;
|
||||
std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
|
||||
|
||||
bool m_IsRunning;
|
||||
std::thread * m_Thread;
|
||||
@@ -177,6 +183,9 @@ namespace data
|
||||
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
|
||||
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
|
||||
|
||||
/** true if in hidden mode */
|
||||
bool m_HiddenMode;
|
||||
|
||||
std::set<IdentHash> m_PublishExcluded;
|
||||
uint32_t m_PublishReplyToken = 0;
|
||||
|
||||
@@ -184,7 +193,6 @@ namespace data
|
||||
i2p::util::MemoryPoolMt<RouterInfo::Address> m_RouterInfoAddressesPool;
|
||||
i2p::util::MemoryPoolMt<RouterInfo::Addresses> m_RouterInfoAddressVectorsPool;
|
||||
i2p::util::MemoryPoolMt<Lease> m_LeasesPool;
|
||||
i2p::util::MemoryPoolMt<IdentityEx> m_IdentitiesPool;
|
||||
};
|
||||
|
||||
extern NetDb netdb;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -137,7 +137,7 @@ namespace data
|
||||
auto inbound = pool->GetNextInboundTunnel ();
|
||||
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||
if (nextFloodfill && outbound && inbound)
|
||||
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
|
||||
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
|
||||
dest->CreateRequestMessage (nextFloodfill, inbound));
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#include "Base.h"
|
||||
@@ -22,27 +19,24 @@ namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
static i2p::fs::HashedStorage g_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
|
||||
static std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > g_Profiles;
|
||||
static std::mutex g_ProfilesMutex;
|
||||
|
||||
static boost::posix_time::ptime GetTime ()
|
||||
{
|
||||
return boost::posix_time::second_clock::local_time();
|
||||
}
|
||||
i2p::fs::HashedStorage m_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
|
||||
|
||||
RouterProfile::RouterProfile ():
|
||||
m_LastUpdateTime (GetTime ()), m_IsUpdated (false),
|
||||
m_LastDeclineTime (0), m_LastUnreachableTime (0),
|
||||
m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
|
||||
m_LastDeclineTime (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)
|
||||
{
|
||||
}
|
||||
|
||||
boost::posix_time::ptime RouterProfile::GetTime () const
|
||||
{
|
||||
return boost::posix_time::second_clock::local_time();
|
||||
}
|
||||
|
||||
void RouterProfile::UpdateTime ()
|
||||
{
|
||||
m_LastUpdateTime = GetTime ();
|
||||
m_IsUpdated = true;
|
||||
}
|
||||
|
||||
void RouterProfile::Save (const IdentHash& identHash)
|
||||
@@ -55,18 +49,15 @@ namespace data
|
||||
boost::property_tree::ptree usage;
|
||||
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
|
||||
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
|
||||
usage.put (PEER_PROFILE_USAGE_CONNECTED, m_HasConnected);
|
||||
// fill property tree
|
||||
boost::property_tree::ptree pt;
|
||||
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
|
||||
if (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_USAGE, usage);
|
||||
|
||||
// save to file
|
||||
std::string ident = identHash.ToBase64 ();
|
||||
std::string path = g_ProfilesStorage.Path(ident);
|
||||
std::string path = m_ProfilesStorage.Path(ident);
|
||||
|
||||
try {
|
||||
boost::property_tree::write_ini (path, pt);
|
||||
@@ -79,7 +70,7 @@ namespace data
|
||||
void RouterProfile::Load (const IdentHash& identHash)
|
||||
{
|
||||
std::string ident = identHash.ToBase64 ();
|
||||
std::string path = g_ProfilesStorage.Path(ident);
|
||||
std::string path = m_ProfilesStorage.Path(ident);
|
||||
boost::property_tree::ptree pt;
|
||||
|
||||
if (!i2p::fs::Exists(path))
|
||||
@@ -105,7 +96,6 @@ namespace data
|
||||
m_LastUpdateTime = boost::posix_time::time_from_string (t);
|
||||
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||
{
|
||||
m_LastUnreachableTime = pt.get (PEER_PROFILE_LAST_UNREACHABLE_TIME, 0);
|
||||
try
|
||||
{
|
||||
// read participations
|
||||
@@ -124,7 +114,6 @@ namespace data
|
||||
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
|
||||
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
|
||||
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
|
||||
m_HasConnected = usage.get (PEER_PROFILE_USAGE_CONNECTED, false);
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path& ex)
|
||||
{
|
||||
@@ -144,37 +133,23 @@ namespace data
|
||||
{
|
||||
UpdateTime ();
|
||||
if (ret > 0)
|
||||
{
|
||||
{
|
||||
m_NumTunnelsDeclined++;
|
||||
m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_NumTunnelsAgreed++;
|
||||
{
|
||||
m_NumTunnelsAgreed++;
|
||||
m_LastDeclineTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RouterProfile::TunnelNonReplied ()
|
||||
{
|
||||
m_NumTunnelsNonReplied++;
|
||||
m_NumTunnelsNonReplied++;
|
||||
UpdateTime ();
|
||||
if (m_NumTunnelsNonReplied > 2*m_NumTunnelsAgreed && m_NumTunnelsNonReplied > 3)
|
||||
{
|
||||
m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterProfile::Unreachable ()
|
||||
{
|
||||
m_LastUnreachableTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
UpdateTime ();
|
||||
}
|
||||
|
||||
void RouterProfile::Connected ()
|
||||
{
|
||||
m_HasConnected = true;
|
||||
UpdateTime ();
|
||||
}
|
||||
|
||||
bool RouterProfile::IsLowPartcipationRate () const
|
||||
@@ -192,15 +167,14 @@ namespace data
|
||||
{
|
||||
if (!m_LastDeclineTime) return false;
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL ||
|
||||
ts + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL < m_LastDeclineTime)
|
||||
if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL)
|
||||
m_LastDeclineTime = 0;
|
||||
return (bool)m_LastDeclineTime;
|
||||
}
|
||||
|
||||
return m_LastDeclineTime;
|
||||
}
|
||||
|
||||
bool RouterProfile::IsBad ()
|
||||
{
|
||||
if (IsDeclinedRecently () || IsUnreachable ()) return true;
|
||||
if (IsDeclinedRecently ()) return true;
|
||||
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
||||
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
||||
{
|
||||
@@ -214,103 +188,32 @@ namespace data
|
||||
return isBad;
|
||||
}
|
||||
|
||||
bool RouterProfile::IsUnreachable ()
|
||||
{
|
||||
if (!m_LastUnreachableTime) return false;
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts > m_LastUnreachableTime + PEER_PROFILE_UNREACHABLE_INTERVAL ||
|
||||
ts + PEER_PROFILE_UNREACHABLE_INTERVAL < m_LastUnreachableTime)
|
||||
m_LastUnreachableTime = 0;
|
||||
return (bool)m_LastUnreachableTime;
|
||||
}
|
||||
|
||||
bool RouterProfile::IsUseful() const
|
||||
{
|
||||
return IsReal () || m_NumTunnelsNonReplied >= PEER_PROFILE_USEFUL_THRESHOLD;
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
auto it = g_Profiles.find (identHash);
|
||||
if (it != g_Profiles.end ())
|
||||
return it->second;
|
||||
}
|
||||
auto profile = std::make_shared<RouterProfile> ();
|
||||
profile->Load (identHash); // if possible
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
g_Profiles.emplace (identHash, profile);
|
||||
return profile;
|
||||
}
|
||||
|
||||
void InitProfilesStorage ()
|
||||
{
|
||||
g_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
|
||||
g_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
|
||||
}
|
||||
|
||||
void PersistProfiles ()
|
||||
{
|
||||
auto ts = GetTime ();
|
||||
std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > > tmp;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
||||
{
|
||||
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () > PEER_PROFILE_PERSIST_INTERVAL)
|
||||
{
|
||||
if (it->second->IsUpdated ())
|
||||
tmp.push_back (std::make_pair (it->first, it->second));
|
||||
it = g_Profiles.erase (it);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
for (auto& it: tmp)
|
||||
if (it.second) it.second->Save (it.first);
|
||||
}
|
||||
|
||||
void SaveProfiles ()
|
||||
{
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > tmp;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
tmp = g_Profiles;
|
||||
g_Profiles.clear ();
|
||||
}
|
||||
auto ts = GetTime ();
|
||||
for (auto& it: tmp)
|
||||
if (it.second->IsUseful() && (it.second->IsUpdated () || (ts - it.second->GetLastUpdateTime ()).total_seconds () < PEER_PROFILE_EXPIRATION_TIMEOUT*3600))
|
||||
it.second->Save (it.first);
|
||||
m_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
|
||||
m_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
|
||||
}
|
||||
|
||||
void DeleteObsoleteProfiles ()
|
||||
{
|
||||
{
|
||||
auto ts = GetTime ();
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
||||
{
|
||||
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600)
|
||||
it = g_Profiles.erase (it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
std::time_t now = std::time(nullptr);
|
||||
|
||||
std::vector<std::string> files;
|
||||
g_ProfilesStorage.Traverse(files);
|
||||
m_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) {
|
||||
if (((now - st.st_mtime) / 3600) >= PEER_PROFILE_EXPIRATION_TIMEOUT) {
|
||||
LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path);
|
||||
i2p::fs::Remove(path);
|
||||
}
|
||||
|
||||
@@ -22,21 +22,16 @@ namespace data
|
||||
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
|
||||
// params
|
||||
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
|
||||
const char PEER_PROFILE_LAST_UNREACHABLE_TIME[] = "lastunreachabletime";
|
||||
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
|
||||
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
|
||||
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
|
||||
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
|
||||
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
|
||||
const char PEER_PROFILE_USAGE_CONNECTED[] = "connected";
|
||||
|
||||
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36; // in hours (1.5 days)
|
||||
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 6 * 3600; // in seconds (6 hours)
|
||||
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3600; // in seconds (1 hour)
|
||||
|
||||
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
|
||||
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 24 * 3600; // in seconds (1 day)
|
||||
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3 * 3600; // in seconds (3 hours)
|
||||
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_UNREACHABLE_INTERVAL = 2*3600; // on seconds (2 hours)
|
||||
const int PEER_PROFILE_USEFUL_THRESHOLD = 3;
|
||||
|
||||
class RouterProfile
|
||||
{
|
||||
@@ -49,22 +44,13 @@ namespace data
|
||||
void Load (const IdentHash& identHash);
|
||||
|
||||
bool IsBad ();
|
||||
bool IsUnreachable ();
|
||||
bool IsReal () const { return m_HasConnected || m_NumTunnelsAgreed > 0 || m_NumTunnelsDeclined > 0; }
|
||||
|
||||
void TunnelBuildResponse (uint8_t ret);
|
||||
void TunnelNonReplied ();
|
||||
|
||||
void Unreachable ();
|
||||
void Connected ();
|
||||
|
||||
boost::posix_time::ptime GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||
bool IsUpdated () const { return m_IsUpdated; };
|
||||
|
||||
bool IsUseful() const;
|
||||
|
||||
private:
|
||||
|
||||
boost::posix_time::ptime GetTime () const;
|
||||
void UpdateTime ();
|
||||
|
||||
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
||||
@@ -75,8 +61,7 @@ namespace data
|
||||
private:
|
||||
|
||||
boost::posix_time::ptime m_LastUpdateTime; // TODO: use std::chrono
|
||||
bool m_IsUpdated;
|
||||
uint64_t m_LastDeclineTime, m_LastUnreachableTime; // in seconds
|
||||
uint64_t m_LastDeclineTime; // in seconds
|
||||
// participation
|
||||
uint32_t m_NumTunnelsAgreed;
|
||||
uint32_t m_NumTunnelsDeclined;
|
||||
@@ -84,14 +69,11 @@ namespace data
|
||||
// usage
|
||||
uint32_t m_NumTimesTaken;
|
||||
uint32_t m_NumTimesRejected;
|
||||
bool m_HasConnected; // successful trusted(incoming or NTCP2) connection
|
||||
};
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
||||
void InitProfilesStorage ();
|
||||
void DeleteObsoleteProfiles ();
|
||||
void SaveProfiles ();
|
||||
void PersistProfiles ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -153,7 +153,7 @@ namespace data
|
||||
return ProcessSU3Stream (s);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogCritical, "Reseed: Can't open file ", filename);
|
||||
LogPrint (eLogError, "Reseed: Can't open file ", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ namespace data
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogCritical, "Reseed: Can't open file ", filename);
|
||||
LogPrint (eLogError, "Reseed: Can't open file ", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -278,7 +278,7 @@ namespace data
|
||||
|
||||
if (verify) // not verified
|
||||
{
|
||||
LogPrint (eLogCritical, "Reseed: SU3 verification failed");
|
||||
LogPrint (eLogError, "Reseed: SU3 verification failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ namespace data
|
||||
uint16_t fileNameLength, extraFieldLength;
|
||||
s.read ((char *)&fileNameLength, 2);
|
||||
fileNameLength = le16toh (fileNameLength);
|
||||
if ( fileNameLength >= 255 ) {
|
||||
if ( fileNameLength > 255 ) {
|
||||
// too big
|
||||
LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength);
|
||||
return numFiles;
|
||||
@@ -492,7 +492,7 @@ namespace data
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogCritical, "Reseed: Can't open certificate file ", filename);
|
||||
LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
|
||||
SSL_CTX_free (ctx);
|
||||
}
|
||||
|
||||
@@ -534,17 +534,17 @@ namespace data
|
||||
}
|
||||
// check for valid proxy url schema
|
||||
if (proxyUrl.schema != "http" && proxyUrl.schema != "socks") {
|
||||
LogPrint(eLogCritical, "Reseed: Bad proxy url: ", proxy);
|
||||
LogPrint(eLogError, "Reseed: Bad proxy url: ", proxy);
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
LogPrint(eLogCritical, "Reseed: Bad proxy url: ", proxy);
|
||||
LogPrint(eLogError, "Reseed: Bad proxy url: ", proxy);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
i2p::http::URL url;
|
||||
if (!url.parse(address)) {
|
||||
LogPrint(eLogCritical, "Reseed: Failed to parse url: ", address);
|
||||
LogPrint(eLogError, "Reseed: Failed to parse url: ", address);
|
||||
return "";
|
||||
}
|
||||
url.schema = "https";
|
||||
@@ -687,23 +687,12 @@ namespace data
|
||||
while (it != end)
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint ep = *it;
|
||||
if (
|
||||
(
|
||||
!i2p::util::net::IsInReservedRange(ep.address ()) && (
|
||||
(ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
|
||||
(ep.address ().is_v6 () && i2p::context.SupportsV6 ())
|
||||
)
|
||||
) ||
|
||||
(
|
||||
i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
|
||||
i2p::context.SupportsMesh ()
|
||||
)
|
||||
)
|
||||
if ((ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
|
||||
(ep.address ().is_v6 () && i2p::context.SupportsV6 ()))
|
||||
{
|
||||
s.lowest_layer().connect (ep, ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint (eLogDebug, "Reseed: Resolved to ", ep.address ());
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
@@ -791,45 +780,17 @@ namespace data
|
||||
boost::asio::io_service service;
|
||||
boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6());
|
||||
|
||||
auto it = boost::asio::ip::tcp::resolver(service).resolve (
|
||||
boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode);
|
||||
|
||||
if (url.host.length () < 2) return ""; // assume []
|
||||
auto host = url.host.substr (1, url.host.length () - 2);
|
||||
LogPrint (eLogDebug, "Reseed: Connecting to Yggdrasil ", url.host, ":", url.port);
|
||||
s.connect (boost::asio::ip::tcp::endpoint (boost::asio::ip::address_v6::from_string (host), url.port), ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
bool connected = false;
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
while (it != end)
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint ep = *it;
|
||||
if (
|
||||
i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
|
||||
i2p::context.SupportsMesh ()
|
||||
)
|
||||
{
|
||||
LogPrint (eLogDebug, "Reseed: Yggdrasil: Resolved to ", ep.address ());
|
||||
s.connect (ep, ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
if (!connected)
|
||||
{
|
||||
LogPrint(eLogError, "Reseed: Yggdrasil: Failed to connect to ", url.host);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint (eLogDebug, "Reseed: Yggdrasil: Connected to ", url.host, ":", url.port);
|
||||
LogPrint (eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port);
|
||||
return ReseedRequest (s, url.to_string());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Yggdrasil: Couldn't connect to ", url.host, ": ", ecode.message ());
|
||||
LogPrint (eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message ());
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#include "Log.h"
|
||||
#include "Family.h"
|
||||
#include "ECIESX25519AEADRatchetSession.h"
|
||||
#include "Transports.h"
|
||||
#include "Tunnel.h"
|
||||
#include "RouterContext.h"
|
||||
|
||||
namespace i2p
|
||||
@@ -31,8 +29,7 @@ namespace i2p
|
||||
RouterContext::RouterContext ():
|
||||
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
||||
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
|
||||
m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID),
|
||||
m_PublishReplyToken (0), m_IsHiddenMode (false)
|
||||
m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -50,34 +47,6 @@ namespace i2p
|
||||
m_ECIESSession = std::make_shared<i2p::garlic::RouterIncomingRatchetSession>(m_InitialNoiseState);
|
||||
}
|
||||
|
||||
void RouterContext::Start ()
|
||||
{
|
||||
if (!m_Service)
|
||||
{
|
||||
m_Service.reset (new RouterService);
|
||||
m_Service->Start ();
|
||||
if (!m_IsHiddenMode)
|
||||
{
|
||||
m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleInitialPublish ();
|
||||
m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleCongestionUpdate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::Stop ()
|
||||
{
|
||||
if (m_Service)
|
||||
{
|
||||
if (m_PublishTimer)
|
||||
m_PublishTimer->cancel ();
|
||||
if (m_CongestionUpdateTimer)
|
||||
m_CongestionUpdateTimer->cancel ();
|
||||
m_Service->Stop ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::CreateNewRouter ()
|
||||
{
|
||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
||||
@@ -116,103 +85,96 @@ namespace i2p
|
||||
bool ssu2Published = false;
|
||||
if (ssu2)
|
||||
i2p::config::GetOption("ssu2.published", ssu2Published);
|
||||
uint8_t caps = 0;
|
||||
uint8_t caps = 0, addressCaps = 0;
|
||||
if (ipv4)
|
||||
{
|
||||
std::string host;
|
||||
if (!nat)
|
||||
std::string host = "127.0.0.1";
|
||||
if (!i2p::config::IsDefault("host"))
|
||||
i2p::config::GetOption("host", host);
|
||||
else if (!nat)
|
||||
{
|
||||
// we have no NAT so set external address from local address
|
||||
i2p::config::GetOption("address4", host);
|
||||
if (host.empty ()) i2p::config::GetOption("host", host);
|
||||
std::string address4; i2p::config::GetOption("address4", address4);
|
||||
if (!address4.empty ()) host = address4;
|
||||
}
|
||||
|
||||
if (ntcp2)
|
||||
{
|
||||
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
|
||||
if (!ntcp2Port) ntcp2Port = port;
|
||||
if (ntcp2Published && ntcp2Port)
|
||||
if (ntcp2Published)
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v4::from_string (host), port);
|
||||
else // add non-published NTCP2 address
|
||||
{
|
||||
boost::asio::ip::address addr;
|
||||
if (!host.empty ())
|
||||
addr = boost::asio::ip::address::from_string (host);
|
||||
if (!addr.is_v4())
|
||||
addr = boost::asio::ip::address_v4 ();
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
// add non-published NTCP2 address
|
||||
uint8_t addressCaps = i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, addressCaps);
|
||||
addressCaps = i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
|
||||
}
|
||||
}
|
||||
if (ssu2)
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = port;
|
||||
if (ssu2Published && ssu2Port)
|
||||
if (ssu2Published)
|
||||
{
|
||||
boost::asio::ip::address addr;
|
||||
if (!host.empty ())
|
||||
addr = boost::asio::ip::address::from_string (host);
|
||||
if (!addr.is_v4())
|
||||
addr = boost::asio::ip::address_v4 ();
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = port;
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), ssu2Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t addressCaps = i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, addressCaps);
|
||||
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ipv6)
|
||||
{
|
||||
std::string host; i2p::config::GetOption("address6", host);
|
||||
if (host.empty () && !ipv4) i2p::config::GetOption("host", host); // use host for ipv6 only if ipv4 is not presented
|
||||
std::string host;
|
||||
if (!i2p::config::IsDefault("host") && !ipv4) // override if v6 only
|
||||
i2p::config::GetOption("host", host);
|
||||
else
|
||||
{
|
||||
std::string address6; i2p::config::GetOption("address6", address6);
|
||||
if (!address6.empty ()) host = address6;
|
||||
}
|
||||
|
||||
if (ntcp2)
|
||||
{
|
||||
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
|
||||
if (!ntcp2Port) ntcp2Port = port;
|
||||
if (ntcp2Published && ntcp2Port)
|
||||
bool added = false;
|
||||
if (ntcp2Published)
|
||||
{
|
||||
std::string ntcp2Host;
|
||||
if (!i2p::config::IsDefault ("ntcp2.addressv6"))
|
||||
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
|
||||
else
|
||||
ntcp2Host = host;
|
||||
boost::asio::ip::address addr;
|
||||
if (!ntcp2Host.empty ())
|
||||
addr = boost::asio::ip::address::from_string (ntcp2Host);
|
||||
if (!addr.is_v6())
|
||||
addr = boost::asio::ip::address_v6 ();
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
|
||||
if (!ntcp2Host.empty () && port)
|
||||
{
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v6::from_string (ntcp2Host), port);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!added)
|
||||
{
|
||||
if (!ipv4) // no other ntcp2 addresses yet
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::AddressCaps::eV6);
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
|
||||
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||
}
|
||||
}
|
||||
if (ssu2)
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = port;
|
||||
if (ssu2Published && ssu2Port)
|
||||
bool added = false;
|
||||
if (ssu2Published)
|
||||
{
|
||||
boost::asio::ip::address addr;
|
||||
if (!host.empty ())
|
||||
addr = boost::asio::ip::address::from_string (host);
|
||||
if (!addr.is_v6())
|
||||
addr = boost::asio::ip::address_v6 ();
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = port;
|
||||
if (!host.empty () && ssu2Port)
|
||||
{
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), ssu2Port);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!added)
|
||||
{
|
||||
if (!ipv4) // no other ssu2 addresses yet
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::AddressCaps::eV6);
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
|
||||
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,24 +185,20 @@ namespace i2p
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port);
|
||||
}
|
||||
|
||||
if (addressCaps)
|
||||
routerInfo.SetUnreachableAddressesTransportCaps (addressCaps);
|
||||
routerInfo.UpdateCaps (caps); // caps + L
|
||||
routerInfo.SetProperty ("netId", std::to_string (m_NetID));
|
||||
routerInfo.SetProperty ("router.version", I2P_VERSION);
|
||||
routerInfo.CreateBuffer (m_Keys);
|
||||
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||
m_RouterInfo.SetUnreachable (false);
|
||||
}
|
||||
|
||||
uint16_t RouterContext::SelectRandomPort () const
|
||||
{
|
||||
uint16_t port;
|
||||
do
|
||||
{
|
||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||
}
|
||||
while(i2p::util::net::IsPortInReservedRange(port));
|
||||
|
||||
uint16_t port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||
if (port == 9150) port = 9151; // Tor browser
|
||||
return port;
|
||||
}
|
||||
|
||||
@@ -292,7 +250,7 @@ namespace i2p
|
||||
break;
|
||||
case eRouterStatusTesting:
|
||||
m_Error = eRouterErrorNone;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
@@ -314,7 +272,7 @@ namespace i2p
|
||||
break;
|
||||
case eRouterStatusTesting:
|
||||
m_ErrorV6 = eRouterErrorNone;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
@@ -328,7 +286,7 @@ namespace i2p
|
||||
bool updated = false;
|
||||
for (auto& address : *addresses)
|
||||
{
|
||||
if (address && address->port != port)
|
||||
if (address && address->port != port && address->transportStyle == i2p::data::RouterInfo::eTransportSSU2)
|
||||
{
|
||||
address->port = port;
|
||||
updated = true;
|
||||
@@ -338,67 +296,65 @@ namespace i2p
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address,
|
||||
int port, bool publish) const
|
||||
{
|
||||
if (!address) return;
|
||||
if (!port && !address->port) port = SelectRandomPort ();
|
||||
if (port) address->port = port;
|
||||
address->published = publish;
|
||||
memcpy (address->i, m_NTCP2Keys->iv, 16);
|
||||
}
|
||||
|
||||
void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg)
|
||||
{
|
||||
if (!m_NTCP2Keys) return;
|
||||
auto addresses = m_RouterInfo.GetAddresses ();
|
||||
if (!addresses) return;
|
||||
bool updated = false;
|
||||
if (v4)
|
||||
for (auto& address : *addresses)
|
||||
{
|
||||
auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V4Idx];
|
||||
if (addr && (addr->port != port || addr->published != publish))
|
||||
if (address && address->IsNTCP2 () && (address->port != port || address->published != publish))
|
||||
{
|
||||
PublishNTCP2Address (addr, port, publish);
|
||||
updated = true;
|
||||
bool isAddr = v4 && address->IsV4 ();
|
||||
if (!isAddr && (v6 || ygg))
|
||||
{
|
||||
if (i2p::util::net::IsYggdrasilAddress (address->host))
|
||||
isAddr = ygg;
|
||||
else
|
||||
isAddr = v6 && address->IsV6 ();
|
||||
}
|
||||
if (isAddr)
|
||||
{
|
||||
if (!port && !address->port) port = SelectRandomPort ();
|
||||
if (port) address->port = port;
|
||||
address->published = publish;
|
||||
memcpy (address->i, m_NTCP2Keys->iv, 16);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v6)
|
||||
{
|
||||
auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6Idx];
|
||||
if (addr && (addr->port != port || addr->published != publish))
|
||||
{
|
||||
PublishNTCP2Address (addr, port, publish);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (ygg)
|
||||
{
|
||||
auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6MeshIdx];
|
||||
if (addr && (addr->port != port || addr->published != publish))
|
||||
{
|
||||
PublishNTCP2Address (addr, port, publish);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateNTCP2Keys ()
|
||||
void RouterContext::UpdateNTCP2Address (bool enable)
|
||||
{
|
||||
if (!m_NTCP2Keys) return;
|
||||
auto addresses = m_RouterInfo.GetAddresses ();
|
||||
if (!addresses) return;
|
||||
bool found = false, updated = false;
|
||||
for (auto& it: *addresses)
|
||||
{
|
||||
if (it && it->IsNTCP2 ())
|
||||
{
|
||||
it->s = m_NTCP2Keys->staticPublicKey;
|
||||
memcpy (it->i, m_NTCP2Keys->iv, 16);
|
||||
found = true;
|
||||
if (enable)
|
||||
{
|
||||
it->s = m_NTCP2Keys->staticPublicKey;
|
||||
memcpy (it->i, m_NTCP2Keys->iv, 16);
|
||||
}
|
||||
else
|
||||
it.reset ();
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (enable && !found)
|
||||
{
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
|
||||
updated = true;
|
||||
}
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6)
|
||||
@@ -437,19 +393,47 @@ namespace i2p
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateSSU2Keys ()
|
||||
void RouterContext::UpdateSSU2Address (bool enable)
|
||||
{
|
||||
if (!m_SSU2Keys) return;
|
||||
auto addresses = m_RouterInfo.GetAddresses ();
|
||||
if (!addresses) return;
|
||||
for (auto& it: *addresses)
|
||||
bool found = false, updated = false;
|
||||
for (auto& it : *addresses)
|
||||
{
|
||||
if (it && it->IsSSU2 ())
|
||||
{
|
||||
it->s = m_SSU2Keys->staticPublicKey;
|
||||
it->i = m_SSU2Keys->intro;
|
||||
found = true;
|
||||
if (enable)
|
||||
{
|
||||
it->s = m_SSU2Keys->staticPublicKey;
|
||||
it->i = m_SSU2Keys->intro;
|
||||
}
|
||||
else
|
||||
it.reset ();
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (enable && !found)
|
||||
{
|
||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
bool published; i2p::config::GetOption("ntcp2.published", published);
|
||||
if (published)
|
||||
{
|
||||
if (ipv4) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV4);
|
||||
if (ipv6) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV6);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t addressCaps = 0;
|
||||
if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
|
||||
@@ -744,69 +728,45 @@ namespace i2p
|
||||
if (!port) port = SelectRandomPort ();
|
||||
}
|
||||
// NTCP2
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
if (ntcp2)
|
||||
if (!foundNTCP2)
|
||||
{
|
||||
if (!foundNTCP2)
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
|
||||
if (ntcp2)
|
||||
{
|
||||
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
|
||||
if (!ntcp2Port) ntcp2Port = port;
|
||||
bool added = false;
|
||||
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
|
||||
if (ntcp2Published)
|
||||
{
|
||||
std::string ntcp2Host;
|
||||
if (!i2p::config::IsDefault ("ntcp2.addressv6"))
|
||||
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
|
||||
else
|
||||
i2p::config::GetOption("host", ntcp2Host);
|
||||
if (!ntcp2Host.empty () && ntcp2Port)
|
||||
{
|
||||
auto addr = boost::asio::ip::address::from_string (ntcp2Host);
|
||||
if (addr.is_v6 ())
|
||||
{
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
ntcp2Host = "::1";
|
||||
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
|
||||
if (!ntcp2Port) ntcp2Port = port;
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (ntcp2Host), ntcp2Port);
|
||||
}
|
||||
if (!added)
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::eV6);
|
||||
else
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV6);
|
||||
}
|
||||
}
|
||||
else
|
||||
m_RouterInfo.RemoveNTCP2Address (false);
|
||||
// SSU2
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2)
|
||||
if (!foundSSU2)
|
||||
{
|
||||
if (!foundSSU2)
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2)
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = port;
|
||||
bool added = false;
|
||||
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
|
||||
if (ssu2Published && ssu2Port)
|
||||
if (ssu2Published)
|
||||
{
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (!host.empty ())
|
||||
{
|
||||
auto addr = boost::asio::ip::address::from_string (host);
|
||||
if (addr.is_v6 ())
|
||||
{
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = port;
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port);
|
||||
}
|
||||
if (!added)
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::eV6);
|
||||
else
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6);
|
||||
}
|
||||
}
|
||||
else
|
||||
m_RouterInfo.RemoveSSU2Address (false);
|
||||
if (ntcp2 || ssu2)
|
||||
m_RouterInfo.EnableV6 ();
|
||||
m_RouterInfo.EnableV6 ();
|
||||
}
|
||||
else
|
||||
m_RouterInfo.DisableV6 ();
|
||||
@@ -815,9 +775,14 @@ namespace i2p
|
||||
|
||||
void RouterContext::SetSupportsV4 (bool supportsV4)
|
||||
{
|
||||
// check if updates
|
||||
if (supportsV4 && SupportsV4 ()) return;
|
||||
if (!supportsV4 && !SupportsV4 ()) return;
|
||||
// update
|
||||
if (supportsV4)
|
||||
{
|
||||
bool foundNTCP2 = false, foundSSU2 = false;
|
||||
std::string host = "127.0.0.1";
|
||||
uint16_t port = 0;
|
||||
auto addresses = m_RouterInfo.GetAddresses ();
|
||||
if (addresses)
|
||||
@@ -846,66 +811,40 @@ namespace i2p
|
||||
if (!port) port = SelectRandomPort ();
|
||||
}
|
||||
// NTCP2
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
if (ntcp2)
|
||||
if (!foundNTCP2)
|
||||
{
|
||||
if (!foundNTCP2)
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
if (ntcp2)
|
||||
{
|
||||
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
|
||||
if (!ntcp2Port) ntcp2Port = port;
|
||||
bool added = false;
|
||||
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
|
||||
if (ntcp2Published && ntcp2Port)
|
||||
if (ntcp2Published)
|
||||
{
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (!host.empty ())
|
||||
{
|
||||
auto addr = boost::asio::ip::address::from_string (host);
|
||||
if (addr.is_v4 ())
|
||||
{
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
|
||||
if (!ntcp2Port) ntcp2Port = port;
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (host), ntcp2Port);
|
||||
}
|
||||
if (!added)
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::eV4);
|
||||
else
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV4);
|
||||
}
|
||||
}
|
||||
else
|
||||
m_RouterInfo.RemoveNTCP2Address (true);
|
||||
// SSU2
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2)
|
||||
if (!foundSSU2)
|
||||
{
|
||||
if (!foundSSU2)
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2)
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = port;
|
||||
bool added = false;
|
||||
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (ssu2Published && ssu2Port)
|
||||
if (ssu2Published)
|
||||
{
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (!host.empty ())
|
||||
{
|
||||
auto addr = boost::asio::ip::address::from_string (host);
|
||||
if (addr.is_v4 ())
|
||||
{
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = port;
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port);
|
||||
}
|
||||
if (!added)
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::eV4);
|
||||
else
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV4);
|
||||
}
|
||||
}
|
||||
else
|
||||
m_RouterInfo.RemoveSSU2Address (true);
|
||||
if (ntcp2 || ssu2)
|
||||
m_RouterInfo.EnableV4 ();
|
||||
m_RouterInfo.EnableV4 ();
|
||||
}
|
||||
else
|
||||
m_RouterInfo.DisableV4 ();
|
||||
@@ -959,18 +898,29 @@ namespace i2p
|
||||
|
||||
void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host)
|
||||
{
|
||||
bool isYgg = i2p::util::net::IsYggdrasilAddress (host);
|
||||
bool updated = false;
|
||||
auto addresses = m_RouterInfo.GetAddresses ();
|
||||
if (!addresses) return;
|
||||
std::shared_ptr<i2p::data::RouterInfo::Address> addr;
|
||||
if (i2p::util::net::IsYggdrasilAddress (host)) // yggdrasil
|
||||
addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6MeshIdx];
|
||||
else if (host.is_v6 ())
|
||||
addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6Idx];
|
||||
if (addr && addr->IsPublishedNTCP2 () && addr->host != host)
|
||||
for (auto& addr: *addresses)
|
||||
{
|
||||
addr->host = host;
|
||||
UpdateRouterInfo ();
|
||||
if (addr && addr->IsPublishedNTCP2 ())
|
||||
{
|
||||
bool isYgg1 = i2p::util::net::IsYggdrasilAddress (addr->host);
|
||||
if (addr->IsV6 () && ((isYgg && isYgg1) || (!isYgg && !isYgg1)))
|
||||
{
|
||||
if (addr->host != host)
|
||||
{
|
||||
addr->host = host;
|
||||
updated = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateStats ()
|
||||
@@ -1038,20 +988,6 @@ namespace i2p
|
||||
}
|
||||
n2k.close ();
|
||||
}
|
||||
// read SSU2 keys if available
|
||||
std::ifstream s2k (i2p::fs::DataDirPath (SSU2_KEYS), std::ifstream::in | std::ifstream::binary);
|
||||
if (s2k)
|
||||
{
|
||||
s2k.seekg (0, std::ios::end);
|
||||
size_t len = s2k.tellg();
|
||||
s2k.seekg (0, std::ios::beg);
|
||||
if (len == sizeof (SSU2PrivateKeys))
|
||||
{
|
||||
m_SSU2Keys.reset (new SSU2PrivateKeys ());
|
||||
s2k.read ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
|
||||
}
|
||||
s2k.close ();
|
||||
}
|
||||
// read RouterInfo
|
||||
m_RouterInfo.SetRouterIdentity (oldIdentity ? oldIdentity : GetIdentity ());
|
||||
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO));
|
||||
@@ -1072,28 +1008,40 @@ namespace i2p
|
||||
if (IsUnreachable ())
|
||||
SetReachable (true, true); // we assume reachable until we discover firewall through peer tests
|
||||
|
||||
bool updated = false;
|
||||
// create new NTCP2 keys if required
|
||||
// read NTCP2
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
|
||||
if ((ntcp2 || ygg) && !m_NTCP2Keys)
|
||||
if (ntcp2 || ygg)
|
||||
{
|
||||
NewNTCP2Keys ();
|
||||
UpdateNTCP2Keys ();
|
||||
updated = true;
|
||||
if (!m_NTCP2Keys) NewNTCP2Keys ();
|
||||
UpdateNTCP2Address (true); // enable NTCP2
|
||||
}
|
||||
// create new SSU2 keys if required
|
||||
else
|
||||
UpdateNTCP2Address (false); // disable NTCP2
|
||||
|
||||
// read SSU2
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2 && !m_SSU2Keys)
|
||||
if (ssu2)
|
||||
{
|
||||
NewSSU2Keys ();
|
||||
UpdateSSU2Keys ();
|
||||
updated = true;
|
||||
// read SSU2 keys if available
|
||||
std::ifstream s2k (i2p::fs::DataDirPath (SSU2_KEYS), std::ifstream::in | std::ifstream::binary);
|
||||
if (s2k)
|
||||
{
|
||||
s2k.seekg (0, std::ios::end);
|
||||
size_t len = s2k.tellg();
|
||||
s2k.seekg (0, std::ios::beg);
|
||||
if (len == sizeof (SSU2PrivateKeys))
|
||||
{
|
||||
m_SSU2Keys.reset (new SSU2PrivateKeys ());
|
||||
s2k.read ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
|
||||
}
|
||||
s2k.close ();
|
||||
}
|
||||
if (!m_SSU2Keys) NewSSU2Keys ();
|
||||
UpdateSSU2Address (true); // enable SSU2
|
||||
}
|
||||
if (m_RouterInfo.UpdateCongestion (i2p::data::RouterInfo::eLowCongestion))
|
||||
updated = true;
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
else
|
||||
UpdateSSU2Address (false); // disable SSU2
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1114,13 +1062,6 @@ namespace i2p
|
||||
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
}
|
||||
|
||||
bool RouterContext::IsHighCongestion () const
|
||||
{
|
||||
return i2p::tunnel::tunnels.IsTooManyTransitTunnels () ||
|
||||
i2p::transport::transports.IsBandwidthExceeded () ||
|
||||
i2p::transport::transports.IsTransitBandwidthExceeded ();
|
||||
}
|
||||
|
||||
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len)
|
||||
{
|
||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
|
||||
@@ -1134,16 +1075,10 @@ namespace i2p
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (m_Service)
|
||||
m_Service->GetService ().post (std::bind (&RouterContext::PostGarlicMessage, this, msg));
|
||||
else
|
||||
LogPrint (eLogError, "Router: service is NULL");
|
||||
}
|
||||
|
||||
void RouterContext::PostGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
uint32_t len = bufbe32toh (buf);
|
||||
if (len > msg->GetLength ())
|
||||
@@ -1160,38 +1095,23 @@ namespace i2p
|
||||
else
|
||||
LogPrint (eLogError, "Router: Session is not set for ECIES router");
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (m_Service)
|
||||
m_Service->GetService ().post (std::bind (&RouterContext::PostDeliveryStatusMessage, this, msg));
|
||||
else
|
||||
LogPrint (eLogError, "Router: service is NULL");
|
||||
}
|
||||
|
||||
void RouterContext::PostDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
|
||||
if (i2p::data::netdb.GetPublishReplyToken () == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
|
||||
i2p::data::netdb.PostI2NPMsg (msg);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "Router: Publishing confirmed. reply token=", m_PublishReplyToken);
|
||||
m_PublishExcluded.clear ();
|
||||
m_PublishReplyToken = 0;
|
||||
SchedulePublish ();
|
||||
}
|
||||
else
|
||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RouterContext::CleanupDestination ()
|
||||
{
|
||||
if (m_Service)
|
||||
m_Service->GetService ().post ([this]()
|
||||
{
|
||||
this->i2p::garlic::GarlicDestination::CleanupExpiredTags ();
|
||||
});
|
||||
else
|
||||
LogPrint (eLogError, "Router: service is NULL");
|
||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||
i2p::garlic::GarlicDestination::CleanupExpiredTags ();
|
||||
}
|
||||
|
||||
uint32_t RouterContext::GetUptime () const
|
||||
@@ -1266,152 +1186,4 @@ namespace i2p
|
||||
}
|
||||
return *m_SSU2StaticKeys;
|
||||
}
|
||||
|
||||
void RouterContext::ScheduleInitialPublish ()
|
||||
{
|
||||
if (m_PublishTimer)
|
||||
{
|
||||
m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_INITIAL_PUBLISH_INTERVAL));
|
||||
m_PublishTimer->async_wait (std::bind (&RouterContext::HandleInitialPublishTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Router: Publish timer is NULL");
|
||||
}
|
||||
|
||||
void RouterContext::HandleInitialPublishTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
if (m_RouterInfo.IsReachableBy (i2p::data::RouterInfo::eAllTransports))
|
||||
HandlePublishTimer (ecode);
|
||||
else
|
||||
ScheduleInitialPublish ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SchedulePublish ()
|
||||
{
|
||||
if (m_PublishTimer)
|
||||
{
|
||||
m_PublishTimer->cancel ();
|
||||
m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_PUBLISH_INTERVAL +
|
||||
rand () % ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE));
|
||||
m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Router: Publish timer is NULL");
|
||||
}
|
||||
|
||||
void RouterContext::HandlePublishTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
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 ());
|
||||
Publish ();
|
||||
SchedulePublishResend ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::Publish ()
|
||||
{
|
||||
if (!i2p::transport::transports.IsOnline ()) return;
|
||||
if (m_PublishExcluded.size () > ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS)
|
||||
{
|
||||
LogPrint (eLogError, "Router: Couldn't publish our RouterInfo to ", ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
|
||||
m_PublishExcluded.clear ();
|
||||
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
|
||||
}
|
||||
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
|
||||
if (floodfill)
|
||||
{
|
||||
uint32_t replyToken;
|
||||
RAND_bytes ((uint8_t *)&replyToken, 4);
|
||||
LogPrint (eLogInfo, "Router: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
|
||||
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
|
||||
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
|
||||
// send directly
|
||||
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
|
||||
else
|
||||
{
|
||||
// otherwise through exploratory
|
||||
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
|
||||
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
|
||||
if (inbound && outbound)
|
||||
{
|
||||
// encrypt for floodfill
|
||||
auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound);
|
||||
outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0,
|
||||
i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "Router: Can't publish our RouterInfo. No tunnles. Try again in ", ROUTER_INFO_CONFIRMATION_TIMEOUT, " seconds");
|
||||
}
|
||||
m_PublishExcluded.insert (floodfill->GetIdentHash ());
|
||||
m_PublishReplyToken = replyToken;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "Router: Can't find floodfill to publish our RouterInfo");
|
||||
}
|
||||
|
||||
void RouterContext::SchedulePublishResend ()
|
||||
{
|
||||
if (m_PublishTimer)
|
||||
{
|
||||
m_PublishTimer->cancel ();
|
||||
m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONFIRMATION_TIMEOUT));
|
||||
m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishResendTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Router: Publish timer is NULL");
|
||||
}
|
||||
|
||||
void RouterContext::HandlePublishResendTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
i2p::context.UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
|
||||
Publish ();
|
||||
SchedulePublishResend ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::ScheduleCongestionUpdate ()
|
||||
{
|
||||
if (m_CongestionUpdateTimer)
|
||||
{
|
||||
m_CongestionUpdateTimer->cancel ();
|
||||
m_CongestionUpdateTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONGESTION_UPDATE_INTERVAL));
|
||||
m_CongestionUpdateTimer->async_wait (std::bind (&RouterContext::HandleCongestionUpdateTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Router: Congestion update timer is NULL");
|
||||
}
|
||||
|
||||
void RouterContext::HandleCongestionUpdateTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto c = i2p::data::RouterInfo::eLowCongestion;
|
||||
if (!AcceptsTunnels ())
|
||||
c = i2p::data::RouterInfo::eRejectAll;
|
||||
else if (IsHighCongestion ())
|
||||
c = i2p::data::RouterInfo::eHighCongestion;
|
||||
if (m_RouterInfo.UpdateCongestion (c))
|
||||
UpdateRouterInfo ();
|
||||
ScheduleCongestionUpdate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -12,13 +12,12 @@
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <set>
|
||||
#include <boost/asio.hpp>
|
||||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "Garlic.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
@@ -31,13 +30,7 @@ namespace garlic
|
||||
const char ROUTER_KEYS[] = "router.keys";
|
||||
const char NTCP2_KEYS[] = "ntcp2.keys";
|
||||
const char SSU2_KEYS[] = "ssu2.keys";
|
||||
const int ROUTER_INFO_UPDATE_INTERVAL = 30*60; // 30 minutes
|
||||
const int ROUTER_INFO_PUBLISH_INTERVAL = 39*60; // in seconds
|
||||
const int ROUTER_INFO_INITIAL_PUBLISH_INTERVAL = 10; // in seconds
|
||||
const int ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE = 105;// in seconds
|
||||
const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||
const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
|
||||
const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 12*60; // in seconds
|
||||
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
|
||||
|
||||
enum RouterStatus
|
||||
{
|
||||
@@ -77,23 +70,11 @@ namespace garlic
|
||||
uint8_t intro[32];
|
||||
};
|
||||
|
||||
class RouterService: public i2p::util::RunnableServiceWithWork
|
||||
{
|
||||
public:
|
||||
|
||||
RouterService (): RunnableServiceWithWork ("Router") {};
|
||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||
void Start () { StartIOService (); };
|
||||
void Stop () { StopIOService (); };
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
RouterContext ();
|
||||
void Init ();
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
|
||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||
i2p::data::LocalRouterInfo& GetRouterInfo () { return m_RouterInfo; };
|
||||
std::shared_ptr<i2p::data::RouterInfo> GetSharedRouterInfo ()
|
||||
@@ -135,9 +116,11 @@ namespace garlic
|
||||
bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data);
|
||||
|
||||
void UpdatePort (int port); // called from Daemon
|
||||
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU2 or Daemon
|
||||
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
||||
void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg);
|
||||
void UpdateNTCP2Address (bool enable);
|
||||
void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
|
||||
void UpdateSSU2Address (bool enable);
|
||||
bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4);
|
||||
void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4);
|
||||
void ClearSSU2Introducers (bool v4);
|
||||
@@ -153,7 +136,6 @@ namespace garlic
|
||||
void SetShareRatio (int percents); // 0 - 100
|
||||
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
|
||||
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
|
||||
bool IsHighCongestion () const;
|
||||
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
|
||||
bool SupportsV4 () const { return m_RouterInfo.IsV4 (); };
|
||||
bool SupportsMesh () const { return m_RouterInfo.IsMesh (); };
|
||||
@@ -161,8 +143,6 @@ namespace garlic
|
||||
void SetSupportsV4 (bool supportsV4);
|
||||
void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host);
|
||||
void SetMTU (int mtu, bool v4);
|
||||
void SetHidden(bool hide) { m_IsHiddenMode = hide; };
|
||||
bool IsHidden() const { return m_IsHiddenMode; };
|
||||
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
|
||||
|
||||
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
|
||||
@@ -197,27 +177,13 @@ namespace garlic
|
||||
void UpdateRouterInfo ();
|
||||
void NewNTCP2Keys ();
|
||||
void NewSSU2Keys ();
|
||||
void UpdateNTCP2Keys ();
|
||||
void UpdateSSU2Keys ();
|
||||
bool IsSSU2Only () const; // SSU2 and no SSU
|
||||
bool Load ();
|
||||
void SaveKeys ();
|
||||
uint16_t SelectRandomPort () const;
|
||||
void PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address, int port, bool publish) const;
|
||||
|
||||
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
|
||||
void PostGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void PostDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void ScheduleInitialPublish ();
|
||||
void HandleInitialPublishTimer (const boost::system::error_code& ecode);
|
||||
void SchedulePublish ();
|
||||
void HandlePublishTimer (const boost::system::error_code& ecode);
|
||||
void Publish ();
|
||||
void SchedulePublishResend ();
|
||||
void HandlePublishResendTimer (const boost::system::error_code& ecode);
|
||||
void ScheduleCongestionUpdate ();
|
||||
void HandleCongestionUpdateTimer (const boost::system::error_code& ecode);
|
||||
|
||||
private:
|
||||
|
||||
i2p::data::LocalRouterInfo m_RouterInfo;
|
||||
@@ -232,17 +198,12 @@ namespace garlic
|
||||
RouterStatus m_Status, m_StatusV6;
|
||||
RouterError m_Error, m_ErrorV6;
|
||||
int m_NetID;
|
||||
std::mutex m_GarlicMutex;
|
||||
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
||||
std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys;
|
||||
std::unique_ptr<i2p::crypto::X25519Keys> m_NTCP2StaticKeys, m_SSU2StaticKeys;
|
||||
// for ECIESx25519
|
||||
i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState;
|
||||
// publish
|
||||
std::unique_ptr<RouterService> m_Service;
|
||||
std::unique_ptr<boost::asio::deadline_timer> m_PublishTimer, m_CongestionUpdateTimer;
|
||||
std::set<i2p::data::IdentHash> m_PublishExcluded;
|
||||
uint32_t m_PublishReplyToken;
|
||||
bool m_IsHiddenMode; // not publish
|
||||
};
|
||||
|
||||
extern RouterContext context;
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace data
|
||||
RouterInfo::RouterInfo (const std::string& fullPath):
|
||||
m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false),
|
||||
m_SupportedTransports (0),m_ReachableTransports (0),
|
||||
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
|
||||
m_Caps (0), m_Version (0)
|
||||
{
|
||||
m_Addresses = boost::make_shared<Addresses>(); // create empty list
|
||||
m_Buffer = NewBuffer (); // always RouterInfo's
|
||||
@@ -53,7 +53,7 @@ namespace data
|
||||
RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len):
|
||||
m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false),
|
||||
m_SupportedTransports (0), m_ReachableTransports (0),
|
||||
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
|
||||
m_Caps (0), m_Version (0)
|
||||
{
|
||||
if (len <= MAX_RI_BUFFER_SIZE)
|
||||
{
|
||||
@@ -79,12 +79,13 @@ namespace data
|
||||
{
|
||||
}
|
||||
|
||||
bool RouterInfo::Update (const uint8_t * buf, size_t len)
|
||||
void RouterInfo::Update (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (len > MAX_RI_BUFFER_SIZE)
|
||||
{
|
||||
LogPrint (eLogWarning, "RouterInfo: Updated buffer is too long ", len, ". Not changed");
|
||||
return false;
|
||||
LogPrint (eLogError, "RouterInfo: Buffer is too long ", len);
|
||||
m_IsUnreachable = true;
|
||||
return;
|
||||
}
|
||||
// verify signature since we have identity already
|
||||
int l = len - m_RouterIdentity->GetSignatureLen ();
|
||||
@@ -98,21 +99,20 @@ namespace data
|
||||
m_Caps = 0;
|
||||
// don't clean up m_Addresses, it will be replaced in ReadFromStream
|
||||
ClearProperties ();
|
||||
// copy buffer
|
||||
UpdateBuffer (buf, len);
|
||||
// skip identity
|
||||
size_t identityLen = m_RouterIdentity->GetFullLen ();
|
||||
// read new RI
|
||||
std::stringstream str (std::string ((char *)buf + identityLen, len - identityLen));
|
||||
std::stringstream str (std::string ((char *)m_Buffer->data () + identityLen, m_BufferLen - identityLen));
|
||||
ReadFromStream (str);
|
||||
if (!m_IsUnreachable)
|
||||
UpdateBuffer (buf, len); // save buffer
|
||||
// don't delete buffer until saved to the file
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "RouterInfo: Updated signature verification failed. Not changed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: Signature verification failed");
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
|
||||
@@ -161,7 +161,7 @@ namespace data
|
||||
m_IsUnreachable = true;
|
||||
return;
|
||||
}
|
||||
m_RouterIdentity = NewIdentity (m_Buffer->data (), m_BufferLen);
|
||||
m_RouterIdentity = std::make_shared<IdentityEx>(m_Buffer->data (), m_BufferLen);
|
||||
size_t identityLen = m_RouterIdentity->GetFullLen ();
|
||||
if (identityLen >= m_BufferLen)
|
||||
{
|
||||
@@ -186,6 +186,7 @@ namespace data
|
||||
m_IsUnreachable = true;
|
||||
return;
|
||||
}
|
||||
m_RouterIdentity->DropVerifier ();
|
||||
}
|
||||
// parse RI
|
||||
std::stringstream str;
|
||||
@@ -201,7 +202,7 @@ namespace data
|
||||
void RouterInfo::ReadFromStream (std::istream& s)
|
||||
{
|
||||
if (!s) return;
|
||||
m_Caps = 0; m_Congestion = eLowCongestion;
|
||||
m_Caps = 0;
|
||||
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
|
||||
m_Timestamp = be64toh (m_Timestamp);
|
||||
// read addresses
|
||||
@@ -251,15 +252,7 @@ namespace data
|
||||
{
|
||||
boost::system::error_code ecode;
|
||||
address->host = boost::asio::ip::address::from_string (value, ecode);
|
||||
if (!ecode && !address->host.is_unspecified ())
|
||||
{
|
||||
if (!i2p::util::net::IsInReservedRange (address->host) ||
|
||||
i2p::util::net::IsYggdrasilAddress (address->host))
|
||||
isHost = true;
|
||||
else
|
||||
// we consider such address as invalid
|
||||
address->transportStyle = eTransportUnknown;
|
||||
}
|
||||
if (!ecode && !address->host.is_unspecified ()) isHost = true;
|
||||
}
|
||||
else if (!strcmp (key, "port"))
|
||||
{
|
||||
@@ -293,8 +286,7 @@ namespace data
|
||||
else if (!strcmp (key, "s")) // ntcp2 or ssu2 static key
|
||||
{
|
||||
Base64ToByteStream (value, strlen (value), address->s, 32);
|
||||
if (!(address->s[31] & 0x80)) // check if x25519 public key
|
||||
isStaticKey = true;
|
||||
isStaticKey = true;
|
||||
}
|
||||
else if (!strcmp (key, "i")) // ntcp2 iv or ssu2 intro
|
||||
{
|
||||
@@ -336,7 +328,11 @@ namespace data
|
||||
address->ssu->introducers.resize (index + 1);
|
||||
}
|
||||
Introducer& introducer = address->ssu->introducers.at (index);
|
||||
if (!strcmp (key, "itag"))
|
||||
if (!strcmp (key, "ihost"))
|
||||
introducer.isH = false; // SSU1
|
||||
else if (!strcmp (key, "iport"))
|
||||
introducer.isH = false; // SSU1
|
||||
else if (!strcmp (key, "itag"))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -348,7 +344,10 @@ namespace data
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "ih"))
|
||||
{
|
||||
Base64ToByteStream (value, strlen (value), introducer.iH, 32);
|
||||
introducer.isH = true;
|
||||
}
|
||||
else if (!strcmp (key, "iexp"))
|
||||
{
|
||||
try
|
||||
@@ -363,12 +362,11 @@ namespace data
|
||||
}
|
||||
if (!s) return;
|
||||
}
|
||||
|
||||
if (address->transportStyle == eTransportNTCP2)
|
||||
{
|
||||
if (isStaticKey)
|
||||
{
|
||||
if (isHost && address->port)
|
||||
if (isHost)
|
||||
{
|
||||
if (address->host.is_v6 ())
|
||||
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
|
||||
@@ -376,9 +374,8 @@ namespace data
|
||||
supportedTransports |= eNTCP2V4;
|
||||
m_ReachableTransports |= supportedTransports;
|
||||
}
|
||||
else
|
||||
else if (!address->published)
|
||||
{
|
||||
address->published = false;
|
||||
if (address->caps)
|
||||
{
|
||||
if (address->caps & AddressCaps::eV4) supportedTransports |= eNTCP2V4;
|
||||
@@ -389,11 +386,11 @@ namespace data
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (address->transportStyle == eTransportSSU2 && isV2 && isStaticKey)
|
||||
else if (address->transportStyle == eTransportSSU2 && isV2)
|
||||
{
|
||||
if (address->IsV4 ()) supportedTransports |= eSSU2V4;
|
||||
if (address->IsV6 ()) supportedTransports |= eSSU2V6;
|
||||
if (isHost && address->port)
|
||||
if (address->port)
|
||||
{
|
||||
if (address->host.is_v4 ()) m_ReachableTransports |= eSSU2V4;
|
||||
if (address->host.is_v6 ()) m_ReachableTransports |= eSSU2V6;
|
||||
@@ -403,9 +400,18 @@ namespace data
|
||||
{
|
||||
// exclude invalid introducers
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
UpdateIntroducers (address, ts);
|
||||
if (!address->ssu->introducers.empty ()) // still has something
|
||||
int numValid = 0;
|
||||
for (auto& it: address->ssu->introducers)
|
||||
{
|
||||
if (it.iTag && ts < it.iExp && it.isH)
|
||||
numValid++;
|
||||
else
|
||||
it.iTag = 0;
|
||||
}
|
||||
if (numValid)
|
||||
m_ReachableTransports |= supportedTransports;
|
||||
else
|
||||
address->ssu->introducers.resize (0);
|
||||
}
|
||||
}
|
||||
if (supportedTransports)
|
||||
@@ -485,10 +491,7 @@ namespace data
|
||||
if (netdb.GetFamilies ().VerifyFamily (family, GetIdentHash (), value))
|
||||
m_FamilyID = netdb.GetFamilies ().GetFamilyID (family);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "RouterInfo: Family ", family, " signature verification failed");
|
||||
SetUnreachable (true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!s) return;
|
||||
@@ -531,15 +534,6 @@ namespace data
|
||||
case CAPS_FLAG_UNREACHABLE:
|
||||
m_Caps |= Caps::eUnreachable;
|
||||
break;
|
||||
case CAPS_FLAG_MEDIUM_CONGESTION:
|
||||
m_Congestion = eMediumCongestion;
|
||||
break;
|
||||
case CAPS_FLAG_HIGH_CONGESTION:
|
||||
m_Congestion = eHighCongestion;
|
||||
break;
|
||||
case CAPS_FLAG_REJECT_ALL_CONGESTION:
|
||||
m_Congestion = eRejectAll;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
cap++;
|
||||
@@ -573,21 +567,6 @@ namespace data
|
||||
return caps;
|
||||
}
|
||||
|
||||
void RouterInfo::UpdateIntroducers (std::shared_ptr<Address> address, uint64_t ts)
|
||||
{
|
||||
if (!address || !address->ssu) return;
|
||||
int numValid = 0;
|
||||
for (auto& it: address->ssu->introducers)
|
||||
{
|
||||
if (it.iTag && ts < it.iExp)
|
||||
numValid++;
|
||||
else
|
||||
it.iTag = 0;
|
||||
}
|
||||
if (!numValid)
|
||||
address->ssu->introducers.resize (0);
|
||||
}
|
||||
|
||||
bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
|
||||
{
|
||||
if (!m_RouterIdentity) return false;
|
||||
@@ -602,24 +581,20 @@ namespace data
|
||||
{
|
||||
if (LoadFile (fullPath))
|
||||
LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
return m_Buffer->data ();
|
||||
}
|
||||
|
||||
bool RouterInfo::SaveToFile (const std::string& fullPath)
|
||||
{
|
||||
if (m_IsUnreachable) return false; // don't save bad router
|
||||
if (!m_Buffer)
|
||||
{
|
||||
LogPrint (eLogWarning, "RouterInfo: Can't save, m_Buffer == NULL");
|
||||
LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL");
|
||||
return false;
|
||||
}
|
||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||
if (!f.is_open ())
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: Can't save to ", fullPath);
|
||||
if (!f.is_open ()) {
|
||||
LogPrint(eLogError, "RouterInfo: Can't save to ", fullPath);
|
||||
return false;
|
||||
}
|
||||
f.write ((char *)m_Buffer->data (), m_BufferLen);
|
||||
@@ -645,49 +620,22 @@ namespace data
|
||||
return l+1;
|
||||
}
|
||||
|
||||
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,int port, uint8_t caps)
|
||||
{
|
||||
auto addr = std::make_shared<Address>();
|
||||
addr->port = port;
|
||||
addr->transportStyle = eTransportNTCP2;
|
||||
addr->caps = caps;
|
||||
addr->date = 0;
|
||||
addr->published = false;
|
||||
memcpy (addr->s, staticKey, 32);
|
||||
memcpy (addr->i, iv, 16);
|
||||
if (addr->IsV4 ())
|
||||
{
|
||||
m_SupportedTransports |= eNTCP2V4;
|
||||
(*m_Addresses)[eNTCP2V4Idx] = addr;
|
||||
}
|
||||
if (addr->IsV6 ())
|
||||
{
|
||||
m_SupportedTransports |= eNTCP2V6;
|
||||
(*m_Addresses)[eNTCP2V6Idx] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
|
||||
const boost::asio::ip::address& host, int port)
|
||||
const boost::asio::ip::address& host, int port, uint8_t caps)
|
||||
{
|
||||
auto addr = std::make_shared<Address>();
|
||||
addr->host = host;
|
||||
addr->port = port;
|
||||
addr->transportStyle = eTransportNTCP2;
|
||||
addr->caps = caps;
|
||||
addr->date = 0;
|
||||
addr->published = true;
|
||||
if (port) addr->published = true;
|
||||
memcpy (addr->s, staticKey, 32);
|
||||
memcpy (addr->i, iv, 16);
|
||||
addr->caps = 0;
|
||||
if (host.is_unspecified ())
|
||||
{
|
||||
if (host.is_v4 ()) addr->caps |= eV4;
|
||||
if (host.is_v6 ()) addr->caps |= eV6;
|
||||
}
|
||||
if (addr->IsV4 ())
|
||||
{
|
||||
m_SupportedTransports |= eNTCP2V4;
|
||||
m_ReachableTransports |= eNTCP2V4;
|
||||
if (addr->published) m_ReachableTransports |= eNTCP2V4;
|
||||
(*m_Addresses)[eNTCP2V4Idx] = addr;
|
||||
}
|
||||
if (addr->IsV6 ())
|
||||
@@ -701,34 +649,17 @@ namespace data
|
||||
else
|
||||
{
|
||||
m_SupportedTransports |= eNTCP2V6;
|
||||
m_ReachableTransports |= eNTCP2V6;
|
||||
if (addr->published) m_ReachableTransports |= eNTCP2V6;
|
||||
(*m_Addresses)[eNTCP2V6Idx] = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::RemoveNTCP2Address (bool v4)
|
||||
{
|
||||
if (v4)
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V6Idx])
|
||||
(*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*m_Addresses)[eNTCP2V4Idx].reset ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V4Idx])
|
||||
(*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*m_Addresses)[eNTCP2V6Idx].reset ();
|
||||
}
|
||||
UpdateSupportedTransports ();
|
||||
}
|
||||
|
||||
void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, int port, uint8_t caps)
|
||||
void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps)
|
||||
{
|
||||
auto addr = std::make_shared<Address>();
|
||||
addr->transportStyle = eTransportSSU2;
|
||||
addr->port = port;
|
||||
addr->port = 0;
|
||||
addr->caps = caps;
|
||||
addr->date = 0;
|
||||
addr->ssu.reset (new SSUExt ());
|
||||
@@ -755,19 +686,12 @@ namespace data
|
||||
addr->host = host;
|
||||
addr->port = port;
|
||||
addr->published = true;
|
||||
addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
|
||||
addr->date = 0;
|
||||
addr->ssu.reset (new SSUExt ());
|
||||
addr->ssu->mtu = 0;
|
||||
memcpy (addr->s, staticKey, 32);
|
||||
memcpy (addr->i, introKey, 32);
|
||||
if (!host.is_unspecified ())
|
||||
addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
|
||||
else
|
||||
{
|
||||
addr->caps = 0;
|
||||
if (host.is_v4 ()) addr->caps |= eV4;
|
||||
if (host.is_v6 ()) addr->caps |= eV6;
|
||||
}
|
||||
if (addr->IsV4 ())
|
||||
{
|
||||
m_SupportedTransports |= eSSU2V4;
|
||||
@@ -782,23 +706,6 @@ namespace data
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::RemoveSSU2Address (bool v4)
|
||||
{
|
||||
if (v4)
|
||||
{
|
||||
if ((*m_Addresses)[eSSU2V6Idx])
|
||||
(*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*m_Addresses)[eSSU2V4Idx].reset ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((*m_Addresses)[eSSU2V4Idx])
|
||||
(*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*m_Addresses)[eSSU2V6Idx].reset ();
|
||||
}
|
||||
UpdateSupportedTransports ();
|
||||
}
|
||||
|
||||
bool RouterInfo::IsNTCP2 (bool v4only) const
|
||||
{
|
||||
if (v4only)
|
||||
@@ -837,14 +744,14 @@ namespace data
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V6Idx])
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V6Idx]->IsV4 () && (*m_Addresses)[eNTCP2V4Idx])
|
||||
(*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
if ((*m_Addresses)[eNTCP2V6Idx]->IsV4 ())
|
||||
(*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*m_Addresses)[eNTCP2V6Idx].reset ();
|
||||
}
|
||||
if ((*m_Addresses)[eSSU2V6Idx])
|
||||
{
|
||||
if ((*m_Addresses)[eSSU2V6Idx]->IsV4 () && (*m_Addresses)[eSSU2V4Idx])
|
||||
(*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
if ((*m_Addresses)[eSSU2V6Idx]->IsV4 ())
|
||||
(*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*m_Addresses)[eSSU2V6Idx].reset ();
|
||||
}
|
||||
UpdateSupportedTransports ();
|
||||
@@ -857,14 +764,14 @@ namespace data
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V4Idx])
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V4Idx]->IsV6 () && (*m_Addresses)[eNTCP2V6Idx])
|
||||
(*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
if ((*m_Addresses)[eNTCP2V4Idx]->IsV6 ())
|
||||
(*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*m_Addresses)[eNTCP2V4Idx].reset ();
|
||||
}
|
||||
if ((*m_Addresses)[eSSU2V4Idx])
|
||||
{
|
||||
if ((*m_Addresses)[eSSU2V4Idx]->IsV6 () && (*m_Addresses)[eSSU2V6Idx])
|
||||
(*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
if ((*m_Addresses)[eSSU2V4Idx]->IsV6 ())
|
||||
(*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*m_Addresses)[eSSU2V4Idx].reset ();
|
||||
}
|
||||
UpdateSupportedTransports ();
|
||||
@@ -939,14 +846,23 @@ namespace data
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2V4Address () const
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2AddressWithStaticKey (const uint8_t * key) const
|
||||
{
|
||||
return (*GetAddresses ())[eNTCP2V4Idx];
|
||||
if (!key) return nullptr;
|
||||
return GetAddress (
|
||||
[key](std::shared_ptr<const RouterInfo::Address> address)->bool
|
||||
{
|
||||
return address->IsNTCP2 () && !memcmp (address->s, key, 32);
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2V6Address () const
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const
|
||||
{
|
||||
return (*GetAddresses ())[eNTCP2V6Idx];
|
||||
if (!key) return nullptr;
|
||||
auto addr = (*GetAddresses ())[isV6 ? eSSU2V6Idx : eSSU2V4Idx];
|
||||
if (addr && !memcmp (addr->s, key, 32))
|
||||
return addr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V4Address () const
|
||||
@@ -970,13 +886,9 @@ namespace data
|
||||
|
||||
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
|
||||
{
|
||||
auto profile = m_Profile;
|
||||
if (!profile)
|
||||
{
|
||||
profile = GetRouterProfile (GetIdentHash ());
|
||||
m_Profile = profile;
|
||||
}
|
||||
return profile;
|
||||
if (!m_Profile)
|
||||
m_Profile = GetRouterProfile (GetIdentHash ());
|
||||
return m_Profile;
|
||||
}
|
||||
|
||||
void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted) const
|
||||
@@ -988,22 +900,11 @@ namespace data
|
||||
|
||||
bool RouterInfo::IsEligibleFloodfill () const
|
||||
{
|
||||
// floodfill must have published ipv4, >= 0.9.38 and not DSA
|
||||
return m_Version >= NETDB_MIN_FLOODFILL_VERSION && IsPublished (true) &&
|
||||
// floodfill must be reachable by ipv4, >= 0.9.38 and not DSA
|
||||
return IsReachableBy (eNTCP2V4 | eSSU2V4) && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
|
||||
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
||||
}
|
||||
|
||||
bool RouterInfo::IsPublished (bool v4) const
|
||||
{
|
||||
auto addr = GetAddresses ();
|
||||
if (v4)
|
||||
return ((*addr)[eNTCP2V4Idx] && ((*addr)[eNTCP2V4Idx])->published) ||
|
||||
((*addr)[eSSU2V4Idx] && ((*addr)[eSSU2V4Idx])->published);
|
||||
else
|
||||
return ((*addr)[eNTCP2V6Idx] && ((*addr)[eNTCP2V6Idx])->published) ||
|
||||
((*addr)[eSSU2V6Idx] && ((*addr)[eSSU2V6Idx])->published);
|
||||
}
|
||||
|
||||
bool RouterInfo::IsSSU2PeerTesting (bool v4) const
|
||||
{
|
||||
if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
|
||||
@@ -1059,31 +960,6 @@ namespace data
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::UpdateIntroducers (uint64_t ts)
|
||||
{
|
||||
if (ts*1000 < m_Timestamp + INTRODUCER_UPDATE_INTERVAL) return;
|
||||
if (m_ReachableTransports & eSSU2V4)
|
||||
{
|
||||
auto addr = (*GetAddresses ())[eSSU2V4Idx];
|
||||
if (addr && addr->UsesIntroducer ())
|
||||
{
|
||||
UpdateIntroducers (addr, ts);
|
||||
if (!addr->UsesIntroducer ()) // no more valid introducers
|
||||
m_ReachableTransports &= ~eSSU2V4;
|
||||
}
|
||||
}
|
||||
if (m_ReachableTransports & eSSU2V6)
|
||||
{
|
||||
auto addr = (*GetAddresses ())[eSSU2V6Idx];
|
||||
if (addr && addr->UsesIntroducer ())
|
||||
{
|
||||
UpdateIntroducers (addr, ts);
|
||||
if (!addr->UsesIntroducer ()) // no more valid introducers
|
||||
m_ReachableTransports &= ~eSSU2V6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::UpdateBuffer (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (!m_Buffer)
|
||||
@@ -1101,16 +977,11 @@ namespace data
|
||||
std::shared_ptr<RouterInfo::Address> RouterInfo::NewAddress () const
|
||||
{
|
||||
return netdb.NewRouterInfoAddress ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
boost::shared_ptr<RouterInfo::Addresses> RouterInfo::NewAddresses () const
|
||||
{
|
||||
return netdb.NewRouterInfoAddresses ();
|
||||
}
|
||||
|
||||
std::shared_ptr<IdentityEx> RouterInfo::NewIdentity (const uint8_t * buf, size_t len) const
|
||||
{
|
||||
return netdb.NewIdentity (buf, len);
|
||||
}
|
||||
|
||||
void RouterInfo::RefreshTimestamp ()
|
||||
@@ -1118,27 +989,6 @@ namespace data
|
||||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
bool RouterInfo::IsHighCongestion (bool highBandwidth) const
|
||||
{
|
||||
switch (m_Congestion)
|
||||
{
|
||||
case eLowCongestion:
|
||||
return false;
|
||||
break;
|
||||
case eMediumCongestion:
|
||||
return highBandwidth;
|
||||
break;
|
||||
case eHighCongestion:
|
||||
return i2p::util::GetMillisecondsSinceEpoch () < m_Timestamp + HIGH_CONGESTION_INTERVAL*1000LL;
|
||||
break;
|
||||
case eRejectAll:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
|
||||
{
|
||||
RefreshTimestamp ();
|
||||
@@ -1190,34 +1040,9 @@ namespace data
|
||||
if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
|
||||
if (c & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
|
||||
|
||||
switch (GetCongestion ())
|
||||
{
|
||||
case eMediumCongestion:
|
||||
caps += CAPS_FLAG_MEDIUM_CONGESTION;
|
||||
break;
|
||||
case eHighCongestion:
|
||||
caps += CAPS_FLAG_HIGH_CONGESTION;
|
||||
break;
|
||||
case eRejectAll:
|
||||
caps += CAPS_FLAG_REJECT_ALL_CONGESTION;
|
||||
break;
|
||||
default: ;
|
||||
};
|
||||
|
||||
SetProperty ("caps", caps);
|
||||
}
|
||||
|
||||
bool LocalRouterInfo::UpdateCongestion (Congestion c)
|
||||
{
|
||||
if (c != GetCongestion ())
|
||||
{
|
||||
SetCongestion (c);
|
||||
UpdateCapsProperty ();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LocalRouterInfo::WriteToStream (std::ostream& s) const
|
||||
{
|
||||
auto addresses = GetAddresses ();
|
||||
@@ -1254,37 +1079,44 @@ namespace data
|
||||
s.write ((const char *)&cost, sizeof (cost));
|
||||
s.write ((const char *)&address.date, sizeof (address.date));
|
||||
std::stringstream properties;
|
||||
bool isPublished = address.published && !address.host.is_unspecified () && address.port;
|
||||
bool isPublished = false;
|
||||
if (address.transportStyle == eTransportNTCP2)
|
||||
{
|
||||
WriteString ("NTCP2", s);
|
||||
// caps
|
||||
if (!isPublished)
|
||||
if (address.IsNTCP2 ())
|
||||
{
|
||||
WriteString ("caps", properties);
|
||||
properties << '=';
|
||||
std::string caps;
|
||||
if (address.IsV4 ()) caps += CAPS_FLAG_V4;
|
||||
if (address.IsV6 () || address.host.is_v6 ()) caps += CAPS_FLAG_V6; // we set 6 for unspecified ipv6
|
||||
if (caps.empty ()) caps += CAPS_FLAG_V4;
|
||||
WriteString (caps, properties);
|
||||
properties << ';';
|
||||
WriteString ("NTCP2", s);
|
||||
if (address.IsPublishedNTCP2 () && !address.host.is_unspecified () && address.port)
|
||||
isPublished = true;
|
||||
else
|
||||
{
|
||||
WriteString ("caps", properties);
|
||||
properties << '=';
|
||||
std::string caps;
|
||||
if (address.IsV4 ()) caps += CAPS_FLAG_V4;
|
||||
if (address.IsV6 ()) caps += CAPS_FLAG_V6;
|
||||
if (caps.empty ()) caps += CAPS_FLAG_V4;
|
||||
WriteString (caps, properties);
|
||||
properties << ';';
|
||||
}
|
||||
}
|
||||
else
|
||||
continue; // don't write NTCP address
|
||||
}
|
||||
else if (address.transportStyle == eTransportSSU2)
|
||||
{
|
||||
WriteString ("SSU2", s);
|
||||
// caps
|
||||
std::string caps;
|
||||
if (isPublished)
|
||||
if (address.published)
|
||||
{
|
||||
isPublished = true;
|
||||
if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU2_TESTING;
|
||||
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU2_INTRODUCER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (address.IsV4 ()) caps += CAPS_FLAG_V4;
|
||||
if (address.IsV6 () || address.host.is_v6 ()) caps += CAPS_FLAG_V6; // we set 6 for unspecified ipv6
|
||||
if (address.IsV6 ()) caps += CAPS_FLAG_V6;
|
||||
if (caps.empty ()) caps += CAPS_FLAG_V4;
|
||||
}
|
||||
if (!caps.empty ())
|
||||
@@ -1437,15 +1269,10 @@ namespace data
|
||||
{
|
||||
return std::make_shared<Address> ();
|
||||
}
|
||||
|
||||
|
||||
boost::shared_ptr<RouterInfo::Addresses> LocalRouterInfo::NewAddresses () const
|
||||
{
|
||||
return boost::make_shared<Addresses> ();
|
||||
}
|
||||
|
||||
std::shared_ptr<IdentityEx> LocalRouterInfo::NewIdentity (const uint8_t * buf, size_t len) const
|
||||
{
|
||||
return std::make_shared<IdentityEx> (buf, len);
|
||||
}
|
||||
|
||||
bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4)
|
||||
|
||||
@@ -44,11 +44,7 @@ namespace data
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
|
||||
// congesion flags
|
||||
const char CAPS_FLAG_MEDIUM_CONGESTION = 'D';
|
||||
const char CAPS_FLAG_HIGH_CONGESTION = 'E';
|
||||
const char CAPS_FLAG_REJECT_ALL_CONGESTION = 'G';
|
||||
|
||||
|
||||
const char CAPS_FLAG_V4 = '4';
|
||||
const char CAPS_FLAG_V6 = '6';
|
||||
const char CAPS_FLAG_SSU2_TESTING = 'B';
|
||||
@@ -60,9 +56,6 @@ namespace data
|
||||
const uint8_t COST_SSU2_NON_PUBLISHED = 15;
|
||||
|
||||
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later
|
||||
const int HIGH_CONGESTION_INTERVAL = 15*60; // in seconds, 15 minutes
|
||||
const int INTRODUCER_UPDATE_INTERVAL = 20*60*1000; // in milliseconds, 20 minutes
|
||||
|
||||
class RouterInfo: public RoutingDestination
|
||||
{
|
||||
public:
|
||||
@@ -100,14 +93,6 @@ namespace data
|
||||
eUnreachable = 0x20
|
||||
};
|
||||
|
||||
enum Congestion
|
||||
{
|
||||
eLowCongestion = 0,
|
||||
eMediumCongestion,
|
||||
eHighCongestion,
|
||||
eRejectAll
|
||||
};
|
||||
|
||||
enum AddressCaps
|
||||
{
|
||||
eV4 = 0x01,
|
||||
@@ -125,10 +110,11 @@ namespace data
|
||||
|
||||
struct Introducer
|
||||
{
|
||||
Introducer (): iTag (0), iExp (0) {};
|
||||
Introducer (): iTag (0), iExp (0), isH (false) {};
|
||||
IdentHash iH;
|
||||
uint32_t iTag;
|
||||
uint32_t iExp;
|
||||
bool isH; // TODO: remove later
|
||||
};
|
||||
|
||||
struct SSUExt
|
||||
@@ -203,8 +189,8 @@ namespace data
|
||||
virtual void SetProperty (const std::string& key, const std::string& value) {};
|
||||
virtual void ClearProperties () {};
|
||||
boost::shared_ptr<Addresses> GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr
|
||||
std::shared_ptr<const Address> GetNTCP2V4Address () const;
|
||||
std::shared_ptr<const Address> GetNTCP2V6Address () const;
|
||||
std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const;
|
||||
std::shared_ptr<const Address> GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const;
|
||||
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
|
||||
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
|
||||
std::shared_ptr<const Address> GetYggdrasilAddress () const;
|
||||
@@ -212,19 +198,15 @@ namespace data
|
||||
std::shared_ptr<const Address> GetSSU2V6Address () const;
|
||||
std::shared_ptr<const Address> GetSSU2Address (bool v4) const;
|
||||
|
||||
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,int port, uint8_t caps); // non published
|
||||
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
|
||||
const boost::asio::ip::address& host, int port); // published
|
||||
void RemoveNTCP2Address (bool v4);
|
||||
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, int port, uint8_t caps); // non published
|
||||
const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0);
|
||||
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps = 0); // non published
|
||||
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
|
||||
const boost::asio::ip::address& host, int port); // published
|
||||
void RemoveSSU2Address (bool v4);
|
||||
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
|
||||
void UpdateSupportedTransports ();
|
||||
void UpdateIntroducers (uint64_t ts); // ts in seconds
|
||||
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
|
||||
void ResetFlooldFill () { m_Caps &= ~Caps::eFloodfill; };
|
||||
bool IsReachable () const { return m_Caps & Caps::eReachable; };
|
||||
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
||||
bool IsNTCP2 (bool v4only = true) const;
|
||||
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
|
||||
@@ -248,21 +230,16 @@ namespace data
|
||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||
bool IsEligibleFloodfill () const;
|
||||
bool IsPublished (bool v4) const;
|
||||
bool IsSSU2PeerTesting (bool v4) const;
|
||||
bool IsSSU2Introducer (bool v4) const;
|
||||
bool IsHighCongestion (bool highBandwidth) const;
|
||||
|
||||
uint8_t GetCaps () const { return m_Caps; };
|
||||
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
||||
|
||||
Congestion GetCongestion () const { return m_Congestion; };
|
||||
|
||||
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
||||
bool IsUnreachable () const { return m_IsUnreachable; };
|
||||
void ExcludeReachableTransports (CompatibleTransports transports) { m_ReachableTransports &= ~transports; };
|
||||
|
||||
const uint8_t * GetBuffer () const { return m_Buffer ? m_Buffer->data () : nullptr; };
|
||||
const uint8_t * GetBuffer () const { return m_Buffer->data (); };
|
||||
const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
|
||||
@@ -271,9 +248,9 @@ namespace data
|
||||
bool SaveToFile (const std::string& fullPath);
|
||||
|
||||
std::shared_ptr<RouterProfile> GetProfile () const;
|
||||
void DropProfile () { m_Profile = nullptr; };
|
||||
void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); };
|
||||
|
||||
bool Update (const uint8_t * buf, size_t len);
|
||||
void Update (const uint8_t * buf, size_t len);
|
||||
void DeleteBuffer () { m_Buffer = nullptr; };
|
||||
bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||
|
||||
@@ -295,8 +272,7 @@ namespace data
|
||||
void RefreshTimestamp ();
|
||||
CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; };
|
||||
void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
|
||||
void SetCongestion (Congestion c) { m_Congestion = c; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
bool LoadFile (const std::string& fullPath);
|
||||
@@ -306,13 +282,11 @@ namespace data
|
||||
size_t ReadString (char* str, size_t len, std::istream& s) const;
|
||||
void ExtractCaps (const char * value);
|
||||
uint8_t ExtractAddressCaps (const char * value) const;
|
||||
void UpdateIntroducers (std::shared_ptr<Address> address, uint64_t ts);
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const Address> GetAddress (Filter filter) const;
|
||||
virtual std::shared_ptr<Buffer> NewBuffer () const;
|
||||
virtual std::shared_ptr<Address> NewAddress () const;
|
||||
virtual boost::shared_ptr<Addresses> NewAddresses () const;
|
||||
virtual std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -320,13 +294,12 @@ namespace data
|
||||
std::shared_ptr<const IdentityEx> m_RouterIdentity;
|
||||
std::shared_ptr<Buffer> m_Buffer;
|
||||
size_t m_BufferLen;
|
||||
uint64_t m_Timestamp; // in milliseconds
|
||||
uint64_t m_Timestamp;
|
||||
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
|
||||
bool m_IsUpdated, m_IsUnreachable;
|
||||
CompatibleTransports m_SupportedTransports, m_ReachableTransports;
|
||||
uint8_t m_Caps;
|
||||
int m_Version;
|
||||
Congestion m_Congestion;
|
||||
mutable std::shared_ptr<RouterProfile> m_Profile;
|
||||
};
|
||||
|
||||
@@ -335,9 +308,9 @@ namespace data
|
||||
public:
|
||||
|
||||
LocalRouterInfo () = default;
|
||||
LocalRouterInfo (const std::string& fullPath): RouterInfo (fullPath) {};
|
||||
void CreateBuffer (const PrivateKeys& privateKeys);
|
||||
void UpdateCaps (uint8_t caps);
|
||||
bool UpdateCongestion (Congestion c); // returns true if updated
|
||||
|
||||
void SetProperty (const std::string& key, const std::string& value) override;
|
||||
void DeleteProperty (const std::string& key);
|
||||
@@ -355,7 +328,6 @@ namespace data
|
||||
std::shared_ptr<Buffer> NewBuffer () const override;
|
||||
std::shared_ptr<Address> NewAddress () const override;
|
||||
boost::shared_ptr<Addresses> NewAddresses () const override;
|
||||
std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) const override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -78,7 +78,6 @@ namespace transport
|
||||
if (address->IsV4 ())
|
||||
{
|
||||
found = true;
|
||||
LogPrint (eLogDebug, "SSU2: Opening IPv4 socket at Start");
|
||||
OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV4, port));
|
||||
m_ReceiveService.GetService ().post(
|
||||
[this]()
|
||||
@@ -90,7 +89,6 @@ namespace transport
|
||||
if (address->IsV6 ())
|
||||
{
|
||||
found = true;
|
||||
LogPrint (eLogDebug, "SSU2: Opening IPv6 socket at Start");
|
||||
OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV6, port));
|
||||
m_ReceiveService.GetService ().post(
|
||||
[this]()
|
||||
@@ -101,7 +99,7 @@ namespace transport
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogCritical, "SSU2: Can't start server because port not specified");
|
||||
LogPrint (eLogError, "SSU2: Can't start server because port not specified");
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
@@ -214,8 +212,6 @@ namespace transport
|
||||
boost::asio::ip::udp::socket& socket = localEndpoint.address ().is_v6 () ? m_SocketV6 : m_SocketV4;
|
||||
try
|
||||
{
|
||||
if (socket.is_open ())
|
||||
socket.close ();
|
||||
socket.open (localEndpoint.protocol ());
|
||||
if (localEndpoint.address ().is_v6 ())
|
||||
socket.set_option (boost::asio::ip::v6_only (true));
|
||||
@@ -226,7 +222,7 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex )
|
||||
{
|
||||
LogPrint (eLogCritical, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what());
|
||||
LogPrint (eLogError, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what());
|
||||
ThrowFatal ("Unable to start SSU2 transport on ", localEndpoint, ": ", ex.what ());
|
||||
}
|
||||
return socket;
|
||||
@@ -245,12 +241,10 @@ namespace transport
|
||||
if (!ecode
|
||||
|| ecode == boost::asio::error::connection_refused
|
||||
|| ecode == boost::asio::error::connection_reset
|
||||
|| ecode == boost::asio::error::network_reset
|
||||
|| ecode == boost::asio::error::network_unreachable
|
||||
|| ecode == boost::asio::error::host_unreachable
|
||||
#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
|
||||
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|
||||
|| ecode.value() == boost::winapi::WSAENETRESET_ // 10052
|
||||
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|
||||
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
|
||||
#endif
|
||||
@@ -307,7 +301,7 @@ namespace transport
|
||||
else
|
||||
{
|
||||
auto ep = socket.local_endpoint ();
|
||||
LogPrint (eLogCritical, "SSU2: Reopening socket in HandleReceivedFrom: code ", ecode.value(), ": ", ecode.message ());
|
||||
socket.close ();
|
||||
OpenSocket (ep);
|
||||
Receive (socket);
|
||||
}
|
||||
@@ -562,25 +556,16 @@ namespace transport
|
||||
SendThroughProxy (header, headerLen, nullptr, 0, payload, payloadLen, to);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> bufs
|
||||
{
|
||||
boost::asio::buffer (header, headerLen),
|
||||
boost::asio::buffer (payload, payloadLen)
|
||||
};
|
||||
|
||||
boost::system::error_code ec;
|
||||
if (to.address ().is_v6 ())
|
||||
{
|
||||
if (!m_SocketV6.is_open ()) return;
|
||||
m_SocketV6.send_to (bufs, to, 0, ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_SocketV4.is_open ()) return;
|
||||
m_SocketV4.send_to (bufs, to, 0, ec);
|
||||
}
|
||||
|
||||
if (!ec)
|
||||
i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen);
|
||||
else
|
||||
@@ -595,25 +580,17 @@ namespace transport
|
||||
SendThroughProxy (header, headerLen, headerX, headerXLen, payload, payloadLen, to);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> bufs
|
||||
{
|
||||
boost::asio::buffer (header, headerLen),
|
||||
boost::asio::buffer (headerX, headerXLen),
|
||||
boost::asio::buffer (payload, payloadLen)
|
||||
};
|
||||
|
||||
boost::system::error_code ec;
|
||||
if (to.address ().is_v6 ())
|
||||
{
|
||||
if (!m_SocketV6.is_open ()) return;
|
||||
m_SocketV6.send_to (bufs, to, 0, ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_SocketV4.is_open ()) return;
|
||||
m_SocketV4.send_to (bufs, to, 0, ec);
|
||||
}
|
||||
|
||||
if (!ec)
|
||||
i2p::transport::transports.UpdateSentBytes (headerLen + headerXLen + payloadLen);
|
||||
@@ -842,7 +819,7 @@ namespace transport
|
||||
m_CleanupTimer.async_wait (std::bind (&SSU2Server::HandleCleanupTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
|
||||
void SSU2Server::HandleCleanupTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
@@ -871,15 +848,15 @@ namespace transport
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
|
||||
m_PacketsPool.CleanUpMt ();
|
||||
m_SentPacketsPool.CleanUp ();
|
||||
m_IncompleteMessagesPool.CleanUp ();
|
||||
m_FragmentsPool.CleanUp ();
|
||||
ScheduleCleanup ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SSU2Server::ScheduleResend (bool more)
|
||||
{
|
||||
m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ? SSU2_RESEND_CHECK_MORE_TIMEOUT :
|
||||
@@ -939,7 +916,7 @@ namespace transport
|
||||
}
|
||||
uint64_t token;
|
||||
RAND_bytes ((uint8_t *)&token, 8);
|
||||
m_IncomingTokens.emplace (ep, std::make_pair (token, uint32_t(ts + SSU2_TOKEN_EXPIRATION_TIMEOUT)));
|
||||
m_IncomingTokens.emplace (ep, std::make_pair (token, ts + SSU2_TOKEN_EXPIRATION_TIMEOUT));
|
||||
return token;
|
||||
}
|
||||
|
||||
@@ -948,7 +925,7 @@ namespace transport
|
||||
m_IncomingTokens.erase (ep); // drop previous
|
||||
uint64_t token;
|
||||
RAND_bytes ((uint8_t *)&token, 8);
|
||||
auto ret = std::make_pair (token, uint32_t(i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT));
|
||||
auto ret = std::make_pair (token, i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT);
|
||||
m_IncomingTokens.emplace (ep, ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -1038,6 +1015,7 @@ namespace transport
|
||||
i2p::data::RouterInfo::Introducer introducer;
|
||||
introducer.iTag = it->GetRelayTag ();
|
||||
introducer.iH = it->GetRemoteIdentity ()->GetIdentHash ();
|
||||
introducer.isH = true;
|
||||
introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
|
||||
excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
|
||||
if (i2p::context.AddSSU2Introducer (introducer, v4))
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace transport
|
||||
i2p::util::MemoryPool<SSU2SentPacket>& GetSentPacketsPool () { return m_SentPacketsPool; };
|
||||
i2p::util::MemoryPool<SSU2IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; };
|
||||
i2p::util::MemoryPool<SSU2IncompleteMessage::Fragment>& GetFragmentsPool () { return m_FragmentsPool; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::ip::udp::socket& OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint);
|
||||
@@ -116,7 +116,7 @@ namespace transport
|
||||
|
||||
void ScheduleCleanup ();
|
||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||
|
||||
|
||||
void ScheduleResend (bool more);
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace transport
|
||||
if (msg->len + fragmentSize > msg->maxLen)
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU2: I2NP message size ", msg->maxLen, " is not enough");
|
||||
auto newMsg = NewI2NPMessage (msg->len + fragmentSize);
|
||||
auto newMsg = NewI2NPMessage ();
|
||||
*newMsg = *msg;
|
||||
msg = newMsg;
|
||||
}
|
||||
@@ -36,34 +36,34 @@ namespace transport
|
||||
{
|
||||
bool isLast = false;
|
||||
while (outOfSequenceFragments)
|
||||
{
|
||||
{
|
||||
if (outOfSequenceFragments->fragmentNum == nextFragmentNum)
|
||||
{
|
||||
AttachNextFragment (outOfSequenceFragments->buf, outOfSequenceFragments->len);
|
||||
isLast = outOfSequenceFragments->isLast;
|
||||
if (isLast)
|
||||
outOfSequenceFragments = nullptr;
|
||||
else
|
||||
else
|
||||
outOfSequenceFragments = outOfSequenceFragments->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isLast;
|
||||
}
|
||||
}
|
||||
|
||||
void SSU2IncompleteMessage::AddOutOfSequenceFragment (std::shared_ptr<SSU2IncompleteMessage::Fragment> fragment)
|
||||
{
|
||||
{
|
||||
if (!fragment || !fragment->fragmentNum) return; // fragment 0 not allowed
|
||||
if (fragment->fragmentNum < nextFragmentNum) return; // already processed
|
||||
if (!outOfSequenceFragments)
|
||||
if (!outOfSequenceFragments)
|
||||
outOfSequenceFragments = fragment;
|
||||
else
|
||||
{
|
||||
auto frag = outOfSequenceFragments;
|
||||
std::shared_ptr<Fragment> prev;
|
||||
do
|
||||
{
|
||||
{
|
||||
if (fragment->fragmentNum < frag->fragmentNum) break; // found
|
||||
if (fragment->fragmentNum == frag->fragmentNum) return; // duplicate
|
||||
prev = frag; frag = frag->next;
|
||||
@@ -71,21 +71,21 @@ namespace transport
|
||||
while (frag);
|
||||
fragment->next = frag;
|
||||
if (prev)
|
||||
prev->next = fragment;
|
||||
prev->next = fragment;
|
||||
else
|
||||
outOfSequenceFragments = fragment;
|
||||
}
|
||||
}
|
||||
lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
|
||||
SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr):
|
||||
TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT),
|
||||
m_Server (server), m_Address (addr), m_RemoteTransports (0),
|
||||
m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown),
|
||||
m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0),
|
||||
m_IsDataReceived (false), m_WindowSize (SSU2_MIN_WINDOW_SIZE),
|
||||
m_RTT (SSU2_RESEND_INTERVAL), m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0),
|
||||
m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false),
|
||||
m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RTT (SSU2_RESEND_INTERVAL),
|
||||
m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0),
|
||||
m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose),
|
||||
m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size
|
||||
{
|
||||
@@ -608,7 +608,7 @@ namespace transport
|
||||
* payload = m_SentHandshakePacket->payload;
|
||||
// fill packet
|
||||
header.h.connID = m_DestConnID; // dest id
|
||||
RAND_bytes (header.buf + 8, 4); // random packet num
|
||||
header.h.packetNum = 0;
|
||||
header.h.type = eSSU2SessionRequest;
|
||||
header.h.flags[0] = 2; // ver
|
||||
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
|
||||
@@ -636,7 +636,7 @@ namespace transport
|
||||
m_EphemeralKeys->Agree (m_Address->s, sharedSecret);
|
||||
m_NoiseState->MixKey (sharedSecret);
|
||||
// encrypt
|
||||
const uint8_t nonce[12] = {0}; // always 0
|
||||
const uint8_t nonce[12] = {0};
|
||||
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
|
||||
payloadSize += 16;
|
||||
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
|
||||
@@ -648,7 +648,6 @@ namespace transport
|
||||
if (m_State == eSSU2SessionStateTokenReceived || m_Server.AddPendingOutgoingSession (shared_from_this ()))
|
||||
{
|
||||
m_State = eSSU2SessionStateSessionRequestSent;
|
||||
m_HandshakeInterval = ts;
|
||||
m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
|
||||
}
|
||||
else
|
||||
@@ -722,7 +721,7 @@ namespace transport
|
||||
uint8_t * headerX = m_SentHandshakePacket->headerX,
|
||||
* payload = m_SentHandshakePacket->payload;
|
||||
header.h.connID = m_DestConnID; // dest id
|
||||
RAND_bytes (header.buf + 8, 4); // random packet num
|
||||
header.h.packetNum = 0;
|
||||
header.h.type = eSSU2SessionCreated;
|
||||
header.h.flags[0] = 2; // ver
|
||||
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
|
||||
@@ -761,7 +760,7 @@ namespace transport
|
||||
m_EphemeralKeys->Agree (X, sharedSecret);
|
||||
m_NoiseState->MixKey (sharedSecret);
|
||||
// encrypt
|
||||
const uint8_t nonce[12] = {0}; // always zero
|
||||
const uint8_t nonce[12] = {0};
|
||||
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
|
||||
payloadSize += 16;
|
||||
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted Noise payload from Session Created)
|
||||
@@ -771,7 +770,6 @@ namespace transport
|
||||
m_State = eSSU2SessionStateSessionCreatedSent;
|
||||
m_SentHandshakePacket->payloadSize = payloadSize;
|
||||
// send
|
||||
m_HandshakeInterval = ts;
|
||||
m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
|
||||
}
|
||||
|
||||
@@ -792,7 +790,6 @@ namespace transport
|
||||
LogPrint (eLogWarning, "SSU2: SessionCreated message too short ", len);
|
||||
return false;
|
||||
}
|
||||
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
|
||||
const uint8_t nonce[12] = {0};
|
||||
uint8_t headerX[48];
|
||||
i2p::crypto::ChaCha20 (buf + 16, 48, kh2, nonce, headerX);
|
||||
@@ -809,8 +806,6 @@ namespace transport
|
||||
m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false))
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: SessionCreated AEAD verification failed ");
|
||||
if (GetRemoteIdentity ())
|
||||
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key
|
||||
return false;
|
||||
}
|
||||
m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from SessionCreated) for SessionConfirmed
|
||||
@@ -837,7 +832,7 @@ namespace transport
|
||||
// fill packet
|
||||
Header& header = m_SentHandshakePacket->header;
|
||||
header.h.connID = m_DestConnID; // dest id
|
||||
header.h.packetNum = 0; // always zero
|
||||
header.h.packetNum = 0;
|
||||
header.h.type = eSSU2SessionConfirmed;
|
||||
memset (header.h.flags, 0, 3);
|
||||
header.h.flags[0] = 1; // frag, total fragments always 1
|
||||
@@ -860,7 +855,7 @@ namespace transport
|
||||
// Encrypt part 1
|
||||
uint8_t * part1 = m_SentHandshakePacket->headerX;
|
||||
uint8_t nonce[12];
|
||||
CreateNonce (1, nonce); // always one
|
||||
CreateNonce (1, nonce);
|
||||
i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetSSU2StaticPublicKey (), 32, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, part1, 48, true);
|
||||
m_NoiseState->MixHash (part1, 48); // h = SHA256(h || ciphertext);
|
||||
// KDF for Session Confirmed part 2
|
||||
@@ -868,7 +863,7 @@ namespace transport
|
||||
i2p::context.GetSSU2StaticKeys ().Agree (Y, sharedSecret);
|
||||
m_NoiseState->MixKey (sharedSecret);
|
||||
// Encrypt part2
|
||||
memset (nonce, 0, 12); // always zero
|
||||
memset (nonce, 0, 12);
|
||||
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
|
||||
payloadSize += 16;
|
||||
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || ciphertext);
|
||||
@@ -925,12 +920,6 @@ namespace transport
|
||||
// TODO: queue up
|
||||
return true;
|
||||
}
|
||||
// packet num must be always zero
|
||||
if (header.h.packetNum)
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Non zero packet number in SessionConfirmed");
|
||||
return false;
|
||||
}
|
||||
// check if fragmented
|
||||
uint8_t numFragments = header.h.flags[0] & 0x0F;
|
||||
if (numFragments > 1)
|
||||
@@ -1000,7 +989,6 @@ namespace transport
|
||||
if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
|
||||
return false;
|
||||
}
|
||||
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
|
||||
// KDF for Session Confirmed part 1
|
||||
m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header)
|
||||
// decrypt part1
|
||||
@@ -1053,18 +1041,10 @@ namespace transport
|
||||
LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block");
|
||||
return false;
|
||||
}
|
||||
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address ();
|
||||
if (!m_Address || memcmp (S, m_Address->s, 32))
|
||||
m_Address = ri->GetSSU2AddressWithStaticKey (S, m_RemoteEndpoint.address ().is_v6 ());
|
||||
if (!m_Address)
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Wrong static key in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
||||
return false;
|
||||
}
|
||||
if (m_Address->published && m_RemoteEndpoint.address () != m_Address->host &&
|
||||
(!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
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Host mismatch between published address ", m_Address->host,
|
||||
" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
||||
LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
||||
return false;
|
||||
}
|
||||
// update RouterInfo in netdb
|
||||
@@ -1629,7 +1609,6 @@ namespace transport
|
||||
{
|
||||
case eSSU2SessionStateSessionRequestReceived:
|
||||
case eSSU2SessionStateTokenRequestReceived:
|
||||
case eSSU2SessionStateEstablished:
|
||||
if (std::abs (offset) > SSU2_CLOCK_SKEW)
|
||||
m_TerminationReason = eSSU2TerminationReasonClockSkew;
|
||||
break;
|
||||
@@ -1673,7 +1652,7 @@ namespace transport
|
||||
// ranges
|
||||
len -= 5;
|
||||
const uint8_t * ranges = buf + 5;
|
||||
while (len > 0 && firstPacketNum && ackThrough - firstPacketNum < SSU2_MAX_NUM_ACK_PACKETS)
|
||||
while (len > 0 && firstPacketNum)
|
||||
{
|
||||
uint32_t lastPacketNum = firstPacketNum - 1;
|
||||
if (*ranges > lastPacketNum) break;
|
||||
@@ -1778,8 +1757,8 @@ namespace transport
|
||||
|
||||
void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len)
|
||||
{
|
||||
auto msg = (buf[0] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage ();
|
||||
uint32_t msgID; memcpy (&msgID, buf + 1, 4);
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
// same format as I2NP message block
|
||||
msg->len = msg->offset + len + 7;
|
||||
memcpy (msg->GetNTCP2Header (), buf, len);
|
||||
@@ -1816,7 +1795,7 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: Invalid follow-on fragment num ", fragmentNum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
bool isLast = buf[0] & 0x01;
|
||||
uint32_t msgID; memcpy (&msgID, buf + 1, 4);
|
||||
auto it = m_IncompleteMessages.find (msgID);
|
||||
@@ -1884,9 +1863,10 @@ namespace transport
|
||||
|
||||
// send relay intro to Charlie
|
||||
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI
|
||||
if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
|
||||
if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found");
|
||||
|
||||
if (r)
|
||||
i2p::data::netdb.PopulateRouterInfoBuffer (r);
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found");
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
||||
size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
|
||||
if (!payloadSize && r)
|
||||
@@ -2080,7 +2060,7 @@ namespace transport
|
||||
auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
|
||||
// Alice's RouterInfo
|
||||
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
|
||||
if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
|
||||
if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r);
|
||||
packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0;
|
||||
if (!packet->payloadSize && r)
|
||||
session->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
|
||||
@@ -2184,7 +2164,7 @@ namespace transport
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
||||
// Charlie's RouterInfo
|
||||
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
|
||||
if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
|
||||
if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r);
|
||||
size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
|
||||
if (!payloadSize && r)
|
||||
it->second.first->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
|
||||
@@ -2308,9 +2288,9 @@ namespace transport
|
||||
m_Server.RemoveSession (~htobe64 (((uint64_t)nonce << 32) | nonce));
|
||||
break;
|
||||
case 7: // Alice from Charlie 2
|
||||
m_Server.RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce));
|
||||
if (m_Address->IsV6 ())
|
||||
i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2
|
||||
m_Server.RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce));
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", buf[0]);
|
||||
@@ -2318,21 +2298,21 @@ namespace transport
|
||||
}
|
||||
|
||||
void SSU2Session::HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg)
|
||||
{
|
||||
{
|
||||
if (!msg) return;
|
||||
uint32_t msgID = msg->GetMsgID ();
|
||||
int32_t msgID = msg->GetMsgID ();
|
||||
if (!msg->IsExpired ())
|
||||
{
|
||||
// m_LastActivityTimestamp is updated in ProcessData before
|
||||
if (m_ReceivedI2NPMsgIDs.emplace (msgID, (uint32_t)m_LastActivityTimestamp).second)
|
||||
m_Handler.PutNextMessage (std::move (msg));
|
||||
m_Handler.PutNextMessage (std::move (msg));
|
||||
else
|
||||
LogPrint (eLogDebug, "SSU2: Message ", msgID, " already received");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "SSU2: Message ", msgID, " expired");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SSU2Session::ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep)
|
||||
{
|
||||
if (size < 2) return false;
|
||||
@@ -2475,24 +2455,21 @@ namespace transport
|
||||
if (ackThrough)
|
||||
{
|
||||
if (m_OutOfSequencePackets.empty ())
|
||||
acnt = std::min ((int)ackThrough, SSU2_MAX_NUM_ACNT); // no gaps
|
||||
acnt = std::min ((int)ackThrough, 255); // no gaps
|
||||
else
|
||||
{
|
||||
auto it = m_OutOfSequencePackets.rbegin (); it++; // prev packet num
|
||||
while (it != m_OutOfSequencePackets.rend () && *it == ackThrough - acnt - 1)
|
||||
{
|
||||
acnt++;
|
||||
if (acnt >= SSU2_MAX_NUM_ACK_PACKETS)
|
||||
break;
|
||||
else
|
||||
it++;
|
||||
it++;
|
||||
}
|
||||
// ranges
|
||||
uint32_t lastNum = ackThrough - acnt;
|
||||
if (acnt > SSU2_MAX_NUM_ACNT)
|
||||
if (acnt > 255)
|
||||
{
|
||||
auto d = std::div (acnt - SSU2_MAX_NUM_ACNT, SSU2_MAX_NUM_ACNT);
|
||||
acnt = SSU2_MAX_NUM_ACNT;
|
||||
auto d = std::div (acnt - 255, 255);
|
||||
acnt = 255;
|
||||
if (d.quot > maxNumRanges)
|
||||
{
|
||||
d.quot = maxNumRanges;
|
||||
@@ -2501,7 +2478,7 @@ namespace transport
|
||||
// Acks only ranges for acnt
|
||||
for (int i = 0; i < d.quot; i++)
|
||||
{
|
||||
buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // NACKs 0, Acks 255
|
||||
buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = 255; // NACKs 0, Acks 255
|
||||
numRanges++;
|
||||
}
|
||||
if (d.rem > 0)
|
||||
@@ -2510,25 +2487,21 @@ namespace transport
|
||||
numRanges++;
|
||||
}
|
||||
}
|
||||
int numPackets = acnt + numRanges*SSU2_MAX_NUM_ACNT;
|
||||
while (it != m_OutOfSequencePackets.rend () &&
|
||||
numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS)
|
||||
while (it != m_OutOfSequencePackets.rend () && numRanges < maxNumRanges)
|
||||
{
|
||||
if (lastNum - (*it) > SSU2_MAX_NUM_ACNT)
|
||||
if (lastNum - (*it) > 255)
|
||||
{
|
||||
// NACKs only ranges
|
||||
if (lastNum > (*it) + SSU2_MAX_NUM_ACNT*(maxNumRanges - numRanges)) break; // too many NACKs
|
||||
while (lastNum - (*it) > SSU2_MAX_NUM_ACNT)
|
||||
if (lastNum > (*it) + 255*(maxNumRanges - numRanges)) break; // too many NACKs
|
||||
while (lastNum - (*it) > 255)
|
||||
{
|
||||
buf[8 + numRanges*2] = SSU2_MAX_NUM_ACNT; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0
|
||||
lastNum -= SSU2_MAX_NUM_ACNT;
|
||||
buf[8 + numRanges*2] = 255; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0
|
||||
lastNum -= 255;
|
||||
numRanges++;
|
||||
numPackets += SSU2_MAX_NUM_ACNT;
|
||||
}
|
||||
}
|
||||
// NACKs and Acks ranges
|
||||
buf[8 + numRanges*2] = lastNum - (*it) - 1; // NACKs
|
||||
numPackets += buf[8 + numRanges*2];
|
||||
lastNum = *it; it++;
|
||||
int numAcks = 1;
|
||||
while (it != m_OutOfSequencePackets.rend () && lastNum > 0 && *it == lastNum - 1)
|
||||
@@ -2536,31 +2509,28 @@ namespace transport
|
||||
numAcks++; lastNum--;
|
||||
it++;
|
||||
}
|
||||
while (numAcks > SSU2_MAX_NUM_ACNT)
|
||||
while (numAcks > 255)
|
||||
{
|
||||
// Acks only ranges
|
||||
buf[8 + numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // Acks 255
|
||||
numAcks -= SSU2_MAX_NUM_ACNT;
|
||||
buf[8 + numRanges*2 + 1] = 255; // Acks 255
|
||||
numAcks -= 255;
|
||||
numRanges++;
|
||||
numPackets += SSU2_MAX_NUM_ACNT;
|
||||
buf[8 + numRanges*2] = 0; // NACKs 0
|
||||
if (numRanges >= maxNumRanges || numPackets >= SSU2_MAX_NUM_ACK_PACKETS) break;
|
||||
if (numRanges >= maxNumRanges) break;
|
||||
}
|
||||
if (numAcks > SSU2_MAX_NUM_ACNT) numAcks = SSU2_MAX_NUM_ACNT;
|
||||
if (numAcks > 255) numAcks = 255;
|
||||
buf[8 + numRanges*2 + 1] = (uint8_t)numAcks; // Acks
|
||||
numPackets += numAcks;
|
||||
numRanges++;
|
||||
}
|
||||
if (it == m_OutOfSequencePackets.rend () &&
|
||||
numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS)
|
||||
if (numRanges < maxNumRanges && it == m_OutOfSequencePackets.rend ())
|
||||
{
|
||||
// add range between out-of-sequence and received
|
||||
int nacks = *m_OutOfSequencePackets.begin () - m_ReceivePacketNum - 1;
|
||||
if (nacks > 0)
|
||||
{
|
||||
if (nacks > SSU2_MAX_NUM_ACNT) nacks = SSU2_MAX_NUM_ACNT;
|
||||
if (nacks > 255) nacks = 255;
|
||||
buf[8 + numRanges*2] = nacks;
|
||||
buf[8 + numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, SSU2_MAX_NUM_ACNT);
|
||||
buf[8 + numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, 255);
|
||||
numRanges++;
|
||||
}
|
||||
}
|
||||
@@ -2787,25 +2757,15 @@ namespace transport
|
||||
if (packetNum <= m_ReceivePacketNum) return false; // duplicate
|
||||
if (packetNum == m_ReceivePacketNum + 1)
|
||||
{
|
||||
if (!m_OutOfSequencePackets.empty ())
|
||||
for (auto it = m_OutOfSequencePackets.begin (); it != m_OutOfSequencePackets.end ();)
|
||||
{
|
||||
auto it = m_OutOfSequencePackets.begin ();
|
||||
if (*it == packetNum + 1)
|
||||
{
|
||||
// first out of sequence packet is in sequence now
|
||||
packetNum++; it++;
|
||||
while (it != m_OutOfSequencePackets.end ())
|
||||
{
|
||||
if (*it == packetNum + 1)
|
||||
{
|
||||
packetNum++;
|
||||
it++;
|
||||
}
|
||||
else // next out of sequence
|
||||
break;
|
||||
}
|
||||
m_OutOfSequencePackets.erase (m_OutOfSequencePackets.begin (), it);
|
||||
packetNum++;
|
||||
it = m_OutOfSequencePackets.erase (it);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
m_ReceivePacketNum = packetNum;
|
||||
}
|
||||
@@ -2817,16 +2777,7 @@ namespace transport
|
||||
void SSU2Session::SendQuickAck ()
|
||||
{
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
||||
size_t payloadSize = 0;
|
||||
if (m_SendPacketNum > m_LastDatetimeSentPacketNum + SSU2_SEND_DATETIME_NUM_PACKETS)
|
||||
{
|
||||
payload[0] = eSSU2BlkDateTime;
|
||||
htobe16buf (payload + 1, 4);
|
||||
htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
|
||||
payloadSize += 7;
|
||||
m_LastDatetimeSentPacketNum = m_SendPacketNum;
|
||||
}
|
||||
payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
|
||||
size_t payloadSize = CreateAckBlock (payload, m_MaxPayloadSize);
|
||||
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
|
||||
SendData (payload, payloadSize);
|
||||
}
|
||||
@@ -2900,10 +2851,8 @@ namespace transport
|
||||
}
|
||||
if (!m_OutOfSequencePackets.empty ())
|
||||
{
|
||||
int ranges = 0;
|
||||
while (ranges < 8 && !m_OutOfSequencePackets.empty () &&
|
||||
(m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES ||
|
||||
*m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + SSU2_MAX_NUM_ACK_PACKETS))
|
||||
if (m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES ||
|
||||
*m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + 255*8)
|
||||
{
|
||||
uint32_t packet = *m_OutOfSequencePackets.begin ();
|
||||
if (packet > m_ReceivePacketNum + 1)
|
||||
@@ -2912,13 +2861,9 @@ namespace transport
|
||||
packet--;
|
||||
m_ReceivePacketNum = packet - 1;
|
||||
UpdateReceivePacketNum (packet);
|
||||
ranges++;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_OutOfSequencePackets.size () > 255*4)
|
||||
{
|
||||
|
||||
@@ -48,12 +48,9 @@ namespace transport
|
||||
const size_t SSU2_MAX_RTO = 2500; // in milliseconds
|
||||
const float SSU2_kAPPA = 1.8;
|
||||
const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages
|
||||
const int SSU2_MAX_NUM_ACNT = 255; // acnt, acks or nacks
|
||||
const int SSU2_MAX_NUM_ACK_PACKETS = 511; // ackthrough + acnt + 1 range
|
||||
const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send
|
||||
const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64;
|
||||
const int SSU2_SEND_DATETIME_NUM_PACKETS = 256;
|
||||
|
||||
|
||||
// flags
|
||||
const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01;
|
||||
|
||||
@@ -318,7 +315,7 @@ namespace transport
|
||||
void HandleRelayResponse (const uint8_t * buf, size_t len);
|
||||
void HandlePeerTest (const uint8_t * buf, size_t len);
|
||||
void HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg);
|
||||
|
||||
|
||||
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 CreateAckBlock (uint8_t * buf, size_t len);
|
||||
@@ -345,7 +342,7 @@ namespace transport
|
||||
uint64_t m_DestConnID, m_SourceConnID;
|
||||
SSU2SessionState m_State;
|
||||
uint8_t m_KeyDataSend[64], m_KeyDataReceive[64];
|
||||
uint32_t m_SendPacketNum, m_ReceivePacketNum, m_LastDatetimeSentPacketNum;
|
||||
uint32_t m_SendPacketNum, m_ReceivePacketNum;
|
||||
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
|
||||
std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > m_SentPackets; // packetNum -> packet
|
||||
std::unordered_map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // msgID -> I2NP
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -51,8 +51,8 @@ namespace stream
|
||||
{
|
||||
// partially
|
||||
rem = len - offset;
|
||||
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem);
|
||||
nextBuffer->offset += rem;
|
||||
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset);
|
||||
nextBuffer->offset += (len - offset);
|
||||
offset = len; // break
|
||||
}
|
||||
}
|
||||
@@ -139,22 +139,14 @@ namespace stream
|
||||
{
|
||||
m_NumReceivedBytes += packet->GetLength ();
|
||||
if (!m_SendStreamID)
|
||||
{
|
||||
m_SendStreamID = packet->GetReceiveStreamID ();
|
||||
if (!m_RemoteIdentity && packet->GetNACKCount () == 8 && // first incoming packet
|
||||
memcmp (packet->GetNACKs (), m_LocalDestination.GetOwner ()->GetIdentHash (), 32))
|
||||
{
|
||||
LogPrint (eLogWarning, "Streaming: Destination mismatch for ", m_LocalDestination.GetOwner ()->GetIdentHash ().ToBase32 ());
|
||||
m_LocalDestination.DeletePacket (packet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!packet->IsNoAck ()) // ack received
|
||||
ProcessAck (packet);
|
||||
|
||||
int32_t receivedSeqn = packet->GetSeqn ();
|
||||
if (!receivedSeqn && !packet->GetFlags ())
|
||||
bool isSyn = packet->IsSYN ();
|
||||
if (!receivedSeqn && !isSyn)
|
||||
{
|
||||
// plain ack
|
||||
LogPrint (eLogDebug, "Streaming: Plain ACK received");
|
||||
@@ -196,7 +188,7 @@ namespace stream
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
else if (packet->IsSYN ())
|
||||
else if (isSyn)
|
||||
// we have to send SYN back to incoming connection
|
||||
SendBuffer (); // also sets m_IsOpen
|
||||
}
|
||||
@@ -392,7 +384,7 @@ namespace stream
|
||||
memset (p.buf, 0, 22); // minimal header all zeroes
|
||||
memcpy (p.buf + 4, packet->buf, 4); // but receiveStreamID is the sendStreamID from the ping
|
||||
htobe16buf (p.buf + 18, PACKET_FLAG_ECHO); // and echo flag
|
||||
auto payloadLen = int(packet->len) - (packet->GetPayload () - packet->buf);
|
||||
ssize_t payloadLen = packet->len - (packet->GetPayload () - packet->buf);
|
||||
if (payloadLen > 0)
|
||||
memcpy (p.buf + 22, packet->GetPayload (), payloadLen);
|
||||
else
|
||||
@@ -568,19 +560,8 @@ namespace stream
|
||||
else
|
||||
htobe32buf (packet + size, m_LastReceivedSequenceNumber);
|
||||
size += 4; // ack Through
|
||||
if (m_Status == eStreamStatusNew && !m_SendStreamID && m_RemoteIdentity)
|
||||
{
|
||||
// first SYN packet
|
||||
packet[size] = 8;
|
||||
size++; // NACK count
|
||||
memcpy (packet + size, m_RemoteIdentity->GetIdentHash (), 32);
|
||||
size += 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[size] = 0;
|
||||
size++; // NACK count
|
||||
}
|
||||
packet[size] = 0;
|
||||
size++; // NACK count
|
||||
packet[size] = m_RTO/1000;
|
||||
size++; // resend delay
|
||||
if (m_Status == eStreamStatusNew)
|
||||
@@ -925,7 +906,7 @@ namespace stream
|
||||
});
|
||||
m_NumSentBytes += it->GetLength ();
|
||||
}
|
||||
m_CurrentOutboundTunnel->SendTunnelDataMsgs (msgs);
|
||||
m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1447,7 +1428,7 @@ namespace stream
|
||||
const uint8_t * payload, size_t len, uint16_t toPort, bool checksum, bool gzip)
|
||||
{
|
||||
size_t size;
|
||||
auto msg = (len <= STREAMING_MTU_RATCHETS) ? m_I2NPMsgsPool.AcquireShared () : NewI2NPMessage ();
|
||||
auto msg = m_I2NPMsgsPool.AcquireShared ();
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
buf += 4; // reserve for lengthlength
|
||||
msg->len += 4;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -80,7 +80,6 @@ namespace stream
|
||||
uint32_t GetAckThrough () const { return bufbe32toh (buf + 12); };
|
||||
uint8_t GetNACKCount () const { return buf[16]; };
|
||||
uint32_t GetNACK (int i) const { return bufbe32toh (buf + 17 + 4 * i); };
|
||||
const uint8_t * GetNACKs () const { return buf + 17; };
|
||||
const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags
|
||||
uint16_t GetFlags () const { return bufbe16toh (GetOption () - 2); };
|
||||
uint16_t GetOptionSize () const { return bufbe16toh (GetOption ()); };
|
||||
@@ -313,7 +312,7 @@ namespace stream
|
||||
std::unordered_map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
|
||||
|
||||
i2p::util::MemoryPool<Packet> m_PacketsPool;
|
||||
i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> > m_I2NPMsgsPool;
|
||||
i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -80,13 +80,6 @@ namespace data {
|
||||
return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
||||
}
|
||||
|
||||
uint8_t GetBit (int i) const
|
||||
{
|
||||
int pos = i >> 3; // /8
|
||||
if (pos >= (int)sz) return 0;
|
||||
return m_Buf[pos] & (0x80 >> (i & 0x07));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
union // 8 bytes aligned
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -34,9 +34,9 @@ namespace tunnel
|
||||
virtual size_t GetNumTransmittedBytes () const { return 0; };
|
||||
|
||||
// implements TunnelBase
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
|
||||
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
|
||||
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) override;
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
|
||||
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
||||
private:
|
||||
|
||||
i2p::crypto::AESKey m_LayerKey, m_IVKey;
|
||||
@@ -54,9 +54,9 @@ namespace tunnel
|
||||
layerKey, ivKey), m_NumTransmittedBytes (0) {};
|
||||
~TransitTunnelParticipant ();
|
||||
|
||||
size_t GetNumTransmittedBytes () const override { return m_NumTransmittedBytes; };
|
||||
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
|
||||
void FlushTunnelDataMsgs () override;
|
||||
size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; };
|
||||
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
|
||||
void FlushTunnelDataMsgs ();
|
||||
|
||||
private:
|
||||
|
||||
@@ -74,9 +74,9 @@ namespace tunnel
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
||||
layerKey, ivKey), m_Gateway(this) {};
|
||||
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
|
||||
void FlushTunnelDataMsgs () override;
|
||||
size_t GetNumTransmittedBytes () const override { return m_Gateway.GetNumSentBytes (); };
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void FlushTunnelDataMsgs ();
|
||||
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
|
||||
|
||||
private:
|
||||
|
||||
@@ -94,10 +94,10 @@ namespace tunnel
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
|
||||
m_Endpoint (false) {}; // transit endpoint is always outbound
|
||||
|
||||
void Cleanup () override { m_Endpoint.Cleanup (); }
|
||||
void Cleanup () { m_Endpoint.Cleanup (); }
|
||||
|
||||
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
|
||||
size_t GetNumTransmittedBytes () const override { return m_Endpoint.GetNumReceivedBytes (); }
|
||||
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
|
||||
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user