Browse Source

resolve merge conflicts

pull/1669/head
idk 3 years ago
parent
commit
d62d2ed269
No known key found for this signature in database
GPG Key ID: D75C03B39B5E14E1
  1. 2
      .gitignore
  2. 54
      .travis.yml
  3. 10
      Makefile
  4. 2
      README.md
  5. 57
      appveyor.yml
  6. 17
      build/CMakeLists.txt
  7. 34
      build/docker/README.md
  8. 11
      build/docker/old-ubuntu-based/Dockerfile
  9. 2
      build/fig.yml
  10. 2
      contrib/docker/Dockerfile
  11. 320
      contrib/i18n/English.po
  12. 3
      contrib/i18n/regex.txt
  13. 7
      contrib/i2pd.conf
  14. 6
      daemon/Daemon.cpp
  15. 108
      daemon/HTTPServer.cpp
  16. 2
      daemon/I2PControl.cpp
  17. 7
      i18n/Afrikaans.cpp
  18. 7
      i18n/English.cpp
  19. 13
      i18n/I18N.h
  20. 28
      i18n/I18N_langs.h
  21. 136
      i18n/Russian.cpp
  22. 7
      i18n/Turkmen.cpp
  23. 146
      i18n/Ukrainian.cpp
  24. 3
      libi2pd/Config.cpp
  25. 20
      libi2pd/FS.cpp
  26. 16
      libi2pd/FS.h
  27. 4
      libi2pd/Family.cpp
  28. 23
      libi2pd/I2NPProtocol.cpp
  29. 8
      libi2pd/I2NPProtocol.h
  30. 3
      libi2pd/Reseed.cpp
  31. 10
      libi2pd/RouterContext.cpp
  32. 16
      libi2pd/RouterInfo.cpp
  33. 3
      libi2pd/RouterInfo.h
  34. 17
      libi2pd/Streaming.cpp
  35. 11
      libi2pd/Streaming.h
  36. 4
      libi2pd/TransitTunnel.cpp
  37. 2
      libi2pd/Transports.cpp
  38. 2
      libi2pd/Tunnel.cpp
  39. 177
      libi2pd/TunnelEndpoint.cpp
  40. 23
      libi2pd/TunnelEndpoint.h
  41. 2
      libi2pd/TunnelGateway.cpp
  42. 2
      libi2pd_client/HTTPProxy.cpp

2
.gitignore vendored

@ -7,8 +7,10 @@ netDb
/i2pd /i2pd
/libi2pd.a /libi2pd.a
/libi2pdclient.a /libi2pdclient.a
/libi2pdlang.a
/libi2pd.so /libi2pd.so
/libi2pdclient.so /libi2pdclient.so
/libi2pdlang.so
*.exe *.exe

54
.travis.yml

@ -1,54 +0,0 @@
language: cpp
cache:
apt: true
os:
- linux
#- osx
dist: xenial
sudo: required
compiler:
- g++
- clang++
env:
global:
- MAKEFLAGS="-j 2"
matrix:
- BUILD_TYPE=make UPNP=ON MAKE_UPNP=yes
- BUILD_TYPE=make UPNP=OFF MAKE_UPNP=no
- BUILD_TYPE=cmake UPNP=ON MAKE_UPNP=yes
- BUILD_TYPE=cmake UPNP=OFF MAKE_UPNP=no
matrix:
exclude:
- os: osx
env: BUILD_TYPE=cmake UPNP=ON MAKE_UPNP=yes
- os: osx
env: BUILD_TYPE=cmake UPNP=OFF MAKE_UPNP=no
- os: linux
compiler: clang++
env: BUILD_TYPE=make UPNP=ON MAKE_UPNP=yes
- os: linux
compiler: clang++
env: BUILD_TYPE=make UPNP=OFF MAKE_UPNP=no
addons:
apt:
packages:
- build-essential
- cmake
- g++
- clang
- libboost-chrono-dev
- libboost-date-time-dev
- libboost-filesystem-dev
- libboost-program-options-dev
- libboost-system-dev
- libboost-thread-dev
- libminiupnpc-dev
- libssl-dev
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libressl miniupnpc ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew outdated boost || brew upgrade boost ; fi
script:
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$BUILD_TYPE" == "cmake" ]]; then cd build && cmake -DCMAKE_BUILD_TYPE=Release -DWITH_UPNP=${UPNP} && make ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$BUILD_TYPE" == "make" ]]; then make USE_UPNP=${MAKE_UPNP} ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make HOMEBREW=1 USE_UPNP=${MAKE_UPNP} ; fi

10
Makefile

@ -79,7 +79,8 @@ api: mk_obj_dir $(SHLIB) $(ARLIB)
client: mk_obj_dir $(SHLIB_CLIENT) $(ARLIB_CLIENT) client: mk_obj_dir $(SHLIB_CLIENT) $(ARLIB_CLIENT)
api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
wrapper: api_client $(SHLIB_WRAP) $(ARLIB_WRAP) wrapper: api_client $(SHLIB_WRAP) $(ARLIB_WRAP)
langs: mk_obj_dir $(LANG_OBJS) $(SHLIB_LANG) $(ARLIB_LANG) lang: mk_obj_dir $(SHLIB_LANG) $(ARLIB_LANG)
## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time ## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time
## **without** overwriting the CXXFLAGS which we need in order to build. ## **without** overwriting the CXXFLAGS which we need in order to build.
@ -94,7 +95,7 @@ obj/%.o: %.cpp
# '-' is 'ignore if missing' on first run # '-' is 'ignore if missing' on first run
-include $(DEPS) -include $(DEPS)
$(I2PD): $(LANG_OBJS) $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG)
$(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS) $(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS)
$(SHLIB): $(LIB_OBJS) $(SHLIB): $(LIB_OBJS)
@ -132,9 +133,9 @@ $(ARLIB_LANG): $(LANG_OBJS)
clean: clean:
$(RM) -r obj $(RM) -r obj
$(RM) -r docs/generated $(RM) -r docs/generated
$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) $(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) $(SHLIB_LANG) $(ARLIB_LANG)
strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB) strip: $(I2PD) $(SHLIB) $(SHLIB_CLIENT) $(SHLIB_LANG)
strip $^ strip $^
LATEST_TAG=$(shell git describe --tags --abbrev=0 openssl) LATEST_TAG=$(shell git describe --tags --abbrev=0 openssl)
@ -158,6 +159,7 @@ doxygen:
.PHONY: api .PHONY: api
.PHONY: api_client .PHONY: api_client
.PHONY: client .PHONY: client
.PHONY: lang
.PHONY: mk_obj_dir .PHONY: mk_obj_dir
.PHONY: install .PHONY: install
.PHONY: strip .PHONY: strip

2
README.md

@ -73,7 +73,7 @@ Build instructions:
* Alpine, ArchLinux, openSUSE, Gentoo, Debian, Ubuntu, etc. * Alpine, ArchLinux, openSUSE, Gentoo, Debian, Ubuntu, etc.
* Windows - [![Build on Windows](https://github.com/PurpleI2P/i2pd/actions/workflows/build-windows.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-windows.yml) * Windows - [![Build on Windows](https://github.com/PurpleI2P/i2pd/actions/workflows/build-windows.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-windows.yml)
* Mac OS X - [![Build on OSX](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml) * Mac OS X - [![Build on OSX](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-osx.yml)
* Docker image - [![Build Status](https://img.shields.io/docker/cloud/build/purplei2p/i2pd)](https://hub.docker.com/r/purplei2p/i2pd/builds/) * Docker image - [![Build Status](https://img.shields.io/docker/cloud/build/purplei2p/i2pd)](https://hub.docker.com/r/purplei2p/i2pd/builds/) [![Build containers](https://github.com/PurpleI2P/i2pd/actions/workflows/docker.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/docker.yml)
* Snap - [![i2pd](https://snapcraft.io/i2pd/badge.svg)](https://snapcraft.io/i2pd) [![i2pd](https://snapcraft.io/i2pd/trending.svg?name=0)](https://snapcraft.io/i2pd) * Snap - [![i2pd](https://snapcraft.io/i2pd/badge.svg)](https://snapcraft.io/i2pd) [![i2pd](https://snapcraft.io/i2pd/trending.svg?name=0)](https://snapcraft.io/i2pd)
* FreeBSD - [![Build on FreeBSD](https://github.com/PurpleI2P/i2pd/actions/workflows/build-freebsd.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-freebsd.yml) * FreeBSD - [![Build on FreeBSD](https://github.com/PurpleI2P/i2pd/actions/workflows/build-freebsd.yml/badge.svg)](https://github.com/PurpleI2P/i2pd/actions/workflows/build-freebsd.yml)
* Android - [![Android CI](https://github.com/PurpleI2P/i2pd-android/actions/workflows/android.yml/badge.svg)](https://github.com/PurpleI2P/i2pd-android/actions/workflows/android.yml) * Android - [![Android CI](https://github.com/PurpleI2P/i2pd-android/actions/workflows/android.yml/badge.svg)](https://github.com/PurpleI2P/i2pd-android/actions/workflows/android.yml)

57
appveyor.yml

@ -1,57 +0,0 @@
version: 2.38.0.{build}
pull_requests:
do_not_increment_build_number: true
branches:
only:
- openssl
skip_tags: true
os: Visual Studio 2015
shallow_clone: true
clone_depth: 1
# avoid building 32-bit if 64-bit failed already
matrix:
fast_finish: true
environment:
APPVEYOR_SAVE_CACHE_ON_ERROR: true
MSYS2_PATH_TYPE: inherit
CHERE_INVOKING: enabled_from_arguments
matrix:
- MSYSTEM: MINGW64
- MSYSTEM: MINGW32
cache:
- c:\msys64\var\cache\pacman\pkg\
install:
# install new signing keyring
- c:\msys64\usr\bin\bash -lc "curl -O https://mirror.selfnet.de/msys2/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz"
- c:\msys64\usr\bin\bash -lc "curl -O https://mirror.selfnet.de/msys2/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig"
- c:\msys64\usr\bin\bash -lc "pacman-key --verify msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig"
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -U msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz"
# remove packages which can break build
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc mingw-w64-{i686,x86_64}-gcc-ada mingw-w64-{i686,x86_64}-gcc-objc"
# update runtime
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
# Kill bash before next try
- taskkill /T /F /IM bash.exe /IM gpg.exe /IM gpg-agent.exe | exit /B 0
# update packages and install required
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu $MINGW_PACKAGE_PREFIX-boost $MINGW_PACKAGE_PREFIX-miniupnpc"
build_script:
- c:\msys64\usr\bin\bash -lc "make USE_UPNP=yes DEBUG=no -j3"
# prepare archive for uploading
- set "FILELIST=i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates contrib/tunnels.d"
- echo This is development build, use it carefully! For running in portable mode, move all files from contrib directory here. > README.txt
- 7z a -tzip -mx9 -mmt i2pd-%APPVEYOR_BUILD_VERSION%-%APPVEYOR_REPO_COMMIT:~0,7%-mingw-win%MSYSTEM:~-2%.zip %FILELIST%
after_build:
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Sc"
test: off
deploy: off
artifacts:
- path: i2pd-*.zip

17
build/CMakeLists.txt

@ -69,6 +69,16 @@ if(WITH_LIBRARY)
endif() endif()
FILE(GLOB LANG_SRC ${LANG_SRC_DIR}/*.cpp) FILE(GLOB LANG_SRC ${LANG_SRC_DIR}/*.cpp)
add_library(libi2pdlang ${LANG_SRC})
set_target_properties(libi2pdlang PROPERTIES PREFIX "")
if(WITH_LIBRARY)
install(TARGETS libi2pdlang
EXPORT libi2pdlang
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
COMPONENT Libraries)
endif()
set(DAEMON_SRC set(DAEMON_SRC
"${DAEMON_SRC_DIR}/Daemon.cpp" "${DAEMON_SRC_DIR}/Daemon.cpp"
@ -198,10 +208,11 @@ if(WITH_PCH)
) )
target_compile_options(libi2pd PRIVATE -include libi2pd/stdafx.h) target_compile_options(libi2pd PRIVATE -include libi2pd/stdafx.h)
target_compile_options(libi2pdclient PRIVATE -include libi2pd/stdafx.h) target_compile_options(libi2pdclient PRIVATE -include libi2pd/stdafx.h)
target_compile_options(libi2pdlang PRIVATE -include libi2pd/stdafx.h)
target_link_libraries(libi2pd stdafx) target_link_libraries(libi2pd stdafx)
endif() endif()
target_link_libraries(libi2pdclient libi2pd) target_link_libraries(libi2pdclient libi2pd libi2pdlang)
find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED) find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED)
if(NOT DEFINED Boost_INCLUDE_DIRS) if(NOT DEFINED Boost_INCLUDE_DIRS)
@ -265,7 +276,7 @@ message(STATUS "---------------------------------------")
include(GNUInstallDirs) include(GNUInstallDirs)
if(WITH_BINARY) if(WITH_BINARY)
add_executable("${PROJECT_NAME}" ${LANG_SRC} ${DAEMON_SRC}) add_executable("${PROJECT_NAME}" ${DAEMON_SRC})
if(WITH_STATIC) if(WITH_STATIC)
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static") set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static")
@ -295,7 +306,7 @@ if(WITH_BINARY)
endif() endif()
target_link_libraries(libi2pd ${Boost_LIBRARIES} ${ZLIB_LIBRARY}) target_link_libraries(libi2pd ${Boost_LIBRARIES} ${ZLIB_LIBRARY})
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${UPNP_LIB} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES}) target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${UPNP_LIB} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime) install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}") set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")

34
build/docker/README.md

@ -1,34 +0,0 @@
Howto build & run
==================
**Build**
Assuming you're in the root directory of the anoncoin source code.
$ `cd build/docker`
$ `docker -t meeh/i2pd:latest .`
**Run**
To run either the local build, or if not found - fetched prebuild from hub.docker.io, run the following command.
$ `docker run --name anonnode -v /path/to/i2pd/datadir/on/host:/var/lib/i2pd -p 7070:7070 -p 4444:4444 -p 4447:4447 -p 7656:7656 -p 2827:2827 -p 7654:7654 -p 7650:7650 -d meeh/i2pd`
All the ports ( -p HOSTPORT:DOCKERPORT ) is optional. However the command above enable all features (Webconsole, HTTP Proxy, BOB, SAM, i2cp, etc)
The volume ( -v HOSTDIR:DOCKERDIR ) is also optional, but if you don't use it, your config, routerid and private keys will die along with the container.
**Options**
Options are set via docker environment variables. This can be set at run with -e parameters.
* **ENABLE_IPV6** - Enable IPv6 support. Any value can be used - it triggers as long as it's not empty.
* **LOGLEVEL** - Set the loglevel.
* **ENABLE_AUTH** - Enable auth for the webconsole. Username and password needs to be set manually in i2pd.conf cause security reasons.
**Logging**
Logging happens to STDOUT as the best practise with docker containers, since infrastructure systems like kubernetes with ELK integration can automatically forward the log to say, kibana or greylog without manual setup. :)

11
build/docker/old-ubuntu-based/Dockerfile

@ -1,11 +0,0 @@
FROM ubuntu
RUN apt-get update && apt-get install -y libboost-dev libboost-filesystem-dev \
libboost-program-options-dev libboost-date-time-dev \
libssl-dev git build-essential
RUN git clone https://github.com/PurpleI2P/i2pd.git
WORKDIR /i2pd
RUN make
CMD ./i2pd

2
build/fig.yml

@ -1,2 +0,0 @@
i2pd:
build: .

2
contrib/docker/Dockerfile

@ -1,4 +1,4 @@
FROM alpine:3.13 FROM alpine:latest
LABEL authors "Mikal Villa <mikal@sigterm.no>, Darknet Villain <supervillain@riseup.net>" LABEL authors "Mikal Villa <mikal@sigterm.no>, Darknet Villain <supervillain@riseup.net>"
# Expose git branch, tag and URL variables as arguments # Expose git branch, tag and URL variables as arguments

320
contrib/i18n/English.po

@ -26,551 +26,551 @@ msgstr ""
msgid "Enabled" msgid "Enabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:141 #: daemon/HTTPServer.cpp:147
msgid "day" msgid "day"
msgid_plural "days" msgid_plural "days"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:145
#: daemon/HTTPServer.cpp:151
msgid "hour" msgid "hour"
msgid_plural "hours" msgid_plural "hours"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:149
#: daemon/HTTPServer.cpp:155
msgid "minute" msgid "minute"
msgid_plural "minutes" msgid_plural "minutes"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:152 #: daemon/HTTPServer.cpp:158
msgid "second" msgid "second"
msgid_plural "seconds" msgid_plural "seconds"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:160 daemon/HTTPServer.cpp:188 #. tr: Kibibit
#: daemon/HTTPServer.cpp:166 daemon/HTTPServer.cpp:194
msgid "KiB" msgid "KiB"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:162 #. tr: Mebibit
#: daemon/HTTPServer.cpp:168
msgid "MiB" msgid "MiB"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:164 #. tr: Gibibit
#: daemon/HTTPServer.cpp:170
msgid "GiB" msgid "GiB"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:181 #: daemon/HTTPServer.cpp:187
msgid "building" msgid "building"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:182 #: daemon/HTTPServer.cpp:188
msgid "failed" msgid "failed"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:183 #: daemon/HTTPServer.cpp:189
msgid "expiring" msgid "expiring"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:184 #: daemon/HTTPServer.cpp:190
msgid "established" msgid "established"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:185 #: daemon/HTTPServer.cpp:191
msgid "unknown" msgid "unknown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:187 #: daemon/HTTPServer.cpp:193
msgid "exploratory" msgid "exploratory"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:223 #: daemon/HTTPServer.cpp:229
msgid "<b>i2pd</b> webconsole" msgid "<b>i2pd</b> webconsole"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:226 #: daemon/HTTPServer.cpp:232
msgid "Main page" msgid "Main page"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:227 daemon/HTTPServer.cpp:683 #: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:690
msgid "Router commands" msgid "Router commands"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:228 #: daemon/HTTPServer.cpp:234 daemon/HTTPServer.cpp:413
msgid "Local destinations" #: daemon/HTTPServer.cpp:425
msgid "Local Destinations"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:230 daemon/HTTPServer.cpp:382 #: daemon/HTTPServer.cpp:236 daemon/HTTPServer.cpp:388
#: daemon/HTTPServer.cpp:463 daemon/HTTPServer.cpp:469 #: daemon/HTTPServer.cpp:469 daemon/HTTPServer.cpp:475
#: daemon/HTTPServer.cpp:599 daemon/HTTPServer.cpp:642 #: daemon/HTTPServer.cpp:606 daemon/HTTPServer.cpp:649
#: daemon/HTTPServer.cpp:646 #: daemon/HTTPServer.cpp:653
msgid "LeaseSets" msgid "LeaseSets"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:652 #: daemon/HTTPServer.cpp:238 daemon/HTTPServer.cpp:659
msgid "Tunnels" msgid "Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:727 #: daemon/HTTPServer.cpp:239 daemon/HTTPServer.cpp:395
#: daemon/HTTPServer.cpp:743 #: daemon/HTTPServer.cpp:753 daemon/HTTPServer.cpp:769
msgid "Transit tunnels" msgid "Transit Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:234 daemon/HTTPServer.cpp:792 #: daemon/HTTPServer.cpp:240 daemon/HTTPServer.cpp:818
msgid "Transports" msgid "Transports"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:235 #: daemon/HTTPServer.cpp:241
msgid "I2P tunnels" msgid "I2P tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:237 daemon/HTTPServer.cpp:854 #: daemon/HTTPServer.cpp:243 daemon/HTTPServer.cpp:880
#: daemon/HTTPServer.cpp:864 #: daemon/HTTPServer.cpp:890
msgid "SAM sessions" msgid "SAM sessions"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:253 daemon/HTTPServer.cpp:1254 #: daemon/HTTPServer.cpp:259 daemon/HTTPServer.cpp:1280
#: daemon/HTTPServer.cpp:1257 daemon/HTTPServer.cpp:1260 #: daemon/HTTPServer.cpp:1283 daemon/HTTPServer.cpp:1286
#: daemon/HTTPServer.cpp:1274 daemon/HTTPServer.cpp:1319 #: daemon/HTTPServer.cpp:1300 daemon/HTTPServer.cpp:1345
#: daemon/HTTPServer.cpp:1322 daemon/HTTPServer.cpp:1325 #: daemon/HTTPServer.cpp:1348 daemon/HTTPServer.cpp:1351
msgid "ERROR" msgid "ERROR"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:260 #: daemon/HTTPServer.cpp:266
msgid "OK" msgid "OK"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:261 #: daemon/HTTPServer.cpp:267
msgid "Testing" msgid "Testing"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:262 #: daemon/HTTPServer.cpp:268
msgid "Firewalled" msgid "Firewalled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:263 daemon/HTTPServer.cpp:284 #: daemon/HTTPServer.cpp:269 daemon/HTTPServer.cpp:290
#: daemon/HTTPServer.cpp:370 #: daemon/HTTPServer.cpp:376
msgid "Unknown" msgid "Unknown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:264 daemon/HTTPServer.cpp:394 #: daemon/HTTPServer.cpp:270 daemon/HTTPServer.cpp:400
#: daemon/HTTPServer.cpp:395 daemon/HTTPServer.cpp:922 #: daemon/HTTPServer.cpp:401 daemon/HTTPServer.cpp:948
#: daemon/HTTPServer.cpp:931 #: daemon/HTTPServer.cpp:957
msgid "Proxy" msgid "Proxy"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:265 #: daemon/HTTPServer.cpp:271
msgid "Mesh" msgid "Mesh"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:268 #: daemon/HTTPServer.cpp:274
msgid "Error" msgid "Error"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:272 #: daemon/HTTPServer.cpp:278
msgid "Clock skew" msgid "Clock skew"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:275 #: daemon/HTTPServer.cpp:281
msgid "Offline" msgid "Offline"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:278 #: daemon/HTTPServer.cpp:284
msgid "Symmetric NAT" msgid "Symmetric NAT"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:290 #: daemon/HTTPServer.cpp:296
msgid "Uptime" msgid "Uptime"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:293 #: daemon/HTTPServer.cpp:299
msgid "Network status" msgid "Network status"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:298 #: daemon/HTTPServer.cpp:304
msgid "Network status v6" msgid "Network status v6"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:304 daemon/HTTPServer.cpp:311 #: daemon/HTTPServer.cpp:310 daemon/HTTPServer.cpp:317
msgid "Stopping in" msgid "Stopping in"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:318 #: daemon/HTTPServer.cpp:324
msgid "Family" msgid "Family"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:319 #: daemon/HTTPServer.cpp:325
msgid "Tunnel creation success rate" msgid "Tunnel creation success rate"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:320 #: daemon/HTTPServer.cpp:326
msgid "Received" msgid "Received"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:322 daemon/HTTPServer.cpp:325 #. tr: Kibibit/s
#: daemon/HTTPServer.cpp:328 #: daemon/HTTPServer.cpp:328 daemon/HTTPServer.cpp:331
#: daemon/HTTPServer.cpp:334
msgid "KiB/s" msgid "KiB/s"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:323 #: daemon/HTTPServer.cpp:329
msgid "Sent" msgid "Sent"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:326 #: daemon/HTTPServer.cpp:332
msgid "Transit" msgid "Transit"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:329 #: daemon/HTTPServer.cpp:335
msgid "Data path" msgid "Data path"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:332 #: daemon/HTTPServer.cpp:338
msgid "Hidden content. Press on text to see." msgid "Hidden content. Press on text to see."
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:335 #: daemon/HTTPServer.cpp:341
msgid "Router Ident" msgid "Router Ident"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:337 #: daemon/HTTPServer.cpp:343
msgid "Router Family" msgid "Router Family"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:338 #: daemon/HTTPServer.cpp:344
msgid "Router Caps" msgid "Router Caps"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:339 #: daemon/HTTPServer.cpp:345
msgid "Version" msgid "Version"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:340 #: daemon/HTTPServer.cpp:346
msgid "Our external address" msgid "Our external address"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:348 #: daemon/HTTPServer.cpp:354
msgid "supported" msgid "supported"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:380 #: daemon/HTTPServer.cpp:386
msgid "Routers" msgid "Routers"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:381 #: daemon/HTTPServer.cpp:387
msgid "Floodfills" msgid "Floodfills"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:388 daemon/HTTPServer.cpp:908 #: daemon/HTTPServer.cpp:394 daemon/HTTPServer.cpp:934
msgid "Client Tunnels" msgid "Client Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:389 #: daemon/HTTPServer.cpp:399
msgid "Transit Tunnels"
msgstr ""
#: daemon/HTTPServer.cpp:393
msgid "Services" msgid "Services"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:407 daemon/HTTPServer.cpp:419 #: daemon/HTTPServer.cpp:448
msgid "Local Destinations"
msgstr ""
#: daemon/HTTPServer.cpp:442
msgid "Encrypted B33 address" msgid "Encrypted B33 address"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:451 #: daemon/HTTPServer.cpp:457
msgid "Address registration line" msgid "Address registration line"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:456 #: daemon/HTTPServer.cpp:462
msgid "Domain" msgid "Domain"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:457 #: daemon/HTTPServer.cpp:463
msgid "Generate" msgid "Generate"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:458 #: daemon/HTTPServer.cpp:464
msgid "" msgid ""
"<b>Note:</b> result string can be used only for registering 2LD domains " "<b>Note:</b> result string can be used only for registering 2LD domains "
"(example.i2p). For registering subdomains please use i2pd-tools." "(example.i2p). For registering subdomains please use i2pd-tools."
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:464 #: daemon/HTTPServer.cpp:470
msgid "Address" msgid "Address"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:464 #: daemon/HTTPServer.cpp:470
msgid "Type" msgid "Type"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:464 #: daemon/HTTPServer.cpp:470
msgid "EncType" msgid "EncType"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:474 daemon/HTTPServer.cpp:657 #: daemon/HTTPServer.cpp:480 daemon/HTTPServer.cpp:664
msgid "Inbound tunnels" msgid "Inbound tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:479 daemon/HTTPServer.cpp:489 #. tr: Milliseconds
#: daemon/HTTPServer.cpp:662 daemon/HTTPServer.cpp:672 #: daemon/HTTPServer.cpp:485 daemon/HTTPServer.cpp:495
#: Means milliseconds #: daemon/HTTPServer.cpp:669 daemon/HTTPServer.cpp:679
msgid "ms" msgid "ms"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:484 daemon/HTTPServer.cpp:667 #: daemon/HTTPServer.cpp:490 daemon/HTTPServer.cpp:674
msgid "Outbound tunnels" msgid "Outbound tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:496 #: daemon/HTTPServer.cpp:502
msgid "Tags" msgid "Tags"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:496 #: daemon/HTTPServer.cpp:502
msgid "Incoming" msgid "Incoming"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:503 daemon/HTTPServer.cpp:506 #: daemon/HTTPServer.cpp:509 daemon/HTTPServer.cpp:512
msgid "Outgoing" msgid "Outgoing"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:504 daemon/HTTPServer.cpp:520 #: daemon/HTTPServer.cpp:510 daemon/HTTPServer.cpp:526
msgid "Destination" msgid "Destination"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:504 #: daemon/HTTPServer.cpp:510
msgid "Amount" msgid "Amount"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:511 #: daemon/HTTPServer.cpp:517
msgid "Incoming Tags" msgid "Incoming Tags"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:519 daemon/HTTPServer.cpp:522 #: daemon/HTTPServer.cpp:525 daemon/HTTPServer.cpp:528
msgid "Tags sessions" msgid "Tags sessions"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:520 #: daemon/HTTPServer.cpp:526
msgid "Status" msgid "Status"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:529 daemon/HTTPServer.cpp:584 #: daemon/HTTPServer.cpp:535 daemon/HTTPServer.cpp:591
msgid "Local Destination" msgid "Local Destination"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:538 daemon/HTTPServer.cpp:887 #: daemon/HTTPServer.cpp:545 daemon/HTTPServer.cpp:913
msgid "Streams" msgid "Streams"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:560 #: daemon/HTTPServer.cpp:567
msgid "Close stream" msgid "Close stream"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:589 #: daemon/HTTPServer.cpp:596
msgid "I2CP session not found" msgid "I2CP session not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:592 #: daemon/HTTPServer.cpp:599
msgid "I2CP is not enabled" msgid "I2CP is not enabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:618 #: daemon/HTTPServer.cpp:625
msgid "Invalid" msgid "Invalid"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:621 #: daemon/HTTPServer.cpp:628
msgid "Store type" msgid "Store type"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:622 #: daemon/HTTPServer.cpp:629
msgid "Expires" msgid "Expires"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:627 #: daemon/HTTPServer.cpp:634
msgid "Non Expired Leases" msgid "Non Expired Leases"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:630 #: daemon/HTTPServer.cpp:637
msgid "Gateway" msgid "Gateway"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:631 #: daemon/HTTPServer.cpp:638
msgid "TunnelID" msgid "TunnelID"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:632 #: daemon/HTTPServer.cpp:639
msgid "EndDate" msgid "EndDate"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:642 #: daemon/HTTPServer.cpp:649
msgid "not floodfill" msgid "not floodfill"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:653 #: daemon/HTTPServer.cpp:660
msgid "Queue size" msgid "Queue size"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:684 #: daemon/HTTPServer.cpp:691
msgid "Run peer test" msgid "Run peer test"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:687 #: daemon/HTTPServer.cpp:698
msgid "Decline transit tunnels" msgid "Decline transit tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:689 #: daemon/HTTPServer.cpp:700
msgid "Accept transit tunnels" msgid "Accept transit tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:692 daemon/HTTPServer.cpp:697 #: daemon/HTTPServer.cpp:704 daemon/HTTPServer.cpp:709
msgid "Cancel graceful shutdown" msgid "Cancel graceful shutdown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:694 daemon/HTTPServer.cpp:699 #: daemon/HTTPServer.cpp:706 daemon/HTTPServer.cpp:711
msgid "Start graceful shutdown" msgid "Start graceful shutdown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:701 #: daemon/HTTPServer.cpp:714
msgid "Force shutdown" msgid "Force shutdown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:704 #: daemon/HTTPServer.cpp:717
msgid "" msgid ""
"<b>Note:</b> any action done here are not persistent and not changes your " "<b>Note:</b> any action done here are not persistent and not changes your "
"config files." "config files."
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:706 #: daemon/HTTPServer.cpp:719
msgid "Logging level" msgid "Logging level"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:714 #: daemon/HTTPServer.cpp:727
msgid "Transit tunnels limit" msgid "Transit tunnels limit"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:719 #: daemon/HTTPServer.cpp:732 daemon/HTTPServer.cpp:744
msgid "Change" msgid "Change"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:743 #: daemon/HTTPServer.cpp:736
msgid "Change language"
msgstr ""
#: daemon/HTTPServer.cpp:769
msgid "no transit tunnels currently built" msgid "no transit tunnels currently built"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:848 daemon/HTTPServer.cpp:871 #: daemon/HTTPServer.cpp:874 daemon/HTTPServer.cpp:897
msgid "SAM disabled" msgid "SAM disabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:864 #: daemon/HTTPServer.cpp:890
msgid "no sessions currently running" msgid "no sessions currently running"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:877 #: daemon/HTTPServer.cpp:903
msgid "SAM session not found" msgid "SAM session not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:882 #: daemon/HTTPServer.cpp:908
msgid "SAM Session" msgid "SAM Session"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:939 #: daemon/HTTPServer.cpp:965
msgid "Server Tunnels" msgid "Server Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:955 #: daemon/HTTPServer.cpp:981
msgid "Client Forwards" msgid "Client Forwards"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:969 #: daemon/HTTPServer.cpp:995
msgid "Server Forwards" msgid "Server Forwards"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1175 #: daemon/HTTPServer.cpp:1201
msgid "Unknown page" msgid "Unknown page"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1194 #: daemon/HTTPServer.cpp:1220
msgid "Invalid token" msgid "Invalid token"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1252 daemon/HTTPServer.cpp:1309 #: daemon/HTTPServer.cpp:1278 daemon/HTTPServer.cpp:1335
#: daemon/HTTPServer.cpp:1337 #: daemon/HTTPServer.cpp:1371
msgid "SUCCESS" msgid "SUCCESS"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1252 #: daemon/HTTPServer.cpp:1278
msgid "Stream closed" msgid "Stream closed"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1254 #: daemon/HTTPServer.cpp:1280
msgid "Stream not found or already was closed" msgid "Stream not found or already was closed"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1257 #: daemon/HTTPServer.cpp:1283
msgid "Destination not found" msgid "Destination not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1260 #: daemon/HTTPServer.cpp:1286
msgid "StreamID can't be null" msgid "StreamID can't be null"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1262 daemon/HTTPServer.cpp:1327 #: daemon/HTTPServer.cpp:1288 daemon/HTTPServer.cpp:1353
msgid "Return to destination page" msgid "Return to destination page"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1263 daemon/HTTPServer.cpp:1276 #: daemon/HTTPServer.cpp:1289 daemon/HTTPServer.cpp:1302
msgid "You will be redirected back in 5 seconds" #: daemon/HTTPServer.cpp:1373
msgid "You will be redirected in 5 seconds"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1274 #: daemon/HTTPServer.cpp:1300
msgid "Transit tunnels count must not exceed 65535" msgid "Transit tunnels count must not exceed 65535"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1275 daemon/HTTPServer.cpp:1338 #: daemon/HTTPServer.cpp:1301 daemon/HTTPServer.cpp:1372
msgid "Back to commands list" msgid "Back to commands list"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1311 #: daemon/HTTPServer.cpp:1337
msgid "Register at reg.i2p" msgid "Register at reg.i2p"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1312 #: daemon/HTTPServer.cpp:1338
msgid "Description" msgid "Description"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1312 #: daemon/HTTPServer.cpp:1338
msgid "A bit information about service on domain" msgid "A bit information about service on domain"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1313 #: daemon/HTTPServer.cpp:1339
msgid "Submit" msgid "Submit"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1319 #: daemon/HTTPServer.cpp:1345
msgid "Domain can't end with .b32.i2p" msgid "Domain can't end with .b32.i2p"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1322 #: daemon/HTTPServer.cpp:1348
msgid "Domain must end with .i2p" msgid "Domain must end with .i2p"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1325 #: daemon/HTTPServer.cpp:1351
msgid "Such destination is not found" msgid "Such destination is not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1333 #: daemon/HTTPServer.cpp:1367
msgid "Unknown command" msgid "Unknown command"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1337 #: daemon/HTTPServer.cpp:1371
msgid "Command accepted" msgid "Command accepted"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1339
msgid "You will be redirected in 5 seconds"
msgstr ""
#: libi2pd_client/HTTPProxy.cpp:157 #: libi2pd_client/HTTPProxy.cpp:157
msgid "Proxy error" msgid "Proxy error"
msgstr "" msgstr ""
@ -592,7 +592,7 @@ msgid "You may try to find this host on jump services below"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:273 libi2pd_client/HTTPProxy.cpp:288 #: libi2pd_client/HTTPProxy.cpp:273 libi2pd_client/HTTPProxy.cpp:288
#: libi2pd_client/HTTPProxy.cpp:365 #: libi2pd_client/HTTPProxy.cpp:322 libi2pd_client/HTTPProxy.cpp:365
msgid "Invalid request" msgid "Invalid request"
msgstr "" msgstr ""
@ -637,10 +637,6 @@ msgstr ""
msgid "to update record" msgid "to update record"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:322
msgid "Invalid Request"
msgstr ""
#: libi2pd_client/HTTPProxy.cpp:322 #: libi2pd_client/HTTPProxy.cpp:322
msgid "invalid request uri" msgid "invalid request uri"
msgstr "" msgstr ""

3
contrib/i18n/regex.txt

@ -5,3 +5,6 @@ msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\nmsgstr\[1\]\ \"(
msgid\ \"(.*)\"\nmsgstr\ \"(.*)\"\n msgid\ \"(.*)\"\nmsgstr\ \"(.*)\"\n
{"$1", "$2"},\n {"$1", "$2"},\n
^#:(.*)$\n
<to empty line>

7
contrib/i2pd.conf

@ -15,6 +15,10 @@
## Default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d ## Default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d
# tunnelsdir = /var/lib/i2pd/tunnels.d # tunnelsdir = /var/lib/i2pd/tunnels.d
## Path to certificates used for verifying .su3, families
## Default: ~/.i2pd/certificates or /var/lib/i2pd/certificates
# certsdir = /var/lib/i2pd/certificates
## Where to write pidfile (default: i2pd.pid, not used in Windows) ## Where to write pidfile (default: i2pd.pid, not used in Windows)
# pidfile = /run/i2pd.pid # pidfile = /run/i2pd.pid
@ -104,7 +108,8 @@ port = 7070
# user = i2pd # user = i2pd
# pass = changeme # pass = changeme
## Select webconsole language ## Select webconsole language
## Currently supported english (default), russian, turkmen and ukrainian languages ## Currently supported english (default), afrikaans, russian, turkmen and ukrainian languages
# lang = english # lang = english
[httpproxy] [httpproxy]

6
daemon/Daemon.cpp

@ -94,6 +94,11 @@ namespace util
i2p::config::GetOption("daemon", isDaemon); i2p::config::GetOption("daemon", isDaemon);
std::string certsdir; i2p::config::GetOption("certsdir", certsdir);
i2p::fs::SetCertsDir(certsdir);
certsdir = i2p::fs::GetCertsDir();
std::string logs = ""; i2p::config::GetOption("log", logs); std::string logs = ""; i2p::config::GetOption("log", logs);
std::string logfile = ""; i2p::config::GetOption("logfile", logfile); std::string logfile = ""; i2p::config::GetOption("logfile", logfile);
std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel); std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);
@ -132,6 +137,7 @@ namespace util
LogPrint(eLogNone, "i2pd v", VERSION, " starting"); LogPrint(eLogNone, "i2pd v", VERSION, " starting");
LogPrint(eLogDebug, "FS: main config file: ", config); LogPrint(eLogDebug, "FS: main config file: ", config);
LogPrint(eLogDebug, "FS: data directory: ", datadir); LogPrint(eLogDebug, "FS: data directory: ", datadir);
LogPrint(eLogDebug, "FS: certificates directory: ", certsdir);
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);

108
daemon/HTTPServer.cpp

@ -68,11 +68,11 @@ namespace http {
<< " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n" << " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n"
<< " color: initial; padding: 0 5px; border: 1px solid #894C84; }\r\n" << " color: initial; padding: 0 5px; border: 1px solid #894C84; }\r\n"
<< " .header { font-size: 2.5em; text-align: center; margin: 1em 0; color: #894C84; }\r\n" << " .header { font-size: 2.5em; text-align: center; margin: 1em 0; color: #894C84; }\r\n"
<< " .wrapper { margin: 0 auto; padding: 1em; max-width: 58em; }\r\n" << " .wrapper { margin: 0 auto; padding: 1em; max-width: 64em; }\r\n"
<< " .menu { float: left; } .menu a, .commands a { display: block; }\r\n" << " .menu { display: block; float: left; overflow: hidden; max-width: 12em; white-space: nowrap; text-overflow: ellipsis; }\r\n"
<< " .listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n" << " .listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
<< " .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n" << " .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
<< " .content { float: left; font-size: 1em; margin-left: 4em; max-width: 45em; overflow: auto; }\r\n" << " .content { float: left; font-size: 1em; margin-left: 4em; max-width: 48em; overflow: auto; }\r\n"
<< " .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n" << " .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n"
<< " .tunnel.failed { color: #D33F3F; } .tunnel.building { color: #434343; }\r\n" << " .tunnel.failed { color: #D33F3F; } .tunnel.building { color: #434343; }\r\n"
<< " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" << " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
@ -84,19 +84,24 @@ namespace http {
<< " .slide [type=\"checkbox\"]:checked ~ div.slidecontent { display: block; margin-top: 0; padding: 0; }\r\n" << " .slide [type=\"checkbox\"]:checked ~ div.slidecontent { display: block; margin-top: 0; padding: 0; }\r\n"
<< " .disabled:after { color: #D33F3F; content: \"" << tr("Disabled") << "\" }\r\n" << " .disabled:after { color: #D33F3F; content: \"" << tr("Disabled") << "\" }\r\n"
<< " .enabled:after { color: #56B734; content: \"" << tr("Enabled") << "\" }\r\n" << " .enabled:after { color: #56B734; content: \"" << tr("Enabled") << "\" }\r\n"
<< " @media screen and (max-width: 980px) {\r\n" /* adaptive style */ << " @media screen and (max-width: 1150px) {\r\n" /* adaptive style */
<< " .wrapper { max-width: 58em; } .menu { max-width: 10em; }\r\n"
<< " .content { margin-left: 2em; max-width: 42em; }\r\n"
<< " }\r\n"
<< " @media screen and (max-width: 980px) {\r\n"
<< " body { padding: 1.5em 0 0 0; }\r\n" << " body { padding: 1.5em 0 0 0; }\r\n"
<< " .menu { width: 100%; display: block; float: none; position: unset; font-size: 16px;\r\n" << " .menu { width: 100%; max-width: unset; display: block; float: none; position: unset; font-size: 16px;\r\n"
<< " text-align: center; }\r\n" << " text-align: center; }\r\n"
<< " .menu a, .commands a { padding: 2px; }\r\n" << " .menu a, .commands a { display: inline-block; padding: 4px; }\r\n"
<< " .content { float: none; margin-left: unset; margin-top: 16px; max-width: 100%; width: 100%;\r\n" << " .content { float: none; margin-left: unset; margin-top: 16px; max-width: 100%; width: 100%;\r\n"
<< " text-align: center; }\r\n" << " text-align: center; }\r\n"
<< " a, .slide label { /* margin-right: 10px; */ display: block; /* font-size: 18px; */ }\r\n" << " a, .slide label { /* margin-right: 10px; */ display: block; /* font-size: 18px; */ }\r\n"
<< " .header { margin: unset; font-size: 1.5em; } small {display: block}\r\n" << " .header { margin: unset; font-size: 1.5em; } small {display: block}\r\n"
<< " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n" << " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n"
<< " color: initial; margin-top: 10px; padding: 6px; border: 1px solid #894c84; width: -webkit-fill-available; }\r\n" << " color: initial; margin-top: 10px; padding: 6px; border: 1px solid #894c84; width: -webkit-fill-available; }\r\n"
<< " input { width: 35%; text-align: center; padding: 5px;\r\n" << " input, select { width: 35%; text-align: center; padding: 5px;\r\n"
<< " border: 2px solid #ccc; -webkit-border-radius: 5px; border-radius: 5px; font-size: 18px; }\r\n" << " border: 2px solid #ccc; -webkit-border-radius: 5px; border-radius: 5px; font-size: 18px; }\r\n"
<< " table.extaddr { margin: auto; text-align: unset; }\r\n"
<< " textarea { width: -webkit-fill-available; height: auto; padding:5px; border:2px solid #ccc;\r\n" << " textarea { width: -webkit-fill-available; height: auto; padding:5px; border:2px solid #ccc;\r\n"
<< " -webkit-border-radius: 5px; border-radius: 5px; font-size: 12px; }\r\n" << " -webkit-border-radius: 5px; border-radius: 5px; font-size: 12px; }\r\n"
<< " button[type=submit] { padding: 5px 15px; background: #ccc; border: 0 none; cursor: pointer;\r\n" << " button[type=submit] { padding: 5px 15px; background: #ccc; border: 0 none; cursor: pointer;\r\n"
@ -127,6 +132,7 @@ namespace http {
const char HTTP_COMMAND_KILLSTREAM[] = "closestream"; const char HTTP_COMMAND_KILLSTREAM[] = "closestream";
const char HTTP_COMMAND_LIMITTRANSIT[] = "limittransit"; const char HTTP_COMMAND_LIMITTRANSIT[] = "limittransit";
const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string"; const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string";
const char HTTP_COMMAND_SETLANGUAGE[] = "setlanguage";
const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
const char HTTP_PARAM_ADDRESS[] = "address"; const char HTTP_PARAM_ADDRESS[] = "address";
@ -157,11 +163,11 @@ namespace http {
s << std::fixed << std::setprecision(2); s << std::fixed << std::setprecision(2);
auto numKBytes = (double) bytes / 1024; auto numKBytes = (double) bytes / 1024;
if (numKBytes < 1024) if (numKBytes < 1024)
s << numKBytes << " " << tr("KiB"); s << numKBytes << " " << tr(/* tr: Kibibit */ "KiB");
else if (numKBytes < 1024 * 1024) else if (numKBytes < 1024 * 1024)
s << numKBytes / 1024 << " " << tr("MiB"); s << numKBytes / 1024 << " " << tr(/* tr: Mebibit */ "MiB");
else else
s << numKBytes / 1024 / 1024 << " " << tr("GiB"); s << numKBytes / 1024 / 1024 << " " << tr(/* tr: Gibibit */ "GiB");
} }
static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes) static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes)
@ -185,7 +191,7 @@ namespace http {
else stateText = tr("unknown"); else stateText = tr("unknown");
s << "<span class=\"tunnel " << state << "\"> " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << "</span>, "; s << "<span class=\"tunnel " << state << "\"> " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << "</span>, ";
s << " " << (int) (bytes / 1024) << "&nbsp;" << tr("KiB") << "\r\n"; s << " " << (int) (bytes / 1024) << "&nbsp;" << tr(/* tr: Kibibit */ "KiB") << "\r\n";
} }
static void SetLogLevel (const std::string& level) static void SetLogLevel (const std::string& level)
@ -223,18 +229,18 @@ namespace http {
"<div class=\"header\">" << tr("<b>i2pd</b> webconsole") << "</div>\r\n" "<div class=\"header\">" << tr("<b>i2pd</b> webconsole") << "</div>\r\n"
"<div class=\"wrapper\">\r\n" "<div class=\"wrapper\">\r\n"
"<div class=\"menu\">\r\n" "<div class=\"menu\">\r\n"
" <a href=\"" << webroot << "\">" << tr("Main page") << "</a><br>\r\n" " <a href=\"" << webroot << "\">" << tr("Main page") << "</a><br><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_COMMANDS << "\">" << tr("Router commands") << "</a>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_COMMANDS << "\">" << tr("Router commands") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">" << tr("Local destinations") << "</a>\r\n"; " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">" << tr("Local Destinations") << "</a><br>\r\n";
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">" << tr("LeaseSets") << "</a>\r\n"; s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">" << tr("LeaseSets") << "</a><br>\r\n";
s << s <<
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">" << tr("Tunnels") << "</a>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">" << tr("Tunnels") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">" << tr("Transit tunnels") << "</a>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">" << tr("Transit Tunnels") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a>\r\n"; " <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a><br>\r\n";
if (i2p::client::context.GetSAMBridge ()) if (i2p::client::context.GetSAMBridge ())
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">" << tr("SAM sessions") << "</a>\r\n"; s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">" << tr("SAM sessions") << "</a><br>\r\n";
s << s <<
"</div>\r\n" "</div>\r\n"
"<div class=\"content\">"; "<div class=\"content\">";
@ -319,13 +325,13 @@ namespace http {
s << "<b>" << tr("Tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n"; s << "<b>" << tr("Tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n";
s << "<b>" << tr("Received") << ":</b> "; s << "<b>" << tr("Received") << ":</b> ";
ShowTraffic (s, i2p::transport::transports.GetTotalReceivedBytes ()); ShowTraffic (s, i2p::transport::transports.GetTotalReceivedBytes ());
s << " (" << (double) i2p::transport::transports.GetInBandwidth () / 1024 << " " << tr("KiB/s") << ")<br>\r\n"; s << " (" << (double) i2p::transport::transports.GetInBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
s << "<b>" << tr("Sent") << ":</b> "; s << "<b>" << tr("Sent") << ":</b> ";
ShowTraffic (s, i2p::transport::transports.GetTotalSentBytes ()); ShowTraffic (s, i2p::transport::transports.GetTotalSentBytes ());
s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " " << tr("KiB/s") << ")<br>\r\n"; s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
s << "<b>" << tr("Transit") << ":</b> "; s << "<b>" << tr("Transit") << ":</b> ";
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ()); ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " " << tr("KiB/s") << ")<br>\r\n"; s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
s << "<b>" << tr("Data path") << ":</b> " << i2p::fs::GetUTF8DataDir() << "<br>\r\n"; s << "<b>" << tr("Data path") << ":</b> " << i2p::fs::GetUTF8DataDir() << "<br>\r\n";
s << "<div class='slide'>"; s << "<div class='slide'>";
if((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) { if((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) {
@ -476,7 +482,7 @@ namespace http {
s << "<div class=\"listitem\">"; s << "<div class=\"listitem\">";
it->Print(s); it->Print(s);
if(it->LatencyIsKnown()) if(it->LatencyIsKnown())
s << " ( " << it->GetMeanLatency() << tr("ms") << " )"; s << " ( " << it->GetMeanLatency() << tr(/* tr: Milliseconds */ "ms") << " )";
ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ()); ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ());
s << "</div>\r\n"; s << "</div>\r\n";
} }
@ -534,7 +540,8 @@ namespace http {
if (dest) if (dest)
{ {
ShowLeaseSetDestination (s, dest, token); ShowLeaseSetDestination (s, dest, token);
// show streams
// Print table with streams information
s << "<table>\r\n<caption>" << tr("Streams") << "</caption>\r\n<thead>\r\n<tr>"; s << "<table>\r\n<caption>" << tr("Streams") << "</caption>\r\n<thead>\r\n<tr>";
s << "<th style=\"width:25px;\">StreamID</th>"; s << "<th style=\"width:25px;\">StreamID</th>";
s << "<th style=\"width:5px;\" \\>"; // Stream closing button column s << "<th style=\"width:5px;\" \\>"; // Stream closing button column
@ -679,25 +686,29 @@ namespace http {
static void ShowCommands (std::stringstream& s, uint32_t token) static void ShowCommands (std::stringstream& s, uint32_t token)
{ {
std::string webroot; i2p::config::GetOption("http.webroot", webroot); std::string webroot; i2p::config::GetOption("http.webroot", webroot);
/* commands */
s << "<b>" << tr("Router commands") << "</b><br>\r\n<br>\r\n<div class=\"commands\">\r\n"; s << "<b>" << tr("Router commands") << "</b><br>\r\n<br>\r\n<div class=\"commands\">\r\n";
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">" << tr("Run peer test") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">" << tr("Run peer test") << "</a><br>\r\n";
// s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n"; // s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
if (i2p::context.AcceptsTunnels ()) if (i2p::context.AcceptsTunnels ())
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">" << tr("Decline transit tunnels") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">" << tr("Decline transit tunnels") << "</a><br>\r\n";
else else
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">" << tr("Accept transit tunnels") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">" << tr("Accept transit tunnels") << "</a><br>\r\n";
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
if (Daemon.gracefulShutdownInterval) if (Daemon.gracefulShutdownInterval)
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">" << tr("Cancel graceful shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">" << tr("Cancel graceful shutdown") << "</a><br>\r\n";
else else
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">" << tr("Start graceful shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">" << tr("Start graceful shutdown") << "</a><br>\r\n";
#elif defined(WIN32_APP) #elif defined(WIN32_APP)
if (i2p::util::DaemonWin32::Instance().isGraceful) if (i2p::util::DaemonWin32::Instance().isGraceful)
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">" << tr("Cancel graceful shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">" << tr("Cancel graceful shutdown") << "</a><br>\r\n";
else else
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">" << tr("Start graceful shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">" << tr("Start graceful shutdown") << "</a><br>\r\n";
#endif #endif
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">" << tr("Force shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">" << tr("Force shutdown") << "</a>\r\n";
s << "</div>"; s << "</div>";
@ -718,13 +729,26 @@ namespace http {
s << " <input type=\"number\" min=\"0\" max=\"65535\" name=\"limit\" value=\"" << maxTunnels << "\">\r\n"; s << " <input type=\"number\" min=\"0\" max=\"65535\" name=\"limit\" value=\"" << maxTunnels << "\">\r\n";
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n"; s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
s << "</form>\r\n<br>\r\n"; s << "</form>\r\n<br>\r\n";
std::string currLang = i2p::context.GetLanguage ()->GetLanguage(); // get current used language
s << "<b>" << tr("Change language") << "</b><br>\r\n";
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_SETLANGUAGE << "\">\r\n";
s << " <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n";
s << " <select name=\"lang\" id=\"lang\">\r\n";
for (const auto& it: i2p::i18n::languages)
s << " <option value=\"" << it.first << "\"" << ((it.first.compare(currLang) == 0) ? " selected" : "") << ">" << it.second.LocaleName << "</option>\r\n";
s << " </select>\r\n";
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
s << "</form>\r\n<br>\r\n";
} }
void ShowTransitTunnels (std::stringstream& s) void ShowTransitTunnels (std::stringstream& s)
{ {
if(i2p::tunnel::tunnels.CountTransitTunnels()) if(i2p::tunnel::tunnels.CountTransitTunnels())
{ {
s << "<b>" << tr("Transit tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n"; s << "<b>" << tr("Transit Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
{ {
s << "<div class=\"listitem\">\r\n"; s << "<div class=\"listitem\">\r\n";
@ -740,7 +764,7 @@ namespace http {
} }
else else
{ {
s << "<b>" << tr("Transit tunnels") << ":</b> " << tr("no transit tunnels currently built") << ".<br>\r\n"; s << "<b>" << tr("Transit Tunnels") << ":</b> " << tr("no transit tunnels currently built") << ".<br>\r\n";
} }
} }
@ -1260,7 +1284,7 @@ namespace http {
s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("StreamID can't be null") << "<br>\r\n<br>\r\n"; s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("StreamID can't be null") << "<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 << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a><br>\r\n";
s << "<p>" << tr("You will be redirected back in 5 seconds") << "</b>"; s << "<p>" << tr("You will be redirected in 5 seconds") << "</b>";
redirect = "5; url=" + webroot + "?page=local_destination&b32=" + b32; redirect = "5; url=" + webroot + "?page=local_destination&b32=" + b32;
res.add_header("Refresh", redirect.c_str()); res.add_header("Refresh", redirect.c_str());
return; return;
@ -1273,7 +1297,7 @@ namespace http {
else { else {
s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("Transit tunnels count must not exceed 65535") << "\r\n<br>\r\n<br>\r\n"; s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("Transit tunnels count must not exceed 65535") << "\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"; s << "<a href=\"" << webroot << "?page=commands\">" << tr("Back to commands list") << "</a>\r\n<br>\r\n";
s << "<p>" << tr("You will be redirected back in 5 seconds") << "</b>"; s << "<p>" << tr("You will be redirected in 5 seconds") << "</b>";
res.add_header("Refresh", redirect.c_str()); res.add_header("Refresh", redirect.c_str());
return; return;
} }
@ -1281,7 +1305,7 @@ namespace http {
else if (cmd == HTTP_COMMAND_GET_REG_STRING) else if (cmd == HTTP_COMMAND_GET_REG_STRING)
{ {
std::string b32 = params["b32"]; std::string b32 = params["b32"];
std::string name = params["name"]; std::string name = i2p::http::UrlDecode(params["name"]);
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
ident.FromBase32 (b32); ident.FromBase32 (b32);
@ -1327,6 +1351,14 @@ namespace http {
s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a>\r\n"; s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a>\r\n";
return; return;
} }
else if (cmd == HTTP_COMMAND_SETLANGUAGE)
{
std::string lang = params["lang"];
std::string currLang = i2p::context.GetLanguage ()->GetLanguage();
if (currLang.compare(lang) != 0)
i2p::i18n::SetLanguage(lang);
}
else else
{ {
res.code = 400; res.code = 400;

2
daemon/I2PControl.cpp

@ -406,7 +406,7 @@ namespace client
void I2PControlService::UptimeHandler (std::ostringstream& results) void I2PControlService::UptimeHandler (std::ostringstream& results)
{ {
InsertParam (results, "i2p.router.uptime", (int)i2p::context.GetUptime ()*1000); InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL));
} }
void I2PControlService::VersionHandler (std::ostringstream& results) void I2PControlService::VersionHandler (std::ostringstream& results)

7
i18n/Afrikaans.cpp

@ -18,8 +18,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace afrikaans // language namespace afrikaans // language namespace
{ {
// language name in lowercase
static std::string language = "afrikaans";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -65,7 +68,7 @@ namespace afrikaans // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language

7
i18n/English.cpp

@ -19,8 +19,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace english // language namespace english // language namespace
{ {
// language name in lowercase
static std::string language = "english";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -39,7 +42,7 @@ namespace english // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language

13
i18n/I18N.h

@ -17,16 +17,11 @@ namespace i18n
{ {
inline void SetLanguage(const std::string &lang) inline void SetLanguage(const std::string &lang)
{ {
if (!lang.compare("afrikaans")) const auto it = i2p::i18n::languages.find(lang);
i2p::context.SetLanguage (i2p::i18n::afrikaans::GetLocale()); if (it == i2p::i18n::languages.end()) // fallback
else if (!lang.compare("russian"))
i2p::context.SetLanguage (i2p::i18n::russian::GetLocale());
else if (!lang.compare("turkmen"))
i2p::context.SetLanguage (i2p::i18n::turkmen::GetLocale());
else if (!lang.compare("ukrainian"))
i2p::context.SetLanguage (i2p::i18n::ukrainian::GetLocale());
else // fallback
i2p::context.SetLanguage (i2p::i18n::english::GetLocale()); i2p::context.SetLanguage (i2p::i18n::english::GetLocale());
else
i2p::context.SetLanguage (it->second.LocaleFunc());
} }
inline std::string translate (const std::string& arg) inline std::string translate (const std::string& arg)

28
i18n/I18N_langs.h

@ -17,10 +17,17 @@ namespace i18n
{ {
public: public:
Locale ( Locale (
const std::string& language,
const std::map<std::string, std::string>& strings, const std::map<std::string, std::string>& strings,
const std::map<std::string, std::vector<std::string>>& plurals, const std::map<std::string, std::vector<std::string>>& plurals,
std::function<int(int)> formula std::function<int(int)> formula
): m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { }; ): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { };
// Get activated language name for webconsole
std::string GetLanguage() const
{
return m_Language;
}
std::string GetString (const std::string& arg) const std::string GetString (const std::string& arg) const
{ {
@ -50,11 +57,18 @@ namespace i18n
} }
private: private:
const std::string m_Language;
const std::map<std::string, std::string> m_Strings; const std::map<std::string, std::string> m_Strings;
const std::map<std::string, std::vector<std::string>> m_Plurals; const std::map<std::string, std::vector<std::string>> m_Plurals;
std::function<int(int)> m_Formula; std::function<int(int)> m_Formula;
}; };
struct langData
{
std::string LocaleName; //localized name
std::function<std::shared_ptr<const i2p::i18n::Locale> (void)> LocaleFunc;
};
// Add localization here with language name as namespace // Add localization here with language name as namespace
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
@ -62,6 +76,18 @@ namespace i18n
namespace turkmen { 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 ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
/**
* That map contains international language name lower-case and name in it's language
*/
static std::map<std::string, langData> languages
{
{ "afrikaans", {"Afrikaans", i2p::i18n::afrikaans::GetLocale} },
{ "english", {"English", i2p::i18n::english::GetLocale} },
{ "russian", {"русский язык", i2p::i18n::russian::GetLocale} },
{ "turkmen", {"türkmen dili", i2p::i18n::turkmen::GetLocale} },
{ "ukrainian", {"украї́нська мо́ва", i2p::i18n::ukrainian::GetLocale} },
};
} // i18n } // i18n
} // i2p } // i2p

136
i18n/Russian.cpp

@ -18,8 +18,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace russian // language namespace russian // language namespace
{ {
// language name in lowercase
static std::string language = "russian";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -28,72 +31,28 @@ namespace russian // language
static std::map<std::string, std::string> strings static std::map<std::string, std::string> strings
{ {
// HTTP Proxy
{"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", "Вы можете попробовать найти адрес на джамп сервисах ниже"},
{"Invalid request", "Некорректный запрос"},
{"Proxy unable to parse your request", "Прокси не может разобрать ваш запрос"},
{"addresshelper is not supported", "addresshelper не поддерживается"},
{"Host", "Адрес"},
{"added to router's addressbook from helper", "добавлен в адресную книгу роутера через хелпер"},
{"already in router's addressbook", "уже в адресной книге роутера"},
{"Click", "Нажмите"},
{"here", "здесь"},
{"to proceed", "чтобы продолжить"},
{"to update record", "чтобы обновить запись"},
{"Addresshelper found", "Найден addresshelper"},
{"invalid request uri", "некорректный URI запроса"},
{"Can't detect destination host from request", "Не удалось определить адрес назначения из запроса"},
{"Outproxy failure", "Ошибка внешнего прокси"},
{"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 прокси серверу"},
{"Host is down", "Адрес недоступен"},
{"Can't create connection to requested host, it may be down. Please try again later.",
"Не удалось установить соединение к запрошенному адресу, возможно он не в сети. Попробуйте повторить запрос позже."},
// Webconsole //
// cssStyles
{"Disabled", "Выключено"}, {"Disabled", "Выключено"},
{"Enabled", "Включено"}, {"Enabled", "Включено"},
// ShowTraffic
{"KiB", "КиБ"}, {"KiB", "КиБ"},
{"MiB", "МиБ"}, {"MiB", "МиБ"},
{"GiB", "ГиБ"}, {"GiB", "ГиБ"},
// ShowTunnelDetails
{"building", "строится"}, {"building", "строится"},
{"failed", "неудачный"}, {"failed", "неудачный"},
{"expiring", "истекает"}, {"expiring", "истекает"},
{"established", "работает"}, {"established", "работает"},
{"exploratory", "исследовательский"},
{"unknown", "неизвестно"}, {"unknown", "неизвестно"},
{"exploratory", "исследовательский"},
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"}, {"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
// ShowPageHead
{"Main page", "Главная"}, {"Main page", "Главная"},
{"Router commands", "Команды роутера"}, {"Router commands", "Команды роутера"},
{"Local destinations", "Локальные назнач."}, {"Local destinations", "Локальные назначения"},
{"LeaseSets", "Лизсеты"}, {"LeaseSets", "Лизсеты"},
{"Tunnels", "Туннели"}, {"Tunnels", "Туннели"},
{"Transit tunnels", "Транзит. туннели"}, {"Transit tunnels", "Транзитные туннели"},
{"Transports", "Транспорты"}, {"Transports", "Транспорты"},
{"I2P tunnels", "I2P туннели"}, {"I2P tunnels", "I2P туннели"},
{"SAM sessions", "SAM сессии"}, {"SAM sessions", "SAM сессии"},
// Network Status {"ERROR", "ОШИБКА"},
{"OK", "OK"}, {"OK", "OK"},
{"Testing", "Тестирование"}, {"Testing", "Тестирование"},
{"Firewalled", "Заблокировано извне"}, {"Firewalled", "Заблокировано извне"},
@ -104,7 +63,6 @@ namespace russian // language
{"Clock skew", "Не точное время"}, {"Clock skew", "Не точное время"},
{"Offline", "Оффлайн"}, {"Offline", "Оффлайн"},
{"Symmetric NAT", "Симметричный NAT"}, {"Symmetric NAT", "Симметричный NAT"},
// Status
{"Uptime", "В сети"}, {"Uptime", "В сети"},
{"Network status", "Сетевой статус"}, {"Network status", "Сетевой статус"},
{"Network status v6", "Сетевой статус v6"}, {"Network status v6", "Сетевой статус v6"},
@ -112,9 +70,9 @@ namespace russian // language
{"Family", "Семейство"}, {"Family", "Семейство"},
{"Tunnel creation success rate", "Успешно построенных туннелей"}, {"Tunnel creation success rate", "Успешно построенных туннелей"},
{"Received", "Получено"}, {"Received", "Получено"},
{"KiB/s", "КиБ/с"},
{"Sent", "Отправлено"}, {"Sent", "Отправлено"},
{"Transit", "Транзит"}, {"Transit", "Транзит"},
{"KiB/s", "КиБ/с"},
{"Data path", "Путь к данным"}, {"Data path", "Путь к данным"},
{"Hidden content. Press on text to see.", "Скрытый контент. Нажмите на текст чтобы отобразить."}, {"Hidden content. Press on text to see.", "Скрытый контент. Нажмите на текст чтобы отобразить."},
{"Router Ident", "Идентификатор роутера"}, {"Router Ident", "Идентификатор роутера"},
@ -125,25 +83,21 @@ namespace russian // language
{"supported", "поддерживается"}, {"supported", "поддерживается"},
{"Routers", "Роутеры"}, {"Routers", "Роутеры"},
{"Floodfills", "Флудфилы"}, {"Floodfills", "Флудфилы"},
{"LeaseSets", "Лизсеты"},
{"Client Tunnels", "Клиентские туннели"}, {"Client Tunnels", "Клиентские туннели"},
{"Transit Tunnels", "Транзитные туннели"}, {"Transit Tunnels", "Транзитные туннели"},
{"Services", "Сервисы"}, {"Services", "Сервисы"},
// ShowLocalDestinations
{"Local Destinations", "Локальные назначения"}, {"Local Destinations", "Локальные назначения"},
// ShowLeaseSetDestination
{"Encrypted B33 address", "Шифрованные B33 адреса"}, {"Encrypted B33 address", "Шифрованные B33 адреса"},
{"Address registration line", "Строка регистрации адреса"}, {"Address registration line", "Строка регистрации адреса"},
{"Domain", "Домен"}, {"Domain", "Домен"},
{"Generate", "Сгенерировать"}, {"Generate", "Сгенерировать"},
{"<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> 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>Примечание:</b> полученная строка может быть использована только для регистрации доменов второго уровня. Для регистрации поддоменов используйте i2pd-tools."},
{"Address", "Адрес"}, {"Address", "Адрес"},
{"Type", "Тип"}, {"Type", "Тип"},
{"EncType", "ТипШифр"}, {"EncType", "ТипШифр"},
{"Inbound tunnels", "Входящие туннели"}, {"Inbound tunnels", "Входящие туннели"},
{"ms", "мс"},
{"Outbound tunnels", "Исходящие туннели"}, {"Outbound tunnels", "Исходящие туннели"},
{"ms", "мс"}, // milliseconds
{"Tags", "Теги"}, {"Tags", "Теги"},
{"Incoming", "Входящие"}, {"Incoming", "Входящие"},
{"Outgoing", "Исходящие"}, {"Outgoing", "Исходящие"},
@ -152,14 +106,11 @@ namespace russian // language
{"Incoming Tags", "Входящие Теги"}, {"Incoming Tags", "Входящие Теги"},
{"Tags sessions", "Сессии Тегов"}, {"Tags sessions", "Сессии Тегов"},
{"Status", "Статус"}, {"Status", "Статус"},
// ShowLocalDestination
{"Local Destination", "Локальное назначение"}, {"Local Destination", "Локальное назначение"},
{"Streams", "Стримы"}, {"Streams", "Стримы"},
{"Close stream", "Закрыть стрим"}, {"Close stream", "Закрыть стрим"},
// ShowI2CPLocalDestination
{"I2CP session not found", "I2CP сессия не найдена"}, {"I2CP session not found", "I2CP сессия не найдена"},
{"I2CP is not enabled", "I2CP не включен"}, {"I2CP is not enabled", "I2CP не включен"},
// ShowLeasesSets
{"Invalid", "Некорректный"}, {"Invalid", "Некорректный"},
{"Store type", "Тип хранилища"}, {"Store type", "Тип хранилища"},
{"Expires", "Истекает"}, {"Expires", "Истекает"},
@ -168,51 +119,37 @@ namespace russian // language
{"TunnelID", "ID туннеля"}, {"TunnelID", "ID туннеля"},
{"EndDate", "Заканчивается"}, {"EndDate", "Заканчивается"},
{"not floodfill", "не флудфил"}, {"not floodfill", "не флудфил"},
// ShowTunnels
{"Queue size", "Размер очереди"}, {"Queue size", "Размер очереди"},
// ShowCommands
{"Run peer test", "Запустить тестирование"}, {"Run peer test", "Запустить тестирование"},
{"Decline transit tunnels", "Отклонять транзитные туннели"}, {"Decline transit tunnels", "Отклонять транзитные туннели"},
{"Accept transit tunnels", "Принимать транзитные туннели"}, {"Accept transit tunnels", "Принимать транзитные туннели"},
{"Cancel graceful shutdown", "Отменить плавную остановку"}, {"Cancel graceful shutdown", "Отменить плавную остановку"},
{"Start graceful shutdown", "Запустить плавную остановку"}, {"Start graceful shutdown", "Запустить плавную остановку"},
{"Force shutdown", "Принудительная остановка"}, {"Force shutdown", "Принудительная остановка"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Примечание:</b> любое действие произведенное здесь не является постоянным и не изменяет ваши конфигурационные файлы."},
"<b>Примечание:</b> любое действие произведенное здесь не является постоянным и не изменяет ваши конфигурационные файлы."},
{"Logging level", "Уровень логирования"}, {"Logging level", "Уровень логирования"},
{"Transit tunnels limit", "Лимит транзитных туннелей"}, {"Transit tunnels limit", "Лимит транзитных туннелей"},
{"Change", "Изменить"}, {"Change", "Изменить"},
// ShowTransitTunnels {"Change language", "Изменение языка"},
{"no transit tunnels currently built", "нет построенных транзитных туннелей"}, {"no transit tunnels currently built", "нет построенных транзитных туннелей"},
// ShowSAMSessions/ShowSAMSession
{"SAM disabled", "SAM выключен"}, {"SAM disabled", "SAM выключен"},
{"SAM session not found", "SAM сессия не найдена"},
{"no sessions currently running", "нет запущенных сессий"}, {"no sessions currently running", "нет запущенных сессий"},
{"SAM session not found", "SAM сессия не найдена"},
{"SAM Session", "SAM сессия"}, {"SAM Session", "SAM сессия"},
// ShowI2PTunnels
{"Server Tunnels", "Серверные туннели"}, {"Server Tunnels", "Серверные туннели"},
{"Client Forwards", "Клиентские перенаправления"}, {"Client Forwards", "Клиентские перенаправления"},
{"Server Forwards", "Серверные перенаправления"}, {"Server Forwards", "Серверные перенаправления"},
// HandlePage
{"Unknown page", "Неизвестная страница"}, {"Unknown page", "Неизвестная страница"},
// HandleCommand, ShowError
{"Invalid token", "Неверный токен"}, {"Invalid token", "Неверный токен"},
{"SUCCESS", "УСПЕШНО"}, {"SUCCESS", "УСПЕШНО"},
{"ERROR", "ОШИБКА"},
{"Unknown command", "Неизвестная команда"},
{"Command accepted", "Команда принята"},
{"Back to commands list", "Вернуться к списку команд"},
{"You will be redirected in 5 seconds", "Вы будете переадресованы через 5 секунд"},
// HTTP_COMMAND_KILLSTREAM
{"Stream closed", "Стрим закрыт"}, {"Stream closed", "Стрим закрыт"},
{"Stream not found or already was closed", "Стрим не найден или уже закрыт"}, {"Stream not found or already was closed", "Стрим не найден или уже закрыт"},
{"Destination not found", "Точка назначения не найдена"}, {"Destination not found", "Точка назначения не найдена"},
{"StreamID can't be null", "StreamID не может быть пустым"}, {"StreamID can't be null", "StreamID не может быть пустым"},
{"Return to destination page", "Вернуться на страницу точки назначения"}, {"Return to destination page", "Вернуться на страницу точки назначения"},
{"You will be redirected back in 5 seconds", "Вы будете переадресованы назад через 5 секунд"}, {"You will be redirected back in 5 seconds", "Вы будете переадресованы назад через 5 секунд"},
// HTTP_COMMAND_LIMITTRANSIT
{"Transit tunnels count must not exceed 65535", "Число транзитных туннелей не должно превышать 65535"}, {"Transit tunnels count must not exceed 65535", "Число транзитных туннелей не должно превышать 65535"},
// HTTP_COMMAND_GET_REG_STRING {"Back to commands list", "Вернуться к списку команд"},
{"Register at reg.i2p", "Зарегистрировать на reg.i2p"}, {"Register at reg.i2p", "Зарегистрировать на reg.i2p"},
{"Description", "Описание"}, {"Description", "Описание"},
{"A bit information about service on domain", "Немного информации о сервисе на домене"}, {"A bit information about service on domain", "Немного информации о сервисе на домене"},
@ -220,12 +157,51 @@ namespace russian // language
{"Domain can't end with .b32.i2p", "Домен не может заканчиваться на .b32.i2p"}, {"Domain can't end with .b32.i2p", "Домен не может заканчиваться на .b32.i2p"},
{"Domain must end with .i2p", "Домен должен заканчиваться на .i2p"}, {"Domain must end with .i2p", "Домен должен заканчиваться на .i2p"},
{"Such destination is not found", "Такая точка назначения не найдена"}, {"Such destination is not found", "Такая точка назначения не найдена"},
{"Unknown command", "Неизвестная команда"},
{"Command accepted", "Команда принята"},
{"You will be redirected in 5 seconds", "Вы будете переадресованы через 5 секунд"},
{"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", "Вы можете попробовать найти узел через джамп сервисы ниже"},
{"Invalid request", "Некорректный запрос"},
{"Proxy unable to parse your request", "Прокси не может разобрать ваш запрос"},
{"addresshelper is not supported", "addresshelper не поддерживается"},
{"Host", "Узел"},
{"added to router's addressbook from helper", "добавлен в адресную книгу роутера через хелпер"},
{"Click", "Нажмите"},
{"here", "здесь"},
{"to proceed", "чтобы продолжить"},
{"Addresshelper found", "Найден addresshelper"},
{"already in router's addressbook", "уже в адресной книге роутера"},
{"to update record", "чтобы обновить запись"},
{"Invalid Request", "неверный запрос"},
{"invalid request uri", "некорректный URI запроса"},
{"Can't detect destination host from request", "Не удалось определить адрес назначения из запроса"},
{"Outproxy failure", "Ошибка внешнего прокси"},
{"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 прокси серверу"},
{"Host is down", "Узел недоступен"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Не удалось установить соединение к запрошенному узлу, возможно он не в сети. Попробуйте повторить запрос позже."},
{"", ""}, {"", ""},
}; };
static std::map<std::string, std::vector<std::string>> plurals static std::map<std::string, std::vector<std::string>> plurals
{ {
// ShowUptime
{"days", {"день", "дня", "дней"}}, {"days", {"день", "дня", "дней"}},
{"hours", {"час", "часа", "часов"}}, {"hours", {"час", "часа", "часов"}},
{"minutes", {"минуту", "минуты", "минут"}}, {"minutes", {"минуту", "минуты", "минут"}},
@ -235,7 +211,7 @@ namespace russian // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language

7
i18n/Turkmen.cpp

@ -18,8 +18,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace turkmen // language namespace turkmen // language namespace
{ {
// language name in lowercase
static std::string language = "turkmen";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -234,7 +237,7 @@ namespace turkmen // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language

146
i18n/Ukrainian.cpp

@ -18,8 +18,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace ukrainian // language namespace ukrainian // language namespace
{ {
// language name in lowercase
static std::string language = "ukrainian";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -28,64 +31,20 @@ namespace ukrainian // language
static std::map<std::string, std::string> strings static std::map<std::string, std::string> strings
{ {
// HTTP Proxy
{"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", "Ви можете спробувати знайти дану адресу на джамп сервісах нижче"},
{"Invalid request", "Некоректний запит"},
{"Proxy unable to parse your request", "Проксі не може розібрати ваш запит"},
{"addresshelper is not supported", "addresshelper не підтримується"},
{"Host", "Адреса"},
{"added to router's addressbook from helper", "доданий в адресну книгу роутера через хелпер"},
{"already in router's addressbook", "вже в адресній книзі роутера"},
{"Click", "Натисніть"},
{"here", "тут"},
{"to proceed", "щоб продовжити"},
{"to update record", "щоб оновити запис"},
{"Addresshelper found", "Знайдено addresshelper"},
{"invalid request uri", "некоректний URI запиту"},
{"Can't detect destination host from request", "Не вдалось визначити адресу призначення з запиту"},
{"Outproxy failure", "Помилка зовнішнього проксі"},
{"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 проксі сервера"},
{"Host is down", "Вузол недоступний"},
{"Can't create connection to requested host, it may be down. Please try again later.",
"Не вдалося встановити з'єднання до запитаного вузла, можливо він не в мережі. Спробуйте повторити запит пізніше."},
// Webconsole //
// cssStyles
{"Disabled", "Вимкнуто"}, {"Disabled", "Вимкнуто"},
{"Enabled", "Увімкнуто"}, {"Enabled", "Увімкнуто"},
// ShowTraffic
{"KiB", "КіБ"}, {"KiB", "КіБ"},
{"MiB", "МіБ"}, {"MiB", "МіБ"},
{"GiB", "ГіБ"}, {"GiB", "ГіБ"},
// ShowTunnelDetails
{"building", "будується"}, {"building", "будується"},
{"failed", "невдалий"}, {"failed", "невдалий"},
{"expiring", "завершується"}, {"expiring", "завершується"},
{"established", "працює"}, {"established", "працює"},
{"exploratory", "дослідницький"},
{"unknown", "невідомо"}, {"unknown", "невідомо"},
{"exploratory", "дослідницький"},
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"}, {"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
// ShowPageHead
{"Main page", "Головна"}, {"Main page", "Головна"},
{"Router commands", "Команди роутера"}, {"Router commands", "Команди маршрутизатора"},
{"Local destinations", "Локальні призначення"}, {"Local destinations", "Локальні призначення"},
{"LeaseSets", "Лізсети"}, {"LeaseSets", "Лізсети"},
{"Tunnels", "Тунелі"}, {"Tunnels", "Тунелі"},
@ -93,7 +52,7 @@ namespace ukrainian // language
{"Transports", "Транспорти"}, {"Transports", "Транспорти"},
{"I2P tunnels", "I2P тунелі"}, {"I2P tunnels", "I2P тунелі"},
{"SAM sessions", "SAM сесії"}, {"SAM sessions", "SAM сесії"},
// Network Status {"ERROR", "ПОМИЛКА"},
{"OK", "OK"}, {"OK", "OK"},
{"Testing", "Тестування"}, {"Testing", "Тестування"},
{"Firewalled", "Заблоковано ззовні"}, {"Firewalled", "Заблоковано ззовні"},
@ -104,61 +63,54 @@ namespace ukrainian // language
{"Clock skew", "Неточний час"}, {"Clock skew", "Неточний час"},
{"Offline", "Офлайн"}, {"Offline", "Офлайн"},
{"Symmetric NAT", "Симетричний NAT"}, {"Symmetric NAT", "Симетричний NAT"},
// Status {"Uptime", "У мережі"},
{"Uptime", "В мережі"},
{"Network status", "Мережевий статус"}, {"Network status", "Мережевий статус"},
{"Network status v6", "Мережевий статус v6"}, {"Network status v6", "Мережевий статус v6"},
{"Stopping in", "Зупинка через"}, {"Stopping in", "Зупинка через"},
{"Family", "Сімейство"}, {"Family", "Сімейство"},
{"Tunnel creation success rate", "Успішно побудованих тунелів"}, {"Tunnel creation success rate", "Успішно побудованих тунелів"},
{"Received", "Отримано"}, {"Received", "Отримано"},
{"KiB/s", "КіБ/с"},
{"Sent", "Відправлено"}, {"Sent", "Відправлено"},
{"Transit", "Транзит"}, {"Transit", "Транзит"},
{"KiB/s", "КіБ/с"},
{"Data path", "Шлях до даних"}, {"Data path", "Шлях до даних"},
{"Hidden content. Press on text to see.", "Прихований вміст. Натисніть на текст щоб відобразити."}, {"Hidden content. Press on text to see.", "Прихований вміст. Щоб відобразити, натисніть на текст."},
{"Router Ident", "Ідентифікатор Роутера"}, {"Router Ident", "Ідентифікатор маршрутизатора"},
{"Router Family", "Сімейство Роутера"}, {"Router Family", "Сімейство маршрутизатора"},
{"Router Caps", "Прапорці Роутера"}, {"Router Caps", "Прапорці маршрутизатора"},
{"Version", "Версія"}, {"Version", "Версія"},
{"Our external address", "Наша зовнішня адреса"}, {"Our external address", "Наша зовнішня адреса"},
{"supported", "підтримується"}, {"supported", "підтримується"},
{"Routers", "Роутери"}, {"Routers", "Маршрутизатори"},
{"Floodfills", "Флудфіли"}, {"Floodfills", "Флудфіли"},
{"Client Tunnels", "Клієнтські Тунелі"}, {"Client Tunnels", "Клієнтські Тунелі"},
{"Transit Tunnels", "Транзитні Тунелі"}, {"Transit Tunnels", "Транзитні Тунелі"},
{"Services", "Сервіси"}, {"Services", "Сервіси"},
// ShowLocalDestinations
{"Local Destinations", "Локальні Призначення"}, {"Local Destinations", "Локальні Призначення"},
// ShowLeaseSetDestination
{"Encrypted B33 address", "Шифровані B33 адреси"}, {"Encrypted B33 address", "Шифровані B33 адреси"},
{"Address registration line", "Рядок реєстрації адреси"}, {"Address registration line", "Рядок реєстрації адреси"},
{"Domain", "Домен"}, {"Domain", "Домен"},
{"Generate", "Згенерувати"}, {"Generate", "Згенерувати"},
{"<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> 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>Примітка:</b> отриманий рядок може бути використаний тільки для реєстрації доменів другого рівня. Для реєстрації піддоменів використовуйте i2pd-tools."},
{"Address", "Адреса"}, {"Address", "Адреса"},
{"Type", "Тип"}, {"Type", "Тип"},
{"EncType", "ТипШифр"}, {"EncType", "ТипШифр"},
{"Inbound tunnels", "Вхідні тунелі"}, {"Inbound tunnels", "Вхідні тунелі"},
{"ms", "мс"},
{"Outbound tunnels", "Вихідні тунелі"}, {"Outbound tunnels", "Вихідні тунелі"},
{"ms", "мс"}, // milliseconds
{"Tags", "Теги"}, {"Tags", "Теги"},
{"Incoming", "Вхідні"}, {"Incoming", "Вхідні"},
{"Outgoing", "Вихідні"}, {"Outgoing", "Вихідні"},
{"Destination", "Призначення"}, {"Destination", "Призначення"},
{"Amount", "Кількість"}, {"Amount", "Кількість"},
{"Incoming Tags", "Вхідні Теги"}, {"Incoming Tags", "Вхідні Теги"},
{"Tags sessions", "Сесії тегів"}, {"Tags sessions", "Сесії Тегів"},
{"Status", "Статус"}, {"Status", "Статус"},
// ShowLocalDestination
{"Local Destination", "Локальні Призначення"}, {"Local Destination", "Локальні Призначення"},
{"Streams", "Потоки"}, {"Streams", "Потоки"},
{"Close stream", "Закрити потік"}, {"Close stream", "Закрити потік"},
// ShowI2CPLocalDestination
{"I2CP session not found", "I2CP сесія не знайдена"}, {"I2CP session not found", "I2CP сесія не знайдена"},
{"I2CP is not enabled", "I2CP не увікнуто"}, {"I2CP is not enabled", "I2CP не увікнуто"},
// ShowLeasesSets
{"Invalid", "Некоректний"}, {"Invalid", "Некоректний"},
{"Store type", "Тип сховища"}, {"Store type", "Тип сховища"},
{"Expires", "Завершується"}, {"Expires", "Завершується"},
@ -167,51 +119,36 @@ namespace ukrainian // language
{"TunnelID", "ID тунеля"}, {"TunnelID", "ID тунеля"},
{"EndDate", "Закінчується"}, {"EndDate", "Закінчується"},
{"not floodfill", "не флудфіл"}, {"not floodfill", "не флудфіл"},
// ShowTunnels
{"Queue size", "Розмір черги"}, {"Queue size", "Розмір черги"},
// ShowCommands
{"Run peer test", "Запустити тестування"}, {"Run peer test", "Запустити тестування"},
{"Decline transit tunnels", "Відхиляти транзитні тунелі"}, {"Decline transit tunnels", "Відхиляти транзитні тунелі"},
{"Accept transit tunnels", "Ухвалювати транзитні тунелі"}, {"Accept transit tunnels", "Ухвалювати транзитні тунелі"},
{"Cancel graceful shutdown", "Скасувати плавну зупинку"}, {"Cancel graceful shutdown", "Скасувати плавну зупинку"},
{"Start graceful shutdown", "Запустити плавну зупинку"}, {"Start graceful shutdown", "Запустити плавну зупинку"},
{"Force shutdown", "Примусова зупинка"}, {"Force shutdown", "Примусова зупинка"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Примітка:</b> будь-яка зроблена тут дія не є постійною та не змінює ваші конфігураційні файли."},
"<b>Примітка:</b> будь-яка зроблена тут дія не є постійною та не змінює ваші конфігураційні файли."},
{"Logging level", "Рівень логування"}, {"Logging level", "Рівень логування"},
{"Transit tunnels limit", "Обмеження транзитних тунелів"}, {"Transit tunnels limit", "Обмеження транзитних тунелів"},
{"Change", "Змінити"}, {"Change", "Змінити"},
// ShowTransitTunnels
{"no transit tunnels currently built", "немає побудованих транзитних тунелів"}, {"no transit tunnels currently built", "немає побудованих транзитних тунелів"},
// ShowSAMSessions/ShowSAMSession
{"SAM disabled", "SAM вимкнуто"}, {"SAM disabled", "SAM вимкнуто"},
{"SAM session not found", "SAM сесія не знайдена"},
{"no sessions currently running", "немає запущених сесій"}, {"no sessions currently running", "немає запущених сесій"},
{"SAM session not found", "SAM сесія не знайдена"},
{"SAM Session", "SAM сесія"}, {"SAM Session", "SAM сесія"},
// ShowI2PTunnels
{"Server Tunnels", "Серверні Тунелі"}, {"Server Tunnels", "Серверні Тунелі"},
{"Client Forwards", "Клієнтські Переспрямування"}, {"Client Forwards", "Клієнтські Переспрямування"},
{"Server Forwards", "Серверні Переспрямування"}, {"Server Forwards", "Серверні Переспрямування"},
// HandlePage
{"Unknown page", "Невідома сторінка"}, {"Unknown page", "Невідома сторінка"},
// HandleCommand, ShowError
{"Invalid token", "Невірний токен"}, {"Invalid token", "Невірний токен"},
{"SUCCESS", "УСПІШНО"}, {"SUCCESS", "УСПІШНО"},
{"ERROR", "ПОМИЛКА"},
{"Unknown command", "Невідома команда"},
{"Command accepted", "Команда прийнята"},
{"Back to commands list", "Повернутися до списку команд"},
{"You will be redirected in 5 seconds", "Ви будете переадресовані через 5 секунд"},
// HTTP_COMMAND_KILLSTREAM
{"Stream closed", "Потік зачинений"}, {"Stream closed", "Потік зачинений"},
{"Stream not found or already was closed", "Потік не знайдений або вже зачинений"}, {"Stream not found or already was closed", "Потік не знайдений або вже зачинений"},
{"Destination not found", "Точка призначення не знайдена"}, {"Destination not found", "Точка призначення не знайдена"},
{"StreamID can't be null", "Ідентифікатор потоку не може бути порожнім"}, {"StreamID can't be null", "Ідентифікатор потоку не може бути порожнім"},
{"Return to destination page", "Повернутися на сторінку точки призначення"}, {"Return to destination page", "Повернутися на сторінку точки призначення"},
{"You will be redirected back in 5 seconds", "Ви будете переадресовані назад через 5 секунд"}, {"You will be redirected back in 5 seconds", "Ви будете переадресовані назад через 5 секунд"},
// HTTP_COMMAND_LIMITTRANSIT
{"Transit tunnels count must not exceed 65535", "Кількість транзитних тунелів не повинна перевищувати 65535"}, {"Transit tunnels count must not exceed 65535", "Кількість транзитних тунелів не повинна перевищувати 65535"},
// HTTP_COMMAND_GET_REG_STRING {"Back to commands list", "Повернутися до списку команд"},
{"Register at reg.i2p", "Зареєструвати на reg.i2p"}, {"Register at reg.i2p", "Зареєструвати на reg.i2p"},
{"Description", "Опис"}, {"Description", "Опис"},
{"A bit information about service on domain", "Трохи інформації про сервіс на домені"}, {"A bit information about service on domain", "Трохи інформації про сервіс на домені"},
@ -219,12 +156,51 @@ namespace ukrainian // language
{"Domain can't end with .b32.i2p", "Домен не може закінчуватися на .b32.i2p"}, {"Domain can't end with .b32.i2p", "Домен не може закінчуватися на .b32.i2p"},
{"Domain must end with .i2p", "Домен повинен закінчуватися на .i2p"}, {"Domain must end with .i2p", "Домен повинен закінчуватися на .i2p"},
{"Such destination is not found", "Така точка призначення не знайдена"}, {"Such destination is not found", "Така точка призначення не знайдена"},
{"Unknown command", "Невідома команда"},
{"Command accepted", "Команда прийнята"},
{"You will be redirected in 5 seconds", "Ви будете переадресовані через 5 секунд"},
{"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", "Ви можете спробувати знайти дану адресу на джамп сервісах нижче"},
{"Invalid request", "Некоректний запит"},
{"Proxy unable to parse your request", "Проксі не може розібрати ваш запит"},
{"addresshelper is not supported", "addresshelper не підтримується"},
{"Host", "Адреса"},
{"added to router's addressbook from helper", "доданий в адресну книгу маршрутизатора через хелпер"},
{"Click", "Натисніть"},
{"here", "тут"},
{"to proceed", "щоб продовжити"},
{"Addresshelper found", "Знайдено addresshelper"},
{"already in router's addressbook", "вже в адресній книзі маршрутизатора"},
{"to update record", "щоб оновити запис"},
{"Invalid Request", "Некоректний Запит"},
{"invalid request uri", "некоректний URI запиту"},
{"Can't detect destination host from request", "Не вдалось визначити адресу призначення з запиту"},
{"Outproxy failure", "Помилка зовнішнього проксі"},
{"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 проксі сервера"},
{"Host is down", "Вузол недоступний"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Не вдалося встановити з'єднання до запитаного вузла, можливо він не в мережі. Спробуйте повторити запит пізніше."},
{"", ""}, {"", ""},
}; };
static std::map<std::string, std::vector<std::string>> plurals static std::map<std::string, std::vector<std::string>> plurals
{ {
// ShowUptime
{"days", {"день", "дня", "днів"}}, {"days", {"день", "дня", "днів"}},
{"hours", {"годину", "години", "годин"}}, {"hours", {"годину", "години", "годин"}},
{"minutes", {"хвилину", "хвилини", "хвилин"}}, {"minutes", {"хвилину", "хвилини", "хвилин"}},
@ -234,7 +210,7 @@ namespace ukrainian // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language

3
libi2pd/Config.cpp

@ -37,6 +37,7 @@ namespace config {
("conf", value<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)") ("conf", value<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)")
("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)") ("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)")
("tunnelsdir", value<std::string>()->default_value(""), "Path to extra tunnels' configs folder (default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d") ("tunnelsdir", value<std::string>()->default_value(""), "Path to extra tunnels' configs folder (default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d")
("certsdir", value<std::string>()->default_value(""), "Path to certificates used for verifying .su3, families (default: ~/.i2pd/certificates or /var/lib/i2pd/certificates")
("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)") ("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)")
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)")
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
@ -284,7 +285,7 @@ namespace config {
options_description meshnets("Meshnet transports options"); options_description meshnets("Meshnet transports options");
meshnets.add_options() meshnets.add_options()
("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (deafult: false)") ("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (default: false)")
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish") ("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish")
; ;

20
libi2pd/FS.cpp

@ -24,6 +24,7 @@ namespace i2p {
namespace fs { namespace fs {
std::string appName = "i2pd"; std::string appName = "i2pd";
std::string dataDir = ""; std::string dataDir = "";
std::string certsDir = "";
#ifdef _WIN32 #ifdef _WIN32
std::string dirSep = "\\"; std::string dirSep = "\\";
#else #else
@ -42,6 +43,10 @@ namespace fs {
return dataDir; return dataDir;
} }
const std::string & GetCertsDir () {
return certsDir;
}
const std::string GetUTF8DataDir () { const std::string GetUTF8DataDir () {
#ifdef _WIN32 #ifdef _WIN32
boost::filesystem::wpath path (dataDir); boost::filesystem::wpath path (dataDir);
@ -126,6 +131,21 @@ namespace fs {
#endif #endif
} }
void SetCertsDir(const std::string & cmdline_certsdir) {
if (cmdline_certsdir != "")
{
if (cmdline_certsdir[cmdline_certsdir.length()-1] == '/')
certsDir = cmdline_certsdir.substr(0, cmdline_certsdir.size()-1); // strip trailing slash
else
certsDir = cmdline_certsdir;
}
else
{
certsDir = i2p::fs::DataDirPath("certificates");
}
return;
}
bool Init() { bool Init() {
if (!boost::filesystem::exists(dataDir)) if (!boost::filesystem::exists(dataDir))
boost::filesystem::create_directory(dataDir); boost::filesystem::create_directory(dataDir);

16
libi2pd/FS.h

@ -75,6 +75,9 @@ namespace fs {
/** @brief Returns datadir path */ /** @brief Returns datadir path */
const std::string & GetDataDir(); const std::string & GetDataDir();
/** @brief Returns certsdir path */
const std::string & GetCertsDir();
/** @brief Returns datadir path in UTF-8 encoding */ /** @brief Returns datadir path in UTF-8 encoding */
const std::string GetUTF8DataDir(); const std::string GetUTF8DataDir();
@ -92,6 +95,19 @@ namespace fs {
*/ */
void DetectDataDir(const std::string & cmdline_datadir, bool isService = false); void DetectDataDir(const std::string & cmdline_datadir, bool isService = false);
/**
* @brief Set certsdir either from cmdline option or using autodetection
* @param cmdline_param Value of cmdline parameter --certsdir=<something>
*
* Examples of autodetected paths:
*
* Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd\certificates
* Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd\certificates
* Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/certificates
* Unix: /var/lib/i2pd/certificates (system=1) >> ~/.i2pd/ or /tmp/i2pd/certificates
*/
void SetCertsDir(const std::string & cmdline_certsdir);
/** /**
* @brief Create subdirectories inside datadir * @brief Create subdirectories inside datadir
*/ */

4
libi2pd/Family.cpp

@ -13,6 +13,7 @@
#include "FS.h" #include "FS.h"
#include "Log.h" #include "Log.h"
#include "Family.h" #include "Family.h"
#include "Config.h"
namespace i2p namespace i2p
{ {
@ -98,7 +99,8 @@ namespace data
void Families::LoadCertificates () void Families::LoadCertificates ()
{ {
std::string certDir = i2p::fs::DataDirPath("certificates", "family"); std::string certDir = i2p::fs::GetCertsDir() + i2p::fs::dirSep + "family";
std::vector<std::string> files; std::vector<std::string> files;
int numCertificates = 0; int numCertificates = 0;

23
libi2pd/I2NPProtocol.cpp

@ -36,10 +36,21 @@ namespace i2p
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >(); return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >();
} }
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage () std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint)
{ {
auto msg = new I2NPMessageBuffer<i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34>(); // reserved for alignment and NTCP 16 + 6 + 12 I2NPMessage * msg = nullptr;
if (endpoint)
{
// should fit two tunnel message + tunnel gateway header, enough for one garlic encrypted streaming packet
msg = new I2NPMessageBuffer<2*i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + 28>(); // reserved for alignment and NTCP 16 + 6 + 6
msg->Align (6);
msg->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
}
else
{
msg = new I2NPMessageBuffer<i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34>(); // reserved for alignment and NTCP 16 + 6 + 12
msg->Align (12); msg->Align (12);
}
return std::shared_ptr<I2NPMessage>(msg); return std::shared_ptr<I2NPMessage>(msg);
} }
@ -691,7 +702,7 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf) std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf)
{ {
auto msg = NewI2NPTunnelMessage (); auto msg = NewI2NPTunnelMessage (false);
msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE); msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
msg->FillI2NPMessageHeader (eI2NPTunnelData); msg->FillI2NPMessageHeader (eI2NPTunnelData);
return msg; return msg;
@ -699,7 +710,7 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload) std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload)
{ {
auto msg = NewI2NPTunnelMessage (); auto msg = NewI2NPTunnelMessage (false);
htobe32buf (msg->GetPayload (), tunnelID); htobe32buf (msg->GetPayload (), tunnelID);
msg->len += 4; // tunnelID msg->len += 4; // tunnelID
msg->Concat (payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4); msg->Concat (payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4);
@ -707,9 +718,9 @@ namespace i2p
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg () std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg (bool endpoint)
{ {
auto msg = NewI2NPTunnelMessage (); auto msg = NewI2NPTunnelMessage (endpoint);
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE; msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
return msg; return msg;
} }

8
libi2pd/I2NPProtocol.h

@ -55,7 +55,7 @@ namespace i2p
// TunnelBuild // TunnelBuild
const size_t TUNNEL_BUILD_RECORD_SIZE = 528; const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
const size_t SHORT_TUNNEL_BUILD_RECORD_SIZE = 236; const size_t SHORT_TUNNEL_BUILD_RECORD_SIZE = 218;
//BuildRequestRecordClearText //BuildRequestRecordClearText
const size_t BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET = 0; const size_t BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET = 0;
@ -113,7 +113,7 @@ namespace i2p
const size_t SHORT_REQUEST_RECORD_REQUEST_TIME_OFFSET = SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE + 1; const size_t SHORT_REQUEST_RECORD_REQUEST_TIME_OFFSET = SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE + 1;
const size_t SHORT_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET = SHORT_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4; const size_t SHORT_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET = SHORT_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4;
const size_t SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET = SHORT_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET + 4; const size_t SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET = SHORT_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET + 4;
const size_t SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE = 172; const size_t SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE = 154;
enum I2NPMessageType enum I2NPMessageType
{ {
@ -278,7 +278,7 @@ namespace tunnel
std::shared_ptr<I2NPMessage> NewI2NPMessage (); std::shared_ptr<I2NPMessage> NewI2NPMessage ();
std::shared_ptr<I2NPMessage> NewI2NPShortMessage (); std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (); std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len); std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0); std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
@ -307,7 +307,7 @@ namespace tunnel
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf); std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload); std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg (); std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg (bool endpoint);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len); std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType, std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,

3
libi2pd/Reseed.cpp

@ -497,7 +497,8 @@ namespace data
void Reseeder::LoadCertificates () void Reseeder::LoadCertificates ()
{ {
std::string certDir = i2p::fs::DataDirPath("certificates", "reseed"); std::string certDir = i2p::fs::GetCertsDir() + i2p::fs::dirSep + "reseed";
std::vector<std::string> files; std::vector<std::string> files;
int numCertificates = 0; int numCertificates = 0;

10
libi2pd/RouterContext.cpp

@ -470,6 +470,7 @@ namespace i2p
uint8_t caps = m_RouterInfo.GetCaps (); uint8_t caps = m_RouterInfo.GetCaps ();
caps &= ~i2p::data::RouterInfo::eReachable; caps &= ~i2p::data::RouterInfo::eReachable;
caps |= i2p::data::RouterInfo::eUnreachable; caps |= i2p::data::RouterInfo::eUnreachable;
if (v6 || !SupportsV6 ())
caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill
m_RouterInfo.SetCaps (caps); m_RouterInfo.SetCaps (caps);
} }
@ -568,7 +569,9 @@ namespace i2p
{ {
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published); bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2 && ntcp2Published) if (ntcp2)
{
if (ntcp2Published)
{ {
std::string ntcp2Host; std::string ntcp2Host;
if (!i2p::config::IsDefault ("ntcp2.addressv6")) if (!i2p::config::IsDefault ("ntcp2.addressv6"))
@ -579,6 +582,9 @@ namespace i2p
if (!ntcp2Port) ntcp2Port = port; if (!ntcp2Port) ntcp2Port = port;
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (ntcp2Host), ntcp2Port); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (ntcp2Host), ntcp2Port);
} }
else
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV6);
}
} }
m_RouterInfo.EnableV6 (); m_RouterInfo.EnableV6 ();
} }
@ -632,7 +638,7 @@ namespace i2p
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (host), ntcp2Port); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (host), ntcp2Port);
} }
else else
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV4);
} }
} }
m_RouterInfo.EnableV4 (); m_RouterInfo.EnableV4 ();

16
libi2pd/RouterInfo.cpp

@ -840,21 +840,33 @@ namespace data
for (const auto& it: *m_Addresses) // don't insert same address twice for (const auto& it: *m_Addresses) // don't insert same address twice
if (*it == *addr) return; if (*it == *addr) return;
m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4; m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
m_ReachableTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
m_Addresses->push_back(std::move(addr)); m_Addresses->push_back(std::move(addr));
} }
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, const boost::asio::ip::address& host, int port) void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
const boost::asio::ip::address& host, int port, uint8_t caps)
{ {
auto addr = std::make_shared<Address>(); auto addr = std::make_shared<Address>();
addr->host = host; addr->host = host;
addr->port = port; addr->port = port;
addr->transportStyle = eTransportNTCP; addr->transportStyle = eTransportNTCP;
addr->caps = 0; addr->caps = caps;
addr->date = 0; addr->date = 0;
addr->ntcp2.reset (new NTCP2Ext ()); addr->ntcp2.reset (new NTCP2Ext ());
if (port) addr->published = true; if (port) addr->published = true;
memcpy (addr->ntcp2->staticKey, staticKey, 32); memcpy (addr->ntcp2->staticKey, staticKey, 32);
memcpy (addr->ntcp2->iv, iv, 16); memcpy (addr->ntcp2->iv, iv, 16);
if (addr->IsV4 ())
{
m_SupportedTransports |= eNTCP2V4;
if (addr->published) m_ReachableTransports |= eNTCP2V4;
}
if (addr->IsV6 ())
{
m_SupportedTransports |= eNTCP2V6;
if (addr->published) m_ReachableTransports |= eNTCP2V6;
}
m_Addresses->push_back(std::move(addr)); m_Addresses->push_back(std::move(addr));
} }

3
libi2pd/RouterInfo.h

@ -179,7 +179,8 @@ namespace data
std::shared_ptr<const Address> GetYggdrasilAddress () const; std::shared_ptr<const Address> GetYggdrasilAddress () const;
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0); void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0);
bool AddIntroducer (const Introducer& introducer); bool AddIntroducer (const Introducer& introducer);
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only

17
libi2pd/Streaming.cpp

@ -1050,6 +1050,7 @@ namespace stream
it.second->Terminate (false); // we delete here it.second->Terminate (false); // we delete here
m_Streams.clear (); m_Streams.clear ();
m_IncomingStreams.clear (); m_IncomingStreams.clear ();
m_LastStream = nullptr;
} }
} }
@ -1057,10 +1058,17 @@ namespace stream
{ {
uint32_t sendStreamID = packet->GetSendStreamID (); uint32_t sendStreamID = packet->GetSendStreamID ();
if (sendStreamID) if (sendStreamID)
{
if (!m_LastStream || sendStreamID != m_LastStream->GetRecvStreamID ())
{ {
auto it = m_Streams.find (sendStreamID); auto it = m_Streams.find (sendStreamID);
if (it != m_Streams.end ()) if (it != m_Streams.end ())
it->second->HandleNextPacket (packet); m_LastStream = it->second;
else
m_LastStream = nullptr;
}
if (m_LastStream)
m_LastStream->HandleNextPacket (packet);
else if (packet->IsEcho () && m_Owner->IsStreamingAnswerPings ()) else if (packet->IsEcho () && m_Owner->IsStreamingAnswerPings ())
{ {
// ping // ping
@ -1166,7 +1174,7 @@ namespace stream
{ {
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this, remote, port); auto s = std::make_shared<Stream> (m_Owner->GetService (), *this, remote, port);
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s; m_Streams.emplace (s->GetRecvStreamID (), s);
return s; return s;
} }
@ -1174,8 +1182,8 @@ namespace stream
{ {
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this); auto s = std::make_shared<Stream> (m_Owner->GetService (), *this);
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s; m_Streams.emplace (s->GetRecvStreamID (), s);
m_IncomingStreams[receiveStreamID] = s; m_IncomingStreams.emplace (receiveStreamID, s);
return s; return s;
} }
@ -1186,6 +1194,7 @@ namespace stream
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams.erase (stream->GetRecvStreamID ()); m_Streams.erase (stream->GetRecvStreamID ());
m_IncomingStreams.erase (stream->GetSendStreamID ()); m_IncomingStreams.erase (stream->GetSendStreamID ());
if (m_LastStream == stream) m_LastStream = nullptr;
} }
} }

11
libi2pd/Streaming.h

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, The PurpleI2P Project * Copyright (c) 2013-2021, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -11,7 +11,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <string> #include <string>
#include <map> #include <unordered_map>
#include <set> #include <set>
#include <queue> #include <queue>
#include <functional> #include <functional>
@ -297,12 +297,13 @@ namespace stream
uint16_t m_LocalPort; uint16_t m_LocalPort;
bool m_Gzip; // gzip compression of data messages bool m_Gzip; // gzip compression of data messages
std::mutex m_StreamsMutex; std::mutex m_StreamsMutex;
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams; // sendStreamID->stream std::unordered_map<uint32_t, std::shared_ptr<Stream> > m_Streams; // sendStreamID->stream
std::map<uint32_t, std::shared_ptr<Stream> > m_IncomingStreams; // receiveStreamID->stream std::unordered_map<uint32_t, std::shared_ptr<Stream> > m_IncomingStreams; // receiveStreamID->stream
std::shared_ptr<Stream> m_LastStream;
Acceptor m_Acceptor; Acceptor m_Acceptor;
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams; std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
boost::asio::deadline_timer m_PendingIncomingTimer; boost::asio::deadline_timer m_PendingIncomingTimer;
std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN std::unordered_map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
i2p::util::MemoryPool<Packet> m_PacketsPool; i2p::util::MemoryPool<Packet> m_PacketsPool;
i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool; i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool;

4
libi2pd/TransitTunnel.cpp

@ -39,7 +39,7 @@ namespace tunnel
void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
auto newMsg = CreateEmptyTunnelDataMsg (); auto newMsg = CreateEmptyTunnelDataMsg (false);
EncryptTunnelMsg (tunnelMsg, newMsg); EncryptTunnelMsg (tunnelMsg, newMsg);
m_NumTransmittedBytes += tunnelMsg->GetLength (); m_NumTransmittedBytes += tunnelMsg->GetLength ();
@ -87,7 +87,7 @@ namespace tunnel
void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
auto newMsg = CreateEmptyTunnelDataMsg (); auto newMsg = CreateEmptyTunnelDataMsg (true);
EncryptTunnelMsg (tunnelMsg, newMsg); EncryptTunnelMsg (tunnelMsg, newMsg);
LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ()); LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ());

2
libi2pd/Transports.cpp

@ -401,7 +401,7 @@ namespace transport
try try
{ {
auto r = netdb.FindRouter (ident); auto r = netdb.FindRouter (ident);
if (!r || r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ())) return; if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable
{ {
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {}, it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},

2
libi2pd/Tunnel.cpp

@ -234,7 +234,7 @@ namespace tunnel
void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg) void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg)
{ {
if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive
auto newMsg = CreateEmptyTunnelDataMsg (); auto newMsg = CreateEmptyTunnelDataMsg (true);
EncryptTunnelMsg (msg, newMsg); EncryptTunnelMsg (msg, newMsg);
newMsg->from = shared_from_this (); newMsg->from = shared_from_this ();
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);

177
libi2pd/TunnelEndpoint.cpp

@ -52,24 +52,25 @@ namespace tunnel
bool isFollowOnFragment = flag & 0x80, isLastFragment = true; bool isFollowOnFragment = flag & 0x80, isLastFragment = true;
uint32_t msgID = 0; uint32_t msgID = 0;
int fragmentNum = 0; int fragmentNum = 0;
TunnelMessageBlockEx m;
if (!isFollowOnFragment) if (!isFollowOnFragment)
{ {
// first fragment // first fragment
if (m_CurrentMsgID)
AddIncompleteCurrentMessage (); // we have got a new message while previous is not complete
m.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03); m_CurrentMessage.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03);
switch (m.deliveryType) switch (m_CurrentMessage.deliveryType)
{ {
case eDeliveryTypeLocal: // 0 case eDeliveryTypeLocal: // 0
break; break;
case eDeliveryTypeTunnel: // 1 case eDeliveryTypeTunnel: // 1
m.tunnelID = bufbe32toh (fragment); m_CurrentMessage.tunnelID = bufbe32toh (fragment);
fragment += 4; // tunnelID fragment += 4; // tunnelID
m.hash = i2p::data::IdentHash (fragment); m_CurrentMessage.hash = i2p::data::IdentHash (fragment);
fragment += 32; // hash fragment += 32; // hash
break; break;
case eDeliveryTypeRouter: // 2 case eDeliveryTypeRouter: // 2
m.hash = i2p::data::IdentHash (fragment); m_CurrentMessage.hash = i2p::data::IdentHash (fragment);
fragment += 32; // to hash fragment += 32; // to hash
break; break;
default: ; default: ;
@ -81,6 +82,7 @@ namespace tunnel
// Message ID // Message ID
msgID = bufbe32toh (fragment); msgID = bufbe32toh (fragment);
fragment += 4; fragment += 4;
m_CurrentMsgID = msgID;
isLastFragment = false; isLastFragment = false;
} }
} }
@ -96,48 +98,58 @@ namespace tunnel
uint16_t size = bufbe16toh (fragment); uint16_t size = bufbe16toh (fragment);
fragment += 2; fragment += 2;
// handle fragment
if (isFollowOnFragment)
{
// existing message
if (m_CurrentMsgID && m_CurrentMsgID == msgID && m_CurrentMessage.nextFragmentNum == fragmentNum)
HandleCurrenMessageFollowOnFragment (fragment, size, isLastFragment); // previous
else
{
HandleFollowOnFragment (msgID, isLastFragment, fragmentNum, fragment, size); // another
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
}
}
else
{
// new message
msg->offset = fragment - msg->buf; msg->offset = fragment - msg->buf;
msg->len = msg->offset + size; msg->len = msg->offset + size;
// check message size
if (msg->len > msg->maxLen) if (msg->len > msg->maxLen)
{ {
LogPrint (eLogError, "TunnelMessage: fragment is too long ", (int)size); LogPrint (eLogError, "TunnelMessage: fragment is too long ", (int)size);
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
return; return;
} }
// create new or assign I2NP message
if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE) if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
{ {
// this is not last message. we have to copy it // this is not last message. we have to copy it
m.data = NewI2NPTunnelMessage (); m_CurrentMessage.data = NewI2NPTunnelMessage (true);
m.data->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header *(m_CurrentMessage.data) = *msg;
m.data->len += TUNNEL_GATEWAY_HEADER_SIZE;
*(m.data) = *msg;
} }
else else
m.data = msg; m_CurrentMessage.data = msg;
if (!isFollowOnFragment && isLastFragment) if (isLastFragment)
HandleNextMessage (m);
else
{
if (msgID) // msgID is presented, assume message is fragmented
{
if (!isFollowOnFragment) // create new incomlete message
{ {
m.nextFragmentNum = 1; // single message
m.receiveTime = i2p::util::GetMillisecondsSinceEpoch (); HandleNextMessage (m_CurrentMessage);
auto ret = m_IncompleteMessages.insert (std::pair<uint32_t, TunnelMessageBlockEx>(msgID, m)); m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
if (ret.second)
HandleOutOfSequenceFragments (msgID, ret.first->second);
else
LogPrint (eLogError, "TunnelMessage: Incomplete message ", msgID, " already exists");
} }
else else if (msgID)
{ {
m.nextFragmentNum = fragmentNum; // first fragment of a new message
HandleFollowOnFragment (msgID, isLastFragment, m); m_CurrentMessage.nextFragmentNum = 1;
} m_CurrentMessage.receiveTime = i2p::util::GetMillisecondsSinceEpoch ();
HandleOutOfSequenceFragments (msgID, m_CurrentMessage);
} }
else else
{
LogPrint (eLogError, "TunnelMessage: Message is fragmented, but msgID is not presented"); LogPrint (eLogError, "TunnelMessage: Message is fragmented, but msgID is not presented");
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
}
} }
fragment += size; fragment += size;
@ -147,15 +159,49 @@ namespace tunnel
LogPrint (eLogError, "TunnelMessage: zero not found"); LogPrint (eLogError, "TunnelMessage: zero not found");
} }
void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m) void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment,
uint8_t fragmentNum, const uint8_t * fragment, size_t size)
{ {
auto fragment = m.data->GetBuffer ();
auto size = m.data->GetLength ();
auto it = m_IncompleteMessages.find (msgID); auto it = m_IncompleteMessages.find (msgID);
if (it != m_IncompleteMessages.end()) if (it != m_IncompleteMessages.end())
{ {
auto& msg = it->second; auto& msg = it->second;
if (m.nextFragmentNum == msg.nextFragmentNum) if (fragmentNum == msg.nextFragmentNum)
{
if (ConcatFollowOnFragment (msg, fragment, size))
{
if (isLastFragment)
{
// message complete
HandleNextMessage (msg);
m_IncompleteMessages.erase (it);
}
else
{
msg.nextFragmentNum++;
HandleOutOfSequenceFragments (msgID, msg);
}
}
else
{
LogPrint (eLogError, "TunnelMessage: Fragment ", fragmentNum, " of message ", msgID, "exceeds max I2NP message size, message dropped");
m_IncompleteMessages.erase (it);
}
}
else
{
LogPrint (eLogWarning, "TunnelMessage: Unexpected fragment ", (int)fragmentNum, " instead ", (int)msg.nextFragmentNum, " of message ", msgID, ", saved");
AddOutOfSequenceFragment (msgID, fragmentNum, isLastFragment, fragment, size);
}
}
else
{
LogPrint (eLogDebug, "TunnelMessage: First fragment of message ", msgID, " not found, saved");
AddOutOfSequenceFragment (msgID, fragmentNum, isLastFragment, fragment, size);
}
}
bool TunnelEndpoint::ConcatFollowOnFragment (TunnelMessageBlockEx& msg, const uint8_t * fragment, size_t size) const
{ {
if (msg.data->len + size < I2NP_MAX_MESSAGE_SIZE) // check if message is not too long if (msg.data->len + size < I2NP_MAX_MESSAGE_SIZE) // check if message is not too long
{ {
@ -167,41 +213,57 @@ namespace tunnel
msg.data = newMsg; msg.data = newMsg;
} }
if (msg.data->Concat (fragment, size) < size) // concatenate fragment if (msg.data->Concat (fragment, size) < size) // concatenate fragment
{
LogPrint (eLogError, "TunnelMessage: I2NP buffer overflow ", msg.data->maxLen); LogPrint (eLogError, "TunnelMessage: I2NP buffer overflow ", msg.data->maxLen);
return false;
}
}
else
return false;
return true;
}
void TunnelEndpoint::HandleCurrenMessageFollowOnFragment (const uint8_t * fragment, size_t size, bool isLastFragment)
{
if (ConcatFollowOnFragment (m_CurrentMessage, fragment, size))
{
if (isLastFragment) if (isLastFragment)
{ {
// message complete // message complete
HandleNextMessage (msg); HandleNextMessage (m_CurrentMessage);
m_IncompleteMessages.erase (it); m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
} }
else else
{ {
msg.nextFragmentNum++; m_CurrentMessage.nextFragmentNum++;
HandleOutOfSequenceFragments (msgID, msg); HandleOutOfSequenceFragments (m_CurrentMsgID, m_CurrentMessage);
} }
} }
else else
{ {
LogPrint (eLogError, "TunnelMessage: Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size, message dropped"); LogPrint (eLogError, "TunnelMessage: Fragment ", m_CurrentMessage.nextFragmentNum, " of message ", m_CurrentMsgID, " exceeds max I2NP message size, message dropped");
m_IncompleteMessages.erase (it); m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
} }
} }
else
void TunnelEndpoint::AddIncompleteCurrentMessage ()
{ {
LogPrint (eLogWarning, "TunnelMessage: Unexpected fragment ", (int)m.nextFragmentNum, " instead ", (int)msg.nextFragmentNum, " of message ", msgID, ", saved"); if (m_CurrentMsgID)
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data);
}
}
else
{ {
LogPrint (eLogWarning, "TunnelMessage: First fragment of message ", msgID, " not found, saved"); auto ret = m_IncompleteMessages.emplace (m_CurrentMsgID, m_CurrentMessage);
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data); if (!ret.second)
LogPrint (eLogError, "TunnelMessage: Incomplete message ", m_CurrentMsgID, " already exists");
m_CurrentMessage.data = nullptr;
m_CurrentMsgID = 0;
} }
} }
void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data) void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum,
bool isLastFragment, const uint8_t * fragment, size_t size)
{ {
if (!m_OutOfSequenceFragments.insert ({{msgID, fragmentNum}, {isLastFragment, data, i2p::util::GetMillisecondsSinceEpoch () }}).second) std::unique_ptr<Fragment> f(new Fragment (isLastFragment, i2p::util::GetMillisecondsSinceEpoch (), size));
memcpy (f->data.data (), fragment, size);
if (!m_OutOfSequenceFragments.emplace ((uint64_t)msgID << 32 | fragmentNum, std::move (f)).second)
LogPrint (eLogInfo, "TunnelMessage: duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID); LogPrint (eLogInfo, "TunnelMessage: duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID);
} }
@ -212,7 +274,14 @@ namespace tunnel
if (!msg.nextFragmentNum) // message complete if (!msg.nextFragmentNum) // message complete
{ {
HandleNextMessage (msg); HandleNextMessage (msg);
if (&msg == &m_CurrentMessage)
{
m_CurrentMsgID = 0;
m_CurrentMessage.data = nullptr;
}
else
m_IncompleteMessages.erase (msgID); m_IncompleteMessages.erase (msgID);
LogPrint (eLogDebug, "TunnelMessage: All fragments of message ", msgID, " found");
break; break;
} }
} }
@ -220,11 +289,11 @@ namespace tunnel
bool TunnelEndpoint::ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg) bool TunnelEndpoint::ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg)
{ {
auto it = m_OutOfSequenceFragments.find ({msgID, msg.nextFragmentNum}); auto it = m_OutOfSequenceFragments.find ((uint64_t)msgID << 32 | msg.nextFragmentNum);
if (it != m_OutOfSequenceFragments.end ()) if (it != m_OutOfSequenceFragments.end ())
{ {
LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)msg.nextFragmentNum, " of message ", msgID, " found"); LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)msg.nextFragmentNum, " of message ", msgID, " found");
size_t size = it->second.data->GetLength (); size_t size = it->second->data.size ();
if (msg.data->len + size > msg.data->maxLen) if (msg.data->len + size > msg.data->maxLen)
{ {
LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
@ -232,9 +301,9 @@ namespace tunnel
*newMsg = *(msg.data); *newMsg = *(msg.data);
msg.data = newMsg; msg.data = newMsg;
} }
if (msg.data->Concat (it->second.data->GetBuffer (), size) < size) // concatenate out-of-sync fragment if (msg.data->Concat (it->second->data.data (), size) < size) // concatenate out-of-sync fragment
LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen); LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen);
if (it->second.isLastFragment) if (it->second->isLastFragment)
// message complete // message complete
msg.nextFragmentNum = 0; msg.nextFragmentNum = 0;
else else
@ -287,7 +356,7 @@ namespace tunnel
// out-of-sequence fragments // out-of-sequence fragments
for (auto it = m_OutOfSequenceFragments.begin (); it != m_OutOfSequenceFragments.end ();) for (auto it = m_OutOfSequenceFragments.begin (); it != m_OutOfSequenceFragments.end ();)
{ {
if (ts > it->second.receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT) if (ts > it->second->receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT)
it = m_OutOfSequenceFragments.erase (it); it = m_OutOfSequenceFragments.erase (it);
else else
++it; ++it;

23
libi2pd/TunnelEndpoint.h

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, The PurpleI2P Project * Copyright (c) 2013-2021, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -10,7 +10,8 @@
#define TUNNEL_ENDPOINT_H__ #define TUNNEL_ENDPOINT_H__
#include <inttypes.h> #include <inttypes.h>
#include <map> #include <unordered_map>
#include <vector>
#include <string> #include <string>
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "TunnelBase.h" #include "TunnelBase.h"
@ -29,14 +30,15 @@ namespace tunnel
struct Fragment struct Fragment
{ {
Fragment (bool last, uint64_t t, size_t size): isLastFragment (last), receiveTime (t), data (size) {};
bool isLastFragment; bool isLastFragment;
std::shared_ptr<I2NPMessage> data;
uint64_t receiveTime; // milliseconds since epoch uint64_t receiveTime; // milliseconds since epoch
std::vector<uint8_t> data;
}; };
public: public:
TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {}; TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0), m_CurrentMsgID (0) {};
~TunnelEndpoint (); ~TunnelEndpoint ();
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
void Cleanup (); void Cleanup ();
@ -45,19 +47,24 @@ namespace tunnel
private: private:
void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m); void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, uint8_t fragmentNum, const uint8_t * fragment, size_t size);
bool ConcatFollowOnFragment (TunnelMessageBlockEx& msg, const uint8_t * fragment, size_t size) const; // true if success
void HandleCurrenMessageFollowOnFragment (const uint8_t * frgament, size_t size, bool isLastFragment);
void HandleNextMessage (const TunnelMessageBlock& msg); void HandleNextMessage (const TunnelMessageBlock& msg);
void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data); void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, const uint8_t * fragment, size_t size);
bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added
void HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg); void HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg);
void AddIncompleteCurrentMessage ();
private: private:
std::map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages; std::unordered_map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;
std::map<std::pair<uint32_t, uint8_t>, Fragment> m_OutOfSequenceFragments; // (msgID, fragment#)->fragment std::unordered_map<uint64_t, std::unique_ptr<Fragment> > m_OutOfSequenceFragments; // ((msgID << 8) + fragment#)->fragment
bool m_IsInbound; bool m_IsInbound;
size_t m_NumReceivedBytes; size_t m_NumReceivedBytes;
TunnelMessageBlockEx m_CurrentMessage;
uint32_t m_CurrentMsgID;
}; };
} }
} }

2
libi2pd/TunnelGateway.cpp

@ -215,7 +215,7 @@ namespace tunnel
const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs (); const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs ();
for (auto& tunnelMsg : tunnelDataMsgs) for (auto& tunnelMsg : tunnelDataMsgs)
{ {
auto newMsg = CreateEmptyTunnelDataMsg (); auto newMsg = CreateEmptyTunnelDataMsg (false);
m_Tunnel->EncryptTunnelMsg (tunnelMsg, newMsg); m_Tunnel->EncryptTunnelMsg (tunnelMsg, newMsg);
htobe32buf (newMsg->GetPayload (), m_Tunnel->GetNextTunnelID ()); htobe32buf (newMsg->GetPayload (), m_Tunnel->GetNextTunnelID ());
newMsg->FillI2NPMessageHeader (eI2NPTunnelData); newMsg->FillI2NPMessageHeader (eI2NPTunnelData);

2
libi2pd_client/HTTPProxy.cpp

@ -319,7 +319,7 @@ namespace proxy {
auto pos = uri.find(":"); auto pos = uri.find(":");
if(pos == std::string::npos || pos == uri.size() - 1) if(pos == std::string::npos || pos == uri.size() - 1)
{ {
GenericProxyError(tr("Invalid Request"), tr("invalid request uri")); GenericProxyError(tr("Invalid request"), tr("invalid request uri"));
return true; return true;
} }
else else

Loading…
Cancel
Save